Repository

js/Mobilizing/core/util/Device.js

const MOBILE = "mobile";

const DESKTOP = "desktop";

// A map of regular expressions to test the userAgent with and retreive OS information
const OS_REGEX = new Map([
    ["Windows 10", /(Windows 10.0|Windows NT 10.0)/],
    ["Windows 8.1", /(Windows 8.1|Windows NT 6.3)/],
    ["Windows 8", /(Windows 8|Windows NT 6.2)/],
    ["Windows 7", /(Windows 7|Windows NT 6.1)/],
    ["Windows Vista", /Windows NT 6.0/],
    ["Windows Server 2003", /Windows NT 5.2/],
    ["Windows XP", /(Windows NT 5.1|Windows XP)/],
    ["Windows 2000", /(Windows NT 5.0|Windows 2000)/],
    ["Windows ME", /(Win 9x 4.90|Windows ME)/],
    ["Windows 98", /(Windows 98|Win98)/],
    ["Windows 95", /(Windows 95|Win95|Windows_95)/],
    ["Windows NT 4.0", /(Windows NT 4.0|WinNT4.0|WinNT|Windows NT)/],
    ["Windows CE", /Windows CE/],
    ["Windows 3.11", /Win16/],
    ["Android", /Android/],
    ["Open BSD", /OpenBSD/],
    ["Sun OS", /SunOS/],
    ["Linux", /(Linux|X11)/],
    ["iOS", /(iPhone|iPad|iPod)/],
    ["Mac OS X", /Mac OS X/],
    ["Mac OS", /(MacPPC|MacIntel|Mac_PowerPC|Macintosh)/],
    ["QNX", /QNX/],
    ["UNIX", /UNIX/],
    ["BeOS", /BeOS/],
    ["OS/2", /OS\/2/],
    ["Search Bot", /(nuhk|Googlebot|Yammybot|Openbot|Slurp|MSNBot|Ask Jeeves\/Teoma|ia_archiver)/]
]);

const _STATICS = {};

/**
* Device class gives easy access to some device information such as the operating system and browser used
*
* @example
*     Mobilizing.Device.getOS();
*
* @class Device
*/
export default class Device {

    /**
    * Parse OS data from navigator.userAgent and navigator.appVersion
    * Credit goes to http://stackoverflow.com/questions/9514179/how-to-find-the-operating-system-version-using-javascript
    *
    * @method parseOSData
    * @static
    * @private
    */
    static parseOSData() {
        let os = "unknown";
        let osVersion = "unknown";

        for (const [key, regex] of OS_REGEX) {
            if (regex.test(navigator.userAgent)) {
                os = key;

                if (/Windows/.test(os)) {
                    osVersion = /Windows (.*)/.exec(os)[1];
                    os = "Windows";
                }
                break;
            }
        }

        switch (os) {
            case "Mac OS X":
                osVersion = /Mac OS X (10[._\d]+)/.exec(navigator.userAgent)[1];
                break;

            case "Android":
                osVersion = /Android ([._\d]+)/.exec(navigator.userAgent)[1];
                break;

            case "iOS":
                osVersion = /OS (\d+)_(\d+)_?(\d+)?/.exec(navigator.appVersion);
                osVersion = `${osVersion[1]}.${osVersion[2]}.${osVersion[3] | 0}`;
                break;
        }

        _STATICS.os = os;
        _STATICS.osVersion = osVersion;

    }

    /**
    * Parse browser data from navigator.appName, navigator.userAgent and navigator.appVersion
    * Credit goes to http://stackoverflow.com/questions/9514179/how-to-find-the-operating-system-version-using-javascript
    *
    * @method parseBrowserData
    * @static
    * @private
    */
    static parseBrowserData() {
        let browser = navigator.appName;
        let version;
        let majorVersion;
        let versionOffset;
        let nameOffset;
        let ix;

        // Opera
        if ((versionOffset = navigator.userAgent.indexOf("Opera")) !== -1) {
            browser = "Opera";
            version = navigator.userAgent.substring(versionOffset + 6);
            if ((versionOffset = navigator.userAgent.indexOf("Version")) !== -1) {
                version = navigator.userAgent.substring(versionOffset + 8);
            }
        }
        // MSIE
        else if ((versionOffset = navigator.userAgent.indexOf("MSIE")) !== -1) {
            browser = "Microsoft Internet Explorer";
            version = navigator.userAgent.substring(versionOffset + 5);
        }
        // Chrome
        else if ((versionOffset = navigator.userAgent.indexOf("Chrome")) !== -1) {
            browser = "Chrome";
            version = navigator.userAgent.substring(versionOffset + 7);
        }
        // Safari
        else if ((versionOffset = navigator.userAgent.indexOf("Safari")) !== -1) {
            browser = "Safari";
            version = navigator.userAgent.substring(versionOffset + 7);
            if ((versionOffset = navigator.userAgent.indexOf("Version")) !== -1) {
                version = navigator.userAgent.substring(versionOffset + 8);
            }
        }
        // Firefox
        else if ((versionOffset = navigator.userAgent.indexOf("Firefox")) !== -1) {
            browser = "Firefox";
            version = navigator.userAgent.substring(versionOffset + 8);
        }
        // MSIE 11+
        else if (navigator.userAgent.indexOf("Trident/") !== -1) {
            browser = "Microsoft Internet Explorer";
            version = navigator.userAgent.substring(navigator.userAgent.indexOf("rv:") + 3);
        }
        // Other browsers
        else if ((nameOffset = navigator.userAgent.lastIndexOf(" ") + 1) < (versionOffset = navigator.userAgent.lastIndexOf("/"))) {
            browser = navigator.userAgent.substring(nameOffset, versionOffset);
            version = navigator.userAgent.substring(versionOffset + 1);
            if (browser.toLowerCase() === browser.toUpperCase()) {
                browser = navigator.appName;
            }
        }

        // trim the version string
        if ((ix = version.indexOf(";")) !== -1) {
            version = version.substring(0, ix);
        }

        if ((ix = version.indexOf(" ")) !== -1) {
            version = version.substring(0, ix);
        }

        if ((ix = version.indexOf(")")) !== -1) {
            version = version.substring(0, ix);
        }

        majorVersion = parseInt(`${version}`, 10);
        if (isNaN(majorVersion)) {
            version = `${parseFloat(navigator.appVersion)}`;
            majorVersion = parseInt(navigator.appVersion, 10);
        }

        _STATICS.browser = browser;
        _STATICS.browserVersion = version;
        _STATICS.browserMajorVersion = majorVersion;

    }

    /**
    * Get the device type
    *
    * @method getType
    * @static
    * @return {String} The device type (mobile or desktop)
    */
    static getType() {
        if (!("type" in _STATICS)) {
            _STATICS.type = /Mobile|mini|Fennec|Android|iP(ad|od|hone)/.test(navigator.appVersion) ? MOBILE : DESKTOP;
        }

        return _STATICS.type;
    }

    /**
    * Get the operating system's type
    *
    * @method getOS
    * @static
    * @return {String} The OS type (Windows, Mac OS X, Android, iOS, etc)
    */
    static getOS() {
        if (!("os" in _STATICS)) {
            Device.parseOSData();
        }

        return _STATICS.os;
    }

    /**
    * Get the operating system's version
    *
    * @method getOSVersion
    * @static
    * @return {String} The OS version
    */
    static getOSVersion() {
        if (!("osVersion" in _STATICS)) {
            Device.parseOSData();
        }

        return _STATICS.osVersion;
    }

    /**
    * Get the name of the web browser
    *
    * @method getBrowser
    * @static
    * @return {String} The browser's name
    */
    static getBrowser() {
        if (!("browser" in _STATICS)) {
            Device.parseBrowserData();
        }

        return _STATICS.browser;
    }

    /**
    * Get the version of the web browser
    *
    * @method getBrowserVersion
    * @static
    * @return {String} The browser's version
    */
    static getBrowserVersion() {
        if (!("browserVersion" in _STATICS)) {
            Device.parseBrowserData();
        }

        return _STATICS.browserVersion;
    }

    /**
    * Get the major version number of the web browser
    *
    * @method getBrowserMajorVersion
    * @static
    * @return {Number} The browser's major version
    */
    static getBrowserMajorVersion() {
        if (!("browserMajorVersion" in _STATICS)) {
            Device.parseBrowserData();
        }

        return _STATICS.browserMajorVersion;
    }

    /**
    * Get the framework the html page is running under (ejecta or cordova), if any
    *
    * @method getFramework
    * @static
    * @return {String} The framework's name, or null if none
    */
    static getFramework() {
        if (!("framework" in _STATICS)) {
            _STATICS.framework = null;

            if (navigator.userAgent.toLowerCase().indexOf("ejecta") > -1) {
                _STATICS.framework = "ejecta";
            }
            else if (window.cordova) {
                _STATICS.framework = "cordova";
            }
        }

        return _STATICS.framework;
    }

    /**
    * Get the screen's width
    * This does not necessarily indicate the width available
    * Some of the screen's width might be used by browser widgets and scrollbars
    *
    * @method getScreenWidth
    * @static
    * @return {Number} The screen's width in pixels
    */
    static getScreenWidth() {
        return window.screen.width;
    }

    /**
    * Get the screen's height
    * This does not necessarily indicate the height available
    * Some of the screen's height might be used by browser widgets and scrollbars
    *
    * @method getScreenHeight
    * @static
    * @return {Number} The screen's height in pixels
    */
    static getScreenHeight() {
        return window.screen.height;
    }

    /**
    * Shortcut to {{#crossLink "Device/getScreenWidth:method"}}{{/crossLink}} and {{#crossLink "Device/getScreenHeight:method"}}{{/crossLink}}
    *
    * @method getScreenSize
    * @static
    * @return {Object} An object with "width" and "height" as keys representing the screen's dimensions
    */
    static getScreenSize() {
        return {
            "width": Device.getScreenWidth(),
            "height": Device.getScreenHeight()
        };
    }

    static getUUID() {
        let uuid;

        if (window.cordova && window.device && ("uuid" in window.device)) {

            uuid = window.device.uuid;

        }
        else {

            uuid = window.localStorage.getItem("uuid");

            if (!uuid) {

                uuid = Date.now() + Math.floor(Math.random() * 10000000).toString() + Math.floor(Math.random() * 10000000).toString();

                window.localStorage.setItem("uuid", uuid);
            }
        }
        return uuid;
    }
}