match_media_js 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,3 +1,3 @@
1
1
  module MatchMediaJs
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
@@ -0,0 +1,271 @@
1
+ // enquire.js v2.0.0 - Awesome Media Queries in JavaScript
2
+ // Copyright (c) 2013 Nick Williams - http://wicky.nillia.ms/enquire.js
3
+ // License: MIT (http://www.opensource.org/licenses/mit-license.php)
4
+
5
+ window.enquire = (function(matchMedia) {
6
+
7
+ 'use strict';
8
+ /*jshint -W098 */
9
+ /**
10
+ * Helper function for iterating over a collection
11
+ *
12
+ * @param collection
13
+ * @param fn
14
+ */
15
+ function each(collection, fn) {
16
+ var i = 0,
17
+ length = collection.length,
18
+ cont;
19
+
20
+ for(i; i < length; i++) {
21
+ cont = fn(collection[i], i);
22
+ if(cont === false) {
23
+ break; //allow early exit
24
+ }
25
+ }
26
+ }
27
+
28
+ /**
29
+ * Helper function for determining whether target object is an array
30
+ *
31
+ * @param target the object under test
32
+ * @return {Boolean} true if array, false otherwise
33
+ */
34
+ function isArray(target) {
35
+ return Object.prototype.toString.apply(target) === '[object Array]';
36
+ }
37
+
38
+ /**
39
+ * Helper function for determining whether target object is a function
40
+ *
41
+ * @param target the object under test
42
+ * @return {Boolean} true if function, false otherwise
43
+ */
44
+ function isFunction(target) {
45
+ return typeof target === 'function';
46
+ }
47
+
48
+ /**
49
+ * Delegate to handle a media query being matched and unmatched.
50
+ *
51
+ * @param {object} options
52
+ * @param {function} options.match callback for when the media query is matched
53
+ * @param {function} [options.unmatch] callback for when the media query is unmatched
54
+ * @param {function} [options.setup] one-time callback triggered the first time a query is matched
55
+ * @param {boolean} [options.deferSetup=false] should the setup callback be run immediately, rather than first time query is matched?
56
+ * @constructor
57
+ */
58
+ function QueryHandler(options) {
59
+ this.options = options;
60
+ !options.deferSetup && this.setup();
61
+ }
62
+ QueryHandler.prototype = {
63
+
64
+ /**
65
+ * coordinates setup of the handler
66
+ *
67
+ * @function
68
+ */
69
+ setup : function() {
70
+ if(this.options.setup) {
71
+ this.options.setup();
72
+ }
73
+ this.initialised = true;
74
+ },
75
+
76
+ /**
77
+ * coordinates setup and triggering of the handler
78
+ *
79
+ * @function
80
+ */
81
+ on : function() {
82
+ !this.initialised && this.setup();
83
+ this.options.match && this.options.match();
84
+ },
85
+
86
+ /**
87
+ * coordinates the unmatch event for the handler
88
+ *
89
+ * @function
90
+ */
91
+ off : function() {
92
+ this.options.unmatch && this.options.unmatch();
93
+ },
94
+
95
+ /**
96
+ * called when a handler is to be destroyed.
97
+ * delegates to the destroy or unmatch callbacks, depending on availability.
98
+ *
99
+ * @function
100
+ */
101
+ destroy : function() {
102
+ this.options.destroy ? this.options.destroy() : this.off();
103
+ },
104
+
105
+ /**
106
+ * determines equality by reference.
107
+ * if object is supplied compare options, if function, compare match callback
108
+ *
109
+ * @function
110
+ * @param {object || function} [target] the target for comparison
111
+ */
112
+ equals : function(target) {
113
+ return this.options === target || this.options.match === target;
114
+ }
115
+
116
+ };
117
+ /**
118
+ * Represents a single media query, manages it's state and registered handlers for this query
119
+ *
120
+ * @constructor
121
+ * @param {string} query the media query string
122
+ * @param {boolean} [isUnconditional=false] whether the media query should run regardless of whether the conditions are met. Primarily for helping older browsers deal with mobile-first design
123
+ */
124
+ function MediaQuery(query, isUnconditional) {
125
+ this.query = query;
126
+ this.isUnconditional = isUnconditional;
127
+ this.handlers = [];
128
+ this.mql = matchMedia(query);
129
+
130
+ var self = this;
131
+ this.listener = function(mql) {
132
+ self.mql = mql;
133
+ self.assess();
134
+ };
135
+ this.mql.addListener(this.listener);
136
+ }
137
+ MediaQuery.prototype = {
138
+
139
+ /**
140
+ * add a handler for this query, triggering if already active
141
+ *
142
+ * @function
143
+ * @param {object} handler
144
+ * @param {function} handler.match callback for when query is activated
145
+ * @param {function} [handler.unmatch] callback for when query is deactivated
146
+ * @param {function} [handler.setup] callback for immediate execution when a query handler is registered
147
+ * @param {boolean} [handler.deferSetup=false] should the setup callback be deferred until the first time the handler is matched?
148
+ */
149
+ addHandler : function(handler) {
150
+ var qh = new QueryHandler(handler);
151
+ this.handlers.push(qh);
152
+
153
+ this.mql.matches && qh.on();
154
+ },
155
+
156
+ /**
157
+ * removes the given handler from the collection, and calls it's destroy methods
158
+ *
159
+ * @function
160
+ * @param {object || function} handler the handler to remove
161
+ */
162
+ removeHandler : function(handler) {
163
+ var handlers = this.handlers;
164
+ each(handlers, function(h, i) {
165
+ if(h.equals(handler)) {
166
+ h.destroy();
167
+ return !handlers.splice(i,1); //remove from array and exit each early
168
+ }
169
+ });
170
+ },
171
+
172
+ clear : function() {
173
+ each(this.handlers, function(handler) {
174
+ handler.destroy();
175
+ });
176
+ this.mql.removeListener(this.listener);
177
+ this.handlers.length = 0; //clear array
178
+ },
179
+
180
+ /*
181
+ * assesses the query, turning on all handlers if it matches, turning them off if it doesn't match
182
+ *
183
+ * @function
184
+ */
185
+ assess : function() {
186
+ var action = (this.mql.matches || this.isUnconditional) ? 'on' : 'off';
187
+
188
+ each(this.handlers, function(handler) {
189
+ handler[action]();
190
+ });
191
+ }
192
+ };
193
+ /**
194
+ * Allows for registration of query handlers.
195
+ * Manages the query handler's state and is responsible for wiring up browser events
196
+ *
197
+ * @constructor
198
+ */
199
+ function MediaQueryDispatch () {
200
+ if(!matchMedia) {
201
+ throw new Error('matchMedia not present, legacy browsers require a polyfill');
202
+ }
203
+
204
+ this.queries = {};
205
+ this.browserIsIncapable = !matchMedia('only all').matches;
206
+ }
207
+
208
+ MediaQueryDispatch.prototype = {
209
+
210
+ /**
211
+ * Registers a handler for the given media query
212
+ *
213
+ * @function
214
+ * @param {string} q the media query
215
+ * @param {object || Array || Function} options either a single query handler object, a function, or an array of query handlers
216
+ * @param {function} options.match fired when query matched
217
+ * @param {function} [options.unmatch] fired when a query is no longer matched
218
+ * @param {function} [options.setup] fired when handler first triggered
219
+ * @param {boolean} [options.deferSetup=false] whether setup should be run immediately or deferred until query is first matched
220
+ * @param {boolean} [shouldDegrade=false] whether this particular media query should always run on incapable browsers
221
+ */
222
+ register : function(q, options, shouldDegrade) {
223
+ var queries = this.queries,
224
+ isUnconditional = shouldDegrade && this.browserIsIncapable;
225
+
226
+ if(!queries[q]) {
227
+ queries[q] = new MediaQuery(q, isUnconditional);
228
+ }
229
+
230
+ //normalise to object in an array
231
+ if(isFunction(options)) {
232
+ options = { match : options };
233
+ }
234
+ if(!isArray(options)) {
235
+ options = [options];
236
+ }
237
+ each(options, function(handler) {
238
+ queries[q].addHandler(handler);
239
+ });
240
+
241
+ return this;
242
+ },
243
+
244
+ /**
245
+ * unregisters a query and all it's handlers, or a specific handler for a query
246
+ *
247
+ * @function
248
+ * @param {string} q the media query to target
249
+ * @param {object || function} [handler] specific handler to unregister
250
+ */
251
+ unregister : function(q, handler) {
252
+ var query = this.queries[q];
253
+
254
+ if(query) {
255
+ if(handler) {
256
+ query.removeHandler(handler);
257
+ }
258
+ else {
259
+ query.clear();
260
+ delete this.queries[q];
261
+ }
262
+ }
263
+
264
+ return this;
265
+ }
266
+ };
267
+
268
+
269
+ return new MediaQueryDispatch();
270
+
271
+ }(window.matchMedia));
@@ -0,0 +1 @@
1
+ //= require respond/respond
@@ -0,0 +1,3 @@
1
+ //= require match_media
2
+ //= require respond
3
+ //= require enquire
@@ -0,0 +1,342 @@
1
+ /*! matchMedia() polyfill - Test a CSS media type/query in JS. Authors & copyright (c) 2012: Scott Jehl, Paul Irish, Nicholas Zakas. Dual MIT/BSD license */
2
+ /*! NOTE: If you're already including a window.matchMedia polyfill via Modernizr or otherwise, you don't need this part */
3
+
4
+ window.matchMedia = window.matchMedia || (function( doc, undefined ) {
5
+
6
+ "use strict";
7
+
8
+ var bool,
9
+ docElem = doc.documentElement,
10
+ refNode = docElem.firstElementChild || docElem.firstChild,
11
+ // fakeBody required for <FF4 when executed in <head>
12
+ fakeBody = doc.createElement( "body" ),
13
+ div = doc.createElement( "div" );
14
+
15
+ div.id = "mq-test-1";
16
+ div.style.cssText = "position:absolute;top:-100em";
17
+ fakeBody.style.background = "none";
18
+ fakeBody.appendChild(div);
19
+
20
+ return function(q){
21
+
22
+ div.innerHTML = "&shy;<style media=\"" + q + "\"> #mq-test-1 { width: 42px; }</style>";
23
+
24
+ docElem.insertBefore( fakeBody, refNode );
25
+ bool = div.offsetWidth === 42;
26
+ docElem.removeChild( fakeBody );
27
+
28
+ return {
29
+ matches: bool,
30
+ media: q
31
+ };
32
+
33
+ };
34
+
35
+ }( document ));
36
+
37
+
38
+
39
+
40
+
41
+ /*! Respond.js v1.1.0: min/max-width media query polyfill. (c) Scott Jehl. MIT/GPLv2 Lic. j.mp/respondjs */
42
+ (function( win ){
43
+
44
+ "use strict";
45
+
46
+ //exposed namespace
47
+ var respond = {};
48
+ win.respond = respond;
49
+
50
+ //define update even in native-mq-supporting browsers, to avoid errors
51
+ respond.update = function(){};
52
+
53
+ //expose media query support flag for external use
54
+ respond.mediaQueriesSupported = win.matchMedia && win.matchMedia( "only all" ).matches;
55
+
56
+ //if media queries are supported, exit here
57
+ if( respond.mediaQueriesSupported ){
58
+ return;
59
+ }
60
+
61
+ //define vars
62
+ var doc = win.document,
63
+ docElem = doc.documentElement,
64
+ mediastyles = [],
65
+ rules = [],
66
+ appendedEls = [],
67
+ parsedSheets = {},
68
+ resizeThrottle = 30,
69
+ head = doc.getElementsByTagName( "head" )[0] || docElem,
70
+ base = doc.getElementsByTagName( "base" )[0],
71
+ links = head.getElementsByTagName( "link" ),
72
+ requestQueue = [],
73
+
74
+ //loop stylesheets, send text content to translate
75
+ ripCSS = function(){
76
+
77
+ for( var i = 0; i < links.length; i++ ){
78
+ var sheet = links[ i ],
79
+ href = sheet.href,
80
+ media = sheet.media,
81
+ isCSS = sheet.rel && sheet.rel.toLowerCase() === "stylesheet";
82
+
83
+ //only links plz and prevent re-parsing
84
+ if( !!href && isCSS && !parsedSheets[ href ] ){
85
+ // selectivizr exposes css through the rawCssText expando
86
+ if (sheet.styleSheet && sheet.styleSheet.rawCssText) {
87
+ translate( sheet.styleSheet.rawCssText, href, media );
88
+ parsedSheets[ href ] = true;
89
+ } else {
90
+ if( (!/^([a-zA-Z:]*\/\/)/.test( href ) && !base) ||
91
+ href.replace( RegExp.$1, "" ).split( "/" )[0] === win.location.host ){
92
+ requestQueue.push( {
93
+ href: href,
94
+ media: media
95
+ } );
96
+ }
97
+ }
98
+ }
99
+ }
100
+ makeRequests();
101
+ },
102
+
103
+ //recurse through request queue, get css text
104
+ makeRequests = function(){
105
+ if( requestQueue.length ){
106
+ var thisRequest = requestQueue.shift();
107
+
108
+ ajax( thisRequest.href, function( styles ){
109
+ translate( styles, thisRequest.href, thisRequest.media );
110
+ parsedSheets[ thisRequest.href ] = true;
111
+
112
+ // by wrapping recursive function call in setTimeout
113
+ // we prevent "Stack overflow" error in IE7
114
+ win.setTimeout(function(){ makeRequests(); },0);
115
+ } );
116
+ }
117
+ },
118
+
119
+ //find media blocks in css text, convert to style blocks
120
+ translate = function( styles, href, media ){
121
+ var qs = styles.match( /@media[^\{]+\{([^\{\}]*\{[^\}\{]*\})+/gi ),
122
+ ql = qs && qs.length || 0;
123
+
124
+ //try to get CSS path
125
+ href = href.substring( 0, href.lastIndexOf( "/" ) );
126
+
127
+ var repUrls = function( css ){
128
+ return css.replace( /(url\()['"]?([^\/\)'"][^:\)'"]+)['"]?(\))/g, "$1" + href + "$2$3" );
129
+ },
130
+ useMedia = !ql && media;
131
+
132
+ //if path exists, tack on trailing slash
133
+ if( href.length ){ href += "/"; }
134
+
135
+ //if no internal queries exist, but media attr does, use that
136
+ //note: this currently lacks support for situations where a media attr is specified on a link AND
137
+ //its associated stylesheet has internal CSS media queries.
138
+ //In those cases, the media attribute will currently be ignored.
139
+ if( useMedia ){
140
+ ql = 1;
141
+ }
142
+
143
+ for( var i = 0; i < ql; i++ ){
144
+ var fullq, thisq, eachq, eql;
145
+
146
+ //media attr
147
+ if( useMedia ){
148
+ fullq = media;
149
+ rules.push( repUrls( styles ) );
150
+ }
151
+ //parse for styles
152
+ else{
153
+ fullq = qs[ i ].match( /@media *([^\{]+)\{([\S\s]+?)$/ ) && RegExp.$1;
154
+ rules.push( RegExp.$2 && repUrls( RegExp.$2 ) );
155
+ }
156
+
157
+ eachq = fullq.split( "," );
158
+ eql = eachq.length;
159
+
160
+ for( var j = 0; j < eql; j++ ){
161
+ thisq = eachq[ j ];
162
+ mediastyles.push( {
163
+ media : thisq.split( "(" )[ 0 ].match( /(only\s+)?([a-zA-Z]+)\s?/ ) && RegExp.$2 || "all",
164
+ rules : rules.length - 1,
165
+ hasquery : thisq.indexOf("(") > -1,
166
+ minw : thisq.match( /\(\s*min\-width\s*:\s*(\s*[0-9\.]+)(px|em)\s*\)/ ) && parseFloat( RegExp.$1 ) + ( RegExp.$2 || "" ),
167
+ maxw : thisq.match( /\(\s*max\-width\s*:\s*(\s*[0-9\.]+)(px|em)\s*\)/ ) && parseFloat( RegExp.$1 ) + ( RegExp.$2 || "" )
168
+ } );
169
+ }
170
+ }
171
+
172
+ applyMedia();
173
+ },
174
+
175
+ lastCall,
176
+
177
+ resizeDefer,
178
+
179
+ // returns the value of 1em in pixels
180
+ getEmValue = function() {
181
+ var ret,
182
+ div = doc.createElement('div'),
183
+ body = doc.body,
184
+ fakeUsed = false;
185
+
186
+ div.style.cssText = "position:absolute;font-size:1em;width:1em";
187
+
188
+ if( !body ){
189
+ body = fakeUsed = doc.createElement( "body" );
190
+ body.style.background = "none";
191
+ }
192
+
193
+ body.appendChild( div );
194
+
195
+ docElem.insertBefore( body, docElem.firstChild );
196
+
197
+ ret = div.offsetWidth;
198
+
199
+ if( fakeUsed ){
200
+ docElem.removeChild( body );
201
+ }
202
+ else {
203
+ body.removeChild( div );
204
+ }
205
+
206
+ //also update eminpx before returning
207
+ ret = eminpx = parseFloat(ret);
208
+
209
+ return ret;
210
+ },
211
+
212
+ //cached container for 1em value, populated the first time it's needed
213
+ eminpx,
214
+
215
+ //enable/disable styles
216
+ applyMedia = function( fromResize ){
217
+ var name = "clientWidth",
218
+ docElemProp = docElem[ name ],
219
+ currWidth = doc.compatMode === "CSS1Compat" && docElemProp || doc.body[ name ] || docElemProp,
220
+ styleBlocks = {},
221
+ lastLink = links[ links.length-1 ],
222
+ now = (new Date()).getTime();
223
+
224
+ //throttle resize calls
225
+ if( fromResize && lastCall && now - lastCall < resizeThrottle ){
226
+ win.clearTimeout( resizeDefer );
227
+ resizeDefer = win.setTimeout( applyMedia, resizeThrottle );
228
+ return;
229
+ }
230
+ else {
231
+ lastCall = now;
232
+ }
233
+
234
+ for( var i in mediastyles ){
235
+ if( mediastyles.hasOwnProperty( i ) ){
236
+ var thisstyle = mediastyles[ i ],
237
+ min = thisstyle.minw,
238
+ max = thisstyle.maxw,
239
+ minnull = min === null,
240
+ maxnull = max === null,
241
+ em = "em";
242
+
243
+ if( !!min ){
244
+ min = parseFloat( min ) * ( min.indexOf( em ) > -1 ? ( eminpx || getEmValue() ) : 1 );
245
+ }
246
+ if( !!max ){
247
+ max = parseFloat( max ) * ( max.indexOf( em ) > -1 ? ( eminpx || getEmValue() ) : 1 );
248
+ }
249
+
250
+ // if there's no media query at all (the () part), or min or max is not null, and if either is present, they're true
251
+ if( !thisstyle.hasquery || ( !minnull || !maxnull ) && ( minnull || currWidth >= min ) && ( maxnull || currWidth <= max ) ){
252
+ if( !styleBlocks[ thisstyle.media ] ){
253
+ styleBlocks[ thisstyle.media ] = [];
254
+ }
255
+ styleBlocks[ thisstyle.media ].push( rules[ thisstyle.rules ] );
256
+ }
257
+ }
258
+ }
259
+
260
+ //remove any existing respond style element(s)
261
+ for( var j in appendedEls ){
262
+ if( appendedEls.hasOwnProperty( j ) ){
263
+ if( appendedEls[ j ] && appendedEls[ j ].parentNode === head ){
264
+ head.removeChild( appendedEls[ j ] );
265
+ }
266
+ }
267
+ }
268
+
269
+ //inject active styles, grouped by media type
270
+ for( var k in styleBlocks ){
271
+ if( styleBlocks.hasOwnProperty( k ) ){
272
+ var ss = doc.createElement( "style" ),
273
+ css = styleBlocks[ k ].join( "\n" );
274
+
275
+ ss.type = "text/css";
276
+ ss.media = k;
277
+
278
+ //originally, ss was appended to a documentFragment and sheets were appended in bulk.
279
+ //this caused crashes in IE in a number of circumstances, such as when the HTML element had a bg image set, so appending beforehand seems best. Thanks to @dvelyk for the initial research on this one!
280
+ head.insertBefore( ss, lastLink.nextSibling );
281
+
282
+ if ( ss.styleSheet ){
283
+ ss.styleSheet.cssText = css;
284
+ }
285
+ else {
286
+ ss.appendChild( doc.createTextNode( css ) );
287
+ }
288
+
289
+ //push to appendedEls to track for later removal
290
+ appendedEls.push( ss );
291
+ }
292
+ }
293
+ },
294
+ //tweaked Ajax functions from Quirksmode
295
+ ajax = function( url, callback ) {
296
+ var req = xmlHttp();
297
+ if (!req){
298
+ return;
299
+ }
300
+ req.open( "GET", url, true );
301
+ req.onreadystatechange = function () {
302
+ if ( req.readyState !== 4 || req.status !== 200 && req.status !== 304 ){
303
+ return;
304
+ }
305
+ callback( req.responseText );
306
+ };
307
+ if ( req.readyState === 4 ){
308
+ return;
309
+ }
310
+ req.send( null );
311
+ },
312
+ //define ajax obj
313
+ xmlHttp = (function() {
314
+ var xmlhttpmethod = false;
315
+ try {
316
+ xmlhttpmethod = new win.XMLHttpRequest();
317
+ }
318
+ catch( e ){
319
+ xmlhttpmethod = new win.ActiveXObject( "Microsoft.XMLHTTP" );
320
+ }
321
+ return function(){
322
+ return xmlhttpmethod;
323
+ };
324
+ })();
325
+
326
+ //translate CSS
327
+ ripCSS();
328
+
329
+ //expose update for re-running respond later on
330
+ respond.update = ripCSS;
331
+
332
+ //adjust on resize
333
+ function callMedia(){
334
+ applyMedia( true );
335
+ }
336
+ if( win.addEventListener ){
337
+ win.addEventListener( "resize", callMedia, false );
338
+ }
339
+ else if( win.attachEvent ){
340
+ win.attachEvent( "onresize", callMedia );
341
+ }
342
+ })(this);
@@ -0,0 +1 @@
1
+ //= require respond/respond
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 0
8
- - 1
9
- version: 0.0.1
8
+ - 2
9
+ version: 0.0.2
10
10
  platform: ruby
11
11
  authors:
12
12
  - rheaton
@@ -42,9 +42,14 @@ extra_rdoc_files: []
42
42
  files:
43
43
  - lib/match_media_js/version.rb
44
44
  - lib/match_media_js.rb
45
+ - vendor/assets/javascripts/enquire/enquire.js
46
+ - vendor/assets/javascripts/enquire.js
45
47
  - vendor/assets/javascripts/match_media/matchMedia.addListener.js
46
48
  - vendor/assets/javascripts/match_media/matchMedia.js
47
49
  - vendor/assets/javascripts/match_media.js
50
+ - vendor/assets/javascripts/match_media_js.js
51
+ - vendor/assets/javascripts/respond/respond.js
52
+ - vendor/assets/javascripts/respond.js
48
53
  - README.md
49
54
  has_rdoc: true
50
55
  homepage: https://github.com/rheaton/match_media_js