Repository

js/Mobilizing/core/util/Misc.js

/**
 * Simple object check.
 * @param  {any}     item - The item
 * @return {boolean} True if object, false otherwise.
 */
export function isObject(item) {
    return (item && typeof item === 'object' && !Array.isArray(item) && item !== null);
}

import cloneDeep from "lodash/cloneDeep";

export function cloneObject(object) {
    return cloneDeep(object);
}

/**
* Method to convert a string to Base64. Used internally to convert loaded raw data to img. Wrote by  phil@philten.com - http://www.philten.com
*
* @author phil@philten.com - http://www.philten.com
* Date: 2010/12/15
* version: 1.0
* url french: http://www.philten.com/fr-xmlhttprequest-image
* url english: http://www.philten.com/us-xmlhttprequest-image
* @param inputStr the string to encode
*/
export function encode64(inputStr) {
    const b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
    let outputStr = "";
    let i = 0;

    while (i < inputStr.length) {
        //all three "& 0xff" added below are there to fix a known bug
        //with bytes returned by xhr.responseText
        const byte1 = inputStr.charCodeAt(i++) & 0xff;
        const byte2 = inputStr.charCodeAt(i++) & 0xff;
        const byte3 = inputStr.charCodeAt(i++) & 0xff;

        const enc1 = byte1 >> 2;
        const enc2 = ((byte1 & 3) << 4) | (byte2 >> 4);

        var enc3, enc4;
        if (isNaN(byte2)) {
            enc3 = enc4 = 64;
        }
        else {
            enc3 = ((byte2 & 15) << 2) | (byte3 >> 6);
            if (isNaN(byte3)) {
                enc4 = 64;
            }
            else {
                enc4 = byte3 & 63;
            }
        }

        outputStr += b64.charAt(enc1) + b64.charAt(enc2) + b64.charAt(enc3) + b64.charAt(enc4);
    }

    return outputStr;
}

/**
* Converts a DOMString to an ArrayBuffer (raw data binary).
*
* @param {DOMString} str a string returned by a XMLHTTPRequest (responseText)
* @return {ArrayBuffer} the resulting ArrayBuffer
*/
export function stringToArrayBuffer(str) {
    const buffer = new ArrayBuffer(str.length);
    const bufView = new Uint8Array(buffer);
    for (let i = 0, strLen = str.length; i < strLen; i++) {
        bufView[i] = str.charCodeAt(i);
    }
    return buffer;
}

export function getFileExtension(url){
    if (url.lastIndexOf(".") > 0) {
        return url.substr(url.lastIndexOf(".")).toLowerCase();
    }
    return null;
}

/**
* Extract the MimeType from the URL string of image files. Used internally for texture loading
*
* @param {String} url
* @return {String} mimeType from the url
*/
export function getMimeType(url) {

    let mimeType = null;

    const extension = getFileExtension(url);

    if (extension === ".jpg" || extension === ".jpeg") {
        mimeType = "jpeg";
    }
    else if (extension === ".tiff" || extension === ".tif") {
        mimeType = "tiff";
    }
    else if (extension === ".png") {
        mimeType = "png";
    }
    else if (extension === ".gif") {
        mimeType = "gif";
    }

    console.log(`extension ${extension}`, `mimeType ${mimeType}`);

    return mimeType;
}

/**
* Returns a throttled version of a function
* The returned function will only call the original function at most once per the specified threshhold
*
* @param {Function} fn The function to throttle
* @param {Number} threshhold The threshhold in milliseconds
* @param {Object} scope The scope in which the original function will be called
* @return {Function} The throttled function
*/
export function throttle(fn, threshhold, scope = null) {
    let inThrottle;

    return function () {
        const args = arguments;

        if (!inThrottle) {
            fn.apply(scope, args);
            inThrottle = true;
            setTimeout(() => {
                inThrottle = false
            }, threshhold);
        }
    }
}

/**
* A function that return null as a value
*
* @return {null} null
*/
export function noop() {
    return null;
}

/**
* function to get the parameters of the url
*
* @param sParam the string of the parameter to get from the url
* @return {String} the parameter if found, undefined elsewhere
*/
export function getUrlParameter(sParam) {
    const sPageURL = decodeURIComponent(window.location.search.substring(1));
    const sURLVariables = sPageURL.split('&');

    for (let i = 0; i < sURLVariables.length; i++) {
        const sParameterName = sURLVariables[i].split('=');

        if (sParameterName[0] === sParam) {
            return (typeof sParameterName[1] === "undefined") ? true : sParameterName[1];
        }
    }

    return undefined;
}

/**
* Generate a random uuid
*
* @author Broofa <robert@broofa.com> (http://www.broofa.com/2008/09/javascript-uuid-function/)
* @param {Integer} [len] The desired number of characters
* @param {Integer} [radix] The number of allowable values for each character
* @return {String} The generated uuid
*
* @example
*    let id = uuid();
*    // "66209871-857D-4A12-AC7E-E9EEBC2A6AC3"
*
* @example
*    let id = uuid(5);
*    // "kryIh"
*
* @example
*    let id = uuid(5, 2);
*    // "10100"
*/
export function uuid(len, radix) {
    const chars = [
        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
        'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
        'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'
    ];
    const _radix = radix || chars.length;
    const id = [];

    if (len) {
        // Compact form
        for (let i = 0; i < len; i++) {
            id[i] = chars[0 | Math.random() * _radix];
        }
    }
    else {
        // rfc4122 requires these characters
        id[8] = id[13] = id[18] = id[23] = '-';
        id[14] = '4';

        // Fill in random data.    At i==19 set the high bits of clock sequence as per rfc4122, sec. 4.1.5
        for (let i = 0; i < 36; i++) {
            if (!id[i]) {
                const r = 0 | Math.random() * 16;
                id[i] = chars[(i === 19) ? (r & 0x3) | 0x8 : r];
            }
        }
    }

    return id.join('');
}

/**
Copyright (c) 2011, Daniel Guerrero
All rights reserved.
* Uses the new array typed in javascript to binary base64 encode/decode
* at the moment just decodes a binary base64 encoded
* into either an ArrayBuffer (decodeArrayBuffer)
* or into an Uint8Array (decode)
*
* References:
* https://developer.mozilla.org/en/JavaScript_typed_arrays/ArrayBuffer
* https://developer.mozilla.org/en/JavaScript_typed_arrays/Uint8Array
*/

export class Base64Binary {
    constructor() {
        this._keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
    }

    /* will return a  Uint8Array type */
    decodeArrayBuffer(input) {
        const bytes = (input.length / 4) * 3;
        const ab = new ArrayBuffer(bytes);
        this.decode(input, ab);

        return ab;
    }

    removePaddingChars(input) {
        const lkey = this._keyStr.indexOf(input.charAt(input.length - 1));
        if (lkey === 64) {
            return input.substring(0, input.length - 1);
        }
        return input;
    }

    decode(input, arrayBuffer) {
        //get last chars to see if are valid
        input = this.removePaddingChars(input);
        input = this.removePaddingChars(input);

        const bytes = parseInt((input.length / 4) * 3, 10);

        let uarray;
        let chr1, chr2, chr3;
        let enc1, enc2, enc3, enc4;
        let i = 0;
        let j = 0;

        if (arrayBuffer) {
            uarray = new Uint8Array(arrayBuffer);
        }
        else {
            uarray = new Uint8Array(bytes);
        }

        const regex = /[^A-Za-z0-9\+\/\=]/g;
        input = input.replace(regex, "");

        for (i = 0; i < bytes; i += 3) {
            //get the 3 octects in 4 ascii chars
            enc1 = this._keyStr.indexOf(input.charAt(j++));
            enc2 = this._keyStr.indexOf(input.charAt(j++));
            enc3 = this._keyStr.indexOf(input.charAt(j++));
            enc4 = this._keyStr.indexOf(input.charAt(j++));

            chr1 = (enc1 << 2) | (enc2 >> 4);
            chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
            chr3 = ((enc3 & 3) << 6) | enc4;

            uarray[i] = chr1;
            if (enc3 !== 64) {
                uarray[i + 1] = chr2;
            }
            if (enc4 !== 64) {
                uarray[i + 2] = chr3;
            }
        }

        return uarray;
    }
}