archwhite
4/12/2020 - 7:14 PM

utils.js

Utils.js from V. project

var showlog = false;
var ge = function (elementId) {
    return document.getElementById(elementId);
};


var  MApp = function () {
    var self = this;

    /**
     * @name {_interface}
     * @param {Object} setup
     * @param {Object} extra <as like beforeSend:function(){}..>
     * @return {Object}
     * @use /-self._interface({type:'get'|'post', url:url|+,(data:{})|undefined}, false|true)-/
     */
    this.ajaxInterface = function (setup, extra) {
        var _self = this;
        /**@type {Object} base*/
        this.base = {
            url: null,
            type: 'post',
            data: null
        };

        /**@set {url} */
        this.base.url = setup.url;

        if (!!setup.type && setup.type.toLowerCase() === "get") {
            this.base.type = setup.type;
        }

        this.base.data = setup.data;

        !!extra
            ? $.extend(_self.base, extra)
            : void (0);

        return $.ajax(_self.base);
    };

    this.initBodyScrollBar = function () {

    };
    
    this.ajaxPrefilter = function () {
        self.currentRequests = {};
        $.ajaxPrefilter(function (options, originalOptions, jqXHR) {
            if (options.abortOnRetry) {
                //if (self.currentRequests[options.url] && self.currentRequests[options.url].status !== 200) {
                if (self.currentRequests[options.url] && options.url !== '/api/nodes') {
                    self.currentRequests[options.url].abort();
                       //jqXHR.abort();
                }
                self.currentRequests[options.url] = jqXHR;
            }
        });
    };

    this.date = function (utcDate, formatNow, formatNeed) {
        formatNow = formatNow || 'YYYY-MM-DD HH:mm:ss';
        formatNeed = formatNeed || 'DD.MM.YYYY HH:mm:ss';
        
        if (utcDate === "0001-01-01T00:00:00" || !utcDate) {
            return "-";
        }
    
        if(self.getGMT() > 0){
            date = moment(utcDate, formatNow).add(mApp.getGMT(), "hour").format(formatNeed);
        }else{
            date = moment(utcDate, formatNow).subtract(mApp.getGMT(), "hour").format(formatNeed);
        }
    
        return date;
    };

    this.utc = function (date, formatNow, formatNeed) {
	      formatNow = formatNow || 'DD.MM.YYYY HH:mm';
	      formatNeed = formatNeed || 'YYYY-MM-DD HH:mm';
	    
        if (self.getGMT() < 0) {
            utcDate = moment(date, formatNow).add(mApp.getGMT(), "hour").format(formatNeed);
        } else {
            utcDate = moment(date, formatNow).subtract(mApp.getGMT(), "hour").format(formatNeed);
        }

        return utcDate;
    };

    this.ajaxSetup = function (settings) {
        var startTme;
        $.ajaxSetup({
            abortOnRetry: true,
            cache: false,
            beforeSend: function () {
                startTme = +new Date();
            },
            error: function (jqXHR, textStatus, errorThrown) {
                if (jqXHR.status == 500) {
                    $.alert("(500) Произошла ошибка на сервере: " + "URL:" + this.url + ", " + textStatus + ", "
                        + errorThrown + ", "
                        + JSON.stringify(jqXHR.responseJSON || jqXHR.responseText, null, 4), "error", true, false);
                }
            },
            success: function (response, a, b, c) {
                if (!!response && response.error) {
                    $.alert("Произошла ошибка на сервере: " + response.error, "error", true);
                }
                if (window.showlog) {
                    console.debug("%c%s", "color: #fff; background: #000; font-size: 12px;", "[request successed]", "[" + this.url + "]","["+ (+new Date() - startTme) + " ms]");
                }
            }
        });
    };

    this.numbersDeclaration = function (number, titles) {
        var cases = [2, 0, 1, 1, 1, 2];
        return titles[(number % 100 > 4 && number % 100 < 20) ? 2 : cases[(number % 10 < 5) ? number % 10 : 5]];
    };

    /**
     * @name {dispatchEvent}
     * @param {Event} eventName
     * @param {Object|int|String|array|undefined} data
     * @return {Object} self
     */
    this.dispatchEvent = function (eventName, data) {
        $(document).trigger(eventName, data);
        return this;
    };

    this.toggler = function () {
        var _this = this;
        this.$$selector = "a.js-toggler";

        $(document).on("click", _this.$$selector, function () {
            var $toggleText = $(this).find("strong");
            $(this)
    		.toggleClass("open")
    		.parent().find(".js-toggler_t")
    		.toggleClass($(this).data("toggler"));
            self.dispatchEvent("u.toggle.end");

            $(this).hasClass("open") ? $toggleText.text("Скрыть все") : $toggleText.text("Показать все");
        });
    };

    this.isDate = function(str) {
        return isNaN(str) && !isNaN(new Date(str).getTime());
    };

    /**
     * !@rewrite
     * @type {bool}
     */
    this.isDateTime = function(str) {
        return /\d{2}\.\d{2}\.\d{4}\s(\d{2}:\d{2}:\d{2}|\d{2}:\d{2})/.test(str);
    };

    this.changeDateFormat = function(d) {
        var r = d.match(/^\s*(\d+)\s*\.\s*(\d+)\s*\.\s*(\d+)(.*)$/);
        return r[3] + "-" + r[2] + "-" + r[1] + r[4];
    };

    this.summ = function(m) {
        var ml = m.length;
        for (var s = 0, k = ml; k; s += parseFloat(m[--k]));
        return s.toFixed(2);
    };

    this.createNumericArray = function (startIndex, len) {
        console.log(startIndex, len);
        var resultArray = [];

        for (var i = startIndex; i <= len; i++) {
            resultArray.push(i);
        }

        return resultArray;
    };

    this.imgError = function (image) {
        image.setAttribute("src", "data:image/png;base64,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");
    };

    this.uniq = function(arr) {
        var result = [];
        for (var i in arr) {
            if (arr.hasOwnProperty(i)) {
                if (result.indexOf(arr[i]) === -1) {
                    result.push(arr[i]);
                }
            }
        }
        return result;
    };

    this.uniqCollection = function (collection, property) {
        var result = [], helper= [];
        for (var i in collection) {
            if (collection.hasOwnProperty(i)) {
                if (helper.indexOf(collection[i][property]) === -1) {
                    helper.push(collection[i][property]);
                    result.push(collection[i]);
                }
            }
        }
        return result;
    };

    this.initTooltips = function() {
        var $tooltip = $('[data-toggle="tooltip"]');
        return $tooltip.tooltip();
    };

    this.serializeObjectGetString = function(obj) {
        return _.map(obj, function(i, n) {return n + "=" + i; }).join("&");
    };

    this.serializeGetStringToObject = function (obj, splitResult) {
        var result = {};
        if (!obj) {
            return false;
        }
        _.map(obj.split("&"), function(item) {
            var i = item.split("=");
            return result[i[0]] = i[1].indexOf(",") > -1 && splitResult
                ? i[1].split(",")
                : i[1];
        });
        return result;
    };

    this.getGMT = function() {
        return (new Date().getTimezoneOffset() / 60) * (-1);
    };
    
    this.logOff = function () {
      self.dropSession();
      
      window.location.href = '/account/logoff'
    };

    this.dropSession = function () {
      window.localStorage.removeItem('model.selectedSet');
      window.localStorage.removeItem('nc.selectedSets');
	    window.localStorage.removeItem('jstree');
    };

    this.isClass = function (obj, type) {
	    var aliases = {
			    0:'Object'
		    };

	    if (Number(type) === type) {
		    type = aliases[type];
	    }
      
	    
      return Object.prototype.toString.call(obj) === "[object " + type + "]";
    };

    this.toggleSidebar = function () {
        var $toggleSidebar = $(".toggleSidebar");
        return $toggleSidebar.click(function () {
            $('body').toggleClass('page-quick-sidebar-open');
        });
    };

    this.setDividerStycky = function (elementSelector) {
        var $element = $(elementSelector), offset = $element.offset(), $portlet = $("div.portlet");
        
        $(window).on("scroll", function () {
            if ($element.height() > $portlet.height()) {
                return false;
            }

            setTimeout(function () {
                $element.width($element.parent().width() - 30);
            }, 0);
            
            try {
                if ($(this).scrollTop() >= (offset.top - 51)) {

                    _.once($element.addClass("scrollable_fixed"));
                    $element.height($(window).height() - 54);
                    
                }else{
                    _.once($element.removeClass("scrollable_fixed"));
                    
                    $element.height("auto");
                    $element.css({width: "100%"});
                }
            
            } catch (e) {
                console.log(e);
            }
        }).on("resize", setTimeout.bind(null, function () {
            $element.width($element.parent().width() - 30);
        }, 0));
    };

    var execution = false;

    window.ok = function () {
        execution = true;

        $("body #isvisor-confirmation").remove();

        self.confirm();

        execution = false;
    };

    window.no = function() {
        $("body #isvisor-confirmation").remove();

        execution = false;
    };

    this.confirm = function (message, trueCallback) {
        var modal = "<div id=\"isvisor-confirmation\"><div>" + message + "</div><div><button onclick='ok()'>Ок</button><button onclick='no()'>Отмена</button></div></div>",
            $body = $("body"),
            cancel;

            if ($("body #isvisor-confirmation").length === 0) {
                $body.append(modal);
            }

            if (!execution) {
                throw new Error();
            } else {
                console.log("ok clicked");
                return true;
            }
        
    };
    
    this.activeElement = null;

    this.getActiveElement = function () {
        var setActive = function (event) {
            self.activeElement = $(event.target || event.srcElement);
        };

        $(document).on("click", setActive);
    };
    
    this.asArray = function (obj) {
      if (self.isClass(obj, 'Array')){
          return obj;
      }
      
      return [obj];
    };
    
    this.initHandlers = function () {
	    $('#log-off-btn').on('click.logoff', self.logOff);      
    };
    
    
    this.init = function () {
	    self.initHandlers();
    };
};



var mApp = new MApp();

mApp.toggler();
mApp.toggleSidebar();
//mApp.ajaxPrefilter();
mApp.ajaxSetup();
mApp.getActiveElement();
mApp.initHandlers();
console.debug("%c%s", "color: #e26a6a; background: #000; font-size: 20px;", "console api:\n");
console.debug("%c%s", "color: #e26a6a; font-size: 14px;", "{\n\tshowlog:boolean\n}");

;(function ($, window, document) {
    /**
	 * Alert Plagin
	 *
	 *
	 *  -------EXAMPLE-------
	 *
	 *   $.alert('alert text'); // renders simple alert as default[red color]
	 *   $.alert(['alert text1', 'alert text2'], 'success'); // renders success alert with multi string content
	 *   $.alert('alert text', 'info'); //renders simple info alert
	 *   
	 *
	 */
    $.alert = function (alertText, Atype, offautohide, html, relative) {
        Atype = Atype || 'error';

        var spanMessages = "";

        if (Object.prototype.toString.call(alertText) === "[object Array]") {
            for (var i = 0, len = alertText.length; i < len ; ++i) {
                spanMessages += ['<span>', alertText[i], '</span><br/>'].join("");
            }
        } else {
            spanMessages = html && "<pre>" + alertText + "</pre>" || alertText;
        }
                
        var template = ('<div class="alert-block_' + Atype + ' alert alert-block">\
						    \<i class="icon icon-alert_big___' + Atype + ' s-mr_20"></i>\
						        \<span class="alert-heading js-insertAllertText">' + spanMessages + '</span>\
						        \<a class="close icon s-float_r s-pt_31" data-dismiss="alert" href="javascript:void(0)">\
						            \<i class="icon icon-alert_close"></i>\
						        \</a>\
						    \</div>');
        
        $('div.alert-block').remove();
        

        $('body').append(template);
        
        if (!offautohide) {
            var timeout = setTimeout(function () {
                $('div.alert-block').fadeOut(100);
            }, 2000);
        }

        function dismiss(event) {
            event = event || window.event;
            event.preventDefault ? event.preventDefault() : event.returnValue = false;
            $(this).parent().remove();
        };

        $(document).on('click', '[data-dismiss="alert"]', dismiss);
    };
})(jQuery, window, document);

/**
 * @name {highlight}
 * @return {jQuery} fn.highlight
 * 
 * $(selector).highlight('word');
 * $(selector).removeHighlight();
 * 
 */
jQuery.fn.highlight = function (pat) {
    function innerHighlight(node, pat) {
        var skip = 0;
        if (node.nodeType == 3) {
            var pos = node.data.toUpperCase().indexOf(pat);
            pos -= (node.data.substr(0, pos).toUpperCase().length - node.data.substr(0, pos).length);
            if (pos >= 0) {
                var spannode = document.createElement('span');
                spannode.className = 'highlight';
                var middlebit = node.splitText(pos);
                var endbit = middlebit.splitText(pat.length);
                var middleclone = middlebit.cloneNode(true);
                spannode.appendChild(middleclone);
                middlebit.parentNode.replaceChild(spannode, middlebit);
                skip = 1;
            }
        }
        else if (node.nodeType == 1 && node.childNodes && !/(script|style)/i.test(node.tagName)) {
            for (var i = 0; i < node.childNodes.length; ++i) {
                i += innerHighlight(node.childNodes[i], pat);
            }
        }
        return skip;
    }
    return this.length && pat && pat.length ? this.each(function () {
        innerHighlight(this, pat.toUpperCase());
    }) : this;
};

jQuery.fn.removeHighlight = function () {
    return this.find("span.highlight").each(function () {
        this.parentNode.firstChild.nodeName;
        with (this.parentNode) {
            replaceChild(this.firstChild, this);
            normalize();
        }
    }).end();
};
Number.prototype.roundTo = function (n){
    var x = 0;
    if (typeof (n) == 'number')
        if (n.isInt())
            if (n >= -6 && n <= 6) x = n;
    x = Math.pow(10, x);
    return Math.round(this * x) / x;
}

Number.prototype.isInt = function (){
    return (Math.round(this) == this);
}

/**
 * конвертирует дробное число в форматированную строку
 * с количеством знаков после запятой n и с разделением
 * триад цифр пробелами (при triads!=0)
 */ 
Number.prototype.toFloatStr = function (n, triads) {
    var s, d = 0, k, m;

    if (typeof (n) == 'number')
        if (n.isInt())
            if (n >= -6 && n <= 6) d = n;

    s = this.roundTo(d).toString().replace('.', ',');

    if (d > 0) {
        k = s.indexOf(',');
        if (k == -1)
            s += ',' + '0'.repeat(d);
        else
            s += '0'.repeat(d - (s.length - k - 1));
    }

    k = s.indexOf(',');
    if (k == -1) k = s.length;
    m = s.indexOf('-');
    if (m == -1)
        m = 0;
    else
        m = 1;

    if (triads)
        for (d = k - 3; d > m; d = d - 3) {
            s = s.substr(0, d) + ' ' + s.substr(d, s.length - d + 1);
        }

    return s;
};

/**
 * @type {function} Calc true округление до порядка
 * @author @arthur33277
 * @void
 */
var Calc = function () {
    var self = this;

    this.float2Array = function (num) {
        var floatString = num.toString(),
            exp = floatString.indexOf(".") - (floatString.length - 1),
            mant = floatString.replace(".", "").split("").map(function (i) { return parseInt(i); });
        return { exp: exp, mant: mant };
    };

    this.round2 = function (num, dec, sep) {
        var decimal = !!dec ? dec : 2,
        separator = !!sep ? sep : '',
        r = parseFloat(num),
        exp10 = Math.pow(10, decimal);
        r = Math.round(r * exp10) / exp10;

        var rr = Number(r).toFixed(decimal).toString().split('.');

        var b = rr[0].replace(/(\d{1,3}(?=(\d{3})+(?:\.\d|\b)))/g, "\$1" + separator);
        r = (rr[1] ? b + '.' + rr[1] : b);

        return r;
    };

    this.toFixed10 = function (f, num) {
        var prepareInt = self.float2Array(f),
            naturalInt = prepareInt.mant,
            places = Math.abs(prepareInt.exp),
            result = prepareInt.mant.slice(),
            resultFixedLenth;

        // if number non fractional or has zero fractional part
        if (f.isInt()) {
            return f.toFixed(num);
        }
        // if the number of decimal places equals to required rounding
        if (places === num) {
            return Number(f).toString();
        }
        //if number has trailing zero (when casting to string type float 1.0050 => "1.005" => 005 <0050)
        if (places < num) {
            return Number(f).round2(num);
        }

        for (var e = naturalInt.length - (places > num ? (places - num) : 0), s = 0; e >= s; e--) {
            if (naturalInt.hasOwnProperty(e)) {
                if (naturalInt[e] > 4 && naturalInt[e - 1] < 9) {
                    result[e] = 0;
                    result[e - 1] = naturalInt[e - 1] + 1;
                    break;
                } else if (naturalInt[e] > 4 && naturalInt[e - 1] === 9) {
                    result[e] = 0;
                    result[e - 1] = 0;
                    result[e - 2] = naturalInt[e - 2] < 9 ? naturalInt[e - 2] + 1 : 0;
                } else if (e === 0 && naturalInt[e] === 9 && naturalInt[e + 1] === 9) {
                    result[e] = 0;
                    result.unshift(1);
                } else {
                    break;
                }
            }
        }

        if (places - num > 0) {
            resultFixedLenth = result.slice(0, -(places - num));
        } else {
            for (var i = 0, l = num - places; i < l; i++) {
                result.push(0);
            }
            resultFixedLenth = result;
        }

        return (parseInt(resultFixedLenth.join("")) / Math.pow(10, num)).round2(num);
    };
    this.polyfill = function () {
        if (!Array.prototype.map) {
            Array.prototype.map = function (callback, thisArg) {
                var T, A, k;
                if (this == null) { throw new TypeError(' this is null or not defined'); }
                var O = Object(this), len = O.length >>> 0;
                if (typeof callback !== 'function') { throw new TypeError(callback + ' is not a function'); }
                if (arguments.length > 1) { T = thisArg; }

                A = new Array(len);
                k = 0;
                while (k < len) {
                    var kValue, mappedValue;
                    if (k in O) {
                        kValue = O[k];
                        mappedValue = callback.call(T, kValue, k, O);
                        A[k] = mappedValue;
                    }
                    k++;
                }
                return A;
            };
        }
    };

    this.init = function () {
        self.polyfill();
        Number.prototype.toFixed10 = function (decimal) {
            return calc.toFixed10(this, decimal);
        }
        Number.prototype.round2 = function (decimal) {
            return calc.round2(this, decimal);
        }
        Number.prototype.isInt = function () {
            return (Math.round(this) == this);
        }
    }
}, calc = new Calc(); calc.init();

String.prototype.hashCode = function () {
    var hash = 0, i, chr, len;

    if (this.length === 0) {
        return hash;
    }

    for (i = 0, len = this.length; i < len; i++) {
        chr = this.charCodeAt(i);

        hash = ((hash << 5) - hash) + chr;

        hash |= 0;
    }

    return hash;
};

String.prototype.capitalize = function () {
    return this.charAt(0).toUpperCase() + this.slice(1);
};