/** * @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);