1/*! 2 * angular-masonry 0.16.0 3 * Pascal Hartig, https://passy.me/ 4 * License: MIT 5 */ 6(function () { 7 'use strict'; 8 angular.module('wu.masonry', []).controller('MasonryCtrl', [ 9 '$scope', 10 '$element', 11 '$timeout', 12 function controller($scope, $element, $timeout) { 13 var bricks = {}; 14 var schedule = []; 15 var destroyed = false; 16 var self = this; 17 var timeout = null; 18 this.preserveOrder = false; 19 this.loadImages = true; 20 this.scheduleMasonryOnce = function scheduleMasonryOnce() { 21 var args = arguments; 22 var found = schedule.filter(function filterFn(item) { 23 return item[0] === args[0]; 24 }).length > 0; 25 if (!found) { 26 this.scheduleMasonry.apply(null, arguments); 27 } 28 }; 29 // Make sure it's only executed once within a reasonable time-frame in 30 // case multiple elements are removed or added at once. 31 this.scheduleMasonry = function scheduleMasonry() { 32 if (timeout) { 33 $timeout.cancel(timeout); 34 } 35 schedule.push([].slice.call(arguments)); 36 timeout = $timeout(function runMasonry() { 37 if (destroyed) { 38 return; 39 } 40 schedule.forEach(function scheduleForEach(args) { 41 $element.masonry.apply($element, args); 42 }); 43 schedule = []; 44 }, 50); 45 }; 46 function defaultLoaded($element) { 47 $element.addClass('loaded'); 48 } 49 this.addBrick = function addBrick(method, element, id) { 50 if (destroyed) { 51 return; 52 } 53 function _add() { 54 if (Object.keys(bricks).length === 0) { 55 $element.masonry('resize'); 56 } 57 if (bricks[id] === undefined) { 58 // Keep track of added elements. 59 bricks[id] = true; 60 defaultLoaded(element); 61 $element.masonry(method, element, true); 62 } 63 } 64 function _layout() { 65 // I wanted to make this dynamic but ran into huuuge memory leaks 66 // that I couldn't fix. If you know how to dynamically add a 67 // callback so one could say <masonry loaded="callback($element)"> 68 // please submit a pull request! 69 self.scheduleMasonryOnce('layout'); 70 } 71 if (!self.loadImages) { 72 _add(); 73 _layout(); 74 } else if (self.preserveOrder) { 75 _add(); 76 element.imagesLoaded(_layout); 77 } else { 78 element.imagesLoaded(function imagesLoaded() { 79 _add(); 80 _layout(); 81 }); 82 } 83 }; 84 this.removeBrick = function removeBrick(id, element) { 85 if (destroyed) { 86 return; 87 } 88 delete bricks[id]; 89 $element.masonry('remove', element); 90 this.scheduleMasonryOnce('layout'); 91 }; 92 this.destroy = function destroy() { 93 destroyed = true; 94 if ($element.data('masonry')) { 95 // Gently uninitialize if still present 96 $element.masonry('destroy'); 97 } 98 $scope.$emit('masonry.destroyed'); 99 bricks = {}; 100 }; 101 this.reload = function reload() { 102 $element.masonry(); 103 $scope.$emit('masonry.reloaded'); 104 }; 105 } 106 ]).directive('masonry', function masonryDirective() { 107 return { 108 restrict: 'AE', 109 controller: 'MasonryCtrl', 110 link: { 111 pre: function preLink(scope, element, attrs, ctrl) { 112 var attrOptions = scope.$eval(attrs.masonry || attrs.masonryOptions); 113 var options = angular.extend({ 114 itemSelector: attrs.itemSelector || '.masonry-brick', 115 columnWidth: parseInt(attrs.columnWidth, 10) || attrs.columnWidth 116 }, attrOptions || {}); 117 element.masonry(options); 118 scope.masonryContainer = element[0]; 119 var loadImages = scope.$eval(attrs.loadImages); 120 ctrl.loadImages = loadImages !== false; 121 var preserveOrder = scope.$eval(attrs.preserveOrder); 122 ctrl.preserveOrder = preserveOrder !== false && attrs.preserveOrder !== undefined; 123 var reloadOnShow = scope.$eval(attrs.reloadOnShow); 124 if (reloadOnShow !== false && attrs.reloadOnShow !== undefined) { 125 scope.$watch(function () { 126 return element.prop('offsetParent'); 127 }, function (isVisible, wasVisible) { 128 if (isVisible && !wasVisible) { 129 ctrl.reload(); 130 } 131 }); 132 } 133 var reloadOnResize = scope.$eval(attrs.reloadOnResize); 134 if (reloadOnResize !== false && attrs.reloadOnResize !== undefined) { 135 scope.$watch('masonryContainer.offsetWidth', function (newWidth, oldWidth) { 136 if (newWidth != oldWidth) { 137 ctrl.reload(); 138 } 139 }); 140 } 141 scope.$emit('masonry.created', element); 142 scope.$on('$destroy', ctrl.destroy); 143 } 144 } 145 }; 146 }).directive('masonryBrick', function masonryBrickDirective() { 147 return { 148 restrict: 'AC', 149 require: '^masonry', 150 scope: true, 151 link: { 152 pre: function preLink(scope, element, attrs, ctrl) { 153 var id = scope.$id, index; 154 var prependBrick = scope.$eval(attrs.prepend); 155 var method = prependBrick ? 'prepended' : 'appended'; 156 ctrl.addBrick(method, element, id); 157 element.on('$destroy', function () { 158 ctrl.removeBrick(id, element); 159 }); 160 scope.$on('masonry.reload', function () { 161 ctrl.scheduleMasonryOnce('reloadItems'); 162 ctrl.scheduleMasonryOnce('layout'); 163 }); 164 scope.$watch('$index', function () { 165 if (index !== undefined && index !== scope.$index) { 166 ctrl.scheduleMasonryOnce('reloadItems'); 167 ctrl.scheduleMasonryOnce('layout'); 168 } 169 index = scope.$index; 170 }); 171 } 172 } 173 }; 174 }); 175}());
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.