/*! Copyright (C) 2013-2015 by WebReflection Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ (function(window){ /*! (C) WebReflection Mit Style License */ if (document.createEvent) return; var DUNNOABOUTDOMLOADED = true, READYEVENTDISPATCHED = false, ONREADYSTATECHANGE = 'onreadystatechange', DOMCONTENTLOADED = 'DOMContentLoaded', SECRET = '__IE8__' + Math.random(), // Object = window.Object, defineProperty = Object.defineProperty || // just in case ... function (object, property, descriptor) { object[property] = descriptor.value; }, defineProperties = Object.defineProperties || // IE8 implemented defineProperty but not the plural... function (object, descriptors) { for(var key in descriptors) { if (hasOwnProperty.call(descriptors, key)) { try { defineProperty(object, key, descriptors[key]); } catch(o_O) { if (window.console) { console.log(key + ' failed on object:', object, o_O.message); } } } } }, getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor, hasOwnProperty = Object.prototype.hasOwnProperty, // here IE7 will break like a charm ElementPrototype = window.Element.prototype, TextPrototype = window.Text.prototype, // none of above native constructors exist/are exposed possiblyNativeEvent = /^[a-z]+$/, // ^ actually could probably be just /^[a-z]+$/ readyStateOK = /loaded|complete/, types = {}, div = document.createElement('div'), html = document.documentElement, removeAttribute = html.removeAttribute, setAttribute = html.setAttribute, valueDesc = function (value) { return { enumerable: true, writable: true, configurable: true, value: value }; } ; function commonEventLoop(currentTarget, e, $handlers, synthetic) { for(var handler, continuePropagation, handlers = $handlers.slice(), evt = enrich(e, currentTarget), i = 0, length = handlers.length; i < length; i++ ) { handler = handlers[i]; if (typeof handler === 'object') { if (typeof handler.handleEvent === 'function') { handler.handleEvent(evt); } } else { handler.call(currentTarget, evt); } if (evt.stoppedImmediatePropagation) break; } continuePropagation = !evt.stoppedPropagation; /* if (continuePropagation && !synthetic && !live(currentTarget)) { evt.cancelBubble = true; } */ return ( synthetic && continuePropagation && currentTarget.parentNode ) ? currentTarget.parentNode.dispatchEvent(evt) : !evt.defaultPrevented ; } function commonDescriptor(get, set) { return { // if you try with enumerable: true // IE8 will miserably fail configurable: true, get: get, set: set }; } function commonTextContent(protoDest, protoSource, property) { var descriptor = getOwnPropertyDescriptor( protoSource || protoDest, property ); defineProperty( protoDest, 'textContent', commonDescriptor( function () { return descriptor.get.call(this); }, function (textContent) { descriptor.set.call(this, textContent); } ) ); } function enrich(e, currentTarget) { e.currentTarget = currentTarget; e.eventPhase = ( // AT_TARGET : BUBBLING_PHASE e.target === e.currentTarget ? 2 : 3 ); return e; } function find(array, value) { var i = array.length; while(i-- && array[i] !== value); return i; } function getTextContent() { if (this.tagName === 'BR') return '\n'; var textNode = this.firstChild, arrayContent = [] ; while(textNode) { if (textNode.nodeType !== 8 && textNode.nodeType !== 7) { arrayContent.push(textNode.textContent); } textNode = textNode.nextSibling; } return arrayContent.join(''); } function live(self) { return self.nodeType !== 9 && html.contains(self); } function onkeyup(e) { var evt = document.createEvent('Event'); evt.initEvent('input', true, true); (e.srcElement || e.fromElement || document).dispatchEvent(evt); } function onReadyState(e) { if (!READYEVENTDISPATCHED && readyStateOK.test( document.readyState )) { READYEVENTDISPATCHED = !READYEVENTDISPATCHED; document.detachEvent(ONREADYSTATECHANGE, onReadyState); e = document.createEvent('Event'); e.initEvent(DOMCONTENTLOADED, true, true); document.dispatchEvent(e); } } function pageGetter(coord) { var Dir = (coord === 'X' ? 'Left' : 'Top'), clientXY = 'client' + coord, clientLR = 'client' + Dir, scrollLR = 'scroll' + Dir, secretXY = '_@' + clientXY ; return function get() { /* jshint validthis:true */ return this[secretXY] || ( this[secretXY] = ( this[clientXY] + ( html[scrollLR] || (document.body && document.body[scrollLR]) || 0 ) - html[clientLR] ) ); }; } function setTextContent(textContent) { var node; while ((node = this.lastChild)) { this.removeChild(node); } /*jshint eqnull:true */ if (textContent != null) { this.appendChild(document.createTextNode(textContent)); } } function verify(self, e) { if (!e) { e = window.event; } if (!e.target) { e.target = e.srcElement || e.fromElement || document; } if (!e.timeStamp) { e.timeStamp = (new Date()).getTime(); } return e; } // normalized textContent for: // comment, script, style, text, title commonTextContent( window.HTMLCommentElement.prototype, ElementPrototype, 'nodeValue' ); commonTextContent( window.HTMLScriptElement.prototype, null, 'text' ); commonTextContent( TextPrototype, null, 'nodeValue' ); commonTextContent( window.HTMLTitleElement.prototype, null, 'text' ); defineProperty( window.HTMLStyleElement.prototype, 'textContent', (function(descriptor){ return commonDescriptor( function () { return descriptor.get.call(this.styleSheet); }, function (textContent) { descriptor.set.call(this.styleSheet, textContent); } ); }(getOwnPropertyDescriptor(window.CSSStyleSheet.prototype, 'cssText'))) ); defineProperties( ElementPrototype, { // bonus textContent: { get: getTextContent, set: setTextContent }, // http://www.w3.org/TR/ElementTraversal/#interface-elementTraversal firstElementChild: { get: function () { for(var childNodes = this.childNodes || [], i = 0, length = childNodes.length; i < length; i++ ) { if (childNodes[i].nodeType == 1) return childNodes[i]; } } }, lastElementChild: { get: function () { for(var childNodes = this.childNodes || [], i = childNodes.length; i--; ) { if (childNodes[i].nodeType == 1) return childNodes[i]; } } }, oninput: { get: function () { return this._oninput || null; }, set: function (oninput) { if (this._oninput) { this.removeEventListener('input', this._oninput); this._oninput = oninput; if (oninput) { this.addEventListener('input', oninput); } } } }, previousElementSibling: { get: function () { var previousElementSibling = this.previousSibling; while (previousElementSibling && previousElementSibling.nodeType != 1) { previousElementSibling = previousElementSibling.previousSibling; } return previousElementSibling; } }, nextElementSibling: { get: function () { var nextElementSibling = this.nextSibling; while (nextElementSibling && nextElementSibling.nodeType != 1) { nextElementSibling = nextElementSibling.nextSibling; } return nextElementSibling; } }, childElementCount: { get: function () { for(var count = 0, childNodes = this.childNodes || [], i = childNodes.length; i--; count += childNodes[i].nodeType == 1 ); return count; } }, /* // children would be an override // IE8 already supports them but with comments too // not just nodeType 1 children: { get: function () { for(var children = [], childNodes = this.childNodes || [], i = 0, length = childNodes.length; i < length; i++ ) { if (childNodes[i].nodeType == 1) { children.push(childNodes[i]); } } return children; } }, */ // DOM Level 2 EventTarget methods and events addEventListener: valueDesc(function (type, handler, capture) { if (typeof handler !== 'function' && typeof handler !== 'object') return; var self = this, ontype = 'on' + type, temple = self[SECRET] || defineProperty( self, SECRET, {value: {}} )[SECRET], currentType = temple[ontype] || (temple[ontype] = {}), handlers = currentType.h || (currentType.h = []), e, attr ; if (!hasOwnProperty.call(currentType, 'w')) { currentType.w = function (e) { // e[SECRET] is a silent notification needed to avoid // fired events during live test return e[SECRET] || commonEventLoop(self, verify(self, e), handlers, false); }; // if not detected yet if (!hasOwnProperty.call(types, ontype)) { // and potentially a native event if(possiblyNativeEvent.test(type)) { // do this heavy thing try { // TODO: should I consider tagName too so that // INPUT[ontype] could be different ? e = document.createEventObject(); // do not clone ever a node // specially a document one ... // use the secret to ignore them all e[SECRET] = true; // document a part if a node has never been // added to any other node, fireEvent might // behave very weirdly (read: trigger unspecified errors) if (self.nodeType != 9) { /*jshint eqnull:true */ if (self.parentNode == null) { div.appendChild(self); } if ((attr = self.getAttribute(ontype))) { removeAttribute.call(self, ontype); } } self.fireEvent(ontype, e); types[ontype] = true; } catch(meh) { types[ontype] = false; while (div.hasChildNodes()) { div.removeChild(div.firstChild); } } if (attr != null) { setAttribute.call(self, ontype, attr); } } else { // no need to bother since // 'x-event' ain't native for sure types[ontype] = false; } } if ((currentType.n = types[ontype])) { self.attachEvent(ontype, currentType.w); } } if (find(handlers, handler) < 0) { handlers[capture ? 'unshift' : 'push'](handler); } if (type === 'input') { self.attachEvent('onkeyup', onkeyup); } }), dispatchEvent: valueDesc(function (e) { var self = this, ontype = 'on' + e.type, temple = self[SECRET], currentType = temple && temple[ontype], valid = !!currentType, parentNode ; if (!e.target) e.target = self; return (valid ? ( currentType.n /* && live(self) */ ? self.fireEvent(ontype, e) : commonEventLoop( self, e, currentType.h, true ) ) : ( (parentNode = self.parentNode) /* && live(self) */ ? parentNode.dispatchEvent(e) : true )), !e.defaultPrevented; }), removeEventListener: valueDesc(function (type, handler, capture) { if (typeof handler !== 'function' && typeof handler !== 'object') return; var self = this, ontype = 'on' + type, temple = self[SECRET], currentType = temple && temple[ontype], handlers = currentType && currentType.h, i = handlers ? find(handlers, handler) : -1 ; if (-1 < i) handlers.splice(i, 1); }) } ); /* this is not needed in IE8 defineProperties(window.HTMLSelectElement.prototype, { value: { get: function () { return this.options[this.selectedIndex].value; } } }); //*/ // EventTarget methods for Text nodes too defineProperties(TextPrototype, { addEventListener: valueDesc(ElementPrototype.addEventListener), dispatchEvent: valueDesc(ElementPrototype.dispatchEvent), removeEventListener: valueDesc(ElementPrototype.removeEventListener) }); defineProperties( window.XMLHttpRequest.prototype, { addEventListener: valueDesc(function (type, handler, capture) { var self = this, ontype = 'on' + type, temple = self[SECRET] || defineProperty( self, SECRET, {value: {}} )[SECRET], currentType = temple[ontype] || (temple[ontype] = {}), handlers = currentType.h || (currentType.h = []) ; if (find(handlers, handler) < 0) { if (!self[ontype]) { self[ontype] = function () { var e = document.createEvent('Event'); e.initEvent(type, true, true); self.dispatchEvent(e); }; } handlers[capture ? 'unshift' : 'push'](handler); } }), dispatchEvent: valueDesc(function (e) { var self = this, ontype = 'on' + e.type, temple = self[SECRET], currentType = temple && temple[ontype], valid = !!currentType ; return valid && ( currentType.n /* && live(self) */ ? self.fireEvent(ontype, e) : commonEventLoop( self, e, currentType.h, true ) ); }), removeEventListener: valueDesc(ElementPrototype.removeEventListener) } ); defineProperties( window.Event.prototype, { bubbles: valueDesc(true), cancelable: valueDesc(true), preventDefault: valueDesc(function () { if (this.cancelable) { this.defaultPrevented = true; this.returnValue = false; } }), stopPropagation: valueDesc(function () { this.stoppedPropagation = true; this.cancelBubble = true; }), stopImmediatePropagation: valueDesc(function () { this.stoppedImmediatePropagation = true; this.stopPropagation(); }), initEvent: valueDesc(function(type, bubbles, cancelable){ this.type = type; this.bubbles = !!bubbles; this.cancelable = !!cancelable; if (!this.bubbles) { this.stopPropagation(); } }), pageX: {get: pageGetter('X')}, pageY: {get: pageGetter('Y')} } ); defineProperties( window.HTMLDocument.prototype, { defaultView: { get: function () { return this.parentWindow; } }, textContent: { get: function () { return this.nodeType === 11 ? getTextContent.call(this) : null; }, set: function (textContent) { if (this.nodeType === 11) { setTextContent.call(this, textContent); } } }, addEventListener: valueDesc(function(type, handler, capture) { var self = this; ElementPrototype.addEventListener.call(self, type, handler, capture); // NOTE: it won't fire if already loaded, this is NOT a $.ready() shim! // this behaves just like standard browsers if ( DUNNOABOUTDOMLOADED && type === DOMCONTENTLOADED && !readyStateOK.test( self.readyState ) ) { DUNNOABOUTDOMLOADED = false; self.attachEvent(ONREADYSTATECHANGE, onReadyState); /* global top */ if (window == top) { (function gonna(e){try{ self.documentElement.doScroll('left'); onReadyState(); }catch(o_O){ setTimeout(gonna, 50); }}()); } } }), dispatchEvent: valueDesc(ElementPrototype.dispatchEvent), removeEventListener: valueDesc(ElementPrototype.removeEventListener), createEvent: valueDesc(function(Class){ var e; if (Class !== 'Event') throw new Error('unsupported ' + Class); e = document.createEventObject(); e.timeStamp = (new Date()).getTime(); return e; }) } ); defineProperties( window.Window.prototype, { getComputedStyle: valueDesc(function(){ var // partially grabbed from jQuery and Dean's hack notpixel = /^(?:[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|))(?!px)[a-z%]+$/, position = /^(top|right|bottom|left)$/, re = /\-([a-z])/g, place = function (match, $1) { return $1.toUpperCase(); } ; function ComputedStyle(_) { this._ = _; } ComputedStyle.prototype.getPropertyValue = function (name) { var el = this._, style = el.style, currentStyle = el.currentStyle, runtimeStyle = el.runtimeStyle, result, left, rtLeft ; name = (name === 'float' ? 'style-float' : name).replace(re, place); result = currentStyle ? currentStyle[name] : style[name]; if (notpixel.test(result) && !position.test(name)) { left = style.left; rtLeft = runtimeStyle && runtimeStyle.left; if (rtLeft) { runtimeStyle.left = currentStyle.left; } style.left = name === 'fontSize' ? '1em' : result; result = style.pixelLeft + 'px'; style.left = left; if (rtLeft) { runtimeStyle.left = rtLeft; } } /*jshint eqnull:true */ return result == null ? result : ((result + '') || 'auto'); }; // unsupported function PseudoComputedStyle() {} PseudoComputedStyle.prototype.getPropertyValue = function () { return null; }; return function (el, pseudo) { return pseudo ? new PseudoComputedStyle(el) : new ComputedStyle(el); }; }()), addEventListener: valueDesc(function (type, handler, capture) { var self = window, ontype = 'on' + type, handlers ; if (!self[ontype]) { self[ontype] = function(e) { return commonEventLoop(self, verify(self, e), handlers, false); }; } handlers = self[ontype][SECRET] || ( self[ontype][SECRET] = [] ); if (find(handlers, handler) < 0) { handlers[capture ? 'unshift' : 'push'](handler); } }), dispatchEvent: valueDesc(function (e) { var method = window['on' + e.type]; return method ? method.call(window, e) !== false && !e.defaultPrevented : true; }), removeEventListener: valueDesc(function (type, handler, capture) { var ontype = 'on' + type, handlers = (window[ontype] || Object)[SECRET], i = handlers ? find(handlers, handler) : -1 ; if (-1 < i) handlers.splice(i, 1); }) } ); (function (styleSheets, HTML5Element, i) { for (i = 0; i < HTML5Element.length; i++) document.createElement(HTML5Element[i]); if (!styleSheets.length) document.createStyleSheet(''); styleSheets[0].addRule(HTML5Element.join(','), 'display:block;'); }(document.styleSheets, ['header', 'nav', 'section', 'article', 'aside', 'footer'])); }(this.window || global));