nexus site path corrected
[portal.git] / ecomp-portal-FE / client / bower_components / angular-smart-table / dist / smart-table.js
1 /** 
2 * @version 2.1.8
3 * @license MIT
4 */
5 (function (ng, undefined){
6     'use strict';
7
8 ng.module('smart-table', []).run(['$templateCache', function ($templateCache) {
9     $templateCache.put('template/smart-table/pagination.html',
10         '<nav ng-if="numPages && pages.length >= 2"><ul class="pagination">' +
11         '<li ng-repeat="page in pages" ng-class="{active: page==currentPage}"><a href="javascript: void(0);" ng-click="selectPage(page)">{{page}}</a></li>' +
12         '</ul></nav>');
13 }]);
14
15
16 ng.module('smart-table')
17   .constant('stConfig', {
18     pagination: {
19       template: 'template/smart-table/pagination.html',
20       itemsByPage: 10,
21       displayedPages: 5
22     },
23     search: {
24       delay: 400, // ms
25       inputEvent: 'input'
26     },
27     select: {
28       mode: 'single',
29       selectedClass: 'st-selected'
30     },
31     sort: {
32       ascentClass: 'st-sort-ascent',
33       descentClass: 'st-sort-descent',
34       descendingFirst: false,
35       skipNatural: false,
36       delay:300
37     },
38     pipe: {
39       delay: 100 //ms
40     }
41   });
42 ng.module('smart-table')
43   .controller('stTableController', ['$scope', '$parse', '$filter', '$attrs', function StTableController ($scope, $parse, $filter, $attrs) {
44     var propertyName = $attrs.stTable;
45     var displayGetter = $parse(propertyName);
46     var displaySetter = displayGetter.assign;
47     var safeGetter;
48     var orderBy = $filter('orderBy');
49     var filter = $filter('filter');
50     var safeCopy = copyRefs(displayGetter($scope));
51     var tableState = {
52       sort: {},
53       search: {},
54       pagination: {
55         start: 0,
56         totalItemCount: 0
57       }
58     };
59     var filtered;
60     var pipeAfterSafeCopy = true;
61     var ctrl = this;
62     var lastSelected;
63
64     function copyRefs (src) {
65       return src ? [].concat(src) : [];
66     }
67
68     function updateSafeCopy () {
69       safeCopy = copyRefs(safeGetter($scope));
70       if (pipeAfterSafeCopy === true) {
71         ctrl.pipe();
72       }
73     }
74
75     function deepDelete (object, path) {
76       if (path.indexOf('.') != -1) {
77         var partials = path.split('.');
78         var key = partials.pop();
79         var parentPath = partials.join('.');
80         var parentObject = $parse(parentPath)(object)
81         delete parentObject[key];
82         if (Object.keys(parentObject).length == 0) {
83           deepDelete(object, parentPath);
84         }
85       } else {
86         delete object[path];
87       }
88     }
89
90     if ($attrs.stSafeSrc) {
91       safeGetter = $parse($attrs.stSafeSrc);
92       $scope.$watch(function () {
93         var safeSrc = safeGetter($scope);
94         return safeSrc && safeSrc.length ? safeSrc[0] : undefined;
95       }, function (newValue, oldValue) {
96         if (newValue !== oldValue) {
97           updateSafeCopy();
98         }
99       });
100       $scope.$watch(function () {
101         var safeSrc = safeGetter($scope);
102         return safeSrc ? safeSrc.length : 0;
103       }, function (newValue, oldValue) {
104         if (newValue !== safeCopy.length) {
105           updateSafeCopy();
106         }
107       });
108       $scope.$watch(function () {
109         return safeGetter($scope);
110       }, function (newValue, oldValue) {
111         if (newValue !== oldValue) {
112           tableState.pagination.start = 0;
113           updateSafeCopy();
114         }
115       });
116     }
117
118     /**
119      * sort the rows
120      * @param {Function | String} predicate - function or string which will be used as predicate for the sorting
121      * @param [reverse] - if you want to reverse the order
122      */
123     this.sortBy = function sortBy (predicate, reverse) {
124       tableState.sort.predicate = predicate;
125       tableState.sort.reverse = reverse === true;
126
127       if (ng.isFunction(predicate)) {
128         tableState.sort.functionName = predicate.name;
129       } else {
130         delete tableState.sort.functionName;
131       }
132
133       tableState.pagination.start = 0;
134       return this.pipe();
135     };
136
137     /**
138      * search matching rows
139      * @param {String} input - the input string
140      * @param {String} [predicate] - the property name against you want to check the match, otherwise it will search on all properties
141      */
142     this.search = function search (input, predicate) {
143       var predicateObject = tableState.search.predicateObject || {};
144       var prop = predicate ? predicate : '$';
145
146       input = ng.isString(input) ? input.trim() : input;
147       $parse(prop).assign(predicateObject, input);
148       // to avoid to filter out null value
149       if (!input) {
150         deepDelete(predicateObject, prop);
151       }
152       tableState.search.predicateObject = predicateObject;
153       tableState.pagination.start = 0;
154       return this.pipe();
155     };
156
157     /**
158      * this will chain the operations of sorting and filtering based on the current table state (sort options, filtering, ect)
159      */
160     this.pipe = function pipe () {
161       var pagination = tableState.pagination;
162       var output;
163       filtered = tableState.search.predicateObject ? filter(safeCopy, tableState.search.predicateObject) : safeCopy;
164       if (tableState.sort.predicate) {
165         filtered = orderBy(filtered, tableState.sort.predicate, tableState.sort.reverse);
166       }
167       pagination.totalItemCount = filtered.length;
168       if (pagination.number !== undefined) {
169         pagination.numberOfPages = filtered.length > 0 ? Math.ceil(filtered.length / pagination.number) : 1;
170         pagination.start = pagination.start >= filtered.length ? (pagination.numberOfPages - 1) * pagination.number : pagination.start;
171         output = filtered.slice(pagination.start, pagination.start + parseInt(pagination.number));
172       }
173       displaySetter($scope, output || filtered);
174     };
175
176     /**
177      * select a dataRow (it will add the attribute isSelected to the row object)
178      * @param {Object} row - the row to select
179      * @param {String} [mode] - "single" or "multiple" (multiple by default)
180      */
181     this.select = function select (row, mode) {
182       var rows = copyRefs(displayGetter($scope));
183       var index = rows.indexOf(row);
184       if (index !== -1) {
185         if (mode === 'single') {
186           row.isSelected = row.isSelected !== true;
187           if (lastSelected) {
188             lastSelected.isSelected = false;
189           }
190           lastSelected = row.isSelected === true ? row : undefined;
191         } else {
192           rows[index].isSelected = !rows[index].isSelected;
193         }
194       }
195     };
196
197     /**
198      * take a slice of the current sorted/filtered collection (pagination)
199      *
200      * @param {Number} start - start index of the slice
201      * @param {Number} number - the number of item in the slice
202      */
203     this.slice = function splice (start, number) {
204       tableState.pagination.start = start;
205       tableState.pagination.number = number;
206       return this.pipe();
207     };
208
209     /**
210      * return the current state of the table
211      * @returns {{sort: {}, search: {}, pagination: {start: number}}}
212      */
213     this.tableState = function getTableState () {
214       return tableState;
215     };
216
217     this.getFilteredCollection = function getFilteredCollection () {
218       return filtered || safeCopy;
219     };
220
221     /**
222      * Use a different filter function than the angular FilterFilter
223      * @param filterName the name under which the custom filter is registered
224      */
225     this.setFilterFunction = function setFilterFunction (filterName) {
226       filter = $filter(filterName);
227     };
228
229     /**
230      * Use a different function than the angular orderBy
231      * @param sortFunctionName the name under which the custom order function is registered
232      */
233     this.setSortFunction = function setSortFunction (sortFunctionName) {
234       orderBy = $filter(sortFunctionName);
235     };
236
237     /**
238      * Usually when the safe copy is updated the pipe function is called.
239      * Calling this method will prevent it, which is something required when using a custom pipe function
240      */
241     this.preventPipeOnWatch = function preventPipe () {
242       pipeAfterSafeCopy = false;
243     };
244   }])
245   .directive('stTable', function () {
246     return {
247       restrict: 'A',
248       controller: 'stTableController',
249       link: function (scope, element, attr, ctrl) {
250
251         if (attr.stSetFilter) {
252           ctrl.setFilterFunction(attr.stSetFilter);
253         }
254
255         if (attr.stSetSort) {
256           ctrl.setSortFunction(attr.stSetSort);
257         }
258       }
259     };
260   });
261
262 ng.module('smart-table')
263   .directive('stSearch', ['stConfig', '$timeout','$parse', function (stConfig, $timeout, $parse) {
264     return {
265       require: '^stTable',
266       link: function (scope, element, attr, ctrl) {
267         var tableCtrl = ctrl;
268         var promise = null;
269         var throttle = attr.stDelay || stConfig.search.delay;
270         var event = attr.stInputEvent || stConfig.search.inputEvent;
271
272         attr.$observe('stSearch', function (newValue, oldValue) {
273           var input = element[0].value;
274           if (newValue !== oldValue && input) {
275             ctrl.tableState().search = {};
276             tableCtrl.search(input, newValue);
277           }
278         });
279
280         //table state -> view
281         scope.$watch(function () {
282           return ctrl.tableState().search;
283         }, function (newValue, oldValue) {
284           var predicateExpression = attr.stSearch || '$';
285           if (newValue.predicateObject && $parse(predicateExpression)(newValue.predicateObject) !== element[0].value) {
286             element[0].value = $parse(predicateExpression)(newValue.predicateObject) || '';
287           }
288         }, true);
289
290         // view -> table state
291         element.bind(event, function (evt) {
292           evt = evt.originalEvent || evt;
293           if (promise !== null) {
294             $timeout.cancel(promise);
295           }
296
297           promise = $timeout(function () {
298             tableCtrl.search(evt.target.value, attr.stSearch || '');
299             promise = null;
300           }, throttle);
301         });
302       }
303     };
304   }]);
305
306 ng.module('smart-table')
307   .directive('stSelectRow', ['stConfig', function (stConfig) {
308     return {
309       restrict: 'A',
310       require: '^stTable',
311       scope: {
312         row: '=stSelectRow'
313       },
314       link: function (scope, element, attr, ctrl) {
315         var mode = attr.stSelectMode || stConfig.select.mode;
316         element.bind('click', function () {
317           scope.$apply(function () {
318             ctrl.select(scope.row, mode);
319           });
320         });
321
322         scope.$watch('row.isSelected', function (newValue) {
323           if (newValue === true) {
324             element.addClass(stConfig.select.selectedClass);
325           } else {
326             element.removeClass(stConfig.select.selectedClass);
327           }
328         });
329       }
330     };
331   }]);
332
333 ng.module('smart-table')
334   .directive('stSort', ['stConfig', '$parse', '$timeout', function (stConfig, $parse, $timeout) {
335     return {
336       restrict: 'A',
337       require: '^stTable',
338       link: function (scope, element, attr, ctrl) {
339
340         var predicate = attr.stSort;
341         var getter = $parse(predicate);
342         var index = 0;
343         var classAscent = attr.stClassAscent || stConfig.sort.ascentClass;
344         var classDescent = attr.stClassDescent || stConfig.sort.descentClass;
345         var stateClasses = [classAscent, classDescent];
346         var sortDefault;
347         var skipNatural = attr.stSkipNatural !== undefined ? attr.stSkipNatural : stConfig.sort.skipNatural;
348         var descendingFirst = attr.stDescendingFirst !== undefined ? attr.stDescendingFirst : stConfig.sort.descendingFirst;
349         var promise = null;
350         var throttle = attr.stDelay || stConfig.sort.delay;
351
352         if (attr.stSortDefault) {
353           sortDefault = scope.$eval(attr.stSortDefault) !== undefined ? scope.$eval(attr.stSortDefault) : attr.stSortDefault;
354         }
355
356         //view --> table state
357         function sort () {
358           if (descendingFirst) {
359             index = index === 0 ? 2 : index - 1;
360           } else {
361             index++;
362           }
363
364           var func;
365           predicate = ng.isFunction(getter(scope)) || ng.isArray(getter(scope)) ? getter(scope) : attr.stSort;
366           if (index % 3 === 0 && !!skipNatural !== true) {
367             //manual reset
368             index = 0;
369             ctrl.tableState().sort = {};
370             ctrl.tableState().pagination.start = 0;
371             func = ctrl.pipe.bind(ctrl);
372           } else {
373             func = ctrl.sortBy.bind(ctrl, predicate, index % 2 === 0);
374           }
375           if (promise !== null) {
376             $timeout.cancel(promise);
377           }
378           if (throttle < 0) {
379             func();
380           } else {
381             promise = $timeout(func, throttle);
382           }
383         }
384
385         element.bind('click', function sortClick () {
386           if (predicate) {
387             scope.$apply(sort);
388           }
389         });
390
391         if (sortDefault) {
392           index = sortDefault === 'reverse' ? 1 : 0;
393           sort();
394         }
395
396         //table state --> view
397         scope.$watch(function () {
398           return ctrl.tableState().sort;
399         }, function (newValue) {
400           if (newValue.predicate !== predicate) {
401             index = 0;
402             element
403               .removeClass(classAscent)
404               .removeClass(classDescent);
405           } else {
406             index = newValue.reverse === true ? 2 : 1;
407             element
408               .removeClass(stateClasses[index % 2])
409               .addClass(stateClasses[index - 1]);
410           }
411         }, true);
412       }
413     };
414   }]);
415
416 ng.module('smart-table')
417   .directive('stPagination', ['stConfig', function (stConfig) {
418     return {
419       restrict: 'EA',
420       require: '^stTable',
421       scope: {
422         stItemsByPage: '=?',
423         stDisplayedPages: '=?',
424         stPageChange: '&'
425       },
426       templateUrl: function (element, attrs) {
427         if (attrs.stTemplate) {
428           return attrs.stTemplate;
429         }
430         return stConfig.pagination.template;
431       },
432       link: function (scope, element, attrs, ctrl) {
433
434         scope.stItemsByPage = scope.stItemsByPage ? +(scope.stItemsByPage) : stConfig.pagination.itemsByPage;
435         scope.stDisplayedPages = scope.stDisplayedPages ? +(scope.stDisplayedPages) : stConfig.pagination.displayedPages;
436
437         scope.currentPage = 1;
438         scope.pages = [];
439
440         function redraw () {
441           var paginationState = ctrl.tableState().pagination;
442           var start = 1;
443           var end;
444           var i;
445           var prevPage = scope.currentPage;
446           scope.totalItemCount = paginationState.totalItemCount;
447           scope.currentPage = Math.floor(paginationState.start / paginationState.number) + 1;
448
449           start = Math.max(start, scope.currentPage - Math.abs(Math.floor(scope.stDisplayedPages / 2)));
450           end = start + scope.stDisplayedPages;
451
452           if (end > paginationState.numberOfPages) {
453             end = paginationState.numberOfPages + 1;
454             start = Math.max(1, end - scope.stDisplayedPages);
455           }
456
457           scope.pages = [];
458           scope.numPages = paginationState.numberOfPages;
459
460           for (i = start; i < end; i++) {
461             scope.pages.push(i);
462           }
463
464           if (prevPage !== scope.currentPage) {
465             scope.stPageChange({newPage: scope.currentPage});
466           }
467         }
468
469         //table state --> view
470         scope.$watch(function () {
471           return ctrl.tableState().pagination;
472         }, redraw, true);
473
474         //scope --> table state  (--> view)
475         scope.$watch('stItemsByPage', function (newValue, oldValue) {
476           if (newValue !== oldValue) {
477             scope.selectPage(1);
478           }
479         });
480
481         scope.$watch('stDisplayedPages', redraw);
482
483         //view -> table state
484         scope.selectPage = function (page) {
485           if (page > 0 && page <= scope.numPages) {
486             ctrl.slice((page - 1) * scope.stItemsByPage, scope.stItemsByPage);
487           }
488         };
489
490         if (!ctrl.tableState().pagination.number) {
491           ctrl.slice(0, scope.stItemsByPage);
492         }
493       }
494     };
495   }]);
496
497 ng.module('smart-table')
498   .directive('stPipe', ['stConfig', '$timeout', function (config, $timeout) {
499     return {
500       require: 'stTable',
501       scope: {
502         stPipe: '='
503       },
504       link: {
505
506         pre: function (scope, element, attrs, ctrl) {
507
508           var pipePromise = null;
509
510           if (ng.isFunction(scope.stPipe)) {
511             ctrl.preventPipeOnWatch();
512             ctrl.pipe = function () {
513
514               if (pipePromise !== null) {
515                 $timeout.cancel(pipePromise)
516               }
517
518               pipePromise = $timeout(function () {
519                 scope.stPipe(ctrl.tableState(), ctrl);
520               }, config.pipe.delay);
521
522               return pipePromise;
523             }
524           }
525         },
526
527         post: function (scope, element, attrs, ctrl) {
528           ctrl.pipe();
529         }
530       }
531     };
532   }]);
533
534 })(angular);