can
Version:
MIT-licensed, client-side, JavaScript framework that makes building rich web applications easy.
292 lines (227 loc) • 6.62 kB
JavaScript
/*
---
name: Browser
description: The Browser Object. Contains Browser initialization, Window and Document, and the Browser Hash.
license: MIT-style license.
requires: [Array, Function, Number, String]
provides: [Browser, Window, Document]
...
*/
(function(){
var document = this.document;
var window = document.window = this;
var parse = function(ua, platform){
ua = ua.toLowerCase();
platform = (platform ? platform.toLowerCase() : '');
// chrome is included in the edge UA, so need to check for edge first,
// before checking if it's chrome.
var UA = ua.match(/(edge)[\s\/:]([\w\d\.]+)/);
if (!UA){
UA = ua.match(/(opera|ie|firefox|chrome|trident|crios|version)[\s\/:]([\w\d\.]+)?.*?(safari|(?:rv[\s\/:]|version[\s\/:])([\w\d\.]+)|$)/) || [null, 'unknown', 0];
}
if (UA[1] == 'trident'){
UA[1] = 'ie';
if (UA[4]) UA[2] = UA[4];
} else if (UA[1] == 'crios'){
UA[1] = 'chrome';
}
platform = ua.match(/ip(?:ad|od|hone)/) ? 'ios' : (ua.match(/(?:webos|android)/) || ua.match(/mac|win|linux/) || ['other'])[0];
if (platform == 'win') platform = 'windows';
return {
extend: Function.prototype.extend,
name: (UA[1] == 'version') ? UA[3] : UA[1],
version: parseFloat((UA[1] == 'opera' && UA[4]) ? UA[4] : UA[2]),
platform: platform
};
};
var Browser = this.Browser = parse(navigator.userAgent, navigator.platform);
if (Browser.name == 'ie' && document.documentMode){
Browser.version = document.documentMode;
}
Browser.extend({
Features: {
xpath: !!(document.evaluate),
air: !!(window.runtime),
query: !!(document.querySelector),
json: !!(window.JSON)
},
parseUA: parse
});
//<1.4compat>
Browser[Browser.name] = true;
Browser[Browser.name + parseInt(Browser.version, 10)] = true;
if (Browser.name == 'ie' && Browser.version >= '11'){
delete Browser.ie;
}
var platform = Browser.platform;
if (platform == 'windows'){
platform = 'win';
}
Browser.Platform = {
name: platform
};
Browser.Platform[platform] = true;
//</1.4compat>
// Request
Browser.Request = (function(){
var XMLHTTP = function(){
return new XMLHttpRequest();
};
var MSXML2 = function(){
return new ActiveXObject('MSXML2.XMLHTTP');
};
var MSXML = function(){
return new ActiveXObject('Microsoft.XMLHTTP');
};
return Function.attempt(function(){
XMLHTTP();
return XMLHTTP;
}, function(){
MSXML2();
return MSXML2;
}, function(){
MSXML();
return MSXML;
});
})();
Browser.Features.xhr = !!(Browser.Request);
//<1.4compat>
// Flash detection
var version = (Function.attempt(function(){
return navigator.plugins['Shockwave Flash'].description;
}, function(){
return new ActiveXObject('ShockwaveFlash.ShockwaveFlash').GetVariable('$version');
}) || '0 r0').match(/\d+/g);
Browser.Plugins = {
Flash: {
version: Number(version[0] || '0.' + version[1]) || 0,
build: Number(version[2]) || 0
}
};
//</1.4compat>
// String scripts
Browser.exec = function(text){
if (!text) return text;
if (window.execScript){
window.execScript(text);
} else {
var script = document.createElement('script');
script.setAttribute('type', 'text/javascript');
script.text = text;
document.head.appendChild(script);
document.head.removeChild(script);
}
return text;
};
String.implement('stripScripts', function(exec){
var scripts = '';
var text = this.replace(/<script[^>]*>([\s\S]*?)<\/script>/gi, function(all, code){
scripts += code + '\n';
return '';
});
if (exec === true) Browser.exec(scripts);
else if (typeOf(exec) == 'function') exec(scripts, text);
return text;
});
// Window, Document
Browser.extend({
Document: this.Document,
Window: this.Window,
Element: this.Element,
Event: this.Event
});
this.Window = this.$constructor = new Type('Window', function(){});
this.$family = Function.from('window').hide();
Window.mirror(function(name, method){
window[name] = method;
});
this.Document = document.$constructor = new Type('Document', function(){});
document.$family = Function.from('document').hide();
Document.mirror(function(name, method){
document[name] = method;
});
document.html = document.documentElement;
if (!document.head) document.head = document.getElementsByTagName('head')[0];
if (document.execCommand) try {
document.execCommand("BackgroundImageCache", false, true);
} catch (e){}
/*<ltIE9>*/
if (this.attachEvent && !this.addEventListener){
var unloadEvent = function(){
this.detachEvent('onunload', unloadEvent);
document.head = document.html = document.window = null;
window = this.Window = document = null;
};
this.attachEvent('onunload', unloadEvent);
}
// IE fails on collections and <select>.options (refers to <select>)
var arrayFrom = Array.from;
try {
arrayFrom(document.html.childNodes);
} catch(e){
Array.from = function(item){
if (typeof item != 'string' && Type.isEnumerable(item) && typeOf(item) != 'array'){
var i = item.length, array = new Array(i);
while (i--) array[i] = item[i];
return array;
}
return arrayFrom(item);
};
var prototype = Array.prototype,
slice = prototype.slice;
['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift', 'concat', 'join', 'slice'].each(function(name){
var method = prototype[name];
Array[name] = function(item){
return method.apply(Array.from(item), slice.call(arguments, 1));
};
});
}
/*</ltIE9>*/
//<1.2compat>
if (Browser.Platform.ios) Browser.Platform.ipod = true;
Browser.Engine = {};
var setEngine = function(name, version){
Browser.Engine.name = name;
Browser.Engine[name + version] = true;
Browser.Engine.version = version;
};
if (Browser.ie){
Browser.Engine.trident = true;
switch (Browser.version){
case 6: setEngine('trident', 4); break;
case 7: setEngine('trident', 5); break;
case 8: setEngine('trident', 6);
}
}
if (Browser.firefox){
Browser.Engine.gecko = true;
if (Browser.version >= 3) setEngine('gecko', 19);
else setEngine('gecko', 18);
}
if (Browser.safari || Browser.chrome){
Browser.Engine.webkit = true;
switch (Browser.version){
case 2: setEngine('webkit', 419); break;
case 3: setEngine('webkit', 420); break;
case 4: setEngine('webkit', 525);
}
}
if (Browser.opera){
Browser.Engine.presto = true;
if (Browser.version >= 9.6) setEngine('presto', 960);
else if (Browser.version >= 9.5) setEngine('presto', 950);
else setEngine('presto', 925);
}
if (Browser.name == 'unknown'){
switch ((navigator.userAgent.toLowerCase().match(/(?:webkit|khtml|gecko)/) || [])[0]){
case 'webkit':
case 'khtml':
Browser.Engine.webkit = true;
break;
case 'gecko':
Browser.Engine.gecko = true;
}
}
this.$exec = Browser.exec;
//</1.2compat>
})();