vendor: 31,440 bytes, lines 1-1239
1/*! 2 * Packery layout mode PACKAGED v2.0.1 3 * sub-classes Packery 4 */ 5 6/** 7 * Rect 8 * low-level utility class for basic geometry 9 */ 10 11( function( window, factory ) { 12 // universal module definition 13 /* jshint strict: false */ /* globals define, module */ 14 if ( typeof define == 'function' && define.amd ) { 15 // AMD 16 define( 'packery/js/rect',factory ); 17 } else if ( typeof module == 'object' && module.exports ) { 18 // CommonJS 19 module.exports = factory(); 20 } else { 21 // browser global 22 window.Packery = window.Packery || {}; 23 window.Packery.Rect = factory(); 24 } 25 26}( window, function factory() { 27 28 29// -------------------------- Rect -------------------------- // 30 31function Rect( props ) { 32 // extend properties from defaults 33 for ( var prop in Rect.defaults ) { 34 this[ prop ] = Rect.defaults[ prop ]; 35 } 36 37 for ( prop in props ) { 38 this[ prop ] = props[ prop ]; 39 } 40 41} 42 43Rect.defaults = { 44 x: 0, 45 y: 0, 46 width: 0, 47 height: 0 48}; 49 50var proto = Rect.prototype; 51 52/** 53 * Determines whether or not this rectangle wholly encloses another rectangle or point. 54 * @param {Rect} rect 55 * @returns {Boolean} 56**/ 57proto.contains = function( rect ) { 58 // points don't have width or height 59 var otherWidth = rect.width || 0; 60 var otherHeight = rect.height || 0; 61 return this.x <= rect.x && 62 this.y <= rect.y && 63 this.x + this.width >= rect.x + otherWidth && 64 this.y + this.height >= rect.y + otherHeight; 65}; 66 67/** 68 * Determines whether or not the rectangle intersects with another. 69 * @param {Rect} rect 70 * @returns {Boolean} 71**/ 72proto.overlaps = function( rect ) { 73 var thisRight = this.x + this.width; 74 var thisBottom = this.y + this.height; 75 var rectRight = rect.x + rect.width; 76 var rectBottom = rect.y + rect.height; 77 78 // http://stackoverflow.com/a/306332 79 return this.x < rectRight && 80 thisRight > rect.x && 81 this.y < rectBottom && 82 thisBottom > rect.y; 83}; 84 85/** 86 * @param {Rect} rect - the overlapping rect 87 * @returns {Array} freeRects - rects representing the area around the rect 88**/ 89proto.getMaximalFreeRects = function( rect ) { 90 91 // if no intersection, return false 92 if ( !this.overlaps( rect ) ) { 93 return false; 94 } 95 96 var freeRects = []; 97 var freeRect; 98 99 var thisRight = this.x + this.width; 100 var thisBottom = this.y + this.height; 101 var rectRight = rect.x + rect.width; 102 var rectBottom = rect.y + rect.height; 103 104 // top 105 if ( this.y < rect.y ) { 106 freeRect = new Rect({ 107 x: this.x, 108 y: this.y, 109 width: this.width, 110 height: rect.y - this.y 111 }); 112 freeRects.push( freeRect ); 113 } 114 115 // right 116 if ( thisRight > rectRight ) { 117 freeRect = new Rect({ 118 x: rectRight, 119 y: this.y, 120 width: thisRight - rectRight, 121 height: this.height 122 }); 123 freeRects.push( freeRect ); 124 } 125 126 // bottom 127 if ( thisBottom > rectBottom ) { 128 freeRect = new Rect({ 129 x: this.x, 130 y: rectBottom, 131 width: this.width, 132 height: thisBottom - rectBottom 133 }); 134 freeRects.push( freeRect ); 135 } 136 137 // left 138 if ( this.x < rect.x ) { 139 freeRect = new Rect({ 140 x: this.x, 141 y: this.y, 142 width: rect.x - this.x, 143 height: this.height 144 }); 145 freeRects.push( freeRect ); 146 } 147 148 return freeRects; 149}; 150 151proto.canFit = function( rect ) { 152 return this.width >= rect.width && this.height >= rect.height; 153}; 154 155return Rect; 156 157})); 158 159/** 160 * Packer 161 * bin-packing algorithm 162 */ 163 164( function( window, factory ) { 165 // universal module definition 166 /* jshint strict: false */ /* globals define, module, require */ 167 if ( typeof define == 'function' && define.amd ) { 168 // AMD 169 define( 'packery/js/packer',[ './rect' ], factory ); 170 } else if ( typeof module == 'object' && module.exports ) { 171 // CommonJS 172 module.exports = factory( 173 require('./rect') 174 ); 175 } else { 176 // browser global 177 var Packery = window.Packery = window.Packery || {}; 178 Packery.Packer = factory( Packery.Rect ); 179 } 180 181}( window, function factory( Rect ) { 182 183 184// -------------------------- Packer -------------------------- // 185 186/** 187 * @param {Number} width 188 * @param {Number} height 189 * @param {String} sortDirection 190 * topLeft for vertical, leftTop for horizontal 191 */ 192function Packer( width, height, sortDirection ) { 193 this.width = width || 0; 194 this.height = height || 0; 195 this.sortDirection = sortDirection || 'downwardLeftToRight'; 196 197 this.reset(); 198} 199 200var proto = Packer.prototype; 201 202proto.reset = function() { 203 this.spaces = []; 204 205 var initialSpace = new Rect({ 206 x: 0, 207 y: 0, 208 width: this.width, 209 height: this.height 210 }); 211 212 this.spaces.push( initialSpace ); 213 // set sorter 214 this.sorter = sorters[ this.sortDirection ] || sorters.downwardLeftToRight; 215}; 216 217// change x and y of rect to fit with in Packer's available spaces 218proto.pack = function( rect ) { 219 for ( var i=0; i < this.spaces.length; i++ ) { 220 var space = this.spaces[i]; 221 if ( space.canFit( rect ) ) { 222 this.placeInSpace( rect, space ); 223 break; 224 } 225 } 226}; 227 228proto.columnPack = function( rect ) { 229 for ( var i=0; i < this.spaces.length; i++ ) { 230 var space = this.spaces[i]; 231 var canFitInSpaceColumn = space.x <= rect.x && 232 space.x + space.width >= rect.x + rect.width && 233 space.height >= rect.height - 0.01; // fudge number for rounding error 234 if ( canFitInSpaceColumn ) { 235 rect.y = space.y; 236 this.placed( rect ); 237 break; 238 } 239 } 240}; 241 242proto.rowPack = function( rect ) { 243 for ( var i=0; i < this.spaces.length; i++ ) { 244 var space = this.spaces[i]; 245 var canFitInSpaceRow = space.y <= rect.y && 246 space.y + space.height >= rect.y + rect.height && 247 space.width >= rect.width - 0.01; // fudge number for rounding error 248 if ( canFitInSpaceRow ) { 249 rect.x = space.x; 250 this.placed( rect ); 251 break; 252 } 253 } 254}; 255 256proto.placeInSpace = function( rect, space ) { 257 // place rect in space 258 rect.x = space.x; 259 rect.y = space.y; 260 261 this.placed( rect ); 262}; 263 264// update spaces with placed rect 265proto.placed = function( rect ) { 266 // update spaces 267 var revisedSpaces = []; 268 for ( var i=0; i < this.spaces.length; i++ ) { 269 var space = this.spaces[i]; 270 var newSpaces = space.getMaximalFreeRects( rect ); 271 // add either the original space or the new spaces to the revised spaces 272 if ( newSpaces ) { 273 revisedSpaces.push.apply( revisedSpaces, newSpaces ); 274 } else { 275 revisedSpaces.push( space ); 276 } 277 } 278 279 this.spaces = revisedSpaces; 280 281 this.mergeSortSpaces(); 282}; 283 284proto.mergeSortSpaces = function() { 285 // remove redundant spaces 286 Packer.mergeRects( this.spaces ); 287 this.spaces.sort( this.sorter ); 288}; 289 290// add a space back 291proto.addSpace = function( rect ) { 292 this.spaces.push( rect ); 293 this.mergeSortSpaces(); 294}; 295 296// -------------------------- utility functions -------------------------- // 297 298/** 299 * Remove redundant rectangle from array of rectangles 300 * @param {Array} rects: an array of Rects 301 * @returns {Array} rects: an array of Rects 302**/ 303Packer.mergeRects = function( rects ) { 304 var i = 0; 305 var rect = rects[i]; 306 307 rectLoop: 308 while ( rect ) { 309 var j = 0; 310 var compareRect = rects[ i + j ]; 311 312 while ( compareRect ) { 313 if ( compareRect == rect ) { 314 j++; // next 315 } else if ( compareRect.contains( rect ) ) { 316 // remove rect 317 rects.splice( i, 1 ); 318 rect = rects[i]; // set next rect 319 continue rectLoop; // bail on compareLoop 320 } else if ( rect.contains( compareRect ) ) { 321 // remove compareRect 322 rects.splice( i + j, 1 ); 323 } else { 324 j++; 325 } 326 compareRect = rects[ i + j ]; // set next compareRect 327 } 328 i++; 329 rect = rects[i]; 330 } 331 332 return rects; 333}; 334 335 336// -------------------------- sorters -------------------------- // 337 338// functions for sorting rects in order 339var sorters = { 340 // top down, then left to right 341 downwardLeftToRight: function( a, b ) { 342 return a.y - b.y || a.x - b.x; 343 }, 344 // left to right, then top down 345 rightwardTopToBottom: function( a, b ) { 346 return a.x - b.x || a.y - b.y; 347 } 348}; 349 350 351// -------------------------- -------------------------- // 352 353return Packer; 354 355})); 356 357/** 358 * Packery Item Element 359**/ 360 361( function( window, factory ) { 362 // universal module definition 363 /* jshint strict: false */ /* globals define, module, require */ 364 if ( typeof define == 'function' && define.amd ) { 365 // AMD 366 define( 'packery/js/item',[ 367 'outlayer/outlayer', 368 './rect' 369 ], 370 factory ); 371 } else if ( typeof module == 'object' && module.exports ) { 372 // CommonJS 373 module.exports = factory( 374 require('outlayer'), 375 require('./rect') 376 ); 377 } else { 378 // browser global 379 window.Packery.Item = factory( 380 window.Outlayer, 381 window.Packery.Rect 382 ); 383 } 384 385}( window, function factory( Outlayer, Rect ) { 386 387 388// -------------------------- Item -------------------------- // 389 390var docElemStyle = document.documentElement.style; 391 392var transformProperty = typeof docElemStyle.transform == 'string' ? 393 'transform' : 'WebkitTransform'; 394 395// sub-class Item 396var Item = function PackeryItem() { 397 Outlayer.Item.apply( this, arguments ); 398}; 399 400var proto = Item.prototype = Object.create( Outlayer.Item.prototype ); 401 402var __create = proto._create; 403proto._create = function() { 404 // call default _create logic 405 __create.call( this ); 406 this.rect = new Rect(); 407}; 408 409var _moveTo = proto.moveTo; 410proto.moveTo = function( x, y ) { 411 // don't shift 1px while dragging 412 var dx = Math.abs( this.position.x - x ); 413 var dy = Math.abs( this.position.y - y ); 414 415 var canHackGoTo = this.layout.dragItemCount && !this.isPlacing && 416 !this.isTransitioning && dx < 1 && dy < 1; 417 if ( canHackGoTo ) { 418 this.goTo( x, y ); 419 return; 420 } 421 _moveTo.apply( this, arguments ); 422}; 423 424// -------------------------- placing -------------------------- // 425 426proto.enablePlacing = function() { 427 this.removeTransitionStyles(); 428 // remove transform property from transition 429 if ( this.isTransitioning && transformProperty ) { 430 this.element.style[ transformProperty ] = 'none'; 431 } 432 this.isTransitioning = false; 433 this.getSize(); 434 this.layout._setRectSize( this.element, this.rect ); 435 this.isPlacing = true; 436}; 437 438proto.disablePlacing = function() { 439 this.isPlacing = false; 440}; 441 442// ----- ----- // 443 444// remove element from DOM 445proto.removeElem = function() { 446 this.element.parentNode.removeChild( this.element ); 447 // add space back to packer 448 this.layout.packer.addSpace( this.rect ); 449 this.emitEvent( 'remove', [ this ] ); 450}; 451 452// ----- dropPlaceholder ----- // 453 454proto.showDropPlaceholder = function() { 455 var dropPlaceholder = this.dropPlaceholder; 456 if ( !dropPlaceholder ) { 457 // create dropPlaceholder 458 dropPlaceholder = this.dropPlaceholder = document.createElement('div'); 459 dropPlaceholder.className = 'packery-drop-placeholder'; 460 dropPlaceholder.style.position = 'absolute'; 461 } 462 463 dropPlaceholder.style.width = this.size.width + 'px'; 464 dropPlaceholder.style.height = this.size.height + 'px'; 465 this.positionDropPlaceholder(); 466 this.layout.element.appendChild( dropPlaceholder ); 467}; 468 469proto.positionDropPlaceholder = function() { 470 this.dropPlaceholder.style[ transformProperty ] = 'translate(' + 471 this.rect.x + 'px, ' + this.rect.y + 'px)'; 472}; 473 474proto.hideDropPlaceholder = function() { 475 this.layout.element.removeChild( this.dropPlaceholder ); 476}; 477 478// ----- ----- // 479 480return Item; 481 482})); 483 484/*! 485 * Packery v2.0.0 486 * Gapless, draggable grid layouts 487 * 488 * Licensed GPLv3 for open source use 489 * or Packery Commercial License for commercial use 490 * 491 * http://packery.metafizzy.co 492 * Copyright 2016 Metafizzy 493 */ 494 495( function( window, factory ) { 496 // universal module definition 497 /* jshint strict: false */ /* globals define, module, require */ 498 if ( typeof define == 'function' && define.amd ) { 499 // AMD 500 define( 'packery/js/packery',[ 501 'get-size/get-size', 502 'outlayer/outlayer', 503 './rect', 504 './packer', 505 './item' 506 ], 507 factory ); 508 } else if ( typeof module == 'object' && module.exports ) { 509 // CommonJS 510 module.exports = factory( 511 require('get-size'), 512 require('outlayer'), 513 require('./rect'), 514 require('./packer'), 515 require('./item') 516 ); 517 } else { 518 // browser global 519 window.Packery = factory( 520 window.getSize, 521 window.Outlayer, 522 window.Packery.Rect, 523 window.Packery.Packer, 524 window.Packery.Item 525 ); 526 } 527 528}( window, function factory( getSize, Outlayer, Rect, Packer, Item ) { 529 530 531// ----- Rect ----- // 532 533// allow for pixel rounding errors IE8-IE11 & Firefox; #227 534Rect.prototype.canFit = function( rect ) { 535 return this.width >= rect.width - 1 && this.height >= rect.height - 1; 536}; 537 538// -------------------------- Packery -------------------------- // 539 540// create an Outlayer layout class 541var Packery = Outlayer.create('packery'); 542Packery.Item = Item; 543 544var proto = Packery.prototype; 545 546proto._create = function() { 547 // call super 548 Outlayer.prototype._create.call( this ); 549 550 // initial properties 551 this.packer = new Packer(); 552 // packer for drop targets 553 this.shiftPacker = new Packer(); 554 this.isEnabled = true; 555 556 this.dragItemCount = 0; 557 558 // create drag handlers 559 var _this = this; 560 this.handleDraggabilly = { 561 dragStart: function() { 562 _this.itemDragStart( this.element ); 563 }, 564 dragMove: function() { 565 _this.itemDragMove( this.element, this.position.x, this.position.y ); 566 }, 567 dragEnd: function() { 568 _this.itemDragEnd( this.element ); 569 } 570 }; 571 572 this.handleUIDraggable = { 573 start: function handleUIDraggableStart( event, ui ) { 574 // HTML5 may trigger dragstart, dismiss HTML5 dragging 575 if ( !ui ) { 576 return; 577 } 578 _this.itemDragStart( event.currentTarget ); 579 }, 580 drag: function handleUIDraggableDrag( event, ui ) { 581 if ( !ui ) { 582 return; 583 } 584 _this.itemDragMove( event.currentTarget, ui.position.left, ui.position.top ); 585 }, 586 stop: function handleUIDraggableStop( event, ui ) { 587 if ( !ui ) { 588 return; 589 } 590 _this.itemDragEnd( event.currentTarget ); 591 } 592 }; 593 594}; 595 596 597// ----- init & layout ----- // 598 599/** 600 * logic before any new layout 601 */ 602proto._resetLayout = function() { 603 this.getSize(); 604 605 this._getMeasurements(); 606 607 // reset packer 608 var width, height, sortDirection; 609 // packer settings, if horizontal or vertical 610 if ( this._getOption('horizontal') ) { 611 width = Infinity; 612 height = this.size.innerHeight + this.gutter; 613 sortDirection = 'rightwardTopToBottom'; 614 } else { 615 width = this.size.innerWidth + this.gutter; 616 height = Infinity; 617 sortDirection = 'downwardLeftToRight'; 618 } 619 620 this.packer.width = this.shiftPacker.width = width; 621 this.packer.height = this.shiftPacker.height = height; 622 this.packer.sortDirection = this.shiftPacker.sortDirection = sortDirection; 623 624 this.packer.reset(); 625 626 // layout 627 this.maxY = 0; 628 this.maxX = 0; 629}; 630 631/** 632 * update columnWidth, rowHeight, & gutter 633 * @private 634 */ 635proto._getMeasurements = function() { 636 this._getMeasurement( 'columnWidth', 'width' ); 637 this._getMeasurement( 'rowHeight', 'height' ); 638 this._getMeasurement( 'gutter', 'width' ); 639}; 640 641proto._getItemLayoutPosition = function( item ) { 642 this._setRectSize( item.element, item.rect ); 643 if ( this.isShifting || this.dragItemCount > 0 ) { 644 var packMethod = this._getPackMethod(); 645 this.packer[ packMethod ]( item.rect ); 646 } else { 647 this.packer.pack( item.rect ); 648 } 649 650 this._setMaxXY( item.rect ); 651 return item.rect; 652}; 653 654proto.shiftLayout = function() { 655 this.isShifting = true; 656 this.layout(); 657 delete this.isShifting; 658}; 659 660proto._getPackMethod = function() { 661 return this._getOption('horizontal') ? 'rowPack' : 'columnPack'; 662}; 663 664 665/** 666 * set max X and Y value, for size of container 667 * @param {Packery.Rect} rect 668 * @private 669 */ 670proto._setMaxXY = function( rect ) { 671 this.maxX = Math.max( rect.x + rect.width, this.maxX ); 672 this.maxY = Math.max( rect.y + rect.height, this.maxY ); 673}; 674 675/** 676 * set the width and height of a rect, applying columnWidth and rowHeight 677 * @param {Element} elem 678 * @param {Packery.Rect} rect 679 */ 680proto._setRectSize = function( elem, rect ) { 681 var size = getSize( elem ); 682 var w = size.outerWidth; 683 var h = size.outerHeight; 684 // size for columnWidth and rowHeight, if available 685 // only check if size is non-zero, #177 686 if ( w || h ) { 687 w = this._applyGridGutter( w, this.columnWidth ); 688 h = this._applyGridGutter( h, this.rowHeight ); 689 } 690 // rect must fit in packer 691 rect.width = Math.min( w, this.packer.width ); 692 rect.height = Math.min( h, this.packer.height ); 693}; 694 695/** 696 * fits item to columnWidth/rowHeight and adds gutter 697 * @param {Number} measurement - item width or height 698 * @param {Number} gridSize - columnWidth or rowHeight 699 * @returns measurement 700 */ 701proto._applyGridGutter = function( measurement, gridSize ) { 702 // just add gutter if no gridSize 703 if ( !gridSize ) { 704 return measurement + this.gutter; 705 } 706 gridSize += this.gutter; 707 // fit item to columnWidth/rowHeight 708 var remainder = measurement % gridSize; 709 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil'; 710 measurement = Math[ mathMethod ]( measurement / gridSize ) * gridSize; 711 return measurement; 712}; 713 714proto._getContainerSize = function() { 715 if ( this._getOption('horizontal') ) { 716 return { 717 width: this.maxX - this.gutter 718 }; 719 } else { 720 return { 721 height: this.maxY - this.gutter 722 }; 723 } 724}; 725 726 727// -------------------------- stamp -------------------------- // 728 729/** 730 * makes space for element 731 * @param {Element} elem 732 */ 733proto._manageStamp = function( elem ) { 734 735 var item = this.getItem( elem ); 736 var rect; 737 if ( item && item.isPlacing ) { 738 rect = item.rect; 739 } else { 740 var offset = this._getElementOffset( elem ); 741 rect = new Rect({ 742 x: this._getOption('originLeft') ? offset.left : offset.right, 743 y: this._getOption('originTop') ? offset.top : offset.bottom 744 }); 745 } 746 747 this._setRectSize( elem, rect ); 748 // save its space in the packer 749 this.packer.placed( rect ); 750 this._setMaxXY( rect ); 751}; 752 753// -------------------------- methods -------------------------- // 754 755function verticalSorter( a, b ) { 756 return a.position.y - b.position.y || a.position.x - b.position.x; 757} 758 759function horizontalSorter( a, b ) { 760 return a.position.x - b.position.x || a.position.y - b.position.y; 761} 762 763proto.sortItemsByPosition = function() { 764 var sorter = this._getOption('horizontal') ? horizontalSorter : verticalSorter; 765 this.items.sort( sorter ); 766}; 767 768/** 769 * Fit item element in its current position 770 * Packery will position elements around it 771 * useful for expanding elements 772 * 773 * @param {Element} elem 774 * @param {Number} x - horizontal destination position, optional 775 * @param {Number} y - vertical destination position, optional 776 */ 777proto.fit = function( elem, x, y ) { 778 var item = this.getItem( elem ); 779 if ( !item ) { 780 return; 781 } 782 783 // stamp item to get it out of layout 784 this.stamp( item.element ); 785 // set placing flag 786 item.enablePlacing(); 787 this.updateShiftTargets( item ); 788 // fall back to current position for fitting 789 x = x === undefined ? item.rect.x: x; 790 y = y === undefined ? item.rect.y: y; 791 // position it best at its destination 792 this.shift( item, x, y ); 793 this._bindFitEvents( item ); 794 item.moveTo( item.rect.x, item.rect.y ); 795 // layout everything else 796 this.shiftLayout(); 797 // return back to regularly scheduled programming 798 this.unstamp( item.element ); 799 this.sortItemsByPosition(); 800 item.disablePlacing(); 801}; 802 803/** 804 * emit event when item is fit and other items are laid out 805 * @param {Packery.Item} item 806 * @private 807 */ 808proto._bindFitEvents = function( item ) { 809 var _this = this; 810 var ticks = 0; 811 function onLayout() { 812 ticks++; 813 if ( ticks != 2 ) { 814 return; 815 } 816 _this.dispatchEvent( 'fitComplete', null, [ item ] ); 817 } 818 // when item is laid out 819 item.once( 'layout', onLayout ); 820 // when all items are laid out 821 this.once( 'layoutComplete', onLayout ); 822}; 823 824// -------------------------- resize -------------------------- // 825 826// debounced, layout on resize 827proto.resize = function() { 828 // don't trigger if size did not change 829 // or if resize was unbound. See #285, outlayer#9 830 if ( !this.isResizeBound || !this.needsResizeLayout() ) { 831 return; 832 } 833 834 if ( this.options.shiftPercentResize ) { 835 this.resizeShiftPercentLayout(); 836 } else { 837 this.layout(); 838 } 839}; 840 841/** 842 * check if layout is needed post layout 843 * @returns Boolean 844 */ 845proto.needsResizeLayout = function() { 846 var size = getSize( this.element ); 847 var innerSize = this._getOption('horizontal') ? 'innerHeight' : 'innerWidth'; 848 return size[ innerSize ] != this.size[ innerSize ]; 849}; 850 851proto.resizeShiftPercentLayout = function() { 852 var items = this._getItemsForLayout( this.items ); 853 854 var isHorizontal = this._getOption('horizontal'); 855 var coord = isHorizontal ? 'y' : 'x'; 856 var measure = isHorizontal ? 'height' : 'width'; 857 var segmentName = isHorizontal ? 'rowHeight' : 'columnWidth'; 858 var innerSize = isHorizontal ? 'innerHeight' : 'innerWidth'; 859 860 // proportional re-align items 861 var previousSegment = this[ segmentName ]; 862 previousSegment = previousSegment && previousSegment + this.gutter; 863 864 if ( previousSegment ) { 865 this._getMeasurements(); 866 var currentSegment = this[ segmentName ] + this.gutter; 867 items.forEach( function( item ) { 868 var seg = Math.round( item.rect[ coord ] / previousSegment ); 869 item.rect[ coord ] = seg * currentSegment; 870 }); 871 } else { 872 var currentSize = getSize( this.element )[ innerSize ] + this.gutter; 873 var previousSize = this.packer[ measure ]; 874 items.forEach( function( item ) { 875 item.rect[ coord ] = ( item.rect[ coord ] / previousSize ) * currentSize; 876 }); 877 } 878 879 this.shiftLayout(); 880}; 881 882// -------------------------- drag -------------------------- // 883 884/** 885 * handle an item drag start event 886 * @param {Element} elem 887 */ 888proto.itemDragStart = function( elem ) { 889 if ( !this.isEnabled ) { 890 return; 891 } 892 this.stamp( elem ); 893 // this.ignore( elem ); 894 var item = this.getItem( elem ); 895 if ( !item ) { 896 return; 897 } 898 899 item.enablePlacing(); 900 item.showDropPlaceholder(); 901 this.dragItemCount++; 902 this.updateShiftTargets( item ); 903}; 904 905proto.updateShiftTargets = function( dropItem ) { 906 this.shiftPacker.reset(); 907 908 // pack stamps 909 this._getBoundingRect(); 910 var isOriginLeft = this._getOption('originLeft'); 911 var isOriginTop = this._getOption('originTop'); 912 this.stamps.forEach( function( stamp ) { 913 // ignore dragged item 914 var item = this.getItem( stamp ); 915 if ( item && item.isPlacing ) { 916 return; 917 } 918 var offset = this._getElementOffset( stamp ); 919 var rect = new Rect({ 920 x: isOriginLeft ? offset.left : offset.right, 921 y: isOriginTop ? offset.top : offset.bottom 922 }); 923 this._setRectSize( stamp, rect ); 924 // save its space in the packer 925 this.shiftPacker.placed( rect ); 926 }, this ); 927 928 // reset shiftTargets 929 var isHorizontal = this._getOption('horizontal'); 930 var segmentName = isHorizontal ? 'rowHeight' : 'columnWidth'; 931 var measure = isHorizontal ? 'height' : 'width'; 932 933 this.shiftTargetKeys = []; 934 this.shiftTargets = []; 935 var boundsSize; 936 var segment = this[ segmentName ]; 937 segment = segment && segment + this.gutter; 938 939 if ( segment ) { 940 var segmentSpan = Math.ceil( dropItem.rect[ measure ] / segment ); 941 var segs = Math.floor( ( this.shiftPacker[ measure ] + this.gutter ) / segment ); 942 boundsSize = ( segs - segmentSpan ) * segment; 943 // add targets on top 944 for ( var i=0; i < segs; i++ ) { 945 this._addShiftTarget( i * segment, 0, boundsSize ); 946 } 947 } else { 948 boundsSize = ( this.shiftPacker[ measure ] + this.gutter ) - dropItem.rect[ measure ]; 949 this._addShiftTarget( 0, 0, boundsSize ); 950 } 951 952 // pack each item to measure where shiftTargets are 953 var items = this._getItemsForLayout( this.items ); 954 var packMethod = this._getPackMethod(); 955 items.forEach( function( item ) { 956 var rect = item.rect; 957 this._setRectSize( item.element, rect ); 958 this.shiftPacker[ packMethod ]( rect ); 959 960 // add top left corner 961 this._addShiftTarget( rect.x, rect.y, boundsSize ); 962 // add bottom left / top right corner 963 var cornerX = isHorizontal ? rect.x + rect.width : rect.x; 964 var cornerY = isHorizontal ? rect.y : rect.y + rect.height; 965 this._addShiftTarget( cornerX, cornerY, boundsSize ); 966 967 if ( segment ) { 968 // add targets for each column on bottom / row on right 969 var segSpan = Math.round( rect[ measure ] / segment ); 970 for ( var i=1; i < segSpan; i++ ) { 971 var segX = isHorizontal ? cornerX : rect.x + segment * i; 972 var segY = isHorizontal ? rect.y + segment * i : cornerY; 973 this._addShiftTarget( segX, segY, boundsSize ); 974 } 975 } 976 }, this ); 977 978}; 979 980proto._addShiftTarget = function( x, y, boundsSize ) { 981 var checkCoord = this._getOption('horizontal') ? y : x; 982 if ( checkCoord !== 0 && checkCoord > boundsSize ) { 983 return; 984 } 985 // create string for a key, easier to keep track of what targets 986 var key = x + ',' + y; 987 var hasKey = this.shiftTargetKeys.indexOf( key ) != -1; 988 if ( hasKey ) { 989 return; 990 } 991 this.shiftTargetKeys.push( key ); 992 this.shiftTargets.push({ x: x, y: y }); 993}; 994 995// -------------------------- drop -------------------------- // 996 997proto.shift = function( item, x, y ) { 998 var shiftPosition; 999 var minDistance = Infinity; 1000 var position = { x: x, y: y }; 1001 this.shiftTargets.forEach( function( target ) { 1002 var distance = getDistance( target, position ); 1003 if ( distance < minDistance ) { 1004 shiftPosition = target; 1005 minDistance = distance; 1006 } 1007 }); 1008 item.rect.x = shiftPosition.x; 1009 item.rect.y = shiftPosition.y; 1010}; 1011 1012function getDistance( a, b ) { 1013 var dx = b.x - a.x; 1014 var dy = b.y - a.y; 1015 return Math.sqrt( dx * dx + dy * dy ); 1016} 1017 1018// -------------------------- drag move -------------------------- // 1019 1020var DRAG_THROTTLE_TIME = 120; 1021 1022/** 1023 * handle an item drag move event 1024 * @param {Element} elem 1025 * @param {Number} x - horizontal change in position 1026 * @param {Number} y - vertical change in position 1027 */ 1028proto.itemDragMove = function( elem, x, y ) { 1029 var item = this.isEnabled && this.getItem( elem ); 1030 if ( !item ) { 1031 return; 1032 } 1033 1034 x -= this.size.paddingLeft; 1035 y -= this.size.paddingTop; 1036 1037 var _this = this; 1038 function onDrag() { 1039 _this.shift( item, x, y ); 1040 item.positionDropPlaceholder(); 1041 _this.layout(); 1042 } 1043 1044 // throttle 1045 var now = new Date(); 1046 if ( this._itemDragTime && now - this._itemDragTime < DRAG_THROTTLE_TIME ) { 1047 clearTimeout( this.dragTimeout ); 1048 this.dragTimeout = setTimeout( onDrag, DRAG_THROTTLE_TIME ); 1049 } else { 1050 onDrag(); 1051 this._itemDragTime = now; 1052 } 1053}; 1054 1055// -------------------------- drag end -------------------------- // 1056 1057/** 1058 * handle an item drag end event 1059 * @param {Element} elem 1060 */ 1061proto.itemDragEnd = function( elem ) { 1062 var item = this.isEnabled && this.getItem( elem ); 1063 if ( !item ) { 1064 return; 1065 } 1066 1067 clearTimeout( this.dragTimeout ); 1068 item.element.classList.add('is-positioning-post-drag'); 1069 1070 var completeCount = 0; 1071 var _this = this; 1072 function onDragEndLayoutComplete() { 1073 completeCount++; 1074 if ( completeCount != 2 ) { 1075 return; 1076 } 1077 // reset drag item 1078 item.element.classList.remove('is-positioning-post-drag'); 1079 item.hideDropPlaceholder(); 1080 _this.dispatchEvent( 'dragItemPositioned', null, [ item ] ); 1081 } 1082 1083 item.once( 'layout', onDragEndLayoutComplete ); 1084 this.once( 'layoutComplete', onDragEndLayoutComplete ); 1085 item.moveTo( item.rect.x, item.rect.y ); 1086 this.layout(); 1087 this.dragItemCount = Math.max( 0, this.dragItemCount - 1 ); 1088 this.sortItemsByPosition(); 1089 item.disablePlacing(); 1090 this.unstamp( item.element ); 1091}; 1092 1093/** 1094 * binds Draggabilly events 1095 * @param {Draggabilly} draggie 1096 */ 1097proto.bindDraggabillyEvents = function( draggie ) { 1098 this._bindDraggabillyEvents( draggie, 'on' ); 1099}; 1100 1101proto.unbindDraggabillyEvents = function( draggie ) { 1102 this._bindDraggabillyEvents( draggie, 'off' ); 1103}; 1104 1105proto._bindDraggabillyEvents = function( draggie, method ) { 1106 var handlers = this.handleDraggabilly; 1107 draggie[ method ]( 'dragStart', handlers.dragStart ); 1108 draggie[ method ]( 'dragMove', handlers.dragMove ); 1109 draggie[ method ]( 'dragEnd', handlers.dragEnd ); 1110}; 1111 1112/** 1113 * binds jQuery UI Draggable events 1114 * @param {jQuery} $elems 1115 */ 1116proto.bindUIDraggableEvents = function( $elems ) { 1117 this._bindUIDraggableEvents( $elems, 'on' ); 1118}; 1119 1120proto.unbindUIDraggableEvents = function( $elems ) { 1121 this._bindUIDraggableEvents( $elems, 'off' ); 1122}; 1123 1124proto._bindUIDraggableEvents = function( $elems, method ) { 1125 var handlers = this.handleUIDraggable; 1126 $elems 1127 [ method ]( 'dragstart', handlers.start ) 1128 [ method ]( 'drag', handlers.drag ) 1129 [ method ]( 'dragstop', handlers.stop ); 1130}; 1131 1132// ----- destroy ----- // 1133 1134var _destroy = proto.destroy; 1135proto.destroy = function() { 1136 _destroy.apply( this, arguments ); 1137 // disable flag; prevent drag events from triggering. #72 1138 this.isEnabled = false; 1139}; 1140 1141// ----- ----- // 1142 1143Packery.Rect = Rect; 1144Packery.Packer = Packer; 1145 1146return Packery; 1147 1148})); 1149 1150/*! 1151 * Packery layout mode v2.0.1 1152 * sub-classes Packery 1153 */ 1154 1155/*jshint browser: true, strict: true, undef: true, unused: true */ 1156 1157( function( window, factory ) { 1158 1159 // universal module definition 1160 if ( typeof define == 'function' && define.amd ) { 1161 // AMD 1162 define( [ 1163 'isotope-layout/js/layout-mode', 1164 'packery/js/packery' 1165 ], 1166 factory ); 1167 } else if ( typeof module == 'object' && module.exports ) { 1168 // CommonJS 1169 module.exports = factory( 1170 require('isotope-layout/js/layout-mode'), 1171 require('packery') 1172 ); 1173 } else { 1174 // browser global 1175 factory( 1176 window.Isotope.LayoutMode, 1177 window.Packery 1178 ); 1179 } 1180 1181}( window, function factor( LayoutMode, Packery ) { 1182 1183 1184 // create an Outlayer layout class 1185 var PackeryMode = LayoutMode.create('packery'); 1186 var proto = PackeryMode.prototype; 1187 1188 var keepModeMethods = { 1189 _getElementOffset: true, 1190 _getMeasurement: true 1191 }; 1192 1193 // inherit Packery prototype 1194 for ( var method in Packery.prototype ) { 1195 // do not inherit mode methods 1196 if ( !keepModeMethods[ method ] ) { 1197 proto[ method ] = Packery.prototype[ method ]; 1198 } 1199 } 1200 1201 // set packer in _resetLayout 1202 var _resetLayout = proto._resetLayout; 1203 proto._resetLayout = function() { 1204 this.packer = this.packer || new Packery.Packer(); 1205 this.shiftPacker = this.shiftPacker || new Packery.Packer(); 1206 _resetLayout.apply( this, arguments ); 1207 }; 1208 1209 var _getItemLayoutPosition = proto._getItemLayoutPosition; 1210 proto._getItemLayoutPosition = function( item ) { 1211 // set packery rect 1212 item.rect = item.rect || new Packery.Rect(); 1213 return _getItemLayoutPosition.call( this, item ); 1214 }; 1215 1216 // needsResizeLayout for vertical or horizontal 1217 var _needsResizeLayout = proto.needsResizeLayout; 1218 proto.needsResizeLayout = function() { 1219 if ( this._getOption('horizontal') ) { 1220 return this.needsVerticalResizeLayout(); 1221 } else { 1222 return _needsResizeLayout.call( this ); 1223 } 1224 }; 1225 1226 // point to mode options for horizontal 1227 var _getOption = proto._getOption; 1228 proto._getOption = function( option ) { 1229 if ( option == 'horizontal' ) { 1230 return this.options.isHorizontal !== undefined ? 1231 this.options.isHorizontal : this.options.horizontal; 1232 } 1233 return _getOption.apply( this.isotope, arguments ); 1234 }; 1235 1236 return PackeryMode; 1237 1238})); 1239
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.