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