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