match_media_js 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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