QutBioacousticsResearchGroup/bioacoustic-workbench

View on GitHub
lib/assets/javascripts/functions.js

Summary

Maintainability
B
6 hrs
Test Coverage
'use strict';

///**
// * String format function
// * http://www.isurinder.com/blog/post/2011/04/02/StringFormat-In-JavaScript.aspx#.UKWRyvgzpQs
// * @type {Function}
// */
//String.format = String.prototype.format = function() {
//    var i=0;
//    var string = (typeof(this) == "function" && !(i++)) ? arguments[0] : this;
//
//    for (; i < arguments.length; i++){
//        string = string.replace(/\{\d+?\}/, arguments[i]);
//    }
//
//    return string;
//};

/**
 * Generates a unique number for the page. Unique only for each refresh.
 * @return {*|number}
 * @constructor
 */
Number.Unique = function () {
    var i = Number.uniqueIncrementId || 0;
    i += 1;
    Number.uniqueIncrementId = i;
    return i;
};


/**
 * IndexOf Shim
 */
if (!Array.prototype.indexOf) {
    Array.prototype.indexOf = function (what, i) {
        i = i || 0;
        var L = this.length;
        while (i < L) {
            if (this[i] === what) return i;
            ++i;
        }
        return -1;
    };
}

/**
 * Array filter compatibility
 * https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/filter
 */

if (!Array.prototype.filter) {
    Array.prototype.filter = function (fun /*, thisp */) {
        "use strict";

        if (this == null)
            throw new TypeError();

        var t = Object(this);
        var len = t.length >>> 0;
        if (typeof fun != "function")
            throw new TypeError();

        var res = [];
        var thisp = arguments[1];
        for (var i = 0; i < len; i++) {
            if (i in t) {
                var val = t[i]; // in case fun mutates this
                if (fun.call(thisp, val, i, t))
                    res.push(val);
            }
        }

        return res;
    };
}

/*!
 * requestAnimationFrame polyfill by Erik Möller, with fixes from Paul Irish, Tino Zijdel and Richard Fussenegger.
 *
 * I applied the following fixes:
 *   - Added names to the anonymous functions for better stack traces.
 *   - Indentation of code for better readability.
 *   - Combined all variable declarations into a single statement: performance.
 *
 * @link http://paulirish.com/2011/requestanimationframe-for-smart-animating/
 * @link http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating
 *
 * https://gist.github.com/Fleshgrinder/4523839
 */
;
(function requestAnimationFramePolyfill() {
    var
        lastTime = 0,
        vendors = ['ms', 'moz', 'webkit', 'o'];

    for (var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
        window.requestAnimationFrame = window[vendors[x] + 'RequestAnimationFrame'];
        window.cancelAnimationFrame = window[vendors[x] + 'CancelAnimationFrame'] || window[vendors[x] + 'CancelRequestAnimationFrame'];
    }

    if (!window.requestAnimationFrame) {
        window.requestAnimationFrame = function requestAnimationFrame(callback, element) {
            var
                currTime = new Date().getTime(),
                timeToCall = Math.max(0, 16 - (currTime - lastTime)),
                id = window.setTimeout(function requestAnimationFrameSetTimeout() {
                    callback(currTime + timeToCall);
                }, timeToCall);

            lastTime = currTime + timeToCall;
            return id;
        };
    }

    if (!window.cancelAnimationFrame) {
        window.cancelAnimationFrame = function cancelAnimationFrame(id) {
            clearTimeout(id);
        };
    }
}());


(function (undefined) {

    var baw = window.baw = window.baw || {};

    /**
     *  Fisher-Yates shuffle
     * shuffles list in-place
     * http://dtm.livejournal.com/38725.html
     * @param list
     */
    baw.shuffle = function shuffle(list) {
        var i, j, t;
        for (i = 1; i < list.length; i++) {
            j = Math.floor(Math.random()*(1+i));  // choose j in [0..i]
            if (j != i) {
                t = list[i];                        // swap list[i] and list[j]
                list[i] = list[j];
                list[j] = t;
            }
        }

//        var length = list.length;
//
//        var olds = angular.copy(list);
//
//        for (var i = 0; i < length; i++) {
//            var randomIndex = Math.floor(Math.random()  * (olds.length));
//            list[i] = olds.splice(randomIndex, 1)[0];
//        }
    };

    /**
     * Chainable if statement
     * @param test - the test that is evaluated
     * @param {Function} truthyAction - the function to run if the test is truthy
     * @param {Function} falseyAction - the function to run if the test id falsey
     * @returns {Object} returns 'this'
     */
    baw.fluidIf = function fluidIf(test, truthyAction, falseyAction) {
        if (test) {
            return truthyAction.call(this) || this;
        }

        if (falseyAction) {
            return falseyAction.call(this) || this;
        }

        return this;
    };

    baw.toType = function toType(obj) {
        return ({}).toString.call(obj).match(/\s([a-zA-Z]+)/)[1].toLowerCase()
    };

    function stringPad(number, paddingDigits, paddingCharacter) {
        var padLoop = Math.floor(number).toString().length;

        var output = number.toString();
        if (!paddingCharacter) {
            paddingCharacter = '0';
        }
        while (padLoop < paddingDigits) {
            padLoop++;
            output = paddingCharacter + output;
        }
        return output;
    }

    baw.stringPad = stringPad;

    /**
     * A custom formatter for TimeSpans - accepts seconds only
     * @param seconds - the number of seconds to convert
     * @returns {string}
     */
    baw.secondsToDurationFormat = function secondsToDurationFormat(seconds) {
        if (typeof seconds != 'number') {
            seconds = parseFloat(seconds);
        }

        if (isNaN(seconds)) {
            return seconds;
        }

        var negative = false;
        if (seconds < 0) {
            negative = true;
            seconds = Math.abs(seconds);
        }

        var totalMilliseconds = Math.round(seconds * 1000),
            totalSeconds = seconds,
            totalMinutes = seconds / 60,
            totalHours = totalMinutes / 60,
            totalDays = totalHours / 24,
            result = negative ? "-" : "";

        // default format [+/-d days] HH:mm:ss.fff
        var dayComponent = Math.floor(totalDays);
        if (dayComponent != 0) {
            result += dayComponent.toString() + ( dayComponent == 1 ? " day " : " days ");
        }

        result += stringPad(Math.floor(totalHours) % 24, 2) + ":";
        result += stringPad(Math.floor(totalMinutes) % 60, 2) + ":";
        result += stringPad(Math.floor(totalSeconds) % 60, 2) + ".";
        result += stringPad(totalMilliseconds % 1000, 3);

        return result;
    };

    /**
     * Is it a valid guid?
     * @type {RegExp}
     */
    baw.GUID_REGEXP = /^\{?[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\}?$/i;

    baw.popUpWindow = function popUpWindow(provider_url, width, height, callback) {
        var screenX = typeof window.screenX != 'undefined' ? window.screenX : window.screenLeft,
            screenY = typeof window.screenY != 'undefined' ? window.screenY : window.screenTop,
            outerWidth = typeof window.outerWidth != 'undefined' ? window.outerWidth : document.body.clientWidth,
            outerHeight = typeof window.outerHeight != 'undefined' ? window.outerHeight : (document.body.clientHeight - 22),
            left = parseInt(screenX + ((outerWidth - width) / 2), 10),
            top = parseInt(screenY + ((outerHeight - height) / 2.5), 10),
            features = ('width=' + width + ',height=' + height + ',left=' + left + ',top=' + top);

        var returneddata = 0;
        var newWindow = window.open(provider_url, 'Login', features);
        newWindow.returneddata = returneddata;

        function callbackOnClose() {
            setTimeout(function () {
                if (newWindow.closed) {
                    callback(newWindow.returneddata);
                }
                else {
                    callbackOnClose();
                }
            }, 50);
        }


        if (callback) {
            callbackOnClose();
        }

        if (window.focus)
            newWindow.focus();

        return false;
    };

    baw.angularCopies = new (function Angular() {
        this.fixedEncodeURIComponent = function fixedEncodeURIComponent(str) {
            str = str || "";
            return encodeURIComponent(str)
                .replace(/!/g, '%21')
                .replace(/'/g, '%27')
                .replace(/\(/g, '%28')
                .replace(/\)/g, '%29')
                .replace(/\*/g, '%2A')
                .replace(/%20/g, '+');
        };
        this.toKeyValue = function toKeyValue(obj) {
            var parts = [];
            angular.forEach(obj, function (value, key) {
                parts.push(encodeUriQuery(key, true) + (value === true ? '' : '=' + encodeUriQuery(value, true)));
            });
            return parts.length ? parts.join('&') : '';
        };
        this.encodeUriQuery = function encodeUriQuery(val, pctEncodeSpaces) {
            val = val || "";
            return encodeURIComponent(val).
                replace(/%40/gi, '@').
                replace(/%3A/gi, ':').
                replace(/%24/g, '$').
                replace(/%2C/gi, ',').
                replace((pctEncodeSpaces ? null : /%20/g), '+');
        };

        this.isUndefined = function isUndefined(value) {
            return typeof value == 'undefined';
        }

    });

}());


///**
// * moment duration patch
// *
// */
//if (moment) {
//    // make a dummy instance so i can patch constructor
//    var dummy = moment.duration();
//
//    // basic implementation, enhance where necessary
//    dummy.prototype.format = function momentDurationFormat() {
//        var result = "";
//
//        // default format [+/-d days] HH:mm:ss.fff
//        var dayComponent = Math.floor(this.asDays());
//        if (dayComponent != 0) {
//            result += dayComponent.toString() + " days ";
//        }
//
//        result += stringPad(Math.floor(this.hours()), 2) + ":";
//        result += stringPad(Math.floor(this.minutes()), 2) + ":";
//        result += stringPad(this.seconds().toFixed(3), 2);
//
//        return result;
//    };
//}
//else {
//    throw "moment.js not found, cannot patch";
//}