/** * @file * @copyright 2013 Andrea Giammarchi, WebReflection * @license MIT */ /* eslint-disable */ (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 getter(attr) { return function() { return html[attr] || (document.body && document.body[attr]) || 0; }; } 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'))) ); var opacityre = /\b\s*alpha\s*\(\s*opacity\s*=\s*(\d+)\s*\)/; defineProperty( window.CSSStyleDeclaration.prototype, 'opacity', { get: function() { var m = this.filter.match(opacityre); return m ? (m[1] / 100).toString() : ''; }, set: function(value) { this.zoom = 1; var found = false; if (value < 1) { value = ' alpha(opacity=' + Math.round(value * 100) + ')'; } else { value = ''; } this.filter = this.filter.replace(opacityre, function() { found = true; return value; }); if (!found && value) { this.filter += value; } } } ); 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) } ); var buttonGetter = getOwnPropertyDescriptor(Event.prototype, 'button').get; defineProperties( window.Event.prototype, { bubbles: valueDesc(true), cancelable: valueDesc(true), preventDefault: valueDesc(function () { if (this.cancelable) { 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: function(){ return this._pageX || (this._pageX = this.clientX + window.scrollX - (html.clientLeft || 0)); }}, pageY: {get: function(){ return this._pageY || (this._pageY = this.clientY + window.scrollY - (html.clientTop || 0)); }}, which: {get: function(){ return this.keyCode ? this.keyCode : (isNaN(this.button) ? undefined : this.button + 1); }}, charCode: {get: function(){ return (this.keyCode && this.type == 'keypress') ? this.keyCode : 0; }}, buttons: {get: function(){ return buttonGetter.call(this); }}, button: {get: function() { var buttons = this.buttons; return (buttons & 1 ? 0 : (buttons & 2 ? 2 : (buttons & 4 ? 1 : undefined))); }}, defaultPrevented: {get: function() { // if preventDefault() was never called, or returnValue not given a value // then returnValue is undefined var returnValue = this.returnValue, undef; return !(returnValue === undef || returnValue); }}, relatedTarget: {get: function() { var type = this.type; if (type === 'mouseover') { return this.fromElement; } else if (type === 'mouseout') { return this.toElement; } else { return null; } }} } ); 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 ; if (name == 'opacity') { return style.opacity || '1'; } 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) && undefined; }; } 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); }), pageXOffset: {get: getter('scrollLeft')}, pageYOffset: {get: getter('scrollTop')}, scrollX: {get: getter('scrollLeft')}, scrollY: {get: getter('scrollTop')}, innerWidth: {get: getter('clientWidth')}, innerHeight: {get: getter('clientHeight')} } ); window.HTMLElement = window.Element; (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'])); (function () { if (document.createRange) return; document.createRange = function createRange() { return new Range(); }; function getContents(start, end) { var nodes = [start]; while (start !== end) { nodes.push(start = start.nextSibling); } return nodes; } function Range() {} var proto = Range.prototype; proto.cloneContents = function cloneContents() { for (var fragment = this._start.ownerDocument.createDocumentFragment(), nodes = getContents(this._start, this._end), i = 0, length = nodes.length; i < length; i++ ) { fragment.appendChild(nodes[i].cloneNode(true)); } return fragment; }; proto.cloneRange = function cloneRange() { var range = new Range(); range._start = this._start; range._end = this._end; return range; }; proto.deleteContents = function deleteContents() { for (var parentNode = this._start.parentNode, nodes = getContents(this._start, this._end), i = 0, length = nodes.length; i < length; i++ ) { parentNode.removeChild(nodes[i]); } }; proto.extractContents = function extractContents() { for (var fragment = this._start.ownerDocument.createDocumentFragment(), nodes = getContents(this._start, this._end), i = 0, length = nodes.length; i < length; i++ ) { fragment.appendChild(nodes[i]); } return fragment; }; proto.setEndAfter = function setEndAfter(node) { this._end = node; }; proto.setEndBefore = function setEndBefore(node) { this._end = node.previousSibling; }; proto.setStartAfter = function setStartAfter(node) { this._start = node.nextSibling; }; proto.setStartBefore = function setStartBefore(node) { this._start = node; }; }()); }(window));