• Jump To … +
    app.js ifCondHelper.js localizationHelper.js menuHelper.js sortByHelper.js titleHelper.js utils.js main.js defaultModel.js examsModel.js giaModel.js populationModel.js souModel.js examsModule.js mainPack.js populationModule.js souModule.js chartView.js defaultView.js tableView.js
  • utils.js

  • ¶
    /*jslint nomen: true */
    /*globals require, define, $, Env, window, navigator, console*/
    
    
    /**
     * @module utils
     */
    
    define(["framework", "underscore"],
        function ($, _) {
            "use strict";
            return {
                /**
                 * @name module:utils#strictBool
                 * @description Returns strict boolean value or default or false
                 * @param [param] {*} Param value
                 * @param [def] {Boolean} Default value or false
                 * @function
                 * @returns {boolean}
                 */
                strictBool: function (param, def) {
                    return typeof param === "boolean" ? param : !!def;
                },
                /**
                 * @name module:utils#isx64
                 * @description Detects x64
                 * @function
                 * @returns {boolean}
                 */
                isx64: function () {
                    /* istanbul ignore next */
                    return window.navigator.platform === "MacIntel" ||
                            window.navigator.platform === "Linux x86_64" ||
                            navigator.userAgent.indexOf('WOW64') > -1 ||
                            window.navigator.platform === 'Win64' ||
                            false;
                },
                sum: function (obj) {
                    if (!$.isArray(obj) || obj.length === 0) {
                        return 0;
                    }
                    return _.reduce(obj, function (sum, n) {
                        return sum + n;
                    });
                },
                /**
                 * @name module:utils#sortBy
                 * @description _.sortBy extension for Handlebars Helpers
                 * @function
                 * @param list {Array} Array of anything
                 * @param [param] {Function|String} Fn or static method name as iterator
                 * @param [attr] {String} Object attr name for iterator
                 * @param [withExceptions] {Boolean} Enables sorter injection
                 * @returns {Array|*} Sorted array or list param as is
                 *
                 * @example Handlebars: {{#sortBy this 'toLocaleString' null true}}
                 */
                sortBy: function (list, param, attr, withExceptions) {
                    if (typeof list === "object" && !!param) {
  • ¶

    Fn definition

                        var fn = typeof param === "string" ?
                                function (item) {
                                    return typeof item[param] === "function" ?
                                            item[param]() :
                                            item[param] || item;
                                } :
  • ¶

    Iterate through attribute

                                typeof attr === "string" ?
                                        function (item) {
                                            return item[attr];
                                        } :
  • ¶

    Return element itself

                                        function (item) {
                                            return item;
                                        },
  • ¶

    A sorting hack, which allows to set “avg” as first array element for all l10ns

                            inj = function (item) {
                                var str = fn(item),
                                    exceptions = [
                                        "avg".toLocaleString(),
                                        "yearSlice".toLocaleString()
                                    ];
  • ¶

    Didgit is always upper

                                return _.contains(exceptions, str) ? "00" + str : str;
                            },
                            wrapFn = withExceptions ? inj : fn;
                        return _.sortBy(list, wrapFn);
                    }
                    return list;
                },
                /**
                 * @name module:utils#getCacheSize
                 * @description Returns cache size (in bytes) of specified scope
                 * @function
                 * @param [scope] {Object} Scope instance
                 * @returns {number|undefined}
                 */
                getCacheSize: function (scope) {
                    return this.getCacheScope(scope).cacheSize;
                },
                /**
                 * @name module:utils#setCacheSize
                 * @description Sets cache size (in bytes) of scope
                 * @function
                 * @param [size] {number} Size in bytes
                 * @param [scope] {object} Scope instance or default scope
                 * @param [isx64] {boolean} x64
                 * @returns {number}
                 */
                setCacheSize: function (size, scope, isx64) {
                    var _scope = this.getCacheScope(scope),
                        mb = 1024 * 1024,
                        _size = (
                            isNaN(size) || typeof size !== 'number' ?
                                    mb * (this.strictBool(isx64, this.isx64()) ? 1 : 0.25) :
                                    size > 20 * mb ?
                                            20 * mb :
                                            size < 0 ?
                                                    0 :
                                                    size
                        );
                    if (typeof _scope.cacheSize === "number") {
                        this.freeCacheSpace(_scope, _scope.cacheSize - _size);
                    } else {
                        _scope.cacheRest = _size;
                    }
                    _scope.cacheSize = _size;
                    return _size;
                },
                /**
                 * @name module:utils#freeCacheSpace
                 * @description Frees up memory of scope cache
                 * @function
                 * @param [scope] {object} Scope instance
                 * @param [space] {number} Target free space
                 * @returns {number}
                 */
                freeCacheSpace: function (scope, space) {
                    var _scope = this.getCacheScope(scope),
                        cache = this.getCache(_scope),
                        rest = _scope.cacheRest,
                        limit = _scope.cacheSize,
                        item;
    
                    if (limit && typeof space === "number" && space > 0) {
                        if (space >= limit) {
                            this.flushCache(_scope);
                        } else {while (rest < space) {
                            item = _scope.cacheStack.shift();
                            rest += item.size;
                            delete cache[item.key];
                        } }
                        _scope.cacheRest = rest;
                    }
                    return rest;
                },
                /**
                 * @name module:utils#getCacheScope
                 * @description Returns cache scope for specified object
                 * @function
                 * @returns {Object} Scope
                 */
                getCacheScope: function (scope) {
  • ¶

    Default scope is window.Enw

                    return typeof scope === "object" ? scope : this.getDefaultCacheScope();
                },
                /**
                 * @name module:utils#getDefaultCacheScope
                 * @description Returns default cache scope
                 * @function
                 * @returns {Object} Scope
                 */
                getDefaultCacheScope: function () {
                    if (typeof window.Enw !== "object") {
                        window.Enw = {};
                    }
                    return window.Enw;
                },
                /**
                 * @name module:utils#getCache
                 * @description Returns/creates scope cache
                 * @function
                 * @param [scope] {Object} Scope instance
                 *
                 * @returns {Object} Scope.cache object
                 */
                getCache: function (scope) {
                    var _scope = this.getCacheScope(scope);
                    if (!_scope.cache) {
                        _scope.cache = {};
                        _scope.cacheStack = [];
                        this.setCacheSize(this.getCacheSize(_scope), _scope);
                    }
                    return _scope.cache;
                },
                /**
                 * @name module:utils#getCacheRest
                 * @description Returns free cache space in bytes
                 * @function
                 * @param [scope] {Object} Scope instance
                 * @returns {number}
                 */
                getCacheRest: function (scope) {
                    var _scope = this.getCacheScope(scope);
                    return _scope.cacheRest;
                },
                /**
                 * @name module:utils#setToCache
                 * @description Stores value to the cache
                 * @function
                 * @param key {String} Hash key
                 * @param val {*} Hash value
                 * @param [scope] {Object} Scope instance
                 *
                 * @returns {*} val param as is
                 */
                setToCache: function (key, val, scope) {
                    var _scope = this.getCacheScope(scope),
                        cache = this.getCache(scope),
                        limit = _scope.cacheSize,
                        size = this.sizeOf(val);
    
                    this.delFromCache(key, _scope);
    
                    if (size <= limit && !!key) {
    
                        if (size > _scope.cacheRest) {
                            this.freeCacheSpace(_scope, size);
                        }
                        cache[key] = val;
                        _scope.cacheStack.push({key: key, size: size});
                        _scope.cacheRest -= size;
                    }
                    return val;
                },
                /**
                 * @name module:utils#getFromCache
                 * @description Gets cached value
                 * @function
                 * @param key {String} Hash key
                 * @param [scope] {Object} Scope instance
                 *
                 * @returns {*} value
                 */
                getFromCache: function (key, scope) {
                    /* istanbul ignore else */
                    if (!!key) {
                        return this.getCache(scope)[key];
                    }
                },
                /**
                 * @name module:utils#delFromCache
                 * @description Removes value from cache
                 * @function
                 * @param key {String} Hash key
                 * @param [scope] {Object} Scope instance
                 *
                 * @returns {Undefined} Undefined
                 */
                delFromCache: function (key, scope) {
                    var _scope = this.getCacheScope(scope),
                        cache = this.getCache(_scope),
                        stack = _scope.cacheStack;
                    if (!!key && cache[key]) {
                        delete cache[key];
                        _.each(stack, function (item, i) {
                            if (item.key === key) {
                                _scope.cacheRest += item.size;
    
                                stack = stack.splice(i, 1);
                                return;
                            }
                        });
                    }
                    return;
                },
                /**
                 * @name module:utils#flushCache
                 * @description Cache annihilation
                 * @function
                 * @param [scope] {Object} Scope instance
                 *
                 * @returns {Object} Empty object
                 */
                flushCache: function (scope) {
                    var _scope = this.getCacheScope(scope);
                    delete _scope.cache;
                    delete _scope.cacheRest;
                    delete _scope.cacheStack;
                    delete _scope.cacheSize;
                    return;
                },
                /**
                 * @name module:utils#replace
                 * @description Smart replace
                 * @function
                 * @param a {String|Array} Replace in
                 * @param b {*} 1st arg
                 * @param c {*} 2nd arg
                 *
                 * @returns {String|Array} Replace output
                 */
                replace: function (a, b, c) {
  • ¶

    Replacement should be set strictly

                    if (arguments.length > 2) {
                        if (a instanceof Array) {
                            var i;
  • ¶

    _.map is much slower

                            for (i = a.length; i; i -= 1) {
                                if (a[i - 1] === b) {
                                    a[i - 1] = c;
                                }
                            }
                        } else {
                            /* istanbul ignore else */
                            if (typeof a === "string") {
                                return a.replace(b, c);
                            }
                        }
                    }
                    return a;
    
                },
                /**
                 * @name module:utils#sizeOf
                 * @author Stephen Morley - http://code.stephenmorley.org/
                 * @licence CC0 1.0 http://creativecommons.org/publicdomain/zero/1.0/legalcode
                 * @description A function to calculate the approximate memory usage of objects
                 * @function
                 * @param object {*} Measurable object
                 * @returns {Number} Size in bytes
                 */
                sizeOf: function (object) {
  • ¶

    initialise the list of objects and size

                    var objects = [object],
                        index,
                        size = 0,
                        processed,
                        search,
                        key;
  • ¶

    loop over the objects

                    for (index = 0; index < objects.length; index += 1) {
  • ¶

    determine the type of the object

                        switch (typeof objects[index]) {
  • ¶

    the object is a boolean

                        case 'boolean':
                            size += 4;
                            break;
  • ¶

    the object is a number

                        case 'number':
                            size += 8;
                            break;
  • ¶

    the object is a string

                        case 'string':
                            size += 2 * objects[index].length;
                            break;
  • ¶

    the object is a generic object

                        case 'object':
  • ¶

    if the object is not an array, add the sizes of the keys

                            /* istanbul ignore else */
                            if (Object.prototype.toString.call(objects[index]) !== '[object Array]') {
                                for (key in objects[index]) {
                                    /* istanbul ignore else */
                                    if (objects[index].hasOwnProperty(key)) {
                                        size += 2 * key.length;
                                    }
                                }
                            }
  • ¶

    loop over the keys

                            for (key in objects[index]) {
                                /* istanbul ignore else */
                                if (objects[index].hasOwnProperty(key)) {
  • ¶

    determine whether the value has already been processed

                                    processed = false;
                                    for (search = 0; search < objects.length; search += 1) {
                                        if (objects[search] === objects[index][key]) {
                                            processed = true;
                                            break;
                                        }
                                    }
  • ¶

    queue the value to be processed if appropriate

                                    if (!processed) {
                                        objects.push(objects[index][key]);
                                    }
                                }
                            }
                            break;
                        }
                    }
  • ¶

    return the calculated size

                    return size;
    
                }
            };
        });