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