js/core/core-utils.js
(function(){
var E = Ergo;
E.deferred = function() {
return {
promise: function() {
var self = this;
return this._promise = this._promise || new Promise(function(resolve, reject) {
self.resolve = resolve;
self.reject = reject;
});
}
}
}
E.fixDisorder = function(kv_a, callback) {
// разница между индексами и позициями
var indexDeltas = [];
kv_a.forEach(function(kv, i) {
indexDeltas[kv[2]] = kv[2] - i;
});
var n = 0;
var indexDisorders = [];
var moved_a = [];
while( n < kv_a.length+1 ) {
// 0 -
// 1 -
// 2 -
// 3 - индекс
var maxDisorder = [-1,-1];
indexDisorders = [];
for(var i = 0; i < kv_a.length; i++) {
// индекс элемента i
var i_index = i - indexDeltas[i];
// пропускаем элемент, если мы его уже переместили
if( moved_a[i_index] )
continue;
// 0 количество нарушений
// 1 позиция первого нарушения
// 2 позиция последнего нарушения
var disorder = [-1, -1, -1];
//
for(var j = 0; j < kv_a.length; j++) {
// индекс элемента j
var j_index = j - indexDeltas[j];
// если присутствует нарушение порядка, запоминаем его
if( (j < i && j_index > i_index) || (j > i && j_index < i_index) ) {
if(disorder[0] == -1) {
disorder[1] = j;
}
disorder[2] = j;
disorder[0]++;
}
}
// обновляем информацию о нарушении
indexDisorders[i] = disorder;
// запоминаем наибольшее нарушение
if(disorder[0] > maxDisorder[0]) {
maxDisorder[0] = disorder[0];
maxDisorder[1] = disorder[1];
maxDisorder[2] = disorder[2];
maxDisorder[3] = i;
}
}
// если наибольшее нарушение не определено - исправление закончено
if(maxDisorder[0] == -1) {
break;
}
n++;
// var k = 0;
//
// for(var i = 0; i < measure_a.length; i++) {
// if(max_measure[0] == measure_a[i][0])
// k++;
// }
// console.log( 'max measure, count', max_measure, k);
// выполняем перемещение
var _i = maxDisorder[3];
var _j = (maxDisorder[2] > maxDisorder[3]) ? maxDisorder[2] : maxDisorder[1];
// уведомляем о перемещении
callback(_i, _j, kv_a[_i], kv_a[_j]);
// запоминаем перемещенный индекс
moved_a[_i-indexDeltas[_i]] = true;
// корректируем дельту после перемещения
var i_delta = indexDeltas[_i];
if(_j < _i) {
for(var i = _i; i > _j; i--) {
indexDeltas[i] = indexDeltas[i-1]+1;
}
}
if(_j > _i) {
for(var i = _i; i < _j; i++) {
indexDeltas[i] = indexDeltas[i+1]-1;
}
}
indexDeltas[_j] = i_delta + (_j - _i);
}
}
E.print = JSON.stringify;
E.indent_s = ' ';
/**
* Печать объекта в удобочитаемой форме
*
* @function
*
* @returns {String}
*/
E.prettyPrint = function(obj) {
return JSON.stringify(obj, null, E.indent_s);
}
/*
* Печать объекта в удобочитаемой форме
*
* @name Ergo.prettyPrint
* @function
* @param {Any} obj любой объект/примитив
* @param {Integer} indent отступ
* @param {Integer} i_symb исимвол отступа
* @returns {String}
*/
// E.prettyPrint = function(obj, indent) {
//
// if(obj == undefined) return undefined;
//
// indent = indent || 0;
// var tabs = '';
// for(var i = 0; i < indent; i++) tabs += E.indent_s;
//
// if(obj.prettyPrint) return obj.prettyPrint(indent);
//
// if($.isString(obj))
// return '"'+obj.replace(/\n/g, '\\n')+'"';
// else if($.isBoolean(obj))
// return ''+obj;
// else if($.isNumeric(obj) || $.isBoolean(obj))
// return obj;
// else if($.isArray(obj)){
// var items = [];
// E.each(obj, function(item){
// items.push(E.prettyPrint(item, indent));
// });
// return '[' + items.join(', ') + ']';
// }
// else if($.isFunction(obj)){
// return 'function() { ... }';
// }
// else if($.isPlainObject(obj) || !indent){
// var items = [];
// E.each(obj, function(item, key){
// if(key[0] == '!' || key[0] == '-' || key[0] == '+') key = "'"+key+"'";
// items.push(tabs + E.indent_s + key + ': ' + E.prettyPrint(item, indent+1));
// });
// return '{\n' + items.join(',\n') + '\n' + tabs + '}';
// }
// else
// return obj;
//
// };
/**
* Экранирование строки для вывода в html
*
* @name Ergo.escapeHtml
* @function
* @param {String} s строка
* @returns {String} экранированная строка
*/
E.escapeHtml = function(s) {
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
};
/**
*
*
* @name Ergo.ms
* @function
*/
E.ms = E.timestamp = function() {
return new Date().getTime();
};
// E.ms = E.timestamp;
/**
* Форматированный вывод значений.
*
* @example
* Ergo.format("%s items from %s selected", 1, 10);
*
* @name Ergo.format
* @function
* @param {String} format_str строка форматирования
* @return {String}
*/
E.format = function(format_str) {
var values = [];
for(var i = 1; i < arguments.length; i++) values.push(arguments[i]);
return format_str.replace(/(%s)/g, function(str) {
var replace_val = '';
if(str == '%s') replace_val = ''+values.shift();
return replace_val;
});
};
/**
* Форматированный вывод значения
*
* Поддерживается конвеер с разделителем `|`
*
* @name Ergo.formatValue
* @function
*/
E.formatValue = function(key, obj) {
var o = obj;
var fmt_a = [];
if( key.indexOf('|') > 0 ) {
var a = key.split('|');
key = a[0];
for(var i = 1; i < a.length; i++) {
fmt = Ergo.alias('formats:'+a[i]);
if(!fmt)
console.warn('Format ['+a[i]+'] is not registered');
fmt_a.push(fmt);
}
}
if(key && key != '*') {
var arr = key.split('.');
for(var i = 0; i < arr.length; i++) {
if(o == null) return o;
o = o[arr[i]];
}
}
for(var i = 0; i < fmt_a.length; i++)
o = fmt_a[i](o);
return o === undefined ? '' : o;
};
/**
* Форматированный вывод объекта
*
* @example
*
* var record = {
* first_name: 'Alice',
* last_name: 'Green',
* email_count: 3
* }
*
* Ergo.formatObj("#{first_name} #{last_name} has #{email_count} e-mails", record);
*
* Output: Alice Green has 3 e-mails
*
* @name Ergo.formatObj
* @function
* @param {Object} format_str строка форматирования
* @param {Object} obj объект
*/
E.formatObj = function(format_str, obj) {
if(obj === null || obj === undefined) return '';
var m = format_str.match(/^{{([^}{]+?)}}$/);
if(m) {
}
return format_str.replace(/#{\s*(.+?)\s*}/g, function(str, key) {
var o = obj;
var fmt_a = [];
if( key.indexOf('|') > 0 ) {
var a = key.split('|');
key = a[0];
for(var i = 1; i < a.length; i++) {
fmt = Ergo.alias('formats:'+a[i]);
if(!fmt)
console.warn('Format ['+a[i]+'] is not registered');
fmt_a.push(fmt);
}
}
if(key && key != '*') {
var arr = key.split('.');
for(var i = 0; i < arr.length; i++) {
if(o == null) return o;
o = o[arr[i]];
}
}
for(var i = 0; i < fmt_a.length; i++)
o = fmt_a[i](o);
return o === undefined ? '' : o;
});
};
/**
* Извлечение из строки значений
*
* @name Ergo.unformatObj
* @function
*
*/
E.unformatObj = function(ufmt, s) {
var n=0;
var tmpl = ufmt.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
var keys = []
tmpl = tmpl.replace(/#\\{\s*(.+?)\s*\\}/g, function(str, key) {
key = key.replace(/\\\*|\\\|/g, function(s) {
return s.substr(1);
});
keys.push(key);
return '(.+?)'
});
var m = s.match('^'+tmpl+'$');
var obj = {};
for(var i = 0; i < keys.length; i++ ) {
var k = keys[i];
var v = m[i+1];
var key_a = k.split('|');
k = key_a.shift(0);
key_a.forEach(function(fmt) {
fmt = Ergo.alias('formats:'+fmt);
if(!fmt) {
console.warn('Unformat ['+a[i]+'] is not registered');
}
v = fmt(v);
});
if(k == '*') {
return v;
}
else {
obj[k] = v;
}
}
return obj;
// if( keys[0] == '*') {
// return m[1];
// }
// else {
// var v = {}
// keys.forEach(function(key, i) {
// v[key] = m[i+1]
// })
// return v;
// }
};
/**
* Полное копирование объекта.
*
* Копируются вложенные простые объекты и массивы
*
* @name Ergo.deepCopy
* @function
* @param {Any} src копируемый объект
*/
E.deepCopy = function(src) {
if(src && src.constructor == Object) {
var copy = {};
for(var i in src) {
copy[i] = E.deepCopy(src[i]);
}
return copy;
}
else if(src && src.constructor == Array) {
var copy = [];
for(var i = 0; i < src.length; i++) {
copy[i] = E.deepCopy(src[i]);
}
return copy;
}
else {
return src;
}
/*
var copy = null;
// var is_po = $.isPlainObject(src);
// if(is_po || $.isArray(src)){
var is_po = (src && src.constructor == Object);
if( src && (is_po || src.constructor == Array)) {
copy = is_po ? {} : [];
for(var i in src)
copy[i] = E.deepCopy(src[i]);
// E.each(src, function(item, i){
// copy[i] = E.deepCopy(item);
// });
}
else{
copy = src;
}
return copy;
*/
};
E.loadpath = {};
E.require = function() {
for(var i = 0; i < arguments.length; i++) {
var class_name = arguments[i];
//TODO здесь нужно проверить, загружен ли класс
try{
if( eval('typeof '+class_name) == 'function') continue;
}
catch(e) {
}
for(var j in E.loadpath) {
if(class_name.search(j) != -1) {
class_name = class_name.replace(j, E.loadpath[j]);
break;
}
}
var url = class_name.replace(/\./g, '/') + '.js';
$.ajax({
url: url,
dataType: "script",
success: function(){
//TODO здесь нужно вызывать функцию, оповещающую, что класс загружен
},
error: function(jqXHR, textStatus, errorThrown){
console.log(errorThrown);
},
async: false
});
}
};
//TODO перенести в примеси
E.glass_pane = function() {
return $('<div class="e-glass-pane" autoheight="ignore"/>')
.on('mousedown', function(e){
e.preventDefault();
return false;
});
};
E.curry = function(func) {
var F = func;
var post_args = arguments;
return function(){
var args = [];
for(var i = 1; i < post_args.length; i++) args.push(post_args[i]);
for(var i = 0; i < arguments.length; i++) args.push(arguments[i]);
// args.push(arg);
return F.apply(this, args);
};
};
E.rcurry = function(func) {
var F = func;
var post_args = arguments;
return function(){
var args = [];
for(var i = 0; i < arguments.length; i++) args.push(arguments[i]);
for(var i = 1; i < post_args.length; i++) args.push(post_args[i]);
// args.push(arg);
return F.apply(this, args);
};
};
E.debounce = function debounce(func, wait, immediate) {
var timeout;
return function() {
var context = this, args = arguments;
var later = function() {
timeout = null;
if (!immediate) func.apply(context, args);
};
var callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) func.apply(context, args);
};
};
E.measure = function(callback) {
var t0 = E.ms();
callback();
var t1 = E.ms();
return (t1-t0)
};
E.parseQueryString = function(queryStr) {
var query = {};
var query_a = queryStr.split('&');
for(var i = 0; i < query_a.length; i++) {
var p_a = query_a[i].split('=');
var p_name = decodeURIComponent(p_a[0]);
if( p_name ) {
if( p_a.length == 1 ) {
query[p_name] = '';
}
else {
query[p_name] = decodeURIComponent(p_a[1].replace(/\+/g, " "));
}
}
}
return query;
}
//FIXME по большому счету это нужно только для корректной работы с событиями клавиатуры
/*Browser detection patch*/
E.browser = {};
E.browser.mozilla = /mozilla/.test(navigator.userAgent.toLowerCase()) && !/webkit/.test(navigator.userAgent.toLowerCase());
E.browser.webkit = /webkit/.test(navigator.userAgent.toLowerCase());
E.browser.opera = /opera/.test(navigator.userAgent.toLowerCase());
E.browser.msie = /msie/.test(navigator.userAgent.toLowerCase());
})();