пятница, 8 июля 2016 г.

JavaScript Get Browser version

/**
 * @class window.env.Browser
 * Provides information about browser.
 *
 * Should not be manually instantiated unless for unit-testing.
 * Access the global instance stored in {@link window.env.browser} instead.
 * @private
 */
;(window.env || (window.env = {})).Browser = function (userAgent, publish) {
    // @define window.env.Browser
    // @define window.env.browser
   
   
    function isEmpty (value, allowEmptyString) {
        return (value === undefined || value === null) || (!allowEmptyString ? value === '' : false) || (isArray(value) && value.length === 0);
    }

    function isArray (value) {
        return Object.prototype.toString.call(value) === '[object Array]';
    }

    function apply (object, config, defaults) {
        var enumerables = ['valueOf', 'toLocaleString', 'toString', 'constructor'];
       
        if (defaults) {
            apply(object, defaults);
        }

        if (object && config && typeof config === 'object') {
            var i, j, k;

            for (i in config) {
                if (config.hasOwnProperty(i)) {
                    object[i] = config[i];
                }
            }

            if (enumerables) {
                for (j = enumerables.length; j--;) {
                    k = enumerables[j];
                    if (config.hasOwnProperty(k)) {
                        object[k] = config[k];
                    }
                }
            }
        }

        return object;
    }

    function getValues (object) {
        var values = [],
            property;

        for (property in object) {
            if (object.hasOwnProperty(property)) {
                values.push(object[property]);
            }
        }

        return values;
    }
   
    function getKey (object, value) {
        for (var property in object) {
            if (object.hasOwnProperty(property) && object[property] === value) {
                return property;
            }
        }

        return null;
    }
   

     function Version (version) {
            var me = this,
                padModes = me.padModes,
                ch, i, pad, parts, release, releaseStartIndex, ver;

            me.version = ver = String(version).toLowerCase().replace(/_/g, '.').replace(/[\-+]/g, '');

            ch = ver.charAt(0);
            if (ch in padModes) {
                ver = ver.substring(1);
                pad = padModes[ch];
            } else {
                pad = 0;
            }
            me.pad = pad;

            releaseStartIndex = ver.search(/([^\d\.])/);
            me.shortVersion = ver;

            if (releaseStartIndex !== -1) {
                me.release = release = ver.substr(releaseStartIndex, version.length);
                me.shortVersion = ver.substr(0, releaseStartIndex);
                release = Version.releaseValueMap[release] || release;
            }

            me.releaseValue = release || pad;
            me.shortVersion = me.shortVersion.replace(/[^\d]/g, '');

            /**
             * @property {Number[]} parts
             * The split array of version number components found in the version string.
             * For example, for "1.2.3", this would be `[1, 2, 3]`.
             * @readonly
             * @private
             */
            me.parts = parts = ver.split('.');
            for (i = parts.length; i--;) {
                parts[i] = parseInt(parts[i], 10);
            }
            if (pad === Infinity) {
                // have to add this to the end to create an upper bound:
                parts.push(pad);
            }

            /**
             * @property {Number} major
             * The first numeric part of the version number string.
             * @readonly
             */
            me.major = parts[0] || pad;

            return me;
    }
   
    Version.releaseValueMap = {
        dev:   -6,
        alpha: -5,
        a:     -5,
        beta:  -4,
        b:     -4,
        rc:    -3,
        '#':   -2,
        p:     -1,
        pl:    -1
    };
   
    Version.prototype = {
        padModes: {
            '~': NaN,
            '^': Infinity
        },
       
        /**
         * Returns the major component value.
         * @return {Number}
         */
        getMajor: function() {
            return this.major;
        },
       
        /**
         * Returns shortVersion version without dots and release
         * @return {String}
         */
        getShortVersion: function() {
            return this.shortVersion;
        }
    };

    var me = this,
        browserPrefixes = {
            ie: 'MSIE ',
            edge: 'Edge/',
            firefox: 'Firefox/',
            chrome: 'Chrome/',
            safari: 'Version/',
            opera: 'OPR/',
            dolfin: 'Dolfin/',
            webosbrowser: 'wOSBrowser/',
            chromeMobile: 'CrMo/',
            chromeiOS: 'CriOS/',
            silk: 'Silk/'
        },
        browserNames = {
            ie: 'IE',
            firefox: 'Firefox',
            safari: 'Safari',
            chrome: 'Chrome',
            opera: 'Opera',
            dolfin: 'Dolfin',
            edge: 'Edge',
            webosbrowser: 'webOSBrowser',
            chromeMobile: 'ChromeMobile',
            chromeiOS: 'ChromeiOS',
            silk: 'Silk',
            other: 'Other'
        },
        enginePrefixes = me.enginePrefixes,
        engineNames = me.engineNames,
        browserMatch = userAgent.match(new RegExp('((?:' + getValues(browserPrefixes).join(')|(?:') + '))([\\w\\._]+)')),
        engineMatch = userAgent.match(new RegExp('((?:' + getValues(enginePrefixes).join(')|(?:') + '))([\\w\\._]+)')),
        browserName = browserNames.other,
        engineName = engineNames.other,
        browserVersion = '',
        engineVersion = '',
        majorVer = '',
        isWebView = false,
        i, prefix, mode, name, maxIEVersion;

    /**
     * @property {String}
     * Browser User Agent string.
     */
    me.userAgent = userAgent;

    /**
     * A "hybrid" property, can be either accessed as a method call, for example:
     *
     *     if (window.env.browser.is('IE')) {
     *         // ...
     *     }
     *
     * Or as an object with Boolean properties, for example:
     *
     *     if (window.env.browser.is.IE) {
     *         // ...
     *     }
     *
     * Versions can be conveniently checked as well. For example:
     *
     *     if (window.env.browser.is.IE10) {
     *         // Equivalent to (window.env.browser.is.IE && window.env.browser.version.equals(10))
     *     }
     *
     * __Note:__ Only {@link Version#getMajor major component}  and {@link Version#getShortVersion simplified}
     * value of the version are available via direct property checking.
     *
     * Supported values are:
     *
     * - IE
     * - Firefox
     * - Safari
     * - Chrome
     * - Opera
     * - WebKit
     * - Gecko
     * - Presto
     * - Trident
     * - WebView
     * - Other
     *
     * @param {String} name The OS name to check.
     * @return {Boolean}
     */
    this.is = function (name) {
        // Since this function reference also acts as a map, we do not want it to be
        // shared between instances, so it is defined here, not on the prototype.
        return !!this.is[name];
    };

    // Edge has a userAgent with All browsers so we manage it separately
    // "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36 Edge/12.10240"
    if (/Edge\//.test(userAgent)) {
        browserMatch = userAgent.match(/(Edge\/)([\w.]+)/);
    }

    if (browserMatch) {
        browserName = browserNames[getKey(browserPrefixes, browserMatch[1])];
        //<feature legacyBrowser>
        if (browserName === 'Safari' && /^Opera/.test(userAgent)) {
            // Prevent Opera 12 and earlier from being incorrectly reported as Safari
            browserName = 'Opera';
        }
        //</feature>
        browserVersion = new Version(browserMatch[2]);
    }

    if (engineMatch) {
        engineName = engineNames[getKey(enginePrefixes, engineMatch[1])];
        engineVersion = new Version(engineMatch[2]);
    }

    if (engineName === 'Trident' && browserName !== 'IE') {
        browserName = 'IE';
        var version = userAgent.match(/.*rv:(\d+.\d+)/);
        if (version && version.length) {
            version = version[1];
            browserVersion = new Version(version);
        }
    }
   
    /**
     * @property chromeVersion
     * The current version of Chrome (0 if the browser is not Chrome).
     * @readonly
     * @type Number
     */

    /**
     * @property firefoxVersion
     * The current version of Firefox (0 if the browser is not Firefox).
     * @readonly
     * @type Number
     */

    /**
     * @property ieVersion
     * The current version of IE (0 if the browser is not IE). This does not account
     * for the documentMode of the current page, which is factored into {@link #isIE8},
     * and {@link #isIE9}. Thus this is not always true:
     *
     *     window.env.isIE8 == (window.env.ieVersion == 8)
     *
     * @readonly
     * @type Number
     */

    /**
     * @property isChrome
     * True if the detected browser is Chrome.
     * @readonly
     * @type Boolean
     */

    /**
     * @property isGecko
     * True if the detected browser uses the Gecko layout engine (e.g. Mozilla, Firefox).
     * @readonly
     * @type Boolean
     */

    /**
     * @property isIE
     * True if the detected browser is Internet Explorer.
     * @readonly
     * @type Boolean
     */

    /**
     * @property isIE8
     * True if the detected browser is Internet Explorer 8.x.
     * @readonly
     * @type Boolean
     */

    /**
     * @property isIE8m
     * True if the detected browser is Internet Explorer 8.x or lower.
     * @readonly
     * @type Boolean
     */

    /**
     * @property isIE8p
     * True if the detected browser is Internet Explorer 8.x or higher.
     * @readonly
     * @type Boolean
     */

    /**
     * @property isIE9
     * True if the detected browser is Internet Explorer 9.x.
     * @readonly
     * @type Boolean
     */

    /**
     * @property isIE9m
     * True if the detected browser is Internet Explorer 9.x or lower.
     * @readonly
     * @type Boolean
     */

    /**
     * @property isIE9p
     * True if the detected browser is Internet Explorer 9.x or higher.
     * @readonly
     * @type Boolean
     */

    /**
     * @property isIE10
     * True if the detected browser is Internet Explorer 10.x.
     * @readonly
     * @type Boolean
     */

    /**
     * @property isIE10m
     * True if the detected browser is Internet Explorer 10.x or lower.
     * @readonly
     * @type Boolean
     */

    /**
     * @property isIE10p
     * True if the detected browser is Internet Explorer 10.x or higher.
     * @readonly
     * @type Boolean
     */

    /**
     * @property isIE11
     * True if the detected browser is Internet Explorer 11.x.
     * @readonly
     * @type Boolean
     */

    /**
     * @property isIE11m
     * True if the detected browser is Internet Explorer 11.x or lower.
     * @readonly
     * @type Boolean
     */

    /**
     * @property isIE11p
     * True if the detected browser is Internet Explorer 11.x or higher.
     * @readonly
     * @type Boolean
     */

    /**
     * @property isEdge
     * True if the detected browser is Edge.
     * @readonly
     * @type Boolean
     */

    /**
     * @property isLinux
     * True if the detected platform is Linux.
     * @readonly
     * @type Boolean
     */

    /**
     * @property isMac
     * True if the detected platform is Mac OS.
     * @readonly
     * @type Boolean
     */

    /**
     * @property isOpera
     * True if the detected browser is Opera.
     * @readonly
     * @type Boolean
     */

    /**
     * @property isSafari
     * True if the detected browser is Safari.
     * @readonly
     * @type Boolean
     */

    /**
     * @property isWebKit
     * True if the detected browser uses WebKit.
     * @readonly
     * @type Boolean
     */

    /**
     * @property isWindows
     * True if the detected platform is Windows.
     * @readonly
     * @type Boolean
     */

    /**
     * @property operaVersion
     * The current version of Opera (0 if the browser is not Opera).
     * @readonly
     * @type Number
     */

    /**
     * @property safariVersion
     * The current version of Safari (0 if the browser is not Safari).
     * @readonly
     * @type Number
     */

    /**
     * @property webKitVersion
     * The current version of WebKit (0 if the browser does not use WebKit).
     * @readonly
     * @type Number
     */

    // Facebook changes the userAgent when you view a website within their iOS app. For some reason, the strip out information
    // about the browser, so we have to detect that and fake it...
    if (userAgent.match(/FB/) && browserName === "Other") {
        browserName = browserNames.safari;
        engineName = engineNames.webkit;
    }

    if (userAgent.match(/Android.*Chrome/g)) {
        browserName = 'ChromeMobile';
    }

    if (userAgent.match(/OPR/)) {
        browserName = 'Opera';
        browserMatch = userAgent.match(/OPR\/(\d+.\d+)/);
        browserVersion = new Version(browserMatch[1]);
    }

    apply(this, {
        engineName: engineName,
        engineVersion: engineVersion,
        name: browserName,
        version: browserVersion
    });

    this.setFlag(browserName, true, publish); // e.g., window.env.isIE

    if (browserVersion) {
        majorVer = browserVersion.getMajor() || '';
        //<feature legacyBrowser>
        if (me.is.IE) {
            majorVer = parseInt(majorVer, 10);
            mode = document.documentMode;

            // IE's Developer Tools allows switching of Browser Mode (userAgent) and
            // Document Mode (actual behavior) independently. While this makes no real
            // sense, the bottom line is that document.documentMode holds the key to
            // getting the proper "version" determined. That value is always 5 when in
            // Quirks Mode.

            if (mode === 7 || (majorVer === 7 && mode !== 8 && mode !== 9 && mode !== 10)) {
                majorVer = 7;
            } else if (mode === 8 || (majorVer === 8 && mode !== 8 && mode !== 9 && mode !== 10)) {
                majorVer = 8;
            } else if (mode === 9 || (majorVer === 9 && mode !== 7 && mode !== 8 && mode !== 10)) {
                majorVer = 9;
            } else if (mode === 10 || (majorVer === 10 && mode !== 7 && mode !== 8 && mode !== 9)) {
                majorVer = 10;
            } else if (mode === 11 || (majorVer === 11 && mode !== 7 && mode !== 8 && mode !== 9 && mode !== 10)) {
                majorVer = 11;
            }

            maxIEVersion = Math.max(majorVer, 12);
            for (i = 7; i <= maxIEVersion; ++i) {
                prefix = 'isIE' + i;
                if (majorVer <= i) {
                    window.env[prefix + 'm'] = true;
                }

                if (majorVer === i) {
                    window.env[prefix] = true;
                }

                if (majorVer >= i) {
                    window.env[prefix + 'p'] = true;
                }
            }
        }

        if (me.is.Opera && parseInt(majorVer, 10) <= 12) {
            window.env.isOpera12m = true;
        }
        //</feature>

        window.env.chromeVersion = window.env.isChrome ? majorVer : 0;
        window.env.firefoxVersion = window.env.isFirefox ? majorVer : 0;
        window.env.ieVersion = window.env.isIE ? majorVer : 0;
        window.env.operaVersion = window.env.isOpera ? majorVer : 0;
        window.env.safariVersion = window.env.isSafari ? majorVer : 0;
        window.env.webKitVersion = window.env.isWebKit ? majorVer : 0;

        this.setFlag(browserName + majorVer, true, publish); // window.env.isIE10
        this.setFlag(browserName + browserVersion.getShortVersion());
    }

    for (i in browserNames) {
        if (browserNames.hasOwnProperty(i)) {
            name = browserNames[i];

            this.setFlag(name, browserName === name);
        }
    }

    this.setFlag(name);

    if (engineVersion) {
        this.setFlag(engineName + (engineVersion.getMajor() || ''));
        this.setFlag(engineName + engineVersion.getShortVersion());
    }

    for (i in engineNames) {
        if (engineNames.hasOwnProperty(i)) {
            name = engineNames[i];

            this.setFlag(name, engineName === name, publish);
        }
    }

    this.setFlag('Standalone', !!navigator.standalone);

    this.setFlag('Ripple', !!document.getElementById("tinyhippos-injected") && !isEmpty(window.top.ripple));
    this.setFlag('WebWorks', !!window.blackberry);

    if (window.PhoneGap !== undefined || window.Cordova !== undefined || window.cordova !== undefined) {
        isWebView = true;
        this.setFlag('PhoneGap');
        this.setFlag('Cordova');
    }

    // Check if running in UIWebView
    if (/(iPhone|iPod|iPad).*AppleWebKit(?!.*Safari)(?!.*FBAN)/i.test(userAgent)) {
        isWebView = true;
    }

    // Flag to check if it we are in the WebView
    this.setFlag('WebView', isWebView);

    /**
     * @property {Boolean}
     * `true` if browser is using strict mode.
     */
    this.isStrict = window.env.isStrict = document.compatMode === "CSS1Compat";

    /**
     * @property {Boolean}
     * `true` if page is running over SSL.
     */
    this.isSecure = /^https/i.test(window.location.protocol);

    // IE10Quirks, Chrome26Strict, etc.
    this.identity = browserName + majorVer + (this.isStrict ? 'Strict' : 'Quirks');
};

window.env.Browser.prototype = {
    constructor: window.env.Browser,

    engineNames: {
        webkit: 'WebKit',
        gecko: 'Gecko',
        presto: 'Presto',
        trident: 'Trident',
        other: 'Other'
    },

    enginePrefixes: {
        webkit: 'AppleWebKit/',
        gecko: 'Gecko/',
        presto: 'Presto/',
        trident: 'Trident/'
    },

    styleDashPrefixes: {
        WebKit: '-webkit-',
        Gecko: '-moz-',
        Trident: '-ms-',
        Presto: '-o-',
        Other: ''
    },

    stylePrefixes: {
        WebKit: 'Webkit',
        Gecko: 'Moz',
        Trident: 'ms',
        Presto: 'O',
        Other: ''
    },

    propertyPrefixes: {
        WebKit: 'webkit',
        Gecko: 'moz',
        Trident: 'ms',
        Presto: 'o',
        Other: ''
    },

    // scope: window.env.Browser.prototype

    /**
     * The full name of the current browser.
     * Possible values are:
     *
     * - IE
     * - Firefox
     * - Safari
     * - Chrome
     * - Opera
     * - Other
     * @type String
     * @readonly
     */
    name: null,

    /**
     * Refer to {@link Version}.
     * @type Version
     * @readonly
     */
    version: null,

    /**
     * The full name of the current browser's engine.
     * Possible values are:
     *
     * - WebKit
     * - Gecko
     * - Presto
     * - Trident
     * - Other
     * @type String
     * @readonly
     */
    engineName: null,

    /**
     * Refer to {@link Version}.
     * @type Version
     * @readonly
     */
    engineVersion: null,

    setFlag: function(name, value, publish) {
        if (value === undefined) {
            value = true;
        }

        this.is[name] = value;
        this.is[name.toLowerCase()] = value;
        if (publish) {
            window.env['is' + name] = value;
        }

        return this;
    },

    getStyleDashPrefix: function() {
        return this.styleDashPrefixes[this.engineName];
    },

    getStylePrefix: function() {
        return this.stylePrefixes[this.engineName];
    },

    getVendorProperyName: function(name) {
        function capitalize (string) {
            if (string) {
                string = string.charAt(0).toUpperCase() + string.substr(1);
            }
            return string || '';
        }
       
        var prefix = this.propertyPrefixes[this.engineName];

        if (prefix.length > 0) {
            return prefix + capitalize(name);
        }

        return name;
    },

    getPreferredTranslationMethod: function(config) {
        if (typeof config === 'object' && 'translationMethod' in config && config.translationMethod !== 'auto') {
            return config.translationMethod;
        } else {
            return 'csstransform';
        }
    }

};

/**
 * @class window.env.browser
 * @extends window.env.Browser
 * @singleton
 * Provides useful information about the current browser.
 *
 * Example:
 *
 *     if (window.env.browser.is.IE) {
 *         // IE specific code here
 *     }
 *
 *     if (window.env.browser.is.WebKit) {
 *         // WebKit specific code here
 *     }
 *
 *     console.log("Version " + window.env.browser.version);
 *
 * For a full list of supported values, refer to {@link #is} property/method.
 *
 */
;(function (userAgent) {
    window.env.browser = new window.env.Browser(userAgent, true);
    window.env.userAgent = userAgent.toLowerCase();

    /**
     * @property {String} SSL_SECURE_URL
     * URL to a blank file used when in secure mode for iframe src and onReady src
     * to prevent the IE insecure content warning (`'about:blank'`, except for IE
     * in secure mode, which is `'javascript:""'`).
     */
    window.env.SSL_SECURE_URL = /^https/i.test(window.location.protocol) && window.env.isIE ? 'javascript:\'\'' : 'about:blank'; // jshint ignore:line
})(window.navigator.userAgent);

console.log(window.env.browser.name);
console.log(window.env.browser.version.version);

Комментариев нет:

Отправить комментарий