Import upstream version 2.1.11+git20180109.1.4dd9d0d
Debian Janitor
2 years ago
0 | 0 | language: node_js |
1 | 1 | node_js: |
2 | - "0.10" | |
3 | ||
2 | - "8" | |
4 | 3 | |
5 | 4 | before_script: |
6 | - npm install -g gulp bower | |
7 | 5 | - npm install |
8 | - bower install | |
9 | 6 | |
10 | 7 | script: |
11 | 8 | - 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. |
0 | 0 | { |
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 | ] | |
28 | 22 | } |
0 | 0 | ## version 1.1.0 |
1 | 1 | |
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)). | |
3 | 3 | 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 |
4 | 4 | ```markup |
5 | 5 | <input st-search="'name'"/> |
7 | 7 | |
8 | 8 | ## version 1.1.1 |
9 | 9 | |
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) | |
11 | 11 | |
12 | 12 | ## version 1.2.1 |
13 | 13 | |
14 | * implement #149 (default sorting) | |
14 | * implement [#149](https://github.com/lorenzofox3/Smart-Table/issues/149) (default sorting) | |
15 | 15 | |
16 | 16 | ## version 1.2.2 |
17 | 17 | |
25 | 25 | |
26 | 26 | ## version 1.2.4 |
27 | 27 | |
28 | * fix #161 | |
28 | * fix [#161](https://github.com/lorenzofox3/Smart-Table/issues/161) | |
29 | 29 | |
30 | 30 | ## version 1.2.5 |
31 | 31 | |
32 | * fix #162 | |
32 | * fix [#162](https://github.com/lorenzofox3/Smart-Table/issues/162) | |
33 | 33 | |
34 | 34 | ## version 1.2.6 |
35 | 35 | |
36 | * fix #165 | |
36 | * fix [#165](https://github.com/lorenzofox3/Smart-Table/issues/165) | |
37 | 37 | * ability to overwrite class names for (st-sort-ascent and st-sort-descent) thanks to [replacement87](https://github.com/replacement87) |
38 | 38 | |
39 | 39 | ## version 1.2.7 |
40 | 40 | |
41 | * fix #167 | |
41 | * fix [#167](https://github.com/lorenzofox3/Smart-Table/issues/167) | |
42 | 42 | |
43 | 43 | ## version 1.3.0 |
44 | 44 | |
51 | 51 | |
52 | 52 | ## version 1.4.1 |
53 | 53 | |
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)) | |
55 | 55 | |
56 | 56 | ## versiokn 1.4.2 |
57 | 57 | |
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 | |
59 | 59 | ```javascript |
60 | 60 | function(tableState, tableController){ |
61 | 61 | |
73 | 73 | |
74 | 74 | ## version 1.4.5 |
75 | 75 | |
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) | |
78 | 78 | |
79 | 79 | ## version 1.4.6 |
80 | 80 | |
81 | 81 | * evaluate sort predicate as late as possible |
82 | * fix #262 | |
82 | * fix [#262](https://github.com/lorenzofox3/Smart-Table/issues/262) | |
83 | 83 | |
84 | 84 | ## version 1.4.7 |
85 | 85 | |
86 | * fix #276 | |
86 | * fix [#276](https://github.com/lorenzofox3/Smart-Table/issues/276) | |
87 | 87 | |
88 | 88 | ## version 1.4.8 |
89 | 89 | |
90 | * fix #281 | |
90 | * fix [#281](https://github.com/lorenzofox3/Smart-Table/issues/281) | |
91 | 91 | |
92 | 92 | ## version 1.4.9 |
93 | 93 | |
94 | * fix #285 | |
94 | * fix [#285](https://github.com/lorenzofox3/Smart-Table/issues/285) | |
95 | 95 | |
96 | 96 | ## version 1.4.10 |
97 | 97 | |
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) | |
100 | 100 | |
101 | 101 | ## version 1.4.11 |
102 | 102 | |
103 | * fix #296 | |
103 | * fix [#296](https://github.com/lorenzofox3/Smart-Table/issues/296) | |
104 | 104 | * add possibility to bind a callback when page changes |
105 | 105 | |
106 | 106 | ## version 1.4.12 |
113 | 113 | * use a global configuration |
114 | 114 | * expose filtered collection result |
115 | 115 | |
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 |
0 | 0 | /** |
1 | * @version 1.4.13 | |
1 | * @version 2.1.11 | |
2 | 2 | * @license MIT |
3 | 3 | */ |
4 | 4 | (function (ng, undefined){ |
6 | 6 | |
7 | 7 | ng.module('smart-table', []).run(['$templateCache', function ($templateCache) { |
8 | 8 | $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>' + | |
11 | 11 | '</ul></nav>'); |
12 | 12 | }]); |
13 | 13 | |
20 | 20 | displayedPages: 5 |
21 | 21 | }, |
22 | 22 | search: { |
23 | delay: 400 // ms | |
23 | delay: 400, // ms | |
24 | inputEvent: 'input', | |
25 | trimSearch: false | |
24 | 26 | }, |
25 | 27 | select: { |
26 | 28 | mode: 'single', |
28 | 30 | }, |
29 | 31 | sort: { |
30 | 32 | 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 | |
32 | 40 | } |
33 | 41 | }); |
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) { | |
36 | 48 | var propertyName = $attrs.stTable; |
37 | 49 | var displayGetter = $parse(propertyName); |
38 | 50 | var displaySetter = displayGetter.assign; |
43 | 55 | var tableState = { |
44 | 56 | sort: {}, |
45 | 57 | search: {}, |
46 | pagination: { | |
47 | start: 0 | |
48 | } | |
58 | pagination: { start: 0, totalItemCount: 0 } | |
49 | 59 | }; |
50 | 60 | var filtered; |
51 | 61 | var pipeAfterSafeCopy = true; |
52 | 62 | var ctrl = this; |
53 | 63 | var lastSelected; |
54 | 64 | |
55 | function copyRefs (src) { | |
65 | function copyRefs(src) { | |
56 | 66 | return src ? [].concat(src) : []; |
57 | 67 | } |
58 | 68 | |
59 | function updateSafeCopy () { | |
69 | function updateSafeCopy() { | |
60 | 70 | safeCopy = copyRefs(safeGetter($scope)); |
61 | 71 | if (pipeAfterSafeCopy === true) { |
62 | 72 | ctrl.pipe(); |
63 | 73 | } |
64 | 74 | } |
65 | 75 | |
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 | ||
66 | 91 | if ($attrs.stSafeSrc) { |
67 | 92 | 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 | ); | |
84 | 126 | } |
85 | 127 | |
86 | 128 | /** |
88 | 130 | * @param {Function | String} predicate - function or string which will be used as predicate for the sorting |
89 | 131 | * @param [reverse] - if you want to reverse the order |
90 | 132 | */ |
91 | this.sortBy = function sortBy (predicate, reverse) { | |
133 | this.sortBy = function sortBy(predicate, reverse) { | |
92 | 134 | tableState.sort.predicate = predicate; |
93 | 135 | tableState.sort.reverse = reverse === true; |
94 | 136 | |
106 | 148 | * search matching rows |
107 | 149 | * @param {String} input - the input string |
108 | 150 | * @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) { | |
111 | 154 | var predicateObject = tableState.search.predicateObject || {}; |
112 | 155 | var prop = predicate ? predicate : '$'; |
113 | 156 | |
114 | input = ng.isString(input) ? input.trim() : input; | |
115 | predicateObject[prop] = input; | |
157 | $parse(prop).assign(predicateObject, input); | |
116 | 158 | // to avoid to filter out null value |
117 | 159 | if (!input) { |
118 | delete predicateObject[prop]; | |
160 | deepDelete(predicateObject, prop); | |
119 | 161 | } |
120 | 162 | tableState.search.predicateObject = predicateObject; |
121 | 163 | tableState.pagination.start = 0; |
125 | 167 | /** |
126 | 168 | * this will chain the operations of sorting and filtering based on the current table state (sort options, filtering, ect) |
127 | 169 | */ |
128 | this.pipe = function pipe () { | |
170 | this.pipe = function pipe() { | |
129 | 171 | var pagination = tableState.pagination; |
130 | 172 | 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; | |
132 | 176 | 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; | |
135 | 184 | 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 | ); | |
139 | 195 | } |
140 | 196 | displaySetter($scope, output || filtered); |
141 | 197 | }; |
145 | 201 | * @param {Object} row - the row to select |
146 | 202 | * @param {String} [mode] - "single" or "multiple" (multiple by default) |
147 | 203 | */ |
148 | this.select = function select (row, mode) { | |
149 | var rows = safeCopy; | |
204 | this.select = function select(row, mode) { | |
205 | var rows = copyRefs(displayGetter($scope)); | |
150 | 206 | var index = rows.indexOf(row); |
151 | 207 | if (index !== -1) { |
152 | 208 | if (mode === 'single') { |
167 | 223 | * @param {Number} start - start index of the slice |
168 | 224 | * @param {Number} number - the number of item in the slice |
169 | 225 | */ |
170 | this.slice = function splice (start, number) { | |
226 | this.slice = function splice(start, number) { | |
171 | 227 | tableState.pagination.start = start; |
172 | 228 | tableState.pagination.number = number; |
173 | 229 | return this.pipe(); |
177 | 233 | * return the current state of the table |
178 | 234 | * @returns {{sort: {}, search: {}, pagination: {start: number}}} |
179 | 235 | */ |
180 | this.tableState = function getTableState () { | |
236 | this.tableState = function getTableState() { | |
181 | 237 | return tableState; |
182 | 238 | }; |
183 | 239 | |
184 | this.getFilteredCollection = function getFilteredCollection () { | |
240 | this.getFilteredCollection = function getFilteredCollection() { | |
185 | 241 | return filtered || safeCopy; |
186 | 242 | }; |
187 | 243 | |
189 | 245 | * Use a different filter function than the angular FilterFilter |
190 | 246 | * @param filterName the name under which the custom filter is registered |
191 | 247 | */ |
192 | this.setFilterFunction = function setFilterFunction (filterName) { | |
248 | this.setFilterFunction = function setFilterFunction(filterName) { | |
193 | 249 | filter = $filter(filterName); |
194 | 250 | }; |
195 | 251 | |
197 | 253 | * Use a different function than the angular orderBy |
198 | 254 | * @param sortFunctionName the name under which the custom order function is registered |
199 | 255 | */ |
200 | this.setSortFunction = function setSortFunction (sortFunctionName) { | |
256 | this.setSortFunction = function setSortFunction(sortFunctionName) { | |
201 | 257 | orderBy = $filter(sortFunctionName); |
202 | 258 | }; |
203 | 259 | |
205 | 261 | * Usually when the safe copy is updated the pipe function is called. |
206 | 262 | * Calling this method will prevent it, which is something required when using a custom pipe function |
207 | 263 | */ |
208 | this.preventPipeOnWatch = function preventPipe () { | |
264 | this.preventPipeOnWatch = function preventPipe() { | |
209 | 265 | pipeAfterSafeCopy = false; |
210 | 266 | }; |
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 | }); | |
228 | 283 | |
229 | 284 | ng.module('smart-table') |
230 | .directive('stSearch', ['stConfig', '$timeout', function (stConfig, $timeout) { | |
285 | .directive('stSearch', ['stConfig', '$timeout','$parse', function (stConfig, $timeout, $parse) { | |
231 | 286 | return { |
232 | 287 | require: '^stTable', |
233 | scope: { | |
234 | predicate: '=?stSearch' | |
235 | }, | |
236 | 288 | link: function (scope, element, attr, ctrl) { |
237 | 289 | var tableCtrl = ctrl; |
238 | 290 | var promise = null; |
239 | 291 | 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) { | |
243 | 298 | ctrl.tableState().search = {}; |
244 | tableCtrl.search(element[0].value || '', newValue); | |
299 | input = ng.isString(input) && trimSearch ? input.trim() : input; | |
300 | tableCtrl.search(input, newValue); | |
245 | 301 | } |
246 | 302 | }); |
247 | 303 | |
249 | 305 | scope.$watch(function () { |
250 | 306 | return ctrl.tableState().search; |
251 | 307 | }, 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) || ''; | |
255 | 311 | } |
256 | 312 | }, true); |
257 | 313 | |
258 | 314 | // view -> table state |
259 | element.bind('input', function (evt) { | |
315 | element.bind(event, function (evt) { | |
260 | 316 | evt = evt.originalEvent || evt; |
261 | 317 | if (promise !== null) { |
262 | 318 | $timeout.cancel(promise); |
263 | 319 | } |
320 | ||
264 | 321 | 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 || ''); | |
266 | 325 | promise = null; |
267 | 326 | }, throttle); |
268 | 327 | }); |
298 | 357 | }]); |
299 | 358 | |
300 | 359 | ng.module('smart-table') |
301 | .directive('stSort', ['stConfig', '$parse', function (stConfig, $parse) { | |
360 | .directive('stSort', ['stConfig', '$parse', '$timeout', function (stConfig, $parse, $timeout) { | |
302 | 361 | return { |
303 | 362 | restrict: 'A', |
304 | 363 | require: '^stTable', |
311 | 370 | var classDescent = attr.stClassDescent || stConfig.sort.descentClass; |
312 | 371 | var stateClasses = [classAscent, classDescent]; |
313 | 372 | 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); | |
314 | 386 | |
315 | 387 | if (attr.stSortDefault) { |
316 | 388 | sortDefault = scope.$eval(attr.stSortDefault) !== undefined ? scope.$eval(attr.stSortDefault) : attr.stSortDefault; |
318 | 390 | |
319 | 391 | //view --> table state |
320 | 392 | 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) { | |
324 | 402 | //manual reset |
325 | 403 | index = 0; |
326 | 404 | ctrl.tableState().sort = {}; |
327 | 405 | ctrl.tableState().pagination.start = 0; |
328 | ctrl.pipe(); | |
406 | func = ctrl.pipe.bind(ctrl); | |
329 | 407 | } 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); | |
331 | 419 | } |
332 | 420 | } |
333 | 421 | |
350 | 438 | index = 0; |
351 | 439 | element |
352 | 440 | .removeClass(classAscent) |
353 | .removeClass(classDescent); | |
441 | .removeClass(classDescent) | |
442 | .attr(ariaSort, ariaSortNone); | |
354 | 443 | } else { |
355 | 444 | index = newValue.reverse === true ? 2 : 1; |
356 | 445 | element |
357 | 446 | .removeClass(stateClasses[index % 2]) |
358 | .addClass(stateClasses[index - 1]); | |
447 | .addClass(stateClasses[index - 1]) | |
448 | .attr(ariaSort, newValue.reverse ? ariaSortAscending : ariaSortDescending); | |
359 | 449 | } |
360 | 450 | }, true); |
361 | 451 | } |
392 | 482 | var end; |
393 | 483 | var i; |
394 | 484 | var prevPage = scope.currentPage; |
485 | scope.totalItemCount = paginationState.totalItemCount; | |
395 | 486 | scope.currentPage = Math.floor(paginationState.start / paginationState.number) + 1; |
396 | 487 | |
397 | 488 | start = Math.max(start, scope.currentPage - Math.abs(Math.floor(scope.stDisplayedPages / 2))); |
443 | 534 | }]); |
444 | 535 | |
445 | 536 | ng.module('smart-table') |
446 | .directive('stPipe', function () { | |
537 | .directive('stPipe', ['stConfig', '$timeout', function (config, $timeout) { | |
447 | 538 | return { |
448 | 539 | require: 'stTable', |
449 | 540 | scope: { |
452 | 543 | link: { |
453 | 544 | |
454 | 545 | pre: function (scope, element, attrs, ctrl) { |
546 | ||
547 | var pipePromise = null; | |
548 | ||
455 | 549 | if (ng.isFunction(scope.stPipe)) { |
456 | 550 | ctrl.preventPipeOnWatch(); |
457 | 551 | 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; | |
459 | 562 | } |
460 | 563 | } |
461 | 564 | }, |
465 | 568 | } |
466 | 569 | } |
467 | 570 | }; |
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);⏎ |
0 | 0 | /** |
1 | * @version 1.4.13 | |
1 | * @version 2.1.11 | |
2 | 2 | * @license MIT |
3 | 3 | */ |
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":"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","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);"]}⏎ |
1 | 1 | var concat = require('gulp-concat'); |
2 | 2 | var uglify = require('gulp-uglify'); |
3 | 3 | var karma = require('karma').server; |
4 | var jshint = require('gulp-jshint'); | |
5 | 4 | var insert = require('gulp-insert'); |
6 | 5 | var sourcemaps = require('gulp-sourcemaps'); |
7 | var stylish = require('jshint-stylish'); | |
8 | 6 | var packageJson = require('./package.json'); |
9 | 7 | var pluginList = ['stSearch', 'stSelectRow', 'stSort', 'stPagination', 'stPipe']; |
10 | 8 | var disFolder = './dist/'; |
15 | 13 | src.push('src/bottom.txt'); |
16 | 14 | src.unshift('src/top.txt'); |
17 | 15 | |
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 | ||
34 | 16 | |
35 | 17 | gulp.task('karma-CI', function (done) { |
36 | 18 | var conf = require('./test/karma.common.js'); |
40 | 22 | karma.start(conf, done); |
41 | 23 | }); |
42 | 24 | |
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 | ||
43 | 34 | gulp.task('concat', function () { |
44 | 35 | 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)); | |
49 | 38 | }); |
50 | 39 | |
51 | 40 | gulp.task('test', ['karma-CI']); |
0 | 0 | { |
1 | 1 | "name": "angular-smart-table", |
2 | "version": "1.4.13", | |
2 | "version": "2.1.11", | |
3 | 3 | "description": "", |
4 | "main": "dist/smart-table.js", | |
4 | "main": "index.js", | |
5 | 5 | "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" | |
7 | 8 | }, |
8 | 9 | "repository": { |
9 | 10 | "type": "git", |
10 | 11 | "url": "https://github.com/lorenzofox3/Smart-Table.git" |
11 | 12 | }, |
12 | "author": "", | |
13 | "license": "ISC", | |
13 | "author": "Laurent Renard", | |
14 | "license": "MIT", | |
14 | 15 | "devDependencies": { |
16 | "angular": "^1.6.4", | |
17 | "angular-mocks": "^1.6.4", | |
15 | 18 | "gulp": "^3.8.7", |
16 | 19 | "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" | |
27 | 30 | } |
28 | 31 | } |
0 | 0 | [![Build Status](https://travis-ci.org/lorenzofox3/Smart-Table.svg?branch=master)](https://travis-ci.org/lorenzofox3/Smart-Table) |
1 | 1 | |
2 | **Hey I am not too much into angular these days. If someone wants to maintain this project, please contact me !** | |
3 | ||
2 | 4 | # 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) | |
4 | 5 | |
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. | |
6 | 7 | It is lightweight (around 3kb minified) and has no other dependencies than Angular itself. |
7 | 8 | Check the [documentation](http://lorenzofox3.github.io/smart-table-website/) website for more details |
8 | 9 | |
9 | ## submitting an issue | |
10 | ## Submitting an issue | |
10 | 11 | |
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: | |
12 | 13 | |
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. | |
14 | 15 | |
15 | 2. give a precise description mentionning angular version, smart-table version. | |
16 | 2. Give a precise description mentionning angular version, smart-table version. | |
16 | 17 | |
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). | |
18 | 19 | |
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. | |
20 | 21 | |
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). | |
22 | 23 | |
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. | |
24 | 27 | |
25 | 28 | ## Install |
26 | 29 | |
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 | |
28 | 33 | |
29 | 34 | ## Test |
30 | 35 | |
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`). | |
32 | 37 | |
33 | ## custom builds | |
38 | ## Custom builds | |
34 | 39 | |
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`. | |
37 | 42 | |
38 | 43 | ## Older versions |
39 | 44 | |
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 | |
41 | 46 | [here](https://github.com/lorenzofox3/smart-table-website) (simply open index.html in a browser). |
42 | 47 | |
43 | 48 | 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. |
46 | 51 | |
47 | 52 | Smart Table module is under MIT license: |
48 | 53 | |
49 | > Copyright (C) 2014 Laurent Renard. | |
54 | > Copyright (C) 2016 Laurent Renard. | |
50 | 55 | > |
51 | 56 | > Permission is hereby granted, free of charge, to any person |
52 | 57 | > obtaining a copy of this software and associated documentation files |
0 | 0 | ng.module('smart-table', []).run(['$templateCache', function ($templateCache) { |
1 | 1 | $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>' + | |
4 | 4 | '</ul></nav>'); |
5 | 5 | }]); |
6 | 6 |
5 | 5 | displayedPages: 5 |
6 | 6 | }, |
7 | 7 | search: { |
8 | delay: 400 // ms | |
8 | delay: 400, // ms | |
9 | inputEvent: 'input', | |
10 | trimSearch: false | |
9 | 11 | }, |
10 | 12 | select: { |
11 | 13 | mode: 'single', |
13 | 15 | }, |
14 | 16 | sort: { |
15 | 17 | 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 | |
17 | 25 | } |
18 | 26 | });⏎ |
27 | 27 | var end; |
28 | 28 | var i; |
29 | 29 | var prevPage = scope.currentPage; |
30 | scope.totalItemCount = paginationState.totalItemCount; | |
30 | 31 | scope.currentPage = Math.floor(paginationState.start / paginationState.number) + 1; |
31 | 32 | |
32 | 33 | start = Math.max(start, scope.currentPage - Math.abs(Math.floor(scope.stDisplayedPages / 2))); |
0 | 0 | ng.module('smart-table') |
1 | .directive('stPipe', function () { | |
1 | .directive('stPipe', ['stConfig', '$timeout', function (config, $timeout) { | |
2 | 2 | return { |
3 | 3 | require: 'stTable', |
4 | 4 | scope: { |
7 | 7 | link: { |
8 | 8 | |
9 | 9 | pre: function (scope, element, attrs, ctrl) { |
10 | ||
11 | var pipePromise = null; | |
12 | ||
10 | 13 | if (ng.isFunction(scope.stPipe)) { |
11 | 14 | ctrl.preventPipeOnWatch(); |
12 | 15 | 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; | |
14 | 26 | } |
15 | 27 | } |
16 | 28 | }, |
20 | 32 | } |
21 | 33 | } |
22 | 34 | }; |
23 | }); | |
35 | }]); |
0 | 0 | ng.module('smart-table') |
1 | .directive('stSearch', ['stConfig', '$timeout', function (stConfig, $timeout) { | |
1 | .directive('stSearch', ['stConfig', '$timeout','$parse', function (stConfig, $timeout, $parse) { | |
2 | 2 | return { |
3 | 3 | require: '^stTable', |
4 | scope: { | |
5 | predicate: '=?stSearch' | |
6 | }, | |
7 | 4 | link: function (scope, element, attr, ctrl) { |
8 | 5 | var tableCtrl = ctrl; |
9 | 6 | var promise = null; |
10 | 7 | var throttle = attr.stDelay || stConfig.search.delay; |
8 | var event = attr.stInputEvent || stConfig.search.inputEvent; | |
9 | var trimSearch = attr.trimSearch || stConfig.search.trimSearch; | |
11 | 10 | |
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) { | |
14 | 14 | ctrl.tableState().search = {}; |
15 | tableCtrl.search(element[0].value || '', newValue); | |
15 | input = ng.isString(input) && trimSearch ? input.trim() : input; | |
16 | tableCtrl.search(input, newValue); | |
16 | 17 | } |
17 | 18 | }); |
18 | 19 | |
20 | 21 | scope.$watch(function () { |
21 | 22 | return ctrl.tableState().search; |
22 | 23 | }, 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) || ''; | |
26 | 27 | } |
27 | 28 | }, true); |
28 | 29 | |
29 | 30 | // view -> table state |
30 | element.bind('input', function (evt) { | |
31 | element.bind(event, function (evt) { | |
31 | 32 | evt = evt.originalEvent || evt; |
32 | 33 | if (promise !== null) { |
33 | 34 | $timeout.cancel(promise); |
34 | 35 | } |
36 | ||
35 | 37 | 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 || ''); | |
37 | 41 | promise = null; |
38 | 42 | }, throttle); |
39 | 43 | }); |
0 | 0 | ng.module('smart-table') |
1 | .directive('stSort', ['stConfig', '$parse', function (stConfig, $parse) { | |
1 | .directive('stSort', ['stConfig', '$parse', '$timeout', function (stConfig, $parse, $timeout) { | |
2 | 2 | return { |
3 | 3 | restrict: 'A', |
4 | 4 | require: '^stTable', |
11 | 11 | var classDescent = attr.stClassDescent || stConfig.sort.descentClass; |
12 | 12 | var stateClasses = [classAscent, classDescent]; |
13 | 13 | 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); | |
14 | 27 | |
15 | 28 | if (attr.stSortDefault) { |
16 | 29 | sortDefault = scope.$eval(attr.stSortDefault) !== undefined ? scope.$eval(attr.stSortDefault) : attr.stSortDefault; |
18 | 31 | |
19 | 32 | //view --> table state |
20 | 33 | 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) { | |
24 | 43 | //manual reset |
25 | 44 | index = 0; |
26 | 45 | ctrl.tableState().sort = {}; |
27 | 46 | ctrl.tableState().pagination.start = 0; |
28 | ctrl.pipe(); | |
47 | func = ctrl.pipe.bind(ctrl); | |
29 | 48 | } 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); | |
31 | 60 | } |
32 | 61 | } |
33 | 62 | |
50 | 79 | index = 0; |
51 | 80 | element |
52 | 81 | .removeClass(classAscent) |
53 | .removeClass(classDescent); | |
82 | .removeClass(classDescent) | |
83 | .attr(ariaSort, ariaSortNone); | |
54 | 84 | } else { |
55 | 85 | index = newValue.reverse === true ? 2 : 1; |
56 | 86 | element |
57 | 87 | .removeClass(stateClasses[index % 2]) |
58 | .addClass(stateClasses[index - 1]); | |
88 | .addClass(stateClasses[index - 1]) | |
89 | .attr(ariaSort, newValue.reverse ? ariaSortAscending : ariaSortDescending); | |
59 | 90 | } |
60 | 91 | }, true); |
61 | 92 | } |
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) { | |
2 | 6 | var propertyName = $attrs.stTable; |
3 | 7 | var displayGetter = $parse(propertyName); |
4 | 8 | var displaySetter = displayGetter.assign; |
9 | 13 | var tableState = { |
10 | 14 | sort: {}, |
11 | 15 | search: {}, |
12 | pagination: { | |
13 | start: 0 | |
14 | } | |
16 | pagination: { start: 0, totalItemCount: 0 } | |
15 | 17 | }; |
16 | 18 | var filtered; |
17 | 19 | var pipeAfterSafeCopy = true; |
18 | 20 | var ctrl = this; |
19 | 21 | var lastSelected; |
20 | 22 | |
21 | function copyRefs (src) { | |
23 | function copyRefs(src) { | |
22 | 24 | return src ? [].concat(src) : []; |
23 | 25 | } |
24 | 26 | |
25 | function updateSafeCopy () { | |
27 | function updateSafeCopy() { | |
26 | 28 | safeCopy = copyRefs(safeGetter($scope)); |
27 | 29 | if (pipeAfterSafeCopy === true) { |
28 | 30 | ctrl.pipe(); |
29 | 31 | } |
30 | 32 | } |
31 | 33 | |
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 | ||
32 | 49 | if ($attrs.stSafeSrc) { |
33 | 50 | 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 | ); | |
50 | 84 | } |
51 | 85 | |
52 | 86 | /** |
54 | 88 | * @param {Function | String} predicate - function or string which will be used as predicate for the sorting |
55 | 89 | * @param [reverse] - if you want to reverse the order |
56 | 90 | */ |
57 | this.sortBy = function sortBy (predicate, reverse) { | |
91 | this.sortBy = function sortBy(predicate, reverse) { | |
58 | 92 | tableState.sort.predicate = predicate; |
59 | 93 | tableState.sort.reverse = reverse === true; |
60 | 94 | |
72 | 106 | * search matching rows |
73 | 107 | * @param {String} input - the input string |
74 | 108 | * @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) { | |
77 | 112 | var predicateObject = tableState.search.predicateObject || {}; |
78 | 113 | var prop = predicate ? predicate : '$'; |
79 | 114 | |
80 | input = ng.isString(input) ? input.trim() : input; | |
81 | predicateObject[prop] = input; | |
115 | $parse(prop).assign(predicateObject, input); | |
82 | 116 | // to avoid to filter out null value |
83 | 117 | if (!input) { |
84 | delete predicateObject[prop]; | |
118 | deepDelete(predicateObject, prop); | |
85 | 119 | } |
86 | 120 | tableState.search.predicateObject = predicateObject; |
87 | 121 | tableState.pagination.start = 0; |
91 | 125 | /** |
92 | 126 | * this will chain the operations of sorting and filtering based on the current table state (sort options, filtering, ect) |
93 | 127 | */ |
94 | this.pipe = function pipe () { | |
128 | this.pipe = function pipe() { | |
95 | 129 | var pagination = tableState.pagination; |
96 | 130 | 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; | |
98 | 134 | 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; | |
101 | 142 | 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 | ); | |
105 | 153 | } |
106 | 154 | displaySetter($scope, output || filtered); |
107 | 155 | }; |
111 | 159 | * @param {Object} row - the row to select |
112 | 160 | * @param {String} [mode] - "single" or "multiple" (multiple by default) |
113 | 161 | */ |
114 | this.select = function select (row, mode) { | |
115 | var rows = safeCopy; | |
162 | this.select = function select(row, mode) { | |
163 | var rows = copyRefs(displayGetter($scope)); | |
116 | 164 | var index = rows.indexOf(row); |
117 | 165 | if (index !== -1) { |
118 | 166 | if (mode === 'single') { |
133 | 181 | * @param {Number} start - start index of the slice |
134 | 182 | * @param {Number} number - the number of item in the slice |
135 | 183 | */ |
136 | this.slice = function splice (start, number) { | |
184 | this.slice = function splice(start, number) { | |
137 | 185 | tableState.pagination.start = start; |
138 | 186 | tableState.pagination.number = number; |
139 | 187 | return this.pipe(); |
143 | 191 | * return the current state of the table |
144 | 192 | * @returns {{sort: {}, search: {}, pagination: {start: number}}} |
145 | 193 | */ |
146 | this.tableState = function getTableState () { | |
194 | this.tableState = function getTableState() { | |
147 | 195 | return tableState; |
148 | 196 | }; |
149 | 197 | |
150 | this.getFilteredCollection = function getFilteredCollection () { | |
198 | this.getFilteredCollection = function getFilteredCollection() { | |
151 | 199 | return filtered || safeCopy; |
152 | 200 | }; |
153 | 201 | |
155 | 203 | * Use a different filter function than the angular FilterFilter |
156 | 204 | * @param filterName the name under which the custom filter is registered |
157 | 205 | */ |
158 | this.setFilterFunction = function setFilterFunction (filterName) { | |
206 | this.setFilterFunction = function setFilterFunction(filterName) { | |
159 | 207 | filter = $filter(filterName); |
160 | 208 | }; |
161 | 209 | |
163 | 211 | * Use a different function than the angular orderBy |
164 | 212 | * @param sortFunctionName the name under which the custom order function is registered |
165 | 213 | */ |
166 | this.setSortFunction = function setSortFunction (sortFunctionName) { | |
214 | this.setSortFunction = function setSortFunction(sortFunctionName) { | |
167 | 215 | orderBy = $filter(sortFunctionName); |
168 | 216 | }; |
169 | 217 | |
171 | 219 | * Usually when the safe copy is updated the pipe function is called. |
172 | 220 | * Calling this method will prevent it, which is something required when using a custom pipe function |
173 | 221 | */ |
174 | this.preventPipeOnWatch = function preventPipe () { | |
222 | this.preventPipeOnWatch = function preventPipe() { | |
175 | 223 | pipeAfterSafeCopy = false; |
176 | 224 | }; |
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 | }); |
0 | 0 | module.exports = { |
1 | 1 | |
2 | 2 | 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', | |
6 | 6 | 'test/init.js', |
7 | 7 | 'src/*.js', |
8 | 8 | 'test/spec/*.spec.js' |
18 | 18 | var tableState = { |
19 | 19 | sort: {}, |
20 | 20 | search: {}, |
21 | pagination: {start: 0} | |
21 | pagination: {start: 0, totalItemCount: 0} | |
22 | 22 | }; |
23 | 23 | var compile; |
24 | 24 | |
379 | 379 | expect(pages.length).toBe(0); |
380 | 380 | }); |
381 | 381 | |
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 | }); | |
382 | 412 | }); |
383 | 413 | |
384 | 414 | describe('select page', function () { |
385 | 415 | |
386 | 416 | it('should select a page', function () { |
387 | 417 | |
388 | spyOn(controllerMock, 'slice').andCallThrough(); | |
418 | spyOn(controllerMock, 'slice').and.callThrough(); | |
389 | 419 | |
390 | 420 | var template = '<table st-table="rowCollection"><tfoot><tr><td id="pagination" st-pagination=""></td></tr></tfoot></table>'; |
391 | 421 | element = compile(template)(rootScope); |
431 | 461 | |
432 | 462 | it('should call onPageChange method', function () { |
433 | 463 | rootScope.onPageChange = jasmine.createSpy('onPageChange'); |
434 | spyOn(controllerMock, 'slice').andCallThrough(); | |
464 | spyOn(controllerMock, 'slice').and.callThrough(); | |
435 | 465 | |
436 | 466 | tableState.pagination = { |
437 | 467 | start: 1, |
453 | 483 | |
454 | 484 | expect(controllerMock.slice).toHaveBeenCalledWith(20, 10); |
455 | 485 | expect(rootScope.onPageChange).toHaveBeenCalledWith(3); |
456 | expect(rootScope.onPageChange.calls.length).toBe(1); | |
486 | expect(rootScope.onPageChange.calls.count()).toBe(1); | |
457 | 487 | |
458 | 488 | }); |
459 | 489 | |
460 | 490 | it('should should not call when current page is not changed', function () { |
461 | 491 | |
462 | 492 | rootScope.onPageChange = jasmine.createSpy('onPageChange'); |
463 | spyOn(controllerMock, 'slice').andCallThrough(); | |
493 | spyOn(controllerMock, 'slice').and.callThrough(); | |
464 | 494 | |
465 | 495 | tableState.pagination = { |
466 | 496 | start: 1, |
482 | 512 | |
483 | 513 | expect(controllerMock.slice).toHaveBeenCalledWith(20, 10); |
484 | 514 | 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; | |
488 | 518 | |
489 | 519 | rootScope.$apply(); |
490 | 520 | pages = getPages(); |
491 | 521 | |
492 | 522 | expect(pages.length).toBe(5); |
493 | expect(rootScope.onPageChange.calls.length).toBe(1); | |
523 | expect(rootScope.onPageChange.calls.count()).toBe(1); | |
494 | 524 | }); |
495 | 525 | |
496 | 526 | }); |
18 | 18 | } |
19 | 19 | })); |
20 | 20 | |
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) { | |
22 | 22 | var element; |
23 | 23 | var template = '<table st-pipe="customPipe" st-table="rowCollection">' + |
24 | 24 | '<thead>' + |
27 | 27 | '<th st-sort="getters.age">age</th>' + |
28 | 28 | '</tr>' + |
29 | 29 | '</table>'; |
30 | spyOn(scope, 'customPipe').andCallThrough(); | |
30 | spyOn(scope, 'customPipe').and.callThrough(); | |
31 | 31 | |
32 | 32 | element = $compile(template)(scope); |
33 | 33 | |
34 | 34 | var ths = element.find('th'); |
35 | 35 | angular.element(ths[0]).triggerHandler('click'); |
36 | 36 | |
37 | expect(firstArg).toBe(undefined); | |
38 | expect(secondArg).toBe(undefined); | |
39 | ||
40 | $timeout.flush(); | |
41 | ||
37 | 42 | 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} | |
39 | 44 | }); |
40 | 45 | |
41 | 46 | 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} | |
43 | 48 | }); |
44 | 49 | })); |
45 | 50 | });⏎ |
30 | 30 | {name: 'Renard', firstname: 'Laurent', age: 66}, |
31 | 31 | {name: 'Francoise', firstname: 'Frere', age: 99}, |
32 | 32 | {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}, | |
34 | 133 | {name: 'Faivre', firstname: 'Blandine', age: 44} |
35 | 134 | ]; |
36 | 135 | |
53 | 152 | |
54 | 153 | element = $compile(template)(scope); |
55 | 154 | 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 | ||
92 | 173 | })); |
93 | 174 | |
94 | 175 | it('should throttle searching to 400ms by default', inject(function ($timeout) { |
117 | 198 | {name: 'Renard', firstname: 'Laurent', age: 66}, |
118 | 199 | {name: 'Francoise', firstname: 'Frere', age: 99}, |
119 | 200 | {name: 'Renard', firstname: 'Olivier', age: 33}, |
120 | {name: 'Leponge', firstname: 'Bob', age: 22}, | |
201 | {name: 'Le Blond', firstname: 'Bob', age: 22}, | |
121 | 202 | {name: 'Faivre', firstname: 'Blandine', age: 44} |
122 | 203 | ]; |
123 | 204 | |
168 | 249 | {name: 'Renard', firstname: 'Laurent', age: 66}, |
169 | 250 | {name: 'Francoise', firstname: 'Frere', age: 99}, |
170 | 251 | {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>' + | |
179 | 260 | '<th><input st-search="" /></th>' + |
180 | 261 | '<th>age</th>' + |
181 | 262 | '</tr>' + |
193 | 274 | scope.$apply(); |
194 | 275 | })); |
195 | 276 | |
196 | ||
197 | 277 | it('should support binding on search predicate', inject(function ($compile, $timeout) { |
198 | 278 | scope.searchPredicate = 'name'; |
199 | 279 | var ths = element.find('th'); |
224 | 304 | |
225 | 305 | })); |
226 | 306 | }); |
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 | }); | |
227 | 394 | }); |
4 | 4 | var element; |
5 | 5 | var tableState; |
6 | 6 | |
7 | function hasClass(element, classname) { | |
7 | function hasClass (element, classname) { | |
8 | 8 | return Array.prototype.indexOf.call(element.classList, classname) !== -1 |
9 | 9 | } |
10 | 10 | |
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) { | |
12 | 17 | return Array.prototype.map.call(trs, function (ele) { |
13 | 18 | return { |
14 | 19 | name: ele.cells[0].innerHTML, |
31 | 36 | }); |
32 | 37 | })); |
33 | 38 | |
34 | describe('customized stConfig', function() { | |
39 | describe('customized stConfig', function () { | |
35 | 40 | |
36 | 41 | beforeEach(inject(function ($compile, $rootScope, stConfig) { |
37 | 42 | var oldAscentClass = stConfig.sort.ascentClass; |
38 | 43 | var oldDescentClass = stConfig.sort.descentClass; |
44 | var oldSkipNatural = stConfig.sort.skipNatural; | |
39 | 45 | stConfig.sort.ascentClass = 'custom-ascent'; |
40 | 46 | stConfig.sort.descentClass = 'custom-descent'; |
47 | stConfig.sort.skipNatural = true; | |
41 | 48 | |
42 | 49 | rootScope = $rootScope; |
43 | 50 | scope = $rootScope.$new(); |
49 | 56 | {name: 'Faivre', firstname: 'Blandine', age: 44} |
50 | 57 | ]; |
51 | 58 | scope.getters = { |
52 | age: function ageGetter(row) { | |
59 | age: function ageGetter (row) { | |
53 | 60 | return row.name.length; |
54 | 61 | }, |
55 | name: function nameGetter(row) { | |
62 | name: function nameGetter (row) { | |
56 | 63 | return row.name.length; |
57 | 64 | } |
58 | 65 | }; |
63 | 70 | '<th st-sort="firstname">firstname</th>' + |
64 | 71 | '<th st-sort="getters.age">age</th>' + |
65 | 72 | '<th st-sort="getters.name">age</th>' + |
73 | '<th st-sort="[\'name\', \'age\']">age</th>' + | |
66 | 74 | '</tr>' + |
67 | 75 | '</thead>' + |
68 | 76 | '<tbody>' + |
80 | 88 | |
81 | 89 | stConfig.sort.ascentClass = oldAscentClass; |
82 | 90 | 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(); | |
88 | 98 | expect(hasClass(ths[1], 'custom-ascent')).toBe(true); |
89 | 99 | 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 | ||
91 | 137 | }); |
92 | 138 | |
93 | describe('normal stConfig', function() { | |
139 | describe('normal stConfig', function () { | |
94 | 140 | |
95 | 141 | beforeEach(inject(function ($compile, $rootScope) { |
96 | 142 | |
104 | 150 | {name: 'Faivre', firstname: 'Blandine', age: 44} |
105 | 151 | ]; |
106 | 152 | scope.getters = { |
107 | age: function ageGetter(row) { | |
153 | age: function ageGetter (row) { | |
108 | 154 | return row.name.length; |
109 | 155 | }, |
110 | name: function nameGetter(row) { | |
156 | name: function nameGetter (row) { | |
111 | 157 | return row.name.length; |
112 | 158 | } |
113 | 159 | }; |
133 | 179 | scope.$apply(); |
134 | 180 | })); |
135 | 181 | |
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(); | |
140 | 187 | actual = trToModel(element.find('tr.test-row')); |
141 | 188 | expect(hasClass(ths[1], 'st-sort-ascent')).toBe(true); |
142 | 189 | expect(hasClass(ths[1], 'st-sort-descent')).toBe(false); |
147 | 194 | {name: 'Renard', firstname: 'Laurent', age: 66}, |
148 | 195 | {name: 'Renard', firstname: 'Olivier', age: 33} |
149 | 196 | ]); |
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(); | |
158 | 206 | actual = trToModel(element.find('tr.test-row')); |
159 | 207 | expect(hasClass(ths[1], 'st-sort-ascent')).toBe(false); |
160 | 208 | expect(hasClass(ths[1], 'st-sort-descent')).toBe(true); |
165 | 213 | {name: 'Leponge', firstname: 'Bob', age: 22}, |
166 | 214 | {name: 'Faivre', firstname: 'Blandine', age: 44} |
167 | 215 | ]); |
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(); | |
176 | 225 | tableState.sort = { |
177 | 226 | predicate: 'firstname', |
178 | 227 | reverse: true |
179 | 228 | }; |
180 | 229 | tableState.pagination.start = 40; |
181 | 230 | angular.element(ths[1]).triggerHandler('click'); |
231 | $timeout.flush(); | |
182 | 232 | actual = trToModel(element.find('tr.test-row')); |
183 | 233 | expect(hasClass(ths[1], 'st-sort-ascent')).toBe(false); |
184 | 234 | expect(hasClass(ths[1], 'st-sort-descent')).toBe(false); |
191 | 241 | ]); |
192 | 242 | expect(tableState.sort).toEqual({}); |
193 | 243 | 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) { | |
198 | 247 | var ths = element.find('th'); |
199 | 248 | var actual; |
200 | 249 | angular.element(ths[2]).triggerHandler('click'); |
250 | $timeout.flush(); | |
201 | 251 | actual = trToModel(element.find('tr.test-row')); |
202 | 252 | expect(actual).toEqual([ |
203 | 253 | {name: 'Renard', firstname: 'Laurent', age: 66}, |
206 | 256 | {name: 'Leponge', firstname: 'Bob', age: 22}, |
207 | 257 | {name: 'Francoise', firstname: 'Frere', age: 99} |
208 | 258 | ]); |
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) { | |
213 | 262 | var ths = element.find('th'); |
214 | 263 | var actual; |
215 | 264 | angular.element(ths[2]).triggerHandler('click'); |
265 | $timeout.flush(); | |
216 | 266 | expect(hasClass(ths[2], 'st-sort-ascent')).toBe(true); |
217 | 267 | expect(hasClass(ths[3], 'st-sort-ascent')).toBe(false); |
218 | 268 | |
219 | 269 | angular.element(ths[3]).triggerHandler('click'); |
270 | $timeout.flush(); | |
220 | 271 | expect(hasClass(ths[2], 'st-sort-ascent')).toBe(false); |
221 | 272 | 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(); | |
228 | 279 | expect(hasClass(ths[1], 'st-sort-ascent')).toBe(true); |
229 | 280 | |
230 | 281 | tableState.sort = { |
235 | 286 | expect(hasClass(ths[1], 'st-sort-ascent')).toBe(false); |
236 | 287 | expect(hasClass(ths[1], 'st-sort-descent')).toBe(false); |
237 | 288 | |
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) { | |
241 | 292 | var template = '<table dummy="" st-table="rowCollection">' + |
242 | 293 | '<thead>' + |
243 | 294 | '<tr><th st-sort="name">name</th>' + |
256 | 307 | |
257 | 308 | element = $compile(template)(scope); |
258 | 309 | |
259 | scope.$apply(); | |
310 | $timeout.flush(); | |
260 | 311 | |
261 | 312 | var ths = element.find('th'); |
262 | 313 | var actual = trToModel(element.find('tr.test-row')); |
309 | 360 | |
310 | 361 | })); |
311 | 362 | |
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) { | |
313 | 364 | var template = '<table dummy="" st-table="rowCollection">' + |
314 | 365 | '<thead>' + |
315 | 366 | '<tr><th st-sort="name">name</th>' + |
328 | 379 | |
329 | 380 | element = $compile(template)(scope); |
330 | 381 | |
331 | scope.$apply(); | |
382 | $timeout.flush(); | |
332 | 383 | |
333 | 384 | var ths = element.find('th'); |
334 | 385 | var actual = trToModel(element.find('tr.test-row')); |
344 | 395 | })); |
345 | 396 | |
346 | 397 | |
347 | it('should skip natural order', inject(function ($compile) { | |
398 | it('should skip natural order', inject(function ($compile, $timeout) { | |
348 | 399 | var template = '<table dummy="" st-table="rowCollection">' + |
349 | 400 | '<thead>' + |
350 | 401 | '<tr><th>name</th>' + |
368 | 419 | var ths = element.find('th'); |
369 | 420 | var th1 = angular.element(ths[1]); |
370 | 421 | th1.triggerHandler('click'); |
422 | $timeout.flush(); | |
371 | 423 | th1.triggerHandler('click'); |
424 | $timeout.flush(); | |
372 | 425 | th1.triggerHandler('click'); |
373 | scope.$apply(); | |
426 | $timeout.flush(); | |
374 | 427 | var actual = trToModel(element.find('tr.test-row')); |
375 | 428 | expect(hasClass(ths[1], 'st-sort-ascent')).toBe(true); |
376 | 429 | expect(hasClass(ths[1], 'st-sort-descent')).toBe(false); |
382 | 435 | {name: 'Renard', firstname: 'Olivier', age: 33} |
383 | 436 | ]); |
384 | 437 | })); |
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 | ||
386 | 628 | }); |
387 | 629 | |
388 | 630 | |
389 | });⏎ | |
631 | }); |
13 | 13 | {name: 'Renard', firstname: 'Laurent', age: 66}, |
14 | 14 | {name: 'Francoise', firstname: 'Frere', age: 99}, |
15 | 15 | {name: 'Renard', firstname: 'Olivier', age: 33}, |
16 | {name: 'Leponge', firstname: 'Bob', age: 22}, | |
16 | {name: 'Le Blond', firstname: 'Bob', age: 22}, | |
17 | 17 | {name: 'Faivre', firstname: 'Blandine', age: 44} |
18 | 18 | ]; |
19 | 19 | scope = $rootScope; |
27 | 27 | |
28 | 28 | })); |
29 | 29 | |
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 | ||
30 | 46 | describe('sort', function () { |
31 | 47 | it('should sort the data', function () { |
32 | 48 | ctrl.sortBy('firstname'); |
33 | 49 | expect(scope.data).toEqual([ |
34 | 50 | {name: 'Faivre', firstname: 'Blandine', age: 44}, |
35 | {name: 'Leponge', firstname: 'Bob', age: 22}, | |
51 | {name: 'Le Blond', firstname: 'Bob', age: 22}, | |
36 | 52 | {name: 'Francoise', firstname: 'Frere', age: 99}, |
37 | 53 | {name: 'Renard', firstname: 'Laurent', age: 66}, |
38 | 54 | {name: 'Renard', firstname: 'Olivier', age: 33} |
45 | 61 | {name: 'Renard', firstname: 'Olivier', age: 33}, |
46 | 62 | {name: 'Renard', firstname: 'Laurent', age: 66}, |
47 | 63 | {name: 'Francoise', firstname: 'Frere', age: 99}, |
48 | {name: 'Leponge', firstname: 'Bob', age: 22}, | |
64 | {name: 'Le Blond', firstname: 'Bob', age: 22}, | |
49 | 65 | {name: 'Faivre', firstname: 'Blandine', age: 44} |
50 | 66 | ]); |
51 | 67 | }); |
55 | 71 | return row.firstname.length; |
56 | 72 | }); |
57 | 73 | expect(scope.data).toEqual([ |
58 | {name: 'Leponge', firstname: 'Bob', age: 22}, | |
74 | {name: 'Le Blond', firstname: 'Bob', age: 22}, | |
59 | 75 | {name: 'Francoise', firstname: 'Frere', age: 99}, |
60 | 76 | {name: 'Renard', firstname: 'Laurent', age: 66}, |
61 | 77 | {name: 'Renard', firstname: 'Olivier', age: 33}, |
69 | 85 | }); |
70 | 86 | |
71 | 87 | expect(scope.data).toEqual([ |
72 | {name: 'Leponge', firstname: 'Bob', age: 22}, | |
88 | {name: 'Le Blond', firstname: 'Bob', age: 22}, | |
73 | 89 | {name: 'Francoise', firstname: 'Frere', age: 99}, |
74 | 90 | {name: 'Renard', firstname: 'Laurent', age: 66}, |
75 | 91 | {name: 'Renard', firstname: 'Olivier', age: 33}, |
160 | 176 | ]); |
161 | 177 | }); |
162 | 178 | |
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} | |
169 | 206 | ]); |
170 | 207 | }); |
171 | 208 | }); |
190 | 227 | }); |
191 | 228 | |
192 | 229 | 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 | ||
193 | 244 | it('should remembered the last slice length but start back to zero when sorting', function () { |
194 | 245 | ctrl.slice(1, 2); |
195 | 246 | expect(scope.data.length).toBe(2); |
202 | 253 | expect(scope.data.length).toBe(2); |
203 | 254 | expect(scope.data).toEqual([ |
204 | 255 | {name: 'Faivre', firstname: 'Blandine', age: 44}, |
205 | {name: 'Leponge', firstname: 'Bob', age: 22} | |
256 | {name: 'Le Blond', firstname: 'Bob', age: 22} | |
206 | 257 | ]); |
207 | 258 | }); |
208 | 259 | |
226 | 277 | ctrl.sortBy('firstname'); |
227 | 278 | expect(scope.data).toEqual([ |
228 | 279 | {name: 'Faivre', firstname: 'Blandine', age: 44}, |
229 | {name: 'Leponge', firstname: 'Bob', age: 22}, | |
280 | {name: 'Le Blond', firstname: 'Bob', age: 22}, | |
230 | 281 | {name: 'Francoise', firstname: 'Frere', age: 99}, |
231 | 282 | {name: 'Renard', firstname: 'Laurent', age: 66}, |
232 | 283 | {name: 'Renard', firstname: 'Olivier', age: 33} |