# The engine the browser is running on. # # Keep in mind it uses the user agent to know, so it's not reliable in case of # spoofing. BROWSER_ENGINE = `/MSIE|WebKit|Presto|Gecko/.exec(navigator.userAgent)[0]`.downcase rescue :unknown module Browser # @private @support = `{}` # Check if the browser supports the given feature. def self.supports?(feature) if defined?(`#@support[#{feature}]`) return `#@support[#{feature}]` end support = case feature when 'MutationObserver' defined?(`window.MutationObserver`) when 'WebSocket' defined?(`window.WebSocket`) when 'EventSource' defined?(`window.EventSource`) when 'XHR' defined?(`window.XMLHttpRequest`) when 'ActiveX' defined?(`window.ActiveXObject`) when 'WebSQL' defined?(`window.openDatabase`) when 'Query.css' defined?(`document.querySelectorAll`) when 'Query.xpath' defined?(`document.evaluate`) when 'Storage.local' defined?(`window.localStorage`) when 'Storage.global' defined?(`window.globalStorage`) when 'Storage.session' defined?(`window.sessionStorage`) when 'Immediate' defined?(`window.setImmediate`) when 'Immediate (Internet Explorer)' defined?(`window.msSetImmediate`) when 'Immediate (Firefox)' defined?(`window.mozSetImmediate`) when 'Immediate (Opera)' defined?(`window.oSetImmediate`) when 'Immediate (Chrome)', 'setImmediate (Safari)' defined?(`window.webkitSetImmediate`) when 'CSS.computed' defined?(`window.getComputedStyle`) when 'CSS.current' defined?(`document.documentElement.currentStyle`) when 'Window.send' defined?(`window.postMessage`) when 'Window.send (Asynchronous)' if defined?(`window.postMessage`) && !defined?(`window.importScripts`) %x{ (function() { var ok = true, old = window.onmessage; window.onmessage = function() { ok = false; }; window.postMessage("", "*") window.onmessage = old; return ok; })() } end when 'Window.send (Synchronous)' !supports?('Window.send (Asynchronous)') when 'Window.innerSize' defined?(`window.innerHeight`) when 'Window.outerSize' defined?(`window.outerHeight`) when 'Window.scroll' defined?(`document.documentElement.scrollLeft`) when 'Window.scrollBy' defined?(`document.documentElement.scrollBy`) when 'Window.pageOffset' defined?(`window.pageXOffset`) when 'Attr.isId' %x{ (function() { var div = document.createElement('div'); div.setAttribute('id', 'xxxxxxxxxxxxx'); return typeof(div.attributes['id'].isId) !== "undefined"; })() } when 'Element.addBehavior' defined?(`document.documentElement.addBehavior`) when 'Element.className' %x{ (function() { var div = document.createElement("div"); div.setAttribute('className', 'x'); return div.className === 'x'; })() } when 'Element.class' %x{ (function() { var div = document.createElement("div"); div.setAttribute('class', 'x'); return div.className === 'x'; })() } when 'Element.for' %x{ (function() { var label = document.createElement("label"); label.setAttribute('for', 'x'); return label.htmlFor === 'x'; })() } when 'Element.htmlFor' %x{ (function() { var label = document.createElement("label"); label.setAttribute('htmlFor', 'x'); return label.htmlFor === 'x'; })() } when 'Element.clientSize' defined?(`document.documentElement.clientHeight`) when 'Element.scroll' defined?(`document.documentElement.scrollLeft`) when 'Element.textContent' defined?(`document.documentElement.textContent`) when 'Element.innerText' defined?(`document.documentElement.innerText`) when 'Element.matches' defined?(`document.documentElement.matches`) when 'Element.matches (Internet Explorer)' defined?(`document.documentElement.msMatchesSelector`) when 'Element.matches (Firefox)' defined?(`document.documentElement.mozMatchesSelector`) when 'Element.matches (Opera)' defined?(`document.documentElement.oMatchesSelector`) when 'Element.matches (Chrome)', 'Element.matches (Safari)' defined?(`document.documentElement.webkitMatchesSelector`) when 'Element.getBoundingClientRect' defined?(`document.documentElement.getBoundingClientRect`) when 'Event.readystatechange' `"onreadystatechange" in window.document.createElement("script")` when 'Event.constructor' begin `new MouseEvent("click")` true rescue StandardError, JS::Error false end when 'Event.create' defined?(`document.createEvent`) when 'Event.createObject' defined?(`document.createEventObject`) when 'Event.addListener' defined?(`document.addEventListener`) when 'Event.attach' defined?(`document.attachEvent`) when 'Event.removeListener' defined?(`document.removeEventListener`) when 'Event.detach' defined?(`document.detachEvent`) when 'Event.dispatch' defined?(`document.dispatchEvent`) when 'Event.fire' defined?(`document.fireEvent`) when /^Event\.([A-Z].*?)$/ `(#{$1} + "Event") in window` when 'Document.view' defined?(`document.defaultView`) when 'Document.window' defined?(`document.parentWindow`) when 'History' defined?(`window.history.pushState`) when 'History.state' defined?(`window.history.state`) when 'Animation.request' defined?(`window.requestAnimationFrame`) when 'Animation.request (Internet Explorer)' defined?(`window.msRequestAnimationFrame`) when 'Animation.request (Firefox)' defined?(`window.mozRequestAnimationFrame`) when 'Animation.request (Opera)' defined?(`window.oRequestAnimationFrame`) when 'Animation.request (Chrome)', 'Animation.request (Safari)' defined?(`window.webkitRequestAnimationFrame`) when 'Animation.cancel' defined?(`window.cancelAnimationFrame`) when 'Animation.cancel (Internet Explorer)' defined?(`window.msCancelAnimationFrame`) when 'Animation.cancel (Firefox)' defined?(`window.mozCancelAnimationFrame`) when 'Animation.cancel (Opera)' defined?(`window.oCancelAnimationFrame`) when 'Animation.cancel (Chrome)', 'Animation.cancel (Safari)' defined?(`window.webkitCancelAnimationFrame`) when 'Animation.cancelRequest' defined?(`window.cancelRequestAnimationFrame`) when 'Animation.cancelRequest (Internet Explorer)' defined?(`window.msCancelRequestAnimationFrame`) when 'Animation.cancelRequest (Firefox)' defined?(`window.mozCancelRequestAnimationFrame`) when 'Animation.cancelRequest (Opera)' defined?(`window.oCancelRequestAnimationFrame`) when 'Animation.cancelRequest (Chrome)', 'Animation.cancelRequest (Safari)' defined?(`window.webkitCancelRequestAnimationFrame`) when 'Audio' defined?(`window.AudioContext`) when 'Audio (Safari)', 'Audio (Chrome)' defined?(`window.webkitAudioContext`) when 'Custom Elements' defined?(`window.customElements`) end `#@support[#{feature}] = #{support}` end # Check if the given polyfill is loaded. def self.loaded?(name) case name when 'Sizzle' defined?(`window.Sizzle`) when 'wicked-good-xpath' defined?(`window.wgxpath`) end end end