jquery-masonry-rails 3.1.5 → 4.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8dde661a3d0f5ddc211f2c16b56b26be6818f99f
4
- data.tar.gz: 3d49bbc0b15735a1d18ea306860d5d81eaee2dee
3
+ metadata.gz: d2a0713658b2a7982b8d13e0aeef987fcacb750f
4
+ data.tar.gz: 2bdf7d511e43a73a61edf60ef58be066d2caa26d
5
5
  SHA512:
6
- metadata.gz: 393615f0b163b680dc93c9b539916522944c03f4cfeb5388862c9833ef4475c06de2566c0c4e73e9ea6d4206d2c7b78ab2493450f315518009de14a1b4ef24c8
7
- data.tar.gz: afa709e12c8f40439e8d8ee49306f030db48f3ca42fb6b8bba79d22b73a503583ea8b488bd5bfc235cd599c7108e6ed844f45c3444c60f6c0685aa158c338388
6
+ metadata.gz: 41e141d4356c6486a2455353b9b160bc809992b8cab2fed0ce1cdb11709e74ead0e8168f2ba61141e68de269135d15633674b092325ba90454c3d70d35543f8c
7
+ data.tar.gz: bb00d3095ffe9bfcc68cf62bcc7c1a3753a036417b0740c1a3961da1513a5e278fc8f71eb444aec2290a2ed8180ad5bc4ab54bf993ccbff59a718e3ee06c205d
@@ -1,4 +1,4 @@
1
- Copyright (c) 2014 Christian Dobert
1
+ Copyright (c) 2016 Christian Dobert
2
2
 
3
3
  MIT License
4
4
 
data/README.md CHANGED
@@ -4,6 +4,8 @@ This gem is a simple wrapper around the Masonry plugin.
4
4
  It is bundled as a gem to be able to include this 3rd party asset into the asset pipeline, without having to locally import the actual CSS and JavaScript into your project.
5
5
  Please see http://masonry.desandro.com/ for the original plugin.
6
6
 
7
+ # [![Gem Version](https://badge.fury.io/rb/jquery-masonry-rails.svg)](http://badge.fury.io/rb/jquery-masonry-rails)
8
+
7
9
  ## Installation
8
10
 
9
11
  Add this line to your application's Gemfile:
@@ -1,7 +1,7 @@
1
1
  module Jquery
2
2
  module Masonry
3
3
  module Rails
4
- VERSION = "3.1.5"
4
+ VERSION = "4.0.0"
5
5
  end
6
6
  end
7
7
  end
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * Masonry PACKAGED v3.1.5
2
+ * Masonry PACKAGED v4.0.0
3
3
  * Cascading grid layout library
4
4
  * http://masonry.desandro.com
5
5
  * MIT License
@@ -8,854 +8,304 @@
8
8
 
9
9
  /**
10
10
  * Bridget makes jQuery widgets
11
- * v1.0.1
11
+ * v2.0.0
12
+ * MIT license
12
13
  */
13
14
 
14
- ( function( window ) {
15
-
16
-
17
-
18
- // -------------------------- utils -------------------------- //
19
-
20
- var slice = Array.prototype.slice;
21
-
22
- function noop() {}
23
-
24
- // -------------------------- definition -------------------------- //
25
-
26
- function defineBridget( $ ) {
27
-
28
- // bail if no jQuery
29
- if ( !$ ) {
30
- return;
31
- }
15
+ /* jshint browser: true, strict: true, undef: true, unused: true */
32
16
 
33
- // -------------------------- addOptionMethod -------------------------- //
17
+ ( function( window, factory ) {
18
+ 'use strict';
19
+ /* globals define: false, module: false, require: false */
34
20
 
35
- /**
36
- * adds option method -> $().plugin('option', {...})
37
- * @param {Function} PluginClass - constructor class
38
- */
39
- function addOptionMethod( PluginClass ) {
40
- // don't overwrite original option method
41
- if ( PluginClass.prototype.option ) {
42
- return;
21
+ if ( typeof define == 'function' && define.amd ) {
22
+ // AMD
23
+ define( 'jquery-bridget/jquery-bridget',[ 'jquery' ], function( jQuery ) {
24
+ factory( window, jQuery );
25
+ });
26
+ } else if ( typeof module == 'object' && module.exports ) {
27
+ // CommonJS
28
+ module.exports = factory(
29
+ window,
30
+ require('jquery')
31
+ );
32
+ } else {
33
+ // browser global
34
+ window.jQueryBridget = factory(
35
+ window,
36
+ window.jQuery
37
+ );
43
38
  }
44
39
 
45
- // option setter
46
- PluginClass.prototype.option = function( opts ) {
47
- // bail out if not an object
48
- if ( !$.isPlainObject( opts ) ){
49
- return;
50
- }
51
- this.options = $.extend( true, this.options, opts );
52
- };
53
- }
40
+ }( window, function factory( window, jQuery ) {
41
+ 'use strict';
54
42
 
43
+ // ----- utils ----- //
55
44
 
56
- // -------------------------- plugin bridge -------------------------- //
45
+ var arraySlice = Array.prototype.slice;
57
46
 
58
47
  // helper function for logging errors
59
48
  // $.error breaks jQuery chaining
60
- var logError = typeof console === 'undefined' ? noop :
49
+ var console = window.console;
50
+ var logError = typeof console == 'undefined' ? function() {} :
61
51
  function( message ) {
62
52
  console.error( message );
63
53
  };
64
54
 
65
- /**
66
- * jQuery plugin bridge, access methods like $elem.plugin('method')
67
- * @param {String} namespace - plugin name
68
- * @param {Function} PluginClass - constructor class
69
- */
70
- function bridge( namespace, PluginClass ) {
71
- // add to jQuery fn namespace
72
- $.fn[ namespace ] = function( options ) {
73
- if ( typeof options === 'string' ) {
74
- // call plugin method when first argument is a string
75
- // get arguments for method
76
- var args = slice.call( arguments, 1 );
77
-
78
- for ( var i=0, len = this.length; i < len; i++ ) {
79
- var elem = this[i];
80
- var instance = $.data( elem, namespace );
81
- if ( !instance ) {
82
- logError( "cannot call methods on " + namespace + " prior to initialization; " +
83
- "attempted to call '" + options + "'" );
84
- continue;
85
- }
86
- if ( !$.isFunction( instance[options] ) || options.charAt(0) === '_' ) {
87
- logError( "no such method '" + options + "' for " + namespace + " instance" );
88
- continue;
89
- }
90
-
91
- // trigger method with arguments
92
- var returnValue = instance[ options ].apply( instance, args );
93
-
94
- // break look and return first value if provided
95
- if ( returnValue !== undefined ) {
96
- return returnValue;
97
- }
98
- }
99
- // return this if no return value
100
- return this;
101
- } else {
102
- return this.each( function() {
103
- var instance = $.data( this, namespace );
104
- if ( instance ) {
105
- // apply options & init
106
- instance.option( options );
107
- instance._init();
108
- } else {
109
- // initialize new instance
110
- instance = new PluginClass( this, options );
111
- $.data( this, namespace, instance );
112
- }
113
- });
114
- }
115
- };
116
-
117
- }
118
-
119
- // -------------------------- bridget -------------------------- //
120
-
121
- /**
122
- * converts a Prototypical class into a proper jQuery plugin
123
- * the class must have a ._init method
124
- * @param {String} namespace - plugin name, used in $().pluginName
125
- * @param {Function} PluginClass - constructor class
126
- */
127
- $.bridget = function( namespace, PluginClass ) {
128
- addOptionMethod( PluginClass );
129
- bridge( namespace, PluginClass );
130
- };
131
-
132
- return $.bridget;
133
-
134
- }
135
-
136
- // transport
137
- if ( typeof define === 'function' && define.amd ) {
138
- // AMD
139
- define( 'jquery-bridget/jquery.bridget',[ 'jquery' ], defineBridget );
140
- } else {
141
- // get jquery from browser global
142
- defineBridget( window.jQuery );
143
- }
144
-
145
- })( window );
146
-
147
- /*!
148
- * eventie v1.0.5
149
- * event binding helper
150
- * eventie.bind( elem, 'click', myFn )
151
- * eventie.unbind( elem, 'click', myFn )
152
- * MIT license
153
- */
154
-
155
- /*jshint browser: true, undef: true, unused: true */
156
- /*global define: false, module: false */
157
-
158
- ( function( window ) {
159
-
160
-
161
-
162
- var docElem = document.documentElement;
163
-
164
- var bind = function() {};
165
-
166
- function getIEEvent( obj ) {
167
- var event = window.event;
168
- // add event.target
169
- event.target = event.target || event.srcElement || obj;
170
- return event;
171
- }
172
-
173
- if ( docElem.addEventListener ) {
174
- bind = function( obj, type, fn ) {
175
- obj.addEventListener( type, fn, false );
176
- };
177
- } else if ( docElem.attachEvent ) {
178
- bind = function( obj, type, fn ) {
179
- obj[ type + fn ] = fn.handleEvent ?
180
- function() {
181
- var event = getIEEvent( obj );
182
- fn.handleEvent.call( fn, event );
183
- } :
184
- function() {
185
- var event = getIEEvent( obj );
186
- fn.call( obj, event );
187
- };
188
- obj.attachEvent( "on" + type, obj[ type + fn ] );
189
- };
190
- }
191
-
192
- var unbind = function() {};
193
-
194
- if ( docElem.removeEventListener ) {
195
- unbind = function( obj, type, fn ) {
196
- obj.removeEventListener( type, fn, false );
197
- };
198
- } else if ( docElem.detachEvent ) {
199
- unbind = function( obj, type, fn ) {
200
- obj.detachEvent( "on" + type, obj[ type + fn ] );
201
- try {
202
- delete obj[ type + fn ];
203
- } catch ( err ) {
204
- // can't delete window object properties
205
- obj[ type + fn ] = undefined;
206
- }
207
- };
208
- }
209
-
210
- var eventie = {
211
- bind: bind,
212
- unbind: unbind
213
- };
214
-
215
- // ----- module definition ----- //
216
-
217
- if ( typeof define === 'function' && define.amd ) {
218
- // AMD
219
- define( 'eventie/eventie',eventie );
220
- } else if ( typeof exports === 'object' ) {
221
- // CommonJS
222
- module.exports = eventie;
223
- } else {
224
- // browser global
225
- window.eventie = eventie;
226
- }
227
-
228
- })( this );
229
-
230
- /*!
231
- * docReady
232
- * Cross browser DOMContentLoaded event emitter
233
- */
234
-
235
- /*jshint browser: true, strict: true, undef: true, unused: true*/
236
- /*global define: false */
237
-
238
- ( function( window ) {
55
+ // ----- jQueryBridget ----- //
239
56
 
240
-
241
-
242
- var document = window.document;
243
- // collection of functions to be triggered on ready
244
- var queue = [];
245
-
246
- function docReady( fn ) {
247
- // throw out non-functions
248
- if ( typeof fn !== 'function' ) {
249
- return;
250
- }
251
-
252
- if ( docReady.isReady ) {
253
- // ready now, hit it
254
- fn();
255
- } else {
256
- // queue function when ready
257
- queue.push( fn );
258
- }
259
- }
260
-
261
- docReady.isReady = false;
262
-
263
- // triggered on various doc ready events
264
- function init( event ) {
265
- // bail if IE8 document is not ready just yet
266
- var isIE8NotReady = event.type === 'readystatechange' && document.readyState !== 'complete';
267
- if ( docReady.isReady || isIE8NotReady ) {
57
+ function jQueryBridget( namespace, PluginClass, $ ) {
58
+ $ = $ || jQuery || window.jQuery;
59
+ if ( !$ ) {
268
60
  return;
269
61
  }
270
- docReady.isReady = true;
271
-
272
- // process queue
273
- for ( var i=0, len = queue.length; i < len; i++ ) {
274
- var fn = queue[i];
275
- fn();
276
- }
277
- }
278
-
279
- function defineDocReady( eventie ) {
280
- eventie.bind( document, 'DOMContentLoaded', init );
281
- eventie.bind( document, 'readystatechange', init );
282
- eventie.bind( window, 'load', init );
283
-
284
- return docReady;
285
- }
286
-
287
- // transport
288
- if ( typeof define === 'function' && define.amd ) {
289
- // AMD
290
- // if RequireJS, then doc is already ready
291
- docReady.isReady = typeof requirejs === 'function';
292
- define( 'doc-ready/doc-ready',[ 'eventie/eventie' ], defineDocReady );
293
- } else {
294
- // browser global
295
- window.docReady = defineDocReady( window.eventie );
296
- }
297
-
298
- })( this );
299
-
300
- /*!
301
- * EventEmitter v4.2.7 - git.io/ee
302
- * Oliver Caldwell
303
- * MIT license
304
- * @preserve
305
- */
306
-
307
- (function () {
308
-
309
-
310
- /**
311
- * Class for managing events.
312
- * Can be extended to provide event functionality in other classes.
313
- *
314
- * @class EventEmitter Manages event registering and emitting.
315
- */
316
- function EventEmitter() {}
317
-
318
- // Shortcuts to improve speed and size
319
- var proto = EventEmitter.prototype;
320
- var exports = this;
321
- var originalGlobalValue = exports.EventEmitter;
322
62
 
323
- /**
324
- * Finds the index of the listener for the event in it's storage array.
325
- *
326
- * @param {Function[]} listeners Array of listeners to search through.
327
- * @param {Function} listener Method to look for.
328
- * @return {Number} Index of the specified listener, -1 if not found
329
- * @api private
330
- */
331
- function indexOfListener(listeners, listener) {
332
- var i = listeners.length;
333
- while (i--) {
334
- if (listeners[i].listener === listener) {
335
- return i;
63
+ // add option method -> $().plugin('option', {...})
64
+ if ( !PluginClass.prototype.option ) {
65
+ // option setter
66
+ PluginClass.prototype.option = function( opts ) {
67
+ // bail out if not an object
68
+ if ( !$.isPlainObject( opts ) ){
69
+ return;
336
70
  }
337
- }
338
-
339
- return -1;
340
- }
341
-
342
- /**
343
- * Alias a method while keeping the context correct, to allow for overwriting of target method.
344
- *
345
- * @param {String} name The name of the target method.
346
- * @return {Function} The aliased method
347
- * @api private
348
- */
349
- function alias(name) {
350
- return function aliasClosure() {
351
- return this[name].apply(this, arguments);
71
+ this.options = $.extend( true, this.options, opts );
352
72
  };
353
73
  }
354
74
 
355
- /**
356
- * Returns the listener array for the specified event.
357
- * Will initialise the event object and listener arrays if required.
358
- * Will return an object if you use a regex search. The object contains keys for each matched event. So /ba[rz]/ might return an object containing bar and baz. But only if you have either defined them with defineEvent or added some listeners to them.
359
- * Each property in the object response is an array of listener functions.
360
- *
361
- * @param {String|RegExp} evt Name of the event to return the listeners from.
362
- * @return {Function[]|Object} All listener functions for the event.
363
- */
364
- proto.getListeners = function getListeners(evt) {
365
- var events = this._getEvents();
366
- var response;
367
- var key;
368
-
369
- // Return a concatenated array of all matching events if
370
- // the selector is a regular expression.
371
- if (evt instanceof RegExp) {
372
- response = {};
373
- for (key in events) {
374
- if (events.hasOwnProperty(key) && evt.test(key)) {
375
- response[key] = events[key];
376
- }
377
- }
378
- }
379
- else {
380
- response = events[evt] || (events[evt] = []);
381
- }
382
-
383
- return response;
384
- };
385
-
386
- /**
387
- * Takes a list of listener objects and flattens it into a list of listener functions.
388
- *
389
- * @param {Object[]} listeners Raw listener objects.
390
- * @return {Function[]} Just the listener functions.
391
- */
392
- proto.flattenListeners = function flattenListeners(listeners) {
393
- var flatListeners = [];
394
- var i;
395
-
396
- for (i = 0; i < listeners.length; i += 1) {
397
- flatListeners.push(listeners[i].listener);
398
- }
399
-
400
- return flatListeners;
401
- };
402
-
403
- /**
404
- * Fetches the requested listeners via getListeners but will always return the results inside an object. This is mainly for internal use but others may find it useful.
405
- *
406
- * @param {String|RegExp} evt Name of the event to return the listeners from.
407
- * @return {Object} All listener functions for an event in an object.
408
- */
409
- proto.getListenersAsObject = function getListenersAsObject(evt) {
410
- var listeners = this.getListeners(evt);
411
- var response;
412
-
413
- if (listeners instanceof Array) {
414
- response = {};
415
- response[evt] = listeners;
75
+ // make jQuery plugin
76
+ $.fn[ namespace ] = function( arg0 /*, arg1 */ ) {
77
+ if ( typeof arg0 == 'string' ) {
78
+ // method call $().plugin( 'methodName', { options } )
79
+ // shift arguments by 1
80
+ var args = arraySlice.call( arguments, 1 );
81
+ return methodCall( this, arg0, args );
416
82
  }
417
-
418
- return response || listeners;
83
+ // just $().plugin({ options })
84
+ plainCall( this, arg0 );
85
+ return this;
419
86
  };
420
87
 
421
- /**
422
- * Adds a listener function to the specified event.
423
- * The listener will not be added if it is a duplicate.
424
- * If the listener returns true then it will be removed after it is called.
425
- * If you pass a regular expression as the event name then the listener will be added to all events that match it.
426
- *
427
- * @param {String|RegExp} evt Name of the event to attach the listener to.
428
- * @param {Function} listener Method to be called when the event is emitted. If the function returns true then it will be removed after calling.
429
- * @return {Object} Current instance of EventEmitter for chaining.
430
- */
431
- proto.addListener = function addListener(evt, listener) {
432
- var listeners = this.getListenersAsObject(evt);
433
- var listenerIsWrapped = typeof listener === 'object';
434
- var key;
435
-
436
- for (key in listeners) {
437
- if (listeners.hasOwnProperty(key) && indexOfListener(listeners[key], listener) === -1) {
438
- listeners[key].push(listenerIsWrapped ? listener : {
439
- listener: listener,
440
- once: false
441
- });
88
+ // $().plugin('methodName')
89
+ function methodCall( $elems, methodName, args ) {
90
+ var returnValue;
91
+ var pluginMethodStr = '$().' + namespace + '("' + methodName + '")';
92
+
93
+ $elems.each( function( i, elem ) {
94
+ // get instance
95
+ var instance = $.data( elem, namespace );
96
+ if ( !instance ) {
97
+ logError( namespace + ' not initialized. Cannot call methods, i.e. ' +
98
+ pluginMethodStr );
99
+ return;
442
100
  }
443
- }
444
101
 
445
- return this;
446
- };
447
-
448
- /**
449
- * Alias of addListener
450
- */
451
- proto.on = alias('addListener');
102
+ var method = instance[ methodName ];
103
+ if ( !method || methodName.charAt(0) == '_' ) {
104
+ logError( pluginMethodStr + ' is not a valid method' );
105
+ return;
106
+ }
452
107
 
453
- /**
454
- * Semi-alias of addListener. It will add a listener that will be
455
- * automatically removed after it's first execution.
456
- *
457
- * @param {String|RegExp} evt Name of the event to attach the listener to.
458
- * @param {Function} listener Method to be called when the event is emitted. If the function returns true then it will be removed after calling.
459
- * @return {Object} Current instance of EventEmitter for chaining.
460
- */
461
- proto.addOnceListener = function addOnceListener(evt, listener) {
462
- return this.addListener(evt, {
463
- listener: listener,
464
- once: true
108
+ // apply method, get return value
109
+ var value = method.apply( instance, args );
110
+ // set return value if value is returned, use only first value
111
+ returnValue = returnValue === undefined ? value : returnValue;
465
112
  });
466
- };
467
-
468
- /**
469
- * Alias of addOnceListener.
470
- */
471
- proto.once = alias('addOnceListener');
472
-
473
- /**
474
- * Defines an event name. This is required if you want to use a regex to add a listener to multiple events at once. If you don't do this then how do you expect it to know what event to add to? Should it just add to every possible match for a regex? No. That is scary and bad.
475
- * You need to tell it what event names should be matched by a regex.
476
- *
477
- * @param {String} evt Name of the event to create.
478
- * @return {Object} Current instance of EventEmitter for chaining.
479
- */
480
- proto.defineEvent = function defineEvent(evt) {
481
- this.getListeners(evt);
482
- return this;
483
- };
484
-
485
- /**
486
- * Uses defineEvent to define multiple events.
487
- *
488
- * @param {String[]} evts An array of event names to define.
489
- * @return {Object} Current instance of EventEmitter for chaining.
490
- */
491
- proto.defineEvents = function defineEvents(evts) {
492
- for (var i = 0; i < evts.length; i += 1) {
493
- this.defineEvent(evts[i]);
494
- }
495
- return this;
496
- };
497
113
 
498
- /**
499
- * Removes a listener function from the specified event.
500
- * When passed a regular expression as the event name, it will remove the listener from all events that match it.
501
- *
502
- * @param {String|RegExp} evt Name of the event to remove the listener from.
503
- * @param {Function} listener Method to remove from the event.
504
- * @return {Object} Current instance of EventEmitter for chaining.
505
- */
506
- proto.removeListener = function removeListener(evt, listener) {
507
- var listeners = this.getListenersAsObject(evt);
508
- var index;
509
- var key;
510
-
511
- for (key in listeners) {
512
- if (listeners.hasOwnProperty(key)) {
513
- index = indexOfListener(listeners[key], listener);
114
+ return returnValue !== undefined ? returnValue : $elems;
115
+ }
514
116
 
515
- if (index !== -1) {
516
- listeners[key].splice(index, 1);
517
- }
117
+ function plainCall( $elems, options ) {
118
+ $elems.each( function( i, elem ) {
119
+ var instance = $.data( elem, namespace );
120
+ if ( instance ) {
121
+ // set options & init
122
+ instance.option( options );
123
+ instance._init();
124
+ } else {
125
+ // initialize new instance
126
+ instance = new PluginClass( elem, options );
127
+ $.data( elem, namespace, instance );
518
128
  }
519
- }
520
-
521
- return this;
522
- };
523
-
524
- /**
525
- * Alias of removeListener
526
- */
527
- proto.off = alias('removeListener');
129
+ });
130
+ }
528
131
 
529
- /**
530
- * Adds listeners in bulk using the manipulateListeners method.
531
- * If you pass an object as the second argument you can add to multiple events at once. The object should contain key value pairs of events and listeners or listener arrays. You can also pass it an event name and an array of listeners to be added.
532
- * You can also pass it a regular expression to add the array of listeners to all events that match it.
533
- * Yeah, this function does quite a bit. That's probably a bad thing.
534
- *
535
- * @param {String|Object|RegExp} evt An event name if you will pass an array of listeners next. An object if you wish to add to multiple events at once.
536
- * @param {Function[]} [listeners] An optional array of listener functions to add.
537
- * @return {Object} Current instance of EventEmitter for chaining.
538
- */
539
- proto.addListeners = function addListeners(evt, listeners) {
540
- // Pass through to manipulateListeners
541
- return this.manipulateListeners(false, evt, listeners);
542
- };
132
+ updateJQuery( $ );
543
133
 
544
- /**
545
- * Removes listeners in bulk using the manipulateListeners method.
546
- * If you pass an object as the second argument you can remove from multiple events at once. The object should contain key value pairs of events and listeners or listener arrays.
547
- * You can also pass it an event name and an array of listeners to be removed.
548
- * You can also pass it a regular expression to remove the listeners from all events that match it.
549
- *
550
- * @param {String|Object|RegExp} evt An event name if you will pass an array of listeners next. An object if you wish to remove from multiple events at once.
551
- * @param {Function[]} [listeners] An optional array of listener functions to remove.
552
- * @return {Object} Current instance of EventEmitter for chaining.
553
- */
554
- proto.removeListeners = function removeListeners(evt, listeners) {
555
- // Pass through to manipulateListeners
556
- return this.manipulateListeners(true, evt, listeners);
557
- };
134
+ }
558
135
 
559
- /**
560
- * Edits listeners in bulk. The addListeners and removeListeners methods both use this to do their job. You should really use those instead, this is a little lower level.
561
- * The first argument will determine if the listeners are removed (true) or added (false).
562
- * If you pass an object as the second argument you can add/remove from multiple events at once. The object should contain key value pairs of events and listeners or listener arrays.
563
- * You can also pass it an event name and an array of listeners to be added/removed.
564
- * You can also pass it a regular expression to manipulate the listeners of all events that match it.
565
- *
566
- * @param {Boolean} remove True if you want to remove listeners, false if you want to add.
567
- * @param {String|Object|RegExp} evt An event name if you will pass an array of listeners next. An object if you wish to add/remove from multiple events at once.
568
- * @param {Function[]} [listeners] An optional array of listener functions to add/remove.
569
- * @return {Object} Current instance of EventEmitter for chaining.
570
- */
571
- proto.manipulateListeners = function manipulateListeners(remove, evt, listeners) {
572
- var i;
573
- var value;
574
- var single = remove ? this.removeListener : this.addListener;
575
- var multiple = remove ? this.removeListeners : this.addListeners;
576
-
577
- // If evt is an object then pass each of it's properties to this method
578
- if (typeof evt === 'object' && !(evt instanceof RegExp)) {
579
- for (i in evt) {
580
- if (evt.hasOwnProperty(i) && (value = evt[i])) {
581
- // Pass the single listener straight through to the singular method
582
- if (typeof value === 'function') {
583
- single.call(this, i, value);
584
- }
585
- else {
586
- // Otherwise pass back to the multiple function
587
- multiple.call(this, i, value);
588
- }
589
- }
590
- }
591
- }
592
- else {
593
- // So evt must be a string
594
- // And listeners must be an array of listeners
595
- // Loop over it and pass each one to the multiple method
596
- i = listeners.length;
597
- while (i--) {
598
- single.call(this, evt, listeners[i]);
599
- }
600
- }
136
+ // ----- updateJQuery ----- //
601
137
 
602
- return this;
603
- };
138
+ // set $.bridget for v1 backwards compatibility
139
+ function updateJQuery( $ ) {
140
+ if ( !$ || ( $ && $.bridget ) ) {
141
+ return;
142
+ }
143
+ $.bridget = jQueryBridget;
144
+ }
604
145
 
605
- /**
606
- * Removes all listeners from a specified event.
607
- * If you do not specify an event then all listeners will be removed.
608
- * That means every event will be emptied.
609
- * You can also pass a regex to remove all events that match it.
610
- *
611
- * @param {String|RegExp} [evt] Optional name of the event to remove all listeners for. Will remove from every event if not passed.
612
- * @return {Object} Current instance of EventEmitter for chaining.
613
- */
614
- proto.removeEvent = function removeEvent(evt) {
615
- var type = typeof evt;
616
- var events = this._getEvents();
617
- var key;
618
-
619
- // Remove different things depending on the state of evt
620
- if (type === 'string') {
621
- // Remove all listeners for the specified event
622
- delete events[evt];
623
- }
624
- else if (evt instanceof RegExp) {
625
- // Remove all events matching the regex.
626
- for (key in events) {
627
- if (events.hasOwnProperty(key) && evt.test(key)) {
628
- delete events[key];
629
- }
630
- }
631
- }
632
- else {
633
- // Remove all listeners in all events
634
- delete this._events;
635
- }
146
+ updateJQuery( jQuery || window.jQuery );
636
147
 
637
- return this;
638
- };
148
+ // ----- ----- //
639
149
 
640
- /**
641
- * Alias of removeEvent.
642
- *
643
- * Added to mirror the node API.
644
- */
645
- proto.removeAllListeners = alias('removeEvent');
150
+ return jQueryBridget;
646
151
 
647
- /**
648
- * Emits an event of your choice.
649
- * When emitted, every listener attached to that event will be executed.
650
- * If you pass the optional argument array then those arguments will be passed to every listener upon execution.
651
- * Because it uses `apply`, your array of arguments will be passed as if you wrote them out separately.
652
- * So they will not arrive within the array on the other side, they will be separate.
653
- * You can also pass a regular expression to emit to all events that match it.
654
- *
655
- * @param {String|RegExp} evt Name of the event to emit and execute listeners for.
656
- * @param {Array} [args] Optional array of arguments to be passed to each listener.
657
- * @return {Object} Current instance of EventEmitter for chaining.
658
- */
659
- proto.emitEvent = function emitEvent(evt, args) {
660
- var listeners = this.getListenersAsObject(evt);
661
- var listener;
662
- var i;
663
- var key;
664
- var response;
665
-
666
- for (key in listeners) {
667
- if (listeners.hasOwnProperty(key)) {
668
- i = listeners[key].length;
669
-
670
- while (i--) {
671
- // If the listener returns true then it shall be removed from the event
672
- // The function is executed either with a basic call or an apply if there is an args array
673
- listener = listeners[key][i];
674
-
675
- if (listener.once === true) {
676
- this.removeListener(evt, listener.listener);
677
- }
678
-
679
- response = listener.listener.apply(this, args || []);
680
-
681
- if (response === this._getOnceReturnValue()) {
682
- this.removeListener(evt, listener.listener);
683
- }
684
- }
685
- }
686
- }
152
+ }));
687
153
 
688
- return this;
689
- };
154
+ /**
155
+ * EvEmitter v1.0.1
156
+ * Lil' event emitter
157
+ * MIT License
158
+ */
690
159
 
691
- /**
692
- * Alias of emitEvent
693
- */
694
- proto.trigger = alias('emitEvent');
160
+ /* jshint unused: true, undef: true, strict: true */
161
+
162
+ ( function( global, factory ) {
163
+ // universal module definition
164
+ /* jshint strict: false */ /* globals define, module */
165
+ if ( typeof define == 'function' && define.amd ) {
166
+ // AMD - RequireJS
167
+ define( 'ev-emitter/ev-emitter',factory );
168
+ } else if ( typeof module == 'object' && module.exports ) {
169
+ // CommonJS - Browserify, Webpack
170
+ module.exports = factory();
171
+ } else {
172
+ // Browser globals
173
+ global.EvEmitter = factory();
174
+ }
695
175
 
696
- /**
697
- * Subtly different from emitEvent in that it will pass its arguments on to the listeners, as opposed to taking a single array of arguments to pass on.
698
- * As with emitEvent, you can pass a regex in place of the event name to emit to all events that match it.
699
- *
700
- * @param {String|RegExp} evt Name of the event to emit and execute listeners for.
701
- * @param {...*} Optional additional arguments to be passed to each listener.
702
- * @return {Object} Current instance of EventEmitter for chaining.
703
- */
704
- proto.emit = function emit(evt) {
705
- var args = Array.prototype.slice.call(arguments, 1);
706
- return this.emitEvent(evt, args);
707
- };
176
+ }( this, function() {
708
177
 
709
- /**
710
- * Sets the current value to check against when executing listeners. If a
711
- * listeners return value matches the one set here then it will be removed
712
- * after execution. This value defaults to true.
713
- *
714
- * @param {*} value The new value to check for when executing listeners.
715
- * @return {Object} Current instance of EventEmitter for chaining.
716
- */
717
- proto.setOnceReturnValue = function setOnceReturnValue(value) {
718
- this._onceReturnValue = value;
719
- return this;
720
- };
721
178
 
722
- /**
723
- * Fetches the current value to check against when executing listeners. If
724
- * the listeners return value matches this one then it should be removed
725
- * automatically. It will return true by default.
726
- *
727
- * @return {*|Boolean} The current value to check for or the default, true.
728
- * @api private
729
- */
730
- proto._getOnceReturnValue = function _getOnceReturnValue() {
731
- if (this.hasOwnProperty('_onceReturnValue')) {
732
- return this._onceReturnValue;
733
- }
734
- else {
735
- return true;
736
- }
737
- };
738
179
 
739
- /**
740
- * Fetches the events object and creates one if required.
741
- *
742
- * @return {Object} The events storage object.
743
- * @api private
744
- */
745
- proto._getEvents = function _getEvents() {
746
- return this._events || (this._events = {});
747
- };
180
+ function EvEmitter() {}
748
181
 
749
- /**
750
- * Reverts the global {@link EventEmitter} to its previous value and returns a reference to this version.
751
- *
752
- * @return {Function} Non conflicting EventEmitter class.
753
- */
754
- EventEmitter.noConflict = function noConflict() {
755
- exports.EventEmitter = originalGlobalValue;
756
- return EventEmitter;
757
- };
182
+ var proto = EvEmitter.prototype;
758
183
 
759
- // Expose the class either via AMD, CommonJS or the global object
760
- if (typeof define === 'function' && define.amd) {
761
- define('eventEmitter/EventEmitter',[],function () {
762
- return EventEmitter;
763
- });
764
- }
765
- else if (typeof module === 'object' && module.exports){
766
- module.exports = EventEmitter;
184
+ proto.on = function( eventName, listener ) {
185
+ if ( !eventName || !listener ) {
186
+ return;
767
187
  }
768
- else {
769
- this.EventEmitter = EventEmitter;
188
+ // set events hash
189
+ var events = this._events = this._events || {};
190
+ // set listeners array
191
+ var listeners = events[ eventName ] = events[ eventName ] || [];
192
+ // only add once
193
+ if ( listeners.indexOf( listener ) == -1 ) {
194
+ listeners.push( listener );
770
195
  }
771
- }.call(this));
772
-
773
- /*!
774
- * getStyleProperty v1.0.3
775
- * original by kangax
776
- * http://perfectionkills.com/feature-testing-css-properties/
777
- */
778
-
779
- /*jshint browser: true, strict: true, undef: true */
780
- /*global define: false, exports: false, module: false */
781
-
782
- ( function( window ) {
783
196
 
197
+ return this;
198
+ };
784
199
 
200
+ proto.once = function( eventName, listener ) {
201
+ if ( !eventName || !listener ) {
202
+ return;
203
+ }
204
+ // add event
205
+ this.on( eventName, listener );
206
+ // set once flag
207
+ // set onceEvents hash
208
+ var onceEvents = this._onceEvents = this._onceEvents || {};
209
+ // set onceListeners array
210
+ var onceListeners = onceEvents[ eventName ] = onceEvents[ eventName ] || [];
211
+ // set flag
212
+ onceListeners[ listener ] = true;
785
213
 
786
- var prefixes = 'Webkit Moz ms Ms O'.split(' ');
787
- var docElemStyle = document.documentElement.style;
214
+ return this;
215
+ };
788
216
 
789
- function getStyleProperty( propName ) {
790
- if ( !propName ) {
217
+ proto.off = function( eventName, listener ) {
218
+ var listeners = this._events && this._events[ eventName ];
219
+ if ( !listeners || !listeners.length ) {
791
220
  return;
792
221
  }
793
-
794
- // test standard property first
795
- if ( typeof docElemStyle[ propName ] === 'string' ) {
796
- return propName;
222
+ var index = listeners.indexOf( listener );
223
+ if ( index != -1 ) {
224
+ listeners.splice( index, 1 );
797
225
  }
798
226
 
799
- // capitalize
800
- propName = propName.charAt(0).toUpperCase() + propName.slice(1);
227
+ return this;
228
+ };
801
229
 
802
- // test vendor specific properties
803
- var prefixed;
804
- for ( var i=0, len = prefixes.length; i < len; i++ ) {
805
- prefixed = prefixes[i] + propName;
806
- if ( typeof docElemStyle[ prefixed ] === 'string' ) {
807
- return prefixed;
230
+ proto.emitEvent = function( eventName, args ) {
231
+ var listeners = this._events && this._events[ eventName ];
232
+ if ( !listeners || !listeners.length ) {
233
+ return;
234
+ }
235
+ var i = 0;
236
+ var listener = listeners[i];
237
+ args = args || [];
238
+ // once stuff
239
+ var onceListeners = this._onceEvents && this._onceEvents[ eventName ];
240
+
241
+ while ( listener ) {
242
+ var isOnce = onceListeners && onceListeners[ listener ];
243
+ if ( isOnce ) {
244
+ // remove listener
245
+ // remove before trigger to prevent recursion
246
+ this.off( eventName, listener );
247
+ // unset once flag
248
+ delete onceListeners[ listener ];
808
249
  }
250
+ // trigger listener
251
+ listener.apply( this, args );
252
+ // get next listener
253
+ i += isOnce ? 0 : 1;
254
+ listener = listeners[i];
809
255
  }
810
- }
811
256
 
812
- // transport
813
- if ( typeof define === 'function' && define.amd ) {
814
- // AMD
815
- define( 'get-style-property/get-style-property',[],function() {
816
- return getStyleProperty;
817
- });
818
- } else if ( typeof exports === 'object' ) {
819
- // CommonJS for Component
820
- module.exports = getStyleProperty;
821
- } else {
822
- // browser global
823
- window.getStyleProperty = getStyleProperty;
824
- }
257
+ return this;
258
+ };
825
259
 
826
- })( window );
260
+ return EvEmitter;
827
261
 
828
- /**
829
- * getSize v1.1.7
262
+ }));
263
+
264
+ /*!
265
+ * getSize v2.0.2
830
266
  * measure size of elements
267
+ * MIT license
831
268
  */
832
269
 
833
270
  /*jshint browser: true, strict: true, undef: true, unused: true */
834
- /*global define: false, exports: false, require: false, module: false */
271
+ /*global define: false, module: false, console: false */
835
272
 
836
- ( function( window, undefined ) {
273
+ ( function( window, factory ) {
274
+ 'use strict';
837
275
 
276
+ if ( typeof define == 'function' && define.amd ) {
277
+ // AMD
278
+ define( 'get-size/get-size',[],function() {
279
+ return factory();
280
+ });
281
+ } else if ( typeof module == 'object' && module.exports ) {
282
+ // CommonJS
283
+ module.exports = factory();
284
+ } else {
285
+ // browser global
286
+ window.getSize = factory();
287
+ }
838
288
 
289
+ })( window, function factory() {
290
+ 'use strict';
839
291
 
840
292
  // -------------------------- helpers -------------------------- //
841
293
 
842
- var getComputedStyle = window.getComputedStyle;
843
- var getStyle = getComputedStyle ?
844
- function( elem ) {
845
- return getComputedStyle( elem, null );
846
- } :
847
- function( elem ) {
848
- return elem.currentStyle;
849
- };
850
-
851
294
  // get a number from a string, not a percentage
852
295
  function getStyleSize( value ) {
853
296
  var num = parseFloat( value );
854
297
  // not a percent like '100%', and a number
855
- var isValid = value.indexOf('%') === -1 && !isNaN( num );
298
+ var isValid = value.indexOf('%') == -1 && !isNaN( num );
856
299
  return isValid && num;
857
300
  }
858
301
 
302
+ function noop() {}
303
+
304
+ var logError = typeof console == 'undefined' ? noop :
305
+ function( message ) {
306
+ console.error( message );
307
+ };
308
+
859
309
  // -------------------------- measurements -------------------------- //
860
310
 
861
311
  var measurements = [
@@ -873,6 +323,8 @@ var measurements = [
873
323
  'borderBottomWidth'
874
324
  ];
875
325
 
326
+ var measurementsLength = measurements.length;
327
+
876
328
  function getZeroSize() {
877
329
  var size = {
878
330
  width: 0,
@@ -882,64 +334,88 @@ function getZeroSize() {
882
334
  outerWidth: 0,
883
335
  outerHeight: 0
884
336
  };
885
- for ( var i=0, len = measurements.length; i < len; i++ ) {
337
+ for ( var i=0; i < measurementsLength; i++ ) {
886
338
  var measurement = measurements[i];
887
339
  size[ measurement ] = 0;
888
340
  }
889
341
  return size;
890
342
  }
891
343
 
344
+ // -------------------------- getStyle -------------------------- //
892
345
 
346
+ /**
347
+ * getStyle, get style of element, check for Firefox bug
348
+ * https://bugzilla.mozilla.org/show_bug.cgi?id=548397
349
+ */
350
+ function getStyle( elem ) {
351
+ var style = getComputedStyle( elem );
352
+ if ( !style ) {
353
+ logError( 'Style returned ' + style +
354
+ '. Are you running this code in a hidden iframe on Firefox? ' +
355
+ 'See http://bit.ly/getsizebug1' );
356
+ }
357
+ return style;
358
+ }
893
359
 
894
- function defineGetSize( getStyleProperty ) {
360
+ // -------------------------- setup -------------------------- //
895
361
 
896
- // -------------------------- box sizing -------------------------- //
362
+ var isSetup = false;
897
363
 
898
- var boxSizingProp = getStyleProperty('boxSizing');
899
364
  var isBoxSizeOuter;
900
365
 
901
366
  /**
902
- * WebKit measures the outer-width on style.width on border-box elems
903
- * IE & Firefox measures the inner-width
367
+ * setup
368
+ * check isBoxSizerOuter
369
+ * do on first getSize() rather than on page load for Firefox bug
904
370
  */
905
- ( function() {
906
- if ( !boxSizingProp ) {
371
+ function setup() {
372
+ // setup once
373
+ if ( isSetup ) {
907
374
  return;
908
375
  }
376
+ isSetup = true;
909
377
 
378
+ // -------------------------- box sizing -------------------------- //
379
+
380
+ /**
381
+ * WebKit measures the outer-width on style.width on border-box elems
382
+ * IE & Firefox<29 measures the inner-width
383
+ */
910
384
  var div = document.createElement('div');
911
385
  div.style.width = '200px';
912
386
  div.style.padding = '1px 2px 3px 4px';
913
387
  div.style.borderStyle = 'solid';
914
388
  div.style.borderWidth = '1px 2px 3px 4px';
915
- div.style[ boxSizingProp ] = 'border-box';
389
+ div.style.boxSizing = 'border-box';
916
390
 
917
391
  var body = document.body || document.documentElement;
918
392
  body.appendChild( div );
919
393
  var style = getStyle( div );
920
394
 
921
- isBoxSizeOuter = getStyleSize( style.width ) === 200;
395
+ getSize.isBoxSizeOuter = isBoxSizeOuter = getStyleSize( style.width ) == 200;
922
396
  body.removeChild( div );
923
- })();
924
397
 
398
+ }
925
399
 
926
400
  // -------------------------- getSize -------------------------- //
927
401
 
928
402
  function getSize( elem ) {
403
+ setup();
404
+
929
405
  // use querySeletor if elem is string
930
- if ( typeof elem === 'string' ) {
406
+ if ( typeof elem == 'string' ) {
931
407
  elem = document.querySelector( elem );
932
408
  }
933
409
 
934
410
  // do not proceed on non-objects
935
- if ( !elem || typeof elem !== 'object' || !elem.nodeType ) {
411
+ if ( !elem || typeof elem != 'object' || !elem.nodeType ) {
936
412
  return;
937
413
  }
938
414
 
939
415
  var style = getStyle( elem );
940
416
 
941
417
  // if hidden, everything is 0
942
- if ( style.display === 'none' ) {
418
+ if ( style.display == 'none' ) {
943
419
  return getZeroSize();
944
420
  }
945
421
 
@@ -947,14 +423,12 @@ function getSize( elem ) {
947
423
  size.width = elem.offsetWidth;
948
424
  size.height = elem.offsetHeight;
949
425
 
950
- var isBorderBox = size.isBorderBox = !!( boxSizingProp &&
951
- style[ boxSizingProp ] && style[ boxSizingProp ] === 'border-box' );
426
+ var isBorderBox = size.isBorderBox = style.boxSizing == 'border-box';
952
427
 
953
428
  // get all measurements
954
- for ( var i=0, len = measurements.length; i < len; i++ ) {
429
+ for ( var i=0; i < measurementsLength; i++ ) {
955
430
  var measurement = measurements[i];
956
431
  var value = style[ measurement ];
957
- value = mungeNonPixel( elem, value );
958
432
  var num = parseFloat( value );
959
433
  // any 'auto', 'medium' value will be 0
960
434
  size[ measurement ] = !isNaN( num ) ? num : 0;
@@ -993,69 +467,42 @@ function getSize( elem ) {
993
467
  return size;
994
468
  }
995
469
 
996
- // IE8 returns percent values, not pixels
997
- // taken from jQuery's curCSS
998
- function mungeNonPixel( elem, value ) {
999
- // IE8 and has percent value
1000
- if ( getComputedStyle || value.indexOf('%') === -1 ) {
1001
- return value;
1002
- }
1003
- var style = elem.style;
1004
- // Remember the original values
1005
- var left = style.left;
1006
- var rs = elem.runtimeStyle;
1007
- var rsLeft = rs && rs.left;
1008
-
1009
- // Put in the new values to get a computed value out
1010
- if ( rsLeft ) {
1011
- rs.left = elem.currentStyle.left;
1012
- }
1013
- style.left = value;
1014
- value = style.pixelLeft;
1015
-
1016
- // Revert the changed values
1017
- style.left = left;
1018
- if ( rsLeft ) {
1019
- rs.left = rsLeft;
1020
- }
1021
-
1022
- return value;
1023
- }
1024
-
1025
470
  return getSize;
1026
471
 
1027
- }
1028
-
1029
- // transport
1030
- if ( typeof define === 'function' && define.amd ) {
1031
- // AMD for RequireJS
1032
- define( 'get-size/get-size',[ 'get-style-property/get-style-property' ], defineGetSize );
1033
- } else if ( typeof exports === 'object' ) {
1034
- // CommonJS for Component
1035
- module.exports = defineGetSize( require('get-style-property') );
1036
- } else {
1037
- // browser global
1038
- window.getSize = defineGetSize( window.getStyleProperty );
1039
- }
1040
-
1041
- })( window );
472
+ });
1042
473
 
1043
474
  /**
1044
- * matchesSelector helper v1.0.1
1045
- *
1046
- * @name matchesSelector
1047
- * @param {Element} elem
1048
- * @param {String} selector
475
+ * matchesSelector v2.0.1
476
+ * matchesSelector( element, '.selector' )
477
+ * MIT license
1049
478
  */
1050
479
 
1051
480
  /*jshint browser: true, strict: true, undef: true, unused: true */
1052
- /*global define: false */
1053
481
 
1054
- ( function( global, ElemProto ) {
482
+ ( function( window, factory ) {
483
+ /*global define: false, module: false */
484
+ 'use strict';
485
+ // universal module definition
486
+ if ( typeof define == 'function' && define.amd ) {
487
+ // AMD
488
+ define( 'matches-selector/matches-selector',factory );
489
+ } else if ( typeof module == 'object' && module.exports ) {
490
+ // CommonJS
491
+ module.exports = factory();
492
+ } else {
493
+ // browser global
494
+ window.matchesSelector = factory();
495
+ }
1055
496
 
1056
-
497
+ }( window, function factory() {
498
+ 'use strict';
1057
499
 
1058
500
  var matchesMethod = ( function() {
501
+ var ElemProto = Element.prototype;
502
+ // check for the standard method name first
503
+ if ( ElemProto.matches ) {
504
+ return 'matches';
505
+ }
1059
506
  // check un-prefixed
1060
507
  if ( ElemProto.matchesSelector ) {
1061
508
  return 'matchesSelector';
@@ -1063,7 +510,7 @@ if ( typeof define === 'function' && define.amd ) {
1063
510
  // check vendor prefixes
1064
511
  var prefixes = [ 'webkit', 'moz', 'ms', 'o' ];
1065
512
 
1066
- for ( var i=0, len = prefixes.length; i < len; i++ ) {
513
+ for ( var i=0; i < prefixes.length; i++ ) {
1067
514
  var prefix = prefixes[i];
1068
515
  var method = prefix + 'MatchesSelector';
1069
516
  if ( ElemProto[ method ] ) {
@@ -1072,158 +519,318 @@ if ( typeof define === 'function' && define.amd ) {
1072
519
  }
1073
520
  })();
1074
521
 
1075
- // ----- match ----- //
1076
-
1077
- function match( elem, selector ) {
522
+ return function matchesSelector( elem, selector ) {
1078
523
  return elem[ matchesMethod ]( selector );
524
+ };
525
+
526
+ }));
527
+
528
+ /**
529
+ * Fizzy UI utils v2.0.0
530
+ * MIT license
531
+ */
532
+
533
+ /*jshint browser: true, undef: true, unused: true, strict: true */
534
+
535
+ ( function( window, factory ) {
536
+ /*global define: false, module: false, require: false */
537
+ 'use strict';
538
+ // universal module definition
539
+
540
+ if ( typeof define == 'function' && define.amd ) {
541
+ // AMD
542
+ define( 'fizzy-ui-utils/utils',[
543
+ 'matches-selector/matches-selector'
544
+ ], function( matchesSelector ) {
545
+ return factory( window, matchesSelector );
546
+ });
547
+ } else if ( typeof module == 'object' && module.exports ) {
548
+ // CommonJS
549
+ module.exports = factory(
550
+ window,
551
+ require('desandro-matches-selector')
552
+ );
553
+ } else {
554
+ // browser global
555
+ window.fizzyUIUtils = factory(
556
+ window,
557
+ window.matchesSelector
558
+ );
1079
559
  }
1080
560
 
1081
- // ----- appendToFragment ----- //
561
+ }( window, function factory( window, matchesSelector ) {
1082
562
 
1083
- function checkParent( elem ) {
1084
- // not needed if already has parent
1085
- if ( elem.parentNode ) {
1086
- return;
1087
- }
1088
- var fragment = document.createDocumentFragment();
1089
- fragment.appendChild( elem );
563
+
564
+
565
+ var utils = {};
566
+
567
+ // ----- extend ----- //
568
+
569
+ // extends objects
570
+ utils.extend = function( a, b ) {
571
+ for ( var prop in b ) {
572
+ a[ prop ] = b[ prop ];
1090
573
  }
574
+ return a;
575
+ };
576
+
577
+ // ----- modulo ----- //
1091
578
 
1092
- // ----- query ----- //
579
+ utils.modulo = function( num, div ) {
580
+ return ( ( num % div ) + div ) % div;
581
+ };
1093
582
 
1094
- // fall back to using QSA
1095
- // thx @jonathantneal https://gist.github.com/3062955
1096
- function query( elem, selector ) {
1097
- // append to fragment if no parent
1098
- checkParent( elem );
583
+ // ----- makeArray ----- //
1099
584
 
1100
- // match elem with all selected elems of parent
1101
- var elems = elem.parentNode.querySelectorAll( selector );
1102
- for ( var i=0, len = elems.length; i < len; i++ ) {
1103
- // return true if match
1104
- if ( elems[i] === elem ) {
1105
- return true;
1106
- }
585
+ // turn element or nodeList into an array
586
+ utils.makeArray = function( obj ) {
587
+ var ary = [];
588
+ if ( Array.isArray( obj ) ) {
589
+ // use object if already an array
590
+ ary = obj;
591
+ } else if ( obj && typeof obj.length == 'number' ) {
592
+ // convert nodeList to array
593
+ for ( var i=0; i < obj.length; i++ ) {
594
+ ary.push( obj[i] );
1107
595
  }
1108
- // otherwise return false
1109
- return false;
596
+ } else {
597
+ // array of single index
598
+ ary.push( obj );
599
+ }
600
+ return ary;
601
+ };
602
+
603
+ // ----- removeFrom ----- //
604
+
605
+ utils.removeFrom = function( ary, obj ) {
606
+ var index = ary.indexOf( obj );
607
+ if ( index != -1 ) {
608
+ ary.splice( index, 1 );
1110
609
  }
610
+ };
1111
611
 
1112
- // ----- matchChild ----- //
612
+ // ----- getParent ----- //
1113
613
 
1114
- function matchChild( elem, selector ) {
1115
- checkParent( elem );
1116
- return match( elem, selector );
614
+ utils.getParent = function( elem, selector ) {
615
+ while ( elem != document.body ) {
616
+ elem = elem.parentNode;
617
+ if ( matchesSelector( elem, selector ) ) {
618
+ return elem;
619
+ }
1117
620
  }
621
+ };
1118
622
 
1119
- // ----- matchesSelector ----- //
623
+ // ----- getQueryElement ----- //
1120
624
 
1121
- var matchesSelector;
625
+ // use element as selector string
626
+ utils.getQueryElement = function( elem ) {
627
+ if ( typeof elem == 'string' ) {
628
+ return document.querySelector( elem );
629
+ }
630
+ return elem;
631
+ };
1122
632
 
1123
- if ( matchesMethod ) {
1124
- // IE9 supports matchesSelector, but doesn't work on orphaned elems
1125
- // check for that
1126
- var div = document.createElement('div');
1127
- var supportsOrphans = match( div, 'div' );
1128
- matchesSelector = supportsOrphans ? match : matchChild;
1129
- } else {
1130
- matchesSelector = query;
633
+ // ----- handleEvent ----- //
634
+
635
+ // enable .ontype to trigger from .addEventListener( elem, 'type' )
636
+ utils.handleEvent = function( event ) {
637
+ var method = 'on' + event.type;
638
+ if ( this[ method ] ) {
639
+ this[ method ]( event );
1131
640
  }
641
+ };
1132
642
 
1133
- // transport
1134
- if ( typeof define === 'function' && define.amd ) {
1135
- // AMD
1136
- define( 'matches-selector/matches-selector',[],function() {
1137
- return matchesSelector;
1138
- });
643
+ // ----- filterFindElements ----- //
644
+
645
+ utils.filterFindElements = function( elems, selector ) {
646
+ // make array of elems
647
+ elems = utils.makeArray( elems );
648
+ var ffElems = [];
649
+
650
+ elems.forEach( function( elem ) {
651
+ // check that elem is an actual element
652
+ if ( !( elem instanceof HTMLElement ) ) {
653
+ return;
654
+ }
655
+ // add elem if no selector
656
+ if ( !selector ) {
657
+ ffElems.push( elem );
658
+ return;
659
+ }
660
+ // filter & find items if we have a selector
661
+ // filter
662
+ if ( matchesSelector( elem, selector ) ) {
663
+ ffElems.push( elem );
664
+ }
665
+ // find children
666
+ var childElems = elem.querySelectorAll( selector );
667
+ // concat childElems to filterFound array
668
+ for ( var i=0; i < childElems.length; i++ ) {
669
+ ffElems.push( childElems[i] );
670
+ }
671
+ });
672
+
673
+ return ffElems;
674
+ };
675
+
676
+ // ----- debounceMethod ----- //
677
+
678
+ utils.debounceMethod = function( _class, methodName, threshold ) {
679
+ // original method
680
+ var method = _class.prototype[ methodName ];
681
+ var timeoutName = methodName + 'Timeout';
682
+
683
+ _class.prototype[ methodName ] = function() {
684
+ var timeout = this[ timeoutName ];
685
+ if ( timeout ) {
686
+ clearTimeout( timeout );
687
+ }
688
+ var args = arguments;
689
+
690
+ var _this = this;
691
+ this[ timeoutName ] = setTimeout( function() {
692
+ method.apply( _this, args );
693
+ delete _this[ timeoutName ];
694
+ }, threshold || 100 );
695
+ };
696
+ };
697
+
698
+ // ----- docReady ----- //
699
+
700
+ utils.docReady = function( callback ) {
701
+ if ( document.readyState == 'complete' ) {
702
+ callback();
1139
703
  } else {
1140
- // browser global
1141
- window.matchesSelector = matchesSelector;
704
+ document.addEventListener( 'DOMContentLoaded', callback );
1142
705
  }
706
+ };
1143
707
 
1144
- })( this, Element.prototype );
708
+ // ----- htmlInit ----- //
1145
709
 
710
+ // http://jamesroberts.name/blog/2010/02/22/string-functions-for-javascript-trim-to-camel-case-to-dashed-and-to-underscore/
711
+ utils.toDashed = function( str ) {
712
+ return str.replace( /(.)([A-Z])/g, function( match, $1, $2 ) {
713
+ return $1 + '-' + $2;
714
+ }).toLowerCase();
715
+ };
716
+
717
+ var console = window.console;
1146
718
  /**
1147
- * Outlayer Item
719
+ * allow user to initialize classes via [data-namespace] or .js-namespace class
720
+ * htmlInit( Widget, 'widgetName' )
721
+ * options are parsed from data-namespace-options
1148
722
  */
723
+ utils.htmlInit = function( WidgetClass, namespace ) {
724
+ utils.docReady( function() {
725
+ var dashedNamespace = utils.toDashed( namespace );
726
+ var dataAttr = 'data-' + dashedNamespace;
727
+ var dataAttrElems = document.querySelectorAll( '[' + dataAttr + ']' );
728
+ var jsDashElems = document.querySelectorAll( '.js-' + dashedNamespace );
729
+ var elems = utils.makeArray( dataAttrElems )
730
+ .concat( utils.makeArray( jsDashElems ) );
731
+ var dataOptionsAttr = dataAttr + '-options';
732
+ var jQuery = window.jQuery;
733
+
734
+ elems.forEach( function( elem ) {
735
+ var attr = elem.getAttribute( dataAttr ) ||
736
+ elem.getAttribute( dataOptionsAttr );
737
+ var options;
738
+ try {
739
+ options = attr && JSON.parse( attr );
740
+ } catch ( error ) {
741
+ // log error, do not initialize
742
+ if ( console ) {
743
+ console.error( 'Error parsing ' + dataAttr + ' on ' + elem.className +
744
+ ': ' + error );
745
+ }
746
+ return;
747
+ }
748
+ // initialize
749
+ var instance = new WidgetClass( elem, options );
750
+ // make available via $().data('layoutname')
751
+ if ( jQuery ) {
752
+ jQuery.data( elem, namespace, instance );
753
+ }
754
+ });
1149
755
 
1150
- ( function( window ) {
1151
-
756
+ });
757
+ };
1152
758
 
759
+ // ----- ----- //
1153
760
 
1154
- // ----- get style ----- //
761
+ return utils;
1155
762
 
1156
- var getComputedStyle = window.getComputedStyle;
1157
- var getStyle = getComputedStyle ?
1158
- function( elem ) {
1159
- return getComputedStyle( elem, null );
1160
- } :
1161
- function( elem ) {
1162
- return elem.currentStyle;
1163
- };
763
+ }));
1164
764
 
765
+ /**
766
+ * Outlayer Item
767
+ */
1165
768
 
1166
- // extend objects
1167
- function extend( a, b ) {
1168
- for ( var prop in b ) {
1169
- a[ prop ] = b[ prop ];
769
+ ( function( window, factory ) {
770
+ // universal module definition
771
+ /* jshint strict: false */ /* globals define, module, require */
772
+ if ( typeof define == 'function' && define.amd ) {
773
+ // AMD - RequireJS
774
+ define( 'outlayer/item',[
775
+ 'ev-emitter/ev-emitter',
776
+ 'get-size/get-size'
777
+ ],
778
+ function( EvEmitter, getSize ) {
779
+ return factory( window, EvEmitter, getSize );
780
+ }
781
+ );
782
+ } else if ( typeof module == 'object' && module.exports ) {
783
+ // CommonJS - Browserify, Webpack
784
+ module.exports = factory(
785
+ window,
786
+ require('ev-emitter'),
787
+ require('get-size')
788
+ );
789
+ } else {
790
+ // browser global
791
+ window.Outlayer = {};
792
+ window.Outlayer.Item = factory(
793
+ window,
794
+ window.EvEmitter,
795
+ window.getSize
796
+ );
1170
797
  }
1171
- return a;
1172
- }
798
+
799
+ }( window, function factory( window, EvEmitter, getSize ) {
800
+ 'use strict';
801
+
802
+ // ----- helpers ----- //
1173
803
 
1174
804
  function isEmptyObj( obj ) {
1175
805
  for ( var prop in obj ) {
1176
806
  return false;
1177
807
  }
1178
808
  prop = null;
1179
- return true;
1180
- }
1181
-
1182
- // http://jamesroberts.name/blog/2010/02/22/string-functions-for-javascript-trim-to-camel-case-to-dashed-and-to-underscore/
1183
- function toDash( str ) {
1184
- return str.replace( /([A-Z])/g, function( $1 ){
1185
- return '-' + $1.toLowerCase();
1186
- });
809
+ return true;
1187
810
  }
1188
811
 
1189
- // -------------------------- Outlayer definition -------------------------- //
812
+ // -------------------------- CSS3 support -------------------------- //
1190
813
 
1191
- function outlayerItemDefinition( EventEmitter, getSize, getStyleProperty ) {
1192
814
 
1193
- // -------------------------- CSS3 support -------------------------- //
815
+ var docElemStyle = document.documentElement.style;
1194
816
 
1195
- var transitionProperty = getStyleProperty('transition');
1196
- var transformProperty = getStyleProperty('transform');
1197
- var supportsCSS3 = transitionProperty && transformProperty;
1198
- var is3d = !!getStyleProperty('perspective');
817
+ var transitionProperty = typeof docElemStyle.transition == 'string' ?
818
+ 'transition' : 'WebkitTransition';
819
+ var transformProperty = typeof docElemStyle.transform == 'string' ?
820
+ 'transform' : 'WebkitTransform';
1199
821
 
1200
822
  var transitionEndEvent = {
1201
823
  WebkitTransition: 'webkitTransitionEnd',
1202
- MozTransition: 'transitionend',
1203
- OTransition: 'otransitionend',
1204
824
  transition: 'transitionend'
1205
825
  }[ transitionProperty ];
1206
826
 
1207
- // properties that could have vendor prefix
1208
- var prefixableProperties = [
1209
- 'transform',
1210
- 'transition',
1211
- 'transitionDuration',
1212
- 'transitionProperty'
1213
- ];
1214
-
1215
827
  // cache all vendor properties
1216
- var vendorProperties = ( function() {
1217
- var cache = {};
1218
- for ( var i=0, len = prefixableProperties.length; i < len; i++ ) {
1219
- var prop = prefixableProperties[i];
1220
- var supportedProp = getStyleProperty( prop );
1221
- if ( supportedProp && supportedProp !== prop ) {
1222
- cache[ prop ] = supportedProp;
1223
- }
1224
- }
1225
- return cache;
1226
- })();
828
+ var vendorProperties = [
829
+ transformProperty,
830
+ transitionProperty,
831
+ transitionProperty + 'Duration',
832
+ transitionProperty + 'Property'
833
+ ];
1227
834
 
1228
835
  // -------------------------- Item -------------------------- //
1229
836
 
@@ -1243,10 +850,11 @@ function Item( element, layout ) {
1243
850
  this._create();
1244
851
  }
1245
852
 
1246
- // inherit EventEmitter
1247
- extend( Item.prototype, EventEmitter.prototype );
853
+ // inherit EvEmitter
854
+ var proto = Item.prototype = Object.create( EvEmitter.prototype );
855
+ proto.constructor = Item;
1248
856
 
1249
- Item.prototype._create = function() {
857
+ proto._create = function() {
1250
858
  // transition objects
1251
859
  this._transn = {
1252
860
  ingProperties: {},
@@ -1260,14 +868,14 @@ Item.prototype._create = function() {
1260
868
  };
1261
869
 
1262
870
  // trigger specified handler for event type
1263
- Item.prototype.handleEvent = function( event ) {
871
+ proto.handleEvent = function( event ) {
1264
872
  var method = 'on' + event.type;
1265
873
  if ( this[ method ] ) {
1266
874
  this[ method ]( event );
1267
875
  }
1268
876
  };
1269
877
 
1270
- Item.prototype.getSize = function() {
878
+ proto.getSize = function() {
1271
879
  this.size = getSize( this.element );
1272
880
  };
1273
881
 
@@ -1275,7 +883,7 @@ Item.prototype.getSize = function() {
1275
883
  * apply CSS styles to element
1276
884
  * @param {Object} style
1277
885
  */
1278
- Item.prototype.css = function( style ) {
886
+ proto.css = function( style ) {
1279
887
  var elemStyle = this.element.style;
1280
888
 
1281
889
  for ( var prop in style ) {
@@ -1286,19 +894,23 @@ Item.prototype.css = function( style ) {
1286
894
  };
1287
895
 
1288
896
  // measure position, and sets it
1289
- Item.prototype.getPosition = function() {
1290
- var style = getStyle( this.element );
1291
- var layoutOptions = this.layout.options;
1292
- var isOriginLeft = layoutOptions.isOriginLeft;
1293
- var isOriginTop = layoutOptions.isOriginTop;
1294
- var x = parseInt( style[ isOriginLeft ? 'left' : 'right' ], 10 );
1295
- var y = parseInt( style[ isOriginTop ? 'top' : 'bottom' ], 10 );
897
+ proto.getPosition = function() {
898
+ var style = getComputedStyle( this.element );
899
+ var isOriginLeft = this.layout._getOption('originLeft');
900
+ var isOriginTop = this.layout._getOption('originTop');
901
+ var xValue = style[ isOriginLeft ? 'left' : 'right' ];
902
+ var yValue = style[ isOriginTop ? 'top' : 'bottom' ];
903
+ // convert percent to pixels
904
+ var layoutSize = this.layout.size;
905
+ var x = xValue.indexOf('%') != -1 ?
906
+ ( parseFloat( xValue ) / 100 ) * layoutSize.width : parseInt( xValue, 10 );
907
+ var y = yValue.indexOf('%') != -1 ?
908
+ ( parseFloat( yValue ) / 100 ) * layoutSize.height : parseInt( yValue, 10 );
1296
909
 
1297
910
  // clean up 'auto' or other non-integer values
1298
911
  x = isNaN( x ) ? 0 : x;
1299
912
  y = isNaN( y ) ? 0 : y;
1300
913
  // remove padding from measurement
1301
- var layoutSize = this.layout.size;
1302
914
  x -= isOriginLeft ? layoutSize.paddingLeft : layoutSize.paddingRight;
1303
915
  y -= isOriginTop ? layoutSize.paddingTop : layoutSize.paddingBottom;
1304
916
 
@@ -1307,44 +919,51 @@ Item.prototype.getPosition = function() {
1307
919
  };
1308
920
 
1309
921
  // set settled position, apply padding
1310
- Item.prototype.layoutPosition = function() {
922
+ proto.layoutPosition = function() {
1311
923
  var layoutSize = this.layout.size;
1312
- var layoutOptions = this.layout.options;
1313
924
  var style = {};
1314
-
1315
- if ( layoutOptions.isOriginLeft ) {
1316
- style.left = ( this.position.x + layoutSize.paddingLeft ) + 'px';
1317
- // reset other property
1318
- style.right = '';
1319
- } else {
1320
- style.right = ( this.position.x + layoutSize.paddingRight ) + 'px';
1321
- style.left = '';
1322
- }
1323
-
1324
- if ( layoutOptions.isOriginTop ) {
1325
- style.top = ( this.position.y + layoutSize.paddingTop ) + 'px';
1326
- style.bottom = '';
1327
- } else {
1328
- style.bottom = ( this.position.y + layoutSize.paddingBottom ) + 'px';
1329
- style.top = '';
1330
- }
925
+ var isOriginLeft = this.layout._getOption('originLeft');
926
+ var isOriginTop = this.layout._getOption('originTop');
927
+
928
+ // x
929
+ var xPadding = isOriginLeft ? 'paddingLeft' : 'paddingRight';
930
+ var xProperty = isOriginLeft ? 'left' : 'right';
931
+ var xResetProperty = isOriginLeft ? 'right' : 'left';
932
+
933
+ var x = this.position.x + layoutSize[ xPadding ];
934
+ // set in percentage or pixels
935
+ style[ xProperty ] = this.getXValue( x );
936
+ // reset other property
937
+ style[ xResetProperty ] = '';
938
+
939
+ // y
940
+ var yPadding = isOriginTop ? 'paddingTop' : 'paddingBottom';
941
+ var yProperty = isOriginTop ? 'top' : 'bottom';
942
+ var yResetProperty = isOriginTop ? 'bottom' : 'top';
943
+
944
+ var y = this.position.y + layoutSize[ yPadding ];
945
+ // set in percentage or pixels
946
+ style[ yProperty ] = this.getYValue( y );
947
+ // reset other property
948
+ style[ yResetProperty ] = '';
1331
949
 
1332
950
  this.css( style );
1333
951
  this.emitEvent( 'layout', [ this ] );
1334
952
  };
1335
953
 
954
+ proto.getXValue = function( x ) {
955
+ var isHorizontal = this.layout._getOption('horizontal');
956
+ return this.layout.options.percentPosition && !isHorizontal ?
957
+ ( ( x / this.layout.size.width ) * 100 ) + '%' : x + 'px';
958
+ };
1336
959
 
1337
- // transform translate function
1338
- var translate = is3d ?
1339
- function( x, y ) {
1340
- return 'translate3d(' + x + 'px, ' + y + 'px, 0)';
1341
- } :
1342
- function( x, y ) {
1343
- return 'translate(' + x + 'px, ' + y + 'px)';
1344
- };
1345
-
960
+ proto.getYValue = function( y ) {
961
+ var isHorizontal = this.layout._getOption('horizontal');
962
+ return this.layout.options.percentPosition && isHorizontal ?
963
+ ( ( y / this.layout.size.height ) * 100 ) + '%' : y + 'px';
964
+ };
1346
965
 
1347
- Item.prototype._transitionTo = function( x, y ) {
966
+ proto._transitionTo = function( x, y ) {
1348
967
  this.getPosition();
1349
968
  // get current x & y from top/left
1350
969
  var curX = this.position.x;
@@ -1366,11 +985,7 @@ Item.prototype._transitionTo = function( x, y ) {
1366
985
  var transX = x - curX;
1367
986
  var transY = y - curY;
1368
987
  var transitionStyle = {};
1369
- // flip cooridinates if origin on right or bottom
1370
- var layoutOptions = this.layout.options;
1371
- transX = layoutOptions.isOriginLeft ? transX : -transX;
1372
- transY = layoutOptions.isOriginTop ? transY : -transY;
1373
- transitionStyle.transform = translate( transX, transY );
988
+ transitionStyle.transform = this.getTranslate( transX, transY );
1374
989
 
1375
990
  this.transition({
1376
991
  to: transitionStyle,
@@ -1381,17 +996,24 @@ Item.prototype._transitionTo = function( x, y ) {
1381
996
  });
1382
997
  };
1383
998
 
999
+ proto.getTranslate = function( x, y ) {
1000
+ // flip cooridinates if origin on right or bottom
1001
+ var isOriginLeft = this.layout._getOption('originLeft');
1002
+ var isOriginTop = this.layout._getOption('originTop');
1003
+ x = isOriginLeft ? x : -x;
1004
+ y = isOriginTop ? y : -y;
1005
+ return 'translate3d(' + x + 'px, ' + y + 'px, 0)';
1006
+ };
1007
+
1384
1008
  // non transition + transform support
1385
- Item.prototype.goTo = function( x, y ) {
1009
+ proto.goTo = function( x, y ) {
1386
1010
  this.setPosition( x, y );
1387
1011
  this.layoutPosition();
1388
1012
  };
1389
1013
 
1390
- // use transition and transforms if supported
1391
- Item.prototype.moveTo = supportsCSS3 ?
1392
- Item.prototype._transitionTo : Item.prototype.goTo;
1014
+ proto.moveTo = proto._transitionTo;
1393
1015
 
1394
- Item.prototype.setPosition = function( x, y ) {
1016
+ proto.setPosition = function( x, y ) {
1395
1017
  this.position.x = parseInt( x, 10 );
1396
1018
  this.position.y = parseInt( y, 10 );
1397
1019
  };
@@ -1404,7 +1026,7 @@ Item.prototype.setPosition = function( x, y ) {
1404
1026
  */
1405
1027
 
1406
1028
  // non transition, just trigger callback
1407
- Item.prototype._nonTransition = function( args ) {
1029
+ proto._nonTransition = function( args ) {
1408
1030
  this.css( args.to );
1409
1031
  if ( args.isCleaning ) {
1410
1032
  this._removeStyles( args.to );
@@ -1422,7 +1044,7 @@ Item.prototype._nonTransition = function( args ) {
1422
1044
  * @param {Boolean} isCleaning - removes transition styles after transition
1423
1045
  * @param {Function} onTransitionEnd - callback
1424
1046
  */
1425
- Item.prototype._transition = function( args ) {
1047
+ proto._transition = function( args ) {
1426
1048
  // redirect to nonTransition if no transition duration
1427
1049
  if ( !parseFloat( this.layout.options.transitionDuration ) ) {
1428
1050
  this._nonTransition( args );
@@ -1460,54 +1082,60 @@ Item.prototype._transition = function( args ) {
1460
1082
 
1461
1083
  };
1462
1084
 
1463
- var itemTransitionProperties = transformProperty && ( toDash( transformProperty ) +
1464
- ',opacity' );
1085
+ // dash before all cap letters, including first for
1086
+ // WebkitTransform => -webkit-transform
1087
+ function toDashedAll( str ) {
1088
+ return str.replace( /([A-Z])/g, function( $1 ) {
1089
+ return '-' + $1.toLowerCase();
1090
+ });
1091
+ }
1092
+
1093
+ var transitionProps = 'opacity,' +
1094
+ toDashedAll( vendorProperties.transform || 'transform' );
1465
1095
 
1466
- Item.prototype.enableTransition = function(/* style */) {
1467
- // only enable if not already transitioning
1468
- // bug in IE10 were re-setting transition style will prevent
1469
- // transitionend event from triggering
1096
+ proto.enableTransition = function(/* style */) {
1097
+ // HACK changing transitionProperty during a transition
1098
+ // will cause transition to jump
1470
1099
  if ( this.isTransitioning ) {
1471
1100
  return;
1472
1101
  }
1473
1102
 
1474
- // make transition: foo, bar, baz from style object
1475
- // TODO uncomment this bit when IE10 bug is resolved
1476
- // var transitionValue = [];
1103
+ // make `transition: foo, bar, baz` from style object
1104
+ // HACK un-comment this when enableTransition can work
1105
+ // while a transition is happening
1106
+ // var transitionValues = [];
1477
1107
  // for ( var prop in style ) {
1478
1108
  // // dash-ify camelCased properties like WebkitTransition
1479
- // transitionValue.push( toDash( prop ) );
1109
+ // prop = vendorProperties[ prop ] || prop;
1110
+ // transitionValues.push( toDashedAll( prop ) );
1480
1111
  // }
1481
1112
  // enable transition styles
1482
- // HACK always enable transform,opacity for IE10
1483
1113
  this.css({
1484
- transitionProperty: itemTransitionProperties,
1114
+ transitionProperty: transitionProps,
1485
1115
  transitionDuration: this.layout.options.transitionDuration
1486
1116
  });
1487
1117
  // listen for transition end event
1488
1118
  this.element.addEventListener( transitionEndEvent, this, false );
1489
1119
  };
1490
1120
 
1491
- Item.prototype.transition = Item.prototype[ transitionProperty ? '_transition' : '_nonTransition' ];
1121
+ proto.transition = Item.prototype[ transitionProperty ? '_transition' : '_nonTransition' ];
1492
1122
 
1493
1123
  // ----- events ----- //
1494
1124
 
1495
- Item.prototype.onwebkitTransitionEnd = function( event ) {
1125
+ proto.onwebkitTransitionEnd = function( event ) {
1496
1126
  this.ontransitionend( event );
1497
1127
  };
1498
1128
 
1499
- Item.prototype.onotransitionend = function( event ) {
1129
+ proto.onotransitionend = function( event ) {
1500
1130
  this.ontransitionend( event );
1501
1131
  };
1502
1132
 
1503
1133
  // properties that I munge to make my life easier
1504
1134
  var dashedVendorProperties = {
1505
- '-webkit-transform': 'transform',
1506
- '-moz-transform': 'transform',
1507
- '-o-transform': 'transform'
1135
+ '-webkit-transform': 'transform'
1508
1136
  };
1509
1137
 
1510
- Item.prototype.ontransitionend = function( event ) {
1138
+ proto.ontransitionend = function( event ) {
1511
1139
  // disregard bubbled events from children
1512
1140
  if ( event.target !== this.element ) {
1513
1141
  return;
@@ -1539,7 +1167,7 @@ Item.prototype.ontransitionend = function( event ) {
1539
1167
  this.emitEvent( 'transitionEnd', [ this ] );
1540
1168
  };
1541
1169
 
1542
- Item.prototype.disableTransition = function() {
1170
+ proto.disableTransition = function() {
1543
1171
  this.removeTransitionStyles();
1544
1172
  this.element.removeEventListener( transitionEndEvent, this, false );
1545
1173
  this.isTransitioning = false;
@@ -1549,7 +1177,7 @@ Item.prototype.disableTransition = function() {
1549
1177
  * removes style property from element
1550
1178
  * @param {Object} style
1551
1179
  **/
1552
- Item.prototype._removeStyles = function( style ) {
1180
+ proto._removeStyles = function( style ) {
1553
1181
  // clean up transition styles
1554
1182
  var cleanStyle = {};
1555
1183
  for ( var prop in style ) {
@@ -1563,7 +1191,7 @@ var cleanTransitionStyle = {
1563
1191
  transitionDuration: ''
1564
1192
  };
1565
1193
 
1566
- Item.prototype.removeTransitionStyles = function() {
1194
+ proto.removeTransitionStyles = function() {
1567
1195
  // remove transition
1568
1196
  this.css( cleanTransitionStyle );
1569
1197
  };
@@ -1571,12 +1199,14 @@ Item.prototype.removeTransitionStyles = function() {
1571
1199
  // ----- show/hide/remove ----- //
1572
1200
 
1573
1201
  // remove element from DOM
1574
- Item.prototype.removeElem = function() {
1202
+ proto.removeElem = function() {
1575
1203
  this.element.parentNode.removeChild( this.element );
1204
+ // remove display: none
1205
+ this.css({ display: '' });
1576
1206
  this.emitEvent( 'remove', [ this ] );
1577
1207
  };
1578
1208
 
1579
- Item.prototype.remove = function() {
1209
+ proto.remove = function() {
1580
1210
  // just remove element if no transition support or no transition
1581
1211
  if ( !transitionProperty || !parseFloat( this.layout.options.transitionDuration ) ) {
1582
1212
  this.removeElem();
@@ -1584,52 +1214,87 @@ Item.prototype.remove = function() {
1584
1214
  }
1585
1215
 
1586
1216
  // start transition
1587
- var _this = this;
1588
- this.on( 'transitionEnd', function() {
1589
- _this.removeElem();
1590
- return true; // bind once
1217
+ this.once( 'transitionEnd', function() {
1218
+ this.removeElem();
1591
1219
  });
1592
1220
  this.hide();
1593
1221
  };
1594
1222
 
1595
- Item.prototype.reveal = function() {
1223
+ proto.reveal = function() {
1596
1224
  delete this.isHidden;
1597
1225
  // remove display: none
1598
1226
  this.css({ display: '' });
1599
1227
 
1600
1228
  var options = this.layout.options;
1229
+
1230
+ var onTransitionEnd = {};
1231
+ var transitionEndProperty = this.getHideRevealTransitionEndProperty('visibleStyle');
1232
+ onTransitionEnd[ transitionEndProperty ] = this.onRevealTransitionEnd;
1233
+
1601
1234
  this.transition({
1602
1235
  from: options.hiddenStyle,
1603
1236
  to: options.visibleStyle,
1604
- isCleaning: true
1237
+ isCleaning: true,
1238
+ onTransitionEnd: onTransitionEnd
1605
1239
  });
1606
1240
  };
1607
1241
 
1608
- Item.prototype.hide = function() {
1242
+ proto.onRevealTransitionEnd = function() {
1243
+ // check if still visible
1244
+ // during transition, item may have been hidden
1245
+ if ( !this.isHidden ) {
1246
+ this.emitEvent('reveal');
1247
+ }
1248
+ };
1249
+
1250
+ /**
1251
+ * get style property use for hide/reveal transition end
1252
+ * @param {String} styleProperty - hiddenStyle/visibleStyle
1253
+ * @returns {String}
1254
+ */
1255
+ proto.getHideRevealTransitionEndProperty = function( styleProperty ) {
1256
+ var optionStyle = this.layout.options[ styleProperty ];
1257
+ // use opacity
1258
+ if ( optionStyle.opacity ) {
1259
+ return 'opacity';
1260
+ }
1261
+ // get first property
1262
+ for ( var prop in optionStyle ) {
1263
+ return prop;
1264
+ }
1265
+ };
1266
+
1267
+ proto.hide = function() {
1609
1268
  // set flag
1610
1269
  this.isHidden = true;
1611
1270
  // remove display: none
1612
1271
  this.css({ display: '' });
1613
1272
 
1614
1273
  var options = this.layout.options;
1274
+
1275
+ var onTransitionEnd = {};
1276
+ var transitionEndProperty = this.getHideRevealTransitionEndProperty('hiddenStyle');
1277
+ onTransitionEnd[ transitionEndProperty ] = this.onHideTransitionEnd;
1278
+
1615
1279
  this.transition({
1616
1280
  from: options.visibleStyle,
1617
1281
  to: options.hiddenStyle,
1618
1282
  // keep hidden stuff hidden
1619
1283
  isCleaning: true,
1620
- onTransitionEnd: {
1621
- opacity: function() {
1622
- // check if still hidden
1623
- // during transition, item may have been un-hidden
1624
- if ( this.isHidden ) {
1625
- this.css({ display: 'none' });
1626
- }
1627
- }
1628
- }
1284
+ onTransitionEnd: onTransitionEnd
1629
1285
  });
1630
1286
  };
1631
1287
 
1632
- Item.prototype.destroy = function() {
1288
+ proto.onHideTransitionEnd = function() {
1289
+ // check if still hidden
1290
+ // during transition, item may have been un-hidden
1291
+ if ( this.isHidden ) {
1292
+ this.css({ display: 'none' });
1293
+ this.emitEvent('hide');
1294
+ }
1295
+ };
1296
+
1297
+ proto.destroy = function() {
1633
1298
  this.css({
1634
1299
  position: '',
1635
1300
  left: '',
@@ -1643,121 +1308,59 @@ Item.prototype.destroy = function() {
1643
1308
 
1644
1309
  return Item;
1645
1310
 
1646
- }
1647
-
1648
- // -------------------------- transport -------------------------- //
1649
-
1650
- if ( typeof define === 'function' && define.amd ) {
1651
- // AMD
1652
- define( 'outlayer/item',[
1653
- 'eventEmitter/EventEmitter',
1654
- 'get-size/get-size',
1655
- 'get-style-property/get-style-property'
1656
- ],
1657
- outlayerItemDefinition );
1658
- } else {
1659
- // browser global
1660
- window.Outlayer = {};
1661
- window.Outlayer.Item = outlayerItemDefinition(
1662
- window.EventEmitter,
1663
- window.getSize,
1664
- window.getStyleProperty
1665
- );
1666
- }
1667
-
1668
- })( window );
1311
+ }));
1669
1312
 
1670
1313
  /*!
1671
- * Outlayer v1.2.0
1314
+ * Outlayer v2.0.0
1672
1315
  * the brains and guts of a layout library
1673
1316
  * MIT license
1674
1317
  */
1675
1318
 
1676
- ( function( window ) {
1677
-
1319
+ ( function( window, factory ) {
1320
+ 'use strict';
1321
+ // universal module definition
1322
+ /* jshint strict: false */ /* globals define, module, require */
1323
+ if ( typeof define == 'function' && define.amd ) {
1324
+ // AMD - RequireJS
1325
+ define( 'outlayer/outlayer',[
1326
+ 'ev-emitter/ev-emitter',
1327
+ 'get-size/get-size',
1328
+ 'fizzy-ui-utils/utils',
1329
+ './item'
1330
+ ],
1331
+ function( EvEmitter, getSize, utils, Item ) {
1332
+ return factory( window, EvEmitter, getSize, utils, Item);
1333
+ }
1334
+ );
1335
+ } else if ( typeof module == 'object' && module.exports ) {
1336
+ // CommonJS - Browserify, Webpack
1337
+ module.exports = factory(
1338
+ window,
1339
+ require('ev-emitter'),
1340
+ require('get-size'),
1341
+ require('fizzy-ui-utils'),
1342
+ require('./item')
1343
+ );
1344
+ } else {
1345
+ // browser global
1346
+ window.Outlayer = factory(
1347
+ window,
1348
+ window.EvEmitter,
1349
+ window.getSize,
1350
+ window.fizzyUIUtils,
1351
+ window.Outlayer.Item
1352
+ );
1353
+ }
1678
1354
 
1355
+ }( window, function factory( window, EvEmitter, getSize, utils, Item ) {
1356
+ 'use strict';
1679
1357
 
1680
1358
  // ----- vars ----- //
1681
1359
 
1682
- var document = window.document;
1683
1360
  var console = window.console;
1684
1361
  var jQuery = window.jQuery;
1685
-
1686
1362
  var noop = function() {};
1687
1363
 
1688
- // -------------------------- helpers -------------------------- //
1689
-
1690
- // extend objects
1691
- function extend( a, b ) {
1692
- for ( var prop in b ) {
1693
- a[ prop ] = b[ prop ];
1694
- }
1695
- return a;
1696
- }
1697
-
1698
-
1699
- var objToString = Object.prototype.toString;
1700
- function isArray( obj ) {
1701
- return objToString.call( obj ) === '[object Array]';
1702
- }
1703
-
1704
- // turn element or nodeList into an array
1705
- function makeArray( obj ) {
1706
- var ary = [];
1707
- if ( isArray( obj ) ) {
1708
- // use object if already an array
1709
- ary = obj;
1710
- } else if ( obj && typeof obj.length === 'number' ) {
1711
- // convert nodeList to array
1712
- for ( var i=0, len = obj.length; i < len; i++ ) {
1713
- ary.push( obj[i] );
1714
- }
1715
- } else {
1716
- // array of single index
1717
- ary.push( obj );
1718
- }
1719
- return ary;
1720
- }
1721
-
1722
- // http://stackoverflow.com/a/384380/182183
1723
- var isElement = ( typeof HTMLElement === 'object' ) ?
1724
- function isElementDOM2( obj ) {
1725
- return obj instanceof HTMLElement;
1726
- } :
1727
- function isElementQuirky( obj ) {
1728
- return obj && typeof obj === 'object' &&
1729
- obj.nodeType === 1 && typeof obj.nodeName === 'string';
1730
- };
1731
-
1732
- // index of helper cause IE8
1733
- var indexOf = Array.prototype.indexOf ? function( ary, obj ) {
1734
- return ary.indexOf( obj );
1735
- } : function( ary, obj ) {
1736
- for ( var i=0, len = ary.length; i < len; i++ ) {
1737
- if ( ary[i] === obj ) {
1738
- return i;
1739
- }
1740
- }
1741
- return -1;
1742
- };
1743
-
1744
- function removeFrom( obj, ary ) {
1745
- var index = indexOf( ary, obj );
1746
- if ( index !== -1 ) {
1747
- ary.splice( index, 1 );
1748
- }
1749
- }
1750
-
1751
- // http://jamesroberts.name/blog/2010/02/22/string-functions-for-javascript-trim-to-camel-case-to-dashed-and-to-underscore/
1752
- function toDashed( str ) {
1753
- return str.replace( /(.)([A-Z])/g, function( match, $1, $2 ) {
1754
- return $1 + '-' + $2;
1755
- }).toLowerCase();
1756
- }
1757
-
1758
-
1759
- function outlayerDefinition( eventie, docReady, EventEmitter, getSize, matchesSelector, Item ) {
1760
-
1761
1364
  // -------------------------- Outlayer -------------------------- //
1762
1365
 
1763
1366
  // globally unique identifiers
@@ -1772,23 +1375,22 @@ var instances = {};
1772
1375
  * @constructor
1773
1376
  */
1774
1377
  function Outlayer( element, options ) {
1775
- // use element as selector string
1776
- if ( typeof element === 'string' ) {
1777
- element = document.querySelector( element );
1778
- }
1779
-
1780
- // bail out if not proper element
1781
- if ( !element || !isElement( element ) ) {
1378
+ var queryElement = utils.getQueryElement( element );
1379
+ if ( !queryElement ) {
1782
1380
  if ( console ) {
1783
- console.error( 'Bad ' + this.constructor.namespace + ' element: ' + element );
1381
+ console.error( 'Bad element for ' + this.constructor.namespace +
1382
+ ': ' + ( queryElement || element ) );
1784
1383
  }
1785
1384
  return;
1786
1385
  }
1787
-
1788
- this.element = element;
1386
+ this.element = queryElement;
1387
+ // add jQuery
1388
+ if ( jQuery ) {
1389
+ this.$element = jQuery( this.element );
1390
+ }
1789
1391
 
1790
1392
  // options
1791
- this.options = extend( {}, this.constructor.defaults );
1393
+ this.options = utils.extend( {}, this.constructor.defaults );
1792
1394
  this.option( options );
1793
1395
 
1794
1396
  // add id for Outlayer.getFromElement
@@ -1799,7 +1401,8 @@ function Outlayer( element, options ) {
1799
1401
  // kick it off
1800
1402
  this._create();
1801
1403
 
1802
- if ( this.options.isInitLayout ) {
1404
+ var isInitLayout = this._getOption('initLayout');
1405
+ if ( isInitLayout ) {
1803
1406
  this.layout();
1804
1407
  }
1805
1408
  }
@@ -1813,11 +1416,11 @@ Outlayer.defaults = {
1813
1416
  containerStyle: {
1814
1417
  position: 'relative'
1815
1418
  },
1816
- isInitLayout: true,
1817
- isOriginLeft: true,
1818
- isOriginTop: true,
1819
- isResizeBound: true,
1820
- isResizingContainer: true,
1419
+ initLayout: true,
1420
+ originLeft: true,
1421
+ originTop: true,
1422
+ resize: true,
1423
+ resizeContainer: true,
1821
1424
  // item options
1822
1425
  transitionDuration: '0.4s',
1823
1426
  hiddenStyle: {
@@ -1830,34 +1433,56 @@ Outlayer.defaults = {
1830
1433
  }
1831
1434
  };
1832
1435
 
1833
- // inherit EventEmitter
1834
- extend( Outlayer.prototype, EventEmitter.prototype );
1436
+ var proto = Outlayer.prototype;
1437
+ // inherit EvEmitter
1438
+ utils.extend( proto, EvEmitter.prototype );
1835
1439
 
1836
1440
  /**
1837
1441
  * set options
1838
1442
  * @param {Object} opts
1839
1443
  */
1840
- Outlayer.prototype.option = function( opts ) {
1841
- extend( this.options, opts );
1444
+ proto.option = function( opts ) {
1445
+ utils.extend( this.options, opts );
1446
+ };
1447
+
1448
+ /**
1449
+ * get backwards compatible option value, check old name
1450
+ */
1451
+ proto._getOption = function( option ) {
1452
+ var oldOption = this.constructor.compatOptions[ option ];
1453
+ return oldOption && this.options[ oldOption ] !== undefined ?
1454
+ this.options[ oldOption ] : this.options[ option ];
1455
+ };
1456
+
1457
+ Outlayer.compatOptions = {
1458
+ // currentName: oldName
1459
+ initLayout: 'isInitLayout',
1460
+ horizontal: 'isHorizontal',
1461
+ layoutInstant: 'isLayoutInstant',
1462
+ originLeft: 'isOriginLeft',
1463
+ originTop: 'isOriginTop',
1464
+ resize: 'isResizeBound',
1465
+ resizeContainer: 'isResizingContainer'
1842
1466
  };
1843
1467
 
1844
- Outlayer.prototype._create = function() {
1468
+ proto._create = function() {
1845
1469
  // get items from children
1846
1470
  this.reloadItems();
1847
1471
  // elements that affect layout, but are not laid out
1848
1472
  this.stamps = [];
1849
1473
  this.stamp( this.options.stamp );
1850
1474
  // set container style
1851
- extend( this.element.style, this.options.containerStyle );
1475
+ utils.extend( this.element.style, this.options.containerStyle );
1852
1476
 
1853
1477
  // bind resize method
1854
- if ( this.options.isResizeBound ) {
1478
+ var canBindResize = this._getOption('resize');
1479
+ if ( canBindResize ) {
1855
1480
  this.bindResize();
1856
1481
  }
1857
1482
  };
1858
1483
 
1859
1484
  // goes through all children again and gets bricks in proper order
1860
- Outlayer.prototype.reloadItems = function() {
1485
+ proto.reloadItems = function() {
1861
1486
  // collection of item elements
1862
1487
  this.items = this._itemize( this.element.children );
1863
1488
  };
@@ -1868,14 +1493,14 @@ Outlayer.prototype.reloadItems = function() {
1868
1493
  * @param {Array or NodeList or HTMLElement} elems
1869
1494
  * @returns {Array} items - collection of new Outlayer Items
1870
1495
  */
1871
- Outlayer.prototype._itemize = function( elems ) {
1496
+ proto._itemize = function( elems ) {
1872
1497
 
1873
1498
  var itemElems = this._filterFindItemElements( elems );
1874
1499
  var Item = this.constructor.Item;
1875
1500
 
1876
1501
  // create new Outlayer Items for collection
1877
1502
  var items = [];
1878
- for ( var i=0, len = itemElems.length; i < len; i++ ) {
1503
+ for ( var i=0; i < itemElems.length; i++ ) {
1879
1504
  var elem = itemElems[i];
1880
1505
  var item = new Item( elem, this );
1881
1506
  items.push( item );
@@ -1889,48 +1514,18 @@ Outlayer.prototype._itemize = function( elems ) {
1889
1514
  * @param {Array or NodeList or HTMLElement} elems
1890
1515
  * @returns {Array} items - item elements
1891
1516
  */
1892
- Outlayer.prototype._filterFindItemElements = function( elems ) {
1893
- // make array of elems
1894
- elems = makeArray( elems );
1895
- var itemSelector = this.options.itemSelector;
1896
- var itemElems = [];
1897
-
1898
- for ( var i=0, len = elems.length; i < len; i++ ) {
1899
- var elem = elems[i];
1900
- // check that elem is an actual element
1901
- if ( !isElement( elem ) ) {
1902
- continue;
1903
- }
1904
- // filter & find items if we have an item selector
1905
- if ( itemSelector ) {
1906
- // filter siblings
1907
- if ( matchesSelector( elem, itemSelector ) ) {
1908
- itemElems.push( elem );
1909
- }
1910
- // find children
1911
- var childElems = elem.querySelectorAll( itemSelector );
1912
- // concat childElems to filterFound array
1913
- for ( var j=0, jLen = childElems.length; j < jLen; j++ ) {
1914
- itemElems.push( childElems[j] );
1915
- }
1916
- } else {
1917
- itemElems.push( elem );
1918
- }
1919
- }
1920
-
1921
- return itemElems;
1517
+ proto._filterFindItemElements = function( elems ) {
1518
+ return utils.filterFindElements( elems, this.options.itemSelector );
1922
1519
  };
1923
1520
 
1924
1521
  /**
1925
1522
  * getter method for getting item elements
1926
1523
  * @returns {Array} elems - collection of item elements
1927
1524
  */
1928
- Outlayer.prototype.getItemElements = function() {
1929
- var elems = [];
1930
- for ( var i=0, len = this.items.length; i < len; i++ ) {
1931
- elems.push( this.items[i].element );
1932
- }
1933
- return elems;
1525
+ proto.getItemElements = function() {
1526
+ return this.items.map( function( item ) {
1527
+ return item.element;
1528
+ });
1934
1529
  };
1935
1530
 
1936
1531
  // ----- init & layout ----- //
@@ -1938,13 +1533,14 @@ Outlayer.prototype.getItemElements = function() {
1938
1533
  /**
1939
1534
  * lays out all items
1940
1535
  */
1941
- Outlayer.prototype.layout = function() {
1536
+ proto.layout = function() {
1942
1537
  this._resetLayout();
1943
1538
  this._manageStamps();
1944
1539
 
1945
1540
  // don't animate first layout
1946
- var isInstant = this.options.isLayoutInstant !== undefined ?
1947
- this.options.isLayoutInstant : !this._isLayoutInited;
1541
+ var layoutInstant = this._getOption('layoutInstant');
1542
+ var isInstant = layoutInstant !== undefined ?
1543
+ layoutInstant : !this._isLayoutInited;
1948
1544
  this.layoutItems( this.items, isInstant );
1949
1545
 
1950
1546
  // flag for initalized
@@ -1952,17 +1548,17 @@ Outlayer.prototype.layout = function() {
1952
1548
  };
1953
1549
 
1954
1550
  // _init is alias for layout
1955
- Outlayer.prototype._init = Outlayer.prototype.layout;
1551
+ proto._init = proto.layout;
1956
1552
 
1957
1553
  /**
1958
1554
  * logic before any new layout
1959
1555
  */
1960
- Outlayer.prototype._resetLayout = function() {
1556
+ proto._resetLayout = function() {
1961
1557
  this.getSize();
1962
1558
  };
1963
1559
 
1964
1560
 
1965
- Outlayer.prototype.getSize = function() {
1561
+ proto.getSize = function() {
1966
1562
  this.size = getSize( this.element );
1967
1563
  };
1968
1564
 
@@ -1976,7 +1572,7 @@ Outlayer.prototype.getSize = function() {
1976
1572
  * @param {String} size - width or height
1977
1573
  * @private
1978
1574
  */
1979
- Outlayer.prototype._getMeasurement = function( measurement, size ) {
1575
+ proto._getMeasurement = function( measurement, size ) {
1980
1576
  var option = this.options[ measurement ];
1981
1577
  var elem;
1982
1578
  if ( !option ) {
@@ -1984,9 +1580,9 @@ Outlayer.prototype._getMeasurement = function( measurement, size ) {
1984
1580
  this[ measurement ] = 0;
1985
1581
  } else {
1986
1582
  // use option as an element
1987
- if ( typeof option === 'string' ) {
1583
+ if ( typeof option == 'string' ) {
1988
1584
  elem = this.element.querySelector( option );
1989
- } else if ( isElement( option ) ) {
1585
+ } else if ( option instanceof HTMLElement ) {
1990
1586
  elem = option;
1991
1587
  }
1992
1588
  // use size of element, if element
@@ -1998,7 +1594,7 @@ Outlayer.prototype._getMeasurement = function( measurement, size ) {
1998
1594
  * layout a collection of item elements
1999
1595
  * @api public
2000
1596
  */
2001
- Outlayer.prototype.layoutItems = function( items, isInstant ) {
1597
+ proto.layoutItems = function( items, isInstant ) {
2002
1598
  items = this._getItemsForLayout( items );
2003
1599
 
2004
1600
  this._layoutItems( items, isInstant );
@@ -2012,15 +1608,10 @@ Outlayer.prototype.layoutItems = function( items, isInstant ) {
2012
1608
  * @param {Array} items
2013
1609
  * @returns {Array} items
2014
1610
  */
2015
- Outlayer.prototype._getItemsForLayout = function( items ) {
2016
- var layoutItems = [];
2017
- for ( var i=0, len = items.length; i < len; i++ ) {
2018
- var item = items[i];
2019
- if ( !item.isIgnored ) {
2020
- layoutItems.push( item );
2021
- }
2022
- }
2023
- return layoutItems;
1611
+ proto._getItemsForLayout = function( items ) {
1612
+ return items.filter( function( item ) {
1613
+ return !item.isIgnored;
1614
+ });
2024
1615
  };
2025
1616
 
2026
1617
  /**
@@ -2028,32 +1619,24 @@ Outlayer.prototype._getItemsForLayout = function( items ) {
2028
1619
  * @param {Array} items
2029
1620
  * @param {Boolean} isInstant
2030
1621
  */
2031
- Outlayer.prototype._layoutItems = function( items, isInstant ) {
2032
- var _this = this;
2033
- function onItemsLayout() {
2034
- _this.emitEvent( 'layoutComplete', [ _this, items ] );
2035
- }
1622
+ proto._layoutItems = function( items, isInstant ) {
1623
+ this._emitCompleteOnItems( 'layout', items );
2036
1624
 
2037
1625
  if ( !items || !items.length ) {
2038
1626
  // no items, emit event with empty array
2039
- onItemsLayout();
2040
1627
  return;
2041
1628
  }
2042
1629
 
2043
- // emit layoutComplete when done
2044
- this._itemsOn( items, 'layout', onItemsLayout );
2045
-
2046
1630
  var queue = [];
2047
1631
 
2048
- for ( var i=0, len = items.length; i < len; i++ ) {
2049
- var item = items[i];
1632
+ items.forEach( function( item ) {
2050
1633
  // get x/y object from method
2051
1634
  var position = this._getItemLayoutPosition( item );
2052
1635
  // enqueue
2053
1636
  position.item = item;
2054
1637
  position.isInstant = isInstant || item.isLayoutInstant;
2055
1638
  queue.push( position );
2056
- }
1639
+ }, this );
2057
1640
 
2058
1641
  this._processLayoutQueue( queue );
2059
1642
  };
@@ -2063,7 +1646,7 @@ Outlayer.prototype._layoutItems = function( items, isInstant ) {
2063
1646
  * @param {Outlayer.Item} item
2064
1647
  * @returns {Object} x and y position
2065
1648
  */
2066
- Outlayer.prototype._getItemLayoutPosition = function( /* item */ ) {
1649
+ proto._getItemLayoutPosition = function( /* item */ ) {
2067
1650
  return {
2068
1651
  x: 0,
2069
1652
  y: 0
@@ -2076,11 +1659,10 @@ Outlayer.prototype._getItemLayoutPosition = function( /* item */ ) {
2076
1659
  * thx @paul_irish
2077
1660
  * @param {Array} queue
2078
1661
  */
2079
- Outlayer.prototype._processLayoutQueue = function( queue ) {
2080
- for ( var i=0, len = queue.length; i < len; i++ ) {
2081
- var obj = queue[i];
1662
+ proto._processLayoutQueue = function( queue ) {
1663
+ queue.forEach( function( obj ) {
2082
1664
  this._positionItem( obj.item, obj.x, obj.y, obj.isInstant );
2083
- }
1665
+ }, this );
2084
1666
  };
2085
1667
 
2086
1668
  /**
@@ -2090,7 +1672,7 @@ Outlayer.prototype._processLayoutQueue = function( queue ) {
2090
1672
  * @param {Number} y - vertical position
2091
1673
  * @param {Boolean} isInstant - disables transitions
2092
1674
  */
2093
- Outlayer.prototype._positionItem = function( item, x, y, isInstant ) {
1675
+ proto._positionItem = function( item, x, y, isInstant ) {
2094
1676
  if ( isInstant ) {
2095
1677
  // if not transition, just set CSS
2096
1678
  item.goTo( x, y );
@@ -2103,12 +1685,13 @@ Outlayer.prototype._positionItem = function( item, x, y, isInstant ) {
2103
1685
  * Any logic you want to do after each layout,
2104
1686
  * i.e. size the container
2105
1687
  */
2106
- Outlayer.prototype._postLayout = function() {
1688
+ proto._postLayout = function() {
2107
1689
  this.resizeContainer();
2108
1690
  };
2109
1691
 
2110
- Outlayer.prototype.resizeContainer = function() {
2111
- if ( !this.options.isResizingContainer ) {
1692
+ proto.resizeContainer = function() {
1693
+ var isResizingContainer = this._getOption('resizeContainer');
1694
+ if ( !isResizingContainer ) {
2112
1695
  return;
2113
1696
  }
2114
1697
  var size = this._getContainerSize();
@@ -2124,13 +1707,13 @@ Outlayer.prototype.resizeContainer = function() {
2124
1707
  * @param {Number} width
2125
1708
  * @param {Number} height
2126
1709
  */
2127
- Outlayer.prototype._getContainerSize = noop;
1710
+ proto._getContainerSize = noop;
2128
1711
 
2129
1712
  /**
2130
1713
  * @param {Number} measure - size of width or height
2131
1714
  * @param {Boolean} isWidth
2132
1715
  */
2133
- Outlayer.prototype._setContainerMeasure = function( measure, isWidth ) {
1716
+ proto._setContainerMeasure = function( measure, isWidth ) {
2134
1717
  if ( measure === undefined ) {
2135
1718
  return;
2136
1719
  }
@@ -2149,27 +1732,59 @@ Outlayer.prototype._setContainerMeasure = function( measure, isWidth ) {
2149
1732
  };
2150
1733
 
2151
1734
  /**
2152
- * trigger a callback for a collection of items events
2153
- * @param {Array} items - Outlayer.Items
1735
+ * emit eventComplete on a collection of items events
2154
1736
  * @param {String} eventName
2155
- * @param {Function} callback
1737
+ * @param {Array} items - Outlayer.Items
2156
1738
  */
2157
- Outlayer.prototype._itemsOn = function( items, eventName, callback ) {
2158
- var doneCount = 0;
2159
- var count = items.length;
2160
- // event callback
1739
+ proto._emitCompleteOnItems = function( eventName, items ) {
2161
1740
  var _this = this;
1741
+ function onComplete() {
1742
+ _this.dispatchEvent( eventName + 'Complete', null, [ items ] );
1743
+ }
1744
+
1745
+ var count = items.length;
1746
+ if ( !items || !count ) {
1747
+ onComplete();
1748
+ return;
1749
+ }
1750
+
1751
+ var doneCount = 0;
2162
1752
  function tick() {
2163
1753
  doneCount++;
2164
- if ( doneCount === count ) {
2165
- callback.call( _this );
1754
+ if ( doneCount == count ) {
1755
+ onComplete();
2166
1756
  }
2167
- return true; // bind once
2168
1757
  }
1758
+
2169
1759
  // bind callback
2170
- for ( var i=0, len = items.length; i < len; i++ ) {
2171
- var item = items[i];
2172
- item.on( eventName, tick );
1760
+ items.forEach( function( item ) {
1761
+ item.once( eventName, tick );
1762
+ });
1763
+ };
1764
+
1765
+ /**
1766
+ * emits events via EvEmitter and jQuery events
1767
+ * @param {String} type - name of event
1768
+ * @param {Event} event - original event
1769
+ * @param {Array} args - extra arguments
1770
+ */
1771
+ proto.dispatchEvent = function( type, event, args ) {
1772
+ // add original event to arguments
1773
+ var emitArgs = event ? [ event ].concat( args ) : args;
1774
+ this.emitEvent( type, emitArgs );
1775
+
1776
+ if ( jQuery ) {
1777
+ // set this.$element
1778
+ this.$element = this.$element || jQuery( this.element );
1779
+ if ( event ) {
1780
+ // create jQuery event
1781
+ var $event = jQuery.Event( event );
1782
+ $event.type = type;
1783
+ this.$element.trigger( $event, args );
1784
+ } else {
1785
+ // just trigger with type if no event available
1786
+ this.$element.trigger( type, args );
1787
+ }
2173
1788
  }
2174
1789
  };
2175
1790
 
@@ -2181,7 +1796,7 @@ Outlayer.prototype._itemsOn = function( items, eventName, callback ) {
2181
1796
  * ignored items do not get skipped in layout
2182
1797
  * @param {Element} elem
2183
1798
  */
2184
- Outlayer.prototype.ignore = function( elem ) {
1799
+ proto.ignore = function( elem ) {
2185
1800
  var item = this.getItem( elem );
2186
1801
  if ( item ) {
2187
1802
  item.isIgnored = true;
@@ -2192,7 +1807,7 @@ Outlayer.prototype.ignore = function( elem ) {
2192
1807
  * return item to layout collection
2193
1808
  * @param {Element} elem
2194
1809
  */
2195
- Outlayer.prototype.unignore = function( elem ) {
1810
+ proto.unignore = function( elem ) {
2196
1811
  var item = this.getItem( elem );
2197
1812
  if ( item ) {
2198
1813
  delete item.isIgnored;
@@ -2203,7 +1818,7 @@ Outlayer.prototype.unignore = function( elem ) {
2203
1818
  * adds elements to stamps
2204
1819
  * @param {NodeList, Array, Element, or String} elems
2205
1820
  */
2206
- Outlayer.prototype.stamp = function( elems ) {
1821
+ proto.stamp = function( elems ) {
2207
1822
  elems = this._find( elems );
2208
1823
  if ( !elems ) {
2209
1824
  return;
@@ -2211,29 +1826,24 @@ Outlayer.prototype.stamp = function( elems ) {
2211
1826
 
2212
1827
  this.stamps = this.stamps.concat( elems );
2213
1828
  // ignore
2214
- for ( var i=0, len = elems.length; i < len; i++ ) {
2215
- var elem = elems[i];
2216
- this.ignore( elem );
2217
- }
1829
+ elems.forEach( this.ignore, this );
2218
1830
  };
2219
1831
 
2220
1832
  /**
2221
1833
  * removes elements to stamps
2222
1834
  * @param {NodeList, Array, or Element} elems
2223
1835
  */
2224
- Outlayer.prototype.unstamp = function( elems ) {
1836
+ proto.unstamp = function( elems ) {
2225
1837
  elems = this._find( elems );
2226
1838
  if ( !elems ){
2227
1839
  return;
2228
1840
  }
2229
1841
 
2230
- for ( var i=0, len = elems.length; i < len; i++ ) {
2231
- var elem = elems[i];
1842
+ elems.forEach( function( elem ) {
2232
1843
  // filter out removed stamp elements
2233
- removeFrom( elem, this.stamps );
1844
+ utils.removeFrom( this.stamps, elem );
2234
1845
  this.unignore( elem );
2235
- }
2236
-
1846
+ }, this );
2237
1847
  };
2238
1848
 
2239
1849
  /**
@@ -2241,33 +1851,30 @@ Outlayer.prototype.unstamp = function( elems ) {
2241
1851
  * @param {NodeList, Array, Element, or String} elems
2242
1852
  * @returns {Array} elems
2243
1853
  */
2244
- Outlayer.prototype._find = function( elems ) {
1854
+ proto._find = function( elems ) {
2245
1855
  if ( !elems ) {
2246
1856
  return;
2247
1857
  }
2248
1858
  // if string, use argument as selector string
2249
- if ( typeof elems === 'string' ) {
1859
+ if ( typeof elems == 'string' ) {
2250
1860
  elems = this.element.querySelectorAll( elems );
2251
1861
  }
2252
- elems = makeArray( elems );
1862
+ elems = utils.makeArray( elems );
2253
1863
  return elems;
2254
1864
  };
2255
1865
 
2256
- Outlayer.prototype._manageStamps = function() {
1866
+ proto._manageStamps = function() {
2257
1867
  if ( !this.stamps || !this.stamps.length ) {
2258
1868
  return;
2259
1869
  }
2260
1870
 
2261
1871
  this._getBoundingRect();
2262
1872
 
2263
- for ( var i=0, len = this.stamps.length; i < len; i++ ) {
2264
- var stamp = this.stamps[i];
2265
- this._manageStamp( stamp );
2266
- }
1873
+ this.stamps.forEach( this._manageStamp, this );
2267
1874
  };
2268
1875
 
2269
1876
  // update boundingLeft / Top
2270
- Outlayer.prototype._getBoundingRect = function() {
1877
+ proto._getBoundingRect = function() {
2271
1878
  // get bounding rect for container element
2272
1879
  var boundingRect = this.element.getBoundingClientRect();
2273
1880
  var size = this.size;
@@ -2282,14 +1889,14 @@ Outlayer.prototype._getBoundingRect = function() {
2282
1889
  /**
2283
1890
  * @param {Element} stamp
2284
1891
  **/
2285
- Outlayer.prototype._manageStamp = noop;
1892
+ proto._manageStamp = noop;
2286
1893
 
2287
1894
  /**
2288
1895
  * get x/y position of element relative to container element
2289
1896
  * @param {Element} elem
2290
1897
  * @returns {Object} offset - has left, top, right, bottom
2291
1898
  */
2292
- Outlayer.prototype._getElementOffset = function( elem ) {
1899
+ proto._getElementOffset = function( elem ) {
2293
1900
  var boundingRect = elem.getBoundingClientRect();
2294
1901
  var thisRect = this._boundingRect;
2295
1902
  var size = getSize( elem );
@@ -2306,58 +1913,33 @@ Outlayer.prototype._getElementOffset = function( elem ) {
2306
1913
 
2307
1914
  // enable event handlers for listeners
2308
1915
  // i.e. resize -> onresize
2309
- Outlayer.prototype.handleEvent = function( event ) {
2310
- var method = 'on' + event.type;
2311
- if ( this[ method ] ) {
2312
- this[ method ]( event );
2313
- }
2314
- };
1916
+ proto.handleEvent = utils.handleEvent;
2315
1917
 
2316
1918
  /**
2317
1919
  * Bind layout to window resizing
2318
1920
  */
2319
- Outlayer.prototype.bindResize = function() {
2320
- // bind just one listener
2321
- if ( this.isResizeBound ) {
2322
- return;
2323
- }
2324
- eventie.bind( window, 'resize', this );
1921
+ proto.bindResize = function() {
1922
+ window.addEventListener( 'resize', this );
2325
1923
  this.isResizeBound = true;
2326
1924
  };
2327
1925
 
2328
1926
  /**
2329
1927
  * Unbind layout to window resizing
2330
1928
  */
2331
- Outlayer.prototype.unbindResize = function() {
2332
- if ( this.isResizeBound ) {
2333
- eventie.unbind( window, 'resize', this );
2334
- }
1929
+ proto.unbindResize = function() {
1930
+ window.removeEventListener( 'resize', this );
2335
1931
  this.isResizeBound = false;
2336
1932
  };
2337
1933
 
2338
- // original debounce by John Hann
2339
- // http://unscriptable.com/index.php/2009/03/20/debouncing-javascript-methods/
2340
-
2341
- // this fires every resize
2342
- Outlayer.prototype.onresize = function() {
2343
- if ( this.resizeTimeout ) {
2344
- clearTimeout( this.resizeTimeout );
2345
- }
2346
-
2347
- var _this = this;
2348
- function delayed() {
2349
- _this.resize();
2350
- delete _this.resizeTimeout;
2351
- }
2352
-
2353
- this.resizeTimeout = setTimeout( delayed, 100 );
1934
+ proto.onresize = function() {
1935
+ this.resize();
2354
1936
  };
2355
1937
 
2356
- // debounced, layout on resize
2357
- Outlayer.prototype.resize = function() {
1938
+ utils.debounceMethod( Outlayer, 'onresize', 100 );
1939
+
1940
+ proto.resize = function() {
2358
1941
  // don't trigger if size did not change
2359
1942
  // or if resize was unbound. See #9
2360
-
2361
1943
  if ( !this.isResizeBound || !this.needsResizeLayout() ) {
2362
1944
  return;
2363
1945
  }
@@ -2369,7 +1951,7 @@ Outlayer.prototype.resize = function() {
2369
1951
  * check if layout is needed post layout
2370
1952
  * @returns Boolean
2371
1953
  */
2372
- Outlayer.prototype.needsResizeLayout = function() {
1954
+ proto.needsResizeLayout = function() {
2373
1955
  var size = getSize( this.element );
2374
1956
  // check that this.size and size are there
2375
1957
  // IE8 triggers resize on body size change, so they might not be
@@ -2384,7 +1966,7 @@ Outlayer.prototype.needsResizeLayout = function() {
2384
1966
  * @param {Array or NodeList or Element} elems
2385
1967
  * @returns {Array} items - Outlayer.Items
2386
1968
  **/
2387
- Outlayer.prototype.addItems = function( elems ) {
1969
+ proto.addItems = function( elems ) {
2388
1970
  var items = this._itemize( elems );
2389
1971
  // add items to collection
2390
1972
  if ( items.length ) {
@@ -2397,7 +1979,7 @@ Outlayer.prototype.addItems = function( elems ) {
2397
1979
  * Layout newly-appended item elements
2398
1980
  * @param {Array or NodeList or Element} elems
2399
1981
  */
2400
- Outlayer.prototype.appended = function( elems ) {
1982
+ proto.appended = function( elems ) {
2401
1983
  var items = this.addItems( elems );
2402
1984
  if ( !items.length ) {
2403
1985
  return;
@@ -2411,7 +1993,7 @@ Outlayer.prototype.appended = function( elems ) {
2411
1993
  * Layout prepended elements
2412
1994
  * @param {Array or NodeList or Element} elems
2413
1995
  */
2414
- Outlayer.prototype.prepended = function( elems ) {
1996
+ proto.prepended = function( elems ) {
2415
1997
  var items = this._itemize( elems );
2416
1998
  if ( !items.length ) {
2417
1999
  return;
@@ -2433,30 +2015,46 @@ Outlayer.prototype.prepended = function( elems ) {
2433
2015
  * reveal a collection of items
2434
2016
  * @param {Array of Outlayer.Items} items
2435
2017
  */
2436
- Outlayer.prototype.reveal = function( items ) {
2437
- var len = items && items.length;
2438
- if ( !len ) {
2018
+ proto.reveal = function( items ) {
2019
+ this._emitCompleteOnItems( 'reveal', items );
2020
+ if ( !items || !items.length ) {
2439
2021
  return;
2440
2022
  }
2441
- for ( var i=0; i < len; i++ ) {
2442
- var item = items[i];
2023
+ items.forEach( function( item ) {
2443
2024
  item.reveal();
2444
- }
2025
+ });
2445
2026
  };
2446
2027
 
2447
2028
  /**
2448
2029
  * hide a collection of items
2449
2030
  * @param {Array of Outlayer.Items} items
2450
2031
  */
2451
- Outlayer.prototype.hide = function( items ) {
2452
- var len = items && items.length;
2453
- if ( !len ) {
2032
+ proto.hide = function( items ) {
2033
+ this._emitCompleteOnItems( 'hide', items );
2034
+ if ( !items || !items.length ) {
2454
2035
  return;
2455
2036
  }
2456
- for ( var i=0; i < len; i++ ) {
2457
- var item = items[i];
2037
+ items.forEach( function( item ) {
2458
2038
  item.hide();
2459
- }
2039
+ });
2040
+ };
2041
+
2042
+ /**
2043
+ * reveal item elements
2044
+ * @param {Array}, {Element}, {NodeList} items
2045
+ */
2046
+ proto.revealItemElements = function( elems ) {
2047
+ var items = this.getItems( elems );
2048
+ this.reveal( items );
2049
+ };
2050
+
2051
+ /**
2052
+ * hide item elements
2053
+ * @param {Array}, {Element}, {NodeList} items
2054
+ */
2055
+ proto.hideItemElements = function( elems ) {
2056
+ var items = this.getItems( elems );
2057
+ this.hide( items );
2460
2058
  };
2461
2059
 
2462
2060
  /**
@@ -2465,11 +2063,11 @@ Outlayer.prototype.hide = function( items ) {
2465
2063
  * @param {Function} callback
2466
2064
  * @returns {Outlayer.Item} item
2467
2065
  */
2468
- Outlayer.prototype.getItem = function( elem ) {
2066
+ proto.getItem = function( elem ) {
2469
2067
  // loop through items to get the one that matches
2470
- for ( var i=0, len = this.items.length; i < len; i++ ) {
2068
+ for ( var i=0; i < this.items.length; i++ ) {
2471
2069
  var item = this.items[i];
2472
- if ( item.element === elem ) {
2070
+ if ( item.element == elem ) {
2473
2071
  // return item
2474
2072
  return item;
2475
2073
  }
@@ -2481,18 +2079,15 @@ Outlayer.prototype.getItem = function( elem ) {
2481
2079
  * @param {Array} elems
2482
2080
  * @returns {Array} items - Outlayer.Items
2483
2081
  */
2484
- Outlayer.prototype.getItems = function( elems ) {
2485
- if ( !elems || !elems.length ) {
2486
- return;
2487
- }
2082
+ proto.getItems = function( elems ) {
2083
+ elems = utils.makeArray( elems );
2488
2084
  var items = [];
2489
- for ( var i=0, len = elems.length; i < len; i++ ) {
2490
- var elem = elems[i];
2085
+ elems.forEach( function( elem ) {
2491
2086
  var item = this.getItem( elem );
2492
2087
  if ( item ) {
2493
2088
  items.push( item );
2494
2089
  }
2495
- }
2090
+ }, this );
2496
2091
 
2497
2092
  return items;
2498
2093
  };
@@ -2501,44 +2096,41 @@ Outlayer.prototype.getItems = function( elems ) {
2501
2096
  * remove element(s) from instance and DOM
2502
2097
  * @param {Array or NodeList or Element} elems
2503
2098
  */
2504
- Outlayer.prototype.remove = function( elems ) {
2505
- elems = makeArray( elems );
2506
-
2099
+ proto.remove = function( elems ) {
2507
2100
  var removeItems = this.getItems( elems );
2101
+
2102
+ this._emitCompleteOnItems( 'remove', removeItems );
2103
+
2508
2104
  // bail if no items to remove
2509
2105
  if ( !removeItems || !removeItems.length ) {
2510
2106
  return;
2511
2107
  }
2512
2108
 
2513
- this._itemsOn( removeItems, 'remove', function() {
2514
- this.emitEvent( 'removeComplete', [ this, removeItems ] );
2515
- });
2516
-
2517
- for ( var i=0, len = removeItems.length; i < len; i++ ) {
2518
- var item = removeItems[i];
2109
+ removeItems.forEach( function( item ) {
2519
2110
  item.remove();
2520
2111
  // remove item from collection
2521
- removeFrom( item, this.items );
2522
- }
2112
+ utils.removeFrom( this.items, item );
2113
+ }, this );
2523
2114
  };
2524
2115
 
2525
2116
  // ----- destroy ----- //
2526
2117
 
2527
2118
  // remove and disable Outlayer instance
2528
- Outlayer.prototype.destroy = function() {
2119
+ proto.destroy = function() {
2529
2120
  // clean up dynamic styles
2530
2121
  var style = this.element.style;
2531
2122
  style.height = '';
2532
2123
  style.position = '';
2533
2124
  style.width = '';
2534
2125
  // destroy items
2535
- for ( var i=0, len = this.items.length; i < len; i++ ) {
2536
- var item = this.items[i];
2126
+ this.items.forEach( function( item ) {
2537
2127
  item.destroy();
2538
- }
2128
+ });
2539
2129
 
2540
2130
  this.unbindResize();
2541
2131
 
2132
+ var id = this.element.outlayerGUID;
2133
+ delete instances[ id ]; // remove reference to instance by id
2542
2134
  delete this.element.outlayerGUID;
2543
2135
  // remove data for jQuery
2544
2136
  if ( jQuery ) {
@@ -2555,6 +2147,7 @@ Outlayer.prototype.destroy = function() {
2555
2147
  * @returns {Outlayer}
2556
2148
  */
2557
2149
  Outlayer.data = function( elem ) {
2150
+ elem = utils.getQueryElement( elem );
2558
2151
  var id = elem && elem.outlayerGUID;
2559
2152
  return id && instances[ id ];
2560
2153
  };
@@ -2568,69 +2161,22 @@ Outlayer.data = function( elem ) {
2568
2161
  */
2569
2162
  Outlayer.create = function( namespace, options ) {
2570
2163
  // sub-class Outlayer
2571
- function Layout() {
2572
- Outlayer.apply( this, arguments );
2573
- }
2574
- // inherit Outlayer prototype, use Object.create if there
2575
- if ( Object.create ) {
2576
- Layout.prototype = Object.create( Outlayer.prototype );
2577
- } else {
2578
- extend( Layout.prototype, Outlayer.prototype );
2579
- }
2580
- // set contructor, used for namespace and Item
2581
- Layout.prototype.constructor = Layout;
2582
-
2583
- Layout.defaults = extend( {}, Outlayer.defaults );
2584
- // apply new options
2585
- extend( Layout.defaults, options );
2586
- // keep prototype.settings for backwards compatibility (Packery v1.2.0)
2587
- Layout.prototype.settings = {};
2164
+ var Layout = subclass( Outlayer );
2165
+ // apply new options and compatOptions
2166
+ Layout.defaults = utils.extend( {}, Outlayer.defaults );
2167
+ utils.extend( Layout.defaults, options );
2168
+ Layout.compatOptions = utils.extend( {}, Outlayer.compatOptions );
2588
2169
 
2589
2170
  Layout.namespace = namespace;
2590
2171
 
2591
2172
  Layout.data = Outlayer.data;
2592
2173
 
2593
2174
  // sub-class Item
2594
- Layout.Item = function LayoutItem() {
2595
- Item.apply( this, arguments );
2596
- };
2597
-
2598
- Layout.Item.prototype = new Item();
2175
+ Layout.Item = subclass( Item );
2599
2176
 
2600
2177
  // -------------------------- declarative -------------------------- //
2601
2178
 
2602
- /**
2603
- * allow user to initialize Outlayer via .js-namespace class
2604
- * options are parsed from data-namespace-option attribute
2605
- */
2606
- docReady( function() {
2607
- var dashedNamespace = toDashed( namespace );
2608
- var elems = document.querySelectorAll( '.js-' + dashedNamespace );
2609
- var dataAttr = 'data-' + dashedNamespace + '-options';
2610
-
2611
- for ( var i=0, len = elems.length; i < len; i++ ) {
2612
- var elem = elems[i];
2613
- var attr = elem.getAttribute( dataAttr );
2614
- var options;
2615
- try {
2616
- options = attr && JSON.parse( attr );
2617
- } catch ( error ) {
2618
- // log error, do not initialize
2619
- if ( console ) {
2620
- console.error( 'Error parsing ' + dataAttr + ' on ' +
2621
- elem.nodeName.toLowerCase() + ( elem.id ? '#' + elem.id : '' ) + ': ' +
2622
- error );
2623
- }
2624
- continue;
2625
- }
2626
- // initialize
2627
- var instance = new Layout( elem, options );
2628
- // make available via $().data('layoutname')
2629
- if ( jQuery ) {
2630
- jQuery.data( elem, namespace, instance );
2631
- }
2632
- }
2633
- });
2179
+ utils.htmlInit( Layout, namespace );
2634
2180
 
2635
2181
  // -------------------------- jQuery bridge -------------------------- //
2636
2182
 
@@ -2642,6 +2188,17 @@ Outlayer.create = function( namespace, options ) {
2642
2188
  return Layout;
2643
2189
  };
2644
2190
 
2191
+ function subclass( Parent ) {
2192
+ function SubClass() {
2193
+ Parent.apply( this, arguments );
2194
+ }
2195
+
2196
+ SubClass.prototype = Object.create( Parent.prototype );
2197
+ SubClass.prototype.constructor = SubClass;
2198
+
2199
+ return SubClass;
2200
+ }
2201
+
2645
2202
  // ----- fin ----- //
2646
2203
 
2647
2204
  // back in global
@@ -2649,69 +2206,50 @@ Outlayer.Item = Item;
2649
2206
 
2650
2207
  return Outlayer;
2651
2208
 
2652
- }
2653
-
2654
- // -------------------------- transport -------------------------- //
2655
-
2656
- if ( typeof define === 'function' && define.amd ) {
2657
- // AMD
2658
- define( 'outlayer/outlayer',[
2659
- 'eventie/eventie',
2660
- 'doc-ready/doc-ready',
2661
- 'eventEmitter/EventEmitter',
2662
- 'get-size/get-size',
2663
- 'matches-selector/matches-selector',
2664
- './item'
2665
- ],
2666
- outlayerDefinition );
2667
- } else {
2668
- // browser global
2669
- window.Outlayer = outlayerDefinition(
2670
- window.eventie,
2671
- window.docReady,
2672
- window.EventEmitter,
2673
- window.getSize,
2674
- window.matchesSelector,
2675
- window.Outlayer.Item
2676
- );
2677
- }
2678
-
2679
- })( window );
2209
+ }));
2680
2210
 
2681
2211
  /*!
2682
- * Masonry v3.1.5
2212
+ * Masonry v4.0.0
2683
2213
  * Cascading grid layout library
2684
2214
  * http://masonry.desandro.com
2685
2215
  * MIT License
2686
2216
  * by David DeSandro
2687
2217
  */
2688
2218
 
2689
- ( function( window ) {
2690
-
2219
+ ( function( window, factory ) {
2220
+ // universal module definition
2221
+ /* jshint strict: false */ /*globals define, module, require */
2222
+ if ( typeof define == 'function' && define.amd ) {
2223
+ // AMD
2224
+ define( [
2225
+ 'outlayer/outlayer',
2226
+ 'get-size/get-size'
2227
+ ],
2228
+ factory );
2229
+ } else if ( typeof module == 'object' && module.exports ) {
2230
+ // CommonJS
2231
+ module.exports = factory(
2232
+ require('outlayer'),
2233
+ require('get-size')
2234
+ );
2235
+ } else {
2236
+ // browser global
2237
+ window.Masonry = factory(
2238
+ window.Outlayer,
2239
+ window.getSize
2240
+ );
2241
+ }
2691
2242
 
2243
+ }( window, function factory( Outlayer, getSize ) {
2692
2244
 
2693
- // -------------------------- helpers -------------------------- //
2694
2245
 
2695
- var indexOf = Array.prototype.indexOf ?
2696
- function( items, value ) {
2697
- return items.indexOf( value );
2698
- } :
2699
- function ( items, value ) {
2700
- for ( var i=0, len = items.length; i < len; i++ ) {
2701
- var item = items[i];
2702
- if ( item === value ) {
2703
- return i;
2704
- }
2705
- }
2706
- return -1;
2707
- };
2708
2246
 
2709
2247
  // -------------------------- masonryDefinition -------------------------- //
2710
2248
 
2711
- // used for AMD definition and requires
2712
- function masonryDefinition( Outlayer, getSize ) {
2713
2249
  // create an Outlayer layout class
2714
2250
  var Masonry = Outlayer.create('masonry');
2251
+ // isFitWidth -> fitWidth
2252
+ Masonry.compatOptions.fitWidth = 'isFitWidth';
2715
2253
 
2716
2254
  Masonry.prototype._resetLayout = function() {
2717
2255
  this.getSize();
@@ -2720,9 +2258,8 @@ function masonryDefinition( Outlayer, getSize ) {
2720
2258
  this.measureColumns();
2721
2259
 
2722
2260
  // reset column Y
2723
- var i = this.cols;
2724
2261
  this.colYs = [];
2725
- while (i--) {
2262
+ for ( var i=0; i < this.cols; i++ ) {
2726
2263
  this.colYs.push( 0 );
2727
2264
  }
2728
2265
 
@@ -2741,15 +2278,23 @@ function masonryDefinition( Outlayer, getSize ) {
2741
2278
  this.containerWidth;
2742
2279
  }
2743
2280
 
2744
- this.columnWidth += this.gutter;
2745
-
2746
- this.cols = Math.floor( ( this.containerWidth + this.gutter ) / this.columnWidth );
2747
- this.cols = Math.max( this.cols, 1 );
2281
+ var columnWidth = this.columnWidth += this.gutter;
2282
+
2283
+ // calculate columns
2284
+ var containerWidth = this.containerWidth + this.gutter;
2285
+ var cols = containerWidth / columnWidth;
2286
+ // fix rounding errors, typically with gutters
2287
+ var excess = columnWidth - containerWidth % columnWidth;
2288
+ // if overshoot is less than a pixel, round up, otherwise floor it
2289
+ var mathMethod = excess && excess < 1 ? 'round' : 'floor';
2290
+ cols = Math[ mathMethod ]( cols );
2291
+ this.cols = Math.max( cols, 1 );
2748
2292
  };
2749
2293
 
2750
2294
  Masonry.prototype.getContainerWidth = function() {
2751
2295
  // container is parent if fit width
2752
- var container = this.options.isFitWidth ? this.element.parentNode : this.element;
2296
+ var isFitWidth = this._getOption('fitWidth');
2297
+ var container = isFitWidth ? this.element.parentNode : this.element;
2753
2298
  // check that this.size and size are there
2754
2299
  // IE8 triggers resize on body size change, so they might not be
2755
2300
  var size = getSize( container );
@@ -2768,7 +2313,7 @@ function masonryDefinition( Outlayer, getSize ) {
2768
2313
  var colGroup = this._getColGroup( colSpan );
2769
2314
  // get the minimum Y value from the columns
2770
2315
  var minimumY = Math.min.apply( Math, colGroup );
2771
- var shortColIndex = indexOf( colGroup, minimumY );
2316
+ var shortColIndex = colGroup.indexOf( minimumY );
2772
2317
 
2773
2318
  // position the brick
2774
2319
  var position = {
@@ -2813,7 +2358,8 @@ function masonryDefinition( Outlayer, getSize ) {
2813
2358
  var stampSize = getSize( stamp );
2814
2359
  var offset = this._getElementOffset( stamp );
2815
2360
  // get the columns that this stamp affects
2816
- var firstX = this.options.isOriginLeft ? offset.left : offset.right;
2361
+ var isOriginLeft = this._getOption('originLeft');
2362
+ var firstX = isOriginLeft ? offset.left : offset.right;
2817
2363
  var lastX = firstX + stampSize.outerWidth;
2818
2364
  var firstCol = Math.floor( firstX / this.columnWidth );
2819
2365
  firstCol = Math.max( 0, firstCol );
@@ -2822,7 +2368,9 @@ function masonryDefinition( Outlayer, getSize ) {
2822
2368
  lastCol -= lastX % this.columnWidth ? 0 : 1;
2823
2369
  lastCol = Math.min( this.cols - 1, lastCol );
2824
2370
  // set colYs to bottom of the stamp
2825
- var stampMaxY = ( this.options.isOriginTop ? offset.top : offset.bottom ) +
2371
+
2372
+ var isOriginTop = this._getOption('originTop');
2373
+ var stampMaxY = ( isOriginTop ? offset.top : offset.bottom ) +
2826
2374
  stampSize.outerHeight;
2827
2375
  for ( var i = firstCol; i <= lastCol; i++ ) {
2828
2376
  this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
@@ -2835,7 +2383,7 @@ function masonryDefinition( Outlayer, getSize ) {
2835
2383
  height: this.maxY
2836
2384
  };
2837
2385
 
2838
- if ( this.options.isFitWidth ) {
2386
+ if ( this._getOption('fitWidth') ) {
2839
2387
  size.width = this._getContainerFitWidth();
2840
2388
  }
2841
2389
 
@@ -2859,27 +2407,10 @@ function masonryDefinition( Outlayer, getSize ) {
2859
2407
  Masonry.prototype.needsResizeLayout = function() {
2860
2408
  var previousWidth = this.containerWidth;
2861
2409
  this.getContainerWidth();
2862
- return previousWidth !== this.containerWidth;
2410
+ return previousWidth != this.containerWidth;
2863
2411
  };
2864
2412
 
2865
2413
  return Masonry;
2866
- }
2867
2414
 
2868
- // -------------------------- transport -------------------------- //
2869
-
2870
- if ( typeof define === 'function' && define.amd ) {
2871
- // AMD
2872
- define( [
2873
- 'outlayer/outlayer',
2874
- 'get-size/get-size'
2875
- ],
2876
- masonryDefinition );
2877
- } else {
2878
- // browser global
2879
- window.Masonry = masonryDefinition(
2880
- window.Outlayer,
2881
- window.getSize
2882
- );
2883
- }
2415
+ }));
2884
2416
 
2885
- })( window );