diff --git a/.gitignore b/.gitignore index 5c904f3..6e229ee 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ node_modules .vendor .bundle .sass-cache +coverage/ diff --git a/Gulpfile.js b/Gulpfile.js index 727d81d..18dad09 100644 --- a/Gulpfile.js +++ b/Gulpfile.js @@ -17,8 +17,7 @@ require('./tasks/karma')(gulp); // Dist Tasks ////////////////////////////// require('./tasks/dist')(gulp, [ - 'build/**/*.js', - '!build/**/*.min.js' + 'build/**/eq.js' ]); ////////////////////////////// diff --git a/README.md b/README.md index b1093a3..108f950 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,9 @@ # eq.js [![Build Status](https://travis-ci.org/Snugug/eq.js.svg)](https://travis-ci.org/Snugug/eq.js) [![Coverage Status](https://img.shields.io/coveralls/Snugug/eq.js.svg)](https://coveralls.io/r/Snugug/eq.js?branch=1.x.x) [![Code Climate](https://codeclimate.com/github/Snugug/eq.js/badges/gpa.svg)](https://codeclimate.com/github/Snugug/eq.js) [![Bower version](https://badge.fury.io/bo/eq.js.svg)](http://badge.fury.io/bo/eq.js) ### Element queries, fast and light -## WARNING: 1.5.0 does not work with IE8; I totally forgot about it while writing the CSS feature. When I have resolved the issue, I will pull 1.5.0 and push 1.6.0 - Element queries are the "holy grail" of responsive web design, allowing you to create a single component that can be dropped into any position in any layout and have them respond appropriately. Unfortunately, due to some hard-to-deal-with chicken-and-egg cases, especially involving inline elements, it's unlikely that element queries will make it into browsers any time soon. -**eq.js** aims to be a relatively easy to use drop-in solution to JavaScript powered element queries. Weighing in at about 3.3KB minified, around 1.3KB gzipped, and requiring no external dependencies, **eq.js** sets itself apart through size, speed, and ease of use. Simply drop **eq.js** on to your site and set the `eq-pts` attribute of your element (or set your points in Sass) and you're ready to go! +**eq.js** aims to be a relatively easy to use drop-in solution to JavaScript powered element queries. Weighing in at about 2.5KB minified, around 1.1KB gzipped, and requiring no external dependencies, **eq.js** sets itself apart through size, speed, and ease of use. Simply drop **eq.js** on to your site and set the `eq-pts` attribute of your element (or set your points in Sass) and you're ready to go! ## Installation @@ -151,7 +149,7 @@ add_import_path "bower_components/eq.js/sass" **eq.js** uses [`document.querySelectorAll()`](http://caniuse.com/queryselector) and provides polyfills for [`requestAnimationFrame()`](http://caniuse.com/requestanimationframe) and [`Object.getPrototypeOf`](http://stackoverflow.com/a/15851520/703084). It has been tested in the following browsers: -* IE9+ (IE8+ with [domready](https://github.com/ded/domready) available for `DOMContentLoaded` support) +* IE8+ (see below for notes) * Firefox 3.5+ * Chrome * Safari @@ -165,7 +163,17 @@ add_import_path "bower_components/eq.js/sass" * Firefox for Android * IE Mobile -**Caveats**: On the current test site in IE8, the correct attributes get applied and the correct CSS gets applied (check in the developer tools, be sure to refresh the HTML after you've loaded the page or it'll appear as if they haven't!), but the correct paint doesn't get applied. I'm not entirely sure this is why, I guess this is due to the number of nodes, but really I've got no idea why it doesn't repaint properly. +### A note on IE8/Older Browser Support + +There are two files provided; `eq.min.js` and `eq.polyfilled.min.js`. The later includes the polyfills needed to run **eq.js** in older browsers that are missing some newer JavaScript niceties (yes, this includes IE8+). While this allows for a drop-in solution using just what's provided here, a better solution (and where a bunch of the polyfills come from), consider using something like a [polyfill service](https://github.com/Financial-Times/polyfill-service) for a more robust and well-rounded solution. + +The specific polyfills included are as follows: + +* [`Object.getPrototypeOf`](http://kangax.github.io/compat-table/es5/#Object.getPrototypeOf) +* [`window.requestAnimationFrame`](http://caniuse.com/#feat=requestanimationframe) +* [`Event.DOMContentLoaded`](http://caniuse.com/#feat=domcontentloaded) +* [`window.getComputedStyle`](http://caniuse.com/#feat=getcomputedstyle) +* [`Array.prototype.forEach`](http://kangax.github.io/compat-table/es5/#Array.prototype.forEach) ## Technical Mumbo Jumbo diff --git a/bower.json b/bower.json index f4d9afc..7dd40e6 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "eq.js", - "version": "1.5.0", + "version": "1.6.0", "authors": [ "Sam Richard " ], @@ -27,8 +27,5 @@ "index.html", "package.json", "sass/style.scss" - ], - "dependencies": { - "domready": "*" - } + ] } diff --git a/build/eq.js b/build/eq.js index 2c0d9f4..714eb50 100644 --- a/build/eq.js +++ b/build/eq.js @@ -9,7 +9,7 @@ * eqjs.query - Runs through all nodes and finds their widths and points * eqjs.nodeWrites - Runs through all nodes and writes their eq status */ -(function (eqjs, domready) { +(function (eqjs) { 'use strict'; function EQjs() { @@ -20,55 +20,6 @@ this.callback = undefined; } - /** @{polyfills} **/ - /* - * Object.getPrototypeOf Polyfill - * From http://stackoverflow.com/a/15851520/703084 - */ - if (typeof Object.getPrototypeOf !== 'function') { - Object.getPrototypeOf = ''.__proto__ === String.prototype ? function (object) { - return object.__proto__; - } - : function (object) { - // May break if the constructor has been tampered with - return object.constructor.prototype; - }; - } - - /* - * Request Animation Frame Polyfill - * - * Written by Erik Möller and Paul Irish - * From http://www.paulirish.com/2011/requestanimationframe-for-smart-animating/ - */ - var lastTime = 0; - var vendors = ['webkit', 'moz']; - for (var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) { - window.requestAnimationFrame = window[vendors[x] + 'RequestAnimationFrame']; - window.cancelAnimationFrame = window[vendors[x] + 'CancelAnimationFrame'] || window[vendors[x] + 'CancelRequestAnimationFrame']; - } - - if (!window.requestAnimationFrame) { - window.requestAnimationFrame = function (callback, element) { - element = element; - var currTime = new Date().getTime(); - var timeToCall = Math.max(0, 16 - (currTime - lastTime)); - var id = window.setTimeout(function () { - callback(currTime + timeToCall); - }, timeToCall); - lastTime = currTime + timeToCall; - return id; - }; - } - - if (!window.cancelAnimationFrame) { - window.cancelAnimationFrame = function (id) { - clearTimeout(id); - }; - } - - /** {polyfills}@ **/ - /* * Add event (cross browser) * From http://stackoverflow.com/a/10150042 @@ -284,18 +235,10 @@ * * Fires on document load; for HTML based EQs */ - if (domready) { - domready(function () { - eqjs.refreshNodes(); - eqjs.query(undefined, true); - }); - } - else { - addEvent(window, 'DOMContentLoaded', function () { - eqjs.refreshNodes(); - eqjs.query(undefined, true); - }); - } + addEvent(window, 'DOMContentLoaded', function () { + eqjs.refreshNodes(); + eqjs.query(undefined, true); + }); /* * Window Loaded @@ -325,4 +268,4 @@ } else { window.eqjs = eqjs; } -})(window.eqjs, window.domready); +})(window.eqjs); diff --git a/build/polyfills.js b/build/polyfills.js new file mode 100644 index 0000000..384ae77 --- /dev/null +++ b/build/polyfills.js @@ -0,0 +1,224 @@ +/** + * Polyfills for eq.js +**/ +(function () { + /* + * Object.getPrototypeOf Polyfill + * From http://stackoverflow.com/a/15851520/703084 + */ + if (typeof Object.getPrototypeOf !== 'function') { + Object.getPrototypeOf = ''.__proto__ === String.prototype ? function (object) { + return object.__proto__; + } + : function (object) { + // May break if the constructor has been tampered with + return object.constructor.prototype; + }; + } + + /* + * Request Animation Frame Polyfill + * + * Written by Erik Möller and Paul Irish + * From http://www.paulirish.com/2011/requestanimationframe-for-smart-animating/ + */ + var lastTime = 0; + var vendors = ['webkit', 'moz']; + for (var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) { + window.requestAnimationFrame = window[vendors[x] + 'RequestAnimationFrame']; + window.cancelAnimationFrame = window[vendors[x] + 'CancelAnimationFrame'] || window[vendors[x] + 'CancelRequestAnimationFrame']; + } + + if (!window.requestAnimationFrame) { + window.requestAnimationFrame = function (callback, element) { + element = element; + var currTime = new Date().getTime(); + var timeToCall = Math.max(0, 16 - (currTime - lastTime)); + var id = window.setTimeout(function () { + callback(currTime + timeToCall); + }, timeToCall); + lastTime = currTime + timeToCall; + return id; + }; + } + + if (!window.cancelAnimationFrame) { + window.cancelAnimationFrame = function (id) { + clearTimeout(id); + }; + } + + /** + * DOMContentLoaded Polyfill + * + * Adapted from the Financial Times polyfill service + * https://github.com/Financial-Times/polyfill-service/blob/master/polyfills/Event.DOMContentLoaded/polyfill.js + **/ + if (!('addEventListener' in window)) { + document.attachEvent('onreadystatechange', function() { + if (document.readyState === 'complete') { + document.dispatchEvent(new Event('DOMContentLoaded', { + bubbles: true + })); + } + }); + } + + /** + * getComputedStyle Polyfill + * + * Adapted from the Financial Times polyfill service + * https://github.com/Financial-Times/polyfill-service/blob/master/polyfills/getComputedStyle/polyfill.js + **/ + if (!('getComputedStyle' in window)) { + (function (global) { + function getComputedStylePixel(element, property, fontSize) { + var + // Internet Explorer sometimes struggles to read currentStyle until the element's document is accessed. + value = element.document && element.currentStyle[property].match(/([\d\.]+)(%|cm|em|in|mm|pc|pt|)/) || [0, 0, ''], + size = value[1], + suffix = value[2], + rootSize; + + fontSize = !fontSize ? fontSize : /%|em/.test(suffix) && element.parentElement ? getComputedStylePixel(element.parentElement, 'fontSize', null) : 16; + rootSize = property == 'fontSize' ? fontSize : /width/i.test(property) ? element.clientWidth : element.clientHeight; + + return suffix == '%' ? size / 100 * rootSize : + suffix == 'cm' ? size * 0.3937 * 96 : + suffix == 'em' ? size * fontSize : + suffix == 'in' ? size * 96 : + suffix == 'mm' ? size * 0.3937 * 96 / 10 : + suffix == 'pc' ? size * 12 * 96 / 72 : + suffix == 'pt' ? size * 96 / 72 : + 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[t] == style[b] && style[t] == 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 + style = this, + currentStyle = element.currentStyle, + fontSize = getComputedStylePixel(element, 'fontSize'), + unCamelCase = function (match) { + return '-' + match.toLowerCase(); + }, + property; + + for (property in currentStyle) { + Array.prototype.push.call(style, property == 'styleFloat' ? 'float' : property.replace(/[A-Z]/, unCamelCase)); + + if (property == 'width') { + style[property] = element.offsetWidth + 'px'; + } else if (property == 'height') { + style[property] = element.offsetHeight + 'px'; + } else if (property == 'styleFloat') { + style.float = currentStyle[property]; + } else if (/margin.|padding.|border.+W/.test(property) && style[property] != 'auto') { + style[property] = Math.round(getComputedStylePixel(element, property, fontSize)) + 'px'; + } else if (/^outline/.test(property)) { + // errors on checking outline + try { + style[property] = currentStyle[property]; + } catch (error) { + style.outlineColor = currentStyle.color; + style.outlineStyle = style.outlineStyle || 'none'; + style.outlineWidth = style.outlineWidth || '0px'; + style.outline = [style.outlineColor, style.outlineWidth, style.outlineStyle].join(' '); + } + } else { + style[property] = currentStyle[property]; + } + } + + setShortStyleProperty(style, 'margin'); + setShortStyleProperty(style, 'padding'); + setShortStyleProperty(style, 'border'); + + style.fontSize = Math.round(fontSize) + 'px'; + } + + CSSStyleDeclaration.prototype = { + constructor: CSSStyleDeclaration, + // .getPropertyPriority + getPropertyPriority: function () { + throw new Error('NotSupportedError: DOM Exception 9'); + }, + // .getPropertyValue + getPropertyValue: function (property) { + return this[property.replace(/-\w/g, function (match) { + return match[1].toUpperCase(); + })]; + }, + // .item + item: function (index) { + return this[index]; + }, + // .removeProperty + removeProperty: function () { + throw new Error('NoModificationAllowedError: DOM Exception 7'); + }, + // .setProperty + setProperty: function () { + throw new Error('NoModificationAllowedError: DOM Exception 7'); + }, + // .getPropertyCSSValue + getPropertyCSSValue: function () { + throw new Error('NotSupportedError: DOM Exception 9'); + } + }; + + // .getComputedStyle + global.getComputedStyle = function getComputedStyle(element) { + return new CSSStyleDeclaration(element); + }; + })(this); + } + + /** + * Array.prototype.forEach Polyfill + * + * Adapted from the Financial Times polyfill service + * https://github.com/Financial-Times/polyfill-service/blob/master/polyfills/Array.prototype.forEach/polyfill.js + **/ + + if (!Array.prototype.forEach) { + Array.prototype.forEach = function forEach(callback) { + if (this === undefined || this === null) { + throw new TypeError(this + 'is not an object'); + } + + if (!(callback instanceof Function)) { + throw new TypeError(callback + ' is not a function'); + } + + var + object = Object(this), + scope = arguments[1], + arraylike = object instanceof String ? object.split('') : object, + length = Math.max(Math.min(arraylike.length, 9007199254740991), 0) || 0, + index = -1, + result = [], + element; + + while (++index < length) { + if (index in arraylike) { + callback.call(scope, arraylike[index], index, object); + } + } + }; + } +}()); diff --git a/dist/eq.gz.js b/dist/eq.gz.js deleted file mode 100644 index 1892605..0000000 Binary files a/dist/eq.gz.js and /dev/null differ diff --git a/dist/eq.min.js b/dist/eq.min.js index 85fd7ac..4670d47 100644 --- a/dist/eq.min.js +++ b/dist/eq.min.js @@ -1,3 +1,3 @@ -/*! eq.js v1.5.0 (c) 2013-2014 Sam Richard, MIT license */ -!function(e,t){"use strict";function n(){this.nodes=[],this.eqsLength=0,this.widths=[],this.points=[],this.callback=void 0}function o(e,t,n){e.addEventListener?e.addEventListener(t,n,!1):e.attachEvent("on"+t,function(){return n.call(e,window.event)})}function r(e){return window.getComputedStyle(e,":before").getPropertyValue("content").slice(1,-1)}"function"!=typeof Object.getPrototypeOf&&(Object.getPrototypeOf="".__proto__===String.prototype?function(e){return e.__proto__}:function(e){return e.constructor.prototype});for(var i=0,a=["webkit","moz"],u=0;ua;a++){u.push(t[a].offsetWidth);try{s.push(i.sortObj(t[a].getAttribute("data-eq-pts")))}catch(d){try{s.push(i.sortObj(r(t[a])))}catch(c){s.push([{key:"",value:0}])}}}i.widths=u,i.points=s,t&&"number"!=typeof t?i.nodeWrites(t,u,s):n&&"function"!=typeof n?i.nodeWrites():window.requestAnimationFrame(i.nodeWrites)},n.prototype.nodeWrites=function(t){var n,o,r,i=Object.getPrototypeOf(e),a=i.widths,u=i.points;for(t&&"number"!=typeof t?o=t.length:(t=i.nodes,o=i.nodesLength),n=0;o>n;n++){var s=a[n],d=t[n],c=u[n],f=c.length;if(s=c[f-1].value)d.setAttribute("data-eq-state",c[f-1].key);else for(var l=0;f>l;l++){var w=c[l],p=c[l+1];if(0===l&&s=w.value&&ss;s++){a.push(t[s].offsetWidth);try{u.push(i.sortObj(t[s].getAttribute("data-eq-pts")))}catch(d){try{u.push(i.sortObj(n(t[s])))}catch(c){u.push([{key:"",value:0}])}}}i.widths=a,i.points=u,t&&"number"!=typeof t?i.nodeWrites(t,a,u):o&&"function"!=typeof o?i.nodeWrites():window.requestAnimationFrame(i.nodeWrites)},t.prototype.nodeWrites=function(t){var o,n,r,i=Object.getPrototypeOf(e),s=i.widths,a=i.points;for(t&&"number"!=typeof t?n=t.length:(t=i.nodes,n=i.nodesLength),o=0;n>o;o++){var u=s[o],d=t[o],c=a[o],l=c.length;if(u=c[l-1].value)d.setAttribute("data-eq-state",c[l-1].key);else for(var f=0;l>f;f++){var p=c[f],h=c[f+1];if(0===f&&u=p.value&&ua;a++){u.push(e[a].offsetWidth);try{c.push(i.sortObj(e[a].getAttribute("data-eq-pts")))}catch(s){try{c.push(i.sortObj(n(e[a])))}catch(l){c.push([{key:"",value:0}])}}}i.widths=u,i.points=c,e&&"number"!=typeof e?i.nodeWrites(e,u,c):o&&"function"!=typeof o?i.nodeWrites():window.requestAnimationFrame(i.nodeWrites)},e.prototype.nodeWrites=function(e){var o,n,r,i=Object.getPrototypeOf(t),a=i.widths,u=i.points;for(e&&"number"!=typeof e?n=e.length:(e=i.nodes,n=i.nodesLength),o=0;n>o;o++){var c=a[o],s=e[o],l=u[o],d=l.length;if(c=l[d-1].value)s.setAttribute("data-eq-state",l[d-1].key);else for(var f=0;d>f;f++){var p=l[f],h=l[f+1];if(0===f&&c=p.value&&c