pip-webui
Version:
HTML5 UI for LOB applications
464 lines (402 loc) • 18.9 kB
JavaScript
/**
* @file General purpose utilities
* @copyright Digital Living Software Corp. 2014-2016
*/
/* global _, $, angular */
(function () {
'use strict';
var thisModule = angular.module('pipUtils.General', ['pipState', 'pipAssert']);
thisModule.factory('pipUtils', function ($rootScope, $window, $state, pipAssert) {
function strRepeat(str, qty) {
if (qty < 1) return '';
var result = '';
while (qty > 0) {
if (qty & 1) result += str;
qty >>= 1, str += str;
}
return result;
}
var toString = Object.prototype.toString;
var sprintf = (function sprintf() {
function get_type(variable) {
return toString.call(variable).slice(8, -1).toLowerCase();
}
var str_repeat = strRepeat;
var str_format = function() {
if (!str_format.cache.hasOwnProperty(arguments[0])) {
str_format.cache[arguments[0]] = str_format.parse(arguments[0]);
}
return str_format.format.call(null, str_format.cache[arguments[0]], arguments);
};
str_format.format = function(parse_tree, argv) {
var cursor = 1, tree_length = parse_tree.length, node_type = '', arg, output = [], i, k, match, pad, pad_character, pad_length;
for (i = 0; i < tree_length; i++) {
node_type = get_type(parse_tree[i]);
if (node_type === 'string') {
output.push(parse_tree[i]);
}
else if (node_type === 'array') {
match = parse_tree[i]; // convenience purposes only
if (match[2]) { // keyword argument
arg = argv[cursor];
for (k = 0; k < match[2].length; k++) {
if (!arg.hasOwnProperty(match[2][k])) {
throw new Error(sprintf('[_.sprintf] property "%s" does not exist', match[2][k]));
}
arg = arg[match[2][k]];
}
} else if (match[1]) { // positional argument (explicit)
arg = argv[match[1]];
}
else { // positional argument (implicit)
arg = argv[cursor++];
}
if (/[^s]/.test(match[8]) && (get_type(arg) != 'number')) {
throw new Error(sprintf('[_.sprintf] expecting number but found %s', get_type(arg)));
}
switch (match[8]) {
case 'b': arg = arg.toString(2); break;
case 'c': arg = String.fromCharCode(arg); break;
case 'd': arg = parseInt(arg, 10); break;
case 'e': arg = match[7] ? arg.toExponential(match[7]) : arg.toExponential(); break;
case 'f': arg = match[7] ? parseFloat(arg).toFixed(match[7]) : parseFloat(arg); break;
case 'o': arg = arg.toString(8); break;
case 's': arg = ((arg = String(arg)) && match[7] ? arg.substring(0, match[7]) : arg); break;
case 'u': arg = Math.abs(arg); break;
case 'x': arg = arg.toString(16); break;
case 'X': arg = arg.toString(16).toUpperCase(); break;
}
arg = (/[def]/.test(match[8]) && match[3] && arg >= 0 ? '+'+ arg : arg);
pad_character = match[4] ? match[4] == '0' ? '0' : match[4].charAt(1) : ' ';
pad_length = match[6] - String(arg).length;
pad = match[6] ? str_repeat(pad_character, pad_length) : '';
output.push(match[5] ? arg + pad : pad + arg);
}
}
return output.join('');
};
str_format.cache = {};
str_format.parse = function(fmt) {
var _fmt = fmt, match = [], parse_tree = [], arg_names = 0;
while (_fmt) {
if ((match = /^[^\x25]+/.exec(_fmt)) !== null) {
parse_tree.push(match[0]);
}
else if ((match = /^\x25{2}/.exec(_fmt)) !== null) {
parse_tree.push('%');
}
else if ((match = /^\x25(?:([1-9]\d*)\$|\(([^\)]+)\))?(\+)?(0|'[^$])?(-)?(\d+)?(?:\.(\d+))?([b-fosuxX])/.exec(_fmt)) !== null) {
if (match[2]) {
arg_names |= 1;
var field_list = [], replacement_field = match[2], field_match = [];
if ((field_match = /^([a-z_][a-z_\d]*)/i.exec(replacement_field)) !== null) {
field_list.push(field_match[1]);
while ((replacement_field = replacement_field.substring(field_match[0].length)) !== '') {
if ((field_match = /^\.([a-z_][a-z_\d]*)/i.exec(replacement_field)) !== null) {
field_list.push(field_match[1]);
}
else if ((field_match = /^\[(\d+)\]/.exec(replacement_field)) !== null) {
field_list.push(field_match[1]);
}
else {
throw new Error('[_.sprintf] huh?');
}
}
}
else {
throw new Error('[_.sprintf] huh?');
}
match[2] = field_list;
}
else {
arg_names |= 2;
}
if (arg_names === 3) {
throw new Error('[_.sprintf] mixing positional and named placeholders is not (yet) supported');
}
parse_tree.push(match);
}
else {
throw new Error('[_.sprintf] huh?');
}
_fmt = _fmt.substring(match[0].length);
}
return parse_tree;
};
return str_format;
})();
return {
copyProperty: copyProperty,
copy: copyProperty,
swapProperties: swapProperties,
swap: swapProperties,
convertToBoolean: convertToBoolean,
toBoolean: convertToBoolean,
toBool: convertToBoolean,
convertObjectIdsToString: convertObjectIdsToString,
OidToString: convertObjectIdsToString,
generateVerificationCode: generateVerificationCode,
vercode: generateVerificationCode,
goBack: goBack,
goBackAndSelect: goBackAndSelect,
scrollTo: scrollTo,
equalObjectIds: equalObjectIds,
eqOid: equalObjectIds,
notEqualObjectIds: notEqualObjectIds,
neqOid: notEqualObjectIds,
containsObjectId: containsObjectId,
hasOid: containsObjectId,
isObjectId: isObjectId,
// Strings functions. No analogues in lodash.strings
sampleLine: sampleLine,
hashCode: hashCode,
makeString: makeString,
getBrowser: getBrowser,
checkSupported: checkSupported,
sprintf: sprintf,
// Collection function. No analogues in lodash. It may be in lodash later. Look gitHub/lodash issue #1022
replaceBy: replaceBy
};
//--------------------
function replaceBy(items, key, value, data) {
if (!items || !items.length)
return null;
for (var i = 0; i < items.length; i++) {
if (items[i][key] == value) {
items[i] = data;
return;
}
}
};
// Creates a sample line from a text
function sampleLine(value, maxLength) {
if (!value || value == '') return '';
var length = value.indexOf('\n');
length = length >= 0 ? length : value.length;
length = length < maxLength ? value.length : maxLength;
return value.substring(0, length);
};
// Simple version of string hashcode
function hashCode(value) {
if (value == null) return 0;
var result = 0;
for (var i = 0; i < value.length; i++) {
result += value.charCodeAt(i);
}
return result;
};
// Ensure some object is a coerced to a string
function makeString(object) {
if (object == null) return '';
return '' + object;
};
function isObjectId(value) {
var checkForHexRegExp = new RegExp("^[0-9a-fA-F]{24}$");
return checkForHexRegExp.test(value);
}
// Compares two ObjectIds (they are not equal by '==')
function equalObjectIds(value1, value2) {
if (value1 == null && value2 == null)
return true;
if (value1 == null || value2 == null)
return false;
return value1.toString() == value2.toString();
};
// Compares two ObjectIds (they are always not equal by '!=')
function notEqualObjectIds(value1, value2) {
if (value1 == null && value2 == null)
return false;
if (value1 == null || value2 == null)
return true;
return value1.toString() != value2.toString();
};
// Checks if array contains concrete objectId
function containsObjectId(values, value) {
return _.some(values, function (value1) {
return equalObjectIds(value1, value);
});
};
// Copy property from one object to another if it exists (not null)
function copyProperty(dest, destProperty, orig, origProperty) {
// Shift if only 3 arguments set
if (_.isObject(destProperty)
&& typeof (origProperty) == 'undefined') {
origProperty = orig;
orig = destProperty;
destProperty = origProperty;
}
if (orig[origProperty] || (typeof (orig[origProperty]) === 'number' && orig[origProperty] % 1 == 0)) {
dest[destProperty] = orig[origProperty];
return true;
}
return false;
};
// Swaps values of two properties
function swapProperties(obj, prop1, prop2) {
var
temp1 = obj[prop1],
temp2 = obj[prop2];
if (temp1) {
obj[prop2] = temp1;
}
else {
delete obj[prop2];
}
if (temp2) {
obj[prop1] = temp2;
}
else {
delete obj[prop1];
}
};
// Converts value into boolean
function convertToBoolean(value) {
if (value == null) return false;
if (!value) return false;
value = value.toString().toLowerCase();
return value == '1' || value == 'true';
};
// Converts array of object ids to strings (for comparison)
function convertObjectIdsToString(values) {
return _.map(values, function (value) {
return value ? value.toString() : 0;
});
};
// Generates random big number for verification codes
function generateVerificationCode() {
return Math.random().toString(36).substr(2, 10).toUpperCase(); // remove `0.`
};
// Navigation
//-------------
function goBack() {
$window.history.back()
};
function goBackAndSelect(object, idParamName, objParamName) {
pipAssert.isDef(object, 'pipUtils.goBack: first argument should be defined');
pipAssert.isDef(idParamName, 'pipUtils.goBack: second argument should be defined');
pipAssert.isDef(objParamName, 'pipUtils.goBack: third argument should be defined');
pipAssert.isObject(object, 'pipUtils.goBack: first argument should be an object');
pipAssert.isString(idParamName, 'pipUtils.goBack: second argument should a string');
pipAssert.isString(objParamName, 'pipUtils.goBack: third argument should a string');
if ($rootScope.$prevState && $rootScope.$prevState.name) {
var state = _.cloneDeep($rootScope.$prevState);
state.params[idParamName] = object.id;
state.params[objParamName] = object;
$state.go(state.name, state.params);
} else {
$window.history.back();
}
};
// Scrolling
//--------------
function scrollTo(parentElement, childElement, animationDuration) {
if(!parentElement || !childElement) return;
if (animationDuration == undefined) animationDuration = 300;
setTimeout(function () {
if (!$(childElement).position()) return;
var modDiff= Math.abs($(parentElement).scrollTop() - $(childElement).position().top);
if (modDiff < 20) return;
var scrollTo = $(parentElement).scrollTop() + ($(childElement).position().top - 20);
if (animationDuration > 0)
$(parentElement).animate({
scrollTop: scrollTo + 'px'
}, animationDuration);
}, 100);
};
// todo add support for iPhone
function getBrowser() {
var ua = $window.navigator.userAgent;
var bName = function () {
if (ua.search(/Edge/) > -1) return "edge";
if (ua.search(/MSIE/) > -1) return "ie";
if (ua.search(/Trident/) > -1) return "ie11";
if (ua.search(/Firefox/) > -1) return "firefox";
if (ua.search(/Opera/) > -1) return "opera";
if (ua.search(/OPR/) > -1) return "operaWebkit";
if (ua.search(/YaBrowser/) > -1) return "yabrowser";
if (ua.search(/Chrome/) > -1) return "chrome";
if (ua.search(/Safari/) > -1) return "safari";
if (ua.search(/Maxthon/) > -1) return "maxthon";
}();
var version;
switch (bName) {
case "edge":
version = (ua.split("Edge")[1]).split("/")[1];
break;
case "ie":
version = (ua.split("MSIE ")[1]).split(";")[0];
break;
case "ie11":
bName = "ie";
version = (ua.split("; rv:")[1]).split(")")[0];
break;
case "firefox":
version = ua.split("Firefox/")[1];
break;
case "opera":
version = ua.split("Version/")[1];
break;
case "operaWebkit":
bName = "opera";
version = ua.split("OPR/")[1];
break;
case "yabrowser":
version = (ua.split("YaBrowser/")[1]).split(" ")[0];
break;
case "chrome":
version = (ua.split("Chrome/")[1]).split(" ")[0];
break;
case "safari":
version = (ua.split("Version/")[1]).split(" ")[0];
break;
case "maxthon":
version = ua.split("Maxthon/")[1];
break;
}
var platform = 'desktop';
if (/iphone|ipad|ipod|android|blackberry|mini|windows\sce|palm/i.test(ua.toLowerCase())) platform = 'mobile';
var os;
try {
var osAll = (/(windows|mac|android|linux|blackberry|sunos|solaris|iphone)/.exec(ua.toLowerCase()) || [u])[0].replace('sunos', 'solaris'),
osAndroid = (/(android)/.exec(ua.toLowerCase()) || '');
os = osAndroid && (osAndroid == 'android' || (osAndroid[0] == 'android')) ? 'android' : osAll;
} catch (err) {
os = 'unknown'
}
var browsrObj;
try {
browsrObj = {
platform: platform,
browser: bName,
versionFull: version,
versionShort: version.split(".")[0],
os: os
};
} catch (err) {
browsrObj = {
platform: platform,
browser: 'unknown',
versionFull: 'unknown',
versionShort: 'unknown',
os: 'unknown'
};
}
return browsrObj;
}
// todo нужны каке нибудь настройки?
function checkSupported(supported) {
if (!supported) supported = {
edge: 11,
ie: 11,
firefox: 43, //4, for testing
opera: 35,
chrome: 47
};
var systemInfo = getBrowser();
if (systemInfo && systemInfo.browser && supported[systemInfo.browser]){
if (systemInfo.versionShort >= supported[systemInfo.browser]) return true;
}
return true;
};
});
})();