1/*! 2 * Isotope PACKAGED v2.2.2 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 'use strict'; 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 'use strict'; 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 'use strict'; 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 'use strict'; 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'use strict'; 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 xValue = style[ isOriginLeft ? 'left' : 'right' ]; 1639 var yValue = style[ isOriginTop ? 'top' : 'bottom' ]; 1640 // convert percent to pixels 1641 var layoutSize = this.layout.size; 1642 var x = xValue.indexOf('%') != -1 ? 1643 ( parseFloat( xValue ) / 100 ) * layoutSize.width : parseInt( xValue, 10 ); 1644 var y = yValue.indexOf('%') != -1 ? 1645 ( parseFloat( yValue ) / 100 ) * layoutSize.height : parseInt( yValue, 10 ); 1646 1647 // clean up 'auto' or other non-integer values 1648 x = isNaN( x ) ? 0 : x; 1649 y = isNaN( y ) ? 0 : y; 1650 // remove padding from measurement 1651 x -= isOriginLeft ? layoutSize.paddingLeft : layoutSize.paddingRight; 1652 y -= isOriginTop ? layoutSize.paddingTop : layoutSize.paddingBottom; 1653 1654 this.position.x = x; 1655 this.position.y = y; 1656}; 1657 1658// set settled position, apply padding 1659Item.prototype.layoutPosition = function() { 1660 var layoutSize = this.layout.size; 1661 var layoutOptions = this.layout.options; 1662 var style = {}; 1663 1664 // x 1665 var xPadding = layoutOptions.isOriginLeft ? 'paddingLeft' : 'paddingRight'; 1666 var xProperty = layoutOptions.isOriginLeft ? 'left' : 'right'; 1667 var xResetProperty = layoutOptions.isOriginLeft ? 'right' : 'left'; 1668 1669 var x = this.position.x + layoutSize[ xPadding ]; 1670 // set in percentage or pixels 1671 style[ xProperty ] = this.getXValue( x ); 1672 // reset other property 1673 style[ xResetProperty ] = ''; 1674 1675 // y 1676 var yPadding = layoutOptions.isOriginTop ? 'paddingTop' : 'paddingBottom'; 1677 var yProperty = layoutOptions.isOriginTop ? 'top' : 'bottom'; 1678 var yResetProperty = layoutOptions.isOriginTop ? 'bottom' : 'top'; 1679 1680 var y = this.position.y + layoutSize[ yPadding ]; 1681 // set in percentage or pixels 1682 style[ yProperty ] = this.getYValue( y ); 1683 // reset other property 1684 style[ yResetProperty ] = ''; 1685 1686 this.css( style ); 1687 this.emitEvent( 'layout', [ this ] ); 1688}; 1689 1690Item.prototype.getXValue = function( x ) { 1691 var layoutOptions = this.layout.options; 1692 return layoutOptions.percentPosition && !layoutOptions.isHorizontal ? 1693 ( ( x / this.layout.size.width ) * 100 ) + '%' : x + 'px'; 1694}; 1695 1696Item.prototype.getYValue = function( y ) { 1697 var layoutOptions = this.layout.options; 1698 return layoutOptions.percentPosition && layoutOptions.isHorizontal ? 1699 ( ( y / this.layout.size.height ) * 100 ) + '%' : y + 'px'; 1700}; 1701 1702 1703Item.prototype._transitionTo = function( x, y ) { 1704 this.getPosition(); 1705 // get current x & y from top/left 1706 var curX = this.position.x; 1707 var curY = this.position.y; 1708 1709 var compareX = parseInt( x, 10 ); 1710 var compareY = parseInt( y, 10 ); 1711 var didNotMove = compareX === this.position.x && compareY === this.position.y; 1712 1713 // save end position 1714 this.setPosition( x, y ); 1715 1716 // if did not move and not transitioning, just go to layout 1717 if ( didNotMove && !this.isTransitioning ) { 1718 this.layoutPosition(); 1719 return; 1720 } 1721 1722 var transX = x - curX; 1723 var transY = y - curY; 1724 var transitionStyle = {}; 1725 transitionStyle.transform = this.getTranslate( transX, transY ); 1726 1727 this.transition({ 1728 to: transitionStyle, 1729 onTransitionEnd: { 1730 transform: this.layoutPosition 1731 }, 1732 isCleaning: true 1733 }); 1734}; 1735 1736Item.prototype.getTranslate = function( x, y ) { 1737 // flip cooridinates if origin on right or bottom 1738 var layoutOptions = this.layout.options; 1739 x = layoutOptions.isOriginLeft ? x : -x; 1740 y = layoutOptions.isOriginTop ? y : -y; 1741 1742 if ( is3d ) { 1743 return 'translate3d(' + x + 'px, ' + y + 'px, 0)'; 1744 } 1745 1746 return 'translate(' + x + 'px, ' + y + 'px)'; 1747}; 1748 1749// non transition + transform support 1750Item.prototype.goTo = function( x, y ) { 1751 this.setPosition( x, y ); 1752 this.layoutPosition(); 1753}; 1754 1755// use transition and transforms if supported 1756Item.prototype.moveTo = supportsCSS3 ? 1757 Item.prototype._transitionTo : Item.prototype.goTo; 1758 1759Item.prototype.setPosition = function( x, y ) { 1760 this.position.x = parseInt( x, 10 ); 1761 this.position.y = parseInt( y, 10 ); 1762}; 1763 1764// ----- transition ----- // 1765 1766/** 1767 * @param {Object} style - CSS 1768 * @param {Function} onTransitionEnd 1769 */ 1770 1771// non transition, just trigger callback 1772Item.prototype._nonTransition = function( args ) { 1773 this.css( args.to ); 1774 if ( args.isCleaning ) { 1775 this._removeStyles( args.to ); 1776 } 1777 for ( var prop in args.onTransitionEnd ) { 1778 args.onTransitionEnd[ prop ].call( this ); 1779 } 1780}; 1781 1782/** 1783 * proper transition 1784 * @param {Object} args - arguments 1785 * @param {Object} to - style to transition to 1786 * @param {Object} from - style to start transition from 1787 * @param {Boolean} isCleaning - removes transition styles after transition 1788 * @param {Function} onTransitionEnd - callback 1789 */ 1790Item.prototype._transition = function( args ) { 1791 // redirect to nonTransition if no transition duration 1792 if ( !parseFloat( this.layout.options.transitionDuration ) ) { 1793 this._nonTransition( args ); 1794 return; 1795 } 1796 1797 var _transition = this._transn; 1798 // keep track of onTransitionEnd callback by css property 1799 for ( var prop in args.onTransitionEnd ) { 1800 _transition.onEnd[ prop ] = args.onTransitionEnd[ prop ]; 1801 } 1802 // keep track of properties that are transitioning 1803 for ( prop in args.to ) { 1804 _transition.ingProperties[ prop ] = true; 1805 // keep track of properties to clean up when transition is done 1806 if ( args.isCleaning ) { 1807 _transition.clean[ prop ] = true; 1808 } 1809 } 1810 1811 // set from styles 1812 if ( args.from ) { 1813 this.css( args.from ); 1814 // force redraw. http://blog.alexmaccaw.com/css-transitions 1815 var h = this.element.offsetHeight; 1816 // hack for JSHint to hush about unused var 1817 h = null; 1818 } 1819 // enable transition 1820 this.enableTransition( args.to ); 1821 // set styles that are transitioning 1822 this.css( args.to ); 1823 1824 this.isTransitioning = true; 1825 1826}; 1827 1828// dash before all cap letters, including first for 1829// WebkitTransform => -webkit-transform 1830function toDashedAll( str ) { 1831 return str.replace( /([A-Z])/g, function( $1 ) { 1832 return '-' + $1.toLowerCase(); 1833 }); 1834} 1835 1836var transitionProps = 'opacity,' +
vendor: 11,190 bytes, lines 1837-2283
1837 toDashedAll( vendorProperties.transform || 'transform' ); 1838 1839Item.prototype.enableTransition = function(/* style */) { 1840 // HACK changing transitionProperty during a transition 1841 // will cause transition to jump 1842 if ( this.isTransitioning ) { 1843 return; 1844 } 1845 1846 // make `transition: foo, bar, baz` from style object 1847 // HACK un-comment this when enableTransition can work 1848 // while a transition is happening 1849 // var transitionValues = []; 1850 // for ( var prop in style ) { 1851 // // dash-ify camelCased properties like WebkitTransition 1852 // prop = vendorProperties[ prop ] || prop; 1853 // transitionValues.push( toDashedAll( prop ) ); 1854 // } 1855 // enable transition styles 1856 this.css({ 1857 transitionProperty: transitionProps, 1858 transitionDuration: this.layout.options.transitionDuration 1859 }); 1860 // listen for transition end event 1861 this.element.addEventListener( transitionEndEvent, this, false ); 1862}; 1863 1864Item.prototype.transition = Item.prototype[ transitionProperty ? '_transition' : '_nonTransition' ]; 1865 1866// ----- events ----- // 1867 1868Item.prototype.onwebkitTransitionEnd = function( event ) { 1869 this.ontransitionend( event ); 1870}; 1871 1872Item.prototype.onotransitionend = function( event ) { 1873 this.ontransitionend( event ); 1874}; 1875 1876// properties that I munge to make my life easier 1877var dashedVendorProperties = { 1878 '-webkit-transform': 'transform', 1879 '-moz-transform': 'transform', 1880 '-o-transform': 'transform' 1881}; 1882 1883Item.prototype.ontransitionend = function( event ) { 1884 // disregard bubbled events from children 1885 if ( event.target !== this.element ) { 1886 return; 1887 } 1888 var _transition = this._transn; 1889 // get property name of transitioned property, convert to prefix-free 1890 var propertyName = dashedVendorProperties[ event.propertyName ] || event.propertyName; 1891 1892 // remove property that has completed transitioning 1893 delete _transition.ingProperties[ propertyName ]; 1894 // check if any properties are still transitioning 1895 if ( isEmptyObj( _transition.ingProperties ) ) { 1896 // all properties have completed transitioning 1897 this.disableTransition(); 1898 } 1899 // clean style 1900 if ( propertyName in _transition.clean ) { 1901 // clean up style 1902 this.element.style[ event.propertyName ] = ''; 1903 delete _transition.clean[ propertyName ]; 1904 } 1905 // trigger onTransitionEnd callback 1906 if ( propertyName in _transition.onEnd ) { 1907 var onTransitionEnd = _transition.onEnd[ propertyName ]; 1908 onTransitionEnd.call( this ); 1909 delete _transition.onEnd[ propertyName ]; 1910 } 1911 1912 this.emitEvent( 'transitionEnd', [ this ] ); 1913}; 1914 1915Item.prototype.disableTransition = function() { 1916 this.removeTransitionStyles(); 1917 this.element.removeEventListener( transitionEndEvent, this, false ); 1918 this.isTransitioning = false; 1919}; 1920 1921/** 1922 * removes style property from element 1923 * @param {Object} style 1924**/ 1925Item.prototype._removeStyles = function( style ) { 1926 // clean up transition styles 1927 var cleanStyle = {}; 1928 for ( var prop in style ) { 1929 cleanStyle[ prop ] = ''; 1930 } 1931 this.css( cleanStyle ); 1932}; 1933 1934var cleanTransitionStyle = { 1935 transitionProperty: '', 1936 transitionDuration: '' 1937}; 1938 1939Item.prototype.removeTransitionStyles = function() { 1940 // remove transition 1941 this.css( cleanTransitionStyle ); 1942}; 1943 1944// ----- show/hide/remove ----- // 1945 1946// remove element from DOM 1947Item.prototype.removeElem = function() { 1948 this.element.parentNode.removeChild( this.element ); 1949 // remove display: none 1950 this.css({ display: '' }); 1951 this.emitEvent( 'remove', [ this ] ); 1952}; 1953 1954Item.prototype.remove = function() { 1955 // just remove element if no transition support or no transition 1956 if ( !transitionProperty || !parseFloat( this.layout.options.transitionDuration ) ) { 1957 this.removeElem(); 1958 return; 1959 } 1960 1961 // start transition 1962 var _this = this; 1963 this.once( 'transitionEnd', function() { 1964 _this.removeElem(); 1965 }); 1966 this.hide(); 1967}; 1968 1969Item.prototype.reveal = function() { 1970 delete this.isHidden; 1971 // remove display: none 1972 this.css({ display: '' }); 1973 1974 var options = this.layout.options; 1975 1976 var onTransitionEnd = {}; 1977 var transitionEndProperty = this.getHideRevealTransitionEndProperty('visibleStyle'); 1978 onTransitionEnd[ transitionEndProperty ] = this.onRevealTransitionEnd; 1979 1980 this.transition({ 1981 from: options.hiddenStyle, 1982 to: options.visibleStyle, 1983 isCleaning: true, 1984 onTransitionEnd: onTransitionEnd 1985 }); 1986}; 1987 1988Item.prototype.onRevealTransitionEnd = function() { 1989 // check if still visible 1990 // during transition, item may have been hidden 1991 if ( !this.isHidden ) { 1992 this.emitEvent('reveal'); 1993 } 1994}; 1995 1996/** 1997 * get style property use for hide/reveal transition end 1998 * @param {String} styleProperty - hiddenStyle/visibleStyle 1999 * @returns {String} 2000 */ 2001Item.prototype.getHideRevealTransitionEndProperty = function( styleProperty ) { 2002 var optionStyle = this.layout.options[ styleProperty ]; 2003 // use opacity 2004 if ( optionStyle.opacity ) { 2005 return 'opacity'; 2006 } 2007 // get first property 2008 for ( var prop in optionStyle ) { 2009 return prop; 2010 } 2011}; 2012 2013Item.prototype.hide = function() { 2014 // set flag 2015 this.isHidden = true; 2016 // remove display: none 2017 this.css({ display: '' }); 2018 2019 var options = this.layout.options; 2020 2021 var onTransitionEnd = {}; 2022 var transitionEndProperty = this.getHideRevealTransitionEndProperty('hiddenStyle'); 2023 onTransitionEnd[ transitionEndProperty ] = this.onHideTransitionEnd; 2024 2025 this.transition({ 2026 from: options.visibleStyle, 2027 to: options.hiddenStyle, 2028 // keep hidden stuff hidden 2029 isCleaning: true, 2030 onTransitionEnd: onTransitionEnd 2031 }); 2032}; 2033 2034Item.prototype.onHideTransitionEnd = function() { 2035 // check if still hidden 2036 // during transition, item may have been un-hidden 2037 if ( this.isHidden ) { 2038 this.css({ display: 'none' }); 2039 this.emitEvent('hide'); 2040 } 2041}; 2042 2043Item.prototype.destroy = function() { 2044 this.css({ 2045 position: '', 2046 left: '', 2047 right: '', 2048 top: '', 2049 bottom: '', 2050 transition: '', 2051 transform: '' 2052 }); 2053}; 2054 2055return Item; 2056 2057})); 2058 2059/*! 2060 * Outlayer v1.4.2 2061 * the brains and guts of a layout library 2062 * MIT license 2063 */ 2064 2065( function( window, factory ) { 2066 'use strict'; 2067 // universal module definition 2068 2069 if ( typeof define == 'function' && define.amd ) { 2070 // AMD 2071 define( 'outlayer/outlayer',[ 2072 'eventie/eventie', 2073 'eventEmitter/EventEmitter', 2074 'get-size/get-size', 2075 'fizzy-ui-utils/utils', 2076 './item' 2077 ], 2078 function( eventie, EventEmitter, getSize, utils, Item ) { 2079 return factory( window, eventie, EventEmitter, getSize, utils, Item); 2080 } 2081 ); 2082 } else if ( typeof exports == 'object' ) { 2083 // CommonJS 2084 module.exports = factory( 2085 window, 2086 require('eventie'), 2087 require('wolfy87-eventemitter'), 2088 require('get-size'), 2089 require('fizzy-ui-utils'), 2090 require('./item') 2091 ); 2092 } else { 2093 // browser global 2094 window.Outlayer = factory( 2095 window, 2096 window.eventie, 2097 window.EventEmitter, 2098 window.getSize, 2099 window.fizzyUIUtils, 2100 window.Outlayer.Item 2101 ); 2102 } 2103 2104}( window, function factory( window, eventie, EventEmitter, getSize, utils, Item ) { 2105'use strict'; 2106 2107// ----- vars ----- // 2108 2109var console = window.console; 2110var jQuery = window.jQuery; 2111var noop = function() {}; 2112 2113// -------------------------- Outlayer -------------------------- // 2114 2115// globally unique identifiers 2116var GUID = 0; 2117// internal store of all Outlayer intances 2118var instances = {}; 2119 2120 2121/** 2122 * @param {Element, String} element 2123 * @param {Object} options 2124 * @constructor 2125 */ 2126function Outlayer( element, options ) { 2127 var queryElement = utils.getQueryElement( element ); 2128 if ( !queryElement ) { 2129 if ( console ) { 2130 console.error( 'Bad element for ' + this.constructor.namespace + 2131 ': ' + ( queryElement || element ) ); 2132 } 2133 return; 2134 } 2135 this.element = queryElement; 2136 // add jQuery 2137 if ( jQuery ) { 2138 this.$element = jQuery( this.element ); 2139 } 2140 2141 // options 2142 this.options = utils.extend( {}, this.constructor.defaults ); 2143 this.option( options ); 2144 2145 // add id for Outlayer.getFromElement 2146 var id = ++GUID; 2147 this.element.outlayerGUID = id; // expando 2148 instances[ id ] = this; // associate via id 2149 2150 // kick it off 2151 this._create(); 2152 2153 if ( this.options.isInitLayout ) { 2154 this.layout(); 2155 } 2156} 2157 2158// settings are for internal use only 2159Outlayer.namespace = 'outlayer'; 2160Outlayer.Item = Item; 2161 2162// default options 2163Outlayer.defaults = { 2164 containerStyle: { 2165 position: 'relative' 2166 }, 2167 isInitLayout: true, 2168 isOriginLeft: true, 2169 isOriginTop: true, 2170 isResizeBound: true, 2171 isResizingContainer: true, 2172 // item options 2173 transitionDuration: '0.4s', 2174 hiddenStyle: { 2175 opacity: 0, 2176 transform: 'scale(0.001)' 2177 }, 2178 visibleStyle: { 2179 opacity: 1, 2180 transform: 'scale(1)' 2181 } 2182}; 2183 2184// inherit EventEmitter 2185utils.extend( Outlayer.prototype, EventEmitter.prototype ); 2186 2187/** 2188 * set options 2189 * @param {Object} opts 2190 */ 2191Outlayer.prototype.option = function( opts ) { 2192 utils.extend( this.options, opts ); 2193}; 2194 2195Outlayer.prototype._create = function() { 2196 // get items from children 2197 this.reloadItems(); 2198 // elements that affect layout, but are not laid out 2199 this.stamps = []; 2200 this.stamp( this.options.stamp ); 2201 // set container style 2202 utils.extend( this.element.style, this.options.containerStyle ); 2203 2204 // bind resize method 2205 if ( this.options.isResizeBound ) { 2206 this.bindResize(); 2207 } 2208}; 2209 2210// goes through all children again and gets bricks in proper order 2211Outlayer.prototype.reloadItems = function() { 2212 // collection of item elements 2213 this.items = this._itemize( this.element.children ); 2214}; 2215 2216 2217/** 2218 * turn elements into Outlayer.Items to be used in layout 2219 * @param {Array or NodeList or HTMLElement} elems 2220 * @returns {Array} items - collection of new Outlayer Items 2221 */ 2222Outlayer.prototype._itemize = function( elems ) { 2223 2224 var itemElems = this._filterFindItemElements( elems ); 2225 var Item = this.constructor.Item; 2226 2227 // create new Outlayer Items for collection 2228 var items = []; 2229 for ( var i=0, len = itemElems.length; i < len; i++ ) { 2230 var elem = itemElems[i]; 2231 var item = new Item( elem, this ); 2232 items.push( item ); 2233 } 2234 2235 return items; 2236}; 2237 2238/** 2239 * get item elements to be used in layout 2240 * @param {Array or NodeList or HTMLElement} elems 2241 * @returns {Array} items - item elements 2242 */ 2243Outlayer.prototype._filterFindItemElements = function( elems ) { 2244 return utils.filterFindElements( elems, this.options.itemSelector ); 2245}; 2246 2247/** 2248 * getter method for getting item elements 2249 * @returns {Array} elems - collection of item elements 2250 */ 2251Outlayer.prototype.getItemElements = function() { 2252 var elems = []; 2253 for ( var i=0, len = this.items.length; i < len; i++ ) { 2254 elems.push( this.items[i].element ); 2255 } 2256 return elems; 2257}; 2258 2259// ----- init & layout ----- // 2260 2261/** 2262 * lays out all items 2263 */ 2264Outlayer.prototype.layout = function() { 2265 this._resetLayout(); 2266 this._manageStamps(); 2267 2268 // don't animate first layout 2269 var isInstant = this.options.isLayoutInstant !== undefined ? 2270 this.options.isLayoutInstant : !this._isLayoutInited; 2271 this.layoutItems( this.items, isInstant ); 2272 2273 // flag for initalized 2274 this._isLayoutInited = true; 2275}; 2276 2277// _init is alias for layout 2278Outlayer.prototype._init = Outlayer.prototype.layout; 2279 2280/** 2281 * logic before any new layout 2282 */ 2283Outlayer.prototype._resetLayout = function() {
vendor: 6,719 bytes, lines 2284-2560
2284 this.getSize(); 2285}; 2286 2287 2288Outlayer.prototype.getSize = function() { 2289 this.size = getSize( this.element ); 2290}; 2291 2292/** 2293 * get measurement from option, for columnWidth, rowHeight, gutter 2294 * if option is String -> get element from selector string, & get size of element 2295 * if option is Element -> get size of element 2296 * else use option as a number 2297 * 2298 * @param {String} measurement 2299 * @param {String} size - width or height 2300 * @private 2301 */ 2302Outlayer.prototype._getMeasurement = function( measurement, size ) { 2303 var option = this.options[ measurement ]; 2304 var elem; 2305 if ( !option ) { 2306 // default to 0 2307 this[ measurement ] = 0; 2308 } else { 2309 // use option as an element 2310 if ( typeof option === 'string' ) { 2311 elem = this.element.querySelector( option ); 2312 } else if ( utils.isElement( option ) ) { 2313 elem = option; 2314 } 2315 // use size of element, if element 2316 this[ measurement ] = elem ? getSize( elem )[ size ] : option; 2317 } 2318}; 2319 2320/** 2321 * layout a collection of item elements 2322 * @api public 2323 */ 2324Outlayer.prototype.layoutItems = function( items, isInstant ) { 2325 items = this._getItemsForLayout( items ); 2326 2327 this._layoutItems( items, isInstant ); 2328 2329 this._postLayout(); 2330}; 2331 2332/** 2333 * get the items to be laid out 2334 * you may want to skip over some items 2335 * @param {Array} items 2336 * @returns {Array} items 2337 */ 2338Outlayer.prototype._getItemsForLayout = function( items ) { 2339 var layoutItems = []; 2340 for ( var i=0, len = items.length; i < len; i++ ) { 2341 var item = items[i]; 2342 if ( !item.isIgnored ) { 2343 layoutItems.push( item ); 2344 } 2345 } 2346 return layoutItems; 2347}; 2348 2349/** 2350 * layout items 2351 * @param {Array} items 2352 * @param {Boolean} isInstant 2353 */ 2354Outlayer.prototype._layoutItems = function( items, isInstant ) { 2355 this._emitCompleteOnItems( 'layout', items ); 2356 2357 if ( !items || !items.length ) { 2358 // no items, emit event with empty array 2359 return; 2360 } 2361 2362 var queue = []; 2363 2364 for ( var i=0, len = items.length; i < len; i++ ) { 2365 var item = items[i]; 2366 // get x/y object from method 2367 var position = this._getItemLayoutPosition( item ); 2368 // enqueue 2369 position.item = item; 2370 position.isInstant = isInstant || item.isLayoutInstant; 2371 queue.push( position ); 2372 } 2373 2374 this._processLayoutQueue( queue ); 2375}; 2376 2377/** 2378 * get item layout position 2379 * @param {Outlayer.Item} item 2380 * @returns {Object} x and y position 2381 */ 2382Outlayer.prototype._getItemLayoutPosition = function( /* item */ ) { 2383 return { 2384 x: 0, 2385 y: 0 2386 }; 2387}; 2388 2389/** 2390 * iterate over array and position each item 2391 * Reason being - separating this logic prevents 'layout invalidation' 2392 * thx @paul_irish 2393 * @param {Array} queue 2394 */ 2395Outlayer.prototype._processLayoutQueue = function( queue ) { 2396 for ( var i=0, len = queue.length; i < len; i++ ) { 2397 var obj = queue[i]; 2398 this._positionItem( obj.item, obj.x, obj.y, obj.isInstant ); 2399 } 2400}; 2401 2402/** 2403 * Sets position of item in DOM 2404 * @param {Outlayer.Item} item 2405 * @param {Number} x - horizontal position 2406 * @param {Number} y - vertical position 2407 * @param {Boolean} isInstant - disables transitions 2408 */ 2409Outlayer.prototype._positionItem = function( item, x, y, isInstant ) { 2410 if ( isInstant ) { 2411 // if not transition, just set CSS 2412 item.goTo( x, y ); 2413 } else { 2414 item.moveTo( x, y ); 2415 } 2416}; 2417 2418/** 2419 * Any logic you want to do after each layout, 2420 * i.e. size the container 2421 */ 2422Outlayer.prototype._postLayout = function() { 2423 this.resizeContainer(); 2424}; 2425 2426Outlayer.prototype.resizeContainer = function() { 2427 if ( !this.options.isResizingContainer ) { 2428 return; 2429 } 2430 var size = this._getContainerSize(); 2431 if ( size ) { 2432 this._setContainerMeasure( size.width, true ); 2433 this._setContainerMeasure( size.height, false ); 2434 } 2435}; 2436 2437/** 2438 * Sets width or height of container if returned 2439 * @returns {Object} size 2440 * @param {Number} width 2441 * @param {Number} height 2442 */ 2443Outlayer.prototype._getContainerSize = noop; 2444 2445/** 2446 * @param {Number} measure - size of width or height 2447 * @param {Boolean} isWidth 2448 */ 2449Outlayer.prototype._setContainerMeasure = function( measure, isWidth ) { 2450 if ( measure === undefined ) { 2451 return; 2452 } 2453 2454 var elemSize = this.size; 2455 // add padding and border width if border box 2456 if ( elemSize.isBorderBox ) { 2457 measure += isWidth ? elemSize.paddingLeft + elemSize.paddingRight + 2458 elemSize.borderLeftWidth + elemSize.borderRightWidth : 2459 elemSize.paddingBottom + elemSize.paddingTop + 2460 elemSize.borderTopWidth + elemSize.borderBottomWidth; 2461 } 2462 2463 measure = Math.max( measure, 0 ); 2464 this.element.style[ isWidth ? 'width' : 'height' ] = measure + 'px'; 2465}; 2466 2467/** 2468 * emit eventComplete on a collection of items events 2469 * @param {String} eventName 2470 * @param {Array} items - Outlayer.Items 2471 */ 2472Outlayer.prototype._emitCompleteOnItems = function( eventName, items ) { 2473 var _this = this; 2474 function onComplete() { 2475 _this.dispatchEvent( eventName + 'Complete', null, [ items ] ); 2476 } 2477 2478 var count = items.length; 2479 if ( !items || !count ) { 2480 onComplete(); 2481 return; 2482 } 2483 2484 var doneCount = 0; 2485 function tick() { 2486 doneCount++; 2487 if ( doneCount === count ) { 2488 onComplete(); 2489 } 2490 } 2491 2492 // bind callback 2493 for ( var i=0, len = items.length; i < len; i++ ) { 2494 var item = items[i]; 2495 item.once( eventName, tick ); 2496 } 2497}; 2498 2499/** 2500 * emits events via eventEmitter and jQuery events 2501 * @param {String} type - name of event 2502 * @param {Event} event - original event 2503 * @param {Array} args - extra arguments 2504 */ 2505Outlayer.prototype.dispatchEvent = function( type, event, args ) { 2506 // add original event to arguments 2507 var emitArgs = event ? [ event ].concat( args ) : args; 2508 this.emitEvent( type, emitArgs ); 2509 2510 if ( jQuery ) { 2511 // set this.$element 2512 this.$element = this.$element || jQuery( this.element ); 2513 if ( event ) { 2514 // create jQuery event 2515 var $event = jQuery.Event( event ); 2516 $event.type = type; 2517 this.$element.trigger( $event, args ); 2518 } else { 2519 // just trigger with type if no event available 2520 this.$element.trigger( type, args ); 2521 } 2522 } 2523}; 2524 2525// -------------------------- ignore & stamps -------------------------- // 2526 2527 2528/** 2529 * keep item in collection, but do not lay it out 2530 * ignored items do not get skipped in layout 2531 * @param {Element} elem 2532 */ 2533Outlayer.prototype.ignore = function( elem ) { 2534 var item = this.getItem( elem ); 2535 if ( item ) { 2536 item.isIgnored = true; 2537 } 2538}; 2539 2540/** 2541 * return item to layout collection 2542 * @param {Element} elem 2543 */ 2544Outlayer.prototype.unignore = function( elem ) { 2545 var item = this.getItem( elem ); 2546 if ( item ) { 2547 delete item.isIgnored; 2548 } 2549}; 2550 2551/** 2552 * adds elements to stamps 2553 * @param {NodeList, Array, Element, or String} elems 2554 */ 2555Outlayer.prototype.stamp = function( elems ) { 2556 elems = this._find( elems ); 2557 if ( !elems ) { 2558 return; 2559 } 2560
2561 this.stamps = this.stamps.concat( elems ); 2562 // ignore 2563 for ( var i=0, len = elems.length; i < len; i++ ) { 2564 var elem = elems[i]; 2565 this.ignore( elem ); 2566 } 2567}; 2568 2569/** 2570 * removes elements to stamps 2571 * @param {NodeList, Array, or Element} elems 2572 */ 2573Outlayer.prototype.unstamp = function( elems ) { 2574 elems = this._find( elems ); 2575 if ( !elems ){ 2576 return; 2577 } 2578 2579 for ( var i=0, len = elems.length; i < len; i++ ) { 2580 var elem = elems[i]; 2581 // filter out removed stamp elements 2582 utils.removeFrom( this.stamps, elem ); 2583 this.unignore( elem ); 2584 } 2585 2586}; 2587 2588/** 2589 * finds child elements 2590 * @param {NodeList, Array, Element, or String} elems 2591 * @returns {Array} elems 2592 */ 2593Outlayer.prototype._find = function( elems ) { 2594 if ( !elems ) { 2595 return; 2596 } 2597 // if string, use argument as selector string 2598 if ( typeof elems === 'string' ) { 2599 elems = this.element.querySelectorAll( elems ); 2600 } 2601 elems = utils.makeArray( elems ); 2602 return elems; 2603}; 2604 2605Outlayer.prototype._manageStamps = function() { 2606 if ( !this.stamps || !this.stamps.length ) { 2607 return; 2608 } 2609 2610 this._getBoundingRect(); 2611 2612 for ( var i=0, len = this.stamps.length; i < len; i++ ) { 2613 var stamp = this.stamps[i]; 2614 this._manageStamp( stamp ); 2615 } 2616}; 2617 2618// update boundingLeft / Top 2619Outlayer.prototype._getBoundingRect = function() { 2620 // get bounding rect for container element 2621 var boundingRect = this.element.getBoundingClientRect(); 2622 var size = this.size; 2623 this._boundingRect = { 2624 left: boundingRect.left + size.paddingLeft + size.borderLeftWidth, 2625 top: boundingRect.top + size.paddingTop + size.borderTopWidth, 2626 right: boundingRect.right - ( size.paddingRight + size.borderRightWidth ), 2627 bottom: boundingRect.bottom - ( size.paddingBottom + size.borderBottomWidth ) 2628 }; 2629}; 2630 2631/** 2632 * @param {Element} stamp 2633**/ 2634Outlayer.prototype._manageStamp = noop; 2635 2636/** 2637 * get x/y position of element relative to container element 2638 * @param {Element} elem 2639 * @returns {Object} offset - has left, top, right, bottom 2640 */ 2641Outlayer.prototype._getElementOffset = function( elem ) { 2642 var boundingRect = elem.getBoundingClientRect(); 2643 var thisRect = this._boundingRect; 2644 var size = getSize( elem ); 2645 var offset = { 2646 left: boundingRect.left - thisRect.left - size.marginLeft, 2647 top: boundingRect.top - thisRect.top - size.marginTop, 2648 right: thisRect.right - boundingRect.right - size.marginRight, 2649 bottom: thisRect.bottom - boundingRect.bottom - size.marginBottom 2650 }; 2651 return offset; 2652}; 2653 2654// -------------------------- resize -------------------------- // 2655 2656// enable event handlers for listeners 2657// i.e. resize -> onresize 2658Outlayer.prototype.handleEvent = function( event ) { 2659 var method = 'on' + event.type; 2660 if ( this[ method ] ) { 2661 this[ method ]( event ); 2662 } 2663}; 2664 2665/** 2666 * Bind layout to window resizing 2667 */ 2668Outlayer.prototype.bindResize = function() { 2669 // bind just one listener 2670 if ( this.isResizeBound ) { 2671 return; 2672 } 2673 eventie.bind( window, 'resize', this ); 2674 this.isResizeBound = true; 2675}; 2676 2677/** 2678 * Unbind layout to window resizing 2679 */ 2680Outlayer.prototype.unbindResize = function() { 2681 if ( this.isResizeBound ) { 2682 eventie.unbind( window, 'resize', this ); 2683 } 2684 this.isResizeBound = false; 2685}; 2686 2687// original debounce by John Hann 2688// http://unscriptable.com/index.php/2009/03/20/debouncing-javascript-methods/ 2689 2690// this fires every resize 2691Outlayer.prototype.onresize = function() { 2692 if ( this.resizeTimeout ) { 2693 clearTimeout( this.resizeTimeout ); 2694 } 2695 2696 var _this = this; 2697 function delayed() { 2698 _this.resize(); 2699 delete _this.resizeTimeout; 2700 } 2701 2702 this.resizeTimeout = setTimeout( delayed, 100 ); 2703}; 2704 2705// debounced, layout on resize 2706Outlayer.prototype.resize = function() { 2707 // don't trigger if size did not change 2708 // or if resize was unbound. See #9 2709 if ( !this.isResizeBound || !this.needsResizeLayout() ) { 2710 return; 2711 } 2712 2713 this.layout(); 2714}; 2715 2716/** 2717 * check if layout is needed post layout 2718 * @returns Boolean 2719 */ 2720Outlayer.prototype.needsResizeLayout = function() { 2721 var size = getSize( this.element ); 2722 // check that this.size and size are there 2723 // IE8 triggers resize on body size change, so they might not be 2724 var hasSizes = this.size && size; 2725 return hasSizes && size.innerWidth !== this.size.innerWidth; 2726}; 2727 2728// -------------------------- methods -------------------------- // 2729 2730/** 2731 * add items to Outlayer instance 2732 * @param {Array or NodeList or Element} elems 2733 * @returns {Array} items - Outlayer.Items 2734**/ 2735Outlayer.prototype.addItems = function( elems ) { 2736 var items = this._itemize( elems ); 2737 // add items to collection 2738 if ( items.length ) { 2739 this.items = this.items.concat( items ); 2740 } 2741 return items; 2742}; 2743 2744/** 2745 * Layout newly-appended item elements 2746 * @param {Array or NodeList or Element} elems 2747 */ 2748Outlayer.prototype.appended = function( elems ) { 2749 var items = this.addItems( elems ); 2750 if ( !items.length ) { 2751 return; 2752 } 2753 // layout and reveal just the new items 2754 this.layoutItems( items, true ); 2755 this.reveal( items ); 2756}; 2757 2758/** 2759 * Layout prepended elements 2760 * @param {Array or NodeList or Element} elems 2761 */ 2762Outlayer.prototype.prepended = function( elems ) { 2763 var items = this._itemize( elems ); 2764 if ( !items.length ) { 2765 return; 2766 } 2767 // add items to beginning of collection 2768 var previousItems = this.items.slice(0); 2769 this.items = items.concat( previousItems ); 2770 // start new layout 2771 this._resetLayout(); 2772 this._manageStamps(); 2773 // layout new stuff without transition 2774 this.layoutItems( items, true ); 2775 this.reveal( items ); 2776 // layout previous items 2777 this.layoutItems( previousItems ); 2778}; 2779 2780/** 2781 * reveal a collection of items 2782 * @param {Array of Outlayer.Items} items 2783 */ 2784Outlayer.prototype.reveal = function( items ) { 2785 this._emitCompleteOnItems( 'reveal', items ); 2786 2787 var len = items && items.length; 2788 for ( var i=0; len && i < len; i++ ) { 2789 var item = items[i]; 2790 item.reveal(); 2791 } 2792}; 2793 2794/** 2795 * hide a collection of items 2796 * @param {Array of Outlayer.Items} items 2797 */ 2798Outlayer.prototype.hide = function( items ) { 2799 this._emitCompleteOnItems( 'hide', items ); 2800 2801 var len = items && items.length; 2802 for ( var i=0; len && i < len; i++ ) { 2803 var item = items[i]; 2804 item.hide(); 2805 } 2806}; 2807 2808/** 2809 * reveal item elements 2810 * @param {Array}, {Element}, {NodeList} items 2811 */ 2812Outlayer.prototype.revealItemElements = function( elems ) { 2813 var items = this.getItems( elems ); 2814 this.reveal( items ); 2815}; 2816 2817/** 2818 * hide item elements 2819 * @param {Array}, {Element}, {NodeList} items 2820 */ 2821Outlayer.prototype.hideItemElements = function( elems ) { 2822 var items = this.getItems( elems ); 2823 this.hide( items ); 2824}; 2825 2826/** 2827 * get Outlayer.Item, given an Element 2828 * @param {Element} elem 2829 * @param {Function} callback 2830 * @returns {Outlayer.Item} item 2831 */ 2832Outlayer.prototype.getItem = function( elem ) { 2833 // loop through items to get the one that matches 2834 for ( var i=0, len = this.items.length; i < len; i++ ) { 2835 var item = this.items[i]; 2836 if ( item.element === elem ) { 2837 // return item 2838 return item; 2839 } 2840 } 2841}; 2842 2843/** 2844 * get collection of Outlayer.Items, given Elements 2845 * @param {Array} elems 2846 * @returns {Array} items - Outlayer.Items 2847 */ 2848Outlayer.prototype.getItems = function( elems ) { 2849 elems = utils.makeArray( elems ); 2850 var items = []; 2851 for ( var i=0, len = elems.length; i < len; i++ ) { 2852 var elem = elems[i]; 2853 var item = this.getItem( elem ); 2854 if ( item ) { 2855 items.push( item ); 2856 } 2857 } 2858 2859 return items; 2860}; 2861 2862/**
2863 * remove element(s) from instance and DOM 2864 * @param {Array or NodeList or Element} elems 2865 */ 2866Outlayer.prototype.remove = function( elems ) { 2867 var removeItems = this.getItems( elems ); 2868 2869 this._emitCompleteOnItems( 'remove', removeItems ); 2870 2871 // bail if no items to remove 2872 if ( !removeItems || !removeItems.length ) { 2873 return; 2874 } 2875 2876 for ( var i=0, len = removeItems.length; i < len; i++ ) { 2877 var item = removeItems[i]; 2878 item.remove(); 2879 // remove item from collection 2880 utils.removeFrom( this.items, item ); 2881 } 2882}; 2883 2884// ----- destroy ----- // 2885 2886// remove and disable Outlayer instance 2887Outlayer.prototype.destroy = function() { 2888 // clean up dynamic styles 2889 var style = this.element.style; 2890 style.height = ''; 2891 style.position = ''; 2892 style.width = ''; 2893 // destroy items 2894 for ( var i=0, len = this.items.length; i < len; i++ ) { 2895 var item = this.items[i]; 2896 item.destroy(); 2897 } 2898 2899 this.unbindResize(); 2900 2901 var id = this.element.outlayerGUID; 2902 delete instances[ id ]; // remove reference to instance by id 2903 delete this.element.outlayerGUID; 2904 // remove data for jQuery 2905 if ( jQuery ) { 2906 jQuery.removeData( this.element, this.constructor.namespace ); 2907 } 2908 2909}; 2910 2911// -------------------------- data -------------------------- // 2912 2913/** 2914 * get Outlayer instance from element 2915 * @param {Element} elem 2916 * @returns {Outlayer} 2917 */ 2918Outlayer.data = function( elem ) { 2919 elem = utils.getQueryElement( elem ); 2920 var id = elem && elem.outlayerGUID; 2921 return id && instances[ id ]; 2922}; 2923 2924 2925// -------------------------- create Outlayer class -------------------------- // 2926 2927/** 2928 * create a layout class 2929 * @param {String} namespace 2930 */ 2931Outlayer.create = function( namespace, options ) { 2932 // sub-class Outlayer 2933 function Layout() { 2934 Outlayer.apply( this, arguments ); 2935 } 2936 // inherit Outlayer prototype, use Object.create if there 2937 if ( Object.create ) { 2938 Layout.prototype = Object.create( Outlayer.prototype ); 2939 } else { 2940 utils.extend( Layout.prototype, Outlayer.prototype ); 2941 } 2942 // set contructor, used for namespace and Item 2943 Layout.prototype.constructor = Layout; 2944 2945 Layout.defaults = utils.extend( {}, Outlayer.defaults ); 2946 // apply new options 2947 utils.extend( Layout.defaults, options ); 2948 // keep prototype.settings for backwards compatibility (Packery v1.2.0) 2949 Layout.prototype.settings = {}; 2950 2951 Layout.namespace = namespace; 2952 2953 Layout.data = Outlayer.data; 2954 2955 // sub-class Item 2956 Layout.Item = function LayoutItem() { 2957 Item.apply( this, arguments ); 2958 }; 2959 2960 Layout.Item.prototype = new Item(); 2961 2962 // -------------------------- declarative -------------------------- // 2963 2964 utils.htmlInit( Layout, namespace ); 2965 2966 // -------------------------- jQuery bridge -------------------------- // 2967 2968 // make into jQuery plugin 2969 if ( jQuery && jQuery.bridget ) { 2970 jQuery.bridget( namespace, Layout ); 2971 } 2972 2973 return Layout; 2974}; 2975 2976// ----- fin ----- // 2977 2978// back in global 2979Outlayer.Item = Item; 2980 2981return Outlayer; 2982 2983})); 2984 2985 2986/** 2987 * Isotope Item 2988**/ 2989 2990( function( window, factory ) { 2991'use strict'; 2992 // universal module definition 2993 if ( typeof define == 'function' && define.amd ) { 2994 // AMD 2995 define( 'isotope/js/item',[ 2996 'outlayer/outlayer' 2997 ], 2998 factory ); 2999 } else if ( typeof exports == 'object' ) { 3000 // CommonJS 3001 module.exports = factory( 3002 require('outlayer') 3003 ); 3004 } else { 3005 // browser global 3006 window.Isotope = window.Isotope || {}; 3007 window.Isotope.Item = factory( 3008 window.Outlayer 3009 ); 3010 } 3011 3012}( window, function factory( Outlayer ) { 3013'use strict'; 3014 3015// -------------------------- Item -------------------------- // 3016 3017// sub-class Outlayer Item 3018function Item() { 3019 Outlayer.Item.apply( this, arguments ); 3020} 3021 3022Item.prototype = new Outlayer.Item(); 3023 3024Item.prototype._create = function() { 3025 // assign id, used for original-order sorting 3026 this.id = this.layout.itemGUID++; 3027 Outlayer.Item.prototype._create.call( this ); 3028 this.sortData = {}; 3029}; 3030 3031Item.prototype.updateSortData = function() { 3032 if ( this.isIgnored ) { 3033 return; 3034 } 3035 // default sorters 3036 this.sortData.id = this.id; 3037 // for backward compatibility 3038 this.sortData['original-order'] = this.id; 3039 this.sortData.random = Math.random(); 3040 // go thru getSortData obj and apply the sorters 3041 var getSortData = this.layout.options.getSortData; 3042 var sorters = this.layout._sorters; 3043 for ( var key in getSortData ) { 3044 var sorter = sorters[ key ]; 3045 this.sortData[ key ] = sorter( this.element, this ); 3046 } 3047}; 3048 3049var _destroy = Item.prototype.destroy; 3050Item.prototype.destroy = function() { 3051 // call super 3052 _destroy.apply( this, arguments ); 3053 // reset display, #741 3054 this.css({ 3055 display: '' 3056 }); 3057}; 3058 3059return Item; 3060 3061})); 3062 3063/** 3064 * Isotope LayoutMode 3065 */ 3066 3067( function( window, factory ) { 3068 'use strict'; 3069 // universal module definition 3070 3071 if ( typeof define == 'function' && define.amd ) { 3072 // AMD 3073 define( 'isotope/js/layout-mode',[ 3074 'get-size/get-size', 3075 'outlayer/outlayer' 3076 ], 3077 factory ); 3078 } else if ( typeof exports == 'object' ) { 3079 // CommonJS 3080 module.exports = factory( 3081 require('get-size'), 3082 require('outlayer') 3083 ); 3084 } else { 3085 // browser global 3086 window.Isotope = window.Isotope || {}; 3087 window.Isotope.LayoutMode = factory( 3088 window.getSize, 3089 window.Outlayer 3090 ); 3091 } 3092 3093}( window, function factory( getSize, Outlayer ) { 3094 'use strict'; 3095 3096 // layout mode class 3097 function LayoutMode( isotope ) { 3098 this.isotope = isotope; 3099 // link properties 3100 if ( isotope ) { 3101 this.options = isotope.options[ this.namespace ]; 3102 this.element = isotope.element; 3103 this.items = isotope.filteredItems; 3104 this.size = isotope.size; 3105 } 3106 } 3107 3108 /** 3109 * some methods should just defer to default Outlayer method 3110 * and reference the Isotope instance as `this` 3111 **/ 3112 ( function() { 3113 var facadeMethods = [ 3114 '_resetLayout', 3115 '_getItemLayoutPosition', 3116 '_manageStamp', 3117 '_getContainerSize', 3118 '_getElementOffset', 3119 'needsResizeLayout' 3120 ]; 3121 3122 for ( var i=0, len = facadeMethods.length; i < len; i++ ) { 3123 var methodName = facadeMethods[i]; 3124 LayoutMode.prototype[ methodName ] = getOutlayerMethod( methodName ); 3125 } 3126 3127 function getOutlayerMethod( methodName ) { 3128 return function() { 3129 return Outlayer.prototype[ methodName ].apply( this.isotope, arguments ); 3130 }; 3131 } 3132 })(); 3133 3134 // ----- ----- // 3135 3136 // for horizontal layout modes, check vertical size 3137 LayoutMode.prototype.needsVerticalResizeLayout = function() {
vendor: 20,029 bytes, lines 3138-3873
3138 // don't trigger if size did not change 3139 var size = getSize( this.isotope.element ); 3140 // check that this.size and size are there 3141 // IE8 triggers resize on body size change, so they might not be 3142 var hasSizes = this.isotope.size && size; 3143 return hasSizes && size.innerHeight != this.isotope.size.innerHeight; 3144 }; 3145 3146 // ----- measurements ----- // 3147 3148 LayoutMode.prototype._getMeasurement = function() { 3149 this.isotope._getMeasurement.apply( this, arguments ); 3150 }; 3151 3152 LayoutMode.prototype.getColumnWidth = function() { 3153 this.getSegmentSize( 'column', 'Width' ); 3154 }; 3155 3156 LayoutMode.prototype.getRowHeight = function() { 3157 this.getSegmentSize( 'row', 'Height' ); 3158 }; 3159 3160 /** 3161 * get columnWidth or rowHeight 3162 * segment: 'column' or 'row' 3163 * size 'Width' or 'Height' 3164 **/ 3165 LayoutMode.prototype.getSegmentSize = function( segment, size ) { 3166 var segmentName = segment + size; 3167 var outerSize = 'outer' + size; 3168 // columnWidth / outerWidth // rowHeight / outerHeight 3169 this._getMeasurement( segmentName, outerSize ); 3170 // got rowHeight or columnWidth, we can chill 3171 if ( this[ segmentName ] ) { 3172 return; 3173 } 3174 // fall back to item of first element 3175 var firstItemSize = this.getFirstItemSize(); 3176 this[ segmentName ] = firstItemSize && firstItemSize[ outerSize ] || 3177 // or size of container 3178 this.isotope.size[ 'inner' + size ]; 3179 }; 3180 3181 LayoutMode.prototype.getFirstItemSize = function() { 3182 var firstItem = this.isotope.filteredItems[0]; 3183 return firstItem && firstItem.element && getSize( firstItem.element ); 3184 }; 3185 3186 // ----- methods that should reference isotope ----- // 3187 3188 LayoutMode.prototype.layout = function() { 3189 this.isotope.layout.apply( this.isotope, arguments ); 3190 }; 3191 3192 LayoutMode.prototype.getSize = function() { 3193 this.isotope.getSize(); 3194 this.size = this.isotope.size; 3195 }; 3196 3197 // -------------------------- create -------------------------- // 3198 3199 LayoutMode.modes = {}; 3200 3201 LayoutMode.create = function( namespace, options ) { 3202 3203 function Mode() { 3204 LayoutMode.apply( this, arguments ); 3205 } 3206 3207 Mode.prototype = new LayoutMode(); 3208 3209 // default options 3210 if ( options ) { 3211 Mode.options = options; 3212 } 3213 3214 Mode.prototype.namespace = namespace; 3215 // register in Isotope 3216 LayoutMode.modes[ namespace ] = Mode; 3217 3218 return Mode; 3219 }; 3220 3221 return LayoutMode; 3222 3223})); 3224 3225/*! 3226 * Masonry v3.3.1 3227 * Cascading grid layout library 3228 * http://masonry.desandro.com 3229 * MIT License 3230 * by David DeSandro 3231 */ 3232 3233( function( window, factory ) { 3234 'use strict'; 3235 // universal module definition 3236 if ( typeof define === 'function' && define.amd ) { 3237 // AMD 3238 define( 'masonry/masonry',[ 3239 'outlayer/outlayer', 3240 'get-size/get-size', 3241 'fizzy-ui-utils/utils' 3242 ], 3243 factory ); 3244 } else if ( typeof exports === 'object' ) { 3245 // CommonJS 3246 module.exports = factory( 3247 require('outlayer'), 3248 require('get-size'), 3249 require('fizzy-ui-utils') 3250 ); 3251 } else { 3252 // browser global 3253 window.Masonry = factory( 3254 window.Outlayer, 3255 window.getSize, 3256 window.fizzyUIUtils 3257 ); 3258 } 3259 3260}( window, function factory( Outlayer, getSize, utils ) { 3261 3262 3263 3264// -------------------------- masonryDefinition -------------------------- // 3265 3266 // create an Outlayer layout class 3267 var Masonry = Outlayer.create('masonry'); 3268 3269 Masonry.prototype._resetLayout = function() { 3270 this.getSize(); 3271 this._getMeasurement( 'columnWidth', 'outerWidth' ); 3272 this._getMeasurement( 'gutter', 'outerWidth' ); 3273 this.measureColumns(); 3274 3275 // reset column Y 3276 var i = this.cols; 3277 this.colYs = []; 3278 while (i--) { 3279 this.colYs.push( 0 ); 3280 } 3281 3282 this.maxY = 0; 3283 }; 3284 3285 Masonry.prototype.measureColumns = function() { 3286 this.getContainerWidth(); 3287 // if columnWidth is 0, default to outerWidth of first item 3288 if ( !this.columnWidth ) { 3289 var firstItem = this.items[0]; 3290 var firstItemElem = firstItem && firstItem.element; 3291 // columnWidth fall back to item of first element 3292 this.columnWidth = firstItemElem && getSize( firstItemElem ).outerWidth || 3293 // if first elem has no width, default to size of container 3294 this.containerWidth; 3295 } 3296 3297 var columnWidth = this.columnWidth += this.gutter; 3298 3299 // calculate columns 3300 var containerWidth = this.containerWidth + this.gutter; 3301 var cols = containerWidth / columnWidth; 3302 // fix rounding errors, typically with gutters 3303 var excess = columnWidth - containerWidth % columnWidth; 3304 // if overshoot is less than a pixel, round up, otherwise floor it 3305 var mathMethod = excess && excess < 1 ? 'round' : 'floor'; 3306 cols = Math[ mathMethod ]( cols ); 3307 this.cols = Math.max( cols, 1 ); 3308 }; 3309 3310 Masonry.prototype.getContainerWidth = function() { 3311 // container is parent if fit width 3312 var container = this.options.isFitWidth ? this.element.parentNode : this.element; 3313 // check that this.size and size are there 3314 // IE8 triggers resize on body size change, so they might not be 3315 var size = getSize( container ); 3316 this.containerWidth = size && size.innerWidth; 3317 }; 3318 3319 Masonry.prototype._getItemLayoutPosition = function( item ) { 3320 item.getSize(); 3321 // how many columns does this brick span 3322 var remainder = item.size.outerWidth % this.columnWidth; 3323 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil'; 3324 // round if off by 1 pixel, otherwise use ceil 3325 var colSpan = Math[ mathMethod ]( item.size.outerWidth / this.columnWidth ); 3326 colSpan = Math.min( colSpan, this.cols ); 3327 3328 var colGroup = this._getColGroup( colSpan ); 3329 // get the minimum Y value from the columns 3330 var minimumY = Math.min.apply( Math, colGroup ); 3331 var shortColIndex = utils.indexOf( colGroup, minimumY ); 3332 3333 // position the brick 3334 var position = { 3335 x: this.columnWidth * shortColIndex, 3336 y: minimumY 3337 }; 3338 3339 // apply setHeight to necessary columns 3340 var setHeight = minimumY + item.size.outerHeight; 3341 var setSpan = this.cols + 1 - colGroup.length; 3342 for ( var i = 0; i < setSpan; i++ ) { 3343 this.colYs[ shortColIndex + i ] = setHeight; 3344 } 3345 3346 return position; 3347 }; 3348 3349 /** 3350 * @param {Number} colSpan - number of columns the element spans 3351 * @returns {Array} colGroup 3352 */ 3353 Masonry.prototype._getColGroup = function( colSpan ) { 3354 if ( colSpan < 2 ) { 3355 // if brick spans only one column, use all the column Ys 3356 return this.colYs; 3357 } 3358 3359 var colGroup = []; 3360 // how many different places could this brick fit horizontally 3361 var groupCount = this.cols + 1 - colSpan; 3362 // for each group potential horizontal position 3363 for ( var i = 0; i < groupCount; i++ ) { 3364 // make an array of colY values for that one group 3365 var groupColYs = this.colYs.slice( i, i + colSpan ); 3366 // and get the max value of the array 3367 colGroup[i] = Math.max.apply( Math, groupColYs ); 3368 } 3369 return colGroup; 3370 }; 3371 3372 Masonry.prototype._manageStamp = function( stamp ) { 3373 var stampSize = getSize( stamp ); 3374 var offset = this._getElementOffset( stamp ); 3375 // get the columns that this stamp affects 3376 var firstX = this.options.isOriginLeft ? offset.left : offset.right; 3377 var lastX = firstX + stampSize.outerWidth; 3378 var firstCol = Math.floor( firstX / this.columnWidth ); 3379 firstCol = Math.max( 0, firstCol ); 3380 var lastCol = Math.floor( lastX / this.columnWidth ); 3381 // lastCol should not go over if multiple of columnWidth #425 3382 lastCol -= lastX % this.columnWidth ? 0 : 1; 3383 lastCol = Math.min( this.cols - 1, lastCol ); 3384 // set colYs to bottom of the stamp 3385 var stampMaxY = ( this.options.isOriginTop ? offset.top : offset.bottom ) + 3386 stampSize.outerHeight; 3387 for ( var i = firstCol; i <= lastCol; i++ ) { 3388 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] ); 3389 } 3390 }; 3391 3392 Masonry.prototype._getContainerSize = function() { 3393 this.maxY = Math.max.apply( Math, this.colYs ); 3394 var size = { 3395 height: this.maxY 3396 }; 3397 3398 if ( this.options.isFitWidth ) { 3399 size.width = this._getContainerFitWidth(); 3400 } 3401 3402 return size; 3403 }; 3404 3405 Masonry.prototype._getContainerFitWidth = function() { 3406 var unusedCols = 0; 3407 // count unused columns 3408 var i = this.cols; 3409 while ( --i ) { 3410 if ( this.colYs[i] !== 0 ) { 3411 break; 3412 } 3413 unusedCols++; 3414 } 3415 // fit container to columns that have been used 3416 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter; 3417 }; 3418 3419 Masonry.prototype.needsResizeLayout = function() { 3420 var previousWidth = this.containerWidth; 3421 this.getContainerWidth(); 3422 return previousWidth !== this.containerWidth; 3423 }; 3424 3425 return Masonry; 3426 3427})); 3428 3429/*! 3430 * Masonry layout mode 3431 * sub-classes Masonry 3432 * http://masonry.desandro.com 3433 */ 3434 3435( function( window, factory ) { 3436 'use strict'; 3437 // universal module definition 3438 if ( typeof define == 'function' && define.amd ) { 3439 // AMD 3440 define( 'isotope/js/layout-modes/masonry',[ 3441 '../layout-mode', 3442 'masonry/masonry' 3443 ], 3444 factory ); 3445 } else if ( typeof exports == 'object' ) { 3446 // CommonJS 3447 module.exports = factory( 3448 require('../layout-mode'), 3449 require('masonry-layout') 3450 ); 3451 } else { 3452 // browser global 3453 factory( 3454 window.Isotope.LayoutMode, 3455 window.Masonry 3456 ); 3457 } 3458 3459}( window, function factory( LayoutMode, Masonry ) { 3460'use strict'; 3461 3462// -------------------------- helpers -------------------------- // 3463 3464// extend objects 3465function extend( a, b ) { 3466 for ( var prop in b ) { 3467 a[ prop ] = b[ prop ]; 3468 } 3469 return a; 3470} 3471 3472// -------------------------- masonryDefinition -------------------------- // 3473 3474 // create an Outlayer layout class 3475 var MasonryMode = LayoutMode.create('masonry'); 3476 3477 // save on to these methods 3478 var _getElementOffset = MasonryMode.prototype._getElementOffset; 3479 var layout = MasonryMode.prototype.layout; 3480 var _getMeasurement = MasonryMode.prototype._getMeasurement; 3481 3482 // sub-class Masonry 3483 extend( MasonryMode.prototype, Masonry.prototype ); 3484 3485 // set back, as it was overwritten by Masonry 3486 MasonryMode.prototype._getElementOffset = _getElementOffset; 3487 MasonryMode.prototype.layout = layout; 3488 MasonryMode.prototype._getMeasurement = _getMeasurement; 3489 3490 var measureColumns = MasonryMode.prototype.measureColumns; 3491 MasonryMode.prototype.measureColumns = function() { 3492 // set items, used if measuring first item 3493 this.items = this.isotope.filteredItems; 3494 measureColumns.call( this ); 3495 }; 3496 3497 // HACK copy over isOriginLeft/Top options 3498 var _manageStamp = MasonryMode.prototype._manageStamp; 3499 MasonryMode.prototype._manageStamp = function() { 3500 this.options.isOriginLeft = this.isotope.options.isOriginLeft; 3501 this.options.isOriginTop = this.isotope.options.isOriginTop; 3502 _manageStamp.apply( this, arguments ); 3503 }; 3504 3505 return MasonryMode; 3506 3507})); 3508 3509/** 3510 * fitRows layout mode 3511 */ 3512 3513( function( window, factory ) { 3514 'use strict'; 3515 // universal module definition 3516 if ( typeof define == 'function' && define.amd ) { 3517 // AMD 3518 define( 'isotope/js/layout-modes/fit-rows',[ 3519 '../layout-mode' 3520 ], 3521 factory ); 3522 } else if ( typeof exports == 'object' ) { 3523 // CommonJS 3524 module.exports = factory( 3525 require('../layout-mode') 3526 ); 3527 } else { 3528 // browser global 3529 factory( 3530 window.Isotope.LayoutMode 3531 ); 3532 } 3533 3534}( window, function factory( LayoutMode ) { 3535'use strict'; 3536 3537var FitRows = LayoutMode.create('fitRows'); 3538 3539FitRows.prototype._resetLayout = function() { 3540 this.x = 0; 3541 this.y = 0; 3542 this.maxY = 0; 3543 this._getMeasurement( 'gutter', 'outerWidth' ); 3544}; 3545 3546FitRows.prototype._getItemLayoutPosition = function( item ) { 3547 item.getSize(); 3548 3549 var itemWidth = item.size.outerWidth + this.gutter; 3550 // if this element cannot fit in the current row 3551 var containerWidth = this.isotope.size.innerWidth + this.gutter; 3552 if ( this.x !== 0 && itemWidth + this.x > containerWidth ) { 3553 this.x = 0; 3554 this.y = this.maxY; 3555 } 3556 3557 var position = { 3558 x: this.x, 3559 y: this.y 3560 }; 3561 3562 this.maxY = Math.max( this.maxY, this.y + item.size.outerHeight ); 3563 this.x += itemWidth; 3564 3565 return position; 3566}; 3567 3568FitRows.prototype._getContainerSize = function() { 3569 return { height: this.maxY }; 3570}; 3571 3572return FitRows; 3573 3574})); 3575 3576/** 3577 * vertical layout mode 3578 */ 3579 3580( function( window, factory ) { 3581 'use strict'; 3582 // universal module definition 3583 if ( typeof define == 'function' && define.amd ) { 3584 // AMD 3585 define( 'isotope/js/layout-modes/vertical',[ 3586 '../layout-mode' 3587 ], 3588 factory ); 3589 } else if ( typeof exports == 'object' ) { 3590 // CommonJS 3591 module.exports = factory( 3592 require('../layout-mode') 3593 ); 3594 } else { 3595 // browser global 3596 factory( 3597 window.Isotope.LayoutMode 3598 ); 3599 } 3600 3601}( window, function factory( LayoutMode ) { 3602'use strict'; 3603 3604var Vertical = LayoutMode.create( 'vertical', { 3605 horizontalAlignment: 0 3606}); 3607 3608Vertical.prototype._resetLayout = function() { 3609 this.y = 0; 3610}; 3611 3612Vertical.prototype._getItemLayoutPosition = function( item ) { 3613 item.getSize(); 3614 var x = ( this.isotope.size.innerWidth - item.size.outerWidth ) * 3615 this.options.horizontalAlignment; 3616 var y = this.y; 3617 this.y += item.size.outerHeight; 3618 return { x: x, y: y }; 3619}; 3620 3621Vertical.prototype._getContainerSize = function() { 3622 return { height: this.y }; 3623}; 3624 3625return Vertical; 3626 3627})); 3628 3629/*! 3630 * Isotope v2.2.2 3631 * 3632 * Licensed GPLv3 for open source use 3633 * or Isotope Commercial License for commercial use 3634 * 3635 * http://isotope.metafizzy.co 3636 * Copyright 2015 Metafizzy 3637 */ 3638 3639( function( window, factory ) { 3640 'use strict'; 3641 // universal module definition 3642 3643 if ( typeof define == 'function' && define.amd ) { 3644 // AMD 3645 define( [ 3646 'outlayer/outlayer', 3647 'get-size/get-size', 3648 'matches-selector/matches-selector', 3649 'fizzy-ui-utils/utils', 3650 'isotope/js/item', 3651 'isotope/js/layout-mode', 3652 // include default layout modes 3653 'isotope/js/layout-modes/masonry', 3654 'isotope/js/layout-modes/fit-rows', 3655 'isotope/js/layout-modes/vertical' 3656 ], 3657 function( Outlayer, getSize, matchesSelector, utils, Item, LayoutMode ) { 3658 return factory( window, Outlayer, getSize, matchesSelector, utils, Item, LayoutMode ); 3659 }); 3660 } else if ( typeof exports == 'object' ) { 3661 // CommonJS 3662 module.exports = factory( 3663 window, 3664 require('outlayer'), 3665 require('get-size'), 3666 require('desandro-matches-selector'), 3667 require('fizzy-ui-utils'), 3668 require('./item'), 3669 require('./layout-mode'), 3670 // include default layout modes 3671 require('./layout-modes/masonry'), 3672 require('./layout-modes/fit-rows'), 3673 require('./layout-modes/vertical') 3674 ); 3675 } else { 3676 // browser global 3677 window.Isotope = factory( 3678 window, 3679 window.Outlayer, 3680 window.getSize, 3681 window.matchesSelector, 3682 window.fizzyUIUtils, 3683 window.Isotope.Item, 3684 window.Isotope.LayoutMode 3685 ); 3686 } 3687 3688}( window, function factory( window, Outlayer, getSize, matchesSelector, utils, 3689 Item, LayoutMode ) { 3690 3691 3692 3693// -------------------------- vars -------------------------- // 3694 3695var jQuery = window.jQuery; 3696 3697// -------------------------- helpers -------------------------- // 3698 3699var trim = String.prototype.trim ? 3700 function( str ) { 3701 return str.trim(); 3702 } : 3703 function( str ) { 3704 return str.replace( /^\s+|\s+$/g, '' ); 3705 }; 3706 3707var docElem = document.documentElement; 3708 3709var getText = docElem.textContent ? 3710 function( elem ) { 3711 return elem.textContent; 3712 } : 3713 function( elem ) { 3714 return elem.innerText; 3715 }; 3716 3717// -------------------------- isotopeDefinition -------------------------- // 3718 3719 // create an Outlayer layout class 3720 var Isotope = Outlayer.create( 'isotope', { 3721 layoutMode: "masonry", 3722 isJQueryFiltering: true, 3723 sortAscending: true 3724 }); 3725 3726 Isotope.Item = Item; 3727 Isotope.LayoutMode = LayoutMode; 3728 3729 Isotope.prototype._create = function() { 3730 this.itemGUID = 0; 3731 // functions that sort items 3732 this._sorters = {}; 3733 this._getSorters(); 3734 // call super 3735 Outlayer.prototype._create.call( this ); 3736 3737 // create layout modes 3738 this.modes = {}; 3739 // start filteredItems with all items 3740 this.filteredItems = this.items; 3741 // keep of track of sortBys 3742 this.sortHistory = [ 'original-order' ]; 3743 // create from registered layout modes 3744 for ( var name in LayoutMode.modes ) { 3745 this._initLayoutMode( name ); 3746 } 3747 }; 3748 3749 Isotope.prototype.reloadItems = function() { 3750 // reset item ID counter 3751 this.itemGUID = 0; 3752 // call super 3753 Outlayer.prototype.reloadItems.call( this ); 3754 }; 3755 3756 Isotope.prototype._itemize = function() { 3757 var items = Outlayer.prototype._itemize.apply( this, arguments ); 3758 // assign ID for original-order 3759 for ( var i=0, len = items.length; i < len; i++ ) { 3760 var item = items[i]; 3761 item.id = this.itemGUID++; 3762 } 3763 this._updateItemsSortData( items ); 3764 return items; 3765 }; 3766 3767 3768 // -------------------------- layout -------------------------- // 3769 3770 Isotope.prototype._initLayoutMode = function( name ) { 3771 var Mode = LayoutMode.modes[ name ]; 3772 // set mode options 3773 // HACK extend initial options, back-fill in default options 3774 var initialOpts = this.options[ name ] || {}; 3775 this.options[ name ] = Mode.options ? 3776 utils.extend( Mode.options, initialOpts ) : initialOpts; 3777 // init layout mode instance 3778 this.modes[ name ] = new Mode( this ); 3779 }; 3780 3781 3782 Isotope.prototype.layout = function() { 3783 // if first time doing layout, do all magic 3784 if ( !this._isLayoutInited && this.options.isInitLayout ) { 3785 this.arrange(); 3786 return; 3787 } 3788 this._layout(); 3789 }; 3790 3791 // private method to be used in layout() & magic() 3792 Isotope.prototype._layout = function() { 3793 // don't animate first layout 3794 var isInstant = this._getIsInstant(); 3795 // layout flow 3796 this._resetLayout(); 3797 this._manageStamps(); 3798 this.layoutItems( this.filteredItems, isInstant ); 3799 3800 // flag for initalized 3801 this._isLayoutInited = true; 3802 }; 3803 3804 // filter + sort + layout 3805 Isotope.prototype.arrange = function( opts ) { 3806 // set any options pass 3807 this.option( opts ); 3808 this._getIsInstant(); 3809 // filter, sort, and layout 3810 3811 // filter 3812 var filtered = this._filter( this.items ); 3813 this.filteredItems = filtered.matches; 3814 3815 var _this = this; 3816 function hideReveal() { 3817 _this.reveal( filtered.needReveal ); 3818 _this.hide( filtered.needHide ); 3819 } 3820 3821 this._bindArrangeComplete(); 3822 3823 if ( this._isInstant ) { 3824 this._noTransition( hideReveal ); 3825 } else { 3826 hideReveal(); 3827 } 3828 3829 this._sort(); 3830 this._layout(); 3831 }; 3832 // alias to _init for main plugin method 3833 Isotope.prototype._init = Isotope.prototype.arrange; 3834 3835 // HACK 3836 // Don't animate/transition first layout 3837 // Or don't animate/transition other layouts 3838 Isotope.prototype._getIsInstant = function() { 3839 var isInstant = this.options.isLayoutInstant !== undefined ? 3840 this.options.isLayoutInstant : !this._isLayoutInited; 3841 this._isInstant = isInstant; 3842 return isInstant; 3843 }; 3844 3845 // listen for layoutComplete, hideComplete and revealComplete 3846 // to trigger arrangeComplete 3847 Isotope.prototype._bindArrangeComplete = function() { 3848 // listen for 3 events to trigger arrangeComplete 3849 var isLayoutComplete, isHideComplete, isRevealComplete; 3850 var _this = this; 3851 function arrangeParallelCallback() { 3852 if ( isLayoutComplete && isHideComplete && isRevealComplete ) { 3853 _this.dispatchEvent( 'arrangeComplete', null, [ _this.filteredItems ] ); 3854 } 3855 } 3856 this.once( 'layoutComplete', function() { 3857 isLayoutComplete = true; 3858 arrangeParallelCallback(); 3859 }); 3860 this.once( 'hideComplete', function() { 3861 isHideComplete = true; 3862 arrangeParallelCallback(); 3863 }); 3864 this.once( 'revealComplete', function() { 3865 isRevealComplete = true; 3866 arrangeParallelCallback(); 3867 }); 3868 }; 3869 3870 // -------------------------- filter -------------------------- // 3871 3872 Isotope.prototype._filter = function( items ) { 3873 var filter = this.options.filter;
vendor: 11,150 bytes, lines 3874-4256
3874 filter = filter || '*'; 3875 var matches = []; 3876 var hiddenMatched = []; 3877 var visibleUnmatched = []; 3878 3879 var test = this._getFilterTest( filter ); 3880 3881 // test each item 3882 for ( var i=0, len = items.length; i < len; i++ ) { 3883 var item = items[i]; 3884 if ( item.isIgnored ) { 3885 continue; 3886 } 3887 // add item to either matched or unmatched group 3888 var isMatched = test( item ); 3889 // item.isFilterMatched = isMatched; 3890 // add to matches if its a match 3891 if ( isMatched ) { 3892 matches.push( item ); 3893 } 3894 // add to additional group if item needs to be hidden or revealed 3895 if ( isMatched && item.isHidden ) { 3896 hiddenMatched.push( item ); 3897 } else if ( !isMatched && !item.isHidden ) { 3898 visibleUnmatched.push( item ); 3899 } 3900 } 3901 3902 // return collections of items to be manipulated 3903 return { 3904 matches: matches, 3905 needReveal: hiddenMatched, 3906 needHide: visibleUnmatched 3907 }; 3908 }; 3909 3910 // get a jQuery, function, or a matchesSelector test given the filter 3911 Isotope.prototype._getFilterTest = function( filter ) { 3912 if ( jQuery && this.options.isJQueryFiltering ) { 3913 // use jQuery 3914 return function( item ) { 3915 return jQuery( item.element ).is( filter ); 3916 }; 3917 } 3918 if ( typeof filter == 'function' ) { 3919 // use filter as function 3920 return function( item ) { 3921 return filter( item.element ); 3922 }; 3923 } 3924 // default, use filter as selector string 3925 return function( item ) { 3926 return matchesSelector( item.element, filter ); 3927 }; 3928 }; 3929 3930 // -------------------------- sorting -------------------------- // 3931 3932 /** 3933 * @params {Array} elems 3934 * @public 3935 */ 3936 Isotope.prototype.updateSortData = function( elems ) { 3937 // get items 3938 var items; 3939 if ( elems ) { 3940 elems = utils.makeArray( elems ); 3941 items = this.getItems( elems ); 3942 } else { 3943 // update all items if no elems provided 3944 items = this.items; 3945 } 3946 3947 this._getSorters(); 3948 this._updateItemsSortData( items ); 3949 }; 3950 3951 Isotope.prototype._getSorters = function() { 3952 var getSortData = this.options.getSortData; 3953 for ( var key in getSortData ) { 3954 var sorter = getSortData[ key ]; 3955 this._sorters[ key ] = mungeSorter( sorter ); 3956 } 3957 }; 3958 3959 /** 3960 * @params {Array} items - of Isotope.Items 3961 * @private 3962 */ 3963 Isotope.prototype._updateItemsSortData = function( items ) { 3964 // do not update if no items 3965 var len = items && items.length; 3966 3967 for ( var i=0; len && i < len; i++ ) { 3968 var item = items[i]; 3969 item.updateSortData(); 3970 } 3971 }; 3972 3973 // ----- munge sorter ----- // 3974 3975 // encapsulate this, as we just need mungeSorter 3976 // other functions in here are just for munging 3977 var mungeSorter = ( function() { 3978 // add a magic layer to sorters for convienent shorthands 3979 // `.foo-bar` will use the text of .foo-bar querySelector 3980 // `[foo-bar]` will use attribute 3981 // you can also add parser 3982 // `.foo-bar parseInt` will parse that as a number 3983 function mungeSorter( sorter ) { 3984 // if not a string, return function or whatever it is 3985 if ( typeof sorter != 'string' ) { 3986 return sorter; 3987 } 3988 // parse the sorter string 3989 var args = trim( sorter ).split(' '); 3990 var query = args[0]; 3991 // check if query looks like [an-attribute] 3992 var attrMatch = query.match( /^\[(.+)\]$/ ); 3993 var attr = attrMatch && attrMatch[1]; 3994 var getValue = getValueGetter( attr, query ); 3995 // use second argument as a parser 3996 var parser = Isotope.sortDataParsers[ args[1] ]; 3997 // parse the value, if there was a parser 3998 sorter = parser ? function( elem ) { 3999 return elem && parser( getValue( elem ) ); 4000 } : 4001 // otherwise just return value 4002 function( elem ) { 4003 return elem && getValue( elem ); 4004 }; 4005 4006 return sorter; 4007 } 4008 4009 // get an attribute getter, or get text of the querySelector 4010 function getValueGetter( attr, query ) { 4011 var getValue; 4012 // if query looks like [foo-bar], get attribute 4013 if ( attr ) { 4014 getValue = function( elem ) { 4015 return elem.getAttribute( attr ); 4016 }; 4017 } else { 4018 // otherwise, assume its a querySelector, and get its text 4019 getValue = function( elem ) { 4020 var child = elem.querySelector( query ); 4021 return child && getText( child ); 4022 }; 4023 } 4024 return getValue; 4025 } 4026 4027 return mungeSorter; 4028 })(); 4029 4030 // parsers used in getSortData shortcut strings 4031 Isotope.sortDataParsers = { 4032 'parseInt': function( val ) { 4033 return parseInt( val, 10 ); 4034 }, 4035 'parseFloat': function( val ) { 4036 return parseFloat( val ); 4037 } 4038 }; 4039 4040 // ----- sort method ----- // 4041 4042 // sort filteredItem order 4043 Isotope.prototype._sort = function() { 4044 var sortByOpt = this.options.sortBy; 4045 if ( !sortByOpt ) { 4046 return; 4047 } 4048 // concat all sortBy and sortHistory 4049 var sortBys = [].concat.apply( sortByOpt, this.sortHistory ); 4050 // sort magic 4051 var itemSorter = getItemSorter( sortBys, this.options.sortAscending ); 4052 this.filteredItems.sort( itemSorter ); 4053 // keep track of sortBy History 4054 if ( sortByOpt != this.sortHistory[0] ) { 4055 // add to front, oldest goes in last 4056 this.sortHistory.unshift( sortByOpt ); 4057 } 4058 }; 4059 4060 // returns a function used for sorting 4061 function getItemSorter( sortBys, sortAsc ) { 4062 return function sorter( itemA, itemB ) { 4063 // cycle through all sortKeys 4064 for ( var i = 0, len = sortBys.length; i < len; i++ ) { 4065 var sortBy = sortBys[i]; 4066 var a = itemA.sortData[ sortBy ]; 4067 var b = itemB.sortData[ sortBy ]; 4068 if ( a > b || a < b ) { 4069 // if sortAsc is an object, use the value given the sortBy key 4070 var isAscending = sortAsc[ sortBy ] !== undefined ? sortAsc[ sortBy ] : sortAsc; 4071 var direction = isAscending ? 1 : -1; 4072 return ( a > b ? 1 : -1 ) * direction; 4073 } 4074 } 4075 return 0; 4076 }; 4077 } 4078 4079 // -------------------------- methods -------------------------- // 4080 4081 // get layout mode 4082 Isotope.prototype._mode = function() { 4083 var layoutMode = this.options.layoutMode; 4084 var mode = this.modes[ layoutMode ]; 4085 if ( !mode ) { 4086 // TODO console.error 4087 throw new Error( 'No layout mode: ' + layoutMode ); 4088 } 4089 // HACK sync mode's options 4090 // any options set after init for layout mode need to be synced 4091 mode.options = this.options[ layoutMode ]; 4092 return mode; 4093 }; 4094 4095 Isotope.prototype._resetLayout = function() { 4096 // trigger original reset layout 4097 Outlayer.prototype._resetLayout.call( this ); 4098 this._mode()._resetLayout(); 4099 }; 4100 4101 Isotope.prototype._getItemLayoutPosition = function( item ) { 4102 return this._mode()._getItemLayoutPosition( item ); 4103 }; 4104 4105 Isotope.prototype._manageStamp = function( stamp ) { 4106 this._mode()._manageStamp( stamp ); 4107 }; 4108 4109 Isotope.prototype._getContainerSize = function() { 4110 return this._mode()._getContainerSize(); 4111 }; 4112 4113 Isotope.prototype.needsResizeLayout = function() { 4114 return this._mode().needsResizeLayout(); 4115 }; 4116 4117 // -------------------------- adding & removing -------------------------- // 4118 4119 // HEADS UP overwrites default Outlayer appended 4120 Isotope.prototype.appended = function( elems ) { 4121 var items = this.addItems( elems ); 4122 if ( !items.length ) { 4123 return; 4124 } 4125 // filter, layout, reveal new items 4126 var filteredItems = this._filterRevealAdded( items ); 4127 // add to filteredItems 4128 this.filteredItems = this.filteredItems.concat( filteredItems ); 4129 }; 4130 4131 // HEADS UP overwrites default Outlayer prepended 4132 Isotope.prototype.prepended = function( elems ) { 4133 var items = this._itemize( elems ); 4134 if ( !items.length ) { 4135 return; 4136 } 4137 // start new layout 4138 this._resetLayout(); 4139 this._manageStamps(); 4140 // filter, layout, reveal new items 4141 var filteredItems = this._filterRevealAdded( items ); 4142 // layout previous items 4143 this.layoutItems( this.filteredItems ); 4144 // add to items and filteredItems 4145 this.filteredItems = filteredItems.concat( this.filteredItems ); 4146 this.items = items.concat( this.items ); 4147 }; 4148 4149 Isotope.prototype._filterRevealAdded = function( items ) { 4150 var filtered = this._filter( items ); 4151 this.hide( filtered.needHide ); 4152 // reveal all new items 4153 this.reveal( filtered.matches ); 4154 // layout new items, no transition 4155 this.layoutItems( filtered.matches, true ); 4156 return filtered.matches; 4157 }; 4158 4159 /** 4160 * Filter, sort, and layout newly-appended item elements 4161 * @param {Array or NodeList or Element} elems 4162 */ 4163 Isotope.prototype.insert = function( elems ) { 4164 var items = this.addItems( elems ); 4165 if ( !items.length ) { 4166 return; 4167 } 4168 // append item elements 4169 var i, item; 4170 var len = items.length; 4171 for ( i=0; i < len; i++ ) { 4172 item = items[i]; 4173 this.element.appendChild( item.element ); 4174 } 4175 // filter new stuff 4176 var filteredInsertItems = this._filter( items ).matches; 4177 // set flag 4178 for ( i=0; i < len; i++ ) { 4179 items[i].isLayoutInstant = true; 4180 } 4181 this.arrange(); 4182 // reset flag 4183 for ( i=0; i < len; i++ ) { 4184 delete items[i].isLayoutInstant; 4185 } 4186 this.reveal( filteredInsertItems ); 4187 }; 4188 4189 var _remove = Isotope.prototype.remove; 4190 Isotope.prototype.remove = function( elems ) { 4191 elems = utils.makeArray( elems ); 4192 var removeItems = this.getItems( elems ); 4193 // do regular thing 4194 _remove.call( this, elems ); 4195 // bail if no items to remove 4196 var len = removeItems && removeItems.length; 4197 if ( !len ) { 4198 return; 4199 } 4200 // remove elems from filteredItems 4201 for ( var i=0; i < len; i++ ) { 4202 var item = removeItems[i]; 4203 // remove item from collection 4204 utils.removeFrom( this.filteredItems, item ); 4205 } 4206 }; 4207 4208 Isotope.prototype.shuffle = function() { 4209 // update random sortData 4210 for ( var i=0, len = this.items.length; i < len; i++ ) { 4211 var item = this.items[i]; 4212 item.sortData.random = Math.random(); 4213 } 4214 this.options.sortBy = 'random'; 4215 this._sort(); 4216 this._layout(); 4217 }; 4218 4219 /** 4220 * trigger fn without transition 4221 * kind of hacky to have this in the first place 4222 * @param {Function} fn 4223 * @returns ret 4224 * @private 4225 */ 4226 Isotope.prototype._noTransition = function( fn ) { 4227 // save transitionDuration before disabling 4228 var transitionDuration = this.options.transitionDuration; 4229 // disable transition 4230 this.options.transitionDuration = 0; 4231 // do it 4232 var returnValue = fn.call( this ); 4233 // re-enable transition for reveal 4234 this.options.transitionDuration = transitionDuration; 4235 return returnValue; 4236 }; 4237 4238 // ----- helper methods ----- // 4239 4240 /** 4241 * getter method for getting filtered item elements 4242 * @returns {Array} elems - collection of item elements 4243 */ 4244 Isotope.prototype.getFilteredItemElements = function() { 4245 var elems = []; 4246 for ( var i=0, len = this.filteredItems.length; i < len; i++ ) { 4247 elems.push( this.filteredItems[i].element ); 4248 } 4249 return elems; 4250 }; 4251 4252 // ----- ----- // 4253 4254 return Isotope; 4255 4256}));
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.