Advertisement
Guest User

Untitled

a guest
Aug 20th, 2014
451
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 103.56 KB | None | 0 0
  1. /*!
  2. * Isotope PACKAGED v2.0.0
  3. * Filter & sort magical layouts
  4. * http://isotope.metafizzy.co
  5. */
  6.  
  7. /**
  8. * Bridget makes jQuery widgets
  9. * v1.0.1
  10. */
  11.  
  12. ( function( window ) {
  13.  
  14.  
  15.  
  16. // -------------------------- utils -------------------------- //
  17.  
  18. var slice = Array.prototype.slice;
  19.  
  20. function noop() {}
  21.  
  22. // -------------------------- definition -------------------------- //
  23.  
  24. function defineBridget( $ ) {
  25.  
  26. // bail if no jQuery
  27. if ( !$ ) {
  28. return;
  29. }
  30.  
  31. // -------------------------- addOptionMethod -------------------------- //
  32.  
  33. /**
  34. * adds option method -> $().plugin('option', {...})
  35. * @param {Function} PluginClass - constructor class
  36. */
  37. function addOptionMethod( PluginClass ) {
  38. // don't overwrite original option method
  39. if ( PluginClass.prototype.option ) {
  40. return;
  41. }
  42.  
  43. // option setter
  44. PluginClass.prototype.option = function( opts ) {
  45. // bail out if not an object
  46. if ( !$.isPlainObject( opts ) ){
  47. return;
  48. }
  49. this.options = $.extend( true, this.options, opts );
  50. };
  51. }
  52.  
  53.  
  54. // -------------------------- plugin bridge -------------------------- //
  55.  
  56. // helper function for logging errors
  57. // $.error breaks jQuery chaining
  58. var logError = typeof console === 'undefined' ? noop :
  59. function( message ) {
  60. console.error( message );
  61. };
  62.  
  63. /**
  64. * jQuery plugin bridge, access methods like $elem.plugin('method')
  65. * @param {String} namespace - plugin name
  66. * @param {Function} PluginClass - constructor class
  67. */
  68. function bridge( namespace, PluginClass ) {
  69. // add to jQuery fn namespace
  70. $.fn[ namespace ] = function( options ) {
  71. if ( typeof options === 'string' ) {
  72. // call plugin method when first argument is a string
  73. // get arguments for method
  74. var args = slice.call( arguments, 1 );
  75.  
  76. for ( var i=0, len = this.length; i < len; i++ ) {
  77. var elem = this[i];
  78. var instance = $.data( elem, namespace );
  79. if ( !instance ) {
  80. logError( "cannot call methods on " + namespace + " prior to initialization; " +
  81. "attempted to call '" + options + "'" );
  82. continue;
  83. }
  84. if ( !$.isFunction( instance[options] ) || options.charAt(0) === '_' ) {
  85. logError( "no such method '" + options + "' for " + namespace + " instance" );
  86. continue;
  87. }
  88.  
  89. // trigger method with arguments
  90. var returnValue = instance[ options ].apply( instance, args );
  91.  
  92. // break look and return first value if provided
  93. if ( returnValue !== undefined ) {
  94. return returnValue;
  95. }
  96. }
  97. // return this if no return value
  98. return this;
  99. } else {
  100. return this.each( function() {
  101. var instance = $.data( this, namespace );
  102. if ( instance ) {
  103. // apply options & init
  104. instance.option( options );
  105. instance._init();
  106. } else {
  107. // initialize new instance
  108. instance = new PluginClass( this, options );
  109. $.data( this, namespace, instance );
  110. }
  111. });
  112. }
  113. };
  114.  
  115. }
  116.  
  117. // -------------------------- bridget -------------------------- //
  118.  
  119. /**
  120. * converts a Prototypical class into a proper jQuery plugin
  121. * the class must have a ._init method
  122. * @param {String} namespace - plugin name, used in $().pluginName
  123. * @param {Function} PluginClass - constructor class
  124. */
  125. $.bridget = function( namespace, PluginClass ) {
  126. addOptionMethod( PluginClass );
  127. bridge( namespace, PluginClass );
  128. };
  129.  
  130. return $.bridget;
  131.  
  132. }
  133.  
  134. // transport
  135. if ( typeof define === 'function' && define.amd ) {
  136. // AMD
  137. define( 'jquery-bridget/jquery.bridget',[ 'jquery' ], defineBridget );
  138. } else {
  139. // get jquery from browser global
  140. defineBridget( window.jQuery );
  141. }
  142.  
  143. })( window );
  144.  
  145. /*!
  146. * eventie v1.0.5
  147. * event binding helper
  148. * eventie.bind( elem, 'click', myFn )
  149. * eventie.unbind( elem, 'click', myFn )
  150. * MIT license
  151. */
  152.  
  153. /*jshint browser: true, undef: true, unused: true */
  154. /*global define: false, module: false */
  155.  
  156. ( function( window ) {
  157.  
  158.  
  159.  
  160. var docElem = document.documentElement;
  161.  
  162. var bind = function() {};
  163.  
  164. function getIEEvent( obj ) {
  165. var event = window.event;
  166. // add event.target
  167. event.target = event.target || event.srcElement || obj;
  168. return event;
  169. }
  170.  
  171. if ( docElem.addEventListener ) {
  172. bind = function( obj, type, fn ) {
  173. obj.addEventListener( type, fn, false );
  174. };
  175. } else if ( docElem.attachEvent ) {
  176. bind = function( obj, type, fn ) {
  177. obj[ type + fn ] = fn.handleEvent ?
  178. function() {
  179. var event = getIEEvent( obj );
  180. fn.handleEvent.call( fn, event );
  181. } :
  182. function() {
  183. var event = getIEEvent( obj );
  184. fn.call( obj, event );
  185. };
  186. obj.attachEvent( "on" + type, obj[ type + fn ] );
  187. };
  188. }
  189.  
  190. var unbind = function() {};
  191.  
  192. if ( docElem.removeEventListener ) {
  193. unbind = function( obj, type, fn ) {
  194. obj.removeEventListener( type, fn, false );
  195. };
  196. } else if ( docElem.detachEvent ) {
  197. unbind = function( obj, type, fn ) {
  198. obj.detachEvent( "on" + type, obj[ type + fn ] );
  199. try {
  200. delete obj[ type + fn ];
  201. } catch ( err ) {
  202. // can't delete window object properties
  203. obj[ type + fn ] = undefined;
  204. }
  205. };
  206. }
  207.  
  208. var eventie = {
  209. bind: bind,
  210. unbind: unbind
  211. };
  212.  
  213. // ----- module definition ----- //
  214.  
  215. if ( typeof define === 'function' && define.amd ) {
  216. // AMD
  217. define( 'eventie/eventie',eventie );
  218. } else if ( typeof exports === 'object' ) {
  219. // CommonJS
  220. module.exports = eventie;
  221. } else {
  222. // browser global
  223. window.eventie = eventie;
  224. }
  225.  
  226. })( this );
  227.  
  228. /*!
  229. * docReady
  230. * Cross browser DOMContentLoaded event emitter
  231. */
  232.  
  233. /*jshint browser: true, strict: true, undef: true, unused: true*/
  234. /*global define: false */
  235.  
  236. ( function( window ) {
  237.  
  238.  
  239.  
  240. var document = window.document;
  241. // collection of functions to be triggered on ready
  242. var queue = [];
  243.  
  244. function docReady( fn ) {
  245. // throw out non-functions
  246. if ( typeof fn !== 'function' ) {
  247. return;
  248. }
  249.  
  250. if ( docReady.isReady ) {
  251. // ready now, hit it
  252. fn();
  253. } else {
  254. // queue function when ready
  255. queue.push( fn );
  256. }
  257. }
  258.  
  259. docReady.isReady = false;
  260.  
  261. // triggered on various doc ready events
  262. function init( event ) {
  263. // bail if IE8 document is not ready just yet
  264. var isIE8NotReady = event.type === 'readystatechange' && document.readyState !== 'complete';
  265. if ( docReady.isReady || isIE8NotReady ) {
  266. return;
  267. }
  268. docReady.isReady = true;
  269.  
  270. // process queue
  271. for ( var i=0, len = queue.length; i < len; i++ ) {
  272. var fn = queue[i];
  273. fn();
  274. }
  275. }
  276.  
  277. function defineDocReady( eventie ) {
  278. eventie.bind( document, 'DOMContentLoaded', init );
  279. eventie.bind( document, 'readystatechange', init );
  280. eventie.bind( window, 'load', init );
  281.  
  282. return docReady;
  283. }
  284.  
  285. // transport
  286. if ( typeof define === 'function' && define.amd ) {
  287. // AMD
  288. // if RequireJS, then doc is already ready
  289. docReady.isReady = typeof requirejs === 'function';
  290. define( 'doc-ready/doc-ready',[ 'eventie/eventie' ], defineDocReady );
  291. } else {
  292. // browser global
  293. window.docReady = defineDocReady( window.eventie );
  294. }
  295.  
  296. })( this );
  297.  
  298. /*!
  299. * EventEmitter v4.2.7 - git.io/ee
  300. * Oliver Caldwell
  301. * MIT license
  302. * @preserve
  303. */
  304.  
  305. (function () {
  306.  
  307.  
  308. /**
  309. * Class for managing events.
  310. * Can be extended to provide event functionality in other classes.
  311. *
  312. * @class EventEmitter Manages event registering and emitting.
  313. */
  314. function EventEmitter() {}
  315.  
  316. // Shortcuts to improve speed and size
  317. var proto = EventEmitter.prototype;
  318. var exports = this;
  319. var originalGlobalValue = exports.EventEmitter;
  320.  
  321. /**
  322. * Finds the index of the listener for the event in it's storage array.
  323. *
  324. * @param {Function[]} listeners Array of listeners to search through.
  325. * @param {Function} listener Method to look for.
  326. * @return {Number} Index of the specified listener, -1 if not found
  327. * @api private
  328. */
  329. function indexOfListener(listeners, listener) {
  330. var i = listeners.length;
  331. while (i--) {
  332. if (listeners[i].listener === listener) {
  333. return i;
  334. }
  335. }
  336.  
  337. return -1;
  338. }
  339.  
  340. /**
  341. * Alias a method while keeping the context correct, to allow for overwriting of target method.
  342. *
  343. * @param {String} name The name of the target method.
  344. * @return {Function} The aliased method
  345. * @api private
  346. */
  347. function alias(name) {
  348. return function aliasClosure() {
  349. return this[name].apply(this, arguments);
  350. };
  351. }
  352.  
  353. /**
  354. * Returns the listener array for the specified event.
  355. * Will initialise the event object and listener arrays if required.
  356. * 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.
  357. * Each property in the object response is an array of listener functions.
  358. *
  359. * @param {String|RegExp} evt Name of the event to return the listeners from.
  360. * @return {Function[]|Object} All listener functions for the event.
  361. */
  362. proto.getListeners = function getListeners(evt) {
  363. var events = this._getEvents();
  364. var response;
  365. var key;
  366.  
  367. // Return a concatenated array of all matching events if
  368. // the selector is a regular expression.
  369. if (evt instanceof RegExp) {
  370. response = {};
  371. for (key in events) {
  372. if (events.hasOwnProperty(key) && evt.test(key)) {
  373. response[key] = events[key];
  374. }
  375. }
  376. }
  377. else {
  378. response = events[evt] || (events[evt] = []);
  379. }
  380.  
  381. return response;
  382. };
  383.  
  384. /**
  385. * Takes a list of listener objects and flattens it into a list of listener functions.
  386. *
  387. * @param {Object[]} listeners Raw listener objects.
  388. * @return {Function[]} Just the listener functions.
  389. */
  390. proto.flattenListeners = function flattenListeners(listeners) {
  391. var flatListeners = [];
  392. var i;
  393.  
  394. for (i = 0; i < listeners.length; i += 1) {
  395. flatListeners.push(listeners[i].listener);
  396. }
  397.  
  398. return flatListeners;
  399. };
  400.  
  401. /**
  402. * 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.
  403. *
  404. * @param {String|RegExp} evt Name of the event to return the listeners from.
  405. * @return {Object} All listener functions for an event in an object.
  406. */
  407. proto.getListenersAsObject = function getListenersAsObject(evt) {
  408. var listeners = this.getListeners(evt);
  409. var response;
  410.  
  411. if (listeners instanceof Array) {
  412. response = {};
  413. response[evt] = listeners;
  414. }
  415.  
  416. return response || listeners;
  417. };
  418.  
  419. /**
  420. * Adds a listener function to the specified event.
  421. * The listener will not be added if it is a duplicate.
  422. * If the listener returns true then it will be removed after it is called.
  423. * If you pass a regular expression as the event name then the listener will be added to all events that match it.
  424. *
  425. * @param {String|RegExp} evt Name of the event to attach the listener to.
  426. * @param {Function} listener Method to be called when the event is emitted. If the function returns true then it will be removed after calling.
  427. * @return {Object} Current instance of EventEmitter for chaining.
  428. */
  429. proto.addListener = function addListener(evt, listener) {
  430. var listeners = this.getListenersAsObject(evt);
  431. var listenerIsWrapped = typeof listener === 'object';
  432. var key;
  433.  
  434. for (key in listeners) {
  435. if (listeners.hasOwnProperty(key) && indexOfListener(listeners[key], listener) === -1) {
  436. listeners[key].push(listenerIsWrapped ? listener : {
  437. listener: listener,
  438. once: false
  439. });
  440. }
  441. }
  442.  
  443. return this;
  444. };
  445.  
  446. /**
  447. * Alias of addListener
  448. */
  449. proto.on = alias('addListener');
  450.  
  451. /**
  452. * Semi-alias of addListener. It will add a listener that will be
  453. * automatically removed after it's first execution.
  454. *
  455. * @param {String|RegExp} evt Name of the event to attach the listener to.
  456. * @param {Function} listener Method to be called when the event is emitted. If the function returns true then it will be removed after calling.
  457. * @return {Object} Current instance of EventEmitter for chaining.
  458. */
  459. proto.addOnceListener = function addOnceListener(evt, listener) {
  460. return this.addListener(evt, {
  461. listener: listener,
  462. once: true
  463. });
  464. };
  465.  
  466. /**
  467. * Alias of addOnceListener.
  468. */
  469. proto.once = alias('addOnceListener');
  470.  
  471. /**
  472. * 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.
  473. * You need to tell it what event names should be matched by a regex.
  474. *
  475. * @param {String} evt Name of the event to create.
  476. * @return {Object} Current instance of EventEmitter for chaining.
  477. */
  478. proto.defineEvent = function defineEvent(evt) {
  479. this.getListeners(evt);
  480. return this;
  481. };
  482.  
  483. /**
  484. * Uses defineEvent to define multiple events.
  485. *
  486. * @param {String[]} evts An array of event names to define.
  487. * @return {Object} Current instance of EventEmitter for chaining.
  488. */
  489. proto.defineEvents = function defineEvents(evts) {
  490. for (var i = 0; i < evts.length; i += 1) {
  491. this.defineEvent(evts[i]);
  492. }
  493. return this;
  494. };
  495.  
  496. /**
  497. * Removes a listener function from the specified event.
  498. * When passed a regular expression as the event name, it will remove the listener from all events that match it.
  499. *
  500. * @param {String|RegExp} evt Name of the event to remove the listener from.
  501. * @param {Function} listener Method to remove from the event.
  502. * @return {Object} Current instance of EventEmitter for chaining.
  503. */
  504. proto.removeListener = function removeListener(evt, listener) {
  505. var listeners = this.getListenersAsObject(evt);
  506. var index;
  507. var key;
  508.  
  509. for (key in listeners) {
  510. if (listeners.hasOwnProperty(key)) {
  511. index = indexOfListener(listeners[key], listener);
  512.  
  513. if (index !== -1) {
  514. listeners[key].splice(index, 1);
  515. }
  516. }
  517. }
  518.  
  519. return this;
  520. };
  521.  
  522. /**
  523. * Alias of removeListener
  524. */
  525. proto.off = alias('removeListener');
  526.  
  527. /**
  528. * Adds listeners in bulk using the manipulateListeners method.
  529. * 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.
  530. * You can also pass it a regular expression to add the array of listeners to all events that match it.
  531. * Yeah, this function does quite a bit. That's probably a bad thing.
  532. *
  533. * @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.
  534. * @param {Function[]} [listeners] An optional array of listener functions to add.
  535. * @return {Object} Current instance of EventEmitter for chaining.
  536. */
  537. proto.addListeners = function addListeners(evt, listeners) {
  538. // Pass through to manipulateListeners
  539. return this.manipulateListeners(false, evt, listeners);
  540. };
  541.  
  542. /**
  543. * Removes listeners in bulk using the manipulateListeners method.
  544. * 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.
  545. * You can also pass it an event name and an array of listeners to be removed.
  546. * You can also pass it a regular expression to remove the listeners from all events that match it.
  547. *
  548. * @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.
  549. * @param {Function[]} [listeners] An optional array of listener functions to remove.
  550. * @return {Object} Current instance of EventEmitter for chaining.
  551. */
  552. proto.removeListeners = function removeListeners(evt, listeners) {
  553. // Pass through to manipulateListeners
  554. return this.manipulateListeners(true, evt, listeners);
  555. };
  556.  
  557. /**
  558. * 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.
  559. * The first argument will determine if the listeners are removed (true) or added (false).
  560. * 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.
  561. * You can also pass it an event name and an array of listeners to be added/removed.
  562. * You can also pass it a regular expression to manipulate the listeners of all events that match it.
  563. *
  564. * @param {Boolean} remove True if you want to remove listeners, false if you want to add.
  565. * @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.
  566. * @param {Function[]} [listeners] An optional array of listener functions to add/remove.
  567. * @return {Object} Current instance of EventEmitter for chaining.
  568. */
  569. proto.manipulateListeners = function manipulateListeners(remove, evt, listeners) {
  570. var i;
  571. var value;
  572. var single = remove ? this.removeListener : this.addListener;
  573. var multiple = remove ? this.removeListeners : this.addListeners;
  574.  
  575. // If evt is an object then pass each of it's properties to this method
  576. if (typeof evt === 'object' && !(evt instanceof RegExp)) {
  577. for (i in evt) {
  578. if (evt.hasOwnProperty(i) && (value = evt[i])) {
  579. // Pass the single listener straight through to the singular method
  580. if (typeof value === 'function') {
  581. single.call(this, i, value);
  582. }
  583. else {
  584. // Otherwise pass back to the multiple function
  585. multiple.call(this, i, value);
  586. }
  587. }
  588. }
  589. }
  590. else {
  591. // So evt must be a string
  592. // And listeners must be an array of listeners
  593. // Loop over it and pass each one to the multiple method
  594. i = listeners.length;
  595. while (i--) {
  596. single.call(this, evt, listeners[i]);
  597. }
  598. }
  599.  
  600. return this;
  601. };
  602.  
  603. /**
  604. * Removes all listeners from a specified event.
  605. * If you do not specify an event then all listeners will be removed.
  606. * That means every event will be emptied.
  607. * You can also pass a regex to remove all events that match it.
  608. *
  609. * @param {String|RegExp} [evt] Optional name of the event to remove all listeners for. Will remove from every event if not passed.
  610. * @return {Object} Current instance of EventEmitter for chaining.
  611. */
  612. proto.removeEvent = function removeEvent(evt) {
  613. var type = typeof evt;
  614. var events = this._getEvents();
  615. var key;
  616.  
  617. // Remove different things depending on the state of evt
  618. if (type === 'string') {
  619. // Remove all listeners for the specified event
  620. delete events[evt];
  621. }
  622. else if (evt instanceof RegExp) {
  623. // Remove all events matching the regex.
  624. for (key in events) {
  625. if (events.hasOwnProperty(key) && evt.test(key)) {
  626. delete events[key];
  627. }
  628. }
  629. }
  630. else {
  631. // Remove all listeners in all events
  632. delete this._events;
  633. }
  634.  
  635. return this;
  636. };
  637.  
  638. /**
  639. * Alias of removeEvent.
  640. *
  641. * Added to mirror the node API.
  642. */
  643. proto.removeAllListeners = alias('removeEvent');
  644.  
  645. /**
  646. * Emits an event of your choice.
  647. * When emitted, every listener attached to that event will be executed.
  648. * If you pass the optional argument array then those arguments will be passed to every listener upon execution.
  649. * Because it uses `apply`, your array of arguments will be passed as if you wrote them out separately.
  650. * So they will not arrive within the array on the other side, they will be separate.
  651. * You can also pass a regular expression to emit to all events that match it.
  652. *
  653. * @param {String|RegExp} evt Name of the event to emit and execute listeners for.
  654. * @param {Array} [args] Optional array of arguments to be passed to each listener.
  655. * @return {Object} Current instance of EventEmitter for chaining.
  656. */
  657. proto.emitEvent = function emitEvent(evt, args) {
  658. var listeners = this.getListenersAsObject(evt);
  659. var listener;
  660. var i;
  661. var key;
  662. var response;
  663.  
  664. for (key in listeners) {
  665. if (listeners.hasOwnProperty(key)) {
  666. i = listeners[key].length;
  667.  
  668. while (i--) {
  669. // If the listener returns true then it shall be removed from the event
  670. // The function is executed either with a basic call or an apply if there is an args array
  671. listener = listeners[key][i];
  672.  
  673. if (listener.once === true) {
  674. this.removeListener(evt, listener.listener);
  675. }
  676.  
  677. response = listener.listener.apply(this, args || []);
  678.  
  679. if (response === this._getOnceReturnValue()) {
  680. this.removeListener(evt, listener.listener);
  681. }
  682. }
  683. }
  684. }
  685.  
  686. return this;
  687. };
  688.  
  689. /**
  690. * Alias of emitEvent
  691. */
  692. proto.trigger = alias('emitEvent');
  693.  
  694. /**
  695. * 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.
  696. * As with emitEvent, you can pass a regex in place of the event name to emit to all events that match it.
  697. *
  698. * @param {String|RegExp} evt Name of the event to emit and execute listeners for.
  699. * @param {...*} Optional additional arguments to be passed to each listener.
  700. * @return {Object} Current instance of EventEmitter for chaining.
  701. */
  702. proto.emit = function emit(evt) {
  703. var args = Array.prototype.slice.call(arguments, 1);
  704. return this.emitEvent(evt, args);
  705. };
  706.  
  707. /**
  708. * Sets the current value to check against when executing listeners. If a
  709. * listeners return value matches the one set here then it will be removed
  710. * after execution. This value defaults to true.
  711. *
  712. * @param {*} value The new value to check for when executing listeners.
  713. * @return {Object} Current instance of EventEmitter for chaining.
  714. */
  715. proto.setOnceReturnValue = function setOnceReturnValue(value) {
  716. this._onceReturnValue = value;
  717. return this;
  718. };
  719.  
  720. /**
  721. * Fetches the current value to check against when executing listeners. If
  722. * the listeners return value matches this one then it should be removed
  723. * automatically. It will return true by default.
  724. *
  725. * @return {*|Boolean} The current value to check for or the default, true.
  726. * @api private
  727. */
  728. proto._getOnceReturnValue = function _getOnceReturnValue() {
  729. if (this.hasOwnProperty('_onceReturnValue')) {
  730. return this._onceReturnValue;
  731. }
  732. else {
  733. return true;
  734. }
  735. };
  736.  
  737. /**
  738. * Fetches the events object and creates one if required.
  739. *
  740. * @return {Object} The events storage object.
  741. * @api private
  742. */
  743. proto._getEvents = function _getEvents() {
  744. return this._events || (this._events = {});
  745. };
  746.  
  747. /**
  748. * Reverts the global {@link EventEmitter} to its previous value and returns a reference to this version.
  749. *
  750. * @return {Function} Non conflicting EventEmitter class.
  751. */
  752. EventEmitter.noConflict = function noConflict() {
  753. exports.EventEmitter = originalGlobalValue;
  754. return EventEmitter;
  755. };
  756.  
  757. // Expose the class either via AMD, CommonJS or the global object
  758. if (typeof define === 'function' && define.amd) {
  759. define('eventEmitter/EventEmitter',[],function () {
  760. return EventEmitter;
  761. });
  762. }
  763. else if (typeof module === 'object' && module.exports){
  764. module.exports = EventEmitter;
  765. }
  766. else {
  767. this.EventEmitter = EventEmitter;
  768. }
  769. }.call(this));
  770.  
  771. /*!
  772. * getStyleProperty v1.0.3
  773. * original by kangax
  774. * http://perfectionkills.com/feature-testing-css-properties/
  775. */
  776.  
  777. /*jshint browser: true, strict: true, undef: true */
  778. /*global define: false, exports: false, module: false */
  779.  
  780. ( function( window ) {
  781.  
  782.  
  783.  
  784. var prefixes = 'Webkit Moz ms Ms O'.split(' ');
  785. var docElemStyle = document.documentElement.style;
  786.  
  787. function getStyleProperty( propName ) {
  788. if ( !propName ) {
  789. return;
  790. }
  791.  
  792. // test standard property first
  793. if ( typeof docElemStyle[ propName ] === 'string' ) {
  794. return propName;
  795. }
  796.  
  797. // capitalize
  798. propName = propName.charAt(0).toUpperCase() + propName.slice(1);
  799.  
  800. // test vendor specific properties
  801. var prefixed;
  802. for ( var i=0, len = prefixes.length; i < len; i++ ) {
  803. prefixed = prefixes[i] + propName;
  804. if ( typeof docElemStyle[ prefixed ] === 'string' ) {
  805. return prefixed;
  806. }
  807. }
  808. }
  809.  
  810. // transport
  811. if ( typeof define === 'function' && define.amd ) {
  812. // AMD
  813. define( 'get-style-property/get-style-property',[],function() {
  814. return getStyleProperty;
  815. });
  816. } else if ( typeof exports === 'object' ) {
  817. // CommonJS for Component
  818. module.exports = getStyleProperty;
  819. } else {
  820. // browser global
  821. window.getStyleProperty = getStyleProperty;
  822. }
  823.  
  824. })( window );
  825.  
  826. /**
  827. * getSize v1.1.7
  828. * measure size of elements
  829. */
  830.  
  831. /*jshint browser: true, strict: true, undef: true, unused: true */
  832. /*global define: false, exports: false, require: false, module: false */
  833.  
  834. ( function( window, undefined ) {
  835.  
  836.  
  837.  
  838. // -------------------------- helpers -------------------------- //
  839.  
  840. var getComputedStyle = window.getComputedStyle;
  841. var getStyle = getComputedStyle ?
  842. function( elem ) {
  843. return getComputedStyle( elem, null );
  844. } :
  845. function( elem ) {
  846. return elem.currentStyle;
  847. };
  848.  
  849. // get a number from a string, not a percentage
  850. function getStyleSize( value ) {
  851. var num = parseFloat( value );
  852. // not a percent like '100%', and a number
  853. var isValid = value.indexOf('%') === -1 && !isNaN( num );
  854. return isValid && num;
  855. }
  856.  
  857. // -------------------------- measurements -------------------------- //
  858.  
  859. var measurements = [
  860. 'paddingLeft',
  861. 'paddingRight',
  862. 'paddingTop',
  863. 'paddingBottom',
  864. 'marginLeft',
  865. 'marginRight',
  866. 'marginTop',
  867. 'marginBottom',
  868. 'borderLeftWidth',
  869. 'borderRightWidth',
  870. 'borderTopWidth',
  871. 'borderBottomWidth'
  872. ];
  873.  
  874. function getZeroSize() {
  875. var size = {
  876. width: 0,
  877. height: 0,
  878. innerWidth: 0,
  879. innerHeight: 0,
  880. outerWidth: 0,
  881. outerHeight: 0
  882. };
  883. for ( var i=0, len = measurements.length; i < len; i++ ) {
  884. var measurement = measurements[i];
  885. size[ measurement ] = 0;
  886. }
  887. return size;
  888. }
  889.  
  890.  
  891.  
  892. function defineGetSize( getStyleProperty ) {
  893.  
  894. // -------------------------- box sizing -------------------------- //
  895.  
  896. var boxSizingProp = getStyleProperty('boxSizing');
  897. var isBoxSizeOuter;
  898.  
  899. /**
  900. * WebKit measures the outer-width on style.width on border-box elems
  901. * IE & Firefox measures the inner-width
  902. */
  903. ( function() {
  904. if ( !boxSizingProp ) {
  905. return;
  906. }
  907.  
  908. var div = document.createElement('div');
  909. div.style.width = '200px';
  910. div.style.padding = '1px 2px 3px 4px';
  911. div.style.borderStyle = 'solid';
  912. div.style.borderWidth = '1px 2px 3px 4px';
  913. div.style[ boxSizingProp ] = 'border-box';
  914.  
  915. var body = document.body || document.documentElement;
  916. body.appendChild( div );
  917. var style = getStyle( div );
  918.  
  919. isBoxSizeOuter = getStyleSize( style.width ) === 200;
  920. body.removeChild( div );
  921. })();
  922.  
  923.  
  924. // -------------------------- getSize -------------------------- //
  925.  
  926. function getSize( elem ) {
  927. // use querySeletor if elem is string
  928. if ( typeof elem === 'string' ) {
  929. elem = document.querySelector( elem );
  930. }
  931.  
  932. // do not proceed on non-objects
  933. if ( !elem || typeof elem !== 'object' || !elem.nodeType ) {
  934. return;
  935. }
  936.  
  937. var style = getStyle( elem );
  938.  
  939. // if hidden, everything is 0
  940. if ( style.display === 'none' ) {
  941. return getZeroSize();
  942. }
  943.  
  944. var size = {};
  945. size.width = elem.offsetWidth;
  946. size.height = elem.offsetHeight;
  947.  
  948. var isBorderBox = size.isBorderBox = !!( boxSizingProp &&
  949. style[ boxSizingProp ] && style[ boxSizingProp ] === 'border-box' );
  950.  
  951. // get all measurements
  952. for ( var i=0, len = measurements.length; i < len; i++ ) {
  953. var measurement = measurements[i];
  954. var value = style[ measurement ];
  955. value = mungeNonPixel( elem, value );
  956. var num = parseFloat( value );
  957. // any 'auto', 'medium' value will be 0
  958. size[ measurement ] = !isNaN( num ) ? num : 0;
  959. }
  960.  
  961. var paddingWidth = size.paddingLeft + size.paddingRight;
  962. var paddingHeight = size.paddingTop + size.paddingBottom;
  963. var marginWidth = size.marginLeft + size.marginRight;
  964. var marginHeight = size.marginTop + size.marginBottom;
  965. var borderWidth = size.borderLeftWidth + size.borderRightWidth;
  966. var borderHeight = size.borderTopWidth + size.borderBottomWidth;
  967.  
  968. var isBorderBoxSizeOuter = isBorderBox && isBoxSizeOuter;
  969.  
  970. // overwrite width and height if we can get it from style
  971. var styleWidth = getStyleSize( style.width );
  972. if ( styleWidth !== false ) {
  973. size.width = styleWidth +
  974. // add padding and border unless it's already including it
  975. ( isBorderBoxSizeOuter ? 0 : paddingWidth + borderWidth );
  976. }
  977.  
  978. var styleHeight = getStyleSize( style.height );
  979. if ( styleHeight !== false ) {
  980. size.height = styleHeight +
  981. // add padding and border unless it's already including it
  982. ( isBorderBoxSizeOuter ? 0 : paddingHeight + borderHeight );
  983. }
  984.  
  985. size.innerWidth = size.width - ( paddingWidth + borderWidth );
  986. size.innerHeight = size.height - ( paddingHeight + borderHeight );
  987.  
  988. size.outerWidth = size.width + marginWidth;
  989. size.outerHeight = size.height + marginHeight;
  990.  
  991. return size;
  992. }
  993.  
  994. // IE8 returns percent values, not pixels
  995. // taken from jQuery's curCSS
  996. function mungeNonPixel( elem, value ) {
  997. // IE8 and has percent value
  998. if ( getComputedStyle || value.indexOf('%') === -1 ) {
  999. return value;
  1000. }
  1001. var style = elem.style;
  1002. // Remember the original values
  1003. var left = style.left;
  1004. var rs = elem.runtimeStyle;
  1005. var rsLeft = rs && rs.left;
  1006.  
  1007. // Put in the new values to get a computed value out
  1008. if ( rsLeft ) {
  1009. rs.left = elem.currentStyle.left;
  1010. }
  1011. style.left = value;
  1012. value = style.pixelLeft;
  1013.  
  1014. // Revert the changed values
  1015. style.left = left;
  1016. if ( rsLeft ) {
  1017. rs.left = rsLeft;
  1018. }
  1019.  
  1020. return value;
  1021. }
  1022.  
  1023. return getSize;
  1024.  
  1025. }
  1026.  
  1027. // transport
  1028. if ( typeof define === 'function' && define.amd ) {
  1029. // AMD for RequireJS
  1030. define( 'get-size/get-size',[ 'get-style-property/get-style-property' ], defineGetSize );
  1031. } else if ( typeof exports === 'object' ) {
  1032. // CommonJS for Component
  1033. module.exports = defineGetSize( require('get-style-property') );
  1034. } else {
  1035. // browser global
  1036. window.getSize = defineGetSize( window.getStyleProperty );
  1037. }
  1038.  
  1039. })( window );
  1040.  
  1041. /**
  1042. * matchesSelector helper v1.0.1
  1043. *
  1044. * @name matchesSelector
  1045. * @param {Element} elem
  1046. * @param {String} selector
  1047. */
  1048.  
  1049. /*jshint browser: true, strict: true, undef: true, unused: true */
  1050. /*global define: false */
  1051.  
  1052. ( function( global, ElemProto ) {
  1053.  
  1054.  
  1055.  
  1056. var matchesMethod = ( function() {
  1057. // check un-prefixed
  1058. if ( ElemProto.matchesSelector ) {
  1059. return 'matchesSelector';
  1060. }
  1061. // check vendor prefixes
  1062. var prefixes = [ 'webkit', 'moz', 'ms', 'o' ];
  1063.  
  1064. for ( var i=0, len = prefixes.length; i < len; i++ ) {
  1065. var prefix = prefixes[i];
  1066. var method = prefix + 'MatchesSelector';
  1067. if ( ElemProto[ method ] ) {
  1068. return method;
  1069. }
  1070. }
  1071. })();
  1072.  
  1073. // ----- match ----- //
  1074.  
  1075. function match( elem, selector ) {
  1076. return elem[ matchesMethod ]( selector );
  1077. }
  1078.  
  1079. // ----- appendToFragment ----- //
  1080.  
  1081. function checkParent( elem ) {
  1082. // not needed if already has parent
  1083. if ( elem.parentNode ) {
  1084. return;
  1085. }
  1086. var fragment = document.createDocumentFragment();
  1087. fragment.appendChild( elem );
  1088. }
  1089.  
  1090. // ----- query ----- //
  1091.  
  1092. // fall back to using QSA
  1093. // thx @jonathantneal https://gist.github.com/3062955
  1094. function query( elem, selector ) {
  1095. // append to fragment if no parent
  1096. checkParent( elem );
  1097.  
  1098. // match elem with all selected elems of parent
  1099. var elems = elem.parentNode.querySelectorAll( selector );
  1100. for ( var i=0, len = elems.length; i < len; i++ ) {
  1101. // return true if match
  1102. if ( elems[i] === elem ) {
  1103. return true;
  1104. }
  1105. }
  1106. // otherwise return false
  1107. return false;
  1108. }
  1109.  
  1110. // ----- matchChild ----- //
  1111.  
  1112. function matchChild( elem, selector ) {
  1113. checkParent( elem );
  1114. return match( elem, selector );
  1115. }
  1116.  
  1117. // ----- matchesSelector ----- //
  1118.  
  1119. var matchesSelector;
  1120.  
  1121. if ( matchesMethod ) {
  1122. // IE9 supports matchesSelector, but doesn't work on orphaned elems
  1123. // check for that
  1124. var div = document.createElement('div');
  1125. var supportsOrphans = match( div, 'div' );
  1126. matchesSelector = supportsOrphans ? match : matchChild;
  1127. } else {
  1128. matchesSelector = query;
  1129. }
  1130.  
  1131. // transport
  1132. if ( typeof define === 'function' && define.amd ) {
  1133. // AMD
  1134. define( 'matches-selector/matches-selector',[],function() {
  1135. return matchesSelector;
  1136. });
  1137. } else {
  1138. // browser global
  1139. window.matchesSelector = matchesSelector;
  1140. }
  1141.  
  1142. })( this, Element.prototype );
  1143.  
  1144. /**
  1145. * Outlayer Item
  1146. */
  1147.  
  1148. ( function( window ) {
  1149.  
  1150.  
  1151.  
  1152. // ----- get style ----- //
  1153.  
  1154. var getComputedStyle = window.getComputedStyle;
  1155. var getStyle = getComputedStyle ?
  1156. function( elem ) {
  1157. return getComputedStyle( elem, null );
  1158. } :
  1159. function( elem ) {
  1160. return elem.currentStyle;
  1161. };
  1162.  
  1163.  
  1164. // extend objects
  1165. function extend( a, b ) {
  1166. for ( var prop in b ) {
  1167. a[ prop ] = b[ prop ];
  1168. }
  1169. return a;
  1170. }
  1171.  
  1172. function isEmptyObj( obj ) {
  1173. for ( var prop in obj ) {
  1174. return false;
  1175. }
  1176. prop = null;
  1177. return true;
  1178. }
  1179.  
  1180. // http://jamesroberts.name/blog/2010/02/22/string-functions-for-javascript-trim-to-camel-case-to-dashed-and-to-underscore/
  1181. function toDash( str ) {
  1182. return str.replace( /([A-Z])/g, function( $1 ){
  1183. return '-' + $1.toLowerCase();
  1184. });
  1185. }
  1186.  
  1187. // -------------------------- Outlayer definition -------------------------- //
  1188.  
  1189. function outlayerItemDefinition( EventEmitter, getSize, getStyleProperty ) {
  1190.  
  1191. // -------------------------- CSS3 support -------------------------- //
  1192.  
  1193. var transitionProperty = getStyleProperty('transition');
  1194. var transformProperty = getStyleProperty('transform');
  1195. var supportsCSS3 = transitionProperty && transformProperty;
  1196. var is3d = !!getStyleProperty('perspective');
  1197.  
  1198. var transitionEndEvent = {
  1199. WebkitTransition: 'webkitTransitionEnd',
  1200. MozTransition: 'transitionend',
  1201. OTransition: 'otransitionend',
  1202. transition: 'transitionend'
  1203. }[ transitionProperty ];
  1204.  
  1205. // properties that could have vendor prefix
  1206. var prefixableProperties = [
  1207. 'transform',
  1208. 'transition',
  1209. 'transitionDuration',
  1210. 'transitionProperty'
  1211. ];
  1212.  
  1213. // cache all vendor properties
  1214. var vendorProperties = ( function() {
  1215. var cache = {};
  1216. for ( var i=0, len = prefixableProperties.length; i < len; i++ ) {
  1217. var prop = prefixableProperties[i];
  1218. var supportedProp = getStyleProperty( prop );
  1219. if ( supportedProp && supportedProp !== prop ) {
  1220. cache[ prop ] = supportedProp;
  1221. }
  1222. }
  1223. return cache;
  1224. })();
  1225.  
  1226. // -------------------------- Item -------------------------- //
  1227.  
  1228. function Item( element, layout ) {
  1229. if ( !element ) {
  1230. return;
  1231. }
  1232.  
  1233. this.element = element;
  1234. // parent layout class, i.e. Masonry, Isotope, or Packery
  1235. this.layout = layout;
  1236. this.position = {
  1237. x: 0,
  1238. y: 0
  1239. };
  1240.  
  1241. this._create();
  1242. }
  1243.  
  1244. // inherit EventEmitter
  1245. extend( Item.prototype, EventEmitter.prototype );
  1246.  
  1247. Item.prototype._create = function() {
  1248. // transition objects
  1249. this._transn = {
  1250. ingProperties: {},
  1251. clean: {},
  1252. onEnd: {}
  1253. };
  1254.  
  1255. this.css({
  1256. position: 'absolute'
  1257. });
  1258. };
  1259.  
  1260. // trigger specified handler for event type
  1261. Item.prototype.handleEvent = function( event ) {
  1262. var method = 'on' + event.type;
  1263. if ( this[ method ] ) {
  1264. this[ method ]( event );
  1265. }
  1266. };
  1267.  
  1268. Item.prototype.getSize = function() {
  1269. this.size = getSize( this.element );
  1270. };
  1271.  
  1272. /**
  1273. * apply CSS styles to element
  1274. * @param {Object} style
  1275. */
  1276. Item.prototype.css = function( style ) {
  1277. var elemStyle = this.element.style;
  1278.  
  1279. for ( var prop in style ) {
  1280. // use vendor property if available
  1281. var supportedProp = vendorProperties[ prop ] || prop;
  1282. elemStyle[ supportedProp ] = style[ prop ];
  1283. }
  1284. };
  1285.  
  1286. // measure position, and sets it
  1287. Item.prototype.getPosition = function() {
  1288. var style = getStyle( this.element );
  1289. var layoutOptions = this.layout.options;
  1290. var isOriginLeft = layoutOptions.isOriginLeft;
  1291. var isOriginTop = layoutOptions.isOriginTop;
  1292. var x = parseInt( style[ isOriginLeft ? 'left' : 'right' ], 10 );
  1293. var y = parseInt( style[ isOriginTop ? 'top' : 'bottom' ], 10 );
  1294.  
  1295. // clean up 'auto' or other non-integer values
  1296. x = isNaN( x ) ? 0 : x;
  1297. y = isNaN( y ) ? 0 : y;
  1298. // remove padding from measurement
  1299. var layoutSize = this.layout.size;
  1300. x -= isOriginLeft ? layoutSize.paddingLeft : layoutSize.paddingRight;
  1301. y -= isOriginTop ? layoutSize.paddingTop : layoutSize.paddingBottom;
  1302.  
  1303. this.position.x = x;
  1304. this.position.y = y;
  1305. };
  1306.  
  1307. // set settled position, apply padding
  1308. Item.prototype.layoutPosition = function() {
  1309. var layoutSize = this.layout.size;
  1310. var layoutOptions = this.layout.options;
  1311. var style = {};
  1312.  
  1313. if ( layoutOptions.isOriginLeft ) {
  1314. style.left = ( this.position.x + layoutSize.paddingLeft ) + 'px';
  1315. // reset other property
  1316. style.right = '';
  1317. } else {
  1318. style.right = ( this.position.x + layoutSize.paddingRight ) + 'px';
  1319. style.left = '';
  1320. }
  1321.  
  1322. if ( layoutOptions.isOriginTop ) {
  1323. style.top = ( this.position.y + layoutSize.paddingTop ) + 'px';
  1324. style.bottom = '';
  1325. } else {
  1326. style.bottom = ( this.position.y + layoutSize.paddingBottom ) + 'px';
  1327. style.top = '';
  1328. }
  1329.  
  1330. this.css( style );
  1331. this.emitEvent( 'layout', [ this ] );
  1332. };
  1333.  
  1334.  
  1335. // transform translate function
  1336. var translate = is3d ?
  1337. function( x, y ) {
  1338. return 'translate3d(' + x + 'px, ' + y + 'px, 0)';
  1339. } :
  1340. function( x, y ) {
  1341. return 'translate(' + x + 'px, ' + y + 'px)';
  1342. };
  1343.  
  1344.  
  1345. Item.prototype._transitionTo = function( x, y ) {
  1346. this.getPosition();
  1347. // get current x & y from top/left
  1348. var curX = this.position.x;
  1349. var curY = this.position.y;
  1350.  
  1351. var compareX = parseInt( x, 10 );
  1352. var compareY = parseInt( y, 10 );
  1353. var didNotMove = compareX === this.position.x && compareY === this.position.y;
  1354.  
  1355. // save end position
  1356. this.setPosition( x, y );
  1357.  
  1358. // if did not move and not transitioning, just go to layout
  1359. if ( didNotMove && !this.isTransitioning ) {
  1360. this.layoutPosition();
  1361. return;
  1362. }
  1363.  
  1364. var transX = x - curX;
  1365. var transY = y - curY;
  1366. var transitionStyle = {};
  1367. // flip cooridinates if origin on right or bottom
  1368. var layoutOptions = this.layout.options;
  1369. transX = layoutOptions.isOriginLeft ? transX : -transX;
  1370. transY = layoutOptions.isOriginTop ? transY : -transY;
  1371. transitionStyle.transform = translate( transX, transY );
  1372.  
  1373. this.transition({
  1374. to: transitionStyle,
  1375. onTransitionEnd: {
  1376. transform: this.layoutPosition
  1377. },
  1378. isCleaning: true
  1379. });
  1380. };
  1381.  
  1382. // non transition + transform support
  1383. Item.prototype.goTo = function( x, y ) {
  1384. this.setPosition( x, y );
  1385. this.layoutPosition();
  1386. };
  1387.  
  1388. // use transition and transforms if supported
  1389. Item.prototype.moveTo = supportsCSS3 ?
  1390. Item.prototype._transitionTo : Item.prototype.goTo;
  1391.  
  1392. Item.prototype.setPosition = function( x, y ) {
  1393. this.position.x = parseInt( x, 10 );
  1394. this.position.y = parseInt( y, 10 );
  1395. };
  1396.  
  1397. // ----- transition ----- //
  1398.  
  1399. /**
  1400. * @param {Object} style - CSS
  1401. * @param {Function} onTransitionEnd
  1402. */
  1403.  
  1404. // non transition, just trigger callback
  1405. Item.prototype._nonTransition = function( args ) {
  1406. this.css( args.to );
  1407. if ( args.isCleaning ) {
  1408. this._removeStyles( args.to );
  1409. }
  1410. for ( var prop in args.onTransitionEnd ) {
  1411. args.onTransitionEnd[ prop ].call( this );
  1412. }
  1413. };
  1414.  
  1415. /**
  1416. * proper transition
  1417. * @param {Object} args - arguments
  1418. * @param {Object} to - style to transition to
  1419. * @param {Object} from - style to start transition from
  1420. * @param {Boolean} isCleaning - removes transition styles after transition
  1421. * @param {Function} onTransitionEnd - callback
  1422. */
  1423. Item.prototype._transition = function( args ) {
  1424. // redirect to nonTransition if no transition duration
  1425. if ( !parseFloat( this.layout.options.transitionDuration ) ) {
  1426. this._nonTransition( args );
  1427. return;
  1428. }
  1429.  
  1430. var _transition = this._transn;
  1431. // keep track of onTransitionEnd callback by css property
  1432. for ( var prop in args.onTransitionEnd ) {
  1433. _transition.onEnd[ prop ] = args.onTransitionEnd[ prop ];
  1434. }
  1435. // keep track of properties that are transitioning
  1436. for ( prop in args.to ) {
  1437. _transition.ingProperties[ prop ] = true;
  1438. // keep track of properties to clean up when transition is done
  1439. if ( args.isCleaning ) {
  1440. _transition.clean[ prop ] = true;
  1441. }
  1442. }
  1443.  
  1444. // set from styles
  1445. if ( args.from ) {
  1446. this.css( args.from );
  1447. // force redraw. http://blog.alexmaccaw.com/css-transitions
  1448. var h = this.element.offsetHeight;
  1449. // hack for JSHint to hush about unused var
  1450. h = null;
  1451. }
  1452. // enable transition
  1453. this.enableTransition( args.to );
  1454. // set styles that are transitioning
  1455. this.css( args.to );
  1456.  
  1457. this.isTransitioning = true;
  1458.  
  1459. };
  1460.  
  1461. var itemTransitionProperties = transformProperty && ( toDash( transformProperty ) +
  1462. ',opacity' );
  1463.  
  1464. Item.prototype.enableTransition = function(/* style */) {
  1465. // only enable if not already transitioning
  1466. // bug in IE10 were re-setting transition style will prevent
  1467. // transitionend event from triggering
  1468. if ( this.isTransitioning ) {
  1469. return;
  1470. }
  1471.  
  1472. // make transition: foo, bar, baz from style object
  1473. // TODO uncomment this bit when IE10 bug is resolved
  1474. // var transitionValue = [];
  1475. // for ( var prop in style ) {
  1476. // // dash-ify camelCased properties like WebkitTransition
  1477. // transitionValue.push( toDash( prop ) );
  1478. // }
  1479. // enable transition styles
  1480. // HACK always enable transform,opacity for IE10
  1481. this.css({
  1482. transitionProperty: itemTransitionProperties,
  1483. transitionDuration: this.layout.options.transitionDuration
  1484. });
  1485. // listen for transition end event
  1486. this.element.addEventListener( transitionEndEvent, this, false );
  1487. };
  1488.  
  1489. Item.prototype.transition = Item.prototype[ transitionProperty ? '_transition' : '_nonTransition' ];
  1490.  
  1491. // ----- events ----- //
  1492.  
  1493. Item.prototype.onwebkitTransitionEnd = function( event ) {
  1494. this.ontransitionend( event );
  1495. };
  1496.  
  1497. Item.prototype.onotransitionend = function( event ) {
  1498. this.ontransitionend( event );
  1499. };
  1500.  
  1501. // properties that I munge to make my life easier
  1502. var dashedVendorProperties = {
  1503. '-webkit-transform': 'transform',
  1504. '-moz-transform': 'transform',
  1505. '-o-transform': 'transform'
  1506. };
  1507.  
  1508. Item.prototype.ontransitionend = function( event ) {
  1509. // disregard bubbled events from children
  1510. if ( event.target !== this.element ) {
  1511. return;
  1512. }
  1513. var _transition = this._transn;
  1514. // get property name of transitioned property, convert to prefix-free
  1515. var propertyName = dashedVendorProperties[ event.propertyName ] || event.propertyName;
  1516.  
  1517. // remove property that has completed transitioning
  1518. delete _transition.ingProperties[ propertyName ];
  1519. // check if any properties are still transitioning
  1520. if ( isEmptyObj( _transition.ingProperties ) ) {
  1521. // all properties have completed transitioning
  1522. this.disableTransition();
  1523. }
  1524. // clean style
  1525. if ( propertyName in _transition.clean ) {
  1526. // clean up style
  1527. this.element.style[ event.propertyName ] = '';
  1528. delete _transition.clean[ propertyName ];
  1529. }
  1530. // trigger onTransitionEnd callback
  1531. if ( propertyName in _transition.onEnd ) {
  1532. var onTransitionEnd = _transition.onEnd[ propertyName ];
  1533. onTransitionEnd.call( this );
  1534. delete _transition.onEnd[ propertyName ];
  1535. }
  1536.  
  1537. this.emitEvent( 'transitionEnd', [ this ] );
  1538. };
  1539.  
  1540. Item.prototype.disableTransition = function() {
  1541. this.removeTransitionStyles();
  1542. this.element.removeEventListener( transitionEndEvent, this, false );
  1543. this.isTransitioning = false;
  1544. };
  1545.  
  1546. /**
  1547. * removes style property from element
  1548. * @param {Object} style
  1549. **/
  1550. Item.prototype._removeStyles = function( style ) {
  1551. // clean up transition styles
  1552. var cleanStyle = {};
  1553. for ( var prop in style ) {
  1554. cleanStyle[ prop ] = '';
  1555. }
  1556. this.css( cleanStyle );
  1557. };
  1558.  
  1559. var cleanTransitionStyle = {
  1560. transitionProperty: '',
  1561. transitionDuration: ''
  1562. };
  1563.  
  1564. Item.prototype.removeTransitionStyles = function() {
  1565. // remove transition
  1566. this.css( cleanTransitionStyle );
  1567. };
  1568.  
  1569. // ----- show/hide/remove ----- //
  1570.  
  1571. // remove element from DOM
  1572. Item.prototype.removeElem = function() {
  1573. this.element.parentNode.removeChild( this.element );
  1574. this.emitEvent( 'remove', [ this ] );
  1575. };
  1576.  
  1577. Item.prototype.remove = function() {
  1578. // just remove element if no transition support or no transition
  1579. if ( !transitionProperty || !parseFloat( this.layout.options.transitionDuration ) ) {
  1580. this.removeElem();
  1581. return;
  1582. }
  1583.  
  1584. // start transition
  1585. var _this = this;
  1586. this.on( 'transitionEnd', function() {
  1587. _this.removeElem();
  1588. return true; // bind once
  1589. });
  1590. this.hide();
  1591. };
  1592.  
  1593. Item.prototype.reveal = function() {
  1594. delete this.isHidden;
  1595. // remove display: none
  1596. this.css({ display: '' });
  1597.  
  1598. var options = this.layout.options;
  1599. this.transition({
  1600. from: options.hiddenStyle,
  1601. to: options.visibleStyle,
  1602. isCleaning: true
  1603. });
  1604. };
  1605.  
  1606. Item.prototype.hide = function() {
  1607. // set flag
  1608. this.isHidden = true;
  1609. // remove display: none
  1610. this.css({ display: '' });
  1611.  
  1612. var options = this.layout.options;
  1613. this.transition({
  1614. from: options.visibleStyle,
  1615. to: options.hiddenStyle,
  1616. // keep hidden stuff hidden
  1617. isCleaning: true,
  1618. onTransitionEnd: {
  1619. opacity: function() {
  1620. // check if still hidden
  1621. // during transition, item may have been un-hidden
  1622. if ( this.isHidden ) {
  1623. this.css({ display: 'none' });
  1624. }
  1625. }
  1626. }
  1627. });
  1628. };
  1629.  
  1630. Item.prototype.destroy = function() {
  1631. this.css({
  1632. position: '',
  1633. left: '',
  1634. right: '',
  1635. top: '',
  1636. bottom: '',
  1637. transition: '',
  1638. transform: ''
  1639. });
  1640. };
  1641.  
  1642. return Item;
  1643.  
  1644. }
  1645.  
  1646. // -------------------------- transport -------------------------- //
  1647.  
  1648. if ( typeof define === 'function' && define.amd ) {
  1649. // AMD
  1650. define( 'outlayer/item',[
  1651. 'eventEmitter/EventEmitter',
  1652. 'get-size/get-size',
  1653. 'get-style-property/get-style-property'
  1654. ],
  1655. outlayerItemDefinition );
  1656. } else {
  1657. // browser global
  1658. window.Outlayer = {};
  1659. window.Outlayer.Item = outlayerItemDefinition(
  1660. window.EventEmitter,
  1661. window.getSize,
  1662. window.getStyleProperty
  1663. );
  1664. }
  1665.  
  1666. })( window );
  1667.  
  1668. /*!
  1669. * Outlayer v1.2.0
  1670. * the brains and guts of a layout library
  1671. * MIT license
  1672. */
  1673.  
  1674. ( function( window ) {
  1675.  
  1676.  
  1677.  
  1678. // ----- vars ----- //
  1679.  
  1680. var document = window.document;
  1681. var console = window.console;
  1682. var jQuery = window.jQuery;
  1683.  
  1684. var noop = function() {};
  1685.  
  1686. // -------------------------- helpers -------------------------- //
  1687.  
  1688. // extend objects
  1689. function extend( a, b ) {
  1690. for ( var prop in b ) {
  1691. a[ prop ] = b[ prop ];
  1692. }
  1693. return a;
  1694. }
  1695.  
  1696.  
  1697. var objToString = Object.prototype.toString;
  1698. function isArray( obj ) {
  1699. return objToString.call( obj ) === '[object Array]';
  1700. }
  1701.  
  1702. // turn element or nodeList into an array
  1703. function makeArray( obj ) {
  1704. var ary = [];
  1705. if ( isArray( obj ) ) {
  1706. // use object if already an array
  1707. ary = obj;
  1708. } else if ( obj && typeof obj.length === 'number' ) {
  1709. // convert nodeList to array
  1710. for ( var i=0, len = obj.length; i < len; i++ ) {
  1711. ary.push( obj[i] );
  1712. }
  1713. } else {
  1714. // array of single index
  1715. ary.push( obj );
  1716. }
  1717. return ary;
  1718. }
  1719.  
  1720. // http://stackoverflow.com/a/384380/182183
  1721. var isElement = ( typeof HTMLElement === 'object' ) ?
  1722. function isElementDOM2( obj ) {
  1723. return obj instanceof HTMLElement;
  1724. } :
  1725. function isElementQuirky( obj ) {
  1726. return obj && typeof obj === 'object' &&
  1727. obj.nodeType === 1 && typeof obj.nodeName === 'string';
  1728. };
  1729.  
  1730. // index of helper cause IE8
  1731. var indexOf = Array.prototype.indexOf ? function( ary, obj ) {
  1732. return ary.indexOf( obj );
  1733. } : function( ary, obj ) {
  1734. for ( var i=0, len = ary.length; i < len; i++ ) {
  1735. if ( ary[i] === obj ) {
  1736. return i;
  1737. }
  1738. }
  1739. return -1;
  1740. };
  1741.  
  1742. function removeFrom( obj, ary ) {
  1743. var index = indexOf( ary, obj );
  1744. if ( index !== -1 ) {
  1745. ary.splice( index, 1 );
  1746. }
  1747. }
  1748.  
  1749. // http://jamesroberts.name/blog/2010/02/22/string-functions-for-javascript-trim-to-camel-case-to-dashed-and-to-underscore/
  1750. function toDashed( str ) {
  1751. return str.replace( /(.)([A-Z])/g, function( match, $1, $2 ) {
  1752. return $1 + '-' + $2;
  1753. }).toLowerCase();
  1754. }
  1755.  
  1756.  
  1757. function outlayerDefinition( eventie, docReady, EventEmitter, getSize, matchesSelector, Item ) {
  1758.  
  1759. // -------------------------- Outlayer -------------------------- //
  1760.  
  1761. // globally unique identifiers
  1762. var GUID = 0;
  1763. // internal store of all Outlayer intances
  1764. var instances = {};
  1765.  
  1766.  
  1767. /**
  1768. * @param {Element, String} element
  1769. * @param {Object} options
  1770. * @constructor
  1771. */
  1772. function Outlayer( element, options ) {
  1773. // use element as selector string
  1774. if ( typeof element === 'string' ) {
  1775. element = document.querySelector( element );
  1776. }
  1777.  
  1778. // bail out if not proper element
  1779. if ( !element || !isElement( element ) ) {
  1780. if ( console ) {
  1781. console.error( 'Bad ' + this.constructor.namespace + ' element: ' + element );
  1782. }
  1783. return;
  1784. }
  1785.  
  1786. this.element = element;
  1787.  
  1788. // options
  1789. this.options = extend( {}, this.constructor.defaults );
  1790. this.option( options );
  1791.  
  1792. // add id for Outlayer.getFromElement
  1793. var id = ++GUID;
  1794. this.element.outlayerGUID = id; // expando
  1795. instances[ id ] = this; // associate via id
  1796.  
  1797. // kick it off
  1798. this._create();
  1799.  
  1800. if ( this.options.isInitLayout ) {
  1801. this.layout();
  1802. }
  1803. }
  1804.  
  1805. // settings are for internal use only
  1806. Outlayer.namespace = 'outlayer';
  1807. Outlayer.Item = Item;
  1808.  
  1809. // default options
  1810. Outlayer.defaults = {
  1811. containerStyle: {
  1812. position: 'relative'
  1813. },
  1814. isInitLayout: true,
  1815. isOriginLeft: true,
  1816. isOriginTop: true,
  1817. isResizeBound: true,
  1818. isResizingContainer: true,
  1819. // item options
  1820. transitionDuration: '0.4s',
  1821. hiddenStyle: {
  1822. opacity: 0,
  1823. transform: 'scale(0.001)'
  1824. },
  1825. visibleStyle: {
  1826. opacity: 1,
  1827. transform: 'scale(1)'
  1828. }
  1829. };
  1830.  
  1831. // inherit EventEmitter
  1832. extend( Outlayer.prototype, EventEmitter.prototype );
  1833.  
  1834. /**
  1835. * set options
  1836. * @param {Object} opts
  1837. */
  1838. Outlayer.prototype.option = function( opts ) {
  1839. extend( this.options, opts );
  1840. };
  1841.  
  1842. Outlayer.prototype._create = function() {
  1843. // get items from children
  1844. this.reloadItems();
  1845. // elements that affect layout, but are not laid out
  1846. this.stamps = [];
  1847. this.stamp( this.options.stamp );
  1848. // set container style
  1849. extend( this.element.style, this.options.containerStyle );
  1850.  
  1851. // bind resize method
  1852. if ( this.options.isResizeBound ) {
  1853. this.bindResize();
  1854. }
  1855. };
  1856.  
  1857. // goes through all children again and gets bricks in proper order
  1858. Outlayer.prototype.reloadItems = function() {
  1859. // collection of item elements
  1860. this.items = this._itemize( this.element.children );
  1861. };
  1862.  
  1863.  
  1864. /**
  1865. * turn elements into Outlayer.Items to be used in layout
  1866. * @param {Array or NodeList or HTMLElement} elems
  1867. * @returns {Array} items - collection of new Outlayer Items
  1868. */
  1869. Outlayer.prototype._itemize = function( elems ) {
  1870.  
  1871. var itemElems = this._filterFindItemElements( elems );
  1872. var Item = this.constructor.Item;
  1873.  
  1874. // create new Outlayer Items for collection
  1875. var items = [];
  1876. for ( var i=0, len = itemElems.length; i < len; i++ ) {
  1877. var elem = itemElems[i];
  1878. var item = new Item( elem, this );
  1879. items.push( item );
  1880. }
  1881.  
  1882. return items;
  1883. };
  1884.  
  1885. /**
  1886. * get item elements to be used in layout
  1887. * @param {Array or NodeList or HTMLElement} elems
  1888. * @returns {Array} items - item elements
  1889. */
  1890. Outlayer.prototype._filterFindItemElements = function( elems ) {
  1891. // make array of elems
  1892. elems = makeArray( elems );
  1893. var itemSelector = this.options.itemSelector;
  1894. var itemElems = [];
  1895.  
  1896. for ( var i=0, len = elems.length; i < len; i++ ) {
  1897. var elem = elems[i];
  1898. // check that elem is an actual element
  1899. if ( !isElement( elem ) ) {
  1900. continue;
  1901. }
  1902. // filter & find items if we have an item selector
  1903. if ( itemSelector ) {
  1904. // filter siblings
  1905. if ( matchesSelector( elem, itemSelector ) ) {
  1906. itemElems.push( elem );
  1907. }
  1908. // find children
  1909. var childElems = elem.querySelectorAll( itemSelector );
  1910. // concat childElems to filterFound array
  1911. for ( var j=0, jLen = childElems.length; j < jLen; j++ ) {
  1912. itemElems.push( childElems[j] );
  1913. }
  1914. } else {
  1915. itemElems.push( elem );
  1916. }
  1917. }
  1918.  
  1919. return itemElems;
  1920. };
  1921.  
  1922. /**
  1923. * getter method for getting item elements
  1924. * @returns {Array} elems - collection of item elements
  1925. */
  1926. Outlayer.prototype.getItemElements = function() {
  1927. var elems = [];
  1928. for ( var i=0, len = this.items.length; i < len; i++ ) {
  1929. elems.push( this.items[i].element );
  1930. }
  1931. return elems;
  1932. };
  1933.  
  1934. // ----- init & layout ----- //
  1935.  
  1936. /**
  1937. * lays out all items
  1938. */
  1939. Outlayer.prototype.layout = function() {
  1940. this._resetLayout();
  1941. this._manageStamps();
  1942.  
  1943. // don't animate first layout
  1944. var isInstant = this.options.isLayoutInstant !== undefined ?
  1945. this.options.isLayoutInstant : !this._isLayoutInited;
  1946. this.layoutItems( this.items, isInstant );
  1947.  
  1948. // flag for initalized
  1949. this._isLayoutInited = true;
  1950. };
  1951.  
  1952. // _init is alias for layout
  1953. Outlayer.prototype._init = Outlayer.prototype.layout;
  1954.  
  1955. /**
  1956. * logic before any new layout
  1957. */
  1958. Outlayer.prototype._resetLayout = function() {
  1959. this.getSize();
  1960. };
  1961.  
  1962.  
  1963. Outlayer.prototype.getSize = function() {
  1964. this.size = getSize( this.element );
  1965. };
  1966.  
  1967. /**
  1968. * get measurement from option, for columnWidth, rowHeight, gutter
  1969. * if option is String -> get element from selector string, & get size of element
  1970. * if option is Element -> get size of element
  1971. * else use option as a number
  1972. *
  1973. * @param {String} measurement
  1974. * @param {String} size - width or height
  1975. * @private
  1976. */
  1977. Outlayer.prototype._getMeasurement = function( measurement, size ) {
  1978. var option = this.options[ measurement ];
  1979. var elem;
  1980. if ( !option ) {
  1981. // default to 0
  1982. this[ measurement ] = 0;
  1983. } else {
  1984. // use option as an element
  1985. if ( typeof option === 'string' ) {
  1986. elem = this.element.querySelector( option );
  1987. } else if ( isElement( option ) ) {
  1988. elem = option;
  1989. }
  1990. // use size of element, if element
  1991. this[ measurement ] = elem ? getSize( elem )[ size ] : option;
  1992. }
  1993. };
  1994.  
  1995. /**
  1996. * layout a collection of item elements
  1997. * @api public
  1998. */
  1999. Outlayer.prototype.layoutItems = function( items, isInstant ) {
  2000. items = this._getItemsForLayout( items );
  2001.  
  2002. this._layoutItems( items, isInstant );
  2003.  
  2004. this._postLayout();
  2005. };
  2006.  
  2007. /**
  2008. * get the items to be laid out
  2009. * you may want to skip over some items
  2010. * @param {Array} items
  2011. * @returns {Array} items
  2012. */
  2013. Outlayer.prototype._getItemsForLayout = function( items ) {
  2014. var layoutItems = [];
  2015. for ( var i=0, len = items.length; i < len; i++ ) {
  2016. var item = items[i];
  2017. if ( !item.isIgnored ) {
  2018. layoutItems.push( item );
  2019. }
  2020. }
  2021. return layoutItems;
  2022. };
  2023.  
  2024. /**
  2025. * layout items
  2026. * @param {Array} items
  2027. * @param {Boolean} isInstant
  2028. */
  2029. Outlayer.prototype._layoutItems = function( items, isInstant ) {
  2030. var _this = this;
  2031. function onItemsLayout() {
  2032. _this.emitEvent( 'layoutComplete', [ _this, items ] );
  2033. }
  2034.  
  2035. if ( !items || !items.length ) {
  2036. // no items, emit event with empty array
  2037. onItemsLayout();
  2038. return;
  2039. }
  2040.  
  2041. // emit layoutComplete when done
  2042. this._itemsOn( items, 'layout', onItemsLayout );
  2043.  
  2044. var queue = [];
  2045.  
  2046. for ( var i=0, len = items.length; i < len; i++ ) {
  2047. var item = items[i];
  2048. // get x/y object from method
  2049. var position = this._getItemLayoutPosition( item );
  2050. // enqueue
  2051. position.item = item;
  2052. position.isInstant = isInstant || item.isLayoutInstant;
  2053. queue.push( position );
  2054. }
  2055.  
  2056. this._processLayoutQueue( queue );
  2057. };
  2058.  
  2059. /**
  2060. * get item layout position
  2061. * @param {Outlayer.Item} item
  2062. * @returns {Object} x and y position
  2063. */
  2064. Outlayer.prototype._getItemLayoutPosition = function( /* item */ ) {
  2065. return {
  2066. x: 0,
  2067. y: 0
  2068. };
  2069. };
  2070.  
  2071. /**
  2072. * iterate over array and position each item
  2073. * Reason being - separating this logic prevents 'layout invalidation'
  2074. * thx @paul_irish
  2075. * @param {Array} queue
  2076. */
  2077. Outlayer.prototype._processLayoutQueue = function( queue ) {
  2078. for ( var i=0, len = queue.length; i < len; i++ ) {
  2079. var obj = queue[i];
  2080. this._positionItem( obj.item, obj.x, obj.y, obj.isInstant );
  2081. }
  2082. };
  2083.  
  2084. /**
  2085. * Sets position of item in DOM
  2086. * @param {Outlayer.Item} item
  2087. * @param {Number} x - horizontal position
  2088. * @param {Number} y - vertical position
  2089. * @param {Boolean} isInstant - disables transitions
  2090. */
  2091. Outlayer.prototype._positionItem = function( item, x, y, isInstant ) {
  2092. if ( isInstant ) {
  2093. // if not transition, just set CSS
  2094. item.goTo( x, y );
  2095. } else {
  2096. item.moveTo( x, y );
  2097. }
  2098. };
  2099.  
  2100. /**
  2101. * Any logic you want to do after each layout,
  2102. * i.e. size the container
  2103. */
  2104. Outlayer.prototype._postLayout = function() {
  2105. this.resizeContainer();
  2106. };
  2107.  
  2108. Outlayer.prototype.resizeContainer = function() {
  2109. if ( !this.options.isResizingContainer ) {
  2110. return;
  2111. }
  2112. var size = this._getContainerSize();
  2113. if ( size ) {
  2114. this._setContainerMeasure( size.width, true );
  2115. this._setContainerMeasure( size.height, false );
  2116. }
  2117. };
  2118.  
  2119. /**
  2120. * Sets width or height of container if returned
  2121. * @returns {Object} size
  2122. * @param {Number} width
  2123. * @param {Number} height
  2124. */
  2125. Outlayer.prototype._getContainerSize = noop;
  2126.  
  2127. /**
  2128. * @param {Number} measure - size of width or height
  2129. * @param {Boolean} isWidth
  2130. */
  2131. Outlayer.prototype._setContainerMeasure = function( measure, isWidth ) {
  2132. if ( measure === undefined ) {
  2133. return;
  2134. }
  2135.  
  2136. var elemSize = this.size;
  2137. // add padding and border width if border box
  2138. if ( elemSize.isBorderBox ) {
  2139. measure += isWidth ? elemSize.paddingLeft + elemSize.paddingRight +
  2140. elemSize.borderLeftWidth + elemSize.borderRightWidth :
  2141. elemSize.paddingBottom + elemSize.paddingTop +
  2142. elemSize.borderTopWidth + elemSize.borderBottomWidth;
  2143. }
  2144.  
  2145. measure = Math.max( measure, 0 );
  2146. this.element.style[ isWidth ? 'width' : 'height' ] = measure + 'px';
  2147. };
  2148.  
  2149. /**
  2150. * trigger a callback for a collection of items events
  2151. * @param {Array} items - Outlayer.Items
  2152. * @param {String} eventName
  2153. * @param {Function} callback
  2154. */
  2155. Outlayer.prototype._itemsOn = function( items, eventName, callback ) {
  2156. var doneCount = 0;
  2157. var count = items.length;
  2158. // event callback
  2159. var _this = this;
  2160. function tick() {
  2161. doneCount++;
  2162. if ( doneCount === count ) {
  2163. callback.call( _this );
  2164. }
  2165. return true; // bind once
  2166. }
  2167. // bind callback
  2168. for ( var i=0, len = items.length; i < len; i++ ) {
  2169. var item = items[i];
  2170. item.on( eventName, tick );
  2171. }
  2172. };
  2173.  
  2174. // -------------------------- ignore & stamps -------------------------- //
  2175.  
  2176.  
  2177. /**
  2178. * keep item in collection, but do not lay it out
  2179. * ignored items do not get skipped in layout
  2180. * @param {Element} elem
  2181. */
  2182. Outlayer.prototype.ignore = function( elem ) {
  2183. var item = this.getItem( elem );
  2184. if ( item ) {
  2185. item.isIgnored = true;
  2186. }
  2187. };
  2188.  
  2189. /**
  2190. * return item to layout collection
  2191. * @param {Element} elem
  2192. */
  2193. Outlayer.prototype.unignore = function( elem ) {
  2194. var item = this.getItem( elem );
  2195. if ( item ) {
  2196. delete item.isIgnored;
  2197. }
  2198. };
  2199.  
  2200. /**
  2201. * adds elements to stamps
  2202. * @param {NodeList, Array, Element, or String} elems
  2203. */
  2204. Outlayer.prototype.stamp = function( elems ) {
  2205. elems = this._find( elems );
  2206. if ( !elems ) {
  2207. return;
  2208. }
  2209.  
  2210. this.stamps = this.stamps.concat( elems );
  2211. // ignore
  2212. for ( var i=0, len = elems.length; i < len; i++ ) {
  2213. var elem = elems[i];
  2214. this.ignore( elem );
  2215. }
  2216. };
  2217.  
  2218. /**
  2219. * removes elements to stamps
  2220. * @param {NodeList, Array, or Element} elems
  2221. */
  2222. Outlayer.prototype.unstamp = function( elems ) {
  2223. elems = this._find( elems );
  2224. if ( !elems ){
  2225. return;
  2226. }
  2227.  
  2228. for ( var i=0, len = elems.length; i < len; i++ ) {
  2229. var elem = elems[i];
  2230. // filter out removed stamp elements
  2231. removeFrom( elem, this.stamps );
  2232. this.unignore( elem );
  2233. }
  2234.  
  2235. };
  2236.  
  2237. /**
  2238. * finds child elements
  2239. * @param {NodeList, Array, Element, or String} elems
  2240. * @returns {Array} elems
  2241. */
  2242. Outlayer.prototype._find = function( elems ) {
  2243. if ( !elems ) {
  2244. return;
  2245. }
  2246. // if string, use argument as selector string
  2247. if ( typeof elems === 'string' ) {
  2248. elems = this.element.querySelectorAll( elems );
  2249. }
  2250. elems = makeArray( elems );
  2251. return elems;
  2252. };
  2253.  
  2254. Outlayer.prototype._manageStamps = function() {
  2255. if ( !this.stamps || !this.stamps.length ) {
  2256. return;
  2257. }
  2258.  
  2259. this._getBoundingRect();
  2260.  
  2261. for ( var i=0, len = this.stamps.length; i < len; i++ ) {
  2262. var stamp = this.stamps[i];
  2263. this._manageStamp( stamp );
  2264. }
  2265. };
  2266.  
  2267. // update boundingLeft / Top
  2268. Outlayer.prototype._getBoundingRect = function() {
  2269. // get bounding rect for container element
  2270. var boundingRect = this.element.getBoundingClientRect();
  2271. var size = this.size;
  2272. this._boundingRect = {
  2273. left: boundingRect.left + size.paddingLeft + size.borderLeftWidth,
  2274. top: boundingRect.top + size.paddingTop + size.borderTopWidth,
  2275. right: boundingRect.right - ( size.paddingRight + size.borderRightWidth ),
  2276. bottom: boundingRect.bottom - ( size.paddingBottom + size.borderBottomWidth )
  2277. };
  2278. };
  2279.  
  2280. /**
  2281. * @param {Element} stamp
  2282. **/
  2283. Outlayer.prototype._manageStamp = noop;
  2284.  
  2285. /**
  2286. * get x/y position of element relative to container element
  2287. * @param {Element} elem
  2288. * @returns {Object} offset - has left, top, right, bottom
  2289. */
  2290. Outlayer.prototype._getElementOffset = function( elem ) {
  2291. var boundingRect = elem.getBoundingClientRect();
  2292. var thisRect = this._boundingRect;
  2293. var size = getSize( elem );
  2294. var offset = {
  2295. left: boundingRect.left - thisRect.left - size.marginLeft,
  2296. top: boundingRect.top - thisRect.top - size.marginTop,
  2297. right: thisRect.right - boundingRect.right - size.marginRight,
  2298. bottom: thisRect.bottom - boundingRect.bottom - size.marginBottom
  2299. };
  2300. return offset;
  2301. };
  2302.  
  2303. // -------------------------- resize -------------------------- //
  2304.  
  2305. // enable event handlers for listeners
  2306. // i.e. resize -> onresize
  2307. Outlayer.prototype.handleEvent = function( event ) {
  2308. var method = 'on' + event.type;
  2309. if ( this[ method ] ) {
  2310. this[ method ]( event );
  2311. }
  2312. };
  2313.  
  2314. /**
  2315. * Bind layout to window resizing
  2316. */
  2317. Outlayer.prototype.bindResize = function() {
  2318. // bind just one listener
  2319. if ( this.isResizeBound ) {
  2320. return;
  2321. }
  2322. eventie.bind( window, 'resize', this );
  2323. this.isResizeBound = true;
  2324. };
  2325.  
  2326. /**
  2327. * Unbind layout to window resizing
  2328. */
  2329. Outlayer.prototype.unbindResize = function() {
  2330. if ( this.isResizeBound ) {
  2331. eventie.unbind( window, 'resize', this );
  2332. }
  2333. this.isResizeBound = false;
  2334. };
  2335.  
  2336. // original debounce by John Hann
  2337. // http://unscriptable.com/index.php/2009/03/20/debouncing-javascript-methods/
  2338.  
  2339. // this fires every resize
  2340. Outlayer.prototype.onresize = function() {
  2341. if ( this.resizeTimeout ) {
  2342. clearTimeout( this.resizeTimeout );
  2343. }
  2344.  
  2345. var _this = this;
  2346. function delayed() {
  2347. _this.resize();
  2348. delete _this.resizeTimeout;
  2349. }
  2350.  
  2351. this.resizeTimeout = setTimeout( delayed, 100 );
  2352. };
  2353.  
  2354. // debounced, layout on resize
  2355. Outlayer.prototype.resize = function() {
  2356. // don't trigger if size did not change
  2357. // or if resize was unbound. See #9
  2358. if ( !this.isResizeBound || !this.needsResizeLayout() ) {
  2359. return;
  2360. }
  2361.  
  2362. this.layout();
  2363. };
  2364.  
  2365. /**
  2366. * check if layout is needed post layout
  2367. * @returns Boolean
  2368. */
  2369. Outlayer.prototype.needsResizeLayout = function() {
  2370. var size = getSize( this.element );
  2371. // check that this.size and size are there
  2372. // IE8 triggers resize on body size change, so they might not be
  2373. var hasSizes = this.size && size;
  2374. return hasSizes && size.innerWidth !== this.size.innerWidth;
  2375. };
  2376.  
  2377. // -------------------------- methods -------------------------- //
  2378.  
  2379. /**
  2380. * add items to Outlayer instance
  2381. * @param {Array or NodeList or Element} elems
  2382. * @returns {Array} items - Outlayer.Items
  2383. **/
  2384. Outlayer.prototype.addItems = function( elems ) {
  2385. var items = this._itemize( elems );
  2386. // add items to collection
  2387. if ( items.length ) {
  2388. this.items = this.items.concat( items );
  2389. }
  2390. return items;
  2391. };
  2392.  
  2393. /**
  2394. * Layout newly-appended item elements
  2395. * @param {Array or NodeList or Element} elems
  2396. */
  2397. Outlayer.prototype.appended = function( elems ) {
  2398. var items = this.addItems( elems );
  2399. if ( !items.length ) {
  2400. return;
  2401. }
  2402. // layout and reveal just the new items
  2403. this.layoutItems( items, true );
  2404. this.reveal( items );
  2405. };
  2406.  
  2407. /**
  2408. * Layout prepended elements
  2409. * @param {Array or NodeList or Element} elems
  2410. */
  2411. Outlayer.prototype.prepended = function( elems ) {
  2412. var items = this._itemize( elems );
  2413. if ( !items.length ) {
  2414. return;
  2415. }
  2416. // add items to beginning of collection
  2417. var previousItems = this.items.slice(0);
  2418. this.items = items.concat( previousItems );
  2419. // start new layout
  2420. this._resetLayout();
  2421. this._manageStamps();
  2422. // layout new stuff without transition
  2423. this.layoutItems( items, true );
  2424. this.reveal( items );
  2425. // layout previous items
  2426. this.layoutItems( previousItems );
  2427. };
  2428.  
  2429. /**
  2430. * reveal a collection of items
  2431. * @param {Array of Outlayer.Items} items
  2432. */
  2433. Outlayer.prototype.reveal = function( items ) {
  2434. var len = items && items.length;
  2435. if ( !len ) {
  2436. return;
  2437. }
  2438. for ( var i=0; i < len; i++ ) {
  2439. var item = items[i];
  2440. item.reveal();
  2441. }
  2442. };
  2443.  
  2444. /**
  2445. * hide a collection of items
  2446. * @param {Array of Outlayer.Items} items
  2447. */
  2448. Outlayer.prototype.hide = function( items ) {
  2449. var len = items && items.length;
  2450. if ( !len ) {
  2451. return;
  2452. }
  2453. for ( var i=0; i < len; i++ ) {
  2454. var item = items[i];
  2455. item.hide();
  2456. }
  2457. };
  2458.  
  2459. /**
  2460. * get Outlayer.Item, given an Element
  2461. * @param {Element} elem
  2462. * @param {Function} callback
  2463. * @returns {Outlayer.Item} item
  2464. */
  2465. Outlayer.prototype.getItem = function( elem ) {
  2466. // loop through items to get the one that matches
  2467. for ( var i=0, len = this.items.length; i < len; i++ ) {
  2468. var item = this.items[i];
  2469. if ( item.element === elem ) {
  2470. // return item
  2471. return item;
  2472. }
  2473. }
  2474. };
  2475.  
  2476. /**
  2477. * get collection of Outlayer.Items, given Elements
  2478. * @param {Array} elems
  2479. * @returns {Array} items - Outlayer.Items
  2480. */
  2481. Outlayer.prototype.getItems = function( elems ) {
  2482. if ( !elems || !elems.length ) {
  2483. return;
  2484. }
  2485. var items = [];
  2486. for ( var i=0, len = elems.length; i < len; i++ ) {
  2487. var elem = elems[i];
  2488. var item = this.getItem( elem );
  2489. if ( item ) {
  2490. items.push( item );
  2491. }
  2492. }
  2493.  
  2494. return items;
  2495. };
  2496.  
  2497. /**
  2498. * remove element(s) from instance and DOM
  2499. * @param {Array or NodeList or Element} elems
  2500. */
  2501. Outlayer.prototype.remove = function( elems ) {
  2502. elems = makeArray( elems );
  2503.  
  2504. var removeItems = this.getItems( elems );
  2505. // bail if no items to remove
  2506. if ( !removeItems || !removeItems.length ) {
  2507. return;
  2508. }
  2509.  
  2510. this._itemsOn( removeItems, 'remove', function() {
  2511. this.emitEvent( 'removeComplete', [ this, removeItems ] );
  2512. });
  2513.  
  2514. for ( var i=0, len = removeItems.length; i < len; i++ ) {
  2515. var item = removeItems[i];
  2516. item.remove();
  2517. // remove item from collection
  2518. removeFrom( item, this.items );
  2519. }
  2520. };
  2521.  
  2522. // ----- destroy ----- //
  2523.  
  2524. // remove and disable Outlayer instance
  2525. Outlayer.prototype.destroy = function() {
  2526. // clean up dynamic styles
  2527. var style = this.element.style;
  2528. style.height = '';
  2529. style.position = '';
  2530. style.width = '';
  2531. // destroy items
  2532. for ( var i=0, len = this.items.length; i < len; i++ ) {
  2533. var item = this.items[i];
  2534. item.destroy();
  2535. }
  2536.  
  2537. this.unbindResize();
  2538.  
  2539. delete this.element.outlayerGUID;
  2540. // remove data for jQuery
  2541. if ( jQuery ) {
  2542. jQuery.removeData( this.element, this.constructor.namespace );
  2543. }
  2544.  
  2545. };
  2546.  
  2547. // -------------------------- data -------------------------- //
  2548.  
  2549. /**
  2550. * get Outlayer instance from element
  2551. * @param {Element} elem
  2552. * @returns {Outlayer}
  2553. */
  2554. Outlayer.data = function( elem ) {
  2555. var id = elem && elem.outlayerGUID;
  2556. return id && instances[ id ];
  2557. };
  2558.  
  2559.  
  2560. // -------------------------- create Outlayer class -------------------------- //
  2561.  
  2562. /**
  2563. * create a layout class
  2564. * @param {String} namespace
  2565. */
  2566. Outlayer.create = function( namespace, options ) {
  2567. // sub-class Outlayer
  2568. function Layout() {
  2569. Outlayer.apply( this, arguments );
  2570. }
  2571. // inherit Outlayer prototype, use Object.create if there
  2572. if ( Object.create ) {
  2573. Layout.prototype = Object.create( Outlayer.prototype );
  2574. } else {
  2575. extend( Layout.prototype, Outlayer.prototype );
  2576. }
  2577. // set contructor, used for namespace and Item
  2578. Layout.prototype.constructor = Layout;
  2579.  
  2580. Layout.defaults = extend( {}, Outlayer.defaults );
  2581. // apply new options
  2582. extend( Layout.defaults, options );
  2583. // keep prototype.settings for backwards compatibility (Packery v1.2.0)
  2584. Layout.prototype.settings = {};
  2585.  
  2586. Layout.namespace = namespace;
  2587.  
  2588. Layout.data = Outlayer.data;
  2589.  
  2590. // sub-class Item
  2591. Layout.Item = function LayoutItem() {
  2592. Item.apply( this, arguments );
  2593. };
  2594.  
  2595. Layout.Item.prototype = new Item();
  2596.  
  2597. // -------------------------- declarative -------------------------- //
  2598.  
  2599. /**
  2600. * allow user to initialize Outlayer via .js-namespace class
  2601. * options are parsed from data-namespace-option attribute
  2602. */
  2603. docReady( function() {
  2604. var dashedNamespace = toDashed( namespace );
  2605. var elems = document.querySelectorAll( '.js-' + dashedNamespace );
  2606. var dataAttr = 'data-' + dashedNamespace + '-options';
  2607.  
  2608. for ( var i=0, len = elems.length; i < len; i++ ) {
  2609. var elem = elems[i];
  2610. var attr = elem.getAttribute( dataAttr );
  2611. var options;
  2612. try {
  2613. options = attr && JSON.parse( attr );
  2614. } catch ( error ) {
  2615. // log error, do not initialize
  2616. if ( console ) {
  2617. console.error( 'Error parsing ' + dataAttr + ' on ' +
  2618. elem.nodeName.toLowerCase() + ( elem.id ? '#' + elem.id : '' ) + ': ' +
  2619. error );
  2620. }
  2621. continue;
  2622. }
  2623. // initialize
  2624. var instance = new Layout( elem, options );
  2625. // make available via $().data('layoutname')
  2626. if ( jQuery ) {
  2627. jQuery.data( elem, namespace, instance );
  2628. }
  2629. }
  2630. });
  2631.  
  2632. // -------------------------- jQuery bridge -------------------------- //
  2633.  
  2634. // make into jQuery plugin
  2635. if ( jQuery && jQuery.bridget ) {
  2636. jQuery.bridget( namespace, Layout );
  2637. }
  2638.  
  2639. return Layout;
  2640. };
  2641.  
  2642. // ----- fin ----- //
  2643.  
  2644. // back in global
  2645. Outlayer.Item = Item;
  2646.  
  2647. return Outlayer;
  2648.  
  2649. }
  2650.  
  2651. // -------------------------- transport -------------------------- //
  2652.  
  2653. if ( typeof define === 'function' && define.amd ) {
  2654. // AMD
  2655. define( 'outlayer/outlayer',[
  2656. 'eventie/eventie',
  2657. 'doc-ready/doc-ready',
  2658. 'eventEmitter/EventEmitter',
  2659. 'get-size/get-size',
  2660. 'matches-selector/matches-selector',
  2661. './item'
  2662. ],
  2663. outlayerDefinition );
  2664. } else {
  2665. // browser global
  2666. window.Outlayer = outlayerDefinition(
  2667. window.eventie,
  2668. window.docReady,
  2669. window.EventEmitter,
  2670. window.getSize,
  2671. window.matchesSelector,
  2672. window.Outlayer.Item
  2673. );
  2674. }
  2675.  
  2676. })( window );
  2677.  
  2678. /**
  2679. * Isotope Item
  2680. **/
  2681.  
  2682. ( function( window ) {
  2683.  
  2684.  
  2685.  
  2686. // -------------------------- Item -------------------------- //
  2687.  
  2688. function itemDefinition( Outlayer ) {
  2689.  
  2690. // sub-class Outlayer Item
  2691. function Item() {
  2692. Outlayer.Item.apply( this, arguments );
  2693. }
  2694.  
  2695. Item.prototype = new Outlayer.Item();
  2696.  
  2697. Item.prototype._create = function() {
  2698. // assign id, used for original-order sorting
  2699. this.id = this.layout.itemGUID++;
  2700. Outlayer.Item.prototype._create.call( this );
  2701. this.sortData = {};
  2702. };
  2703.  
  2704. Item.prototype.updateSortData = function() {
  2705. if ( this.isIgnored ) {
  2706. return;
  2707. }
  2708. // default sorters
  2709. this.sortData.id = this.id;
  2710. // for backward compatibility
  2711. this.sortData['original-order'] = this.id;
  2712. this.sortData.random = Math.random();
  2713. // go thru getSortData obj and apply the sorters
  2714. var getSortData = this.layout.options.getSortData;
  2715. var sorters = this.layout._sorters;
  2716. for ( var key in getSortData ) {
  2717. var sorter = sorters[ key ];
  2718. this.sortData[ key ] = sorter( this.element, this );
  2719. }
  2720. };
  2721.  
  2722. return Item;
  2723.  
  2724. }
  2725.  
  2726. // -------------------------- transport -------------------------- //
  2727.  
  2728. if ( typeof define === 'function' && define.amd ) {
  2729. // AMD
  2730. define( 'isotope/js/item',[
  2731. 'outlayer/outlayer'
  2732. ],
  2733. itemDefinition );
  2734. } else {
  2735. // browser global
  2736. window.Isotope = window.Isotope || {};
  2737. window.Isotope.Item = itemDefinition(
  2738. window.Outlayer
  2739. );
  2740. }
  2741.  
  2742. })( window );
  2743.  
  2744. ( function( window ) {
  2745.  
  2746.  
  2747.  
  2748. // -------------------------- -------------------------- //
  2749.  
  2750. function layoutModeDefinition( getSize, Outlayer ) {
  2751.  
  2752. // layout mode class
  2753. function LayoutMode( isotope ) {
  2754. this.isotope = isotope;
  2755. // link properties
  2756. if ( isotope ) {
  2757. this.options = isotope.options[ this.namespace ];
  2758. this.element = isotope.element;
  2759. this.items = isotope.filteredItems;
  2760. this.size = isotope.size;
  2761. }
  2762. }
  2763.  
  2764. /**
  2765. * some methods should just defer to default Outlayer method
  2766. * and reference the Isotope instance as `this`
  2767. **/
  2768. ( function() {
  2769. var facadeMethods = [
  2770. '_resetLayout',
  2771. '_getItemLayoutPosition',
  2772. '_manageStamp',
  2773. '_getContainerSize',
  2774. '_getElementOffset',
  2775. 'needsResizeLayout'
  2776. ];
  2777.  
  2778. for ( var i=0, len = facadeMethods.length; i < len; i++ ) {
  2779. var methodName = facadeMethods[i];
  2780. LayoutMode.prototype[ methodName ] = getOutlayerMethod( methodName );
  2781. }
  2782.  
  2783. function getOutlayerMethod( methodName ) {
  2784. return function() {
  2785. return Outlayer.prototype[ methodName ].apply( this.isotope, arguments );
  2786. };
  2787. }
  2788. })();
  2789.  
  2790. // ----- ----- //
  2791.  
  2792. // for horizontal layout modes, check vertical size
  2793. LayoutMode.prototype.needsVerticalResizeLayout = function() {
  2794. // don't trigger if size did not change
  2795. var size = getSize( this.isotope.element );
  2796. // check that this.size and size are there
  2797. // IE8 triggers resize on body size change, so they might not be
  2798. var hasSizes = this.isotope.size && size;
  2799. return hasSizes && size.innerHeight !== this.isotope.size.innerHeight;
  2800. };
  2801.  
  2802. // ----- measurements ----- //
  2803.  
  2804. LayoutMode.prototype._getMeasurement = function() {
  2805. this.isotope._getMeasurement.apply( this, arguments );
  2806. };
  2807.  
  2808. LayoutMode.prototype.getColumnWidth = function() {
  2809. this.getSegmentSize( 'column', 'Width' );
  2810. };
  2811.  
  2812. LayoutMode.prototype.getRowHeight = function() {
  2813. this.getSegmentSize( 'row', 'Height' );
  2814. };
  2815.  
  2816. /**
  2817. * get columnWidth or rowHeight
  2818. * segment: 'column' or 'row'
  2819. * size 'Width' or 'Height'
  2820. **/
  2821. LayoutMode.prototype.getSegmentSize = function( segment, size ) {
  2822. var segmentName = segment + size;
  2823. var outerSize = 'outer' + size;
  2824. // columnWidth / outerWidth // rowHeight / outerHeight
  2825. this._getMeasurement( segmentName, outerSize );
  2826. // got rowHeight or columnWidth, we can chill
  2827. if ( this[ segmentName ] ) {
  2828. return;
  2829. }
  2830. // fall back to item of first element
  2831. var firstItemSize = this.getFirstItemSize();
  2832. this[ segmentName ] = firstItemSize && firstItemSize[ outerSize ] ||
  2833. // or size of container
  2834. this.isotope.size[ 'inner' + size ];
  2835. };
  2836.  
  2837. LayoutMode.prototype.getFirstItemSize = function() {
  2838. var firstItem = this.isotope.filteredItems[0];
  2839. return firstItem && firstItem.element && getSize( firstItem.element );
  2840. };
  2841.  
  2842. // ----- methods that should reference isotope ----- //
  2843.  
  2844. LayoutMode.prototype.layout = function() {
  2845. this.isotope.layout.apply( this.isotope, arguments );
  2846. };
  2847.  
  2848. LayoutMode.prototype.getSize = function() {
  2849. this.isotope.getSize();
  2850. this.size = this.isotope.size;
  2851. };
  2852.  
  2853. // -------------------------- create -------------------------- //
  2854.  
  2855. LayoutMode.modes = {};
  2856.  
  2857. LayoutMode.create = function( namespace, options ) {
  2858.  
  2859. function Mode() {
  2860. LayoutMode.apply( this, arguments );
  2861. }
  2862.  
  2863. Mode.prototype = new LayoutMode();
  2864.  
  2865. // default options
  2866. if ( options ) {
  2867. Mode.options = options;
  2868. }
  2869.  
  2870. Mode.prototype.namespace = namespace;
  2871. // register in Isotope
  2872. LayoutMode.modes[ namespace ] = Mode;
  2873.  
  2874. return Mode;
  2875. };
  2876.  
  2877.  
  2878. return LayoutMode;
  2879.  
  2880. }
  2881.  
  2882. if ( typeof define === 'function' && define.amd ) {
  2883. // AMD
  2884. define( 'isotope/js/layout-mode',[
  2885. 'get-size/get-size',
  2886. 'outlayer/outlayer'
  2887. ],
  2888. layoutModeDefinition );
  2889. } else {
  2890. // browser global
  2891. window.Isotope = window.Isotope || {};
  2892. window.Isotope.LayoutMode = layoutModeDefinition(
  2893. window.getSize,
  2894. window.Outlayer
  2895. );
  2896. }
  2897.  
  2898.  
  2899. })( window );
  2900.  
  2901. /*!
  2902. * Masonry v3.1.5
  2903. * Cascading grid layout library
  2904. * http://masonry.desandro.com
  2905. * MIT License
  2906. * by David DeSandro
  2907. */
  2908.  
  2909. ( function( window ) {
  2910.  
  2911.  
  2912.  
  2913. // -------------------------- helpers -------------------------- //
  2914.  
  2915. var indexOf = Array.prototype.indexOf ?
  2916. function( items, value ) {
  2917. return items.indexOf( value );
  2918. } :
  2919. function ( items, value ) {
  2920. for ( var i=0, len = items.length; i < len; i++ ) {
  2921. var item = items[i];
  2922. if ( item === value ) {
  2923. return i;
  2924. }
  2925. }
  2926. return -1;
  2927. };
  2928.  
  2929. // -------------------------- masonryDefinition -------------------------- //
  2930.  
  2931. // used for AMD definition and requires
  2932. function masonryDefinition( Outlayer, getSize ) {
  2933. // create an Outlayer layout class
  2934. var Masonry = Outlayer.create('masonry');
  2935.  
  2936. Masonry.prototype._resetLayout = function() {
  2937. this.getSize();
  2938. this._getMeasurement( 'columnWidth', 'outerWidth' );
  2939. this._getMeasurement( 'gutter', 'outerWidth' );
  2940. this.measureColumns();
  2941.  
  2942. // reset column Y
  2943. var i = this.cols;
  2944. this.colYs = [];
  2945. while (i--) {
  2946. this.colYs.push( 0 );
  2947. }
  2948.  
  2949. this.maxY = 0;
  2950. };
  2951.  
  2952. Masonry.prototype.measureColumns = function() {
  2953. this.getContainerWidth();
  2954. // if columnWidth is 0, default to outerWidth of first item
  2955. if ( !this.columnWidth ) {
  2956. var firstItem = this.items[0];
  2957. var firstItemElem = firstItem && firstItem.element;
  2958. // columnWidth fall back to item of first element
  2959. this.columnWidth = firstItemElem && getSize( firstItemElem ).outerWidth ||
  2960. // if first elem has no width, default to size of container
  2961. this.containerWidth;
  2962. }
  2963.  
  2964. this.columnWidth += this.gutter;
  2965.  
  2966. this.cols = Math.floor( ( this.containerWidth + this.gutter ) / this.columnWidth );
  2967. this.cols = Math.max( this.cols, 1 );
  2968. };
  2969.  
  2970. Masonry.prototype.getContainerWidth = function() {
  2971. // container is parent if fit width
  2972. var container = this.options.isFitWidth ? this.element.parentNode : this.element;
  2973. // check that this.size and size are there
  2974. // IE8 triggers resize on body size change, so they might not be
  2975. var size = getSize( container );
  2976. this.containerWidth = size && size.innerWidth;
  2977. };
  2978.  
  2979. Masonry.prototype._getItemLayoutPosition = function( item ) {
  2980. item.getSize();
  2981. // how many columns does this brick span
  2982. var remainder = item.size.outerWidth % this.columnWidth;
  2983. var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
  2984. // round if off by 1 pixel, otherwise use ceil
  2985. var colSpan = Math[ mathMethod ]( item.size.outerWidth / this.columnWidth );
  2986. colSpan = Math.min( colSpan, this.cols );
  2987.  
  2988. var colGroup = this._getColGroup( colSpan );
  2989. // get the minimum Y value from the columns
  2990. var minimumY = Math.min.apply( Math, colGroup );
  2991. var shortColIndex = indexOf( colGroup, minimumY );
  2992.  
  2993. // position the brick
  2994. var position = {
  2995. x: this.columnWidth * shortColIndex,
  2996. y: minimumY
  2997. };
  2998.  
  2999. // apply setHeight to necessary columns
  3000. var setHeight = minimumY + item.size.outerHeight;
  3001. var setSpan = this.cols + 1 - colGroup.length;
  3002. for ( var i = 0; i < setSpan; i++ ) {
  3003. this.colYs[ shortColIndex + i ] = setHeight;
  3004. }
  3005.  
  3006. return position;
  3007. };
  3008.  
  3009. /**
  3010. * @param {Number} colSpan - number of columns the element spans
  3011. * @returns {Array} colGroup
  3012. */
  3013. Masonry.prototype._getColGroup = function( colSpan ) {
  3014. if ( colSpan < 2 ) {
  3015. // if brick spans only one column, use all the column Ys
  3016. return this.colYs;
  3017. }
  3018.  
  3019. var colGroup = [];
  3020. // how many different places could this brick fit horizontally
  3021. var groupCount = this.cols + 1 - colSpan;
  3022. // for each group potential horizontal position
  3023. for ( var i = 0; i < groupCount; i++ ) {
  3024. // make an array of colY values for that one group
  3025. var groupColYs = this.colYs.slice( i, i + colSpan );
  3026. // and get the max value of the array
  3027. colGroup[i] = Math.max.apply( Math, groupColYs );
  3028. }
  3029. return colGroup;
  3030. };
  3031.  
  3032. Masonry.prototype._manageStamp = function( stamp ) {
  3033. var stampSize = getSize( stamp );
  3034. var offset = this._getElementOffset( stamp );
  3035. // get the columns that this stamp affects
  3036. var firstX = this.options.isOriginLeft ? offset.left : offset.right;
  3037. var lastX = firstX + stampSize.outerWidth;
  3038. var firstCol = Math.floor( firstX / this.columnWidth );
  3039. firstCol = Math.max( 0, firstCol );
  3040. var lastCol = Math.floor( lastX / this.columnWidth );
  3041. // lastCol should not go over if multiple of columnWidth #425
  3042. lastCol -= lastX % this.columnWidth ? 0 : 1;
  3043. lastCol = Math.min( this.cols - 1, lastCol );
  3044. // set colYs to bottom of the stamp
  3045. var stampMaxY = ( this.options.isOriginTop ? offset.top : offset.bottom ) +
  3046. stampSize.outerHeight;
  3047. for ( var i = firstCol; i <= lastCol; i++ ) {
  3048. this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
  3049. }
  3050. };
  3051.  
  3052. Masonry.prototype._getContainerSize = function() {
  3053. this.maxY = Math.max.apply( Math, this.colYs );
  3054. var size = {
  3055. height: this.maxY
  3056. };
  3057.  
  3058. if ( this.options.isFitWidth ) {
  3059. size.width = this._getContainerFitWidth();
  3060. }
  3061.  
  3062. return size;
  3063. };
  3064.  
  3065. Masonry.prototype._getContainerFitWidth = function() {
  3066. var unusedCols = 0;
  3067. // count unused columns
  3068. var i = this.cols;
  3069. while ( --i ) {
  3070. if ( this.colYs[i] !== 0 ) {
  3071. break;
  3072. }
  3073. unusedCols++;
  3074. }
  3075. // fit container to columns that have been used
  3076. return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
  3077. };
  3078.  
  3079. Masonry.prototype.needsResizeLayout = function() {
  3080. var previousWidth = this.containerWidth;
  3081. this.getContainerWidth();
  3082. return previousWidth !== this.containerWidth;
  3083. };
  3084.  
  3085. return Masonry;
  3086. }
  3087.  
  3088. // -------------------------- transport -------------------------- //
  3089.  
  3090. if ( typeof define === 'function' && define.amd ) {
  3091. // AMD
  3092. define( 'masonry/masonry',[
  3093. 'outlayer/outlayer',
  3094. 'get-size/get-size'
  3095. ],
  3096. masonryDefinition );
  3097. } else {
  3098. // browser global
  3099. window.Masonry = masonryDefinition(
  3100. window.Outlayer,
  3101. window.getSize
  3102. );
  3103. }
  3104.  
  3105. })( window );
  3106.  
  3107. /*!
  3108. * Masonry layout mode
  3109. * sub-classes Masonry
  3110. * http://masonry.desandro.com
  3111. */
  3112.  
  3113. ( function( window ) {
  3114.  
  3115.  
  3116.  
  3117. // -------------------------- helpers -------------------------- //
  3118.  
  3119. // extend objects
  3120. function extend( a, b ) {
  3121. for ( var prop in b ) {
  3122. a[ prop ] = b[ prop ];
  3123. }
  3124. return a;
  3125. }
  3126.  
  3127. // -------------------------- masonryDefinition -------------------------- //
  3128.  
  3129. // used for AMD definition and requires
  3130. function masonryDefinition( LayoutMode, Masonry ) {
  3131. // create an Outlayer layout class
  3132. var MasonryMode = LayoutMode.create('masonry');
  3133.  
  3134. // save on to these methods
  3135. var _getElementOffset = MasonryMode.prototype._getElementOffset;
  3136. var layout = MasonryMode.prototype.layout;
  3137. var _getMeasurement = MasonryMode.prototype._getMeasurement;
  3138.  
  3139. // sub-class Masonry
  3140. extend( MasonryMode.prototype, Masonry.prototype );
  3141.  
  3142. // set back, as it was overwritten by Masonry
  3143. MasonryMode.prototype._getElementOffset = _getElementOffset;
  3144. MasonryMode.prototype.layout = layout;
  3145. MasonryMode.prototype._getMeasurement = _getMeasurement;
  3146.  
  3147. var measureColumns = MasonryMode.prototype.measureColumns;
  3148. MasonryMode.prototype.measureColumns = function() {
  3149. // set items, used if measuring first item
  3150. this.items = this.isotope.filteredItems;
  3151. measureColumns.call( this );
  3152. };
  3153.  
  3154. // HACK copy over isOriginLeft/Top options
  3155. var _manageStamp = MasonryMode.prototype._manageStamp;
  3156. MasonryMode.prototype._manageStamp = function() {
  3157. this.options.isOriginLeft = this.isotope.options.isOriginLeft;
  3158. this.options.isOriginTop = this.isotope.options.isOriginTop;
  3159. _manageStamp.apply( this, arguments );
  3160. };
  3161.  
  3162. return MasonryMode;
  3163. }
  3164.  
  3165. // -------------------------- transport -------------------------- //
  3166.  
  3167. if ( typeof define === 'function' && define.amd ) {
  3168. // AMD
  3169. define( 'isotope/js/layout-modes/masonry',[
  3170. '../layout-mode',
  3171. 'masonry/masonry'
  3172. ],
  3173. masonryDefinition );
  3174. } else {
  3175. // browser global
  3176. masonryDefinition(
  3177. window.Isotope.LayoutMode,
  3178. window.Masonry
  3179. );
  3180. }
  3181.  
  3182. })( window );
  3183.  
  3184. ( function( window ) {
  3185.  
  3186.  
  3187.  
  3188. function fitRowsDefinition( LayoutMode ) {
  3189.  
  3190. var FitRows = LayoutMode.create('fitRows');
  3191.  
  3192. FitRows.prototype._resetLayout = function() {
  3193. this.x = 0;
  3194. this.y = 0;
  3195. this.maxY = 0;
  3196. };
  3197.  
  3198. FitRows.prototype._getItemLayoutPosition = function( item ) {
  3199. item.getSize();
  3200.  
  3201. // if this element cannot fit in the current row
  3202. if ( this.x !== 0 && item.size.outerWidth + this.x > this.isotope.size.innerWidth ) {
  3203. this.x = 0;
  3204. this.y = this.maxY;
  3205. }
  3206.  
  3207. var position = {
  3208. x: this.x,
  3209. y: this.y
  3210. };
  3211.  
  3212. this.maxY = Math.max( this.maxY, this.y + item.size.outerHeight );
  3213. this.x += item.size.outerWidth;
  3214.  
  3215. return position;
  3216. };
  3217.  
  3218. FitRows.prototype._getContainerSize = function() {
  3219. return { height: this.maxY };
  3220. };
  3221.  
  3222. return FitRows;
  3223.  
  3224. }
  3225.  
  3226. if ( typeof define === 'function' && define.amd ) {
  3227. // AMD
  3228. define( 'isotope/js/layout-modes/fit-rows',[
  3229. '../layout-mode'
  3230. ],
  3231. fitRowsDefinition );
  3232. } else {
  3233. // browser global
  3234. fitRowsDefinition(
  3235. window.Isotope.LayoutMode
  3236. );
  3237. }
  3238.  
  3239. })( window );
  3240.  
  3241. ( function( window ) {
  3242.  
  3243.  
  3244.  
  3245. function verticalDefinition( LayoutMode ) {
  3246.  
  3247. var Vertical = LayoutMode.create( 'vertical', {
  3248. horizontalAlignment: 0
  3249. });
  3250.  
  3251. Vertical.prototype._resetLayout = function() {
  3252. this.y = 0;
  3253. };
  3254.  
  3255. Vertical.prototype._getItemLayoutPosition = function( item ) {
  3256. item.getSize();
  3257. var x = ( this.isotope.size.innerWidth - item.size.outerWidth ) *
  3258. this.options.horizontalAlignment;
  3259. var y = this.y;
  3260. this.y += item.size.outerHeight;
  3261. return { x: x, y: y };
  3262. };
  3263.  
  3264. Vertical.prototype._getContainerSize = function() {
  3265. return { height: this.y };
  3266. };
  3267.  
  3268. return Vertical;
  3269.  
  3270. }
  3271.  
  3272. if ( typeof define === 'function' && define.amd ) {
  3273. // AMD
  3274. define( 'isotope/js/layout-modes/vertical',[
  3275. '../layout-mode'
  3276. ],
  3277. verticalDefinition );
  3278. } else {
  3279. // browser global
  3280. verticalDefinition(
  3281. window.Isotope.LayoutMode
  3282. );
  3283. }
  3284.  
  3285. })( window );
  3286.  
  3287. /*!
  3288. * Isotope v2.0.0
  3289. * Filter & sort magical layouts
  3290. * http://isotope.metafizzy.co
  3291. */
  3292.  
  3293. ( function( window ) {
  3294.  
  3295.  
  3296.  
  3297. // -------------------------- vars -------------------------- //
  3298.  
  3299. var jQuery = window.jQuery;
  3300.  
  3301. // -------------------------- helpers -------------------------- //
  3302.  
  3303. // extend objects
  3304. function extend( a, b ) {
  3305. for ( var prop in b ) {
  3306. a[ prop ] = b[ prop ];
  3307. }
  3308. return a;
  3309. }
  3310.  
  3311. var trim = String.prototype.trim ?
  3312. function( str ) {
  3313. return str.trim();
  3314. } :
  3315. function( str ) {
  3316. return str.replace( /^\s+|\s+$/g, '' );
  3317. };
  3318.  
  3319. var docElem = document.documentElement;
  3320.  
  3321. var getText = docElem.textContent ?
  3322. function( elem ) {
  3323. return elem.textContent;
  3324. } :
  3325. function( elem ) {
  3326. return elem.innerText;
  3327. };
  3328.  
  3329. var objToString = Object.prototype.toString;
  3330. function isArray( obj ) {
  3331. return objToString.call( obj ) === '[object Array]';
  3332. }
  3333.  
  3334. // index of helper cause IE8
  3335. var indexOf = Array.prototype.indexOf ? function( ary, obj ) {
  3336. return ary.indexOf( obj );
  3337. } : function( ary, obj ) {
  3338. for ( var i=0, len = ary.length; i < len; i++ ) {
  3339. if ( ary[i] === obj ) {
  3340. return i;
  3341. }
  3342. }
  3343. return -1;
  3344. };
  3345.  
  3346. // turn element or nodeList into an array
  3347. function makeArray( obj ) {
  3348. var ary = [];
  3349. if ( isArray( obj ) ) {
  3350. // use object if already an array
  3351. ary = obj;
  3352. } else if ( obj && typeof obj.length === 'number' ) {
  3353. // convert nodeList to array
  3354. for ( var i=0, len = obj.length; i < len; i++ ) {
  3355. ary.push( obj[i] );
  3356. }
  3357. } else {
  3358. // array of single index
  3359. ary.push( obj );
  3360. }
  3361. return ary;
  3362. }
  3363.  
  3364. function removeFrom( obj, ary ) {
  3365. var index = indexOf( ary, obj );
  3366. if ( index !== -1 ) {
  3367. ary.splice( index, 1 );
  3368. }
  3369. }
  3370.  
  3371. // -------------------------- isotopeDefinition -------------------------- //
  3372.  
  3373. // used for AMD definition and requires
  3374. function isotopeDefinition( Outlayer, getSize, matchesSelector, Item, LayoutMode ) {
  3375. // create an Outlayer layout class
  3376. var Isotope = Outlayer.create( 'isotope', {
  3377. layoutMode: "masonry",
  3378. isJQueryFiltering: true,
  3379. sortAscending: true
  3380. });
  3381.  
  3382. Isotope.Item = Item;
  3383. Isotope.LayoutMode = LayoutMode;
  3384.  
  3385. Isotope.prototype._create = function() {
  3386. this.itemGUID = 0;
  3387. // functions that sort items
  3388. this._sorters = {};
  3389. this._getSorters();
  3390. // call super
  3391. Outlayer.prototype._create.call( this );
  3392.  
  3393. // create layout modes
  3394. this.modes = {};
  3395. // start filteredItems with all items
  3396. this.filteredItems = this.items;
  3397. // keep of track of sortBys
  3398. this.sortHistory = [ 'original-order' ];
  3399. // create from registered layout modes
  3400. for ( var name in LayoutMode.modes ) {
  3401. this._initLayoutMode( name );
  3402. }
  3403. };
  3404.  
  3405. Isotope.prototype.reloadItems = function() {
  3406. // reset item ID counter
  3407. this.itemGUID = 0;
  3408. // call super
  3409. Outlayer.prototype.reloadItems.call( this );
  3410. };
  3411.  
  3412. Isotope.prototype._itemize = function() {
  3413. var items = Outlayer.prototype._itemize.apply( this, arguments );
  3414. // assign ID for original-order
  3415. for ( var i=0, len = items.length; i < len; i++ ) {
  3416. var item = items[i];
  3417. item.id = this.itemGUID++;
  3418. }
  3419. this._updateItemsSortData( items );
  3420. return items;
  3421. };
  3422.  
  3423.  
  3424. // -------------------------- layout -------------------------- //
  3425.  
  3426. Isotope.prototype._initLayoutMode = function( name ) {
  3427. var Mode = LayoutMode.modes[ name ];
  3428. // set mode options
  3429. // HACK extend initial options, back-fill in default options
  3430. var initialOpts = this.options[ name ] || {};
  3431. this.options[ name ] = Mode.options ?
  3432. extend( Mode.options, initialOpts ) : initialOpts;
  3433. // init layout mode instance
  3434. this.modes[ name ] = new Mode( this );
  3435. };
  3436.  
  3437.  
  3438. Isotope.prototype.layout = function() {
  3439. // if first time doing layout, do all magic
  3440. if ( !this._isLayoutInited && this.options.isInitLayout ) {
  3441. this.arrange();
  3442. return;
  3443. }
  3444. this._layout();
  3445. };
  3446.  
  3447. // private method to be used in layout() & magic()
  3448. Isotope.prototype._layout = function() {
  3449. // don't animate first layout
  3450. var isInstant = this._getIsInstant();
  3451. // layout flow
  3452. this._resetLayout();
  3453. this._manageStamps();
  3454. this.layoutItems( this.filteredItems, isInstant );
  3455.  
  3456. // flag for initalized
  3457. this._isLayoutInited = true;
  3458. };
  3459.  
  3460. // filter + sort + layout
  3461. Isotope.prototype.arrange = function( opts ) {
  3462. // set any options pass
  3463. this.option( opts );
  3464. this._getIsInstant();
  3465. // filter, sort, and layout
  3466. this.filteredItems = this._filter( this.items );
  3467. this._sort();
  3468. this._layout();
  3469. };
  3470. // alias to _init for main plugin method
  3471. Isotope.prototype._init = Isotope.prototype.arrange;
  3472.  
  3473. // HACK
  3474. // Don't animate/transition first layout
  3475. // Or don't animate/transition other layouts
  3476. Isotope.prototype._getIsInstant = function() {
  3477. var isInstant = this.options.isLayoutInstant !== undefined ?
  3478. this.options.isLayoutInstant : !this._isLayoutInited;
  3479. this._isInstant = isInstant;
  3480. return isInstant;
  3481. };
  3482.  
  3483. // -------------------------- filter -------------------------- //
  3484.  
  3485. Isotope.prototype._filter = function( items ) {
  3486. var filter = this.options.filter;
  3487. filter = filter || '*';
  3488. var matches = [];
  3489. var hiddenMatched = [];
  3490. var visibleUnmatched = [];
  3491.  
  3492. var test = this._getFilterTest( filter );
  3493.  
  3494. // test each item
  3495. for ( var i=0, len = items.length; i < len; i++ ) {
  3496. var item = items[i];
  3497. if ( item.isIgnored ) {
  3498. continue;
  3499. }
  3500. // add item to either matched or unmatched group
  3501. var isMatched = test( item );
  3502. // item.isFilterMatched = isMatched;
  3503. // add to matches if its a match
  3504. if ( isMatched ) {
  3505. matches.push( item );
  3506. }
  3507. // add to additional group if item needs to be hidden or revealed
  3508. if ( isMatched && item.isHidden ) {
  3509. hiddenMatched.push( item );
  3510. } else if ( !isMatched && !item.isHidden ) {
  3511. visibleUnmatched.push( item );
  3512. }
  3513. }
  3514.  
  3515. var _this = this;
  3516. function hideReveal() {
  3517. _this.reveal( hiddenMatched );
  3518. _this.hide( visibleUnmatched );
  3519. }
  3520.  
  3521. if ( this._isInstant ) {
  3522. this._noTransition( hideReveal );
  3523. } else {
  3524. hideReveal();
  3525. }
  3526.  
  3527. return matches;
  3528. };
  3529.  
  3530. // get a jQuery, function, or a matchesSelector test given the filter
  3531. Isotope.prototype._getFilterTest = function( filter ) {
  3532. if ( jQuery && this.options.isJQueryFiltering ) {
  3533. // use jQuery
  3534. return function( item ) {
  3535. return jQuery( item.element ).is( filter );
  3536. };
  3537. }
  3538. if ( typeof filter === 'function' ) {
  3539. // use filter as function
  3540. return function( item ) {
  3541. return filter( item.element );
  3542. };
  3543. }
  3544. // default, use filter as selector string
  3545. return function( item ) {
  3546. return matchesSelector( item.element, filter );
  3547. };
  3548. };
  3549.  
  3550. // -------------------------- sorting -------------------------- //
  3551.  
  3552. /**
  3553. * @params {Array} elems
  3554. * @public
  3555. */
  3556. Isotope.prototype.updateSortData = function( elems ) {
  3557. this._getSorters();
  3558. // update item sort data
  3559. // default to all items if none are passed in
  3560. elems = makeArray( elems );
  3561. var items = this.getItems( elems );
  3562. // if no items found, update all items
  3563. items = items.length ? items : this.items;
  3564. this._updateItemsSortData( items );
  3565. };
  3566.  
  3567. Isotope.prototype._getSorters = function() {
  3568. var getSortData = this.options.getSortData;
  3569. for ( var key in getSortData ) {
  3570. var sorter = getSortData[ key ];
  3571. this._sorters[ key ] = mungeSorter( sorter );
  3572. }
  3573. };
  3574.  
  3575. /**
  3576. * @params {Array} items - of Isotope.Items
  3577. * @private
  3578. */
  3579. Isotope.prototype._updateItemsSortData = function( items ) {
  3580. for ( var i=0, len = items.length; i < len; i++ ) {
  3581. var item = items[i];
  3582. item.updateSortData();
  3583. }
  3584. };
  3585.  
  3586. // ----- munge sorter ----- //
  3587.  
  3588. // encapsulate this, as we just need mungeSorter
  3589. // other functions in here are just for munging
  3590. var mungeSorter = ( function() {
  3591. // add a magic layer to sorters for convienent shorthands
  3592. // `.foo-bar` will use the text of .foo-bar querySelector
  3593. // `[foo-bar]` will use attribute
  3594. // you can also add parser
  3595. // `.foo-bar parseInt` will parse that as a number
  3596. function mungeSorter( sorter ) {
  3597. // if not a string, return function or whatever it is
  3598. if ( typeof sorter !== 'string' ) {
  3599. return sorter;
  3600. }
  3601. // parse the sorter string
  3602. var args = trim( sorter ).split(' ');
  3603. var query = args[0];
  3604. // check if query looks like [an-attribute]
  3605. var attrMatch = query.match( /^\[(.+)\]$/ );
  3606. var attr = attrMatch && attrMatch[1];
  3607. var getValue = getValueGetter( attr, query );
  3608. // use second argument as a parser
  3609. var parser = Isotope.sortDataParsers[ args[1] ];
  3610. // parse the value, if there was a parser
  3611. sorter = parser ? function( elem ) {
  3612. return elem && parser( getValue( elem ) );
  3613. } :
  3614. // otherwise just return value
  3615. function( elem ) {
  3616. return elem && getValue( elem );
  3617. };
  3618.  
  3619. return sorter;
  3620. }
  3621.  
  3622. // get an attribute getter, or get text of the querySelector
  3623. function getValueGetter( attr, query ) {
  3624. var getValue;
  3625. // if query looks like [foo-bar], get attribute
  3626. if ( attr ) {
  3627. getValue = function( elem ) {
  3628. return elem.getAttribute( attr );
  3629. };
  3630. } else {
  3631. // otherwise, assume its a querySelector, and get its text
  3632. getValue = function( elem ) {
  3633. var child = elem.querySelector( query );
  3634. return child && getText( child );
  3635. };
  3636. }
  3637. return getValue;
  3638. }
  3639.  
  3640. return mungeSorter;
  3641. })();
  3642.  
  3643. // parsers used in getSortData shortcut strings
  3644. Isotope.sortDataParsers = {
  3645. 'parseInt': function( val ) {
  3646. return parseInt( val, 10 );
  3647. },
  3648. 'parseFloat': function( val ) {
  3649. return parseFloat( val );
  3650. }
  3651. };
  3652.  
  3653. // ----- sort method ----- //
  3654.  
  3655. // sort filteredItem order
  3656. Isotope.prototype._sort = function() {
  3657. var sortByOpt = this.options.sortBy;
  3658. if ( !sortByOpt ) {
  3659. return;
  3660. }
  3661. // concat all sortBy and sortHistory
  3662. var sortBys = [].concat.apply( sortByOpt, this.sortHistory );
  3663. // sort magic
  3664. var itemSorter = getItemSorter( sortBys, this.options.sortAscending );
  3665. this.filteredItems.sort( itemSorter );
  3666. // keep track of sortBy History
  3667. if ( sortByOpt !== this.sortHistory[0] ) {
  3668. // add to front, oldest goes in last
  3669. this.sortHistory.unshift( sortByOpt );
  3670. }
  3671. };
  3672.  
  3673. // returns a function used for sorting
  3674. function getItemSorter( sortBys, sortAsc ) {
  3675. return function sorter( itemA, itemB ) {
  3676. // cycle through all sortKeys
  3677. for ( var i = 0, len = sortBys.length; i < len; i++ ) {
  3678. var sortBy = sortBys[i];
  3679. var a = itemA.sortData[ sortBy ];
  3680. var b = itemB.sortData[ sortBy ];
  3681. if ( a > b || a < b ) {
  3682. // if sortAsc is an object, use the value given the sortBy key
  3683. var isAscending = sortAsc[ sortBy ] !== undefined ? sortAsc[ sortBy ] : sortAsc;
  3684. var direction = isAscending ? 1 : -1;
  3685. return ( a > b ? 1 : -1 ) * direction;
  3686. }
  3687. }
  3688. return 0;
  3689. };
  3690. }
  3691.  
  3692. // -------------------------- methods -------------------------- //
  3693.  
  3694. // get layout mode
  3695. Isotope.prototype._mode = function() {
  3696. var layoutMode = this.options.layoutMode;
  3697. var mode = this.modes[ layoutMode ];
  3698. if ( !mode ) {
  3699. // TODO console.error
  3700. throw new Error( 'No layout mode: ' + layoutMode );
  3701. }
  3702. // HACK sync mode's options
  3703. // any options set after init for layout mode need to be synced
  3704. mode.options = this.options[ layoutMode ];
  3705. return mode;
  3706. };
  3707.  
  3708. Isotope.prototype._resetLayout = function() {
  3709. // trigger original reset layout
  3710. Outlayer.prototype._resetLayout.call( this );
  3711. this._mode()._resetLayout();
  3712. };
  3713.  
  3714. Isotope.prototype._getItemLayoutPosition = function( item ) {
  3715. return this._mode()._getItemLayoutPosition( item );
  3716. };
  3717.  
  3718. Isotope.prototype._manageStamp = function( stamp ) {
  3719. this._mode()._manageStamp( stamp );
  3720. };
  3721.  
  3722. Isotope.prototype._getContainerSize = function() {
  3723. return this._mode()._getContainerSize();
  3724. };
  3725.  
  3726. Isotope.prototype.needsResizeLayout = function() {
  3727. return this._mode().needsResizeLayout();
  3728. };
  3729.  
  3730. // -------------------------- adding & removing -------------------------- //
  3731.  
  3732. // HEADS UP overwrites default Outlayer appended
  3733. Isotope.prototype.appended = function( elems ) {
  3734. var items = this.addItems( elems );
  3735. if ( !items.length ) {
  3736. return;
  3737. }
  3738. var filteredItems = this._filterRevealAdded( items );
  3739. // add to filteredItems
  3740. this.filteredItems = this.filteredItems.concat( filteredItems );
  3741. };
  3742.  
  3743. // HEADS UP overwrites default Outlayer prepended
  3744. Isotope.prototype.prepended = function( elems ) {
  3745. var items = this._itemize( elems );
  3746. if ( !items.length ) {
  3747. return;
  3748. }
  3749. // add items to beginning of collection
  3750. var previousItems = this.items.slice(0);
  3751. this.items = items.concat( previousItems );
  3752. // start new layout
  3753. this._resetLayout();
  3754. this._manageStamps();
  3755. // layout new stuff without transition
  3756. var filteredItems = this._filterRevealAdded( items );
  3757. // layout previous items
  3758. this.layoutItems( previousItems );
  3759. // add to filteredItems
  3760. this.filteredItems = filteredItems.concat( this.filteredItems );
  3761. };
  3762.  
  3763. Isotope.prototype._filterRevealAdded = function( items ) {
  3764. var filteredItems = this._noTransition( function() {
  3765. return this._filter( items );
  3766. });
  3767. // layout and reveal just the new items
  3768. this.layoutItems( filteredItems, true );
  3769. this.reveal( filteredItems );
  3770. return items;
  3771. };
  3772.  
  3773. /**
  3774. * Filter, sort, and layout newly-appended item elements
  3775. * @param {Array or NodeList or Element} elems
  3776. */
  3777. Isotope.prototype.insert = function( elems ) {
  3778. var items = this.addItems( elems );
  3779. if ( !items.length ) {
  3780. return;
  3781. }
  3782. // append item elements
  3783. var i, item;
  3784. var len = items.length;
  3785. for ( i=0; i < len; i++ ) {
  3786. item = items[i];
  3787. this.element.appendChild( item.element );
  3788. }
  3789. // filter new stuff
  3790. /*
  3791. // this way adds hides new filtered items with NO transition
  3792. // so user can't see if new hidden items have been inserted
  3793. var filteredInsertItems;
  3794. this._noTransition( function() {
  3795. filteredInsertItems = this._filter( items );
  3796. // hide all new items
  3797. this.hide( filteredInsertItems );
  3798. });
  3799. // */
  3800. // this way hides new filtered items with transition
  3801. // so user at least sees that something has been added
  3802. var filteredInsertItems = this._filter( items );
  3803. // hide all newitems
  3804. this._noTransition( function() {
  3805. this.hide( filteredInsertItems );
  3806. });
  3807. // */
  3808. // set flag
  3809. for ( i=0; i < len; i++ ) {
  3810. items[i].isLayoutInstant = true;
  3811. }
  3812. this.arrange();
  3813. // reset flag
  3814. for ( i=0; i < len; i++ ) {
  3815. delete items[i].isLayoutInstant;
  3816. }
  3817. this.reveal( filteredInsertItems );
  3818. };
  3819.  
  3820. var _remove = Isotope.prototype.remove;
  3821. Isotope.prototype.remove = function( elems ) {
  3822. elems = makeArray( elems );
  3823. var removeItems = this.getItems( elems );
  3824. // do regular thing
  3825. _remove.call( this, elems );
  3826. // bail if no items to remove
  3827. if ( !removeItems || !removeItems.length ) {
  3828. return;
  3829. }
  3830. // remove elems from filteredItems
  3831. for ( var i=0, len = removeItems.length; i < len; i++ ) {
  3832. var item = removeItems[i];
  3833. // remove item from collection
  3834. removeFrom( item, this.filteredItems );
  3835. }
  3836. };
  3837.  
  3838. /**
  3839. * trigger fn without transition
  3840. * kind of hacky to have this in the first place
  3841. * @param {Function} fn
  3842. * @returns ret
  3843. * @private
  3844. */
  3845. Isotope.prototype._noTransition = function( fn ) {
  3846. // save transitionDuration before disabling
  3847. var transitionDuration = this.options.transitionDuration;
  3848. // disable transition
  3849. this.options.transitionDuration = 0;
  3850. // do it
  3851. var returnValue = fn.call( this );
  3852. // re-enable transition for reveal
  3853. this.options.transitionDuration = transitionDuration;
  3854. return returnValue;
  3855. };
  3856.  
  3857. // ----- ----- //
  3858.  
  3859. return Isotope;
  3860. }
  3861.  
  3862. // -------------------------- transport -------------------------- //
  3863.  
  3864.  
  3865. // browser global
  3866. window.Isotope = isotopeDefinition(
  3867. window.Outlayer,
  3868. window.getSize,
  3869. window.matchesSelector,
  3870. window.Isotope.Item,
  3871. window.Isotope.LayoutMode
  3872. );
  3873.  
  3874.  
  3875. })( window );
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement