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