;(function (global, factory) {
if (typeof define === 'function' && define.amd) {
define(factory);
} else if (typeof module === 'object' && typeof module.exports === 'object') {
module.exports = factory();
} else {
global.JSONSchema = factory();
}
})(this, function () {
// Валидация данных в формате JSON согласно схеме проверки.
// Допустимые для типы значений:
// - types - массив с возможными вариантами типов значений
// - type - тип значения: null, boolean, number, string, array, object
// - min - минимальная длина значения или число элементов, входящих в него
// - max - максимальная длина значения или число элементов, входящих в него
// - regexp: {pattern: 'abcde', flags: 'gi'} - регулярное выражение для проверки содержимого строки
// - items - объект, содержащий в себе описание схемы для проверки элементов внутри массива, имеющих числовые индексы
// - allItems - массив, содержащий в себе описание схемы для проверки всех элементов внутри массива, имеющих одинаковый тип
// - properties - объект, содержащий в себе описание схемы для проверки элементов внутри объекта
// - optional: true - булево значение, всегда равное true и указывающее на то, что не является ошибкой, если данный элемент будет отсутствовать
//
// undefined:
// - type
// - optional: true
//
// null:
// - type
// - optional: true
//
// boolean:
// - type
// - optional: true
//
// number:
// - type
// - min
// - max
// - optional: true
//
// string:
// - type
// - min
// - max
// - regexp
// - optional: true
//
// array:
// - type
// - min
// - max
// - items
// - allItems
// - optional: true
//
// object:
// - type
// - min
// - max
// - properties
// - optional: true
// Пример использования:
//
// var data = {
// undef: undefined
// , nul: null
// , bool: false
// , num: 5
// , str: 'ab1c2de'
// , arr: [1, 2, [3, 4]]
// , obj: {one: '', two: {three: 3}}
// , anyTypeFrom: 5
// , all: [1, 2, 3, 4]
// };
//
// var schema = {
// undef: {type: 'undefined'}
// , nul: {type: 'null'}
// , bool: {type: 'boolean'}
// , num: {type: 'number', min: 0, max: 10}
// , str: {type: 'string', min: 0, max: 10, regexp: {pattern: 'abcde', flags: 'gi'}}
// , arr: {type: 'array', min: 0, max: 10, items: {
// '0': {type: 'number'}
// , '1': {type: 'number'}
// , '2': {type: 'array', items: {
// '0': {type: 'number'}
// , '1': {type: 'string'}
// }
// }
// }
// }
// , obj: {type: 'object', min: 0, max: 10, properties: {
// one: {type: 'number'}
// , two: {type: 'object', properties: {
// three: {type: 'string'}
// , four: {type: 'string', optional: true}
// }
// }
// }
// }
// , anyTypeFrom: {
// types: [
// {type: 'number', min: 0, max: 10}
// , {type: 'string', min: 0, max: 10, regexp: {pattern: 'abcde', flags: 'gi'}}
// ]
// }
// , all: {type: 'array', allItems: {type: 'number'}}
// , notExist1: {type: 'array', optional: true}
// , notExist2: {
// types: [
// {type: 'number', min: 0, max: 10}
// , {type: 'string', min: 0, max: 10, regexp: {pattern: 'abcde', flags: 'gi'}}
// ]
// , optional: true
// }
// };
//
// var result = JSONSchema.validate(data, schema);
//
// if (!result.valid) {
// for (var i = 0, len = result.errors.length; i < len; i++) {
// console.log('Ошибка: ' + result.errors[i].message);
// console.log('Путь до элемента: ' + result.errors[i].path);
// }
// }
function has (object, key) {
return Object.prototype.hasOwnProperty.call(object, key);
}
function isTypeOf (value, type) {
return Object.prototype.toString.call(value).toLowerCase().slice(8, -1) === type;
}
function objectLength (object) {
var length = 0
, key;
for (key in object) {if (has(object, key)) {
length++;
}}
return length;
}
function validate (json, schema) {
var result = {
valid: true
, errors: []
};
function addError (path, message) {
result.valid = false;
result.errors.push({path: path, message: message});
}
if (!isTypeOf(json, 'object')) {
addError('корневой элемент', 'Корневой элемент должен быть объектом.');
} else {
for (var key in schema) {if (has(schema, key)) {
if (
!has(json, key)
&& (
(has(schema[key], 'type') && schema[key].type !== 'undefined' && !has(schema[key], 'optional'))
|| (has(schema[key], 'types') && !has(schema[key], 'optional'))
)
) {
addError('корневой объект', 'Элемент "' + key + '" должен присутствовать в корневом объекте.');
}
if (has(schema[key], 'type')) {validateSingleRootType(json, schema, key);
} else if (has(schema[key], 'types')) {validateManyRootTypes(json, schema, key);
}
}}
}
function validateSingleRootType (json, schema, key) {
if (!has(schema[key], 'type')) {throw new Error('Описание "type" всегда должно присутствовать в схеме для элемента "' + key + '" корневого объекта.');}
if (schema[key].type === 'undefined') {validateUndefined(key, json[key], schema[key], '');
} else if (schema[key].type === 'null') {validateNull(key, json[key], schema[key], '');
} else if (schema[key].type === 'boolean') {validateBoolean(key, json[key], schema[key], '');
} else if (schema[key].type === 'number') {validateNumber(key, json[key], schema[key], '');
} else if (schema[key].type === 'string') {validateString(key, json[key], schema[key], '');
} else if (schema[key].type === 'array') {validateArray(key, json[key], schema[key], '');
} else if (schema[key].type === 'object') {validateObject(key, json[key], schema[key], '');
}
}
function validateManyRootTypes (json, schema, key) {
var elementType
, requiredElements = [];
for (var i = 0, len = schema[key].types.length; i < len; i++) {
if (!has(schema[key].types[i], 'type')) {throw new Error('Описание "type" всегда должно присутствовать в схеме для элемента "' + key + '" корневого объекта.');}
if (schema[key].types[i].type === 'undefined' && isTypeOf(json[key], 'undefined')) {elementType = 'undefined'; break;
} else if (schema[key].types[i].type === 'null' && isTypeOf(json[key], 'null')) {elementType = 'null'; break;
} else if (schema[key].types[i].type === 'boolean' && isTypeOf(json[key], 'boolean')) {elementType = 'boolean'; break;
} else if (schema[key].types[i].type === 'number' && isTypeOf(json[key], 'number')) {elementType = 'number'; validateNumber(key, json[key], schema[key].types[i], ''); break;
} else if (schema[key].types[i].type === 'string' && isTypeOf(json[key], 'string')) {elementType = 'string'; validateString(key, json[key], schema[key].types[i], ''); break;
} else if (schema[key].types[i].type === 'array' && isTypeOf(json[key], 'array')) {elementType = 'array'; validateArray(key, json[key], schema[key].types[i], ''); break;
} else if (schema[key].types[i].type === 'object' && isTypeOf(json[key], 'object')) {elementType = 'object'; validateObject(key, json[key], schema[key].types[i], ''); break;
} else {requiredElements.push('"' + schema[key].types[i].type + '"');
}
}
if (elementType === undefined && !has(schema[key], 'optional')) {addError('корневой объект', 'Элемент "' + key + '" корневого объекта должен иметь значение с типом: ' + requiredElements.join(', ') + '.');}
}
function validateUndefined (/*key, value, schemaForUndefined, pathToElement*/) {
// Сообщение об ошибке выводить не нужно. Если элемента нет, то это допустимо.
// if (!isTypeOf(value, 'undefined') && !has(schemaForNull, 'optional')) {addError(pathToElement + key, 'Элемент "' + key + '" не должен присутствовать.');}
}
function validateNull (key, value, schemaForNull, pathToElement) {
if (isTypeOf(value, 'undefined') && has(schemaForNull, 'optional')) {return;}
if (!isTypeOf(value, 'null')) {addError(pathToElement + key, 'Элемент "' + key + '" должен иметь значение null.');}
}
function validateBoolean (key, bool, schemaForBoolean, pathToElement) {
if (isTypeOf(bool, 'undefined') && has(schemaForBoolean, 'optional')) {return;}
if (!isTypeOf(bool, 'boolean')) {addError(pathToElement + key, 'Элемент "' + key + '" должен иметь значение true или false.');}
}
function validateNumber (key, number, schemaForNumber, pathToElement) {
if (isTypeOf(number, 'undefined') && has(schemaForNumber, 'optional')) {return;}
if (!isTypeOf(number, 'number')) {addError(pathToElement + key, 'Элемент "' + key + '" должен иметь в качестве значения число.');
} else {
if (number !== number) {addError(pathToElement + key, 'Элемент "' + key + '" не должен иметь в качестве значения NaN.');}
if (has(schemaForNumber, 'min') && number < schemaForNumber.min) {addError(pathToElement + key, 'Значение элемента "' + key + '" должно быть больше или равно ' + schemaForNumber.min + '.');}
if (has(schemaForNumber, 'max') && number > schemaForNumber.max) {addError(pathToElement + key, 'Значение элемента "' + key + '" должно быть меньше или равно ' + schemaForNumber.max + '.');}
}
}
function validateString (key, string, schemaForString, pathToElement) {
if (isTypeOf(string, 'undefined') && has(schemaForString, 'optional')) {return;}
if (!isTypeOf(string, 'string')) {addError(pathToElement + key, 'Элемент "' + key + '" должен иметь в качестве значения строку.');
} else {
if (has(schemaForString, 'min') && schemaForString.min === 0 && string.length === 0) {return;}
if (has(schemaForString, 'min') && string.length < schemaForString.min) {addError(pathToElement + key, 'Число символов в строке "' + key + '" должно быть больше или равно ' + schemaForString.min + '.');}
if (has(schemaForString, 'max') && string.length > schemaForString.max) {addError(pathToElement + key, 'Число символов в строке "' + key + '" должно быть меньше или равно ' + schemaForString.max + '.');}
if (has(schemaForString, 'regexp') && !(new RegExp(schemaForString.regexp.pattern, schemaForString.regexp.flags).test(string))) {addError(pathToElement + key, 'Значение элемента "' + key + '" не соответствует регулярному выражению: new RegExp("' + schemaForString.regexp.pattern + '", "' + schemaForString.regexp.flags + '")');}
}
}
function validateArray (key, array, schemaForArray, pathToElement) {
var index
, arrayLength;
if (isTypeOf(array, 'undefined') && has(schemaForArray, 'optional')) {return;}
if (!isTypeOf(array, 'array')) {addError(pathToElement + key, 'Элемент "' + key + '" должен иметь в качестве значения массив.');
} else {
if (has(schemaForArray, 'min') && schemaForArray.min === 0 && array.length === 0) {return;}
if (has(schemaForArray, 'min') && array.length < schemaForArray.min) {addError(pathToElement + key, 'Число элементов в массиве "' + key + '" должно быть больше или равно ' + schemaForArray.min + '.');}
if (has(schemaForArray, 'max') && array.length > schemaForArray.max) {addError(pathToElement + key, 'Число элементов в массиве "' + key + '" должно быть меньше или равно ' + schemaForArray.max + '.');}
if (has(schemaForArray, 'items')) {
for (index in schemaForArray.items) {if (has(schemaForArray.items, index)) {
if (array[index] === undefined) {addError(pathToElement + key, 'Элемент с индексом "' + index + '" должен присутствовать в массиве "' + key + '".');}
if (has(schemaForArray.items[index], 'type')) {validateSingleArrayType(array, schemaForArray, index, key, pathToElement);
} else if (has(schemaForArray.items[index], 'types')) {validateManyArrayTypes(array, schemaForArray, index, key, pathToElement);
}
}}
}
if (has(schemaForArray, 'allItems')) {
for (index = 0, arrayLength = array.length; index < arrayLength; index++) {
if (!has(schemaForArray.allItems, 'type')) {throw new Error('Описание "type" всегда должно присутствовать в схеме для всех элементов массива "' + key + '".');}
if (schemaForArray.allItems.type === 'undefined') {validateUndefined(index, array[index], schemaForArray.allItems, pathToElement + key + '.');
} else if (schemaForArray.allItems.type === 'null') {validateNull(index, array[index], schemaForArray.allItems, pathToElement + key + '.');
} else if (schemaForArray.allItems.type === 'boolean') {validateBoolean(index, array[index], schemaForArray.allItems, pathToElement + key + '.');
} else if (schemaForArray.allItems.type === 'number') {validateNumber(index, array[index], schemaForArray.allItems, pathToElement + key + '.');
} else if (schemaForArray.allItems.type === 'string') {validateString(index, array[index], schemaForArray.allItems, pathToElement + key + '.');
} else if (schemaForArray.allItems.type === 'array') {validateArray(index, array[index], schemaForArray.allItems, pathToElement + key + '.');
} else if (schemaForArray.allItems.type === 'object') {validateObject(index, array[index], schemaForArray.allItems, pathToElement + key + '.');
}
}
}
}
}
function validateSingleArrayType (array, schemaForArray, index, key, pathToElement) {
if (!has(schemaForArray.items[index], 'type')) {throw new Error('Описание "type" всегда должно присутствовать в схеме для элемента с индексом "' + index + '" массива "' + key + '".');}
if (schemaForArray.items[index].type === 'undefined') {validateUndefined(index, array[index], schemaForArray.items[index], pathToElement + key + '.');
} else if (schemaForArray.items[index].type === 'null') {validateNull(index, array[index], schemaForArray.items[index], pathToElement + key + '.');
} else if (schemaForArray.items[index].type === 'boolean') {validateBoolean(index, array[index], schemaForArray.items[index], pathToElement + key + '.');
} else if (schemaForArray.items[index].type === 'number') {validateNumber(index, array[index], schemaForArray.items[index], pathToElement + key + '.');
} else if (schemaForArray.items[index].type === 'string') {validateString(index, array[index], schemaForArray.items[index], pathToElement + key + '.');
} else if (schemaForArray.items[index].type === 'array') {validateArray(index, array[index], schemaForArray.items[index], pathToElement + key + '.');
} else if (schemaForArray.items[index].type === 'object') {validateObject(index, array[index], schemaForArray.items[index], pathToElement + key + '.');
}
}
function validateManyArrayTypes (array, schemaForArray, index, key, pathToElement) {
var elementType
, requiredElements = [];
for (var i = 0, len = schemaForArray.items[index].types.length; i < len; i++) {
if (!has(schemaForArray.items[index].types[i], 'type')) {throw new Error('Описание "type" всегда должно присутствовать в схеме для элемента с индексом "' + index + '" массива "' + key + '".');}
if (schemaForArray.items[index].types[i].type === 'undefined' && isTypeOf(array[index], 'undefined')) {elementType = 'undefined'; break;
} else if (schemaForArray.items[index].types[i].type === 'null' && isTypeOf(array[index], 'null')) {elementType = 'null'; break;
} else if (schemaForArray.items[index].types[i].type === 'boolean' && isTypeOf(array[index], 'boolean')) {elementType = 'boolean'; break;
} else if (schemaForArray.items[index].types[i].type === 'number' && isTypeOf(array[index], 'number')) {elementType = 'number'; validateNumber(index, array[index], schemaForArray.items[index].types[i], pathToElement + key + '.'); break;
} else if (schemaForArray.items[index].types[i].type === 'string' && isTypeOf(array[index], 'string')) {elementType = 'string'; validateString(index, array[index], schemaForArray.items[index].types[i], pathToElement + key + '.'); break;
} else if (schemaForArray.items[index].types[i].type === 'array' && isTypeOf(array[index], 'array')) {elementType = 'array'; validateArray(index, array[index], schemaForArray.items[index].types[i], pathToElement + key + '.'); break;
} else if (schemaForArray.items[index].types[i].type === 'object' && isTypeOf(array[index], 'object')) {elementType = 'object'; validateObject(index, array[index], schemaForArray.items[index].types[i], pathToElement + key + '.'); break;
} else {requiredElements.push('"' + schemaForArray.items[index].types[i].type + '"');
}
}
if (elementType === undefined && !has(schemaForArray.items[index], 'optional')) {addError(pathToElement + key + '.' + index, 'Элемент с индексом "' + index + '" массива "' + key + '" должен иметь значение с типом: ' + requiredElements.join(', ') + '.');}
}
function validateObject (key, object, schemaForObject, pathToElement) {
if (isTypeOf(object, 'undefined') && has(schemaForObject, 'optional')) {return;}
if (!isTypeOf(object, 'object')) {addError(pathToElement + key, 'Элемент "' + key + '" должен иметь в качестве значения объект.');
} else {
if (has(schemaForObject, 'min') && schemaForObject.min === 0 && objectLength(object) === 0) {return;}
if (has(schemaForObject, 'min') && objectLength(object) < schemaForObject.min) {addError(pathToElement + key, 'Число свойств в объекте "' + key + '" должно быть больше или равно ' + schemaForObject.min + '.');}
if (has(schemaForObject, 'max') && objectLength(object) > schemaForObject.max) {addError(pathToElement + key, 'Число свойств в объекте "' + key + '" должно быть меньше или равно ' + schemaForObject.max + '.');}
if (has(schemaForObject, 'properties')) {
for (var property in schemaForObject.properties) {if (has(schemaForObject.properties, property)) {
if (
!has(object, property)
&& (
(has(schemaForObject.properties[property], 'type') && schemaForObject.properties[property].type !== 'undefined' && !has(schemaForObject.properties[property], 'optional'))
|| (has(schemaForObject.properties[property], 'types') && !has(schemaForObject.properties[property], 'optional'))
)
) {
addError(pathToElement + key, 'Элемент "' + property + '" должен присутствовать в объекте "' + key + '".');
}
if (has(schemaForObject.properties[property], 'type')) {validateSingleObjectType(object, schemaForObject, property, key, pathToElement);
} else if (has(schemaForObject.properties[property], 'types')) {validateManyObjectTypes(object, schemaForObject, property, key, pathToElement);
}
}}
}
}
}
function validateSingleObjectType (object, schemaForObject, property, key, pathToElement) {
if (!has(schemaForObject.properties[property], 'type')) {throw new Error('Описание "type" всегда должно присутствовать в схеме для элемента "' + property + '" объекта "' + key + '".');}
if (schemaForObject.properties[property].type === 'undefined') {validateUndefined(property, object[property], schemaForObject.properties[property], pathToElement + key + '.');
} else if (schemaForObject.properties[property].type === 'null') {validateNull(property, object[property], schemaForObject.properties[property], pathToElement + key + '.');
} else if (schemaForObject.properties[property].type === 'boolean') {validateBoolean(property, object[property], schemaForObject.properties[property], pathToElement + key + '.');
} else if (schemaForObject.properties[property].type === 'number') {validateNumber(property, object[property], schemaForObject.properties[property], pathToElement + key + '.');
} else if (schemaForObject.properties[property].type === 'string') {validateString(property, object[property], schemaForObject.properties[property], pathToElement + key + '.');
} else if (schemaForObject.properties[property].type === 'array') {validateArray(property, object[property], schemaForObject.properties[property], pathToElement + key + '.');
} else if (schemaForObject.properties[property].type === 'object') {validateObject(property, object[property], schemaForObject.properties[property], pathToElement + key + '.');
}
}
function validateManyObjectTypes (object, schemaForObject, property, key, pathToElement) {
var elementType
, requiredElements = [];
for (var i = 0, len = schemaForObject.properties[property].types.length; i < len; i++) {
if (!has(schemaForObject.properties[property].types[i], 'type')) {throw new Error('Описание "type" всегда должно присутствовать в схеме для элемента "' + property + '" объекта "' + key + '".');}
if (schemaForObject.properties[property].types[i].type === 'undefined' && isTypeOf(object[property], 'undefined')) {elementType = 'undefined'; break;
} else if (schemaForObject.properties[property].types[i].type === 'null' && isTypeOf(object[property], 'null')) {elementType = 'null'; break;
} else if (schemaForObject.properties[property].types[i].type === 'boolean' && isTypeOf(object[property], 'boolean')) {elementType = 'boolean'; break;
} else if (schemaForObject.properties[property].types[i].type === 'number' && isTypeOf(object[property], 'number')) {elementType = 'number'; validateNumber(property, object[property], schemaForObject.properties[property].types[i], pathToElement + key + '.'); break;
} else if (schemaForObject.properties[property].types[i].type === 'string' && isTypeOf(object[property], 'string')) {elementType = 'string'; validateString(property, object[property], schemaForObject.properties[property].types[i], pathToElement + key + '.'); break;
} else if (schemaForObject.properties[property].types[i].type === 'array' && isTypeOf(object[property], 'array')) {elementType = 'array'; validateArray(property, object[property], schemaForObject.properties[property].types[i], pathToElement + key + '.'); break;
} else if (schemaForObject.properties[property].types[i].type === 'object' && isTypeOf(object[property], 'object')) {elementType = 'object'; validateObject(property, object[property], schemaForObject.properties[property].types[i], pathToElement + key + '.'); break;
} else {requiredElements.push('"' + schemaForObject.properties[property].types[i].type + '"');
}
}
if (elementType === undefined && !has(schemaForObject.properties[property], 'optional')) {addError(pathToElement + key + '.' + property, 'Элемент "' + property + '" объекта "' + key + '" должен иметь значение с типом: ' + requiredElements.join(', ') + '.');}
}
if (result.errors.length > 0) {
(function(){
var pathElements
, pathElementsLength
, resultPath = ''
, separator
, errorsLength = result.errors.length
, i;
while (errorsLength--) {
pathElements = result.errors[errorsLength].path.split('.');
pathElementsLength = pathElements.length;
for (i = 0; i < pathElementsLength; i++) {
if (i === 0) {
separator = '';
} else {
separator = '.';
}
if ((/^\d+$/g).test(pathElements[i])) {resultPath += '[' + pathElements[i] + ']';
} else if ((/^\d+/g).test(pathElements[i])) {resultPath += '["' + pathElements[i] + '"]';
} else {resultPath += separator + pathElements[i];
}
}
result.errors[errorsLength].path = resultPath;
resultPath = '';
}
})();
}
return result;
}
return {validate: validate};
});
четверг, 28 июля 2016 г.
среда, 27 июля 2016 г.
JavaScript CSS
// JS CSS
// Variables
var color = "#4d926f";
module.exports = {
"#header": {
color: color
}
, "h2": {
color: color
}
};
// Compiled CSS
#header {
color: #4d926f;
}
h2 {
color: #4d926f;
}
// Mixins
function roundedCorners (radius) {
radius || (radius = "5px");
return {
"-webkit-border-radius": radius
, "-moz-border-radius": radius
, "border-radius": radius
};
}
module.exports = {
"#header": roundedCorners()
, "#footer": roundedCorners("10px")
};
// Compiled CSS
#header {
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
border-radius: 5px;
}
#footer {
-webkit-border-radius: 10px;
-moz-border-radius: 10px;
border-radius: 10px;
}
// Nested Rules
module.exports = {
"#header": {
"h1": {
"font-size": "26px"
, "font-weight": "bold"
}
, "p": {
"font-size": "12px"
, "a": {
"text-decoration": "none"
}
, "> .poop": {
"color": "brown"
}
}
}
};
// Compiled CSS
#header h1 {
font-size: 26px;
font-weight: bold;
}
#header p {
font-size: 12px;
}
#header p a {
text-decoration: none;
}
#header p a:hover {
border-width: 1px;
}
#header p > .poop {
color: brown;
}
// Functions and Operators
// Currently all I have is hex math
module.exports = {
".jibber-jabber": {
color: globals.baseColor
// Pretty stupid but whatever
, "background-color": hex.multiply(globals.baseColor, globals.accent, globals.backgroundColor)
}
}
// Animations, Media Queries, and Other More-Nested Features
module.exports = {
".columns": {
"display": "table"
, "width": "100%"
}
, ".columns > .column": {
"width": "50%"
, "box-sizing": "border-box"
, "margin-left": "20px"
}
, "@-animation-keyframes spin": {
"0%": {
"transform": "rotate(0deg)"
}
, "100%": {
"transform": "rotate(360deg)"
}
}
};
// Compiled CSS
/* ./layout.js*/
.columns {
display: table;
width: 100%;
}
.columns > .column {
width: 50%;
box-sizing: border-box;
margin-left: 20px;
}
@-animation-keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
// Make a jscss Build File
// It's just a javascript file you execute with node.js.
var jscss = require('jscss')
// Require your modules
, globals = require('./css/globals.js')
, layout = require('./css/layout.js')
, themes = require('./css/themes.js')
, main = require('./css/main.js')
;
// Compile your css
jscss(
// First parameter defines your output file
'./css/main.css'
// Subsequent parameters define modules to be compiled
, globals
, layout
, themes
, main
);
// Or just pass in the paths
jscss(
'./css/main.css'
, './css/globals.js'
, './css/layout.js'
, './css/themes.js'
, './css/main.js'
);
// Since this is all javascript, use a package manager.
// Organize your code into self-contained javascript modules. Easily include everything you'll need
// In the Browser
<!DOCTYPE HTML>
<html>
<head>
<script type="text/javascript" src="../lib/index.js"></script>
<script type="text/javascript">
// Mixin
function roundedCorners (radius{
radius || (radius = "5px");
return {
"-webkit-border-radius": radius
, "-moz-border-radius": radius
, "border-radius": radius
};
}
// Just a quick and dirty merge object
function mix (obj1, obj2) {
for (var key in obj2){
obj1[key] = obj2[key];
}
return obj1;
}
// Css declarations
var cssObj = {
"body": {
"background-color": "pink"
}
, ".testing": mix(
{
"background-color": "#fff"
, "padding": "22px"
, "> .test": {
"color": "blue"
}
}
, roundedCorners("10px")
)
};
// Embed the compiled jscss object
jscss.embed(jscss.compile(cssObj));
</script>
</head>
<body>
<div class="testing">
<span class="test">Just testing</span>
</div>
</body>
</html>
// JS CSS Source
// File index.js
;(function(){
var
id = 0
, indent = function(level){
var out = "";
for (var i = 0; i < level; i++){
out += " ";
}
return out
}
, _jscss = {
compile: function(obj){
var
selectors = {}
// Build nested rules into single rules
, _buildSelectors = function(hash, selector){
var curr, type, selector, key;
for (key in hash){
type = typeof (curr = hash[key]);
if (type == "string"){
if (!selectors[selector]) selectors[selector] = {};
selectors[selector][key] = curr;
}else if (type == "object"){
// Media query or animation or something
if (key[0] == "@"){
selectors[key] = curr;
}else{
_buildSelectors(curr, (selector ? (selector + " ") : "") + key);
}
}
}
}
// Take a flat css object and turn it into a string
, _compile = function(hash, level){
var spaces = " ", out = "", level = level || 0, curr;
for (var key in hash){
curr = hash[key];
out += indent(level) + key;
if (typeof curr == "object"){
out += " {\n" + _compile(curr, level + 1) + indent(level) + "}\n";
}else{
out += ": " + curr + ";\n";
}
}
return out;
}
;
_buildSelectors(obj, "");
return _compile(selectors, 0);
}
// Embeds a
, embed: function(styles, styleId){
if (typeof styles === "object") styles = _jscss(styles);
styleId || (styleId = "jscss-" + (id++));
var el = document.createElement('style');
el.type = "text/css";
el.rel = "stylesheet";
el.id = styleId;
el.innerHTML = "\n" + styles;
document.head.appendChild(el);
}
}
;
if (typeof define !== "undefined") {
define('jscss', function(){ return _jscss; });
}else if (typeof module !== "undefined" && module.exports){
module.exports = _jscss;
}else{
window.jscss = _jscss;
}
})();
// File jscss-old.js - заменен на index.js
var fs = require('fs');
var indent = function(level){
var out = "";
for (var i = 0; i < level; i++){
out += " ";
}
return out
};
// This is O(2s + 2d)
// Where s is the number of selectors
// And d is the number of properties
// I wonder if I can make it O(s + d)
var compile = function(obj){
var selectors = {},
// Make a predictable object we can work with
_buildSelectors = function(hash, selector){
var curr, type, selector, key;
for (key in hash){
type = typeof (curr = hash[key]);
if (type == "string"){
if (!selectors[selector]) selectors[selector] = {};
selectors[selector][key] = curr;
}else if (type == "object"){
// Media query or animation or something
if (key[0] == "@"){
selectors[key] = curr;
}else{
_buildSelectors(curr, (selector ? (selector + " ") : "") + key);
}
}
}
},
// Take a flat css object and turn it into a string
_compile = function(hash, level){
var spaces = " ", out = "", level = level || 0, curr;
for (var key in hash){
curr = hash[key];
out += indent(level) + key;
if (typeof curr == "object"){
out += " {\n" + _compile(curr, level + 1) + indent(level) + "}\n";
}else{
out += ": " + curr + ";\n";
}
}
return out;
};
_buildSelectors(obj, "");
// console.log(selectors);
return _compile(selectors, 0);
};
module.exports = function(output){
var stream = fs.createWriteStream(output);
var files = Array.prototype.slice.call(arguments, 1);
stream.once('open', function(){
for (var i = 0, file; i < files.length; i++){
file = require(files[i]);
stream.write('/* ' + files[i] + ' */\n\n');
stream.write(compile(file));
}
});
};
// File hex-math.js
var maxColor = 16777215
, colorToInt = function(hex){
hex = hex.replace('#', '');
// Change shorthand so we can do proper math
if (hex.length == 3){
var tmp = hex;
hex = "";
for (var i = 0; i < tmp.length; i++){
hex += "" + tmp[i] + tmp[i];
}
}
return ("0x" + hex - 0);
}
, intToColor = function(int){
int = int.toString(16);
while (int.length < 6){
int = "" + "0" + int;
}
return '#' + int;
}
, colorIntClamp = function(int){
if (int > maxColor) return maxColor;
if (int < 0) return 0;
return int;
}
;
module.exports = {
add: function(){
var args = Array.prototype.slice.call(arguments, 0), total = colorToInt(args[0]);
for (var i = 1; i < args.length; i++){
total += colorToInt(args[i]);
}
return colorIntClamp(intToColor(total));
}
, subtract: function(){
var args = Array.prototype.slice.call(arguments, 0), total = colorToInt(args[0]);
for (var i = 1; i < args.length; i++){
total += colorToInt(args[i]);
}
return colorIntClamp(intToColor(total));
}
, multiply: function(){
var args = Array.prototype.slice.call(arguments, 0), total = colorToInt(args[0]);
for (var i = 1; i < args.length; i++){
total *= colorToInt(args[i]);
}
return colorIntClamp(intToColor(total));
}
, divide: function(){
var args = Array.prototype.slice.call(arguments, 0), total = colorToInt(args[0]);
for (var i = 1; i < args.length; i++){
total /= colorToInt(args[i]);
}
return colorIntClamp(intToColor(total));
}
};
// Build example
// File build-jscss.js
var jscss = require('./jscss.js');
jscss(
'./style.css'
, './layout.js'
);
// File layout.js
module.exports = {
'.columns': {
'display': 'table'
, 'width': '100%'
}
, '.columns > .column': {
'width': '50%'
, 'box-sizing': 'border-box'
, 'margin-left': "20px"
}
, '#header': {
"h1": {
"font-size": "26px"
, "font-weight": "bold"
}
, "p": {
"font-size": "12px"
, "a": {
"text-decoration": "none"
// , "&:hover": { "border-width": "1px" }
}
, '> .poop': {
'color': 'brown'
}
}
, ".test": {
"font-size": "1.2rem"
}
}
, '@-animation-keyframes spin': {
'0%': {
'transform': 'rotate(0deg)'
}
, '100%': {
'transform': 'rotate(360deg)'
}
}
};
// File style.css
/* ./layout.js*/
.columns {
display: table;
width: 100%;
}
.columns > .column {
width: 50%;
box-sizing: border-box;
margin-left: 20px;
}
#header h1 {
font-size: 26px;
font-weight: bold;
}
#header p {
font-size: 12px;
}
#header p a {
text-decoration: none;
}
#header p > .poop {
color: brown;
}
#header .test {
font-size: 1.2rem;
}
@-animation-keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
// Variables
var color = "#4d926f";
module.exports = {
"#header": {
color: color
}
, "h2": {
color: color
}
};
// Compiled CSS
#header {
color: #4d926f;
}
h2 {
color: #4d926f;
}
// Mixins
function roundedCorners (radius) {
radius || (radius = "5px");
return {
"-webkit-border-radius": radius
, "-moz-border-radius": radius
, "border-radius": radius
};
}
module.exports = {
"#header": roundedCorners()
, "#footer": roundedCorners("10px")
};
// Compiled CSS
#header {
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
border-radius: 5px;
}
#footer {
-webkit-border-radius: 10px;
-moz-border-radius: 10px;
border-radius: 10px;
}
// Nested Rules
module.exports = {
"#header": {
"h1": {
"font-size": "26px"
, "font-weight": "bold"
}
, "p": {
"font-size": "12px"
, "a": {
"text-decoration": "none"
}
, "> .poop": {
"color": "brown"
}
}
}
};
// Compiled CSS
#header h1 {
font-size: 26px;
font-weight: bold;
}
#header p {
font-size: 12px;
}
#header p a {
text-decoration: none;
}
#header p a:hover {
border-width: 1px;
}
#header p > .poop {
color: brown;
}
// Functions and Operators
// Currently all I have is hex math
module.exports = {
".jibber-jabber": {
color: globals.baseColor
// Pretty stupid but whatever
, "background-color": hex.multiply(globals.baseColor, globals.accent, globals.backgroundColor)
}
}
// Animations, Media Queries, and Other More-Nested Features
module.exports = {
".columns": {
"display": "table"
, "width": "100%"
}
, ".columns > .column": {
"width": "50%"
, "box-sizing": "border-box"
, "margin-left": "20px"
}
, "@-animation-keyframes spin": {
"0%": {
"transform": "rotate(0deg)"
}
, "100%": {
"transform": "rotate(360deg)"
}
}
};
// Compiled CSS
/* ./layout.js*/
.columns {
display: table;
width: 100%;
}
.columns > .column {
width: 50%;
box-sizing: border-box;
margin-left: 20px;
}
@-animation-keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
// Make a jscss Build File
// It's just a javascript file you execute with node.js.
var jscss = require('jscss')
// Require your modules
, globals = require('./css/globals.js')
, layout = require('./css/layout.js')
, themes = require('./css/themes.js')
, main = require('./css/main.js')
;
// Compile your css
jscss(
// First parameter defines your output file
'./css/main.css'
// Subsequent parameters define modules to be compiled
, globals
, layout
, themes
, main
);
// Or just pass in the paths
jscss(
'./css/main.css'
, './css/globals.js'
, './css/layout.js'
, './css/themes.js'
, './css/main.js'
);
// Since this is all javascript, use a package manager.
// Organize your code into self-contained javascript modules. Easily include everything you'll need
// In the Browser
<!DOCTYPE HTML>
<html>
<head>
<script type="text/javascript" src="../lib/index.js"></script>
<script type="text/javascript">
// Mixin
function roundedCorners (radius{
radius || (radius = "5px");
return {
"-webkit-border-radius": radius
, "-moz-border-radius": radius
, "border-radius": radius
};
}
// Just a quick and dirty merge object
function mix (obj1, obj2) {
for (var key in obj2){
obj1[key] = obj2[key];
}
return obj1;
}
// Css declarations
var cssObj = {
"body": {
"background-color": "pink"
}
, ".testing": mix(
{
"background-color": "#fff"
, "padding": "22px"
, "> .test": {
"color": "blue"
}
}
, roundedCorners("10px")
)
};
// Embed the compiled jscss object
jscss.embed(jscss.compile(cssObj));
</script>
</head>
<body>
<div class="testing">
<span class="test">Just testing</span>
</div>
</body>
</html>
// JS CSS Source
// File index.js
;(function(){
var
id = 0
, indent = function(level){
var out = "";
for (var i = 0; i < level; i++){
out += " ";
}
return out
}
, _jscss = {
compile: function(obj){
var
selectors = {}
// Build nested rules into single rules
, _buildSelectors = function(hash, selector){
var curr, type, selector, key;
for (key in hash){
type = typeof (curr = hash[key]);
if (type == "string"){
if (!selectors[selector]) selectors[selector] = {};
selectors[selector][key] = curr;
}else if (type == "object"){
// Media query or animation or something
if (key[0] == "@"){
selectors[key] = curr;
}else{
_buildSelectors(curr, (selector ? (selector + " ") : "") + key);
}
}
}
}
// Take a flat css object and turn it into a string
, _compile = function(hash, level){
var spaces = " ", out = "", level = level || 0, curr;
for (var key in hash){
curr = hash[key];
out += indent(level) + key;
if (typeof curr == "object"){
out += " {\n" + _compile(curr, level + 1) + indent(level) + "}\n";
}else{
out += ": " + curr + ";\n";
}
}
return out;
}
;
_buildSelectors(obj, "");
return _compile(selectors, 0);
}
// Embeds a
, embed: function(styles, styleId){
if (typeof styles === "object") styles = _jscss(styles);
styleId || (styleId = "jscss-" + (id++));
var el = document.createElement('style');
el.type = "text/css";
el.rel = "stylesheet";
el.id = styleId;
el.innerHTML = "\n" + styles;
document.head.appendChild(el);
}
}
;
if (typeof define !== "undefined") {
define('jscss', function(){ return _jscss; });
}else if (typeof module !== "undefined" && module.exports){
module.exports = _jscss;
}else{
window.jscss = _jscss;
}
})();
// File jscss-old.js - заменен на index.js
var fs = require('fs');
var indent = function(level){
var out = "";
for (var i = 0; i < level; i++){
out += " ";
}
return out
};
// This is O(2s + 2d)
// Where s is the number of selectors
// And d is the number of properties
// I wonder if I can make it O(s + d)
var compile = function(obj){
var selectors = {},
// Make a predictable object we can work with
_buildSelectors = function(hash, selector){
var curr, type, selector, key;
for (key in hash){
type = typeof (curr = hash[key]);
if (type == "string"){
if (!selectors[selector]) selectors[selector] = {};
selectors[selector][key] = curr;
}else if (type == "object"){
// Media query or animation or something
if (key[0] == "@"){
selectors[key] = curr;
}else{
_buildSelectors(curr, (selector ? (selector + " ") : "") + key);
}
}
}
},
// Take a flat css object and turn it into a string
_compile = function(hash, level){
var spaces = " ", out = "", level = level || 0, curr;
for (var key in hash){
curr = hash[key];
out += indent(level) + key;
if (typeof curr == "object"){
out += " {\n" + _compile(curr, level + 1) + indent(level) + "}\n";
}else{
out += ": " + curr + ";\n";
}
}
return out;
};
_buildSelectors(obj, "");
// console.log(selectors);
return _compile(selectors, 0);
};
module.exports = function(output){
var stream = fs.createWriteStream(output);
var files = Array.prototype.slice.call(arguments, 1);
stream.once('open', function(){
for (var i = 0, file; i < files.length; i++){
file = require(files[i]);
stream.write('/* ' + files[i] + ' */\n\n');
stream.write(compile(file));
}
});
};
// File hex-math.js
var maxColor = 16777215
, colorToInt = function(hex){
hex = hex.replace('#', '');
// Change shorthand so we can do proper math
if (hex.length == 3){
var tmp = hex;
hex = "";
for (var i = 0; i < tmp.length; i++){
hex += "" + tmp[i] + tmp[i];
}
}
return ("0x" + hex - 0);
}
, intToColor = function(int){
int = int.toString(16);
while (int.length < 6){
int = "" + "0" + int;
}
return '#' + int;
}
, colorIntClamp = function(int){
if (int > maxColor) return maxColor;
if (int < 0) return 0;
return int;
}
;
module.exports = {
add: function(){
var args = Array.prototype.slice.call(arguments, 0), total = colorToInt(args[0]);
for (var i = 1; i < args.length; i++){
total += colorToInt(args[i]);
}
return colorIntClamp(intToColor(total));
}
, subtract: function(){
var args = Array.prototype.slice.call(arguments, 0), total = colorToInt(args[0]);
for (var i = 1; i < args.length; i++){
total += colorToInt(args[i]);
}
return colorIntClamp(intToColor(total));
}
, multiply: function(){
var args = Array.prototype.slice.call(arguments, 0), total = colorToInt(args[0]);
for (var i = 1; i < args.length; i++){
total *= colorToInt(args[i]);
}
return colorIntClamp(intToColor(total));
}
, divide: function(){
var args = Array.prototype.slice.call(arguments, 0), total = colorToInt(args[0]);
for (var i = 1; i < args.length; i++){
total /= colorToInt(args[i]);
}
return colorIntClamp(intToColor(total));
}
};
// Build example
// File build-jscss.js
var jscss = require('./jscss.js');
jscss(
'./style.css'
, './layout.js'
);
// File layout.js
module.exports = {
'.columns': {
'display': 'table'
, 'width': '100%'
}
, '.columns > .column': {
'width': '50%'
, 'box-sizing': 'border-box'
, 'margin-left': "20px"
}
, '#header': {
"h1": {
"font-size": "26px"
, "font-weight": "bold"
}
, "p": {
"font-size": "12px"
, "a": {
"text-decoration": "none"
// , "&:hover": { "border-width": "1px" }
}
, '> .poop': {
'color': 'brown'
}
}
, ".test": {
"font-size": "1.2rem"
}
}
, '@-animation-keyframes spin': {
'0%': {
'transform': 'rotate(0deg)'
}
, '100%': {
'transform': 'rotate(360deg)'
}
}
};
// File style.css
/* ./layout.js*/
.columns {
display: table;
width: 100%;
}
.columns > .column {
width: 50%;
box-sizing: border-box;
margin-left: 20px;
}
#header h1 {
font-size: 26px;
font-weight: bold;
}
#header p {
font-size: 12px;
}
#header p a {
text-decoration: none;
}
#header p > .poop {
color: brown;
}
#header .test {
font-size: 1.2rem;
}
@-animation-keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
пятница, 8 июля 2016 г.
JavaScript Get Browser version
/**
* @class window.env.Browser
* Provides information about browser.
*
* Should not be manually instantiated unless for unit-testing.
* Access the global instance stored in {@link window.env.browser} instead.
* @private
*/
;(window.env || (window.env = {})).Browser = function (userAgent, publish) {
// @define window.env.Browser
// @define window.env.browser
function isEmpty (value, allowEmptyString) {
return (value === undefined || value === null) || (!allowEmptyString ? value === '' : false) || (isArray(value) && value.length === 0);
}
function isArray (value) {
return Object.prototype.toString.call(value) === '[object Array]';
}
function apply (object, config, defaults) {
var enumerables = ['valueOf', 'toLocaleString', 'toString', 'constructor'];
if (defaults) {
apply(object, defaults);
}
if (object && config && typeof config === 'object') {
var i, j, k;
for (i in config) {
if (config.hasOwnProperty(i)) {
object[i] = config[i];
}
}
if (enumerables) {
for (j = enumerables.length; j--;) {
k = enumerables[j];
if (config.hasOwnProperty(k)) {
object[k] = config[k];
}
}
}
}
return object;
}
function getValues (object) {
var values = [],
property;
for (property in object) {
if (object.hasOwnProperty(property)) {
values.push(object[property]);
}
}
return values;
}
function getKey (object, value) {
for (var property in object) {
if (object.hasOwnProperty(property) && object[property] === value) {
return property;
}
}
return null;
}
function Version (version) {
var me = this,
padModes = me.padModes,
ch, i, pad, parts, release, releaseStartIndex, ver;
me.version = ver = String(version).toLowerCase().replace(/_/g, '.').replace(/[\-+]/g, '');
ch = ver.charAt(0);
if (ch in padModes) {
ver = ver.substring(1);
pad = padModes[ch];
} else {
pad = 0;
}
me.pad = pad;
releaseStartIndex = ver.search(/([^\d\.])/);
me.shortVersion = ver;
if (releaseStartIndex !== -1) {
me.release = release = ver.substr(releaseStartIndex, version.length);
me.shortVersion = ver.substr(0, releaseStartIndex);
release = Version.releaseValueMap[release] || release;
}
me.releaseValue = release || pad;
me.shortVersion = me.shortVersion.replace(/[^\d]/g, '');
/**
* @property {Number[]} parts
* The split array of version number components found in the version string.
* For example, for "1.2.3", this would be `[1, 2, 3]`.
* @readonly
* @private
*/
me.parts = parts = ver.split('.');
for (i = parts.length; i--;) {
parts[i] = parseInt(parts[i], 10);
}
if (pad === Infinity) {
// have to add this to the end to create an upper bound:
parts.push(pad);
}
/**
* @property {Number} major
* The first numeric part of the version number string.
* @readonly
*/
me.major = parts[0] || pad;
return me;
}
Version.releaseValueMap = {
dev: -6,
alpha: -5,
a: -5,
beta: -4,
b: -4,
rc: -3,
'#': -2,
p: -1,
pl: -1
};
Version.prototype = {
padModes: {
'~': NaN,
'^': Infinity
},
/**
* Returns the major component value.
* @return {Number}
*/
getMajor: function() {
return this.major;
},
/**
* Returns shortVersion version without dots and release
* @return {String}
*/
getShortVersion: function() {
return this.shortVersion;
}
};
var me = this,
browserPrefixes = {
ie: 'MSIE ',
edge: 'Edge/',
firefox: 'Firefox/',
chrome: 'Chrome/',
safari: 'Version/',
opera: 'OPR/',
dolfin: 'Dolfin/',
webosbrowser: 'wOSBrowser/',
chromeMobile: 'CrMo/',
chromeiOS: 'CriOS/',
silk: 'Silk/'
},
browserNames = {
ie: 'IE',
firefox: 'Firefox',
safari: 'Safari',
chrome: 'Chrome',
opera: 'Opera',
dolfin: 'Dolfin',
edge: 'Edge',
webosbrowser: 'webOSBrowser',
chromeMobile: 'ChromeMobile',
chromeiOS: 'ChromeiOS',
silk: 'Silk',
other: 'Other'
},
enginePrefixes = me.enginePrefixes,
engineNames = me.engineNames,
browserMatch = userAgent.match(new RegExp('((?:' + getValues(browserPrefixes).join(')|(?:') + '))([\\w\\._]+)')),
engineMatch = userAgent.match(new RegExp('((?:' + getValues(enginePrefixes).join(')|(?:') + '))([\\w\\._]+)')),
browserName = browserNames.other,
engineName = engineNames.other,
browserVersion = '',
engineVersion = '',
majorVer = '',
isWebView = false,
i, prefix, mode, name, maxIEVersion;
/**
* @property {String}
* Browser User Agent string.
*/
me.userAgent = userAgent;
/**
* A "hybrid" property, can be either accessed as a method call, for example:
*
* if (window.env.browser.is('IE')) {
* // ...
* }
*
* Or as an object with Boolean properties, for example:
*
* if (window.env.browser.is.IE) {
* // ...
* }
*
* Versions can be conveniently checked as well. For example:
*
* if (window.env.browser.is.IE10) {
* // Equivalent to (window.env.browser.is.IE && window.env.browser.version.equals(10))
* }
*
* __Note:__ Only {@link Version#getMajor major component} and {@link Version#getShortVersion simplified}
* value of the version are available via direct property checking.
*
* Supported values are:
*
* - IE
* - Firefox
* - Safari
* - Chrome
* - Opera
* - WebKit
* - Gecko
* - Presto
* - Trident
* - WebView
* - Other
*
* @param {String} name The OS name to check.
* @return {Boolean}
*/
this.is = function (name) {
// Since this function reference also acts as a map, we do not want it to be
// shared between instances, so it is defined here, not on the prototype.
return !!this.is[name];
};
// Edge has a userAgent with All browsers so we manage it separately
// "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36 Edge/12.10240"
if (/Edge\//.test(userAgent)) {
browserMatch = userAgent.match(/(Edge\/)([\w.]+)/);
}
if (browserMatch) {
browserName = browserNames[getKey(browserPrefixes, browserMatch[1])];
//<feature legacyBrowser>
if (browserName === 'Safari' && /^Opera/.test(userAgent)) {
// Prevent Opera 12 and earlier from being incorrectly reported as Safari
browserName = 'Opera';
}
//</feature>
browserVersion = new Version(browserMatch[2]);
}
if (engineMatch) {
engineName = engineNames[getKey(enginePrefixes, engineMatch[1])];
engineVersion = new Version(engineMatch[2]);
}
if (engineName === 'Trident' && browserName !== 'IE') {
browserName = 'IE';
var version = userAgent.match(/.*rv:(\d+.\d+)/);
if (version && version.length) {
version = version[1];
browserVersion = new Version(version);
}
}
/**
* @property chromeVersion
* The current version of Chrome (0 if the browser is not Chrome).
* @readonly
* @type Number
*/
/**
* @property firefoxVersion
* The current version of Firefox (0 if the browser is not Firefox).
* @readonly
* @type Number
*/
/**
* @property ieVersion
* The current version of IE (0 if the browser is not IE). This does not account
* for the documentMode of the current page, which is factored into {@link #isIE8},
* and {@link #isIE9}. Thus this is not always true:
*
* window.env.isIE8 == (window.env.ieVersion == 8)
*
* @readonly
* @type Number
*/
/**
* @property isChrome
* True if the detected browser is Chrome.
* @readonly
* @type Boolean
*/
/**
* @property isGecko
* True if the detected browser uses the Gecko layout engine (e.g. Mozilla, Firefox).
* @readonly
* @type Boolean
*/
/**
* @property isIE
* True if the detected browser is Internet Explorer.
* @readonly
* @type Boolean
*/
/**
* @property isIE8
* True if the detected browser is Internet Explorer 8.x.
* @readonly
* @type Boolean
*/
/**
* @property isIE8m
* True if the detected browser is Internet Explorer 8.x or lower.
* @readonly
* @type Boolean
*/
/**
* @property isIE8p
* True if the detected browser is Internet Explorer 8.x or higher.
* @readonly
* @type Boolean
*/
/**
* @property isIE9
* True if the detected browser is Internet Explorer 9.x.
* @readonly
* @type Boolean
*/
/**
* @property isIE9m
* True if the detected browser is Internet Explorer 9.x or lower.
* @readonly
* @type Boolean
*/
/**
* @property isIE9p
* True if the detected browser is Internet Explorer 9.x or higher.
* @readonly
* @type Boolean
*/
/**
* @property isIE10
* True if the detected browser is Internet Explorer 10.x.
* @readonly
* @type Boolean
*/
/**
* @property isIE10m
* True if the detected browser is Internet Explorer 10.x or lower.
* @readonly
* @type Boolean
*/
/**
* @property isIE10p
* True if the detected browser is Internet Explorer 10.x or higher.
* @readonly
* @type Boolean
*/
/**
* @property isIE11
* True if the detected browser is Internet Explorer 11.x.
* @readonly
* @type Boolean
*/
/**
* @property isIE11m
* True if the detected browser is Internet Explorer 11.x or lower.
* @readonly
* @type Boolean
*/
/**
* @property isIE11p
* True if the detected browser is Internet Explorer 11.x or higher.
* @readonly
* @type Boolean
*/
/**
* @property isEdge
* True if the detected browser is Edge.
* @readonly
* @type Boolean
*/
/**
* @property isLinux
* True if the detected platform is Linux.
* @readonly
* @type Boolean
*/
/**
* @property isMac
* True if the detected platform is Mac OS.
* @readonly
* @type Boolean
*/
/**
* @property isOpera
* True if the detected browser is Opera.
* @readonly
* @type Boolean
*/
/**
* @property isSafari
* True if the detected browser is Safari.
* @readonly
* @type Boolean
*/
/**
* @property isWebKit
* True if the detected browser uses WebKit.
* @readonly
* @type Boolean
*/
/**
* @property isWindows
* True if the detected platform is Windows.
* @readonly
* @type Boolean
*/
/**
* @property operaVersion
* The current version of Opera (0 if the browser is not Opera).
* @readonly
* @type Number
*/
/**
* @property safariVersion
* The current version of Safari (0 if the browser is not Safari).
* @readonly
* @type Number
*/
/**
* @property webKitVersion
* The current version of WebKit (0 if the browser does not use WebKit).
* @readonly
* @type Number
*/
// Facebook changes the userAgent when you view a website within their iOS app. For some reason, the strip out information
// about the browser, so we have to detect that and fake it...
if (userAgent.match(/FB/) && browserName === "Other") {
browserName = browserNames.safari;
engineName = engineNames.webkit;
}
if (userAgent.match(/Android.*Chrome/g)) {
browserName = 'ChromeMobile';
}
if (userAgent.match(/OPR/)) {
browserName = 'Opera';
browserMatch = userAgent.match(/OPR\/(\d+.\d+)/);
browserVersion = new Version(browserMatch[1]);
}
apply(this, {
engineName: engineName,
engineVersion: engineVersion,
name: browserName,
version: browserVersion
});
this.setFlag(browserName, true, publish); // e.g., window.env.isIE
if (browserVersion) {
majorVer = browserVersion.getMajor() || '';
//<feature legacyBrowser>
if (me.is.IE) {
majorVer = parseInt(majorVer, 10);
mode = document.documentMode;
// IE's Developer Tools allows switching of Browser Mode (userAgent) and
// Document Mode (actual behavior) independently. While this makes no real
// sense, the bottom line is that document.documentMode holds the key to
// getting the proper "version" determined. That value is always 5 when in
// Quirks Mode.
if (mode === 7 || (majorVer === 7 && mode !== 8 && mode !== 9 && mode !== 10)) {
majorVer = 7;
} else if (mode === 8 || (majorVer === 8 && mode !== 8 && mode !== 9 && mode !== 10)) {
majorVer = 8;
} else if (mode === 9 || (majorVer === 9 && mode !== 7 && mode !== 8 && mode !== 10)) {
majorVer = 9;
} else if (mode === 10 || (majorVer === 10 && mode !== 7 && mode !== 8 && mode !== 9)) {
majorVer = 10;
} else if (mode === 11 || (majorVer === 11 && mode !== 7 && mode !== 8 && mode !== 9 && mode !== 10)) {
majorVer = 11;
}
maxIEVersion = Math.max(majorVer, 12);
for (i = 7; i <= maxIEVersion; ++i) {
prefix = 'isIE' + i;
if (majorVer <= i) {
window.env[prefix + 'm'] = true;
}
if (majorVer === i) {
window.env[prefix] = true;
}
if (majorVer >= i) {
window.env[prefix + 'p'] = true;
}
}
}
if (me.is.Opera && parseInt(majorVer, 10) <= 12) {
window.env.isOpera12m = true;
}
//</feature>
window.env.chromeVersion = window.env.isChrome ? majorVer : 0;
window.env.firefoxVersion = window.env.isFirefox ? majorVer : 0;
window.env.ieVersion = window.env.isIE ? majorVer : 0;
window.env.operaVersion = window.env.isOpera ? majorVer : 0;
window.env.safariVersion = window.env.isSafari ? majorVer : 0;
window.env.webKitVersion = window.env.isWebKit ? majorVer : 0;
this.setFlag(browserName + majorVer, true, publish); // window.env.isIE10
this.setFlag(browserName + browserVersion.getShortVersion());
}
for (i in browserNames) {
if (browserNames.hasOwnProperty(i)) {
name = browserNames[i];
this.setFlag(name, browserName === name);
}
}
this.setFlag(name);
if (engineVersion) {
this.setFlag(engineName + (engineVersion.getMajor() || ''));
this.setFlag(engineName + engineVersion.getShortVersion());
}
for (i in engineNames) {
if (engineNames.hasOwnProperty(i)) {
name = engineNames[i];
this.setFlag(name, engineName === name, publish);
}
}
this.setFlag('Standalone', !!navigator.standalone);
this.setFlag('Ripple', !!document.getElementById("tinyhippos-injected") && !isEmpty(window.top.ripple));
this.setFlag('WebWorks', !!window.blackberry);
if (window.PhoneGap !== undefined || window.Cordova !== undefined || window.cordova !== undefined) {
isWebView = true;
this.setFlag('PhoneGap');
this.setFlag('Cordova');
}
// Check if running in UIWebView
if (/(iPhone|iPod|iPad).*AppleWebKit(?!.*Safari)(?!.*FBAN)/i.test(userAgent)) {
isWebView = true;
}
// Flag to check if it we are in the WebView
this.setFlag('WebView', isWebView);
/**
* @property {Boolean}
* `true` if browser is using strict mode.
*/
this.isStrict = window.env.isStrict = document.compatMode === "CSS1Compat";
/**
* @property {Boolean}
* `true` if page is running over SSL.
*/
this.isSecure = /^https/i.test(window.location.protocol);
// IE10Quirks, Chrome26Strict, etc.
this.identity = browserName + majorVer + (this.isStrict ? 'Strict' : 'Quirks');
};
window.env.Browser.prototype = {
constructor: window.env.Browser,
engineNames: {
webkit: 'WebKit',
gecko: 'Gecko',
presto: 'Presto',
trident: 'Trident',
other: 'Other'
},
enginePrefixes: {
webkit: 'AppleWebKit/',
gecko: 'Gecko/',
presto: 'Presto/',
trident: 'Trident/'
},
styleDashPrefixes: {
WebKit: '-webkit-',
Gecko: '-moz-',
Trident: '-ms-',
Presto: '-o-',
Other: ''
},
stylePrefixes: {
WebKit: 'Webkit',
Gecko: 'Moz',
Trident: 'ms',
Presto: 'O',
Other: ''
},
propertyPrefixes: {
WebKit: 'webkit',
Gecko: 'moz',
Trident: 'ms',
Presto: 'o',
Other: ''
},
// scope: window.env.Browser.prototype
/**
* The full name of the current browser.
* Possible values are:
*
* - IE
* - Firefox
* - Safari
* - Chrome
* - Opera
* - Other
* @type String
* @readonly
*/
name: null,
/**
* Refer to {@link Version}.
* @type Version
* @readonly
*/
version: null,
/**
* The full name of the current browser's engine.
* Possible values are:
*
* - WebKit
* - Gecko
* - Presto
* - Trident
* - Other
* @type String
* @readonly
*/
engineName: null,
/**
* Refer to {@link Version}.
* @type Version
* @readonly
*/
engineVersion: null,
setFlag: function(name, value, publish) {
if (value === undefined) {
value = true;
}
this.is[name] = value;
this.is[name.toLowerCase()] = value;
if (publish) {
window.env['is' + name] = value;
}
return this;
},
getStyleDashPrefix: function() {
return this.styleDashPrefixes[this.engineName];
},
getStylePrefix: function() {
return this.stylePrefixes[this.engineName];
},
getVendorProperyName: function(name) {
function capitalize (string) {
if (string) {
string = string.charAt(0).toUpperCase() + string.substr(1);
}
return string || '';
}
var prefix = this.propertyPrefixes[this.engineName];
if (prefix.length > 0) {
return prefix + capitalize(name);
}
return name;
},
getPreferredTranslationMethod: function(config) {
if (typeof config === 'object' && 'translationMethod' in config && config.translationMethod !== 'auto') {
return config.translationMethod;
} else {
return 'csstransform';
}
}
};
/**
* @class window.env.browser
* @extends window.env.Browser
* @singleton
* Provides useful information about the current browser.
*
* Example:
*
* if (window.env.browser.is.IE) {
* // IE specific code here
* }
*
* if (window.env.browser.is.WebKit) {
* // WebKit specific code here
* }
*
* console.log("Version " + window.env.browser.version);
*
* For a full list of supported values, refer to {@link #is} property/method.
*
*/
;(function (userAgent) {
window.env.browser = new window.env.Browser(userAgent, true);
window.env.userAgent = userAgent.toLowerCase();
/**
* @property {String} SSL_SECURE_URL
* URL to a blank file used when in secure mode for iframe src and onReady src
* to prevent the IE insecure content warning (`'about:blank'`, except for IE
* in secure mode, which is `'javascript:""'`).
*/
window.env.SSL_SECURE_URL = /^https/i.test(window.location.protocol) && window.env.isIE ? 'javascript:\'\'' : 'about:blank'; // jshint ignore:line
})(window.navigator.userAgent);
console.log(window.env.browser.name);
console.log(window.env.browser.version.version);
* @class window.env.Browser
* Provides information about browser.
*
* Should not be manually instantiated unless for unit-testing.
* Access the global instance stored in {@link window.env.browser} instead.
* @private
*/
;(window.env || (window.env = {})).Browser = function (userAgent, publish) {
// @define window.env.Browser
// @define window.env.browser
function isEmpty (value, allowEmptyString) {
return (value === undefined || value === null) || (!allowEmptyString ? value === '' : false) || (isArray(value) && value.length === 0);
}
function isArray (value) {
return Object.prototype.toString.call(value) === '[object Array]';
}
function apply (object, config, defaults) {
var enumerables = ['valueOf', 'toLocaleString', 'toString', 'constructor'];
if (defaults) {
apply(object, defaults);
}
if (object && config && typeof config === 'object') {
var i, j, k;
for (i in config) {
if (config.hasOwnProperty(i)) {
object[i] = config[i];
}
}
if (enumerables) {
for (j = enumerables.length; j--;) {
k = enumerables[j];
if (config.hasOwnProperty(k)) {
object[k] = config[k];
}
}
}
}
return object;
}
function getValues (object) {
var values = [],
property;
for (property in object) {
if (object.hasOwnProperty(property)) {
values.push(object[property]);
}
}
return values;
}
function getKey (object, value) {
for (var property in object) {
if (object.hasOwnProperty(property) && object[property] === value) {
return property;
}
}
return null;
}
function Version (version) {
var me = this,
padModes = me.padModes,
ch, i, pad, parts, release, releaseStartIndex, ver;
me.version = ver = String(version).toLowerCase().replace(/_/g, '.').replace(/[\-+]/g, '');
ch = ver.charAt(0);
if (ch in padModes) {
ver = ver.substring(1);
pad = padModes[ch];
} else {
pad = 0;
}
me.pad = pad;
releaseStartIndex = ver.search(/([^\d\.])/);
me.shortVersion = ver;
if (releaseStartIndex !== -1) {
me.release = release = ver.substr(releaseStartIndex, version.length);
me.shortVersion = ver.substr(0, releaseStartIndex);
release = Version.releaseValueMap[release] || release;
}
me.releaseValue = release || pad;
me.shortVersion = me.shortVersion.replace(/[^\d]/g, '');
/**
* @property {Number[]} parts
* The split array of version number components found in the version string.
* For example, for "1.2.3", this would be `[1, 2, 3]`.
* @readonly
* @private
*/
me.parts = parts = ver.split('.');
for (i = parts.length; i--;) {
parts[i] = parseInt(parts[i], 10);
}
if (pad === Infinity) {
// have to add this to the end to create an upper bound:
parts.push(pad);
}
/**
* @property {Number} major
* The first numeric part of the version number string.
* @readonly
*/
me.major = parts[0] || pad;
return me;
}
Version.releaseValueMap = {
dev: -6,
alpha: -5,
a: -5,
beta: -4,
b: -4,
rc: -3,
'#': -2,
p: -1,
pl: -1
};
Version.prototype = {
padModes: {
'~': NaN,
'^': Infinity
},
/**
* Returns the major component value.
* @return {Number}
*/
getMajor: function() {
return this.major;
},
/**
* Returns shortVersion version without dots and release
* @return {String}
*/
getShortVersion: function() {
return this.shortVersion;
}
};
var me = this,
browserPrefixes = {
ie: 'MSIE ',
edge: 'Edge/',
firefox: 'Firefox/',
chrome: 'Chrome/',
safari: 'Version/',
opera: 'OPR/',
dolfin: 'Dolfin/',
webosbrowser: 'wOSBrowser/',
chromeMobile: 'CrMo/',
chromeiOS: 'CriOS/',
silk: 'Silk/'
},
browserNames = {
ie: 'IE',
firefox: 'Firefox',
safari: 'Safari',
chrome: 'Chrome',
opera: 'Opera',
dolfin: 'Dolfin',
edge: 'Edge',
webosbrowser: 'webOSBrowser',
chromeMobile: 'ChromeMobile',
chromeiOS: 'ChromeiOS',
silk: 'Silk',
other: 'Other'
},
enginePrefixes = me.enginePrefixes,
engineNames = me.engineNames,
browserMatch = userAgent.match(new RegExp('((?:' + getValues(browserPrefixes).join(')|(?:') + '))([\\w\\._]+)')),
engineMatch = userAgent.match(new RegExp('((?:' + getValues(enginePrefixes).join(')|(?:') + '))([\\w\\._]+)')),
browserName = browserNames.other,
engineName = engineNames.other,
browserVersion = '',
engineVersion = '',
majorVer = '',
isWebView = false,
i, prefix, mode, name, maxIEVersion;
/**
* @property {String}
* Browser User Agent string.
*/
me.userAgent = userAgent;
/**
* A "hybrid" property, can be either accessed as a method call, for example:
*
* if (window.env.browser.is('IE')) {
* // ...
* }
*
* Or as an object with Boolean properties, for example:
*
* if (window.env.browser.is.IE) {
* // ...
* }
*
* Versions can be conveniently checked as well. For example:
*
* if (window.env.browser.is.IE10) {
* // Equivalent to (window.env.browser.is.IE && window.env.browser.version.equals(10))
* }
*
* __Note:__ Only {@link Version#getMajor major component} and {@link Version#getShortVersion simplified}
* value of the version are available via direct property checking.
*
* Supported values are:
*
* - IE
* - Firefox
* - Safari
* - Chrome
* - Opera
* - WebKit
* - Gecko
* - Presto
* - Trident
* - WebView
* - Other
*
* @param {String} name The OS name to check.
* @return {Boolean}
*/
this.is = function (name) {
// Since this function reference also acts as a map, we do not want it to be
// shared between instances, so it is defined here, not on the prototype.
return !!this.is[name];
};
// Edge has a userAgent with All browsers so we manage it separately
// "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36 Edge/12.10240"
if (/Edge\//.test(userAgent)) {
browserMatch = userAgent.match(/(Edge\/)([\w.]+)/);
}
if (browserMatch) {
browserName = browserNames[getKey(browserPrefixes, browserMatch[1])];
//<feature legacyBrowser>
if (browserName === 'Safari' && /^Opera/.test(userAgent)) {
// Prevent Opera 12 and earlier from being incorrectly reported as Safari
browserName = 'Opera';
}
//</feature>
browserVersion = new Version(browserMatch[2]);
}
if (engineMatch) {
engineName = engineNames[getKey(enginePrefixes, engineMatch[1])];
engineVersion = new Version(engineMatch[2]);
}
if (engineName === 'Trident' && browserName !== 'IE') {
browserName = 'IE';
var version = userAgent.match(/.*rv:(\d+.\d+)/);
if (version && version.length) {
version = version[1];
browserVersion = new Version(version);
}
}
/**
* @property chromeVersion
* The current version of Chrome (0 if the browser is not Chrome).
* @readonly
* @type Number
*/
/**
* @property firefoxVersion
* The current version of Firefox (0 if the browser is not Firefox).
* @readonly
* @type Number
*/
/**
* @property ieVersion
* The current version of IE (0 if the browser is not IE). This does not account
* for the documentMode of the current page, which is factored into {@link #isIE8},
* and {@link #isIE9}. Thus this is not always true:
*
* window.env.isIE8 == (window.env.ieVersion == 8)
*
* @readonly
* @type Number
*/
/**
* @property isChrome
* True if the detected browser is Chrome.
* @readonly
* @type Boolean
*/
/**
* @property isGecko
* True if the detected browser uses the Gecko layout engine (e.g. Mozilla, Firefox).
* @readonly
* @type Boolean
*/
/**
* @property isIE
* True if the detected browser is Internet Explorer.
* @readonly
* @type Boolean
*/
/**
* @property isIE8
* True if the detected browser is Internet Explorer 8.x.
* @readonly
* @type Boolean
*/
/**
* @property isIE8m
* True if the detected browser is Internet Explorer 8.x or lower.
* @readonly
* @type Boolean
*/
/**
* @property isIE8p
* True if the detected browser is Internet Explorer 8.x or higher.
* @readonly
* @type Boolean
*/
/**
* @property isIE9
* True if the detected browser is Internet Explorer 9.x.
* @readonly
* @type Boolean
*/
/**
* @property isIE9m
* True if the detected browser is Internet Explorer 9.x or lower.
* @readonly
* @type Boolean
*/
/**
* @property isIE9p
* True if the detected browser is Internet Explorer 9.x or higher.
* @readonly
* @type Boolean
*/
/**
* @property isIE10
* True if the detected browser is Internet Explorer 10.x.
* @readonly
* @type Boolean
*/
/**
* @property isIE10m
* True if the detected browser is Internet Explorer 10.x or lower.
* @readonly
* @type Boolean
*/
/**
* @property isIE10p
* True if the detected browser is Internet Explorer 10.x or higher.
* @readonly
* @type Boolean
*/
/**
* @property isIE11
* True if the detected browser is Internet Explorer 11.x.
* @readonly
* @type Boolean
*/
/**
* @property isIE11m
* True if the detected browser is Internet Explorer 11.x or lower.
* @readonly
* @type Boolean
*/
/**
* @property isIE11p
* True if the detected browser is Internet Explorer 11.x or higher.
* @readonly
* @type Boolean
*/
/**
* @property isEdge
* True if the detected browser is Edge.
* @readonly
* @type Boolean
*/
/**
* @property isLinux
* True if the detected platform is Linux.
* @readonly
* @type Boolean
*/
/**
* @property isMac
* True if the detected platform is Mac OS.
* @readonly
* @type Boolean
*/
/**
* @property isOpera
* True if the detected browser is Opera.
* @readonly
* @type Boolean
*/
/**
* @property isSafari
* True if the detected browser is Safari.
* @readonly
* @type Boolean
*/
/**
* @property isWebKit
* True if the detected browser uses WebKit.
* @readonly
* @type Boolean
*/
/**
* @property isWindows
* True if the detected platform is Windows.
* @readonly
* @type Boolean
*/
/**
* @property operaVersion
* The current version of Opera (0 if the browser is not Opera).
* @readonly
* @type Number
*/
/**
* @property safariVersion
* The current version of Safari (0 if the browser is not Safari).
* @readonly
* @type Number
*/
/**
* @property webKitVersion
* The current version of WebKit (0 if the browser does not use WebKit).
* @readonly
* @type Number
*/
// Facebook changes the userAgent when you view a website within their iOS app. For some reason, the strip out information
// about the browser, so we have to detect that and fake it...
if (userAgent.match(/FB/) && browserName === "Other") {
browserName = browserNames.safari;
engineName = engineNames.webkit;
}
if (userAgent.match(/Android.*Chrome/g)) {
browserName = 'ChromeMobile';
}
if (userAgent.match(/OPR/)) {
browserName = 'Opera';
browserMatch = userAgent.match(/OPR\/(\d+.\d+)/);
browserVersion = new Version(browserMatch[1]);
}
apply(this, {
engineName: engineName,
engineVersion: engineVersion,
name: browserName,
version: browserVersion
});
this.setFlag(browserName, true, publish); // e.g., window.env.isIE
if (browserVersion) {
majorVer = browserVersion.getMajor() || '';
//<feature legacyBrowser>
if (me.is.IE) {
majorVer = parseInt(majorVer, 10);
mode = document.documentMode;
// IE's Developer Tools allows switching of Browser Mode (userAgent) and
// Document Mode (actual behavior) independently. While this makes no real
// sense, the bottom line is that document.documentMode holds the key to
// getting the proper "version" determined. That value is always 5 when in
// Quirks Mode.
if (mode === 7 || (majorVer === 7 && mode !== 8 && mode !== 9 && mode !== 10)) {
majorVer = 7;
} else if (mode === 8 || (majorVer === 8 && mode !== 8 && mode !== 9 && mode !== 10)) {
majorVer = 8;
} else if (mode === 9 || (majorVer === 9 && mode !== 7 && mode !== 8 && mode !== 10)) {
majorVer = 9;
} else if (mode === 10 || (majorVer === 10 && mode !== 7 && mode !== 8 && mode !== 9)) {
majorVer = 10;
} else if (mode === 11 || (majorVer === 11 && mode !== 7 && mode !== 8 && mode !== 9 && mode !== 10)) {
majorVer = 11;
}
maxIEVersion = Math.max(majorVer, 12);
for (i = 7; i <= maxIEVersion; ++i) {
prefix = 'isIE' + i;
if (majorVer <= i) {
window.env[prefix + 'm'] = true;
}
if (majorVer === i) {
window.env[prefix] = true;
}
if (majorVer >= i) {
window.env[prefix + 'p'] = true;
}
}
}
if (me.is.Opera && parseInt(majorVer, 10) <= 12) {
window.env.isOpera12m = true;
}
//</feature>
window.env.chromeVersion = window.env.isChrome ? majorVer : 0;
window.env.firefoxVersion = window.env.isFirefox ? majorVer : 0;
window.env.ieVersion = window.env.isIE ? majorVer : 0;
window.env.operaVersion = window.env.isOpera ? majorVer : 0;
window.env.safariVersion = window.env.isSafari ? majorVer : 0;
window.env.webKitVersion = window.env.isWebKit ? majorVer : 0;
this.setFlag(browserName + majorVer, true, publish); // window.env.isIE10
this.setFlag(browserName + browserVersion.getShortVersion());
}
for (i in browserNames) {
if (browserNames.hasOwnProperty(i)) {
name = browserNames[i];
this.setFlag(name, browserName === name);
}
}
this.setFlag(name);
if (engineVersion) {
this.setFlag(engineName + (engineVersion.getMajor() || ''));
this.setFlag(engineName + engineVersion.getShortVersion());
}
for (i in engineNames) {
if (engineNames.hasOwnProperty(i)) {
name = engineNames[i];
this.setFlag(name, engineName === name, publish);
}
}
this.setFlag('Standalone', !!navigator.standalone);
this.setFlag('Ripple', !!document.getElementById("tinyhippos-injected") && !isEmpty(window.top.ripple));
this.setFlag('WebWorks', !!window.blackberry);
if (window.PhoneGap !== undefined || window.Cordova !== undefined || window.cordova !== undefined) {
isWebView = true;
this.setFlag('PhoneGap');
this.setFlag('Cordova');
}
// Check if running in UIWebView
if (/(iPhone|iPod|iPad).*AppleWebKit(?!.*Safari)(?!.*FBAN)/i.test(userAgent)) {
isWebView = true;
}
// Flag to check if it we are in the WebView
this.setFlag('WebView', isWebView);
/**
* @property {Boolean}
* `true` if browser is using strict mode.
*/
this.isStrict = window.env.isStrict = document.compatMode === "CSS1Compat";
/**
* @property {Boolean}
* `true` if page is running over SSL.
*/
this.isSecure = /^https/i.test(window.location.protocol);
// IE10Quirks, Chrome26Strict, etc.
this.identity = browserName + majorVer + (this.isStrict ? 'Strict' : 'Quirks');
};
window.env.Browser.prototype = {
constructor: window.env.Browser,
engineNames: {
webkit: 'WebKit',
gecko: 'Gecko',
presto: 'Presto',
trident: 'Trident',
other: 'Other'
},
enginePrefixes: {
webkit: 'AppleWebKit/',
gecko: 'Gecko/',
presto: 'Presto/',
trident: 'Trident/'
},
styleDashPrefixes: {
WebKit: '-webkit-',
Gecko: '-moz-',
Trident: '-ms-',
Presto: '-o-',
Other: ''
},
stylePrefixes: {
WebKit: 'Webkit',
Gecko: 'Moz',
Trident: 'ms',
Presto: 'O',
Other: ''
},
propertyPrefixes: {
WebKit: 'webkit',
Gecko: 'moz',
Trident: 'ms',
Presto: 'o',
Other: ''
},
// scope: window.env.Browser.prototype
/**
* The full name of the current browser.
* Possible values are:
*
* - IE
* - Firefox
* - Safari
* - Chrome
* - Opera
* - Other
* @type String
* @readonly
*/
name: null,
/**
* Refer to {@link Version}.
* @type Version
* @readonly
*/
version: null,
/**
* The full name of the current browser's engine.
* Possible values are:
*
* - WebKit
* - Gecko
* - Presto
* - Trident
* - Other
* @type String
* @readonly
*/
engineName: null,
/**
* Refer to {@link Version}.
* @type Version
* @readonly
*/
engineVersion: null,
setFlag: function(name, value, publish) {
if (value === undefined) {
value = true;
}
this.is[name] = value;
this.is[name.toLowerCase()] = value;
if (publish) {
window.env['is' + name] = value;
}
return this;
},
getStyleDashPrefix: function() {
return this.styleDashPrefixes[this.engineName];
},
getStylePrefix: function() {
return this.stylePrefixes[this.engineName];
},
getVendorProperyName: function(name) {
function capitalize (string) {
if (string) {
string = string.charAt(0).toUpperCase() + string.substr(1);
}
return string || '';
}
var prefix = this.propertyPrefixes[this.engineName];
if (prefix.length > 0) {
return prefix + capitalize(name);
}
return name;
},
getPreferredTranslationMethod: function(config) {
if (typeof config === 'object' && 'translationMethod' in config && config.translationMethod !== 'auto') {
return config.translationMethod;
} else {
return 'csstransform';
}
}
};
/**
* @class window.env.browser
* @extends window.env.Browser
* @singleton
* Provides useful information about the current browser.
*
* Example:
*
* if (window.env.browser.is.IE) {
* // IE specific code here
* }
*
* if (window.env.browser.is.WebKit) {
* // WebKit specific code here
* }
*
* console.log("Version " + window.env.browser.version);
*
* For a full list of supported values, refer to {@link #is} property/method.
*
*/
;(function (userAgent) {
window.env.browser = new window.env.Browser(userAgent, true);
window.env.userAgent = userAgent.toLowerCase();
/**
* @property {String} SSL_SECURE_URL
* URL to a blank file used when in secure mode for iframe src and onReady src
* to prevent the IE insecure content warning (`'about:blank'`, except for IE
* in secure mode, which is `'javascript:""'`).
*/
window.env.SSL_SECURE_URL = /^https/i.test(window.location.protocol) && window.env.isIE ? 'javascript:\'\'' : 'about:blank'; // jshint ignore:line
})(window.navigator.userAgent);
console.log(window.env.browser.name);
console.log(window.env.browser.version.version);
четверг, 7 июля 2016 г.
Parse XML to JSON
var xml = '<?xml version="1.0" encoding="UTF-8"?>'
+ '<catalog>'
+ '<book id="bk101">'
+ '<author>Gambardella, Matthew</author>'
+ '<title>XML Developer\'s Guide</title>'
+ '<genre>Computer</genre>'
+ '<price>44.95</price>'
+ '<publish_date>2000-10-01</publish_date>'
+ '<description>An in-depth look at creating applications with XML.</description>'
+ '</book>'
+ '</catalog>';
function parseXML (data) {
var xml, tmp;
if (!data || typeof data !== "string") {
return null;
}
try {
if (window.DOMParser) { // Standard
tmp = new DOMParser();
xml = tmp.parseFromString(data, "text/xml");
} else { // IE
xml = new ActiveXObject("Microsoft.XMLDOM");
xml.async = "false";
xml.loadXML(data);
}
} catch(e) {
xml = undefined;
}
if (!xml || !xml.documentElement || xml.getElementsByTagName("parsererror").length) {
throw new Error("Invalid XML: " + data);
}
return xml;
}
// Changes XML to JSON
function xmlToJson(xml) {
// Create the return object
var obj = {};
if (xml.nodeType == 1) { // element
// do attributes
if (xml.attributes.length > 0) {
obj["@attributes"] = {};
for (var j = 0; j < xml.attributes.length; j++) {
var attribute = xml.attributes.item(j);
obj["@attributes"][attribute.nodeName] = attribute.nodeValue;
}
}
} else if (xml.nodeType == 3) { // text
obj = xml.nodeValue;
}
// do children
if (xml.hasChildNodes()) {
for(var i = 0; i < xml.childNodes.length; i++) {
var item = xml.childNodes.item(i);
var nodeName = item.nodeName;
if (typeof(obj[nodeName]) == "undefined") {
obj[nodeName] = xmlToJson(item);
} else {
if (typeof(obj[nodeName].push) == "undefined") {
var old = obj[nodeName];
obj[nodeName] = [];
obj[nodeName].push(old);
}
obj[nodeName].push(xmlToJson(item));
}
}
}
return obj;
}
function convertObjectToHtmlText (obj, options) {
var indentString = ' '
, newLine = '<br />'
, newLineJoin = ',' + newLine;
if (options && options.rawHTML) {
indentString = ' '; // 4 пробела
newLine = '\n';
newLineJoin = ',' + newLine;
}
// Функция определения типа объекта
function objectType (obj) {
var types = {
'null': 'null'
, 'undefined': 'undefined'
, 'number': 'number'
, 'boolean': 'boolean'
, 'string': 'string'
, '[object Function]': 'function'
, '[object RegExp]': 'regexp'
, '[object Array]': 'array'
, '[object Date]': 'date'
, '[object Error]': 'error'
};
return types[typeof obj] || types[Object.prototype.toString.call(obj)] || (obj ? 'object' : 'null');
}
// Функция определения числа элементов в объекте
function objectSize (obj) {
var size = 0
, key;
for (key in obj) {
if (obj.hasOwnProperty(key)) {size++;}
}
return size;
}
// Привести элемент к нужному формату
function formatElement (element, indent, indentFromArray) {
indentFromArray = indentFromArray || '';
switch (objectType(element)) {
case 'null': return indentFromArray + 'null';
case 'undefined': return indentFromArray + 'undefined';
case 'number': return indentFromArray + element;
case 'boolean': return indentFromArray + (element ? 'true' : 'false');
case 'string': if (options && options.rawHTML) {
return indentFromArray + '"'
+ element
+ '"';
} else {
return indentFromArray + '"'
+ element.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/, '"')
.replace(/'/g, ''')
+ '"';
}
case 'array': return indentFromArray + (element.length > 0 ? '[' + newLine + formatArray(element, indent) + indent + ']' : '[]');
case 'object': return indentFromArray + (objectSize(element) > 0 ? '{' + newLine + formatObject(element, indent) + indent + '}' : '{}');
default: return indentFromArray + element.toString();
}
}
// Привести массив к нужному формату
function formatArray (array, indent) {
var index
, length = array.length
, value = [];
indent += indentString;
for (index = 0; index < length; index += 1) {
value.push(formatElement(array[index], indent, indent));
}
return value.join(newLineJoin) + newLine;
}
// Привести объект к нужному формату
function formatObject (object, indent) {
var value = []
, property;
indent += indentString;
for (property in object) {
if (object.hasOwnProperty(property)) {
if (options && options.rawHTML) {
value.push(indent + '"' + property + '": ' + formatElement(object[property], indent));
} else {
value.push(indent + '"' + property + '": ' + formatElement(object[property], indent));
}
}
}
return value.join(newLineJoin) + newLine;
}
if (typeof obj === 'object') {return formatElement(obj, '');
} else {throw new Error ('No javascript object has been provided to function convertObjectToHtmlText (obj) {...}');
}
}
console.log(JSON.stringify(xmlToJson(parseXML(xml))));
console.log(convertObjectToHtmlText (xmlToJson(parseXML(xml)), {rawHTML: true}));
+ '<catalog>'
+ '<book id="bk101">'
+ '<author>Gambardella, Matthew</author>'
+ '<title>XML Developer\'s Guide</title>'
+ '<genre>Computer</genre>'
+ '<price>44.95</price>'
+ '<publish_date>2000-10-01</publish_date>'
+ '<description>An in-depth look at creating applications with XML.</description>'
+ '</book>'
+ '</catalog>';
function parseXML (data) {
var xml, tmp;
if (!data || typeof data !== "string") {
return null;
}
try {
if (window.DOMParser) { // Standard
tmp = new DOMParser();
xml = tmp.parseFromString(data, "text/xml");
} else { // IE
xml = new ActiveXObject("Microsoft.XMLDOM");
xml.async = "false";
xml.loadXML(data);
}
} catch(e) {
xml = undefined;
}
if (!xml || !xml.documentElement || xml.getElementsByTagName("parsererror").length) {
throw new Error("Invalid XML: " + data);
}
return xml;
}
// Changes XML to JSON
function xmlToJson(xml) {
// Create the return object
var obj = {};
if (xml.nodeType == 1) { // element
// do attributes
if (xml.attributes.length > 0) {
obj["@attributes"] = {};
for (var j = 0; j < xml.attributes.length; j++) {
var attribute = xml.attributes.item(j);
obj["@attributes"][attribute.nodeName] = attribute.nodeValue;
}
}
} else if (xml.nodeType == 3) { // text
obj = xml.nodeValue;
}
// do children
if (xml.hasChildNodes()) {
for(var i = 0; i < xml.childNodes.length; i++) {
var item = xml.childNodes.item(i);
var nodeName = item.nodeName;
if (typeof(obj[nodeName]) == "undefined") {
obj[nodeName] = xmlToJson(item);
} else {
if (typeof(obj[nodeName].push) == "undefined") {
var old = obj[nodeName];
obj[nodeName] = [];
obj[nodeName].push(old);
}
obj[nodeName].push(xmlToJson(item));
}
}
}
return obj;
}
function convertObjectToHtmlText (obj, options) {
var indentString = ' '
, newLine = '<br />'
, newLineJoin = ',' + newLine;
if (options && options.rawHTML) {
indentString = ' '; // 4 пробела
newLine = '\n';
newLineJoin = ',' + newLine;
}
// Функция определения типа объекта
function objectType (obj) {
var types = {
'null': 'null'
, 'undefined': 'undefined'
, 'number': 'number'
, 'boolean': 'boolean'
, 'string': 'string'
, '[object Function]': 'function'
, '[object RegExp]': 'regexp'
, '[object Array]': 'array'
, '[object Date]': 'date'
, '[object Error]': 'error'
};
return types[typeof obj] || types[Object.prototype.toString.call(obj)] || (obj ? 'object' : 'null');
}
// Функция определения числа элементов в объекте
function objectSize (obj) {
var size = 0
, key;
for (key in obj) {
if (obj.hasOwnProperty(key)) {size++;}
}
return size;
}
// Привести элемент к нужному формату
function formatElement (element, indent, indentFromArray) {
indentFromArray = indentFromArray || '';
switch (objectType(element)) {
case 'null': return indentFromArray + 'null';
case 'undefined': return indentFromArray + 'undefined';
case 'number': return indentFromArray + element;
case 'boolean': return indentFromArray + (element ? 'true' : 'false');
case 'string': if (options && options.rawHTML) {
return indentFromArray + '"'
+ element
+ '"';
} else {
return indentFromArray + '"'
+ element.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/, '"')
.replace(/'/g, ''')
+ '"';
}
case 'array': return indentFromArray + (element.length > 0 ? '[' + newLine + formatArray(element, indent) + indent + ']' : '[]');
case 'object': return indentFromArray + (objectSize(element) > 0 ? '{' + newLine + formatObject(element, indent) + indent + '}' : '{}');
default: return indentFromArray + element.toString();
}
}
// Привести массив к нужному формату
function formatArray (array, indent) {
var index
, length = array.length
, value = [];
indent += indentString;
for (index = 0; index < length; index += 1) {
value.push(formatElement(array[index], indent, indent));
}
return value.join(newLineJoin) + newLine;
}
// Привести объект к нужному формату
function formatObject (object, indent) {
var value = []
, property;
indent += indentString;
for (property in object) {
if (object.hasOwnProperty(property)) {
if (options && options.rawHTML) {
value.push(indent + '"' + property + '": ' + formatElement(object[property], indent));
} else {
value.push(indent + '"' + property + '": ' + formatElement(object[property], indent));
}
}
}
return value.join(newLineJoin) + newLine;
}
if (typeof obj === 'object') {return formatElement(obj, '');
} else {throw new Error ('No javascript object has been provided to function convertObjectToHtmlText (obj) {...}');
}
}
console.log(JSON.stringify(xmlToJson(parseXML(xml))));
console.log(convertObjectToHtmlText (xmlToJson(parseXML(xml)), {rawHTML: true}));
Подписаться на:
Сообщения (Atom)