diff --git a/ISSUE_TEMPLATE.md b/ISSUE_TEMPLATE.md new file mode 100644 index 0000000..165469f --- /dev/null +++ b/ISSUE_TEMPLATE.md @@ -0,0 +1,5 @@ +Template to report about browser detection issue + +`window.navigator.userAgent` of the browser is: ... + And it's detected like a ... + But real name of the browser is ... diff --git a/src/bowser.js b/src/bowser.js index d966269..c76c4cc 100644 --- a/src/bowser.js +++ b/src/bowser.js @@ -407,6 +407,145 @@ return false; } + /** + * Get version precisions count + * + * @example + * getVersionPrecision("1.10.3") // 3 + * + * @param {string} version + * @return {number} + */ + function getVersionPrecision(version) { + return version.split(".").length; + } + + /** + * Array::map polyfill + * + * @param {Array} arr + * @param {Function} iterator + * @return {Array} + */ + function map(arr, iterator) { + var result = [], i; + if (Array.prototype.map) { + return Array.prototype.map.call(arr, iterator); + } + for (i = 0; i < arr.length; i++) { + result = iterator(arr[i]); + } + return result; + } + + /** + * Calculate browser version weight + * + * @example + * compareVersions(['1.10.2.1', '1.8.2.1.90']) // 1 + * compareVersions(['1.010.2.1', '1.09.2.1.90']); // 1 + * compareVersions(['1.10.2.1', '1.10.2.1']); // 0 + * compareVersions(['1.10.2.1', '1.0800.2']); // -1 + * + * @param {Array} versions versions to compare + * @return {Number} comparison result + */ + function compareVersions(versions) { + // 1) get common precision for both versions, for example for "10.0" and "9" it should be 2 + var precision = Math.max(getVersionPrecision(versions[0]), getVersionPrecision(versions[1])); + var chunks = map(versions, function (version) { + var delta = precision - getVersionPrecision(version); + + // 2) "9" -> "9.0" (for precision = 2) + version = version + new Array(delta + 1).join(".0"); + + // 3) "9.0" -> ["000000000"", "000000009"] + return map(version.split("."), function (chunk) { + return new Array(20 - chunk.length).join("0") + chunk; + }).reverse(); + }); + + // iterate in reverse order by reversed chunks array + while (--precision >= 0) { + // 4) compare: "000000009" > "000000010" = false (but "9" > "10" = true) + if (chunks[0][precision] > chunks[1][precision]) { + return 1; + } + else if (chunks[0][precision] === chunks[1][precision]) { + if (precision === 0) { + // all version chunks are same + return 0; + } + } + else { + return -1; + } + } + } + + /** + * Check if browser is unsupported + * + * @example + * bowser.isUnsupportedBrowser({ + * msie: "10", + * firefox: "23", + * chrome: "29", + * safari: "5.1", + * opera: "16", + * phantom: "534" + * }); + * + * @param {Object} minVersions map of minimal version to browser + * @param {Boolean} [strictMode = false] flag to return false if browser wasn't found in map + * @param {String} [ua] user agent string + * @return {Boolean} + */ + function isUnsupportedBrowser(minVersions, strictMode, ua) { + var _bowser = bowser; + + // make strictMode param optional with ua param usage + if (typeof strictMode === 'string') { + ua = strictMode; + strictMode = void(0); + } + + if (strictMode === void(0)) { + strictMode = false; + } + if (ua) { + _bowser = detect(ua); + } + + var version = "" + _bowser.version; + for (var browser in minVersions) { + if (minVersions.hasOwnProperty(browser)) { + if (_bowser[browser]) { + // browser version and min supported version. + if (compareVersions([version, minVersions[browser]]) < 0) { + return true; // unsupported + } + } + } + } + return strictMode; // not found + } + + /** + * Check if browser is supported + * + * @param {Object} minVersions map of minimal version to browser + * @param {Boolean} [strictMode = false] flag to return false if browser wasn't found in map + * @return {Boolean} + */ + function check(minVersions, strictMode) { + return !isUnsupportedBrowser(minVersions, strictMode); + } + + bowser.isUnsupportedBrowser = isUnsupportedBrowser; + bowser.compareVersions = compareVersions; + bowser.check = check; + /* * Set our detect method to the main bowser object so we can * reuse it to test other user agents. diff --git a/test/test.js b/test/test.js index c11e035..cce4198 100644 --- a/test/test.js +++ b/test/test.js @@ -73,3 +73,58 @@ for (g in allUserAgents) { (function(group, userAgents) { }) })(g, allUserAgents[g])} + +var comparisionsTasks = [ + ['9.0', '10', -1], + ['11', '10', 1], + ['1.10.2.1', '1.8.2.1.90', 1], + ['1.010.2.1', '1.08.2.1.90', 1], + ['1.10.2.1', '1.10.2.1', 0], + ['1.10.2.1', '1.0800.2', -1], + ['1.0.0-alpha', '1.0.0-alpha.1', -1], + ['1.0.0-alpha.1', '1.0.0-alpha.beta', -1], + ['1.0.0-alpha.beta', '1.0.0-beta', -1], + ['1.0.0-beta', '1.0.0-beta.2', -1], + ['1.0.0-beta.11', '1.0.0-rc.1', -1], + ['1.0.0-rc.1', '1.0.0', -1] +]; + +describe('Browser versions comparision', function() { + for(g in comparisionsTasks) { + var task = comparisionsTasks[g], + version = task[0], + version2 = task[1], + matching = task[2] === 0 ? ' == ' : (task[2] > 0) ? ' > ' : ' < '; + it('version ' + version + ' should be' + matching + 'version ' + version2, function(){ + assert.equal(browser.compareVersions([version, version2]), task[2]); + }); + } +}); + +describe('Unsupported browser check', function() { + + before(function() { + this.ie10_6 = "Mozilla/5.0 (compatible; MSIE 10.6; Windows NT 6.1; Trident/5.0; InfoPath.2; SLCC1; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; .NET CLR 2.0.50727) 3gpp-gba UNTRUSTED/1.0"; + }); + + it('should be passed by #isUnsupportedBrowser for IE10.6 and for IE10 miminal version specified', function() { + var unsupported = browser.isUnsupportedBrowser({msie: "10"}, this.ie10_6); + assert.equal(unsupported, false); + }); + + it('should NOT be passed by #check for IE10.6 and for IE11 miminal version specified', function() { + var supported = browser.check({msie: "11"}, this.ie10_6); + assert.equal(supported, false); + }); + + it('should be passed by #check for IE10.6 when version was not specified', function() { + var supported = browser.check({}, this.ie10_6); + assert.equal(supported, true); + }); + + it('should NOT be passed by #check for IE10.6 when version was not specified in strict mode', function() { + var supported = browser.check({}, true, this.ie10_6); + assert.equal(supported, false); + }); + +})