| 3999 |
julien |
1 |
/*!
|
|
|
2 |
* Masonry PACKAGED v4.2.2
|
|
|
3 |
* Cascading grid layout library
|
|
|
4 |
* https://masonry.desandro.com
|
|
|
5 |
* MIT License
|
|
|
6 |
* by David DeSandro
|
|
|
7 |
*/
|
|
|
8 |
|
|
|
9 |
/**
|
|
|
10 |
* Bridget makes jQuery widgets
|
|
|
11 |
* v2.0.1
|
|
|
12 |
* MIT license
|
|
|
13 |
*/
|
|
|
14 |
|
|
|
15 |
/* jshint browser: true, strict: true, undef: true, unused: true */
|
|
|
16 |
|
|
|
17 |
( function( window, factory ) {
|
|
|
18 |
// universal module definition
|
|
|
19 |
/*jshint strict: false */ /* globals define, module, require */
|
|
|
20 |
if ( typeof define == 'function' && define.amd ) {
|
|
|
21 |
// AMD
|
|
|
22 |
define( 'jquery-bridget/jquery-bridget',[ 'jquery' ], function( jQuery ) {
|
|
|
23 |
return factory( window, jQuery );
|
|
|
24 |
});
|
|
|
25 |
} else if ( typeof module == 'object' && module.exports ) {
|
|
|
26 |
// CommonJS
|
|
|
27 |
module.exports = factory(
|
|
|
28 |
window,
|
|
|
29 |
require('jquery')
|
|
|
30 |
);
|
|
|
31 |
} else {
|
|
|
32 |
// browser global
|
|
|
33 |
window.jQueryBridget = factory(
|
|
|
34 |
window,
|
|
|
35 |
window.jQuery
|
|
|
36 |
);
|
|
|
37 |
}
|
|
|
38 |
|
|
|
39 |
}( window, function factory( window, jQuery ) {
|
|
|
40 |
'use strict';
|
|
|
41 |
|
|
|
42 |
// ----- utils ----- //
|
|
|
43 |
|
|
|
44 |
var arraySlice = Array.prototype.slice;
|
|
|
45 |
|
|
|
46 |
// helper function for logging errors
|
|
|
47 |
// $.error breaks jQuery chaining
|
|
|
48 |
var console = window.console;
|
|
|
49 |
var logError = typeof console == 'undefined' ? function() {} :
|
|
|
50 |
function( message ) {
|
|
|
51 |
console.error( message );
|
|
|
52 |
};
|
|
|
53 |
|
|
|
54 |
// ----- jQueryBridget ----- //
|
|
|
55 |
|
|
|
56 |
function jQueryBridget( namespace, PluginClass, $ ) {
|
|
|
57 |
$ = $ || jQuery || window.jQuery;
|
|
|
58 |
if ( !$ ) {
|
|
|
59 |
return;
|
|
|
60 |
}
|
|
|
61 |
|
|
|
62 |
// add option method -> $().plugin('option', {...})
|
|
|
63 |
if ( !PluginClass.prototype.option ) {
|
|
|
64 |
// option setter
|
|
|
65 |
PluginClass.prototype.option = function( opts ) {
|
|
|
66 |
// bail out if not an object
|
|
|
67 |
if ( !$.isPlainObject( opts ) ){
|
|
|
68 |
return;
|
|
|
69 |
}
|
|
|
70 |
this.options = $.extend( true, this.options, opts );
|
|
|
71 |
};
|
|
|
72 |
}
|
|
|
73 |
|
|
|
74 |
// make jQuery plugin
|
|
|
75 |
$.fn[ namespace ] = function( arg0 /*, arg1 */ ) {
|
|
|
76 |
if ( typeof arg0 == 'string' ) {
|
|
|
77 |
// method call $().plugin( 'methodName', { options } )
|
|
|
78 |
// shift arguments by 1
|
|
|
79 |
var args = arraySlice.call( arguments, 1 );
|
|
|
80 |
return methodCall( this, arg0, args );
|
|
|
81 |
}
|
|
|
82 |
// just $().plugin({ options })
|
|
|
83 |
plainCall( this, arg0 );
|
|
|
84 |
return this;
|
|
|
85 |
};
|
|
|
86 |
|
|
|
87 |
// $().plugin('methodName')
|
|
|
88 |
function methodCall( $elems, methodName, args ) {
|
|
|
89 |
var returnValue;
|
|
|
90 |
var pluginMethodStr = '$().' + namespace + '("' + methodName + '")';
|
|
|
91 |
|
|
|
92 |
$elems.each( function( i, elem ) {
|
|
|
93 |
// get instance
|
|
|
94 |
var instance = $.data( elem, namespace );
|
|
|
95 |
if ( !instance ) {
|
|
|
96 |
logError( namespace + ' not initialized. Cannot call methods, i.e. ' +
|
|
|
97 |
pluginMethodStr );
|
|
|
98 |
return;
|
|
|
99 |
}
|
|
|
100 |
|
|
|
101 |
var method = instance[ methodName ];
|
|
|
102 |
if ( !method || methodName.charAt(0) == '_' ) {
|
|
|
103 |
logError( pluginMethodStr + ' is not a valid method' );
|
|
|
104 |
return;
|
|
|
105 |
}
|
|
|
106 |
|
|
|
107 |
// apply method, get return value
|
|
|
108 |
var value = method.apply( instance, args );
|
|
|
109 |
// set return value if value is returned, use only first value
|
|
|
110 |
returnValue = returnValue === undefined ? value : returnValue;
|
|
|
111 |
});
|
|
|
112 |
|
|
|
113 |
return returnValue !== undefined ? returnValue : $elems;
|
|
|
114 |
}
|
|
|
115 |
|
|
|
116 |
function plainCall( $elems, options ) {
|
|
|
117 |
$elems.each( function( i, elem ) {
|
|
|
118 |
var instance = $.data( elem, namespace );
|
|
|
119 |
if ( instance ) {
|
|
|
120 |
// set options & init
|
|
|
121 |
instance.option( options );
|
|
|
122 |
instance._init();
|
|
|
123 |
} else {
|
|
|
124 |
// initialize new instance
|
|
|
125 |
instance = new PluginClass( elem, options );
|
|
|
126 |
$.data( elem, namespace, instance );
|
|
|
127 |
}
|
|
|
128 |
});
|
|
|
129 |
}
|
|
|
130 |
|
|
|
131 |
updateJQuery( $ );
|
|
|
132 |
|
|
|
133 |
}
|
|
|
134 |
|
|
|
135 |
// ----- updateJQuery ----- //
|
|
|
136 |
|
|
|
137 |
// set $.bridget for v1 backwards compatibility
|
|
|
138 |
function updateJQuery( $ ) {
|
|
|
139 |
if ( !$ || ( $ && $.bridget ) ) {
|
|
|
140 |
return;
|
|
|
141 |
}
|
|
|
142 |
$.bridget = jQueryBridget;
|
|
|
143 |
}
|
|
|
144 |
|
|
|
145 |
updateJQuery( jQuery || window.jQuery );
|
|
|
146 |
|
|
|
147 |
// ----- ----- //
|
|
|
148 |
|
|
|
149 |
return jQueryBridget;
|
|
|
150 |
|
|
|
151 |
}));
|
|
|
152 |
|
|
|
153 |
/**
|
|
|
154 |
* EvEmitter v1.1.0
|
|
|
155 |
* Lil' event emitter
|
|
|
156 |
* MIT License
|
|
|
157 |
*/
|
|
|
158 |
|
|
|
159 |
/* jshint unused: true, undef: true, strict: true */
|
|
|
160 |
|
|
|
161 |
( function( global, factory ) {
|
|
|
162 |
// universal module definition
|
|
|
163 |
/* jshint strict: false */ /* globals define, module, window */
|
|
|
164 |
if ( typeof define == 'function' && define.amd ) {
|
|
|
165 |
// AMD - RequireJS
|
|
|
166 |
define( 'ev-emitter/ev-emitter',factory );
|
|
|
167 |
} else if ( typeof module == 'object' && module.exports ) {
|
|
|
168 |
// CommonJS - Browserify, Webpack
|
|
|
169 |
module.exports = factory();
|
|
|
170 |
} else {
|
|
|
171 |
// Browser globals
|
|
|
172 |
global.EvEmitter = factory();
|
|
|
173 |
}
|
|
|
174 |
|
|
|
175 |
}( typeof window != 'undefined' ? window : this, function() {
|
|
|
176 |
|
|
|
177 |
|
|
|
178 |
|
|
|
179 |
function EvEmitter() {}
|
|
|
180 |
|
|
|
181 |
var proto = EvEmitter.prototype;
|
|
|
182 |
|
|
|
183 |
proto.on = function( eventName, listener ) {
|
|
|
184 |
if ( !eventName || !listener ) {
|
|
|
185 |
return;
|
|
|
186 |
}
|
|
|
187 |
// set events hash
|
|
|
188 |
var events = this._events = this._events || {};
|
|
|
189 |
// set listeners array
|
|
|
190 |
var listeners = events[ eventName ] = events[ eventName ] || [];
|
|
|
191 |
// only add once
|
|
|
192 |
if ( listeners.indexOf( listener ) == -1 ) {
|
|
|
193 |
listeners.push( listener );
|
|
|
194 |
}
|
|
|
195 |
|
|
|
196 |
return this;
|
|
|
197 |
};
|
|
|
198 |
|
|
|
199 |
proto.once = function( eventName, listener ) {
|
|
|
200 |
if ( !eventName || !listener ) {
|
|
|
201 |
return;
|
|
|
202 |
}
|
|
|
203 |
// add event
|
|
|
204 |
this.on( eventName, listener );
|
|
|
205 |
// set once flag
|
|
|
206 |
// set onceEvents hash
|
|
|
207 |
var onceEvents = this._onceEvents = this._onceEvents || {};
|
|
|
208 |
// set onceListeners object
|
|
|
209 |
var onceListeners = onceEvents[ eventName ] = onceEvents[ eventName ] || {};
|
|
|
210 |
// set flag
|
|
|
211 |
onceListeners[ listener ] = true;
|
|
|
212 |
|
|
|
213 |
return this;
|
|
|
214 |
};
|
|
|
215 |
|
|
|
216 |
proto.off = function( eventName, listener ) {
|
|
|
217 |
var listeners = this._events && this._events[ eventName ];
|
|
|
218 |
if ( !listeners || !listeners.length ) {
|
|
|
219 |
return;
|
|
|
220 |
}
|
|
|
221 |
var index = listeners.indexOf( listener );
|
|
|
222 |
if ( index != -1 ) {
|
|
|
223 |
listeners.splice( index, 1 );
|
|
|
224 |
}
|
|
|
225 |
|
|
|
226 |
return this;
|
|
|
227 |
};
|
|
|
228 |
|
|
|
229 |
proto.emitEvent = function( eventName, args ) {
|
|
|
230 |
var listeners = this._events && this._events[ eventName ];
|
|
|
231 |
if ( !listeners || !listeners.length ) {
|
|
|
232 |
return;
|
|
|
233 |
}
|
|
|
234 |
// copy over to avoid interference if .off() in listener
|
|
|
235 |
listeners = listeners.slice(0);
|
|
|
236 |
args = args || [];
|
|
|
237 |
// once stuff
|
|
|
238 |
var onceListeners = this._onceEvents && this._onceEvents[ eventName ];
|
|
|
239 |
|
|
|
240 |
for ( var i=0; i < listeners.length; i++ ) {
|
|
|
241 |
var listener = listeners[i]
|
|
|
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 ];
|
|
|
249 |
}
|
|
|
250 |
// trigger listener
|
|
|
251 |
listener.apply( this, args );
|
|
|
252 |
}
|
|
|
253 |
|
|
|
254 |
return this;
|
|
|
255 |
};
|
|
|
256 |
|
|
|
257 |
proto.allOff = function() {
|
|
|
258 |
delete this._events;
|
|
|
259 |
delete this._onceEvents;
|
|
|
260 |
};
|
|
|
261 |
|
|
|
262 |
return EvEmitter;
|
|
|
263 |
|
|
|
264 |
}));
|
|
|
265 |
|
|
|
266 |
/*!
|
|
|
267 |
* getSize v2.0.3
|
|
|
268 |
* measure size of elements
|
|
|
269 |
* MIT license
|
|
|
270 |
*/
|
|
|
271 |
|
|
|
272 |
/* jshint browser: true, strict: true, undef: true, unused: true */
|
|
|
273 |
/* globals console: false */
|
|
|
274 |
|
|
|
275 |
( function( window, factory ) {
|
|
|
276 |
/* jshint strict: false */ /* globals define, module */
|
|
|
277 |
if ( typeof define == 'function' && define.amd ) {
|
|
|
278 |
// AMD
|
|
|
279 |
define( 'get-size/get-size',factory );
|
|
|
280 |
} else if ( typeof module == 'object' && module.exports ) {
|
|
|
281 |
// CommonJS
|
|
|
282 |
module.exports = factory();
|
|
|
283 |
} else {
|
|
|
284 |
// browser global
|
|
|
285 |
window.getSize = factory();
|
|
|
286 |
}
|
|
|
287 |
|
|
|
288 |
})( window, function factory() {
|
|
|
289 |
'use strict';
|
|
|
290 |
|
|
|
291 |
// -------------------------- helpers -------------------------- //
|
|
|
292 |
|
|
|
293 |
// get a number from a string, not a percentage
|
|
|
294 |
function getStyleSize( value ) {
|
|
|
295 |
var num = parseFloat( value );
|
|
|
296 |
// not a percent like '100%', and a number
|
|
|
297 |
var isValid = value.indexOf('%') == -1 && !isNaN( num );
|
|
|
298 |
return isValid && num;
|
|
|
299 |
}
|
|
|
300 |
|
|
|
301 |
function noop() {}
|
|
|
302 |
|
|
|
303 |
var logError = typeof console == 'undefined' ? noop :
|
|
|
304 |
function( message ) {
|
|
|
305 |
console.error( message );
|
|
|
306 |
};
|
|
|
307 |
|
|
|
308 |
// -------------------------- measurements -------------------------- //
|
|
|
309 |
|
|
|
310 |
var measurements = [
|
|
|
311 |
'paddingLeft',
|
|
|
312 |
'paddingRight',
|
|
|
313 |
'paddingTop',
|
|
|
314 |
'paddingBottom',
|
|
|
315 |
'marginLeft',
|
|
|
316 |
'marginRight',
|
|
|
317 |
'marginTop',
|
|
|
318 |
'marginBottom',
|
|
|
319 |
'borderLeftWidth',
|
|
|
320 |
'borderRightWidth',
|
|
|
321 |
'borderTopWidth',
|
|
|
322 |
'borderBottomWidth'
|
|
|
323 |
];
|
|
|
324 |
|
|
|
325 |
var measurementsLength = measurements.length;
|
|
|
326 |
|
|
|
327 |
function getZeroSize() {
|
|
|
328 |
var size = {
|
|
|
329 |
width: 0,
|
|
|
330 |
height: 0,
|
|
|
331 |
innerWidth: 0,
|
|
|
332 |
innerHeight: 0,
|
|
|
333 |
outerWidth: 0,
|
|
|
334 |
outerHeight: 0
|
|
|
335 |
};
|
|
|
336 |
for ( var i=0; i < measurementsLength; i++ ) {
|
|
|
337 |
var measurement = measurements[i];
|
|
|
338 |
size[ measurement ] = 0;
|
|
|
339 |
}
|
|
|
340 |
return size;
|
|
|
341 |
}
|
|
|
342 |
|
|
|
343 |
// -------------------------- getStyle -------------------------- //
|
|
|
344 |
|
|
|
345 |
/**
|
|
|
346 |
* getStyle, get style of element, check for Firefox bug
|
|
|
347 |
* https://bugzilla.mozilla.org/show_bug.cgi?id=548397
|
|
|
348 |
*/
|
|
|
349 |
function getStyle( elem ) {
|
|
|
350 |
var style = getComputedStyle( elem );
|
|
|
351 |
if ( !style ) {
|
|
|
352 |
logError( 'Style returned ' + style +
|
|
|
353 |
'. Are you running this code in a hidden iframe on Firefox? ' +
|
|
|
354 |
'See https://bit.ly/getsizebug1' );
|
|
|
355 |
}
|
|
|
356 |
return style;
|
|
|
357 |
}
|
|
|
358 |
|
|
|
359 |
// -------------------------- setup -------------------------- //
|
|
|
360 |
|
|
|
361 |
var isSetup = false;
|
|
|
362 |
|
|
|
363 |
var isBoxSizeOuter;
|
|
|
364 |
|
|
|
365 |
/**
|
|
|
366 |
* setup
|
|
|
367 |
* check isBoxSizerOuter
|
|
|
368 |
* do on first getSize() rather than on page load for Firefox bug
|
|
|
369 |
*/
|
|
|
370 |
function setup() {
|
|
|
371 |
// setup once
|
|
|
372 |
if ( isSetup ) {
|
|
|
373 |
return;
|
|
|
374 |
}
|
|
|
375 |
isSetup = true;
|
|
|
376 |
|
|
|
377 |
// -------------------------- box sizing -------------------------- //
|
|
|
378 |
|
|
|
379 |
/**
|
|
|
380 |
* Chrome & Safari measure the outer-width on style.width on border-box elems
|
|
|
381 |
* IE11 & Firefox<29 measures the inner-width
|
|
|
382 |
*/
|
|
|
383 |
var div = document.createElement('div');
|
|
|
384 |
div.style.width = '200px';
|
|
|
385 |
div.style.padding = '1px 2px 3px 4px';
|
|
|
386 |
div.style.borderStyle = 'solid';
|
|
|
387 |
div.style.borderWidth = '1px 2px 3px 4px';
|
|
|
388 |
div.style.boxSizing = 'border-box';
|
|
|
389 |
|
|
|
390 |
var body = document.body || document.documentElement;
|
|
|
391 |
body.appendChild( div );
|
|
|
392 |
var style = getStyle( div );
|
|
|
393 |
// round value for browser zoom. desandro/masonry#928
|
|
|
394 |
isBoxSizeOuter = Math.round( getStyleSize( style.width ) ) == 200;
|
|
|
395 |
getSize.isBoxSizeOuter = isBoxSizeOuter;
|
|
|
396 |
|
|
|
397 |
body.removeChild( div );
|
|
|
398 |
}
|
|
|
399 |
|
|
|
400 |
// -------------------------- getSize -------------------------- //
|
|
|
401 |
|
|
|
402 |
function getSize( elem ) {
|
|
|
403 |
setup();
|
|
|
404 |
|
|
|
405 |
// use querySeletor if elem is string
|
|
|
406 |
if ( typeof elem == 'string' ) {
|
|
|
407 |
elem = document.querySelector( elem );
|
|
|
408 |
}
|
|
|
409 |
|
|
|
410 |
// do not proceed on non-objects
|
|
|
411 |
if ( !elem || typeof elem != 'object' || !elem.nodeType ) {
|
|
|
412 |
return;
|
|
|
413 |
}
|
|
|
414 |
|
|
|
415 |
var style = getStyle( elem );
|
|
|
416 |
|
|
|
417 |
// if hidden, everything is 0
|
|
|
418 |
if ( style.display == 'none' ) {
|
|
|
419 |
return getZeroSize();
|
|
|
420 |
}
|
|
|
421 |
|
|
|
422 |
var size = {};
|
|
|
423 |
size.width = elem.offsetWidth;
|
|
|
424 |
size.height = elem.offsetHeight;
|
|
|
425 |
|
|
|
426 |
var isBorderBox = size.isBorderBox = style.boxSizing == 'border-box';
|
|
|
427 |
|
|
|
428 |
// get all measurements
|
|
|
429 |
for ( var i=0; i < measurementsLength; i++ ) {
|
|
|
430 |
var measurement = measurements[i];
|
|
|
431 |
var value = style[ measurement ];
|
|
|
432 |
var num = parseFloat( value );
|
|
|
433 |
// any 'auto', 'medium' value will be 0
|
|
|
434 |
size[ measurement ] = !isNaN( num ) ? num : 0;
|
|
|
435 |
}
|
|
|
436 |
|
|
|
437 |
var paddingWidth = size.paddingLeft + size.paddingRight;
|
|
|
438 |
var paddingHeight = size.paddingTop + size.paddingBottom;
|
|
|
439 |
var marginWidth = size.marginLeft + size.marginRight;
|
|
|
440 |
var marginHeight = size.marginTop + size.marginBottom;
|
|
|
441 |
var borderWidth = size.borderLeftWidth + size.borderRightWidth;
|
|
|
442 |
var borderHeight = size.borderTopWidth + size.borderBottomWidth;
|
|
|
443 |
|
|
|
444 |
var isBorderBoxSizeOuter = isBorderBox && isBoxSizeOuter;
|
|
|
445 |
|
|
|
446 |
// overwrite width and height if we can get it from style
|
|
|
447 |
var styleWidth = getStyleSize( style.width );
|
|
|
448 |
if ( styleWidth !== false ) {
|
|
|
449 |
size.width = styleWidth +
|
|
|
450 |
// add padding and border unless it's already including it
|
|
|
451 |
( isBorderBoxSizeOuter ? 0 : paddingWidth + borderWidth );
|
|
|
452 |
}
|
|
|
453 |
|
|
|
454 |
var styleHeight = getStyleSize( style.height );
|
|
|
455 |
if ( styleHeight !== false ) {
|
|
|
456 |
size.height = styleHeight +
|
|
|
457 |
// add padding and border unless it's already including it
|
|
|
458 |
( isBorderBoxSizeOuter ? 0 : paddingHeight + borderHeight );
|
|
|
459 |
}
|
|
|
460 |
|
|
|
461 |
size.innerWidth = size.width - ( paddingWidth + borderWidth );
|
|
|
462 |
size.innerHeight = size.height - ( paddingHeight + borderHeight );
|
|
|
463 |
|
|
|
464 |
size.outerWidth = size.width + marginWidth;
|
|
|
465 |
size.outerHeight = size.height + marginHeight;
|
|
|
466 |
|
|
|
467 |
return size;
|
|
|
468 |
}
|
|
|
469 |
|
|
|
470 |
return getSize;
|
|
|
471 |
|
|
|
472 |
});
|
|
|
473 |
|
|
|
474 |
/**
|
|
|
475 |
* matchesSelector v2.0.2
|
|
|
476 |
* matchesSelector( element, '.selector' )
|
|
|
477 |
* MIT license
|
|
|
478 |
*/
|
|
|
479 |
|
|
|
480 |
/*jshint browser: true, strict: true, undef: true, unused: true */
|
|
|
481 |
|
|
|
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( 'desandro-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 |
}
|
|
|
496 |
|
|
|
497 |
}( window, function factory() {
|
|
|
498 |
'use strict';
|
|
|
499 |
|
|
|
500 |
var matchesMethod = ( function() {
|
|
|
501 |
var ElemProto = window.Element.prototype;
|
|
|
502 |
// check for the standard method name first
|
|
|
503 |
if ( ElemProto.matches ) {
|
|
|
504 |
return 'matches';
|
|
|
505 |
}
|
|
|
506 |
// check un-prefixed
|
|
|
507 |
if ( ElemProto.matchesSelector ) {
|
|
|
508 |
return 'matchesSelector';
|
|
|
509 |
}
|
|
|
510 |
// check vendor prefixes
|
|
|
511 |
var prefixes = [ 'webkit', 'moz', 'ms', 'o' ];
|
|
|
512 |
|
|
|
513 |
for ( var i=0; i < prefixes.length; i++ ) {
|
|
|
514 |
var prefix = prefixes[i];
|
|
|
515 |
var method = prefix + 'MatchesSelector';
|
|
|
516 |
if ( ElemProto[ method ] ) {
|
|
|
517 |
return method;
|
|
|
518 |
}
|
|
|
519 |
}
|
|
|
520 |
})();
|
|
|
521 |
|
|
|
522 |
return function matchesSelector( elem, selector ) {
|
|
|
523 |
return elem[ matchesMethod ]( selector );
|
|
|
524 |
};
|
|
|
525 |
|
|
|
526 |
}));
|
|
|
527 |
|
|
|
528 |
/**
|
|
|
529 |
* Fizzy UI utils v2.0.7
|
|
|
530 |
* MIT license
|
|
|
531 |
*/
|
|
|
532 |
|
|
|
533 |
/*jshint browser: true, undef: true, unused: true, strict: true */
|
|
|
534 |
|
|
|
535 |
( function( window, factory ) {
|
|
|
536 |
// universal module definition
|
|
|
537 |
/*jshint strict: false */ /*globals define, module, require */
|
|
|
538 |
|
|
|
539 |
if ( typeof define == 'function' && define.amd ) {
|
|
|
540 |
// AMD
|
|
|
541 |
define( 'fizzy-ui-utils/utils',[
|
|
|
542 |
'desandro-matches-selector/matches-selector'
|
|
|
543 |
], function( matchesSelector ) {
|
|
|
544 |
return factory( window, matchesSelector );
|
|
|
545 |
});
|
|
|
546 |
} else if ( typeof module == 'object' && module.exports ) {
|
|
|
547 |
// CommonJS
|
|
|
548 |
module.exports = factory(
|
|
|
549 |
window,
|
|
|
550 |
require('desandro-matches-selector')
|
|
|
551 |
);
|
|
|
552 |
} else {
|
|
|
553 |
// browser global
|
|
|
554 |
window.fizzyUIUtils = factory(
|
|
|
555 |
window,
|
|
|
556 |
window.matchesSelector
|
|
|
557 |
);
|
|
|
558 |
}
|
|
|
559 |
|
|
|
560 |
}( window, function factory( window, matchesSelector ) {
|
|
|
561 |
|
|
|
562 |
|
|
|
563 |
|
|
|
564 |
var utils = {};
|
|
|
565 |
|
|
|
566 |
// ----- extend ----- //
|
|
|
567 |
|
|
|
568 |
// extends objects
|
|
|
569 |
utils.extend = function( a, b ) {
|
|
|
570 |
for ( var prop in b ) {
|
|
|
571 |
a[ prop ] = b[ prop ];
|
|
|
572 |
}
|
|
|
573 |
return a;
|
|
|
574 |
};
|
|
|
575 |
|
|
|
576 |
// ----- modulo ----- //
|
|
|
577 |
|
|
|
578 |
utils.modulo = function( num, div ) {
|
|
|
579 |
return ( ( num % div ) + div ) % div;
|
|
|
580 |
};
|
|
|
581 |
|
|
|
582 |
// ----- makeArray ----- //
|
|
|
583 |
|
|
|
584 |
var arraySlice = Array.prototype.slice;
|
|
|
585 |
|
|
|
586 |
// turn element or nodeList into an array
|
|
|
587 |
utils.makeArray = function( obj ) {
|
|
|
588 |
if ( Array.isArray( obj ) ) {
|
|
|
589 |
// use object if already an array
|
|
|
590 |
return obj;
|
|
|
591 |
}
|
|
|
592 |
// return empty array if undefined or null. #6
|
|
|
593 |
if ( obj === null || obj === undefined ) {
|
|
|
594 |
return [];
|
|
|
595 |
}
|
|
|
596 |
|
|
|
597 |
var isArrayLike = typeof obj == 'object' && typeof obj.length == 'number';
|
|
|
598 |
if ( isArrayLike ) {
|
|
|
599 |
// convert nodeList to array
|
|
|
600 |
return arraySlice.call( obj );
|
|
|
601 |
}
|
|
|
602 |
|
|
|
603 |
// array of single index
|
|
|
604 |
return [ obj ];
|
|
|
605 |
};
|
|
|
606 |
|
|
|
607 |
// ----- removeFrom ----- //
|
|
|
608 |
|
|
|
609 |
utils.removeFrom = function( ary, obj ) {
|
|
|
610 |
var index = ary.indexOf( obj );
|
|
|
611 |
if ( index != -1 ) {
|
|
|
612 |
ary.splice( index, 1 );
|
|
|
613 |
}
|
|
|
614 |
};
|
|
|
615 |
|
|
|
616 |
// ----- getParent ----- //
|
|
|
617 |
|
|
|
618 |
utils.getParent = function( elem, selector ) {
|
|
|
619 |
while ( elem.parentNode && elem != document.body ) {
|
|
|
620 |
elem = elem.parentNode;
|
|
|
621 |
if ( matchesSelector( elem, selector ) ) {
|
|
|
622 |
return elem;
|
|
|
623 |
}
|
|
|
624 |
}
|
|
|
625 |
};
|
|
|
626 |
|
|
|
627 |
// ----- getQueryElement ----- //
|
|
|
628 |
|
|
|
629 |
// use element as selector string
|
|
|
630 |
utils.getQueryElement = function( elem ) {
|
|
|
631 |
if ( typeof elem == 'string' ) {
|
|
|
632 |
return document.querySelector( elem );
|
|
|
633 |
}
|
|
|
634 |
return elem;
|
|
|
635 |
};
|
|
|
636 |
|
|
|
637 |
// ----- handleEvent ----- //
|
|
|
638 |
|
|
|
639 |
// enable .ontype to trigger from .addEventListener( elem, 'type' )
|
|
|
640 |
utils.handleEvent = function( event ) {
|
|
|
641 |
var method = 'on' + event.type;
|
|
|
642 |
if ( this[ method ] ) {
|
|
|
643 |
this[ method ]( event );
|
|
|
644 |
}
|
|
|
645 |
};
|
|
|
646 |
|
|
|
647 |
// ----- filterFindElements ----- //
|
|
|
648 |
|
|
|
649 |
utils.filterFindElements = function( elems, selector ) {
|
|
|
650 |
// make array of elems
|
|
|
651 |
elems = utils.makeArray( elems );
|
|
|
652 |
var ffElems = [];
|
|
|
653 |
|
|
|
654 |
elems.forEach( function( elem ) {
|
|
|
655 |
// check that elem is an actual element
|
|
|
656 |
if ( !( elem instanceof HTMLElement ) ) {
|
|
|
657 |
return;
|
|
|
658 |
}
|
|
|
659 |
// add elem if no selector
|
|
|
660 |
if ( !selector ) {
|
|
|
661 |
ffElems.push( elem );
|
|
|
662 |
return;
|
|
|
663 |
}
|
|
|
664 |
// filter & find items if we have a selector
|
|
|
665 |
// filter
|
|
|
666 |
if ( matchesSelector( elem, selector ) ) {
|
|
|
667 |
ffElems.push( elem );
|
|
|
668 |
}
|
|
|
669 |
// find children
|
|
|
670 |
var childElems = elem.querySelectorAll( selector );
|
|
|
671 |
// concat childElems to filterFound array
|
|
|
672 |
for ( var i=0; i < childElems.length; i++ ) {
|
|
|
673 |
ffElems.push( childElems[i] );
|
|
|
674 |
}
|
|
|
675 |
});
|
|
|
676 |
|
|
|
677 |
return ffElems;
|
|
|
678 |
};
|
|
|
679 |
|
|
|
680 |
// ----- debounceMethod ----- //
|
|
|
681 |
|
|
|
682 |
utils.debounceMethod = function( _class, methodName, threshold ) {
|
|
|
683 |
threshold = threshold || 100;
|
|
|
684 |
// original method
|
|
|
685 |
var method = _class.prototype[ methodName ];
|
|
|
686 |
var timeoutName = methodName + 'Timeout';
|
|
|
687 |
|
|
|
688 |
_class.prototype[ methodName ] = function() {
|
|
|
689 |
var timeout = this[ timeoutName ];
|
|
|
690 |
clearTimeout( timeout );
|
|
|
691 |
|
|
|
692 |
var args = arguments;
|
|
|
693 |
var _this = this;
|
|
|
694 |
this[ timeoutName ] = setTimeout( function() {
|
|
|
695 |
method.apply( _this, args );
|
|
|
696 |
delete _this[ timeoutName ];
|
|
|
697 |
}, threshold );
|
|
|
698 |
};
|
|
|
699 |
};
|
|
|
700 |
|
|
|
701 |
// ----- docReady ----- //
|
|
|
702 |
|
|
|
703 |
utils.docReady = function( callback ) {
|
|
|
704 |
var readyState = document.readyState;
|
|
|
705 |
if ( readyState == 'complete' || readyState == 'interactive' ) {
|
|
|
706 |
// do async to allow for other scripts to run. metafizzy/flickity#441
|
|
|
707 |
setTimeout( callback );
|
|
|
708 |
} else {
|
|
|
709 |
document.addEventListener( 'DOMContentLoaded', callback );
|
|
|
710 |
}
|
|
|
711 |
};
|
|
|
712 |
|
|
|
713 |
// ----- htmlInit ----- //
|
|
|
714 |
|
|
|
715 |
// http://jamesroberts.name/blog/2010/02/22/string-functions-for-javascript-trim-to-camel-case-to-dashed-and-to-underscore/
|
|
|
716 |
utils.toDashed = function( str ) {
|
|
|
717 |
return str.replace( /(.)([A-Z])/g, function( match, $1, $2 ) {
|
|
|
718 |
return $1 + '-' + $2;
|
|
|
719 |
}).toLowerCase();
|
|
|
720 |
};
|
|
|
721 |
|
|
|
722 |
var console = window.console;
|
|
|
723 |
/**
|
|
|
724 |
* allow user to initialize classes via [data-namespace] or .js-namespace class
|
|
|
725 |
* htmlInit( Widget, 'widgetName' )
|
|
|
726 |
* options are parsed from data-namespace-options
|
|
|
727 |
*/
|
|
|
728 |
utils.htmlInit = function( WidgetClass, namespace ) {
|
|
|
729 |
utils.docReady( function() {
|
|
|
730 |
var dashedNamespace = utils.toDashed( namespace );
|
|
|
731 |
var dataAttr = 'data-' + dashedNamespace;
|
|
|
732 |
var dataAttrElems = document.querySelectorAll( '[' + dataAttr + ']' );
|
|
|
733 |
var jsDashElems = document.querySelectorAll( '.js-' + dashedNamespace );
|
|
|
734 |
var elems = utils.makeArray( dataAttrElems )
|
|
|
735 |
.concat( utils.makeArray( jsDashElems ) );
|
|
|
736 |
var dataOptionsAttr = dataAttr + '-options';
|
|
|
737 |
var jQuery = window.jQuery;
|
|
|
738 |
|
|
|
739 |
elems.forEach( function( elem ) {
|
|
|
740 |
var attr = elem.getAttribute( dataAttr ) ||
|
|
|
741 |
elem.getAttribute( dataOptionsAttr );
|
|
|
742 |
var options;
|
|
|
743 |
try {
|
|
|
744 |
options = attr && JSON.parse( attr );
|
|
|
745 |
} catch ( error ) {
|
|
|
746 |
// log error, do not initialize
|
|
|
747 |
if ( console ) {
|
|
|
748 |
console.error( 'Error parsing ' + dataAttr + ' on ' + elem.className +
|
|
|
749 |
': ' + error );
|
|
|
750 |
}
|
|
|
751 |
return;
|
|
|
752 |
}
|
|
|
753 |
// initialize
|
|
|
754 |
var instance = new WidgetClass( elem, options );
|
|
|
755 |
// make available via $().data('namespace')
|
|
|
756 |
if ( jQuery ) {
|
|
|
757 |
jQuery.data( elem, namespace, instance );
|
|
|
758 |
}
|
|
|
759 |
});
|
|
|
760 |
|
|
|
761 |
});
|
|
|
762 |
};
|
|
|
763 |
|
|
|
764 |
// ----- ----- //
|
|
|
765 |
|
|
|
766 |
return utils;
|
|
|
767 |
|
|
|
768 |
}));
|
|
|
769 |
|
|
|
770 |
/**
|
|
|
771 |
* Outlayer Item
|
|
|
772 |
*/
|
|
|
773 |
|
|
|
774 |
( function( window, factory ) {
|
|
|
775 |
// universal module definition
|
|
|
776 |
/* jshint strict: false */ /* globals define, module, require */
|
|
|
777 |
if ( typeof define == 'function' && define.amd ) {
|
|
|
778 |
// AMD - RequireJS
|
|
|
779 |
define( 'outlayer/item',[
|
|
|
780 |
'ev-emitter/ev-emitter',
|
|
|
781 |
'get-size/get-size'
|
|
|
782 |
],
|
|
|
783 |
factory
|
|
|
784 |
);
|
|
|
785 |
} else if ( typeof module == 'object' && module.exports ) {
|
|
|
786 |
// CommonJS - Browserify, Webpack
|
|
|
787 |
module.exports = factory(
|
|
|
788 |
require('ev-emitter'),
|
|
|
789 |
require('get-size')
|
|
|
790 |
);
|
|
|
791 |
} else {
|
|
|
792 |
// browser global
|
|
|
793 |
window.Outlayer = {};
|
|
|
794 |
window.Outlayer.Item = factory(
|
|
|
795 |
window.EvEmitter,
|
|
|
796 |
window.getSize
|
|
|
797 |
);
|
|
|
798 |
}
|
|
|
799 |
|
|
|
800 |
}( window, function factory( EvEmitter, getSize ) {
|
|
|
801 |
'use strict';
|
|
|
802 |
|
|
|
803 |
// ----- helpers ----- //
|
|
|
804 |
|
|
|
805 |
function isEmptyObj( obj ) {
|
|
|
806 |
for ( var prop in obj ) {
|
|
|
807 |
return false;
|
|
|
808 |
}
|
|
|
809 |
prop = null;
|
|
|
810 |
return true;
|
|
|
811 |
}
|
|
|
812 |
|
|
|
813 |
// -------------------------- CSS3 support -------------------------- //
|
|
|
814 |
|
|
|
815 |
|
|
|
816 |
var docElemStyle = document.documentElement.style;
|
|
|
817 |
|
|
|
818 |
var transitionProperty = typeof docElemStyle.transition == 'string' ?
|
|
|
819 |
'transition' : 'WebkitTransition';
|
|
|
820 |
var transformProperty = typeof docElemStyle.transform == 'string' ?
|
|
|
821 |
'transform' : 'WebkitTransform';
|
|
|
822 |
|
|
|
823 |
var transitionEndEvent = {
|
|
|
824 |
WebkitTransition: 'webkitTransitionEnd',
|
|
|
825 |
transition: 'transitionend'
|
|
|
826 |
}[ transitionProperty ];
|
|
|
827 |
|
|
|
828 |
// cache all vendor properties that could have vendor prefix
|
|
|
829 |
var vendorProperties = {
|
|
|
830 |
transform: transformProperty,
|
|
|
831 |
transition: transitionProperty,
|
|
|
832 |
transitionDuration: transitionProperty + 'Duration',
|
|
|
833 |
transitionProperty: transitionProperty + 'Property',
|
|
|
834 |
transitionDelay: transitionProperty + 'Delay'
|
|
|
835 |
};
|
|
|
836 |
|
|
|
837 |
// -------------------------- Item -------------------------- //
|
|
|
838 |
|
|
|
839 |
function Item( element, layout ) {
|
|
|
840 |
if ( !element ) {
|
|
|
841 |
return;
|
|
|
842 |
}
|
|
|
843 |
|
|
|
844 |
this.element = element;
|
|
|
845 |
// parent layout class, i.e. Masonry, Isotope, or Packery
|
|
|
846 |
this.layout = layout;
|
|
|
847 |
this.position = {
|
|
|
848 |
x: 0,
|
|
|
849 |
y: 0
|
|
|
850 |
};
|
|
|
851 |
|
|
|
852 |
this._create();
|
|
|
853 |
}
|
|
|
854 |
|
|
|
855 |
// inherit EvEmitter
|
|
|
856 |
var proto = Item.prototype = Object.create( EvEmitter.prototype );
|
|
|
857 |
proto.constructor = Item;
|
|
|
858 |
|
|
|
859 |
proto._create = function() {
|
|
|
860 |
// transition objects
|
|
|
861 |
this._transn = {
|
|
|
862 |
ingProperties: {},
|
|
|
863 |
clean: {},
|
|
|
864 |
onEnd: {}
|
|
|
865 |
};
|
|
|
866 |
|
|
|
867 |
this.css({
|
|
|
868 |
position: 'absolute'
|
|
|
869 |
});
|
|
|
870 |
};
|
|
|
871 |
|
|
|
872 |
// trigger specified handler for event type
|
|
|
873 |
proto.handleEvent = function( event ) {
|
|
|
874 |
var method = 'on' + event.type;
|
|
|
875 |
if ( this[ method ] ) {
|
|
|
876 |
this[ method ]( event );
|
|
|
877 |
}
|
|
|
878 |
};
|
|
|
879 |
|
|
|
880 |
proto.getSize = function() {
|
|
|
881 |
this.size = getSize( this.element );
|
|
|
882 |
};
|
|
|
883 |
|
|
|
884 |
/**
|
|
|
885 |
* apply CSS styles to element
|
|
|
886 |
* @param {Object} style
|
|
|
887 |
*/
|
|
|
888 |
proto.css = function( style ) {
|
|
|
889 |
var elemStyle = this.element.style;
|
|
|
890 |
|
|
|
891 |
for ( var prop in style ) {
|
|
|
892 |
// use vendor property if available
|
|
|
893 |
var supportedProp = vendorProperties[ prop ] || prop;
|
|
|
894 |
elemStyle[ supportedProp ] = style[ prop ];
|
|
|
895 |
}
|
|
|
896 |
};
|
|
|
897 |
|
|
|
898 |
// measure position, and sets it
|
|
|
899 |
proto.getPosition = function() {
|
|
|
900 |
var style = getComputedStyle( this.element );
|
|
|
901 |
var isOriginLeft = this.layout._getOption('originLeft');
|
|
|
902 |
var isOriginTop = this.layout._getOption('originTop');
|
|
|
903 |
var xValue = style[ isOriginLeft ? 'left' : 'right' ];
|
|
|
904 |
var yValue = style[ isOriginTop ? 'top' : 'bottom' ];
|
|
|
905 |
var x = parseFloat( xValue );
|
|
|
906 |
var y = parseFloat( yValue );
|
|
|
907 |
// convert percent to pixels
|
|
|
908 |
var layoutSize = this.layout.size;
|
|
|
909 |
if ( xValue.indexOf('%') != -1 ) {
|
|
|
910 |
x = ( x / 100 ) * layoutSize.width;
|
|
|
911 |
}
|
|
|
912 |
if ( yValue.indexOf('%') != -1 ) {
|
|
|
913 |
y = ( y / 100 ) * layoutSize.height;
|
|
|
914 |
}
|
|
|
915 |
// clean up 'auto' or other non-integer values
|
|
|
916 |
x = isNaN( x ) ? 0 : x;
|
|
|
917 |
y = isNaN( y ) ? 0 : y;
|
|
|
918 |
// remove padding from measurement
|
|
|
919 |
x -= isOriginLeft ? layoutSize.paddingLeft : layoutSize.paddingRight;
|
|
|
920 |
y -= isOriginTop ? layoutSize.paddingTop : layoutSize.paddingBottom;
|
|
|
921 |
|
|
|
922 |
this.position.x = x;
|
|
|
923 |
this.position.y = y;
|
|
|
924 |
};
|
|
|
925 |
|
|
|
926 |
// set settled position, apply padding
|
|
|
927 |
proto.layoutPosition = function() {
|
|
|
928 |
var layoutSize = this.layout.size;
|
|
|
929 |
var style = {};
|
|
|
930 |
var isOriginLeft = this.layout._getOption('originLeft');
|
|
|
931 |
var isOriginTop = this.layout._getOption('originTop');
|
|
|
932 |
|
|
|
933 |
// x
|
|
|
934 |
var xPadding = isOriginLeft ? 'paddingLeft' : 'paddingRight';
|
|
|
935 |
var xProperty = isOriginLeft ? 'left' : 'right';
|
|
|
936 |
var xResetProperty = isOriginLeft ? 'right' : 'left';
|
|
|
937 |
|
|
|
938 |
var x = this.position.x + layoutSize[ xPadding ];
|
|
|
939 |
// set in percentage or pixels
|
|
|
940 |
style[ xProperty ] = this.getXValue( x );
|
|
|
941 |
// reset other property
|
|
|
942 |
style[ xResetProperty ] = '';
|
|
|
943 |
|
|
|
944 |
// y
|
|
|
945 |
var yPadding = isOriginTop ? 'paddingTop' : 'paddingBottom';
|
|
|
946 |
var yProperty = isOriginTop ? 'top' : 'bottom';
|
|
|
947 |
var yResetProperty = isOriginTop ? 'bottom' : 'top';
|
|
|
948 |
|
|
|
949 |
var y = this.position.y + layoutSize[ yPadding ];
|
|
|
950 |
// set in percentage or pixels
|
|
|
951 |
style[ yProperty ] = this.getYValue( y );
|
|
|
952 |
// reset other property
|
|
|
953 |
style[ yResetProperty ] = '';
|
|
|
954 |
|
|
|
955 |
this.css( style );
|
|
|
956 |
this.emitEvent( 'layout', [ this ] );
|
|
|
957 |
};
|
|
|
958 |
|
|
|
959 |
proto.getXValue = function( x ) {
|
|
|
960 |
var isHorizontal = this.layout._getOption('horizontal');
|
|
|
961 |
return this.layout.options.percentPosition && !isHorizontal ?
|
|
|
962 |
( ( x / this.layout.size.width ) * 100 ) + '%' : x + 'px';
|
|
|
963 |
};
|
|
|
964 |
|
|
|
965 |
proto.getYValue = function( y ) {
|
|
|
966 |
var isHorizontal = this.layout._getOption('horizontal');
|
|
|
967 |
return this.layout.options.percentPosition && isHorizontal ?
|
|
|
968 |
( ( y / this.layout.size.height ) * 100 ) + '%' : y + 'px';
|
|
|
969 |
};
|
|
|
970 |
|
|
|
971 |
proto._transitionTo = function( x, y ) {
|
|
|
972 |
this.getPosition();
|
|
|
973 |
// get current x & y from top/left
|
|
|
974 |
var curX = this.position.x;
|
|
|
975 |
var curY = this.position.y;
|
|
|
976 |
|
|
|
977 |
var didNotMove = x == this.position.x && y == this.position.y;
|
|
|
978 |
|
|
|
979 |
// save end position
|
|
|
980 |
this.setPosition( x, y );
|
|
|
981 |
|
|
|
982 |
// if did not move and not transitioning, just go to layout
|
|
|
983 |
if ( didNotMove && !this.isTransitioning ) {
|
|
|
984 |
this.layoutPosition();
|
|
|
985 |
return;
|
|
|
986 |
}
|
|
|
987 |
|
|
|
988 |
var transX = x - curX;
|
|
|
989 |
var transY = y - curY;
|
|
|
990 |
var transitionStyle = {};
|
|
|
991 |
transitionStyle.transform = this.getTranslate( transX, transY );
|
|
|
992 |
|
|
|
993 |
this.transition({
|
|
|
994 |
to: transitionStyle,
|
|
|
995 |
onTransitionEnd: {
|
|
|
996 |
transform: this.layoutPosition
|
|
|
997 |
},
|
|
|
998 |
isCleaning: true
|
|
|
999 |
});
|
|
|
1000 |
};
|
|
|
1001 |
|
|
|
1002 |
proto.getTranslate = function( x, y ) {
|
|
|
1003 |
// flip cooridinates if origin on right or bottom
|
|
|
1004 |
var isOriginLeft = this.layout._getOption('originLeft');
|
|
|
1005 |
var isOriginTop = this.layout._getOption('originTop');
|
|
|
1006 |
x = isOriginLeft ? x : -x;
|
|
|
1007 |
y = isOriginTop ? y : -y;
|
|
|
1008 |
return 'translate3d(' + x + 'px, ' + y + 'px, 0)';
|
|
|
1009 |
};
|
|
|
1010 |
|
|
|
1011 |
// non transition + transform support
|
|
|
1012 |
proto.goTo = function( x, y ) {
|
|
|
1013 |
this.setPosition( x, y );
|
|
|
1014 |
this.layoutPosition();
|
|
|
1015 |
};
|
|
|
1016 |
|
|
|
1017 |
proto.moveTo = proto._transitionTo;
|
|
|
1018 |
|
|
|
1019 |
proto.setPosition = function( x, y ) {
|
|
|
1020 |
this.position.x = parseFloat( x );
|
|
|
1021 |
this.position.y = parseFloat( y );
|
|
|
1022 |
};
|
|
|
1023 |
|
|
|
1024 |
// ----- transition ----- //
|
|
|
1025 |
|
|
|
1026 |
/**
|
|
|
1027 |
* @param {Object} style - CSS
|
|
|
1028 |
* @param {Function} onTransitionEnd
|
|
|
1029 |
*/
|
|
|
1030 |
|
|
|
1031 |
// non transition, just trigger callback
|
|
|
1032 |
proto._nonTransition = function( args ) {
|
|
|
1033 |
this.css( args.to );
|
|
|
1034 |
if ( args.isCleaning ) {
|
|
|
1035 |
this._removeStyles( args.to );
|
|
|
1036 |
}
|
|
|
1037 |
for ( var prop in args.onTransitionEnd ) {
|
|
|
1038 |
args.onTransitionEnd[ prop ].call( this );
|
|
|
1039 |
}
|
|
|
1040 |
};
|
|
|
1041 |
|
|
|
1042 |
/**
|
|
|
1043 |
* proper transition
|
|
|
1044 |
* @param {Object} args - arguments
|
|
|
1045 |
* @param {Object} to - style to transition to
|
|
|
1046 |
* @param {Object} from - style to start transition from
|
|
|
1047 |
* @param {Boolean} isCleaning - removes transition styles after transition
|
|
|
1048 |
* @param {Function} onTransitionEnd - callback
|
|
|
1049 |
*/
|
|
|
1050 |
proto.transition = function( args ) {
|
|
|
1051 |
// redirect to nonTransition if no transition duration
|
|
|
1052 |
if ( !parseFloat( this.layout.options.transitionDuration ) ) {
|
|
|
1053 |
this._nonTransition( args );
|
|
|
1054 |
return;
|
|
|
1055 |
}
|
|
|
1056 |
|
|
|
1057 |
var _transition = this._transn;
|
|
|
1058 |
// keep track of onTransitionEnd callback by css property
|
|
|
1059 |
for ( var prop in args.onTransitionEnd ) {
|
|
|
1060 |
_transition.onEnd[ prop ] = args.onTransitionEnd[ prop ];
|
|
|
1061 |
}
|
|
|
1062 |
// keep track of properties that are transitioning
|
|
|
1063 |
for ( prop in args.to ) {
|
|
|
1064 |
_transition.ingProperties[ prop ] = true;
|
|
|
1065 |
// keep track of properties to clean up when transition is done
|
|
|
1066 |
if ( args.isCleaning ) {
|
|
|
1067 |
_transition.clean[ prop ] = true;
|
|
|
1068 |
}
|
|
|
1069 |
}
|
|
|
1070 |
|
|
|
1071 |
// set from styles
|
|
|
1072 |
if ( args.from ) {
|
|
|
1073 |
this.css( args.from );
|
|
|
1074 |
// force redraw. http://blog.alexmaccaw.com/css-transitions
|
|
|
1075 |
var h = this.element.offsetHeight;
|
|
|
1076 |
// hack for JSHint to hush about unused var
|
|
|
1077 |
h = null;
|
|
|
1078 |
}
|
|
|
1079 |
// enable transition
|
|
|
1080 |
this.enableTransition( args.to );
|
|
|
1081 |
// set styles that are transitioning
|
|
|
1082 |
this.css( args.to );
|
|
|
1083 |
|
|
|
1084 |
this.isTransitioning = true;
|
|
|
1085 |
|
|
|
1086 |
};
|
|
|
1087 |
|
|
|
1088 |
// dash before all cap letters, including first for
|
|
|
1089 |
// WebkitTransform => -webkit-transform
|
|
|
1090 |
function toDashedAll( str ) {
|
|
|
1091 |
return str.replace( /([A-Z])/g, function( $1 ) {
|
|
|
1092 |
return '-' + $1.toLowerCase();
|
|
|
1093 |
});
|
|
|
1094 |
}
|
|
|
1095 |
|
|
|
1096 |
var transitionProps = 'opacity,' + toDashedAll( transformProperty );
|
|
|
1097 |
|
|
|
1098 |
proto.enableTransition = function(/* style */) {
|
|
|
1099 |
// HACK changing transitionProperty during a transition
|
|
|
1100 |
// will cause transition to jump
|
|
|
1101 |
if ( this.isTransitioning ) {
|
|
|
1102 |
return;
|
|
|
1103 |
}
|
|
|
1104 |
|
|
|
1105 |
// make `transition: foo, bar, baz` from style object
|
|
|
1106 |
// HACK un-comment this when enableTransition can work
|
|
|
1107 |
// while a transition is happening
|
|
|
1108 |
// var transitionValues = [];
|
|
|
1109 |
// for ( var prop in style ) {
|
|
|
1110 |
// // dash-ify camelCased properties like WebkitTransition
|
|
|
1111 |
// prop = vendorProperties[ prop ] || prop;
|
|
|
1112 |
// transitionValues.push( toDashedAll( prop ) );
|
|
|
1113 |
// }
|
|
|
1114 |
// munge number to millisecond, to match stagger
|
|
|
1115 |
var duration = this.layout.options.transitionDuration;
|
|
|
1116 |
duration = typeof duration == 'number' ? duration + 'ms' : duration;
|
|
|
1117 |
// enable transition styles
|
|
|
1118 |
this.css({
|
|
|
1119 |
transitionProperty: transitionProps,
|
|
|
1120 |
transitionDuration: duration,
|
|
|
1121 |
transitionDelay: this.staggerDelay || 0
|
|
|
1122 |
});
|
|
|
1123 |
// listen for transition end event
|
|
|
1124 |
this.element.addEventListener( transitionEndEvent, this, false );
|
|
|
1125 |
};
|
|
|
1126 |
|
|
|
1127 |
// ----- events ----- //
|
|
|
1128 |
|
|
|
1129 |
proto.onwebkitTransitionEnd = function( event ) {
|
|
|
1130 |
this.ontransitionend( event );
|
|
|
1131 |
};
|
|
|
1132 |
|
|
|
1133 |
proto.onotransitionend = function( event ) {
|
|
|
1134 |
this.ontransitionend( event );
|
|
|
1135 |
};
|
|
|
1136 |
|
|
|
1137 |
// properties that I munge to make my life easier
|
|
|
1138 |
var dashedVendorProperties = {
|
|
|
1139 |
'-webkit-transform': 'transform'
|
|
|
1140 |
};
|
|
|
1141 |
|
|
|
1142 |
proto.ontransitionend = function( event ) {
|
|
|
1143 |
// disregard bubbled events from children
|
|
|
1144 |
if ( event.target !== this.element ) {
|
|
|
1145 |
return;
|
|
|
1146 |
}
|
|
|
1147 |
var _transition = this._transn;
|
|
|
1148 |
// get property name of transitioned property, convert to prefix-free
|
|
|
1149 |
var propertyName = dashedVendorProperties[ event.propertyName ] || event.propertyName;
|
|
|
1150 |
|
|
|
1151 |
// remove property that has completed transitioning
|
|
|
1152 |
delete _transition.ingProperties[ propertyName ];
|
|
|
1153 |
// check if any properties are still transitioning
|
|
|
1154 |
if ( isEmptyObj( _transition.ingProperties ) ) {
|
|
|
1155 |
// all properties have completed transitioning
|
|
|
1156 |
this.disableTransition();
|
|
|
1157 |
}
|
|
|
1158 |
// clean style
|
|
|
1159 |
if ( propertyName in _transition.clean ) {
|
|
|
1160 |
// clean up style
|
|
|
1161 |
this.element.style[ event.propertyName ] = '';
|
|
|
1162 |
delete _transition.clean[ propertyName ];
|
|
|
1163 |
}
|
|
|
1164 |
// trigger onTransitionEnd callback
|
|
|
1165 |
if ( propertyName in _transition.onEnd ) {
|
|
|
1166 |
var onTransitionEnd = _transition.onEnd[ propertyName ];
|
|
|
1167 |
onTransitionEnd.call( this );
|
|
|
1168 |
delete _transition.onEnd[ propertyName ];
|
|
|
1169 |
}
|
|
|
1170 |
|
|
|
1171 |
this.emitEvent( 'transitionEnd', [ this ] );
|
|
|
1172 |
};
|
|
|
1173 |
|
|
|
1174 |
proto.disableTransition = function() {
|
|
|
1175 |
this.removeTransitionStyles();
|
|
|
1176 |
this.element.removeEventListener( transitionEndEvent, this, false );
|
|
|
1177 |
this.isTransitioning = false;
|
|
|
1178 |
};
|
|
|
1179 |
|
|
|
1180 |
/**
|
|
|
1181 |
* removes style property from element
|
|
|
1182 |
* @param {Object} style
|
|
|
1183 |
**/
|
|
|
1184 |
proto._removeStyles = function( style ) {
|
|
|
1185 |
// clean up transition styles
|
|
|
1186 |
var cleanStyle = {};
|
|
|
1187 |
for ( var prop in style ) {
|
|
|
1188 |
cleanStyle[ prop ] = '';
|
|
|
1189 |
}
|
|
|
1190 |
this.css( cleanStyle );
|
|
|
1191 |
};
|
|
|
1192 |
|
|
|
1193 |
var cleanTransitionStyle = {
|
|
|
1194 |
transitionProperty: '',
|
|
|
1195 |
transitionDuration: '',
|
|
|
1196 |
transitionDelay: ''
|
|
|
1197 |
};
|
|
|
1198 |
|
|
|
1199 |
proto.removeTransitionStyles = function() {
|
|
|
1200 |
// remove transition
|
|
|
1201 |
this.css( cleanTransitionStyle );
|
|
|
1202 |
};
|
|
|
1203 |
|
|
|
1204 |
// ----- stagger ----- //
|
|
|
1205 |
|
|
|
1206 |
proto.stagger = function( delay ) {
|
|
|
1207 |
delay = isNaN( delay ) ? 0 : delay;
|
|
|
1208 |
this.staggerDelay = delay + 'ms';
|
|
|
1209 |
};
|
|
|
1210 |
|
|
|
1211 |
// ----- show/hide/remove ----- //
|
|
|
1212 |
|
|
|
1213 |
// remove element from DOM
|
|
|
1214 |
proto.removeElem = function() {
|
|
|
1215 |
this.element.parentNode.removeChild( this.element );
|
|
|
1216 |
// remove display: none
|
|
|
1217 |
this.css({ display: '' });
|
|
|
1218 |
this.emitEvent( 'remove', [ this ] );
|
|
|
1219 |
};
|
|
|
1220 |
|
|
|
1221 |
proto.remove = function() {
|
|
|
1222 |
// just remove element if no transition support or no transition
|
|
|
1223 |
if ( !transitionProperty || !parseFloat( this.layout.options.transitionDuration ) ) {
|
|
|
1224 |
this.removeElem();
|
|
|
1225 |
return;
|
|
|
1226 |
}
|
|
|
1227 |
|
|
|
1228 |
// start transition
|
|
|
1229 |
this.once( 'transitionEnd', function() {
|
|
|
1230 |
this.removeElem();
|
|
|
1231 |
});
|
|
|
1232 |
this.hide();
|
|
|
1233 |
};
|
|
|
1234 |
|
|
|
1235 |
proto.reveal = function() {
|
|
|
1236 |
delete this.isHidden;
|
|
|
1237 |
// remove display: none
|
|
|
1238 |
this.css({ display: '' });
|
|
|
1239 |
|
|
|
1240 |
var options = this.layout.options;
|
|
|
1241 |
|
|
|
1242 |
var onTransitionEnd = {};
|
|
|
1243 |
var transitionEndProperty = this.getHideRevealTransitionEndProperty('visibleStyle');
|
|
|
1244 |
onTransitionEnd[ transitionEndProperty ] = this.onRevealTransitionEnd;
|
|
|
1245 |
|
|
|
1246 |
this.transition({
|
|
|
1247 |
from: options.hiddenStyle,
|
|
|
1248 |
to: options.visibleStyle,
|
|
|
1249 |
isCleaning: true,
|
|
|
1250 |
onTransitionEnd: onTransitionEnd
|
|
|
1251 |
});
|
|
|
1252 |
};
|
|
|
1253 |
|
|
|
1254 |
proto.onRevealTransitionEnd = function() {
|
|
|
1255 |
// check if still visible
|
|
|
1256 |
// during transition, item may have been hidden
|
|
|
1257 |
if ( !this.isHidden ) {
|
|
|
1258 |
this.emitEvent('reveal');
|
|
|
1259 |
}
|
|
|
1260 |
};
|
|
|
1261 |
|
|
|
1262 |
/**
|
|
|
1263 |
* get style property use for hide/reveal transition end
|
|
|
1264 |
* @param {String} styleProperty - hiddenStyle/visibleStyle
|
|
|
1265 |
* @returns {String}
|
|
|
1266 |
*/
|
|
|
1267 |
proto.getHideRevealTransitionEndProperty = function( styleProperty ) {
|
|
|
1268 |
var optionStyle = this.layout.options[ styleProperty ];
|
|
|
1269 |
// use opacity
|
|
|
1270 |
if ( optionStyle.opacity ) {
|
|
|
1271 |
return 'opacity';
|
|
|
1272 |
}
|
|
|
1273 |
// get first property
|
|
|
1274 |
for ( var prop in optionStyle ) {
|
|
|
1275 |
return prop;
|
|
|
1276 |
}
|
|
|
1277 |
};
|
|
|
1278 |
|
|
|
1279 |
proto.hide = function() {
|
|
|
1280 |
// set flag
|
|
|
1281 |
this.isHidden = true;
|
|
|
1282 |
// remove display: none
|
|
|
1283 |
this.css({ display: '' });
|
|
|
1284 |
|
|
|
1285 |
var options = this.layout.options;
|
|
|
1286 |
|
|
|
1287 |
var onTransitionEnd = {};
|
|
|
1288 |
var transitionEndProperty = this.getHideRevealTransitionEndProperty('hiddenStyle');
|
|
|
1289 |
onTransitionEnd[ transitionEndProperty ] = this.onHideTransitionEnd;
|
|
|
1290 |
|
|
|
1291 |
this.transition({
|
|
|
1292 |
from: options.visibleStyle,
|
|
|
1293 |
to: options.hiddenStyle,
|
|
|
1294 |
// keep hidden stuff hidden
|
|
|
1295 |
isCleaning: true,
|
|
|
1296 |
onTransitionEnd: onTransitionEnd
|
|
|
1297 |
});
|
|
|
1298 |
};
|
|
|
1299 |
|
|
|
1300 |
proto.onHideTransitionEnd = function() {
|
|
|
1301 |
// check if still hidden
|
|
|
1302 |
// during transition, item may have been un-hidden
|
|
|
1303 |
if ( this.isHidden ) {
|
|
|
1304 |
this.css({ display: 'none' });
|
|
|
1305 |
this.emitEvent('hide');
|
|
|
1306 |
}
|
|
|
1307 |
};
|
|
|
1308 |
|
|
|
1309 |
proto.destroy = function() {
|
|
|
1310 |
this.css({
|
|
|
1311 |
position: '',
|
|
|
1312 |
left: '',
|
|
|
1313 |
right: '',
|
|
|
1314 |
top: '',
|
|
|
1315 |
bottom: '',
|
|
|
1316 |
transition: '',
|
|
|
1317 |
transform: ''
|
|
|
1318 |
});
|
|
|
1319 |
};
|
|
|
1320 |
|
|
|
1321 |
return Item;
|
|
|
1322 |
|
|
|
1323 |
}));
|
|
|
1324 |
|
|
|
1325 |
/*!
|
|
|
1326 |
* Outlayer v2.1.1
|
|
|
1327 |
* the brains and guts of a layout library
|
|
|
1328 |
* MIT license
|
|
|
1329 |
*/
|
|
|
1330 |
|
|
|
1331 |
( function( window, factory ) {
|
|
|
1332 |
'use strict';
|
|
|
1333 |
// universal module definition
|
|
|
1334 |
/* jshint strict: false */ /* globals define, module, require */
|
|
|
1335 |
if ( typeof define == 'function' && define.amd ) {
|
|
|
1336 |
// AMD - RequireJS
|
|
|
1337 |
define( 'outlayer/outlayer',[
|
|
|
1338 |
'ev-emitter/ev-emitter',
|
|
|
1339 |
'get-size/get-size',
|
|
|
1340 |
'fizzy-ui-utils/utils',
|
|
|
1341 |
'./item'
|
|
|
1342 |
],
|
|
|
1343 |
function( EvEmitter, getSize, utils, Item ) {
|
|
|
1344 |
return factory( window, EvEmitter, getSize, utils, Item);
|
|
|
1345 |
}
|
|
|
1346 |
);
|
|
|
1347 |
} else if ( typeof module == 'object' && module.exports ) {
|
|
|
1348 |
// CommonJS - Browserify, Webpack
|
|
|
1349 |
module.exports = factory(
|
|
|
1350 |
window,
|
|
|
1351 |
require('ev-emitter'),
|
|
|
1352 |
require('get-size'),
|
|
|
1353 |
require('fizzy-ui-utils'),
|
|
|
1354 |
require('./item')
|
|
|
1355 |
);
|
|
|
1356 |
} else {
|
|
|
1357 |
// browser global
|
|
|
1358 |
window.Outlayer = factory(
|
|
|
1359 |
window,
|
|
|
1360 |
window.EvEmitter,
|
|
|
1361 |
window.getSize,
|
|
|
1362 |
window.fizzyUIUtils,
|
|
|
1363 |
window.Outlayer.Item
|
|
|
1364 |
);
|
|
|
1365 |
}
|
|
|
1366 |
|
|
|
1367 |
}( window, function factory( window, EvEmitter, getSize, utils, Item ) {
|
|
|
1368 |
'use strict';
|
|
|
1369 |
|
|
|
1370 |
// ----- vars ----- //
|
|
|
1371 |
|
|
|
1372 |
var console = window.console;
|
|
|
1373 |
var jQuery = window.jQuery;
|
|
|
1374 |
var noop = function() {};
|
|
|
1375 |
|
|
|
1376 |
// -------------------------- Outlayer -------------------------- //
|
|
|
1377 |
|
|
|
1378 |
// globally unique identifiers
|
|
|
1379 |
var GUID = 0;
|
|
|
1380 |
// internal store of all Outlayer intances
|
|
|
1381 |
var instances = {};
|
|
|
1382 |
|
|
|
1383 |
|
|
|
1384 |
/**
|
|
|
1385 |
* @param {Element, String} element
|
|
|
1386 |
* @param {Object} options
|
|
|
1387 |
* @constructor
|
|
|
1388 |
*/
|
|
|
1389 |
function Outlayer( element, options ) {
|
|
|
1390 |
var queryElement = utils.getQueryElement( element );
|
|
|
1391 |
if ( !queryElement ) {
|
|
|
1392 |
if ( console ) {
|
|
|
1393 |
console.error( 'Bad element for ' + this.constructor.namespace +
|
|
|
1394 |
': ' + ( queryElement || element ) );
|
|
|
1395 |
}
|
|
|
1396 |
return;
|
|
|
1397 |
}
|
|
|
1398 |
this.element = queryElement;
|
|
|
1399 |
// add jQuery
|
|
|
1400 |
if ( jQuery ) {
|
|
|
1401 |
this.$element = jQuery( this.element );
|
|
|
1402 |
}
|
|
|
1403 |
|
|
|
1404 |
// options
|
|
|
1405 |
this.options = utils.extend( {}, this.constructor.defaults );
|
|
|
1406 |
this.option( options );
|
|
|
1407 |
|
|
|
1408 |
// add id for Outlayer.getFromElement
|
|
|
1409 |
var id = ++GUID;
|
|
|
1410 |
this.element.outlayerGUID = id; // expando
|
|
|
1411 |
instances[ id ] = this; // associate via id
|
|
|
1412 |
|
|
|
1413 |
// kick it off
|
|
|
1414 |
this._create();
|
|
|
1415 |
|
|
|
1416 |
var isInitLayout = this._getOption('initLayout');
|
|
|
1417 |
if ( isInitLayout ) {
|
|
|
1418 |
this.layout();
|
|
|
1419 |
}
|
|
|
1420 |
}
|
|
|
1421 |
|
|
|
1422 |
// settings are for internal use only
|
|
|
1423 |
Outlayer.namespace = 'outlayer';
|
|
|
1424 |
Outlayer.Item = Item;
|
|
|
1425 |
|
|
|
1426 |
// default options
|
|
|
1427 |
Outlayer.defaults = {
|
|
|
1428 |
containerStyle: {
|
|
|
1429 |
position: 'relative'
|
|
|
1430 |
},
|
|
|
1431 |
initLayout: true,
|
|
|
1432 |
originLeft: true,
|
|
|
1433 |
originTop: true,
|
|
|
1434 |
resize: true,
|
|
|
1435 |
resizeContainer: true,
|
|
|
1436 |
// item options
|
|
|
1437 |
transitionDuration: '0.4s',
|
|
|
1438 |
hiddenStyle: {
|
|
|
1439 |
opacity: 0,
|
|
|
1440 |
transform: 'scale(0.001)'
|
|
|
1441 |
},
|
|
|
1442 |
visibleStyle: {
|
|
|
1443 |
opacity: 1,
|
|
|
1444 |
transform: 'scale(1)'
|
|
|
1445 |
}
|
|
|
1446 |
};
|
|
|
1447 |
|
|
|
1448 |
var proto = Outlayer.prototype;
|
|
|
1449 |
// inherit EvEmitter
|
|
|
1450 |
utils.extend( proto, EvEmitter.prototype );
|
|
|
1451 |
|
|
|
1452 |
/**
|
|
|
1453 |
* set options
|
|
|
1454 |
* @param {Object} opts
|
|
|
1455 |
*/
|
|
|
1456 |
proto.option = function( opts ) {
|
|
|
1457 |
utils.extend( this.options, opts );
|
|
|
1458 |
};
|
|
|
1459 |
|
|
|
1460 |
/**
|
|
|
1461 |
* get backwards compatible option value, check old name
|
|
|
1462 |
*/
|
|
|
1463 |
proto._getOption = function( option ) {
|
|
|
1464 |
var oldOption = this.constructor.compatOptions[ option ];
|
|
|
1465 |
return oldOption && this.options[ oldOption ] !== undefined ?
|
|
|
1466 |
this.options[ oldOption ] : this.options[ option ];
|
|
|
1467 |
};
|
|
|
1468 |
|
|
|
1469 |
Outlayer.compatOptions = {
|
|
|
1470 |
// currentName: oldName
|
|
|
1471 |
initLayout: 'isInitLayout',
|
|
|
1472 |
horizontal: 'isHorizontal',
|
|
|
1473 |
layoutInstant: 'isLayoutInstant',
|
|
|
1474 |
originLeft: 'isOriginLeft',
|
|
|
1475 |
originTop: 'isOriginTop',
|
|
|
1476 |
resize: 'isResizeBound',
|
|
|
1477 |
resizeContainer: 'isResizingContainer'
|
|
|
1478 |
};
|
|
|
1479 |
|
|
|
1480 |
proto._create = function() {
|
|
|
1481 |
// get items from children
|
|
|
1482 |
this.reloadItems();
|
|
|
1483 |
// elements that affect layout, but are not laid out
|
|
|
1484 |
this.stamps = [];
|
|
|
1485 |
this.stamp( this.options.stamp );
|
|
|
1486 |
// set container style
|
|
|
1487 |
utils.extend( this.element.style, this.options.containerStyle );
|
|
|
1488 |
|
|
|
1489 |
// bind resize method
|
|
|
1490 |
var canBindResize = this._getOption('resize');
|
|
|
1491 |
if ( canBindResize ) {
|
|
|
1492 |
this.bindResize();
|
|
|
1493 |
}
|
|
|
1494 |
};
|
|
|
1495 |
|
|
|
1496 |
// goes through all children again and gets bricks in proper order
|
|
|
1497 |
proto.reloadItems = function() {
|
|
|
1498 |
// collection of item elements
|
|
|
1499 |
this.items = this._itemize( this.element.children );
|
|
|
1500 |
};
|
|
|
1501 |
|
|
|
1502 |
|
|
|
1503 |
/**
|
|
|
1504 |
* turn elements into Outlayer.Items to be used in layout
|
|
|
1505 |
* @param {Array or NodeList or HTMLElement} elems
|
|
|
1506 |
* @returns {Array} items - collection of new Outlayer Items
|
|
|
1507 |
*/
|
|
|
1508 |
proto._itemize = function( elems ) {
|
|
|
1509 |
|
|
|
1510 |
var itemElems = this._filterFindItemElements( elems );
|
|
|
1511 |
var Item = this.constructor.Item;
|
|
|
1512 |
|
|
|
1513 |
// create new Outlayer Items for collection
|
|
|
1514 |
var items = [];
|
|
|
1515 |
for ( var i=0; i < itemElems.length; i++ ) {
|
|
|
1516 |
var elem = itemElems[i];
|
|
|
1517 |
var item = new Item( elem, this );
|
|
|
1518 |
items.push( item );
|
|
|
1519 |
}
|
|
|
1520 |
|
|
|
1521 |
return items;
|
|
|
1522 |
};
|
|
|
1523 |
|
|
|
1524 |
/**
|
|
|
1525 |
* get item elements to be used in layout
|
|
|
1526 |
* @param {Array or NodeList or HTMLElement} elems
|
|
|
1527 |
* @returns {Array} items - item elements
|
|
|
1528 |
*/
|
|
|
1529 |
proto._filterFindItemElements = function( elems ) {
|
|
|
1530 |
return utils.filterFindElements( elems, this.options.itemSelector );
|
|
|
1531 |
};
|
|
|
1532 |
|
|
|
1533 |
/**
|
|
|
1534 |
* getter method for getting item elements
|
|
|
1535 |
* @returns {Array} elems - collection of item elements
|
|
|
1536 |
*/
|
|
|
1537 |
proto.getItemElements = function() {
|
|
|
1538 |
return this.items.map( function( item ) {
|
|
|
1539 |
return item.element;
|
|
|
1540 |
});
|
|
|
1541 |
};
|
|
|
1542 |
|
|
|
1543 |
// ----- init & layout ----- //
|
|
|
1544 |
|
|
|
1545 |
/**
|
|
|
1546 |
* lays out all items
|
|
|
1547 |
*/
|
|
|
1548 |
proto.layout = function() {
|
|
|
1549 |
this._resetLayout();
|
|
|
1550 |
this._manageStamps();
|
|
|
1551 |
|
|
|
1552 |
// don't animate first layout
|
|
|
1553 |
var layoutInstant = this._getOption('layoutInstant');
|
|
|
1554 |
var isInstant = layoutInstant !== undefined ?
|
|
|
1555 |
layoutInstant : !this._isLayoutInited;
|
|
|
1556 |
this.layoutItems( this.items, isInstant );
|
|
|
1557 |
|
|
|
1558 |
// flag for initalized
|
|
|
1559 |
this._isLayoutInited = true;
|
|
|
1560 |
};
|
|
|
1561 |
|
|
|
1562 |
// _init is alias for layout
|
|
|
1563 |
proto._init = proto.layout;
|
|
|
1564 |
|
|
|
1565 |
/**
|
|
|
1566 |
* logic before any new layout
|
|
|
1567 |
*/
|
|
|
1568 |
proto._resetLayout = function() {
|
|
|
1569 |
this.getSize();
|
|
|
1570 |
};
|
|
|
1571 |
|
|
|
1572 |
|
|
|
1573 |
proto.getSize = function() {
|
|
|
1574 |
this.size = getSize( this.element );
|
|
|
1575 |
};
|
|
|
1576 |
|
|
|
1577 |
/**
|
|
|
1578 |
* get measurement from option, for columnWidth, rowHeight, gutter
|
|
|
1579 |
* if option is String -> get element from selector string, & get size of element
|
|
|
1580 |
* if option is Element -> get size of element
|
|
|
1581 |
* else use option as a number
|
|
|
1582 |
*
|
|
|
1583 |
* @param {String} measurement
|
|
|
1584 |
* @param {String} size - width or height
|
|
|
1585 |
* @private
|
|
|
1586 |
*/
|
|
|
1587 |
proto._getMeasurement = function( measurement, size ) {
|
|
|
1588 |
var option = this.options[ measurement ];
|
|
|
1589 |
var elem;
|
|
|
1590 |
if ( !option ) {
|
|
|
1591 |
// default to 0
|
|
|
1592 |
this[ measurement ] = 0;
|
|
|
1593 |
} else {
|
|
|
1594 |
// use option as an element
|
|
|
1595 |
if ( typeof option == 'string' ) {
|
|
|
1596 |
elem = this.element.querySelector( option );
|
|
|
1597 |
} else if ( option instanceof HTMLElement ) {
|
|
|
1598 |
elem = option;
|
|
|
1599 |
}
|
|
|
1600 |
// use size of element, if element
|
|
|
1601 |
this[ measurement ] = elem ? getSize( elem )[ size ] : option;
|
|
|
1602 |
}
|
|
|
1603 |
};
|
|
|
1604 |
|
|
|
1605 |
/**
|
|
|
1606 |
* layout a collection of item elements
|
|
|
1607 |
* @api public
|
|
|
1608 |
*/
|
|
|
1609 |
proto.layoutItems = function( items, isInstant ) {
|
|
|
1610 |
items = this._getItemsForLayout( items );
|
|
|
1611 |
|
|
|
1612 |
this._layoutItems( items, isInstant );
|
|
|
1613 |
|
|
|
1614 |
this._postLayout();
|
|
|
1615 |
};
|
|
|
1616 |
|
|
|
1617 |
/**
|
|
|
1618 |
* get the items to be laid out
|
|
|
1619 |
* you may want to skip over some items
|
|
|
1620 |
* @param {Array} items
|
|
|
1621 |
* @returns {Array} items
|
|
|
1622 |
*/
|
|
|
1623 |
proto._getItemsForLayout = function( items ) {
|
|
|
1624 |
return items.filter( function( item ) {
|
|
|
1625 |
return !item.isIgnored;
|
|
|
1626 |
});
|
|
|
1627 |
};
|
|
|
1628 |
|
|
|
1629 |
/**
|
|
|
1630 |
* layout items
|
|
|
1631 |
* @param {Array} items
|
|
|
1632 |
* @param {Boolean} isInstant
|
|
|
1633 |
*/
|
|
|
1634 |
proto._layoutItems = function( items, isInstant ) {
|
|
|
1635 |
this._emitCompleteOnItems( 'layout', items );
|
|
|
1636 |
|
|
|
1637 |
if ( !items || !items.length ) {
|
|
|
1638 |
// no items, emit event with empty array
|
|
|
1639 |
return;
|
|
|
1640 |
}
|
|
|
1641 |
|
|
|
1642 |
var queue = [];
|
|
|
1643 |
|
|
|
1644 |
items.forEach( function( item ) {
|
|
|
1645 |
// get x/y object from method
|
|
|
1646 |
var position = this._getItemLayoutPosition( item );
|
|
|
1647 |
// enqueue
|
|
|
1648 |
position.item = item;
|
|
|
1649 |
position.isInstant = isInstant || item.isLayoutInstant;
|
|
|
1650 |
queue.push( position );
|
|
|
1651 |
}, this );
|
|
|
1652 |
|
|
|
1653 |
this._processLayoutQueue( queue );
|
|
|
1654 |
};
|
|
|
1655 |
|
|
|
1656 |
/**
|
|
|
1657 |
* get item layout position
|
|
|
1658 |
* @param {Outlayer.Item} item
|
|
|
1659 |
* @returns {Object} x and y position
|
|
|
1660 |
*/
|
|
|
1661 |
proto._getItemLayoutPosition = function( /* item */ ) {
|
|
|
1662 |
return {
|
|
|
1663 |
x: 0,
|
|
|
1664 |
y: 0
|
|
|
1665 |
};
|
|
|
1666 |
};
|
|
|
1667 |
|
|
|
1668 |
/**
|
|
|
1669 |
* iterate over array and position each item
|
|
|
1670 |
* Reason being - separating this logic prevents 'layout invalidation'
|
|
|
1671 |
* thx @paul_irish
|
|
|
1672 |
* @param {Array} queue
|
|
|
1673 |
*/
|
|
|
1674 |
proto._processLayoutQueue = function( queue ) {
|
|
|
1675 |
this.updateStagger();
|
|
|
1676 |
queue.forEach( function( obj, i ) {
|
|
|
1677 |
this._positionItem( obj.item, obj.x, obj.y, obj.isInstant, i );
|
|
|
1678 |
}, this );
|
|
|
1679 |
};
|
|
|
1680 |
|
|
|
1681 |
// set stagger from option in milliseconds number
|
|
|
1682 |
proto.updateStagger = function() {
|
|
|
1683 |
var stagger = this.options.stagger;
|
|
|
1684 |
if ( stagger === null || stagger === undefined ) {
|
|
|
1685 |
this.stagger = 0;
|
|
|
1686 |
return;
|
|
|
1687 |
}
|
|
|
1688 |
this.stagger = getMilliseconds( stagger );
|
|
|
1689 |
return this.stagger;
|
|
|
1690 |
};
|
|
|
1691 |
|
|
|
1692 |
/**
|
|
|
1693 |
* Sets position of item in DOM
|
|
|
1694 |
* @param {Outlayer.Item} item
|
|
|
1695 |
* @param {Number} x - horizontal position
|
|
|
1696 |
* @param {Number} y - vertical position
|
|
|
1697 |
* @param {Boolean} isInstant - disables transitions
|
|
|
1698 |
*/
|
|
|
1699 |
proto._positionItem = function( item, x, y, isInstant, i ) {
|
|
|
1700 |
if ( isInstant ) {
|
|
|
1701 |
// if not transition, just set CSS
|
|
|
1702 |
item.goTo( x, y );
|
|
|
1703 |
} else {
|
|
|
1704 |
item.stagger( i * this.stagger );
|
|
|
1705 |
item.moveTo( x, y );
|
|
|
1706 |
}
|
|
|
1707 |
};
|
|
|
1708 |
|
|
|
1709 |
/**
|
|
|
1710 |
* Any logic you want to do after each layout,
|
|
|
1711 |
* i.e. size the container
|
|
|
1712 |
*/
|
|
|
1713 |
proto._postLayout = function() {
|
|
|
1714 |
this.resizeContainer();
|
|
|
1715 |
};
|
|
|
1716 |
|
|
|
1717 |
proto.resizeContainer = function() {
|
|
|
1718 |
var isResizingContainer = this._getOption('resizeContainer');
|
|
|
1719 |
if ( !isResizingContainer ) {
|
|
|
1720 |
return;
|
|
|
1721 |
}
|
|
|
1722 |
var size = this._getContainerSize();
|
|
|
1723 |
if ( size ) {
|
|
|
1724 |
this._setContainerMeasure( size.width, true );
|
|
|
1725 |
this._setContainerMeasure( size.height, false );
|
|
|
1726 |
}
|
|
|
1727 |
};
|
|
|
1728 |
|
|
|
1729 |
/**
|
|
|
1730 |
* Sets width or height of container if returned
|
|
|
1731 |
* @returns {Object} size
|
|
|
1732 |
* @param {Number} width
|
|
|
1733 |
* @param {Number} height
|
|
|
1734 |
*/
|
|
|
1735 |
proto._getContainerSize = noop;
|
|
|
1736 |
|
|
|
1737 |
/**
|
|
|
1738 |
* @param {Number} measure - size of width or height
|
|
|
1739 |
* @param {Boolean} isWidth
|
|
|
1740 |
*/
|
|
|
1741 |
proto._setContainerMeasure = function( measure, isWidth ) {
|
|
|
1742 |
if ( measure === undefined ) {
|
|
|
1743 |
return;
|
|
|
1744 |
}
|
|
|
1745 |
|
|
|
1746 |
var elemSize = this.size;
|
|
|
1747 |
// add padding and border width if border box
|
|
|
1748 |
if ( elemSize.isBorderBox ) {
|
|
|
1749 |
measure += isWidth ? elemSize.paddingLeft + elemSize.paddingRight +
|
|
|
1750 |
elemSize.borderLeftWidth + elemSize.borderRightWidth :
|
|
|
1751 |
elemSize.paddingBottom + elemSize.paddingTop +
|
|
|
1752 |
elemSize.borderTopWidth + elemSize.borderBottomWidth;
|
|
|
1753 |
}
|
|
|
1754 |
|
|
|
1755 |
measure = Math.max( measure, 0 );
|
|
|
1756 |
this.element.style[ isWidth ? 'width' : 'height' ] = measure + 'px';
|
|
|
1757 |
};
|
|
|
1758 |
|
|
|
1759 |
/**
|
|
|
1760 |
* emit eventComplete on a collection of items events
|
|
|
1761 |
* @param {String} eventName
|
|
|
1762 |
* @param {Array} items - Outlayer.Items
|
|
|
1763 |
*/
|
|
|
1764 |
proto._emitCompleteOnItems = function( eventName, items ) {
|
|
|
1765 |
var _this = this;
|
|
|
1766 |
function onComplete() {
|
|
|
1767 |
_this.dispatchEvent( eventName + 'Complete', null, [ items ] );
|
|
|
1768 |
}
|
|
|
1769 |
|
|
|
1770 |
var count = items.length;
|
|
|
1771 |
if ( !items || !count ) {
|
|
|
1772 |
onComplete();
|
|
|
1773 |
return;
|
|
|
1774 |
}
|
|
|
1775 |
|
|
|
1776 |
var doneCount = 0;
|
|
|
1777 |
function tick() {
|
|
|
1778 |
doneCount++;
|
|
|
1779 |
if ( doneCount == count ) {
|
|
|
1780 |
onComplete();
|
|
|
1781 |
}
|
|
|
1782 |
}
|
|
|
1783 |
|
|
|
1784 |
// bind callback
|
|
|
1785 |
items.forEach( function( item ) {
|
|
|
1786 |
item.once( eventName, tick );
|
|
|
1787 |
});
|
|
|
1788 |
};
|
|
|
1789 |
|
|
|
1790 |
/**
|
|
|
1791 |
* emits events via EvEmitter and jQuery events
|
|
|
1792 |
* @param {String} type - name of event
|
|
|
1793 |
* @param {Event} event - original event
|
|
|
1794 |
* @param {Array} args - extra arguments
|
|
|
1795 |
*/
|
|
|
1796 |
proto.dispatchEvent = function( type, event, args ) {
|
|
|
1797 |
// add original event to arguments
|
|
|
1798 |
var emitArgs = event ? [ event ].concat( args ) : args;
|
|
|
1799 |
this.emitEvent( type, emitArgs );
|
|
|
1800 |
|
|
|
1801 |
if ( jQuery ) {
|
|
|
1802 |
// set this.$element
|
|
|
1803 |
this.$element = this.$element || jQuery( this.element );
|
|
|
1804 |
if ( event ) {
|
|
|
1805 |
// create jQuery event
|
|
|
1806 |
var $event = jQuery.Event( event );
|
|
|
1807 |
$event.type = type;
|
|
|
1808 |
this.$element.trigger( $event, args );
|
|
|
1809 |
} else {
|
|
|
1810 |
// just trigger with type if no event available
|
|
|
1811 |
this.$element.trigger( type, args );
|
|
|
1812 |
}
|
|
|
1813 |
}
|
|
|
1814 |
};
|
|
|
1815 |
|
|
|
1816 |
// -------------------------- ignore & stamps -------------------------- //
|
|
|
1817 |
|
|
|
1818 |
|
|
|
1819 |
/**
|
|
|
1820 |
* keep item in collection, but do not lay it out
|
|
|
1821 |
* ignored items do not get skipped in layout
|
|
|
1822 |
* @param {Element} elem
|
|
|
1823 |
*/
|
|
|
1824 |
proto.ignore = function( elem ) {
|
|
|
1825 |
var item = this.getItem( elem );
|
|
|
1826 |
if ( item ) {
|
|
|
1827 |
item.isIgnored = true;
|
|
|
1828 |
}
|
|
|
1829 |
};
|
|
|
1830 |
|
|
|
1831 |
/**
|
|
|
1832 |
* return item to layout collection
|
|
|
1833 |
* @param {Element} elem
|
|
|
1834 |
*/
|
|
|
1835 |
proto.unignore = function( elem ) {
|
|
|
1836 |
var item = this.getItem( elem );
|
|
|
1837 |
if ( item ) {
|
|
|
1838 |
delete item.isIgnored;
|
|
|
1839 |
}
|
|
|
1840 |
};
|
|
|
1841 |
|
|
|
1842 |
/**
|
|
|
1843 |
* adds elements to stamps
|
|
|
1844 |
* @param {NodeList, Array, Element, or String} elems
|
|
|
1845 |
*/
|
|
|
1846 |
proto.stamp = function( elems ) {
|
|
|
1847 |
elems = this._find( elems );
|
|
|
1848 |
if ( !elems ) {
|
|
|
1849 |
return;
|
|
|
1850 |
}
|
|
|
1851 |
|
|
|
1852 |
this.stamps = this.stamps.concat( elems );
|
|
|
1853 |
// ignore
|
|
|
1854 |
elems.forEach( this.ignore, this );
|
|
|
1855 |
};
|
|
|
1856 |
|
|
|
1857 |
/**
|
|
|
1858 |
* removes elements to stamps
|
|
|
1859 |
* @param {NodeList, Array, or Element} elems
|
|
|
1860 |
*/
|
|
|
1861 |
proto.unstamp = function( elems ) {
|
|
|
1862 |
elems = this._find( elems );
|
|
|
1863 |
if ( !elems ){
|
|
|
1864 |
return;
|
|
|
1865 |
}
|
|
|
1866 |
|
|
|
1867 |
elems.forEach( function( elem ) {
|
|
|
1868 |
// filter out removed stamp elements
|
|
|
1869 |
utils.removeFrom( this.stamps, elem );
|
|
|
1870 |
this.unignore( elem );
|
|
|
1871 |
}, this );
|
|
|
1872 |
};
|
|
|
1873 |
|
|
|
1874 |
/**
|
|
|
1875 |
* finds child elements
|
|
|
1876 |
* @param {NodeList, Array, Element, or String} elems
|
|
|
1877 |
* @returns {Array} elems
|
|
|
1878 |
*/
|
|
|
1879 |
proto._find = function( elems ) {
|
|
|
1880 |
if ( !elems ) {
|
|
|
1881 |
return;
|
|
|
1882 |
}
|
|
|
1883 |
// if string, use argument as selector string
|
|
|
1884 |
if ( typeof elems == 'string' ) {
|
|
|
1885 |
elems = this.element.querySelectorAll( elems );
|
|
|
1886 |
}
|
|
|
1887 |
elems = utils.makeArray( elems );
|
|
|
1888 |
return elems;
|
|
|
1889 |
};
|
|
|
1890 |
|
|
|
1891 |
proto._manageStamps = function() {
|
|
|
1892 |
if ( !this.stamps || !this.stamps.length ) {
|
|
|
1893 |
return;
|
|
|
1894 |
}
|
|
|
1895 |
|
|
|
1896 |
this._getBoundingRect();
|
|
|
1897 |
|
|
|
1898 |
this.stamps.forEach( this._manageStamp, this );
|
|
|
1899 |
};
|
|
|
1900 |
|
|
|
1901 |
// update boundingLeft / Top
|
|
|
1902 |
proto._getBoundingRect = function() {
|
|
|
1903 |
// get bounding rect for container element
|
|
|
1904 |
var boundingRect = this.element.getBoundingClientRect();
|
|
|
1905 |
var size = this.size;
|
|
|
1906 |
this._boundingRect = {
|
|
|
1907 |
left: boundingRect.left + size.paddingLeft + size.borderLeftWidth,
|
|
|
1908 |
top: boundingRect.top + size.paddingTop + size.borderTopWidth,
|
|
|
1909 |
right: boundingRect.right - ( size.paddingRight + size.borderRightWidth ),
|
|
|
1910 |
bottom: boundingRect.bottom - ( size.paddingBottom + size.borderBottomWidth )
|
|
|
1911 |
};
|
|
|
1912 |
};
|
|
|
1913 |
|
|
|
1914 |
/**
|
|
|
1915 |
* @param {Element} stamp
|
|
|
1916 |
**/
|
|
|
1917 |
proto._manageStamp = noop;
|
|
|
1918 |
|
|
|
1919 |
/**
|
|
|
1920 |
* get x/y position of element relative to container element
|
|
|
1921 |
* @param {Element} elem
|
|
|
1922 |
* @returns {Object} offset - has left, top, right, bottom
|
|
|
1923 |
*/
|
|
|
1924 |
proto._getElementOffset = function( elem ) {
|
|
|
1925 |
var boundingRect = elem.getBoundingClientRect();
|
|
|
1926 |
var thisRect = this._boundingRect;
|
|
|
1927 |
var size = getSize( elem );
|
|
|
1928 |
var offset = {
|
|
|
1929 |
left: boundingRect.left - thisRect.left - size.marginLeft,
|
|
|
1930 |
top: boundingRect.top - thisRect.top - size.marginTop,
|
|
|
1931 |
right: thisRect.right - boundingRect.right - size.marginRight,
|
|
|
1932 |
bottom: thisRect.bottom - boundingRect.bottom - size.marginBottom
|
|
|
1933 |
};
|
|
|
1934 |
return offset;
|
|
|
1935 |
};
|
|
|
1936 |
|
|
|
1937 |
// -------------------------- resize -------------------------- //
|
|
|
1938 |
|
|
|
1939 |
// enable event handlers for listeners
|
|
|
1940 |
// i.e. resize -> onresize
|
|
|
1941 |
proto.handleEvent = utils.handleEvent;
|
|
|
1942 |
|
|
|
1943 |
/**
|
|
|
1944 |
* Bind layout to window resizing
|
|
|
1945 |
*/
|
|
|
1946 |
proto.bindResize = function() {
|
|
|
1947 |
window.addEventListener( 'resize', this );
|
|
|
1948 |
this.isResizeBound = true;
|
|
|
1949 |
};
|
|
|
1950 |
|
|
|
1951 |
/**
|
|
|
1952 |
* Unbind layout to window resizing
|
|
|
1953 |
*/
|
|
|
1954 |
proto.unbindResize = function() {
|
|
|
1955 |
window.removeEventListener( 'resize', this );
|
|
|
1956 |
this.isResizeBound = false;
|
|
|
1957 |
};
|
|
|
1958 |
|
|
|
1959 |
proto.onresize = function() {
|
|
|
1960 |
this.resize();
|
|
|
1961 |
};
|
|
|
1962 |
|
|
|
1963 |
utils.debounceMethod( Outlayer, 'onresize', 100 );
|
|
|
1964 |
|
|
|
1965 |
proto.resize = function() {
|
|
|
1966 |
// don't trigger if size did not change
|
|
|
1967 |
// or if resize was unbound. See #9
|
|
|
1968 |
if ( !this.isResizeBound || !this.needsResizeLayout() ) {
|
|
|
1969 |
return;
|
|
|
1970 |
}
|
|
|
1971 |
|
|
|
1972 |
this.layout();
|
|
|
1973 |
};
|
|
|
1974 |
|
|
|
1975 |
/**
|
|
|
1976 |
* check if layout is needed post layout
|
|
|
1977 |
* @returns Boolean
|
|
|
1978 |
*/
|
|
|
1979 |
proto.needsResizeLayout = function() {
|
|
|
1980 |
var size = getSize( this.element );
|
|
|
1981 |
// check that this.size and size are there
|
|
|
1982 |
// IE8 triggers resize on body size change, so they might not be
|
|
|
1983 |
var hasSizes = this.size && size;
|
|
|
1984 |
return hasSizes && size.innerWidth !== this.size.innerWidth;
|
|
|
1985 |
};
|
|
|
1986 |
|
|
|
1987 |
// -------------------------- methods -------------------------- //
|
|
|
1988 |
|
|
|
1989 |
/**
|
|
|
1990 |
* add items to Outlayer instance
|
|
|
1991 |
* @param {Array or NodeList or Element} elems
|
|
|
1992 |
* @returns {Array} items - Outlayer.Items
|
|
|
1993 |
**/
|
|
|
1994 |
proto.addItems = function( elems ) {
|
|
|
1995 |
var items = this._itemize( elems );
|
|
|
1996 |
// add items to collection
|
|
|
1997 |
if ( items.length ) {
|
|
|
1998 |
this.items = this.items.concat( items );
|
|
|
1999 |
}
|
|
|
2000 |
return items;
|
|
|
2001 |
};
|
|
|
2002 |
|
|
|
2003 |
/**
|
|
|
2004 |
* Layout newly-appended item elements
|
|
|
2005 |
* @param {Array or NodeList or Element} elems
|
|
|
2006 |
*/
|
|
|
2007 |
proto.appended = function( elems ) {
|
|
|
2008 |
var items = this.addItems( elems );
|
|
|
2009 |
if ( !items.length ) {
|
|
|
2010 |
return;
|
|
|
2011 |
}
|
|
|
2012 |
// layout and reveal just the new items
|
|
|
2013 |
this.layoutItems( items, true );
|
|
|
2014 |
this.reveal( items );
|
|
|
2015 |
};
|
|
|
2016 |
|
|
|
2017 |
/**
|
|
|
2018 |
* Layout prepended elements
|
|
|
2019 |
* @param {Array or NodeList or Element} elems
|
|
|
2020 |
*/
|
|
|
2021 |
proto.prepended = function( elems ) {
|
|
|
2022 |
var items = this._itemize( elems );
|
|
|
2023 |
if ( !items.length ) {
|
|
|
2024 |
return;
|
|
|
2025 |
}
|
|
|
2026 |
// add items to beginning of collection
|
|
|
2027 |
var previousItems = this.items.slice(0);
|
|
|
2028 |
this.items = items.concat( previousItems );
|
|
|
2029 |
// start new layout
|
|
|
2030 |
this._resetLayout();
|
|
|
2031 |
this._manageStamps();
|
|
|
2032 |
// layout new stuff without transition
|
|
|
2033 |
this.layoutItems( items, true );
|
|
|
2034 |
this.reveal( items );
|
|
|
2035 |
// layout previous items
|
|
|
2036 |
this.layoutItems( previousItems );
|
|
|
2037 |
};
|
|
|
2038 |
|
|
|
2039 |
/**
|
|
|
2040 |
* reveal a collection of items
|
|
|
2041 |
* @param {Array of Outlayer.Items} items
|
|
|
2042 |
*/
|
|
|
2043 |
proto.reveal = function( items ) {
|
|
|
2044 |
this._emitCompleteOnItems( 'reveal', items );
|
|
|
2045 |
if ( !items || !items.length ) {
|
|
|
2046 |
return;
|
|
|
2047 |
}
|
|
|
2048 |
var stagger = this.updateStagger();
|
|
|
2049 |
items.forEach( function( item, i ) {
|
|
|
2050 |
item.stagger( i * stagger );
|
|
|
2051 |
item.reveal();
|
|
|
2052 |
});
|
|
|
2053 |
};
|
|
|
2054 |
|
|
|
2055 |
/**
|
|
|
2056 |
* hide a collection of items
|
|
|
2057 |
* @param {Array of Outlayer.Items} items
|
|
|
2058 |
*/
|
|
|
2059 |
proto.hide = function( items ) {
|
|
|
2060 |
this._emitCompleteOnItems( 'hide', items );
|
|
|
2061 |
if ( !items || !items.length ) {
|
|
|
2062 |
return;
|
|
|
2063 |
}
|
|
|
2064 |
var stagger = this.updateStagger();
|
|
|
2065 |
items.forEach( function( item, i ) {
|
|
|
2066 |
item.stagger( i * stagger );
|
|
|
2067 |
item.hide();
|
|
|
2068 |
});
|
|
|
2069 |
};
|
|
|
2070 |
|
|
|
2071 |
/**
|
|
|
2072 |
* reveal item elements
|
|
|
2073 |
* @param {Array}, {Element}, {NodeList} items
|
|
|
2074 |
*/
|
|
|
2075 |
proto.revealItemElements = function( elems ) {
|
|
|
2076 |
var items = this.getItems( elems );
|
|
|
2077 |
this.reveal( items );
|
|
|
2078 |
};
|
|
|
2079 |
|
|
|
2080 |
/**
|
|
|
2081 |
* hide item elements
|
|
|
2082 |
* @param {Array}, {Element}, {NodeList} items
|
|
|
2083 |
*/
|
|
|
2084 |
proto.hideItemElements = function( elems ) {
|
|
|
2085 |
var items = this.getItems( elems );
|
|
|
2086 |
this.hide( items );
|
|
|
2087 |
};
|
|
|
2088 |
|
|
|
2089 |
/**
|
|
|
2090 |
* get Outlayer.Item, given an Element
|
|
|
2091 |
* @param {Element} elem
|
|
|
2092 |
* @param {Function} callback
|
|
|
2093 |
* @returns {Outlayer.Item} item
|
|
|
2094 |
*/
|
|
|
2095 |
proto.getItem = function( elem ) {
|
|
|
2096 |
// loop through items to get the one that matches
|
|
|
2097 |
for ( var i=0; i < this.items.length; i++ ) {
|
|
|
2098 |
var item = this.items[i];
|
|
|
2099 |
if ( item.element == elem ) {
|
|
|
2100 |
// return item
|
|
|
2101 |
return item;
|
|
|
2102 |
}
|
|
|
2103 |
}
|
|
|
2104 |
};
|
|
|
2105 |
|
|
|
2106 |
/**
|
|
|
2107 |
* get collection of Outlayer.Items, given Elements
|
|
|
2108 |
* @param {Array} elems
|
|
|
2109 |
* @returns {Array} items - Outlayer.Items
|
|
|
2110 |
*/
|
|
|
2111 |
proto.getItems = function( elems ) {
|
|
|
2112 |
elems = utils.makeArray( elems );
|
|
|
2113 |
var items = [];
|
|
|
2114 |
elems.forEach( function( elem ) {
|
|
|
2115 |
var item = this.getItem( elem );
|
|
|
2116 |
if ( item ) {
|
|
|
2117 |
items.push( item );
|
|
|
2118 |
}
|
|
|
2119 |
}, this );
|
|
|
2120 |
|
|
|
2121 |
return items;
|
|
|
2122 |
};
|
|
|
2123 |
|
|
|
2124 |
/**
|
|
|
2125 |
* remove element(s) from instance and DOM
|
|
|
2126 |
* @param {Array or NodeList or Element} elems
|
|
|
2127 |
*/
|
|
|
2128 |
proto.remove = function( elems ) {
|
|
|
2129 |
var removeItems = this.getItems( elems );
|
|
|
2130 |
|
|
|
2131 |
this._emitCompleteOnItems( 'remove', removeItems );
|
|
|
2132 |
|
|
|
2133 |
// bail if no items to remove
|
|
|
2134 |
if ( !removeItems || !removeItems.length ) {
|
|
|
2135 |
return;
|
|
|
2136 |
}
|
|
|
2137 |
|
|
|
2138 |
removeItems.forEach( function( item ) {
|
|
|
2139 |
item.remove();
|
|
|
2140 |
// remove item from collection
|
|
|
2141 |
utils.removeFrom( this.items, item );
|
|
|
2142 |
}, this );
|
|
|
2143 |
};
|
|
|
2144 |
|
|
|
2145 |
// ----- destroy ----- //
|
|
|
2146 |
|
|
|
2147 |
// remove and disable Outlayer instance
|
|
|
2148 |
proto.destroy = function() {
|
|
|
2149 |
// clean up dynamic styles
|
|
|
2150 |
var style = this.element.style;
|
|
|
2151 |
style.height = '';
|
|
|
2152 |
style.position = '';
|
|
|
2153 |
style.width = '';
|
|
|
2154 |
// destroy items
|
|
|
2155 |
this.items.forEach( function( item ) {
|
|
|
2156 |
item.destroy();
|
|
|
2157 |
});
|
|
|
2158 |
|
|
|
2159 |
this.unbindResize();
|
|
|
2160 |
|
|
|
2161 |
var id = this.element.outlayerGUID;
|
|
|
2162 |
delete instances[ id ]; // remove reference to instance by id
|
|
|
2163 |
delete this.element.outlayerGUID;
|
|
|
2164 |
// remove data for jQuery
|
|
|
2165 |
if ( jQuery ) {
|
|
|
2166 |
jQuery.removeData( this.element, this.constructor.namespace );
|
|
|
2167 |
}
|
|
|
2168 |
|
|
|
2169 |
};
|
|
|
2170 |
|
|
|
2171 |
// -------------------------- data -------------------------- //
|
|
|
2172 |
|
|
|
2173 |
/**
|
|
|
2174 |
* get Outlayer instance from element
|
|
|
2175 |
* @param {Element} elem
|
|
|
2176 |
* @returns {Outlayer}
|
|
|
2177 |
*/
|
|
|
2178 |
Outlayer.data = function( elem ) {
|
|
|
2179 |
elem = utils.getQueryElement( elem );
|
|
|
2180 |
var id = elem && elem.outlayerGUID;
|
|
|
2181 |
return id && instances[ id ];
|
|
|
2182 |
};
|
|
|
2183 |
|
|
|
2184 |
|
|
|
2185 |
// -------------------------- create Outlayer class -------------------------- //
|
|
|
2186 |
|
|
|
2187 |
/**
|
|
|
2188 |
* create a layout class
|
|
|
2189 |
* @param {String} namespace
|
|
|
2190 |
*/
|
|
|
2191 |
Outlayer.create = function( namespace, options ) {
|
|
|
2192 |
// sub-class Outlayer
|
|
|
2193 |
var Layout = subclass( Outlayer );
|
|
|
2194 |
// apply new options and compatOptions
|
|
|
2195 |
Layout.defaults = utils.extend( {}, Outlayer.defaults );
|
|
|
2196 |
utils.extend( Layout.defaults, options );
|
|
|
2197 |
Layout.compatOptions = utils.extend( {}, Outlayer.compatOptions );
|
|
|
2198 |
|
|
|
2199 |
Layout.namespace = namespace;
|
|
|
2200 |
|
|
|
2201 |
Layout.data = Outlayer.data;
|
|
|
2202 |
|
|
|
2203 |
// sub-class Item
|
|
|
2204 |
Layout.Item = subclass( Item );
|
|
|
2205 |
|
|
|
2206 |
// -------------------------- declarative -------------------------- //
|
|
|
2207 |
|
|
|
2208 |
utils.htmlInit( Layout, namespace );
|
|
|
2209 |
|
|
|
2210 |
// -------------------------- jQuery bridge -------------------------- //
|
|
|
2211 |
|
|
|
2212 |
// make into jQuery plugin
|
|
|
2213 |
if ( jQuery && jQuery.bridget ) {
|
|
|
2214 |
jQuery.bridget( namespace, Layout );
|
|
|
2215 |
}
|
|
|
2216 |
|
|
|
2217 |
return Layout;
|
|
|
2218 |
};
|
|
|
2219 |
|
|
|
2220 |
function subclass( Parent ) {
|
|
|
2221 |
function SubClass() {
|
|
|
2222 |
Parent.apply( this, arguments );
|
|
|
2223 |
}
|
|
|
2224 |
|
|
|
2225 |
SubClass.prototype = Object.create( Parent.prototype );
|
|
|
2226 |
SubClass.prototype.constructor = SubClass;
|
|
|
2227 |
|
|
|
2228 |
return SubClass;
|
|
|
2229 |
}
|
|
|
2230 |
|
|
|
2231 |
// ----- helpers ----- //
|
|
|
2232 |
|
|
|
2233 |
// how many milliseconds are in each unit
|
|
|
2234 |
var msUnits = {
|
|
|
2235 |
ms: 1,
|
|
|
2236 |
s: 1000
|
|
|
2237 |
};
|
|
|
2238 |
|
|
|
2239 |
// munge time-like parameter into millisecond number
|
|
|
2240 |
// '0.4s' -> 40
|
|
|
2241 |
function getMilliseconds( time ) {
|
|
|
2242 |
if ( typeof time == 'number' ) {
|
|
|
2243 |
return time;
|
|
|
2244 |
}
|
|
|
2245 |
var matches = time.match( /(^\d*\.?\d*)(\w*)/ );
|
|
|
2246 |
var num = matches && matches[1];
|
|
|
2247 |
var unit = matches && matches[2];
|
|
|
2248 |
if ( !num.length ) {
|
|
|
2249 |
return 0;
|
|
|
2250 |
}
|
|
|
2251 |
num = parseFloat( num );
|
|
|
2252 |
var mult = msUnits[ unit ] || 1;
|
|
|
2253 |
return num * mult;
|
|
|
2254 |
}
|
|
|
2255 |
|
|
|
2256 |
// ----- fin ----- //
|
|
|
2257 |
|
|
|
2258 |
// back in global
|
|
|
2259 |
Outlayer.Item = Item;
|
|
|
2260 |
|
|
|
2261 |
return Outlayer;
|
|
|
2262 |
|
|
|
2263 |
}));
|
|
|
2264 |
|
|
|
2265 |
/*!
|
|
|
2266 |
* Masonry v4.2.2
|
|
|
2267 |
* Cascading grid layout library
|
|
|
2268 |
* https://masonry.desandro.com
|
|
|
2269 |
* MIT License
|
|
|
2270 |
* by David DeSandro
|
|
|
2271 |
*/
|
|
|
2272 |
|
|
|
2273 |
( function( window, factory ) {
|
|
|
2274 |
// universal module definition
|
|
|
2275 |
/* jshint strict: false */ /*globals define, module, require */
|
|
|
2276 |
if ( typeof define == 'function' && define.amd ) {
|
|
|
2277 |
// AMD
|
|
|
2278 |
define( [
|
|
|
2279 |
'outlayer/outlayer',
|
|
|
2280 |
'get-size/get-size'
|
|
|
2281 |
],
|
|
|
2282 |
factory );
|
|
|
2283 |
} else if ( typeof module == 'object' && module.exports ) {
|
|
|
2284 |
// CommonJS
|
|
|
2285 |
module.exports = factory(
|
|
|
2286 |
require('outlayer'),
|
|
|
2287 |
require('get-size')
|
|
|
2288 |
);
|
|
|
2289 |
} else {
|
|
|
2290 |
// browser global
|
|
|
2291 |
window.Masonry = factory(
|
|
|
2292 |
window.Outlayer,
|
|
|
2293 |
window.getSize
|
|
|
2294 |
);
|
|
|
2295 |
}
|
|
|
2296 |
|
|
|
2297 |
}( window, function factory( Outlayer, getSize ) {
|
|
|
2298 |
|
|
|
2299 |
|
|
|
2300 |
|
|
|
2301 |
// -------------------------- masonryDefinition -------------------------- //
|
|
|
2302 |
|
|
|
2303 |
// create an Outlayer layout class
|
|
|
2304 |
var Masonry = Outlayer.create('masonry');
|
|
|
2305 |
// isFitWidth -> fitWidth
|
|
|
2306 |
Masonry.compatOptions.fitWidth = 'isFitWidth';
|
|
|
2307 |
|
|
|
2308 |
var proto = Masonry.prototype;
|
|
|
2309 |
|
|
|
2310 |
proto._resetLayout = function() {
|
|
|
2311 |
this.getSize();
|
|
|
2312 |
this._getMeasurement( 'columnWidth', 'outerWidth' );
|
|
|
2313 |
this._getMeasurement( 'gutter', 'outerWidth' );
|
|
|
2314 |
this.measureColumns();
|
|
|
2315 |
|
|
|
2316 |
// reset column Y
|
|
|
2317 |
this.colYs = [];
|
|
|
2318 |
for ( var i=0; i < this.cols; i++ ) {
|
|
|
2319 |
this.colYs.push( 0 );
|
|
|
2320 |
}
|
|
|
2321 |
|
|
|
2322 |
this.maxY = 0;
|
|
|
2323 |
this.horizontalColIndex = 0;
|
|
|
2324 |
};
|
|
|
2325 |
|
|
|
2326 |
proto.measureColumns = function() {
|
|
|
2327 |
this.getContainerWidth();
|
|
|
2328 |
// if columnWidth is 0, default to outerWidth of first item
|
|
|
2329 |
if ( !this.columnWidth ) {
|
|
|
2330 |
var firstItem = this.items[0];
|
|
|
2331 |
var firstItemElem = firstItem && firstItem.element;
|
|
|
2332 |
// columnWidth fall back to item of first element
|
|
|
2333 |
this.columnWidth = firstItemElem && getSize( firstItemElem ).outerWidth ||
|
|
|
2334 |
// if first elem has no width, default to size of container
|
|
|
2335 |
this.containerWidth;
|
|
|
2336 |
}
|
|
|
2337 |
|
|
|
2338 |
var columnWidth = this.columnWidth += this.gutter;
|
|
|
2339 |
|
|
|
2340 |
// calculate columns
|
|
|
2341 |
var containerWidth = this.containerWidth + this.gutter;
|
|
|
2342 |
var cols = containerWidth / columnWidth;
|
|
|
2343 |
// fix rounding errors, typically with gutters
|
|
|
2344 |
var excess = columnWidth - containerWidth % columnWidth;
|
|
|
2345 |
// if overshoot is less than a pixel, round up, otherwise floor it
|
|
|
2346 |
var mathMethod = excess && excess < 1 ? 'round' : 'floor';
|
|
|
2347 |
cols = Math[ mathMethod ]( cols );
|
|
|
2348 |
this.cols = Math.max( cols, 1 );
|
|
|
2349 |
};
|
|
|
2350 |
|
|
|
2351 |
proto.getContainerWidth = function() {
|
|
|
2352 |
// container is parent if fit width
|
|
|
2353 |
var isFitWidth = this._getOption('fitWidth');
|
|
|
2354 |
var container = isFitWidth ? this.element.parentNode : this.element;
|
|
|
2355 |
// check that this.size and size are there
|
|
|
2356 |
// IE8 triggers resize on body size change, so they might not be
|
|
|
2357 |
var size = getSize( container );
|
|
|
2358 |
this.containerWidth = size && size.innerWidth;
|
|
|
2359 |
};
|
|
|
2360 |
|
|
|
2361 |
proto._getItemLayoutPosition = function( item ) {
|
|
|
2362 |
item.getSize();
|
|
|
2363 |
// how many columns does this brick span
|
|
|
2364 |
var remainder = item.size.outerWidth % this.columnWidth;
|
|
|
2365 |
var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
|
|
|
2366 |
// round if off by 1 pixel, otherwise use ceil
|
|
|
2367 |
var colSpan = Math[ mathMethod ]( item.size.outerWidth / this.columnWidth );
|
|
|
2368 |
colSpan = Math.min( colSpan, this.cols );
|
|
|
2369 |
// use horizontal or top column position
|
|
|
2370 |
var colPosMethod = this.options.horizontalOrder ?
|
|
|
2371 |
'_getHorizontalColPosition' : '_getTopColPosition';
|
|
|
2372 |
var colPosition = this[ colPosMethod ]( colSpan, item );
|
|
|
2373 |
// position the brick
|
|
|
2374 |
var position = {
|
|
|
2375 |
x: this.columnWidth * colPosition.col,
|
|
|
2376 |
y: colPosition.y
|
|
|
2377 |
};
|
|
|
2378 |
// apply setHeight to necessary columns
|
|
|
2379 |
var setHeight = colPosition.y + item.size.outerHeight;
|
|
|
2380 |
var setMax = colSpan + colPosition.col;
|
|
|
2381 |
for ( var i = colPosition.col; i < setMax; i++ ) {
|
|
|
2382 |
this.colYs[i] = setHeight;
|
|
|
2383 |
}
|
|
|
2384 |
|
|
|
2385 |
return position;
|
|
|
2386 |
};
|
|
|
2387 |
|
|
|
2388 |
proto._getTopColPosition = function( colSpan ) {
|
|
|
2389 |
var colGroup = this._getTopColGroup( colSpan );
|
|
|
2390 |
// get the minimum Y value from the columns
|
|
|
2391 |
var minimumY = Math.min.apply( Math, colGroup );
|
|
|
2392 |
|
|
|
2393 |
return {
|
|
|
2394 |
col: colGroup.indexOf( minimumY ),
|
|
|
2395 |
y: minimumY,
|
|
|
2396 |
};
|
|
|
2397 |
};
|
|
|
2398 |
|
|
|
2399 |
/**
|
|
|
2400 |
* @param {Number} colSpan - number of columns the element spans
|
|
|
2401 |
* @returns {Array} colGroup
|
|
|
2402 |
*/
|
|
|
2403 |
proto._getTopColGroup = function( colSpan ) {
|
|
|
2404 |
if ( colSpan < 2 ) {
|
|
|
2405 |
// if brick spans only one column, use all the column Ys
|
|
|
2406 |
return this.colYs;
|
|
|
2407 |
}
|
|
|
2408 |
|
|
|
2409 |
var colGroup = [];
|
|
|
2410 |
// how many different places could this brick fit horizontally
|
|
|
2411 |
var groupCount = this.cols + 1 - colSpan;
|
|
|
2412 |
// for each group potential horizontal position
|
|
|
2413 |
for ( var i = 0; i < groupCount; i++ ) {
|
|
|
2414 |
colGroup[i] = this._getColGroupY( i, colSpan );
|
|
|
2415 |
}
|
|
|
2416 |
return colGroup;
|
|
|
2417 |
};
|
|
|
2418 |
|
|
|
2419 |
proto._getColGroupY = function( col, colSpan ) {
|
|
|
2420 |
if ( colSpan < 2 ) {
|
|
|
2421 |
return this.colYs[ col ];
|
|
|
2422 |
}
|
|
|
2423 |
// make an array of colY values for that one group
|
|
|
2424 |
var groupColYs = this.colYs.slice( col, col + colSpan );
|
|
|
2425 |
// and get the max value of the array
|
|
|
2426 |
return Math.max.apply( Math, groupColYs );
|
|
|
2427 |
};
|
|
|
2428 |
|
|
|
2429 |
// get column position based on horizontal index. #873
|
|
|
2430 |
proto._getHorizontalColPosition = function( colSpan, item ) {
|
|
|
2431 |
var col = this.horizontalColIndex % this.cols;
|
|
|
2432 |
var isOver = colSpan > 1 && col + colSpan > this.cols;
|
|
|
2433 |
// shift to next row if item can't fit on current row
|
|
|
2434 |
col = isOver ? 0 : col;
|
|
|
2435 |
// don't let zero-size items take up space
|
|
|
2436 |
var hasSize = item.size.outerWidth && item.size.outerHeight;
|
|
|
2437 |
this.horizontalColIndex = hasSize ? col + colSpan : this.horizontalColIndex;
|
|
|
2438 |
|
|
|
2439 |
return {
|
|
|
2440 |
col: col,
|
|
|
2441 |
y: this._getColGroupY( col, colSpan ),
|
|
|
2442 |
};
|
|
|
2443 |
};
|
|
|
2444 |
|
|
|
2445 |
proto._manageStamp = function( stamp ) {
|
|
|
2446 |
var stampSize = getSize( stamp );
|
|
|
2447 |
var offset = this._getElementOffset( stamp );
|
|
|
2448 |
// get the columns that this stamp affects
|
|
|
2449 |
var isOriginLeft = this._getOption('originLeft');
|
|
|
2450 |
var firstX = isOriginLeft ? offset.left : offset.right;
|
|
|
2451 |
var lastX = firstX + stampSize.outerWidth;
|
|
|
2452 |
var firstCol = Math.floor( firstX / this.columnWidth );
|
|
|
2453 |
firstCol = Math.max( 0, firstCol );
|
|
|
2454 |
var lastCol = Math.floor( lastX / this.columnWidth );
|
|
|
2455 |
// lastCol should not go over if multiple of columnWidth #425
|
|
|
2456 |
lastCol -= lastX % this.columnWidth ? 0 : 1;
|
|
|
2457 |
lastCol = Math.min( this.cols - 1, lastCol );
|
|
|
2458 |
// set colYs to bottom of the stamp
|
|
|
2459 |
|
|
|
2460 |
var isOriginTop = this._getOption('originTop');
|
|
|
2461 |
var stampMaxY = ( isOriginTop ? offset.top : offset.bottom ) +
|
|
|
2462 |
stampSize.outerHeight;
|
|
|
2463 |
for ( var i = firstCol; i <= lastCol; i++ ) {
|
|
|
2464 |
this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
|
|
|
2465 |
}
|
|
|
2466 |
};
|
|
|
2467 |
|
|
|
2468 |
proto._getContainerSize = function() {
|
|
|
2469 |
this.maxY = Math.max.apply( Math, this.colYs );
|
|
|
2470 |
var size = {
|
|
|
2471 |
height: this.maxY
|
|
|
2472 |
};
|
|
|
2473 |
|
|
|
2474 |
if ( this._getOption('fitWidth') ) {
|
|
|
2475 |
size.width = this._getContainerFitWidth();
|
|
|
2476 |
}
|
|
|
2477 |
|
|
|
2478 |
return size;
|
|
|
2479 |
};
|
|
|
2480 |
|
|
|
2481 |
proto._getContainerFitWidth = function() {
|
|
|
2482 |
var unusedCols = 0;
|
|
|
2483 |
// count unused columns
|
|
|
2484 |
var i = this.cols;
|
|
|
2485 |
while ( --i ) {
|
|
|
2486 |
if ( this.colYs[i] !== 0 ) {
|
|
|
2487 |
break;
|
|
|
2488 |
}
|
|
|
2489 |
unusedCols++;
|
|
|
2490 |
}
|
|
|
2491 |
// fit container to columns that have been used
|
|
|
2492 |
return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
|
|
|
2493 |
};
|
|
|
2494 |
|
|
|
2495 |
proto.needsResizeLayout = function() {
|
|
|
2496 |
var previousWidth = this.containerWidth;
|
|
|
2497 |
this.getContainerWidth();
|
|
|
2498 |
return previousWidth != this.containerWidth;
|
|
|
2499 |
};
|
|
|
2500 |
|
|
|
2501 |
return Masonry;
|
|
|
2502 |
|
|
|
2503 |
}));
|
|
|
2504 |
|