From 619d9ba64ae8d874ef5a1b926f5a99a14ab38842 Mon Sep 17 00:00:00 2001 From: Jonathan Hornung Date: Mon, 25 Apr 2016 10:57:39 +0200 Subject: [PATCH] bump version --- README.md | 2 +- bower.json | 2 +- demo/app.js | 1 - dist/angular-bricklayer.js | 519 ++++++++++++++++++++++++++++++++- dist/angular-bricklayer.min.js | 4 +- package.json | 2 +- src/angular-bricklayer.js | 2 +- 7 files changed, 515 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index a23008f..2e9415e 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ AngularJS module for [ademilter's bricklayer](https://github.com/ademilter/brick ```html - + ``` 4. When using downloaded files ```html diff --git a/bower.json b/bower.json index 129359c..0428451 100644 --- a/bower.json +++ b/bower.json @@ -6,7 +6,7 @@ ], "description": "AngularJS module for bricklayer, a lightweight & independent cascading grid layout library", "main": "dist/angular-bricklayer.js", - "version": "1.0.2", + "version": "1.1.0", "moduleType": [], "keywords": [ "angular", diff --git a/demo/app.js b/demo/app.js index 2f8b98d..ad4f40b 100644 --- a/demo/app.js +++ b/demo/app.js @@ -22,5 +22,4 @@ angular.module('app') $scope.appendNew(); } - }); \ No newline at end of file diff --git a/dist/angular-bricklayer.js b/dist/angular-bricklayer.js index df0be96..1bd88b2 100644 --- a/dist/angular-bricklayer.js +++ b/dist/angular-bricklayer.js @@ -1,52 +1,551 @@ /** @name: angular-bricklayer - @version: 1.0.2 (24-04-2016) + @version: 1.1.0 (25-04-2016) @author: @url: https://github.com/JohnnyTheTank/angular-bricklayer @license: MIT */ -angular.module('jtt_bricklayer', []) +/*! + * imagesLoaded PACKAGED v4.1.0 + * JavaScript is all like "You images are done yet or what?" + * MIT License + */ + +/** + * EvEmitter v1.0.1 + * Lil' event emitter + * MIT License + */ + +/* jshint unused: true, undef: true, strict: true */ + +( function( global, factory ) { + // universal module definition + /* jshint strict: false */ /* globals define, module */ + if ( typeof define == 'function' && define.amd ) { + // AMD - RequireJS + define( 'ev-emitter/ev-emitter',factory ); + } else if ( typeof module == 'object' && module.exports ) { + // CommonJS - Browserify, Webpack + module.exports = factory(); + } else { + // Browser globals + global.EvEmitter = factory(); + } + +}( this, function() { + + + +function EvEmitter() {} + +var proto = EvEmitter.prototype; + +proto.on = function( eventName, listener ) { + if ( !eventName || !listener ) { + return; + } + // set events hash + var events = this._events = this._events || {}; + // set listeners array + var listeners = events[ eventName ] = events[ eventName ] || []; + // only add once + if ( listeners.indexOf( listener ) == -1 ) { + listeners.push( listener ); + } + + return this; +}; + +proto.once = function( eventName, listener ) { + if ( !eventName || !listener ) { + return; + } + // add event + this.on( eventName, listener ); + // set once flag + // set onceEvents hash + var onceEvents = this._onceEvents = this._onceEvents || {}; + // set onceListeners array + var onceListeners = onceEvents[ eventName ] = onceEvents[ eventName ] || []; + // set flag + onceListeners[ listener ] = true; + + return this; +}; + +proto.off = function( eventName, listener ) { + var listeners = this._events && this._events[ eventName ]; + if ( !listeners || !listeners.length ) { + return; + } + var index = listeners.indexOf( listener ); + if ( index != -1 ) { + listeners.splice( index, 1 ); + } + + return this; +}; + +proto.emitEvent = function( eventName, args ) { + var listeners = this._events && this._events[ eventName ]; + if ( !listeners || !listeners.length ) { + return; + } + var i = 0; + var listener = listeners[i]; + args = args || []; + // once stuff + var onceListeners = this._onceEvents && this._onceEvents[ eventName ]; + + while ( listener ) { + var isOnce = onceListeners && onceListeners[ listener ]; + if ( isOnce ) { + // remove listener + // remove before trigger to prevent recursion + this.off( eventName, listener ); + // unset once flag + delete onceListeners[ listener ]; + } + // trigger listener + listener.apply( this, args ); + // get next listener + i += isOnce ? 0 : 1; + listener = listeners[i]; + } + + return this; +}; + +return EvEmitter; + +})); + +/*! + * imagesLoaded v4.1.0 + * JavaScript is all like "You images are done yet or what?" + * MIT License + */ + +( function( window, factory ) { 'use strict'; + // universal module definition + + /*global define: false, module: false, require: false */ + + if ( typeof define == 'function' && define.amd ) { + // AMD + define( [ + 'ev-emitter/ev-emitter' + ], function( EvEmitter ) { + return factory( window, EvEmitter ); + }); + } else if ( typeof module == 'object' && module.exports ) { + // CommonJS + module.exports = factory( + window, + require('ev-emitter') + ); + } else { + // browser global + window.imagesLoaded = factory( + window, + window.EvEmitter + ); + } + +})( window, + +// -------------------------- factory -------------------------- // + +function factory( window, EvEmitter ) { + + + +var $ = window.jQuery; +var console = window.console; + +// -------------------------- helpers -------------------------- // + +// extend objects +function extend( a, b ) { + for ( var prop in b ) { + a[ prop ] = b[ prop ]; + } + return a; +} + +// turn element or nodeList into an array +function makeArray( obj ) { + var ary = []; + if ( Array.isArray( obj ) ) { + // use object if already an array + ary = obj; + } else if ( typeof obj.length == 'number' ) { + // convert nodeList to array + for ( var i=0; i < obj.length; i++ ) { + ary.push( obj[i] ); + } + } else { + // array of single index + ary.push( obj ); + } + return ary; +} + +// -------------------------- imagesLoaded -------------------------- // + +/** + * @param {Array, Element, NodeList, String} elem + * @param {Object or Function} options - if function, use as callback + * @param {Function} onAlways - callback function + */ +function ImagesLoaded( elem, options, onAlways ) { + // coerce ImagesLoaded() without new, to be new ImagesLoaded() + if ( !( this instanceof ImagesLoaded ) ) { + return new ImagesLoaded( elem, options, onAlways ); + } + // use elem as selector string + if ( typeof elem == 'string' ) { + elem = document.querySelectorAll( elem ); + } + + this.elements = makeArray( elem ); + this.options = extend( {}, this.options ); + + if ( typeof options == 'function' ) { + onAlways = options; + } else { + extend( this.options, options ); + } + + if ( onAlways ) { + this.on( 'always', onAlways ); + } + + this.getImages(); + + if ( $ ) { + // add jQuery Deferred object + this.jqDeferred = new $.Deferred(); + } + + // HACK check async to allow time to bind listeners + setTimeout( function() { + this.check(); + }.bind( this )); +} + +ImagesLoaded.prototype = Object.create( EvEmitter.prototype ); + +ImagesLoaded.prototype.options = {}; + +ImagesLoaded.prototype.getImages = function() { + this.images = []; + + // filter & find items if we have an item selector + this.elements.forEach( this.addElementImages, this ); +}; + +/** + * @param {Node} element + */ +ImagesLoaded.prototype.addElementImages = function( elem ) { + // filter siblings + if ( elem.nodeName == 'IMG' ) { + this.addImage( elem ); + } + // get background image on element + if ( this.options.background === true ) { + this.addElementBackgroundImages( elem ); + } + + // find children + // no non-element nodes, #143 + var nodeType = elem.nodeType; + if ( !nodeType || !elementNodeTypes[ nodeType ] ) { + return; + } + var childImgs = elem.querySelectorAll('img'); + // concat childElems to filterFound array + for ( var i=0; i < childImgs.length; i++ ) { + var img = childImgs[i]; + this.addImage( img ); + } + + // get child background images + if ( typeof this.options.background == 'string' ) { + var children = elem.querySelectorAll( this.options.background ); + for ( i=0; i < children.length; i++ ) { + var child = children[i]; + this.addElementBackgroundImages( child ); + } + } +}; + +var elementNodeTypes = { + 1: true, + 9: true, + 11: true +}; + +ImagesLoaded.prototype.addElementBackgroundImages = function( elem ) { + var style = getComputedStyle( elem ); + if ( !style ) { + // Firefox returns null if in a hidden iframe https://bugzil.la/548397 + return; + } + // get url inside url("...") + var reURL = /url\((['"])?(.*?)\1\)/gi; + var matches = reURL.exec( style.backgroundImage ); + while ( matches !== null ) { + var url = matches && matches[2]; + if ( url ) { + this.addBackground( url, elem ); + } + matches = reURL.exec( style.backgroundImage ); + } +}; + +/** + * @param {Image} img + */ +ImagesLoaded.prototype.addImage = function( img ) { + var loadingImage = new LoadingImage( img ); + this.images.push( loadingImage ); +}; + +ImagesLoaded.prototype.addBackground = function( url, elem ) { + var background = new Background( url, elem ); + this.images.push( background ); +}; + +ImagesLoaded.prototype.check = function() { + var _this = this; + this.progressedCount = 0; + this.hasAnyBroken = false; + // complete if no images + if ( !this.images.length ) { + this.complete(); + return; + } + + function onProgress( image, elem, message ) { + // HACK - Chrome triggers event before object properties have changed. #83 + setTimeout( function() { + _this.progress( image, elem, message ); + }); + } + + this.images.forEach( function( loadingImage ) { + loadingImage.once( 'progress', onProgress ); + loadingImage.check(); + }); +}; + +ImagesLoaded.prototype.progress = function( image, elem, message ) { + this.progressedCount++; + this.hasAnyBroken = this.hasAnyBroken || !image.isLoaded; + // progress event + this.emitEvent( 'progress', [ this, image, elem ] ); + if ( this.jqDeferred && this.jqDeferred.notify ) { + this.jqDeferred.notify( this, image ); + } + // check if completed + if ( this.progressedCount == this.images.length ) { + this.complete(); + } + + if ( this.options.debug && console ) { + console.log( 'progress: ' + message, image, elem ); + } +}; + +ImagesLoaded.prototype.complete = function() { + var eventName = this.hasAnyBroken ? 'fail' : 'done'; + this.isComplete = true; + this.emitEvent( eventName, [ this ] ); + this.emitEvent( 'always', [ this ] ); + if ( this.jqDeferred ) { + var jqMethod = this.hasAnyBroken ? 'reject' : 'resolve'; + this.jqDeferred[ jqMethod ]( this ); + } +}; + +// -------------------------- -------------------------- // + +function LoadingImage( img ) { + this.img = img; +} + +LoadingImage.prototype = Object.create( EvEmitter.prototype ); + +LoadingImage.prototype.check = function() { + // If complete is true and browser supports natural sizes, + // try to check for image status manually. + var isComplete = this.getIsImageComplete(); + if ( isComplete ) { + // report based on naturalWidth + this.confirm( this.img.naturalWidth !== 0, 'naturalWidth' ); + return; + } + + // If none of the checks above matched, simulate loading on detached element. + this.proxyImage = new Image(); + this.proxyImage.addEventListener( 'load', this ); + this.proxyImage.addEventListener( 'error', this ); + // bind to image as well for Firefox. #191 + this.img.addEventListener( 'load', this ); + this.img.addEventListener( 'error', this ); + this.proxyImage.src = this.img.src; +}; + +LoadingImage.prototype.getIsImageComplete = function() { + return this.img.complete && this.img.naturalWidth !== undefined; +}; + +LoadingImage.prototype.confirm = function( isLoaded, message ) { + this.isLoaded = isLoaded; + this.emitEvent( 'progress', [ this, this.img, message ] ); +}; + +// ----- events ----- // + +// trigger specified handler for event type +LoadingImage.prototype.handleEvent = function( event ) { + var method = 'on' + event.type; + if ( this[ method ] ) { + this[ method ]( event ); + } +}; + +LoadingImage.prototype.onload = function() { + this.confirm( true, 'onload' ); + this.unbindEvents(); +}; + +LoadingImage.prototype.onerror = function() { + this.confirm( false, 'onerror' ); + this.unbindEvents(); +}; + +LoadingImage.prototype.unbindEvents = function() { + this.proxyImage.removeEventListener( 'load', this ); + this.proxyImage.removeEventListener( 'error', this ); + this.img.removeEventListener( 'load', this ); + this.img.removeEventListener( 'error', this ); +}; + +// -------------------------- Background -------------------------- // + +function Background( url, element ) { + this.url = url; + this.element = element; + this.img = new Image(); +} + +// inherit LoadingImage prototype +Background.prototype = Object.create( LoadingImage.prototype ); + +Background.prototype.check = function() { + this.img.addEventListener( 'load', this ); + this.img.addEventListener( 'error', this ); + this.img.src = this.url; + // check if image is already complete + var isComplete = this.getIsImageComplete(); + if ( isComplete ) { + this.confirm( this.img.naturalWidth !== 0, 'naturalWidth' ); + this.unbindEvents(); + } +}; + +Background.prototype.unbindEvents = function() { + this.img.removeEventListener( 'load', this ); + this.img.removeEventListener( 'error', this ); +}; + +Background.prototype.confirm = function( isLoaded, message ) { + this.isLoaded = isLoaded; + this.emitEvent( 'progress', [ this, this.element, message ] ); +}; + +// -------------------------- jQuery -------------------------- // + +ImagesLoaded.makeJQueryPlugin = function( jQuery ) { + jQuery = jQuery || window.jQuery; + if ( !jQuery ) { + return; + } + // set local variable + $ = jQuery; + // $().imagesLoaded() + $.fn.imagesLoaded = function( options, callback ) { + var instance = new ImagesLoaded( this, options, callback ); + return instance.jqDeferred.promise( $(this) ); + }; +}; +// try making plugin +ImagesLoaded.makeJQueryPlugin(); + +// -------------------------- -------------------------- // + +return ImagesLoaded; + +}); + +;angular.module('jtt_bricklayer', []) .directive('bricklayer', ['$timeout', function ($timeout) { return { restrict: 'C', link: function (scope, element, attrs) { var bricklayer = new Bricklayer(element[0]); + imagesLoaded(element[0], function () { + bricklayer.redraw(); + }); + $timeout(function () { bricklayer.redraw(); }); - scope.$on('bricklayer.append', function (event, element) { - bricklayer.append(element); + scope.$on('bricklayer.append', function (event, selectedElement) { + bricklayer.append(selectedElement[0]); bricklayer.redraw(); + imagesLoaded(selectedElement, function () { + bricklayer.redraw(); + }); }); - scope.$on('bricklayer.prepend', function (event, element) { - bricklayer.prepend(element); + scope.$on('bricklayer.prepend', function (event, selectedElement) { + bricklayer.prepend(selectedElement[0]); bricklayer.redraw(); + imagesLoaded(selectedElement, function () { + bricklayer.redraw(); + }); }); scope.$on('bricklayer.redraw', function () { bricklayer.redraw(); }); + }, + controller: function () { } } }]) .directive('bricklayerAppend', function () { return { - require: '?bricklayer', + require: '^^bricklayer', restrict: 'ACE', link: function (scope, element, attrs) { - scope.$emit('bricklayer.append', element[0]); + scope.$emit('bricklayer.append', element); } } }) .directive('bricklayerPrepend', function () { return { - require: '?bricklayer', + require: '^^bricklayer', restrict: 'ACE', link: function (scope, element, attrs) { - scope.$emit('bricklayer.prepend', element[0]); + scope.$emit('bricklayer.prepend', element); } } }); \ No newline at end of file diff --git a/dist/angular-bricklayer.min.js b/dist/angular-bricklayer.min.js index c692e96..eb215ad 100644 --- a/dist/angular-bricklayer.min.js +++ b/dist/angular-bricklayer.min.js @@ -1,8 +1,8 @@ /** @name: angular-bricklayer - @version: 1.0.2 (24-04-2016) + @version: 1.1.0 (25-04-2016) @author: @url: https://github.com/JohnnyTheTank/angular-bricklayer @license: MIT */ -angular.module("jtt_bricklayer",[]).directive("bricklayer",["$timeout",function(a){return{restrict:"C",link:function(b,c,d){var e=new Bricklayer(c[0]);a(function(){e.redraw()}),b.$on("bricklayer.append",function(a,b){e.append(b),e.redraw()}),b.$on("bricklayer.prepend",function(a,b){e.prepend(b),e.redraw()}),b.$on("bricklayer.redraw",function(){e.redraw()})}}}]).directive("bricklayerAppend",function(){return{require:"?bricklayer",restrict:"ACE",link:function(a,b,c){a.$emit("bricklayer.append",b[0])}}}).directive("bricklayerPrepend",function(){return{require:"?bricklayer",restrict:"ACE",link:function(a,b,c){a.$emit("bricklayer.prepend",b[0])}}}); \ No newline at end of file +!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" ], diff --git a/src/angular-bricklayer.js b/src/angular-bricklayer.js index 96272db..c45b737 100644 --- a/src/angular-bricklayer.js +++ b/src/angular-bricklayer.js @@ -33,7 +33,7 @@ angular.module('jtt_bricklayer', []) bricklayer.redraw(); }); }, - controller: function ($scope) { + controller: function () { } } }])