jsxgrid 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. package/LICENSE +23 -0
  2. package/README.md +2329 -0
  3. package/dist/fields/jsgrid.field.XDateTimeField.min.js +6 -0
  4. package/dist/fields/jsgrid.field.XRowSelectField.min.js +6 -0
  5. package/dist/fields/jsgrid.field.Xcheckbox.min.js +6 -0
  6. package/dist/fields/jsgrid.field.XimgField.min.js +6 -0
  7. package/dist/fields/jsgrid.field.Xjsoneditor.min.js +6 -0
  8. package/dist/fields/jsgrid.field.Xselect.min.js +6 -0
  9. package/dist/fields/jsgrid.field.Xtextarea.min.js +6 -0
  10. package/dist/fields/lib/jsGridSummaryPlugin.min.js +6 -0
  11. package/dist/fields/lib/jsgrid.popup.basic.min.js +6 -0
  12. package/dist/i18n/jsgrid-Ko.js +46 -0
  13. package/dist/i18n/jsgrid-cs.js +46 -0
  14. package/dist/i18n/jsgrid-de.js +46 -0
  15. package/dist/i18n/jsgrid-el.js +46 -0
  16. package/dist/i18n/jsgrid-es.js +46 -0
  17. package/dist/i18n/jsgrid-fa.js +46 -0
  18. package/dist/i18n/jsgrid-fr.js +47 -0
  19. package/dist/i18n/jsgrid-he.js +46 -0
  20. package/dist/i18n/jsgrid-it.js +47 -0
  21. package/dist/i18n/jsgrid-ja.js +46 -0
  22. package/dist/i18n/jsgrid-ka.js +46 -0
  23. package/dist/i18n/jsgrid-lt.js +47 -0
  24. package/dist/i18n/jsgrid-pl.js +62 -0
  25. package/dist/i18n/jsgrid-pt-br.js +46 -0
  26. package/dist/i18n/jsgrid-pt.js +46 -0
  27. package/dist/i18n/jsgrid-ru.js +47 -0
  28. package/dist/i18n/jsgrid-tr.js +47 -0
  29. package/dist/i18n/jsgrid-zh-cn.js +46 -0
  30. package/dist/i18n/jsgrid-zh-tw.js +46 -0
  31. package/dist/icons-2x.png +0 -0
  32. package/dist/icons.png +0 -0
  33. package/dist/jsxgrid-fields.js +606 -0
  34. package/dist/jsxgrid-fields.min.js +6 -0
  35. package/dist/jsxgrid-theme.css +258 -0
  36. package/dist/jsxgrid-theme.min.css +1 -0
  37. package/dist/jsxgrid-xfields.js +979 -0
  38. package/dist/jsxgrid-xfields.min.js +6 -0
  39. package/dist/jsxgrid.css +126 -0
  40. package/dist/jsxgrid.js +2137 -0
  41. package/dist/jsxgrid.min.css +1 -0
  42. package/dist/jsxgrid.min.js +6 -0
  43. package/package.json +57 -0
  44. package/src/fields/jsgrid.field.XDateTimeField.js +122 -0
  45. package/src/fields/jsgrid.field.XRowSelectField.js +62 -0
  46. package/src/fields/jsgrid.field.Xcheckbox.js +108 -0
  47. package/src/fields/jsgrid.field.XimgField.js +99 -0
  48. package/src/fields/jsgrid.field.Xjsoneditor.js +165 -0
  49. package/src/fields/jsgrid.field.Xselect.js +176 -0
  50. package/src/fields/jsgrid.field.Xtextarea.js +97 -0
  51. package/src/fields/jsgrid.field.checkbox.js +97 -0
  52. package/src/fields/jsgrid.field.control.js +224 -0
  53. package/src/fields/jsgrid.field.number.js +41 -0
  54. package/src/fields/jsgrid.field.select.js +130 -0
  55. package/src/fields/jsgrid.field.text.js +69 -0
  56. package/src/fields/jsgrid.field.textarea.js +34 -0
  57. package/src/i18n/Ko.js +46 -0
  58. package/src/i18n/cs.js +46 -0
  59. package/src/i18n/de.js +46 -0
  60. package/src/i18n/el.js +46 -0
  61. package/src/i18n/es.js +46 -0
  62. package/src/i18n/fa.js +46 -0
  63. package/src/i18n/fr.js +47 -0
  64. package/src/i18n/he.js +46 -0
  65. package/src/i18n/it.js +47 -0
  66. package/src/i18n/ja.js +46 -0
  67. package/src/i18n/ka.js +46 -0
  68. package/src/i18n/lt.js +47 -0
  69. package/src/i18n/pl.js +62 -0
  70. package/src/i18n/pt-br.js +46 -0
  71. package/src/i18n/pt.js +46 -0
  72. package/src/i18n/ru.js +47 -0
  73. package/src/i18n/tr.js +47 -0
  74. package/src/i18n/zh-cn.js +46 -0
  75. package/src/i18n/zh-tw.js +46 -0
  76. package/src/jsgrid.core.js +1655 -0
  77. package/src/jsgrid.field.js +74 -0
  78. package/src/jsgrid.load-indicator.js +82 -0
  79. package/src/jsgrid.load-strategies.js +131 -0
  80. package/src/jsgrid.sort-strategies.js +49 -0
  81. package/src/jsgrid.validation.js +135 -0
  82. package/src/lib/jsGridSummaryPlugin.js +37 -0
  83. package/src/lib/jsgrid.popup.basic.js +107 -0
@@ -0,0 +1,2137 @@
1
+ /*
2
+ * jsxgrid v2.0.0 (https://github.com/rok9ru/jsxgrid#readme)
3
+ * (c) 2026 Mikhail Kremza
4
+ * Licensed under MIT
5
+ */
6
+
7
+ (function(window, $, undefined) {
8
+
9
+ var JSGRID = "JSGrid",
10
+ JSGRID_DATA_KEY = JSGRID,
11
+ JSGRID_ROW_DATA_KEY = "JSGridItem",
12
+ JSGRID_EDIT_ROW_DATA_KEY = "JSGridEditRow",
13
+
14
+ JSGRID_RECYCLED_IDS = [],
15
+ JSGRID_LAST_ID = 0,
16
+ SORT_ORDER_ASC = "asc",
17
+ SORT_ORDER_DESC = "desc",
18
+
19
+ FIRST_PAGE_PLACEHOLDER = "{first}",
20
+ PAGES_PLACEHOLDER = "{pages}",
21
+ PREV_PAGE_PLACEHOLDER = "{prev}",
22
+ NEXT_PAGE_PLACEHOLDER = "{next}",
23
+ LAST_PAGE_PLACEHOLDER = "{last}",
24
+ PAGE_INDEX_PLACEHOLDER = "{pageIndex}",
25
+ PAGE_COUNT_PLACEHOLDER = "{pageCount}",
26
+ ITEM_COUNT_PLACEHOLDER = "{itemCount}",
27
+
28
+ EMPTY_HREF = "javascript:void(0);";
29
+
30
+ var getOrApply = function(value, context) {
31
+ if($.isFunction(value)) {
32
+ return value.apply(context, $.makeArray(arguments).slice(2));
33
+ }
34
+ return value;
35
+ };
36
+
37
+ var normalizePromise = function(promise) {
38
+ var d = $.Deferred();
39
+
40
+ if(promise && promise.then) {
41
+ promise.then(function() {
42
+ d.resolve.apply(d, arguments);
43
+ }, function() {
44
+ d.reject.apply(d, arguments);
45
+ });
46
+ } else {
47
+ d.resolve(promise);
48
+ }
49
+
50
+ return d.promise();
51
+ };
52
+
53
+ var defaultController = {
54
+ loadData: $.noop,
55
+ insertItem: $.noop,
56
+ updateItem: $.noop,
57
+ deleteItem: $.noop
58
+ };
59
+
60
+
61
+ function Grid(element, config) {
62
+ var $element = $(element);
63
+
64
+ if (JSGRID_RECYCLED_IDS.length==0) {
65
+ this._id=JSGRID_LAST_ID;
66
+ JSGRID_LAST_ID++;
67
+ } else {
68
+ this._id=JSGRID_RECYCLED_IDS.pop();
69
+ }
70
+
71
+ $element.data(JSGRID_DATA_KEY, this);
72
+
73
+ this._container = $element;
74
+
75
+ this.data = [];
76
+ this.fields = [];
77
+
78
+ this._editingRow = null;
79
+ this._sortField = null;
80
+ this._sortOrder = SORT_ORDER_ASC;
81
+ this._firstDisplayingPage = 1;
82
+
83
+ this._init(config);
84
+ this.render();
85
+ }
86
+
87
+ Grid.prototype = {
88
+ width: "auto",
89
+ height: "auto",
90
+ updateOnResize: true,
91
+
92
+ rowClass: $.noop,
93
+ rowRenderer: null,
94
+
95
+ rowClick: function(args) {
96
+ if(this.editing) {
97
+ this.editItem($(args.event.target).closest("tr"));
98
+ }
99
+ },
100
+ rowDoubleClick: $.noop,
101
+
102
+ noDataContent: "Not found",
103
+ noDataRowClass: "jsgrid-nodata-row",
104
+
105
+ heading: true,
106
+ headerRowRenderer: null,
107
+ headerRowClass: "jsgrid-header-row",
108
+ headerCellClass: "jsgrid-header-cell",
109
+
110
+ filtering: false,
111
+ filterRowRenderer: null,
112
+ filterRowClass: "jsgrid-filter-row",
113
+
114
+ inserting: false,
115
+ insertRowLocation: "bottom",
116
+ insertRowRenderer: null,
117
+ insertRowClass: "jsgrid-insert-row",
118
+
119
+ editing: false,
120
+ editRowRenderer: null,
121
+ editRowClass: "jsgrid-edit-row",
122
+
123
+ confirmDeleting: true,
124
+ deleteConfirm: "Are you sure?",
125
+
126
+ selecting: true,
127
+ selectedRowClass: "jsgrid-selected-row",
128
+ oddRowClass: "jsgrid-row",
129
+ evenRowClass: "jsgrid-alt-row",
130
+ cellClass: "jsgrid-cell",
131
+
132
+ sorting: false,
133
+ sortableClass: "jsgrid-header-sortable",
134
+ sortAscClass: "jsgrid-header-sort jsgrid-header-sort-asc",
135
+ sortDescClass: "jsgrid-header-sort jsgrid-header-sort-desc",
136
+
137
+ paging: false,
138
+ pagerContainer: null,
139
+ pageIndex: 1,
140
+ pageSize: 20,
141
+ pageButtonCount: 15,
142
+ pagerFormat: "Pages: {first} {prev} {pages} {next} {last}    {pageIndex} of {pageCount}",
143
+ pagePrevText: "Prev",
144
+ pageNextText: "Next",
145
+ pageFirstText: "First",
146
+ pageLastText: "Last",
147
+ pageNavigatorNextText: "...",
148
+ pageNavigatorPrevText: "...",
149
+ pagerContainerClass: "jsgrid-pager-container",
150
+ pagerClass: "jsgrid-pager",
151
+ pagerNavButtonClass: "jsgrid-pager-nav-button",
152
+ pagerNavButtonInactiveClass: "jsgrid-pager-nav-inactive-button",
153
+ pageClass: "jsgrid-pager-page",
154
+ currentPageClass: "jsgrid-pager-current-page",
155
+
156
+ customLoading: false,
157
+ pageLoading: false,
158
+
159
+ autoload: false,
160
+ controller: defaultController,
161
+
162
+ loadIndication: true,
163
+ loadIndicationDelay: 500,
164
+ loadMessage: "Please, wait...",
165
+ loadShading: true,
166
+
167
+ invalidMessage: "Invalid data entered!",
168
+
169
+ invalidNotify: function(args) {
170
+ var messages = $.map(args.errors, function(error) {
171
+ return error.message || null;
172
+ });
173
+
174
+ window.alert([this.invalidMessage].concat(messages).join("\n"));
175
+ },
176
+
177
+ onInit: $.noop,
178
+ onRefreshing: $.noop,
179
+ onRefreshed: $.noop,
180
+ onPageChanged: $.noop,
181
+ onItemDeleting: $.noop,
182
+ onItemDeleted: $.noop,
183
+ onItemInserting: $.noop,
184
+ onItemInserted: $.noop,
185
+ onItemEditing: $.noop,
186
+ onItemEditCancelling: $.noop,
187
+ onItemUpdating: $.noop,
188
+ onItemUpdated: $.noop,
189
+ onItemInvalid: $.noop,
190
+ onDataLoading: $.noop,
191
+ onDataLoaded: $.noop,
192
+ onDataExporting: $.noop,
193
+ onOptionChanging: $.noop,
194
+ onOptionChanged: $.noop,
195
+ onError: $.noop,
196
+
197
+ invalidClass: "jsgrid-invalid",
198
+
199
+ containerClass: "jsgrid",
200
+ tableClass: "jsgrid-table",
201
+ gridHeaderClass: "jsgrid-grid-header",
202
+ gridBodyClass: "jsgrid-grid-body",
203
+
204
+ _init: function(config) {
205
+ $.extend(this, config);
206
+ this._initLoadStrategy();
207
+ this._initController();
208
+ this._initFields();
209
+ this._attachWindowLoadResize();
210
+ this._attachWindowResizeCallback();
211
+ this._callEventHandler(this.onInit)
212
+ },
213
+
214
+ loadStrategy: function() {
215
+ return this.pageLoading
216
+ ? new jsGrid.loadStrategies.PageLoadingStrategy(this)
217
+ : new jsGrid.loadStrategies.DirectLoadingStrategy(this);
218
+ },
219
+
220
+ _initLoadStrategy: function() {
221
+ this._loadStrategy = getOrApply(this.loadStrategy, this);
222
+ },
223
+
224
+ _initController: function() {
225
+ this._controller = $.extend({}, defaultController, getOrApply(this.controller, this));
226
+ },
227
+
228
+ renderTemplate: function(source, context, config) {
229
+ var args = [];
230
+ for(var key in config) {
231
+ args.push(config[key]);
232
+ }
233
+
234
+ args.unshift(source, context);
235
+
236
+ source = getOrApply.apply(null, args);
237
+ return (source === undefined || source === null) ? "" : source;
238
+ },
239
+
240
+ loadIndicator: function(config) {
241
+ return new jsGrid.LoadIndicator(config);
242
+ },
243
+
244
+ validation: function(config) {
245
+ return jsGrid.Validation && new jsGrid.Validation(config);
246
+ },
247
+
248
+ _initFields: function() {
249
+ var self = this;
250
+ self.fields = $.map(self.fields, function(field) {
251
+ if($.isPlainObject(field)) {
252
+ var fieldConstructor = (field.type && jsGrid.fields[field.type]) || jsGrid.Field;
253
+ field = new fieldConstructor(field);
254
+ }
255
+ field._grid = self;
256
+ return field;
257
+ });
258
+ },
259
+
260
+ _attachWindowLoadResize: function() {
261
+ $(window).on("load.table-"+this._id, $.proxy(this._refreshSize, this));
262
+ },
263
+
264
+ _attachWindowResizeCallback: function() {
265
+ if(this.updateOnResize) {
266
+ $(window).on("resize.table-"+this._id, $.proxy(this._refreshSize, this));
267
+ }
268
+ },
269
+
270
+ _detachWindowLoadResize: function() {
271
+ $(window).off("load.table-"+this._id);
272
+ },
273
+
274
+ _detachWindowResizeCallback: function() {
275
+ $(window).off("resize.table-"+this._id);
276
+ },
277
+
278
+ option: function(key, value) {
279
+ var optionChangingEventArgs,
280
+ optionChangedEventArgs;
281
+
282
+ if(arguments.length === 1)
283
+ return this[key];
284
+
285
+ optionChangingEventArgs = {
286
+ option: key,
287
+ oldValue: this[key],
288
+ newValue: value
289
+ };
290
+ this._callEventHandler(this.onOptionChanging, optionChangingEventArgs);
291
+
292
+ this._handleOptionChange(optionChangingEventArgs.option, optionChangingEventArgs.newValue);
293
+
294
+ optionChangedEventArgs = {
295
+ option: optionChangingEventArgs.option,
296
+ value: optionChangingEventArgs.newValue
297
+ };
298
+ this._callEventHandler(this.onOptionChanged, optionChangedEventArgs);
299
+ },
300
+
301
+ fieldOption: function(field, key, value) {
302
+ field = this._normalizeField(field);
303
+
304
+ if(arguments.length === 2)
305
+ return field[key];
306
+
307
+ field[key] = value;
308
+ this._renderGrid();
309
+ },
310
+
311
+ _handleOptionChange: function(name, value) {
312
+ this[name] = value;
313
+
314
+ switch(name) {
315
+ case "width":
316
+ case "height":
317
+ this._refreshSize();
318
+ break;
319
+ case "rowClass":
320
+ case "rowRenderer":
321
+ case "rowClick":
322
+ case "rowDoubleClick":
323
+ case "noDataRowClass":
324
+ case "noDataContent":
325
+ case "selecting":
326
+ case "selectedRowClass":
327
+ case "oddRowClass":
328
+ case "evenRowClass":
329
+ this._refreshContent();
330
+ break;
331
+ case "pageButtonCount":
332
+ case "pagerFormat":
333
+ case "pagePrevText":
334
+ case "pageNextText":
335
+ case "pageFirstText":
336
+ case "pageLastText":
337
+ case "pageNavigatorNextText":
338
+ case "pageNavigatorPrevText":
339
+ case "pagerClass":
340
+ case "pagerNavButtonClass":
341
+ case "pageClass":
342
+ case "currentPageClass":
343
+ case "pagerRenderer":
344
+ this._refreshPager();
345
+ break;
346
+ case "fields":
347
+ this._initFields();
348
+ this.render();
349
+ break;
350
+ case "data":
351
+ case "editing":
352
+ case "heading":
353
+ case "filtering":
354
+ case "inserting":
355
+ case "paging":
356
+ this.refresh();
357
+ break;
358
+ case "loadStrategy":
359
+ case "pageLoading":
360
+ this._initLoadStrategy();
361
+ this.search();
362
+ break;
363
+ case "pageIndex":
364
+ this.openPage(value);
365
+ break;
366
+ case "pageSize":
367
+ this.refresh();
368
+ this.search();
369
+ break;
370
+ case "editRowRenderer":
371
+ case "editRowClass":
372
+ this.cancelEdit();
373
+ break;
374
+ case "updateOnResize":
375
+ this._detachWindowResizeCallback();
376
+ this._attachWindowResizeCallback();
377
+ break;
378
+ case "invalidNotify":
379
+ case "invalidMessage":
380
+ break;
381
+ default:
382
+ this.render();
383
+ break;
384
+ }
385
+ },
386
+
387
+ destroy: function() {
388
+ this._detachWindowResizeCallback();
389
+ this._detachWindowLoadResize();
390
+ JSGRID_RECYCLED_IDS.push(this._id);
391
+ this._clear();
392
+ this._container.removeData(JSGRID_DATA_KEY);
393
+ },
394
+
395
+ render: function() {
396
+ this._renderGrid();
397
+ return this.autoload ? this.loadData() : $.Deferred().resolve().promise();
398
+ },
399
+
400
+ _renderGrid: function() {
401
+ this._clear();
402
+
403
+ this._container.addClass(this.containerClass)
404
+ .css("position", "relative")
405
+ .append(this._createHeader())
406
+ .append(this._createBody());
407
+
408
+ this._pagerContainer = this._createPagerContainer();
409
+ this._loadIndicator = this._createLoadIndicator();
410
+ this._validation = this._createValidation();
411
+
412
+ this.refresh();
413
+ },
414
+
415
+ _createLoadIndicator: function() {
416
+ return getOrApply(this.loadIndicator, this, {
417
+ message: this.loadMessage,
418
+ shading: this.loadShading,
419
+ container: this._container
420
+ });
421
+ },
422
+
423
+ _createValidation: function() {
424
+ return getOrApply(this.validation, this);
425
+ },
426
+
427
+ _clear: function() {
428
+ this.cancelEdit();
429
+
430
+ clearTimeout(this._loadingTimer);
431
+
432
+ this._pagerContainer && this._pagerContainer.empty();
433
+
434
+ this._container.empty()
435
+ .css({ position: "", width: "", height: "" });
436
+ },
437
+
438
+ _createHeader: function() {
439
+ var $headerRow = this._headerRow = this._createHeaderRow(),
440
+ $filterRow = this._filterRow = this._createFilterRow(),
441
+ $insertRow = this._insertRow = this._createInsertRow();
442
+
443
+ var $headerGrid = this._headerGrid = $("<table>").addClass(this.tableClass)
444
+ .append($headerRow)
445
+ .append($filterRow)
446
+ .append($insertRow);
447
+
448
+ var $header = this._header = $("<div>").addClass(this.gridHeaderClass)
449
+ .addClass(this._scrollBarWidth() ? "jsgrid-header-scrollbar" : "")
450
+ .append($headerGrid);
451
+
452
+ return $header;
453
+ },
454
+
455
+ _createBody: function() {
456
+ var $content = this._content = $("<tbody>");
457
+
458
+ var $bodyGrid = this._bodyGrid = $("<table>").addClass(this.tableClass)
459
+ .append($content);
460
+
461
+ var $body = this._body = $("<div>").addClass(this.gridBodyClass)
462
+ .append($bodyGrid)
463
+ .on("scroll", $.proxy(function(e) {
464
+ this._header.scrollLeft(e.target.scrollLeft);
465
+ }, this));
466
+
467
+ return $body;
468
+ },
469
+
470
+ _createPagerContainer: function() {
471
+ var pagerContainer = this.pagerContainer || $("<div>").appendTo(this._container);
472
+ return $(pagerContainer).addClass(this.pagerContainerClass);
473
+ },
474
+
475
+ _eachField: function(callBack) {
476
+ var self = this;
477
+ $.each(this.fields, function(index, field) {
478
+ if(field.visible) {
479
+ callBack.call(self, field, index);
480
+ }
481
+ });
482
+ },
483
+
484
+ _createHeaderRow: function() {
485
+ if($.isFunction(this.headerRowRenderer))
486
+ return $(this.renderTemplate(this.headerRowRenderer, this));
487
+
488
+ var $result = $("<tr>").addClass(this.headerRowClass);
489
+
490
+ this._eachField(function(field, index) {
491
+ var $th = this._prepareCell("<th>", field, "headercss", this.headerCellClass)
492
+ .append(this.renderTemplate(field.headerTemplate, field))
493
+ .appendTo($result);
494
+
495
+ if(this.sorting && field.sorting) {
496
+ $th.addClass(this.sortableClass)
497
+ .on("click", $.proxy(function() {
498
+ this.sort(index);
499
+ }, this));
500
+ }
501
+ });
502
+
503
+ return $result;
504
+ },
505
+
506
+ _prepareCell: function(cell, field, cssprop, cellClass) {
507
+ return $(cell).css("width", field.width)
508
+ .addClass(cellClass || this.cellClass)
509
+ .addClass((cssprop && field[cssprop]) || field.css)
510
+ .addClass(field.align ? ("jsgrid-align-" + field.align) : "");
511
+ },
512
+
513
+ _createFilterRow: function() {
514
+ if($.isFunction(this.filterRowRenderer))
515
+ return $(this.renderTemplate(this.filterRowRenderer, this));
516
+
517
+ var $result = $("<tr>").addClass(this.filterRowClass);
518
+
519
+ this._eachField(function(field) {
520
+ this._prepareCell("<td>", field, "filtercss")
521
+ .append(this.renderTemplate(field.filterTemplate, field))
522
+ .appendTo($result);
523
+ });
524
+
525
+ return $result;
526
+ },
527
+
528
+ _createInsertRow: function() {
529
+ if($.isFunction(this.insertRowRenderer))
530
+ return $(this.renderTemplate(this.insertRowRenderer, this));
531
+
532
+ var $result = $("<tr>").addClass(this.insertRowClass);
533
+
534
+ this._eachField(function(field) {
535
+ this._prepareCell("<td>", field, "insertcss")
536
+ .append(this.renderTemplate(field.insertTemplate, field))
537
+ .appendTo($result);
538
+ });
539
+
540
+ return $result;
541
+ },
542
+
543
+ _callEventHandler: function(handler, eventParams) {
544
+ handler.call(this, $.extend(eventParams, {
545
+ grid: this
546
+ }));
547
+
548
+ return eventParams;
549
+ },
550
+
551
+ reset: function() {
552
+ this._resetSorting();
553
+ this._resetPager();
554
+ return this._loadStrategy.reset();
555
+ },
556
+
557
+ _resetPager: function() {
558
+ this._firstDisplayingPage = 1;
559
+ this._setPage(1);
560
+ },
561
+
562
+ _resetSorting: function() {
563
+ this._sortField = null;
564
+ this._sortOrder = SORT_ORDER_ASC;
565
+ this._clearSortingCss();
566
+ },
567
+
568
+ refresh: function() {
569
+ this._callEventHandler(this.onRefreshing);
570
+
571
+ this.cancelEdit();
572
+
573
+ this._refreshHeading();
574
+ this._refreshFiltering();
575
+ this._refreshInserting();
576
+ this._refreshContent();
577
+ this._refreshPager();
578
+ this._refreshSize();
579
+
580
+ this._callEventHandler(this.onRefreshed);
581
+ },
582
+
583
+ _refreshHeading: function() {
584
+ this._headerRow.toggle(this.heading);
585
+ },
586
+
587
+ _refreshFiltering: function() {
588
+ this._filterRow.toggle(this.filtering);
589
+ },
590
+
591
+ _refreshInserting: function() {
592
+ this._insertRow.toggle(this.inserting);
593
+ },
594
+
595
+ _refreshContent: function() {
596
+ var $content = this._content;
597
+ $content.empty();
598
+
599
+ if(!this.data.length) {
600
+ $content.append(this._createNoDataRow());
601
+ return this;
602
+ }
603
+
604
+ var indexFrom = this._loadStrategy.firstDisplayIndex();
605
+ var indexTo = this._loadStrategy.lastDisplayIndex();
606
+
607
+ for(var itemIndex = indexFrom; itemIndex < indexTo; itemIndex++) {
608
+ var item = this.data[itemIndex];
609
+ $content.append(this._createRow(item, itemIndex));
610
+ }
611
+ },
612
+
613
+ _createNoDataRow: function() {
614
+ var amountOfFields = 0;
615
+ this._eachField(function() {
616
+ amountOfFields++;
617
+ });
618
+
619
+ return $("<tr>").addClass(this.noDataRowClass)
620
+ .append($("<td>").addClass(this.cellClass).attr("colspan", amountOfFields)
621
+ .append(this.renderTemplate(this.noDataContent, this)));
622
+ },
623
+
624
+ _createRow: function(item, itemIndex) {
625
+ var $result;
626
+
627
+ if($.isFunction(this.rowRenderer)) {
628
+ $result = this.renderTemplate(this.rowRenderer, this, { item: item, itemIndex: itemIndex });
629
+ } else {
630
+ $result = $("<tr>");
631
+ this._renderCells($result, item);
632
+ }
633
+
634
+ $result.addClass(this._getRowClasses(item, itemIndex))
635
+ .data(JSGRID_ROW_DATA_KEY, item)
636
+ .on("click", $.proxy(function(e) {
637
+ this.rowClick({
638
+ item: item,
639
+ itemIndex: itemIndex,
640
+ event: e
641
+ });
642
+ }, this))
643
+ .on("dblclick", $.proxy(function(e) {
644
+ this.rowDoubleClick({
645
+ item: item,
646
+ itemIndex: itemIndex,
647
+ event: e
648
+ });
649
+ }, this));
650
+
651
+ if(this.selecting) {
652
+ this._attachRowHover($result);
653
+ }
654
+
655
+ return $result;
656
+ },
657
+
658
+ _getRowClasses: function(item, itemIndex) {
659
+ var classes = [];
660
+ classes.push(((itemIndex + 1) % 2) ? this.oddRowClass : this.evenRowClass);
661
+ classes.push(getOrApply(this.rowClass, this, item, itemIndex));
662
+ return classes.join(" ");
663
+ },
664
+
665
+ _attachRowHover: function($row) {
666
+ var selectedRowClass = this.selectedRowClass;
667
+ $row.hover(function() {
668
+ $(this).addClass(selectedRowClass);
669
+ },
670
+ function() {
671
+ $(this).removeClass(selectedRowClass);
672
+ }
673
+ );
674
+ },
675
+
676
+ _renderCells: function($row, item) {
677
+ this._eachField(function(field) {
678
+ $row.append(this._createCell(item, field));
679
+ });
680
+ return this;
681
+ },
682
+
683
+ _createCell: function(item, field) {
684
+ var $result;
685
+ var fieldValue = this._getItemFieldValue(item, field);
686
+
687
+ var args = { value: fieldValue, item : item };
688
+ if($.isFunction(field.cellRenderer)) {
689
+ $result = this.renderTemplate(field.cellRenderer, field, args);
690
+ } else {
691
+ $result = $("<td>").append(this.renderTemplate(field.itemTemplate || fieldValue, field, args));
692
+ }
693
+
694
+ return this._prepareCell($result, field);
695
+ },
696
+
697
+ _getItemFieldValue: function(item, field) {
698
+ var props = field.name.split('.');
699
+ var result = item[props.shift()];
700
+
701
+ while(result && props.length) {
702
+ result = result[props.shift()];
703
+ }
704
+
705
+ return result;
706
+ },
707
+
708
+ _setItemFieldValue: function(item, field, value) {
709
+ var props = field.name.split('.');
710
+ var current = item;
711
+ var prop = props[0];
712
+
713
+ while(current && props.length) {
714
+ item = current;
715
+ prop = props.shift();
716
+ current = item[prop];
717
+ }
718
+
719
+ if(!current) {
720
+ while(props.length) {
721
+ item = item[prop] = {};
722
+ prop = props.shift();
723
+ }
724
+ }
725
+
726
+ item[prop] = value;
727
+ },
728
+
729
+ sort: function(field, order) {
730
+ if($.isPlainObject(field)) {
731
+ order = field.order;
732
+ field = field.field;
733
+ }
734
+
735
+ this._clearSortingCss();
736
+ this._setSortingParams(field, order);
737
+ this._setSortingCss();
738
+ return this._loadStrategy.sort();
739
+ },
740
+
741
+ _clearSortingCss: function() {
742
+ this._headerRow.find("th")
743
+ .removeClass(this.sortAscClass)
744
+ .removeClass(this.sortDescClass);
745
+ },
746
+
747
+ _setSortingParams: function(field, order) {
748
+ field = this._normalizeField(field);
749
+ order = order || ((this._sortField === field) ? this._reversedSortOrder(this._sortOrder) : SORT_ORDER_ASC);
750
+
751
+ this._sortField = field;
752
+ this._sortOrder = order;
753
+ },
754
+
755
+ _normalizeField: function(field) {
756
+ if($.isNumeric(field)) {
757
+ return this.fields[field];
758
+ }
759
+
760
+ if(typeof field === "string") {
761
+ return $.grep(this.fields, function(f) {
762
+ return f.name === field;
763
+ })[0];
764
+ }
765
+
766
+ return field;
767
+ },
768
+
769
+ _reversedSortOrder: function(order) {
770
+ return (order === SORT_ORDER_ASC ? SORT_ORDER_DESC : SORT_ORDER_ASC);
771
+ },
772
+
773
+ _setSortingCss: function() {
774
+ var fieldIndex = this._visibleFieldIndex(this._sortField);
775
+
776
+ this._headerRow.find("th").eq(fieldIndex)
777
+ .addClass(this._sortOrder === SORT_ORDER_ASC ? this.sortAscClass : this.sortDescClass);
778
+ },
779
+
780
+ _visibleFieldIndex: function(field) {
781
+ return $.inArray(field, $.grep(this.fields, function(f) { return f.visible; }));
782
+ },
783
+
784
+ _sortData: function() {
785
+ var sortFactor = this._sortFactor(),
786
+ sortField = this._sortField;
787
+
788
+ if(sortField) {
789
+ var self = this;
790
+ self.data.sort(function(item1, item2) {
791
+ var value1 = self._getItemFieldValue(item1, sortField);
792
+ var value2 = self._getItemFieldValue(item2, sortField);
793
+ return sortFactor * sortField.sortingFunc(value1, value2);
794
+ });
795
+ }
796
+ },
797
+
798
+ _sortFactor: function() {
799
+ return this._sortOrder === SORT_ORDER_ASC ? 1 : -1;
800
+ },
801
+
802
+ _itemsCount: function() {
803
+ return this._loadStrategy.itemsCount();
804
+ },
805
+
806
+ _pagesCount: function() {
807
+ var itemsCount = this._itemsCount(),
808
+ pageSize = this.pageSize;
809
+ return Math.floor(itemsCount / pageSize) + (itemsCount % pageSize ? 1 : 0);
810
+ },
811
+
812
+ _refreshPager: function() {
813
+ var $pagerContainer = this._pagerContainer;
814
+ $pagerContainer.empty();
815
+
816
+ if(this.paging) {
817
+ $pagerContainer.append(this._createPager());
818
+ }
819
+
820
+ var showPager = this.paging && this._pagesCount() > 1;
821
+ $pagerContainer.toggle(showPager);
822
+ },
823
+
824
+ _createPager: function() {
825
+ var $result;
826
+
827
+ if($.isFunction(this.pagerRenderer)) {
828
+ $result = $(this.pagerRenderer({
829
+ pageIndex: this.pageIndex,
830
+ pageCount: this._pagesCount()
831
+ }));
832
+ } else {
833
+ $result = $("<div>").append(this._createPagerByFormat());
834
+ }
835
+
836
+ $result.addClass(this.pagerClass);
837
+
838
+ return $result;
839
+ },
840
+
841
+ _createPagerByFormat: function() {
842
+ var pageIndex = this.pageIndex,
843
+ pageCount = this._pagesCount(),
844
+ itemCount = this._itemsCount(),
845
+ pagerParts = this.pagerFormat.split(" ");
846
+
847
+ return $.map(pagerParts, $.proxy(function(pagerPart) {
848
+ var result = pagerPart;
849
+
850
+ if(pagerPart === PAGES_PLACEHOLDER) {
851
+ result = this._createPages();
852
+ } else if(pagerPart === FIRST_PAGE_PLACEHOLDER) {
853
+ result = this._createPagerNavButton(this.pageFirstText, 1, pageIndex > 1);
854
+ } else if(pagerPart === PREV_PAGE_PLACEHOLDER) {
855
+ result = this._createPagerNavButton(this.pagePrevText, pageIndex - 1, pageIndex > 1);
856
+ } else if(pagerPart === NEXT_PAGE_PLACEHOLDER) {
857
+ result = this._createPagerNavButton(this.pageNextText, pageIndex + 1, pageIndex < pageCount);
858
+ } else if(pagerPart === LAST_PAGE_PLACEHOLDER) {
859
+ result = this._createPagerNavButton(this.pageLastText, pageCount, pageIndex < pageCount);
860
+ } else if(pagerPart === PAGE_INDEX_PLACEHOLDER) {
861
+ result = pageIndex;
862
+ } else if(pagerPart === PAGE_COUNT_PLACEHOLDER) {
863
+ result = pageCount;
864
+ } else if(pagerPart === ITEM_COUNT_PLACEHOLDER) {
865
+ result = itemCount;
866
+ }
867
+
868
+ return $.isArray(result) ? result.concat([" "]) : [result, " "];
869
+ }, this));
870
+ },
871
+
872
+ _createPages: function() {
873
+ var pageCount = this._pagesCount(),
874
+ pageButtonCount = this.pageButtonCount,
875
+ firstDisplayingPage = this._firstDisplayingPage,
876
+ pages = [];
877
+
878
+ if(firstDisplayingPage > 1) {
879
+ pages.push(this._createPagerPageNavButton(this.pageNavigatorPrevText, this.showPrevPages));
880
+ }
881
+
882
+ for(var i = 0, pageNumber = firstDisplayingPage; i < pageButtonCount && pageNumber <= pageCount; i++, pageNumber++) {
883
+ pages.push(pageNumber === this.pageIndex
884
+ ? this._createPagerCurrentPage()
885
+ : this._createPagerPage(pageNumber));
886
+ }
887
+
888
+ if((firstDisplayingPage + pageButtonCount - 1) < pageCount) {
889
+ pages.push(this._createPagerPageNavButton(this.pageNavigatorNextText, this.showNextPages));
890
+ }
891
+
892
+ return pages;
893
+ },
894
+
895
+ _createPagerNavButton: function(text, pageIndex, isActive) {
896
+ return this._createPagerButton(text, this.pagerNavButtonClass + (isActive ? "" : " " + this.pagerNavButtonInactiveClass),
897
+ isActive ? function() { this.openPage(pageIndex); } : $.noop);
898
+ },
899
+
900
+ _createPagerPageNavButton: function(text, handler) {
901
+ return this._createPagerButton(text, this.pagerNavButtonClass, handler);
902
+ },
903
+
904
+ _createPagerPage: function(pageIndex) {
905
+ return this._createPagerButton(pageIndex, this.pageClass, function() {
906
+ this.openPage(pageIndex);
907
+ });
908
+ },
909
+
910
+ _createPagerButton: function(text, css, handler) {
911
+ var $link = $("<a>").attr("href", EMPTY_HREF)
912
+ .html(text)
913
+ .on("click", $.proxy(handler, this));
914
+
915
+ return $("<span>").addClass(css).append($link);
916
+ },
917
+
918
+ _createPagerCurrentPage: function() {
919
+ return $("<span>")
920
+ .addClass(this.pageClass)
921
+ .addClass(this.currentPageClass)
922
+ .text(this.pageIndex);
923
+ },
924
+
925
+ _refreshSize: function() {
926
+ this._refreshHeight();
927
+ this._refreshWidth();
928
+ },
929
+
930
+ _refreshWidth: function() {
931
+ var width = (this.width === "auto") ? this._getAutoWidth() : this.width;
932
+
933
+ this._container.width(width);
934
+ },
935
+
936
+ _getAutoWidth: function() {
937
+ var $headerGrid = this._headerGrid,
938
+ $header = this._header;
939
+
940
+ $headerGrid.width("auto");
941
+
942
+ var contentWidth = $headerGrid.outerWidth();
943
+ var borderWidth = $header.outerWidth() - $header.innerWidth();
944
+
945
+ $headerGrid.width("");
946
+
947
+ return contentWidth + borderWidth;
948
+ },
949
+
950
+ _scrollBarWidth: (function() {
951
+ var result;
952
+
953
+ return function() {
954
+ if(result === undefined) {
955
+ var $ghostContainer = $("<div></div>");
956
+ var ghostContainer = $ghostContainer.get(0);
957
+ ghostContainer.style.width = "50px";
958
+ ghostContainer.style.height = "50px";
959
+ ghostContainer.style.position = "absolute";
960
+ ghostContainer.style.top = "-10000px";
961
+ ghostContainer.style.left = "-10000px";
962
+ var $ghostContent = $("<div></div>");
963
+ var ghostContent = $ghostContent.get(0);
964
+ ghostContent.style.height = "100px";
965
+ $ghostContainer.append($ghostContent).appendTo("body");
966
+ var width = $ghostContent.innerWidth();
967
+ $ghostContainer.get(0).style.overflowY = "auto";
968
+ var widthExcludingScrollBar = $ghostContent.innerWidth();
969
+ $ghostContainer.remove();
970
+ result = width - widthExcludingScrollBar;
971
+ }
972
+ return result;
973
+ };
974
+ })(),
975
+
976
+ _refreshHeight: function() {
977
+ var container = this._container,
978
+ pagerContainer = this._pagerContainer,
979
+ height = this.height,
980
+ nonBodyHeight;
981
+
982
+ container.height(height);
983
+
984
+ if(height !== "auto") {
985
+ height = container.height();
986
+
987
+ nonBodyHeight = this._header.outerHeight(true);
988
+ if(pagerContainer.parents(container).length) {
989
+ nonBodyHeight += pagerContainer.outerHeight(true);
990
+ }
991
+
992
+ this._body.outerHeight(height - nonBodyHeight);
993
+ }
994
+ },
995
+
996
+ showPrevPages: function() {
997
+ var firstDisplayingPage = this._firstDisplayingPage,
998
+ pageButtonCount = this.pageButtonCount;
999
+
1000
+ this._firstDisplayingPage = (firstDisplayingPage > pageButtonCount) ? firstDisplayingPage - pageButtonCount : 1;
1001
+
1002
+ this._refreshPager();
1003
+ },
1004
+
1005
+ showNextPages: function() {
1006
+ var firstDisplayingPage = this._firstDisplayingPage,
1007
+ pageButtonCount = this.pageButtonCount,
1008
+ pageCount = this._pagesCount();
1009
+
1010
+ this._firstDisplayingPage = (firstDisplayingPage + 2 * pageButtonCount > pageCount)
1011
+ ? pageCount - pageButtonCount + 1
1012
+ : firstDisplayingPage + pageButtonCount;
1013
+
1014
+ this._refreshPager();
1015
+ },
1016
+
1017
+ openPage: function(pageIndex) {
1018
+ if(pageIndex < 1 || pageIndex > this._pagesCount())
1019
+ return;
1020
+
1021
+ this._setPage(pageIndex);
1022
+ this._loadStrategy.openPage(pageIndex);
1023
+ },
1024
+
1025
+ _setPage: function(pageIndex) {
1026
+ var firstDisplayingPage = this._firstDisplayingPage,
1027
+ pageButtonCount = this.pageButtonCount;
1028
+
1029
+ this.pageIndex = pageIndex;
1030
+
1031
+ if(pageIndex < firstDisplayingPage) {
1032
+ this._firstDisplayingPage = pageIndex;
1033
+ }
1034
+
1035
+ if(pageIndex > firstDisplayingPage + pageButtonCount - 1) {
1036
+ this._firstDisplayingPage = pageIndex - pageButtonCount + 1;
1037
+ }
1038
+
1039
+ this._callEventHandler(this.onPageChanged, {
1040
+ pageIndex: pageIndex
1041
+ });
1042
+ },
1043
+
1044
+ _controllerCall: function(method, param, isCanceled, doneCallback) {
1045
+ if(isCanceled)
1046
+ return $.Deferred().reject().promise();
1047
+
1048
+ this._showLoading();
1049
+
1050
+ var controller = this._controller;
1051
+ if(!controller || !controller[method]) {
1052
+ throw Error("controller has no method '" + method + "'");
1053
+ }
1054
+
1055
+ return normalizePromise(controller[method](param))
1056
+ .done($.proxy(doneCallback, this))
1057
+ .fail($.proxy(this._errorHandler, this))
1058
+ .always($.proxy(this._hideLoading, this));
1059
+ },
1060
+
1061
+ _errorHandler: function() {
1062
+ this._callEventHandler(this.onError, {
1063
+ args: $.makeArray(arguments)
1064
+ });
1065
+ },
1066
+
1067
+ _showLoading: function() {
1068
+ if(!this.loadIndication)
1069
+ return;
1070
+
1071
+ clearTimeout(this._loadingTimer);
1072
+
1073
+ this._loadingTimer = setTimeout($.proxy(function() {
1074
+ this._loadIndicator.show();
1075
+ }, this), this.loadIndicationDelay);
1076
+ },
1077
+
1078
+ _hideLoading: function() {
1079
+ if(!this.loadIndication)
1080
+ return;
1081
+
1082
+ clearTimeout(this._loadingTimer);
1083
+ this._loadIndicator.hide();
1084
+ },
1085
+
1086
+ search: function(filter) {
1087
+ this._resetSorting();
1088
+ this._resetPager();
1089
+ return this.loadData(filter);
1090
+ },
1091
+
1092
+ loadData: function(filter) {
1093
+ filter = filter || (this.filtering ? this.getFilter() : {});
1094
+
1095
+ $.extend(filter, this._loadStrategy.loadParams(), this._sortingParams());
1096
+
1097
+ var args = this._callEventHandler(this.onDataLoading, {
1098
+ filter: filter
1099
+ });
1100
+
1101
+ return this._controllerCall("loadData", filter, args.cancel, function(loadedData) {
1102
+ if(!loadedData)
1103
+ return;
1104
+
1105
+ this._loadStrategy.finishLoad(loadedData);
1106
+
1107
+ this._callEventHandler(this.onDataLoaded, {
1108
+ data: loadedData
1109
+ });
1110
+ });
1111
+ },
1112
+
1113
+ exportData: function(exportOptions){
1114
+ var options = exportOptions || {};
1115
+ var type = options.type || "csv";
1116
+
1117
+ var result = "";
1118
+
1119
+ this._callEventHandler(this.onDataExporting);
1120
+
1121
+ switch(type){
1122
+
1123
+ case "csv":
1124
+ result = this._dataToCsv(options);
1125
+ break;
1126
+
1127
+ }
1128
+ return result;
1129
+ },
1130
+
1131
+ _dataToCsv: function(options){
1132
+ var options = options || {};
1133
+ var includeHeaders = options.hasOwnProperty("includeHeaders") ? options.includeHeaders : true;
1134
+ var subset = options.subset || "all";
1135
+ var filter = options.filter || undefined;
1136
+
1137
+ var result = [];
1138
+
1139
+ if (includeHeaders){
1140
+ var fieldsLength = this.fields.length;
1141
+ var fieldNames = {};
1142
+
1143
+ for(var i=0;i<fieldsLength;i++){
1144
+ var field = this.fields[i];
1145
+
1146
+ if ("includeInDataExport" in field){
1147
+ if (field.includeInDataExport === true)
1148
+ fieldNames[i] = field.title || field.name;
1149
+ }
1150
+
1151
+ }
1152
+
1153
+ var headerLine = this._itemToCsv(fieldNames,{},options);
1154
+ result.push(headerLine);
1155
+ }
1156
+
1157
+ var exportStartIndex = 0;
1158
+ var exportEndIndex = this.data.length;
1159
+
1160
+ switch(subset){
1161
+
1162
+ case "visible":
1163
+ exportEndIndex = this._firstDisplayingPage * this.pageSize;
1164
+ exportStartIndex = exportEndIndex - this.pageSize;
1165
+
1166
+ case "all":
1167
+ default:
1168
+ break;
1169
+ }
1170
+
1171
+ for (var i = exportStartIndex; i < exportEndIndex; i++){
1172
+ var item = this.data[i];
1173
+ var itemLine = "";
1174
+ var includeItem = true;
1175
+
1176
+ if (filter)
1177
+ if (!filter(item))
1178
+ includeItem = false;
1179
+
1180
+ if (includeItem){
1181
+ itemLine = this._itemToCsv(item, this.fields, options);
1182
+ result.push(itemLine);
1183
+ }
1184
+
1185
+ }
1186
+
1187
+ return result.join("");
1188
+
1189
+ },
1190
+
1191
+ _itemToCsv: function(item, fields, options){
1192
+ var options = options || {};
1193
+ var delimiter = options.delimiter || "|";
1194
+ var encapsulate = options.hasOwnProperty("encapsulate") ? options.encapsulate : true;
1195
+ var newline = options.newline || "\r\n";
1196
+ var transforms = options.transforms || {};
1197
+
1198
+ var fields = fields || {};
1199
+ var getItem = this._getItemFieldValue;
1200
+ var result = [];
1201
+
1202
+ Object.keys(item).forEach(function(key,index) {
1203
+
1204
+ var entry = "";
1205
+
1206
+ //Fields.length is greater than 0 when we are matching agaisnt fields
1207
+ //Field.length will be 0 when exporting header rows
1208
+ if (fields.length > 0){
1209
+
1210
+ var field = fields[index];
1211
+
1212
+ //Field may be excluded from data export
1213
+ if ("includeInDataExport" in field){
1214
+
1215
+ if (field.includeInDataExport){
1216
+
1217
+ //Field may be a select, which requires additional logic
1218
+ if (field.type === "select"){
1219
+
1220
+ var selectedItem = getItem(item, field);
1221
+
1222
+ var resultItem = $.grep(field.items, function(item, index) {
1223
+ return item[field.valueField] === selectedItem;
1224
+ })[0] || "";
1225
+
1226
+ entry = resultItem[field.textField];
1227
+ }
1228
+ else{
1229
+ entry = getItem(item, field);
1230
+ }
1231
+ }
1232
+ else{
1233
+ return;
1234
+ }
1235
+
1236
+ }
1237
+ else{
1238
+ entry = getItem(item, field);
1239
+ }
1240
+
1241
+ if (transforms.hasOwnProperty(field.name)){
1242
+ entry = transforms[field.name](entry);
1243
+ }
1244
+
1245
+
1246
+ }
1247
+ else{
1248
+ entry = item[key];
1249
+ }
1250
+
1251
+ if (encapsulate){
1252
+ entry = '"'+entry+'"';
1253
+ }
1254
+
1255
+
1256
+ result.push(entry);
1257
+ });
1258
+
1259
+ return result.join(delimiter) + newline;
1260
+ },
1261
+
1262
+ getFilter: function() {
1263
+ var result = {};
1264
+ this._eachField(function(field) {
1265
+ if(field.filtering) {
1266
+ this._setItemFieldValue(result, field, field.filterValue());
1267
+ }
1268
+ });
1269
+ return result;
1270
+ },
1271
+
1272
+ _sortingParams: function() {
1273
+ if(this.sorting && this._sortField) {
1274
+ return {
1275
+ sortField: this._sortField.name,
1276
+ sortOrder: this._sortOrder
1277
+ };
1278
+ }
1279
+ return {};
1280
+ },
1281
+
1282
+ getSorting: function() {
1283
+ var sortingParams = this._sortingParams();
1284
+ return {
1285
+ field: sortingParams.sortField,
1286
+ order: sortingParams.sortOrder
1287
+ };
1288
+ },
1289
+
1290
+ clearFilter: function() {
1291
+ var $filterRow = this._createFilterRow();
1292
+ this._filterRow.replaceWith($filterRow);
1293
+ this._filterRow = $filterRow;
1294
+ return this.search();
1295
+ },
1296
+
1297
+ insertItem: function(item) {
1298
+ var insertingItem = item || this._getValidatedInsertItem();
1299
+
1300
+ if(!insertingItem)
1301
+ return $.Deferred().reject().promise();
1302
+
1303
+ var args = this._callEventHandler(this.onItemInserting, {
1304
+ item: insertingItem
1305
+ });
1306
+
1307
+ return this._controllerCall("insertItem", insertingItem, args.cancel, function(insertedItem) {
1308
+ insertedItem = insertedItem || insertingItem;
1309
+ this._loadStrategy.finishInsert(insertedItem, this.insertRowLocation);
1310
+
1311
+ this._callEventHandler(this.onItemInserted, {
1312
+ item: insertedItem
1313
+ });
1314
+ });
1315
+ },
1316
+
1317
+ _getValidatedInsertItem: function() {
1318
+ var item = this._getInsertItem();
1319
+ return this._validateItem(item, this._insertRow) ? item : null;
1320
+ },
1321
+
1322
+ _getInsertItem: function() {
1323
+ var result = {};
1324
+ this._eachField(function(field) {
1325
+ if(field.inserting) {
1326
+ this._setItemFieldValue(result, field, field.insertValue());
1327
+ }
1328
+ });
1329
+ return result;
1330
+ },
1331
+
1332
+ _validateItem: function(item, $row) {
1333
+ var validationErrors = [];
1334
+
1335
+ var args = {
1336
+ item: item,
1337
+ itemIndex: this._rowIndex($row),
1338
+ row: $row
1339
+ };
1340
+
1341
+ this._eachField(function(field) {
1342
+ if(!field.validate ||
1343
+ ($row === this._insertRow && !field.inserting) ||
1344
+ ($row === this._getEditRow() && !field.editing))
1345
+ return;
1346
+
1347
+ var fieldValue = this._getItemFieldValue(item, field);
1348
+
1349
+ var errors = this._validation.validate($.extend({
1350
+ value: fieldValue,
1351
+ rules: field.validate
1352
+ }, args));
1353
+
1354
+ this._setCellValidity($row.children().eq(this._visibleFieldIndex(field)), errors);
1355
+
1356
+ if(!errors.length)
1357
+ return;
1358
+
1359
+ validationErrors.push.apply(validationErrors,
1360
+ $.map(errors, function(message) {
1361
+ return { field: field, message: message };
1362
+ }));
1363
+ });
1364
+
1365
+ if(!validationErrors.length)
1366
+ return true;
1367
+
1368
+ var invalidArgs = $.extend({
1369
+ errors: validationErrors
1370
+ }, args);
1371
+ this._callEventHandler(this.onItemInvalid, invalidArgs);
1372
+ this.invalidNotify(invalidArgs);
1373
+
1374
+ return false;
1375
+ },
1376
+
1377
+ _setCellValidity: function($cell, errors) {
1378
+ $cell
1379
+ .toggleClass(this.invalidClass, !!errors.length)
1380
+ .attr("title", errors.join("\n"));
1381
+ },
1382
+
1383
+ clearInsert: function() {
1384
+ var insertRow = this._createInsertRow();
1385
+ this._insertRow.replaceWith(insertRow);
1386
+ this._insertRow = insertRow;
1387
+ this.refresh();
1388
+ },
1389
+
1390
+ editItem: function(item) {
1391
+ var $row = this.rowByItem(item);
1392
+ if($row.length) {
1393
+ this._editRow($row);
1394
+ }
1395
+ },
1396
+
1397
+ rowByItem: function(item) {
1398
+ if(item.jquery || item.nodeType)
1399
+ return $(item);
1400
+
1401
+ return this._content.find("tr").filter(function() {
1402
+ return $.data(this, JSGRID_ROW_DATA_KEY) === item;
1403
+ });
1404
+ },
1405
+
1406
+ _editRow: function($row) {
1407
+ if(!this.editing)
1408
+ return;
1409
+
1410
+ var item = $row.data(JSGRID_ROW_DATA_KEY);
1411
+
1412
+ var args = this._callEventHandler(this.onItemEditing, {
1413
+ row: $row,
1414
+ item: item,
1415
+ itemIndex: this._itemIndex(item)
1416
+ });
1417
+
1418
+ if(args.cancel)
1419
+ return;
1420
+
1421
+ if(this._editingRow) {
1422
+ this.cancelEdit();
1423
+ }
1424
+
1425
+ var $editRow = this._createEditRow(item);
1426
+
1427
+ this._editingRow = $row;
1428
+ $row.hide();
1429
+ $editRow.insertBefore($row);
1430
+ $row.data(JSGRID_EDIT_ROW_DATA_KEY, $editRow);
1431
+ },
1432
+
1433
+ _createEditRow: function(item) {
1434
+ if($.isFunction(this.editRowRenderer)) {
1435
+ return $(this.renderTemplate(this.editRowRenderer, this, { item: item, itemIndex: this._itemIndex(item) }));
1436
+ }
1437
+
1438
+ var $result = $("<tr>").addClass(this.editRowClass);
1439
+
1440
+ this._eachField(function(field) {
1441
+ var fieldValue = this._getItemFieldValue(item, field);
1442
+
1443
+ this._prepareCell("<td>", field, "editcss")
1444
+ .append(this.renderTemplate(field.editTemplate || "", field, { value: fieldValue, item: item }))
1445
+ .appendTo($result);
1446
+ });
1447
+
1448
+ return $result;
1449
+ },
1450
+
1451
+ updateItem: function(item, editedItem) {
1452
+ if(arguments.length === 1) {
1453
+ editedItem = item;
1454
+ }
1455
+
1456
+ var $row = item ? this.rowByItem(item) : this._editingRow;
1457
+ editedItem = editedItem || this._getValidatedEditedItem();
1458
+
1459
+ if(!editedItem)
1460
+ return;
1461
+
1462
+ return this._updateRow($row, editedItem);
1463
+ },
1464
+
1465
+ _getValidatedEditedItem: function() {
1466
+ var item = this._getEditedItem();
1467
+ return this._validateItem(item, this._getEditRow()) ? item : null;
1468
+ },
1469
+
1470
+ _updateRow: function($updatingRow, editedItem) {
1471
+ var updatingItem = $updatingRow.data(JSGRID_ROW_DATA_KEY),
1472
+ updatingItemIndex = this._itemIndex(updatingItem),
1473
+ updatedItem = $.extend(true, {}, updatingItem, editedItem);
1474
+
1475
+ var args = this._callEventHandler(this.onItemUpdating, {
1476
+ row: $updatingRow,
1477
+ item: updatedItem,
1478
+ itemIndex: updatingItemIndex,
1479
+ previousItem: updatingItem
1480
+ });
1481
+
1482
+ return this._controllerCall("updateItem", updatedItem, args.cancel, function(loadedUpdatedItem) {
1483
+ var previousItem = $.extend(true, {}, updatingItem);
1484
+ updatedItem = loadedUpdatedItem || $.extend(true, updatingItem, updatedItem);
1485
+
1486
+ var $updatedRow = this._finishUpdate($updatingRow, updatedItem, updatingItemIndex);
1487
+
1488
+ this._callEventHandler(this.onItemUpdated, {
1489
+ row: $updatedRow,
1490
+ item: updatedItem,
1491
+ itemIndex: updatingItemIndex,
1492
+ previousItem: previousItem
1493
+ });
1494
+ });
1495
+ },
1496
+
1497
+ _rowIndex: function(row) {
1498
+ return this._content.children().index($(row));
1499
+ },
1500
+
1501
+ _itemIndex: function(item) {
1502
+ return $.inArray(item, this.data);
1503
+ },
1504
+
1505
+ _finishUpdate: function($updatingRow, updatedItem, updatedItemIndex) {
1506
+ this.cancelEdit();
1507
+ this.data[updatedItemIndex] = updatedItem;
1508
+
1509
+ var $updatedRow = this._createRow(updatedItem, updatedItemIndex);
1510
+ $updatingRow.replaceWith($updatedRow);
1511
+ return $updatedRow;
1512
+ },
1513
+
1514
+ _getEditedItem: function() {
1515
+ var result = {};
1516
+ this._eachField(function(field) {
1517
+ if(field.editing) {
1518
+ this._setItemFieldValue(result, field, field.editValue());
1519
+ }
1520
+ });
1521
+ return result;
1522
+ },
1523
+
1524
+ cancelEdit: function() {
1525
+ if(!this._editingRow)
1526
+ return;
1527
+
1528
+ var $row = this._editingRow,
1529
+ editingItem = $row.data(JSGRID_ROW_DATA_KEY),
1530
+ editingItemIndex = this._itemIndex(editingItem);
1531
+
1532
+ this._callEventHandler(this.onItemEditCancelling, {
1533
+ row: $row,
1534
+ item: editingItem,
1535
+ itemIndex: editingItemIndex
1536
+ });
1537
+
1538
+ this._getEditRow().remove();
1539
+ this._editingRow.show();
1540
+ this._editingRow = null;
1541
+ },
1542
+
1543
+ _getEditRow: function() {
1544
+ return this._editingRow && this._editingRow.data(JSGRID_EDIT_ROW_DATA_KEY);
1545
+ },
1546
+
1547
+ deleteItem: function(item) {
1548
+ var $row = this.rowByItem(item);
1549
+
1550
+ if(!$row.length)
1551
+ return;
1552
+
1553
+ if(this.confirmDeleting && !window.confirm(getOrApply(this.deleteConfirm, this, $row.data(JSGRID_ROW_DATA_KEY))))
1554
+ return;
1555
+
1556
+ return this._deleteRow($row);
1557
+ },
1558
+
1559
+ _deleteRow: function($row) {
1560
+ var deletingItem = $row.data(JSGRID_ROW_DATA_KEY),
1561
+ deletingItemIndex = this._itemIndex(deletingItem);
1562
+
1563
+ var args = this._callEventHandler(this.onItemDeleting, {
1564
+ row: $row,
1565
+ item: deletingItem,
1566
+ itemIndex: deletingItemIndex
1567
+ });
1568
+
1569
+ return this._controllerCall("deleteItem", deletingItem, args.cancel, function() {
1570
+ this._loadStrategy.finishDelete(deletingItem, deletingItemIndex);
1571
+
1572
+ this._callEventHandler(this.onItemDeleted, {
1573
+ row: $row,
1574
+ item: deletingItem,
1575
+ itemIndex: deletingItemIndex
1576
+ });
1577
+ });
1578
+ }
1579
+ };
1580
+
1581
+ $.fn.jsGrid = function(config) {
1582
+ var args = $.makeArray(arguments),
1583
+ methodArgs = args.slice(1),
1584
+ result = this;
1585
+
1586
+ this.each(function() {
1587
+ var $element = $(this),
1588
+ instance = $element.data(JSGRID_DATA_KEY),
1589
+ methodResult;
1590
+
1591
+ if(instance) {
1592
+ if(typeof config === "string") {
1593
+ methodResult = instance[config].apply(instance, methodArgs);
1594
+ if(methodResult !== undefined && methodResult !== instance) {
1595
+ result = methodResult;
1596
+ return false;
1597
+ }
1598
+ } else {
1599
+ instance._detachWindowResizeCallback();
1600
+ instance._init(config);
1601
+ instance.render();
1602
+ }
1603
+ } else {
1604
+ new Grid($element, config);
1605
+ }
1606
+ });
1607
+
1608
+ return result;
1609
+ };
1610
+
1611
+ var fields = {};
1612
+
1613
+ var setDefaults = function(config) {
1614
+ var componentPrototype;
1615
+
1616
+ if($.isPlainObject(config)) {
1617
+ componentPrototype = Grid.prototype;
1618
+ } else {
1619
+ componentPrototype = fields[config].prototype;
1620
+ config = arguments[1] || {};
1621
+ }
1622
+
1623
+ $.extend(componentPrototype, config);
1624
+ };
1625
+
1626
+ var locales = {};
1627
+
1628
+ var locale = function(lang) {
1629
+ var localeConfig = $.isPlainObject(lang) ? lang : locales[lang];
1630
+
1631
+ if(!localeConfig)
1632
+ throw Error("unknown locale " + lang);
1633
+
1634
+ setLocale(jsGrid, localeConfig);
1635
+ };
1636
+
1637
+ var setLocale = function(obj, localeConfig) {
1638
+ $.each(localeConfig, function(field, value) {
1639
+ if($.isPlainObject(value)) {
1640
+ setLocale(obj[field] || obj[field[0].toUpperCase() + field.slice(1)], value);
1641
+ return;
1642
+ }
1643
+
1644
+ if(obj.hasOwnProperty(field)) {
1645
+ obj[field] = value;
1646
+ } else {
1647
+ obj.prototype[field] = value;
1648
+ }
1649
+ });
1650
+ };
1651
+
1652
+ window.jsGrid = {
1653
+ Grid: Grid,
1654
+ fields: fields,
1655
+ setDefaults: setDefaults,
1656
+ locales: locales,
1657
+ locale: locale,
1658
+ version: '2.0.0'
1659
+ };
1660
+
1661
+ }(window, jQuery));
1662
+
1663
+ (function(jsGrid, $, undefined) {
1664
+
1665
+ function LoadIndicator(config) {
1666
+ this._init(config);
1667
+ }
1668
+
1669
+ LoadIndicator.prototype = {
1670
+
1671
+ container: "body",
1672
+ message: "Loading...",
1673
+ shading: true,
1674
+
1675
+ zIndex: 1000,
1676
+ shaderClass: "jsgrid-load-shader",
1677
+ loadPanelClass: "jsgrid-load-panel",
1678
+
1679
+ _init: function(config) {
1680
+ $.extend(true, this, config);
1681
+
1682
+ this._initContainer();
1683
+ this._initShader();
1684
+ this._initLoadPanel();
1685
+ },
1686
+
1687
+ _initContainer: function() {
1688
+ this._container = $(this.container);
1689
+ },
1690
+
1691
+ _initShader: function() {
1692
+ if(!this.shading)
1693
+ return;
1694
+
1695
+ this._shader = $("<div>").addClass(this.shaderClass)
1696
+ .hide()
1697
+ .css({
1698
+ position: "absolute",
1699
+ top: 0,
1700
+ right: 0,
1701
+ bottom: 0,
1702
+ left: 0,
1703
+ zIndex: this.zIndex
1704
+ })
1705
+ .appendTo(this._container);
1706
+ },
1707
+
1708
+ _initLoadPanel: function() {
1709
+ this._loadPanel = $("<div>").addClass(this.loadPanelClass)
1710
+ .text(this.message)
1711
+ .hide()
1712
+ .css({
1713
+ position: "absolute",
1714
+ top: "50%",
1715
+ left: "50%",
1716
+ zIndex: this.zIndex
1717
+ })
1718
+ .appendTo(this._container);
1719
+ },
1720
+
1721
+ show: function() {
1722
+ var $loadPanel = this._loadPanel.show();
1723
+
1724
+ var actualWidth = $loadPanel.outerWidth();
1725
+ var actualHeight = $loadPanel.outerHeight();
1726
+
1727
+ $loadPanel.css({
1728
+ marginTop: -actualHeight / 2,
1729
+ marginLeft: -actualWidth / 2
1730
+ });
1731
+
1732
+ this._shader.show();
1733
+ },
1734
+
1735
+ hide: function() {
1736
+ this._loadPanel.hide();
1737
+ this._shader.hide();
1738
+ }
1739
+
1740
+ };
1741
+
1742
+ jsGrid.LoadIndicator = LoadIndicator;
1743
+
1744
+ }(jsGrid, jQuery));
1745
+
1746
+ (function(jsGrid, $, undefined) {
1747
+
1748
+ function DirectLoadingStrategy(grid) {
1749
+ this._grid = grid;
1750
+ }
1751
+
1752
+ DirectLoadingStrategy.prototype = {
1753
+
1754
+ firstDisplayIndex: function() {
1755
+ var grid = this._grid;
1756
+ return grid.option("paging") ? (grid.option("pageIndex") - 1) * grid.option("pageSize") : 0;
1757
+ },
1758
+
1759
+ lastDisplayIndex: function() {
1760
+ var grid = this._grid;
1761
+ var itemsCount = grid.option("data").length;
1762
+
1763
+ return grid.option("paging")
1764
+ ? Math.min(grid.option("pageIndex") * grid.option("pageSize"), itemsCount)
1765
+ : itemsCount;
1766
+ },
1767
+
1768
+ itemsCount: function() {
1769
+ return this._grid.option("data").length;
1770
+ },
1771
+
1772
+ openPage: function(index) {
1773
+ this._grid.refresh();
1774
+ },
1775
+
1776
+ loadParams: function() {
1777
+ return {};
1778
+ },
1779
+
1780
+ sort: function() {
1781
+ this._grid._sortData();
1782
+ this._grid.refresh();
1783
+ return $.Deferred().resolve().promise();
1784
+ },
1785
+
1786
+ reset: function() {
1787
+ this._grid.refresh();
1788
+ return $.Deferred().resolve().promise();
1789
+ },
1790
+
1791
+ finishLoad: function(loadedData) {
1792
+ this._grid.option("data", loadedData);
1793
+ },
1794
+
1795
+ finishInsert: function(insertedItem, location) {
1796
+ var grid = this._grid;
1797
+
1798
+ switch(location){
1799
+ case "top":
1800
+ grid.option("data").unshift(insertedItem);
1801
+ break;
1802
+ case "bottom":
1803
+ default:
1804
+ grid.option("data").push(insertedItem);
1805
+ }
1806
+
1807
+ grid.refresh();
1808
+ },
1809
+
1810
+ finishDelete: function(deletedItem, deletedItemIndex) {
1811
+ var grid = this._grid;
1812
+ grid.option("data").splice(deletedItemIndex, 1);
1813
+ grid.reset();
1814
+ }
1815
+ };
1816
+
1817
+
1818
+ function PageLoadingStrategy(grid) {
1819
+ this._grid = grid;
1820
+ this._itemsCount = 0;
1821
+ }
1822
+
1823
+ PageLoadingStrategy.prototype = {
1824
+
1825
+ firstDisplayIndex: function() {
1826
+ return 0;
1827
+ },
1828
+
1829
+ lastDisplayIndex: function() {
1830
+ return this._grid.option("data").length;
1831
+ },
1832
+
1833
+ itemsCount: function() {
1834
+ return this._itemsCount;
1835
+ },
1836
+
1837
+ openPage: function(index) {
1838
+ this._grid.loadData();
1839
+ },
1840
+
1841
+ loadParams: function() {
1842
+ var grid = this._grid;
1843
+ return {
1844
+ pageIndex: grid.option("pageIndex"),
1845
+ pageSize: grid.option("pageSize")
1846
+ };
1847
+ },
1848
+
1849
+ reset: function() {
1850
+ return this._grid.loadData();
1851
+ },
1852
+
1853
+ sort: function() {
1854
+ return this._grid.loadData();
1855
+ },
1856
+
1857
+ finishLoad: function(loadedData) {
1858
+ this._itemsCount = loadedData.itemsCount;
1859
+ this._grid.option("data", loadedData.data);
1860
+ },
1861
+
1862
+ finishInsert: function(insertedItem) {
1863
+ this._grid.search();
1864
+ },
1865
+
1866
+ finishDelete: function(deletedItem, deletedItemIndex) {
1867
+ this._grid.search();
1868
+ }
1869
+ };
1870
+
1871
+ jsGrid.loadStrategies = {
1872
+ DirectLoadingStrategy: DirectLoadingStrategy,
1873
+ PageLoadingStrategy: PageLoadingStrategy
1874
+ };
1875
+
1876
+ }(jsGrid, jQuery));
1877
+
1878
+ (function(jsGrid, $, undefined) {
1879
+
1880
+ var isDefined = function(val) {
1881
+ return typeof(val) !== "undefined" && val !== null;
1882
+ };
1883
+
1884
+ var sortStrategies = {
1885
+ string: function(str1, str2) {
1886
+ if(!isDefined(str1) && !isDefined(str2))
1887
+ return 0;
1888
+
1889
+ if(!isDefined(str1))
1890
+ return -1;
1891
+
1892
+ if(!isDefined(str2))
1893
+ return 1;
1894
+
1895
+ return ("" + str1).localeCompare("" + str2);
1896
+ },
1897
+
1898
+ stringNaturalSort: function(str1, str2) {
1899
+ if(!isDefined(str1) && !isDefined(str2))
1900
+ return 0;
1901
+
1902
+ if(!isDefined(str1))
1903
+ return -1;
1904
+
1905
+ if(!isDefined(str2))
1906
+ return 1;
1907
+
1908
+ return ("" + str1).localeCompare("" + str2, undefined, { numeric: true, sensitivity: 'base' });
1909
+ },
1910
+
1911
+ number: function(n1, n2) {
1912
+ return n1 - n2;
1913
+ },
1914
+
1915
+ date: function(dt1, dt2) {
1916
+ return dt1 - dt2;
1917
+ },
1918
+
1919
+ numberAsString: function(n1, n2) {
1920
+ return parseFloat(n1) - parseFloat(n2);
1921
+ }
1922
+ };
1923
+
1924
+ jsGrid.sortStrategies = sortStrategies;
1925
+
1926
+ }(jsGrid, jQuery));
1927
+
1928
+ (function(jsGrid, $, undefined) {
1929
+
1930
+ function Validation(config) {
1931
+ this._init(config);
1932
+ }
1933
+
1934
+ Validation.prototype = {
1935
+
1936
+ _init: function(config) {
1937
+ $.extend(true, this, config);
1938
+ },
1939
+
1940
+ validate: function(args) {
1941
+ var errors = [];
1942
+
1943
+ $.each(this._normalizeRules(args.rules), function(_, rule) {
1944
+ if(rule.validator(args.value, args.item, rule.param))
1945
+ return;
1946
+
1947
+ var errorMessage = $.isFunction(rule.message) ? rule.message(args.value, args.item) : rule.message;
1948
+ errors.push(errorMessage);
1949
+ });
1950
+
1951
+ return errors;
1952
+ },
1953
+
1954
+ _normalizeRules: function(rules) {
1955
+ if(!$.isArray(rules))
1956
+ rules = [rules];
1957
+
1958
+ return $.map(rules, $.proxy(function(rule) {
1959
+ return this._normalizeRule(rule);
1960
+ }, this));
1961
+ },
1962
+
1963
+ _normalizeRule: function(rule) {
1964
+ if(typeof rule === "string")
1965
+ rule = { validator: rule };
1966
+
1967
+ if($.isFunction(rule))
1968
+ rule = { validator: rule };
1969
+
1970
+ if($.isPlainObject(rule))
1971
+ rule = $.extend({}, rule);
1972
+ else
1973
+ throw Error("wrong validation config specified");
1974
+
1975
+ if($.isFunction(rule.validator))
1976
+ return rule;
1977
+
1978
+ return this._applyNamedValidator(rule, rule.validator);
1979
+ },
1980
+
1981
+ _applyNamedValidator: function(rule, validatorName) {
1982
+ delete rule.validator;
1983
+
1984
+ var validator = validators[validatorName];
1985
+ if(!validator)
1986
+ throw Error("unknown validator \"" + validatorName + "\"");
1987
+
1988
+ if($.isFunction(validator)) {
1989
+ validator = { validator: validator };
1990
+ }
1991
+
1992
+ return $.extend({}, validator, rule);
1993
+ }
1994
+ };
1995
+
1996
+ jsGrid.Validation = Validation;
1997
+
1998
+
1999
+ var validators = {
2000
+ required: {
2001
+ message: "Field is required",
2002
+ validator: function(value) {
2003
+ return value !== undefined && value !== null && value !== "";
2004
+ }
2005
+ },
2006
+
2007
+ rangeLength: {
2008
+ message: "Field value length is out of the defined range",
2009
+ validator: function(value, _, param) {
2010
+ return value.length >= param[0] && value.length <= param[1];
2011
+ }
2012
+ },
2013
+
2014
+ minLength: {
2015
+ message: "Field value is too short",
2016
+ validator: function(value, _, param) {
2017
+ return value.length >= param;
2018
+ }
2019
+ },
2020
+
2021
+ maxLength: {
2022
+ message: "Field value is too long",
2023
+ validator: function(value, _, param) {
2024
+ return value.length <= param;
2025
+ }
2026
+ },
2027
+
2028
+ pattern: {
2029
+ message: "Field value is not matching the defined pattern",
2030
+ validator: function(value, _, param) {
2031
+ if(typeof param === "string") {
2032
+ param = new RegExp("^(?:" + param + ")$");
2033
+ }
2034
+ return param.test(value);
2035
+ }
2036
+ },
2037
+
2038
+ range: {
2039
+ message: "Field value is out of the defined range",
2040
+ validator: function(value, _, param) {
2041
+ return value >= param[0] && value <= param[1];
2042
+ }
2043
+ },
2044
+
2045
+ min: {
2046
+ message: "Field value is too small",
2047
+ validator: function(value, _, param) {
2048
+ return value >= param;
2049
+ }
2050
+ },
2051
+
2052
+ max: {
2053
+ message: "Field value is too large",
2054
+ validator: function(value, _, param) {
2055
+ return value <= param;
2056
+ }
2057
+ }
2058
+ };
2059
+
2060
+ jsGrid.validators = validators;
2061
+
2062
+ }(jsGrid, jQuery));
2063
+
2064
+ (function(jsGrid, $, undefined) {
2065
+
2066
+ function Field(config) {
2067
+ $.extend(true, this, config);
2068
+ this.sortingFunc = this._getSortingFunc();
2069
+ }
2070
+
2071
+ Field.prototype = {
2072
+ name: "",
2073
+ title: null,
2074
+ css: "",
2075
+ align: "",
2076
+ width: 100,
2077
+
2078
+ visible: true,
2079
+ filtering: true,
2080
+ inserting: true,
2081
+ editing: true,
2082
+ sorting: true,
2083
+ sorter: "string", // name of SortStrategy or function to compare elements
2084
+
2085
+ includeInDataExport: true,
2086
+
2087
+ headerTemplate: function() {
2088
+ return (this.title === undefined || this.title === null) ? this.name : this.title;
2089
+ },
2090
+
2091
+ itemTemplate: function(value, item) {
2092
+ return value;
2093
+ },
2094
+
2095
+ filterTemplate: function() {
2096
+ return "";
2097
+ },
2098
+
2099
+ insertTemplate: function() {
2100
+ return "";
2101
+ },
2102
+
2103
+ editTemplate: function(value, item) {
2104
+ this._value = value;
2105
+ return this.itemTemplate(value, item);
2106
+ },
2107
+
2108
+ filterValue: function() {
2109
+ return "";
2110
+ },
2111
+
2112
+ insertValue: function() {
2113
+ return "";
2114
+ },
2115
+
2116
+ editValue: function() {
2117
+ return this._value;
2118
+ },
2119
+
2120
+ _getSortingFunc: function() {
2121
+ var sorter = this.sorter;
2122
+
2123
+ if($.isFunction(sorter)) {
2124
+ return sorter;
2125
+ }
2126
+
2127
+ if(typeof sorter === "string") {
2128
+ return jsGrid.sortStrategies[sorter];
2129
+ }
2130
+
2131
+ throw Error("wrong sorter for the field \"" + this.name + "\"!");
2132
+ }
2133
+ };
2134
+
2135
+ jsGrid.Field = Field;
2136
+
2137
+ }(jsGrid, jQuery));