├── .gitignore ├── Gruntfile.js ├── LICENSE ├── README.md ├── bower.json ├── demo ├── app.js └── index.html ├── dist ├── angular-bricklayer.js └── angular-bricklayer.min.js ├── package.json └── src └── angular-bricklayer.js /.gitignore: -------------------------------------------------------------------------------- 1 | /bower_components 2 | /.idea 3 | /node_modules -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function(grunt) { 2 | 3 | var banner = '/**\n @name: <%= pkg.name %> \n @version: <%= pkg.version %> (<%= grunt.template.today("dd-mm-yyyy") %>) \n @author: <%= pkg.author %> \n @url: <%= pkg.homepage %> \n @license: <%= pkg.license %>\n*/\n'; 4 | 5 | var sources = [ 6 | 'node_modules/imagesloaded/imagesloaded.pkgd.js', 7 | 'src/angular-bricklayer.js' 8 | ]; 9 | 10 | grunt.initConfig({ 11 | pkg: grunt.file.readJSON('package.json'), 12 | uglify: { 13 | js: { 14 | files : { 15 | 'dist/angular-bricklayer.min.js' : sources 16 | } 17 | }, 18 | options: { 19 | banner: banner 20 | } 21 | }, 22 | concat: { 23 | options: { 24 | separator: ';', 25 | banner: banner 26 | }, 27 | dist: { 28 | src: sources, 29 | dest: 'dist/angular-bricklayer.js' 30 | } 31 | }, 32 | watch: { 33 | minifiyJs: { 34 | files: sources, 35 | tasks: ['uglify', 'concat'], 36 | options: { 37 | spawn: true 38 | } 39 | } 40 | } 41 | }); 42 | 43 | grunt.loadNpmTasks('grunt-contrib-concat'); 44 | grunt.loadNpmTasks('grunt-contrib-uglify'); 45 | grunt.loadNpmTasks('grunt-contrib-watch'); 46 | 47 | grunt.registerTask('default', ['watch']); 48 | 49 | }; 50 | 51 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Jonathan Hornung 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # angular-bricklayer 2 | AngularJS module for [ademilter's bricklayer](https://github.com/ademilter/bricklayer), a lightweight & independent cascading grid layout library 3 | 4 | [![npm version](https://badge.fury.io/js/angular-bricklayer.svg)](https://badge.fury.io/js/angular-bricklayer) 5 | [![Bower version](https://badge.fury.io/bo/angular-bricklayer.svg)](https://badge.fury.io/bo/angular-bricklayer) 6 | 7 | ## Demos 8 | - [Simple demo on GitHub](https://rawgit.com/JohnnyTheTank/angular-bricklayer/master/demo/index.html) 9 | - [Simple demo on Plnkr](http://plnkr.co/edit/mo3G36) 10 | - [Demo with images from flickr](https://rawgit.com/JohnnyTheTank/apiNG-design-bricklayer/master/demo/index.html) (made with [apiNG](https://github.com/JohnnyTheTank/apiNG)) 11 | 12 | [![Image](https://rawgit.com/ademilter/bricklayer/master/assets/screenshot.gif)](http://ademilter.github.io/bricklayer) 13 | 14 | ## Installation 15 | 16 | 1. Install via either [bower](http://bower.io/), [npm](https://www.npmjs.com/) or downloaded files: 17 | 1. via bower: `bower install --save angular-bricklayer` 18 | 2. via npm: `npm install --save angular-bricklayer` 19 | 3. via CDN (jsDelivr) 20 | 4. via [downloaded files](https://github.com/JohnnyTheTank/angular-bricklayer/zipball/master) 21 | 22 | 2. Include dependencies and angular-bricklayer in your HTML. 23 | 1. When using bower 24 | ```html 25 | 26 | 27 | 28 | ``` 29 | 2. When using npm 30 | ```html 31 | 32 | 33 | 34 | ``` 35 | 3. When using CDN 36 | ```html 37 | 38 | 39 | 40 | ``` 41 | 4. When using downloaded files 42 | ```html 43 | 44 | 45 | 46 | ``` 47 | 48 | 3. Add **`jtt_bricklayer`** to your application's module dependencies, like this: 49 | ```javascript 50 | angular.module('app', ['jtt_bricklayer']); 51 | ``` 52 | 53 | ## Usage 54 | Create a simple list and set the css class **`bricklayer`** like this 55 | 56 | ```html 57 |
58 |
Your item
59 |
Your another item
60 |
Your another but long item
61 |
Your another but very short item
62 |
Your one more item
63 |
Your smallest item
64 |
65 | ``` 66 | 67 | Define **bricklayer column size**: 68 | 69 | ```css 70 | @media screen and (min-width: 1200px) { 71 | .bricklayer-column-sizer { 72 | /* divide by 3. */ 73 | width: 33.3%; 74 | } 75 | } 76 | 77 | @media screen and (min-width: 768px) { 78 | .bricklayer-column-sizer { 79 | /* divide by 2. */ 80 | width: 50%; 81 | } 82 | } 83 | ``` 84 | 85 | ## Add bricks dynamically 86 | 87 | Use `bricklayer-append` or `bricklayer-prepend` as attribute, class or element name inside of your `bricklayer` instance 88 | 89 | ```html 90 |
91 | 92 |
93 | 94 | 95 |
96 |
97 | ``` 98 | 99 | ## Images 100 | Since `v1.1.0` the grid gets redrawn when images have been loaded, by including and using [desandro's imagesloaded](https://github.com/desandro/imagesloaded) 101 | 102 | # License 103 | MIT 104 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-bricklayer", 3 | "homepage": "https://github.com/JohnnyTheTank/angular-bricklayer", 4 | "authors": [ 5 | "Jonathan Hornung " 6 | ], 7 | "description": "AngularJS module for bricklayer, a lightweight & independent cascading grid layout library", 8 | "main": "dist/angular-bricklayer.js", 9 | "version": "1.1.0", 10 | "moduleType": [], 11 | "keywords": [ 12 | "angular", 13 | "angularjs", 14 | "grid", 15 | "bricklayer", 16 | "masonry" 17 | ], 18 | "ignore": [ 19 | "**/.*", 20 | "src", 21 | "node_modules", 22 | "bower_components", 23 | "test", 24 | "tests", 25 | "demo" 26 | ], 27 | "license": "MIT", 28 | "devDependencies": { 29 | "angular": "^1.5.5" 30 | }, 31 | "dependencies": { 32 | "bricklayer": "^0.4.1", 33 | "imagesloaded": "^4.1.0" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /demo/app.js: -------------------------------------------------------------------------------- 1 | angular.module('app', ['jtt_bricklayer']); 2 | 3 | angular.module('app') 4 | .controller("appController", function ($scope) { 5 | $scope.createElement = function () { 6 | return { 7 | color: '#' + Math.random().toString(16).substr(-6), 8 | height: sizes[Math.floor(Math.random() * sizes.length)], 9 | width: sizes[Math.floor(Math.random() * sizes.length)], 10 | } 11 | }; 12 | 13 | $scope.data = []; 14 | 15 | $scope.appendNew = function () { 16 | $scope.data.push($scope.createElement()); 17 | }; 18 | 19 | var sizes = [220, 250, 260, 270, 290, 300, 310, 330, 400, 430, 450, 480, 500]; 20 | 21 | for (var i = 0; i < 10; i++) { 22 | $scope.appendNew(); 23 | } 24 | 25 | }); -------------------------------------------------------------------------------- /demo/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | angular-bricklayer 10 | 11 | 12 | 13 | 14 | 15 | 20 | 21 | 22 | 23 | 24 | 25 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 |
68 |
69 | 70 | 71 |
72 |
73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /dist/angular-bricklayer.js: -------------------------------------------------------------------------------- 1 | /** 2 | @name: angular-bricklayer 3 | @version: 1.1.0 (25-04-2016) 4 | @author: 5 | @url: https://github.com/JohnnyTheTank/angular-bricklayer 6 | @license: MIT 7 | */ 8 | /*! 9 | * imagesLoaded PACKAGED v4.1.0 10 | * JavaScript is all like "You images are done yet or what?" 11 | * MIT License 12 | */ 13 | 14 | /** 15 | * EvEmitter v1.0.1 16 | * Lil' event emitter 17 | * MIT License 18 | */ 19 | 20 | /* jshint unused: true, undef: true, strict: true */ 21 | 22 | ( function( global, factory ) { 23 | // universal module definition 24 | /* jshint strict: false */ /* globals define, module */ 25 | if ( typeof define == 'function' && define.amd ) { 26 | // AMD - RequireJS 27 | define( 'ev-emitter/ev-emitter',factory ); 28 | } else if ( typeof module == 'object' && module.exports ) { 29 | // CommonJS - Browserify, Webpack 30 | module.exports = factory(); 31 | } else { 32 | // Browser globals 33 | global.EvEmitter = factory(); 34 | } 35 | 36 | }( this, function() { 37 | 38 | 39 | 40 | function EvEmitter() {} 41 | 42 | var proto = EvEmitter.prototype; 43 | 44 | proto.on = function( eventName, listener ) { 45 | if ( !eventName || !listener ) { 46 | return; 47 | } 48 | // set events hash 49 | var events = this._events = this._events || {}; 50 | // set listeners array 51 | var listeners = events[ eventName ] = events[ eventName ] || []; 52 | // only add once 53 | if ( listeners.indexOf( listener ) == -1 ) { 54 | listeners.push( listener ); 55 | } 56 | 57 | return this; 58 | }; 59 | 60 | proto.once = function( eventName, listener ) { 61 | if ( !eventName || !listener ) { 62 | return; 63 | } 64 | // add event 65 | this.on( eventName, listener ); 66 | // set once flag 67 | // set onceEvents hash 68 | var onceEvents = this._onceEvents = this._onceEvents || {}; 69 | // set onceListeners array 70 | var onceListeners = onceEvents[ eventName ] = onceEvents[ eventName ] || []; 71 | // set flag 72 | onceListeners[ listener ] = true; 73 | 74 | return this; 75 | }; 76 | 77 | proto.off = function( eventName, listener ) { 78 | var listeners = this._events && this._events[ eventName ]; 79 | if ( !listeners || !listeners.length ) { 80 | return; 81 | } 82 | var index = listeners.indexOf( listener ); 83 | if ( index != -1 ) { 84 | listeners.splice( index, 1 ); 85 | } 86 | 87 | return this; 88 | }; 89 | 90 | proto.emitEvent = function( eventName, args ) { 91 | var listeners = this._events && this._events[ eventName ]; 92 | if ( !listeners || !listeners.length ) { 93 | return; 94 | } 95 | var i = 0; 96 | var listener = listeners[i]; 97 | args = args || []; 98 | // once stuff 99 | var onceListeners = this._onceEvents && this._onceEvents[ eventName ]; 100 | 101 | while ( listener ) { 102 | var isOnce = onceListeners && onceListeners[ listener ]; 103 | if ( isOnce ) { 104 | // remove listener 105 | // remove before trigger to prevent recursion 106 | this.off( eventName, listener ); 107 | // unset once flag 108 | delete onceListeners[ listener ]; 109 | } 110 | // trigger listener 111 | listener.apply( this, args ); 112 | // get next listener 113 | i += isOnce ? 0 : 1; 114 | listener = listeners[i]; 115 | } 116 | 117 | return this; 118 | }; 119 | 120 | return EvEmitter; 121 | 122 | })); 123 | 124 | /*! 125 | * imagesLoaded v4.1.0 126 | * JavaScript is all like "You images are done yet or what?" 127 | * MIT License 128 | */ 129 | 130 | ( function( window, factory ) { 'use strict'; 131 | // universal module definition 132 | 133 | /*global define: false, module: false, require: false */ 134 | 135 | if ( typeof define == 'function' && define.amd ) { 136 | // AMD 137 | define( [ 138 | 'ev-emitter/ev-emitter' 139 | ], function( EvEmitter ) { 140 | return factory( window, EvEmitter ); 141 | }); 142 | } else if ( typeof module == 'object' && module.exports ) { 143 | // CommonJS 144 | module.exports = factory( 145 | window, 146 | require('ev-emitter') 147 | ); 148 | } else { 149 | // browser global 150 | window.imagesLoaded = factory( 151 | window, 152 | window.EvEmitter 153 | ); 154 | } 155 | 156 | })( window, 157 | 158 | // -------------------------- factory -------------------------- // 159 | 160 | function factory( window, EvEmitter ) { 161 | 162 | 163 | 164 | var $ = window.jQuery; 165 | var console = window.console; 166 | 167 | // -------------------------- helpers -------------------------- // 168 | 169 | // extend objects 170 | function extend( a, b ) { 171 | for ( var prop in b ) { 172 | a[ prop ] = b[ prop ]; 173 | } 174 | return a; 175 | } 176 | 177 | // turn element or nodeList into an array 178 | function makeArray( obj ) { 179 | var ary = []; 180 | if ( Array.isArray( obj ) ) { 181 | // use object if already an array 182 | ary = obj; 183 | } else if ( typeof obj.length == 'number' ) { 184 | // convert nodeList to array 185 | for ( var i=0; i < obj.length; i++ ) { 186 | ary.push( obj[i] ); 187 | } 188 | } else { 189 | // array of single index 190 | ary.push( obj ); 191 | } 192 | return ary; 193 | } 194 | 195 | // -------------------------- imagesLoaded -------------------------- // 196 | 197 | /** 198 | * @param {Array, Element, NodeList, String} elem 199 | * @param {Object or Function} options - if function, use as callback 200 | * @param {Function} onAlways - callback function 201 | */ 202 | function ImagesLoaded( elem, options, onAlways ) { 203 | // coerce ImagesLoaded() without new, to be new ImagesLoaded() 204 | if ( !( this instanceof ImagesLoaded ) ) { 205 | return new ImagesLoaded( elem, options, onAlways ); 206 | } 207 | // use elem as selector string 208 | if ( typeof elem == 'string' ) { 209 | elem = document.querySelectorAll( elem ); 210 | } 211 | 212 | this.elements = makeArray( elem ); 213 | this.options = extend( {}, this.options ); 214 | 215 | if ( typeof options == 'function' ) { 216 | onAlways = options; 217 | } else { 218 | extend( this.options, options ); 219 | } 220 | 221 | if ( onAlways ) { 222 | this.on( 'always', onAlways ); 223 | } 224 | 225 | this.getImages(); 226 | 227 | if ( $ ) { 228 | // add jQuery Deferred object 229 | this.jqDeferred = new $.Deferred(); 230 | } 231 | 232 | // HACK check async to allow time to bind listeners 233 | setTimeout( function() { 234 | this.check(); 235 | }.bind( this )); 236 | } 237 | 238 | ImagesLoaded.prototype = Object.create( EvEmitter.prototype ); 239 | 240 | ImagesLoaded.prototype.options = {}; 241 | 242 | ImagesLoaded.prototype.getImages = function() { 243 | this.images = []; 244 | 245 | // filter & find items if we have an item selector 246 | this.elements.forEach( this.addElementImages, this ); 247 | }; 248 | 249 | /** 250 | * @param {Node} element 251 | */ 252 | ImagesLoaded.prototype.addElementImages = function( elem ) { 253 | // filter siblings 254 | if ( elem.nodeName == 'IMG' ) { 255 | this.addImage( elem ); 256 | } 257 | // get background image on element 258 | if ( this.options.background === true ) { 259 | this.addElementBackgroundImages( elem ); 260 | } 261 | 262 | // find children 263 | // no non-element nodes, #143 264 | var nodeType = elem.nodeType; 265 | if ( !nodeType || !elementNodeTypes[ nodeType ] ) { 266 | return; 267 | } 268 | var childImgs = elem.querySelectorAll('img'); 269 | // concat childElems to filterFound array 270 | for ( var i=0; i < childImgs.length; i++ ) { 271 | var img = childImgs[i]; 272 | this.addImage( img ); 273 | } 274 | 275 | // get child background images 276 | if ( typeof this.options.background == 'string' ) { 277 | var children = elem.querySelectorAll( this.options.background ); 278 | for ( i=0; i < children.length; i++ ) { 279 | var child = children[i]; 280 | this.addElementBackgroundImages( child ); 281 | } 282 | } 283 | }; 284 | 285 | var elementNodeTypes = { 286 | 1: true, 287 | 9: true, 288 | 11: true 289 | }; 290 | 291 | ImagesLoaded.prototype.addElementBackgroundImages = function( elem ) { 292 | var style = getComputedStyle( elem ); 293 | if ( !style ) { 294 | // Firefox returns null if in a hidden iframe https://bugzil.la/548397 295 | return; 296 | } 297 | // get url inside url("...") 298 | var reURL = /url\((['"])?(.*?)\1\)/gi; 299 | var matches = reURL.exec( style.backgroundImage ); 300 | while ( matches !== null ) { 301 | var url = matches && matches[2]; 302 | if ( url ) { 303 | this.addBackground( url, elem ); 304 | } 305 | matches = reURL.exec( style.backgroundImage ); 306 | } 307 | }; 308 | 309 | /** 310 | * @param {Image} img 311 | */ 312 | ImagesLoaded.prototype.addImage = function( img ) { 313 | var loadingImage = new LoadingImage( img ); 314 | this.images.push( loadingImage ); 315 | }; 316 | 317 | ImagesLoaded.prototype.addBackground = function( url, elem ) { 318 | var background = new Background( url, elem ); 319 | this.images.push( background ); 320 | }; 321 | 322 | ImagesLoaded.prototype.check = function() { 323 | var _this = this; 324 | this.progressedCount = 0; 325 | this.hasAnyBroken = false; 326 | // complete if no images 327 | if ( !this.images.length ) { 328 | this.complete(); 329 | return; 330 | } 331 | 332 | function onProgress( image, elem, message ) { 333 | // HACK - Chrome triggers event before object properties have changed. #83 334 | setTimeout( function() { 335 | _this.progress( image, elem, message ); 336 | }); 337 | } 338 | 339 | this.images.forEach( function( loadingImage ) { 340 | loadingImage.once( 'progress', onProgress ); 341 | loadingImage.check(); 342 | }); 343 | }; 344 | 345 | ImagesLoaded.prototype.progress = function( image, elem, message ) { 346 | this.progressedCount++; 347 | this.hasAnyBroken = this.hasAnyBroken || !image.isLoaded; 348 | // progress event 349 | this.emitEvent( 'progress', [ this, image, elem ] ); 350 | if ( this.jqDeferred && this.jqDeferred.notify ) { 351 | this.jqDeferred.notify( this, image ); 352 | } 353 | // check if completed 354 | if ( this.progressedCount == this.images.length ) { 355 | this.complete(); 356 | } 357 | 358 | if ( this.options.debug && console ) { 359 | console.log( 'progress: ' + message, image, elem ); 360 | } 361 | }; 362 | 363 | ImagesLoaded.prototype.complete = function() { 364 | var eventName = this.hasAnyBroken ? 'fail' : 'done'; 365 | this.isComplete = true; 366 | this.emitEvent( eventName, [ this ] ); 367 | this.emitEvent( 'always', [ this ] ); 368 | if ( this.jqDeferred ) { 369 | var jqMethod = this.hasAnyBroken ? 'reject' : 'resolve'; 370 | this.jqDeferred[ jqMethod ]( this ); 371 | } 372 | }; 373 | 374 | // -------------------------- -------------------------- // 375 | 376 | function LoadingImage( img ) { 377 | this.img = img; 378 | } 379 | 380 | LoadingImage.prototype = Object.create( EvEmitter.prototype ); 381 | 382 | LoadingImage.prototype.check = function() { 383 | // If complete is true and browser supports natural sizes, 384 | // try to check for image status manually. 385 | var isComplete = this.getIsImageComplete(); 386 | if ( isComplete ) { 387 | // report based on naturalWidth 388 | this.confirm( this.img.naturalWidth !== 0, 'naturalWidth' ); 389 | return; 390 | } 391 | 392 | // If none of the checks above matched, simulate loading on detached element. 393 | this.proxyImage = new Image(); 394 | this.proxyImage.addEventListener( 'load', this ); 395 | this.proxyImage.addEventListener( 'error', this ); 396 | // bind to image as well for Firefox. #191 397 | this.img.addEventListener( 'load', this ); 398 | this.img.addEventListener( 'error', this ); 399 | this.proxyImage.src = this.img.src; 400 | }; 401 | 402 | LoadingImage.prototype.getIsImageComplete = function() { 403 | return this.img.complete && this.img.naturalWidth !== undefined; 404 | }; 405 | 406 | LoadingImage.prototype.confirm = function( isLoaded, message ) { 407 | this.isLoaded = isLoaded; 408 | this.emitEvent( 'progress', [ this, this.img, message ] ); 409 | }; 410 | 411 | // ----- events ----- // 412 | 413 | // trigger specified handler for event type 414 | LoadingImage.prototype.handleEvent = function( event ) { 415 | var method = 'on' + event.type; 416 | if ( this[ method ] ) { 417 | this[ method ]( event ); 418 | } 419 | }; 420 | 421 | LoadingImage.prototype.onload = function() { 422 | this.confirm( true, 'onload' ); 423 | this.unbindEvents(); 424 | }; 425 | 426 | LoadingImage.prototype.onerror = function() { 427 | this.confirm( false, 'onerror' ); 428 | this.unbindEvents(); 429 | }; 430 | 431 | LoadingImage.prototype.unbindEvents = function() { 432 | this.proxyImage.removeEventListener( 'load', this ); 433 | this.proxyImage.removeEventListener( 'error', this ); 434 | this.img.removeEventListener( 'load', this ); 435 | this.img.removeEventListener( 'error', this ); 436 | }; 437 | 438 | // -------------------------- Background -------------------------- // 439 | 440 | function Background( url, element ) { 441 | this.url = url; 442 | this.element = element; 443 | this.img = new Image(); 444 | } 445 | 446 | // inherit LoadingImage prototype 447 | Background.prototype = Object.create( LoadingImage.prototype ); 448 | 449 | Background.prototype.check = function() { 450 | this.img.addEventListener( 'load', this ); 451 | this.img.addEventListener( 'error', this ); 452 | this.img.src = this.url; 453 | // check if image is already complete 454 | var isComplete = this.getIsImageComplete(); 455 | if ( isComplete ) { 456 | this.confirm( this.img.naturalWidth !== 0, 'naturalWidth' ); 457 | this.unbindEvents(); 458 | } 459 | }; 460 | 461 | Background.prototype.unbindEvents = function() { 462 | this.img.removeEventListener( 'load', this ); 463 | this.img.removeEventListener( 'error', this ); 464 | }; 465 | 466 | Background.prototype.confirm = function( isLoaded, message ) { 467 | this.isLoaded = isLoaded; 468 | this.emitEvent( 'progress', [ this, this.element, message ] ); 469 | }; 470 | 471 | // -------------------------- jQuery -------------------------- // 472 | 473 | ImagesLoaded.makeJQueryPlugin = function( jQuery ) { 474 | jQuery = jQuery || window.jQuery; 475 | if ( !jQuery ) { 476 | return; 477 | } 478 | // set local variable 479 | $ = jQuery; 480 | // $().imagesLoaded() 481 | $.fn.imagesLoaded = function( options, callback ) { 482 | var instance = new ImagesLoaded( this, options, callback ); 483 | return instance.jqDeferred.promise( $(this) ); 484 | }; 485 | }; 486 | // try making plugin 487 | ImagesLoaded.makeJQueryPlugin(); 488 | 489 | // -------------------------- -------------------------- // 490 | 491 | return ImagesLoaded; 492 | 493 | }); 494 | 495 | ;angular.module('jtt_bricklayer', []) 496 | .directive('bricklayer', ['$timeout', function ($timeout) { 497 | return { 498 | restrict: 'C', 499 | link: function (scope, element, attrs) { 500 | var bricklayer = new Bricklayer(element[0]); 501 | 502 | imagesLoaded(element[0], function () { 503 | bricklayer.redraw(); 504 | }); 505 | 506 | $timeout(function () { 507 | bricklayer.redraw(); 508 | }); 509 | 510 | scope.$on('bricklayer.append', function (event, selectedElement) { 511 | bricklayer.append(selectedElement[0]); 512 | bricklayer.redraw(); 513 | imagesLoaded(selectedElement, function () { 514 | bricklayer.redraw(); 515 | }); 516 | }); 517 | 518 | scope.$on('bricklayer.prepend', function (event, selectedElement) { 519 | bricklayer.prepend(selectedElement[0]); 520 | bricklayer.redraw(); 521 | imagesLoaded(selectedElement, function () { 522 | bricklayer.redraw(); 523 | }); 524 | }); 525 | 526 | scope.$on('bricklayer.redraw', function () { 527 | bricklayer.redraw(); 528 | }); 529 | }, 530 | controller: function () { 531 | } 532 | } 533 | }]) 534 | .directive('bricklayerAppend', function () { 535 | return { 536 | require: '^^bricklayer', 537 | restrict: 'ACE', 538 | link: function (scope, element, attrs) { 539 | scope.$emit('bricklayer.append', element); 540 | } 541 | } 542 | }) 543 | .directive('bricklayerPrepend', function () { 544 | return { 545 | require: '^^bricklayer', 546 | restrict: 'ACE', 547 | link: function (scope, element, attrs) { 548 | scope.$emit('bricklayer.prepend', element); 549 | } 550 | } 551 | }); -------------------------------------------------------------------------------- /dist/angular-bricklayer.min.js: -------------------------------------------------------------------------------- 1 | /** 2 | @name: angular-bricklayer 3 | @version: 1.1.0 (25-04-2016) 4 | @author: 5 | @url: https://github.com/JohnnyTheTank/angular-bricklayer 6 | @license: MIT 7 | */ 8 | !function(a,b){"function"==typeof define&&define.amd?define("ev-emitter/ev-emitter",b):"object"==typeof module&&module.exports?module.exports=b():a.EvEmitter=b()}(this,function(){function a(){}var b=a.prototype;return b.on=function(a,b){if(a&&b){var c=this._events=this._events||{},d=c[a]=c[a]||[];return-1==d.indexOf(b)&&d.push(b),this}},b.once=function(a,b){if(a&&b){this.on(a,b);var c=this._onceEvents=this._onceEvents||{},d=c[a]=c[a]||[];return d[b]=!0,this}},b.off=function(a,b){var c=this._events&&this._events[a];if(c&&c.length){var d=c.indexOf(b);return-1!=d&&c.splice(d,1),this}},b.emitEvent=function(a,b){var c=this._events&&this._events[a];if(c&&c.length){var d=0,e=c[d];b=b||[];for(var f=this._onceEvents&&this._onceEvents[a];e;){var g=f&&f[e];g&&(this.off(a,e),delete f[e]),e.apply(this,b),d+=g?0:1,e=c[d]}return this}},a}),function(a,b){"use strict";"function"==typeof define&&define.amd?define(["ev-emitter/ev-emitter"],function(c){return b(a,c)}):"object"==typeof module&&module.exports?module.exports=b(a,require("ev-emitter")):a.imagesLoaded=b(a,a.EvEmitter)}(window,function(a,b){function c(a,b){for(var c in b)a[c]=b[c];return a}function d(a){var b=[];if(Array.isArray(a))b=a;else if("number"==typeof a.length)for(var c=0;c" 6 | ], 7 | "description": "AngularJS module for bricklayer, a lightweight & independent cascading grid layout library", 8 | "main": "dist/angular-bricklayer.js", 9 | "keywords": [ 10 | "angular", 11 | "angularjs", 12 | "grid", 13 | "bricklayer", 14 | "masonry" 15 | ], 16 | "scripts": { 17 | "test": "echo \"Error: no test specified\" && exit 1" 18 | }, 19 | "repository": { 20 | "type": "git", 21 | "url": "git+https://github.com/JohnnyTheTank/angular-bricklayer.git" 22 | }, 23 | "author": "", 24 | "license": "MIT", 25 | "bugs": { 26 | "url": "https://github.com/JohnnyTheTank/angular-bricklayer/issues" 27 | }, 28 | "homepage": "https://github.com/JohnnyTheTank/angular-bricklayer", 29 | "devDependencies": { 30 | "angular": "^1.5.5", 31 | "grunt": "^0.4.5", 32 | "grunt-contrib-concat": "^0.5.1", 33 | "grunt-contrib-uglify": "^0.11.0", 34 | "grunt-contrib-watch": "^0.6.1" 35 | }, 36 | "dependencies": { 37 | "bricklayer": "^0.4.1", 38 | "imagesloaded": "^4.1.0" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/angular-bricklayer.js: -------------------------------------------------------------------------------- 1 | angular.module('jtt_bricklayer', []) 2 | .directive('bricklayer', ['$timeout', function ($timeout) { 3 | return { 4 | restrict: 'C', 5 | link: function (scope, element, attrs) { 6 | var bricklayer = new Bricklayer(element[0]); 7 | 8 | imagesLoaded(element[0], function () { 9 | bricklayer.redraw(); 10 | }); 11 | 12 | $timeout(function () { 13 | bricklayer.redraw(); 14 | }); 15 | 16 | scope.$on('bricklayer.append', function (event, selectedElement) { 17 | bricklayer.append(selectedElement[0]); 18 | bricklayer.redraw(); 19 | imagesLoaded(selectedElement, function () { 20 | bricklayer.redraw(); 21 | }); 22 | }); 23 | 24 | scope.$on('bricklayer.prepend', function (event, selectedElement) { 25 | bricklayer.prepend(selectedElement[0]); 26 | bricklayer.redraw(); 27 | imagesLoaded(selectedElement, function () { 28 | bricklayer.redraw(); 29 | }); 30 | }); 31 | 32 | scope.$on('bricklayer.redraw', function () { 33 | bricklayer.redraw(); 34 | }); 35 | }, 36 | controller: function () { 37 | } 38 | } 39 | }]) 40 | .directive('bricklayerAppend', function () { 41 | return { 42 | require: '^^bricklayer', 43 | restrict: 'ACE', 44 | link: function (scope, element, attrs) { 45 | scope.$emit('bricklayer.append', element); 46 | } 47 | } 48 | }) 49 | .directive('bricklayerPrepend', function () { 50 | return { 51 | require: '^^bricklayer', 52 | restrict: 'ACE', 53 | link: function (scope, element, attrs) { 54 | scope.$emit('bricklayer.prepend', element); 55 | } 56 | } 57 | }); --------------------------------------------------------------------------------