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,1655 @@
1
+ (function(window, $, undefined) {
2
+
3
+ var JSGRID = "JSGrid",
4
+ JSGRID_DATA_KEY = JSGRID,
5
+ JSGRID_ROW_DATA_KEY = "JSGridItem",
6
+ JSGRID_EDIT_ROW_DATA_KEY = "JSGridEditRow",
7
+
8
+ JSGRID_RECYCLED_IDS = [],
9
+ JSGRID_LAST_ID = 0,
10
+ SORT_ORDER_ASC = "asc",
11
+ SORT_ORDER_DESC = "desc",
12
+
13
+ FIRST_PAGE_PLACEHOLDER = "{first}",
14
+ PAGES_PLACEHOLDER = "{pages}",
15
+ PREV_PAGE_PLACEHOLDER = "{prev}",
16
+ NEXT_PAGE_PLACEHOLDER = "{next}",
17
+ LAST_PAGE_PLACEHOLDER = "{last}",
18
+ PAGE_INDEX_PLACEHOLDER = "{pageIndex}",
19
+ PAGE_COUNT_PLACEHOLDER = "{pageCount}",
20
+ ITEM_COUNT_PLACEHOLDER = "{itemCount}",
21
+
22
+ EMPTY_HREF = "javascript:void(0);";
23
+
24
+ var getOrApply = function(value, context) {
25
+ if($.isFunction(value)) {
26
+ return value.apply(context, $.makeArray(arguments).slice(2));
27
+ }
28
+ return value;
29
+ };
30
+
31
+ var normalizePromise = function(promise) {
32
+ var d = $.Deferred();
33
+
34
+ if(promise && promise.then) {
35
+ promise.then(function() {
36
+ d.resolve.apply(d, arguments);
37
+ }, function() {
38
+ d.reject.apply(d, arguments);
39
+ });
40
+ } else {
41
+ d.resolve(promise);
42
+ }
43
+
44
+ return d.promise();
45
+ };
46
+
47
+ var defaultController = {
48
+ loadData: $.noop,
49
+ insertItem: $.noop,
50
+ updateItem: $.noop,
51
+ deleteItem: $.noop
52
+ };
53
+
54
+
55
+ function Grid(element, config) {
56
+ var $element = $(element);
57
+
58
+ if (JSGRID_RECYCLED_IDS.length==0) {
59
+ this._id=JSGRID_LAST_ID;
60
+ JSGRID_LAST_ID++;
61
+ } else {
62
+ this._id=JSGRID_RECYCLED_IDS.pop();
63
+ }
64
+
65
+ $element.data(JSGRID_DATA_KEY, this);
66
+
67
+ this._container = $element;
68
+
69
+ this.data = [];
70
+ this.fields = [];
71
+
72
+ this._editingRow = null;
73
+ this._sortField = null;
74
+ this._sortOrder = SORT_ORDER_ASC;
75
+ this._firstDisplayingPage = 1;
76
+
77
+ this._init(config);
78
+ this.render();
79
+ }
80
+
81
+ Grid.prototype = {
82
+ width: "auto",
83
+ height: "auto",
84
+ updateOnResize: true,
85
+
86
+ rowClass: $.noop,
87
+ rowRenderer: null,
88
+
89
+ rowClick: function(args) {
90
+ if(this.editing) {
91
+ this.editItem($(args.event.target).closest("tr"));
92
+ }
93
+ },
94
+ rowDoubleClick: $.noop,
95
+
96
+ noDataContent: "Not found",
97
+ noDataRowClass: "jsgrid-nodata-row",
98
+
99
+ heading: true,
100
+ headerRowRenderer: null,
101
+ headerRowClass: "jsgrid-header-row",
102
+ headerCellClass: "jsgrid-header-cell",
103
+
104
+ filtering: false,
105
+ filterRowRenderer: null,
106
+ filterRowClass: "jsgrid-filter-row",
107
+
108
+ inserting: false,
109
+ insertRowLocation: "bottom",
110
+ insertRowRenderer: null,
111
+ insertRowClass: "jsgrid-insert-row",
112
+
113
+ editing: false,
114
+ editRowRenderer: null,
115
+ editRowClass: "jsgrid-edit-row",
116
+
117
+ confirmDeleting: true,
118
+ deleteConfirm: "Are you sure?",
119
+
120
+ selecting: true,
121
+ selectedRowClass: "jsgrid-selected-row",
122
+ oddRowClass: "jsgrid-row",
123
+ evenRowClass: "jsgrid-alt-row",
124
+ cellClass: "jsgrid-cell",
125
+
126
+ sorting: false,
127
+ sortableClass: "jsgrid-header-sortable",
128
+ sortAscClass: "jsgrid-header-sort jsgrid-header-sort-asc",
129
+ sortDescClass: "jsgrid-header-sort jsgrid-header-sort-desc",
130
+
131
+ paging: false,
132
+ pagerContainer: null,
133
+ pageIndex: 1,
134
+ pageSize: 20,
135
+ pageButtonCount: 15,
136
+ pagerFormat: "Pages: {first} {prev} {pages} {next} {last}    {pageIndex} of {pageCount}",
137
+ pagePrevText: "Prev",
138
+ pageNextText: "Next",
139
+ pageFirstText: "First",
140
+ pageLastText: "Last",
141
+ pageNavigatorNextText: "...",
142
+ pageNavigatorPrevText: "...",
143
+ pagerContainerClass: "jsgrid-pager-container",
144
+ pagerClass: "jsgrid-pager",
145
+ pagerNavButtonClass: "jsgrid-pager-nav-button",
146
+ pagerNavButtonInactiveClass: "jsgrid-pager-nav-inactive-button",
147
+ pageClass: "jsgrid-pager-page",
148
+ currentPageClass: "jsgrid-pager-current-page",
149
+
150
+ customLoading: false,
151
+ pageLoading: false,
152
+
153
+ autoload: false,
154
+ controller: defaultController,
155
+
156
+ loadIndication: true,
157
+ loadIndicationDelay: 500,
158
+ loadMessage: "Please, wait...",
159
+ loadShading: true,
160
+
161
+ invalidMessage: "Invalid data entered!",
162
+
163
+ invalidNotify: function(args) {
164
+ var messages = $.map(args.errors, function(error) {
165
+ return error.message || null;
166
+ });
167
+
168
+ window.alert([this.invalidMessage].concat(messages).join("\n"));
169
+ },
170
+
171
+ onInit: $.noop,
172
+ onRefreshing: $.noop,
173
+ onRefreshed: $.noop,
174
+ onPageChanged: $.noop,
175
+ onItemDeleting: $.noop,
176
+ onItemDeleted: $.noop,
177
+ onItemInserting: $.noop,
178
+ onItemInserted: $.noop,
179
+ onItemEditing: $.noop,
180
+ onItemEditCancelling: $.noop,
181
+ onItemUpdating: $.noop,
182
+ onItemUpdated: $.noop,
183
+ onItemInvalid: $.noop,
184
+ onDataLoading: $.noop,
185
+ onDataLoaded: $.noop,
186
+ onDataExporting: $.noop,
187
+ onOptionChanging: $.noop,
188
+ onOptionChanged: $.noop,
189
+ onError: $.noop,
190
+
191
+ invalidClass: "jsgrid-invalid",
192
+
193
+ containerClass: "jsgrid",
194
+ tableClass: "jsgrid-table",
195
+ gridHeaderClass: "jsgrid-grid-header",
196
+ gridBodyClass: "jsgrid-grid-body",
197
+
198
+ _init: function(config) {
199
+ $.extend(this, config);
200
+ this._initLoadStrategy();
201
+ this._initController();
202
+ this._initFields();
203
+ this._attachWindowLoadResize();
204
+ this._attachWindowResizeCallback();
205
+ this._callEventHandler(this.onInit)
206
+ },
207
+
208
+ loadStrategy: function() {
209
+ return this.pageLoading
210
+ ? new jsGrid.loadStrategies.PageLoadingStrategy(this)
211
+ : new jsGrid.loadStrategies.DirectLoadingStrategy(this);
212
+ },
213
+
214
+ _initLoadStrategy: function() {
215
+ this._loadStrategy = getOrApply(this.loadStrategy, this);
216
+ },
217
+
218
+ _initController: function() {
219
+ this._controller = $.extend({}, defaultController, getOrApply(this.controller, this));
220
+ },
221
+
222
+ renderTemplate: function(source, context, config) {
223
+ var args = [];
224
+ for(var key in config) {
225
+ args.push(config[key]);
226
+ }
227
+
228
+ args.unshift(source, context);
229
+
230
+ source = getOrApply.apply(null, args);
231
+ return (source === undefined || source === null) ? "" : source;
232
+ },
233
+
234
+ loadIndicator: function(config) {
235
+ return new jsGrid.LoadIndicator(config);
236
+ },
237
+
238
+ validation: function(config) {
239
+ return jsGrid.Validation && new jsGrid.Validation(config);
240
+ },
241
+
242
+ _initFields: function() {
243
+ var self = this;
244
+ self.fields = $.map(self.fields, function(field) {
245
+ if($.isPlainObject(field)) {
246
+ var fieldConstructor = (field.type && jsGrid.fields[field.type]) || jsGrid.Field;
247
+ field = new fieldConstructor(field);
248
+ }
249
+ field._grid = self;
250
+ return field;
251
+ });
252
+ },
253
+
254
+ _attachWindowLoadResize: function() {
255
+ $(window).on("load.table-"+this._id, $.proxy(this._refreshSize, this));
256
+ },
257
+
258
+ _attachWindowResizeCallback: function() {
259
+ if(this.updateOnResize) {
260
+ $(window).on("resize.table-"+this._id, $.proxy(this._refreshSize, this));
261
+ }
262
+ },
263
+
264
+ _detachWindowLoadResize: function() {
265
+ $(window).off("load.table-"+this._id);
266
+ },
267
+
268
+ _detachWindowResizeCallback: function() {
269
+ $(window).off("resize.table-"+this._id);
270
+ },
271
+
272
+ option: function(key, value) {
273
+ var optionChangingEventArgs,
274
+ optionChangedEventArgs;
275
+
276
+ if(arguments.length === 1)
277
+ return this[key];
278
+
279
+ optionChangingEventArgs = {
280
+ option: key,
281
+ oldValue: this[key],
282
+ newValue: value
283
+ };
284
+ this._callEventHandler(this.onOptionChanging, optionChangingEventArgs);
285
+
286
+ this._handleOptionChange(optionChangingEventArgs.option, optionChangingEventArgs.newValue);
287
+
288
+ optionChangedEventArgs = {
289
+ option: optionChangingEventArgs.option,
290
+ value: optionChangingEventArgs.newValue
291
+ };
292
+ this._callEventHandler(this.onOptionChanged, optionChangedEventArgs);
293
+ },
294
+
295
+ fieldOption: function(field, key, value) {
296
+ field = this._normalizeField(field);
297
+
298
+ if(arguments.length === 2)
299
+ return field[key];
300
+
301
+ field[key] = value;
302
+ this._renderGrid();
303
+ },
304
+
305
+ _handleOptionChange: function(name, value) {
306
+ this[name] = value;
307
+
308
+ switch(name) {
309
+ case "width":
310
+ case "height":
311
+ this._refreshSize();
312
+ break;
313
+ case "rowClass":
314
+ case "rowRenderer":
315
+ case "rowClick":
316
+ case "rowDoubleClick":
317
+ case "noDataRowClass":
318
+ case "noDataContent":
319
+ case "selecting":
320
+ case "selectedRowClass":
321
+ case "oddRowClass":
322
+ case "evenRowClass":
323
+ this._refreshContent();
324
+ break;
325
+ case "pageButtonCount":
326
+ case "pagerFormat":
327
+ case "pagePrevText":
328
+ case "pageNextText":
329
+ case "pageFirstText":
330
+ case "pageLastText":
331
+ case "pageNavigatorNextText":
332
+ case "pageNavigatorPrevText":
333
+ case "pagerClass":
334
+ case "pagerNavButtonClass":
335
+ case "pageClass":
336
+ case "currentPageClass":
337
+ case "pagerRenderer":
338
+ this._refreshPager();
339
+ break;
340
+ case "fields":
341
+ this._initFields();
342
+ this.render();
343
+ break;
344
+ case "data":
345
+ case "editing":
346
+ case "heading":
347
+ case "filtering":
348
+ case "inserting":
349
+ case "paging":
350
+ this.refresh();
351
+ break;
352
+ case "loadStrategy":
353
+ case "pageLoading":
354
+ this._initLoadStrategy();
355
+ this.search();
356
+ break;
357
+ case "pageIndex":
358
+ this.openPage(value);
359
+ break;
360
+ case "pageSize":
361
+ this.refresh();
362
+ this.search();
363
+ break;
364
+ case "editRowRenderer":
365
+ case "editRowClass":
366
+ this.cancelEdit();
367
+ break;
368
+ case "updateOnResize":
369
+ this._detachWindowResizeCallback();
370
+ this._attachWindowResizeCallback();
371
+ break;
372
+ case "invalidNotify":
373
+ case "invalidMessage":
374
+ break;
375
+ default:
376
+ this.render();
377
+ break;
378
+ }
379
+ },
380
+
381
+ destroy: function() {
382
+ this._detachWindowResizeCallback();
383
+ this._detachWindowLoadResize();
384
+ JSGRID_RECYCLED_IDS.push(this._id);
385
+ this._clear();
386
+ this._container.removeData(JSGRID_DATA_KEY);
387
+ },
388
+
389
+ render: function() {
390
+ this._renderGrid();
391
+ return this.autoload ? this.loadData() : $.Deferred().resolve().promise();
392
+ },
393
+
394
+ _renderGrid: function() {
395
+ this._clear();
396
+
397
+ this._container.addClass(this.containerClass)
398
+ .css("position", "relative")
399
+ .append(this._createHeader())
400
+ .append(this._createBody());
401
+
402
+ this._pagerContainer = this._createPagerContainer();
403
+ this._loadIndicator = this._createLoadIndicator();
404
+ this._validation = this._createValidation();
405
+
406
+ this.refresh();
407
+ },
408
+
409
+ _createLoadIndicator: function() {
410
+ return getOrApply(this.loadIndicator, this, {
411
+ message: this.loadMessage,
412
+ shading: this.loadShading,
413
+ container: this._container
414
+ });
415
+ },
416
+
417
+ _createValidation: function() {
418
+ return getOrApply(this.validation, this);
419
+ },
420
+
421
+ _clear: function() {
422
+ this.cancelEdit();
423
+
424
+ clearTimeout(this._loadingTimer);
425
+
426
+ this._pagerContainer && this._pagerContainer.empty();
427
+
428
+ this._container.empty()
429
+ .css({ position: "", width: "", height: "" });
430
+ },
431
+
432
+ _createHeader: function() {
433
+ var $headerRow = this._headerRow = this._createHeaderRow(),
434
+ $filterRow = this._filterRow = this._createFilterRow(),
435
+ $insertRow = this._insertRow = this._createInsertRow();
436
+
437
+ var $headerGrid = this._headerGrid = $("<table>").addClass(this.tableClass)
438
+ .append($headerRow)
439
+ .append($filterRow)
440
+ .append($insertRow);
441
+
442
+ var $header = this._header = $("<div>").addClass(this.gridHeaderClass)
443
+ .addClass(this._scrollBarWidth() ? "jsgrid-header-scrollbar" : "")
444
+ .append($headerGrid);
445
+
446
+ return $header;
447
+ },
448
+
449
+ _createBody: function() {
450
+ var $content = this._content = $("<tbody>");
451
+
452
+ var $bodyGrid = this._bodyGrid = $("<table>").addClass(this.tableClass)
453
+ .append($content);
454
+
455
+ var $body = this._body = $("<div>").addClass(this.gridBodyClass)
456
+ .append($bodyGrid)
457
+ .on("scroll", $.proxy(function(e) {
458
+ this._header.scrollLeft(e.target.scrollLeft);
459
+ }, this));
460
+
461
+ return $body;
462
+ },
463
+
464
+ _createPagerContainer: function() {
465
+ var pagerContainer = this.pagerContainer || $("<div>").appendTo(this._container);
466
+ return $(pagerContainer).addClass(this.pagerContainerClass);
467
+ },
468
+
469
+ _eachField: function(callBack) {
470
+ var self = this;
471
+ $.each(this.fields, function(index, field) {
472
+ if(field.visible) {
473
+ callBack.call(self, field, index);
474
+ }
475
+ });
476
+ },
477
+
478
+ _createHeaderRow: function() {
479
+ if($.isFunction(this.headerRowRenderer))
480
+ return $(this.renderTemplate(this.headerRowRenderer, this));
481
+
482
+ var $result = $("<tr>").addClass(this.headerRowClass);
483
+
484
+ this._eachField(function(field, index) {
485
+ var $th = this._prepareCell("<th>", field, "headercss", this.headerCellClass)
486
+ .append(this.renderTemplate(field.headerTemplate, field))
487
+ .appendTo($result);
488
+
489
+ if(this.sorting && field.sorting) {
490
+ $th.addClass(this.sortableClass)
491
+ .on("click", $.proxy(function() {
492
+ this.sort(index);
493
+ }, this));
494
+ }
495
+ });
496
+
497
+ return $result;
498
+ },
499
+
500
+ _prepareCell: function(cell, field, cssprop, cellClass) {
501
+ return $(cell).css("width", field.width)
502
+ .addClass(cellClass || this.cellClass)
503
+ .addClass((cssprop && field[cssprop]) || field.css)
504
+ .addClass(field.align ? ("jsgrid-align-" + field.align) : "");
505
+ },
506
+
507
+ _createFilterRow: function() {
508
+ if($.isFunction(this.filterRowRenderer))
509
+ return $(this.renderTemplate(this.filterRowRenderer, this));
510
+
511
+ var $result = $("<tr>").addClass(this.filterRowClass);
512
+
513
+ this._eachField(function(field) {
514
+ this._prepareCell("<td>", field, "filtercss")
515
+ .append(this.renderTemplate(field.filterTemplate, field))
516
+ .appendTo($result);
517
+ });
518
+
519
+ return $result;
520
+ },
521
+
522
+ _createInsertRow: function() {
523
+ if($.isFunction(this.insertRowRenderer))
524
+ return $(this.renderTemplate(this.insertRowRenderer, this));
525
+
526
+ var $result = $("<tr>").addClass(this.insertRowClass);
527
+
528
+ this._eachField(function(field) {
529
+ this._prepareCell("<td>", field, "insertcss")
530
+ .append(this.renderTemplate(field.insertTemplate, field))
531
+ .appendTo($result);
532
+ });
533
+
534
+ return $result;
535
+ },
536
+
537
+ _callEventHandler: function(handler, eventParams) {
538
+ handler.call(this, $.extend(eventParams, {
539
+ grid: this
540
+ }));
541
+
542
+ return eventParams;
543
+ },
544
+
545
+ reset: function() {
546
+ this._resetSorting();
547
+ this._resetPager();
548
+ return this._loadStrategy.reset();
549
+ },
550
+
551
+ _resetPager: function() {
552
+ this._firstDisplayingPage = 1;
553
+ this._setPage(1);
554
+ },
555
+
556
+ _resetSorting: function() {
557
+ this._sortField = null;
558
+ this._sortOrder = SORT_ORDER_ASC;
559
+ this._clearSortingCss();
560
+ },
561
+
562
+ refresh: function() {
563
+ this._callEventHandler(this.onRefreshing);
564
+
565
+ this.cancelEdit();
566
+
567
+ this._refreshHeading();
568
+ this._refreshFiltering();
569
+ this._refreshInserting();
570
+ this._refreshContent();
571
+ this._refreshPager();
572
+ this._refreshSize();
573
+
574
+ this._callEventHandler(this.onRefreshed);
575
+ },
576
+
577
+ _refreshHeading: function() {
578
+ this._headerRow.toggle(this.heading);
579
+ },
580
+
581
+ _refreshFiltering: function() {
582
+ this._filterRow.toggle(this.filtering);
583
+ },
584
+
585
+ _refreshInserting: function() {
586
+ this._insertRow.toggle(this.inserting);
587
+ },
588
+
589
+ _refreshContent: function() {
590
+ var $content = this._content;
591
+ $content.empty();
592
+
593
+ if(!this.data.length) {
594
+ $content.append(this._createNoDataRow());
595
+ return this;
596
+ }
597
+
598
+ var indexFrom = this._loadStrategy.firstDisplayIndex();
599
+ var indexTo = this._loadStrategy.lastDisplayIndex();
600
+
601
+ for(var itemIndex = indexFrom; itemIndex < indexTo; itemIndex++) {
602
+ var item = this.data[itemIndex];
603
+ $content.append(this._createRow(item, itemIndex));
604
+ }
605
+ },
606
+
607
+ _createNoDataRow: function() {
608
+ var amountOfFields = 0;
609
+ this._eachField(function() {
610
+ amountOfFields++;
611
+ });
612
+
613
+ return $("<tr>").addClass(this.noDataRowClass)
614
+ .append($("<td>").addClass(this.cellClass).attr("colspan", amountOfFields)
615
+ .append(this.renderTemplate(this.noDataContent, this)));
616
+ },
617
+
618
+ _createRow: function(item, itemIndex) {
619
+ var $result;
620
+
621
+ if($.isFunction(this.rowRenderer)) {
622
+ $result = this.renderTemplate(this.rowRenderer, this, { item: item, itemIndex: itemIndex });
623
+ } else {
624
+ $result = $("<tr>");
625
+ this._renderCells($result, item);
626
+ }
627
+
628
+ $result.addClass(this._getRowClasses(item, itemIndex))
629
+ .data(JSGRID_ROW_DATA_KEY, item)
630
+ .on("click", $.proxy(function(e) {
631
+ this.rowClick({
632
+ item: item,
633
+ itemIndex: itemIndex,
634
+ event: e
635
+ });
636
+ }, this))
637
+ .on("dblclick", $.proxy(function(e) {
638
+ this.rowDoubleClick({
639
+ item: item,
640
+ itemIndex: itemIndex,
641
+ event: e
642
+ });
643
+ }, this));
644
+
645
+ if(this.selecting) {
646
+ this._attachRowHover($result);
647
+ }
648
+
649
+ return $result;
650
+ },
651
+
652
+ _getRowClasses: function(item, itemIndex) {
653
+ var classes = [];
654
+ classes.push(((itemIndex + 1) % 2) ? this.oddRowClass : this.evenRowClass);
655
+ classes.push(getOrApply(this.rowClass, this, item, itemIndex));
656
+ return classes.join(" ");
657
+ },
658
+
659
+ _attachRowHover: function($row) {
660
+ var selectedRowClass = this.selectedRowClass;
661
+ $row.hover(function() {
662
+ $(this).addClass(selectedRowClass);
663
+ },
664
+ function() {
665
+ $(this).removeClass(selectedRowClass);
666
+ }
667
+ );
668
+ },
669
+
670
+ _renderCells: function($row, item) {
671
+ this._eachField(function(field) {
672
+ $row.append(this._createCell(item, field));
673
+ });
674
+ return this;
675
+ },
676
+
677
+ _createCell: function(item, field) {
678
+ var $result;
679
+ var fieldValue = this._getItemFieldValue(item, field);
680
+
681
+ var args = { value: fieldValue, item : item };
682
+ if($.isFunction(field.cellRenderer)) {
683
+ $result = this.renderTemplate(field.cellRenderer, field, args);
684
+ } else {
685
+ $result = $("<td>").append(this.renderTemplate(field.itemTemplate || fieldValue, field, args));
686
+ }
687
+
688
+ return this._prepareCell($result, field);
689
+ },
690
+
691
+ _getItemFieldValue: function(item, field) {
692
+ var props = field.name.split('.');
693
+ var result = item[props.shift()];
694
+
695
+ while(result && props.length) {
696
+ result = result[props.shift()];
697
+ }
698
+
699
+ return result;
700
+ },
701
+
702
+ _setItemFieldValue: function(item, field, value) {
703
+ var props = field.name.split('.');
704
+ var current = item;
705
+ var prop = props[0];
706
+
707
+ while(current && props.length) {
708
+ item = current;
709
+ prop = props.shift();
710
+ current = item[prop];
711
+ }
712
+
713
+ if(!current) {
714
+ while(props.length) {
715
+ item = item[prop] = {};
716
+ prop = props.shift();
717
+ }
718
+ }
719
+
720
+ item[prop] = value;
721
+ },
722
+
723
+ sort: function(field, order) {
724
+ if($.isPlainObject(field)) {
725
+ order = field.order;
726
+ field = field.field;
727
+ }
728
+
729
+ this._clearSortingCss();
730
+ this._setSortingParams(field, order);
731
+ this._setSortingCss();
732
+ return this._loadStrategy.sort();
733
+ },
734
+
735
+ _clearSortingCss: function() {
736
+ this._headerRow.find("th")
737
+ .removeClass(this.sortAscClass)
738
+ .removeClass(this.sortDescClass);
739
+ },
740
+
741
+ _setSortingParams: function(field, order) {
742
+ field = this._normalizeField(field);
743
+ order = order || ((this._sortField === field) ? this._reversedSortOrder(this._sortOrder) : SORT_ORDER_ASC);
744
+
745
+ this._sortField = field;
746
+ this._sortOrder = order;
747
+ },
748
+
749
+ _normalizeField: function(field) {
750
+ if($.isNumeric(field)) {
751
+ return this.fields[field];
752
+ }
753
+
754
+ if(typeof field === "string") {
755
+ return $.grep(this.fields, function(f) {
756
+ return f.name === field;
757
+ })[0];
758
+ }
759
+
760
+ return field;
761
+ },
762
+
763
+ _reversedSortOrder: function(order) {
764
+ return (order === SORT_ORDER_ASC ? SORT_ORDER_DESC : SORT_ORDER_ASC);
765
+ },
766
+
767
+ _setSortingCss: function() {
768
+ var fieldIndex = this._visibleFieldIndex(this._sortField);
769
+
770
+ this._headerRow.find("th").eq(fieldIndex)
771
+ .addClass(this._sortOrder === SORT_ORDER_ASC ? this.sortAscClass : this.sortDescClass);
772
+ },
773
+
774
+ _visibleFieldIndex: function(field) {
775
+ return $.inArray(field, $.grep(this.fields, function(f) { return f.visible; }));
776
+ },
777
+
778
+ _sortData: function() {
779
+ var sortFactor = this._sortFactor(),
780
+ sortField = this._sortField;
781
+
782
+ if(sortField) {
783
+ var self = this;
784
+ self.data.sort(function(item1, item2) {
785
+ var value1 = self._getItemFieldValue(item1, sortField);
786
+ var value2 = self._getItemFieldValue(item2, sortField);
787
+ return sortFactor * sortField.sortingFunc(value1, value2);
788
+ });
789
+ }
790
+ },
791
+
792
+ _sortFactor: function() {
793
+ return this._sortOrder === SORT_ORDER_ASC ? 1 : -1;
794
+ },
795
+
796
+ _itemsCount: function() {
797
+ return this._loadStrategy.itemsCount();
798
+ },
799
+
800
+ _pagesCount: function() {
801
+ var itemsCount = this._itemsCount(),
802
+ pageSize = this.pageSize;
803
+ return Math.floor(itemsCount / pageSize) + (itemsCount % pageSize ? 1 : 0);
804
+ },
805
+
806
+ _refreshPager: function() {
807
+ var $pagerContainer = this._pagerContainer;
808
+ $pagerContainer.empty();
809
+
810
+ if(this.paging) {
811
+ $pagerContainer.append(this._createPager());
812
+ }
813
+
814
+ var showPager = this.paging && this._pagesCount() > 1;
815
+ $pagerContainer.toggle(showPager);
816
+ },
817
+
818
+ _createPager: function() {
819
+ var $result;
820
+
821
+ if($.isFunction(this.pagerRenderer)) {
822
+ $result = $(this.pagerRenderer({
823
+ pageIndex: this.pageIndex,
824
+ pageCount: this._pagesCount()
825
+ }));
826
+ } else {
827
+ $result = $("<div>").append(this._createPagerByFormat());
828
+ }
829
+
830
+ $result.addClass(this.pagerClass);
831
+
832
+ return $result;
833
+ },
834
+
835
+ _createPagerByFormat: function() {
836
+ var pageIndex = this.pageIndex,
837
+ pageCount = this._pagesCount(),
838
+ itemCount = this._itemsCount(),
839
+ pagerParts = this.pagerFormat.split(" ");
840
+
841
+ return $.map(pagerParts, $.proxy(function(pagerPart) {
842
+ var result = pagerPart;
843
+
844
+ if(pagerPart === PAGES_PLACEHOLDER) {
845
+ result = this._createPages();
846
+ } else if(pagerPart === FIRST_PAGE_PLACEHOLDER) {
847
+ result = this._createPagerNavButton(this.pageFirstText, 1, pageIndex > 1);
848
+ } else if(pagerPart === PREV_PAGE_PLACEHOLDER) {
849
+ result = this._createPagerNavButton(this.pagePrevText, pageIndex - 1, pageIndex > 1);
850
+ } else if(pagerPart === NEXT_PAGE_PLACEHOLDER) {
851
+ result = this._createPagerNavButton(this.pageNextText, pageIndex + 1, pageIndex < pageCount);
852
+ } else if(pagerPart === LAST_PAGE_PLACEHOLDER) {
853
+ result = this._createPagerNavButton(this.pageLastText, pageCount, pageIndex < pageCount);
854
+ } else if(pagerPart === PAGE_INDEX_PLACEHOLDER) {
855
+ result = pageIndex;
856
+ } else if(pagerPart === PAGE_COUNT_PLACEHOLDER) {
857
+ result = pageCount;
858
+ } else if(pagerPart === ITEM_COUNT_PLACEHOLDER) {
859
+ result = itemCount;
860
+ }
861
+
862
+ return $.isArray(result) ? result.concat([" "]) : [result, " "];
863
+ }, this));
864
+ },
865
+
866
+ _createPages: function() {
867
+ var pageCount = this._pagesCount(),
868
+ pageButtonCount = this.pageButtonCount,
869
+ firstDisplayingPage = this._firstDisplayingPage,
870
+ pages = [];
871
+
872
+ if(firstDisplayingPage > 1) {
873
+ pages.push(this._createPagerPageNavButton(this.pageNavigatorPrevText, this.showPrevPages));
874
+ }
875
+
876
+ for(var i = 0, pageNumber = firstDisplayingPage; i < pageButtonCount && pageNumber <= pageCount; i++, pageNumber++) {
877
+ pages.push(pageNumber === this.pageIndex
878
+ ? this._createPagerCurrentPage()
879
+ : this._createPagerPage(pageNumber));
880
+ }
881
+
882
+ if((firstDisplayingPage + pageButtonCount - 1) < pageCount) {
883
+ pages.push(this._createPagerPageNavButton(this.pageNavigatorNextText, this.showNextPages));
884
+ }
885
+
886
+ return pages;
887
+ },
888
+
889
+ _createPagerNavButton: function(text, pageIndex, isActive) {
890
+ return this._createPagerButton(text, this.pagerNavButtonClass + (isActive ? "" : " " + this.pagerNavButtonInactiveClass),
891
+ isActive ? function() { this.openPage(pageIndex); } : $.noop);
892
+ },
893
+
894
+ _createPagerPageNavButton: function(text, handler) {
895
+ return this._createPagerButton(text, this.pagerNavButtonClass, handler);
896
+ },
897
+
898
+ _createPagerPage: function(pageIndex) {
899
+ return this._createPagerButton(pageIndex, this.pageClass, function() {
900
+ this.openPage(pageIndex);
901
+ });
902
+ },
903
+
904
+ _createPagerButton: function(text, css, handler) {
905
+ var $link = $("<a>").attr("href", EMPTY_HREF)
906
+ .html(text)
907
+ .on("click", $.proxy(handler, this));
908
+
909
+ return $("<span>").addClass(css).append($link);
910
+ },
911
+
912
+ _createPagerCurrentPage: function() {
913
+ return $("<span>")
914
+ .addClass(this.pageClass)
915
+ .addClass(this.currentPageClass)
916
+ .text(this.pageIndex);
917
+ },
918
+
919
+ _refreshSize: function() {
920
+ this._refreshHeight();
921
+ this._refreshWidth();
922
+ },
923
+
924
+ _refreshWidth: function() {
925
+ var width = (this.width === "auto") ? this._getAutoWidth() : this.width;
926
+
927
+ this._container.width(width);
928
+ },
929
+
930
+ _getAutoWidth: function() {
931
+ var $headerGrid = this._headerGrid,
932
+ $header = this._header;
933
+
934
+ $headerGrid.width("auto");
935
+
936
+ var contentWidth = $headerGrid.outerWidth();
937
+ var borderWidth = $header.outerWidth() - $header.innerWidth();
938
+
939
+ $headerGrid.width("");
940
+
941
+ return contentWidth + borderWidth;
942
+ },
943
+
944
+ _scrollBarWidth: (function() {
945
+ var result;
946
+
947
+ return function() {
948
+ if(result === undefined) {
949
+ var $ghostContainer = $("<div></div>");
950
+ var ghostContainer = $ghostContainer.get(0);
951
+ ghostContainer.style.width = "50px";
952
+ ghostContainer.style.height = "50px";
953
+ ghostContainer.style.position = "absolute";
954
+ ghostContainer.style.top = "-10000px";
955
+ ghostContainer.style.left = "-10000px";
956
+ var $ghostContent = $("<div></div>");
957
+ var ghostContent = $ghostContent.get(0);
958
+ ghostContent.style.height = "100px";
959
+ $ghostContainer.append($ghostContent).appendTo("body");
960
+ var width = $ghostContent.innerWidth();
961
+ $ghostContainer.get(0).style.overflowY = "auto";
962
+ var widthExcludingScrollBar = $ghostContent.innerWidth();
963
+ $ghostContainer.remove();
964
+ result = width - widthExcludingScrollBar;
965
+ }
966
+ return result;
967
+ };
968
+ })(),
969
+
970
+ _refreshHeight: function() {
971
+ var container = this._container,
972
+ pagerContainer = this._pagerContainer,
973
+ height = this.height,
974
+ nonBodyHeight;
975
+
976
+ container.height(height);
977
+
978
+ if(height !== "auto") {
979
+ height = container.height();
980
+
981
+ nonBodyHeight = this._header.outerHeight(true);
982
+ if(pagerContainer.parents(container).length) {
983
+ nonBodyHeight += pagerContainer.outerHeight(true);
984
+ }
985
+
986
+ this._body.outerHeight(height - nonBodyHeight);
987
+ }
988
+ },
989
+
990
+ showPrevPages: function() {
991
+ var firstDisplayingPage = this._firstDisplayingPage,
992
+ pageButtonCount = this.pageButtonCount;
993
+
994
+ this._firstDisplayingPage = (firstDisplayingPage > pageButtonCount) ? firstDisplayingPage - pageButtonCount : 1;
995
+
996
+ this._refreshPager();
997
+ },
998
+
999
+ showNextPages: function() {
1000
+ var firstDisplayingPage = this._firstDisplayingPage,
1001
+ pageButtonCount = this.pageButtonCount,
1002
+ pageCount = this._pagesCount();
1003
+
1004
+ this._firstDisplayingPage = (firstDisplayingPage + 2 * pageButtonCount > pageCount)
1005
+ ? pageCount - pageButtonCount + 1
1006
+ : firstDisplayingPage + pageButtonCount;
1007
+
1008
+ this._refreshPager();
1009
+ },
1010
+
1011
+ openPage: function(pageIndex) {
1012
+ if(pageIndex < 1 || pageIndex > this._pagesCount())
1013
+ return;
1014
+
1015
+ this._setPage(pageIndex);
1016
+ this._loadStrategy.openPage(pageIndex);
1017
+ },
1018
+
1019
+ _setPage: function(pageIndex) {
1020
+ var firstDisplayingPage = this._firstDisplayingPage,
1021
+ pageButtonCount = this.pageButtonCount;
1022
+
1023
+ this.pageIndex = pageIndex;
1024
+
1025
+ if(pageIndex < firstDisplayingPage) {
1026
+ this._firstDisplayingPage = pageIndex;
1027
+ }
1028
+
1029
+ if(pageIndex > firstDisplayingPage + pageButtonCount - 1) {
1030
+ this._firstDisplayingPage = pageIndex - pageButtonCount + 1;
1031
+ }
1032
+
1033
+ this._callEventHandler(this.onPageChanged, {
1034
+ pageIndex: pageIndex
1035
+ });
1036
+ },
1037
+
1038
+ _controllerCall: function(method, param, isCanceled, doneCallback) {
1039
+ if(isCanceled)
1040
+ return $.Deferred().reject().promise();
1041
+
1042
+ this._showLoading();
1043
+
1044
+ var controller = this._controller;
1045
+ if(!controller || !controller[method]) {
1046
+ throw Error("controller has no method '" + method + "'");
1047
+ }
1048
+
1049
+ return normalizePromise(controller[method](param))
1050
+ .done($.proxy(doneCallback, this))
1051
+ .fail($.proxy(this._errorHandler, this))
1052
+ .always($.proxy(this._hideLoading, this));
1053
+ },
1054
+
1055
+ _errorHandler: function() {
1056
+ this._callEventHandler(this.onError, {
1057
+ args: $.makeArray(arguments)
1058
+ });
1059
+ },
1060
+
1061
+ _showLoading: function() {
1062
+ if(!this.loadIndication)
1063
+ return;
1064
+
1065
+ clearTimeout(this._loadingTimer);
1066
+
1067
+ this._loadingTimer = setTimeout($.proxy(function() {
1068
+ this._loadIndicator.show();
1069
+ }, this), this.loadIndicationDelay);
1070
+ },
1071
+
1072
+ _hideLoading: function() {
1073
+ if(!this.loadIndication)
1074
+ return;
1075
+
1076
+ clearTimeout(this._loadingTimer);
1077
+ this._loadIndicator.hide();
1078
+ },
1079
+
1080
+ search: function(filter) {
1081
+ this._resetSorting();
1082
+ this._resetPager();
1083
+ return this.loadData(filter);
1084
+ },
1085
+
1086
+ loadData: function(filter) {
1087
+ filter = filter || (this.filtering ? this.getFilter() : {});
1088
+
1089
+ $.extend(filter, this._loadStrategy.loadParams(), this._sortingParams());
1090
+
1091
+ var args = this._callEventHandler(this.onDataLoading, {
1092
+ filter: filter
1093
+ });
1094
+
1095
+ return this._controllerCall("loadData", filter, args.cancel, function(loadedData) {
1096
+ if(!loadedData)
1097
+ return;
1098
+
1099
+ this._loadStrategy.finishLoad(loadedData);
1100
+
1101
+ this._callEventHandler(this.onDataLoaded, {
1102
+ data: loadedData
1103
+ });
1104
+ });
1105
+ },
1106
+
1107
+ exportData: function(exportOptions){
1108
+ var options = exportOptions || {};
1109
+ var type = options.type || "csv";
1110
+
1111
+ var result = "";
1112
+
1113
+ this._callEventHandler(this.onDataExporting);
1114
+
1115
+ switch(type){
1116
+
1117
+ case "csv":
1118
+ result = this._dataToCsv(options);
1119
+ break;
1120
+
1121
+ }
1122
+ return result;
1123
+ },
1124
+
1125
+ _dataToCsv: function(options){
1126
+ var options = options || {};
1127
+ var includeHeaders = options.hasOwnProperty("includeHeaders") ? options.includeHeaders : true;
1128
+ var subset = options.subset || "all";
1129
+ var filter = options.filter || undefined;
1130
+
1131
+ var result = [];
1132
+
1133
+ if (includeHeaders){
1134
+ var fieldsLength = this.fields.length;
1135
+ var fieldNames = {};
1136
+
1137
+ for(var i=0;i<fieldsLength;i++){
1138
+ var field = this.fields[i];
1139
+
1140
+ if ("includeInDataExport" in field){
1141
+ if (field.includeInDataExport === true)
1142
+ fieldNames[i] = field.title || field.name;
1143
+ }
1144
+
1145
+ }
1146
+
1147
+ var headerLine = this._itemToCsv(fieldNames,{},options);
1148
+ result.push(headerLine);
1149
+ }
1150
+
1151
+ var exportStartIndex = 0;
1152
+ var exportEndIndex = this.data.length;
1153
+
1154
+ switch(subset){
1155
+
1156
+ case "visible":
1157
+ exportEndIndex = this._firstDisplayingPage * this.pageSize;
1158
+ exportStartIndex = exportEndIndex - this.pageSize;
1159
+
1160
+ case "all":
1161
+ default:
1162
+ break;
1163
+ }
1164
+
1165
+ for (var i = exportStartIndex; i < exportEndIndex; i++){
1166
+ var item = this.data[i];
1167
+ var itemLine = "";
1168
+ var includeItem = true;
1169
+
1170
+ if (filter)
1171
+ if (!filter(item))
1172
+ includeItem = false;
1173
+
1174
+ if (includeItem){
1175
+ itemLine = this._itemToCsv(item, this.fields, options);
1176
+ result.push(itemLine);
1177
+ }
1178
+
1179
+ }
1180
+
1181
+ return result.join("");
1182
+
1183
+ },
1184
+
1185
+ _itemToCsv: function(item, fields, options){
1186
+ var options = options || {};
1187
+ var delimiter = options.delimiter || "|";
1188
+ var encapsulate = options.hasOwnProperty("encapsulate") ? options.encapsulate : true;
1189
+ var newline = options.newline || "\r\n";
1190
+ var transforms = options.transforms || {};
1191
+
1192
+ var fields = fields || {};
1193
+ var getItem = this._getItemFieldValue;
1194
+ var result = [];
1195
+
1196
+ Object.keys(item).forEach(function(key,index) {
1197
+
1198
+ var entry = "";
1199
+
1200
+ //Fields.length is greater than 0 when we are matching agaisnt fields
1201
+ //Field.length will be 0 when exporting header rows
1202
+ if (fields.length > 0){
1203
+
1204
+ var field = fields[index];
1205
+
1206
+ //Field may be excluded from data export
1207
+ if ("includeInDataExport" in field){
1208
+
1209
+ if (field.includeInDataExport){
1210
+
1211
+ //Field may be a select, which requires additional logic
1212
+ if (field.type === "select"){
1213
+
1214
+ var selectedItem = getItem(item, field);
1215
+
1216
+ var resultItem = $.grep(field.items, function(item, index) {
1217
+ return item[field.valueField] === selectedItem;
1218
+ })[0] || "";
1219
+
1220
+ entry = resultItem[field.textField];
1221
+ }
1222
+ else{
1223
+ entry = getItem(item, field);
1224
+ }
1225
+ }
1226
+ else{
1227
+ return;
1228
+ }
1229
+
1230
+ }
1231
+ else{
1232
+ entry = getItem(item, field);
1233
+ }
1234
+
1235
+ if (transforms.hasOwnProperty(field.name)){
1236
+ entry = transforms[field.name](entry);
1237
+ }
1238
+
1239
+
1240
+ }
1241
+ else{
1242
+ entry = item[key];
1243
+ }
1244
+
1245
+ if (encapsulate){
1246
+ entry = '"'+entry+'"';
1247
+ }
1248
+
1249
+
1250
+ result.push(entry);
1251
+ });
1252
+
1253
+ return result.join(delimiter) + newline;
1254
+ },
1255
+
1256
+ getFilter: function() {
1257
+ var result = {};
1258
+ this._eachField(function(field) {
1259
+ if(field.filtering) {
1260
+ this._setItemFieldValue(result, field, field.filterValue());
1261
+ }
1262
+ });
1263
+ return result;
1264
+ },
1265
+
1266
+ _sortingParams: function() {
1267
+ if(this.sorting && this._sortField) {
1268
+ return {
1269
+ sortField: this._sortField.name,
1270
+ sortOrder: this._sortOrder
1271
+ };
1272
+ }
1273
+ return {};
1274
+ },
1275
+
1276
+ getSorting: function() {
1277
+ var sortingParams = this._sortingParams();
1278
+ return {
1279
+ field: sortingParams.sortField,
1280
+ order: sortingParams.sortOrder
1281
+ };
1282
+ },
1283
+
1284
+ clearFilter: function() {
1285
+ var $filterRow = this._createFilterRow();
1286
+ this._filterRow.replaceWith($filterRow);
1287
+ this._filterRow = $filterRow;
1288
+ return this.search();
1289
+ },
1290
+
1291
+ insertItem: function(item) {
1292
+ var insertingItem = item || this._getValidatedInsertItem();
1293
+
1294
+ if(!insertingItem)
1295
+ return $.Deferred().reject().promise();
1296
+
1297
+ var args = this._callEventHandler(this.onItemInserting, {
1298
+ item: insertingItem
1299
+ });
1300
+
1301
+ return this._controllerCall("insertItem", insertingItem, args.cancel, function(insertedItem) {
1302
+ insertedItem = insertedItem || insertingItem;
1303
+ this._loadStrategy.finishInsert(insertedItem, this.insertRowLocation);
1304
+
1305
+ this._callEventHandler(this.onItemInserted, {
1306
+ item: insertedItem
1307
+ });
1308
+ });
1309
+ },
1310
+
1311
+ _getValidatedInsertItem: function() {
1312
+ var item = this._getInsertItem();
1313
+ return this._validateItem(item, this._insertRow) ? item : null;
1314
+ },
1315
+
1316
+ _getInsertItem: function() {
1317
+ var result = {};
1318
+ this._eachField(function(field) {
1319
+ if(field.inserting) {
1320
+ this._setItemFieldValue(result, field, field.insertValue());
1321
+ }
1322
+ });
1323
+ return result;
1324
+ },
1325
+
1326
+ _validateItem: function(item, $row) {
1327
+ var validationErrors = [];
1328
+
1329
+ var args = {
1330
+ item: item,
1331
+ itemIndex: this._rowIndex($row),
1332
+ row: $row
1333
+ };
1334
+
1335
+ this._eachField(function(field) {
1336
+ if(!field.validate ||
1337
+ ($row === this._insertRow && !field.inserting) ||
1338
+ ($row === this._getEditRow() && !field.editing))
1339
+ return;
1340
+
1341
+ var fieldValue = this._getItemFieldValue(item, field);
1342
+
1343
+ var errors = this._validation.validate($.extend({
1344
+ value: fieldValue,
1345
+ rules: field.validate
1346
+ }, args));
1347
+
1348
+ this._setCellValidity($row.children().eq(this._visibleFieldIndex(field)), errors);
1349
+
1350
+ if(!errors.length)
1351
+ return;
1352
+
1353
+ validationErrors.push.apply(validationErrors,
1354
+ $.map(errors, function(message) {
1355
+ return { field: field, message: message };
1356
+ }));
1357
+ });
1358
+
1359
+ if(!validationErrors.length)
1360
+ return true;
1361
+
1362
+ var invalidArgs = $.extend({
1363
+ errors: validationErrors
1364
+ }, args);
1365
+ this._callEventHandler(this.onItemInvalid, invalidArgs);
1366
+ this.invalidNotify(invalidArgs);
1367
+
1368
+ return false;
1369
+ },
1370
+
1371
+ _setCellValidity: function($cell, errors) {
1372
+ $cell
1373
+ .toggleClass(this.invalidClass, !!errors.length)
1374
+ .attr("title", errors.join("\n"));
1375
+ },
1376
+
1377
+ clearInsert: function() {
1378
+ var insertRow = this._createInsertRow();
1379
+ this._insertRow.replaceWith(insertRow);
1380
+ this._insertRow = insertRow;
1381
+ this.refresh();
1382
+ },
1383
+
1384
+ editItem: function(item) {
1385
+ var $row = this.rowByItem(item);
1386
+ if($row.length) {
1387
+ this._editRow($row);
1388
+ }
1389
+ },
1390
+
1391
+ rowByItem: function(item) {
1392
+ if(item.jquery || item.nodeType)
1393
+ return $(item);
1394
+
1395
+ return this._content.find("tr").filter(function() {
1396
+ return $.data(this, JSGRID_ROW_DATA_KEY) === item;
1397
+ });
1398
+ },
1399
+
1400
+ _editRow: function($row) {
1401
+ if(!this.editing)
1402
+ return;
1403
+
1404
+ var item = $row.data(JSGRID_ROW_DATA_KEY);
1405
+
1406
+ var args = this._callEventHandler(this.onItemEditing, {
1407
+ row: $row,
1408
+ item: item,
1409
+ itemIndex: this._itemIndex(item)
1410
+ });
1411
+
1412
+ if(args.cancel)
1413
+ return;
1414
+
1415
+ if(this._editingRow) {
1416
+ this.cancelEdit();
1417
+ }
1418
+
1419
+ var $editRow = this._createEditRow(item);
1420
+
1421
+ this._editingRow = $row;
1422
+ $row.hide();
1423
+ $editRow.insertBefore($row);
1424
+ $row.data(JSGRID_EDIT_ROW_DATA_KEY, $editRow);
1425
+ },
1426
+
1427
+ _createEditRow: function(item) {
1428
+ if($.isFunction(this.editRowRenderer)) {
1429
+ return $(this.renderTemplate(this.editRowRenderer, this, { item: item, itemIndex: this._itemIndex(item) }));
1430
+ }
1431
+
1432
+ var $result = $("<tr>").addClass(this.editRowClass);
1433
+
1434
+ this._eachField(function(field) {
1435
+ var fieldValue = this._getItemFieldValue(item, field);
1436
+
1437
+ this._prepareCell("<td>", field, "editcss")
1438
+ .append(this.renderTemplate(field.editTemplate || "", field, { value: fieldValue, item: item }))
1439
+ .appendTo($result);
1440
+ });
1441
+
1442
+ return $result;
1443
+ },
1444
+
1445
+ updateItem: function(item, editedItem) {
1446
+ if(arguments.length === 1) {
1447
+ editedItem = item;
1448
+ }
1449
+
1450
+ var $row = item ? this.rowByItem(item) : this._editingRow;
1451
+ editedItem = editedItem || this._getValidatedEditedItem();
1452
+
1453
+ if(!editedItem)
1454
+ return;
1455
+
1456
+ return this._updateRow($row, editedItem);
1457
+ },
1458
+
1459
+ _getValidatedEditedItem: function() {
1460
+ var item = this._getEditedItem();
1461
+ return this._validateItem(item, this._getEditRow()) ? item : null;
1462
+ },
1463
+
1464
+ _updateRow: function($updatingRow, editedItem) {
1465
+ var updatingItem = $updatingRow.data(JSGRID_ROW_DATA_KEY),
1466
+ updatingItemIndex = this._itemIndex(updatingItem),
1467
+ updatedItem = $.extend(true, {}, updatingItem, editedItem);
1468
+
1469
+ var args = this._callEventHandler(this.onItemUpdating, {
1470
+ row: $updatingRow,
1471
+ item: updatedItem,
1472
+ itemIndex: updatingItemIndex,
1473
+ previousItem: updatingItem
1474
+ });
1475
+
1476
+ return this._controllerCall("updateItem", updatedItem, args.cancel, function(loadedUpdatedItem) {
1477
+ var previousItem = $.extend(true, {}, updatingItem);
1478
+ updatedItem = loadedUpdatedItem || $.extend(true, updatingItem, updatedItem);
1479
+
1480
+ var $updatedRow = this._finishUpdate($updatingRow, updatedItem, updatingItemIndex);
1481
+
1482
+ this._callEventHandler(this.onItemUpdated, {
1483
+ row: $updatedRow,
1484
+ item: updatedItem,
1485
+ itemIndex: updatingItemIndex,
1486
+ previousItem: previousItem
1487
+ });
1488
+ });
1489
+ },
1490
+
1491
+ _rowIndex: function(row) {
1492
+ return this._content.children().index($(row));
1493
+ },
1494
+
1495
+ _itemIndex: function(item) {
1496
+ return $.inArray(item, this.data);
1497
+ },
1498
+
1499
+ _finishUpdate: function($updatingRow, updatedItem, updatedItemIndex) {
1500
+ this.cancelEdit();
1501
+ this.data[updatedItemIndex] = updatedItem;
1502
+
1503
+ var $updatedRow = this._createRow(updatedItem, updatedItemIndex);
1504
+ $updatingRow.replaceWith($updatedRow);
1505
+ return $updatedRow;
1506
+ },
1507
+
1508
+ _getEditedItem: function() {
1509
+ var result = {};
1510
+ this._eachField(function(field) {
1511
+ if(field.editing) {
1512
+ this._setItemFieldValue(result, field, field.editValue());
1513
+ }
1514
+ });
1515
+ return result;
1516
+ },
1517
+
1518
+ cancelEdit: function() {
1519
+ if(!this._editingRow)
1520
+ return;
1521
+
1522
+ var $row = this._editingRow,
1523
+ editingItem = $row.data(JSGRID_ROW_DATA_KEY),
1524
+ editingItemIndex = this._itemIndex(editingItem);
1525
+
1526
+ this._callEventHandler(this.onItemEditCancelling, {
1527
+ row: $row,
1528
+ item: editingItem,
1529
+ itemIndex: editingItemIndex
1530
+ });
1531
+
1532
+ this._getEditRow().remove();
1533
+ this._editingRow.show();
1534
+ this._editingRow = null;
1535
+ },
1536
+
1537
+ _getEditRow: function() {
1538
+ return this._editingRow && this._editingRow.data(JSGRID_EDIT_ROW_DATA_KEY);
1539
+ },
1540
+
1541
+ deleteItem: function(item) {
1542
+ var $row = this.rowByItem(item);
1543
+
1544
+ if(!$row.length)
1545
+ return;
1546
+
1547
+ if(this.confirmDeleting && !window.confirm(getOrApply(this.deleteConfirm, this, $row.data(JSGRID_ROW_DATA_KEY))))
1548
+ return;
1549
+
1550
+ return this._deleteRow($row);
1551
+ },
1552
+
1553
+ _deleteRow: function($row) {
1554
+ var deletingItem = $row.data(JSGRID_ROW_DATA_KEY),
1555
+ deletingItemIndex = this._itemIndex(deletingItem);
1556
+
1557
+ var args = this._callEventHandler(this.onItemDeleting, {
1558
+ row: $row,
1559
+ item: deletingItem,
1560
+ itemIndex: deletingItemIndex
1561
+ });
1562
+
1563
+ return this._controllerCall("deleteItem", deletingItem, args.cancel, function() {
1564
+ this._loadStrategy.finishDelete(deletingItem, deletingItemIndex);
1565
+
1566
+ this._callEventHandler(this.onItemDeleted, {
1567
+ row: $row,
1568
+ item: deletingItem,
1569
+ itemIndex: deletingItemIndex
1570
+ });
1571
+ });
1572
+ }
1573
+ };
1574
+
1575
+ $.fn.jsGrid = function(config) {
1576
+ var args = $.makeArray(arguments),
1577
+ methodArgs = args.slice(1),
1578
+ result = this;
1579
+
1580
+ this.each(function() {
1581
+ var $element = $(this),
1582
+ instance = $element.data(JSGRID_DATA_KEY),
1583
+ methodResult;
1584
+
1585
+ if(instance) {
1586
+ if(typeof config === "string") {
1587
+ methodResult = instance[config].apply(instance, methodArgs);
1588
+ if(methodResult !== undefined && methodResult !== instance) {
1589
+ result = methodResult;
1590
+ return false;
1591
+ }
1592
+ } else {
1593
+ instance._detachWindowResizeCallback();
1594
+ instance._init(config);
1595
+ instance.render();
1596
+ }
1597
+ } else {
1598
+ new Grid($element, config);
1599
+ }
1600
+ });
1601
+
1602
+ return result;
1603
+ };
1604
+
1605
+ var fields = {};
1606
+
1607
+ var setDefaults = function(config) {
1608
+ var componentPrototype;
1609
+
1610
+ if($.isPlainObject(config)) {
1611
+ componentPrototype = Grid.prototype;
1612
+ } else {
1613
+ componentPrototype = fields[config].prototype;
1614
+ config = arguments[1] || {};
1615
+ }
1616
+
1617
+ $.extend(componentPrototype, config);
1618
+ };
1619
+
1620
+ var locales = {};
1621
+
1622
+ var locale = function(lang) {
1623
+ var localeConfig = $.isPlainObject(lang) ? lang : locales[lang];
1624
+
1625
+ if(!localeConfig)
1626
+ throw Error("unknown locale " + lang);
1627
+
1628
+ setLocale(jsGrid, localeConfig);
1629
+ };
1630
+
1631
+ var setLocale = function(obj, localeConfig) {
1632
+ $.each(localeConfig, function(field, value) {
1633
+ if($.isPlainObject(value)) {
1634
+ setLocale(obj[field] || obj[field[0].toUpperCase() + field.slice(1)], value);
1635
+ return;
1636
+ }
1637
+
1638
+ if(obj.hasOwnProperty(field)) {
1639
+ obj[field] = value;
1640
+ } else {
1641
+ obj.prototype[field] = value;
1642
+ }
1643
+ });
1644
+ };
1645
+
1646
+ window.jsGrid = {
1647
+ Grid: Grid,
1648
+ fields: fields,
1649
+ setDefaults: setDefaults,
1650
+ locales: locales,
1651
+ locale: locale,
1652
+ version: "@VERSION"
1653
+ };
1654
+
1655
+ }(window, jQuery));