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