From 8077ade76ac473078a875067e41443e3d065d360 Mon Sep 17 00:00:00 2001 From: Michel Boudreau Date: Thu, 18 Sep 2014 17:51:13 +1000 Subject: [PATCH 1/5] changing how columns are being added to scope so that it doesn't bind on every push --- angular-deckgrid.js | 16 ++++++++-------- angular-deckgrid.min.js | 2 +- src/deckgrid.js | 14 +++++++------- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/angular-deckgrid.js b/angular-deckgrid.js index fe7ab1f..b54d2c3 100644 --- a/angular-deckgrid.js +++ b/angular-deckgrid.js @@ -181,7 +181,7 @@ angular.module('akoenig.deckgrid').factory('Deckgrid', [ this.$$watchers = []; this.$$scope = scope; - this.$$scope.columns = []; +// this.$$scope.columns = []; // // The layout configuration will be parsed from @@ -295,25 +295,25 @@ angular.module('akoenig.deckgrid').factory('Deckgrid', [ * */ Deckgrid.prototype.$$createColumns = function $$createColumns () { - var self = this; - if (!this.$$scope.layout) { return $log.error('angular-deckgrid: No CSS configuration found (see ' + 'https://github.com/akoenig/angular-deckgrid#the-grid-configuration)'); } - this.$$scope.columns = []; + var columns = [], columnNum = this.$$scope.layout.columns; angular.forEach(this.$$scope.model, function onIteration (card, index) { - var column = (index % self.$$scope.layout.columns) | 0; + var column = (index % columnNum) | 0; - if (!self.$$scope.columns[column]) { - self.$$scope.columns[column] = []; + if (!columns[column]) { + columns[column] = []; } card.$index = index; - self.$$scope.columns[column].push(card); + columns[column].push(card); }); + + this.$$scope.columns = columns; }; /** diff --git a/angular-deckgrid.min.js b/angular-deckgrid.min.js index 35de844..3442bd4 100644 --- a/angular-deckgrid.min.js +++ b/angular-deckgrid.min.js @@ -1,2 +1,2 @@ /*! angular-deckgrid (v0.4.4) - Copyright: 2013 - 2014, André König (andre.koenig@posteo.de) - MIT */ -angular.module("akoenig.deckgrid",[]),angular.module("akoenig.deckgrid").directive("deckgrid",["DeckgridDescriptor",function(a){"use strict";return a.create()}]),angular.module("akoenig.deckgrid").factory("DeckgridDescriptor",["Deckgrid","$templateCache",function(a,b){"use strict";function c(){this.restrict="AE",this.template='
',this.scope={model:"=source"},this.$$deckgrid=null,this.transclude=!0,this.link=this.$$link.bind(this),this.$$templateKeyIndex=0}return c.prototype.$$destroy=function(){this.$$deckgrid.destroy()},c.prototype.$$link=function(c,d,e,f,g){var h="deckgrid/innerHtmlTemplate"+ ++this.$$templateKeyIndex+".html";c.$on("$destroy",this.$$destroy.bind(this)),void 0===e.cardtemplate?(void 0===e.cardtemplatestring?g(c,function(a){var c,d=[],e=0,f=a.length;for(e;f>e;e+=1)c=a[e].outerHTML,void 0!==c&&d.push(c);b.put(h,d.join())}):b.put(h,d.attr("cardtemplatestring")),c.cardTemplate=h):c.cardTemplate=e.cardtemplate,c.mother=c.$parent,this.$$deckgrid=a.create(c,d[0])},{create:function(){return new c}}}]),angular.module("akoenig.deckgrid").factory("Deckgrid",["$window","$log",function(a,b){"use strict";function c(b,c){var d,e,f=this;this.$$elem=c,this.$$watchers=[],this.$$scope=b,this.$$scope.columns=[],this.$$scope.layout=this.$$getLayout(),this.$$createColumns(),d=this.$$scope.$watch("model",this.$$onModelChange.bind(this),!0),this.$$watchers.push(d),angular.forEach(f.$$getMediaQueries(),function(a){function b(){a.removeListener(c)}var c=f.$$onMediaQueryChange.bind(f);a.addListener(c),f.$$watchers.push(b)}),e=a.matchMedia("(orientation: portrait)"),e.addListener(f.$$onMediaQueryChange.bind(f))}return c.prototype.$$getMediaQueries=function(){function b(a){try{return a.sheet.cssRules||[]}catch(b){return[]}}function c(a){var b=/\[(\w*-)?deckgrid\]::?before/g,c=0,d="";if(!a.media||angular.isUndefined(a.cssRules))return!1;for(c=a.cssRules.length-1;c>=0;c-=1)if(d=a.cssRules[c].selectorText,angular.isDefined(d)&&d.match(b))return!0;return!1}var d=[],e=[];return d=Array.prototype.concat.call(Array.prototype.slice.call(document.querySelectorAll("style[type='text/css']")),Array.prototype.slice.call(document.querySelectorAll("link[rel='stylesheet']"))),angular.forEach(d,function(d){var f=b(d);angular.forEach(f,function(b){c(b)&&e.push(a.matchMedia(b.media.mediaText))})}),e},c.prototype.$$createColumns=function(){var a=this;return this.$$scope.layout?(this.$$scope.columns=[],void angular.forEach(this.$$scope.model,function(b,c){var d=c%a.$$scope.layout.columns|0;a.$$scope.columns[d]||(a.$$scope.columns[d]=[]),b.$index=c,a.$$scope.columns[d].push(b)})):b.error("angular-deckgrid: No CSS configuration found (see https://github.com/akoenig/angular-deckgrid#the-grid-configuration)")},c.prototype.$$getLayout=function(){var b,c=a.getComputedStyle(this.$$elem,":before").content;return c&&(c=c.replace(/'/g,""),c=c.replace(/"/g,""),c=c.split(" "),2===c.length&&(b={},b.columns=0|c[0],b.classList=c[1].replace(/\./g," ").trim())),b},c.prototype.$$onMediaQueryChange=function(){var a=this,b=this.$$getLayout();b.columns!==this.$$scope.layout.columns&&(a.$$scope.layout=b,a.$$scope.$apply(function(){a.$$createColumns()}))},c.prototype.$$onModelChange=function(a,b){var c=this;a=a||[],b=b||[],b.length!==a.length&&c.$$createColumns()},c.prototype.destroy=function(){var a=this.$$watchers.length-1;for(a;a>=0;a-=1)this.$$watchers[a]()},{create:function(a,b){return new c(a,b)}}}]); \ No newline at end of file +angular.module("akoenig.deckgrid",[]),angular.module("akoenig.deckgrid").directive("deckgrid",["DeckgridDescriptor",function(a){"use strict";return a.create()}]),angular.module("akoenig.deckgrid").factory("DeckgridDescriptor",["Deckgrid","$templateCache",function(a,b){"use strict";function c(){this.restrict="AE",this.template='
',this.scope={model:"=source"},this.$$deckgrid=null,this.transclude=!0,this.link=this.$$link.bind(this),this.$$templateKeyIndex=0}return c.prototype.$$destroy=function(){this.$$deckgrid.destroy()},c.prototype.$$link=function(c,d,e,f,g){var h="deckgrid/innerHtmlTemplate"+ ++this.$$templateKeyIndex+".html";c.$on("$destroy",this.$$destroy.bind(this)),void 0===e.cardtemplate?(void 0===e.cardtemplatestring?g(c,function(a){var c,d=[],e=0,f=a.length;for(e;f>e;e+=1)c=a[e].outerHTML,void 0!==c&&d.push(c);b.put(h,d.join())}):b.put(h,d.attr("cardtemplatestring")),c.cardTemplate=h):c.cardTemplate=e.cardtemplate,c.mother=c.$parent,this.$$deckgrid=a.create(c,d[0])},{create:function(){return new c}}}]),angular.module("akoenig.deckgrid").factory("Deckgrid",["$window","$log",function(a,b){"use strict";function c(b,c){var d,e,f=this;this.$$elem=c,this.$$watchers=[],this.$$scope=b,this.$$scope.layout=this.$$getLayout(),this.$$createColumns(),d=this.$$scope.$watch("model",this.$$onModelChange.bind(this),!0),this.$$watchers.push(d),angular.forEach(f.$$getMediaQueries(),function(a){function b(){a.removeListener(c)}var c=f.$$onMediaQueryChange.bind(f);a.addListener(c),f.$$watchers.push(b)}),e=a.matchMedia("(orientation: portrait)"),e.addListener(f.$$onMediaQueryChange.bind(f))}return c.prototype.$$getMediaQueries=function(){function b(a){try{return a.sheet.cssRules||[]}catch(b){return[]}}function c(a){var b=/\[(\w*-)?deckgrid\]::?before/g,c=0,d="";if(!a.media||angular.isUndefined(a.cssRules))return!1;for(c=a.cssRules.length-1;c>=0;c-=1)if(d=a.cssRules[c].selectorText,angular.isDefined(d)&&d.match(b))return!0;return!1}var d=[],e=[];return d=Array.prototype.concat.call(Array.prototype.slice.call(document.querySelectorAll("style[type='text/css']")),Array.prototype.slice.call(document.querySelectorAll("link[rel='stylesheet']"))),angular.forEach(d,function(d){var f=b(d);angular.forEach(f,function(b){c(b)&&e.push(a.matchMedia(b.media.mediaText))})}),e},c.prototype.$$createColumns=function(){if(!this.$$scope.layout)return b.error("angular-deckgrid: No CSS configuration found (see https://github.com/akoenig/angular-deckgrid#the-grid-configuration)");var a=[],c=this.$$scope.layout.columns;angular.forEach(this.$$scope.model,function(b,d){var e=d%c|0;a[e]||(a[e]=[]),b.$index=d,a[e].push(b)}),this.$$scope.columns=a},c.prototype.$$getLayout=function(){var b,c=a.getComputedStyle(this.$$elem,":before").content;return c&&(c=c.replace(/'/g,""),c=c.replace(/"/g,""),c=c.split(" "),2===c.length&&(b={},b.columns=0|c[0],b.classList=c[1].replace(/\./g," ").trim())),b},c.prototype.$$onMediaQueryChange=function(){var a=this,b=this.$$getLayout();b.columns!==this.$$scope.layout.columns&&(a.$$scope.layout=b,a.$$scope.$apply(function(){a.$$createColumns()}))},c.prototype.$$onModelChange=function(a,b){var c=this;a=a||[],b=b||[],b.length!==a.length&&c.$$createColumns()},c.prototype.destroy=function(){var a=this.$$watchers.length-1;for(a;a>=0;a-=1)this.$$watchers[a]()},{create:function(a,b){return new c(a,b)}}}]); \ No newline at end of file diff --git a/src/deckgrid.js b/src/deckgrid.js index cb07dd7..0937756 100644 --- a/src/deckgrid.js +++ b/src/deckgrid.js @@ -147,25 +147,25 @@ angular.module('akoenig.deckgrid').factory('Deckgrid', [ * */ Deckgrid.prototype.$$createColumns = function $$createColumns () { - var self = this; - if (!this.$$scope.layout) { return $log.error('angular-deckgrid: No CSS configuration found (see ' + 'https://github.com/akoenig/angular-deckgrid#the-grid-configuration)'); } - this.$$scope.columns = []; + var columns = [], columnNum = this.$$scope.layout.columns; angular.forEach(this.$$scope.model, function onIteration (card, index) { - var column = (index % self.$$scope.layout.columns) | 0; + var column = (index % columnNum) | 0; - if (!self.$$scope.columns[column]) { - self.$$scope.columns[column] = []; + if (!columns[column]) { + columns[column] = []; } card.$index = index; - self.$$scope.columns[column].push(card); + columns[column].push(card); }); + + this.$$scope.columns = columns; }; /** From 0f57f8c47cc5db90ac98b56f173dad1d12a9e664 Mon Sep 17 00:00:00 2001 From: Michel Boudreau Date: Fri, 19 Sep 2014 14:29:21 +1000 Subject: [PATCH 2/5] adding patch from pull 11 --- src/deckgrid.js | 504 ++++++++++++++++++++++++------------------------ 1 file changed, 256 insertions(+), 248 deletions(-) diff --git a/src/deckgrid.js b/src/deckgrid.js index 0937756..5d28e77 100644 --- a/src/deckgrid.js +++ b/src/deckgrid.js @@ -13,254 +13,262 @@ angular.module('akoenig.deckgrid').factory('Deckgrid', [ - '$window', - '$log', - - function initialize ($window, $log) { - - 'use strict'; - - /** - * The deckgrid directive. - * - */ - function Deckgrid (scope, element) { - var self = this, - watcher, - mql; - - this.$$elem = element; - this.$$watchers = []; - - this.$$scope = scope; - this.$$scope.columns = []; - - // - // The layout configuration will be parsed from - // the pseudo "before element." There you have to save all - // the column configurations. - // - this.$$scope.layout = this.$$getLayout(); - - this.$$createColumns(); - - // - // Register model change. - // - watcher = this.$$scope.$watch('model', this.$$onModelChange.bind(this), true); - this.$$watchers.push(watcher); - - // - // Register media query change events. - // - angular.forEach(self.$$getMediaQueries(), function onIteration (rule) { - var handler = self.$$onMediaQueryChange.bind(self); - - function onDestroy () { - rule.removeListener(handler); - } - - rule.addListener(handler); - - self.$$watchers.push(onDestroy); - }); - - mql = $window.matchMedia('(orientation: portrait)'); - mql.addListener(self.$$onMediaQueryChange.bind(self)); - - } - - /** - * @private - * - * Extracts the media queries out of the stylesheets. - * - * This method will fetch the media queries out of the stylesheets that are - * responsible for styling the angular-deckgrid. - * - * @return {array} An array with all respective styles. - * - */ - Deckgrid.prototype.$$getMediaQueries = function $$getMediaQueries () { - var stylesheets = [], - mediaQueries = []; - - stylesheets = Array.prototype.concat.call( - Array.prototype.slice.call(document.querySelectorAll('style[type=\'text/css\']')), - Array.prototype.slice.call(document.querySelectorAll('link[rel=\'stylesheet\']')) - ); - - function extractRules (stylesheet) { - try { - return (stylesheet.sheet.cssRules || []); - } catch (e) { - return []; - } - } - - function hasDeckgridStyles (rule) { - var regexe = /\[(\w*-)?deckgrid\]::?before/g, - i = 0, - selector = ''; - - if (!rule.media || angular.isUndefined(rule.cssRules)) { - return false; - } - - i = rule.cssRules.length - 1; - - for (i; i >= 0; i = i - 1) { - selector = rule.cssRules[i].selectorText; - - if (angular.isDefined(selector) && selector.match(regexe)) { - return true; - } - } - - return false; - } - - angular.forEach(stylesheets, function onIteration (stylesheet) { - var rules = extractRules(stylesheet); - - angular.forEach(rules, function inRuleIteration (rule) { - if (hasDeckgridStyles(rule)) { - mediaQueries.push($window.matchMedia(rule.media.mediaText)); - } - }); - }); - - return mediaQueries; - }; - - /** - * @private - * - * Creates the column segmentation. With other words: - * This method creates the internal data structure from the - * passed "source" attribute. Every card within this "source" - * model will be passed into this internal column structure by - * reference. So if you modify the data within your controller - * this directive will reflect these changes immediately. - * - * NOTE that calling this method will trigger a complete template "redraw". - * - */ - Deckgrid.prototype.$$createColumns = function $$createColumns () { - if (!this.$$scope.layout) { - return $log.error('angular-deckgrid: No CSS configuration found (see ' + - 'https://github.com/akoenig/angular-deckgrid#the-grid-configuration)'); - } - - var columns = [], columnNum = this.$$scope.layout.columns; - - angular.forEach(this.$$scope.model, function onIteration (card, index) { - var column = (index % columnNum) | 0; - - if (!columns[column]) { - columns[column] = []; - } - - card.$index = index; - columns[column].push(card); - }); - - this.$$scope.columns = columns; - }; - - /** - * @private - * - * Parses the configuration out of the configured CSS styles. - * - * Example: - * - * .deckgrid::before { + '$window', + '$log', + + function initialize($window, $log) { + + 'use strict'; + + /** + * The deckgrid directive. + * + */ + function Deckgrid(scope, element) { + var self = this, + watcher, + mql; + + this.$$elem = element; + this.$$watchers = []; + + this.$$scope = scope; + this.$$scope.columns = []; + + // + // The layout configuration will be parsed from + // the pseudo "before element." There you have to save all + // the column configurations. + // + this.$$scope.layout = this.$$getLayout(); + + this.$$createColumns(); + + // + // Register model change. + // + watcher = this.$$scope.$watch('model', this.$$onModelChange.bind(this), true); + this.$$watchers.push(watcher); + + // + // Register media query change events. + // + angular.forEach(self.$$getMediaQueries(), function onIteration(rule) { + var handler = self.$$onMediaQueryChange.bind(self); + + function onDestroy() { + rule.removeListener(handler); + } + + rule.addListener(handler); + + self.$$watchers.push(onDestroy); + }); + + mql = $window.matchMedia('(orientation: portrait)'); + mql.addListener(self.$$onMediaQueryChange.bind(self)); + + } + + /** + * @private + * + * Extracts the media queries out of the stylesheets. + * + * This method will fetch the media queries out of the stylesheets that are + * responsible for styling the angular-deckgrid. + * + * @return {array} An array with all respective styles. + * + */ + Deckgrid.prototype.$$getMediaQueries = function $$getMediaQueries() { + var stylesheets = [], + mediaQueries = []; + + stylesheets = Array.prototype.concat.call( + Array.prototype.slice.call(document.querySelectorAll('style[type=\'text/css\']')), + Array.prototype.slice.call(document.querySelectorAll('link[rel=\'stylesheet\']')) + ); + + function extractRules(stylesheet) { + try { + return (stylesheet.sheet.cssRules || []); + } catch (e) { + return []; + } + } + + function hasDeckgridStyles(rule) { + var regexe = /\[(\w*-)?deckgrid\]::?before/g, + i = 0, + selector = ''; + + if (!rule.media || angular.isUndefined(rule.cssRules)) { + return false; + } + + i = rule.cssRules.length - 1; + + for (i; i >= 0; i = i - 1) { + selector = rule.cssRules[i].selectorText; + + if (angular.isDefined(selector) && selector.match(regexe)) { + return true; + } + } + + return false; + } + + angular.forEach(stylesheets, function onIteration(stylesheet) { + var rules = extractRules(stylesheet); + + angular.forEach(rules, function inRuleIteration(rule) { + if (hasDeckgridStyles(rule)) { + mediaQueries.push($window.matchMedia(rule.media.mediaText)); + } + }); + }); + + return mediaQueries; + }; + + /** + * @private + * + * Creates the column segmentation. With other words: + * This method creates the internal data structure from the + * passed "source" attribute. Every card within this "source" + * model will be passed into this internal column structure by + * reference. So if you modify the data within your controller + * this directive will reflect these changes immediately. + * + * NOTE that calling this method will trigger a complete template "redraw". + * + */ + Deckgrid.prototype.$$createColumns = function $$createColumns() { + if (!this.$$scope.layout) { + return $log.error('angular-deckgrid: No CSS configuration found (see ' + + 'https://github.com/akoenig/angular-deckgrid#the-grid-configuration)'); + } + + var columns = [], columnNum = this.$$scope.layout.columns; + + angular.forEach(this.$$scope.model, function onIteration(card, index) { + var column = (index % columnNum) | 0; + + if (!columns[column]) { + columns[column] = []; + } + + card.$index = index; + columns[column].push(card); + }); + + this.$$scope.columns = columns; + }; + + /** + * @private + * + * Parses the configuration out of the configured CSS styles. + * + * Example: + * + * .deckgrid::before { * content: '3 .column.size-1-3'; * } - * - * Will result in a three column grid where each column will have the - * classes: "column size-1-3". - * - * You are responsible for defining the respective styles within your CSS. - * - */ - Deckgrid.prototype.$$getLayout = function $$getLayout () { - var content = $window.getComputedStyle(this.$$elem, ':before').content, - layout; - - if (content) { - content = content.replace(/'/g, ''); // before e.g. '3 .column.size-1of3' - content = content.replace(/"/g, ''); // before e.g. "3 .column.size-1of3" - content = content.split(' '); - - if (2 === content.length) { - layout = {}; - layout.columns = (content[0] | 0); - layout.classList = content[1].replace(/\./g, ' ').trim(); - } - } - - return layout; - }; - - /** - * @private - * - * Event that will be triggered if a CSS media query changed. - * - */ - Deckgrid.prototype.$$onMediaQueryChange = function $$onMediaQueryChange () { - var self = this, - layout = this.$$getLayout(); - - // - // Okay, the layout has changed. - // Creating a new column structure is not avoidable. - // - if (layout.columns !== this.$$scope.layout.columns) { - self.$$scope.layout = layout; - - self.$$scope.$apply(function onApply () { - self.$$createColumns(); - }); - } - }; - - /** - * @private - * - * Event that will be triggered when the source model has changed. - * - */ - Deckgrid.prototype.$$onModelChange = function $$onModelChange (newModel, oldModel) { - var self = this; - - newModel = newModel || []; - oldModel = oldModel || []; - - if (oldModel.length !== newModel.length) { - self.$$createColumns(); - } - }; - - /** - * Destroys the directive. Takes care of cleaning all - * watchers and event handlers. - * - */ - Deckgrid.prototype.destroy = function destroy () { - var i = this.$$watchers.length - 1; - - for (i; i >= 0; i = i - 1) { - this.$$watchers[i](); - } - }; - - return { - create : function create (scope, element) { - return new Deckgrid(scope, element); - } - }; - } + * + * Will result in a three column grid where each column will have the + * classes: "column size-1-3". + * + * You are responsible for defining the respective styles within your CSS. + * + */ + Deckgrid.prototype.$$getLayout = function $$getLayout() { + var content = $window.getComputedStyle(this.$$elem, ':before').content, + layout; + + if (content) { + content = content.replace(/'/g, ''); // before e.g. '3 .column.size-1of3' + content = content.replace(/"/g, ''); // before e.g. "3 .column.size-1of3" + content = content.split(' '); + + if (2 === content.length) { + layout = {}; + layout.columns = (content[0] | 0); + layout.classList = content[1].replace(/\./g, ' ').trim(); + } + } + + return layout; + }; + + /** + * @private + * + * Event that will be triggered if a CSS media query changed. + * + */ + Deckgrid.prototype.$$onMediaQueryChange = function $$onMediaQueryChange() { + var self = this, + layout = this.$$getLayout(); + + // + // Okay, the layout has changed. + // Creating a new column structure is not avoidable. + // + if (layout.columns !== this.$$scope.layout.columns) { + self.$$scope.layout = layout; + + self.$$scope.$apply(function onApply() { + self.$$createColumns(); + }); + } + }; + + /** + * @private + * + * Event that will be triggered when the source model has changed. + * + */ + Deckgrid.prototype.$$onModelChange = function $$onModelChange(newModel, oldModel) { + var self = this; + + newModel = newModel || []; + oldModel = oldModel || []; + + if (oldModel.length !== newModel.length) { + self.$$createColumns(); + } else { + var i = newModel.length - 1; + for (i; i >= 0; i = i - 1) { + if (oldModel[i] !== newModel[i]) { + self.$$createColumns(); + break; + } + } + } + }; + + /** + * Destroys the directive. Takes care of cleaning all + * watchers and event handlers. + * + */ + Deckgrid.prototype.destroy = function destroy() { + var i = this.$$watchers.length - 1; + + for (i; i >= 0; i = i - 1) { + this.$$watchers[i](); + } + }; + + return { + create: function create(scope, element) { + return new Deckgrid(scope, element); + } + }; + } ]); From 9ceae0843443dde586b9dc1458e268485c2668bf Mon Sep 17 00:00:00 2001 From: Michel Boudreau Date: Fri, 19 Sep 2014 14:34:25 +1000 Subject: [PATCH 3/5] adding pull request 48 --- .gitignore | 4 +++- README.md | 29 +++++++++++++++++++++++++++++ angular-deckgrid.js | 2 +- 3 files changed, 33 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index bb93d68..8dd3dc2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ node_modules -bower_components \ No newline at end of file +bower_components +.idea +*.iml \ No newline at end of file diff --git a/README.md b/README.md index 9b819d1..74caa13 100644 --- a/README.md +++ b/README.md @@ -87,6 +87,35 @@ This index reflects the index of the corresponding object in the source collecti That's all! Ehm, no. If you run your application now, you will notice that there is only one column. What is missing? Well, we have to define the configuration for the visual representation. And what is the best place for something like this? Yes, for sure! Your CSS file(s). +### Providing a custom function to build the watch listener + +If you are expecting a lot of items or have complex objects you may want to provide a custom function to build a watch expression instead of asking angular to deep compare each object. The function should return a string and will be called for each item in `source`. The result will be a concatenated string from the result of each function. + +Example: + +```html +
+
    + ... +
+
+``` + +```javascript +$scope.items = [ + { id: 1, name: "Photo 1", properties: {...} }, + { id: 2, name: "Photo 2", properties: {...} }, + { id: 3, name: "Photo 3", properties: {...} }, + { id: 4, name: "Photo 4", properties: {...} }, +]; + +$scope.getItemId = function (item) { + return item.id + "|"; +} +``` + +The value used for the watch expression will be: `'1|2|3|4|'`. + ## The grid configuration The grid items will be distributed by your configured CSS selectors. An example: diff --git a/angular-deckgrid.js b/angular-deckgrid.js index b54d2c3..2e0e50b 100644 --- a/angular-deckgrid.js +++ b/angular-deckgrid.js @@ -387,7 +387,7 @@ angular.module('akoenig.deckgrid').factory('Deckgrid', [ newModel = newModel || []; oldModel = oldModel || []; - if (oldModel.length !== newModel.length) { + if (!angular.equals(oldModel, newModel)) { self.$$createColumns(); } }; From 1e18cb2ecd853e21d2f963cb7c1a595890b6b893 Mon Sep 17 00:00:00 2001 From: Michel Boudreau Date: Fri, 19 Sep 2014 15:16:33 +1000 Subject: [PATCH 4/5] adding pull request 56, removing ingore min in bower file --- angular-deckgrid.js | 523 +++++++++++++++++++++------------------- angular-deckgrid.min.js | 2 +- bower.json | 1 - src/deckgrid.js | 39 ++- 4 files changed, 305 insertions(+), 260 deletions(-) diff --git a/angular-deckgrid.js b/angular-deckgrid.js index 2e0e50b..1aea7c6 100644 --- a/angular-deckgrid.js +++ b/angular-deckgrid.js @@ -161,254 +161,281 @@ angular.module('akoenig.deckgrid').factory('DeckgridDescriptor', [ angular.module('akoenig.deckgrid').factory('Deckgrid', [ - '$window', - '$log', - - function initialize ($window, $log) { - - 'use strict'; - - /** - * The deckgrid directive. - * - */ - function Deckgrid (scope, element) { - var self = this, - watcher, - mql; - - this.$$elem = element; - this.$$watchers = []; - - this.$$scope = scope; -// this.$$scope.columns = []; - - // - // The layout configuration will be parsed from - // the pseudo "before element." There you have to save all - // the column configurations. - // - this.$$scope.layout = this.$$getLayout(); - - this.$$createColumns(); - - // - // Register model change. - // - watcher = this.$$scope.$watch('model', this.$$onModelChange.bind(this), true); - this.$$watchers.push(watcher); - - // - // Register media query change events. - // - angular.forEach(self.$$getMediaQueries(), function onIteration (rule) { - var handler = self.$$onMediaQueryChange.bind(self); - - function onDestroy () { - rule.removeListener(handler); - } - - rule.addListener(handler); - - self.$$watchers.push(onDestroy); - }); - - mql = $window.matchMedia('(orientation: portrait)'); - mql.addListener(self.$$onMediaQueryChange.bind(self)); - - } - - /** - * @private - * - * Extracts the media queries out of the stylesheets. - * - * This method will fetch the media queries out of the stylesheets that are - * responsible for styling the angular-deckgrid. - * - * @return {array} An array with all respective styles. - * - */ - Deckgrid.prototype.$$getMediaQueries = function $$getMediaQueries () { - var stylesheets = [], - mediaQueries = []; - - stylesheets = Array.prototype.concat.call( - Array.prototype.slice.call(document.querySelectorAll('style[type=\'text/css\']')), - Array.prototype.slice.call(document.querySelectorAll('link[rel=\'stylesheet\']')) - ); - - function extractRules (stylesheet) { - try { - return (stylesheet.sheet.cssRules || []); - } catch (e) { - return []; - } - } - - function hasDeckgridStyles (rule) { - var regexe = /\[(\w*-)?deckgrid\]::?before/g, - i = 0, - selector = ''; - - if (!rule.media || angular.isUndefined(rule.cssRules)) { - return false; - } - - i = rule.cssRules.length - 1; - - for (i; i >= 0; i = i - 1) { - selector = rule.cssRules[i].selectorText; - - if (angular.isDefined(selector) && selector.match(regexe)) { - return true; - } - } - - return false; - } - - angular.forEach(stylesheets, function onIteration (stylesheet) { - var rules = extractRules(stylesheet); - - angular.forEach(rules, function inRuleIteration (rule) { - if (hasDeckgridStyles(rule)) { - mediaQueries.push($window.matchMedia(rule.media.mediaText)); - } - }); - }); - - return mediaQueries; - }; - - /** - * @private - * - * Creates the column segmentation. With other words: - * This method creates the internal data structure from the - * passed "source" attribute. Every card within this "source" - * model will be passed into this internal column structure by - * reference. So if you modify the data within your controller - * this directive will reflect these changes immediately. - * - * NOTE that calling this method will trigger a complete template "redraw". - * - */ - Deckgrid.prototype.$$createColumns = function $$createColumns () { - if (!this.$$scope.layout) { - return $log.error('angular-deckgrid: No CSS configuration found (see ' + - 'https://github.com/akoenig/angular-deckgrid#the-grid-configuration)'); - } - - var columns = [], columnNum = this.$$scope.layout.columns; - - angular.forEach(this.$$scope.model, function onIteration (card, index) { - var column = (index % columnNum) | 0; - - if (!columns[column]) { - columns[column] = []; - } - - card.$index = index; - columns[column].push(card); - }); - - this.$$scope.columns = columns; - }; - - /** - * @private - * - * Parses the configuration out of the configured CSS styles. - * - * Example: - * - * .deckgrid::before { + '$window', + '$log', + + function initialize($window, $log) { + + 'use strict'; + + /** + * The deckgrid directive. + * + */ + function Deckgrid(scope, element) { + var self = this, + watcher, + mql; + + this.$$elem = element; + this.$$watchers = []; + + this.$$scope = scope; + this.$$scope.columns = []; + + // + // The layout configuration will be parsed from + // the pseudo "before element." There you have to save all + // the column configurations. + // + this.$$scope.layout = this.$$getLayout(); + + this.$$createColumns(); + + // + // Register model change. + // + watcher = this.$$scope.$watchCollection('model', this.$$onModelChange.bind(this)); + this.$$watchers.push(watcher); + + // + // Register media query change events. + // + angular.forEach(self.$$getMediaQueries(), function onIteration(rule) { + var handler = self.$$onMediaQueryChange.bind(self); + + function onDestroy() { + rule.removeListener(handler); + } + + rule.addListener(handler); + + self.$$watchers.push(onDestroy); + }); + + mql = $window.matchMedia('(orientation: portrait)'); + mql.addListener(self.$$onMediaQueryChange.bind(self)); + + } + + /** + * @private + * + * Extracts the media queries out of the stylesheets. + * + * This method will fetch the media queries out of the stylesheets that are + * responsible for styling the angular-deckgrid. + * + * @return {array} An array with all respective styles. + * + */ + Deckgrid.prototype.$$getMediaQueries = function $$getMediaQueries() { + var stylesheets = [], + mediaQueries = []; + + stylesheets = Array.prototype.concat.call( + Array.prototype.slice.call(document.querySelectorAll('style[type=\'text/css\']')), + Array.prototype.slice.call(document.querySelectorAll('link[rel=\'stylesheet\']')) + ); + + function extractRules(stylesheet) { + try { + return (stylesheet.sheet.cssRules || []); + } catch (e) { + return []; + } + } + + function hasDeckgridStyles(rule) { + var regexe = /\[(\w*-)?deckgrid\]::?before/g, + i = 0, + selector = ''; + + if (!rule.media || angular.isUndefined(rule.cssRules)) { + return false; + } + + i = rule.cssRules.length - 1; + + for (i; i >= 0; i = i - 1) { + selector = rule.cssRules[i].selectorText; + + if (angular.isDefined(selector) && selector.match(regexe)) { + return true; + } + } + + return false; + } + + angular.forEach(stylesheets, function onIteration(stylesheet) { + var rules = extractRules(stylesheet); + + angular.forEach(rules, function inRuleIteration(rule) { + if (hasDeckgridStyles(rule)) { + mediaQueries.push($window.matchMedia(rule.media.mediaText)); + } + }); + }); + + return mediaQueries; + }; + + Deckgrid.prototype.$$cachedParams = function $$cachedParams(column) { + if (!this.$$cache) { + this.$$cache = {}; + } + if (this.$$cache.column === column) { + return this.$$cache; + } + this.$$cache = { column: column, modelLength: 0 }; + return this.$$cache; + }; + + /** + * @private + * + * Creates the column segmentation. With other words: + * This method creates the internal data structure from the + * passed "source" attribute. Every card within this "source" + * model will be passed into this internal column structure by + * reference. So if you modify the data within your controller + * this directive will reflect these changes immediately. + * + * NOTE that calling this method will trigger a complete template "redraw". + * + */ + Deckgrid.prototype.$$createColumns = function $$createColumns() { + if (!this.$$scope.layout) { + return $log.error('angular-deckgrid: No CSS configuration found (see ' + + 'https://github.com/akoenig/angular-deckgrid#the-grid-configuration)'); + } + + var cachedParams = this.$$cachedParams(this.$$scope.layout.columns); + if (cachedParams.modelLength === 0) { + // layout change, reset columns + this.$$scope.columns = []; + } + + var modelLength = 0; + if (this.$$scope.model) { + modelLength = this.$$scope.model.length; + } + for (var index = cachedParams.modelLength; index < modelLength; index++) { + var card = this.$$scope.model[index]; + var column = (index % this.$$scope.layout.columns) | 0; + + if (!this.$$scope.columns[column]) { + this.$$scope.columns[column] = []; + } + card.$index = index; + this.$$scope.columns[column].push(card); + } + + cachedParams.modelLength = modelLength; + }; + + /** + * @private + * + * Parses the configuration out of the configured CSS styles. + * + * Example: + * + * .deckgrid::before { * content: '3 .column.size-1-3'; * } - * - * Will result in a three column grid where each column will have the - * classes: "column size-1-3". - * - * You are responsible for defining the respective styles within your CSS. - * - */ - Deckgrid.prototype.$$getLayout = function $$getLayout () { - var content = $window.getComputedStyle(this.$$elem, ':before').content, - layout; - - if (content) { - content = content.replace(/'/g, ''); // before e.g. '3 .column.size-1of3' - content = content.replace(/"/g, ''); // before e.g. "3 .column.size-1of3" - content = content.split(' '); - - if (2 === content.length) { - layout = {}; - layout.columns = (content[0] | 0); - layout.classList = content[1].replace(/\./g, ' ').trim(); - } - } - - return layout; - }; - - /** - * @private - * - * Event that will be triggered if a CSS media query changed. - * - */ - Deckgrid.prototype.$$onMediaQueryChange = function $$onMediaQueryChange () { - var self = this, - layout = this.$$getLayout(); - - // - // Okay, the layout has changed. - // Creating a new column structure is not avoidable. - // - if (layout.columns !== this.$$scope.layout.columns) { - self.$$scope.layout = layout; - - self.$$scope.$apply(function onApply () { - self.$$createColumns(); - }); - } - }; - - /** - * @private - * - * Event that will be triggered when the source model has changed. - * - */ - Deckgrid.prototype.$$onModelChange = function $$onModelChange (newModel, oldModel) { - var self = this; - - newModel = newModel || []; - oldModel = oldModel || []; - - if (!angular.equals(oldModel, newModel)) { - self.$$createColumns(); - } - }; - - /** - * Destroys the directive. Takes care of cleaning all - * watchers and event handlers. - * - */ - Deckgrid.prototype.destroy = function destroy () { - var i = this.$$watchers.length - 1; - - for (i; i >= 0; i = i - 1) { - this.$$watchers[i](); - } - }; - - return { - create : function create (scope, element) { - return new Deckgrid(scope, element); - } - }; - } + * + * Will result in a three column grid where each column will have the + * classes: "column size-1-3". + * + * You are responsible for defining the respective styles within your CSS. + * + */ + Deckgrid.prototype.$$getLayout = function $$getLayout() { + var content = $window.getComputedStyle(this.$$elem, ':before').content, + layout; + + if (content) { + content = content.replace(/'/g, ''); // before e.g. '3 .column.size-1of3' + content = content.replace(/"/g, ''); // before e.g. "3 .column.size-1of3" + content = content.split(' '); + + if (2 === content.length) { + layout = {}; + layout.columns = (content[0] | 0); + layout.classList = content[1].replace(/\./g, ' ').trim(); + } + } + + return layout; + }; + + /** + * @private + * + * Event that will be triggered if a CSS media query changed. + * + */ + Deckgrid.prototype.$$onMediaQueryChange = function $$onMediaQueryChange() { + var self = this, + layout = this.$$getLayout(); + + // + // Okay, the layout has changed. + // Creating a new column structure is not avoidable. + // + if (layout.columns !== this.$$scope.layout.columns) { + self.$$scope.layout = layout; + + self.$$scope.$apply(function onApply() { + self.$$createColumns(); + }); + } + }; + + /** + * @private + * + * Event that will be triggered when the source model has changed. + * + */ + Deckgrid.prototype.$$onModelChange = function $$onModelChange(newModel, oldModel) { + var self = this; + + newModel = newModel || []; + oldModel = oldModel || []; + + if (oldModel.length !== newModel.length) { + self.$$createColumns(); + } else { + var i = newModel.length - 1; + for (i; i >= 0; i = i - 1) { + if (oldModel[i] !== newModel[i]) { + self.$$createColumns(); + break; + } + } + } + }; + + /** + * Destroys the directive. Takes care of cleaning all + * watchers and event handlers. + * + */ + Deckgrid.prototype.destroy = function destroy() { + var i = this.$$watchers.length - 1; + + for (i; i >= 0; i = i - 1) { + this.$$watchers[i](); + } + }; + + return { + create: function create(scope, element) { + return new Deckgrid(scope, element); + } + }; + } ]); diff --git a/angular-deckgrid.min.js b/angular-deckgrid.min.js index 3442bd4..c722792 100644 --- a/angular-deckgrid.min.js +++ b/angular-deckgrid.min.js @@ -1,2 +1,2 @@ /*! angular-deckgrid (v0.4.4) - Copyright: 2013 - 2014, André König (andre.koenig@posteo.de) - MIT */ -angular.module("akoenig.deckgrid",[]),angular.module("akoenig.deckgrid").directive("deckgrid",["DeckgridDescriptor",function(a){"use strict";return a.create()}]),angular.module("akoenig.deckgrid").factory("DeckgridDescriptor",["Deckgrid","$templateCache",function(a,b){"use strict";function c(){this.restrict="AE",this.template='
',this.scope={model:"=source"},this.$$deckgrid=null,this.transclude=!0,this.link=this.$$link.bind(this),this.$$templateKeyIndex=0}return c.prototype.$$destroy=function(){this.$$deckgrid.destroy()},c.prototype.$$link=function(c,d,e,f,g){var h="deckgrid/innerHtmlTemplate"+ ++this.$$templateKeyIndex+".html";c.$on("$destroy",this.$$destroy.bind(this)),void 0===e.cardtemplate?(void 0===e.cardtemplatestring?g(c,function(a){var c,d=[],e=0,f=a.length;for(e;f>e;e+=1)c=a[e].outerHTML,void 0!==c&&d.push(c);b.put(h,d.join())}):b.put(h,d.attr("cardtemplatestring")),c.cardTemplate=h):c.cardTemplate=e.cardtemplate,c.mother=c.$parent,this.$$deckgrid=a.create(c,d[0])},{create:function(){return new c}}}]),angular.module("akoenig.deckgrid").factory("Deckgrid",["$window","$log",function(a,b){"use strict";function c(b,c){var d,e,f=this;this.$$elem=c,this.$$watchers=[],this.$$scope=b,this.$$scope.layout=this.$$getLayout(),this.$$createColumns(),d=this.$$scope.$watch("model",this.$$onModelChange.bind(this),!0),this.$$watchers.push(d),angular.forEach(f.$$getMediaQueries(),function(a){function b(){a.removeListener(c)}var c=f.$$onMediaQueryChange.bind(f);a.addListener(c),f.$$watchers.push(b)}),e=a.matchMedia("(orientation: portrait)"),e.addListener(f.$$onMediaQueryChange.bind(f))}return c.prototype.$$getMediaQueries=function(){function b(a){try{return a.sheet.cssRules||[]}catch(b){return[]}}function c(a){var b=/\[(\w*-)?deckgrid\]::?before/g,c=0,d="";if(!a.media||angular.isUndefined(a.cssRules))return!1;for(c=a.cssRules.length-1;c>=0;c-=1)if(d=a.cssRules[c].selectorText,angular.isDefined(d)&&d.match(b))return!0;return!1}var d=[],e=[];return d=Array.prototype.concat.call(Array.prototype.slice.call(document.querySelectorAll("style[type='text/css']")),Array.prototype.slice.call(document.querySelectorAll("link[rel='stylesheet']"))),angular.forEach(d,function(d){var f=b(d);angular.forEach(f,function(b){c(b)&&e.push(a.matchMedia(b.media.mediaText))})}),e},c.prototype.$$createColumns=function(){if(!this.$$scope.layout)return b.error("angular-deckgrid: No CSS configuration found (see https://github.com/akoenig/angular-deckgrid#the-grid-configuration)");var a=[],c=this.$$scope.layout.columns;angular.forEach(this.$$scope.model,function(b,d){var e=d%c|0;a[e]||(a[e]=[]),b.$index=d,a[e].push(b)}),this.$$scope.columns=a},c.prototype.$$getLayout=function(){var b,c=a.getComputedStyle(this.$$elem,":before").content;return c&&(c=c.replace(/'/g,""),c=c.replace(/"/g,""),c=c.split(" "),2===c.length&&(b={},b.columns=0|c[0],b.classList=c[1].replace(/\./g," ").trim())),b},c.prototype.$$onMediaQueryChange=function(){var a=this,b=this.$$getLayout();b.columns!==this.$$scope.layout.columns&&(a.$$scope.layout=b,a.$$scope.$apply(function(){a.$$createColumns()}))},c.prototype.$$onModelChange=function(a,b){var c=this;a=a||[],b=b||[],b.length!==a.length&&c.$$createColumns()},c.prototype.destroy=function(){var a=this.$$watchers.length-1;for(a;a>=0;a-=1)this.$$watchers[a]()},{create:function(a,b){return new c(a,b)}}}]); \ No newline at end of file +angular.module("akoenig.deckgrid",[]),angular.module("akoenig.deckgrid").directive("deckgrid",["DeckgridDescriptor",function(a){"use strict";return a.create()}]),angular.module("akoenig.deckgrid").factory("DeckgridDescriptor",["Deckgrid","$templateCache",function(a,b){"use strict";function c(){this.restrict="AE",this.template='
',this.scope={model:"=source"},this.$$deckgrid=null,this.transclude=!0,this.link=this.$$link.bind(this),this.$$templateKeyIndex=0}return c.prototype.$$destroy=function(){this.$$deckgrid.destroy()},c.prototype.$$link=function(c,d,e,f,g){var h="deckgrid/innerHtmlTemplate"+ ++this.$$templateKeyIndex+".html";c.$on("$destroy",this.$$destroy.bind(this)),void 0===e.cardtemplate?(void 0===e.cardtemplatestring?g(c,function(a){var c,d=[],e=0,f=a.length;for(e;f>e;e+=1)c=a[e].outerHTML,void 0!==c&&d.push(c);b.put(h,d.join())}):b.put(h,d.attr("cardtemplatestring")),c.cardTemplate=h):c.cardTemplate=e.cardtemplate,c.mother=c.$parent,this.$$deckgrid=a.create(c,d[0])},{create:function(){return new c}}}]),angular.module("akoenig.deckgrid").factory("Deckgrid",["$window","$log",function(a,b){"use strict";function c(b,c){var d,e,f=this;this.$$elem=c,this.$$watchers=[],this.$$scope=b,this.$$scope.columns=[],this.$$scope.layout=this.$$getLayout(),this.$$createColumns(),d=this.$$scope.$watchCollection("model",this.$$onModelChange.bind(this)),this.$$watchers.push(d),angular.forEach(f.$$getMediaQueries(),function(a){function b(){a.removeListener(c)}var c=f.$$onMediaQueryChange.bind(f);a.addListener(c),f.$$watchers.push(b)}),e=a.matchMedia("(orientation: portrait)"),e.addListener(f.$$onMediaQueryChange.bind(f))}return c.prototype.$$getMediaQueries=function(){function b(a){try{return a.sheet.cssRules||[]}catch(b){return[]}}function c(a){var b=/\[(\w*-)?deckgrid\]::?before/g,c=0,d="";if(!a.media||angular.isUndefined(a.cssRules))return!1;for(c=a.cssRules.length-1;c>=0;c-=1)if(d=a.cssRules[c].selectorText,angular.isDefined(d)&&d.match(b))return!0;return!1}var d=[],e=[];return d=Array.prototype.concat.call(Array.prototype.slice.call(document.querySelectorAll("style[type='text/css']")),Array.prototype.slice.call(document.querySelectorAll("link[rel='stylesheet']"))),angular.forEach(d,function(d){var f=b(d);angular.forEach(f,function(b){c(b)&&e.push(a.matchMedia(b.media.mediaText))})}),e},c.prototype.$$cachedParams=function(a){return this.$$cache||(this.$$cache={}),this.$$cache.column===a?this.$$cache:(this.$$cache={column:a,modelLength:0},this.$$cache)},c.prototype.$$createColumns=function(){if(!this.$$scope.layout)return b.error("angular-deckgrid: No CSS configuration found (see https://github.com/akoenig/angular-deckgrid#the-grid-configuration)");var a=this.$$cachedParams(this.$$scope.layout.columns);0===a.modelLength&&(this.$$scope.columns=[]);var c=0;this.$$scope.model&&(c=this.$$scope.model.length);for(var d=a.modelLength;c>d;d++){var e=this.$$scope.model[d],f=d%this.$$scope.layout.columns|0;this.$$scope.columns[f]||(this.$$scope.columns[f]=[]),e.$index=d,this.$$scope.columns[f].push(e)}a.modelLength=c},c.prototype.$$getLayout=function(){var b,c=a.getComputedStyle(this.$$elem,":before").content;return c&&(c=c.replace(/'/g,""),c=c.replace(/"/g,""),c=c.split(" "),2===c.length&&(b={},b.columns=0|c[0],b.classList=c[1].replace(/\./g," ").trim())),b},c.prototype.$$onMediaQueryChange=function(){var a=this,b=this.$$getLayout();b.columns!==this.$$scope.layout.columns&&(a.$$scope.layout=b,a.$$scope.$apply(function(){a.$$createColumns()}))},c.prototype.$$onModelChange=function(a,b){var c=this;if(a=a||[],b=b||[],b.length!==a.length)c.$$createColumns();else{var d=a.length-1;for(d;d>=0;d-=1)if(b[d]!==a[d]){c.$$createColumns();break}}},c.prototype.destroy=function(){var a=this.$$watchers.length-1;for(a;a>=0;a-=1)this.$$watchers[a]()},{create:function(a,b){return new c(a,b)}}}]); \ No newline at end of file diff --git a/bower.json b/bower.json index c2cdd46..4766802 100644 --- a/bower.json +++ b/bower.json @@ -15,7 +15,6 @@ "bower_components", "src", "test", - "*.min.js", "*.conf.js", "*.html", "Gruntfile.js", diff --git a/src/deckgrid.js b/src/deckgrid.js index 5d28e77..52bdebe 100644 --- a/src/deckgrid.js +++ b/src/deckgrid.js @@ -47,7 +47,7 @@ angular.module('akoenig.deckgrid').factory('Deckgrid', [ // // Register model change. // - watcher = this.$$scope.$watch('model', this.$$onModelChange.bind(this), true); + watcher = this.$$scope.$watchCollection('model', this.$$onModelChange.bind(this)); this.$$watchers.push(watcher); // @@ -133,6 +133,17 @@ angular.module('akoenig.deckgrid').factory('Deckgrid', [ return mediaQueries; }; + Deckgrid.prototype.$$cachedParams = function $$cachedParams(column) { + if (!this.$$cache) { + this.$$cache = {}; + } + if (this.$$cache.column === column) { + return this.$$cache; + } + this.$$cache = { column: column, modelLength: 0 }; + return this.$$cache; + }; + /** * @private * @@ -152,20 +163,28 @@ angular.module('akoenig.deckgrid').factory('Deckgrid', [ 'https://github.com/akoenig/angular-deckgrid#the-grid-configuration)'); } - var columns = [], columnNum = this.$$scope.layout.columns; + var cachedParams = this.$$cachedParams(this.$$scope.layout.columns); + if (cachedParams.modelLength === 0) { + // layout change, reset columns + this.$$scope.columns = []; + } - angular.forEach(this.$$scope.model, function onIteration(card, index) { - var column = (index % columnNum) | 0; + var modelLength = 0; + if (this.$$scope.model) { + modelLength = this.$$scope.model.length; + } + for (var index = cachedParams.modelLength; index < modelLength; index++) { + var card = this.$$scope.model[index]; + var column = (index % this.$$scope.layout.columns) | 0; - if (!columns[column]) { - columns[column] = []; + if (!this.$$scope.columns[column]) { + this.$$scope.columns[column] = []; } - card.$index = index; - columns[column].push(card); - }); + this.$$scope.columns[column].push(card); + } - this.$$scope.columns = columns; + cachedParams.modelLength = modelLength; }; /** From 245a78697b877e84bf775d71a842461eb4326c8e Mon Sep 17 00:00:00 2001 From: Michel Boudreau Date: Fri, 19 Sep 2014 16:03:12 +1000 Subject: [PATCH 5/5] changing some undefined check to use angular function --- angular-deckgrid.js | 6 +++--- angular-deckgrid.min.js | 2 +- src/descriptor.js | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/angular-deckgrid.js b/angular-deckgrid.js index 1aea7c6..75215c2 100644 --- a/angular-deckgrid.js +++ b/angular-deckgrid.js @@ -100,8 +100,8 @@ angular.module('akoenig.deckgrid').factory('DeckgridDescriptor', [ scope.$on('$destroy', this.$$destroy.bind(this)); - if (attrs.cardtemplate === undefined) { - if (attrs.cardtemplatestring === undefined) { + if (angular.isUndefined(attrs.cardtemplate)) { + if (angular.isUndefined(attrs.cardtemplatestring)) { // use the provided inner html as template transclude(scope, function onTransclude (innerHTML) { var extractedInnerHTML = [], @@ -112,7 +112,7 @@ angular.module('akoenig.deckgrid').factory('DeckgridDescriptor', [ for (i; i < len; i = i + 1) { outerHTML = innerHTML[i].outerHTML; - if (outerHTML !== undefined) { + if (angular.isDefined(outerHTML)) { extractedInnerHTML.push(outerHTML); } } diff --git a/angular-deckgrid.min.js b/angular-deckgrid.min.js index c722792..7744bb2 100644 --- a/angular-deckgrid.min.js +++ b/angular-deckgrid.min.js @@ -1,2 +1,2 @@ /*! angular-deckgrid (v0.4.4) - Copyright: 2013 - 2014, André König (andre.koenig@posteo.de) - MIT */ -angular.module("akoenig.deckgrid",[]),angular.module("akoenig.deckgrid").directive("deckgrid",["DeckgridDescriptor",function(a){"use strict";return a.create()}]),angular.module("akoenig.deckgrid").factory("DeckgridDescriptor",["Deckgrid","$templateCache",function(a,b){"use strict";function c(){this.restrict="AE",this.template='
',this.scope={model:"=source"},this.$$deckgrid=null,this.transclude=!0,this.link=this.$$link.bind(this),this.$$templateKeyIndex=0}return c.prototype.$$destroy=function(){this.$$deckgrid.destroy()},c.prototype.$$link=function(c,d,e,f,g){var h="deckgrid/innerHtmlTemplate"+ ++this.$$templateKeyIndex+".html";c.$on("$destroy",this.$$destroy.bind(this)),void 0===e.cardtemplate?(void 0===e.cardtemplatestring?g(c,function(a){var c,d=[],e=0,f=a.length;for(e;f>e;e+=1)c=a[e].outerHTML,void 0!==c&&d.push(c);b.put(h,d.join())}):b.put(h,d.attr("cardtemplatestring")),c.cardTemplate=h):c.cardTemplate=e.cardtemplate,c.mother=c.$parent,this.$$deckgrid=a.create(c,d[0])},{create:function(){return new c}}}]),angular.module("akoenig.deckgrid").factory("Deckgrid",["$window","$log",function(a,b){"use strict";function c(b,c){var d,e,f=this;this.$$elem=c,this.$$watchers=[],this.$$scope=b,this.$$scope.columns=[],this.$$scope.layout=this.$$getLayout(),this.$$createColumns(),d=this.$$scope.$watchCollection("model",this.$$onModelChange.bind(this)),this.$$watchers.push(d),angular.forEach(f.$$getMediaQueries(),function(a){function b(){a.removeListener(c)}var c=f.$$onMediaQueryChange.bind(f);a.addListener(c),f.$$watchers.push(b)}),e=a.matchMedia("(orientation: portrait)"),e.addListener(f.$$onMediaQueryChange.bind(f))}return c.prototype.$$getMediaQueries=function(){function b(a){try{return a.sheet.cssRules||[]}catch(b){return[]}}function c(a){var b=/\[(\w*-)?deckgrid\]::?before/g,c=0,d="";if(!a.media||angular.isUndefined(a.cssRules))return!1;for(c=a.cssRules.length-1;c>=0;c-=1)if(d=a.cssRules[c].selectorText,angular.isDefined(d)&&d.match(b))return!0;return!1}var d=[],e=[];return d=Array.prototype.concat.call(Array.prototype.slice.call(document.querySelectorAll("style[type='text/css']")),Array.prototype.slice.call(document.querySelectorAll("link[rel='stylesheet']"))),angular.forEach(d,function(d){var f=b(d);angular.forEach(f,function(b){c(b)&&e.push(a.matchMedia(b.media.mediaText))})}),e},c.prototype.$$cachedParams=function(a){return this.$$cache||(this.$$cache={}),this.$$cache.column===a?this.$$cache:(this.$$cache={column:a,modelLength:0},this.$$cache)},c.prototype.$$createColumns=function(){if(!this.$$scope.layout)return b.error("angular-deckgrid: No CSS configuration found (see https://github.com/akoenig/angular-deckgrid#the-grid-configuration)");var a=this.$$cachedParams(this.$$scope.layout.columns);0===a.modelLength&&(this.$$scope.columns=[]);var c=0;this.$$scope.model&&(c=this.$$scope.model.length);for(var d=a.modelLength;c>d;d++){var e=this.$$scope.model[d],f=d%this.$$scope.layout.columns|0;this.$$scope.columns[f]||(this.$$scope.columns[f]=[]),e.$index=d,this.$$scope.columns[f].push(e)}a.modelLength=c},c.prototype.$$getLayout=function(){var b,c=a.getComputedStyle(this.$$elem,":before").content;return c&&(c=c.replace(/'/g,""),c=c.replace(/"/g,""),c=c.split(" "),2===c.length&&(b={},b.columns=0|c[0],b.classList=c[1].replace(/\./g," ").trim())),b},c.prototype.$$onMediaQueryChange=function(){var a=this,b=this.$$getLayout();b.columns!==this.$$scope.layout.columns&&(a.$$scope.layout=b,a.$$scope.$apply(function(){a.$$createColumns()}))},c.prototype.$$onModelChange=function(a,b){var c=this;if(a=a||[],b=b||[],b.length!==a.length)c.$$createColumns();else{var d=a.length-1;for(d;d>=0;d-=1)if(b[d]!==a[d]){c.$$createColumns();break}}},c.prototype.destroy=function(){var a=this.$$watchers.length-1;for(a;a>=0;a-=1)this.$$watchers[a]()},{create:function(a,b){return new c(a,b)}}}]); \ No newline at end of file +angular.module("akoenig.deckgrid",[]),angular.module("akoenig.deckgrid").directive("deckgrid",["DeckgridDescriptor",function(a){"use strict";return a.create()}]),angular.module("akoenig.deckgrid").factory("DeckgridDescriptor",["Deckgrid","$templateCache",function(a,b){"use strict";function c(){this.restrict="AE",this.template='
',this.scope={model:"=source"},this.$$deckgrid=null,this.transclude=!0,this.link=this.$$link.bind(this),this.$$templateKeyIndex=0}return c.prototype.$$destroy=function(){this.$$deckgrid.destroy()},c.prototype.$$link=function(c,d,e,f,g){var h="deckgrid/innerHtmlTemplate"+ ++this.$$templateKeyIndex+".html";c.$on("$destroy",this.$$destroy.bind(this)),angular.isUndefined(e.cardtemplate)?(angular.isUndefined(e.cardtemplatestring)?g(c,function(a){var c,d=[],e=0,f=a.length;for(e;f>e;e+=1)c=a[e].outerHTML,angular.isDefined(c)&&d.push(c);b.put(h,d.join())}):b.put(h,d.attr("cardtemplatestring")),c.cardTemplate=h):c.cardTemplate=e.cardtemplate,c.mother=c.$parent,this.$$deckgrid=a.create(c,d[0])},{create:function(){return new c}}}]),angular.module("akoenig.deckgrid").factory("Deckgrid",["$window","$log",function(a,b){"use strict";function c(b,c){var d,e,f=this;this.$$elem=c,this.$$watchers=[],this.$$scope=b,this.$$scope.columns=[],this.$$scope.layout=this.$$getLayout(),this.$$createColumns(),d=this.$$scope.$watchCollection("model",this.$$onModelChange.bind(this)),this.$$watchers.push(d),angular.forEach(f.$$getMediaQueries(),function(a){function b(){a.removeListener(c)}var c=f.$$onMediaQueryChange.bind(f);a.addListener(c),f.$$watchers.push(b)}),e=a.matchMedia("(orientation: portrait)"),e.addListener(f.$$onMediaQueryChange.bind(f))}return c.prototype.$$getMediaQueries=function(){function b(a){try{return a.sheet.cssRules||[]}catch(b){return[]}}function c(a){var b=/\[(\w*-)?deckgrid\]::?before/g,c=0,d="";if(!a.media||angular.isUndefined(a.cssRules))return!1;for(c=a.cssRules.length-1;c>=0;c-=1)if(d=a.cssRules[c].selectorText,angular.isDefined(d)&&d.match(b))return!0;return!1}var d=[],e=[];return d=Array.prototype.concat.call(Array.prototype.slice.call(document.querySelectorAll("style[type='text/css']")),Array.prototype.slice.call(document.querySelectorAll("link[rel='stylesheet']"))),angular.forEach(d,function(d){var f=b(d);angular.forEach(f,function(b){c(b)&&e.push(a.matchMedia(b.media.mediaText))})}),e},c.prototype.$$cachedParams=function(a){return this.$$cache||(this.$$cache={}),this.$$cache.column===a?this.$$cache:(this.$$cache={column:a,modelLength:0},this.$$cache)},c.prototype.$$createColumns=function(){if(!this.$$scope.layout)return b.error("angular-deckgrid: No CSS configuration found (see https://github.com/akoenig/angular-deckgrid#the-grid-configuration)");var a=this.$$cachedParams(this.$$scope.layout.columns);0===a.modelLength&&(this.$$scope.columns=[]);var c=0;this.$$scope.model&&(c=this.$$scope.model.length);for(var d=a.modelLength;c>d;d++){var e=this.$$scope.model[d],f=d%this.$$scope.layout.columns|0;this.$$scope.columns[f]||(this.$$scope.columns[f]=[]),e.$index=d,this.$$scope.columns[f].push(e)}a.modelLength=c},c.prototype.$$getLayout=function(){var b,c=a.getComputedStyle(this.$$elem,":before").content;return c&&(c=c.replace(/'/g,""),c=c.replace(/"/g,""),c=c.split(" "),2===c.length&&(b={},b.columns=0|c[0],b.classList=c[1].replace(/\./g," ").trim())),b},c.prototype.$$onMediaQueryChange=function(){var a=this,b=this.$$getLayout();b.columns!==this.$$scope.layout.columns&&(a.$$scope.layout=b,a.$$scope.$apply(function(){a.$$createColumns()}))},c.prototype.$$onModelChange=function(a,b){var c=this;if(a=a||[],b=b||[],b.length!==a.length)c.$$createColumns();else{var d=a.length-1;for(d;d>=0;d-=1)if(b[d]!==a[d]){c.$$createColumns();break}}},c.prototype.destroy=function(){var a=this.$$watchers.length-1;for(a;a>=0;a-=1)this.$$watchers[a]()},{create:function(a,b){return new c(a,b)}}}]); \ No newline at end of file diff --git a/src/descriptor.js b/src/descriptor.js index 8fdad69..175b6f7 100644 --- a/src/descriptor.js +++ b/src/descriptor.js @@ -73,8 +73,8 @@ angular.module('akoenig.deckgrid').factory('DeckgridDescriptor', [ scope.$on('$destroy', this.$$destroy.bind(this)); - if (attrs.cardtemplate === undefined) { - if (attrs.cardtemplatestring === undefined) { + if (angular.isUndefined(attrs.cardtemplate)) { + if (angular.isUndefined(attrs.cardtemplatestring)) { // use the provided inner html as template transclude(scope, function onTransclude (innerHTML) { var extractedInnerHTML = [], @@ -85,7 +85,7 @@ angular.module('akoenig.deckgrid').factory('DeckgridDescriptor', [ for (i; i < len; i = i + 1) { outerHTML = innerHTML[i].outerHTML; - if (outerHTML !== undefined) { + if (angular.isDefined(outerHTML)) { extractedInnerHTML.push(outerHTML); } }