jquery-jtable-rails 1.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 (127) hide show
  1. checksums.yaml +7 -0
  2. data/app/assets/javascripts/jtable/extensions/jquery.jtable.aspnetpagemethods.js +150 -0
  3. data/app/assets/javascripts/jtable/extensions/jquery.jtable.aspnetpagemethods.min.js +27 -0
  4. data/app/assets/javascripts/jtable/external/json2.js +486 -0
  5. data/app/assets/javascripts/jtable/external/json2.min.js +8 -0
  6. data/app/assets/javascripts/jtable/jquery.jtable.js +4791 -0
  7. data/app/assets/javascripts/jtable/localization/jquery.jtable.ca.js +30 -0
  8. data/app/assets/javascripts/jtable/localization/jquery.jtable.de.js +30 -0
  9. data/app/assets/javascripts/jtable/localization/jquery.jtable.es.js +30 -0
  10. data/app/assets/javascripts/jtable/localization/jquery.jtable.fa.js +30 -0
  11. data/app/assets/javascripts/jtable/localization/jquery.jtable.fr.js +30 -0
  12. data/app/assets/javascripts/jtable/localization/jquery.jtable.hr.js +30 -0
  13. data/app/assets/javascripts/jtable/localization/jquery.jtable.hu.js +30 -0
  14. data/app/assets/javascripts/jtable/localization/jquery.jtable.id.js +30 -0
  15. data/app/assets/javascripts/jtable/localization/jquery.jtable.it.js +30 -0
  16. data/app/assets/javascripts/jtable/localization/jquery.jtable.lt.js +30 -0
  17. data/app/assets/javascripts/jtable/localization/jquery.jtable.nl-NL.js +30 -0
  18. data/app/assets/javascripts/jtable/localization/jquery.jtable.pl.js +30 -0
  19. data/app/assets/javascripts/jtable/localization/jquery.jtable.pt-BR.js +30 -0
  20. data/app/assets/javascripts/jtable/localization/jquery.jtable.pt-PT.js +29 -0
  21. data/app/assets/javascripts/jtable/localization/jquery.jtable.ro.js +30 -0
  22. data/app/assets/javascripts/jtable/localization/jquery.jtable.ru.js +28 -0
  23. data/app/assets/javascripts/jtable/localization/jquery.jtable.se.js +30 -0
  24. data/app/assets/javascripts/jtable/localization/jquery.jtable.tr.js +30 -0
  25. data/app/assets/javascripts/jtable/localization/jquery.jtable.vi.js +28 -0
  26. data/app/assets/javascripts/jtable/localization/jquery.jtable.zh-CN.js +30 -0
  27. data/app/assets/stylesheets/jtable/themes/basic/close.png +0 -0
  28. data/app/assets/stylesheets/jtable/themes/basic/column-asc.png +0 -0
  29. data/app/assets/stylesheets/jtable/themes/basic/column-desc.png +0 -0
  30. data/app/assets/stylesheets/jtable/themes/basic/column-sortable.png +0 -0
  31. data/app/assets/stylesheets/jtable/themes/basic/delete.png +0 -0
  32. data/app/assets/stylesheets/jtable/themes/basic/edit.png +0 -0
  33. data/app/assets/stylesheets/jtable/themes/basic/jtable_basic.css +282 -0
  34. data/app/assets/stylesheets/jtable/themes/basic/jtable_basic.min.css +1 -0
  35. data/app/assets/stylesheets/jtable/themes/jqueryui/add.png +0 -0
  36. data/app/assets/stylesheets/jtable/themes/jqueryui/bg-thead.png +0 -0
  37. data/app/assets/stylesheets/jtable/themes/jqueryui/close.png +0 -0
  38. data/app/assets/stylesheets/jtable/themes/jqueryui/column-asc.png +0 -0
  39. data/app/assets/stylesheets/jtable/themes/jqueryui/column-desc.png +0 -0
  40. data/app/assets/stylesheets/jtable/themes/jqueryui/column-sortable.png +0 -0
  41. data/app/assets/stylesheets/jtable/themes/jqueryui/delete.png +0 -0
  42. data/app/assets/stylesheets/jtable/themes/jqueryui/edit.png +0 -0
  43. data/app/assets/stylesheets/jtable/themes/jqueryui/jtable_jqueryui.css +398 -0
  44. data/app/assets/stylesheets/jtable/themes/jqueryui/jtable_jqueryui.min.css +1 -0
  45. data/app/assets/stylesheets/jtable/themes/jqueryui/loading.gif +0 -0
  46. data/app/assets/stylesheets/jtable/themes/lightcolor/add.png +0 -0
  47. data/app/assets/stylesheets/jtable/themes/lightcolor/bg-thead.png +0 -0
  48. data/app/assets/stylesheets/jtable/themes/lightcolor/blue/jtable.css +521 -0
  49. data/app/assets/stylesheets/jtable/themes/lightcolor/blue/jtable.less +90 -0
  50. data/app/assets/stylesheets/jtable/themes/lightcolor/blue/jtable.min.css +1 -0
  51. data/app/assets/stylesheets/jtable/themes/lightcolor/blue/loading.gif +0 -0
  52. data/app/assets/stylesheets/jtable/themes/lightcolor/close.png +0 -0
  53. data/app/assets/stylesheets/jtable/themes/lightcolor/column-asc.png +0 -0
  54. data/app/assets/stylesheets/jtable/themes/lightcolor/column-desc.png +0 -0
  55. data/app/assets/stylesheets/jtable/themes/lightcolor/column-sortable.png +0 -0
  56. data/app/assets/stylesheets/jtable/themes/lightcolor/delete.png +0 -0
  57. data/app/assets/stylesheets/jtable/themes/lightcolor/edit.png +0 -0
  58. data/app/assets/stylesheets/jtable/themes/lightcolor/gray/jtable.css +521 -0
  59. data/app/assets/stylesheets/jtable/themes/lightcolor/gray/jtable.less +90 -0
  60. data/app/assets/stylesheets/jtable/themes/lightcolor/gray/jtable.min.css +1 -0
  61. data/app/assets/stylesheets/jtable/themes/lightcolor/gray/loading.gif +0 -0
  62. data/app/assets/stylesheets/jtable/themes/lightcolor/green/jtable.css +521 -0
  63. data/app/assets/stylesheets/jtable/themes/lightcolor/green/jtable.less +90 -0
  64. data/app/assets/stylesheets/jtable/themes/lightcolor/green/jtable.min.css +1 -0
  65. data/app/assets/stylesheets/jtable/themes/lightcolor/green/loading.gif +0 -0
  66. data/app/assets/stylesheets/jtable/themes/lightcolor/jtable_lightcolor_base.less +329 -0
  67. data/app/assets/stylesheets/jtable/themes/lightcolor/orange/jtable.css +521 -0
  68. data/app/assets/stylesheets/jtable/themes/lightcolor/orange/jtable.less +90 -0
  69. data/app/assets/stylesheets/jtable/themes/lightcolor/orange/jtable.min.css +1 -0
  70. data/app/assets/stylesheets/jtable/themes/lightcolor/orange/loading.gif +0 -0
  71. data/app/assets/stylesheets/jtable/themes/lightcolor/red/jtable.css +521 -0
  72. data/app/assets/stylesheets/jtable/themes/lightcolor/red/jtable.less +90 -0
  73. data/app/assets/stylesheets/jtable/themes/lightcolor/red/jtable.min.css +1 -0
  74. data/app/assets/stylesheets/jtable/themes/lightcolor/red/loading.gif +0 -0
  75. data/app/assets/stylesheets/jtable/themes/metro/add.png +0 -0
  76. data/app/assets/stylesheets/jtable/themes/metro/blue/jtable.css +495 -0
  77. data/app/assets/stylesheets/jtable/themes/metro/blue/jtable.less +11 -0
  78. data/app/assets/stylesheets/jtable/themes/metro/blue/jtable.min.css +1 -0
  79. data/app/assets/stylesheets/jtable/themes/metro/blue/loading.gif +0 -0
  80. data/app/assets/stylesheets/jtable/themes/metro/brown/jtable.css +495 -0
  81. data/app/assets/stylesheets/jtable/themes/metro/brown/jtable.less +11 -0
  82. data/app/assets/stylesheets/jtable/themes/metro/brown/jtable.min.css +1 -0
  83. data/app/assets/stylesheets/jtable/themes/metro/brown/loading.gif +0 -0
  84. data/app/assets/stylesheets/jtable/themes/metro/close.png +0 -0
  85. data/app/assets/stylesheets/jtable/themes/metro/column-asc.png +0 -0
  86. data/app/assets/stylesheets/jtable/themes/metro/column-desc.png +0 -0
  87. data/app/assets/stylesheets/jtable/themes/metro/column-sortable.png +0 -0
  88. data/app/assets/stylesheets/jtable/themes/metro/crimson/jtable.css +495 -0
  89. data/app/assets/stylesheets/jtable/themes/metro/crimson/jtable.less +11 -0
  90. data/app/assets/stylesheets/jtable/themes/metro/crimson/jtable.min.css +1 -0
  91. data/app/assets/stylesheets/jtable/themes/metro/crimson/loading.gif +0 -0
  92. data/app/assets/stylesheets/jtable/themes/metro/darkgray/jtable.css +495 -0
  93. data/app/assets/stylesheets/jtable/themes/metro/darkgray/jtable.less +11 -0
  94. data/app/assets/stylesheets/jtable/themes/metro/darkgray/jtable.min.css +1 -0
  95. data/app/assets/stylesheets/jtable/themes/metro/darkgray/loading.gif +0 -0
  96. data/app/assets/stylesheets/jtable/themes/metro/darkorange/jtable.css +495 -0
  97. data/app/assets/stylesheets/jtable/themes/metro/darkorange/jtable.less +11 -0
  98. data/app/assets/stylesheets/jtable/themes/metro/darkorange/jtable.min.css +1 -0
  99. data/app/assets/stylesheets/jtable/themes/metro/darkorange/loading.gif +0 -0
  100. data/app/assets/stylesheets/jtable/themes/metro/delete.png +0 -0
  101. data/app/assets/stylesheets/jtable/themes/metro/edit.png +0 -0
  102. data/app/assets/stylesheets/jtable/themes/metro/green/jtable.css +495 -0
  103. data/app/assets/stylesheets/jtable/themes/metro/green/jtable.less +11 -0
  104. data/app/assets/stylesheets/jtable/themes/metro/green/jtable.min.css +1 -0
  105. data/app/assets/stylesheets/jtable/themes/metro/green/loading.gif +0 -0
  106. data/app/assets/stylesheets/jtable/themes/metro/jtable_metro_base.css +48 -0
  107. data/app/assets/stylesheets/jtable/themes/metro/jtable_metro_base.min.css +1 -0
  108. data/app/assets/stylesheets/jtable/themes/metro/lightgray/jtable.css +495 -0
  109. data/app/assets/stylesheets/jtable/themes/metro/lightgray/jtable.less +11 -0
  110. data/app/assets/stylesheets/jtable/themes/metro/lightgray/jtable.min.css +1 -0
  111. data/app/assets/stylesheets/jtable/themes/metro/lightgray/loading.gif +0 -0
  112. data/app/assets/stylesheets/jtable/themes/metro/pink/jtable.css +495 -0
  113. data/app/assets/stylesheets/jtable/themes/metro/pink/jtable.less +11 -0
  114. data/app/assets/stylesheets/jtable/themes/metro/pink/jtable.min.css +1 -0
  115. data/app/assets/stylesheets/jtable/themes/metro/pink/loading.gif +0 -0
  116. data/app/assets/stylesheets/jtable/themes/metro/purple/jtable.css +495 -0
  117. data/app/assets/stylesheets/jtable/themes/metro/purple/jtable.less +11 -0
  118. data/app/assets/stylesheets/jtable/themes/metro/purple/jtable.min.css +1 -0
  119. data/app/assets/stylesheets/jtable/themes/metro/purple/loading.gif +0 -0
  120. data/app/assets/stylesheets/jtable/themes/metro/red/jtable.css +495 -0
  121. data/app/assets/stylesheets/jtable/themes/metro/red/jtable.less +11 -0
  122. data/app/assets/stylesheets/jtable/themes/metro/red/jtable.min.css +1 -0
  123. data/app/assets/stylesheets/jtable/themes/metro/red/loading.gif +0 -0
  124. data/lib/jquery-jtable-rails.rb +2 -0
  125. data/lib/jquery/jtable/rails/engine.rb +8 -0
  126. data/lib/jquery/jtable/rails/version.rb +7 -0
  127. metadata +182 -0
@@ -0,0 +1,8 @@
1
+ /* http://www.JSON.org */
2
+ "object"!==typeof JSON&&(JSON={});
3
+ (function(){function l(a){return 10>a?"0"+a:a}function q(a){r.lastIndex=0;return r.test(a)?'"'+a.replace(r,function(a){var c=t[a];return"string"===typeof c?c:"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4)})+'"':'"'+a+'"'}function n(a,k){var c,d,h,p,g=e,f,b=k[a];b&&("object"===typeof b&&"function"===typeof b.toJSON)&&(b=b.toJSON(a));"function"===typeof j&&(b=j.call(k,a,b));switch(typeof b){case "string":return q(b);case "number":return isFinite(b)?String(b):"null";case "boolean":case "null":return String(b);
4
+ case "object":if(!b)return"null";e+=m;f=[];if("[object Array]"===Object.prototype.toString.apply(b)){p=b.length;for(c=0;c<p;c+=1)f[c]=n(c,b)||"null";h=0===f.length?"[]":e?"[\n"+e+f.join(",\n"+e)+"\n"+g+"]":"["+f.join(",")+"]";e=g;return h}if(j&&"object"===typeof j){p=j.length;for(c=0;c<p;c+=1)"string"===typeof j[c]&&(d=j[c],(h=n(d,b))&&f.push(q(d)+(e?": ":":")+h))}else for(d in b)Object.prototype.hasOwnProperty.call(b,d)&&(h=n(d,b))&&f.push(q(d)+(e?": ":":")+h);h=0===f.length?"{}":e?"{\n"+e+f.join(",\n"+
5
+ e)+"\n"+g+"}":"{"+f.join(",")+"}";e=g;return h}}"function"!==typeof Date.prototype.toJSON&&(Date.prototype.toJSON=function(){return isFinite(this.valueOf())?this.getUTCFullYear()+"-"+l(this.getUTCMonth()+1)+"-"+l(this.getUTCDate())+"T"+l(this.getUTCHours())+":"+l(this.getUTCMinutes())+":"+l(this.getUTCSeconds())+"Z":null},String.prototype.toJSON=Number.prototype.toJSON=Boolean.prototype.toJSON=function(){return this.valueOf()});var s=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
6
+ r=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,e,m,t={"\b":"\\b","\t":"\\t","\n":"\\n","\f":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"},j;"function"!==typeof JSON.stringify&&(JSON.stringify=function(a,k,c){var d;m=e="";if("number"===typeof c)for(d=0;d<c;d+=1)m+=" ";else"string"===typeof c&&(m=c);if((j=k)&&"function"!==typeof k&&("object"!==typeof k||"number"!==typeof k.length))throw Error("JSON.stringify");return n("",{"":a})});
7
+ "function"!==typeof JSON.parse&&(JSON.parse=function(a,e){function c(a,d){var g,f,b=a[d];if(b&&"object"===typeof b)for(g in b)Object.prototype.hasOwnProperty.call(b,g)&&(f=c(b,g),void 0!==f?b[g]=f:delete b[g]);return e.call(a,d,b)}var d;a=String(a);s.lastIndex=0;s.test(a)&&(a=a.replace(s,function(a){return"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4)}));if(/^[\],:{}\s]*$/.test(a.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,
8
+ "]").replace(/(?:^|:|,)(?:\s*\[)+/g,"")))return d=eval("("+a+")"),"function"===typeof e?c({"":d},""):d;throw new SyntaxError("JSON.parse");})})();
@@ -0,0 +1,4791 @@
1
+ /*
2
+
3
+ jTable 2.3.1
4
+ http://www.jtable.org
5
+
6
+ ---------------------------------------------------------------------------
7
+
8
+ Copyright (C) 2011-2013 by Halil İbrahim Kalkan (http://www.halilibrahimkalkan.com)
9
+
10
+ Permission is hereby granted, free of charge, to any person obtaining a copy
11
+ of this software and associated documentation files (the "Software"), to deal
12
+ in the Software without restriction, including without limitation the rights
13
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
+ copies of the Software, and to permit persons to whom the Software is
15
+ furnished to do so, subject to the following conditions:
16
+
17
+ The above copyright notice and this permission notice shall be included in
18
+ all copies or substantial portions of the Software.
19
+
20
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26
+ THE SOFTWARE.
27
+
28
+ */
29
+
30
+ /************************************************************************
31
+ * CORE jTable module *
32
+ *************************************************************************/
33
+ (function ($) {
34
+
35
+ var unloadingPage;
36
+
37
+ $(window).on('beforeunload', function () {
38
+ unloadingPage = true;
39
+ });
40
+ $(window).on('unload', function () {
41
+ unloadingPage = false;
42
+ });
43
+
44
+ $.widget("hik.jtable", {
45
+
46
+ /************************************************************************
47
+ * DEFAULT OPTIONS / EVENTS *
48
+ *************************************************************************/
49
+ options: {
50
+
51
+ //Options
52
+ actions: {},
53
+ fields: {},
54
+ animationsEnabled: true,
55
+ defaultDateFormat: 'yy-mm-dd',
56
+ dialogShowEffect: 'fade',
57
+ dialogHideEffect: 'fade',
58
+ showCloseButton: false,
59
+ loadingAnimationDelay: 500,
60
+ saveUserPreferences: true,
61
+ jqueryuiTheme: false,
62
+
63
+ ajaxSettings: {
64
+ type: 'POST',
65
+ dataType: 'json'
66
+ },
67
+
68
+ toolbar: {
69
+ hoverAnimation: true,
70
+ hoverAnimationDuration: 60,
71
+ hoverAnimationEasing: undefined,
72
+ items: []
73
+ },
74
+
75
+ //Events
76
+ closeRequested: function (event, data) { },
77
+ formCreated: function (event, data) { },
78
+ formSubmitting: function (event, data) { },
79
+ formClosed: function (event, data) { },
80
+ loadingRecords: function (event, data) { },
81
+ recordsLoaded: function (event, data) { },
82
+ rowInserted: function (event, data) { },
83
+ rowsRemoved: function (event, data) { },
84
+
85
+ //Localization
86
+ messages: {
87
+ serverCommunicationError: 'An error occured while communicating to the server.',
88
+ loadingMessage: 'Loading records...',
89
+ noDataAvailable: 'No data available!',
90
+ areYouSure: 'Are you sure?',
91
+ save: 'Save',
92
+ saving: 'Saving',
93
+ cancel: 'Cancel',
94
+ error: 'Error',
95
+ close: 'Close',
96
+ cannotLoadOptionsFor: 'Can not load options for field {0}'
97
+ }
98
+ },
99
+
100
+ /************************************************************************
101
+ * PRIVATE FIELDS *
102
+ *************************************************************************/
103
+
104
+ _$mainContainer: null, //Reference to the main container of all elements that are created by this plug-in (jQuery object)
105
+
106
+ _$titleDiv: null, //Reference to the title div (jQuery object)
107
+ _$toolbarDiv: null, //Reference to the toolbar div (jQuery object)
108
+
109
+ _$table: null, //Reference to the main <table> (jQuery object)
110
+ _$tableBody: null, //Reference to <body> in the table (jQuery object)
111
+ _$tableRows: null, //Array of all <tr> in the table (except "no data" row) (jQuery object array)
112
+
113
+ _$busyDiv: null, //Reference to the div that is used to block UI while busy (jQuery object)
114
+ _$busyMessageDiv: null, //Reference to the div that is used to show some message when UI is blocked (jQuery object)
115
+ _$errorDialogDiv: null, //Reference to the error dialog div (jQuery object)
116
+
117
+ _columnList: null, //Name of all data columns in the table (select column and command columns are not included) (string array)
118
+ _fieldList: null, //Name of all fields of a record (defined in fields option) (string array)
119
+ _keyField: null, //Name of the key field of a record (that is defined as 'key: true' in the fields option) (string)
120
+
121
+ _firstDataColumnOffset: 0, //Start index of first record field in table columns (some columns can be placed before first data column, such as select checkbox column) (integer)
122
+ _lastPostData: null, //Last posted data on load method (object)
123
+
124
+ _cache: null, //General purpose cache dictionary (object)
125
+
126
+ /************************************************************************
127
+ * CONSTRUCTOR AND INITIALIZATION METHODS *
128
+ *************************************************************************/
129
+
130
+ /* Contructor.
131
+ *************************************************************************/
132
+ _create: function () {
133
+
134
+ //Initialization
135
+ this._normalizeFieldsOptions();
136
+ this._initializeFields();
137
+ this._createFieldAndColumnList();
138
+
139
+ //Creating DOM elements
140
+ this._createMainContainer();
141
+ this._createTableTitle();
142
+ this._createToolBar();
143
+ this._createTable();
144
+ this._createBusyPanel();
145
+ this._createErrorDialogDiv();
146
+ this._addNoDataRow();
147
+
148
+ this._cookieKeyPrefix = this._generateCookieKeyPrefix();
149
+ },
150
+
151
+ /* Normalizes some options for all fields (sets default values).
152
+ *************************************************************************/
153
+ _normalizeFieldsOptions: function () {
154
+ var self = this;
155
+ $.each(self.options.fields, function (fieldName, props) {
156
+ self._normalizeFieldOptions(fieldName, props);
157
+ });
158
+ },
159
+
160
+ /* Normalizes some options for a field (sets default values).
161
+ *************************************************************************/
162
+ _normalizeFieldOptions: function (fieldName, props) {
163
+ if (props.listClass == undefined) {
164
+ props.listClass = '';
165
+ }
166
+ if (props.inputClass == undefined) {
167
+ props.inputClass = '';
168
+ }
169
+
170
+ //Convert dependsOn to array if it's a comma seperated lists
171
+ if (props.dependsOn && $.type(props.dependsOn) === 'string') {
172
+ var dependsOnArray = props.dependsOn.split(',');
173
+ props.dependsOn = [];
174
+ for (var i = 0; i < dependsOnArray.length; i++) {
175
+ props.dependsOn.push($.trim(dependsOnArray[i]));
176
+ }
177
+ }
178
+ },
179
+
180
+ /* Intializes some private variables.
181
+ *************************************************************************/
182
+ _initializeFields: function () {
183
+ this._lastPostData = {};
184
+ this._$tableRows = [];
185
+ this._columnList = [];
186
+ this._fieldList = [];
187
+ this._cache = [];
188
+ },
189
+
190
+ /* Fills _fieldList, _columnList arrays and sets _keyField variable.
191
+ *************************************************************************/
192
+ _createFieldAndColumnList: function () {
193
+ var self = this;
194
+
195
+ $.each(self.options.fields, function (name, props) {
196
+
197
+ //Add field to the field list
198
+ self._fieldList.push(name);
199
+
200
+ //Check if this field is the key field
201
+ if (props.key == true) {
202
+ self._keyField = name;
203
+ }
204
+
205
+ //Add field to column list if it is shown in the table
206
+ if (props.list != false && props.type != 'hidden') {
207
+ self._columnList.push(name);
208
+ }
209
+ });
210
+ },
211
+
212
+ /* Creates the main container div.
213
+ *************************************************************************/
214
+ _createMainContainer: function () {
215
+ this._$mainContainer = $('<div />')
216
+ .addClass('jtable-main-container')
217
+ .appendTo(this.element);
218
+
219
+ this._jqueryuiThemeAddClass(this._$mainContainer, 'ui-widget');
220
+ },
221
+
222
+ /* Creates title of the table if a title supplied in options.
223
+ *************************************************************************/
224
+ _createTableTitle: function () {
225
+ var self = this;
226
+
227
+ if (!self.options.title) {
228
+ return;
229
+ }
230
+
231
+ var $titleDiv = $('<div />')
232
+ .addClass('jtable-title')
233
+ .appendTo(self._$mainContainer);
234
+
235
+ self._jqueryuiThemeAddClass($titleDiv, 'ui-widget-header');
236
+
237
+ $('<div />')
238
+ .addClass('jtable-title-text')
239
+ .appendTo($titleDiv)
240
+ .append(self.options.title);
241
+
242
+ if (self.options.showCloseButton) {
243
+
244
+ var $textSpan = $('<span />')
245
+ .html(self.options.messages.close);
246
+
247
+ $('<button></button>')
248
+ .addClass('jtable-command-button jtable-close-button')
249
+ .attr('title', self.options.messages.close)
250
+ .append($textSpan)
251
+ .appendTo($titleDiv)
252
+ .click(function (e) {
253
+ e.preventDefault();
254
+ e.stopPropagation();
255
+ self._onCloseRequested();
256
+ });
257
+ }
258
+
259
+ self._$titleDiv = $titleDiv;
260
+ },
261
+
262
+ /* Creates the table.
263
+ *************************************************************************/
264
+ _createTable: function () {
265
+ this._$table = $('<table></table>')
266
+ .addClass('jtable')
267
+ .appendTo(this._$mainContainer);
268
+
269
+ if (this.options.tableId) {
270
+ this._$table.attr('id', this.options.tableId);
271
+ }
272
+
273
+ this._jqueryuiThemeAddClass(this._$table, 'ui-widget-content');
274
+
275
+ this._createTableHead();
276
+ this._createTableBody();
277
+ },
278
+
279
+ /* Creates header (all column headers) of the table.
280
+ *************************************************************************/
281
+ _createTableHead: function () {
282
+ var $thead = $('<thead></thead>')
283
+ .appendTo(this._$table);
284
+
285
+ this._addRowToTableHead($thead);
286
+ },
287
+
288
+ /* Adds tr element to given thead element
289
+ *************************************************************************/
290
+ _addRowToTableHead: function ($thead) {
291
+ var $tr = $('<tr></tr>')
292
+ .appendTo($thead);
293
+
294
+ this._addColumnsToHeaderRow($tr);
295
+ },
296
+
297
+ /* Adds column header cells to given tr element.
298
+ *************************************************************************/
299
+ _addColumnsToHeaderRow: function ($tr) {
300
+ for (var i = 0; i < this._columnList.length; i++) {
301
+ var fieldName = this._columnList[i];
302
+ var $headerCell = this._createHeaderCellForField(fieldName, this.options.fields[fieldName]);
303
+ $headerCell.appendTo($tr);
304
+ }
305
+ },
306
+
307
+ /* Creates a header cell for given field.
308
+ * Returns th jQuery object.
309
+ *************************************************************************/
310
+ _createHeaderCellForField: function (fieldName, field) {
311
+ field.width = field.width || '10%'; //default column width: 10%.
312
+
313
+ var $headerTextSpan = $('<span />')
314
+ .addClass('jtable-column-header-text')
315
+ .html(field.title);
316
+
317
+ var $headerContainerDiv = $('<div />')
318
+ .addClass('jtable-column-header-container')
319
+ .append($headerTextSpan);
320
+
321
+ var $th = $('<th></th>')
322
+ .addClass('jtable-column-header')
323
+ .addClass(field.listClass)
324
+ .css('width', field.width)
325
+ .data('fieldName', fieldName)
326
+ .append($headerContainerDiv);
327
+
328
+ this._jqueryuiThemeAddClass($th, 'ui-state-default');
329
+
330
+ return $th;
331
+ },
332
+
333
+ /* Creates an empty header cell that can be used as command column headers.
334
+ *************************************************************************/
335
+ _createEmptyCommandHeader: function () {
336
+ var $th = $('<th></th>')
337
+ .addClass('jtable-command-column-header')
338
+ .css('width', '1%');
339
+
340
+ this._jqueryuiThemeAddClass($th, 'ui-state-default');
341
+
342
+ return $th;
343
+ },
344
+
345
+ /* Creates tbody tag and adds to the table.
346
+ *************************************************************************/
347
+ _createTableBody: function () {
348
+ this._$tableBody = $('<tbody></tbody>').appendTo(this._$table);
349
+ },
350
+
351
+ /* Creates a div to block UI while jTable is busy.
352
+ *************************************************************************/
353
+ _createBusyPanel: function () {
354
+ this._$busyMessageDiv = $('<div />').addClass('jtable-busy-message').prependTo(this._$mainContainer);
355
+ this._$busyDiv = $('<div />').addClass('jtable-busy-panel-background').prependTo(this._$mainContainer);
356
+ this._jqueryuiThemeAddClass(this._$busyMessageDiv, 'ui-widget-header');
357
+ this._hideBusy();
358
+ },
359
+
360
+ /* Creates and prepares error dialog div.
361
+ *************************************************************************/
362
+ _createErrorDialogDiv: function () {
363
+ var self = this;
364
+
365
+ self._$errorDialogDiv = $('<div></div>').appendTo(self._$mainContainer);
366
+ self._$errorDialogDiv.dialog({
367
+ autoOpen: false,
368
+ show: self.options.dialogShowEffect,
369
+ hide: self.options.dialogHideEffect,
370
+ modal: true,
371
+ title: self.options.messages.error,
372
+ buttons: [{
373
+ text: self.options.messages.close,
374
+ click: function () {
375
+ self._$errorDialogDiv.dialog('close');
376
+ }
377
+ }]
378
+ });
379
+ },
380
+
381
+ /************************************************************************
382
+ * PUBLIC METHODS *
383
+ *************************************************************************/
384
+
385
+ /* Loads data using AJAX call, clears table and fills with new data.
386
+ *************************************************************************/
387
+ load: function (postData, completeCallback) {
388
+ this._lastPostData = postData;
389
+ this._reloadTable(completeCallback);
390
+ },
391
+
392
+ /* Refreshes (re-loads) table data with last postData.
393
+ *************************************************************************/
394
+ reload: function (completeCallback) {
395
+ this._reloadTable(completeCallback);
396
+ },
397
+
398
+ /* Gets a jQuery row object according to given record key
399
+ *************************************************************************/
400
+ getRowByKey: function (key) {
401
+ for (var i = 0; i < this._$tableRows.length; i++) {
402
+ if (key == this._getKeyValueOfRecord(this._$tableRows[i].data('record'))) {
403
+ return this._$tableRows[i];
404
+ }
405
+ }
406
+
407
+ return null;
408
+ },
409
+
410
+ /* Completely removes the table from it's container.
411
+ *************************************************************************/
412
+ destroy: function () {
413
+ this.element.empty();
414
+ $.Widget.prototype.destroy.call(this);
415
+ },
416
+
417
+ /************************************************************************
418
+ * PRIVATE METHODS *
419
+ *************************************************************************/
420
+
421
+ /* Used to change options dynamically after initialization.
422
+ *************************************************************************/
423
+ _setOption: function (key, value) {
424
+
425
+ },
426
+
427
+ /* LOADING RECORDS *****************************************************/
428
+
429
+ /* Performs an AJAX call to reload data of the table.
430
+ *************************************************************************/
431
+ _reloadTable: function (completeCallback) {
432
+ var self = this;
433
+
434
+ //Disable table since it's busy
435
+ self._showBusy(self.options.messages.loadingMessage, self.options.loadingAnimationDelay);
436
+
437
+ //Generate URL (with query string parameters) to load records
438
+ var loadUrl = self._createRecordLoadUrl();
439
+
440
+ //Load data from server
441
+ self._onLoadingRecords();
442
+ self._ajax({
443
+ url: loadUrl,
444
+ data: self._lastPostData,
445
+ success: function (data) {
446
+ self._hideBusy();
447
+
448
+ //Show the error message if server returns error
449
+ if (data.Result != 'OK') {
450
+ self._showError(data.Message);
451
+ return;
452
+ }
453
+
454
+ //Re-generate table rows
455
+ self._removeAllRows('reloading');
456
+ self._addRecordsToTable(data.Records);
457
+
458
+ self._onRecordsLoaded(data);
459
+
460
+ //Call complete callback
461
+ if (completeCallback) {
462
+ completeCallback();
463
+ }
464
+ },
465
+ error: function () {
466
+ self._hideBusy();
467
+ self._showError(self.options.messages.serverCommunicationError);
468
+ }
469
+ });
470
+ },
471
+
472
+ /* Creates URL to load records.
473
+ *************************************************************************/
474
+ _createRecordLoadUrl: function () {
475
+ return this.options.actions.listAction;
476
+ },
477
+
478
+ /* TABLE MANIPULATION METHODS *******************************************/
479
+
480
+ /* Creates a row from given record
481
+ *************************************************************************/
482
+ _createRowFromRecord: function (record) {
483
+ var $tr = $('<tr></tr>')
484
+ .addClass('jtable-data-row')
485
+ .attr('data-record-key', this._getKeyValueOfRecord(record))
486
+ .data('record', record);
487
+
488
+ this._addCellsToRowUsingRecord($tr);
489
+ return $tr;
490
+ },
491
+
492
+ /* Adds all cells to given row.
493
+ *************************************************************************/
494
+ _addCellsToRowUsingRecord: function ($row) {
495
+ var record = $row.data('record');
496
+ for (var i = 0; i < this._columnList.length; i++) {
497
+ this._createCellForRecordField(record, this._columnList[i])
498
+ .appendTo($row);
499
+ }
500
+ },
501
+
502
+ /* Create a cell for given field.
503
+ *************************************************************************/
504
+ _createCellForRecordField: function (record, fieldName) {
505
+ return $('<td></td>')
506
+ .addClass(this.options.fields[fieldName].listClass)
507
+ .append((this._getDisplayTextForRecordField(record, fieldName)));
508
+ },
509
+
510
+ /* Adds a list of records to the table.
511
+ *************************************************************************/
512
+ _addRecordsToTable: function (records) {
513
+ var self = this;
514
+
515
+ $.each(records, function (index, record) {
516
+ self._addRow(self._createRowFromRecord(record));
517
+ });
518
+
519
+ self._refreshRowStyles();
520
+ },
521
+
522
+ /* Adds a single row to the table.
523
+ * NOTE: THIS METHOD IS DEPRECATED AND WILL BE REMOVED FROM FEATURE RELEASES.
524
+ * USE _addRow METHOD.
525
+ *************************************************************************/
526
+ _addRowToTable: function ($tableRow, index, isNewRow, animationsEnabled) {
527
+ var options = {
528
+ index: this._normalizeNumber(index, 0, this._$tableRows.length, this._$tableRows.length)
529
+ };
530
+
531
+ if (isNewRow == true) {
532
+ options.isNewRow = true;
533
+ }
534
+
535
+ if (animationsEnabled == false) {
536
+ options.animationsEnabled = false;
537
+ }
538
+
539
+ this._addRow($tableRow, options);
540
+ },
541
+
542
+ /* Adds a single row to the table.
543
+ *************************************************************************/
544
+ _addRow: function ($row, options) {
545
+ //Set defaults
546
+ options = $.extend({
547
+ index: this._$tableRows.length,
548
+ isNewRow: false,
549
+ animationsEnabled: true
550
+ }, options);
551
+
552
+ //Remove 'no data' row if this is first row
553
+ if (this._$tableRows.length <= 0) {
554
+ this._removeNoDataRow();
555
+ }
556
+
557
+ //Add new row to the table according to it's index
558
+ options.index = this._normalizeNumber(options.index, 0, this._$tableRows.length, this._$tableRows.length);
559
+ if (options.index == this._$tableRows.length) {
560
+ //add as last row
561
+ this._$tableBody.append($row);
562
+ this._$tableRows.push($row);
563
+ } else if (options.index == 0) {
564
+ //add as first row
565
+ this._$tableBody.prepend($row);
566
+ this._$tableRows.unshift($row);
567
+ } else {
568
+ //insert to specified index
569
+ this._$tableRows[options.index - 1].after($row);
570
+ this._$tableRows.splice(options.index, 0, $row);
571
+ }
572
+
573
+ this._onRowInserted($row, options.isNewRow);
574
+
575
+ //Show animation if needed
576
+ if (options.isNewRow) {
577
+ this._refreshRowStyles();
578
+ if (this.options.animationsEnabled && options.animationsEnabled) {
579
+ this._showNewRowAnimation($row);
580
+ }
581
+ }
582
+ },
583
+
584
+ /* Shows created animation for a table row
585
+ * TODO: Make this animation cofigurable and changable
586
+ *************************************************************************/
587
+ _showNewRowAnimation: function ($tableRow) {
588
+ var className = 'jtable-row-created';
589
+ if (this.options.jqueryuiTheme) {
590
+ className = className + ' ui-state-highlight';
591
+ }
592
+
593
+ $tableRow.addClass(className, 'slow', '', function () {
594
+ $tableRow.removeClass(className, 5000);
595
+ });
596
+ },
597
+
598
+ /* Removes a row or rows (jQuery selection) from table.
599
+ *************************************************************************/
600
+ _removeRowsFromTable: function ($rows, reason) {
601
+ var self = this;
602
+
603
+ //Check if any row specified
604
+ if ($rows.length <= 0) {
605
+ return;
606
+ }
607
+
608
+ //remove from DOM
609
+ $rows.addClass('jtable-row-removed').remove();
610
+
611
+ //remove from _$tableRows array
612
+ $rows.each(function () {
613
+ var index = self._findRowIndex($(this));
614
+ if (index >= 0) {
615
+ self._$tableRows.splice(index, 1);
616
+ }
617
+ });
618
+
619
+ self._onRowsRemoved($rows, reason);
620
+
621
+ //Add 'no data' row if all rows removed from table
622
+ if (self._$tableRows.length == 0) {
623
+ self._addNoDataRow();
624
+ }
625
+
626
+ self._refreshRowStyles();
627
+ },
628
+
629
+ /* Finds index of a row in table.
630
+ *************************************************************************/
631
+ _findRowIndex: function ($row) {
632
+ return this._findIndexInArray($row, this._$tableRows, function ($row1, $row2) {
633
+ return $row1.data('record') == $row2.data('record');
634
+ });
635
+ },
636
+
637
+ /* Removes all rows in the table and adds 'no data' row.
638
+ *************************************************************************/
639
+ _removeAllRows: function (reason) {
640
+ //If no rows does exists, do nothing
641
+ if (this._$tableRows.length <= 0) {
642
+ return;
643
+ }
644
+
645
+ //Select all rows (to pass it on raising _onRowsRemoved event)
646
+ var $rows = this._$tableBody.find('tr.jtable-data-row');
647
+
648
+ //Remove all rows from DOM and the _$tableRows array
649
+ this._$tableBody.empty();
650
+ this._$tableRows = [];
651
+
652
+ this._onRowsRemoved($rows, reason);
653
+
654
+ //Add 'no data' row since we removed all rows
655
+ this._addNoDataRow();
656
+ },
657
+
658
+ /* Adds "no data available" row to the table.
659
+ *************************************************************************/
660
+ _addNoDataRow: function () {
661
+ if (this._$tableBody.find('>tr.jtable-no-data-row').length > 0) {
662
+ return;
663
+ }
664
+
665
+ var $tr = $('<tr></tr>')
666
+ .addClass('jtable-no-data-row')
667
+ .appendTo(this._$tableBody);
668
+
669
+ var totalColumnCount = this._$table.find('thead th').length;
670
+ $('<td></td>')
671
+ .attr('colspan', totalColumnCount)
672
+ .html(this.options.messages.noDataAvailable)
673
+ .appendTo($tr);
674
+ },
675
+
676
+ /* Removes "no data available" row from the table.
677
+ *************************************************************************/
678
+ _removeNoDataRow: function () {
679
+ this._$tableBody.find('.jtable-no-data-row').remove();
680
+ },
681
+
682
+ /* Refreshes styles of all rows in the table
683
+ *************************************************************************/
684
+ _refreshRowStyles: function () {
685
+ for (var i = 0; i < this._$tableRows.length; i++) {
686
+ if (i % 2 == 0) {
687
+ this._$tableRows[i].addClass('jtable-row-even');
688
+ } else {
689
+ this._$tableRows[i].removeClass('jtable-row-even');
690
+ }
691
+ }
692
+ },
693
+
694
+ /* RENDERING FIELD VALUES ***********************************************/
695
+
696
+ /* Gets text for a field of a record according to it's type.
697
+ *************************************************************************/
698
+ _getDisplayTextForRecordField: function (record, fieldName) {
699
+ var field = this.options.fields[fieldName];
700
+ var fieldValue = record[fieldName];
701
+
702
+ //if this is a custom field, call display function
703
+ if (field.display) {
704
+ return field.display({ record: record });
705
+ }
706
+
707
+ if (field.type == 'date') {
708
+ return this._getDisplayTextForDateRecordField(field, fieldValue);
709
+ } else if (field.type == 'checkbox') {
710
+ return this._getCheckBoxTextForFieldByValue(fieldName, fieldValue);
711
+ } else if (field.options) { //combobox or radio button list since there are options.
712
+ var options = this._getOptionsForField(fieldName, {
713
+ record: record,
714
+ value: fieldValue,
715
+ source: 'list',
716
+ dependedValues: this._createDependedValuesUsingRecord(record, field.dependsOn)
717
+ });
718
+ return this._findOptionByValue(options, fieldValue).DisplayText;
719
+ } else { //other types
720
+ return fieldValue;
721
+ }
722
+ },
723
+
724
+ /* Creates and returns an object that's properties are depended values of a record.
725
+ *************************************************************************/
726
+ _createDependedValuesUsingRecord: function (record, dependsOn) {
727
+ if (!dependsOn) {
728
+ return {};
729
+ }
730
+
731
+ var dependedValues = {};
732
+ for (var i = 0; i < dependsOn.length; i++) {
733
+ dependedValues[dependsOn[i]] = record[dependsOn[i]];
734
+ }
735
+
736
+ return dependedValues;
737
+ },
738
+
739
+ /* Finds an option object by given value.
740
+ *************************************************************************/
741
+ _findOptionByValue: function (options, value) {
742
+ for (var i = 0; i < options.length; i++) {
743
+ if (options[i].Value == value) {
744
+ return options[i];
745
+ }
746
+ }
747
+
748
+ return {}; //no option found
749
+ },
750
+
751
+ /* Gets text for a date field.
752
+ *************************************************************************/
753
+ _getDisplayTextForDateRecordField: function (field, fieldValue) {
754
+ if (!fieldValue) {
755
+ return '';
756
+ }
757
+
758
+ var displayFormat = field.displayFormat || this.options.defaultDateFormat;
759
+ var date = this._parseDate(fieldValue);
760
+ return $.datepicker.formatDate(displayFormat, date);
761
+ },
762
+
763
+ /* Gets options for a field according to user preferences.
764
+ *************************************************************************/
765
+ _getOptionsForField: function (fieldName, funcParams) {
766
+ var field = this.options.fields[fieldName];
767
+ var optionsSource = field.options;
768
+
769
+ if ($.isFunction(optionsSource)) {
770
+ //prepare parameter to the function
771
+ funcParams = $.extend(true, {
772
+ _cacheCleared: false,
773
+ dependedValues: {},
774
+ clearCache: function () {
775
+ this._cacheCleared = true;
776
+ }
777
+ }, funcParams);
778
+
779
+ //call function and get actual options source
780
+ optionsSource = optionsSource(funcParams);
781
+ }
782
+
783
+ var options;
784
+
785
+ //Build options according to it's source type
786
+ if (typeof optionsSource == 'string') { //It is an Url to download options
787
+ var cacheKey = 'options_' + fieldName + '_' + optionsSource; //create a unique cache key
788
+ if (funcParams._cacheCleared || (!this._cache[cacheKey])) {
789
+ //if user calls clearCache() or options are not found in the cache, download options
790
+ this._cache[cacheKey] = this._buildOptionsFromArray(this._downloadOptions(fieldName, optionsSource));
791
+ this._sortFieldOptions(this._cache[cacheKey], field.optionsSorting);
792
+ } else {
793
+ //found on cache..
794
+ //if this method (_getOptionsForField) is called to get option for a specific value (on funcParams.source == 'list')
795
+ //and this value is not in cached options, we need to re-download options to get the unfound (probably new) option.
796
+ if (funcParams.value != undefined) {
797
+ var optionForValue = this._findOptionByValue(this._cache[cacheKey], funcParams.value);
798
+ if (optionForValue.DisplayText == undefined) { //this value is not in cached options...
799
+ this._cache[cacheKey] = this._buildOptionsFromArray(this._downloadOptions(fieldName, optionsSource));
800
+ this._sortFieldOptions(this._cache[cacheKey], field.optionsSorting);
801
+ }
802
+ }
803
+ }
804
+
805
+ options = this._cache[cacheKey];
806
+ } else if (jQuery.isArray(optionsSource)) { //It is an array of options
807
+ options = this._buildOptionsFromArray(optionsSource);
808
+ this._sortFieldOptions(options, field.optionsSorting);
809
+ } else { //It is an object that it's properties are options
810
+ options = this._buildOptionsArrayFromObject(optionsSource);
811
+ this._sortFieldOptions(options, field.optionsSorting);
812
+ }
813
+
814
+ return options;
815
+ },
816
+
817
+ /* Download options for a field from server.
818
+ *************************************************************************/
819
+ _downloadOptions: function (fieldName, url) {
820
+ var self = this;
821
+ var options = [];
822
+
823
+ self._ajax({
824
+ url: url,
825
+ async: false,
826
+ success: function (data) {
827
+ if (data.Result != 'OK') {
828
+ self._showError(data.Message);
829
+ return;
830
+ }
831
+
832
+ options = data.Options;
833
+ },
834
+ error: function () {
835
+ var errMessage = self._formatString(self.options.messages.cannotLoadOptionsFor, fieldName);
836
+ self._showError(errMessage);
837
+ }
838
+ });
839
+
840
+ return options;
841
+ },
842
+
843
+ /* Sorts given options according to sorting parameter.
844
+ * sorting can be: 'value', 'value-desc', 'text' or 'text-desc'.
845
+ *************************************************************************/
846
+ _sortFieldOptions: function (options, sorting) {
847
+
848
+ if ((!options) || (!options.length) || (!sorting)) {
849
+ return;
850
+ }
851
+
852
+ //Determine using value of text
853
+ var dataSelector;
854
+ if (sorting.indexOf('value') == 0) {
855
+ dataSelector = function (option) {
856
+ return option.Value;
857
+ };
858
+ } else { //assume as text
859
+ dataSelector = function (option) {
860
+ return option.DisplayText;
861
+ };
862
+ }
863
+
864
+ var compareFunc;
865
+ if ($.type(dataSelector(options[0])) == 'string') {
866
+ compareFunc = function (option1, option2) {
867
+ return dataSelector(option1).localeCompare(dataSelector(option2));
868
+ };
869
+ } else { //asuume as numeric
870
+ compareFunc = function (option1, option2) {
871
+ return dataSelector(option1) - dataSelector(option2);
872
+ };
873
+ }
874
+
875
+ if (sorting.indexOf('desc') > 0) {
876
+ options.sort(function (a, b) {
877
+ return compareFunc(b, a);
878
+ });
879
+ } else { //assume as asc
880
+ options.sort(function (a, b) {
881
+ return compareFunc(a, b);
882
+ });
883
+ }
884
+ },
885
+
886
+ /* Creates an array of options from given object.
887
+ *************************************************************************/
888
+ _buildOptionsArrayFromObject: function (options) {
889
+ var list = [];
890
+
891
+ $.each(options, function (propName, propValue) {
892
+ list.push({
893
+ Value: propName,
894
+ DisplayText: propValue
895
+ });
896
+ });
897
+
898
+ return list;
899
+ },
900
+
901
+ /* Creates array of options from giving options array.
902
+ *************************************************************************/
903
+ _buildOptionsFromArray: function (optionsArray) {
904
+ var list = [];
905
+
906
+ for (var i = 0; i < optionsArray.length; i++) {
907
+ if ($.isPlainObject(optionsArray[i])) {
908
+ list.push(optionsArray[i]);
909
+ } else { //assumed as primitive type (int, string...)
910
+ list.push({
911
+ Value: optionsArray[i],
912
+ DisplayText: optionsArray[i]
913
+ });
914
+ }
915
+ }
916
+
917
+ return list;
918
+ },
919
+
920
+ /* Parses given date string to a javascript Date object.
921
+ * Given string must be formatted one of the samples shown below:
922
+ * /Date(1320259705710)/
923
+ * 2011-01-01 20:32:42 (YYYY-MM-DD HH:MM:SS)
924
+ * 2011-01-01 (YYYY-MM-DD)
925
+ *************************************************************************/
926
+ _parseDate: function (dateString) {
927
+ if (dateString.indexOf('Date') >= 0) { //Format: /Date(1320259705710)/
928
+ return new Date(
929
+ parseInt(dateString.substr(6), 10)
930
+ );
931
+ } else if (dateString.length == 10) { //Format: 2011-01-01
932
+ return new Date(
933
+ parseInt(dateString.substr(0, 4), 10),
934
+ parseInt(dateString.substr(5, 2), 10) - 1,
935
+ parseInt(dateString.substr(8, 2), 10)
936
+ );
937
+ } else if (dateString.length == 19) { //Format: 2011-01-01 20:32:42
938
+ return new Date(
939
+ parseInt(dateString.substr(0, 4), 10),
940
+ parseInt(dateString.substr(5, 2), 10) - 1,
941
+ parseInt(dateString.substr(8, 2, 10)),
942
+ parseInt(dateString.substr(11, 2), 10),
943
+ parseInt(dateString.substr(14, 2), 10),
944
+ parseInt(dateString.substr(17, 2), 10)
945
+ );
946
+ } else {
947
+ this._logWarn('Given date is not properly formatted: ' + dateString);
948
+ return 'format error!';
949
+ }
950
+ },
951
+
952
+ /* TOOL BAR *************************************************************/
953
+
954
+ /* Creates the toolbar.
955
+ *************************************************************************/
956
+ _createToolBar: function () {
957
+ this._$toolbarDiv = $('<div />')
958
+ .addClass('jtable-toolbar')
959
+ .appendTo(this._$titleDiv);
960
+
961
+ for (var i = 0; i < this.options.toolbar.items.length; i++) {
962
+ this._addToolBarItem(this.options.toolbar.items[i]);
963
+ }
964
+ },
965
+
966
+ /* Adds a new item to the toolbar.
967
+ *************************************************************************/
968
+ _addToolBarItem: function (item) {
969
+
970
+ //Check if item is valid
971
+ if ((item == undefined) || (item.text == undefined && item.icon == undefined)) {
972
+ this._logWarn('Can not add tool bar item since it is not valid!');
973
+ this._logWarn(item);
974
+ return null;
975
+ }
976
+
977
+ var $toolBarItem = $('<span></span>')
978
+ .addClass('jtable-toolbar-item')
979
+ .appendTo(this._$toolbarDiv);
980
+
981
+ this._jqueryuiThemeAddClass($toolBarItem, 'ui-widget ui-state-default ui-corner-all', 'ui-state-hover');
982
+
983
+ //cssClass property
984
+ if (item.cssClass) {
985
+ $toolBarItem
986
+ .addClass(item.cssClass);
987
+ }
988
+
989
+ //tooltip property
990
+ if (item.tooltip) {
991
+ $toolBarItem
992
+ .attr('title', item.tooltip);
993
+ }
994
+
995
+ //icon property
996
+ if (item.icon) {
997
+ var $icon = $('<span class="jtable-toolbar-item-icon"></span>').appendTo($toolBarItem);
998
+ if (item.icon === true) {
999
+ //do nothing
1000
+ } else if ($.type(item.icon === 'string')) {
1001
+ $icon.css('background', 'url("' + item.icon + '")');
1002
+ }
1003
+ }
1004
+
1005
+ //text property
1006
+ if (item.text) {
1007
+ $('<span class=""></span>')
1008
+ .html(item.text)
1009
+ .addClass('jtable-toolbar-item-text').appendTo($toolBarItem);
1010
+ }
1011
+
1012
+ //click event
1013
+ if (item.click) {
1014
+ $toolBarItem.click(function () {
1015
+ item.click();
1016
+ });
1017
+ }
1018
+
1019
+ //set hover animation parameters
1020
+ var hoverAnimationDuration = undefined;
1021
+ var hoverAnimationEasing = undefined;
1022
+ if (this.options.toolbar.hoverAnimation) {
1023
+ hoverAnimationDuration = this.options.toolbar.hoverAnimationDuration;
1024
+ hoverAnimationEasing = this.options.toolbar.hoverAnimationEasing;
1025
+ }
1026
+
1027
+ //change class on hover
1028
+ $toolBarItem.hover(function () {
1029
+ $toolBarItem.addClass('jtable-toolbar-item-hover', hoverAnimationDuration, hoverAnimationEasing);
1030
+ }, function () {
1031
+ $toolBarItem.removeClass('jtable-toolbar-item-hover', hoverAnimationDuration, hoverAnimationEasing);
1032
+ });
1033
+
1034
+ return $toolBarItem;
1035
+ },
1036
+
1037
+ /* ERROR DIALOG *********************************************************/
1038
+
1039
+ /* Shows error message dialog with given message.
1040
+ *************************************************************************/
1041
+ _showError: function (message) {
1042
+ this._$errorDialogDiv.html(message).dialog('open');
1043
+ },
1044
+
1045
+ /* BUSY PANEL ***********************************************************/
1046
+
1047
+ /* Shows busy indicator and blocks table UI.
1048
+ * TODO: Make this cofigurable and changable
1049
+ *************************************************************************/
1050
+ _setBusyTimer: null,
1051
+ _showBusy: function (message, delay) {
1052
+ var self = this; //
1053
+
1054
+ //Show a transparent overlay to prevent clicking to the table
1055
+ self._$busyDiv
1056
+ .width(self._$mainContainer.width())
1057
+ .height(self._$mainContainer.height())
1058
+ .addClass('jtable-busy-panel-background-invisible')
1059
+ .show();
1060
+
1061
+ var makeVisible = function () {
1062
+ self._$busyDiv.removeClass('jtable-busy-panel-background-invisible');
1063
+ self._$busyMessageDiv.html(message).show();
1064
+ };
1065
+
1066
+ if (delay) {
1067
+ if (self._setBusyTimer) {
1068
+ return;
1069
+ }
1070
+
1071
+ self._setBusyTimer = setTimeout(makeVisible, delay);
1072
+ } else {
1073
+ makeVisible();
1074
+ }
1075
+ },
1076
+
1077
+ /* Hides busy indicator and unblocks table UI.
1078
+ *************************************************************************/
1079
+ _hideBusy: function () {
1080
+ clearTimeout(this._setBusyTimer);
1081
+ this._setBusyTimer = null;
1082
+ this._$busyDiv.hide();
1083
+ this._$busyMessageDiv.html('').hide();
1084
+ },
1085
+
1086
+ /* Returns true if jTable is busy.
1087
+ *************************************************************************/
1088
+ _isBusy: function () {
1089
+ return this._$busyMessageDiv.is(':visible');
1090
+ },
1091
+
1092
+ /* Adds jQueryUI class to an item.
1093
+ *************************************************************************/
1094
+ _jqueryuiThemeAddClass: function ($elm, className, hoverClassName) {
1095
+ if (!this.options.jqueryuiTheme) {
1096
+ return;
1097
+ }
1098
+
1099
+ $elm.addClass(className);
1100
+
1101
+ if (hoverClassName) {
1102
+ $elm.hover(function () {
1103
+ $elm.addClass(hoverClassName);
1104
+ }, function () {
1105
+ $elm.removeClass(hoverClassName);
1106
+ });
1107
+ }
1108
+ },
1109
+
1110
+ /* COMMON METHODS *******************************************************/
1111
+
1112
+ /* Performs an AJAX call to specified URL.
1113
+ * THIS METHOD IS DEPRECATED AND WILL BE REMOVED FROM FEATURE RELEASES.
1114
+ * USE _ajax METHOD.
1115
+ *************************************************************************/
1116
+ _performAjaxCall: function (url, postData, async, success, error) {
1117
+ this._ajax({
1118
+ url: url,
1119
+ data: postData,
1120
+ async: async,
1121
+ success: success,
1122
+ error: error
1123
+ });
1124
+ },
1125
+
1126
+ /* This method is used to perform AJAX calls in jTable instead of direct
1127
+ * usage of jQuery.ajax method.
1128
+ *************************************************************************/
1129
+ _ajax: function (options) {
1130
+ var opts = $.extend({}, this.options.ajaxSettings, options);
1131
+
1132
+ //Override success
1133
+ opts.success = function (data) {
1134
+ if (options.success) {
1135
+ options.success(data);
1136
+ }
1137
+ };
1138
+
1139
+ //Override error
1140
+ opts.error = function (jqXHR, textStatus, errorThrown) {
1141
+ if (unloadingPage) {
1142
+ jqXHR.abort();
1143
+ return;
1144
+ }
1145
+
1146
+ if (options.error) {
1147
+ options.error(arguments);
1148
+ }
1149
+ };
1150
+
1151
+ //Override complete
1152
+ opts.complete = function () {
1153
+ if (options.complete) {
1154
+ options.complete();
1155
+ }
1156
+ };
1157
+
1158
+ $.ajax(opts);
1159
+ },
1160
+
1161
+ /* Gets value of key field of a record.
1162
+ *************************************************************************/
1163
+ _getKeyValueOfRecord: function (record) {
1164
+ return record[this._keyField];
1165
+ },
1166
+
1167
+ /************************************************************************
1168
+ * COOKIE *
1169
+ *************************************************************************/
1170
+
1171
+ /* Sets a cookie with given key.
1172
+ *************************************************************************/
1173
+ _setCookie: function (key, value) {
1174
+ key = this._cookieKeyPrefix + key;
1175
+
1176
+ var expireDate = new Date();
1177
+ expireDate.setDate(expireDate.getDate() + 30);
1178
+ document.cookie = encodeURIComponent(key) + '=' + encodeURIComponent(value) + "; expires=" + expireDate.toUTCString();
1179
+ },
1180
+
1181
+ /* Gets a cookie with given key.
1182
+ *************************************************************************/
1183
+ _getCookie: function (key) {
1184
+ key = this._cookieKeyPrefix + key;
1185
+
1186
+ var equalities = document.cookie.split('; ');
1187
+ for (var i = 0; i < equalities.length; i++) {
1188
+ if (!equalities[i]) {
1189
+ continue;
1190
+ }
1191
+
1192
+ var splitted = equalities[i].split('=');
1193
+ if (splitted.length != 2) {
1194
+ continue;
1195
+ }
1196
+
1197
+ if (decodeURIComponent(splitted[0]) === key) {
1198
+ return decodeURIComponent(splitted[1] || '');
1199
+ }
1200
+ }
1201
+
1202
+ return null;
1203
+ },
1204
+
1205
+ /* Generates a hash key to be prefix for all cookies for this jtable instance.
1206
+ *************************************************************************/
1207
+ _generateCookieKeyPrefix: function () {
1208
+
1209
+ var simpleHash = function (value) {
1210
+ var hash = 0;
1211
+ if (value.length == 0) {
1212
+ return hash;
1213
+ }
1214
+
1215
+ for (var i = 0; i < value.length; i++) {
1216
+ var ch = value.charCodeAt(i);
1217
+ hash = ((hash << 5) - hash) + ch;
1218
+ hash = hash & hash;
1219
+ }
1220
+
1221
+ return hash;
1222
+ };
1223
+
1224
+ var strToHash = '';
1225
+ if (this.options.tableId) {
1226
+ strToHash = strToHash + this.options.tableId + '#';
1227
+ }
1228
+
1229
+ strToHash = strToHash + this._columnList.join('$') + '#c' + this._$table.find('thead th').length;
1230
+ return 'jtable#' + simpleHash(strToHash);
1231
+ },
1232
+
1233
+ /************************************************************************
1234
+ * EVENT RAISING METHODS *
1235
+ *************************************************************************/
1236
+
1237
+ _onLoadingRecords: function () {
1238
+ this._trigger("loadingRecords", null, {});
1239
+ },
1240
+
1241
+ _onRecordsLoaded: function (data) {
1242
+ this._trigger("recordsLoaded", null, { records: data.Records, serverResponse: data });
1243
+ },
1244
+
1245
+ _onRowInserted: function ($row, isNewRow) {
1246
+ this._trigger("rowInserted", null, { row: $row, record: $row.data('record'), isNewRow: isNewRow });
1247
+ },
1248
+
1249
+ _onRowsRemoved: function ($rows, reason) {
1250
+ this._trigger("rowsRemoved", null, { rows: $rows, reason: reason });
1251
+ },
1252
+
1253
+ _onCloseRequested: function () {
1254
+ this._trigger("closeRequested", null, {});
1255
+ }
1256
+
1257
+ });
1258
+
1259
+ }(jQuery));
1260
+
1261
+
1262
+ /************************************************************************
1263
+ * Some UTULITY methods used by jTable *
1264
+ *************************************************************************/
1265
+ (function ($) {
1266
+
1267
+ $.extend(true, $.hik.jtable.prototype, {
1268
+
1269
+ /* Gets property value of an object recursively.
1270
+ *************************************************************************/
1271
+ _getPropertyOfObject: function (obj, propName) {
1272
+ if (propName.indexOf('.') < 0) {
1273
+ return obj[propName];
1274
+ } else {
1275
+ var preDot = propName.substring(0, propName.indexOf('.'));
1276
+ var postDot = propName.substring(propName.indexOf('.') + 1);
1277
+ return this._getPropertyOfObject(obj[preDot], postDot);
1278
+ }
1279
+ },
1280
+
1281
+ /* Sets property value of an object recursively.
1282
+ *************************************************************************/
1283
+ _setPropertyOfObject: function (obj, propName, value) {
1284
+ if (propName.indexOf('.') < 0) {
1285
+ obj[propName] = value;
1286
+ } else {
1287
+ var preDot = propName.substring(0, propName.indexOf('.'));
1288
+ var postDot = propName.substring(propName.indexOf('.') + 1);
1289
+ this._setPropertyOfObject(obj[preDot], postDot, value);
1290
+ }
1291
+ },
1292
+
1293
+ /* Inserts a value to an array if it does not exists in the array.
1294
+ *************************************************************************/
1295
+ _insertToArrayIfDoesNotExists: function (array, value) {
1296
+ if ($.inArray(value, array) < 0) {
1297
+ array.push(value);
1298
+ }
1299
+ },
1300
+
1301
+ /* Finds index of an element in an array according to given comparision function
1302
+ *************************************************************************/
1303
+ _findIndexInArray: function (value, array, compareFunc) {
1304
+
1305
+ //If not defined, use default comparision
1306
+ if (!compareFunc) {
1307
+ compareFunc = function (a, b) {
1308
+ return a == b;
1309
+ };
1310
+ }
1311
+
1312
+ for (var i = 0; i < array.length; i++) {
1313
+ if (compareFunc(value, array[i])) {
1314
+ return i;
1315
+ }
1316
+ }
1317
+
1318
+ return -1;
1319
+ },
1320
+
1321
+ /* Normalizes a number between given bounds or sets to a defaultValue
1322
+ * if it is undefined
1323
+ *************************************************************************/
1324
+ _normalizeNumber: function (number, min, max, defaultValue) {
1325
+ if (number == undefined || number == null || isNaN(number)) {
1326
+ return defaultValue;
1327
+ }
1328
+
1329
+ if (number < min) {
1330
+ return min;
1331
+ }
1332
+
1333
+ if (number > max) {
1334
+ return max;
1335
+ }
1336
+
1337
+ return number;
1338
+ },
1339
+
1340
+ /* Formats a string just like string.format in c#.
1341
+ * Example:
1342
+ * _formatString('Hello {0}','Halil') = 'Hello Halil'
1343
+ *************************************************************************/
1344
+ _formatString: function () {
1345
+ if (arguments.length == 0) {
1346
+ return null;
1347
+ }
1348
+
1349
+ var str = arguments[0];
1350
+ for (var i = 1; i < arguments.length; i++) {
1351
+ var placeHolder = '{' + (i - 1) + '}';
1352
+ str = str.replace(placeHolder, arguments[i]);
1353
+ }
1354
+
1355
+ return str;
1356
+ },
1357
+
1358
+ //Logging methods ////////////////////////////////////////////////////////
1359
+
1360
+ _logDebug: function (text) {
1361
+ if (!window.console) {
1362
+ return;
1363
+ }
1364
+
1365
+ console.log('jTable DEBUG: ' + text);
1366
+ },
1367
+
1368
+ _logInfo: function (text) {
1369
+ if (!window.console) {
1370
+ return;
1371
+ }
1372
+
1373
+ console.log('jTable INFO: ' + text);
1374
+ },
1375
+
1376
+ _logWarn: function (text) {
1377
+ if (!window.console) {
1378
+ return;
1379
+ }
1380
+
1381
+ console.log('jTable WARNING: ' + text);
1382
+ },
1383
+
1384
+ _logError: function (text) {
1385
+ if (!window.console) {
1386
+ return;
1387
+ }
1388
+
1389
+ console.log('jTable ERROR: ' + text);
1390
+ }
1391
+
1392
+ });
1393
+
1394
+ /* Fix for array.indexOf method in IE7.
1395
+ * This code is taken from http://www.tutorialspoint.com/javascript/array_indexof.htm */
1396
+ if (!Array.prototype.indexOf) {
1397
+ Array.prototype.indexOf = function (elt) {
1398
+ var len = this.length;
1399
+ var from = Number(arguments[1]) || 0;
1400
+ from = (from < 0)
1401
+ ? Math.ceil(from)
1402
+ : Math.floor(from);
1403
+ if (from < 0)
1404
+ from += len;
1405
+ for (; from < len; from++) {
1406
+ if (from in this &&
1407
+ this[from] === elt)
1408
+ return from;
1409
+ }
1410
+ return -1;
1411
+ };
1412
+ }
1413
+
1414
+ })(jQuery);
1415
+
1416
+
1417
+ /************************************************************************
1418
+ * FORMS extension for jTable (base for edit/create forms) *
1419
+ *************************************************************************/
1420
+ (function ($) {
1421
+
1422
+ $.extend(true, $.hik.jtable.prototype, {
1423
+
1424
+ /************************************************************************
1425
+ * PRIVATE METHODS *
1426
+ *************************************************************************/
1427
+
1428
+ /* Submits a form asynchronously using AJAX.
1429
+ * This method is needed, since form submitting logic can be overrided
1430
+ * by extensions.
1431
+ *************************************************************************/
1432
+ _submitFormUsingAjax: function (url, formData, success, error) {
1433
+ this._ajax({
1434
+ url: url,
1435
+ data: formData,
1436
+ success: success,
1437
+ error: error
1438
+ });
1439
+ },
1440
+
1441
+ /* Creates label for an input element.
1442
+ *************************************************************************/
1443
+ _createInputLabelForRecordField: function (fieldName) {
1444
+ //TODO: May create label tag instead of a div.
1445
+ return $('<div />')
1446
+ .addClass('jtable-input-label')
1447
+ .html(this.options.fields[fieldName].inputTitle || this.options.fields[fieldName].title);
1448
+ },
1449
+
1450
+ /* Creates an input element according to field type.
1451
+ *************************************************************************/
1452
+ _createInputForRecordField: function (funcParams) {
1453
+ var fieldName = funcParams.fieldName,
1454
+ value = funcParams.value,
1455
+ record = funcParams.record,
1456
+ formType = funcParams.formType,
1457
+ form = funcParams.form;
1458
+
1459
+ //Get the field
1460
+ var field = this.options.fields[fieldName];
1461
+
1462
+ //If value if not supplied, use defaultValue of the field
1463
+ if (value == undefined || value == null) {
1464
+ value = field.defaultValue;
1465
+ }
1466
+
1467
+ //Use custom function if supplied
1468
+ if (field.input) {
1469
+ var $input = $(field.input({
1470
+ value: value,
1471
+ record: record,
1472
+ formType: formType,
1473
+ form: form
1474
+ }));
1475
+
1476
+ //Add id attribute if does not exists
1477
+ if (!$input.attr('id')) {
1478
+ $input.attr('id', 'Edit-' + fieldName);
1479
+ }
1480
+
1481
+ //Wrap input element with div
1482
+ return $('<div />')
1483
+ .addClass('jtable-input jtable-custom-input')
1484
+ .append($input);
1485
+ }
1486
+
1487
+ //Create input according to field type
1488
+ if (field.type == 'date') {
1489
+ return this._createDateInputForField(field, fieldName, value);
1490
+ } else if (field.type == 'textarea') {
1491
+ return this._createTextAreaForField(field, fieldName, value);
1492
+ } else if (field.type == 'password') {
1493
+ return this._createPasswordInputForField(field, fieldName, value);
1494
+ } else if (field.type == 'checkbox') {
1495
+ return this._createCheckboxForField(field, fieldName, value);
1496
+ } else if (field.options) {
1497
+ if (field.type == 'radiobutton') {
1498
+ return this._createRadioButtonListForField(field, fieldName, value, record, formType);
1499
+ } else {
1500
+ return this._createDropDownListForField(field, fieldName, value, record, formType, form);
1501
+ }
1502
+ } else {
1503
+ return this._createTextInputForField(field, fieldName, value);
1504
+ }
1505
+ },
1506
+
1507
+ //Creates a hidden input element with given name and value.
1508
+ _createInputForHidden: function (fieldName, value) {
1509
+ if (value == undefined) {
1510
+ value = "";
1511
+ }
1512
+
1513
+ return $('<input type="hidden" name="' + fieldName + '" id="Edit-' + fieldName + '"></input>')
1514
+ .val(value);
1515
+ },
1516
+
1517
+ /* Creates a date input for a field.
1518
+ *************************************************************************/
1519
+ _createDateInputForField: function (field, fieldName, value) {
1520
+ var $input = $('<input class="' + field.inputClass + '" id="Edit-' + fieldName + '" type="text" name="' + fieldName + '"></input>');
1521
+ if(value != undefined) {
1522
+ $input.val(value);
1523
+ }
1524
+
1525
+ var displayFormat = field.displayFormat || this.options.defaultDateFormat;
1526
+ $input.datepicker({ dateFormat: displayFormat });
1527
+ return $('<div />')
1528
+ .addClass('jtable-input jtable-date-input')
1529
+ .append($input);
1530
+ },
1531
+
1532
+ /* Creates a textarea element for a field.
1533
+ *************************************************************************/
1534
+ _createTextAreaForField: function (field, fieldName, value) {
1535
+ var $textArea = $('<textarea class="' + field.inputClass + '" id="Edit-' + fieldName + '" name="' + fieldName + '"></textarea>');
1536
+ if (value != undefined) {
1537
+ $textArea.val(value);
1538
+ }
1539
+
1540
+ return $('<div />')
1541
+ .addClass('jtable-input jtable-textarea-input')
1542
+ .append($textArea);
1543
+ },
1544
+
1545
+ /* Creates a standart textbox for a field.
1546
+ *************************************************************************/
1547
+ _createTextInputForField: function (field, fieldName, value) {
1548
+ var $input = $('<input class="' + field.inputClass + '" id="Edit-' + fieldName + '" type="text" name="' + fieldName + '"></input>');
1549
+ if (value != undefined) {
1550
+ $input.val(value);
1551
+ }
1552
+
1553
+ return $('<div />')
1554
+ .addClass('jtable-input jtable-text-input')
1555
+ .append($input);
1556
+ },
1557
+
1558
+ /* Creates a password input for a field.
1559
+ *************************************************************************/
1560
+ _createPasswordInputForField: function (field, fieldName, value) {
1561
+ var $input = $('<input class="' + field.inputClass + '" id="Edit-' + fieldName + '" type="password" name="' + fieldName + '"></input>');
1562
+ if (value != undefined) {
1563
+ $input.val(value);
1564
+ }
1565
+
1566
+ return $('<div />')
1567
+ .addClass('jtable-input jtable-password-input')
1568
+ .append($input);
1569
+ },
1570
+
1571
+ /* Creates a checkboxfor a field.
1572
+ *************************************************************************/
1573
+ _createCheckboxForField: function (field, fieldName, value) {
1574
+ var self = this;
1575
+
1576
+ //If value is undefined, get unchecked state's value
1577
+ if (value == undefined) {
1578
+ value = self._getCheckBoxPropertiesForFieldByState(fieldName, false).Value;
1579
+ }
1580
+
1581
+ //Create a container div
1582
+ var $containerDiv = $('<div />')
1583
+ .addClass('jtable-input jtable-checkbox-input');
1584
+
1585
+ //Create checkbox and check if needed
1586
+ var $checkBox = $('<input class="' + field.inputClass + '" id="Edit-' + fieldName + '" type="checkbox" name="' + fieldName + '" />')
1587
+ .appendTo($containerDiv);
1588
+ if (value != undefined) {
1589
+ $checkBox.val(value);
1590
+ }
1591
+
1592
+ //Create display text of checkbox for current state
1593
+ var $textSpan = $('<span>' + (field.formText || self._getCheckBoxTextForFieldByValue(fieldName, value)) + '</span>')
1594
+ .appendTo($containerDiv);
1595
+
1596
+ //Check the checkbox if it's value is checked-value
1597
+ if (self._getIsCheckBoxSelectedForFieldByValue(fieldName, value)) {
1598
+ $checkBox.attr('checked', 'checked');
1599
+ }
1600
+
1601
+ //This method sets checkbox's value and text according to state of the checkbox
1602
+ var refreshCheckBoxValueAndText = function () {
1603
+ var checkboxProps = self._getCheckBoxPropertiesForFieldByState(fieldName, $checkBox.is(':checked'));
1604
+ $checkBox.attr('value', checkboxProps.Value);
1605
+ $textSpan.html(field.formText || checkboxProps.DisplayText);
1606
+ };
1607
+
1608
+ //Register to click event to change display text when state of checkbox is changed.
1609
+ $checkBox.click(function () {
1610
+ refreshCheckBoxValueAndText();
1611
+ });
1612
+
1613
+ //Change checkbox state when clicked to text
1614
+ if (field.setOnTextClick != false) {
1615
+ $textSpan
1616
+ .addClass('jtable-option-text-clickable')
1617
+ .click(function () {
1618
+ if ($checkBox.is(':checked')) {
1619
+ $checkBox.attr('checked', false);
1620
+ } else {
1621
+ $checkBox.attr('checked', true);
1622
+ }
1623
+
1624
+ refreshCheckBoxValueAndText();
1625
+ });
1626
+ }
1627
+
1628
+ return $containerDiv;
1629
+ },
1630
+
1631
+ /* Creates a drop down list (combobox) input element for a field.
1632
+ *************************************************************************/
1633
+ _createDropDownListForField: function (field, fieldName, value, record, source, form) {
1634
+
1635
+ //Create a container div
1636
+ var $containerDiv = $('<div />')
1637
+ .addClass('jtable-input jtable-dropdown-input');
1638
+
1639
+ //Create select element
1640
+ var $select = $('<select class="' + field.inputClass + '" id="Edit-' + fieldName + '" name="' + fieldName + '"></select>')
1641
+ .appendTo($containerDiv);
1642
+
1643
+ //add options
1644
+ var options = this._getOptionsForField(fieldName, {
1645
+ record: record,
1646
+ source: source,
1647
+ form: form,
1648
+ dependedValues: this._createDependedValuesUsingForm(form, field.dependsOn)
1649
+ });
1650
+
1651
+ this._fillDropDownListWithOptions($select, options, value);
1652
+
1653
+ return $containerDiv;
1654
+ },
1655
+
1656
+ /* Fills a dropdown list with given options.
1657
+ *************************************************************************/
1658
+ _fillDropDownListWithOptions: function ($select, options, value) {
1659
+ $select.empty();
1660
+ for (var i = 0; i < options.length; i++) {
1661
+ $('<option' + (options[i].Value == value ? ' selected="selected"' : '') + '>' + options[i].DisplayText + '</option>')
1662
+ .val(options[i].Value)
1663
+ .appendTo($select);
1664
+ }
1665
+ },
1666
+
1667
+ /* Creates depended values object from given form.
1668
+ *************************************************************************/
1669
+ _createDependedValuesUsingForm: function ($form, dependsOn) {
1670
+ if (!dependsOn) {
1671
+ return {};
1672
+ }
1673
+
1674
+ var dependedValues = {};
1675
+
1676
+ for (var i = 0; i < dependsOn.length; i++) {
1677
+ var dependedField = dependsOn[i];
1678
+
1679
+ var $dependsOn = $form.find('select[name=' + dependedField + ']');
1680
+ if ($dependsOn.length <= 0) {
1681
+ continue;
1682
+ }
1683
+
1684
+ dependedValues[dependedField] = $dependsOn.val();
1685
+ }
1686
+
1687
+
1688
+ return dependedValues;
1689
+ },
1690
+
1691
+ /* Creates a radio button list for a field.
1692
+ *************************************************************************/
1693
+ _createRadioButtonListForField: function (field, fieldName, value, record, source) {
1694
+ var $containerDiv = $('<div />')
1695
+ .addClass('jtable-input jtable-radiobuttonlist-input');
1696
+
1697
+ var options = this._getOptionsForField(fieldName, {
1698
+ record: record,
1699
+ source: source
1700
+ });
1701
+
1702
+ $.each(options, function(i, option) {
1703
+ var $radioButtonDiv = $('<div class=""></div>')
1704
+ .addClass('jtable-radio-input')
1705
+ .appendTo($containerDiv);
1706
+
1707
+ var $radioButton = $('<input type="radio" id="Edit-' + fieldName + '-' + i + '" class="' + field.inputClass + '" name="' + fieldName + '"' + ((option.Value == (value + '')) ? ' checked="true"' : '') + ' />')
1708
+ .val(option.Value)
1709
+ .appendTo($radioButtonDiv);
1710
+
1711
+ var $textSpan = $('<span></span>')
1712
+ .html(option.DisplayText)
1713
+ .appendTo($radioButtonDiv);
1714
+
1715
+ if (field.setOnTextClick != false) {
1716
+ $textSpan
1717
+ .addClass('jtable-option-text-clickable')
1718
+ .click(function () {
1719
+ if (!$radioButton.is(':checked')) {
1720
+ $radioButton.attr('checked', true);
1721
+ }
1722
+ });
1723
+ }
1724
+ });
1725
+
1726
+ return $containerDiv;
1727
+ },
1728
+
1729
+ /* Gets display text for a checkbox field.
1730
+ *************************************************************************/
1731
+ _getCheckBoxTextForFieldByValue: function (fieldName, value) {
1732
+ return this.options.fields[fieldName].values[value];
1733
+ },
1734
+
1735
+ /* Returns true if given field's value must be checked state.
1736
+ *************************************************************************/
1737
+ _getIsCheckBoxSelectedForFieldByValue: function (fieldName, value) {
1738
+ return (this._createCheckBoxStateArrayForFieldWithCaching(fieldName)[1].Value.toString() == value.toString());
1739
+ },
1740
+
1741
+ /* Gets an object for a checkbox field that has Value and DisplayText
1742
+ * properties.
1743
+ *************************************************************************/
1744
+ _getCheckBoxPropertiesForFieldByState: function (fieldName, checked) {
1745
+ return this._createCheckBoxStateArrayForFieldWithCaching(fieldName)[(checked ? 1 : 0)];
1746
+ },
1747
+
1748
+ /* Calls _createCheckBoxStateArrayForField with caching.
1749
+ *************************************************************************/
1750
+ _createCheckBoxStateArrayForFieldWithCaching: function (fieldName) {
1751
+ var cacheKey = 'checkbox_' + fieldName;
1752
+ if (!this._cache[cacheKey]) {
1753
+
1754
+ this._cache[cacheKey] = this._createCheckBoxStateArrayForField(fieldName);
1755
+ }
1756
+
1757
+ return this._cache[cacheKey];
1758
+ },
1759
+
1760
+ /* Creates a two element array of objects for states of a checkbox field.
1761
+ * First element for unchecked state, second for checked state.
1762
+ * Each object has two properties: Value and DisplayText
1763
+ *************************************************************************/
1764
+ _createCheckBoxStateArrayForField: function (fieldName) {
1765
+ var stateArray = [];
1766
+ var currentIndex = 0;
1767
+ $.each(this.options.fields[fieldName].values, function (propName, propValue) {
1768
+ if (currentIndex++ < 2) {
1769
+ stateArray.push({ 'Value': propName, 'DisplayText': propValue });
1770
+ }
1771
+ });
1772
+
1773
+ return stateArray;
1774
+ },
1775
+
1776
+ /* Searches a form for dependend dropdowns and makes them cascaded.
1777
+ */
1778
+ _makeCascadeDropDowns: function ($form, record, source) {
1779
+ var self = this;
1780
+
1781
+ $form.find('select') //for each combobox
1782
+ .each(function () {
1783
+ var $thisDropdown = $(this);
1784
+
1785
+ //get field name
1786
+ var fieldName = $thisDropdown.attr('name');
1787
+ if (!fieldName) {
1788
+ return;
1789
+ }
1790
+
1791
+ var field = self.options.fields[fieldName];
1792
+
1793
+ //check if this combobox depends on others
1794
+ if (!field.dependsOn) {
1795
+ return;
1796
+ }
1797
+
1798
+ //for each dependency
1799
+ $.each(field.dependsOn, function (index, dependsOnField) {
1800
+ //find the depended combobox
1801
+ var $dependsOnDropdown = $form.find('select[name=' + dependsOnField + ']');
1802
+ //when depended combobox changes
1803
+ $dependsOnDropdown.change(function () {
1804
+
1805
+ //Refresh options
1806
+ var funcParams = {
1807
+ record: record,
1808
+ source: source,
1809
+ form: $form,
1810
+ dependedValues: {}
1811
+ };
1812
+ funcParams.dependedValues = self._createDependedValuesUsingForm($form, field.dependsOn);
1813
+ var options = self._getOptionsForField(fieldName, funcParams);
1814
+
1815
+ //Fill combobox with new options
1816
+ self._fillDropDownListWithOptions($thisDropdown, options, undefined);
1817
+
1818
+ //Thigger change event to refresh multi cascade dropdowns.
1819
+ $thisDropdown.change();
1820
+ });
1821
+ });
1822
+ });
1823
+ },
1824
+
1825
+ /* Updates values of a record from given form
1826
+ *************************************************************************/
1827
+ _updateRecordValuesFromForm: function (record, $form) {
1828
+ for (var i = 0; i < this._fieldList.length; i++) {
1829
+ var fieldName = this._fieldList[i];
1830
+ var field = this.options.fields[fieldName];
1831
+
1832
+ //Do not update non-editable fields
1833
+ if (field.edit == false) {
1834
+ continue;
1835
+ }
1836
+
1837
+ //Get field name and the input element of this field in the form
1838
+ var $inputElement = $form.find('[name="' + fieldName + '"]');
1839
+ if ($inputElement.length <= 0) {
1840
+ continue;
1841
+ }
1842
+
1843
+ //Update field in record according to it's type
1844
+ if (field.type == 'date') {
1845
+ var dateVal = $inputElement.val();
1846
+ if (dateVal) {
1847
+ var displayFormat = field.displayFormat || this.options.defaultDateFormat;
1848
+ try {
1849
+ var date = $.datepicker.parseDate(displayFormat, dateVal);
1850
+ record[fieldName] = '/Date(' + date.getTime() + ')/';
1851
+ } catch (e) {
1852
+ //TODO: Handle incorrect/different date formats
1853
+ this._logWarn('Date format is incorrect for field ' + fieldName + ': ' + dateVal);
1854
+ record[fieldName] = undefined;
1855
+ }
1856
+ } else {
1857
+ this._logDebug('Date is empty for ' + fieldName);
1858
+ record[fieldName] = undefined; //TODO: undefined, null or empty string?
1859
+ }
1860
+ } else if (field.options && field.type == 'radiobutton') {
1861
+ var $checkedElement = $inputElement.filter(':checked');
1862
+ if ($checkedElement.length) {
1863
+ record[fieldName] = $checkedElement.val();
1864
+ } else {
1865
+ record[fieldName] = undefined;
1866
+ }
1867
+ } else {
1868
+ record[fieldName] = $inputElement.val();
1869
+ }
1870
+ }
1871
+ },
1872
+
1873
+ /* Sets enabled/disabled state of a dialog button.
1874
+ *************************************************************************/
1875
+ _setEnabledOfDialogButton: function ($button, enabled, buttonText) {
1876
+ if (!$button) {
1877
+ return;
1878
+ }
1879
+
1880
+ if (enabled != false) {
1881
+ $button
1882
+ .removeAttr('disabled')
1883
+ .removeClass('ui-state-disabled');
1884
+ } else {
1885
+ $button
1886
+ .attr('disabled', 'disabled')
1887
+ .addClass('ui-state-disabled');
1888
+ }
1889
+
1890
+ if (buttonText) {
1891
+ $button
1892
+ .find('span')
1893
+ .text(buttonText);
1894
+ }
1895
+ }
1896
+
1897
+ });
1898
+
1899
+ })(jQuery);
1900
+
1901
+
1902
+ /************************************************************************
1903
+ * CREATE RECORD extension for jTable *
1904
+ *************************************************************************/
1905
+ (function ($) {
1906
+
1907
+ //Reference to base object members
1908
+ var base = {
1909
+ _create: $.hik.jtable.prototype._create
1910
+ };
1911
+
1912
+ //extension members
1913
+ $.extend(true, $.hik.jtable.prototype, {
1914
+
1915
+ /************************************************************************
1916
+ * DEFAULT OPTIONS / EVENTS *
1917
+ *************************************************************************/
1918
+ options: {
1919
+
1920
+ //Events
1921
+ recordAdded: function (event, data) { },
1922
+
1923
+ //Localization
1924
+ messages: {
1925
+ addNewRecord: 'Add new record'
1926
+ }
1927
+ },
1928
+
1929
+ /************************************************************************
1930
+ * PRIVATE FIELDS *
1931
+ *************************************************************************/
1932
+
1933
+ _$addRecordDiv: null, //Reference to the adding new record dialog div (jQuery object)
1934
+
1935
+ /************************************************************************
1936
+ * CONSTRUCTOR *
1937
+ *************************************************************************/
1938
+
1939
+ /* Overrides base method to do create-specific constructions.
1940
+ *************************************************************************/
1941
+ _create: function () {
1942
+ base._create.apply(this, arguments);
1943
+
1944
+ if (!this.options.actions.createAction) {
1945
+ return;
1946
+ }
1947
+
1948
+ this._createAddRecordDialogDiv();
1949
+ },
1950
+
1951
+ /* Creates and prepares add new record dialog div
1952
+ *************************************************************************/
1953
+ _createAddRecordDialogDiv: function () {
1954
+ var self = this;
1955
+
1956
+ //Create a div for dialog and add to container element
1957
+ self._$addRecordDiv = $('<div />')
1958
+ .appendTo(self._$mainContainer);
1959
+
1960
+ //Prepare dialog
1961
+ self._$addRecordDiv.dialog({
1962
+ autoOpen: false,
1963
+ show: self.options.dialogShowEffect,
1964
+ hide: self.options.dialogHideEffect,
1965
+ width: 'auto',
1966
+ minWidth: '300',
1967
+ modal: true,
1968
+ title: self.options.messages.addNewRecord,
1969
+ buttons:
1970
+ [{ //Cancel button
1971
+ text: self.options.messages.cancel,
1972
+ click: function () {
1973
+ self._$addRecordDiv.dialog('close');
1974
+ }
1975
+ }, { //Save button
1976
+ id: 'AddRecordDialogSaveButton',
1977
+ text: self.options.messages.save,
1978
+ click: function () {
1979
+ self._onSaveClickedOnCreateForm();
1980
+ }
1981
+ }],
1982
+ close: function () {
1983
+ var $addRecordForm = self._$addRecordDiv.find('form').first();
1984
+ var $saveButton = $('#AddRecordDialogSaveButton');
1985
+ self._trigger("formClosed", null, { form: $addRecordForm, formType: 'create' });
1986
+ self._setEnabledOfDialogButton($saveButton, true, self.options.messages.save);
1987
+ $addRecordForm.remove();
1988
+ }
1989
+ });
1990
+
1991
+ if (self.options.addRecordButton) {
1992
+ //If user supplied a button, bind the click event to show dialog form
1993
+ self.options.addRecordButton.click(function (e) {
1994
+ e.preventDefault();
1995
+ self._showAddRecordForm();
1996
+ });
1997
+ } else {
1998
+ //If user did not supplied a button, create a 'add record button' toolbar item.
1999
+ self._addToolBarItem({
2000
+ icon: true,
2001
+ cssClass: 'jtable-toolbar-item-add-record',
2002
+ text: self.options.messages.addNewRecord,
2003
+ click: function () {
2004
+ self._showAddRecordForm();
2005
+ }
2006
+ });
2007
+ }
2008
+ },
2009
+
2010
+ _onSaveClickedOnCreateForm: function () {
2011
+ var self = this;
2012
+
2013
+ var $saveButton = $('#AddRecordDialogSaveButton');
2014
+ var $addRecordForm = self._$addRecordDiv.find('form');
2015
+
2016
+ if (self._trigger("formSubmitting", null, { form: $addRecordForm, formType: 'create' }) != false) {
2017
+ self._setEnabledOfDialogButton($saveButton, false, self.options.messages.saving);
2018
+ self._saveAddRecordForm($addRecordForm, $saveButton);
2019
+ }
2020
+ },
2021
+
2022
+ /************************************************************************
2023
+ * PUBLIC METHODS *
2024
+ *************************************************************************/
2025
+
2026
+ /* Shows add new record dialog form.
2027
+ *************************************************************************/
2028
+ showCreateForm: function () {
2029
+ this._showAddRecordForm();
2030
+ },
2031
+
2032
+ /* Adds a new record to the table (optionally to the server also)
2033
+ *************************************************************************/
2034
+ addRecord: function (options) {
2035
+ var self = this;
2036
+ options = $.extend({
2037
+ clientOnly: false,
2038
+ animationsEnabled: self.options.animationsEnabled,
2039
+ url: self.options.actions.createAction,
2040
+ success: function () { },
2041
+ error: function () { }
2042
+ }, options);
2043
+
2044
+ if (!options.record) {
2045
+ self._logWarn('options parameter in addRecord method must contain a record property.');
2046
+ return;
2047
+ }
2048
+
2049
+ if (options.clientOnly) {
2050
+ self._addRow(
2051
+ self._createRowFromRecord(options.record), {
2052
+ isNewRow: true,
2053
+ animationsEnabled: options.animationsEnabled
2054
+ });
2055
+
2056
+ options.success();
2057
+ return;
2058
+ }
2059
+
2060
+ self._submitFormUsingAjax(
2061
+ options.url,
2062
+ $.param(options.record),
2063
+ function (data) {
2064
+ if (data.Result != 'OK') {
2065
+ self._showError(data.Message);
2066
+ options.error(data);
2067
+ return;
2068
+ }
2069
+
2070
+ if(!data.Record) {
2071
+ self._logError('Server must return the created Record object.');
2072
+ options.error(data);
2073
+ return;
2074
+ }
2075
+
2076
+ self._onRecordAdded(data);
2077
+
2078
+ self._addRow(
2079
+ self._createRowFromRecord(data.Record), {
2080
+ isNewRow: true,
2081
+ animationsEnabled: options.animationsEnabled
2082
+ });
2083
+
2084
+ options.success(data);
2085
+ },
2086
+ function () {
2087
+ self._showError(self.options.messages.serverCommunicationError);
2088
+ options.error();
2089
+ });
2090
+ },
2091
+
2092
+ /************************************************************************
2093
+ * PRIVATE METHODS *
2094
+ *************************************************************************/
2095
+
2096
+ /* Shows add new record dialog form.
2097
+ *************************************************************************/
2098
+ _showAddRecordForm: function () {
2099
+ var self = this;
2100
+
2101
+ //Create add new record form
2102
+ var $addRecordForm = $('<form id="jtable-create-form" class="jtable-dialog-form jtable-create-form"></form>');
2103
+
2104
+ //Create input elements
2105
+ for (var i = 0; i < self._fieldList.length; i++) {
2106
+
2107
+ var fieldName = self._fieldList[i];
2108
+ var field = self.options.fields[fieldName];
2109
+
2110
+ //Do not create input for fields that is key and not specially marked as creatable
2111
+ if (field.key == true && field.create != true) {
2112
+ continue;
2113
+ }
2114
+
2115
+ //Do not create input for fields that are not creatable
2116
+ if (field.create == false) {
2117
+ continue;
2118
+ }
2119
+
2120
+ if (field.type == 'hidden') {
2121
+ $addRecordForm.append(self._createInputForHidden(fieldName, field.defaultValue));
2122
+ continue;
2123
+ }
2124
+
2125
+ //Create a container div for this input field and add to form
2126
+ var $fieldContainer = $('<div />')
2127
+ .addClass('jtable-input-field-container')
2128
+ .appendTo($addRecordForm);
2129
+
2130
+ //Create a label for input
2131
+ $fieldContainer.append(self._createInputLabelForRecordField(fieldName));
2132
+
2133
+ //Create input element
2134
+ $fieldContainer.append(
2135
+ self._createInputForRecordField({
2136
+ fieldName: fieldName,
2137
+ formType: 'create',
2138
+ form: $addRecordForm
2139
+ }));
2140
+ }
2141
+
2142
+ self._makeCascadeDropDowns($addRecordForm, undefined, 'create');
2143
+
2144
+ $addRecordForm.submit(function () {
2145
+ self._onSaveClickedOnCreateForm();
2146
+ return false;
2147
+ });
2148
+
2149
+ //Open the form
2150
+ self._$addRecordDiv.append($addRecordForm).dialog('open');
2151
+ self._trigger("formCreated", null, { form: $addRecordForm, formType: 'create' });
2152
+ },
2153
+
2154
+ /* Saves new added record to the server and updates table.
2155
+ *************************************************************************/
2156
+ _saveAddRecordForm: function ($addRecordForm, $saveButton) {
2157
+ var self = this;
2158
+
2159
+ //Make an Ajax call to update record
2160
+ $addRecordForm.data('submitting', true);
2161
+
2162
+ self._submitFormUsingAjax(
2163
+ self.options.actions.createAction,
2164
+ $addRecordForm.serialize(),
2165
+ function (data) {
2166
+
2167
+ if (data.Result != 'OK') {
2168
+ self._showError(data.Message);
2169
+ self._setEnabledOfDialogButton($saveButton, true, self.options.messages.save);
2170
+ return;
2171
+ }
2172
+
2173
+ if (!data.Record) {
2174
+ self._logError('Server must return the created Record object.');
2175
+ self._setEnabledOfDialogButton($saveButton, true, self.options.messages.save);
2176
+ return;
2177
+ }
2178
+
2179
+ self._onRecordAdded(data);
2180
+ self._addRow(
2181
+ self._createRowFromRecord(data.Record), {
2182
+ isNewRow: true
2183
+ });
2184
+ self._$addRecordDiv.dialog("close");
2185
+ },
2186
+ function () {
2187
+ self._showError(self.options.messages.serverCommunicationError);
2188
+ self._setEnabledOfDialogButton($saveButton, true, self.options.messages.save);
2189
+ });
2190
+ },
2191
+
2192
+ _onRecordAdded: function (data) {
2193
+ this._trigger("recordAdded", null, { record: data.Record, serverResponse: data });
2194
+ }
2195
+
2196
+ });
2197
+
2198
+ })(jQuery);
2199
+
2200
+
2201
+ /************************************************************************
2202
+ * EDIT RECORD extension for jTable *
2203
+ *************************************************************************/
2204
+ (function ($) {
2205
+
2206
+ //Reference to base object members
2207
+ var base = {
2208
+ _create: $.hik.jtable.prototype._create,
2209
+ _addColumnsToHeaderRow: $.hik.jtable.prototype._addColumnsToHeaderRow,
2210
+ _addCellsToRowUsingRecord: $.hik.jtable.prototype._addCellsToRowUsingRecord
2211
+ };
2212
+
2213
+ //extension members
2214
+ $.extend(true, $.hik.jtable.prototype, {
2215
+
2216
+ /************************************************************************
2217
+ * DEFAULT OPTIONS / EVENTS *
2218
+ *************************************************************************/
2219
+ options: {
2220
+
2221
+ //Events
2222
+ recordUpdated: function (event, data) { },
2223
+ rowUpdated: function (event, data) { },
2224
+
2225
+ //Localization
2226
+ messages: {
2227
+ editRecord: 'Edit Record'
2228
+ }
2229
+ },
2230
+
2231
+ /************************************************************************
2232
+ * PRIVATE FIELDS *
2233
+ *************************************************************************/
2234
+
2235
+ _$editDiv: null, //Reference to the editing dialog div (jQuery object)
2236
+ _$editingRow: null, //Reference to currently editing row (jQuery object)
2237
+
2238
+ /************************************************************************
2239
+ * CONSTRUCTOR AND INITIALIZATION METHODS *
2240
+ *************************************************************************/
2241
+
2242
+ /* Overrides base method to do editing-specific constructions.
2243
+ *************************************************************************/
2244
+ _create: function () {
2245
+ base._create.apply(this, arguments);
2246
+
2247
+ if (!this.options.actions.updateAction) {
2248
+ return;
2249
+ }
2250
+
2251
+ this._createEditDialogDiv();
2252
+ },
2253
+
2254
+ /* Creates and prepares edit dialog div
2255
+ *************************************************************************/
2256
+ _createEditDialogDiv: function () {
2257
+ var self = this;
2258
+
2259
+ //Create a div for dialog and add to container element
2260
+ self._$editDiv = $('<div></div>')
2261
+ .appendTo(self._$mainContainer);
2262
+
2263
+ //Prepare dialog
2264
+ self._$editDiv.dialog({
2265
+ autoOpen: false,
2266
+ show: self.options.dialogShowEffect,
2267
+ hide: self.options.dialogHideEffect,
2268
+ width: 'auto',
2269
+ minWidth: '300',
2270
+ modal: true,
2271
+ title: self.options.messages.editRecord,
2272
+ buttons:
2273
+ [{ //cancel button
2274
+ text: self.options.messages.cancel,
2275
+ click: function () {
2276
+ self._$editDiv.dialog('close');
2277
+ }
2278
+ }, { //save button
2279
+ id: 'EditDialogSaveButton',
2280
+ text: self.options.messages.save,
2281
+ click: function () {
2282
+ self._onSaveClickedOnEditForm();
2283
+ }
2284
+ }],
2285
+ close: function () {
2286
+ var $editForm = self._$editDiv.find('form:first');
2287
+ var $saveButton = $('#EditDialogSaveButton');
2288
+ self._trigger("formClosed", null, { form: $editForm, formType: 'edit', row: self._$editingRow });
2289
+ self._setEnabledOfDialogButton($saveButton, true, self.options.messages.save);
2290
+ $editForm.remove();
2291
+ }
2292
+ });
2293
+ },
2294
+
2295
+ /* Saves editing form to server.
2296
+ *************************************************************************/
2297
+ _onSaveClickedOnEditForm: function () {
2298
+ var self = this;
2299
+
2300
+ //row maybe removed by another source, if so, do nothing
2301
+ if (self._$editingRow.hasClass('jtable-row-removed')) {
2302
+ self._$editDiv.dialog('close');
2303
+ return;
2304
+ }
2305
+
2306
+ var $saveButton = $('#EditDialogSaveButton');
2307
+ var $editForm = self._$editDiv.find('form');
2308
+ if (self._trigger("formSubmitting", null, { form: $editForm, formType: 'edit', row: self._$editingRow }) != false) {
2309
+ self._setEnabledOfDialogButton($saveButton, false, self.options.messages.saving);
2310
+ self._saveEditForm($editForm, $saveButton);
2311
+ }
2312
+ },
2313
+
2314
+ /************************************************************************
2315
+ * PUBLIC METHODS *
2316
+ *************************************************************************/
2317
+
2318
+ /* Updates a record on the table (optionally on the server also)
2319
+ *************************************************************************/
2320
+ updateRecord: function (options) {
2321
+ var self = this;
2322
+ options = $.extend({
2323
+ clientOnly: false,
2324
+ animationsEnabled: self.options.animationsEnabled,
2325
+ url: self.options.actions.updateAction,
2326
+ success: function () { },
2327
+ error: function () { }
2328
+ }, options);
2329
+
2330
+ if (!options.record) {
2331
+ self._logWarn('options parameter in updateRecord method must contain a record property.');
2332
+ return;
2333
+ }
2334
+
2335
+ var key = self._getKeyValueOfRecord(options.record);
2336
+ if (key == undefined || key == null) {
2337
+ self._logWarn('options parameter in updateRecord method must contain a record that contains the key field property.');
2338
+ return;
2339
+ }
2340
+
2341
+ var $updatingRow = self.getRowByKey(key);
2342
+ if ($updatingRow == null) {
2343
+ self._logWarn('Can not found any row by key: ' + key);
2344
+ return;
2345
+ }
2346
+
2347
+ if (options.clientOnly) {
2348
+ $.extend($updatingRow.data('record'), options.record);
2349
+ self._updateRowTexts($updatingRow);
2350
+ self._onRecordUpdated($updatingRow, null);
2351
+ if (options.animationsEnabled) {
2352
+ self._showUpdateAnimationForRow($updatingRow);
2353
+ }
2354
+
2355
+ options.success();
2356
+ return;
2357
+ }
2358
+
2359
+ self._submitFormUsingAjax(
2360
+ options.url,
2361
+ $.param(options.record),
2362
+ function (data) {
2363
+ if (data.Result != 'OK') {
2364
+ self._showError(data.Message);
2365
+ options.error(data);
2366
+ return;
2367
+ }
2368
+
2369
+ $.extend($updatingRow.data('record'), options.record);
2370
+ self._updateRecordValuesFromServerResponse($updatingRow.data('record'), data);
2371
+
2372
+ self._updateRowTexts($updatingRow);
2373
+ self._onRecordUpdated($updatingRow, data);
2374
+ if (options.animationsEnabled) {
2375
+ self._showUpdateAnimationForRow($updatingRow);
2376
+ }
2377
+
2378
+ options.success(data);
2379
+ },
2380
+ function () {
2381
+ self._showError(self.options.messages.serverCommunicationError);
2382
+ options.error();
2383
+ });
2384
+ },
2385
+
2386
+ /************************************************************************
2387
+ * OVERRIDED METHODS *
2388
+ *************************************************************************/
2389
+
2390
+ /* Overrides base method to add a 'editing column cell' to header row.
2391
+ *************************************************************************/
2392
+ _addColumnsToHeaderRow: function ($tr) {
2393
+ base._addColumnsToHeaderRow.apply(this, arguments);
2394
+ if (this.options.actions.updateAction != undefined) {
2395
+ $tr.append(this._createEmptyCommandHeader());
2396
+ }
2397
+ },
2398
+
2399
+ /* Overrides base method to add a 'edit command cell' to a row.
2400
+ *************************************************************************/
2401
+ _addCellsToRowUsingRecord: function ($row) {
2402
+ var self = this;
2403
+ base._addCellsToRowUsingRecord.apply(this, arguments);
2404
+
2405
+ if (self.options.actions.updateAction != undefined) {
2406
+ var $span = $('<span></span>').html(self.options.messages.editRecord);
2407
+ var $button = $('<button title="' + self.options.messages.editRecord + '"></button>')
2408
+ .addClass('jtable-command-button jtable-edit-command-button')
2409
+ .append($span)
2410
+ .click(function (e) {
2411
+ e.preventDefault();
2412
+ e.stopPropagation();
2413
+ self._showEditForm($row);
2414
+ });
2415
+ $('<td></td>')
2416
+ .addClass('jtable-command-column')
2417
+ .append($button)
2418
+ .appendTo($row);
2419
+ }
2420
+ },
2421
+
2422
+ /************************************************************************
2423
+ * PRIVATE METHODS *
2424
+ *************************************************************************/
2425
+
2426
+ /* Shows edit form for a row.
2427
+ *************************************************************************/
2428
+ _showEditForm: function ($tableRow) {
2429
+ var self = this;
2430
+ var record = $tableRow.data('record');
2431
+
2432
+ //Create edit form
2433
+ var $editForm = $('<form id="jtable-edit-form" class="jtable-dialog-form jtable-edit-form"></form>');
2434
+
2435
+ //Create input fields
2436
+ for (var i = 0; i < self._fieldList.length; i++) {
2437
+
2438
+ var fieldName = self._fieldList[i];
2439
+ var field = self.options.fields[fieldName];
2440
+ var fieldValue = record[fieldName];
2441
+
2442
+ if (field.key == true) {
2443
+ if (field.edit != true) {
2444
+ //Create hidden field for key
2445
+ $editForm.append(self._createInputForHidden(fieldName, fieldValue));
2446
+ continue;
2447
+ } else {
2448
+ //Create a special hidden field for key (since key is be editable)
2449
+ $editForm.append(self._createInputForHidden('jtRecordKey', fieldValue));
2450
+ }
2451
+ }
2452
+
2453
+ //Do not create element for non-editable fields
2454
+ if (field.edit == false) {
2455
+ continue;
2456
+ }
2457
+
2458
+ //Hidden field
2459
+ if (field.type == 'hidden') {
2460
+ $editForm.append(self._createInputForHidden(fieldName, fieldValue));
2461
+ continue;
2462
+ }
2463
+
2464
+ //Create a container div for this input field and add to form
2465
+ var $fieldContainer = $('<div class="jtable-input-field-container"></div>').appendTo($editForm);
2466
+
2467
+ //Create a label for input
2468
+ $fieldContainer.append(self._createInputLabelForRecordField(fieldName));
2469
+
2470
+ //Create input element with it's current value
2471
+ var currentValue = self._getValueForRecordField(record, fieldName);
2472
+ $fieldContainer.append(
2473
+ self._createInputForRecordField({
2474
+ fieldName: fieldName,
2475
+ value: currentValue,
2476
+ record: record,
2477
+ formType: 'edit',
2478
+ form: $editForm
2479
+ }));
2480
+ }
2481
+
2482
+ self._makeCascadeDropDowns($editForm, record, 'edit');
2483
+
2484
+ $editForm.submit(function () {
2485
+ self._onSaveClickedOnEditForm();
2486
+ return false;
2487
+ });
2488
+
2489
+ //Open dialog
2490
+ self._$editingRow = $tableRow;
2491
+ self._$editDiv.append($editForm).dialog('open');
2492
+ self._trigger("formCreated", null, { form: $editForm, formType: 'edit', record: record, row: $tableRow });
2493
+ },
2494
+
2495
+ /* Saves editing form to the server and updates the record on the table.
2496
+ *************************************************************************/
2497
+ _saveEditForm: function ($editForm, $saveButton) {
2498
+ var self = this;
2499
+ self._submitFormUsingAjax(
2500
+ self.options.actions.updateAction,
2501
+ $editForm.serialize(),
2502
+ function (data) {
2503
+ //Check for errors
2504
+ if (data.Result != 'OK') {
2505
+ self._showError(data.Message);
2506
+ self._setEnabledOfDialogButton($saveButton, true, self.options.messages.save);
2507
+ return;
2508
+ }
2509
+
2510
+ var record = self._$editingRow.data('record');
2511
+
2512
+ self._updateRecordValuesFromForm(record, $editForm);
2513
+ self._updateRecordValuesFromServerResponse(record, data);
2514
+ self._updateRowTexts(self._$editingRow);
2515
+
2516
+ self._$editingRow.attr('data-record-key', self._getKeyValueOfRecord(record));
2517
+
2518
+ self._onRecordUpdated(self._$editingRow, data);
2519
+
2520
+ if (self.options.animationsEnabled) {
2521
+ self._showUpdateAnimationForRow(self._$editingRow);
2522
+ }
2523
+
2524
+ self._$editDiv.dialog("close");
2525
+ },
2526
+ function () {
2527
+ self._showError(self.options.messages.serverCommunicationError);
2528
+ self._setEnabledOfDialogButton($saveButton, true, self.options.messages.save);
2529
+ });
2530
+ },
2531
+
2532
+ /* This method ensures updating of current record with server response,
2533
+ * if server sends a Record object as response to updateAction.
2534
+ *************************************************************************/
2535
+ _updateRecordValuesFromServerResponse: function (record, serverResponse) {
2536
+ if (!serverResponse || !serverResponse.Record) {
2537
+ return;
2538
+ }
2539
+
2540
+ $.extend(true, record, serverResponse.Record);
2541
+ },
2542
+
2543
+ /* Gets text for a field of a record according to it's type.
2544
+ *************************************************************************/
2545
+ _getValueForRecordField: function (record, fieldName) {
2546
+ var field = this.options.fields[fieldName];
2547
+ var fieldValue = record[fieldName];
2548
+ if (field.type == 'date') {
2549
+ return this._getDisplayTextForDateRecordField(field, fieldValue);
2550
+ } else {
2551
+ return fieldValue;
2552
+ }
2553
+ },
2554
+
2555
+ /* Updates cells of a table row's text values from row's record values.
2556
+ *************************************************************************/
2557
+ _updateRowTexts: function ($tableRow) {
2558
+ var record = $tableRow.data('record');
2559
+ var $columns = $tableRow.find('td');
2560
+ for (var i = 0; i < this._columnList.length; i++) {
2561
+ var displayItem = this._getDisplayTextForRecordField(record, this._columnList[i]);
2562
+ if (displayItem == 0) displayItem = "0";
2563
+ $columns.eq(this._firstDataColumnOffset + i).html(displayItem || '');
2564
+ }
2565
+
2566
+ this._onRowUpdated($tableRow);
2567
+ },
2568
+
2569
+ /* Shows 'updated' animation for a table row.
2570
+ *************************************************************************/
2571
+ _showUpdateAnimationForRow: function ($tableRow) {
2572
+ var className = 'jtable-row-updated';
2573
+ if (this.options.jqueryuiTheme) {
2574
+ className = className + ' ui-state-highlight';
2575
+ }
2576
+
2577
+ $tableRow.stop(true, true).addClass(className, 'slow', '', function () {
2578
+ $tableRow.removeClass(className, 5000);
2579
+ });
2580
+ },
2581
+
2582
+ /************************************************************************
2583
+ * EVENT RAISING METHODS *
2584
+ *************************************************************************/
2585
+
2586
+ _onRowUpdated: function ($row) {
2587
+ this._trigger("rowUpdated", null, { row: $row, record: $row.data('record') });
2588
+ },
2589
+
2590
+ _onRecordUpdated: function ($row, data) {
2591
+ this._trigger("recordUpdated", null, { record: $row.data('record'), row: $row, serverResponse: data });
2592
+ }
2593
+
2594
+ });
2595
+
2596
+ })(jQuery);
2597
+
2598
+
2599
+ /************************************************************************
2600
+ * DELETION extension for jTable *
2601
+ *************************************************************************/
2602
+ (function ($) {
2603
+
2604
+ //Reference to base object members
2605
+ var base = {
2606
+ _create: $.hik.jtable.prototype._create,
2607
+ _addColumnsToHeaderRow: $.hik.jtable.prototype._addColumnsToHeaderRow,
2608
+ _addCellsToRowUsingRecord: $.hik.jtable.prototype._addCellsToRowUsingRecord
2609
+ };
2610
+
2611
+ //extension members
2612
+ $.extend(true, $.hik.jtable.prototype, {
2613
+
2614
+ /************************************************************************
2615
+ * DEFAULT OPTIONS / EVENTS *
2616
+ *************************************************************************/
2617
+ options: {
2618
+
2619
+ //Options
2620
+ deleteConfirmation: true,
2621
+
2622
+ //Events
2623
+ recordDeleted: function (event, data) { },
2624
+
2625
+ //Localization
2626
+ messages: {
2627
+ deleteConfirmation: 'This record will be deleted. Are you sure?',
2628
+ deleteText: 'Delete',
2629
+ deleting: 'Deleting',
2630
+ canNotDeletedRecords: 'Can not delete {0} of {1} records!',
2631
+ deleteProggress: 'Deleting {0} of {1} records, processing...'
2632
+ }
2633
+ },
2634
+
2635
+ /************************************************************************
2636
+ * PRIVATE FIELDS *
2637
+ *************************************************************************/
2638
+
2639
+ _$deleteRecordDiv: null, //Reference to the adding new record dialog div (jQuery object)
2640
+ _$deletingRow: null, //Reference to currently deleting row (jQuery object)
2641
+
2642
+ /************************************************************************
2643
+ * CONSTRUCTOR *
2644
+ *************************************************************************/
2645
+
2646
+ /* Overrides base method to do deletion-specific constructions.
2647
+ *************************************************************************/
2648
+ _create: function () {
2649
+ base._create.apply(this, arguments);
2650
+ this._createDeleteDialogDiv();
2651
+ },
2652
+
2653
+ /* Creates and prepares delete record confirmation dialog div.
2654
+ *************************************************************************/
2655
+ _createDeleteDialogDiv: function () {
2656
+ var self = this;
2657
+
2658
+ //Check if deleteAction is supplied
2659
+ if (!self.options.actions.deleteAction) {
2660
+ return;
2661
+ }
2662
+
2663
+ //Create div element for delete confirmation dialog
2664
+ self._$deleteRecordDiv = $('<div><p><span class="ui-icon ui-icon-alert" style="float:left; margin:0 7px 20px 0;"></span><span class="jtable-delete-confirm-message"></span></p></div>').appendTo(self._$mainContainer);
2665
+
2666
+ //Prepare dialog
2667
+ self._$deleteRecordDiv.dialog({
2668
+ autoOpen: false,
2669
+ show: self.options.dialogShowEffect,
2670
+ hide: self.options.dialogHideEffect,
2671
+ modal: true,
2672
+ title: self.options.messages.areYouSure,
2673
+ buttons:
2674
+ [{ //cancel button
2675
+ text: self.options.messages.cancel,
2676
+ click: function () {
2677
+ self._$deleteRecordDiv.dialog("close");
2678
+ }
2679
+ }, {//delete button
2680
+ id: 'DeleteDialogButton',
2681
+ text: self.options.messages.deleteText,
2682
+ click: function () {
2683
+
2684
+ //row maybe removed by another source, if so, do nothing
2685
+ if (self._$deletingRow.hasClass('jtable-row-removed')) {
2686
+ self._$deleteRecordDiv.dialog('close');
2687
+ return;
2688
+ }
2689
+
2690
+ var $deleteButton = $('#DeleteDialogButton');
2691
+ self._setEnabledOfDialogButton($deleteButton, false, self.options.messages.deleting);
2692
+ self._deleteRecordFromServer(
2693
+ self._$deletingRow,
2694
+ function () {
2695
+ self._removeRowsFromTableWithAnimation(self._$deletingRow);
2696
+ self._$deleteRecordDiv.dialog('close');
2697
+ },
2698
+ function (message) { //error
2699
+ self._showError(message);
2700
+ self._setEnabledOfDialogButton($deleteButton, true, self.options.messages.deleteText);
2701
+ }
2702
+ );
2703
+ }
2704
+ }],
2705
+ close: function () {
2706
+ var $deleteButton = $('#DeleteDialogButton');
2707
+ self._setEnabledOfDialogButton($deleteButton, true, self.options.messages.deleteText);
2708
+ }
2709
+ });
2710
+ },
2711
+
2712
+ /************************************************************************
2713
+ * PUBLIC METHODS *
2714
+ *************************************************************************/
2715
+
2716
+ /* This method is used to delete one or more rows from server and the table.
2717
+ *************************************************************************/
2718
+ deleteRows: function ($rows) {
2719
+ var self = this;
2720
+
2721
+ if ($rows.length <= 0) {
2722
+ self._logWarn('No rows specified to jTable deleteRows method.');
2723
+ return;
2724
+ }
2725
+
2726
+ if (self._isBusy()) {
2727
+ self._logWarn('Can not delete rows since jTable is busy!');
2728
+ return;
2729
+ }
2730
+
2731
+ //Deleting just one row
2732
+ if ($rows.length == 1) {
2733
+ self._deleteRecordFromServer(
2734
+ $rows,
2735
+ function () { //success
2736
+ self._removeRowsFromTableWithAnimation($rows);
2737
+ },
2738
+ function (message) { //error
2739
+ self._showError(message);
2740
+ }
2741
+ );
2742
+
2743
+ return;
2744
+ }
2745
+
2746
+ //Deleting multiple rows
2747
+ self._showBusy(self._formatString(self.options.messages.deleteProggress, 0, $rows.length));
2748
+
2749
+ //This method checks if deleting of all records is completed
2750
+ var completedCount = 0;
2751
+ var isCompleted = function () {
2752
+ return (completedCount >= $rows.length);
2753
+ };
2754
+
2755
+ //This method is called when deleting of all records completed
2756
+ var completed = function () {
2757
+ var $deletedRows = $rows.filter('.jtable-row-ready-to-remove');
2758
+ if ($deletedRows.length < $rows.length) {
2759
+ self._showError(self._formatString(self.options.messages.canNotDeletedRecords, $rows.length - $deletedRows.length, $rows.length));
2760
+ }
2761
+
2762
+ if ($deletedRows.length > 0) {
2763
+ self._removeRowsFromTableWithAnimation($deletedRows);
2764
+ }
2765
+
2766
+ self._hideBusy();
2767
+ };
2768
+
2769
+ //Delete all rows
2770
+ var deletedCount = 0;
2771
+ $rows.each(function () {
2772
+ var $row = $(this);
2773
+ self._deleteRecordFromServer(
2774
+ $row,
2775
+ function () { //success
2776
+ ++deletedCount; ++completedCount;
2777
+ $row.addClass('jtable-row-ready-to-remove');
2778
+ self._showBusy(self._formatString(self.options.messages.deleteProggress, deletedCount, $rows.length));
2779
+ if (isCompleted()) {
2780
+ completed();
2781
+ }
2782
+ },
2783
+ function () { //error
2784
+ ++completedCount;
2785
+ if (isCompleted()) {
2786
+ completed();
2787
+ }
2788
+ }
2789
+ );
2790
+ });
2791
+ },
2792
+
2793
+ /* Deletes a record from the table (optionally from the server also).
2794
+ *************************************************************************/
2795
+ deleteRecord: function (options) {
2796
+ var self = this;
2797
+ options = $.extend({
2798
+ clientOnly: false,
2799
+ animationsEnabled: self.options.animationsEnabled,
2800
+ url: self.options.actions.deleteAction,
2801
+ success: function () { },
2802
+ error: function () { }
2803
+ }, options);
2804
+
2805
+ if (options.key == undefined) {
2806
+ self._logWarn('options parameter in deleteRecord method must contain a key property.');
2807
+ return;
2808
+ }
2809
+
2810
+ var $deletingRow = self.getRowByKey(options.key);
2811
+ if ($deletingRow == null) {
2812
+ self._logWarn('Can not found any row by key: ' + options.key);
2813
+ return;
2814
+ }
2815
+
2816
+ if (options.clientOnly) {
2817
+ self._removeRowsFromTableWithAnimation($deletingRow, options.animationsEnabled);
2818
+ options.success();
2819
+ return;
2820
+ }
2821
+
2822
+ self._deleteRecordFromServer(
2823
+ $deletingRow,
2824
+ function (data) { //success
2825
+ self._removeRowsFromTableWithAnimation($deletingRow, options.animationsEnabled);
2826
+ options.success(data);
2827
+ },
2828
+ function (message) { //error
2829
+ self._showError(message);
2830
+ options.error(message);
2831
+ },
2832
+ options.url
2833
+ );
2834
+ },
2835
+
2836
+ /************************************************************************
2837
+ * OVERRIDED METHODS *
2838
+ *************************************************************************/
2839
+
2840
+ /* Overrides base method to add a 'deletion column cell' to header row.
2841
+ *************************************************************************/
2842
+ _addColumnsToHeaderRow: function ($tr) {
2843
+ base._addColumnsToHeaderRow.apply(this, arguments);
2844
+ if (this.options.actions.deleteAction != undefined) {
2845
+ $tr.append(this._createEmptyCommandHeader());
2846
+ }
2847
+ },
2848
+
2849
+ /* Overrides base method to add a 'delete command cell' to a row.
2850
+ *************************************************************************/
2851
+ _addCellsToRowUsingRecord: function ($row) {
2852
+ base._addCellsToRowUsingRecord.apply(this, arguments);
2853
+
2854
+ var self = this;
2855
+ if (self.options.actions.deleteAction != undefined) {
2856
+ var $span = $('<span></span>').html(self.options.messages.deleteText);
2857
+ var $button = $('<button title="' + self.options.messages.deleteText + '"></button>')
2858
+ .addClass('jtable-command-button jtable-delete-command-button')
2859
+ .append($span)
2860
+ .click(function (e) {
2861
+ e.preventDefault();
2862
+ e.stopPropagation();
2863
+ self._deleteButtonClickedForRow($row);
2864
+ });
2865
+ $('<td></td>')
2866
+ .addClass('jtable-command-column')
2867
+ .append($button)
2868
+ .appendTo($row);
2869
+ }
2870
+ },
2871
+
2872
+ /************************************************************************
2873
+ * PRIVATE METHODS *
2874
+ *************************************************************************/
2875
+
2876
+ /* This method is called when user clicks delete button on a row.
2877
+ *************************************************************************/
2878
+ _deleteButtonClickedForRow: function ($row) {
2879
+ var self = this;
2880
+
2881
+ var deleteConfirm;
2882
+ var deleteConfirmMessage = self.options.messages.deleteConfirmation;
2883
+
2884
+ //If options.deleteConfirmation is function then call it
2885
+ if ($.isFunction(self.options.deleteConfirmation)) {
2886
+ var data = { row: $row, record: $row.data('record'), deleteConfirm: true, deleteConfirmMessage: deleteConfirmMessage, cancel: false, cancelMessage: null };
2887
+ self.options.deleteConfirmation(data);
2888
+
2889
+ //If delete progress is cancelled
2890
+ if (data.cancel) {
2891
+
2892
+ //If a canlellation reason is specified
2893
+ if (data.cancelMessage) {
2894
+ self._showError(data.cancelMessage); //TODO: show warning/stop message instead of error (also show warning/error ui icon)!
2895
+ }
2896
+
2897
+ return;
2898
+ }
2899
+
2900
+ deleteConfirmMessage = data.deleteConfirmMessage;
2901
+ deleteConfirm = data.deleteConfirm;
2902
+ } else {
2903
+ deleteConfirm = self.options.deleteConfirmation;
2904
+ }
2905
+
2906
+ if (deleteConfirm != false) {
2907
+ //Confirmation
2908
+ self._$deleteRecordDiv.find('.jtable-delete-confirm-message').html(deleteConfirmMessage);
2909
+ self._showDeleteDialog($row);
2910
+ } else {
2911
+ //No confirmation
2912
+ self._deleteRecordFromServer(
2913
+ $row,
2914
+ function () { //success
2915
+ self._removeRowsFromTableWithAnimation($row);
2916
+ },
2917
+ function (message) { //error
2918
+ self._showError(message);
2919
+ }
2920
+ );
2921
+ }
2922
+ },
2923
+
2924
+ /* Shows delete comfirmation dialog.
2925
+ *************************************************************************/
2926
+ _showDeleteDialog: function ($row) {
2927
+ this._$deletingRow = $row;
2928
+ this._$deleteRecordDiv.dialog('open');
2929
+ },
2930
+
2931
+ /* Performs an ajax call to server to delete record
2932
+ * and removesd row of record from table if ajax call success.
2933
+ *************************************************************************/
2934
+ _deleteRecordFromServer: function ($row, success, error, url) {
2935
+ var self = this;
2936
+
2937
+ //Check if it is already being deleted right now
2938
+ if ($row.data('deleting') == true) {
2939
+ return;
2940
+ }
2941
+
2942
+ $row.data('deleting', true);
2943
+
2944
+ var postData = {};
2945
+ postData[self._keyField] = self._getKeyValueOfRecord($row.data('record'));
2946
+
2947
+ this._ajax({
2948
+ url: (url || self.options.actions.deleteAction),
2949
+ data: postData,
2950
+ success: function (data) {
2951
+
2952
+ if (data.Result != 'OK') {
2953
+ $row.data('deleting', false);
2954
+ if (error) {
2955
+ error(data.Message);
2956
+ }
2957
+
2958
+ return;
2959
+ }
2960
+
2961
+ self._trigger("recordDeleted", null, { record: $row.data('record'), row: $row, serverResponse: data });
2962
+
2963
+ if (success) {
2964
+ success(data);
2965
+ }
2966
+ },
2967
+ error: function () {
2968
+ $row.data('deleting', false);
2969
+ if (error) {
2970
+ error(self.options.messages.serverCommunicationError);
2971
+ }
2972
+ }
2973
+ });
2974
+ },
2975
+
2976
+ /* Removes a row from table after a 'deleting' animation.
2977
+ *************************************************************************/
2978
+ _removeRowsFromTableWithAnimation: function ($rows, animationsEnabled) {
2979
+ var self = this;
2980
+
2981
+ if (animationsEnabled == undefined) {
2982
+ animationsEnabled = self.options.animationsEnabled;
2983
+ }
2984
+
2985
+ if (animationsEnabled) {
2986
+ var className = 'jtable-row-deleting';
2987
+ if (this.options.jqueryuiTheme) {
2988
+ className = className + ' ui-state-disabled';
2989
+ }
2990
+
2991
+ //Stop current animation (if does exists) and begin 'deleting' animation.
2992
+ $rows.stop(true, true).addClass(className, 'slow', '').promise().done(function () {
2993
+ self._removeRowsFromTable($rows, 'deleted');
2994
+ });
2995
+ } else {
2996
+ self._removeRowsFromTable($rows, 'deleted');
2997
+ }
2998
+ }
2999
+
3000
+ });
3001
+
3002
+ })(jQuery);
3003
+
3004
+
3005
+ /************************************************************************
3006
+ * SELECTING extension for jTable *
3007
+ *************************************************************************/
3008
+ (function ($) {
3009
+
3010
+ //Reference to base object members
3011
+ var base = {
3012
+ _create: $.hik.jtable.prototype._create,
3013
+ _addColumnsToHeaderRow: $.hik.jtable.prototype._addColumnsToHeaderRow,
3014
+ _addCellsToRowUsingRecord: $.hik.jtable.prototype._addCellsToRowUsingRecord,
3015
+ _onLoadingRecords: $.hik.jtable.prototype._onLoadingRecords,
3016
+ _onRecordsLoaded: $.hik.jtable.prototype._onRecordsLoaded,
3017
+ _onRowsRemoved: $.hik.jtable.prototype._onRowsRemoved
3018
+ };
3019
+
3020
+ //extension members
3021
+ $.extend(true, $.hik.jtable.prototype, {
3022
+
3023
+ /************************************************************************
3024
+ * DEFAULT OPTIONS / EVENTS *
3025
+ *************************************************************************/
3026
+ options: {
3027
+
3028
+ //Options
3029
+ selecting: false,
3030
+ multiselect: false,
3031
+ selectingCheckboxes: false,
3032
+ selectOnRowClick: true,
3033
+
3034
+ //Events
3035
+ selectionChanged: function (event, data) { }
3036
+ },
3037
+
3038
+ /************************************************************************
3039
+ * PRIVATE FIELDS *
3040
+ *************************************************************************/
3041
+
3042
+ _selectedRecordIdsBeforeLoad: null, //This array is used to store selected row Id's to restore them after a page refresh (string array).
3043
+ _$selectAllCheckbox: null, //Reference to the 'select/deselect all' checkbox (jQuery object)
3044
+ _shiftKeyDown: false, //True, if shift key is currently down.
3045
+
3046
+ /************************************************************************
3047
+ * CONSTRUCTOR *
3048
+ *************************************************************************/
3049
+
3050
+ /* Overrides base method to do selecting-specific constructions.
3051
+ *************************************************************************/
3052
+ _create: function () {
3053
+ if (this.options.selecting && this.options.selectingCheckboxes) {
3054
+ ++this._firstDataColumnOffset;
3055
+ this._bindKeyboardEvents();
3056
+ }
3057
+
3058
+ //Call base method
3059
+ base._create.apply(this, arguments);
3060
+ },
3061
+
3062
+ /* Registers to keyboard events those are needed for selection
3063
+ *************************************************************************/
3064
+ _bindKeyboardEvents: function () {
3065
+ var self = this;
3066
+ //Register to events to set _shiftKeyDown value
3067
+ $(document)
3068
+ .keydown(function (event) {
3069
+ switch (event.which) {
3070
+ case 16:
3071
+ self._shiftKeyDown = true;
3072
+ break;
3073
+ }
3074
+ })
3075
+ .keyup(function (event) {
3076
+ switch (event.which) {
3077
+ case 16:
3078
+ self._shiftKeyDown = false;
3079
+ break;
3080
+ }
3081
+ });
3082
+ },
3083
+
3084
+ /************************************************************************
3085
+ * PUBLIC METHODS *
3086
+ *************************************************************************/
3087
+
3088
+ /* Gets jQuery selection for currently selected rows.
3089
+ *************************************************************************/
3090
+ selectedRows: function () {
3091
+ return this._getSelectedRows();
3092
+ },
3093
+
3094
+ /* Makes row/rows 'selected'.
3095
+ *************************************************************************/
3096
+ selectRows: function ($rows) {
3097
+ this._selectRows($rows);
3098
+ this._onSelectionChanged(); //TODO: trigger only if selected rows changes?
3099
+ },
3100
+
3101
+ /************************************************************************
3102
+ * OVERRIDED METHODS *
3103
+ *************************************************************************/
3104
+
3105
+ /* Overrides base method to add a 'select column' to header row.
3106
+ *************************************************************************/
3107
+ _addColumnsToHeaderRow: function ($tr) {
3108
+ if (this.options.selecting && this.options.selectingCheckboxes) {
3109
+ if (this.options.multiselect) {
3110
+ $tr.append(this._createSelectAllHeader());
3111
+ } else {
3112
+ $tr.append(this._createEmptyCommandHeader());
3113
+ }
3114
+ }
3115
+
3116
+ base._addColumnsToHeaderRow.apply(this, arguments);
3117
+ },
3118
+
3119
+ /* Overrides base method to add a 'delete command cell' to a row.
3120
+ *************************************************************************/
3121
+ _addCellsToRowUsingRecord: function ($row) {
3122
+ if (this.options.selecting) {
3123
+ this._makeRowSelectable($row);
3124
+ }
3125
+
3126
+ base._addCellsToRowUsingRecord.apply(this, arguments);
3127
+ },
3128
+
3129
+ /* Overrides base event to store selection list
3130
+ *************************************************************************/
3131
+ _onLoadingRecords: function () {
3132
+ if (this.options.selecting) {
3133
+ this._storeSelectionList();
3134
+ }
3135
+
3136
+ base._onLoadingRecords.apply(this, arguments);
3137
+ },
3138
+
3139
+ /* Overrides base event to restore selection list
3140
+ *************************************************************************/
3141
+ _onRecordsLoaded: function () {
3142
+ if (this.options.selecting) {
3143
+ this._restoreSelectionList();
3144
+ }
3145
+
3146
+ base._onRecordsLoaded.apply(this, arguments);
3147
+ },
3148
+
3149
+ /* Overrides base event to check is any selected row is being removed.
3150
+ *************************************************************************/
3151
+ _onRowsRemoved: function ($rows, reason) {
3152
+ if (this.options.selecting && (reason != 'reloading') && ($rows.filter('.jtable-row-selected').length > 0)) {
3153
+ this._onSelectionChanged();
3154
+ }
3155
+
3156
+ base._onRowsRemoved.apply(this, arguments);
3157
+ },
3158
+
3159
+ /************************************************************************
3160
+ * PRIVATE METHODS *
3161
+ *************************************************************************/
3162
+
3163
+ /* Creates a header column to select/deselect all rows.
3164
+ *************************************************************************/
3165
+ _createSelectAllHeader: function () {
3166
+ var self = this;
3167
+
3168
+ var $columnHeader = $('<th class=""></th>')
3169
+ .addClass('jtable-command-column-header jtable-column-header-selecting');
3170
+ this._jqueryuiThemeAddClass($columnHeader, 'ui-state-default');
3171
+
3172
+ var $headerContainer = $('<div />')
3173
+ .addClass('jtable-column-header-container')
3174
+ .appendTo($columnHeader);
3175
+
3176
+ self._$selectAllCheckbox = $('<input type="checkbox" />')
3177
+ .appendTo($headerContainer)
3178
+ .click(function () {
3179
+ if (self._$tableRows.length <= 0) {
3180
+ self._$selectAllCheckbox.attr('checked', false);
3181
+ return;
3182
+ }
3183
+
3184
+ var allRows = self._$tableBody.find('>tr.jtable-data-row');
3185
+ if (self._$selectAllCheckbox.is(':checked')) {
3186
+ self._selectRows(allRows);
3187
+ } else {
3188
+ self._deselectRows(allRows);
3189
+ }
3190
+
3191
+ self._onSelectionChanged();
3192
+ });
3193
+
3194
+ return $columnHeader;
3195
+ },
3196
+
3197
+ /* Stores Id's of currently selected records to _selectedRecordIdsBeforeLoad.
3198
+ *************************************************************************/
3199
+ _storeSelectionList: function () {
3200
+ var self = this;
3201
+
3202
+ if (!self.options.selecting) {
3203
+ return;
3204
+ }
3205
+
3206
+ self._selectedRecordIdsBeforeLoad = [];
3207
+ self._getSelectedRows().each(function () {
3208
+ self._selectedRecordIdsBeforeLoad.push(self._getKeyValueOfRecord($(this).data('record')));
3209
+ });
3210
+ },
3211
+
3212
+ /* Selects rows whose Id is in _selectedRecordIdsBeforeLoad;
3213
+ *************************************************************************/
3214
+ _restoreSelectionList: function () {
3215
+ var self = this;
3216
+
3217
+ if (!self.options.selecting) {
3218
+ return;
3219
+ }
3220
+
3221
+ var selectedRowCount = 0;
3222
+ for (var i = 0; i < self._$tableRows.length; ++i) {
3223
+ var recordId = self._getKeyValueOfRecord(self._$tableRows[i].data('record'));
3224
+ if ($.inArray(recordId, self._selectedRecordIdsBeforeLoad) > -1) {
3225
+ self._selectRows(self._$tableRows[i]);
3226
+ ++selectedRowCount;
3227
+ }
3228
+ }
3229
+
3230
+ if (self._selectedRecordIdsBeforeLoad.length > 0 && self._selectedRecordIdsBeforeLoad.length != selectedRowCount) {
3231
+ self._onSelectionChanged();
3232
+ }
3233
+
3234
+ self._selectedRecordIdsBeforeLoad = [];
3235
+ self._refreshSelectAllCheckboxState();
3236
+ },
3237
+
3238
+ /* Gets all selected rows.
3239
+ *************************************************************************/
3240
+ _getSelectedRows: function () {
3241
+ return this._$tableBody
3242
+ .find('>tr.jtable-row-selected');
3243
+ },
3244
+
3245
+ /* Adds selectable feature to a row.
3246
+ *************************************************************************/
3247
+ _makeRowSelectable: function ($row) {
3248
+ var self = this;
3249
+
3250
+ //Select/deselect on row click
3251
+ if (self.options.selectOnRowClick) {
3252
+ $row.click(function () {
3253
+ self._invertRowSelection($row);
3254
+ });
3255
+ }
3256
+
3257
+ //'select/deselect' checkbox column
3258
+ if (self.options.selectingCheckboxes) {
3259
+ var $cell = $('<td></td>').addClass('jtable-selecting-column');
3260
+ var $selectCheckbox = $('<input type="checkbox" />').appendTo($cell);
3261
+ if (!self.options.selectOnRowClick) {
3262
+ $selectCheckbox.click(function () {
3263
+ self._invertRowSelection($row);
3264
+ });
3265
+ }
3266
+
3267
+ $row.append($cell);
3268
+ }
3269
+ },
3270
+
3271
+ /* Inverts selection state of a single row.
3272
+ *************************************************************************/
3273
+ _invertRowSelection: function ($row) {
3274
+ if ($row.hasClass('jtable-row-selected')) {
3275
+ this._deselectRows($row);
3276
+ } else {
3277
+ //Shift key?
3278
+ if (this._shiftKeyDown) {
3279
+ var rowIndex = this._findRowIndex($row);
3280
+ //try to select row and above rows until first selected row
3281
+ var beforeIndex = this._findFirstSelectedRowIndexBeforeIndex(rowIndex) + 1;
3282
+ if (beforeIndex > 0 && beforeIndex < rowIndex) {
3283
+ this._selectRows(this._$tableBody.find('tr').slice(beforeIndex, rowIndex + 1));
3284
+ } else {
3285
+ //try to select row and below rows until first selected row
3286
+ var afterIndex = this._findFirstSelectedRowIndexAfterIndex(rowIndex) - 1;
3287
+ if (afterIndex > rowIndex) {
3288
+ this._selectRows(this._$tableBody.find('tr').slice(rowIndex, afterIndex + 1));
3289
+ } else {
3290
+ //just select this row
3291
+ this._selectRows($row);
3292
+ }
3293
+ }
3294
+ } else {
3295
+ this._selectRows($row);
3296
+ }
3297
+ }
3298
+
3299
+ this._onSelectionChanged();
3300
+ },
3301
+
3302
+ /* Search for a selected row (that is before given row index) to up and returns it's index
3303
+ *************************************************************************/
3304
+ _findFirstSelectedRowIndexBeforeIndex: function (rowIndex) {
3305
+ for (var i = rowIndex - 1; i >= 0; --i) {
3306
+ if (this._$tableRows[i].hasClass('jtable-row-selected')) {
3307
+ return i;
3308
+ }
3309
+ }
3310
+
3311
+ return -1;
3312
+ },
3313
+
3314
+ /* Search for a selected row (that is after given row index) to down and returns it's index
3315
+ *************************************************************************/
3316
+ _findFirstSelectedRowIndexAfterIndex: function (rowIndex) {
3317
+ for (var i = rowIndex + 1; i < this._$tableRows.length; ++i) {
3318
+ if (this._$tableRows[i].hasClass('jtable-row-selected')) {
3319
+ return i;
3320
+ }
3321
+ }
3322
+
3323
+ return -1;
3324
+ },
3325
+
3326
+ /* Makes row/rows 'selected'.
3327
+ *************************************************************************/
3328
+ _selectRows: function ($rows) {
3329
+ if (!this.options.multiselect) {
3330
+ this._deselectRows(this._getSelectedRows());
3331
+ }
3332
+
3333
+ $rows.addClass('jtable-row-selected');
3334
+ this._jqueryuiThemeAddClass($rows, 'ui-state-highlight');
3335
+
3336
+ if (this.options.selectingCheckboxes) {
3337
+ $rows.find('>td.jtable-selecting-column >input').prop('checked', true);
3338
+ }
3339
+
3340
+ this._refreshSelectAllCheckboxState();
3341
+ },
3342
+
3343
+ /* Makes row/rows 'non selected'.
3344
+ *************************************************************************/
3345
+ _deselectRows: function ($rows) {
3346
+ $rows.removeClass('jtable-row-selected ui-state-highlight');
3347
+ if (this.options.selectingCheckboxes) {
3348
+ $rows.find('>td.jtable-selecting-column >input').prop('checked', false);
3349
+ }
3350
+
3351
+ this._refreshSelectAllCheckboxState();
3352
+ },
3353
+
3354
+ /* Updates state of the 'select/deselect' all checkbox according to count of selected rows.
3355
+ *************************************************************************/
3356
+ _refreshSelectAllCheckboxState: function () {
3357
+ if (!this.options.selectingCheckboxes || !this.options.multiselect) {
3358
+ return;
3359
+ }
3360
+
3361
+ var totalRowCount = this._$tableRows.length;
3362
+ var selectedRowCount = this._getSelectedRows().length;
3363
+
3364
+ if (selectedRowCount == 0) {
3365
+ this._$selectAllCheckbox.prop('indeterminate', false);
3366
+ this._$selectAllCheckbox.attr('checked', false);
3367
+ } else if (selectedRowCount == totalRowCount) {
3368
+ this._$selectAllCheckbox.prop('indeterminate', false);
3369
+ this._$selectAllCheckbox.attr('checked', true);
3370
+ } else {
3371
+ this._$selectAllCheckbox.attr('checked', false);
3372
+ this._$selectAllCheckbox.prop('indeterminate', true);
3373
+ }
3374
+ },
3375
+
3376
+ /************************************************************************
3377
+ * EVENT RAISING METHODS *
3378
+ *************************************************************************/
3379
+
3380
+ _onSelectionChanged: function () {
3381
+ this._trigger("selectionChanged", null, {});
3382
+ }
3383
+
3384
+ });
3385
+
3386
+ })(jQuery);
3387
+
3388
+
3389
+ /************************************************************************
3390
+ * PAGING extension for jTable *
3391
+ *************************************************************************/
3392
+ (function ($) {
3393
+
3394
+ //Reference to base object members
3395
+ var base = {
3396
+ load: $.hik.jtable.prototype.load,
3397
+ _create: $.hik.jtable.prototype._create,
3398
+ _setOption: $.hik.jtable.prototype._setOption,
3399
+ _createRecordLoadUrl: $.hik.jtable.prototype._createRecordLoadUrl,
3400
+ _addRowToTable: $.hik.jtable.prototype._addRowToTable,
3401
+ _addRow: $.hik.jtable.prototype._addRow,
3402
+ _removeRowsFromTable: $.hik.jtable.prototype._removeRowsFromTable,
3403
+ _onRecordsLoaded: $.hik.jtable.prototype._onRecordsLoaded
3404
+ };
3405
+
3406
+ //extension members
3407
+ $.extend(true, $.hik.jtable.prototype, {
3408
+
3409
+ /************************************************************************
3410
+ * DEFAULT OPTIONS / EVENTS *
3411
+ *************************************************************************/
3412
+ options: {
3413
+ paging: false,
3414
+ pageList: 'normal', //possible values: 'minimal', 'normal'
3415
+ pageSize: 10,
3416
+ pageSizes: [10, 25, 50, 100, 250, 500],
3417
+ pageSizeChangeArea: true,
3418
+ gotoPageArea: 'combobox', //possible values: 'textbox', 'combobox', 'none'
3419
+
3420
+ messages: {
3421
+ pagingInfo: 'Showing {0}-{1} of {2}',
3422
+ pageSizeChangeLabel: 'Row count',
3423
+ gotoPageLabel: 'Go to page'
3424
+ }
3425
+ },
3426
+
3427
+ /************************************************************************
3428
+ * PRIVATE FIELDS *
3429
+ *************************************************************************/
3430
+
3431
+ _$bottomPanel: null, //Reference to the panel at the bottom of the table (jQuery object)
3432
+ _$pagingListArea: null, //Reference to the page list area in to bottom panel (jQuery object)
3433
+ _$pageSizeChangeArea: null, //Reference to the page size change area in to bottom panel (jQuery object)
3434
+ _$pageInfoSpan: null, //Reference to the paging info area in to bottom panel (jQuery object)
3435
+ _$gotoPageArea: null, //Reference to 'Go to page' input area in to bottom panel (jQuery object)
3436
+ _$gotoPageInput: null, //Reference to 'Go to page' input in to bottom panel (jQuery object)
3437
+ _totalRecordCount: 0, //Total count of records on all pages
3438
+ _currentPageNo: 1, //Current page number
3439
+
3440
+ /************************************************************************
3441
+ * CONSTRUCTOR AND INITIALIZING METHODS *
3442
+ *************************************************************************/
3443
+
3444
+ /* Overrides base method to do paging-specific constructions.
3445
+ *************************************************************************/
3446
+ _create: function () {
3447
+ base._create.apply(this, arguments);
3448
+ if (this.options.paging) {
3449
+ this._loadPagingSettings();
3450
+ this._createBottomPanel();
3451
+ this._createPageListArea();
3452
+ this._createGotoPageInput();
3453
+ this._createPageSizeSelection();
3454
+ }
3455
+ },
3456
+
3457
+ /* Loads user preferences for paging.
3458
+ *************************************************************************/
3459
+ _loadPagingSettings: function () {
3460
+ if (!this.options.saveUserPreferences) {
3461
+ return;
3462
+ }
3463
+
3464
+ var pageSize = this._getCookie('page-size');
3465
+ if (pageSize) {
3466
+ this.options.pageSize = this._normalizeNumber(pageSize, 1, 1000000, this.options.pageSize);
3467
+ }
3468
+ },
3469
+
3470
+ /* Creates bottom panel and adds to the page.
3471
+ *************************************************************************/
3472
+ _createBottomPanel: function () {
3473
+ this._$bottomPanel = $('<div />')
3474
+ .addClass('jtable-bottom-panel')
3475
+ .insertAfter(this._$table);
3476
+
3477
+ this._jqueryuiThemeAddClass(this._$bottomPanel, 'ui-state-default');
3478
+
3479
+ $('<div />').addClass('jtable-left-area').appendTo(this._$bottomPanel);
3480
+ $('<div />').addClass('jtable-right-area').appendTo(this._$bottomPanel);
3481
+ },
3482
+
3483
+ /* Creates page list area.
3484
+ *************************************************************************/
3485
+ _createPageListArea: function () {
3486
+ this._$pagingListArea = $('<span></span>')
3487
+ .addClass('jtable-page-list')
3488
+ .appendTo(this._$bottomPanel.find('.jtable-left-area'));
3489
+
3490
+ this._$pageInfoSpan = $('<span></span>')
3491
+ .addClass('jtable-page-info')
3492
+ .appendTo(this._$bottomPanel.find('.jtable-right-area'));
3493
+ },
3494
+
3495
+ /* Creates page list change area.
3496
+ *************************************************************************/
3497
+ _createPageSizeSelection: function () {
3498
+ var self = this;
3499
+
3500
+ if (!self.options.pageSizeChangeArea) {
3501
+ return;
3502
+ }
3503
+
3504
+ //Add current page size to page sizes list if not contains it
3505
+ if (self._findIndexInArray(self.options.pageSize, self.options.pageSizes) < 0) {
3506
+ self.options.pageSizes.push(parseInt(self.options.pageSize));
3507
+ self.options.pageSizes.sort(function (a, b) { return a - b; });
3508
+ }
3509
+
3510
+ //Add a span to contain page size change items
3511
+ self._$pageSizeChangeArea = $('<span></span>')
3512
+ .addClass('jtable-page-size-change')
3513
+ .appendTo(self._$bottomPanel.find('.jtable-left-area'));
3514
+
3515
+ //Page size label
3516
+ self._$pageSizeChangeArea.append('<span>' + self.options.messages.pageSizeChangeLabel + ': </span>');
3517
+
3518
+ //Page size change combobox
3519
+ var $pageSizeChangeCombobox = $('<select></select>').appendTo(self._$pageSizeChangeArea);
3520
+
3521
+ //Add page sizes to the combobox
3522
+ for (var i = 0; i < self.options.pageSizes.length; i++) {
3523
+ $pageSizeChangeCombobox.append('<option value="' + self.options.pageSizes[i] + '">' + self.options.pageSizes[i] + '</option>');
3524
+ }
3525
+
3526
+ //Select current page size
3527
+ $pageSizeChangeCombobox.val(self.options.pageSize);
3528
+
3529
+ //Change page size on combobox change
3530
+ $pageSizeChangeCombobox.change(function () {
3531
+ self._changePageSize(parseInt($(this).val()));
3532
+ });
3533
+ },
3534
+
3535
+ /* Creates go to page area.
3536
+ *************************************************************************/
3537
+ _createGotoPageInput: function () {
3538
+ var self = this;
3539
+
3540
+ if (!self.options.gotoPageArea || self.options.gotoPageArea == 'none') {
3541
+ return;
3542
+ }
3543
+
3544
+ //Add a span to contain goto page items
3545
+ this._$gotoPageArea = $('<span></span>')
3546
+ .addClass('jtable-goto-page')
3547
+ .appendTo(self._$bottomPanel.find('.jtable-left-area'));
3548
+
3549
+ //Goto page label
3550
+ this._$gotoPageArea.append('<span>' + self.options.messages.gotoPageLabel + ': </span>');
3551
+
3552
+ //Goto page input
3553
+ if (self.options.gotoPageArea == 'combobox') {
3554
+
3555
+ self._$gotoPageInput = $('<select></select>')
3556
+ .appendTo(this._$gotoPageArea)
3557
+ .data('pageCount', 1)
3558
+ .change(function () {
3559
+ self._changePage(parseInt($(this).val()));
3560
+ });
3561
+ self._$gotoPageInput.append('<option value="1">1</option>');
3562
+
3563
+ } else { //textbox
3564
+
3565
+ self._$gotoPageInput = $('<input type="text" maxlength="10" value="' + self._currentPageNo + '" />')
3566
+ .appendTo(this._$gotoPageArea)
3567
+ .keypress(function (event) {
3568
+ if (event.which == 13) { //enter
3569
+ event.preventDefault();
3570
+ self._changePage(parseInt(self._$gotoPageInput.val()));
3571
+ } else if (event.which == 43) { // +
3572
+ event.preventDefault();
3573
+ self._changePage(parseInt(self._$gotoPageInput.val()) + 1);
3574
+ } else if (event.which == 45) { // -
3575
+ event.preventDefault();
3576
+ self._changePage(parseInt(self._$gotoPageInput.val()) - 1);
3577
+ } else {
3578
+ //Allow only digits
3579
+ var isValid = (
3580
+ (47 < event.keyCode && event.keyCode < 58 && event.shiftKey == false && event.altKey == false)
3581
+ || (event.keyCode == 8)
3582
+ || (event.keyCode == 9)
3583
+ );
3584
+
3585
+ if (!isValid) {
3586
+ event.preventDefault();
3587
+ }
3588
+ }
3589
+ });
3590
+
3591
+ }
3592
+ },
3593
+
3594
+ /* Refreshes the 'go to page' input.
3595
+ *************************************************************************/
3596
+ _refreshGotoPageInput: function () {
3597
+ if (!this.options.gotoPageArea || this.options.gotoPageArea == 'none') {
3598
+ return;
3599
+ }
3600
+
3601
+ if (this._totalRecordCount <= 0) {
3602
+ this._$gotoPageArea.hide();
3603
+ } else {
3604
+ this._$gotoPageArea.show();
3605
+ }
3606
+
3607
+ if (this.options.gotoPageArea == 'combobox') {
3608
+ var oldPageCount = this._$gotoPageInput.data('pageCount');
3609
+ var currentPageCount = this._calculatePageCount();
3610
+ if (oldPageCount != currentPageCount) {
3611
+ this._$gotoPageInput.empty();
3612
+
3613
+ //Skip some pages is there are too many pages
3614
+ var pageStep = 1;
3615
+ if (currentPageCount > 10000) {
3616
+ pageStep = 100;
3617
+ } else if (currentPageCount > 5000) {
3618
+ pageStep = 10;
3619
+ } else if (currentPageCount > 2000) {
3620
+ pageStep = 5;
3621
+ } else if (currentPageCount > 1000) {
3622
+ pageStep = 2;
3623
+ }
3624
+
3625
+ for (var i = pageStep; i <= currentPageCount; i += pageStep) {
3626
+ this._$gotoPageInput.append('<option value="' + i + '">' + i + '</option>');
3627
+ }
3628
+
3629
+ this._$gotoPageInput.data('pageCount', currentPageCount);
3630
+ }
3631
+ }
3632
+
3633
+ //same for 'textbox' and 'combobox'
3634
+ this._$gotoPageInput.val(this._currentPageNo);
3635
+ },
3636
+
3637
+ /************************************************************************
3638
+ * OVERRIDED METHODS *
3639
+ *************************************************************************/
3640
+
3641
+ /* Overrides load method to set current page to 1.
3642
+ *************************************************************************/
3643
+ load: function () {
3644
+ this._currentPageNo = 1;
3645
+
3646
+ base.load.apply(this, arguments);
3647
+ },
3648
+
3649
+ /* Used to change options dynamically after initialization.
3650
+ *************************************************************************/
3651
+ _setOption: function (key, value) {
3652
+ base._setOption.apply(this, arguments);
3653
+
3654
+ if (key == 'pageSize') {
3655
+ this._changePageSize(parseInt(value));
3656
+ }
3657
+ },
3658
+
3659
+ /* Changes current page size with given value.
3660
+ *************************************************************************/
3661
+ _changePageSize: function (pageSize) {
3662
+ if (pageSize == this.options.pageSize) {
3663
+ return;
3664
+ }
3665
+
3666
+ this.options.pageSize = pageSize;
3667
+
3668
+ //Normalize current page
3669
+ var pageCount = this._calculatePageCount();
3670
+ if (this._currentPageNo > pageCount) {
3671
+ this._currentPageNo = pageCount;
3672
+ }
3673
+ if (this._currentPageNo <= 0) {
3674
+ this._currentPageNo = 1;
3675
+ }
3676
+
3677
+ //if user sets one of the options on the combobox, then select it.
3678
+ var $pageSizeChangeCombobox = this._$bottomPanel.find('.jtable-page-size-change select');
3679
+ if ($pageSizeChangeCombobox.length > 0) {
3680
+ if (parseInt($pageSizeChangeCombobox.val()) != pageSize) {
3681
+ var selectedOption = $pageSizeChangeCombobox.find('option[value=' + pageSize + ']');
3682
+ if (selectedOption.length > 0) {
3683
+ $pageSizeChangeCombobox.val(pageSize);
3684
+ }
3685
+ }
3686
+ }
3687
+
3688
+ this._savePagingSettings();
3689
+ this._reloadTable();
3690
+ },
3691
+
3692
+ /* Saves user preferences for paging
3693
+ *************************************************************************/
3694
+ _savePagingSettings: function () {
3695
+ if (!this.options.saveUserPreferences) {
3696
+ return;
3697
+ }
3698
+
3699
+ this._setCookie('page-size', this.options.pageSize);
3700
+ },
3701
+
3702
+ /* Overrides _createRecordLoadUrl method to add paging info to URL.
3703
+ *************************************************************************/
3704
+ _createRecordLoadUrl: function () {
3705
+ var loadUrl = base._createRecordLoadUrl.apply(this, arguments);
3706
+ loadUrl = this._addPagingInfoToUrl(loadUrl, this._currentPageNo);
3707
+ return loadUrl;
3708
+ },
3709
+
3710
+ /* Overrides _addRowToTable method to re-load table when a new row is created.
3711
+ * NOTE: THIS METHOD IS DEPRECATED AND WILL BE REMOVED FROM FEATURE RELEASES.
3712
+ * USE _addRow METHOD.
3713
+ *************************************************************************/
3714
+ _addRowToTable: function ($tableRow, index, isNewRow) {
3715
+ if (isNewRow && this.options.paging) {
3716
+ this._reloadTable();
3717
+ return;
3718
+ }
3719
+
3720
+ base._addRowToTable.apply(this, arguments);
3721
+ },
3722
+
3723
+ /* Overrides _addRow method to re-load table when a new row is created.
3724
+ *************************************************************************/
3725
+ _addRow: function ($row, options) {
3726
+ if (options && options.isNewRow && this.options.paging) {
3727
+ this._reloadTable();
3728
+ return;
3729
+ }
3730
+
3731
+ base._addRow.apply(this, arguments);
3732
+ },
3733
+
3734
+ /* Overrides _removeRowsFromTable method to re-load table when a row is removed from table.
3735
+ *************************************************************************/
3736
+ _removeRowsFromTable: function ($rows, reason) {
3737
+ base._removeRowsFromTable.apply(this, arguments);
3738
+
3739
+ if (this.options.paging) {
3740
+ if (this._$tableRows.length <= 0 && this._currentPageNo > 1) {
3741
+ --this._currentPageNo;
3742
+ }
3743
+
3744
+ this._reloadTable();
3745
+ }
3746
+ },
3747
+
3748
+ /* Overrides _onRecordsLoaded method to to do paging specific tasks.
3749
+ *************************************************************************/
3750
+ _onRecordsLoaded: function (data) {
3751
+ if (this.options.paging) {
3752
+ this._totalRecordCount = data.TotalRecordCount;
3753
+ this._createPagingList();
3754
+ this._createPagingInfo();
3755
+ this._refreshGotoPageInput();
3756
+ }
3757
+
3758
+ base._onRecordsLoaded.apply(this, arguments);
3759
+ },
3760
+
3761
+ /************************************************************************
3762
+ * PRIVATE METHODS *
3763
+ *************************************************************************/
3764
+
3765
+ /* Adds jtStartIndex and jtPageSize parameters to a URL as query string.
3766
+ *************************************************************************/
3767
+ _addPagingInfoToUrl: function (url, pageNumber) {
3768
+ if (!this.options.paging) {
3769
+ return url;
3770
+ }
3771
+
3772
+ var jtStartIndex = (pageNumber - 1) * this.options.pageSize;
3773
+ var jtPageSize = this.options.pageSize;
3774
+
3775
+ return (url + (url.indexOf('?') < 0 ? '?' : '&') + 'jtStartIndex=' + jtStartIndex + '&jtPageSize=' + jtPageSize);
3776
+ },
3777
+
3778
+ /* Creates and shows the page list.
3779
+ *************************************************************************/
3780
+ _createPagingList: function () {
3781
+ if (this.options.pageSize <= 0) {
3782
+ return;
3783
+ }
3784
+
3785
+ this._$pagingListArea.empty();
3786
+ if (this._totalRecordCount <= 0) {
3787
+ return;
3788
+ }
3789
+
3790
+ var pageCount = this._calculatePageCount();
3791
+
3792
+ this._createFirstAndPreviousPageButtons();
3793
+ if (this.options.pageList == 'normal') {
3794
+ this._createPageNumberButtons(this._calculatePageNumbers(pageCount));
3795
+ }
3796
+ this._createLastAndNextPageButtons(pageCount);
3797
+ this._bindClickEventsToPageNumberButtons();
3798
+ },
3799
+
3800
+ /* Creates and shows previous and first page links.
3801
+ *************************************************************************/
3802
+ _createFirstAndPreviousPageButtons: function () {
3803
+ var $first = $('<span></span>')
3804
+ .addClass('jtable-page-number-first')
3805
+ .html('&lt&lt')
3806
+ .data('pageNumber', 1)
3807
+ .appendTo(this._$pagingListArea);
3808
+
3809
+ var $previous = $('<span></span>')
3810
+ .addClass('jtable-page-number-previous')
3811
+ .html('&lt')
3812
+ .data('pageNumber', this._currentPageNo - 1)
3813
+ .appendTo(this._$pagingListArea);
3814
+
3815
+ this._jqueryuiThemeAddClass($first, 'ui-button ui-state-default', 'ui-state-hover');
3816
+ this._jqueryuiThemeAddClass($previous, 'ui-button ui-state-default', 'ui-state-hover');
3817
+
3818
+ if (this._currentPageNo <= 1) {
3819
+ $first.addClass('jtable-page-number-disabled');
3820
+ $previous.addClass('jtable-page-number-disabled');
3821
+ this._jqueryuiThemeAddClass($first, 'ui-state-disabled');
3822
+ this._jqueryuiThemeAddClass($previous, 'ui-state-disabled');
3823
+ }
3824
+ },
3825
+
3826
+ /* Creates and shows next and last page links.
3827
+ *************************************************************************/
3828
+ _createLastAndNextPageButtons: function (pageCount) {
3829
+ var $next = $('<span></span>')
3830
+ .addClass('jtable-page-number-next')
3831
+ .html('&gt')
3832
+ .data('pageNumber', this._currentPageNo + 1)
3833
+ .appendTo(this._$pagingListArea);
3834
+ var $last = $('<span></span>')
3835
+ .addClass('jtable-page-number-last')
3836
+ .html('&gt&gt')
3837
+ .data('pageNumber', pageCount)
3838
+ .appendTo(this._$pagingListArea);
3839
+
3840
+ this._jqueryuiThemeAddClass($next, 'ui-button ui-state-default', 'ui-state-hover');
3841
+ this._jqueryuiThemeAddClass($last, 'ui-button ui-state-default', 'ui-state-hover');
3842
+
3843
+ if (this._currentPageNo >= pageCount) {
3844
+ $next.addClass('jtable-page-number-disabled');
3845
+ $last.addClass('jtable-page-number-disabled');
3846
+ this._jqueryuiThemeAddClass($next, 'ui-state-disabled');
3847
+ this._jqueryuiThemeAddClass($last, 'ui-state-disabled');
3848
+ }
3849
+ },
3850
+
3851
+ /* Creates and shows page number links for given number array.
3852
+ *************************************************************************/
3853
+ _createPageNumberButtons: function (pageNumbers) {
3854
+ var previousNumber = 0;
3855
+ for (var i = 0; i < pageNumbers.length; i++) {
3856
+ //Create "..." between page numbers if needed
3857
+ if ((pageNumbers[i] - previousNumber) > 1) {
3858
+ $('<span></span>')
3859
+ .addClass('jtable-page-number-space')
3860
+ .html('...')
3861
+ .appendTo(this._$pagingListArea);
3862
+ }
3863
+
3864
+ this._createPageNumberButton(pageNumbers[i]);
3865
+ previousNumber = pageNumbers[i];
3866
+ }
3867
+ },
3868
+
3869
+ /* Creates a page number link and adds to paging area.
3870
+ *************************************************************************/
3871
+ _createPageNumberButton: function (pageNumber) {
3872
+ var $pageNumber = $('<span></span>')
3873
+ .addClass('jtable-page-number')
3874
+ .html(pageNumber)
3875
+ .data('pageNumber', pageNumber)
3876
+ .appendTo(this._$pagingListArea);
3877
+
3878
+ this._jqueryuiThemeAddClass($pageNumber, 'ui-button ui-state-default', 'ui-state-hover');
3879
+
3880
+ if (this._currentPageNo == pageNumber) {
3881
+ $pageNumber.addClass('jtable-page-number-active jtable-page-number-disabled');
3882
+ this._jqueryuiThemeAddClass($pageNumber, 'ui-state-active');
3883
+ }
3884
+ },
3885
+
3886
+ /* Calculates total page count according to page size and total record count.
3887
+ *************************************************************************/
3888
+ _calculatePageCount: function () {
3889
+ var pageCount = Math.floor(this._totalRecordCount / this.options.pageSize);
3890
+ if (this._totalRecordCount % this.options.pageSize != 0) {
3891
+ ++pageCount;
3892
+ }
3893
+
3894
+ return pageCount;
3895
+ },
3896
+
3897
+ /* Calculates page numbers and returns an array of these numbers.
3898
+ *************************************************************************/
3899
+ _calculatePageNumbers: function (pageCount) {
3900
+ if (pageCount <= 4) {
3901
+ //Show all pages
3902
+ var pageNumbers = [];
3903
+ for (var i = 1; i <= pageCount; ++i) {
3904
+ pageNumbers.push(i);
3905
+ }
3906
+
3907
+ return pageNumbers;
3908
+ } else {
3909
+ //show first three, last three, current, previous and next page numbers
3910
+ var shownPageNumbers = [1, 2, pageCount - 1, pageCount];
3911
+ var previousPageNo = this._normalizeNumber(this._currentPageNo - 1, 1, pageCount, 1);
3912
+ var nextPageNo = this._normalizeNumber(this._currentPageNo + 1, 1, pageCount, 1);
3913
+
3914
+ this._insertToArrayIfDoesNotExists(shownPageNumbers, previousPageNo);
3915
+ this._insertToArrayIfDoesNotExists(shownPageNumbers, this._currentPageNo);
3916
+ this._insertToArrayIfDoesNotExists(shownPageNumbers, nextPageNo);
3917
+
3918
+ shownPageNumbers.sort(function (a, b) { return a - b; });
3919
+ return shownPageNumbers;
3920
+ }
3921
+ },
3922
+
3923
+ /* Creates and shows paging informations.
3924
+ *************************************************************************/
3925
+ _createPagingInfo: function () {
3926
+ if (this._totalRecordCount <= 0) {
3927
+ this._$pageInfoSpan.empty();
3928
+ return;
3929
+ }
3930
+
3931
+ var startNo = (this._currentPageNo - 1) * this.options.pageSize + 1;
3932
+ var endNo = this._currentPageNo * this.options.pageSize;
3933
+ endNo = this._normalizeNumber(endNo, startNo, this._totalRecordCount, 0);
3934
+
3935
+ if (endNo >= startNo) {
3936
+ var pagingInfoMessage = this._formatString(this.options.messages.pagingInfo, startNo, endNo, this._totalRecordCount);
3937
+ this._$pageInfoSpan.html(pagingInfoMessage);
3938
+ }
3939
+ },
3940
+
3941
+ /* Binds click events of all page links to change the page.
3942
+ *************************************************************************/
3943
+ _bindClickEventsToPageNumberButtons: function () {
3944
+ var self = this;
3945
+ self._$pagingListArea
3946
+ .find('.jtable-page-number,.jtable-page-number-previous,.jtable-page-number-next,.jtable-page-number-first,.jtable-page-number-last')
3947
+ .not('.jtable-page-number-disabled')
3948
+ .click(function (e) {
3949
+ e.preventDefault();
3950
+ self._changePage($(this).data('pageNumber'));
3951
+ });
3952
+ },
3953
+
3954
+ /* Changes current page to given value.
3955
+ *************************************************************************/
3956
+ _changePage: function (pageNo) {
3957
+ pageNo = this._normalizeNumber(pageNo, 1, this._calculatePageCount(), 1);
3958
+ if (pageNo == this._currentPageNo) {
3959
+ this._refreshGotoPageInput();
3960
+ return;
3961
+ }
3962
+
3963
+ this._currentPageNo = pageNo;
3964
+ this._reloadTable();
3965
+ }
3966
+
3967
+ });
3968
+
3969
+ })(jQuery);
3970
+
3971
+
3972
+ /************************************************************************
3973
+ * SORTING extension for jTable *
3974
+ *************************************************************************/
3975
+ (function ($) {
3976
+
3977
+ //Reference to base object members
3978
+ var base = {
3979
+ _initializeFields: $.hik.jtable.prototype._initializeFields,
3980
+ _normalizeFieldOptions: $.hik.jtable.prototype._normalizeFieldOptions,
3981
+ _createHeaderCellForField: $.hik.jtable.prototype._createHeaderCellForField,
3982
+ _createRecordLoadUrl: $.hik.jtable.prototype._createRecordLoadUrl
3983
+ };
3984
+
3985
+ //extension members
3986
+ $.extend(true, $.hik.jtable.prototype, {
3987
+
3988
+ /************************************************************************
3989
+ * DEFAULT OPTIONS / EVENTS *
3990
+ *************************************************************************/
3991
+ options: {
3992
+ sorting: false,
3993
+ multiSorting: false,
3994
+ defaultSorting: ''
3995
+ },
3996
+
3997
+ /************************************************************************
3998
+ * PRIVATE FIELDS *
3999
+ *************************************************************************/
4000
+
4001
+ _lastSorting: null, //Last sorting of the table
4002
+
4003
+ /************************************************************************
4004
+ * OVERRIDED METHODS *
4005
+ *************************************************************************/
4006
+
4007
+ /* Overrides base method to create sorting array.
4008
+ *************************************************************************/
4009
+ _initializeFields: function () {
4010
+ base._initializeFields.apply(this, arguments);
4011
+
4012
+ this._lastSorting = [];
4013
+ if (this.options.sorting) {
4014
+ this._buildDefaultSortingArray();
4015
+ }
4016
+ },
4017
+
4018
+ /* Overrides _normalizeFieldOptions method to normalize sorting option for fields.
4019
+ *************************************************************************/
4020
+ _normalizeFieldOptions: function (fieldName, props) {
4021
+ base._normalizeFieldOptions.apply(this, arguments);
4022
+ props.sorting = (props.sorting != false);
4023
+ },
4024
+
4025
+ /* Overrides _createHeaderCellForField to make columns sortable.
4026
+ *************************************************************************/
4027
+ _createHeaderCellForField: function (fieldName, field) {
4028
+ var $headerCell = base._createHeaderCellForField.apply(this, arguments);
4029
+ if (this.options.sorting && field.sorting) {
4030
+ this._makeColumnSortable($headerCell, fieldName);
4031
+ }
4032
+
4033
+ return $headerCell;
4034
+ },
4035
+
4036
+ /* Overrides _createRecordLoadUrl to add sorting specific info to URL.
4037
+ *************************************************************************/
4038
+ _createRecordLoadUrl: function () {
4039
+ var loadUrl = base._createRecordLoadUrl.apply(this, arguments);
4040
+ loadUrl = this._addSortingInfoToUrl(loadUrl);
4041
+ return loadUrl;
4042
+ },
4043
+
4044
+ /************************************************************************
4045
+ * PRIVATE METHODS *
4046
+ *************************************************************************/
4047
+
4048
+ /* Builds the sorting array according to defaultSorting string
4049
+ *************************************************************************/
4050
+ _buildDefaultSortingArray: function () {
4051
+ var self = this;
4052
+
4053
+ $.each(self.options.defaultSorting.split(","), function (orderIndex, orderValue) {
4054
+ $.each(self.options.fields, function (fieldName, fieldProps) {
4055
+ if (fieldProps.sorting) {
4056
+ var colOffset = orderValue.indexOf(fieldName);
4057
+ if (colOffset > -1) {
4058
+ if (orderValue.toUpperCase().indexOf(' DESC', colOffset) > -1) {
4059
+ self._lastSorting.push({
4060
+ fieldName: fieldName,
4061
+ sortOrder: 'DESC'
4062
+ });
4063
+ } else {
4064
+ self._lastSorting.push({
4065
+ fieldName: fieldName,
4066
+ sortOrder: 'ASC'
4067
+ });
4068
+ }
4069
+ }
4070
+ }
4071
+ });
4072
+ });
4073
+ },
4074
+
4075
+ /* Makes a column sortable.
4076
+ *************************************************************************/
4077
+ _makeColumnSortable: function ($columnHeader, fieldName) {
4078
+ var self = this;
4079
+
4080
+ $columnHeader
4081
+ .addClass('jtable-column-header-sortable')
4082
+ .click(function (e) {
4083
+ e.preventDefault();
4084
+
4085
+ if (!self.options.multiSorting || !e.ctrlKey) {
4086
+ self._lastSorting = []; //clear previous sorting
4087
+ }
4088
+
4089
+ self._sortTableByColumn($columnHeader);
4090
+ });
4091
+
4092
+ //Set default sorting
4093
+ $.each(this._lastSorting, function (sortIndex, sortField) {
4094
+ if (sortField.fieldName == fieldName) {
4095
+ if (sortField.sortOrder == 'DESC') {
4096
+ $columnHeader.addClass('jtable-column-header-sorted-desc');
4097
+ } else {
4098
+ $columnHeader.addClass('jtable-column-header-sorted-asc');
4099
+ }
4100
+ }
4101
+ });
4102
+ },
4103
+
4104
+ /* Sorts table according to a column header.
4105
+ *************************************************************************/
4106
+ _sortTableByColumn: function ($columnHeader) {
4107
+ //Remove sorting styles from all columns except this one
4108
+ if (this._lastSorting.length == 0) {
4109
+ $columnHeader.siblings().removeClass('jtable-column-header-sorted-asc jtable-column-header-sorted-desc');
4110
+ }
4111
+
4112
+ //If current sorting list includes this column, remove it from the list
4113
+ for (var i = 0; i < this._lastSorting.length; i++) {
4114
+ if (this._lastSorting[i].fieldName == $columnHeader.data('fieldName')) {
4115
+ this._lastSorting.splice(i--, 1);
4116
+ }
4117
+ }
4118
+
4119
+ //Sort ASC or DESC according to current sorting state
4120
+ if ($columnHeader.hasClass('jtable-column-header-sorted-asc')) {
4121
+ $columnHeader.removeClass('jtable-column-header-sorted-asc').addClass('jtable-column-header-sorted-desc');
4122
+ this._lastSorting.push({
4123
+ 'fieldName': $columnHeader.data('fieldName'),
4124
+ sortOrder: 'DESC'
4125
+ });
4126
+ } else {
4127
+ $columnHeader.removeClass('jtable-column-header-sorted-desc').addClass('jtable-column-header-sorted-asc');
4128
+ this._lastSorting.push({
4129
+ 'fieldName': $columnHeader.data('fieldName'),
4130
+ sortOrder: 'ASC'
4131
+ });
4132
+ }
4133
+
4134
+ //Load current page again
4135
+ this._reloadTable();
4136
+ },
4137
+
4138
+ /* Adds jtSorting parameter to a URL as query string.
4139
+ *************************************************************************/
4140
+ _addSortingInfoToUrl: function (url) {
4141
+ if (!this.options.sorting || this._lastSorting.length == 0) {
4142
+ return url;
4143
+ }
4144
+
4145
+ var sorting = [];
4146
+ $.each(this._lastSorting, function (idx, value) {
4147
+ sorting.push(value.fieldName + ' ' + value.sortOrder);
4148
+ });
4149
+
4150
+ return (url + (url.indexOf('?') < 0 ? '?' : '&') + 'jtSorting=' + sorting.join(","));
4151
+ }
4152
+
4153
+ });
4154
+
4155
+ })(jQuery);
4156
+
4157
+ /************************************************************************
4158
+ * DYNAMIC COLUMNS extension for jTable *
4159
+ * (Show/hide/resize columns) *
4160
+ *************************************************************************/
4161
+ (function ($) {
4162
+
4163
+ //Reference to base object members
4164
+ var base = {
4165
+ _create: $.hik.jtable.prototype._create,
4166
+ _normalizeFieldOptions: $.hik.jtable.prototype._normalizeFieldOptions,
4167
+ _createHeaderCellForField: $.hik.jtable.prototype._createHeaderCellForField,
4168
+ _createCellForRecordField: $.hik.jtable.prototype._createCellForRecordField
4169
+ };
4170
+
4171
+ //extension members
4172
+ $.extend(true, $.hik.jtable.prototype, {
4173
+
4174
+ /************************************************************************
4175
+ * DEFAULT OPTIONS / EVENTS *
4176
+ *************************************************************************/
4177
+
4178
+ options: {
4179
+ tableId: undefined,
4180
+ columnResizable: true,
4181
+ columnSelectable: true
4182
+ },
4183
+
4184
+ /************************************************************************
4185
+ * PRIVATE FIELDS *
4186
+ *************************************************************************/
4187
+
4188
+ _$columnSelectionDiv: null,
4189
+ _$columnResizeBar: null,
4190
+ _cookieKeyPrefix: null,
4191
+ _currentResizeArgs: null,
4192
+
4193
+ /************************************************************************
4194
+ * OVERRIDED METHODS *
4195
+ *************************************************************************/
4196
+
4197
+ /* Overrides _addRowToTableHead method.
4198
+ *************************************************************************/
4199
+
4200
+ _create: function () {
4201
+ base._create.apply(this, arguments);
4202
+
4203
+ this._createColumnResizeBar();
4204
+ this._createColumnSelection();
4205
+
4206
+ if (this.options.saveUserPreferences) {
4207
+ this._loadColumnSettings();
4208
+ }
4209
+
4210
+ this._normalizeColumnWidths();
4211
+ },
4212
+
4213
+ /* Normalizes some options for a field (sets default values).
4214
+ *************************************************************************/
4215
+ _normalizeFieldOptions: function (fieldName, props) {
4216
+ base._normalizeFieldOptions.apply(this, arguments);
4217
+
4218
+ //columnResizable
4219
+ if (this.options.columnResizable) {
4220
+ props.columnResizable = (props.columnResizable != false);
4221
+ }
4222
+
4223
+ //visibility
4224
+ if (!props.visibility) {
4225
+ props.visibility = 'visible';
4226
+ }
4227
+ },
4228
+
4229
+ /* Overrides _createHeaderCellForField to make columns dynamic.
4230
+ *************************************************************************/
4231
+ _createHeaderCellForField: function (fieldName, field) {
4232
+ var $headerCell = base._createHeaderCellForField.apply(this, arguments);
4233
+
4234
+ //Make data columns resizable except the last one
4235
+ if (this.options.columnResizable && field.columnResizable && (fieldName != this._columnList[this._columnList.length - 1])) {
4236
+ this._makeColumnResizable($headerCell);
4237
+ }
4238
+
4239
+ //Hide column if needed
4240
+ if (field.visibility == 'hidden') {
4241
+ $headerCell.hide();
4242
+ }
4243
+
4244
+ return $headerCell;
4245
+ },
4246
+
4247
+ /* Overrides _createHeaderCellForField to decide show or hide a column.
4248
+ *************************************************************************/
4249
+ _createCellForRecordField: function (record, fieldName) {
4250
+ var $column = base._createCellForRecordField.apply(this, arguments);
4251
+
4252
+ var field = this.options.fields[fieldName];
4253
+ if (field.visibility == 'hidden') {
4254
+ $column.hide();
4255
+ }
4256
+
4257
+ return $column;
4258
+ },
4259
+
4260
+ /************************************************************************
4261
+ * PUBLIC METHODS *
4262
+ *************************************************************************/
4263
+
4264
+ /* Changes visibility of a column.
4265
+ *************************************************************************/
4266
+ changeColumnVisibility: function (columnName, visibility) {
4267
+ this._changeColumnVisibilityInternal(columnName, visibility);
4268
+ this._normalizeColumnWidths();
4269
+ if (this.options.saveUserPreferences) {
4270
+ this._saveColumnSettings();
4271
+ }
4272
+ },
4273
+
4274
+ /************************************************************************
4275
+ * PRIVATE METHODS *
4276
+ *************************************************************************/
4277
+
4278
+ /* Changes visibility of a column.
4279
+ *************************************************************************/
4280
+ _changeColumnVisibilityInternal: function (columnName, visibility) {
4281
+ //Check if there is a column with given name
4282
+ var columnIndex = this._columnList.indexOf(columnName);
4283
+ if (columnIndex < 0) {
4284
+ this._logWarn('Column "' + columnName + '" does not exist in fields!');
4285
+ return;
4286
+ }
4287
+
4288
+ //Check if visibility value is valid
4289
+ if (['visible', 'hidden', 'fixed'].indexOf(visibility) < 0) {
4290
+ this._logWarn('Visibility value is not valid: "' + visibility + '"! Options are: visible, hidden, fixed.');
4291
+ return;
4292
+ }
4293
+
4294
+ //Get the field
4295
+ var field = this.options.fields[columnName];
4296
+ if (field.visibility == visibility) {
4297
+ return; //No action if new value is same as old one.
4298
+ }
4299
+
4300
+ //Hide or show the column if needed
4301
+ var columnIndexInTable = this._firstDataColumnOffset + columnIndex + 1;
4302
+ if (field.visibility != 'hidden' && visibility == 'hidden') {
4303
+ this._$table
4304
+ .find('>thead >tr >th:nth-child(' + columnIndexInTable + '),>tbody >tr >td:nth-child(' + columnIndexInTable + ')')
4305
+ .hide();
4306
+ } else if (field.visibility == 'hidden' && visibility != 'hidden') {
4307
+ this._$table
4308
+ .find('>thead >tr >th:nth-child(' + columnIndexInTable + '),>tbody >tr >td:nth-child(' + columnIndexInTable + ')')
4309
+ .show()
4310
+ .css('display', 'table-cell');
4311
+ }
4312
+
4313
+ field.visibility = visibility;
4314
+ },
4315
+
4316
+ /* Prepares dialog to change settings.
4317
+ *************************************************************************/
4318
+ _createColumnSelection: function () {
4319
+ var self = this;
4320
+
4321
+ //Create a div for dialog and add to container element
4322
+ this._$columnSelectionDiv = $('<div />')
4323
+ .addClass('jtable-column-selection-container')
4324
+ .appendTo(self._$mainContainer);
4325
+
4326
+ this._$table.children('thead').bind('contextmenu', function (e) {
4327
+ if (!self.options.columnSelectable) {
4328
+ return;
4329
+ }
4330
+
4331
+ e.preventDefault();
4332
+
4333
+ //Make an overlay div to disable page clicks
4334
+ $('<div />')
4335
+ .addClass('jtable-contextmenu-overlay')
4336
+ .click(function () {
4337
+ $(this).remove();
4338
+ self._$columnSelectionDiv.hide();
4339
+ })
4340
+ .bind('contextmenu', function () { return false; })
4341
+ .appendTo(document.body);
4342
+
4343
+ self._fillColumnSelection();
4344
+
4345
+ //Calculate position of column selection list and show it
4346
+
4347
+ var containerOffset = self._$mainContainer.offset();
4348
+ var selectionDivTop = e.pageY - containerOffset.top;
4349
+ var selectionDivLeft = e.pageX - containerOffset.left;
4350
+
4351
+ var selectionDivMinWidth = 100; //in pixels
4352
+ var containerWidth = self._$mainContainer.width();
4353
+
4354
+ //If user clicks right area of header of the table, show list at a little left
4355
+ if ((containerWidth > selectionDivMinWidth) && (selectionDivLeft > (containerWidth - selectionDivMinWidth))) {
4356
+ selectionDivLeft = containerWidth - selectionDivMinWidth;
4357
+ }
4358
+
4359
+ self._$columnSelectionDiv.css({
4360
+ left: selectionDivLeft,
4361
+ top: selectionDivTop,
4362
+ 'min-width': selectionDivMinWidth + 'px'
4363
+ }).show();
4364
+ });
4365
+ },
4366
+
4367
+ /* Prepares content of settings dialog.
4368
+ *************************************************************************/
4369
+ _fillColumnSelection: function () {
4370
+ var self = this;
4371
+
4372
+ var $columnsUl = $('<ul></ul>')
4373
+ .addClass('jtable-column-select-list');
4374
+ for (var i = 0; i < this._columnList.length; i++) {
4375
+ var columnName = this._columnList[i];
4376
+ var field = this.options.fields[columnName];
4377
+
4378
+ //Crete li element
4379
+ var $columnLi = $('<li></li>').appendTo($columnsUl);
4380
+
4381
+ //Create label for the checkbox
4382
+ var $label = $('<label for="' + columnName + '"></label>')
4383
+ .append($('<span>' + (field.title || columnName) + '</span>'))
4384
+ .appendTo($columnLi);
4385
+
4386
+ //Create checkbox
4387
+ var $checkbox = $('<input type="checkbox" name="' + columnName + '">')
4388
+ .prependTo($label)
4389
+ .click(function () {
4390
+ var $clickedCheckbox = $(this);
4391
+ var clickedColumnName = $clickedCheckbox.attr('name');
4392
+ var clickedField = self.options.fields[clickedColumnName];
4393
+ if (clickedField.visibility == 'fixed') {
4394
+ return;
4395
+ }
4396
+
4397
+ self.changeColumnVisibility(clickedColumnName, $clickedCheckbox.is(':checked') ? 'visible' : 'hidden');
4398
+ });
4399
+
4400
+ //Check, if column if shown
4401
+ if (field.visibility != 'hidden') {
4402
+ $checkbox.attr('checked', 'checked');
4403
+ }
4404
+
4405
+ //Disable, if column is fixed
4406
+ if (field.visibility == 'fixed') {
4407
+ $checkbox.attr('disabled', 'disabled');
4408
+ }
4409
+ }
4410
+
4411
+ this._$columnSelectionDiv.html($columnsUl);
4412
+ },
4413
+
4414
+ /* creates a vertical bar that is shown while resizing columns.
4415
+ *************************************************************************/
4416
+ _createColumnResizeBar: function () {
4417
+ this._$columnResizeBar = $('<div />')
4418
+ .addClass('jtable-column-resize-bar')
4419
+ .appendTo(this._$mainContainer)
4420
+ .hide();
4421
+ },
4422
+
4423
+ /* Makes a column sortable.
4424
+ *************************************************************************/
4425
+ _makeColumnResizable: function ($columnHeader) {
4426
+ var self = this;
4427
+
4428
+ //Create a handler to handle mouse click event
4429
+ $('<div />')
4430
+ .addClass('jtable-column-resize-handler')
4431
+ .appendTo($columnHeader.find('.jtable-column-header-container')) //Append the handler to the column
4432
+ .mousedown(function (downevent) { //handle mousedown event for the handler
4433
+ downevent.preventDefault();
4434
+ downevent.stopPropagation();
4435
+
4436
+ var mainContainerOffset = self._$mainContainer.offset();
4437
+
4438
+ //Get a reference to the next column
4439
+ var $nextColumnHeader = $columnHeader.nextAll('th.jtable-column-header:visible:first');
4440
+ if (!$nextColumnHeader.length) {
4441
+ return;
4442
+ }
4443
+
4444
+ //Store some information to be used on resizing
4445
+ var minimumColumnWidth = 10; //A column's width can not be smaller than 10 pixel.
4446
+ self._currentResizeArgs = {
4447
+ currentColumnStartWidth: $columnHeader.outerWidth(),
4448
+ minWidth: minimumColumnWidth,
4449
+ maxWidth: $columnHeader.outerWidth() + $nextColumnHeader.outerWidth() - minimumColumnWidth,
4450
+ mouseStartX: downevent.pageX,
4451
+ minResizeX: function () { return this.mouseStartX - (this.currentColumnStartWidth - this.minWidth); },
4452
+ maxResizeX: function () { return this.mouseStartX + (this.maxWidth - this.currentColumnStartWidth); }
4453
+ };
4454
+
4455
+ //Handle mouse move event to move resizing bar
4456
+ var resizeonmousemove = function (moveevent) {
4457
+ if (!self._currentResizeArgs) {
4458
+ return;
4459
+ }
4460
+
4461
+ var resizeBarX = self._normalizeNumber(moveevent.pageX, self._currentResizeArgs.minResizeX(), self._currentResizeArgs.maxResizeX());
4462
+ self._$columnResizeBar.css('left', (resizeBarX - mainContainerOffset.left) + 'px');
4463
+ };
4464
+
4465
+ //Handle mouse up event to finish resizing of the column
4466
+ var resizeonmouseup = function (upevent) {
4467
+ if (!self._currentResizeArgs) {
4468
+ return;
4469
+ }
4470
+
4471
+ $(document).unbind('mousemove', resizeonmousemove);
4472
+ $(document).unbind('mouseup', resizeonmouseup);
4473
+
4474
+ self._$columnResizeBar.hide();
4475
+
4476
+ //Calculate new widths in pixels
4477
+ var mouseChangeX = upevent.pageX - self._currentResizeArgs.mouseStartX;
4478
+ var currentColumnFinalWidth = self._normalizeNumber(self._currentResizeArgs.currentColumnStartWidth + mouseChangeX, self._currentResizeArgs.minWidth, self._currentResizeArgs.maxWidth);
4479
+ var nextColumnFinalWidth = $nextColumnHeader.outerWidth() + (self._currentResizeArgs.currentColumnStartWidth - currentColumnFinalWidth);
4480
+
4481
+ //Calculate widths as percent
4482
+ var pixelToPercentRatio = $columnHeader.data('width-in-percent') / self._currentResizeArgs.currentColumnStartWidth;
4483
+ $columnHeader.data('width-in-percent', currentColumnFinalWidth * pixelToPercentRatio);
4484
+ $nextColumnHeader.data('width-in-percent', nextColumnFinalWidth * pixelToPercentRatio);
4485
+
4486
+ //Set new widths to columns (resize!)
4487
+ $columnHeader.css('width', $columnHeader.data('width-in-percent') + '%');
4488
+ $nextColumnHeader.css('width', $nextColumnHeader.data('width-in-percent') + '%');
4489
+
4490
+ //Normalize all column widths
4491
+ self._normalizeColumnWidths();
4492
+
4493
+ //Finish resizing
4494
+ self._currentResizeArgs = null;
4495
+
4496
+ //Save current preferences
4497
+ if (self.options.saveUserPreferences) {
4498
+ self._saveColumnSettings();
4499
+ }
4500
+ };
4501
+
4502
+ //Show vertical resize bar
4503
+ self._$columnResizeBar
4504
+ .show()
4505
+ .css({
4506
+ top: ($columnHeader.offset().top - mainContainerOffset.top) + 'px',
4507
+ left: (downevent.pageX - mainContainerOffset.left) + 'px',
4508
+ height: (self._$table.outerHeight()) + 'px'
4509
+ });
4510
+
4511
+ //Bind events
4512
+ $(document).bind('mousemove', resizeonmousemove);
4513
+ $(document).bind('mouseup', resizeonmouseup);
4514
+ });
4515
+ },
4516
+
4517
+ /* Normalizes column widths as percent for current view.
4518
+ *************************************************************************/
4519
+ _normalizeColumnWidths: function () {
4520
+
4521
+ //Set command column width
4522
+ var commandColumnHeaders = this._$table
4523
+ .find('>thead th.jtable-command-column-header')
4524
+ .data('width-in-percent', 1)
4525
+ .css('width', '1%');
4526
+
4527
+ //Find data columns
4528
+ var headerCells = this._$table.find('>thead th.jtable-column-header');
4529
+
4530
+ //Calculate total width of data columns
4531
+ var totalWidthInPixel = 0;
4532
+ headerCells.each(function () {
4533
+ var $cell = $(this);
4534
+ if ($cell.is(':visible')) {
4535
+ totalWidthInPixel += $cell.outerWidth();
4536
+ }
4537
+ });
4538
+
4539
+ //Calculate width of each column
4540
+ var columnWidhts = {};
4541
+ var availableWidthInPercent = 100.0 - commandColumnHeaders.length;
4542
+ headerCells.each(function () {
4543
+ var $cell = $(this);
4544
+ if ($cell.is(':visible')) {
4545
+ var fieldName = $cell.data('fieldName');
4546
+ var widthInPercent = $cell.outerWidth() * availableWidthInPercent / totalWidthInPixel;
4547
+ columnWidhts[fieldName] = widthInPercent;
4548
+ }
4549
+ });
4550
+
4551
+ //Set width of each column
4552
+ headerCells.each(function () {
4553
+ var $cell = $(this);
4554
+ if ($cell.is(':visible')) {
4555
+ var fieldName = $cell.data('fieldName');
4556
+ $cell.data('width-in-percent', columnWidhts[fieldName]).css('width', columnWidhts[fieldName] + '%');
4557
+ }
4558
+ });
4559
+ },
4560
+
4561
+ /* Saves field setting to cookie.
4562
+ * Saved setting will be a string like that:
4563
+ * fieldName1=visible;23|fieldName2=hidden;17|...
4564
+ *************************************************************************/
4565
+ _saveColumnSettings: function () {
4566
+ var self = this;
4567
+ var fieldSettings = '';
4568
+ this._$table.find('>thead >tr >th.jtable-column-header').each(function () {
4569
+ var $cell = $(this);
4570
+ var fieldName = $cell.data('fieldName');
4571
+ var columnWidth = $cell.data('width-in-percent');
4572
+ var fieldVisibility = self.options.fields[fieldName].visibility;
4573
+ var fieldSetting = fieldName + "=" + fieldVisibility + ';' + columnWidth;
4574
+ fieldSettings = fieldSettings + fieldSetting + '|';
4575
+ });
4576
+
4577
+ this._setCookie('column-settings', fieldSettings.substr(0, fieldSettings.length - 1));
4578
+ },
4579
+
4580
+ /* Loads field settings from cookie that is saved by _saveFieldSettings method.
4581
+ *************************************************************************/
4582
+ _loadColumnSettings: function () {
4583
+ var self = this;
4584
+ var columnSettingsCookie = this._getCookie('column-settings');
4585
+ if (!columnSettingsCookie) {
4586
+ return;
4587
+ }
4588
+
4589
+ var columnSettings = {};
4590
+ $.each(columnSettingsCookie.split('|'), function (inx, fieldSetting) {
4591
+ var splitted = fieldSetting.split('=');
4592
+ var fieldName = splitted[0];
4593
+ var settings = splitted[1].split(';');
4594
+ columnSettings[fieldName] = {
4595
+ columnVisibility: settings[0],
4596
+ columnWidth: settings[1]
4597
+ };
4598
+ });
4599
+
4600
+ var headerCells = this._$table.find('>thead >tr >th.jtable-column-header');
4601
+ headerCells.each(function () {
4602
+ var $cell = $(this);
4603
+ var fieldName = $cell.data('fieldName');
4604
+ var field = self.options.fields[fieldName];
4605
+ if (columnSettings[fieldName]) {
4606
+ if (field.visibility != 'fixed') {
4607
+ self._changeColumnVisibilityInternal(fieldName, columnSettings[fieldName].columnVisibility);
4608
+ }
4609
+
4610
+ $cell.data('width-in-percent', columnSettings[fieldName].columnWidth).css('width', columnSettings[fieldName].columnWidth + '%');
4611
+ }
4612
+ });
4613
+ }
4614
+
4615
+ });
4616
+
4617
+ })(jQuery);
4618
+
4619
+
4620
+ /************************************************************************
4621
+ * MASTER/CHILD tables extension for jTable *
4622
+ *************************************************************************/
4623
+ (function ($) {
4624
+
4625
+ //Reference to base object members
4626
+ var base = {
4627
+ _removeRowsFromTable: $.hik.jtable.prototype._removeRowsFromTable
4628
+ };
4629
+
4630
+ //extension members
4631
+ $.extend(true, $.hik.jtable.prototype, {
4632
+
4633
+ /************************************************************************
4634
+ * DEFAULT OPTIONS / EVENTS *
4635
+ *************************************************************************/
4636
+ options: {
4637
+ openChildAsAccordion: false
4638
+ },
4639
+
4640
+ /************************************************************************
4641
+ * PUBLIC METHODS *
4642
+ *************************************************************************/
4643
+
4644
+ /* Creates and opens a new child table for given row.
4645
+ *************************************************************************/
4646
+ openChildTable: function ($row, tableOptions, opened) {
4647
+ var self = this;
4648
+
4649
+ //Apply theming as same as parent table unless explicitily set
4650
+ if (tableOptions.jqueryuiTheme == undefined) {
4651
+ tableOptions.jqueryuiTheme = self.options.jqueryuiTheme;
4652
+ }
4653
+
4654
+ //Show close button as default
4655
+ tableOptions.showCloseButton = (tableOptions.showCloseButton != false);
4656
+
4657
+ //Close child table when close button is clicked (default behavior)
4658
+ if (tableOptions.showCloseButton && !tableOptions.closeRequested) {
4659
+ tableOptions.closeRequested = function () {
4660
+ self.closeChildTable($row);
4661
+ };
4662
+ }
4663
+
4664
+ //If accordion style, close open child table (if it does exists)
4665
+ if (self.options.openChildAsAccordion) {
4666
+ $row.siblings('.jtable-data-row').each(function () {
4667
+ self.closeChildTable($(this));
4668
+ });
4669
+ }
4670
+
4671
+ //Close child table for this row and open new one for child table
4672
+ self.closeChildTable($row, function () {
4673
+ var $childRowColumn = self.getChildRow($row).children('td').empty();
4674
+ var $childTableContainer = $('<div />')
4675
+ .addClass('jtable-child-table-container')
4676
+ .appendTo($childRowColumn);
4677
+ $childRowColumn.data('childTable', $childTableContainer);
4678
+ $childTableContainer.jtable(tableOptions);
4679
+ self.openChildRow($row);
4680
+ $childTableContainer.hide().slideDown('fast', function () {
4681
+ if (opened) {
4682
+ opened({
4683
+ childTable: $childTableContainer
4684
+ });
4685
+ }
4686
+ });
4687
+ });
4688
+ },
4689
+
4690
+ /* Closes child table for given row.
4691
+ *************************************************************************/
4692
+ closeChildTable: function ($row, closed) {
4693
+ var self = this;
4694
+
4695
+ var $childRowColumn = this.getChildRow($row).children('td');
4696
+ var $childTable = $childRowColumn.data('childTable');
4697
+ if (!$childTable) {
4698
+ if (closed) {
4699
+ closed();
4700
+ }
4701
+
4702
+ return;
4703
+ }
4704
+
4705
+ $childRowColumn.data('childTable', null);
4706
+ $childTable.slideUp('fast', function () {
4707
+ $childTable.jtable('destroy');
4708
+ $childTable.remove();
4709
+ self.closeChildRow($row);
4710
+ if (closed) {
4711
+ closed();
4712
+ }
4713
+ });
4714
+ },
4715
+
4716
+ /* Returns a boolean value indicates that if a child row is open for given row.
4717
+ *************************************************************************/
4718
+ isChildRowOpen: function ($row) {
4719
+ return (this.getChildRow($row).is(':visible'));
4720
+ },
4721
+
4722
+ /* Gets child row for given row, opens it if it's closed (Creates if needed).
4723
+ *************************************************************************/
4724
+ getChildRow: function ($row) {
4725
+ return $row.data('childRow') || this._createChildRow($row);
4726
+ },
4727
+
4728
+ /* Creates and opens child row for given row.
4729
+ *************************************************************************/
4730
+ openChildRow: function ($row) {
4731
+ var $childRow = this.getChildRow($row);
4732
+ if (!$childRow.is(':visible')) {
4733
+ $childRow.show();
4734
+ }
4735
+
4736
+ return $childRow;
4737
+ },
4738
+
4739
+ /* Closes child row if it's open.
4740
+ *************************************************************************/
4741
+ closeChildRow: function ($row) {
4742
+ var $childRow = this.getChildRow($row);
4743
+ if ($childRow.is(':visible')) {
4744
+ $childRow.hide();
4745
+ }
4746
+ },
4747
+
4748
+ /************************************************************************
4749
+ * OVERRIDED METHODS *
4750
+ *************************************************************************/
4751
+
4752
+ /* Overrides _removeRowsFromTable method to remove child rows of deleted rows.
4753
+ *************************************************************************/
4754
+ _removeRowsFromTable: function ($rows, reason) {
4755
+ //var self = this;
4756
+
4757
+ if (reason == 'deleted') {
4758
+ $rows.each(function () {
4759
+ var $row = $(this);
4760
+ var $childRow = $row.data('childRow');
4761
+ if ($childRow) {
4762
+ //self.closeChildTable($row); //Removed since it causes "Uncaught Error: cannot call methods on jtable prior to initialization; attempted to call method 'destroy'"
4763
+ $childRow.remove();
4764
+ }
4765
+ });
4766
+ }
4767
+
4768
+ base._removeRowsFromTable.apply(this, arguments);
4769
+ },
4770
+
4771
+ /************************************************************************
4772
+ * PRIVATE METHODS *
4773
+ *************************************************************************/
4774
+
4775
+ /* Creates a child row for a row, hides and returns it.
4776
+ *************************************************************************/
4777
+ _createChildRow: function ($row) {
4778
+ var totalColumnCount = this._$table.find('thead th').length;
4779
+ var $childRow = $('<tr></tr>')
4780
+ .addClass('jtable-child-row')
4781
+ .append('<td colspan="' + totalColumnCount + '"></td>');
4782
+ $row.after($childRow);
4783
+ $row.data('childRow', $childRow);
4784
+ $childRow.hide();
4785
+ return $childRow;
4786
+ }
4787
+
4788
+ });
4789
+
4790
+ })(jQuery);
4791
+