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