UNPKG

ractive

Version:

Next-generation DOM manipulation

473 lines (378 loc) 12.2 kB
var win, doc, exportedShims; if ( typeof window === 'undefined' ) { exportedShims = null; } win = window; doc = win.document; exportedShims = {}; if ( !doc ) { exportedShims = null; } // Shims for older browsers if ( !Date.now ) { Date.now = function () { return +new Date(); }; } if ( !String.prototype.trim ) { String.prototype.trim = function () { return this.replace(/^\s+/, '').replace(/\s+$/, ''); }; } // Polyfill for Object.keys // https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/keys if ( !Object.keys ) { Object.keys = (function () { var hasOwnProperty = Object.prototype.hasOwnProperty, hasDontEnumBug = !({toString: null}).propertyIsEnumerable('toString'), dontEnums = [ 'toString', 'toLocaleString', 'valueOf', 'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumerable', 'constructor' ], dontEnumsLength = dontEnums.length; return function ( obj ) { if ( typeof obj !== 'object' && typeof obj !== 'function' || obj === null ) { throw new TypeError( 'Object.keys called on non-object' ); } var result = []; for ( var prop in obj ) { if ( hasOwnProperty.call( obj, prop ) ){ result.push( prop ); } } if ( hasDontEnumBug ) { for ( var i=0; i < dontEnumsLength; i++ ) { if ( hasOwnProperty.call( obj, dontEnums[i] ) ){ result.push( dontEnums[i] ); } } } return result; }; }()); } // TODO: use defineProperty to make these non-enumerable // Array extras if ( !Array.prototype.indexOf ) { Array.prototype.indexOf = function ( needle, i ) { var len; if ( i === undefined ) { i = 0; } if ( i < 0 ) { i+= this.length; } if ( i < 0 ) { i = 0; } for ( len = this.length; i<len; i++ ) { if ( this.hasOwnProperty( i ) && this[i] === needle ) { return i; } } return -1; }; } if ( !Array.prototype.forEach ) { Array.prototype.forEach = function ( callback, context ) { var i, len; for ( i=0, len=this.length; i<len; i+=1 ) { if ( this.hasOwnProperty( i ) ) { callback.call( context, this[i], i, this ); } } }; } if ( !Array.prototype.map ) { Array.prototype.map = function ( mapper, context ) { var array = this, i, len, mapped = [], isActuallyString; // incredibly, if you do something like // Array.prototype.map.call( someString, iterator ) // then `this` will become an instance of String in IE8. // And in IE8, you then can't do string[i]. Facepalm. if ( array instanceof String ) { array = array.toString(); isActuallyString = true; } for ( i=0, len=array.length; i<len; i+=1 ) { if ( array.hasOwnProperty( i ) || isActuallyString ) { mapped[i] = mapper.call( context, array[i], i, array ); } } return mapped; }; } if ( typeof Array.prototype.reduce !== 'function' ) { Array.prototype.reduce = function(callback, opt_initialValue){ var i, value, len, valueIsSet; if ('function' !== typeof callback) { throw new TypeError(callback + ' is not a function'); } len = this.length; valueIsSet = false; if ( arguments.length > 1 ) { value = opt_initialValue; valueIsSet = true; } for ( i = 0; i < len; i += 1) { if ( this.hasOwnProperty( i ) ) { if ( valueIsSet ) { value = callback(value, this[i], i, this); } } else { value = this[i]; valueIsSet = true; } } if ( !valueIsSet ) { throw new TypeError( 'Reduce of empty array with no initial value' ); } return value; }; } if ( !Array.prototype.filter ) { Array.prototype.filter = function ( filter, context ) { var i, len, filtered = []; for ( i=0, len=this.length; i<len; i+=1 ) { if ( this.hasOwnProperty( i ) && filter.call( context, this[i], i, this ) ) { filtered[ filtered.length ] = this[i]; } } return filtered; }; } if ( !Array.prototype.every ) { Array.prototype.every = function ( iterator, context ) { var t, len, i; if ( this == null ) { throw new TypeError(); } t = Object( this ); len = t.length >>> 0; if ( typeof iterator !== 'function' ) { throw new TypeError(); } for ( i = 0; i < len; i += 1 ) { if ( i in t && !iterator.call( context, t[i], i, t) ) { return false; } } return true; }; } /* // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find if (!Array.prototype.find) { Array.prototype.find = function(predicate) { if (this == null) { throw new TypeError('Array.prototype.find called on null or undefined'); } if (typeof predicate !== 'function') { throw new TypeError('predicate must be a function'); } var list = Object(this); var length = list.length >>> 0; var thisArg = arguments[1]; var value; for (var i = 0; i < length; i++) { if (i in list) { value = list[i]; if (predicate.call(thisArg, value, i, list)) { return value; } } } return undefined; } } */ if ( typeof Function.prototype.bind !== 'function' ) { Function.prototype.bind = function ( context ) { var args, fn, Empty, bound, slice = [].slice; if ( typeof this !== 'function' ) { throw new TypeError( 'Function.prototype.bind called on non-function' ); } args = slice.call( arguments, 1 ); fn = this; Empty = function () {}; bound = function () { var ctx = this instanceof Empty && context ? this : context; return fn.apply( ctx, args.concat( slice.call( arguments ) ) ); }; Empty.prototype = this.prototype; bound.prototype = new Empty(); return bound; }; } // https://gist.github.com/Rich-Harris/6010282 via https://gist.github.com/jonathantneal/2869388 // addEventListener polyfill IE6+ if ( !win.addEventListener ) { ((function(win, doc) { var Event, addEventListener, removeEventListener, head, style, origCreateElement; Event = function ( e, element ) { var property, instance = this; for ( property in e ) { instance[ property ] = e[ property ]; } instance.currentTarget = element; instance.target = e.srcElement || element; instance.timeStamp = +new Date(); instance.preventDefault = function () { e.returnValue = false; }; instance.stopPropagation = function () { e.cancelBubble = true; }; }; addEventListener = function ( type, listener ) { var element = this, listeners, i; listeners = element.listeners || ( element.listeners = [] ); i = listeners.length; listeners[i] = [ listener, function (e) { listener.call( element, new Event( e, element ) ); }]; element.attachEvent( 'on' + type, listeners[i][1] ); }; removeEventListener = function ( type, listener ) { var element = this, listeners, i; if ( !element.listeners ) { return; } listeners = element.listeners; i = listeners.length; while ( i-- ) { if (listeners[i][0] === listener) { element.detachEvent( 'on' + type, listeners[i][1] ); } } }; win.addEventListener = doc.addEventListener = addEventListener; win.removeEventListener = doc.removeEventListener = removeEventListener; if ( 'Element' in win ) { win.Element.prototype.addEventListener = addEventListener; win.Element.prototype.removeEventListener = removeEventListener; } else { // First, intercept any calls to document.createElement - this is necessary // because the CSS hack (see below) doesn't come into play until after a // node is added to the DOM, which is too late for a lot of Ractive setup work origCreateElement = doc.createElement; doc.createElement = function ( tagName ) { var el = origCreateElement( tagName ); el.addEventListener = addEventListener; el.removeEventListener = removeEventListener; return el; }; // Then, mop up any additional elements that weren't created via // document.createElement (i.e. with innerHTML). head = doc.getElementsByTagName('head')[0]; style = doc.createElement('style'); head.insertBefore( style, head.firstChild ); //style.styleSheet.cssText = '*{-ms-event-prototype:expression(!this.addEventListener&&(this.addEventListener=addEventListener)&&(this.removeEventListener=removeEventListener))}'; } })( win, doc )); } // The getComputedStyle polyfill interacts badly with jQuery, so we don't attach // it to window. Instead, we export it for other modules to use as needed // https://github.com/jonathantneal/Polyfills-for-IE8/blob/master/getComputedStyle.js if ( !win.getComputedStyle ) { exportedShims.getComputedStyle = (function () { var borderSizes = {}; function getPixelSize(element, style, property, fontSize) { var sizeWithSuffix = style[property], size = parseFloat(sizeWithSuffix), suffix = sizeWithSuffix.split(/\d/)[0], rootSize; if ( isNaN( size ) ) { if ( /^thin|medium|thick$/.test( sizeWithSuffix ) ) { size = getBorderPixelSize( sizeWithSuffix ); suffix = ''; } else { // TODO... } } fontSize = fontSize != null ? fontSize : /%|em/.test(suffix) && element.parentElement ? getPixelSize(element.parentElement, element.parentElement.currentStyle, 'fontSize', null) : 16; rootSize = property == 'fontSize' ? fontSize : /width/i.test(property) ? element.clientWidth : element.clientHeight; return (suffix == 'em') ? size * fontSize : (suffix == 'in') ? size * 96 : (suffix == 'pt') ? size * 96 / 72 : (suffix == '%') ? size / 100 * rootSize : size; } function getBorderPixelSize ( size ) { var div, bcr; // `thin`, `medium` and `thick` vary between browsers. (Don't ever use them.) if ( !borderSizes[ size ] ) { div = document.createElement( 'div' ); div.style.display = 'block'; div.style.position = 'fixed'; div.style.width = div.style.height = '0'; div.style.borderRight = size + ' solid black'; document.getElementsByTagName( 'body' )[0].appendChild( div ); bcr = div.getBoundingClientRect(); borderSizes[ size ] = bcr.right - bcr.left; } return borderSizes[ size ]; } function setShortStyleProperty(style, property) { var borderSuffix = property == 'border' ? 'Width' : '', t = property + 'Top' + borderSuffix, r = property + 'Right' + borderSuffix, b = property + 'Bottom' + borderSuffix, l = property + 'Left' + borderSuffix; style[property] = (style[t] == style[r] == style[b] == style[l] ? [style[t]] : style[t] == style[b] && style[l] == style[r] ? [style[t], style[r]] : style[l] == style[r] ? [style[t], style[r], style[b]] : [style[t], style[r], style[b], style[l]]).join(' '); } function CSSStyleDeclaration(element) { var currentStyle, style, fontSize, property; currentStyle = element.currentStyle; style = this; fontSize = getPixelSize(element, currentStyle, 'fontSize', null); // TODO tidy this up, test it, send PR to jonathantneal! for (property in currentStyle) { if ( /width|height|margin.|padding.|border.+W/.test(property) ) { if ( currentStyle[ property ] === 'auto' ) { if ( /^width|height/.test( property ) ) { // just use clientWidth/clientHeight... style[ property ] = ( property === 'width' ? element.clientWidth : element.clientHeight ) + 'px'; } else if ( /(?:padding)?Top|Bottom$/.test( property ) ) { style[ property ] = '0px'; } } else { style[ property ] = getPixelSize(element, currentStyle, property, fontSize) + 'px'; } } else if (property === 'styleFloat') { style.float = currentStyle[property]; } else { style[property] = currentStyle[property]; } } setShortStyleProperty(style, 'margin'); setShortStyleProperty(style, 'padding'); setShortStyleProperty(style, 'border'); style.fontSize = fontSize + 'px'; return style; } CSSStyleDeclaration.prototype = { constructor: CSSStyleDeclaration, getPropertyPriority: function () {}, getPropertyValue: function ( prop ) { return this[prop] || ''; }, item: function () {}, removeProperty: function () {}, setProperty: function () {}, getPropertyCSSValue: function () {} }; function getComputedStyle(element) { return new CSSStyleDeclaration(element); } return getComputedStyle; }()); } export default exportedShims;