Codebase list libjs-angularjs-smart-table / e8b1a39
Import upstream version 2.1.11+git20180109.1.4dd9d0d Debian Janitor 2 years ago
25 changed file(s) with 1186 addition(s) and 427 deletion(s). Raw diff Collapse all Expand all
+0
-7
.gitignore less more
0 .idea
1 node_modules
2 example-app
3 bower_components
4 coverage
5 .DS_Store
6 test/.DS_Store
00 language: node_js
11 node_js:
2 - "0.10"
3
2 - "8"
43
54 before_script:
6 - npm install -g gulp bower
75 - npm install
8 - bower install
96
107 script:
118 - gulp build
0 ## Hello contributor !
1
2 Please before you submit your issue, make sure all the below can be checked (note if anything is expected, you can simply add it under the relevant checkbox)
3
4 - [ ] I have searched through the issue section and on [stackoverflow](http://stackoverflow.com/questions/tagged/smart-table?sort=newest&pageSize=30) if my issue has already been raised.
5 - [ ] I have provided Angular version.
6 - [ ] I have provided Smart table version.
7 - [ ] I have set a precise description of my problem, mentioning the expected result.
8 - [ ] I have given a way to reproduce my issue, by providing a <strong>running example</strong>, I can use [plunkr](http://plnkr.co/). Note if you want to mimic ajax loading behaviour you can use [$timeout](https://docs.angularjs.org/api/ng/service/$timeout) angular service or [$httpBackend](https://docs.angularjs.org/api/ng/service/$httpBackend).
9
10 Note that it not all the above checkbox can be marked as checked the issue will immediately be closed. Thanks for your understanding.
11
12 And don't forget to close you issue when it is solved !
13
14 Thanks again for your contribution.
00 {
1 "name": "angular-smart-table",
2 "version": "1.4.13",
3 "homepage": "https://github.com/lorenzofox3/Smart-Table",
4 "authors": [
5 "lorenzofox3 <laurent34azerty@gmail.com>"
6 ],
7 "description": "table module for angular",
8 "main": "dist/smart-table.js",
9 "keywords": [
10 "smart-table",
11 "angular",
12 "table"
13 ],
14 "license": "MIT",
15 "ignore": [
16 "node_modules",
17 "bower_components",
18 "test",
19 "tests"
20 ],
21 "dependencies": {
22 "angular": "latest"
23 },
24 "devDependencies": {
25 "angular-mocks": "latest",
26 "jquery": "latest"
27 }
1 "name": "angular-smart-table",
2 "description": "smart table component for angular v < 2.0",
3 "main": "./dist/smart-table.js",
4 "authors": [
5 "Laurent Renard"
6 ],
7 "license": "MIT",
8 "keywords": [
9 "smart-table",
10 "table",
11 "grid",
12 "angular"
13 ],
14 "homepage": "https://github.com/lorenzofox3/Smart-Table",
15 "ignore": [
16 "**/.*",
17 "node_modules",
18 "bower_components",
19 "test",
20 "tests"
21 ]
2822 }
00 ## version 1.1.0
11
2 * allow binding on search predicate [https://github.com/lorenzofox3/Smart-Table/issues/142] (issue 142)
2 * allow binding on search predicate ([#142](https://github.com/lorenzofox3/Smart-Table/issues/142)).
33 Note that if you want to search against a property name you have now to put in under single quote otherwise it will be considered as a binding
44 ```markup
55 <input st-search="'name'"/>
77
88 ## version 1.1.1
99
10 * fix #146 and #148, set stPipe before stPagination is called. Thanks [brianchance](https://github.com/brianchance)
10 * fix [#146](https://github.com/lorenzofox3/Smart-Table/issues/146) and [#148](https://github.com/lorenzofox3/Smart-Table/issues/148), set stPipe before stPagination is called. Thanks [brianchance](https://github.com/brianchance)
1111
1212 ## version 1.2.1
1313
14 * implement #149 (default sorting)
14 * implement [#149](https://github.com/lorenzofox3/Smart-Table/issues/149) (default sorting)
1515
1616 ## version 1.2.2
1717
2525
2626 ## version 1.2.4
2727
28 * fix #161
28 * fix [#161](https://github.com/lorenzofox3/Smart-Table/issues/161)
2929
3030 ## version 1.2.5
3131
32 * fix #162
32 * fix [#162](https://github.com/lorenzofox3/Smart-Table/issues/162)
3333
3434 ## version 1.2.6
3535
36 * fix #165
36 * fix [#165](https://github.com/lorenzofox3/Smart-Table/issues/165)
3737 * ability to overwrite class names for (st-sort-ascent and st-sort-descent) thanks to [replacement87](https://github.com/replacement87)
3838
3939 ## version 1.2.7
4040
41 * fix #167
41 * fix [#167](https://github.com/lorenzofox3/Smart-Table/issues/167)
4242
4343 ## version 1.3.0
4444
5151
5252 ## version 1.4.1
5353
54 * ability to skip natural ordering state (ie fix #192)
54 * ability to skip natural ordering state (ie fix [#192](https://github.com/lorenzofox3/Smart-Table/issues/192))
5555
5656 ## versiokn 1.4.2
5757
58 * fix #200, `this` in a custom pipe function does not refer to the table controller anymore, and the signature of a custom pipe function is
58 * fix [#200](https://github.com/lorenzofox3/Smart-Table/issues/200), `this` in a custom pipe function does not refer to the table controller anymore, and the signature of a custom pipe function is
5959 ```javascript
6060 function(tableState, tableController){
6161
7373
7474 ## version 1.4.5
7575
76 * merge #234, #218
77 * fix #233 #237
76 * merge [#234](https://github.com/lorenzofox3/Smart-Table/issues/234), [#218](https://github.com/lorenzofox3/Smart-Table/issues/218)
77 * fix [#233](https://github.com/lorenzofox3/Smart-Table/issues/2332), [#237](https://github.com/lorenzofox3/Smart-Table/issues/237)
7878
7979 ## version 1.4.6
8080
8181 * evaluate sort predicate as late as possible
82 * fix #262
82 * fix [#262](https://github.com/lorenzofox3/Smart-Table/issues/262)
8383
8484 ## version 1.4.7
8585
86 * fix #276
86 * fix [#276](https://github.com/lorenzofox3/Smart-Table/issues/276)
8787
8888 ## version 1.4.8
8989
90 * fix #281
90 * fix [#281](https://github.com/lorenzofox3/Smart-Table/issues/281)
9191
9292 ## version 1.4.9
9393
94 * fix #285
94 * fix [#285](https://github.com/lorenzofox3/Smart-Table/issues/285)
9595
9696 ## version 1.4.10
9797
98 * fix #284
99 * fix #290
98 * fix [#284](https://github.com/lorenzofox3/Smart-Table/issues/284)
99 * fix [#290](https://github.com/lorenzofox3/Smart-Table/issues/290)
100100
101101 ## version 1.4.11
102102
103 * fix #296
103 * fix [#296](https://github.com/lorenzofox3/Smart-Table/issues/296)
104104 * add possibility to bind a callback when page changes
105105
106106 ## version 1.4.12
113113 * use a global configuration
114114 * expose filtered collection result
115115
116 ## version 2.0.0
117
118 * use interpolation rather than binding for st-search directive (to avoid the creation of isolated scope)
119
120 **This is a breaking change as now, you will have to remove the single quote around the predicate property name, and if you were using a binding, you'll have to interpolate it with the curly brace notation**
121
122 ## version 2.0.1
123
124 * fix [#328](https://github.com/lorenzofox3/Smart-Table/issues/328)
125
126 ## version 2.0.2
127
128 * add debounce to custom pipe function to make sure tableState is stable
129 * fix [#329](https://github.com/lorenzofox3/Smart-Table/issues/329)
130
131 ## version 2.0.3
132
133 * implements [#379](https://github.com/lorenzofox3/Smart-Table/issues/379)
134 * fix [#390](https://github.com/lorenzofox3/Smart-Table/issues/390)
135
136 ## version 2.1.0
137
138 * support nested search (thanks to @jansabbe)
139 * fix [#254](https://github.com/lorenzofox3/Smart-Table/issues/254)
140 * fix wrong path to default config for stSkipNatural (@phuvo)
141 * fix [#406](https://github.com/lorenzofox3/Smart-Table/issues/406)
142
143 ## version 2.1.1
144
145 * support commonjs
146 * add totalItemCount on tableState (@eirikbell)
147
148 ## version 2.1.2
149
150 * improve build [#461](https://github.com/lorenzofox3/Smart-Table/issues/461) [stanleyxu](https://github.com/stanleyxu2005)
151
152 ## version 2.1.3
153
154 * fix [#477](https://github.com/lorenzofox3/Smart-Table/issues/477)
155
156 ## version 2.1.4
157
158 * add throttle to sort
159 * add watch to first item in collection (@matthewbednarski)
160
161 ## version 2.1.5
162
163 * added multiple sort support to st-sort, [#544](https://github.com/lorenzofox3/Smart-Table/issues/544)
164 * fix [#533](https://github.com/lorenzofox3/Smart-Table/issues/533)
165 * fix [#515](https://github.com/lorenzofox3/Smart-Table/issues/515)
166
167 ## version 2.1.6
168
169 * fix [#559](https://github.com/lorenzofox3/Smart-Table/issues/559)
170
171 ## version 2.1.7
172
173 * fix [#468](https://github.com/lorenzofox3/Smart-Table/issues/468) thanks to Douglas-Treadwell
174
00 /**
1 * @version 1.4.13
1 * @version 2.1.11
22 * @license MIT
33 */
44 (function (ng, undefined){
66
77 ng.module('smart-table', []).run(['$templateCache', function ($templateCache) {
88 $templateCache.put('template/smart-table/pagination.html',
9 '<nav ng-if="pages.length >= 2"><ul class="pagination">' +
10 '<li ng-repeat="page in pages" ng-class="{active: page==currentPage}"><a ng-click="selectPage(page)">{{page}}</a></li>' +
9 '<nav ng-if="numPages && pages.length >= 2"><ul class="pagination">' +
10 '<li ng-repeat="page in pages" ng-class="{active: page==currentPage}"><a href="#" ng-click="selectPage(page); $event.preventDefault(); $event.stopPropagation();">{{page}}</a></li>' +
1111 '</ul></nav>');
1212 }]);
1313
2020 displayedPages: 5
2121 },
2222 search: {
23 delay: 400 // ms
23 delay: 400, // ms
24 inputEvent: 'input',
25 trimSearch: false
2426 },
2527 select: {
2628 mode: 'single',
2830 },
2931 sort: {
3032 ascentClass: 'st-sort-ascent',
31 descentClass: 'st-sort-descent'
33 descentClass: 'st-sort-descent',
34 descendingFirst: false,
35 skipNatural: false,
36 delay:300
37 },
38 pipe: {
39 delay: 100 //ms
3240 }
3341 });
34 ng.module('smart-table')
35 .controller('stTableController', ['$scope', '$parse', '$filter', '$attrs', function StTableController ($scope, $parse, $filter, $attrs) {
42 ng.module('smart-table').controller('stTableController', [
43 '$scope',
44 '$parse',
45 '$filter',
46 '$attrs',
47 function StTableController($scope, $parse, $filter, $attrs) {
3648 var propertyName = $attrs.stTable;
3749 var displayGetter = $parse(propertyName);
3850 var displaySetter = displayGetter.assign;
4355 var tableState = {
4456 sort: {},
4557 search: {},
46 pagination: {
47 start: 0
48 }
58 pagination: { start: 0, totalItemCount: 0 }
4959 };
5060 var filtered;
5161 var pipeAfterSafeCopy = true;
5262 var ctrl = this;
5363 var lastSelected;
5464
55 function copyRefs (src) {
65 function copyRefs(src) {
5666 return src ? [].concat(src) : [];
5767 }
5868
59 function updateSafeCopy () {
69 function updateSafeCopy() {
6070 safeCopy = copyRefs(safeGetter($scope));
6171 if (pipeAfterSafeCopy === true) {
6272 ctrl.pipe();
6373 }
6474 }
6575
76 function deepDelete(object, path) {
77 if (path.indexOf('.') != -1) {
78 var partials = path.split('.');
79 var key = partials.pop();
80 var parentPath = partials.join('.');
81 var parentObject = $parse(parentPath)(object);
82 delete parentObject[key];
83 if (Object.keys(parentObject).length == 0) {
84 deepDelete(object, parentPath);
85 }
86 } else {
87 delete object[path];
88 }
89 }
90
6691 if ($attrs.stSafeSrc) {
6792 safeGetter = $parse($attrs.stSafeSrc);
68 $scope.$watch(function () {
69 var safeSrc = safeGetter($scope);
70 return safeSrc ? safeSrc.length : 0;
71
72 }, function (newValue, oldValue) {
73 if (newValue !== safeCopy.length) {
74 updateSafeCopy();
75 }
76 });
77 $scope.$watch(function () {
78 return safeGetter($scope);
79 }, function (newValue, oldValue) {
80 if (newValue !== oldValue) {
81 updateSafeCopy();
82 }
83 });
93 $scope.$watch(
94 function() {
95 var safeSrc = safeGetter($scope);
96 return safeSrc && safeSrc.length ? safeSrc[0] : undefined;
97 },
98 function(newValue, oldValue) {
99 if (newValue !== oldValue) {
100 updateSafeCopy();
101 }
102 }
103 );
104 $scope.$watch(
105 function() {
106 var safeSrc = safeGetter($scope);
107 return safeSrc ? safeSrc.length : 0;
108 },
109 function(newValue, oldValue) {
110 if (newValue !== safeCopy.length) {
111 updateSafeCopy();
112 }
113 }
114 );
115 $scope.$watch(
116 function() {
117 return safeGetter($scope);
118 },
119 function(newValue, oldValue) {
120 if (newValue !== oldValue) {
121 tableState.pagination.start = 0;
122 updateSafeCopy();
123 }
124 }
125 );
84126 }
85127
86128 /**
88130 * @param {Function | String} predicate - function or string which will be used as predicate for the sorting
89131 * @param [reverse] - if you want to reverse the order
90132 */
91 this.sortBy = function sortBy (predicate, reverse) {
133 this.sortBy = function sortBy(predicate, reverse) {
92134 tableState.sort.predicate = predicate;
93135 tableState.sort.reverse = reverse === true;
94136
106148 * search matching rows
107149 * @param {String} input - the input string
108150 * @param {String} [predicate] - the property name against you want to check the match, otherwise it will search on all properties
109 */
110 this.search = function search (input, predicate) {
151 * @param {String | Function } [comparator] - a comparator to pass to the filter for the (pass true for stric mode)
152 */
153 this.search = function search(input, predicate, comparator) {
111154 var predicateObject = tableState.search.predicateObject || {};
112155 var prop = predicate ? predicate : '$';
113156
114 input = ng.isString(input) ? input.trim() : input;
115 predicateObject[prop] = input;
157 $parse(prop).assign(predicateObject, input);
116158 // to avoid to filter out null value
117159 if (!input) {
118 delete predicateObject[prop];
160 deepDelete(predicateObject, prop);
119161 }
120162 tableState.search.predicateObject = predicateObject;
121163 tableState.pagination.start = 0;
125167 /**
126168 * this will chain the operations of sorting and filtering based on the current table state (sort options, filtering, ect)
127169 */
128 this.pipe = function pipe () {
170 this.pipe = function pipe() {
129171 var pagination = tableState.pagination;
130172 var output;
131 filtered = tableState.search.predicateObject ? filter(safeCopy, tableState.search.predicateObject) : safeCopy;
173 filtered = tableState.search.predicateObject
174 ? filter(safeCopy, tableState.search.predicateObject)
175 : safeCopy;
132176 if (tableState.sort.predicate) {
133 filtered = orderBy(filtered, tableState.sort.predicate, tableState.sort.reverse);
134 }
177 filtered = orderBy(
178 filtered,
179 tableState.sort.predicate,
180 tableState.sort.reverse
181 );
182 }
183 pagination.totalItemCount = filtered.length;
135184 if (pagination.number !== undefined) {
136 pagination.numberOfPages = filtered.length > 0 ? Math.ceil(filtered.length / pagination.number) : 1;
137 pagination.start = pagination.start >= filtered.length ? (pagination.numberOfPages - 1) * pagination.number : pagination.start;
138 output = filtered.slice(pagination.start, pagination.start + parseInt(pagination.number));
185 pagination.numberOfPages = filtered.length > 0
186 ? Math.ceil(filtered.length / pagination.number)
187 : 1;
188 pagination.start = pagination.start >= filtered.length
189 ? (pagination.numberOfPages - 1) * pagination.number
190 : pagination.start;
191 output = filtered.slice(
192 pagination.start,
193 pagination.start + parseInt(pagination.number)
194 );
139195 }
140196 displaySetter($scope, output || filtered);
141197 };
145201 * @param {Object} row - the row to select
146202 * @param {String} [mode] - "single" or "multiple" (multiple by default)
147203 */
148 this.select = function select (row, mode) {
149 var rows = safeCopy;
204 this.select = function select(row, mode) {
205 var rows = copyRefs(displayGetter($scope));
150206 var index = rows.indexOf(row);
151207 if (index !== -1) {
152208 if (mode === 'single') {
167223 * @param {Number} start - start index of the slice
168224 * @param {Number} number - the number of item in the slice
169225 */
170 this.slice = function splice (start, number) {
226 this.slice = function splice(start, number) {
171227 tableState.pagination.start = start;
172228 tableState.pagination.number = number;
173229 return this.pipe();
177233 * return the current state of the table
178234 * @returns {{sort: {}, search: {}, pagination: {start: number}}}
179235 */
180 this.tableState = function getTableState () {
236 this.tableState = function getTableState() {
181237 return tableState;
182238 };
183239
184 this.getFilteredCollection = function getFilteredCollection () {
240 this.getFilteredCollection = function getFilteredCollection() {
185241 return filtered || safeCopy;
186242 };
187243
189245 * Use a different filter function than the angular FilterFilter
190246 * @param filterName the name under which the custom filter is registered
191247 */
192 this.setFilterFunction = function setFilterFunction (filterName) {
248 this.setFilterFunction = function setFilterFunction(filterName) {
193249 filter = $filter(filterName);
194250 };
195251
197253 * Use a different function than the angular orderBy
198254 * @param sortFunctionName the name under which the custom order function is registered
199255 */
200 this.setSortFunction = function setSortFunction (sortFunctionName) {
256 this.setSortFunction = function setSortFunction(sortFunctionName) {
201257 orderBy = $filter(sortFunctionName);
202258 };
203259
205261 * Usually when the safe copy is updated the pipe function is called.
206262 * Calling this method will prevent it, which is something required when using a custom pipe function
207263 */
208 this.preventPipeOnWatch = function preventPipe () {
264 this.preventPipeOnWatch = function preventPipe() {
209265 pipeAfterSafeCopy = false;
210266 };
211 }])
212 .directive('stTable', function () {
213 return {
214 restrict: 'A',
215 controller: 'stTableController',
216 link: function (scope, element, attr, ctrl) {
217
218 if (attr.stSetFilter) {
219 ctrl.setFilterFunction(attr.stSetFilter);
220 }
221
222 if (attr.stSetSort) {
223 ctrl.setSortFunction(attr.stSetSort);
224 }
225 }
226 };
227 });
267 }
268 ]).directive('stTable', function() {
269 return {
270 restrict: 'A',
271 controller: 'stTableController',
272 link: function(scope, element, attr, ctrl) {
273 if (attr.stSetFilter) {
274 ctrl.setFilterFunction(attr.stSetFilter);
275 }
276
277 if (attr.stSetSort) {
278 ctrl.setSortFunction(attr.stSetSort);
279 }
280 }
281 };
282 });
228283
229284 ng.module('smart-table')
230 .directive('stSearch', ['stConfig', '$timeout', function (stConfig, $timeout) {
285 .directive('stSearch', ['stConfig', '$timeout','$parse', function (stConfig, $timeout, $parse) {
231286 return {
232287 require: '^stTable',
233 scope: {
234 predicate: '=?stSearch'
235 },
236288 link: function (scope, element, attr, ctrl) {
237289 var tableCtrl = ctrl;
238290 var promise = null;
239291 var throttle = attr.stDelay || stConfig.search.delay;
240
241 scope.$watch('predicate', function (newValue, oldValue) {
242 if (newValue !== oldValue) {
292 var event = attr.stInputEvent || stConfig.search.inputEvent;
293 var trimSearch = attr.trimSearch || stConfig.search.trimSearch;
294
295 attr.$observe('stSearch', function (newValue, oldValue) {
296 var input = element[0].value;
297 if (newValue !== oldValue && input) {
243298 ctrl.tableState().search = {};
244 tableCtrl.search(element[0].value || '', newValue);
299 input = ng.isString(input) && trimSearch ? input.trim() : input;
300 tableCtrl.search(input, newValue);
245301 }
246302 });
247303
249305 scope.$watch(function () {
250306 return ctrl.tableState().search;
251307 }, function (newValue, oldValue) {
252 var predicateExpression = scope.predicate || '$';
253 if (newValue.predicateObject && newValue.predicateObject[predicateExpression] !== element[0].value) {
254 element[0].value = newValue.predicateObject[predicateExpression] || '';
308 var predicateExpression = attr.stSearch || '$';
309 if (newValue.predicateObject && $parse(predicateExpression)(newValue.predicateObject) !== element[0].value) {
310 element[0].value = $parse(predicateExpression)(newValue.predicateObject) || '';
255311 }
256312 }, true);
257313
258314 // view -> table state
259 element.bind('input', function (evt) {
315 element.bind(event, function (evt) {
260316 evt = evt.originalEvent || evt;
261317 if (promise !== null) {
262318 $timeout.cancel(promise);
263319 }
320
264321 promise = $timeout(function () {
265 tableCtrl.search(evt.target.value, scope.predicate || '');
322 var input = evt.target.value;
323 input = ng.isString(input) && trimSearch ? input.trim() : input;
324 tableCtrl.search(input, attr.stSearch || '');
266325 promise = null;
267326 }, throttle);
268327 });
298357 }]);
299358
300359 ng.module('smart-table')
301 .directive('stSort', ['stConfig', '$parse', function (stConfig, $parse) {
360 .directive('stSort', ['stConfig', '$parse', '$timeout', function (stConfig, $parse, $timeout) {
302361 return {
303362 restrict: 'A',
304363 require: '^stTable',
311370 var classDescent = attr.stClassDescent || stConfig.sort.descentClass;
312371 var stateClasses = [classAscent, classDescent];
313372 var sortDefault;
373 var skipNatural = attr.stSkipNatural !== undefined ? attr.stSkipNatural : stConfig.sort.skipNatural;
374 var descendingFirst = attr.stDescendingFirst !== undefined ? attr.stDescendingFirst : stConfig.sort.descendingFirst;
375 var promise = null;
376 var throttle = attr.stDelay || stConfig.sort.delay;
377
378 // set aria attributes
379 var ariaSort = 'aria-sort';
380 var ariaSortNone = 'none';
381 var ariaSortAscending = 'ascending';
382 var ariaSortDescending = 'descending';
383 element
384 .attr('role', 'columnheader')
385 .attr(ariaSort, ariaSortNone);
314386
315387 if (attr.stSortDefault) {
316388 sortDefault = scope.$eval(attr.stSortDefault) !== undefined ? scope.$eval(attr.stSortDefault) : attr.stSortDefault;
318390
319391 //view --> table state
320392 function sort () {
321 index++;
322 predicate = ng.isFunction(getter(scope)) ? getter(scope) : attr.stSort;
323 if (index % 3 === 0 && attr.stSkipNatural === undefined) {
393 if (descendingFirst) {
394 index = index === 0 ? 2 : index - 1;
395 } else {
396 index++;
397 }
398
399 var func;
400 predicate = ng.isFunction(getter(scope)) || ng.isArray(getter(scope)) ? getter(scope) : attr.stSort;
401 if (index % 3 === 0 && !!skipNatural !== true) {
324402 //manual reset
325403 index = 0;
326404 ctrl.tableState().sort = {};
327405 ctrl.tableState().pagination.start = 0;
328 ctrl.pipe();
406 func = ctrl.pipe.bind(ctrl);
329407 } else {
330 ctrl.sortBy(predicate, index % 2 === 0);
408 func = ctrl.sortBy.bind(ctrl, predicate, index % 2 === 0);
409 }
410 if (promise !== null) {
411 $timeout.cancel(promise);
412 }
413 if (throttle < 0) {
414 func();
415 } else {
416 promise = $timeout(function(){
417 func();
418 }, throttle);
331419 }
332420 }
333421
350438 index = 0;
351439 element
352440 .removeClass(classAscent)
353 .removeClass(classDescent);
441 .removeClass(classDescent)
442 .attr(ariaSort, ariaSortNone);
354443 } else {
355444 index = newValue.reverse === true ? 2 : 1;
356445 element
357446 .removeClass(stateClasses[index % 2])
358 .addClass(stateClasses[index - 1]);
447 .addClass(stateClasses[index - 1])
448 .attr(ariaSort, newValue.reverse ? ariaSortAscending : ariaSortDescending);
359449 }
360450 }, true);
361451 }
392482 var end;
393483 var i;
394484 var prevPage = scope.currentPage;
485 scope.totalItemCount = paginationState.totalItemCount;
395486 scope.currentPage = Math.floor(paginationState.start / paginationState.number) + 1;
396487
397488 start = Math.max(start, scope.currentPage - Math.abs(Math.floor(scope.stDisplayedPages / 2)));
443534 }]);
444535
445536 ng.module('smart-table')
446 .directive('stPipe', function () {
537 .directive('stPipe', ['stConfig', '$timeout', function (config, $timeout) {
447538 return {
448539 require: 'stTable',
449540 scope: {
452543 link: {
453544
454545 pre: function (scope, element, attrs, ctrl) {
546
547 var pipePromise = null;
548
455549 if (ng.isFunction(scope.stPipe)) {
456550 ctrl.preventPipeOnWatch();
457551 ctrl.pipe = function () {
458 return scope.stPipe(ctrl.tableState(), ctrl);
552
553 if (pipePromise !== null) {
554 $timeout.cancel(pipePromise)
555 }
556
557 pipePromise = $timeout(function () {
558 scope.stPipe(ctrl.tableState(), ctrl);
559 }, config.pipe.delay);
560
561 return pipePromise;
459562 }
460563 }
461564 },
465568 }
466569 }
467570 };
468 });
469
470 })(angular);
471 //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInNyYy90b3AudHh0Iiwic3JjL3NtYXJ0LXRhYmxlLm1vZHVsZS5qcyIsInNyYy9zdENvbmZpZy5qcyIsInNyYy9zdFRhYmxlLmpzIiwic3JjL3N0U2VhcmNoLmpzIiwic3JjL3N0U2VsZWN0Um93LmpzIiwic3JjL3N0U29ydC5qcyIsInNyYy9zdFBhZ2luYXRpb24uanMiLCJzcmMvc3RQaXBlLmpzIiwic3JjL2JvdHRvbS50eHQiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7QUFDQTtBQUNBO0FDRkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQ1BBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FDbEJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQ2xNQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FDM0NBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQzFCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FDaEVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUMvRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUN4QkEiLCJmaWxlIjoic21hcnQtdGFibGUuanMiLCJzb3VyY2VzQ29udGVudCI6WyIoZnVuY3Rpb24gKG5nLCB1bmRlZmluZWQpe1xuICAgICd1c2Ugc3RyaWN0JztcbiIsIm5nLm1vZHVsZSgnc21hcnQtdGFibGUnLCBbXSkucnVuKFsnJHRlbXBsYXRlQ2FjaGUnLCBmdW5jdGlvbiAoJHRlbXBsYXRlQ2FjaGUpIHtcbiAgICAkdGVtcGxhdGVDYWNoZS5wdXQoJ3RlbXBsYXRlL3NtYXJ0LXRhYmxlL3BhZ2luYXRpb24uaHRtbCcsXG4gICAgICAgICc8bmF2IG5nLWlmPVwicGFnZXMubGVuZ3RoID49IDJcIj48dWwgY2xhc3M9XCJwYWdpbmF0aW9uXCI+JyArXG4gICAgICAgICc8bGkgbmctcmVwZWF0PVwicGFnZSBpbiBwYWdlc1wiIG5nLWNsYXNzPVwie2FjdGl2ZTogcGFnZT09Y3VycmVudFBhZ2V9XCI+PGEgbmctY2xpY2s9XCJzZWxlY3RQYWdlKHBhZ2UpXCI+e3twYWdlfX08L2E+PC9saT4nICtcbiAgICAgICAgJzwvdWw+PC9uYXY+Jyk7XG59XSk7XG5cbiIsIm5nLm1vZHVsZSgnc21hcnQtdGFibGUnKVxuICAuY29uc3RhbnQoJ3N0Q29uZmlnJywge1xuICAgIHBhZ2luYXRpb246IHtcbiAgICAgIHRlbXBsYXRlOiAndGVtcGxhdGUvc21hcnQtdGFibGUvcGFnaW5hdGlvbi5odG1sJyxcbiAgICAgIGl0ZW1zQnlQYWdlOiAxMCxcbiAgICAgIGRpc3BsYXllZFBhZ2VzOiA1XG4gICAgfSxcbiAgICBzZWFyY2g6IHtcbiAgICAgIGRlbGF5OiA0MDAgLy8gbXNcbiAgICB9LFxuICAgIHNlbGVjdDoge1xuICAgICAgbW9kZTogJ3NpbmdsZScsXG4gICAgICBzZWxlY3RlZENsYXNzOiAnc3Qtc2VsZWN0ZWQnXG4gICAgfSxcbiAgICBzb3J0OiB7XG4gICAgICBhc2NlbnRDbGFzczogJ3N0LXNvcnQtYXNjZW50JyxcbiAgICAgIGRlc2NlbnRDbGFzczogJ3N0LXNvcnQtZGVzY2VudCdcbiAgICB9XG4gIH0pOyIsIm5nLm1vZHVsZSgnc21hcnQtdGFibGUnKVxuICAuY29udHJvbGxlcignc3RUYWJsZUNvbnRyb2xsZXInLCBbJyRzY29wZScsICckcGFyc2UnLCAnJGZpbHRlcicsICckYXR0cnMnLCBmdW5jdGlvbiBTdFRhYmxlQ29udHJvbGxlciAoJHNjb3BlLCAkcGFyc2UsICRmaWx0ZXIsICRhdHRycykge1xuICAgIHZhciBwcm9wZXJ0eU5hbWUgPSAkYXR0cnMuc3RUYWJsZTtcbiAgICB2YXIgZGlzcGxheUdldHRlciA9ICRwYXJzZShwcm9wZXJ0eU5hbWUpO1xuICAgIHZhciBkaXNwbGF5U2V0dGVyID0gZGlzcGxheUdldHRlci5hc3NpZ247XG4gICAgdmFyIHNhZmVHZXR0ZXI7XG4gICAgdmFyIG9yZGVyQnkgPSAkZmlsdGVyKCdvcmRlckJ5Jyk7XG4gICAgdmFyIGZpbHRlciA9ICRmaWx0ZXIoJ2ZpbHRlcicpO1xuICAgIHZhciBzYWZlQ29weSA9IGNvcHlSZWZzKGRpc3BsYXlHZXR0ZXIoJHNjb3BlKSk7XG4gICAgdmFyIHRhYmxlU3RhdGUgPSB7XG4gICAgICBzb3J0OiB7fSxcbiAgICAgIHNlYXJjaDoge30sXG4gICAgICBwYWdpbmF0aW9uOiB7XG4gICAgICAgIHN0YXJ0OiAwXG4gICAgICB9XG4gICAgfTtcbiAgICB2YXIgZmlsdGVyZWQ7XG4gICAgdmFyIHBpcGVBZnRlclNhZmVDb3B5ID0gdHJ1ZTtcbiAgICB2YXIgY3RybCA9IHRoaXM7XG4gICAgdmFyIGxhc3RTZWxlY3RlZDtcblxuICAgIGZ1bmN0aW9uIGNvcHlSZWZzIChzcmMpIHtcbiAgICAgIHJldHVybiBzcmMgPyBbXS5jb25jYXQoc3JjKSA6IFtdO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIHVwZGF0ZVNhZmVDb3B5ICgpIHtcbiAgICAgIHNhZmVDb3B5ID0gY29weVJlZnMoc2FmZUdldHRlcigkc2NvcGUpKTtcbiAgICAgIGlmIChwaXBlQWZ0ZXJTYWZlQ29weSA9PT0gdHJ1ZSkge1xuICAgICAgICBjdHJsLnBpcGUoKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBpZiAoJGF0dHJzLnN0U2FmZVNyYykge1xuICAgICAgc2FmZUdldHRlciA9ICRwYXJzZSgkYXR0cnMuc3RTYWZlU3JjKTtcbiAgICAgICRzY29wZS4kd2F0Y2goZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgc2FmZVNyYyA9IHNhZmVHZXR0ZXIoJHNjb3BlKTtcbiAgICAgICAgcmV0dXJuIHNhZmVTcmMgPyBzYWZlU3JjLmxlbmd0aCA6IDA7XG5cbiAgICAgIH0sIGZ1bmN0aW9uIChuZXdWYWx1ZSwgb2xkVmFsdWUpIHtcbiAgICAgICAgaWYgKG5ld1ZhbHVlICE9PSBzYWZlQ29weS5sZW5ndGgpIHtcbiAgICAgICAgICB1cGRhdGVTYWZlQ29weSgpO1xuICAgICAgICB9XG4gICAgICB9KTtcbiAgICAgICRzY29wZS4kd2F0Y2goZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gc2FmZUdldHRlcigkc2NvcGUpO1xuICAgICAgfSwgZnVuY3Rpb24gKG5ld1ZhbHVlLCBvbGRWYWx1ZSkge1xuICAgICAgICBpZiAobmV3VmFsdWUgIT09IG9sZFZhbHVlKSB7XG4gICAgICAgICAgdXBkYXRlU2FmZUNvcHkoKTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogc29ydCB0aGUgcm93c1xuICAgICAqIEBwYXJhbSB7RnVuY3Rpb24gfCBTdHJpbmd9IHByZWRpY2F0ZSAtIGZ1bmN0aW9uIG9yIHN0cmluZyB3aGljaCB3aWxsIGJlIHVzZWQgYXMgcHJlZGljYXRlIGZvciB0aGUgc29ydGluZ1xuICAgICAqIEBwYXJhbSBbcmV2ZXJzZV0gLSBpZiB5b3Ugd2FudCB0byByZXZlcnNlIHRoZSBvcmRlclxuICAgICAqL1xuICAgIHRoaXMuc29ydEJ5ID0gZnVuY3Rpb24gc29ydEJ5IChwcmVkaWNhdGUsIHJldmVyc2UpIHtcbiAgICAgIHRhYmxlU3RhdGUuc29ydC5wcmVkaWNhdGUgPSBwcmVkaWNhdGU7XG4gICAgICB0YWJsZVN0YXRlLnNvcnQucmV2ZXJzZSA9IHJldmVyc2UgPT09IHRydWU7XG5cbiAgICAgIGlmIChuZy5pc0Z1bmN0aW9uKHByZWRpY2F0ZSkpIHtcbiAgICAgICAgdGFibGVTdGF0ZS5zb3J0LmZ1bmN0aW9uTmFtZSA9IHByZWRpY2F0ZS5uYW1lO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgZGVsZXRlIHRhYmxlU3RhdGUuc29ydC5mdW5jdGlvbk5hbWU7XG4gICAgICB9XG5cbiAgICAgIHRhYmxlU3RhdGUucGFnaW5hdGlvbi5zdGFydCA9IDA7XG4gICAgICByZXR1cm4gdGhpcy5waXBlKCk7XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIHNlYXJjaCBtYXRjaGluZyByb3dzXG4gICAgICogQHBhcmFtIHtTdHJpbmd9IGlucHV0IC0gdGhlIGlucHV0IHN0cmluZ1xuICAgICAqIEBwYXJhbSB7U3RyaW5nfSBbcHJlZGljYXRlXSAtIHRoZSBwcm9wZXJ0eSBuYW1lIGFnYWluc3QgeW91IHdhbnQgdG8gY2hlY2sgdGhlIG1hdGNoLCBvdGhlcndpc2UgaXQgd2lsbCBzZWFyY2ggb24gYWxsIHByb3BlcnRpZXNcbiAgICAgKi9cbiAgICB0aGlzLnNlYXJjaCA9IGZ1bmN0aW9uIHNlYXJjaCAoaW5wdXQsIHByZWRpY2F0ZSkge1xuICAgICAgdmFyIHByZWRpY2F0ZU9iamVjdCA9IHRhYmxlU3RhdGUuc2VhcmNoLnByZWRpY2F0ZU9iamVjdCB8fCB7fTtcbiAgICAgIHZhciBwcm9wID0gcHJlZGljYXRlID8gcHJlZGljYXRlIDogJyQnO1xuXG4gICAgICBpbnB1dCA9IG5nLmlzU3RyaW5nKGlucHV0KSA/IGlucHV0LnRyaW0oKSA6IGlucHV0O1xuICAgICAgcHJlZGljYXRlT2JqZWN0W3Byb3BdID0gaW5wdXQ7XG4gICAgICAvLyB0byBhdm9pZCB0byBmaWx0ZXIgb3V0IG51bGwgdmFsdWVcbiAgICAgIGlmICghaW5wdXQpIHtcbiAgICAgICAgZGVsZXRlIHByZWRpY2F0ZU9iamVjdFtwcm9wXTtcbiAgICAgIH1cbiAgICAgIHRhYmxlU3RhdGUuc2VhcmNoLnByZWRpY2F0ZU9iamVjdCA9IHByZWRpY2F0ZU9iamVjdDtcbiAgICAgIHRhYmxlU3RhdGUucGFnaW5hdGlvbi5zdGFydCA9IDA7XG4gICAgICByZXR1cm4gdGhpcy5waXBlKCk7XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIHRoaXMgd2lsbCBjaGFpbiB0aGUgb3BlcmF0aW9ucyBvZiBzb3J0aW5nIGFuZCBmaWx0ZXJpbmcgYmFzZWQgb24gdGhlIGN1cnJlbnQgdGFibGUgc3RhdGUgKHNvcnQgb3B0aW9ucywgZmlsdGVyaW5nLCBlY3QpXG4gICAgICovXG4gICAgdGhpcy5waXBlID0gZnVuY3Rpb24gcGlwZSAoKSB7XG4gICAgICB2YXIgcGFnaW5hdGlvbiA9IHRhYmxlU3RhdGUucGFnaW5hdGlvbjtcbiAgICAgIHZhciBvdXRwdXQ7XG4gICAgICBmaWx0ZXJlZCA9IHRhYmxlU3RhdGUuc2VhcmNoLnByZWRpY2F0ZU9iamVjdCA/IGZpbHRlcihzYWZlQ29weSwgdGFibGVTdGF0ZS5zZWFyY2gucHJlZGljYXRlT2JqZWN0KSA6IHNhZmVDb3B5O1xuICAgICAgaWYgKHRhYmxlU3RhdGUuc29ydC5wcmVkaWNhdGUpIHtcbiAgICAgICAgZmlsdGVyZWQgPSBvcmRlckJ5KGZpbHRlcmVkLCB0YWJsZVN0YXRlLnNvcnQucHJlZGljYXRlLCB0YWJsZVN0YXRlLnNvcnQucmV2ZXJzZSk7XG4gICAgICB9XG4gICAgICBpZiAocGFnaW5hdGlvbi5udW1iZXIgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICBwYWdpbmF0aW9uLm51bWJlck9mUGFnZXMgPSBmaWx0ZXJlZC5sZW5ndGggPiAwID8gTWF0aC5jZWlsKGZpbHRlcmVkLmxlbmd0aCAvIHBhZ2luYXRpb24ubnVtYmVyKSA6IDE7XG4gICAgICAgIHBhZ2luYXRpb24uc3RhcnQgPSBwYWdpbmF0aW9uLnN0YXJ0ID49IGZpbHRlcmVkLmxlbmd0aCA/IChwYWdpbmF0aW9uLm51bWJlck9mUGFnZXMgLSAxKSAqIHBhZ2luYXRpb24ubnVtYmVyIDogcGFnaW5hdGlvbi5zdGFydDtcbiAgICAgICAgb3V0cHV0ID0gZmlsdGVyZWQuc2xpY2UocGFnaW5hdGlvbi5zdGFydCwgcGFnaW5hdGlvbi5zdGFydCArIHBhcnNlSW50KHBhZ2luYXRpb24ubnVtYmVyKSk7XG4gICAgICB9XG4gICAgICBkaXNwbGF5U2V0dGVyKCRzY29wZSwgb3V0cHV0IHx8IGZpbHRlcmVkKTtcbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogc2VsZWN0IGEgZGF0YVJvdyAoaXQgd2lsbCBhZGQgdGhlIGF0dHJpYnV0ZSBpc1NlbGVjdGVkIHRvIHRoZSByb3cgb2JqZWN0KVxuICAgICAqIEBwYXJhbSB7T2JqZWN0fSByb3cgLSB0aGUgcm93IHRvIHNlbGVjdFxuICAgICAqIEBwYXJhbSB7U3RyaW5nfSBbbW9kZV0gLSBcInNpbmdsZVwiIG9yIFwibXVsdGlwbGVcIiAobXVsdGlwbGUgYnkgZGVmYXVsdClcbiAgICAgKi9cbiAgICB0aGlzLnNlbGVjdCA9IGZ1bmN0aW9uIHNlbGVjdCAocm93LCBtb2RlKSB7XG4gICAgICB2YXIgcm93cyA9IHNhZmVDb3B5O1xuICAgICAgdmFyIGluZGV4ID0gcm93cy5pbmRleE9mKHJvdyk7XG4gICAgICBpZiAoaW5kZXggIT09IC0xKSB7XG4gICAgICAgIGlmIChtb2RlID09PSAnc2luZ2xlJykge1xuICAgICAgICAgIHJvdy5pc1NlbGVjdGVkID0gcm93LmlzU2VsZWN0ZWQgIT09IHRydWU7XG4gICAgICAgICAgaWYgKGxhc3RTZWxlY3RlZCkge1xuICAgICAgICAgICAgbGFzdFNlbGVjdGVkLmlzU2VsZWN0ZWQgPSBmYWxzZTtcbiAgICAgICAgICB9XG4gICAgICAgICAgbGFzdFNlbGVjdGVkID0gcm93LmlzU2VsZWN0ZWQgPT09IHRydWUgPyByb3cgOiB1bmRlZmluZWQ7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgcm93c1tpbmRleF0uaXNTZWxlY3RlZCA9ICFyb3dzW2luZGV4XS5pc1NlbGVjdGVkO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIHRha2UgYSBzbGljZSBvZiB0aGUgY3VycmVudCBzb3J0ZWQvZmlsdGVyZWQgY29sbGVjdGlvbiAocGFnaW5hdGlvbilcbiAgICAgKlxuICAgICAqIEBwYXJhbSB7TnVtYmVyfSBzdGFydCAtIHN0YXJ0IGluZGV4IG9mIHRoZSBzbGljZVxuICAgICAqIEBwYXJhbSB7TnVtYmVyfSBudW1iZXIgLSB0aGUgbnVtYmVyIG9mIGl0ZW0gaW4gdGhlIHNsaWNlXG4gICAgICovXG4gICAgdGhpcy5zbGljZSA9IGZ1bmN0aW9uIHNwbGljZSAoc3RhcnQsIG51bWJlcikge1xuICAgICAgdGFibGVTdGF0ZS5wYWdpbmF0aW9uLnN0YXJ0ID0gc3RhcnQ7XG4gICAgICB0YWJsZVN0YXRlLnBhZ2luYXRpb24ubnVtYmVyID0gbnVtYmVyO1xuICAgICAgcmV0dXJuIHRoaXMucGlwZSgpO1xuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiByZXR1cm4gdGhlIGN1cnJlbnQgc3RhdGUgb2YgdGhlIHRhYmxlXG4gICAgICogQHJldHVybnMge3tzb3J0OiB7fSwgc2VhcmNoOiB7fSwgcGFnaW5hdGlvbjoge3N0YXJ0OiBudW1iZXJ9fX1cbiAgICAgKi9cbiAgICB0aGlzLnRhYmxlU3RhdGUgPSBmdW5jdGlvbiBnZXRUYWJsZVN0YXRlICgpIHtcbiAgICAgIHJldHVybiB0YWJsZVN0YXRlO1xuICAgIH07XG5cbiAgICB0aGlzLmdldEZpbHRlcmVkQ29sbGVjdGlvbiA9IGZ1bmN0aW9uIGdldEZpbHRlcmVkQ29sbGVjdGlvbiAoKSB7XG4gICAgICByZXR1cm4gZmlsdGVyZWQgfHwgc2FmZUNvcHk7XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIFVzZSBhIGRpZmZlcmVudCBmaWx0ZXIgZnVuY3Rpb24gdGhhbiB0aGUgYW5ndWxhciBGaWx0ZXJGaWx0ZXJcbiAgICAgKiBAcGFyYW0gZmlsdGVyTmFtZSB0aGUgbmFtZSB1bmRlciB3aGljaCB0aGUgY3VzdG9tIGZpbHRlciBpcyByZWdpc3RlcmVkXG4gICAgICovXG4gICAgdGhpcy5zZXRGaWx0ZXJGdW5jdGlvbiA9IGZ1bmN0aW9uIHNldEZpbHRlckZ1bmN0aW9uIChmaWx0ZXJOYW1lKSB7XG4gICAgICBmaWx0ZXIgPSAkZmlsdGVyKGZpbHRlck5hbWUpO1xuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBVc2UgYSBkaWZmZXJlbnQgZnVuY3Rpb24gdGhhbiB0aGUgYW5ndWxhciBvcmRlckJ5XG4gICAgICogQHBhcmFtIHNvcnRGdW5jdGlvbk5hbWUgdGhlIG5hbWUgdW5kZXIgd2hpY2ggdGhlIGN1c3RvbSBvcmRlciBmdW5jdGlvbiBpcyByZWdpc3RlcmVkXG4gICAgICovXG4gICAgdGhpcy5zZXRTb3J0RnVuY3Rpb24gPSBmdW5jdGlvbiBzZXRTb3J0RnVuY3Rpb24gKHNvcnRGdW5jdGlvbk5hbWUpIHtcbiAgICAgIG9yZGVyQnkgPSAkZmlsdGVyKHNvcnRGdW5jdGlvbk5hbWUpO1xuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBVc3VhbGx5IHdoZW4gdGhlIHNhZmUgY29weSBpcyB1cGRhdGVkIHRoZSBwaXBlIGZ1bmN0aW9uIGlzIGNhbGxlZC5cbiAgICAgKiBDYWxsaW5nIHRoaXMgbWV0aG9kIHdpbGwgcHJldmVudCBpdCwgd2hpY2ggaXMgc29tZXRoaW5nIHJlcXVpcmVkIHdoZW4gdXNpbmcgYSBjdXN0b20gcGlwZSBmdW5jdGlvblxuICAgICAqL1xuICAgIHRoaXMucHJldmVudFBpcGVPbldhdGNoID0gZnVuY3Rpb24gcHJldmVudFBpcGUgKCkge1xuICAgICAgcGlwZUFmdGVyU2FmZUNvcHkgPSBmYWxzZTtcbiAgICB9O1xuICB9XSlcbiAgLmRpcmVjdGl2ZSgnc3RUYWJsZScsIGZ1bmN0aW9uICgpIHtcbiAgICByZXR1cm4ge1xuICAgICAgcmVzdHJpY3Q6ICdBJyxcbiAgICAgIGNvbnRyb2xsZXI6ICdzdFRhYmxlQ29udHJvbGxlcicsXG4gICAgICBsaW5rOiBmdW5jdGlvbiAoc2NvcGUsIGVsZW1lbnQsIGF0dHIsIGN0cmwpIHtcblxuICAgICAgICBpZiAoYXR0ci5zdFNldEZpbHRlcikge1xuICAgICAgICAgIGN0cmwuc2V0RmlsdGVyRnVuY3Rpb24oYXR0ci5zdFNldEZpbHRlcik7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoYXR0ci5zdFNldFNvcnQpIHtcbiAgICAgICAgICBjdHJsLnNldFNvcnRGdW5jdGlvbihhdHRyLnN0U2V0U29ydCk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9O1xuICB9KTtcbiIsIm5nLm1vZHVsZSgnc21hcnQtdGFibGUnKVxuICAuZGlyZWN0aXZlKCdzdFNlYXJjaCcsIFsnc3RDb25maWcnLCAnJHRpbWVvdXQnLCBmdW5jdGlvbiAoc3RDb25maWcsICR0aW1lb3V0KSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIHJlcXVpcmU6ICdec3RUYWJsZScsXG4gICAgICBzY29wZToge1xuICAgICAgICBwcmVkaWNhdGU6ICc9P3N0U2VhcmNoJ1xuICAgICAgfSxcbiAgICAgIGxpbms6IGZ1bmN0aW9uIChzY29wZSwgZWxlbWVudCwgYXR0ciwgY3RybCkge1xuICAgICAgICB2YXIgdGFibGVDdHJsID0gY3RybDtcbiAgICAgICAgdmFyIHByb21pc2UgPSBudWxsO1xuICAgICAgICB2YXIgdGhyb3R0bGUgPSBhdHRyLnN0RGVsYXkgfHwgc3RDb25maWcuc2VhcmNoLmRlbGF5O1xuXG4gICAgICAgIHNjb3BlLiR3YXRjaCgncHJlZGljYXRlJywgZnVuY3Rpb24gKG5ld1ZhbHVlLCBvbGRWYWx1ZSkge1xuICAgICAgICAgIGlmIChuZXdWYWx1ZSAhPT0gb2xkVmFsdWUpIHtcbiAgICAgICAgICAgIGN0cmwudGFibGVTdGF0ZSgpLnNlYXJjaCA9IHt9O1xuICAgICAgICAgICAgdGFibGVDdHJsLnNlYXJjaChlbGVtZW50WzBdLnZhbHVlIHx8ICcnLCBuZXdWYWx1ZSk7XG4gICAgICAgICAgfVxuICAgICAgICB9KTtcblxuICAgICAgICAvL3RhYmxlIHN0YXRlIC0+IHZpZXdcbiAgICAgICAgc2NvcGUuJHdhdGNoKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICByZXR1cm4gY3RybC50YWJsZVN0YXRlKCkuc2VhcmNoO1xuICAgICAgICB9LCBmdW5jdGlvbiAobmV3VmFsdWUsIG9sZFZhbHVlKSB7XG4gICAgICAgICAgdmFyIHByZWRpY2F0ZUV4cHJlc3Npb24gPSBzY29wZS5wcmVkaWNhdGUgfHwgJyQnO1xuICAgICAgICAgIGlmIChuZXdWYWx1ZS5wcmVkaWNhdGVPYmplY3QgJiYgbmV3VmFsdWUucHJlZGljYXRlT2JqZWN0W3ByZWRpY2F0ZUV4cHJlc3Npb25dICE9PSBlbGVtZW50WzBdLnZhbHVlKSB7XG4gICAgICAgICAgICBlbGVtZW50WzBdLnZhbHVlID0gbmV3VmFsdWUucHJlZGljYXRlT2JqZWN0W3ByZWRpY2F0ZUV4cHJlc3Npb25dIHx8ICcnO1xuICAgICAgICAgIH1cbiAgICAgICAgfSwgdHJ1ZSk7XG5cbiAgICAgICAgLy8gdmlldyAtPiB0YWJsZSBzdGF0ZVxuICAgICAgICBlbGVtZW50LmJpbmQoJ2lucHV0JywgZnVuY3Rpb24gKGV2dCkge1xuICAgICAgICAgIGV2dCA9IGV2dC5vcmlnaW5hbEV2ZW50IHx8IGV2dDtcbiAgICAgICAgICBpZiAocHJvbWlzZSAhPT0gbnVsbCkge1xuICAgICAgICAgICAgJHRpbWVvdXQuY2FuY2VsKHByb21pc2UpO1xuICAgICAgICAgIH1cbiAgICAgICAgICBwcm9taXNlID0gJHRpbWVvdXQoZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdGFibGVDdHJsLnNlYXJjaChldnQudGFyZ2V0LnZhbHVlLCBzY29wZS5wcmVkaWNhdGUgfHwgJycpO1xuICAgICAgICAgICAgcHJvbWlzZSA9IG51bGw7XG4gICAgICAgICAgfSwgdGhyb3R0bGUpO1xuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9O1xuICB9XSk7XG4iLCJuZy5tb2R1bGUoJ3NtYXJ0LXRhYmxlJylcbiAgLmRpcmVjdGl2ZSgnc3RTZWxlY3RSb3cnLCBbJ3N0Q29uZmlnJywgZnVuY3Rpb24gKHN0Q29uZmlnKSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIHJlc3RyaWN0OiAnQScsXG4gICAgICByZXF1aXJlOiAnXnN0VGFibGUnLFxuICAgICAgc2NvcGU6IHtcbiAgICAgICAgcm93OiAnPXN0U2VsZWN0Um93J1xuICAgICAgfSxcbiAgICAgIGxpbms6IGZ1bmN0aW9uIChzY29wZSwgZWxlbWVudCwgYXR0ciwgY3RybCkge1xuICAgICAgICB2YXIgbW9kZSA9IGF0dHIuc3RTZWxlY3RNb2RlIHx8IHN0Q29uZmlnLnNlbGVjdC5tb2RlO1xuICAgICAgICBlbGVtZW50LmJpbmQoJ2NsaWNrJywgZnVuY3Rpb24gKCkge1xuICAgICAgICAgIHNjb3BlLiRhcHBseShmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICBjdHJsLnNlbGVjdChzY29wZS5yb3csIG1vZGUpO1xuICAgICAgICAgIH0pO1xuICAgICAgICB9KTtcblxuICAgICAgICBzY29wZS4kd2F0Y2goJ3Jvdy5pc1NlbGVjdGVkJywgZnVuY3Rpb24gKG5ld1ZhbHVlKSB7XG4gICAgICAgICAgaWYgKG5ld1ZhbHVlID09PSB0cnVlKSB7XG4gICAgICAgICAgICBlbGVtZW50LmFkZENsYXNzKHN0Q29uZmlnLnNlbGVjdC5zZWxlY3RlZENsYXNzKTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgZWxlbWVudC5yZW1vdmVDbGFzcyhzdENvbmZpZy5zZWxlY3Quc2VsZWN0ZWRDbGFzcyk7XG4gICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9O1xuICB9XSk7XG4iLCJuZy5tb2R1bGUoJ3NtYXJ0LXRhYmxlJylcbiAgLmRpcmVjdGl2ZSgnc3RTb3J0JywgWydzdENvbmZpZycsICckcGFyc2UnLCBmdW5jdGlvbiAoc3RDb25maWcsICRwYXJzZSkge1xuICAgIHJldHVybiB7XG4gICAgICByZXN0cmljdDogJ0EnLFxuICAgICAgcmVxdWlyZTogJ15zdFRhYmxlJyxcbiAgICAgIGxpbms6IGZ1bmN0aW9uIChzY29wZSwgZWxlbWVudCwgYXR0ciwgY3RybCkge1xuXG4gICAgICAgIHZhciBwcmVkaWNhdGUgPSBhdHRyLnN0U29ydDtcbiAgICAgICAgdmFyIGdldHRlciA9ICRwYXJzZShwcmVkaWNhdGUpO1xuICAgICAgICB2YXIgaW5kZXggPSAwO1xuICAgICAgICB2YXIgY2xhc3NBc2NlbnQgPSBhdHRyLnN0Q2xhc3NBc2NlbnQgfHwgc3RDb25maWcuc29ydC5hc2NlbnRDbGFzcztcbiAgICAgICAgdmFyIGNsYXNzRGVzY2VudCA9IGF0dHIuc3RDbGFzc0Rlc2NlbnQgfHwgc3RDb25maWcuc29ydC5kZXNjZW50Q2xhc3M7XG4gICAgICAgIHZhciBzdGF0ZUNsYXNzZXMgPSBbY2xhc3NBc2NlbnQsIGNsYXNzRGVzY2VudF07XG4gICAgICAgIHZhciBzb3J0RGVmYXVsdDtcblxuICAgICAgICBpZiAoYXR0ci5zdFNvcnREZWZhdWx0KSB7XG4gICAgICAgICAgc29ydERlZmF1bHQgPSBzY29wZS4kZXZhbChhdHRyLnN0U29ydERlZmF1bHQpICE9PSB1bmRlZmluZWQgPyBzY29wZS4kZXZhbChhdHRyLnN0U29ydERlZmF1bHQpIDogYXR0ci5zdFNvcnREZWZhdWx0O1xuICAgICAgICB9XG5cbiAgICAgICAgLy92aWV3IC0tPiB0YWJsZSBzdGF0ZVxuICAgICAgICBmdW5jdGlvbiBzb3J0ICgpIHtcbiAgICAgICAgICBpbmRleCsrO1xuICAgICAgICAgIHByZWRpY2F0ZSA9IG5nLmlzRnVuY3Rpb24oZ2V0dGVyKHNjb3BlKSkgPyBnZXR0ZXIoc2NvcGUpIDogYXR0ci5zdFNvcnQ7XG4gICAgICAgICAgaWYgKGluZGV4ICUgMyA9PT0gMCAmJiBhdHRyLnN0U2tpcE5hdHVyYWwgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgLy9tYW51YWwgcmVzZXRcbiAgICAgICAgICAgIGluZGV4ID0gMDtcbiAgICAgICAgICAgIGN0cmwudGFibGVTdGF0ZSgpLnNvcnQgPSB7fTtcbiAgICAgICAgICAgIGN0cmwudGFibGVTdGF0ZSgpLnBhZ2luYXRpb24uc3RhcnQgPSAwO1xuICAgICAgICAgICAgY3RybC5waXBlKCk7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGN0cmwuc29ydEJ5KHByZWRpY2F0ZSwgaW5kZXggJSAyID09PSAwKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBlbGVtZW50LmJpbmQoJ2NsaWNrJywgZnVuY3Rpb24gc29ydENsaWNrICgpIHtcbiAgICAgICAgICBpZiAocHJlZGljYXRlKSB7XG4gICAgICAgICAgICBzY29wZS4kYXBwbHkoc29ydCk7XG4gICAgICAgICAgfVxuICAgICAgICB9KTtcblxuICAgICAgICBpZiAoc29ydERlZmF1bHQpIHtcbiAgICAgICAgICBpbmRleCA9IHNvcnREZWZhdWx0ID09PSAncmV2ZXJzZScgPyAxIDogMDtcbiAgICAgICAgICBzb3J0KCk7XG4gICAgICAgIH1cblxuICAgICAgICAvL3RhYmxlIHN0YXRlIC0tPiB2aWV3XG4gICAgICAgIHNjb3BlLiR3YXRjaChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgcmV0dXJuIGN0cmwudGFibGVTdGF0ZSgpLnNvcnQ7XG4gICAgICAgIH0sIGZ1bmN0aW9uIChuZXdWYWx1ZSkge1xuICAgICAgICAgIGlmIChuZXdWYWx1ZS5wcmVkaWNhdGUgIT09IHByZWRpY2F0ZSkge1xuICAgICAgICAgICAgaW5kZXggPSAwO1xuICAgICAgICAgICAgZWxlbWVudFxuICAgICAgICAgICAgICAucmVtb3ZlQ2xhc3MoY2xhc3NBc2NlbnQpXG4gICAgICAgICAgICAgIC5yZW1vdmVDbGFzcyhjbGFzc0Rlc2NlbnQpO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBpbmRleCA9IG5ld1ZhbHVlLnJldmVyc2UgPT09IHRydWUgPyAyIDogMTtcbiAgICAgICAgICAgIGVsZW1lbnRcbiAgICAgICAgICAgICAgLnJlbW92ZUNsYXNzKHN0YXRlQ2xhc3Nlc1tpbmRleCAlIDJdKVxuICAgICAgICAgICAgICAuYWRkQ2xhc3Moc3RhdGVDbGFzc2VzW2luZGV4IC0gMV0pO1xuICAgICAgICAgIH1cbiAgICAgICAgfSwgdHJ1ZSk7XG4gICAgICB9XG4gICAgfTtcbiAgfV0pO1xuIiwibmcubW9kdWxlKCdzbWFydC10YWJsZScpXG4gIC5kaXJlY3RpdmUoJ3N0UGFnaW5hdGlvbicsIFsnc3RDb25maWcnLCBmdW5jdGlvbiAoc3RDb25maWcpIHtcbiAgICByZXR1cm4ge1xuICAgICAgcmVzdHJpY3Q6ICdFQScsXG4gICAgICByZXF1aXJlOiAnXnN0VGFibGUnLFxuICAgICAgc2NvcGU6IHtcbiAgICAgICAgc3RJdGVtc0J5UGFnZTogJz0/JyxcbiAgICAgICAgc3REaXNwbGF5ZWRQYWdlczogJz0/JyxcbiAgICAgICAgc3RQYWdlQ2hhbmdlOiAnJidcbiAgICAgIH0sXG4gICAgICB0ZW1wbGF0ZVVybDogZnVuY3Rpb24gKGVsZW1lbnQsIGF0dHJzKSB7XG4gICAgICAgIGlmIChhdHRycy5zdFRlbXBsYXRlKSB7XG4gICAgICAgICAgcmV0dXJuIGF0dHJzLnN0VGVtcGxhdGU7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHN0Q29uZmlnLnBhZ2luYXRpb24udGVtcGxhdGU7XG4gICAgICB9LFxuICAgICAgbGluazogZnVuY3Rpb24gKHNjb3BlLCBlbGVtZW50LCBhdHRycywgY3RybCkge1xuXG4gICAgICAgIHNjb3BlLnN0SXRlbXNCeVBhZ2UgPSBzY29wZS5zdEl0ZW1zQnlQYWdlID8gKyhzY29wZS5zdEl0ZW1zQnlQYWdlKSA6IHN0Q29uZmlnLnBhZ2luYXRpb24uaXRlbXNCeVBhZ2U7XG4gICAgICAgIHNjb3BlLnN0RGlzcGxheWVkUGFnZXMgPSBzY29wZS5zdERpc3BsYXllZFBhZ2VzID8gKyhzY29wZS5zdERpc3BsYXllZFBhZ2VzKSA6IHN0Q29uZmlnLnBhZ2luYXRpb24uZGlzcGxheWVkUGFnZXM7XG5cbiAgICAgICAgc2NvcGUuY3VycmVudFBhZ2UgPSAxO1xuICAgICAgICBzY29wZS5wYWdlcyA9IFtdO1xuXG4gICAgICAgIGZ1bmN0aW9uIHJlZHJhdyAoKSB7XG4gICAgICAgICAgdmFyIHBhZ2luYXRpb25TdGF0ZSA9IGN0cmwudGFibGVTdGF0ZSgpLnBhZ2luYXRpb247XG4gICAgICAgICAgdmFyIHN0YXJ0ID0gMTtcbiAgICAgICAgICB2YXIgZW5kO1xuICAgICAgICAgIHZhciBpO1xuICAgICAgICAgIHZhciBwcmV2UGFnZSA9IHNjb3BlLmN1cnJlbnRQYWdlO1xuICAgICAgICAgIHNjb3BlLmN1cnJlbnRQYWdlID0gTWF0aC5mbG9vcihwYWdpbmF0aW9uU3RhdGUuc3RhcnQgLyBwYWdpbmF0aW9uU3RhdGUubnVtYmVyKSArIDE7XG5cbiAgICAgICAgICBzdGFydCA9IE1hdGgubWF4KHN0YXJ0LCBzY29wZS5jdXJyZW50UGFnZSAtIE1hdGguYWJzKE1hdGguZmxvb3Ioc2NvcGUuc3REaXNwbGF5ZWRQYWdlcyAvIDIpKSk7XG4gICAgICAgICAgZW5kID0gc3RhcnQgKyBzY29wZS5zdERpc3BsYXllZFBhZ2VzO1xuXG4gICAgICAgICAgaWYgKGVuZCA+IHBhZ2luYXRpb25TdGF0ZS5udW1iZXJPZlBhZ2VzKSB7XG4gICAgICAgICAgICBlbmQgPSBwYWdpbmF0aW9uU3RhdGUubnVtYmVyT2ZQYWdlcyArIDE7XG4gICAgICAgICAgICBzdGFydCA9IE1hdGgubWF4KDEsIGVuZCAtIHNjb3BlLnN0RGlzcGxheWVkUGFnZXMpO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIHNjb3BlLnBhZ2VzID0gW107XG4gICAgICAgICAgc2NvcGUubnVtUGFnZXMgPSBwYWdpbmF0aW9uU3RhdGUubnVtYmVyT2ZQYWdlcztcblxuICAgICAgICAgIGZvciAoaSA9IHN0YXJ0OyBpIDwgZW5kOyBpKyspIHtcbiAgICAgICAgICAgIHNjb3BlLnBhZ2VzLnB1c2goaSk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgaWYgKHByZXZQYWdlICE9PSBzY29wZS5jdXJyZW50UGFnZSkge1xuICAgICAgICAgICAgc2NvcGUuc3RQYWdlQ2hhbmdlKHtuZXdQYWdlOiBzY29wZS5jdXJyZW50UGFnZX0pO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIC8vdGFibGUgc3RhdGUgLS0+IHZpZXdcbiAgICAgICAgc2NvcGUuJHdhdGNoKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICByZXR1cm4gY3RybC50YWJsZVN0YXRlKCkucGFnaW5hdGlvbjtcbiAgICAgICAgfSwgcmVkcmF3LCB0cnVlKTtcblxuICAgICAgICAvL3Njb3BlIC0tPiB0YWJsZSBzdGF0ZSAgKC0tPiB2aWV3KVxuICAgICAgICBzY29wZS4kd2F0Y2goJ3N0SXRlbXNCeVBhZ2UnLCBmdW5jdGlvbiAobmV3VmFsdWUsIG9sZFZhbHVlKSB7XG4gICAgICAgICAgaWYgKG5ld1ZhbHVlICE9PSBvbGRWYWx1ZSkge1xuICAgICAgICAgICAgc2NvcGUuc2VsZWN0UGFnZSgxKTtcbiAgICAgICAgICB9XG4gICAgICAgIH0pO1xuXG4gICAgICAgIHNjb3BlLiR3YXRjaCgnc3REaXNwbGF5ZWRQYWdlcycsIHJlZHJhdyk7XG5cbiAgICAgICAgLy92aWV3IC0+IHRhYmxlIHN0YXRlXG4gICAgICAgIHNjb3BlLnNlbGVjdFBhZ2UgPSBmdW5jdGlvbiAocGFnZSkge1xuICAgICAgICAgIGlmIChwYWdlID4gMCAmJiBwYWdlIDw9IHNjb3BlLm51bVBhZ2VzKSB7XG4gICAgICAgICAgICBjdHJsLnNsaWNlKChwYWdlIC0gMSkgKiBzY29wZS5zdEl0ZW1zQnlQYWdlLCBzY29wZS5zdEl0ZW1zQnlQYWdlKTtcbiAgICAgICAgICB9XG4gICAgICAgIH07XG5cbiAgICAgICAgaWYgKCFjdHJsLnRhYmxlU3RhdGUoKS5wYWdpbmF0aW9uLm51bWJlcikge1xuICAgICAgICAgIGN0cmwuc2xpY2UoMCwgc2NvcGUuc3RJdGVtc0J5UGFnZSk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9O1xuICB9XSk7XG4iLCJuZy5tb2R1bGUoJ3NtYXJ0LXRhYmxlJylcbiAgLmRpcmVjdGl2ZSgnc3RQaXBlJywgZnVuY3Rpb24gKCkge1xuICAgIHJldHVybiB7XG4gICAgICByZXF1aXJlOiAnc3RUYWJsZScsXG4gICAgICBzY29wZToge1xuICAgICAgICBzdFBpcGU6ICc9J1xuICAgICAgfSxcbiAgICAgIGxpbms6IHtcblxuICAgICAgICBwcmU6IGZ1bmN0aW9uIChzY29wZSwgZWxlbWVudCwgYXR0cnMsIGN0cmwpIHtcbiAgICAgICAgICBpZiAobmcuaXNGdW5jdGlvbihzY29wZS5zdFBpcGUpKSB7XG4gICAgICAgICAgICBjdHJsLnByZXZlbnRQaXBlT25XYXRjaCgpO1xuICAgICAgICAgICAgY3RybC5waXBlID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICByZXR1cm4gc2NvcGUuc3RQaXBlKGN0cmwudGFibGVTdGF0ZSgpLCBjdHJsKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH0sXG5cbiAgICAgICAgcG9zdDogZnVuY3Rpb24gKHNjb3BlLCBlbGVtZW50LCBhdHRycywgY3RybCkge1xuICAgICAgICAgIGN0cmwucGlwZSgpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfTtcbiAgfSk7XG4iLCJ9KShhbmd1bGFyKTsiXSwic291cmNlUm9vdCI6Ii9zb3VyY2UvIn0=
571 }]);
572
573 })(angular);
00 /**
1 * @version 1.4.13
1 * @version 2.1.11
22 * @license MIT
33 */
4 !function(t,e){"use strict";t.module("smart-table",[]).run(["$templateCache",function(t){t.put("template/smart-table/pagination.html",'<nav ng-if="pages.length >= 2"><ul class="pagination"><li ng-repeat="page in pages" ng-class="{active: page==currentPage}"><a ng-click="selectPage(page)">{{page}}</a></li></ul></nav>')}]),t.module("smart-table").constant("stConfig",{pagination:{template:"template/smart-table/pagination.html",itemsByPage:10,displayedPages:5},search:{delay:400},select:{mode:"single",selectedClass:"st-selected"},sort:{ascentClass:"st-sort-ascent",descentClass:"st-sort-descent"}}),t.module("smart-table").controller("stTableController",["$scope","$parse","$filter","$attrs",function(a,s,n,r){function i(t){return t?[].concat(t):[]}function c(){h=i(l(a)),P===!0&&S.pipe()}var l,o,u,p=r.stTable,g=s(p),f=g.assign,d=n("orderBy"),m=n("filter"),h=i(g(a)),b={sort:{},search:{},pagination:{start:0}},P=!0,S=this;r.stSafeSrc&&(l=s(r.stSafeSrc),a.$watch(function(){var t=l(a);return t?t.length:0},function(t){t!==h.length&&c()}),a.$watch(function(){return l(a)},function(t,e){t!==e&&c()})),this.sortBy=function(e,a){return b.sort.predicate=e,b.sort.reverse=a===!0,t.isFunction(e)?b.sort.functionName=e.name:delete b.sort.functionName,b.pagination.start=0,this.pipe()},this.search=function(e,a){var s=b.search.predicateObject||{},n=a?a:"$";return e=t.isString(e)?e.trim():e,s[n]=e,e||delete s[n],b.search.predicateObject=s,b.pagination.start=0,this.pipe()},this.pipe=function(){var t,s=b.pagination;o=b.search.predicateObject?m(h,b.search.predicateObject):h,b.sort.predicate&&(o=d(o,b.sort.predicate,b.sort.reverse)),s.number!==e&&(s.numberOfPages=o.length>0?Math.ceil(o.length/s.number):1,s.start=s.start>=o.length?(s.numberOfPages-1)*s.number:s.start,t=o.slice(s.start,s.start+parseInt(s.number))),f(a,t||o)},this.select=function(t,a){var s=h,n=s.indexOf(t);-1!==n&&("single"===a?(t.isSelected=t.isSelected!==!0,u&&(u.isSelected=!1),u=t.isSelected===!0?t:e):s[n].isSelected=!s[n].isSelected)},this.slice=function(t,e){return b.pagination.start=t,b.pagination.number=e,this.pipe()},this.tableState=function(){return b},this.getFilteredCollection=function(){return o||h},this.setFilterFunction=function(t){m=n(t)},this.setSortFunction=function(t){d=n(t)},this.preventPipeOnWatch=function(){P=!1}}]).directive("stTable",function(){return{restrict:"A",controller:"stTableController",link:function(t,e,a,s){a.stSetFilter&&s.setFilterFunction(a.stSetFilter),a.stSetSort&&s.setSortFunction(a.stSetSort)}}}),t.module("smart-table").directive("stSearch",["stConfig","$timeout",function(t,e){return{require:"^stTable",scope:{predicate:"=?stSearch"},link:function(a,s,n,r){var i=r,c=null,l=n.stDelay||t.search.delay;a.$watch("predicate",function(t,e){t!==e&&(r.tableState().search={},i.search(s[0].value||"",t))}),a.$watch(function(){return r.tableState().search},function(t){var e=a.predicate||"$";t.predicateObject&&t.predicateObject[e]!==s[0].value&&(s[0].value=t.predicateObject[e]||"")},!0),s.bind("input",function(t){t=t.originalEvent||t,null!==c&&e.cancel(c),c=e(function(){i.search(t.target.value,a.predicate||""),c=null},l)})}}}]),t.module("smart-table").directive("stSelectRow",["stConfig",function(t){return{restrict:"A",require:"^stTable",scope:{row:"=stSelectRow"},link:function(e,a,s,n){var r=s.stSelectMode||t.select.mode;a.bind("click",function(){e.$apply(function(){n.select(e.row,r)})}),e.$watch("row.isSelected",function(e){e===!0?a.addClass(t.select.selectedClass):a.removeClass(t.select.selectedClass)})}}}]),t.module("smart-table").directive("stSort",["stConfig","$parse",function(a,s){return{restrict:"A",require:"^stTable",link:function(n,r,i,c){function l(){g++,u=t.isFunction(p(n))?p(n):i.stSort,g%3===0&&i.stSkipNatural===e?(g=0,c.tableState().sort={},c.tableState().pagination.start=0,c.pipe()):c.sortBy(u,g%2===0)}var o,u=i.stSort,p=s(u),g=0,f=i.stClassAscent||a.sort.ascentClass,d=i.stClassDescent||a.sort.descentClass,m=[f,d];i.stSortDefault&&(o=n.$eval(i.stSortDefault)!==e?n.$eval(i.stSortDefault):i.stSortDefault),r.bind("click",function(){u&&n.$apply(l)}),o&&(g="reverse"===o?1:0,l()),n.$watch(function(){return c.tableState().sort},function(t){t.predicate!==u?(g=0,r.removeClass(f).removeClass(d)):(g=t.reverse===!0?2:1,r.removeClass(m[g%2]).addClass(m[g-1]))},!0)}}}]),t.module("smart-table").directive("stPagination",["stConfig",function(t){return{restrict:"EA",require:"^stTable",scope:{stItemsByPage:"=?",stDisplayedPages:"=?",stPageChange:"&"},templateUrl:function(e,a){return a.stTemplate?a.stTemplate:t.pagination.template},link:function(e,a,s,n){function r(){var t,a,s=n.tableState().pagination,r=1,i=e.currentPage;for(e.currentPage=Math.floor(s.start/s.number)+1,r=Math.max(r,e.currentPage-Math.abs(Math.floor(e.stDisplayedPages/2))),t=r+e.stDisplayedPages,t>s.numberOfPages&&(t=s.numberOfPages+1,r=Math.max(1,t-e.stDisplayedPages)),e.pages=[],e.numPages=s.numberOfPages,a=r;t>a;a++)e.pages.push(a);i!==e.currentPage&&e.stPageChange({newPage:e.currentPage})}e.stItemsByPage=e.stItemsByPage?+e.stItemsByPage:t.pagination.itemsByPage,e.stDisplayedPages=e.stDisplayedPages?+e.stDisplayedPages:t.pagination.displayedPages,e.currentPage=1,e.pages=[],e.$watch(function(){return n.tableState().pagination},r,!0),e.$watch("stItemsByPage",function(t,a){t!==a&&e.selectPage(1)}),e.$watch("stDisplayedPages",r),e.selectPage=function(t){t>0&&t<=e.numPages&&n.slice((t-1)*e.stItemsByPage,e.stItemsByPage)},n.tableState().pagination.number||n.slice(0,e.stItemsByPage)}}}]),t.module("smart-table").directive("stPipe",function(){return{require:"stTable",scope:{stPipe:"="},link:{pre:function(e,a,s,n){t.isFunction(e.stPipe)&&(n.preventPipeOnWatch(),n.pipe=function(){return e.stPipe(n.tableState(),n)})},post:function(t,e,a,s){s.pipe()}}}})}(angular);
4 !function(t,e){"use strict";t.module("smart-table",[]).run(["$templateCache",function(t){t.put("template/smart-table/pagination.html",'<nav ng-if="numPages && pages.length >= 2"><ul class="pagination"><li ng-repeat="page in pages" ng-class="{active: page==currentPage}"><a href="#" ng-click="selectPage(page); $event.preventDefault(); $event.stopPropagation();">{{page}}</a></li></ul></nav>')}]),t.module("smart-table").constant("stConfig",{pagination:{template:"template/smart-table/pagination.html",itemsByPage:10,displayedPages:5},search:{delay:400,inputEvent:"input",trimSearch:!1},select:{mode:"single",selectedClass:"st-selected"},sort:{ascentClass:"st-sort-ascent",descentClass:"st-sort-descent",descendingFirst:!1,skipNatural:!1,delay:300},pipe:{delay:100}}),t.module("smart-table").controller("stTableController",["$scope","$parse","$filter","$attrs",function(a,n,s,r){function i(t){return t?[].concat(t):[]}function c(){b=i(o(a)),!0===S&&P.pipe()}function l(t,e){if(-1!=e.indexOf(".")){var a=e.split("."),s=a.pop(),r=a.join("."),i=n(r)(t);delete i[s],0==Object.keys(i).length&&l(t,r)}else delete t[e]}var o,u,p,g=r.stTable,d=n(g),f=d.assign,m=s("orderBy"),h=s("filter"),b=i(d(a)),v={sort:{},search:{},pagination:{start:0,totalItemCount:0}},S=!0,P=this;r.stSafeSrc&&(o=n(r.stSafeSrc),a.$watch(function(){var t=o(a);return t&&t.length?t[0]:e},function(t,e){t!==e&&c()}),a.$watch(function(){var t=o(a);return t?t.length:0},function(t,e){t!==b.length&&c()}),a.$watch(function(){return o(a)},function(t,e){t!==e&&(v.pagination.start=0,c())})),this.sortBy=function(e,a){return v.sort.predicate=e,v.sort.reverse=!0===a,t.isFunction(e)?v.sort.functionName=e.name:delete v.sort.functionName,v.pagination.start=0,this.pipe()},this.search=function(t,e,a){var s=v.search.predicateObject||{},r=e||"$";return n(r).assign(s,t),t||l(s,r),v.search.predicateObject=s,v.pagination.start=0,this.pipe()},this.pipe=function(){var t,n=v.pagination;u=v.search.predicateObject?h(b,v.search.predicateObject):b,v.sort.predicate&&(u=m(u,v.sort.predicate,v.sort.reverse)),n.totalItemCount=u.length,n.number!==e&&(n.numberOfPages=u.length>0?Math.ceil(u.length/n.number):1,n.start=n.start>=u.length?(n.numberOfPages-1)*n.number:n.start,t=u.slice(n.start,n.start+parseInt(n.number))),f(a,t||u)},this.select=function(t,n){var s=i(d(a)),r=s.indexOf(t);-1!==r&&("single"===n?(t.isSelected=!0!==t.isSelected,p&&(p.isSelected=!1),p=!0===t.isSelected?t:e):s[r].isSelected=!s[r].isSelected)},this.slice=function(t,e){return v.pagination.start=t,v.pagination.number=e,this.pipe()},this.tableState=function(){return v},this.getFilteredCollection=function(){return u||b},this.setFilterFunction=function(t){h=s(t)},this.setSortFunction=function(t){m=s(t)},this.preventPipeOnWatch=function(){S=!1}}]).directive("stTable",function(){return{restrict:"A",controller:"stTableController",link:function(t,e,a,n){a.stSetFilter&&n.setFilterFunction(a.stSetFilter),a.stSetSort&&n.setSortFunction(a.stSetSort)}}}),t.module("smart-table").directive("stSearch",["stConfig","$timeout","$parse",function(e,a,n){return{require:"^stTable",link:function(s,r,i,c){var l=c,o=null,u=i.stDelay||e.search.delay,p=i.stInputEvent||e.search.inputEvent,g=i.trimSearch||e.search.trimSearch;i.$observe("stSearch",function(e,a){var n=r[0].value;e!==a&&n&&(c.tableState().search={},n=t.isString(n)&&g?n.trim():n,l.search(n,e))}),s.$watch(function(){return c.tableState().search},function(t,e){var a=i.stSearch||"$";t.predicateObject&&n(a)(t.predicateObject)!==r[0].value&&(r[0].value=n(a)(t.predicateObject)||"")},!0),r.bind(p,function(e){e=e.originalEvent||e,null!==o&&a.cancel(o),o=a(function(){var a=e.target.value;a=t.isString(a)&&g?a.trim():a,l.search(a,i.stSearch||""),o=null},u)})}}}]),t.module("smart-table").directive("stSelectRow",["stConfig",function(t){return{restrict:"A",require:"^stTable",scope:{row:"=stSelectRow"},link:function(e,a,n,s){var r=n.stSelectMode||t.select.mode;a.bind("click",function(){e.$apply(function(){s.select(e.row,r)})}),e.$watch("row.isSelected",function(e){!0===e?a.addClass(t.select.selectedClass):a.removeClass(t.select.selectedClass)})}}}]),t.module("smart-table").directive("stSort",["stConfig","$parse","$timeout",function(a,n,s){return{restrict:"A",require:"^stTable",link:function(r,i,c,l){function o(){v?d=0===d?2:d-1:d++;var e;p=t.isFunction(g(r))||t.isArray(g(r))?g(r):c.stSort,d%3==0&&!0!=!!b?(d=0,l.tableState().sort={},l.tableState().pagination.start=0,e=l.pipe.bind(l)):e=l.sortBy.bind(l,p,d%2==0),null!==S&&s.cancel(S),P<0?e():S=s(function(){e()},P)}var u,p=c.stSort,g=n(p),d=0,f=c.stClassAscent||a.sort.ascentClass,m=c.stClassDescent||a.sort.descentClass,h=[f,m],b=c.stSkipNatural!==e?c.stSkipNatural:a.sort.skipNatural,v=c.stDescendingFirst!==e?c.stDescendingFirst:a.sort.descendingFirst,S=null,P=c.stDelay||a.sort.delay,y="aria-sort";i.attr("role","columnheader").attr(y,"none"),c.stSortDefault&&(u=r.$eval(c.stSortDefault)!==e?r.$eval(c.stSortDefault):c.stSortDefault),i.bind("click",function(){p&&r.$apply(o)}),u&&(d="reverse"===u?1:0,o()),r.$watch(function(){return l.tableState().sort},function(t){t.predicate!==p?(d=0,i.removeClass(f).removeClass(m).attr(y,"none")):(d=!0===t.reverse?2:1,i.removeClass(h[d%2]).addClass(h[d-1]).attr(y,t.reverse?"ascending":"descending"))},!0)}}}]),t.module("smart-table").directive("stPagination",["stConfig",function(t){return{restrict:"EA",require:"^stTable",scope:{stItemsByPage:"=?",stDisplayedPages:"=?",stPageChange:"&"},templateUrl:function(e,a){return a.stTemplate?a.stTemplate:t.pagination.template},link:function(e,a,n,s){function r(){var t,a,n=s.tableState().pagination,r=1,i=e.currentPage;for(e.totalItemCount=n.totalItemCount,e.currentPage=Math.floor(n.start/n.number)+1,(t=(r=Math.max(r,e.currentPage-Math.abs(Math.floor(e.stDisplayedPages/2))))+e.stDisplayedPages)>n.numberOfPages&&(t=n.numberOfPages+1,r=Math.max(1,t-e.stDisplayedPages)),e.pages=[],e.numPages=n.numberOfPages,a=r;a<t;a++)e.pages.push(a);i!==e.currentPage&&e.stPageChange({newPage:e.currentPage})}e.stItemsByPage=e.stItemsByPage?+e.stItemsByPage:t.pagination.itemsByPage,e.stDisplayedPages=e.stDisplayedPages?+e.stDisplayedPages:t.pagination.displayedPages,e.currentPage=1,e.pages=[],e.$watch(function(){return s.tableState().pagination},r,!0),e.$watch("stItemsByPage",function(t,a){t!==a&&e.selectPage(1)}),e.$watch("stDisplayedPages",r),e.selectPage=function(t){t>0&&t<=e.numPages&&s.slice((t-1)*e.stItemsByPage,e.stItemsByPage)},s.tableState().pagination.number||s.slice(0,e.stItemsByPage)}}}]),t.module("smart-table").directive("stPipe",["stConfig","$timeout",function(e,a){return{require:"stTable",scope:{stPipe:"="},link:{pre:function(n,s,r,i){var c=null;t.isFunction(n.stPipe)&&(i.preventPipeOnWatch(),i.pipe=function(){return null!==c&&a.cancel(c),c=a(function(){n.stPipe(i.tableState(),i)},e.pipe.delay)})},post:function(t,e,a,n){n.pipe()}}}}])}(angular);
5 //# sourceMappingURL=smart-table.min.js.map
0 {"version":3,"sources":["smart-table.min.js"],"names":["ng","undefined","module","run","$templateCache","put","constant","pagination","template","itemsByPage","displayedPages","search","delay","inputEvent","trimSearch","select","mode","selectedClass","sort","ascentClass","descentClass","descendingFirst","skipNatural","pipe","controller","$scope","$parse","$filter","$attrs","copyRefs","src","concat","updateSafeCopy","safeCopy","safeGetter","pipeAfterSafeCopy","ctrl","deepDelete","object","path","indexOf","partials","split","key","pop","parentPath","join","parentObject","Object","keys","length","filtered","lastSelected","propertyName","stTable","displayGetter","displaySetter","assign","orderBy","filter","tableState","start","totalItemCount","this","stSafeSrc","$watch","safeSrc","newValue","oldValue","sortBy","predicate","reverse","isFunction","functionName","name","input","comparator","predicateObject","prop","output","number","numberOfPages","Math","ceil","slice","parseInt","row","rows","index","isSelected","getFilteredCollection","setFilterFunction","filterName","setSortFunction","sortFunctionName","preventPipeOnWatch","directive","restrict","link","scope","element","attr","stSetFilter","stSetSort","stConfig","$timeout","require","tableCtrl","promise","throttle","stDelay","event","stInputEvent","$observe","value","isString","trim","predicateExpression","stSearch","bind","evt","originalEvent","cancel","target","stSelectMode","$apply","addClass","removeClass","func","getter","isArray","stSort","sortDefault","classAscent","stClassAscent","classDescent","stClassDescent","stateClasses","stSkipNatural","stDescendingFirst","ariaSort","stSortDefault","$eval","stItemsByPage","stDisplayedPages","stPageChange","templateUrl","attrs","stTemplate","redraw","end","i","paginationState","prevPage","currentPage","floor","max","abs","pages","numPages","push","newPage","selectPage","page","config","stPipe","pre","pipePromise","post","angular"],"mappings":"CAAA,SAAWA,EAAIC,GACX,aAEJD,EAAGE,OAAO,kBAAmBC,KAAK,iBAAkB,SAAUC,GAC1DA,EAAeC,IAAI,uCACf,sQAMRL,EAAGE,OAAO,eACPI,SAAS,YACRC,YACEC,SAAU,uCACVC,YAAa,GACbC,eAAgB,GAElBC,QACEC,MAAO,IACPC,WAAY,QACZC,YAAY,GAEdC,QACEC,KAAM,SACNC,cAAe,eAEjBC,MACEC,YAAa,iBACbC,aAAc,kBACdC,iBAAiB,EACjBC,aAAa,EACbV,MAAM,KAERW,MACEX,MAAO,OAGbZ,EAAGE,OAAO,eAAesB,WAAW,qBAClC,SACA,SACA,UACA,SACA,SAA2BC,EAAQC,EAAQC,EAASC,GAkBlD,SAASC,EAASC,GAChB,OAAOA,KAASC,OAAOD,MAGzB,SAASE,IACPC,EAAWJ,EAASK,EAAWT,KACL,IAAtBU,GACFC,EAAKb,OAIT,SAASc,EAAWC,EAAQC,GAC1B,IAA0B,GAAtBA,EAAKC,QAAQ,KAAY,CAC3B,IAAIC,EAAWF,EAAKG,MAAM,KACtBC,EAAMF,EAASG,MACfC,EAAaJ,EAASK,KAAK,KAC3BC,EAAerB,EAAOmB,EAAPnB,CAAmBY,UAC/BS,EAAaJ,GACoB,GAApCK,OAAOC,KAAKF,GAAcG,QAC5Bb,EAAWC,EAAQO,eAGdP,EAAOC,GAvClB,IAGIL,EASAiB,EAGAC,EAfAC,EAAezB,EAAO0B,QACtBC,EAAgB7B,EAAO2B,GACvBG,EAAgBD,EAAcE,OAE9BC,EAAU/B,EAAQ,WAClBgC,EAAShC,EAAQ,UACjBM,EAAWJ,EAAS0B,EAAc9B,IAClCmC,GACF1C,QACAP,UACAJ,YAAcsD,MAAO,EAAGC,eAAgB,IAGtC3B,GAAoB,EACpBC,EAAO2B,KA6BPnC,EAAOoC,YACT9B,EAAaR,EAAOE,EAAOoC,WAC3BvC,EAAOwC,OACL,WACE,IAAIC,EAAUhC,EAAWT,GACzB,OAAOyC,GAAWA,EAAQhB,OAASgB,EAAQ,GAAKjE,GAElD,SAASkE,EAAUC,GACbD,IAAaC,GACfpC,MAINP,EAAOwC,OACL,WACE,IAAIC,EAAUhC,EAAWT,GACzB,OAAOyC,EAAUA,EAAQhB,OAAS,GAEpC,SAASiB,EAAUC,GACbD,IAAalC,EAASiB,QACxBlB,MAINP,EAAOwC,OACL,WACE,OAAO/B,EAAWT,IAEpB,SAAS0C,EAAUC,GACbD,IAAaC,IACfR,EAAWrD,WAAWsD,MAAQ,EAC9B7B,QAWR+B,KAAKM,OAAS,SAAgBC,EAAWC,GAWvC,OAVAX,EAAW1C,KAAKoD,UAAYA,EAC5BV,EAAW1C,KAAKqD,SAAsB,IAAZA,EAEtBvE,EAAGwE,WAAWF,GAChBV,EAAW1C,KAAKuD,aAAeH,EAAUI,YAElCd,EAAW1C,KAAKuD,aAGzBb,EAAWrD,WAAWsD,MAAQ,EACvBE,KAAKxC,QASdwC,KAAKpD,OAAS,SAAgBgE,EAAOL,EAAWM,GAC9C,IAAIC,EAAkBjB,EAAWjD,OAAOkE,oBACpCC,EAAOR,GAAwB,IASnC,OAPA5C,EAAOoD,GAAMrB,OAAOoB,EAAiBF,GAEhCA,GACHtC,EAAWwC,EAAiBC,GAE9BlB,EAAWjD,OAAOkE,gBAAkBA,EACpCjB,EAAWrD,WAAWsD,MAAQ,EACvBE,KAAKxC,QAMdwC,KAAKxC,KAAO,WACV,IACIwD,EADAxE,EAAaqD,EAAWrD,WAE5B4C,EAAWS,EAAWjD,OAAOkE,gBACzBlB,EAAO1B,EAAU2B,EAAWjD,OAAOkE,iBACnC5C,EACA2B,EAAW1C,KAAKoD,YAClBnB,EAAWO,EACTP,EACAS,EAAW1C,KAAKoD,UAChBV,EAAW1C,KAAKqD,UAGpBhE,EAAWuD,eAAiBX,EAASD,OACjC3C,EAAWyE,SAAW/E,IACxBM,EAAW0E,cAAgB9B,EAASD,OAAS,EACzCgC,KAAKC,KAAKhC,EAASD,OAAS3C,EAAWyE,QACvC,EACJzE,EAAWsD,MAAQtD,EAAWsD,OAASV,EAASD,QAC3C3C,EAAW0E,cAAgB,GAAK1E,EAAWyE,OAC5CzE,EAAWsD,MACfkB,EAAS5B,EAASiC,MAChB7E,EAAWsD,MACXtD,EAAWsD,MAAQwB,SAAS9E,EAAWyE,UAG3CxB,EAAc/B,EAAQsD,GAAU5B,IAQlCY,KAAKhD,OAAS,SAAgBuE,EAAKtE,GACjC,IAAIuE,EAAO1D,EAAS0B,EAAc9B,IAC9B+D,EAAQD,EAAK/C,QAAQ8C,IACV,IAAXE,IACW,WAATxE,GACFsE,EAAIG,YAAgC,IAAnBH,EAAIG,WACjBrC,IACFA,EAAaqC,YAAa,GAE5BrC,GAAkC,IAAnBkC,EAAIG,WAAsBH,EAAMrF,GAE/CsF,EAAKC,GAAOC,YAAcF,EAAKC,GAAOC,aAW5C1B,KAAKqB,MAAQ,SAAgBvB,EAAOmB,GAGlC,OAFApB,EAAWrD,WAAWsD,MAAQA,EAC9BD,EAAWrD,WAAWyE,OAASA,EACxBjB,KAAKxC,QAOdwC,KAAKH,WAAa,WAChB,OAAOA,GAGTG,KAAK2B,sBAAwB,WAC3B,OAAOvC,GAAYlB,GAOrB8B,KAAK4B,kBAAoB,SAA2BC,GAClDjC,EAAShC,EAAQiE,IAOnB7B,KAAK8B,gBAAkB,SAAyBC,GAC9CpC,EAAU/B,EAAQmE,IAOpB/B,KAAKgC,mBAAqB,WACxB5D,GAAoB,MAGvB6D,UAAU,UAAW,WACtB,OACEC,SAAU,IACVzE,WAAY,oBACZ0E,KAAM,SAASC,EAAOC,EAASC,EAAMjE,GAC/BiE,EAAKC,aACPlE,EAAKuD,kBAAkBU,EAAKC,aAG1BD,EAAKE,WACPnE,EAAKyD,gBAAgBQ,EAAKE,eAMlCvG,EAAGE,OAAO,eACP8F,UAAU,YAAa,WAAY,WAAW,SAAU,SAAUQ,EAAUC,EAAU/E,GACrF,OACEgF,QAAS,WACTR,KAAM,SAAUC,EAAOC,EAASC,EAAMjE,GACpC,IAAIuE,EAAYvE,EACZwE,EAAU,KACVC,EAAWR,EAAKS,SAAWN,EAAS7F,OAAOC,MAC3CmG,EAAQV,EAAKW,cAAgBR,EAAS7F,OAAOE,WAC7CC,EAAauF,EAAKvF,YAAc0F,EAAS7F,OAAOG,WAEpDuF,EAAKY,SAAS,WAAY,SAAU9C,EAAUC,GAC5C,IAAIO,EAAQyB,EAAQ,GAAGc,MACnB/C,IAAaC,GAAYO,IAC3BvC,EAAKwB,aAAajD,UAClBgE,EAAQ3E,EAAGmH,SAASxC,IAAU7D,EAAa6D,EAAMyC,OAASzC,EAC1DgC,EAAUhG,OAAOgE,EAAOR,MAK5BgC,EAAMlC,OAAO,WACX,OAAO7B,EAAKwB,aAAajD,QACxB,SAAUwD,EAAUC,GACrB,IAAIiD,EAAsBhB,EAAKiB,UAAY,IACvCnD,EAASU,iBAAmBnD,EAAO2F,EAAP3F,CAA4ByC,EAASU,mBAAqBuB,EAAQ,GAAGc,QACnGd,EAAQ,GAAGc,MAAQxF,EAAO2F,EAAP3F,CAA4ByC,EAASU,kBAAoB,MAE7E,GAGHuB,EAAQmB,KAAKR,EAAO,SAAUS,GAC5BA,EAAMA,EAAIC,eAAiBD,EACX,OAAZZ,GACFH,EAASiB,OAAOd,GAGlBA,EAAUH,EAAS,WACjB,IAAI9B,EAAQ6C,EAAIG,OAAOT,MACvBvC,EAAQ3E,EAAGmH,SAASxC,IAAU7D,EAAa6D,EAAMyC,OAASzC,EAC1DgC,EAAUhG,OAAOgE,EAAO0B,EAAKiB,UAAY,IACzCV,EAAU,MACTC,UAMb7G,EAAGE,OAAO,eACP8F,UAAU,eAAgB,WAAY,SAAUQ,GAC/C,OACEP,SAAU,IACVS,QAAS,WACTP,OACEb,IAAK,gBAEPY,KAAM,SAAUC,EAAOC,EAASC,EAAMjE,GACpC,IAAIpB,EAAOqF,EAAKuB,cAAgBpB,EAASzF,OAAOC,KAChDoF,EAAQmB,KAAK,QAAS,WACpBpB,EAAM0B,OAAO,WACXzF,EAAKrB,OAAOoF,EAAMb,IAAKtE,OAI3BmF,EAAMlC,OAAO,iBAAkB,SAAUE,IACtB,IAAbA,EACFiC,EAAQ0B,SAAStB,EAASzF,OAAOE,eAEjCmF,EAAQ2B,YAAYvB,EAASzF,OAAOE,sBAOhDjB,EAAGE,OAAO,eACP8F,UAAU,UAAW,WAAY,SAAU,WAAY,SAAUQ,EAAU9E,EAAQ+E,GAClF,OACER,SAAU,IACVS,QAAS,WACTR,KAAM,SAAUC,EAAOC,EAASC,EAAMjE,GA4BpC,SAASlB,IACHG,EACFmE,EAAkB,IAAVA,EAAc,EAAIA,EAAQ,EAElCA,IAGF,IAAIwC,EACJ1D,EAAYtE,EAAGwE,WAAWyD,EAAO9B,KAAWnG,EAAGkI,QAAQD,EAAO9B,IAAU8B,EAAO9B,GAASE,EAAK8B,OACzF3C,EAAQ,GAAM,IAAuB,KAAhBlE,GAEvBkE,EAAQ,EACRpD,EAAKwB,aAAa1C,QAClBkB,EAAKwB,aAAarD,WAAWsD,MAAQ,EACrCmE,EAAO5F,EAAKb,KAAKgG,KAAKnF,IAEtB4F,EAAO5F,EAAKiC,OAAOkD,KAAKnF,EAAMkC,EAAWkB,EAAQ,GAAM,GAEzC,OAAZoB,GACFH,EAASiB,OAAOd,GAEdC,EAAW,EACbmB,IAEApB,EAAUH,EAAS,WACjBuB,KACCnB,GApDP,IAMIuB,EANA9D,EAAY+B,EAAK8B,OACjBF,EAASvG,EAAO4C,GAChBkB,EAAQ,EACR6C,EAAchC,EAAKiC,eAAiB9B,EAAStF,KAAKC,YAClDoH,EAAelC,EAAKmC,gBAAkBhC,EAAStF,KAAKE,aACpDqH,GAAgBJ,EAAaE,GAE7BjH,EAAc+E,EAAKqC,gBAAkBzI,EAAYoG,EAAKqC,cAAgBlC,EAAStF,KAAKI,YACpFD,EAAkBgF,EAAKsC,oBAAsB1I,EAAYoG,EAAKsC,kBAAoBnC,EAAStF,KAAKG,gBAChGuF,EAAU,KACVC,EAAWR,EAAKS,SAAWN,EAAStF,KAAKN,MAGzCgI,EAAW,YAIfxC,EACGC,KAAK,OAAQ,gBACbA,KAAKuC,EALW,QAOfvC,EAAKwC,gBACPT,EAAcjC,EAAM2C,MAAMzC,EAAKwC,iBAAmB5I,EAAYkG,EAAM2C,MAAMzC,EAAKwC,eAAiBxC,EAAKwC,eAkCvGzC,EAAQmB,KAAK,QAAS,WAChBjD,GACF6B,EAAM0B,OAAO3G,KAIbkH,IACF5C,EAAwB,YAAhB4C,EAA4B,EAAI,EACxClH,KAIFiF,EAAMlC,OAAO,WACX,OAAO7B,EAAKwB,aAAa1C,MACxB,SAAUiD,GACPA,EAASG,YAAcA,GACzBkB,EAAQ,EACRY,EACG2B,YAAYM,GACZN,YAAYQ,GACZlC,KAAKuC,EA9DO,UAgEfpD,GAA6B,IAArBrB,EAASI,QAAmB,EAAI,EACxC6B,EACG2B,YAAYU,EAAajD,EAAQ,IACjCsC,SAASW,EAAajD,EAAQ,IAC9Ba,KAAKuC,EAAUzE,EAASI,QAnEP,YACC,iBAoEtB,QAKXvE,EAAGE,OAAO,eACP8F,UAAU,gBAAiB,WAAY,SAAUQ,GAChD,OACEP,SAAU,KACVS,QAAS,WACTP,OACE4C,cAAe,KACfC,iBAAkB,KAClBC,aAAc,KAEhBC,YAAa,SAAU9C,EAAS+C,GAC9B,OAAIA,EAAMC,WACDD,EAAMC,WAER5C,EAASjG,WAAWC,UAE7B0F,KAAM,SAAUC,EAAOC,EAAS+C,EAAO/G,GAQrC,SAASiH,IACP,IAEIC,EACAC,EAHAC,EAAkBpH,EAAKwB,aAAarD,WACpCsD,EAAQ,EAGR4F,EAAWtD,EAAMuD,YAerB,IAdAvD,EAAMrC,eAAiB0F,EAAgB1F,eACvCqC,EAAMuD,YAAcxE,KAAKyE,MAAMH,EAAgB3F,MAAQ2F,EAAgBxE,QAAU,GAGjFsE,GADAzF,EAAQqB,KAAK0E,IAAI/F,EAAOsC,EAAMuD,YAAcxE,KAAK2E,IAAI3E,KAAKyE,MAAMxD,EAAM6C,iBAAmB,MAC3E7C,EAAM6C,kBAEVQ,EAAgBvE,gBACxBqE,EAAME,EAAgBvE,cAAgB,EACtCpB,EAAQqB,KAAK0E,IAAI,EAAGN,EAAMnD,EAAM6C,mBAGlC7C,EAAM2D,SACN3D,EAAM4D,SAAWP,EAAgBvE,cAE5BsE,EAAI1F,EAAO0F,EAAID,EAAKC,IACvBpD,EAAM2D,MAAME,KAAKT,GAGfE,IAAatD,EAAMuD,aACrBvD,EAAM8C,cAAcgB,QAAS9D,EAAMuD,cA/BvCvD,EAAM4C,cAAgB5C,EAAM4C,eAAkB5C,EAAmB,cAAIK,EAASjG,WAAWE,YACzF0F,EAAM6C,iBAAmB7C,EAAM6C,kBAAqB7C,EAAsB,iBAAIK,EAASjG,WAAWG,eAElGyF,EAAMuD,YAAc,EACpBvD,EAAM2D,SAgCN3D,EAAMlC,OAAO,WACX,OAAO7B,EAAKwB,aAAarD,YACxB8I,GAAQ,GAGXlD,EAAMlC,OAAO,gBAAiB,SAAUE,EAAUC,GAC5CD,IAAaC,GACf+B,EAAM+D,WAAW,KAIrB/D,EAAMlC,OAAO,mBAAoBoF,GAGjClD,EAAM+D,WAAa,SAAUC,GACvBA,EAAO,GAAKA,GAAQhE,EAAM4D,UAC5B3H,EAAKgD,OAAO+E,EAAO,GAAKhE,EAAM4C,cAAe5C,EAAM4C,gBAIlD3G,EAAKwB,aAAarD,WAAWyE,QAChC5C,EAAKgD,MAAM,EAAGe,EAAM4C,oBAM9B/I,EAAGE,OAAO,eACP8F,UAAU,UAAW,WAAY,WAAY,SAAUoE,EAAQ3D,GAC9D,OACEC,QAAS,UACTP,OACEkE,OAAQ,KAEVnE,MAEEoE,IAAK,SAAUnE,EAAOC,EAAS+C,EAAO/G,GAEpC,IAAImI,EAAc,KAEdvK,EAAGwE,WAAW2B,EAAMkE,UACtBjI,EAAK2D,qBACL3D,EAAKb,KAAO,WAUV,OARoB,OAAhBgJ,GACF9D,EAASiB,OAAO6C,GAGlBA,EAAc9D,EAAS,WACrBN,EAAMkE,OAAOjI,EAAKwB,aAAcxB,IAC/BgI,EAAO7I,KAAKX,UAOrB4J,KAAM,SAAUrE,EAAOC,EAAS+C,EAAO/G,GACrCA,EAAKb,aAnjBf,CAyjBGkJ","file":"smart-table.min.js","sourcesContent":["(function (ng, undefined){\n 'use strict';\n\nng.module('smart-table', []).run(['$templateCache', function ($templateCache) {\n $templateCache.put('template/smart-table/pagination.html',\n '<nav ng-if=\"numPages && pages.length >= 2\"><ul class=\"pagination\">' +\n '<li ng-repeat=\"page in pages\" ng-class=\"{active: page==currentPage}\"><a href=\"#\" ng-click=\"selectPage(page); $event.preventDefault(); $event.stopPropagation();\">{{page}}</a></li>' +\n '</ul></nav>');\n}]);\n\n\nng.module('smart-table')\n .constant('stConfig', {\n pagination: {\n template: 'template/smart-table/pagination.html',\n itemsByPage: 10,\n displayedPages: 5\n },\n search: {\n delay: 400, // ms\n inputEvent: 'input',\n trimSearch: false\n },\n select: {\n mode: 'single',\n selectedClass: 'st-selected'\n },\n sort: {\n ascentClass: 'st-sort-ascent',\n descentClass: 'st-sort-descent',\n descendingFirst: false,\n skipNatural: false,\n delay:300\n },\n pipe: {\n delay: 100 //ms\n }\n });\nng.module('smart-table').controller('stTableController', [\n '$scope',\n '$parse',\n '$filter',\n '$attrs',\n function StTableController($scope, $parse, $filter, $attrs) {\n var propertyName = $attrs.stTable;\n var displayGetter = $parse(propertyName);\n var displaySetter = displayGetter.assign;\n var safeGetter;\n var orderBy = $filter('orderBy');\n var filter = $filter('filter');\n var safeCopy = copyRefs(displayGetter($scope));\n var tableState = {\n sort: {},\n search: {},\n pagination: { start: 0, totalItemCount: 0 }\n };\n var filtered;\n var pipeAfterSafeCopy = true;\n var ctrl = this;\n var lastSelected;\n\n function copyRefs(src) {\n return src ? [].concat(src) : [];\n }\n\n function updateSafeCopy() {\n safeCopy = copyRefs(safeGetter($scope));\n if (pipeAfterSafeCopy === true) {\n ctrl.pipe();\n }\n }\n\n function deepDelete(object, path) {\n if (path.indexOf('.') != -1) {\n var partials = path.split('.');\n var key = partials.pop();\n var parentPath = partials.join('.');\n var parentObject = $parse(parentPath)(object);\n delete parentObject[key];\n if (Object.keys(parentObject).length == 0) {\n deepDelete(object, parentPath);\n }\n } else {\n delete object[path];\n }\n }\n\n if ($attrs.stSafeSrc) {\n safeGetter = $parse($attrs.stSafeSrc);\n $scope.$watch(\n function() {\n var safeSrc = safeGetter($scope);\n return safeSrc && safeSrc.length ? safeSrc[0] : undefined;\n },\n function(newValue, oldValue) {\n if (newValue !== oldValue) {\n updateSafeCopy();\n }\n }\n );\n $scope.$watch(\n function() {\n var safeSrc = safeGetter($scope);\n return safeSrc ? safeSrc.length : 0;\n },\n function(newValue, oldValue) {\n if (newValue !== safeCopy.length) {\n updateSafeCopy();\n }\n }\n );\n $scope.$watch(\n function() {\n return safeGetter($scope);\n },\n function(newValue, oldValue) {\n if (newValue !== oldValue) {\n tableState.pagination.start = 0;\n updateSafeCopy();\n }\n }\n );\n }\n\n /**\n * sort the rows\n * @param {Function | String} predicate - function or string which will be used as predicate for the sorting\n * @param [reverse] - if you want to reverse the order\n */\n this.sortBy = function sortBy(predicate, reverse) {\n tableState.sort.predicate = predicate;\n tableState.sort.reverse = reverse === true;\n\n if (ng.isFunction(predicate)) {\n tableState.sort.functionName = predicate.name;\n } else {\n delete tableState.sort.functionName;\n }\n\n tableState.pagination.start = 0;\n return this.pipe();\n };\n\n /**\n * search matching rows\n * @param {String} input - the input string\n * @param {String} [predicate] - the property name against you want to check the match, otherwise it will search on all properties\n * @param {String | Function } [comparator] - a comparator to pass to the filter for the (pass true for stric mode)\n */\n this.search = function search(input, predicate, comparator) {\n var predicateObject = tableState.search.predicateObject || {};\n var prop = predicate ? predicate : '$';\n\n $parse(prop).assign(predicateObject, input);\n // to avoid to filter out null value\n if (!input) {\n deepDelete(predicateObject, prop);\n }\n tableState.search.predicateObject = predicateObject;\n tableState.pagination.start = 0;\n return this.pipe();\n };\n\n /**\n * this will chain the operations of sorting and filtering based on the current table state (sort options, filtering, ect)\n */\n this.pipe = function pipe() {\n var pagination = tableState.pagination;\n var output;\n filtered = tableState.search.predicateObject\n ? filter(safeCopy, tableState.search.predicateObject)\n : safeCopy;\n if (tableState.sort.predicate) {\n filtered = orderBy(\n filtered,\n tableState.sort.predicate,\n tableState.sort.reverse\n );\n }\n pagination.totalItemCount = filtered.length;\n if (pagination.number !== undefined) {\n pagination.numberOfPages = filtered.length > 0\n ? Math.ceil(filtered.length / pagination.number)\n : 1;\n pagination.start = pagination.start >= filtered.length\n ? (pagination.numberOfPages - 1) * pagination.number\n : pagination.start;\n output = filtered.slice(\n pagination.start,\n pagination.start + parseInt(pagination.number)\n );\n }\n displaySetter($scope, output || filtered);\n };\n\n /**\n * select a dataRow (it will add the attribute isSelected to the row object)\n * @param {Object} row - the row to select\n * @param {String} [mode] - \"single\" or \"multiple\" (multiple by default)\n */\n this.select = function select(row, mode) {\n var rows = copyRefs(displayGetter($scope));\n var index = rows.indexOf(row);\n if (index !== -1) {\n if (mode === 'single') {\n row.isSelected = row.isSelected !== true;\n if (lastSelected) {\n lastSelected.isSelected = false;\n }\n lastSelected = row.isSelected === true ? row : undefined;\n } else {\n rows[index].isSelected = !rows[index].isSelected;\n }\n }\n };\n\n /**\n * take a slice of the current sorted/filtered collection (pagination)\n *\n * @param {Number} start - start index of the slice\n * @param {Number} number - the number of item in the slice\n */\n this.slice = function splice(start, number) {\n tableState.pagination.start = start;\n tableState.pagination.number = number;\n return this.pipe();\n };\n\n /**\n * return the current state of the table\n * @returns {{sort: {}, search: {}, pagination: {start: number}}}\n */\n this.tableState = function getTableState() {\n return tableState;\n };\n\n this.getFilteredCollection = function getFilteredCollection() {\n return filtered || safeCopy;\n };\n\n /**\n * Use a different filter function than the angular FilterFilter\n * @param filterName the name under which the custom filter is registered\n */\n this.setFilterFunction = function setFilterFunction(filterName) {\n filter = $filter(filterName);\n };\n\n /**\n * Use a different function than the angular orderBy\n * @param sortFunctionName the name under which the custom order function is registered\n */\n this.setSortFunction = function setSortFunction(sortFunctionName) {\n orderBy = $filter(sortFunctionName);\n };\n\n /**\n * Usually when the safe copy is updated the pipe function is called.\n * Calling this method will prevent it, which is something required when using a custom pipe function\n */\n this.preventPipeOnWatch = function preventPipe() {\n pipeAfterSafeCopy = false;\n };\n }\n]).directive('stTable', function() {\n return {\n restrict: 'A',\n controller: 'stTableController',\n link: function(scope, element, attr, ctrl) {\n if (attr.stSetFilter) {\n ctrl.setFilterFunction(attr.stSetFilter);\n }\n\n if (attr.stSetSort) {\n ctrl.setSortFunction(attr.stSetSort);\n }\n }\n };\n});\n\nng.module('smart-table')\n .directive('stSearch', ['stConfig', '$timeout','$parse', function (stConfig, $timeout, $parse) {\n return {\n require: '^stTable',\n link: function (scope, element, attr, ctrl) {\n var tableCtrl = ctrl;\n var promise = null;\n var throttle = attr.stDelay || stConfig.search.delay;\n var event = attr.stInputEvent || stConfig.search.inputEvent;\n var trimSearch = attr.trimSearch || stConfig.search.trimSearch;\n\n attr.$observe('stSearch', function (newValue, oldValue) {\n var input = element[0].value;\n if (newValue !== oldValue && input) {\n ctrl.tableState().search = {};\n input = ng.isString(input) && trimSearch ? input.trim() : input;\n tableCtrl.search(input, newValue);\n }\n });\n\n //table state -> view\n scope.$watch(function () {\n return ctrl.tableState().search;\n }, function (newValue, oldValue) {\n var predicateExpression = attr.stSearch || '$';\n if (newValue.predicateObject && $parse(predicateExpression)(newValue.predicateObject) !== element[0].value) {\n element[0].value = $parse(predicateExpression)(newValue.predicateObject) || '';\n }\n }, true);\n\n // view -> table state\n element.bind(event, function (evt) {\n evt = evt.originalEvent || evt;\n if (promise !== null) {\n $timeout.cancel(promise);\n }\n\n promise = $timeout(function () {\n var input = evt.target.value;\n input = ng.isString(input) && trimSearch ? input.trim() : input;\n tableCtrl.search(input, attr.stSearch || '');\n promise = null;\n }, throttle);\n });\n }\n };\n }]);\n\nng.module('smart-table')\n .directive('stSelectRow', ['stConfig', function (stConfig) {\n return {\n restrict: 'A',\n require: '^stTable',\n scope: {\n row: '=stSelectRow'\n },\n link: function (scope, element, attr, ctrl) {\n var mode = attr.stSelectMode || stConfig.select.mode;\n element.bind('click', function () {\n scope.$apply(function () {\n ctrl.select(scope.row, mode);\n });\n });\n\n scope.$watch('row.isSelected', function (newValue) {\n if (newValue === true) {\n element.addClass(stConfig.select.selectedClass);\n } else {\n element.removeClass(stConfig.select.selectedClass);\n }\n });\n }\n };\n }]);\n\nng.module('smart-table')\n .directive('stSort', ['stConfig', '$parse', '$timeout', function (stConfig, $parse, $timeout) {\n return {\n restrict: 'A',\n require: '^stTable',\n link: function (scope, element, attr, ctrl) {\n\n var predicate = attr.stSort;\n var getter = $parse(predicate);\n var index = 0;\n var classAscent = attr.stClassAscent || stConfig.sort.ascentClass;\n var classDescent = attr.stClassDescent || stConfig.sort.descentClass;\n var stateClasses = [classAscent, classDescent];\n var sortDefault;\n var skipNatural = attr.stSkipNatural !== undefined ? attr.stSkipNatural : stConfig.sort.skipNatural;\n var descendingFirst = attr.stDescendingFirst !== undefined ? attr.stDescendingFirst : stConfig.sort.descendingFirst;\n var promise = null;\n var throttle = attr.stDelay || stConfig.sort.delay;\n\n // set aria attributes\n var ariaSort = 'aria-sort';\n var ariaSortNone = 'none';\n var ariaSortAscending = 'ascending';\n var ariaSortDescending = 'descending';\n element\n .attr('role', 'columnheader')\n .attr(ariaSort, ariaSortNone);\n\n if (attr.stSortDefault) {\n sortDefault = scope.$eval(attr.stSortDefault) !== undefined ? scope.$eval(attr.stSortDefault) : attr.stSortDefault;\n }\n\n //view --> table state\n function sort () {\n if (descendingFirst) {\n index = index === 0 ? 2 : index - 1;\n } else {\n index++;\n }\n\n var func;\n predicate = ng.isFunction(getter(scope)) || ng.isArray(getter(scope)) ? getter(scope) : attr.stSort;\n if (index % 3 === 0 && !!skipNatural !== true) {\n //manual reset\n index = 0;\n ctrl.tableState().sort = {};\n ctrl.tableState().pagination.start = 0;\n func = ctrl.pipe.bind(ctrl);\n } else {\n func = ctrl.sortBy.bind(ctrl, predicate, index % 2 === 0);\n }\n if (promise !== null) {\n $timeout.cancel(promise);\n }\n if (throttle < 0) {\n func();\n } else {\n promise = $timeout(function(){\n func();\n }, throttle);\n }\n }\n\n element.bind('click', function sortClick () {\n if (predicate) {\n scope.$apply(sort);\n }\n });\n\n if (sortDefault) {\n index = sortDefault === 'reverse' ? 1 : 0;\n sort();\n }\n\n //table state --> view\n scope.$watch(function () {\n return ctrl.tableState().sort;\n }, function (newValue) {\n if (newValue.predicate !== predicate) {\n index = 0;\n element\n .removeClass(classAscent)\n .removeClass(classDescent)\n .attr(ariaSort, ariaSortNone);\n } else {\n index = newValue.reverse === true ? 2 : 1;\n element\n .removeClass(stateClasses[index % 2])\n .addClass(stateClasses[index - 1])\n .attr(ariaSort, newValue.reverse ? ariaSortAscending : ariaSortDescending);\n }\n }, true);\n }\n };\n }]);\n\nng.module('smart-table')\n .directive('stPagination', ['stConfig', function (stConfig) {\n return {\n restrict: 'EA',\n require: '^stTable',\n scope: {\n stItemsByPage: '=?',\n stDisplayedPages: '=?',\n stPageChange: '&'\n },\n templateUrl: function (element, attrs) {\n if (attrs.stTemplate) {\n return attrs.stTemplate;\n }\n return stConfig.pagination.template;\n },\n link: function (scope, element, attrs, ctrl) {\n\n scope.stItemsByPage = scope.stItemsByPage ? +(scope.stItemsByPage) : stConfig.pagination.itemsByPage;\n scope.stDisplayedPages = scope.stDisplayedPages ? +(scope.stDisplayedPages) : stConfig.pagination.displayedPages;\n\n scope.currentPage = 1;\n scope.pages = [];\n\n function redraw () {\n var paginationState = ctrl.tableState().pagination;\n var start = 1;\n var end;\n var i;\n var prevPage = scope.currentPage;\n scope.totalItemCount = paginationState.totalItemCount;\n scope.currentPage = Math.floor(paginationState.start / paginationState.number) + 1;\n\n start = Math.max(start, scope.currentPage - Math.abs(Math.floor(scope.stDisplayedPages / 2)));\n end = start + scope.stDisplayedPages;\n\n if (end > paginationState.numberOfPages) {\n end = paginationState.numberOfPages + 1;\n start = Math.max(1, end - scope.stDisplayedPages);\n }\n\n scope.pages = [];\n scope.numPages = paginationState.numberOfPages;\n\n for (i = start; i < end; i++) {\n scope.pages.push(i);\n }\n\n if (prevPage !== scope.currentPage) {\n scope.stPageChange({newPage: scope.currentPage});\n }\n }\n\n //table state --> view\n scope.$watch(function () {\n return ctrl.tableState().pagination;\n }, redraw, true);\n\n //scope --> table state (--> view)\n scope.$watch('stItemsByPage', function (newValue, oldValue) {\n if (newValue !== oldValue) {\n scope.selectPage(1);\n }\n });\n\n scope.$watch('stDisplayedPages', redraw);\n\n //view -> table state\n scope.selectPage = function (page) {\n if (page > 0 && page <= scope.numPages) {\n ctrl.slice((page - 1) * scope.stItemsByPage, scope.stItemsByPage);\n }\n };\n\n if (!ctrl.tableState().pagination.number) {\n ctrl.slice(0, scope.stItemsByPage);\n }\n }\n };\n }]);\n\nng.module('smart-table')\n .directive('stPipe', ['stConfig', '$timeout', function (config, $timeout) {\n return {\n require: 'stTable',\n scope: {\n stPipe: '='\n },\n link: {\n\n pre: function (scope, element, attrs, ctrl) {\n\n var pipePromise = null;\n\n if (ng.isFunction(scope.stPipe)) {\n ctrl.preventPipeOnWatch();\n ctrl.pipe = function () {\n\n if (pipePromise !== null) {\n $timeout.cancel(pipePromise)\n }\n\n pipePromise = $timeout(function () {\n scope.stPipe(ctrl.tableState(), ctrl);\n }, config.pipe.delay);\n\n return pipePromise;\n }\n }\n },\n\n post: function (scope, element, attrs, ctrl) {\n ctrl.pipe();\n }\n }\n };\n }]);\n\n})(angular);"]}
11 var concat = require('gulp-concat');
22 var uglify = require('gulp-uglify');
33 var karma = require('karma').server;
4 var jshint = require('gulp-jshint');
54 var insert = require('gulp-insert');
65 var sourcemaps = require('gulp-sourcemaps');
7 var stylish = require('jshint-stylish');
86 var packageJson = require('./package.json');
97 var pluginList = ['stSearch', 'stSelectRow', 'stSort', 'stPagination', 'stPipe'];
108 var disFolder = './dist/';
1513 src.push('src/bottom.txt');
1614 src.unshift('src/top.txt');
1715
18 //modules
19 gulp.task('uglify', function () {
20 gulp.src(src)
21 .pipe(concat('smart-table.min.js'))
22 .pipe(uglify())
23 .pipe(gulp.dest(disFolder));
24 });
25
26
27 //just as indication
28 gulp.task('lint', function () {
29 gulp.src(src)
30 .pipe(jshint())
31 .pipe(jshint.reporter(stylish));
32 });
33
3416
3517 gulp.task('karma-CI', function (done) {
3618 var conf = require('./test/karma.common.js');
4022 karma.start(conf, done);
4123 });
4224
25 gulp.task('uglify', function () {
26 gulp.src(src)
27 .pipe(concat('smart-table.min.js'))
28 .pipe(sourcemaps.init())
29 .pipe(uglify())
30 .pipe(sourcemaps.write('.'))
31 .pipe(gulp.dest(disFolder));
32 });
33
4334 gulp.task('concat', function () {
4435 gulp.src(src, { base: '.' })
45 .pipe(sourcemaps.init())
46 .pipe(concat('smart-table.js'))
47 .pipe(sourcemaps.write())
48 .pipe(gulp.dest(disFolder));
36 .pipe(concat('smart-table.js'))
37 .pipe(gulp.dest(disFolder));
4938 });
5039
5140 gulp.task('test', ['karma-CI']);
0 require('./dist/smart-table.js');
1 module.exports = 'smart-table';
00 {
11 "name": "angular-smart-table",
2 "version": "1.4.13",
2 "version": "2.1.11",
33 "description": "",
4 "main": "dist/smart-table.js",
4 "main": "index.js",
55 "scripts": {
6 "test": "node ./node_modules/.bin/gulp karma-CI"
6 "test": "node ./node_modules/.bin/gulp karma-CI",
7 "build": "node ./node_modules/.bin/gulp build"
78 },
89 "repository": {
910 "type": "git",
1011 "url": "https://github.com/lorenzofox3/Smart-Table.git"
1112 },
12 "author": "",
13 "license": "ISC",
13 "author": "Laurent Renard",
14 "license": "MIT",
1415 "devDependencies": {
16 "angular": "^1.6.4",
17 "angular-mocks": "^1.6.4",
1518 "gulp": "^3.8.7",
1619 "gulp-concat": "^2.3.4",
17 "gulp-insert": "^0.4.0",
18 "gulp-jshint": "^1.8.4",
19 "gulp-sourcemaps": "^1.3.0",
20 "gulp-uglify": "^0.3.1",
21 "jshint-stylish": "^0.4.0",
22 "karma": "^0.12.21",
23 "karma-chrome-launcher": "^0.1.4",
24 "karma-coverage": "^0.2.6",
25 "karma-jasmine": "^0.1.5",
26 "karma-phantomjs-launcher": "^0.1.4"
20 "gulp-insert": "^0.5.0",
21 "gulp-sourcemaps": "^2.6.0",
22 "gulp-uglify": "^3.0.0",
23 "jasmine-core": "^2.6.3",
24 "jquery": "^3.2.1",
25 "karma": "^1.7.0",
26 "karma-chrome-launcher": "^2.1.1",
27 "karma-coverage": "^1.1.1",
28 "karma-jasmine": "^1.1.0",
29 "karma-phantomjs-launcher": "^1.0.4"
2730 }
2831 }
00 [![Build Status](https://travis-ci.org/lorenzofox3/Smart-Table.svg?branch=master)](https://travis-ci.org/lorenzofox3/Smart-Table)
11
2 **Hey I am not too much into angular these days. If someone wants to maintain this project, please contact me !**
3
24 # Smart Table
3 [![Gitter](https://badges.gitter.im/Join Chat.svg)](https://gitter.im/lorenzofox3/Smart-Table?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
45
5 Smart table is a table module for angular js. It allows you to quickly compose your table in a declarative way including sorting, filtering, row selection pagination.
6 Smart Table is a table module for angular js. It allows you to quickly compose your table in a declarative way including sorting, filtering, row selection, and pagination.
67 It is lightweight (around 3kb minified) and has no other dependencies than Angular itself.
78 Check the [documentation](http://lorenzofox3.github.io/smart-table-website/) website for more details
89
9 ## submitting an issue
10 ## Submitting an issue
1011
11 Please be responsible, the open source community is not there to guess your problem or to do your job. When submitting an issue try as much as possible to:
12 Please be responsible -- investigate potential issues yourself to eliminate the possibility that your issue isn't just an error. If you are still having problems, try posting on our [gitter](https://gitter.im/lorenzofox3/Smart-Table). When submitting an issue try as much as possible to:
1213
13 1. search in the already existing issues or on [stackoverflow](http://stackoverflow.com/questions/tagged/smart-table?sort=newest&pageSize=30) if your issue has not been raised before.
14 1. Search in the already existing issues or on [stackoverflow](http://stackoverflow.com/questions/tagged/smart-table?sort=newest&pageSize=30) if your issue has not been raised before.
1415
15 2. give a precise description mentionning angular version, smart-table version.
16 2. Give a precise description mentionning angular version, smart-table version.
1617
17 3. give a way to reproduce your issue, the best would be with a <strong>running example</strong>, you can use [plunkr](http://plnkr.co/) (smart-table is the list of available packages). Note if you want to mimic ajax loading behaviour you can use [$timeout](https://docs.angularjs.org/api/ng/service/$timeout) angular service or [$httpBackend](https://docs.angularjs.org/api/ng/service/$httpBackend).
18 3. Give a way to reproduce your issue, the best would be with a <strong>running example</strong>, you can use [plunkr](http://plnkr.co/) (smart-table is the list of available packages). Note if you want to mimic ajax loading behaviour you can use [$timeout](https://docs.angularjs.org/api/ng/service/$timeout) angular service or [$httpBackend](https://docs.angularjs.org/api/ng/service/$httpBackend).
1819
19 4. isolate your code sample on the probable issue to avoid pollution and noise.
20 4. Isolate your code sample on the probable issue to avoid pollution and noise.
2021
21 5. Close your issue when a solution has been found (and share it with the community)
22 5. Close your issue when a solution has been found (and share it with the community).
2223
23 Note that 80% of the open issues are actually not issues but "problem" due to developpers laziness or lack of investigation. These "issues" are a waste of time for us and especially if we have to setup a sample to reproduce the issue which those developpers could have done. Any open issue which does not fulfill this contract will be closed without investigation.
24 Note that 80% of the open issues are actually not issues but due to lack of good investigation. These issues create unnecessary work, so please be considerate.
25
26 Any open issue which do not follow the steps above will be closed without investigation.
2427
2528 ## Install
2629
27 the easiest way is to run `bower install angular-smart-table`, then you just have to add the script and register the module `smart-table` to you application
30 The easiest way is to run `bower install angular-smart-table`, then you just have to add the script and register the module `smart-table` to you application.
31
32 You can also install using NPM `npm install angular-smart-table`, so you can use with browserify or webpack
2833
2934 ## Test
3035
31 run `npm install` after you have installed the dependencies (`npm install` and `bower install`)
36 Run `npm install` after you have installed the dependencies (`npm install` and `bower install`).
3237
33 ## custom builds
38 ## Custom builds
3439
35 smart-table is based around a main directive which generate a top level controller whose API can be accessed by sub directives
36 (plugins), if you don't need some of these, simply edit the gulpfile (the pluginList variable) and run `gulp build`
40 Smart Table is based around a main directive which generate a top level controller whose API can be accessed by sub directives
41 (plugins). If you don't need some of these, simply edit the gulpfile (the pluginList variable) and run `gulp build`.
3742
3843 ## Older versions
3944
40 Smart-Table used to be configuration based and if you rely on this version, you can still access the code on the [0.2.x](https://github.com/lorenzofox3/Smart-Table/tree/vx.2.x) branch. You will be able to find the documentation related to this version
45 Smart Table used to be configuration based and if you rely on this version, you can still access the code on the [0.2.x](https://github.com/lorenzofox3/Smart-Table/tree/vx.2.x) branch. You will be able to find the documentation related to this version
4146 [here](https://github.com/lorenzofox3/smart-table-website) (simply open index.html in a browser).
4247
4348 Note, I have closed all the issues related to these versions as people get confused when reading these issues and commented on them like it was related to the newer version. Feel free to reopen any of them (or open a new one), but don't forget to mention it is related to the older versions.
4651
4752 Smart Table module is under MIT license:
4853
49 > Copyright (C) 2014 Laurent Renard.
54 > Copyright (C) 2016 Laurent Renard.
5055 >
5156 > Permission is hereby granted, free of charge, to any person
5257 > obtaining a copy of this software and associated documentation files
00 ng.module('smart-table', []).run(['$templateCache', function ($templateCache) {
11 $templateCache.put('template/smart-table/pagination.html',
2 '<nav ng-if="pages.length >= 2"><ul class="pagination">' +
3 '<li ng-repeat="page in pages" ng-class="{active: page==currentPage}"><a ng-click="selectPage(page)">{{page}}</a></li>' +
2 '<nav ng-if="numPages && pages.length >= 2"><ul class="pagination">' +
3 '<li ng-repeat="page in pages" ng-class="{active: page==currentPage}"><a href="#" ng-click="selectPage(page); $event.preventDefault(); $event.stopPropagation();">{{page}}</a></li>' +
44 '</ul></nav>');
55 }]);
66
55 displayedPages: 5
66 },
77 search: {
8 delay: 400 // ms
8 delay: 400, // ms
9 inputEvent: 'input',
10 trimSearch: false
911 },
1012 select: {
1113 mode: 'single',
1315 },
1416 sort: {
1517 ascentClass: 'st-sort-ascent',
16 descentClass: 'st-sort-descent'
18 descentClass: 'st-sort-descent',
19 descendingFirst: false,
20 skipNatural: false,
21 delay:300
22 },
23 pipe: {
24 delay: 100 //ms
1725 }
1826 });
2727 var end;
2828 var i;
2929 var prevPage = scope.currentPage;
30 scope.totalItemCount = paginationState.totalItemCount;
3031 scope.currentPage = Math.floor(paginationState.start / paginationState.number) + 1;
3132
3233 start = Math.max(start, scope.currentPage - Math.abs(Math.floor(scope.stDisplayedPages / 2)));
00 ng.module('smart-table')
1 .directive('stPipe', function () {
1 .directive('stPipe', ['stConfig', '$timeout', function (config, $timeout) {
22 return {
33 require: 'stTable',
44 scope: {
77 link: {
88
99 pre: function (scope, element, attrs, ctrl) {
10
11 var pipePromise = null;
12
1013 if (ng.isFunction(scope.stPipe)) {
1114 ctrl.preventPipeOnWatch();
1215 ctrl.pipe = function () {
13 return scope.stPipe(ctrl.tableState(), ctrl);
16
17 if (pipePromise !== null) {
18 $timeout.cancel(pipePromise)
19 }
20
21 pipePromise = $timeout(function () {
22 scope.stPipe(ctrl.tableState(), ctrl);
23 }, config.pipe.delay);
24
25 return pipePromise;
1426 }
1527 }
1628 },
2032 }
2133 }
2234 };
23 });
35 }]);
00 ng.module('smart-table')
1 .directive('stSearch', ['stConfig', '$timeout', function (stConfig, $timeout) {
1 .directive('stSearch', ['stConfig', '$timeout','$parse', function (stConfig, $timeout, $parse) {
22 return {
33 require: '^stTable',
4 scope: {
5 predicate: '=?stSearch'
6 },
74 link: function (scope, element, attr, ctrl) {
85 var tableCtrl = ctrl;
96 var promise = null;
107 var throttle = attr.stDelay || stConfig.search.delay;
8 var event = attr.stInputEvent || stConfig.search.inputEvent;
9 var trimSearch = attr.trimSearch || stConfig.search.trimSearch;
1110
12 scope.$watch('predicate', function (newValue, oldValue) {
13 if (newValue !== oldValue) {
11 attr.$observe('stSearch', function (newValue, oldValue) {
12 var input = element[0].value;
13 if (newValue !== oldValue && input) {
1414 ctrl.tableState().search = {};
15 tableCtrl.search(element[0].value || '', newValue);
15 input = ng.isString(input) && trimSearch ? input.trim() : input;
16 tableCtrl.search(input, newValue);
1617 }
1718 });
1819
2021 scope.$watch(function () {
2122 return ctrl.tableState().search;
2223 }, function (newValue, oldValue) {
23 var predicateExpression = scope.predicate || '$';
24 if (newValue.predicateObject && newValue.predicateObject[predicateExpression] !== element[0].value) {
25 element[0].value = newValue.predicateObject[predicateExpression] || '';
24 var predicateExpression = attr.stSearch || '$';
25 if (newValue.predicateObject && $parse(predicateExpression)(newValue.predicateObject) !== element[0].value) {
26 element[0].value = $parse(predicateExpression)(newValue.predicateObject) || '';
2627 }
2728 }, true);
2829
2930 // view -> table state
30 element.bind('input', function (evt) {
31 element.bind(event, function (evt) {
3132 evt = evt.originalEvent || evt;
3233 if (promise !== null) {
3334 $timeout.cancel(promise);
3435 }
36
3537 promise = $timeout(function () {
36 tableCtrl.search(evt.target.value, scope.predicate || '');
38 var input = evt.target.value;
39 input = ng.isString(input) && trimSearch ? input.trim() : input;
40 tableCtrl.search(input, attr.stSearch || '');
3741 promise = null;
3842 }, throttle);
3943 });
00 ng.module('smart-table')
1 .directive('stSort', ['stConfig', '$parse', function (stConfig, $parse) {
1 .directive('stSort', ['stConfig', '$parse', '$timeout', function (stConfig, $parse, $timeout) {
22 return {
33 restrict: 'A',
44 require: '^stTable',
1111 var classDescent = attr.stClassDescent || stConfig.sort.descentClass;
1212 var stateClasses = [classAscent, classDescent];
1313 var sortDefault;
14 var skipNatural = attr.stSkipNatural !== undefined ? attr.stSkipNatural : stConfig.sort.skipNatural;
15 var descendingFirst = attr.stDescendingFirst !== undefined ? attr.stDescendingFirst : stConfig.sort.descendingFirst;
16 var promise = null;
17 var throttle = attr.stDelay || stConfig.sort.delay;
18
19 // set aria attributes
20 var ariaSort = 'aria-sort';
21 var ariaSortNone = 'none';
22 var ariaSortAscending = 'ascending';
23 var ariaSortDescending = 'descending';
24 element
25 .attr('role', 'columnheader')
26 .attr(ariaSort, ariaSortNone);
1427
1528 if (attr.stSortDefault) {
1629 sortDefault = scope.$eval(attr.stSortDefault) !== undefined ? scope.$eval(attr.stSortDefault) : attr.stSortDefault;
1831
1932 //view --> table state
2033 function sort () {
21 index++;
22 predicate = ng.isFunction(getter(scope)) ? getter(scope) : attr.stSort;
23 if (index % 3 === 0 && attr.stSkipNatural === undefined) {
34 if (descendingFirst) {
35 index = index === 0 ? 2 : index - 1;
36 } else {
37 index++;
38 }
39
40 var func;
41 predicate = ng.isFunction(getter(scope)) || ng.isArray(getter(scope)) ? getter(scope) : attr.stSort;
42 if (index % 3 === 0 && !!skipNatural !== true) {
2443 //manual reset
2544 index = 0;
2645 ctrl.tableState().sort = {};
2746 ctrl.tableState().pagination.start = 0;
28 ctrl.pipe();
47 func = ctrl.pipe.bind(ctrl);
2948 } else {
30 ctrl.sortBy(predicate, index % 2 === 0);
49 func = ctrl.sortBy.bind(ctrl, predicate, index % 2 === 0);
50 }
51 if (promise !== null) {
52 $timeout.cancel(promise);
53 }
54 if (throttle < 0) {
55 func();
56 } else {
57 promise = $timeout(function(){
58 func();
59 }, throttle);
3160 }
3261 }
3362
5079 index = 0;
5180 element
5281 .removeClass(classAscent)
53 .removeClass(classDescent);
82 .removeClass(classDescent)
83 .attr(ariaSort, ariaSortNone);
5484 } else {
5585 index = newValue.reverse === true ? 2 : 1;
5686 element
5787 .removeClass(stateClasses[index % 2])
58 .addClass(stateClasses[index - 1]);
88 .addClass(stateClasses[index - 1])
89 .attr(ariaSort, newValue.reverse ? ariaSortAscending : ariaSortDescending);
5990 }
6091 }, true);
6192 }
0 ng.module('smart-table')
1 .controller('stTableController', ['$scope', '$parse', '$filter', '$attrs', function StTableController ($scope, $parse, $filter, $attrs) {
0 ng.module('smart-table').controller('stTableController', [
1 '$scope',
2 '$parse',
3 '$filter',
4 '$attrs',
5 function StTableController($scope, $parse, $filter, $attrs) {
26 var propertyName = $attrs.stTable;
37 var displayGetter = $parse(propertyName);
48 var displaySetter = displayGetter.assign;
913 var tableState = {
1014 sort: {},
1115 search: {},
12 pagination: {
13 start: 0
14 }
16 pagination: { start: 0, totalItemCount: 0 }
1517 };
1618 var filtered;
1719 var pipeAfterSafeCopy = true;
1820 var ctrl = this;
1921 var lastSelected;
2022
21 function copyRefs (src) {
23 function copyRefs(src) {
2224 return src ? [].concat(src) : [];
2325 }
2426
25 function updateSafeCopy () {
27 function updateSafeCopy() {
2628 safeCopy = copyRefs(safeGetter($scope));
2729 if (pipeAfterSafeCopy === true) {
2830 ctrl.pipe();
2931 }
3032 }
3133
34 function deepDelete(object, path) {
35 if (path.indexOf('.') != -1) {
36 var partials = path.split('.');
37 var key = partials.pop();
38 var parentPath = partials.join('.');
39 var parentObject = $parse(parentPath)(object);
40 delete parentObject[key];
41 if (Object.keys(parentObject).length == 0) {
42 deepDelete(object, parentPath);
43 }
44 } else {
45 delete object[path];
46 }
47 }
48
3249 if ($attrs.stSafeSrc) {
3350 safeGetter = $parse($attrs.stSafeSrc);
34 $scope.$watch(function () {
35 var safeSrc = safeGetter($scope);
36 return safeSrc ? safeSrc.length : 0;
37
38 }, function (newValue, oldValue) {
39 if (newValue !== safeCopy.length) {
40 updateSafeCopy();
41 }
42 });
43 $scope.$watch(function () {
44 return safeGetter($scope);
45 }, function (newValue, oldValue) {
46 if (newValue !== oldValue) {
47 updateSafeCopy();
48 }
49 });
51 $scope.$watch(
52 function() {
53 var safeSrc = safeGetter($scope);
54 return safeSrc && safeSrc.length ? safeSrc[0] : undefined;
55 },
56 function(newValue, oldValue) {
57 if (newValue !== oldValue) {
58 updateSafeCopy();
59 }
60 }
61 );
62 $scope.$watch(
63 function() {
64 var safeSrc = safeGetter($scope);
65 return safeSrc ? safeSrc.length : 0;
66 },
67 function(newValue, oldValue) {
68 if (newValue !== safeCopy.length) {
69 updateSafeCopy();
70 }
71 }
72 );
73 $scope.$watch(
74 function() {
75 return safeGetter($scope);
76 },
77 function(newValue, oldValue) {
78 if (newValue !== oldValue) {
79 tableState.pagination.start = 0;
80 updateSafeCopy();
81 }
82 }
83 );
5084 }
5185
5286 /**
5488 * @param {Function | String} predicate - function or string which will be used as predicate for the sorting
5589 * @param [reverse] - if you want to reverse the order
5690 */
57 this.sortBy = function sortBy (predicate, reverse) {
91 this.sortBy = function sortBy(predicate, reverse) {
5892 tableState.sort.predicate = predicate;
5993 tableState.sort.reverse = reverse === true;
6094
72106 * search matching rows
73107 * @param {String} input - the input string
74108 * @param {String} [predicate] - the property name against you want to check the match, otherwise it will search on all properties
75 */
76 this.search = function search (input, predicate) {
109 * @param {String | Function } [comparator] - a comparator to pass to the filter for the (pass true for stric mode)
110 */
111 this.search = function search(input, predicate, comparator) {
77112 var predicateObject = tableState.search.predicateObject || {};
78113 var prop = predicate ? predicate : '$';
79114
80 input = ng.isString(input) ? input.trim() : input;
81 predicateObject[prop] = input;
115 $parse(prop).assign(predicateObject, input);
82116 // to avoid to filter out null value
83117 if (!input) {
84 delete predicateObject[prop];
118 deepDelete(predicateObject, prop);
85119 }
86120 tableState.search.predicateObject = predicateObject;
87121 tableState.pagination.start = 0;
91125 /**
92126 * this will chain the operations of sorting and filtering based on the current table state (sort options, filtering, ect)
93127 */
94 this.pipe = function pipe () {
128 this.pipe = function pipe() {
95129 var pagination = tableState.pagination;
96130 var output;
97 filtered = tableState.search.predicateObject ? filter(safeCopy, tableState.search.predicateObject) : safeCopy;
131 filtered = tableState.search.predicateObject
132 ? filter(safeCopy, tableState.search.predicateObject)
133 : safeCopy;
98134 if (tableState.sort.predicate) {
99 filtered = orderBy(filtered, tableState.sort.predicate, tableState.sort.reverse);
100 }
135 filtered = orderBy(
136 filtered,
137 tableState.sort.predicate,
138 tableState.sort.reverse
139 );
140 }
141 pagination.totalItemCount = filtered.length;
101142 if (pagination.number !== undefined) {
102 pagination.numberOfPages = filtered.length > 0 ? Math.ceil(filtered.length / pagination.number) : 1;
103 pagination.start = pagination.start >= filtered.length ? (pagination.numberOfPages - 1) * pagination.number : pagination.start;
104 output = filtered.slice(pagination.start, pagination.start + parseInt(pagination.number));
143 pagination.numberOfPages = filtered.length > 0
144 ? Math.ceil(filtered.length / pagination.number)
145 : 1;
146 pagination.start = pagination.start >= filtered.length
147 ? (pagination.numberOfPages - 1) * pagination.number
148 : pagination.start;
149 output = filtered.slice(
150 pagination.start,
151 pagination.start + parseInt(pagination.number)
152 );
105153 }
106154 displaySetter($scope, output || filtered);
107155 };
111159 * @param {Object} row - the row to select
112160 * @param {String} [mode] - "single" or "multiple" (multiple by default)
113161 */
114 this.select = function select (row, mode) {
115 var rows = safeCopy;
162 this.select = function select(row, mode) {
163 var rows = copyRefs(displayGetter($scope));
116164 var index = rows.indexOf(row);
117165 if (index !== -1) {
118166 if (mode === 'single') {
133181 * @param {Number} start - start index of the slice
134182 * @param {Number} number - the number of item in the slice
135183 */
136 this.slice = function splice (start, number) {
184 this.slice = function splice(start, number) {
137185 tableState.pagination.start = start;
138186 tableState.pagination.number = number;
139187 return this.pipe();
143191 * return the current state of the table
144192 * @returns {{sort: {}, search: {}, pagination: {start: number}}}
145193 */
146 this.tableState = function getTableState () {
194 this.tableState = function getTableState() {
147195 return tableState;
148196 };
149197
150 this.getFilteredCollection = function getFilteredCollection () {
198 this.getFilteredCollection = function getFilteredCollection() {
151199 return filtered || safeCopy;
152200 };
153201
155203 * Use a different filter function than the angular FilterFilter
156204 * @param filterName the name under which the custom filter is registered
157205 */
158 this.setFilterFunction = function setFilterFunction (filterName) {
206 this.setFilterFunction = function setFilterFunction(filterName) {
159207 filter = $filter(filterName);
160208 };
161209
163211 * Use a different function than the angular orderBy
164212 * @param sortFunctionName the name under which the custom order function is registered
165213 */
166 this.setSortFunction = function setSortFunction (sortFunctionName) {
214 this.setSortFunction = function setSortFunction(sortFunctionName) {
167215 orderBy = $filter(sortFunctionName);
168216 };
169217
171219 * Usually when the safe copy is updated the pipe function is called.
172220 * Calling this method will prevent it, which is something required when using a custom pipe function
173221 */
174 this.preventPipeOnWatch = function preventPipe () {
222 this.preventPipeOnWatch = function preventPipe() {
175223 pipeAfterSafeCopy = false;
176224 };
177 }])
178 .directive('stTable', function () {
179 return {
180 restrict: 'A',
181 controller: 'stTableController',
182 link: function (scope, element, attr, ctrl) {
183
184 if (attr.stSetFilter) {
185 ctrl.setFilterFunction(attr.stSetFilter);
186 }
187
188 if (attr.stSetSort) {
189 ctrl.setSortFunction(attr.stSetSort);
190 }
191 }
192 };
193 });
225 }
226 ]).directive('stTable', function() {
227 return {
228 restrict: 'A',
229 controller: 'stTableController',
230 link: function(scope, element, attr, ctrl) {
231 if (attr.stSetFilter) {
232 ctrl.setFilterFunction(attr.stSetFilter);
233 }
234
235 if (attr.stSetSort) {
236 ctrl.setSortFunction(attr.stSetSort);
237 }
238 }
239 };
240 });
00 module.exports = {
11
22 files: [
3 'bower_components/jquery/dist/jquery.js',
4 'bower_components/angular/angular.js',
5 'bower_components/angular-mocks/angular-mocks.js',
3 'node_modules/jquery/dist/jquery.js',
4 'node_modules/angular/angular.js',
5 'node_modules/angular-mocks/angular-mocks.js',
66 'test/init.js',
77 'src/*.js',
88 'test/spec/*.spec.js'
1818 var tableState = {
1919 sort: {},
2020 search: {},
21 pagination: {start: 0}
21 pagination: {start: 0, totalItemCount: 0}
2222 };
2323 var compile;
2424
379379 expect(pages.length).toBe(0);
380380 });
381381
382 describe('with extended template', function () {
383 var templateCache;
384 beforeEach(inject(function ($templateCache) {
385 templateCache = $templateCache;
386 }));
387
388 it('should save totalItemCount from paginationState on scope', function () {
389 templateCache.put('custom_template.html', '<nav ng-if="pages.length >= 2"><ul class="pagination">' +
390 '<li ng-repeat="page in pages" ng-class="{active: page==currentPage}"><a ng-click="selectPage(page)">{{page}}</a></li>' +
391 '</ul>' +
392 '<span>Showing {{(currentPage-1)*stItemsByPage+1}}-{{(currentPage)*stItemsByPage > totalItemCount ? totalItemCount : (currentPage)*stItemsByPage}} of {{totalItemCount}}</span>' +
393 '</nav>');
394
395 var template = '<table st-table="rowCollection"><tfoot><tr><td id="pagination" st-pagination="" st-template="custom_template.html" st-items-by-page="2"></td></tr></tfoot></table>';
396 element = compile(template)(rootScope);
397
398 rootScope.$apply();
399
400 tableState.pagination = {
401 start: 3,
402 numberOfPages: 3,
403 number: 2,
404 totalItemCount: 5
405 };
406
407 rootScope.$apply();
408
409 expect(element.find('SPAN')[0].innerHTML).toBe('Showing 3-4 of 5');
410 });
411 });
382412 });
383413
384414 describe('select page', function () {
385415
386416 it('should select a page', function () {
387417
388 spyOn(controllerMock, 'slice').andCallThrough();
418 spyOn(controllerMock, 'slice').and.callThrough();
389419
390420 var template = '<table st-table="rowCollection"><tfoot><tr><td id="pagination" st-pagination=""></td></tr></tfoot></table>';
391421 element = compile(template)(rootScope);
431461
432462 it('should call onPageChange method', function () {
433463 rootScope.onPageChange = jasmine.createSpy('onPageChange');
434 spyOn(controllerMock, 'slice').andCallThrough();
464 spyOn(controllerMock, 'slice').and.callThrough();
435465
436466 tableState.pagination = {
437467 start: 1,
453483
454484 expect(controllerMock.slice).toHaveBeenCalledWith(20, 10);
455485 expect(rootScope.onPageChange).toHaveBeenCalledWith(3);
456 expect(rootScope.onPageChange.calls.length).toBe(1);
486 expect(rootScope.onPageChange.calls.count()).toBe(1);
457487
458488 });
459489
460490 it('should should not call when current page is not changed', function () {
461491
462492 rootScope.onPageChange = jasmine.createSpy('onPageChange');
463 spyOn(controllerMock, 'slice').andCallThrough();
493 spyOn(controllerMock, 'slice').and.callThrough();
464494
465495 tableState.pagination = {
466496 start: 1,
482512
483513 expect(controllerMock.slice).toHaveBeenCalledWith(20, 10);
484514 expect(rootScope.onPageChange).toHaveBeenCalledWith(3);
485 expect(rootScope.onPageChange.calls.length).toBe(1);
486
487 tableState.pagination.numberOfPages=5;
515 expect(rootScope.onPageChange.calls.count()).toBe(1);
516
517 tableState.pagination.numberOfPages = 5;
488518
489519 rootScope.$apply();
490520 pages = getPages();
491521
492522 expect(pages.length).toBe(5);
493 expect(rootScope.onPageChange.calls.length).toBe(1);
523 expect(rootScope.onPageChange.calls.count()).toBe(1);
494524 });
495525
496526 });
1818 }
1919 }));
2020
21 it('should use the custom pipe function with the current table state as argument', inject(function ($compile) {
21 it('should use the custom pipe function with the current table state as argument', inject(function ($timeout,$compile) {
2222 var element;
2323 var template = '<table st-pipe="customPipe" st-table="rowCollection">' +
2424 '<thead>' +
2727 '<th st-sort="getters.age">age</th>' +
2828 '</tr>' +
2929 '</table>';
30 spyOn(scope, 'customPipe').andCallThrough();
30 spyOn(scope, 'customPipe').and.callThrough();
3131
3232 element = $compile(template)(scope);
3333
3434 var ths = element.find('th');
3535 angular.element(ths[0]).triggerHandler('click');
3636
37 expect(firstArg).toBe(undefined);
38 expect(secondArg).toBe(undefined);
39
40 $timeout.flush();
41
3742 expect(firstArg).toEqual({
38 sort: {predicate: 'name', reverse: false}, search: {}, pagination: {start: 0}
43 sort: {predicate: 'name', reverse: false}, search: {}, pagination: {start: 0, totalItemCount: 0}
3944 });
4045
4146 expect(secondArg.tableState()).toEqual({
42 sort: {predicate: 'name', reverse: false}, search: {}, pagination: {start: 0}
47 sort: {predicate: 'name', reverse: false}, search: {}, pagination: {start: 0, totalItemCount: 0}
4348 });
4449 }));
4550 });
3030 {name: 'Renard', firstname: 'Laurent', age: 66},
3131 {name: 'Francoise', firstname: 'Frere', age: 99},
3232 {name: 'Renard', firstname: 'Olivier', age: 33},
33 {name: 'Leponge', firstname: 'Bob', age: 22},
33 {name: 'Le Blond', firstname: 'Bob', age: 22},
34 {name: 'Faivre', firstname: 'Blandine', age: 44}
35 ];
36
37 var template = '<table st-table="rowCollection">' +
38 '<thead>' +
39 '<tr>' +
40 '<th><input st-search="name" /></th>' +
41 '<th><input st-search="" /></th>' +
42 '<th>age</th>' +
43 '</tr>' +
44 '</thead>' +
45 '<tbody>' +
46 '<tr class="test-filtered" ng-repeat="row in rowCollection">' +
47 '<td>{{row.name}}</td>' +
48 '<td>{{row.firstname}}</td>' +
49 '<td>{{row.age}}</td>' +
50 '</tr>' +
51 '</tbody>' +
52 '</table>';
53
54 element = $compile(template)(scope);
55 scope.$apply();
56 }));
57
58 it('should keep only items which matches', inject(function ($timeout) {
59 var ths = element.find('th');
60 var trs;
61
62 var input = angular.element(ths[0].children[0]);
63 input[0].value = 're';
64 input.triggerHandler('input');
65 trs = element.find('tr.test-filtered');
66 expect(trs.length).toBe(5);
67 $timeout.flush();
68 trs = element.find('tr.test-filtered');
69 expect(trs.length).toBe(3);
70 expect(trToModel(trs)).toEqual([
71 {name: 'Renard', firstname: 'Laurent', age: 66},
72 {name: 'Renard', firstname: 'Olivier', age: 33},
73 {name: 'Faivre', firstname: 'Blandine', age: 44}
74 ]);
75 }));
76
77 it('should search globally', inject(function ($timeout) {
78 var ths = element.find('th');
79
80 var input = angular.element(ths[1].children[0]);
81 input[0].value = 're';
82 input.triggerHandler('input');
83 $timeout.flush();
84 trs = element.find('tr.test-filtered');
85 expect(trs.length).toBe(4);
86 expect(trToModel(trs)).toEqual([
87 {name: 'Renard', firstname: 'Laurent', age: 66},
88 {name: 'Francoise', firstname: 'Frere', age: 99},
89 {name: 'Renard', firstname: 'Olivier', age: 33},
90 {name: 'Faivre', firstname: 'Blandine', age: 44}
91 ]);
92 }));
93
94 it('should keep leading space in search input by default', inject(function ($timeout) {
95 var ths = element.find('th');
96
97 var input = angular.element(ths[1].children[0]);
98 input[0].value = ' bl';
99 input.triggerHandler('input');
100 $timeout.flush();
101 trs = element.find('tr.test-filtered');
102 expect(trs.length).toBe(1);
103 expect(trToModel(trs)).toEqual([
104 {name: 'Le Blond', firstname: 'Bob', age: 22}
105 ]);
106 }));
107
108 it('should keep trailing space in search input by default', inject(function ($timeout) {
109 var ths = element.find('th');
110
111 var input = angular.element(ths[1].children[0]);
112 input[0].value = 'le ';
113 input.triggerHandler('input');
114 $timeout.flush();
115 trs = element.find('tr.test-filtered');
116 expect(trs.length).toBe(1);
117 expect(trToModel(trs)).toEqual([
118 {name: 'Le Blond', firstname: 'Bob', age: 22}
119 ]);
120 }));
121
122 it('should support trim leading and trailing space in search input', inject(function ($timeout, $rootScope, $compile) {
123 var oldTrimSearch= stConfig.search.trimSearch;
124 stConfig.search.trimSearch = true;
125
126 // Since we must set the stCofig before compiling, we must recompile after configuring a delay
127 scope = $rootScope.$new();
128 scope.rowCollection = [
129 {name: 'Renard', firstname: 'Laurent', age: 66},
130 {name: 'Francoise', firstname: 'Frere', age: 99},
131 {name: 'Renard', firstname: 'Olivier', age: 33},
132 {name: 'Le Blond', firstname: 'Bob', age: 22},
34133 {name: 'Faivre', firstname: 'Blandine', age: 44}
35134 ];
36135
53152
54153 element = $compile(template)(scope);
55154 scope.$apply();
56 }));
57
58 it('should keep only items which matches', inject(function ($timeout) {
59 var ths = element.find('th');
60 var trs;
61
62 var input = angular.element(ths[0].children[0]);
63 input[0].value = 're';
64 input.triggerHandler('input');
65 trs = element.find('tr.test-filtered');
66 expect(trs.length).toBe(5);
67 $timeout.flush();
68 trs = element.find('tr.test-filtered');
69 expect(trs.length).toBe(3);
70 expect(trToModel(trs)).toEqual([
71 {name: 'Renard', firstname: 'Laurent', age: 66},
72 {name: 'Renard', firstname: 'Olivier', age: 33},
73 {name: 'Faivre', firstname: 'Blandine', age: 44}
74 ]);
75 }));
76
77 it('should search globally', inject(function ($timeout) {
78 var ths = element.find('th');
79
80 var input = angular.element(ths[1].children[0]);
81 input[0].value = 're';
82 input.triggerHandler('input');
83 $timeout.flush();
84 trs = element.find('tr.test-filtered');
85 expect(trs.length).toBe(4);
86 expect(trToModel(trs)).toEqual([
87 {name: 'Renard', firstname: 'Laurent', age: 66},
88 {name: 'Francoise', firstname: 'Frere', age: 99},
89 {name: 'Renard', firstname: 'Olivier', age: 33},
90 {name: 'Faivre', firstname: 'Blandine', age: 44}
91 ]);
155 var ths = element.find('th');
156
157 var input = angular.element(ths[1].children[0]);
158 input[0].value = ' re ';
159 input.triggerHandler('input');
160
161 $timeout.flush();
162 trs = element.find('tr.test-filtered');
163 expect(trs.length).toBe(4);
164 expect(trToModel(trs)).toEqual([
165 {name: 'Renard', firstname: 'Laurent', age: 66},
166 {name: 'Francoise', firstname: 'Frere', age: 99},
167 {name: 'Renard', firstname: 'Olivier', age: 33},
168 {name: 'Faivre', firstname: 'Blandine', age: 44}
169 ]);
170
171 stConfig.search.trimSearch = oldTrimSearch;
172
92173 }));
93174
94175 it('should throttle searching to 400ms by default', inject(function ($timeout) {
117198 {name: 'Renard', firstname: 'Laurent', age: 66},
118199 {name: 'Francoise', firstname: 'Frere', age: 99},
119200 {name: 'Renard', firstname: 'Olivier', age: 33},
120 {name: 'Leponge', firstname: 'Bob', age: 22},
201 {name: 'Le Blond', firstname: 'Bob', age: 22},
121202 {name: 'Faivre', firstname: 'Blandine', age: 44}
122203 ];
123204
168249 {name: 'Renard', firstname: 'Laurent', age: 66},
169250 {name: 'Francoise', firstname: 'Frere', age: 99},
170251 {name: 'Renard', firstname: 'Olivier', age: 33},
171 {name: 'Leponge', firstname: 'Bob', age: 22},
172 {name: 'Faivre', firstname: 'Blandine', age: 44}
173 ];
174
175 var template = '<table st-table="rowCollection">' +
176 '<thead>' +
177 '<tr>' +
178 '<th><input st-search="searchPredicate" /></th>' +
252 {name: 'Le Blond', firstname: 'Bob', age: 22},
253 {name: 'Faivre', firstname: 'Blandine', age: 44}
254 ];
255
256 var template = '<table st-table="rowCollection">' +
257 '<thead>' +
258 '<tr>' +
259 '<th><input st-search="{{searchPredicate}}" /></th>' +
179260 '<th><input st-search="" /></th>' +
180261 '<th>age</th>' +
181262 '</tr>' +
193274 scope.$apply();
194275 }));
195276
196
197277 it('should support binding on search predicate', inject(function ($compile, $timeout) {
198278 scope.searchPredicate = 'name';
199279 var ths = element.find('th');
224304
225305 }));
226306 });
307
308 describe('deep object predicate', function () {
309
310 beforeEach(inject(function ($compile, $rootScope) {
311
312 rootScope = $rootScope;
313 scope = $rootScope.$new();
314 scope.rowCollection = [
315 {name: {lastname: 'Renard', firstname: 'Laurent'}, age: 66, description:'really silly description'},
316 {name: {lastname: 'Francoise', firstname: 'Frere'}, age: 99, description:'really silly description'},
317 {name: {lastname: 'Renard', firstname: 'Olivier'}, age: 33, description:'really silly description'},
318 {name: {lastname: 'Le Blond', firstname: 'Bob'}, age: 22, description:'really silly description'},
319 {name: {lastname: 'Faivre', firstname: 'Blandine'}, age: 44, description:'really silly description'},
320 {name: null, age: 33, description:'really silly description'}
321 ];
322
323 var template = '<table st-table="rowCollection">' +
324 '<thead>' +
325 '<tr>' +
326 '<th><input st-search="name.lastname" /></th>' +
327 '<th><input st-search="name.$" /></th>' +
328 '<th>age</th>' +
329 '</tr>' +
330 '</thead>' +
331 '<tbody>' +
332 '<tr class="test-filtered" ng-repeat="row in rowCollection">' +
333 '<td>{{row.name.lastname}}</td>' +
334 '<td>{{row.name.firstname}}</td>' +
335 '<td>{{row.age}}</td>' +
336 '</tr>' +
337 '</tbody>' +
338 '</table>';
339
340 element = $compile(template)(scope);
341 scope.$apply();
342 }));
343
344 it('should keep only items which matches', inject(function ($timeout) {
345 var ths = element.find('th');
346 var trs;
347
348 var input = angular.element(ths[0].children[0]);
349 input[0].value = 're';
350 input.triggerHandler('input');
351 trs = element.find('tr.test-filtered');
352 expect(trs.length).toBe(6);
353 $timeout.flush();
354 trs = element.find('tr.test-filtered');
355 expect(trs.length).toBe(3);
356 expect(trToModel(trs)).toEqual([
357 {name: 'Renard', firstname: 'Laurent', age: 66},
358 {name: 'Renard', firstname: 'Olivier', age: 33},
359 {name: 'Faivre', firstname: 'Blandine', age: 44}
360 ]);
361 }));
362
363 it('should search globally within the name object', inject(function ($timeout) {
364 var ths = element.find('th');
365
366 var input = angular.element(ths[1].children[0]);
367 input[0].value = 're';
368 input.triggerHandler('input');
369 $timeout.flush();
370 var trs = element.find('tr.test-filtered');
371 expect(trs.length).toBe(4);
372 expect(trToModel(trs)).toEqual([
373 {name: 'Renard', firstname: 'Laurent', age: 66},
374 {name: 'Francoise', firstname: 'Frere', age: 99},
375 {name: 'Renard', firstname: 'Olivier', age: 33},
376 {name: 'Faivre', firstname: 'Blandine', age: 44}
377 ]);
378 }));
379
380 it('should be able to reset deep paths', inject(function ($timeout) {
381 var ths = element.find('th');
382
383 var input = angular.element(ths[0].children[0]);
384 input[0].value = 're';
385 input.triggerHandler('input');
386 $timeout.flush();
387 input[0].value = '';
388 input.triggerHandler('input');
389 $timeout.flush();
390 trs = element.find('tr.test-filtered');
391 expect(trs.length).toBe(6);
392 }));
393 });
227394 });
44 var element;
55 var tableState;
66
7 function hasClass(element, classname) {
7 function hasClass (element, classname) {
88 return Array.prototype.indexOf.call(element.classList, classname) !== -1
99 }
1010
11 function trToModel(trs) {
11 function hasAttr (element, attr, value) {
12 if (!attr || !value) return false;
13 return element.getAttribute(attr) === value;
14 }
15
16 function trToModel (trs) {
1217 return Array.prototype.map.call(trs, function (ele) {
1318 return {
1419 name: ele.cells[0].innerHTML,
3136 });
3237 }));
3338
34 describe('customized stConfig', function() {
39 describe('customized stConfig', function () {
3540
3641 beforeEach(inject(function ($compile, $rootScope, stConfig) {
3742 var oldAscentClass = stConfig.sort.ascentClass;
3843 var oldDescentClass = stConfig.sort.descentClass;
44 var oldSkipNatural = stConfig.sort.skipNatural;
3945 stConfig.sort.ascentClass = 'custom-ascent';
4046 stConfig.sort.descentClass = 'custom-descent';
47 stConfig.sort.skipNatural = true;
4148
4249 rootScope = $rootScope;
4350 scope = $rootScope.$new();
4956 {name: 'Faivre', firstname: 'Blandine', age: 44}
5057 ];
5158 scope.getters = {
52 age: function ageGetter(row) {
59 age: function ageGetter (row) {
5360 return row.name.length;
5461 },
55 name: function nameGetter(row) {
62 name: function nameGetter (row) {
5663 return row.name.length;
5764 }
5865 };
6370 '<th st-sort="firstname">firstname</th>' +
6471 '<th st-sort="getters.age">age</th>' +
6572 '<th st-sort="getters.name">age</th>' +
73 '<th st-sort="[\'name\', \'age\']">age</th>' +
6674 '</tr>' +
6775 '</thead>' +
6876 '<tbody>' +
8088
8189 stConfig.sort.ascentClass = oldAscentClass;
8290 stConfig.sort.descentClass = oldDescentClass;
83 }));
84
85 it('should customize classes for sorting', function() {
86 var ths = element.find('th');
87 angular.element(ths[1]).triggerHandler('click');
91 stConfig.sort.skipNatural = oldSkipNatural;
92 }));
93
94 it('should customize classes for sorting', inject(function ($timeout) {
95 var ths = element.find('th');
96 angular.element(ths[1]).triggerHandler('click');
97 $timeout.flush();
8898 expect(hasClass(ths[1], 'custom-ascent')).toBe(true);
8999 expect(hasClass(ths[1], 'custom-descent')).toBe(false);
90 });
100 }));
101
102 it('should skip natural order', inject(function ($timeout) {
103 var ths = element.find('th');
104 var th1 = angular.element(ths[1]);
105 th1.triggerHandler('click');
106 th1.triggerHandler('click');
107 th1.triggerHandler('click');
108 $timeout.flush();
109 var actual = trToModel(element.find('tr.test-row'));
110 expect(hasClass(ths[1], 'custom-ascent')).toBe(true);
111 expect(hasClass(ths[1], 'custom-descent')).toBe(false);
112 expect(actual).toEqual([
113 {name: 'Faivre', firstname: 'Blandine', age: 44},
114 {name: 'Leponge', firstname: 'Bob', age: 22},
115 {name: 'Francoise', firstname: 'Frere', age: 99},
116 {name: 'Renard', firstname: 'Laurent', age: 66},
117 {name: 'Renard', firstname: 'Olivier', age: 33}
118 ]);
119 }));
120
121 it('should sort properly with array value', inject(function ($timeout) {
122 var ths = element.find('th');
123 var th4 = angular.element(ths[4]);
124 th4.triggerHandler('click');
125 th4.triggerHandler('click');
126 $timeout.flush();
127 var actual = trToModel(element.find('tr.test-row'));
128 expect(actual).toEqual([
129 {name: 'Renard', firstname: 'Laurent', age: 66},
130 {name: 'Renard', firstname: 'Olivier', age: 33},
131 {name: 'Leponge', firstname: 'Bob', age: 22},
132 {name: 'Francoise', firstname: 'Frere', age: 99},
133 {name: 'Faivre', firstname: 'Blandine', age: 44},
134 ]);
135 }));
136
91137 });
92138
93 describe('normal stConfig', function() {
139 describe('normal stConfig', function () {
94140
95141 beforeEach(inject(function ($compile, $rootScope) {
96142
104150 {name: 'Faivre', firstname: 'Blandine', age: 44}
105151 ];
106152 scope.getters = {
107 age: function ageGetter(row) {
153 age: function ageGetter (row) {
108154 return row.name.length;
109155 },
110 name: function nameGetter(row) {
156 name: function nameGetter (row) {
111157 return row.name.length;
112158 }
113159 };
133179 scope.$apply();
134180 }));
135181
136 it('should sort by clicked header', function () {
137 var ths = element.find('th');
138 var actual;
139 angular.element(ths[1]).triggerHandler('click');
182 it('should sort by clicked header', inject(function ($timeout) {
183 var ths = element.find('th');
184 var actual;
185 angular.element(ths[1]).triggerHandler('click');
186 $timeout.flush();
140187 actual = trToModel(element.find('tr.test-row'));
141188 expect(hasClass(ths[1], 'st-sort-ascent')).toBe(true);
142189 expect(hasClass(ths[1], 'st-sort-descent')).toBe(false);
147194 {name: 'Renard', firstname: 'Laurent', age: 66},
148195 {name: 'Renard', firstname: 'Olivier', age: 33}
149196 ]);
150
151 });
152
153 it('should revert on the second click', function () {
154 var ths = element.find('th');
155 var actual;
156 angular.element(ths[1]).triggerHandler('click');
157 angular.element(ths[1]).triggerHandler('click');
197 }));
198
199 it('should revert on the second click', inject(function ($timeout) {
200 var ths = element.find('th');
201 var actual;
202 angular.element(ths[1]).triggerHandler('click');
203 $timeout.flush();
204 angular.element(ths[1]).triggerHandler('click');
205 $timeout.flush();
158206 actual = trToModel(element.find('tr.test-row'));
159207 expect(hasClass(ths[1], 'st-sort-ascent')).toBe(false);
160208 expect(hasClass(ths[1], 'st-sort-descent')).toBe(true);
165213 {name: 'Leponge', firstname: 'Bob', age: 22},
166214 {name: 'Faivre', firstname: 'Blandine', age: 44}
167215 ]);
168
169 });
170
171 it('should reset the sort state on the third call', function () {
172 var ths = element.find('th');
173 var actual;
174 angular.element(ths[1]).triggerHandler('click');
175 angular.element(ths[1]).triggerHandler('click');
216 }));
217
218 it('should reset the sort state on the third call', inject(function ($timeout) {
219 var ths = element.find('th');
220 var actual;
221 angular.element(ths[1]).triggerHandler('click');
222 $timeout.flush();
223 angular.element(ths[1]).triggerHandler('click');
224 $timeout.flush();
176225 tableState.sort = {
177226 predicate: 'firstname',
178227 reverse: true
179228 };
180229 tableState.pagination.start = 40;
181230 angular.element(ths[1]).triggerHandler('click');
231 $timeout.flush();
182232 actual = trToModel(element.find('tr.test-row'));
183233 expect(hasClass(ths[1], 'st-sort-ascent')).toBe(false);
184234 expect(hasClass(ths[1], 'st-sort-descent')).toBe(false);
191241 ]);
192242 expect(tableState.sort).toEqual({});
193243 expect(tableState.pagination.start).toEqual(0);
194
195 });
196
197 it('should support getter function as predicate', function () {
244 }));
245
246 it('should support getter function as predicate', inject(function ($timeout) {
198247 var ths = element.find('th');
199248 var actual;
200249 angular.element(ths[2]).triggerHandler('click');
250 $timeout.flush();
201251 actual = trToModel(element.find('tr.test-row'));
202252 expect(actual).toEqual([
203253 {name: 'Renard', firstname: 'Laurent', age: 66},
206256 {name: 'Leponge', firstname: 'Bob', age: 22},
207257 {name: 'Francoise', firstname: 'Frere', age: 99}
208258 ]);
209
210 });
211
212 it('should switch from getter function to the other', function () {
259 }));
260
261 it('should switch from getter function to the other', inject(function ($timeout) {
213262 var ths = element.find('th');
214263 var actual;
215264 angular.element(ths[2]).triggerHandler('click');
265 $timeout.flush();
216266 expect(hasClass(ths[2], 'st-sort-ascent')).toBe(true);
217267 expect(hasClass(ths[3], 'st-sort-ascent')).toBe(false);
218268
219269 angular.element(ths[3]).triggerHandler('click');
270 $timeout.flush();
220271 expect(hasClass(ths[2], 'st-sort-ascent')).toBe(false);
221272 expect(hasClass(ths[3], 'st-sort-ascent')).toBe(true);
222
223 });
224
225 it('should reset its class if table state has changed', function () {
226 var ths = element.find('th');
227 angular.element(ths[1]).triggerHandler('click');
273 }));
274
275 it('should reset its class if table state has changed', inject(function ($timeout) {
276 var ths = element.find('th');
277 angular.element(ths[1]).triggerHandler('click');
278 $timeout.flush();
228279 expect(hasClass(ths[1], 'st-sort-ascent')).toBe(true);
229280
230281 tableState.sort = {
235286 expect(hasClass(ths[1], 'st-sort-ascent')).toBe(false);
236287 expect(hasClass(ths[1], 'st-sort-descent')).toBe(false);
237288
238 });
239
240 it('should sort by default a column', inject(function ($compile) {
289 }));
290
291 it('should sort by default a column', inject(function ($compile, $timeout) {
241292 var template = '<table dummy="" st-table="rowCollection">' +
242293 '<thead>' +
243294 '<tr><th st-sort="name">name</th>' +
256307
257308 element = $compile(template)(scope);
258309
259 scope.$apply();
310 $timeout.flush();
260311
261312 var ths = element.find('th');
262313 var actual = trToModel(element.find('tr.test-row'));
309360
310361 }));
311362
312 it('should sort by default a column in reverse mode', inject(function ($compile) {
363 it('should sort by default a column in reverse mode', inject(function ($compile, $timeout) {
313364 var template = '<table dummy="" st-table="rowCollection">' +
314365 '<thead>' +
315366 '<tr><th st-sort="name">name</th>' +
328379
329380 element = $compile(template)(scope);
330381
331 scope.$apply();
382 $timeout.flush();
332383
333384 var ths = element.find('th');
334385 var actual = trToModel(element.find('tr.test-row'));
344395 }));
345396
346397
347 it('should skip natural order', inject(function ($compile) {
398 it('should skip natural order', inject(function ($compile, $timeout) {
348399 var template = '<table dummy="" st-table="rowCollection">' +
349400 '<thead>' +
350401 '<tr><th>name</th>' +
368419 var ths = element.find('th');
369420 var th1 = angular.element(ths[1]);
370421 th1.triggerHandler('click');
422 $timeout.flush();
371423 th1.triggerHandler('click');
424 $timeout.flush();
372425 th1.triggerHandler('click');
373 scope.$apply();
426 $timeout.flush();
374427 var actual = trToModel(element.find('tr.test-row'));
375428 expect(hasClass(ths[1], 'st-sort-ascent')).toBe(true);
376429 expect(hasClass(ths[1], 'st-sort-descent')).toBe(false);
382435 {name: 'Renard', firstname: 'Olivier', age: 33}
383436 ]);
384437 }));
385
438
439 it('should sort by clicked header in descending order first (by default) when requested', inject(function ($timeout, $compile, stConfig) {
440 var template = '<table dummy="" st-table="rowCollection">' +
441 '<thead>' +
442 '<tr><th st-sort="name">name</th>' +
443 '<th st-sort="firstname">firstname</th>' +
444 '<th st-sort="getters.age">age</th>' +
445 '<th st-sort="getters.name">age</th>' +
446 '</tr>' +
447 '</thead>' +
448 '<tbody>' +
449 '<tr class="test-row" ng-repeat="row in rowCollection">' +
450 '<td>{{row.name}}</td>' +
451 '<td>{{row.firstname}}</td>' +
452 '<td>{{row.age}}</td>' +
453 '</tr>' +
454 '</tbody>' +
455 '</table>';
456
457 stConfig.sort.descendingFirst = 'true'; // or any defined value
458
459 element = $compile(template)(scope);
460 scope.$apply();
461
462 var ths = element.find('th');
463 var actual;
464 angular.element(ths[1]).triggerHandler('click');
465 $timeout.flush();
466 actual = trToModel(element.find('tr.test-row'));
467 expect(hasClass(ths[1], 'st-sort-ascent')).toBe(false);
468 expect(hasClass(ths[1], 'st-sort-descent')).toBe(true);
469 expect(actual).toEqual([
470 {name: 'Renard', firstname: 'Olivier', age: 33},
471 {name: 'Renard', firstname: 'Laurent', age: 66},
472 {name: 'Francoise', firstname: 'Frere', age: 99},
473 {name: 'Leponge', firstname: 'Bob', age: 22},
474 {name: 'Faivre', firstname: 'Blandine', age: 44}
475 ]);
476 }));
477
478 it('should sort by clicked header in descending order first when requested', inject(function ($timeout, $compile) {
479 var template = '<table dummy="" st-table="rowCollection">' +
480 '<thead>' +
481 '<tr><th st-sort="name">name</th>' +
482 '<th st-sort="firstname" st-descending-first="true">firstname</th>' +
483 '<th st-sort="getters.age">age</th>' +
484 '<th st-sort="getters.name">age</th>' +
485 '</tr>' +
486 '</thead>' +
487 '<tbody>' +
488 '<tr class="test-row" ng-repeat="row in rowCollection">' +
489 '<td>{{row.name}}</td>' +
490 '<td>{{row.firstname}}</td>' +
491 '<td>{{row.age}}</td>' +
492 '</tr>' +
493 '</tbody>' +
494 '</table>';
495
496 element = $compile(template)(scope);
497 scope.$apply();
498
499 var ths = element.find('th');
500 var actual;
501 angular.element(ths[1]).triggerHandler('click');
502 $timeout.flush();
503 actual = trToModel(element.find('tr.test-row'));
504 expect(hasClass(ths[1], 'st-sort-ascent')).toBe(false);
505 expect(hasClass(ths[1], 'st-sort-descent')).toBe(true);
506 expect(actual).toEqual([
507 {name: 'Renard', firstname: 'Olivier', age: 33},
508 {name: 'Renard', firstname: 'Laurent', age: 66},
509 {name: 'Francoise', firstname: 'Frere', age: 99},
510 {name: 'Leponge', firstname: 'Bob', age: 22},
511 {name: 'Faivre', firstname: 'Blandine', age: 44}
512 ]);
513 }));
514
515 it('should switch to ascending order on the second click', inject(function ($timeout, $compile) {
516 var template = '<table dummy="" st-table="rowCollection">' +
517 '<thead>' +
518 '<tr><th st-sort="name">name</th>' +
519 '<th st-sort="firstname" st-descending-first="true">firstname</th>' +
520 '<th st-sort="getters.age">age</th>' +
521 '<th st-sort="getters.name">age</th>' +
522 '</tr>' +
523 '</thead>' +
524 '<tbody>' +
525 '<tr class="test-row" ng-repeat="row in rowCollection">' +
526 '<td>{{row.name}}</td>' +
527 '<td>{{row.firstname}}</td>' +
528 '<td>{{row.age}}</td>' +
529 '</tr>' +
530 '</tbody>' +
531 '</table>';
532
533 element = $compile(template)(scope);
534 scope.$apply();
535
536 var ths = element.find('th');
537 var actual;
538 angular.element(ths[1]).triggerHandler('click');
539 $timeout.flush();
540 angular.element(ths[1]).triggerHandler('click');
541 $timeout.flush();
542 actual = trToModel(element.find('tr.test-row'));
543 expect(hasClass(ths[1], 'st-sort-ascent')).toBe(true);
544 expect(hasClass(ths[1], 'st-sort-descent')).toBe(false);
545 expect(actual).toEqual([
546 {name: 'Faivre', firstname: 'Blandine', age: 44},
547 {name: 'Leponge', firstname: 'Bob', age: 22},
548 {name: 'Francoise', firstname: 'Frere', age: 99},
549 {name: 'Renard', firstname: 'Laurent', age: 66},
550 {name: 'Renard', firstname: 'Olivier', age: 33}
551 ]);
552 }));
553
554 it('should reset the sort state on the third call regardless of st-desending-first', inject(function ($timeout, $compile) {
555 var template = '<table dummy="" st-table="rowCollection">' +
556 '<thead>' +
557 '<tr><th st-sort="name">name</th>' +
558 '<th st-sort="firstname" st-descending-first="true">firstname</th>' +
559 '<th st-sort="getters.age">age</th>' +
560 '<th st-sort="getters.name">age</th>' +
561 '</tr>' +
562 '</thead>' +
563 '<tbody>' +
564 '<tr class="test-row" ng-repeat="row in rowCollection">' +
565 '<td>{{row.name}}</td>' +
566 '<td>{{row.firstname}}</td>' +
567 '<td>{{row.age}}</td>' +
568 '</tr>' +
569 '</tbody>' +
570 '</table>';
571
572 element = $compile(template)(scope);
573 scope.$apply();
574
575 var ths = element.find('th');
576 var actual;
577 angular.element(ths[1]).triggerHandler('click');
578 $timeout.flush();
579 angular.element(ths[1]).triggerHandler('click');
580 $timeout.flush();
581 tableState.sort = {
582 predicate: 'firstname',
583 reverse: true
584 };
585 tableState.pagination.start = 40;
586 angular.element(ths[1]).triggerHandler('click');
587 $timeout.flush();
588 actual = trToModel(element.find('tr.test-row'));
589 expect(hasClass(ths[1], 'st-sort-ascent')).toBe(false);
590 expect(hasClass(ths[1], 'st-sort-descent')).toBe(false);
591 expect(actual).toEqual([
592 {name: 'Renard', firstname: 'Laurent', age: 66},
593 {name: 'Francoise', firstname: 'Frere', age: 99},
594 {name: 'Renard', firstname: 'Olivier', age: 33},
595 {name: 'Leponge', firstname: 'Bob', age: 22},
596 {name: 'Faivre', firstname: 'Blandine', age: 44}
597 ]);
598 expect(tableState.sort).toEqual({});
599 expect(tableState.pagination.start).toEqual(0);
600 }));
601
602 it('should initialize headers with the aria role attribute set to columnheader', inject(function ($timeout) {
603 var ths = element.find('th');
604 expect((ths[1], ''))
605 expect(hasAttr(ths[1], 'role', 'columnheader')).toBe(true);
606 }));
607
608 it('should update aria-sort attribute when clicking', inject(function ($timeout) {
609 var ariaSort = 'aria-sort';
610 var ariaSortNone = 'none';
611 var ariaSortAscending = 'ascending';
612 var ariaSortDescending = 'descending';
613
614 var ths = element.find('th');
615 expect(hasAttr(ths[1], ariaSort, ariaSortNone)).toBe(true);
616 angular.element(ths[1]).triggerHandler('click');
617 $timeout.flush();
618 expect(hasAttr(ths[1], ariaSort, ariaSortAscending)).toBe(true);
619 angular.element(ths[1]).triggerHandler('click');
620 $timeout.flush();
621 expect(hasAttr(ths[1], ariaSort, ariaSortDescending)).toBe(true);
622 angular.element(ths[1]).triggerHandler('click');
623 $timeout.flush();
624 expect(hasAttr(ths[1], ariaSort, ariaSortNone)).toBe(true);
625 }));
626
627
386628 });
387629
388630
389 });
631 });
1313 {name: 'Renard', firstname: 'Laurent', age: 66},
1414 {name: 'Francoise', firstname: 'Frere', age: 99},
1515 {name: 'Renard', firstname: 'Olivier', age: 33},
16 {name: 'Leponge', firstname: 'Bob', age: 22},
16 {name: 'Le Blond', firstname: 'Bob', age: 22},
1717 {name: 'Faivre', firstname: 'Blandine', age: 44}
1818 ];
1919 scope = $rootScope;
2727
2828 }));
2929
30 describe('init', function(){
31 it('should contain default tableState', function(){
32 var defaultTableState = {
33 sort: {},
34 search: {},
35 pagination: {
36 start: 0,
37 totalItemCount: 0
38 }
39 };
40
41 var tableState = ctrl.tableState();
42 expect(tableState).toEqual(defaultTableState);
43 });
44 });
45
3046 describe('sort', function () {
3147 it('should sort the data', function () {
3248 ctrl.sortBy('firstname');
3349 expect(scope.data).toEqual([
3450 {name: 'Faivre', firstname: 'Blandine', age: 44},
35 {name: 'Leponge', firstname: 'Bob', age: 22},
51 {name: 'Le Blond', firstname: 'Bob', age: 22},
3652 {name: 'Francoise', firstname: 'Frere', age: 99},
3753 {name: 'Renard', firstname: 'Laurent', age: 66},
3854 {name: 'Renard', firstname: 'Olivier', age: 33}
4561 {name: 'Renard', firstname: 'Olivier', age: 33},
4662 {name: 'Renard', firstname: 'Laurent', age: 66},
4763 {name: 'Francoise', firstname: 'Frere', age: 99},
48 {name: 'Leponge', firstname: 'Bob', age: 22},
64 {name: 'Le Blond', firstname: 'Bob', age: 22},
4965 {name: 'Faivre', firstname: 'Blandine', age: 44}
5066 ]);
5167 });
5571 return row.firstname.length;
5672 });
5773 expect(scope.data).toEqual([
58 {name: 'Leponge', firstname: 'Bob', age: 22},
74 {name: 'Le Blond', firstname: 'Bob', age: 22},
5975 {name: 'Francoise', firstname: 'Frere', age: 99},
6076 {name: 'Renard', firstname: 'Laurent', age: 66},
6177 {name: 'Renard', firstname: 'Olivier', age: 33},
6985 });
7086
7187 expect(scope.data).toEqual([
72 {name: 'Leponge', firstname: 'Bob', age: 22},
88 {name: 'Le Blond', firstname: 'Bob', age: 22},
7389 {name: 'Francoise', firstname: 'Frere', age: 99},
7490 {name: 'Renard', firstname: 'Laurent', age: 66},
7591 {name: 'Renard', firstname: 'Olivier', age: 33},
160176 ]);
161177 });
162178
163 it('should trim if the input is a string', function () {
164 ctrl.search(' re ', 'name');
165 expect(scope.data).toEqual([
166 {name: 'Renard', firstname: 'Laurent', age: 66},
167 {name: 'Renard', firstname: 'Olivier', age: 33},
168 {name: 'Faivre', firstname: 'Blandine', age: 44}
179 it('should search input string containing leading space', function () {
180 ctrl.search(' blond', 'name', true);
181 expect(scope.data).toEqual([
182 {name: 'Le Blond', firstname: 'Bob', age: 22}
183 ]);
184 });
185
186 it('should search input string containing trailing space', function () {
187 ctrl.search('le ', 'name', true);
188 expect(scope.data).toEqual([
189 {name: 'Le Blond', firstname: 'Bob', age: 22}
190 ]);
191 });
192
193 it('should search input string with no leading or trailing space', function () {
194 ctrl.search('re', 'name', true);
195 expect(scope.data).toEqual([
196 {name: 'Renard', firstname: 'Laurent', age: 66},
197 {name: 'Renard', firstname: 'Olivier', age: 33},
198 {name: 'Faivre', firstname: 'Blandine', age: 44}
199 ]);
200 });
201
202 it('should search when input is not a string', function () {
203 ctrl.search(2, 'age');
204 expect(scope.data).toEqual([
205 {name: 'Le Blond', firstname: 'Bob', age: 22}
169206 ]);
170207 });
171208 });
190227 });
191228
192229 describe('pipe', function () {
230 it('should set totalItemCount on tableState pagination', function(){
231 var expectedLength = 5;
232 ctrl.pipe();
233 expect(scope.data.length).toBe(expectedLength);
234 expect(ctrl.tableState().pagination.totalItemCount).toBe(expectedLength);
235 });
236
237 it('should set totalItemCount as size of filtered array', function(){
238 var expectedLength = 3;
239 ctrl.search('re', 'name');
240 expect(scope.data.length).toBe(expectedLength);
241 expect(ctrl.tableState().pagination.totalItemCount).toBe(expectedLength);
242 });
243
193244 it('should remembered the last slice length but start back to zero when sorting', function () {
194245 ctrl.slice(1, 2);
195246 expect(scope.data.length).toBe(2);
202253 expect(scope.data.length).toBe(2);
203254 expect(scope.data).toEqual([
204255 {name: 'Faivre', firstname: 'Blandine', age: 44},
205 {name: 'Leponge', firstname: 'Bob', age: 22}
256 {name: 'Le Blond', firstname: 'Bob', age: 22}
206257 ]);
207258 });
208259
226277 ctrl.sortBy('firstname');
227278 expect(scope.data).toEqual([
228279 {name: 'Faivre', firstname: 'Blandine', age: 44},
229 {name: 'Leponge', firstname: 'Bob', age: 22},
280 {name: 'Le Blond', firstname: 'Bob', age: 22},
230281 {name: 'Francoise', firstname: 'Frere', age: 99},
231282 {name: 'Renard', firstname: 'Laurent', age: 66},
232283 {name: 'Renard', firstname: 'Olivier', age: 33}