UNPKG

746 kBJavaScriptView Raw
1(function (global, factory) {
2 typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@angular/core'), require('@ngx-translate/core'), require('rxjs'), require('rxjs/operators'), require('moment-mini'), require('text-encoding-utf-8'), require('slickgrid/plugins/slick.cellrangedecorator'), require('slickgrid/plugins/slick.cellrangeselector'), require('slickgrid/plugins/slick.cellselectionmodel'), require('flatpickr'), require('dompurify'), require('lodash.isequal'), require('jquery-ui-dist/jquery-ui'), require('slickgrid/lib/jquery.event.drag-2.3.0'), require('slickgrid/slick.core'), require('slickgrid/slick.grid'), require('slickgrid/slick.dataview'), require('@angular/common')) :
3 typeof define === 'function' && define.amd ? define('angular-slickgrid', ['exports', '@angular/core', '@ngx-translate/core', 'rxjs', 'rxjs/operators', 'moment-mini', 'text-encoding-utf-8', 'slickgrid/plugins/slick.cellrangedecorator', 'slickgrid/plugins/slick.cellrangeselector', 'slickgrid/plugins/slick.cellselectionmodel', 'flatpickr', 'dompurify', 'lodash.isequal', 'jquery-ui-dist/jquery-ui', 'slickgrid/lib/jquery.event.drag-2.3.0', 'slickgrid/slick.core', 'slickgrid/slick.grid', 'slickgrid/slick.dataview', '@angular/common'], factory) :
4 (global = global || self, factory(global['angular-slickgrid'] = {}, global.ng.core, global['ngx-translate-core'], global.rxjs, global.rxjs.operators, global.moment, global.textEncodingUtf8, null, null, null, global.flatpickr, global.dompurify, global.lodash.isequal, null, null, null, null, null, global.ng.common));
5}(this, function (exports, core, core$1, rxjs, operators, moment_, textEncodingUtf8, slick_cellrangedecorator, slick_cellrangeselector, slick_cellselectionmodel, Flatpickr, DOMPurify_, isequal_, jqueryUi, jquery_event_drag2_3_0, slick_core, slick_grid, slick_dataview, common) { 'use strict';
6
7 Flatpickr = Flatpickr && Flatpickr.hasOwnProperty('default') ? Flatpickr['default'] : Flatpickr;
8
9 /*! *****************************************************************************
10 Copyright (c) Microsoft Corporation. All rights reserved.
11 Licensed under the Apache License, Version 2.0 (the "License"); you may not use
12 this file except in compliance with the License. You may obtain a copy of the
13 License at http://www.apache.org/licenses/LICENSE-2.0
14
15 THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
17 WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
18 MERCHANTABLITY OR NON-INFRINGEMENT.
19
20 See the Apache Version 2.0 License for specific language governing permissions
21 and limitations under the License.
22 ***************************************************************************** */
23 /* global Reflect, Promise */
24
25 var extendStatics = function(d, b) {
26 extendStatics = Object.setPrototypeOf ||
27 ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
28 function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
29 return extendStatics(d, b);
30 };
31
32 function __extends(d, b) {
33 extendStatics(d, b);
34 function __() { this.constructor = d; }
35 d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
36 }
37
38 var __assign = function() {
39 __assign = Object.assign || function __assign(t) {
40 for (var s, i = 1, n = arguments.length; i < n; i++) {
41 s = arguments[i];
42 for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
43 }
44 return t;
45 };
46 return __assign.apply(this, arguments);
47 };
48
49 function __decorate(decorators, target, key, desc) {
50 var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
51 if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
52 else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
53 return c > 3 && r && Object.defineProperty(target, key, r), r;
54 }
55
56 function __param(paramIndex, decorator) {
57 return function (target, key) { decorator(target, key, paramIndex); }
58 }
59
60 function __metadata(metadataKey, metadataValue) {
61 if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(metadataKey, metadataValue);
62 }
63
64 function __awaiter(thisArg, _arguments, P, generator) {
65 return new (P || (P = Promise))(function (resolve, reject) {
66 function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
67 function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
68 function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
69 step((generator = generator.apply(thisArg, _arguments || [])).next());
70 });
71 }
72
73 function __generator(thisArg, body) {
74 var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
75 return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
76 function verb(n) { return function (v) { return step([n, v]); }; }
77 function step(op) {
78 if (f) throw new TypeError("Generator is already executing.");
79 while (_) try {
80 if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
81 if (y = 0, t) op = [op[0] & 2, t.value];
82 switch (op[0]) {
83 case 0: case 1: t = op; break;
84 case 4: _.label++; return { value: op[1], done: false };
85 case 5: _.label++; y = op[1]; op = [0]; continue;
86 case 7: op = _.ops.pop(); _.trys.pop(); continue;
87 default:
88 if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
89 if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
90 if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
91 if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
92 if (t[2]) _.ops.pop();
93 _.trys.pop(); continue;
94 }
95 op = body.call(thisArg, _);
96 } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
97 if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
98 }
99 }
100
101 function __values(o) {
102 var m = typeof Symbol === "function" && o[Symbol.iterator], i = 0;
103 if (m) return m.call(o);
104 return {
105 next: function () {
106 if (o && i >= o.length) o = void 0;
107 return { value: o && o[i++], done: !o };
108 }
109 };
110 }
111
112 function __read(o, n) {
113 var m = typeof Symbol === "function" && o[Symbol.iterator];
114 if (!m) return o;
115 var i = m.call(o), r, ar = [], e;
116 try {
117 while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
118 }
119 catch (error) { e = { error: error }; }
120 finally {
121 try {
122 if (r && !r.done && (m = i["return"])) m.call(i);
123 }
124 finally { if (e) throw e.error; }
125 }
126 return ar;
127 }
128
129 function __spread() {
130 for (var ar = [], i = 0; i < arguments.length; i++)
131 ar = ar.concat(__read(arguments[i]));
132 return ar;
133 }
134
135 (function (CaseType) {
136 /** For example: camelCase */
137 CaseType[CaseType["camelCase"] = 0] = "camelCase";
138 /** For example: PascalCase */
139 CaseType[CaseType["pascalCase"] = 1] = "pascalCase";
140 /** For example: snake_case */
141 CaseType[CaseType["snakeCase"] = 2] = "snakeCase";
142 /** For example: kebab-case */
143 CaseType[CaseType["kebabCase"] = 3] = "kebabCase";
144 })(exports.CaseType || (exports.CaseType = {}));
145
146
147 (function (DelimiterType) {
148 DelimiterType["colon"] = ":";
149 DelimiterType["comma"] = ",";
150 DelimiterType["equalSign"] = "=";
151 DelimiterType["pipe"] = "|";
152 DelimiterType["semicolon"] = ";";
153 DelimiterType["space"] = " ";
154 DelimiterType["tab"] = "\t";
155 DelimiterType["doubleColon"] = "::";
156 DelimiterType["doublePipe"] = "||";
157 DelimiterType["doubleSemicolon"] = ";;";
158 })(exports.DelimiterType || (exports.DelimiterType = {}));
159
160
161 (function (EmitterType) {
162 EmitterType["local"] = "local";
163 EmitterType["remote"] = "remote";
164 })(exports.EmitterType || (exports.EmitterType = {}));
165
166 /** List of available SlickGrid Extensions (Controls & Plugins) */
167
168 (function (ExtensionName) {
169 ExtensionName["autoTooltip"] = "autoTooltip";
170 ExtensionName["cellExternalCopyManager"] = "cellExternalCopyManager";
171 ExtensionName["checkboxSelector"] = "checkboxSelector";
172 ExtensionName["columnPicker"] = "columnPicker";
173 ExtensionName["draggableGrouping"] = "draggableGrouping";
174 ExtensionName["groupItemMetaProvider"] = "groupItemMetaProvider";
175 ExtensionName["gridMenu"] = "gridMenu";
176 ExtensionName["headerButton"] = "headerButton";
177 ExtensionName["headerMenu"] = "headerMenu";
178 ExtensionName["noname"] = "noname";
179 ExtensionName["rowDetailView"] = "rowDetailView";
180 ExtensionName["rowMoveManager"] = "rowMoveManager";
181 ExtensionName["rowSelection"] = "rowSelection";
182 })(exports.ExtensionName || (exports.ExtensionName = {}));
183
184
185 (function (FieldType) {
186 FieldType[FieldType["unknown"] = 0] = "unknown";
187 FieldType[FieldType["string"] = 1] = "string";
188 FieldType[FieldType["boolean"] = 2] = "boolean";
189 FieldType[FieldType["integer"] = 3] = "integer";
190 FieldType[FieldType["float"] = 4] = "float";
191 /** number includes Integer and Float */
192 FieldType[FieldType["number"] = 5] = "number";
193 /** new Date(), javascript Date object */
194 FieldType[FieldType["date"] = 6] = "date";
195 /** Format: 'YYYY-MM-DD' => 2001-01-01 */
196 FieldType[FieldType["dateIso"] = 7] = "dateIso";
197 /** Format: 'YYYY-MM-DDTHH:mm:ss.SSSZ' => 2001-01-01T14:00:00.123Z */
198 FieldType[FieldType["dateUtc"] = 8] = "dateUtc";
199 /** new Date(), javacript Date Object with Time */
200 FieldType[FieldType["dateTime"] = 9] = "dateTime";
201 /** Format: 'YYYY-MM-DD HH:mm:ss' => 2001-01-01 14:01:01 */
202 FieldType[FieldType["dateTimeIso"] = 10] = "dateTimeIso";
203 /** Format: 'YYYY-MM-DD h:mm:ss a' => 2001-01-01 11:01:01 pm */
204 FieldType[FieldType["dateTimeIsoAmPm"] = 11] = "dateTimeIsoAmPm";
205 /** Format: 'YYYY-MM-DD h:mm:ss A' => 2001-01-01 11:01:01 PM */
206 FieldType[FieldType["dateTimeIsoAM_PM"] = 12] = "dateTimeIsoAM_PM";
207 /** Format: 'YYYY-MM-DD HH:mm' => 2001-01-01 14:01 */
208 FieldType[FieldType["dateTimeShortIso"] = 13] = "dateTimeShortIso";
209 /** Format (Euro): 'DD/MM/YYYY' => 02/28/2001 */
210 FieldType[FieldType["dateEuro"] = 14] = "dateEuro";
211 /** Format (Euro): 'D/M/YY' => 2/28/12 */
212 FieldType[FieldType["dateEuroShort"] = 15] = "dateEuroShort";
213 /** Format (Euro): 'DD/MM/YYYY HH:mm' => 02/28/2001 13:01 */
214 FieldType[FieldType["dateTimeShortEuro"] = 16] = "dateTimeShortEuro";
215 /** Format (Euro): 'DD/MM/YYYY HH:mm:ss' => 02/28/2001 13:01:01 */
216 FieldType[FieldType["dateTimeEuro"] = 17] = "dateTimeEuro";
217 /** Format (Euro): 'DD/MM/YYYY hh:mm:ss a' => 02/28/2001 11:01:01 pm */
218 FieldType[FieldType["dateTimeEuroAmPm"] = 18] = "dateTimeEuroAmPm";
219 /** Format (Euro): 'DD/MM/YYYY hh:mm:ss A' => 02/28/2001 11:01:01 PM */
220 FieldType[FieldType["dateTimeEuroAM_PM"] = 19] = "dateTimeEuroAM_PM";
221 /** Format (Euro): 'D/M/YY H:m:s' => 2/28/14 14:1:2 */
222 FieldType[FieldType["dateTimeEuroShort"] = 20] = "dateTimeEuroShort";
223 /** Format (Euro): 'D/M/YY h:m:s a' => 2/28/14 1:2:10 pm */
224 FieldType[FieldType["dateTimeEuroShortAmPm"] = 21] = "dateTimeEuroShortAmPm";
225 /** Format (Euro): 'D/M/YY h:m:s A' => 2/28/14 14:1:1 PM */
226 FieldType[FieldType["dateTimeEuroShortAM_PM"] = 22] = "dateTimeEuroShortAM_PM";
227 /** Format: 'MM/DD/YYYY' => 02/28/2001 */
228 FieldType[FieldType["dateUs"] = 23] = "dateUs";
229 /** Format: 'M/D/YY' => 2/28/12 */
230 FieldType[FieldType["dateUsShort"] = 24] = "dateUsShort";
231 /** Format: 'MM/DD/YYYY HH:mm' => 02/28/2001 13:01 */
232 FieldType[FieldType["dateTimeShortUs"] = 25] = "dateTimeShortUs";
233 /** Format: 'MM/DD/YYYY HH:mm:ss' => 02/28/2001 13:01:01 */
234 FieldType[FieldType["dateTimeUs"] = 26] = "dateTimeUs";
235 /** Format: 'MM/DD/YYYY hh:mm:ss a' => 02/28/2001 11:01:01 pm */
236 FieldType[FieldType["dateTimeUsAmPm"] = 27] = "dateTimeUsAmPm";
237 /** Format: 'MM/DD/YYYY hh:mm:ss A' => 02/28/2001 11:01:01 PM */
238 FieldType[FieldType["dateTimeUsAM_PM"] = 28] = "dateTimeUsAM_PM";
239 /** Format: 'M/D/YY H:m:s' => 2/28/14 14:1:2 */
240 FieldType[FieldType["dateTimeUsShort"] = 29] = "dateTimeUsShort";
241 /** Format: 'M/D/YY h:m:s a' => 2/28/14 1:2:10 pm */
242 FieldType[FieldType["dateTimeUsShortAmPm"] = 30] = "dateTimeUsShortAmPm";
243 /** Format: 'M/D/YY h:m:s A' => 2/28/14 14:1:1 PM */
244 FieldType[FieldType["dateTimeUsShortAM_PM"] = 31] = "dateTimeUsShortAM_PM";
245 /** complex object with various properties */
246 FieldType[FieldType["object"] = 32] = "object";
247 })(exports.FieldType || (exports.FieldType = {}));
248
249
250 (function (FileType) {
251 FileType["csv"] = "csv";
252 FileType["doc"] = "doc";
253 FileType["docx"] = "docx";
254 FileType["pdf"] = "pdf";
255 FileType["txt"] = "txt";
256 FileType["xls"] = "xls";
257 FileType["xlsx"] = "xlsx";
258 })(exports.FileType || (exports.FileType = {}));
259
260
261 (function (FilterMultiplePassType) {
262 FilterMultiplePassType["merge"] = "merge";
263 FilterMultiplePassType["chain"] = "chain";
264 })(exports.FilterMultiplePassType || (exports.FilterMultiplePassType = {}));
265
266
267 (function (GridStateType) {
268 GridStateType["columns"] = "columns";
269 GridStateType["filter"] = "filter";
270 GridStateType["pagination"] = "pagination";
271 GridStateType["sorter"] = "sorter";
272 })(exports.GridStateType || (exports.GridStateType = {}));
273
274
275 (function (KeyCode) {
276 KeyCode[KeyCode["BACKSPACE"] = 8] = "BACKSPACE";
277 KeyCode[KeyCode["DELETE"] = 46] = "DELETE";
278 KeyCode[KeyCode["DOWN"] = 40] = "DOWN";
279 KeyCode[KeyCode["END"] = 35] = "END";
280 KeyCode[KeyCode["ENTER"] = 13] = "ENTER";
281 KeyCode[KeyCode["ESCAPE"] = 27] = "ESCAPE";
282 KeyCode[KeyCode["HOME"] = 36] = "HOME";
283 KeyCode[KeyCode["INSERT"] = 45] = "INSERT";
284 KeyCode[KeyCode["LEFT"] = 37] = "LEFT";
285 KeyCode[KeyCode["PAGE_DOWN"] = 34] = "PAGE_DOWN";
286 KeyCode[KeyCode["PAGE_UP"] = 33] = "PAGE_UP";
287 KeyCode[KeyCode["RIGHT"] = 39] = "RIGHT";
288 KeyCode[KeyCode["TAB"] = 9] = "TAB";
289 KeyCode[KeyCode["UP"] = 38] = "UP";
290 })(exports.KeyCode || (exports.KeyCode = {}));
291
292
293 (function (OperatorType) {
294 /** value is empty */
295 OperatorType["empty"] = "";
296 /** value contains x */
297 OperatorType["contains"] = "Contains";
298 /** value not contains x (inversed of contains) */
299 OperatorType["notContains"] = "Not_Contains";
300 /** value less than x */
301 OperatorType["lessThan"] = "LT";
302 /** value less than or equal to x */
303 OperatorType["lessThanOrEqual"] = "LE";
304 /** value greater than x */
305 OperatorType["greaterThan"] = "GT";
306 /** value great than or equal to x */
307 OperatorType["greaterThanOrEqual"] = "GE";
308 /** value not equal to x */
309 OperatorType["notEqual"] = "NE";
310 /** value equal to x */
311 OperatorType["equal"] = "EQ";
312 /** String ends with value */
313 OperatorType["endsWith"] = "EndsWith";
314 /** String starts with value */
315 OperatorType["startsWith"] = "StartsWith";
316 /** Find an equal match inside a collection */
317 OperatorType["in"] = "IN";
318 /** Inverse (Not In) of an equal match inside a collection */
319 OperatorType["notIn"] = "NOT_IN";
320 /**
321 * Find a substring contained inside a collection
322 * For example, this condition would return True with "IN_CONTAINS":: value='Task2,Task3', collection=['Task2','Task3']
323 * This would have returned False with "IN" because 'Task2' does not equal 'Task2,Task3'. However 'Task2' is contained in 'Task2,Task3'
324 */
325 OperatorType["inContains"] = "IN_CONTAINS";
326 /** Inversed (Not In) of substring contained inside a collection */
327 OperatorType["notInContains"] = "NOT_IN_CONTAINS";
328 })(exports.OperatorType || (exports.OperatorType = {}));
329
330
331 (function (SortDirection) {
332 SortDirection["asc"] = "asc";
333 SortDirection["ASC"] = "ASC";
334 SortDirection["desc"] = "desc";
335 SortDirection["DESC"] = "DESC";
336 })(exports.SortDirection || (exports.SortDirection = {}));
337
338
339 (function (SortDirectionNumber) {
340 SortDirectionNumber[SortDirectionNumber["asc"] = 1] = "asc";
341 SortDirectionNumber[SortDirectionNumber["desc"] = -1] = "desc";
342 SortDirectionNumber[SortDirectionNumber["neutral"] = 0] = "neutral";
343 })(exports.SortDirectionNumber || (exports.SortDirectionNumber = {}));
344
345 var AngularUtilService = /** @class */ (function () {
346 function AngularUtilService(compFactoryResolver, appRef, injector) {
347 this.compFactoryResolver = compFactoryResolver;
348 this.appRef = appRef;
349 this.injector = injector;
350 }
351 // ref https://hackernoon.com/angular-pro-tip-how-to-dynamically-create-components-in-body-ba200cc289e6
352 AngularUtilService.prototype.createAngularComponent = function (component) {
353 // Create a component reference from the component
354 var componentRef = this.compFactoryResolver
355 .resolveComponentFactory(component)
356 .create(this.injector);
357 // Attach component to the appRef so that it's inside the ng component tree
358 this.appRef.attachView(componentRef.hostView);
359 // Get DOM element from component
360 var domElem;
361 var viewRef = componentRef.hostView;
362 if (viewRef && Array.isArray(viewRef.rootNodes) && viewRef.rootNodes[0]) {
363 domElem = viewRef.rootNodes[0];
364 }
365 return { componentRef: componentRef, domElement: domElem };
366 };
367 // ref https://hackernoon.com/angular-pro-tip-how-to-dynamically-create-components-in-body-ba200cc289e6
368 AngularUtilService.prototype.createAngularComponentAppendToDom = function (component, targetElement, clearTargetContent) {
369 if (clearTargetContent === void 0) { clearTargetContent = false; }
370 var componentOutput = this.createAngularComponent(component);
371 // Append DOM element to the HTML element specified
372 if (targetElement && targetElement.appendChild) {
373 if (clearTargetContent && targetElement.innerHTML) {
374 targetElement.innerHTML = '';
375 }
376 targetElement.appendChild(componentOutput.domElement);
377 }
378 else {
379 document.body.appendChild(componentOutput.domElement); // when no target provided, we'll simply add it to the HTML Body
380 }
381 return componentOutput;
382 };
383 AngularUtilService = __decorate([
384 core.Injectable(),
385 __metadata("design:paramtypes", [core.ComponentFactoryResolver,
386 core.ApplicationRef,
387 core.Injector])
388 ], AngularUtilService);
389 return AngularUtilService;
390 }());
391
392 /** Execute the Backend Processes Callback, that could come from an Observable or a Promise callback */
393 function executeBackendProcessesCallback(startTime, processResult, backendApi, gridOptions) {
394 var endTime = new Date();
395 // define what our internal Post Process callback, only available for GraphQL Service for now
396 // it will basically refresh the Dataset & Pagination without having the user to create his own PostProcess every time
397 if (processResult && backendApi && backendApi.internalPostProcess) {
398 backendApi.internalPostProcess(processResult);
399 }
400 // send the response process to the postProcess callback
401 if (backendApi.postProcess) {
402 if (processResult instanceof Object) {
403 processResult.statistics = {
404 startTime: startTime,
405 endTime: endTime,
406 executionTime: endTime.valueOf() - startTime.valueOf(),
407 itemCount: gridOptions && gridOptions.pagination && gridOptions.pagination.totalItems,
408 totalItemCount: gridOptions && gridOptions.pagination && gridOptions.pagination.totalItems
409 };
410 }
411 backendApi.postProcess(processResult);
412 }
413 }
414 /** On a backend service api error, we will run the "onError" if there is 1 provided or just throw back the error when nothing is provided */
415 function onBackendError(e, backendApi) {
416 if (backendApi && backendApi.onError) {
417 backendApi.onError(e);
418 }
419 else {
420 throw e;
421 }
422 }
423
424 var moment = moment_; // patch to fix rollup "moment has no default export" issue, document here https://github.com/rollup/rollup/issues/670
425 /**
426 * Add an item to an array only when the item does not exists, when the item is an object we will be using their "id" to compare
427 * @param inputArray
428 * @param inputItem
429 */
430 function addToArrayWhenNotExists(inputArray, inputItem) {
431 var arrayRowIndex = -1;
432 if (typeof inputItem === 'object' && inputItem.hasOwnProperty('id')) {
433 arrayRowIndex = inputArray.findIndex(function (item) { return item.id === inputItem.id; });
434 }
435 else {
436 arrayRowIndex = inputArray.findIndex(function (item) { return item === inputItem; });
437 }
438 if (arrayRowIndex < 0) {
439 inputArray.push(inputItem);
440 }
441 }
442 /**
443 * Simple function to which will loop and create as demanded the number of white spaces,
444 * this is used in the CSV export
445 * @param int nbSpaces: number of white spaces to create
446 */
447 function addWhiteSpaces(nbSpaces) {
448 var result = '';
449 for (var i = 0; i < nbSpaces; i++) {
450 result += ' ';
451 }
452 return result;
453 }
454 /** HTML decode using jQuery with a <div>
455 * Create a in-memory div, set it's inner text(which jQuery automatically encodes)
456 * then grab the encoded contents back out. The div never exists on the page.
457 */
458 function htmlDecode(encodedStr) {
459 var parser = DOMParser && new DOMParser;
460 if (parser && parser.parseFromString) {
461 var dom = parser.parseFromString('<!doctype html><body>' + encodedStr, 'text/html');
462 return dom && dom.body && dom.body.textContent;
463 }
464 else {
465 // for some browsers that might not support DOMParser, use jQuery instead
466 return $('<div/>').html(encodedStr).text();
467 }
468 }
469 /** HTML encode using jQuery with a <div>
470 * Create a in-memory div, set it's inner text(which jQuery automatically encodes)
471 * then grab the encoded contents back out. The div never exists on the page.
472 */
473 function htmlEncode(inputValue) {
474 var entityMap = {
475 '&': '&amp;',
476 '<': '&lt;',
477 '>': '&gt;',
478 '"': '&quot;',
479 '\'': '&#39;',
480 };
481 // all symbols:: /[&<>"'`=\/]/g
482 return inputValue.replace(/[&<>"']/g, function (s) {
483 return entityMap[s];
484 });
485 }
486 /** decode text into html entity
487 * @param string text: input text
488 * @param string text: output text
489 */
490 function htmlEntityDecode(input) {
491 return input.replace(/&#(\d+);/g, function (match, dec) {
492 return String.fromCharCode(dec);
493 });
494 }
495 /** decode text into html entity
496 * @param string text: input text
497 * @param string text: output text
498 */
499 function htmlEntityEncode(input) {
500 var buf = [];
501 for (var i = input.length - 1; i >= 0; i--) {
502 buf.unshift(['&#', input[i].charCodeAt(), ';'].join(''));
503 }
504 return buf.join('');
505 }
506 /**
507 * Compares two arrays of characters to determine if all the items are equal
508 * @param a first array
509 * @param b second array to compare with a
510 * @param [orderMatters=false] flag if the order matters, if not arrays will be sorted before comparison
511 * @return boolean true if equal, else false
512 */
513 function charArraysEqual(a, b, orderMatters) {
514 if (orderMatters === void 0) { orderMatters = false; }
515 if (!Array.isArray(a) || !Array.isArray(a)) {
516 return false;
517 }
518 if (a.length !== b.length) {
519 return false;
520 }
521 if (!orderMatters) {
522 a.sort();
523 b.sort();
524 }
525 for (var i = 0; i < a.length; ++i) {
526 if (a[i] !== b[i]) {
527 return false;
528 }
529 }
530 return true;
531 }
532 /**
533 * Try casting an input of type Promise | Observable into a Promise type.
534 * @param object which could be of type Promise or Observable
535 * @param fromServiceName string representing the caller service name and will be used if we throw a casting problem error
536 */
537 function castToPromise(input, fromServiceName) {
538 if (fromServiceName === void 0) { fromServiceName = ''; }
539 var promise = input;
540 if (input instanceof Promise) {
541 // if it's already a Promise then return it
542 return input;
543 }
544 else if (input instanceof rxjs.Observable) {
545 promise = input.pipe(operators.first()).toPromise();
546 }
547 if (!(promise instanceof Promise)) {
548 throw new Error("Something went wrong, Angular-Slickgrid " + fromServiceName + " is not able to convert the Observable into a Promise.\n If you are using Angular HttpClient, you could try converting your http call to a Promise with \".toPromise()\"\n for example:: this.http.post('graphql', { query: graphqlQuery }).toPromise()\n ");
549 }
550 return promise;
551 }
552 /**
553 * Uses the logic function to find an item in an array or returns the default
554 * value provided (empty object by default)
555 * @param any[] array the array to filter
556 * @param function logic the logic to find the item
557 * @param any [defaultVal={}] the default value to return
558 * @return object the found object or default value
559 */
560 function findOrDefault(array, logic, defaultVal) {
561 if (defaultVal === void 0) { defaultVal = {}; }
562 return array.find(logic) || defaultVal;
563 }
564 /**
565 * Take a number (or a string) and display it as a formatted decimal string with defined minimum and maximum decimals
566 * @param input
567 * @param minDecimal
568 * @param maxDecimal
569 */
570 function decimalFormatted(input, minDecimal, maxDecimal) {
571 if (isNaN(+input)) {
572 return input;
573 }
574 var minDec = (minDecimal === undefined) ? 2 : minDecimal;
575 var maxDec = (maxDecimal === undefined) ? 2 : maxDecimal;
576 var amount = String(Math.round(+input * Math.pow(10, maxDec)) / Math.pow(10, maxDec));
577 if ((amount.indexOf('.') < 0) && (minDec > 0)) {
578 amount += '.';
579 }
580 while ((amount.length - amount.indexOf('.')) <= minDec) {
581 amount += '0';
582 }
583 return amount;
584 }
585 function formatNumber(input, minDecimal, maxDecimal, displayNegativeNumberWithParentheses, symbolPrefix, symbolSuffix) {
586 if (symbolPrefix === void 0) { symbolPrefix = ''; }
587 if (symbolSuffix === void 0) { symbolSuffix = ''; }
588 if (isNaN(+input)) {
589 return input;
590 }
591 var calculatedValue = ((Math.round(parseFloat(input) * 1000000) / 1000000));
592 if (calculatedValue < 0) {
593 var absValue = Math.abs(calculatedValue);
594 if (displayNegativeNumberWithParentheses) {
595 if (!isNaN(minDecimal) || !isNaN(maxDecimal)) {
596 return "(" + symbolPrefix + decimalFormatted(absValue, minDecimal, maxDecimal) + symbolSuffix + ")";
597 }
598 return "(" + symbolPrefix + absValue + symbolSuffix + ")";
599 }
600 else {
601 if (!isNaN(minDecimal) || !isNaN(maxDecimal)) {
602 return "-" + symbolPrefix + decimalFormatted(absValue, minDecimal, maxDecimal) + symbolSuffix;
603 }
604 return "-" + symbolPrefix + absValue + symbolSuffix;
605 }
606 }
607 else {
608 if (!isNaN(minDecimal) || !isNaN(maxDecimal)) {
609 return "" + symbolPrefix + decimalFormatted(input, minDecimal, maxDecimal) + symbolSuffix;
610 }
611 return "" + symbolPrefix + input + symbolSuffix;
612 }
613 }
614 /** From a dot (.) notation find and return a property within an object given a path */
615 function getDescendantProperty(obj, path) {
616 return path.split('.').reduce(function (acc, part) { return acc && acc[part]; }, obj);
617 }
618 /** Get the browser's scrollbar width, this is different to each browser */
619 function getScrollBarWidth() {
620 var $outer = $('<div>').css({ visibility: 'hidden', width: 100, overflow: 'scroll' }).appendTo('body');
621 var widthWithScroll = $('<div>').css({ width: '100%' }).appendTo($outer).outerWidth();
622 $outer.remove();
623 return Math.ceil(100 - widthWithScroll);
624 }
625 /**
626 * From a Date FieldType, return it's equivalent moment.js format
627 * refer to moment.js for the format standard used: https://momentjs.com/docs/#/parsing/string-format/
628 * @param fieldType
629 */
630 function mapMomentDateFormatWithFieldType(fieldType) {
631 var map;
632 switch (fieldType) {
633 case exports.FieldType.dateTime:
634 case exports.FieldType.dateTimeIso:
635 map = 'YYYY-MM-DD HH:mm:ss';
636 break;
637 case exports.FieldType.dateTimeShortIso:
638 map = 'YYYY-MM-DD HH:mm';
639 break;
640 case exports.FieldType.dateTimeIsoAmPm:
641 map = 'YYYY-MM-DD hh:mm:ss a';
642 break;
643 case exports.FieldType.dateTimeIsoAM_PM:
644 map = 'YYYY-MM-DD hh:mm:ss A';
645 break;
646 // all Euro Formats (date/month/year)
647 case exports.FieldType.dateEuro:
648 map = 'DD/MM/YYYY';
649 break;
650 case exports.FieldType.dateEuroShort:
651 map = 'D/M/YY';
652 break;
653 case exports.FieldType.dateTimeEuro:
654 map = 'DD/MM/YYYY HH:mm:ss';
655 break;
656 case exports.FieldType.dateTimeShortEuro:
657 map = 'DD/MM/YYYY HH:mm';
658 break;
659 case exports.FieldType.dateTimeEuroAmPm:
660 map = 'DD/MM/YYYY hh:mm:ss a';
661 break;
662 case exports.FieldType.dateTimeEuroAM_PM:
663 map = 'DD/MM/YYYY hh:mm:ss A';
664 break;
665 case exports.FieldType.dateTimeEuroShort:
666 map = 'D/M/YY H:m:s';
667 break;
668 case exports.FieldType.dateTimeEuroShortAmPm:
669 map = 'D/M/YY h:m:s a';
670 break;
671 // all US Formats (month/date/year)
672 case exports.FieldType.dateUs:
673 map = 'MM/DD/YYYY';
674 break;
675 case exports.FieldType.dateUsShort:
676 map = 'M/D/YY';
677 break;
678 case exports.FieldType.dateTimeUs:
679 map = 'MM/DD/YYYY HH:mm:ss';
680 break;
681 case exports.FieldType.dateTimeShortUs:
682 map = 'MM/DD/YYYY HH:mm';
683 break;
684 case exports.FieldType.dateTimeUsAmPm:
685 map = 'MM/DD/YYYY hh:mm:ss a';
686 break;
687 case exports.FieldType.dateTimeUsAM_PM:
688 map = 'MM/DD/YYYY hh:mm:ss A';
689 break;
690 case exports.FieldType.dateTimeUsShort:
691 map = 'M/D/YY H:m:s';
692 break;
693 case exports.FieldType.dateTimeUsShortAmPm:
694 map = 'M/D/YY h:m:s a';
695 break;
696 case exports.FieldType.dateUtc:
697 map = 'YYYY-MM-DDTHH:mm:ss.SSSZ';
698 break;
699 case exports.FieldType.date:
700 case exports.FieldType.dateIso:
701 default:
702 map = 'YYYY-MM-DD';
703 break;
704 }
705 return map;
706 }
707 /**
708 * From a Date FieldType, return it's equivalent Flatpickr format
709 * refer to Flatpickr for the format standard used: https://chmln.github.io/flatpickr/formatting/#date-formatting-tokens
710 * also note that they seem very similar to PHP format (except for am/pm): http://php.net/manual/en/function.date.php
711 * @param fieldType
712 */
713 function mapFlatpickrDateFormatWithFieldType(fieldType) {
714 /*
715 d: Day of the month, 2 digits with leading zeros 01 to 31
716 D: A textual representation of a day Mon through Sun
717 l: (lowercase 'L') A full textual representation of the day of the week Sunday through Saturday
718 j: Day of the month without leading zeros 1 to 31
719 J: Day of the month without leading zeros and ordinal suffix 1st, 2nd, to 31st
720 w: Numeric representation of the day of the week 0 (for Sunday) through 6 (for Saturday)
721 F: A full textual representation of a month January through December
722 m: Numeric representation of a month, with leading zero 01 through 12
723 n: Numeric representation of a month, without leading zeros 1 through 12
724 M: A short textual representation of a month Jan through Dec
725 U: The number of seconds since the Unix Epoch 1413704993
726 y: A two digit representation of a year 99 or 03
727 Y: A full numeric representation of a year, 4 digits 1999 or 2003
728 H: Hours (24 hours) 00 to 23
729 h: Hours 1 to 12
730 i: Minutes 00 to 59
731 S: Seconds, 2 digits 00 to 59
732 s: Seconds 0, 1 to 59
733 K: AM/PM AM or PM
734 */
735 var map;
736 switch (fieldType) {
737 case exports.FieldType.dateTime:
738 case exports.FieldType.dateTimeIso:
739 map = 'Y-m-d H:i:S';
740 break;
741 case exports.FieldType.dateTimeShortIso:
742 map = 'Y-m-d H:i';
743 break;
744 case exports.FieldType.dateTimeIsoAmPm:
745 case exports.FieldType.dateTimeIsoAM_PM:
746 map = 'Y-m-d h:i:S K'; // there is no lowercase in Flatpickr :(
747 break;
748 // all Euro Formats (date/month/year)
749 case exports.FieldType.dateEuro:
750 map = 'd/m/Y';
751 break;
752 case exports.FieldType.dateEuroShort:
753 map = 'd/m/y';
754 break;
755 case exports.FieldType.dateTimeEuro:
756 map = 'd/m/Y H:i:S';
757 break;
758 case exports.FieldType.dateTimeShortEuro:
759 map = 'd/m/y H:i';
760 break;
761 case exports.FieldType.dateTimeEuroAmPm:
762 map = 'd/m/Y h:i:S K'; // there is no lowercase in Flatpickr :(
763 break;
764 case exports.FieldType.dateTimeEuroAM_PM:
765 map = 'd/m/Y h:i:s K';
766 break;
767 case exports.FieldType.dateTimeEuroShort:
768 map = 'd/m/y H:i:s';
769 break;
770 case exports.FieldType.dateTimeEuroShortAmPm:
771 map = 'd/m/y h:i:s K'; // there is no lowercase in Flatpickr :(
772 break;
773 // all US Formats (month/date/year)
774 case exports.FieldType.dateUs:
775 map = 'm/d/Y';
776 break;
777 case exports.FieldType.dateUsShort:
778 map = 'm/d/y';
779 break;
780 case exports.FieldType.dateTimeUs:
781 map = 'm/d/Y H:i:S';
782 break;
783 case exports.FieldType.dateTimeShortUs:
784 map = 'm/d/y H:i';
785 break;
786 case exports.FieldType.dateTimeUsAmPm:
787 map = 'm/d/Y h:i:S K'; // there is no lowercase in Flatpickr :(
788 break;
789 case exports.FieldType.dateTimeUsAM_PM:
790 map = 'm/d/Y h:i:s K';
791 break;
792 case exports.FieldType.dateTimeUsShort:
793 map = 'm/d/y H:i:s';
794 break;
795 case exports.FieldType.dateTimeUsShortAmPm:
796 map = 'm/d/y h:i:s K'; // there is no lowercase in Flatpickr :(
797 break;
798 case exports.FieldType.dateUtc:
799 map = 'Z';
800 break;
801 case exports.FieldType.date:
802 case exports.FieldType.dateIso:
803 default:
804 map = 'Y-m-d';
805 break;
806 }
807 return map;
808 }
809 /**
810 * Mapper for query operators (ex.: <= is "le", > is "gt")
811 * @param string operator
812 * @returns string map
813 */
814 function mapOperatorType(operator) {
815 var map;
816 switch (operator) {
817 case '<':
818 map = exports.OperatorType.lessThan;
819 break;
820 case '<=':
821 map = exports.OperatorType.lessThanOrEqual;
822 break;
823 case '>':
824 map = exports.OperatorType.greaterThan;
825 break;
826 case '>=':
827 map = exports.OperatorType.greaterThanOrEqual;
828 break;
829 case '<>':
830 case '!=':
831 case 'neq':
832 case 'NEQ':
833 map = exports.OperatorType.notEqual;
834 break;
835 case '*':
836 case '.*':
837 case 'a*':
838 case 'startsWith':
839 case 'StartsWith':
840 map = exports.OperatorType.startsWith;
841 break;
842 case '*.':
843 case '*z':
844 case 'endsWith':
845 case 'EndsWith':
846 map = exports.OperatorType.endsWith;
847 break;
848 case '=':
849 case '==':
850 case 'eq':
851 case 'EQ':
852 map = exports.OperatorType.equal;
853 break;
854 case 'in':
855 case 'IN':
856 map = exports.OperatorType.in;
857 break;
858 case 'notIn':
859 case 'NIN':
860 case 'NOT_IN':
861 map = exports.OperatorType.notIn;
862 break;
863 case 'not_contains':
864 case 'Not_Contains':
865 case 'notContains':
866 case 'NotContains':
867 case 'NOT_CONTAINS':
868 map = exports.OperatorType.notContains;
869 break;
870 case 'Contains':
871 default:
872 map = exports.OperatorType.contains;
873 break;
874 }
875 return map;
876 }
877 /**
878 * Mapper for query operator by a Filter Type
879 * For example a multiple-select typically uses 'IN' operator
880 * @param operator
881 * @returns string map
882 */
883 function mapOperatorByFieldType(fieldType) {
884 var map;
885 switch (fieldType) {
886 case exports.FieldType.string:
887 case exports.FieldType.unknown:
888 map = exports.OperatorType.contains;
889 break;
890 case exports.FieldType.float:
891 case exports.FieldType.number:
892 case exports.FieldType.date:
893 case exports.FieldType.dateIso:
894 case exports.FieldType.date:
895 case exports.FieldType.dateUtc:
896 case exports.FieldType.dateTime:
897 case exports.FieldType.dateTimeIso:
898 case exports.FieldType.dateTimeIsoAmPm:
899 case exports.FieldType.dateTimeIsoAM_PM:
900 case exports.FieldType.dateEuro:
901 case exports.FieldType.dateEuroShort:
902 case exports.FieldType.dateTimeEuro:
903 case exports.FieldType.dateTimeEuroAmPm:
904 case exports.FieldType.dateTimeEuroAM_PM:
905 case exports.FieldType.dateTimeEuroShort:
906 case exports.FieldType.dateTimeEuroShortAmPm:
907 case exports.FieldType.dateTimeEuroShortAM_PM:
908 case exports.FieldType.dateUs:
909 case exports.FieldType.dateUsShort:
910 case exports.FieldType.dateTimeUs:
911 case exports.FieldType.dateTimeUsAmPm:
912 case exports.FieldType.dateTimeUsAM_PM:
913 case exports.FieldType.dateTimeUsShort:
914 case exports.FieldType.dateTimeUsShortAmPm:
915 case exports.FieldType.dateTimeUsShortAM_PM:
916 default:
917 map = exports.OperatorType.equal;
918 break;
919 }
920 return map;
921 }
922 /** Parse any input (bool, number, string) and return a boolean or False when not possible */
923 function parseBoolean(input) {
924 return /(true|1)/i.test(input + '');
925 }
926 /**
927 * Parse a date passed as a string (Date only, without time) and return a Date object (if valid)
928 * @param inputDateString
929 * @returns string date formatted
930 */
931 function parseUtcDate(inputDateString, useUtc) {
932 var date = null;
933 if (/^[0-9\-\/]*$/.test(inputDateString)) {
934 // get the UTC datetime with moment.js but we need to decode the value so that it's valid text
935 var dateString = decodeURIComponent(inputDateString);
936 var dateMoment = moment(new Date(dateString));
937 if (dateMoment.isValid() && dateMoment.year().toString().length === 4) {
938 date = (useUtc) ? dateMoment.utc().format() : dateMoment.format();
939 }
940 }
941 return date;
942 }
943 /**
944 * Sanitize, return only the text without HTML tags
945 * @input htmlString
946 * @return text
947 */
948 function sanitizeHtmlToText(htmlString) {
949 var temp = document.createElement('div');
950 temp.innerHTML = htmlString;
951 return temp.textContent || temp.innerText || '';
952 }
953 /**
954 * Title case (or capitalize) first char of a string
955 * Optionall title case the complete sentence (upper case first char of each word while changing everything else to lower case)
956 * @param inputStr
957 * @returns string
958 */
959 function titleCase(inputStr, caseEveryWords) {
960 if (caseEveryWords === void 0) { caseEveryWords = false; }
961 if (typeof inputStr === 'string') {
962 if (caseEveryWords) {
963 return inputStr.replace(/\w\S*/g, function (outputStr) {
964 return outputStr.charAt(0).toUpperCase() + outputStr.substr(1).toLowerCase();
965 });
966 }
967 return inputStr.charAt(0).toUpperCase() + inputStr.slice(1);
968 }
969 return inputStr;
970 }
971 /**
972 * Converts a string to camel case (camelCase)
973 * @param inputStr the string to convert
974 * @return the string in camel case
975 */
976 function toCamelCase(inputStr) {
977 if (typeof inputStr === 'string') {
978 return inputStr.replace(/(?:^\w|[A-Z]|\b\w|[\s+\-_\/])/g, function (match, offset) {
979 // remove white space or hypens or underscores
980 if (/[\s+\-_\/]/.test(match)) {
981 return '';
982 }
983 return offset === 0 ? match.toLowerCase() : match.toUpperCase();
984 });
985 }
986 return inputStr;
987 }
988 /**
989 * Converts a string to kebab (hypen) case
990 * @param str the string to convert
991 * @return the string in kebab case
992 */
993 function toKebabCase(inputStr) {
994 if (typeof inputStr === 'string') {
995 return toCamelCase(inputStr).replace(/([A-Z])/g, '-$1').toLowerCase();
996 }
997 return inputStr;
998 }
999 /**
1000 * Converts a string from camelCase to snake_case (underscore) case
1001 * @param str the string to convert
1002 * @return the string in kebab case
1003 */
1004 function toSnakeCase(inputStr) {
1005 if (typeof inputStr === 'string') {
1006 return toCamelCase(inputStr).replace(/([A-Z])/g, '_$1').toLowerCase();
1007 }
1008 return inputStr;
1009 }
1010 /**
1011 * Takes an input array and makes sure the array has unique values by removing duplicates
1012 * @param array input with possible duplicates
1013 * @param objectProperty optionally provide an object property to compare (example: 'id')
1014 * @return array output without duplicates
1015 */
1016 function uniqueArray(arr) {
1017 if (Array.isArray(arr) && arr.length > 0) {
1018 return arr.filter(function (item, index) {
1019 return arr.indexOf(item) >= index;
1020 });
1021 }
1022 return arr;
1023 }
1024 /**
1025 * Takes an input array of objects and makes sure the array has unique object values by removing duplicates
1026 * it will loop through the array using a property name (or "id" when is not provided) to compare uniqueness
1027 * @param array input with possible duplicates
1028 * @param propertyName defaults to "id"
1029 * @return array output without duplicates
1030 */
1031 function uniqueObjectArray(arr, propertyName) {
1032 if (propertyName === void 0) { propertyName = 'id'; }
1033 var e_1, _a;
1034 if (Array.isArray(arr) && arr.length > 0) {
1035 var result = [];
1036 var map = new Map();
1037 try {
1038 for (var arr_1 = __values(arr), arr_1_1 = arr_1.next(); !arr_1_1.done; arr_1_1 = arr_1.next()) {
1039 var item = arr_1_1.value;
1040 if (!map.has(item[propertyName])) {
1041 map.set(item[propertyName], true); // set any value to Map
1042 result.push({
1043 id: item[propertyName],
1044 name: item.name
1045 });
1046 }
1047 }
1048 }
1049 catch (e_1_1) { e_1 = { error: e_1_1 }; }
1050 finally {
1051 try {
1052 if (arr_1_1 && !arr_1_1.done && (_a = arr_1.return)) _a.call(arr_1);
1053 }
1054 finally { if (e_1) throw e_1.error; }
1055 }
1056 return result;
1057 }
1058 return arr;
1059 }
1060 /**
1061 * Unsubscribe all Observables Subscriptions
1062 * It will return an empty array if it all went well
1063 * @param subscriptions
1064 */
1065 function unsubscribeAllObservables(subscriptions) {
1066 if (Array.isArray(subscriptions)) {
1067 subscriptions.forEach(function (subscription) {
1068 if (subscription && subscription.unsubscribe) {
1069 subscription.unsubscribe();
1070 }
1071 });
1072 subscriptions = [];
1073 }
1074 return subscriptions;
1075 }
1076
1077 var moment$1 = moment_; // patch to fix rollup "moment has no default export" issue, document here https://github.com/rollup/rollup/issues/670
1078 function compareDates(value1, value2, format, sortDirection, strict) {
1079 var diff = 0;
1080 if (value1 === null || value1 === '' || !moment$1(value1, format, strict).isValid()) {
1081 diff = -1;
1082 }
1083 else if (value2 === null || value2 === '' || !moment$1(value2, format, strict).isValid()) {
1084 diff = 1;
1085 }
1086 else {
1087 var date1 = moment$1(value1, format, strict);
1088 var date2 = moment$1(value2, format, strict);
1089 diff = parseInt(date1.format('X'), 10) - parseInt(date2.format('X'), 10);
1090 }
1091 return sortDirection * (diff === 0 ? 0 : (diff > 0 ? 1 : -1));
1092 }
1093
1094 var FORMAT = mapMomentDateFormatWithFieldType(exports.FieldType.dateEuroShort);
1095 var dateEuroShortSorter = function (value1, value2, sortDirection) {
1096 return compareDates(value1, value2, FORMAT, sortDirection, true);
1097 };
1098
1099 var FORMAT$1 = mapMomentDateFormatWithFieldType(exports.FieldType.dateEuro);
1100 var dateEuroSorter = function (value1, value2, sortDirection) {
1101 return compareDates(value1, value2, FORMAT$1, sortDirection, true);
1102 };
1103
1104 var FORMAT$2 = mapMomentDateFormatWithFieldType(exports.FieldType.dateIso);
1105 var dateIsoSorter = function (value1, value2, sortDirection) {
1106 return compareDates(value1, value2, FORMAT$2, sortDirection, true);
1107 };
1108
1109 var moment$2 = moment_; // patch to fix rollup "moment has no default export" issue, document here https://github.com/rollup/rollup/issues/670
1110 var dateSorter = function (value1, value2, sortDirection) {
1111 return compareDates(value1, value2, moment$2.ISO_8601, sortDirection);
1112 };
1113
1114 var FORMAT$3 = mapMomentDateFormatWithFieldType(exports.FieldType.dateUsShort);
1115 var dateUsShortSorter = function (value1, value2, sortDirection) {
1116 return compareDates(value1, value2, FORMAT$3, sortDirection, true);
1117 };
1118
1119 var FORMAT$4 = mapMomentDateFormatWithFieldType(exports.FieldType.dateUs);
1120 var dateUsSorter = function (value1, value2, sortDirection) {
1121 return compareDates(value1, value2, FORMAT$4, sortDirection, true);
1122 };
1123
1124 var numericSorter = function (value1, value2, sortDirection) {
1125 var x = (isNaN(value1) || value1 === '' || value1 === null) ? -99e+10 : parseFloat(value1);
1126 var y = (isNaN(value2) || value2 === '' || value2 === null) ? -99e+10 : parseFloat(value2);
1127 return sortDirection * (x === y ? 0 : (x > y ? 1 : -1));
1128 };
1129
1130 var objectStringSorter = function (value1, value2, sortDirection, sortColumn) {
1131 if (!sortColumn || !sortColumn.dataKey) {
1132 throw new Error('Sorting a "FieldType.object" requires you to provide the "dataKey" (object property name) of the object so that we can use it to sort correctly');
1133 }
1134 var stringValue1 = value1.hasOwnProperty(sortColumn.dataKey) ? value1[sortColumn.dataKey] : value1;
1135 var stringValue2 = value2.hasOwnProperty(sortColumn.dataKey) ? value2[sortColumn.dataKey] : value2;
1136 if (sortDirection === undefined || sortDirection === null) {
1137 sortDirection = exports.SortDirectionNumber.neutral;
1138 }
1139 var position = 0;
1140 if (typeof value1 !== 'object') {
1141 position = -99e+10;
1142 }
1143 else if (typeof value2 !== 'object') {
1144 position = 99e+10;
1145 }
1146 else if (!stringValue1) {
1147 position = -1;
1148 }
1149 else if (!stringValue2) {
1150 position = 1;
1151 }
1152 else if (stringValue1 === stringValue2) {
1153 position = 0;
1154 }
1155 else if (sortDirection) {
1156 position = stringValue1 < stringValue2 ? -1 : 1;
1157 }
1158 else {
1159 position = stringValue1 < stringValue2 ? 1 : -1;
1160 }
1161 return sortDirection * position;
1162 };
1163
1164 var stringSorter = function (value1, value2, sortDirection) {
1165 if (sortDirection === undefined || sortDirection === null) {
1166 sortDirection = exports.SortDirectionNumber.neutral;
1167 }
1168 var position = 0;
1169 if (value1 === null) {
1170 position = -1;
1171 }
1172 else if (value2 === null) {
1173 position = 1;
1174 }
1175 else if (value1 === value2) {
1176 position = 0;
1177 }
1178 else if (sortDirection) {
1179 position = value1 < value2 ? -1 : 1;
1180 }
1181 else {
1182 position = value1 < value2 ? 1 : -1;
1183 }
1184 return sortDirection * position;
1185 };
1186
1187 var Sorters = {
1188 /** Sorter method to sort values by Date object type (uses Moment.js ISO_8601 standard format, optionally include time) */
1189 date: dateSorter,
1190 /**
1191 * Sorter method to sort values by Date formatted as ISO date (excluding time),
1192 * If you wish to optionally include time simply use the "Sorters.date" which work with/without time
1193 */
1194 dateIso: dateIsoSorter,
1195 /** Sorter method to sort values by Date formatted as Euro date (dd/mm/yyyy) */
1196 dateEuro: dateEuroSorter,
1197 /** Sorter method to sort values by Date formatted as Euro short date (d/m/yy) */
1198 dateEuroShort: dateEuroShortSorter,
1199 /** Sorter method to sort values by Date formatted as US date (mm/dd/yyyy) */
1200 dateUs: dateUsSorter,
1201 /** Sorter method to sort values by Date formatted as US short date (m/d/yy) */
1202 dateUsShort: dateUsShortSorter,
1203 /** Sorter method to sort values as numeric fields */
1204 numeric: numericSorter,
1205 /**
1206 * Sorter method to sort object values with a "dataKey" provided in your column definition, it's data content must be of type string
1207 * Example:
1208 * columnDef = { id='user', field: 'user', ..., dataKey: 'firstName', sorter: Sorters.objectString }
1209 * collection = [{ firstName: 'John', lastName: 'Doe' }, { firstName: 'Bob', lastName: 'Cash' }]
1210 */
1211 objectString: objectStringSorter,
1212 /** Sorter method to sort values as regular strings */
1213 string: stringSorter
1214 };
1215
1216 function sortByFieldType(value1, value2, fieldType, sortDirection, sortColumn) {
1217 var sortResult = 0;
1218 switch (fieldType) {
1219 case exports.FieldType.number:
1220 sortResult = Sorters.numeric(value1, value2, sortDirection);
1221 break;
1222 case exports.FieldType.date:
1223 sortResult = Sorters.date(value1, value2, sortDirection);
1224 break;
1225 case exports.FieldType.dateIso:
1226 sortResult = Sorters.dateIso(value1, value2, sortDirection);
1227 break;
1228 // all Euro Formats (date/month/year)
1229 case exports.FieldType.dateEuro:
1230 sortResult = Sorters.dateEuro(value1, value2, sortDirection);
1231 break;
1232 case exports.FieldType.dateEuroShort:
1233 sortResult = Sorters.dateEuroShort(value1, value2, sortDirection);
1234 break;
1235 // all US Formats (month/date/year)
1236 case exports.FieldType.dateUs:
1237 sortResult = Sorters.dateUs(value1, value2, sortDirection);
1238 break;
1239 case exports.FieldType.dateUsShort:
1240 sortResult = Sorters.dateUsShort(value1, value2, sortDirection);
1241 break;
1242 case exports.FieldType.object:
1243 sortResult = Sorters.objectString(value1, value2, sortDirection, sortColumn);
1244 break;
1245 default:
1246 sortResult = Sorters.string(value1, value2, sortDirection);
1247 break;
1248 }
1249 return sortResult;
1250 }
1251
1252 var CollectionService = /** @class */ (function () {
1253 function CollectionService(translate) {
1254 this.translate = translate;
1255 }
1256 /**
1257 * Filter 1 or more items from a collection
1258 * @param collection
1259 * @param filterByOptions
1260 */
1261 CollectionService.prototype.filterCollection = function (collection, filterByOptions, filterResultBy) {
1262 if (filterResultBy === void 0) { filterResultBy = exports.FilterMultiplePassType.chain; }
1263 var e_1, _a;
1264 var filteredCollection = [];
1265 // when it's array, we will use the new filtered collection after every pass
1266 // basically if input collection has 10 items on 1st pass and 1 item is filtered out, then on 2nd pass the input collection will be 9 items
1267 if (Array.isArray(filterByOptions)) {
1268 filteredCollection = (filterResultBy === exports.FilterMultiplePassType.merge) ? [] : collection;
1269 try {
1270 for (var filterByOptions_1 = __values(filterByOptions), filterByOptions_1_1 = filterByOptions_1.next(); !filterByOptions_1_1.done; filterByOptions_1_1 = filterByOptions_1.next()) {
1271 var filter = filterByOptions_1_1.value;
1272 if (filterResultBy === exports.FilterMultiplePassType.merge) {
1273 var filteredPass = this.singleFilterCollection(collection, filter);
1274 filteredCollection = uniqueArray(__spread(filteredCollection, filteredPass));
1275 }
1276 else {
1277 filteredCollection = this.singleFilterCollection(filteredCollection, filter);
1278 }
1279 }
1280 }
1281 catch (e_1_1) { e_1 = { error: e_1_1 }; }
1282 finally {
1283 try {
1284 if (filterByOptions_1_1 && !filterByOptions_1_1.done && (_a = filterByOptions_1.return)) _a.call(filterByOptions_1);
1285 }
1286 finally { if (e_1) throw e_1.error; }
1287 }
1288 }
1289 else {
1290 filteredCollection = this.singleFilterCollection(collection, filterByOptions);
1291 }
1292 return filteredCollection;
1293 };
1294 /**
1295 * Filter an item from a collection
1296 * @param collection
1297 * @param filterBy
1298 */
1299 CollectionService.prototype.singleFilterCollection = function (collection, filterBy) {
1300 var filteredCollection = [];
1301 if (filterBy && filterBy.property) {
1302 var property_1 = filterBy.property;
1303 var operator = filterBy.operator || exports.OperatorType.equal;
1304 // just check for undefined since the filter value could be null, 0, '', false etc
1305 var value_1 = typeof filterBy.value === 'undefined' ? '' : filterBy.value;
1306 switch (operator) {
1307 case exports.OperatorType.equal:
1308 filteredCollection = collection.filter(function (item) { return item[property_1] === value_1; });
1309 break;
1310 case exports.OperatorType.contains:
1311 filteredCollection = collection.filter(function (item) { return item[property_1].toString().indexOf(value_1.toString()) !== -1; });
1312 break;
1313 case exports.OperatorType.notContains:
1314 filteredCollection = collection.filter(function (item) { return item[property_1].toString().indexOf(value_1.toString()) === -1; });
1315 break;
1316 case exports.OperatorType.notEqual:
1317 default:
1318 filteredCollection = collection.filter(function (item) { return item[property_1] !== value_1; });
1319 }
1320 }
1321 return filteredCollection;
1322 };
1323 /**
1324 * Sort 1 or more items in a collection
1325 * @param column definition
1326 * @param collection
1327 * @param sortByOptions
1328 * @param enableTranslateLabel
1329 */
1330 CollectionService.prototype.sortCollection = function (columnDef, collection, sortByOptions, enableTranslateLabel) {
1331 var _this = this;
1332 var sortedCollection = [];
1333 if (sortByOptions) {
1334 if (Array.isArray(sortByOptions)) {
1335 // multi-sort
1336 sortedCollection = collection.sort(function (dataRow1, dataRow2) {
1337 for (var i = 0, l = sortByOptions.length; i < l; i++) {
1338 var sortBy = sortByOptions[i];
1339 if (sortBy && sortBy.property) {
1340 var sortDirection = sortBy.sortDesc ? exports.SortDirectionNumber.desc : exports.SortDirectionNumber.asc;
1341 var propertyName = sortBy.property;
1342 var fieldType = sortBy.fieldType || exports.FieldType.string;
1343 var value1 = (enableTranslateLabel) ? _this.translate.instant(dataRow1[propertyName] || ' ') : dataRow1[propertyName];
1344 var value2 = (enableTranslateLabel) ? _this.translate.instant(dataRow2[propertyName] || ' ') : dataRow2[propertyName];
1345 var sortResult = sortByFieldType(value1, value2, fieldType, sortDirection, columnDef);
1346 if (sortResult !== exports.SortDirectionNumber.neutral) {
1347 return sortResult;
1348 }
1349 }
1350 }
1351 return exports.SortDirectionNumber.neutral;
1352 });
1353 }
1354 else if (sortByOptions && sortByOptions.property) {
1355 // single sort
1356 var propertyName_1 = sortByOptions.property;
1357 var sortDirection_1 = sortByOptions.sortDesc ? exports.SortDirectionNumber.desc : exports.SortDirectionNumber.asc;
1358 var fieldType_1 = sortByOptions.fieldType || exports.FieldType.string;
1359 sortedCollection = collection.sort(function (dataRow1, dataRow2) {
1360 var value1 = (enableTranslateLabel) ? _this.translate.instant(dataRow1[propertyName_1] || ' ') : dataRow1[propertyName_1];
1361 var value2 = (enableTranslateLabel) ? _this.translate.instant(dataRow2[propertyName_1] || ' ') : dataRow2[propertyName_1];
1362 var sortResult = sortByFieldType(value1, value2, fieldType_1, sortDirection_1, columnDef);
1363 if (sortResult !== exports.SortDirectionNumber.neutral) {
1364 return sortResult;
1365 }
1366 return exports.SortDirectionNumber.neutral;
1367 });
1368 }
1369 else if (sortByOptions && !sortByOptions.property) {
1370 var sortDirection_2 = sortByOptions.sortDesc ? exports.SortDirectionNumber.desc : exports.SortDirectionNumber.asc;
1371 var fieldType_2 = sortByOptions.fieldType || exports.FieldType.string;
1372 sortedCollection = collection.sort(function (dataRow1, dataRow2) {
1373 var value1 = (enableTranslateLabel) ? _this.translate.instant(dataRow1 || ' ') : dataRow1;
1374 var value2 = (enableTranslateLabel) ? _this.translate.instant(dataRow2 || ' ') : dataRow2;
1375 var sortResult = sortByFieldType(value1, value2, fieldType_2, sortDirection_2, columnDef);
1376 if (sortResult !== exports.SortDirectionNumber.neutral) {
1377 return sortResult;
1378 }
1379 return exports.SortDirectionNumber.neutral;
1380 });
1381 }
1382 }
1383 return sortedCollection;
1384 };
1385 CollectionService = __decorate([
1386 core.Injectable(),
1387 __metadata("design:paramtypes", [core$1.TranslateService])
1388 ], CollectionService);
1389 return CollectionService;
1390 }());
1391
1392 var ExportService = /** @class */ (function () {
1393 function ExportService(translate) {
1394 this.translate = translate;
1395 this._lineCarriageReturn = '\n';
1396 this._hasGroupedItems = false;
1397 this.onGridBeforeExportToFile = new rxjs.Subject();
1398 this.onGridAfterExportToFile = new rxjs.Subject();
1399 }
1400 Object.defineProperty(ExportService.prototype, "datasetIdName", {
1401 get: function () {
1402 return this._gridOptions && this._gridOptions.datasetIdPropertyName || 'id';
1403 },
1404 enumerable: true,
1405 configurable: true
1406 });
1407 Object.defineProperty(ExportService.prototype, "_gridOptions", {
1408 /** Getter for the Grid Options pulled through the Grid Object */
1409 get: function () {
1410 return (this._grid && this._grid.getOptions) ? this._grid.getOptions() : {};
1411 },
1412 enumerable: true,
1413 configurable: true
1414 });
1415 /**
1416 * Initialize the Export Service
1417 * @param grid
1418 * @param gridOptions
1419 * @param dataView
1420 */
1421 ExportService.prototype.init = function (grid, dataView) {
1422 this._grid = grid;
1423 this._dataView = dataView;
1424 };
1425 /**
1426 * Function to export the Grid result to an Excel CSV format using javascript for it to produce the CSV file.
1427 * This is a WYSIWYG export to file output (What You See is What You Get)
1428 *
1429 * NOTES: The column position needs to match perfectly the JSON Object position because of the way we are pulling the data,
1430 * which means that if any column(s) got moved in the UI, it has to be reflected in the JSON array output as well
1431 *
1432 * Example: exportToFile({ format: FileType.csv, delimiter: DelimiterType.comma })
1433 */
1434 ExportService.prototype.exportToFile = function (options) {
1435 var _this = this;
1436 this.onGridBeforeExportToFile.next(true);
1437 this._exportOptions = $.extend(true, {}, this._gridOptions.exportOptions, options);
1438 // get the CSV output from the grid data
1439 var dataOutput = this.getDataOutput();
1440 // trigger a download file
1441 // wrap it into a setTimeout so that the EventAggregator has enough time to start a pre-process like showing a spinner
1442 setTimeout(function () {
1443 var downloadOptions = {
1444 filename: _this._exportOptions.filename + "." + _this._exportOptions.format,
1445 csvContent: dataOutput,
1446 format: _this._exportOptions.format,
1447 useUtf8WithBom: _this._exportOptions.useUtf8WithBom
1448 };
1449 _this.startDownloadFile(downloadOptions);
1450 _this.onGridAfterExportToFile.next({ options: downloadOptions });
1451 }, 0);
1452 };
1453 // -----------------------
1454 // Private functions
1455 // -----------------------
1456 ExportService.prototype.getDataOutput = function () {
1457 var _this = this;
1458 var columns = this._grid.getColumns() || [];
1459 var delimiter = this._exportOptions.delimiter || '';
1460 var format = this._exportOptions.format || '';
1461 var groupByColumnHeader = this._exportOptions.groupingColumnHeaderTitle || this.translate.instant('GROUP_BY');
1462 // a CSV needs double quotes wrapper, the other types do not need any wrapper
1463 this._exportQuoteWrapper = (format === exports.FileType.csv) ? '"' : '';
1464 // data variable which will hold all the fields data of a row
1465 var outputDataString = '';
1466 // get grouped column titles and if found, we will add a "Group by" column at the first column index
1467 var grouping = this._dataView.getGrouping();
1468 if (grouping && Array.isArray(grouping) && grouping.length > 0) {
1469 this._hasGroupedItems = true;
1470 outputDataString += "" + groupByColumnHeader + delimiter;
1471 }
1472 else {
1473 this._hasGroupedItems = false;
1474 }
1475 // get all column headers
1476 this._columnHeaders = this.getColumnHeaders(columns) || [];
1477 if (this._columnHeaders && Array.isArray(this._columnHeaders) && this._columnHeaders.length > 0) {
1478 // add the header row + add a new line at the end of the row
1479 var outputHeaderTitles = this._columnHeaders.map(function (header) {
1480 return _this._exportQuoteWrapper + header.title + _this._exportQuoteWrapper;
1481 });
1482 outputDataString += (outputHeaderTitles.join(delimiter) + this._lineCarriageReturn);
1483 }
1484 // Populate the rest of the Grid Data
1485 outputDataString += this.getAllGridRowData(columns, this._lineCarriageReturn);
1486 return outputDataString;
1487 };
1488 /**
1489 * Get all the grid row data and return that as an output string
1490 */
1491 ExportService.prototype.getAllGridRowData = function (columns, lineCarriageReturn) {
1492 var outputDataStrings = [];
1493 var lineCount = this._dataView.getLength();
1494 // loop through all the grid rows of data
1495 for (var rowNumber = 0; rowNumber < lineCount; rowNumber++) {
1496 var itemObj = this._dataView.getItem(rowNumber);
1497 if (itemObj != null) {
1498 // Normal row (not grouped by anything) would have an ID which was predefined in the Grid Columns definition
1499 if (itemObj[this.datasetIdName] != null) {
1500 // get regular row item data
1501 outputDataStrings.push(this.readRegularRowData(columns, rowNumber, itemObj));
1502 }
1503 else if (this._hasGroupedItems && itemObj.__groupTotals === undefined) {
1504 // get the group row
1505 outputDataStrings.push(this.readGroupedTitleRow(itemObj));
1506 }
1507 else if (itemObj.__groupTotals) {
1508 // else if the row is a Group By and we have agreggators, then a property of '__groupTotals' would exist under that object
1509 outputDataStrings.push(this.readGroupedTotalRow(columns, itemObj));
1510 }
1511 }
1512 }
1513 return outputDataStrings.join(this._lineCarriageReturn);
1514 };
1515 /**
1516 * Get all header titles and their keys, translate the title when required.
1517 * @param columns of the grid
1518 */
1519 ExportService.prototype.getColumnHeaders = function (columns) {
1520 var _this = this;
1521 if (!columns || !Array.isArray(columns) || columns.length === 0) {
1522 return null;
1523 }
1524 var columnHeaders = [];
1525 // Populate the Column Header, pull the name defined
1526 columns.forEach(function (columnDef) {
1527 var fieldName = (columnDef.headerKey) ? _this.translate.instant(columnDef.headerKey) : columnDef.name;
1528 var skippedField = columnDef.excludeFromExport || false;
1529 // if column width is 0 then it's not evaluated since that field is considered hidden should not be part of the export
1530 if ((columnDef.width === undefined || columnDef.width > 0) && !skippedField) {
1531 columnHeaders.push({
1532 key: columnDef.field || columnDef.id,
1533 title: fieldName
1534 });
1535 }
1536 });
1537 return columnHeaders;
1538 };
1539 /**
1540 * Get the data of a regular row (a row without grouping)
1541 * @param row
1542 * @param itemObj
1543 */
1544 ExportService.prototype.readRegularRowData = function (columns, row, itemObj) {
1545 var idx = 0;
1546 var rowOutputStrings = [];
1547 var delimiter = this._exportOptions.delimiter;
1548 var format = this._exportOptions.format;
1549 var exportQuoteWrapper = this._exportQuoteWrapper || '';
1550 for (var col = 0, ln = columns.length; col < ln; col++) {
1551 var columnDef = columns[col];
1552 var fieldId = columnDef.field || columnDef.id || '';
1553 // skip excluded column
1554 if (columnDef.excludeFromExport) {
1555 continue;
1556 }
1557 // if we are grouping and are on 1st column index, we need to skip this column since it will be used later by the grouping text:: Group by [columnX]
1558 if (this._hasGroupedItems && idx === 0) {
1559 rowOutputStrings.push("\"\"");
1560 }
1561 // does the user want to evaluate current column Formatter?
1562 var isEvaluatingFormatter = (columnDef.exportWithFormatter !== undefined) ? columnDef.exportWithFormatter : this._exportOptions.exportWithFormatter;
1563 // did the user provide a Custom Formatter for the export
1564 var exportCustomFormatter = (columnDef.exportCustomFormatter !== undefined) ? columnDef.exportCustomFormatter : undefined;
1565 var itemData = '';
1566 if (itemObj && itemObj[fieldId] && exportCustomFormatter !== undefined && exportCustomFormatter !== null) {
1567 var formattedData = exportCustomFormatter(row, col, itemObj[fieldId], columnDef, itemObj, this._grid);
1568 itemData = formattedData;
1569 if (formattedData && typeof formattedData === 'object' && formattedData.hasOwnProperty('text')) {
1570 itemData = formattedData.text;
1571 }
1572 if (itemData === null) {
1573 itemData = '';
1574 }
1575 }
1576 else if (isEvaluatingFormatter && columnDef.formatter !== undefined && columnDef.formatter !== null) {
1577 var formattedData = columnDef.formatter(row, col, itemObj[fieldId], columnDef, itemObj, this._grid);
1578 itemData = formattedData;
1579 if (formattedData && typeof formattedData === 'object' && formattedData.hasOwnProperty('text')) {
1580 itemData = formattedData.text;
1581 }
1582 if (itemData === null) {
1583 itemData = '';
1584 }
1585 }
1586 else {
1587 itemData = (itemObj[fieldId] === null || itemObj[fieldId] === undefined) ? '' : itemObj[fieldId];
1588 if (itemData === null) {
1589 itemData = '';
1590 }
1591 }
1592 // does the user want to sanitize the output data (remove HTML tags)?
1593 if (columnDef.sanitizeDataExport || this._exportOptions.sanitizeDataExport) {
1594 itemData = sanitizeHtmlToText(itemData);
1595 }
1596 // when CSV we also need to escape double quotes twice, so " becomes ""
1597 if (format === exports.FileType.csv && itemData) {
1598 itemData = itemData.toString().replace(/"/gi, "\"\"");
1599 }
1600 // do we have a wrapper to keep as a string? in certain cases like "1E06", we don't want excel to transform it into exponential (1.0E06)
1601 // to cancel that effect we can had = in front, ex: ="1E06"
1602 var keepAsStringWrapper = (columnDef && columnDef.exportCsvForceToKeepAsString) ? '=' : '';
1603 rowOutputStrings.push(keepAsStringWrapper + exportQuoteWrapper + itemData + exportQuoteWrapper);
1604 idx++;
1605 }
1606 return rowOutputStrings.join(delimiter);
1607 };
1608 /**
1609 * Get the grouped title(s), for example if we grouped by salesRep, the returned result would be:: 'Sales Rep'
1610 * @param itemObj
1611 */
1612 ExportService.prototype.readGroupedTitleRow = function (itemObj) {
1613 var groupName = sanitizeHtmlToText(itemObj.title);
1614 var exportQuoteWrapper = this._exportQuoteWrapper || '';
1615 var format = this._exportOptions.format;
1616 groupName = addWhiteSpaces(5 * itemObj.level) + groupName;
1617 if (format === exports.FileType.csv) {
1618 // when CSV we also need to escape double quotes twice, so " becomes ""
1619 groupName = groupName.toString().replace(/"/gi, "\"\"");
1620 }
1621 return exportQuoteWrapper + ' ' + groupName + exportQuoteWrapper;
1622 };
1623 /**
1624 * Get the grouped totals, these are set by Slick Aggregators.
1625 * For example if we grouped by "salesRep" and we have a Sum Aggregator on "sales", then the returned output would be:: ["Sum 123$"]
1626 * @param itemObj
1627 */
1628 ExportService.prototype.readGroupedTotalRow = function (columns, itemObj) {
1629 var _this = this;
1630 var delimiter = this._exportOptions.delimiter;
1631 var format = this._exportOptions.format;
1632 var groupingAggregatorRowText = this._exportOptions.groupingAggregatorRowText || '';
1633 var exportQuoteWrapper = this._exportQuoteWrapper || '';
1634 var outputStrings = ["" + exportQuoteWrapper + groupingAggregatorRowText + exportQuoteWrapper];
1635 columns.forEach(function (columnDef) {
1636 var itemData = '';
1637 // if there's a groupTotalsFormatter, we will re-run it to get the exact same output as what is shown in UI
1638 if (columnDef.groupTotalsFormatter) {
1639 itemData = columnDef.groupTotalsFormatter(itemObj, columnDef);
1640 }
1641 // does the user want to sanitize the output data (remove HTML tags)?
1642 if (columnDef.sanitizeDataExport || _this._exportOptions.sanitizeDataExport) {
1643 itemData = sanitizeHtmlToText(itemData);
1644 }
1645 if (format === exports.FileType.csv) {
1646 // when CSV we also need to escape double quotes twice, so a double quote " becomes 2x double quotes ""
1647 itemData = itemData.toString().replace(/"/gi, "\"\"");
1648 }
1649 outputStrings.push(exportQuoteWrapper + itemData + exportQuoteWrapper);
1650 });
1651 return outputStrings.join(delimiter);
1652 };
1653 /**
1654 * Triggers download file with file format.
1655 * IE(6-10) are not supported
1656 * All other browsers will use plain javascript on client side to produce a file download.
1657 * @param options
1658 */
1659 ExportService.prototype.startDownloadFile = function (options) {
1660 // IE(6-10) don't support javascript download and our service doesn't support either so throw an error, we have to make a round trip to the Web Server for exporting
1661 if (navigator.appName === 'Microsoft Internet Explorer') {
1662 throw new Error('Microsoft Internet Explorer 6 to 10 do not support javascript export to CSV. Please upgrade your browser.');
1663 }
1664 // set the correct MIME type
1665 var mimeType = (options.format === exports.FileType.csv) ? 'text/csv' : 'text/plain';
1666 // make sure no html entities exist in the data
1667 var csvContent = htmlEntityDecode(options.csvContent);
1668 // dealing with Excel CSV export and UTF-8 is a little tricky.. We will use Option #2 to cover older Excel versions
1669 // Option #1: we need to make Excel knowing that it's dealing with an UTF-8, A correctly formatted UTF8 file can have a Byte Order Mark as its first three octets
1670 // reference: http://stackoverflow.com/questions/155097/microsoft-excel-mangles-diacritics-in-csv-files
1671 // Option#2: use a 3rd party extension to javascript encode into UTF-16
1672 var outputData;
1673 if (options.format === exports.FileType.csv) {
1674 outputData = new textEncodingUtf8.TextEncoder('utf-8').encode(csvContent);
1675 }
1676 else {
1677 outputData = csvContent;
1678 }
1679 // create a Blob object for the download
1680 var blob = new Blob([options.useUtf8WithBom ? '\uFEFF' : '', outputData], {
1681 type: mimeType + ";charset=utf-8;"
1682 });
1683 // when using IE/Edge, then use different download call
1684 if (typeof navigator.msSaveOrOpenBlob === 'function') {
1685 navigator.msSaveOrOpenBlob(blob, options.filename);
1686 }
1687 else {
1688 // this trick will generate a temp <a /> tag
1689 // the code will then trigger a hidden click for it to start downloading
1690 var link = document.createElement('a');
1691 var csvUrl = URL.createObjectURL(blob);
1692 link.textContent = 'download';
1693 link.href = csvUrl;
1694 link.setAttribute('download', options.filename);
1695 // set the visibility to hidden so there is no effect on your web-layout
1696 link.style.visibility = 'hidden';
1697 // this part will append the anchor tag, trigger a click (for download to start) and finally remove the tag once completed
1698 document.body.appendChild(link);
1699 link.click();
1700 document.body.removeChild(link);
1701 }
1702 };
1703 ExportService = __decorate([
1704 core.Injectable(),
1705 __metadata("design:paramtypes", [core$1.TranslateService])
1706 ], ExportService);
1707 return ExportService;
1708 }());
1709
1710 var Constants = /** @class */ (function () {
1711 function Constants() {
1712 }
1713 Constants.TEXT_CANCEL = 'Cancel';
1714 Constants.TEXT_CLEAR_ALL_FILTERS = 'Clear All Filters';
1715 Constants.TEXT_CLEAR_ALL_SORTING = 'Clear All Sorting';
1716 Constants.TEXT_COLUMNS = 'Columns';
1717 Constants.TEXT_COMMANDS = 'Commands';
1718 Constants.TEXT_EXPORT_IN_CSV_FORMAT = 'Export in CSV format';
1719 Constants.TEXT_EXPORT_IN_TEXT_FORMAT = 'Export in Text format (Tab delimited)';
1720 Constants.TEXT_FORCE_FIT_COLUMNS = 'Force fit columns';
1721 Constants.TEXT_HIDE_COLUMN = 'Hide Column';
1722 Constants.TEXT_REFRESH_DATASET = 'Refresh Dataset';
1723 Constants.TEXT_REMOVE_FILTER = 'Remove Filter';
1724 Constants.TEXT_REMOVE_SORT = 'Remove Sort';
1725 Constants.TEXT_SAVE = 'Save';
1726 Constants.TEXT_SYNCHRONOUS_RESIZE = 'Synchronous resize';
1727 Constants.TEXT_SORT_ASCENDING = 'Sort Ascending';
1728 Constants.TEXT_SORT_DESCENDING = 'Sort Descending';
1729 Constants.TEXT_TOGGLE_FILTER_ROW = 'Toggle Filter Row';
1730 Constants.TEXT_TOGGLE_PRE_HEADER_ROW = 'Toggle Pre-Header Row';
1731 Constants.VALIDATION_REQUIRED_FIELD = 'Field is required';
1732 Constants.VALIDATION_EDITOR_VALID_NUMBER = 'Please enter a valid number';
1733 Constants.VALIDATION_EDITOR_VALID_INTEGER = 'Please enter a valid integer number';
1734 Constants.VALIDATION_EDITOR_INTEGER_BETWEEN = 'Please enter a valid integer number between {{minValue}} and {{maxValue}}';
1735 Constants.VALIDATION_EDITOR_INTEGER_MAX = 'Please enter a valid integer number that is lower than {{maxValue}}';
1736 Constants.VALIDATION_EDITOR_INTEGER_MIN = 'Please enter a valid integer number that is greater than {{minValue}}';
1737 Constants.VALIDATION_EDITOR_NUMBER_BETWEEN = 'Please enter a valid number between {{minValue}} and {{maxValue}}';
1738 Constants.VALIDATION_EDITOR_NUMBER_MAX = 'Please enter a valid number that is lower than {{maxValue}}';
1739 Constants.VALIDATION_EDITOR_NUMBER_MIN = 'Please enter a valid number that is greater than {{minValue}}';
1740 Constants.VALIDATION_EDITOR_DECIMAL_BETWEEN = 'Please enter a valid number with a maximum of {{maxDecimal}} decimals';
1741 return Constants;
1742 }());
1743
1744 var SharedService = /** @class */ (function () {
1745 function SharedService() {
1746 }
1747 Object.defineProperty(SharedService.prototype, "allColumns", {
1748 // --
1749 // public
1750 /** Getter for All Columns in the grid (hidden/visible) */
1751 get: function () {
1752 return this._allColumns;
1753 },
1754 /** Setter for All Columns in the grid (hidden/visible) */
1755 set: function (allColumns) {
1756 this._allColumns = allColumns;
1757 },
1758 enumerable: true,
1759 configurable: true
1760 });
1761 Object.defineProperty(SharedService.prototype, "columnDefinitions", {
1762 /** Getter for the Column Definitions pulled through the Grid Object */
1763 get: function () {
1764 return (this._grid && this._grid.getColumns) ? this._grid.getColumns() : [];
1765 },
1766 enumerable: true,
1767 configurable: true
1768 });
1769 Object.defineProperty(SharedService.prototype, "dataView", {
1770 /** Getter for SlickGrid DataView object */
1771 get: function () {
1772 return this._dataView;
1773 },
1774 /** Setter for SlickGrid DataView object */
1775 set: function (dataView) {
1776 this._dataView = dataView;
1777 },
1778 enumerable: true,
1779 configurable: true
1780 });
1781 Object.defineProperty(SharedService.prototype, "grid", {
1782 /** Getter for SlickGrid Grid object */
1783 get: function () {
1784 return this._grid;
1785 },
1786 /** Setter for SlickGrid Grid object */
1787 set: function (grid) {
1788 this._grid = grid;
1789 },
1790 enumerable: true,
1791 configurable: true
1792 });
1793 Object.defineProperty(SharedService.prototype, "gridOptions", {
1794 /** Getter for the Grid Options pulled through the Grid Object */
1795 get: function () {
1796 return this._gridOptions || this._grid && this._grid.getOptions && this._grid.getOptions() || {};
1797 },
1798 /** Setter for the Grid Options pulled through the Grid Object */
1799 set: function (gridOptions) {
1800 this._gridOptions = gridOptions;
1801 },
1802 enumerable: true,
1803 configurable: true
1804 });
1805 Object.defineProperty(SharedService.prototype, "groupItemMetadataProvider", {
1806 /** Getter for the Grid Options */
1807 get: function () {
1808 return this._groupItemMetadataProvider;
1809 },
1810 /** Setter for the Grid Options */
1811 set: function (groupItemMetadataProvider) {
1812 this._groupItemMetadataProvider = groupItemMetadataProvider;
1813 },
1814 enumerable: true,
1815 configurable: true
1816 });
1817 Object.defineProperty(SharedService.prototype, "visibleColumns", {
1818 /** Getter for the Visible Columns in the grid */
1819 get: function () {
1820 return this._visibleColumns;
1821 },
1822 /** Setter for the Visible Columns in the grid */
1823 set: function (visibleColumns) {
1824 this._visibleColumns = visibleColumns;
1825 },
1826 enumerable: true,
1827 configurable: true
1828 });
1829 return SharedService;
1830 }());
1831
1832 var ExtensionUtility = /** @class */ (function () {
1833 function ExtensionUtility(sharedService, translate) {
1834 this.sharedService = sharedService;
1835 this.translate = translate;
1836 }
1837 /**
1838 * Remove a column from the grid by it's index in the grid
1839 * @param array input
1840 * @param index
1841 */
1842 ExtensionUtility.prototype.arrayRemoveItemByIndex = function (array, index) {
1843 return array.filter(function (el, i) { return index !== i; });
1844 };
1845 /**
1846 * Load SlickGrid Extension (Control/Plugin) dynamically (on demand)
1847 * This will basically only load the extension when user enables the feature
1848 * @param extensionName
1849 */
1850 ExtensionUtility.prototype.loadExtensionDynamically = function (extensionName) {
1851 try {
1852 switch (extensionName) {
1853 case exports.ExtensionName.autoTooltip:
1854 require('slickgrid/plugins/slick.autotooltips');
1855 break;
1856 case exports.ExtensionName.cellExternalCopyManager:
1857 require('slickgrid/plugins/slick.cellexternalcopymanager');
1858 break;
1859 case exports.ExtensionName.checkboxSelector:
1860 require('slickgrid/plugins/slick.checkboxselectcolumn');
1861 break;
1862 case exports.ExtensionName.columnPicker:
1863 require('slickgrid/controls/slick.columnpicker');
1864 break;
1865 case exports.ExtensionName.draggableGrouping:
1866 require('slickgrid/plugins/slick.draggablegrouping');
1867 break;
1868 case exports.ExtensionName.gridMenu:
1869 require('slickgrid/controls/slick.gridmenu');
1870 break;
1871 case exports.ExtensionName.groupItemMetaProvider:
1872 require('slickgrid/slick.groupitemmetadataprovider');
1873 break;
1874 case exports.ExtensionName.headerButton:
1875 require('slickgrid/plugins/slick.headerbuttons');
1876 break;
1877 case exports.ExtensionName.headerMenu:
1878 require('slickgrid/plugins/slick.headermenu');
1879 break;
1880 case exports.ExtensionName.rowSelection:
1881 require('slickgrid/plugins/slick.rowselectionmodel');
1882 break;
1883 case exports.ExtensionName.rowDetailView:
1884 require('slickgrid/plugins/slick.rowdetailview');
1885 break;
1886 case exports.ExtensionName.rowMoveManager:
1887 require('slickgrid/plugins/slick.rowmovemanager');
1888 break;
1889 }
1890 }
1891 catch (e) {
1892 // do nothing, we fall here when using Angular and RequireJS
1893 }
1894 };
1895 /**
1896 * From a Grid Menu object property name, we will return the correct title output string following this order
1897 * 1- if user provided a title, use it as the output title
1898 * 2- else if user provided a title key, use it to translate the output title
1899 * 3- else if nothing is provided use
1900 */
1901 ExtensionUtility.prototype.getPickerTitleOutputString = function (propName, pickerName) {
1902 var output = '';
1903 var picker = this.sharedService.gridOptions && this.sharedService.gridOptions[pickerName] || {};
1904 var enableTranslate = this.sharedService.gridOptions && this.sharedService.gridOptions.enableTranslate || false;
1905 var title = picker && picker[propName];
1906 var titleKey = picker && picker[propName + "Key"];
1907 if (titleKey) {
1908 output = this.translate.instant(titleKey || ' ');
1909 }
1910 else {
1911 switch (propName) {
1912 case 'customTitle':
1913 output = title || (enableTranslate ? this.translate.instant('COMMANDS') : Constants.TEXT_COMMANDS);
1914 break;
1915 case 'columnTitle':
1916 output = title || (enableTranslate ? this.translate.instant('COLUMNS') : Constants.TEXT_COLUMNS);
1917 break;
1918 case 'forceFitTitle':
1919 output = title || (enableTranslate ? this.translate.instant('FORCE_FIT_COLUMNS') : Constants.TEXT_FORCE_FIT_COLUMNS);
1920 break;
1921 case 'syncResizeTitle':
1922 output = title || (enableTranslate ? this.translate.instant('SYNCHRONOUS_RESIZE') : Constants.TEXT_SYNCHRONOUS_RESIZE);
1923 break;
1924 default:
1925 output = title;
1926 break;
1927 }
1928 }
1929 return output;
1930 };
1931 /**
1932 * Sort items (by pointers) in an array by a property name
1933 * @params items array
1934 * @param property name to sort with
1935 */
1936 ExtensionUtility.prototype.sortItems = function (items, propertyName) {
1937 // sort the custom items by their position in the list
1938 items.sort(function (itemA, itemB) {
1939 if (itemA && itemB && itemA.hasOwnProperty(propertyName) && itemB.hasOwnProperty(propertyName)) {
1940 return itemA[propertyName] - itemB[propertyName];
1941 }
1942 return -1;
1943 });
1944 };
1945 /** Translate the an array of items from an input key and assign to the output key */
1946 ExtensionUtility.prototype.translateItems = function (items, inputKey, outputKey) {
1947 var e_1, _a;
1948 if (Array.isArray(items)) {
1949 try {
1950 for (var items_1 = __values(items), items_1_1 = items_1.next(); !items_1_1.done; items_1_1 = items_1.next()) {
1951 var item = items_1_1.value;
1952 if (item[inputKey]) {
1953 item[outputKey] = this.translate.instant(item[inputKey]);
1954 }
1955 }
1956 }
1957 catch (e_1_1) { e_1 = { error: e_1_1 }; }
1958 finally {
1959 try {
1960 if (items_1_1 && !items_1_1.done && (_a = items_1.return)) _a.call(items_1);
1961 }
1962 finally { if (e_1) throw e_1.error; }
1963 }
1964 }
1965 };
1966 ExtensionUtility = __decorate([
1967 core.Injectable(),
1968 __metadata("design:paramtypes", [SharedService, core$1.TranslateService])
1969 ], ExtensionUtility);
1970 return ExtensionUtility;
1971 }());
1972
1973 var AutoTooltipExtension = /** @class */ (function () {
1974 function AutoTooltipExtension(extensionUtility, sharedService) {
1975 this.extensionUtility = extensionUtility;
1976 this.sharedService = sharedService;
1977 }
1978 AutoTooltipExtension.prototype.dispose = function () {
1979 if (this._addon && this._addon.destroy) {
1980 this._addon.destroy();
1981 }
1982 };
1983 AutoTooltipExtension.prototype.register = function () {
1984 if (this.sharedService && this.sharedService.grid && this.sharedService.gridOptions) {
1985 // dynamically import the SlickGrid plugin (addon) with RequireJS
1986 this.extensionUtility.loadExtensionDynamically(exports.ExtensionName.autoTooltip);
1987 this._addon = new Slick.AutoTooltips(this.sharedService.gridOptions.autoTooltipOptions || {});
1988 this.sharedService.grid.registerPlugin(this._addon);
1989 return this._addon;
1990 }
1991 return null;
1992 };
1993 AutoTooltipExtension = __decorate([
1994 core.Injectable(),
1995 __metadata("design:paramtypes", [ExtensionUtility, SharedService])
1996 ], AutoTooltipExtension);
1997 return AutoTooltipExtension;
1998 }());
1999
2000 var CellExternalCopyManagerExtension = /** @class */ (function () {
2001 function CellExternalCopyManagerExtension(extensionUtility, sharedService) {
2002 this.extensionUtility = extensionUtility;
2003 this.sharedService = sharedService;
2004 this._eventHandler = new Slick.EventHandler();
2005 }
2006 Object.defineProperty(CellExternalCopyManagerExtension.prototype, "addonOptions", {
2007 get: function () {
2008 return this._addonOptions;
2009 },
2010 enumerable: true,
2011 configurable: true
2012 });
2013 Object.defineProperty(CellExternalCopyManagerExtension.prototype, "eventHandler", {
2014 get: function () {
2015 return this._eventHandler;
2016 },
2017 enumerable: true,
2018 configurable: true
2019 });
2020 Object.defineProperty(CellExternalCopyManagerExtension.prototype, "commandQueue", {
2021 get: function () {
2022 return this._commandQueue;
2023 },
2024 enumerable: true,
2025 configurable: true
2026 });
2027 Object.defineProperty(CellExternalCopyManagerExtension.prototype, "undoRedoBuffer", {
2028 get: function () {
2029 return this._undoRedoBuffer;
2030 },
2031 enumerable: true,
2032 configurable: true
2033 });
2034 CellExternalCopyManagerExtension.prototype.dispose = function () {
2035 // unsubscribe all SlickGrid events
2036 this._eventHandler.unsubscribeAll();
2037 if (this._addon && this._addon.destroy) {
2038 this._addon.destroy();
2039 }
2040 };
2041 CellExternalCopyManagerExtension.prototype.register = function () {
2042 var _this = this;
2043 if (this.sharedService && this.sharedService.grid && this.sharedService.gridOptions) {
2044 // dynamically import the SlickGrid plugin (addon) with RequireJS
2045 this.extensionUtility.loadExtensionDynamically(exports.ExtensionName.cellExternalCopyManager);
2046 this.createUndoRedoBuffer();
2047 this.hookUndoShortcutKey();
2048 this._addonOptions = __assign({}, this.getDefaultOptions(), this.sharedService.gridOptions.excelCopyBufferOptions);
2049 this.sharedService.grid.setSelectionModel(new Slick.CellSelectionModel());
2050 this._addon = new Slick.CellExternalCopyManager(this._addonOptions);
2051 this.sharedService.grid.registerPlugin(this._addon);
2052 // hook to all possible events
2053 if (this.sharedService.grid && this.sharedService.gridOptions.excelCopyBufferOptions) {
2054 if (this.sharedService.gridOptions.excelCopyBufferOptions.onExtensionRegistered) {
2055 this.sharedService.gridOptions.excelCopyBufferOptions.onExtensionRegistered(this._addon);
2056 }
2057 this._eventHandler.subscribe(this._addon.onCopyCells, function (e, args) {
2058 if (_this.sharedService.gridOptions.excelCopyBufferOptions && typeof _this.sharedService.gridOptions.excelCopyBufferOptions.onCopyCells === 'function') {
2059 _this.sharedService.gridOptions.excelCopyBufferOptions.onCopyCells(e, args);
2060 }
2061 });
2062 this._eventHandler.subscribe(this._addon.onCopyCancelled, function (e, args) {
2063 if (_this.sharedService.gridOptions.excelCopyBufferOptions && typeof _this.sharedService.gridOptions.excelCopyBufferOptions.onCopyCancelled === 'function') {
2064 _this.sharedService.gridOptions.excelCopyBufferOptions.onCopyCancelled(e, args);
2065 }
2066 });
2067 this._eventHandler.subscribe(this._addon.onPasteCells, function (e, args) {
2068 if (_this.sharedService.gridOptions.excelCopyBufferOptions && typeof _this.sharedService.gridOptions.excelCopyBufferOptions.onPasteCells === 'function') {
2069 _this.sharedService.gridOptions.excelCopyBufferOptions.onPasteCells(e, args);
2070 }
2071 });
2072 }
2073 return this._addon;
2074 }
2075 return null;
2076 };
2077 /** Create an undo redo buffer used by the Excel like copy */
2078 CellExternalCopyManagerExtension.prototype.createUndoRedoBuffer = function () {
2079 var _this = this;
2080 var commandCtr = 0;
2081 this._commandQueue = [];
2082 this._undoRedoBuffer = {
2083 queueAndExecuteCommand: function (editCommand) {
2084 _this._commandQueue[commandCtr] = editCommand;
2085 commandCtr++;
2086 editCommand.execute();
2087 },
2088 undo: function () {
2089 if (commandCtr === 0) {
2090 return;
2091 }
2092 commandCtr--;
2093 var command = _this._commandQueue[commandCtr];
2094 if (command && Slick.GlobalEditorLock.cancelCurrentEdit()) {
2095 command.undo();
2096 }
2097 },
2098 redo: function () {
2099 if (commandCtr >= _this._commandQueue.length) {
2100 return;
2101 }
2102 var command = _this._commandQueue[commandCtr];
2103 commandCtr++;
2104 if (command && Slick.GlobalEditorLock.cancelCurrentEdit()) {
2105 command.execute();
2106 }
2107 }
2108 };
2109 };
2110 /** @return default plugin (addon) options */
2111 CellExternalCopyManagerExtension.prototype.getDefaultOptions = function () {
2112 var _this = this;
2113 var newRowIds = 0;
2114 return {
2115 clipboardCommandHandler: function (editCommand) {
2116 _this._undoRedoBuffer.queueAndExecuteCommand.call(_this._undoRedoBuffer, editCommand);
2117 },
2118 dataItemColumnValueExtractor: function (item, columnDef) {
2119 // when grid or cell is not editable, we will possibly evaluate the Formatter if it was passed
2120 // to decide if we evaluate the Formatter, we will use the same flag from Export which is "exportWithFormatter"
2121 if (!_this.sharedService.gridOptions.editable || !columnDef.editor) {
2122 var isEvaluatingFormatter = (columnDef.exportWithFormatter !== undefined) ? columnDef.exportWithFormatter : (_this.sharedService.gridOptions.exportOptions && _this.sharedService.gridOptions.exportOptions.exportWithFormatter);
2123 if (columnDef.formatter && isEvaluatingFormatter) {
2124 var formattedOutput = columnDef.formatter(0, 0, item[columnDef.field], columnDef, item, _this.sharedService.grid);
2125 if (columnDef.sanitizeDataExport || (_this.sharedService.gridOptions.exportOptions && _this.sharedService.gridOptions.exportOptions.sanitizeDataExport)) {
2126 var outputString = formattedOutput;
2127 if (formattedOutput && typeof formattedOutput === 'object' && formattedOutput.hasOwnProperty('text')) {
2128 outputString = formattedOutput.text;
2129 }
2130 if (outputString === null) {
2131 outputString = '';
2132 }
2133 return sanitizeHtmlToText(outputString);
2134 }
2135 return formattedOutput;
2136 }
2137 }
2138 // else use the default "dataItemColumnValueExtractor" from the plugin itself
2139 // we can do that by setting back the getter with null
2140 return null;
2141 },
2142 readOnlyMode: false,
2143 includeHeaderWhenCopying: false,
2144 newRowCreator: function (count) {
2145 for (var i = 0; i < count; i++) {
2146 var item = {
2147 id: 'newRow_' + newRowIds++
2148 };
2149 _this.sharedService.grid.getData().addItem(item);
2150 }
2151 }
2152 };
2153 };
2154 /** Hook an undo shortcut key hook that will redo/undo the copy buffer using Ctrl+(Shift)+Z keyboard events */
2155 CellExternalCopyManagerExtension.prototype.hookUndoShortcutKey = function () {
2156 var _this = this;
2157 document.addEventListener('keydown', function (e) {
2158 var keyCode = e.keyCode || e.code;
2159 if (keyCode === 90 && (e.ctrlKey || e.metaKey)) {
2160 if (e.shiftKey) {
2161 _this._undoRedoBuffer.redo(); // Ctrl + Shift + Z
2162 }
2163 else {
2164 _this._undoRedoBuffer.undo(); // Ctrl + Z
2165 }
2166 }
2167 });
2168 };
2169 CellExternalCopyManagerExtension = __decorate([
2170 core.Injectable(),
2171 __metadata("design:paramtypes", [ExtensionUtility, SharedService])
2172 ], CellExternalCopyManagerExtension);
2173 return CellExternalCopyManagerExtension;
2174 }());
2175
2176 var CheckboxSelectorExtension = /** @class */ (function () {
2177 function CheckboxSelectorExtension(extensionUtility, sharedService) {
2178 this.extensionUtility = extensionUtility;
2179 this.sharedService = sharedService;
2180 }
2181 CheckboxSelectorExtension.prototype.dispose = function () {
2182 if (this._addon && this._addon.destroy) {
2183 this._addon.destroy();
2184 }
2185 };
2186 /**
2187 * Create the plugin before the Grid creation, else it will behave oddly.
2188 * Mostly because the column definitions might change after the grid creation
2189 */
2190 CheckboxSelectorExtension.prototype.create = function (columnDefinitions, gridOptions) {
2191 if (Array.isArray(columnDefinitions) && gridOptions) {
2192 // dynamically import the SlickGrid plugin (addon) with RequireJS
2193 this.extensionUtility.loadExtensionDynamically(exports.ExtensionName.checkboxSelector);
2194 if (!this._addon) {
2195 this._addon = new Slick.CheckboxSelectColumn(gridOptions.checkboxSelector || {});
2196 }
2197 var selectionColumn = this._addon.getColumnDefinition();
2198 if (typeof selectionColumn === 'object') {
2199 selectionColumn.excludeFromExport = true;
2200 selectionColumn.excludeFromColumnPicker = true;
2201 selectionColumn.excludeFromGridMenu = true;
2202 selectionColumn.excludeFromQuery = true;
2203 selectionColumn.excludeFromHeaderMenu = true;
2204 columnDefinitions.unshift(selectionColumn);
2205 }
2206 return this._addon;
2207 }
2208 return null;
2209 };
2210 CheckboxSelectorExtension.prototype.register = function (rowSelectionPlugin) {
2211 var _this = this;
2212 if (this.sharedService && this.sharedService.grid && this.sharedService.gridOptions) {
2213 // the plugin has to be created BEFORE the grid (else it behaves oddly), but we can only watch grid events AFTER the grid is created
2214 this.sharedService.grid.registerPlugin(this._addon);
2215 // this also requires the Row Selection Model to be registered as well
2216 if (!rowSelectionPlugin || !this.sharedService.grid.getSelectionModel()) {
2217 this.extensionUtility.loadExtensionDynamically(exports.ExtensionName.rowSelection);
2218 rowSelectionPlugin = new Slick.RowSelectionModel(this.sharedService.gridOptions.rowSelectionOptions || {});
2219 this.sharedService.grid.setSelectionModel(rowSelectionPlugin);
2220 }
2221 // user might want to pre-select some rows
2222 // the setTimeout is because of timing issue with styling (row selection happen but rows aren't highlighted properly)
2223 if (this.sharedService.gridOptions.preselectedRows && rowSelectionPlugin && this.sharedService.grid.getSelectionModel()) {
2224 setTimeout(function () { return _this._addon.selectRows(_this.sharedService.gridOptions.preselectedRows); }, 0);
2225 }
2226 return rowSelectionPlugin;
2227 }
2228 return null;
2229 };
2230 CheckboxSelectorExtension = __decorate([
2231 core.Injectable(),
2232 __metadata("design:paramtypes", [ExtensionUtility, SharedService])
2233 ], CheckboxSelectorExtension);
2234 return CheckboxSelectorExtension;
2235 }());
2236
2237 var ColumnPickerExtension = /** @class */ (function () {
2238 function ColumnPickerExtension(extensionUtility, sharedService) {
2239 this.extensionUtility = extensionUtility;
2240 this.sharedService = sharedService;
2241 this._eventHandler = new Slick.EventHandler();
2242 }
2243 Object.defineProperty(ColumnPickerExtension.prototype, "eventHandler", {
2244 get: function () {
2245 return this._eventHandler;
2246 },
2247 enumerable: true,
2248 configurable: true
2249 });
2250 ColumnPickerExtension.prototype.dispose = function () {
2251 // unsubscribe all SlickGrid events
2252 this._eventHandler.unsubscribeAll();
2253 if (this._addon && this._addon.destroy) {
2254 this._addon.destroy();
2255 }
2256 };
2257 ColumnPickerExtension.prototype.register = function () {
2258 var _this = this;
2259 if (this.sharedService && this.sharedService.grid && this.sharedService.gridOptions) {
2260 // dynamically import the SlickGrid plugin (addon) with RequireJS
2261 this.extensionUtility.loadExtensionDynamically(exports.ExtensionName.columnPicker);
2262 // localization support for the picker
2263 var columnTitle = this.extensionUtility.getPickerTitleOutputString('columnTitle', 'columnPicker');
2264 var forceFitTitle = this.extensionUtility.getPickerTitleOutputString('forceFitTitle', 'columnPicker');
2265 var syncResizeTitle = this.extensionUtility.getPickerTitleOutputString('syncResizeTitle', 'columnPicker');
2266 this.sharedService.gridOptions.columnPicker = this.sharedService.gridOptions.columnPicker || {};
2267 this.sharedService.gridOptions.columnPicker.columnTitle = this.sharedService.gridOptions.columnPicker.columnTitle || columnTitle;
2268 this.sharedService.gridOptions.columnPicker.forceFitTitle = this.sharedService.gridOptions.columnPicker.forceFitTitle || forceFitTitle;
2269 this.sharedService.gridOptions.columnPicker.syncResizeTitle = this.sharedService.gridOptions.columnPicker.syncResizeTitle || syncResizeTitle;
2270 this._addon = new Slick.Controls.ColumnPicker(this.sharedService.columnDefinitions, this.sharedService.grid, this.sharedService.gridOptions);
2271 if (this.sharedService.grid && this.sharedService.gridOptions.enableColumnPicker) {
2272 if (this.sharedService.gridOptions.columnPicker.onExtensionRegistered) {
2273 this.sharedService.gridOptions.columnPicker.onExtensionRegistered(this._addon);
2274 }
2275 this._eventHandler.subscribe(this._addon.onColumnsChanged, function (e, args) {
2276 if (_this.sharedService.gridOptions.columnPicker && typeof _this.sharedService.gridOptions.columnPicker.onColumnsChanged === 'function') {
2277 _this.sharedService.gridOptions.columnPicker.onColumnsChanged(e, args);
2278 }
2279 });
2280 }
2281 return this._addon;
2282 }
2283 return null;
2284 };
2285 /** Translate the Column Picker headers and also the last 2 checkboxes */
2286 ColumnPickerExtension.prototype.translateColumnPicker = function () {
2287 if (this.sharedService && this.sharedService.grid && this.sharedService.gridOptions) {
2288 // update the properties by pointers, that is the only way to get Column Picker Control to see the new values
2289 if (this.sharedService.gridOptions.columnPicker) {
2290 this.emptyColumnPickerTitles();
2291 this.sharedService.gridOptions.columnPicker.columnTitle = this.extensionUtility.getPickerTitleOutputString('columnTitle', 'columnPicker');
2292 this.sharedService.gridOptions.columnPicker.forceFitTitle = this.extensionUtility.getPickerTitleOutputString('forceFitTitle', 'columnPicker');
2293 this.sharedService.gridOptions.columnPicker.syncResizeTitle = this.extensionUtility.getPickerTitleOutputString('syncResizeTitle', 'columnPicker');
2294 }
2295 // translate all columns (including hidden columns)
2296 this.extensionUtility.translateItems(this.sharedService.allColumns, 'headerKey', 'name');
2297 // re-initialize the Column Picker, that will recreate all the list
2298 // doing an "init()" won't drop any existing command attached
2299 if (this._addon.init) {
2300 this._addon.init(this.sharedService.grid);
2301 }
2302 }
2303 };
2304 ColumnPickerExtension.prototype.emptyColumnPickerTitles = function () {
2305 if (this.sharedService && this.sharedService.gridOptions && this.sharedService.gridOptions.columnPicker) {
2306 this.sharedService.gridOptions.columnPicker.columnTitle = '';
2307 this.sharedService.gridOptions.columnPicker.forceFitTitle = '';
2308 this.sharedService.gridOptions.columnPicker.syncResizeTitle = '';
2309 }
2310 };
2311 ColumnPickerExtension = __decorate([
2312 core.Injectable(),
2313 __metadata("design:paramtypes", [ExtensionUtility, SharedService])
2314 ], ColumnPickerExtension);
2315 return ColumnPickerExtension;
2316 }());
2317
2318 var DraggableGroupingExtension = /** @class */ (function () {
2319 function DraggableGroupingExtension(extensionUtility, sharedService) {
2320 this.extensionUtility = extensionUtility;
2321 this.sharedService = sharedService;
2322 this._eventHandler = new Slick.EventHandler();
2323 }
2324 Object.defineProperty(DraggableGroupingExtension.prototype, "eventHandler", {
2325 get: function () {
2326 return this._eventHandler;
2327 },
2328 enumerable: true,
2329 configurable: true
2330 });
2331 DraggableGroupingExtension.prototype.dispose = function () {
2332 // unsubscribe all SlickGrid events
2333 this._eventHandler.unsubscribeAll();
2334 if (this._addon && this._addon.destroy) {
2335 this._addon.destroy();
2336 }
2337 };
2338 /**
2339 * Bind/Create different plugins before the Grid creation.
2340 * For example the multi-select have to be added to the column definition before the grid is created to work properly
2341 */
2342 DraggableGroupingExtension.prototype.create = function (gridOptions) {
2343 if (gridOptions) {
2344 // dynamically import the SlickGrid plugin (addon) with RequireJS
2345 this.extensionUtility.loadExtensionDynamically(exports.ExtensionName.draggableGrouping);
2346 if (!this._addon) {
2347 this._addon = new Slick.DraggableGrouping(gridOptions.draggableGrouping || {});
2348 }
2349 return this._addon;
2350 }
2351 return null;
2352 };
2353 DraggableGroupingExtension.prototype.register = function () {
2354 var _this = this;
2355 if (this.sharedService && this.sharedService.grid && this.sharedService.gridOptions) {
2356 this.sharedService.grid.registerPlugin(this._addon);
2357 // Events
2358 if (this.sharedService.grid && this.sharedService.gridOptions.draggableGrouping) {
2359 if (this.sharedService.gridOptions.draggableGrouping.onExtensionRegistered) {
2360 this.sharedService.gridOptions.draggableGrouping.onExtensionRegistered(this._addon);
2361 }
2362 this._eventHandler.subscribe(this._addon.onGroupChanged, function (e, args) {
2363 if (_this.sharedService.gridOptions.draggableGrouping && typeof _this.sharedService.gridOptions.draggableGrouping.onGroupChanged === 'function') {
2364 _this.sharedService.gridOptions.draggableGrouping.onGroupChanged(e, args);
2365 }
2366 });
2367 }
2368 return this._addon;
2369 }
2370 return null;
2371 };
2372 DraggableGroupingExtension = __decorate([
2373 core.Injectable(),
2374 __metadata("design:paramtypes", [ExtensionUtility, SharedService])
2375 ], DraggableGroupingExtension);
2376 return DraggableGroupingExtension;
2377 }());
2378
2379 var booleanFilterCondition = function (options) {
2380 var searchTerm = Array.isArray(options.searchTerms) && options.searchTerms[0] || '';
2381 return parseBoolean(options.cellValue) === parseBoolean(searchTerm);
2382 };
2383
2384 /**
2385 * Compare 2 objects,
2386 * we will loop through all properties of the object to compare the entire content of both objects
2387 * Optionally we can compare by a property key, when that is provided we will compare the object content
2388 * @param o1
2389 * @param o2
2390 * @param compareKey optional
2391 */
2392 var compareObjects = function (o1, o2, compareKey) {
2393 // if user provided an object compare key then compare directly both objects by that key
2394 if (compareKey && (o1.hasOwnProperty(compareKey) || o2.hasOwnProperty(compareKey))) {
2395 return o1[compareKey] === o2 || o1 === o2[compareKey] || o1[compareKey] === o2[compareKey];
2396 }
2397 // loop through all object properties to compare the full content of the object
2398 // we'll return false as soon as a difference is detected
2399 for (var p in o1) {
2400 if (o1.hasOwnProperty(p)) {
2401 if (o1[p] !== o2[p]) {
2402 return false;
2403 }
2404 }
2405 }
2406 return true;
2407 };
2408 var testFilterCondition = function (operator, value1, value2) {
2409 switch (operator) {
2410 case '<':
2411 case 'LT': return (value1 < value2);
2412 case '<=':
2413 case 'LE': return (value1 <= value2);
2414 case '>':
2415 case 'GT': return (value1 > value2);
2416 case '>=':
2417 case 'GE': return (value1 >= value2);
2418 case '!=':
2419 case '<>':
2420 case 'NE': return (value1 !== value2);
2421 case '=':
2422 case '==':
2423 case 'EQ': return (value1 === value2);
2424 case 'IN': return ((value2 && value2.includes) ? (value2.includes(value1)) : false);
2425 case 'NIN':
2426 case 'NOT_IN':
2427 return ((value2 && value2.includes) ? (!value2.includes(value1)) : false);
2428 case 'IN_CONTAINS':
2429 if (value2 && Array.isArray(value2) && value2.findIndex) {
2430 return ((value2.findIndex(function (val) { return value1.indexOf(val) > -1; })) > -1);
2431 }
2432 return false;
2433 case 'NIN_CONTAINS':
2434 case 'NOT_IN_CONTAINS':
2435 if (value2 && Array.isArray(value2) && value2.findIndex) {
2436 return !((value2.findIndex(function (val) { return value1.indexOf(val) > -1; })) > -1);
2437 }
2438 return false;
2439 }
2440 return true;
2441 };
2442
2443 var moment$3 = moment_; // patch to fix rollup "moment has no default export" issue, document here https://github.com/rollup/rollup/issues/670
2444 var FORMAT$5 = mapMomentDateFormatWithFieldType(exports.FieldType.dateEuro);
2445 var dateEuroFilterCondition = function (options) {
2446 var searchTerm = Array.isArray(options.searchTerms) && options.searchTerms[0] || '';
2447 if (searchTerm === null || searchTerm === '' || !moment$3(options.cellValue, FORMAT$5, true).isValid() || !moment$3(searchTerm, FORMAT$5, true).isValid()) {
2448 return false;
2449 }
2450 var dateCell = moment$3(options.cellValue, FORMAT$5, true);
2451 var dateSearch = moment$3(searchTerm, FORMAT$5, true);
2452 // run the filter condition with date in Unix Timestamp format
2453 return testFilterCondition(options.operator || '==', parseInt(dateCell.format('X'), 10), parseInt(dateSearch.format('X'), 10));
2454 };
2455
2456 var moment$4 = moment_; // patch to fix rollup "moment has no default export" issue, document here https://github.com/rollup/rollup/issues/670
2457 var FORMAT$6 = mapMomentDateFormatWithFieldType(exports.FieldType.dateEuroShort);
2458 var dateEuroShortFilterCondition = function (options) {
2459 var searchTerm = Array.isArray(options.searchTerms) && options.searchTerms[0] || '';
2460 if (searchTerm === null || searchTerm === '' || !moment$4(options.cellValue, FORMAT$6, true).isValid() || !moment$4(searchTerm, FORMAT$6, true).isValid()) {
2461 return false;
2462 }
2463 var dateCell = moment$4(options.cellValue, FORMAT$6, true);
2464 var dateSearch = moment$4(searchTerm, FORMAT$6, true);
2465 // run the filter condition with date in Unix Timestamp format
2466 return testFilterCondition(options.operator || '==', parseInt(dateCell.format('X'), 10), parseInt(dateSearch.format('X'), 10));
2467 };
2468
2469 var moment$5 = moment_; // patch to fix rollup "moment has no default export" issue, document here https://github.com/rollup/rollup/issues/670
2470 var dateFilterCondition = function (options) {
2471 var searchTerm = Array.isArray(options.searchTerms) && options.searchTerms[0] || '';
2472 var filterSearchType = options.filterSearchType || exports.FieldType.dateIso;
2473 var searchDateFormat = mapMomentDateFormatWithFieldType(filterSearchType);
2474 if (searchTerm === null || searchTerm === '' || !moment$5(options.cellValue, moment$5.ISO_8601).isValid() || !moment$5(searchTerm, searchDateFormat, true).isValid()) {
2475 return false;
2476 }
2477 var dateCell = moment$5(options.cellValue);
2478 var dateSearch = moment$5(searchTerm);
2479 // run the filter condition with date in Unix Timestamp format
2480 return testFilterCondition(options.operator || '==', parseInt(dateCell.format('X'), 10), parseInt(dateSearch.format('X'), 10));
2481 };
2482
2483 var moment$6 = moment_; // patch to fix rollup "moment has no default export" issue, document here https://github.com/rollup/rollup/issues/670
2484 var FORMAT$7 = mapMomentDateFormatWithFieldType(exports.FieldType.dateIso);
2485 var dateIsoFilterCondition = function (options) {
2486 var searchTerm = Array.isArray(options.searchTerms) && options.searchTerms[0] || '';
2487 if (searchTerm === null || searchTerm === '' || !moment$6(options.cellValue, FORMAT$7, true).isValid() || !moment$6(searchTerm, FORMAT$7, true).isValid()) {
2488 return false;
2489 }
2490 var dateCell = moment$6(options.cellValue, FORMAT$7, true);
2491 var dateSearch = moment$6(searchTerm, FORMAT$7, true);
2492 // run the filter condition with date in Unix Timestamp format
2493 return testFilterCondition(options.operator || '==', parseInt(dateCell.format('X'), 10), parseInt(dateSearch.format('X'), 10));
2494 };
2495
2496 var moment$7 = moment_; // patch to fix rollup "moment has no default export" issue, document here https://github.com/rollup/rollup/issues/670
2497 var FORMAT$8 = mapMomentDateFormatWithFieldType(exports.FieldType.dateUs);
2498 var dateUsFilterCondition = function (options) {
2499 var searchTerm = Array.isArray(options.searchTerms) && options.searchTerms[0] || '';
2500 if (searchTerm === null || searchTerm === '' || !moment$7(options.cellValue, FORMAT$8, true).isValid() || !moment$7(searchTerm, FORMAT$8, true).isValid()) {
2501 return false;
2502 }
2503 var dateCell = moment$7(options.cellValue, FORMAT$8, true);
2504 var dateSearch = moment$7(searchTerm, FORMAT$8, true);
2505 // run the filter condition with date in Unix Timestamp format
2506 return testFilterCondition(options.operator || '==', parseInt(dateCell.format('X'), 10), parseInt(dateSearch.format('X'), 10));
2507 };
2508
2509 var moment$8 = moment_; // patch to fix rollup "moment has no default export" issue, document here https://github.com/rollup/rollup/issues/670
2510 var FORMAT$9 = mapMomentDateFormatWithFieldType(exports.FieldType.dateUsShort);
2511 var dateUsShortFilterCondition = function (options) {
2512 var searchTerm = Array.isArray(options.searchTerms) && options.searchTerms[0] || '';
2513 if (searchTerm === null || searchTerm === '' || !moment$8(options.cellValue, FORMAT$9, true).isValid() || !moment$8(searchTerm, FORMAT$9, true).isValid()) {
2514 return false;
2515 }
2516 var dateCell = moment$8(options.cellValue, FORMAT$9, true);
2517 var dateSearch = moment$8(searchTerm, FORMAT$9, true);
2518 // run the filter condition with date in Unix Timestamp format
2519 return testFilterCondition(options.operator || '==', parseInt(dateCell.format('X'), 10), parseInt(dateSearch.format('X'), 10));
2520 };
2521
2522 var moment$9 = moment_; // patch to fix rollup "moment has no default export" issue, document here https://github.com/rollup/rollup/issues/670
2523 var dateUtcFilterCondition = function (options) {
2524 var searchTerm = Array.isArray(options.searchTerms) && options.searchTerms[0] || '';
2525 var searchDateFormat = mapMomentDateFormatWithFieldType(options.filterSearchType || options.fieldType);
2526 if (!moment$9(options.cellValue, moment$9.ISO_8601).isValid() || !moment$9(searchTerm, searchDateFormat, true).isValid()) {
2527 return false;
2528 }
2529 var dateCell = moment$9(options.cellValue, moment$9.ISO_8601, true);
2530 var dateSearch = moment$9(searchTerm, searchDateFormat, true);
2531 // run the filter condition with date in Unix Timestamp format
2532 return testFilterCondition(options.operator || '==', parseInt(dateCell.format('X'), 10), parseInt(dateSearch.format('X'), 10));
2533 };
2534
2535 var collectionSearchFilterCondition = function (options) {
2536 // multiple-select will always return text, so we should make our cell values text as well
2537 var cellValue = options.cellValue + '';
2538 return testFilterCondition(options.operator || 'IN', cellValue, options.searchTerms || []);
2539 };
2540
2541 var numberFilterCondition = function (options) {
2542 var cellValue = parseFloat(options.cellValue);
2543 var searchTerm = (Array.isArray(options.searchTerms) && options.searchTerms[0]) || 0;
2544 if (typeof searchTerm === 'string') {
2545 searchTerm = parseFloat(searchTerm);
2546 }
2547 if (!searchTerm && !options.operator) {
2548 return true;
2549 }
2550 return testFilterCondition(options.operator || '==', cellValue, searchTerm);
2551 };
2552
2553 var objectFilterCondition = function (options) {
2554 var searchTerm = (Array.isArray(options.searchTerms) && options.searchTerms[0] || '');
2555 if (!searchTerm && !options.operator) {
2556 return true;
2557 }
2558 switch (options.operator) {
2559 case '!=':
2560 case '<>':
2561 case 'NE':
2562 return !compareObjects(options.cellValue, searchTerm, options.dataKey);
2563 case '=':
2564 case '==':
2565 case 'EQ':
2566 default:
2567 return compareObjects(options.cellValue, searchTerm, options.dataKey);
2568 }
2569 };
2570
2571 var stringFilterCondition = function (options) {
2572 // make sure the cell value is a string by casting it when possible
2573 options.cellValue = (options.cellValue === undefined || options.cellValue === null) ? '' : options.cellValue.toString();
2574 // make both the cell value and search value lower for case insensitive comparison
2575 var cellValue = options.cellValue.toLowerCase();
2576 var searchTerm = (Array.isArray(options.searchTerms) && options.searchTerms[0]) || '';
2577 if (typeof searchTerm === 'string') {
2578 searchTerm = searchTerm.toLowerCase();
2579 }
2580 if (options.operator === '*' || options.operator === 'EndsWith') {
2581 return cellValue.endsWith(searchTerm);
2582 }
2583 else if ((options.operator === '' && options.cellValueLastChar === '*') || options.operator === 'StartsWith') {
2584 return cellValue.startsWith(searchTerm);
2585 }
2586 else if (options.operator === '') {
2587 return cellValue.includes(searchTerm);
2588 }
2589 return testFilterCondition(options.operator || '==', cellValue, searchTerm);
2590 };
2591
2592 var executeMappedCondition = function (options) {
2593 // when using a multi-select ('IN' operator) we will not use the field type but instead go directly with a collection search
2594 var operator = options && options.operator && options.operator.toUpperCase();
2595 if (operator === 'IN' || operator === 'NIN' || operator === 'IN_CONTAINS' || operator === 'NIN_CONTAINS') {
2596 return collectionSearchFilterCondition(options);
2597 }
2598 // execute the mapped type, or default to String condition check
2599 switch (options.fieldType) {
2600 case exports.FieldType.boolean:
2601 return booleanFilterCondition(options);
2602 case exports.FieldType.date:
2603 return dateFilterCondition(options);
2604 case exports.FieldType.dateUtc:
2605 return dateUtcFilterCondition(options);
2606 case exports.FieldType.dateIso:
2607 return dateIsoFilterCondition(options);
2608 // all Euro Formats (date/month/year)
2609 case exports.FieldType.dateEuro:
2610 return dateEuroFilterCondition(options);
2611 case exports.FieldType.dateEuroShort:
2612 return dateEuroShortFilterCondition(options);
2613 // all US Formats (month/date/year)
2614 case exports.FieldType.dateUs:
2615 case exports.FieldType.dateTimeUs:
2616 return dateUsFilterCondition(options);
2617 case exports.FieldType.dateUsShort:
2618 case exports.FieldType.dateTimeUsShort:
2619 return dateUsShortFilterCondition(options);
2620 case exports.FieldType.number:
2621 return numberFilterCondition(options);
2622 case exports.FieldType.object:
2623 return objectFilterCondition(options);
2624 case exports.FieldType.string:
2625 default:
2626 return stringFilterCondition(options);
2627 }
2628 };
2629
2630 var FilterConditions = {
2631 executeMappedCondition: executeMappedCondition,
2632 booleanFilter: booleanFilterCondition,
2633 collectionSearchFilter: collectionSearchFilterCondition,
2634 dateEuroFilter: dateEuroFilterCondition,
2635 dateEuroShortFilter: dateEuroShortFilterCondition,
2636 dateFilter: dateFilterCondition,
2637 dateIsoFilter: dateIsoFilterCondition,
2638 dateUtcFilter: dateUtcFilterCondition,
2639 dateUsFilter: dateUsFilterCondition,
2640 dateUsShortFilter: dateUsShortFilterCondition,
2641 numberFilter: numberFilterCondition,
2642 stringFilter: stringFilterCondition,
2643 testFilter: testFilterCondition
2644 };
2645
2646 var AutoCompleteFilter = /** @class */ (function () {
2647 /**
2648 * Initialize the Filter
2649 */
2650 function AutoCompleteFilter(translate, collectionService) {
2651 this.translate = translate;
2652 this.collectionService = collectionService;
2653 this._clearFilterTriggered = false;
2654 this._shouldTriggerQuery = true;
2655 this.isFilled = false;
2656 /** The property name for values in the collection */
2657 this.valueName = 'label';
2658 this.enableTranslateLabel = false;
2659 this.subscriptions = [];
2660 }
2661 Object.defineProperty(AutoCompleteFilter.prototype, "collectionOptions", {
2662 /** Getter for the Collection Options */
2663 get: function () {
2664 return this.columnDef && this.columnDef.filter && this.columnDef.filter.collectionOptions || {};
2665 },
2666 enumerable: true,
2667 configurable: true
2668 });
2669 Object.defineProperty(AutoCompleteFilter.prototype, "columnFilter", {
2670 /** Getter for the Column Filter */
2671 get: function () {
2672 return this.columnDef && this.columnDef.filter || {};
2673 },
2674 enumerable: true,
2675 configurable: true
2676 });
2677 Object.defineProperty(AutoCompleteFilter.prototype, "customStructure", {
2678 /** Getter for the Custom Structure if exist */
2679 get: function () {
2680 return this.columnDef && this.columnDef.filter && this.columnDef.filter.customStructure;
2681 },
2682 enumerable: true,
2683 configurable: true
2684 });
2685 Object.defineProperty(AutoCompleteFilter.prototype, "gridOptions", {
2686 /** Getter for the Grid Options pulled through the Grid Object */
2687 get: function () {
2688 return (this.grid && this.grid.getOptions) ? this.grid.getOptions() : {};
2689 },
2690 enumerable: true,
2691 configurable: true
2692 });
2693 Object.defineProperty(AutoCompleteFilter.prototype, "operator", {
2694 /** Getter of the Operator to use when doing the filter comparing */
2695 get: function () {
2696 return this.columnDef && this.columnDef.filter && this.columnDef.filter.operator || exports.OperatorType.equal;
2697 },
2698 enumerable: true,
2699 configurable: true
2700 });
2701 /**
2702 * Initialize the filter template
2703 */
2704 AutoCompleteFilter.prototype.init = function (args) {
2705 if (!args) {
2706 throw new Error('[Angular-SlickGrid] A filter must always have an "init()" with valid arguments.');
2707 }
2708 this.grid = args.grid;
2709 this.callback = args.callback;
2710 this.columnDef = args.columnDef;
2711 this.searchTerms = args.searchTerms || [];
2712 if (!this.grid || !this.columnDef || !this.columnFilter || (!this.columnFilter.collection && !this.columnFilter.collectionAsync && !this.columnFilter.filterOptions)) {
2713 throw new Error("[Angular-SlickGrid] You need to pass a \"collection\" (or \"collectionAsync\") for the AutoComplete Filter to work correctly. Also each option should include a value/label pair (or value/labelKey when using Locale). For example:: { filter: model: Filters.autoComplete, collection: [{ value: true, label: 'True' }, { value: false, label: 'False'}] }");
2714 }
2715 this.enableTranslateLabel = this.columnFilter && this.columnFilter.enableTranslateLabel || false;
2716 this.labelName = this.customStructure && this.customStructure.label || 'label';
2717 this.valueName = this.customStructure && this.customStructure.value || 'value';
2718 // always render the DOM element, even if user passed a "collectionAsync",
2719 var newCollection = this.columnFilter.collection || [];
2720 this.renderDomElement(newCollection);
2721 // on every Filter which have a "collection" or a "collectionAsync"
2722 // we will add (or replace) a Subject to the "collectionAsync" property so that user has possibility to change the collection
2723 // if "collectionAsync" is already set by the user, it will resolve it first then after it will replace it with a Subject
2724 var collectionAsync = this.columnFilter && this.columnFilter.collectionAsync;
2725 if (collectionAsync) {
2726 this.renderOptionsAsync(collectionAsync); // create Subject after resolve (createCollectionAsyncSubject)
2727 }
2728 };
2729 /**
2730 * Clear the filter value
2731 */
2732 AutoCompleteFilter.prototype.clear = function (shouldTriggerQuery) {
2733 if (shouldTriggerQuery === void 0) { shouldTriggerQuery = true; }
2734 if (this.$filterElm) {
2735 this._clearFilterTriggered = true;
2736 this._shouldTriggerQuery = shouldTriggerQuery;
2737 this.searchTerms = [];
2738 this.$filterElm.val('');
2739 this.$filterElm.trigger('keyup');
2740 }
2741 };
2742 /**
2743 * destroy the filter
2744 */
2745 AutoCompleteFilter.prototype.destroy = function () {
2746 if (this.$filterElm) {
2747 this.$filterElm.off('keyup input change').remove();
2748 }
2749 };
2750 /**
2751 * Set value(s) on the DOM element
2752 */
2753 AutoCompleteFilter.prototype.setValues = function (values) {
2754 if (values) {
2755 this.$filterElm.val(values);
2756 }
2757 };
2758 //
2759 // protected functions
2760 // ------------------
2761 /**
2762 * user might want to filter certain items of the collection
2763 * @param inputCollection
2764 * @return outputCollection filtered and/or sorted collection
2765 */
2766 AutoCompleteFilter.prototype.filterCollection = function (inputCollection) {
2767 var outputCollection = inputCollection;
2768 // user might want to filter certain items of the collection
2769 if (this.columnFilter && this.columnFilter.collectionFilterBy) {
2770 var filterBy = this.columnFilter.collectionFilterBy;
2771 var filterCollectionBy = this.columnFilter.collectionOptions && this.columnFilter.collectionOptions.filterResultAfterEachPass || null;
2772 outputCollection = this.collectionService.filterCollection(outputCollection, filterBy, filterCollectionBy);
2773 }
2774 return outputCollection;
2775 };
2776 /**
2777 * user might want to sort the collection in a certain way
2778 * @param inputCollection
2779 * @return outputCollection filtered and/or sorted collection
2780 */
2781 AutoCompleteFilter.prototype.sortCollection = function (inputCollection) {
2782 var outputCollection = inputCollection;
2783 // user might want to sort the collection
2784 if (this.columnFilter && this.columnFilter.collectionSortBy) {
2785 var sortBy = this.columnFilter.collectionSortBy;
2786 outputCollection = this.collectionService.sortCollection(this.columnDef, outputCollection, sortBy, this.enableTranslateLabel);
2787 }
2788 return outputCollection;
2789 };
2790 AutoCompleteFilter.prototype.renderOptionsAsync = function (collectionAsync) {
2791 return __awaiter(this, void 0, void 0, function () {
2792 var awaitedCollection;
2793 return __generator(this, function (_a) {
2794 switch (_a.label) {
2795 case 0:
2796 awaitedCollection = [];
2797 if (!collectionAsync) return [3 /*break*/, 2];
2798 return [4 /*yield*/, castToPromise(collectionAsync)];
2799 case 1:
2800 awaitedCollection = _a.sent();
2801 this.renderDomElementFromCollectionAsync(awaitedCollection);
2802 // because we accept Promises & HttpClient Observable only execute once
2803 // we will re-create an RxJs Subject which will replace the "collectionAsync" which got executed once anyway
2804 // doing this provide the user a way to call a "collectionAsync.next()"
2805 this.createCollectionAsyncSubject();
2806 _a.label = 2;
2807 case 2: return [2 /*return*/];
2808 }
2809 });
2810 });
2811 };
2812 /** Create or recreate an Observable Subject and reassign it to the "collectionAsync" object so user can call a "collectionAsync.next()" on it */
2813 AutoCompleteFilter.prototype.createCollectionAsyncSubject = function () {
2814 var _this = this;
2815 var newCollectionAsync = new rxjs.Subject();
2816 this.columnFilter.collectionAsync = newCollectionAsync;
2817 this.subscriptions.push(newCollectionAsync.subscribe(function (collection) { return _this.renderDomElementFromCollectionAsync(collection); }));
2818 };
2819 /**
2820 * When user use a CollectionAsync we will use the returned collection to render the filter DOM element
2821 * and reinitialize filter collection with this new collection
2822 */
2823 AutoCompleteFilter.prototype.renderDomElementFromCollectionAsync = function (collection) {
2824 if (this.collectionOptions && this.collectionOptions.collectionInObjectProperty) {
2825 collection = getDescendantProperty(collection, this.collectionOptions.collectionInObjectProperty);
2826 }
2827 if (!Array.isArray(collection)) {
2828 throw new Error('Something went wrong while trying to pull the collection from the "collectionAsync" call in the AutoComplete Filter, the collection is not a valid array.');
2829 }
2830 // copy over the array received from the async call to the "collection" as the new collection to use
2831 // this has to be BEFORE the `collectionObserver().subscribe` to avoid going into an infinite loop
2832 this.columnFilter.collection = collection;
2833 // recreate Filter DOM element after getting async collection
2834 this.renderDomElement(collection);
2835 };
2836 AutoCompleteFilter.prototype.renderDomElement = function (collection) {
2837 var _this = this;
2838 if (!Array.isArray(collection) && this.collectionOptions && this.collectionOptions.collectionInObjectProperty) {
2839 collection = getDescendantProperty(collection, this.collectionOptions.collectionInObjectProperty);
2840 }
2841 if (!Array.isArray(collection)) {
2842 throw new Error('The "collection" passed to the Autocomplete Filter is not a valid array');
2843 }
2844 // assign the collection to a temp variable before filtering/sorting the collection
2845 var newCollection = collection;
2846 // user might want to filter and/or sort certain items of the collection
2847 newCollection = this.filterCollection(newCollection);
2848 newCollection = this.sortCollection(newCollection);
2849 // filter input can only have 1 search term, so we will use the 1st array index if it exist
2850 var searchTerm = (Array.isArray(this.searchTerms) && this.searchTerms[0]) || '';
2851 // step 1, create HTML string template
2852 var filterTemplate = this.buildTemplateHtmlString();
2853 // step 2, create the DOM Element of the filter & pre-load search term
2854 // also subscribe to the onClose event
2855 this.$filterElm = this.createDomElement(filterTemplate, newCollection, searchTerm);
2856 // step 3, subscribe to the keyup event and run the callback when that happens
2857 // also add/remove "filled" class for styling purposes
2858 this.$filterElm.on('keyup input change', function (e) {
2859 var value = e && e.target && e.target.value || '';
2860 var enableWhiteSpaceTrim = _this.gridOptions.enableFilterTrimWhiteSpace || _this.columnFilter.enableTrimWhiteSpace;
2861 if (typeof value === 'string' && enableWhiteSpaceTrim) {
2862 value = value.trim();
2863 }
2864 if (_this._clearFilterTriggered) {
2865 _this.callback(e, { columnDef: _this.columnDef, clearFilterTriggered: _this._clearFilterTriggered, shouldTriggerQuery: _this._shouldTriggerQuery });
2866 _this.$filterElm.removeClass('filled');
2867 }
2868 else {
2869 if (value === '') {
2870 _this.$filterElm.removeClass('filled');
2871 _this.callback(e, { columnDef: _this.columnDef, operator: _this.operator, searchTerms: [value], shouldTriggerQuery: _this._shouldTriggerQuery });
2872 }
2873 else {
2874 _this.$filterElm.addClass('filled');
2875 }
2876 }
2877 // reset both flags for next use
2878 _this._clearFilterTriggered = false;
2879 _this._shouldTriggerQuery = true;
2880 });
2881 };
2882 /**
2883 * Create the HTML template as a string
2884 */
2885 AutoCompleteFilter.prototype.buildTemplateHtmlString = function () {
2886 var columnId = this.columnDef && this.columnDef.id;
2887 var placeholder = (this.gridOptions) ? (this.gridOptions.defaultFilterPlaceholder || '') : '';
2888 if (this.columnFilter && this.columnFilter.placeholder) {
2889 placeholder = this.columnFilter.placeholder;
2890 }
2891 return "<input type=\"text\" role=\"presentation\" autocomplete=\"off\" class=\"form-control autocomplete search-filter filter-" + columnId + "\" placeholder=\"" + placeholder + "\">";
2892 };
2893 /**
2894 * From the html template string, create a DOM element
2895 * @param filterTemplate
2896 */
2897 AutoCompleteFilter.prototype.createDomElement = function (filterTemplate, collection, searchTerm) {
2898 var _this = this;
2899 var columnId = this.columnDef && this.columnDef.id;
2900 var $headerElm = this.grid.getHeaderRowColumn(columnId);
2901 $($headerElm).empty();
2902 // create the DOM element & add an ID and filter class
2903 var $filterElm = $(filterTemplate);
2904 var searchTermInput = searchTerm;
2905 // user might provide his own custom structure
2906 // jQuery UI autocomplete requires a label/value pair, so we must remap them when user provide different ones
2907 if (Array.isArray(collection) && this.customStructure) {
2908 collection = collection.map(function (item) {
2909 return { label: item[_this.labelName], value: item[_this.valueName] };
2910 });
2911 }
2912 // user might pass his own autocomplete options
2913 var autoCompleteOptions = this.columnFilter.filterOptions;
2914 // when user passes it's own autocomplete options
2915 // we still need to provide our own "select" callback implementation
2916 if (autoCompleteOptions) {
2917 autoCompleteOptions.select = function (event, ui) { return _this.onSelect(event, ui); };
2918 $filterElm.autocomplete(autoCompleteOptions);
2919 }
2920 else {
2921 if (!Array.isArray(collection)) {
2922 throw new Error('AutoComplete default implementation requires a "collection" or "collectionAsync" to be provided for the filter to work properly');
2923 }
2924 $filterElm.autocomplete({
2925 minLength: 0,
2926 source: collection,
2927 select: function (event, ui) { return _this.onSelect(event, ui); },
2928 });
2929 }
2930 $filterElm.val(searchTermInput);
2931 $filterElm.attr('id', "filter-" + columnId);
2932 $filterElm.data('columnId', columnId);
2933 // if there's a search term, we will add the "filled" class for styling purposes
2934 if (searchTerm) {
2935 $filterElm.addClass('filled');
2936 }
2937 // append the new DOM element to the header row
2938 if ($filterElm && typeof $filterElm.appendTo === 'function') {
2939 $filterElm.appendTo($headerElm);
2940 }
2941 return $filterElm;
2942 };
2943 //
2944 // private functions
2945 // ------------------
2946 AutoCompleteFilter.prototype.onSelect = function (event, ui) {
2947 if (ui && ui.item) {
2948 var itemLabel = typeof ui.item === 'string' ? ui.item : ui.item.label;
2949 var itemValue = typeof ui.item === 'string' ? ui.item : ui.item.value;
2950 this.$filterElm.val(itemLabel);
2951 this.callback(event, { columnDef: this.columnDef, operator: this.operator, searchTerms: [itemValue], shouldTriggerQuery: this._shouldTriggerQuery });
2952 // reset both flags for next use
2953 this._clearFilterTriggered = false;
2954 this._shouldTriggerQuery = true;
2955 }
2956 return false;
2957 };
2958 AutoCompleteFilter = __decorate([
2959 core.Injectable(),
2960 __metadata("design:paramtypes", [core$1.TranslateService, CollectionService])
2961 ], AutoCompleteFilter);
2962 return AutoCompleteFilter;
2963 }());
2964
2965 require('flatpickr');
2966 var CompoundDateFilter = /** @class */ (function () {
2967 function CompoundDateFilter(translate) {
2968 this.translate = translate;
2969 this._clearFilterTriggered = false;
2970 this._shouldTriggerQuery = true;
2971 }
2972 Object.defineProperty(CompoundDateFilter.prototype, "gridOptions", {
2973 /** Getter for the Grid Options pulled through the Grid Object */
2974 get: function () {
2975 return (this.grid && this.grid.getOptions) ? this.grid.getOptions() : {};
2976 },
2977 enumerable: true,
2978 configurable: true
2979 });
2980 Object.defineProperty(CompoundDateFilter.prototype, "columnFilter", {
2981 /** Getter for the Column Filter */
2982 get: function () {
2983 return this.columnDef && this.columnDef.filter || {};
2984 },
2985 enumerable: true,
2986 configurable: true
2987 });
2988 Object.defineProperty(CompoundDateFilter.prototype, "operator", {
2989 /** Getter for the Filter Operator */
2990 get: function () {
2991 return this._operator || exports.OperatorType.empty;
2992 },
2993 /** Setter for the Filter Operator */
2994 set: function (op) {
2995 this._operator = op;
2996 },
2997 enumerable: true,
2998 configurable: true
2999 });
3000 /**
3001 * Initialize the Filter
3002 */
3003 CompoundDateFilter.prototype.init = function (args) {
3004 var _this = this;
3005 if (args) {
3006 this.grid = args.grid;
3007 this.callback = args.callback;
3008 this.columnDef = args.columnDef;
3009 this.operator = args.operator || '';
3010 this.searchTerms = args.searchTerms || [];
3011 // date input can only have 1 search term, so we will use the 1st array index if it exist
3012 var searchTerm = (Array.isArray(this.searchTerms) && this.searchTerms[0]) || '';
3013 // step 1, create the DOM Element of the filter which contain the compound Operator+Input
3014 // and initialize it if searchTerm is filled
3015 this.$filterElm = this.createDomElement(searchTerm);
3016 // step 3, subscribe to the keyup event and run the callback when that happens
3017 // also add/remove "filled" class for styling purposes
3018 this.$filterInputElm.keyup(function (e) {
3019 _this.onTriggerEvent(e);
3020 });
3021 this.$selectOperatorElm.change(function (e) {
3022 _this.onTriggerEvent(e);
3023 });
3024 }
3025 };
3026 /**
3027 * Clear the filter value
3028 */
3029 CompoundDateFilter.prototype.clear = function (shouldTriggerQuery) {
3030 if (shouldTriggerQuery === void 0) { shouldTriggerQuery = true; }
3031 if (this.flatInstance && this.$selectOperatorElm) {
3032 this._clearFilterTriggered = true;
3033 this._shouldTriggerQuery = shouldTriggerQuery;
3034 this.searchTerms = [];
3035 this.$selectOperatorElm.val(0);
3036 this.flatInstance.clear();
3037 }
3038 };
3039 /**
3040 * destroy the filter
3041 */
3042 CompoundDateFilter.prototype.destroy = function () {
3043 if (this.$filterElm) {
3044 this.$filterElm.off('keyup').remove();
3045 }
3046 };
3047 /**
3048 * Set value(s) on the DOM element
3049 */
3050 CompoundDateFilter.prototype.setValues = function (values) {
3051 if (this.flatInstance && values && Array.isArray(values)) {
3052 this.flatInstance.setDate(values[0]);
3053 }
3054 };
3055 //
3056 // private functions
3057 // ------------------
3058 CompoundDateFilter.prototype.buildDatePickerInput = function (searchTerm) {
3059 var _this = this;
3060 var inputFormat = mapFlatpickrDateFormatWithFieldType(this.columnDef.type || exports.FieldType.dateIso);
3061 var outputFormat = mapFlatpickrDateFormatWithFieldType(this.columnDef.outputType || this.columnDef.type || exports.FieldType.dateUtc);
3062 var currentLocale = this.translate.currentLang || 'en';
3063 if (currentLocale.length > 2) {
3064 currentLocale = currentLocale.substring(0, 2);
3065 }
3066 var pickerOptions = {
3067 defaultDate: searchTerm || '',
3068 altInput: true,
3069 altFormat: outputFormat,
3070 dateFormat: inputFormat,
3071 wrap: true,
3072 closeOnSelect: true,
3073 locale: (currentLocale !== 'en') ? this.loadFlatpickrLocale(currentLocale) : 'en',
3074 onChange: function (selectedDates, dateStr, instance) {
3075 _this._currentValue = dateStr;
3076 // when using the time picker, we can simulate a keyup event to avoid multiple backend request
3077 // since backend request are only executed after user start typing, changing the time should be treated the same way
3078 if (pickerOptions.enableTime) {
3079 _this.onTriggerEvent(new CustomEvent('keyup'));
3080 }
3081 else {
3082 _this.onTriggerEvent(undefined);
3083 }
3084 }
3085 };
3086 // add the time picker when format is UTC (Z) or has the 'h' (meaning hours)
3087 if (outputFormat && (outputFormat === 'Z' || outputFormat.toLowerCase().includes('h'))) {
3088 pickerOptions.enableTime = true;
3089 }
3090 // merge options with optional user's custom options
3091 var pickerMergedOptions = __assign({}, pickerOptions, this.columnFilter.filterOptions);
3092 var placeholder = (this.gridOptions) ? (this.gridOptions.defaultFilterPlaceholder || '') : '';
3093 if (this.columnFilter && this.columnFilter.placeholder) {
3094 placeholder = this.columnFilter.placeholder;
3095 }
3096 var $filterInputElm = $("<div class=\"flatpickr\"><input type=\"text\" class=\"form-control\" data-input placeholder=\"" + placeholder + "\"></div>");
3097 this.flatInstance = ($filterInputElm[0] && typeof $filterInputElm[0].flatpickr === 'function') ? $filterInputElm[0].flatpickr(pickerMergedOptions) : Flatpickr($filterInputElm, pickerMergedOptions);
3098 return $filterInputElm;
3099 };
3100 CompoundDateFilter.prototype.buildSelectOperatorHtmlString = function () {
3101 var optionValues = this.getOptionValues();
3102 var optionValueString = '';
3103 optionValues.forEach(function (option) {
3104 optionValueString += "<option value=\"" + option.operator + "\" title=\"" + option.description + "\">" + option.operator + "</option>";
3105 });
3106 return "<select class=\"form-control\">" + optionValueString + "</select>";
3107 };
3108 CompoundDateFilter.prototype.getOptionValues = function () {
3109 return [
3110 { operator: '', description: '' },
3111 { operator: '=', description: '' },
3112 { operator: '<', description: '' },
3113 { operator: '<=', description: '' },
3114 { operator: '>', description: '' },
3115 { operator: '>=', description: '' },
3116 { operator: '<>', description: '' }
3117 ];
3118 };
3119 /**
3120 * Create the DOM element
3121 */
3122 CompoundDateFilter.prototype.createDomElement = function (searchTerm) {
3123 var fieldId = this.columnDef && this.columnDef.id;
3124 var $headerElm = this.grid.getHeaderRowColumn(fieldId);
3125 $($headerElm).empty();
3126 // create the DOM Select dropdown for the Operator
3127 this.$selectOperatorElm = $(this.buildSelectOperatorHtmlString());
3128 this.$filterInputElm = this.buildDatePickerInput(searchTerm);
3129 var $filterContainerElm = $("<div class=\"form-group search-filter filter-" + fieldId + "\"></div>");
3130 var $containerInputGroup = $("<div class=\"input-group flatpickr\"></div>");
3131 var $operatorInputGroupAddon = $("<div class=\"input-group-addon input-group-prepend operator\"></div>");
3132 /* the DOM element final structure will be
3133 <div class="input-group">
3134 <div class="input-group-addon input-group-prepend operator">
3135 <select class="form-control"></select>
3136 </div>
3137 <div class=flatpickr>
3138 <input type="text" class="form-control" data-input>
3139 </div>
3140 </div>
3141 */
3142 $operatorInputGroupAddon.append(this.$selectOperatorElm);
3143 $containerInputGroup.append($operatorInputGroupAddon);
3144 $containerInputGroup.append(this.$filterInputElm);
3145 // create the DOM element & add an ID and filter class
3146 $filterContainerElm.append($containerInputGroup);
3147 $filterContainerElm.attr('id', "filter-" + fieldId);
3148 this.$filterInputElm.data('columnId', fieldId);
3149 if (this.operator) {
3150 this.$selectOperatorElm.val(this.operator);
3151 }
3152 // if there's a search term, we will add the "filled" class for styling purposes
3153 if (searchTerm) {
3154 $filterContainerElm.addClass('filled');
3155 this._currentValue = searchTerm;
3156 }
3157 // append the new DOM element to the header row
3158 if ($filterContainerElm && typeof $filterContainerElm.appendTo === 'function') {
3159 $filterContainerElm.appendTo($headerElm);
3160 }
3161 return $filterContainerElm;
3162 };
3163 CompoundDateFilter.prototype.loadFlatpickrLocale = function (locale) {
3164 // change locale if needed, Flatpickr reference: https://chmln.github.io/flatpickr/localization/
3165 if (this.gridOptions && this.gridOptions.params && this.gridOptions.params.flapickrLocale) {
3166 return this.gridOptions.params.flapickrLocale;
3167 }
3168 else if (locale !== 'en') {
3169 var localeDefault = require("flatpickr/dist/l10n/" + locale + ".js").default;
3170 return (localeDefault && localeDefault[locale]) ? localeDefault[locale] : 'en';
3171 }
3172 return 'en';
3173 };
3174 CompoundDateFilter.prototype.onTriggerEvent = function (e) {
3175 if (this._clearFilterTriggered) {
3176 this.callback(e, { columnDef: this.columnDef, clearFilterTriggered: this._clearFilterTriggered, shouldTriggerQuery: this._shouldTriggerQuery });
3177 this.$filterElm.removeClass('filled');
3178 }
3179 else {
3180 var selectedOperator = this.$selectOperatorElm.find('option:selected').text();
3181 (this._currentValue) ? this.$filterElm.addClass('filled') : this.$filterElm.removeClass('filled');
3182 this.callback(e, { columnDef: this.columnDef, searchTerms: (this._currentValue ? [this._currentValue] : null), operator: selectedOperator || '', shouldTriggerQuery: this._shouldTriggerQuery });
3183 }
3184 // reset both flags for next use
3185 this._clearFilterTriggered = false;
3186 this._shouldTriggerQuery = true;
3187 };
3188 CompoundDateFilter.prototype.hide = function () {
3189 if (this.flatInstance && typeof this.flatInstance.close === 'function') {
3190 this.flatInstance.close();
3191 }
3192 };
3193 CompoundDateFilter.prototype.show = function () {
3194 if (this.flatInstance && typeof this.flatInstance.open === 'function') {
3195 this.flatInstance.open();
3196 }
3197 };
3198 return CompoundDateFilter;
3199 }());
3200
3201 var CompoundInputFilter = /** @class */ (function () {
3202 function CompoundInputFilter(translate) {
3203 this.translate = translate;
3204 this._clearFilterTriggered = false;
3205 this._shouldTriggerQuery = true;
3206 this._inputType = 'text';
3207 }
3208 Object.defineProperty(CompoundInputFilter.prototype, "gridOptions", {
3209 /** Getter for the Grid Options pulled through the Grid Object */
3210 get: function () {
3211 return (this.grid && this.grid.getOptions) ? this.grid.getOptions() : {};
3212 },
3213 enumerable: true,
3214 configurable: true
3215 });
3216 Object.defineProperty(CompoundInputFilter.prototype, "columnFilter", {
3217 /** Getter for the Column Filter */
3218 get: function () {
3219 return this.columnDef && this.columnDef.filter || {};
3220 },
3221 enumerable: true,
3222 configurable: true
3223 });
3224 Object.defineProperty(CompoundInputFilter.prototype, "inputType", {
3225 /** Getter of input type (text, number, password) */
3226 get: function () {
3227 return this._inputType;
3228 },
3229 /** Setter of input type (text, number, password) */
3230 set: function (type) {
3231 this._inputType = type;
3232 },
3233 enumerable: true,
3234 configurable: true
3235 });
3236 Object.defineProperty(CompoundInputFilter.prototype, "operator", {
3237 /** Getter of the Operator to use when doing the filter comparing */
3238 get: function () {
3239 return this._operator || exports.OperatorType.empty;
3240 },
3241 /** Getter of the Operator to use when doing the filter comparing */
3242 set: function (op) {
3243 this._operator = op;
3244 },
3245 enumerable: true,
3246 configurable: true
3247 });
3248 /**
3249 * Initialize the Filter
3250 */
3251 CompoundInputFilter.prototype.init = function (args) {
3252 var _this = this;
3253 this.grid = args.grid;
3254 this.callback = args.callback;
3255 this.columnDef = args.columnDef;
3256 this.operator = args.operator;
3257 this.searchTerms = args.searchTerms || [];
3258 // filter input can only have 1 search term, so we will use the 1st array index if it exist
3259 var searchTerm = (Array.isArray(this.searchTerms) && this.searchTerms[0]) || '';
3260 // step 1, create the DOM Element of the filter which contain the compound Operator+Input
3261 // and initialize it if searchTerms is filled
3262 this.$filterElm = this.createDomElement(searchTerm);
3263 // step 3, subscribe to the keyup event and run the callback when that happens
3264 // also add/remove "filled" class for styling purposes
3265 this.$filterInputElm.on('keyup input change', function (e) {
3266 _this.onTriggerEvent(e);
3267 });
3268 this.$selectOperatorElm.on('change', function (e) {
3269 _this.onTriggerEvent(e);
3270 });
3271 };
3272 /**
3273 * Clear the filter value
3274 */
3275 CompoundInputFilter.prototype.clear = function (shouldTriggerQuery) {
3276 if (shouldTriggerQuery === void 0) { shouldTriggerQuery = true; }
3277 if (this.$filterElm && this.$selectOperatorElm) {
3278 this._clearFilterTriggered = true;
3279 this._shouldTriggerQuery = shouldTriggerQuery;
3280 this.searchTerms = [];
3281 this.$selectOperatorElm.val(0);
3282 this.$filterInputElm.val('');
3283 this.onTriggerEvent(null);
3284 }
3285 };
3286 /**
3287 * destroy the filter
3288 */
3289 CompoundInputFilter.prototype.destroy = function () {
3290 if (this.$filterElm && this.$selectOperatorElm) {
3291 this.$filterElm.off('keyup input change').remove();
3292 this.$selectOperatorElm.off('change');
3293 }
3294 };
3295 /**
3296 * Set value(s) on the DOM element
3297 */
3298 CompoundInputFilter.prototype.setValues = function (values) {
3299 if (values && Array.isArray(values)) {
3300 this.$filterElm.val(values[0]);
3301 }
3302 };
3303 //
3304 // private functions
3305 // ------------------
3306 CompoundInputFilter.prototype.buildInputHtmlString = function () {
3307 var placeholder = (this.gridOptions) ? (this.gridOptions.defaultFilterPlaceholder || '') : '';
3308 if (this.columnFilter && this.columnFilter.placeholder) {
3309 placeholder = this.columnFilter.placeholder;
3310 }
3311 return "<input type=\"" + (this._inputType || 'text') + "\" role=\"presentation\" autocomplete=\"off\" class=\"form-control\" placeholder=\"" + placeholder + "\" /><span></span>";
3312 };
3313 CompoundInputFilter.prototype.buildSelectOperatorHtmlString = function () {
3314 var optionValues = this.getOptionValues();
3315 var optionValueString = '';
3316 optionValues.forEach(function (option) {
3317 optionValueString += "<option value=\"" + option.operator + "\" title=\"" + option.description + "\">" + option.operator + "</option>";
3318 });
3319 return "<select class=\"form-control\">" + optionValueString + "</select>";
3320 };
3321 CompoundInputFilter.prototype.getOptionValues = function () {
3322 var type = (this.columnDef.type && this.columnDef.type) ? this.columnDef.type : exports.FieldType.string;
3323 var optionValues = [];
3324 switch (type) {
3325 case exports.FieldType.string:
3326 optionValues = [
3327 { operator: '', description: this.translate.instant('CONTAINS') },
3328 { operator: '=', description: this.translate.instant('EQUALS') },
3329 { operator: 'a*', description: this.translate.instant('STARTS_WITH') },
3330 { operator: '*z', description: this.translate.instant('ENDS_WITH') },
3331 ];
3332 break;
3333 default:
3334 optionValues = [
3335 { operator: '', description: this.translate.instant('CONTAINS') },
3336 { operator: '=', description: '' },
3337 { operator: '<', description: '' },
3338 { operator: '<=', description: '' },
3339 { operator: '>', description: '' },
3340 { operator: '>=', description: '' },
3341 { operator: '<>', description: '' }
3342 ];
3343 break;
3344 }
3345 return optionValues;
3346 };
3347 /**
3348 * Create the DOM element
3349 */
3350 CompoundInputFilter.prototype.createDomElement = function (searchTerm) {
3351 var fieldId = this.columnDef && this.columnDef.id;
3352 var $headerElm = this.grid.getHeaderRowColumn(fieldId);
3353 $($headerElm).empty();
3354 // create the DOM Select dropdown for the Operator
3355 this.$selectOperatorElm = $(this.buildSelectOperatorHtmlString());
3356 this.$filterInputElm = $(this.buildInputHtmlString());
3357 var $filterContainerElm = $("<div class=\"form-group search-filter filter-" + fieldId + "\"></div>");
3358 var $containerInputGroup = $("<div class=\"input-group\"></div>");
3359 var $operatorInputGroupAddon = $("<div class=\"input-group-addon input-group-prepend operator\"></div>");
3360 /* the DOM element final structure will be
3361 <div class="input-group">
3362 <div class="input-group-addon input-group-prepend operator">
3363 <select class="form-control"></select>
3364 </div>
3365 <input class="form-control" type="text" />
3366 </div>
3367 */
3368 $operatorInputGroupAddon.append(this.$selectOperatorElm);
3369 $containerInputGroup.append($operatorInputGroupAddon);
3370 $containerInputGroup.append(this.$filterInputElm);
3371 // create the DOM element & add an ID and filter class
3372 $filterContainerElm.append($containerInputGroup);
3373 $filterContainerElm.attr('id', "filter-" + fieldId);
3374 this.$filterInputElm.val(searchTerm);
3375 this.$filterInputElm.data('columnId', fieldId);
3376 if (this.operator) {
3377 this.$selectOperatorElm.val(this.operator);
3378 }
3379 // if there's a search term, we will add the "filled" class for styling purposes
3380 if (searchTerm) {
3381 $filterContainerElm.addClass('filled');
3382 }
3383 // append the new DOM element to the header row
3384 if ($filterContainerElm && typeof $filterContainerElm.appendTo === 'function') {
3385 $filterContainerElm.appendTo($headerElm);
3386 }
3387 return $filterContainerElm;
3388 };
3389 CompoundInputFilter.prototype.onTriggerEvent = function (e) {
3390 if (this._clearFilterTriggered) {
3391 this.callback(e, { columnDef: this.columnDef, clearFilterTriggered: this._clearFilterTriggered, shouldTriggerQuery: this._shouldTriggerQuery });
3392 this.$filterElm.removeClass('filled');
3393 }
3394 else {
3395 var selectedOperator = this.$selectOperatorElm.find('option:selected').text();
3396 var value = this.$filterInputElm.val();
3397 var enableWhiteSpaceTrim = this.gridOptions.enableFilterTrimWhiteSpace || this.columnFilter.enableTrimWhiteSpace;
3398 if (typeof value === 'string' && enableWhiteSpaceTrim) {
3399 value = value.trim();
3400 }
3401 (value !== null && value !== undefined && value !== '') ? this.$filterElm.addClass('filled') : this.$filterElm.removeClass('filled');
3402 this.callback(e, { columnDef: this.columnDef, searchTerms: (value ? [value] : null), operator: selectedOperator || '', shouldTriggerQuery: this._shouldTriggerQuery });
3403 }
3404 // reset both flags for next use
3405 this._clearFilterTriggered = false;
3406 this._shouldTriggerQuery = true;
3407 };
3408 return CompoundInputFilter;
3409 }());
3410
3411 var CompoundInputNumberFilter = /** @class */ (function (_super) {
3412 __extends(CompoundInputNumberFilter, _super);
3413 /** Initialize the Filter */
3414 function CompoundInputNumberFilter(translate) {
3415 var _this = _super.call(this, translate) || this;
3416 _this.translate = translate;
3417 _this.inputType = 'number';
3418 return _this;
3419 }
3420 return CompoundInputNumberFilter;
3421 }(CompoundInputFilter));
3422
3423 var CompoundInputPasswordFilter = /** @class */ (function (_super) {
3424 __extends(CompoundInputPasswordFilter, _super);
3425 /** Initialize the Filter */
3426 function CompoundInputPasswordFilter(translate) {
3427 var _this = _super.call(this, translate) || this;
3428 _this.translate = translate;
3429 _this.inputType = 'password';
3430 return _this;
3431 }
3432 return CompoundInputPasswordFilter;
3433 }(CompoundInputFilter));
3434
3435 var DEFAULT_MIN_VALUE = 0;
3436 var DEFAULT_MAX_VALUE = 100;
3437 var DEFAULT_STEP = 1;
3438 var CompoundSliderFilter = /** @class */ (function () {
3439 function CompoundSliderFilter() {
3440 this._clearFilterTriggered = false;
3441 this._shouldTriggerQuery = true;
3442 }
3443 Object.defineProperty(CompoundSliderFilter.prototype, "gridOptions", {
3444 /** Getter for the Grid Options pulled through the Grid Object */
3445 get: function () {
3446 return (this.grid && this.grid.getOptions) ? this.grid.getOptions() : {};
3447 },
3448 enumerable: true,
3449 configurable: true
3450 });
3451 Object.defineProperty(CompoundSliderFilter.prototype, "filterParams", {
3452 /** Getter for the Filter Generic Params */
3453 get: function () {
3454 return this.columnDef && this.columnDef.filter && this.columnDef.filter.params || {};
3455 },
3456 enumerable: true,
3457 configurable: true
3458 });
3459 Object.defineProperty(CompoundSliderFilter.prototype, "filterProperties", {
3460 /** Getter for the `filter` properties */
3461 get: function () {
3462 return this.columnDef && this.columnDef.filter;
3463 },
3464 enumerable: true,
3465 configurable: true
3466 });
3467 Object.defineProperty(CompoundSliderFilter.prototype, "operator", {
3468 get: function () {
3469 return this._operator || exports.OperatorType.empty;
3470 },
3471 set: function (op) {
3472 this._operator = op;
3473 },
3474 enumerable: true,
3475 configurable: true
3476 });
3477 /**
3478 * Initialize the Filter
3479 */
3480 CompoundSliderFilter.prototype.init = function (args) {
3481 var _this = this;
3482 if (args) {
3483 this.grid = args.grid;
3484 this.callback = args.callback;
3485 this.columnDef = args.columnDef;
3486 this.operator = args.operator || '';
3487 this.searchTerms = args.searchTerms || [];
3488 // define the input & slider number IDs
3489 this._elementRangeInputId = "rangeInput_" + this.columnDef.field;
3490 this._elementRangeOutputId = "rangeOutput_" + this.columnDef.field;
3491 // filter input can only have 1 search term, so we will use the 1st array index if it exist
3492 var searchTerm = (Array.isArray(this.searchTerms) && this.searchTerms[0]) || '';
3493 // step 1, create the DOM Element of the filter which contain the compound Operator+Input
3494 // and initialize it if searchTerm is filled
3495 this.$filterElm = this.createDomElement(searchTerm);
3496 // step 3, subscribe to the keyup event and run the callback when that happens
3497 // also add/remove "filled" class for styling purposes
3498 this.$filterInputElm.change(function (e) {
3499 _this.onTriggerEvent(e);
3500 });
3501 this.$selectOperatorElm.change(function (e) {
3502 _this.onTriggerEvent(e);
3503 });
3504 // if user chose to display the slider number on the right side, then update it every time it changes
3505 // we need to use both "input" and "change" event to be all cross-browser
3506 if (!this.filterParams.hideSliderNumber) {
3507 this.$filterInputElm.on('input change', function (e) {
3508 var value = e && e.target && e.target.value || '';
3509 if (value) {
3510 document.getElementById(_this._elementRangeOutputId).innerHTML = value;
3511 }
3512 });
3513 }
3514 }
3515 };
3516 /**
3517 * Clear the filter value
3518 */
3519 CompoundSliderFilter.prototype.clear = function (shouldTriggerQuery) {
3520 if (shouldTriggerQuery === void 0) { shouldTriggerQuery = true; }
3521 if (this.$filterElm && this.$selectOperatorElm) {
3522 this._clearFilterTriggered = true;
3523 this._shouldTriggerQuery = shouldTriggerQuery;
3524 this.searchTerms = [];
3525 var clearedValue = this.filterParams.hasOwnProperty('sliderStartValue') ? this.filterParams.sliderStartValue : DEFAULT_MIN_VALUE;
3526 this.$selectOperatorElm.val(0);
3527 this.$filterInputElm.val(clearedValue);
3528 if (!this.filterParams.hideSliderNumber) {
3529 this.$containerInputGroupElm.children('div.input-group-addon.input-group-append').children().last().html(clearedValue);
3530 }
3531 this.onTriggerEvent(undefined);
3532 this.$filterElm.removeClass('filled');
3533 }
3534 };
3535 /**
3536 * destroy the filter
3537 */
3538 CompoundSliderFilter.prototype.destroy = function () {
3539 if (this.$filterElm) {
3540 this.$filterElm.off('input change').remove();
3541 }
3542 };
3543 /**
3544 * Set value(s) on the DOM element
3545 */
3546 CompoundSliderFilter.prototype.setValues = function (values) {
3547 if (values && Array.isArray(values)) {
3548 this.$filterInputElm.val(values[0]);
3549 this.$containerInputGroupElm.children('div.input-group-addon.input-group-append').children().last().html(values[0]);
3550 }
3551 };
3552 //
3553 // private functions
3554 // ------------------
3555 /** Build HTML Template for the input range (slider) */
3556 CompoundSliderFilter.prototype.buildTemplateHtmlString = function () {
3557 var minValue = this.filterProperties.hasOwnProperty('minValue') ? this.filterProperties.minValue : DEFAULT_MIN_VALUE;
3558 var maxValue = this.filterProperties.hasOwnProperty('maxValue') ? this.filterProperties.maxValue : DEFAULT_MAX_VALUE;
3559 var defaultValue = this.filterParams.hasOwnProperty('sliderStartValue') ? this.filterParams.sliderStartValue : minValue;
3560 var step = this.filterProperties.hasOwnProperty('valueStep') ? this.filterProperties.valueStep : DEFAULT_STEP;
3561 return "<input type=\"range\" id=\"" + this._elementRangeInputId + "\"\n name=\"" + this._elementRangeInputId + "\"\n defaultValue=\"" + defaultValue + "\" min=\"" + minValue + "\" max=\"" + maxValue + "\" step=\"" + step + "\"\n class=\"form-control slider-filter-input range compound-slider\" />";
3562 };
3563 /** Build HTML Template for the text (number) that is shown appended to the slider */
3564 CompoundSliderFilter.prototype.buildTemplateSliderTextHtmlString = function () {
3565 var minValue = this.filterProperties.hasOwnProperty('minValue') ? this.filterProperties.minValue : DEFAULT_MIN_VALUE;
3566 var defaultValue = this.filterParams.hasOwnProperty('sliderStartValue') ? this.filterParams.sliderStartValue : minValue;
3567 return "<div class=\"input-group-addon input-group-append slider-value\"><span class=\"input-group-text\" id=\"" + this._elementRangeOutputId + "\">" + defaultValue + "</span></div>";
3568 };
3569 /** Build HTML Template select dropdown (operator) */
3570 CompoundSliderFilter.prototype.buildSelectOperatorHtmlString = function () {
3571 var optionValues = this.getOptionValues();
3572 var optionValueString = '';
3573 optionValues.forEach(function (option) {
3574 optionValueString += "<option value=\"" + option.operator + "\" title=\"" + option.description + "\">" + option.operator + "</option>";
3575 });
3576 return "<select class=\"form-control\">" + optionValueString + "</select>";
3577 };
3578 /** Get the available operator option values */
3579 CompoundSliderFilter.prototype.getOptionValues = function () {
3580 return [
3581 { operator: '', description: '' },
3582 { operator: '=', description: '' },
3583 { operator: '<', description: '' },
3584 { operator: '<=', description: '' },
3585 { operator: '>', description: '' },
3586 { operator: '>=', description: '' },
3587 { operator: '<>', description: '' }
3588 ];
3589 };
3590 /**
3591 * Create the DOM element
3592 */
3593 CompoundSliderFilter.prototype.createDomElement = function (searchTerm) {
3594 var fieldId = this.columnDef && this.columnDef.id;
3595 var searchTermInput = (searchTerm || '0');
3596 var $headerElm = this.grid.getHeaderRowColumn(this.columnDef.id);
3597 $($headerElm).empty();
3598 // create the DOM Select dropdown for the Operator
3599 this.$selectOperatorElm = $(this.buildSelectOperatorHtmlString());
3600 this.$filterInputElm = $(this.buildTemplateHtmlString());
3601 var $filterContainerElm = $("<div class=\"form-group search-filter filter-" + fieldId + "\"></div>");
3602 this.$containerInputGroupElm = $("<div class=\"input-group search-filter filter-" + fieldId + "\"></div>");
3603 var $operatorInputGroupAddon = $("<span class=\"input-group-addon input-group-prepend operator\"></span>");
3604 /* the DOM element final structure will be
3605 <div class="input-group">
3606 <div class="input-group-addon input-group-prepend operator">
3607 <select class="form-control"></select>
3608 </div>
3609 <input class="form-control" type="text" />
3610 <div class="input-group-addon input-group-prepend" id="rangeOuput_percentComplete"><span class="input-group-text">0</span></div>
3611 </div>
3612 */
3613 $operatorInputGroupAddon.append(this.$selectOperatorElm);
3614 this.$containerInputGroupElm.append($operatorInputGroupAddon);
3615 this.$containerInputGroupElm.append(this.$filterInputElm);
3616 if (!this.filterParams.hideSliderNumber) {
3617 var $sliderTextInputAppendAddon = $(this.buildTemplateSliderTextHtmlString());
3618 $sliderTextInputAppendAddon.children().html(searchTermInput);
3619 this.$containerInputGroupElm.append($sliderTextInputAppendAddon);
3620 }
3621 // create the DOM element & add an ID and filter class
3622 $filterContainerElm.append(this.$containerInputGroupElm);
3623 $filterContainerElm.attr('id', "filter-" + fieldId);
3624 this.$filterInputElm.val(searchTermInput);
3625 this.$filterInputElm.data('columnId', fieldId);
3626 if (this.operator) {
3627 this.$selectOperatorElm.val(this.operator);
3628 }
3629 // if there's a search term, we will add the "filled" class for styling purposes
3630 if (searchTerm) {
3631 $filterContainerElm.addClass('filled');
3632 }
3633 // append the new DOM element to the header row
3634 if ($filterContainerElm && typeof $filterContainerElm.appendTo === 'function') {
3635 $filterContainerElm.appendTo($headerElm);
3636 }
3637 return $filterContainerElm;
3638 };
3639 CompoundSliderFilter.prototype.onTriggerEvent = function (e) {
3640 if (this._clearFilterTriggered) {
3641 this.callback(e, { columnDef: this.columnDef, clearFilterTriggered: this._clearFilterTriggered, shouldTriggerQuery: this._shouldTriggerQuery });
3642 }
3643 else {
3644 var selectedOperator = this.$selectOperatorElm.find('option:selected').text();
3645 var value = this.$filterInputElm.val();
3646 (value) ? this.$filterElm.addClass('filled') : this.$filterElm.removeClass('filled');
3647 this.callback(e, { columnDef: this.columnDef, searchTerms: (value ? [value] : null), operator: selectedOperator || '', shouldTriggerQuery: this._shouldTriggerQuery });
3648 }
3649 // reset both flags for next use
3650 this._clearFilterTriggered = false;
3651 this._shouldTriggerQuery = true;
3652 };
3653 return CompoundSliderFilter;
3654 }());
3655
3656 var InputFilter = /** @class */ (function () {
3657 function InputFilter() {
3658 this._clearFilterTriggered = false;
3659 this._shouldTriggerQuery = true;
3660 this._inputType = 'text';
3661 }
3662 Object.defineProperty(InputFilter.prototype, "columnFilter", {
3663 /** Getter for the Column Filter */
3664 get: function () {
3665 return this.columnDef && this.columnDef.filter || {};
3666 },
3667 enumerable: true,
3668 configurable: true
3669 });
3670 Object.defineProperty(InputFilter.prototype, "inputType", {
3671 /** Getter of input type (text, number, password) */
3672 get: function () {
3673 return this._inputType;
3674 },
3675 /** Setter of input type (text, number, password) */
3676 set: function (type) {
3677 this._inputType = type;
3678 },
3679 enumerable: true,
3680 configurable: true
3681 });
3682 Object.defineProperty(InputFilter.prototype, "operator", {
3683 /** Getter of the Operator to use when doing the filter comparing */
3684 get: function () {
3685 return this.columnDef && this.columnDef.filter && this.columnDef.filter.operator || '';
3686 },
3687 enumerable: true,
3688 configurable: true
3689 });
3690 Object.defineProperty(InputFilter.prototype, "gridOptions", {
3691 /** Getter for the Grid Options pulled through the Grid Object */
3692 get: function () {
3693 return (this.grid && this.grid.getOptions) ? this.grid.getOptions() : {};
3694 },
3695 enumerable: true,
3696 configurable: true
3697 });
3698 /**
3699 * Initialize the Filter
3700 */
3701 InputFilter.prototype.init = function (args) {
3702 var _this = this;
3703 this.grid = args.grid;
3704 this.callback = args.callback;
3705 this.columnDef = args.columnDef;
3706 this.searchTerms = args.searchTerms || [];
3707 // filter input can only have 1 search term, so we will use the 1st array index if it exist
3708 var searchTerm = (Array.isArray(this.searchTerms) && this.searchTerms[0]) || '';
3709 // step 1, create HTML string template
3710 var filterTemplate = this.buildTemplateHtmlString();
3711 // step 2, create the DOM Element of the filter & initialize it if searchTerm is filled
3712 this.$filterElm = this.createDomElement(filterTemplate, searchTerm);
3713 // step 3, subscribe to the keyup event and run the callback when that happens
3714 // also add/remove "filled" class for styling purposes
3715 this.$filterElm.on('keyup input change', function (e) {
3716 var value = e && e.target && e.target.value || '';
3717 var enableWhiteSpaceTrim = _this.gridOptions.enableFilterTrimWhiteSpace || _this.columnFilter.enableTrimWhiteSpace;
3718 if (typeof value === 'string' && enableWhiteSpaceTrim) {
3719 value = value.trim();
3720 }
3721 if (_this._clearFilterTriggered) {
3722 _this.callback(e, { columnDef: _this.columnDef, clearFilterTriggered: _this._clearFilterTriggered, shouldTriggerQuery: _this._shouldTriggerQuery });
3723 _this.$filterElm.removeClass('filled');
3724 }
3725 else {
3726 value === '' ? _this.$filterElm.removeClass('filled') : _this.$filterElm.addClass('filled');
3727 _this.callback(e, { columnDef: _this.columnDef, operator: _this.operator, searchTerms: [value], shouldTriggerQuery: _this._shouldTriggerQuery });
3728 }
3729 // reset both flags for next use
3730 _this._clearFilterTriggered = false;
3731 _this._shouldTriggerQuery = true;
3732 });
3733 };
3734 /**
3735 * Clear the filter value
3736 */
3737 InputFilter.prototype.clear = function (shouldTriggerQuery) {
3738 if (shouldTriggerQuery === void 0) { shouldTriggerQuery = true; }
3739 if (this.$filterElm) {
3740 this._clearFilterTriggered = true;
3741 this._shouldTriggerQuery = shouldTriggerQuery;
3742 this.searchTerms = [];
3743 this.$filterElm.val('');
3744 this.$filterElm.trigger('keyup');
3745 }
3746 };
3747 /**
3748 * destroy the filter
3749 */
3750 InputFilter.prototype.destroy = function () {
3751 if (this.$filterElm) {
3752 this.$filterElm.off('keyup input change').remove();
3753 }
3754 };
3755 /**
3756 * Set value(s) on the DOM element
3757 */
3758 InputFilter.prototype.setValues = function (values) {
3759 if (values) {
3760 this.$filterElm.val(values);
3761 }
3762 };
3763 //
3764 // protected functions
3765 // ------------------
3766 /**
3767 * Create the HTML template as a string
3768 */
3769 InputFilter.prototype.buildTemplateHtmlString = function () {
3770 var fieldId = this.columnDef && this.columnDef.id;
3771 var placeholder = (this.gridOptions) ? (this.gridOptions.defaultFilterPlaceholder || '') : '';
3772 if (this.columnFilter && this.columnFilter.placeholder) {
3773 placeholder = this.columnFilter.placeholder;
3774 }
3775 return "<input type=\"" + (this._inputType || 'text') + "\" role=\"presentation\" autocomplete=\"off\" class=\"form-control search-filter filter-" + fieldId + "\" placeholder=\"" + placeholder + "\"><span></span>";
3776 };
3777 /**
3778 * From the html template string, create a DOM element
3779 * @param filterTemplate
3780 */
3781 InputFilter.prototype.createDomElement = function (filterTemplate, searchTerm) {
3782 var fieldId = this.columnDef && this.columnDef.id;
3783 var $headerElm = this.grid.getHeaderRowColumn(fieldId);
3784 $($headerElm).empty();
3785 // create the DOM element & add an ID and filter class
3786 var $filterElm = $(filterTemplate);
3787 $filterElm.val(searchTerm);
3788 $filterElm.attr('id', "filter-" + fieldId);
3789 $filterElm.data('columnId', fieldId);
3790 // if there's a search term, we will add the "filled" class for styling purposes
3791 if (searchTerm) {
3792 $filterElm.addClass('filled');
3793 }
3794 // append the new DOM element to the header row
3795 if ($filterElm && typeof $filterElm.appendTo === 'function') {
3796 $filterElm.appendTo($headerElm);
3797 }
3798 return $filterElm;
3799 };
3800 return InputFilter;
3801 }());
3802
3803 var InputMaskFilter = /** @class */ (function (_super) {
3804 __extends(InputMaskFilter, _super);
3805 /** Initialize the Filter */
3806 function InputMaskFilter() {
3807 var _this = _super.call(this) || this;
3808 _this.inputType = 'text';
3809 return _this;
3810 }
3811 Object.defineProperty(InputMaskFilter.prototype, "inputMask", {
3812 /** Getter of the input mask, when provided */
3813 get: function () {
3814 return this.columnDef.params && this.columnDef.params && this.columnDef.params.mask;
3815 },
3816 enumerable: true,
3817 configurable: true
3818 });
3819 /**
3820 * Override the Filter init used by SlickGrid
3821 */
3822 InputMaskFilter.prototype.init = function (args) {
3823 var _this = this;
3824 if (!args) {
3825 throw new Error('[Angular-SlickGrid] A filter must always have an "init()" with valid arguments.');
3826 }
3827 this.grid = args.grid;
3828 this.callback = args.callback;
3829 this.columnDef = args.columnDef;
3830 this.searchTerms = args.searchTerms || [];
3831 // filter input can only have 1 search term, so we will use the 1st array index if it exist
3832 var searchTerm = (Array.isArray(this.searchTerms) && this.searchTerms[0]) || '';
3833 // step 1, create HTML string template
3834 var filterTemplate = this.buildTemplateHtmlString();
3835 // step 2, create the DOM Element of the filter & initialize it if searchTerm is filled
3836 this.$filterElm = this.createDomElement(filterTemplate, searchTerm);
3837 // step 3, subscribe to the keyup event and run the callback when that happens
3838 // also add/remove "filled" class for styling purposes
3839 this.$filterElm.on('keyup input change', function (e) {
3840 var value = '';
3841 if (e && e.target && e.target.value) {
3842 var targetValue = e.target.value;
3843 var enableWhiteSpaceTrim = _this.gridOptions.enableFilterTrimWhiteSpace || _this.columnFilter.enableTrimWhiteSpace;
3844 if (typeof targetValue === 'string' && enableWhiteSpaceTrim) {
3845 targetValue = targetValue.trim();
3846 }
3847 // if it has a mask, we need to do a bit more work
3848 // and replace the filter string by the masked output without triggering an event
3849 var unmaskedValue = _this.unmaskValue(targetValue);
3850 var maskedValue = _this.maskValue(unmaskedValue);
3851 value = unmaskedValue;
3852 if (e.keyCode >= 48) {
3853 _this.$filterElm.val(maskedValue); // replace filter string with masked string
3854 e.preventDefault();
3855 }
3856 }
3857 if (_this._clearFilterTriggered) {
3858 _this.callback(e, { columnDef: _this.columnDef, clearFilterTriggered: _this._clearFilterTriggered, shouldTriggerQuery: _this._shouldTriggerQuery });
3859 _this.$filterElm.removeClass('filled');
3860 }
3861 else {
3862 _this.$filterElm.addClass('filled');
3863 _this.callback(e, { columnDef: _this.columnDef, operator: _this.operator, searchTerms: [value], shouldTriggerQuery: _this._shouldTriggerQuery });
3864 }
3865 // reset both flags for next use
3866 _this._clearFilterTriggered = false;
3867 _this._shouldTriggerQuery = true;
3868 });
3869 };
3870 /** From a regular string, we will use the mask to output a new string */
3871 InputMaskFilter.prototype.maskValue = function (inputValue) {
3872 var i = 0;
3873 var maskedValue = '';
3874 if (this.inputMask) {
3875 maskedValue = this.inputMask.replace(/[09A]/gi, function (match) {
3876 // only replace the char when the mask is a 0 or 9 for a digit OR the mask is "A" and the char is a non-digit meaning a string char
3877 if (((match === '0' || match === '9') && /\d+/g.test(inputValue[i])) // mask is 0 or 9 and value is a digit
3878 || (match.toUpperCase() === 'A' && /[^\d]+/gi.test(inputValue[i])) // OR mask is an "A" and value is non-digit
3879 ) {
3880 return inputValue[i++] || '';
3881 }
3882 return '';
3883 });
3884 }
3885 return maskedValue;
3886 };
3887 /** From a masked string, we will remove the mask and make a regular string again */
3888 InputMaskFilter.prototype.unmaskValue = function (maskedValue) {
3889 // remove anything else but digits and chars from both the input mask and the input masked value for later comparison
3890 // e.g. (000) 000-0000 would return 0000000000
3891 var valueWithoutSymbols = maskedValue.replace(/[^0-9a-z]*/gi, '');
3892 var maskWithoutSymbols = this.inputMask.replace(/[^0-9a-z]*/gi, '');
3893 // then we can analyze if each char on each indexes equals what the mask requires, if not the char will be disregarded from the output
3894 // basically, if our mask is "0A0" and input value is "2ab", then only "2a" will be returned since the last char "b" is not part of the mask and is invalid
3895 var output = '';
3896 for (var i = 0; i < maskWithoutSymbols.length; i++) {
3897 if (valueWithoutSymbols[i]) {
3898 if (((maskWithoutSymbols[i] === '0' || maskWithoutSymbols[i] === '9') && /\d+/g.test(valueWithoutSymbols[i])) // mask is 0 or 9 and value is a digit
3899 || (maskWithoutSymbols[i].toUpperCase() === 'A' && /[^\d]+/gi.test(valueWithoutSymbols[i])) // OR mask is an "A" and value is non-digit
3900 ) {
3901 output += valueWithoutSymbols[i]; // valid and matches the Mask, so we can add it up to the string output
3902 }
3903 }
3904 }
3905 return output;
3906 };
3907 return InputMaskFilter;
3908 }(InputFilter));
3909
3910 var InputNumberFilter = /** @class */ (function (_super) {
3911 __extends(InputNumberFilter, _super);
3912 /** Initialize the Filter */
3913 function InputNumberFilter() {
3914 var _this = _super.call(this) || this;
3915 _this.inputType = 'number';
3916 return _this;
3917 }
3918 return InputNumberFilter;
3919 }(InputFilter));
3920
3921 var InputPasswordFilter = /** @class */ (function (_super) {
3922 __extends(InputPasswordFilter, _super);
3923 /** Initialize the Filter */
3924 function InputPasswordFilter() {
3925 var _this = _super.call(this) || this;
3926 _this.inputType = 'password';
3927 return _this;
3928 }
3929 return InputPasswordFilter;
3930 }(InputFilter));
3931
3932 var DOMPurify = DOMPurify_; // patch to fix rollup to work
3933 var SelectFilter = /** @class */ (function () {
3934 /**
3935 * Initialize the Filter
3936 */
3937 function SelectFilter(translate, collectionService, isMultipleSelect) {
3938 if (isMultipleSelect === void 0) { isMultipleSelect = true; }
3939 var _this = this;
3940 this.translate = translate;
3941 this.collectionService = collectionService;
3942 this.isMultipleSelect = isMultipleSelect;
3943 this._isFilterFirstRender = true;
3944 this._shouldTriggerQuery = true;
3945 this.isFilled = false;
3946 this.enableTranslateLabel = false;
3947 this.subscriptions = [];
3948 // default options used by this Filter, user can overwrite any of these by passing "otions"
3949 var options = {
3950 autoAdjustDropHeight: true,
3951 autoAdjustDropPosition: true,
3952 autoAdjustDropWidthByTextSize: true,
3953 container: 'body',
3954 filter: false,
3955 maxHeight: 275,
3956 single: true,
3957 textTemplate: function ($elm) {
3958 // render HTML code or not, by default it is sanitized and won't be rendered
3959 var isRenderHtmlEnabled = _this.columnDef && _this.columnDef.filter && _this.columnDef.filter.enableRenderHtml || false;
3960 return isRenderHtmlEnabled ? $elm.text() : $elm.html();
3961 },
3962 onClose: function () {
3963 // we will subscribe to the onClose event for triggering our callback
3964 // also add/remove "filled" class for styling purposes
3965 var selectedItems = _this.$filterElm.multipleSelect('getSelects');
3966 if (Array.isArray(selectedItems) && selectedItems.length > 1 || (selectedItems.length === 1 && selectedItems[0] !== '')) {
3967 _this.isFilled = true;
3968 _this.$filterElm.addClass('filled').siblings('div .search-filter').addClass('filled');
3969 }
3970 else {
3971 _this.isFilled = false;
3972 _this.$filterElm.removeClass('filled');
3973 _this.$filterElm.siblings('div .search-filter').removeClass('filled');
3974 }
3975 _this.callback(undefined, { columnDef: _this.columnDef, operator: _this.operator, searchTerms: selectedItems, shouldTriggerQuery: _this._shouldTriggerQuery });
3976 // reset flag for next use
3977 _this._shouldTriggerQuery = true;
3978 }
3979 };
3980 if (this.isMultipleSelect) {
3981 options.single = false;
3982 options.okButton = true;
3983 options.addTitle = true; // show tooltip of all selected items while hovering the filter
3984 options.countSelected = this.translate.instant('X_OF_Y_SELECTED');
3985 options.allSelected = this.translate.instant('ALL_SELECTED');
3986 options.selectAllText = this.translate.instant('SELECT_ALL');
3987 options.selectAllDelimiter = ['', '']; // remove default square brackets of default text "[Select All]" => "Select All"
3988 }
3989 this.defaultOptions = options;
3990 }
3991 Object.defineProperty(SelectFilter.prototype, "columnFilter", {
3992 /** Getter for the Column Filter itself */
3993 get: function () {
3994 return this.columnDef && this.columnDef.filter;
3995 },
3996 enumerable: true,
3997 configurable: true
3998 });
3999 Object.defineProperty(SelectFilter.prototype, "collectionOptions", {
4000 /** Getter for the Collection Options */
4001 get: function () {
4002 return this.columnDef && this.columnDef.filter && this.columnDef.filter.collectionOptions;
4003 },
4004 enumerable: true,
4005 configurable: true
4006 });
4007 Object.defineProperty(SelectFilter.prototype, "customStructure", {
4008 /** Getter for the Custom Structure if exist */
4009 get: function () {
4010 return this.columnDef && this.columnDef.filter && this.columnDef.filter.customStructure;
4011 },
4012 enumerable: true,
4013 configurable: true
4014 });
4015 Object.defineProperty(SelectFilter.prototype, "gridOptions", {
4016 /** Getter for the Grid Options pulled through the Grid Object */
4017 get: function () {
4018 return (this.grid && this.grid.getOptions) ? this.grid.getOptions() : {};
4019 },
4020 enumerable: true,
4021 configurable: true
4022 });
4023 Object.defineProperty(SelectFilter.prototype, "operator", {
4024 /** Getter for the filter operator */
4025 get: function () {
4026 if (this.columnDef && this.columnDef.filter && this.columnDef.filter.operator) {
4027 return this.columnDef && this.columnDef.filter && this.columnDef.filter.operator;
4028 }
4029 return this.isMultipleSelect ? exports.OperatorType.in : exports.OperatorType.equal;
4030 },
4031 enumerable: true,
4032 configurable: true
4033 });
4034 /**
4035 * Initialize the filter template
4036 */
4037 SelectFilter.prototype.init = function (args, isFilterFirstRender) {
4038 this._isFilterFirstRender = isFilterFirstRender;
4039 this.grid = args.grid;
4040 this.callback = args.callback;
4041 this.columnDef = args.columnDef;
4042 this.searchTerms = args.searchTerms || [];
4043 if (!this.grid || !this.columnDef || !this.columnFilter || (!this.columnFilter.collection && !this.columnFilter.collectionAsync)) {
4044 throw new Error("[Angular-SlickGrid] You need to pass a \"collection\" (or \"collectionAsync\") for the MultipleSelect/SingleSelect Filter to work correctly. Also each option should include a value/label pair (or value/labelKey when using Locale). For example:: { filter: model: Filters.multipleSelect, collection: [{ value: true, label: 'True' }, { value: false, label: 'False'}] }");
4045 }
4046 this.enableTranslateLabel = this.columnFilter.enableTranslateLabel;
4047 this.labelName = this.customStructure && this.customStructure.label || 'label';
4048 this.labelPrefixName = this.customStructure && this.customStructure.labelPrefix || 'labelPrefix';
4049 this.labelSuffixName = this.customStructure && this.customStructure.labelSuffix || 'labelSuffix';
4050 this.optionLabel = this.customStructure && this.customStructure.optionLabel || 'value';
4051 this.valueName = this.customStructure && this.customStructure.value || 'value';
4052 if (this.enableTranslateLabel && (!this.translate || typeof this.translate.instant !== 'function')) {
4053 throw new Error("[select-editor] The ngx-translate TranslateService is required for the Select Filter to work correctly");
4054 }
4055 // always render the Select (dropdown) DOM element, even if user passed a "collectionAsync",
4056 // if that is the case, the Select will simply be without any options but we still have to render it (else SlickGrid would throw an error)
4057 var newCollection = this.columnFilter.collection || [];
4058 this.renderDomElement(newCollection);
4059 // on every Filter which have a "collection" or a "collectionAsync"
4060 // we will add (or replace) a Subject to the "collectionAsync" property so that user has possibility to change the collection
4061 // if "collectionAsync" is already set by the user, it will resolve it first then after it will replace it with a Subject
4062 var collectionAsync = this.columnFilter && this.columnFilter.collectionAsync;
4063 if (collectionAsync) {
4064 this.renderOptionsAsync(collectionAsync); // create Subject after resolve (createCollectionAsyncSubject)
4065 }
4066 };
4067 /**
4068 * Clear the filter values
4069 */
4070 SelectFilter.prototype.clear = function (shouldTriggerQuery) {
4071 if (shouldTriggerQuery === void 0) { shouldTriggerQuery = true; }
4072 if (this.$filterElm && this.$filterElm.multipleSelect) {
4073 // reload the filter element by it's id, to make sure it's still a valid element (because of some issue in the GraphQL example)
4074 this.$filterElm.multipleSelect('setSelects', []);
4075 this.$filterElm.removeClass('filled');
4076 this.$filterElm.siblings('div .search-filter').removeClass('filled');
4077 this.searchTerms = [];
4078 this._shouldTriggerQuery = shouldTriggerQuery;
4079 this.callback(undefined, { columnDef: this.columnDef, clearFilterTriggered: true, shouldTriggerQuery: this._shouldTriggerQuery });
4080 // reset both flags for next use
4081 this._shouldTriggerQuery = true;
4082 }
4083 };
4084 /**
4085 * destroy the filter
4086 */
4087 SelectFilter.prototype.destroy = function () {
4088 if (this.$filterElm) {
4089 // remove event watcher
4090 this.$filterElm.off().remove();
4091 var elementClassName = this.elementName.toString().replace('.', '\\.'); // make sure to escape any dot "." from CSS class to avoid console error
4092 $("[name=" + elementClassName + "].ms-drop").remove();
4093 }
4094 // also dispose of all Subscriptions
4095 this.subscriptions = unsubscribeAllObservables(this.subscriptions);
4096 };
4097 /**
4098 * Set value(s) on the DOM element
4099 */
4100 SelectFilter.prototype.setValues = function (values) {
4101 if (values) {
4102 values = Array.isArray(values) ? values : [values];
4103 this.$filterElm.multipleSelect('setSelects', values);
4104 }
4105 };
4106 //
4107 // protected functions
4108 // ------------------
4109 /**
4110 * user might want to filter certain items of the collection
4111 * @param inputCollection
4112 * @return outputCollection filtered and/or sorted collection
4113 */
4114 SelectFilter.prototype.filterCollection = function (inputCollection) {
4115 var outputCollection = inputCollection;
4116 // user might want to filter certain items of the collection
4117 if (this.columnDef && this.columnFilter && this.columnFilter.collectionFilterBy) {
4118 var filterBy = this.columnFilter.collectionFilterBy;
4119 var filterCollectionBy = this.columnFilter.collectionOptions && this.columnFilter.collectionOptions.filterResultAfterEachPass || null;
4120 outputCollection = this.collectionService.filterCollection(outputCollection, filterBy, filterCollectionBy);
4121 }
4122 return outputCollection;
4123 };
4124 /**
4125 * user might want to sort the collection in a certain way
4126 * @param inputCollection
4127 * @return outputCollection filtered and/or sorted collection
4128 */
4129 SelectFilter.prototype.sortCollection = function (inputCollection) {
4130 var outputCollection = inputCollection;
4131 // user might want to sort the collection
4132 if (this.columnDef && this.columnFilter && this.columnFilter.collectionSortBy) {
4133 var sortBy = this.columnFilter.collectionSortBy;
4134 outputCollection = this.collectionService.sortCollection(this.columnDef, outputCollection, sortBy, this.enableTranslateLabel);
4135 }
4136 return outputCollection;
4137 };
4138 SelectFilter.prototype.renderOptionsAsync = function (collectionAsync) {
4139 return __awaiter(this, void 0, void 0, function () {
4140 var awaitedCollection;
4141 return __generator(this, function (_a) {
4142 switch (_a.label) {
4143 case 0:
4144 awaitedCollection = [];
4145 if (!collectionAsync) return [3 /*break*/, 2];
4146 return [4 /*yield*/, castToPromise(collectionAsync)];
4147 case 1:
4148 awaitedCollection = _a.sent();
4149 this.renderDomElementFromCollectionAsync(awaitedCollection);
4150 // because we accept Promises & HttpClient Observable only execute once
4151 // we will re-create an RxJs Subject which will replace the "collectionAsync" which got executed once anyway
4152 // doing this provide the user a way to call a "collectionAsync.next()"
4153 this.createCollectionAsyncSubject();
4154 _a.label = 2;
4155 case 2: return [2 /*return*/];
4156 }
4157 });
4158 });
4159 };
4160 /** Create or recreate an Observable Subject and reassign it to the "collectionAsync" object so user can call a "collectionAsync.next()" on it */
4161 SelectFilter.prototype.createCollectionAsyncSubject = function () {
4162 var _this = this;
4163 var newCollectionAsync = new rxjs.Subject();
4164 this.columnFilter.collectionAsync = newCollectionAsync;
4165 this.subscriptions.push(newCollectionAsync.subscribe(function (collection) { return _this.renderDomElementFromCollectionAsync(collection); }));
4166 };
4167 /**
4168 * When user use a CollectionAsync we will use the returned collection to render the filter DOM element
4169 * and reinitialize filter collection with this new collection
4170 */
4171 SelectFilter.prototype.renderDomElementFromCollectionAsync = function (collection) {
4172 if (this.collectionOptions && this.collectionOptions.collectionInObjectProperty) {
4173 collection = getDescendantProperty(collection, this.collectionOptions.collectionInObjectProperty);
4174 }
4175 if (!Array.isArray(collection)) {
4176 throw new Error('Something went wrong while trying to pull the collection from the "collectionAsync" call in the Select Filter, the collection is not a valid array.');
4177 }
4178 // copy over the array received from the async call to the "collection" as the new collection to use
4179 // this has to be BEFORE the `collectionObserver().subscribe` to avoid going into an infinite loop
4180 this.columnFilter.collection = collection;
4181 // recreate Multiple Select after getting async collection
4182 this.renderDomElement(collection);
4183 };
4184 SelectFilter.prototype.renderDomElement = function (collection) {
4185 if (!Array.isArray(collection) && this.collectionOptions && this.collectionOptions.collectionInObjectProperty) {
4186 collection = getDescendantProperty(collection, this.collectionOptions.collectionInObjectProperty);
4187 }
4188 if (!Array.isArray(collection)) {
4189 throw new Error('The "collection" passed to the Select Filter is not a valid array');
4190 }
4191 // user can optionally add a blank entry at the beginning of the collection
4192 if (this.collectionOptions && this.collectionOptions.addBlankEntry && this._isFilterFirstRender) {
4193 collection.unshift(this.createBlankEntry());
4194 }
4195 var newCollection = collection;
4196 // user might want to filter and/or sort certain items of the collection
4197 newCollection = this.filterCollection(newCollection);
4198 newCollection = this.sortCollection(newCollection);
4199 // step 1, create HTML string template
4200 var filterTemplate = this.buildTemplateHtmlString(newCollection, this.searchTerms);
4201 // step 2, create the DOM Element of the filter & pre-load search terms
4202 // also subscribe to the onClose event
4203 this.createDomElement(filterTemplate);
4204 };
4205 /**
4206 * Create the HTML template as a string
4207 */
4208 SelectFilter.prototype.buildTemplateHtmlString = function (optionCollection, searchTerms) {
4209 var _this = this;
4210 var options = '';
4211 var fieldId = this.columnDef && this.columnDef.id;
4212 var separatorBetweenLabels = this.collectionOptions && this.collectionOptions.separatorBetweenTextLabels || '';
4213 var isRenderHtmlEnabled = this.columnFilter && this.columnFilter.enableRenderHtml || false;
4214 var sanitizedOptions = this.gridOptions && this.gridOptions.sanitizeHtmlOptions || {};
4215 // collection could be an Array of Strings OR Objects
4216 if (optionCollection.every(function (x) { return typeof x === 'string'; })) {
4217 optionCollection.forEach(function (option) {
4218 var selected = (searchTerms.findIndex(function (term) { return term === option; }) >= 0) ? 'selected' : '';
4219 options += "<option value=\"" + option + "\" label=\"" + option + "\" " + selected + ">" + option + "</option>";
4220 // if there's at least 1 search term found, we will add the "filled" class for styling purposes
4221 if (selected) {
4222 _this.isFilled = true;
4223 }
4224 });
4225 }
4226 else {
4227 // array of objects will require a label/value pair unless a customStructure is passed
4228 optionCollection.forEach(function (option) {
4229 if (!option || (option[_this.labelName] === undefined && option.labelKey === undefined)) {
4230 throw new Error("[select-filter] A collection with value/label (or value/labelKey when using Locale) is required to populate the Select list, for example:: { filter: model: Filters.multipleSelect, collection: [ { value: '1', label: 'One' } ]')");
4231 }
4232 var labelKey = (option.labelKey || option[_this.labelName]);
4233 var selected = (searchTerms.findIndex(function (term) { return term === option[_this.valueName]; }) >= 0) ? 'selected' : '';
4234 var labelText = ((option.labelKey || _this.enableTranslateLabel) && labelKey) ? _this.translate.instant(labelKey || ' ') : labelKey;
4235 var prefixText = option[_this.labelPrefixName] || '';
4236 var suffixText = option[_this.labelSuffixName] || '';
4237 var optionLabel = option[_this.optionLabel] || '';
4238 optionLabel = optionLabel.toString().replace(/\"/g, '\''); // replace double quotes by single quotes to avoid interfering with regular html
4239 // also translate prefix/suffix if enableTranslateLabel is true and text is a string
4240 prefixText = (_this.enableTranslateLabel && prefixText && typeof prefixText === 'string') ? _this.translate.instant(prefixText || ' ') : prefixText;
4241 suffixText = (_this.enableTranslateLabel && suffixText && typeof suffixText === 'string') ? _this.translate.instant(suffixText || ' ') : suffixText;
4242 optionLabel = (_this.enableTranslateLabel && optionLabel && typeof optionLabel === 'string') ? _this.translate.instant(optionLabel || ' ') : optionLabel;
4243 // add to a temp array for joining purpose and filter out empty text
4244 var tmpOptionArray = [prefixText, labelText, suffixText].filter(function (text) { return text; });
4245 var optionText = tmpOptionArray.join(separatorBetweenLabels);
4246 // if user specifically wants to render html text, he needs to opt-in else it will stripped out by default
4247 // also, the 3rd party lib will saninitze any html code unless it's encoded, so we'll do that
4248 if (isRenderHtmlEnabled) {
4249 // sanitize any unauthorized html tags like script and others
4250 // for the remaining allowed tags we'll permit all attributes
4251 var sanitizedText = DOMPurify.sanitize(optionText, sanitizedOptions);
4252 optionText = htmlEncode(sanitizedText);
4253 }
4254 // html text of each select option
4255 options += "<option value=\"" + option[_this.valueName] + "\" label=\"" + optionLabel + "\" " + selected + ">" + optionText + "</option>";
4256 // if there's at least 1 search term found, we will add the "filled" class for styling purposes
4257 if (selected) {
4258 _this.isFilled = true;
4259 }
4260 });
4261 }
4262 return "<select class=\"ms-filter search-filter filter-" + fieldId + "\" " + (this.isMultipleSelect ? 'multiple="multiple"' : '') + ">" + options + "</select>";
4263 };
4264 /** Create a blank entry that can be added to the collection. It will also reuse the same customStructure if need be */
4265 SelectFilter.prototype.createBlankEntry = function () {
4266 var _a;
4267 var blankEntry = (_a = {},
4268 _a[this.labelName] = '',
4269 _a[this.valueName] = '',
4270 _a);
4271 if (this.labelPrefixName) {
4272 blankEntry[this.labelPrefixName] = '';
4273 }
4274 if (this.labelSuffixName) {
4275 blankEntry[this.labelSuffixName] = '';
4276 }
4277 return blankEntry;
4278 };
4279 /**
4280 * From the html template string, create a DOM element
4281 * Subscribe to the onClose event and run the callback when that happens
4282 * @param filterTemplate
4283 */
4284 SelectFilter.prototype.createDomElement = function (filterTemplate) {
4285 var fieldId = this.columnDef && this.columnDef.id;
4286 // provide the name attribute to the DOM element which will be needed to auto-adjust drop position (dropup / dropdown)
4287 this.elementName = "filter-" + fieldId;
4288 this.defaultOptions.name = this.elementName;
4289 var $headerElm = this.grid.getHeaderRowColumn(fieldId);
4290 $($headerElm).empty();
4291 // create the DOM element & add an ID and filter class
4292 this.$filterElm = $(filterTemplate);
4293 if (typeof this.$filterElm.multipleSelect !== 'function') {
4294 throw new Error("multiple-select.js was not found, make sure to modify your \"angular-cli.json\" file and include \"../node_modules/angular-slickgrid/lib/multiple-select/multiple-select.js\" and it's css or SASS file");
4295 }
4296 this.$filterElm.attr('id', this.elementName);
4297 this.$filterElm.attr('name', this.elementName);
4298 this.$filterElm.data('columnId', fieldId);
4299 // if there's a search term, we will add the "filled" class for styling purposes
4300 if (this.isFilled) {
4301 this.$filterElm.addClass('filled');
4302 }
4303 // append the new DOM element to the header row
4304 if (this.$filterElm && typeof this.$filterElm.appendTo === 'function') {
4305 this.$filterElm.appendTo($headerElm);
4306 }
4307 // merge options & attach multiSelect
4308 var elementOptions = __assign({}, this.defaultOptions, this.columnFilter.filterOptions);
4309 this.filterElmOptions = __assign({}, this.defaultOptions, elementOptions);
4310 this.$filterElm = this.$filterElm.multipleSelect(this.filterElmOptions);
4311 };
4312 return SelectFilter;
4313 }());
4314
4315 var MultipleSelectFilter = /** @class */ (function (_super) {
4316 __extends(MultipleSelectFilter, _super);
4317 /**
4318 * Initialize the Filter
4319 */
4320 function MultipleSelectFilter(translate, collectionService) {
4321 var _this = _super.call(this, translate, collectionService, true) || this;
4322 _this.translate = translate;
4323 _this.collectionService = collectionService;
4324 return _this;
4325 }
4326 return MultipleSelectFilter;
4327 }(SelectFilter));
4328
4329 var NativeSelectFilter = /** @class */ (function () {
4330 function NativeSelectFilter(translate) {
4331 this.translate = translate;
4332 this._clearFilterTriggered = false;
4333 this._shouldTriggerQuery = true;
4334 }
4335 Object.defineProperty(NativeSelectFilter.prototype, "operator", {
4336 get: function () {
4337 return (this.columnDef && this.columnDef.filter && this.columnDef.filter.operator) || exports.OperatorType.equal;
4338 },
4339 enumerable: true,
4340 configurable: true
4341 });
4342 /**
4343 * Initialize the Filter
4344 */
4345 NativeSelectFilter.prototype.init = function (args) {
4346 var _this = this;
4347 this.grid = args.grid;
4348 this.callback = args.callback;
4349 this.columnDef = args.columnDef;
4350 this.searchTerms = args.searchTerms || [];
4351 // filter input can only have 1 search term, so we will use the 1st array index if it exist
4352 var searchTerm = (Array.isArray(this.searchTerms) && this.searchTerms[0]) || '';
4353 if (typeof searchTerm === 'boolean' || typeof searchTerm === 'number') {
4354 searchTerm = "" + searchTerm;
4355 }
4356 // step 1, create HTML string template
4357 var filterTemplate = this.buildTemplateHtmlString();
4358 // step 2, create the DOM Element of the filter & initialize it if searchTerm is filled
4359 this.$filterElm = this.createDomElement(filterTemplate, searchTerm);
4360 // step 3, subscribe to the change event and run the callback when that happens
4361 // also add/remove "filled" class for styling purposes
4362 this.$filterElm.change(function (e) {
4363 var value = e && e.target && e.target.value || '';
4364 if (_this._clearFilterTriggered) {
4365 _this.callback(e, { columnDef: _this.columnDef, clearFilterTriggered: _this._clearFilterTriggered, shouldTriggerQuery: _this._shouldTriggerQuery });
4366 _this.$filterElm.removeClass('filled');
4367 }
4368 else {
4369 value === '' ? _this.$filterElm.removeClass('filled') : _this.$filterElm.addClass('filled');
4370 _this.callback(e, { columnDef: _this.columnDef, operator: _this.operator, searchTerms: [value], shouldTriggerQuery: _this._shouldTriggerQuery });
4371 }
4372 // reset both flags for next use
4373 _this._clearFilterTriggered = false;
4374 _this._shouldTriggerQuery = true;
4375 });
4376 };
4377 /**
4378 * Clear the filter values
4379 */
4380 NativeSelectFilter.prototype.clear = function (shouldTriggerQuery) {
4381 if (shouldTriggerQuery === void 0) { shouldTriggerQuery = true; }
4382 if (this.$filterElm) {
4383 this._clearFilterTriggered = true;
4384 this._shouldTriggerQuery = shouldTriggerQuery;
4385 this.searchTerms = [];
4386 this.$filterElm.val('');
4387 this.$filterElm.trigger('change');
4388 }
4389 };
4390 /**
4391 * destroy the filter
4392 */
4393 NativeSelectFilter.prototype.destroy = function () {
4394 if (this.$filterElm) {
4395 this.$filterElm.off('change').remove();
4396 }
4397 };
4398 /**
4399 * Set value(s) on the DOM element
4400 */
4401 NativeSelectFilter.prototype.setValues = function (values) {
4402 if (values) {
4403 this.$filterElm.val(values);
4404 }
4405 };
4406 //
4407 // private functions
4408 // ------------------
4409 NativeSelectFilter.prototype.buildTemplateHtmlString = function () {
4410 var _this = this;
4411 if (!this.columnDef || !this.columnDef.filter || !this.columnDef.filter.collection) {
4412 throw new Error("[Angular-SlickGrid] You need to pass a \"collection\" for the Select Filter to work correctly. Also each option should include a value/label pair (or value/labelKey when using Locale). For example:: { filter: model: Filters.select, collection: [{ value: true, label: 'True' }, { value: false, label: 'False'}] }");
4413 }
4414 var fieldId = this.columnDef && this.columnDef.id;
4415 var optionCollection = this.columnDef.filter.collection || [];
4416 var labelName = (this.columnDef.filter.customStructure) ? this.columnDef.filter.customStructure.label : 'label';
4417 var valueName = (this.columnDef.filter.customStructure) ? this.columnDef.filter.customStructure.value : 'value';
4418 var options = '';
4419 // collection could be an Array of Strings OR Objects
4420 if (optionCollection.every(function (x) { return typeof x === 'string'; })) {
4421 optionCollection.forEach(function (option) {
4422 options += "<option value=\"" + option + "\" label=\"" + option + "\">" + option + "</option>";
4423 });
4424 }
4425 else {
4426 optionCollection.forEach(function (option) {
4427 if (!option || (option[labelName] === undefined && option.labelKey === undefined)) {
4428 throw new Error("A collection with value/label (or value/labelKey when using Locale) is required to populate the Select list, for example:: { filter: model: Filters.select, collection: [ { value: '1', label: 'One' } ]')");
4429 }
4430 var labelKey = option.labelKey || option[labelName];
4431 var textLabel = ((option.labelKey || _this.columnDef.filter.enableTranslateLabel) && _this.translate && typeof _this.translate.instant === 'function') ? _this.translate.instant(labelKey || ' ') : labelKey;
4432 options += "<option value=\"" + option[valueName] + "\">" + textLabel + "</option>";
4433 });
4434 }
4435 return "<select class=\"form-control search-filter filter-" + fieldId + "\">" + options + "</select>";
4436 };
4437 /**
4438 * From the html template string, create a DOM element
4439 * @param filterTemplate
4440 */
4441 NativeSelectFilter.prototype.createDomElement = function (filterTemplate, searchTerm) {
4442 var fieldId = this.columnDef && this.columnDef.id;
4443 var $headerElm = this.grid.getHeaderRowColumn(fieldId);
4444 $($headerElm).empty();
4445 // create the DOM element & add an ID and filter class
4446 var $filterElm = $(filterTemplate);
4447 var searchTermInput = (searchTerm || '');
4448 $filterElm.val(searchTermInput);
4449 $filterElm.attr('id', "filter-" + fieldId);
4450 $filterElm.data('columnId', fieldId);
4451 // append the new DOM element to the header row
4452 if ($filterElm && typeof $filterElm.appendTo === 'function') {
4453 $filterElm.appendTo($headerElm);
4454 }
4455 return $filterElm;
4456 };
4457 return NativeSelectFilter;
4458 }());
4459
4460 var SingleSelectFilter = /** @class */ (function (_super) {
4461 __extends(SingleSelectFilter, _super);
4462 /**
4463 * Initialize the Filter
4464 */
4465 function SingleSelectFilter(translate, collectionService) {
4466 var _this = _super.call(this, translate, collectionService, false) || this;
4467 _this.translate = translate;
4468 _this.collectionService = collectionService;
4469 return _this;
4470 }
4471 return SingleSelectFilter;
4472 }(SelectFilter));
4473
4474 var DEFAULT_MIN_VALUE$1 = 0;
4475 var DEFAULT_MAX_VALUE$1 = 100;
4476 var DEFAULT_STEP$1 = 1;
4477 var SliderFilter = /** @class */ (function () {
4478 function SliderFilter() {
4479 this._clearFilterTriggered = false;
4480 this._shouldTriggerQuery = true;
4481 }
4482 Object.defineProperty(SliderFilter.prototype, "filterParams", {
4483 /** Getter for the Filter Generic Params */
4484 get: function () {
4485 return this.columnDef && this.columnDef.filter && this.columnDef.filter.params || {};
4486 },
4487 enumerable: true,
4488 configurable: true
4489 });
4490 Object.defineProperty(SliderFilter.prototype, "filterProperties", {
4491 /** Getter for the `filter` properties */
4492 get: function () {
4493 return this.columnDef && this.columnDef.filter;
4494 },
4495 enumerable: true,
4496 configurable: true
4497 });
4498 Object.defineProperty(SliderFilter.prototype, "operator", {
4499 get: function () {
4500 return (this.columnDef && this.columnDef.filter && this.columnDef.filter.operator) || exports.OperatorType.equal;
4501 },
4502 enumerable: true,
4503 configurable: true
4504 });
4505 /**
4506 * Initialize the Filter
4507 */
4508 SliderFilter.prototype.init = function (args) {
4509 var _this = this;
4510 if (!args) {
4511 throw new Error('[Angular-SlickGrid] A filter must always have an "init()" with valid arguments.');
4512 }
4513 this.grid = args.grid;
4514 this.callback = args.callback;
4515 this.columnDef = args.columnDef;
4516 this.searchTerms = args.searchTerms || [];
4517 // define the input & slider number IDs
4518 this._elementRangeInputId = "rangeInput_" + this.columnDef.field;
4519 this._elementRangeOutputId = "rangeOutput_" + this.columnDef.field;
4520 // filter input can only have 1 search term, so we will use the 1st array index if it exist
4521 var searchTerm = (Array.isArray(this.searchTerms) && this.searchTerms[0]) || '';
4522 // step 1, create HTML string template
4523 var filterTemplate = this.buildTemplateHtmlString();
4524 // step 2, create the DOM Element of the filter & initialize it if searchTerm is filled
4525 this.$filterElm = this.createDomElement(filterTemplate, searchTerm);
4526 // step 3, subscribe to the change event and run the callback when that happens
4527 // also add/remove "filled" class for styling purposes
4528 this.$filterElm.change(function (e) {
4529 var value = e && e.target && e.target.value || '';
4530 if (_this._clearFilterTriggered) {
4531 _this.callback(e, { columnDef: _this.columnDef, clearFilterTriggered: _this._clearFilterTriggered, shouldTriggerQuery: _this._shouldTriggerQuery });
4532 _this.$filterElm.removeClass('filled');
4533 }
4534 else {
4535 value === '' ? _this.$filterElm.removeClass('filled') : _this.$filterElm.addClass('filled');
4536 _this.callback(e, { columnDef: _this.columnDef, operator: _this.operator, searchTerms: [value], shouldTriggerQuery: _this._shouldTriggerQuery });
4537 }
4538 // reset both flags for next use
4539 _this._clearFilterTriggered = false;
4540 _this._shouldTriggerQuery = true;
4541 });
4542 // if user chose to display the slider number on the right side, then update it every time it changes
4543 // we need to use both "input" and "change" event to be all cross-browser
4544 if (!this.filterParams.hideSliderNumber) {
4545 this.$filterElm.on('input change', function (e) {
4546 var value = e && e.target && e.target.value || '';
4547 if (value) {
4548 document.getElementById(_this._elementRangeOutputId).innerHTML = value;
4549 }
4550 });
4551 }
4552 };
4553 /**
4554 * Clear the filter value
4555 */
4556 SliderFilter.prototype.clear = function (shouldTriggerQuery) {
4557 if (shouldTriggerQuery === void 0) { shouldTriggerQuery = true; }
4558 if (this.$filterElm) {
4559 this._clearFilterTriggered = true;
4560 this._shouldTriggerQuery = shouldTriggerQuery;
4561 this.searchTerms = [];
4562 var clearedValue = this.filterParams.hasOwnProperty('sliderStartValue') ? this.filterParams.sliderStartValue : DEFAULT_MIN_VALUE$1;
4563 this.$filterElm.children('input').val(clearedValue);
4564 this.$filterElm.children('div.input-group-addon.input-group-append').children().html(clearedValue);
4565 this.$filterElm.trigger('change');
4566 }
4567 };
4568 /**
4569 * destroy the filter
4570 */
4571 SliderFilter.prototype.destroy = function () {
4572 if (this.$filterElm) {
4573 this.$filterElm.off('change').remove();
4574 }
4575 };
4576 /**
4577 * Set value(s) on the DOM element
4578 */
4579 SliderFilter.prototype.setValues = function (values) {
4580 if (values) {
4581 this.$filterElm.val(values);
4582 }
4583 };
4584 //
4585 // private functions
4586 // ------------------
4587 /**
4588 * Create the HTML template as a string
4589 */
4590 SliderFilter.prototype.buildTemplateHtmlString = function () {
4591 var fieldId = this.columnDef && this.columnDef.id;
4592 var minValue = this.filterProperties.hasOwnProperty('minValue') ? this.filterProperties.minValue : DEFAULT_MIN_VALUE$1;
4593 var maxValue = this.filterProperties.hasOwnProperty('maxValue') ? this.filterProperties.maxValue : DEFAULT_MAX_VALUE$1;
4594 var defaultValue = this.filterParams.hasOwnProperty('sliderStartValue') ? this.filterParams.sliderStartValue : minValue;
4595 var step = this.filterProperties.hasOwnProperty('valueStep') ? this.filterProperties.valueStep : DEFAULT_STEP$1;
4596 if (this.filterParams.hideSliderNumber) {
4597 return "\n <div class=\"search-filter filter-" + fieldId + "\">\n <input type=\"range\" id=\"" + this._elementRangeInputId + "\"\n name=\"" + this._elementRangeInputId + "\"\n defaultValue=\"" + defaultValue + "\" min=\"" + minValue + "\" max=\"" + maxValue + "\" step=\"" + step + "\"\n class=\"form-control slider-filter-input range\" />\n </div>";
4598 }
4599 return "\n <div class=\"input-group search-filter filter-" + fieldId + "\">\n <input type=\"range\" id=\"" + this._elementRangeInputId + "\"\n name=\"" + this._elementRangeInputId + "\"\n defaultValue=\"" + defaultValue + "\" min=\"" + minValue + "\" max=\"" + maxValue + "\" step=\"" + step + "\"\n class=\"form-control slider-filter-input range\" />\n <div class=\"input-group-addon input-group-append slider-value\">\n <span class=\"input-group-text\" id=\"" + this._elementRangeOutputId + "\">" + defaultValue + "</span>\n </div>\n </div>";
4600 };
4601 /**
4602 * From the html template string, create a DOM element
4603 * @param filterTemplate
4604 */
4605 SliderFilter.prototype.createDomElement = function (filterTemplate, searchTerm) {
4606 var fieldId = this.columnDef && this.columnDef.id;
4607 var $headerElm = this.grid.getHeaderRowColumn(fieldId);
4608 $($headerElm).empty();
4609 // create the DOM element & add an ID and filter class
4610 var $filterElm = $(filterTemplate);
4611 var searchTermInput = (searchTerm || '0');
4612 $filterElm.children('input').val(searchTermInput);
4613 $filterElm.children('div.input-group-addon.input-group-append').children().html(searchTermInput);
4614 $filterElm.attr('id', "filter-" + fieldId);
4615 $filterElm.data('columnId', fieldId);
4616 // if there's a search term, we will add the "filled" class for styling purposes
4617 if (searchTerm) {
4618 $filterElm.addClass('filled');
4619 }
4620 // append the new DOM element to the header row
4621 if ($filterElm && typeof $filterElm.appendTo === 'function') {
4622 $filterElm.appendTo($headerElm);
4623 }
4624 return $filterElm;
4625 };
4626 return SliderFilter;
4627 }());
4628
4629 var Filters = {
4630 /** AutoComplete Filter (using jQuery UI autocomplete feature) */
4631 autoComplete: AutoCompleteFilter,
4632 /** Compound Date Filter (compound of Operator + Date picker) */
4633 compoundDate: CompoundDateFilter,
4634 /** Alias to compoundInputText to Compound Input Filter (compound of Operator + Input Text) */
4635 compoundInput: CompoundInputFilter,
4636 /** Compound Input Number Filter (compound of Operator + Input of type Number) */
4637 compoundInputNumber: CompoundInputNumberFilter,
4638 /** Compound Input Password Filter (compound of Operator + Input of type Password, also note that only the text shown in the UI will be masked, filter query is still plain text) */
4639 compoundInputPassword: CompoundInputPasswordFilter,
4640 /** Compound Input Text Filter (compound of Operator + Input Text) */
4641 compoundInputText: CompoundInputFilter,
4642 /** Compound Slider Filter (compound of Operator + Slider) */
4643 compoundSlider: CompoundSliderFilter,
4644 /** Alias to inputText, input type text filter */
4645 input: InputFilter,
4646 /**
4647 * Input Filter of type text that will be formatted with a mask output
4648 * e.g.: column: { filter: { model: Filters.inputMask }, params: { mask: '(000) 000-0000' }}
4649 */
4650 inputMask: InputMaskFilter,
4651 /** Input Filter of type Number */
4652 inputNumber: InputNumberFilter,
4653 /** Input Filter of type Password (note that only the text shown in the UI will be masked, filter query is still plain text) */
4654 inputPassword: InputPasswordFilter,
4655 /** Default Filter, input type text filter */
4656 inputText: InputFilter,
4657 /** Multiple Select filter, which uses 3rd party lib "multiple-select.js" */
4658 multipleSelect: MultipleSelectFilter,
4659 /** Select filter, which uses native DOM element select */
4660 select: NativeSelectFilter,
4661 /** Single Select filter, which uses 3rd party lib "multiple-select.js" */
4662 singleSelect: SingleSelectFilter,
4663 /** Slider Filter */
4664 slider: SliderFilter,
4665 };
4666
4667 /**
4668 * Options that can be passed to the Bootstrap-Datetimepicker directly
4669 */
4670 var GlobalGridOptions = {
4671 alwaysShowVerticalScroll: true,
4672 autoEdit: false,
4673 asyncEditorLoading: false,
4674 autoFitColumnsOnFirstLoad: true,
4675 autoResize: {
4676 calculateAvailableSizeBy: 'window',
4677 bottomPadding: 20,
4678 minHeight: 180,
4679 minWidth: 300,
4680 sidePadding: 0
4681 },
4682 cellHighlightCssClass: 'slick-cell-modified',
4683 checkboxSelector: {
4684 cssClass: 'slick-cell-checkboxsel'
4685 },
4686 columnPicker: {
4687 hideForceFitButton: false,
4688 hideSyncResizeButton: true
4689 },
4690 datasetIdPropertyName: 'id',
4691 defaultFilter: Filters.input,
4692 enableFilterTrimWhiteSpace: false,
4693 defaultFilterPlaceholder: '&#128269;',
4694 editable: false,
4695 enableAutoResize: true,
4696 enableAutoSizeColumns: true,
4697 enableCellNavigation: false,
4698 enableColumnPicker: true,
4699 enableColumnReorder: true,
4700 enableExport: true,
4701 enableGridMenu: true,
4702 enableHeaderMenu: true,
4703 enableMouseHoverHighlightRow: true,
4704 enableSorting: true,
4705 enableTextSelectionOnCells: true,
4706 explicitInitialization: true,
4707 exportOptions: {
4708 delimiter: exports.DelimiterType.comma,
4709 exportWithFormatter: false,
4710 filename: 'export',
4711 format: exports.FileType.csv,
4712 groupingAggregatorRowText: '',
4713 sanitizeDataExport: false,
4714 useUtf8WithBom: true
4715 },
4716 forceFitColumns: false,
4717 gridMenu: {
4718 hideClearAllFiltersCommand: false,
4719 hideClearAllSortingCommand: false,
4720 hideExportCsvCommand: false,
4721 hideExportTextDelimitedCommand: true,
4722 hideForceFitButton: false,
4723 hideRefreshDatasetCommand: false,
4724 hideSyncResizeButton: true,
4725 hideToggleFilterCommand: false,
4726 hideTogglePreHeaderCommand: false,
4727 iconCssClass: 'fa fa-bars',
4728 iconClearAllFiltersCommand: 'fa fa-filter text-danger',
4729 iconClearAllSortingCommand: 'fa fa-unsorted text-danger',
4730 iconExportCsvCommand: 'fa fa-download',
4731 iconExportTextDelimitedCommand: 'fa fa-download',
4732 iconRefreshDatasetCommand: 'fa fa-refresh',
4733 iconToggleFilterCommand: 'fa fa-random',
4734 iconTogglePreHeaderCommand: 'fa fa-random',
4735 menuWidth: 16,
4736 resizeOnShowHeaderRow: true
4737 },
4738 headerMenu: {
4739 autoAlign: true,
4740 autoAlignOffset: 12,
4741 minWidth: 140,
4742 iconClearFilterCommand: 'fa fa-filter text-danger',
4743 iconClearSortCommand: 'fa fa-unsorted',
4744 iconSortAscCommand: 'fa fa-sort-amount-asc',
4745 iconSortDescCommand: 'fa fa-sort-amount-desc',
4746 iconColumnHideCommand: 'fa fa-times',
4747 hideColumnHideCommand: false,
4748 hideClearFilterCommand: false,
4749 hideClearSortCommand: false,
4750 hideSortCommands: false
4751 },
4752 headerRowHeight: 35,
4753 multiColumnSort: true,
4754 numberedMultiColumnSort: true,
4755 tristateMultiColumnSort: false,
4756 sortColNumberInSeparateSpan: true,
4757 suppressActiveCellChangeOnEdit: true,
4758 pagination: {
4759 pageSizes: [10, 15, 20, 25, 30, 40, 50, 75, 100],
4760 pageSize: 25,
4761 totalItems: 0
4762 },
4763 rowDetailView: {
4764 cssClass: 'detail-view-toggle',
4765 panelRows: 1,
4766 keyPrefix: '__',
4767 useRowClick: true,
4768 useSimpleViewportCalc: true,
4769 saveDetailViewOnScroll: false,
4770 // the following 2 property/method should always be override by the user
4771 process: undefined,
4772 viewComponent: null
4773 },
4774 rowHeight: 35,
4775 topPanelHeight: 35
4776 };
4777
4778 var SlickgridConfig = /** @class */ (function () {
4779 function SlickgridConfig() {
4780 this.options = GlobalGridOptions;
4781 }
4782 return SlickgridConfig;
4783 }());
4784
4785 var FilterFactory = /** @class */ (function () {
4786 function FilterFactory(config, translate, collectionService) {
4787 this.config = config;
4788 this.translate = translate;
4789 this.collectionService = collectionService;
4790 this._options = this.config.options;
4791 }
4792 // Uses the User model to create a new User
4793 FilterFactory.prototype.createFilter = function (columnFilter) {
4794 var filter;
4795 if (columnFilter && columnFilter.model) {
4796 filter = typeof columnFilter.model === 'function' ? new columnFilter.model(this.translate, this.collectionService) : columnFilter.model;
4797 }
4798 // fallback to the default filter
4799 if (!filter && this._options.defaultFilter) {
4800 filter = new this._options.defaultFilter(this.translate, this.collectionService);
4801 }
4802 return filter;
4803 };
4804 FilterFactory = __decorate([
4805 core.Injectable(),
4806 __metadata("design:paramtypes", [SlickgridConfig, core$1.TranslateService, CollectionService])
4807 ], FilterFactory);
4808 return FilterFactory;
4809 }());
4810
4811 var isequal = isequal_; // patch to fix rollup to work
4812 // timer for keeping track of user typing waits
4813 var timer;
4814 var DEFAULT_FILTER_TYPING_DEBOUNCE = 500;
4815 var FilterService = /** @class */ (function () {
4816 function FilterService(filterFactory) {
4817 this.filterFactory = filterFactory;
4818 this._isFilterFirstRender = true;
4819 this._firstColumnIdRendered = '';
4820 this._filtersMetadata = [];
4821 this._columnFilters = {};
4822 this.onFilterChanged = new rxjs.Subject();
4823 this.onFilterCleared = new rxjs.Subject();
4824 this._eventHandler = new Slick.EventHandler();
4825 this._onSearchChange = new Slick.Event();
4826 }
4827 Object.defineProperty(FilterService.prototype, "eventHandler", {
4828 /** Getter of the SlickGrid Event Handler */
4829 get: function () {
4830 return this._eventHandler;
4831 },
4832 enumerable: true,
4833 configurable: true
4834 });
4835 Object.defineProperty(FilterService.prototype, "isFilterFirstRender", {
4836 /** Getter to know if the filter was already rendered or if it was its first time render */
4837 get: function () {
4838 return this._isFilterFirstRender;
4839 },
4840 enumerable: true,
4841 configurable: true
4842 });
4843 Object.defineProperty(FilterService.prototype, "onSearchChange", {
4844 /** Getter of the SlickGrid Event Handler */
4845 get: function () {
4846 return this._onSearchChange;
4847 },
4848 enumerable: true,
4849 configurable: true
4850 });
4851 Object.defineProperty(FilterService.prototype, "_gridOptions", {
4852 /** Getter for the Grid Options pulled through the Grid Object */
4853 get: function () {
4854 return (this._grid && this._grid.getOptions) ? this._grid.getOptions() : {};
4855 },
4856 enumerable: true,
4857 configurable: true
4858 });
4859 Object.defineProperty(FilterService.prototype, "_columnDefinitions", {
4860 /** Getter for the Column Definitions pulled through the Grid Object */
4861 get: function () {
4862 return (this._grid && this._grid.getColumns) ? this._grid.getColumns() : [];
4863 },
4864 enumerable: true,
4865 configurable: true
4866 });
4867 FilterService.prototype.init = function (grid) {
4868 this._grid = grid;
4869 };
4870 FilterService.prototype.dispose = function () {
4871 this.disposeColumnFilters();
4872 // unsubscribe all SlickGrid events
4873 if (this._eventHandler && this._eventHandler.unsubscribeAll) {
4874 this._eventHandler.unsubscribeAll();
4875 }
4876 };
4877 /**
4878 * Dispose of the filters, since it's a singleton, we don't want to affect other grids with same columns
4879 */
4880 FilterService.prototype.disposeColumnFilters = function () {
4881 // we need to loop through all columnFilters and delete them 1 by 1
4882 // only trying to make columnFilter an empty (without looping) would not trigger a dataset change
4883 if (typeof this._columnFilters === 'object') {
4884 for (var columnId in this._columnFilters) {
4885 if (columnId && this._columnFilters[columnId]) {
4886 delete this._columnFilters[columnId];
4887 }
4888 }
4889 }
4890 // also destroy each Filter instances
4891 if (Array.isArray(this._filtersMetadata)) {
4892 this._filtersMetadata.forEach(function (filter) {
4893 if (filter && filter.destroy) {
4894 filter.destroy(true);
4895 }
4896 });
4897 }
4898 };
4899 /**
4900 * Bind a backend filter hook to the grid
4901 * @param grid SlickGrid Grid object
4902 */
4903 FilterService.prototype.bindBackendOnFilter = function (grid, dataView) {
4904 var _this = this;
4905 this._dataView = dataView;
4906 this._filtersMetadata = [];
4907 // subscribe to SlickGrid onHeaderRowCellRendered event to create filter template
4908 this._eventHandler.subscribe(grid.onHeaderRowCellRendered, function (e, args) {
4909 // firstColumnIdRendered is null at first, so if it changes to being filled and equal, then we would know that it was already rendered
4910 // this is to avoid rendering the filter twice (only the Select Filter for now), rendering it again also clears the filter which has unwanted side effect
4911 if (args.column.id === _this._firstColumnIdRendered) {
4912 _this._isFilterFirstRender = false;
4913 }
4914 _this.addFilterTemplateToHeaderRow(args, _this._isFilterFirstRender);
4915 if (_this._firstColumnIdRendered === '') {
4916 _this._firstColumnIdRendered = args.column.id;
4917 }
4918 });
4919 // subscribe to the SlickGrid event and call the backend execution
4920 this._eventHandler.subscribe(this._onSearchChange, this.onBackendFilterChange.bind(this));
4921 };
4922 /**
4923 * Bind a local filter hook to the grid
4924 * @param grid SlickGrid Grid object
4925 * @param dataView
4926 */
4927 FilterService.prototype.bindLocalOnFilter = function (grid, dataView) {
4928 var _this = this;
4929 this._filtersMetadata = [];
4930 this._dataView = dataView;
4931 dataView.setFilterArgs({ columnFilters: this._columnFilters, grid: this._grid });
4932 dataView.setFilter(this.customLocalFilter.bind(this, dataView));
4933 this._eventHandler.subscribe(this._onSearchChange, function (e, args) {
4934 var columnId = args.columnId;
4935 if (columnId != null) {
4936 dataView.refresh();
4937 }
4938 // emit an onFilterChanged event when it's not called by a clear filter
4939 if (args && !args.clearFilterTriggered) {
4940 _this.emitFilterChanged(exports.EmitterType.local);
4941 }
4942 });
4943 // subscribe to SlickGrid onHeaderRowCellRendered event to create filter template
4944 this._eventHandler.subscribe(grid.onHeaderRowCellRendered, function (e, args) {
4945 _this.addFilterTemplateToHeaderRow(args);
4946 });
4947 };
4948 FilterService.prototype.callbackSearchEvent = function (event, args) {
4949 if (args) {
4950 var searchTerm = ((event && event.target) ? event.target.value : undefined);
4951 var searchTerms = (args.searchTerms && Array.isArray(args.searchTerms)) ? args.searchTerms : (searchTerm ? [searchTerm] : undefined);
4952 var columnDef = args.columnDef || null;
4953 var columnId = columnDef ? (columnDef.id || '') : '';
4954 var operator = args.operator || undefined;
4955 var hasSearchTerms = searchTerms && Array.isArray(searchTerms);
4956 var termsCount = hasSearchTerms && searchTerms.length;
4957 var oldColumnFilters = __assign({}, this._columnFilters);
4958 if (!hasSearchTerms || termsCount === 0 || (termsCount === 1 && searchTerms[0] === '')) {
4959 // delete the property from the columnFilters when it becomes empty
4960 // without doing this, it would leave an incorrect state of the previous column filters when filtering on another column
4961 delete this._columnFilters[columnId];
4962 }
4963 else {
4964 var colId = '' + columnId;
4965 var colFilter = {
4966 columnId: colId,
4967 columnDef: columnDef,
4968 searchTerms: searchTerms,
4969 };
4970 if (operator) {
4971 colFilter.operator = operator;
4972 }
4973 this._columnFilters[colId] = colFilter;
4974 }
4975 // event might have been created as a CustomEvent (e.g. CompoundDateFilter), without being a valid Slick.EventData,
4976 // if so we will create a new Slick.EventData and merge it with that CustomEvent to avoid having SlickGrid errors
4977 var eventData = (event && typeof event.isPropagationStopped !== 'function') ? $.extend({}, new Slick.EventData(), event) : event;
4978 // trigger an event only if Filters changed or if ENTER key was pressed
4979 var eventKeyCode = event && event.keyCode;
4980 if (eventKeyCode === exports.KeyCode.ENTER || !isequal(oldColumnFilters, this._columnFilters)) {
4981 this._onSearchChange.notify({
4982 clearFilterTriggered: args.clearFilterTriggered,
4983 shouldTriggerQuery: args.shouldTriggerQuery,
4984 columnId: columnId,
4985 columnDef: args.columnDef || null,
4986 columnFilters: this._columnFilters,
4987 operator: operator,
4988 searchTerms: searchTerms,
4989 grid: this._grid
4990 }, eventData);
4991 }
4992 }
4993 };
4994 FilterService.prototype.clearFilterByColumnId = function (event, columnId) {
4995 var colFilter = this._filtersMetadata.find(function (filter) { return filter.columnDef.id === columnId; });
4996 if (colFilter && colFilter.clear) {
4997 colFilter.clear(true);
4998 }
4999 // we need to loop through all columnFilters and delete the filter found
5000 // only trying to clear columnFilter (without looping through) would not trigger a dataset change
5001 for (var colId in this._columnFilters) {
5002 if (colId === columnId && this._columnFilters[colId]) {
5003 delete this._columnFilters[colId];
5004 }
5005 }
5006 var emitter = exports.EmitterType.local;
5007 var isBackendApi = this._gridOptions && this._gridOptions.backendServiceApi || false;
5008 // when using a backend service, we need to manually trigger a filter change
5009 if (isBackendApi) {
5010 emitter = exports.EmitterType.remote;
5011 this.onBackendFilterChange(event, { grid: this._grid, columnFilters: this._columnFilters });
5012 }
5013 // emit an event when filter is cleared
5014 this.emitFilterChanged(emitter);
5015 };
5016 /** Clear the search filters (below the column titles) */
5017 FilterService.prototype.clearFilters = function () {
5018 this._filtersMetadata.forEach(function (filter) {
5019 if (filter && filter.clear) {
5020 // clear element and trigger a change
5021 filter.clear(false);
5022 }
5023 });
5024 // we need to loop through all columnFilters and delete them 1 by 1
5025 // only trying to clear columnFilter (without looping through) would not trigger a dataset change
5026 for (var columnId in this._columnFilters) {
5027 if (columnId && this._columnFilters[columnId]) {
5028 delete this._columnFilters[columnId];
5029 }
5030 }
5031 // we also need to refresh the dataView and optionally the grid (it's optional since we use DataView)
5032 if (this._dataView && this._grid) {
5033 this._dataView.refresh();
5034 this._grid.invalidate();
5035 }
5036 // when using backend service, we need to query only once so it's better to do it here
5037 if (this._gridOptions && this._gridOptions.backendServiceApi) {
5038 var callbackArgs = { clearFilterTriggered: true, shouldTriggerQuery: true, grid: this._grid, columnFilters: this._columnFilters };
5039 this.executeBackendCallback(undefined, callbackArgs, new Date(), this._gridOptions.backendServiceApi);
5040 }
5041 // emit an event when filters are all cleared
5042 this.onFilterCleared.next(true);
5043 };
5044 FilterService.prototype.customLocalFilter = function (dataView, item, args) {
5045 var e_1, _a;
5046 try {
5047 for (var _b = __values(Object.keys(args.columnFilters)), _c = _b.next(); !_c.done; _c = _b.next()) {
5048 var columnId = _c.value;
5049 var columnFilter = args.columnFilters[columnId];
5050 var columnIndex = args.grid.getColumnIndex(columnId);
5051 var columnDef = args.grid.getColumns()[columnIndex];
5052 if (!columnDef) {
5053 return false;
5054 }
5055 // Row Detail View plugin, if the row is padding we just get the value we're filtering on from it's parent
5056 if (this._gridOptions.enableRowDetailView) {
5057 var metadataPrefix = this._gridOptions.rowDetailView && this._gridOptions.rowDetailView.keyPrefix || '__';
5058 if (item[metadataPrefix + "isPadding"] && item[metadataPrefix + "parent"]) {
5059 item = item[metadataPrefix + "parent"];
5060 }
5061 }
5062 var dataKey = columnDef.dataKey;
5063 var fieldName = columnDef.queryFieldFilter || columnDef.queryField || columnDef.field;
5064 var fieldType = columnDef.type || exports.FieldType.string;
5065 var filterSearchType = (columnDef.filterSearchType) ? columnDef.filterSearchType : null;
5066 var cellValue = item[fieldName];
5067 // when item is a complex object (dot "." notation), we need to filter the value contained in the object tree
5068 if (fieldName.indexOf('.') >= 0) {
5069 cellValue = getDescendantProperty(item, fieldName);
5070 }
5071 // if we find searchTerms use them but make a deep copy so that we don't affect original array
5072 // we might have to overwrite the value(s) locally that are returned
5073 // e.g: we don't want to operator within the search value, since it will fail filter condition check trigger afterward
5074 var searchValues = (columnFilter && columnFilter.searchTerms) ? $.extend(true, [], columnFilter.searchTerms) : null;
5075 var fieldSearchValue = (Array.isArray(searchValues) && searchValues.length === 1) ? searchValues[0] : '';
5076 var matches = null;
5077 if (fieldType !== exports.FieldType.object) {
5078 fieldSearchValue = '' + fieldSearchValue; // make sure it's a string
5079 matches = fieldSearchValue.match(/^([<>!=\*]{0,2})(.*[^<>!=\*])([\*]?)$/); // group 1: Operator, 2: searchValue, 3: last char is '*' (meaning starts with, ex.: abc*)
5080 }
5081 var operator = columnFilter.operator || ((matches) ? matches[1] : '');
5082 var searchTerm = (!!matches) ? matches[2] : '';
5083 var lastValueChar = (!!matches) ? matches[3] : (operator === '*z' ? '*' : '');
5084 if (searchValues && searchValues.length > 1) {
5085 fieldSearchValue = searchValues.join(',');
5086 }
5087 else if (typeof fieldSearchValue === 'string') {
5088 // escaping the search value
5089 fieldSearchValue = fieldSearchValue.replace("'", "''"); // escape single quotes by doubling them
5090 if (operator === '*' || operator === 'a*' || operator === '*z' || lastValueChar === '*') {
5091 operator = (operator === '*' || operator === '*z') ? exports.OperatorType.endsWith : exports.OperatorType.startsWith;
5092 }
5093 }
5094 // no need to query if search value is empty
5095 if (searchTerm === '' && (!searchValues || (Array.isArray(searchValues) && searchValues.length === 0))) {
5096 return true;
5097 }
5098 // if search value has a regex match we will only keep the value without the operator
5099 // in this case we need to overwrite the returned search values to truncate operator from the string search
5100 if (Array.isArray(matches) && matches.length >= 1 && (Array.isArray(searchValues) && searchValues.length === 1)) {
5101 searchValues[0] = searchTerm;
5102 }
5103 // filter search terms should always be string type (even though we permit the end user to input numbers)
5104 // so make sure each term are strings, if user has some default search terms, we will cast them to string
5105 if (searchValues && Array.isArray(searchValues) && fieldType !== exports.FieldType.object) {
5106 for (var k = 0, ln = searchValues.length; k < ln; k++) {
5107 // make sure all search terms are strings
5108 searchValues[k] = ((searchValues[k] === undefined || searchValues[k] === null) ? '' : searchValues[k]) + '';
5109 }
5110 }
5111 // when using localization (i18n), we should use the formatter output to search as the new cell value
5112 if (columnDef && columnDef.params && columnDef.params.useFormatterOuputToFilter) {
5113 var rowIndex = (dataView && typeof dataView.getIdxById === 'function') ? dataView.getIdxById(item.id) : 0;
5114 cellValue = columnDef.formatter(rowIndex, columnIndex, cellValue, columnDef, item, this._grid);
5115 }
5116 // make sure cell value is always a string
5117 if (typeof cellValue === 'number') {
5118 cellValue = cellValue.toString();
5119 }
5120 var conditionOptions = {
5121 dataKey: dataKey,
5122 fieldType: fieldType,
5123 searchTerms: searchValues,
5124 cellValue: cellValue,
5125 operator: operator,
5126 cellValueLastChar: lastValueChar,
5127 filterSearchType: filterSearchType
5128 };
5129 if (!FilterConditions.executeMappedCondition(conditionOptions)) {
5130 return false;
5131 }
5132 }
5133 }
5134 catch (e_1_1) { e_1 = { error: e_1_1 }; }
5135 finally {
5136 try {
5137 if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
5138 }
5139 finally { if (e_1) throw e_1.error; }
5140 }
5141 return true;
5142 };
5143 FilterService.prototype.executeBackendCallback = function (event, args, startTime, backendApi) {
5144 return __awaiter(this, void 0, void 0, function () {
5145 var query, process;
5146 var _this = this;
5147 return __generator(this, function (_a) {
5148 switch (_a.label) {
5149 case 0: return [4 /*yield*/, backendApi.service.processOnFilterChanged(event, args)];
5150 case 1:
5151 query = _a.sent();
5152 // emit an onFilterChanged event when it's not called by a clear filter
5153 if (args && !args.clearFilterTriggered) {
5154 this.emitFilterChanged(exports.EmitterType.remote);
5155 }
5156 process = backendApi.process(query);
5157 if (process instanceof Promise && process.then) {
5158 process.then(function (processResult) { return executeBackendProcessesCallback(startTime, processResult, backendApi, _this._gridOptions); });
5159 }
5160 else if (rxjs.isObservable(process)) {
5161 process.subscribe(function (processResult) { return executeBackendProcessesCallback(startTime, processResult, backendApi, _this._gridOptions); }, function (error) { return onBackendError(error, backendApi); });
5162 }
5163 return [2 /*return*/];
5164 }
5165 });
5166 });
5167 };
5168 FilterService.prototype.getColumnFilters = function () {
5169 return this._columnFilters;
5170 };
5171 FilterService.prototype.getFiltersMetadata = function () {
5172 return this._filtersMetadata;
5173 };
5174 FilterService.prototype.getCurrentLocalFilters = function () {
5175 var e_2, _a;
5176 var currentFilters = [];
5177 if (this._columnFilters) {
5178 try {
5179 for (var _b = __values(Object.keys(this._columnFilters)), _c = _b.next(); !_c.done; _c = _b.next()) {
5180 var colId = _c.value;
5181 var columnFilter = this._columnFilters[colId];
5182 var filter = { columnId: colId || '' };
5183 if (columnFilter && columnFilter.searchTerms) {
5184 filter.searchTerms = columnFilter.searchTerms;
5185 }
5186 if (columnFilter.operator) {
5187 filter.operator = columnFilter.operator;
5188 }
5189 if (Array.isArray(filter.searchTerms) && filter.searchTerms.length > 0 && filter.searchTerms[0] !== '') {
5190 currentFilters.push(filter);
5191 }
5192 }
5193 }
5194 catch (e_2_1) { e_2 = { error: e_2_1 }; }
5195 finally {
5196 try {
5197 if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
5198 }
5199 finally { if (e_2) throw e_2.error; }
5200 }
5201 }
5202 return currentFilters;
5203 };
5204 /**
5205 * A simple function that is binded to the subscriber and emit a change when the filter is called.
5206 * Other services, like Pagination, can then subscribe to it.
5207 * @param caller
5208 */
5209 FilterService.prototype.emitFilterChanged = function (caller) {
5210 if (caller === exports.EmitterType.remote && this._gridOptions && this._gridOptions.backendServiceApi) {
5211 var currentFilters = [];
5212 var backendService = this._gridOptions.backendServiceApi.service;
5213 if (backendService && backendService.getCurrentFilters) {
5214 currentFilters = backendService.getCurrentFilters();
5215 }
5216 this.onFilterChanged.next(currentFilters);
5217 }
5218 else if (caller === exports.EmitterType.local) {
5219 this.onFilterChanged.next(this.getCurrentLocalFilters());
5220 }
5221 };
5222 FilterService.prototype.onBackendFilterChange = function (event, args) {
5223 var _this = this;
5224 if (!args || !args.grid) {
5225 throw new Error('Something went wrong when trying to bind the "onBackendFilterChange(event, args)" function, it seems that "args" is not populated correctly');
5226 }
5227 var gridOptions = (args.grid && args.grid.getOptions) ? args.grid.getOptions() : {};
5228 var backendApi = gridOptions.backendServiceApi;
5229 if (!backendApi || !backendApi.process || !backendApi.service) {
5230 throw new Error("BackendServiceApi requires at least a \"process\" function and a \"service\" defined");
5231 }
5232 try {
5233 // keep start time & end timestamps & return it after process execution
5234 var startTime_1 = new Date();
5235 // run a preProcess callback if defined
5236 if (backendApi.preProcess) {
5237 backendApi.preProcess();
5238 }
5239 // only add a delay when user is typing, on select dropdown filter (or "Clear Filter") it will execute right away
5240 var debounceTypingDelay = 0;
5241 var isTriggeredByClearFilter = args && args.clearFilterTriggered; // was it trigger by a "Clear Filter" command?
5242 if (!isTriggeredByClearFilter && event && event.keyCode !== exports.KeyCode.ENTER && (event.type === 'input' || event.type === 'keyup' || event.type === 'keydown')) {
5243 debounceTypingDelay = backendApi.filterTypingDebounce || DEFAULT_FILTER_TYPING_DEBOUNCE;
5244 }
5245 // query backend, except when it's called by a ClearFilters then we won't
5246 if (args && args.shouldTriggerQuery) {
5247 // call the service to get a query back
5248 if (debounceTypingDelay > 0) {
5249 clearTimeout(timer);
5250 timer = setTimeout(function () { return _this.executeBackendCallback(event, args, startTime_1, backendApi); }, debounceTypingDelay);
5251 }
5252 else {
5253 this.executeBackendCallback(event, args, startTime_1, backendApi);
5254 }
5255 }
5256 }
5257 catch (error) {
5258 onBackendError(error, backendApi);
5259 }
5260 };
5261 /**
5262 * When user passes an array of preset filters, we need to pre-populate each column filter searchTerm(s)
5263 * The process is to loop through the preset filters array, find the associated column from columnDefinitions and fill in the filter object searchTerm(s)
5264 * This is basically the same as if we would manually add searchTerm(s) to a column filter object in the column definition, but we do it programmatically.
5265 * At the end of the day, when creating the Filter (DOM Element), it will use these searchTerm(s) so we can take advantage of that without recoding each Filter type (DOM element)
5266 */
5267 FilterService.prototype.populateColumnFilterSearchTerms = function () {
5268 if (this._gridOptions.presets && Array.isArray(this._gridOptions.presets.filters) && this._gridOptions.presets.filters.length > 0) {
5269 var filters_1 = this._gridOptions.presets.filters;
5270 this._columnDefinitions.forEach(function (columnDef) {
5271 // clear any columnDef searchTerms before applying Presets
5272 if (columnDef.filter && columnDef.filter.searchTerms) {
5273 delete columnDef.filter.searchTerms;
5274 }
5275 // from each presets, we will find the associated columnDef and apply the preset searchTerms & operator if there is
5276 var columnPreset = filters_1.find(function (presetFilter) {
5277 return presetFilter.columnId === columnDef.id;
5278 });
5279 if (columnPreset && columnPreset.searchTerms && Array.isArray(columnPreset.searchTerms)) {
5280 columnDef.filter = columnDef.filter || {};
5281 columnDef.filter.operator = columnPreset.operator || columnDef.filter.operator || '';
5282 columnDef.filter.searchTerms = columnPreset.searchTerms;
5283 }
5284 });
5285 }
5286 };
5287 // --
5288 // private functions
5289 // -------------------
5290 /** Add all created filters (from their template) to the header row section area */
5291 FilterService.prototype.addFilterTemplateToHeaderRow = function (args, isFilterFirstRender) {
5292 if (isFilterFirstRender === void 0) { isFilterFirstRender = true; }
5293 var columnDef = args.column;
5294 var columnId = columnDef.id || '';
5295 if (columnDef && columnId !== 'selector' && columnDef.filterable) {
5296 var searchTerms = void 0;
5297 var operator = void 0;
5298 var newFilter_1 = this.filterFactory.createFilter(args.column.filter);
5299 operator = (columnDef && columnDef.filter && columnDef.filter.operator) || (newFilter_1 && newFilter_1.operator) || undefined;
5300 if (this._columnFilters[columnDef.id]) {
5301 searchTerms = this._columnFilters[columnDef.id].searchTerms || undefined;
5302 operator = this._columnFilters[columnDef.id].operator || undefined;
5303 }
5304 else if (columnDef.filter) {
5305 // when hiding/showing (with Column Picker or Grid Menu), it will try to re-create yet again the filters (since SlickGrid does a re-render)
5306 // because of that we need to first get searchTerm(s) from the columnFilters (that is what the user last typed in a filter search input)
5307 searchTerms = columnDef.filter.searchTerms || undefined;
5308 this.updateColumnFilters(searchTerms, columnDef, operator);
5309 }
5310 var filterArguments = {
5311 grid: this._grid,
5312 operator: operator,
5313 searchTerms: searchTerms,
5314 columnDef: columnDef,
5315 callback: this.callbackSearchEvent.bind(this)
5316 };
5317 if (newFilter_1) {
5318 newFilter_1.init(filterArguments, isFilterFirstRender);
5319 var filterExistIndex = this._filtersMetadata.findIndex(function (filter) { return newFilter_1.columnDef.name === filter.columnDef.name; });
5320 // add to the filters arrays or replace it when found
5321 if (filterExistIndex === -1) {
5322 this._filtersMetadata.push(newFilter_1);
5323 }
5324 else {
5325 this._filtersMetadata[filterExistIndex] = newFilter_1;
5326 }
5327 // when hiding/showing (with Column Picker or Grid Menu), it will try to re-create yet again the filters (since SlickGrid does a re-render)
5328 // we need to also set again the values in the DOM elements if the values were set by a searchTerm(s)
5329 if (searchTerms && newFilter_1.setValues) {
5330 newFilter_1.setValues(searchTerms);
5331 }
5332 }
5333 }
5334 };
5335 FilterService.prototype.updateColumnFilters = function (searchTerms, columnDef, operator) {
5336 if (searchTerms && columnDef) {
5337 this._columnFilters[columnDef.id] = {
5338 columnId: columnDef.id,
5339 columnDef: columnDef,
5340 searchTerms: searchTerms,
5341 operator: operator
5342 };
5343 }
5344 };
5345 FilterService = __decorate([
5346 core.Injectable(),
5347 __metadata("design:paramtypes", [FilterFactory])
5348 ], FilterService);
5349 return FilterService;
5350 }());
5351
5352 var SortService = /** @class */ (function () {
5353 function SortService() {
5354 this._currentLocalSorters = [];
5355 this._isBackendGrid = false;
5356 this.onSortChanged = new rxjs.Subject();
5357 this.onSortCleared = new rxjs.Subject();
5358 this._eventHandler = new Slick.EventHandler();
5359 }
5360 Object.defineProperty(SortService.prototype, "eventHandler", {
5361 /** Getter of the SlickGrid Event Handler */
5362 get: function () {
5363 return this._eventHandler;
5364 },
5365 enumerable: true,
5366 configurable: true
5367 });
5368 Object.defineProperty(SortService.prototype, "_gridOptions", {
5369 /** Getter for the Grid Options pulled through the Grid Object */
5370 get: function () {
5371 return (this._grid && this._grid.getOptions) ? this._grid.getOptions() : {};
5372 },
5373 enumerable: true,
5374 configurable: true
5375 });
5376 Object.defineProperty(SortService.prototype, "_columnDefinitions", {
5377 /** Getter for the Column Definitions pulled through the Grid Object */
5378 get: function () {
5379 return (this._grid && this._grid.getColumns) ? this._grid.getColumns() : [];
5380 },
5381 enumerable: true,
5382 configurable: true
5383 });
5384 /**
5385 * Bind a backend sort (single/multi) hook to the grid
5386 * @param grid SlickGrid Grid object
5387 * @param dataView SlickGrid DataView object
5388 */
5389 SortService.prototype.bindBackendOnSort = function (grid, dataView) {
5390 this._isBackendGrid = true;
5391 this._grid = grid;
5392 this._dataView = dataView;
5393 // subscribe to the SlickGrid event and call the backend execution
5394 this._eventHandler.subscribe(grid.onSort, this.onBackendSortChanged.bind(this));
5395 };
5396 /**
5397 * Bind a local sort (single/multi) hook to the grid
5398 * @param grid SlickGrid Grid object
5399 * @param gridOptions Grid Options object
5400 * @param dataView
5401 */
5402 SortService.prototype.bindLocalOnSort = function (grid, dataView) {
5403 var _this = this;
5404 this._isBackendGrid = false;
5405 this._grid = grid;
5406 this._dataView = dataView;
5407 this._eventHandler.subscribe(grid.onSort, function (e, args) {
5408 if (args && (args.sortCols || args.sortCol)) {
5409 // multiSort and singleSort are not exactly the same, but we want to structure it the same for the (for loop) after
5410 // also to avoid having to rewrite the for loop in the sort, we will make the singleSort an array of 1 object
5411 var sortColumns = (args.multiColumnSort) ? args.sortCols : new Array({ sortAsc: args.sortAsc, sortCol: args.sortCol });
5412 // keep current sorters
5413 _this._currentLocalSorters = []; // reset current local sorters
5414 if (Array.isArray(sortColumns)) {
5415 sortColumns.forEach(function (sortColumn) {
5416 if (sortColumn.sortCol) {
5417 _this._currentLocalSorters.push({
5418 columnId: sortColumn.sortCol.id,
5419 direction: sortColumn.sortAsc ? exports.SortDirection.ASC : exports.SortDirection.DESC
5420 });
5421 }
5422 });
5423 }
5424 _this.onLocalSortChanged(grid, dataView, sortColumns);
5425 _this.emitSortChanged(exports.EmitterType.local);
5426 }
5427 });
5428 };
5429 SortService.prototype.clearSorting = function (triggerQueryEvent) {
5430 if (triggerQueryEvent === void 0) { triggerQueryEvent = true; }
5431 if (this._grid && this._gridOptions && this._dataView) {
5432 // remove any sort icons (this setSortColumns function call really does only that)
5433 this._grid.setSortColumns([]);
5434 // we also need to trigger a sort change
5435 // for a backend grid, we will trigger a backend sort changed with an empty sort columns array
5436 // however for a local grid, we need to pass a sort column and so we will sort by the 1st column
5437 if (triggerQueryEvent) {
5438 if (this._isBackendGrid) {
5439 this.onBackendSortChanged(undefined, { grid: this._grid, sortCols: [] });
5440 }
5441 else {
5442 if (this._columnDefinitions && Array.isArray(this._columnDefinitions)) {
5443 this.onLocalSortChanged(this._grid, this._dataView, new Array({ sortAsc: true, sortCol: this._columnDefinitions[0] }));
5444 }
5445 }
5446 }
5447 else if (this._isBackendGrid) {
5448 var backendService = this._gridOptions && this._gridOptions.backendServiceApi && this._gridOptions.backendServiceApi.service;
5449 if (backendService && backendService.clearSorters) {
5450 backendService.clearSorters();
5451 }
5452 }
5453 }
5454 // set current sorter to empty & emit a sort changed event
5455 this._currentLocalSorters = [];
5456 // emit an event when sorts are all cleared
5457 this.onSortCleared.next(true);
5458 };
5459 SortService.prototype.dispose = function () {
5460 // unsubscribe all SlickGrid events
5461 if (this._eventHandler && this._eventHandler.unsubscribeAll) {
5462 this._eventHandler.unsubscribeAll();
5463 }
5464 };
5465 SortService.prototype.getCurrentLocalSorters = function () {
5466 return this._currentLocalSorters;
5467 };
5468 /**
5469 * Get current column sorts,
5470 * If a column is passed as an argument, that will be exclusion so we won't add this column to our output array since it is already in the array.
5471 * The usage of this method is that we want to know the sort prior to calling the next sorting command
5472 */
5473 SortService.prototype.getCurrentColumnSorts = function (excludedColumnId) {
5474 var _this = this;
5475 // getSortColumns() only returns sortAsc & columnId, we want the entire column definition
5476 var oldSortColumns = this._grid && this._grid.getSortColumns();
5477 // get the column definition but only keep column which are not equal to our current column
5478 if (Array.isArray(oldSortColumns)) {
5479 var sortedCols = oldSortColumns.reduce(function (cols, col) {
5480 if (!excludedColumnId || col.columnId !== excludedColumnId) {
5481 cols.push({ sortCol: _this._columnDefinitions[_this._grid.getColumnIndex(col.columnId)], sortAsc: col.sortAsc });
5482 }
5483 return cols;
5484 }, []);
5485 return sortedCols;
5486 }
5487 return [];
5488 };
5489 /**
5490 * Load any presets, if there are any, that are defined in the Grid Options
5491 * @param grid
5492 * @param dataView
5493 */
5494 SortService.prototype.loadLocalGridPresets = function (grid, dataView) {
5495 var _this = this;
5496 var sortCols = [];
5497 this._currentLocalSorters = []; // reset current local sorters
5498 if (this._gridOptions && this._gridOptions.presets && this._gridOptions.presets.sorters) {
5499 var sorters = this._gridOptions.presets.sorters;
5500 sorters.forEach(function (presetSorting) {
5501 var gridColumn = _this._columnDefinitions.find(function (col) { return col.id === presetSorting.columnId; });
5502 if (gridColumn) {
5503 sortCols.push({
5504 columnId: gridColumn.id,
5505 sortAsc: ((presetSorting.direction.toUpperCase() === exports.SortDirection.ASC) ? true : false),
5506 sortCol: gridColumn
5507 });
5508 // keep current sorters
5509 _this._currentLocalSorters.push({
5510 columnId: gridColumn.id + '',
5511 direction: presetSorting.direction.toUpperCase()
5512 });
5513 }
5514 });
5515 if (sortCols.length > 0) {
5516 this.onLocalSortChanged(grid, dataView, sortCols);
5517 grid.setSortColumns(sortCols); // use this to add sort icon(s) in UI
5518 }
5519 }
5520 };
5521 SortService.prototype.onBackendSortChanged = function (event, args) {
5522 var _this = this;
5523 if (!args || !args.grid) {
5524 throw new Error('Something went wrong when trying to bind the "onBackendSortChanged(event, args)" function, it seems that "args" is not populated correctly');
5525 }
5526 var gridOptions = (args.grid && args.grid.getOptions) ? args.grid.getOptions() : {};
5527 var backendApi = gridOptions.backendServiceApi;
5528 if (!backendApi || !backendApi.process || !backendApi.service) {
5529 throw new Error("BackendServiceApi requires at least a \"process\" function and a \"service\" defined");
5530 }
5531 // keep start time & end timestamps & return it after process execution
5532 var startTime = new Date();
5533 if (backendApi.preProcess) {
5534 backendApi.preProcess();
5535 }
5536 var query = backendApi.service.processOnSortChanged(event, args);
5537 this.emitSortChanged(exports.EmitterType.remote);
5538 // the processes can be Observables (like HttpClient) or Promises
5539 var process = backendApi.process(query);
5540 if (process instanceof Promise && process.then) {
5541 process.then(function (processResult) { return executeBackendProcessesCallback(startTime, processResult, backendApi, _this._gridOptions); })
5542 .catch(function (error) { return onBackendError(error, backendApi); });
5543 }
5544 else if (rxjs.isObservable(process)) {
5545 process.subscribe(function (processResult) { return executeBackendProcessesCallback(startTime, processResult, backendApi, _this._gridOptions); }, function (error) { return onBackendError(error, backendApi); });
5546 }
5547 };
5548 SortService.prototype.onLocalSortChanged = function (grid, dataView, sortColumns, forceReSort) {
5549 if (forceReSort === void 0) { forceReSort = false; }
5550 if (grid && dataView) {
5551 if (forceReSort) {
5552 dataView.reSort();
5553 }
5554 dataView.sort(this.sortComparer.bind(this, sortColumns));
5555 grid.invalidate();
5556 grid.render();
5557 }
5558 };
5559 SortService.prototype.sortComparer = function (sortColumns, dataRow1, dataRow2) {
5560 if (Array.isArray(sortColumns)) {
5561 for (var i = 0, l = sortColumns.length; i < l; i++) {
5562 var columnSortObj = sortColumns[i];
5563 if (columnSortObj && columnSortObj.sortCol) {
5564 var sortDirection = columnSortObj.sortAsc ? exports.SortDirectionNumber.asc : exports.SortDirectionNumber.desc;
5565 var sortField = columnSortObj.sortCol.queryFieldSorter || columnSortObj.sortCol.queryField || columnSortObj.sortCol.field;
5566 var fieldType = columnSortObj.sortCol.type || exports.FieldType.string;
5567 var value1 = dataRow1[sortField];
5568 var value2 = dataRow2[sortField];
5569 // when item is a complex object (dot "." notation), we need to filter the value contained in the object tree
5570 if (sortField && sortField.indexOf('.') >= 0) {
5571 value1 = getDescendantProperty(dataRow1, sortField);
5572 value2 = getDescendantProperty(dataRow2, sortField);
5573 }
5574 // user could provide his own custom Sorter
5575 if (columnSortObj.sortCol && columnSortObj.sortCol.sorter) {
5576 var customSortResult = columnSortObj.sortCol.sorter(value1, value2, sortDirection, columnSortObj.sortCol);
5577 if (customSortResult !== exports.SortDirectionNumber.neutral) {
5578 return customSortResult;
5579 }
5580 }
5581 else {
5582 var sortResult = sortByFieldType(value1, value2, fieldType, sortDirection, columnSortObj.sortCol);
5583 if (sortResult !== exports.SortDirectionNumber.neutral) {
5584 return sortResult;
5585 }
5586 }
5587 }
5588 }
5589 }
5590 return exports.SortDirectionNumber.neutral;
5591 };
5592 // --
5593 // private functions
5594 // ------------------
5595 /**
5596 * A simple function that is binded to the subscriber and emit a change when the sort is called.
5597 * Other services, like Pagination, can then subscribe to it.
5598 * @param sender
5599 */
5600 SortService.prototype.emitSortChanged = function (sender) {
5601 if (sender === exports.EmitterType.remote && this._gridOptions && this._gridOptions.backendServiceApi) {
5602 var currentSorters = [];
5603 var backendService = this._gridOptions.backendServiceApi.service;
5604 if (backendService && backendService.getCurrentSorters) {
5605 currentSorters = backendService.getCurrentSorters();
5606 }
5607 this.onSortChanged.next(currentSorters);
5608 }
5609 else if (sender === exports.EmitterType.local) {
5610 this.onSortChanged.next(this.getCurrentLocalSorters());
5611 }
5612 };
5613 return SortService;
5614 }());
5615
5616 var GridMenuExtension = /** @class */ (function () {
5617 function GridMenuExtension(exportService, extensionUtility, filterService, sharedService, sortService, translate) {
5618 this.exportService = exportService;
5619 this.extensionUtility = extensionUtility;
5620 this.filterService = filterService;
5621 this.sharedService = sharedService;
5622 this.sortService = sortService;
5623 this.translate = translate;
5624 this._areVisibleColumnDifferent = false;
5625 this._eventHandler = new Slick.EventHandler();
5626 }
5627 Object.defineProperty(GridMenuExtension.prototype, "eventHandler", {
5628 get: function () {
5629 return this._eventHandler;
5630 },
5631 enumerable: true,
5632 configurable: true
5633 });
5634 GridMenuExtension.prototype.dispose = function () {
5635 // unsubscribe all SlickGrid events
5636 this._eventHandler.unsubscribeAll();
5637 if (this._addon && this._addon.destroy) {
5638 this._addon.destroy();
5639 }
5640 };
5641 GridMenuExtension.prototype.showGridMenu = function (e) {
5642 this._addon.showGridMenu(e);
5643 };
5644 /** Create the Header Menu and expose all the available hooks that user can subscribe (onCommand, onBeforeMenuShow, ...) */
5645 GridMenuExtension.prototype.register = function () {
5646 var _this = this;
5647 // keep original user grid menu, useful when switching locale to translate
5648 this._userOriginalGridMenu = __assign({}, this.sharedService.gridOptions.gridMenu);
5649 if (this.sharedService.gridOptions && this.sharedService.gridOptions.gridMenu) {
5650 // dynamically import the SlickGrid plugin (addon) with RequireJS
5651 this.extensionUtility.loadExtensionDynamically(exports.ExtensionName.gridMenu);
5652 this.sharedService.gridOptions.gridMenu = __assign({}, this.getDefaultGridMenuOptions(), this.sharedService.gridOptions.gridMenu);
5653 // merge original user grid menu items with internal items
5654 // then sort all Grid Menu Custom Items (sorted by pointer, no need to use the return)
5655 this.sharedService.gridOptions.gridMenu.customItems = __spread(this._userOriginalGridMenu.customItems || [], this.addGridMenuCustomCommands());
5656 this.extensionUtility.translateItems(this.sharedService.gridOptions.gridMenu.customItems, 'titleKey', 'title');
5657 this.extensionUtility.sortItems(this.sharedService.gridOptions.gridMenu.customItems, 'positionOrder');
5658 this._addon = new Slick.Controls.GridMenu(this.sharedService.columnDefinitions, this.sharedService.grid, this.sharedService.gridOptions);
5659 // hook all events
5660 if (this.sharedService.grid && this.sharedService.gridOptions.gridMenu) {
5661 if (this.sharedService.gridOptions.gridMenu.onExtensionRegistered) {
5662 this.sharedService.gridOptions.gridMenu.onExtensionRegistered(this._addon);
5663 }
5664 this._eventHandler.subscribe(this._addon.onBeforeMenuShow, function (e, args) {
5665 if (_this.sharedService.gridOptions.gridMenu && typeof _this.sharedService.gridOptions.gridMenu.onBeforeMenuShow === 'function') {
5666 _this.sharedService.gridOptions.gridMenu.onBeforeMenuShow(e, args);
5667 }
5668 });
5669 this._eventHandler.subscribe(this._addon.onColumnsChanged, function (e, args) {
5670 _this._areVisibleColumnDifferent = true;
5671 if (_this.sharedService.gridOptions.gridMenu && typeof _this.sharedService.gridOptions.gridMenu.onColumnsChanged === 'function') {
5672 _this.sharedService.gridOptions.gridMenu.onColumnsChanged(e, args);
5673 }
5674 });
5675 this._eventHandler.subscribe(this._addon.onCommand, function (e, args) {
5676 _this.executeGridMenuInternalCustomCommands(e, args);
5677 if (_this.sharedService.gridOptions.gridMenu && typeof _this.sharedService.gridOptions.gridMenu.onCommand === 'function') {
5678 _this.sharedService.gridOptions.gridMenu.onCommand(e, args);
5679 }
5680 });
5681 this._eventHandler.subscribe(this._addon.onMenuClose, function (e, args) {
5682 if (_this.sharedService.gridOptions.gridMenu && typeof _this.sharedService.gridOptions.gridMenu.onMenuClose === 'function') {
5683 _this.sharedService.gridOptions.gridMenu.onMenuClose(e, args);
5684 }
5685 // we also want to resize the columns if the user decided to hide certain column(s)
5686 if (_this.sharedService.grid && typeof _this.sharedService.grid.autosizeColumns === 'function') {
5687 // make sure that the grid still exist (by looking if the Grid UID is found in the DOM tree)
5688 var gridUid = _this.sharedService.grid.getUID();
5689 if (_this._areVisibleColumnDifferent && gridUid && $("." + gridUid).length > 0) {
5690 if (_this.sharedService.gridOptions && _this.sharedService.gridOptions.enableAutoSizeColumns) {
5691 _this.sharedService.grid.autosizeColumns();
5692 }
5693 _this._areVisibleColumnDifferent = false;
5694 }
5695 }
5696 });
5697 }
5698 return this._addon;
5699 }
5700 return null;
5701 };
5702 /** Refresh the dataset through the Backend Service */
5703 GridMenuExtension.prototype.refreshBackendDataset = function (gridOptions) {
5704 var _this = this;
5705 var query = '';
5706 // user can pass new set of grid options which will override current ones
5707 if (gridOptions) {
5708 this.sharedService.gridOptions = __assign({}, this.sharedService.gridOptions, gridOptions);
5709 }
5710 var backendApi = this.sharedService.gridOptions.backendServiceApi;
5711 if (!backendApi || !backendApi.service || !backendApi.process) {
5712 throw new Error("BackendServiceApi requires at least a \"process\" function and a \"service\" defined");
5713 }
5714 if (backendApi.service) {
5715 query = backendApi.service.buildQuery();
5716 }
5717 if (query && query !== '') {
5718 // keep start time & end timestamps & return it after process execution
5719 var startTime_1 = new Date();
5720 if (backendApi.preProcess) {
5721 backendApi.preProcess();
5722 }
5723 // the process could be an Observable (like HttpClient) or a Promise
5724 // in any case, we need to have a Promise so that we can await on it (if an Observable, convert it to Promise)
5725 var observableOrPromise = backendApi.process(query);
5726 castToPromise(observableOrPromise).then(function (processResult) {
5727 var endTime = new Date();
5728 // from the result, call our internal post process to update the Dataset and Pagination info
5729 if (processResult && backendApi && backendApi.internalPostProcess) {
5730 backendApi.internalPostProcess(processResult);
5731 }
5732 // send the response process to the postProcess callback
5733 if (backendApi && backendApi.postProcess) {
5734 if (processResult instanceof Object) {
5735 processResult.statistics = {
5736 startTime: startTime_1,
5737 endTime: endTime,
5738 executionTime: endTime.valueOf() - startTime_1.valueOf(),
5739 totalItemCount: _this.sharedService.gridOptions && _this.sharedService.gridOptions.pagination && _this.sharedService.gridOptions.pagination.totalItems
5740 };
5741 }
5742 backendApi.postProcess(processResult);
5743 }
5744 });
5745 }
5746 };
5747 /** Translate the Grid Menu titles and column picker */
5748 GridMenuExtension.prototype.translateGridMenu = function () {
5749 // update the properties by pointers, that is the only way to get Grid Menu Control to see the new values
5750 // we also need to call the control init so that it takes the new Grid object with latest values
5751 if (this.sharedService.gridOptions && this.sharedService.gridOptions.gridMenu) {
5752 this.sharedService.gridOptions.gridMenu.customItems = [];
5753 this.emptyGridMenuTitles();
5754 // merge original user grid menu items with internal items
5755 // then sort all Grid Menu Custom Items (sorted by pointer, no need to use the return)
5756 this.sharedService.gridOptions.gridMenu.customItems = __spread(this._userOriginalGridMenu.customItems || [], this.addGridMenuCustomCommands());
5757 this.extensionUtility.translateItems(this.sharedService.gridOptions.gridMenu.customItems, 'titleKey', 'title');
5758 this.extensionUtility.sortItems(this.sharedService.gridOptions.gridMenu.customItems, 'positionOrder');
5759 this.sharedService.gridOptions.gridMenu.columnTitle = this.extensionUtility.getPickerTitleOutputString('columnTitle', 'gridMenu');
5760 this.sharedService.gridOptions.gridMenu.forceFitTitle = this.extensionUtility.getPickerTitleOutputString('forceFitTitle', 'gridMenu');
5761 this.sharedService.gridOptions.gridMenu.syncResizeTitle = this.extensionUtility.getPickerTitleOutputString('syncResizeTitle', 'gridMenu');
5762 // translate all columns (including non-visible)
5763 this.extensionUtility.translateItems(this.sharedService.allColumns, 'headerKey', 'name');
5764 // re-initialize the Grid Menu, that will recreate all the menus & list
5765 // doing an "init()" won't drop any existing command attached
5766 if (this._addon.init) {
5767 this._addon.init(this.sharedService.grid);
5768 }
5769 }
5770 };
5771 // --
5772 // private functions
5773 // ------------------
5774 /** Create Grid Menu with Custom Commands if user has enabled Filters and/or uses a Backend Service (OData, GraphQL) */
5775 GridMenuExtension.prototype.addGridMenuCustomCommands = function () {
5776 var backendApi = this.sharedService.gridOptions.backendServiceApi || null;
5777 var gridMenuCustomItems = [];
5778 if (this.sharedService.gridOptions && this.sharedService.gridOptions.enableFiltering) {
5779 // show grid menu: clear all filters
5780 if (this.sharedService.gridOptions && this.sharedService.gridOptions.gridMenu && !this.sharedService.gridOptions.gridMenu.hideClearAllFiltersCommand) {
5781 gridMenuCustomItems.push({
5782 iconCssClass: this.sharedService.gridOptions.gridMenu.iconClearAllFiltersCommand || 'fa fa-filter text-danger',
5783 title: this.sharedService.gridOptions.enableTranslate ? this.translate.instant('CLEAR_ALL_FILTERS') : Constants.TEXT_CLEAR_ALL_FILTERS,
5784 disabled: false,
5785 command: 'clear-filter',
5786 positionOrder: 50
5787 });
5788 }
5789 // show grid menu: toggle filter row
5790 if (this.sharedService.gridOptions && this.sharedService.gridOptions.gridMenu && !this.sharedService.gridOptions.gridMenu.hideToggleFilterCommand) {
5791 gridMenuCustomItems.push({
5792 iconCssClass: this.sharedService.gridOptions.gridMenu.iconToggleFilterCommand || 'fa fa-random',
5793 title: this.sharedService.gridOptions.enableTranslate ? this.translate.instant('TOGGLE_FILTER_ROW') : Constants.TEXT_TOGGLE_FILTER_ROW,
5794 disabled: false,
5795 command: 'toggle-filter',
5796 positionOrder: 52
5797 });
5798 }
5799 // show grid menu: refresh dataset
5800 if (this.sharedService.gridOptions && this.sharedService.gridOptions.gridMenu && !this.sharedService.gridOptions.gridMenu.hideRefreshDatasetCommand && backendApi) {
5801 gridMenuCustomItems.push({
5802 iconCssClass: this.sharedService.gridOptions.gridMenu.iconRefreshDatasetCommand || 'fa fa-refresh',
5803 title: this.sharedService.gridOptions.enableTranslate ? this.translate.instant('REFRESH_DATASET') : Constants.TEXT_REFRESH_DATASET,
5804 disabled: false,
5805 command: 'refresh-dataset',
5806 positionOrder: 54
5807 });
5808 }
5809 }
5810 if (this.sharedService.gridOptions.showPreHeaderPanel) {
5811 // show grid menu: toggle pre-header row
5812 if (this.sharedService.gridOptions && this.sharedService.gridOptions.gridMenu && !this.sharedService.gridOptions.gridMenu.hideTogglePreHeaderCommand) {
5813 gridMenuCustomItems.push({
5814 iconCssClass: this.sharedService.gridOptions.gridMenu.iconTogglePreHeaderCommand || 'fa fa-random',
5815 title: this.sharedService.gridOptions.enableTranslate ? this.translate.instant('TOGGLE_PRE_HEADER_ROW') : Constants.TEXT_TOGGLE_PRE_HEADER_ROW,
5816 disabled: false,
5817 command: 'toggle-preheader',
5818 positionOrder: 52
5819 });
5820 }
5821 }
5822 if (this.sharedService.gridOptions.enableSorting) {
5823 // show grid menu: clear all sorting
5824 if (this.sharedService.gridOptions && this.sharedService.gridOptions.gridMenu && !this.sharedService.gridOptions.gridMenu.hideClearAllSortingCommand) {
5825 gridMenuCustomItems.push({
5826 iconCssClass: this.sharedService.gridOptions.gridMenu.iconClearAllSortingCommand || 'fa fa-unsorted text-danger',
5827 title: this.sharedService.gridOptions.enableTranslate ? this.translate.instant('CLEAR_ALL_SORTING') : Constants.TEXT_CLEAR_ALL_SORTING,
5828 disabled: false,
5829 command: 'clear-sorting',
5830 positionOrder: 51
5831 });
5832 }
5833 }
5834 // show grid menu: export to file
5835 if (this.sharedService.gridOptions && this.sharedService.gridOptions.enableExport && this.sharedService.gridOptions.gridMenu && !this.sharedService.gridOptions.gridMenu.hideExportCsvCommand) {
5836 gridMenuCustomItems.push({
5837 iconCssClass: this.sharedService.gridOptions.gridMenu.iconExportCsvCommand || 'fa fa-download',
5838 title: this.sharedService.gridOptions.enableTranslate ? this.translate.instant('EXPORT_TO_CSV') : Constants.TEXT_EXPORT_IN_CSV_FORMAT,
5839 disabled: false,
5840 command: 'export-csv',
5841 positionOrder: 53
5842 });
5843 }
5844 // show grid menu: export to text file as tab delimited
5845 if (this.sharedService.gridOptions && this.sharedService.gridOptions.enableExport && this.sharedService.gridOptions.gridMenu && !this.sharedService.gridOptions.gridMenu.hideExportTextDelimitedCommand) {
5846 gridMenuCustomItems.push({
5847 iconCssClass: this.sharedService.gridOptions.gridMenu.iconExportTextDelimitedCommand || 'fa fa-download',
5848 title: this.sharedService.gridOptions.enableTranslate ? this.translate.instant('EXPORT_TO_TAB_DELIMITED') : Constants.TEXT_EXPORT_IN_TEXT_FORMAT,
5849 disabled: false,
5850 command: 'export-text-delimited',
5851 positionOrder: 54
5852 });
5853 }
5854 // add the custom "Commands" title if there are any commands
5855 if (this.sharedService.gridOptions && this.sharedService.gridOptions.gridMenu && (gridMenuCustomItems.length > 0 || (this.sharedService.gridOptions.gridMenu.customItems && this.sharedService.gridOptions.gridMenu.customItems.length > 0))) {
5856 this.sharedService.gridOptions.gridMenu.customTitle = this.sharedService.gridOptions.gridMenu.customTitle || this.extensionUtility.getPickerTitleOutputString('customTitle', 'gridMenu');
5857 }
5858 return gridMenuCustomItems;
5859 };
5860 /**
5861 * Execute the Grid Menu Custom command callback that was triggered by the onCommand subscribe
5862 * These are the default internal custom commands
5863 * @param event
5864 * @param GridMenuItem args
5865 */
5866 GridMenuExtension.prototype.executeGridMenuInternalCustomCommands = function (e, args) {
5867 if (args && args.command) {
5868 switch (args.command) {
5869 case 'clear-filter':
5870 this.filterService.clearFilters();
5871 this.sharedService.dataView.refresh();
5872 break;
5873 case 'clear-sorting':
5874 this.sortService.clearSorting();
5875 this.sharedService.dataView.refresh();
5876 break;
5877 case 'export-csv':
5878 this.exportService.exportToFile({
5879 delimiter: exports.DelimiterType.comma,
5880 filename: 'export',
5881 format: exports.FileType.csv,
5882 useUtf8WithBom: true
5883 });
5884 break;
5885 case 'export-text-delimited':
5886 this.exportService.exportToFile({
5887 delimiter: exports.DelimiterType.tab,
5888 filename: 'export',
5889 format: exports.FileType.txt,
5890 useUtf8WithBom: true
5891 });
5892 break;
5893 case 'toggle-filter':
5894 var showHeaderRow = this.sharedService && this.sharedService.gridOptions && this.sharedService.gridOptions.showHeaderRow || false;
5895 this.sharedService.grid.setHeaderRowVisibility(!showHeaderRow);
5896 break;
5897 case 'toggle-toppanel':
5898 var showTopPanel = this.sharedService && this.sharedService.gridOptions && this.sharedService.gridOptions.showTopPanel || false;
5899 this.sharedService.grid.setTopPanelVisibility(!showTopPanel);
5900 break;
5901 case 'toggle-preheader':
5902 var showPreHeaderPanel = this.sharedService && this.sharedService.gridOptions && this.sharedService.gridOptions.showPreHeaderPanel || false;
5903 this.sharedService.grid.setPreHeaderPanelVisibility(!showPreHeaderPanel);
5904 break;
5905 case 'refresh-dataset':
5906 this.refreshBackendDataset();
5907 break;
5908 default:
5909 break;
5910 }
5911 }
5912 };
5913 GridMenuExtension.prototype.emptyGridMenuTitles = function () {
5914 if (this.sharedService && this.sharedService.gridOptions && this.sharedService.gridOptions.gridMenu) {
5915 this.sharedService.gridOptions.gridMenu.customTitle = '';
5916 this.sharedService.gridOptions.gridMenu.columnTitle = '';
5917 this.sharedService.gridOptions.gridMenu.forceFitTitle = '';
5918 this.sharedService.gridOptions.gridMenu.syncResizeTitle = '';
5919 }
5920 };
5921 /** @return default Grid Menu options */
5922 GridMenuExtension.prototype.getDefaultGridMenuOptions = function () {
5923 return {
5924 customTitle: undefined,
5925 columnTitle: this.extensionUtility.getPickerTitleOutputString('columnTitle', 'gridMenu'),
5926 forceFitTitle: this.extensionUtility.getPickerTitleOutputString('forceFitTitle', 'gridMenu'),
5927 syncResizeTitle: this.extensionUtility.getPickerTitleOutputString('syncResizeTitle', 'gridMenu'),
5928 iconCssClass: 'fa fa-bars',
5929 menuWidth: 18,
5930 customItems: [],
5931 hideClearAllFiltersCommand: false,
5932 hideRefreshDatasetCommand: false,
5933 hideToggleFilterCommand: false,
5934 };
5935 };
5936 GridMenuExtension = __decorate([
5937 core.Injectable(),
5938 __metadata("design:paramtypes", [ExportService,
5939 ExtensionUtility,
5940 FilterService,
5941 SharedService,
5942 SortService,
5943 core$1.TranslateService])
5944 ], GridMenuExtension);
5945 return GridMenuExtension;
5946 }());
5947
5948 var GroupItemMetaProviderExtension = /** @class */ (function () {
5949 function GroupItemMetaProviderExtension(sharedService) {
5950 this.sharedService = sharedService;
5951 }
5952 GroupItemMetaProviderExtension.prototype.dispose = function () {
5953 if (this._addon && this._addon.destroy) {
5954 this._addon.destroy();
5955 }
5956 };
5957 /** register the group item metadata provider to add expand/collapse group handlers */
5958 GroupItemMetaProviderExtension.prototype.register = function () {
5959 if (this.sharedService && this.sharedService.grid) {
5960 this._addon = this.sharedService.groupItemMetadataProvider || {};
5961 this.sharedService.grid.registerPlugin(this._addon);
5962 return this._addon;
5963 }
5964 return null;
5965 };
5966 GroupItemMetaProviderExtension = __decorate([
5967 core.Injectable(),
5968 __metadata("design:paramtypes", [SharedService])
5969 ], GroupItemMetaProviderExtension);
5970 return GroupItemMetaProviderExtension;
5971 }());
5972
5973 var HeaderButtonExtension = /** @class */ (function () {
5974 function HeaderButtonExtension(extensionUtility, sharedService) {
5975 this.extensionUtility = extensionUtility;
5976 this.sharedService = sharedService;
5977 this._eventHandler = new Slick.EventHandler();
5978 }
5979 Object.defineProperty(HeaderButtonExtension.prototype, "eventHandler", {
5980 get: function () {
5981 return this._eventHandler;
5982 },
5983 enumerable: true,
5984 configurable: true
5985 });
5986 HeaderButtonExtension.prototype.dispose = function () {
5987 // unsubscribe all SlickGrid events
5988 this._eventHandler.unsubscribeAll();
5989 if (this._addon && this._addon.destroy) {
5990 this._addon.destroy();
5991 }
5992 };
5993 // Header Button Plugin
5994 HeaderButtonExtension.prototype.register = function () {
5995 var _this = this;
5996 if (this.sharedService && this.sharedService.grid && this.sharedService.gridOptions) {
5997 // dynamically import the SlickGrid plugin (addon) with RequireJS
5998 this.extensionUtility.loadExtensionDynamically(exports.ExtensionName.headerButton);
5999 this._addon = new Slick.Plugins.HeaderButtons(this.sharedService.gridOptions.headerButton || {});
6000 this.sharedService.grid.registerPlugin(this._addon);
6001 // hook all events
6002 if (this.sharedService.grid && this.sharedService.gridOptions.headerButton) {
6003 if (this.sharedService.gridOptions.headerButton.onExtensionRegistered) {
6004 this.sharedService.gridOptions.headerButton.onExtensionRegistered(this._addon);
6005 }
6006 this._eventHandler.subscribe(this._addon.onCommand, function (e, args) {
6007 if (_this.sharedService.gridOptions.headerButton && typeof _this.sharedService.gridOptions.headerButton.onCommand === 'function') {
6008 _this.sharedService.gridOptions.headerButton.onCommand(e, args);
6009 }
6010 });
6011 }
6012 return this._addon;
6013 }
6014 return null;
6015 };
6016 HeaderButtonExtension = __decorate([
6017 core.Injectable(),
6018 __metadata("design:paramtypes", [ExtensionUtility, SharedService])
6019 ], HeaderButtonExtension);
6020 return HeaderButtonExtension;
6021 }());
6022
6023 var HeaderMenuExtension = /** @class */ (function () {
6024 function HeaderMenuExtension(extensionUtility, filterService, sharedService, sortService, translate) {
6025 this.extensionUtility = extensionUtility;
6026 this.filterService = filterService;
6027 this.sharedService = sharedService;
6028 this.sortService = sortService;
6029 this.translate = translate;
6030 this._eventHandler = new Slick.EventHandler();
6031 }
6032 Object.defineProperty(HeaderMenuExtension.prototype, "eventHandler", {
6033 get: function () {
6034 return this._eventHandler;
6035 },
6036 enumerable: true,
6037 configurable: true
6038 });
6039 HeaderMenuExtension.prototype.dispose = function () {
6040 // unsubscribe all SlickGrid events
6041 this._eventHandler.unsubscribeAll();
6042 if (this._addon && this._addon.destroy) {
6043 this._addon.destroy();
6044 }
6045 };
6046 /**
6047 * Create the Header Menu and expose all the available hooks that user can subscribe (onCommand, onBeforeMenuShow, ...)
6048 * @param grid
6049 * @param dataView
6050 * @param columnDefinitions
6051 */
6052 HeaderMenuExtension.prototype.register = function () {
6053 var _this = this;
6054 if (this.sharedService && this.sharedService.grid && this.sharedService.gridOptions) {
6055 // dynamically import the SlickGrid plugin (addon) with RequireJS
6056 this.extensionUtility.loadExtensionDynamically(exports.ExtensionName.headerMenu);
6057 this.sharedService.gridOptions.headerMenu = __assign({}, this.getDefaultHeaderMenuOptions(), this.sharedService.gridOptions.headerMenu);
6058 if (this.sharedService.gridOptions.enableHeaderMenu) {
6059 this.sharedService.gridOptions.headerMenu = this.addHeaderMenuCustomCommands(this.sharedService.gridOptions, this.sharedService.columnDefinitions);
6060 }
6061 this._addon = new Slick.Plugins.HeaderMenu(this.sharedService.gridOptions.headerMenu);
6062 this.sharedService.grid.registerPlugin(this._addon);
6063 // hook all events
6064 if (this.sharedService.grid && this.sharedService.gridOptions.headerMenu) {
6065 if (this.sharedService.gridOptions.headerMenu.onExtensionRegistered) {
6066 this.sharedService.gridOptions.headerMenu.onExtensionRegistered(this._addon);
6067 }
6068 this._eventHandler.subscribe(this._addon.onCommand, function (e, args) {
6069 _this.executeHeaderMenuInternalCommands(e, args);
6070 if (_this.sharedService.gridOptions.headerMenu && typeof _this.sharedService.gridOptions.headerMenu.onCommand === 'function') {
6071 _this.sharedService.gridOptions.headerMenu.onCommand(e, args);
6072 }
6073 });
6074 this._eventHandler.subscribe(this._addon.onBeforeMenuShow, function (e, args) {
6075 if (_this.sharedService.gridOptions.headerMenu && typeof _this.sharedService.gridOptions.headerMenu.onBeforeMenuShow === 'function') {
6076 _this.sharedService.gridOptions.headerMenu.onBeforeMenuShow(e, args);
6077 }
6078 });
6079 }
6080 return this._addon;
6081 }
6082 return null;
6083 };
6084 /**
6085 * Create Header Menu with Custom Commands if user has enabled Header Menu
6086 * @param options
6087 * @param columnDefinitions
6088 * @return header menu
6089 */
6090 HeaderMenuExtension.prototype.addHeaderMenuCustomCommands = function (options, columnDefinitions) {
6091 var _this = this;
6092 var headerMenuOptions = options.headerMenu || {};
6093 if (columnDefinitions && Array.isArray(columnDefinitions) && options.enableHeaderMenu) {
6094 columnDefinitions.forEach(function (columnDef) {
6095 if (columnDef && !columnDef.excludeFromHeaderMenu) {
6096 if (!columnDef.header || !columnDef.header.menu) {
6097 columnDef.header = {
6098 menu: {
6099 items: []
6100 }
6101 };
6102 }
6103 var columnHeaderMenuItems = columnDef && columnDef.header && columnDef.header.menu && columnDef.header.menu.items || [];
6104 // Sorting Commands
6105 if (options.enableSorting && columnDef.sortable && headerMenuOptions && !headerMenuOptions.hideSortCommands) {
6106 if (columnHeaderMenuItems.filter(function (item) { return item.command === 'sort-asc'; }).length === 0) {
6107 columnHeaderMenuItems.push({
6108 iconCssClass: headerMenuOptions.iconSortAscCommand || 'fa fa-sort-asc',
6109 title: options.enableTranslate ? _this.translate.instant('SORT_ASCENDING') : Constants.TEXT_SORT_ASCENDING,
6110 command: 'sort-asc',
6111 positionOrder: 50
6112 });
6113 }
6114 if (columnHeaderMenuItems.filter(function (item) { return item.command === 'sort-desc'; }).length === 0) {
6115 columnHeaderMenuItems.push({
6116 iconCssClass: headerMenuOptions.iconSortDescCommand || 'fa fa-sort-desc',
6117 title: options.enableTranslate ? _this.translate.instant('SORT_DESCENDING') : Constants.TEXT_SORT_DESCENDING,
6118 command: 'sort-desc',
6119 positionOrder: 51
6120 });
6121 }
6122 // add a divider (separator) between the top sort commands and the other clear commands
6123 if (columnHeaderMenuItems.filter(function (item) { return item.positionOrder === 52; }).length === 0) {
6124 columnHeaderMenuItems.push({ divider: true, command: '', positionOrder: 52 });
6125 }
6126 if (!headerMenuOptions.hideClearSortCommand && columnHeaderMenuItems.filter(function (item) { return item.command === 'clear-sort'; }).length === 0) {
6127 columnHeaderMenuItems.push({
6128 iconCssClass: headerMenuOptions.iconClearSortCommand || 'fa fa-unsorted',
6129 title: options.enableTranslate ? _this.translate.instant('REMOVE_SORT') : Constants.TEXT_REMOVE_SORT,
6130 command: 'clear-sort',
6131 positionOrder: 54
6132 });
6133 }
6134 }
6135 // Filtering Commands
6136 if (options.enableFiltering && columnDef.filterable && headerMenuOptions && !headerMenuOptions.hideFilterCommands) {
6137 if (!headerMenuOptions.hideClearFilterCommand && columnHeaderMenuItems.filter(function (item) { return item.command === 'clear-filter'; }).length === 0) {
6138 columnHeaderMenuItems.push({
6139 iconCssClass: headerMenuOptions.iconClearFilterCommand || 'fa fa-filter',
6140 title: options.enableTranslate ? _this.translate.instant('REMOVE_FILTER') : Constants.TEXT_REMOVE_FILTER,
6141 command: 'clear-filter',
6142 positionOrder: 53
6143 });
6144 }
6145 }
6146 // Hide Column Command
6147 if (headerMenuOptions && !headerMenuOptions.hideColumnHideCommand && columnHeaderMenuItems.filter(function (item) { return item.command === 'hide'; }).length === 0) {
6148 columnHeaderMenuItems.push({
6149 iconCssClass: headerMenuOptions.iconColumnHideCommand || 'fa fa-times',
6150 title: options.enableTranslate ? _this.translate.instant('HIDE_COLUMN') : Constants.TEXT_HIDE_COLUMN,
6151 command: 'hide',
6152 positionOrder: 55
6153 });
6154 }
6155 _this.extensionUtility.translateItems(columnHeaderMenuItems, 'titleKey', 'title');
6156 _this.extensionUtility.sortItems(columnHeaderMenuItems, 'positionOrder');
6157 }
6158 });
6159 }
6160 return headerMenuOptions;
6161 };
6162 /** Hide a column from the grid */
6163 HeaderMenuExtension.prototype.hideColumn = function (column) {
6164 if (this.sharedService.grid && this.sharedService.grid.getColumns && this.sharedService.grid.setColumns && this.sharedService.grid.getColumnIndex) {
6165 var columnIndex = this.sharedService.grid.getColumnIndex(column.id);
6166 var currentColumns = this.sharedService.grid.getColumns();
6167 var visibleColumns = this.extensionUtility.arrayRemoveItemByIndex(currentColumns, columnIndex);
6168 this.sharedService.visibleColumns = visibleColumns;
6169 this.sharedService.grid.setColumns(visibleColumns);
6170 }
6171 };
6172 /**
6173 * Translate the Header Menu titles, we need to loop through all column definition to re-translate them
6174 */
6175 HeaderMenuExtension.prototype.translateHeaderMenu = function () {
6176 if (this.sharedService.gridOptions && this.sharedService.gridOptions.headerMenu) {
6177 this.resetHeaderMenuTranslations(this.sharedService.visibleColumns);
6178 }
6179 };
6180 // --
6181 // private functions
6182 // ------------------
6183 /** @return default Header Menu options */
6184 HeaderMenuExtension.prototype.getDefaultHeaderMenuOptions = function () {
6185 return {
6186 autoAlignOffset: 12,
6187 minWidth: 140,
6188 hideColumnHideCommand: false,
6189 hideSortCommands: false,
6190 title: ''
6191 };
6192 };
6193 /**
6194 * Reset all the Grid Menu options which have text to translate
6195 * @param grid menu object
6196 */
6197 HeaderMenuExtension.prototype.resetHeaderMenuTranslations = function (columnDefinitions) {
6198 var _this = this;
6199 columnDefinitions.forEach(function (columnDef) {
6200 if (columnDef && columnDef.header && columnDef.header && columnDef.header.menu && columnDef.header.menu.items) {
6201 if (!columnDef.excludeFromHeaderMenu) {
6202 var columnHeaderMenuItems_1 = columnDef.header.menu.items || [];
6203 columnHeaderMenuItems_1.forEach(function (item) {
6204 switch (item.command) {
6205 case 'clear-filter':
6206 item.title = _this.translate.instant('REMOVE_FILTER') || Constants.TEXT_REMOVE_FILTER;
6207 break;
6208 case 'clear-sort':
6209 item.title = _this.translate.instant('REMOVE_SORT') || Constants.TEXT_REMOVE_SORT;
6210 break;
6211 case 'sort-asc':
6212 item.title = _this.translate.instant('SORT_ASCENDING') || Constants.TEXT_SORT_ASCENDING;
6213 break;
6214 case 'sort-desc':
6215 item.title = _this.translate.instant('SORT_DESCENDING') || Constants.TEXT_SORT_DESCENDING;
6216 break;
6217 case 'hide':
6218 item.title = _this.translate.instant('HIDE_COLUMN') || Constants.TEXT_HIDE_COLUMN;
6219 break;
6220 }
6221 // re-translate if there's a "titleKey"
6222 if (_this.sharedService.gridOptions && _this.sharedService.gridOptions.enableTranslate) {
6223 _this.extensionUtility.translateItems(columnHeaderMenuItems_1, 'titleKey', 'title');
6224 }
6225 });
6226 }
6227 }
6228 });
6229 };
6230 /** Clear the Filter on the current column (if it's actually filtered) */
6231 HeaderMenuExtension.prototype.clearColumnFilter = function (event, args) {
6232 if (args && args.column) {
6233 this.filterService.clearFilterByColumnId(event, args.column.id);
6234 }
6235 };
6236 /** Clear the Sort on the current column (if it's actually sorted) */
6237 HeaderMenuExtension.prototype.clearColumnSort = function (event, args) {
6238 if (args && args.column && this.sharedService) {
6239 // get current sorted columns, prior to calling the new column sort
6240 var allSortedCols = this.sortService.getCurrentColumnSorts();
6241 var sortedColsWithoutCurrent = this.sortService.getCurrentColumnSorts(args.column.id + '');
6242 if (Array.isArray(allSortedCols) && Array.isArray(sortedColsWithoutCurrent) && allSortedCols.length !== sortedColsWithoutCurrent.length) {
6243 if (this.sharedService.gridOptions && this.sharedService.gridOptions.backendServiceApi) {
6244 this.sortService.onBackendSortChanged(event, { multiColumnSort: true, sortCols: sortedColsWithoutCurrent, grid: this.sharedService.grid });
6245 }
6246 else if (this.sharedService.dataView) {
6247 this.sortService.onLocalSortChanged(this.sharedService.grid, this.sharedService.dataView, sortedColsWithoutCurrent, true);
6248 }
6249 else {
6250 // when using customDataView, we will simply send it as a onSort event with notify
6251 var isMultiSort = this.sharedService.gridOptions && this.sharedService.gridOptions.multiColumnSort || false;
6252 var sortOutput = isMultiSort ? sortedColsWithoutCurrent : sortedColsWithoutCurrent[0];
6253 args.grid.onSort.notify(sortOutput);
6254 }
6255 // update the this.sharedService.gridObj sortColumns array which will at the same add the visual sort icon(s) on the UI
6256 var updatedSortColumns = sortedColsWithoutCurrent.map(function (col) {
6257 return {
6258 columnId: col && col.sortCol && col.sortCol.id,
6259 sortAsc: col && col.sortAsc,
6260 sortCol: col && col.sortCol,
6261 };
6262 });
6263 this.sharedService.grid.setSortColumns(updatedSortColumns); // add sort icon in UI
6264 }
6265 }
6266 };
6267 /** Execute the Header Menu Commands that was triggered by the onCommand subscribe */
6268 HeaderMenuExtension.prototype.executeHeaderMenuInternalCommands = function (event, args) {
6269 if (args && args.command) {
6270 switch (args.command) {
6271 case 'hide':
6272 this.hideColumn(args.column);
6273 if (this.sharedService.gridOptions && this.sharedService.gridOptions.enableAutoSizeColumns) {
6274 this.sharedService.grid.autosizeColumns();
6275 }
6276 break;
6277 case 'clear-filter':
6278 this.clearColumnFilter(event, args);
6279 break;
6280 case 'clear-sort':
6281 this.clearColumnSort(event, args);
6282 break;
6283 case 'sort-asc':
6284 case 'sort-desc':
6285 var isSortingAsc = (args.command === 'sort-asc');
6286 this.sortColumn(event, args, isSortingAsc);
6287 break;
6288 default:
6289 break;
6290 }
6291 }
6292 };
6293 /** Sort the current column */
6294 HeaderMenuExtension.prototype.sortColumn = function (event, args, isSortingAsc) {
6295 if (isSortingAsc === void 0) { isSortingAsc = true; }
6296 if (args && args.column) {
6297 // get previously sorted columns
6298 var sortedColsWithoutCurrent = this.sortService.getCurrentColumnSorts(args.column.id + '');
6299 // add to the column array, the column sorted by the header menu
6300 sortedColsWithoutCurrent.push({ sortCol: args.column, sortAsc: isSortingAsc });
6301 if (this.sharedService.gridOptions.backendServiceApi) {
6302 this.sortService.onBackendSortChanged(event, { multiColumnSort: true, sortCols: sortedColsWithoutCurrent, grid: this.sharedService.grid });
6303 }
6304 else if (this.sharedService.dataView) {
6305 this.sortService.onLocalSortChanged(this.sharedService.grid, this.sharedService.dataView, sortedColsWithoutCurrent);
6306 }
6307 else {
6308 // when using customDataView, we will simply send it as a onSort event with notify
6309 var isMultiSort = this.sharedService && this.sharedService.gridOptions && this.sharedService.gridOptions.multiColumnSort || false;
6310 var sortOutput = isMultiSort ? sortedColsWithoutCurrent : sortedColsWithoutCurrent[0];
6311 args.grid.onSort.notify(sortOutput);
6312 }
6313 // update the this.sharedService.gridObj sortColumns array which will at the same add the visual sort icon(s) on the UI
6314 var newSortColumns = sortedColsWithoutCurrent.map(function (col) {
6315 return {
6316 columnId: col && col.sortCol && col.sortCol.id,
6317 sortAsc: col && col.sortAsc,
6318 sortCol: col && col.sortCol,
6319 };
6320 });
6321 this.sharedService.grid.setSortColumns(newSortColumns); // add sort icon in UI
6322 }
6323 };
6324 HeaderMenuExtension = __decorate([
6325 core.Injectable(),
6326 __metadata("design:paramtypes", [ExtensionUtility,
6327 FilterService,
6328 SharedService,
6329 SortService,
6330 core$1.TranslateService])
6331 ], HeaderMenuExtension);
6332 return HeaderMenuExtension;
6333 }());
6334
6335 var DOMPurify$1 = DOMPurify_; // patch to fix rollup to work
6336 var ROW_DETAIL_CONTAINER_PREFIX = 'container_';
6337 var PRELOAD_CONTAINER_PREFIX = 'container_loading';
6338 var RowDetailViewExtension = /** @class */ (function () {
6339 function RowDetailViewExtension(angularUtilService, appRef, extensionUtility, filterService, sharedService) {
6340 this.angularUtilService = angularUtilService;
6341 this.appRef = appRef;
6342 this.extensionUtility = extensionUtility;
6343 this.filterService = filterService;
6344 this.sharedService = sharedService;
6345 this._views = [];
6346 this._subscriptions = [];
6347 this._eventHandler = new Slick.EventHandler();
6348 }
6349 Object.defineProperty(RowDetailViewExtension.prototype, "eventHandler", {
6350 get: function () {
6351 return this._eventHandler;
6352 },
6353 enumerable: true,
6354 configurable: true
6355 });
6356 /** Dispose of the RowDetailView Extension */
6357 RowDetailViewExtension.prototype.dispose = function () {
6358 // unsubscribe all SlickGrid events
6359 this._eventHandler.unsubscribeAll();
6360 if (this._addon && this._addon.destroy) {
6361 this._addon.destroy();
6362 }
6363 // also unsubscribe all RxJS subscriptions
6364 this._subscriptions = unsubscribeAllObservables(this._subscriptions);
6365 this.disposeAllViewComponents();
6366 };
6367 /** Dispose of all the opened Row Detail Panels Angular View Components */
6368 RowDetailViewExtension.prototype.disposeAllViewComponents = function () {
6369 var _this = this;
6370 this._views.forEach(function (compRef) { return _this.disposeViewComponent(compRef); });
6371 this._views = [];
6372 };
6373 /**
6374 * Create the plugin before the Grid creation, else it will behave oddly.
6375 * Mostly because the column definitions might change after the grid creation
6376 */
6377 RowDetailViewExtension.prototype.create = function (columnDefinitions, gridOptions) {
6378 var _this = this;
6379 if (columnDefinitions && gridOptions) {
6380 // dynamically import the SlickGrid plugin (addon) with RequireJS
6381 this.extensionUtility.loadExtensionDynamically(exports.ExtensionName.rowDetailView);
6382 if (!gridOptions.rowDetailView) {
6383 throw new Error('The Row Detail View requires options to be passed via the "rowDetailView" property of the Grid Options');
6384 }
6385 if (gridOptions && gridOptions.rowDetailView) {
6386 if (!this._addon) {
6387 if (typeof gridOptions.rowDetailView.process === 'function') {
6388 // we need to keep the user "process" method and replace it with our own execution method
6389 // we do this because when we get the item detail, we need to call "onAsyncResponse.notify" for the plugin to work
6390 this._userProcessFn = gridOptions.rowDetailView.process; // keep user's process method
6391 gridOptions.rowDetailView.process = function (item) { return _this.onProcessing(item); }; // replace process method & run our internal one
6392 }
6393 else {
6394 throw new Error('You need to provide a "process" function for the Row Detail Extension to work properly');
6395 }
6396 // load the Preload & RowDetail Templates (could be straight HTML or Angular View/ViewModel)
6397 // when those are Angular View/ViewModel, we need to create View Component & provide the html containers to the Plugin (preTemplate/postTemplate methods)
6398 if (!gridOptions.rowDetailView.preTemplate) {
6399 this._preloadComponent = gridOptions && gridOptions.rowDetailView && gridOptions.rowDetailView.preloadComponent;
6400 gridOptions.rowDetailView.preTemplate = function () { return DOMPurify$1.sanitize("<div class=\"" + PRELOAD_CONTAINER_PREFIX + "\"></div>"); };
6401 }
6402 if (!gridOptions.rowDetailView.postTemplate) {
6403 this._viewComponent = gridOptions && gridOptions.rowDetailView && gridOptions.rowDetailView.viewComponent;
6404 gridOptions.rowDetailView.postTemplate = function (itemDetail) { return DOMPurify$1.sanitize("<div class=\"" + ROW_DETAIL_CONTAINER_PREFIX + itemDetail.id + "\"></div>"); };
6405 }
6406 // finally register the Row Detail View Plugin
6407 this._addon = new Slick.Plugins.RowDetailView(gridOptions.rowDetailView);
6408 }
6409 var selectionColumn = this._addon.getColumnDefinition();
6410 if (typeof selectionColumn === 'object') {
6411 selectionColumn.excludeFromExport = true;
6412 selectionColumn.excludeFromColumnPicker = true;
6413 selectionColumn.excludeFromGridMenu = true;
6414 selectionColumn.excludeFromQuery = true;
6415 selectionColumn.excludeFromHeaderMenu = true;
6416 columnDefinitions.unshift(selectionColumn);
6417 }
6418 }
6419 return this._addon;
6420 }
6421 return null;
6422 };
6423 RowDetailViewExtension.prototype.register = function (rowSelectionPlugin) {
6424 var _this = this;
6425 if (this.sharedService && this.sharedService.grid && this.sharedService.gridOptions) {
6426 // the plugin has to be created BEFORE the grid (else it behaves oddly), but we can only watch grid events AFTER the grid is created
6427 this.sharedService.grid.registerPlugin(this._addon);
6428 // this also requires the Row Selection Model to be registered as well
6429 if (!rowSelectionPlugin || !this.sharedService.grid.getSelectionModel()) {
6430 this.extensionUtility.loadExtensionDynamically(exports.ExtensionName.rowSelection);
6431 rowSelectionPlugin = new Slick.RowSelectionModel(this.sharedService.gridOptions.rowSelectionOptions || { selectActiveRow: true });
6432 this.sharedService.grid.setSelectionModel(rowSelectionPlugin);
6433 }
6434 // hook all events
6435 if (this.sharedService.grid && this.sharedService.gridOptions.rowDetailView) {
6436 if (this.sharedService.gridOptions.rowDetailView.onExtensionRegistered) {
6437 this.sharedService.gridOptions.rowDetailView.onExtensionRegistered(this._addon);
6438 }
6439 this._eventHandler.subscribe(this._addon.onAsyncResponse, function (e, args) {
6440 if (_this.sharedService.gridOptions.rowDetailView && typeof _this.sharedService.gridOptions.rowDetailView.onAsyncResponse === 'function') {
6441 _this.sharedService.gridOptions.rowDetailView.onAsyncResponse(e, args);
6442 }
6443 });
6444 this._eventHandler.subscribe(this._addon.onAsyncEndUpdate, function (e, args) {
6445 // triggers after backend called "onAsyncResponse.notify()"
6446 _this.renderViewModel(args && args.item);
6447 if (_this.sharedService.gridOptions.rowDetailView && typeof _this.sharedService.gridOptions.rowDetailView.onAsyncEndUpdate === 'function') {
6448 _this.sharedService.gridOptions.rowDetailView.onAsyncEndUpdate(e, args);
6449 }
6450 });
6451 this._eventHandler.subscribe(this._addon.onAfterRowDetailToggle, function (e, args) {
6452 // display preload template & re-render all the other Detail Views after toggling
6453 // the preload View will eventually go away once the data gets loaded after the "onAsyncEndUpdate" event
6454 _this.renderPreloadView();
6455 _this.renderAllViewComponents();
6456 if (_this.sharedService.gridOptions.rowDetailView && typeof _this.sharedService.gridOptions.rowDetailView.onAfterRowDetailToggle === 'function') {
6457 _this.sharedService.gridOptions.rowDetailView.onAfterRowDetailToggle(e, args);
6458 }
6459 });
6460 this._eventHandler.subscribe(this._addon.onBeforeRowDetailToggle, function (e, args) {
6461 // before toggling row detail, we need to create View Component if it doesn't exist
6462 _this.onBeforeRowDetailToggle(e, args);
6463 if (_this.sharedService.gridOptions.rowDetailView && typeof _this.sharedService.gridOptions.rowDetailView.onBeforeRowDetailToggle === 'function') {
6464 _this.sharedService.gridOptions.rowDetailView.onBeforeRowDetailToggle(e, args);
6465 }
6466 });
6467 this._eventHandler.subscribe(this._addon.onRowBackToViewportRange, function (e, args) {
6468 // when row is back to viewport range, we will re-render the View Component(s)
6469 _this.onRowBackToViewportRange(e, args);
6470 if (_this.sharedService.gridOptions.rowDetailView && typeof _this.sharedService.gridOptions.rowDetailView.onRowBackToViewportRange === 'function') {
6471 _this.sharedService.gridOptions.rowDetailView.onRowBackToViewportRange(e, args);
6472 }
6473 });
6474 this._eventHandler.subscribe(this._addon.onRowOutOfViewportRange, function (e, args) {
6475 if (_this.sharedService.gridOptions.rowDetailView && typeof _this.sharedService.gridOptions.rowDetailView.onRowOutOfViewportRange === 'function') {
6476 _this.sharedService.gridOptions.rowDetailView.onRowOutOfViewportRange(e, args);
6477 }
6478 });
6479 // --
6480 // hook some events needed by the Plugin itself
6481 this._eventHandler.subscribe(this.sharedService.grid.onColumnsReordered, function () { return _this.redrawAllViewComponents(); });
6482 // on sort, all row detail are collapsed so we can dispose of all the Views as well
6483 this._eventHandler.subscribe(this.sharedService.grid.onSort, function () { return _this.disposeAllViewComponents(); });
6484 // on filter changed, we need to re-render all Views
6485 this._subscriptions.push(this.filterService.onFilterChanged.subscribe(function () { return _this.redrawAllViewComponents(); }));
6486 }
6487 return this._addon;
6488 }
6489 return null;
6490 };
6491 // --
6492 // private functions
6493 // ------------------
6494 RowDetailViewExtension.prototype.disposeViewComponent = function (expandedView) {
6495 var compRef = expandedView && expandedView.componentRef;
6496 if (compRef) {
6497 this.appRef.detachView(compRef.hostView);
6498 compRef.destroy();
6499 return expandedView;
6500 }
6501 return null;
6502 };
6503 /**
6504 * notify the onAsyncResponse with the "args.item" (required property)
6505 * the plugin will then use item to populate the row detail panel with the "postTemplate"
6506 * @param item
6507 */
6508 RowDetailViewExtension.prototype.notifyTemplate = function (item) {
6509 if (this._addon) {
6510 this._addon.onAsyncResponse.notify({ item: item }, undefined, this);
6511 }
6512 };
6513 /**
6514 * On Processing, we will notify the plugin with the new item detail once backend server call completes
6515 * @param item
6516 */
6517 RowDetailViewExtension.prototype.onProcessing = function (item) {
6518 return __awaiter(this, void 0, void 0, function () {
6519 var awaitedItemDetail, userProcessFn, response;
6520 return __generator(this, function (_a) {
6521 switch (_a.label) {
6522 case 0:
6523 if (!(item && typeof this._userProcessFn === 'function')) return [3 /*break*/, 5];
6524 awaitedItemDetail = void 0;
6525 userProcessFn = this._userProcessFn(item);
6526 return [4 /*yield*/, userProcessFn];
6527 case 1:
6528 response = _a.sent();
6529 if (!response.hasOwnProperty('id')) return [3 /*break*/, 2];
6530 awaitedItemDetail = response; // from Promise
6531 return [3 /*break*/, 4];
6532 case 2:
6533 if (!(response && response instanceof rxjs.Observable || response instanceof Promise)) return [3 /*break*/, 4];
6534 return [4 /*yield*/, castToPromise(response)];
6535 case 3:
6536 awaitedItemDetail = _a.sent(); // from Angular-http-client
6537 _a.label = 4;
6538 case 4:
6539 if (!awaitedItemDetail || !awaitedItemDetail.hasOwnProperty('id')) {
6540 throw new Error("[Angular-Slickgrid] could not process the Row Detail, you must make sure that your \"process\" callback\n (a Promise or an HttpClient call returning an Observable) returns an item object that has an \"id\" property");
6541 }
6542 // notify the plugin with the new item details
6543 this.notifyTemplate(awaitedItemDetail || {});
6544 _a.label = 5;
6545 case 5: return [2 /*return*/];
6546 }
6547 });
6548 });
6549 };
6550 /**
6551 * Just before the row get expanded or collapsed we will do the following
6552 * First determine if the row is expanding or collapsing,
6553 * if it's expanding we will add it to our View Components reference array if we don't already have it
6554 * or if it's collapsing we will remove it from our View Components reference array
6555 */
6556 RowDetailViewExtension.prototype.onBeforeRowDetailToggle = function (e, args) {
6557 // expanding
6558 if (args && args.item && args.item.__collapsed) {
6559 // expanding row detail
6560 var viewInfo = {
6561 id: args.item.id,
6562 dataContext: args.item
6563 };
6564 addToArrayWhenNotExists(this._views, viewInfo);
6565 }
6566 else {
6567 // collapsing, so dispose of the View/Component
6568 var foundViewIndex = this._views.findIndex(function (view) { return view.id === args.item.id; });
6569 if (foundViewIndex >= 0 && this._views.hasOwnProperty(foundViewIndex)) {
6570 var compRef = this._views[foundViewIndex].componentRef;
6571 this.appRef.detachView(compRef.hostView);
6572 compRef.destroy();
6573 this._views.splice(foundViewIndex, 1);
6574 }
6575 }
6576 };
6577 /** When Row comes back to Viewport Range, we need to redraw the View */
6578 RowDetailViewExtension.prototype.onRowBackToViewportRange = function (e, args) {
6579 var _this = this;
6580 if (args && args.item) {
6581 this._views.forEach(function (view) {
6582 if (view.id === args.item.id) {
6583 _this.redrawViewComponent(view);
6584 }
6585 });
6586 }
6587 };
6588 /** Redraw (re-render) all the expanded row detail View Components */
6589 RowDetailViewExtension.prototype.redrawAllViewComponents = function () {
6590 var _this = this;
6591 this._views.forEach(function (compRef) {
6592 _this.redrawViewComponent(compRef);
6593 });
6594 };
6595 /** Render all the expanded row detail View Components */
6596 RowDetailViewExtension.prototype.renderAllViewComponents = function () {
6597 var _this = this;
6598 this._views.forEach(function (view) {
6599 if (view && view.dataContext) {
6600 _this.renderViewModel(view.dataContext);
6601 }
6602 });
6603 };
6604 /** Redraw the necessary View Component */
6605 RowDetailViewExtension.prototype.redrawViewComponent = function (createdView) {
6606 var containerElements = document.getElementsByClassName("" + ROW_DETAIL_CONTAINER_PREFIX + createdView.id);
6607 if (containerElements && containerElements.length) {
6608 this.renderViewModel(createdView.dataContext);
6609 }
6610 };
6611 /** Render (or rerender) the View Component (Row Detail) */
6612 RowDetailViewExtension.prototype.renderPreloadView = function () {
6613 var containerElements = document.getElementsByClassName("" + PRELOAD_CONTAINER_PREFIX);
6614 if (containerElements && containerElements.length) {
6615 this.angularUtilService.createAngularComponentAppendToDom(this._preloadComponent, containerElements[0], true);
6616 }
6617 };
6618 /** Render (or rerender) the View Component (Row Detail) */
6619 RowDetailViewExtension.prototype.renderViewModel = function (item) {
6620 var containerElements = document.getElementsByClassName("" + ROW_DETAIL_CONTAINER_PREFIX + item.id);
6621 if (containerElements && containerElements.length) {
6622 var componentOutput = this.angularUtilService.createAngularComponentAppendToDom(this._viewComponent, containerElements[0], true);
6623 if (componentOutput && componentOutput.componentRef && componentOutput.componentRef.instance) {
6624 Object.assign(componentOutput.componentRef.instance, { model: item });
6625 var viewObj = this._views.find(function (obj) { return obj.id === item.id; });
6626 if (viewObj) {
6627 viewObj.componentRef = componentOutput.componentRef;
6628 }
6629 }
6630 }
6631 };
6632 RowDetailViewExtension = __decorate([
6633 core.Injectable(),
6634 __metadata("design:paramtypes", [AngularUtilService,
6635 core.ApplicationRef,
6636 ExtensionUtility,
6637 FilterService,
6638 SharedService])
6639 ], RowDetailViewExtension);
6640 return RowDetailViewExtension;
6641 }());
6642
6643 var RowMoveManagerExtension = /** @class */ (function () {
6644 function RowMoveManagerExtension(extensionUtility, sharedService) {
6645 this.extensionUtility = extensionUtility;
6646 this.sharedService = sharedService;
6647 this._eventHandler = new Slick.EventHandler();
6648 }
6649 Object.defineProperty(RowMoveManagerExtension.prototype, "eventHandler", {
6650 get: function () {
6651 return this._eventHandler;
6652 },
6653 enumerable: true,
6654 configurable: true
6655 });
6656 RowMoveManagerExtension.prototype.dispose = function () {
6657 // unsubscribe all SlickGrid events
6658 this._eventHandler.unsubscribeAll();
6659 if (this._addon && this._addon.destroy) {
6660 this._addon.destroy();
6661 }
6662 };
6663 RowMoveManagerExtension.prototype.register = function (rowSelectionPlugin) {
6664 var _this = this;
6665 if (this.sharedService && this.sharedService.grid && this.sharedService.gridOptions) {
6666 // dynamically import the SlickGrid plugin (addon) with RequireJS
6667 this.extensionUtility.loadExtensionDynamically(exports.ExtensionName.rowMoveManager);
6668 // this also requires the Row Selection Model to be registered as well
6669 if (!rowSelectionPlugin || !this.sharedService.grid.getSelectionModel()) {
6670 this.extensionUtility.loadExtensionDynamically(exports.ExtensionName.rowSelection);
6671 rowSelectionPlugin = new Slick.RowSelectionModel(this.sharedService.gridOptions.rowSelectionOptions || {});
6672 this.sharedService.grid.setSelectionModel(rowSelectionPlugin);
6673 }
6674 this._addon = new Slick.RowMoveManager(this.sharedService.gridOptions.rowMoveManager || { cancelEditOnDrag: true });
6675 this.sharedService.grid.registerPlugin(this._addon);
6676 // hook all events
6677 if (this.sharedService.grid && this.sharedService.gridOptions.rowMoveManager) {
6678 if (this.sharedService.gridOptions.rowMoveManager.onExtensionRegistered) {
6679 this.sharedService.gridOptions.rowMoveManager.onExtensionRegistered(this._addon);
6680 }
6681 this._eventHandler.subscribe(this._addon.onBeforeMoveRows, function (e, args) {
6682 if (_this.sharedService.gridOptions.rowMoveManager && typeof _this.sharedService.gridOptions.rowMoveManager.onBeforeMoveRows === 'function') {
6683 _this.sharedService.gridOptions.rowMoveManager.onBeforeMoveRows(e, args);
6684 }
6685 });
6686 this._eventHandler.subscribe(this._addon.onMoveRows, function (e, args) {
6687 if (_this.sharedService.gridOptions.rowMoveManager && typeof _this.sharedService.gridOptions.rowMoveManager.onMoveRows === 'function') {
6688 _this.sharedService.gridOptions.rowMoveManager.onMoveRows(e, args);
6689 }
6690 });
6691 }
6692 return this._addon;
6693 }
6694 return null;
6695 };
6696 RowMoveManagerExtension = __decorate([
6697 core.Injectable(),
6698 __metadata("design:paramtypes", [ExtensionUtility, SharedService])
6699 ], RowMoveManagerExtension);
6700 return RowMoveManagerExtension;
6701 }());
6702
6703 var RowSelectionExtension = /** @class */ (function () {
6704 function RowSelectionExtension(extensionUtility, sharedService) {
6705 this.extensionUtility = extensionUtility;
6706 this.sharedService = sharedService;
6707 }
6708 RowSelectionExtension.prototype.dispose = function () {
6709 if (this._addon && this._addon.destroy) {
6710 this._addon.destroy();
6711 }
6712 };
6713 RowSelectionExtension.prototype.register = function () {
6714 if (this.sharedService && this.sharedService.grid && this.sharedService.gridOptions) {
6715 // dynamically import the SlickGrid plugin (addon) with RequireJS
6716 this.extensionUtility.loadExtensionDynamically(exports.ExtensionName.rowSelection);
6717 this._addon = new Slick.RowSelectionModel(this.sharedService.gridOptions.rowSelectionOptions || {});
6718 this.sharedService.grid.setSelectionModel(this._addon);
6719 return this._addon;
6720 }
6721 return null;
6722 };
6723 RowSelectionExtension = __decorate([
6724 core.Injectable(),
6725 __metadata("design:paramtypes", [ExtensionUtility, SharedService])
6726 ], RowSelectionExtension);
6727 return RowSelectionExtension;
6728 }());
6729
6730 var ExtensionService = /** @class */ (function () {
6731 function ExtensionService(autoTooltipExtension, cellExternalCopyExtension, checkboxSelectorExtension, columnPickerExtension, draggableGroupingExtension, gridMenuExtension, groupItemMetaExtension, headerButtonExtension, headerMenuExtension, rowDetailViewExtension, rowMoveManagerExtension, rowSelectionExtension, sharedService, translate) {
6732 this.autoTooltipExtension = autoTooltipExtension;
6733 this.cellExternalCopyExtension = cellExternalCopyExtension;
6734 this.checkboxSelectorExtension = checkboxSelectorExtension;
6735 this.columnPickerExtension = columnPickerExtension;
6736 this.draggableGroupingExtension = draggableGroupingExtension;
6737 this.gridMenuExtension = gridMenuExtension;
6738 this.groupItemMetaExtension = groupItemMetaExtension;
6739 this.headerButtonExtension = headerButtonExtension;
6740 this.headerMenuExtension = headerMenuExtension;
6741 this.rowDetailViewExtension = rowDetailViewExtension;
6742 this.rowMoveManagerExtension = rowMoveManagerExtension;
6743 this.rowSelectionExtension = rowSelectionExtension;
6744 this.sharedService = sharedService;
6745 this.translate = translate;
6746 this._extensionList = [];
6747 }
6748 /** Dispose of all the controls & plugins */
6749 ExtensionService.prototype.dispose = function () {
6750 this.sharedService.grid = null;
6751 this.sharedService.visibleColumns = [];
6752 // dispose of each control/plugin & reset the list
6753 this._extensionList.forEach(function (item) {
6754 if (item && item.class && item.class.dispose) {
6755 item.class.dispose();
6756 }
6757 });
6758 this._extensionList = [];
6759 };
6760 /** Get all columns (includes visible and non-visible) */
6761 ExtensionService.prototype.getAllColumns = function () {
6762 return this.sharedService.allColumns || [];
6763 };
6764 /** Get only visible columns */
6765 ExtensionService.prototype.getVisibleColumns = function () {
6766 return this.sharedService.visibleColumns || [];
6767 };
6768 /** Get all Extensions */
6769 ExtensionService.prototype.getAllExtensions = function () {
6770 return this._extensionList;
6771 };
6772 /**
6773 * Get an Extension by it's name
6774 * @param name
6775 */
6776 ExtensionService.prototype.getExtensionByName = function (name) {
6777 return this._extensionList.find(function (p) { return p.name === name; });
6778 };
6779 /**
6780 * Get the instance of the SlickGrid addon (control or plugin).
6781 * This is the raw addon coming directly from SlickGrid itself, not to confuse with Angular-Slickgrid extension
6782 * @param name
6783 */
6784 ExtensionService.prototype.getSlickgridAddonInstance = function (name) {
6785 var extension = this.getExtensionByName(name);
6786 if (extension && (extension.instance || extension.addon)) {
6787 return extension.instance;
6788 }
6789 return null;
6790 };
6791 /** Auto-resize all the column in the grid to fit the grid width */
6792 ExtensionService.prototype.autoResizeColumns = function () {
6793 this.sharedService.grid.autosizeColumns();
6794 };
6795 /** Bind/Create different Controls or Plugins after the Grid is created */
6796 ExtensionService.prototype.bindDifferentExtensions = function () {
6797 var _this = this;
6798 if (this.sharedService && this.sharedService.gridOptions) {
6799 // make sure all columns are translated before creating ColumnPicker/GridMenu Controls
6800 // this is to avoid having hidden columns not being translated on first load
6801 if (this.sharedService.gridOptions.enableTranslate) {
6802 this.translateItems(this.sharedService.allColumns, 'headerKey', 'name');
6803 }
6804 // Auto Tooltip Plugin
6805 if (this.sharedService.gridOptions.enableAutoTooltip) {
6806 if (this.autoTooltipExtension && this.autoTooltipExtension.register) {
6807 var instance = this.autoTooltipExtension.register();
6808 this._extensionList.push({ name: exports.ExtensionName.autoTooltip, class: this.autoTooltipExtension, addon: instance, instance: instance });
6809 }
6810 }
6811 // Cell External Copy Manager Plugin (Excel Like)
6812 if (this.sharedService.gridOptions.enableExcelCopyBuffer) {
6813 if (this.cellExternalCopyExtension && this.cellExternalCopyExtension.register) {
6814 var instance = this.cellExternalCopyExtension.register();
6815 this._extensionList.push({ name: exports.ExtensionName.cellExternalCopyManager, class: this.cellExternalCopyExtension, addon: instance, instance: instance });
6816 }
6817 }
6818 // Checkbox Selector Plugin
6819 if (this.sharedService.gridOptions.enableCheckboxSelector) {
6820 if (this.checkboxSelectorExtension && this.checkboxSelectorExtension.register) {
6821 var rowSelectionExtension = this.getExtensionByName(exports.ExtensionName.rowSelection);
6822 var instance = this.checkboxSelectorExtension.register(rowSelectionExtension);
6823 this._extensionList.push({ name: exports.ExtensionName.checkboxSelector, class: this.checkboxSelectorExtension, addon: instance, instance: instance });
6824 }
6825 }
6826 // Column Picker Control
6827 if (this.sharedService.gridOptions.enableColumnPicker) {
6828 if (this.columnPickerExtension && this.columnPickerExtension.register) {
6829 var instance = this.columnPickerExtension.register();
6830 this._extensionList.push({ name: exports.ExtensionName.columnPicker, class: this.columnPickerExtension, addon: instance, instance: instance });
6831 }
6832 }
6833 // Draggable Grouping Plugin
6834 if (this.sharedService.gridOptions.enableDraggableGrouping) {
6835 if (this.draggableGroupingExtension && this.draggableGroupingExtension.register) {
6836 var instance = this.draggableGroupingExtension.register();
6837 this._extensionList.push({ name: exports.ExtensionName.draggableGrouping, class: this.draggableGroupingExtension, addon: instance, instance: instance });
6838 }
6839 }
6840 // Grid Menu Control
6841 if (this.sharedService.gridOptions.enableGridMenu) {
6842 if (this.gridMenuExtension && this.gridMenuExtension.register) {
6843 var instance = this.gridMenuExtension.register();
6844 this._extensionList.push({ name: exports.ExtensionName.gridMenu, class: this.gridMenuExtension, addon: instance, instance: instance });
6845 }
6846 }
6847 // Grouping Plugin
6848 // register the group item metadata provider to add expand/collapse group handlers
6849 if (this.sharedService.gridOptions.enableDraggableGrouping || this.sharedService.gridOptions.enableGrouping) {
6850 if (this.groupItemMetaExtension && this.groupItemMetaExtension.register) {
6851 var instance = this.groupItemMetaExtension.register();
6852 this._extensionList.push({ name: exports.ExtensionName.groupItemMetaProvider, class: this.groupItemMetaExtension, addon: instance, instance: instance });
6853 }
6854 }
6855 // Header Button Plugin
6856 if (this.sharedService.gridOptions.enableHeaderButton) {
6857 if (this.headerButtonExtension && this.headerButtonExtension.register) {
6858 var instance = this.headerButtonExtension.register();
6859 this._extensionList.push({ name: exports.ExtensionName.headerButton, class: this.headerButtonExtension, addon: instance, instance: instance });
6860 }
6861 }
6862 // Header Menu Plugin
6863 if (this.sharedService.gridOptions.enableHeaderMenu) {
6864 if (this.headerMenuExtension && this.headerMenuExtension.register) {
6865 var instance = this.headerMenuExtension.register();
6866 this._extensionList.push({ name: exports.ExtensionName.headerMenu, class: this.headerMenuExtension, addon: instance, instance: instance });
6867 }
6868 }
6869 // Row Detail View Plugin
6870 if (this.sharedService.gridOptions.enableRowDetailView) {
6871 if (this.rowDetailViewExtension && this.rowDetailViewExtension.register) {
6872 var rowSelectionExtension = this.getExtensionByName(exports.ExtensionName.rowSelection);
6873 var instance = this.rowDetailViewExtension.register(rowSelectionExtension);
6874 this._extensionList.push({ name: exports.ExtensionName.rowDetailView, class: this.rowDetailViewExtension, addon: instance, instance: instance });
6875 }
6876 }
6877 // Row Move Manager Plugin
6878 if (this.sharedService.gridOptions.enableRowMoveManager) {
6879 if (this.rowMoveManagerExtension && this.rowMoveManagerExtension.register) {
6880 var instance = this.rowMoveManagerExtension.register();
6881 this._extensionList.push({ name: exports.ExtensionName.rowMoveManager, class: this.rowMoveManagerExtension, addon: instance, instance: instance });
6882 }
6883 }
6884 // Row Selection Plugin
6885 if (!this.sharedService.gridOptions.enableCheckboxSelector && this.sharedService.gridOptions.enableRowSelection) {
6886 if (this.rowSelectionExtension && this.rowSelectionExtension.register) {
6887 var instance = this.rowSelectionExtension.register();
6888 this._extensionList.push({ name: exports.ExtensionName.rowSelection, class: this.rowSelectionExtension, addon: instance, instance: instance });
6889 }
6890 }
6891 // manually register other plugins
6892 if (this.sharedService.gridOptions.registerPlugins !== undefined) {
6893 if (Array.isArray(this.sharedService.gridOptions.registerPlugins)) {
6894 this.sharedService.gridOptions.registerPlugins.forEach(function (plugin) {
6895 var instance = _this.sharedService.grid.registerPlugin(plugin);
6896 _this._extensionList.push({ name: exports.ExtensionName.noname, class: null, addon: instance, instance: instance });
6897 });
6898 }
6899 else {
6900 this.sharedService.grid.registerPlugin(this.sharedService.gridOptions.registerPlugins);
6901 var plugin = this.sharedService.gridOptions.registerPlugins;
6902 var instance = this.sharedService.grid.registerPlugin(plugin);
6903 this._extensionList.push({ name: exports.ExtensionName.noname, class: null, addon: instance, instance: instance });
6904 }
6905 }
6906 }
6907 };
6908 /**
6909 * Bind/Create certain plugins before the Grid creation, else they might behave oddly.
6910 * Mostly because the column definitions might change after the grid creation
6911 * @param columnDefinitions
6912 * @param options
6913 */
6914 ExtensionService.prototype.createExtensionsBeforeGridCreation = function (columnDefinitions, options) {
6915 if (options.enableCheckboxSelector) {
6916 this.checkboxSelectorExtension.create(columnDefinitions, options);
6917 }
6918 if (options.enableRowDetailView) {
6919 this.rowDetailViewExtension.create(columnDefinitions, options);
6920 }
6921 if (options.enableDraggableGrouping) {
6922 var plugin = this.draggableGroupingExtension.create(options);
6923 options.enableColumnReorder = plugin.getSetupColumnReorder;
6924 }
6925 };
6926 /** Hide a column from the grid */
6927 ExtensionService.prototype.hideColumn = function (column) {
6928 if (this.sharedService && this.sharedService.grid && this.sharedService.grid.getColumns && this.sharedService.grid.setColumns) {
6929 var columnIndex = this.sharedService.grid.getColumnIndex(column.id);
6930 this.sharedService.visibleColumns = this.removeColumnByIndex(this.sharedService.grid.getColumns(), columnIndex);
6931 this.sharedService.grid.setColumns(this.sharedService.visibleColumns);
6932 }
6933 };
6934 /** Refresh the dataset through the Backend Service */
6935 ExtensionService.prototype.refreshBackendDataset = function (gridOptions) {
6936 this.gridMenuExtension.refreshBackendDataset(gridOptions);
6937 };
6938 /**
6939 * Remove a column from the grid by it's index in the grid
6940 * @param columns input
6941 * @param index
6942 */
6943 ExtensionService.prototype.removeColumnByIndex = function (columns, index) {
6944 if (Array.isArray(columns)) {
6945 return columns.filter(function (el, i) { return index !== i; });
6946 }
6947 return columns;
6948 };
6949 /** Translate the Column Picker and it's last 2 checkboxes */
6950 ExtensionService.prototype.translateColumnPicker = function () {
6951 if (this.columnPickerExtension && this.columnPickerExtension.translateColumnPicker) {
6952 this.columnPickerExtension.translateColumnPicker();
6953 }
6954 };
6955 /**
6956 * Translate the Header Menu titles, we need to loop through all column definition to re-translate them
6957 */
6958 ExtensionService.prototype.translateGridMenu = function () {
6959 if (this.gridMenuExtension && this.gridMenuExtension.translateGridMenu) {
6960 this.gridMenuExtension.translateGridMenu();
6961 }
6962 };
6963 /**
6964 * Translate the Header Menu titles, we need to loop through all column definition to re-translate them
6965 */
6966 ExtensionService.prototype.translateHeaderMenu = function () {
6967 if (this.headerMenuExtension && this.headerMenuExtension.translateHeaderMenu) {
6968 this.headerMenuExtension.translateHeaderMenu();
6969 }
6970 };
6971 /**
6972 * Translate manually the header titles.
6973 * We could optionally pass a locale (that will change currently loaded locale), else it will use current locale
6974 * @param locale to use
6975 * @param new column definitions (optional)
6976 */
6977 ExtensionService.prototype.translateColumnHeaders = function (locale, newColumnDefinitions) {
6978 if (locale) {
6979 this.translate.use(locale);
6980 }
6981 var columnDefinitions = newColumnDefinitions;
6982 if (!columnDefinitions) {
6983 columnDefinitions = this.sharedService.columnDefinitions;
6984 }
6985 this.translateItems(columnDefinitions, 'headerKey', 'name');
6986 this.translateItems(this.sharedService.allColumns, 'headerKey', 'name');
6987 // re-render the column headers
6988 this.renderColumnHeaders(columnDefinitions);
6989 };
6990 /**
6991 * Render (or re-render) the column headers from column definitions.
6992 * calling setColumns() will trigger a grid re-render
6993 */
6994 ExtensionService.prototype.renderColumnHeaders = function (newColumnDefinitions) {
6995 var collection = newColumnDefinitions;
6996 if (!collection) {
6997 collection = this.sharedService.columnDefinitions;
6998 }
6999 if (Array.isArray(collection) && this.sharedService.grid && this.sharedService.grid.setColumns) {
7000 this.sharedService.grid.setColumns(collection);
7001 }
7002 };
7003 /** Translate an array of items from an input key and assign translated value to the output key */
7004 ExtensionService.prototype.translateItems = function (items, inputKey, outputKey) {
7005 var e_1, _a;
7006 if (Array.isArray(items)) {
7007 try {
7008 for (var items_1 = __values(items), items_1_1 = items_1.next(); !items_1_1.done; items_1_1 = items_1.next()) {
7009 var item = items_1_1.value;
7010 if (item[inputKey]) {
7011 item[outputKey] = this.translate.instant(item[inputKey]);
7012 }
7013 }
7014 }
7015 catch (e_1_1) { e_1 = { error: e_1_1 }; }
7016 finally {
7017 try {
7018 if (items_1_1 && !items_1_1.done && (_a = items_1.return)) _a.call(items_1);
7019 }
7020 finally { if (e_1) throw e_1.error; }
7021 }
7022 }
7023 };
7024 ExtensionService = __decorate([
7025 core.Injectable(),
7026 __metadata("design:paramtypes", [AutoTooltipExtension,
7027 CellExternalCopyManagerExtension,
7028 CheckboxSelectorExtension,
7029 ColumnPickerExtension,
7030 DraggableGroupingExtension,
7031 GridMenuExtension,
7032 GroupItemMetaProviderExtension,
7033 HeaderButtonExtension,
7034 HeaderMenuExtension,
7035 RowDetailViewExtension,
7036 RowMoveManagerExtension,
7037 RowSelectionExtension,
7038 SharedService,
7039 core$1.TranslateService])
7040 ], ExtensionService);
7041 return ExtensionService;
7042 }());
7043
7044 /**
7045 * This GraphqlQueryBuilder class is a lib that already exist
7046 * but was causing issues with TypeScript, RequireJS and other bundler/packagers
7047 * and so I rewrote it in pure TypeScript.
7048 *
7049 * The previous lib can be viewed here at this Github
7050 * https://github.com/codemeasandwich/graphql-query-builder
7051 */
7052 var GraphqlQueryBuilder = /** @class */ (function () {
7053 /* Constructor, query/mutator you wish to use, and an alias or filter arguments. */
7054 function GraphqlQueryBuilder(queryFnName, aliasOrFilter) {
7055 this.queryFnName = queryFnName;
7056 this.head = [];
7057 if (typeof aliasOrFilter === 'string') {
7058 this.alias = aliasOrFilter;
7059 }
7060 else if (typeof aliasOrFilter === 'object') {
7061 this.filter(aliasOrFilter);
7062 }
7063 else if (aliasOrFilter === undefined && arguments.length === 2) {
7064 throw new TypeError("You have passed undefined as Second argument to \"Query\"");
7065 }
7066 else if (aliasOrFilter !== undefined) {
7067 throw new TypeError("Second argument to \"Query\" should be an alias name(String) or filter arguments(Object). What was passed is: " + aliasOrFilter);
7068 }
7069 }
7070 /**
7071 * The parameters to run the query against.
7072 * @param filters An object mapping attribute to values
7073 */
7074 GraphqlQueryBuilder.prototype.filter = function (filters) {
7075 var e_1, _a;
7076 try {
7077 for (var _b = __values(Object.keys(filters)), _c = _b.next(); !_c.done; _c = _b.next()) {
7078 var prop = _c.value;
7079 if (typeof filters[prop] === 'function') {
7080 continue;
7081 }
7082 var val = this.getGraphQLValue(filters[prop]);
7083 if (val === '{}') {
7084 continue;
7085 }
7086 this.head.push(prop + ":" + val);
7087 }
7088 }
7089 catch (e_1_1) { e_1 = { error: e_1_1 }; }
7090 finally {
7091 try {
7092 if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
7093 }
7094 finally { if (e_1) throw e_1.error; }
7095 }
7096 return this;
7097 };
7098 /**
7099 * Outlines the properties you wish to be returned from the query.
7100 * @param properties representing each attribute you want Returned
7101 */
7102 GraphqlQueryBuilder.prototype.find = function () {
7103 var searches = [];
7104 for (var _i = 0; _i < arguments.length; _i++) {
7105 searches[_i] = arguments[_i];
7106 }
7107 if (!searches || !Array.isArray(searches) || searches.length === 0) {
7108 throw new TypeError("find value can not be >>falsy<<");
7109 }
7110 // if its a string.. it may have other values
7111 // else it sould be an Object or Array of maped values
7112 var searchKeys = (searches.length === 1 && Array.isArray(searches[0])) ? searches[0] : searches;
7113 this.body = this.parceFind(searchKeys);
7114 return this;
7115 };
7116 /**
7117 * set an alias for this result.
7118 * @param alias
7119 */
7120 GraphqlQueryBuilder.prototype.setAlias = function (alias) {
7121 this.alias = alias;
7122 };
7123 /**
7124 * Return to the formatted query string
7125 * @return
7126 */
7127 GraphqlQueryBuilder.prototype.toString = function () {
7128 if (this.body === undefined) {
7129 throw new ReferenceError("return properties are not defined. use the 'find' function to defined them");
7130 }
7131 return ((this.alias) ? (this.alias + ':') : '') + " " + this.queryFnName + " " + ((this.head.length > 0) ? '(' + this.head.join(',') + ')' : '') + " { " + this.body + " }";
7132 };
7133 // --
7134 // PRIVATE FUNCTIONS
7135 // -----------------
7136 GraphqlQueryBuilder.prototype.parceFind = function (_levelA) {
7137 var propsA = _levelA.map(function (currentValue, index) {
7138 var itemX = _levelA[index];
7139 if (itemX instanceof GraphqlQueryBuilder) {
7140 return itemX.toString();
7141 }
7142 else if (!Array.isArray(itemX) && typeof itemX === 'object') {
7143 var propsAA = Object.keys(itemX);
7144 if (1 !== propsAA.length) {
7145 throw new RangeError("Alias objects should only have one value. was passed: " + JSON.stringify(itemX));
7146 }
7147 var propS = propsAA[0];
7148 var item = itemX[propS];
7149 if (Array.isArray(item)) {
7150 return new GraphqlQueryBuilder(propS).find(item);
7151 }
7152 return propS + " : " + item + " ";
7153 }
7154 else if (typeof itemX === 'string') {
7155 return itemX;
7156 }
7157 else {
7158 throw new RangeError("cannot handle Find value of " + itemX);
7159 }
7160 });
7161 return propsA.join(',');
7162 };
7163 GraphqlQueryBuilder.prototype.getGraphQLValue = function (value) {
7164 var _this = this;
7165 if (typeof value === 'string') {
7166 value = JSON.stringify(value);
7167 }
7168 else if (Array.isArray(value)) {
7169 value = value.map(function (item) {
7170 return _this.getGraphQLValue(item);
7171 }).join();
7172 value = "[" + value + "]";
7173 }
7174 else if (value instanceof Date) {
7175 value = JSON.stringify(value);
7176 }
7177 else if (value !== null && typeof value === 'object') {
7178 value = this.objectToString(value);
7179 }
7180 return value;
7181 };
7182 GraphqlQueryBuilder.prototype.objectToString = function (obj) {
7183 var e_2, _a;
7184 var sourceA = [];
7185 try {
7186 for (var _b = __values(Object.keys(obj)), _c = _b.next(); !_c.done; _c = _b.next()) {
7187 var prop = _c.value;
7188 if (typeof obj[prop] === 'function') {
7189 continue;
7190 }
7191 sourceA.push(prop + ":" + this.getGraphQLValue(obj[prop]));
7192 }
7193 }
7194 catch (e_2_1) { e_2 = { error: e_2_1 }; }
7195 finally {
7196 try {
7197 if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
7198 }
7199 finally { if (e_2) throw e_2.error; }
7200 }
7201 return "{" + sourceA.join() + "}";
7202 };
7203 return GraphqlQueryBuilder;
7204 }());
7205
7206 var DEFAULT_ITEMS_PER_PAGE = 25;
7207 var DEFAULT_PAGE_SIZE = 20;
7208 var GraphqlService = /** @class */ (function () {
7209 function GraphqlService() {
7210 this._currentFilters = [];
7211 this._currentSorters = [];
7212 this.defaultPaginationOptions = {
7213 first: DEFAULT_ITEMS_PER_PAGE,
7214 offset: 0
7215 };
7216 }
7217 Object.defineProperty(GraphqlService.prototype, "columnDefinitions", {
7218 /** Getter for the Column Definitions */
7219 get: function () {
7220 return this._columnDefinitions;
7221 },
7222 enumerable: true,
7223 configurable: true
7224 });
7225 Object.defineProperty(GraphqlService.prototype, "_gridOptions", {
7226 /** Getter for the Grid Options pulled through the Grid Object */
7227 get: function () {
7228 return (this._grid && this._grid.getOptions) ? this._grid.getOptions() : {};
7229 },
7230 enumerable: true,
7231 configurable: true
7232 });
7233 /** Initialization of the service, which acts as a constructor */
7234 GraphqlService.prototype.init = function (serviceOptions, pagination, grid) {
7235 this._grid = grid;
7236 this.options = serviceOptions || {};
7237 this.pagination = pagination;
7238 if (grid && grid.getColumns) {
7239 this._columnDefinitions = (serviceOptions && serviceOptions.columnDefinitions) || grid.getColumns();
7240 }
7241 };
7242 /**
7243 * Build the GraphQL query, since the service include/exclude cursor, the output query will be different.
7244 * @param serviceOptions GraphqlServiceOption
7245 */
7246 GraphqlService.prototype.buildQuery = function () {
7247 var e_1, _a, e_2, _b;
7248 if (!this.options || !this.options.datasetName || (!this._columnDefinitions && !Array.isArray(this.options.columnDefinitions))) {
7249 throw new Error('GraphQL Service requires "datasetName" & "columnDefinitions" properties for it to work');
7250 }
7251 // get the column definitions and exclude some if they were tagged as excluded
7252 var columnDefinitions = this._columnDefinitions || this.options.columnDefinitions;
7253 columnDefinitions = columnDefinitions.filter(function (column) { return !column.excludeFromQuery; });
7254 var queryQb = new GraphqlQueryBuilder('query');
7255 var datasetQb = new GraphqlQueryBuilder(this.options.datasetName);
7256 var dataQb = (this.options.isWithCursor) ? new GraphqlQueryBuilder('edges') : new GraphqlQueryBuilder('nodes');
7257 // get all the columnds Ids for the filters to work
7258 var columnIds = [];
7259 if (columnDefinitions && Array.isArray(columnDefinitions)) {
7260 try {
7261 for (var columnDefinitions_1 = __values(columnDefinitions), columnDefinitions_1_1 = columnDefinitions_1.next(); !columnDefinitions_1_1.done; columnDefinitions_1_1 = columnDefinitions_1.next()) {
7262 var column = columnDefinitions_1_1.value;
7263 columnIds.push(column.field);
7264 // if extra "fields" are passed, also push them to columnIds
7265 if (column.fields) {
7266 columnIds.push.apply(columnIds, __spread(column.fields));
7267 }
7268 }
7269 }
7270 catch (e_1_1) { e_1 = { error: e_1_1 }; }
7271 finally {
7272 try {
7273 if (columnDefinitions_1_1 && !columnDefinitions_1_1.done && (_a = columnDefinitions_1.return)) _a.call(columnDefinitions_1);
7274 }
7275 finally { if (e_1) throw e_1.error; }
7276 }
7277 }
7278 // Slickgrid also requires the "id" field to be part of DataView
7279 // add it to the GraphQL query if it wasn't already part of the list
7280 if (columnIds.indexOf('id') === -1) {
7281 columnIds.unshift('id');
7282 }
7283 var filters = this.buildFilterQuery(columnIds);
7284 if (this.options.isWithCursor) {
7285 // ...pageInfo { hasNextPage, endCursor }, edges { cursor, node { _filters_ } }
7286 var pageInfoQb = new GraphqlQueryBuilder('pageInfo');
7287 pageInfoQb.find('hasNextPage', 'endCursor');
7288 dataQb.find(['cursor', { node: filters }]);
7289 datasetQb.find(['totalCount', pageInfoQb, dataQb]);
7290 }
7291 else {
7292 // ...nodes { _filters_ }
7293 dataQb.find(filters);
7294 datasetQb.find(['totalCount', dataQb]);
7295 }
7296 // add dataset filters, could be Pagination and SortingFilters and/or FieldFilters
7297 var datasetFilters = {};
7298 // only add pagination if it's enabled in the grid options
7299 if (this._gridOptions.enablePagination !== false) {
7300 datasetFilters = __assign({}, this.options.paginationOptions, { first: ((this.options.paginationOptions && this.options.paginationOptions.first) ? this.options.paginationOptions.first : ((this.pagination && this.pagination.pageSize) ? this.pagination.pageSize : null)) || this.defaultPaginationOptions.first });
7301 if (!this.options.isWithCursor) {
7302 datasetFilters.offset = ((this.options.paginationOptions && this.options.paginationOptions.hasOwnProperty('offset')) ? +this.options.paginationOptions['offset'] : 0);
7303 }
7304 }
7305 if (this.options.sortingOptions && Array.isArray(this.options.sortingOptions) && this.options.sortingOptions.length > 0) {
7306 // orderBy: [{ field:x, direction: 'ASC' }]
7307 datasetFilters.orderBy = this.options.sortingOptions;
7308 }
7309 if (this.options.filteringOptions && Array.isArray(this.options.filteringOptions) && this.options.filteringOptions.length > 0) {
7310 // filterBy: [{ field: date, operator: '>', value: '2000-10-10' }]
7311 datasetFilters.filterBy = this.options.filteringOptions;
7312 }
7313 if (this.options.addLocaleIntoQuery) {
7314 // first: 20, ... locale: "en-CA"
7315 datasetFilters.locale = this._gridOptions && this._gridOptions.i18n && this._gridOptions.i18n.currentLang || 'en';
7316 }
7317 if (this.options.extraQueryArguments) {
7318 try {
7319 // first: 20, ... userId: 123
7320 for (var _c = __values(this.options.extraQueryArguments), _d = _c.next(); !_d.done; _d = _c.next()) {
7321 var queryArgument = _d.value;
7322 datasetFilters[queryArgument.field] = queryArgument.value;
7323 }
7324 }
7325 catch (e_2_1) { e_2 = { error: e_2_1 }; }
7326 finally {
7327 try {
7328 if (_d && !_d.done && (_b = _c.return)) _b.call(_c);
7329 }
7330 finally { if (e_2) throw e_2.error; }
7331 }
7332 }
7333 // query { users(first: 20, orderBy: [], filterBy: [])}
7334 datasetQb.filter(datasetFilters);
7335 queryQb.find(datasetQb);
7336 var enumSearchProperties = ['direction:', 'field:', 'operator:'];
7337 return this.trimDoubleQuotesOnEnumField(queryQb.toString(), enumSearchProperties, this.options.keepArgumentFieldDoubleQuotes || false);
7338 };
7339 /**
7340 * From an input array of strings, we want to build a GraphQL query string.
7341 * The process has to take the dot notation and parse it into a valid GraphQL query
7342 * Following this SO answer https://stackoverflow.com/a/47705476/1212166
7343 *
7344 * INPUT
7345 * ['firstName', 'lastName', 'billing.address.street', 'billing.address.zip']
7346 * OUTPUT
7347 * firstName, lastName, billing{address{street, zip}}
7348 * @param inputArray
7349 */
7350 GraphqlService.prototype.buildFilterQuery = function (inputArray) {
7351 var set = function (o, a) {
7352 if (o === void 0) { o = {}; }
7353 var k = a.shift();
7354 o[k] = a.length ? set(o[k], a) : null;
7355 return o;
7356 };
7357 var output = inputArray.reduce(function (o, a) { return set(o, a.split('.')); }, {});
7358 return JSON.stringify(output)
7359 .replace(/\"|\:|null/g, '')
7360 .replace(/^\{/, '')
7361 .replace(/\}$/, '');
7362 };
7363 GraphqlService.prototype.clearFilters = function () {
7364 this._currentFilters = [];
7365 this.updateOptions({ filteringOptions: [] });
7366 };
7367 GraphqlService.prototype.clearSorters = function () {
7368 this._currentSorters = [];
7369 this.updateOptions({ sortingOptions: [] });
7370 };
7371 /**
7372 * Get an initialization of Pagination options
7373 * @return Pagination Options
7374 */
7375 GraphqlService.prototype.getInitPaginationOptions = function () {
7376 var paginationFirst = this.pagination ? this.pagination.pageSize : DEFAULT_ITEMS_PER_PAGE;
7377 return (this.options && this.options.isWithCursor) ? { first: paginationFirst } : { first: paginationFirst, offset: 0 };
7378 };
7379 /** Get the GraphQL dataset name */
7380 GraphqlService.prototype.getDatasetName = function () {
7381 return this.options.datasetName || '';
7382 };
7383 /** Get the Filters that are currently used by the grid */
7384 GraphqlService.prototype.getCurrentFilters = function () {
7385 return this._currentFilters;
7386 };
7387 /** Get the Pagination that is currently used by the grid */
7388 GraphqlService.prototype.getCurrentPagination = function () {
7389 return this._currentPagination;
7390 };
7391 /** Get the Sorters that are currently used by the grid */
7392 GraphqlService.prototype.getCurrentSorters = function () {
7393 return this._currentSorters;
7394 };
7395 /*
7396 * Reset the pagination options
7397 */
7398 GraphqlService.prototype.resetPaginationOptions = function () {
7399 var paginationOptions;
7400 if (this.options && this.options.isWithCursor) {
7401 // first, last, after, before
7402 paginationOptions = {
7403 after: '',
7404 before: undefined,
7405 last: undefined
7406 };
7407 }
7408 else {
7409 // first, last, offset
7410 paginationOptions = (this.options.paginationOptions || this.getInitPaginationOptions());
7411 paginationOptions.offset = 0;
7412 }
7413 // save current pagination as Page 1 and page size as "first" set size
7414 this._currentPagination = {
7415 pageNumber: 1,
7416 pageSize: paginationOptions.first
7417 };
7418 this.updateOptions({ paginationOptions: paginationOptions });
7419 };
7420 GraphqlService.prototype.updateOptions = function (serviceOptions) {
7421 this.options = __assign({}, this.options, serviceOptions);
7422 };
7423 /*
7424 * FILTERING
7425 */
7426 GraphqlService.prototype.processOnFilterChanged = function (event, args) {
7427 var gridOptions = this._gridOptions;
7428 var backendApi = gridOptions.backendServiceApi;
7429 if (backendApi === undefined) {
7430 throw new Error('Something went wrong in the GraphqlService, "backendServiceApi" is not initialized');
7431 }
7432 // keep current filters & always save it as an array (columnFilters can be an object when it is dealt by SlickGrid Filter)
7433 this._currentFilters = this.castFilterToColumnFilters(args.columnFilters);
7434 if (!args || !args.grid) {
7435 throw new Error('Something went wrong when trying create the GraphQL Backend Service, it seems that "args" is not populated correctly');
7436 }
7437 // loop through all columns to inspect filters & set the query
7438 this.updateFilters(args.columnFilters, false);
7439 this.resetPaginationOptions();
7440 return this.buildQuery();
7441 };
7442 /*
7443 * PAGINATION
7444 * With cursor, the query can have 4 arguments (first, after, last, before), for example:
7445 * users (first:20, after:"YXJyYXljb25uZWN0aW9uOjM=") {
7446 * totalCount
7447 * pageInfo {
7448 * hasNextPage
7449 * endCursor
7450 * }
7451 * edges {
7452 * cursor
7453 * node {
7454 * name
7455 * gender
7456 * }
7457 * }
7458 * }
7459 * Without cursor, the query can have 3 arguments (first, last, offset), for example:
7460 * users (first:20, offset: 10) {
7461 * totalCount
7462 * nodes {
7463 * name
7464 * gender
7465 * }
7466 * }
7467 */
7468 GraphqlService.prototype.processOnPaginationChanged = function (event, args) {
7469 var pageSize = +(args.pageSize || ((this.pagination) ? this.pagination.pageSize : DEFAULT_PAGE_SIZE));
7470 this.updatePagination(args.newPage, pageSize);
7471 // build the GraphQL query which we will use in the WebAPI callback
7472 return this.buildQuery();
7473 };
7474 /*
7475 * SORTING
7476 * we will use sorting as per a Facebook suggestion on a Github issue (with some small changes)
7477 * https://github.com/graphql/graphql-relay-js/issues/20#issuecomment-220494222
7478 *
7479 * users (first: 20, offset: 10, orderBy: [{field: lastName, direction: ASC}, {field: firstName, direction: DESC}]) {
7480 * totalCount
7481 * nodes {
7482 * name
7483 * gender
7484 * }
7485 * }
7486 */
7487 // @deprecated note, we should remove "SortChangedArgs" and only use: ColumnSort | MultiColumnSort
7488 GraphqlService.prototype.processOnSortChanged = function (event, args) {
7489 var sortColumns = (args.multiColumnSort) ? args.sortCols : new Array({ sortCol: args.sortCol, sortAsc: args.sortAsc });
7490 // loop through all columns to inspect sorters & set the query
7491 this.updateSorters(sortColumns);
7492 // build the GraphQL query which we will use in the WebAPI callback
7493 return this.buildQuery();
7494 };
7495 /**
7496 * loop through all columns to inspect filters & update backend service filteringOptions
7497 * @param columnFilters
7498 */
7499 GraphqlService.prototype.updateFilters = function (columnFilters, isUpdatedByPreset) {
7500 var searchByArray = [];
7501 var searchValue;
7502 // on filter preset load, we need to keep current filters
7503 if (isUpdatedByPreset) {
7504 this._currentFilters = this.castFilterToColumnFilters(columnFilters);
7505 }
7506 var _loop_1 = function (columnId) {
7507 if (columnFilters.hasOwnProperty(columnId)) {
7508 var columnFilter_1 = columnFilters[columnId];
7509 // if user defined some "presets", then we need to find the filters from the column definitions instead
7510 var columnDef = void 0;
7511 if (isUpdatedByPreset && Array.isArray(this_1._columnDefinitions)) {
7512 columnDef = this_1._columnDefinitions.find(function (column) { return column.id === columnFilter_1.columnId; });
7513 }
7514 else {
7515 columnDef = columnFilter_1.columnDef;
7516 }
7517 if (!columnDef) {
7518 throw new Error('[GraphQL Service]: Something went wrong in trying to get the column definition of the specified filter (or preset filters). Did you make a typo on the filter columnId?');
7519 }
7520 var fieldName = columnDef.queryFieldFilter || columnDef.queryField || columnDef.field || columnDef.name || '';
7521 var searchTerms = columnFilter_1 && columnFilter_1.searchTerms || [];
7522 var fieldSearchValue = (Array.isArray(searchTerms) && searchTerms.length === 1) ? searchTerms[0] : '';
7523 if (typeof fieldSearchValue === 'undefined') {
7524 fieldSearchValue = '';
7525 }
7526 if (!fieldName) {
7527 throw new Error("GraphQL filter could not find the field name to query the search, your column definition must include a valid \"field\" or \"name\" (optionally you can also use the \"queryfield\" or \"queryFieldFilter\").");
7528 }
7529 fieldSearchValue = '' + fieldSearchValue; // make sure it's a string
7530 var matches = fieldSearchValue.match(/^([<>!=\*]{0,2})(.*[^<>!=\*])([\*]?)$/); // group 1: Operator, 2: searchValue, 3: last char is '*' (meaning starts with, ex.: abc*)
7531 var operator = columnFilter_1.operator || ((matches) ? matches[1] : '');
7532 searchValue = (!!matches) ? matches[2] : '';
7533 var lastValueChar = (!!matches) ? matches[3] : (operator === '*z' ? '*' : '');
7534 // no need to query if search value is empty
7535 if (fieldName && searchValue === '' && searchTerms.length === 0) {
7536 return "continue";
7537 }
7538 // when having more than 1 search term (we need to create a CSV string for GraphQL "IN" or "NOT IN" filter search)
7539 if (searchTerms && searchTerms.length > 1) {
7540 searchValue = searchTerms.join(',');
7541 }
7542 else if (typeof searchValue === 'string') {
7543 // escaping the search value
7544 searchValue = searchValue.replace("'", "''"); // escape single quotes by doubling them
7545 if (operator === '*' || operator === 'a*' || operator === '*z' || lastValueChar === '*') {
7546 operator = (operator === '*' || operator === '*z') ? 'endsWith' : 'startsWith';
7547 }
7548 }
7549 // if we didn't find an Operator but we have a Column Operator inside the Filter (DOM Element), we should use its default Operator
7550 // multipleSelect is "IN", while singleSelect is "EQ", else don't map any operator
7551 if (!operator && columnDef.filter) {
7552 operator = columnDef.filter.operator;
7553 }
7554 // if we still don't have an operator find the proper Operator to use by it's field type
7555 if (!operator) {
7556 operator = mapOperatorByFieldType(columnDef.type || exports.FieldType.string);
7557 }
7558 searchByArray.push({
7559 field: fieldName,
7560 operator: mapOperatorType(operator),
7561 value: searchValue
7562 });
7563 }
7564 };
7565 var this_1 = this;
7566 for (var columnId in columnFilters) {
7567 _loop_1(columnId);
7568 }
7569 // update the service options with filters for the buildQuery() to work later
7570 this.updateOptions({ filteringOptions: searchByArray });
7571 };
7572 /**
7573 * Update the pagination component with it's new page number and size
7574 * @param newPage
7575 * @param pageSize
7576 */
7577 GraphqlService.prototype.updatePagination = function (newPage, pageSize) {
7578 this._currentPagination = {
7579 pageNumber: newPage,
7580 pageSize: pageSize
7581 };
7582 var paginationOptions;
7583 if (this.options.isWithCursor) {
7584 paginationOptions = {
7585 first: pageSize
7586 };
7587 }
7588 else {
7589 paginationOptions = {
7590 first: pageSize,
7591 offset: (newPage - 1) * pageSize
7592 };
7593 }
7594 this.updateOptions({ paginationOptions: paginationOptions });
7595 };
7596 /**
7597 * loop through all columns to inspect sorters & update backend service sortingOptions
7598 * @param columnFilters
7599 */
7600 GraphqlService.prototype.updateSorters = function (sortColumns, presetSorters) {
7601 var _this = this;
7602 var e_3, _a;
7603 var currentSorters = [];
7604 var graphqlSorters = [];
7605 if (!sortColumns && presetSorters) {
7606 // make the presets the current sorters, also make sure that all direction are in uppercase for GraphQL
7607 currentSorters = presetSorters;
7608 currentSorters.forEach(function (sorter) { return sorter.direction = sorter.direction.toUpperCase(); });
7609 // display the correct sorting icons on the UI, for that it requires (columnId, sortAsc) properties
7610 var tmpSorterArray = currentSorters.map(function (sorter) {
7611 var columnDef = _this._columnDefinitions.find(function (column) { return column.id === sorter.columnId; });
7612 graphqlSorters.push({
7613 field: columnDef ? ((columnDef.queryFieldSorter || columnDef.queryField || columnDef.field) + '') : (sorter.columnId + ''),
7614 direction: sorter.direction
7615 });
7616 // return only the column(s) found in the Column Definitions ELSE null
7617 if (columnDef) {
7618 return {
7619 columnId: sorter.columnId,
7620 sortAsc: sorter.direction.toUpperCase() === exports.SortDirection.ASC
7621 };
7622 }
7623 return null;
7624 });
7625 // set the sort icons, but also make sure to filter out null values (that happens when columnDef is not found)
7626 if (Array.isArray(tmpSorterArray)) {
7627 this._grid.setSortColumns(tmpSorterArray.filter(function (sorter) { return sorter; }));
7628 }
7629 }
7630 else if (sortColumns && !presetSorters) {
7631 // build the orderBy array, it could be multisort, example
7632 // orderBy:[{field: lastName, direction: ASC}, {field: firstName, direction: DESC}]
7633 if (Array.isArray(sortColumns) && sortColumns.length > 0) {
7634 try {
7635 for (var sortColumns_1 = __values(sortColumns), sortColumns_1_1 = sortColumns_1.next(); !sortColumns_1_1.done; sortColumns_1_1 = sortColumns_1.next()) {
7636 var column = sortColumns_1_1.value;
7637 if (column && column.sortCol) {
7638 currentSorters.push({
7639 columnId: column.sortCol.id + '',
7640 direction: column.sortAsc ? exports.SortDirection.ASC : exports.SortDirection.DESC
7641 });
7642 var fieldName = (column.sortCol.queryFieldSorter || column.sortCol.queryField || column.sortCol.field || '') + '';
7643 if (fieldName) {
7644 graphqlSorters.push({
7645 field: fieldName,
7646 direction: column.sortAsc ? exports.SortDirection.ASC : exports.SortDirection.DESC
7647 });
7648 }
7649 }
7650 }
7651 }
7652 catch (e_3_1) { e_3 = { error: e_3_1 }; }
7653 finally {
7654 try {
7655 if (sortColumns_1_1 && !sortColumns_1_1.done && (_a = sortColumns_1.return)) _a.call(sortColumns_1);
7656 }
7657 finally { if (e_3) throw e_3.error; }
7658 }
7659 }
7660 }
7661 // keep current Sorters and update the service options with the new sorting
7662 this._currentSorters = currentSorters;
7663 this.updateOptions({ sortingOptions: graphqlSorters });
7664 };
7665 /**
7666 * A function which takes an input string and removes double quotes only
7667 * on certain fields are identified as GraphQL enums (except fields with dot notation)
7668 * For example let say we identified ("direction:", "sort") as word which are GraphQL enum fields
7669 * then the result will be:
7670 * FROM
7671 * query { users (orderBy:[{field:"firstName", direction:"ASC"} }]) }
7672 * TO
7673 * query { users (orderBy:[{field: firstName, direction: ASC}})}
7674 *
7675 * EXCEPTIONS (fields with dot notation "." which are inside a "field:")
7676 * these fields will keep double quotes while everything else will be stripped of double quotes
7677 * query { users (orderBy:[{field:"billing.street.name", direction: "ASC"} }
7678 * TO
7679 * query { users (orderBy:[{field:"billing.street.name", direction: ASC}}
7680 * @param inputStr input string
7681 * @param enumSearchWords array of enum words to filter
7682 * @returns outputStr output string
7683 */
7684 GraphqlService.prototype.trimDoubleQuotesOnEnumField = function (inputStr, enumSearchWords, keepArgumentFieldDoubleQuotes) {
7685 var patternWordInQuotes = "s?((field:s*)?\".*?\")";
7686 var patternRegex = enumSearchWords.join(patternWordInQuotes + '|');
7687 patternRegex += patternWordInQuotes; // the last one should also have the pattern but without the pipe "|"
7688 // example with (field: & direction:): /field:s?(".*?")|direction:s?(".*?")/
7689 var reg = new RegExp(patternRegex, 'g');
7690 return inputStr.replace(reg, function (group1, group2, group3) {
7691 // remove double quotes except when the string starts with a "field:"
7692 var removeDoubleQuotes = true;
7693 if (group1.startsWith('field:') && keepArgumentFieldDoubleQuotes) {
7694 removeDoubleQuotes = false;
7695 }
7696 var rep = removeDoubleQuotes ? group1.replace(/"/g, '') : group1;
7697 return rep;
7698 });
7699 };
7700 //
7701 // private functions
7702 // -------------------
7703 /**
7704 * Cast provided filters (could be in multiple formats) into an array of ColumnFilter
7705 * @param columnFilters
7706 */
7707 GraphqlService.prototype.castFilterToColumnFilters = function (columnFilters) {
7708 // keep current filters & always save it as an array (columnFilters can be an object when it is dealt by SlickGrid Filter)
7709 var filtersArray = (typeof columnFilters === 'object') ? Object.keys(columnFilters).map(function (key) { return columnFilters[key]; }) : columnFilters;
7710 if (!Array.isArray(filtersArray)) {
7711 return [];
7712 }
7713 return filtersArray.map(function (filter) {
7714 var tmpFilter = { columnId: filter.columnId || '' };
7715 if (filter.operator) {
7716 tmpFilter.operator = filter.operator;
7717 }
7718 if (Array.isArray(filter.searchTerms)) {
7719 tmpFilter.searchTerms = filter.searchTerms;
7720 }
7721 return tmpFilter;
7722 });
7723 };
7724 return GraphqlService;
7725 }());
7726
7727 var OdataQueryBuilderService = /** @class */ (function () {
7728 function OdataQueryBuilderService() {
7729 this._odataOptions = {
7730 filterQueue: [],
7731 orderBy: ''
7732 };
7733 this._defaultSortBy = '';
7734 this._columnFilters = {};
7735 }
7736 /*
7737 * Build the OData query string from all the options provided
7738 * @return string OData query
7739 */
7740 OdataQueryBuilderService.prototype.buildQuery = function () {
7741 if (!this._odataOptions) {
7742 throw new Error('Odata Service requires certain options like "top" for it to work');
7743 }
7744 this._odataOptions.filterQueue = [];
7745 var queryTmpArray = [];
7746 if (this._odataOptions.top) {
7747 queryTmpArray.push("$top=" + this._odataOptions.top);
7748 }
7749 if (this._odataOptions.skip) {
7750 queryTmpArray.push("$skip=" + this._odataOptions.skip);
7751 }
7752 if (this._odataOptions.orderBy) {
7753 var argument = '';
7754 if (Array.isArray(this._odataOptions.orderBy)) {
7755 argument = this._odataOptions.orderBy.join(','); // csv, that will form a query, for example: $orderby=RoleName asc, Id desc
7756 }
7757 else {
7758 argument = this._odataOptions.orderBy;
7759 }
7760 queryTmpArray.push("$orderby=" + argument);
7761 }
7762 if (this._odataOptions.filterBy || this._odataOptions.filter) {
7763 var filterBy = this._odataOptions.filter || this._odataOptions.filterBy;
7764 if (filterBy) {
7765 this._filterCount = 1;
7766 this._odataOptions.filterQueue = [];
7767 var filterStr = filterBy;
7768 if (Array.isArray(filterBy)) {
7769 this._filterCount = filterBy.length;
7770 filterStr = filterBy.join(" " + (this._odataOptions.filterBySeparator || 'and') + " ");
7771 }
7772 if (typeof filterStr === 'string') {
7773 if (!(filterStr[0] === '(' && filterStr.slice(-1) === ')')) {
7774 this.addToFilterQueueWhenNotExists("(" + filterStr + ")");
7775 }
7776 else {
7777 this.addToFilterQueueWhenNotExists(filterStr);
7778 }
7779 }
7780 }
7781 }
7782 if (this._odataOptions.filterQueue.length > 0) {
7783 var query = this._odataOptions.filterQueue.join(" " + (this._odataOptions.filterBySeparator || 'and') + " ");
7784 this._odataOptions.filter = query; // overwrite with
7785 queryTmpArray.push("$filter=" + query);
7786 }
7787 // join all the odata functions by a '&'
7788 return queryTmpArray.join('&');
7789 };
7790 OdataQueryBuilderService.prototype.getFilterCount = function () {
7791 return this._filterCount;
7792 };
7793 Object.defineProperty(OdataQueryBuilderService.prototype, "columnFilters", {
7794 get: function () {
7795 return this._columnFilters;
7796 },
7797 enumerable: true,
7798 configurable: true
7799 });
7800 Object.defineProperty(OdataQueryBuilderService.prototype, "options", {
7801 get: function () {
7802 return this._odataOptions;
7803 },
7804 set: function (options) {
7805 this._odataOptions = options;
7806 },
7807 enumerable: true,
7808 configurable: true
7809 });
7810 OdataQueryBuilderService.prototype.removeColumnFilter = function (fieldName) {
7811 if (this._columnFilters && this._columnFilters.hasOwnProperty(fieldName)) {
7812 delete this._columnFilters[fieldName];
7813 }
7814 };
7815 OdataQueryBuilderService.prototype.saveColumnFilter = function (fieldName, value, searchTerms) {
7816 this._columnFilters[fieldName] = {
7817 search: searchTerms,
7818 value: value
7819 };
7820 };
7821 /**
7822 * Change any OData options that will be used to build the query
7823 * @param object options
7824 */
7825 OdataQueryBuilderService.prototype.updateOptions = function (options) {
7826 var e_1, _a;
7827 try {
7828 for (var _b = __values(Object.keys(options)), _c = _b.next(); !_c.done; _c = _b.next()) {
7829 var property = _c.value;
7830 if (options.hasOwnProperty(property)) {
7831 this._odataOptions[property] = options[property]; // replace of the property
7832 }
7833 // we need to keep the defaultSortBy for references whenever the user removes his Sorting
7834 // then we would revert to the defaultSortBy and the only way is to keep a hard copy here
7835 if (property === 'orderBy' || property === 'sortBy') {
7836 var sortBy = options[property];
7837 // make sure first char of each orderBy field is capitalize
7838 if (this._odataOptions.caseType === exports.CaseType.pascalCase) {
7839 if (Array.isArray(sortBy)) {
7840 sortBy.forEach(function (field, index, inputArray) {
7841 inputArray[index] = titleCase(field);
7842 });
7843 }
7844 else {
7845 sortBy = titleCase(options[property]);
7846 }
7847 }
7848 this._odataOptions.orderBy = sortBy;
7849 this._defaultSortBy = sortBy;
7850 }
7851 }
7852 }
7853 catch (e_1_1) { e_1 = { error: e_1_1 }; }
7854 finally {
7855 try {
7856 if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
7857 }
7858 finally { if (e_1) throw e_1.error; }
7859 }
7860 };
7861 //
7862 // private functions
7863 // -------------------
7864 OdataQueryBuilderService.prototype.addToFilterQueueWhenNotExists = function (filterStr) {
7865 if (this._odataOptions.filterQueue && this._odataOptions.filterQueue.indexOf(filterStr) === -1) {
7866 this._odataOptions.filterQueue.push(filterStr);
7867 }
7868 };
7869 return OdataQueryBuilderService;
7870 }());
7871
7872 var DEFAULT_ITEMS_PER_PAGE$1 = 25;
7873 var DEFAULT_PAGE_SIZE$1 = 20;
7874 var GridOdataService = /** @class */ (function () {
7875 function GridOdataService() {
7876 this._currentFilters = [];
7877 this._currentSorters = [];
7878 this.defaultOptions = {
7879 top: DEFAULT_ITEMS_PER_PAGE$1,
7880 orderBy: '',
7881 caseType: exports.CaseType.pascalCase
7882 };
7883 this._odataService = new OdataQueryBuilderService();
7884 }
7885 Object.defineProperty(GridOdataService.prototype, "columnDefinitions", {
7886 /** Getter for the Column Definitions */
7887 get: function () {
7888 return this._columnDefinitions;
7889 },
7890 enumerable: true,
7891 configurable: true
7892 });
7893 Object.defineProperty(GridOdataService.prototype, "odataService", {
7894 /** Getter for the Odata Service */
7895 get: function () {
7896 return this._odataService;
7897 },
7898 enumerable: true,
7899 configurable: true
7900 });
7901 Object.defineProperty(GridOdataService.prototype, "_gridOptions", {
7902 /** Getter for the Grid Options pulled through the Grid Object */
7903 get: function () {
7904 return (this._grid && this._grid.getOptions) ? this._grid.getOptions() : {};
7905 },
7906 enumerable: true,
7907 configurable: true
7908 });
7909 GridOdataService.prototype.init = function (serviceOptions, pagination, grid) {
7910 this._grid = grid;
7911 var mergedOptions = __assign({}, this.defaultOptions, serviceOptions);
7912 if (pagination && pagination.pageSize) {
7913 mergedOptions.top = pagination.pageSize;
7914 }
7915 this._odataService.options = __assign({}, mergedOptions, { top: mergedOptions.top || this.defaultOptions.top });
7916 this.options = this._odataService.options;
7917 this.pagination = pagination;
7918 // save current pagination as Page 1 and page size as "top"
7919 this._currentPagination = {
7920 pageNumber: 1,
7921 pageSize: this._odataService.options.top || this.defaultOptions.top || DEFAULT_PAGE_SIZE$1
7922 };
7923 if (grid && grid.getColumns) {
7924 this._columnDefinitions = serviceOptions && serviceOptions.columnDefinitions || grid.getColumns();
7925 this._columnDefinitions = this._columnDefinitions.filter(function (column) { return !column.excludeFromQuery; });
7926 }
7927 };
7928 GridOdataService.prototype.buildQuery = function () {
7929 return this._odataService.buildQuery();
7930 };
7931 GridOdataService.prototype.clearFilters = function () {
7932 this._currentFilters = [];
7933 this.updateFilters([]);
7934 };
7935 GridOdataService.prototype.clearSorters = function () {
7936 this._currentSorters = [];
7937 this.updateSorters([]);
7938 };
7939 GridOdataService.prototype.updateOptions = function (serviceOptions) {
7940 this.options = __assign({}, this.options, serviceOptions);
7941 this._odataService.options = this.options;
7942 };
7943 GridOdataService.prototype.removeColumnFilter = function (fieldName) {
7944 this._odataService.removeColumnFilter(fieldName);
7945 };
7946 /** Get the Filters that are currently used by the grid */
7947 GridOdataService.prototype.getCurrentFilters = function () {
7948 return this._currentFilters;
7949 };
7950 /** Get the Pagination that is currently used by the grid */
7951 GridOdataService.prototype.getCurrentPagination = function () {
7952 return this._currentPagination;
7953 };
7954 /** Get the Sorters that are currently used by the grid */
7955 GridOdataService.prototype.getCurrentSorters = function () {
7956 return this._currentSorters;
7957 };
7958 /**
7959 * Mapper for mathematical operators (ex.: <= is "le", > is "gt")
7960 * @param string operator
7961 * @returns string map
7962 */
7963 GridOdataService.prototype.mapOdataOperator = function (operator) {
7964 var map = '';
7965 switch (operator) {
7966 case '<':
7967 map = 'lt';
7968 break;
7969 case '<=':
7970 map = 'le';
7971 break;
7972 case '>':
7973 map = 'gt';
7974 break;
7975 case '>=':
7976 map = 'ge';
7977 break;
7978 case '<>':
7979 case '!=':
7980 map = 'ne';
7981 break;
7982 case '=':
7983 case '==':
7984 default:
7985 map = 'eq';
7986 break;
7987 }
7988 return map;
7989 };
7990 /*
7991 * Reset the pagination options
7992 */
7993 GridOdataService.prototype.resetPaginationOptions = function () {
7994 this._odataService.updateOptions({
7995 skip: 0
7996 });
7997 };
7998 GridOdataService.prototype.saveColumnFilter = function (fieldName, value, terms) {
7999 this._odataService.saveColumnFilter(fieldName, value, terms);
8000 };
8001 /*
8002 * FILTERING
8003 */
8004 GridOdataService.prototype.processOnFilterChanged = function (event, args) {
8005 var gridOptions = this._gridOptions;
8006 var backendApi = gridOptions.backendServiceApi;
8007 if (backendApi === undefined) {
8008 throw new Error('Something went wrong in the GridOdataService, "backendServiceApi" is not initialized');
8009 }
8010 // keep current filters & always save it as an array (columnFilters can be an object when it is dealt by SlickGrid Filter)
8011 this._currentFilters = this.castFilterToColumnFilters(args.columnFilters);
8012 if (!args || !args.grid) {
8013 throw new Error('Something went wrong when trying create the GridOdataService, it seems that "args" is not populated correctly');
8014 }
8015 // loop through all columns to inspect filters & set the query
8016 this.updateFilters(args.columnFilters);
8017 this.resetPaginationOptions();
8018 return this._odataService.buildQuery();
8019 };
8020 /*
8021 * PAGINATION
8022 */
8023 GridOdataService.prototype.processOnPaginationChanged = function (event, args) {
8024 var pageSize = +(args.pageSize || ((this.pagination) ? this.pagination.pageSize : DEFAULT_PAGE_SIZE$1));
8025 this.updatePagination(args.newPage, pageSize);
8026 // build the OData query which we will use in the WebAPI callback
8027 return this._odataService.buildQuery();
8028 };
8029 /*
8030 * SORTING
8031 */
8032 GridOdataService.prototype.processOnSortChanged = function (event, args) {
8033 var sortColumns = (args.multiColumnSort) ? args.sortCols : new Array({ sortCol: args.sortCol, sortAsc: args.sortAsc });
8034 // loop through all columns to inspect sorters & set the query
8035 this.updateSorters(sortColumns);
8036 // build the OData query which we will use in the WebAPI callback
8037 return this._odataService.buildQuery();
8038 };
8039 /**
8040 * loop through all columns to inspect filters & update backend service filters
8041 * @param columnFilters
8042 */
8043 GridOdataService.prototype.updateFilters = function (columnFilters, isUpdatedByPreset) {
8044 var searchBy = '';
8045 var searchByArray = [];
8046 // on filter preset load, we need to keep current filters
8047 if (isUpdatedByPreset) {
8048 this._currentFilters = this.castFilterToColumnFilters(columnFilters);
8049 }
8050 var _loop_1 = function (columnId) {
8051 if (columnFilters.hasOwnProperty(columnId)) {
8052 var columnFilter_1 = columnFilters[columnId];
8053 // if user defined some "presets", then we need to find the filters from the column definitions instead
8054 var columnDef = void 0;
8055 if (isUpdatedByPreset && Array.isArray(this_1._columnDefinitions)) {
8056 columnDef = this_1._columnDefinitions.find(function (column) {
8057 return column.id === columnFilter_1.columnId;
8058 });
8059 }
8060 else {
8061 columnDef = columnFilter_1.columnDef;
8062 }
8063 if (!columnDef) {
8064 throw new Error('[GridOData Service]: Something went wrong in trying to get the column definition of the specified filter (or preset filters). Did you make a typo on the filter columnId?');
8065 }
8066 var fieldName = columnDef.queryFieldFilter || columnDef.queryField || columnDef.field || columnDef.name || '';
8067 var fieldType = columnDef.type || exports.FieldType.string;
8068 var searchTerms = (columnFilter_1 ? columnFilter_1.searchTerms : null) || [];
8069 var fieldSearchValue = (Array.isArray(searchTerms) && searchTerms.length === 1) ? searchTerms[0] : '';
8070 if (typeof fieldSearchValue === 'undefined') {
8071 fieldSearchValue = '';
8072 }
8073 if (!fieldName) {
8074 throw new Error("GridOData filter could not find the field name to query the search, your column definition must include a valid \"field\" or \"name\" (optionally you can also use the \"queryfield\" or \"queryFieldFilter\").");
8075 }
8076 fieldSearchValue = '' + fieldSearchValue; // make sure it's a string
8077 var matches = fieldSearchValue.match(/^([<>!=\*]{0,2})(.*[^<>!=\*])([\*]?)$/); // group 1: Operator, 2: searchValue, 3: last char is '*' (meaning starts with, ex.: abc*)
8078 var operator = columnFilter_1.operator || ((matches) ? matches[1] : '');
8079 var searchValue = (!!matches) ? matches[2] : '';
8080 var lastValueChar = (!!matches) ? matches[3] : (operator === '*z' ? '*' : '');
8081 var bypassOdataQuery = columnFilter_1.bypassBackendQuery || false;
8082 // no need to query if search value is empty
8083 if (fieldName && searchValue === '' && searchTerms.length <= 1) {
8084 this_1.removeColumnFilter(fieldName);
8085 return "continue";
8086 }
8087 // escaping the search value
8088 searchValue = searchValue.replace("'", "''"); // escape single quotes by doubling them
8089 searchValue = encodeURIComponent(searchValue); // encode URI of the final search value
8090 // if we didn't find an Operator but we have a Column Operator inside the Filter (DOM Element), we should use its default Operator
8091 // multipleSelect is "IN", while singleSelect is "EQ", else don't map any operator
8092 if (!operator && columnDef.filter) {
8093 operator = columnDef.filter.operator;
8094 }
8095 // if we still don't have an operator find the proper Operator to use by it's field type
8096 if (!operator) {
8097 operator = mapOperatorByFieldType(columnDef.type || exports.FieldType.string);
8098 }
8099 // extra query arguments
8100 if (bypassOdataQuery) {
8101 // push to our temp array and also trim white spaces
8102 if (fieldName) {
8103 this_1.saveColumnFilter(fieldName, fieldSearchValue, searchTerms);
8104 }
8105 }
8106 else {
8107 searchBy = '';
8108 // titleCase the fieldName so that it matches the WebApi names
8109 if (this_1._odataService.options.caseType === exports.CaseType.pascalCase) {
8110 fieldName = titleCase(fieldName || '');
8111 }
8112 // when having more than 1 search term (then check if we have a "IN" or "NOT IN" filter search)
8113 if (searchTerms && searchTerms.length > 1) {
8114 var tmpSearchTerms = [];
8115 if (operator === 'IN') {
8116 // example:: (Stage eq "Expired" or Stage eq "Renewal")
8117 for (var j = 0, lnj = searchTerms.length; j < lnj; j++) {
8118 tmpSearchTerms.push(fieldName + " eq '" + searchTerms[j] + "'");
8119 }
8120 searchBy = tmpSearchTerms.join(' or ');
8121 if (!(typeof searchBy === 'string' && searchBy[0] === '(' && searchBy.slice(-1) === ')')) {
8122 searchBy = "(" + searchBy + ")";
8123 }
8124 }
8125 else if (operator === 'NIN' || operator === 'NOTIN' || operator === 'NOT IN' || operator === 'NOT_IN') {
8126 // example:: (Stage ne "Expired" and Stage ne "Renewal")
8127 for (var k = 0, lnk = searchTerms.length; k < lnk; k++) {
8128 tmpSearchTerms.push(fieldName + " ne '" + searchTerms[k] + "'");
8129 }
8130 searchBy = tmpSearchTerms.join(' and ');
8131 if (!(typeof searchBy === 'string' && searchBy[0] === '(' && searchBy.slice(-1) === ')')) {
8132 searchBy = "(" + searchBy + ")";
8133 }
8134 }
8135 }
8136 else if (operator === '*' || operator === 'a*' || operator === '*z' || lastValueChar === '*') {
8137 // first/last character is a '*' will be a startsWith or endsWith
8138 searchBy = (operator === '*' || operator === '*z')
8139 ? "endswith(" + fieldName + ", '" + searchValue + "')"
8140 : "startswith(" + fieldName + ", '" + searchValue + "')";
8141 }
8142 else if (fieldType === exports.FieldType.date) {
8143 // date field needs to be UTC and within DateTime function
8144 var dateFormatted = parseUtcDate(searchValue, true);
8145 if (dateFormatted) {
8146 searchBy = fieldName + " " + this_1.mapOdataOperator(operator) + " DateTime'" + dateFormatted + "'";
8147 }
8148 }
8149 else if (fieldType === exports.FieldType.string) {
8150 // string field needs to be in single quotes
8151 if (operator === '' || operator === exports.OperatorType.contains || operator === exports.OperatorType.notContains) {
8152 searchBy = "substringof('" + searchValue + "', " + fieldName + ")";
8153 if (operator === exports.OperatorType.notContains) {
8154 searchBy = "not " + searchBy;
8155 }
8156 }
8157 else {
8158 // searchBy = `substringof('${searchValue}', ${fieldNameCased}) ${this.mapOdataOperator(operator)} true`;
8159 searchBy = fieldName + " " + this_1.mapOdataOperator(operator) + " '" + searchValue + "'";
8160 }
8161 }
8162 else {
8163 // any other field type (or undefined type)
8164 searchValue = (fieldType === exports.FieldType.number || fieldType === exports.FieldType.boolean) ? searchValue : "'" + searchValue + "'";
8165 searchBy = fieldName + " " + this_1.mapOdataOperator(operator) + " " + searchValue;
8166 }
8167 // push to our temp array and also trim white spaces
8168 if (searchBy !== '') {
8169 searchByArray.push(searchBy.trim());
8170 this_1.saveColumnFilter(fieldName || '', fieldSearchValue, searchTerms);
8171 }
8172 }
8173 }
8174 };
8175 var this_1 = this;
8176 // loop through all columns to inspect filters
8177 for (var columnId in columnFilters) {
8178 _loop_1(columnId);
8179 }
8180 // update the service options with filters for the buildQuery() to work later
8181 this._odataService.updateOptions({
8182 filter: (searchByArray.length > 0) ? searchByArray.join(' and ') : '',
8183 skip: undefined
8184 });
8185 };
8186 /**
8187 * Update the pagination component with it's new page number and size
8188 * @param newPage
8189 * @param pageSize
8190 */
8191 GridOdataService.prototype.updatePagination = function (newPage, pageSize) {
8192 this._currentPagination = {
8193 pageNumber: newPage,
8194 pageSize: pageSize
8195 };
8196 this._odataService.updateOptions({
8197 top: pageSize,
8198 skip: (newPage - 1) * pageSize
8199 });
8200 };
8201 /**
8202 * loop through all columns to inspect sorters & update backend service orderBy
8203 * @param columnFilters
8204 */
8205 GridOdataService.prototype.updateSorters = function (sortColumns, presetSorters) {
8206 var _this = this;
8207 var e_1, _a;
8208 var currentSorters = [];
8209 var odataSorters = [];
8210 if (!sortColumns && presetSorters) {
8211 // make the presets the current sorters, also make sure that all direction are in lowercase for OData
8212 currentSorters = presetSorters;
8213 currentSorters.forEach(function (sorter) { return sorter.direction = sorter.direction.toLowerCase(); });
8214 // display the correct sorting icons on the UI, for that it requires (columnId, sortAsc) properties
8215 var tmpSorterArray = currentSorters.map(function (sorter) {
8216 var columnDef = _this._columnDefinitions.find(function (column) { return column.id === sorter.columnId; });
8217 odataSorters.push({
8218 field: columnDef ? ((columnDef.queryFieldSorter || columnDef.queryField || columnDef.field) + '') : (sorter.columnId + ''),
8219 direction: sorter.direction
8220 });
8221 // return only the column(s) found in the Column Definitions ELSE null
8222 if (columnDef) {
8223 return {
8224 columnId: sorter.columnId,
8225 sortAsc: sorter.direction.toUpperCase() === exports.SortDirection.ASC
8226 };
8227 }
8228 return null;
8229 });
8230 // set the sort icons, but also make sure to filter out null values (that happens when columnDef is not found)
8231 if (Array.isArray(tmpSorterArray)) {
8232 this._grid.setSortColumns(tmpSorterArray);
8233 }
8234 }
8235 else if (sortColumns && !presetSorters) {
8236 // build the SortBy string, it could be multisort, example: customerNo asc, purchaserName desc
8237 if (sortColumns && sortColumns.length === 0) ;
8238 else {
8239 if (sortColumns) {
8240 try {
8241 for (var sortColumns_1 = __values(sortColumns), sortColumns_1_1 = sortColumns_1.next(); !sortColumns_1_1.done; sortColumns_1_1 = sortColumns_1.next()) {
8242 var columnDef = sortColumns_1_1.value;
8243 if (columnDef.sortCol) {
8244 var fieldName = (columnDef.sortCol.queryFieldSorter || columnDef.sortCol.queryField || columnDef.sortCol.field) + '';
8245 var columnFieldName = (columnDef.sortCol.field || columnDef.sortCol.id) + '';
8246 var queryField = (columnDef.sortCol.queryFieldSorter || columnDef.sortCol.queryField || columnDef.sortCol.field || '') + '';
8247 if (this._odataService.options.caseType === exports.CaseType.pascalCase) {
8248 fieldName = titleCase(fieldName);
8249 columnFieldName = titleCase(columnFieldName);
8250 queryField = titleCase(queryField);
8251 }
8252 if (columnFieldName !== '') {
8253 currentSorters.push({
8254 columnId: columnFieldName,
8255 direction: columnDef.sortAsc ? 'asc' : 'desc'
8256 });
8257 }
8258 if (queryField !== '') {
8259 odataSorters.push({
8260 field: queryField,
8261 direction: columnDef.sortAsc ? exports.SortDirection.ASC : exports.SortDirection.DESC
8262 });
8263 }
8264 }
8265 }
8266 }
8267 catch (e_1_1) { e_1 = { error: e_1_1 }; }
8268 finally {
8269 try {
8270 if (sortColumns_1_1 && !sortColumns_1_1.done && (_a = sortColumns_1.return)) _a.call(sortColumns_1);
8271 }
8272 finally { if (e_1) throw e_1.error; }
8273 }
8274 }
8275 }
8276 }
8277 // transform the sortby array into a CSV string for OData
8278 currentSorters = currentSorters || [];
8279 var csvString = odataSorters.map(function (sorter) {
8280 if (sorter && sorter.field) {
8281 var sortField = (_this._odataService.options.caseType === exports.CaseType.pascalCase) ? titleCase(sorter.field) : sorter.field;
8282 return sortField + " " + (sorter && sorter.direction && sorter.direction.toLowerCase() || '');
8283 }
8284 return '';
8285 }).join(',');
8286 this._odataService.updateOptions({
8287 orderBy: csvString
8288 });
8289 // keep current Sorters and update the service options with the new sorting
8290 this._currentSorters = currentSorters;
8291 // build the OData query which we will use in the WebAPI callback
8292 return this._odataService.buildQuery();
8293 };
8294 //
8295 // private functions
8296 // -------------------
8297 /**
8298 * Cast provided filters (could be in multiple format) into an array of ColumnFilter
8299 * @param columnFilters
8300 */
8301 GridOdataService.prototype.castFilterToColumnFilters = function (columnFilters) {
8302 // keep current filters & always save it as an array (columnFilters can be an object when it is dealt by SlickGrid Filter)
8303 var filtersArray = (typeof columnFilters === 'object') ? Object.keys(columnFilters).map(function (key) { return columnFilters[key]; }) : columnFilters;
8304 if (!Array.isArray(filtersArray)) {
8305 return [];
8306 }
8307 return filtersArray.map(function (filter) {
8308 var tmpFilter = { columnId: filter.columnId || '' };
8309 if (filter.operator) {
8310 tmpFilter.operator = filter.operator;
8311 }
8312 if (Array.isArray(filter.searchTerms)) {
8313 tmpFilter.searchTerms = filter.searchTerms;
8314 }
8315 return tmpFilter;
8316 });
8317 };
8318 GridOdataService = __decorate([
8319 core.Injectable(),
8320 __metadata("design:paramtypes", [])
8321 ], GridOdataService);
8322 return GridOdataService;
8323 }());
8324
8325 var GridEventService = /** @class */ (function () {
8326 function GridEventService() {
8327 this._eventHandler = new Slick.EventHandler();
8328 }
8329 Object.defineProperty(GridEventService.prototype, "eventHandler", {
8330 get: function () {
8331 return this._eventHandler;
8332 },
8333 enumerable: true,
8334 configurable: true
8335 });
8336 /* OnCellChange Event */
8337 GridEventService.prototype.bindOnCellChange = function (grid, dataView) {
8338 // subscribe to this Slickgrid event of onCellChange
8339 this._eventHandler.subscribe(grid.onCellChange, function (e, args) {
8340 if (!e || !args || !grid || args.cell === undefined || !grid.getColumns || !grid.getDataItem) {
8341 return;
8342 }
8343 var column = grid.getColumns()[args.cell];
8344 // if the column definition has a onCellChange property (a callback function), then run it
8345 if (typeof column.onCellChange === 'function') {
8346 // add to the output gridOptions & dataView since we'll need them inside the AJAX column.onCellChange
8347 var returnedArgs = {
8348 row: args.row,
8349 cell: args.cell,
8350 dataView: dataView,
8351 grid: grid,
8352 columnDef: column,
8353 dataContext: grid.getDataItem(args.row)
8354 };
8355 // finally call up the Slick.column.onCellChanges.... function
8356 column.onCellChange(e, returnedArgs);
8357 }
8358 });
8359 };
8360 /* OnClick Event */
8361 GridEventService.prototype.bindOnClick = function (grid, dataView) {
8362 this._eventHandler.subscribe(grid.onClick, function (e, args) {
8363 if (!e || !args || !grid || args.cell === undefined || !grid.getColumns || !grid.getDataItem) {
8364 return;
8365 }
8366 var column = grid && grid.getColumns && grid.getColumns()[args.cell];
8367 var gridOptions = grid && grid.getOptions && grid.getOptions() || {};
8368 // only when using autoCommitEdit, we will make the cell active (in focus) when clicked
8369 // setting the cell as active as a side effect and if autoCommitEdit is set to false then the Editors won't save correctly
8370 if (gridOptions.enableCellNavigation && (!gridOptions.editable || (gridOptions.editable && gridOptions.autoCommitEdit))) {
8371 grid.setActiveCell(args.row, args.cell);
8372 }
8373 // if the column definition has a onCellClick property (a callback function), then run it
8374 if (typeof column.onCellClick === 'function') {
8375 // add to the output gridOptions & dataView since we'll need them inside the AJAX column.onClick
8376 var returnedArgs = {
8377 row: args.row,
8378 cell: args.cell,
8379 dataView: dataView,
8380 grid: grid,
8381 columnDef: column,
8382 dataContext: grid.getDataItem(args.row)
8383 };
8384 // finally call up the Slick.column.onCellClick.... function
8385 column.onCellClick(e, returnedArgs);
8386 }
8387 });
8388 };
8389 GridEventService.prototype.dispose = function () {
8390 this._eventHandler.unsubscribeAll();
8391 };
8392 return GridEventService;
8393 }());
8394
8395 var GridStateService = /** @class */ (function () {
8396 function GridStateService() {
8397 this._eventHandler = new Slick.EventHandler();
8398 this._columns = [];
8399 this._currentColumns = [];
8400 this.subscriptions = [];
8401 this.onGridStateChanged = new rxjs.Subject();
8402 }
8403 Object.defineProperty(GridStateService.prototype, "_gridOptions", {
8404 /** Getter for the Grid Options pulled through the Grid Object */
8405 get: function () {
8406 return (this._grid && this._grid.getOptions) ? this._grid.getOptions() : {};
8407 },
8408 enumerable: true,
8409 configurable: true
8410 });
8411 /**
8412 * Initialize the Export Service
8413 * @param grid
8414 * @param filterService
8415 * @param sortService
8416 * @param dataView
8417 */
8418 GridStateService.prototype.init = function (grid, extensionService, filterService, sortService) {
8419 this._grid = grid;
8420 this.extensionService = extensionService;
8421 this.filterService = filterService;
8422 this.sortService = sortService;
8423 this.subscribeToAllGridChanges(grid);
8424 };
8425 /** Dispose of all the SlickGrid & Angular subscriptions */
8426 GridStateService.prototype.dispose = function () {
8427 // unsubscribe all SlickGrid events
8428 this._eventHandler.unsubscribeAll();
8429 // also unsubscribe all Angular Subscriptions
8430 this.subscriptions.forEach(function (subscription) {
8431 if (subscription && subscription.unsubscribe) {
8432 subscription.unsubscribe();
8433 }
8434 });
8435 this.subscriptions = [];
8436 this._currentColumns = [];
8437 this._columns = [];
8438 };
8439 /**
8440 * Get the current grid state (filters/sorters/pagination)
8441 * @return grid state
8442 */
8443 GridStateService.prototype.getCurrentGridState = function () {
8444 var gridState = {
8445 columns: this.getCurrentColumns(),
8446 filters: this.getCurrentFilters(),
8447 sorters: this.getCurrentSorters()
8448 };
8449 var currentPagination = this.getCurrentPagination();
8450 if (currentPagination) {
8451 gridState.pagination = currentPagination;
8452 }
8453 return gridState;
8454 };
8455 /**
8456 * Get the Columns (and their state: visibility/position) that are currently applied in the grid
8457 * @return current columns
8458 */
8459 GridStateService.prototype.getColumns = function () {
8460 return this._columns;
8461 };
8462 /**
8463 * From an array of Grid Column Definitions, get the associated Current Columns
8464 * @param gridColumns
8465 */
8466 GridStateService.prototype.getAssociatedCurrentColumns = function (gridColumns) {
8467 var currentColumns = [];
8468 if (gridColumns && Array.isArray(gridColumns)) {
8469 gridColumns.forEach(function (column, index) {
8470 if (column && column.id) {
8471 currentColumns.push({
8472 columnId: column.id,
8473 cssClass: column.cssClass || '',
8474 headerCssClass: column.headerCssClass || '',
8475 width: column.width || 0
8476 });
8477 }
8478 });
8479 }
8480 this._currentColumns = currentColumns;
8481 return currentColumns;
8482 };
8483 /**
8484 * From an array of Current Columns, get the associated Grid Column Definitions
8485 * @param grid
8486 * @param currentColumns
8487 */
8488 GridStateService.prototype.getAssociatedGridColumns = function (grid, currentColumns) {
8489 var columns = [];
8490 var gridColumns = grid.getColumns();
8491 if (currentColumns && Array.isArray(currentColumns)) {
8492 currentColumns.forEach(function (currentColumn, index) {
8493 var gridColumn = gridColumns.find(function (c) { return c.id === currentColumn.columnId; });
8494 if (gridColumn && gridColumn.id) {
8495 columns.push(__assign({}, gridColumn, { cssClass: currentColumn.cssClass, headerCssClass: currentColumn.headerCssClass, width: currentColumn.width }));
8496 }
8497 });
8498 }
8499 this._columns = columns;
8500 return columns;
8501 };
8502 /**
8503 * Get the Columns (and their state: visibility/position) that are currently applied in the grid
8504 * @return current columns
8505 */
8506 GridStateService.prototype.getCurrentColumns = function () {
8507 var currentColumns = [];
8508 if (this._currentColumns && Array.isArray(this._currentColumns) && this._currentColumns.length > 0) {
8509 currentColumns = this._currentColumns;
8510 }
8511 else {
8512 currentColumns = this.getAssociatedCurrentColumns(this._grid.getColumns());
8513 }
8514 return currentColumns;
8515 };
8516 /**
8517 * Get the Filters (and their state, columnId, searchTerm(s)) that are currently applied in the grid
8518 * @return current filters
8519 */
8520 GridStateService.prototype.getCurrentFilters = function () {
8521 if (this._gridOptions && this._gridOptions.backendServiceApi) {
8522 var backendService = this._gridOptions.backendServiceApi.service;
8523 if (backendService && backendService.getCurrentFilters) {
8524 return backendService.getCurrentFilters();
8525 }
8526 }
8527 else if (this.filterService && this.filterService.getCurrentLocalFilters) {
8528 return this.filterService.getCurrentLocalFilters();
8529 }
8530 return null;
8531 };
8532 /**
8533 * Get current Pagination (and it's state, pageNumber, pageSize) that are currently applied in the grid
8534 * @return current pagination state
8535 */
8536 GridStateService.prototype.getCurrentPagination = function () {
8537 if (this._gridOptions && this._gridOptions.backendServiceApi) {
8538 var backendService = this._gridOptions.backendServiceApi.service;
8539 if (backendService && backendService.getCurrentPagination) {
8540 return backendService.getCurrentPagination();
8541 }
8542 }
8543 return null;
8544 };
8545 /**
8546 * Get the current Sorters (and their state, columnId, direction) that are currently applied in the grid
8547 * @return current sorters
8548 */
8549 GridStateService.prototype.getCurrentSorters = function () {
8550 if (this._gridOptions && this._gridOptions.backendServiceApi) {
8551 var backendService = this._gridOptions.backendServiceApi.service;
8552 if (backendService && backendService.getCurrentSorters) {
8553 return backendService.getCurrentSorters();
8554 }
8555 }
8556 else if (this.sortService && this.sortService.getCurrentLocalSorters) {
8557 return this.sortService.getCurrentLocalSorters();
8558 }
8559 return null;
8560 };
8561 GridStateService.prototype.resetColumns = function (columnDefinitions) {
8562 var columns = columnDefinitions || this._columns;
8563 var currentColumns = this.getAssociatedCurrentColumns(columns);
8564 this.onGridStateChanged.next({ change: { newValues: currentColumns, type: exports.GridStateType.columns }, gridState: this.getCurrentGridState() });
8565 };
8566 /** if we use Row Selection or the Checkbox Selector, we need to reset any selection */
8567 GridStateService.prototype.resetRowSelection = function () {
8568 if (this._gridOptions.enableRowSelection || this._gridOptions.enableCheckboxSelector) {
8569 // this also requires the Row Selection Model to be registered as well
8570 var rowSelectionExtension = this.extensionService && this.extensionService.getExtensionByName && this.extensionService.getExtensionByName(exports.ExtensionName.rowSelection);
8571 if (rowSelectionExtension && rowSelectionExtension.instance) {
8572 this._grid.setSelectedRows([]);
8573 }
8574 }
8575 };
8576 /**
8577 * Subscribe to all necessary SlickGrid or Service Events that deals with a Grid change,
8578 * when triggered, we will publish a Grid State Event with current Grid State
8579 */
8580 GridStateService.prototype.subscribeToAllGridChanges = function (grid) {
8581 var _this = this;
8582 // Subscribe to Event Emitter of Filter changed
8583 this.subscriptions.push(this.filterService.onFilterChanged.subscribe(function (currentFilters) {
8584 _this.resetRowSelection();
8585 _this.onGridStateChanged.next({ change: { newValues: currentFilters, type: exports.GridStateType.filter }, gridState: _this.getCurrentGridState() });
8586 }));
8587 // Subscribe to Event Emitter of Filter cleared
8588 this.subscriptions.push(this.filterService.onFilterCleared.subscribe(function () {
8589 _this.resetRowSelection();
8590 _this.onGridStateChanged.next({ change: { newValues: [], type: exports.GridStateType.filter }, gridState: _this.getCurrentGridState() });
8591 }));
8592 // Subscribe to Event Emitter of Sort changed
8593 this.subscriptions.push(this.sortService.onSortChanged.subscribe(function (currentSorters) {
8594 _this.resetRowSelection();
8595 _this.onGridStateChanged.next({ change: { newValues: currentSorters, type: exports.GridStateType.sorter }, gridState: _this.getCurrentGridState() });
8596 }));
8597 // Subscribe to Event Emitter of Sort cleared
8598 this.subscriptions.push(this.sortService.onSortCleared.subscribe(function () {
8599 _this.resetRowSelection();
8600 _this.onGridStateChanged.next({ change: { newValues: [], type: exports.GridStateType.sorter }, gridState: _this.getCurrentGridState() });
8601 }));
8602 // Subscribe to ColumnPicker and/or GridMenu for show/hide Columns visibility changes
8603 this.bindExtensionAddonEventToGridStateChange(exports.ExtensionName.columnPicker, 'onColumnsChanged');
8604 this.bindExtensionAddonEventToGridStateChange(exports.ExtensionName.gridMenu, 'onColumnsChanged');
8605 // subscribe to Column Resize & Reordering
8606 this.bindSlickGridEventToGridStateChange('onColumnsReordered', grid);
8607 this.bindSlickGridEventToGridStateChange('onColumnsResized', grid);
8608 };
8609 // --
8610 // private methods
8611 // ------------------
8612 /**
8613 * Bind a SlickGrid Extension Event to a Grid State change event
8614 * @param extension name
8615 * @param grid
8616 */
8617 GridStateService.prototype.bindExtensionAddonEventToGridStateChange = function (extensionName, eventName) {
8618 var _this = this;
8619 var extension = this.extensionService && this.extensionService.getExtensionByName && this.extensionService.getExtensionByName(extensionName);
8620 var slickEvent = extension && extension.instance && extension.instance[eventName];
8621 if (slickEvent && slickEvent.subscribe) {
8622 this._eventHandler.subscribe(slickEvent, function (e, args) {
8623 var columns = args && args.columns;
8624 var currentColumns = _this.getAssociatedCurrentColumns(columns);
8625 _this.onGridStateChanged.next({ change: { newValues: currentColumns, type: exports.GridStateType.columns }, gridState: _this.getCurrentGridState() });
8626 });
8627 }
8628 };
8629 /**
8630 * Bind a Grid Event to a Grid State change event
8631 * @param event name
8632 * @param grid
8633 */
8634 GridStateService.prototype.bindSlickGridEventToGridStateChange = function (eventName, grid) {
8635 var _this = this;
8636 var slickGridEvent = grid && grid[eventName];
8637 if (slickGridEvent && slickGridEvent.subscribe) {
8638 this._eventHandler.subscribe(slickGridEvent, function (e, args) {
8639 var columns = grid.getColumns();
8640 var currentColumns = _this.getAssociatedCurrentColumns(columns);
8641 _this.onGridStateChanged.next({ change: { newValues: currentColumns, type: exports.GridStateType.columns }, gridState: _this.getCurrentGridState() });
8642 });
8643 }
8644 };
8645 return GridStateService;
8646 }());
8647
8648 var highlightTimerEnd;
8649 var GridServiceDeleteOptionDefaults = { triggerEvent: true };
8650 var GridServiceInsertOptionDefaults = { highlightRow: true, resortGrid: false, selectRow: false, triggerEvent: true };
8651 var GridServiceUpdateOptionDefaults = { highlightRow: true, selectRow: false, triggerEvent: true };
8652 var GridService = /** @class */ (function () {
8653 function GridService(extensionService, filterService, gridStateService, sortService) {
8654 this.extensionService = extensionService;
8655 this.filterService = filterService;
8656 this.gridStateService = gridStateService;
8657 this.sortService = sortService;
8658 this.onItemAdded = new rxjs.Subject();
8659 this.onItemDeleted = new rxjs.Subject();
8660 this.onItemUpdated = new rxjs.Subject();
8661 this.onItemUpserted = new rxjs.Subject();
8662 }
8663 Object.defineProperty(GridService.prototype, "_gridOptions", {
8664 /** Getter for the Grid Options pulled through the Grid Object */
8665 get: function () {
8666 return (this._grid && this._grid.getOptions) ? this._grid.getOptions() : {};
8667 },
8668 enumerable: true,
8669 configurable: true
8670 });
8671 GridService.prototype.init = function (grid, dataView) {
8672 this._grid = grid;
8673 this._dataView = dataView;
8674 };
8675 /** Clear all Filters & Sorts */
8676 GridService.prototype.clearAllFiltersAndSorts = function () {
8677 // call both clear Filters & Sort but only trigger the last one to avoid sending multiple backend queries
8678 if (this.sortService && this.sortService.clearSorting) {
8679 this.sortService.clearSorting(false); // skip event trigger on this one
8680 }
8681 if (this.filterService && this.filterService.clearFilters) {
8682 this.filterService.clearFilters();
8683 }
8684 };
8685 /**
8686 * From a SlickGrid Event triggered get the Column Definition and Item Data Context
8687 *
8688 * For example the SlickGrid onClick will return cell arguments when subscribing to it.
8689 * From these cellArgs, we want to get the Column Definition and Item Data
8690 * @param cell event args
8691 * @return object with columnDef and dataContext
8692 */
8693 GridService.prototype.getColumnFromEventArguments = function (args) {
8694 if (!args || !args.grid || !args.grid.getColumns || !args.grid.getDataItem) {
8695 throw new Error('To get the column definition and data, we need to have these arguments passed as objects (row, cell, grid)');
8696 }
8697 return {
8698 row: args.row,
8699 cell: args.cell,
8700 columnDef: args.grid.getColumns()[args.cell],
8701 dataContext: args.grid.getDataItem(args.row),
8702 dataView: this._dataView,
8703 grid: this._grid
8704 };
8705 };
8706 /** Get data item by it's row index number */
8707 GridService.prototype.getDataItemByRowNumber = function (rowNumber) {
8708 if (!this._grid || typeof this._grid.getDataItem !== 'function') {
8709 throw new Error("We could not find SlickGrid Grid object or it's \"getDataItem\" method");
8710 }
8711 return this._grid.getDataItem(rowNumber);
8712 };
8713 /** Chain the item Metadata with our implementation of Metadata at given row index */
8714 GridService.prototype.getItemRowMetadataToHighlight = function (previousItemMetadata) {
8715 var _this = this;
8716 return function (rowNumber) {
8717 var item = _this._dataView.getItem(rowNumber);
8718 var meta = { cssClasses: '' };
8719 if (typeof previousItemMetadata === 'function') {
8720 meta = previousItemMetadata(rowNumber);
8721 }
8722 if (!meta) {
8723 meta = { cssClasses: '' };
8724 }
8725 if (item && item._dirty) {
8726 meta.cssClasses = (meta && meta.cssClasses || '') + ' dirty';
8727 }
8728 if (item && item.rowClass && meta) {
8729 meta.cssClasses += " " + item.rowClass;
8730 meta.cssClasses += " row" + rowNumber;
8731 }
8732 return meta;
8733 };
8734 };
8735 /**
8736 * Highlight then fade a row for x seconds.
8737 * The implementation follows this SO answer: https://stackoverflow.com/a/19985148/1212166
8738 * @param rowNumber
8739 * @param fadeDelay
8740 */
8741 GridService.prototype.highlightRow = function (rowNumber, fadeDelay, fadeOutDelay) {
8742 var _this = this;
8743 if (fadeDelay === void 0) { fadeDelay = 1500; }
8744 if (fadeOutDelay === void 0) { fadeOutDelay = 300; }
8745 // create a SelectionModel if there's not one yet
8746 if (!this._grid.getSelectionModel()) {
8747 var rowSelectionPlugin = new Slick.RowSelectionModel(this._gridOptions.rowSelectionOptions || {});
8748 this._grid.setSelectionModel(rowSelectionPlugin);
8749 }
8750 if (Array.isArray(rowNumber)) {
8751 rowNumber.forEach(function (row) { return _this.highlightRowByMetadata(row, fadeDelay, fadeOutDelay); });
8752 }
8753 else {
8754 this.highlightRowByMetadata(rowNumber, fadeDelay, fadeOutDelay);
8755 }
8756 };
8757 GridService.prototype.highlightRowByMetadata = function (rowNumber, fadeDelay, fadeOutDelay) {
8758 var _this = this;
8759 if (fadeDelay === void 0) { fadeDelay = 1500; }
8760 if (fadeOutDelay === void 0) { fadeOutDelay = 300; }
8761 this._dataView.getItemMetadata = this.getItemRowMetadataToHighlight(this._dataView.getItemMetadata);
8762 var item = this._dataView.getItem(rowNumber);
8763 if (item && item.id) {
8764 item.rowClass = 'highlight';
8765 this._dataView.updateItem(item.id, item);
8766 this.renderGrid();
8767 // fade out
8768 clearTimeout(highlightTimerEnd);
8769 highlightTimerEnd = setTimeout(function () {
8770 item.rowClass = 'highlight-end';
8771 _this._dataView.updateItem(item.id, item);
8772 _this.renderGrid();
8773 }, fadeOutDelay);
8774 // delete the row's CSS highlight classes once the delay is passed
8775 setTimeout(function () {
8776 if (item && item.id) {
8777 delete item.rowClass;
8778 if (_this._dataView.getIdxById(item.id) !== undefined) {
8779 _this._dataView.updateItem(item.id, item);
8780 _this.renderGrid();
8781 }
8782 }
8783 }, fadeDelay + fadeOutDelay);
8784 }
8785 };
8786 /** Get the Data Item from a grid row index */
8787 GridService.prototype.getDataItemByRowIndex = function (index) {
8788 if (!this._grid || typeof this._grid.getDataItem !== 'function') {
8789 throw new Error('We could not find SlickGrid Grid object and/or "getDataItem" method');
8790 }
8791 return this._grid.getDataItem(index);
8792 };
8793 /** Get the Data Item from an array of grid row indexes */
8794 GridService.prototype.getDataItemByRowIndexes = function (indexes) {
8795 var _this = this;
8796 if (!this._grid || typeof this._grid.getDataItem !== 'function') {
8797 throw new Error('We could not find SlickGrid Grid object and/or "getDataItem" method');
8798 }
8799 var dataItems = [];
8800 if (Array.isArray(indexes)) {
8801 indexes.forEach(function (idx) {
8802 dataItems.push(_this._grid.getDataItem(idx));
8803 });
8804 }
8805 return dataItems;
8806 };
8807 /** Get the currently selected row indexes */
8808 GridService.prototype.getSelectedRows = function () {
8809 if (!this._grid || typeof this._grid.getSelectedRows !== 'function') {
8810 throw new Error('We could not find SlickGrid Grid object and/or "getSelectedRows" method');
8811 }
8812 return this._grid.getSelectedRows();
8813 };
8814 /** Get the currently selected rows item data */
8815 GridService.prototype.getSelectedRowsDataItem = function () {
8816 if (!this._grid || typeof this._grid.getSelectedRows !== 'function') {
8817 throw new Error('We could not find SlickGrid Grid object and/or "getSelectedRows" method');
8818 }
8819 var selectedRowIndexes = this._grid.getSelectedRows();
8820 return this.getDataItemByRowIndexes(selectedRowIndexes);
8821 };
8822 /** Select the selected row by a row index */
8823 GridService.prototype.setSelectedRow = function (rowIndex) {
8824 if (this._grid && this._grid.setSelectedRows) {
8825 this._grid.setSelectedRows([rowIndex]);
8826 }
8827 };
8828 /** Set selected rows with provided array of row indexes */
8829 GridService.prototype.setSelectedRows = function (rowIndexes) {
8830 if (this._grid && this._grid.setSelectedRows) {
8831 this._grid.setSelectedRows(rowIndexes);
8832 }
8833 };
8834 /** Re-Render the Grid */
8835 GridService.prototype.renderGrid = function () {
8836 if (this._grid && typeof this._grid.invalidate === 'function') {
8837 this._grid.invalidate();
8838 this._grid.render();
8839 }
8840 };
8841 /**
8842 * Reset the grid to it's original state (clear any filters, sorting & pagination if exists) .
8843 * The column definitions could be passed as argument to reset (this can be used after a Grid State reset)
8844 * The reset will clear the Filters & Sort, then will reset the Columns to their original state
8845 */
8846 GridService.prototype.resetGrid = function (columnDefinitions) {
8847 // reset columns to original states & refresh the grid
8848 if (this._grid && this._dataView) {
8849 var originalColumns = this.extensionService.getAllColumns();
8850 if (Array.isArray(originalColumns) && originalColumns.length > 0) {
8851 // set the grid columns to it's original column definitions
8852 this._grid.setColumns(originalColumns);
8853 if (this._gridOptions && this._gridOptions.enableAutoSizeColumns) {
8854 this._grid.autosizeColumns();
8855 }
8856 this.gridStateService.resetColumns(columnDefinitions);
8857 }
8858 }
8859 if (this.filterService && this.filterService.clearFilters) {
8860 this.filterService.clearFilters();
8861 }
8862 if (this.sortService && this.sortService.clearSorting) {
8863 this.sortService.clearSorting();
8864 }
8865 };
8866 /** @deprecated please use "addItem" method instead */
8867 GridService.prototype.addItemToDatagrid = function (item, shouldHighlightRow, shouldResortGrid, shouldTriggerEvent, shouldSelectRow) {
8868 if (shouldHighlightRow === void 0) { shouldHighlightRow = true; }
8869 if (shouldResortGrid === void 0) { shouldResortGrid = false; }
8870 if (shouldTriggerEvent === void 0) { shouldTriggerEvent = true; }
8871 if (shouldSelectRow === void 0) { shouldSelectRow = true; }
8872 return this.addItem(item, { highlightRow: shouldHighlightRow, resortGrid: shouldResortGrid, triggerEvent: shouldTriggerEvent, selectRow: shouldSelectRow });
8873 };
8874 /** @deprecated please use "addItems" method instead */
8875 GridService.prototype.addItemsToDatagrid = function (items, shouldHighlightRow, shouldResortGrid, shouldTriggerEvent, shouldSelectRow) {
8876 if (shouldHighlightRow === void 0) { shouldHighlightRow = true; }
8877 if (shouldResortGrid === void 0) { shouldResortGrid = false; }
8878 if (shouldTriggerEvent === void 0) { shouldTriggerEvent = true; }
8879 if (shouldSelectRow === void 0) { shouldSelectRow = true; }
8880 return this.addItems(items, { highlightRow: shouldHighlightRow, resortGrid: shouldResortGrid, triggerEvent: shouldTriggerEvent, selectRow: shouldSelectRow });
8881 };
8882 /**
8883 * Add an item (data item) to the datagrid, by default it will highlight (flashing) the inserted row but we can disable it too
8884 * @param item object which must contain a unique "id" property and any other suitable properties
8885 * @param options: provide the possibility to do certain actions after or during the upsert (highlightRow, resortGrid, selectRow, triggerEvent)
8886 * @return rowIndex: typically index 0
8887 */
8888 GridService.prototype.addItem = function (item, options) {
8889 options = __assign({}, GridServiceInsertOptionDefaults, options);
8890 if (!this._grid || !this._gridOptions || !this._dataView) {
8891 throw new Error('We could not find SlickGrid Grid, DataView objects');
8892 }
8893 if (!item || !item.hasOwnProperty('id')) {
8894 throw new Error("Adding an item requires the item to include an \"id\" property");
8895 }
8896 this._dataView.insertItem(0, item); // insert at index 0
8897 // row number in the grid, by default it will be on first row
8898 var rowNumber = 0;
8899 // do we want the item to be sorted in the grid, when set to False it will insert on first row (defaults to false)
8900 if (options.resortGrid) {
8901 this._dataView.reSort();
8902 // find the row number in the grid and if user wanted to see highlighted row
8903 // we need to do it here after resort and get each row number because it possibly changes after the sort
8904 rowNumber = this._dataView.getRowById(item.id);
8905 }
8906 else {
8907 this._grid.scrollRowIntoView(rowNumber); // scroll to row 0
8908 }
8909 // highlight the row we just added, if highlight is defined
8910 if (options.highlightRow) {
8911 this.highlightRow(rowNumber);
8912 }
8913 // select the row in the grid
8914 if (options.selectRow && this._gridOptions && (this._gridOptions.enableCheckboxSelector || this._gridOptions.enableRowSelection)) {
8915 this._grid.setSelectedRows(rowNumber);
8916 }
8917 // do we want to trigger an event after adding the item
8918 if (options.triggerEvent) {
8919 this.onItemAdded.next(item);
8920 }
8921 return rowNumber;
8922 };
8923 /**
8924 * Add item array (data item) to the datagrid, by default it will highlight (flashing) the inserted row but we can disable it too
8925 * @param item object arrays, which must contain unique "id" property and any other suitable properties
8926 * @param options: provide the possibility to do certain actions after or during the upsert (highlightRow, resortGrid, selectRow, triggerEvent)
8927 */
8928 GridService.prototype.addItems = function (items, options) {
8929 var _this = this;
8930 options = __assign({}, GridServiceInsertOptionDefaults, options);
8931 var rowNumbers = [];
8932 // loop through all items to add
8933 if (!Array.isArray(items)) {
8934 return [this.addItem(items, options)];
8935 }
8936 else {
8937 items.forEach(function (item) { return _this.addItem(item, { highlightRow: false, resortGrid: false, selectRow: false, triggerEvent: false }); });
8938 }
8939 // do we want the item to be sorted in the grid, when set to False it will insert on first row (defaults to false)
8940 if (options.resortGrid) {
8941 this._dataView.reSort();
8942 // if user wanted to see highlighted row
8943 // we need to do it here after resort and get each row number because it possibly changes after the sort
8944 if (options.highlightRow) {
8945 items.forEach(function (item) {
8946 var rowNumber = _this._dataView.getRowById(item.id);
8947 rowNumbers.push(rowNumber);
8948 });
8949 }
8950 }
8951 else if (options.highlightRow) {
8952 var ln = items.length;
8953 for (var i = 0; i < ln; i++) {
8954 rowNumbers.push(i);
8955 }
8956 }
8957 // do user want to highlight the rows
8958 if (options.highlightRow) {
8959 this.highlightRow(rowNumbers);
8960 }
8961 // select the row in the grid
8962 if (options.selectRow && this._gridOptions && (this._gridOptions.enableCheckboxSelector || this._gridOptions.enableRowSelection)) {
8963 this._grid.setSelectedRows(rowNumbers);
8964 }
8965 // do we want to trigger an event after adding the item
8966 if (options.triggerEvent) {
8967 this.onItemAdded.next(items);
8968 }
8969 return rowNumbers;
8970 };
8971 /** @deprecated please use "deleteItem" method instead */
8972 GridService.prototype.deleteDataGridItem = function (item, shouldTriggerEvent) {
8973 if (shouldTriggerEvent === void 0) { shouldTriggerEvent = true; }
8974 this.deleteItem(item, { triggerEvent: shouldTriggerEvent });
8975 };
8976 /** @deprecated please use "deleteItems" method instead */
8977 GridService.prototype.deleteDataGridItems = function (items, shouldTriggerEvent) {
8978 if (shouldTriggerEvent === void 0) { shouldTriggerEvent = true; }
8979 this.deleteItems(items, { triggerEvent: shouldTriggerEvent });
8980 };
8981 /** @deprecated please use "deleteItemById" method instead */
8982 GridService.prototype.deleteDataGridItemById = function (itemId, shouldTriggerEvent) {
8983 if (shouldTriggerEvent === void 0) { shouldTriggerEvent = true; }
8984 this.deleteItemById(itemId, { triggerEvent: shouldTriggerEvent });
8985 };
8986 /** @deprecated please use "deleteItemByIds" method instead */
8987 GridService.prototype.deleteDataGridItemByIds = function (itemIds, shouldTriggerEvent) {
8988 if (shouldTriggerEvent === void 0) { shouldTriggerEvent = true; }
8989 this.deleteItemByIds(itemIds, { triggerEvent: shouldTriggerEvent });
8990 };
8991 /**
8992 * Delete an existing item from the datagrid (dataView)
8993 * @param item object which must contain a unique "id" property and any other suitable properties
8994 * @param options: provide the possibility to do certain actions after or during the upsert (triggerEvent)
8995 * @return item id deleted
8996 */
8997 GridService.prototype.deleteItem = function (item, options) {
8998 options = __assign({}, GridServiceDeleteOptionDefaults, options);
8999 if (!item || !item.hasOwnProperty('id')) {
9000 throw new Error("Deleting an item requires the item to include an \"id\" property");
9001 }
9002 return this.deleteItemById(item.id, options);
9003 };
9004 /**
9005 * Delete an array of existing items from the datagrid
9006 * @param item object which must contain a unique "id" property and any other suitable properties
9007 * @param options: provide the possibility to do certain actions after or during the upsert (triggerEvent)
9008 * @return item id deleted
9009 */
9010 GridService.prototype.deleteItems = function (items, options) {
9011 var _this = this;
9012 options = __assign({}, GridServiceDeleteOptionDefaults, options);
9013 // when it's not an array, we can call directly the single item delete
9014 if (!Array.isArray(items)) {
9015 this.deleteItem(items, options);
9016 return [items.id];
9017 }
9018 var itemIds = [];
9019 items.forEach(function (item) {
9020 if (item && item.id !== undefined) {
9021 itemIds.push(item.id);
9022 }
9023 _this.deleteItem(item, { triggerEvent: false });
9024 });
9025 // do we want to trigger an event after deleting the item
9026 if (options.triggerEvent) {
9027 this.onItemDeleted.next(items);
9028 }
9029 return itemIds;
9030 };
9031 /**
9032 * Delete an existing item from the datagrid (dataView) by it's id
9033 * @param itemId: item unique id
9034 * @param options: provide the possibility to do certain actions after or during the upsert (triggerEvent)
9035 * @return item id deleted
9036 */
9037 GridService.prototype.deleteItemById = function (itemId, options) {
9038 options = __assign({}, GridServiceDeleteOptionDefaults, options);
9039 if (itemId === null || itemId === undefined) {
9040 throw new Error("Cannot delete a row without a valid \"id\"");
9041 }
9042 // when user has row selection enabled, we should clear any selection to avoid confusion after a delete
9043 if (this._grid && this._gridOptions && (this._gridOptions.enableCheckboxSelector || this._gridOptions.enableRowSelection)) {
9044 this._grid.setSelectedRows([]);
9045 }
9046 // delete the item from the dataView
9047 this._dataView.deleteItem(itemId);
9048 // do we want to trigger an event after deleting the item
9049 if (options.triggerEvent) {
9050 this.onItemDeleted.next(itemId);
9051 }
9052 return itemId;
9053 };
9054 /**
9055 * Delete an array of existing items from the datagrid
9056 * @param itemIds array of item unique IDs
9057 * @param options: provide the possibility to do certain actions after or during the upsert (triggerEvent)
9058 */
9059 GridService.prototype.deleteItemByIds = function (itemIds, options) {
9060 options = __assign({}, GridServiceDeleteOptionDefaults, options);
9061 // when it's not an array, we can call directly the single item delete
9062 if (Array.isArray(itemIds)) {
9063 for (var i = 0; i < itemIds.length; i++) {
9064 if (itemIds[i] !== null) {
9065 this.deleteItemById(itemIds[i], { triggerEvent: false });
9066 }
9067 }
9068 // do we want to trigger an event after deleting the item
9069 if (options.triggerEvent) {
9070 this.onItemDeleted.next(itemIds);
9071 }
9072 return itemIds;
9073 }
9074 return [];
9075 };
9076 /** @deprecated please use "updateItem" method instead */
9077 GridService.prototype.updateDataGridItem = function (item, shouldHighlightRow, shouldTriggerEvent, shouldSelectRow) {
9078 if (shouldHighlightRow === void 0) { shouldHighlightRow = true; }
9079 if (shouldTriggerEvent === void 0) { shouldTriggerEvent = true; }
9080 if (shouldSelectRow === void 0) { shouldSelectRow = true; }
9081 return this.updateItem(item, { highlightRow: shouldHighlightRow, triggerEvent: shouldTriggerEvent, selectRow: shouldSelectRow });
9082 };
9083 /** @deprecated please use "updateItems" method instead */
9084 GridService.prototype.updateDataGridItems = function (items, shouldHighlightRow, shouldTriggerEvent, shouldSelectRow) {
9085 if (shouldHighlightRow === void 0) { shouldHighlightRow = true; }
9086 if (shouldTriggerEvent === void 0) { shouldTriggerEvent = true; }
9087 if (shouldSelectRow === void 0) { shouldSelectRow = true; }
9088 return this.updateItems(items, { highlightRow: shouldHighlightRow, triggerEvent: shouldTriggerEvent, selectRow: shouldSelectRow });
9089 };
9090 /** @deprecated please use "updateItemById" method instead */
9091 GridService.prototype.updateDataGridItemById = function (itemId, item, shouldHighlightRow, shouldTriggerEvent, shouldSelectRow) {
9092 if (shouldHighlightRow === void 0) { shouldHighlightRow = true; }
9093 if (shouldTriggerEvent === void 0) { shouldTriggerEvent = true; }
9094 if (shouldSelectRow === void 0) { shouldSelectRow = true; }
9095 return this.updateItemById(itemId, item, { highlightRow: shouldHighlightRow, triggerEvent: shouldTriggerEvent, selectRow: shouldSelectRow });
9096 };
9097 /**
9098 * Update an existing item with new properties inside the datagrid
9099 * @param item object which must contain a unique "id" property and any other suitable properties
9100 * @param options: provide the possibility to do certain actions after or during the upsert (highlightRow, selectRow, triggerEvent)
9101 * @return grid row index
9102 */
9103 GridService.prototype.updateItem = function (item, options) {
9104 options = __assign({}, GridServiceUpdateOptionDefaults, options);
9105 var itemId = (!item || !item.hasOwnProperty('id')) ? undefined : item.id;
9106 if (itemId === undefined) {
9107 throw new Error("Calling Update of an item requires the item to include an \"id\" property");
9108 }
9109 return this.updateItemById(itemId, item, options);
9110 };
9111 /**
9112 * Update an array of existing items with new properties inside the datagrid
9113 * @param item object arrays, which must contain unique "id" property and any other suitable properties
9114 * @param options: provide the possibility to do certain actions after or during the upsert (highlightRow, selectRow, triggerEvent)
9115 * @return grid row indexes
9116 */
9117 GridService.prototype.updateItems = function (items, options) {
9118 var _this = this;
9119 options = __assign({}, GridServiceUpdateOptionDefaults, options);
9120 // when it's not an array, we can call directly the single item update
9121 if (!Array.isArray(items)) {
9122 return [this.updateItem(items, options)];
9123 }
9124 var gridRowNumbers = [];
9125 items.forEach(function (item) {
9126 gridRowNumbers.push(_this.updateItem(item, { highlightRow: false, selectRow: false, triggerEvent: false }));
9127 });
9128 // only highlight at the end, all at once
9129 // we have to do this because doing highlight 1 by 1 would only re-select the last highlighted row which is wrong behavior
9130 if (options.highlightRow) {
9131 this.highlightRow(gridRowNumbers);
9132 }
9133 // select the row in the grid
9134 if (options.selectRow && this._gridOptions && (this._gridOptions.enableCheckboxSelector || this._gridOptions.enableRowSelection)) {
9135 this._grid.setSelectedRows(gridRowNumbers);
9136 }
9137 // do we want to trigger an event after updating the item
9138 if (options.triggerEvent) {
9139 this.onItemUpdated.next(items);
9140 }
9141 return gridRowNumbers;
9142 };
9143 /**
9144 * Update an existing item in the datagrid by it's id and new properties
9145 * @param itemId: item unique id
9146 * @param item object which must contain a unique "id" property and any other suitable properties
9147 * @param options: provide the possibility to do certain actions after or during the upsert (highlightRow, selectRow, triggerEvent)
9148 * @return grid row number
9149 */
9150 GridService.prototype.updateItemById = function (itemId, item, options) {
9151 options = __assign({}, GridServiceUpdateOptionDefaults, options);
9152 if (itemId === undefined) {
9153 throw new Error("Cannot update a row without a valid \"id\"");
9154 }
9155 var rowNumber = this._dataView.getRowById(itemId);
9156 if (!item || rowNumber === undefined) {
9157 throw new Error("The item to update in the grid was not found with id: " + itemId);
9158 }
9159 if (this._dataView.getIdxById(itemId) !== undefined) {
9160 // Update the item itself inside the dataView
9161 this._dataView.updateItem(itemId, item);
9162 this._grid.updateRow(rowNumber);
9163 // highlight the row we just updated, if defined
9164 if (options.highlightRow) {
9165 this.highlightRow(rowNumber);
9166 }
9167 // select the row in the grid
9168 if (options.selectRow && this._gridOptions && (this._gridOptions.enableCheckboxSelector || this._gridOptions.enableRowSelection)) {
9169 this._grid.setSelectedRows(rowNumber);
9170 }
9171 // do we want to trigger an event after updating the item
9172 if (options.triggerEvent) {
9173 this.onItemUpdated.next(item);
9174 }
9175 }
9176 return rowNumber;
9177 };
9178 /**
9179 * Insert a row into the grid if it doesn't already exist or update if it does.
9180 * @param item object which must contain a unique "id" property and any other suitable properties
9181 * @param options: provide the possibility to do certain actions after or during the upsert (highlightRow, resortGrid, selectRow, triggerEvent)
9182 */
9183 GridService.prototype.upsertItem = function (item, options) {
9184 options = __assign({}, GridServiceInsertOptionDefaults, options);
9185 var itemId = (!item || !item.hasOwnProperty('id')) ? undefined : item.id;
9186 if (itemId === undefined) {
9187 throw new Error("Calling Upsert of an item requires the item to include an \"id\" property");
9188 }
9189 return this.upsertItemById(itemId, item, options);
9190 };
9191 /**
9192 * Update an array of existing items with new properties inside the datagrid
9193 * @param item object arrays, which must contain unique "id" property and any other suitable properties
9194 * @param options: provide the possibility to do certain actions after or during the upsert (highlightRow, resortGrid, selectRow, triggerEvent)
9195 * @return row numbers in the grid
9196 */
9197 GridService.prototype.upsertItems = function (items, options) {
9198 var _this = this;
9199 options = __assign({}, GridServiceInsertOptionDefaults, options);
9200 // when it's not an array, we can call directly the single item update
9201 if (!Array.isArray(items)) {
9202 return [this.upsertItem(items, options)];
9203 }
9204 var gridRowNumbers = [];
9205 items.forEach(function (item) {
9206 gridRowNumbers.push(_this.upsertItem(item, { highlightRow: false, resortGrid: false, selectRow: false, triggerEvent: false }));
9207 });
9208 // only highlight at the end, all at once
9209 // we have to do this because doing highlight 1 by 1 would only re-select the last highlighted row which is wrong behavior
9210 if (options.highlightRow) {
9211 this.highlightRow(gridRowNumbers);
9212 }
9213 // select the row in the grid
9214 if (options.selectRow && this._gridOptions && (this._gridOptions.enableCheckboxSelector || this._gridOptions.enableRowSelection)) {
9215 this._grid.setSelectedRows(gridRowNumbers);
9216 }
9217 // do we want to trigger an event after updating the item
9218 if (options.triggerEvent) {
9219 this.onItemUpserted.next(items);
9220 }
9221 return gridRowNumbers;
9222 };
9223 /**
9224 * Update an existing item in the datagrid by it's id and new properties
9225 * @param itemId: item unique id
9226 * @param item object which must contain a unique "id" property and any other suitable properties
9227 * @param options: provide the possibility to do certain actions after or during the upsert (highlightRow, resortGrid, selectRow, triggerEvent)
9228 * @return grid row number in the grid
9229 */
9230 GridService.prototype.upsertItemById = function (itemId, item, options) {
9231 options = __assign({}, GridServiceInsertOptionDefaults, options);
9232 if (itemId === undefined) {
9233 throw new Error("Calling Upsert of an item requires the item to include a valid and unique \"id\" property");
9234 }
9235 var rowNumber;
9236 if (this._dataView.getRowById(itemId) === undefined) {
9237 rowNumber = this.addItem(item, options);
9238 }
9239 else {
9240 rowNumber = this.updateItem(item, { highlightRow: options.highlightRow, selectRow: options.selectRow, triggerEvent: options.triggerEvent });
9241 }
9242 // do we want to trigger an event after updating the item
9243 if (options.triggerEvent) {
9244 this.onItemUpserted.next(item);
9245 }
9246 return rowNumber;
9247 };
9248 GridService = __decorate([
9249 core.Injectable(),
9250 __metadata("design:paramtypes", [ExtensionService,
9251 FilterService,
9252 GridStateService,
9253 SortService])
9254 ], GridService);
9255 return GridService;
9256 }());
9257
9258 var GroupingAndColspanService = /** @class */ (function () {
9259 function GroupingAndColspanService() {
9260 this._eventHandler = new Slick.EventHandler();
9261 }
9262 Object.defineProperty(GroupingAndColspanService.prototype, "eventHandler", {
9263 /** Getter of the SlickGrid Event Handler */
9264 get: function () {
9265 return this._eventHandler;
9266 },
9267 enumerable: true,
9268 configurable: true
9269 });
9270 Object.defineProperty(GroupingAndColspanService.prototype, "_gridOptions", {
9271 /** Getter for the Grid Options pulled through the Grid Object */
9272 get: function () {
9273 return (this._grid && this._grid.getOptions) ? this._grid.getOptions() : {};
9274 },
9275 enumerable: true,
9276 configurable: true
9277 });
9278 Object.defineProperty(GroupingAndColspanService.prototype, "_columnDefinitions", {
9279 /** Getter for the Column Definitions pulled through the Grid Object */
9280 get: function () {
9281 return (this._grid && this._grid.getColumns) ? this._grid.getColumns() : [];
9282 },
9283 enumerable: true,
9284 configurable: true
9285 });
9286 GroupingAndColspanService.prototype.init = function (grid, dataView) {
9287 var _this = this;
9288 this._grid = grid;
9289 if (grid && this._gridOptions) {
9290 // When dealing with Pre-Header Grouping colspan, we need to re-create the pre-header in multiple occasions
9291 // for all these events, we have to trigger a re-create
9292 if (this._gridOptions.createPreHeaderPanel) {
9293 this._eventHandler.subscribe(grid.onSort, function (e, args) {
9294 _this.createPreHeaderRowGroupingTitle();
9295 });
9296 this._eventHandler.subscribe(grid.onColumnsResized, function (e, args) {
9297 _this.createPreHeaderRowGroupingTitle();
9298 });
9299 this._eventHandler.subscribe(dataView.onRowCountChanged, function (e, args) {
9300 _this.createPreHeaderRowGroupingTitle();
9301 });
9302 // also not sure why at this point, but it seems that I need to call the 1st create in a delayed execution
9303 // probably some kind of timing issues and delaying it until the grid is fully ready does help
9304 setTimeout(function () { return _this.createPreHeaderRowGroupingTitle(); }, 50);
9305 }
9306 }
9307 };
9308 GroupingAndColspanService.prototype.dispose = function () {
9309 // unsubscribe all SlickGrid events
9310 this._eventHandler.unsubscribeAll();
9311 };
9312 GroupingAndColspanService.prototype.createPreHeaderRowGroupingTitle = function () {
9313 var $preHeaderPanel = $(this._grid.getPreHeaderPanel())
9314 .empty()
9315 .addClass('slick-header-columns')
9316 .css('left', '-1000px')
9317 .width(this._grid.getHeadersWidth());
9318 $preHeaderPanel.parent().addClass('slick-header');
9319 var headerColumnWidthDiff = this._grid.getHeaderColumnWidthDiff();
9320 var m;
9321 var header;
9322 var lastColumnGroup = '';
9323 var widthTotal = 0;
9324 for (var i = 0; i < this._columnDefinitions.length; i++) {
9325 m = this._columnDefinitions[i];
9326 if (lastColumnGroup === m.columnGroup && i > 0) {
9327 widthTotal += m.width;
9328 header.width(widthTotal - headerColumnWidthDiff);
9329 }
9330 else {
9331 widthTotal = m.width;
9332 header = $("<div class=\"ui-state-default slick-header-column\" />")
9333 .html("<span class=\"slick-column-name\">" + (m.columnGroup || '') + "</span>")
9334 .width(m.width - headerColumnWidthDiff)
9335 .appendTo($preHeaderPanel);
9336 }
9337 lastColumnGroup = m.columnGroup;
9338 }
9339 };
9340 return GroupingAndColspanService;
9341 }());
9342
9343 // global constants, height/width are in pixels
9344 var DATAGRID_MIN_HEIGHT = 180;
9345 var DATAGRID_MIN_WIDTH = 300;
9346 var DATAGRID_BOTTOM_PADDING = 20;
9347 var DATAGRID_PAGINATION_HEIGHT = 35;
9348 var ResizerService = /** @class */ (function () {
9349 function ResizerService() {
9350 this._resizePaused = false;
9351 this.onGridAfterResize = new rxjs.Subject();
9352 this.onGridBeforeResize = new rxjs.Subject();
9353 }
9354 Object.defineProperty(ResizerService.prototype, "_gridOptions", {
9355 /** Getter for the Grid Options pulled through the Grid Object */
9356 get: function () {
9357 return (this._grid && this._grid.getOptions) ? this._grid.getOptions() : {};
9358 },
9359 enumerable: true,
9360 configurable: true
9361 });
9362 Object.defineProperty(ResizerService.prototype, "_gridUid", {
9363 get: function () {
9364 return (this._grid && this._grid.getUID) ? this._grid.getUID() : this._gridOptions && this._gridOptions.gridId;
9365 },
9366 enumerable: true,
9367 configurable: true
9368 });
9369 ResizerService.prototype.init = function (grid, fixedDimensions) {
9370 this._grid = grid;
9371 if (fixedDimensions) {
9372 this._fixedHeight = fixedDimensions.height;
9373 this._fixedWidth = fixedDimensions.width;
9374 }
9375 };
9376 /** Bind an auto resize trigger on the datagrid, if that is enable then it will resize itself to the available space
9377 * Options: we could also provide a % factor to resize on each height/width independently
9378 */
9379 ResizerService.prototype.bindAutoResizeDataGrid = function (newSizes) {
9380 var _this = this;
9381 // if we can't find the grid to resize, return without binding anything
9382 var gridDomElm = $("#" + (this._gridOptions && this._gridOptions.gridId ? this._gridOptions.gridId : 'grid1'));
9383 if (gridDomElm === undefined || gridDomElm.offset() === undefined) {
9384 return null;
9385 }
9386 // -- 1st resize the datagrid size at first load (we need this because the .on event is not triggered on first load)
9387 // -- also we add a slight delay (in ms) so that we resize after the grid render is done
9388 this.resizeGrid(10, newSizes);
9389 // -- 2nd bind a trigger on the Window DOM element, so that it happens also when resizing after first load
9390 // -- bind auto-resize to Window object only if it exist
9391 $(window).on("resize.grid." + this._gridUid, function (event) {
9392 _this.onGridBeforeResize.next(event);
9393 if (!_this._resizePaused) {
9394 _this.resizeGrid(0, newSizes);
9395 }
9396 });
9397 };
9398 /**
9399 * Calculate the datagrid new height/width from the available space, also consider that a % factor might be applied to calculation
9400 * object gridOptions
9401 */
9402 ResizerService.prototype.calculateGridNewDimensions = function (gridOptions) {
9403 var gridDomElm = $("#" + gridOptions.gridId);
9404 var autoResizeOptions = gridOptions && gridOptions.autoResize || {};
9405 var containerElm = (autoResizeOptions && autoResizeOptions.containerId) ? $("#" + autoResizeOptions.containerId) : $("#" + gridOptions.gridContainerId);
9406 if (!window || containerElm === undefined || gridDomElm === undefined) {
9407 return null;
9408 }
9409 // calculate bottom padding
9410 // if using pagination, we need to add the pagination height to this bottom padding
9411 var bottomPadding = (autoResizeOptions && autoResizeOptions.bottomPadding) ? autoResizeOptions.bottomPadding : DATAGRID_BOTTOM_PADDING;
9412 if (bottomPadding && (gridOptions.enablePagination || this._gridOptions.backendServiceApi)) {
9413 bottomPadding += DATAGRID_PAGINATION_HEIGHT;
9414 }
9415 var gridHeight = 0;
9416 var gridOffsetTop = 0;
9417 // which DOM element are we using to calculate the available size for the grid?
9418 if (autoResizeOptions.calculateAvailableSizeBy === 'container') {
9419 // uses the container's height to calculate grid height without any top offset
9420 gridHeight = containerElm.height() || 0;
9421 }
9422 else {
9423 // uses the browser's window height with its top offset to calculate grid height
9424 gridHeight = window.innerHeight || 0;
9425 var coordOffsetTop = gridDomElm.offset();
9426 gridOffsetTop = (coordOffsetTop !== undefined) ? coordOffsetTop.top : 0;
9427 }
9428 var availableHeight = gridHeight - gridOffsetTop - bottomPadding;
9429 var availableWidth = containerElm.width() || 0;
9430 var maxHeight = autoResizeOptions && autoResizeOptions.maxHeight || undefined;
9431 var minHeight = autoResizeOptions && autoResizeOptions.minHeight || DATAGRID_MIN_HEIGHT;
9432 var maxWidth = autoResizeOptions && autoResizeOptions.maxWidth || undefined;
9433 var minWidth = autoResizeOptions && autoResizeOptions.minWidth || DATAGRID_MIN_WIDTH;
9434 var newHeight = availableHeight;
9435 var newWidth = (autoResizeOptions && autoResizeOptions.sidePadding) ? availableWidth - autoResizeOptions.sidePadding : availableWidth;
9436 // optionally (when defined), make sure that grid height & width are within their thresholds
9437 if (newHeight < minHeight) {
9438 newHeight = minHeight;
9439 }
9440 if (maxHeight && newHeight > maxHeight) {
9441 newHeight = maxHeight;
9442 }
9443 if (newWidth < minWidth) {
9444 newWidth = minWidth;
9445 }
9446 if (maxWidth && newWidth > maxWidth) {
9447 newWidth = maxWidth;
9448 }
9449 // return the new dimensions unless a fixed height/width was defined
9450 return {
9451 height: this._fixedHeight || newHeight,
9452 width: this._fixedWidth || newWidth
9453 };
9454 };
9455 /**
9456 * Dispose function when element is destroyed
9457 */
9458 ResizerService.prototype.dispose = function () {
9459 $(window).off("resize.grid." + this._gridUid);
9460 };
9461 /**
9462 * For some reason this only seems to happen in Chrome and is sometime miscalculated by SlickGrid measureSrollbar() method
9463 * When that happens we will compensate and resize the Grid Viewport to avoid seeing horizontal scrollbar
9464 * Most of the time it happens, it's a tiny offset calculation of usually 3px (enough to show scrollbar)
9465 * GitHub issue reference: https://github.com/6pac/SlickGrid/issues/275
9466 */
9467 ResizerService.prototype.compensateHorizontalScroll = function (grid, gridOptions) {
9468 var gridElm = $("#" + gridOptions.gridId);
9469 var scrollbarDimensions = grid && grid.getScrollbarDimensions();
9470 var slickGridScrollbarWidth = scrollbarDimensions && scrollbarDimensions.width;
9471 var calculatedScrollbarWidth = getScrollBarWidth();
9472 // if scrollbar width is different from SlickGrid calculation to our custom calculation
9473 // then resize the grid with the missing pixels to remove scroll (usually only 3px)
9474 if (slickGridScrollbarWidth < calculatedScrollbarWidth) {
9475 gridElm.width(gridElm.width() + (calculatedScrollbarWidth - slickGridScrollbarWidth));
9476 }
9477 };
9478 /**
9479 * Return the last resize dimensions used by the service
9480 * @return last dimensions
9481 */
9482 ResizerService.prototype.getLastResizeDimensions = function () {
9483 return this._lastDimensions;
9484 };
9485 /** Provide the possibility to pause the resizer for some time, until user decides to re-enabled it later if he wish to. */
9486 ResizerService.prototype.pauseResizer = function (isResizePaused) {
9487 this._resizePaused = isResizePaused;
9488 };
9489 /** Resize the datagrid to fit the browser height & width */
9490 ResizerService.prototype.resizeGrid = function (delay, newSizes) {
9491 var _this = this;
9492 if (delay === void 0) { delay = 10; }
9493 if (!this._grid || !this._gridOptions) {
9494 throw new Error("\n Angular-Slickgrid resizer requires a valid Grid object and Grid Options defined.\n You can fix this by setting your gridOption to use \"enableAutoResize\" or create an instance of the ResizerService by calling bindAutoResizeDataGrid()");
9495 }
9496 return new Promise(function (resolve) {
9497 // because of the javascript async nature, we might want to delay the resize a little bit
9498 delay = delay || 0;
9499 if (delay > 0) {
9500 clearTimeout(_this._timer);
9501 _this._timer = setTimeout(function () { return resolve(_this.resizeGridCallback(newSizes)); }, delay);
9502 }
9503 else {
9504 resolve(_this.resizeGridCallback(newSizes));
9505 }
9506 });
9507 };
9508 ResizerService.prototype.resizeGridCallback = function (newSizes) {
9509 var lastDimensions = this.resizeGridWithDimensions(newSizes);
9510 this.onGridAfterResize.next(lastDimensions);
9511 return lastDimensions;
9512 };
9513 ResizerService.prototype.resizeGridWithDimensions = function (newSizes) {
9514 // calculate the available sizes with minimum height defined as a constant
9515 var availableDimensions = this.calculateGridNewDimensions(this._gridOptions);
9516 var gridElm = $("#" + this._gridOptions.gridId) || {};
9517 var gridContainerElm = $("#" + this._gridOptions.gridContainerId) || {};
9518 if ((newSizes || availableDimensions) && gridElm.length > 0) {
9519 // get the new sizes, if new sizes are passed (not 0), we will use them else use available space
9520 // basically if user passes 1 of the dimension, let say he passes just the height,
9521 // we will use the height as a fixed height but the width will be resized by it's available space
9522 var newHeight = (newSizes && newSizes.height) ? newSizes.height : availableDimensions.height;
9523 var newWidth = (newSizes && newSizes.width) ? newSizes.width : availableDimensions.width;
9524 // apply these new height/width to the datagrid
9525 if (!this._gridOptions.autoHeight) {
9526 gridElm.height(newHeight);
9527 gridContainerElm.height(newHeight);
9528 }
9529 gridElm.width(newWidth);
9530 gridContainerElm.width(newWidth);
9531 // resize the slickgrid canvas on all browser except some IE versions
9532 // exclude all IE below IE11
9533 // IE11 wants to be a better standard (W3C) follower (finally) they even changed their appName output to also have 'Netscape'
9534 if (new RegExp('MSIE [6-8]').exec(navigator.userAgent) === null && this._grid && this._grid.resizeCanvas) {
9535 this._grid.resizeCanvas();
9536 }
9537 // also call the grid auto-size columns so that it takes available when going bigger
9538 if (this._gridOptions && this._gridOptions.enableAutoSizeColumns && this._grid.autosizeColumns) {
9539 // make sure that the grid still exist (by looking if the Grid UID is found in the DOM tree) to avoid SlickGrid error "missing stylesheet"
9540 if (this._gridUid && $("." + this._gridUid).length > 0) {
9541 this._grid.autosizeColumns();
9542 }
9543 // compensate anytime SlickGrid measureScrollbar is incorrect
9544 this.compensateHorizontalScroll(this._grid, this._gridOptions);
9545 }
9546 // keep last resized dimensions & resolve them to the Promise
9547 this._lastDimensions = {
9548 height: newHeight,
9549 width: newWidth
9550 };
9551 if ((this._gridOptions.enablePagination || this._gridOptions.backendServiceApi)) {
9552 this._lastDimensions.heightWithPagination = newHeight + DATAGRID_PAGINATION_HEIGHT;
9553 }
9554 }
9555 return this._lastDimensions;
9556 };
9557 return ResizerService;
9558 }());
9559
9560 var AvgAggregator = /** @class */ (function () {
9561 function AvgAggregator(field) {
9562 this._count = 0;
9563 this._field = field;
9564 }
9565 AvgAggregator.prototype.init = function () {
9566 this._count = 0;
9567 this._nonNullCount = 0;
9568 this._sum = 0;
9569 };
9570 AvgAggregator.prototype.accumulate = function (item) {
9571 var val = (item && item.hasOwnProperty(this._field)) ? item[this._field] : null;
9572 this._count++;
9573 if (val != null && val !== '' && !isNaN(val)) {
9574 this._nonNullCount++;
9575 this._sum += parseFloat(val);
9576 }
9577 };
9578 AvgAggregator.prototype.storeResult = function (groupTotals) {
9579 if (!groupTotals || groupTotals.avg === undefined) {
9580 groupTotals.avg = {};
9581 }
9582 if (this._nonNullCount !== 0) {
9583 groupTotals.avg[this._field] = this._sum / this._nonNullCount;
9584 }
9585 };
9586 return AvgAggregator;
9587 }());
9588
9589 var MinAggregator = /** @class */ (function () {
9590 function MinAggregator(field) {
9591 this._field = field;
9592 }
9593 MinAggregator.prototype.init = function () {
9594 this._min = null;
9595 };
9596 MinAggregator.prototype.accumulate = function (item) {
9597 var val = (item && item.hasOwnProperty(this._field)) ? item[this._field] : null;
9598 if (val != null && val !== '' && !isNaN(val)) {
9599 if (this._min == null || val < this._min) {
9600 this._min = parseFloat(val);
9601 }
9602 }
9603 };
9604 MinAggregator.prototype.storeResult = function (groupTotals) {
9605 if (!groupTotals || groupTotals.min === undefined) {
9606 groupTotals.min = {};
9607 }
9608 groupTotals.min[this._field] = this._min;
9609 };
9610 return MinAggregator;
9611 }());
9612
9613 var MaxAggregator = /** @class */ (function () {
9614 function MaxAggregator(field) {
9615 this._field = field;
9616 }
9617 MaxAggregator.prototype.init = function () {
9618 this._max = null;
9619 };
9620 MaxAggregator.prototype.accumulate = function (item) {
9621 var val = (item && item.hasOwnProperty(this._field)) ? item[this._field] : null;
9622 if (val != null && val !== '' && !isNaN(val)) {
9623 if (this._max == null || val > this._max) {
9624 this._max = parseFloat(val);
9625 }
9626 }
9627 };
9628 MaxAggregator.prototype.storeResult = function (groupTotals) {
9629 if (!groupTotals || groupTotals.max === undefined) {
9630 groupTotals.max = {};
9631 }
9632 groupTotals.max[this._field] = this._max;
9633 };
9634 return MaxAggregator;
9635 }());
9636
9637 var SumAggregator = /** @class */ (function () {
9638 function SumAggregator(field) {
9639 this._sum = 0;
9640 this._field = field;
9641 }
9642 SumAggregator.prototype.init = function () {
9643 this._sum = 0;
9644 };
9645 SumAggregator.prototype.accumulate = function (item) {
9646 var val = (item && item.hasOwnProperty(this._field)) ? item[this._field] : null;
9647 if (val != null && val !== '' && !isNaN(val)) {
9648 this._sum += parseFloat(val);
9649 }
9650 };
9651 SumAggregator.prototype.storeResult = function (groupTotals) {
9652 if (!groupTotals || groupTotals.sum === undefined) {
9653 groupTotals.sum = {};
9654 }
9655 groupTotals.sum[this._field] = this._sum;
9656 };
9657 return SumAggregator;
9658 }());
9659
9660 /** Provides a list of different Aggregators for the Group Formatter */
9661 var Aggregators = {
9662 Avg: AvgAggregator,
9663 Min: MinAggregator,
9664 Max: MaxAggregator,
9665 Sum: SumAggregator
9666 };
9667
9668 /*
9669 * An example of a 'detached' editor.
9670 * KeyDown events are also handled to provide handling for Tab, Shift-Tab, Esc and Ctrl-Enter.
9671 */
9672 var AutoCompleteEditor = /** @class */ (function () {
9673 function AutoCompleteEditor(args) {
9674 this.args = args;
9675 this.init();
9676 }
9677 Object.defineProperty(AutoCompleteEditor.prototype, "collection", {
9678 /** Get the Collection */
9679 get: function () {
9680 return this.columnDef && this.columnDef && this.columnDef.internalColumnEditor.collection || [];
9681 },
9682 enumerable: true,
9683 configurable: true
9684 });
9685 Object.defineProperty(AutoCompleteEditor.prototype, "columnDef", {
9686 /** Get Column Definition object */
9687 get: function () {
9688 return this.args && this.args.column || {};
9689 },
9690 enumerable: true,
9691 configurable: true
9692 });
9693 Object.defineProperty(AutoCompleteEditor.prototype, "columnEditor", {
9694 /** Get Column Editor object */
9695 get: function () {
9696 return this.columnDef && this.columnDef.internalColumnEditor || {};
9697 },
9698 enumerable: true,
9699 configurable: true
9700 });
9701 Object.defineProperty(AutoCompleteEditor.prototype, "customStructure", {
9702 /** Getter for the Custom Structure if exist */
9703 get: function () {
9704 return this.columnDef && this.columnDef.internalColumnEditor && this.columnDef.internalColumnEditor.customStructure;
9705 },
9706 enumerable: true,
9707 configurable: true
9708 });
9709 Object.defineProperty(AutoCompleteEditor.prototype, "hasAutoCommitEdit", {
9710 get: function () {
9711 return this.args.grid.getOptions().autoCommitEdit;
9712 },
9713 enumerable: true,
9714 configurable: true
9715 });
9716 Object.defineProperty(AutoCompleteEditor.prototype, "validator", {
9717 /** Get the Validator function, can be passed in Editor property or Column Definition */
9718 get: function () {
9719 return this.columnEditor.validator || this.columnDef.validator;
9720 },
9721 enumerable: true,
9722 configurable: true
9723 });
9724 Object.defineProperty(AutoCompleteEditor.prototype, "editorOptions", {
9725 get: function () {
9726 return this.columnEditor && this.columnEditor.editorOptions || {};
9727 },
9728 enumerable: true,
9729 configurable: true
9730 });
9731 AutoCompleteEditor.prototype.init = function () {
9732 var _this = this;
9733 var columnId = this.columnDef && this.columnDef.id;
9734 var placeholder = this.columnEditor && this.columnEditor.placeholder || '';
9735 var title = this.columnEditor && this.columnEditor.title || '';
9736 this.labelName = this.customStructure && this.customStructure.label || 'label';
9737 this.valueName = this.customStructure && this.customStructure.value || 'value';
9738 this.$input = $("<input type=\"text\" role=\"presentation\" autocomplete=\"off\" class=\"autocomplete editor-text editor-" + columnId + "\" placeholder=\"" + placeholder + "\" title=\"" + title + "\" />")
9739 .appendTo(this.args.container)
9740 .on('keydown.nav', function (event) {
9741 _this._lastInputEvent = event;
9742 if (event.keyCode === exports.KeyCode.LEFT || event.keyCode === exports.KeyCode.RIGHT) {
9743 event.stopImmediatePropagation();
9744 }
9745 });
9746 // user might pass his own autocomplete options
9747 var autoCompleteOptions = this.columnDef && this.columnDef.internalColumnEditor && this.columnDef.internalColumnEditor.editorOptions;
9748 // user might provide his own custom structure
9749 // jQuery UI autocomplete requires a label/value pair, so we must remap them when user provide different ones
9750 var collection = this.collection;
9751 if (Array.isArray(collection) && this.customStructure) {
9752 collection = collection.map(function (item) {
9753 return { label: item[_this.labelName], value: item[_this.valueName] };
9754 });
9755 }
9756 // when user passes it's own autocomplete options
9757 // we still need to provide our own "select" callback implementation
9758 if (autoCompleteOptions) {
9759 autoCompleteOptions.select = function (event, ui) { return _this.onClose(event, ui); };
9760 this.$input.autocomplete(autoCompleteOptions);
9761 }
9762 else {
9763 this.$input.autocomplete({
9764 source: collection,
9765 minLength: 0,
9766 select: function (event, ui) { return _this.onClose(event, ui); },
9767 });
9768 }
9769 setTimeout(function () {
9770 _this.$input.focus().select();
9771 }, 50);
9772 };
9773 AutoCompleteEditor.prototype.destroy = function () {
9774 this.$input.off('keydown.nav').remove();
9775 };
9776 AutoCompleteEditor.prototype.focus = function () {
9777 this.$input.focus();
9778 };
9779 AutoCompleteEditor.prototype.getValue = function () {
9780 return this.$input.val();
9781 };
9782 AutoCompleteEditor.prototype.setValue = function (val) {
9783 this.$input.val(val);
9784 };
9785 AutoCompleteEditor.prototype.loadValue = function (item) {
9786 var fieldName = this.columnDef && this.columnDef.field;
9787 // when it's a complex object, then pull the object name only, e.g.: "user.firstName" => "user"
9788 var fieldNameFromComplexObject = fieldName.indexOf('.') ? fieldName.substring(0, fieldName.indexOf('.')) : '';
9789 if (item && this.columnDef && (item.hasOwnProperty(fieldName) || item.hasOwnProperty(fieldNameFromComplexObject))) {
9790 var data = item[fieldNameFromComplexObject || fieldName];
9791 this._currentValue = data;
9792 this._defaultTextValue = typeof data === 'string' ? data : data[this.labelName];
9793 this.$input.val(this._defaultTextValue);
9794 this.$input[0].defaultValue = this._defaultTextValue;
9795 this.$input.select();
9796 }
9797 };
9798 AutoCompleteEditor.prototype.save = function () {
9799 var validation = this.validate();
9800 if (validation && validation.valid) {
9801 if (this.hasAutoCommitEdit) {
9802 this.args.grid.getEditorLock().commitCurrentEdit();
9803 }
9804 else {
9805 this.args.commitChanges();
9806 }
9807 }
9808 };
9809 AutoCompleteEditor.prototype.serializeValue = function () {
9810 var _a;
9811 // if user provided a custom structure, we will serialize the value returned from the object with custom structure
9812 var minLength = typeof this.editorOptions.minLength !== 'undefined' ? this.editorOptions.minLength : 3;
9813 if (this.editorOptions.forceUserInput) {
9814 this._currentValue = this.$input.val().length >= minLength ? this.$input.val() : this._currentValue;
9815 }
9816 if (this.customStructure && this._currentValue.hasOwnProperty(this.labelName)) {
9817 return this._currentValue[this.labelName];
9818 }
9819 else if (this._currentValue.label) {
9820 if (this.columnDef.type === exports.FieldType.object) {
9821 return _a = {},
9822 _a[this.labelName] = this._currentValue.label,
9823 _a[this.valueName] = this._currentValue.value,
9824 _a;
9825 }
9826 return this._currentValue.label;
9827 }
9828 return this._currentValue;
9829 };
9830 AutoCompleteEditor.prototype.applyValue = function (item, state) {
9831 var _this = this;
9832 var newValue = state;
9833 var fieldName = this.columnDef && this.columnDef.field;
9834 // if we have a collection defined, we will try to find the string within the collection and return it
9835 if (Array.isArray(this.collection) && this.collection.length > 0) {
9836 newValue = findOrDefault(this.collection, function (collectionItem) {
9837 if (collectionItem && collectionItem.hasOwnProperty(_this.labelName)) {
9838 return collectionItem[_this.labelName].toString() === state;
9839 }
9840 return collectionItem.toString() === state;
9841 });
9842 }
9843 // when it's a complex object, then pull the object name only, e.g.: "user.firstName" => "user"
9844 var fieldNameFromComplexObject = fieldName.indexOf('.') ? fieldName.substring(0, fieldName.indexOf('.')) : '';
9845 var validation = this.validate(newValue);
9846 item[fieldNameFromComplexObject || fieldName] = (validation && validation.valid) ? newValue : '';
9847 };
9848 AutoCompleteEditor.prototype.isValueChanged = function () {
9849 var lastEvent = this._lastInputEvent && this._lastInputEvent.keyCode;
9850 if (this.columnEditor && this.columnEditor.alwaysSaveOnEnterKey && lastEvent === exports.KeyCode.ENTER) {
9851 return true;
9852 }
9853 return (!(this.$input.val() === '' && this._defaultTextValue === null)) && (this.$input.val() !== this._defaultTextValue);
9854 };
9855 AutoCompleteEditor.prototype.validate = function (inputValue) {
9856 var isRequired = this.columnEditor.required;
9857 var elmValue = (inputValue !== undefined) ? inputValue : this.$input && this.$input.val && this.$input.val();
9858 var errorMsg = this.columnEditor.errorMessage;
9859 if (this.validator) {
9860 return this.validator(elmValue, this.args);
9861 }
9862 // by default the editor is almost always valid (except when it's required but not provided)
9863 if (isRequired && elmValue === '') {
9864 return {
9865 valid: false,
9866 msg: errorMsg || Constants.VALIDATION_REQUIRED_FIELD
9867 };
9868 }
9869 return {
9870 valid: true,
9871 msg: null
9872 };
9873 };
9874 //
9875 // private functions
9876 // ------------------
9877 AutoCompleteEditor.prototype.onClose = function (event, ui) {
9878 if (ui && ui.item) {
9879 this._currentValue = ui && ui.item;
9880 var itemLabel = typeof ui.item === 'string' ? ui.item : ui.item.label;
9881 this.setValue(itemLabel);
9882 if (this.args.grid.getOptions().autoCommitEdit) {
9883 // do not use args.commitChanges() as this sets the focus to the next row.
9884 var validation = this.validate();
9885 if (validation && validation.valid) {
9886 this.args.grid.getEditorLock().commitCurrentEdit();
9887 }
9888 }
9889 }
9890 return false;
9891 };
9892 return AutoCompleteEditor;
9893 }());
9894
9895 /*
9896 * An example of a 'detached' editor.
9897 * KeyDown events are also handled to provide handling for Tab, Shift-Tab, Esc and Ctrl-Enter.
9898 */
9899 var CheckboxEditor = /** @class */ (function () {
9900 function CheckboxEditor(args) {
9901 this.args = args;
9902 this.init();
9903 }
9904 Object.defineProperty(CheckboxEditor.prototype, "columnDef", {
9905 /** Get Column Definition object */
9906 get: function () {
9907 return this.args && this.args.column || {};
9908 },
9909 enumerable: true,
9910 configurable: true
9911 });
9912 Object.defineProperty(CheckboxEditor.prototype, "columnEditor", {
9913 /** Get Column Editor object */
9914 get: function () {
9915 return this.columnDef && this.columnDef.internalColumnEditor && this.columnDef.internalColumnEditor || {};
9916 },
9917 enumerable: true,
9918 configurable: true
9919 });
9920 Object.defineProperty(CheckboxEditor.prototype, "validator", {
9921 /** Get the Validator function, can be passed in Editor property or Column Definition */
9922 get: function () {
9923 return this.columnEditor.validator || this.columnDef.validator;
9924 },
9925 enumerable: true,
9926 configurable: true
9927 });
9928 CheckboxEditor.prototype.init = function () {
9929 var _this = this;
9930 var fieldId = this.columnDef && this.columnDef.id;
9931 var title = this.columnEditor && this.columnEditor.title || '';
9932 this.$input = $("<input type=\"checkbox\" value=\"true\" class=\"editor-checkbox editor-" + fieldId + "\" title=\"" + title + "\" />");
9933 this.$input.appendTo(this.args.container);
9934 this.$input.focus();
9935 // make the checkbox editor act like a regular checkbox that commit the value on click
9936 if (this.args.grid.getOptions().autoCommitEdit) {
9937 this.$input.click(function () { return _this.args.grid.getEditorLock().commitCurrentEdit(); });
9938 }
9939 };
9940 CheckboxEditor.prototype.destroy = function () {
9941 this.$input.remove();
9942 };
9943 CheckboxEditor.prototype.focus = function () {
9944 this.$input.focus();
9945 };
9946 CheckboxEditor.prototype.hide = function () {
9947 this.$input.hide();
9948 };
9949 CheckboxEditor.prototype.show = function () {
9950 this.$input.show();
9951 };
9952 CheckboxEditor.prototype.loadValue = function (item) {
9953 var fieldName = this.columnDef && this.columnDef.field;
9954 // when it's a complex object, then pull the object name only, e.g.: "user.firstName" => "user"
9955 var fieldNameFromComplexObject = fieldName.indexOf('.') ? fieldName.substring(0, fieldName.indexOf('.')) : '';
9956 if (item && this.columnDef && (item.hasOwnProperty(fieldName) || item.hasOwnProperty(fieldNameFromComplexObject))) {
9957 this.defaultValue = !!item[fieldNameFromComplexObject || fieldName];
9958 if (this.defaultValue) {
9959 this.$input.prop('checked', true);
9960 }
9961 else {
9962 this.$input.prop('checked', false);
9963 }
9964 }
9965 };
9966 CheckboxEditor.prototype.preClick = function () {
9967 this.$input.prop('checked', !this.$input.prop('checked'));
9968 };
9969 CheckboxEditor.prototype.serializeValue = function () {
9970 return this.$input.prop('checked');
9971 };
9972 CheckboxEditor.prototype.applyValue = function (item, state) {
9973 var fieldName = this.columnDef && this.columnDef.field;
9974 // when it's a complex object, then pull the object name only, e.g.: "user.firstName" => "user"
9975 var fieldNameFromComplexObject = fieldName.indexOf('.') ? fieldName.substring(0, fieldName.indexOf('.')) : '';
9976 var validation = this.validate(state);
9977 item[fieldNameFromComplexObject || fieldName] = (validation && validation.valid) ? state : '';
9978 };
9979 CheckboxEditor.prototype.isValueChanged = function () {
9980 return (this.serializeValue() !== this.defaultValue);
9981 };
9982 CheckboxEditor.prototype.validate = function (inputValue) {
9983 var isRequired = this.columnEditor.required;
9984 var isChecked = (inputValue !== undefined) ? inputValue : this.$input && this.$input.prop && this.$input.prop('checked');
9985 var errorMsg = this.columnEditor.errorMessage;
9986 if (this.validator) {
9987 return this.validator(isChecked, this.args);
9988 }
9989 // by default the editor is almost always valid (except when it's required but not provided)
9990 if (isRequired && !isChecked) {
9991 return {
9992 valid: false,
9993 msg: errorMsg || Constants.VALIDATION_REQUIRED_FIELD
9994 };
9995 }
9996 return {
9997 valid: true,
9998 msg: null
9999 };
10000 };
10001 return CheckboxEditor;
10002 }());
10003
10004 var moment$a = moment_; // patch to fix rollup "moment has no default export" issue, document here https://github.com/rollup/rollup/issues/670
10005 require('flatpickr');
10006 /*
10007 * An example of a date picker editor using Flatpickr
10008 * https://chmln.github.io/flatpickr
10009 */
10010 var DateEditor = /** @class */ (function () {
10011 function DateEditor(args) {
10012 this.args = args;
10013 this.init();
10014 }
10015 Object.defineProperty(DateEditor.prototype, "columnDef", {
10016 /** Get Column Definition object */
10017 get: function () {
10018 return this.args && this.args.column || {};
10019 },
10020 enumerable: true,
10021 configurable: true
10022 });
10023 Object.defineProperty(DateEditor.prototype, "columnEditor", {
10024 /** Get Column Editor object */
10025 get: function () {
10026 return this.columnDef && this.columnDef.internalColumnEditor && this.columnDef.internalColumnEditor || {};
10027 },
10028 enumerable: true,
10029 configurable: true
10030 });
10031 Object.defineProperty(DateEditor.prototype, "editorOptions", {
10032 /** Get Flatpickr options passed to the editor by the user */
10033 get: function () {
10034 return this.columnEditor.editorOptions || {};
10035 },
10036 enumerable: true,
10037 configurable: true
10038 });
10039 Object.defineProperty(DateEditor.prototype, "validator", {
10040 /** Get the Validator function, can be passed in Editor property or Column Definition */
10041 get: function () {
10042 return this.columnEditor.validator || this.columnDef.validator;
10043 },
10044 enumerable: true,
10045 configurable: true
10046 });
10047 DateEditor.prototype.init = function () {
10048 var _this = this;
10049 if (this.args && this.args.column) {
10050 var columnId = this.columnDef && this.columnDef.id;
10051 var placeholder = this.columnEditor && this.columnEditor.placeholder || '';
10052 var title = this.columnEditor && this.columnEditor.title || '';
10053 var gridOptions = this.args.grid.getOptions();
10054 this.defaultDate = (this.args.item) ? this.args.item[this.args.column.field] : null;
10055 var inputFormat = mapFlatpickrDateFormatWithFieldType(this.columnDef.type || exports.FieldType.dateIso);
10056 var outputFormat = mapFlatpickrDateFormatWithFieldType(this.columnDef.outputType || exports.FieldType.dateUtc);
10057 var currentLocale = this.getCurrentLocale(this.columnDef, gridOptions);
10058 if (currentLocale.length > 2) {
10059 currentLocale = currentLocale.substring(0, 2);
10060 }
10061 var pickerOptions = {
10062 defaultDate: this.defaultDate,
10063 altInput: true,
10064 altInputClass: 'flatpickr-alt-input',
10065 altFormat: inputFormat,
10066 dateFormat: outputFormat,
10067 closeOnSelect: false,
10068 locale: (currentLocale !== 'en') ? this.loadFlatpickrLocale(currentLocale) : 'en',
10069 onChange: function (selectedDates, dateStr, instance) {
10070 _this.save();
10071 },
10072 };
10073 // merge options with optional user's custom options
10074 var pickerMergedOptions = __assign({}, pickerOptions, this.editorOptions);
10075 var inputCssClasses = ".editor-text.editor-" + columnId + ".flatpickr";
10076 this.$input = $("<input type=\"text\" data-defaultDate=\"" + this.defaultDate + "\" class=\"" + inputCssClasses.replace(/\./g, ' ') + "\" placeholder=\"" + placeholder + "\" title=\"" + title + "\" />");
10077 this.$input.appendTo(this.args.container);
10078 this.flatInstance = (this.$input[0] && typeof this.$input[0].flatpickr === 'function') ? this.$input[0].flatpickr(pickerMergedOptions) : null;
10079 // when we're using an alternate input to display data, we'll consider this input as the one to do the focus later on
10080 // else just use the top one
10081 this._$inputWithData = (pickerMergedOptions && pickerMergedOptions.altInput) ? $(inputCssClasses + ".flatpickr-alt-input") : this.$input;
10082 }
10083 };
10084 DateEditor.prototype.getCurrentLocale = function (columnDef, gridOptions) {
10085 var options = gridOptions || columnDef.params || {};
10086 if (options.i18n && options.i18n instanceof core$1.TranslateService) {
10087 return options.i18n.currentLang;
10088 }
10089 return 'en';
10090 };
10091 DateEditor.prototype.loadFlatpickrLocale = function (locale) {
10092 // change locale if needed, Flatpickr reference: https://chmln.github.io/flatpickr/localization/
10093 var gridOptions = this.args && this.args.grid && this.args.grid.getOptions();
10094 if (gridOptions && gridOptions.params && gridOptions.params.flapickrLocale) {
10095 return gridOptions.params.flapickrLocale;
10096 }
10097 else if (locale !== 'en') {
10098 var localeDefault = require("flatpickr/dist/l10n/" + locale + ".js").default;
10099 return (localeDefault && localeDefault[locale]) ? localeDefault[locale] : 'en';
10100 }
10101 return 'en';
10102 };
10103 DateEditor.prototype.destroy = function () {
10104 this.hide();
10105 this.$input.remove();
10106 if (this._$inputWithData && typeof this._$inputWithData.remove === 'function') {
10107 this._$inputWithData.remove();
10108 }
10109 };
10110 DateEditor.prototype.show = function () {
10111 if (this.flatInstance && typeof this.flatInstance.open === 'function') {
10112 this.flatInstance.open();
10113 }
10114 };
10115 DateEditor.prototype.hide = function () {
10116 if (this.flatInstance && typeof this.flatInstance.close === 'function') {
10117 this.flatInstance.close();
10118 }
10119 };
10120 DateEditor.prototype.focus = function () {
10121 if (this._$inputWithData && this._$inputWithData.focus) {
10122 this._$inputWithData.focus().select();
10123 }
10124 else if (this.$input && this.$input.focus) {
10125 this.$input.focus().select();
10126 }
10127 };
10128 DateEditor.prototype.save = function () {
10129 // autocommit will not focus the next editor
10130 var validation = this.validate();
10131 if (validation && validation.valid) {
10132 if (this.args.grid.getOptions().autoCommitEdit) {
10133 this.args.grid.getEditorLock().commitCurrentEdit();
10134 }
10135 else {
10136 this.args.commitChanges();
10137 }
10138 }
10139 };
10140 DateEditor.prototype.getColumnEditor = function () {
10141 return this.args && this.args.column && this.args.column.internalColumnEditor && this.args.column.internalColumnEditor;
10142 };
10143 DateEditor.prototype.loadValue = function (item) {
10144 var fieldName = this.columnDef && this.columnDef.field;
10145 // when it's a complex object, then pull the object name only, e.g.: "user.firstName" => "user"
10146 var fieldNameFromComplexObject = fieldName.indexOf('.') ? fieldName.substring(0, fieldName.indexOf('.')) : '';
10147 if (item && this.columnDef && (item.hasOwnProperty(fieldName) || item.hasOwnProperty(fieldNameFromComplexObject))) {
10148 this.defaultDate = item[fieldNameFromComplexObject || fieldName];
10149 this.flatInstance.setDate(item[this.args.column.field]);
10150 this.focus();
10151 }
10152 };
10153 DateEditor.prototype.serializeValue = function () {
10154 var domValue = this.$input.val();
10155 if (!domValue) {
10156 return '';
10157 }
10158 var outputFormat = mapMomentDateFormatWithFieldType(this.args.column.type || exports.FieldType.dateIso);
10159 var value = moment$a(domValue).format(outputFormat);
10160 return value;
10161 };
10162 DateEditor.prototype.applyValue = function (item, state) {
10163 var fieldName = this.columnDef && this.columnDef.field;
10164 var outputFormat = mapMomentDateFormatWithFieldType(this.args.column.type || exports.FieldType.dateIso);
10165 // when it's a complex object, then pull the object name only, e.g.: "user.firstName" => "user"
10166 var fieldNameFromComplexObject = fieldName.indexOf('.') ? fieldName.substring(0, fieldName.indexOf('.')) : '';
10167 var newValue = state ? moment$a(state, outputFormat).toDate() : '';
10168 var validation = this.validate(newValue);
10169 item[fieldNameFromComplexObject || fieldName] = (validation && validation.valid) ? newValue : '';
10170 };
10171 DateEditor.prototype.isValueChanged = function () {
10172 return (!(this.$input.val() === '' && this.defaultDate == null)) && (this.$input.val() !== this.defaultDate);
10173 };
10174 DateEditor.prototype.validate = function (inputValue) {
10175 var isRequired = this.columnEditor.required;
10176 var elmValue = (inputValue !== undefined) ? inputValue : this.$input && this.$input.val && this.$input.val();
10177 var errorMsg = this.columnEditor.errorMessage;
10178 if (this.validator) {
10179 return this.validator(elmValue, this.args);
10180 }
10181 // by default the editor is almost always valid (except when it's required but not provided)
10182 if (isRequired && elmValue === '') {
10183 return {
10184 valid: false,
10185 msg: errorMsg || Constants.VALIDATION_REQUIRED_FIELD
10186 };
10187 }
10188 return {
10189 valid: true,
10190 msg: null
10191 };
10192 };
10193 return DateEditor;
10194 }());
10195
10196 var defaultDecimalPlaces = 0;
10197 /*
10198 * An example of a 'detached' editor.
10199 * KeyDown events are also handled to provide handling for Tab, Shift-Tab, Esc and Ctrl-Enter.
10200 */
10201 var FloatEditor = /** @class */ (function () {
10202 function FloatEditor(args) {
10203 this.args = args;
10204 this.init();
10205 }
10206 Object.defineProperty(FloatEditor.prototype, "columnDef", {
10207 /** Get Column Definition object */
10208 get: function () {
10209 return this.args && this.args.column || {};
10210 },
10211 enumerable: true,
10212 configurable: true
10213 });
10214 Object.defineProperty(FloatEditor.prototype, "columnEditor", {
10215 /** Get Column Editor object */
10216 get: function () {
10217 return this.columnDef && this.columnDef.internalColumnEditor || {};
10218 },
10219 enumerable: true,
10220 configurable: true
10221 });
10222 Object.defineProperty(FloatEditor.prototype, "hasAutoCommitEdit", {
10223 get: function () {
10224 return this.args && this.args.grid && this.args.grid.getOptions && this.args.grid.getOptions().autoCommitEdit;
10225 },
10226 enumerable: true,
10227 configurable: true
10228 });
10229 Object.defineProperty(FloatEditor.prototype, "validator", {
10230 /** Get the Validator function, can be passed in Editor property or Column Definition */
10231 get: function () {
10232 return this.columnEditor.validator || this.columnDef.validator;
10233 },
10234 enumerable: true,
10235 configurable: true
10236 });
10237 FloatEditor.prototype.init = function () {
10238 var _this = this;
10239 var columnId = this.columnDef && this.columnDef.id;
10240 var placeholder = this.columnEditor && this.columnEditor.placeholder || '';
10241 var title = this.columnEditor && this.columnEditor.title || '';
10242 this.$input = $("<input type=\"number\" role=\"presentation\" autocomplete=\"off\" class=\"editor-text editor-" + columnId + "\" placeholder=\"" + placeholder + "\" title=\"" + title + "\" step=\"" + this.getInputDecimalSteps() + "\" />")
10243 .appendTo(this.args.container)
10244 .on('keydown.nav', function (event) {
10245 _this._lastInputEvent = event;
10246 if (event.keyCode === exports.KeyCode.LEFT || event.keyCode === exports.KeyCode.RIGHT) {
10247 event.stopImmediatePropagation();
10248 }
10249 });
10250 // the lib does not get the focus out event for some reason
10251 // so register it here
10252 if (this.hasAutoCommitEdit) {
10253 this.$input.on('focusout', function () { return _this.save(); });
10254 }
10255 setTimeout(function () {
10256 _this.$input.focus().select();
10257 }, 50);
10258 };
10259 FloatEditor.prototype.destroy = function () {
10260 this.$input.off('keydown.nav focusout').remove();
10261 };
10262 FloatEditor.prototype.focus = function () {
10263 this.$input.focus();
10264 };
10265 FloatEditor.prototype.getColumnEditor = function () {
10266 return this.args && this.args.column && this.args.column.internalColumnEditor;
10267 };
10268 FloatEditor.prototype.getDecimalPlaces = function () {
10269 // returns the number of fixed decimal places or null
10270 var rtn = (this.columnEditor.params && this.columnEditor.params.hasOwnProperty('decimalPlaces')) ? this.columnEditor.params.decimalPlaces : undefined;
10271 if (rtn === undefined) {
10272 rtn = defaultDecimalPlaces;
10273 }
10274 return (!rtn && rtn !== 0 ? null : rtn);
10275 };
10276 FloatEditor.prototype.getInputDecimalSteps = function () {
10277 var decimals = this.getDecimalPlaces();
10278 var zeroString = '';
10279 for (var i = 1; i < decimals; i++) {
10280 zeroString += '0';
10281 }
10282 if (decimals > 0) {
10283 return "0." + zeroString + "1";
10284 }
10285 return '1';
10286 };
10287 FloatEditor.prototype.loadValue = function (item) {
10288 var fieldName = this.columnDef && this.columnDef.field;
10289 // when it's a complex object, then pull the object name only, e.g.: "user.firstName" => "user"
10290 var fieldNameFromComplexObject = fieldName.indexOf('.') ? fieldName.substring(0, fieldName.indexOf('.')) : '';
10291 if (item && this.columnDef && (item.hasOwnProperty(fieldName) || item.hasOwnProperty(fieldNameFromComplexObject))) {
10292 this.defaultValue = item[fieldNameFromComplexObject || fieldName];
10293 var decPlaces = this.getDecimalPlaces();
10294 if (decPlaces !== null
10295 && (this.defaultValue || this.defaultValue === 0)
10296 && this.defaultValue.toFixed) {
10297 this.defaultValue = this.defaultValue.toFixed(decPlaces);
10298 }
10299 this.$input.val(this.defaultValue);
10300 this.$input[0].defaultValue = this.defaultValue;
10301 this.$input.select();
10302 }
10303 };
10304 FloatEditor.prototype.serializeValue = function () {
10305 var elmValue = this.$input.val();
10306 if (elmValue === '' || isNaN(elmValue)) {
10307 return elmValue;
10308 }
10309 var rtn = parseFloat(elmValue);
10310 var decPlaces = this.getDecimalPlaces();
10311 if (decPlaces !== null
10312 && (rtn || rtn === 0)
10313 && rtn.toFixed) {
10314 rtn = parseFloat(rtn.toFixed(decPlaces));
10315 }
10316 return rtn;
10317 };
10318 FloatEditor.prototype.applyValue = function (item, state) {
10319 var fieldName = this.columnDef && this.columnDef.field;
10320 // when it's a complex object, then pull the object name only, e.g.: "user.firstName" => "user"
10321 var fieldNameFromComplexObject = fieldName.indexOf('.') ? fieldName.substring(0, fieldName.indexOf('.')) : '';
10322 var validation = this.validate(state);
10323 item[fieldNameFromComplexObject || fieldName] = (validation && validation.valid) ? state : '';
10324 };
10325 FloatEditor.prototype.isValueChanged = function () {
10326 var elmValue = this.$input.val();
10327 var lastEvent = this._lastInputEvent && this._lastInputEvent.keyCode;
10328 if (this.columnEditor && this.columnEditor.alwaysSaveOnEnterKey && lastEvent === exports.KeyCode.ENTER) {
10329 return true;
10330 }
10331 return (!(elmValue === '' && this.defaultValue === null)) && (elmValue !== this.defaultValue);
10332 };
10333 FloatEditor.prototype.save = function () {
10334 var validation = this.validate();
10335 if (validation && validation.valid) {
10336 if (this.hasAutoCommitEdit) {
10337 this.args.grid.getEditorLock().commitCurrentEdit();
10338 }
10339 else {
10340 this.args.commitChanges();
10341 }
10342 }
10343 };
10344 FloatEditor.prototype.validate = function (inputValue) {
10345 var elmValue = (inputValue !== undefined) ? inputValue : this.$input && this.$input.val && this.$input.val();
10346 var floatNumber = !isNaN(elmValue) ? parseFloat(elmValue) : null;
10347 var decPlaces = this.getDecimalPlaces();
10348 var isRequired = this.columnEditor.required;
10349 var minValue = this.columnEditor.minValue;
10350 var maxValue = this.columnEditor.maxValue;
10351 var errorMsg = this.columnEditor.errorMessage;
10352 var mapValidation = {
10353 '{{minValue}}': minValue,
10354 '{{maxValue}}': maxValue,
10355 '{{minDecimal}}': 0,
10356 '{{maxDecimal}}': decPlaces
10357 };
10358 var isValid = true;
10359 var outputMsg = '';
10360 if (this.validator) {
10361 return this.validator(elmValue, this.args);
10362 }
10363 else if (isRequired && elmValue === '') {
10364 isValid = false;
10365 outputMsg = errorMsg || Constants.VALIDATION_REQUIRED_FIELD;
10366 }
10367 else if (isNaN(elmValue) || (decPlaces === 0 && !/^[-+]?(\d+(\.)?(\d)*)$/.test(elmValue))) {
10368 // when decimal value is 0 (which is the default), we accept 0 or more decimal values
10369 isValid = false;
10370 outputMsg = errorMsg || Constants.VALIDATION_EDITOR_VALID_NUMBER;
10371 }
10372 else if (minValue !== undefined && maxValue !== undefined && floatNumber !== null && (floatNumber < minValue || floatNumber > maxValue)) {
10373 // MIN & MAX Values provided
10374 // when decimal value is bigger than 0, we only accept the decimal values as that value set
10375 // for example if we set decimalPlaces to 2, we will only accept numbers between 0 and 2 decimals
10376 isValid = false;
10377 outputMsg = errorMsg || Constants.VALIDATION_EDITOR_NUMBER_BETWEEN.replace(/{{minValue}}|{{maxValue}}/gi, function (matched) { return mapValidation[matched]; });
10378 }
10379 else if (minValue !== undefined && floatNumber !== null && floatNumber <= minValue) {
10380 // MIN VALUE ONLY
10381 // when decimal value is bigger than 0, we only accept the decimal values as that value set
10382 // for example if we set decimalPlaces to 2, we will only accept numbers between 0 and 2 decimals
10383 isValid = false;
10384 outputMsg = errorMsg || Constants.VALIDATION_EDITOR_NUMBER_MIN.replace(/{{minValue}}/gi, function (matched) { return mapValidation[matched]; });
10385 }
10386 else if (maxValue !== undefined && floatNumber !== null && floatNumber >= maxValue) {
10387 // MAX VALUE ONLY
10388 // when decimal value is bigger than 0, we only accept the decimal values as that value set
10389 // for example if we set decimalPlaces to 2, we will only accept numbers between 0 and 2 decimals
10390 isValid = false;
10391 outputMsg = errorMsg || Constants.VALIDATION_EDITOR_NUMBER_MAX.replace(/{{maxValue}}/gi, function (matched) { return mapValidation[matched]; });
10392 }
10393 else if ((decPlaces > 0 && !new RegExp("^(\\d*(\\.)?(\\d){0," + decPlaces + "})$").test(elmValue))) {
10394 // when decimal value is bigger than 0, we only accept the decimal values as that value set
10395 // for example if we set decimalPlaces to 2, we will only accept numbers between 0 and 2 decimals
10396 isValid = false;
10397 outputMsg = errorMsg || Constants.VALIDATION_EDITOR_DECIMAL_BETWEEN.replace(/{{minDecimal}}|{{maxDecimal}}/gi, function (matched) { return mapValidation[matched]; });
10398 }
10399 return {
10400 valid: isValid,
10401 msg: outputMsg
10402 };
10403 };
10404 return FloatEditor;
10405 }());
10406
10407 /*
10408 * An example of a 'detached' editor.
10409 * KeyDown events are also handled to provide handling for Tab, Shift-Tab, Esc and Ctrl-Enter.
10410 */
10411 var IntegerEditor = /** @class */ (function () {
10412 function IntegerEditor(args) {
10413 this.args = args;
10414 this.init();
10415 }
10416 Object.defineProperty(IntegerEditor.prototype, "columnDef", {
10417 /** Get Column Definition object */
10418 get: function () {
10419 return this.args && this.args.column || {};
10420 },
10421 enumerable: true,
10422 configurable: true
10423 });
10424 Object.defineProperty(IntegerEditor.prototype, "columnEditor", {
10425 /** Get Column Editor object */
10426 get: function () {
10427 return this.columnDef && this.columnDef.internalColumnEditor && this.columnDef.internalColumnEditor || {};
10428 },
10429 enumerable: true,
10430 configurable: true
10431 });
10432 Object.defineProperty(IntegerEditor.prototype, "hasAutoCommitEdit", {
10433 get: function () {
10434 return this.args && this.args.grid && this.args.grid.getOptions && this.args.grid.getOptions().autoCommitEdit;
10435 },
10436 enumerable: true,
10437 configurable: true
10438 });
10439 Object.defineProperty(IntegerEditor.prototype, "validator", {
10440 /** Get the Validator function, can be passed in Editor property or Column Definition */
10441 get: function () {
10442 return this.columnEditor.validator || this.columnDef.validator;
10443 },
10444 enumerable: true,
10445 configurable: true
10446 });
10447 IntegerEditor.prototype.init = function () {
10448 var _this = this;
10449 var columnId = this.columnDef && this.columnDef.id;
10450 var placeholder = this.columnEditor && this.columnEditor.placeholder || '';
10451 var title = this.columnEditor && this.columnEditor.title || '';
10452 this.$input = $("<input type=\"number\" role=\"presentation\" autocomplete=\"off\" class=\"editor-text editor-" + columnId + "\" placeholder=\"" + placeholder + "\" title=\"" + title + "\" />")
10453 .appendTo(this.args.container)
10454 .on('keydown.nav', function (event) {
10455 _this._lastInputEvent = event;
10456 if (event.keyCode === exports.KeyCode.LEFT || event.keyCode === exports.KeyCode.RIGHT) {
10457 event.stopImmediatePropagation();
10458 }
10459 });
10460 // the lib does not get the focus out event for some reason
10461 // so register it here
10462 if (this.hasAutoCommitEdit) {
10463 this.$input.on('focusout', function () { return _this.save(); });
10464 }
10465 setTimeout(function () {
10466 _this.$input.focus().select();
10467 }, 50);
10468 };
10469 IntegerEditor.prototype.destroy = function () {
10470 this.$input.off('keydown.nav focusout').remove();
10471 };
10472 IntegerEditor.prototype.focus = function () {
10473 this.$input.focus();
10474 };
10475 IntegerEditor.prototype.getColumnEditor = function () {
10476 return this.args && this.args.column && this.args.column.internalColumnEditor;
10477 };
10478 IntegerEditor.prototype.loadValue = function (item) {
10479 var fieldName = this.columnDef && this.columnDef.field;
10480 // when it's a complex object, then pull the object name only, e.g.: "user.firstName" => "user"
10481 var fieldNameFromComplexObject = fieldName.indexOf('.') ? fieldName.substring(0, fieldName.indexOf('.')) : '';
10482 if (item && this.columnDef && (item.hasOwnProperty(fieldName) || item.hasOwnProperty(fieldNameFromComplexObject))) {
10483 this.defaultValue = item[fieldNameFromComplexObject || fieldName];
10484 this.$input.val(this.defaultValue);
10485 this.$input[0].defaultValue = this.defaultValue;
10486 this.$input.select();
10487 }
10488 };
10489 IntegerEditor.prototype.serializeValue = function () {
10490 var elmValue = this.$input.val();
10491 if (elmValue === '' || isNaN(elmValue)) {
10492 return elmValue;
10493 }
10494 return isNaN(elmValue) ? elmValue : parseInt(elmValue, 10);
10495 };
10496 IntegerEditor.prototype.applyValue = function (item, state) {
10497 var fieldName = this.columnDef && this.columnDef.field;
10498 // when it's a complex object, then pull the object name only, e.g.: "user.firstName" => "user"
10499 var fieldNameFromComplexObject = fieldName.indexOf('.') ? fieldName.substring(0, fieldName.indexOf('.')) : '';
10500 var validation = this.validate(state);
10501 item[fieldNameFromComplexObject || fieldName] = (validation && validation.valid) ? state : '';
10502 };
10503 IntegerEditor.prototype.isValueChanged = function () {
10504 var elmValue = this.$input.val();
10505 var lastEvent = this._lastInputEvent && this._lastInputEvent.keyCode;
10506 if (this.columnEditor && this.columnEditor.alwaysSaveOnEnterKey && lastEvent === exports.KeyCode.ENTER) {
10507 return true;
10508 }
10509 return (!(elmValue === '' && this.defaultValue === null)) && (elmValue !== this.defaultValue);
10510 };
10511 IntegerEditor.prototype.save = function () {
10512 var validation = this.validate();
10513 if (validation && validation.valid) {
10514 if (this.hasAutoCommitEdit) {
10515 this.args.grid.getEditorLock().commitCurrentEdit();
10516 }
10517 else {
10518 this.args.commitChanges();
10519 }
10520 }
10521 };
10522 IntegerEditor.prototype.validate = function (inputValue) {
10523 var elmValue = (inputValue !== undefined) ? inputValue : this.$input && this.$input.val && this.$input.val();
10524 var intNumber = !isNaN(elmValue) ? parseInt(elmValue, 10) : null;
10525 var errorMsg = this.columnEditor.errorMessage;
10526 var isRequired = this.columnEditor.required;
10527 var minValue = this.columnEditor.minValue;
10528 var maxValue = this.columnEditor.maxValue;
10529 var mapValidation = {
10530 '{{minValue}}': minValue,
10531 '{{maxValue}}': maxValue
10532 };
10533 var isValid = true;
10534 var outputMsg = '';
10535 if (this.validator) {
10536 return this.validator(elmValue, this.args);
10537 }
10538 else if (isRequired && elmValue === '') {
10539 isValid = false;
10540 outputMsg = errorMsg || Constants.VALIDATION_REQUIRED_FIELD;
10541 }
10542 else if (isNaN(elmValue) || !/^[+-]?\d+$/.test(elmValue)) {
10543 isValid = false;
10544 outputMsg = errorMsg || Constants.VALIDATION_EDITOR_VALID_INTEGER;
10545 }
10546 else if (minValue !== undefined && maxValue !== undefined && intNumber !== null && (intNumber < minValue || intNumber > maxValue)) {
10547 // MIN & MAX Values provided
10548 // when decimal value is bigger than 0, we only accept the decimal values as that value set
10549 // for example if we set decimalPlaces to 2, we will only accept numbers between 0 and 2 decimals
10550 isValid = false;
10551 outputMsg = errorMsg || Constants.VALIDATION_EDITOR_INTEGER_BETWEEN.replace(/{{minValue}}|{{maxValue}}/gi, function (matched) { return mapValidation[matched]; });
10552 }
10553 else if (minValue !== undefined && intNumber !== null && intNumber <= minValue) {
10554 // MIN VALUE ONLY
10555 // when decimal value is bigger than 0, we only accept the decimal values as that value set
10556 // for example if we set decimalPlaces to 2, we will only accept numbers between 0 and 2 decimals
10557 isValid = false;
10558 outputMsg = errorMsg || Constants.VALIDATION_EDITOR_INTEGER_MIN.replace(/{{minValue}}/gi, function (matched) { return mapValidation[matched]; });
10559 }
10560 else if (maxValue !== undefined && intNumber !== null && intNumber >= maxValue) {
10561 // MAX VALUE ONLY
10562 // when decimal value is bigger than 0, we only accept the decimal values as that value set
10563 // for example if we set decimalPlaces to 2, we will only accept numbers between 0 and 2 decimals
10564 isValid = false;
10565 outputMsg = errorMsg || Constants.VALIDATION_EDITOR_INTEGER_MAX.replace(/{{maxValue}}/gi, function (matched) { return mapValidation[matched]; });
10566 }
10567 return {
10568 valid: isValid,
10569 msg: outputMsg
10570 };
10571 };
10572 return IntegerEditor;
10573 }());
10574
10575 /*
10576 * An example of a 'detached' editor.
10577 * The UI is added onto document BODY and .position(), .show() and .hide() are implemented.
10578 * KeyDown events are also handled to provide handling for Tab, Shift-Tab, Esc and Ctrl-Enter.
10579 */
10580 var LongTextEditor = /** @class */ (function () {
10581 function LongTextEditor(args) {
10582 this.args = args;
10583 this.gridOptions = this.args.grid.getOptions();
10584 var options = this.gridOptions || this.args.column.params || {};
10585 this._translate = options.i18n;
10586 this.init();
10587 }
10588 Object.defineProperty(LongTextEditor.prototype, "columnDef", {
10589 /** Get Column Definition object */
10590 get: function () {
10591 return this.args && this.args.column || {};
10592 },
10593 enumerable: true,
10594 configurable: true
10595 });
10596 Object.defineProperty(LongTextEditor.prototype, "columnEditor", {
10597 /** Get Column Editor object */
10598 get: function () {
10599 return this.columnDef && this.columnDef.internalColumnEditor && this.columnDef.internalColumnEditor || {};
10600 },
10601 enumerable: true,
10602 configurable: true
10603 });
10604 Object.defineProperty(LongTextEditor.prototype, "validator", {
10605 /** Get the Validator function, can be passed in Editor property or Column Definition */
10606 get: function () {
10607 return this.columnEditor.validator || this.columnDef.validator;
10608 },
10609 enumerable: true,
10610 configurable: true
10611 });
10612 Object.defineProperty(LongTextEditor.prototype, "hasAutoCommitEdit", {
10613 get: function () {
10614 return this.args.grid.getOptions().autoCommitEdit;
10615 },
10616 enumerable: true,
10617 configurable: true
10618 });
10619 LongTextEditor.prototype.init = function () {
10620 var _this = this;
10621 var columnId = this.columnDef && this.columnDef.id;
10622 var placeholder = this.columnEditor && this.columnEditor.placeholder || '';
10623 var title = this.columnEditor && this.columnEditor.title || '';
10624 var cancelText = this._translate && this._translate.instant('CANCEL') || Constants.TEXT_CANCEL;
10625 var saveText = this._translate && this._translate.instant('SAVE') || Constants.TEXT_SAVE;
10626 var $container = $('body');
10627 this.$wrapper = $("<div class=\"slick-large-editor-text editor-" + columnId + "\" />").appendTo($container);
10628 this.$textarea = $("<textarea hidefocus rows=\"5\" placeholder=\"" + placeholder + "\" title=\"" + title + "\">").appendTo(this.$wrapper);
10629 // the lib does not get the focus out event for some reason
10630 // so register it here
10631 if (this.hasAutoCommitEdit) {
10632 this.$textarea.on('focusout', function () { return _this.save(); });
10633 }
10634 $("<div class=\"editor-footer\">\n <button class=\"btn btn-primary btn-xs\">" + saveText + "</button>\n <button class=\"btn btn-default btn-xs\">" + cancelText + "</button>\n </div>").appendTo(this.$wrapper);
10635 this.$wrapper.find('button:first').on('click', function () { return _this.save(); });
10636 this.$wrapper.find('button:last').on('click', function () { return _this.cancel(); });
10637 this.$textarea.on('keydown', this.handleKeyDown.bind(this));
10638 this.position(this.args && this.args.position);
10639 this.$textarea.focus().select();
10640 };
10641 LongTextEditor.prototype.handleKeyDown = function (event) {
10642 if (event.which === exports.KeyCode.ENTER && event.ctrlKey) {
10643 this.save();
10644 }
10645 else if (event.which === exports.KeyCode.ESCAPE) {
10646 event.preventDefault();
10647 this.cancel();
10648 }
10649 else if (event.which === exports.KeyCode.TAB && event.shiftKey) {
10650 event.preventDefault();
10651 if (this.args && this.args.grid) {
10652 this.args.grid.navigatePrev();
10653 }
10654 }
10655 else if (event.which === exports.KeyCode.TAB) {
10656 event.preventDefault();
10657 if (this.args && this.args.grid) {
10658 this.args.grid.navigateNext();
10659 }
10660 }
10661 };
10662 LongTextEditor.prototype.cancel = function () {
10663 this.$textarea.val(this.defaultValue);
10664 if (this.args && this.args.cancelChanges) {
10665 this.args.cancelChanges();
10666 }
10667 };
10668 LongTextEditor.prototype.hide = function () {
10669 this.$wrapper.hide();
10670 };
10671 LongTextEditor.prototype.show = function () {
10672 this.$wrapper.show();
10673 };
10674 LongTextEditor.prototype.position = function (position) {
10675 this.$wrapper
10676 .css('top', (position.top || 0) - 5)
10677 .css('left', (position.left || 0) - 5);
10678 };
10679 LongTextEditor.prototype.destroy = function () {
10680 this.$wrapper.off('keydown focusout').remove();
10681 };
10682 LongTextEditor.prototype.focus = function () {
10683 this.$textarea.focus();
10684 };
10685 LongTextEditor.prototype.getValue = function () {
10686 return this.$textarea.val();
10687 };
10688 LongTextEditor.prototype.setValue = function (val) {
10689 this.$textarea.val(val);
10690 };
10691 LongTextEditor.prototype.getColumnEditor = function () {
10692 return this.args && this.args.column && this.args.column.internalColumnEditor && this.args.column.internalColumnEditor;
10693 };
10694 LongTextEditor.prototype.loadValue = function (item) {
10695 var fieldName = this.columnDef && this.columnDef.field;
10696 // when it's a complex object, then pull the object name only, e.g.: "user.firstName" => "user"
10697 var fieldNameFromComplexObject = fieldName.indexOf('.') ? fieldName.substring(0, fieldName.indexOf('.')) : '';
10698 if (item && this.columnDef && (item.hasOwnProperty(fieldName) || item.hasOwnProperty(fieldNameFromComplexObject))) {
10699 this.defaultValue = item[fieldNameFromComplexObject || fieldName];
10700 this.$textarea.val(this.defaultValue);
10701 this.$textarea.select();
10702 }
10703 };
10704 LongTextEditor.prototype.serializeValue = function () {
10705 return this.$textarea.val();
10706 };
10707 LongTextEditor.prototype.applyValue = function (item, state) {
10708 var fieldName = this.columnDef && this.columnDef.field;
10709 // when it's a complex object, then pull the object name only, e.g.: "user.firstName" => "user"
10710 var fieldNameFromComplexObject = fieldName.indexOf('.') ? fieldName.substring(0, fieldName.indexOf('.')) : '';
10711 var validation = this.validate(state);
10712 item[fieldNameFromComplexObject || fieldName] = (validation && validation.valid) ? state : '';
10713 };
10714 LongTextEditor.prototype.isValueChanged = function () {
10715 return (!(this.$textarea.val() === '' && this.defaultValue === null)) && (this.$textarea.val() !== this.defaultValue);
10716 };
10717 LongTextEditor.prototype.save = function () {
10718 var validation = this.validate();
10719 if (validation && validation.valid) {
10720 if (this.hasAutoCommitEdit) {
10721 this.args.grid.getEditorLock().commitCurrentEdit();
10722 }
10723 else {
10724 this.args.commitChanges();
10725 }
10726 }
10727 else {
10728 this.args.commitChanges();
10729 }
10730 };
10731 LongTextEditor.prototype.validate = function (inputValue) {
10732 var isRequired = this.columnEditor.required;
10733 var elmValue = (inputValue !== undefined) ? inputValue : this.$textarea && this.$textarea.val && this.$textarea.val();
10734 var errorMsg = this.columnEditor.errorMessage;
10735 if (this.validator) {
10736 return this.validator(elmValue, this.args);
10737 }
10738 // by default the editor is almost always valid (except when it's required but not provided)
10739 if (isRequired && elmValue === '') {
10740 return {
10741 valid: false,
10742 msg: errorMsg || Constants.VALIDATION_REQUIRED_FIELD
10743 };
10744 }
10745 return {
10746 valid: true,
10747 msg: null
10748 };
10749 };
10750 return LongTextEditor;
10751 }());
10752
10753 var DOMPurify$2 = DOMPurify_; // patch to fix rollup to work
10754 /**
10755 * Slickgrid editor class for multiple/single select lists
10756 */
10757 var SelectEditor = /** @class */ (function () {
10758 function SelectEditor(args, isMultipleSelect) {
10759 var _this = this;
10760 this.args = args;
10761 this.isMultipleSelect = isMultipleSelect;
10762 /** Observable Subscriptions */
10763 this._subscriptions = [];
10764 // flag to signal that the editor is destroying itself, helps prevent
10765 // commit changes from being called twice and erroring
10766 this._destroying = false;
10767 this.gridOptions = this.args.grid.getOptions();
10768 var gridOptions = this.gridOptions || this.args.column.params || {};
10769 this._translate = gridOptions.i18n;
10770 // provide the name attribute to the DOM element which will be needed to auto-adjust drop position (dropup / dropdown)
10771 var fieldId = this.columnDef && this.columnDef.id;
10772 this.elementName = "editor-" + fieldId;
10773 var libOptions = {
10774 autoAdjustDropHeight: true,
10775 autoAdjustDropPosition: true,
10776 autoAdjustDropWidthByTextSize: true,
10777 container: 'body',
10778 filter: false,
10779 maxHeight: 275,
10780 name: this.elementName,
10781 single: true,
10782 textTemplate: function ($elm) {
10783 // render HTML code or not, by default it is sanitized and won't be rendered
10784 var isRenderHtmlEnabled = _this.columnDef && _this.columnDef.internalColumnEditor && _this.columnDef.internalColumnEditor.enableRenderHtml || false;
10785 return isRenderHtmlEnabled ? $elm.text() : $elm.html();
10786 },
10787 onBlur: function () { return _this.destroy(); },
10788 onClose: function () {
10789 if (!_this._destroying && _this.hasAutoCommitEdit) {
10790 // do not use args.commitChanges() as this sets the focus to the next
10791 // row. Also the select list will stay shown when clicking off the grid
10792 args.grid.getEditorLock().commitCurrentEdit();
10793 }
10794 }
10795 };
10796 if (isMultipleSelect) {
10797 libOptions.single = false;
10798 libOptions.addTitle = true;
10799 libOptions.okButton = true;
10800 libOptions.selectAllDelimiter = ['', ''];
10801 if (this._translate) {
10802 libOptions.countSelected = this._translate.instant('X_OF_Y_SELECTED');
10803 libOptions.allSelected = this._translate.instant('ALL_SELECTED');
10804 libOptions.selectAllText = this._translate.instant('SELECT_ALL');
10805 }
10806 }
10807 // assign the multiple select lib options
10808 this.defaultOptions = libOptions;
10809 this.init();
10810 }
10811 Object.defineProperty(SelectEditor.prototype, "collection", {
10812 /** Get the Collection */
10813 get: function () {
10814 return this.columnDef && this.columnDef && this.columnDef.internalColumnEditor.collection || [];
10815 },
10816 enumerable: true,
10817 configurable: true
10818 });
10819 Object.defineProperty(SelectEditor.prototype, "collectionOptions", {
10820 /** Getter for the Collection Options */
10821 get: function () {
10822 return this.columnDef && this.columnDef.internalColumnEditor && this.columnDef.internalColumnEditor.collectionOptions;
10823 },
10824 enumerable: true,
10825 configurable: true
10826 });
10827 Object.defineProperty(SelectEditor.prototype, "columnDef", {
10828 /** Get Column Definition object */
10829 get: function () {
10830 return this.args && this.args.column || {};
10831 },
10832 enumerable: true,
10833 configurable: true
10834 });
10835 Object.defineProperty(SelectEditor.prototype, "columnEditor", {
10836 /** Get Column Editor object */
10837 get: function () {
10838 return this.columnDef && this.columnDef.internalColumnEditor && this.columnDef.internalColumnEditor || {};
10839 },
10840 enumerable: true,
10841 configurable: true
10842 });
10843 Object.defineProperty(SelectEditor.prototype, "customStructure", {
10844 /** Getter for the Custom Structure if exist */
10845 get: function () {
10846 return this.columnDef && this.columnDef.internalColumnEditor && this.columnDef.internalColumnEditor.customStructure;
10847 },
10848 enumerable: true,
10849 configurable: true
10850 });
10851 Object.defineProperty(SelectEditor.prototype, "hasAutoCommitEdit", {
10852 get: function () {
10853 return this.args.grid.getOptions().autoCommitEdit;
10854 },
10855 enumerable: true,
10856 configurable: true
10857 });
10858 Object.defineProperty(SelectEditor.prototype, "currentValues", {
10859 /**
10860 * The current selected values (multiple select) from the collection
10861 */
10862 get: function () {
10863 var _this = this;
10864 // collection of strings, just return the filtered string that are equals
10865 if (this.collection.every(function (x) { return typeof x === 'string'; })) {
10866 return this.collection.filter(function (c) { return _this.$editorElm.val().indexOf(c.toString()) !== -1; });
10867 }
10868 // collection of label/value pair
10869 var separatorBetweenLabels = this.collectionOptions && this.collectionOptions.separatorBetweenTextLabels || '';
10870 var isIncludingPrefixSuffix = this.collectionOptions && this.collectionOptions.includePrefixSuffixToSelectedValues || false;
10871 return this.collection
10872 .filter(function (c) { return _this.$editorElm.val().indexOf(c[_this.valueName].toString()) !== -1; })
10873 .map(function (c) {
10874 var labelText = c[_this.valueName];
10875 var prefixText = c[_this.labelPrefixName] || '';
10876 var suffixText = c[_this.labelSuffixName] || '';
10877 // when it's a complex object, then pull the object name only, e.g.: "user.firstName" => "user"
10878 var fieldName = _this.columnDef && _this.columnDef.field;
10879 var fieldNameFromComplexObject = fieldName.indexOf('.') ? fieldName.substring(0, fieldName.indexOf('.')) : '';
10880 if (fieldNameFromComplexObject && typeof c === 'object') {
10881 return c;
10882 }
10883 // also translate prefix/suffix if enableTranslateLabel is true and text is a string
10884 prefixText = (_this.enableTranslateLabel && prefixText && typeof prefixText === 'string') ? _this._translate.instant(prefixText || ' ') : prefixText;
10885 suffixText = (_this.enableTranslateLabel && suffixText && typeof suffixText === 'string') ? _this._translate.instant(suffixText || ' ') : suffixText;
10886 if (isIncludingPrefixSuffix) {
10887 var tmpOptionArray = [prefixText, labelText, suffixText].filter(function (text) { return text; }); // add to a temp array for joining purpose and filter out empty text
10888 return tmpOptionArray.join(separatorBetweenLabels);
10889 }
10890 return labelText;
10891 });
10892 },
10893 enumerable: true,
10894 configurable: true
10895 });
10896 Object.defineProperty(SelectEditor.prototype, "currentValue", {
10897 /**
10898 * The current selected values (single select) from the collection
10899 */
10900 get: function () {
10901 var _this = this;
10902 // collection of strings, just return the filtered string that are equals
10903 if (this.collection.every(function (x) { return typeof x === 'string'; })) {
10904 return findOrDefault(this.collection, function (c) { return c.toString() === _this.$editorElm.val(); });
10905 }
10906 // collection of label/value pair
10907 var separatorBetweenLabels = this.collectionOptions && this.collectionOptions.separatorBetweenTextLabels || '';
10908 var isIncludingPrefixSuffix = this.collectionOptions && this.collectionOptions.includePrefixSuffixToSelectedValues || false;
10909 var itemFound = findOrDefault(this.collection, function (c) { return c[_this.valueName].toString() === _this.$editorElm.val(); });
10910 // when it's a complex object, then pull the object name only, e.g.: "user.firstName" => "user"
10911 var fieldName = this.columnDef && this.columnDef.field;
10912 var fieldNameFromComplexObject = fieldName.indexOf('.') ? fieldName.substring(0, fieldName.indexOf('.')) : '';
10913 if (fieldNameFromComplexObject && typeof itemFound === 'object') {
10914 return itemFound;
10915 }
10916 else if (itemFound) {
10917 var labelText = itemFound[this.valueName];
10918 if (isIncludingPrefixSuffix) {
10919 var prefixText = itemFound[this.labelPrefixName] || '';
10920 var suffixText = itemFound[this.labelSuffixName] || '';
10921 // also translate prefix/suffix if enableTranslateLabel is true and text is a string
10922 prefixText = (this.enableTranslateLabel && prefixText && typeof prefixText === 'string') ? this._translate.instant(prefixText || ' ') : prefixText;
10923 suffixText = (this.enableTranslateLabel && suffixText && typeof suffixText === 'string') ? this._translate.instant(suffixText || ' ') : suffixText;
10924 // add to a temp array for joining purpose and filter out empty text
10925 var tmpOptionArray = [prefixText, labelText, suffixText].filter(function (text) { return text; });
10926 return tmpOptionArray.join(separatorBetweenLabels);
10927 }
10928 return labelText;
10929 }
10930 return '';
10931 },
10932 enumerable: true,
10933 configurable: true
10934 });
10935 Object.defineProperty(SelectEditor.prototype, "validator", {
10936 /** Get the Validator function, can be passed in Editor property or Column Definition */
10937 get: function () {
10938 return this.columnEditor.validator || this.columnDef.validator;
10939 },
10940 enumerable: true,
10941 configurable: true
10942 });
10943 SelectEditor.prototype.init = function () {
10944 if (!this.args) {
10945 throw new Error('[Angular-SlickGrid] An editor must always have an "init()" with valid arguments.');
10946 }
10947 if (!this.columnDef || !this.columnDef.internalColumnEditor || (!this.columnDef.internalColumnEditor.collection && !this.columnDef.internalColumnEditor.collectionAsync)) {
10948 throw new Error("[Angular-SlickGrid] You need to pass a \"collection\" (or \"collectionAsync\") inside Column Definition Editor for the MultipleSelect/SingleSelect Editor to work correctly.\n Also each option should include a value/label pair (or value/labelKey when using Locale).\n For example: { editor: { collection: [{ value: true, label: 'True' },{ value: false, label: 'False'}] } }");
10949 }
10950 this._collectionService = new CollectionService(this._translate);
10951 this.enableTranslateLabel = (this.columnDef.internalColumnEditor.enableTranslateLabel) ? this.columnDef.internalColumnEditor.enableTranslateLabel : false;
10952 this.labelName = this.customStructure && this.customStructure.label || 'label';
10953 this.labelPrefixName = this.customStructure && this.customStructure.labelPrefix || 'labelPrefix';
10954 this.labelSuffixName = this.customStructure && this.customStructure.labelSuffix || 'labelSuffix';
10955 this.optionLabel = this.customStructure && this.customStructure.optionLabel || 'value';
10956 this.valueName = this.customStructure && this.customStructure.value || 'value';
10957 if (this.enableTranslateLabel && (!this._translate || typeof this._translate.instant !== 'function')) {
10958 throw new Error("[select-editor] The ngx-translate TranslateService is required for the Select Editor to work correctly");
10959 }
10960 // always render the Select (dropdown) DOM element, even if user passed a "collectionAsync",
10961 // if that is the case, the Select will simply be without any options but we still have to render it (else SlickGrid would throw an error)
10962 this.renderDomElement(this.collection);
10963 };
10964 SelectEditor.prototype.applyValue = function (item, state) {
10965 var fieldName = this.columnDef && this.columnDef.field;
10966 var fieldType = this.columnDef && this.columnDef.type;
10967 var newValue = state;
10968 // when the provided user defined the column field type as a possible number then try parsing the state value as that
10969 if (fieldType === exports.FieldType.number || fieldType === exports.FieldType.integer || fieldType === exports.FieldType.boolean) {
10970 newValue = parseFloat(state);
10971 }
10972 // when set as a multiple selection, we can assume that the 3rd party lib multiple-select will return a CSV string
10973 // we need to re-split that into an array to be the same as the original column
10974 if (this.isMultipleSelect && typeof state === 'string' && state.indexOf(',') >= 0) {
10975 newValue = state.split(',');
10976 }
10977 // when it's a complex object, then pull the object name only, e.g.: "user.firstName" => "user"
10978 var fieldNameFromComplexObject = fieldName.indexOf('.') ? fieldName.substring(0, fieldName.indexOf('.')) : '';
10979 var validation = this.validate(newValue);
10980 item[fieldNameFromComplexObject || fieldName] = (validation && validation.valid) ? newValue : '';
10981 };
10982 SelectEditor.prototype.destroy = function () {
10983 this._destroying = true;
10984 if (this.$editorElm && typeof this.$editorElm.multipleSelect === 'function') {
10985 this.$editorElm.multipleSelect('destroy');
10986 this.$editorElm.remove();
10987 var elementClassName = this.elementName.toString().replace('.', '\\.'); // make sure to escape any dot "." from CSS class to avoid console error
10988 $("[name=" + elementClassName + "].ms-drop").remove();
10989 }
10990 else if (this.$editorElm && typeof this.$editorElm.remove === 'function') {
10991 this.$editorElm.remove();
10992 }
10993 this._subscriptions = unsubscribeAllObservables(this._subscriptions);
10994 };
10995 SelectEditor.prototype.loadValue = function (item) {
10996 var fieldName = this.columnDef && this.columnDef.field;
10997 // when it's a complex object, then pull the object name only, e.g.: "user.firstName" => "user"
10998 var fieldNameFromComplexObject = fieldName.indexOf('.') ? fieldName.substring(0, fieldName.indexOf('.')) : '';
10999 if (item && this.columnDef && (item.hasOwnProperty(fieldName) || item.hasOwnProperty(fieldNameFromComplexObject))) {
11000 var currentValue = item[fieldNameFromComplexObject || fieldName];
11001 var loadValue = fieldNameFromComplexObject && currentValue.hasOwnProperty(this.valueName) ? currentValue[this.valueName] : currentValue;
11002 if (this.isMultipleSelect && Array.isArray(loadValue)) {
11003 this.loadMultipleValues(loadValue);
11004 }
11005 else {
11006 this.loadSingleValue(loadValue);
11007 }
11008 this.refresh();
11009 }
11010 };
11011 SelectEditor.prototype.loadMultipleValues = function (currentValues) {
11012 // convert to string because that is how the DOM will return these values
11013 if (Array.isArray(currentValues)) {
11014 // keep the default values in memory for references
11015 this.defaultValue = currentValues.map(function (i) { return i; });
11016 // compare all the array values but as string type since multiple-select always return string
11017 var currentStringValues_1 = currentValues.map(function (i) { return i.toString(); });
11018 this.$editorElm.find('option').each(function (i, $e) {
11019 $e.selected = (currentStringValues_1.indexOf($e.value) !== -1);
11020 });
11021 }
11022 };
11023 SelectEditor.prototype.loadSingleValue = function (currentValue) {
11024 // keep the default value in memory for references
11025 this.defaultValue = currentValue;
11026 // make sure the prop exists first
11027 this.$editorElm.find('option').each(function (i, $e) {
11028 // check equality after converting defaultValue to string since the DOM value will always be of type string
11029 $e.selected = (currentValue.toString() === $e.value);
11030 });
11031 };
11032 SelectEditor.prototype.serializeValue = function () {
11033 return (this.isMultipleSelect) ? this.currentValues : this.currentValue;
11034 };
11035 SelectEditor.prototype.focus = function () {
11036 if (this.$editorElm && this.$editorElm.multipleSelect) {
11037 this.$editorElm.multipleSelect('focus');
11038 }
11039 };
11040 SelectEditor.prototype.isValueChanged = function () {
11041 if (this.isMultipleSelect) {
11042 return !charArraysEqual(this.$editorElm.val(), this.defaultValue);
11043 }
11044 return this.$editorElm.val() !== this.defaultValue;
11045 };
11046 SelectEditor.prototype.validate = function (inputValue) {
11047 var isRequired = this.columnEditor.required;
11048 var elmValue = (inputValue !== undefined) ? inputValue : this.$editorElm && this.$editorElm.val && this.$editorElm.val();
11049 var errorMsg = this.columnEditor.errorMessage;
11050 if (this.validator) {
11051 var value = (inputValue !== undefined) ? inputValue : (this.isMultipleSelect ? this.currentValues : this.currentValue);
11052 return this.validator(value, this.args);
11053 }
11054 // by default the editor is almost always valid (except when it's required but not provided)
11055 if (isRequired && (elmValue === '' || (Array.isArray(elmValue) && elmValue.length === 0))) {
11056 return {
11057 valid: false,
11058 msg: errorMsg || Constants.VALIDATION_REQUIRED_FIELD
11059 };
11060 }
11061 return {
11062 valid: true,
11063 msg: null
11064 };
11065 };
11066 //
11067 // protected functions
11068 // ------------------
11069 /**
11070 * user might want to filter certain items of the collection
11071 * @param inputCollection
11072 * @return outputCollection filtered and/or sorted collection
11073 */
11074 SelectEditor.prototype.filterCollection = function (inputCollection) {
11075 var outputCollection = inputCollection;
11076 // user might want to filter certain items of the collection
11077 if (this.columnEditor && this.columnEditor.collectionFilterBy) {
11078 var filterBy = this.columnEditor.collectionFilterBy;
11079 var filterCollectionBy = this.columnEditor.collectionOptions && this.columnEditor.collectionOptions.filterResultAfterEachPass || null;
11080 outputCollection = this._collectionService.filterCollection(outputCollection, filterBy, filterCollectionBy);
11081 }
11082 return outputCollection;
11083 };
11084 /**
11085 * user might want to sort the collection in a certain way
11086 * @param inputCollection
11087 * @return outputCollection sorted collection
11088 */
11089 SelectEditor.prototype.sortCollection = function (inputCollection) {
11090 var outputCollection = inputCollection;
11091 // user might want to sort the collection
11092 if (this.columnDef.internalColumnEditor && this.columnDef.internalColumnEditor.collectionSortBy) {
11093 var sortBy = this.columnDef.internalColumnEditor.collectionSortBy;
11094 outputCollection = this._collectionService.sortCollection(this.columnDef, outputCollection, sortBy, this.enableTranslateLabel);
11095 }
11096 return outputCollection;
11097 };
11098 SelectEditor.prototype.renderDomElement = function (collection) {
11099 if (!Array.isArray(collection) && this.collectionOptions && this.collectionOptions.collectionInObjectProperty) {
11100 collection = getDescendantProperty(collection, this.collectionOptions.collectionInObjectProperty);
11101 }
11102 if (!Array.isArray(collection)) {
11103 throw new Error('The "collection" passed to the Select Editor is not a valid array');
11104 }
11105 // user can optionally add a blank entry at the beginning of the collection
11106 if (this.collectionOptions && this.collectionOptions.addBlankEntry) {
11107 collection.unshift(this.createBlankEntry());
11108 }
11109 var newCollection = collection || [];
11110 // user might want to filter and/or sort certain items of the collection
11111 newCollection = this.filterCollection(newCollection);
11112 newCollection = this.sortCollection(newCollection);
11113 // step 1, create HTML string template
11114 var editorTemplate = this.buildTemplateHtmlString(newCollection);
11115 // step 2, create the DOM Element of the editor
11116 // also subscribe to the onClose event
11117 this.createDomElement(editorTemplate);
11118 };
11119 SelectEditor.prototype.buildTemplateHtmlString = function (collection) {
11120 var _this = this;
11121 var options = '';
11122 var fieldId = this.columnDef && this.columnDef.id;
11123 var separatorBetweenLabels = this.collectionOptions && this.collectionOptions.separatorBetweenTextLabels || '';
11124 var isRenderHtmlEnabled = this.columnDef.internalColumnEditor.enableRenderHtml || false;
11125 var sanitizedOptions = this.gridOptions && this.gridOptions.sanitizeHtmlOptions || {};
11126 // collection could be an Array of Strings OR Objects
11127 if (collection.every(function (x) { return typeof x === 'string'; })) {
11128 collection.forEach(function (option) {
11129 options += "<option value=\"" + option + "\" label=\"" + option + "\">" + option + "</option>";
11130 });
11131 }
11132 else {
11133 // array of objects will require a label/value pair unless a customStructure is passed
11134 collection.forEach(function (option) {
11135 if (!option || (option[_this.labelName] === undefined && option.labelKey === undefined)) {
11136 throw new Error("[select-editor] A collection with value/label (or value/labelKey when using Locale) is required to populate the Select list, for example: { collection: [ { value: '1', label: 'One' } ])");
11137 }
11138 var labelKey = (option.labelKey || option[_this.labelName]);
11139 var labelText = ((option.labelKey || _this.enableTranslateLabel) && labelKey) ? _this._translate.instant(labelKey || ' ') : labelKey;
11140 var prefixText = option[_this.labelPrefixName] || '';
11141 var suffixText = option[_this.labelSuffixName] || '';
11142 var optionLabel = option[_this.optionLabel] || '';
11143 optionLabel = optionLabel.toString().replace(/\"/g, '\''); // replace double quotes by single quotes to avoid interfering with regular html
11144 // also translate prefix/suffix if enableTranslateLabel is true and text is a string
11145 prefixText = (_this.enableTranslateLabel && prefixText && typeof prefixText === 'string') ? _this._translate.instant(prefixText || ' ') : prefixText;
11146 suffixText = (_this.enableTranslateLabel && suffixText && typeof suffixText === 'string') ? _this._translate.instant(suffixText || ' ') : suffixText;
11147 optionLabel = (_this.enableTranslateLabel && optionLabel && typeof optionLabel === 'string') ? _this._translate.instant(optionLabel || ' ') : optionLabel;
11148 // add to a temp array for joining purpose and filter out empty text
11149 var tmpOptionArray = [prefixText, labelText, suffixText].filter(function (text) { return text; });
11150 var optionText = tmpOptionArray.join(separatorBetweenLabels);
11151 // if user specifically wants to render html text, he needs to opt-in else it will stripped out by default
11152 // also, the 3rd party lib will saninitze any html code unless it's encoded, so we'll do that
11153 if (isRenderHtmlEnabled) {
11154 // sanitize any unauthorized html tags like script and others
11155 // for the remaining allowed tags we'll permit all attributes
11156 var sanitizedText = DOMPurify$2.sanitize(optionText, sanitizedOptions);
11157 optionText = htmlEncode(sanitizedText);
11158 }
11159 options += "<option value=\"" + option[_this.valueName] + "\" label=\"" + optionLabel + "\">" + optionText + "</option>";
11160 });
11161 }
11162 return "<select id=\"" + this.elementName + "\" class=\"ms-filter search-filter editor-" + fieldId + "\" " + (this.isMultipleSelect ? 'multiple="multiple"' : '') + ">" + options + "</select>";
11163 };
11164 /** Create a blank entry that can be added to the collection. It will also reuse the same customStructure if need be */
11165 SelectEditor.prototype.createBlankEntry = function () {
11166 var _a;
11167 var blankEntry = (_a = {},
11168 _a[this.labelName] = '',
11169 _a[this.valueName] = '',
11170 _a);
11171 if (this.labelPrefixName) {
11172 blankEntry[this.labelPrefixName] = '';
11173 }
11174 if (this.labelSuffixName) {
11175 blankEntry[this.labelSuffixName] = '';
11176 }
11177 return blankEntry;
11178 };
11179 /** Build the template HTML string */
11180 SelectEditor.prototype.createDomElement = function (editorTemplate) {
11181 var _this = this;
11182 this.$editorElm = $(editorTemplate);
11183 if (this.$editorElm && typeof this.$editorElm.appendTo === 'function') {
11184 this.$editorElm.appendTo(this.args.container);
11185 }
11186 if (typeof this.$editorElm.multipleSelect !== 'function') {
11187 // fallback to bootstrap
11188 this.$editorElm.addClass('form-control');
11189 }
11190 else {
11191 var elementOptions = (this.columnDef.internalColumnEditor) ? this.columnDef.internalColumnEditor.elementOptions : {};
11192 this.editorElmOptions = __assign({}, this.defaultOptions, elementOptions);
11193 this.$editorElm = this.$editorElm.multipleSelect(this.editorElmOptions);
11194 setTimeout(function () {
11195 if (_this.$editorElm && typeof _this.$editorElm.multipleSelect === 'function') {
11196 _this.$editorElm.multipleSelect('open');
11197 }
11198 });
11199 }
11200 };
11201 // refresh the jquery object because the selected checkboxes were already set
11202 // prior to this method being called
11203 SelectEditor.prototype.refresh = function () {
11204 if (typeof this.$editorElm.multipleSelect === 'function') {
11205 this.$editorElm.multipleSelect('refresh');
11206 }
11207 };
11208 return SelectEditor;
11209 }());
11210
11211 var MultipleSelectEditor = /** @class */ (function (_super) {
11212 __extends(MultipleSelectEditor, _super);
11213 /**
11214 * Initialize the Editor
11215 */
11216 function MultipleSelectEditor(args) {
11217 var _this = _super.call(this, args, true) || this;
11218 _this.args = args;
11219 return _this;
11220 }
11221 return MultipleSelectEditor;
11222 }(SelectEditor));
11223
11224 var SingleSelectEditor = /** @class */ (function (_super) {
11225 __extends(SingleSelectEditor, _super);
11226 /**
11227 * Initialize the Editor
11228 */
11229 function SingleSelectEditor(args) {
11230 var _this = _super.call(this, args, false) || this;
11231 _this.args = args;
11232 return _this;
11233 }
11234 return SingleSelectEditor;
11235 }(SelectEditor));
11236
11237 var DEFAULT_MIN_VALUE$2 = 0;
11238 var DEFAULT_MAX_VALUE$2 = 100;
11239 var DEFAULT_STEP$2 = 1;
11240 var SliderEditor = /** @class */ (function () {
11241 function SliderEditor(args) {
11242 this.args = args;
11243 this.init();
11244 }
11245 Object.defineProperty(SliderEditor.prototype, "columnDef", {
11246 /** Get Column Definition object */
11247 get: function () {
11248 return this.args && this.args.column || {};
11249 },
11250 enumerable: true,
11251 configurable: true
11252 });
11253 Object.defineProperty(SliderEditor.prototype, "columnEditor", {
11254 /** Get Column Editor object */
11255 get: function () {
11256 return this.columnDef && this.columnDef.internalColumnEditor || {};
11257 },
11258 enumerable: true,
11259 configurable: true
11260 });
11261 Object.defineProperty(SliderEditor.prototype, "editorParams", {
11262 /** Getter for the Editor Generic Params */
11263 get: function () {
11264 return this.columnEditor.params || {};
11265 },
11266 enumerable: true,
11267 configurable: true
11268 });
11269 Object.defineProperty(SliderEditor.prototype, "validator", {
11270 /** Get the Validator function, can be passed in Editor property or Column Definition */
11271 get: function () {
11272 return this.columnEditor.validator || this.columnDef.validator;
11273 },
11274 enumerable: true,
11275 configurable: true
11276 });
11277 SliderEditor.prototype.init = function () {
11278 var _this = this;
11279 var container = this.args && this.args.container;
11280 // define the input & slider number IDs
11281 var itemId = this.args && this.args.item && this.args.item.id;
11282 this._elementRangeInputId = "rangeInput_" + this.columnDef.field + "_" + itemId;
11283 this._elementRangeOutputId = "rangeOutput_" + this.columnDef.field + "_" + itemId;
11284 // create HTML string template
11285 var editorTemplate = this.buildTemplateHtmlString();
11286 this.$editorElm = $(editorTemplate);
11287 this.$input = this.$editorElm.children('input');
11288 this.$sliderNumber = this.$editorElm.children('div.input-group-addon.input-group-append').children();
11289 // watch on change event
11290 this.$editorElm
11291 .appendTo(container)
11292 .on('mouseup', function () { return _this.save(); });
11293 // if user chose to display the slider number on the right side, then update it every time it changes
11294 // we need to use both "input" and "change" event to be all cross-browser
11295 if (!this.editorParams.hideSliderNumber) {
11296 this.$editorElm.on('input change', function (event) {
11297 _this._lastInputEvent = event;
11298 var value = event && event.target && event.target.value || '';
11299 if (value) {
11300 document.getElementById(_this._elementRangeOutputId).innerHTML = event.target.value;
11301 }
11302 });
11303 }
11304 };
11305 SliderEditor.prototype.destroy = function () {
11306 this.$editorElm.off('input change mouseup').remove();
11307 };
11308 SliderEditor.prototype.focus = function () {
11309 this.$editorElm.focus();
11310 };
11311 SliderEditor.prototype.save = function () {
11312 var validation = this.validate();
11313 if (validation && validation.valid) {
11314 if (this.args.grid.getOptions().autoCommitEdit) {
11315 this.args.grid.getEditorLock().commitCurrentEdit();
11316 }
11317 else {
11318 this.args.commitChanges();
11319 }
11320 }
11321 };
11322 SliderEditor.prototype.cancel = function () {
11323 this.$input.val(this.defaultValue);
11324 this.args.cancelChanges();
11325 };
11326 SliderEditor.prototype.loadValue = function (item) {
11327 var fieldName = this.columnDef && this.columnDef.field;
11328 // when it's a complex object, then pull the object name only, e.g.: "user.firstName" => "user"
11329 var fieldNameFromComplexObject = fieldName.indexOf('.') ? fieldName.substring(0, fieldName.indexOf('.')) : '';
11330 if (item && this.columnDef && (item.hasOwnProperty(fieldName) || item.hasOwnProperty(fieldNameFromComplexObject))) {
11331 this.defaultValue = item[fieldNameFromComplexObject || fieldName];
11332 this.$input.val(this.defaultValue);
11333 this.$input[0].defaultValue = this.defaultValue;
11334 this.$sliderNumber.html(this.defaultValue);
11335 }
11336 };
11337 SliderEditor.prototype.serializeValue = function () {
11338 return parseInt(this.$input.val(), 10) || 0;
11339 };
11340 SliderEditor.prototype.applyValue = function (item, state) {
11341 var fieldName = this.columnDef && this.columnDef.field;
11342 // when it's a complex object, then pull the object name only, e.g.: "user.firstName" => "user"
11343 var fieldNameFromComplexObject = fieldName.indexOf('.') ? fieldName.substring(0, fieldName.indexOf('.')) : '';
11344 var validation = this.validate(state);
11345 item[fieldNameFromComplexObject || fieldName] = (validation && validation.valid) ? state : '';
11346 };
11347 SliderEditor.prototype.isValueChanged = function () {
11348 var elmValue = this.$input.val();
11349 var lastEvent = this._lastInputEvent && this._lastInputEvent.keyCode;
11350 if (this.columnEditor && this.columnEditor.alwaysSaveOnEnterKey && lastEvent === exports.KeyCode.ENTER) {
11351 return true;
11352 }
11353 return (!(elmValue === '' && this.defaultValue === null)) && (elmValue !== this.defaultValue);
11354 };
11355 SliderEditor.prototype.validate = function (inputValue) {
11356 var elmValue = (inputValue !== undefined) ? inputValue : this.$input && this.$input.val && this.$input.val();
11357 var isRequired = this.columnEditor.required;
11358 var minValue = this.columnEditor.minValue;
11359 var maxValue = this.columnEditor.maxValue;
11360 var errorMsg = this.columnEditor.errorMessage;
11361 var mapValidation = {
11362 '{{minValue}}': minValue,
11363 '{{maxValue}}': maxValue
11364 };
11365 if (this.validator) {
11366 return this.validator(elmValue, this.args);
11367 }
11368 else if (isRequired && elmValue === '') {
11369 return {
11370 valid: false,
11371 msg: errorMsg || Constants.VALIDATION_REQUIRED_FIELD
11372 };
11373 }
11374 else if (minValue !== undefined && (elmValue < minValue || elmValue > maxValue)) {
11375 // when decimal value is bigger than 0, we only accept the decimal values as that value set
11376 // for example if we set decimalPlaces to 2, we will only accept numbers between 0 and 2 decimals
11377 return {
11378 valid: false,
11379 msg: errorMsg || Constants.VALIDATION_EDITOR_NUMBER_BETWEEN.replace(/{{minValue}}|{{maxValue}}/gi, function (matched) {
11380 return mapValidation[matched];
11381 })
11382 };
11383 }
11384 return {
11385 valid: true,
11386 msg: null
11387 };
11388 };
11389 //
11390 // private functions
11391 // ------------------
11392 /**
11393 * Create the HTML template as a string
11394 */
11395 SliderEditor.prototype.buildTemplateHtmlString = function () {
11396 var fieldId = this.columnDef && this.columnDef.id;
11397 var title = this.columnEditor && this.columnEditor.title || '';
11398 var minValue = this.columnEditor.hasOwnProperty('minValue') ? this.columnEditor.minValue : DEFAULT_MIN_VALUE$2;
11399 var maxValue = this.columnEditor.hasOwnProperty('maxValue') ? this.columnEditor.maxValue : DEFAULT_MAX_VALUE$2;
11400 var defaultValue = this.editorParams.hasOwnProperty('sliderStartValue') ? this.editorParams.sliderStartValue : minValue;
11401 var step = this.columnEditor.hasOwnProperty('valueStep') ? this.columnEditor.valueStep : DEFAULT_STEP$2;
11402 if (this.editorParams.hideSliderNumber) {
11403 return "\n <div class=\"slider-editor\">\n <input type=\"range\" id=\"" + this._elementRangeInputId + "\"\n name=\"" + this._elementRangeInputId + "\"\n title=\"" + title + "\"\n defaultValue=\"" + defaultValue + "\" min=\"" + minValue + "\" max=\"" + maxValue + "\" step=\"" + step + "\"\n class=\"form-control slider-editor-input editor-" + fieldId + " range\" />\n </div>";
11404 }
11405 return "\n <div class=\"input-group slider-editor\">\n <input type=\"range\" id=\"" + this._elementRangeInputId + "\"\n name=\"" + this._elementRangeInputId + "\"\n title=\"" + title + "\"\n defaultValue=\"" + defaultValue + "\" min=\"" + minValue + "\" max=\"" + maxValue + "\" step=\"" + step + "\"\n class=\"form-control slider-editor-input editor-" + fieldId + " range\" />\n <div class=\"input-group-addon input-group-append slider-value\"><span class=\"input-group-text\" id=\"" + this._elementRangeOutputId + "\">" + defaultValue + "</span></div>\n </div>";
11406 };
11407 return SliderEditor;
11408 }());
11409
11410 /*
11411 * An example of a 'detached' editor.
11412 * KeyDown events are also handled to provide handling for Tab, Shift-Tab, Esc and Ctrl-Enter.
11413 */
11414 var TextEditor = /** @class */ (function () {
11415 function TextEditor(args) {
11416 this.args = args;
11417 this.init();
11418 }
11419 Object.defineProperty(TextEditor.prototype, "columnDef", {
11420 /** Get Column Definition object */
11421 get: function () {
11422 return this.args && this.args.column || {};
11423 },
11424 enumerable: true,
11425 configurable: true
11426 });
11427 Object.defineProperty(TextEditor.prototype, "columnEditor", {
11428 /** Get Column Editor object */
11429 get: function () {
11430 return this.columnDef && this.columnDef.internalColumnEditor && this.columnDef.internalColumnEditor || {};
11431 },
11432 enumerable: true,
11433 configurable: true
11434 });
11435 Object.defineProperty(TextEditor.prototype, "hasAutoCommitEdit", {
11436 get: function () {
11437 return this.args.grid.getOptions().autoCommitEdit;
11438 },
11439 enumerable: true,
11440 configurable: true
11441 });
11442 Object.defineProperty(TextEditor.prototype, "validator", {
11443 /** Get the Validator function, can be passed in Editor property or Column Definition */
11444 get: function () {
11445 return this.columnEditor.validator || this.columnDef.validator;
11446 },
11447 enumerable: true,
11448 configurable: true
11449 });
11450 TextEditor.prototype.init = function () {
11451 var _this = this;
11452 var columnId = this.columnDef && this.columnDef.id;
11453 var placeholder = this.columnEditor && this.columnEditor.placeholder || '';
11454 var title = this.columnEditor && this.columnEditor.title || '';
11455 this.$input = $("<input type=\"text\" role=\"presentation\" autocomplete=\"off\" class=\"editor-text editor-" + columnId + "\" placeholder=\"" + placeholder + "\" title=\"" + title + "\" />")
11456 .appendTo(this.args.container)
11457 .on('keydown.nav', function (event) {
11458 _this._lastInputEvent = event;
11459 if (event.keyCode === exports.KeyCode.LEFT || event.keyCode === exports.KeyCode.RIGHT) {
11460 event.stopImmediatePropagation();
11461 }
11462 });
11463 // the lib does not get the focus out event for some reason
11464 // so register it here
11465 if (this.hasAutoCommitEdit) {
11466 this.$input.on('focusout', function () { return _this.save(); });
11467 }
11468 setTimeout(function () {
11469 _this.$input.focus().select();
11470 }, 50);
11471 };
11472 TextEditor.prototype.destroy = function () {
11473 this.$input.off('keydown.nav focusout').remove();
11474 };
11475 TextEditor.prototype.focus = function () {
11476 this.$input.focus();
11477 };
11478 TextEditor.prototype.getValue = function () {
11479 return this.$input.val();
11480 };
11481 TextEditor.prototype.setValue = function (val) {
11482 this.$input.val(val);
11483 };
11484 TextEditor.prototype.loadValue = function (item) {
11485 var fieldName = this.columnDef && this.columnDef.field;
11486 // when it's a complex object, then pull the object name only, e.g.: "user.firstName" => "user"
11487 var fieldNameFromComplexObject = fieldName.indexOf('.') ? fieldName.substring(0, fieldName.indexOf('.')) : '';
11488 if (item && this.columnDef && (item.hasOwnProperty(fieldName) || item.hasOwnProperty(fieldNameFromComplexObject))) {
11489 this.defaultValue = item[fieldNameFromComplexObject || fieldName] || '';
11490 this.$input.val(this.defaultValue);
11491 this.$input[0].defaultValue = this.defaultValue;
11492 this.$input.select();
11493 }
11494 };
11495 TextEditor.prototype.serializeValue = function () {
11496 return this.$input.val();
11497 };
11498 TextEditor.prototype.applyValue = function (item, state) {
11499 var fieldName = this.columnDef && this.columnDef.field;
11500 // when it's a complex object, then pull the object name only, e.g.: "user.firstName" => "user"
11501 var fieldNameFromComplexObject = fieldName.indexOf('.') ? fieldName.substring(0, fieldName.indexOf('.')) : '';
11502 var validation = this.validate(state);
11503 item[fieldNameFromComplexObject || fieldName] = (validation && validation.valid) ? state : '';
11504 };
11505 TextEditor.prototype.isValueChanged = function () {
11506 var lastEvent = this._lastInputEvent && this._lastInputEvent.keyCode;
11507 if (this.columnEditor && this.columnEditor.alwaysSaveOnEnterKey && lastEvent === exports.KeyCode.ENTER) {
11508 return true;
11509 }
11510 return (!(this.$input.val() === '' && this.defaultValue === null)) && (this.$input.val() !== this.defaultValue);
11511 };
11512 TextEditor.prototype.save = function () {
11513 var validation = this.validate();
11514 if (validation && validation.valid) {
11515 if (this.hasAutoCommitEdit) {
11516 this.args.grid.getEditorLock().commitCurrentEdit();
11517 }
11518 else {
11519 this.args.commitChanges();
11520 }
11521 }
11522 };
11523 TextEditor.prototype.validate = function (inputValue) {
11524 var isRequired = this.columnEditor.required;
11525 var elmValue = (inputValue !== undefined) ? inputValue : this.$input && this.$input.val && this.$input.val();
11526 var errorMsg = this.columnEditor.errorMessage;
11527 if (this.validator) {
11528 var value = this.$input && this.$input.val && this.$input.val();
11529 return this.validator(value, this.args);
11530 }
11531 // by default the editor is almost always valid (except when it's required but not provided)
11532 if (isRequired && elmValue === '') {
11533 return {
11534 valid: false,
11535 msg: errorMsg || Constants.VALIDATION_REQUIRED_FIELD
11536 };
11537 }
11538 return {
11539 valid: true,
11540 msg: null
11541 };
11542 };
11543 return TextEditor;
11544 }());
11545
11546 var Editors = {
11547 /** AutoComplete Editor (using jQuery UI autocomplete feature) */
11548 autoComplete: AutoCompleteEditor,
11549 /** Checkbox Editor (uses native checkbox DOM element) */
11550 checkbox: CheckboxEditor,
11551 /** Date Picker Editor (which uses 3rd party lib "flatpickr") */
11552 date: DateEditor,
11553 /** Float Number Editor */
11554 float: FloatEditor,
11555 /** Integer Editor */
11556 integer: IntegerEditor,
11557 /** Long Text Editor (uses a textarea) */
11558 longText: LongTextEditor,
11559 /** Multiple Select editor (which uses 3rd party lib "multiple-select.js") */
11560 multipleSelect: MultipleSelectEditor,
11561 /** Single Select editor (which uses 3rd party lib "multiple-select.js") */
11562 singleSelect: SingleSelectEditor,
11563 /** Slider Editor */
11564 slider: SliderEditor,
11565 /** Text Editor */
11566 text: TextEditor
11567 };
11568
11569 var moment$b = moment_; // patch to fix rollup "moment has no default export" issue, document here https://github.com/rollup/rollup/issues/670
11570 /**
11571 * Find the option value from the following (in order of execution)
11572 * 1- Column Definition "params"
11573 * 2- Grid Options "formatterOptions"
11574 * 3- nothing found, return default value provided
11575 */
11576 function getValueFromParamsOrGridOptions(optionName, columnDef, grid, defaultValue) {
11577 var gridOptions = ((grid && typeof grid.getOptions === 'function') ? grid.getOptions() : {});
11578 var params = columnDef && columnDef.params;
11579 if (params && params.hasOwnProperty(optionName)) {
11580 return params[optionName];
11581 }
11582 else if (gridOptions.formatterOptions && gridOptions.formatterOptions.hasOwnProperty(optionName)) {
11583 return gridOptions.formatterOptions[optionName];
11584 }
11585 return defaultValue;
11586 }
11587 /** From a FieldType, return the associated date Formatter */
11588 function getAssociatedDateFormatter(fieldType, defaultSeparator) {
11589 var defaultDateFormat = mapMomentDateFormatWithFieldType(fieldType);
11590 return function (row, cell, value, columnDef, dataContext, grid) {
11591 var gridOptions = ((grid && typeof grid.getOptions === 'function') ? grid.getOptions() : {});
11592 var customSeparator = gridOptions && gridOptions.formatterOptions && gridOptions.formatterOptions.dateSeparator || defaultSeparator;
11593 var isDateValid = moment$b(value, defaultDateFormat, false).isValid();
11594 var outputDate = (value && isDateValid) ? moment$b(value).format(defaultDateFormat) : value;
11595 // user can customize the separator through the "formatterOptions"
11596 // if that is the case we need to replace the default "/" to the new separator
11597 if (outputDate && customSeparator !== defaultSeparator) {
11598 var regex = new RegExp(defaultSeparator, 'ig'); // find separator globally
11599 outputDate = outputDate.replace(regex, customSeparator);
11600 }
11601 return outputDate;
11602 };
11603 }
11604
11605 var arrayObjectToCsvFormatter = function (row, cell, value, columnDef, dataContext) {
11606 var columnParams = columnDef && columnDef.params || {};
11607 var propertyNames = columnParams.propertyNames;
11608 var parentObjectKeyName = columnParams.dataContextProperty;
11609 if (!parentObjectKeyName) {
11610 parentObjectKeyName = columnDef && columnDef.field && columnDef.field.split('.')[0]; // e.g. "users.roles" would be "users"
11611 }
11612 if (!propertyNames || !Array.isArray(propertyNames) || !parentObjectKeyName) {
11613 throw new Error("Formatters.arrayObjectToCsv requires you to pass an array of \"propertyNames\" (declared in \"params\") that you want to pull the data from.\n For example, if we have an array of user objects that have the property of firstName & lastName then we need to pass in your column definition:: { params: { propertyNames: ['firtName'] }}.\n Optionally, you can also pass the \"dataContextProperty\" if you wish to run this on another completely different field of the dataContext object.");
11614 }
11615 // the dataContext holds all the data, so we can find the values we want even when "value" argument might be null
11616 // e.g. if we want to use the propertyNames of ['firstName', 'lastName'] from the "users" array of objects
11617 if (dataContext[parentObjectKeyName] && Array.isArray(dataContext[parentObjectKeyName])) {
11618 // we will 1st get the object from the dataContext, then
11619 if (Array.isArray(dataContext[parentObjectKeyName]) && dataContext[parentObjectKeyName].length > 0) {
11620 var outputStrings_1 = [];
11621 dataContext[parentObjectKeyName].forEach(function (data) {
11622 var strings = [];
11623 // 2nd from that data loop through all propertyNames we want to use (e.g.: ['firstName', 'lastName'])
11624 propertyNames.forEach(function (prop) {
11625 strings.push(data[prop]);
11626 });
11627 // we will join these strings with spaces (e.g. 'John Doe' where 'John' was firstName and 'Doe' was lastName)
11628 outputStrings_1.push(strings.join(' '));
11629 });
11630 // finally join all the output strings by CSV (e.g.: 'John Doe, Jane Doe')
11631 var output = outputStrings_1.join(', ');
11632 return "<span title=\"" + output + "\">" + output + "</span>";
11633 }
11634 }
11635 return value;
11636 };
11637
11638 var arrayToCsvFormatter = function (row, cell, value, columnDef, dataContext) {
11639 if (value && Array.isArray(value) && value.length > 0) {
11640 var values = value.join(', ');
11641 return "<span title=\"" + values + "\">" + values + "</span>";
11642 }
11643 return value;
11644 };
11645
11646 var boldFormatter = function (row, cell, value, columnDef, dataContext) {
11647 return value ? "<b>" + value + "</b>" : '';
11648 };
11649
11650 var checkboxFormatter = function (row, cell, value, columnDef, dataContext) {
11651 return value ? '&#x2611;' : '';
11652 };
11653
11654 var checkmarkFormatter = function (row, cell, value, columnDef, dataContext) {
11655 return parseBoolean(value) ? "<i class=\"fa fa-check checkmark-icon\" aria-hidden=\"true\"></i>" : '';
11656 };
11657
11658 /**
11659 * A formatter to show the label property value of a params collection
11660 */
11661 var collectionFormatter = function (row, cell, value, columnDef, dataContext) {
11662 if (!value || !columnDef || !columnDef.params || !columnDef.params.collection
11663 || !columnDef.params.collection.length) {
11664 return value;
11665 }
11666 var params = columnDef.params, collection = columnDef.params.collection;
11667 var labelName = (params.customStructure) ? params.customStructure.label : 'label';
11668 var valueName = (params.customStructure) ? params.customStructure.value : 'value';
11669 if (Array.isArray(value)) {
11670 return arrayToCsvFormatter(row, cell, value.map(function (v) { return findOrDefault(collection, function (c) { return c[valueName] === v; })[labelName]; }), columnDef, dataContext);
11671 }
11672 return findOrDefault(collection, function (c) { return c[valueName] === value; })[labelName] || '';
11673 };
11674
11675 /**
11676 * A formatter to show the label property value of an editor collection
11677 */
11678 var collectionEditorFormatter = function (row, cell, value, columnDef, dataContext) {
11679 if (!value || !columnDef || !columnDef.internalColumnEditor || !columnDef.internalColumnEditor.collection
11680 || !columnDef.internalColumnEditor.collection.length) {
11681 return value;
11682 }
11683 var internalColumnEditor = columnDef.internalColumnEditor, collection = columnDef.internalColumnEditor.collection;
11684 var labelName = (internalColumnEditor.customStructure) ? internalColumnEditor.customStructure.label : 'label';
11685 var valueName = (internalColumnEditor.customStructure) ? internalColumnEditor.customStructure.value : 'value';
11686 if (Array.isArray(value)) {
11687 if (collection.every(function (x) { return typeof x === 'string'; })) {
11688 return arrayToCsvFormatter(row, cell, value.map(function (v) { return findOrDefault(collection, function (c) { return c === v; }); }), columnDef, dataContext);
11689 }
11690 else {
11691 return arrayToCsvFormatter(row, cell, value.map(function (v) { return findOrDefault(collection, function (c) { return c[valueName] === v; })[labelName]; }), columnDef, dataContext);
11692 }
11693 }
11694 return findOrDefault(collection, function (c) { return c[valueName] === value; })[labelName] || '';
11695 };
11696
11697 var complexObjectFormatter = function (row, cell, cellValue, columnDef, dataContext) {
11698 if (!columnDef) {
11699 return '';
11700 }
11701 var columnParams = columnDef.params || {};
11702 var complexFieldLabel = columnParams && columnParams.complexFieldLabel || columnDef.field;
11703 if (!complexFieldLabel) {
11704 throw new Error("For the Formatters.complexObject to work properly, you need to tell it which property of the complex object to use.\n There are 3 ways to provide it:\n 1- via the generic \"params\" with a \"complexFieldLabel\" property on your Column Definition, example: this.columnDefs = [{ id: 'user', field: 'user', params: { complexFieldLabel: 'user.firstName' } }]\n 2- via the generic \"params\" with a \"complexFieldLabel\" and a \"labelKey\" property on your Column Definition, example: this.columnDefs = [{ id: 'user', field: 'user', labelKey: 'firstName' params: { complexFieldLabel: 'user' } }]\n 3- via the field name that includes a dot notation, example: this.columnDefs = [{ id: 'user', field: 'user.firstName'}] ");
11705 }
11706 if (columnDef.labelKey && dataContext.hasOwnProperty(complexFieldLabel)) {
11707 return dataContext[complexFieldLabel] && dataContext[complexFieldLabel][columnDef.labelKey];
11708 }
11709 // when complexFieldLabel includes the dot ".", we will do the split and get the value from the complex object
11710 // however we also need to make sure that the complex objet exist, else we'll return the cell value (original value)
11711 if (typeof complexFieldLabel === 'string' && complexFieldLabel.indexOf('.') > 0) {
11712 return complexFieldLabel.split('.').reduce(function (obj, i) { return (obj && obj.hasOwnProperty(i) ? obj[i] : cellValue); }, dataContext);
11713 }
11714 return cellValue;
11715 };
11716
11717 var decimalFormatter = function (row, cell, value, columnDef, dataContext, grid) {
11718 var isNumber = (value === null || value === undefined || value === '') ? false : !isNaN(+value);
11719 var params = columnDef.params || {};
11720 var minDecimal = getValueFromParamsOrGridOptions('minDecimal', columnDef, grid, 2);
11721 var maxDecimal = getValueFromParamsOrGridOptions('maxDecimal', columnDef, grid, 2);
11722 var displayNegativeNumberWithParentheses = getValueFromParamsOrGridOptions('displayNegativeNumberWithParentheses', columnDef, grid, false);
11723 // @deprecated: decimalPlaces, minDecimalPlaces, maxDecimalPlaces
11724 // add these extra checks to support previous way of passing the decimal count
11725 if ((params.minDecimalPlaces !== null && params.minDecimalPlaces) || (params.decimalPlaces !== null && params.decimalPlaces)) {
11726 minDecimal = (params.minDecimalPlaces !== null && params.minDecimalPlaces) || (params.decimalPlaces !== null && params.decimalPlaces);
11727 }
11728 if (params.maxDecimalPlaces !== null && params.maxDecimalPlaces) {
11729 maxDecimal = (params.maxDecimalPlaces !== null && params.maxDecimalPlaces);
11730 }
11731 if (isNumber) {
11732 return formatNumber(value, minDecimal, maxDecimal, displayNegativeNumberWithParentheses);
11733 }
11734 return value;
11735 };
11736
11737 var deleteIconFormatter = function (row, cell, value, columnDef, dataContext) {
11738 return "<i class=\"fa fa-trash pointer delete-icon\" aria-hidden=\"true\"></i>";
11739 };
11740
11741 var dollarColoredBoldFormatter = function (row, cell, value, columnDef, dataContext, grid) {
11742 var isNumber = (value === null || value === undefined || value === '') ? false : !isNaN(+value);
11743 var minDecimal = getValueFromParamsOrGridOptions('minDecimal', columnDef, grid, 2);
11744 var maxDecimal = getValueFromParamsOrGridOptions('maxDecimal', columnDef, grid, 4);
11745 var displayNegativeNumberWithParentheses = getValueFromParamsOrGridOptions('displayNegativeNumberWithParentheses', columnDef, grid, false);
11746 if (isNumber) {
11747 var colorStyle = (value >= 0) ? 'green' : 'red';
11748 var formattedNumber = formatNumber(value, minDecimal, maxDecimal, displayNegativeNumberWithParentheses, '$');
11749 return "<span style=\"color:" + colorStyle + "; font-weight:bold;\">" + formattedNumber + "</span>";
11750 }
11751 return value;
11752 };
11753
11754 var dollarColoredFormatter = function (row, cell, value, columnDef, dataContext, grid) {
11755 var isNumber = (value === null || value === undefined || value === '') ? false : !isNaN(+value);
11756 var minDecimal = getValueFromParamsOrGridOptions('minDecimal', columnDef, grid, 2);
11757 var maxDecimal = getValueFromParamsOrGridOptions('maxDecimal', columnDef, grid, 4);
11758 var displayNegativeNumberWithParentheses = getValueFromParamsOrGridOptions('displayNegativeNumberWithParentheses', columnDef, grid, false);
11759 if (isNumber) {
11760 var colorStyle = (value >= 0) ? 'green' : 'red';
11761 var formattedNumber = formatNumber(value, minDecimal, maxDecimal, displayNegativeNumberWithParentheses, '$');
11762 return "<span style=\"color:" + colorStyle + "\">" + formattedNumber + "</span>";
11763 }
11764 return value;
11765 };
11766
11767 var dollarFormatter = function (row, cell, value, columnDef, dataContext, grid) {
11768 var isNumber = (value === null || value === undefined || value === '') ? false : !isNaN(+value);
11769 var minDecimal = getValueFromParamsOrGridOptions('minDecimal', columnDef, grid, 2);
11770 var maxDecimal = getValueFromParamsOrGridOptions('maxDecimal', columnDef, grid, 4);
11771 var displayNegativeNumberWithParentheses = getValueFromParamsOrGridOptions('displayNegativeNumberWithParentheses', columnDef, grid, false);
11772 if (isNumber) {
11773 return formatNumber(value, minDecimal, maxDecimal, displayNegativeNumberWithParentheses, '$');
11774 }
11775 return value;
11776 };
11777
11778 var editIconFormatter = function (row, cell, value, columnDef, dataContext) {
11779 return "<i class=\"fa fa-pencil pointer edit-icon\" aria-hidden=\"true\"></i>";
11780 };
11781
11782 var DOMPurify$3 = DOMPurify_; // patch to fix rollup to work
11783 /**
11784 * Takes an hyperlink cell value and transforms it into a real hyperlink, given that the value starts with 1 of these (http|ftp|https).
11785 * The structure will be "<a href="hyperlink">hyperlink</a>"
11786 *
11787 * You can optionally change the hyperlink text displayed by using the generic params "hyperlinkText" in the column definition
11788 * For example: { id: 'link', field: 'link', params: { hyperlinkText: 'Company Website' } } will display "<a href="link">Company Website</a>"
11789 *
11790 * You can also optionally provide the hyperlink URL by using the generic params "hyperlinkUrl" in the column definition
11791 * For example: { id: 'link', field: 'link', params: { hyperlinkText: 'Company Website', hyperlinkUrl: 'http://www.somewhere.com' } } will display "<a href="http://www.somewhere.com">Company Website</a>"
11792 */
11793 var hyperlinkFormatter = function (row, cell, value, columnDef, dataContext) {
11794 var columnParams = columnDef && columnDef.params || {};
11795 var displayedText = columnParams.hyperlinkText ? columnParams.hyperlinkText : value;
11796 displayedText = DOMPurify$3.sanitize(displayedText || '');
11797 var outputLink = columnParams.hyperlinkUrl ? columnParams.hyperlinkUrl : value;
11798 outputLink = DOMPurify$3.sanitize(outputLink || '');
11799 var matchUrl = outputLink.match(/^(http|ftp|https):\/\/[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&amp;:\/~\+#]*[\w\-\@?^=%&amp;\/~\+#])?/i);
11800 if (matchUrl && Array.isArray(matchUrl) && matchUrl.length > 0) {
11801 var finalUrl = matchUrl[0];
11802 return "<a href=\"" + finalUrl + "\">" + displayedText + "</a>";
11803 }
11804 return value;
11805 };
11806
11807 var iconFormatter = function (row, cell, value, columnDef, dataContext) {
11808 var columnParams = columnDef && columnDef.params || {};
11809 var icon = columnParams.icon || columnParams.formatterIcon;
11810 if (!icon) {
11811 throw new Error("You must provide the \"icon\" or \"formatterIcon\" via the generic \"params\" options (e.g.: { formatter: Formatters.icon, params: { formatterIcon: 'fa fa-search' }}");
11812 }
11813 return "<i class=\"" + icon + "\" aria-hidden=\"true\"></i>";
11814 };
11815
11816 var infoIconFormatter = function (row, cell, value, columnDef, dataContext) {
11817 return "<i class=\"fa fa-info-circle pointer info-icon\" aria-hidden=\"true\"></i>";
11818 };
11819
11820 var italicFormatter = function (row, cell, value, columnDef, dataContext) {
11821 return value ? "<i>" + value + "</i>" : '';
11822 };
11823
11824 var lowercaseFormatter = function (row, cell, value, columnDef, dataContext) {
11825 // make sure the value is a string
11826 if (value !== undefined && typeof value !== 'string') {
11827 value = value + '';
11828 }
11829 return value ? value.toLowerCase() : '';
11830 };
11831
11832 /**
11833 * Takes a value display it according to a mask provided
11834 * e.: 1234567890 with mask "(000) 000-0000" will display "(123) 456-7890"
11835 */
11836 var maskFormatter = function (row, cell, value, columnDef, dataContext) {
11837 var params = columnDef.params || {};
11838 var mask = params.mask;
11839 if (!mask) {
11840 throw new Error("You must provide a \"mask\" via the generic \"params\" options (e.g.: { formatter: Formatters.mask, params: { mask: '000-000' }}");
11841 }
11842 if (value) {
11843 var i_1 = 0;
11844 var v_1 = value.toString();
11845 return mask.replace(/[09A]/gi, function () { return v_1[i_1++] || ''; });
11846 }
11847 return value;
11848 };
11849
11850 var multipleFormatter = function (row, cell, value, columnDef, dataContext, grid) {
11851 var e_1, _a;
11852 var params = columnDef.params || {};
11853 if (!params.formatters || !Array.isArray(params.formatters)) {
11854 throw new Error("The multiple formatter requires the \"formatters\" to be provided as a column params.\n For example: this.columnDefinitions = [{ id: title, field: title, formatter: Formatters.multiple, params: { formatters: [Formatters.lowercase, Formatters.uppercase] }");
11855 }
11856 var formatters = params.formatters;
11857 // loop through all Formatters, the value of 1st formatter will be used by 2nd formatter and so on.
11858 // they are piped and executed in sequences
11859 var currentValue = value;
11860 try {
11861 for (var formatters_1 = __values(formatters), formatters_1_1 = formatters_1.next(); !formatters_1_1.done; formatters_1_1 = formatters_1.next()) {
11862 var formatter = formatters_1_1.value;
11863 currentValue = formatter(row, cell, currentValue, columnDef, dataContext, grid);
11864 }
11865 }
11866 catch (e_1_1) { e_1 = { error: e_1_1 }; }
11867 finally {
11868 try {
11869 if (formatters_1_1 && !formatters_1_1.done && (_a = formatters_1.return)) _a.call(formatters_1);
11870 }
11871 finally { if (e_1) throw e_1.error; }
11872 }
11873 return currentValue;
11874 };
11875
11876 var percentFormatter = function (row, cell, value, columnDef, dataContext, grid) {
11877 var isNumber = (value === null || value === undefined || value === '') ? false : !isNaN(+value);
11878 var minDecimal = getValueFromParamsOrGridOptions('minDecimal', columnDef, grid);
11879 var maxDecimal = getValueFromParamsOrGridOptions('maxDecimal', columnDef, grid);
11880 var displayNegativeNumberWithParentheses = getValueFromParamsOrGridOptions('displayNegativeNumberWithParentheses', columnDef, grid, false);
11881 if (isNumber) {
11882 var percentValue = value * 100;
11883 return formatNumber(percentValue, minDecimal, maxDecimal, displayNegativeNumberWithParentheses, '', '%');
11884 }
11885 return value;
11886 };
11887
11888 var percentCompleteBarFormatter = function (row, cell, value, columnDef, dataContext) {
11889 var isNumber = (value === null || value === undefined || value === '') ? false : !isNaN(+value);
11890 if (!isNumber) {
11891 return '';
11892 }
11893 var color = '';
11894 var inputNumber = parseFloat(value);
11895 if (inputNumber > 100) {
11896 inputNumber = 100;
11897 }
11898 if (inputNumber < 30) {
11899 color = 'red';
11900 }
11901 else if (inputNumber < 70) {
11902 color = 'silver';
11903 }
11904 else {
11905 color = 'green';
11906 }
11907 return "<span class=\"percent-complete-bar\" style=\"background:" + color + "; width:" + inputNumber + "%\"></span>";
11908 };
11909
11910 var percentCompleteFormatter = function (row, cell, value, columnDef, dataContext, grid) {
11911 var isNumber = (value === null || value === undefined || value === '') ? false : !isNaN(+value);
11912 var minDecimal = getValueFromParamsOrGridOptions('minDecimal', columnDef, grid);
11913 var maxDecimal = getValueFromParamsOrGridOptions('maxDecimal', columnDef, grid);
11914 var displayNegativeNumberWithParentheses = getValueFromParamsOrGridOptions('displayNegativeNumberWithParentheses', columnDef, grid, false);
11915 if (isNumber) {
11916 var colorStyle = (value < 50) ? 'red' : 'green';
11917 var formattedNumber = formatNumber(value, minDecimal, maxDecimal, displayNegativeNumberWithParentheses, '', '%');
11918 var outputFormattedValue = value > 100 ? '100%' : formattedNumber;
11919 return "<span style='color:" + colorStyle + "'>" + outputFormattedValue + "</span>";
11920 }
11921 return value;
11922 };
11923
11924 var percentSymbolFormatter = function (row, cell, value, columnDef, dataContext, grid) {
11925 var isNumber = (value === null || value === undefined || value === '') ? false : !isNaN(+value);
11926 var minDecimal = getValueFromParamsOrGridOptions('minDecimal', columnDef, grid);
11927 var maxDecimal = getValueFromParamsOrGridOptions('maxDecimal', columnDef, grid);
11928 var displayNegativeNumberWithParentheses = getValueFromParamsOrGridOptions('displayNegativeNumberWithParentheses', columnDef, grid, false);
11929 if (isNumber) {
11930 return formatNumber(value, minDecimal, maxDecimal, displayNegativeNumberWithParentheses, '', '%');
11931 }
11932 return value;
11933 };
11934
11935 var progressBarFormatter = function (row, cell, value, columnDef, dataContext) {
11936 var isNumber = (value === null || value === undefined || value === '') ? false : !isNaN(+value);
11937 if (!isNumber) {
11938 return '';
11939 }
11940 var color = '';
11941 var inputNumber = parseFloat(value);
11942 if (inputNumber > 100) {
11943 inputNumber = 100;
11944 }
11945 if (inputNumber < 30) {
11946 color = 'danger';
11947 }
11948 else if (inputNumber < 70) {
11949 color = 'warning';
11950 }
11951 else {
11952 color = 'success';
11953 }
11954 var output = "<div class=\"progress\">\n <div class=\"progress-bar progress-bar-" + color + " bg-" + color + "\" role=\"progressbar\" aria-valuenow=\"" + inputNumber + "\" aria-valuemin=\"0\" aria-valuemax=\"100\" style=\"min-width: 2em; width: " + inputNumber + "%;\">\n " + inputNumber + "%\n </div>\n </div>";
11955 return output.replace(/\s{2,}/g, ' ').trim();
11956 };
11957
11958 /** Takes a cell value and translates it with the "ngx-translate" service */
11959 var translateFormatter = function (row, cell, value, columnDef, dataContext, grid) {
11960 var gridOptions = (grid && typeof grid.getOptions === 'function') ? grid.getOptions() : {};
11961 var translate = gridOptions.i18n || (columnDef && columnDef.params && columnDef.params.i18n);
11962 if (!translate || typeof translate.instant !== 'function') {
11963 throw new Error("The translate formatter requires the \"ngx-translate\" Service to be provided as a Grid Options or Column Definition \"i18n\".\n For example: this.gridOptions = { enableTranslate: true, i18n: this.translate }");
11964 }
11965 // make sure the value is a string (for example a boolean value would throw an error)
11966 if (value !== undefined && value !== null && typeof value !== 'string') {
11967 value = value + '';
11968 }
11969 return value ? translate.instant(value) : '';
11970 };
11971
11972 /** Takes a boolean value, cast it to upperCase string and finally translates it with the "ngx-translate" service */
11973 var translateBooleanFormatter = function (row, cell, value, columnDef, dataContext, grid) {
11974 var gridOptions = (grid && typeof grid.getOptions === 'function') ? grid.getOptions() : {};
11975 var translate = gridOptions.i18n || (columnDef && columnDef.params && columnDef.params.i18n);
11976 if (!translate || typeof translate.instant !== 'function') {
11977 throw new Error("The translate formatter requires the \"ngx-translate\" Service to be provided as a Grid Options or Column Definition \"i18n\".\n For example: this.gridOptions = { enableTranslate: true, i18n: this.translate }");
11978 }
11979 // make sure the value is a string (for example a boolean value would throw an error)
11980 if (value !== undefined && value !== null && typeof value !== 'string') {
11981 value = value + '';
11982 }
11983 return value ? translate.instant(value.toUpperCase()) : '';
11984 };
11985
11986 var uppercaseFormatter = function (row, cell, value, columnDef, dataContext) {
11987 // make sure the value is a string
11988 if (value !== undefined && typeof value !== 'string') {
11989 value = value + '';
11990 }
11991 return value ? value.toUpperCase() : '';
11992 };
11993
11994 var yesNoFormatter = function (row, cell, value, columnDef, dataContext) {
11995 return value ? 'Yes' : 'No';
11996 };
11997
11998 /** Provides a list of different Formatters that will change the cell value displayed in the UI */
11999 var Formatters = {
12000 /**
12001 * Takes an array of complex objects converts it to a comma delimited string.
12002 * Requires to pass an array of "propertyNames" in the column definition the generic "params" property
12003 * For example, if we have an array of user objects that have the property of firstName & lastName then we need to pass in your column definition::
12004 * { params: { propertyNames: ['firtName'] }}
12005 */
12006 arrayObjectToCsv: arrayObjectToCsvFormatter,
12007 /** Takes an array of string and converts it to a comma delimited string */
12008 arrayToCsv: arrayToCsvFormatter,
12009 /** show value in bold font weight */
12010 bold: boldFormatter,
12011 /** When value is filled (true), it will display a checkbox Unicode icon */
12012 checkbox: checkboxFormatter,
12013 /** When value is filled (true), it will display a Font-Awesome icon (fa-check) */
12014 checkmark: checkmarkFormatter,
12015 /**
12016 * Takes a complex data object and return the data under that property (for example: "user.firstName" will return the first name "John")
12017 * You can pass the complex structure in the "field" or the "params: { complexField: string }" properties.
12018 * For example::
12019 * this.columnDefs = [{ id: 'username', field: 'user.firstName', ... }]
12020 * OR this.columnDefs = [{ id: 'username', field: 'user', params: { complexField: 'user.firstName' }, ... }]
12021 */
12022 complexObject: complexObjectFormatter,
12023 /**
12024 * Looks up values from the columnDefinition.params.collection property and displays the label in CSV or string format
12025 * @example
12026 * // the grid will display 'foo' and 'bar' and not 1 and 2 from your dataset
12027 * { params: { collection: [{ value: 1, label: 'foo'}, {value: 2, label: 'bar' }] }}
12028 * const dataset = [1, 2];
12029 */
12030 collection: collectionFormatter,
12031 /**
12032 * Roughly the same as the "collectionFormatter" except that it
12033 * looks up values from the columnDefinition.editor.collection (instead of params) property and displays the label in CSV or string format
12034 * @example
12035 * // the grid will display 'foo' and 'bar' and not 1 and 2 from your dataset
12036 * { editor: { collection: [{ value: 1, label: 'foo'}, {value: 2, label: 'bar' }] }}
12037 * const dataset = [1, 2];
12038 */
12039 collectionEditor: collectionEditorFormatter,
12040 /** Takes a Date object and displays it as an ISO Date format (YYYY-MM-DD) */
12041 dateIso: getAssociatedDateFormatter(exports.FieldType.dateIso, '-'),
12042 /** Takes a Date object and displays it as an ISO Date+Time format (YYYY-MM-DD HH:mm:ss) */
12043 dateTimeIso: getAssociatedDateFormatter(exports.FieldType.dateTimeIso, '-'),
12044 /** Takes a Date object and displays it as an ISO Date+Time (without seconds) format (YYYY-MM-DD HH:mm) */
12045 dateTimeShortIso: getAssociatedDateFormatter(exports.FieldType.dateTimeShortIso, '-'),
12046 /** Takes a Date object and displays it as an ISO Date+Time+(am/pm) format (YYYY-MM-DD h:mm:ss a) */
12047 dateTimeIsoAmPm: getAssociatedDateFormatter(exports.FieldType.dateTimeIsoAmPm, '-'),
12048 /** Takes a Date object and displays it as an Euro Date format (DD/MM/YYYY) */
12049 dateEuro: getAssociatedDateFormatter(exports.FieldType.dateEuro, '/'),
12050 /** Takes a Date object and displays it as an Euro Date+Time format (DD/MM/YYYY HH:mm:ss) */
12051 dateTimeEuro: getAssociatedDateFormatter(exports.FieldType.dateTimeEuro, '/'),
12052 /** Takes a Date object and displays it as an Euro Date+Time (without seconds) format (DD/MM/YYYY HH:mm) */
12053 dateTimeShortEuro: getAssociatedDateFormatter(exports.FieldType.dateTimeShortEuro, '/'),
12054 /** Takes a Date object and displays it as an Euro Date+Time+(am/pm) format (DD/MM/YYYY hh:mm:ss a) */
12055 dateTimeEuroAmPm: getAssociatedDateFormatter(exports.FieldType.dateTimeEuroAmPm, '/'),
12056 /** Takes a Date object and displays it as an US Date format (MM/DD/YYYY) */
12057 dateUs: getAssociatedDateFormatter(exports.FieldType.dateUs, '/'),
12058 /** Takes a Date object and displays it as an US Date+Time format (MM/DD/YYYY HH:mm:ss) */
12059 dateTimeUs: getAssociatedDateFormatter(exports.FieldType.dateTimeUs, '/'),
12060 /** Takes a Date object and displays it as an US Date+Time (without seconds) format (MM/DD/YYYY HH:mm:ss) */
12061 dateTimeShortUs: getAssociatedDateFormatter(exports.FieldType.dateTimeShortUs, '/'),
12062 /** Takes a Date object and displays it as an US Date+Time+(am/pm) format (MM/DD/YYYY hh:mm:ss a) */
12063 dateTimeUsAmPm: getAssociatedDateFormatter(exports.FieldType.dateTimeUsAmPm, '/'),
12064 /** Displays a Font-Awesome delete icon (fa-trash) */
12065 deleteIcon: deleteIconFormatter,
12066 /**
12067 * Display the value as x decimals formatted, defaults to 2 decimals.
12068 * You can pass "decimalPlaces" or "minDecimalPlaces" and/or "maxDecimalPlaces" to the "params" property.
12069 * For example:: `{ formatter: Formatters.decimal, params: { decimalPlaces: 3 }}`
12070 * The property "decimalPlaces" is an alias of "minDecimalPlaces"
12071 */
12072 decimal: decimalFormatter,
12073 /** Display the value as 2 decimals formatted with dollar sign '$' at the end of of the value */
12074 dollar: dollarFormatter,
12075 /** Display the value as 2 decimals formatted with dollar sign '$' at the end of of the value, change color of text to red/green on negative/positive value */
12076 dollarColored: dollarColoredFormatter,
12077 /** Display the value as 2 decimals formatted with dollar sign '$' at the end of of the value, change color of text to red/green on negative/positive value, show it in bold font weight as well */
12078 dollarColoredBold: dollarColoredBoldFormatter,
12079 /** Displays a Font-Awesome edit icon (fa-pencil) */
12080 editIcon: editIconFormatter,
12081 /**
12082 * Takes an hyperlink cell value and transforms it into a real hyperlink, given that the value starts with 1 of these (http|ftp|https).
12083 * The structure will be "<a href="hyperlink">hyperlink</a>"
12084 * You can optionally change the hyperlink text displayed by using the generic params "hyperlinkText" in the column definition
12085 * For example: { id: 'link', field: 'link', params: { hyperlinkText: 'Company Website' } } will display "<a href="link">Company Website</a>"
12086 */
12087 hyperlink: hyperlinkFormatter,
12088 /** Display whichever icon you want (library agnostic, it could be Font-Awesome or any other) */
12089 icon: iconFormatter,
12090 /** Displays a Font-Awesome edit icon (fa-info-circle) */
12091 infoIcon: infoIconFormatter,
12092 /** show input text value as italic text */
12093 italic: italicFormatter,
12094 /** Takes a value and displays it all lowercase */
12095 lowercase: lowercaseFormatter,
12096 /**
12097 * Takes a value display it according to a mask provided
12098 * e.: 1234567890 with mask "(000) 000-0000" will display "(123) 456-7890"
12099 */
12100 mask: maskFormatter,
12101 /**
12102 * You can pipe multiple formatters (executed in sequence), use params to pass the list of formatters.
12103 * Requires to pass an array of "formatters" in the column definition the generic "params" property
12104 * For example::
12105 * { field: 'title', formatter: Formatters.multiple, params: { formatters: [ Formatters.lowercase, Formatters.uppercase ] }
12106 */
12107 multiple: multipleFormatter,
12108 /** Takes a cell value number (between 0.0-1.0) and displays a red (<50) or green (>=50) bar */
12109 percent: percentFormatter,
12110 /** Takes a cell value number (between 0.0-100) and displays a red (<50) or green (>=50) bar */
12111 percentComplete: percentCompleteFormatter,
12112 /** Takes a cell value number (between 0-100) and displays Bootstrap "percent-complete-bar" a red (<30), silver (>30 & <70) or green (>=70) bar */
12113 percentCompleteBar: percentCompleteBarFormatter,
12114 /** Takes a cell value number (between 0-100) and add the "%" after the number */
12115 percentSymbol: percentSymbolFormatter,
12116 /** Takes a cell value number (between 0-100) and displays Bootstrap "progress-bar" a red (<30), silver (>30 & <70) or green (>=70) bar */
12117 progressBar: progressBarFormatter,
12118 /** Takes a cell value and translates it (i18n). Requires an instance of the Translate Service:: `i18n: this.translate */
12119 translate: translateFormatter,
12120 /** Takes a boolean value, cast it to upperCase string and finally translates it (i18n). */
12121 translateBoolean: translateBooleanFormatter,
12122 /** Takes a value and displays it all uppercase */
12123 uppercase: uppercaseFormatter,
12124 /** Takes a boolean value and display a string 'Yes' or 'No' */
12125 yesNo: yesNoFormatter
12126 };
12127
12128 var avgTotalsPercentageFormatter = function (totals, columnDef, grid) {
12129 var field = columnDef.field || '';
12130 var val = totals.avg && totals.avg[field];
12131 var params = columnDef && columnDef.params;
12132 var prefix = params && params.groupFormatterPrefix || '';
12133 var suffix = params && params.groupFormatterSuffix || '';
12134 var minDecimal = getValueFromParamsOrGridOptions('minDecimal', columnDef, grid);
12135 var maxDecimal = getValueFromParamsOrGridOptions('maxDecimal', columnDef, grid);
12136 var displayNegativeNumberWithParentheses = getValueFromParamsOrGridOptions('displayNegativeNumberWithParentheses', columnDef, grid, false);
12137 if (val != null && !isNaN(+val)) {
12138 if (val < 0) {
12139 val = Math.abs(val);
12140 if (!displayNegativeNumberWithParentheses) {
12141 prefix += '-';
12142 }
12143 else {
12144 if (isNaN(minDecimal) && isNaN(maxDecimal)) {
12145 return prefix + "(" + Math.round(val) + "%)" + suffix;
12146 }
12147 return prefix + "(" + decimalFormatted(val, minDecimal, maxDecimal) + "%)" + suffix;
12148 }
12149 }
12150 if (isNaN(minDecimal) && isNaN(maxDecimal)) {
12151 return "" + prefix + Math.round(val) + "%" + suffix;
12152 }
12153 return "" + prefix + decimalFormatted(val, minDecimal, maxDecimal) + "%" + suffix;
12154 }
12155 return '';
12156 };
12157
12158 var avgTotalsDollarFormatter = function (totals, columnDef, grid) {
12159 var field = columnDef.field || '';
12160 var val = totals.avg && totals.avg[field];
12161 var params = columnDef && columnDef.params;
12162 var prefix = params && params.groupFormatterPrefix || '';
12163 var suffix = params && params.groupFormatterSuffix || '';
12164 var minDecimal = getValueFromParamsOrGridOptions('minDecimal', columnDef, grid, 2);
12165 var maxDecimal = getValueFromParamsOrGridOptions('maxDecimal', columnDef, grid, 4);
12166 var displayNegativeNumberWithParentheses = getValueFromParamsOrGridOptions('displayNegativeNumberWithParentheses', columnDef, grid, false);
12167 if (val != null && !isNaN(+val)) {
12168 var formattedNumber = formatNumber(val, minDecimal, maxDecimal, displayNegativeNumberWithParentheses, '$');
12169 return "" + prefix + formattedNumber + suffix;
12170 }
12171 return '';
12172 };
12173
12174 var avgTotalsFormatter = function (totals, columnDef, grid) {
12175 var field = columnDef.field || '';
12176 var val = totals.avg && totals.avg[field];
12177 var params = columnDef && columnDef.params;
12178 var prefix = params && params.groupFormatterPrefix || '';
12179 var suffix = params && params.groupFormatterSuffix || '';
12180 var minDecimal = getValueFromParamsOrGridOptions('minDecimal', columnDef, grid);
12181 var maxDecimal = getValueFromParamsOrGridOptions('maxDecimal', columnDef, grid);
12182 var displayNegativeNumberWithParentheses = getValueFromParamsOrGridOptions('displayNegativeNumberWithParentheses', columnDef, grid, false);
12183 if (val != null && !isNaN(+val)) {
12184 if (val < 0) {
12185 val = Math.abs(val);
12186 if (!displayNegativeNumberWithParentheses) {
12187 prefix += '-';
12188 }
12189 else {
12190 if (isNaN(minDecimal) && isNaN(maxDecimal)) {
12191 return prefix + "(" + Math.round(val) + ")" + suffix;
12192 }
12193 return prefix + "(" + decimalFormatted(val, minDecimal, maxDecimal) + ")" + suffix;
12194 }
12195 }
12196 if (isNaN(minDecimal) && isNaN(maxDecimal)) {
12197 return "" + prefix + Math.round(val) + suffix;
12198 }
12199 return "" + prefix + decimalFormatted(val, minDecimal, maxDecimal) + suffix;
12200 }
12201 return '';
12202 };
12203
12204 var minTotalsFormatter = function (totals, columnDef, grid) {
12205 var field = columnDef.field || '';
12206 var val = totals.min && totals.min[field];
12207 var params = columnDef && columnDef.params;
12208 var prefix = params && params.groupFormatterPrefix || '';
12209 var suffix = params && params.groupFormatterSuffix || '';
12210 var minDecimal = getValueFromParamsOrGridOptions('minDecimal', columnDef, grid);
12211 var maxDecimal = getValueFromParamsOrGridOptions('maxDecimal', columnDef, grid);
12212 var displayNegativeNumberWithParentheses = getValueFromParamsOrGridOptions('displayNegativeNumberWithParentheses', columnDef, grid, false);
12213 if (val != null && !isNaN(+val)) {
12214 var formattedNumber = formatNumber(val, minDecimal, maxDecimal, displayNegativeNumberWithParentheses);
12215 return "" + prefix + formattedNumber + suffix;
12216 }
12217 return '';
12218 };
12219
12220 var maxTotalsFormatter = function (totals, columnDef, grid) {
12221 var field = columnDef.field || '';
12222 var val = totals.max && totals.max[field];
12223 var params = columnDef && columnDef.params;
12224 var prefix = params && params.groupFormatterPrefix || '';
12225 var suffix = params && params.groupFormatterSuffix || '';
12226 var minDecimal = getValueFromParamsOrGridOptions('minDecimal', columnDef, grid);
12227 var maxDecimal = getValueFromParamsOrGridOptions('maxDecimal', columnDef, grid);
12228 var displayNegativeNumberWithParentheses = getValueFromParamsOrGridOptions('displayNegativeNumberWithParentheses', columnDef, grid, false);
12229 if (val != null && !isNaN(+val)) {
12230 var formattedNumber = formatNumber(val, minDecimal, maxDecimal, displayNegativeNumberWithParentheses);
12231 return "" + prefix + formattedNumber + suffix;
12232 }
12233 return '';
12234 };
12235
12236 var sumTotalsColoredFormatter = function (totals, columnDef, grid) {
12237 var field = columnDef.field || '';
12238 var val = totals.sum && totals.sum[field];
12239 var params = columnDef && columnDef.params;
12240 var prefix = params && params.groupFormatterPrefix || '';
12241 var suffix = params && params.groupFormatterSuffix || '';
12242 var minDecimal = getValueFromParamsOrGridOptions('minDecimal', columnDef, grid);
12243 var maxDecimal = getValueFromParamsOrGridOptions('maxDecimal', columnDef, grid);
12244 var displayNegativeNumberWithParentheses = getValueFromParamsOrGridOptions('displayNegativeNumberWithParentheses', columnDef, grid, false);
12245 if (val != null && !isNaN(+val)) {
12246 var colorStyle = (val >= 0) ? 'green' : 'red';
12247 var formattedNumber = formatNumber(val, minDecimal, maxDecimal, displayNegativeNumberWithParentheses);
12248 return "<span style=\"color:" + colorStyle + "\">" + prefix + formattedNumber + suffix + "</span>";
12249 }
12250 return '';
12251 };
12252
12253 var sumTotalsDollarColoredBoldFormatter = function (totals, columnDef, grid) {
12254 var field = columnDef.field || '';
12255 var val = totals.sum && totals.sum[field];
12256 var params = columnDef && columnDef.params;
12257 var prefix = params && params.groupFormatterPrefix || '';
12258 var suffix = params && params.groupFormatterSuffix || '';
12259 var minDecimal = getValueFromParamsOrGridOptions('minDecimal', columnDef, grid, 2);
12260 var maxDecimal = getValueFromParamsOrGridOptions('maxDecimal', columnDef, grid, 4);
12261 var displayNegativeNumberWithParentheses = getValueFromParamsOrGridOptions('displayNegativeNumberWithParentheses', columnDef, grid, false);
12262 if (val != null && !isNaN(+val)) {
12263 var colorStyle = (val >= 0) ? 'green' : 'red';
12264 var formattedNumber = formatNumber(val, minDecimal, maxDecimal, displayNegativeNumberWithParentheses, '$');
12265 return "<span style=\"color:" + colorStyle + "; font-weight: bold;\">" + prefix + formattedNumber + suffix + "</span>";
12266 }
12267 return '';
12268 };
12269
12270 var sumTotalsDollarColoredFormatter = function (totals, columnDef, grid) {
12271 var field = columnDef.field || '';
12272 var val = totals.sum && totals.sum[field];
12273 var params = columnDef && columnDef.params;
12274 var prefix = params && params.groupFormatterPrefix || '';
12275 var suffix = params && params.groupFormatterSuffix || '';
12276 var minDecimal = getValueFromParamsOrGridOptions('minDecimal', columnDef, grid, 2);
12277 var maxDecimal = getValueFromParamsOrGridOptions('maxDecimal', columnDef, grid, 4);
12278 var displayNegativeNumberWithParentheses = getValueFromParamsOrGridOptions('displayNegativeNumberWithParentheses', columnDef, grid, false);
12279 if (val != null && !isNaN(+val)) {
12280 var colorStyle = (val >= 0) ? 'green' : 'red';
12281 var formattedNumber = formatNumber(val, minDecimal, maxDecimal, displayNegativeNumberWithParentheses, '$');
12282 return "<span style=\"color:" + colorStyle + "\">" + prefix + formattedNumber + suffix + "</span>";
12283 }
12284 return '';
12285 };
12286
12287 var sumTotalsDollarBoldFormatter = function (totals, columnDef, grid) {
12288 var field = columnDef.field || '';
12289 var val = totals.sum && totals.sum[field];
12290 var params = columnDef && columnDef.params;
12291 var prefix = params && params.groupFormatterPrefix || '';
12292 var suffix = params && params.groupFormatterSuffix || '';
12293 var minDecimal = getValueFromParamsOrGridOptions('minDecimal', columnDef, grid, 2);
12294 var maxDecimal = getValueFromParamsOrGridOptions('maxDecimal', columnDef, grid, 4);
12295 var displayNegativeNumberWithParentheses = getValueFromParamsOrGridOptions('displayNegativeNumberWithParentheses', columnDef, grid, false);
12296 if (val != null && !isNaN(+val)) {
12297 var formattedNumber = formatNumber(val, minDecimal, maxDecimal, displayNegativeNumberWithParentheses, '$');
12298 return "<b>" + prefix + formattedNumber + suffix + "</b>";
12299 }
12300 return '';
12301 };
12302
12303 var sumTotalsDollarFormatter = function (totals, columnDef, grid) {
12304 var field = columnDef.field || '';
12305 var val = totals.sum && totals.sum[field];
12306 var params = columnDef && columnDef.params;
12307 var prefix = params && params.groupFormatterPrefix || '';
12308 var suffix = params && params.groupFormatterSuffix || '';
12309 var minDecimal = getValueFromParamsOrGridOptions('minDecimal', columnDef, grid, 2);
12310 var maxDecimal = getValueFromParamsOrGridOptions('maxDecimal', columnDef, grid, 4);
12311 var displayNegativeNumberWithParentheses = getValueFromParamsOrGridOptions('displayNegativeNumberWithParentheses', columnDef, grid, false);
12312 if (val != null && !isNaN(+val)) {
12313 var formattedNumber = formatNumber(val, minDecimal, maxDecimal, displayNegativeNumberWithParentheses, '$');
12314 return "" + prefix + formattedNumber + suffix;
12315 }
12316 return '';
12317 };
12318
12319 var sumTotalsFormatter = function (totals, columnDef, grid) {
12320 var field = columnDef.field || '';
12321 var val = totals.sum && totals.sum[field];
12322 var params = columnDef && columnDef.params;
12323 var prefix = params && params.groupFormatterPrefix || '';
12324 var suffix = params && params.groupFormatterSuffix || '';
12325 var minDecimal = getValueFromParamsOrGridOptions('minDecimal', columnDef, grid);
12326 var maxDecimal = getValueFromParamsOrGridOptions('maxDecimal', columnDef, grid);
12327 var displayNegativeNumberWithParentheses = getValueFromParamsOrGridOptions('displayNegativeNumberWithParentheses', columnDef, grid, false);
12328 if (val != null && !isNaN(+val)) {
12329 var formattedNumber = formatNumber(val, minDecimal, maxDecimal, displayNegativeNumberWithParentheses);
12330 return "" + prefix + formattedNumber + suffix;
12331 }
12332 return '';
12333 };
12334
12335 var sumTotalsBoldFormatter = function (totals, columnDef, grid) {
12336 var field = columnDef.field || '';
12337 var val = totals.sum && totals.sum[field];
12338 var params = columnDef && columnDef.params;
12339 var prefix = params && params.groupFormatterPrefix || '';
12340 var suffix = params && params.groupFormatterSuffix || '';
12341 var minDecimal = getValueFromParamsOrGridOptions('minDecimal', columnDef, grid);
12342 var maxDecimal = getValueFromParamsOrGridOptions('maxDecimal', columnDef, grid);
12343 var displayNegativeNumberWithParentheses = getValueFromParamsOrGridOptions('displayNegativeNumberWithParentheses', columnDef, grid, false);
12344 if (val != null && !isNaN(+val)) {
12345 var formattedNumber = formatNumber(val, minDecimal, maxDecimal, displayNegativeNumberWithParentheses);
12346 return "<b>" + prefix + formattedNumber + suffix + "</b>";
12347 }
12348 return '';
12349 };
12350
12351 /** Provides a list of different Formatters that will change the cell value displayed in the UI */
12352 var GroupTotalFormatters = {
12353 /**
12354 * Average all the column totals
12355 * Extra options available in "params":: "groupFormatterPrefix" and "groupFormatterSuffix", e.g.: params: { groupFormatterPrefix: '<i>Total</i>: ', groupFormatterSuffix: '$' }
12356 */
12357 avgTotals: avgTotalsFormatter,
12358 /**
12359 * Average all the column totals and display '$' at the end of the value
12360 * Extra options available in "params":: "groupFormatterPrefix" and "groupFormatterSuffix", e.g.: params: { groupFormatterPrefix: '<i>Total</i>: ', groupFormatterSuffix: '$' }
12361 */
12362 avgTotalsDollar: avgTotalsDollarFormatter,
12363 /**
12364 * Average all the column totals and display '%' at the end of the value
12365 * Extra options available in "params":: "groupFormatterPrefix" and "groupFormatterSuffix", e.g.: params: { groupFormatterPrefix: '<i>Total</i>: ', groupFormatterSuffix: '$' }
12366 */
12367 avgTotalsPercentage: avgTotalsPercentageFormatter,
12368 /**
12369 * Show max value of all the column totals
12370 * Extra options available in "params":: "groupFormatterPrefix" and "groupFormatterSuffix", e.g.: params: { groupFormatterPrefix: '<i>Total</i>: ', groupFormatterSuffix: '$' }
12371 */
12372 maxTotals: maxTotalsFormatter,
12373 /**
12374 * Show min value of all the column totals
12375 * Extra options available in "params":: "groupFormatterPrefix" and "groupFormatterSuffix", e.g.: params: { groupFormatterPrefix: '<i>Total</i>: ', groupFormatterSuffix: '$' }
12376 */
12377 minTotals: minTotalsFormatter,
12378 /**
12379 * Sums up all the column totals
12380 * Extra options available in "params":: "groupFormatterPrefix" and "groupFormatterSuffix", e.g.: params: { groupFormatterPrefix: '<i>Total</i>: ', groupFormatterSuffix: '$' }
12381 */
12382 sumTotals: sumTotalsFormatter,
12383 /**
12384 * Sums up all the column totals and display it in bold font weight
12385 * Extra options available in "params":: "groupFormatterPrefix" and "groupFormatterSuffix", e.g: params: { groupFormatterPrefix: '<i>Total</i>: ', groupFormatterSuffix: '$' }
12386 */
12387 sumTotalsBold: sumTotalsBoldFormatter,
12388 /**
12389 * Sums up all the column totals, change color of text to red/green on negative/positive value
12390 * Extra options available in "params":: "groupFormatterPrefix" and "groupFormatterSuffix", e.g: params: { groupFormatterPrefix: '<i>Total</i>: ', groupFormatterSuffix: '$' }
12391 */
12392 sumTotalsColored: sumTotalsColoredFormatter,
12393 /**
12394 * Sums up all the column totals and display dollar sign
12395 * Extra options available in "params":: "groupFormatterPrefix" and "groupFormatterSuffix", e.g: params: { groupFormatterPrefix: '<i>Total</i>: ', groupFormatterSuffix: '$' }
12396 */
12397 sumTotalsDollar: sumTotalsDollarFormatter,
12398 /**
12399 * Sums up all the column totals and display dollar sign and show it in bold font weight
12400 * Extra options available in "params":: "groupFormatterPrefix" and "groupFormatterSuffix", e.g: params: { groupFormatterPrefix: '<i>Total</i>: ', groupFormatterSuffix: '$' }
12401 */
12402 sumTotalsDollarBold: sumTotalsDollarBoldFormatter,
12403 /**
12404 * Sums up all the column totals, change color of text to red/green on negative/positive value
12405 * Extra options available in "params":: "groupFormatterPrefix" and "groupFormatterSuffix", e.g: params: { groupFormatterPrefix: '<i>Total</i>: ', groupFormatterSuffix: '$' }
12406 */
12407 sumTotalsDollarColored: sumTotalsDollarColoredFormatter,
12408 /**
12409 * Sums up all the column totals, change color of text to red/green on negative/positive value, show it in bold font weight as well
12410 * Extra options available in "params":: "groupFormatterPrefix" and "groupFormatterSuffix", e.g: params: { groupFormatterPrefix: '<i>Total</i>: ', groupFormatterSuffix: '$' }
12411 */
12412 sumTotalsDollarColoredBold: sumTotalsDollarColoredBoldFormatter,
12413 };
12414
12415 var SlickPaginationComponent = /** @class */ (function () {
12416 /** Constructor */
12417 function SlickPaginationComponent(filterService, gridService) {
12418 this.filterService = filterService;
12419 this.gridService = gridService;
12420 this._eventHandler = new Slick.EventHandler();
12421 this._isFirstRender = true;
12422 this.onPaginationChanged = new core.EventEmitter();
12423 this.dataFrom = 1;
12424 this.dataTo = 1;
12425 this.pageCount = 0;
12426 this.pageNumber = 1;
12427 this.totalItems = 0;
12428 this.paginationPageSizes = [25, 75, 100];
12429 this.fromToParams = { from: this.dataFrom, to: this.dataTo, totalItems: this.totalItems };
12430 }
12431 Object.defineProperty(SlickPaginationComponent.prototype, "gridPaginationOptions", {
12432 get: function () {
12433 return this._gridPaginationOptions;
12434 },
12435 set: function (gridPaginationOptions) {
12436 this._gridPaginationOptions = gridPaginationOptions;
12437 if (this._isFirstRender || !gridPaginationOptions || !gridPaginationOptions.pagination || (gridPaginationOptions.pagination.totalItems !== this.totalItems)) {
12438 this.refreshPagination();
12439 this._isFirstRender = false;
12440 }
12441 },
12442 enumerable: true,
12443 configurable: true
12444 });
12445 SlickPaginationComponent.prototype.ngOnDestroy = function () {
12446 this.dispose();
12447 };
12448 SlickPaginationComponent.prototype.ngAfterViewInit = function () {
12449 var _this = this;
12450 this._gridPaginationOptions = this._gridPaginationOptions;
12451 if (!this._gridPaginationOptions || !this._gridPaginationOptions.pagination || (this._gridPaginationOptions.pagination.totalItems !== this.totalItems)) {
12452 this.refreshPagination();
12453 }
12454 // Subscribe to Filter Clear & Changed and go back to page 1 when that happen
12455 this._filterSubcription = this.filterService.onFilterChanged.subscribe(function () { return _this.refreshPagination(true); });
12456 this._filterSubcription = this.filterService.onFilterCleared.subscribe(function () { return _this.refreshPagination(true); });
12457 // Subscribe to any dataview row count changed so that when Adding/Deleting item(s) through the DataView
12458 // that would trigger a refresh of the pagination numbers
12459 if (this.dataView) {
12460 this.gridService.onItemAdded.subscribe(function (items) { return _this.onItemAddedOrRemoved(items, true); });
12461 this.gridService.onItemDeleted.subscribe(function (items) { return _this.onItemAddedOrRemoved(items, false); });
12462 }
12463 };
12464 SlickPaginationComponent.prototype.ceil = function (number) {
12465 return Math.ceil(number);
12466 };
12467 SlickPaginationComponent.prototype.changeToFirstPage = function (event) {
12468 this.pageNumber = 1;
12469 this.onPageChanged(event, this.pageNumber);
12470 };
12471 SlickPaginationComponent.prototype.changeToLastPage = function (event) {
12472 this.pageNumber = this.pageCount;
12473 this.onPageChanged(event, this.pageNumber);
12474 };
12475 SlickPaginationComponent.prototype.changeToNextPage = function (event) {
12476 if (this.pageNumber < this.pageCount) {
12477 this.pageNumber++;
12478 this.onPageChanged(event, this.pageNumber);
12479 }
12480 };
12481 SlickPaginationComponent.prototype.changeToPreviousPage = function (event) {
12482 if (this.pageNumber > 0) {
12483 this.pageNumber--;
12484 this.onPageChanged(event, this.pageNumber);
12485 }
12486 };
12487 SlickPaginationComponent.prototype.changeToCurrentPage = function (event) {
12488 this.pageNumber = +event.currentTarget.value;
12489 if (this.pageNumber < 1) {
12490 this.pageNumber = 1;
12491 }
12492 else if (this.pageNumber > this.pageCount) {
12493 this.pageNumber = this.pageCount;
12494 }
12495 this.onPageChanged(event, this.pageNumber);
12496 };
12497 SlickPaginationComponent.prototype.dispose = function () {
12498 this.onPaginationChanged.unsubscribe();
12499 if (this._filterSubcription) {
12500 this._filterSubcription.unsubscribe();
12501 }
12502 // unsubscribe all SlickGrid events
12503 this._eventHandler.unsubscribeAll();
12504 };
12505 SlickPaginationComponent.prototype.onChangeItemPerPage = function (event) {
12506 var itemsPerPage = +event.target.value;
12507 this.pageCount = Math.ceil(this.totalItems / itemsPerPage);
12508 this.pageNumber = (this.totalItems > 0) ? 1 : 0;
12509 this.itemsPerPage = itemsPerPage;
12510 this.onPageChanged(event, this.pageNumber);
12511 };
12512 SlickPaginationComponent.prototype.refreshPagination = function (isPageNumberReset) {
12513 if (isPageNumberReset === void 0) { isPageNumberReset = false; }
12514 var backendApi = this._gridPaginationOptions.backendServiceApi;
12515 if (!backendApi || !backendApi.service || !backendApi.process) {
12516 throw new Error("BackendServiceApi requires at least a \"process\" function and a \"service\" defined");
12517 }
12518 if (this._gridPaginationOptions && this._gridPaginationOptions.pagination) {
12519 var pagination = this._gridPaginationOptions.pagination;
12520 // set the number of items per page if not already set
12521 if (!this.itemsPerPage) {
12522 this.itemsPerPage = +((backendApi && backendApi.options && backendApi.options.paginationOptions && backendApi.options.paginationOptions.first) ? backendApi.options.paginationOptions.first : this._gridPaginationOptions.pagination.pageSize);
12523 }
12524 // if totalItems changed, we should always go back to the first page and recalculation the From-To indexes
12525 if (isPageNumberReset || this.totalItems !== pagination.totalItems) {
12526 if (this._isFirstRender && pagination.pageNumber && pagination.pageNumber > 1) {
12527 this.pageNumber = pagination.pageNumber || 1;
12528 }
12529 else {
12530 this.pageNumber = 1;
12531 }
12532 // when page number is set to 1 then also reset the "offset" of backend service
12533 if (this.pageNumber === 1) {
12534 backendApi.service.resetPaginationOptions();
12535 }
12536 }
12537 // calculate and refresh the multiple properties of the pagination UI
12538 this.paginationPageSizes = this._gridPaginationOptions.pagination.pageSizes;
12539 this.totalItems = this._gridPaginationOptions.pagination.totalItems;
12540 this.recalculateFromToIndexes();
12541 }
12542 this.pageCount = Math.ceil(this.totalItems / this.itemsPerPage);
12543 };
12544 SlickPaginationComponent.prototype.onPageChanged = function (event, pageNumber) {
12545 var _this = this;
12546 this.recalculateFromToIndexes();
12547 var backendApi = this._gridPaginationOptions.backendServiceApi;
12548 if (!backendApi || !backendApi.service || !backendApi.process) {
12549 throw new Error("BackendServiceApi requires at least a \"process\" function and a \"service\" defined");
12550 }
12551 if (this.dataTo > this.totalItems) {
12552 this.dataTo = this.totalItems;
12553 }
12554 else if (this.totalItems < this.itemsPerPage) {
12555 this.dataTo = this.totalItems;
12556 }
12557 if (backendApi) {
12558 try {
12559 var itemsPerPage = +this.itemsPerPage;
12560 // keep start time & end timestamps & return it after process execution
12561 var startTime_1 = new Date();
12562 // run any pre-process, if defined, for example a spinner
12563 if (backendApi.preProcess) {
12564 backendApi.preProcess();
12565 }
12566 var query = backendApi.service.processOnPaginationChanged(event, { newPage: pageNumber, pageSize: itemsPerPage });
12567 // the processes can be Observables (like HttpClient) or Promises
12568 var process_1 = backendApi.process(query);
12569 if (process_1 instanceof Promise && process_1.then) {
12570 process_1.then(function (processResult) { return executeBackendProcessesCallback(startTime_1, processResult, backendApi, _this._gridPaginationOptions); });
12571 }
12572 else if (rxjs.isObservable(process_1)) {
12573 process_1.subscribe(function (processResult) { return executeBackendProcessesCallback(startTime_1, processResult, backendApi, _this._gridPaginationOptions); }, function (error) { return onBackendError(error, backendApi); });
12574 }
12575 }
12576 catch (error) {
12577 onBackendError(error, backendApi);
12578 }
12579 }
12580 else {
12581 throw new Error('Pagination with a backend service requires "BackendServiceApi" to be defined in your grid options');
12582 }
12583 // emit the changes to the parent component
12584 this.onPaginationChanged.emit({
12585 pageNumber: this.pageNumber,
12586 pageSizes: this.paginationPageSizes,
12587 pageSize: this.itemsPerPage,
12588 totalItems: this.totalItems
12589 });
12590 };
12591 SlickPaginationComponent.prototype.recalculateFromToIndexes = function () {
12592 if (this.totalItems === 0) {
12593 this.dataFrom = 0;
12594 this.dataTo = 0;
12595 this.pageNumber = 0;
12596 }
12597 else {
12598 this.dataFrom = (this.pageNumber * this.itemsPerPage) - this.itemsPerPage + 1;
12599 this.dataTo = (this.totalItems < this.itemsPerPage) ? this.totalItems : (this.pageNumber * this.itemsPerPage);
12600 }
12601 };
12602 /**
12603 * When item is added or removed, we will refresh the numbers on the pagination however we won't trigger a backend change
12604 * This will have a side effect though, which is that the "To" count won't be matching the "items per page" count,
12605 * that is a necessary side effect to avoid triggering a backend query just to refresh the paging,
12606 * basically we assume that this offset is fine for the time being,
12607 * until user does an action which will refresh the data hence the pagination which will then become normal again
12608 */
12609 SlickPaginationComponent.prototype.onItemAddedOrRemoved = function (items, isItemAdded) {
12610 if (isItemAdded === void 0) { isItemAdded = true; }
12611 if (items !== null) {
12612 var previousDataTo = this.dataTo;
12613 var itemCount = Array.isArray(items) ? items.length : 1;
12614 var itemCountWithDirection = isItemAdded ? +itemCount : -itemCount;
12615 // refresh the total count in the pagination and in the UI
12616 this.totalItems += itemCountWithDirection;
12617 this.recalculateFromToIndexes();
12618 // finally refresh the "To" count and we know it might be different than the "items per page" count
12619 // but this is necessary since we don't want an actual backend refresh
12620 this.dataTo = previousDataTo + itemCountWithDirection;
12621 }
12622 };
12623 __decorate([
12624 core.Output(),
12625 __metadata("design:type", Object)
12626 ], SlickPaginationComponent.prototype, "onPaginationChanged", void 0);
12627 __decorate([
12628 core.Input(),
12629 __metadata("design:type", Object)
12630 ], SlickPaginationComponent.prototype, "dataView", void 0);
12631 __decorate([
12632 core.Input(),
12633 __metadata("design:type", Object),
12634 __metadata("design:paramtypes", [Object])
12635 ], SlickPaginationComponent.prototype, "gridPaginationOptions", null);
12636 __decorate([
12637 core.Input(),
12638 __metadata("design:type", Object)
12639 ], SlickPaginationComponent.prototype, "grid", void 0);
12640 SlickPaginationComponent = __decorate([
12641 core.Component({
12642 selector: 'slick-pagination',
12643 template: "<div class=\"slick-pagination\">\n <div class=\"slick-pagination-nav\">\n <nav aria-label=\"Page navigation\">\n <ul class=\"pagination\">\n <li class=\"page-item\" [ngClass]=\"(pageNumber === 1 || totalItems === 0) ? 'disabled' : ''\">\n <a class=\"page-link icon-seek-first fa fa-angle-double-left\" aria-label=\"First\" (click)=\"changeToFirstPage($event)\">\n </a>\n </li>\n <li class=\"page-item\" [ngClass]=\"(pageNumber === 1 || totalItems === 0) ? 'disabled' : ''\">\n <a class=\"page-link icon-seek-prev fa fa-angle-left\" aria-label=\"Previous\" (click)=\"changeToPreviousPage($event)\">\n </a>\n </li>\n </ul>\n </nav>\n\n <div class=\"slick-page-number\">\n <span [translate]=\"'PAGE'\"></span>\n <input type=\"text\" class=\"form-control\" [value]=\"pageNumber\" size=\"1\" [readOnly]=\"totalItems === 0\" (change)=\"changeToCurrentPage($event)\">\n <span [translate]=\"'OF'\"></span><span> {{pageCount}}</span>\n </div>\n\n <nav aria-label=\"Page navigation\">\n <ul class=\"pagination\">\n <li class=\"page-item\" [ngClass]=\"(pageNumber === pageCount || totalItems === 0) ? 'disabled' : ''\">\n <a class=\"page-link icon-seek-next text-center fa fa-lg fa-angle-right\" aria-label=\"Next\" (click)=\"changeToNextPage($event)\">\n </a>\n </li>\n <li class=\"page-item\" [ngClass]=\"(pageNumber === pageCount || totalItems === 0) ? 'disabled' : ''\">\n <a class=\"page-link icon-seek-end fa fa-lg fa-angle-double-right\" aria-label=\"Last\" (click)=\"changeToLastPage($event)\">\n </a>\n </li>\n </ul>\n </nav>\n </div>\n <span class=\"slick-pagination-settings\">\n <select id=\"items-per-page-label\" [value]=\"itemsPerPage\" (change)=\"onChangeItemPerPage($event)\">\n <option value=\"{{pageSize}}\" *ngFor=\"let pageSize of paginationPageSizes;\">{{pageSize}}</option>\n </select>\n <span [translate]=\"'ITEMS_PER_PAGE'\"></span>,\n <span class=\"slick-pagination-count\">\n <span [translate]=\"'FROM_TO_OF_TOTAL_ITEMS'\" [translateParams]=\"{ from: dataFrom, to: dataTo, totalItems: totalItems }\"></span>\n </span>\n </span>\n </div>\n"
12644 }),
12645 core.Injectable(),
12646 __metadata("design:paramtypes", [FilterService, GridService])
12647 ], SlickPaginationComponent);
12648 return SlickPaginationComponent;
12649 }());
12650
12651 var slickgridEventPrefix = 'sg';
12652 var AngularSlickgridComponent = /** @class */ (function () {
12653 function AngularSlickgridComponent(elm, exportService, extensionService, extensionUtility, filterService, gridService, gridEventService, gridStateService, groupingAndColspanService, resizer, sharedService, sortService, translate, forRootConfig) {
12654 this.elm = elm;
12655 this.exportService = exportService;
12656 this.extensionService = extensionService;
12657 this.extensionUtility = extensionUtility;
12658 this.filterService = filterService;
12659 this.gridService = gridService;
12660 this.gridEventService = gridEventService;
12661 this.gridStateService = gridStateService;
12662 this.groupingAndColspanService = groupingAndColspanService;
12663 this.resizer = resizer;
12664 this.sharedService = sharedService;
12665 this.sortService = sortService;
12666 this.translate = translate;
12667 this.forRootConfig = forRootConfig;
12668 this._eventHandler = new Slick.EventHandler();
12669 this._hideHeaderRowAfterPageLoad = false;
12670 this.groupingDefinition = {};
12671 this.showPagination = false;
12672 this.isGridInitialized = false;
12673 this.subscriptions = [];
12674 this.onAngularGridCreated = new core.EventEmitter();
12675 this.onDataviewCreated = new core.EventEmitter();
12676 this.onGridCreated = new core.EventEmitter();
12677 this.onGridInitialized = new core.EventEmitter();
12678 this.onBeforeGridCreate = new core.EventEmitter();
12679 this.onBeforeGridDestroy = new core.EventEmitter();
12680 this.onAfterGridDestroyed = new core.EventEmitter();
12681 this.onGridStateChanged = new core.EventEmitter();
12682 }
12683 Object.defineProperty(AngularSlickgridComponent.prototype, "gridHeight", {
12684 set: function (height) {
12685 this._fixedHeight = height;
12686 },
12687 enumerable: true,
12688 configurable: true
12689 });
12690 Object.defineProperty(AngularSlickgridComponent.prototype, "gridWidth", {
12691 set: function (width) {
12692 this._fixedWidth = width;
12693 },
12694 enumerable: true,
12695 configurable: true
12696 });
12697 Object.defineProperty(AngularSlickgridComponent.prototype, "columnDefinitions", {
12698 get: function () {
12699 return this._columnDefinitions;
12700 },
12701 set: function (columnDefinitions) {
12702 this._columnDefinitions = columnDefinitions;
12703 if (this.isGridInitialized) {
12704 this.updateColumnDefinitionsList(columnDefinitions);
12705 }
12706 },
12707 enumerable: true,
12708 configurable: true
12709 });
12710 Object.defineProperty(AngularSlickgridComponent.prototype, "dataset", {
12711 get: function () {
12712 return this.dataView.getItems();
12713 },
12714 set: function (dataset) {
12715 this._dataset = dataset;
12716 this.refreshGridData(dataset);
12717 },
12718 enumerable: true,
12719 configurable: true
12720 });
12721 AngularSlickgridComponent.prototype.ngOnInit = function () {
12722 this.onBeforeGridCreate.emit(true);
12723 if (this.gridOptions && !this.gridOptions.enableAutoResize && (this._fixedHeight || this._fixedWidth)) {
12724 this.gridHeightString = this._fixedHeight + "px";
12725 this.gridWidthString = this._fixedWidth + "px";
12726 }
12727 };
12728 AngularSlickgridComponent.prototype.ngOnDestroy = function () {
12729 this.onBeforeGridDestroy.emit(this.grid);
12730 this.destroy();
12731 this.onAfterGridDestroyed.emit(true);
12732 };
12733 AngularSlickgridComponent.prototype.destroy = function (emptyDomElementContainer) {
12734 if (emptyDomElementContainer === void 0) { emptyDomElementContainer = false; }
12735 var gridContainerId = this.gridOptions && this.gridOptions.gridContainerId;
12736 this.dataView = undefined;
12737 this.gridOptions = {};
12738 this.extensionService.dispose();
12739 this.filterService.dispose();
12740 this.gridEventService.dispose();
12741 this.gridStateService.dispose();
12742 this.groupingAndColspanService.dispose();
12743 this.resizer.dispose();
12744 this.sortService.dispose();
12745 if (this._eventHandler && this._eventHandler.unsubscribeAll) {
12746 this._eventHandler.unsubscribeAll();
12747 }
12748 if (this.grid && this.grid.destroy) {
12749 this.grid.destroy();
12750 }
12751 if (emptyDomElementContainer) {
12752 $(gridContainerId).empty();
12753 }
12754 // also unsubscribe all RxJS subscriptions
12755 this.subscriptions = unsubscribeAllObservables(this.subscriptions);
12756 };
12757 AngularSlickgridComponent.prototype.ngAfterViewInit = function () {
12758 this.initialization();
12759 this.isGridInitialized = true;
12760 // user must provide a "gridHeight" or use "autoResize: true" in the grid options
12761 if (!this._fixedHeight && !this.gridOptions.enableAutoResize) {
12762 throw new Error("[Angular-Slickgrid] requires a \"grid-height\" or the \"enableAutoResize\" grid option to be enabled.\n Without that the grid will seem empty while in fact it just does not have any height define.");
12763 }
12764 };
12765 AngularSlickgridComponent.prototype.initialization = function () {
12766 // make sure the dataset is initialized (if not it will throw an error that it cannot getLength of null)
12767 this._dataset = this._dataset || [];
12768 this.gridOptions = this.mergeGridOptions(this.gridOptions);
12769 this.createBackendApiInternalPostProcessCallback(this.gridOptions);
12770 if (!this.customDataView) {
12771 if (this.gridOptions.draggableGrouping || this.gridOptions.enableGrouping) {
12772 this.extensionUtility.loadExtensionDynamically(exports.ExtensionName.groupItemMetaProvider);
12773 this.groupItemMetadataProvider = new Slick.Data.GroupItemMetadataProvider();
12774 this.sharedService.groupItemMetadataProvider = this.groupItemMetadataProvider;
12775 this.dataView = new Slick.Data.DataView({ groupItemMetadataProvider: this.groupItemMetadataProvider });
12776 }
12777 else {
12778 this.dataView = new Slick.Data.DataView();
12779 }
12780 }
12781 // for convenience to the user, we provide the property "editor" as an Angular-Slickgrid editor complex object
12782 // however "editor" is used internally by SlickGrid for it's own Editor Factory
12783 // so in our lib we will swap "editor" and copy it into a new property called "internalColumnEditor"
12784 // then take back "editor.model" and make it the new "editor" so that SlickGrid Editor Factory still works
12785 this._columnDefinitions = this.swapInternalEditorToSlickGridFactoryEditor(this._columnDefinitions);
12786 // save reference for all columns before they optionally become hidden/visible
12787 this.sharedService.allColumns = this._columnDefinitions;
12788 this.sharedService.visibleColumns = this._columnDefinitions;
12789 this.extensionService.createExtensionsBeforeGridCreation(this._columnDefinitions, this.gridOptions);
12790 // build SlickGrid Grid, also user might optionally pass a custom dataview (e.g. remote model)
12791 this.grid = new Slick.Grid("#" + this.gridId, this.customDataView || this.dataView, this._columnDefinitions, this.gridOptions);
12792 this.sharedService.dataView = this.dataView;
12793 this.sharedService.grid = this.grid;
12794 this.extensionService.bindDifferentExtensions();
12795 this.bindDifferentHooks(this.grid, this.gridOptions, this.dataView);
12796 // emit the Grid & DataView object to make them available in parent component
12797 this.onGridCreated.emit(this.grid);
12798 // initialize the SlickGrid grid
12799 this.grid.init();
12800 if (!this.customDataView && (this.dataView && this.dataView.beginUpdate && this.dataView.setItems && this.dataView.endUpdate)) {
12801 this.onDataviewCreated.emit(this.dataView);
12802 this.dataView.beginUpdate();
12803 this.dataView.setItems(this._dataset, this.gridOptions.datasetIdPropertyName);
12804 this.dataView.endUpdate();
12805 // if you don't want the items that are not visible (due to being filtered out or being on a different page)
12806 // to stay selected, pass 'false' to the second arg
12807 if (this.gridOptions && this.gridOptions.dataView && this.gridOptions.dataView.hasOwnProperty('syncGridSelection')) {
12808 var syncGridSelection = this.gridOptions.dataView.syncGridSelection;
12809 if (typeof syncGridSelection === 'boolean') {
12810 this.dataView.syncGridSelection(this.grid, this.gridOptions.dataView.syncGridSelection);
12811 }
12812 else {
12813 this.dataView.syncGridSelection(this.grid, syncGridSelection.preserveHidden, syncGridSelection.preserveHiddenOnSelectionChange);
12814 }
12815 }
12816 }
12817 // user might want to hide the header row on page load but still have `enableFiltering: true`
12818 // if that is the case, we need to hide the headerRow ONLY AFTER all filters got created & dataView exist
12819 if (this._hideHeaderRowAfterPageLoad) {
12820 this.showHeaderRow(false);
12821 }
12822 // after the DataView is created & updated execute some processes
12823 this.executeAfterDataviewCreated(this.grid, this.gridOptions, this.dataView);
12824 // bind resize ONLY after the dataView is ready
12825 this.bindResizeHook(this.grid, this.gridOptions);
12826 // bind & initialize grouping and header grouping colspan service
12827 if (this.gridOptions.createPreHeaderPanel && !this.gridOptions.enableDraggableGrouping) {
12828 this.groupingAndColspanService.init(this.grid, this.dataView);
12829 }
12830 // bind & initialize the grid service
12831 this.gridService.init(this.grid, this.dataView);
12832 // when user enables translation, we need to translate Headers on first pass & subsequently in the bindDifferentHooks
12833 if (this.gridOptions.enableTranslate) {
12834 this.extensionService.translateColumnHeaders();
12835 }
12836 // if Export is enabled, initialize the service with the necessary grid and other objects
12837 if (this.gridOptions.enableExport) {
12838 this.exportService.init(this.grid, this.dataView);
12839 }
12840 // once all hooks are in placed and the grid is initialized, we can emit an event
12841 this.onGridInitialized.emit(this.grid);
12842 // bind the Backend Service API callback functions only after the grid is initialized
12843 // because the preProcess() and onInit() might get triggered
12844 if (this.gridOptions && this.gridOptions.backendServiceApi) {
12845 this.bindBackendCallbackFunctions(this.gridOptions);
12846 }
12847 this.gridStateService.init(this.grid, this.extensionService, this.filterService, this.sortService);
12848 this.onAngularGridCreated.emit({
12849 // Slick Grid & DataView objects
12850 dataView: this.dataView,
12851 slickGrid: this.grid,
12852 // public methods
12853 destroy: this.destroy.bind(this),
12854 // return all available Services (non-singleton)
12855 backendService: this.gridOptions && this.gridOptions.backendServiceApi && this.gridOptions.backendServiceApi.service,
12856 exportService: this.exportService,
12857 extensionService: this.extensionService,
12858 filterService: this.filterService,
12859 gridEventService: this.gridEventService,
12860 gridStateService: this.gridStateService,
12861 gridService: this.gridService,
12862 groupingService: this.groupingAndColspanService,
12863 resizerService: this.resizer,
12864 sortService: this.sortService,
12865 /** @deprecated please use "extensionService" instead */
12866 pluginService: this.extensionService,
12867 });
12868 };
12869 /**
12870 * Commits the current edit to the grid
12871 */
12872 AngularSlickgridComponent.prototype.commitEdit = function (target) {
12873 var _this = this;
12874 if (this.grid.getOptions().autoCommitEdit) {
12875 var activeNode_1 = this.grid.getActiveCellNode();
12876 // a timeout must be set or this could come into conflict when slickgrid
12877 // tries to commit the edit when going from one editor to another on the grid
12878 // through the click event. If the timeout was not here it would
12879 // try to commit/destroy the editor twice, which would throw a jquery
12880 // error about the element not being in the DOM
12881 setTimeout(function () {
12882 // make sure the target is the active editor so we do not
12883 // commit prematurely
12884 if (activeNode_1 && activeNode_1.contains(target) && _this.grid.getEditorLock().isActive()) {
12885 _this.grid.getEditorLock().commitCurrentEdit();
12886 }
12887 });
12888 }
12889 };
12890 /**
12891 * Define our internal Post Process callback, it will execute internally after we get back result from the Process backend call
12892 * For now, this is GraphQL Service ONLY feature and it will basically refresh the Dataset & Pagination without having the user to create his own PostProcess every time
12893 */
12894 AngularSlickgridComponent.prototype.createBackendApiInternalPostProcessCallback = function (gridOptions) {
12895 var _this = this;
12896 if (gridOptions && gridOptions.backendServiceApi) {
12897 var backendApi_1 = gridOptions.backendServiceApi;
12898 // internalPostProcess only works with a GraphQL Service, so make sure it is that type
12899 if (backendApi_1 && backendApi_1.service && backendApi_1.service instanceof GraphqlService) {
12900 backendApi_1.internalPostProcess = function (processResult) {
12901 var datasetName = (backendApi_1 && backendApi_1.service && typeof backendApi_1.service.getDatasetName === 'function') ? backendApi_1.service.getDatasetName() : '';
12902 if (processResult && processResult.data && processResult.data[datasetName]) {
12903 _this._dataset = processResult.data[datasetName].nodes;
12904 _this.refreshGridData(_this._dataset, processResult.data[datasetName].totalCount);
12905 }
12906 else {
12907 _this._dataset = [];
12908 }
12909 };
12910 }
12911 }
12912 };
12913 AngularSlickgridComponent.prototype.bindDifferentHooks = function (grid, gridOptions, dataView) {
12914 var _this = this;
12915 // on locale change, we have to manually translate the Headers, GridMenu
12916 this.subscriptions.push(this.translate.onLangChange.subscribe(function (event) {
12917 if (gridOptions.enableTranslate) {
12918 _this.extensionService.translateColumnHeaders();
12919 _this.extensionService.translateColumnPicker();
12920 _this.extensionService.translateGridMenu();
12921 _this.extensionService.translateHeaderMenu();
12922 }
12923 }));
12924 // if user entered some Columns "presets", we need to reflect them all in the grid
12925 if (gridOptions.presets && Array.isArray(gridOptions.presets.columns) && gridOptions.presets.columns.length > 0) {
12926 var gridColumns = this.gridStateService.getAssociatedGridColumns(grid, gridOptions.presets.columns);
12927 if (gridColumns && Array.isArray(gridColumns) && gridColumns.length > 0) {
12928 // make sure that the checkbox selector is also visible if it is enabled
12929 if (gridOptions.enableCheckboxSelector) {
12930 var checkboxColumn = (Array.isArray(this._columnDefinitions) && this._columnDefinitions.length > 0) ? this._columnDefinitions[0] : null;
12931 if (checkboxColumn && checkboxColumn.id === '_checkbox_selector' && gridColumns[0].id !== '_checkbox_selector') {
12932 gridColumns.unshift(checkboxColumn);
12933 }
12934 }
12935 // finally set the new presets columns (including checkbox selector if need be)
12936 grid.setColumns(gridColumns);
12937 }
12938 }
12939 // bind external sorting (backend) when available or default onSort (dataView)
12940 if (gridOptions.enableSorting && !this.customDataView) {
12941 gridOptions.backendServiceApi ? this.sortService.bindBackendOnSort(grid, dataView) : this.sortService.bindLocalOnSort(grid, dataView);
12942 }
12943 // bind external filter (backend) when available or default onFilter (dataView)
12944 if (gridOptions.enableFiltering && !this.customDataView) {
12945 this.filterService.init(grid);
12946 // if user entered some Filter "presets", we need to reflect them all in the DOM
12947 if (gridOptions.presets && Array.isArray(gridOptions.presets.filters) && gridOptions.presets.filters.length > 0) {
12948 this.filterService.populateColumnFilterSearchTerms();
12949 }
12950 gridOptions.backendServiceApi ? this.filterService.bindBackendOnFilter(grid, this.dataView) : this.filterService.bindLocalOnFilter(grid, this.dataView);
12951 }
12952 // if user set an onInit Backend, we'll run it right away (and if so, we also need to run preProcess, internalPostProcess & postProcess)
12953 if (gridOptions.backendServiceApi) {
12954 var backendApi = gridOptions.backendServiceApi;
12955 if (backendApi && backendApi.service && backendApi.service.init) {
12956 backendApi.service.init(backendApi.options, gridOptions.pagination, this.grid);
12957 }
12958 }
12959 var _loop_1 = function (prop) {
12960 if (grid.hasOwnProperty(prop) && prop.startsWith('on')) {
12961 this_1._eventHandler.subscribe(grid[prop], function (e, args) {
12962 return _this.dispatchCustomEvent("" + slickgridEventPrefix + titleCase(prop), { eventData: e, args: args });
12963 });
12964 }
12965 };
12966 var this_1 = this;
12967 // expose all Slick Grid Events through dispatch
12968 for (var prop in grid) {
12969 _loop_1(prop);
12970 }
12971 var _loop_2 = function (prop) {
12972 if (dataView.hasOwnProperty(prop) && prop.startsWith('on')) {
12973 this_2._eventHandler.subscribe(dataView[prop], function (e, args) {
12974 return _this.dispatchCustomEvent("" + slickgridEventPrefix + titleCase(prop), { eventData: e, args: args });
12975 });
12976 }
12977 };
12978 var this_2 = this;
12979 // expose all Slick DataView Events through dispatch
12980 for (var prop in dataView) {
12981 _loop_2(prop);
12982 }
12983 // expose GridState Service changes event through dispatch
12984 this.subscriptions.push(this.gridStateService.onGridStateChanged.subscribe(function (gridStateChange) {
12985 _this.onGridStateChanged.emit(gridStateChange);
12986 }));
12987 // on cell click, mainly used with the columnDef.action callback
12988 this.gridEventService.bindOnCellChange(grid, dataView);
12989 this.gridEventService.bindOnClick(grid, dataView);
12990 if (dataView && grid) {
12991 this._eventHandler.subscribe(dataView.onRowCountChanged, function (e, args) {
12992 grid.invalidate();
12993 });
12994 // without this, filtering data with local dataset will not always show correctly
12995 // also don't use "invalidateRows" since it destroys the entire row and as bad user experience when updating a row
12996 // see commit: https://github.com/ghiscoding/Angular-Slickgrid/commit/bb62c0aa2314a5d61188ff005ccb564577f08805
12997 if (gridOptions && gridOptions.enableFiltering && !gridOptions.enableRowDetailView) {
12998 this._eventHandler.subscribe(dataView.onRowsChanged, function (e, args) {
12999 if (args && args.rows && Array.isArray(args.rows)) {
13000 args.rows.forEach(function (row) { return grid.updateRow(row); });
13001 grid.render();
13002 }
13003 });
13004 }
13005 }
13006 // does the user have a colspan callback?
13007 if (gridOptions.colspanCallback) {
13008 this.dataView.getItemMetadata = function (rowNumber) {
13009 var item = _this.dataView.getItem(rowNumber);
13010 return gridOptions.colspanCallback(item);
13011 };
13012 }
13013 };
13014 AngularSlickgridComponent.prototype.bindBackendCallbackFunctions = function (gridOptions) {
13015 var _this = this;
13016 var backendApi = gridOptions.backendServiceApi;
13017 var serviceOptions = (backendApi && backendApi.service && backendApi.service.options) ? backendApi.service.options : {};
13018 var isExecuteCommandOnInit = (!serviceOptions) ? false : ((serviceOptions && serviceOptions.hasOwnProperty('executeProcessCommandOnInit')) ? serviceOptions['executeProcessCommandOnInit'] : true);
13019 // update backend filters (if need be) before the query runs
13020 if (backendApi) {
13021 var backendService = backendApi.service;
13022 // if user entered some any "presets", we need to reflect them all in the grid
13023 if (gridOptions && gridOptions.presets) {
13024 // Filters "presets"
13025 if (backendService && backendService.updateFilters && Array.isArray(gridOptions.presets.filters) && gridOptions.presets.filters.length > 0) {
13026 backendService.updateFilters(gridOptions.presets.filters, true);
13027 }
13028 // Sorters "presets"
13029 if (backendService && backendService.updateSorters && Array.isArray(gridOptions.presets.sorters) && gridOptions.presets.sorters.length > 0) {
13030 backendService.updateSorters(undefined, gridOptions.presets.sorters);
13031 }
13032 // Pagination "presets"
13033 if (backendService && backendService.updatePagination && gridOptions.presets.pagination) {
13034 backendService.updatePagination(gridOptions.presets.pagination.pageNumber, gridOptions.presets.pagination.pageSize);
13035 }
13036 }
13037 else {
13038 var columnFilters = this.filterService.getColumnFilters();
13039 if (columnFilters && backendService && backendService.updateFilters) {
13040 backendService.updateFilters(columnFilters, false);
13041 }
13042 }
13043 }
13044 if (backendApi && backendApi.service && (backendApi.onInit || isExecuteCommandOnInit)) {
13045 var query = (typeof backendApi.service.buildQuery === 'function') ? backendApi.service.buildQuery() : '';
13046 var process_1 = (isExecuteCommandOnInit) ? backendApi.process(query) : backendApi.onInit(query);
13047 // wrap this inside a setTimeout to avoid timing issue since the gridOptions needs to be ready before running this onInit
13048 setTimeout(function () {
13049 // keep start time & end timestamps & return it after process execution
13050 var startTime = new Date();
13051 // run any pre-process, if defined, for example a spinner
13052 if (backendApi.preProcess) {
13053 backendApi.preProcess();
13054 }
13055 try {
13056 // the processes can be Observables (like HttpClient) or Promises
13057 if (process_1 instanceof Promise && process_1.then) {
13058 process_1.then(function (processResult) { return executeBackendProcessesCallback(startTime, processResult, backendApi, _this.gridOptions); });
13059 }
13060 else if (rxjs.isObservable(process_1)) {
13061 process_1.subscribe(function (processResult) { return executeBackendProcessesCallback(startTime, processResult, backendApi, _this.gridOptions); }, function (error) { return onBackendError(error, backendApi); });
13062 }
13063 }
13064 catch (error) {
13065 onBackendError(error, backendApi);
13066 }
13067 });
13068 }
13069 };
13070 AngularSlickgridComponent.prototype.bindResizeHook = function (grid, options) {
13071 // expand/autofit columns on first page load
13072 if (grid && options.autoFitColumnsOnFirstLoad && options.enableAutoSizeColumns) {
13073 grid.autosizeColumns();
13074 // compensate anytime SlickGrid measureScrollbar is incorrect (only seems to happen in Chrome 1/5 computers)
13075 this.resizer.compensateHorizontalScroll(this.grid, this.gridOptions);
13076 }
13077 // auto-resize grid on browser resize
13078 if (this._fixedHeight || this._fixedWidth) {
13079 this.resizer.init(grid, { height: this._fixedHeight, width: this._fixedWidth });
13080 }
13081 else {
13082 this.resizer.init(grid);
13083 }
13084 if (options.enableAutoResize) {
13085 this.resizer.bindAutoResizeDataGrid();
13086 if (grid && options.autoFitColumnsOnFirstLoad && options.enableAutoSizeColumns) {
13087 grid.autosizeColumns();
13088 }
13089 }
13090 };
13091 AngularSlickgridComponent.prototype.executeAfterDataviewCreated = function (grid, gridOptions, dataView) {
13092 // if user entered some Sort "presets", we need to reflect them all in the DOM
13093 if (gridOptions.enableSorting) {
13094 if (gridOptions.presets && Array.isArray(gridOptions.presets.sorters) && gridOptions.presets.sorters.length > 0) {
13095 this.sortService.loadLocalGridPresets(grid, dataView);
13096 }
13097 }
13098 };
13099 AngularSlickgridComponent.prototype.mergeGridOptions = function (gridOptions) {
13100 gridOptions.gridId = this.gridId;
13101 gridOptions.gridContainerId = "slickGridContainer-" + this.gridId;
13102 // use jquery extend to deep merge & copy to avoid immutable properties being changed in GlobalGridOptions after a route change
13103 var options = $.extend(true, {}, GlobalGridOptions, this.forRootConfig, gridOptions);
13104 // using jQuery extend to do a deep clone has an unwanted side on objects and pageSizes but ES6 spread has other worst side effects
13105 // so we will just overwrite the pageSizes when needed, this is the only one causing issues so far.
13106 // jQuery wrote this on their docs:: On a deep extend, Object and Array are extended, but object wrappers on primitive types such as String, Boolean, and Number are not.
13107 if (gridOptions && gridOptions.backendServiceApi) {
13108 if (gridOptions.pagination && Array.isArray(gridOptions.pagination.pageSizes) && gridOptions.pagination.pageSizes.length > 0) {
13109 options.pagination.pageSizes = gridOptions.pagination.pageSizes;
13110 }
13111 }
13112 // also make sure to show the header row if user have enabled filtering
13113 this._hideHeaderRowAfterPageLoad = (options.showHeaderRow === false);
13114 if (options.enableFiltering && !options.showHeaderRow) {
13115 options.showHeaderRow = options.enableFiltering;
13116 }
13117 return options;
13118 };
13119 /**
13120 * On a Pagination changed, we will trigger a Grid State changed with the new pagination info
13121 * Also if we use Row Selection or the Checkbox Selector, we need to reset any selection
13122 */
13123 AngularSlickgridComponent.prototype.paginationChanged = function (pagination) {
13124 if (this.gridOptions.enableRowSelection || this.gridOptions.enableCheckboxSelector) {
13125 this.gridService.setSelectedRows([]);
13126 }
13127 this.gridStateService.onGridStateChanged.next({
13128 change: { newValues: pagination, type: exports.GridStateType.pagination },
13129 gridState: this.gridStateService.getCurrentGridState()
13130 });
13131 };
13132 /**
13133 * When dataset changes, we need to refresh the entire grid UI & possibly resize it as well
13134 * @param dataset
13135 */
13136 AngularSlickgridComponent.prototype.refreshGridData = function (dataset, totalCount) {
13137 if (Array.isArray(dataset) && this.grid && this.dataView && typeof this.dataView.setItems === 'function') {
13138 this.dataView.setItems(dataset, this.gridOptions.datasetIdPropertyName);
13139 if (!this.gridOptions.backendServiceApi) {
13140 this.dataView.reSort();
13141 }
13142 if (dataset) {
13143 this.grid.invalidate();
13144 this.grid.render();
13145 }
13146 if (this.gridOptions.backendServiceApi) {
13147 // do we want to show pagination?
13148 // if we have a backendServiceApi and the enablePagination is undefined, we'll assume that we do want to see it, else get that defined value
13149 this.showPagination = ((this.gridOptions.backendServiceApi && this.gridOptions.enablePagination === undefined) ? true : this.gridOptions.enablePagination) || false;
13150 // before merging the grid options, make sure that it has the totalItems count
13151 // once we have that, we can merge and pass all these options to the pagination component
13152 if (!this.gridOptions.pagination) {
13153 this.gridOptions.pagination = (this.gridOptions.pagination) ? this.gridOptions.pagination : undefined;
13154 }
13155 if (this.gridOptions.pagination && totalCount !== undefined) {
13156 this.gridOptions.pagination.totalItems = totalCount;
13157 }
13158 if (this.gridOptions.presets && this.gridOptions.presets.pagination && this.gridOptions.pagination) {
13159 this.gridOptions.pagination.pageSize = this.gridOptions.presets.pagination.pageSize;
13160 this.gridOptions.pagination.pageNumber = this.gridOptions.presets.pagination.pageNumber;
13161 }
13162 this.gridPaginationOptions = this.mergeGridOptions(this.gridOptions);
13163 }
13164 // resize the grid inside a slight timeout, in case other DOM element changed prior to the resize (like a filter/pagination changed)
13165 if (this.grid && this.gridOptions.enableAutoResize) {
13166 var delay = this.gridOptions.autoResize && this.gridOptions.autoResize.delay;
13167 this.resizer.resizeGrid(delay || 10);
13168 }
13169 }
13170 };
13171 /**
13172 * Dynamically change or update the column definitions list.
13173 * We will re-render the grid so that the new header and data shows up correctly.
13174 * If using i18n, we also need to trigger a re-translate of the column headers
13175 */
13176 AngularSlickgridComponent.prototype.updateColumnDefinitionsList = function (newColumnDefinitions) {
13177 // map/swap the internal library Editor to the SlickGrid Editor factory
13178 newColumnDefinitions = this.swapInternalEditorToSlickGridFactoryEditor(newColumnDefinitions);
13179 if (this.gridOptions.enableTranslate) {
13180 this.extensionService.translateColumnHeaders(false, newColumnDefinitions);
13181 }
13182 else {
13183 this.extensionService.renderColumnHeaders(newColumnDefinitions);
13184 }
13185 if (this.gridOptions && this.gridOptions.enableAutoSizeColumns) {
13186 this.grid.autosizeColumns();
13187 }
13188 };
13189 /** Toggle the filter row displayed on first row
13190 * @param isShowing
13191 */
13192 AngularSlickgridComponent.prototype.showHeaderRow = function (isShowing) {
13193 this.grid.setHeaderRowVisibility(isShowing);
13194 return isShowing;
13195 };
13196 /** Toggle the filter row displayed on first row */
13197 AngularSlickgridComponent.prototype.toggleHeaderRow = function () {
13198 var isShowing = !this.grid.getOptions().showHeaderRow;
13199 this.grid.setHeaderRowVisibility(isShowing);
13200 return isShowing;
13201 };
13202 //
13203 // private functions
13204 // ------------------
13205 /** Dispatch of Custom Event, which by default will bubble & is cancelable */
13206 AngularSlickgridComponent.prototype.dispatchCustomEvent = function (eventName, data, isBubbling, isCancelable) {
13207 if (isBubbling === void 0) { isBubbling = true; }
13208 if (isCancelable === void 0) { isCancelable = true; }
13209 var eventInit = { bubbles: isBubbling, cancelable: isCancelable };
13210 if (data) {
13211 eventInit.detail = data;
13212 }
13213 return this.elm.nativeElement.dispatchEvent(new CustomEvent(eventName, eventInit));
13214 };
13215 /** Load the Editor Collection asynchronously and replace the "collection" property when Observable resolves */
13216 AngularSlickgridComponent.prototype.loadEditorCollectionAsync = function (column) {
13217 var _this = this;
13218 var collectionAsync = column && column.editor && column.editor.collectionAsync;
13219 if (collectionAsync instanceof rxjs.Observable) {
13220 this.subscriptions.push(collectionAsync.subscribe(function (resolvedCollection) { return _this.updateEditorCollection(column, resolvedCollection); }));
13221 }
13222 };
13223 /**
13224 * For convenience to the user, we provide the property "editor" as an Angular-Slickgrid editor complex object
13225 * however "editor" is used internally by SlickGrid for it's own Editor Factory
13226 * so in our lib we will swap "editor" and copy it into a new property called "internalColumnEditor"
13227 * then take back "editor.model" and make it the new "editor" so that SlickGrid Editor Factory still works
13228 */
13229 AngularSlickgridComponent.prototype.swapInternalEditorToSlickGridFactoryEditor = function (columnDefinitions) {
13230 var _this = this;
13231 return columnDefinitions.map(function (column) {
13232 // on every Editor that have a "collectionAsync", resolve the data and assign it to the "collection" property
13233 if (column.editor && column.editor.collectionAsync) {
13234 _this.loadEditorCollectionAsync(column);
13235 }
13236 return __assign({}, column, { editor: column.editor && column.editor.model, internalColumnEditor: __assign({}, column.editor) });
13237 });
13238 };
13239 /**
13240 * Update the Editor "collection" property from an async call resolved
13241 * Since this is called after the async call resolves, the pointer will not be the same as the "column" argument passed.
13242 * Once we found the new pointer, we will reassign the "editor" and "collection" to the "internalColumnEditor" so it has newest collection
13243 */
13244 AngularSlickgridComponent.prototype.updateEditorCollection = function (column, newCollection) {
13245 column.editor.collection = newCollection;
13246 // find the new column reference pointer
13247 var columns = this.grid.getColumns();
13248 if (Array.isArray(columns)) {
13249 var columnRef = columns.find(function (col) { return col.id === column.id; });
13250 columnRef.internalColumnEditor = column.editor;
13251 }
13252 };
13253 __decorate([
13254 core.Output(),
13255 __metadata("design:type", Object)
13256 ], AngularSlickgridComponent.prototype, "onAngularGridCreated", void 0);
13257 __decorate([
13258 core.Output(),
13259 __metadata("design:type", Object)
13260 ], AngularSlickgridComponent.prototype, "onDataviewCreated", void 0);
13261 __decorate([
13262 core.Output(),
13263 __metadata("design:type", Object)
13264 ], AngularSlickgridComponent.prototype, "onGridCreated", void 0);
13265 __decorate([
13266 core.Output(),
13267 __metadata("design:type", Object)
13268 ], AngularSlickgridComponent.prototype, "onGridInitialized", void 0);
13269 __decorate([
13270 core.Output(),
13271 __metadata("design:type", Object)
13272 ], AngularSlickgridComponent.prototype, "onBeforeGridCreate", void 0);
13273 __decorate([
13274 core.Output(),
13275 __metadata("design:type", Object)
13276 ], AngularSlickgridComponent.prototype, "onBeforeGridDestroy", void 0);
13277 __decorate([
13278 core.Output(),
13279 __metadata("design:type", Object)
13280 ], AngularSlickgridComponent.prototype, "onAfterGridDestroyed", void 0);
13281 __decorate([
13282 core.Output(),
13283 __metadata("design:type", Object)
13284 ], AngularSlickgridComponent.prototype, "onGridStateChanged", void 0);
13285 __decorate([
13286 core.Input(),
13287 __metadata("design:type", Object)
13288 ], AngularSlickgridComponent.prototype, "customDataView", void 0);
13289 __decorate([
13290 core.Input(),
13291 __metadata("design:type", String)
13292 ], AngularSlickgridComponent.prototype, "gridId", void 0);
13293 __decorate([
13294 core.Input(),
13295 __metadata("design:type", Object)
13296 ], AngularSlickgridComponent.prototype, "gridOptions", void 0);
13297 __decorate([
13298 core.Input(),
13299 __metadata("design:type", Number),
13300 __metadata("design:paramtypes", [Number])
13301 ], AngularSlickgridComponent.prototype, "gridHeight", null);
13302 __decorate([
13303 core.Input(),
13304 __metadata("design:type", Number),
13305 __metadata("design:paramtypes", [Number])
13306 ], AngularSlickgridComponent.prototype, "gridWidth", null);
13307 __decorate([
13308 core.Input(),
13309 __metadata("design:type", Array),
13310 __metadata("design:paramtypes", [Array])
13311 ], AngularSlickgridComponent.prototype, "columnDefinitions", null);
13312 __decorate([
13313 core.Input(),
13314 __metadata("design:type", Array),
13315 __metadata("design:paramtypes", [Array])
13316 ], AngularSlickgridComponent.prototype, "dataset", null);
13317 AngularSlickgridComponent = __decorate([
13318 core.Injectable(),
13319 core.Component({
13320 selector: 'angular-slickgrid',
13321 template: "<div id=\"slickGridContainer-{{gridId}}\" class=\"gridPane\" [style.width]=\"gridWidthString\">\r\n <div attr.id='{{gridId}}' class=\"slickgrid-container\" style=\"width: 100%\" [style.height]=\"gridHeightString\">\r\n </div>\r\n\r\n <slick-pagination id=\"slickPagingContainer-{{gridId}}\"\r\n *ngIf=\"showPagination\"\r\n (onPaginationChanged)=\"paginationChanged($event)\"\r\n [dataView]=\"dataView\"\r\n [gridPaginationOptions]=\"gridPaginationOptions\">\r\n </slick-pagination>\r\n</div>\r\n",
13322 providers: [
13323 // make everything transient (non-singleton)
13324 AngularUtilService,
13325 AutoTooltipExtension,
13326 CellExternalCopyManagerExtension,
13327 CheckboxSelectorExtension,
13328 ColumnPickerExtension,
13329 DraggableGroupingExtension,
13330 ExtensionService,
13331 ExportService,
13332 ExtensionUtility,
13333 FilterFactory,
13334 FilterService,
13335 GraphqlService,
13336 GridEventService,
13337 GridMenuExtension,
13338 GridService,
13339 GridStateService,
13340 GroupingAndColspanService,
13341 GroupItemMetaProviderExtension,
13342 HeaderButtonExtension,
13343 HeaderMenuExtension,
13344 ResizerService,
13345 RowDetailViewExtension,
13346 RowMoveManagerExtension,
13347 RowSelectionExtension,
13348 SharedService,
13349 SortService,
13350 SlickgridConfig
13351 ]
13352 }),
13353 __param(13, core.Inject('config')),
13354 __metadata("design:paramtypes", [core.ElementRef,
13355 ExportService,
13356 ExtensionService,
13357 ExtensionUtility,
13358 FilterService,
13359 GridService,
13360 GridEventService,
13361 GridStateService,
13362 GroupingAndColspanService,
13363 ResizerService,
13364 SharedService,
13365 SortService,
13366 core$1.TranslateService, Object])
13367 ], AngularSlickgridComponent);
13368 return AngularSlickgridComponent;
13369 }());
13370
13371 var AngularSlickgridModule = /** @class */ (function () {
13372 function AngularSlickgridModule() {
13373 }
13374 AngularSlickgridModule_1 = AngularSlickgridModule;
13375 AngularSlickgridModule.forRoot = function (config) {
13376 if (config === void 0) { config = {}; }
13377 return {
13378 ngModule: AngularSlickgridModule_1,
13379 providers: [
13380 { provide: 'config', useValue: config },
13381 AngularUtilService,
13382 CollectionService,
13383 FilterFactory,
13384 GraphqlService,
13385 GridOdataService
13386 ]
13387 };
13388 };
13389 var AngularSlickgridModule_1;
13390 AngularSlickgridModule = AngularSlickgridModule_1 = __decorate([
13391 core.NgModule({
13392 imports: [
13393 common.CommonModule,
13394 core$1.TranslateModule
13395 ],
13396 declarations: [
13397 AngularSlickgridComponent,
13398 SlickPaginationComponent
13399 ],
13400 exports: [
13401 AngularSlickgridComponent,
13402 SlickPaginationComponent
13403 ],
13404 entryComponents: [AngularSlickgridComponent]
13405 })
13406 ], AngularSlickgridModule);
13407 return AngularSlickgridModule;
13408 }());
13409
13410 exports.Aggregators = Aggregators;
13411 exports.AngularSlickgridComponent = AngularSlickgridComponent;
13412 exports.AngularSlickgridModule = AngularSlickgridModule;
13413 exports.AngularUtilService = AngularUtilService;
13414 exports.AutoTooltipExtension = AutoTooltipExtension;
13415 exports.CellExternalCopyManagerExtension = CellExternalCopyManagerExtension;
13416 exports.CheckboxSelectorExtension = CheckboxSelectorExtension;
13417 exports.CollectionService = CollectionService;
13418 exports.ColumnPickerExtension = ColumnPickerExtension;
13419 exports.DraggableGroupingExtension = DraggableGroupingExtension;
13420 exports.Editors = Editors;
13421 exports.ExportService = ExportService;
13422 exports.ExtensionService = ExtensionService;
13423 exports.ExtensionUtility = ExtensionUtility;
13424 exports.FilterConditions = FilterConditions;
13425 exports.FilterFactory = FilterFactory;
13426 exports.FilterService = FilterService;
13427 exports.Filters = Filters;
13428 exports.Formatters = Formatters;
13429 exports.GraphqlService = GraphqlService;
13430 exports.GridEventService = GridEventService;
13431 exports.GridMenuExtension = GridMenuExtension;
13432 exports.GridOdataService = GridOdataService;
13433 exports.GridService = GridService;
13434 exports.GridStateService = GridStateService;
13435 exports.GroupItemMetaProviderExtension = GroupItemMetaProviderExtension;
13436 exports.GroupTotalFormatters = GroupTotalFormatters;
13437 exports.GroupingAndColspanService = GroupingAndColspanService;
13438 exports.HeaderButtonExtension = HeaderButtonExtension;
13439 exports.HeaderMenuExtension = HeaderMenuExtension;
13440 exports.OdataQueryBuilderService = OdataQueryBuilderService;
13441 exports.ResizerService = ResizerService;
13442 exports.RowDetailViewExtension = RowDetailViewExtension;
13443 exports.RowMoveManagerExtension = RowMoveManagerExtension;
13444 exports.RowSelectionExtension = RowSelectionExtension;
13445 exports.SharedService = SharedService;
13446 exports.SlickPaginationComponent = SlickPaginationComponent;
13447 exports.SlickgridConfig = SlickgridConfig;
13448 exports.SortService = SortService;
13449 exports.Sorters = Sorters;
13450 exports.addToArrayWhenNotExists = addToArrayWhenNotExists;
13451 exports.addWhiteSpaces = addWhiteSpaces;
13452 exports.castToPromise = castToPromise;
13453 exports.charArraysEqual = charArraysEqual;
13454 exports.decimalFormatted = decimalFormatted;
13455 exports.executeBackendProcessesCallback = executeBackendProcessesCallback;
13456 exports.findOrDefault = findOrDefault;
13457 exports.formatNumber = formatNumber;
13458 exports.getDescendantProperty = getDescendantProperty;
13459 exports.getScrollBarWidth = getScrollBarWidth;
13460 exports.htmlDecode = htmlDecode;
13461 exports.htmlEncode = htmlEncode;
13462 exports.htmlEntityDecode = htmlEntityDecode;
13463 exports.htmlEntityEncode = htmlEntityEncode;
13464 exports.mapFlatpickrDateFormatWithFieldType = mapFlatpickrDateFormatWithFieldType;
13465 exports.mapMomentDateFormatWithFieldType = mapMomentDateFormatWithFieldType;
13466 exports.mapOperatorByFieldType = mapOperatorByFieldType;
13467 exports.mapOperatorType = mapOperatorType;
13468 exports.onBackendError = onBackendError;
13469 exports.parseBoolean = parseBoolean;
13470 exports.parseUtcDate = parseUtcDate;
13471 exports.sanitizeHtmlToText = sanitizeHtmlToText;
13472 exports.titleCase = titleCase;
13473 exports.toCamelCase = toCamelCase;
13474 exports.toKebabCase = toKebabCase;
13475 exports.toSnakeCase = toSnakeCase;
13476 exports.uniqueArray = uniqueArray;
13477 exports.uniqueObjectArray = uniqueObjectArray;
13478 exports.unsubscribeAllObservables = unsubscribeAllObservables;
13479 exports.ɵa = AvgAggregator;
13480 exports.ɵb = MinAggregator;
13481 exports.ɵba = stringFilterCondition;
13482 exports.ɵbb = testFilterCondition;
13483 exports.ɵbc = AutoCompleteFilter;
13484 exports.ɵbd = CompoundDateFilter;
13485 exports.ɵbe = CompoundInputFilter;
13486 exports.ɵbf = CompoundInputNumberFilter;
13487 exports.ɵbg = CompoundInputPasswordFilter;
13488 exports.ɵbh = CompoundSliderFilter;
13489 exports.ɵbi = InputFilter;
13490 exports.ɵbj = InputMaskFilter;
13491 exports.ɵbk = InputNumberFilter;
13492 exports.ɵbl = InputPasswordFilter;
13493 exports.ɵbm = MultipleSelectFilter;
13494 exports.ɵbn = SelectFilter;
13495 exports.ɵbo = NativeSelectFilter;
13496 exports.ɵbp = SingleSelectFilter;
13497 exports.ɵbq = SliderFilter;
13498 exports.ɵbr = arrayObjectToCsvFormatter;
13499 exports.ɵbs = arrayToCsvFormatter;
13500 exports.ɵbt = boldFormatter;
13501 exports.ɵbu = checkboxFormatter;
13502 exports.ɵbv = checkmarkFormatter;
13503 exports.ɵbw = complexObjectFormatter;
13504 exports.ɵbx = collectionFormatter;
13505 exports.ɵby = collectionEditorFormatter;
13506 exports.ɵbz = getAssociatedDateFormatter;
13507 exports.ɵc = MaxAggregator;
13508 exports.ɵca = deleteIconFormatter;
13509 exports.ɵcb = decimalFormatter;
13510 exports.ɵcc = dollarFormatter;
13511 exports.ɵcd = dollarColoredFormatter;
13512 exports.ɵce = dollarColoredBoldFormatter;
13513 exports.ɵcf = editIconFormatter;
13514 exports.ɵcg = hyperlinkFormatter;
13515 exports.ɵch = iconFormatter;
13516 exports.ɵci = infoIconFormatter;
13517 exports.ɵcj = italicFormatter;
13518 exports.ɵck = lowercaseFormatter;
13519 exports.ɵcl = maskFormatter;
13520 exports.ɵcm = multipleFormatter;
13521 exports.ɵcn = percentFormatter;
13522 exports.ɵco = percentCompleteFormatter;
13523 exports.ɵcp = percentCompleteBarFormatter;
13524 exports.ɵcq = percentSymbolFormatter;
13525 exports.ɵcr = progressBarFormatter;
13526 exports.ɵcs = translateFormatter;
13527 exports.ɵct = translateBooleanFormatter;
13528 exports.ɵcu = uppercaseFormatter;
13529 exports.ɵcv = yesNoFormatter;
13530 exports.ɵcw = avgTotalsFormatter;
13531 exports.ɵcx = avgTotalsDollarFormatter;
13532 exports.ɵcy = avgTotalsPercentageFormatter;
13533 exports.ɵcz = maxTotalsFormatter;
13534 exports.ɵd = SumAggregator;
13535 exports.ɵda = minTotalsFormatter;
13536 exports.ɵdb = sumTotalsFormatter;
13537 exports.ɵdc = sumTotalsBoldFormatter;
13538 exports.ɵdd = sumTotalsColoredFormatter;
13539 exports.ɵde = sumTotalsDollarFormatter;
13540 exports.ɵdf = sumTotalsDollarBoldFormatter;
13541 exports.ɵdg = sumTotalsDollarColoredFormatter;
13542 exports.ɵdh = sumTotalsDollarColoredBoldFormatter;
13543 exports.ɵdi = dateSorter;
13544 exports.ɵdj = dateIsoSorter;
13545 exports.ɵdk = dateEuroSorter;
13546 exports.ɵdl = dateEuroShortSorter;
13547 exports.ɵdm = dateUsSorter;
13548 exports.ɵdn = dateUsShortSorter;
13549 exports.ɵdo = numericSorter;
13550 exports.ɵdp = objectStringSorter;
13551 exports.ɵdq = stringSorter;
13552 exports.ɵe = AutoCompleteEditor;
13553 exports.ɵf = CheckboxEditor;
13554 exports.ɵg = DateEditor;
13555 exports.ɵh = FloatEditor;
13556 exports.ɵi = IntegerEditor;
13557 exports.ɵj = LongTextEditor;
13558 exports.ɵk = MultipleSelectEditor;
13559 exports.ɵl = SelectEditor;
13560 exports.ɵm = SingleSelectEditor;
13561 exports.ɵn = SliderEditor;
13562 exports.ɵo = TextEditor;
13563 exports.ɵp = executeMappedCondition;
13564 exports.ɵq = booleanFilterCondition;
13565 exports.ɵr = collectionSearchFilterCondition;
13566 exports.ɵs = dateEuroFilterCondition;
13567 exports.ɵt = dateEuroShortFilterCondition;
13568 exports.ɵu = dateFilterCondition;
13569 exports.ɵv = dateIsoFilterCondition;
13570 exports.ɵw = dateUtcFilterCondition;
13571 exports.ɵx = dateUsFilterCondition;
13572 exports.ɵy = dateUsShortFilterCondition;
13573 exports.ɵz = numberFilterCondition;
13574
13575 Object.defineProperty(exports, '__esModule', { value: true });
13576
13577}));
13578//# sourceMappingURL=angular-slickgrid.umd.js.map