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