comparison js/foundation/foundation.js @ 0:7abe02bf29ec

initial commit
author Alex Krolick <whokilledtheelectricmonk@gmail.com>
date Sat, 07 Nov 2015 18:04:42 -0800
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:7abe02bf29ec
1 /*
2 * Foundation Responsive Library
3 * http://foundation.zurb.com
4 * Copyright 2015, ZURB
5 * Free to use under the MIT license.
6 * http://www.opensource.org/licenses/mit-license.php
7 */
8
9 (function ($, window, document, undefined) {
10 'use strict';
11
12 var header_helpers = function (class_array) {
13 var head = $('head');
14 head.prepend($.map(class_array, function (class_name) {
15 if (head.has('.' + class_name).length === 0) {
16 return '<meta class="' + class_name + '" />';
17 }
18 }));
19 };
20
21 header_helpers([
22 'foundation-mq-small',
23 'foundation-mq-small-only',
24 'foundation-mq-medium',
25 'foundation-mq-medium-only',
26 'foundation-mq-large',
27 'foundation-mq-large-only',
28 'foundation-mq-xlarge',
29 'foundation-mq-xlarge-only',
30 'foundation-mq-xxlarge',
31 'foundation-data-attribute-namespace']);
32
33 // Enable FastClick if present
34
35 $(function () {
36 if (typeof FastClick !== 'undefined') {
37 // Don't attach to body if undefined
38 if (typeof document.body !== 'undefined') {
39 FastClick.attach(document.body);
40 }
41 }
42 });
43
44 // private Fast Selector wrapper,
45 // returns jQuery object. Only use where
46 // getElementById is not available.
47 var S = function (selector, context) {
48 if (typeof selector === 'string') {
49 if (context) {
50 var cont;
51 if (context.jquery) {
52 cont = context[0];
53 if (!cont) {
54 return context;
55 }
56 } else {
57 cont = context;
58 }
59 return $(cont.querySelectorAll(selector));
60 }
61
62 return $(document.querySelectorAll(selector));
63 }
64
65 return $(selector, context);
66 };
67
68 // Namespace functions.
69
70 var attr_name = function (init) {
71 var arr = [];
72 if (!init) {
73 arr.push('data');
74 }
75 if (this.namespace.length > 0) {
76 arr.push(this.namespace);
77 }
78 arr.push(this.name);
79
80 return arr.join('-');
81 };
82
83 var add_namespace = function (str) {
84 var parts = str.split('-'),
85 i = parts.length,
86 arr = [];
87
88 while (i--) {
89 if (i !== 0) {
90 arr.push(parts[i]);
91 } else {
92 if (this.namespace.length > 0) {
93 arr.push(this.namespace, parts[i]);
94 } else {
95 arr.push(parts[i]);
96 }
97 }
98 }
99
100 return arr.reverse().join('-');
101 };
102
103 // Event binding and data-options updating.
104
105 var bindings = function (method, options) {
106 var self = this,
107 bind = function(){
108 var $this = S(this),
109 should_bind_events = !$this.data(self.attr_name(true) + '-init');
110 $this.data(self.attr_name(true) + '-init', $.extend({}, self.settings, (options || method), self.data_options($this)));
111
112 if (should_bind_events) {
113 self.events(this);
114 }
115 };
116
117 if (S(this.scope).is('[' + this.attr_name() +']')) {
118 bind.call(this.scope);
119 } else {
120 S('[' + this.attr_name() +']', this.scope).each(bind);
121 }
122 // # Patch to fix #5043 to move this *after* the if/else clause in order for Backbone and similar frameworks to have improved control over event binding and data-options updating.
123 if (typeof method === 'string') {
124 return this[method].call(this, options);
125 }
126
127 };
128
129 var single_image_loaded = function (image, callback) {
130 function loaded () {
131 callback(image[0]);
132 }
133
134 function bindLoad () {
135 this.one('load', loaded);
136
137 if (/MSIE (\d+\.\d+);/.test(navigator.userAgent)) {
138 var src = this.attr( 'src' ),
139 param = src.match( /\?/ ) ? '&' : '?';
140
141 param += 'random=' + (new Date()).getTime();
142 this.attr('src', src + param);
143 }
144 }
145
146 if (!image.attr('src')) {
147 loaded();
148 return;
149 }
150
151 if (image[0].complete || image[0].readyState === 4) {
152 loaded();
153 } else {
154 bindLoad.call(image);
155 }
156 };
157
158 /*! matchMedia() polyfill - Test a CSS media type/query in JS. Authors & copyright (c) 2012: Scott Jehl, Paul Irish, Nicholas Zakas, David Knight. Dual MIT/BSD license */
159
160 window.matchMedia || (window.matchMedia = function() {
161 "use strict";
162
163 // For browsers that support matchMedium api such as IE 9 and webkit
164 var styleMedia = (window.styleMedia || window.media);
165
166 // For those that don't support matchMedium
167 if (!styleMedia) {
168 var style = document.createElement('style'),
169 script = document.getElementsByTagName('script')[0],
170 info = null;
171
172 style.type = 'text/css';
173 style.id = 'matchmediajs-test';
174
175 script.parentNode.insertBefore(style, script);
176
177 // 'style.currentStyle' is used by IE <= 8 and 'window.getComputedStyle' for all other browsers
178 info = ('getComputedStyle' in window) && window.getComputedStyle(style, null) || style.currentStyle;
179
180 styleMedia = {
181 matchMedium: function(media) {
182 var text = '@media ' + media + '{ #matchmediajs-test { width: 1px; } }';
183
184 // 'style.styleSheet' is used by IE <= 8 and 'style.textContent' for all other browsers
185 if (style.styleSheet) {
186 style.styleSheet.cssText = text;
187 } else {
188 style.textContent = text;
189 }
190
191 // Test if media query is true or false
192 return info.width === '1px';
193 }
194 };
195 }
196
197 return function(media) {
198 return {
199 matches: styleMedia.matchMedium(media || 'all'),
200 media: media || 'all'
201 };
202 };
203 }());
204
205 /*
206 * jquery.requestAnimationFrame
207 * https://github.com/gnarf37/jquery-requestAnimationFrame
208 * Requires jQuery 1.8+
209 *
210 * Copyright (c) 2012 Corey Frang
211 * Licensed under the MIT license.
212 */
213
214 (function(jQuery) {
215
216
217 // requestAnimationFrame polyfill adapted from Erik Möller
218 // fixes from Paul Irish and Tino Zijdel
219 // http://paulirish.com/2011/requestanimationframe-for-smart-animating/
220 // http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating
221
222 var animating,
223 lastTime = 0,
224 vendors = ['webkit', 'moz'],
225 requestAnimationFrame = window.requestAnimationFrame,
226 cancelAnimationFrame = window.cancelAnimationFrame,
227 jqueryFxAvailable = 'undefined' !== typeof jQuery.fx;
228
229 for (; lastTime < vendors.length && !requestAnimationFrame; lastTime++) {
230 requestAnimationFrame = window[ vendors[lastTime] + 'RequestAnimationFrame' ];
231 cancelAnimationFrame = cancelAnimationFrame ||
232 window[ vendors[lastTime] + 'CancelAnimationFrame' ] ||
233 window[ vendors[lastTime] + 'CancelRequestAnimationFrame' ];
234 }
235
236 function raf() {
237 if (animating) {
238 requestAnimationFrame(raf);
239
240 if (jqueryFxAvailable) {
241 jQuery.fx.tick();
242 }
243 }
244 }
245
246 if (requestAnimationFrame) {
247 // use rAF
248 window.requestAnimationFrame = requestAnimationFrame;
249 window.cancelAnimationFrame = cancelAnimationFrame;
250
251 if (jqueryFxAvailable) {
252 jQuery.fx.timer = function (timer) {
253 if (timer() && jQuery.timers.push(timer) && !animating) {
254 animating = true;
255 raf();
256 }
257 };
258
259 jQuery.fx.stop = function () {
260 animating = false;
261 };
262 }
263 } else {
264 // polyfill
265 window.requestAnimationFrame = function (callback) {
266 var currTime = new Date().getTime(),
267 timeToCall = Math.max(0, 16 - (currTime - lastTime)),
268 id = window.setTimeout(function () {
269 callback(currTime + timeToCall);
270 }, timeToCall);
271 lastTime = currTime + timeToCall;
272 return id;
273 };
274
275 window.cancelAnimationFrame = function (id) {
276 clearTimeout(id);
277 };
278
279 }
280
281 }( $ ));
282
283 function removeQuotes (string) {
284 if (typeof string === 'string' || string instanceof String) {
285 string = string.replace(/^['\\/"]+|(;\s?})+|['\\/"]+$/g, '');
286 }
287
288 return string;
289 }
290
291 function MediaQuery(selector) {
292 this.selector = selector;
293 this.query = '';
294 }
295
296 MediaQuery.prototype.toString = function () {
297 return this.query || (this.query = S(this.selector).css('font-family').replace(/^[\/\\'"]+|(;\s?})+|[\/\\'"]+$/g, ''));
298 };
299
300 window.Foundation = {
301 name : 'Foundation',
302
303 version : '5.5.3',
304
305 media_queries : {
306 'small' : new MediaQuery('.foundation-mq-small'),
307 'small-only' : new MediaQuery('.foundation-mq-small-only'),
308 'medium' : new MediaQuery('.foundation-mq-medium'),
309 'medium-only' : new MediaQuery('.foundation-mq-medium-only'),
310 'large' : new MediaQuery('.foundation-mq-large'),
311 'large-only' : new MediaQuery('.foundation-mq-large-only'),
312 'xlarge' : new MediaQuery('.foundation-mq-xlarge'),
313 'xlarge-only' : new MediaQuery('.foundation-mq-xlarge-only'),
314 'xxlarge' : new MediaQuery('.foundation-mq-xxlarge')
315 },
316
317 stylesheet : $('<style></style>').appendTo('head')[0].sheet,
318
319 global : {
320 namespace : undefined
321 },
322
323 init : function (scope, libraries, method, options, response) {
324 var args = [scope, method, options, response],
325 responses = [];
326
327 // check RTL
328 this.rtl = /rtl/i.test(S('html').attr('dir'));
329
330 // set foundation global scope
331 this.scope = scope || this.scope;
332
333 this.set_namespace();
334
335 if (libraries && typeof libraries === 'string' && !/reflow/i.test(libraries)) {
336 if (this.libs.hasOwnProperty(libraries)) {
337 responses.push(this.init_lib(libraries, args));
338 }
339 } else {
340 for (var lib in this.libs) {
341 responses.push(this.init_lib(lib, libraries));
342 }
343 }
344
345 S(window).load(function () {
346 S(window)
347 .trigger('resize.fndtn.clearing')
348 .trigger('resize.fndtn.dropdown')
349 .trigger('resize.fndtn.equalizer')
350 .trigger('resize.fndtn.interchange')
351 .trigger('resize.fndtn.joyride')
352 .trigger('resize.fndtn.magellan')
353 .trigger('resize.fndtn.topbar')
354 .trigger('resize.fndtn.slider');
355 });
356
357 return scope;
358 },
359
360 init_lib : function (lib, args) {
361 if (this.libs.hasOwnProperty(lib)) {
362 this.patch(this.libs[lib]);
363
364 if (args && args.hasOwnProperty(lib)) {
365 if (typeof this.libs[lib].settings !== 'undefined') {
366 $.extend(true, this.libs[lib].settings, args[lib]);
367 } else if (typeof this.libs[lib].defaults !== 'undefined') {
368 $.extend(true, this.libs[lib].defaults, args[lib]);
369 }
370 return this.libs[lib].init.apply(this.libs[lib], [this.scope, args[lib]]);
371 }
372
373 args = args instanceof Array ? args : new Array(args);
374 return this.libs[lib].init.apply(this.libs[lib], args);
375 }
376
377 return function () {};
378 },
379
380 patch : function (lib) {
381 lib.scope = this.scope;
382 lib.namespace = this.global.namespace;
383 lib.rtl = this.rtl;
384 lib['data_options'] = this.utils.data_options;
385 lib['attr_name'] = attr_name;
386 lib['add_namespace'] = add_namespace;
387 lib['bindings'] = bindings;
388 lib['S'] = this.utils.S;
389 },
390
391 inherit : function (scope, methods) {
392 var methods_arr = methods.split(' '),
393 i = methods_arr.length;
394
395 while (i--) {
396 if (this.utils.hasOwnProperty(methods_arr[i])) {
397 scope[methods_arr[i]] = this.utils[methods_arr[i]];
398 }
399 }
400 },
401
402 set_namespace : function () {
403
404 // Description:
405 // Don't bother reading the namespace out of the meta tag
406 // if the namespace has been set globally in javascript
407 //
408 // Example:
409 // Foundation.global.namespace = 'my-namespace';
410 // or make it an empty string:
411 // Foundation.global.namespace = '';
412 //
413 //
414
415 // If the namespace has not been set (is undefined), try to read it out of the meta element.
416 // Otherwise use the globally defined namespace, even if it's empty ('')
417 var namespace = ( this.global.namespace === undefined ) ? $('.foundation-data-attribute-namespace').css('font-family') : this.global.namespace;
418
419 // Finally, if the namsepace is either undefined or false, set it to an empty string.
420 // Otherwise use the namespace value.
421 this.global.namespace = ( namespace === undefined || /false/i.test(namespace) ) ? '' : namespace;
422 },
423
424 libs : {},
425
426 // methods that can be inherited in libraries
427 utils : {
428
429 // Description:
430 // Fast Selector wrapper returns jQuery object. Only use where getElementById
431 // is not available.
432 //
433 // Arguments:
434 // Selector (String): CSS selector describing the element(s) to be
435 // returned as a jQuery object.
436 //
437 // Scope (String): CSS selector describing the area to be searched. Default
438 // is document.
439 //
440 // Returns:
441 // Element (jQuery Object): jQuery object containing elements matching the
442 // selector within the scope.
443 S : S,
444
445 // Description:
446 // Executes a function a max of once every n milliseconds
447 //
448 // Arguments:
449 // Func (Function): Function to be throttled.
450 //
451 // Delay (Integer): Function execution threshold in milliseconds.
452 //
453 // Returns:
454 // Lazy_function (Function): Function with throttling applied.
455 throttle : function (func, delay) {
456 var timer = null;
457
458 return function () {
459 var context = this, args = arguments;
460
461 if (timer == null) {
462 timer = setTimeout(function () {
463 func.apply(context, args);
464 timer = null;
465 }, delay);
466 }
467 };
468 },
469
470 // Description:
471 // Executes a function when it stops being invoked for n seconds
472 // Modified version of _.debounce() http://underscorejs.org
473 //
474 // Arguments:
475 // Func (Function): Function to be debounced.
476 //
477 // Delay (Integer): Function execution threshold in milliseconds.
478 //
479 // Immediate (Bool): Whether the function should be called at the beginning
480 // of the delay instead of the end. Default is false.
481 //
482 // Returns:
483 // Lazy_function (Function): Function with debouncing applied.
484 debounce : function (func, delay, immediate) {
485 var timeout, result;
486 return function () {
487 var context = this, args = arguments;
488 var later = function () {
489 timeout = null;
490 if (!immediate) {
491 result = func.apply(context, args);
492 }
493 };
494 var callNow = immediate && !timeout;
495 clearTimeout(timeout);
496 timeout = setTimeout(later, delay);
497 if (callNow) {
498 result = func.apply(context, args);
499 }
500 return result;
501 };
502 },
503
504 // Description:
505 // Parses data-options attribute
506 //
507 // Arguments:
508 // El (jQuery Object): Element to be parsed.
509 //
510 // Returns:
511 // Options (Javascript Object): Contents of the element's data-options
512 // attribute.
513 data_options : function (el, data_attr_name) {
514 data_attr_name = data_attr_name || 'options';
515 var opts = {}, ii, p, opts_arr,
516 data_options = function (el) {
517 var namespace = Foundation.global.namespace;
518
519 if (namespace.length > 0) {
520 return el.data(namespace + '-' + data_attr_name);
521 }
522
523 return el.data(data_attr_name);
524 };
525
526 var cached_options = data_options(el);
527
528 if (typeof cached_options === 'object') {
529 return cached_options;
530 }
531
532 opts_arr = (cached_options || ':').split(';');
533 ii = opts_arr.length;
534
535 function isNumber (o) {
536 return !isNaN (o - 0) && o !== null && o !== '' && o !== false && o !== true;
537 }
538
539 function trim (str) {
540 if (typeof str === 'string') {
541 return $.trim(str);
542 }
543 return str;
544 }
545
546 while (ii--) {
547 p = opts_arr[ii].split(':');
548 p = [p[0], p.slice(1).join(':')];
549
550 if (/true/i.test(p[1])) {
551 p[1] = true;
552 }
553 if (/false/i.test(p[1])) {
554 p[1] = false;
555 }
556 if (isNumber(p[1])) {
557 if (p[1].indexOf('.') === -1) {
558 p[1] = parseInt(p[1], 10);
559 } else {
560 p[1] = parseFloat(p[1]);
561 }
562 }
563
564 if (p.length === 2 && p[0].length > 0) {
565 opts[trim(p[0])] = trim(p[1]);
566 }
567 }
568
569 return opts;
570 },
571
572 // Description:
573 // Adds JS-recognizable media queries
574 //
575 // Arguments:
576 // Media (String): Key string for the media query to be stored as in
577 // Foundation.media_queries
578 //
579 // Class (String): Class name for the generated <meta> tag
580 register_media : function (media, media_class) {
581 if (Foundation.media_queries[media] === undefined) {
582 $('head').append('<meta class="' + media_class + '"/>');
583 Foundation.media_queries[media] = removeQuotes($('.' + media_class).css('font-family'));
584 }
585 },
586
587 // Description:
588 // Add custom CSS within a JS-defined media query
589 //
590 // Arguments:
591 // Rule (String): CSS rule to be appended to the document.
592 //
593 // Media (String): Optional media query string for the CSS rule to be
594 // nested under.
595 add_custom_rule : function (rule, media) {
596 if (media === undefined && Foundation.stylesheet) {
597 Foundation.stylesheet.insertRule(rule, Foundation.stylesheet.cssRules.length);
598 } else {
599 var query = Foundation.media_queries[media];
600
601 if (query !== undefined) {
602 Foundation.stylesheet.insertRule('@media ' +
603 Foundation.media_queries[media] + '{ ' + rule + ' }', Foundation.stylesheet.cssRules.length);
604 }
605 }
606 },
607
608 // Description:
609 // Performs a callback function when an image is fully loaded
610 //
611 // Arguments:
612 // Image (jQuery Object): Image(s) to check if loaded.
613 //
614 // Callback (Function): Function to execute when image is fully loaded.
615 image_loaded : function (images, callback) {
616 var self = this,
617 unloaded = images.length;
618
619 function pictures_has_height(images) {
620 var pictures_number = images.length;
621
622 for (var i = pictures_number - 1; i >= 0; i--) {
623 if(images.attr('height') === undefined) {
624 return false;
625 };
626 };
627
628 return true;
629 }
630
631 if (unloaded === 0 || pictures_has_height(images)) {
632 callback(images);
633 }
634
635 images.each(function () {
636 single_image_loaded(self.S(this), function () {
637 unloaded -= 1;
638 if (unloaded === 0) {
639 callback(images);
640 }
641 });
642 });
643 },
644
645 // Description:
646 // Returns a random, alphanumeric string
647 //
648 // Arguments:
649 // Length (Integer): Length of string to be generated. Defaults to random
650 // integer.
651 //
652 // Returns:
653 // Rand (String): Pseudo-random, alphanumeric string.
654 random_str : function () {
655 if (!this.fidx) {
656 this.fidx = 0;
657 }
658 this.prefix = this.prefix || [(this.name || 'F'), (+new Date).toString(36)].join('-');
659
660 return this.prefix + (this.fidx++).toString(36);
661 },
662
663 // Description:
664 // Helper for window.matchMedia
665 //
666 // Arguments:
667 // mq (String): Media query
668 //
669 // Returns:
670 // (Boolean): Whether the media query passes or not
671 match : function (mq) {
672 return window.matchMedia(mq).matches;
673 },
674
675 // Description:
676 // Helpers for checking Foundation default media queries with JS
677 //
678 // Returns:
679 // (Boolean): Whether the media query passes or not
680
681 is_small_up : function () {
682 return this.match(Foundation.media_queries.small);
683 },
684
685 is_medium_up : function () {
686 return this.match(Foundation.media_queries.medium);
687 },
688
689 is_large_up : function () {
690 return this.match(Foundation.media_queries.large);
691 },
692
693 is_xlarge_up : function () {
694 return this.match(Foundation.media_queries.xlarge);
695 },
696
697 is_xxlarge_up : function () {
698 return this.match(Foundation.media_queries.xxlarge);
699 },
700
701 is_small_only : function () {
702 return !this.is_medium_up() && !this.is_large_up() && !this.is_xlarge_up() && !this.is_xxlarge_up();
703 },
704
705 is_medium_only : function () {
706 return this.is_medium_up() && !this.is_large_up() && !this.is_xlarge_up() && !this.is_xxlarge_up();
707 },
708
709 is_large_only : function () {
710 return this.is_medium_up() && this.is_large_up() && !this.is_xlarge_up() && !this.is_xxlarge_up();
711 },
712
713 is_xlarge_only : function () {
714 return this.is_medium_up() && this.is_large_up() && this.is_xlarge_up() && !this.is_xxlarge_up();
715 },
716
717 is_xxlarge_only : function () {
718 return this.is_medium_up() && this.is_large_up() && this.is_xlarge_up() && this.is_xxlarge_up();
719 }
720 }
721 };
722
723 $.fn.foundation = function () {
724 var args = Array.prototype.slice.call(arguments, 0);
725
726 return this.each(function () {
727 Foundation.init.apply(Foundation, [this].concat(args));
728 return this;
729 });
730 };
731
732 }(jQuery, window, window.document));