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