Event Tickets - Version 4.7.3.1

Version Description

Download this release

Release Info

Developer ModernTribe
Plugin Icon 128x128 Event Tickets
Version 4.7.3.1
Comparing to
See all releases

Code changes from version 4.7.3 to 4.7.3.1

common/vendor/datatables/DataTables/images/sort_asc.png ADDED
Binary file
common/vendor/datatables/DataTables/images/sort_asc_disabled.png ADDED
Binary file
common/vendor/datatables/DataTables/images/sort_both.png ADDED
Binary file
common/vendor/datatables/DataTables/images/sort_desc.png ADDED
Binary file
common/vendor/datatables/DataTables/images/sort_desc_disabled.png ADDED
Binary file
common/vendor/datatables/datatables.css ADDED
@@ -0,0 +1,1220 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ * This combined file was created by the DataTables downloader builder:
3
+ * https://datatables.net/download
4
+ *
5
+ * To rebuild or modify this file with the latest versions of the included
6
+ * software please visit:
7
+ * https://datatables.net/download/#dt/dt-1.10.16/af-2.2.2/b-1.5.1/cr-1.4.1/fc-3.2.4/fh-3.1.3/kt-2.3.2/r-2.2.1/rr-1.2.3/sc-1.4.4/sl-1.2.5
8
+ *
9
+ * Included libraries:
10
+ * DataTables 1.10.16, AutoFill 2.2.2, Buttons 1.5.1, ColReorder 1.4.1, FixedColumns 3.2.4, FixedHeader 3.1.3, KeyTable 2.3.2, Responsive 2.2.1, RowReorder 1.2.3, Scroller 1.4.4, Select 1.2.5
11
+ */
12
+
13
+ /*
14
+ * Table styles
15
+ */
16
+ table.dataTable {
17
+ width: 100%;
18
+ margin: 0 auto;
19
+ clear: both;
20
+ border-collapse: separate;
21
+ border-spacing: 0;
22
+ /*
23
+ * Header and footer styles
24
+ */
25
+ /*
26
+ * Body styles
27
+ */
28
+ }
29
+ table.dataTable thead th,
30
+ table.dataTable tfoot th {
31
+ font-weight: bold;
32
+ }
33
+ table.dataTable thead th,
34
+ table.dataTable thead td {
35
+ padding: 10px 18px;
36
+ border-bottom: 1px solid #111;
37
+ }
38
+ table.dataTable thead th:active,
39
+ table.dataTable thead td:active {
40
+ outline: none;
41
+ }
42
+ table.dataTable tfoot th,
43
+ table.dataTable tfoot td {
44
+ padding: 10px 18px 6px 18px;
45
+ border-top: 1px solid #111;
46
+ }
47
+ table.dataTable thead .sorting,
48
+ table.dataTable thead .sorting_asc,
49
+ table.dataTable thead .sorting_desc,
50
+ table.dataTable thead .sorting_asc_disabled,
51
+ table.dataTable thead .sorting_desc_disabled {
52
+ cursor: pointer;
53
+ *cursor: hand;
54
+ background-repeat: no-repeat;
55
+ background-position: center right;
56
+ }
57
+ table.dataTable thead .sorting {
58
+ background-image: url("DataTables-1.10.16/images/sort_both.png");
59
+ }
60
+ table.dataTable thead .sorting_asc {
61
+ background-image: url("DataTables-1.10.16/images/sort_asc.png");
62
+ }
63
+ table.dataTable thead .sorting_desc {
64
+ background-image: url("DataTables-1.10.16/images/sort_desc.png");
65
+ }
66
+ table.dataTable thead .sorting_asc_disabled {
67
+ background-image: url("DataTables-1.10.16/images/sort_asc_disabled.png");
68
+ }
69
+ table.dataTable thead .sorting_desc_disabled {
70
+ background-image: url("DataTables-1.10.16/images/sort_desc_disabled.png");
71
+ }
72
+ table.dataTable tbody tr {
73
+ background-color: #ffffff;
74
+ }
75
+ table.dataTable tbody tr.selected {
76
+ background-color: #B0BED9;
77
+ }
78
+ table.dataTable tbody th,
79
+ table.dataTable tbody td {
80
+ padding: 8px 10px;
81
+ }
82
+ table.dataTable.row-border tbody th, table.dataTable.row-border tbody td, table.dataTable.display tbody th, table.dataTable.display tbody td {
83
+ border-top: 1px solid #ddd;
84
+ }
85
+ table.dataTable.row-border tbody tr:first-child th,
86
+ table.dataTable.row-border tbody tr:first-child td, table.dataTable.display tbody tr:first-child th,
87
+ table.dataTable.display tbody tr:first-child td {
88
+ border-top: none;
89
+ }
90
+ table.dataTable.cell-border tbody th, table.dataTable.cell-border tbody td {
91
+ border-top: 1px solid #ddd;
92
+ border-right: 1px solid #ddd;
93
+ }
94
+ table.dataTable.cell-border tbody tr th:first-child,
95
+ table.dataTable.cell-border tbody tr td:first-child {
96
+ border-left: 1px solid #ddd;
97
+ }
98
+ table.dataTable.cell-border tbody tr:first-child th,
99
+ table.dataTable.cell-border tbody tr:first-child td {
100
+ border-top: none;
101
+ }
102
+ table.dataTable.stripe tbody tr.odd, table.dataTable.display tbody tr.odd {
103
+ background-color: #f9f9f9;
104
+ }
105
+ table.dataTable.stripe tbody tr.odd.selected, table.dataTable.display tbody tr.odd.selected {
106
+ background-color: #acbad4;
107
+ }
108
+ table.dataTable.hover tbody tr:hover, table.dataTable.display tbody tr:hover {
109
+ background-color: #f6f6f6;
110
+ }
111
+ table.dataTable.hover tbody tr:hover.selected, table.dataTable.display tbody tr:hover.selected {
112
+ background-color: #aab7d1;
113
+ }
114
+ table.dataTable.order-column tbody tr > .sorting_1,
115
+ table.dataTable.order-column tbody tr > .sorting_2,
116
+ table.dataTable.order-column tbody tr > .sorting_3, table.dataTable.display tbody tr > .sorting_1,
117
+ table.dataTable.display tbody tr > .sorting_2,
118
+ table.dataTable.display tbody tr > .sorting_3 {
119
+ background-color: #fafafa;
120
+ }
121
+ table.dataTable.order-column tbody tr.selected > .sorting_1,
122
+ table.dataTable.order-column tbody tr.selected > .sorting_2,
123
+ table.dataTable.order-column tbody tr.selected > .sorting_3, table.dataTable.display tbody tr.selected > .sorting_1,
124
+ table.dataTable.display tbody tr.selected > .sorting_2,
125
+ table.dataTable.display tbody tr.selected > .sorting_3 {
126
+ background-color: #acbad5;
127
+ }
128
+ table.dataTable.display tbody tr.odd > .sorting_1, table.dataTable.order-column.stripe tbody tr.odd > .sorting_1 {
129
+ background-color: #f1f1f1;
130
+ }
131
+ table.dataTable.display tbody tr.odd > .sorting_2, table.dataTable.order-column.stripe tbody tr.odd > .sorting_2 {
132
+ background-color: #f3f3f3;
133
+ }
134
+ table.dataTable.display tbody tr.odd > .sorting_3, table.dataTable.order-column.stripe tbody tr.odd > .sorting_3 {
135
+ background-color: whitesmoke;
136
+ }
137
+ table.dataTable.display tbody tr.odd.selected > .sorting_1, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_1 {
138
+ background-color: #a6b4cd;
139
+ }
140
+ table.dataTable.display tbody tr.odd.selected > .sorting_2, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_2 {
141
+ background-color: #a8b5cf;
142
+ }
143
+ table.dataTable.display tbody tr.odd.selected > .sorting_3, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_3 {
144
+ background-color: #a9b7d1;
145
+ }
146
+ table.dataTable.display tbody tr.even > .sorting_1, table.dataTable.order-column.stripe tbody tr.even > .sorting_1 {
147
+ background-color: #fafafa;
148
+ }
149
+ table.dataTable.display tbody tr.even > .sorting_2, table.dataTable.order-column.stripe tbody tr.even > .sorting_2 {
150
+ background-color: #fcfcfc;
151
+ }
152
+ table.dataTable.display tbody tr.even > .sorting_3, table.dataTable.order-column.stripe tbody tr.even > .sorting_3 {
153
+ background-color: #fefefe;
154
+ }
155
+ table.dataTable.display tbody tr.even.selected > .sorting_1, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_1 {
156
+ background-color: #acbad5;
157
+ }
158
+ table.dataTable.display tbody tr.even.selected > .sorting_2, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_2 {
159
+ background-color: #aebcd6;
160
+ }
161
+ table.dataTable.display tbody tr.even.selected > .sorting_3, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_3 {
162
+ background-color: #afbdd8;
163
+ }
164
+ table.dataTable.display tbody tr:hover > .sorting_1, table.dataTable.order-column.hover tbody tr:hover > .sorting_1 {
165
+ background-color: #eaeaea;
166
+ }
167
+ table.dataTable.display tbody tr:hover > .sorting_2, table.dataTable.order-column.hover tbody tr:hover > .sorting_2 {
168
+ background-color: #ececec;
169
+ }
170
+ table.dataTable.display tbody tr:hover > .sorting_3, table.dataTable.order-column.hover tbody tr:hover > .sorting_3 {
171
+ background-color: #efefef;
172
+ }
173
+ table.dataTable.display tbody tr:hover.selected > .sorting_1, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_1 {
174
+ background-color: #a2aec7;
175
+ }
176
+ table.dataTable.display tbody tr:hover.selected > .sorting_2, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_2 {
177
+ background-color: #a3b0c9;
178
+ }
179
+ table.dataTable.display tbody tr:hover.selected > .sorting_3, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_3 {
180
+ background-color: #a5b2cb;
181
+ }
182
+ table.dataTable.no-footer {
183
+ border-bottom: 1px solid #111;
184
+ }
185
+ table.dataTable.nowrap th, table.dataTable.nowrap td {
186
+ white-space: nowrap;
187
+ }
188
+ table.dataTable.compact thead th,
189
+ table.dataTable.compact thead td {
190
+ padding: 4px 17px 4px 4px;
191
+ }
192
+ table.dataTable.compact tfoot th,
193
+ table.dataTable.compact tfoot td {
194
+ padding: 4px;
195
+ }
196
+ table.dataTable.compact tbody th,
197
+ table.dataTable.compact tbody td {
198
+ padding: 4px;
199
+ }
200
+ table.dataTable th.dt-left,
201
+ table.dataTable td.dt-left {
202
+ text-align: left;
203
+ }
204
+ table.dataTable th.dt-center,
205
+ table.dataTable td.dt-center,
206
+ table.dataTable td.dataTables_empty {
207
+ text-align: center;
208
+ }
209
+ table.dataTable th.dt-right,
210
+ table.dataTable td.dt-right {
211
+ text-align: right;
212
+ }
213
+ table.dataTable th.dt-justify,
214
+ table.dataTable td.dt-justify {
215
+ text-align: justify;
216
+ }
217
+ table.dataTable th.dt-nowrap,
218
+ table.dataTable td.dt-nowrap {
219
+ white-space: nowrap;
220
+ }
221
+ table.dataTable thead th.dt-head-left,
222
+ table.dataTable thead td.dt-head-left,
223
+ table.dataTable tfoot th.dt-head-left,
224
+ table.dataTable tfoot td.dt-head-left {
225
+ text-align: left;
226
+ }
227
+ table.dataTable thead th.dt-head-center,
228
+ table.dataTable thead td.dt-head-center,
229
+ table.dataTable tfoot th.dt-head-center,
230
+ table.dataTable tfoot td.dt-head-center {
231
+ text-align: center;
232
+ }
233
+ table.dataTable thead th.dt-head-right,
234
+ table.dataTable thead td.dt-head-right,
235
+ table.dataTable tfoot th.dt-head-right,
236
+ table.dataTable tfoot td.dt-head-right {
237
+ text-align: right;
238
+ }
239
+ table.dataTable thead th.dt-head-justify,
240
+ table.dataTable thead td.dt-head-justify,
241
+ table.dataTable tfoot th.dt-head-justify,
242
+ table.dataTable tfoot td.dt-head-justify {
243
+ text-align: justify;
244
+ }
245
+ table.dataTable thead th.dt-head-nowrap,
246
+ table.dataTable thead td.dt-head-nowrap,
247
+ table.dataTable tfoot th.dt-head-nowrap,
248
+ table.dataTable tfoot td.dt-head-nowrap {
249
+ white-space: nowrap;
250
+ }
251
+ table.dataTable tbody th.dt-body-left,
252
+ table.dataTable tbody td.dt-body-left {
253
+ text-align: left;
254
+ }
255
+ table.dataTable tbody th.dt-body-center,
256
+ table.dataTable tbody td.dt-body-center {
257
+ text-align: center;
258
+ }
259
+ table.dataTable tbody th.dt-body-right,
260
+ table.dataTable tbody td.dt-body-right {
261
+ text-align: right;
262
+ }
263
+ table.dataTable tbody th.dt-body-justify,
264
+ table.dataTable tbody td.dt-body-justify {
265
+ text-align: justify;
266
+ }
267
+ table.dataTable tbody th.dt-body-nowrap,
268
+ table.dataTable tbody td.dt-body-nowrap {
269
+ white-space: nowrap;
270
+ }
271
+
272
+ table.dataTable,
273
+ table.dataTable th,
274
+ table.dataTable td {
275
+ box-sizing: content-box;
276
+ }
277
+
278
+ /*
279
+ * Control feature layout
280
+ */
281
+ .dataTables_wrapper {
282
+ position: relative;
283
+ clear: both;
284
+ *zoom: 1;
285
+ zoom: 1;
286
+ }
287
+ .dataTables_wrapper .dataTables_length {
288
+ float: left;
289
+ }
290
+ .dataTables_wrapper .dataTables_filter {
291
+ float: right;
292
+ text-align: right;
293
+ }
294
+ .dataTables_wrapper .dataTables_filter input {
295
+ margin-left: 0.5em;
296
+ }
297
+ .dataTables_wrapper .dataTables_info {
298
+ clear: both;
299
+ float: left;
300
+ padding-top: 0.755em;
301
+ }
302
+ .dataTables_wrapper .dataTables_paginate {
303
+ float: right;
304
+ text-align: right;
305
+ padding-top: 0.25em;
306
+ }
307
+ .dataTables_wrapper .dataTables_paginate .paginate_button {
308
+ box-sizing: border-box;
309
+ display: inline-block;
310
+ min-width: 1.5em;
311
+ padding: 0.5em 1em;
312
+ margin-left: 2px;
313
+ text-align: center;
314
+ text-decoration: none !important;
315
+ cursor: pointer;
316
+ *cursor: hand;
317
+ color: #333 !important;
318
+ border: 1px solid transparent;
319
+ border-radius: 2px;
320
+ }
321
+ .dataTables_wrapper .dataTables_paginate .paginate_button.current, .dataTables_wrapper .dataTables_paginate .paginate_button.current:hover {
322
+ color: #333 !important;
323
+ border: 1px solid #979797;
324
+ background-color: white;
325
+ background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, white), color-stop(100%, #dcdcdc));
326
+ /* Chrome,Safari4+ */
327
+ background: -webkit-linear-gradient(top, white 0%, #dcdcdc 100%);
328
+ /* Chrome10+,Safari5.1+ */
329
+ background: -moz-linear-gradient(top, white 0%, #dcdcdc 100%);
330
+ /* FF3.6+ */
331
+ background: -ms-linear-gradient(top, white 0%, #dcdcdc 100%);
332
+ /* IE10+ */
333
+ background: -o-linear-gradient(top, white 0%, #dcdcdc 100%);
334
+ /* Opera 11.10+ */
335
+ background: linear-gradient(to bottom, white 0%, #dcdcdc 100%);
336
+ /* W3C */
337
+ }
338
+ .dataTables_wrapper .dataTables_paginate .paginate_button.disabled, .dataTables_wrapper .dataTables_paginate .paginate_button.disabled:hover, .dataTables_wrapper .dataTables_paginate .paginate_button.disabled:active {
339
+ cursor: default;
340
+ color: #666 !important;
341
+ border: 1px solid transparent;
342
+ background: transparent;
343
+ box-shadow: none;
344
+ }
345
+ .dataTables_wrapper .dataTables_paginate .paginate_button:hover {
346
+ color: white !important;
347
+ border: 1px solid #111;
348
+ background-color: #585858;
349
+ background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #585858), color-stop(100%, #111));
350
+ /* Chrome,Safari4+ */
351
+ background: -webkit-linear-gradient(top, #585858 0%, #111 100%);
352
+ /* Chrome10+,Safari5.1+ */
353
+ background: -moz-linear-gradient(top, #585858 0%, #111 100%);
354
+ /* FF3.6+ */
355
+ background: -ms-linear-gradient(top, #585858 0%, #111 100%);
356
+ /* IE10+ */
357
+ background: -o-linear-gradient(top, #585858 0%, #111 100%);
358
+ /* Opera 11.10+ */
359
+ background: linear-gradient(to bottom, #585858 0%, #111 100%);
360
+ /* W3C */
361
+ }
362
+ .dataTables_wrapper .dataTables_paginate .paginate_button:active {
363
+ outline: none;
364
+ background-color: #2b2b2b;
365
+ background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #2b2b2b), color-stop(100%, #0c0c0c));
366
+ /* Chrome,Safari4+ */
367
+ background: -webkit-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);
368
+ /* Chrome10+,Safari5.1+ */
369
+ background: -moz-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);
370
+ /* FF3.6+ */
371
+ background: -ms-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);
372
+ /* IE10+ */
373
+ background: -o-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);
374
+ /* Opera 11.10+ */
375
+ background: linear-gradient(to bottom, #2b2b2b 0%, #0c0c0c 100%);
376
+ /* W3C */
377
+ box-shadow: inset 0 0 3px #111;
378
+ }
379
+ .dataTables_wrapper .dataTables_paginate .ellipsis {
380
+ padding: 0 1em;
381
+ }
382
+ .dataTables_wrapper .dataTables_processing {
383
+ position: absolute;
384
+ top: 50%;
385
+ left: 50%;
386
+ width: 100%;
387
+ height: 40px;
388
+ margin-left: -50%;
389
+ margin-top: -25px;
390
+ padding-top: 20px;
391
+ text-align: center;
392
+ font-size: 1.2em;
393
+ background-color: white;
394
+ background: -webkit-gradient(linear, left top, right top, color-stop(0%, rgba(255, 255, 255, 0)), color-stop(25%, rgba(255, 255, 255, 0.9)), color-stop(75%, rgba(255, 255, 255, 0.9)), color-stop(100%, rgba(255, 255, 255, 0)));
395
+ background: -webkit-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);
396
+ background: -moz-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);
397
+ background: -ms-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);
398
+ background: -o-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);
399
+ background: linear-gradient(to right, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);
400
+ }
401
+ .dataTables_wrapper .dataTables_length,
402
+ .dataTables_wrapper .dataTables_filter,
403
+ .dataTables_wrapper .dataTables_info,
404
+ .dataTables_wrapper .dataTables_processing,
405
+ .dataTables_wrapper .dataTables_paginate {
406
+ color: #333;
407
+ }
408
+ .dataTables_wrapper .dataTables_scroll {
409
+ clear: both;
410
+ }
411
+ .dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody {
412
+ *margin-top: -1px;
413
+ -webkit-overflow-scrolling: touch;
414
+ }
415
+ .dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody > table > thead > tr > th, .dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody > table > thead > tr > td, .dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody > table > tbody > tr > th, .dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody > table > tbody > tr > td {
416
+ vertical-align: middle;
417
+ }
418
+ .dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody > table > thead > tr > th > div.dataTables_sizing,
419
+ .dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody > table > thead > tr > td > div.dataTables_sizing, .dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody > table > tbody > tr > th > div.dataTables_sizing,
420
+ .dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody > table > tbody > tr > td > div.dataTables_sizing {
421
+ height: 0;
422
+ overflow: hidden;
423
+ margin: 0 !important;
424
+ padding: 0 !important;
425
+ }
426
+ .dataTables_wrapper.no-footer .dataTables_scrollBody {
427
+ border-bottom: 1px solid #111;
428
+ }
429
+ .dataTables_wrapper.no-footer div.dataTables_scrollHead table.dataTable,
430
+ .dataTables_wrapper.no-footer div.dataTables_scrollBody > table {
431
+ border-bottom: none;
432
+ }
433
+ .dataTables_wrapper:after {
434
+ visibility: hidden;
435
+ display: block;
436
+ content: "";
437
+ clear: both;
438
+ height: 0;
439
+ }
440
+
441
+ @media screen and (max-width: 767px) {
442
+ .dataTables_wrapper .dataTables_info,
443
+ .dataTables_wrapper .dataTables_paginate {
444
+ float: none;
445
+ text-align: center;
446
+ }
447
+ .dataTables_wrapper .dataTables_paginate {
448
+ margin-top: 0.5em;
449
+ }
450
+ }
451
+ @media screen and (max-width: 640px) {
452
+ .dataTables_wrapper .dataTables_length,
453
+ .dataTables_wrapper .dataTables_filter {
454
+ float: none;
455
+ text-align: center;
456
+ }
457
+ .dataTables_wrapper .dataTables_filter {
458
+ margin-top: 0.5em;
459
+ }
460
+ }
461
+
462
+
463
+ div.dt-autofill-handle{position:absolute;height:8px;width:8px;z-index:102;box-sizing:border-box;border:1px solid #316ad1;background:linear-gradient(to bottom, #abcffb 0%, #4989de 100%)}div.dt-autofill-select{position:absolute;z-index:1001;background-color:#4989de;background-image:repeating-linear-gradient(45deg, transparent, transparent 5px, rgba(255,255,255,0.5) 5px, rgba(255,255,255,0.5) 10px)}div.dt-autofill-select.top,div.dt-autofill-select.bottom{height:3px;margin-top:-1px}div.dt-autofill-select.left,div.dt-autofill-select.right{width:3px;margin-left:-1px}div.dt-autofill-list{position:fixed;top:50%;left:50%;width:500px;margin-left:-250px;background-color:white;border-radius:6px;box-shadow:0 0 5px #555;border:2px solid #444;z-index:11;box-sizing:border-box;padding:1.5em 2em}div.dt-autofill-list ul{display:table;margin:0;padding:0;list-style:none;width:100%}div.dt-autofill-list ul li{display:table-row}div.dt-autofill-list ul li:last-child div.dt-autofill-question,div.dt-autofill-list ul li:last-child div.dt-autofill-button{border-bottom:none}div.dt-autofill-list ul li:hover{background-color:#f6f6f6}div.dt-autofill-list div.dt-autofill-question{display:table-cell;padding:0.5em 0;border-bottom:1px solid #ccc}div.dt-autofill-list div.dt-autofill-question input[type=number]{padding:6px;width:30px;margin:-2px 0}div.dt-autofill-list div.dt-autofill-button{display:table-cell;padding:0.5em 0;border-bottom:1px solid #ccc}div.dt-autofill-list div.dt-autofill-button button{color:white;margin:0;padding:6px 12px;text-align:center;border:1px solid #2e6da4;background-color:#337ab7;border-radius:4px;cursor:pointer;vertical-align:middle}div.dt-autofill-background{position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.7);background:radial-gradient(ellipse farthest-corner at center, rgba(0,0,0,0.3) 0%, rgba(0,0,0,0.7) 100%);z-index:10}
464
+
465
+
466
+ @keyframes dtb-spinner {
467
+ 100% {
468
+ transform: rotate(360deg);
469
+ }
470
+ }
471
+ @-o-keyframes dtb-spinner {
472
+ 100% {
473
+ -o-transform: rotate(360deg);
474
+ transform: rotate(360deg);
475
+ }
476
+ }
477
+ @-ms-keyframes dtb-spinner {
478
+ 100% {
479
+ -ms-transform: rotate(360deg);
480
+ transform: rotate(360deg);
481
+ }
482
+ }
483
+ @-webkit-keyframes dtb-spinner {
484
+ 100% {
485
+ -webkit-transform: rotate(360deg);
486
+ transform: rotate(360deg);
487
+ }
488
+ }
489
+ @-moz-keyframes dtb-spinner {
490
+ 100% {
491
+ -moz-transform: rotate(360deg);
492
+ transform: rotate(360deg);
493
+ }
494
+ }
495
+ div.dt-button-info {
496
+ position: fixed;
497
+ top: 50%;
498
+ left: 50%;
499
+ width: 400px;
500
+ margin-top: -100px;
501
+ margin-left: -200px;
502
+ background-color: white;
503
+ border: 2px solid #111;
504
+ box-shadow: 3px 3px 8px rgba(0, 0, 0, 0.3);
505
+ border-radius: 3px;
506
+ text-align: center;
507
+ z-index: 21;
508
+ }
509
+ div.dt-button-info h2 {
510
+ padding: 0.5em;
511
+ margin: 0;
512
+ font-weight: normal;
513
+ border-bottom: 1px solid #ddd;
514
+ background-color: #f3f3f3;
515
+ }
516
+ div.dt-button-info > div {
517
+ padding: 1em;
518
+ }
519
+
520
+ button.dt-button,
521
+ div.dt-button,
522
+ a.dt-button {
523
+ position: relative;
524
+ display: inline-block;
525
+ box-sizing: border-box;
526
+ margin-right: 0.333em;
527
+ margin-bottom: 0.333em;
528
+ padding: 0.5em 1em;
529
+ border: 1px solid #999;
530
+ border-radius: 2px;
531
+ cursor: pointer;
532
+ font-size: 0.88em;
533
+ line-height: 1.6em;
534
+ color: black;
535
+ white-space: nowrap;
536
+ overflow: hidden;
537
+ background-color: #e9e9e9;
538
+ /* Fallback */
539
+ background-image: -webkit-linear-gradient(top, white 0%, #e9e9e9 100%);
540
+ /* Chrome 10+, Saf5.1+, iOS 5+ */
541
+ background-image: -moz-linear-gradient(top, white 0%, #e9e9e9 100%);
542
+ /* FF3.6 */
543
+ background-image: -ms-linear-gradient(top, white 0%, #e9e9e9 100%);
544
+ /* IE10 */
545
+ background-image: -o-linear-gradient(top, white 0%, #e9e9e9 100%);
546
+ /* Opera 11.10+ */
547
+ background-image: linear-gradient(to bottom, white 0%, #e9e9e9 100%);
548
+ filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr='white', EndColorStr='#e9e9e9');
549
+ -webkit-user-select: none;
550
+ -moz-user-select: none;
551
+ -ms-user-select: none;
552
+ user-select: none;
553
+ text-decoration: none;
554
+ outline: none;
555
+ }
556
+ button.dt-button.disabled,
557
+ div.dt-button.disabled,
558
+ a.dt-button.disabled {
559
+ color: #999;
560
+ border: 1px solid #d0d0d0;
561
+ cursor: default;
562
+ background-color: #f9f9f9;
563
+ /* Fallback */
564
+ background-image: -webkit-linear-gradient(top, #ffffff 0%, #f9f9f9 100%);
565
+ /* Chrome 10+, Saf5.1+, iOS 5+ */
566
+ background-image: -moz-linear-gradient(top, #ffffff 0%, #f9f9f9 100%);
567
+ /* FF3.6 */
568
+ background-image: -ms-linear-gradient(top, #ffffff 0%, #f9f9f9 100%);
569
+ /* IE10 */
570
+ background-image: -o-linear-gradient(top, #ffffff 0%, #f9f9f9 100%);
571
+ /* Opera 11.10+ */
572
+ background-image: linear-gradient(to bottom, #ffffff 0%, #f9f9f9 100%);
573
+ filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr='#ffffff', EndColorStr='#f9f9f9');
574
+ }
575
+ button.dt-button:active:not(.disabled), button.dt-button.active:not(.disabled),
576
+ div.dt-button:active:not(.disabled),
577
+ div.dt-button.active:not(.disabled),
578
+ a.dt-button:active:not(.disabled),
579
+ a.dt-button.active:not(.disabled) {
580
+ background-color: #e2e2e2;
581
+ /* Fallback */
582
+ background-image: -webkit-linear-gradient(top, #f3f3f3 0%, #e2e2e2 100%);
583
+ /* Chrome 10+, Saf5.1+, iOS 5+ */
584
+ background-image: -moz-linear-gradient(top, #f3f3f3 0%, #e2e2e2 100%);
585
+ /* FF3.6 */
586
+ background-image: -ms-linear-gradient(top, #f3f3f3 0%, #e2e2e2 100%);
587
+ /* IE10 */
588
+ background-image: -o-linear-gradient(top, #f3f3f3 0%, #e2e2e2 100%);
589
+ /* Opera 11.10+ */
590
+ background-image: linear-gradient(to bottom, #f3f3f3 0%, #e2e2e2 100%);
591
+ filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr='#f3f3f3', EndColorStr='#e2e2e2');
592
+ box-shadow: inset 1px 1px 3px #999999;
593
+ }
594
+ button.dt-button:active:not(.disabled):hover:not(.disabled), button.dt-button.active:not(.disabled):hover:not(.disabled),
595
+ div.dt-button:active:not(.disabled):hover:not(.disabled),
596
+ div.dt-button.active:not(.disabled):hover:not(.disabled),
597
+ a.dt-button:active:not(.disabled):hover:not(.disabled),
598
+ a.dt-button.active:not(.disabled):hover:not(.disabled) {
599
+ box-shadow: inset 1px 1px 3px #999999;
600
+ background-color: #cccccc;
601
+ /* Fallback */
602
+ background-image: -webkit-linear-gradient(top, #eaeaea 0%, #cccccc 100%);
603
+ /* Chrome 10+, Saf5.1+, iOS 5+ */
604
+ background-image: -moz-linear-gradient(top, #eaeaea 0%, #cccccc 100%);
605
+ /* FF3.6 */
606
+ background-image: -ms-linear-gradient(top, #eaeaea 0%, #cccccc 100%);
607
+ /* IE10 */
608
+ background-image: -o-linear-gradient(top, #eaeaea 0%, #cccccc 100%);
609
+ /* Opera 11.10+ */
610
+ background-image: linear-gradient(to bottom, #eaeaea 0%, #cccccc 100%);
611
+ filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr='#eaeaea', EndColorStr='#cccccc');
612
+ }
613
+ button.dt-button:hover,
614
+ div.dt-button:hover,
615
+ a.dt-button:hover {
616
+ text-decoration: none;
617
+ }
618
+ button.dt-button:hover:not(.disabled),
619
+ div.dt-button:hover:not(.disabled),
620
+ a.dt-button:hover:not(.disabled) {
621
+ border: 1px solid #666;
622
+ background-color: #e0e0e0;
623
+ /* Fallback */
624
+ background-image: -webkit-linear-gradient(top, #f9f9f9 0%, #e0e0e0 100%);
625
+ /* Chrome 10+, Saf5.1+, iOS 5+ */
626
+ background-image: -moz-linear-gradient(top, #f9f9f9 0%, #e0e0e0 100%);
627
+ /* FF3.6 */
628
+ background-image: -ms-linear-gradient(top, #f9f9f9 0%, #e0e0e0 100%);
629
+ /* IE10 */
630
+ background-image: -o-linear-gradient(top, #f9f9f9 0%, #e0e0e0 100%);
631
+ /* Opera 11.10+ */
632
+ background-image: linear-gradient(to bottom, #f9f9f9 0%, #e0e0e0 100%);
633
+ filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr='#f9f9f9', EndColorStr='#e0e0e0');
634
+ }
635
+ button.dt-button:focus:not(.disabled),
636
+ div.dt-button:focus:not(.disabled),
637
+ a.dt-button:focus:not(.disabled) {
638
+ border: 1px solid #426c9e;
639
+ text-shadow: 0 1px 0 #c4def1;
640
+ outline: none;
641
+ background-color: #79ace9;
642
+ /* Fallback */
643
+ background-image: -webkit-linear-gradient(top, #bddef4 0%, #79ace9 100%);
644
+ /* Chrome 10+, Saf5.1+, iOS 5+ */
645
+ background-image: -moz-linear-gradient(top, #bddef4 0%, #79ace9 100%);
646
+ /* FF3.6 */
647
+ background-image: -ms-linear-gradient(top, #bddef4 0%, #79ace9 100%);
648
+ /* IE10 */
649
+ background-image: -o-linear-gradient(top, #bddef4 0%, #79ace9 100%);
650
+ /* Opera 11.10+ */
651
+ background-image: linear-gradient(to bottom, #bddef4 0%, #79ace9 100%);
652
+ filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr='#bddef4', EndColorStr='#79ace9');
653
+ }
654
+
655
+ .dt-button embed {
656
+ outline: none;
657
+ }
658
+
659
+ div.dt-buttons {
660
+ position: relative;
661
+ float: left;
662
+ }
663
+ div.dt-buttons.buttons-right {
664
+ float: right;
665
+ }
666
+
667
+ div.dt-button-collection {
668
+ position: absolute;
669
+ top: 0;
670
+ left: 0;
671
+ width: 150px;
672
+ margin-top: 3px;
673
+ padding: 8px 8px 4px 8px;
674
+ border: 1px solid #ccc;
675
+ border: 1px solid rgba(0, 0, 0, 0.4);
676
+ background-color: white;
677
+ overflow: hidden;
678
+ z-index: 2002;
679
+ border-radius: 5px;
680
+ box-shadow: 3px 3px 5px rgba(0, 0, 0, 0.3);
681
+ z-index: 2002;
682
+ -webkit-column-gap: 8px;
683
+ -moz-column-gap: 8px;
684
+ -ms-column-gap: 8px;
685
+ -o-column-gap: 8px;
686
+ column-gap: 8px;
687
+ }
688
+ div.dt-button-collection button.dt-button,
689
+ div.dt-button-collection div.dt-button,
690
+ div.dt-button-collection a.dt-button {
691
+ position: relative;
692
+ left: 0;
693
+ right: 0;
694
+ width: 100%;
695
+ display: block;
696
+ float: none;
697
+ margin-bottom: 4px;
698
+ margin-right: 0;
699
+ }
700
+ div.dt-button-collection button.dt-button:active:not(.disabled), div.dt-button-collection button.dt-button.active:not(.disabled),
701
+ div.dt-button-collection div.dt-button:active:not(.disabled),
702
+ div.dt-button-collection div.dt-button.active:not(.disabled),
703
+ div.dt-button-collection a.dt-button:active:not(.disabled),
704
+ div.dt-button-collection a.dt-button.active:not(.disabled) {
705
+ background-color: #dadada;
706
+ /* Fallback */
707
+ background-image: -webkit-linear-gradient(top, #f0f0f0 0%, #dadada 100%);
708
+ /* Chrome 10+, Saf5.1+, iOS 5+ */
709
+ background-image: -moz-linear-gradient(top, #f0f0f0 0%, #dadada 100%);
710
+ /* FF3.6 */
711
+ background-image: -ms-linear-gradient(top, #f0f0f0 0%, #dadada 100%);
712
+ /* IE10 */
713
+ background-image: -o-linear-gradient(top, #f0f0f0 0%, #dadada 100%);
714
+ /* Opera 11.10+ */
715
+ background-image: linear-gradient(to bottom, #f0f0f0 0%, #dadada 100%);
716
+ filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr='#f0f0f0', EndColorStr='#dadada');
717
+ box-shadow: inset 1px 1px 3px #666;
718
+ }
719
+ div.dt-button-collection.fixed {
720
+ position: fixed;
721
+ top: 50%;
722
+ left: 50%;
723
+ margin-left: -75px;
724
+ border-radius: 0;
725
+ }
726
+ div.dt-button-collection.fixed.two-column {
727
+ margin-left: -150px;
728
+ }
729
+ div.dt-button-collection.fixed.three-column {
730
+ margin-left: -225px;
731
+ }
732
+ div.dt-button-collection.fixed.four-column {
733
+ margin-left: -300px;
734
+ }
735
+ div.dt-button-collection > * {
736
+ -webkit-column-break-inside: avoid;
737
+ break-inside: avoid;
738
+ }
739
+ div.dt-button-collection.two-column {
740
+ width: 300px;
741
+ padding-bottom: 1px;
742
+ -webkit-column-count: 2;
743
+ -moz-column-count: 2;
744
+ -ms-column-count: 2;
745
+ -o-column-count: 2;
746
+ column-count: 2;
747
+ }
748
+ div.dt-button-collection.three-column {
749
+ width: 450px;
750
+ padding-bottom: 1px;
751
+ -webkit-column-count: 3;
752
+ -moz-column-count: 3;
753
+ -ms-column-count: 3;
754
+ -o-column-count: 3;
755
+ column-count: 3;
756
+ }
757
+ div.dt-button-collection.four-column {
758
+ width: 600px;
759
+ padding-bottom: 1px;
760
+ -webkit-column-count: 4;
761
+ -moz-column-count: 4;
762
+ -ms-column-count: 4;
763
+ -o-column-count: 4;
764
+ column-count: 4;
765
+ }
766
+ div.dt-button-collection .dt-button {
767
+ border-radius: 0;
768
+ }
769
+
770
+ div.dt-button-background {
771
+ position: fixed;
772
+ top: 0;
773
+ left: 0;
774
+ width: 100%;
775
+ height: 100%;
776
+ background: rgba(0, 0, 0, 0.7);
777
+ /* Fallback */
778
+ background: -ms-radial-gradient(center, ellipse farthest-corner, rgba(0, 0, 0, 0.3) 0%, rgba(0, 0, 0, 0.7) 100%);
779
+ /* IE10 Consumer Preview */
780
+ background: -moz-radial-gradient(center, ellipse farthest-corner, rgba(0, 0, 0, 0.3) 0%, rgba(0, 0, 0, 0.7) 100%);
781
+ /* Firefox */
782
+ background: -o-radial-gradient(center, ellipse farthest-corner, rgba(0, 0, 0, 0.3) 0%, rgba(0, 0, 0, 0.7) 100%);
783
+ /* Opera */
784
+ background: -webkit-gradient(radial, center center, 0, center center, 497, color-stop(0, rgba(0, 0, 0, 0.3)), color-stop(1, rgba(0, 0, 0, 0.7)));
785
+ /* Webkit (Safari/Chrome 10) */
786
+ background: -webkit-radial-gradient(center, ellipse farthest-corner, rgba(0, 0, 0, 0.3) 0%, rgba(0, 0, 0, 0.7) 100%);
787
+ /* Webkit (Chrome 11+) */
788
+ background: radial-gradient(ellipse farthest-corner at center, rgba(0, 0, 0, 0.3) 0%, rgba(0, 0, 0, 0.7) 100%);
789
+ /* W3C Markup, IE10 Release Preview */
790
+ z-index: 2001;
791
+ }
792
+
793
+ @media screen and (max-width: 640px) {
794
+ div.dt-buttons {
795
+ float: none !important;
796
+ text-align: center;
797
+ }
798
+ }
799
+ button.dt-button.processing,
800
+ div.dt-button.processing,
801
+ a.dt-button.processing {
802
+ color: rgba(0, 0, 0, 0.2);
803
+ }
804
+ button.dt-button.processing:after,
805
+ div.dt-button.processing:after,
806
+ a.dt-button.processing:after {
807
+ position: absolute;
808
+ top: 50%;
809
+ left: 50%;
810
+ width: 16px;
811
+ height: 16px;
812
+ margin: -8px 0 0 -8px;
813
+ box-sizing: border-box;
814
+ display: block;
815
+ content: ' ';
816
+ border: 2px solid #282828;
817
+ border-radius: 50%;
818
+ border-left-color: transparent;
819
+ border-right-color: transparent;
820
+ animation: dtb-spinner 1500ms infinite linear;
821
+ -o-animation: dtb-spinner 1500ms infinite linear;
822
+ -ms-animation: dtb-spinner 1500ms infinite linear;
823
+ -webkit-animation: dtb-spinner 1500ms infinite linear;
824
+ -moz-animation: dtb-spinner 1500ms infinite linear;
825
+ }
826
+
827
+
828
+ table.DTCR_clonedTable.dataTable {
829
+ position: absolute !important;
830
+ background-color: rgba(255, 255, 255, 0.7);
831
+ z-index: 202;
832
+ }
833
+
834
+ div.DTCR_pointer {
835
+ width: 1px;
836
+ background-color: #0259C4;
837
+ z-index: 201;
838
+ }
839
+
840
+
841
+ table.DTFC_Cloned thead,
842
+ table.DTFC_Cloned tfoot {
843
+ background-color: white;
844
+ }
845
+
846
+ div.DTFC_Blocker {
847
+ background-color: white;
848
+ }
849
+
850
+ div.DTFC_LeftWrapper table.dataTable,
851
+ div.DTFC_RightWrapper table.dataTable {
852
+ margin-bottom: 0;
853
+ z-index: 2;
854
+ }
855
+ div.DTFC_LeftWrapper table.dataTable.no-footer,
856
+ div.DTFC_RightWrapper table.dataTable.no-footer {
857
+ border-bottom: none;
858
+ }
859
+
860
+
861
+ table.fixedHeader-floating {
862
+ position: fixed !important;
863
+ background-color: white;
864
+ }
865
+
866
+ table.fixedHeader-floating.no-footer {
867
+ border-bottom-width: 0;
868
+ }
869
+
870
+ table.fixedHeader-locked {
871
+ position: absolute !important;
872
+ background-color: white;
873
+ }
874
+
875
+ @media print {
876
+ table.fixedHeader-floating {
877
+ display: none;
878
+ }
879
+ }
880
+
881
+
882
+ table.dataTable th.focus,
883
+ table.dataTable td.focus {
884
+ outline: 3px solid #3366FF;
885
+ outline-offset: -1px;
886
+ }
887
+
888
+
889
+ table.dataTable.dtr-inline.collapsed > tbody > tr > td.child,
890
+ table.dataTable.dtr-inline.collapsed > tbody > tr > th.child,
891
+ table.dataTable.dtr-inline.collapsed > tbody > tr > td.dataTables_empty {
892
+ cursor: default !important;
893
+ }
894
+ table.dataTable.dtr-inline.collapsed > tbody > tr > td.child:before,
895
+ table.dataTable.dtr-inline.collapsed > tbody > tr > th.child:before,
896
+ table.dataTable.dtr-inline.collapsed > tbody > tr > td.dataTables_empty:before {
897
+ display: none !important;
898
+ }
899
+ table.dataTable.dtr-inline.collapsed > tbody > tr[role="row"] > td:first-child,
900
+ table.dataTable.dtr-inline.collapsed > tbody > tr[role="row"] > th:first-child {
901
+ position: relative;
902
+ padding-left: 30px;
903
+ cursor: pointer;
904
+ }
905
+ table.dataTable.dtr-inline.collapsed > tbody > tr[role="row"] > td:first-child:before,
906
+ table.dataTable.dtr-inline.collapsed > tbody > tr[role="row"] > th:first-child:before {
907
+ top: 9px;
908
+ left: 4px;
909
+ height: 14px;
910
+ width: 14px;
911
+ display: block;
912
+ position: absolute;
913
+ color: white;
914
+ border: 2px solid white;
915
+ border-radius: 14px;
916
+ box-shadow: 0 0 3px #444;
917
+ box-sizing: content-box;
918
+ text-align: center;
919
+ text-indent: 0 !important;
920
+ font-family: 'Courier New', Courier, monospace;
921
+ line-height: 14px;
922
+ content: '+';
923
+ background-color: #31b131;
924
+ }
925
+ table.dataTable.dtr-inline.collapsed > tbody > tr.parent > td:first-child:before,
926
+ table.dataTable.dtr-inline.collapsed > tbody > tr.parent > th:first-child:before {
927
+ content: '-';
928
+ background-color: #d33333;
929
+ }
930
+ table.dataTable.dtr-inline.collapsed.compact > tbody > tr > td:first-child,
931
+ table.dataTable.dtr-inline.collapsed.compact > tbody > tr > th:first-child {
932
+ padding-left: 27px;
933
+ }
934
+ table.dataTable.dtr-inline.collapsed.compact > tbody > tr > td:first-child:before,
935
+ table.dataTable.dtr-inline.collapsed.compact > tbody > tr > th:first-child:before {
936
+ top: 5px;
937
+ left: 4px;
938
+ height: 14px;
939
+ width: 14px;
940
+ border-radius: 14px;
941
+ line-height: 14px;
942
+ text-indent: 3px;
943
+ }
944
+ table.dataTable.dtr-column > tbody > tr > td.control,
945
+ table.dataTable.dtr-column > tbody > tr > th.control {
946
+ position: relative;
947
+ cursor: pointer;
948
+ }
949
+ table.dataTable.dtr-column > tbody > tr > td.control:before,
950
+ table.dataTable.dtr-column > tbody > tr > th.control:before {
951
+ top: 50%;
952
+ left: 50%;
953
+ height: 16px;
954
+ width: 16px;
955
+ margin-top: -10px;
956
+ margin-left: -10px;
957
+ display: block;
958
+ position: absolute;
959
+ color: white;
960
+ border: 2px solid white;
961
+ border-radius: 14px;
962
+ box-shadow: 0 0 3px #444;
963
+ box-sizing: content-box;
964
+ text-align: center;
965
+ text-indent: 0 !important;
966
+ font-family: 'Courier New', Courier, monospace;
967
+ line-height: 14px;
968
+ content: '+';
969
+ background-color: #31b131;
970
+ }
971
+ table.dataTable.dtr-column > tbody > tr.parent td.control:before,
972
+ table.dataTable.dtr-column > tbody > tr.parent th.control:before {
973
+ content: '-';
974
+ background-color: #d33333;
975
+ }
976
+ table.dataTable > tbody > tr.child {
977
+ padding: 0.5em 1em;
978
+ }
979
+ table.dataTable > tbody > tr.child:hover {
980
+ background: transparent !important;
981
+ }
982
+ table.dataTable > tbody > tr.child ul.dtr-details {
983
+ display: inline-block;
984
+ list-style-type: none;
985
+ margin: 0;
986
+ padding: 0;
987
+ }
988
+ table.dataTable > tbody > tr.child ul.dtr-details > li {
989
+ border-bottom: 1px solid #efefef;
990
+ padding: 0.5em 0;
991
+ }
992
+ table.dataTable > tbody > tr.child ul.dtr-details > li:first-child {
993
+ padding-top: 0;
994
+ }
995
+ table.dataTable > tbody > tr.child ul.dtr-details > li:last-child {
996
+ border-bottom: none;
997
+ }
998
+ table.dataTable > tbody > tr.child span.dtr-title {
999
+ display: inline-block;
1000
+ min-width: 75px;
1001
+ font-weight: bold;
1002
+ }
1003
+
1004
+ div.dtr-modal {
1005
+ position: fixed;
1006
+ box-sizing: border-box;
1007
+ top: 0;
1008
+ left: 0;
1009
+ height: 100%;
1010
+ width: 100%;
1011
+ z-index: 100;
1012
+ padding: 10em 1em;
1013
+ }
1014
+ div.dtr-modal div.dtr-modal-display {
1015
+ position: absolute;
1016
+ top: 0;
1017
+ left: 0;
1018
+ bottom: 0;
1019
+ right: 0;
1020
+ width: 50%;
1021
+ height: 50%;
1022
+ overflow: auto;
1023
+ margin: auto;
1024
+ z-index: 102;
1025
+ overflow: auto;
1026
+ background-color: #f5f5f7;
1027
+ border: 1px solid black;
1028
+ border-radius: 0.5em;
1029
+ box-shadow: 0 12px 30px rgba(0, 0, 0, 0.6);
1030
+ }
1031
+ div.dtr-modal div.dtr-modal-content {
1032
+ position: relative;
1033
+ padding: 1em;
1034
+ }
1035
+ div.dtr-modal div.dtr-modal-close {
1036
+ position: absolute;
1037
+ top: 6px;
1038
+ right: 6px;
1039
+ width: 22px;
1040
+ height: 22px;
1041
+ border: 1px solid #eaeaea;
1042
+ background-color: #f9f9f9;
1043
+ text-align: center;
1044
+ border-radius: 3px;
1045
+ cursor: pointer;
1046
+ z-index: 12;
1047
+ }
1048
+ div.dtr-modal div.dtr-modal-close:hover {
1049
+ background-color: #eaeaea;
1050
+ }
1051
+ div.dtr-modal div.dtr-modal-background {
1052
+ position: fixed;
1053
+ top: 0;
1054
+ left: 0;
1055
+ right: 0;
1056
+ bottom: 0;
1057
+ z-index: 101;
1058
+ background: rgba(0, 0, 0, 0.6);
1059
+ }
1060
+
1061
+ @media screen and (max-width: 767px) {
1062
+ div.dtr-modal div.dtr-modal-display {
1063
+ width: 95%;
1064
+ }
1065
+ }
1066
+
1067
+
1068
+ table.dt-rowReorder-float {
1069
+ position: absolute !important;
1070
+ opacity: 0.8;
1071
+ table-layout: fixed;
1072
+ outline: 2px solid #888;
1073
+ outline-offset: -2px;
1074
+ z-index: 2001;
1075
+ }
1076
+
1077
+ tr.dt-rowReorder-moving {
1078
+ outline: 2px solid #555;
1079
+ outline-offset: -2px;
1080
+ }
1081
+
1082
+ body.dt-rowReorder-noOverflow {
1083
+ overflow-x: hidden;
1084
+ }
1085
+
1086
+ table.dataTable td.reorder {
1087
+ text-align: center;
1088
+ cursor: move;
1089
+ }
1090
+
1091
+
1092
+ div.DTS {
1093
+ display: block !important;
1094
+ }
1095
+ div.DTS tbody th,
1096
+ div.DTS tbody td {
1097
+ white-space: nowrap;
1098
+ }
1099
+ div.DTS div.DTS_Loading {
1100
+ z-index: 1;
1101
+ }
1102
+ div.DTS div.dataTables_scrollBody {
1103
+ background: repeating-linear-gradient(45deg, #edeeff, #edeeff 10px, white 10px, white 20px);
1104
+ }
1105
+ div.DTS div.dataTables_scrollBody table {
1106
+ z-index: 2;
1107
+ }
1108
+ div.DTS div.dataTables_paginate,
1109
+ div.DTS div.dataTables_length {
1110
+ display: none;
1111
+ }
1112
+
1113
+
1114
+ table.dataTable tbody > tr.selected,
1115
+ table.dataTable tbody > tr > .selected {
1116
+ background-color: #B0BED9;
1117
+ }
1118
+ table.dataTable.stripe tbody > tr.odd.selected,
1119
+ table.dataTable.stripe tbody > tr.odd > .selected, table.dataTable.display tbody > tr.odd.selected,
1120
+ table.dataTable.display tbody > tr.odd > .selected {
1121
+ background-color: #acbad4;
1122
+ }
1123
+ table.dataTable.hover tbody > tr.selected:hover,
1124
+ table.dataTable.hover tbody > tr > .selected:hover, table.dataTable.display tbody > tr.selected:hover,
1125
+ table.dataTable.display tbody > tr > .selected:hover {
1126
+ background-color: #aab7d1;
1127
+ }
1128
+ table.dataTable.order-column tbody > tr.selected > .sorting_1,
1129
+ table.dataTable.order-column tbody > tr.selected > .sorting_2,
1130
+ table.dataTable.order-column tbody > tr.selected > .sorting_3,
1131
+ table.dataTable.order-column tbody > tr > .selected, table.dataTable.display tbody > tr.selected > .sorting_1,
1132
+ table.dataTable.display tbody > tr.selected > .sorting_2,
1133
+ table.dataTable.display tbody > tr.selected > .sorting_3,
1134
+ table.dataTable.display tbody > tr > .selected {
1135
+ background-color: #acbad5;
1136
+ }
1137
+ table.dataTable.display tbody > tr.odd.selected > .sorting_1, table.dataTable.order-column.stripe tbody > tr.odd.selected > .sorting_1 {
1138
+ background-color: #a6b4cd;
1139
+ }
1140
+ table.dataTable.display tbody > tr.odd.selected > .sorting_2, table.dataTable.order-column.stripe tbody > tr.odd.selected > .sorting_2 {
1141
+ background-color: #a8b5cf;
1142
+ }
1143
+ table.dataTable.display tbody > tr.odd.selected > .sorting_3, table.dataTable.order-column.stripe tbody > tr.odd.selected > .sorting_3 {
1144
+ background-color: #a9b7d1;
1145
+ }
1146
+ table.dataTable.display tbody > tr.even.selected > .sorting_1, table.dataTable.order-column.stripe tbody > tr.even.selected > .sorting_1 {
1147
+ background-color: #acbad5;
1148
+ }
1149
+ table.dataTable.display tbody > tr.even.selected > .sorting_2, table.dataTable.order-column.stripe tbody > tr.even.selected > .sorting_2 {
1150
+ background-color: #aebcd6;
1151
+ }
1152
+ table.dataTable.display tbody > tr.even.selected > .sorting_3, table.dataTable.order-column.stripe tbody > tr.even.selected > .sorting_3 {
1153
+ background-color: #afbdd8;
1154
+ }
1155
+ table.dataTable.display tbody > tr.odd > .selected, table.dataTable.order-column.stripe tbody > tr.odd > .selected {
1156
+ background-color: #a6b4cd;
1157
+ }
1158
+ table.dataTable.display tbody > tr.even > .selected, table.dataTable.order-column.stripe tbody > tr.even > .selected {
1159
+ background-color: #acbad5;
1160
+ }
1161
+ table.dataTable.display tbody > tr.selected:hover > .sorting_1, table.dataTable.order-column.hover tbody > tr.selected:hover > .sorting_1 {
1162
+ background-color: #a2aec7;
1163
+ }
1164
+ table.dataTable.display tbody > tr.selected:hover > .sorting_2, table.dataTable.order-column.hover tbody > tr.selected:hover > .sorting_2 {
1165
+ background-color: #a3b0c9;
1166
+ }
1167
+ table.dataTable.display tbody > tr.selected:hover > .sorting_3, table.dataTable.order-column.hover tbody > tr.selected:hover > .sorting_3 {
1168
+ background-color: #a5b2cb;
1169
+ }
1170
+ table.dataTable.display tbody > tr:hover > .selected,
1171
+ table.dataTable.display tbody > tr > .selected:hover, table.dataTable.order-column.hover tbody > tr:hover > .selected,
1172
+ table.dataTable.order-column.hover tbody > tr > .selected:hover {
1173
+ background-color: #a2aec7;
1174
+ }
1175
+ table.dataTable tbody td.select-checkbox,
1176
+ table.dataTable tbody th.select-checkbox {
1177
+ position: relative;
1178
+ }
1179
+ table.dataTable tbody td.select-checkbox:before, table.dataTable tbody td.select-checkbox:after,
1180
+ table.dataTable tbody th.select-checkbox:before,
1181
+ table.dataTable tbody th.select-checkbox:after {
1182
+ display: block;
1183
+ position: absolute;
1184
+ top: 1.2em;
1185
+ left: 50%;
1186
+ width: 12px;
1187
+ height: 12px;
1188
+ box-sizing: border-box;
1189
+ }
1190
+ table.dataTable tbody td.select-checkbox:before,
1191
+ table.dataTable tbody th.select-checkbox:before {
1192
+ content: ' ';
1193
+ margin-top: -6px;
1194
+ margin-left: -6px;
1195
+ border: 1px solid black;
1196
+ border-radius: 3px;
1197
+ }
1198
+ table.dataTable tr.selected td.select-checkbox:after,
1199
+ table.dataTable tr.selected th.select-checkbox:after {
1200
+ content: '\2714';
1201
+ margin-top: -11px;
1202
+ margin-left: -4px;
1203
+ text-align: center;
1204
+ text-shadow: 1px 1px #B0BED9, -1px -1px #B0BED9, 1px -1px #B0BED9, -1px 1px #B0BED9;
1205
+ }
1206
+
1207
+ div.dataTables_wrapper span.select-info,
1208
+ div.dataTables_wrapper span.select-item {
1209
+ margin-left: 0.5em;
1210
+ }
1211
+
1212
+ @media screen and (max-width: 640px) {
1213
+ div.dataTables_wrapper span.select-info,
1214
+ div.dataTables_wrapper span.select-item {
1215
+ margin-left: 0;
1216
+ display: block;
1217
+ }
1218
+ }
1219
+
1220
+
common/vendor/datatables/datatables.js ADDED
@@ -0,0 +1,27788 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ * This combined file was created by the DataTables downloader builder:
3
+ * https://datatables.net/download
4
+ *
5
+ * To rebuild or modify this file with the latest versions of the included
6
+ * software please visit:
7
+ * https://datatables.net/download/#dt/dt-1.10.16/af-2.2.2/b-1.5.1/cr-1.4.1/fc-3.2.4/fh-3.1.3/kt-2.3.2/r-2.2.1/rr-1.2.3/sc-1.4.4/sl-1.2.5
8
+ *
9
+ * Included libraries:
10
+ * DataTables 1.10.16, AutoFill 2.2.2, Buttons 1.5.1, ColReorder 1.4.1, FixedColumns 3.2.4, FixedHeader 3.1.3, KeyTable 2.3.2, Responsive 2.2.1, RowReorder 1.2.3, Scroller 1.4.4, Select 1.2.5
11
+ */
12
+
13
+ /*! DataTables 1.10.16
14
+ * ©2008-2017 SpryMedia Ltd - datatables.net/license
15
+ */
16
+
17
+ /**
18
+ * @summary DataTables
19
+ * @description Paginate, search and order HTML tables
20
+ * @version 1.10.16
21
+ * @file jquery.dataTables.js
22
+ * @author SpryMedia Ltd
23
+ * @contact www.datatables.net
24
+ * @copyright Copyright 2008-2017 SpryMedia Ltd.
25
+ *
26
+ * This source file is free software, available under the following license:
27
+ * MIT license - http://datatables.net/license
28
+ *
29
+ * This source file is distributed in the hope that it will be useful, but
30
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
31
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
32
+ *
33
+ * For details please refer to: http://www.datatables.net
34
+ */
35
+
36
+ /*jslint evil: true, undef: true, browser: true */
37
+ /*globals $,require,jQuery,define,_selector_run,_selector_opts,_selector_first,_selector_row_indexes,_ext,_Api,_api_register,_api_registerPlural,_re_new_lines,_re_html,_re_formatted_numeric,_re_escape_regex,_empty,_intVal,_numToDecimal,_isNumber,_isHtml,_htmlNumeric,_pluck,_pluck_order,_range,_stripHtml,_unique,_fnBuildAjax,_fnAjaxUpdate,_fnAjaxParameters,_fnAjaxUpdateDraw,_fnAjaxDataSrc,_fnAddColumn,_fnColumnOptions,_fnAdjustColumnSizing,_fnVisibleToColumnIndex,_fnColumnIndexToVisible,_fnVisbleColumns,_fnGetColumns,_fnColumnTypes,_fnApplyColumnDefs,_fnHungarianMap,_fnCamelToHungarian,_fnLanguageCompat,_fnBrowserDetect,_fnAddData,_fnAddTr,_fnNodeToDataIndex,_fnNodeToColumnIndex,_fnGetCellData,_fnSetCellData,_fnSplitObjNotation,_fnGetObjectDataFn,_fnSetObjectDataFn,_fnGetDataMaster,_fnClearTable,_fnDeleteIndex,_fnInvalidate,_fnGetRowElements,_fnCreateTr,_fnBuildHead,_fnDrawHead,_fnDraw,_fnReDraw,_fnAddOptionsHtml,_fnDetectHeader,_fnGetUniqueThs,_fnFeatureHtmlFilter,_fnFilterComplete,_fnFilterCustom,_fnFilterColumn,_fnFilter,_fnFilterCreateSearch,_fnEscapeRegex,_fnFilterData,_fnFeatureHtmlInfo,_fnUpdateInfo,_fnInfoMacros,_fnInitialise,_fnInitComplete,_fnLengthChange,_fnFeatureHtmlLength,_fnFeatureHtmlPaginate,_fnPageChange,_fnFeatureHtmlProcessing,_fnProcessingDisplay,_fnFeatureHtmlTable,_fnScrollDraw,_fnApplyToChildren,_fnCalculateColumnWidths,_fnThrottle,_fnConvertToWidth,_fnGetWidestNode,_fnGetMaxLenString,_fnStringToCss,_fnSortFlatten,_fnSort,_fnSortAria,_fnSortListener,_fnSortAttachListener,_fnSortingClasses,_fnSortData,_fnSaveState,_fnLoadState,_fnSettingsFromNode,_fnLog,_fnMap,_fnBindAction,_fnCallbackReg,_fnCallbackFire,_fnLengthOverflow,_fnRenderer,_fnDataSource,_fnRowAttributes*/
38
+
39
+ (function( factory ) {
40
+ "use strict";
41
+
42
+ if ( typeof define === 'function' && define.amd ) {
43
+ // AMD
44
+ define( ['jquery'], function ( $ ) {
45
+ return factory( $, window, document );
46
+ } );
47
+ }
48
+ else if ( typeof exports === 'object' ) {
49
+ // CommonJS
50
+ module.exports = function (root, $) {
51
+ if ( ! root ) {
52
+ // CommonJS environments without a window global must pass a
53
+ // root. This will give an error otherwise
54
+ root = window;
55
+ }
56
+
57
+ if ( ! $ ) {
58
+ $ = typeof window !== 'undefined' ? // jQuery's factory checks for a global window
59
+ require('jquery') :
60
+ require('jquery')( root );
61
+ }
62
+
63
+ return factory( $, root, root.document );
64
+ };
65
+ }
66
+ else {
67
+ // Browser
68
+ factory( jQuery, window, document );
69
+ }
70
+ }
71
+ (function( $, window, document, undefined ) {
72
+ "use strict";
73
+
74
+ /**
75
+ * DataTables is a plug-in for the jQuery Javascript library. It is a highly
76
+ * flexible tool, based upon the foundations of progressive enhancement,
77
+ * which will add advanced interaction controls to any HTML table. For a
78
+ * full list of features please refer to
79
+ * [DataTables.net](href="http://datatables.net).
80
+ *
81
+ * Note that the `DataTable` object is not a global variable but is aliased
82
+ * to `jQuery.fn.DataTable` and `jQuery.fn.dataTable` through which it may
83
+ * be accessed.
84
+ *
85
+ * @class
86
+ * @param {object} [init={}] Configuration object for DataTables. Options
87
+ * are defined by {@link DataTable.defaults}
88
+ * @requires jQuery 1.7+
89
+ *
90
+ * @example
91
+ * // Basic initialisation
92
+ * $(document).ready( function {
93
+ * $('#example').dataTable();
94
+ * } );
95
+ *
96
+ * @example
97
+ * // Initialisation with configuration options - in this case, disable
98
+ * // pagination and sorting.
99
+ * $(document).ready( function {
100
+ * $('#example').dataTable( {
101
+ * "paginate": false,
102
+ * "sort": false
103
+ * } );
104
+ * } );
105
+ */
106
+ var DataTable = function ( options )
107
+ {
108
+ /**
109
+ * Perform a jQuery selector action on the table's TR elements (from the tbody) and
110
+ * return the resulting jQuery object.
111
+ * @param {string|node|jQuery} sSelector jQuery selector or node collection to act on
112
+ * @param {object} [oOpts] Optional parameters for modifying the rows to be included
113
+ * @param {string} [oOpts.filter=none] Select TR elements that meet the current filter
114
+ * criterion ("applied") or all TR elements (i.e. no filter).
115
+ * @param {string} [oOpts.order=current] Order of the TR elements in the processed array.
116
+ * Can be either 'current', whereby the current sorting of the table is used, or
117
+ * 'original' whereby the original order the data was read into the table is used.
118
+ * @param {string} [oOpts.page=all] Limit the selection to the currently displayed page
119
+ * ("current") or not ("all"). If 'current' is given, then order is assumed to be
120
+ * 'current' and filter is 'applied', regardless of what they might be given as.
121
+ * @returns {object} jQuery object, filtered by the given selector.
122
+ * @dtopt API
123
+ * @deprecated Since v1.10
124
+ *
125
+ * @example
126
+ * $(document).ready(function() {
127
+ * var oTable = $('#example').dataTable();
128
+ *
129
+ * // Highlight every second row
130
+ * oTable.$('tr:odd').css('backgroundColor', 'blue');
131
+ * } );
132
+ *
133
+ * @example
134
+ * $(document).ready(function() {
135
+ * var oTable = $('#example').dataTable();
136
+ *
137
+ * // Filter to rows with 'Webkit' in them, add a background colour and then
138
+ * // remove the filter, thus highlighting the 'Webkit' rows only.
139
+ * oTable.fnFilter('Webkit');
140
+ * oTable.$('tr', {"search": "applied"}).css('backgroundColor', 'blue');
141
+ * oTable.fnFilter('');
142
+ * } );
143
+ */
144
+ this.$ = function ( sSelector, oOpts )
145
+ {
146
+ return this.api(true).$( sSelector, oOpts );
147
+ };
148
+
149
+
150
+ /**
151
+ * Almost identical to $ in operation, but in this case returns the data for the matched
152
+ * rows - as such, the jQuery selector used should match TR row nodes or TD/TH cell nodes
153
+ * rather than any descendants, so the data can be obtained for the row/cell. If matching
154
+ * rows are found, the data returned is the original data array/object that was used to
155
+ * create the row (or a generated array if from a DOM source).
156
+ *
157
+ * This method is often useful in-combination with $ where both functions are given the
158
+ * same parameters and the array indexes will match identically.
159
+ * @param {string|node|jQuery} sSelector jQuery selector or node collection to act on
160
+ * @param {object} [oOpts] Optional parameters for modifying the rows to be included
161
+ * @param {string} [oOpts.filter=none] Select elements that meet the current filter
162
+ * criterion ("applied") or all elements (i.e. no filter).
163
+ * @param {string} [oOpts.order=current] Order of the data in the processed array.
164
+ * Can be either 'current', whereby the current sorting of the table is used, or
165
+ * 'original' whereby the original order the data was read into the table is used.
166
+ * @param {string} [oOpts.page=all] Limit the selection to the currently displayed page
167
+ * ("current") or not ("all"). If 'current' is given, then order is assumed to be
168
+ * 'current' and filter is 'applied', regardless of what they might be given as.
169
+ * @returns {array} Data for the matched elements. If any elements, as a result of the
170
+ * selector, were not TR, TD or TH elements in the DataTable, they will have a null
171
+ * entry in the array.
172
+ * @dtopt API
173
+ * @deprecated Since v1.10
174
+ *
175
+ * @example
176
+ * $(document).ready(function() {
177
+ * var oTable = $('#example').dataTable();
178
+ *
179
+ * // Get the data from the first row in the table
180
+ * var data = oTable._('tr:first');
181
+ *
182
+ * // Do something useful with the data
183
+ * alert( "First cell is: "+data[0] );
184
+ * } );
185
+ *
186
+ * @example
187
+ * $(document).ready(function() {
188
+ * var oTable = $('#example').dataTable();
189
+ *
190
+ * // Filter to 'Webkit' and get all data for
191
+ * oTable.fnFilter('Webkit');
192
+ * var data = oTable._('tr', {"search": "applied"});
193
+ *
194
+ * // Do something with the data
195
+ * alert( data.length+" rows matched the search" );
196
+ * } );
197
+ */
198
+ this._ = function ( sSelector, oOpts )
199
+ {
200
+ return this.api(true).rows( sSelector, oOpts ).data();
201
+ };
202
+
203
+
204
+ /**
205
+ * Create a DataTables Api instance, with the currently selected tables for
206
+ * the Api's context.
207
+ * @param {boolean} [traditional=false] Set the API instance's context to be
208
+ * only the table referred to by the `DataTable.ext.iApiIndex` option, as was
209
+ * used in the API presented by DataTables 1.9- (i.e. the traditional mode),
210
+ * or if all tables captured in the jQuery object should be used.
211
+ * @return {DataTables.Api}
212
+ */
213
+ this.api = function ( traditional )
214
+ {
215
+ return traditional ?
216
+ new _Api(
217
+ _fnSettingsFromNode( this[ _ext.iApiIndex ] )
218
+ ) :
219
+ new _Api( this );
220
+ };
221
+
222
+
223
+ /**
224
+ * Add a single new row or multiple rows of data to the table. Please note
225
+ * that this is suitable for client-side processing only - if you are using
226
+ * server-side processing (i.e. "bServerSide": true), then to add data, you
227
+ * must add it to the data source, i.e. the server-side, through an Ajax call.
228
+ * @param {array|object} data The data to be added to the table. This can be:
229
+ * <ul>
230
+ * <li>1D array of data - add a single row with the data provided</li>
231
+ * <li>2D array of arrays - add multiple rows in a single call</li>
232
+ * <li>object - data object when using <i>mData</i></li>
233
+ * <li>array of objects - multiple data objects when using <i>mData</i></li>
234
+ * </ul>
235
+ * @param {bool} [redraw=true] redraw the table or not
236
+ * @returns {array} An array of integers, representing the list of indexes in
237
+ * <i>aoData</i> ({@link DataTable.models.oSettings}) that have been added to
238
+ * the table.
239
+ * @dtopt API
240
+ * @deprecated Since v1.10
241
+ *
242
+ * @example
243
+ * // Global var for counter
244
+ * var giCount = 2;
245
+ *
246
+ * $(document).ready(function() {
247
+ * $('#example').dataTable();
248
+ * } );
249
+ *
250
+ * function fnClickAddRow() {
251
+ * $('#example').dataTable().fnAddData( [
252
+ * giCount+".1",
253
+ * giCount+".2",
254
+ * giCount+".3",
255
+ * giCount+".4" ]
256
+ * );
257
+ *
258
+ * giCount++;
259
+ * }
260
+ */
261
+ this.fnAddData = function( data, redraw )
262
+ {
263
+ var api = this.api( true );
264
+
265
+ /* Check if we want to add multiple rows or not */
266
+ var rows = $.isArray(data) && ( $.isArray(data[0]) || $.isPlainObject(data[0]) ) ?
267
+ api.rows.add( data ) :
268
+ api.row.add( data );
269
+
270
+ if ( redraw === undefined || redraw ) {
271
+ api.draw();
272
+ }
273
+
274
+ return rows.flatten().toArray();
275
+ };
276
+
277
+
278
+ /**
279
+ * This function will make DataTables recalculate the column sizes, based on the data
280
+ * contained in the table and the sizes applied to the columns (in the DOM, CSS or
281
+ * through the sWidth parameter). This can be useful when the width of the table's
282
+ * parent element changes (for example a window resize).
283
+ * @param {boolean} [bRedraw=true] Redraw the table or not, you will typically want to
284
+ * @dtopt API
285
+ * @deprecated Since v1.10
286
+ *
287
+ * @example
288
+ * $(document).ready(function() {
289
+ * var oTable = $('#example').dataTable( {
290
+ * "sScrollY": "200px",
291
+ * "bPaginate": false
292
+ * } );
293
+ *
294
+ * $(window).on('resize', function () {
295
+ * oTable.fnAdjustColumnSizing();
296
+ * } );
297
+ * } );
298
+ */
299
+ this.fnAdjustColumnSizing = function ( bRedraw )
300
+ {
301
+ var api = this.api( true ).columns.adjust();
302
+ var settings = api.settings()[0];
303
+ var scroll = settings.oScroll;
304
+
305
+ if ( bRedraw === undefined || bRedraw ) {
306
+ api.draw( false );
307
+ }
308
+ else if ( scroll.sX !== "" || scroll.sY !== "" ) {
309
+ /* If not redrawing, but scrolling, we want to apply the new column sizes anyway */
310
+ _fnScrollDraw( settings );
311
+ }
312
+ };
313
+
314
+
315
+ /**
316
+ * Quickly and simply clear a table
317
+ * @param {bool} [bRedraw=true] redraw the table or not
318
+ * @dtopt API
319
+ * @deprecated Since v1.10
320
+ *
321
+ * @example
322
+ * $(document).ready(function() {
323
+ * var oTable = $('#example').dataTable();
324
+ *
325
+ * // Immediately 'nuke' the current rows (perhaps waiting for an Ajax callback...)
326
+ * oTable.fnClearTable();
327
+ * } );
328
+ */
329
+ this.fnClearTable = function( bRedraw )
330
+ {
331
+ var api = this.api( true ).clear();
332
+
333
+ if ( bRedraw === undefined || bRedraw ) {
334
+ api.draw();
335
+ }
336
+ };
337
+
338
+
339
+ /**
340
+ * The exact opposite of 'opening' a row, this function will close any rows which
341
+ * are currently 'open'.
342
+ * @param {node} nTr the table row to 'close'
343
+ * @returns {int} 0 on success, or 1 if failed (can't find the row)
344
+ * @dtopt API
345
+ * @deprecated Since v1.10
346
+ *
347
+ * @example
348
+ * $(document).ready(function() {
349
+ * var oTable;
350
+ *
351
+ * // 'open' an information row when a row is clicked on
352
+ * $('#example tbody tr').click( function () {
353
+ * if ( oTable.fnIsOpen(this) ) {
354
+ * oTable.fnClose( this );
355
+ * } else {
356
+ * oTable.fnOpen( this, "Temporary row opened", "info_row" );
357
+ * }
358
+ * } );
359
+ *
360
+ * oTable = $('#example').dataTable();
361
+ * } );
362
+ */
363
+ this.fnClose = function( nTr )
364
+ {
365
+ this.api( true ).row( nTr ).child.hide();
366
+ };
367
+
368
+
369
+ /**
370
+ * Remove a row for the table
371
+ * @param {mixed} target The index of the row from aoData to be deleted, or
372
+ * the TR element you want to delete
373
+ * @param {function|null} [callBack] Callback function
374
+ * @param {bool} [redraw=true] Redraw the table or not
375
+ * @returns {array} The row that was deleted
376
+ * @dtopt API
377
+ * @deprecated Since v1.10
378
+ *
379
+ * @example
380
+ * $(document).ready(function() {
381
+ * var oTable = $('#example').dataTable();
382
+ *
383
+ * // Immediately remove the first row
384
+ * oTable.fnDeleteRow( 0 );
385
+ * } );
386
+ */
387
+ this.fnDeleteRow = function( target, callback, redraw )
388
+ {
389
+ var api = this.api( true );
390
+ var rows = api.rows( target );
391
+ var settings = rows.settings()[0];
392
+ var data = settings.aoData[ rows[0][0] ];
393
+
394
+ rows.remove();
395
+
396
+ if ( callback ) {
397
+ callback.call( this, settings, data );
398
+ }
399
+
400
+ if ( redraw === undefined || redraw ) {
401
+ api.draw();
402
+ }
403
+
404
+ return data;
405
+ };
406
+
407
+
408
+ /**
409
+ * Restore the table to it's original state in the DOM by removing all of DataTables
410
+ * enhancements, alterations to the DOM structure of the table and event listeners.
411
+ * @param {boolean} [remove=false] Completely remove the table from the DOM
412
+ * @dtopt API
413
+ * @deprecated Since v1.10
414
+ *
415
+ * @example
416
+ * $(document).ready(function() {
417
+ * // This example is fairly pointless in reality, but shows how fnDestroy can be used
418
+ * var oTable = $('#example').dataTable();
419
+ * oTable.fnDestroy();
420
+ * } );
421
+ */
422
+ this.fnDestroy = function ( remove )
423
+ {
424
+ this.api( true ).destroy( remove );
425
+ };
426
+
427
+
428
+ /**
429
+ * Redraw the table
430
+ * @param {bool} [complete=true] Re-filter and resort (if enabled) the table before the draw.
431
+ * @dtopt API
432
+ * @deprecated Since v1.10
433
+ *
434
+ * @example
435
+ * $(document).ready(function() {
436
+ * var oTable = $('#example').dataTable();
437
+ *
438
+ * // Re-draw the table - you wouldn't want to do it here, but it's an example :-)
439
+ * oTable.fnDraw();
440
+ * } );
441
+ */
442
+ this.fnDraw = function( complete )
443
+ {
444
+ // Note that this isn't an exact match to the old call to _fnDraw - it takes
445
+ // into account the new data, but can hold position.
446
+ this.api( true ).draw( complete );
447
+ };
448
+
449
+
450
+ /**
451
+ * Filter the input based on data
452
+ * @param {string} sInput String to filter the table on
453
+ * @param {int|null} [iColumn] Column to limit filtering to
454
+ * @param {bool} [bRegex=false] Treat as regular expression or not
455
+ * @param {bool} [bSmart=true] Perform smart filtering or not
456
+ * @param {bool} [bShowGlobal=true] Show the input global filter in it's input box(es)
457
+ * @param {bool} [bCaseInsensitive=true] Do case-insensitive matching (true) or not (false)
458
+ * @dtopt API
459
+ * @deprecated Since v1.10
460
+ *
461
+ * @example
462
+ * $(document).ready(function() {
463
+ * var oTable = $('#example').dataTable();
464
+ *
465
+ * // Sometime later - filter...
466
+ * oTable.fnFilter( 'test string' );
467
+ * } );
468
+ */
469
+ this.fnFilter = function( sInput, iColumn, bRegex, bSmart, bShowGlobal, bCaseInsensitive )
470
+ {
471
+ var api = this.api( true );
472
+
473
+ if ( iColumn === null || iColumn === undefined ) {
474
+ api.search( sInput, bRegex, bSmart, bCaseInsensitive );
475
+ }
476
+ else {
477
+ api.column( iColumn ).search( sInput, bRegex, bSmart, bCaseInsensitive );
478
+ }
479
+
480
+ api.draw();
481
+ };
482
+
483
+
484
+ /**
485
+ * Get the data for the whole table, an individual row or an individual cell based on the
486
+ * provided parameters.
487
+ * @param {int|node} [src] A TR row node, TD/TH cell node or an integer. If given as
488
+ * a TR node then the data source for the whole row will be returned. If given as a
489
+ * TD/TH cell node then iCol will be automatically calculated and the data for the
490
+ * cell returned. If given as an integer, then this is treated as the aoData internal
491
+ * data index for the row (see fnGetPosition) and the data for that row used.
492
+ * @param {int} [col] Optional column index that you want the data of.
493
+ * @returns {array|object|string} If mRow is undefined, then the data for all rows is
494
+ * returned. If mRow is defined, just data for that row, and is iCol is
495
+ * defined, only data for the designated cell is returned.
496
+ * @dtopt API
497
+ * @deprecated Since v1.10
498
+ *
499
+ * @example
500
+ * // Row data
501
+ * $(document).ready(function() {
502
+ * oTable = $('#example').dataTable();
503
+ *
504
+ * oTable.$('tr').click( function () {
505
+ * var data = oTable.fnGetData( this );
506
+ * // ... do something with the array / object of data for the row
507
+ * } );
508
+ * } );
509
+ *
510
+ * @example
511
+ * // Individual cell data
512
+ * $(document).ready(function() {
513
+ * oTable = $('#example').dataTable();
514
+ *
515
+ * oTable.$('td').click( function () {
516
+ * var sData = oTable.fnGetData( this );
517
+ * alert( 'The cell clicked on had the value of '+sData );
518
+ * } );
519
+ * } );
520
+ */
521
+ this.fnGetData = function( src, col )
522
+ {
523
+ var api = this.api( true );
524
+
525
+ if ( src !== undefined ) {
526
+ var type = src.nodeName ? src.nodeName.toLowerCase() : '';
527
+
528
+ return col !== undefined || type == 'td' || type == 'th' ?
529
+ api.cell( src, col ).data() :
530
+ api.row( src ).data() || null;
531
+ }
532
+
533
+ return api.data().toArray();
534
+ };
535
+
536
+
537
+ /**
538
+ * Get an array of the TR nodes that are used in the table's body. Note that you will
539
+ * typically want to use the '$' API method in preference to this as it is more
540
+ * flexible.
541
+ * @param {int} [iRow] Optional row index for the TR element you want
542
+ * @returns {array|node} If iRow is undefined, returns an array of all TR elements
543
+ * in the table's body, or iRow is defined, just the TR element requested.
544
+ * @dtopt API
545
+ * @deprecated Since v1.10
546
+ *
547
+ * @example
548
+ * $(document).ready(function() {
549
+ * var oTable = $('#example').dataTable();
550
+ *
551
+ * // Get the nodes from the table
552
+ * var nNodes = oTable.fnGetNodes( );
553
+ * } );
554
+ */
555
+ this.fnGetNodes = function( iRow )
556
+ {
557
+ var api = this.api( true );
558
+
559
+ return iRow !== undefined ?
560
+ api.row( iRow ).node() :
561
+ api.rows().nodes().flatten().toArray();
562
+ };
563
+
564
+
565
+ /**
566
+ * Get the array indexes of a particular cell from it's DOM element
567
+ * and column index including hidden columns
568
+ * @param {node} node this can either be a TR, TD or TH in the table's body
569
+ * @returns {int} If nNode is given as a TR, then a single index is returned, or
570
+ * if given as a cell, an array of [row index, column index (visible),
571
+ * column index (all)] is given.
572
+ * @dtopt API
573
+ * @deprecated Since v1.10
574
+ *
575
+ * @example
576
+ * $(document).ready(function() {
577
+ * $('#example tbody td').click( function () {
578
+ * // Get the position of the current data from the node
579
+ * var aPos = oTable.fnGetPosition( this );
580
+ *
581
+ * // Get the data array for this row
582
+ * var aData = oTable.fnGetData( aPos[0] );
583
+ *
584
+ * // Update the data array and return the value
585
+ * aData[ aPos[1] ] = 'clicked';
586
+ * this.innerHTML = 'clicked';
587
+ * } );
588
+ *
589
+ * // Init DataTables
590
+ * oTable = $('#example').dataTable();
591
+ * } );
592
+ */
593
+ this.fnGetPosition = function( node )
594
+ {
595
+ var api = this.api( true );
596
+ var nodeName = node.nodeName.toUpperCase();
597
+
598
+ if ( nodeName == 'TR' ) {
599
+ return api.row( node ).index();
600
+ }
601
+ else if ( nodeName == 'TD' || nodeName == 'TH' ) {
602
+ var cell = api.cell( node ).index();
603
+
604
+ return [
605
+ cell.row,
606
+ cell.columnVisible,
607
+ cell.column
608
+ ];
609
+ }
610
+ return null;
611
+ };
612
+
613
+
614
+ /**
615
+ * Check to see if a row is 'open' or not.
616
+ * @param {node} nTr the table row to check
617
+ * @returns {boolean} true if the row is currently open, false otherwise
618
+ * @dtopt API
619
+ * @deprecated Since v1.10
620
+ *
621
+ * @example
622
+ * $(document).ready(function() {
623
+ * var oTable;
624
+ *
625
+ * // 'open' an information row when a row is clicked on
626
+ * $('#example tbody tr').click( function () {
627
+ * if ( oTable.fnIsOpen(this) ) {
628
+ * oTable.fnClose( this );
629
+ * } else {
630
+ * oTable.fnOpen( this, "Temporary row opened", "info_row" );
631
+ * }
632
+ * } );
633
+ *
634
+ * oTable = $('#example').dataTable();
635
+ * } );
636
+ */
637
+ this.fnIsOpen = function( nTr )
638
+ {
639
+ return this.api( true ).row( nTr ).child.isShown();
640
+ };
641
+
642
+
643
+ /**
644
+ * This function will place a new row directly after a row which is currently
645
+ * on display on the page, with the HTML contents that is passed into the
646
+ * function. This can be used, for example, to ask for confirmation that a
647
+ * particular record should be deleted.
648
+ * @param {node} nTr The table row to 'open'
649
+ * @param {string|node|jQuery} mHtml The HTML to put into the row
650
+ * @param {string} sClass Class to give the new TD cell
651
+ * @returns {node} The row opened. Note that if the table row passed in as the
652
+ * first parameter, is not found in the table, this method will silently
653
+ * return.
654
+ * @dtopt API
655
+ * @deprecated Since v1.10
656
+ *
657
+ * @example
658
+ * $(document).ready(function() {
659
+ * var oTable;
660
+ *
661
+ * // 'open' an information row when a row is clicked on
662
+ * $('#example tbody tr').click( function () {
663
+ * if ( oTable.fnIsOpen(this) ) {
664
+ * oTable.fnClose( this );
665
+ * } else {
666
+ * oTable.fnOpen( this, "Temporary row opened", "info_row" );
667
+ * }
668
+ * } );
669
+ *
670
+ * oTable = $('#example').dataTable();
671
+ * } );
672
+ */
673
+ this.fnOpen = function( nTr, mHtml, sClass )
674
+ {
675
+ return this.api( true )
676
+ .row( nTr )
677
+ .child( mHtml, sClass )
678
+ .show()
679
+ .child()[0];
680
+ };
681
+
682
+
683
+ /**
684
+ * Change the pagination - provides the internal logic for pagination in a simple API
685
+ * function. With this function you can have a DataTables table go to the next,
686
+ * previous, first or last pages.
687
+ * @param {string|int} mAction Paging action to take: "first", "previous", "next" or "last"
688
+ * or page number to jump to (integer), note that page 0 is the first page.
689
+ * @param {bool} [bRedraw=true] Redraw the table or not
690
+ * @dtopt API
691
+ * @deprecated Since v1.10
692
+ *
693
+ * @example
694
+ * $(document).ready(function() {
695
+ * var oTable = $('#example').dataTable();
696
+ * oTable.fnPageChange( 'next' );
697
+ * } );
698
+ */
699
+ this.fnPageChange = function ( mAction, bRedraw )
700
+ {
701
+ var api = this.api( true ).page( mAction );
702
+
703
+ if ( bRedraw === undefined || bRedraw ) {
704
+ api.draw(false);
705
+ }
706
+ };
707
+
708
+
709
+ /**
710
+ * Show a particular column
711
+ * @param {int} iCol The column whose display should be changed
712
+ * @param {bool} bShow Show (true) or hide (false) the column
713
+ * @param {bool} [bRedraw=true] Redraw the table or not
714
+ * @dtopt API
715
+ * @deprecated Since v1.10
716
+ *
717
+ * @example
718
+ * $(document).ready(function() {
719
+ * var oTable = $('#example').dataTable();
720
+ *
721
+ * // Hide the second column after initialisation
722
+ * oTable.fnSetColumnVis( 1, false );
723
+ * } );
724
+ */
725
+ this.fnSetColumnVis = function ( iCol, bShow, bRedraw )
726
+ {
727
+ var api = this.api( true ).column( iCol ).visible( bShow );
728
+
729
+ if ( bRedraw === undefined || bRedraw ) {
730
+ api.columns.adjust().draw();
731
+ }
732
+ };
733
+
734
+
735
+ /**
736
+ * Get the settings for a particular table for external manipulation
737
+ * @returns {object} DataTables settings object. See
738
+ * {@link DataTable.models.oSettings}
739
+ * @dtopt API
740
+ * @deprecated Since v1.10
741
+ *
742
+ * @example
743
+ * $(document).ready(function() {
744
+ * var oTable = $('#example').dataTable();
745
+ * var oSettings = oTable.fnSettings();
746
+ *
747
+ * // Show an example parameter from the settings
748
+ * alert( oSettings._iDisplayStart );
749
+ * } );
750
+ */
751
+ this.fnSettings = function()
752
+ {
753
+ return _fnSettingsFromNode( this[_ext.iApiIndex] );
754
+ };
755
+
756
+
757
+ /**
758
+ * Sort the table by a particular column
759
+ * @param {int} iCol the data index to sort on. Note that this will not match the
760
+ * 'display index' if you have hidden data entries
761
+ * @dtopt API
762
+ * @deprecated Since v1.10
763
+ *
764
+ * @example
765
+ * $(document).ready(function() {
766
+ * var oTable = $('#example').dataTable();
767
+ *
768
+ * // Sort immediately with columns 0 and 1
769
+ * oTable.fnSort( [ [0,'asc'], [1,'asc'] ] );
770
+ * } );
771
+ */
772
+ this.fnSort = function( aaSort )
773
+ {
774
+ this.api( true ).order( aaSort ).draw();
775
+ };
776
+
777
+
778
+ /**
779
+ * Attach a sort listener to an element for a given column
780
+ * @param {node} nNode the element to attach the sort listener to
781
+ * @param {int} iColumn the column that a click on this node will sort on
782
+ * @param {function} [fnCallback] callback function when sort is run
783
+ * @dtopt API
784
+ * @deprecated Since v1.10
785
+ *
786
+ * @example
787
+ * $(document).ready(function() {
788
+ * var oTable = $('#example').dataTable();
789
+ *
790
+ * // Sort on column 1, when 'sorter' is clicked on
791
+ * oTable.fnSortListener( document.getElementById('sorter'), 1 );
792
+ * } );
793
+ */
794
+ this.fnSortListener = function( nNode, iColumn, fnCallback )
795
+ {
796
+ this.api( true ).order.listener( nNode, iColumn, fnCallback );
797
+ };
798
+
799
+
800
+ /**
801
+ * Update a table cell or row - this method will accept either a single value to
802
+ * update the cell with, an array of values with one element for each column or
803
+ * an object in the same format as the original data source. The function is
804
+ * self-referencing in order to make the multi column updates easier.
805
+ * @param {object|array|string} mData Data to update the cell/row with
806
+ * @param {node|int} mRow TR element you want to update or the aoData index
807
+ * @param {int} [iColumn] The column to update, give as null or undefined to
808
+ * update a whole row.
809
+ * @param {bool} [bRedraw=true] Redraw the table or not
810
+ * @param {bool} [bAction=true] Perform pre-draw actions or not
811
+ * @returns {int} 0 on success, 1 on error
812
+ * @dtopt API
813
+ * @deprecated Since v1.10
814
+ *
815
+ * @example
816
+ * $(document).ready(function() {
817
+ * var oTable = $('#example').dataTable();
818
+ * oTable.fnUpdate( 'Example update', 0, 0 ); // Single cell
819
+ * oTable.fnUpdate( ['a', 'b', 'c', 'd', 'e'], $('tbody tr')[0] ); // Row
820
+ * } );
821
+ */
822
+ this.fnUpdate = function( mData, mRow, iColumn, bRedraw, bAction )
823
+ {
824
+ var api = this.api( true );
825
+
826
+ if ( iColumn === undefined || iColumn === null ) {
827
+ api.row( mRow ).data( mData );
828
+ }
829
+ else {
830
+ api.cell( mRow, iColumn ).data( mData );
831
+ }
832
+
833
+ if ( bAction === undefined || bAction ) {
834
+ api.columns.adjust();
835
+ }
836
+
837
+ if ( bRedraw === undefined || bRedraw ) {
838
+ api.draw();
839
+ }
840
+ return 0;
841
+ };
842
+
843
+
844
+ /**
845
+ * Provide a common method for plug-ins to check the version of DataTables being used, in order
846
+ * to ensure compatibility.
847
+ * @param {string} sVersion Version string to check for, in the format "X.Y.Z". Note that the
848
+ * formats "X" and "X.Y" are also acceptable.
849
+ * @returns {boolean} true if this version of DataTables is greater or equal to the required
850
+ * version, or false if this version of DataTales is not suitable
851
+ * @method
852
+ * @dtopt API
853
+ * @deprecated Since v1.10
854
+ *
855
+ * @example
856
+ * $(document).ready(function() {
857
+ * var oTable = $('#example').dataTable();
858
+ * alert( oTable.fnVersionCheck( '1.9.0' ) );
859
+ * } );
860
+ */
861
+ this.fnVersionCheck = _ext.fnVersionCheck;
862
+
863
+
864
+ var _that = this;
865
+ var emptyInit = options === undefined;
866
+ var len = this.length;
867
+
868
+ if ( emptyInit ) {
869
+ options = {};
870
+ }
871
+
872
+ this.oApi = this.internal = _ext.internal;
873
+
874
+ // Extend with old style plug-in API methods
875
+ for ( var fn in DataTable.ext.internal ) {
876
+ if ( fn ) {
877
+ this[fn] = _fnExternApiFunc(fn);
878
+ }
879
+ }
880
+
881
+ this.each(function() {
882
+ // For each initialisation we want to give it a clean initialisation
883
+ // object that can be bashed around
884
+ var o = {};
885
+ var oInit = len > 1 ? // optimisation for single table case
886
+ _fnExtend( o, options, true ) :
887
+ options;
888
+
889
+ /*global oInit,_that,emptyInit*/
890
+ var i=0, iLen, j, jLen, k, kLen;
891
+ var sId = this.getAttribute( 'id' );
892
+ var bInitHandedOff = false;
893
+ var defaults = DataTable.defaults;
894
+ var $this = $(this);
895
+
896
+
897
+ /* Sanity check */
898
+ if ( this.nodeName.toLowerCase() != 'table' )
899
+ {
900
+ _fnLog( null, 0, 'Non-table node initialisation ('+this.nodeName+')', 2 );
901
+ return;
902
+ }
903
+
904
+ /* Backwards compatibility for the defaults */
905
+ _fnCompatOpts( defaults );
906
+ _fnCompatCols( defaults.column );
907
+
908
+ /* Convert the camel-case defaults to Hungarian */
909
+ _fnCamelToHungarian( defaults, defaults, true );
910
+ _fnCamelToHungarian( defaults.column, defaults.column, true );
911
+
912
+ /* Setting up the initialisation object */
913
+ _fnCamelToHungarian( defaults, $.extend( oInit, $this.data() ) );
914
+
915
+
916
+
917
+ /* Check to see if we are re-initialising a table */
918
+ var allSettings = DataTable.settings;
919
+ for ( i=0, iLen=allSettings.length ; i<iLen ; i++ )
920
+ {
921
+ var s = allSettings[i];
922
+
923
+ /* Base check on table node */
924
+ if ( s.nTable == this || s.nTHead.parentNode == this || (s.nTFoot && s.nTFoot.parentNode == this) )
925
+ {
926
+ var bRetrieve = oInit.bRetrieve !== undefined ? oInit.bRetrieve : defaults.bRetrieve;
927
+ var bDestroy = oInit.bDestroy !== undefined ? oInit.bDestroy : defaults.bDestroy;
928
+
929
+ if ( emptyInit || bRetrieve )
930
+ {
931
+ return s.oInstance;
932
+ }
933
+ else if ( bDestroy )
934
+ {
935
+ s.oInstance.fnDestroy();
936
+ break;
937
+ }
938
+ else
939
+ {
940
+ _fnLog( s, 0, 'Cannot reinitialise DataTable', 3 );
941
+ return;
942
+ }
943
+ }
944
+
945
+ /* If the element we are initialising has the same ID as a table which was previously
946
+ * initialised, but the table nodes don't match (from before) then we destroy the old
947
+ * instance by simply deleting it. This is under the assumption that the table has been
948
+ * destroyed by other methods. Anyone using non-id selectors will need to do this manually
949
+ */
950
+ if ( s.sTableId == this.id )
951
+ {
952
+ allSettings.splice( i, 1 );
953
+ break;
954
+ }
955
+ }
956
+
957
+ /* Ensure the table has an ID - required for accessibility */
958
+ if ( sId === null || sId === "" )
959
+ {
960
+ sId = "DataTables_Table_"+(DataTable.ext._unique++);
961
+ this.id = sId;
962
+ }
963
+
964
+ /* Create the settings object for this table and set some of the default parameters */
965
+ var oSettings = $.extend( true, {}, DataTable.models.oSettings, {
966
+ "sDestroyWidth": $this[0].style.width,
967
+ "sInstance": sId,
968
+ "sTableId": sId
969
+ } );
970
+ oSettings.nTable = this;
971
+ oSettings.oApi = _that.internal;
972
+ oSettings.oInit = oInit;
973
+
974
+ allSettings.push( oSettings );
975
+
976
+ // Need to add the instance after the instance after the settings object has been added
977
+ // to the settings array, so we can self reference the table instance if more than one
978
+ oSettings.oInstance = (_that.length===1) ? _that : $this.dataTable();
979
+
980
+ // Backwards compatibility, before we apply all the defaults
981
+ _fnCompatOpts( oInit );
982
+
983
+ if ( oInit.oLanguage )
984
+ {
985
+ _fnLanguageCompat( oInit.oLanguage );
986
+ }
987
+
988
+ // If the length menu is given, but the init display length is not, use the length menu
989
+ if ( oInit.aLengthMenu && ! oInit.iDisplayLength )
990
+ {
991
+ oInit.iDisplayLength = $.isArray( oInit.aLengthMenu[0] ) ?
992
+ oInit.aLengthMenu[0][0] : oInit.aLengthMenu[0];
993
+ }
994
+
995
+ // Apply the defaults and init options to make a single init object will all
996
+ // options defined from defaults and instance options.
997
+ oInit = _fnExtend( $.extend( true, {}, defaults ), oInit );
998
+
999
+
1000
+ // Map the initialisation options onto the settings object
1001
+ _fnMap( oSettings.oFeatures, oInit, [
1002
+ "bPaginate",
1003
+ "bLengthChange",
1004
+ "bFilter",
1005
+ "bSort",
1006
+ "bSortMulti",
1007
+ "bInfo",
1008
+ "bProcessing",
1009
+ "bAutoWidth",
1010
+ "bSortClasses",
1011
+ "bServerSide",
1012
+ "bDeferRender"
1013
+ ] );
1014
+ _fnMap( oSettings, oInit, [
1015
+ "asStripeClasses",
1016
+ "ajax",
1017
+ "fnServerData",
1018
+ "fnFormatNumber",
1019
+ "sServerMethod",
1020
+ "aaSorting",
1021
+ "aaSortingFixed",
1022
+ "aLengthMenu",
1023
+ "sPaginationType",
1024
+ "sAjaxSource",
1025
+ "sAjaxDataProp",
1026
+ "iStateDuration",
1027
+ "sDom",
1028
+ "bSortCellsTop",
1029
+ "iTabIndex",
1030
+ "fnStateLoadCallback",
1031
+ "fnStateSaveCallback",
1032
+ "renderer",
1033
+ "searchDelay",
1034
+ "rowId",
1035
+ [ "iCookieDuration", "iStateDuration" ], // backwards compat
1036
+ [ "oSearch", "oPreviousSearch" ],
1037
+ [ "aoSearchCols", "aoPreSearchCols" ],
1038
+ [ "iDisplayLength", "_iDisplayLength" ]
1039
+ ] );
1040
+ _fnMap( oSettings.oScroll, oInit, [
1041
+ [ "sScrollX", "sX" ],
1042
+ [ "sScrollXInner", "sXInner" ],
1043
+ [ "sScrollY", "sY" ],
1044
+ [ "bScrollCollapse", "bCollapse" ]
1045
+ ] );
1046
+ _fnMap( oSettings.oLanguage, oInit, "fnInfoCallback" );
1047
+
1048
+ /* Callback functions which are array driven */
1049
+ _fnCallbackReg( oSettings, 'aoDrawCallback', oInit.fnDrawCallback, 'user' );
1050
+ _fnCallbackReg( oSettings, 'aoServerParams', oInit.fnServerParams, 'user' );
1051
+ _fnCallbackReg( oSettings, 'aoStateSaveParams', oInit.fnStateSaveParams, 'user' );
1052
+ _fnCallbackReg( oSettings, 'aoStateLoadParams', oInit.fnStateLoadParams, 'user' );
1053
+ _fnCallbackReg( oSettings, 'aoStateLoaded', oInit.fnStateLoaded, 'user' );
1054
+ _fnCallbackReg( oSettings, 'aoRowCallback', oInit.fnRowCallback, 'user' );
1055
+ _fnCallbackReg( oSettings, 'aoRowCreatedCallback', oInit.fnCreatedRow, 'user' );
1056
+ _fnCallbackReg( oSettings, 'aoHeaderCallback', oInit.fnHeaderCallback, 'user' );
1057
+ _fnCallbackReg( oSettings, 'aoFooterCallback', oInit.fnFooterCallback, 'user' );
1058
+ _fnCallbackReg( oSettings, 'aoInitComplete', oInit.fnInitComplete, 'user' );
1059
+ _fnCallbackReg( oSettings, 'aoPreDrawCallback', oInit.fnPreDrawCallback, 'user' );
1060
+
1061
+ oSettings.rowIdFn = _fnGetObjectDataFn( oInit.rowId );
1062
+
1063
+ /* Browser support detection */
1064
+ _fnBrowserDetect( oSettings );
1065
+
1066
+ var oClasses = oSettings.oClasses;
1067
+
1068
+ $.extend( oClasses, DataTable.ext.classes, oInit.oClasses );
1069
+ $this.addClass( oClasses.sTable );
1070
+
1071
+
1072
+ if ( oSettings.iInitDisplayStart === undefined )
1073
+ {
1074
+ /* Display start point, taking into account the save saving */
1075
+ oSettings.iInitDisplayStart = oInit.iDisplayStart;
1076
+ oSettings._iDisplayStart = oInit.iDisplayStart;
1077
+ }
1078
+
1079
+ if ( oInit.iDeferLoading !== null )
1080
+ {
1081
+ oSettings.bDeferLoading = true;
1082
+ var tmp = $.isArray( oInit.iDeferLoading );
1083
+ oSettings._iRecordsDisplay = tmp ? oInit.iDeferLoading[0] : oInit.iDeferLoading;
1084
+ oSettings._iRecordsTotal = tmp ? oInit.iDeferLoading[1] : oInit.iDeferLoading;
1085
+ }
1086
+
1087
+ /* Language definitions */
1088
+ var oLanguage = oSettings.oLanguage;
1089
+ $.extend( true, oLanguage, oInit.oLanguage );
1090
+
1091
+ if ( oLanguage.sUrl )
1092
+ {
1093
+ /* Get the language definitions from a file - because this Ajax call makes the language
1094
+ * get async to the remainder of this function we use bInitHandedOff to indicate that
1095
+ * _fnInitialise will be fired by the returned Ajax handler, rather than the constructor
1096
+ */
1097
+ $.ajax( {
1098
+ dataType: 'json',
1099
+ url: oLanguage.sUrl,
1100
+ success: function ( json ) {
1101
+ _fnLanguageCompat( json );
1102
+ _fnCamelToHungarian( defaults.oLanguage, json );
1103
+ $.extend( true, oLanguage, json );
1104
+ _fnInitialise( oSettings );
1105
+ },
1106
+ error: function () {
1107
+ // Error occurred loading language file, continue on as best we can
1108
+ _fnInitialise( oSettings );
1109
+ }
1110
+ } );
1111
+ bInitHandedOff = true;
1112
+ }
1113
+
1114
+ /*
1115
+ * Stripes
1116
+ */
1117
+ if ( oInit.asStripeClasses === null )
1118
+ {
1119
+ oSettings.asStripeClasses =[
1120
+ oClasses.sStripeOdd,
1121
+ oClasses.sStripeEven
1122
+ ];
1123
+ }
1124
+
1125
+ /* Remove row stripe classes if they are already on the table row */
1126
+ var stripeClasses = oSettings.asStripeClasses;
1127
+ var rowOne = $this.children('tbody').find('tr').eq(0);
1128
+ if ( $.inArray( true, $.map( stripeClasses, function(el, i) {
1129
+ return rowOne.hasClass(el);
1130
+ } ) ) !== -1 ) {
1131
+ $('tbody tr', this).removeClass( stripeClasses.join(' ') );
1132
+ oSettings.asDestroyStripes = stripeClasses.slice();
1133
+ }
1134
+
1135
+ /*
1136
+ * Columns
1137
+ * See if we should load columns automatically or use defined ones
1138
+ */
1139
+ var anThs = [];
1140
+ var aoColumnsInit;
1141
+ var nThead = this.getElementsByTagName('thead');
1142
+ if ( nThead.length !== 0 )
1143
+ {
1144
+ _fnDetectHeader( oSettings.aoHeader, nThead[0] );
1145
+ anThs = _fnGetUniqueThs( oSettings );
1146
+ }
1147
+
1148
+ /* If not given a column array, generate one with nulls */
1149
+ if ( oInit.aoColumns === null )
1150
+ {
1151
+ aoColumnsInit = [];
1152
+ for ( i=0, iLen=anThs.length ; i<iLen ; i++ )
1153
+ {
1154
+ aoColumnsInit.push( null );
1155
+ }
1156
+ }
1157
+ else
1158
+ {
1159
+ aoColumnsInit = oInit.aoColumns;
1160
+ }
1161
+
1162
+ /* Add the columns */
1163
+ for ( i=0, iLen=aoColumnsInit.length ; i<iLen ; i++ )
1164
+ {
1165
+ _fnAddColumn( oSettings, anThs ? anThs[i] : null );
1166
+ }
1167
+
1168
+ /* Apply the column definitions */
1169
+ _fnApplyColumnDefs( oSettings, oInit.aoColumnDefs, aoColumnsInit, function (iCol, oDef) {
1170
+ _fnColumnOptions( oSettings, iCol, oDef );
1171
+ } );
1172
+
1173
+ /* HTML5 attribute detection - build an mData object automatically if the
1174
+ * attributes are found
1175
+ */
1176
+ if ( rowOne.length ) {
1177
+ var a = function ( cell, name ) {
1178
+ return cell.getAttribute( 'data-'+name ) !== null ? name : null;
1179
+ };
1180
+
1181
+ $( rowOne[0] ).children('th, td').each( function (i, cell) {
1182
+ var col = oSettings.aoColumns[i];
1183
+
1184
+ if ( col.mData === i ) {
1185
+ var sort = a( cell, 'sort' ) || a( cell, 'order' );
1186
+ var filter = a( cell, 'filter' ) || a( cell, 'search' );
1187
+
1188
+ if ( sort !== null || filter !== null ) {
1189
+ col.mData = {
1190
+ _: i+'.display',
1191
+ sort: sort !== null ? i+'.@data-'+sort : undefined,
1192
+ type: sort !== null ? i+'.@data-'+sort : undefined,
1193
+ filter: filter !== null ? i+'.@data-'+filter : undefined
1194
+ };
1195
+
1196
+ _fnColumnOptions( oSettings, i );
1197
+ }
1198
+ }
1199
+ } );
1200
+ }
1201
+
1202
+ var features = oSettings.oFeatures;
1203
+ var loadedInit = function () {
1204
+ /*
1205
+ * Sorting
1206
+ * @todo For modularisation (1.11) this needs to do into a sort start up handler
1207
+ */
1208
+
1209
+ // If aaSorting is not defined, then we use the first indicator in asSorting
1210
+ // in case that has been altered, so the default sort reflects that option
1211
+ if ( oInit.aaSorting === undefined ) {
1212
+ var sorting = oSettings.aaSorting;
1213
+ for ( i=0, iLen=sorting.length ; i<iLen ; i++ ) {
1214
+ sorting[i][1] = oSettings.aoColumns[ i ].asSorting[0];
1215
+ }
1216
+ }
1217
+
1218
+ /* Do a first pass on the sorting classes (allows any size changes to be taken into
1219
+ * account, and also will apply sorting disabled classes if disabled
1220
+ */
1221
+ _fnSortingClasses( oSettings );
1222
+
1223
+ if ( features.bSort ) {
1224
+ _fnCallbackReg( oSettings, 'aoDrawCallback', function () {
1225
+ if ( oSettings.bSorted ) {
1226
+ var aSort = _fnSortFlatten( oSettings );
1227
+ var sortedColumns = {};
1228
+
1229
+ $.each( aSort, function (i, val) {
1230
+ sortedColumns[ val.src ] = val.dir;
1231
+ } );
1232
+
1233
+ _fnCallbackFire( oSettings, null, 'order', [oSettings, aSort, sortedColumns] );
1234
+ _fnSortAria( oSettings );
1235
+ }
1236
+ } );
1237
+ }
1238
+
1239
+ _fnCallbackReg( oSettings, 'aoDrawCallback', function () {
1240
+ if ( oSettings.bSorted || _fnDataSource( oSettings ) === 'ssp' || features.bDeferRender ) {
1241
+ _fnSortingClasses( oSettings );
1242
+ }
1243
+ }, 'sc' );
1244
+
1245
+
1246
+ /*
1247
+ * Final init
1248
+ * Cache the header, body and footer as required, creating them if needed
1249
+ */
1250
+
1251
+ // Work around for Webkit bug 83867 - store the caption-side before removing from doc
1252
+ var captions = $this.children('caption').each( function () {
1253
+ this._captionSide = $(this).css('caption-side');
1254
+ } );
1255
+
1256
+ var thead = $this.children('thead');
1257
+ if ( thead.length === 0 ) {
1258
+ thead = $('<thead/>').appendTo($this);
1259
+ }
1260
+ oSettings.nTHead = thead[0];
1261
+
1262
+ var tbody = $this.children('tbody');
1263
+ if ( tbody.length === 0 ) {
1264
+ tbody = $('<tbody/>').appendTo($this);
1265
+ }
1266
+ oSettings.nTBody = tbody[0];
1267
+
1268
+ var tfoot = $this.children('tfoot');
1269
+ if ( tfoot.length === 0 && captions.length > 0 && (oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "") ) {
1270
+ // If we are a scrolling table, and no footer has been given, then we need to create
1271
+ // a tfoot element for the caption element to be appended to
1272
+ tfoot = $('<tfoot/>').appendTo($this);
1273
+ }
1274
+
1275
+ if ( tfoot.length === 0 || tfoot.children().length === 0 ) {
1276
+ $this.addClass( oClasses.sNoFooter );
1277
+ }
1278
+ else if ( tfoot.length > 0 ) {
1279
+ oSettings.nTFoot = tfoot[0];
1280
+ _fnDetectHeader( oSettings.aoFooter, oSettings.nTFoot );
1281
+ }
1282
+
1283
+ /* Check if there is data passing into the constructor */
1284
+ if ( oInit.aaData ) {
1285
+ for ( i=0 ; i<oInit.aaData.length ; i++ ) {
1286
+ _fnAddData( oSettings, oInit.aaData[ i ] );
1287
+ }
1288
+ }
1289
+ else if ( oSettings.bDeferLoading || _fnDataSource( oSettings ) == 'dom' ) {
1290
+ /* Grab the data from the page - only do this when deferred loading or no Ajax
1291
+ * source since there is no point in reading the DOM data if we are then going
1292
+ * to replace it with Ajax data
1293
+ */
1294
+ _fnAddTr( oSettings, $(oSettings.nTBody).children('tr') );
1295
+ }
1296
+
1297
+ /* Copy the data index array */
1298
+ oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
1299
+
1300
+ /* Initialisation complete - table can be drawn */
1301
+ oSettings.bInitialised = true;
1302
+
1303
+ /* Check if we need to initialise the table (it might not have been handed off to the
1304
+ * language processor)
1305
+ */
1306
+ if ( bInitHandedOff === false ) {
1307
+ _fnInitialise( oSettings );
1308
+ }
1309
+ };
1310
+
1311
+ /* Must be done after everything which can be overridden by the state saving! */
1312
+ if ( oInit.bStateSave )
1313
+ {
1314
+ features.bStateSave = true;
1315
+ _fnCallbackReg( oSettings, 'aoDrawCallback', _fnSaveState, 'state_save' );
1316
+ _fnLoadState( oSettings, oInit, loadedInit );
1317
+ }
1318
+ else {
1319
+ loadedInit();
1320
+ }
1321
+
1322
+ } );
1323
+ _that = null;
1324
+ return this;
1325
+ };
1326
+
1327
+
1328
+ /*
1329
+ * It is useful to have variables which are scoped locally so only the
1330
+ * DataTables functions can access them and they don't leak into global space.
1331
+ * At the same time these functions are often useful over multiple files in the
1332
+ * core and API, so we list, or at least document, all variables which are used
1333
+ * by DataTables as private variables here. This also ensures that there is no
1334
+ * clashing of variable names and that they can easily referenced for reuse.
1335
+ */
1336
+
1337
+
1338
+ // Defined else where
1339
+ // _selector_run
1340
+ // _selector_opts
1341
+ // _selector_first
1342
+ // _selector_row_indexes
1343
+
1344
+ var _ext; // DataTable.ext
1345
+ var _Api; // DataTable.Api
1346
+ var _api_register; // DataTable.Api.register
1347
+ var _api_registerPlural; // DataTable.Api.registerPlural
1348
+
1349
+ var _re_dic = {};
1350
+ var _re_new_lines = /[\r\n]/g;
1351
+ var _re_html = /<.*?>/g;
1352
+
1353
+ // This is not strict ISO8601 - Date.parse() is quite lax, although
1354
+ // implementations differ between browsers.
1355
+ var _re_date = /^\d{2,4}[\.\/\-]\d{1,2}[\.\/\-]\d{1,2}([T ]{1}\d{1,2}[:\.]\d{2}([\.:]\d{2})?)?$/;
1356
+
1357
+ // Escape regular expression special characters
1358
+ var _re_escape_regex = new RegExp( '(\\' + [ '/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\', '$', '^', '-' ].join('|\\') + ')', 'g' );
1359
+
1360
+ // http://en.wikipedia.org/wiki/Foreign_exchange_market
1361
+ // - \u20BD - Russian ruble.
1362
+ // - \u20a9 - South Korean Won
1363
+ // - \u20BA - Turkish Lira
1364
+ // - \u20B9 - Indian Rupee
1365
+ // - R - Brazil (R$) and South Africa
1366
+ // - fr - Swiss Franc
1367
+ // - kr - Swedish krona, Norwegian krone and Danish krone
1368
+ // - \u2009 is thin space and \u202F is narrow no-break space, both used in many
1369
+ // standards as thousands separators.
1370
+ var _re_formatted_numeric = /[',$£€¥%\u2009\u202F\u20BD\u20a9\u20BArfk]/gi;
1371
+
1372
+
1373
+ var _empty = function ( d ) {
1374
+ return !d || d === true || d === '-' ? true : false;
1375
+ };
1376
+
1377
+
1378
+ var _intVal = function ( s ) {
1379
+ var integer = parseInt( s, 10 );
1380
+ return !isNaN(integer) && isFinite(s) ? integer : null;
1381
+ };
1382
+
1383
+ // Convert from a formatted number with characters other than `.` as the
1384
+ // decimal place, to a Javascript number
1385
+ var _numToDecimal = function ( num, decimalPoint ) {
1386
+ // Cache created regular expressions for speed as this function is called often
1387
+ if ( ! _re_dic[ decimalPoint ] ) {
1388
+ _re_dic[ decimalPoint ] = new RegExp( _fnEscapeRegex( decimalPoint ), 'g' );
1389
+ }
1390
+ return typeof num === 'string' && decimalPoint !== '.' ?
1391
+ num.replace( /\./g, '' ).replace( _re_dic[ decimalPoint ], '.' ) :
1392
+ num;
1393
+ };
1394
+
1395
+
1396
+ var _isNumber = function ( d, decimalPoint, formatted ) {
1397
+ var strType = typeof d === 'string';
1398
+
1399
+ // If empty return immediately so there must be a number if it is a
1400
+ // formatted string (this stops the string "k", or "kr", etc being detected
1401
+ // as a formatted number for currency
1402
+ if ( _empty( d ) ) {
1403
+ return true;
1404
+ }
1405
+
1406
+ if ( decimalPoint && strType ) {
1407
+ d = _numToDecimal( d, decimalPoint );
1408
+ }
1409
+
1410
+ if ( formatted && strType ) {
1411
+ d = d.replace( _re_formatted_numeric, '' );
1412
+ }
1413
+
1414
+ return !isNaN( parseFloat(d) ) && isFinite( d );
1415
+ };
1416
+
1417
+
1418
+ // A string without HTML in it can be considered to be HTML still
1419
+ var _isHtml = function ( d ) {
1420
+ return _empty( d ) || typeof d === 'string';
1421
+ };
1422
+
1423
+
1424
+ var _htmlNumeric = function ( d, decimalPoint, formatted ) {
1425
+ if ( _empty( d ) ) {
1426
+ return true;
1427
+ }
1428
+
1429
+ var html = _isHtml( d );
1430
+ return ! html ?
1431
+ null :
1432
+ _isNumber( _stripHtml( d ), decimalPoint, formatted ) ?
1433
+ true :
1434
+ null;
1435
+ };
1436
+
1437
+
1438
+ var _pluck = function ( a, prop, prop2 ) {
1439
+ var out = [];
1440
+ var i=0, ien=a.length;
1441
+
1442
+ // Could have the test in the loop for slightly smaller code, but speed
1443
+ // is essential here
1444
+ if ( prop2 !== undefined ) {
1445
+ for ( ; i<ien ; i++ ) {
1446
+ if ( a[i] && a[i][ prop ] ) {
1447
+ out.push( a[i][ prop ][ prop2 ] );
1448
+ }
1449
+ }
1450
+ }
1451
+ else {
1452
+ for ( ; i<ien ; i++ ) {
1453
+ if ( a[i] ) {
1454
+ out.push( a[i][ prop ] );
1455
+ }
1456
+ }
1457
+ }
1458
+
1459
+ return out;
1460
+ };
1461
+
1462
+
1463
+ // Basically the same as _pluck, but rather than looping over `a` we use `order`
1464
+ // as the indexes to pick from `a`
1465
+ var _pluck_order = function ( a, order, prop, prop2 )
1466
+ {
1467
+ var out = [];
1468
+ var i=0, ien=order.length;
1469
+
1470
+ // Could have the test in the loop for slightly smaller code, but speed
1471
+ // is essential here
1472
+ if ( prop2 !== undefined ) {
1473
+ for ( ; i<ien ; i++ ) {
1474
+ if ( a[ order[i] ][ prop ] ) {
1475
+ out.push( a[ order[i] ][ prop ][ prop2 ] );
1476
+ }
1477
+ }
1478
+ }
1479
+ else {
1480
+ for ( ; i<ien ; i++ ) {
1481
+ out.push( a[ order[i] ][ prop ] );
1482
+ }
1483
+ }
1484
+
1485
+ return out;
1486
+ };
1487
+
1488
+
1489
+ var _range = function ( len, start )
1490
+ {
1491
+ var out = [];
1492
+ var end;
1493
+
1494
+ if ( start === undefined ) {
1495
+ start = 0;
1496
+ end = len;
1497
+ }
1498
+ else {
1499
+ end = start;
1500
+ start = len;
1501
+ }
1502
+
1503
+ for ( var i=start ; i<end ; i++ ) {
1504
+ out.push( i );
1505
+ }
1506
+
1507
+ return out;
1508
+ };
1509
+
1510
+
1511
+ var _removeEmpty = function ( a )
1512
+ {
1513
+ var out = [];
1514
+
1515
+ for ( var i=0, ien=a.length ; i<ien ; i++ ) {
1516
+ if ( a[i] ) { // careful - will remove all falsy values!
1517
+ out.push( a[i] );
1518
+ }
1519
+ }
1520
+
1521
+ return out;
1522
+ };
1523
+
1524
+
1525
+ var _stripHtml = function ( d ) {
1526
+ return d.replace( _re_html, '' );
1527
+ };
1528
+
1529
+
1530
+ /**
1531
+ * Determine if all values in the array are unique. This means we can short
1532
+ * cut the _unique method at the cost of a single loop. A sorted array is used
1533
+ * to easily check the values.
1534
+ *
1535
+ * @param {array} src Source array
1536
+ * @return {boolean} true if all unique, false otherwise
1537
+ * @ignore
1538
+ */
1539
+ var _areAllUnique = function ( src ) {
1540
+ if ( src.length < 2 ) {
1541
+ return true;
1542
+ }
1543
+
1544
+ var sorted = src.slice().sort();
1545
+ var last = sorted[0];
1546
+
1547
+ for ( var i=1, ien=sorted.length ; i<ien ; i++ ) {
1548
+ if ( sorted[i] === last ) {
1549
+ return false;
1550
+ }
1551
+
1552
+ last = sorted[i];
1553
+ }
1554
+
1555
+ return true;
1556
+ };
1557
+
1558
+
1559
+ /**
1560
+ * Find the unique elements in a source array.
1561
+ *
1562
+ * @param {array} src Source array
1563
+ * @return {array} Array of unique items
1564
+ * @ignore
1565
+ */
1566
+ var _unique = function ( src )
1567
+ {
1568
+ if ( _areAllUnique( src ) ) {
1569
+ return src.slice();
1570
+ }
1571
+
1572
+ // A faster unique method is to use object keys to identify used values,
1573
+ // but this doesn't work with arrays or objects, which we must also
1574
+ // consider. See jsperf.com/compare-array-unique-versions/4 for more
1575
+ // information.
1576
+ var
1577
+ out = [],
1578
+ val,
1579
+ i, ien=src.length,
1580
+ j, k=0;
1581
+
1582
+ again: for ( i=0 ; i<ien ; i++ ) {
1583
+ val = src[i];
1584
+
1585
+ for ( j=0 ; j<k ; j++ ) {
1586
+ if ( out[j] === val ) {
1587
+ continue again;
1588
+ }
1589
+ }
1590
+
1591
+ out.push( val );
1592
+ k++;
1593
+ }
1594
+
1595
+ return out;
1596
+ };
1597
+
1598
+
1599
+ /**
1600
+ * DataTables utility methods
1601
+ *
1602
+ * This namespace provides helper methods that DataTables uses internally to
1603
+ * create a DataTable, but which are not exclusively used only for DataTables.
1604
+ * These methods can be used by extension authors to save the duplication of
1605
+ * code.
1606
+ *
1607
+ * @namespace
1608
+ */
1609
+ DataTable.util = {
1610
+ /**
1611
+ * Throttle the calls to a function. Arguments and context are maintained
1612
+ * for the throttled function.
1613
+ *
1614
+ * @param {function} fn Function to be called
1615
+ * @param {integer} freq Call frequency in mS
1616
+ * @return {function} Wrapped function
1617
+ */
1618
+ throttle: function ( fn, freq ) {
1619
+ var
1620
+ frequency = freq !== undefined ? freq : 200,
1621
+ last,
1622
+ timer;
1623
+
1624
+ return function () {
1625
+ var
1626
+ that = this,
1627
+ now = +new Date(),
1628
+ args = arguments;
1629
+
1630
+ if ( last && now < last + frequency ) {
1631
+ clearTimeout( timer );
1632
+
1633
+ timer = setTimeout( function () {
1634
+ last = undefined;
1635
+ fn.apply( that, args );
1636
+ }, frequency );
1637
+ }
1638
+ else {
1639
+ last = now;
1640
+ fn.apply( that, args );
1641
+ }
1642
+ };
1643
+ },
1644
+
1645
+
1646
+ /**
1647
+ * Escape a string such that it can be used in a regular expression
1648
+ *
1649
+ * @param {string} val string to escape
1650
+ * @returns {string} escaped string
1651
+ */
1652
+ escapeRegex: function ( val ) {
1653
+ return val.replace( _re_escape_regex, '\\$1' );
1654
+ }
1655
+ };
1656
+
1657
+
1658
+
1659
+ /**
1660
+ * Create a mapping object that allows camel case parameters to be looked up
1661
+ * for their Hungarian counterparts. The mapping is stored in a private
1662
+ * parameter called `_hungarianMap` which can be accessed on the source object.
1663
+ * @param {object} o
1664
+ * @memberof DataTable#oApi
1665
+ */
1666
+ function _fnHungarianMap ( o )
1667
+ {
1668
+ var
1669
+ hungarian = 'a aa ai ao as b fn i m o s ',
1670
+ match,
1671
+ newKey,
1672
+ map = {};
1673
+
1674
+ $.each( o, function (key, val) {
1675
+ match = key.match(/^([^A-Z]+?)([A-Z])/);
1676
+
1677
+ if ( match && hungarian.indexOf(match[1]+' ') !== -1 )
1678
+ {
1679
+ newKey = key.replace( match[0], match[2].toLowerCase() );
1680
+ map[ newKey ] = key;
1681
+
1682
+ if ( match[1] === 'o' )
1683
+ {
1684
+ _fnHungarianMap( o[key] );
1685
+ }
1686
+ }
1687
+ } );
1688
+
1689
+ o._hungarianMap = map;
1690
+ }
1691
+
1692
+
1693
+ /**
1694
+ * Convert from camel case parameters to Hungarian, based on a Hungarian map
1695
+ * created by _fnHungarianMap.
1696
+ * @param {object} src The model object which holds all parameters that can be
1697
+ * mapped.
1698
+ * @param {object} user The object to convert from camel case to Hungarian.
1699
+ * @param {boolean} force When set to `true`, properties which already have a
1700
+ * Hungarian value in the `user` object will be overwritten. Otherwise they
1701
+ * won't be.
1702
+ * @memberof DataTable#oApi
1703
+ */
1704
+ function _fnCamelToHungarian ( src, user, force )
1705
+ {
1706
+ if ( ! src._hungarianMap ) {
1707
+ _fnHungarianMap( src );
1708
+ }
1709
+
1710
+ var hungarianKey;
1711
+
1712
+ $.each( user, function (key, val) {
1713
+ hungarianKey = src._hungarianMap[ key ];
1714
+
1715
+ if ( hungarianKey !== undefined && (force || user[hungarianKey] === undefined) )
1716
+ {
1717
+ // For objects, we need to buzz down into the object to copy parameters
1718
+ if ( hungarianKey.charAt(0) === 'o' )
1719
+ {
1720
+ // Copy the camelCase options over to the hungarian
1721
+ if ( ! user[ hungarianKey ] ) {
1722
+ user[ hungarianKey ] = {};
1723
+ }
1724
+ $.extend( true, user[hungarianKey], user[key] );
1725
+
1726
+ _fnCamelToHungarian( src[hungarianKey], user[hungarianKey], force );
1727
+ }
1728
+ else {
1729
+ user[hungarianKey] = user[ key ];
1730
+ }
1731
+ }
1732
+ } );
1733
+ }
1734
+
1735
+
1736
+ /**
1737
+ * Language compatibility - when certain options are given, and others aren't, we
1738
+ * need to duplicate the values over, in order to provide backwards compatibility
1739
+ * with older language files.
1740
+ * @param {object} oSettings dataTables settings object
1741
+ * @memberof DataTable#oApi
1742
+ */
1743
+ function _fnLanguageCompat( lang )
1744
+ {
1745
+ var defaults = DataTable.defaults.oLanguage;
1746
+ var zeroRecords = lang.sZeroRecords;
1747
+
1748
+ /* Backwards compatibility - if there is no sEmptyTable given, then use the same as
1749
+ * sZeroRecords - assuming that is given.
1750
+ */
1751
+ if ( ! lang.sEmptyTable && zeroRecords &&
1752
+ defaults.sEmptyTable === "No data available in table" )
1753
+ {
1754
+ _fnMap( lang, lang, 'sZeroRecords', 'sEmptyTable' );
1755
+ }
1756
+
1757
+ /* Likewise with loading records */
1758
+ if ( ! lang.sLoadingRecords && zeroRecords &&
1759
+ defaults.sLoadingRecords === "Loading..." )
1760
+ {
1761
+ _fnMap( lang, lang, 'sZeroRecords', 'sLoadingRecords' );
1762
+ }
1763
+
1764
+ // Old parameter name of the thousands separator mapped onto the new
1765
+ if ( lang.sInfoThousands ) {
1766
+ lang.sThousands = lang.sInfoThousands;
1767
+ }
1768
+
1769
+ var decimal = lang.sDecimal;
1770
+ if ( decimal ) {
1771
+ _addNumericSort( decimal );
1772
+ }
1773
+ }
1774
+
1775
+
1776
+ /**
1777
+ * Map one parameter onto another
1778
+ * @param {object} o Object to map
1779
+ * @param {*} knew The new parameter name
1780
+ * @param {*} old The old parameter name
1781
+ */
1782
+ var _fnCompatMap = function ( o, knew, old ) {
1783
+ if ( o[ knew ] !== undefined ) {
1784
+ o[ old ] = o[ knew ];
1785
+ }
1786
+ };
1787
+
1788
+
1789
+ /**
1790
+ * Provide backwards compatibility for the main DT options. Note that the new
1791
+ * options are mapped onto the old parameters, so this is an external interface
1792
+ * change only.
1793
+ * @param {object} init Object to map
1794
+ */
1795
+ function _fnCompatOpts ( init )
1796
+ {
1797
+ _fnCompatMap( init, 'ordering', 'bSort' );
1798
+ _fnCompatMap( init, 'orderMulti', 'bSortMulti' );
1799
+ _fnCompatMap( init, 'orderClasses', 'bSortClasses' );
1800
+ _fnCompatMap( init, 'orderCellsTop', 'bSortCellsTop' );
1801
+ _fnCompatMap( init, 'order', 'aaSorting' );
1802
+ _fnCompatMap( init, 'orderFixed', 'aaSortingFixed' );
1803
+ _fnCompatMap( init, 'paging', 'bPaginate' );
1804
+ _fnCompatMap( init, 'pagingType', 'sPaginationType' );
1805
+ _fnCompatMap( init, 'pageLength', 'iDisplayLength' );
1806
+ _fnCompatMap( init, 'searching', 'bFilter' );
1807
+
1808
+ // Boolean initialisation of x-scrolling
1809
+ if ( typeof init.sScrollX === 'boolean' ) {
1810
+ init.sScrollX = init.sScrollX ? '100%' : '';
1811
+ }
1812
+ if ( typeof init.scrollX === 'boolean' ) {
1813
+ init.scrollX = init.scrollX ? '100%' : '';
1814
+ }
1815
+
1816
+ // Column search objects are in an array, so it needs to be converted
1817
+ // element by element
1818
+ var searchCols = init.aoSearchCols;
1819
+
1820
+ if ( searchCols ) {
1821
+ for ( var i=0, ien=searchCols.length ; i<ien ; i++ ) {
1822
+ if ( searchCols[i] ) {
1823
+ _fnCamelToHungarian( DataTable.models.oSearch, searchCols[i] );
1824
+ }
1825
+ }
1826
+ }
1827
+ }
1828
+
1829
+
1830
+ /**
1831
+ * Provide backwards compatibility for column options. Note that the new options
1832
+ * are mapped onto the old parameters, so this is an external interface change
1833
+ * only.
1834
+ * @param {object} init Object to map
1835
+ */
1836
+ function _fnCompatCols ( init )
1837
+ {
1838
+ _fnCompatMap( init, 'orderable', 'bSortable' );
1839
+ _fnCompatMap( init, 'orderData', 'aDataSort' );
1840
+ _fnCompatMap( init, 'orderSequence', 'asSorting' );
1841
+ _fnCompatMap( init, 'orderDataType', 'sortDataType' );
1842
+
1843
+ // orderData can be given as an integer
1844
+ var dataSort = init.aDataSort;
1845
+ if ( typeof dataSort === 'number' && ! $.isArray( dataSort ) ) {
1846
+ init.aDataSort = [ dataSort ];
1847
+ }
1848
+ }
1849
+
1850
+
1851
+ /**
1852
+ * Browser feature detection for capabilities, quirks
1853
+ * @param {object} settings dataTables settings object
1854
+ * @memberof DataTable#oApi
1855
+ */
1856
+ function _fnBrowserDetect( settings )
1857
+ {
1858
+ // We don't need to do this every time DataTables is constructed, the values
1859
+ // calculated are specific to the browser and OS configuration which we
1860
+ // don't expect to change between initialisations
1861
+ if ( ! DataTable.__browser ) {
1862
+ var browser = {};
1863
+ DataTable.__browser = browser;
1864
+
1865
+ // Scrolling feature / quirks detection
1866
+ var n = $('<div/>')
1867
+ .css( {
1868
+ position: 'fixed',
1869
+ top: 0,
1870
+ left: $(window).scrollLeft()*-1, // allow for scrolling
1871
+ height: 1,
1872
+ width: 1,
1873
+ overflow: 'hidden'
1874
+ } )
1875
+ .append(
1876
+ $('<div/>')
1877
+ .css( {
1878
+ position: 'absolute',
1879
+ top: 1,
1880
+ left: 1,
1881
+ width: 100,
1882
+ overflow: 'scroll'
1883
+ } )
1884
+ .append(
1885
+ $('<div/>')
1886
+ .css( {
1887
+ width: '100%',
1888
+ height: 10
1889
+ } )
1890
+ )
1891
+ )
1892
+ .appendTo( 'body' );
1893
+
1894
+ var outer = n.children();
1895
+ var inner = outer.children();
1896
+
1897
+ // Numbers below, in order, are:
1898
+ // inner.offsetWidth, inner.clientWidth, outer.offsetWidth, outer.clientWidth
1899
+ //
1900
+ // IE6 XP: 100 100 100 83
1901
+ // IE7 Vista: 100 100 100 83
1902
+ // IE 8+ Windows: 83 83 100 83
1903
+ // Evergreen Windows: 83 83 100 83
1904
+ // Evergreen Mac with scrollbars: 85 85 100 85
1905
+ // Evergreen Mac without scrollbars: 100 100 100 100
1906
+
1907
+ // Get scrollbar width
1908
+ browser.barWidth = outer[0].offsetWidth - outer[0].clientWidth;
1909
+
1910
+ // IE6/7 will oversize a width 100% element inside a scrolling element, to
1911
+ // include the width of the scrollbar, while other browsers ensure the inner
1912
+ // element is contained without forcing scrolling
1913
+ browser.bScrollOversize = inner[0].offsetWidth === 100 && outer[0].clientWidth !== 100;
1914
+
1915
+ // In rtl text layout, some browsers (most, but not all) will place the
1916
+ // scrollbar on the left, rather than the right.
1917
+ browser.bScrollbarLeft = Math.round( inner.offset().left ) !== 1;
1918
+
1919
+ // IE8- don't provide height and width for getBoundingClientRect
1920
+ browser.bBounding = n[0].getBoundingClientRect().width ? true : false;
1921
+
1922
+ n.remove();
1923
+ }
1924
+
1925
+ $.extend( settings.oBrowser, DataTable.__browser );
1926
+ settings.oScroll.iBarWidth = DataTable.__browser.barWidth;
1927
+ }
1928
+
1929
+
1930
+ /**
1931
+ * Array.prototype reduce[Right] method, used for browsers which don't support
1932
+ * JS 1.6. Done this way to reduce code size, since we iterate either way
1933
+ * @param {object} settings dataTables settings object
1934
+ * @memberof DataTable#oApi
1935
+ */
1936
+ function _fnReduce ( that, fn, init, start, end, inc )
1937
+ {
1938
+ var
1939
+ i = start,
1940
+ value,
1941
+ isSet = false;
1942
+
1943
+ if ( init !== undefined ) {
1944
+ value = init;
1945
+ isSet = true;
1946
+ }
1947
+
1948
+ while ( i !== end ) {
1949
+ if ( ! that.hasOwnProperty(i) ) {
1950
+ continue;
1951
+ }
1952
+
1953
+ value = isSet ?
1954
+ fn( value, that[i], i, that ) :
1955
+ that[i];
1956
+
1957
+ isSet = true;
1958
+ i += inc;
1959
+ }
1960
+
1961
+ return value;
1962
+ }
1963
+
1964
+ /**
1965
+ * Add a column to the list used for the table with default values
1966
+ * @param {object} oSettings dataTables settings object
1967
+ * @param {node} nTh The th element for this column
1968
+ * @memberof DataTable#oApi
1969
+ */
1970
+ function _fnAddColumn( oSettings, nTh )
1971
+ {
1972
+ // Add column to aoColumns array
1973
+ var oDefaults = DataTable.defaults.column;
1974
+ var iCol = oSettings.aoColumns.length;
1975
+ var oCol = $.extend( {}, DataTable.models.oColumn, oDefaults, {
1976
+ "nTh": nTh ? nTh : document.createElement('th'),
1977
+ "sTitle": oDefaults.sTitle ? oDefaults.sTitle : nTh ? nTh.innerHTML : '',
1978
+ "aDataSort": oDefaults.aDataSort ? oDefaults.aDataSort : [iCol],
1979
+ "mData": oDefaults.mData ? oDefaults.mData : iCol,
1980
+ idx: iCol
1981
+ } );
1982
+ oSettings.aoColumns.push( oCol );
1983
+
1984
+ // Add search object for column specific search. Note that the `searchCols[ iCol ]`
1985
+ // passed into extend can be undefined. This allows the user to give a default
1986
+ // with only some of the parameters defined, and also not give a default
1987
+ var searchCols = oSettings.aoPreSearchCols;
1988
+ searchCols[ iCol ] = $.extend( {}, DataTable.models.oSearch, searchCols[ iCol ] );
1989
+
1990
+ // Use the default column options function to initialise classes etc
1991
+ _fnColumnOptions( oSettings, iCol, $(nTh).data() );
1992
+ }
1993
+
1994
+
1995
+ /**
1996
+ * Apply options for a column
1997
+ * @param {object} oSettings dataTables settings object
1998
+ * @param {int} iCol column index to consider
1999
+ * @param {object} oOptions object with sType, bVisible and bSearchable etc
2000
+ * @memberof DataTable#oApi
2001
+ */
2002
+ function _fnColumnOptions( oSettings, iCol, oOptions )
2003
+ {
2004
+ var oCol = oSettings.aoColumns[ iCol ];
2005
+ var oClasses = oSettings.oClasses;
2006
+ var th = $(oCol.nTh);
2007
+
2008
+ // Try to get width information from the DOM. We can't get it from CSS
2009
+ // as we'd need to parse the CSS stylesheet. `width` option can override
2010
+ if ( ! oCol.sWidthOrig ) {
2011
+ // Width attribute
2012
+ oCol.sWidthOrig = th.attr('width') || null;
2013
+
2014
+ // Style attribute
2015
+ var t = (th.attr('style') || '').match(/width:\s*(\d+[pxem%]+)/);
2016
+ if ( t ) {
2017
+ oCol.sWidthOrig = t[1];
2018
+ }
2019
+ }
2020
+
2021
+ /* User specified column options */
2022
+ if ( oOptions !== undefined && oOptions !== null )
2023
+ {
2024
+ // Backwards compatibility
2025
+ _fnCompatCols( oOptions );
2026
+
2027
+ // Map camel case parameters to their Hungarian counterparts
2028
+ _fnCamelToHungarian( DataTable.defaults.column, oOptions );
2029
+
2030
+ /* Backwards compatibility for mDataProp */
2031
+ if ( oOptions.mDataProp !== undefined && !oOptions.mData )
2032
+ {
2033
+ oOptions.mData = oOptions.mDataProp;
2034
+ }
2035
+
2036
+ if ( oOptions.sType )
2037
+ {
2038
+ oCol._sManualType = oOptions.sType;
2039
+ }
2040
+
2041
+ // `class` is a reserved word in Javascript, so we need to provide
2042
+ // the ability to use a valid name for the camel case input
2043
+ if ( oOptions.className && ! oOptions.sClass )
2044
+ {
2045
+ oOptions.sClass = oOptions.className;
2046
+ }
2047
+ if ( oOptions.sClass ) {
2048
+ th.addClass( oOptions.sClass );
2049
+ }
2050
+
2051
+ $.extend( oCol, oOptions );
2052
+ _fnMap( oCol, oOptions, "sWidth", "sWidthOrig" );
2053
+
2054
+ /* iDataSort to be applied (backwards compatibility), but aDataSort will take
2055
+ * priority if defined
2056
+ */
2057
+ if ( oOptions.iDataSort !== undefined )
2058
+ {
2059
+ oCol.aDataSort = [ oOptions.iDataSort ];
2060
+ }
2061
+ _fnMap( oCol, oOptions, "aDataSort" );
2062
+ }
2063
+
2064
+ /* Cache the data get and set functions for speed */
2065
+ var mDataSrc = oCol.mData;
2066
+ var mData = _fnGetObjectDataFn( mDataSrc );
2067
+ var mRender = oCol.mRender ? _fnGetObjectDataFn( oCol.mRender ) : null;
2068
+
2069
+ var attrTest = function( src ) {
2070
+ return typeof src === 'string' && src.indexOf('@') !== -1;
2071
+ };
2072
+ oCol._bAttrSrc = $.isPlainObject( mDataSrc ) && (
2073
+ attrTest(mDataSrc.sort) || attrTest(mDataSrc.type) || attrTest(mDataSrc.filter)
2074
+ );
2075
+ oCol._setter = null;
2076
+
2077
+ oCol.fnGetData = function (rowData, type, meta) {
2078
+ var innerData = mData( rowData, type, undefined, meta );
2079
+
2080
+ return mRender && type ?
2081
+ mRender( innerData, type, rowData, meta ) :
2082
+ innerData;
2083
+ };
2084
+ oCol.fnSetData = function ( rowData, val, meta ) {
2085
+ return _fnSetObjectDataFn( mDataSrc )( rowData, val, meta );
2086
+ };
2087
+
2088
+ // Indicate if DataTables should read DOM data as an object or array
2089
+ // Used in _fnGetRowElements
2090
+ if ( typeof mDataSrc !== 'number' ) {
2091
+ oSettings._rowReadObject = true;
2092
+ }
2093
+
2094
+ /* Feature sorting overrides column specific when off */
2095
+ if ( !oSettings.oFeatures.bSort )
2096
+ {
2097
+ oCol.bSortable = false;
2098
+ th.addClass( oClasses.sSortableNone ); // Have to add class here as order event isn't called
2099
+ }
2100
+
2101
+ /* Check that the class assignment is correct for sorting */
2102
+ var bAsc = $.inArray('asc', oCol.asSorting) !== -1;
2103
+ var bDesc = $.inArray('desc', oCol.asSorting) !== -1;
2104
+ if ( !oCol.bSortable || (!bAsc && !bDesc) )
2105
+ {
2106
+ oCol.sSortingClass = oClasses.sSortableNone;
2107
+ oCol.sSortingClassJUI = "";
2108
+ }
2109
+ else if ( bAsc && !bDesc )
2110
+ {
2111
+ oCol.sSortingClass = oClasses.sSortableAsc;
2112
+ oCol.sSortingClassJUI = oClasses.sSortJUIAscAllowed;
2113
+ }
2114
+ else if ( !bAsc && bDesc )
2115
+ {
2116
+ oCol.sSortingClass = oClasses.sSortableDesc;
2117
+ oCol.sSortingClassJUI = oClasses.sSortJUIDescAllowed;
2118
+ }
2119
+ else
2120
+ {
2121
+ oCol.sSortingClass = oClasses.sSortable;
2122
+ oCol.sSortingClassJUI = oClasses.sSortJUI;
2123
+ }
2124
+ }
2125
+
2126
+
2127
+ /**
2128
+ * Adjust the table column widths for new data. Note: you would probably want to
2129
+ * do a redraw after calling this function!
2130
+ * @param {object} settings dataTables settings object
2131
+ * @memberof DataTable#oApi
2132
+ */
2133
+ function _fnAdjustColumnSizing ( settings )
2134
+ {
2135
+ /* Not interested in doing column width calculation if auto-width is disabled */
2136
+ if ( settings.oFeatures.bAutoWidth !== false )
2137
+ {
2138
+ var columns = settings.aoColumns;
2139
+
2140
+ _fnCalculateColumnWidths( settings );
2141
+ for ( var i=0 , iLen=columns.length ; i<iLen ; i++ )
2142
+ {
2143
+ columns[i].nTh.style.width = columns[i].sWidth;
2144
+ }
2145
+ }
2146
+
2147
+ var scroll = settings.oScroll;
2148
+ if ( scroll.sY !== '' || scroll.sX !== '')
2149
+ {
2150
+ _fnScrollDraw( settings );
2151
+ }
2152
+
2153
+ _fnCallbackFire( settings, null, 'column-sizing', [settings] );
2154
+ }
2155
+
2156
+
2157
+ /**
2158
+ * Covert the index of a visible column to the index in the data array (take account
2159
+ * of hidden columns)
2160
+ * @param {object} oSettings dataTables settings object
2161
+ * @param {int} iMatch Visible column index to lookup
2162
+ * @returns {int} i the data index
2163
+ * @memberof DataTable#oApi
2164
+ */
2165
+ function _fnVisibleToColumnIndex( oSettings, iMatch )
2166
+ {
2167
+ var aiVis = _fnGetColumns( oSettings, 'bVisible' );
2168
+
2169
+ return typeof aiVis[iMatch] === 'number' ?
2170
+ aiVis[iMatch] :
2171
+ null;
2172
+ }
2173
+
2174
+
2175
+ /**
2176
+ * Covert the index of an index in the data array and convert it to the visible
2177
+ * column index (take account of hidden columns)
2178
+ * @param {int} iMatch Column index to lookup
2179
+ * @param {object} oSettings dataTables settings object
2180
+ * @returns {int} i the data index
2181
+ * @memberof DataTable#oApi
2182
+ */
2183
+ function _fnColumnIndexToVisible( oSettings, iMatch )
2184
+ {
2185
+ var aiVis = _fnGetColumns( oSettings, 'bVisible' );
2186
+ var iPos = $.inArray( iMatch, aiVis );
2187
+
2188
+ return iPos !== -1 ? iPos : null;
2189
+ }
2190
+
2191
+
2192
+ /**
2193
+ * Get the number of visible columns
2194
+ * @param {object} oSettings dataTables settings object
2195
+ * @returns {int} i the number of visible columns
2196
+ * @memberof DataTable#oApi
2197
+ */
2198
+ function _fnVisbleColumns( oSettings )
2199
+ {
2200
+ var vis = 0;
2201
+
2202
+ // No reduce in IE8, use a loop for now
2203
+ $.each( oSettings.aoColumns, function ( i, col ) {
2204
+ if ( col.bVisible && $(col.nTh).css('display') !== 'none' ) {
2205
+ vis++;
2206
+ }
2207
+ } );
2208
+
2209
+ return vis;
2210
+ }
2211
+
2212
+
2213
+ /**
2214
+ * Get an array of column indexes that match a given property
2215
+ * @param {object} oSettings dataTables settings object
2216
+ * @param {string} sParam Parameter in aoColumns to look for - typically
2217
+ * bVisible or bSearchable
2218
+ * @returns {array} Array of indexes with matched properties
2219
+ * @memberof DataTable#oApi
2220
+ */
2221
+ function _fnGetColumns( oSettings, sParam )
2222
+ {
2223
+ var a = [];
2224
+
2225
+ $.map( oSettings.aoColumns, function(val, i) {
2226
+ if ( val[sParam] ) {
2227
+ a.push( i );
2228
+ }
2229
+ } );
2230
+
2231
+ return a;
2232
+ }
2233
+
2234
+
2235
+ /**
2236
+ * Calculate the 'type' of a column
2237
+ * @param {object} settings dataTables settings object
2238
+ * @memberof DataTable#oApi
2239
+ */
2240
+ function _fnColumnTypes ( settings )
2241
+ {
2242
+ var columns = settings.aoColumns;
2243
+ var data = settings.aoData;
2244
+ var types = DataTable.ext.type.detect;
2245
+ var i, ien, j, jen, k, ken;
2246
+ var col, cell, detectedType, cache;
2247
+
2248
+ // For each column, spin over the
2249
+ for ( i=0, ien=columns.length ; i<ien ; i++ ) {
2250
+ col = columns[i];
2251
+ cache = [];
2252
+
2253
+ if ( ! col.sType && col._sManualType ) {
2254
+ col.sType = col._sManualType;
2255
+ }
2256
+ else if ( ! col.sType ) {
2257
+ for ( j=0, jen=types.length ; j<jen ; j++ ) {
2258
+ for ( k=0, ken=data.length ; k<ken ; k++ ) {
2259
+ // Use a cache array so we only need to get the type data
2260
+ // from the formatter once (when using multiple detectors)
2261
+ if ( cache[k] === undefined ) {
2262
+ cache[k] = _fnGetCellData( settings, k, i, 'type' );
2263
+ }
2264
+
2265
+ detectedType = types[j]( cache[k], settings );
2266
+
2267
+ // If null, then this type can't apply to this column, so
2268
+ // rather than testing all cells, break out. There is an
2269
+ // exception for the last type which is `html`. We need to
2270
+ // scan all rows since it is possible to mix string and HTML
2271
+ // types
2272
+ if ( ! detectedType && j !== types.length-1 ) {
2273
+ break;
2274
+ }
2275
+
2276
+ // Only a single match is needed for html type since it is
2277
+ // bottom of the pile and very similar to string
2278
+ if ( detectedType === 'html' ) {
2279
+ break;
2280
+ }
2281
+ }
2282
+
2283
+ // Type is valid for all data points in the column - use this
2284
+ // type
2285
+ if ( detectedType ) {
2286
+ col.sType = detectedType;
2287
+ break;
2288
+ }
2289
+ }
2290
+
2291
+ // Fall back - if no type was detected, always use string
2292
+ if ( ! col.sType ) {
2293
+ col.sType = 'string';
2294
+ }
2295
+ }
2296
+ }
2297
+ }
2298
+
2299
+
2300
+ /**
2301
+ * Take the column definitions and static columns arrays and calculate how
2302
+ * they relate to column indexes. The callback function will then apply the
2303
+ * definition found for a column to a suitable configuration object.
2304
+ * @param {object} oSettings dataTables settings object
2305
+ * @param {array} aoColDefs The aoColumnDefs array that is to be applied
2306
+ * @param {array} aoCols The aoColumns array that defines columns individually
2307
+ * @param {function} fn Callback function - takes two parameters, the calculated
2308
+ * column index and the definition for that column.
2309
+ * @memberof DataTable#oApi
2310
+ */
2311
+ function _fnApplyColumnDefs( oSettings, aoColDefs, aoCols, fn )
2312
+ {
2313
+ var i, iLen, j, jLen, k, kLen, def;
2314
+ var columns = oSettings.aoColumns;
2315
+
2316
+ // Column definitions with aTargets
2317
+ if ( aoColDefs )
2318
+ {
2319
+ /* Loop over the definitions array - loop in reverse so first instance has priority */
2320
+ for ( i=aoColDefs.length-1 ; i>=0 ; i-- )
2321
+ {
2322
+ def = aoColDefs[i];
2323
+
2324
+ /* Each definition can target multiple columns, as it is an array */
2325
+ var aTargets = def.targets !== undefined ?
2326
+ def.targets :
2327
+ def.aTargets;
2328
+
2329
+ if ( ! $.isArray( aTargets ) )
2330
+ {
2331
+ aTargets = [ aTargets ];
2332
+ }
2333
+
2334
+ for ( j=0, jLen=aTargets.length ; j<jLen ; j++ )
2335
+ {
2336
+ if ( typeof aTargets[j] === 'number' && aTargets[j] >= 0 )
2337
+ {
2338
+ /* Add columns that we don't yet know about */
2339
+ while( columns.length <= aTargets[j] )
2340
+ {
2341
+ _fnAddColumn( oSettings );
2342
+ }
2343
+
2344
+ /* Integer, basic index */
2345
+ fn( aTargets[j], def );
2346
+ }
2347
+ else if ( typeof aTargets[j] === 'number' && aTargets[j] < 0 )
2348
+ {
2349
+ /* Negative integer, right to left column counting */
2350
+ fn( columns.length+aTargets[j], def );
2351
+ }
2352
+ else if ( typeof aTargets[j] === 'string' )
2353
+ {
2354
+ /* Class name matching on TH element */
2355
+ for ( k=0, kLen=columns.length ; k<kLen ; k++ )
2356
+ {
2357
+ if ( aTargets[j] == "_all" ||
2358
+ $(columns[k].nTh).hasClass( aTargets[j] ) )
2359
+ {
2360
+ fn( k, def );
2361
+ }
2362
+ }
2363
+ }
2364
+ }
2365
+ }
2366
+ }
2367
+
2368
+ // Statically defined columns array
2369
+ if ( aoCols )
2370
+ {
2371
+ for ( i=0, iLen=aoCols.length ; i<iLen ; i++ )
2372
+ {
2373
+ fn( i, aoCols[i] );
2374
+ }
2375
+ }
2376
+ }
2377
+
2378
+ /**
2379
+ * Add a data array to the table, creating DOM node etc. This is the parallel to
2380
+ * _fnGatherData, but for adding rows from a Javascript source, rather than a
2381
+ * DOM source.
2382
+ * @param {object} oSettings dataTables settings object
2383
+ * @param {array} aData data array to be added
2384
+ * @param {node} [nTr] TR element to add to the table - optional. If not given,
2385
+ * DataTables will create a row automatically
2386
+ * @param {array} [anTds] Array of TD|TH elements for the row - must be given
2387
+ * if nTr is.
2388
+ * @returns {int} >=0 if successful (index of new aoData entry), -1 if failed
2389
+ * @memberof DataTable#oApi
2390
+ */
2391
+ function _fnAddData ( oSettings, aDataIn, nTr, anTds )
2392
+ {
2393
+ /* Create the object for storing information about this new row */
2394
+ var iRow = oSettings.aoData.length;
2395
+ var oData = $.extend( true, {}, DataTable.models.oRow, {
2396
+ src: nTr ? 'dom' : 'data',
2397
+ idx: iRow
2398
+ } );
2399
+
2400
+ oData._aData = aDataIn;
2401
+ oSettings.aoData.push( oData );
2402
+
2403
+ /* Create the cells */
2404
+ var nTd, sThisType;
2405
+ var columns = oSettings.aoColumns;
2406
+
2407
+ // Invalidate the column types as the new data needs to be revalidated
2408
+ for ( var i=0, iLen=columns.length ; i<iLen ; i++ )
2409
+ {
2410
+ columns[i].sType = null;
2411
+ }
2412
+
2413
+ /* Add to the display array */
2414
+ oSettings.aiDisplayMaster.push( iRow );
2415
+
2416
+ var id = oSettings.rowIdFn( aDataIn );
2417
+ if ( id !== undefined ) {
2418
+ oSettings.aIds[ id ] = oData;
2419
+ }
2420
+
2421
+ /* Create the DOM information, or register it if already present */
2422
+ if ( nTr || ! oSettings.oFeatures.bDeferRender )
2423
+ {
2424
+ _fnCreateTr( oSettings, iRow, nTr, anTds );
2425
+ }
2426
+
2427
+ return iRow;
2428
+ }
2429
+
2430
+
2431
+ /**
2432
+ * Add one or more TR elements to the table. Generally we'd expect to
2433
+ * use this for reading data from a DOM sourced table, but it could be
2434
+ * used for an TR element. Note that if a TR is given, it is used (i.e.
2435
+ * it is not cloned).
2436
+ * @param {object} settings dataTables settings object
2437
+ * @param {array|node|jQuery} trs The TR element(s) to add to the table
2438
+ * @returns {array} Array of indexes for the added rows
2439
+ * @memberof DataTable#oApi
2440
+ */
2441
+ function _fnAddTr( settings, trs )
2442
+ {
2443
+ var row;
2444
+
2445
+ // Allow an individual node to be passed in
2446
+ if ( ! (trs instanceof $) ) {
2447
+ trs = $(trs);
2448
+ }
2449
+
2450
+ return trs.map( function (i, el) {
2451
+ row = _fnGetRowElements( settings, el );
2452
+ return _fnAddData( settings, row.data, el, row.cells );
2453
+ } );
2454
+ }
2455
+
2456
+
2457
+ /**
2458
+ * Take a TR element and convert it to an index in aoData
2459
+ * @param {object} oSettings dataTables settings object
2460
+ * @param {node} n the TR element to find
2461
+ * @returns {int} index if the node is found, null if not
2462
+ * @memberof DataTable#oApi
2463
+ */
2464
+ function _fnNodeToDataIndex( oSettings, n )
2465
+ {
2466
+ return (n._DT_RowIndex!==undefined) ? n._DT_RowIndex : null;
2467
+ }
2468
+
2469
+
2470
+ /**
2471
+ * Take a TD element and convert it into a column data index (not the visible index)
2472
+ * @param {object} oSettings dataTables settings object
2473
+ * @param {int} iRow The row number the TD/TH can be found in
2474
+ * @param {node} n The TD/TH element to find
2475
+ * @returns {int} index if the node is found, -1 if not
2476
+ * @memberof DataTable#oApi
2477
+ */
2478
+ function _fnNodeToColumnIndex( oSettings, iRow, n )
2479
+ {
2480
+ return $.inArray( n, oSettings.aoData[ iRow ].anCells );
2481
+ }
2482
+
2483
+
2484
+ /**
2485
+ * Get the data for a given cell from the internal cache, taking into account data mapping
2486
+ * @param {object} settings dataTables settings object
2487
+ * @param {int} rowIdx aoData row id
2488
+ * @param {int} colIdx Column index
2489
+ * @param {string} type data get type ('display', 'type' 'filter' 'sort')
2490
+ * @returns {*} Cell data
2491
+ * @memberof DataTable#oApi
2492
+ */
2493
+ function _fnGetCellData( settings, rowIdx, colIdx, type )
2494
+ {
2495
+ var draw = settings.iDraw;
2496
+ var col = settings.aoColumns[colIdx];
2497
+ var rowData = settings.aoData[rowIdx]._aData;
2498
+ var defaultContent = col.sDefaultContent;
2499
+ var cellData = col.fnGetData( rowData, type, {
2500
+ settings: settings,
2501
+ row: rowIdx,
2502
+ col: colIdx
2503
+ } );
2504
+
2505
+ if ( cellData === undefined ) {
2506
+ if ( settings.iDrawError != draw && defaultContent === null ) {
2507
+ _fnLog( settings, 0, "Requested unknown parameter "+
2508
+ (typeof col.mData=='function' ? '{function}' : "'"+col.mData+"'")+
2509
+ " for row "+rowIdx+", column "+colIdx, 4 );
2510
+ settings.iDrawError = draw;
2511
+ }
2512
+ return defaultContent;
2513
+ }
2514
+
2515
+ // When the data source is null and a specific data type is requested (i.e.
2516
+ // not the original data), we can use default column data
2517
+ if ( (cellData === rowData || cellData === null) && defaultContent !== null && type !== undefined ) {
2518
+ cellData = defaultContent;
2519
+ }
2520
+ else if ( typeof cellData === 'function' ) {
2521
+ // If the data source is a function, then we run it and use the return,
2522
+ // executing in the scope of the data object (for instances)
2523
+ return cellData.call( rowData );
2524
+ }
2525
+
2526
+ if ( cellData === null && type == 'display' ) {
2527
+ return '';
2528
+ }
2529
+ return cellData;
2530
+ }
2531
+
2532
+
2533
+ /**
2534
+ * Set the value for a specific cell, into the internal data cache
2535
+ * @param {object} settings dataTables settings object
2536
+ * @param {int} rowIdx aoData row id
2537
+ * @param {int} colIdx Column index
2538
+ * @param {*} val Value to set
2539
+ * @memberof DataTable#oApi
2540
+ */
2541
+ function _fnSetCellData( settings, rowIdx, colIdx, val )
2542
+ {
2543
+ var col = settings.aoColumns[colIdx];
2544
+ var rowData = settings.aoData[rowIdx]._aData;
2545
+
2546
+ col.fnSetData( rowData, val, {
2547
+ settings: settings,
2548
+ row: rowIdx,
2549
+ col: colIdx
2550
+ } );
2551
+ }
2552
+
2553
+
2554
+ // Private variable that is used to match action syntax in the data property object
2555
+ var __reArray = /\[.*?\]$/;
2556
+ var __reFn = /\(\)$/;
2557
+
2558
+ /**
2559
+ * Split string on periods, taking into account escaped periods
2560
+ * @param {string} str String to split
2561
+ * @return {array} Split string
2562
+ */
2563
+ function _fnSplitObjNotation( str )
2564
+ {
2565
+ return $.map( str.match(/(\\.|[^\.])+/g) || [''], function ( s ) {
2566
+ return s.replace(/\\\./g, '.');
2567
+ } );
2568
+ }
2569
+
2570
+
2571
+ /**
2572
+ * Return a function that can be used to get data from a source object, taking
2573
+ * into account the ability to use nested objects as a source
2574
+ * @param {string|int|function} mSource The data source for the object
2575
+ * @returns {function} Data get function
2576
+ * @memberof DataTable#oApi
2577
+ */
2578
+ function _fnGetObjectDataFn( mSource )
2579
+ {
2580
+ if ( $.isPlainObject( mSource ) )
2581
+ {
2582
+ /* Build an object of get functions, and wrap them in a single call */
2583
+ var o = {};
2584
+ $.each( mSource, function (key, val) {
2585
+ if ( val ) {
2586
+ o[key] = _fnGetObjectDataFn( val );
2587
+ }
2588
+ } );
2589
+
2590
+ return function (data, type, row, meta) {
2591
+ var t = o[type] || o._;
2592
+ return t !== undefined ?
2593
+ t(data, type, row, meta) :
2594
+ data;
2595
+ };
2596
+ }
2597
+ else if ( mSource === null )
2598
+ {
2599
+ /* Give an empty string for rendering / sorting etc */
2600
+ return function (data) { // type, row and meta also passed, but not used
2601
+ return data;
2602
+ };
2603
+ }
2604
+ else if ( typeof mSource === 'function' )
2605
+ {
2606
+ return function (data, type, row, meta) {
2607
+ return mSource( data, type, row, meta );
2608
+ };
2609
+ }
2610
+ else if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 ||
2611
+ mSource.indexOf('[') !== -1 || mSource.indexOf('(') !== -1) )
2612
+ {
2613
+ /* If there is a . in the source string then the data source is in a
2614
+ * nested object so we loop over the data for each level to get the next
2615
+ * level down. On each loop we test for undefined, and if found immediately
2616
+ * return. This allows entire objects to be missing and sDefaultContent to
2617
+ * be used if defined, rather than throwing an error
2618
+ */
2619
+ var fetchData = function (data, type, src) {
2620
+ var arrayNotation, funcNotation, out, innerSrc;
2621
+
2622
+ if ( src !== "" )
2623
+ {
2624
+ var a = _fnSplitObjNotation( src );
2625
+
2626
+ for ( var i=0, iLen=a.length ; i<iLen ; i++ )
2627
+ {
2628
+ // Check if we are dealing with special notation
2629
+ arrayNotation = a[i].match(__reArray);
2630
+ funcNotation = a[i].match(__reFn);
2631
+
2632
+ if ( arrayNotation )
2633
+ {
2634
+ // Array notation
2635
+ a[i] = a[i].replace(__reArray, '');
2636
+
2637
+ // Condition allows simply [] to be passed in
2638
+ if ( a[i] !== "" ) {
2639
+ data = data[ a[i] ];
2640
+ }
2641
+ out = [];
2642
+
2643
+ // Get the remainder of the nested object to get
2644
+ a.splice( 0, i+1 );
2645
+ innerSrc = a.join('.');
2646
+
2647
+ // Traverse each entry in the array getting the properties requested
2648
+ if ( $.isArray( data ) ) {
2649
+ for ( var j=0, jLen=data.length ; j<jLen ; j++ ) {
2650
+ out.push( fetchData( data[j], type, innerSrc ) );
2651
+ }
2652
+ }
2653
+
2654
+ // If a string is given in between the array notation indicators, that
2655
+ // is used to join the strings together, otherwise an array is returned
2656
+ var join = arrayNotation[0].substring(1, arrayNotation[0].length-1);
2657
+ data = (join==="") ? out : out.join(join);
2658
+
2659
+ // The inner call to fetchData has already traversed through the remainder
2660
+ // of the source requested, so we exit from the loop
2661
+ break;
2662
+ }
2663
+ else if ( funcNotation )
2664
+ {
2665
+ // Function call
2666
+ a[i] = a[i].replace(__reFn, '');
2667
+ data = data[ a[i] ]();
2668
+ continue;
2669
+ }
2670
+
2671
+ if ( data === null || data[ a[i] ] === undefined )
2672
+ {
2673
+ return undefined;
2674
+ }
2675
+ data = data[ a[i] ];
2676
+ }
2677
+ }
2678
+
2679
+ return data;
2680
+ };
2681
+
2682
+ return function (data, type) { // row and meta also passed, but not used
2683
+ return fetchData( data, type, mSource );
2684
+ };
2685
+ }
2686
+ else
2687
+ {
2688
+ /* Array or flat object mapping */
2689
+ return function (data, type) { // row and meta also passed, but not used
2690
+ return data[mSource];
2691
+ };
2692
+ }
2693
+ }
2694
+
2695
+
2696
+ /**
2697
+ * Return a function that can be used to set data from a source object, taking
2698
+ * into account the ability to use nested objects as a source
2699
+ * @param {string|int|function} mSource The data source for the object
2700
+ * @returns {function} Data set function
2701
+ * @memberof DataTable#oApi
2702
+ */
2703
+ function _fnSetObjectDataFn( mSource )
2704
+ {
2705
+ if ( $.isPlainObject( mSource ) )
2706
+ {
2707
+ /* Unlike get, only the underscore (global) option is used for for
2708
+ * setting data since we don't know the type here. This is why an object
2709
+ * option is not documented for `mData` (which is read/write), but it is
2710
+ * for `mRender` which is read only.
2711
+ */
2712
+ return _fnSetObjectDataFn( mSource._ );
2713
+ }
2714
+ else if ( mSource === null )
2715
+ {
2716
+ /* Nothing to do when the data source is null */
2717
+ return function () {};
2718
+ }
2719
+ else if ( typeof mSource === 'function' )
2720
+ {
2721
+ return function (data, val, meta) {
2722
+ mSource( data, 'set', val, meta );
2723
+ };
2724
+ }
2725
+ else if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 ||
2726
+ mSource.indexOf('[') !== -1 || mSource.indexOf('(') !== -1) )
2727
+ {
2728
+ /* Like the get, we need to get data from a nested object */
2729
+ var setData = function (data, val, src) {
2730
+ var a = _fnSplitObjNotation( src ), b;
2731
+ var aLast = a[a.length-1];
2732
+ var arrayNotation, funcNotation, o, innerSrc;
2733
+
2734
+ for ( var i=0, iLen=a.length-1 ; i<iLen ; i++ )
2735
+ {
2736
+ // Check if we are dealing with an array notation request
2737
+ arrayNotation = a[i].match(__reArray);
2738
+ funcNotation = a[i].match(__reFn);
2739
+
2740
+ if ( arrayNotation )
2741
+ {
2742
+ a[i] = a[i].replace(__reArray, '');
2743
+ data[ a[i] ] = [];
2744
+
2745
+ // Get the remainder of the nested object to set so we can recurse
2746
+ b = a.slice();
2747
+ b.splice( 0, i+1 );
2748
+ innerSrc = b.join('.');
2749
+
2750
+ // Traverse each entry in the array setting the properties requested
2751
+ if ( $.isArray( val ) )
2752
+ {
2753
+ for ( var j=0, jLen=val.length ; j<jLen ; j++ )
2754
+ {
2755
+ o = {};
2756
+ setData( o, val[j], innerSrc );
2757
+ data[ a[i] ].push( o );
2758
+ }
2759
+ }
2760
+ else
2761
+ {
2762
+ // We've been asked to save data to an array, but it
2763
+ // isn't array data to be saved. Best that can be done
2764
+ // is to just save the value.
2765
+ data[ a[i] ] = val;
2766
+ }
2767
+
2768
+ // The inner call to setData has already traversed through the remainder
2769
+ // of the source and has set the data, thus we can exit here
2770
+ return;
2771
+ }
2772
+ else if ( funcNotation )
2773
+ {
2774
+ // Function call
2775
+ a[i] = a[i].replace(__reFn, '');
2776
+ data = data[ a[i] ]( val );
2777
+ }
2778
+
2779
+ // If the nested object doesn't currently exist - since we are
2780
+ // trying to set the value - create it
2781
+ if ( data[ a[i] ] === null || data[ a[i] ] === undefined )
2782
+ {
2783
+ data[ a[i] ] = {};
2784
+ }
2785
+ data = data[ a[i] ];
2786
+ }
2787
+
2788
+ // Last item in the input - i.e, the actual set
2789
+ if ( aLast.match(__reFn ) )
2790
+ {
2791
+ // Function call
2792
+ data = data[ aLast.replace(__reFn, '') ]( val );
2793
+ }
2794
+ else
2795
+ {
2796
+ // If array notation is used, we just want to strip it and use the property name
2797
+ // and assign the value. If it isn't used, then we get the result we want anyway
2798
+ data[ aLast.replace(__reArray, '') ] = val;
2799
+ }
2800
+ };
2801
+
2802
+ return function (data, val) { // meta is also passed in, but not used
2803
+ return setData( data, val, mSource );
2804
+ };
2805
+ }
2806
+ else
2807
+ {
2808
+ /* Array or flat object mapping */
2809
+ return function (data, val) { // meta is also passed in, but not used
2810
+ data[mSource] = val;
2811
+ };
2812
+ }
2813
+ }
2814
+
2815
+
2816
+ /**
2817
+ * Return an array with the full table data
2818
+ * @param {object} oSettings dataTables settings object
2819
+ * @returns array {array} aData Master data array
2820
+ * @memberof DataTable#oApi
2821
+ */
2822
+ function _fnGetDataMaster ( settings )
2823
+ {
2824
+ return _pluck( settings.aoData, '_aData' );
2825
+ }
2826
+
2827
+
2828
+ /**
2829
+ * Nuke the table
2830
+ * @param {object} oSettings dataTables settings object
2831
+ * @memberof DataTable#oApi
2832
+ */
2833
+ function _fnClearTable( settings )
2834
+ {
2835
+ settings.aoData.length = 0;
2836
+ settings.aiDisplayMaster.length = 0;
2837
+ settings.aiDisplay.length = 0;
2838
+ settings.aIds = {};
2839
+ }
2840
+
2841
+
2842
+ /**
2843
+ * Take an array of integers (index array) and remove a target integer (value - not
2844
+ * the key!)
2845
+ * @param {array} a Index array to target
2846
+ * @param {int} iTarget value to find
2847
+ * @memberof DataTable#oApi
2848
+ */
2849
+ function _fnDeleteIndex( a, iTarget, splice )
2850
+ {
2851
+ var iTargetIndex = -1;
2852
+
2853
+ for ( var i=0, iLen=a.length ; i<iLen ; i++ )
2854
+ {
2855
+ if ( a[i] == iTarget )
2856
+ {
2857
+ iTargetIndex = i;
2858
+ }
2859
+ else if ( a[i] > iTarget )
2860
+ {
2861
+ a[i]--;
2862
+ }
2863
+ }
2864
+
2865
+ if ( iTargetIndex != -1 && splice === undefined )
2866
+ {
2867
+ a.splice( iTargetIndex, 1 );
2868
+ }
2869
+ }
2870
+
2871
+
2872
+ /**
2873
+ * Mark cached data as invalid such that a re-read of the data will occur when
2874
+ * the cached data is next requested. Also update from the data source object.
2875
+ *
2876
+ * @param {object} settings DataTables settings object
2877
+ * @param {int} rowIdx Row index to invalidate
2878
+ * @param {string} [src] Source to invalidate from: undefined, 'auto', 'dom'
2879
+ * or 'data'
2880
+ * @param {int} [colIdx] Column index to invalidate. If undefined the whole
2881
+ * row will be invalidated
2882
+ * @memberof DataTable#oApi
2883
+ *
2884
+ * @todo For the modularisation of v1.11 this will need to become a callback, so
2885
+ * the sort and filter methods can subscribe to it. That will required
2886
+ * initialisation options for sorting, which is why it is not already baked in
2887
+ */
2888
+ function _fnInvalidate( settings, rowIdx, src, colIdx )
2889
+ {
2890
+ var row = settings.aoData[ rowIdx ];
2891
+ var i, ien;
2892
+ var cellWrite = function ( cell, col ) {
2893
+ // This is very frustrating, but in IE if you just write directly
2894
+ // to innerHTML, and elements that are overwritten are GC'ed,
2895
+ // even if there is a reference to them elsewhere
2896
+ while ( cell.childNodes.length ) {
2897
+ cell.removeChild( cell.firstChild );
2898
+ }
2899
+
2900
+ cell.innerHTML = _fnGetCellData( settings, rowIdx, col, 'display' );
2901
+ };
2902
+
2903
+ // Are we reading last data from DOM or the data object?
2904
+ if ( src === 'dom' || ((! src || src === 'auto') && row.src === 'dom') ) {
2905
+ // Read the data from the DOM
2906
+ row._aData = _fnGetRowElements(
2907
+ settings, row, colIdx, colIdx === undefined ? undefined : row._aData
2908
+ )
2909
+ .data;
2910
+ }
2911
+ else {
2912
+ // Reading from data object, update the DOM
2913
+ var cells = row.anCells;
2914
+
2915
+ if ( cells ) {
2916
+ if ( colIdx !== undefined ) {
2917
+ cellWrite( cells[colIdx], colIdx );
2918
+ }
2919
+ else {
2920
+ for ( i=0, ien=cells.length ; i<ien ; i++ ) {
2921
+ cellWrite( cells[i], i );
2922
+ }
2923
+ }
2924
+ }
2925
+ }
2926
+
2927
+ // For both row and cell invalidation, the cached data for sorting and
2928
+ // filtering is nulled out
2929
+ row._aSortData = null;
2930
+ row._aFilterData = null;
2931
+
2932
+ // Invalidate the type for a specific column (if given) or all columns since
2933
+ // the data might have changed
2934
+ var cols = settings.aoColumns;
2935
+ if ( colIdx !== undefined ) {
2936
+ cols[ colIdx ].sType = null;
2937
+ }
2938
+ else {
2939
+ for ( i=0, ien=cols.length ; i<ien ; i++ ) {
2940
+ cols[i].sType = null;
2941
+ }
2942
+
2943
+ // Update DataTables special `DT_*` attributes for the row
2944
+ _fnRowAttributes( settings, row );
2945
+ }
2946
+ }
2947
+
2948
+
2949
+ /**
2950
+ * Build a data source object from an HTML row, reading the contents of the
2951
+ * cells that are in the row.
2952
+ *
2953
+ * @param {object} settings DataTables settings object
2954
+ * @param {node|object} TR element from which to read data or existing row
2955
+ * object from which to re-read the data from the cells
2956
+ * @param {int} [colIdx] Optional column index
2957
+ * @param {array|object} [d] Data source object. If `colIdx` is given then this
2958
+ * parameter should also be given and will be used to write the data into.
2959
+ * Only the column in question will be written
2960
+ * @returns {object} Object with two parameters: `data` the data read, in
2961
+ * document order, and `cells` and array of nodes (they can be useful to the
2962
+ * caller, so rather than needing a second traversal to get them, just return
2963
+ * them from here).
2964
+ * @memberof DataTable#oApi
2965
+ */
2966
+ function _fnGetRowElements( settings, row, colIdx, d )
2967
+ {
2968
+ var
2969
+ tds = [],
2970
+ td = row.firstChild,
2971
+ name, col, o, i=0, contents,
2972
+ columns = settings.aoColumns,
2973
+ objectRead = settings._rowReadObject;
2974
+
2975
+ // Allow the data object to be passed in, or construct
2976
+ d = d !== undefined ?
2977
+ d :
2978
+ objectRead ?
2979
+ {} :
2980
+ [];
2981
+
2982
+ var attr = function ( str, td ) {
2983
+ if ( typeof str === 'string' ) {
2984
+ var idx = str.indexOf('@');
2985
+
2986
+ if ( idx !== -1 ) {
2987
+ var attr = str.substring( idx+1 );
2988
+ var setter = _fnSetObjectDataFn( str );
2989
+ setter( d, td.getAttribute( attr ) );
2990
+ }
2991
+ }
2992
+ };
2993
+
2994
+ // Read data from a cell and store into the data object
2995
+ var cellProcess = function ( cell ) {
2996
+ if ( colIdx === undefined || colIdx === i ) {
2997
+ col = columns[i];
2998
+ contents = $.trim(cell.innerHTML);
2999
+
3000
+ if ( col && col._bAttrSrc ) {
3001
+ var setter = _fnSetObjectDataFn( col.mData._ );
3002
+ setter( d, contents );
3003
+
3004
+ attr( col.mData.sort, cell );
3005
+ attr( col.mData.type, cell );
3006
+ attr( col.mData.filter, cell );
3007
+ }
3008
+ else {
3009
+ // Depending on the `data` option for the columns the data can
3010
+ // be read to either an object or an array.
3011
+ if ( objectRead ) {
3012
+ if ( ! col._setter ) {
3013
+ // Cache the setter function
3014
+ col._setter = _fnSetObjectDataFn( col.mData );
3015
+ }
3016
+ col._setter( d, contents );
3017
+ }
3018
+ else {
3019
+ d[i] = contents;
3020
+ }
3021
+ }
3022
+ }
3023
+
3024
+ i++;
3025
+ };
3026
+
3027
+ if ( td ) {
3028
+ // `tr` element was passed in
3029
+ while ( td ) {
3030
+ name = td.nodeName.toUpperCase();
3031
+
3032
+ if ( name == "TD" || name == "TH" ) {
3033
+ cellProcess( td );
3034
+ tds.push( td );
3035
+ }
3036
+
3037
+ td = td.nextSibling;
3038
+ }
3039
+ }
3040
+ else {
3041
+ // Existing row object passed in
3042
+ tds = row.anCells;
3043
+
3044
+ for ( var j=0, jen=tds.length ; j<jen ; j++ ) {
3045
+ cellProcess( tds[j] );
3046
+ }
3047
+ }
3048
+
3049
+ // Read the ID from the DOM if present
3050
+ var rowNode = row.firstChild ? row : row.nTr;
3051
+
3052
+ if ( rowNode ) {
3053
+ var id = rowNode.getAttribute( 'id' );
3054
+
3055
+ if ( id ) {
3056
+ _fnSetObjectDataFn( settings.rowId )( d, id );
3057
+ }
3058
+ }
3059
+
3060
+ return {
3061
+ data: d,
3062
+ cells: tds
3063
+ };
3064
+ }
3065
+ /**
3066
+ * Create a new TR element (and it's TD children) for a row
3067
+ * @param {object} oSettings dataTables settings object
3068
+ * @param {int} iRow Row to consider
3069
+ * @param {node} [nTrIn] TR element to add to the table - optional. If not given,
3070
+ * DataTables will create a row automatically
3071
+ * @param {array} [anTds] Array of TD|TH elements for the row - must be given
3072
+ * if nTr is.
3073
+ * @memberof DataTable#oApi
3074
+ */
3075
+ function _fnCreateTr ( oSettings, iRow, nTrIn, anTds )
3076
+ {
3077
+ var
3078
+ row = oSettings.aoData[iRow],
3079
+ rowData = row._aData,
3080
+ cells = [],
3081
+ nTr, nTd, oCol,
3082
+ i, iLen;
3083
+
3084
+ if ( row.nTr === null )
3085
+ {
3086
+ nTr = nTrIn || document.createElement('tr');
3087
+
3088
+ row.nTr = nTr;
3089
+ row.anCells = cells;
3090
+
3091
+ /* Use a private property on the node to allow reserve mapping from the node
3092
+ * to the aoData array for fast look up
3093
+ */
3094
+ nTr._DT_RowIndex = iRow;
3095
+
3096
+ /* Special parameters can be given by the data source to be used on the row */
3097
+ _fnRowAttributes( oSettings, row );
3098
+
3099
+ /* Process each column */
3100
+ for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
3101
+ {
3102
+ oCol = oSettings.aoColumns[i];
3103
+
3104
+ nTd = nTrIn ? anTds[i] : document.createElement( oCol.sCellType );
3105
+ nTd._DT_CellIndex = {
3106
+ row: iRow,
3107
+ column: i
3108
+ };
3109
+
3110
+ cells.push( nTd );
3111
+
3112
+ // Need to create the HTML if new, or if a rendering function is defined
3113
+ if ( (!nTrIn || oCol.mRender || oCol.mData !== i) &&
3114
+ (!$.isPlainObject(oCol.mData) || oCol.mData._ !== i+'.display')
3115
+ ) {
3116
+ nTd.innerHTML = _fnGetCellData( oSettings, iRow, i, 'display' );
3117
+ }
3118
+
3119
+ /* Add user defined class */
3120
+ if ( oCol.sClass )
3121
+ {
3122
+ nTd.className += ' '+oCol.sClass;
3123
+ }
3124
+
3125
+ // Visibility - add or remove as required
3126
+ if ( oCol.bVisible && ! nTrIn )
3127
+ {
3128
+ nTr.appendChild( nTd );
3129
+ }
3130
+ else if ( ! oCol.bVisible && nTrIn )
3131
+ {
3132
+ nTd.parentNode.removeChild( nTd );
3133
+ }
3134
+
3135
+ if ( oCol.fnCreatedCell )
3136
+ {
3137
+ oCol.fnCreatedCell.call( oSettings.oInstance,
3138
+ nTd, _fnGetCellData( oSettings, iRow, i ), rowData, iRow, i
3139
+ );
3140
+ }
3141
+ }
3142
+
3143
+ _fnCallbackFire( oSettings, 'aoRowCreatedCallback', null, [nTr, rowData, iRow] );
3144
+ }
3145
+
3146
+ // Remove once webkit bug 131819 and Chromium bug 365619 have been resolved
3147
+ // and deployed
3148
+ row.nTr.setAttribute( 'role', 'row' );
3149
+ }
3150
+
3151
+
3152
+ /**
3153
+ * Add attributes to a row based on the special `DT_*` parameters in a data
3154
+ * source object.
3155
+ * @param {object} settings DataTables settings object
3156
+ * @param {object} DataTables row object for the row to be modified
3157
+ * @memberof DataTable#oApi
3158
+ */
3159
+ function _fnRowAttributes( settings, row )
3160
+ {
3161
+ var tr = row.nTr;
3162
+ var data = row._aData;
3163
+
3164
+ if ( tr ) {
3165
+ var id = settings.rowIdFn( data );
3166
+
3167
+ if ( id ) {
3168
+ tr.id = id;
3169
+ }
3170
+
3171
+ if ( data.DT_RowClass ) {
3172
+ // Remove any classes added by DT_RowClass before
3173
+ var a = data.DT_RowClass.split(' ');
3174
+ row.__rowc = row.__rowc ?
3175
+ _unique( row.__rowc.concat( a ) ) :
3176
+ a;
3177
+
3178
+ $(tr)
3179
+ .removeClass( row.__rowc.join(' ') )
3180
+ .addClass( data.DT_RowClass );
3181
+ }
3182
+
3183
+ if ( data.DT_RowAttr ) {
3184
+ $(tr).attr( data.DT_RowAttr );
3185
+ }
3186
+
3187
+ if ( data.DT_RowData ) {
3188
+ $(tr).data( data.DT_RowData );
3189
+ }
3190
+ }
3191
+ }
3192
+
3193
+
3194
+ /**
3195
+ * Create the HTML header for the table
3196
+ * @param {object} oSettings dataTables settings object
3197
+ * @memberof DataTable#oApi
3198
+ */
3199
+ function _fnBuildHead( oSettings )
3200
+ {
3201
+ var i, ien, cell, row, column;
3202
+ var thead = oSettings.nTHead;
3203
+ var tfoot = oSettings.nTFoot;
3204
+ var createHeader = $('th, td', thead).length === 0;
3205
+ var classes = oSettings.oClasses;
3206
+ var columns = oSettings.aoColumns;
3207
+
3208
+ if ( createHeader ) {
3209
+ row = $('<tr/>').appendTo( thead );
3210
+ }
3211
+
3212
+ for ( i=0, ien=columns.length ; i<ien ; i++ ) {
3213
+ column = columns[i];
3214
+ cell = $( column.nTh ).addClass( column.sClass );
3215
+
3216
+ if ( createHeader ) {
3217
+ cell.appendTo( row );
3218
+ }
3219
+
3220
+ // 1.11 move into sorting
3221
+ if ( oSettings.oFeatures.bSort ) {
3222
+ cell.addClass( column.sSortingClass );
3223
+
3224
+ if ( column.bSortable !== false ) {
3225
+ cell
3226
+ .attr( 'tabindex', oSettings.iTabIndex )
3227
+ .attr( 'aria-controls', oSettings.sTableId );
3228
+
3229
+ _fnSortAttachListener( oSettings, column.nTh, i );
3230
+ }
3231
+ }
3232
+
3233
+ if ( column.sTitle != cell[0].innerHTML ) {
3234
+ cell.html( column.sTitle );
3235
+ }
3236
+
3237
+ _fnRenderer( oSettings, 'header' )(
3238
+ oSettings, cell, column, classes
3239
+ );
3240
+ }
3241
+
3242
+ if ( createHeader ) {
3243
+ _fnDetectHeader( oSettings.aoHeader, thead );
3244
+ }
3245
+
3246
+ /* ARIA role for the rows */
3247
+ $(thead).find('>tr').attr('role', 'row');
3248
+
3249
+ /* Deal with the footer - add classes if required */
3250
+ $(thead).find('>tr>th, >tr>td').addClass( classes.sHeaderTH );
3251
+ $(tfoot).find('>tr>th, >tr>td').addClass( classes.sFooterTH );
3252
+
3253
+ // Cache the footer cells. Note that we only take the cells from the first
3254
+ // row in the footer. If there is more than one row the user wants to
3255
+ // interact with, they need to use the table().foot() method. Note also this
3256
+ // allows cells to be used for multiple columns using colspan
3257
+ if ( tfoot !== null ) {
3258
+ var cells = oSettings.aoFooter[0];
3259
+
3260
+ for ( i=0, ien=cells.length ; i<ien ; i++ ) {
3261
+ column = columns[i];
3262
+ column.nTf = cells[i].cell;
3263
+
3264
+ if ( column.sClass ) {
3265
+ $(column.nTf).addClass( column.sClass );
3266
+ }
3267
+ }
3268
+ }
3269
+ }
3270
+
3271
+
3272
+ /**
3273
+ * Draw the header (or footer) element based on the column visibility states. The
3274
+ * methodology here is to use the layout array from _fnDetectHeader, modified for
3275
+ * the instantaneous column visibility, to construct the new layout. The grid is
3276
+ * traversed over cell at a time in a rows x columns grid fashion, although each
3277
+ * cell insert can cover multiple elements in the grid - which is tracks using the
3278
+ * aApplied array. Cell inserts in the grid will only occur where there isn't
3279
+ * already a cell in that position.
3280
+ * @param {object} oSettings dataTables settings object
3281
+ * @param array {objects} aoSource Layout array from _fnDetectHeader
3282
+ * @param {boolean} [bIncludeHidden=false] If true then include the hidden columns in the calc,
3283
+ * @memberof DataTable#oApi
3284
+ */
3285
+ function _fnDrawHead( oSettings, aoSource, bIncludeHidden )
3286
+ {
3287
+ var i, iLen, j, jLen, k, kLen, n, nLocalTr;
3288
+ var aoLocal = [];
3289
+ var aApplied = [];
3290
+ var iColumns = oSettings.aoColumns.length;
3291
+ var iRowspan, iColspan;
3292
+
3293
+ if ( ! aoSource )
3294
+ {
3295
+ return;
3296
+ }
3297
+
3298
+ if ( bIncludeHidden === undefined )
3299
+ {
3300
+ bIncludeHidden = false;
3301
+ }
3302
+
3303
+ /* Make a copy of the master layout array, but without the visible columns in it */
3304
+ for ( i=0, iLen=aoSource.length ; i<iLen ; i++ )
3305
+ {
3306
+ aoLocal[i] = aoSource[i].slice();
3307
+ aoLocal[i].nTr = aoSource[i].nTr;
3308
+
3309
+ /* Remove any columns which are currently hidden */
3310
+ for ( j=iColumns-1 ; j>=0 ; j-- )
3311
+ {
3312
+ if ( !oSettings.aoColumns[j].bVisible && !bIncludeHidden )
3313
+ {
3314
+ aoLocal[i].splice( j, 1 );
3315
+ }
3316
+ }
3317
+
3318
+ /* Prep the applied array - it needs an element for each row */
3319
+ aApplied.push( [] );
3320
+ }
3321
+
3322
+ for ( i=0, iLen=aoLocal.length ; i<iLen ; i++ )
3323
+ {
3324
+ nLocalTr = aoLocal[i].nTr;
3325
+
3326
+ /* All cells are going to be replaced, so empty out the row */
3327
+ if ( nLocalTr )
3328
+ {
3329
+ while( (n = nLocalTr.firstChild) )
3330
+ {
3331
+ nLocalTr.removeChild( n );
3332
+ }
3333
+ }
3334
+
3335
+ for ( j=0, jLen=aoLocal[i].length ; j<jLen ; j++ )
3336
+ {
3337
+ iRowspan = 1;
3338
+ iColspan = 1;
3339
+
3340
+ /* Check to see if there is already a cell (row/colspan) covering our target
3341
+ * insert point. If there is, then there is nothing to do.
3342
+ */
3343
+ if ( aApplied[i][j] === undefined )
3344
+ {
3345
+ nLocalTr.appendChild( aoLocal[i][j].cell );
3346
+ aApplied[i][j] = 1;
3347
+
3348
+ /* Expand the cell to cover as many rows as needed */
3349
+ while ( aoLocal[i+iRowspan] !== undefined &&
3350
+ aoLocal[i][j].cell == aoLocal[i+iRowspan][j].cell )
3351
+ {
3352
+ aApplied[i+iRowspan][j] = 1;
3353
+ iRowspan++;
3354
+ }
3355
+
3356
+ /* Expand the cell to cover as many columns as needed */
3357
+ while ( aoLocal[i][j+iColspan] !== undefined &&
3358
+ aoLocal[i][j].cell == aoLocal[i][j+iColspan].cell )
3359
+ {
3360
+ /* Must update the applied array over the rows for the columns */
3361
+ for ( k=0 ; k<iRowspan ; k++ )
3362
+ {
3363
+ aApplied[i+k][j+iColspan] = 1;
3364
+ }
3365
+ iColspan++;
3366
+ }
3367
+
3368
+ /* Do the actual expansion in the DOM */
3369
+ $(aoLocal[i][j].cell)
3370
+ .attr('rowspan', iRowspan)
3371
+ .attr('colspan', iColspan);
3372
+ }
3373
+ }
3374
+ }
3375
+ }
3376
+
3377
+
3378
+ /**
3379
+ * Insert the required TR nodes into the table for display
3380
+ * @param {object} oSettings dataTables settings object
3381
+ * @memberof DataTable#oApi
3382
+ */
3383
+ function _fnDraw( oSettings )
3384
+ {
3385
+ /* Provide a pre-callback function which can be used to cancel the draw is false is returned */
3386
+ var aPreDraw = _fnCallbackFire( oSettings, 'aoPreDrawCallback', 'preDraw', [oSettings] );
3387
+ if ( $.inArray( false, aPreDraw ) !== -1 )
3388
+ {
3389
+ _fnProcessingDisplay( oSettings, false );
3390
+ return;
3391
+ }
3392
+
3393
+ var i, iLen, n;
3394
+ var anRows = [];
3395
+ var iRowCount = 0;
3396
+ var asStripeClasses = oSettings.asStripeClasses;
3397
+ var iStripes = asStripeClasses.length;
3398
+ var iOpenRows = oSettings.aoOpenRows.length;
3399
+ var oLang = oSettings.oLanguage;
3400
+ var iInitDisplayStart = oSettings.iInitDisplayStart;
3401
+ var bServerSide = _fnDataSource( oSettings ) == 'ssp';
3402
+ var aiDisplay = oSettings.aiDisplay;
3403
+
3404
+ oSettings.bDrawing = true;
3405
+
3406
+ /* Check and see if we have an initial draw position from state saving */
3407
+ if ( iInitDisplayStart !== undefined && iInitDisplayStart !== -1 )
3408
+ {
3409
+ oSettings._iDisplayStart = bServerSide ?
3410
+ iInitDisplayStart :
3411
+ iInitDisplayStart >= oSettings.fnRecordsDisplay() ?
3412
+ 0 :
3413
+ iInitDisplayStart;
3414
+
3415
+ oSettings.iInitDisplayStart = -1;
3416
+ }
3417
+
3418
+ var iDisplayStart = oSettings._iDisplayStart;
3419
+ var iDisplayEnd = oSettings.fnDisplayEnd();
3420
+
3421
+ /* Server-side processing draw intercept */
3422
+ if ( oSettings.bDeferLoading )
3423
+ {
3424
+ oSettings.bDeferLoading = false;
3425
+ oSettings.iDraw++;
3426
+ _fnProcessingDisplay( oSettings, false );
3427
+ }
3428
+ else if ( !bServerSide )
3429
+ {
3430
+ oSettings.iDraw++;
3431
+ }
3432
+ else if ( !oSettings.bDestroying && !_fnAjaxUpdate( oSettings ) )
3433
+ {
3434
+ return;
3435
+ }
3436
+
3437
+ if ( aiDisplay.length !== 0 )
3438
+ {
3439
+ var iStart = bServerSide ? 0 : iDisplayStart;
3440
+ var iEnd = bServerSide ? oSettings.aoData.length : iDisplayEnd;
3441
+
3442
+ for ( var j=iStart ; j<iEnd ; j++ )
3443
+ {
3444
+ var iDataIndex = aiDisplay[j];
3445
+ var aoData = oSettings.aoData[ iDataIndex ];
3446
+ if ( aoData.nTr === null )
3447
+ {
3448
+ _fnCreateTr( oSettings, iDataIndex );
3449
+ }
3450
+
3451
+ var nRow = aoData.nTr;
3452
+
3453
+ /* Remove the old striping classes and then add the new one */
3454
+ if ( iStripes !== 0 )
3455
+ {
3456
+ var sStripe = asStripeClasses[ iRowCount % iStripes ];
3457
+ if ( aoData._sRowStripe != sStripe )
3458
+ {
3459
+ $(nRow).removeClass( aoData._sRowStripe ).addClass( sStripe );
3460
+ aoData._sRowStripe = sStripe;
3461
+ }
3462
+ }
3463
+
3464
+ // Row callback functions - might want to manipulate the row
3465
+ // iRowCount and j are not currently documented. Are they at all
3466
+ // useful?
3467
+ _fnCallbackFire( oSettings, 'aoRowCallback', null,
3468
+ [nRow, aoData._aData, iRowCount, j] );
3469
+
3470
+ anRows.push( nRow );
3471
+ iRowCount++;
3472
+ }
3473
+ }
3474
+ else
3475
+ {
3476
+ /* Table is empty - create a row with an empty message in it */
3477
+ var sZero = oLang.sZeroRecords;
3478
+ if ( oSettings.iDraw == 1 && _fnDataSource( oSettings ) == 'ajax' )
3479
+ {
3480
+ sZero = oLang.sLoadingRecords;
3481
+ }
3482
+ else if ( oLang.sEmptyTable && oSettings.fnRecordsTotal() === 0 )
3483
+ {
3484
+ sZero = oLang.sEmptyTable;
3485
+ }
3486
+
3487
+ anRows[ 0 ] = $( '<tr/>', { 'class': iStripes ? asStripeClasses[0] : '' } )
3488
+ .append( $('<td />', {
3489
+ 'valign': 'top',
3490
+ 'colSpan': _fnVisbleColumns( oSettings ),
3491
+ 'class': oSettings.oClasses.sRowEmpty
3492
+ } ).html( sZero ) )[0];
3493
+ }
3494
+
3495
+ /* Header and footer callbacks */
3496
+ _fnCallbackFire( oSettings, 'aoHeaderCallback', 'header', [ $(oSettings.nTHead).children('tr')[0],
3497
+ _fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] );
3498
+
3499
+ _fnCallbackFire( oSettings, 'aoFooterCallback', 'footer', [ $(oSettings.nTFoot).children('tr')[0],
3500
+ _fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] );
3501
+
3502
+ var body = $(oSettings.nTBody);
3503
+
3504
+ body.children().detach();
3505
+ body.append( $(anRows) );
3506
+
3507
+ /* Call all required callback functions for the end of a draw */
3508
+ _fnCallbackFire( oSettings, 'aoDrawCallback', 'draw', [oSettings] );
3509
+
3510
+ /* Draw is complete, sorting and filtering must be as well */
3511
+ oSettings.bSorted = false;
3512
+ oSettings.bFiltered = false;
3513
+ oSettings.bDrawing = false;
3514
+ }
3515
+
3516
+
3517
+ /**
3518
+ * Redraw the table - taking account of the various features which are enabled
3519
+ * @param {object} oSettings dataTables settings object
3520
+ * @param {boolean} [holdPosition] Keep the current paging position. By default
3521
+ * the paging is reset to the first page
3522
+ * @memberof DataTable#oApi
3523
+ */
3524
+ function _fnReDraw( settings, holdPosition )
3525
+ {
3526
+ var
3527
+ features = settings.oFeatures,
3528
+ sort = features.bSort,
3529
+ filter = features.bFilter;
3530
+
3531
+ if ( sort ) {
3532
+ _fnSort( settings );
3533
+ }
3534
+
3535
+ if ( filter ) {
3536
+ _fnFilterComplete( settings, settings.oPreviousSearch );
3537
+ }
3538
+ else {
3539
+ // No filtering, so we want to just use the display master
3540
+ settings.aiDisplay = settings.aiDisplayMaster.slice();
3541
+ }
3542
+
3543
+ if ( holdPosition !== true ) {
3544
+ settings._iDisplayStart = 0;
3545
+ }
3546
+
3547
+ // Let any modules know about the draw hold position state (used by
3548
+ // scrolling internally)
3549
+ settings._drawHold = holdPosition;
3550
+
3551
+ _fnDraw( settings );
3552
+
3553
+ settings._drawHold = false;
3554
+ }
3555
+
3556
+
3557
+ /**
3558
+ * Add the options to the page HTML for the table
3559
+ * @param {object} oSettings dataTables settings object
3560
+ * @memberof DataTable#oApi
3561
+ */
3562
+ function _fnAddOptionsHtml ( oSettings )
3563
+ {
3564
+ var classes = oSettings.oClasses;
3565
+ var table = $(oSettings.nTable);
3566
+ var holding = $('<div/>').insertBefore( table ); // Holding element for speed
3567
+ var features = oSettings.oFeatures;
3568
+
3569
+ // All DataTables are wrapped in a div
3570
+ var insert = $('<div/>', {
3571
+ id: oSettings.sTableId+'_wrapper',
3572
+ 'class': classes.sWrapper + (oSettings.nTFoot ? '' : ' '+classes.sNoFooter)
3573
+ } );
3574
+
3575
+ oSettings.nHolding = holding[0];
3576
+ oSettings.nTableWrapper = insert[0];
3577
+ oSettings.nTableReinsertBefore = oSettings.nTable.nextSibling;
3578
+
3579
+ /* Loop over the user set positioning and place the elements as needed */
3580
+ var aDom = oSettings.sDom.split('');
3581
+ var featureNode, cOption, nNewNode, cNext, sAttr, j;
3582
+ for ( var i=0 ; i<aDom.length ; i++ )
3583
+ {
3584
+ featureNode = null;
3585
+ cOption = aDom[i];
3586
+
3587
+ if ( cOption == '<' )
3588
+ {
3589
+ /* New container div */
3590
+ nNewNode = $('<div/>')[0];
3591
+
3592
+ /* Check to see if we should append an id and/or a class name to the container */
3593
+ cNext = aDom[i+1];
3594
+ if ( cNext == "'" || cNext == '"' )
3595
+ {
3596
+ sAttr = "";
3597
+ j = 2;
3598
+ while ( aDom[i+j] != cNext )
3599
+ {
3600
+ sAttr += aDom[i+j];
3601
+ j++;
3602
+ }
3603
+
3604
+ /* Replace jQuery UI constants @todo depreciated */
3605
+ if ( sAttr == "H" )
3606
+ {
3607
+ sAttr = classes.sJUIHeader;
3608
+ }
3609
+ else if ( sAttr == "F" )
3610
+ {
3611
+ sAttr = classes.sJUIFooter;
3612
+ }
3613
+
3614
+ /* The attribute can be in the format of "#id.class", "#id" or "class" This logic
3615
+ * breaks the string into parts and applies them as needed
3616
+ */
3617
+ if ( sAttr.indexOf('.') != -1 )
3618
+ {
3619
+ var aSplit = sAttr.split('.');
3620
+ nNewNode.id = aSplit[0].substr(1, aSplit[0].length-1);
3621
+ nNewNode.className = aSplit[1];
3622
+ }
3623
+ else if ( sAttr.charAt(0) == "#" )
3624
+ {
3625
+ nNewNode.id = sAttr.substr(1, sAttr.length-1);
3626
+ }
3627
+ else
3628
+ {
3629
+ nNewNode.className = sAttr;
3630
+ }
3631
+
3632
+ i += j; /* Move along the position array */
3633
+ }
3634
+
3635
+ insert.append( nNewNode );
3636
+ insert = $(nNewNode);
3637
+ }
3638
+ else if ( cOption == '>' )
3639
+ {
3640
+ /* End container div */
3641
+ insert = insert.parent();
3642
+ }
3643
+ // @todo Move options into their own plugins?
3644
+ else if ( cOption == 'l' && features.bPaginate && features.bLengthChange )
3645
+ {
3646
+ /* Length */
3647
+ featureNode = _fnFeatureHtmlLength( oSettings );
3648
+ }
3649
+ else if ( cOption == 'f' && features.bFilter )
3650
+ {
3651
+ /* Filter */
3652
+ featureNode = _fnFeatureHtmlFilter( oSettings );
3653
+ }
3654
+ else if ( cOption == 'r' && features.bProcessing )
3655
+ {
3656
+ /* pRocessing */
3657
+ featureNode = _fnFeatureHtmlProcessing( oSettings );
3658
+ }
3659
+ else if ( cOption == 't' )
3660
+ {
3661
+ /* Table */
3662
+ featureNode = _fnFeatureHtmlTable( oSettings );
3663
+ }
3664
+ else if ( cOption == 'i' && features.bInfo )
3665
+ {
3666
+ /* Info */
3667
+ featureNode = _fnFeatureHtmlInfo( oSettings );
3668
+ }
3669
+ else if ( cOption == 'p' && features.bPaginate )
3670
+ {
3671
+ /* Pagination */
3672
+ featureNode = _fnFeatureHtmlPaginate( oSettings );
3673
+ }
3674
+ else if ( DataTable.ext.feature.length !== 0 )
3675
+ {
3676
+ /* Plug-in features */
3677
+ var aoFeatures = DataTable.ext.feature;
3678
+ for ( var k=0, kLen=aoFeatures.length ; k<kLen ; k++ )
3679
+ {
3680
+ if ( cOption == aoFeatures[k].cFeature )
3681
+ {
3682
+ featureNode = aoFeatures[k].fnInit( oSettings );
3683
+ break;
3684
+ }
3685
+ }
3686
+ }
3687
+
3688
+ /* Add to the 2D features array */
3689
+ if ( featureNode )
3690
+ {
3691
+ var aanFeatures = oSettings.aanFeatures;
3692
+
3693
+ if ( ! aanFeatures[cOption] )
3694
+ {
3695
+ aanFeatures[cOption] = [];
3696
+ }
3697
+
3698
+ aanFeatures[cOption].push( featureNode );
3699
+ insert.append( featureNode );
3700
+ }
3701
+ }
3702
+
3703
+ /* Built our DOM structure - replace the holding div with what we want */
3704
+ holding.replaceWith( insert );
3705
+ oSettings.nHolding = null;
3706
+ }
3707
+
3708
+
3709
+ /**
3710
+ * Use the DOM source to create up an array of header cells. The idea here is to
3711
+ * create a layout grid (array) of rows x columns, which contains a reference
3712
+ * to the cell that that point in the grid (regardless of col/rowspan), such that
3713
+ * any column / row could be removed and the new grid constructed
3714
+ * @param array {object} aLayout Array to store the calculated layout in
3715
+ * @param {node} nThead The header/footer element for the table
3716
+ * @memberof DataTable#oApi
3717
+ */
3718
+ function _fnDetectHeader ( aLayout, nThead )
3719
+ {
3720
+ var nTrs = $(nThead).children('tr');
3721
+ var nTr, nCell;
3722
+ var i, k, l, iLen, jLen, iColShifted, iColumn, iColspan, iRowspan;
3723
+ var bUnique;
3724
+ var fnShiftCol = function ( a, i, j ) {
3725
+ var k = a[i];
3726
+ while ( k[j] ) {
3727
+ j++;
3728
+ }
3729
+ return j;
3730
+ };
3731
+
3732
+ aLayout.splice( 0, aLayout.length );
3733
+
3734
+ /* We know how many rows there are in the layout - so prep it */
3735
+ for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
3736
+ {
3737
+ aLayout.push( [] );
3738
+ }
3739
+
3740
+ /* Calculate a layout array */
3741
+ for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
3742
+ {
3743
+ nTr = nTrs[i];
3744
+ iColumn = 0;
3745
+
3746
+ /* For every cell in the row... */
3747
+ nCell = nTr.firstChild;
3748
+ while ( nCell ) {
3749
+ if ( nCell.nodeName.toUpperCase() == "TD" ||
3750
+ nCell.nodeName.toUpperCase() == "TH" )
3751
+ {
3752
+ /* Get the col and rowspan attributes from the DOM and sanitise them */
3753
+ iColspan = nCell.getAttribute('colspan') * 1;
3754
+ iRowspan = nCell.getAttribute('rowspan') * 1;
3755
+ iColspan = (!iColspan || iColspan===0 || iColspan===1) ? 1 : iColspan;
3756
+ iRowspan = (!iRowspan || iRowspan===0 || iRowspan===1) ? 1 : iRowspan;
3757
+
3758
+ /* There might be colspan cells already in this row, so shift our target
3759
+ * accordingly
3760
+ */
3761
+ iColShifted = fnShiftCol( aLayout, i, iColumn );
3762
+
3763
+ /* Cache calculation for unique columns */
3764
+ bUnique = iColspan === 1 ? true : false;
3765
+
3766
+ /* If there is col / rowspan, copy the information into the layout grid */
3767
+ for ( l=0 ; l<iColspan ; l++ )
3768
+ {
3769
+ for ( k=0 ; k<iRowspan ; k++ )
3770
+ {
3771
+ aLayout[i+k][iColShifted+l] = {
3772
+ "cell": nCell,
3773
+ "unique": bUnique
3774
+ };
3775
+ aLayout[i+k].nTr = nTr;
3776
+ }
3777
+ }
3778
+ }
3779
+ nCell = nCell.nextSibling;
3780
+ }
3781
+ }
3782
+ }
3783
+
3784
+
3785
+ /**
3786
+ * Get an array of unique th elements, one for each column
3787
+ * @param {object} oSettings dataTables settings object
3788
+ * @param {node} nHeader automatically detect the layout from this node - optional
3789
+ * @param {array} aLayout thead/tfoot layout from _fnDetectHeader - optional
3790
+ * @returns array {node} aReturn list of unique th's
3791
+ * @memberof DataTable#oApi
3792
+ */
3793
+ function _fnGetUniqueThs ( oSettings, nHeader, aLayout )
3794
+ {
3795
+ var aReturn = [];
3796
+ if ( !aLayout )
3797
+ {
3798
+ aLayout = oSettings.aoHeader;
3799
+ if ( nHeader )
3800
+ {
3801
+ aLayout = [];
3802
+ _fnDetectHeader( aLayout, nHeader );
3803
+ }
3804
+ }
3805
+
3806
+ for ( var i=0, iLen=aLayout.length ; i<iLen ; i++ )
3807
+ {
3808
+ for ( var j=0, jLen=aLayout[i].length ; j<jLen ; j++ )
3809
+ {
3810
+ if ( aLayout[i][j].unique &&
3811
+ (!aReturn[j] || !oSettings.bSortCellsTop) )
3812
+ {
3813
+ aReturn[j] = aLayout[i][j].cell;
3814
+ }
3815
+ }
3816
+ }
3817
+
3818
+ return aReturn;
3819
+ }
3820
+
3821
+ /**
3822
+ * Create an Ajax call based on the table's settings, taking into account that
3823
+ * parameters can have multiple forms, and backwards compatibility.
3824
+ *
3825
+ * @param {object} oSettings dataTables settings object
3826
+ * @param {array} data Data to send to the server, required by
3827
+ * DataTables - may be augmented by developer callbacks
3828
+ * @param {function} fn Callback function to run when data is obtained
3829
+ */
3830
+ function _fnBuildAjax( oSettings, data, fn )
3831
+ {
3832
+ // Compatibility with 1.9-, allow fnServerData and event to manipulate
3833
+ _fnCallbackFire( oSettings, 'aoServerParams', 'serverParams', [data] );
3834
+
3835
+ // Convert to object based for 1.10+ if using the old array scheme which can
3836
+ // come from server-side processing or serverParams
3837
+ if ( data && $.isArray(data) ) {
3838
+ var tmp = {};
3839
+ var rbracket = /(.*?)\[\]$/;
3840
+
3841
+ $.each( data, function (key, val) {
3842
+ var match = val.name.match(rbracket);
3843
+
3844
+ if ( match ) {
3845
+ // Support for arrays
3846
+ var name = match[0];
3847
+
3848
+ if ( ! tmp[ name ] ) {
3849
+ tmp[ name ] = [];
3850
+ }
3851
+ tmp[ name ].push( val.value );
3852
+ }
3853
+ else {
3854
+ tmp[val.name] = val.value;
3855
+ }
3856
+ } );
3857
+ data = tmp;
3858
+ }
3859
+
3860
+ var ajaxData;
3861
+ var ajax = oSettings.ajax;
3862
+ var instance = oSettings.oInstance;
3863
+ var callback = function ( json ) {
3864
+ _fnCallbackFire( oSettings, null, 'xhr', [oSettings, json, oSettings.jqXHR] );
3865
+ fn( json );
3866
+ };
3867
+
3868
+ if ( $.isPlainObject( ajax ) && ajax.data )
3869
+ {
3870
+ ajaxData = ajax.data;
3871
+
3872
+ var newData = $.isFunction( ajaxData ) ?
3873
+ ajaxData( data, oSettings ) : // fn can manipulate data or return
3874
+ ajaxData; // an object object or array to merge
3875
+
3876
+ // If the function returned something, use that alone
3877
+ data = $.isFunction( ajaxData ) && newData ?
3878
+ newData :
3879
+ $.extend( true, data, newData );
3880
+
3881
+ // Remove the data property as we've resolved it already and don't want
3882
+ // jQuery to do it again (it is restored at the end of the function)
3883
+ delete ajax.data;
3884
+ }
3885
+
3886
+ var baseAjax = {
3887
+ "data": data,
3888
+ "success": function (json) {
3889
+ var error = json.error || json.sError;
3890
+ if ( error ) {
3891
+ _fnLog( oSettings, 0, error );
3892
+ }
3893
+
3894
+ oSettings.json = json;
3895
+ callback( json );
3896
+ },
3897
+ "dataType": "json",
3898
+ "cache": false,
3899
+ "type": oSettings.sServerMethod,
3900
+ "error": function (xhr, error, thrown) {
3901
+ var ret = _fnCallbackFire( oSettings, null, 'xhr', [oSettings, null, oSettings.jqXHR] );
3902
+
3903
+ if ( $.inArray( true, ret ) === -1 ) {
3904
+ if ( error == "parsererror" ) {
3905
+ _fnLog( oSettings, 0, 'Invalid JSON response', 1 );
3906
+ }
3907
+ else if ( xhr.readyState === 4 ) {
3908
+ _fnLog( oSettings, 0, 'Ajax error', 7 );
3909
+ }
3910
+ }
3911
+
3912
+ _fnProcessingDisplay( oSettings, false );
3913
+ }
3914
+ };
3915
+
3916
+ // Store the data submitted for the API
3917
+ oSettings.oAjaxData = data;
3918
+
3919
+ // Allow plug-ins and external processes to modify the data
3920
+ _fnCallbackFire( oSettings, null, 'preXhr', [oSettings, data] );
3921
+
3922
+ if ( oSettings.fnServerData )
3923
+ {
3924
+ // DataTables 1.9- compatibility
3925
+ oSettings.fnServerData.call( instance,
3926
+ oSettings.sAjaxSource,
3927
+ $.map( data, function (val, key) { // Need to convert back to 1.9 trad format
3928
+ return { name: key, value: val };
3929
+ } ),
3930
+ callback,
3931
+ oSettings
3932
+ );
3933
+ }
3934
+ else if ( oSettings.sAjaxSource || typeof ajax === 'string' )
3935
+ {
3936
+ // DataTables 1.9- compatibility
3937
+ oSettings.jqXHR = $.ajax( $.extend( baseAjax, {
3938
+ url: ajax || oSettings.sAjaxSource
3939
+ } ) );
3940
+ }
3941
+ else if ( $.isFunction( ajax ) )
3942
+ {
3943
+ // Is a function - let the caller define what needs to be done
3944
+ oSettings.jqXHR = ajax.call( instance, data, callback, oSettings );
3945
+ }
3946
+ else
3947
+ {
3948
+ // Object to extend the base settings
3949
+ oSettings.jqXHR = $.ajax( $.extend( baseAjax, ajax ) );
3950
+
3951
+ // Restore for next time around
3952
+ ajax.data = ajaxData;
3953
+ }
3954
+ }
3955
+
3956
+
3957
+ /**
3958
+ * Update the table using an Ajax call
3959
+ * @param {object} settings dataTables settings object
3960
+ * @returns {boolean} Block the table drawing or not
3961
+ * @memberof DataTable#oApi
3962
+ */
3963
+ function _fnAjaxUpdate( settings )
3964
+ {
3965
+ if ( settings.bAjaxDataGet ) {
3966
+ settings.iDraw++;
3967
+ _fnProcessingDisplay( settings, true );
3968
+
3969
+ _fnBuildAjax(
3970
+ settings,
3971
+ _fnAjaxParameters( settings ),
3972
+ function(json) {
3973
+ _fnAjaxUpdateDraw( settings, json );
3974
+ }
3975
+ );
3976
+
3977
+ return false;
3978
+ }
3979
+ return true;
3980
+ }
3981
+
3982
+
3983
+ /**
3984
+ * Build up the parameters in an object needed for a server-side processing
3985
+ * request. Note that this is basically done twice, is different ways - a modern
3986
+ * method which is used by default in DataTables 1.10 which uses objects and
3987
+ * arrays, or the 1.9- method with is name / value pairs. 1.9 method is used if
3988
+ * the sAjaxSource option is used in the initialisation, or the legacyAjax
3989
+ * option is set.
3990
+ * @param {object} oSettings dataTables settings object
3991
+ * @returns {bool} block the table drawing or not
3992
+ * @memberof DataTable#oApi
3993
+ */
3994
+ function _fnAjaxParameters( settings )
3995
+ {
3996
+ var
3997
+ columns = settings.aoColumns,
3998
+ columnCount = columns.length,
3999
+ features = settings.oFeatures,
4000
+ preSearch = settings.oPreviousSearch,
4001
+ preColSearch = settings.aoPreSearchCols,
4002
+ i, data = [], dataProp, column, columnSearch,
4003
+ sort = _fnSortFlatten( settings ),
4004
+ displayStart = settings._iDisplayStart,
4005
+ displayLength = features.bPaginate !== false ?
4006
+ settings._iDisplayLength :
4007
+ -1;
4008
+
4009
+ var param = function ( name, value ) {
4010
+ data.push( { 'name': name, 'value': value } );
4011
+ };
4012
+
4013
+ // DataTables 1.9- compatible method
4014
+ param( 'sEcho', settings.iDraw );
4015
+ param( 'iColumns', columnCount );
4016
+ param( 'sColumns', _pluck( columns, 'sName' ).join(',') );
4017
+ param( 'iDisplayStart', displayStart );
4018
+ param( 'iDisplayLength', displayLength );
4019
+
4020
+ // DataTables 1.10+ method
4021
+ var d = {
4022
+ draw: settings.iDraw,
4023
+ columns: [],
4024
+ order: [],
4025
+ start: displayStart,
4026
+ length: displayLength,
4027
+ search: {
4028
+ value: preSearch.sSearch,
4029
+ regex: preSearch.bRegex
4030
+ }
4031
+ };
4032
+
4033
+ for ( i=0 ; i<columnCount ; i++ ) {
4034
+ column = columns[i];
4035
+ columnSearch = preColSearch[i];
4036
+ dataProp = typeof column.mData=="function" ? 'function' : column.mData ;
4037
+
4038
+ d.columns.push( {
4039
+ data: dataProp,
4040
+ name: column.sName,
4041
+ searchable: column.bSearchable,
4042
+ orderable: column.bSortable,
4043
+ search: {
4044
+ value: columnSearch.sSearch,
4045
+ regex: columnSearch.bRegex
4046
+ }
4047
+ } );
4048
+
4049
+ param( "mDataProp_"+i, dataProp );
4050
+
4051
+ if ( features.bFilter ) {
4052
+ param( 'sSearch_'+i, columnSearch.sSearch );
4053
+ param( 'bRegex_'+i, columnSearch.bRegex );
4054
+ param( 'bSearchable_'+i, column.bSearchable );
4055
+ }
4056
+
4057
+ if ( features.bSort ) {
4058
+ param( 'bSortable_'+i, column.bSortable );
4059
+ }
4060
+ }
4061
+
4062
+ if ( features.bFilter ) {
4063
+ param( 'sSearch', preSearch.sSearch );
4064
+ param( 'bRegex', preSearch.bRegex );
4065
+ }
4066
+
4067
+ if ( features.bSort ) {
4068
+ $.each( sort, function ( i, val ) {
4069
+ d.order.push( { column: val.col, dir: val.dir } );
4070
+
4071
+ param( 'iSortCol_'+i, val.col );
4072
+ param( 'sSortDir_'+i, val.dir );
4073
+ } );
4074
+
4075
+ param( 'iSortingCols', sort.length );
4076
+ }
4077
+
4078
+ // If the legacy.ajax parameter is null, then we automatically decide which
4079
+ // form to use, based on sAjaxSource
4080
+ var legacy = DataTable.ext.legacy.ajax;
4081
+ if ( legacy === null ) {
4082
+ return settings.sAjaxSource ? data : d;
4083
+ }
4084
+
4085
+ // Otherwise, if legacy has been specified then we use that to decide on the
4086
+ // form
4087
+ return legacy ? data : d;
4088
+ }
4089
+
4090
+
4091
+ /**
4092
+ * Data the data from the server (nuking the old) and redraw the table
4093
+ * @param {object} oSettings dataTables settings object
4094
+ * @param {object} json json data return from the server.
4095
+ * @param {string} json.sEcho Tracking flag for DataTables to match requests
4096
+ * @param {int} json.iTotalRecords Number of records in the data set, not accounting for filtering
4097
+ * @param {int} json.iTotalDisplayRecords Number of records in the data set, accounting for filtering
4098
+ * @param {array} json.aaData The data to display on this page
4099
+ * @param {string} [json.sColumns] Column ordering (sName, comma separated)
4100
+ * @memberof DataTable#oApi
4101
+ */
4102
+ function _fnAjaxUpdateDraw ( settings, json )
4103
+ {
4104
+ // v1.10 uses camelCase variables, while 1.9 uses Hungarian notation.
4105
+ // Support both
4106
+ var compat = function ( old, modern ) {
4107
+ return json[old] !== undefined ? json[old] : json[modern];
4108
+ };
4109
+
4110
+ var data = _fnAjaxDataSrc( settings, json );
4111
+ var draw = compat( 'sEcho', 'draw' );
4112
+ var recordsTotal = compat( 'iTotalRecords', 'recordsTotal' );
4113
+ var recordsFiltered = compat( 'iTotalDisplayRecords', 'recordsFiltered' );
4114
+
4115
+ if ( draw ) {
4116
+ // Protect against out of sequence returns
4117
+ if ( draw*1 < settings.iDraw ) {
4118
+ return;
4119
+ }
4120
+ settings.iDraw = draw * 1;
4121
+ }
4122
+
4123
+ _fnClearTable( settings );
4124
+ settings._iRecordsTotal = parseInt(recordsTotal, 10);
4125
+ settings._iRecordsDisplay = parseInt(recordsFiltered, 10);
4126
+
4127
+ for ( var i=0, ien=data.length ; i<ien ; i++ ) {
4128
+ _fnAddData( settings, data[i] );
4129
+ }
4130
+ settings.aiDisplay = settings.aiDisplayMaster.slice();
4131
+
4132
+ settings.bAjaxDataGet = false;
4133
+ _fnDraw( settings );
4134
+
4135
+ if ( ! settings._bInitComplete ) {
4136
+ _fnInitComplete( settings, json );
4137
+ }
4138
+
4139
+ settings.bAjaxDataGet = true;
4140
+ _fnProcessingDisplay( settings, false );
4141
+ }
4142
+
4143
+
4144
+ /**
4145
+ * Get the data from the JSON data source to use for drawing a table. Using
4146
+ * `_fnGetObjectDataFn` allows the data to be sourced from a property of the
4147
+ * source object, or from a processing function.
4148
+ * @param {object} oSettings dataTables settings object
4149
+ * @param {object} json Data source object / array from the server
4150
+ * @return {array} Array of data to use
4151
+ */
4152
+ function _fnAjaxDataSrc ( oSettings, json )
4153
+ {
4154
+ var dataSrc = $.isPlainObject( oSettings.ajax ) && oSettings.ajax.dataSrc !== undefined ?
4155
+ oSettings.ajax.dataSrc :
4156
+ oSettings.sAjaxDataProp; // Compatibility with 1.9-.
4157
+
4158
+ // Compatibility with 1.9-. In order to read from aaData, check if the
4159
+ // default has been changed, if not, check for aaData
4160
+ if ( dataSrc === 'data' ) {
4161
+ return json.aaData || json[dataSrc];
4162
+ }
4163
+
4164
+ return dataSrc !== "" ?
4165
+ _fnGetObjectDataFn( dataSrc )( json ) :
4166
+ json;
4167
+ }
4168
+
4169
+ /**
4170
+ * Generate the node required for filtering text
4171
+ * @returns {node} Filter control element
4172
+ * @param {object} oSettings dataTables settings object
4173
+ * @memberof DataTable#oApi
4174
+ */
4175
+ function _fnFeatureHtmlFilter ( settings )
4176
+ {
4177
+ var classes = settings.oClasses;
4178
+ var tableId = settings.sTableId;
4179
+ var language = settings.oLanguage;
4180
+ var previousSearch = settings.oPreviousSearch;
4181
+ var features = settings.aanFeatures;
4182
+ var input = '<input type="search" class="'+classes.sFilterInput+'"/>';
4183
+
4184
+ var str = language.sSearch;
4185
+ str = str.match(/_INPUT_/) ?
4186
+ str.replace('_INPUT_', input) :
4187
+ str+input;
4188
+
4189
+ var filter = $('<div/>', {
4190
+ 'id': ! features.f ? tableId+'_filter' : null,
4191
+ 'class': classes.sFilter
4192
+ } )
4193
+ .append( $('<label/>' ).append( str ) );
4194
+
4195
+ var searchFn = function() {
4196
+ /* Update all other filter input elements for the new display */
4197
+ var n = features.f;
4198
+ var val = !this.value ? "" : this.value; // mental IE8 fix :-(
4199
+
4200
+ /* Now do the filter */
4201
+ if ( val != previousSearch.sSearch ) {
4202
+ _fnFilterComplete( settings, {
4203
+ "sSearch": val,
4204
+ "bRegex": previousSearch.bRegex,
4205
+ "bSmart": previousSearch.bSmart ,
4206
+ "bCaseInsensitive": previousSearch.bCaseInsensitive
4207
+ } );
4208
+
4209
+ // Need to redraw, without resorting
4210
+ settings._iDisplayStart = 0;
4211
+ _fnDraw( settings );
4212
+ }
4213
+ };
4214
+
4215
+ var searchDelay = settings.searchDelay !== null ?
4216
+ settings.searchDelay :
4217
+ _fnDataSource( settings ) === 'ssp' ?
4218
+ 400 :
4219
+ 0;
4220
+
4221
+ var jqFilter = $('input', filter)
4222
+ .val( previousSearch.sSearch )
4223
+ .attr( 'placeholder', language.sSearchPlaceholder )
4224
+ .on(
4225
+ 'keyup.DT search.DT input.DT paste.DT cut.DT',
4226
+ searchDelay ?
4227
+ _fnThrottle( searchFn, searchDelay ) :
4228
+ searchFn
4229
+ )
4230
+ .on( 'keypress.DT', function(e) {
4231
+ /* Prevent form submission */
4232
+ if ( e.keyCode == 13 ) {
4233
+ return false;
4234
+ }
4235
+ } )
4236
+ .attr('aria-controls', tableId);
4237
+
4238
+ // Update the input elements whenever the table is filtered
4239
+ $(settings.nTable).on( 'search.dt.DT', function ( ev, s ) {
4240
+ if ( settings === s ) {
4241
+ // IE9 throws an 'unknown error' if document.activeElement is used
4242
+ // inside an iframe or frame...
4243
+ try {
4244
+ if ( jqFilter[0] !== document.activeElement ) {
4245
+ jqFilter.val( previousSearch.sSearch );
4246
+ }
4247
+ }
4248
+ catch ( e ) {}
4249
+ }
4250
+ } );
4251
+
4252
+ return filter[0];
4253
+ }
4254
+
4255
+
4256
+ /**
4257
+ * Filter the table using both the global filter and column based filtering
4258
+ * @param {object} oSettings dataTables settings object
4259
+ * @param {object} oSearch search information
4260
+ * @param {int} [iForce] force a research of the master array (1) or not (undefined or 0)
4261
+ * @memberof DataTable#oApi
4262
+ */
4263
+ function _fnFilterComplete ( oSettings, oInput, iForce )
4264
+ {
4265
+ var oPrevSearch = oSettings.oPreviousSearch;
4266
+ var aoPrevSearch = oSettings.aoPreSearchCols;
4267
+ var fnSaveFilter = function ( oFilter ) {
4268
+ /* Save the filtering values */
4269
+ oPrevSearch.sSearch = oFilter.sSearch;
4270
+ oPrevSearch.bRegex = oFilter.bRegex;
4271
+ oPrevSearch.bSmart = oFilter.bSmart;
4272
+ oPrevSearch.bCaseInsensitive = oFilter.bCaseInsensitive;
4273
+ };
4274
+ var fnRegex = function ( o ) {
4275
+ // Backwards compatibility with the bEscapeRegex option
4276
+ return o.bEscapeRegex !== undefined ? !o.bEscapeRegex : o.bRegex;
4277
+ };
4278
+
4279
+ // Resolve any column types that are unknown due to addition or invalidation
4280
+ // @todo As per sort - can this be moved into an event handler?
4281
+ _fnColumnTypes( oSettings );
4282
+
4283
+ /* In server-side processing all filtering is done by the server, so no point hanging around here */
4284
+ if ( _fnDataSource( oSettings ) != 'ssp' )
4285
+ {
4286
+ /* Global filter */
4287
+ _fnFilter( oSettings, oInput.sSearch, iForce, fnRegex(oInput), oInput.bSmart, oInput.bCaseInsensitive );
4288
+ fnSaveFilter( oInput );
4289
+
4290
+ /* Now do the individual column filter */
4291
+ for ( var i=0 ; i<aoPrevSearch.length ; i++ )
4292
+ {
4293
+ _fnFilterColumn( oSettings, aoPrevSearch[i].sSearch, i, fnRegex(aoPrevSearch[i]),
4294
+ aoPrevSearch[i].bSmart, aoPrevSearch[i].bCaseInsensitive );
4295
+ }
4296
+
4297
+ /* Custom filtering */
4298
+ _fnFilterCustom( oSettings );
4299
+ }
4300
+ else
4301
+ {
4302
+ fnSaveFilter( oInput );
4303
+ }
4304
+
4305
+ /* Tell the draw function we have been filtering */
4306
+ oSettings.bFiltered = true;
4307
+ _fnCallbackFire( oSettings, null, 'search', [oSettings] );
4308
+ }
4309
+
4310
+
4311
+ /**
4312
+ * Apply custom filtering functions
4313
+ * @param {object} oSettings dataTables settings object
4314
+ * @memberof DataTable#oApi
4315
+ */
4316
+ function _fnFilterCustom( settings )
4317
+ {
4318
+ var filters = DataTable.ext.search;
4319
+ var displayRows = settings.aiDisplay;
4320
+ var row, rowIdx;
4321
+
4322
+ for ( var i=0, ien=filters.length ; i<ien ; i++ ) {
4323
+ var rows = [];
4324
+
4325
+ // Loop over each row and see if it should be included
4326
+ for ( var j=0, jen=displayRows.length ; j<jen ; j++ ) {
4327
+ rowIdx = displayRows[ j ];
4328
+ row = settings.aoData[ rowIdx ];
4329
+
4330
+ if ( filters[i]( settings, row._aFilterData, rowIdx, row._aData, j ) ) {
4331
+ rows.push( rowIdx );
4332
+ }
4333
+ }
4334
+
4335
+ // So the array reference doesn't break set the results into the
4336
+ // existing array
4337
+ displayRows.length = 0;
4338
+ $.merge( displayRows, rows );
4339
+ }
4340
+ }
4341
+
4342
+
4343
+ /**
4344
+ * Filter the table on a per-column basis
4345
+ * @param {object} oSettings dataTables settings object
4346
+ * @param {string} sInput string to filter on
4347
+ * @param {int} iColumn column to filter
4348
+ * @param {bool} bRegex treat search string as a regular expression or not
4349
+ * @param {bool} bSmart use smart filtering or not
4350
+ * @param {bool} bCaseInsensitive Do case insenstive matching or not
4351
+ * @memberof DataTable#oApi
4352
+ */
4353
+ function _fnFilterColumn ( settings, searchStr, colIdx, regex, smart, caseInsensitive )
4354
+ {
4355
+ if ( searchStr === '' ) {
4356
+ return;
4357
+ }
4358
+
4359
+ var data;
4360
+ var out = [];
4361
+ var display = settings.aiDisplay;
4362
+ var rpSearch = _fnFilterCreateSearch( searchStr, regex, smart, caseInsensitive );
4363
+
4364
+ for ( var i=0 ; i<display.length ; i++ ) {
4365
+ data = settings.aoData[ display[i] ]._aFilterData[ colIdx ];
4366
+
4367
+ if ( rpSearch.test( data ) ) {
4368
+ out.push( display[i] );
4369
+ }
4370
+ }
4371
+
4372
+ settings.aiDisplay = out;
4373
+ }
4374
+
4375
+
4376
+ /**
4377
+ * Filter the data table based on user input and draw the table
4378
+ * @param {object} settings dataTables settings object
4379
+ * @param {string} input string to filter on
4380
+ * @param {int} force optional - force a research of the master array (1) or not (undefined or 0)
4381
+ * @param {bool} regex treat as a regular expression or not
4382
+ * @param {bool} smart perform smart filtering or not
4383
+ * @param {bool} caseInsensitive Do case insenstive matching or not
4384
+ * @memberof DataTable#oApi
4385
+ */
4386
+ function _fnFilter( settings, input, force, regex, smart, caseInsensitive )
4387
+ {
4388
+ var rpSearch = _fnFilterCreateSearch( input, regex, smart, caseInsensitive );
4389
+ var prevSearch = settings.oPreviousSearch.sSearch;
4390
+ var displayMaster = settings.aiDisplayMaster;
4391
+ var display, invalidated, i;
4392
+ var filtered = [];
4393
+
4394
+ // Need to take account of custom filtering functions - always filter
4395
+ if ( DataTable.ext.search.length !== 0 ) {
4396
+ force = true;
4397
+ }
4398
+
4399
+ // Check if any of the rows were invalidated
4400
+ invalidated = _fnFilterData( settings );
4401
+
4402
+ // If the input is blank - we just want the full data set
4403
+ if ( input.length <= 0 ) {
4404
+ settings.aiDisplay = displayMaster.slice();
4405
+ }
4406
+ else {
4407
+ // New search - start from the master array
4408
+ if ( invalidated ||
4409
+ force ||
4410
+ prevSearch.length > input.length ||
4411
+ input.indexOf(prevSearch) !== 0 ||
4412
+ settings.bSorted // On resort, the display master needs to be
4413
+ // re-filtered since indexes will have changed
4414
+ ) {
4415
+ settings.aiDisplay = displayMaster.slice();
4416
+ }
4417
+
4418
+ // Search the display array
4419
+ display = settings.aiDisplay;
4420
+
4421
+ for ( i=0 ; i<display.length ; i++ ) {
4422
+ if ( rpSearch.test( settings.aoData[ display[i] ]._sFilterRow ) ) {
4423
+ filtered.push( display[i] );
4424
+ }
4425
+ }
4426
+
4427
+ settings.aiDisplay = filtered;
4428
+ }
4429
+ }
4430
+
4431
+
4432
+ /**
4433
+ * Build a regular expression object suitable for searching a table
4434
+ * @param {string} sSearch string to search for
4435
+ * @param {bool} bRegex treat as a regular expression or not
4436
+ * @param {bool} bSmart perform smart filtering or not
4437
+ * @param {bool} bCaseInsensitive Do case insensitive matching or not
4438
+ * @returns {RegExp} constructed object
4439
+ * @memberof DataTable#oApi
4440
+ */
4441
+ function _fnFilterCreateSearch( search, regex, smart, caseInsensitive )
4442
+ {
4443
+ search = regex ?
4444
+ search :
4445
+ _fnEscapeRegex( search );
4446
+
4447
+ if ( smart ) {
4448
+ /* For smart filtering we want to allow the search to work regardless of
4449
+ * word order. We also want double quoted text to be preserved, so word
4450
+ * order is important - a la google. So this is what we want to
4451
+ * generate:
4452
+ *
4453
+ * ^(?=.*?\bone\b)(?=.*?\btwo three\b)(?=.*?\bfour\b).*$
4454
+ */
4455
+ var a = $.map( search.match( /"[^"]+"|[^ ]+/g ) || [''], function ( word ) {
4456
+ if ( word.charAt(0) === '"' ) {
4457
+ var m = word.match( /^"(.*)"$/ );
4458
+ word = m ? m[1] : word;
4459
+ }
4460
+
4461
+ return word.replace('"', '');
4462
+ } );
4463
+
4464
+ search = '^(?=.*?'+a.join( ')(?=.*?' )+').*$';
4465
+ }
4466
+
4467
+ return new RegExp( search, caseInsensitive ? 'i' : '' );
4468
+ }
4469
+
4470
+
4471
+ /**
4472
+ * Escape a string such that it can be used in a regular expression
4473
+ * @param {string} sVal string to escape
4474
+ * @returns {string} escaped string
4475
+ * @memberof DataTable#oApi
4476
+ */
4477
+ var _fnEscapeRegex = DataTable.util.escapeRegex;
4478
+
4479
+ var __filter_div = $('<div>')[0];
4480
+ var __filter_div_textContent = __filter_div.textContent !== undefined;
4481
+
4482
+ // Update the filtering data for each row if needed (by invalidation or first run)
4483
+ function _fnFilterData ( settings )
4484
+ {
4485
+ var columns = settings.aoColumns;
4486
+ var column;
4487
+ var i, j, ien, jen, filterData, cellData, row;
4488
+ var fomatters = DataTable.ext.type.search;
4489
+ var wasInvalidated = false;
4490
+
4491
+ for ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
4492
+ row = settings.aoData[i];
4493
+
4494
+ if ( ! row._aFilterData ) {
4495
+ filterData = [];
4496
+
4497
+ for ( j=0, jen=columns.length ; j<jen ; j++ ) {
4498
+ column = columns[j];
4499
+
4500
+ if ( column.bSearchable ) {
4501
+ cellData = _fnGetCellData( settings, i, j, 'filter' );
4502
+
4503
+ if ( fomatters[ column.sType ] ) {
4504
+ cellData = fomatters[ column.sType ]( cellData );
4505
+ }
4506
+
4507
+ // Search in DataTables 1.10 is string based. In 1.11 this
4508
+ // should be altered to also allow strict type checking.
4509
+ if ( cellData === null ) {
4510
+ cellData = '';
4511
+ }
4512
+
4513
+ if ( typeof cellData !== 'string' && cellData.toString ) {
4514
+ cellData = cellData.toString();
4515
+ }
4516
+ }
4517
+ else {
4518
+ cellData = '';
4519
+ }
4520
+
4521
+ // If it looks like there is an HTML entity in the string,
4522
+ // attempt to decode it so sorting works as expected. Note that
4523
+ // we could use a single line of jQuery to do this, but the DOM
4524
+ // method used here is much faster http://jsperf.com/html-decode
4525
+ if ( cellData.indexOf && cellData.indexOf('&') !== -1 ) {
4526
+ __filter_div.innerHTML = cellData;
4527
+ cellData = __filter_div_textContent ?
4528
+ __filter_div.textContent :
4529
+ __filter_div.innerText;
4530
+ }
4531
+
4532
+ if ( cellData.replace ) {
4533
+ cellData = cellData.replace(/[\r\n]/g, '');
4534
+ }
4535
+
4536
+ filterData.push( cellData );
4537
+ }
4538
+
4539
+ row._aFilterData = filterData;
4540
+ row._sFilterRow = filterData.join(' ');
4541
+ wasInvalidated = true;
4542
+ }
4543
+ }
4544
+
4545
+ return wasInvalidated;
4546
+ }
4547
+
4548
+
4549
+ /**
4550
+ * Convert from the internal Hungarian notation to camelCase for external
4551
+ * interaction
4552
+ * @param {object} obj Object to convert
4553
+ * @returns {object} Inverted object
4554
+ * @memberof DataTable#oApi
4555
+ */
4556
+ function _fnSearchToCamel ( obj )
4557
+ {
4558
+ return {
4559
+ search: obj.sSearch,
4560
+ smart: obj.bSmart,
4561
+ regex: obj.bRegex,
4562
+ caseInsensitive: obj.bCaseInsensitive
4563
+ };
4564
+ }
4565
+
4566
+
4567
+
4568
+ /**
4569
+ * Convert from camelCase notation to the internal Hungarian. We could use the
4570
+ * Hungarian convert function here, but this is cleaner
4571
+ * @param {object} obj Object to convert
4572
+ * @returns {object} Inverted object
4573
+ * @memberof DataTable#oApi
4574
+ */
4575
+ function _fnSearchToHung ( obj )
4576
+ {
4577
+ return {
4578
+ sSearch: obj.search,
4579
+ bSmart: obj.smart,
4580
+ bRegex: obj.regex,
4581
+ bCaseInsensitive: obj.caseInsensitive
4582
+ };
4583
+ }
4584
+
4585
+ /**
4586
+ * Generate the node required for the info display
4587
+ * @param {object} oSettings dataTables settings object
4588
+ * @returns {node} Information element
4589
+ * @memberof DataTable#oApi
4590
+ */
4591
+ function _fnFeatureHtmlInfo ( settings )
4592
+ {
4593
+ var
4594
+ tid = settings.sTableId,
4595
+ nodes = settings.aanFeatures.i,
4596
+ n = $('<div/>', {
4597
+ 'class': settings.oClasses.sInfo,
4598
+ 'id': ! nodes ? tid+'_info' : null
4599
+ } );
4600
+
4601
+ if ( ! nodes ) {
4602
+ // Update display on each draw
4603
+ settings.aoDrawCallback.push( {
4604
+ "fn": _fnUpdateInfo,
4605
+ "sName": "information"
4606
+ } );
4607
+
4608
+ n
4609
+ .attr( 'role', 'status' )
4610
+ .attr( 'aria-live', 'polite' );
4611
+
4612
+ // Table is described by our info div
4613
+ $(settings.nTable).attr( 'aria-describedby', tid+'_info' );
4614
+ }
4615
+
4616
+ return n[0];
4617
+ }
4618
+
4619
+
4620
+ /**
4621
+ * Update the information elements in the display
4622
+ * @param {object} settings dataTables settings object
4623
+ * @memberof DataTable#oApi
4624
+ */
4625
+ function _fnUpdateInfo ( settings )
4626
+ {
4627
+ /* Show information about the table */
4628
+ var nodes = settings.aanFeatures.i;
4629
+ if ( nodes.length === 0 ) {
4630
+ return;
4631
+ }
4632
+
4633
+ var
4634
+ lang = settings.oLanguage,
4635
+ start = settings._iDisplayStart+1,
4636
+ end = settings.fnDisplayEnd(),
4637
+ max = settings.fnRecordsTotal(),
4638
+ total = settings.fnRecordsDisplay(),
4639
+ out = total ?
4640
+ lang.sInfo :
4641
+ lang.sInfoEmpty;
4642
+
4643
+ if ( total !== max ) {
4644
+ /* Record set after filtering */
4645
+ out += ' ' + lang.sInfoFiltered;
4646
+ }
4647
+
4648
+ // Convert the macros
4649
+ out += lang.sInfoPostFix;
4650
+ out = _fnInfoMacros( settings, out );
4651
+
4652
+ var callback = lang.fnInfoCallback;
4653
+ if ( callback !== null ) {
4654
+ out = callback.call( settings.oInstance,
4655
+ settings, start, end, max, total, out
4656
+ );
4657
+ }
4658
+
4659
+ $(nodes).html( out );
4660
+ }
4661
+
4662
+
4663
+ function _fnInfoMacros ( settings, str )
4664
+ {
4665
+ // When infinite scrolling, we are always starting at 1. _iDisplayStart is used only
4666
+ // internally
4667
+ var
4668
+ formatter = settings.fnFormatNumber,
4669
+ start = settings._iDisplayStart+1,
4670
+ len = settings._iDisplayLength,
4671
+ vis = settings.fnRecordsDisplay(),
4672
+ all = len === -1;
4673
+
4674
+ return str.
4675
+ replace(/_START_/g, formatter.call( settings, start ) ).
4676
+ replace(/_END_/g, formatter.call( settings, settings.fnDisplayEnd() ) ).
4677
+ replace(/_MAX_/g, formatter.call( settings, settings.fnRecordsTotal() ) ).
4678
+ replace(/_TOTAL_/g, formatter.call( settings, vis ) ).
4679
+ replace(/_PAGE_/g, formatter.call( settings, all ? 1 : Math.ceil( start / len ) ) ).
4680
+ replace(/_PAGES_/g, formatter.call( settings, all ? 1 : Math.ceil( vis / len ) ) );
4681
+ }
4682
+
4683
+
4684
+
4685
+ /**
4686
+ * Draw the table for the first time, adding all required features
4687
+ * @param {object} settings dataTables settings object
4688
+ * @memberof DataTable#oApi
4689
+ */
4690
+ function _fnInitialise ( settings )
4691
+ {
4692
+ var i, iLen, iAjaxStart=settings.iInitDisplayStart;
4693
+ var columns = settings.aoColumns, column;
4694
+ var features = settings.oFeatures;
4695
+ var deferLoading = settings.bDeferLoading; // value modified by the draw
4696
+
4697
+ /* Ensure that the table data is fully initialised */
4698
+ if ( ! settings.bInitialised ) {
4699
+ setTimeout( function(){ _fnInitialise( settings ); }, 200 );
4700
+ return;
4701
+ }
4702
+
4703
+ /* Show the display HTML options */
4704
+ _fnAddOptionsHtml( settings );
4705
+
4706
+ /* Build and draw the header / footer for the table */
4707
+ _fnBuildHead( settings );
4708
+ _fnDrawHead( settings, settings.aoHeader );
4709
+ _fnDrawHead( settings, settings.aoFooter );
4710
+
4711
+ /* Okay to show that something is going on now */
4712
+ _fnProcessingDisplay( settings, true );
4713
+
4714
+ /* Calculate sizes for columns */
4715
+ if ( features.bAutoWidth ) {
4716
+ _fnCalculateColumnWidths( settings );
4717
+ }
4718
+
4719
+ for ( i=0, iLen=columns.length ; i<iLen ; i++ ) {
4720
+ column = columns[i];
4721
+
4722
+ if ( column.sWidth ) {
4723
+ column.nTh.style.width = _fnStringToCss( column.sWidth );
4724
+ }
4725
+ }
4726
+
4727
+ _fnCallbackFire( settings, null, 'preInit', [settings] );
4728
+
4729
+ // If there is default sorting required - let's do it. The sort function
4730
+ // will do the drawing for us. Otherwise we draw the table regardless of the
4731
+ // Ajax source - this allows the table to look initialised for Ajax sourcing
4732
+ // data (show 'loading' message possibly)
4733
+ _fnReDraw( settings );
4734
+
4735
+ // Server-side processing init complete is done by _fnAjaxUpdateDraw
4736
+ var dataSrc = _fnDataSource( settings );
4737
+ if ( dataSrc != 'ssp' || deferLoading ) {
4738
+ // if there is an ajax source load the data
4739
+ if ( dataSrc == 'ajax' ) {
4740
+ _fnBuildAjax( settings, [], function(json) {
4741
+ var aData = _fnAjaxDataSrc( settings, json );
4742
+
4743
+ // Got the data - add it to the table
4744
+ for ( i=0 ; i<aData.length ; i++ ) {
4745
+ _fnAddData( settings, aData[i] );
4746
+ }
4747
+
4748
+ // Reset the init display for cookie saving. We've already done
4749
+ // a filter, and therefore cleared it before. So we need to make
4750
+ // it appear 'fresh'
4751
+ settings.iInitDisplayStart = iAjaxStart;
4752
+
4753
+ _fnReDraw( settings );
4754
+
4755
+ _fnProcessingDisplay( settings, false );
4756
+ _fnInitComplete( settings, json );
4757
+ }, settings );
4758
+ }
4759
+ else {
4760
+ _fnProcessingDisplay( settings, false );
4761
+ _fnInitComplete( settings );
4762
+ }
4763
+ }
4764
+ }
4765
+
4766
+
4767
+ /**
4768
+ * Draw the table for the first time, adding all required features
4769
+ * @param {object} oSettings dataTables settings object
4770
+ * @param {object} [json] JSON from the server that completed the table, if using Ajax source
4771
+ * with client-side processing (optional)
4772
+ * @memberof DataTable#oApi
4773
+ */
4774
+ function _fnInitComplete ( settings, json )
4775
+ {
4776
+ settings._bInitComplete = true;
4777
+
4778
+ // When data was added after the initialisation (data or Ajax) we need to
4779
+ // calculate the column sizing
4780
+ if ( json || settings.oInit.aaData ) {
4781
+ _fnAdjustColumnSizing( settings );
4782
+ }
4783
+
4784
+ _fnCallbackFire( settings, null, 'plugin-init', [settings, json] );
4785
+ _fnCallbackFire( settings, 'aoInitComplete', 'init', [settings, json] );
4786
+ }
4787
+
4788
+
4789
+ function _fnLengthChange ( settings, val )
4790
+ {
4791
+ var len = parseInt( val, 10 );
4792
+ settings._iDisplayLength = len;
4793
+
4794
+ _fnLengthOverflow( settings );
4795
+
4796
+ // Fire length change event
4797
+ _fnCallbackFire( settings, null, 'length', [settings, len] );
4798
+ }
4799
+
4800
+
4801
+ /**
4802
+ * Generate the node required for user display length changing
4803
+ * @param {object} settings dataTables settings object
4804
+ * @returns {node} Display length feature node
4805
+ * @memberof DataTable#oApi
4806
+ */
4807
+ function _fnFeatureHtmlLength ( settings )
4808
+ {
4809
+ var
4810
+ classes = settings.oClasses,
4811
+ tableId = settings.sTableId,
4812
+ menu = settings.aLengthMenu,
4813
+ d2 = $.isArray( menu[0] ),
4814
+ lengths = d2 ? menu[0] : menu,
4815
+ language = d2 ? menu[1] : menu;
4816
+
4817
+ var select = $('<select/>', {
4818
+ 'name': tableId+'_length',
4819
+ 'aria-controls': tableId,
4820
+ 'class': classes.sLengthSelect
4821
+ } );
4822
+
4823
+ for ( var i=0, ien=lengths.length ; i<ien ; i++ ) {
4824
+ select[0][ i ] = new Option(
4825
+ typeof language[i] === 'number' ?
4826
+ settings.fnFormatNumber( language[i] ) :
4827
+ language[i],
4828
+ lengths[i]
4829
+ );
4830
+ }
4831
+
4832
+ var div = $('<div><label/></div>').addClass( classes.sLength );
4833
+ if ( ! settings.aanFeatures.l ) {
4834
+ div[0].id = tableId+'_length';
4835
+ }
4836
+
4837
+ div.children().append(
4838
+ settings.oLanguage.sLengthMenu.replace( '_MENU_', select[0].outerHTML )
4839
+ );
4840
+
4841
+ // Can't use `select` variable as user might provide their own and the
4842
+ // reference is broken by the use of outerHTML
4843
+ $('select', div)
4844
+ .val( settings._iDisplayLength )
4845
+ .on( 'change.DT', function(e) {
4846
+ _fnLengthChange( settings, $(this).val() );
4847
+ _fnDraw( settings );
4848
+ } );
4849
+
4850
+ // Update node value whenever anything changes the table's length
4851
+ $(settings.nTable).on( 'length.dt.DT', function (e, s, len) {
4852
+ if ( settings === s ) {
4853
+ $('select', div).val( len );
4854
+ }
4855
+ } );
4856
+
4857
+ return div[0];
4858
+ }
4859
+
4860
+
4861
+
4862
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
4863
+ * Note that most of the paging logic is done in
4864
+ * DataTable.ext.pager
4865
+ */
4866
+
4867
+ /**
4868
+ * Generate the node required for default pagination
4869
+ * @param {object} oSettings dataTables settings object
4870
+ * @returns {node} Pagination feature node
4871
+ * @memberof DataTable#oApi
4872
+ */
4873
+ function _fnFeatureHtmlPaginate ( settings )
4874
+ {
4875
+ var
4876
+ type = settings.sPaginationType,
4877
+ plugin = DataTable.ext.pager[ type ],
4878
+ modern = typeof plugin === 'function',
4879
+ redraw = function( settings ) {
4880
+ _fnDraw( settings );
4881
+ },
4882
+ node = $('<div/>').addClass( settings.oClasses.sPaging + type )[0],
4883
+ features = settings.aanFeatures;
4884
+
4885
+ if ( ! modern ) {
4886
+ plugin.fnInit( settings, node, redraw );
4887
+ }
4888
+
4889
+ /* Add a draw callback for the pagination on first instance, to update the paging display */
4890
+ if ( ! features.p )
4891
+ {
4892
+ node.id = settings.sTableId+'_paginate';
4893
+
4894
+ settings.aoDrawCallback.push( {
4895
+ "fn": function( settings ) {
4896
+ if ( modern ) {
4897
+ var
4898
+ start = settings._iDisplayStart,
4899
+ len = settings._iDisplayLength,
4900
+ visRecords = settings.fnRecordsDisplay(),
4901
+ all = len === -1,
4902
+ page = all ? 0 : Math.ceil( start / len ),
4903
+ pages = all ? 1 : Math.ceil( visRecords / len ),
4904
+ buttons = plugin(page, pages),
4905
+ i, ien;
4906
+
4907
+ for ( i=0, ien=features.p.length ; i<ien ; i++ ) {
4908
+ _fnRenderer( settings, 'pageButton' )(
4909
+ settings, features.p[i], i, buttons, page, pages
4910
+ );
4911
+ }
4912
+ }
4913
+ else {
4914
+ plugin.fnUpdate( settings, redraw );
4915
+ }
4916
+ },
4917
+ "sName": "pagination"
4918
+ } );
4919
+ }
4920
+
4921
+ return node;
4922
+ }
4923
+
4924
+
4925
+ /**
4926
+ * Alter the display settings to change the page
4927
+ * @param {object} settings DataTables settings object
4928
+ * @param {string|int} action Paging action to take: "first", "previous",
4929
+ * "next" or "last" or page number to jump to (integer)
4930
+ * @param [bool] redraw Automatically draw the update or not
4931
+ * @returns {bool} true page has changed, false - no change
4932
+ * @memberof DataTable#oApi
4933
+ */
4934
+ function _fnPageChange ( settings, action, redraw )
4935
+ {
4936
+ var
4937
+ start = settings._iDisplayStart,
4938
+ len = settings._iDisplayLength,
4939
+ records = settings.fnRecordsDisplay();
4940
+
4941
+ if ( records === 0 || len === -1 )
4942
+ {
4943
+ start = 0;
4944
+ }
4945
+ else if ( typeof action === "number" )
4946
+ {
4947
+ start = action * len;
4948
+
4949
+ if ( start > records )
4950
+ {
4951
+ start = 0;
4952
+ }
4953
+ }
4954
+ else if ( action == "first" )
4955
+ {
4956
+ start = 0;
4957
+ }
4958
+ else if ( action == "previous" )
4959
+ {
4960
+ start = len >= 0 ?
4961
+ start - len :
4962
+ 0;
4963
+
4964
+ if ( start < 0 )
4965
+ {
4966
+ start = 0;
4967
+ }
4968
+ }
4969
+ else if ( action == "next" )
4970
+ {
4971
+ if ( start + len < records )
4972
+ {
4973
+ start += len;
4974
+ }
4975
+ }
4976
+ else if ( action == "last" )
4977
+ {
4978
+ start = Math.floor( (records-1) / len) * len;
4979
+ }
4980
+ else
4981
+ {
4982
+ _fnLog( settings, 0, "Unknown paging action: "+action, 5 );
4983
+ }
4984
+
4985
+ var changed = settings._iDisplayStart !== start;
4986
+ settings._iDisplayStart = start;
4987
+
4988
+ if ( changed ) {
4989
+ _fnCallbackFire( settings, null, 'page', [settings] );
4990
+
4991
+ if ( redraw ) {
4992
+ _fnDraw( settings );
4993
+ }
4994
+ }
4995
+
4996
+ return changed;
4997
+ }
4998
+
4999
+
5000
+
5001
+ /**
5002
+ * Generate the node required for the processing node
5003
+ * @param {object} settings dataTables settings object
5004
+ * @returns {node} Processing element
5005
+ * @memberof DataTable#oApi
5006
+ */
5007
+ function _fnFeatureHtmlProcessing ( settings )
5008
+ {
5009
+ return $('<div/>', {
5010
+ 'id': ! settings.aanFeatures.r ? settings.sTableId+'_processing' : null,
5011
+ 'class': settings.oClasses.sProcessing
5012
+ } )
5013
+ .html( settings.oLanguage.sProcessing )
5014
+ .insertBefore( settings.nTable )[0];
5015
+ }
5016
+
5017
+
5018
+ /**
5019
+ * Display or hide the processing indicator
5020
+ * @param {object} settings dataTables settings object
5021
+ * @param {bool} show Show the processing indicator (true) or not (false)
5022
+ * @memberof DataTable#oApi
5023
+ */
5024
+ function _fnProcessingDisplay ( settings, show )
5025
+ {
5026
+ if ( settings.oFeatures.bProcessing ) {
5027
+ $(settings.aanFeatures.r).css( 'display', show ? 'block' : 'none' );
5028
+ }
5029
+
5030
+ _fnCallbackFire( settings, null, 'processing', [settings, show] );
5031
+ }
5032
+
5033
+ /**
5034
+ * Add any control elements for the table - specifically scrolling
5035
+ * @param {object} settings dataTables settings object
5036
+ * @returns {node} Node to add to the DOM
5037
+ * @memberof DataTable#oApi
5038
+ */
5039
+ function _fnFeatureHtmlTable ( settings )
5040
+ {
5041
+ var table = $(settings.nTable);
5042
+
5043
+ // Add the ARIA grid role to the table
5044
+ table.attr( 'role', 'grid' );
5045
+
5046
+ // Scrolling from here on in
5047
+ var scroll = settings.oScroll;
5048
+
5049
+ if ( scroll.sX === '' && scroll.sY === '' ) {
5050
+ return settings.nTable;
5051
+ }
5052
+
5053
+ var scrollX = scroll.sX;
5054
+ var scrollY = scroll.sY;
5055
+ var classes = settings.oClasses;
5056
+ var caption = table.children('caption');
5057
+ var captionSide = caption.length ? caption[0]._captionSide : null;
5058
+ var headerClone = $( table[0].cloneNode(false) );
5059
+ var footerClone = $( table[0].cloneNode(false) );
5060
+ var footer = table.children('tfoot');
5061
+ var _div = '<div/>';
5062
+ var size = function ( s ) {
5063
+ return !s ? null : _fnStringToCss( s );
5064
+ };
5065
+
5066
+ if ( ! footer.length ) {
5067
+ footer = null;
5068
+ }
5069
+
5070
+ /*
5071
+ * The HTML structure that we want to generate in this function is:
5072
+ * div - scroller
5073
+ * div - scroll head
5074
+ * div - scroll head inner
5075
+ * table - scroll head table
5076
+ * thead - thead
5077
+ * div - scroll body
5078
+ * table - table (master table)
5079
+ * thead - thead clone for sizing
5080
+ * tbody - tbody
5081
+ * div - scroll foot
5082
+ * div - scroll foot inner
5083
+ * table - scroll foot table
5084
+ * tfoot - tfoot
5085
+ */
5086
+ var scroller = $( _div, { 'class': classes.sScrollWrapper } )
5087
+ .append(
5088
+ $(_div, { 'class': classes.sScrollHead } )
5089
+ .css( {
5090
+ overflow: 'hidden',
5091
+ position: 'relative',
5092
+ border: 0,
5093
+ width: scrollX ? size(scrollX) : '100%'
5094
+ } )
5095
+ .append(
5096
+ $(_div, { 'class': classes.sScrollHeadInner } )
5097
+ .css( {
5098
+ 'box-sizing': 'content-box',
5099
+ width: scroll.sXInner || '100%'
5100
+ } )
5101
+ .append(
5102
+ headerClone
5103
+ .removeAttr('id')
5104
+ .css( 'margin-left', 0 )
5105
+ .append( captionSide === 'top' ? caption : null )
5106
+ .append(
5107
+ table.children('thead')
5108
+ )
5109
+ )
5110
+ )
5111
+ )
5112
+ .append(
5113
+ $(_div, { 'class': classes.sScrollBody } )
5114
+ .css( {
5115
+ position: 'relative',
5116
+ overflow: 'auto',
5117
+ width: size( scrollX )
5118
+ } )
5119
+ .append( table )
5120
+ );
5121
+
5122
+ if ( footer ) {
5123
+ scroller.append(
5124
+ $(_div, { 'class': classes.sScrollFoot } )
5125
+ .css( {
5126
+ overflow: 'hidden',
5127
+ border: 0,
5128
+ width: scrollX ? size(scrollX) : '100%'
5129
+ } )
5130
+ .append(
5131
+ $(_div, { 'class': classes.sScrollFootInner } )
5132
+ .append(
5133
+ footerClone
5134
+ .removeAttr('id')
5135
+ .css( 'margin-left', 0 )
5136
+ .append( captionSide === 'bottom' ? caption : null )
5137
+ .append(
5138
+ table.children('tfoot')
5139
+ )
5140
+ )
5141
+ )
5142
+ );
5143
+ }
5144
+
5145
+ var children = scroller.children();
5146
+ var scrollHead = children[0];
5147
+ var scrollBody = children[1];
5148
+ var scrollFoot = footer ? children[2] : null;
5149
+
5150
+ // When the body is scrolled, then we also want to scroll the headers
5151
+ if ( scrollX ) {
5152
+ $(scrollBody).on( 'scroll.DT', function (e) {
5153
+ var scrollLeft = this.scrollLeft;
5154
+
5155
+ scrollHead.scrollLeft = scrollLeft;
5156
+
5157
+ if ( footer ) {
5158
+ scrollFoot.scrollLeft = scrollLeft;
5159
+ }
5160
+ } );
5161
+ }
5162
+
5163
+ $(scrollBody).css(
5164
+ scrollY && scroll.bCollapse ? 'max-height' : 'height',
5165
+ scrollY
5166
+ );
5167
+
5168
+ settings.nScrollHead = scrollHead;
5169
+ settings.nScrollBody = scrollBody;
5170
+ settings.nScrollFoot = scrollFoot;
5171
+
5172
+ // On redraw - align columns
5173
+ settings.aoDrawCallback.push( {
5174
+ "fn": _fnScrollDraw,
5175
+ "sName": "scrolling"
5176
+ } );
5177
+
5178
+ return scroller[0];
5179
+ }
5180
+
5181
+
5182
+
5183
+ /**
5184
+ * Update the header, footer and body tables for resizing - i.e. column
5185
+ * alignment.
5186
+ *
5187
+ * Welcome to the most horrible function DataTables. The process that this
5188
+ * function follows is basically:
5189
+ * 1. Re-create the table inside the scrolling div
5190
+ * 2. Take live measurements from the DOM
5191
+ * 3. Apply the measurements to align the columns
5192
+ * 4. Clean up
5193
+ *
5194
+ * @param {object} settings dataTables settings object
5195
+ * @memberof DataTable#oApi
5196
+ */
5197
+ function _fnScrollDraw ( settings )
5198
+ {
5199
+ // Given that this is such a monster function, a lot of variables are use
5200
+ // to try and keep the minimised size as small as possible
5201
+ var
5202
+ scroll = settings.oScroll,
5203
+ scrollX = scroll.sX,
5204
+ scrollXInner = scroll.sXInner,
5205
+ scrollY = scroll.sY,
5206
+ barWidth = scroll.iBarWidth,
5207
+ divHeader = $(settings.nScrollHead),
5208
+ divHeaderStyle = divHeader[0].style,
5209
+ divHeaderInner = divHeader.children('div'),
5210
+ divHeaderInnerStyle = divHeaderInner[0].style,
5211
+ divHeaderTable = divHeaderInner.children('table'),
5212
+ divBodyEl = settings.nScrollBody,
5213
+ divBody = $(divBodyEl),
5214
+ divBodyStyle = divBodyEl.style,
5215
+ divFooter = $(settings.nScrollFoot),
5216
+ divFooterInner = divFooter.children('div'),
5217
+ divFooterTable = divFooterInner.children('table'),
5218
+ header = $(settings.nTHead),
5219
+ table = $(settings.nTable),
5220
+ tableEl = table[0],
5221
+ tableStyle = tableEl.style,
5222
+ footer = settings.nTFoot ? $(settings.nTFoot) : null,
5223
+ browser = settings.oBrowser,
5224
+ ie67 = browser.bScrollOversize,
5225
+ dtHeaderCells = _pluck( settings.aoColumns, 'nTh' ),
5226
+ headerTrgEls, footerTrgEls,
5227
+ headerSrcEls, footerSrcEls,
5228
+ headerCopy, footerCopy,
5229
+ headerWidths=[], footerWidths=[],
5230
+ headerContent=[], footerContent=[],
5231
+ idx, correction, sanityWidth,
5232
+ zeroOut = function(nSizer) {
5233
+ var style = nSizer.style;
5234
+ style.paddingTop = "0";
5235
+ style.paddingBottom = "0";
5236
+ style.borderTopWidth = "0";
5237
+ style.borderBottomWidth = "0";
5238
+ style.height = 0;
5239
+ };
5240
+
5241
+ // If the scrollbar visibility has changed from the last draw, we need to
5242
+ // adjust the column sizes as the table width will have changed to account
5243
+ // for the scrollbar
5244
+ var scrollBarVis = divBodyEl.scrollHeight > divBodyEl.clientHeight;
5245
+
5246
+ if ( settings.scrollBarVis !== scrollBarVis && settings.scrollBarVis !== undefined ) {
5247
+ settings.scrollBarVis = scrollBarVis;
5248
+ _fnAdjustColumnSizing( settings );
5249
+ return; // adjust column sizing will call this function again
5250
+ }
5251
+ else {
5252
+ settings.scrollBarVis = scrollBarVis;
5253
+ }
5254
+
5255
+ /*
5256
+ * 1. Re-create the table inside the scrolling div
5257
+ */
5258
+
5259
+ // Remove the old minimised thead and tfoot elements in the inner table
5260
+ table.children('thead, tfoot').remove();
5261
+
5262
+ if ( footer ) {
5263
+ footerCopy = footer.clone().prependTo( table );
5264
+ footerTrgEls = footer.find('tr'); // the original tfoot is in its own table and must be sized
5265
+ footerSrcEls = footerCopy.find('tr');
5266
+ }
5267
+
5268
+ // Clone the current header and footer elements and then place it into the inner table
5269
+ headerCopy = header.clone().prependTo( table );
5270
+ headerTrgEls = header.find('tr'); // original header is in its own table
5271
+ headerSrcEls = headerCopy.find('tr');
5272
+ headerCopy.find('th, td').removeAttr('tabindex');
5273
+
5274
+
5275
+ /*
5276
+ * 2. Take live measurements from the DOM - do not alter the DOM itself!
5277
+ */
5278
+
5279
+ // Remove old sizing and apply the calculated column widths
5280
+ // Get the unique column headers in the newly created (cloned) header. We want to apply the
5281
+ // calculated sizes to this header
5282
+ if ( ! scrollX )
5283
+ {
5284
+ divBodyStyle.width = '100%';
5285
+ divHeader[0].style.width = '100%';
5286
+ }
5287
+
5288
+ $.each( _fnGetUniqueThs( settings, headerCopy ), function ( i, el ) {
5289
+ idx = _fnVisibleToColumnIndex( settings, i );
5290
+ el.style.width = settings.aoColumns[idx].sWidth;
5291
+ } );
5292
+
5293
+ if ( footer ) {
5294
+ _fnApplyToChildren( function(n) {
5295
+ n.style.width = "";
5296
+ }, footerSrcEls );
5297
+ }
5298
+
5299
+ // Size the table as a whole
5300
+ sanityWidth = table.outerWidth();
5301
+ if ( scrollX === "" ) {
5302
+ // No x scrolling
5303
+ tableStyle.width = "100%";
5304
+
5305
+ // IE7 will make the width of the table when 100% include the scrollbar
5306
+ // - which is shouldn't. When there is a scrollbar we need to take this
5307
+ // into account.
5308
+ if ( ie67 && (table.find('tbody').height() > divBodyEl.offsetHeight ||
5309
+ divBody.css('overflow-y') == "scroll")
5310
+ ) {
5311
+ tableStyle.width = _fnStringToCss( table.outerWidth() - barWidth);
5312
+ }
5313
+
5314
+ // Recalculate the sanity width
5315
+ sanityWidth = table.outerWidth();
5316
+ }
5317
+ else if ( scrollXInner !== "" ) {
5318
+ // legacy x scroll inner has been given - use it
5319
+ tableStyle.width = _fnStringToCss(scrollXInner);
5320
+
5321
+ // Recalculate the sanity width
5322
+ sanityWidth = table.outerWidth();
5323
+ }
5324
+
5325
+ // Hidden header should have zero height, so remove padding and borders. Then
5326
+ // set the width based on the real headers
5327
+
5328
+ // Apply all styles in one pass
5329
+ _fnApplyToChildren( zeroOut, headerSrcEls );
5330
+
5331
+ // Read all widths in next pass
5332
+ _fnApplyToChildren( function(nSizer) {
5333
+ headerContent.push( nSizer.innerHTML );
5334
+ headerWidths.push( _fnStringToCss( $(nSizer).css('width') ) );
5335
+ }, headerSrcEls );
5336
+
5337
+ // Apply all widths in final pass
5338
+ _fnApplyToChildren( function(nToSize, i) {
5339
+ // Only apply widths to the DataTables detected header cells - this
5340
+ // prevents complex headers from having contradictory sizes applied
5341
+ if ( $.inArray( nToSize, dtHeaderCells ) !== -1 ) {
5342
+ nToSize.style.width = headerWidths[i];
5343
+ }
5344
+ }, headerTrgEls );
5345
+
5346
+ $(headerSrcEls).height(0);
5347
+
5348
+ /* Same again with the footer if we have one */
5349
+ if ( footer )
5350
+ {
5351
+ _fnApplyToChildren( zeroOut, footerSrcEls );
5352
+
5353
+ _fnApplyToChildren( function(nSizer) {
5354
+ footerContent.push( nSizer.innerHTML );
5355
+ footerWidths.push( _fnStringToCss( $(nSizer).css('width') ) );
5356
+ }, footerSrcEls );
5357
+
5358
+ _fnApplyToChildren( function(nToSize, i) {
5359
+ nToSize.style.width = footerWidths[i];
5360
+ }, footerTrgEls );
5361
+
5362
+ $(footerSrcEls).height(0);
5363
+ }
5364
+
5365
+
5366
+ /*
5367
+ * 3. Apply the measurements
5368
+ */
5369
+
5370
+ // "Hide" the header and footer that we used for the sizing. We need to keep
5371
+ // the content of the cell so that the width applied to the header and body
5372
+ // both match, but we want to hide it completely. We want to also fix their
5373
+ // width to what they currently are
5374
+ _fnApplyToChildren( function(nSizer, i) {
5375
+ nSizer.innerHTML = '<div class="dataTables_sizing" style="height:0;overflow:hidden;">'+headerContent[i]+'</div>';
5376
+ nSizer.style.width = headerWidths[i];
5377
+ }, headerSrcEls );
5378
+
5379
+ if ( footer )
5380
+ {
5381
+ _fnApplyToChildren( function(nSizer, i) {
5382
+ nSizer.innerHTML = '<div class="dataTables_sizing" style="height:0;overflow:hidden;">'+footerContent[i]+'</div>';
5383
+ nSizer.style.width = footerWidths[i];
5384
+ }, footerSrcEls );
5385
+ }
5386
+
5387
+ // Sanity check that the table is of a sensible width. If not then we are going to get
5388
+ // misalignment - try to prevent this by not allowing the table to shrink below its min width
5389
+ if ( table.outerWidth() < sanityWidth )
5390
+ {
5391
+ // The min width depends upon if we have a vertical scrollbar visible or not */
5392
+ correction = ((divBodyEl.scrollHeight > divBodyEl.offsetHeight ||
5393
+ divBody.css('overflow-y') == "scroll")) ?
5394
+ sanityWidth+barWidth :
5395
+ sanityWidth;
5396
+
5397
+ // IE6/7 are a law unto themselves...
5398
+ if ( ie67 && (divBodyEl.scrollHeight >
5399
+ divBodyEl.offsetHeight || divBody.css('overflow-y') == "scroll")
5400
+ ) {
5401
+ tableStyle.width = _fnStringToCss( correction-barWidth );
5402
+ }
5403
+
5404
+ // And give the user a warning that we've stopped the table getting too small
5405
+ if ( scrollX === "" || scrollXInner !== "" ) {
5406
+ _fnLog( settings, 1, 'Possible column misalignment', 6 );
5407
+ }
5408
+ }
5409
+ else
5410
+ {
5411
+ correction = '100%';
5412
+ }
5413
+
5414
+ // Apply to the container elements
5415
+ divBodyStyle.width = _fnStringToCss( correction );
5416
+ divHeaderStyle.width = _fnStringToCss( correction );
5417
+
5418
+ if ( footer ) {
5419
+ settings.nScrollFoot.style.width = _fnStringToCss( correction );
5420
+ }
5421
+
5422
+
5423
+ /*
5424
+ * 4. Clean up
5425
+ */
5426
+ if ( ! scrollY ) {
5427
+ /* IE7< puts a vertical scrollbar in place (when it shouldn't be) due to subtracting
5428
+ * the scrollbar height from the visible display, rather than adding it on. We need to
5429
+ * set the height in order to sort this. Don't want to do it in any other browsers.
5430
+ */
5431
+ if ( ie67 ) {
5432
+ divBodyStyle.height = _fnStringToCss( tableEl.offsetHeight+barWidth );
5433
+ }
5434
+ }
5435
+
5436
+ /* Finally set the width's of the header and footer tables */
5437
+ var iOuterWidth = table.outerWidth();
5438
+ divHeaderTable[0].style.width = _fnStringToCss( iOuterWidth );
5439
+ divHeaderInnerStyle.width = _fnStringToCss( iOuterWidth );
5440
+
5441
+ // Figure out if there are scrollbar present - if so then we need a the header and footer to
5442
+ // provide a bit more space to allow "overflow" scrolling (i.e. past the scrollbar)
5443
+ var bScrolling = table.height() > divBodyEl.clientHeight || divBody.css('overflow-y') == "scroll";
5444
+ var padding = 'padding' + (browser.bScrollbarLeft ? 'Left' : 'Right' );
5445
+ divHeaderInnerStyle[ padding ] = bScrolling ? barWidth+"px" : "0px";
5446
+
5447
+ if ( footer ) {
5448
+ divFooterTable[0].style.width = _fnStringToCss( iOuterWidth );
5449
+ divFooterInner[0].style.width = _fnStringToCss( iOuterWidth );
5450
+ divFooterInner[0].style[padding] = bScrolling ? barWidth+"px" : "0px";
5451
+ }
5452
+
5453
+ // Correct DOM ordering for colgroup - comes before the thead
5454
+ table.children('colgroup').insertBefore( table.children('thead') );
5455
+
5456
+ /* Adjust the position of the header in case we loose the y-scrollbar */
5457
+ divBody.scroll();
5458
+
5459
+ // If sorting or filtering has occurred, jump the scrolling back to the top
5460
+ // only if we aren't holding the position
5461
+ if ( (settings.bSorted || settings.bFiltered) && ! settings._drawHold ) {
5462
+ divBodyEl.scrollTop = 0;
5463
+ }
5464
+ }
5465
+
5466
+
5467
+
5468
+ /**
5469
+ * Apply a given function to the display child nodes of an element array (typically
5470
+ * TD children of TR rows
5471
+ * @param {function} fn Method to apply to the objects
5472
+ * @param array {nodes} an1 List of elements to look through for display children
5473
+ * @param array {nodes} an2 Another list (identical structure to the first) - optional
5474
+ * @memberof DataTable#oApi
5475
+ */
5476
+ function _fnApplyToChildren( fn, an1, an2 )
5477
+ {
5478
+ var index=0, i=0, iLen=an1.length;
5479
+ var nNode1, nNode2;
5480
+
5481
+ while ( i < iLen ) {
5482
+ nNode1 = an1[i].firstChild;
5483
+ nNode2 = an2 ? an2[i].firstChild : null;
5484
+
5485
+ while ( nNode1 ) {
5486
+ if ( nNode1.nodeType === 1 ) {
5487
+ if ( an2 ) {
5488
+ fn( nNode1, nNode2, index );
5489
+ }
5490
+ else {
5491
+ fn( nNode1, index );
5492
+ }
5493
+
5494
+ index++;
5495
+ }
5496
+
5497
+ nNode1 = nNode1.nextSibling;
5498
+ nNode2 = an2 ? nNode2.nextSibling : null;
5499
+ }
5500
+
5501
+ i++;
5502
+ }
5503
+ }
5504
+
5505
+
5506
+
5507
+ var __re_html_remove = /<.*?>/g;
5508
+
5509
+
5510
+ /**
5511
+ * Calculate the width of columns for the table
5512
+ * @param {object} oSettings dataTables settings object
5513
+ * @memberof DataTable#oApi
5514
+ */
5515
+ function _fnCalculateColumnWidths ( oSettings )
5516
+ {
5517
+ var
5518
+ table = oSettings.nTable,
5519
+ columns = oSettings.aoColumns,
5520
+ scroll = oSettings.oScroll,
5521
+ scrollY = scroll.sY,
5522
+ scrollX = scroll.sX,
5523
+ scrollXInner = scroll.sXInner,
5524
+ columnCount = columns.length,
5525
+ visibleColumns = _fnGetColumns( oSettings, 'bVisible' ),
5526
+ headerCells = $('th', oSettings.nTHead),
5527
+ tableWidthAttr = table.getAttribute('width'), // from DOM element
5528
+ tableContainer = table.parentNode,
5529
+ userInputs = false,
5530
+ i, column, columnIdx, width, outerWidth,
5531
+ browser = oSettings.oBrowser,
5532
+ ie67 = browser.bScrollOversize;
5533
+
5534
+ var styleWidth = table.style.width;
5535
+ if ( styleWidth && styleWidth.indexOf('%') !== -1 ) {
5536
+ tableWidthAttr = styleWidth;
5537
+ }
5538
+
5539
+ /* Convert any user input sizes into pixel sizes */
5540
+ for ( i=0 ; i<visibleColumns.length ; i++ ) {
5541
+ column = columns[ visibleColumns[i] ];
5542
+
5543
+ if ( column.sWidth !== null ) {
5544
+ column.sWidth = _fnConvertToWidth( column.sWidthOrig, tableContainer );
5545
+
5546
+ userInputs = true;
5547
+ }
5548
+ }
5549
+
5550
+ /* If the number of columns in the DOM equals the number that we have to
5551
+ * process in DataTables, then we can use the offsets that are created by
5552
+ * the web- browser. No custom sizes can be set in order for this to happen,
5553
+ * nor scrolling used
5554
+ */
5555
+ if ( ie67 || ! userInputs && ! scrollX && ! scrollY &&
5556
+ columnCount == _fnVisbleColumns( oSettings ) &&
5557
+ columnCount == headerCells.length
5558
+ ) {
5559
+ for ( i=0 ; i<columnCount ; i++ ) {
5560
+ var colIdx = _fnVisibleToColumnIndex( oSettings, i );
5561
+
5562
+ if ( colIdx !== null ) {
5563
+ columns[ colIdx ].sWidth = _fnStringToCss( headerCells.eq(i).width() );
5564
+ }
5565
+ }
5566
+ }
5567
+ else
5568
+ {
5569
+ // Otherwise construct a single row, worst case, table with the widest
5570
+ // node in the data, assign any user defined widths, then insert it into
5571
+ // the DOM and allow the browser to do all the hard work of calculating
5572
+ // table widths
5573
+ var tmpTable = $(table).clone() // don't use cloneNode - IE8 will remove events on the main table
5574
+ .css( 'visibility', 'hidden' )
5575
+ .removeAttr( 'id' );
5576
+
5577
+ // Clean up the table body
5578
+ tmpTable.find('tbody tr').remove();
5579
+ var tr = $('<tr/>').appendTo( tmpTable.find('tbody') );
5580
+
5581
+ // Clone the table header and footer - we can't use the header / footer
5582
+ // from the cloned table, since if scrolling is active, the table's
5583
+ // real header and footer are contained in different table tags
5584
+ tmpTable.find('thead, tfoot').remove();
5585
+ tmpTable
5586
+ .append( $(oSettings.nTHead).clone() )
5587
+ .append( $(oSettings.nTFoot).clone() );
5588
+
5589
+ // Remove any assigned widths from the footer (from scrolling)
5590
+ tmpTable.find('tfoot th, tfoot td').css('width', '');
5591
+
5592
+ // Apply custom sizing to the cloned header
5593
+ headerCells = _fnGetUniqueThs( oSettings, tmpTable.find('thead')[0] );
5594
+
5595
+ for ( i=0 ; i<visibleColumns.length ; i++ ) {
5596
+ column = columns[ visibleColumns[i] ];
5597
+
5598
+ headerCells[i].style.width = column.sWidthOrig !== null && column.sWidthOrig !== '' ?
5599
+ _fnStringToCss( column.sWidthOrig ) :
5600
+ '';
5601
+
5602
+ // For scrollX we need to force the column width otherwise the
5603
+ // browser will collapse it. If this width is smaller than the
5604
+ // width the column requires, then it will have no effect
5605
+ if ( column.sWidthOrig && scrollX ) {
5606
+ $( headerCells[i] ).append( $('<div/>').css( {
5607
+ width: column.sWidthOrig,
5608
+ margin: 0,
5609
+ padding: 0,
5610
+ border: 0,
5611
+ height: 1
5612
+ } ) );
5613
+ }
5614
+ }
5615
+
5616
+ // Find the widest cell for each column and put it into the table
5617
+ if ( oSettings.aoData.length ) {
5618
+ for ( i=0 ; i<visibleColumns.length ; i++ ) {
5619
+ columnIdx = visibleColumns[i];
5620
+ column = columns[ columnIdx ];
5621
+
5622
+ $( _fnGetWidestNode( oSettings, columnIdx ) )
5623
+ .clone( false )
5624
+ .append( column.sContentPadding )
5625
+ .appendTo( tr );
5626
+ }
5627
+ }
5628
+
5629
+ // Tidy the temporary table - remove name attributes so there aren't
5630
+ // duplicated in the dom (radio elements for example)
5631
+ $('[name]', tmpTable).removeAttr('name');
5632
+
5633
+ // Table has been built, attach to the document so we can work with it.
5634
+ // A holding element is used, positioned at the top of the container
5635
+ // with minimal height, so it has no effect on if the container scrolls
5636
+ // or not. Otherwise it might trigger scrolling when it actually isn't
5637
+ // needed
5638
+ var holder = $('<div/>').css( scrollX || scrollY ?
5639
+ {
5640
+ position: 'absolute',
5641
+ top: 0,
5642
+ left: 0,
5643
+ height: 1,
5644
+ right: 0,
5645
+ overflow: 'hidden'
5646
+ } :
5647
+ {}
5648
+ )
5649
+ .append( tmpTable )
5650
+ .appendTo( tableContainer );
5651
+
5652
+ // When scrolling (X or Y) we want to set the width of the table as
5653
+ // appropriate. However, when not scrolling leave the table width as it
5654
+ // is. This results in slightly different, but I think correct behaviour
5655
+ if ( scrollX && scrollXInner ) {
5656
+ tmpTable.width( scrollXInner );
5657
+ }
5658
+ else if ( scrollX ) {
5659
+ tmpTable.css( 'width', 'auto' );
5660
+ tmpTable.removeAttr('width');
5661
+
5662
+ // If there is no width attribute or style, then allow the table to
5663
+ // collapse
5664
+ if ( tmpTable.width() < tableContainer.clientWidth && tableWidthAttr ) {
5665
+ tmpTable.width( tableContainer.clientWidth );
5666
+ }
5667
+ }
5668
+ else if ( scrollY ) {
5669
+ tmpTable.width( tableContainer.clientWidth );
5670
+ }
5671
+ else if ( tableWidthAttr ) {
5672
+ tmpTable.width( tableWidthAttr );
5673
+ }
5674
+
5675
+ // Get the width of each column in the constructed table - we need to
5676
+ // know the inner width (so it can be assigned to the other table's
5677
+ // cells) and the outer width so we can calculate the full width of the
5678
+ // table. This is safe since DataTables requires a unique cell for each
5679
+ // column, but if ever a header can span multiple columns, this will
5680
+ // need to be modified.
5681
+ var total = 0;
5682
+ for ( i=0 ; i<visibleColumns.length ; i++ ) {
5683
+ var cell = $(headerCells[i]);
5684
+ var border = cell.outerWidth() - cell.width();
5685
+
5686
+ // Use getBounding... where possible (not IE8-) because it can give
5687
+ // sub-pixel accuracy, which we then want to round up!
5688
+ var bounding = browser.bBounding ?
5689
+ Math.ceil( headerCells[i].getBoundingClientRect().width ) :
5690
+ cell.outerWidth();
5691
+
5692
+ // Total is tracked to remove any sub-pixel errors as the outerWidth
5693
+ // of the table might not equal the total given here (IE!).
5694
+ total += bounding;
5695
+
5696
+ // Width for each column to use
5697
+ columns[ visibleColumns[i] ].sWidth = _fnStringToCss( bounding - border );
5698
+ }
5699
+
5700
+ table.style.width = _fnStringToCss( total );
5701
+
5702
+ // Finished with the table - ditch it
5703
+ holder.remove();
5704
+ }
5705
+
5706
+ // If there is a width attr, we want to attach an event listener which
5707
+ // allows the table sizing to automatically adjust when the window is
5708
+ // resized. Use the width attr rather than CSS, since we can't know if the
5709
+ // CSS is a relative value or absolute - DOM read is always px.
5710
+ if ( tableWidthAttr ) {
5711
+ table.style.width = _fnStringToCss( tableWidthAttr );
5712
+ }
5713
+
5714
+ if ( (tableWidthAttr || scrollX) && ! oSettings._reszEvt ) {
5715
+ var bindResize = function () {
5716
+ $(window).on('resize.DT-'+oSettings.sInstance, _fnThrottle( function () {
5717
+ _fnAdjustColumnSizing( oSettings );
5718
+ } ) );
5719
+ };
5720
+
5721
+ // IE6/7 will crash if we bind a resize event handler on page load.
5722
+ // To be removed in 1.11 which drops IE6/7 support
5723
+ if ( ie67 ) {
5724
+ setTimeout( bindResize, 1000 );
5725
+ }
5726
+ else {
5727
+ bindResize();
5728
+ }
5729
+
5730
+ oSettings._reszEvt = true;
5731
+ }
5732
+ }
5733
+
5734
+
5735
+ /**
5736
+ * Throttle the calls to a function. Arguments and context are maintained for
5737
+ * the throttled function
5738
+ * @param {function} fn Function to be called
5739
+ * @param {int} [freq=200] call frequency in mS
5740
+ * @returns {function} wrapped function
5741
+ * @memberof DataTable#oApi
5742
+ */
5743
+ var _fnThrottle = DataTable.util.throttle;
5744
+
5745
+
5746
+ /**
5747
+ * Convert a CSS unit width to pixels (e.g. 2em)
5748
+ * @param {string} width width to be converted
5749
+ * @param {node} parent parent to get the with for (required for relative widths) - optional
5750
+ * @returns {int} width in pixels
5751
+ * @memberof DataTable#oApi
5752
+ */
5753
+ function _fnConvertToWidth ( width, parent )
5754
+ {
5755
+ if ( ! width ) {
5756
+ return 0;
5757
+ }
5758
+
5759
+ var n = $('<div/>')
5760
+ .css( 'width', _fnStringToCss( width ) )
5761
+ .appendTo( parent || document.body );
5762
+
5763
+ var val = n[0].offsetWidth;
5764
+ n.remove();
5765
+
5766
+ return val;
5767
+ }
5768
+
5769
+
5770
+ /**
5771
+ * Get the widest node
5772
+ * @param {object} settings dataTables settings object
5773
+ * @param {int} colIdx column of interest
5774
+ * @returns {node} widest table node
5775
+ * @memberof DataTable#oApi
5776
+ */
5777
+ function _fnGetWidestNode( settings, colIdx )
5778
+ {
5779
+ var idx = _fnGetMaxLenString( settings, colIdx );
5780
+ if ( idx < 0 ) {
5781
+ return null;
5782
+ }
5783
+
5784
+ var data = settings.aoData[ idx ];
5785
+ return ! data.nTr ? // Might not have been created when deferred rendering
5786
+ $('<td/>').html( _fnGetCellData( settings, idx, colIdx, 'display' ) )[0] :
5787
+ data.anCells[ colIdx ];
5788
+ }
5789
+
5790
+
5791
+ /**
5792
+ * Get the maximum strlen for each data column
5793
+ * @param {object} settings dataTables settings object
5794
+ * @param {int} colIdx column of interest
5795
+ * @returns {string} max string length for each column
5796
+ * @memberof DataTable#oApi
5797
+ */
5798
+ function _fnGetMaxLenString( settings, colIdx )
5799
+ {
5800
+ var s, max=-1, maxIdx = -1;
5801
+
5802
+ for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
5803
+ s = _fnGetCellData( settings, i, colIdx, 'display' )+'';
5804
+ s = s.replace( __re_html_remove, '' );
5805
+ s = s.replace( /&nbsp;/g, ' ' );
5806
+
5807
+ if ( s.length > max ) {
5808
+ max = s.length;
5809
+ maxIdx = i;
5810
+ }
5811
+ }
5812
+
5813
+ return maxIdx;
5814
+ }
5815
+
5816
+
5817
+ /**
5818
+ * Append a CSS unit (only if required) to a string
5819
+ * @param {string} value to css-ify
5820
+ * @returns {string} value with css unit
5821
+ * @memberof DataTable#oApi
5822
+ */
5823
+ function _fnStringToCss( s )
5824
+ {
5825
+ if ( s === null ) {
5826
+ return '0px';
5827
+ }
5828
+
5829
+ if ( typeof s == 'number' ) {
5830
+ return s < 0 ?
5831
+ '0px' :
5832
+ s+'px';
5833
+ }
5834
+
5835
+ // Check it has a unit character already
5836
+ return s.match(/\d$/) ?
5837
+ s+'px' :
5838
+ s;
5839
+ }
5840
+
5841
+
5842
+
5843
+ function _fnSortFlatten ( settings )
5844
+ {
5845
+ var
5846
+ i, iLen, k, kLen,
5847
+ aSort = [],
5848
+ aiOrig = [],
5849
+ aoColumns = settings.aoColumns,
5850
+ aDataSort, iCol, sType, srcCol,
5851
+ fixed = settings.aaSortingFixed,
5852
+ fixedObj = $.isPlainObject( fixed ),
5853
+ nestedSort = [],
5854
+ add = function ( a ) {
5855
+ if ( a.length && ! $.isArray( a[0] ) ) {
5856
+ // 1D array
5857
+ nestedSort.push( a );
5858
+ }
5859
+ else {
5860
+ // 2D array
5861
+ $.merge( nestedSort, a );
5862
+ }
5863
+ };
5864
+
5865
+ // Build the sort array, with pre-fix and post-fix options if they have been
5866
+ // specified
5867
+ if ( $.isArray( fixed ) ) {
5868
+ add( fixed );
5869
+ }
5870
+
5871
+ if ( fixedObj && fixed.pre ) {
5872
+ add( fixed.pre );
5873
+ }
5874
+
5875
+ add( settings.aaSorting );
5876
+
5877
+ if (fixedObj && fixed.post ) {
5878
+ add( fixed.post );
5879
+ }
5880
+
5881
+ for ( i=0 ; i<nestedSort.length ; i++ )
5882
+ {
5883
+ srcCol = nestedSort[i][0];
5884
+ aDataSort = aoColumns[ srcCol ].aDataSort;
5885
+
5886
+ for ( k=0, kLen=aDataSort.length ; k<kLen ; k++ )
5887
+ {
5888
+ iCol = aDataSort[k];
5889
+ sType = aoColumns[ iCol ].sType || 'string';
5890
+
5891
+ if ( nestedSort[i]._idx === undefined ) {
5892
+ nestedSort[i]._idx = $.inArray( nestedSort[i][1], aoColumns[iCol].asSorting );
5893
+ }
5894
+
5895
+ aSort.push( {
5896
+ src: srcCol,
5897
+ col: iCol,
5898
+ dir: nestedSort[i][1],
5899
+ index: nestedSort[i]._idx,
5900
+ type: sType,
5901
+ formatter: DataTable.ext.type.order[ sType+"-pre" ]
5902
+ } );
5903
+ }
5904
+ }
5905
+
5906
+ return aSort;
5907
+ }
5908
+
5909
+ /**
5910
+ * Change the order of the table
5911
+ * @param {object} oSettings dataTables settings object
5912
+ * @memberof DataTable#oApi
5913
+ * @todo This really needs split up!
5914
+ */
5915
+ function _fnSort ( oSettings )
5916
+ {
5917
+ var
5918
+ i, ien, iLen, j, jLen, k, kLen,
5919
+ sDataType, nTh,
5920
+ aiOrig = [],
5921
+ oExtSort = DataTable.ext.type.order,
5922
+ aoData = oSettings.aoData,
5923
+ aoColumns = oSettings.aoColumns,
5924
+ aDataSort, data, iCol, sType, oSort,
5925
+ formatters = 0,
5926
+ sortCol,
5927
+ displayMaster = oSettings.aiDisplayMaster,
5928
+ aSort;
5929
+
5930
+ // Resolve any column types that are unknown due to addition or invalidation
5931
+ // @todo Can this be moved into a 'data-ready' handler which is called when
5932
+ // data is going to be used in the table?
5933
+ _fnColumnTypes( oSettings );
5934
+
5935
+ aSort = _fnSortFlatten( oSettings );
5936
+
5937
+ for ( i=0, ien=aSort.length ; i<ien ; i++ ) {
5938
+ sortCol = aSort[i];
5939
+
5940
+ // Track if we can use the fast sort algorithm
5941
+ if ( sortCol.formatter ) {
5942
+ formatters++;
5943
+ }
5944
+
5945
+ // Load the data needed for the sort, for each cell
5946
+ _fnSortData( oSettings, sortCol.col );
5947
+ }
5948
+
5949
+ /* No sorting required if server-side or no sorting array */
5950
+ if ( _fnDataSource( oSettings ) != 'ssp' && aSort.length !== 0 )
5951
+ {
5952
+ // Create a value - key array of the current row positions such that we can use their
5953
+ // current position during the sort, if values match, in order to perform stable sorting
5954
+ for ( i=0, iLen=displayMaster.length ; i<iLen ; i++ ) {
5955
+ aiOrig[ displayMaster[i] ] = i;
5956
+ }
5957
+
5958
+ /* Do the sort - here we want multi-column sorting based on a given data source (column)
5959
+ * and sorting function (from oSort) in a certain direction. It's reasonably complex to
5960
+ * follow on it's own, but this is what we want (example two column sorting):
5961
+ * fnLocalSorting = function(a,b){
5962
+ * var iTest;
5963
+ * iTest = oSort['string-asc']('data11', 'data12');
5964
+ * if (iTest !== 0)
5965
+ * return iTest;
5966
+ * iTest = oSort['numeric-desc']('data21', 'data22');
5967
+ * if (iTest !== 0)
5968
+ * return iTest;
5969
+ * return oSort['numeric-asc']( aiOrig[a], aiOrig[b] );
5970
+ * }
5971
+ * Basically we have a test for each sorting column, if the data in that column is equal,
5972
+ * test the next column. If all columns match, then we use a numeric sort on the row
5973
+ * positions in the original data array to provide a stable sort.
5974
+ *
5975
+ * Note - I know it seems excessive to have two sorting methods, but the first is around
5976
+ * 15% faster, so the second is only maintained for backwards compatibility with sorting
5977
+ * methods which do not have a pre-sort formatting function.
5978
+ */
5979
+ if ( formatters === aSort.length ) {
5980
+ // All sort types have formatting functions
5981
+ displayMaster.sort( function ( a, b ) {
5982
+ var
5983
+ x, y, k, test, sort,
5984
+ len=aSort.length,
5985
+ dataA = aoData[a]._aSortData,
5986
+ dataB = aoData[b]._aSortData;
5987
+
5988
+ for ( k=0 ; k<len ; k++ ) {
5989
+ sort = aSort[k];
5990
+
5991
+ x = dataA[ sort.col ];
5992
+ y = dataB[ sort.col ];
5993
+
5994
+ test = x<y ? -1 : x>y ? 1 : 0;
5995
+ if ( test !== 0 ) {
5996
+ return sort.dir === 'asc' ? test : -test;
5997
+ }
5998
+ }
5999
+
6000
+ x = aiOrig[a];
6001
+ y = aiOrig[b];
6002
+ return x<y ? -1 : x>y ? 1 : 0;
6003
+ } );
6004
+ }
6005
+ else {
6006
+ // Depreciated - remove in 1.11 (providing a plug-in option)
6007
+ // Not all sort types have formatting methods, so we have to call their sorting
6008
+ // methods.
6009
+ displayMaster.sort( function ( a, b ) {
6010
+ var
6011
+ x, y, k, l, test, sort, fn,
6012
+ len=aSort.length,
6013
+ dataA = aoData[a]._aSortData,
6014
+ dataB = aoData[b]._aSortData;
6015
+
6016
+ for ( k=0 ; k<len ; k++ ) {
6017
+ sort = aSort[k];
6018
+
6019
+ x = dataA[ sort.col ];
6020
+ y = dataB[ sort.col ];
6021
+
6022
+ fn = oExtSort[ sort.type+"-"+sort.dir ] || oExtSort[ "string-"+sort.dir ];
6023
+ test = fn( x, y );
6024
+ if ( test !== 0 ) {
6025
+ return test;
6026
+ }
6027
+ }
6028
+
6029
+ x = aiOrig[a];
6030
+ y = aiOrig[b];
6031
+ return x<y ? -1 : x>y ? 1 : 0;
6032
+ } );
6033
+ }
6034
+ }
6035
+
6036
+ /* Tell the draw function that we have sorted the data */
6037
+ oSettings.bSorted = true;
6038
+ }
6039
+
6040
+
6041
+ function _fnSortAria ( settings )
6042
+ {
6043
+ var label;
6044
+ var nextSort;
6045
+ var columns = settings.aoColumns;
6046
+ var aSort = _fnSortFlatten( settings );
6047
+ var oAria = settings.oLanguage.oAria;
6048
+
6049
+ // ARIA attributes - need to loop all columns, to update all (removing old
6050
+ // attributes as needed)
6051
+ for ( var i=0, iLen=columns.length ; i<iLen ; i++ )
6052
+ {
6053
+ var col = columns[i];
6054
+ var asSorting = col.asSorting;
6055
+ var sTitle = col.sTitle.replace( /<.*?>/g, "" );
6056
+ var th = col.nTh;
6057
+
6058
+ // IE7 is throwing an error when setting these properties with jQuery's
6059
+ // attr() and removeAttr() methods...
6060
+ th.removeAttribute('aria-sort');
6061
+
6062
+ /* In ARIA only the first sorting column can be marked as sorting - no multi-sort option */
6063
+ if ( col.bSortable ) {
6064
+ if ( aSort.length > 0 && aSort[0].col == i ) {
6065
+ th.setAttribute('aria-sort', aSort[0].dir=="asc" ? "ascending" : "descending" );
6066
+ nextSort = asSorting[ aSort[0].index+1 ] || asSorting[0];
6067
+ }
6068
+ else {
6069
+ nextSort = asSorting[0];
6070
+ }
6071
+
6072
+ label = sTitle + ( nextSort === "asc" ?
6073
+ oAria.sSortAscending :
6074
+ oAria.sSortDescending
6075
+ );
6076
+ }
6077
+ else {
6078
+ label = sTitle;
6079
+ }
6080
+
6081
+ th.setAttribute('aria-label', label);
6082
+ }
6083
+ }
6084
+
6085
+
6086
+ /**
6087
+ * Function to run on user sort request
6088
+ * @param {object} settings dataTables settings object
6089
+ * @param {node} attachTo node to attach the handler to
6090
+ * @param {int} colIdx column sorting index
6091
+ * @param {boolean} [append=false] Append the requested sort to the existing
6092
+ * sort if true (i.e. multi-column sort)
6093
+ * @param {function} [callback] callback function
6094
+ * @memberof DataTable#oApi
6095
+ */
6096
+ function _fnSortListener ( settings, colIdx, append, callback )
6097
+ {
6098
+ var col = settings.aoColumns[ colIdx ];
6099
+ var sorting = settings.aaSorting;
6100
+ var asSorting = col.asSorting;
6101
+ var nextSortIdx;
6102
+ var next = function ( a, overflow ) {
6103
+ var idx = a._idx;
6104
+ if ( idx === undefined ) {
6105
+ idx = $.inArray( a[1], asSorting );
6106
+ }
6107
+
6108
+ return idx+1 < asSorting.length ?
6109
+ idx+1 :
6110
+ overflow ?
6111
+ null :
6112
+ 0;
6113
+ };
6114
+
6115
+ // Convert to 2D array if needed
6116
+ if ( typeof sorting[0] === 'number' ) {
6117
+ sorting = settings.aaSorting = [ sorting ];
6118
+ }
6119
+
6120
+ // If appending the sort then we are multi-column sorting
6121
+ if ( append && settings.oFeatures.bSortMulti ) {
6122
+ // Are we already doing some kind of sort on this column?
6123
+ var sortIdx = $.inArray( colIdx, _pluck(sorting, '0') );
6124
+
6125
+ if ( sortIdx !== -1 ) {
6126
+ // Yes, modify the sort
6127
+ nextSortIdx = next( sorting[sortIdx], true );
6128
+
6129
+ if ( nextSortIdx === null && sorting.length === 1 ) {
6130
+ nextSortIdx = 0; // can't remove sorting completely
6131
+ }
6132
+
6133
+ if ( nextSortIdx === null ) {
6134
+ sorting.splice( sortIdx, 1 );
6135
+ }
6136
+ else {
6137
+ sorting[sortIdx][1] = asSorting[ nextSortIdx ];
6138
+ sorting[sortIdx]._idx = nextSortIdx;
6139
+ }
6140
+ }
6141
+ else {
6142
+ // No sort on this column yet
6143
+ sorting.push( [ colIdx, asSorting[0], 0 ] );
6144
+ sorting[sorting.length-1]._idx = 0;
6145
+ }
6146
+ }
6147
+ else if ( sorting.length && sorting[0][0] == colIdx ) {
6148
+ // Single column - already sorting on this column, modify the sort
6149
+ nextSortIdx = next( sorting[0] );
6150
+
6151
+ sorting.length = 1;
6152
+ sorting[0][1] = asSorting[ nextSortIdx ];
6153
+ sorting[0]._idx = nextSortIdx;
6154
+ }
6155
+ else {
6156
+ // Single column - sort only on this column
6157
+ sorting.length = 0;
6158
+ sorting.push( [ colIdx, asSorting[0] ] );
6159
+ sorting[0]._idx = 0;
6160
+ }
6161
+
6162
+ // Run the sort by calling a full redraw
6163
+ _fnReDraw( settings );
6164
+
6165
+ // callback used for async user interaction
6166
+ if ( typeof callback == 'function' ) {
6167
+ callback( settings );
6168
+ }
6169
+ }
6170
+
6171
+
6172
+ /**
6173
+ * Attach a sort handler (click) to a node
6174
+ * @param {object} settings dataTables settings object
6175
+ * @param {node} attachTo node to attach the handler to
6176
+ * @param {int} colIdx column sorting index
6177
+ * @param {function} [callback] callback function
6178
+ * @memberof DataTable#oApi
6179
+ */
6180
+ function _fnSortAttachListener ( settings, attachTo, colIdx, callback )
6181
+ {
6182
+ var col = settings.aoColumns[ colIdx ];
6183
+
6184
+ _fnBindAction( attachTo, {}, function (e) {
6185
+ /* If the column is not sortable - don't to anything */
6186
+ if ( col.bSortable === false ) {
6187
+ return;
6188
+ }
6189
+
6190
+ // If processing is enabled use a timeout to allow the processing
6191
+ // display to be shown - otherwise to it synchronously
6192
+ if ( settings.oFeatures.bProcessing ) {
6193
+ _fnProcessingDisplay( settings, true );
6194
+
6195
+ setTimeout( function() {
6196
+ _fnSortListener( settings, colIdx, e.shiftKey, callback );
6197
+
6198
+ // In server-side processing, the draw callback will remove the
6199
+ // processing display
6200
+ if ( _fnDataSource( settings ) !== 'ssp' ) {
6201
+ _fnProcessingDisplay( settings, false );
6202
+ }
6203
+ }, 0 );
6204
+ }
6205
+ else {
6206
+ _fnSortListener( settings, colIdx, e.shiftKey, callback );
6207
+ }
6208
+ } );
6209
+ }
6210
+
6211
+
6212
+ /**
6213
+ * Set the sorting classes on table's body, Note: it is safe to call this function
6214
+ * when bSort and bSortClasses are false
6215
+ * @param {object} oSettings dataTables settings object
6216
+ * @memberof DataTable#oApi
6217
+ */
6218
+ function _fnSortingClasses( settings )
6219
+ {
6220
+ var oldSort = settings.aLastSort;
6221
+ var sortClass = settings.oClasses.sSortColumn;
6222
+ var sort = _fnSortFlatten( settings );
6223
+ var features = settings.oFeatures;
6224
+ var i, ien, colIdx;
6225
+
6226
+ if ( features.bSort && features.bSortClasses ) {
6227
+ // Remove old sorting classes
6228
+ for ( i=0, ien=oldSort.length ; i<ien ; i++ ) {
6229
+ colIdx = oldSort[i].src;
6230
+
6231
+ // Remove column sorting
6232
+ $( _pluck( settings.aoData, 'anCells', colIdx ) )
6233
+ .removeClass( sortClass + (i<2 ? i+1 : 3) );
6234
+ }
6235
+
6236
+ // Add new column sorting
6237
+ for ( i=0, ien=sort.length ; i<ien ; i++ ) {
6238
+ colIdx = sort[i].src;
6239
+
6240
+ $( _pluck( settings.aoData, 'anCells', colIdx ) )
6241
+ .addClass( sortClass + (i<2 ? i+1 : 3) );
6242
+ }
6243
+ }
6244
+
6245
+ settings.aLastSort = sort;
6246
+ }
6247
+
6248
+
6249
+ // Get the data to sort a column, be it from cache, fresh (populating the
6250
+ // cache), or from a sort formatter
6251
+ function _fnSortData( settings, idx )
6252
+ {
6253
+ // Custom sorting function - provided by the sort data type
6254
+ var column = settings.aoColumns[ idx ];
6255
+ var customSort = DataTable.ext.order[ column.sSortDataType ];
6256
+ var customData;
6257
+
6258
+ if ( customSort ) {
6259
+ customData = customSort.call( settings.oInstance, settings, idx,
6260
+ _fnColumnIndexToVisible( settings, idx )
6261
+ );
6262
+ }
6263
+
6264
+ // Use / populate cache
6265
+ var row, cellData;
6266
+ var formatter = DataTable.ext.type.order[ column.sType+"-pre" ];
6267
+
6268
+ for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
6269
+ row = settings.aoData[i];
6270
+
6271
+ if ( ! row._aSortData ) {
6272
+ row._aSortData = [];
6273
+ }
6274
+
6275
+ if ( ! row._aSortData[idx] || customSort ) {
6276
+ cellData = customSort ?
6277
+ customData[i] : // If there was a custom sort function, use data from there
6278
+ _fnGetCellData( settings, i, idx, 'sort' );
6279
+
6280
+ row._aSortData[ idx ] = formatter ?
6281
+ formatter( cellData ) :
6282
+ cellData;
6283
+ }
6284
+ }
6285
+ }
6286
+
6287
+
6288
+
6289
+ /**
6290
+ * Save the state of a table
6291
+ * @param {object} oSettings dataTables settings object
6292
+ * @memberof DataTable#oApi
6293
+ */
6294
+ function _fnSaveState ( settings )
6295
+ {
6296
+ if ( !settings.oFeatures.bStateSave || settings.bDestroying )
6297
+ {
6298
+ return;
6299
+ }
6300
+
6301
+ /* Store the interesting variables */
6302
+ var state = {
6303
+ time: +new Date(),
6304
+ start: settings._iDisplayStart,
6305
+ length: settings._iDisplayLength,
6306
+ order: $.extend( true, [], settings.aaSorting ),
6307
+ search: _fnSearchToCamel( settings.oPreviousSearch ),
6308
+ columns: $.map( settings.aoColumns, function ( col, i ) {
6309
+ return {
6310
+ visible: col.bVisible,
6311
+ search: _fnSearchToCamel( settings.aoPreSearchCols[i] )
6312
+ };
6313
+ } )
6314
+ };
6315
+
6316
+ _fnCallbackFire( settings, "aoStateSaveParams", 'stateSaveParams', [settings, state] );
6317
+
6318
+ settings.oSavedState = state;
6319
+ settings.fnStateSaveCallback.call( settings.oInstance, settings, state );
6320
+ }
6321
+
6322
+
6323
+ /**
6324
+ * Attempt to load a saved table state
6325
+ * @param {object} oSettings dataTables settings object
6326
+ * @param {object} oInit DataTables init object so we can override settings
6327
+ * @param {function} callback Callback to execute when the state has been loaded
6328
+ * @memberof DataTable#oApi
6329
+ */
6330
+ function _fnLoadState ( settings, oInit, callback )
6331
+ {
6332
+ var i, ien;
6333
+ var columns = settings.aoColumns;
6334
+ var loaded = function ( s ) {
6335
+ if ( ! s || ! s.time ) {
6336
+ callback();
6337
+ return;
6338
+ }
6339
+
6340
+ // Allow custom and plug-in manipulation functions to alter the saved data set and
6341
+ // cancelling of loading by returning false
6342
+ var abStateLoad = _fnCallbackFire( settings, 'aoStateLoadParams', 'stateLoadParams', [settings, s] );
6343
+ if ( $.inArray( false, abStateLoad ) !== -1 ) {
6344
+ callback();
6345
+ return;
6346
+ }
6347
+
6348
+ // Reject old data
6349
+ var duration = settings.iStateDuration;
6350
+ if ( duration > 0 && s.time < +new Date() - (duration*1000) ) {
6351
+ callback();
6352
+ return;
6353
+ }
6354
+
6355
+ // Number of columns have changed - all bets are off, no restore of settings
6356
+ if ( s.columns && columns.length !== s.columns.length ) {
6357
+ callback();
6358
+ return;
6359
+ }
6360
+
6361
+ // Store the saved state so it might be accessed at any time
6362
+ settings.oLoadedState = $.extend( true, {}, s );
6363
+
6364
+ // Restore key features - todo - for 1.11 this needs to be done by
6365
+ // subscribed events
6366
+ if ( s.start !== undefined ) {
6367
+ settings._iDisplayStart = s.start;
6368
+ settings.iInitDisplayStart = s.start;
6369
+ }
6370
+ if ( s.length !== undefined ) {
6371
+ settings._iDisplayLength = s.length;
6372
+ }
6373
+
6374
+ // Order
6375
+ if ( s.order !== undefined ) {
6376
+ settings.aaSorting = [];
6377
+ $.each( s.order, function ( i, col ) {
6378
+ settings.aaSorting.push( col[0] >= columns.length ?
6379
+ [ 0, col[1] ] :
6380
+ col
6381
+ );
6382
+ } );
6383
+ }
6384
+
6385
+ // Search
6386
+ if ( s.search !== undefined ) {
6387
+ $.extend( settings.oPreviousSearch, _fnSearchToHung( s.search ) );
6388
+ }
6389
+
6390
+ // Columns
6391
+ //
6392
+ if ( s.columns ) {
6393
+ for ( i=0, ien=s.columns.length ; i<ien ; i++ ) {
6394
+ var col = s.columns[i];
6395
+
6396
+ // Visibility
6397
+ if ( col.visible !== undefined ) {
6398
+ columns[i].bVisible = col.visible;
6399
+ }
6400
+
6401
+ // Search
6402
+ if ( col.search !== undefined ) {
6403
+ $.extend( settings.aoPreSearchCols[i], _fnSearchToHung( col.search ) );
6404
+ }
6405
+ }
6406
+ }
6407
+
6408
+ _fnCallbackFire( settings, 'aoStateLoaded', 'stateLoaded', [settings, s] );
6409
+ callback();
6410
+ }
6411
+
6412
+ if ( ! settings.oFeatures.bStateSave ) {
6413
+ callback();
6414
+ return;
6415
+ }
6416
+
6417
+ var state = settings.fnStateLoadCallback.call( settings.oInstance, settings, loaded );
6418
+
6419
+ if ( state !== undefined ) {
6420
+ loaded( state );
6421
+ }
6422
+ // otherwise, wait for the loaded callback to be executed
6423
+ }
6424
+
6425
+
6426
+ /**
6427
+ * Return the settings object for a particular table
6428
+ * @param {node} table table we are using as a dataTable
6429
+ * @returns {object} Settings object - or null if not found
6430
+ * @memberof DataTable#oApi
6431
+ */
6432
+ function _fnSettingsFromNode ( table )
6433
+ {
6434
+ var settings = DataTable.settings;
6435
+ var idx = $.inArray( table, _pluck( settings, 'nTable' ) );
6436
+
6437
+ return idx !== -1 ?
6438
+ settings[ idx ] :
6439
+ null;
6440
+ }
6441
+
6442
+
6443
+ /**
6444
+ * Log an error message
6445
+ * @param {object} settings dataTables settings object
6446
+ * @param {int} level log error messages, or display them to the user
6447
+ * @param {string} msg error message
6448
+ * @param {int} tn Technical note id to get more information about the error.
6449
+ * @memberof DataTable#oApi
6450
+ */
6451
+ function _fnLog( settings, level, msg, tn )
6452
+ {
6453
+ msg = 'DataTables warning: '+
6454
+ (settings ? 'table id='+settings.sTableId+' - ' : '')+msg;
6455
+
6456
+ if ( tn ) {
6457
+ msg += '. For more information about this error, please see '+
6458
+ 'http://datatables.net/tn/'+tn;
6459
+ }
6460
+
6461
+ if ( ! level ) {
6462
+ // Backwards compatibility pre 1.10
6463
+ var ext = DataTable.ext;
6464
+ var type = ext.sErrMode || ext.errMode;
6465
+
6466
+ if ( settings ) {
6467
+ _fnCallbackFire( settings, null, 'error', [ settings, tn, msg ] );
6468
+ }
6469
+
6470
+ if ( type == 'alert' ) {
6471
+ alert( msg );
6472
+ }
6473
+ else if ( type == 'throw' ) {
6474
+ throw new Error(msg);
6475
+ }
6476
+ else if ( typeof type == 'function' ) {
6477
+ type( settings, tn, msg );
6478
+ }
6479
+ }
6480
+ else if ( window.console && console.log ) {
6481
+ console.log( msg );
6482
+ }
6483
+ }
6484
+
6485
+
6486
+ /**
6487
+ * See if a property is defined on one object, if so assign it to the other object
6488
+ * @param {object} ret target object
6489
+ * @param {object} src source object
6490
+ * @param {string} name property
6491
+ * @param {string} [mappedName] name to map too - optional, name used if not given
6492
+ * @memberof DataTable#oApi
6493
+ */
6494
+ function _fnMap( ret, src, name, mappedName )
6495
+ {
6496
+ if ( $.isArray( name ) ) {
6497
+ $.each( name, function (i, val) {
6498
+ if ( $.isArray( val ) ) {
6499
+ _fnMap( ret, src, val[0], val[1] );
6500
+ }
6501
+ else {
6502
+ _fnMap( ret, src, val );
6503
+ }
6504
+ } );
6505
+
6506
+ return;
6507
+ }
6508
+
6509
+ if ( mappedName === undefined ) {
6510
+ mappedName = name;
6511
+ }
6512
+
6513
+ if ( src[name] !== undefined ) {
6514
+ ret[mappedName] = src[name];
6515
+ }
6516
+ }
6517
+
6518
+
6519
+ /**
6520
+ * Extend objects - very similar to jQuery.extend, but deep copy objects, and
6521
+ * shallow copy arrays. The reason we need to do this, is that we don't want to
6522
+ * deep copy array init values (such as aaSorting) since the dev wouldn't be
6523
+ * able to override them, but we do want to deep copy arrays.
6524
+ * @param {object} out Object to extend
6525
+ * @param {object} extender Object from which the properties will be applied to
6526
+ * out
6527
+ * @param {boolean} breakRefs If true, then arrays will be sliced to take an
6528
+ * independent copy with the exception of the `data` or `aaData` parameters
6529
+ * if they are present. This is so you can pass in a collection to
6530
+ * DataTables and have that used as your data source without breaking the
6531
+ * references
6532
+ * @returns {object} out Reference, just for convenience - out === the return.
6533
+ * @memberof DataTable#oApi
6534
+ * @todo This doesn't take account of arrays inside the deep copied objects.
6535
+ */
6536
+ function _fnExtend( out, extender, breakRefs )
6537
+ {
6538
+ var val;
6539
+
6540
+ for ( var prop in extender ) {
6541
+ if ( extender.hasOwnProperty(prop) ) {
6542
+ val = extender[prop];
6543
+
6544
+ if ( $.isPlainObject( val ) ) {
6545
+ if ( ! $.isPlainObject( out[prop] ) ) {
6546
+ out[prop] = {};
6547
+ }
6548
+ $.extend( true, out[prop], val );
6549
+ }
6550
+ else if ( breakRefs && prop !== 'data' && prop !== 'aaData' && $.isArray(val) ) {
6551
+ out[prop] = val.slice();
6552
+ }
6553
+ else {
6554
+ out[prop] = val;
6555
+ }
6556
+ }
6557
+ }
6558
+
6559
+ return out;
6560
+ }
6561
+
6562
+
6563
+ /**
6564
+ * Bind an event handers to allow a click or return key to activate the callback.
6565
+ * This is good for accessibility since a return on the keyboard will have the
6566
+ * same effect as a click, if the element has focus.
6567
+ * @param {element} n Element to bind the action to
6568
+ * @param {object} oData Data object to pass to the triggered function
6569
+ * @param {function} fn Callback function for when the event is triggered
6570
+ * @memberof DataTable#oApi
6571
+ */
6572
+ function _fnBindAction( n, oData, fn )
6573
+ {
6574
+ $(n)
6575
+ .on( 'click.DT', oData, function (e) {
6576
+ n.blur(); // Remove focus outline for mouse users
6577
+ fn(e);
6578
+ } )
6579
+ .on( 'keypress.DT', oData, function (e){
6580
+ if ( e.which === 13 ) {
6581
+ e.preventDefault();
6582
+ fn(e);
6583
+ }
6584
+ } )
6585
+ .on( 'selectstart.DT', function () {
6586
+ /* Take the brutal approach to cancelling text selection */
6587
+ return false;
6588
+ } );
6589
+ }
6590
+
6591
+
6592
+ /**
6593
+ * Register a callback function. Easily allows a callback function to be added to
6594
+ * an array store of callback functions that can then all be called together.
6595
+ * @param {object} oSettings dataTables settings object
6596
+ * @param {string} sStore Name of the array storage for the callbacks in oSettings
6597
+ * @param {function} fn Function to be called back
6598
+ * @param {string} sName Identifying name for the callback (i.e. a label)
6599
+ * @memberof DataTable#oApi
6600
+ */
6601
+ function _fnCallbackReg( oSettings, sStore, fn, sName )
6602
+ {
6603
+ if ( fn )
6604
+ {
6605
+ oSettings[sStore].push( {
6606
+ "fn": fn,
6607
+ "sName": sName
6608
+ } );
6609
+ }
6610
+ }
6611
+
6612
+
6613
+ /**
6614
+ * Fire callback functions and trigger events. Note that the loop over the
6615
+ * callback array store is done backwards! Further note that you do not want to
6616
+ * fire off triggers in time sensitive applications (for example cell creation)
6617
+ * as its slow.
6618
+ * @param {object} settings dataTables settings object
6619
+ * @param {string} callbackArr Name of the array storage for the callbacks in
6620
+ * oSettings
6621
+ * @param {string} eventName Name of the jQuery custom event to trigger. If
6622
+ * null no trigger is fired
6623
+ * @param {array} args Array of arguments to pass to the callback function /
6624
+ * trigger
6625
+ * @memberof DataTable#oApi
6626
+ */
6627
+ function _fnCallbackFire( settings, callbackArr, eventName, args )
6628
+ {
6629
+ var ret = [];
6630
+
6631
+ if ( callbackArr ) {
6632
+ ret = $.map( settings[callbackArr].slice().reverse(), function (val, i) {
6633
+ return val.fn.apply( settings.oInstance, args );
6634
+ } );
6635
+ }
6636
+
6637
+ if ( eventName !== null ) {
6638
+ var e = $.Event( eventName+'.dt' );
6639
+
6640
+ $(settings.nTable).trigger( e, args );
6641
+
6642
+ ret.push( e.result );
6643
+ }
6644
+
6645
+ return ret;
6646
+ }
6647
+
6648
+
6649
+ function _fnLengthOverflow ( settings )
6650
+ {
6651
+ var
6652
+ start = settings._iDisplayStart,
6653
+ end = settings.fnDisplayEnd(),
6654
+ len = settings._iDisplayLength;
6655
+
6656
+ /* If we have space to show extra rows (backing up from the end point - then do so */
6657
+ if ( start >= end )
6658
+ {
6659
+ start = end - len;
6660
+ }
6661
+
6662
+ // Keep the start record on the current page
6663
+ start -= (start % len);
6664
+
6665
+ if ( len === -1 || start < 0 )
6666
+ {
6667
+ start = 0;
6668
+ }
6669
+
6670
+ settings._iDisplayStart = start;
6671
+ }
6672
+
6673
+
6674
+ function _fnRenderer( settings, type )
6675
+ {
6676
+ var renderer = settings.renderer;
6677
+ var host = DataTable.ext.renderer[type];
6678
+
6679
+ if ( $.isPlainObject( renderer ) && renderer[type] ) {
6680
+ // Specific renderer for this type. If available use it, otherwise use
6681
+ // the default.
6682
+ return host[renderer[type]] || host._;
6683
+ }
6684
+ else if ( typeof renderer === 'string' ) {
6685
+ // Common renderer - if there is one available for this type use it,
6686
+ // otherwise use the default
6687
+ return host[renderer] || host._;
6688
+ }
6689
+
6690
+ // Use the default
6691
+ return host._;
6692
+ }
6693
+
6694
+
6695
+ /**
6696
+ * Detect the data source being used for the table. Used to simplify the code
6697
+ * a little (ajax) and to make it compress a little smaller.
6698
+ *
6699
+ * @param {object} settings dataTables settings object
6700
+ * @returns {string} Data source
6701
+ * @memberof DataTable#oApi
6702
+ */
6703
+ function _fnDataSource ( settings )
6704
+ {
6705
+ if ( settings.oFeatures.bServerSide ) {
6706
+ return 'ssp';
6707
+ }
6708
+ else if ( settings.ajax || settings.sAjaxSource ) {
6709
+ return 'ajax';
6710
+ }
6711
+ return 'dom';
6712
+ }
6713
+
6714
+
6715
+
6716
+
6717
+ /**
6718
+ * Computed structure of the DataTables API, defined by the options passed to
6719
+ * `DataTable.Api.register()` when building the API.
6720
+ *
6721
+ * The structure is built in order to speed creation and extension of the Api
6722
+ * objects since the extensions are effectively pre-parsed.
6723
+ *
6724
+ * The array is an array of objects with the following structure, where this
6725
+ * base array represents the Api prototype base:
6726
+ *
6727
+ * [
6728
+ * {
6729
+ * name: 'data' -- string - Property name
6730
+ * val: function () {}, -- function - Api method (or undefined if just an object
6731
+ * methodExt: [ ... ], -- array - Array of Api object definitions to extend the method result
6732
+ * propExt: [ ... ] -- array - Array of Api object definitions to extend the property
6733
+ * },
6734
+ * {
6735
+ * name: 'row'
6736
+ * val: {},
6737
+ * methodExt: [ ... ],
6738
+ * propExt: [
6739
+ * {
6740
+ * name: 'data'
6741
+ * val: function () {},
6742
+ * methodExt: [ ... ],
6743
+ * propExt: [ ... ]
6744
+ * },
6745
+ * ...
6746
+ * ]
6747
+ * }
6748
+ * ]
6749
+ *
6750
+ * @type {Array}
6751
+ * @ignore
6752
+ */
6753
+ var __apiStruct = [];
6754
+
6755
+
6756
+ /**
6757
+ * `Array.prototype` reference.
6758
+ *
6759
+ * @type object
6760
+ * @ignore
6761
+ */
6762
+ var __arrayProto = Array.prototype;
6763
+
6764
+
6765
+ /**
6766
+ * Abstraction for `context` parameter of the `Api` constructor to allow it to
6767
+ * take several different forms for ease of use.
6768
+ *
6769
+ * Each of the input parameter types will be converted to a DataTables settings
6770
+ * object where possible.
6771
+ *
6772
+ * @param {string|node|jQuery|object} mixed DataTable identifier. Can be one
6773
+ * of:
6774
+ *
6775
+ * * `string` - jQuery selector. Any DataTables' matching the given selector
6776
+ * with be found and used.
6777
+ * * `node` - `TABLE` node which has already been formed into a DataTable.
6778
+ * * `jQuery` - A jQuery object of `TABLE` nodes.
6779
+ * * `object` - DataTables settings object
6780
+ * * `DataTables.Api` - API instance
6781
+ * @return {array|null} Matching DataTables settings objects. `null` or
6782
+ * `undefined` is returned if no matching DataTable is found.
6783
+ * @ignore
6784
+ */
6785
+ var _toSettings = function ( mixed )
6786
+ {
6787
+ var idx, jq;
6788
+ var settings = DataTable.settings;
6789
+ var tables = $.map( settings, function (el, i) {
6790
+ return el.nTable;
6791
+ } );
6792
+
6793
+ if ( ! mixed ) {
6794
+ return [];
6795
+ }
6796
+ else if ( mixed.nTable && mixed.oApi ) {
6797
+ // DataTables settings object
6798
+ return [ mixed ];
6799
+ }
6800
+ else if ( mixed.nodeName && mixed.nodeName.toLowerCase() === 'table' ) {
6801
+ // Table node
6802
+ idx = $.inArray( mixed, tables );
6803
+ return idx !== -1 ? [ settings[idx] ] : null;
6804
+ }
6805
+ else if ( mixed && typeof mixed.settings === 'function' ) {
6806
+ return mixed.settings().toArray();
6807
+ }
6808
+ else if ( typeof mixed === 'string' ) {
6809
+ // jQuery selector
6810
+ jq = $(mixed);
6811
+ }
6812
+ else if ( mixed instanceof $ ) {
6813
+ // jQuery object (also DataTables instance)
6814
+ jq = mixed;
6815
+ }
6816
+
6817
+ if ( jq ) {
6818
+ return jq.map( function(i) {
6819
+ idx = $.inArray( this, tables );
6820
+ return idx !== -1 ? settings[idx] : null;
6821
+ } ).toArray();
6822
+ }
6823
+ };
6824
+
6825
+
6826
+ /**
6827
+ * DataTables API class - used to control and interface with one or more
6828
+ * DataTables enhanced tables.
6829
+ *
6830
+ * The API class is heavily based on jQuery, presenting a chainable interface
6831
+ * that you can use to interact with tables. Each instance of the API class has
6832
+ * a "context" - i.e. the tables that it will operate on. This could be a single
6833
+ * table, all tables on a page or a sub-set thereof.
6834
+ *
6835
+ * Additionally the API is designed to allow you to easily work with the data in
6836
+ * the tables, retrieving and manipulating it as required. This is done by
6837
+ * presenting the API class as an array like interface. The contents of the
6838
+ * array depend upon the actions requested by each method (for example
6839
+ * `rows().nodes()` will return an array of nodes, while `rows().data()` will
6840
+ * return an array of objects or arrays depending upon your table's
6841
+ * configuration). The API object has a number of array like methods (`push`,
6842
+ * `pop`, `reverse` etc) as well as additional helper methods (`each`, `pluck`,
6843
+ * `unique` etc) to assist your working with the data held in a table.
6844
+ *
6845
+ * Most methods (those which return an Api instance) are chainable, which means
6846
+ * the return from a method call also has all of the methods available that the
6847
+ * top level object had. For example, these two calls are equivalent:
6848
+ *
6849
+ * // Not chained
6850
+ * api.row.add( {...} );
6851
+ * api.draw();
6852
+ *
6853
+ * // Chained
6854
+ * api.row.add( {...} ).draw();
6855
+ *
6856
+ * @class DataTable.Api
6857
+ * @param {array|object|string|jQuery} context DataTable identifier. This is
6858
+ * used to define which DataTables enhanced tables this API will operate on.
6859
+ * Can be one of:
6860
+ *
6861
+ * * `string` - jQuery selector. Any DataTables' matching the given selector
6862
+ * with be found and used.
6863
+ * * `node` - `TABLE` node which has already been formed into a DataTable.
6864
+ * * `jQuery` - A jQuery object of `TABLE` nodes.
6865
+ * * `object` - DataTables settings object
6866
+ * @param {array} [data] Data to initialise the Api instance with.
6867
+ *
6868
+ * @example
6869
+ * // Direct initialisation during DataTables construction
6870
+ * var api = $('#example').DataTable();
6871
+ *
6872
+ * @example
6873
+ * // Initialisation using a DataTables jQuery object
6874
+ * var api = $('#example').dataTable().api();
6875
+ *
6876
+ * @example
6877
+ * // Initialisation as a constructor
6878
+ * var api = new $.fn.DataTable.Api( 'table.dataTable' );
6879
+ */
6880
+ _Api = function ( context, data )
6881
+ {
6882
+ if ( ! (this instanceof _Api) ) {
6883
+ return new _Api( context, data );
6884
+ }
6885
+
6886
+ var settings = [];
6887
+ var ctxSettings = function ( o ) {
6888
+ var a = _toSettings( o );
6889
+ if ( a ) {
6890
+ settings = settings.concat( a );
6891
+ }
6892
+ };
6893
+
6894
+ if ( $.isArray( context ) ) {
6895
+ for ( var i=0, ien=context.length ; i<ien ; i++ ) {
6896
+ ctxSettings( context[i] );
6897
+ }
6898
+ }
6899
+ else {
6900
+ ctxSettings( context );
6901
+ }
6902
+
6903
+ // Remove duplicates
6904
+ this.context = _unique( settings );
6905
+
6906
+ // Initial data
6907
+ if ( data ) {
6908
+ $.merge( this, data );
6909
+ }
6910
+
6911
+ // selector
6912
+ this.selector = {
6913
+ rows: null,
6914
+ cols: null,
6915
+ opts: null
6916
+ };
6917
+
6918
+ _Api.extend( this, this, __apiStruct );
6919
+ };
6920
+
6921
+ DataTable.Api = _Api;
6922
+
6923
+ // Don't destroy the existing prototype, just extend it. Required for jQuery 2's
6924
+ // isPlainObject.
6925
+ $.extend( _Api.prototype, {
6926
+ any: function ()
6927
+ {
6928
+ return this.count() !== 0;
6929
+ },
6930
+
6931
+
6932
+ concat: __arrayProto.concat,
6933
+
6934
+
6935
+ context: [], // array of table settings objects
6936
+
6937
+
6938
+ count: function ()
6939
+ {
6940
+ return this.flatten().length;
6941
+ },
6942
+
6943
+
6944
+ each: function ( fn )
6945
+ {
6946
+ for ( var i=0, ien=this.length ; i<ien; i++ ) {
6947
+ fn.call( this, this[i], i, this );
6948
+ }
6949
+
6950
+ return this;
6951
+ },
6952
+
6953
+
6954
+ eq: function ( idx )
6955
+ {
6956
+ var ctx = this.context;
6957
+
6958
+ return ctx.length > idx ?
6959
+ new _Api( ctx[idx], this[idx] ) :
6960
+ null;
6961
+ },
6962
+
6963
+
6964
+ filter: function ( fn )
6965
+ {
6966
+ var a = [];
6967
+
6968
+ if ( __arrayProto.filter ) {
6969
+ a = __arrayProto.filter.call( this, fn, this );
6970
+ }
6971
+ else {
6972
+ // Compatibility for browsers without EMCA-252-5 (JS 1.6)
6973
+ for ( var i=0, ien=this.length ; i<ien ; i++ ) {
6974
+ if ( fn.call( this, this[i], i, this ) ) {
6975
+ a.push( this[i] );
6976
+ }
6977
+ }
6978
+ }
6979
+
6980
+ return new _Api( this.context, a );
6981
+ },
6982
+
6983
+
6984
+ flatten: function ()
6985
+ {
6986
+ var a = [];
6987
+ return new _Api( this.context, a.concat.apply( a, this.toArray() ) );
6988
+ },
6989
+
6990
+
6991
+ join: __arrayProto.join,
6992
+
6993
+
6994
+ indexOf: __arrayProto.indexOf || function (obj, start)
6995
+ {
6996
+ for ( var i=(start || 0), ien=this.length ; i<ien ; i++ ) {
6997
+ if ( this[i] === obj ) {
6998
+ return i;
6999
+ }
7000
+ }
7001
+ return -1;
7002
+ },
7003
+
7004
+ iterator: function ( flatten, type, fn, alwaysNew ) {
7005
+ var
7006
+ a = [], ret,
7007
+ i, ien, j, jen,
7008
+ context = this.context,
7009
+ rows, items, item,
7010
+ selector = this.selector;
7011
+
7012
+ // Argument shifting
7013
+ if ( typeof flatten === 'string' ) {
7014
+ alwaysNew = fn;
7015
+ fn = type;
7016
+ type = flatten;
7017
+ flatten = false;
7018
+ }
7019
+
7020
+ for ( i=0, ien=context.length ; i<ien ; i++ ) {
7021
+ var apiInst = new _Api( context[i] );
7022
+
7023
+ if ( type === 'table' ) {
7024
+ ret = fn.call( apiInst, context[i], i );
7025
+
7026
+ if ( ret !== undefined ) {
7027
+ a.push( ret );
7028
+ }
7029
+ }
7030
+ else if ( type === 'columns' || type === 'rows' ) {
7031
+ // this has same length as context - one entry for each table
7032
+ ret = fn.call( apiInst, context[i], this[i], i );
7033
+
7034
+ if ( ret !== undefined ) {
7035
+ a.push( ret );
7036
+ }
7037
+ }
7038
+ else if ( type === 'column' || type === 'column-rows' || type === 'row' || type === 'cell' ) {
7039
+ // columns and rows share the same structure.
7040
+ // 'this' is an array of column indexes for each context
7041
+ items = this[i];
7042
+
7043
+ if ( type === 'column-rows' ) {
7044
+ rows = _selector_row_indexes( context[i], selector.opts );
7045
+ }
7046
+
7047
+ for ( j=0, jen=items.length ; j<jen ; j++ ) {
7048
+ item = items[j];
7049
+
7050
+ if ( type === 'cell' ) {
7051
+ ret = fn.call( apiInst, context[i], item.row, item.column, i, j );
7052
+ }
7053
+ else {
7054
+ ret = fn.call( apiInst, context[i], item, i, j, rows );
7055
+ }
7056
+
7057
+ if ( ret !== undefined ) {
7058
+ a.push( ret );
7059
+ }
7060
+ }
7061
+ }
7062
+ }
7063
+
7064
+ if ( a.length || alwaysNew ) {
7065
+ var api = new _Api( context, flatten ? a.concat.apply( [], a ) : a );
7066
+ var apiSelector = api.selector;
7067
+ apiSelector.rows = selector.rows;
7068
+ apiSelector.cols = selector.cols;
7069
+ apiSelector.opts = selector.opts;
7070
+ return api;
7071
+ }
7072
+ return this;
7073
+ },
7074
+
7075
+
7076
+ lastIndexOf: __arrayProto.lastIndexOf || function (obj, start)
7077
+ {
7078
+ // Bit cheeky...
7079
+ return this.indexOf.apply( this.toArray.reverse(), arguments );
7080
+ },
7081
+
7082
+
7083
+ length: 0,
7084
+
7085
+
7086
+ map: function ( fn )
7087
+ {
7088
+ var a = [];
7089
+
7090
+ if ( __arrayProto.map ) {
7091
+ a = __arrayProto.map.call( this, fn, this );
7092
+ }
7093
+ else {
7094
+ // Compatibility for browsers without EMCA-252-5 (JS 1.6)
7095
+ for ( var i=0, ien=this.length ; i<ien ; i++ ) {
7096
+ a.push( fn.call( this, this[i], i ) );
7097
+ }
7098
+ }
7099
+
7100
+ return new _Api( this.context, a );
7101
+ },
7102
+
7103
+
7104
+ pluck: function ( prop )
7105
+ {
7106
+ return this.map( function ( el ) {
7107
+ return el[ prop ];
7108
+ } );
7109
+ },
7110
+
7111
+ pop: __arrayProto.pop,
7112
+
7113
+
7114
+ push: __arrayProto.push,
7115
+
7116
+
7117
+ // Does not return an API instance
7118
+ reduce: __arrayProto.reduce || function ( fn, init )
7119
+ {
7120
+ return _fnReduce( this, fn, init, 0, this.length, 1 );
7121
+ },
7122
+
7123
+
7124
+ reduceRight: __arrayProto.reduceRight || function ( fn, init )
7125
+ {
7126
+ return _fnReduce( this, fn, init, this.length-1, -1, -1 );
7127
+ },
7128
+
7129
+
7130
+ reverse: __arrayProto.reverse,
7131
+
7132
+
7133
+ // Object with rows, columns and opts
7134
+ selector: null,
7135
+
7136
+
7137
+ shift: __arrayProto.shift,
7138
+
7139
+
7140
+ slice: function () {
7141
+ return new _Api( this.context, this );
7142
+ },
7143
+
7144
+
7145
+ sort: __arrayProto.sort, // ? name - order?
7146
+
7147
+
7148
+ splice: __arrayProto.splice,
7149
+
7150
+
7151
+ toArray: function ()
7152
+ {
7153
+ return __arrayProto.slice.call( this );
7154
+ },
7155
+
7156
+
7157
+ to$: function ()
7158
+ {
7159
+ return $( this );
7160
+ },
7161
+
7162
+
7163
+ toJQuery: function ()
7164
+ {
7165
+ return $( this );
7166
+ },
7167
+
7168
+
7169
+ unique: function ()
7170
+ {
7171
+ return new _Api( this.context, _unique(this) );
7172
+ },
7173
+
7174
+
7175
+ unshift: __arrayProto.unshift
7176
+ } );
7177
+
7178
+
7179
+ _Api.extend = function ( scope, obj, ext )
7180
+ {
7181
+ // Only extend API instances and static properties of the API
7182
+ if ( ! ext.length || ! obj || ( ! (obj instanceof _Api) && ! obj.__dt_wrapper ) ) {
7183
+ return;
7184
+ }
7185
+
7186
+ var
7187
+ i, ien,
7188
+ j, jen,
7189
+ struct, inner,
7190
+ methodScoping = function ( scope, fn, struc ) {
7191
+ return function () {
7192
+ var ret = fn.apply( scope, arguments );
7193
+
7194
+ // Method extension
7195
+ _Api.extend( ret, ret, struc.methodExt );
7196
+ return ret;
7197
+ };
7198
+ };
7199
+
7200
+ for ( i=0, ien=ext.length ; i<ien ; i++ ) {
7201
+ struct = ext[i];
7202
+
7203
+ // Value
7204
+ obj[ struct.name ] = typeof struct.val === 'function' ?
7205
+ methodScoping( scope, struct.val, struct ) :
7206
+ $.isPlainObject( struct.val ) ?
7207
+ {} :
7208
+ struct.val;
7209
+
7210
+ obj[ struct.name ].__dt_wrapper = true;
7211
+
7212
+ // Property extension
7213
+ _Api.extend( scope, obj[ struct.name ], struct.propExt );
7214
+ }
7215
+ };
7216
+
7217
+
7218
+ // @todo - Is there need for an augment function?
7219
+ // _Api.augment = function ( inst, name )
7220
+ // {
7221
+ // // Find src object in the structure from the name
7222
+ // var parts = name.split('.');
7223
+
7224
+ // _Api.extend( inst, obj );
7225
+ // };
7226
+
7227
+
7228
+ // [
7229
+ // {
7230
+ // name: 'data' -- string - Property name
7231
+ // val: function () {}, -- function - Api method (or undefined if just an object
7232
+ // methodExt: [ ... ], -- array - Array of Api object definitions to extend the method result
7233
+ // propExt: [ ... ] -- array - Array of Api object definitions to extend the property
7234
+ // },
7235
+ // {
7236
+ // name: 'row'
7237
+ // val: {},
7238
+ // methodExt: [ ... ],
7239
+ // propExt: [
7240
+ // {
7241
+ // name: 'data'
7242
+ // val: function () {},
7243
+ // methodExt: [ ... ],
7244
+ // propExt: [ ... ]
7245
+ // },
7246
+ // ...
7247
+ // ]
7248
+ // }
7249
+ // ]
7250
+
7251
+ _Api.register = _api_register = function ( name, val )
7252
+ {
7253
+ if ( $.isArray( name ) ) {
7254
+ for ( var j=0, jen=name.length ; j<jen ; j++ ) {
7255
+ _Api.register( name[j], val );
7256
+ }
7257
+ return;
7258
+ }
7259
+
7260
+ var
7261
+ i, ien,
7262
+ heir = name.split('.'),
7263
+ struct = __apiStruct,
7264
+ key, method;
7265
+
7266
+ var find = function ( src, name ) {
7267
+ for ( var i=0, ien=src.length ; i<ien ; i++ ) {
7268
+ if ( src[i].name === name ) {
7269
+ return src[i];
7270
+ }
7271
+ }
7272
+ return null;
7273
+ };
7274
+
7275
+ for ( i=0, ien=heir.length ; i<ien ; i++ ) {
7276
+ method = heir[i].indexOf('()') !== -1;
7277
+ key = method ?
7278
+ heir[i].replace('()', '') :
7279
+ heir[i];
7280
+
7281
+ var src = find( struct, key );
7282
+ if ( ! src ) {
7283
+ src = {
7284
+ name: key,
7285
+ val: {},
7286
+ methodExt: [],
7287
+ propExt: []
7288
+ };
7289
+ struct.push( src );
7290
+ }
7291
+
7292
+ if ( i === ien-1 ) {
7293
+ src.val = val;
7294
+ }
7295
+ else {
7296
+ struct = method ?
7297
+ src.methodExt :
7298
+ src.propExt;
7299
+ }
7300
+ }
7301
+ };
7302
+
7303
+
7304
+ _Api.registerPlural = _api_registerPlural = function ( pluralName, singularName, val ) {
7305
+ _Api.register( pluralName, val );
7306
+
7307
+ _Api.register( singularName, function () {
7308
+ var ret = val.apply( this, arguments );
7309
+
7310
+ if ( ret === this ) {
7311
+ // Returned item is the API instance that was passed in, return it
7312
+ return this;
7313
+ }
7314
+ else if ( ret instanceof _Api ) {
7315
+ // New API instance returned, want the value from the first item
7316
+ // in the returned array for the singular result.
7317
+ return ret.length ?
7318
+ $.isArray( ret[0] ) ?
7319
+ new _Api( ret.context, ret[0] ) : // Array results are 'enhanced'
7320
+ ret[0] :
7321
+ undefined;
7322
+ }
7323
+
7324
+ // Non-API return - just fire it back
7325
+ return ret;
7326
+ } );
7327
+ };
7328
+
7329
+
7330
+ /**
7331
+ * Selector for HTML tables. Apply the given selector to the give array of
7332
+ * DataTables settings objects.
7333
+ *
7334
+ * @param {string|integer} [selector] jQuery selector string or integer
7335
+ * @param {array} Array of DataTables settings objects to be filtered
7336
+ * @return {array}
7337
+ * @ignore
7338
+ */
7339
+ var __table_selector = function ( selector, a )
7340
+ {
7341
+ // Integer is used to pick out a table by index
7342
+ if ( typeof selector === 'number' ) {
7343
+ return [ a[ selector ] ];
7344
+ }
7345
+
7346
+ // Perform a jQuery selector on the table nodes
7347
+ var nodes = $.map( a, function (el, i) {
7348
+ return el.nTable;
7349
+ } );
7350
+
7351
+ return $(nodes)
7352
+ .filter( selector )
7353
+ .map( function (i) {
7354
+ // Need to translate back from the table node to the settings
7355
+ var idx = $.inArray( this, nodes );
7356
+ return a[ idx ];
7357
+ } )
7358
+ .toArray();
7359
+ };
7360
+
7361
+
7362
+
7363
+ /**
7364
+ * Context selector for the API's context (i.e. the tables the API instance
7365
+ * refers to.
7366
+ *
7367
+ * @name DataTable.Api#tables
7368
+ * @param {string|integer} [selector] Selector to pick which tables the iterator
7369
+ * should operate on. If not given, all tables in the current context are
7370
+ * used. This can be given as a jQuery selector (for example `':gt(0)'`) to
7371
+ * select multiple tables or as an integer to select a single table.
7372
+ * @returns {DataTable.Api} Returns a new API instance if a selector is given.
7373
+ */
7374
+ _api_register( 'tables()', function ( selector ) {
7375
+ // A new instance is created if there was a selector specified
7376
+ return selector ?
7377
+ new _Api( __table_selector( selector, this.context ) ) :
7378
+ this;
7379
+ } );
7380
+
7381
+
7382
+ _api_register( 'table()', function ( selector ) {
7383
+ var tables = this.tables( selector );
7384
+ var ctx = tables.context;
7385
+
7386
+ // Truncate to the first matched table
7387
+ return ctx.length ?
7388
+ new _Api( ctx[0] ) :
7389
+ tables;
7390
+ } );
7391
+
7392
+
7393
+ _api_registerPlural( 'tables().nodes()', 'table().node()' , function () {
7394
+ return this.iterator( 'table', function ( ctx ) {
7395
+ return ctx.nTable;
7396
+ }, 1 );
7397
+ } );
7398
+
7399
+
7400
+ _api_registerPlural( 'tables().body()', 'table().body()' , function () {
7401
+ return this.iterator( 'table', function ( ctx ) {
7402
+ return ctx.nTBody;
7403
+ }, 1 );
7404
+ } );
7405
+
7406
+
7407
+ _api_registerPlural( 'tables().header()', 'table().header()' , function () {
7408
+ return this.iterator( 'table', function ( ctx ) {
7409
+ return ctx.nTHead;
7410
+ }, 1 );
7411
+ } );
7412
+
7413
+
7414
+ _api_registerPlural( 'tables().footer()', 'table().footer()' , function () {
7415
+ return this.iterator( 'table', function ( ctx ) {
7416
+ return ctx.nTFoot;
7417
+ }, 1 );
7418
+ } );
7419
+
7420
+
7421
+ _api_registerPlural( 'tables().containers()', 'table().container()' , function () {
7422
+ return this.iterator( 'table', function ( ctx ) {
7423
+ return ctx.nTableWrapper;
7424
+ }, 1 );
7425
+ } );
7426
+
7427
+
7428
+
7429
+ /**
7430
+ * Redraw the tables in the current context.
7431
+ */
7432
+ _api_register( 'draw()', function ( paging ) {
7433
+ return this.iterator( 'table', function ( settings ) {
7434
+ if ( paging === 'page' ) {
7435
+ _fnDraw( settings );
7436
+ }
7437
+ else {
7438
+ if ( typeof paging === 'string' ) {
7439
+ paging = paging === 'full-hold' ?
7440
+ false :
7441
+ true;
7442
+ }
7443
+
7444
+ _fnReDraw( settings, paging===false );
7445
+ }
7446
+ } );
7447
+ } );
7448
+
7449
+
7450
+
7451
+ /**
7452
+ * Get the current page index.
7453
+ *
7454
+ * @return {integer} Current page index (zero based)
7455
+ *//**
7456
+ * Set the current page.
7457
+ *
7458
+ * Note that if you attempt to show a page which does not exist, DataTables will
7459
+ * not throw an error, but rather reset the paging.
7460
+ *
7461
+ * @param {integer|string} action The paging action to take. This can be one of:
7462
+ * * `integer` - The page index to jump to
7463
+ * * `string` - An action to take:
7464
+ * * `first` - Jump to first page.
7465
+ * * `next` - Jump to the next page
7466
+ * * `previous` - Jump to previous page
7467
+ * * `last` - Jump to the last page.
7468
+ * @returns {DataTables.Api} this
7469
+ */
7470
+ _api_register( 'page()', function ( action ) {
7471
+ if ( action === undefined ) {
7472
+ return this.page.info().page; // not an expensive call
7473
+ }
7474
+
7475
+ // else, have an action to take on all tables
7476
+ return this.iterator( 'table', function ( settings ) {
7477
+ _fnPageChange( settings, action );
7478
+ } );
7479
+ } );
7480
+
7481
+
7482
+ /**
7483
+ * Paging information for the first table in the current context.
7484
+ *
7485
+ * If you require paging information for another table, use the `table()` method
7486
+ * with a suitable selector.
7487
+ *
7488
+ * @return {object} Object with the following properties set:
7489
+ * * `page` - Current page index (zero based - i.e. the first page is `0`)
7490
+ * * `pages` - Total number of pages
7491
+ * * `start` - Display index for the first record shown on the current page
7492
+ * * `end` - Display index for the last record shown on the current page
7493
+ * * `length` - Display length (number of records). Note that generally `start
7494
+ * + length = end`, but this is not always true, for example if there are
7495
+ * only 2 records to show on the final page, with a length of 10.
7496
+ * * `recordsTotal` - Full data set length
7497
+ * * `recordsDisplay` - Data set length once the current filtering criterion
7498
+ * are applied.
7499
+ */
7500
+ _api_register( 'page.info()', function ( action ) {
7501
+ if ( this.context.length === 0 ) {
7502
+ return undefined;
7503
+ }
7504
+
7505
+ var
7506
+ settings = this.context[0],
7507
+ start = settings._iDisplayStart,
7508
+ len = settings.oFeatures.bPaginate ? settings._iDisplayLength : -1,
7509
+ visRecords = settings.fnRecordsDisplay(),
7510
+ all = len === -1;
7511
+
7512
+ return {
7513
+ "page": all ? 0 : Math.floor( start / len ),
7514
+ "pages": all ? 1 : Math.ceil( visRecords / len ),
7515
+ "start": start,
7516
+ "end": settings.fnDisplayEnd(),
7517
+ "length": len,
7518
+ "recordsTotal": settings.fnRecordsTotal(),
7519
+ "recordsDisplay": visRecords,
7520
+ "serverSide": _fnDataSource( settings ) === 'ssp'
7521
+ };
7522
+ } );
7523
+
7524
+
7525
+ /**
7526
+ * Get the current page length.
7527
+ *
7528
+ * @return {integer} Current page length. Note `-1` indicates that all records
7529
+ * are to be shown.
7530
+ *//**
7531
+ * Set the current page length.
7532
+ *
7533
+ * @param {integer} Page length to set. Use `-1` to show all records.
7534
+ * @returns {DataTables.Api} this
7535
+ */
7536
+ _api_register( 'page.len()', function ( len ) {
7537
+ // Note that we can't call this function 'length()' because `length`
7538
+ // is a Javascript property of functions which defines how many arguments
7539
+ // the function expects.
7540
+ if ( len === undefined ) {
7541
+ return this.context.length !== 0 ?
7542
+ this.context[0]._iDisplayLength :
7543
+ undefined;
7544
+ }
7545
+
7546
+ // else, set the page length
7547
+ return this.iterator( 'table', function ( settings ) {
7548
+ _fnLengthChange( settings, len );
7549
+ } );
7550
+ } );
7551
+
7552
+
7553
+
7554
+ var __reload = function ( settings, holdPosition, callback ) {
7555
+ // Use the draw event to trigger a callback
7556
+ if ( callback ) {
7557
+ var api = new _Api( settings );
7558
+
7559
+ api.one( 'draw', function () {
7560
+ callback( api.ajax.json() );
7561
+ } );
7562
+ }
7563
+
7564
+ if ( _fnDataSource( settings ) == 'ssp' ) {
7565
+ _fnReDraw( settings, holdPosition );
7566
+ }
7567
+ else {
7568
+ _fnProcessingDisplay( settings, true );
7569
+
7570
+ // Cancel an existing request
7571
+ var xhr = settings.jqXHR;
7572
+ if ( xhr && xhr.readyState !== 4 ) {
7573
+ xhr.abort();
7574
+ }
7575
+
7576
+ // Trigger xhr
7577
+ _fnBuildAjax( settings, [], function( json ) {
7578
+ _fnClearTable( settings );
7579
+
7580
+ var data = _fnAjaxDataSrc( settings, json );
7581
+ for ( var i=0, ien=data.length ; i<ien ; i++ ) {
7582
+ _fnAddData( settings, data[i] );
7583
+ }
7584
+
7585
+ _fnReDraw( settings, holdPosition );
7586
+ _fnProcessingDisplay( settings, false );
7587
+ } );
7588
+ }
7589
+ };
7590
+
7591
+
7592
+ /**
7593
+ * Get the JSON response from the last Ajax request that DataTables made to the
7594
+ * server. Note that this returns the JSON from the first table in the current
7595
+ * context.
7596
+ *
7597
+ * @return {object} JSON received from the server.
7598
+ */
7599
+ _api_register( 'ajax.json()', function () {
7600
+ var ctx = this.context;
7601
+
7602
+ if ( ctx.length > 0 ) {
7603
+ return ctx[0].json;
7604
+ }
7605
+
7606
+ // else return undefined;
7607
+ } );
7608
+
7609
+
7610
+ /**
7611
+ * Get the data submitted in the last Ajax request
7612
+ */
7613
+ _api_register( 'ajax.params()', function () {
7614
+ var ctx = this.context;
7615
+
7616
+ if ( ctx.length > 0 ) {
7617
+ return ctx[0].oAjaxData;
7618
+ }
7619
+
7620
+ // else return undefined;
7621
+ } );
7622
+
7623
+
7624
+ /**
7625
+ * Reload tables from the Ajax data source. Note that this function will
7626
+ * automatically re-draw the table when the remote data has been loaded.
7627
+ *
7628
+ * @param {boolean} [reset=true] Reset (default) or hold the current paging
7629
+ * position. A full re-sort and re-filter is performed when this method is
7630
+ * called, which is why the pagination reset is the default action.
7631
+ * @returns {DataTables.Api} this
7632
+ */
7633
+ _api_register( 'ajax.reload()', function ( callback, resetPaging ) {
7634
+ return this.iterator( 'table', function (settings) {
7635
+ __reload( settings, resetPaging===false, callback );
7636
+ } );
7637
+ } );
7638
+
7639
+
7640
+ /**
7641
+ * Get the current Ajax URL. Note that this returns the URL from the first
7642
+ * table in the current context.
7643
+ *
7644
+ * @return {string} Current Ajax source URL
7645
+ *//**
7646
+ * Set the Ajax URL. Note that this will set the URL for all tables in the
7647
+ * current context.
7648
+ *
7649
+ * @param {string} url URL to set.
7650
+ * @returns {DataTables.Api} this
7651
+ */
7652
+ _api_register( 'ajax.url()', function ( url ) {
7653
+ var ctx = this.context;
7654
+
7655
+ if ( url === undefined ) {
7656
+ // get
7657
+ if ( ctx.length === 0 ) {
7658
+ return undefined;
7659
+ }
7660
+ ctx = ctx[0];
7661
+
7662
+ return ctx.ajax ?
7663
+ $.isPlainObject( ctx.ajax ) ?
7664
+ ctx.ajax.url :
7665
+ ctx.ajax :
7666
+ ctx.sAjaxSource;
7667
+ }
7668
+
7669
+ // set
7670
+ return this.iterator( 'table', function ( settings ) {
7671
+ if ( $.isPlainObject( settings.ajax ) ) {
7672
+ settings.ajax.url = url;
7673
+ }
7674
+ else {
7675
+ settings.ajax = url;
7676
+ }
7677
+ // No need to consider sAjaxSource here since DataTables gives priority
7678
+ // to `ajax` over `sAjaxSource`. So setting `ajax` here, renders any
7679
+ // value of `sAjaxSource` redundant.
7680
+ } );
7681
+ } );
7682
+
7683
+
7684
+ /**
7685
+ * Load data from the newly set Ajax URL. Note that this method is only
7686
+ * available when `ajax.url()` is used to set a URL. Additionally, this method
7687
+ * has the same effect as calling `ajax.reload()` but is provided for
7688
+ * convenience when setting a new URL. Like `ajax.reload()` it will
7689
+ * automatically redraw the table once the remote data has been loaded.
7690
+ *
7691
+ * @returns {DataTables.Api} this
7692
+ */
7693
+ _api_register( 'ajax.url().load()', function ( callback, resetPaging ) {
7694
+ // Same as a reload, but makes sense to present it for easy access after a
7695
+ // url change
7696
+ return this.iterator( 'table', function ( ctx ) {
7697
+ __reload( ctx, resetPaging===false, callback );
7698
+ } );
7699
+ } );
7700
+
7701
+
7702
+
7703
+
7704
+ var _selector_run = function ( type, selector, selectFn, settings, opts )
7705
+ {
7706
+ var
7707
+ out = [], res,
7708
+ a, i, ien, j, jen,
7709
+ selectorType = typeof selector;
7710
+
7711
+ // Can't just check for isArray here, as an API or jQuery instance might be
7712
+ // given with their array like look
7713
+ if ( ! selector || selectorType === 'string' || selectorType === 'function' || selector.length === undefined ) {
7714
+ selector = [ selector ];
7715
+ }
7716
+
7717
+ for ( i=0, ien=selector.length ; i<ien ; i++ ) {
7718
+ // Only split on simple strings - complex expressions will be jQuery selectors
7719
+ a = selector[i] && selector[i].split && ! selector[i].match(/[\[\(:]/) ?
7720
+ selector[i].split(',') :
7721
+ [ selector[i] ];
7722
+
7723
+ for ( j=0, jen=a.length ; j<jen ; j++ ) {
7724
+ res = selectFn( typeof a[j] === 'string' ? $.trim(a[j]) : a[j] );
7725
+
7726
+ if ( res && res.length ) {
7727
+ out = out.concat( res );
7728
+ }
7729
+ }
7730
+ }
7731
+
7732
+ // selector extensions
7733
+ var ext = _ext.selector[ type ];
7734
+ if ( ext.length ) {
7735
+ for ( i=0, ien=ext.length ; i<ien ; i++ ) {
7736
+ out = ext[i]( settings, opts, out );
7737
+ }
7738
+ }
7739
+
7740
+ return _unique( out );
7741
+ };
7742
+
7743
+
7744
+ var _selector_opts = function ( opts )
7745
+ {
7746
+ if ( ! opts ) {
7747
+ opts = {};
7748
+ }
7749
+
7750
+ // Backwards compatibility for 1.9- which used the terminology filter rather
7751
+ // than search
7752
+ if ( opts.filter && opts.search === undefined ) {
7753
+ opts.search = opts.filter;
7754
+ }
7755
+
7756
+ return $.extend( {
7757
+ search: 'none',
7758
+ order: 'current',
7759
+ page: 'all'
7760
+ }, opts );
7761
+ };
7762
+
7763
+
7764
+ var _selector_first = function ( inst )
7765
+ {
7766
+ // Reduce the API instance to the first item found
7767
+ for ( var i=0, ien=inst.length ; i<ien ; i++ ) {
7768
+ if ( inst[i].length > 0 ) {
7769
+ // Assign the first element to the first item in the instance
7770
+ // and truncate the instance and context
7771
+ inst[0] = inst[i];
7772
+ inst[0].length = 1;
7773
+ inst.length = 1;
7774
+ inst.context = [ inst.context[i] ];
7775
+
7776
+ return inst;
7777
+ }
7778
+ }
7779
+
7780
+ // Not found - return an empty instance
7781
+ inst.length = 0;
7782
+ return inst;
7783
+ };
7784
+
7785
+
7786
+ var _selector_row_indexes = function ( settings, opts )
7787
+ {
7788
+ var
7789
+ i, ien, tmp, a=[],
7790
+ displayFiltered = settings.aiDisplay,
7791
+ displayMaster = settings.aiDisplayMaster;
7792
+
7793
+ var
7794
+ search = opts.search, // none, applied, removed
7795
+ order = opts.order, // applied, current, index (original - compatibility with 1.9)
7796
+ page = opts.page; // all, current
7797
+
7798
+ if ( _fnDataSource( settings ) == 'ssp' ) {
7799
+ // In server-side processing mode, most options are irrelevant since
7800
+ // rows not shown don't exist and the index order is the applied order
7801
+ // Removed is a special case - for consistency just return an empty
7802
+ // array
7803
+ return search === 'removed' ?
7804
+ [] :
7805
+ _range( 0, displayMaster.length );
7806
+ }
7807
+ else if ( page == 'current' ) {
7808
+ // Current page implies that order=current and fitler=applied, since it is
7809
+ // fairly senseless otherwise, regardless of what order and search actually
7810
+ // are
7811
+ for ( i=settings._iDisplayStart, ien=settings.fnDisplayEnd() ; i<ien ; i++ ) {
7812
+ a.push( displayFiltered[i] );
7813
+ }
7814
+ }
7815
+ else if ( order == 'current' || order == 'applied' ) {
7816
+ a = search == 'none' ?
7817
+ displayMaster.slice() : // no search
7818
+ search == 'applied' ?
7819
+ displayFiltered.slice() : // applied search
7820
+ $.map( displayMaster, function (el, i) { // removed search
7821
+ return $.inArray( el, displayFiltered ) === -1 ? el : null;
7822
+ } );
7823
+ }
7824
+ else if ( order == 'index' || order == 'original' ) {
7825
+ for ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
7826
+ if ( search == 'none' ) {
7827
+ a.push( i );
7828
+ }
7829
+ else { // applied | removed
7830
+ tmp = $.inArray( i, displayFiltered );
7831
+
7832
+ if ((tmp === -1 && search == 'removed') ||
7833
+ (tmp >= 0 && search == 'applied') )
7834
+ {
7835
+ a.push( i );
7836
+ }
7837
+ }
7838
+ }
7839
+ }
7840
+
7841
+ return a;
7842
+ };
7843
+
7844
+
7845
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
7846
+ * Rows
7847
+ *
7848
+ * {} - no selector - use all available rows
7849
+ * {integer} - row aoData index
7850
+ * {node} - TR node
7851
+ * {string} - jQuery selector to apply to the TR elements
7852
+ * {array} - jQuery array of nodes, or simply an array of TR nodes
7853
+ *
7854
+ */
7855
+
7856
+
7857
+ var __row_selector = function ( settings, selector, opts )
7858
+ {
7859
+ var rows;
7860
+ var run = function ( sel ) {
7861
+ var selInt = _intVal( sel );
7862
+ var i, ien;
7863
+
7864
+ // Short cut - selector is a number and no options provided (default is
7865
+ // all records, so no need to check if the index is in there, since it
7866
+ // must be - dev error if the index doesn't exist).
7867
+ if ( selInt !== null && ! opts ) {
7868
+ return [ selInt ];
7869
+ }
7870
+
7871
+ if ( ! rows ) {
7872
+ rows = _selector_row_indexes( settings, opts );
7873
+ }
7874
+
7875
+ if ( selInt !== null && $.inArray( selInt, rows ) !== -1 ) {
7876
+ // Selector - integer
7877
+ return [ selInt ];
7878
+ }
7879
+ else if ( sel === null || sel === undefined || sel === '' ) {
7880
+ // Selector - none
7881
+ return rows;
7882
+ }
7883
+
7884
+ // Selector - function
7885
+ if ( typeof sel === 'function' ) {
7886
+ return $.map( rows, function (idx) {
7887
+ var row = settings.aoData[ idx ];
7888
+ return sel( idx, row._aData, row.nTr ) ? idx : null;
7889
+ } );
7890
+ }
7891
+
7892
+ // Get nodes in the order from the `rows` array with null values removed
7893
+ var nodes = _removeEmpty(
7894
+ _pluck_order( settings.aoData, rows, 'nTr' )
7895
+ );
7896
+
7897
+ // Selector - node
7898
+ if ( sel.nodeName ) {
7899
+ if ( sel._DT_RowIndex !== undefined ) {
7900
+ return [ sel._DT_RowIndex ]; // Property added by DT for fast lookup
7901
+ }
7902
+ else if ( sel._DT_CellIndex ) {
7903
+ return [ sel._DT_CellIndex.row ];
7904
+ }
7905
+ else {
7906
+ var host = $(sel).closest('*[data-dt-row]');
7907
+ return host.length ?
7908
+ [ host.data('dt-row') ] :
7909
+ [];
7910
+ }
7911
+ }
7912
+
7913
+ // ID selector. Want to always be able to select rows by id, regardless
7914
+ // of if the tr element has been created or not, so can't rely upon
7915
+ // jQuery here - hence a custom implementation. This does not match
7916
+ // Sizzle's fast selector or HTML4 - in HTML5 the ID can be anything,
7917
+ // but to select it using a CSS selector engine (like Sizzle or
7918
+ // querySelect) it would need to need to be escaped for some characters.
7919
+ // DataTables simplifies this for row selectors since you can select
7920
+ // only a row. A # indicates an id any anything that follows is the id -
7921
+ // unescaped.
7922
+ if ( typeof sel === 'string' && sel.charAt(0) === '#' ) {
7923
+ // get row index from id
7924
+ var rowObj = settings.aIds[ sel.replace( /^#/, '' ) ];
7925
+ if ( rowObj !== undefined ) {
7926
+ return [ rowObj.idx ];
7927
+ }
7928
+
7929
+ // need to fall through to jQuery in case there is DOM id that
7930
+ // matches
7931
+ }
7932
+
7933
+ // Selector - jQuery selector string, array of nodes or jQuery object/
7934
+ // As jQuery's .filter() allows jQuery objects to be passed in filter,
7935
+ // it also allows arrays, so this will cope with all three options
7936
+ return $(nodes)
7937
+ .filter( sel )
7938
+ .map( function () {
7939
+ return this._DT_RowIndex;
7940
+ } )
7941
+ .toArray();
7942
+ };
7943
+
7944
+ return _selector_run( 'row', selector, run, settings, opts );
7945
+ };
7946
+
7947
+
7948
+ _api_register( 'rows()', function ( selector, opts ) {
7949
+ // argument shifting
7950
+ if ( selector === undefined ) {
7951
+ selector = '';
7952
+ }
7953
+ else if ( $.isPlainObject( selector ) ) {
7954
+ opts = selector;
7955
+ selector = '';
7956
+ }
7957
+
7958
+ opts = _selector_opts( opts );
7959
+
7960
+ var inst = this.iterator( 'table', function ( settings ) {
7961
+ return __row_selector( settings, selector, opts );
7962
+ }, 1 );
7963
+
7964
+ // Want argument shifting here and in __row_selector?
7965
+ inst.selector.rows = selector;
7966
+ inst.selector.opts = opts;
7967
+
7968
+ return inst;
7969
+ } );
7970
+
7971
+ _api_register( 'rows().nodes()', function () {
7972
+ return this.iterator( 'row', function ( settings, row ) {
7973
+ return settings.aoData[ row ].nTr || undefined;
7974
+ }, 1 );
7975
+ } );
7976
+
7977
+ _api_register( 'rows().data()', function () {
7978
+ return this.iterator( true, 'rows', function ( settings, rows ) {
7979
+ return _pluck_order( settings.aoData, rows, '_aData' );
7980
+ }, 1 );
7981
+ } );
7982
+
7983
+ _api_registerPlural( 'rows().cache()', 'row().cache()', function ( type ) {
7984
+ return this.iterator( 'row', function ( settings, row ) {
7985
+ var r = settings.aoData[ row ];
7986
+ return type === 'search' ? r._aFilterData : r._aSortData;
7987
+ }, 1 );
7988
+ } );
7989
+
7990
+ _api_registerPlural( 'rows().invalidate()', 'row().invalidate()', function ( src ) {
7991
+ return this.iterator( 'row', function ( settings, row ) {
7992
+ _fnInvalidate( settings, row, src );
7993
+ } );
7994
+ } );
7995
+
7996
+ _api_registerPlural( 'rows().indexes()', 'row().index()', function () {
7997
+ return this.iterator( 'row', function ( settings, row ) {
7998
+ return row;
7999
+ }, 1 );
8000
+ } );
8001
+
8002
+ _api_registerPlural( 'rows().ids()', 'row().id()', function ( hash ) {
8003
+ var a = [];
8004
+ var context = this.context;
8005
+
8006
+ // `iterator` will drop undefined values, but in this case we want them
8007
+ for ( var i=0, ien=context.length ; i<ien ; i++ ) {
8008
+ for ( var j=0, jen=this[i].length ; j<jen ; j++ ) {
8009
+ var id = context[i].rowIdFn( context[i].aoData[ this[i][j] ]._aData );
8010
+ a.push( (hash === true ? '#' : '' )+ id );
8011
+ }
8012
+ }
8013
+
8014
+ return new _Api( context, a );
8015
+ } );
8016
+
8017
+ _api_registerPlural( 'rows().remove()', 'row().remove()', function () {
8018
+ var that = this;
8019
+
8020
+ this.iterator( 'row', function ( settings, row, thatIdx ) {
8021
+ var data = settings.aoData;
8022
+ var rowData = data[ row ];
8023
+ var i, ien, j, jen;
8024
+ var loopRow, loopCells;
8025
+
8026
+ data.splice( row, 1 );
8027
+
8028
+ // Update the cached indexes
8029
+ for ( i=0, ien=data.length ; i<ien ; i++ ) {
8030
+ loopRow = data[i];
8031
+ loopCells = loopRow.anCells;
8032
+
8033
+ // Rows
8034
+ if ( loopRow.nTr !== null ) {
8035
+ loopRow.nTr._DT_RowIndex = i;
8036
+ }
8037
+
8038
+ // Cells
8039
+ if ( loopCells !== null ) {
8040
+ for ( j=0, jen=loopCells.length ; j<jen ; j++ ) {
8041
+ loopCells[j]._DT_CellIndex.row = i;
8042
+ }
8043
+ }
8044
+ }
8045
+
8046
+ // Delete from the display arrays
8047
+ _fnDeleteIndex( settings.aiDisplayMaster, row );
8048
+ _fnDeleteIndex( settings.aiDisplay, row );
8049
+ _fnDeleteIndex( that[ thatIdx ], row, false ); // maintain local indexes
8050
+
8051
+ // For server-side processing tables - subtract the deleted row from the count
8052
+ if ( settings._iRecordsDisplay > 0 ) {
8053
+ settings._iRecordsDisplay--;
8054
+ }
8055
+
8056
+ // Check for an 'overflow' they case for displaying the table
8057
+ _fnLengthOverflow( settings );
8058
+
8059
+ // Remove the row's ID reference if there is one
8060
+ var id = settings.rowIdFn( rowData._aData );
8061
+ if ( id !== undefined ) {
8062
+ delete settings.aIds[ id ];
8063
+ }
8064
+ } );
8065
+
8066
+ this.iterator( 'table', function ( settings ) {
8067
+ for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
8068
+ settings.aoData[i].idx = i;
8069
+ }
8070
+ } );
8071
+
8072
+ return this;
8073
+ } );
8074
+
8075
+
8076
+ _api_register( 'rows.add()', function ( rows ) {
8077
+ var newRows = this.iterator( 'table', function ( settings ) {
8078
+ var row, i, ien;
8079
+ var out = [];
8080
+
8081
+ for ( i=0, ien=rows.length ; i<ien ; i++ ) {
8082
+ row = rows[i];
8083
+
8084
+ if ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) {
8085
+ out.push( _fnAddTr( settings, row )[0] );
8086
+ }
8087
+ else {
8088
+ out.push( _fnAddData( settings, row ) );
8089
+ }
8090
+ }
8091
+
8092
+ return out;
8093
+ }, 1 );
8094
+
8095
+ // Return an Api.rows() extended instance, so rows().nodes() etc can be used
8096
+ var modRows = this.rows( -1 );
8097
+ modRows.pop();
8098
+ $.merge( modRows, newRows );
8099
+
8100
+ return modRows;
8101
+ } );
8102
+
8103
+
8104
+
8105
+
8106
+
8107
+ /**
8108
+ *
8109
+ */
8110
+ _api_register( 'row()', function ( selector, opts ) {
8111
+ return _selector_first( this.rows( selector, opts ) );
8112
+ } );
8113
+
8114
+
8115
+ _api_register( 'row().data()', function ( data ) {
8116
+ var ctx = this.context;
8117
+
8118
+ if ( data === undefined ) {
8119
+ // Get
8120
+ return ctx.length && this.length ?
8121
+ ctx[0].aoData[ this[0] ]._aData :
8122
+ undefined;
8123
+ }
8124
+
8125
+ // Set
8126
+ ctx[0].aoData[ this[0] ]._aData = data;
8127
+
8128
+ // Automatically invalidate
8129
+ _fnInvalidate( ctx[0], this[0], 'data' );
8130
+
8131
+ return this;
8132
+ } );
8133
+
8134
+
8135
+ _api_register( 'row().node()', function () {
8136
+ var ctx = this.context;
8137
+
8138
+ return ctx.length && this.length ?
8139
+ ctx[0].aoData[ this[0] ].nTr || null :
8140
+ null;
8141
+ } );
8142
+
8143
+
8144
+ _api_register( 'row.add()', function ( row ) {
8145
+ // Allow a jQuery object to be passed in - only a single row is added from
8146
+ // it though - the first element in the set
8147
+ if ( row instanceof $ && row.length ) {
8148
+ row = row[0];
8149
+ }
8150
+
8151
+ var rows = this.iterator( 'table', function ( settings ) {
8152
+ if ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) {
8153
+ return _fnAddTr( settings, row )[0];
8154
+ }
8155
+ return _fnAddData( settings, row );
8156
+ } );
8157
+
8158
+ // Return an Api.rows() extended instance, with the newly added row selected
8159
+ return this.row( rows[0] );
8160
+ } );
8161
+
8162
+
8163
+
8164
+ var __details_add = function ( ctx, row, data, klass )
8165
+ {
8166
+ // Convert to array of TR elements
8167
+ var rows = [];
8168
+ var addRow = function ( r, k ) {
8169
+ // Recursion to allow for arrays of jQuery objects
8170
+ if ( $.isArray( r ) || r instanceof $ ) {
8171
+ for ( var i=0, ien=r.length ; i<ien ; i++ ) {
8172
+ addRow( r[i], k );
8173
+ }
8174
+ return;
8175
+ }
8176
+
8177
+ // If we get a TR element, then just add it directly - up to the dev
8178
+ // to add the correct number of columns etc
8179
+ if ( r.nodeName && r.nodeName.toLowerCase() === 'tr' ) {
8180
+ rows.push( r );
8181
+ }
8182
+ else {
8183
+ // Otherwise create a row with a wrapper
8184
+ var created = $('<tr><td/></tr>').addClass( k );
8185
+ $('td', created)
8186
+ .addClass( k )
8187
+ .html( r )
8188
+ [0].colSpan = _fnVisbleColumns( ctx );
8189
+
8190
+ rows.push( created[0] );
8191
+ }
8192
+ };
8193
+
8194
+ addRow( data, klass );
8195
+
8196
+ if ( row._details ) {
8197
+ row._details.detach();
8198
+ }
8199
+
8200
+ row._details = $(rows);
8201
+
8202
+ // If the children were already shown, that state should be retained
8203
+ if ( row._detailsShow ) {
8204
+ row._details.insertAfter( row.nTr );
8205
+ }
8206
+ };
8207
+
8208
+
8209
+ var __details_remove = function ( api, idx )
8210
+ {
8211
+ var ctx = api.context;
8212
+
8213
+ if ( ctx.length ) {
8214
+ var row = ctx[0].aoData[ idx !== undefined ? idx : api[0] ];
8215
+
8216
+ if ( row && row._details ) {
8217
+ row._details.remove();
8218
+
8219
+ row._detailsShow = undefined;
8220
+ row._details = undefined;
8221
+ }
8222
+ }
8223
+ };
8224
+
8225
+
8226
+ var __details_display = function ( api, show ) {
8227
+ var ctx = api.context;
8228
+
8229
+ if ( ctx.length && api.length ) {
8230
+ var row = ctx[0].aoData[ api[0] ];
8231
+
8232
+ if ( row._details ) {
8233
+ row._detailsShow = show;
8234
+
8235
+ if ( show ) {
8236
+ row._details.insertAfter( row.nTr );
8237
+ }
8238
+ else {
8239
+ row._details.detach();
8240
+ }
8241
+
8242
+ __details_events( ctx[0] );
8243
+ }
8244
+ }
8245
+ };
8246
+
8247
+
8248
+ var __details_events = function ( settings )
8249
+ {
8250
+ var api = new _Api( settings );
8251
+ var namespace = '.dt.DT_details';
8252
+ var drawEvent = 'draw'+namespace;
8253
+ var colvisEvent = 'column-visibility'+namespace;
8254
+ var destroyEvent = 'destroy'+namespace;
8255
+ var data = settings.aoData;
8256
+
8257
+ api.off( drawEvent +' '+ colvisEvent +' '+ destroyEvent );
8258
+
8259
+ if ( _pluck( data, '_details' ).length > 0 ) {
8260
+ // On each draw, insert the required elements into the document
8261
+ api.on( drawEvent, function ( e, ctx ) {
8262
+ if ( settings !== ctx ) {
8263
+ return;
8264
+ }
8265
+
8266
+ api.rows( {page:'current'} ).eq(0).each( function (idx) {
8267
+ // Internal data grab
8268
+ var row = data[ idx ];
8269
+
8270
+ if ( row._detailsShow ) {
8271
+ row._details.insertAfter( row.nTr );
8272
+ }
8273
+ } );
8274
+ } );
8275
+
8276
+ // Column visibility change - update the colspan
8277
+ api.on( colvisEvent, function ( e, ctx, idx, vis ) {
8278
+ if ( settings !== ctx ) {
8279
+ return;
8280
+ }
8281
+
8282
+ // Update the colspan for the details rows (note, only if it already has
8283
+ // a colspan)
8284
+ var row, visible = _fnVisbleColumns( ctx );
8285
+
8286
+ for ( var i=0, ien=data.length ; i<ien ; i++ ) {
8287
+ row = data[i];
8288
+
8289
+ if ( row._details ) {
8290
+ row._details.children('td[colspan]').attr('colspan', visible );
8291
+ }
8292
+ }
8293
+ } );
8294
+
8295
+ // Table destroyed - nuke any child rows
8296
+ api.on( destroyEvent, function ( e, ctx ) {
8297
+ if ( settings !== ctx ) {
8298
+ return;
8299
+ }
8300
+
8301
+ for ( var i=0, ien=data.length ; i<ien ; i++ ) {
8302
+ if ( data[i]._details ) {
8303
+ __details_remove( api, i );
8304
+ }
8305
+ }
8306
+ } );
8307
+ }
8308
+ };
8309
+
8310
+ // Strings for the method names to help minification
8311
+ var _emp = '';
8312
+ var _child_obj = _emp+'row().child';
8313
+ var _child_mth = _child_obj+'()';
8314
+
8315
+ // data can be:
8316
+ // tr
8317
+ // string
8318
+ // jQuery or array of any of the above
8319
+ _api_register( _child_mth, function ( data, klass ) {
8320
+ var ctx = this.context;
8321
+
8322
+ if ( data === undefined ) {
8323
+ // get
8324
+ return ctx.length && this.length ?
8325
+ ctx[0].aoData[ this[0] ]._details :
8326
+ undefined;
8327
+ }
8328
+ else if ( data === true ) {
8329
+ // show
8330
+ this.child.show();
8331
+ }
8332
+ else if ( data === false ) {
8333
+ // remove
8334
+ __details_remove( this );
8335
+ }
8336
+ else if ( ctx.length && this.length ) {
8337
+ // set
8338
+ __details_add( ctx[0], ctx[0].aoData[ this[0] ], data, klass );
8339
+ }
8340
+
8341
+ return this;
8342
+ } );
8343
+
8344
+
8345
+ _api_register( [
8346
+ _child_obj+'.show()',
8347
+ _child_mth+'.show()' // only when `child()` was called with parameters (without
8348
+ ], function ( show ) { // it returns an object and this method is not executed)
8349
+ __details_display( this, true );
8350
+ return this;
8351
+ } );
8352
+
8353
+
8354
+ _api_register( [
8355
+ _child_obj+'.hide()',
8356
+ _child_mth+'.hide()' // only when `child()` was called with parameters (without
8357
+ ], function () { // it returns an object and this method is not executed)
8358
+ __details_display( this, false );
8359
+ return this;
8360
+ } );
8361
+
8362
+
8363
+ _api_register( [
8364
+ _child_obj+'.remove()',
8365
+ _child_mth+'.remove()' // only when `child()` was called with parameters (without
8366
+ ], function () { // it returns an object and this method is not executed)
8367
+ __details_remove( this );
8368
+ return this;
8369
+ } );
8370
+
8371
+
8372
+ _api_register( _child_obj+'.isShown()', function () {
8373
+ var ctx = this.context;
8374
+
8375
+ if ( ctx.length && this.length ) {
8376
+ // _detailsShown as false or undefined will fall through to return false
8377
+ return ctx[0].aoData[ this[0] ]._detailsShow || false;
8378
+ }
8379
+ return false;
8380
+ } );
8381
+
8382
+
8383
+
8384
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
8385
+ * Columns
8386
+ *
8387
+ * {integer} - column index (>=0 count from left, <0 count from right)
8388
+ * "{integer}:visIdx" - visible column index (i.e. translate to column index) (>=0 count from left, <0 count from right)
8389
+ * "{integer}:visible" - alias for {integer}:visIdx (>=0 count from left, <0 count from right)
8390
+ * "{string}:name" - column name
8391
+ * "{string}" - jQuery selector on column header nodes
8392
+ *
8393
+ */
8394
+
8395
+ // can be an array of these items, comma separated list, or an array of comma
8396
+ // separated lists
8397
+
8398
+ var __re_column_selector = /^([^:]+):(name|visIdx|visible)$/;
8399
+
8400
+
8401
+ // r1 and r2 are redundant - but it means that the parameters match for the
8402
+ // iterator callback in columns().data()
8403
+ var __columnData = function ( settings, column, r1, r2, rows ) {
8404
+ var a = [];
8405
+ for ( var row=0, ien=rows.length ; row<ien ; row++ ) {
8406
+ a.push( _fnGetCellData( settings, rows[row], column ) );
8407
+ }
8408
+ return a;
8409
+ };
8410
+
8411
+
8412
+ var __column_selector = function ( settings, selector, opts )
8413
+ {
8414
+ var
8415
+ columns = settings.aoColumns,
8416
+ names = _pluck( columns, 'sName' ),
8417
+ nodes = _pluck( columns, 'nTh' );
8418
+
8419
+ var run = function ( s ) {
8420
+ var selInt = _intVal( s );
8421
+
8422
+ // Selector - all
8423
+ if ( s === '' ) {
8424
+ return _range( columns.length );
8425
+ }
8426
+
8427
+ // Selector - index
8428
+ if ( selInt !== null ) {
8429
+ return [ selInt >= 0 ?
8430
+ selInt : // Count from left
8431
+ columns.length + selInt // Count from right (+ because its a negative value)
8432
+ ];
8433
+ }
8434
+
8435
+ // Selector = function
8436
+ if ( typeof s === 'function' ) {
8437
+ var rows = _selector_row_indexes( settings, opts );
8438
+
8439
+ return $.map( columns, function (col, idx) {
8440
+ return s(
8441
+ idx,
8442
+ __columnData( settings, idx, 0, 0, rows ),
8443
+ nodes[ idx ]
8444
+ ) ? idx : null;
8445
+ } );
8446
+ }
8447
+
8448
+ // jQuery or string selector
8449
+ var match = typeof s === 'string' ?
8450
+ s.match( __re_column_selector ) :
8451
+ '';
8452
+
8453
+ if ( match ) {
8454
+ switch( match[2] ) {
8455
+ case 'visIdx':
8456
+ case 'visible':
8457
+ var idx = parseInt( match[1], 10 );
8458
+ // Visible index given, convert to column index
8459
+ if ( idx < 0 ) {
8460
+ // Counting from the right
8461
+ var visColumns = $.map( columns, function (col,i) {
8462
+ return col.bVisible ? i : null;
8463
+ } );
8464
+ return [ visColumns[ visColumns.length + idx ] ];
8465
+ }
8466
+ // Counting from the left
8467
+ return [ _fnVisibleToColumnIndex( settings, idx ) ];
8468
+
8469
+ case 'name':
8470
+ // match by name. `names` is column index complete and in order
8471
+ return $.map( names, function (name, i) {
8472
+ return name === match[1] ? i : null;
8473
+ } );
8474
+
8475
+ default:
8476
+ return [];
8477
+ }
8478
+ }
8479
+
8480
+ // Cell in the table body
8481
+ if ( s.nodeName && s._DT_CellIndex ) {
8482
+ return [ s._DT_CellIndex.column ];
8483
+ }
8484
+
8485
+ // jQuery selector on the TH elements for the columns
8486
+ var jqResult = $( nodes )
8487
+ .filter( s )
8488
+ .map( function () {
8489
+ return $.inArray( this, nodes ); // `nodes` is column index complete and in order
8490
+ } )
8491
+ .toArray();
8492
+
8493
+ if ( jqResult.length || ! s.nodeName ) {
8494
+ return jqResult;
8495
+ }
8496
+
8497
+ // Otherwise a node which might have a `dt-column` data attribute, or be
8498
+ // a child or such an element
8499
+ var host = $(s).closest('*[data-dt-column]');
8500
+ return host.length ?
8501
+ [ host.data('dt-column') ] :
8502
+ [];
8503
+ };
8504
+
8505
+ return _selector_run( 'column', selector, run, settings, opts );
8506
+ };
8507
+
8508
+
8509
+ var __setColumnVis = function ( settings, column, vis ) {
8510
+ var
8511
+ cols = settings.aoColumns,
8512
+ col = cols[ column ],
8513
+ data = settings.aoData,
8514
+ row, cells, i, ien, tr;
8515
+
8516
+ // Get
8517
+ if ( vis === undefined ) {
8518
+ return col.bVisible;
8519
+ }
8520
+
8521
+ // Set
8522
+ // No change
8523
+ if ( col.bVisible === vis ) {
8524
+ return;
8525
+ }
8526
+
8527
+ if ( vis ) {
8528
+ // Insert column
8529
+ // Need to decide if we should use appendChild or insertBefore
8530
+ var insertBefore = $.inArray( true, _pluck(cols, 'bVisible'), column+1 );
8531
+
8532
+ for ( i=0, ien=data.length ; i<ien ; i++ ) {
8533
+ tr = data[i].nTr;
8534
+ cells = data[i].anCells;
8535
+
8536
+ if ( tr ) {
8537
+ // insertBefore can act like appendChild if 2nd arg is null
8538
+ tr.insertBefore( cells[ column ], cells[ insertBefore ] || null );
8539
+ }
8540
+ }
8541
+ }
8542
+ else {
8543
+ // Remove column
8544
+ $( _pluck( settings.aoData, 'anCells', column ) ).detach();
8545
+ }
8546
+
8547
+ // Common actions
8548
+ col.bVisible = vis;
8549
+ _fnDrawHead( settings, settings.aoHeader );
8550
+ _fnDrawHead( settings, settings.aoFooter );
8551
+
8552
+ _fnSaveState( settings );
8553
+ };
8554
+
8555
+
8556
+ _api_register( 'columns()', function ( selector, opts ) {
8557
+ // argument shifting
8558
+ if ( selector === undefined ) {
8559
+ selector = '';
8560
+ }
8561
+ else if ( $.isPlainObject( selector ) ) {
8562
+ opts = selector;
8563
+ selector = '';
8564
+ }
8565
+
8566
+ opts = _selector_opts( opts );
8567
+
8568
+ var inst = this.iterator( 'table', function ( settings ) {
8569
+ return __column_selector( settings, selector, opts );
8570
+ }, 1 );
8571
+
8572
+ // Want argument shifting here and in _row_selector?
8573
+ inst.selector.cols = selector;
8574
+ inst.selector.opts = opts;
8575
+
8576
+ return inst;
8577
+ } );
8578
+
8579
+ _api_registerPlural( 'columns().header()', 'column().header()', function ( selector, opts ) {
8580
+ return this.iterator( 'column', function ( settings, column ) {
8581
+ return settings.aoColumns[column].nTh;
8582
+ }, 1 );
8583
+ } );
8584
+
8585
+ _api_registerPlural( 'columns().footer()', 'column().footer()', function ( selector, opts ) {
8586
+ return this.iterator( 'column', function ( settings, column ) {
8587
+ return settings.aoColumns[column].nTf;
8588
+ }, 1 );
8589
+ } );
8590
+
8591
+ _api_registerPlural( 'columns().data()', 'column().data()', function () {
8592
+ return this.iterator( 'column-rows', __columnData, 1 );
8593
+ } );
8594
+
8595
+ _api_registerPlural( 'columns().dataSrc()', 'column().dataSrc()', function () {
8596
+ return this.iterator( 'column', function ( settings, column ) {
8597
+ return settings.aoColumns[column].mData;
8598
+ }, 1 );
8599
+ } );
8600
+
8601
+ _api_registerPlural( 'columns().cache()', 'column().cache()', function ( type ) {
8602
+ return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {
8603
+ return _pluck_order( settings.aoData, rows,
8604
+ type === 'search' ? '_aFilterData' : '_aSortData', column
8605
+ );
8606
+ }, 1 );
8607
+ } );
8608
+
8609
+ _api_registerPlural( 'columns().nodes()', 'column().nodes()', function () {
8610
+ return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {
8611
+ return _pluck_order( settings.aoData, rows, 'anCells', column ) ;
8612
+ }, 1 );
8613
+ } );
8614
+
8615
+ _api_registerPlural( 'columns().visible()', 'column().visible()', function ( vis, calc ) {
8616
+ var ret = this.iterator( 'column', function ( settings, column ) {
8617
+ if ( vis === undefined ) {
8618
+ return settings.aoColumns[ column ].bVisible;
8619
+ } // else
8620
+ __setColumnVis( settings, column, vis );
8621
+ } );
8622
+
8623
+ // Group the column visibility changes
8624
+ if ( vis !== undefined ) {
8625
+ // Second loop once the first is done for events
8626
+ this.iterator( 'column', function ( settings, column ) {
8627
+ _fnCallbackFire( settings, null, 'column-visibility', [settings, column, vis, calc] );
8628
+ } );
8629
+
8630
+ if ( calc === undefined || calc ) {
8631
+ this.columns.adjust();
8632
+ }
8633
+ }
8634
+
8635
+ return ret;
8636
+ } );
8637
+
8638
+ _api_registerPlural( 'columns().indexes()', 'column().index()', function ( type ) {
8639
+ return this.iterator( 'column', function ( settings, column ) {
8640
+ return type === 'visible' ?
8641
+ _fnColumnIndexToVisible( settings, column ) :
8642
+ column;
8643
+ }, 1 );
8644
+ } );
8645
+
8646
+ _api_register( 'columns.adjust()', function () {
8647
+ return this.iterator( 'table', function ( settings ) {
8648
+ _fnAdjustColumnSizing( settings );
8649
+ }, 1 );
8650
+ } );
8651
+
8652
+ _api_register( 'column.index()', function ( type, idx ) {
8653
+ if ( this.context.length !== 0 ) {
8654
+ var ctx = this.context[0];
8655
+
8656
+ if ( type === 'fromVisible' || type === 'toData' ) {
8657
+ return _fnVisibleToColumnIndex( ctx, idx );
8658
+ }
8659
+ else if ( type === 'fromData' || type === 'toVisible' ) {
8660
+ return _fnColumnIndexToVisible( ctx, idx );
8661
+ }
8662
+ }
8663
+ } );
8664
+
8665
+ _api_register( 'column()', function ( selector, opts ) {
8666
+ return _selector_first( this.columns( selector, opts ) );
8667
+ } );
8668
+
8669
+
8670
+
8671
+ var __cell_selector = function ( settings, selector, opts )
8672
+ {
8673
+ var data = settings.aoData;
8674
+ var rows = _selector_row_indexes( settings, opts );
8675
+ var cells = _removeEmpty( _pluck_order( data, rows, 'anCells' ) );
8676
+ var allCells = $( [].concat.apply([], cells) );
8677
+ var row;
8678
+ var columns = settings.aoColumns.length;
8679
+ var a, i, ien, j, o, host;
8680
+
8681
+ var run = function ( s ) {
8682
+ var fnSelector = typeof s === 'function';
8683
+
8684
+ if ( s === null || s === undefined || fnSelector ) {
8685
+ // All cells and function selectors
8686
+ a = [];
8687
+
8688
+ for ( i=0, ien=rows.length ; i<ien ; i++ ) {
8689
+ row = rows[i];
8690
+
8691
+ for ( j=0 ; j<columns ; j++ ) {
8692
+ o = {
8693
+ row: row,
8694
+ column: j
8695
+ };
8696
+
8697
+ if ( fnSelector ) {
8698
+ // Selector - function
8699
+ host = data[ row ];
8700
+
8701
+ if ( s( o, _fnGetCellData(settings, row, j), host.anCells ? host.anCells[j] : null ) ) {
8702
+ a.push( o );
8703
+ }
8704
+ }
8705
+ else {
8706
+ // Selector - all
8707
+ a.push( o );
8708
+ }
8709
+ }
8710
+ }
8711
+
8712
+ return a;
8713
+ }
8714
+
8715
+ // Selector - index
8716
+ if ( $.isPlainObject( s ) ) {
8717
+ return [s];
8718
+ }
8719
+
8720
+ // Selector - jQuery filtered cells
8721
+ var jqResult = allCells
8722
+ .filter( s )
8723
+ .map( function (i, el) {
8724
+ return { // use a new object, in case someone changes the values
8725
+ row: el._DT_CellIndex.row,
8726
+ column: el._DT_CellIndex.column
8727
+ };
8728
+ } )
8729
+ .toArray();
8730
+
8731
+ if ( jqResult.length || ! s.nodeName ) {
8732
+ return jqResult;
8733
+ }
8734
+
8735
+ // Otherwise the selector is a node, and there is one last option - the
8736
+ // element might be a child of an element which has dt-row and dt-column
8737
+ // data attributes
8738
+ host = $(s).closest('*[data-dt-row]');
8739
+ return host.length ?
8740
+ [ {
8741
+ row: host.data('dt-row'),
8742
+ column: host.data('dt-column')
8743
+ } ] :
8744
+ [];
8745
+ };
8746
+
8747
+ return _selector_run( 'cell', selector, run, settings, opts );
8748
+ };
8749
+
8750
+
8751
+
8752
+
8753
+ _api_register( 'cells()', function ( rowSelector, columnSelector, opts ) {
8754
+ // Argument shifting
8755
+ if ( $.isPlainObject( rowSelector ) ) {
8756
+ // Indexes
8757
+ if ( rowSelector.row === undefined ) {
8758
+ // Selector options in first parameter
8759
+ opts = rowSelector;
8760
+ rowSelector = null;
8761
+ }
8762
+ else {
8763
+ // Cell index objects in first parameter
8764
+ opts = columnSelector;
8765
+ columnSelector = null;
8766
+ }
8767
+ }
8768
+ if ( $.isPlainObject( columnSelector ) ) {
8769
+ opts = columnSelector;
8770
+ columnSelector = null;
8771
+ }
8772
+
8773
+ // Cell selector
8774
+ if ( columnSelector === null || columnSelector === undefined ) {
8775
+ return this.iterator( 'table', function ( settings ) {
8776
+ return __cell_selector( settings, rowSelector, _selector_opts( opts ) );
8777
+ } );
8778
+ }
8779
+
8780
+ // Row + column selector
8781
+ var columns = this.columns( columnSelector, opts );
8782
+ var rows = this.rows( rowSelector, opts );
8783
+ var a, i, ien, j, jen;
8784
+
8785
+ var cells = this.iterator( 'table', function ( settings, idx ) {
8786
+ a = [];
8787
+
8788
+ for ( i=0, ien=rows[idx].length ; i<ien ; i++ ) {
8789
+ for ( j=0, jen=columns[idx].length ; j<jen ; j++ ) {
8790
+ a.push( {
8791
+ row: rows[idx][i],
8792
+ column: columns[idx][j]
8793
+ } );
8794
+ }
8795
+ }
8796
+
8797
+ return a;
8798
+ }, 1 );
8799
+
8800
+ $.extend( cells.selector, {
8801
+ cols: columnSelector,
8802
+ rows: rowSelector,
8803
+ opts: opts
8804
+ } );
8805
+
8806
+ return cells;
8807
+ } );
8808
+
8809
+
8810
+ _api_registerPlural( 'cells().nodes()', 'cell().node()', function () {
8811
+ return this.iterator( 'cell', function ( settings, row, column ) {
8812
+ var data = settings.aoData[ row ];
8813
+
8814
+ return data && data.anCells ?
8815
+ data.anCells[ column ] :
8816
+ undefined;
8817
+ }, 1 );
8818
+ } );
8819
+
8820
+
8821
+ _api_register( 'cells().data()', function () {
8822
+ return this.iterator( 'cell', function ( settings, row, column ) {
8823
+ return _fnGetCellData( settings, row, column );
8824
+ }, 1 );
8825
+ } );
8826
+
8827
+
8828
+ _api_registerPlural( 'cells().cache()', 'cell().cache()', function ( type ) {
8829
+ type = type === 'search' ? '_aFilterData' : '_aSortData';
8830
+
8831
+ return this.iterator( 'cell', function ( settings, row, column ) {
8832
+ return settings.aoData[ row ][ type ][ column ];
8833
+ }, 1 );
8834
+ } );
8835
+
8836
+
8837
+ _api_registerPlural( 'cells().render()', 'cell().render()', function ( type ) {
8838
+ return this.iterator( 'cell', function ( settings, row, column ) {
8839
+ return _fnGetCellData( settings, row, column, type );
8840
+ }, 1 );
8841
+ } );
8842
+
8843
+
8844
+ _api_registerPlural( 'cells().indexes()', 'cell().index()', function () {
8845
+ return this.iterator( 'cell', function ( settings, row, column ) {
8846
+ return {
8847
+ row: row,
8848
+ column: column,
8849
+ columnVisible: _fnColumnIndexToVisible( settings, column )
8850
+ };
8851
+ }, 1 );
8852
+ } );
8853
+
8854
+
8855
+ _api_registerPlural( 'cells().invalidate()', 'cell().invalidate()', function ( src ) {
8856
+ return this.iterator( 'cell', function ( settings, row, column ) {
8857
+ _fnInvalidate( settings, row, src, column );
8858
+ } );
8859
+ } );
8860
+
8861
+
8862
+
8863
+ _api_register( 'cell()', function ( rowSelector, columnSelector, opts ) {
8864
+ return _selector_first( this.cells( rowSelector, columnSelector, opts ) );
8865
+ } );
8866
+
8867
+
8868
+ _api_register( 'cell().data()', function ( data ) {
8869
+ var ctx = this.context;
8870
+ var cell = this[0];
8871
+
8872
+ if ( data === undefined ) {
8873
+ // Get
8874
+ return ctx.length && cell.length ?
8875
+ _fnGetCellData( ctx[0], cell[0].row, cell[0].column ) :
8876
+ undefined;
8877
+ }
8878
+
8879
+ // Set
8880
+ _fnSetCellData( ctx[0], cell[0].row, cell[0].column, data );
8881
+ _fnInvalidate( ctx[0], cell[0].row, 'data', cell[0].column );
8882
+
8883
+ return this;
8884
+ } );
8885
+
8886
+
8887
+
8888
+ /**
8889
+ * Get current ordering (sorting) that has been applied to the table.
8890
+ *
8891
+ * @returns {array} 2D array containing the sorting information for the first
8892
+ * table in the current context. Each element in the parent array represents
8893
+ * a column being sorted upon (i.e. multi-sorting with two columns would have
8894
+ * 2 inner arrays). The inner arrays may have 2 or 3 elements. The first is
8895
+ * the column index that the sorting condition applies to, the second is the
8896
+ * direction of the sort (`desc` or `asc`) and, optionally, the third is the
8897
+ * index of the sorting order from the `column.sorting` initialisation array.
8898
+ *//**
8899
+ * Set the ordering for the table.
8900
+ *
8901
+ * @param {integer} order Column index to sort upon.
8902
+ * @param {string} direction Direction of the sort to be applied (`asc` or `desc`)
8903
+ * @returns {DataTables.Api} this
8904
+ *//**
8905
+ * Set the ordering for the table.
8906
+ *
8907
+ * @param {array} order 1D array of sorting information to be applied.
8908
+ * @param {array} [...] Optional additional sorting conditions
8909
+ * @returns {DataTables.Api} this
8910
+ *//**
8911
+ * Set the ordering for the table.
8912
+ *
8913
+ * @param {array} order 2D array of sorting information to be applied.
8914
+ * @returns {DataTables.Api} this
8915
+ */
8916
+ _api_register( 'order()', function ( order, dir ) {
8917
+ var ctx = this.context;
8918
+
8919
+ if ( order === undefined ) {
8920
+ // get
8921
+ return ctx.length !== 0 ?
8922
+ ctx[0].aaSorting :
8923
+ undefined;
8924
+ }
8925
+
8926
+ // set
8927
+ if ( typeof order === 'number' ) {
8928
+ // Simple column / direction passed in
8929
+ order = [ [ order, dir ] ];
8930
+ }
8931
+ else if ( order.length && ! $.isArray( order[0] ) ) {
8932
+ // Arguments passed in (list of 1D arrays)
8933
+ order = Array.prototype.slice.call( arguments );
8934
+ }
8935
+ // otherwise a 2D array was passed in
8936
+
8937
+ return this.iterator( 'table', function ( settings ) {
8938
+ settings.aaSorting = order.slice();
8939
+ } );
8940
+ } );
8941
+
8942
+
8943
+ /**
8944
+ * Attach a sort listener to an element for a given column
8945
+ *
8946
+ * @param {node|jQuery|string} node Identifier for the element(s) to attach the
8947
+ * listener to. This can take the form of a single DOM node, a jQuery
8948
+ * collection of nodes or a jQuery selector which will identify the node(s).
8949
+ * @param {integer} column the column that a click on this node will sort on
8950
+ * @param {function} [callback] callback function when sort is run
8951
+ * @returns {DataTables.Api} this
8952
+ */
8953
+ _api_register( 'order.listener()', function ( node, column, callback ) {
8954
+ return this.iterator( 'table', function ( settings ) {
8955
+ _fnSortAttachListener( settings, node, column, callback );
8956
+ } );
8957
+ } );
8958
+
8959
+
8960
+ _api_register( 'order.fixed()', function ( set ) {
8961
+ if ( ! set ) {
8962
+ var ctx = this.context;
8963
+ var fixed = ctx.length ?
8964
+ ctx[0].aaSortingFixed :
8965
+ undefined;
8966
+
8967
+ return $.isArray( fixed ) ?
8968
+ { pre: fixed } :
8969
+ fixed;
8970
+ }
8971
+
8972
+ return this.iterator( 'table', function ( settings ) {
8973
+ settings.aaSortingFixed = $.extend( true, {}, set );
8974
+ } );
8975
+ } );
8976
+
8977
+
8978
+ // Order by the selected column(s)
8979
+ _api_register( [
8980
+ 'columns().order()',
8981
+ 'column().order()'
8982
+ ], function ( dir ) {
8983
+ var that = this;
8984
+
8985
+ return this.iterator( 'table', function ( settings, i ) {
8986
+ var sort = [];
8987
+
8988
+ $.each( that[i], function (j, col) {
8989
+ sort.push( [ col, dir ] );
8990
+ } );
8991
+
8992
+ settings.aaSorting = sort;
8993
+ } );
8994
+ } );
8995
+
8996
+
8997
+
8998
+ _api_register( 'search()', function ( input, regex, smart, caseInsen ) {
8999
+ var ctx = this.context;
9000
+
9001
+ if ( input === undefined ) {
9002
+ // get
9003
+ return ctx.length !== 0 ?
9004
+ ctx[0].oPreviousSearch.sSearch :
9005
+ undefined;
9006
+ }
9007
+
9008
+ // set
9009
+ return this.iterator( 'table', function ( settings ) {
9010
+ if ( ! settings.oFeatures.bFilter ) {
9011
+ return;
9012
+ }
9013
+
9014
+ _fnFilterComplete( settings, $.extend( {}, settings.oPreviousSearch, {
9015
+ "sSearch": input+"",
9016
+ "bRegex": regex === null ? false : regex,
9017
+ "bSmart": smart === null ? true : smart,
9018
+ "bCaseInsensitive": caseInsen === null ? true : caseInsen
9019
+ } ), 1 );
9020
+ } );
9021
+ } );
9022
+
9023
+
9024
+ _api_registerPlural(
9025
+ 'columns().search()',
9026
+ 'column().search()',
9027
+ function ( input, regex, smart, caseInsen ) {
9028
+ return this.iterator( 'column', function ( settings, column ) {
9029
+ var preSearch = settings.aoPreSearchCols;
9030
+
9031
+ if ( input === undefined ) {
9032
+ // get
9033
+ return preSearch[ column ].sSearch;
9034
+ }
9035
+
9036
+ // set
9037
+ if ( ! settings.oFeatures.bFilter ) {
9038
+ return;
9039
+ }
9040
+
9041
+ $.extend( preSearch[ column ], {
9042
+ "sSearch": input+"",
9043
+ "bRegex": regex === null ? false : regex,
9044
+ "bSmart": smart === null ? true : smart,
9045
+ "bCaseInsensitive": caseInsen === null ? true : caseInsen
9046
+ } );
9047
+
9048
+ _fnFilterComplete( settings, settings.oPreviousSearch, 1 );
9049
+ } );
9050
+ }
9051
+ );
9052
+
9053
+ /*
9054
+ * State API methods
9055
+ */
9056
+
9057
+ _api_register( 'state()', function () {
9058
+ return this.context.length ?
9059
+ this.context[0].oSavedState :
9060
+ null;
9061
+ } );
9062
+
9063
+
9064
+ _api_register( 'state.clear()', function () {
9065
+ return this.iterator( 'table', function ( settings ) {
9066
+ // Save an empty object
9067
+ settings.fnStateSaveCallback.call( settings.oInstance, settings, {} );
9068
+ } );
9069
+ } );
9070
+
9071
+
9072
+ _api_register( 'state.loaded()', function () {
9073
+ return this.context.length ?
9074
+ this.context[0].oLoadedState :
9075
+ null;
9076
+ } );
9077
+
9078
+
9079
+ _api_register( 'state.save()', function () {
9080
+ return this.iterator( 'table', function ( settings ) {
9081
+ _fnSaveState( settings );
9082
+ } );
9083
+ } );
9084
+
9085
+
9086
+
9087
+ /**
9088
+ * Provide a common method for plug-ins to check the version of DataTables being
9089
+ * used, in order to ensure compatibility.
9090
+ *
9091
+ * @param {string} version Version string to check for, in the format "X.Y.Z".
9092
+ * Note that the formats "X" and "X.Y" are also acceptable.
9093
+ * @returns {boolean} true if this version of DataTables is greater or equal to
9094
+ * the required version, or false if this version of DataTales is not
9095
+ * suitable
9096
+ * @static
9097
+ * @dtopt API-Static
9098
+ *
9099
+ * @example
9100
+ * alert( $.fn.dataTable.versionCheck( '1.9.0' ) );
9101
+ */
9102
+ DataTable.versionCheck = DataTable.fnVersionCheck = function( version )
9103
+ {
9104
+ var aThis = DataTable.version.split('.');
9105
+ var aThat = version.split('.');
9106
+ var iThis, iThat;
9107
+
9108
+ for ( var i=0, iLen=aThat.length ; i<iLen ; i++ ) {
9109
+ iThis = parseInt( aThis[i], 10 ) || 0;
9110
+ iThat = parseInt( aThat[i], 10 ) || 0;
9111
+
9112
+ // Parts are the same, keep comparing
9113
+ if (iThis === iThat) {
9114
+ continue;
9115
+ }
9116
+
9117
+ // Parts are different, return immediately
9118
+ return iThis > iThat;
9119
+ }
9120
+
9121
+ return true;
9122
+ };
9123
+
9124
+
9125
+ /**
9126
+ * Check if a `<table>` node is a DataTable table already or not.
9127
+ *
9128
+ * @param {node|jquery|string} table Table node, jQuery object or jQuery
9129
+ * selector for the table to test. Note that if more than more than one
9130
+ * table is passed on, only the first will be checked
9131
+ * @returns {boolean} true the table given is a DataTable, or false otherwise
9132
+ * @static
9133
+ * @dtopt API-Static
9134
+ *
9135
+ * @example
9136
+ * if ( ! $.fn.DataTable.isDataTable( '#example' ) ) {
9137
+ * $('#example').dataTable();
9138
+ * }
9139
+ */
9140
+ DataTable.isDataTable = DataTable.fnIsDataTable = function ( table )
9141
+ {
9142
+ var t = $(table).get(0);
9143
+ var is = false;
9144
+
9145
+ if ( table instanceof DataTable.Api ) {
9146
+ return true;
9147
+ }
9148
+
9149
+ $.each( DataTable.settings, function (i, o) {
9150
+ var head = o.nScrollHead ? $('table', o.nScrollHead)[0] : null;
9151
+ var foot = o.nScrollFoot ? $('table', o.nScrollFoot)[0] : null;
9152
+
9153
+ if ( o.nTable === t || head === t || foot === t ) {
9154
+ is = true;
9155
+ }
9156
+ } );
9157
+
9158
+ return is;
9159
+ };
9160
+
9161
+
9162
+ /**
9163
+ * Get all DataTable tables that have been initialised - optionally you can
9164
+ * select to get only currently visible tables.
9165
+ *
9166
+ * @param {boolean} [visible=false] Flag to indicate if you want all (default)
9167
+ * or visible tables only.
9168
+ * @returns {array} Array of `table` nodes (not DataTable instances) which are
9169
+ * DataTables
9170
+ * @static
9171
+ * @dtopt API-Static
9172
+ *
9173
+ * @example
9174
+ * $.each( $.fn.dataTable.tables(true), function () {
9175
+ * $(table).DataTable().columns.adjust();
9176
+ * } );
9177
+ */
9178
+ DataTable.tables = DataTable.fnTables = function ( visible )
9179
+ {
9180
+ var api = false;
9181
+
9182
+ if ( $.isPlainObject( visible ) ) {
9183
+ api = visible.api;
9184
+ visible = visible.visible;
9185
+ }
9186
+
9187
+ var a = $.map( DataTable.settings, function (o) {
9188
+ if ( !visible || (visible && $(o.nTable).is(':visible')) ) {
9189
+ return o.nTable;
9190
+ }
9191
+ } );
9192
+
9193
+ return api ?
9194
+ new _Api( a ) :
9195
+ a;
9196
+ };
9197
+
9198
+
9199
+ /**
9200
+ * Convert from camel case parameters to Hungarian notation. This is made public
9201
+ * for the extensions to provide the same ability as DataTables core to accept
9202
+ * either the 1.9 style Hungarian notation, or the 1.10+ style camelCase
9203
+ * parameters.
9204
+ *
9205
+ * @param {object} src The model object which holds all parameters that can be
9206
+ * mapped.
9207
+ * @param {object} user The object to convert from camel case to Hungarian.
9208
+ * @param {boolean} force When set to `true`, properties which already have a
9209
+ * Hungarian value in the `user` object will be overwritten. Otherwise they
9210
+ * won't be.
9211
+ */
9212
+ DataTable.camelToHungarian = _fnCamelToHungarian;
9213
+
9214
+
9215
+
9216
+ /**
9217
+ *
9218
+ */
9219
+ _api_register( '$()', function ( selector, opts ) {
9220
+ var
9221
+ rows = this.rows( opts ).nodes(), // Get all rows
9222
+ jqRows = $(rows);
9223
+
9224
+ return $( [].concat(
9225
+ jqRows.filter( selector ).toArray(),
9226
+ jqRows.find( selector ).toArray()
9227
+ ) );
9228
+ } );
9229
+
9230
+
9231
+ // jQuery functions to operate on the tables
9232
+ $.each( [ 'on', 'one', 'off' ], function (i, key) {
9233
+ _api_register( key+'()', function ( /* event, handler */ ) {
9234
+ var args = Array.prototype.slice.call(arguments);
9235
+
9236
+ // Add the `dt` namespace automatically if it isn't already present
9237
+ args[0] = $.map( args[0].split( /\s/ ), function ( e ) {
9238
+ return ! e.match(/\.dt\b/) ?
9239
+ e+'.dt' :
9240
+ e;
9241
+ } ).join( ' ' );
9242
+
9243
+ var inst = $( this.tables().nodes() );
9244
+ inst[key].apply( inst, args );
9245
+ return this;
9246
+ } );
9247
+ } );
9248
+
9249
+
9250
+ _api_register( 'clear()', function () {
9251
+ return this.iterator( 'table', function ( settings ) {
9252
+ _fnClearTable( settings );
9253
+ } );
9254
+ } );
9255
+
9256
+
9257
+ _api_register( 'settings()', function () {
9258
+ return new _Api( this.context, this.context );
9259
+ } );
9260
+
9261
+
9262
+ _api_register( 'init()', function () {
9263
+ var ctx = this.context;
9264
+ return ctx.length ? ctx[0].oInit : null;
9265
+ } );
9266
+
9267
+
9268
+ _api_register( 'data()', function () {
9269
+ return this.iterator( 'table', function ( settings ) {
9270
+ return _pluck( settings.aoData, '_aData' );
9271
+ } ).flatten();
9272
+ } );
9273
+
9274
+
9275
+ _api_register( 'destroy()', function ( remove ) {
9276
+ remove = remove || false;
9277
+
9278
+ return this.iterator( 'table', function ( settings ) {
9279
+ var orig = settings.nTableWrapper.parentNode;
9280
+ var classes = settings.oClasses;
9281
+ var table = settings.nTable;
9282
+ var tbody = settings.nTBody;
9283
+ var thead = settings.nTHead;
9284
+ var tfoot = settings.nTFoot;
9285
+ var jqTable = $(table);
9286
+ var jqTbody = $(tbody);
9287
+ var jqWrapper = $(settings.nTableWrapper);
9288
+ var rows = $.map( settings.aoData, function (r) { return r.nTr; } );
9289
+ var i, ien;
9290
+
9291
+ // Flag to note that the table is currently being destroyed - no action
9292
+ // should be taken
9293
+ settings.bDestroying = true;
9294
+
9295
+ // Fire off the destroy callbacks for plug-ins etc
9296
+ _fnCallbackFire( settings, "aoDestroyCallback", "destroy", [settings] );
9297
+
9298
+ // If not being removed from the document, make all columns visible
9299
+ if ( ! remove ) {
9300
+ new _Api( settings ).columns().visible( true );
9301
+ }
9302
+
9303
+ // Blitz all `DT` namespaced events (these are internal events, the
9304
+ // lowercase, `dt` events are user subscribed and they are responsible
9305
+ // for removing them
9306
+ jqWrapper.off('.DT').find(':not(tbody *)').off('.DT');
9307
+ $(window).off('.DT-'+settings.sInstance);
9308
+
9309
+ // When scrolling we had to break the table up - restore it
9310
+ if ( table != thead.parentNode ) {
9311
+ jqTable.children('thead').detach();
9312
+ jqTable.append( thead );
9313
+ }
9314
+
9315
+ if ( tfoot && table != tfoot.parentNode ) {
9316
+ jqTable.children('tfoot').detach();
9317
+ jqTable.append( tfoot );
9318
+ }
9319
+
9320
+ settings.aaSorting = [];
9321
+ settings.aaSortingFixed = [];
9322
+ _fnSortingClasses( settings );
9323
+
9324
+ $( rows ).removeClass( settings.asStripeClasses.join(' ') );
9325
+
9326
+ $('th, td', thead).removeClass( classes.sSortable+' '+
9327
+ classes.sSortableAsc+' '+classes.sSortableDesc+' '+classes.sSortableNone
9328
+ );
9329
+
9330
+ // Add the TR elements back into the table in their original order
9331
+ jqTbody.children().detach();
9332
+ jqTbody.append( rows );
9333
+
9334
+ // Remove the DataTables generated nodes, events and classes
9335
+ var removedMethod = remove ? 'remove' : 'detach';
9336
+ jqTable[ removedMethod ]();
9337
+ jqWrapper[ removedMethod ]();
9338
+
9339
+ // If we need to reattach the table to the document
9340
+ if ( ! remove && orig ) {
9341
+ // insertBefore acts like appendChild if !arg[1]
9342
+ orig.insertBefore( table, settings.nTableReinsertBefore );
9343
+
9344
+ // Restore the width of the original table - was read from the style property,
9345
+ // so we can restore directly to that
9346
+ jqTable
9347
+ .css( 'width', settings.sDestroyWidth )
9348
+ .removeClass( classes.sTable );
9349
+
9350
+ // If the were originally stripe classes - then we add them back here.
9351
+ // Note this is not fool proof (for example if not all rows had stripe
9352
+ // classes - but it's a good effort without getting carried away
9353
+ ien = settings.asDestroyStripes.length;
9354
+
9355
+ if ( ien ) {
9356
+ jqTbody.children().each( function (i) {
9357
+ $(this).addClass( settings.asDestroyStripes[i % ien] );
9358
+ } );
9359
+ }
9360
+ }
9361
+
9362
+ /* Remove the settings object from the settings array */
9363
+ var idx = $.inArray( settings, DataTable.settings );
9364
+ if ( idx !== -1 ) {
9365
+ DataTable.settings.splice( idx, 1 );
9366
+ }
9367
+ } );
9368
+ } );
9369
+
9370
+
9371
+ // Add the `every()` method for rows, columns and cells in a compact form
9372
+ $.each( [ 'column', 'row', 'cell' ], function ( i, type ) {
9373
+ _api_register( type+'s().every()', function ( fn ) {
9374
+ var opts = this.selector.opts;
9375
+ var api = this;
9376
+
9377
+ return this.iterator( type, function ( settings, arg1, arg2, arg3, arg4 ) {
9378
+ // Rows and columns:
9379
+ // arg1 - index
9380
+ // arg2 - table counter
9381
+ // arg3 - loop counter
9382
+ // arg4 - undefined
9383
+ // Cells:
9384
+ // arg1 - row index
9385
+ // arg2 - column index
9386
+ // arg3 - table counter
9387
+ // arg4 - loop counter
9388
+ fn.call(
9389
+ api[ type ](
9390
+ arg1,
9391
+ type==='cell' ? arg2 : opts,
9392
+ type==='cell' ? opts : undefined
9393
+ ),
9394
+ arg1, arg2, arg3, arg4
9395
+ );
9396
+ } );
9397
+ } );
9398
+ } );
9399
+
9400
+
9401
+ // i18n method for extensions to be able to use the language object from the
9402
+ // DataTable
9403
+ _api_register( 'i18n()', function ( token, def, plural ) {
9404
+ var ctx = this.context[0];
9405
+ var resolved = _fnGetObjectDataFn( token )( ctx.oLanguage );
9406
+
9407
+ if ( resolved === undefined ) {
9408
+ resolved = def;
9409
+ }
9410
+
9411
+ if ( plural !== undefined && $.isPlainObject( resolved ) ) {
9412
+ resolved = resolved[ plural ] !== undefined ?
9413
+ resolved[ plural ] :
9414
+ resolved._;
9415
+ }
9416
+
9417
+ return resolved.replace( '%d', plural ); // nb: plural might be undefined,
9418
+ } );
9419
+
9420
+ /**
9421
+ * Version string for plug-ins to check compatibility. Allowed format is
9422
+ * `a.b.c-d` where: a:int, b:int, c:int, d:string(dev|beta|alpha). `d` is used
9423
+ * only for non-release builds. See http://semver.org/ for more information.
9424
+ * @member
9425
+ * @type string
9426
+ * @default Version number
9427
+ */
9428
+ DataTable.version = "1.10.16";
9429
+
9430
+ /**
9431
+ * Private data store, containing all of the settings objects that are
9432
+ * created for the tables on a given page.
9433
+ *
9434
+ * Note that the `DataTable.settings` object is aliased to
9435
+ * `jQuery.fn.dataTableExt` through which it may be accessed and
9436
+ * manipulated, or `jQuery.fn.dataTable.settings`.
9437
+ * @member
9438
+ * @type array
9439
+ * @default []
9440
+ * @private
9441
+ */
9442
+ DataTable.settings = [];
9443
+
9444
+ /**
9445
+ * Object models container, for the various models that DataTables has
9446
+ * available to it. These models define the objects that are used to hold
9447
+ * the active state and configuration of the table.
9448
+ * @namespace
9449
+ */
9450
+ DataTable.models = {};
9451
+
9452
+
9453
+
9454
+ /**
9455
+ * Template object for the way in which DataTables holds information about
9456
+ * search information for the global filter and individual column filters.
9457
+ * @namespace
9458
+ */
9459
+ DataTable.models.oSearch = {
9460
+ /**
9461
+ * Flag to indicate if the filtering should be case insensitive or not
9462
+ * @type boolean
9463
+ * @default true
9464
+ */
9465
+ "bCaseInsensitive": true,
9466
+
9467
+ /**
9468
+ * Applied search term
9469
+ * @type string
9470
+ * @default <i>Empty string</i>
9471
+ */
9472
+ "sSearch": "",
9473
+
9474
+ /**
9475
+ * Flag to indicate if the search term should be interpreted as a
9476
+ * regular expression (true) or not (false) and therefore and special
9477
+ * regex characters escaped.
9478
+ * @type boolean
9479
+ * @default false
9480
+ */
9481
+ "bRegex": false,
9482
+
9483
+ /**
9484
+ * Flag to indicate if DataTables is to use its smart filtering or not.
9485
+ * @type boolean
9486
+ * @default true
9487
+ */
9488
+ "bSmart": true
9489
+ };
9490
+
9491
+
9492
+
9493
+
9494
+ /**
9495
+ * Template object for the way in which DataTables holds information about
9496
+ * each individual row. This is the object format used for the settings
9497
+ * aoData array.
9498
+ * @namespace
9499
+ */
9500
+ DataTable.models.oRow = {
9501
+ /**
9502
+ * TR element for the row
9503
+ * @type node
9504
+ * @default null
9505
+ */
9506
+ "nTr": null,
9507
+
9508
+ /**
9509
+ * Array of TD elements for each row. This is null until the row has been
9510
+ * created.
9511
+ * @type array nodes
9512
+ * @default []
9513
+ */
9514
+ "anCells": null,
9515
+
9516
+ /**
9517
+ * Data object from the original data source for the row. This is either
9518
+ * an array if using the traditional form of DataTables, or an object if
9519
+ * using mData options. The exact type will depend on the passed in
9520
+ * data from the data source, or will be an array if using DOM a data
9521
+ * source.
9522
+ * @type array|object
9523
+ * @default []
9524
+ */
9525
+ "_aData": [],
9526
+
9527
+ /**
9528
+ * Sorting data cache - this array is ostensibly the same length as the
9529
+ * number of columns (although each index is generated only as it is
9530
+ * needed), and holds the data that is used for sorting each column in the
9531
+ * row. We do this cache generation at the start of the sort in order that
9532
+ * the formatting of the sort data need be done only once for each cell
9533
+ * per sort. This array should not be read from or written to by anything
9534
+ * other than the master sorting methods.
9535
+ * @type array
9536
+ * @default null
9537
+ * @private
9538
+ */
9539
+ "_aSortData": null,
9540
+
9541
+ /**
9542
+ * Per cell filtering data cache. As per the sort data cache, used to
9543
+ * increase the performance of the filtering in DataTables
9544
+ * @type array
9545
+ * @default null
9546
+ * @private
9547
+ */
9548
+ "_aFilterData": null,
9549
+
9550
+ /**
9551
+ * Filtering data cache. This is the same as the cell filtering cache, but
9552
+ * in this case a string rather than an array. This is easily computed with
9553
+ * a join on `_aFilterData`, but is provided as a cache so the join isn't
9554
+ * needed on every search (memory traded for performance)
9555
+ * @type array
9556
+ * @default null
9557
+ * @private
9558
+ */
9559
+ "_sFilterRow": null,
9560
+
9561
+ /**
9562
+ * Cache of the class name that DataTables has applied to the row, so we
9563
+ * can quickly look at this variable rather than needing to do a DOM check
9564
+ * on className for the nTr property.
9565
+ * @type string
9566
+ * @default <i>Empty string</i>
9567
+ * @private
9568
+ */
9569
+ "_sRowStripe": "",
9570
+
9571
+ /**
9572
+ * Denote if the original data source was from the DOM, or the data source
9573
+ * object. This is used for invalidating data, so DataTables can
9574
+ * automatically read data from the original source, unless uninstructed
9575
+ * otherwise.
9576
+ * @type string
9577
+ * @default null
9578
+ * @private
9579
+ */
9580
+ "src": null,
9581
+
9582
+ /**
9583
+ * Index in the aoData array. This saves an indexOf lookup when we have the
9584
+ * object, but want to know the index
9585
+ * @type integer
9586
+ * @default -1
9587
+ * @private
9588
+ */
9589
+ "idx": -1
9590
+ };
9591
+
9592
+
9593
+ /**
9594
+ * Template object for the column information object in DataTables. This object
9595
+ * is held in the settings aoColumns array and contains all the information that
9596
+ * DataTables needs about each individual column.
9597
+ *
9598
+ * Note that this object is related to {@link DataTable.defaults.column}
9599
+ * but this one is the internal data store for DataTables's cache of columns.
9600
+ * It should NOT be manipulated outside of DataTables. Any configuration should
9601
+ * be done through the initialisation options.
9602
+ * @namespace
9603
+ */
9604
+ DataTable.models.oColumn = {
9605
+ /**
9606
+ * Column index. This could be worked out on-the-fly with $.inArray, but it
9607
+ * is faster to just hold it as a variable
9608
+ * @type integer
9609
+ * @default null
9610
+ */
9611
+ "idx": null,
9612
+
9613
+ /**
9614
+ * A list of the columns that sorting should occur on when this column
9615
+ * is sorted. That this property is an array allows multi-column sorting
9616
+ * to be defined for a column (for example first name / last name columns
9617
+ * would benefit from this). The values are integers pointing to the
9618
+ * columns to be sorted on (typically it will be a single integer pointing
9619
+ * at itself, but that doesn't need to be the case).
9620
+ * @type array
9621
+ */
9622
+ "aDataSort": null,
9623
+
9624
+ /**
9625
+ * Define the sorting directions that are applied to the column, in sequence
9626
+ * as the column is repeatedly sorted upon - i.e. the first value is used
9627
+ * as the sorting direction when the column if first sorted (clicked on).
9628
+ * Sort it again (click again) and it will move on to the next index.
9629
+ * Repeat until loop.
9630
+ * @type array
9631
+ */
9632
+ "asSorting": null,
9633
+
9634
+ /**
9635
+ * Flag to indicate if the column is searchable, and thus should be included
9636
+ * in the filtering or not.
9637
+ * @type boolean
9638
+ */
9639
+ "bSearchable": null,
9640
+
9641
+ /**
9642
+ * Flag to indicate if the column is sortable or not.
9643
+ * @type boolean
9644
+ */
9645
+ "bSortable": null,
9646
+
9647
+ /**
9648
+ * Flag to indicate if the column is currently visible in the table or not
9649
+ * @type boolean
9650
+ */
9651
+ "bVisible": null,
9652
+
9653
+ /**
9654
+ * Store for manual type assignment using the `column.type` option. This
9655
+ * is held in store so we can manipulate the column's `sType` property.
9656
+ * @type string
9657
+ * @default null
9658
+ * @private
9659
+ */
9660
+ "_sManualType": null,
9661
+
9662
+ /**
9663
+ * Flag to indicate if HTML5 data attributes should be used as the data
9664
+ * source for filtering or sorting. True is either are.
9665
+ * @type boolean
9666
+ * @default false
9667
+ * @private
9668
+ */
9669
+ "_bAttrSrc": false,
9670
+
9671
+ /**
9672
+ * Developer definable function that is called whenever a cell is created (Ajax source,
9673
+ * etc) or processed for input (DOM source). This can be used as a compliment to mRender
9674
+ * allowing you to modify the DOM element (add background colour for example) when the
9675
+ * element is available.
9676
+ * @type function
9677
+ * @param {element} nTd The TD node that has been created
9678
+ * @param {*} sData The Data for the cell
9679
+ * @param {array|object} oData The data for the whole row
9680
+ * @param {int} iRow The row index for the aoData data store
9681
+ * @default null
9682
+ */
9683
+ "fnCreatedCell": null,
9684
+
9685
+ /**
9686
+ * Function to get data from a cell in a column. You should <b>never</b>
9687
+ * access data directly through _aData internally in DataTables - always use
9688
+ * the method attached to this property. It allows mData to function as
9689
+ * required. This function is automatically assigned by the column
9690
+ * initialisation method
9691
+ * @type function
9692
+ * @param {array|object} oData The data array/object for the array
9693
+ * (i.e. aoData[]._aData)
9694
+ * @param {string} sSpecific The specific data type you want to get -
9695
+ * 'display', 'type' 'filter' 'sort'
9696
+ * @returns {*} The data for the cell from the given row's data
9697
+ * @default null
9698
+ */
9699
+ "fnGetData": null,
9700
+
9701
+ /**
9702
+ * Function to set data for a cell in the column. You should <b>never</b>
9703
+ * set the data directly to _aData internally in DataTables - always use
9704
+ * this method. It allows mData to function as required. This function
9705
+ * is automatically assigned by the column initialisation method
9706
+ * @type function
9707
+ * @param {array|object} oData The data array/object for the array
9708
+ * (i.e. aoData[]._aData)
9709
+ * @param {*} sValue Value to set
9710
+ * @default null
9711
+ */
9712
+ "fnSetData": null,
9713
+
9714
+ /**
9715
+ * Property to read the value for the cells in the column from the data
9716
+ * source array / object. If null, then the default content is used, if a
9717
+ * function is given then the return from the function is used.
9718
+ * @type function|int|string|null
9719
+ * @default null
9720
+ */
9721
+ "mData": null,
9722
+
9723
+ /**
9724
+ * Partner property to mData which is used (only when defined) to get
9725
+ * the data - i.e. it is basically the same as mData, but without the
9726
+ * 'set' option, and also the data fed to it is the result from mData.
9727
+ * This is the rendering method to match the data method of mData.
9728
+ * @type function|int|string|null
9729
+ * @default null
9730
+ */
9731
+ "mRender": null,
9732
+
9733
+ /**
9734
+ * Unique header TH/TD element for this column - this is what the sorting
9735
+ * listener is attached to (if sorting is enabled.)
9736
+ * @type node
9737
+ * @default null
9738
+ */
9739
+ "nTh": null,
9740
+
9741
+ /**
9742
+ * Unique footer TH/TD element for this column (if there is one). Not used
9743
+ * in DataTables as such, but can be used for plug-ins to reference the
9744
+ * footer for each column.
9745
+ * @type node
9746
+ * @default null
9747
+ */
9748
+ "nTf": null,
9749
+
9750
+ /**
9751
+ * The class to apply to all TD elements in the table's TBODY for the column
9752
+ * @type string
9753
+ * @default null
9754
+ */
9755
+ "sClass": null,
9756
+
9757
+ /**
9758
+ * When DataTables calculates the column widths to assign to each column,
9759
+ * it finds the longest string in each column and then constructs a
9760
+ * temporary table and reads the widths from that. The problem with this
9761
+ * is that "mmm" is much wider then "iiii", but the latter is a longer
9762
+ * string - thus the calculation can go wrong (doing it properly and putting
9763
+ * it into an DOM object and measuring that is horribly(!) slow). Thus as
9764
+ * a "work around" we provide this option. It will append its value to the
9765
+ * text that is found to be the longest string for the column - i.e. padding.
9766
+ * @type string
9767
+ */
9768
+ "sContentPadding": null,
9769
+
9770
+ /**
9771
+ * Allows a default value to be given for a column's data, and will be used
9772
+ * whenever a null data source is encountered (this can be because mData
9773
+ * is set to null, or because the data source itself is null).
9774
+ * @type string
9775
+ * @default null
9776
+ */
9777
+ "sDefaultContent": null,
9778
+
9779
+ /**
9780
+ * Name for the column, allowing reference to the column by name as well as
9781
+ * by index (needs a lookup to work by name).
9782
+ * @type string
9783
+ */
9784
+ "sName": null,
9785
+
9786
+ /**
9787
+ * Custom sorting data type - defines which of the available plug-ins in
9788
+ * afnSortData the custom sorting will use - if any is defined.
9789
+ * @type string
9790
+ * @default std
9791
+ */
9792
+ "sSortDataType": 'std',
9793
+
9794
+ /**
9795
+ * Class to be applied to the header element when sorting on this column
9796
+ * @type string
9797
+ * @default null
9798
+ */
9799
+ "sSortingClass": null,
9800
+
9801
+ /**
9802
+ * Class to be applied to the header element when sorting on this column -
9803
+ * when jQuery UI theming is used.
9804
+ * @type string
9805
+ * @default null
9806
+ */
9807
+ "sSortingClassJUI": null,
9808
+
9809
+ /**
9810
+ * Title of the column - what is seen in the TH element (nTh).
9811
+ * @type string
9812
+ */
9813
+ "sTitle": null,
9814
+
9815
+ /**
9816
+ * Column sorting and filtering type
9817
+ * @type string
9818
+ * @default null
9819
+ */
9820
+ "sType": null,
9821
+
9822
+ /**
9823
+ * Width of the column
9824
+ * @type string
9825
+ * @default null
9826
+ */
9827
+ "sWidth": null,
9828
+
9829
+ /**
9830
+ * Width of the column when it was first "encountered"
9831
+ * @type string
9832
+ * @default null
9833
+ */
9834
+ "sWidthOrig": null
9835
+ };
9836
+
9837
+
9838
+ /*
9839
+ * Developer note: The properties of the object below are given in Hungarian
9840
+ * notation, that was used as the interface for DataTables prior to v1.10, however
9841
+ * from v1.10 onwards the primary interface is camel case. In order to avoid
9842
+ * breaking backwards compatibility utterly with this change, the Hungarian
9843
+ * version is still, internally the primary interface, but is is not documented
9844
+ * - hence the @name tags in each doc comment. This allows a Javascript function
9845
+ * to create a map from Hungarian notation to camel case (going the other direction
9846
+ * would require each property to be listed, which would at around 3K to the size
9847
+ * of DataTables, while this method is about a 0.5K hit.
9848
+ *
9849
+ * Ultimately this does pave the way for Hungarian notation to be dropped
9850
+ * completely, but that is a massive amount of work and will break current
9851
+ * installs (therefore is on-hold until v2).
9852
+ */
9853
+
9854
+ /**
9855
+ * Initialisation options that can be given to DataTables at initialisation
9856
+ * time.
9857
+ * @namespace
9858
+ */
9859
+ DataTable.defaults = {
9860
+ /**
9861
+ * An array of data to use for the table, passed in at initialisation which
9862
+ * will be used in preference to any data which is already in the DOM. This is
9863
+ * particularly useful for constructing tables purely in Javascript, for
9864
+ * example with a custom Ajax call.
9865
+ * @type array
9866
+ * @default null
9867
+ *
9868
+ * @dtopt Option
9869
+ * @name DataTable.defaults.data
9870
+ *
9871
+ * @example
9872
+ * // Using a 2D array data source
9873
+ * $(document).ready( function () {
9874
+ * $('#example').dataTable( {
9875
+ * "data": [
9876
+ * ['Trident', 'Internet Explorer 4.0', 'Win 95+', 4, 'X'],
9877
+ * ['Trident', 'Internet Explorer 5.0', 'Win 95+', 5, 'C'],
9878
+ * ],
9879
+ * "columns": [
9880
+ * { "title": "Engine" },
9881
+ * { "title": "Browser" },
9882
+ * { "title": "Platform" },
9883
+ * { "title": "Version" },
9884
+ * { "title": "Grade" }
9885
+ * ]
9886
+ * } );
9887
+ * } );
9888
+ *
9889
+ * @example
9890
+ * // Using an array of objects as a data source (`data`)
9891
+ * $(document).ready( function () {
9892
+ * $('#example').dataTable( {
9893
+ * "data": [
9894
+ * {
9895
+ * "engine": "Trident",
9896
+ * "browser": "Internet Explorer 4.0",
9897
+ * "platform": "Win 95+",
9898
+ * "version": 4,
9899
+ * "grade": "X"
9900
+ * },
9901
+ * {
9902
+ * "engine": "Trident",
9903
+ * "browser": "Internet Explorer 5.0",
9904
+ * "platform": "Win 95+",
9905
+ * "version": 5,
9906
+ * "grade": "C"
9907
+ * }
9908
+ * ],
9909
+ * "columns": [
9910
+ * { "title": "Engine", "data": "engine" },
9911
+ * { "title": "Browser", "data": "browser" },
9912
+ * { "title": "Platform", "data": "platform" },
9913
+ * { "title": "Version", "data": "version" },
9914
+ * { "title": "Grade", "data": "grade" }
9915
+ * ]
9916
+ * } );
9917
+ * } );
9918
+ */
9919
+ "aaData": null,
9920
+
9921
+
9922
+ /**
9923
+ * If ordering is enabled, then DataTables will perform a first pass sort on
9924
+ * initialisation. You can define which column(s) the sort is performed
9925
+ * upon, and the sorting direction, with this variable. The `sorting` array
9926
+ * should contain an array for each column to be sorted initially containing
9927
+ * the column's index and a direction string ('asc' or 'desc').
9928
+ * @type array
9929
+ * @default [[0,'asc']]
9930
+ *
9931
+ * @dtopt Option
9932
+ * @name DataTable.defaults.order
9933
+ *
9934
+ * @example
9935
+ * // Sort by 3rd column first, and then 4th column
9936
+ * $(document).ready( function() {
9937
+ * $('#example').dataTable( {
9938
+ * "order": [[2,'asc'], [3,'desc']]
9939
+ * } );
9940
+ * } );
9941
+ *
9942
+ * // No initial sorting
9943
+ * $(document).ready( function() {
9944
+ * $('#example').dataTable( {
9945
+ * "order": []
9946
+ * } );
9947
+ * } );
9948
+ */
9949
+ "aaSorting": [[0,'asc']],
9950
+
9951
+
9952
+ /**
9953
+ * This parameter is basically identical to the `sorting` parameter, but
9954
+ * cannot be overridden by user interaction with the table. What this means
9955
+ * is that you could have a column (visible or hidden) which the sorting
9956
+ * will always be forced on first - any sorting after that (from the user)
9957
+ * will then be performed as required. This can be useful for grouping rows
9958
+ * together.
9959
+ * @type array
9960
+ * @default null
9961
+ *
9962
+ * @dtopt Option
9963
+ * @name DataTable.defaults.orderFixed
9964
+ *
9965
+ * @example
9966
+ * $(document).ready( function() {
9967
+ * $('#example').dataTable( {
9968
+ * "orderFixed": [[0,'asc']]
9969
+ * } );
9970
+ * } )
9971
+ */
9972
+ "aaSortingFixed": [],
9973
+
9974
+
9975
+ /**
9976
+ * DataTables can be instructed to load data to display in the table from a
9977
+ * Ajax source. This option defines how that Ajax call is made and where to.
9978
+ *
9979
+ * The `ajax` property has three different modes of operation, depending on
9980
+ * how it is defined. These are:
9981
+ *
9982
+ * * `string` - Set the URL from where the data should be loaded from.
9983
+ * * `object` - Define properties for `jQuery.ajax`.
9984
+ * * `function` - Custom data get function
9985
+ *
9986
+ * `string`
9987
+ * --------
9988
+ *
9989
+ * As a string, the `ajax` property simply defines the URL from which
9990
+ * DataTables will load data.
9991
+ *
9992
+ * `object`
9993
+ * --------
9994
+ *
9995
+ * As an object, the parameters in the object are passed to
9996
+ * [jQuery.ajax](http://api.jquery.com/jQuery.ajax/) allowing fine control
9997
+ * of the Ajax request. DataTables has a number of default parameters which
9998
+ * you can override using this option. Please refer to the jQuery
9999
+ * documentation for a full description of the options available, although
10000
+ * the following parameters provide additional options in DataTables or
10001
+ * require special consideration:
10002
+ *
10003
+ * * `data` - As with jQuery, `data` can be provided as an object, but it
10004
+ * can also be used as a function to manipulate the data DataTables sends
10005
+ * to the server. The function takes a single parameter, an object of
10006
+ * parameters with the values that DataTables has readied for sending. An
10007
+ * object may be returned which will be merged into the DataTables
10008
+ * defaults, or you can add the items to the object that was passed in and
10009
+ * not return anything from the function. This supersedes `fnServerParams`
10010
+ * from DataTables 1.9-.
10011
+ *
10012
+ * * `dataSrc` - By default DataTables will look for the property `data` (or
10013
+ * `aaData` for compatibility with DataTables 1.9-) when obtaining data
10014
+ * from an Ajax source or for server-side processing - this parameter
10015
+ * allows that property to be changed. You can use Javascript dotted
10016
+ * object notation to get a data source for multiple levels of nesting, or
10017
+ * it my be used as a function. As a function it takes a single parameter,
10018
+ * the JSON returned from the server, which can be manipulated as
10019
+ * required, with the returned value being that used by DataTables as the
10020
+ * data source for the table. This supersedes `sAjaxDataProp` from
10021
+ * DataTables 1.9-.
10022
+ *
10023
+ * * `success` - Should not be overridden it is used internally in
10024
+ * DataTables. To manipulate / transform the data returned by the server
10025
+ * use `ajax.dataSrc`, or use `ajax` as a function (see below).
10026
+ *
10027
+ * `function`
10028
+ * ----------
10029
+ *
10030
+ * As a function, making the Ajax call is left up to yourself allowing
10031
+ * complete control of the Ajax request. Indeed, if desired, a method other
10032
+ * than Ajax could be used to obtain the required data, such as Web storage
10033
+ * or an AIR database.
10034
+ *
10035
+ * The function is given four parameters and no return is required. The
10036
+ * parameters are:
10037
+ *
10038
+ * 1. _object_ - Data to send to the server
10039
+ * 2. _function_ - Callback function that must be executed when the required
10040
+ * data has been obtained. That data should be passed into the callback
10041
+ * as the only parameter
10042
+ * 3. _object_ - DataTables settings object for the table
10043
+ *
10044
+ * Note that this supersedes `fnServerData` from DataTables 1.9-.
10045
+ *
10046
+ * @type string|object|function
10047
+ * @default null
10048
+ *
10049
+ * @dtopt Option
10050
+ * @name DataTable.defaults.ajax
10051
+ * @since 1.10.0
10052
+ *
10053
+ * @example
10054
+ * // Get JSON data from a file via Ajax.
10055
+ * // Note DataTables expects data in the form `{ data: [ ...data... ] }` by default).
10056
+ * $('#example').dataTable( {
10057
+ * "ajax": "data.json"
10058
+ * } );
10059
+ *
10060
+ * @example
10061
+ * // Get JSON data from a file via Ajax, using `dataSrc` to change
10062
+ * // `data` to `tableData` (i.e. `{ tableData: [ ...data... ] }`)
10063
+ * $('#example').dataTable( {
10064
+ * "ajax": {
10065
+ * "url": "data.json",
10066
+ * "dataSrc": "tableData"
10067
+ * }
10068
+ * } );
10069
+ *
10070
+ * @example
10071
+ * // Get JSON data from a file via Ajax, using `dataSrc` to read data
10072
+ * // from a plain array rather than an array in an object
10073
+ * $('#example').dataTable( {
10074
+ * "ajax": {
10075
+ * "url": "data.json",
10076
+ * "dataSrc": ""
10077
+ * }
10078
+ * } );
10079
+ *
10080
+ * @example
10081
+ * // Manipulate the data returned from the server - add a link to data
10082
+ * // (note this can, should, be done using `render` for the column - this
10083
+ * // is just a simple example of how the data can be manipulated).
10084
+ * $('#example').dataTable( {
10085
+ * "ajax": {
10086
+ * "url": "data.json",
10087
+ * "dataSrc": function ( json ) {
10088
+ * for ( var i=0, ien=json.length ; i<ien ; i++ ) {
10089
+ * json[i][0] = '<a href="/message/'+json[i][0]+'>View message</a>';
10090
+ * }
10091
+ * return json;
10092
+ * }
10093
+ * }
10094
+ * } );
10095
+ *
10096
+ * @example
10097
+ * // Add data to the request
10098
+ * $('#example').dataTable( {
10099
+ * "ajax": {
10100
+ * "url": "data.json",
10101
+ * "data": function ( d ) {
10102
+ * return {
10103
+ * "extra_search": $('#extra').val()
10104
+ * };
10105
+ * }
10106
+ * }
10107
+ * } );
10108
+ *
10109
+ * @example
10110
+ * // Send request as POST
10111
+ * $('#example').dataTable( {
10112
+ * "ajax": {
10113
+ * "url": "data.json",
10114
+ * "type": "POST"
10115
+ * }
10116
+ * } );
10117
+ *
10118
+ * @example
10119
+ * // Get the data from localStorage (could interface with a form for
10120
+ * // adding, editing and removing rows).
10121
+ * $('#example').dataTable( {
10122
+ * "ajax": function (data, callback, settings) {
10123
+ * callback(
10124
+ * JSON.parse( localStorage.getItem('dataTablesData') )
10125
+ * );
10126
+ * }
10127
+ * } );
10128
+ */
10129
+ "ajax": null,
10130
+
10131
+
10132
+ /**
10133
+ * This parameter allows you to readily specify the entries in the length drop
10134
+ * down menu that DataTables shows when pagination is enabled. It can be
10135
+ * either a 1D array of options which will be used for both the displayed
10136
+ * option and the value, or a 2D array which will use the array in the first
10137
+ * position as the value, and the array in the second position as the
10138
+ * displayed options (useful for language strings such as 'All').
10139
+ *
10140
+ * Note that the `pageLength` property will be automatically set to the
10141
+ * first value given in this array, unless `pageLength` is also provided.
10142
+ * @type array
10143
+ * @default [ 10, 25, 50, 100 ]
10144
+ *
10145
+ * @dtopt Option
10146
+ * @name DataTable.defaults.lengthMenu
10147
+ *
10148
+ * @example
10149
+ * $(document).ready( function() {
10150
+ * $('#example').dataTable( {
10151
+ * "lengthMenu": [[10, 25, 50, -1], [10, 25, 50, "All"]]
10152
+ * } );
10153
+ * } );
10154
+ */
10155
+ "aLengthMenu": [ 10, 25, 50, 100 ],
10156
+
10157
+
10158
+ /**
10159
+ * The `columns` option in the initialisation parameter allows you to define
10160
+ * details about the way individual columns behave. For a full list of
10161
+ * column options that can be set, please see
10162
+ * {@link DataTable.defaults.column}. Note that if you use `columns` to
10163
+ * define your columns, you must have an entry in the array for every single
10164
+ * column that you have in your table (these can be null if you don't which
10165
+ * to specify any options).
10166
+ * @member
10167
+ *
10168
+ * @name DataTable.defaults.column
10169
+ */
10170
+ "aoColumns": null,
10171
+
10172
+ /**
10173
+ * Very similar to `columns`, `columnDefs` allows you to target a specific
10174
+ * column, multiple columns, or all columns, using the `targets` property of
10175
+ * each object in the array. This allows great flexibility when creating
10176
+ * tables, as the `columnDefs` arrays can be of any length, targeting the
10177
+ * columns you specifically want. `columnDefs` may use any of the column
10178
+ * options available: {@link DataTable.defaults.column}, but it _must_
10179
+ * have `targets` defined in each object in the array. Values in the `targets`
10180
+ * array may be:
10181
+ * <ul>
10182
+ * <li>a string - class name will be matched on the TH for the column</li>
10183
+ * <li>0 or a positive integer - column index counting from the left</li>
10184
+ * <li>a negative integer - column index counting from the right</li>
10185
+ * <li>the string "_all" - all columns (i.e. assign a default)</li>
10186
+ * </ul>
10187
+ * @member
10188
+ *
10189
+ * @name DataTable.defaults.columnDefs
10190
+ */
10191
+ "aoColumnDefs": null,
10192
+
10193
+
10194
+ /**
10195
+ * Basically the same as `search`, this parameter defines the individual column
10196
+ * filtering state at initialisation time. The array must be of the same size
10197
+ * as the number of columns, and each element be an object with the parameters
10198
+ * `search` and `escapeRegex` (the latter is optional). 'null' is also
10199
+ * accepted and the default will be used.
10200
+ * @type array
10201
+ * @default []
10202
+ *
10203
+ * @dtopt Option
10204
+ * @name DataTable.defaults.searchCols
10205
+ *
10206
+ * @example
10207
+ * $(document).ready( function() {
10208
+ * $('#example').dataTable( {
10209
+ * "searchCols": [
10210
+ * null,
10211
+ * { "search": "My filter" },
10212
+ * null,
10213
+ * { "search": "^[0-9]", "escapeRegex": false }
10214
+ * ]
10215
+ * } );
10216
+ * } )
10217
+ */
10218
+ "aoSearchCols": [],
10219
+
10220
+
10221
+ /**
10222
+ * An array of CSS classes that should be applied to displayed rows. This
10223
+ * array may be of any length, and DataTables will apply each class
10224
+ * sequentially, looping when required.
10225
+ * @type array
10226
+ * @default null <i>Will take the values determined by the `oClasses.stripe*`
10227
+ * options</i>
10228
+ *
10229
+ * @dtopt Option
10230
+ * @name DataTable.defaults.stripeClasses
10231
+ *
10232
+ * @example
10233
+ * $(document).ready( function() {
10234
+ * $('#example').dataTable( {
10235
+ * "stripeClasses": [ 'strip1', 'strip2', 'strip3' ]
10236
+ * } );
10237
+ * } )
10238
+ */
10239
+ "asStripeClasses": null,
10240
+
10241
+
10242
+ /**
10243
+ * Enable or disable automatic column width calculation. This can be disabled
10244
+ * as an optimisation (it takes some time to calculate the widths) if the
10245
+ * tables widths are passed in using `columns`.
10246
+ * @type boolean
10247
+ * @default true
10248
+ *
10249
+ * @dtopt Features
10250
+ * @name DataTable.defaults.autoWidth
10251
+ *
10252
+ * @example
10253
+ * $(document).ready( function () {
10254
+ * $('#example').dataTable( {
10255
+ * "autoWidth": false
10256
+ * } );
10257
+ * } );
10258
+ */
10259
+ "bAutoWidth": true,
10260
+
10261
+
10262
+ /**
10263
+ * Deferred rendering can provide DataTables with a huge speed boost when you
10264
+ * are using an Ajax or JS data source for the table. This option, when set to
10265
+ * true, will cause DataTables to defer the creation of the table elements for
10266
+ * each row until they are needed for a draw - saving a significant amount of
10267
+ * time.
10268
+ * @type boolean
10269
+ * @default false
10270
+ *
10271
+ * @dtopt Features
10272
+ * @name DataTable.defaults.deferRender
10273
+ *
10274
+ * @example
10275
+ * $(document).ready( function() {
10276
+ * $('#example').dataTable( {
10277
+ * "ajax": "sources/arrays.txt",
10278
+ * "deferRender": true
10279
+ * } );
10280
+ * } );
10281
+ */
10282
+ "bDeferRender": false,
10283
+
10284
+
10285
+ /**
10286
+ * Replace a DataTable which matches the given selector and replace it with
10287
+ * one which has the properties of the new initialisation object passed. If no
10288
+ * table matches the selector, then the new DataTable will be constructed as
10289
+ * per normal.
10290
+ * @type boolean
10291
+ * @default false
10292
+ *
10293
+ * @dtopt Options
10294
+ * @name DataTable.defaults.destroy
10295
+ *
10296
+ * @example
10297
+ * $(document).ready( function() {
10298
+ * $('#example').dataTable( {
10299
+ * "srollY": "200px",
10300
+ * "paginate": false
10301
+ * } );
10302
+ *
10303
+ * // Some time later....
10304
+ * $('#example').dataTable( {
10305
+ * "filter": false,
10306
+ * "destroy": true
10307
+ * } );
10308
+ * } );
10309
+ */
10310
+ "bDestroy": false,
10311
+
10312
+
10313
+ /**
10314
+ * Enable or disable filtering of data. Filtering in DataTables is "smart" in
10315
+ * that it allows the end user to input multiple words (space separated) and
10316
+ * will match a row containing those words, even if not in the order that was
10317
+ * specified (this allow matching across multiple columns). Note that if you
10318
+ * wish to use filtering in DataTables this must remain 'true' - to remove the
10319
+ * default filtering input box and retain filtering abilities, please use
10320
+ * {@link DataTable.defaults.dom}.
10321
+ * @type boolean
10322
+ * @default true
10323
+ *
10324
+ * @dtopt Features
10325
+ * @name DataTable.defaults.searching
10326
+ *
10327
+ * @example
10328
+ * $(document).ready( function () {
10329
+ * $('#example').dataTable( {
10330
+ * "searching": false
10331
+ * } );
10332
+ * } );
10333
+ */
10334
+ "bFilter": true,
10335
+
10336
+
10337
+ /**
10338
+ * Enable or disable the table information display. This shows information
10339
+ * about the data that is currently visible on the page, including information
10340
+ * about filtered data if that action is being performed.
10341
+ * @type boolean
10342
+ * @default true
10343
+ *
10344
+ * @dtopt Features
10345
+ * @name DataTable.defaults.info
10346
+ *
10347
+ * @example
10348
+ * $(document).ready( function () {
10349
+ * $('#example').dataTable( {
10350
+ * "info": false
10351
+ * } );
10352
+ * } );
10353
+ */
10354
+ "bInfo": true,
10355
+
10356
+
10357
+ /**
10358
+ * Allows the end user to select the size of a formatted page from a select
10359
+ * menu (sizes are 10, 25, 50 and 100). Requires pagination (`paginate`).
10360
+ * @type boolean
10361
+ * @default true
10362
+ *
10363
+ * @dtopt Features
10364
+ * @name DataTable.defaults.lengthChange
10365
+ *
10366
+ * @example
10367
+ * $(document).ready( function () {
10368
+ * $('#example').dataTable( {
10369
+ * "lengthChange": false
10370
+ * } );
10371
+ * } );
10372
+ */
10373
+ "bLengthChange": true,
10374
+
10375
+
10376
+ /**
10377
+ * Enable or disable pagination.
10378
+ * @type boolean
10379
+ * @default true
10380
+ *
10381
+ * @dtopt Features
10382
+ * @name DataTable.defaults.paging
10383
+ *
10384
+ * @example
10385
+ * $(document).ready( function () {
10386
+ * $('#example').dataTable( {
10387
+ * "paging": false
10388
+ * } );
10389
+ * } );
10390
+ */
10391
+ "bPaginate": true,
10392
+
10393
+
10394
+ /**
10395
+ * Enable or disable the display of a 'processing' indicator when the table is
10396
+ * being processed (e.g. a sort). This is particularly useful for tables with
10397
+ * large amounts of data where it can take a noticeable amount of time to sort
10398
+ * the entries.
10399
+ * @type boolean
10400
+ * @default false
10401
+ *
10402
+ * @dtopt Features
10403
+ * @name DataTable.defaults.processing
10404
+ *
10405
+ * @example
10406
+ * $(document).ready( function () {
10407
+ * $('#example').dataTable( {
10408
+ * "processing": true
10409
+ * } );
10410
+ * } );
10411
+ */
10412
+ "bProcessing": false,
10413
+
10414
+
10415
+ /**
10416
+ * Retrieve the DataTables object for the given selector. Note that if the
10417
+ * table has already been initialised, this parameter will cause DataTables
10418
+ * to simply return the object that has already been set up - it will not take
10419
+ * account of any changes you might have made to the initialisation object
10420
+ * passed to DataTables (setting this parameter to true is an acknowledgement
10421
+ * that you understand this). `destroy` can be used to reinitialise a table if
10422
+ * you need.
10423
+ * @type boolean
10424
+ * @default false
10425
+ *
10426
+ * @dtopt Options
10427
+ * @name DataTable.defaults.retrieve
10428
+ *
10429
+ * @example
10430
+ * $(document).ready( function() {
10431
+ * initTable();
10432
+ * tableActions();
10433
+ * } );
10434
+ *
10435
+ * function initTable ()
10436
+ * {
10437
+ * return $('#example').dataTable( {
10438
+ * "scrollY": "200px",
10439
+ * "paginate": false,
10440
+ * "retrieve": true
10441
+ * } );
10442
+ * }
10443
+ *
10444
+ * function tableActions ()
10445
+ * {
10446
+ * var table = initTable();
10447
+ * // perform API operations with oTable
10448
+ * }
10449
+ */
10450
+ "bRetrieve": false,
10451
+
10452
+
10453
+ /**
10454
+ * When vertical (y) scrolling is enabled, DataTables will force the height of
10455
+ * the table's viewport to the given height at all times (useful for layout).
10456
+ * However, this can look odd when filtering data down to a small data set,
10457
+ * and the footer is left "floating" further down. This parameter (when
10458
+ * enabled) will cause DataTables to collapse the table's viewport down when
10459
+ * the result set will fit within the given Y height.
10460
+ * @type boolean
10461
+ * @default false
10462
+ *
10463
+ * @dtopt Options
10464
+ * @name DataTable.defaults.scrollCollapse
10465
+ *
10466
+ * @example
10467
+ * $(document).ready( function() {
10468
+ * $('#example').dataTable( {
10469
+ * "scrollY": "200",
10470
+ * "scrollCollapse": true
10471
+ * } );
10472
+ * } );
10473
+ */
10474
+ "bScrollCollapse": false,
10475
+
10476
+
10477
+ /**
10478
+ * Configure DataTables to use server-side processing. Note that the
10479
+ * `ajax` parameter must also be given in order to give DataTables a
10480
+ * source to obtain the required data for each draw.
10481
+ * @type boolean
10482
+ * @default false
10483
+ *
10484
+ * @dtopt Features
10485
+ * @dtopt Server-side
10486
+ * @name DataTable.defaults.serverSide
10487
+ *
10488
+ * @example
10489
+ * $(document).ready( function () {
10490
+ * $('#example').dataTable( {
10491
+ * "serverSide": true,
10492
+ * "ajax": "xhr.php"
10493
+ * } );
10494
+ * } );
10495
+ */
10496
+ "bServerSide": false,
10497
+
10498
+
10499
+ /**
10500
+ * Enable or disable sorting of columns. Sorting of individual columns can be
10501
+ * disabled by the `sortable` option for each column.
10502
+ * @type boolean
10503
+ * @default true
10504
+ *
10505
+ * @dtopt Features
10506
+ * @name DataTable.defaults.ordering
10507
+ *
10508
+ * @example
10509
+ * $(document).ready( function () {
10510
+ * $('#example').dataTable( {
10511
+ * "ordering": false
10512
+ * } );
10513
+ * } );
10514
+ */
10515
+ "bSort": true,
10516
+
10517
+
10518
+ /**
10519
+ * Enable or display DataTables' ability to sort multiple columns at the
10520
+ * same time (activated by shift-click by the user).
10521
+ * @type boolean
10522
+ * @default true
10523
+ *
10524
+ * @dtopt Options
10525
+ * @name DataTable.defaults.orderMulti
10526
+ *
10527
+ * @example
10528
+ * // Disable multiple column sorting ability
10529
+ * $(document).ready( function () {
10530
+ * $('#example').dataTable( {
10531
+ * "orderMulti": false
10532
+ * } );
10533
+ * } );
10534
+ */
10535
+ "bSortMulti": true,
10536
+
10537
+
10538
+ /**
10539
+ * Allows control over whether DataTables should use the top (true) unique
10540
+ * cell that is found for a single column, or the bottom (false - default).
10541
+ * This is useful when using complex headers.
10542
+ * @type boolean
10543
+ * @default false
10544
+ *
10545
+ * @dtopt Options
10546
+ * @name DataTable.defaults.orderCellsTop
10547
+ *
10548
+ * @example
10549
+ * $(document).ready( function() {
10550
+ * $('#example').dataTable( {
10551
+ * "orderCellsTop": true
10552
+ * } );
10553
+ * } );
10554
+ */
10555
+ "bSortCellsTop": false,
10556
+
10557
+
10558
+ /**
10559
+ * Enable or disable the addition of the classes `sorting\_1`, `sorting\_2` and
10560
+ * `sorting\_3` to the columns which are currently being sorted on. This is
10561
+ * presented as a feature switch as it can increase processing time (while
10562
+ * classes are removed and added) so for large data sets you might want to
10563
+ * turn this off.
10564
+ * @type boolean
10565
+ * @default true
10566
+ *
10567
+ * @dtopt Features
10568
+ * @name DataTable.defaults.orderClasses
10569
+ *
10570
+ * @example
10571
+ * $(document).ready( function () {
10572
+ * $('#example').dataTable( {
10573
+ * "orderClasses": false
10574
+ * } );
10575
+ * } );
10576
+ */
10577
+ "bSortClasses": true,
10578
+
10579
+
10580
+ /**
10581
+ * Enable or disable state saving. When enabled HTML5 `localStorage` will be
10582
+ * used to save table display information such as pagination information,
10583
+ * display length, filtering and sorting. As such when the end user reloads
10584
+ * the page the display display will match what thy had previously set up.
10585
+ *
10586
+ * Due to the use of `localStorage` the default state saving is not supported
10587
+ * in IE6 or 7. If state saving is required in those browsers, use
10588
+ * `stateSaveCallback` to provide a storage solution such as cookies.
10589
+ * @type boolean
10590
+ * @default false
10591
+ *
10592
+ * @dtopt Features
10593
+ * @name DataTable.defaults.stateSave
10594
+ *
10595
+ * @example
10596
+ * $(document).ready( function () {
10597
+ * $('#example').dataTable( {
10598
+ * "stateSave": true
10599
+ * } );
10600
+ * } );
10601
+ */
10602
+ "bStateSave": false,
10603
+
10604
+
10605
+ /**
10606
+ * This function is called when a TR element is created (and all TD child
10607
+ * elements have been inserted), or registered if using a DOM source, allowing
10608
+ * manipulation of the TR element (adding classes etc).
10609
+ * @type function
10610
+ * @param {node} row "TR" element for the current row
10611
+ * @param {array} data Raw data array for this row
10612
+ * @param {int} dataIndex The index of this row in the internal aoData array
10613
+ *
10614
+ * @dtopt Callbacks
10615
+ * @name DataTable.defaults.createdRow
10616
+ *
10617
+ * @example
10618
+ * $(document).ready( function() {
10619
+ * $('#example').dataTable( {
10620
+ * "createdRow": function( row, data, dataIndex ) {
10621
+ * // Bold the grade for all 'A' grade browsers
10622
+ * if ( data[4] == "A" )
10623
+ * {
10624
+ * $('td:eq(4)', row).html( '<b>A</b>' );
10625
+ * }
10626
+ * }
10627
+ * } );
10628
+ * } );
10629
+ */
10630
+ "fnCreatedRow": null,
10631
+
10632
+
10633
+ /**
10634
+ * This function is called on every 'draw' event, and allows you to
10635
+ * dynamically modify any aspect you want about the created DOM.
10636
+ * @type function
10637
+ * @param {object} settings DataTables settings object
10638
+ *
10639
+ * @dtopt Callbacks
10640
+ * @name DataTable.defaults.drawCallback
10641
+ *
10642
+ * @example
10643
+ * $(document).ready( function() {
10644
+ * $('#example').dataTable( {
10645
+ * "drawCallback": function( settings ) {
10646
+ * alert( 'DataTables has redrawn the table' );
10647
+ * }
10648
+ * } );
10649
+ * } );
10650
+ */
10651
+ "fnDrawCallback": null,
10652
+
10653
+
10654
+ /**
10655
+ * Identical to fnHeaderCallback() but for the table footer this function
10656
+ * allows you to modify the table footer on every 'draw' event.
10657
+ * @type function
10658
+ * @param {node} foot "TR" element for the footer
10659
+ * @param {array} data Full table data (as derived from the original HTML)
10660
+ * @param {int} start Index for the current display starting point in the
10661
+ * display array
10662
+ * @param {int} end Index for the current display ending point in the
10663
+ * display array
10664
+ * @param {array int} display Index array to translate the visual position
10665
+ * to the full data array
10666
+ *
10667
+ * @dtopt Callbacks
10668
+ * @name DataTable.defaults.footerCallback
10669
+ *
10670
+ * @example
10671
+ * $(document).ready( function() {
10672
+ * $('#example').dataTable( {
10673
+ * "footerCallback": function( tfoot, data, start, end, display ) {
10674
+ * tfoot.getElementsByTagName('th')[0].innerHTML = "Starting index is "+start;
10675
+ * }
10676
+ * } );
10677
+ * } )
10678
+ */
10679
+ "fnFooterCallback": null,
10680
+
10681
+
10682
+ /**
10683
+ * When rendering large numbers in the information element for the table
10684
+ * (i.e. "Showing 1 to 10 of 57 entries") DataTables will render large numbers
10685
+ * to have a comma separator for the 'thousands' units (e.g. 1 million is
10686
+ * rendered as "1,000,000") to help readability for the end user. This
10687
+ * function will override the default method DataTables uses.
10688
+ * @type function
10689
+ * @member
10690
+ * @param {int} toFormat number to be formatted
10691
+ * @returns {string} formatted string for DataTables to show the number
10692
+ *
10693
+ * @dtopt Callbacks
10694
+ * @name DataTable.defaults.formatNumber
10695
+ *
10696
+ * @example
10697
+ * // Format a number using a single quote for the separator (note that
10698
+ * // this can also be done with the language.thousands option)
10699
+ * $(document).ready( function() {
10700
+ * $('#example').dataTable( {
10701
+ * "formatNumber": function ( toFormat ) {
10702
+ * return toFormat.toString().replace(
10703
+ * /\B(?=(\d{3})+(?!\d))/g, "'"
10704
+ * );
10705
+ * };
10706
+ * } );
10707
+ * } );
10708
+ */
10709
+ "fnFormatNumber": function ( toFormat ) {
10710
+ return toFormat.toString().replace(
10711
+ /\B(?=(\d{3})+(?!\d))/g,
10712
+ this.oLanguage.sThousands
10713
+ );
10714
+ },
10715
+
10716
+
10717
+ /**
10718
+ * This function is called on every 'draw' event, and allows you to
10719
+ * dynamically modify the header row. This can be used to calculate and
10720
+ * display useful information about the table.
10721
+ * @type function
10722
+ * @param {node} head "TR" element for the header
10723
+ * @param {array} data Full table data (as derived from the original HTML)
10724
+ * @param {int} start Index for the current display starting point in the
10725
+ * display array
10726
+ * @param {int} end Index for the current display ending point in the
10727
+ * display array
10728
+ * @param {array int} display Index array to translate the visual position
10729
+ * to the full data array
10730
+ *
10731
+ * @dtopt Callbacks
10732
+ * @name DataTable.defaults.headerCallback
10733
+ *
10734
+ * @example
10735
+ * $(document).ready( function() {
10736
+ * $('#example').dataTable( {
10737
+ * "fheaderCallback": function( head, data, start, end, display ) {
10738
+ * head.getElementsByTagName('th')[0].innerHTML = "Displaying "+(end-start)+" records";
10739
+ * }
10740
+ * } );
10741
+ * } )
10742
+ */
10743
+ "fnHeaderCallback": null,
10744
+
10745
+
10746
+ /**
10747
+ * The information element can be used to convey information about the current
10748
+ * state of the table. Although the internationalisation options presented by
10749
+ * DataTables are quite capable of dealing with most customisations, there may
10750
+ * be times where you wish to customise the string further. This callback
10751
+ * allows you to do exactly that.
10752
+ * @type function
10753
+ * @param {object} oSettings DataTables settings object
10754
+ * @param {int} start Starting position in data for the draw
10755
+ * @param {int} end End position in data for the draw
10756
+ * @param {int} max Total number of rows in the table (regardless of
10757
+ * filtering)
10758
+ * @param {int} total Total number of rows in the data set, after filtering
10759
+ * @param {string} pre The string that DataTables has formatted using it's
10760
+ * own rules
10761
+ * @returns {string} The string to be displayed in the information element.
10762
+ *
10763
+ * @dtopt Callbacks
10764
+ * @name DataTable.defaults.infoCallback
10765
+ *
10766
+ * @example
10767
+ * $('#example').dataTable( {
10768
+ * "infoCallback": function( settings, start, end, max, total, pre ) {
10769
+ * return start +" to "+ end;
10770
+ * }
10771
+ * } );
10772
+ */
10773
+ "fnInfoCallback": null,
10774
+
10775
+
10776
+ /**
10777
+ * Called when the table has been initialised. Normally DataTables will
10778
+ * initialise sequentially and there will be no need for this function,
10779
+ * however, this does not hold true when using external language information
10780
+ * since that is obtained using an async XHR call.
10781
+ * @type function
10782
+ * @param {object} settings DataTables settings object
10783
+ * @param {object} json The JSON object request from the server - only
10784
+ * present if client-side Ajax sourced data is used
10785
+ *
10786
+ * @dtopt Callbacks
10787
+ * @name DataTable.defaults.initComplete
10788
+ *
10789
+ * @example
10790
+ * $(document).ready( function() {
10791
+ * $('#example').dataTable( {
10792
+ * "initComplete": function(settings, json) {
10793
+ * alert( 'DataTables has finished its initialisation.' );
10794
+ * }
10795
+ * } );
10796
+ * } )
10797
+ */
10798
+ "fnInitComplete": null,
10799
+
10800
+
10801
+ /**
10802
+ * Called at the very start of each table draw and can be used to cancel the
10803
+ * draw by returning false, any other return (including undefined) results in
10804
+ * the full draw occurring).
10805
+ * @type function
10806
+ * @param {object} settings DataTables settings object
10807
+ * @returns {boolean} False will cancel the draw, anything else (including no
10808
+ * return) will allow it to complete.
10809
+ *
10810
+ * @dtopt Callbacks
10811
+ * @name DataTable.defaults.preDrawCallback
10812
+ *
10813
+ * @example
10814
+ * $(document).ready( function() {
10815
+ * $('#example').dataTable( {
10816
+ * "preDrawCallback": function( settings ) {
10817
+ * if ( $('#test').val() == 1 ) {
10818
+ * return false;
10819
+ * }
10820
+ * }
10821
+ * } );
10822
+ * } );
10823
+ */
10824
+ "fnPreDrawCallback": null,
10825
+
10826
+
10827
+ /**
10828
+ * This function allows you to 'post process' each row after it have been
10829
+ * generated for each table draw, but before it is rendered on screen. This
10830
+ * function might be used for setting the row class name etc.
10831
+ * @type function
10832
+ * @param {node} row "TR" element for the current row
10833
+ * @param {array} data Raw data array for this row
10834
+ * @param {int} displayIndex The display index for the current table draw
10835
+ * @param {int} displayIndexFull The index of the data in the full list of
10836
+ * rows (after filtering)
10837
+ *
10838
+ * @dtopt Callbacks
10839
+ * @name DataTable.defaults.rowCallback
10840
+ *
10841
+ * @example
10842
+ * $(document).ready( function() {
10843
+ * $('#example').dataTable( {
10844
+ * "rowCallback": function( row, data, displayIndex, displayIndexFull ) {
10845
+ * // Bold the grade for all 'A' grade browsers
10846
+ * if ( data[4] == "A" ) {
10847
+ * $('td:eq(4)', row).html( '<b>A</b>' );
10848
+ * }
10849
+ * }
10850
+ * } );
10851
+ * } );
10852
+ */
10853
+ "fnRowCallback": null,
10854
+
10855
+
10856
+ /**
10857
+ * __Deprecated__ The functionality provided by this parameter has now been
10858
+ * superseded by that provided through `ajax`, which should be used instead.
10859
+ *
10860
+ * This parameter allows you to override the default function which obtains
10861
+ * the data from the server so something more suitable for your application.
10862
+ * For example you could use POST data, or pull information from a Gears or
10863
+ * AIR database.
10864
+ * @type function
10865
+ * @member
10866
+ * @param {string} source HTTP source to obtain the data from (`ajax`)
10867
+ * @param {array} data A key/value pair object containing the data to send
10868
+ * to the server
10869
+ * @param {function} callback to be called on completion of the data get
10870
+ * process that will draw the data on the page.
10871
+ * @param {object} settings DataTables settings object
10872
+ *
10873
+ * @dtopt Callbacks
10874
+ * @dtopt Server-side
10875
+ * @name DataTable.defaults.serverData
10876
+ *
10877
+ * @deprecated 1.10. Please use `ajax` for this functionality now.
10878
+ */
10879
+ "fnServerData": null,
10880
+
10881
+
10882
+ /**
10883
+ * __Deprecated__ The functionality provided by this parameter has now been
10884
+ * superseded by that provided through `ajax`, which should be used instead.
10885
+ *
10886
+ * It is often useful to send extra data to the server when making an Ajax
10887
+ * request - for example custom filtering information, and this callback
10888
+ * function makes it trivial to send extra information to the server. The
10889
+ * passed in parameter is the data set that has been constructed by
10890
+ * DataTables, and you can add to this or modify it as you require.
10891
+ * @type function
10892
+ * @param {array} data Data array (array of objects which are name/value
10893
+ * pairs) that has been constructed by DataTables and will be sent to the
10894
+ * server. In the case of Ajax sourced data with server-side processing
10895
+ * this will be an empty array, for server-side processing there will be a
10896
+ * significant number of parameters!
10897
+ * @returns {undefined} Ensure that you modify the data array passed in,
10898
+ * as this is passed by reference.
10899
+ *
10900
+ * @dtopt Callbacks
10901
+ * @dtopt Server-side
10902
+ * @name DataTable.defaults.serverParams
10903
+ *
10904
+ * @deprecated 1.10. Please use `ajax` for this functionality now.
10905
+ */
10906
+ "fnServerParams": null,
10907
+
10908
+
10909
+ /**
10910
+ * Load the table state. With this function you can define from where, and how, the
10911
+ * state of a table is loaded. By default DataTables will load from `localStorage`
10912
+ * but you might wish to use a server-side database or cookies.
10913
+ * @type function
10914
+ * @member
10915
+ * @param {object} settings DataTables settings object
10916
+ * @param {object} callback Callback that can be executed when done. It
10917
+ * should be passed the loaded state object.
10918
+ * @return {object} The DataTables state object to be loaded
10919
+ *
10920
+ * @dtopt Callbacks
10921
+ * @name DataTable.defaults.stateLoadCallback
10922
+ *
10923
+ * @example
10924
+ * $(document).ready( function() {
10925
+ * $('#example').dataTable( {
10926
+ * "stateSave": true,
10927
+ * "stateLoadCallback": function (settings, callback) {
10928
+ * $.ajax( {
10929
+ * "url": "/state_load",
10930
+ * "dataType": "json",
10931
+ * "success": function (json) {
10932
+ * callback( json );
10933
+ * }
10934
+ * } );
10935
+ * }
10936
+ * } );
10937
+ * } );
10938
+ */
10939
+ "fnStateLoadCallback": function ( settings ) {
10940
+ try {
10941
+ return JSON.parse(
10942
+ (settings.iStateDuration === -1 ? sessionStorage : localStorage).getItem(
10943
+ 'DataTables_'+settings.sInstance+'_'+location.pathname
10944
+ )
10945
+ );
10946
+ } catch (e) {}
10947
+ },
10948
+
10949
+
10950
+ /**
10951
+ * Callback which allows modification of the saved state prior to loading that state.
10952
+ * This callback is called when the table is loading state from the stored data, but
10953
+ * prior to the settings object being modified by the saved state. Note that for
10954
+ * plug-in authors, you should use the `stateLoadParams` event to load parameters for
10955
+ * a plug-in.
10956
+ * @type function
10957
+ * @param {object} settings DataTables settings object
10958
+ * @param {object} data The state object that is to be loaded
10959
+ *
10960
+ * @dtopt Callbacks
10961
+ * @name DataTable.defaults.stateLoadParams
10962
+ *
10963
+ * @example
10964
+ * // Remove a saved filter, so filtering is never loaded
10965
+ * $(document).ready( function() {
10966
+ * $('#example').dataTable( {
10967
+ * "stateSave": true,
10968
+ * "stateLoadParams": function (settings, data) {
10969
+ * data.oSearch.sSearch = "";
10970
+ * }
10971
+ * } );
10972
+ * } );
10973
+ *
10974
+ * @example
10975
+ * // Disallow state loading by returning false
10976
+ * $(document).ready( function() {
10977
+ * $('#example').dataTable( {
10978
+ * "stateSave": true,
10979
+ * "stateLoadParams": function (settings, data) {
10980
+ * return false;
10981
+ * }
10982
+ * } );
10983
+ * } );
10984
+ */
10985
+ "fnStateLoadParams": null,
10986
+
10987
+
10988
+ /**
10989
+ * Callback that is called when the state has been loaded from the state saving method
10990
+ * and the DataTables settings object has been modified as a result of the loaded state.
10991
+ * @type function
10992
+ * @param {object} settings DataTables settings object
10993
+ * @param {object} data The state object that was loaded
10994
+ *
10995
+ * @dtopt Callbacks
10996
+ * @name DataTable.defaults.stateLoaded
10997
+ *
10998
+ * @example
10999
+ * // Show an alert with the filtering value that was saved
11000
+ * $(document).ready( function() {
11001
+ * $('#example').dataTable( {
11002
+ * "stateSave": true,
11003
+ * "stateLoaded": function (settings, data) {
11004
+ * alert( 'Saved filter was: '+data.oSearch.sSearch );
11005
+ * }
11006
+ * } );
11007
+ * } );
11008
+ */
11009
+ "fnStateLoaded": null,
11010
+
11011
+
11012
+ /**
11013
+ * Save the table state. This function allows you to define where and how the state
11014
+ * information for the table is stored By default DataTables will use `localStorage`
11015
+ * but you might wish to use a server-side database or cookies.
11016
+ * @type function
11017
+ * @member
11018
+ * @param {object} settings DataTables settings object
11019
+ * @param {object} data The state object to be saved
11020
+ *
11021
+ * @dtopt Callbacks
11022
+ * @name DataTable.defaults.stateSaveCallback
11023
+ *
11024
+ * @example
11025
+ * $(document).ready( function() {
11026
+ * $('#example').dataTable( {
11027
+ * "stateSave": true,
11028
+ * "stateSaveCallback": function (settings, data) {
11029
+ * // Send an Ajax request to the server with the state object
11030
+ * $.ajax( {
11031
+ * "url": "/state_save",
11032
+ * "data": data,
11033
+ * "dataType": "json",
11034
+ * "method": "POST"
11035
+ * "success": function () {}
11036
+ * } );
11037
+ * }
11038
+ * } );
11039
+ * } );
11040
+ */
11041
+ "fnStateSaveCallback": function ( settings, data ) {
11042
+ try {
11043
+ (settings.iStateDuration === -1 ? sessionStorage : localStorage).setItem(
11044
+ 'DataTables_'+settings.sInstance+'_'+location.pathname,
11045
+ JSON.stringify( data )
11046
+ );
11047
+ } catch (e) {}
11048
+ },
11049
+
11050
+
11051
+ /**
11052
+ * Callback which allows modification of the state to be saved. Called when the table
11053
+ * has changed state a new state save is required. This method allows modification of
11054
+ * the state saving object prior to actually doing the save, including addition or
11055
+ * other state properties or modification. Note that for plug-in authors, you should
11056
+ * use the `stateSaveParams` event to save parameters for a plug-in.
11057
+ * @type function
11058
+ * @param {object} settings DataTables settings object
11059
+ * @param {object} data The state object to be saved
11060
+ *
11061
+ * @dtopt Callbacks
11062
+ * @name DataTable.defaults.stateSaveParams
11063
+ *
11064
+ * @example
11065
+ * // Remove a saved filter, so filtering is never saved
11066
+ * $(document).ready( function() {
11067
+ * $('#example').dataTable( {
11068
+ * "stateSave": true,
11069
+ * "stateSaveParams": function (settings, data) {
11070
+ * data.oSearch.sSearch = "";
11071
+ * }
11072
+ * } );
11073
+ * } );
11074
+ */
11075
+ "fnStateSaveParams": null,
11076
+
11077
+
11078
+ /**
11079
+ * Duration for which the saved state information is considered valid. After this period
11080
+ * has elapsed the state will be returned to the default.
11081
+ * Value is given in seconds.
11082
+ * @type int
11083
+ * @default 7200 <i>(2 hours)</i>
11084
+ *
11085
+ * @dtopt Options
11086
+ * @name DataTable.defaults.stateDuration
11087
+ *
11088
+ * @example
11089
+ * $(document).ready( function() {
11090
+ * $('#example').dataTable( {
11091
+ * "stateDuration": 60*60*24; // 1 day
11092
+ * } );
11093
+ * } )
11094
+ */
11095
+ "iStateDuration": 7200,
11096
+
11097
+
11098
+ /**
11099
+ * When enabled DataTables will not make a request to the server for the first
11100
+ * page draw - rather it will use the data already on the page (no sorting etc
11101
+ * will be applied to it), thus saving on an XHR at load time. `deferLoading`
11102
+ * is used to indicate that deferred loading is required, but it is also used
11103
+ * to tell DataTables how many records there are in the full table (allowing
11104
+ * the information element and pagination to be displayed correctly). In the case
11105
+ * where a filtering is applied to the table on initial load, this can be
11106
+ * indicated by giving the parameter as an array, where the first element is
11107
+ * the number of records available after filtering and the second element is the
11108
+ * number of records without filtering (allowing the table information element
11109
+ * to be shown correctly).
11110
+ * @type int | array
11111
+ * @default null
11112
+ *
11113
+ * @dtopt Options
11114
+ * @name DataTable.defaults.deferLoading
11115
+ *
11116
+ * @example
11117
+ * // 57 records available in the table, no filtering applied
11118
+ * $(document).ready( function() {
11119
+ * $('#example').dataTable( {
11120
+ * "serverSide": true,
11121
+ * "ajax": "scripts/server_processing.php",
11122
+ * "deferLoading": 57
11123
+ * } );
11124
+ * } );
11125
+ *
11126
+ * @example
11127
+ * // 57 records after filtering, 100 without filtering (an initial filter applied)
11128
+ * $(document).ready( function() {
11129
+ * $('#example').dataTable( {
11130
+ * "serverSide": true,
11131
+ * "ajax": "scripts/server_processing.php",
11132
+ * "deferLoading": [ 57, 100 ],
11133
+ * "search": {
11134
+ * "search": "my_filter"
11135
+ * }
11136
+ * } );
11137
+ * } );
11138
+ */
11139
+ "iDeferLoading": null,
11140
+
11141
+
11142
+ /**
11143
+ * Number of rows to display on a single page when using pagination. If
11144
+ * feature enabled (`lengthChange`) then the end user will be able to override
11145
+ * this to a custom setting using a pop-up menu.
11146
+ * @type int
11147
+ * @default 10
11148
+ *
11149
+ * @dtopt Options
11150
+ * @name DataTable.defaults.pageLength
11151
+ *
11152
+ * @example
11153
+ * $(document).ready( function() {
11154
+ * $('#example').dataTable( {
11155
+ * "pageLength": 50
11156
+ * } );
11157
+ * } )
11158
+ */
11159
+ "iDisplayLength": 10,
11160
+
11161
+
11162
+ /**
11163
+ * Define the starting point for data display when using DataTables with
11164
+ * pagination. Note that this parameter is the number of records, rather than
11165
+ * the page number, so if you have 10 records per page and want to start on
11166
+ * the third page, it should be "20".
11167
+ * @type int
11168
+ * @default 0
11169
+ *
11170
+ * @dtopt Options
11171
+ * @name DataTable.defaults.displayStart
11172
+ *
11173
+ * @example
11174
+ * $(document).ready( function() {
11175
+ * $('#example').dataTable( {
11176
+ * "displayStart": 20
11177
+ * } );
11178
+ * } )
11179
+ */
11180
+ "iDisplayStart": 0,
11181
+
11182
+
11183
+ /**
11184
+ * By default DataTables allows keyboard navigation of the table (sorting, paging,
11185
+ * and filtering) by adding a `tabindex` attribute to the required elements. This
11186
+ * allows you to tab through the controls and press the enter key to activate them.
11187
+ * The tabindex is default 0, meaning that the tab follows the flow of the document.
11188
+ * You can overrule this using this parameter if you wish. Use a value of -1 to
11189
+ * disable built-in keyboard navigation.
11190
+ * @type int
11191
+ * @default 0
11192
+ *
11193
+ * @dtopt Options
11194
+ * @name DataTable.defaults.tabIndex
11195
+ *
11196
+ * @example
11197
+ * $(document).ready( function() {
11198
+ * $('#example').dataTable( {
11199
+ * "tabIndex": 1
11200
+ * } );
11201
+ * } );
11202
+ */
11203
+ "iTabIndex": 0,
11204
+
11205
+
11206
+ /**
11207
+ * Classes that DataTables assigns to the various components and features
11208
+ * that it adds to the HTML table. This allows classes to be configured
11209
+ * during initialisation in addition to through the static
11210
+ * {@link DataTable.ext.oStdClasses} object).
11211
+ * @namespace
11212
+ * @name DataTable.defaults.classes
11213
+ */
11214
+ "oClasses": {},
11215
+
11216
+
11217
+ /**
11218
+ * All strings that DataTables uses in the user interface that it creates
11219
+ * are defined in this object, allowing you to modified them individually or
11220
+ * completely replace them all as required.
11221
+ * @namespace
11222
+ * @name DataTable.defaults.language
11223
+ */
11224
+ "oLanguage": {
11225
+ /**
11226
+ * Strings that are used for WAI-ARIA labels and controls only (these are not
11227
+ * actually visible on the page, but will be read by screenreaders, and thus
11228
+ * must be internationalised as well).
11229
+ * @namespace
11230
+ * @name DataTable.defaults.language.aria
11231
+ */
11232
+ "oAria": {
11233
+ /**
11234
+ * ARIA label that is added to the table headers when the column may be
11235
+ * sorted ascending by activing the column (click or return when focused).
11236
+ * Note that the column header is prefixed to this string.
11237
+ * @type string
11238
+ * @default : activate to sort column ascending
11239
+ *
11240
+ * @dtopt Language
11241
+ * @name DataTable.defaults.language.aria.sortAscending
11242
+ *
11243
+ * @example
11244
+ * $(document).ready( function() {
11245
+ * $('#example').dataTable( {
11246
+ * "language": {
11247
+ * "aria": {
11248
+ * "sortAscending": " - click/return to sort ascending"
11249
+ * }
11250
+ * }
11251
+ * } );
11252
+ * } );
11253
+ */
11254
+ "sSortAscending": ": activate to sort column ascending",
11255
+
11256
+ /**
11257
+ * ARIA label that is added to the table headers when the column may be
11258
+ * sorted descending by activing the column (click or return when focused).
11259
+ * Note that the column header is prefixed to this string.
11260
+ * @type string
11261
+ * @default : activate to sort column ascending
11262
+ *
11263
+ * @dtopt Language
11264
+ * @name DataTable.defaults.language.aria.sortDescending
11265
+ *
11266
+ * @example
11267
+ * $(document).ready( function() {
11268
+ * $('#example').dataTable( {
11269
+ * "language": {
11270
+ * "aria": {
11271
+ * "sortDescending": " - click/return to sort descending"
11272
+ * }
11273
+ * }
11274
+ * } );
11275
+ * } );
11276
+ */
11277
+ "sSortDescending": ": activate to sort column descending"
11278
+ },
11279
+
11280
+ /**
11281
+ * Pagination string used by DataTables for the built-in pagination
11282
+ * control types.
11283
+ * @namespace
11284
+ * @name DataTable.defaults.language.paginate
11285
+ */
11286
+ "oPaginate": {
11287
+ /**
11288
+ * Text to use when using the 'full_numbers' type of pagination for the
11289
+ * button to take the user to the first page.
11290
+ * @type string
11291
+ * @default First
11292
+ *
11293
+ * @dtopt Language
11294
+ * @name DataTable.defaults.language.paginate.first
11295
+ *
11296
+ * @example
11297
+ * $(document).ready( function() {
11298
+ * $('#example').dataTable( {
11299
+ * "language": {
11300
+ * "paginate": {
11301
+ * "first": "First page"
11302
+ * }
11303
+ * }
11304
+ * } );
11305
+ * } );
11306
+ */
11307
+ "sFirst": "First",
11308
+
11309
+
11310
+ /**
11311
+ * Text to use when using the 'full_numbers' type of pagination for the
11312
+ * button to take the user to the last page.
11313
+ * @type string
11314
+ * @default Last
11315
+ *
11316
+ * @dtopt Language
11317
+ * @name DataTable.defaults.language.paginate.last
11318
+ *
11319
+ * @example
11320
+ * $(document).ready( function() {
11321
+ * $('#example').dataTable( {
11322
+ * "language": {
11323
+ * "paginate": {
11324
+ * "last": "Last page"
11325
+ * }
11326
+ * }
11327
+ * } );
11328
+ * } );
11329
+ */
11330
+ "sLast": "Last",
11331
+
11332
+
11333
+ /**
11334
+ * Text to use for the 'next' pagination button (to take the user to the
11335
+ * next page).
11336
+ * @type string
11337
+ * @default Next
11338
+ *
11339
+ * @dtopt Language
11340
+ * @name DataTable.defaults.language.paginate.next
11341
+ *
11342
+ * @example
11343
+ * $(document).ready( function() {
11344
+ * $('#example').dataTable( {
11345
+ * "language": {
11346
+ * "paginate": {
11347
+ * "next": "Next page"
11348
+ * }
11349
+ * }
11350
+ * } );
11351
+ * } );
11352
+ */
11353
+ "sNext": "Next",
11354
+
11355
+
11356
+ /**
11357
+ * Text to use for the 'previous' pagination button (to take the user to
11358
+ * the previous page).
11359
+ * @type string
11360
+ * @default Previous
11361
+ *
11362
+ * @dtopt Language
11363
+ * @name DataTable.defaults.language.paginate.previous
11364
+ *
11365
+ * @example
11366
+ * $(document).ready( function() {
11367
+ * $('#example').dataTable( {
11368
+ * "language": {
11369
+ * "paginate": {
11370
+ * "previous": "Previous page"
11371
+ * }
11372
+ * }
11373
+ * } );
11374
+ * } );
11375
+ */
11376
+ "sPrevious": "Previous"
11377
+ },
11378
+
11379
+ /**
11380
+ * This string is shown in preference to `zeroRecords` when the table is
11381
+ * empty of data (regardless of filtering). Note that this is an optional
11382
+ * parameter - if it is not given, the value of `zeroRecords` will be used
11383
+ * instead (either the default or given value).
11384
+ * @type string
11385
+ * @default No data available in table
11386
+ *
11387
+ * @dtopt Language
11388
+ * @name DataTable.defaults.language.emptyTable
11389
+ *
11390
+ * @example
11391
+ * $(document).ready( function() {
11392
+ * $('#example').dataTable( {
11393
+ * "language": {
11394
+ * "emptyTable": "No data available in table"
11395
+ * }
11396
+ * } );
11397
+ * } );
11398
+ */
11399
+ "sEmptyTable": "No data available in table",
11400
+
11401
+
11402
+ /**
11403
+ * This string gives information to the end user about the information
11404
+ * that is current on display on the page. The following tokens can be
11405
+ * used in the string and will be dynamically replaced as the table
11406
+ * display updates. This tokens can be placed anywhere in the string, or
11407
+ * removed as needed by the language requires:
11408
+ *
11409
+ * * `\_START\_` - Display index of the first record on the current page
11410
+ * * `\_END\_` - Display index of the last record on the current page
11411
+ * * `\_TOTAL\_` - Number of records in the table after filtering
11412
+ * * `\_MAX\_` - Number of records in the table without filtering
11413
+ * * `\_PAGE\_` - Current page number
11414
+ * * `\_PAGES\_` - Total number of pages of data in the table
11415
+ *
11416
+ * @type string
11417
+ * @default Showing _START_ to _END_ of _TOTAL_ entries
11418
+ *
11419
+ * @dtopt Language
11420
+ * @name DataTable.defaults.language.info
11421
+ *
11422
+ * @example
11423
+ * $(document).ready( function() {
11424
+ * $('#example').dataTable( {
11425
+ * "language": {
11426
+ * "info": "Showing page _PAGE_ of _PAGES_"
11427
+ * }
11428
+ * } );
11429
+ * } );
11430
+ */
11431
+ "sInfo": "Showing _START_ to _END_ of _TOTAL_ entries",
11432
+
11433
+
11434
+ /**
11435
+ * Display information string for when the table is empty. Typically the
11436
+ * format of this string should match `info`.
11437
+ * @type string
11438
+ * @default Showing 0 to 0 of 0 entries
11439
+ *
11440
+ * @dtopt Language
11441
+ * @name DataTable.defaults.language.infoEmpty
11442
+ *
11443
+ * @example
11444
+ * $(document).ready( function() {
11445
+ * $('#example').dataTable( {
11446
+ * "language": {
11447
+ * "infoEmpty": "No entries to show"
11448
+ * }
11449
+ * } );
11450
+ * } );
11451
+ */
11452
+ "sInfoEmpty": "Showing 0 to 0 of 0 entries",
11453
+
11454
+
11455
+ /**
11456
+ * When a user filters the information in a table, this string is appended
11457
+ * to the information (`info`) to give an idea of how strong the filtering
11458
+ * is. The variable _MAX_ is dynamically updated.
11459
+ * @type string
11460
+ * @default (filtered from _MAX_ total entries)
11461
+ *
11462
+ * @dtopt Language
11463
+ * @name DataTable.defaults.language.infoFiltered
11464
+ *
11465
+ * @example
11466
+ * $(document).ready( function() {
11467
+ * $('#example').dataTable( {
11468
+ * "language": {
11469
+ * "infoFiltered": " - filtering from _MAX_ records"
11470
+ * }
11471
+ * } );
11472
+ * } );
11473
+ */
11474
+ "sInfoFiltered": "(filtered from _MAX_ total entries)",
11475
+
11476
+
11477
+ /**
11478
+ * If can be useful to append extra information to the info string at times,
11479
+ * and this variable does exactly that. This information will be appended to
11480
+ * the `info` (`infoEmpty` and `infoFiltered` in whatever combination they are
11481
+ * being used) at all times.
11482
+ * @type string
11483
+ * @default <i>Empty string</i>
11484
+ *
11485
+ * @dtopt Language
11486
+ * @name DataTable.defaults.language.infoPostFix
11487
+ *
11488
+ * @example
11489
+ * $(document).ready( function() {
11490
+ * $('#example').dataTable( {
11491
+ * "language": {
11492
+ * "infoPostFix": "All records shown are derived from real information."
11493
+ * }
11494
+ * } );
11495
+ * } );
11496
+ */
11497
+ "sInfoPostFix": "",
11498
+
11499
+
11500
+ /**
11501
+ * This decimal place operator is a little different from the other
11502
+ * language options since DataTables doesn't output floating point
11503
+ * numbers, so it won't ever use this for display of a number. Rather,
11504
+ * what this parameter does is modify the sort methods of the table so
11505
+ * that numbers which are in a format which has a character other than
11506
+ * a period (`.`) as a decimal place will be sorted numerically.
11507
+ *
11508
+ * Note that numbers with different decimal places cannot be shown in
11509
+ * the same table and still be sortable, the table must be consistent.
11510
+ * However, multiple different tables on the page can use different
11511
+ * decimal place characters.
11512
+ * @type string
11513
+ * @default
11514
+ *
11515
+ * @dtopt Language
11516
+ * @name DataTable.defaults.language.decimal
11517
+ *
11518
+ * @example
11519
+ * $(document).ready( function() {
11520
+ * $('#example').dataTable( {
11521
+ * "language": {
11522
+ * "decimal": ","
11523
+ * "thousands": "."
11524
+ * }
11525
+ * } );
11526
+ * } );
11527
+ */
11528
+ "sDecimal": "",
11529
+
11530
+
11531
+ /**
11532
+ * DataTables has a build in number formatter (`formatNumber`) which is
11533
+ * used to format large numbers that are used in the table information.
11534
+ * By default a comma is used, but this can be trivially changed to any
11535
+ * character you wish with this parameter.
11536
+ * @type string
11537
+ * @default ,
11538
+ *
11539
+ * @dtopt Language
11540
+ * @name DataTable.defaults.language.thousands
11541
+ *
11542
+ * @example
11543
+ * $(document).ready( function() {
11544
+ * $('#example').dataTable( {
11545
+ * "language": {
11546
+ * "thousands": "'"
11547
+ * }
11548
+ * } );
11549
+ * } );
11550
+ */
11551
+ "sThousands": ",",
11552
+
11553
+
11554
+ /**
11555
+ * Detail the action that will be taken when the drop down menu for the
11556
+ * pagination length option is changed. The '_MENU_' variable is replaced
11557
+ * with a default select list of 10, 25, 50 and 100, and can be replaced
11558
+ * with a custom select box if required.
11559
+ * @type string
11560
+ * @default Show _MENU_ entries
11561
+ *
11562
+ * @dtopt Language
11563
+ * @name DataTable.defaults.language.lengthMenu
11564
+ *
11565
+ * @example
11566
+ * // Language change only
11567
+ * $(document).ready( function() {
11568
+ * $('#example').dataTable( {
11569
+ * "language": {
11570
+ * "lengthMenu": "Display _MENU_ records"
11571
+ * }
11572
+ * } );
11573
+ * } );
11574
+ *
11575
+ * @example
11576
+ * // Language and options change
11577
+ * $(document).ready( function() {
11578
+ * $('#example').dataTable( {
11579
+ * "language": {
11580
+ * "lengthMenu": 'Display <select>'+
11581
+ * '<option value="10">10</option>'+
11582
+ * '<option value="20">20</option>'+
11583
+ * '<option value="30">30</option>'+
11584
+ * '<option value="40">40</option>'+
11585
+ * '<option value="50">50</option>'+
11586
+ * '<option value="-1">All</option>'+
11587
+ * '</select> records'
11588
+ * }
11589
+ * } );
11590
+ * } );
11591
+ */
11592
+ "sLengthMenu": "Show _MENU_ entries",
11593
+
11594
+
11595
+ /**
11596
+ * When using Ajax sourced data and during the first draw when DataTables is
11597
+ * gathering the data, this message is shown in an empty row in the table to
11598
+ * indicate to the end user the the data is being loaded. Note that this
11599
+ * parameter is not used when loading data by server-side processing, just
11600
+ * Ajax sourced data with client-side processing.
11601
+ * @type string
11602
+ * @default Loading...
11603
+ *
11604
+ * @dtopt Language
11605
+ * @name DataTable.defaults.language.loadingRecords
11606
+ *
11607
+ * @example
11608
+ * $(document).ready( function() {
11609
+ * $('#example').dataTable( {
11610
+ * "language": {
11611
+ * "loadingRecords": "Please wait - loading..."
11612
+ * }
11613
+ * } );
11614
+ * } );
11615
+ */
11616
+ "sLoadingRecords": "Loading...",
11617
+
11618
+
11619
+ /**
11620
+ * Text which is displayed when the table is processing a user action
11621
+ * (usually a sort command or similar).
11622
+ * @type string
11623
+ * @default Processing...
11624
+ *
11625
+ * @dtopt Language
11626
+ * @name DataTable.defaults.language.processing
11627
+ *
11628
+ * @example
11629
+ * $(document).ready( function() {
11630
+ * $('#example').dataTable( {
11631
+ * "language": {
11632
+ * "processing": "DataTables is currently busy"
11633
+ * }
11634
+ * } );
11635
+ * } );
11636
+ */
11637
+ "sProcessing": "Processing...",
11638
+
11639
+
11640
+ /**
11641
+ * Details the actions that will be taken when the user types into the
11642
+ * filtering input text box. The variable "_INPUT_", if used in the string,
11643
+ * is replaced with the HTML text box for the filtering input allowing
11644
+ * control over where it appears in the string. If "_INPUT_" is not given
11645
+ * then the input box is appended to the string automatically.
11646
+ * @type string
11647
+ * @default Search:
11648
+ *
11649
+ * @dtopt Language
11650
+ * @name DataTable.defaults.language.search
11651
+ *
11652
+ * @example
11653
+ * // Input text box will be appended at the end automatically
11654
+ * $(document).ready( function() {
11655
+ * $('#example').dataTable( {
11656
+ * "language": {
11657
+ * "search": "Filter records:"
11658
+ * }
11659
+ * } );
11660
+ * } );
11661
+ *
11662
+ * @example
11663
+ * // Specify where the filter should appear
11664
+ * $(document).ready( function() {
11665
+ * $('#example').dataTable( {
11666
+ * "language": {
11667
+ * "search": "Apply filter _INPUT_ to table"
11668
+ * }
11669
+ * } );
11670
+ * } );
11671
+ */
11672
+ "sSearch": "Search:",
11673
+
11674
+
11675
+ /**
11676
+ * Assign a `placeholder` attribute to the search `input` element
11677
+ * @type string
11678
+ * @default
11679
+ *
11680
+ * @dtopt Language
11681
+ * @name DataTable.defaults.language.searchPlaceholder
11682
+ */
11683
+ "sSearchPlaceholder": "",
11684
+
11685
+
11686
+ /**
11687
+ * All of the language information can be stored in a file on the
11688
+ * server-side, which DataTables will look up if this parameter is passed.
11689
+ * It must store the URL of the language file, which is in a JSON format,
11690
+ * and the object has the same properties as the oLanguage object in the
11691
+ * initialiser object (i.e. the above parameters). Please refer to one of
11692
+ * the example language files to see how this works in action.
11693
+ * @type string
11694
+ * @default <i>Empty string - i.e. disabled</i>
11695
+ *
11696
+ * @dtopt Language
11697
+ * @name DataTable.defaults.language.url
11698
+ *
11699
+ * @example
11700
+ * $(document).ready( function() {
11701
+ * $('#example').dataTable( {
11702
+ * "language": {
11703
+ * "url": "http://www.sprymedia.co.uk/dataTables/lang.txt"
11704
+ * }
11705
+ * } );
11706
+ * } );
11707
+ */
11708
+ "sUrl": "",
11709
+
11710
+
11711
+ /**
11712
+ * Text shown inside the table records when the is no information to be
11713
+ * displayed after filtering. `emptyTable` is shown when there is simply no
11714
+ * information in the table at all (regardless of filtering).
11715
+ * @type string
11716
+ * @default No matching records found
11717
+ *
11718
+ * @dtopt Language
11719
+ * @name DataTable.defaults.language.zeroRecords
11720
+ *
11721
+ * @example
11722
+ * $(document).ready( function() {
11723
+ * $('#example').dataTable( {
11724
+ * "language": {
11725
+ * "zeroRecords": "No records to display"
11726
+ * }
11727
+ * } );
11728
+ * } );
11729
+ */
11730
+ "sZeroRecords": "No matching records found"
11731
+ },
11732
+
11733
+
11734
+ /**
11735
+ * This parameter allows you to have define the global filtering state at
11736
+ * initialisation time. As an object the `search` parameter must be
11737
+ * defined, but all other parameters are optional. When `regex` is true,
11738
+ * the search string will be treated as a regular expression, when false
11739
+ * (default) it will be treated as a straight string. When `smart`
11740
+ * DataTables will use it's smart filtering methods (to word match at
11741
+ * any point in the data), when false this will not be done.
11742
+ * @namespace
11743
+ * @extends DataTable.models.oSearch
11744
+ *
11745
+ * @dtopt Options
11746
+ * @name DataTable.defaults.search
11747
+ *
11748
+ * @example
11749
+ * $(document).ready( function() {
11750
+ * $('#example').dataTable( {
11751
+ * "search": {"search": "Initial search"}
11752
+ * } );
11753
+ * } )
11754
+ */
11755
+ "oSearch": $.extend( {}, DataTable.models.oSearch ),
11756
+
11757
+
11758
+ /**
11759
+ * __Deprecated__ The functionality provided by this parameter has now been
11760
+ * superseded by that provided through `ajax`, which should be used instead.
11761
+ *
11762
+ * By default DataTables will look for the property `data` (or `aaData` for
11763
+ * compatibility with DataTables 1.9-) when obtaining data from an Ajax
11764
+ * source or for server-side processing - this parameter allows that
11765
+ * property to be changed. You can use Javascript dotted object notation to
11766
+ * get a data source for multiple levels of nesting.
11767
+ * @type string
11768
+ * @default data
11769
+ *
11770
+ * @dtopt Options
11771
+ * @dtopt Server-side
11772
+ * @name DataTable.defaults.ajaxDataProp
11773
+ *
11774
+ * @deprecated 1.10. Please use `ajax` for this functionality now.
11775
+ */
11776
+ "sAjaxDataProp": "data",
11777
+
11778
+
11779
+ /**
11780
+ * __Deprecated__ The functionality provided by this parameter has now been
11781
+ * superseded by that provided through `ajax`, which should be used instead.
11782
+ *
11783
+ * You can instruct DataTables to load data from an external
11784
+ * source using this parameter (use aData if you want to pass data in you
11785
+ * already have). Simply provide a url a JSON object can be obtained from.
11786
+ * @type string
11787
+ * @default null
11788
+ *
11789
+ * @dtopt Options
11790
+ * @dtopt Server-side
11791
+ * @name DataTable.defaults.ajaxSource
11792
+ *
11793
+ * @deprecated 1.10. Please use `ajax` for this functionality now.
11794
+ */
11795
+ "sAjaxSource": null,
11796
+
11797
+
11798
+ /**
11799
+ * This initialisation variable allows you to specify exactly where in the
11800
+ * DOM you want DataTables to inject the various controls it adds to the page
11801
+ * (for example you might want the pagination controls at the top of the
11802
+ * table). DIV elements (with or without a custom class) can also be added to
11803
+ * aid styling. The follow syntax is used:
11804
+ * <ul>
11805
+ * <li>The following options are allowed:
11806
+ * <ul>
11807
+ * <li>'l' - Length changing</li>
11808
+ * <li>'f' - Filtering input</li>
11809
+ * <li>'t' - The table!</li>
11810
+ * <li>'i' - Information</li>
11811
+ * <li>'p' - Pagination</li>
11812
+ * <li>'r' - pRocessing</li>
11813
+ * </ul>
11814
+ * </li>
11815
+ * <li>The following constants are allowed:
11816
+ * <ul>
11817
+ * <li>'H' - jQueryUI theme "header" classes ('fg-toolbar ui-widget-header ui-corner-tl ui-corner-tr ui-helper-clearfix')</li>
11818
+ * <li>'F' - jQueryUI theme "footer" classes ('fg-toolbar ui-widget-header ui-corner-bl ui-corner-br ui-helper-clearfix')</li>
11819
+ * </ul>
11820
+ * </li>
11821
+ * <li>The following syntax is expected:
11822
+ * <ul>
11823
+ * <li>'&lt;' and '&gt;' - div elements</li>
11824
+ * <li>'&lt;"class" and '&gt;' - div with a class</li>
11825
+ * <li>'&lt;"#id" and '&gt;' - div with an ID</li>
11826
+ * </ul>
11827
+ * </li>
11828
+ * <li>Examples:
11829
+ * <ul>
11830
+ * <li>'&lt;"wrapper"flipt&gt;'</li>
11831
+ * <li>'&lt;lf&lt;t&gt;ip&gt;'</li>
11832
+ * </ul>
11833
+ * </li>
11834
+ * </ul>
11835
+ * @type string
11836
+ * @default lfrtip <i>(when `jQueryUI` is false)</i> <b>or</b>
11837
+ * <"H"lfr>t<"F"ip> <i>(when `jQueryUI` is true)</i>
11838
+ *
11839
+ * @dtopt Options
11840
+ * @name DataTable.defaults.dom
11841
+ *
11842
+ * @example
11843
+ * $(document).ready( function() {
11844
+ * $('#example').dataTable( {
11845
+ * "dom": '&lt;"top"i&gt;rt&lt;"bottom"flp&gt;&lt;"clear"&gt;'
11846
+ * } );
11847
+ * } );
11848
+ */
11849
+ "sDom": "lfrtip",
11850
+
11851
+
11852
+ /**
11853
+ * Search delay option. This will throttle full table searches that use the
11854
+ * DataTables provided search input element (it does not effect calls to
11855
+ * `dt-api search()`, providing a delay before the search is made.
11856
+ * @type integer
11857
+ * @default 0
11858
+ *
11859
+ * @dtopt Options
11860
+ * @name DataTable.defaults.searchDelay
11861
+ *
11862
+ * @example
11863
+ * $(document).ready( function() {
11864
+ * $('#example').dataTable( {
11865
+ * "searchDelay": 200
11866
+ * } );
11867
+ * } )
11868
+ */
11869
+ "searchDelay": null,
11870
+
11871
+
11872
+ /**
11873
+ * DataTables features six different built-in options for the buttons to
11874
+ * display for pagination control:
11875
+ *
11876
+ * * `numbers` - Page number buttons only
11877
+ * * `simple` - 'Previous' and 'Next' buttons only
11878
+ * * 'simple_numbers` - 'Previous' and 'Next' buttons, plus page numbers
11879
+ * * `full` - 'First', 'Previous', 'Next' and 'Last' buttons
11880
+ * * `full_numbers` - 'First', 'Previous', 'Next' and 'Last' buttons, plus page numbers
11881
+ * * `first_last_numbers` - 'First' and 'Last' buttons, plus page numbers
11882
+ *
11883
+ * Further methods can be added using {@link DataTable.ext.oPagination}.
11884
+ * @type string
11885
+ * @default simple_numbers
11886
+ *
11887
+ * @dtopt Options
11888
+ * @name DataTable.defaults.pagingType
11889
+ *
11890
+ * @example
11891
+ * $(document).ready( function() {
11892
+ * $('#example').dataTable( {
11893
+ * "pagingType": "full_numbers"
11894
+ * } );
11895
+ * } )
11896
+ */
11897
+ "sPaginationType": "simple_numbers",
11898
+
11899
+
11900
+ /**
11901
+ * Enable horizontal scrolling. When a table is too wide to fit into a
11902
+ * certain layout, or you have a large number of columns in the table, you
11903
+ * can enable x-scrolling to show the table in a viewport, which can be
11904
+ * scrolled. This property can be `true` which will allow the table to
11905
+ * scroll horizontally when needed, or any CSS unit, or a number (in which
11906
+ * case it will be treated as a pixel measurement). Setting as simply `true`
11907
+ * is recommended.
11908
+ * @type boolean|string
11909
+ * @default <i>blank string - i.e. disabled</i>
11910
+ *
11911
+ * @dtopt Features
11912
+ * @name DataTable.defaults.scrollX
11913
+ *
11914
+ * @example
11915
+ * $(document).ready( function() {
11916
+ * $('#example').dataTable( {
11917
+ * "scrollX": true,
11918
+ * "scrollCollapse": true
11919
+ * } );
11920
+ * } );
11921
+ */
11922
+ "sScrollX": "",
11923
+
11924
+
11925
+ /**
11926
+ * This property can be used to force a DataTable to use more width than it
11927
+ * might otherwise do when x-scrolling is enabled. For example if you have a
11928
+ * table which requires to be well spaced, this parameter is useful for
11929
+ * "over-sizing" the table, and thus forcing scrolling. This property can by
11930
+ * any CSS unit, or a number (in which case it will be treated as a pixel
11931
+ * measurement).
11932
+ * @type string
11933
+ * @default <i>blank string - i.e. disabled</i>
11934
+ *
11935
+ * @dtopt Options
11936
+ * @name DataTable.defaults.scrollXInner
11937
+ *
11938
+ * @example
11939
+ * $(document).ready( function() {
11940
+ * $('#example').dataTable( {
11941
+ * "scrollX": "100%",
11942
+ * "scrollXInner": "110%"
11943
+ * } );
11944
+ * } );
11945
+ */
11946
+ "sScrollXInner": "",
11947
+
11948
+
11949
+ /**
11950
+ * Enable vertical scrolling. Vertical scrolling will constrain the DataTable
11951
+ * to the given height, and enable scrolling for any data which overflows the
11952
+ * current viewport. This can be used as an alternative to paging to display
11953
+ * a lot of data in a small area (although paging and scrolling can both be
11954
+ * enabled at the same time). This property can be any CSS unit, or a number
11955
+ * (in which case it will be treated as a pixel measurement).
11956
+ * @type string
11957
+ * @default <i>blank string - i.e. disabled</i>
11958
+ *
11959
+ * @dtopt Features
11960
+ * @name DataTable.defaults.scrollY
11961
+ *
11962
+ * @example
11963
+ * $(document).ready( function() {
11964
+ * $('#example').dataTable( {
11965
+ * "scrollY": "200px",
11966
+ * "paginate": false
11967
+ * } );
11968
+ * } );
11969
+ */
11970
+ "sScrollY": "",
11971
+
11972
+
11973
+ /**
11974
+ * __Deprecated__ The functionality provided by this parameter has now been
11975
+ * superseded by that provided through `ajax`, which should be used instead.
11976
+ *
11977
+ * Set the HTTP method that is used to make the Ajax call for server-side
11978
+ * processing or Ajax sourced data.
11979
+ * @type string
11980
+ * @default GET
11981
+ *
11982
+ * @dtopt Options
11983
+ * @dtopt Server-side
11984
+ * @name DataTable.defaults.serverMethod
11985
+ *
11986
+ * @deprecated 1.10. Please use `ajax` for this functionality now.
11987
+ */
11988
+ "sServerMethod": "GET",
11989
+
11990
+
11991
+ /**
11992
+ * DataTables makes use of renderers when displaying HTML elements for
11993
+ * a table. These renderers can be added or modified by plug-ins to
11994
+ * generate suitable mark-up for a site. For example the Bootstrap
11995
+ * integration plug-in for DataTables uses a paging button renderer to
11996
+ * display pagination buttons in the mark-up required by Bootstrap.
11997
+ *
11998
+ * For further information about the renderers available see
11999
+ * DataTable.ext.renderer
12000
+ * @type string|object
12001
+ * @default null
12002
+ *
12003
+ * @name DataTable.defaults.renderer
12004
+ *
12005
+ */
12006
+ "renderer": null,
12007
+
12008
+
12009
+ /**
12010
+ * Set the data property name that DataTables should use to get a row's id
12011
+ * to set as the `id` property in the node.
12012
+ * @type string
12013
+ * @default DT_RowId
12014
+ *
12015
+ * @name DataTable.defaults.rowId
12016
+ */
12017
+ "rowId": "DT_RowId"
12018
+ };
12019
+
12020
+ _fnHungarianMap( DataTable.defaults );
12021
+
12022
+
12023
+
12024
+ /*
12025
+ * Developer note - See note in model.defaults.js about the use of Hungarian
12026
+ * notation and camel case.
12027
+ */
12028
+
12029
+ /**
12030
+ * Column options that can be given to DataTables at initialisation time.
12031
+ * @namespace
12032
+ */
12033
+ DataTable.defaults.column = {
12034
+ /**
12035
+ * Define which column(s) an order will occur on for this column. This
12036
+ * allows a column's ordering to take multiple columns into account when
12037
+ * doing a sort or use the data from a different column. For example first
12038
+ * name / last name columns make sense to do a multi-column sort over the
12039
+ * two columns.
12040
+ * @type array|int
12041
+ * @default null <i>Takes the value of the column index automatically</i>
12042
+ *
12043
+ * @name DataTable.defaults.column.orderData
12044
+ * @dtopt Columns
12045
+ *
12046
+ * @example
12047
+ * // Using `columnDefs`
12048
+ * $(document).ready( function() {
12049
+ * $('#example').dataTable( {
12050
+ * "columnDefs": [
12051
+ * { "orderData": [ 0, 1 ], "targets": [ 0 ] },
12052
+ * { "orderData": [ 1, 0 ], "targets": [ 1 ] },
12053
+ * { "orderData": 2, "targets": [ 2 ] }
12054
+ * ]
12055
+ * } );
12056
+ * } );
12057
+ *
12058
+ * @example
12059
+ * // Using `columns`
12060
+ * $(document).ready( function() {
12061
+ * $('#example').dataTable( {
12062
+ * "columns": [
12063
+ * { "orderData": [ 0, 1 ] },
12064
+ * { "orderData": [ 1, 0 ] },
12065
+ * { "orderData": 2 },
12066
+ * null,
12067
+ * null
12068
+ * ]
12069
+ * } );
12070
+ * } );
12071
+ */
12072
+ "aDataSort": null,
12073
+ "iDataSort": -1,
12074
+
12075
+
12076
+ /**
12077
+ * You can control the default ordering direction, and even alter the
12078
+ * behaviour of the sort handler (i.e. only allow ascending ordering etc)
12079
+ * using this parameter.
12080
+ * @type array
12081
+ * @default [ 'asc', 'desc' ]
12082
+ *
12083
+ * @name DataTable.defaults.column.orderSequence
12084
+ * @dtopt Columns
12085
+ *
12086
+ * @example
12087
+ * // Using `columnDefs`
12088
+ * $(document).ready( function() {
12089
+ * $('#example').dataTable( {
12090
+ * "columnDefs": [
12091
+ * { "orderSequence": [ "asc" ], "targets": [ 1 ] },
12092
+ * { "orderSequence": [ "desc", "asc", "asc" ], "targets": [ 2 ] },
12093
+ * { "orderSequence": [ "desc" ], "targets": [ 3 ] }
12094
+ * ]
12095
+ * } );
12096
+ * } );
12097
+ *
12098
+ * @example
12099
+ * // Using `columns`
12100
+ * $(document).ready( function() {
12101
+ * $('#example').dataTable( {
12102
+ * "columns": [
12103
+ * null,
12104
+ * { "orderSequence": [ "asc" ] },
12105
+ * { "orderSequence": [ "desc", "asc", "asc" ] },
12106
+ * { "orderSequence": [ "desc" ] },
12107
+ * null
12108
+ * ]
12109
+ * } );
12110
+ * } );
12111
+ */
12112
+ "asSorting": [ 'asc', 'desc' ],
12113
+
12114
+
12115
+ /**
12116
+ * Enable or disable filtering on the data in this column.
12117
+ * @type boolean
12118
+ * @default true
12119
+ *
12120
+ * @name DataTable.defaults.column.searchable
12121
+ * @dtopt Columns
12122
+ *
12123
+ * @example
12124
+ * // Using `columnDefs`
12125
+ * $(document).ready( function() {
12126
+ * $('#example').dataTable( {
12127
+ * "columnDefs": [
12128
+ * { "searchable": false, "targets": [ 0 ] }
12129
+ * ] } );
12130
+ * } );
12131
+ *
12132
+ * @example
12133
+ * // Using `columns`
12134
+ * $(document).ready( function() {
12135
+ * $('#example').dataTable( {
12136
+ * "columns": [
12137
+ * { "searchable": false },
12138
+ * null,
12139
+ * null,
12140
+ * null,
12141
+ * null
12142
+ * ] } );
12143
+ * } );
12144
+ */
12145
+ "bSearchable": true,
12146
+
12147
+
12148
+ /**
12149
+ * Enable or disable ordering on this column.
12150
+ * @type boolean
12151
+ * @default true
12152
+ *
12153
+ * @name DataTable.defaults.column.orderable
12154
+ * @dtopt Columns
12155
+ *
12156
+ * @example
12157
+ * // Using `columnDefs`
12158
+ * $(document).ready( function() {
12159
+ * $('#example').dataTable( {
12160
+ * "columnDefs": [
12161
+ * { "orderable": false, "targets": [ 0 ] }
12162
+ * ] } );
12163
+ * } );
12164
+ *
12165
+ * @example
12166
+ * // Using `columns`
12167
+ * $(document).ready( function() {
12168
+ * $('#example').dataTable( {
12169
+ * "columns": [
12170
+ * { "orderable": false },
12171
+ * null,
12172
+ * null,
12173
+ * null,
12174
+ * null
12175
+ * ] } );
12176
+ * } );
12177
+ */
12178
+ "bSortable": true,
12179
+
12180
+
12181
+ /**
12182
+ * Enable or disable the display of this column.
12183
+ * @type boolean
12184
+ * @default true
12185
+ *
12186
+ * @name DataTable.defaults.column.visible
12187
+ * @dtopt Columns
12188
+ *
12189
+ * @example
12190
+ * // Using `columnDefs`
12191
+ * $(document).ready( function() {
12192
+ * $('#example').dataTable( {
12193
+ * "columnDefs": [
12194
+ * { "visible": false, "targets": [ 0 ] }
12195
+ * ] } );
12196
+ * } );
12197
+ *
12198
+ * @example
12199
+ * // Using `columns`
12200
+ * $(document).ready( function() {
12201
+ * $('#example').dataTable( {
12202
+ * "columns": [
12203
+ * { "visible": false },
12204
+ * null,
12205
+ * null,
12206
+ * null,
12207
+ * null
12208
+ * ] } );
12209
+ * } );
12210
+ */
12211
+ "bVisible": true,
12212
+
12213
+
12214
+ /**
12215
+ * Developer definable function that is called whenever a cell is created (Ajax source,
12216
+ * etc) or processed for input (DOM source). This can be used as a compliment to mRender
12217
+ * allowing you to modify the DOM element (add background colour for example) when the
12218
+ * element is available.
12219
+ * @type function
12220
+ * @param {element} td The TD node that has been created
12221
+ * @param {*} cellData The Data for the cell
12222
+ * @param {array|object} rowData The data for the whole row
12223
+ * @param {int} row The row index for the aoData data store
12224
+ * @param {int} col The column index for aoColumns
12225
+ *
12226
+ * @name DataTable.defaults.column.createdCell
12227
+ * @dtopt Columns
12228
+ *
12229
+ * @example
12230
+ * $(document).ready( function() {
12231
+ * $('#example').dataTable( {
12232
+ * "columnDefs": [ {
12233
+ * "targets": [3],
12234
+ * "createdCell": function (td, cellData, rowData, row, col) {
12235
+ * if ( cellData == "1.7" ) {
12236
+ * $(td).css('color', 'blue')
12237
+ * }
12238
+ * }
12239
+ * } ]
12240
+ * });
12241
+ * } );
12242
+ */
12243
+ "fnCreatedCell": null,
12244
+
12245
+
12246
+ /**
12247
+ * This parameter has been replaced by `data` in DataTables to ensure naming
12248
+ * consistency. `dataProp` can still be used, as there is backwards
12249
+ * compatibility in DataTables for this option, but it is strongly
12250
+ * recommended that you use `data` in preference to `dataProp`.
12251
+ * @name DataTable.defaults.column.dataProp
12252
+ */
12253
+
12254
+
12255
+ /**
12256
+ * This property can be used to read data from any data source property,
12257
+ * including deeply nested objects / properties. `data` can be given in a
12258
+ * number of different ways which effect its behaviour:
12259
+ *
12260
+ * * `integer` - treated as an array index for the data source. This is the
12261
+ * default that DataTables uses (incrementally increased for each column).
12262
+ * * `string` - read an object property from the data source. There are
12263
+ * three 'special' options that can be used in the string to alter how
12264
+ * DataTables reads the data from the source object:
12265
+ * * `.` - Dotted Javascript notation. Just as you use a `.` in
12266
+ * Javascript to read from nested objects, so to can the options
12267
+ * specified in `data`. For example: `browser.version` or
12268
+ * `browser.name`. If your object parameter name contains a period, use
12269
+ * `\\` to escape it - i.e. `first\\.name`.
12270
+ * * `[]` - Array notation. DataTables can automatically combine data
12271
+ * from and array source, joining the data with the characters provided
12272
+ * between the two brackets. For example: `name[, ]` would provide a
12273
+ * comma-space separated list from the source array. If no characters
12274
+ * are provided between the brackets, the original array source is
12275
+ * returned.
12276
+ * * `()` - Function notation. Adding `()` to the end of a parameter will
12277
+ * execute a function of the name given. For example: `browser()` for a
12278
+ * simple function on the data source, `browser.version()` for a
12279
+ * function in a nested property or even `browser().version` to get an
12280
+ * object property if the function called returns an object. Note that
12281
+ * function notation is recommended for use in `render` rather than
12282
+ * `data` as it is much simpler to use as a renderer.
12283
+ * * `null` - use the original data source for the row rather than plucking
12284
+ * data directly from it. This action has effects on two other
12285
+ * initialisation options:
12286
+ * * `defaultContent` - When null is given as the `data` option and
12287
+ * `defaultContent` is specified for the column, the value defined by
12288
+ * `defaultContent` will be used for the cell.
12289
+ * * `render` - When null is used for the `data` option and the `render`
12290
+ * option is specified for the column, the whole data source for the
12291
+ * row is used for the renderer.
12292
+ * * `function` - the function given will be executed whenever DataTables
12293
+ * needs to set or get the data for a cell in the column. The function
12294
+ * takes three parameters:
12295
+ * * Parameters:
12296
+ * * `{array|object}` The data source for the row
12297
+ * * `{string}` The type call data requested - this will be 'set' when
12298
+ * setting data or 'filter', 'display', 'type', 'sort' or undefined
12299
+ * when gathering data. Note that when `undefined` is given for the
12300
+ * type DataTables expects to get the raw data for the object back<
12301
+ * * `{*}` Data to set when the second parameter is 'set'.
12302
+ * * Return:
12303
+ * * The return value from the function is not required when 'set' is
12304
+ * the type of call, but otherwise the return is what will be used
12305
+ * for the data requested.
12306
+ *
12307
+ * Note that `data` is a getter and setter option. If you just require
12308
+ * formatting of data for output, you will likely want to use `render` which
12309
+ * is simply a getter and thus simpler to use.
12310
+ *
12311
+ * Note that prior to DataTables 1.9.2 `data` was called `mDataProp`. The
12312
+ * name change reflects the flexibility of this property and is consistent
12313
+ * with the naming of mRender. If 'mDataProp' is given, then it will still
12314
+ * be used by DataTables, as it automatically maps the old name to the new
12315
+ * if required.
12316
+ *
12317
+ * @type string|int|function|null
12318
+ * @default null <i>Use automatically calculated column index</i>
12319
+ *
12320
+ * @name DataTable.defaults.column.data
12321
+ * @dtopt Columns
12322
+ *
12323
+ * @example
12324
+ * // Read table data from objects
12325
+ * // JSON structure for each row:
12326
+ * // {
12327
+ * // "engine": {value},
12328
+ * // "browser": {value},
12329
+ * // "platform": {value},
12330
+ * // "version": {value},
12331
+ * // "grade": {value}
12332
+ * // }
12333
+ * $(document).ready( function() {
12334
+ * $('#example').dataTable( {
12335
+ * "ajaxSource": "sources/objects.txt",
12336
+ * "columns": [
12337
+ * { "data": "engine" },
12338
+ * { "data": "browser" },
12339
+ * { "data": "platform" },
12340
+ * { "data": "version" },
12341
+ * { "data": "grade" }
12342
+ * ]
12343
+ * } );
12344
+ * } );
12345
+ *
12346
+ * @example
12347
+ * // Read information from deeply nested objects
12348
+ * // JSON structure for each row:
12349
+ * // {
12350
+ * // "engine": {value},
12351
+ * // "browser": {value},
12352
+ * // "platform": {
12353
+ * // "inner": {value}
12354
+ * // },
12355
+ * // "details": [
12356
+ * // {value}, {value}
12357
+ * // ]
12358
+ * // }
12359
+ * $(document).ready( function() {
12360
+ * $('#example').dataTable( {
12361
+ * "ajaxSource": "sources/deep.txt",
12362
+ * "columns": [
12363
+ * { "data": "engine" },
12364
+ * { "data": "browser" },
12365
+ * { "data": "platform.inner" },
12366
+ * { "data": "platform.details.0" },
12367
+ * { "data": "platform.details.1" }
12368
+ * ]
12369
+ * } );
12370
+ * } );
12371
+ *
12372
+ * @example
12373
+ * // Using `data` as a function to provide different information for
12374
+ * // sorting, filtering and display. In this case, currency (price)
12375
+ * $(document).ready( function() {
12376
+ * $('#example').dataTable( {
12377
+ * "columnDefs": [ {
12378
+ * "targets": [ 0 ],
12379
+ * "data": function ( source, type, val ) {
12380
+ * if (type === 'set') {
12381
+ * source.price = val;
12382
+ * // Store the computed dislay and filter values for efficiency
12383
+ * source.price_display = val=="" ? "" : "$"+numberFormat(val);
12384
+ * source.price_filter = val=="" ? "" : "$"+numberFormat(val)+" "+val;
12385
+ * return;
12386
+ * }
12387
+ * else if (type === 'display') {
12388
+ * return source.price_display;
12389
+ * }
12390
+ * else if (type === 'filter') {
12391
+ * return source.price_filter;
12392
+ * }
12393
+ * // 'sort', 'type' and undefined all just use the integer
12394
+ * return source.price;
12395
+ * }
12396
+ * } ]
12397
+ * } );
12398
+ * } );
12399
+ *
12400
+ * @example
12401
+ * // Using default content
12402
+ * $(document).ready( function() {
12403
+ * $('#example').dataTable( {
12404
+ * "columnDefs": [ {
12405
+ * "targets": [ 0 ],
12406
+ * "data": null,
12407
+ * "defaultContent": "Click to edit"
12408
+ * } ]
12409
+ * } );
12410
+ * } );
12411
+ *
12412
+ * @example
12413
+ * // Using array notation - outputting a list from an array
12414
+ * $(document).ready( function() {
12415
+ * $('#example').dataTable( {
12416
+ * "columnDefs": [ {
12417
+ * "targets": [ 0 ],
12418
+ * "data": "name[, ]"
12419
+ * } ]
12420
+ * } );
12421
+ * } );
12422
+ *
12423
+ */
12424
+ "mData": null,
12425
+
12426
+
12427
+ /**
12428
+ * This property is the rendering partner to `data` and it is suggested that
12429
+ * when you want to manipulate data for display (including filtering,
12430
+ * sorting etc) without altering the underlying data for the table, use this
12431
+ * property. `render` can be considered to be the the read only companion to
12432
+ * `data` which is read / write (then as such more complex). Like `data`
12433
+ * this option can be given in a number of different ways to effect its
12434
+ * behaviour:
12435
+ *
12436
+ * * `integer` - treated as an array index for the data source. This is the
12437
+ * default that DataTables uses (incrementally increased for each column).
12438
+ * * `string` - read an object property from the data source. There are
12439
+ * three 'special' options that can be used in the string to alter how
12440
+ * DataTables reads the data from the source object:
12441
+ * * `.` - Dotted Javascript notation. Just as you use a `.` in
12442
+ * Javascript to read from nested objects, so to can the options
12443
+ * specified in `data`. For example: `browser.version` or
12444
+ * `browser.name`. If your object parameter name contains a period, use
12445
+ * `\\` to escape it - i.e. `first\\.name`.
12446
+ * * `[]` - Array notation. DataTables can automatically combine data
12447
+ * from and array source, joining the data with the characters provided
12448
+ * between the two brackets. For example: `name[, ]` would provide a
12449
+ * comma-space separated list from the source array. If no characters
12450
+ * are provided between the brackets, the original array source is
12451
+ * returned.
12452
+ * * `()` - Function notation. Adding `()` to the end of a parameter will
12453
+ * execute a function of the name given. For example: `browser()` for a
12454
+ * simple function on the data source, `browser.version()` for a
12455
+ * function in a nested property or even `browser().version` to get an
12456
+ * object property if the function called returns an object.
12457
+ * * `object` - use different data for the different data types requested by
12458
+ * DataTables ('filter', 'display', 'type' or 'sort'). The property names
12459
+ * of the object is the data type the property refers to and the value can
12460
+ * defined using an integer, string or function using the same rules as
12461
+ * `render` normally does. Note that an `_` option _must_ be specified.
12462
+ * This is the default value to use if you haven't specified a value for
12463
+ * the data type requested by DataTables.
12464
+ * * `function` - the function given will be executed whenever DataTables
12465
+ * needs to set or get the data for a cell in the column. The function
12466
+ * takes three parameters:
12467
+ * * Parameters:
12468
+ * * {array|object} The data source for the row (based on `data`)
12469
+ * * {string} The type call data requested - this will be 'filter',
12470
+ * 'display', 'type' or 'sort'.
12471
+ * * {array|object} The full data source for the row (not based on
12472
+ * `data`)
12473
+ * * Return:
12474
+ * * The return value from the function is what will be used for the
12475
+ * data requested.
12476
+ *
12477
+ * @type string|int|function|object|null
12478
+ * @default null Use the data source value.
12479
+ *
12480
+ * @name DataTable.defaults.column.render
12481
+ * @dtopt Columns
12482
+ *
12483
+ * @example
12484
+ * // Create a comma separated list from an array of objects
12485
+ * $(document).ready( function() {
12486
+ * $('#example').dataTable( {
12487
+ * "ajaxSource": "sources/deep.txt",
12488
+ * "columns": [
12489
+ * { "data": "engine" },
12490
+ * { "data": "browser" },
12491
+ * {
12492
+ * "data": "platform",
12493
+ * "render": "[, ].name"
12494
+ * }
12495
+ * ]
12496
+ * } );
12497
+ * } );
12498
+ *
12499
+ * @example
12500
+ * // Execute a function to obtain data
12501
+ * $(document).ready( function() {
12502
+ * $('#example').dataTable( {
12503
+ * "columnDefs": [ {
12504
+ * "targets": [ 0 ],
12505
+ * "data": null, // Use the full data source object for the renderer's source
12506
+ * "render": "browserName()"
12507
+ * } ]
12508
+ * } );
12509
+ * } );
12510
+ *
12511
+ * @example
12512
+ * // As an object, extracting different data for the different types
12513
+ * // This would be used with a data source such as:
12514
+ * // { "phone": 5552368, "phone_filter": "5552368 555-2368", "phone_display": "555-2368" }
12515
+ * // Here the `phone` integer is used for sorting and type detection, while `phone_filter`
12516
+ * // (which has both forms) is used for filtering for if a user inputs either format, while
12517
+ * // the formatted phone number is the one that is shown in the table.
12518
+ * $(document).ready( function() {
12519
+ * $('#example').dataTable( {
12520
+ * "columnDefs": [ {
12521
+ * "targets": [ 0 ],
12522
+ * "data": null, // Use the full data source object for the renderer's source
12523
+ * "render": {
12524
+ * "_": "phone",
12525
+ * "filter": "phone_filter",
12526
+ * "display": "phone_display"
12527
+ * }
12528
+ * } ]
12529
+ * } );
12530
+ * } );
12531
+ *
12532
+ * @example
12533
+ * // Use as a function to create a link from the data source
12534
+ * $(document).ready( function() {
12535
+ * $('#example').dataTable( {
12536
+ * "columnDefs": [ {
12537
+ * "targets": [ 0 ],
12538
+ * "data": "download_link",
12539
+ * "render": function ( data, type, full ) {
12540
+ * return '<a href="'+data+'">Download</a>';
12541
+ * }
12542
+ * } ]
12543
+ * } );
12544
+ * } );
12545
+ */
12546
+ "mRender": null,
12547
+
12548
+
12549
+ /**
12550
+ * Change the cell type created for the column - either TD cells or TH cells. This
12551
+ * can be useful as TH cells have semantic meaning in the table body, allowing them
12552
+ * to act as a header for a row (you may wish to add scope='row' to the TH elements).
12553
+ * @type string
12554
+ * @default td
12555
+ *
12556
+ * @name DataTable.defaults.column.cellType
12557
+ * @dtopt Columns
12558
+ *
12559
+ * @example
12560
+ * // Make the first column use TH cells
12561
+ * $(document).ready( function() {
12562
+ * $('#example').dataTable( {
12563
+ * "columnDefs": [ {
12564
+ * "targets": [ 0 ],
12565
+ * "cellType": "th"
12566
+ * } ]
12567
+ * } );
12568
+ * } );
12569
+ */
12570
+ "sCellType": "td",
12571
+
12572
+
12573
+ /**
12574
+ * Class to give to each cell in this column.
12575
+ * @type string
12576
+ * @default <i>Empty string</i>
12577
+ *
12578
+ * @name DataTable.defaults.column.class
12579
+ * @dtopt Columns
12580
+ *
12581
+ * @example
12582
+ * // Using `columnDefs`
12583
+ * $(document).ready( function() {
12584
+ * $('#example').dataTable( {
12585
+ * "columnDefs": [
12586
+ * { "class": "my_class", "targets": [ 0 ] }
12587
+ * ]
12588
+ * } );
12589
+ * } );
12590
+ *
12591
+ * @example
12592
+ * // Using `columns`
12593
+ * $(document).ready( function() {
12594
+ * $('#example').dataTable( {
12595
+ * "columns": [
12596
+ * { "class": "my_class" },
12597
+ * null,
12598
+ * null,
12599
+ * null,
12600
+ * null
12601
+ * ]
12602
+ * } );
12603
+ * } );
12604
+ */
12605
+ "sClass": "",
12606
+
12607
+ /**
12608
+ * When DataTables calculates the column widths to assign to each column,
12609
+ * it finds the longest string in each column and then constructs a
12610
+ * temporary table and reads the widths from that. The problem with this
12611
+ * is that "mmm" is much wider then "iiii", but the latter is a longer
12612
+ * string - thus the calculation can go wrong (doing it properly and putting
12613
+ * it into an DOM object and measuring that is horribly(!) slow). Thus as
12614
+ * a "work around" we provide this option. It will append its value to the
12615
+ * text that is found to be the longest string for the column - i.e. padding.
12616
+ * Generally you shouldn't need this!
12617
+ * @type string
12618
+ * @default <i>Empty string<i>
12619
+ *
12620
+ * @name DataTable.defaults.column.contentPadding
12621
+ * @dtopt Columns
12622
+ *
12623
+ * @example
12624
+ * // Using `columns`
12625
+ * $(document).ready( function() {
12626
+ * $('#example').dataTable( {
12627
+ * "columns": [
12628
+ * null,
12629
+ * null,
12630
+ * null,
12631
+ * {
12632
+ * "contentPadding": "mmm"
12633
+ * }
12634
+ * ]
12635
+ * } );
12636
+ * } );
12637
+ */
12638
+ "sContentPadding": "",
12639
+
12640
+
12641
+ /**
12642
+ * Allows a default value to be given for a column's data, and will be used
12643
+ * whenever a null data source is encountered (this can be because `data`
12644
+ * is set to null, or because the data source itself is null).
12645
+ * @type string
12646
+ * @default null
12647
+ *
12648
+ * @name DataTable.defaults.column.defaultContent
12649
+ * @dtopt Columns
12650
+ *
12651
+ * @example
12652
+ * // Using `columnDefs`
12653
+ * $(document).ready( function() {
12654
+ * $('#example').dataTable( {
12655
+ * "columnDefs": [
12656
+ * {
12657
+ * "data": null,
12658
+ * "defaultContent": "Edit",
12659
+ * "targets": [ -1 ]
12660
+ * }
12661
+ * ]
12662
+ * } );
12663
+ * } );
12664
+ *
12665
+ * @example
12666
+ * // Using `columns`
12667
+ * $(document).ready( function() {
12668
+ * $('#example').dataTable( {
12669
+ * "columns": [
12670
+ * null,
12671
+ * null,
12672
+ * null,
12673
+ * {
12674
+ * "data": null,
12675
+ * "defaultContent": "Edit"
12676
+ * }
12677
+ * ]
12678
+ * } );
12679
+ * } );
12680
+ */
12681
+ "sDefaultContent": null,
12682
+
12683
+
12684
+ /**
12685
+ * This parameter is only used in DataTables' server-side processing. It can
12686
+ * be exceptionally useful to know what columns are being displayed on the
12687
+ * client side, and to map these to database fields. When defined, the names
12688
+ * also allow DataTables to reorder information from the server if it comes
12689
+ * back in an unexpected order (i.e. if you switch your columns around on the
12690
+ * client-side, your server-side code does not also need updating).
12691
+ * @type string
12692
+ * @default <i>Empty string</i>
12693
+ *
12694
+ * @name DataTable.defaults.column.name
12695
+ * @dtopt Columns
12696
+ *
12697
+ * @example
12698
+ * // Using `columnDefs`
12699
+ * $(document).ready( function() {
12700
+ * $('#example').dataTable( {
12701
+ * "columnDefs": [
12702
+ * { "name": "engine", "targets": [ 0 ] },
12703
+ * { "name": "browser", "targets": [ 1 ] },
12704
+ * { "name": "platform", "targets": [ 2 ] },
12705
+ * { "name": "version", "targets": [ 3 ] },
12706
+ * { "name": "grade", "targets": [ 4 ] }
12707
+ * ]
12708
+ * } );
12709
+ * } );
12710
+ *
12711
+ * @example
12712
+ * // Using `columns`
12713
+ * $(document).ready( function() {
12714
+ * $('#example').dataTable( {
12715
+ * "columns": [
12716
+ * { "name": "engine" },
12717
+ * { "name": "browser" },
12718
+ * { "name": "platform" },
12719
+ * { "name": "version" },
12720
+ * { "name": "grade" }
12721
+ * ]
12722
+ * } );
12723
+ * } );
12724
+ */
12725
+ "sName": "",
12726
+
12727
+
12728
+ /**
12729
+ * Defines a data source type for the ordering which can be used to read
12730
+ * real-time information from the table (updating the internally cached
12731
+ * version) prior to ordering. This allows ordering to occur on user
12732
+ * editable elements such as form inputs.
12733
+ * @type string
12734
+ * @default std
12735
+ *
12736
+ * @name DataTable.defaults.column.orderDataType
12737
+ * @dtopt Columns
12738
+ *
12739
+ * @example
12740
+ * // Using `columnDefs`
12741
+ * $(document).ready( function() {
12742
+ * $('#example').dataTable( {
12743
+ * "columnDefs": [
12744
+ * { "orderDataType": "dom-text", "targets": [ 2, 3 ] },
12745
+ * { "type": "numeric", "targets": [ 3 ] },
12746
+ * { "orderDataType": "dom-select", "targets": [ 4 ] },
12747
+ * { "orderDataType": "dom-checkbox", "targets": [ 5 ] }
12748
+ * ]
12749
+ * } );
12750
+ * } );
12751
+ *
12752
+ * @example
12753
+ * // Using `columns`
12754
+ * $(document).ready( function() {
12755
+ * $('#example').dataTable( {
12756
+ * "columns": [
12757
+ * null,
12758
+ * null,
12759
+ * { "orderDataType": "dom-text" },
12760
+ * { "orderDataType": "dom-text", "type": "numeric" },
12761
+ * { "orderDataType": "dom-select" },
12762
+ * { "orderDataType": "dom-checkbox" }
12763
+ * ]
12764
+ * } );
12765
+ * } );
12766
+ */
12767
+ "sSortDataType": "std",
12768
+
12769
+
12770
+ /**
12771
+ * The title of this column.
12772
+ * @type string
12773
+ * @default null <i>Derived from the 'TH' value for this column in the
12774
+ * original HTML table.</i>
12775
+ *
12776
+ * @name DataTable.defaults.column.title
12777
+ * @dtopt Columns
12778
+ *
12779
+ * @example
12780
+ * // Using `columnDefs`
12781
+ * $(document).ready( function() {
12782
+ * $('#example').dataTable( {
12783
+ * "columnDefs": [
12784
+ * { "title": "My column title", "targets": [ 0 ] }
12785
+ * ]
12786
+ * } );
12787
+ * } );
12788
+ *
12789
+ * @example
12790
+ * // Using `columns`
12791
+ * $(document).ready( function() {
12792
+ * $('#example').dataTable( {
12793
+ * "columns": [
12794
+ * { "title": "My column title" },
12795
+ * null,
12796
+ * null,
12797
+ * null,
12798
+ * null
12799
+ * ]
12800
+ * } );
12801
+ * } );
12802
+ */
12803
+ "sTitle": null,
12804
+
12805
+
12806
+ /**
12807
+ * The type allows you to specify how the data for this column will be
12808
+ * ordered. Four types (string, numeric, date and html (which will strip
12809
+ * HTML tags before ordering)) are currently available. Note that only date
12810
+ * formats understood by Javascript's Date() object will be accepted as type
12811
+ * date. For example: "Mar 26, 2008 5:03 PM". May take the values: 'string',
12812
+ * 'numeric', 'date' or 'html' (by default). Further types can be adding
12813
+ * through plug-ins.
12814
+ * @type string
12815
+ * @default null <i>Auto-detected from raw data</i>
12816
+ *
12817
+ * @name DataTable.defaults.column.type
12818
+ * @dtopt Columns
12819
+ *
12820
+ * @example
12821
+ * // Using `columnDefs`
12822
+ * $(document).ready( function() {
12823
+ * $('#example').dataTable( {
12824
+ * "columnDefs": [
12825
+ * { "type": "html", "targets": [ 0 ] }
12826
+ * ]
12827
+ * } );
12828
+ * } );
12829
+ *
12830
+ * @example
12831
+ * // Using `columns`
12832
+ * $(document).ready( function() {
12833
+ * $('#example').dataTable( {
12834
+ * "columns": [
12835
+ * { "type": "html" },
12836
+ * null,
12837
+ * null,
12838
+ * null,
12839
+ * null
12840
+ * ]
12841
+ * } );
12842
+ * } );
12843
+ */
12844
+ "sType": null,
12845
+
12846
+
12847
+ /**
12848
+ * Defining the width of the column, this parameter may take any CSS value
12849
+ * (3em, 20px etc). DataTables applies 'smart' widths to columns which have not
12850
+ * been given a specific width through this interface ensuring that the table
12851
+ * remains readable.
12852
+ * @type string
12853
+ * @default null <i>Automatic</i>
12854
+ *
12855
+ * @name DataTable.defaults.column.width
12856
+ * @dtopt Columns
12857
+ *
12858
+ * @example
12859
+ * // Using `columnDefs`
12860
+ * $(document).ready( function() {
12861
+ * $('#example').dataTable( {
12862
+ * "columnDefs": [
12863
+ * { "width": "20%", "targets": [ 0 ] }
12864
+ * ]
12865
+ * } );
12866
+ * } );
12867
+ *
12868
+ * @example
12869
+ * // Using `columns`
12870
+ * $(document).ready( function() {
12871
+ * $('#example').dataTable( {
12872
+ * "columns": [
12873
+ * { "width": "20%" },
12874
+ * null,
12875
+ * null,
12876
+ * null,
12877
+ * null
12878
+ * ]
12879
+ * } );
12880
+ * } );
12881
+ */
12882
+ "sWidth": null
12883
+ };
12884
+
12885
+ _fnHungarianMap( DataTable.defaults.column );
12886
+
12887
+
12888
+
12889
+ /**
12890
+ * DataTables settings object - this holds all the information needed for a
12891
+ * given table, including configuration, data and current application of the
12892
+ * table options. DataTables does not have a single instance for each DataTable
12893
+ * with the settings attached to that instance, but rather instances of the
12894
+ * DataTable "class" are created on-the-fly as needed (typically by a
12895
+ * $().dataTable() call) and the settings object is then applied to that
12896
+ * instance.
12897
+ *
12898
+ * Note that this object is related to {@link DataTable.defaults} but this
12899
+ * one is the internal data store for DataTables's cache of columns. It should
12900
+ * NOT be manipulated outside of DataTables. Any configuration should be done
12901
+ * through the initialisation options.
12902
+ * @namespace
12903
+ * @todo Really should attach the settings object to individual instances so we
12904
+ * don't need to create new instances on each $().dataTable() call (if the
12905
+ * table already exists). It would also save passing oSettings around and
12906
+ * into every single function. However, this is a very significant
12907
+ * architecture change for DataTables and will almost certainly break
12908
+ * backwards compatibility with older installations. This is something that
12909
+ * will be done in 2.0.
12910
+ */
12911
+ DataTable.models.oSettings = {
12912
+ /**
12913
+ * Primary features of DataTables and their enablement state.
12914
+ * @namespace
12915
+ */
12916
+ "oFeatures": {
12917
+
12918
+ /**
12919
+ * Flag to say if DataTables should automatically try to calculate the
12920
+ * optimum table and columns widths (true) or not (false).
12921
+ * Note that this parameter will be set by the initialisation routine. To
12922
+ * set a default use {@link DataTable.defaults}.
12923
+ * @type boolean
12924
+ */
12925
+ "bAutoWidth": null,
12926
+
12927
+ /**
12928
+ * Delay the creation of TR and TD elements until they are actually
12929
+ * needed by a driven page draw. This can give a significant speed
12930
+ * increase for Ajax source and Javascript source data, but makes no
12931
+ * difference at all fro DOM and server-side processing tables.
12932
+ * Note that this parameter will be set by the initialisation routine. To
12933
+ * set a default use {@link DataTable.defaults}.
12934
+ * @type boolean
12935
+ */
12936
+ "bDeferRender": null,
12937
+
12938
+ /**
12939
+ * Enable filtering on the table or not. Note that if this is disabled
12940
+ * then there is no filtering at all on the table, including fnFilter.
12941
+ * To just remove the filtering input use sDom and remove the 'f' option.
12942
+ * Note that this parameter will be set by the initialisation routine. To
12943
+ * set a default use {@link DataTable.defaults}.
12944
+ * @type boolean
12945
+ */
12946
+ "bFilter": null,
12947
+
12948
+ /**
12949
+ * Table information element (the 'Showing x of y records' div) enable
12950
+ * flag.
12951
+ * Note that this parameter will be set by the initialisation routine. To
12952
+ * set a default use {@link DataTable.defaults}.
12953
+ * @type boolean
12954
+ */
12955
+ "bInfo": null,
12956
+
12957
+ /**
12958
+ * Present a user control allowing the end user to change the page size
12959
+ * when pagination is enabled.
12960
+ * Note that this parameter will be set by the initialisation routine. To
12961
+ * set a default use {@link DataTable.defaults}.
12962
+ * @type boolean
12963
+ */
12964
+ "bLengthChange": null,
12965
+
12966
+ /**
12967
+ * Pagination enabled or not. Note that if this is disabled then length
12968
+ * changing must also be disabled.
12969
+ * Note that this parameter will be set by the initialisation routine. To
12970
+ * set a default use {@link DataTable.defaults}.
12971
+ * @type boolean
12972
+ */
12973
+ "bPaginate": null,
12974
+
12975
+ /**
12976
+ * Processing indicator enable flag whenever DataTables is enacting a
12977
+ * user request - typically an Ajax request for server-side processing.
12978
+ * Note that this parameter will be set by the initialisation routine. To
12979
+ * set a default use {@link DataTable.defaults}.
12980
+ * @type boolean
12981
+ */
12982
+ "bProcessing": null,
12983
+
12984
+ /**
12985
+ * Server-side processing enabled flag - when enabled DataTables will
12986
+ * get all data from the server for every draw - there is no filtering,
12987
+ * sorting or paging done on the client-side.
12988
+ * Note that this parameter will be set by the initialisation routine. To
12989
+ * set a default use {@link DataTable.defaults}.
12990
+ * @type boolean
12991
+ */
12992
+ "bServerSide": null,
12993
+
12994
+ /**
12995
+ * Sorting enablement flag.
12996
+ * Note that this parameter will be set by the initialisation routine. To
12997
+ * set a default use {@link DataTable.defaults}.
12998
+ * @type boolean
12999
+ */
13000
+ "bSort": null,
13001
+
13002
+ /**
13003
+ * Multi-column sorting
13004
+ * Note that this parameter will be set by the initialisation routine. To
13005
+ * set a default use {@link DataTable.defaults}.
13006
+ * @type boolean
13007
+ */
13008
+ "bSortMulti": null,
13009
+
13010
+ /**
13011
+ * Apply a class to the columns which are being sorted to provide a
13012
+ * visual highlight or not. This can slow things down when enabled since
13013
+ * there is a lot of DOM interaction.
13014
+ * Note that this parameter will be set by the initialisation routine. To
13015
+ * set a default use {@link DataTable.defaults}.
13016
+ * @type boolean
13017
+ */
13018
+ "bSortClasses": null,
13019
+
13020
+ /**
13021
+ * State saving enablement flag.
13022
+ * Note that this parameter will be set by the initialisation routine. To
13023
+ * set a default use {@link DataTable.defaults}.
13024
+ * @type boolean
13025
+ */
13026
+ "bStateSave": null
13027
+ },
13028
+
13029
+
13030
+ /**
13031
+ * Scrolling settings for a table.
13032
+ * @namespace
13033
+ */
13034
+ "oScroll": {
13035
+ /**
13036
+ * When the table is shorter in height than sScrollY, collapse the
13037
+ * table container down to the height of the table (when true).
13038
+ * Note that this parameter will be set by the initialisation routine. To
13039
+ * set a default use {@link DataTable.defaults}.
13040
+ * @type boolean
13041
+ */
13042
+ "bCollapse": null,
13043
+
13044
+ /**
13045
+ * Width of the scrollbar for the web-browser's platform. Calculated
13046
+ * during table initialisation.
13047
+ * @type int
13048
+ * @default 0
13049
+ */
13050
+ "iBarWidth": 0,
13051
+
13052
+ /**
13053
+ * Viewport width for horizontal scrolling. Horizontal scrolling is
13054
+ * disabled if an empty string.
13055
+ * Note that this parameter will be set by the initialisation routine. To
13056
+ * set a default use {@link DataTable.defaults}.
13057
+ * @type string
13058
+ */
13059
+ "sX": null,
13060
+
13061
+ /**
13062
+ * Width to expand the table to when using x-scrolling. Typically you
13063
+ * should not need to use this.
13064
+ * Note that this parameter will be set by the initialisation routine. To
13065
+ * set a default use {@link DataTable.defaults}.
13066
+ * @type string
13067
+ * @deprecated
13068
+ */
13069
+ "sXInner": null,
13070
+
13071
+ /**
13072
+ * Viewport height for vertical scrolling. Vertical scrolling is disabled
13073
+ * if an empty string.
13074
+ * Note that this parameter will be set by the initialisation routine. To
13075
+ * set a default use {@link DataTable.defaults}.
13076
+ * @type string
13077
+ */
13078
+ "sY": null
13079
+ },
13080
+
13081
+ /**
13082
+ * Language information for the table.
13083
+ * @namespace
13084
+ * @extends DataTable.defaults.oLanguage
13085
+ */
13086
+ "oLanguage": {
13087
+ /**
13088
+ * Information callback function. See
13089
+ * {@link DataTable.defaults.fnInfoCallback}
13090
+ * @type function
13091
+ * @default null
13092
+ */
13093
+ "fnInfoCallback": null
13094
+ },
13095
+
13096
+ /**
13097
+ * Browser support parameters
13098
+ * @namespace
13099
+ */
13100
+ "oBrowser": {
13101
+ /**
13102
+ * Indicate if the browser incorrectly calculates width:100% inside a
13103
+ * scrolling element (IE6/7)
13104
+ * @type boolean
13105
+ * @default false
13106
+ */
13107
+ "bScrollOversize": false,
13108
+
13109
+ /**
13110
+ * Determine if the vertical scrollbar is on the right or left of the
13111
+ * scrolling container - needed for rtl language layout, although not
13112
+ * all browsers move the scrollbar (Safari).
13113
+ * @type boolean
13114
+ * @default false
13115
+ */
13116
+ "bScrollbarLeft": false,
13117
+
13118
+ /**
13119
+ * Flag for if `getBoundingClientRect` is fully supported or not
13120
+ * @type boolean
13121
+ * @default false
13122
+ */
13123
+ "bBounding": false,
13124
+
13125
+ /**
13126
+ * Browser scrollbar width
13127
+ * @type integer
13128
+ * @default 0
13129
+ */
13130
+ "barWidth": 0
13131
+ },
13132
+
13133
+
13134
+ "ajax": null,
13135
+
13136
+
13137
+ /**
13138
+ * Array referencing the nodes which are used for the features. The
13139
+ * parameters of this object match what is allowed by sDom - i.e.
13140
+ * <ul>
13141
+ * <li>'l' - Length changing</li>
13142
+ * <li>'f' - Filtering input</li>
13143
+ * <li>'t' - The table!</li>
13144
+ * <li>'i' - Information</li>
13145
+ * <li>'p' - Pagination</li>
13146
+ * <li>'r' - pRocessing</li>
13147
+ * </ul>
13148
+ * @type array
13149
+ * @default []
13150
+ */
13151
+ "aanFeatures": [],
13152
+
13153
+ /**
13154
+ * Store data information - see {@link DataTable.models.oRow} for detailed
13155
+ * information.
13156
+ * @type array
13157
+ * @default []
13158
+ */
13159
+ "aoData": [],
13160
+
13161
+ /**
13162
+ * Array of indexes which are in the current display (after filtering etc)
13163
+ * @type array
13164
+ * @default []
13165
+ */
13166
+ "aiDisplay": [],
13167
+
13168
+ /**
13169
+ * Array of indexes for display - no filtering
13170
+ * @type array
13171
+ * @default []
13172
+ */
13173
+ "aiDisplayMaster": [],
13174
+
13175
+ /**
13176
+ * Map of row ids to data indexes
13177
+ * @type object
13178
+ * @default {}
13179
+ */
13180
+ "aIds": {},
13181
+
13182
+ /**
13183
+ * Store information about each column that is in use
13184
+ * @type array
13185
+ * @default []
13186
+ */
13187
+ "aoColumns": [],
13188
+
13189
+ /**
13190
+ * Store information about the table's header
13191
+ * @type array
13192
+ * @default []
13193
+ */
13194
+ "aoHeader": [],
13195
+
13196
+ /**
13197
+ * Store information about the table's footer
13198
+ * @type array
13199
+ * @default []
13200
+ */
13201
+ "aoFooter": [],
13202
+
13203
+ /**
13204
+ * Store the applied global search information in case we want to force a
13205
+ * research or compare the old search to a new one.
13206
+ * Note that this parameter will be set by the initialisation routine. To
13207
+ * set a default use {@link DataTable.defaults}.
13208
+ * @namespace
13209
+ * @extends DataTable.models.oSearch
13210
+ */
13211
+ "oPreviousSearch": {},
13212
+
13213
+ /**
13214
+ * Store the applied search for each column - see
13215
+ * {@link DataTable.models.oSearch} for the format that is used for the
13216
+ * filtering information for each column.
13217
+ * @type array
13218
+ * @default []
13219
+ */
13220
+ "aoPreSearchCols": [],
13221
+
13222
+ /**
13223
+ * Sorting that is applied to the table. Note that the inner arrays are
13224
+ * used in the following manner:
13225
+ * <ul>
13226
+ * <li>Index 0 - column number</li>
13227
+ * <li>Index 1 - current sorting direction</li>
13228
+ * </ul>
13229
+ * Note that this parameter will be set by the initialisation routine. To
13230
+ * set a default use {@link DataTable.defaults}.
13231
+ * @type array
13232
+ * @todo These inner arrays should really be objects
13233
+ */
13234
+ "aaSorting": null,
13235
+
13236
+ /**
13237
+ * Sorting that is always applied to the table (i.e. prefixed in front of
13238
+ * aaSorting).
13239
+ * Note that this parameter will be set by the initialisation routine. To
13240
+ * set a default use {@link DataTable.defaults}.
13241
+ * @type array
13242
+ * @default []
13243
+ */
13244
+ "aaSortingFixed": [],
13245
+
13246
+ /**
13247
+ * Classes to use for the striping of a table.
13248
+ * Note that this parameter will be set by the initialisation routine. To
13249
+ * set a default use {@link DataTable.defaults}.
13250
+ * @type array
13251
+ * @default []
13252
+ */
13253
+ "asStripeClasses": null,
13254
+
13255
+ /**
13256
+ * If restoring a table - we should restore its striping classes as well
13257
+ * @type array
13258
+ * @default []
13259
+ */
13260
+ "asDestroyStripes": [],
13261
+
13262
+ /**
13263
+ * If restoring a table - we should restore its width
13264
+ * @type int
13265
+ * @default 0
13266
+ */
13267
+ "sDestroyWidth": 0,
13268
+
13269
+ /**
13270
+ * Callback functions array for every time a row is inserted (i.e. on a draw).
13271
+ * @type array
13272
+ * @default []
13273
+ */
13274
+ "aoRowCallback": [],
13275
+
13276
+ /**
13277
+ * Callback functions for the header on each draw.
13278
+ * @type array
13279
+ * @default []
13280
+ */
13281
+ "aoHeaderCallback": [],
13282
+
13283
+ /**
13284
+ * Callback function for the footer on each draw.
13285
+ * @type array
13286
+ * @default []
13287
+ */
13288
+ "aoFooterCallback": [],
13289
+
13290
+ /**
13291
+ * Array of callback functions for draw callback functions
13292
+ * @type array
13293
+ * @default []
13294
+ */
13295
+ "aoDrawCallback": [],
13296
+
13297
+ /**
13298
+ * Array of callback functions for row created function
13299
+ * @type array
13300
+ * @default []
13301
+ */
13302
+ "aoRowCreatedCallback": [],
13303
+
13304
+ /**
13305
+ * Callback functions for just before the table is redrawn. A return of
13306
+ * false will be used to cancel the draw.
13307
+ * @type array
13308
+ * @default []
13309
+ */
13310
+ "aoPreDrawCallback": [],
13311
+
13312
+ /**
13313
+ * Callback functions for when the table has been initialised.
13314
+ * @type array
13315
+ * @default []
13316
+ */
13317
+ "aoInitComplete": [],
13318
+
13319
+
13320
+ /**
13321
+ * Callbacks for modifying the settings to be stored for state saving, prior to
13322
+ * saving state.
13323
+ * @type array
13324
+ * @default []
13325
+ */
13326
+ "aoStateSaveParams": [],
13327
+
13328
+ /**
13329
+ * Callbacks for modifying the settings that have been stored for state saving
13330
+ * prior to using the stored values to restore the state.
13331
+ * @type array
13332
+ * @default []
13333
+ */
13334
+ "aoStateLoadParams": [],
13335
+
13336
+ /**
13337
+ * Callbacks for operating on the settings object once the saved state has been
13338
+ * loaded
13339
+ * @type array
13340
+ * @default []
13341
+ */
13342
+ "aoStateLoaded": [],
13343
+
13344
+ /**
13345
+ * Cache the table ID for quick access
13346
+ * @type string
13347
+ * @default <i>Empty string</i>
13348
+ */
13349
+ "sTableId": "",
13350
+
13351
+ /**
13352
+ * The TABLE node for the main table
13353
+ * @type node
13354
+ * @default null
13355
+ */
13356
+ "nTable": null,
13357
+
13358
+ /**
13359
+ * Permanent ref to the thead element
13360
+ * @type node
13361
+ * @default null
13362
+ */
13363
+ "nTHead": null,
13364
+
13365
+ /**
13366
+ * Permanent ref to the tfoot element - if it exists
13367
+ * @type node
13368
+ * @default null
13369
+ */
13370
+ "nTFoot": null,
13371
+
13372
+ /**
13373
+ * Permanent ref to the tbody element
13374
+ * @type node
13375
+ * @default null
13376
+ */
13377
+ "nTBody": null,
13378
+
13379
+ /**
13380
+ * Cache the wrapper node (contains all DataTables controlled elements)
13381
+ * @type node
13382
+ * @default null
13383
+ */
13384
+ "nTableWrapper": null,
13385
+
13386
+ /**
13387
+ * Indicate if when using server-side processing the loading of data
13388
+ * should be deferred until the second draw.
13389
+ * Note that this parameter will be set by the initialisation routine. To
13390
+ * set a default use {@link DataTable.defaults}.
13391
+ * @type boolean
13392
+ * @default false
13393
+ */
13394
+ "bDeferLoading": false,
13395
+
13396
+ /**
13397
+ * Indicate if all required information has been read in
13398
+ * @type boolean
13399
+ * @default false
13400
+ */
13401
+ "bInitialised": false,
13402
+
13403
+ /**
13404
+ * Information about open rows. Each object in the array has the parameters
13405
+ * 'nTr' and 'nParent'
13406
+ * @type array
13407
+ * @default []
13408
+ */
13409
+ "aoOpenRows": [],
13410
+
13411
+ /**
13412
+ * Dictate the positioning of DataTables' control elements - see
13413
+ * {@link DataTable.model.oInit.sDom}.
13414
+ * Note that this parameter will be set by the initialisation routine. To
13415
+ * set a default use {@link DataTable.defaults}.
13416
+ * @type string
13417
+ * @default null
13418
+ */
13419
+ "sDom": null,
13420
+
13421
+ /**
13422
+ * Search delay (in mS)
13423
+ * @type integer
13424
+ * @default null
13425
+ */
13426
+ "searchDelay": null,
13427
+
13428
+ /**
13429
+ * Which type of pagination should be used.
13430
+ * Note that this parameter will be set by the initialisation routine. To
13431
+ * set a default use {@link DataTable.defaults}.
13432
+ * @type string
13433
+ * @default two_button
13434
+ */
13435
+ "sPaginationType": "two_button",
13436
+
13437
+ /**
13438
+ * The state duration (for `stateSave`) in seconds.
13439
+ * Note that this parameter will be set by the initialisation routine. To
13440
+ * set a default use {@link DataTable.defaults}.
13441
+ * @type int
13442
+ * @default 0
13443
+ */
13444
+ "iStateDuration": 0,
13445
+
13446
+ /**
13447
+ * Array of callback functions for state saving. Each array element is an
13448
+ * object with the following parameters:
13449
+ * <ul>
13450
+ * <li>function:fn - function to call. Takes two parameters, oSettings
13451
+ * and the JSON string to save that has been thus far created. Returns
13452
+ * a JSON string to be inserted into a json object
13453
+ * (i.e. '"param": [ 0, 1, 2]')</li>
13454
+ * <li>string:sName - name of callback</li>
13455
+ * </ul>
13456
+ * @type array
13457
+ * @default []
13458
+ */
13459
+ "aoStateSave": [],
13460
+
13461
+ /**
13462
+ * Array of callback functions for state loading. Each array element is an
13463
+ * object with the following parameters:
13464
+ * <ul>
13465
+ * <li>function:fn - function to call. Takes two parameters, oSettings
13466
+ * and the object stored. May return false to cancel state loading</li>
13467
+ * <li>string:sName - name of callback</li>
13468
+ * </ul>
13469
+ * @type array
13470
+ * @default []
13471
+ */
13472
+ "aoStateLoad": [],
13473
+
13474
+ /**
13475
+ * State that was saved. Useful for back reference
13476
+ * @type object
13477
+ * @default null
13478
+ */
13479
+ "oSavedState": null,
13480
+
13481
+ /**
13482
+ * State that was loaded. Useful for back reference
13483
+ * @type object
13484
+ * @default null
13485
+ */
13486
+ "oLoadedState": null,
13487
+
13488
+ /**
13489
+ * Source url for AJAX data for the table.
13490
+ * Note that this parameter will be set by the initialisation routine. To
13491
+ * set a default use {@link DataTable.defaults}.
13492
+ * @type string
13493
+ * @default null
13494
+ */
13495
+ "sAjaxSource": null,
13496
+
13497
+ /**
13498
+ * Property from a given object from which to read the table data from. This
13499
+ * can be an empty string (when not server-side processing), in which case
13500
+ * it is assumed an an array is given directly.
13501
+ * Note that this parameter will be set by the initialisation routine. To
13502
+ * set a default use {@link DataTable.defaults}.
13503
+ * @type string
13504
+ */
13505
+ "sAjaxDataProp": null,
13506
+
13507
+ /**
13508
+ * Note if draw should be blocked while getting data
13509
+ * @type boolean
13510
+ * @default true
13511
+ */
13512
+ "bAjaxDataGet": true,
13513
+
13514
+ /**
13515
+ * The last jQuery XHR object that was used for server-side data gathering.
13516
+ * This can be used for working with the XHR information in one of the
13517
+ * callbacks
13518
+ * @type object
13519
+ * @default null
13520
+ */
13521
+ "jqXHR": null,
13522
+
13523
+ /**
13524
+ * JSON returned from the server in the last Ajax request
13525
+ * @type object
13526
+ * @default undefined
13527
+ */
13528
+ "json": undefined,
13529
+
13530
+ /**
13531
+ * Data submitted as part of the last Ajax request
13532
+ * @type object
13533
+ * @default undefined
13534
+ */
13535
+ "oAjaxData": undefined,
13536
+
13537
+ /**
13538
+ * Function to get the server-side data.
13539
+ * Note that this parameter will be set by the initialisation routine. To
13540
+ * set a default use {@link DataTable.defaults}.
13541
+ * @type function
13542
+ */
13543
+ "fnServerData": null,
13544
+
13545
+ /**
13546
+ * Functions which are called prior to sending an Ajax request so extra
13547
+ * parameters can easily be sent to the server
13548
+ * @type array
13549
+ * @default []
13550
+ */
13551
+ "aoServerParams": [],
13552
+
13553
+ /**
13554
+ * Send the XHR HTTP method - GET or POST (could be PUT or DELETE if
13555
+ * required).
13556
+ * Note that this parameter will be set by the initialisation routine. To
13557
+ * set a default use {@link DataTable.defaults}.
13558
+ * @type string
13559
+ */
13560
+ "sServerMethod": null,
13561
+
13562
+ /**
13563
+ * Format numbers for display.
13564
+ * Note that this parameter will be set by the initialisation routine. To
13565
+ * set a default use {@link DataTable.defaults}.
13566
+ * @type function
13567
+ */
13568
+ "fnFormatNumber": null,
13569
+
13570
+ /**
13571
+ * List of options that can be used for the user selectable length menu.
13572
+ * Note that this parameter will be set by the initialisation routine. To
13573
+ * set a default use {@link DataTable.defaults}.
13574
+ * @type array
13575
+ * @default []
13576
+ */
13577
+ "aLengthMenu": null,
13578
+
13579
+ /**
13580
+ * Counter for the draws that the table does. Also used as a tracker for
13581
+ * server-side processing
13582
+ * @type int
13583
+ * @default 0
13584
+ */
13585
+ "iDraw": 0,
13586
+
13587
+ /**
13588
+ * Indicate if a redraw is being done - useful for Ajax
13589
+ * @type boolean
13590
+ * @default false
13591
+ */
13592
+ "bDrawing": false,
13593
+
13594
+ /**
13595
+ * Draw index (iDraw) of the last error when parsing the returned data
13596
+ * @type int
13597
+ * @default -1
13598
+ */
13599
+ "iDrawError": -1,
13600
+
13601
+ /**
13602
+ * Paging display length
13603
+ * @type int
13604
+ * @default 10
13605
+ */
13606
+ "_iDisplayLength": 10,
13607
+
13608
+ /**
13609
+ * Paging start point - aiDisplay index
13610
+ * @type int
13611
+ * @default 0
13612
+ */
13613
+ "_iDisplayStart": 0,
13614
+
13615
+ /**
13616
+ * Server-side processing - number of records in the result set
13617
+ * (i.e. before filtering), Use fnRecordsTotal rather than
13618
+ * this property to get the value of the number of records, regardless of
13619
+ * the server-side processing setting.
13620
+ * @type int
13621
+ * @default 0
13622
+ * @private
13623
+ */
13624
+ "_iRecordsTotal": 0,
13625
+
13626
+ /**
13627
+ * Server-side processing - number of records in the current display set
13628
+ * (i.e. after filtering). Use fnRecordsDisplay rather than
13629
+ * this property to get the value of the number of records, regardless of
13630
+ * the server-side processing setting.
13631
+ * @type boolean
13632
+ * @default 0
13633
+ * @private
13634
+ */
13635
+ "_iRecordsDisplay": 0,
13636
+
13637
+ /**
13638
+ * The classes to use for the table
13639
+ * @type object
13640
+ * @default {}
13641
+ */
13642
+ "oClasses": {},
13643
+
13644
+ /**
13645
+ * Flag attached to the settings object so you can check in the draw
13646
+ * callback if filtering has been done in the draw. Deprecated in favour of
13647
+ * events.
13648
+ * @type boolean
13649
+ * @default false
13650
+ * @deprecated
13651
+ */
13652
+ "bFiltered": false,
13653
+
13654
+ /**
13655
+ * Flag attached to the settings object so you can check in the draw
13656
+ * callback if sorting has been done in the draw. Deprecated in favour of
13657
+ * events.
13658
+ * @type boolean
13659
+ * @default false
13660
+ * @deprecated
13661
+ */
13662
+ "bSorted": false,
13663
+
13664
+ /**
13665
+ * Indicate that if multiple rows are in the header and there is more than
13666
+ * one unique cell per column, if the top one (true) or bottom one (false)
13667
+ * should be used for sorting / title by DataTables.
13668
+ * Note that this parameter will be set by the initialisation routine. To
13669
+ * set a default use {@link DataTable.defaults}.
13670
+ * @type boolean
13671
+ */
13672
+ "bSortCellsTop": null,
13673
+
13674
+ /**
13675
+ * Initialisation object that is used for the table
13676
+ * @type object
13677
+ * @default null
13678
+ */
13679
+ "oInit": null,
13680
+
13681
+ /**
13682
+ * Destroy callback functions - for plug-ins to attach themselves to the
13683
+ * destroy so they can clean up markup and events.
13684
+ * @type array
13685
+ * @default []
13686
+ */
13687
+ "aoDestroyCallback": [],
13688
+
13689
+
13690
+ /**
13691
+ * Get the number of records in the current record set, before filtering
13692
+ * @type function
13693
+ */
13694
+ "fnRecordsTotal": function ()
13695
+ {
13696
+ return _fnDataSource( this ) == 'ssp' ?
13697
+ this._iRecordsTotal * 1 :
13698
+ this.aiDisplayMaster.length;
13699
+ },
13700
+
13701
+ /**
13702
+ * Get the number of records in the current record set, after filtering
13703
+ * @type function
13704
+ */
13705
+ "fnRecordsDisplay": function ()
13706
+ {
13707
+ return _fnDataSource( this ) == 'ssp' ?
13708
+ this._iRecordsDisplay * 1 :
13709
+ this.aiDisplay.length;
13710
+ },
13711
+
13712
+ /**
13713
+ * Get the display end point - aiDisplay index
13714
+ * @type function
13715
+ */
13716
+ "fnDisplayEnd": function ()
13717
+ {
13718
+ var
13719
+ len = this._iDisplayLength,
13720
+ start = this._iDisplayStart,
13721
+ calc = start + len,
13722
+ records = this.aiDisplay.length,
13723
+ features = this.oFeatures,
13724
+ paginate = features.bPaginate;
13725
+
13726
+ if ( features.bServerSide ) {
13727
+ return paginate === false || len === -1 ?
13728
+ start + records :
13729
+ Math.min( start+len, this._iRecordsDisplay );
13730
+ }
13731
+ else {
13732
+ return ! paginate || calc>records || len===-1 ?
13733
+ records :
13734
+ calc;
13735
+ }
13736
+ },
13737
+
13738
+ /**
13739
+ * The DataTables object for this table
13740
+ * @type object
13741
+ * @default null
13742
+ */
13743
+ "oInstance": null,
13744
+
13745
+ /**
13746
+ * Unique identifier for each instance of the DataTables object. If there
13747
+ * is an ID on the table node, then it takes that value, otherwise an
13748
+ * incrementing internal counter is used.
13749
+ * @type string
13750
+ * @default null
13751
+ */
13752
+ "sInstance": null,
13753
+
13754
+ /**
13755
+ * tabindex attribute value that is added to DataTables control elements, allowing
13756
+ * keyboard navigation of the table and its controls.
13757
+ */
13758
+ "iTabIndex": 0,
13759
+
13760
+ /**
13761
+ * DIV container for the footer scrolling table if scrolling
13762
+ */
13763
+ "nScrollHead": null,
13764
+
13765
+ /**
13766
+ * DIV container for the footer scrolling table if scrolling
13767
+ */
13768
+ "nScrollFoot": null,
13769
+
13770
+ /**
13771
+ * Last applied sort
13772
+ * @type array
13773
+ * @default []
13774
+ */
13775
+ "aLastSort": [],
13776
+
13777
+ /**
13778
+ * Stored plug-in instances
13779
+ * @type object
13780
+ * @default {}
13781
+ */
13782
+ "oPlugins": {},
13783
+
13784
+ /**
13785
+ * Function used to get a row's id from the row's data
13786
+ * @type function
13787
+ * @default null
13788
+ */
13789
+ "rowIdFn": null,
13790
+
13791
+ /**
13792
+ * Data location where to store a row's id
13793
+ * @type string
13794
+ * @default null
13795
+ */
13796
+ "rowId": null
13797
+ };
13798
+
13799
+ /**
13800
+ * Extension object for DataTables that is used to provide all extension
13801
+ * options.
13802
+ *
13803
+ * Note that the `DataTable.ext` object is available through
13804
+ * `jQuery.fn.dataTable.ext` where it may be accessed and manipulated. It is
13805
+ * also aliased to `jQuery.fn.dataTableExt` for historic reasons.
13806
+ * @namespace
13807
+ * @extends DataTable.models.ext
13808
+ */
13809
+
13810
+
13811
+ /**
13812
+ * DataTables extensions
13813
+ *
13814
+ * This namespace acts as a collection area for plug-ins that can be used to
13815
+ * extend DataTables capabilities. Indeed many of the build in methods
13816
+ * use this method to provide their own capabilities (sorting methods for
13817
+ * example).
13818
+ *
13819
+ * Note that this namespace is aliased to `jQuery.fn.dataTableExt` for legacy
13820
+ * reasons
13821
+ *
13822
+ * @namespace
13823
+ */
13824
+ DataTable.ext = _ext = {
13825
+ /**
13826
+ * Buttons. For use with the Buttons extension for DataTables. This is
13827
+ * defined here so other extensions can define buttons regardless of load
13828
+ * order. It is _not_ used by DataTables core.
13829
+ *
13830
+ * @type object
13831
+ * @default {}
13832
+ */
13833
+ buttons: {},
13834
+
13835
+
13836
+ /**
13837
+ * Element class names
13838
+ *
13839
+ * @type object
13840
+ * @default {}
13841
+ */
13842
+ classes: {},
13843
+
13844
+
13845
+ /**
13846
+ * DataTables build type (expanded by the download builder)
13847
+ *
13848
+ * @type string
13849
+ */
13850
+ build:"dt/dt-1.10.16/af-2.2.2/b-1.5.1/cr-1.4.1/fc-3.2.4/fh-3.1.3/kt-2.3.2/r-2.2.1/rr-1.2.3/sc-1.4.4/sl-1.2.5",
13851
+
13852
+
13853
+ /**
13854
+ * Error reporting.
13855
+ *
13856
+ * How should DataTables report an error. Can take the value 'alert',
13857
+ * 'throw', 'none' or a function.
13858
+ *
13859
+ * @type string|function
13860
+ * @default alert
13861
+ */
13862
+ errMode: "alert",
13863
+
13864
+
13865
+ /**
13866
+ * Feature plug-ins.
13867
+ *
13868
+ * This is an array of objects which describe the feature plug-ins that are
13869
+ * available to DataTables. These feature plug-ins are then available for
13870
+ * use through the `dom` initialisation option.
13871
+ *
13872
+ * Each feature plug-in is described by an object which must have the
13873
+ * following properties:
13874
+ *
13875
+ * * `fnInit` - function that is used to initialise the plug-in,
13876
+ * * `cFeature` - a character so the feature can be enabled by the `dom`
13877
+ * instillation option. This is case sensitive.
13878
+ *
13879
+ * The `fnInit` function has the following input parameters:
13880
+ *
13881
+ * 1. `{object}` DataTables settings object: see
13882
+ * {@link DataTable.models.oSettings}
13883
+ *
13884
+ * And the following return is expected:
13885
+ *
13886
+ * * {node|null} The element which contains your feature. Note that the
13887
+ * return may also be void if your plug-in does not require to inject any
13888
+ * DOM elements into DataTables control (`dom`) - for example this might
13889
+ * be useful when developing a plug-in which allows table control via
13890
+ * keyboard entry
13891
+ *
13892
+ * @type array
13893
+ *
13894
+ * @example
13895
+ * $.fn.dataTable.ext.features.push( {
13896
+ * "fnInit": function( oSettings ) {
13897
+ * return new TableTools( { "oDTSettings": oSettings } );
13898
+ * },
13899
+ * "cFeature": "T"
13900
+ * } );
13901
+ */
13902
+ feature: [],
13903
+
13904
+
13905
+ /**
13906
+ * Row searching.
13907
+ *
13908
+ * This method of searching is complimentary to the default type based
13909
+ * searching, and a lot more comprehensive as it allows you complete control
13910
+ * over the searching logic. Each element in this array is a function
13911
+ * (parameters described below) that is called for every row in the table,
13912
+ * and your logic decides if it should be included in the searching data set
13913
+ * or not.
13914
+ *
13915
+ * Searching functions have the following input parameters:
13916
+ *
13917
+ * 1. `{object}` DataTables settings object: see
13918
+ * {@link DataTable.models.oSettings}
13919
+ * 2. `{array|object}` Data for the row to be processed (same as the
13920
+ * original format that was passed in as the data source, or an array
13921
+ * from a DOM data source
13922
+ * 3. `{int}` Row index ({@link DataTable.models.oSettings.aoData}), which
13923
+ * can be useful to retrieve the `TR` element if you need DOM interaction.
13924
+ *
13925
+ * And the following return is expected:
13926
+ *
13927
+ * * {boolean} Include the row in the searched result set (true) or not
13928
+ * (false)
13929
+ *
13930
+ * Note that as with the main search ability in DataTables, technically this
13931
+ * is "filtering", since it is subtractive. However, for consistency in
13932
+ * naming we call it searching here.
13933
+ *
13934
+ * @type array
13935
+ * @default []
13936
+ *
13937
+ * @example
13938
+ * // The following example shows custom search being applied to the
13939
+ * // fourth column (i.e. the data[3] index) based on two input values
13940
+ * // from the end-user, matching the data in a certain range.
13941
+ * $.fn.dataTable.ext.search.push(
13942
+ * function( settings, data, dataIndex ) {
13943
+ * var min = document.getElementById('min').value * 1;
13944
+ * var max = document.getElementById('max').value * 1;
13945
+ * var version = data[3] == "-" ? 0 : data[3]*1;
13946
+ *
13947
+ * if ( min == "" && max == "" ) {
13948
+ * return true;
13949
+ * }
13950
+ * else if ( min == "" && version < max ) {
13951
+ * return true;
13952
+ * }
13953
+ * else if ( min < version && "" == max ) {
13954
+ * return true;
13955
+ * }
13956
+ * else if ( min < version && version < max ) {
13957
+ * return true;
13958
+ * }
13959
+ * return false;
13960
+ * }
13961
+ * );
13962
+ */
13963
+ search: [],
13964
+
13965
+
13966
+ /**
13967
+ * Selector extensions
13968
+ *
13969
+ * The `selector` option can be used to extend the options available for the
13970
+ * selector modifier options (`selector-modifier` object data type) that
13971
+ * each of the three built in selector types offer (row, column and cell +
13972
+ * their plural counterparts). For example the Select extension uses this
13973
+ * mechanism to provide an option to select only rows, columns and cells
13974
+ * that have been marked as selected by the end user (`{selected: true}`),
13975
+ * which can be used in conjunction with the existing built in selector
13976
+ * options.
13977
+ *
13978
+ * Each property is an array to which functions can be pushed. The functions
13979
+ * take three attributes:
13980
+ *
13981
+ * * Settings object for the host table
13982
+ * * Options object (`selector-modifier` object type)
13983
+ * * Array of selected item indexes
13984
+ *
13985
+ * The return is an array of the resulting item indexes after the custom
13986
+ * selector has been applied.
13987
+ *
13988
+ * @type object
13989
+ */
13990
+ selector: {
13991
+ cell: [],
13992
+ column: [],
13993
+ row: []
13994
+ },
13995
+
13996
+
13997
+ /**
13998
+ * Internal functions, exposed for used in plug-ins.
13999
+ *
14000
+ * Please note that you should not need to use the internal methods for
14001
+ * anything other than a plug-in (and even then, try to avoid if possible).
14002
+ * The internal function may change between releases.
14003
+ *
14004
+ * @type object
14005
+ * @default {}
14006
+ */
14007
+ internal: {},
14008
+
14009
+
14010
+ /**
14011
+ * Legacy configuration options. Enable and disable legacy options that
14012
+ * are available in DataTables.
14013
+ *
14014
+ * @type object
14015
+ */
14016
+ legacy: {
14017
+ /**
14018
+ * Enable / disable DataTables 1.9 compatible server-side processing
14019
+ * requests
14020
+ *
14021
+ * @type boolean
14022
+ * @default null
14023
+ */
14024
+ ajax: null
14025
+ },
14026
+
14027
+
14028
+ /**
14029
+ * Pagination plug-in methods.
14030
+ *
14031
+ * Each entry in this object is a function and defines which buttons should
14032
+ * be shown by the pagination rendering method that is used for the table:
14033
+ * {@link DataTable.ext.renderer.pageButton}. The renderer addresses how the
14034
+ * buttons are displayed in the document, while the functions here tell it
14035
+ * what buttons to display. This is done by returning an array of button
14036
+ * descriptions (what each button will do).
14037
+ *
14038
+ * Pagination types (the four built in options and any additional plug-in
14039
+ * options defined here) can be used through the `paginationType`
14040
+ * initialisation parameter.
14041
+ *
14042
+ * The functions defined take two parameters:
14043
+ *
14044
+ * 1. `{int} page` The current page index
14045
+ * 2. `{int} pages` The number of pages in the table
14046
+ *
14047
+ * Each function is expected to return an array where each element of the
14048
+ * array can be one of:
14049
+ *
14050
+ * * `first` - Jump to first page when activated
14051
+ * * `last` - Jump to last page when activated
14052
+ * * `previous` - Show previous page when activated
14053
+ * * `next` - Show next page when activated
14054
+ * * `{int}` - Show page of the index given
14055
+ * * `{array}` - A nested array containing the above elements to add a
14056
+ * containing 'DIV' element (might be useful for styling).
14057
+ *
14058
+ * Note that DataTables v1.9- used this object slightly differently whereby
14059
+ * an object with two functions would be defined for each plug-in. That
14060
+ * ability is still supported by DataTables 1.10+ to provide backwards
14061
+ * compatibility, but this option of use is now decremented and no longer
14062
+ * documented in DataTables 1.10+.
14063
+ *
14064
+ * @type object
14065
+ * @default {}
14066
+ *
14067
+ * @example
14068
+ * // Show previous, next and current page buttons only
14069
+ * $.fn.dataTableExt.oPagination.current = function ( page, pages ) {
14070
+ * return [ 'previous', page, 'next' ];
14071
+ * };
14072
+ */
14073
+ pager: {},
14074
+
14075
+
14076
+ renderer: {
14077
+ pageButton: {},
14078
+ header: {}
14079
+ },
14080
+
14081
+
14082
+ /**
14083
+ * Ordering plug-ins - custom data source
14084
+ *
14085
+ * The extension options for ordering of data available here is complimentary
14086
+ * to the default type based ordering that DataTables typically uses. It
14087
+ * allows much greater control over the the data that is being used to
14088
+ * order a column, but is necessarily therefore more complex.
14089
+ *
14090
+ * This type of ordering is useful if you want to do ordering based on data
14091
+ * live from the DOM (for example the contents of an 'input' element) rather
14092
+ * than just the static string that DataTables knows of.
14093
+ *
14094
+ * The way these plug-ins work is that you create an array of the values you
14095
+ * wish to be ordering for the column in question and then return that
14096
+ * array. The data in the array much be in the index order of the rows in
14097
+ * the table (not the currently ordering order!). Which order data gathering
14098
+ * function is run here depends on the `dt-init columns.orderDataType`
14099
+ * parameter that is used for the column (if any).
14100
+ *
14101
+ * The functions defined take two parameters:
14102
+ *
14103
+ * 1. `{object}` DataTables settings object: see
14104
+ * {@link DataTable.models.oSettings}
14105
+ * 2. `{int}` Target column index
14106
+ *
14107
+ * Each function is expected to return an array:
14108
+ *
14109
+ * * `{array}` Data for the column to be ordering upon
14110
+ *
14111
+ * @type array
14112
+ *
14113
+ * @example
14114
+ * // Ordering using `input` node values
14115
+ * $.fn.dataTable.ext.order['dom-text'] = function ( settings, col )
14116
+ * {
14117
+ * return this.api().column( col, {order:'index'} ).nodes().map( function ( td, i ) {
14118
+ * return $('input', td).val();
14119
+ * } );
14120
+ * }
14121
+ */
14122
+ order: {},
14123
+
14124
+
14125
+ /**
14126
+ * Type based plug-ins.
14127
+ *
14128
+ * Each column in DataTables has a type assigned to it, either by automatic
14129
+ * detection or by direct assignment using the `type` option for the column.
14130
+ * The type of a column will effect how it is ordering and search (plug-ins
14131
+ * can also make use of the column type if required).
14132
+ *
14133
+ * @namespace
14134
+ */
14135
+ type: {
14136
+ /**
14137
+ * Type detection functions.
14138
+ *
14139
+ * The functions defined in this object are used to automatically detect
14140
+ * a column's type, making initialisation of DataTables super easy, even
14141
+ * when complex data is in the table.
14142
+ *
14143
+ * The functions defined take two parameters:
14144
+ *
14145
+ * 1. `{*}` Data from the column cell to be analysed
14146
+ * 2. `{settings}` DataTables settings object. This can be used to
14147
+ * perform context specific type detection - for example detection
14148
+ * based on language settings such as using a comma for a decimal
14149
+ * place. Generally speaking the options from the settings will not
14150
+ * be required
14151
+ *
14152
+ * Each function is expected to return:
14153
+ *
14154
+ * * `{string|null}` Data type detected, or null if unknown (and thus
14155
+ * pass it on to the other type detection functions.
14156
+ *
14157
+ * @type array
14158
+ *
14159
+ * @example
14160
+ * // Currency type detection plug-in:
14161
+ * $.fn.dataTable.ext.type.detect.push(
14162
+ * function ( data, settings ) {
14163
+ * // Check the numeric part
14164
+ * if ( ! $.isNumeric( data.substring(1) ) ) {
14165
+ * return null;
14166
+ * }
14167
+ *
14168
+ * // Check prefixed by currency
14169
+ * if ( data.charAt(0) == '$' || data.charAt(0) == '&pound;' ) {
14170
+ * return 'currency';
14171
+ * }
14172
+ * return null;
14173
+ * }
14174
+ * );
14175
+ */
14176
+ detect: [],
14177
+
14178
+
14179
+ /**
14180
+ * Type based search formatting.
14181
+ *
14182
+ * The type based searching functions can be used to pre-format the
14183
+ * data to be search on. For example, it can be used to strip HTML
14184
+ * tags or to de-format telephone numbers for numeric only searching.
14185
+ *
14186
+ * Note that is a search is not defined for a column of a given type,
14187
+ * no search formatting will be performed.
14188
+ *
14189
+ * Pre-processing of searching data plug-ins - When you assign the sType
14190
+ * for a column (or have it automatically detected for you by DataTables
14191
+ * or a type detection plug-in), you will typically be using this for
14192
+ * custom sorting, but it can also be used to provide custom searching
14193
+ * by allowing you to pre-processing the data and returning the data in
14194
+ * the format that should be searched upon. This is done by adding
14195
+ * functions this object with a parameter name which matches the sType
14196
+ * for that target column. This is the corollary of <i>afnSortData</i>
14197
+ * for searching data.
14198
+ *
14199
+ * The functions defined take a single parameter:
14200
+ *
14201
+ * 1. `{*}` Data from the column cell to be prepared for searching
14202
+ *
14203
+ * Each function is expected to return:
14204
+ *
14205
+ * * `{string|null}` Formatted string that will be used for the searching.
14206
+ *
14207
+ * @type object
14208
+ * @default {}
14209
+ *
14210
+ * @example
14211
+ * $.fn.dataTable.ext.type.search['title-numeric'] = function ( d ) {
14212
+ * return d.replace(/\n/g," ").replace( /<.*?>/g, "" );
14213
+ * }
14214
+ */
14215
+ search: {},
14216
+
14217
+
14218
+ /**
14219
+ * Type based ordering.
14220
+ *
14221
+ * The column type tells DataTables what ordering to apply to the table
14222
+ * when a column is sorted upon. The order for each type that is defined,
14223
+ * is defined by the functions available in this object.
14224
+ *
14225
+ * Each ordering option can be described by three properties added to
14226
+ * this object:
14227
+ *
14228
+ * * `{type}-pre` - Pre-formatting function
14229
+ * * `{type}-asc` - Ascending order function
14230
+ * * `{type}-desc` - Descending order function
14231
+ *
14232
+ * All three can be used together, only `{type}-pre` or only
14233
+ * `{type}-asc` and `{type}-desc` together. It is generally recommended
14234
+ * that only `{type}-pre` is used, as this provides the optimal
14235
+ * implementation in terms of speed, although the others are provided
14236
+ * for compatibility with existing Javascript sort functions.
14237
+ *
14238
+ * `{type}-pre`: Functions defined take a single parameter:
14239
+ *
14240
+ * 1. `{*}` Data from the column cell to be prepared for ordering
14241
+ *
14242
+ * And return:
14243
+ *
14244
+ * * `{*}` Data to be sorted upon
14245
+ *
14246
+ * `{type}-asc` and `{type}-desc`: Functions are typical Javascript sort
14247
+ * functions, taking two parameters:
14248
+ *
14249
+ * 1. `{*}` Data to compare to the second parameter
14250
+ * 2. `{*}` Data to compare to the first parameter
14251
+ *
14252
+ * And returning:
14253
+ *
14254
+ * * `{*}` Ordering match: <0 if first parameter should be sorted lower
14255
+ * than the second parameter, ===0 if the two parameters are equal and
14256
+ * >0 if the first parameter should be sorted height than the second
14257
+ * parameter.
14258
+ *
14259
+ * @type object
14260
+ * @default {}
14261
+ *
14262
+ * @example
14263
+ * // Numeric ordering of formatted numbers with a pre-formatter
14264
+ * $.extend( $.fn.dataTable.ext.type.order, {
14265
+ * "string-pre": function(x) {
14266
+ * a = (a === "-" || a === "") ? 0 : a.replace( /[^\d\-\.]/g, "" );
14267
+ * return parseFloat( a );
14268
+ * }
14269
+ * } );
14270
+ *
14271
+ * @example
14272
+ * // Case-sensitive string ordering, with no pre-formatting method
14273
+ * $.extend( $.fn.dataTable.ext.order, {
14274
+ * "string-case-asc": function(x,y) {
14275
+ * return ((x < y) ? -1 : ((x > y) ? 1 : 0));
14276
+ * },
14277
+ * "string-case-desc": function(x,y) {
14278
+ * return ((x < y) ? 1 : ((x > y) ? -1 : 0));
14279
+ * }
14280
+ * } );
14281
+ */
14282
+ order: {}
14283
+ },
14284
+
14285
+ /**
14286
+ * Unique DataTables instance counter
14287
+ *
14288
+ * @type int
14289
+ * @private
14290
+ */
14291
+ _unique: 0,
14292
+
14293
+
14294
+ //
14295
+ // Depreciated
14296
+ // The following properties are retained for backwards compatiblity only.
14297
+ // The should not be used in new projects and will be removed in a future
14298
+ // version
14299
+ //
14300
+
14301
+ /**
14302
+ * Version check function.
14303
+ * @type function
14304
+ * @depreciated Since 1.10
14305
+ */
14306
+ fnVersionCheck: DataTable.fnVersionCheck,
14307
+
14308
+
14309
+ /**
14310
+ * Index for what 'this' index API functions should use
14311
+ * @type int
14312
+ * @deprecated Since v1.10
14313
+ */
14314
+ iApiIndex: 0,
14315
+
14316
+
14317
+ /**
14318
+ * jQuery UI class container
14319
+ * @type object
14320
+ * @deprecated Since v1.10
14321
+ */
14322
+ oJUIClasses: {},
14323
+
14324
+
14325
+ /**
14326
+ * Software version
14327
+ * @type string
14328
+ * @deprecated Since v1.10
14329
+ */
14330
+ sVersion: DataTable.version
14331
+ };
14332
+
14333
+
14334
+ //
14335
+ // Backwards compatibility. Alias to pre 1.10 Hungarian notation counter parts
14336
+ //
14337
+ $.extend( _ext, {
14338
+ afnFiltering: _ext.search,
14339
+ aTypes: _ext.type.detect,
14340
+ ofnSearch: _ext.type.search,
14341
+ oSort: _ext.type.order,
14342
+ afnSortData: _ext.order,
14343
+ aoFeatures: _ext.feature,
14344
+ oApi: _ext.internal,
14345
+ oStdClasses: _ext.classes,
14346
+ oPagination: _ext.pager
14347
+ } );
14348
+
14349
+
14350
+ $.extend( DataTable.ext.classes, {
14351
+ "sTable": "dataTable",
14352
+ "sNoFooter": "no-footer",
14353
+
14354
+ /* Paging buttons */
14355
+ "sPageButton": "paginate_button",
14356
+ "sPageButtonActive": "current",
14357
+ "sPageButtonDisabled": "disabled",
14358
+
14359
+ /* Striping classes */
14360
+ "sStripeOdd": "odd",
14361
+ "sStripeEven": "even",
14362
+
14363
+ /* Empty row */
14364
+ "sRowEmpty": "dataTables_empty",
14365
+
14366
+ /* Features */
14367
+ "sWrapper": "dataTables_wrapper",
14368
+ "sFilter": "dataTables_filter",
14369
+ "sInfo": "dataTables_info",
14370
+ "sPaging": "dataTables_paginate paging_", /* Note that the type is postfixed */
14371
+ "sLength": "dataTables_length",
14372
+ "sProcessing": "dataTables_processing",
14373
+
14374
+ /* Sorting */
14375
+ "sSortAsc": "sorting_asc",
14376
+ "sSortDesc": "sorting_desc",
14377
+ "sSortable": "sorting", /* Sortable in both directions */
14378
+ "sSortableAsc": "sorting_asc_disabled",
14379
+ "sSortableDesc": "sorting_desc_disabled",
14380
+ "sSortableNone": "sorting_disabled",
14381
+ "sSortColumn": "sorting_", /* Note that an int is postfixed for the sorting order */
14382
+
14383
+ /* Filtering */
14384
+ "sFilterInput": "",
14385
+
14386
+ /* Page length */
14387
+ "sLengthSelect": "",
14388
+
14389
+ /* Scrolling */
14390
+ "sScrollWrapper": "dataTables_scroll",
14391
+ "sScrollHead": "dataTables_scrollHead",
14392
+ "sScrollHeadInner": "dataTables_scrollHeadInner",
14393
+ "sScrollBody": "dataTables_scrollBody",
14394
+ "sScrollFoot": "dataTables_scrollFoot",
14395
+ "sScrollFootInner": "dataTables_scrollFootInner",
14396
+
14397
+ /* Misc */
14398
+ "sHeaderTH": "",
14399
+ "sFooterTH": "",
14400
+
14401
+ // Deprecated
14402
+ "sSortJUIAsc": "",
14403
+ "sSortJUIDesc": "",
14404
+ "sSortJUI": "",
14405
+ "sSortJUIAscAllowed": "",
14406
+ "sSortJUIDescAllowed": "",
14407
+ "sSortJUIWrapper": "",
14408
+ "sSortIcon": "",
14409
+ "sJUIHeader": "",
14410
+ "sJUIFooter": ""
14411
+ } );
14412
+
14413
+
14414
+ var extPagination = DataTable.ext.pager;
14415
+
14416
+ function _numbers ( page, pages ) {
14417
+ var
14418
+ numbers = [],
14419
+ buttons = extPagination.numbers_length,
14420
+ half = Math.floor( buttons / 2 ),
14421
+ i = 1;
14422
+
14423
+ if ( pages <= buttons ) {
14424
+ numbers = _range( 0, pages );
14425
+ }
14426
+ else if ( page <= half ) {
14427
+ numbers = _range( 0, buttons-2 );
14428
+ numbers.push( 'ellipsis' );
14429
+ numbers.push( pages-1 );
14430
+ }
14431
+ else if ( page >= pages - 1 - half ) {
14432
+ numbers = _range( pages-(buttons-2), pages );
14433
+ numbers.splice( 0, 0, 'ellipsis' ); // no unshift in ie6
14434
+ numbers.splice( 0, 0, 0 );
14435
+ }
14436
+ else {
14437
+ numbers = _range( page-half+2, page+half-1 );
14438
+ numbers.push( 'ellipsis' );
14439
+ numbers.push( pages-1 );
14440
+ numbers.splice( 0, 0, 'ellipsis' );
14441
+ numbers.splice( 0, 0, 0 );
14442
+ }
14443
+
14444
+ numbers.DT_el = 'span';
14445
+ return numbers;
14446
+ }
14447
+
14448
+
14449
+ $.extend( extPagination, {
14450
+ simple: function ( page, pages ) {
14451
+ return [ 'previous', 'next' ];
14452
+ },
14453
+
14454
+ full: function ( page, pages ) {
14455
+ return [ 'first', 'previous', 'next', 'last' ];
14456
+ },
14457
+
14458
+ numbers: function ( page, pages ) {
14459
+ return [ _numbers(page, pages) ];
14460
+ },
14461
+
14462
+ simple_numbers: function ( page, pages ) {
14463
+ return [ 'previous', _numbers(page, pages), 'next' ];
14464
+ },
14465
+
14466
+ full_numbers: function ( page, pages ) {
14467
+ return [ 'first', 'previous', _numbers(page, pages), 'next', 'last' ];
14468
+ },
14469
+
14470
+ first_last_numbers: function (page, pages) {
14471
+ return ['first', _numbers(page, pages), 'last'];
14472
+ },
14473
+
14474
+ // For testing and plug-ins to use
14475
+ _numbers: _numbers,
14476
+
14477
+ // Number of number buttons (including ellipsis) to show. _Must be odd!_
14478
+ numbers_length: 7
14479
+ } );
14480
+
14481
+
14482
+ $.extend( true, DataTable.ext.renderer, {
14483
+ pageButton: {
14484
+ _: function ( settings, host, idx, buttons, page, pages ) {
14485
+ var classes = settings.oClasses;
14486
+ var lang = settings.oLanguage.oPaginate;
14487
+ var aria = settings.oLanguage.oAria.paginate || {};
14488
+ var btnDisplay, btnClass, counter=0;
14489
+
14490
+ var attach = function( container, buttons ) {
14491
+ var i, ien, node, button;
14492
+ var clickHandler = function ( e ) {
14493
+ _fnPageChange( settings, e.data.action, true );
14494
+ };
14495
+
14496
+ for ( i=0, ien=buttons.length ; i<ien ; i++ ) {
14497
+ button = buttons[i];
14498
+
14499
+ if ( $.isArray( button ) ) {
14500
+ var inner = $( '<'+(button.DT_el || 'div')+'/>' )
14501
+ .appendTo( container );
14502
+ attach( inner, button );
14503
+ }
14504
+ else {
14505
+ btnDisplay = null;
14506
+ btnClass = '';
14507
+
14508
+ switch ( button ) {
14509
+ case 'ellipsis':
14510
+ container.append('<span class="ellipsis">&#x2026;</span>');
14511
+ break;
14512
+
14513
+ case 'first':
14514
+ btnDisplay = lang.sFirst;
14515
+ btnClass = button + (page > 0 ?
14516
+ '' : ' '+classes.sPageButtonDisabled);
14517
+ break;
14518
+
14519
+ case 'previous':
14520
+ btnDisplay = lang.sPrevious;
14521
+ btnClass = button + (page > 0 ?
14522
+ '' : ' '+classes.sPageButtonDisabled);
14523
+ break;
14524
+
14525
+ case 'next':
14526
+ btnDisplay = lang.sNext;
14527
+ btnClass = button + (page < pages-1 ?
14528
+ '' : ' '+classes.sPageButtonDisabled);
14529
+ break;
14530
+
14531
+ case 'last':
14532
+ btnDisplay = lang.sLast;
14533
+ btnClass = button + (page < pages-1 ?
14534
+ '' : ' '+classes.sPageButtonDisabled);
14535
+ break;
14536
+
14537
+ default:
14538
+ btnDisplay = button + 1;
14539
+ btnClass = page === button ?
14540
+ classes.sPageButtonActive : '';
14541
+ break;
14542
+ }
14543
+
14544
+ if ( btnDisplay !== null ) {
14545
+ node = $('<a>', {
14546
+ 'class': classes.sPageButton+' '+btnClass,
14547
+ 'aria-controls': settings.sTableId,
14548
+ 'aria-label': aria[ button ],
14549
+ 'data-dt-idx': counter,
14550
+ 'tabindex': settings.iTabIndex,
14551
+ 'id': idx === 0 && typeof button === 'string' ?
14552
+ settings.sTableId +'_'+ button :
14553
+ null
14554
+ } )
14555
+ .html( btnDisplay )
14556
+ .appendTo( container );
14557
+
14558
+ _fnBindAction(
14559
+ node, {action: button}, clickHandler
14560
+ );
14561
+
14562
+ counter++;
14563
+ }
14564
+ }
14565
+ }
14566
+ };
14567
+
14568
+ // IE9 throws an 'unknown error' if document.activeElement is used
14569
+ // inside an iframe or frame. Try / catch the error. Not good for
14570
+ // accessibility, but neither are frames.
14571
+ var activeEl;
14572
+
14573
+ try {
14574
+ // Because this approach is destroying and recreating the paging
14575
+ // elements, focus is lost on the select button which is bad for
14576
+ // accessibility. So we want to restore focus once the draw has
14577
+ // completed
14578
+ activeEl = $(host).find(document.activeElement).data('dt-idx');
14579
+ }
14580
+ catch (e) {}
14581
+
14582
+ attach( $(host).empty(), buttons );
14583
+
14584
+ if ( activeEl !== undefined ) {
14585
+ $(host).find( '[data-dt-idx='+activeEl+']' ).focus();
14586
+ }
14587
+ }
14588
+ }
14589
+ } );
14590
+
14591
+
14592
+
14593
+ // Built in type detection. See model.ext.aTypes for information about
14594
+ // what is required from this methods.
14595
+ $.extend( DataTable.ext.type.detect, [
14596
+ // Plain numbers - first since V8 detects some plain numbers as dates
14597
+ // e.g. Date.parse('55') (but not all, e.g. Date.parse('22')...).
14598
+ function ( d, settings )
14599
+ {
14600
+ var decimal = settings.oLanguage.sDecimal;
14601
+ return _isNumber( d, decimal ) ? 'num'+decimal : null;
14602
+ },
14603
+
14604
+ // Dates (only those recognised by the browser's Date.parse)
14605
+ function ( d, settings )
14606
+ {
14607
+ // V8 tries _very_ hard to make a string passed into `Date.parse()`
14608
+ // valid, so we need to use a regex to restrict date formats. Use a
14609
+ // plug-in for anything other than ISO8601 style strings
14610
+ if ( d && !(d instanceof Date) && ! _re_date.test(d) ) {
14611
+ return null;
14612
+ }
14613
+ var parsed = Date.parse(d);
14614
+ return (parsed !== null && !isNaN(parsed)) || _empty(d) ? 'date' : null;
14615
+ },
14616
+
14617
+ // Formatted numbers
14618
+ function ( d, settings )
14619
+ {
14620
+ var decimal = settings.oLanguage.sDecimal;
14621
+ return _isNumber( d, decimal, true ) ? 'num-fmt'+decimal : null;
14622
+ },
14623
+
14624
+ // HTML numeric
14625
+ function ( d, settings )
14626
+ {
14627
+ var decimal = settings.oLanguage.sDecimal;
14628
+ return _htmlNumeric( d, decimal ) ? 'html-num'+decimal : null;
14629
+ },
14630
+
14631
+ // HTML numeric, formatted
14632
+ function ( d, settings )
14633
+ {
14634
+ var decimal = settings.oLanguage.sDecimal;
14635
+ return _htmlNumeric( d, decimal, true ) ? 'html-num-fmt'+decimal : null;
14636
+ },
14637
+
14638
+ // HTML (this is strict checking - there must be html)
14639
+ function ( d, settings )
14640
+ {
14641
+ return _empty( d ) || (typeof d === 'string' && d.indexOf('<') !== -1) ?
14642
+ 'html' : null;
14643
+ }
14644
+ ] );
14645
+
14646
+
14647
+
14648
+ // Filter formatting functions. See model.ext.ofnSearch for information about
14649
+ // what is required from these methods.
14650
+ //
14651
+ // Note that additional search methods are added for the html numbers and
14652
+ // html formatted numbers by `_addNumericSort()` when we know what the decimal
14653
+ // place is
14654
+
14655
+
14656
+ $.extend( DataTable.ext.type.search, {
14657
+ html: function ( data ) {
14658
+ return _empty(data) ?
14659
+ data :
14660
+ typeof data === 'string' ?
14661
+ data
14662
+ .replace( _re_new_lines, " " )
14663
+ .replace( _re_html, "" ) :
14664
+ '';
14665
+ },
14666
+
14667
+ string: function ( data ) {
14668
+ return _empty(data) ?
14669
+ data :
14670
+ typeof data === 'string' ?
14671
+ data.replace( _re_new_lines, " " ) :
14672
+ data;
14673
+ }
14674
+ } );
14675
+
14676
+
14677
+
14678
+ var __numericReplace = function ( d, decimalPlace, re1, re2 ) {
14679
+ if ( d !== 0 && (!d || d === '-') ) {
14680
+ return -Infinity;
14681
+ }
14682
+
14683
+ // If a decimal place other than `.` is used, it needs to be given to the
14684
+ // function so we can detect it and replace with a `.` which is the only
14685
+ // decimal place Javascript recognises - it is not locale aware.
14686
+ if ( decimalPlace ) {
14687
+ d = _numToDecimal( d, decimalPlace );
14688
+ }
14689
+
14690
+ if ( d.replace ) {
14691
+ if ( re1 ) {
14692
+ d = d.replace( re1, '' );
14693
+ }
14694
+
14695
+ if ( re2 ) {
14696
+ d = d.replace( re2, '' );
14697
+ }
14698
+ }
14699
+
14700
+ return d * 1;
14701
+ };
14702
+
14703
+
14704
+ // Add the numeric 'deformatting' functions for sorting and search. This is done
14705
+ // in a function to provide an easy ability for the language options to add
14706
+ // additional methods if a non-period decimal place is used.
14707
+ function _addNumericSort ( decimalPlace ) {
14708
+ $.each(
14709
+ {
14710
+ // Plain numbers
14711
+ "num": function ( d ) {
14712
+ return __numericReplace( d, decimalPlace );
14713
+ },
14714
+
14715
+ // Formatted numbers
14716
+ "num-fmt": function ( d ) {
14717
+ return __numericReplace( d, decimalPlace, _re_formatted_numeric );
14718
+ },
14719
+
14720
+ // HTML numeric
14721
+ "html-num": function ( d ) {
14722
+ return __numericReplace( d, decimalPlace, _re_html );
14723
+ },
14724
+
14725
+ // HTML numeric, formatted
14726
+ "html-num-fmt": function ( d ) {
14727
+ return __numericReplace( d, decimalPlace, _re_html, _re_formatted_numeric );
14728
+ }
14729
+ },
14730
+ function ( key, fn ) {
14731
+ // Add the ordering method
14732
+ _ext.type.order[ key+decimalPlace+'-pre' ] = fn;
14733
+
14734
+ // For HTML types add a search formatter that will strip the HTML
14735
+ if ( key.match(/^html\-/) ) {
14736
+ _ext.type.search[ key+decimalPlace ] = _ext.type.search.html;
14737
+ }
14738
+ }
14739
+ );
14740
+ }
14741
+
14742
+
14743
+ // Default sort methods
14744
+ $.extend( _ext.type.order, {
14745
+ // Dates
14746
+ "date-pre": function ( d ) {
14747
+ return Date.parse( d ) || -Infinity;
14748
+ },
14749
+
14750
+ // html
14751
+ "html-pre": function ( a ) {
14752
+ return _empty(a) ?
14753
+ '' :
14754
+ a.replace ?
14755
+ a.replace( /<.*?>/g, "" ).toLowerCase() :
14756
+ a+'';
14757
+ },
14758
+
14759
+ // string
14760
+ "string-pre": function ( a ) {
14761
+ // This is a little complex, but faster than always calling toString,
14762
+ // http://jsperf.com/tostring-v-check
14763
+ return _empty(a) ?
14764
+ '' :
14765
+ typeof a === 'string' ?
14766
+ a.toLowerCase() :
14767
+ ! a.toString ?
14768
+ '' :
14769
+ a.toString();
14770
+ },
14771
+
14772
+ // string-asc and -desc are retained only for compatibility with the old
14773
+ // sort methods
14774
+ "string-asc": function ( x, y ) {
14775
+ return ((x < y) ? -1 : ((x > y) ? 1 : 0));
14776
+ },
14777
+
14778
+ "string-desc": function ( x, y ) {
14779
+ return ((x < y) ? 1 : ((x > y) ? -1 : 0));
14780
+ }
14781
+ } );
14782
+
14783
+
14784
+ // Numeric sorting types - order doesn't matter here
14785
+ _addNumericSort( '' );
14786
+
14787
+
14788
+ $.extend( true, DataTable.ext.renderer, {
14789
+ header: {
14790
+ _: function ( settings, cell, column, classes ) {
14791
+ // No additional mark-up required
14792
+ // Attach a sort listener to update on sort - note that using the
14793
+ // `DT` namespace will allow the event to be removed automatically
14794
+ // on destroy, while the `dt` namespaced event is the one we are
14795
+ // listening for
14796
+ $(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting, columns ) {
14797
+ if ( settings !== ctx ) { // need to check this this is the host
14798
+ return; // table, not a nested one
14799
+ }
14800
+
14801
+ var colIdx = column.idx;
14802
+
14803
+ cell
14804
+ .removeClass(
14805
+ column.sSortingClass +' '+
14806
+ classes.sSortAsc +' '+
14807
+ classes.sSortDesc
14808
+ )
14809
+ .addClass( columns[ colIdx ] == 'asc' ?
14810
+ classes.sSortAsc : columns[ colIdx ] == 'desc' ?
14811
+ classes.sSortDesc :
14812
+ column.sSortingClass
14813
+ );
14814
+ } );
14815
+ },
14816
+
14817
+ jqueryui: function ( settings, cell, column, classes ) {
14818
+ $('<div/>')
14819
+ .addClass( classes.sSortJUIWrapper )
14820
+ .append( cell.contents() )
14821
+ .append( $('<span/>')
14822
+ .addClass( classes.sSortIcon+' '+column.sSortingClassJUI )
14823
+ )
14824
+ .appendTo( cell );
14825
+
14826
+ // Attach a sort listener to update on sort
14827
+ $(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting, columns ) {
14828
+ if ( settings !== ctx ) {
14829
+ return;
14830
+ }
14831
+
14832
+ var colIdx = column.idx;
14833
+
14834
+ cell
14835
+ .removeClass( classes.sSortAsc +" "+classes.sSortDesc )
14836
+ .addClass( columns[ colIdx ] == 'asc' ?
14837
+ classes.sSortAsc : columns[ colIdx ] == 'desc' ?
14838
+ classes.sSortDesc :
14839
+ column.sSortingClass
14840
+ );
14841
+
14842
+ cell
14843
+ .find( 'span.'+classes.sSortIcon )
14844
+ .removeClass(
14845
+ classes.sSortJUIAsc +" "+
14846
+ classes.sSortJUIDesc +" "+
14847
+ classes.sSortJUI +" "+
14848
+ classes.sSortJUIAscAllowed +" "+
14849
+ classes.sSortJUIDescAllowed
14850
+ )
14851
+ .addClass( columns[ colIdx ] == 'asc' ?
14852
+ classes.sSortJUIAsc : columns[ colIdx ] == 'desc' ?
14853
+ classes.sSortJUIDesc :
14854
+ column.sSortingClassJUI
14855
+ );
14856
+ } );
14857
+ }
14858
+ }
14859
+ } );
14860
+
14861
+ /*
14862
+ * Public helper functions. These aren't used internally by DataTables, or
14863
+ * called by any of the options passed into DataTables, but they can be used
14864
+ * externally by developers working with DataTables. They are helper functions
14865
+ * to make working with DataTables a little bit easier.
14866
+ */
14867
+
14868
+ var __htmlEscapeEntities = function ( d ) {
14869
+ return typeof d === 'string' ?
14870
+ d.replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;') :
14871
+ d;
14872
+ };
14873
+
14874
+ /**
14875
+ * Helpers for `columns.render`.
14876
+ *
14877
+ * The options defined here can be used with the `columns.render` initialisation
14878
+ * option to provide a display renderer. The following functions are defined:
14879
+ *
14880
+ * * `number` - Will format numeric data (defined by `columns.data`) for
14881
+ * display, retaining the original unformatted data for sorting and filtering.
14882
+ * It takes 5 parameters:
14883
+ * * `string` - Thousands grouping separator
14884
+ * * `string` - Decimal point indicator
14885
+ * * `integer` - Number of decimal points to show
14886
+ * * `string` (optional) - Prefix.
14887
+ * * `string` (optional) - Postfix (/suffix).
14888
+ * * `text` - Escape HTML to help prevent XSS attacks. It has no optional
14889
+ * parameters.
14890
+ *
14891
+ * @example
14892
+ * // Column definition using the number renderer
14893
+ * {
14894
+ * data: "salary",
14895
+ * render: $.fn.dataTable.render.number( '\'', '.', 0, '$' )
14896
+ * }
14897
+ *
14898
+ * @namespace
14899
+ */
14900
+ DataTable.render = {
14901
+ number: function ( thousands, decimal, precision, prefix, postfix ) {
14902
+ return {
14903
+ display: function ( d ) {
14904
+ if ( typeof d !== 'number' && typeof d !== 'string' ) {
14905
+ return d;
14906
+ }
14907
+
14908
+ var negative = d < 0 ? '-' : '';
14909
+ var flo = parseFloat( d );
14910
+
14911
+ // If NaN then there isn't much formatting that we can do - just
14912
+ // return immediately, escaping any HTML (this was supposed to
14913
+ // be a number after all)
14914
+ if ( isNaN( flo ) ) {
14915
+ return __htmlEscapeEntities( d );
14916
+ }
14917
+
14918
+ flo = flo.toFixed( precision );
14919
+ d = Math.abs( flo );
14920
+
14921
+ var intPart = parseInt( d, 10 );
14922
+ var floatPart = precision ?
14923
+ decimal+(d - intPart).toFixed( precision ).substring( 2 ):
14924
+ '';
14925
+
14926
+ return negative + (prefix||'') +
14927
+ intPart.toString().replace(
14928
+ /\B(?=(\d{3})+(?!\d))/g, thousands
14929
+ ) +
14930
+ floatPart +
14931
+ (postfix||'');
14932
+ }
14933
+ };
14934
+ },
14935
+
14936
+ text: function () {
14937
+ return {
14938
+ display: __htmlEscapeEntities
14939
+ };
14940
+ }
14941
+ };
14942
+
14943
+
14944
+ /*
14945
+ * This is really a good bit rubbish this method of exposing the internal methods
14946
+ * publicly... - To be fixed in 2.0 using methods on the prototype
14947
+ */
14948
+
14949
+
14950
+ /**
14951
+ * Create a wrapper function for exporting an internal functions to an external API.
14952
+ * @param {string} fn API function name
14953
+ * @returns {function} wrapped function
14954
+ * @memberof DataTable#internal
14955
+ */
14956
+ function _fnExternApiFunc (fn)
14957
+ {
14958
+ return function() {
14959
+ var args = [_fnSettingsFromNode( this[DataTable.ext.iApiIndex] )].concat(
14960
+ Array.prototype.slice.call(arguments)
14961
+ );
14962
+ return DataTable.ext.internal[fn].apply( this, args );
14963
+ };
14964
+ }
14965
+
14966
+
14967
+ /**
14968
+ * Reference to internal functions for use by plug-in developers. Note that
14969
+ * these methods are references to internal functions and are considered to be
14970
+ * private. If you use these methods, be aware that they are liable to change
14971
+ * between versions.
14972
+ * @namespace
14973
+ */
14974
+ $.extend( DataTable.ext.internal, {
14975
+ _fnExternApiFunc: _fnExternApiFunc,
14976
+ _fnBuildAjax: _fnBuildAjax,
14977
+ _fnAjaxUpdate: _fnAjaxUpdate,
14978
+ _fnAjaxParameters: _fnAjaxParameters,
14979
+ _fnAjaxUpdateDraw: _fnAjaxUpdateDraw,
14980
+ _fnAjaxDataSrc: _fnAjaxDataSrc,
14981
+ _fnAddColumn: _fnAddColumn,
14982
+ _fnColumnOptions: _fnColumnOptions,
14983
+ _fnAdjustColumnSizing: _fnAdjustColumnSizing,
14984
+ _fnVisibleToColumnIndex: _fnVisibleToColumnIndex,
14985
+ _fnColumnIndexToVisible: _fnColumnIndexToVisible,
14986
+ _fnVisbleColumns: _fnVisbleColumns,
14987
+ _fnGetColumns: _fnGetColumns,
14988
+ _fnColumnTypes: _fnColumnTypes,
14989
+ _fnApplyColumnDefs: _fnApplyColumnDefs,
14990
+ _fnHungarianMap: _fnHungarianMap,
14991
+ _fnCamelToHungarian: _fnCamelToHungarian,
14992
+ _fnLanguageCompat: _fnLanguageCompat,
14993
+ _fnBrowserDetect: _fnBrowserDetect,
14994
+ _fnAddData: _fnAddData,
14995
+ _fnAddTr: _fnAddTr,
14996
+ _fnNodeToDataIndex: _fnNodeToDataIndex,
14997
+ _fnNodeToColumnIndex: _fnNodeToColumnIndex,
14998
+ _fnGetCellData: _fnGetCellData,
14999
+ _fnSetCellData: _fnSetCellData,
15000
+ _fnSplitObjNotation: _fnSplitObjNotation,
15001
+ _fnGetObjectDataFn: _fnGetObjectDataFn,
15002
+ _fnSetObjectDataFn: _fnSetObjectDataFn,
15003
+ _fnGetDataMaster: _fnGetDataMaster,
15004
+ _fnClearTable: _fnClearTable,
15005
+ _fnDeleteIndex: _fnDeleteIndex,
15006
+ _fnInvalidate: _fnInvalidate,
15007
+ _fnGetRowElements: _fnGetRowElements,
15008
+ _fnCreateTr: _fnCreateTr,
15009
+ _fnBuildHead: _fnBuildHead,
15010
+ _fnDrawHead: _fnDrawHead,
15011
+ _fnDraw: _fnDraw,
15012
+ _fnReDraw: _fnReDraw,
15013
+ _fnAddOptionsHtml: _fnAddOptionsHtml,
15014
+ _fnDetectHeader: _fnDetectHeader,
15015
+ _fnGetUniqueThs: _fnGetUniqueThs,
15016
+ _fnFeatureHtmlFilter: _fnFeatureHtmlFilter,
15017
+ _fnFilterComplete: _fnFilterComplete,
15018
+ _fnFilterCustom: _fnFilterCustom,
15019
+ _fnFilterColumn: _fnFilterColumn,
15020
+ _fnFilter: _fnFilter,
15021
+ _fnFilterCreateSearch: _fnFilterCreateSearch,
15022
+ _fnEscapeRegex: _fnEscapeRegex,
15023
+ _fnFilterData: _fnFilterData,
15024
+ _fnFeatureHtmlInfo: _fnFeatureHtmlInfo,
15025
+ _fnUpdateInfo: _fnUpdateInfo,
15026
+ _fnInfoMacros: _fnInfoMacros,
15027
+ _fnInitialise: _fnInitialise,
15028
+ _fnInitComplete: _fnInitComplete,
15029
+ _fnLengthChange: _fnLengthChange,
15030
+ _fnFeatureHtmlLength: _fnFeatureHtmlLength,
15031
+ _fnFeatureHtmlPaginate: _fnFeatureHtmlPaginate,
15032
+ _fnPageChange: _fnPageChange,
15033
+ _fnFeatureHtmlProcessing: _fnFeatureHtmlProcessing,
15034
+ _fnProcessingDisplay: _fnProcessingDisplay,
15035
+ _fnFeatureHtmlTable: _fnFeatureHtmlTable,
15036
+ _fnScrollDraw: _fnScrollDraw,
15037
+ _fnApplyToChildren: _fnApplyToChildren,
15038
+ _fnCalculateColumnWidths: _fnCalculateColumnWidths,
15039
+ _fnThrottle: _fnThrottle,
15040
+ _fnConvertToWidth: _fnConvertToWidth,
15041
+ _fnGetWidestNode: _fnGetWidestNode,
15042
+ _fnGetMaxLenString: _fnGetMaxLenString,
15043
+ _fnStringToCss: _fnStringToCss,
15044
+ _fnSortFlatten: _fnSortFlatten,
15045
+ _fnSort: _fnSort,
15046
+ _fnSortAria: _fnSortAria,
15047
+ _fnSortListener: _fnSortListener,
15048
+ _fnSortAttachListener: _fnSortAttachListener,
15049
+ _fnSortingClasses: _fnSortingClasses,
15050
+ _fnSortData: _fnSortData,
15051
+ _fnSaveState: _fnSaveState,
15052
+ _fnLoadState: _fnLoadState,
15053
+ _fnSettingsFromNode: _fnSettingsFromNode,
15054
+ _fnLog: _fnLog,
15055
+ _fnMap: _fnMap,
15056
+ _fnBindAction: _fnBindAction,
15057
+ _fnCallbackReg: _fnCallbackReg,
15058
+ _fnCallbackFire: _fnCallbackFire,
15059
+ _fnLengthOverflow: _fnLengthOverflow,
15060
+ _fnRenderer: _fnRenderer,
15061
+ _fnDataSource: _fnDataSource,
15062
+ _fnRowAttributes: _fnRowAttributes,
15063
+ _fnCalculateEnd: function () {} // Used by a lot of plug-ins, but redundant
15064
+ // in 1.10, so this dead-end function is
15065
+ // added to prevent errors
15066
+ } );
15067
+
15068
+
15069
+ // jQuery access
15070
+ $.fn.dataTable = DataTable;
15071
+
15072
+ // Provide access to the host jQuery object (circular reference)
15073
+ DataTable.$ = $;
15074
+
15075
+ // Legacy aliases
15076
+ $.fn.dataTableSettings = DataTable.settings;
15077
+ $.fn.dataTableExt = DataTable.ext;
15078
+
15079
+ // With a capital `D` we return a DataTables API instance rather than a
15080
+ // jQuery object
15081
+ $.fn.DataTable = function ( opts ) {
15082
+ return $(this).dataTable( opts ).api();
15083
+ };
15084
+
15085
+ // All properties that are available to $.fn.dataTable should also be
15086
+ // available on $.fn.DataTable
15087
+ $.each( DataTable, function ( prop, val ) {
15088
+ $.fn.DataTable[ prop ] = val;
15089
+ } );
15090
+
15091
+
15092
+ // Information about events fired by DataTables - for documentation.
15093
+ /**
15094
+ * Draw event, fired whenever the table is redrawn on the page, at the same
15095
+ * point as fnDrawCallback. This may be useful for binding events or
15096
+ * performing calculations when the table is altered at all.
15097
+ * @name DataTable#draw.dt
15098
+ * @event
15099
+ * @param {event} e jQuery event object
15100
+ * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
15101
+ */
15102
+
15103
+ /**
15104
+ * Search event, fired when the searching applied to the table (using the
15105
+ * built-in global search, or column filters) is altered.
15106
+ * @name DataTable#search.dt
15107
+ * @event
15108
+ * @param {event} e jQuery event object
15109
+ * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
15110
+ */
15111
+
15112
+ /**
15113
+ * Page change event, fired when the paging of the table is altered.
15114
+ * @name DataTable#page.dt
15115
+ * @event
15116
+ * @param {event} e jQuery event object
15117
+ * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
15118
+ */
15119
+
15120
+ /**
15121
+ * Order event, fired when the ordering applied to the table is altered.
15122
+ * @name DataTable#order.dt
15123
+ * @event
15124
+ * @param {event} e jQuery event object
15125
+ * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
15126
+ */
15127
+
15128
+ /**
15129
+ * DataTables initialisation complete event, fired when the table is fully
15130
+ * drawn, including Ajax data loaded, if Ajax data is required.
15131
+ * @name DataTable#init.dt
15132
+ * @event
15133
+ * @param {event} e jQuery event object
15134
+ * @param {object} oSettings DataTables settings object
15135
+ * @param {object} json The JSON object request from the server - only
15136
+ * present if client-side Ajax sourced data is used</li></ol>
15137
+ */
15138
+
15139
+ /**
15140
+ * State save event, fired when the table has changed state a new state save
15141
+ * is required. This event allows modification of the state saving object
15142
+ * prior to actually doing the save, including addition or other state
15143
+ * properties (for plug-ins) or modification of a DataTables core property.
15144
+ * @name DataTable#stateSaveParams.dt
15145
+ * @event
15146
+ * @param {event} e jQuery event object
15147
+ * @param {object} oSettings DataTables settings object
15148
+ * @param {object} json The state information to be saved
15149
+ */
15150
+
15151
+ /**
15152
+ * State load event, fired when the table is loading state from the stored
15153
+ * data, but prior to the settings object being modified by the saved state
15154
+ * - allowing modification of the saved state is required or loading of
15155
+ * state for a plug-in.
15156
+ * @name DataTable#stateLoadParams.dt
15157
+ * @event
15158
+ * @param {event} e jQuery event object
15159
+ * @param {object} oSettings DataTables settings object
15160
+ * @param {object} json The saved state information
15161
+ */
15162
+
15163
+ /**
15164
+ * State loaded event, fired when state has been loaded from stored data and
15165
+ * the settings object has been modified by the loaded data.
15166
+ * @name DataTable#stateLoaded.dt
15167
+ * @event
15168
+ * @param {event} e jQuery event object
15169
+ * @param {object} oSettings DataTables settings object
15170
+ * @param {object} json The saved state information
15171
+ */
15172
+
15173
+ /**
15174
+ * Processing event, fired when DataTables is doing some kind of processing
15175
+ * (be it, order, searcg or anything else). It can be used to indicate to
15176
+ * the end user that there is something happening, or that something has
15177
+ * finished.
15178
+ * @name DataTable#processing.dt
15179
+ * @event
15180
+ * @param {event} e jQuery event object
15181
+ * @param {object} oSettings DataTables settings object
15182
+ * @param {boolean} bShow Flag for if DataTables is doing processing or not
15183
+ */
15184
+
15185
+ /**
15186
+ * Ajax (XHR) event, fired whenever an Ajax request is completed from a
15187
+ * request to made to the server for new data. This event is called before
15188
+ * DataTables processed the returned data, so it can also be used to pre-
15189
+ * process the data returned from the server, if needed.
15190
+ *
15191
+ * Note that this trigger is called in `fnServerData`, if you override
15192
+ * `fnServerData` and which to use this event, you need to trigger it in you
15193
+ * success function.
15194
+ * @name DataTable#xhr.dt
15195
+ * @event
15196
+ * @param {event} e jQuery event object
15197
+ * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
15198
+ * @param {object} json JSON returned from the server
15199
+ *
15200
+ * @example
15201
+ * // Use a custom property returned from the server in another DOM element
15202
+ * $('#table').dataTable().on('xhr.dt', function (e, settings, json) {
15203
+ * $('#status').html( json.status );
15204
+ * } );
15205
+ *
15206
+ * @example
15207
+ * // Pre-process the data returned from the server
15208
+ * $('#table').dataTable().on('xhr.dt', function (e, settings, json) {
15209
+ * for ( var i=0, ien=json.aaData.length ; i<ien ; i++ ) {
15210
+ * json.aaData[i].sum = json.aaData[i].one + json.aaData[i].two;
15211
+ * }
15212
+ * // Note no return - manipulate the data directly in the JSON object.
15213
+ * } );
15214
+ */
15215
+
15216
+ /**
15217
+ * Destroy event, fired when the DataTable is destroyed by calling fnDestroy
15218
+ * or passing the bDestroy:true parameter in the initialisation object. This
15219
+ * can be used to remove bound events, added DOM nodes, etc.
15220
+ * @name DataTable#destroy.dt
15221
+ * @event
15222
+ * @param {event} e jQuery event object
15223
+ * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
15224
+ */
15225
+
15226
+ /**
15227
+ * Page length change event, fired when number of records to show on each
15228
+ * page (the length) is changed.
15229
+ * @name DataTable#length.dt
15230
+ * @event
15231
+ * @param {event} e jQuery event object
15232
+ * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
15233
+ * @param {integer} len New length
15234
+ */
15235
+
15236
+ /**
15237
+ * Column sizing has changed.
15238
+ * @name DataTable#column-sizing.dt
15239
+ * @event
15240
+ * @param {event} e jQuery event object
15241
+ * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
15242
+ */
15243
+
15244
+ /**
15245
+ * Column visibility has changed.
15246
+ * @name DataTable#column-visibility.dt
15247
+ * @event
15248
+ * @param {event} e jQuery event object
15249
+ * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
15250
+ * @param {int} column Column index
15251
+ * @param {bool} vis `false` if column now hidden, or `true` if visible
15252
+ */
15253
+
15254
+ return $.fn.dataTable;
15255
+ }));
15256
+
15257
+
15258
+ /*! AutoFill 2.2.2
15259
+ * ©2008-2017 SpryMedia Ltd - datatables.net/license
15260
+ */
15261
+
15262
+ /**
15263
+ * @summary AutoFill
15264
+ * @description Add Excel like click and drag auto-fill options to DataTables
15265
+ * @version 2.2.2
15266
+ * @file dataTables.autoFill.js
15267
+ * @author SpryMedia Ltd (www.sprymedia.co.uk)
15268
+ * @contact www.sprymedia.co.uk/contact
15269
+ * @copyright Copyright 2010-2017 SpryMedia Ltd.
15270
+ *
15271
+ * This source file is free software, available under the following license:
15272
+ * MIT license - http://datatables.net/license/mit
15273
+ *
15274
+ * This source file is distributed in the hope that it will be useful, but
15275
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15276
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
15277
+ *
15278
+ * For details please refer to: http://www.datatables.net
15279
+ */
15280
+ (function( factory ){
15281
+ if ( typeof define === 'function' && define.amd ) {
15282
+ // AMD
15283
+ define( ['jquery', 'datatables.net'], function ( $ ) {
15284
+ return factory( $, window, document );
15285
+ } );
15286
+ }
15287
+ else if ( typeof exports === 'object' ) {
15288
+ // CommonJS
15289
+ module.exports = function (root, $) {
15290
+ if ( ! root ) {
15291
+ root = window;
15292
+ }
15293
+
15294
+ if ( ! $ || ! $.fn.dataTable ) {
15295
+ $ = require('datatables.net')(root, $).$;
15296
+ }
15297
+
15298
+ return factory( $, root, root.document );
15299
+ };
15300
+ }
15301
+ else {
15302
+ // Browser
15303
+ factory( jQuery, window, document );
15304
+ }
15305
+ }(function( $, window, document, undefined ) {
15306
+ 'use strict';
15307
+ var DataTable = $.fn.dataTable;
15308
+
15309
+
15310
+ var _instance = 0;
15311
+
15312
+ /**
15313
+ * AutoFill provides Excel like auto-fill features for a DataTable
15314
+ *
15315
+ * @class AutoFill
15316
+ * @constructor
15317
+ * @param {object} oTD DataTables settings object
15318
+ * @param {object} oConfig Configuration object for AutoFill
15319
+ */
15320
+ var AutoFill = function( dt, opts )
15321
+ {
15322
+ if ( ! DataTable.versionCheck || ! DataTable.versionCheck( '1.10.8' ) ) {
15323
+ throw( "Warning: AutoFill requires DataTables 1.10.8 or greater");
15324
+ }
15325
+
15326
+ // User and defaults configuration object
15327
+ this.c = $.extend( true, {},
15328
+ DataTable.defaults.autoFill,
15329
+ AutoFill.defaults,
15330
+ opts
15331
+ );
15332
+
15333
+ /**
15334
+ * @namespace Settings object which contains customisable information for AutoFill instance
15335
+ */
15336
+ this.s = {
15337
+ /** @type {DataTable.Api} DataTables' API instance */
15338
+ dt: new DataTable.Api( dt ),
15339
+
15340
+ /** @type {String} Unique namespace for events attached to the document */
15341
+ namespace: '.autoFill'+(_instance++),
15342
+
15343
+ /** @type {Object} Cached dimension information for use in the mouse move event handler */
15344
+ scroll: {},
15345
+
15346
+ /** @type {integer} Interval object used for smooth scrolling */
15347
+ scrollInterval: null,
15348
+
15349
+ handle: {
15350
+ height: 0,
15351
+ width: 0
15352
+ },
15353
+
15354
+ /**
15355
+ * Enabled setting
15356
+ * @type {Boolean}
15357
+ */
15358
+ enabled: false
15359
+ };
15360
+
15361
+
15362
+ /**
15363
+ * @namespace Common and useful DOM elements for the class instance
15364
+ */
15365
+ this.dom = {
15366
+ /** @type {jQuery} AutoFill handle */
15367
+ handle: $('<div class="dt-autofill-handle"/>'),
15368
+
15369
+ /**
15370
+ * @type {Object} Selected cells outline - Need to use 4 elements,
15371
+ * otherwise the mouse over if you back into the selected rectangle
15372
+ * will be over that element, rather than the cells!
15373
+ */
15374
+ select: {
15375
+ top: $('<div class="dt-autofill-select top"/>'),
15376
+ right: $('<div class="dt-autofill-select right"/>'),
15377
+ bottom: $('<div class="dt-autofill-select bottom"/>'),
15378
+ left: $('<div class="dt-autofill-select left"/>')
15379
+ },
15380
+
15381
+ /** @type {jQuery} Fill type chooser background */
15382
+ background: $('<div class="dt-autofill-background"/>'),
15383
+
15384
+ /** @type {jQuery} Fill type chooser */
15385
+ list: $('<div class="dt-autofill-list">'+this.s.dt.i18n('autoFill.info', '')+'<ul/></div>'),
15386
+
15387
+ /** @type {jQuery} DataTables scrolling container */
15388
+ dtScroll: null,
15389
+
15390
+ /** @type {jQuery} Offset parent element */
15391
+ offsetParent: null
15392
+ };
15393
+
15394
+
15395
+ /* Constructor logic */
15396
+ this._constructor();
15397
+ };
15398
+
15399
+
15400
+
15401
+ $.extend( AutoFill.prototype, {
15402
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
15403
+ * Public methods (exposed via the DataTables API below)
15404
+ */
15405
+ enabled: function ()
15406
+ {
15407
+ return this.s.enabled;
15408
+ },
15409
+
15410
+
15411
+ enable: function ( flag )
15412
+ {
15413
+ var that = this;
15414
+
15415
+ if ( flag === false ) {
15416
+ return this.disable();
15417
+ }
15418
+
15419
+ this.s.enabled = true;
15420
+
15421
+ this._focusListener();
15422
+
15423
+ this.dom.handle.on( 'mousedown', function (e) {
15424
+ that._mousedown( e );
15425
+ return false;
15426
+ } );
15427
+
15428
+ return this;
15429
+ },
15430
+
15431
+ disable: function ()
15432
+ {
15433
+ this.s.enabled = false;
15434
+
15435
+ this._focusListenerRemove();
15436
+
15437
+ return this;
15438
+ },
15439
+
15440
+
15441
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
15442
+ * Constructor
15443
+ */
15444
+
15445
+ /**
15446
+ * Initialise the RowReorder instance
15447
+ *
15448
+ * @private
15449
+ */
15450
+ _constructor: function ()
15451
+ {
15452
+ var that = this;
15453
+ var dt = this.s.dt;
15454
+ var dtScroll = $('div.dataTables_scrollBody', this.s.dt.table().container());
15455
+
15456
+ // Make the instance accessible to the API
15457
+ dt.settings()[0].autoFill = this;
15458
+
15459
+ if ( dtScroll.length ) {
15460
+ this.dom.dtScroll = dtScroll;
15461
+
15462
+ // Need to scroll container to be the offset parent
15463
+ if ( dtScroll.css('position') === 'static' ) {
15464
+ dtScroll.css( 'position', 'relative' );
15465
+ }
15466
+ }
15467
+
15468
+ if ( this.c.enable !== false ) {
15469
+ this.enable();
15470
+ }
15471
+
15472
+ dt.on( 'destroy.autoFill', function () {
15473
+ that._focusListenerRemove();
15474
+ } );
15475
+ },
15476
+
15477
+
15478
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
15479
+ * Private methods
15480
+ */
15481
+
15482
+ /**
15483
+ * Display the AutoFill drag handle by appending it to a table cell. This
15484
+ * is the opposite of the _detach method.
15485
+ *
15486
+ * @param {node} node TD/TH cell to insert the handle into
15487
+ * @private
15488
+ */
15489
+ _attach: function ( node )
15490
+ {
15491
+ var dt = this.s.dt;
15492
+ var idx = dt.cell( node ).index();
15493
+ var handle = this.dom.handle;
15494
+ var handleDim = this.s.handle;
15495
+
15496
+ if ( ! idx || dt.columns( this.c.columns ).indexes().indexOf( idx.column ) === -1 ) {
15497
+ this._detach();
15498
+ return;
15499
+ }
15500
+
15501
+ if ( ! this.dom.offsetParent ) {
15502
+ // We attach to the table's offset parent
15503
+ this.dom.offsetParent = $( dt.table().node() ).offsetParent();
15504
+ }
15505
+
15506
+ if ( ! handleDim.height || ! handleDim.width ) {
15507
+ // Append to document so we can get its size. Not expecting it to
15508
+ // change during the life time of the page
15509
+ handle.appendTo( 'body' );
15510
+ handleDim.height = handle.outerHeight();
15511
+ handleDim.width = handle.outerWidth();
15512
+ }
15513
+
15514
+ // Might need to go through multiple offset parents
15515
+ var offset = this._getPosition( node, this.dom.offsetParent );
15516
+
15517
+ this.dom.attachedTo = node;
15518
+ handle
15519
+ .css( {
15520
+ top: offset.top + node.offsetHeight - handleDim.height,
15521
+ left: offset.left + node.offsetWidth - handleDim.width
15522
+ } )
15523
+ .appendTo( this.dom.offsetParent );
15524
+ },
15525
+
15526
+
15527
+ /**
15528
+ * Determine can the fill type should be. This can be automatic, or ask the
15529
+ * end user.
15530
+ *
15531
+ * @param {array} cells Information about the selected cells from the key
15532
+ * up function
15533
+ * @private
15534
+ */
15535
+ _actionSelector: function ( cells )
15536
+ {
15537
+ var that = this;
15538
+ var dt = this.s.dt;
15539
+ var actions = AutoFill.actions;
15540
+ var available = [];
15541
+
15542
+ // "Ask" each plug-in if it wants to handle this data
15543
+ $.each( actions, function ( key, action ) {
15544
+ if ( action.available( dt, cells ) ) {
15545
+ available.push( key );
15546
+ }
15547
+ } );
15548
+
15549
+ if ( available.length === 1 && this.c.alwaysAsk === false ) {
15550
+ // Only one action available - enact it immediately
15551
+ var result = actions[ available[0] ].execute( dt, cells );
15552
+ this._update( result, cells );
15553
+ }
15554
+ else {
15555
+ // Multiple actions available - ask the end user what they want to do
15556
+ var list = this.dom.list.children('ul').empty();
15557
+
15558
+ // Add a cancel option
15559
+ available.push( 'cancel' );
15560
+
15561
+ $.each( available, function ( i, name ) {
15562
+ list.append( $('<li/>')
15563
+ .append(
15564
+ '<div class="dt-autofill-question">'+
15565
+ actions[ name ].option( dt, cells )+
15566
+ '<div>'
15567
+ )
15568
+ .append( $('<div class="dt-autofill-button">' )
15569
+ .append( $('<button class="'+AutoFill.classes.btn+'">'+dt.i18n('autoFill.button', '&gt;')+'</button>')
15570
+ .on( 'click', function () {
15571
+ var result = actions[ name ].execute(
15572
+ dt, cells, $(this).closest('li')
15573
+ );
15574
+ that._update( result, cells );
15575
+
15576
+ that.dom.background.remove();
15577
+ that.dom.list.remove();
15578
+ } )
15579
+ )
15580
+ )
15581
+ );
15582
+ } );
15583
+
15584
+ this.dom.background.appendTo( 'body' );
15585
+ this.dom.list.appendTo( 'body' );
15586
+
15587
+ this.dom.list.css( 'margin-top', this.dom.list.outerHeight()/2 * -1 );
15588
+ }
15589
+ },
15590
+
15591
+
15592
+ /**
15593
+ * Remove the AutoFill handle from the document
15594
+ *
15595
+ * @private
15596
+ */
15597
+ _detach: function ()
15598
+ {
15599
+ this.dom.attachedTo = null;
15600
+ this.dom.handle.detach();
15601
+ },
15602
+
15603
+
15604
+ /**
15605
+ * Draw the selection outline by calculating the range between the start
15606
+ * and end cells, then placing the highlighting elements to draw a rectangle
15607
+ *
15608
+ * @param {node} target End cell
15609
+ * @param {object} e Originating event
15610
+ * @private
15611
+ */
15612
+ _drawSelection: function ( target, e )
15613
+ {
15614
+ // Calculate boundary for start cell to this one
15615
+ var dt = this.s.dt;
15616
+ var start = this.s.start;
15617
+ var startCell = $(this.dom.start);
15618
+ var endCell = $(target);
15619
+ var end = {
15620
+ row: dt.rows( { page: 'current' } ).nodes().indexOf( endCell.parent()[0] ),
15621
+ column: endCell.index()
15622
+ };
15623
+ var colIndx = dt.column.index( 'toData', end.column );
15624
+
15625
+ // Be sure that is a DataTables controlled cell
15626
+ if ( ! dt.cell( endCell ).any() ) {
15627
+ return;
15628
+ }
15629
+
15630
+ // if target is not in the columns available - do nothing
15631
+ if ( dt.columns( this.c.columns ).indexes().indexOf( colIndx ) === -1 ) {
15632
+ return;
15633
+ }
15634
+
15635
+ this.s.end = end;
15636
+
15637
+ var top, bottom, left, right, height, width;
15638
+
15639
+ top = start.row < end.row ? startCell : endCell;
15640
+ bottom = start.row < end.row ? endCell : startCell;
15641
+ left = start.column < end.column ? startCell : endCell;
15642
+ right = start.column < end.column ? endCell : startCell;
15643
+
15644
+ top = this._getPosition( top ).top;
15645
+ left = this._getPosition( left ).left;
15646
+ height = this._getPosition( bottom ).top + bottom.outerHeight() - top;
15647
+ width = this._getPosition( right ).left + right.outerWidth() - left;
15648
+
15649
+ var select = this.dom.select;
15650
+ select.top.css( {
15651
+ top: top,
15652
+ left: left,
15653
+ width: width
15654
+ } );
15655
+
15656
+ select.left.css( {
15657
+ top: top,
15658
+ left: left,
15659
+ height: height
15660
+ } );
15661
+
15662
+ select.bottom.css( {
15663
+ top: top + height,
15664
+ left: left,
15665
+ width: width
15666
+ } );
15667
+
15668
+ select.right.css( {
15669
+ top: top,
15670
+ left: left + width,
15671
+ height: height
15672
+ } );
15673
+ },
15674
+
15675
+
15676
+ /**
15677
+ * Use the Editor API to perform an update based on the new data for the
15678
+ * cells
15679
+ *
15680
+ * @param {array} cells Information about the selected cells from the key
15681
+ * up function
15682
+ * @private
15683
+ */
15684
+ _editor: function ( cells )
15685
+ {
15686
+ var dt = this.s.dt;
15687
+ var editor = this.c.editor;
15688
+
15689
+ if ( ! editor ) {
15690
+ return;
15691
+ }
15692
+
15693
+ // Build the object structure for Editor's multi-row editing
15694
+ var idValues = {};
15695
+ var nodes = [];
15696
+ var fields = editor.fields();
15697
+
15698
+ for ( var i=0, ien=cells.length ; i<ien ; i++ ) {
15699
+ for ( var j=0, jen=cells[i].length ; j<jen ; j++ ) {
15700
+ var cell = cells[i][j];
15701
+
15702
+ // Determine the field name for the cell being edited
15703
+ var col = dt.settings()[0].aoColumns[ cell.index.column ];
15704
+ var fieldName = col.editField;
15705
+
15706
+ if ( fieldName === undefined ) {
15707
+ var dataSrc = col.mData;
15708
+
15709
+ // dataSrc is the `field.data` property, but we need to set
15710
+ // using the field name, so we need to translate from the
15711
+ // data to the name
15712
+ for ( var k=0, ken=fields.length ; k<ken ; k++ ) {
15713
+ var field = editor.field( fields[k] );
15714
+
15715
+ if ( field.dataSrc() === dataSrc ) {
15716
+ fieldName = field.name();
15717
+ break;
15718
+ }
15719
+ }
15720
+ }
15721
+
15722
+ if ( ! fieldName ) {
15723
+ throw 'Could not automatically determine field data. '+
15724
+ 'Please see https://datatables.net/tn/11';
15725
+ }
15726
+
15727
+ if ( ! idValues[ fieldName ] ) {
15728
+ idValues[ fieldName ] = {};
15729
+ }
15730
+
15731
+ var id = dt.row( cell.index.row ).id();
15732
+ idValues[ fieldName ][ id ] = cell.set;
15733
+
15734
+ // Keep a list of cells so we can activate the bubble editing
15735
+ // with them
15736
+ nodes.push( cell.index );
15737
+ }
15738
+ }
15739
+
15740
+ // Perform the edit using bubble editing as it allows us to specify
15741
+ // the cells to be edited, rather than using full rows
15742
+ editor
15743
+ .bubble( nodes, false )
15744
+ .multiSet( idValues )
15745
+ .submit();
15746
+ },
15747
+
15748
+
15749
+ /**
15750
+ * Emit an event on the DataTable for listeners
15751
+ *
15752
+ * @param {string} name Event name
15753
+ * @param {array} args Event arguments
15754
+ * @private
15755
+ */
15756
+ _emitEvent: function ( name, args )
15757
+ {
15758
+ this.s.dt.iterator( 'table', function ( ctx, i ) {
15759
+ $(ctx.nTable).triggerHandler( name+'.dt', args );
15760
+ } );
15761
+ },
15762
+
15763
+
15764
+ /**
15765
+ * Attach suitable listeners (based on the configuration) that will attach
15766
+ * and detach the AutoFill handle in the document.
15767
+ *
15768
+ * @private
15769
+ */
15770
+ _focusListener: function ()
15771
+ {
15772
+ var that = this;
15773
+ var dt = this.s.dt;
15774
+ var namespace = this.s.namespace;
15775
+ var focus = this.c.focus !== null ?
15776
+ this.c.focus :
15777
+ dt.init().keys || dt.settings()[0].keytable ?
15778
+ 'focus' :
15779
+ 'hover';
15780
+
15781
+ // All event listeners attached here are removed in the `destroy`
15782
+ // callback in the constructor
15783
+ if ( focus === 'focus' ) {
15784
+ dt
15785
+ .on( 'key-focus.autoFill', function ( e, dt, cell ) {
15786
+ that._attach( cell.node() );
15787
+ } )
15788
+ .on( 'key-blur.autoFill', function ( e, dt, cell ) {
15789
+ that._detach();
15790
+ } );
15791
+ }
15792
+ else if ( focus === 'click' ) {
15793
+ $(dt.table().body()).on( 'click'+namespace, 'td, th', function (e) {
15794
+ that._attach( this );
15795
+ } );
15796
+
15797
+ $(document.body).on( 'click'+namespace, function (e) {
15798
+ if ( ! $(e.target).parents().filter( dt.table().body() ).length ) {
15799
+ that._detach();
15800
+ }
15801
+ } );
15802
+ }
15803
+ else {
15804
+ $(dt.table().body())
15805
+ .on( 'mouseenter'+namespace, 'td, th', function (e) {
15806
+ that._attach( this );
15807
+ } )
15808
+ .on( 'mouseleave'+namespace, function (e) {
15809
+ if ( $(e.relatedTarget).hasClass('dt-autofill-handle') ) {
15810
+ return;
15811
+ }
15812
+
15813
+ that._detach();
15814
+ } );
15815
+ }
15816
+ },
15817
+
15818
+
15819
+ _focusListenerRemove: function ()
15820
+ {
15821
+ var dt = this.s.dt;
15822
+
15823
+ dt.off( '.autoFill' );
15824
+ $(dt.table().body()).off( this.s.namespace );
15825
+ $(document.body).off( this.s.namespace );
15826
+ },
15827
+
15828
+
15829
+ /**
15830
+ * Get the position of a node, relative to another, including any scrolling
15831
+ * offsets.
15832
+ * @param {Node} node Node to get the position of
15833
+ * @param {jQuery} targetParent Node to use as the parent
15834
+ * @return {object} Offset calculation
15835
+ * @private
15836
+ */
15837
+ _getPosition: function ( node, targetParent )
15838
+ {
15839
+ var
15840
+ currNode = $(node),
15841
+ currOffsetParent,
15842
+ position,
15843
+ top = 0,
15844
+ left = 0;
15845
+
15846
+ if ( ! targetParent ) {
15847
+ targetParent = $( this.s.dt.table().node() ).offsetParent();
15848
+ }
15849
+
15850
+ do {
15851
+ position = currNode.position();
15852
+ currOffsetParent = currNode.offsetParent();
15853
+
15854
+ top += position.top + currOffsetParent.scrollTop();
15855
+ left += position.left + currOffsetParent.scrollLeft();
15856
+
15857
+ // Emergency fall back. Shouldn't happen, but just in case!
15858
+ if ( currNode.get(0).nodeName.toLowerCase() === 'body' ) {
15859
+ break;
15860
+ }
15861
+
15862
+ currNode = currOffsetParent; // for next loop
15863
+ }
15864
+ while ( currOffsetParent.get(0) !== targetParent.get(0) )
15865
+
15866
+ return {
15867
+ top: top,
15868
+ left: left
15869
+ };
15870
+ },
15871
+
15872
+
15873
+ /**
15874
+ * Start mouse drag - selects the start cell
15875
+ *
15876
+ * @param {object} e Mouse down event
15877
+ * @private
15878
+ */
15879
+ _mousedown: function ( e )
15880
+ {
15881
+ var that = this;
15882
+ var dt = this.s.dt;
15883
+
15884
+ this.dom.start = this.dom.attachedTo;
15885
+ this.s.start = {
15886
+ row: dt.rows( { page: 'current' } ).nodes().indexOf( $(this.dom.start).parent()[0] ),
15887
+ column: $(this.dom.start).index()
15888
+ };
15889
+
15890
+ $(document.body)
15891
+ .on( 'mousemove.autoFill', function (e) {
15892
+ that._mousemove( e );
15893
+ } )
15894
+ .on( 'mouseup.autoFill', function (e) {
15895
+ that._mouseup( e );
15896
+ } );
15897
+
15898
+ var select = this.dom.select;
15899
+ var offsetParent = $( dt.table().node() ).offsetParent();
15900
+ select.top.appendTo( offsetParent );
15901
+ select.left.appendTo( offsetParent );
15902
+ select.right.appendTo( offsetParent );
15903
+ select.bottom.appendTo( offsetParent );
15904
+
15905
+ this._drawSelection( this.dom.start, e );
15906
+
15907
+ this.dom.handle.css( 'display', 'none' );
15908
+
15909
+ // Cache scrolling information so mouse move doesn't need to read.
15910
+ // This assumes that the window and DT scroller will not change size
15911
+ // during an AutoFill drag, which I think is a fair assumption
15912
+ var scrollWrapper = this.dom.dtScroll;
15913
+ this.s.scroll = {
15914
+ windowHeight: $(window).height(),
15915
+ windowWidth: $(window).width(),
15916
+ dtTop: scrollWrapper ? scrollWrapper.offset().top : null,
15917
+ dtLeft: scrollWrapper ? scrollWrapper.offset().left : null,
15918
+ dtHeight: scrollWrapper ? scrollWrapper.outerHeight() : null,
15919
+ dtWidth: scrollWrapper ? scrollWrapper.outerWidth() : null
15920
+ };
15921
+ },
15922
+
15923
+
15924
+ /**
15925
+ * Mouse drag - selects the end cell and update the selection display for
15926
+ * the end user
15927
+ *
15928
+ * @param {object} e Mouse move event
15929
+ * @private
15930
+ */
15931
+ _mousemove: function ( e )
15932
+ {
15933
+ var that = this;
15934
+ var dt = this.s.dt;
15935
+ var name = e.target.nodeName.toLowerCase();
15936
+ if ( name !== 'td' && name !== 'th' ) {
15937
+ return;
15938
+ }
15939
+
15940
+ this._drawSelection( e.target, e );
15941
+ this._shiftScroll( e );
15942
+ },
15943
+
15944
+
15945
+ /**
15946
+ * End mouse drag - perform the update actions
15947
+ *
15948
+ * @param {object} e Mouse up event
15949
+ * @private
15950
+ */
15951
+ _mouseup: function ( e )
15952
+ {
15953
+ $(document.body).off( '.autoFill' );
15954
+
15955
+ var dt = this.s.dt;
15956
+ var select = this.dom.select;
15957
+ select.top.remove();
15958
+ select.left.remove();
15959
+ select.right.remove();
15960
+ select.bottom.remove();
15961
+
15962
+ this.dom.handle.css( 'display', 'block' );
15963
+
15964
+ // Display complete - now do something useful with the selection!
15965
+ var start = this.s.start;
15966
+ var end = this.s.end;
15967
+
15968
+ // Haven't selected multiple cells, so nothing to do
15969
+ if ( start.row === end.row && start.column === end.column ) {
15970
+ return;
15971
+ }
15972
+
15973
+ // Build a matrix representation of the selected rows
15974
+ var rows = this._range( start.row, end.row );
15975
+ var columns = this._range( start.column, end.column );
15976
+ var selected = [];
15977
+ var dtSettings = dt.settings()[0];
15978
+ var dtColumns = dtSettings.aoColumns;
15979
+
15980
+ // Can't use Array.prototype.map as IE8 doesn't support it
15981
+ // Can't use $.map as jQuery flattens 2D arrays
15982
+ // Need to use a good old fashioned for loop
15983
+ for ( var rowIdx=0 ; rowIdx<rows.length ; rowIdx++ ) {
15984
+ selected.push(
15985
+ $.map( columns, function (column) {
15986
+ var cell = dt.cell( ':eq('+rows[rowIdx]+')', column+':visible', {page:'current'} );
15987
+ var data = cell.data();
15988
+ var cellIndex = cell.index();
15989
+ var editField = dtColumns[ cellIndex.column ].editField;
15990
+
15991
+ if ( editField !== undefined ) {
15992
+ data = dtSettings.oApi._fnGetObjectDataFn( editField )( dt.row( cellIndex.row ).data() );
15993
+ }
15994
+
15995
+ return {
15996
+ cell: cell,
15997
+ data: data,
15998
+ label: cell.data(),
15999
+ index: cellIndex
16000
+ };
16001
+ } )
16002
+ );
16003
+ }
16004
+
16005
+ this._actionSelector( selected );
16006
+
16007
+ // Stop shiftScroll
16008
+ clearInterval( this.s.scrollInterval );
16009
+ this.s.scrollInterval = null;
16010
+ },
16011
+
16012
+
16013
+ /**
16014
+ * Create an array with a range of numbers defined by the start and end
16015
+ * parameters passed in (inclusive!).
16016
+ *
16017
+ * @param {integer} start Start
16018
+ * @param {integer} end End
16019
+ * @private
16020
+ */
16021
+ _range: function ( start, end )
16022
+ {
16023
+ var out = [];
16024
+ var i;
16025
+
16026
+ if ( start <= end ) {
16027
+ for ( i=start ; i<=end ; i++ ) {
16028
+ out.push( i );
16029
+ }
16030
+ }
16031
+ else {
16032
+ for ( i=start ; i>=end ; i-- ) {
16033
+ out.push( i );
16034
+ }
16035
+ }
16036
+
16037
+ return out;
16038
+ },
16039
+
16040
+
16041
+ /**
16042
+ * Move the window and DataTables scrolling during a drag to scroll new
16043
+ * content into view. This is done by proximity to the edge of the scrolling
16044
+ * container of the mouse - for example near the top edge of the window
16045
+ * should scroll up. This is a little complicated as there are two elements
16046
+ * that can be scrolled - the window and the DataTables scrolling view port
16047
+ * (if scrollX and / or scrollY is enabled).
16048
+ *
16049
+ * @param {object} e Mouse move event object
16050
+ * @private
16051
+ */
16052
+ _shiftScroll: function ( e )
16053
+ {
16054
+ var that = this;
16055
+ var dt = this.s.dt;
16056
+ var scroll = this.s.scroll;
16057
+ var runInterval = false;
16058
+ var scrollSpeed = 5;
16059
+ var buffer = 65;
16060
+ var
16061
+ windowY = e.pageY - document.body.scrollTop,
16062
+ windowX = e.pageX - document.body.scrollLeft,
16063
+ windowVert, windowHoriz,
16064
+ dtVert, dtHoriz;
16065
+
16066
+ // Window calculations - based on the mouse position in the window,
16067
+ // regardless of scrolling
16068
+ if ( windowY < buffer ) {
16069
+ windowVert = scrollSpeed * -1;
16070
+ }
16071
+ else if ( windowY > scroll.windowHeight - buffer ) {
16072
+ windowVert = scrollSpeed;
16073
+ }
16074
+
16075
+ if ( windowX < buffer ) {
16076
+ windowHoriz = scrollSpeed * -1;
16077
+ }
16078
+ else if ( windowX > scroll.windowWidth - buffer ) {
16079
+ windowHoriz = scrollSpeed;
16080
+ }
16081
+
16082
+ // DataTables scrolling calculations - based on the table's position in
16083
+ // the document and the mouse position on the page
16084
+ if ( scroll.dtTop !== null && e.pageY < scroll.dtTop + buffer ) {
16085
+ dtVert = scrollSpeed * -1;
16086
+ }
16087
+ else if ( scroll.dtTop !== null && e.pageY > scroll.dtTop + scroll.dtHeight - buffer ) {
16088
+ dtVert = scrollSpeed;
16089
+ }
16090
+
16091
+ if ( scroll.dtLeft !== null && e.pageX < scroll.dtLeft + buffer ) {
16092
+ dtHoriz = scrollSpeed * -1;
16093
+ }
16094
+ else if ( scroll.dtLeft !== null && e.pageX > scroll.dtLeft + scroll.dtWidth - buffer ) {
16095
+ dtHoriz = scrollSpeed;
16096
+ }
16097
+
16098
+ // This is where it gets interesting. We want to continue scrolling
16099
+ // without requiring a mouse move, so we need an interval to be
16100
+ // triggered. The interval should continue until it is no longer needed,
16101
+ // but it must also use the latest scroll commands (for example consider
16102
+ // that the mouse might move from scrolling up to scrolling left, all
16103
+ // with the same interval running. We use the `scroll` object to "pass"
16104
+ // this information to the interval. Can't use local variables as they
16105
+ // wouldn't be the ones that are used by an already existing interval!
16106
+ if ( windowVert || windowHoriz || dtVert || dtHoriz ) {
16107
+ scroll.windowVert = windowVert;
16108
+ scroll.windowHoriz = windowHoriz;
16109
+ scroll.dtVert = dtVert;
16110
+ scroll.dtHoriz = dtHoriz;
16111
+ runInterval = true;
16112
+ }
16113
+ else if ( this.s.scrollInterval ) {
16114
+ // Don't need to scroll - remove any existing timer
16115
+ clearInterval( this.s.scrollInterval );
16116
+ this.s.scrollInterval = null;
16117
+ }
16118
+
16119
+ // If we need to run the interval to scroll and there is no existing
16120
+ // interval (if there is an existing one, it will continue to run)
16121
+ if ( ! this.s.scrollInterval && runInterval ) {
16122
+ this.s.scrollInterval = setInterval( function () {
16123
+ // Don't need to worry about setting scroll <0 or beyond the
16124
+ // scroll bound as the browser will just reject that.
16125
+ if ( scroll.windowVert ) {
16126
+ document.body.scrollTop += scroll.windowVert;
16127
+ }
16128
+ if ( scroll.windowHoriz ) {
16129
+ document.body.scrollLeft += scroll.windowHoriz;
16130
+ }
16131
+
16132
+ // DataTables scrolling
16133
+ if ( scroll.dtVert || scroll.dtHoriz ) {
16134
+ var scroller = that.dom.dtScroll[0];
16135
+
16136
+ if ( scroll.dtVert ) {
16137
+ scroller.scrollTop += scroll.dtVert;
16138
+ }
16139
+ if ( scroll.dtHoriz ) {
16140
+ scroller.scrollLeft += scroll.dtHoriz;
16141
+ }
16142
+ }
16143
+ }, 20 );
16144
+ }
16145
+ },
16146
+
16147
+
16148
+ /**
16149
+ * Update the DataTable after the user has selected what they want to do
16150
+ *
16151
+ * @param {false|undefined} result Return from the `execute` method - can
16152
+ * be false internally to do nothing. This is not documented for plug-ins
16153
+ * and is used only by the cancel option.
16154
+ * @param {array} cells Information about the selected cells from the key
16155
+ * up function, argumented with the set values
16156
+ * @private
16157
+ */
16158
+ _update: function ( result, cells )
16159
+ {
16160
+ // Do nothing on `false` return from an execute function
16161
+ if ( result === false ) {
16162
+ return;
16163
+ }
16164
+
16165
+ var dt = this.s.dt;
16166
+ var cell;
16167
+
16168
+ // Potentially allow modifications to the cells matrix
16169
+ this._emitEvent( 'preAutoFill', [ dt, cells ] );
16170
+
16171
+ this._editor( cells );
16172
+
16173
+ // Automatic updates are not performed if `update` is null and the
16174
+ // `editor` parameter is passed in - the reason being that Editor will
16175
+ // update the data once submitted
16176
+ var update = this.c.update !== null ?
16177
+ this.c.update :
16178
+ this.c.editor ?
16179
+ false :
16180
+ true;
16181
+
16182
+ if ( update ) {
16183
+ for ( var i=0, ien=cells.length ; i<ien ; i++ ) {
16184
+ for ( var j=0, jen=cells[i].length ; j<jen ; j++ ) {
16185
+ cell = cells[i][j];
16186
+
16187
+ cell.cell.data( cell.set );
16188
+ }
16189
+ }
16190
+
16191
+ dt.draw(false);
16192
+ }
16193
+
16194
+ this._emitEvent( 'autoFill', [ dt, cells ] );
16195
+ }
16196
+ } );
16197
+
16198
+
16199
+ /**
16200
+ * AutoFill actions. The options here determine how AutoFill will fill the data
16201
+ * in the table when the user has selected a range of cells. Please see the
16202
+ * documentation on the DataTables site for full details on how to create plug-
16203
+ * ins.
16204
+ *
16205
+ * @type {Object}
16206
+ */
16207
+ AutoFill.actions = {
16208
+ increment: {
16209
+ available: function ( dt, cells ) {
16210
+ return $.isNumeric( cells[0][0].label );
16211
+ },
16212
+
16213
+ option: function ( dt, cells ) {
16214
+ return dt.i18n(
16215
+ 'autoFill.increment',
16216
+ 'Increment / decrement each cell by: <input type="number" value="1">'
16217
+ );
16218
+ },
16219
+
16220
+ execute: function ( dt, cells, node ) {
16221
+ var value = cells[0][0].data * 1;
16222
+ var increment = $('input', node).val() * 1;
16223
+
16224
+ for ( var i=0, ien=cells.length ; i<ien ; i++ ) {
16225
+ for ( var j=0, jen=cells[i].length ; j<jen ; j++ ) {
16226
+ cells[i][j].set = value;
16227
+
16228
+ value += increment;
16229
+ }
16230
+ }
16231
+ }
16232
+ },
16233
+
16234
+ fill: {
16235
+ available: function ( dt, cells ) {
16236
+ return true;
16237
+ },
16238
+
16239
+ option: function ( dt, cells ) {
16240
+ return dt.i18n('autoFill.fill', 'Fill all cells with <i>'+cells[0][0].label+'</i>' );
16241
+ },
16242
+
16243
+ execute: function ( dt, cells, node ) {
16244
+ var value = cells[0][0].data;
16245
+
16246
+ for ( var i=0, ien=cells.length ; i<ien ; i++ ) {
16247
+ for ( var j=0, jen=cells[i].length ; j<jen ; j++ ) {
16248
+ cells[i][j].set = value;
16249
+ }
16250
+ }
16251
+ }
16252
+ },
16253
+
16254
+ fillHorizontal: {
16255
+ available: function ( dt, cells ) {
16256
+ return cells.length > 1 && cells[0].length > 1;
16257
+ },
16258
+
16259
+ option: function ( dt, cells ) {
16260
+ return dt.i18n('autoFill.fillHorizontal', 'Fill cells horizontally' );
16261
+ },
16262
+
16263
+ execute: function ( dt, cells, node ) {
16264
+ for ( var i=0, ien=cells.length ; i<ien ; i++ ) {
16265
+ for ( var j=0, jen=cells[i].length ; j<jen ; j++ ) {
16266
+ cells[i][j].set = cells[i][0].data;
16267
+ }
16268
+ }
16269
+ }
16270
+ },
16271
+
16272
+ fillVertical: {
16273
+ available: function ( dt, cells ) {
16274
+ return cells.length > 1 && cells[0].length > 1;
16275
+ },
16276
+
16277
+ option: function ( dt, cells ) {
16278
+ return dt.i18n('autoFill.fillVertical', 'Fill cells vertically' );
16279
+ },
16280
+
16281
+ execute: function ( dt, cells, node ) {
16282
+ for ( var i=0, ien=cells.length ; i<ien ; i++ ) {
16283
+ for ( var j=0, jen=cells[i].length ; j<jen ; j++ ) {
16284
+ cells[i][j].set = cells[0][j].data;
16285
+ }
16286
+ }
16287
+ }
16288
+ },
16289
+
16290
+ // Special type that does not make itself available, but is added
16291
+ // automatically by AutoFill if a multi-choice list is shown. This allows
16292
+ // sensible code reuse
16293
+ cancel: {
16294
+ available: function () {
16295
+ return false;
16296
+ },
16297
+
16298
+ option: function ( dt ) {
16299
+ return dt.i18n('autoFill.cancel', 'Cancel' );
16300
+ },
16301
+
16302
+ execute: function () {
16303
+ return false;
16304
+ }
16305
+ }
16306
+ };
16307
+
16308
+
16309
+ /**
16310
+ * AutoFill version
16311
+ *
16312
+ * @static
16313
+ * @type String
16314
+ */
16315
+ AutoFill.version = '2.2.2';
16316
+
16317
+
16318
+ /**
16319
+ * AutoFill defaults
16320
+ *
16321
+ * @namespace
16322
+ */
16323
+ AutoFill.defaults = {
16324
+ /** @type {Boolean} Ask user what they want to do, even for a single option */
16325
+ alwaysAsk: false,
16326
+
16327
+ /** @type {string|null} What will trigger a focus */
16328
+ focus: null, // focus, click, hover
16329
+
16330
+ /** @type {column-selector} Columns to provide auto fill for */
16331
+ columns: '', // all
16332
+
16333
+ /** @type {Boolean} Enable AutoFill on load */
16334
+ enable: true,
16335
+
16336
+ /** @type {boolean|null} Update the cells after a drag */
16337
+ update: null, // false is editor given, true otherwise
16338
+
16339
+ /** @type {DataTable.Editor} Editor instance for automatic submission */
16340
+ editor: null
16341
+ };
16342
+
16343
+
16344
+ /**
16345
+ * Classes used by AutoFill that are configurable
16346
+ *
16347
+ * @namespace
16348
+ */
16349
+ AutoFill.classes = {
16350
+ /** @type {String} Class used by the selection button */
16351
+ btn: 'btn'
16352
+ };
16353
+
16354
+
16355
+ /*
16356
+ * API
16357
+ */
16358
+ var Api = $.fn.dataTable.Api;
16359
+
16360
+ // Doesn't do anything - Not documented
16361
+ Api.register( 'autoFill()', function () {
16362
+ return this;
16363
+ } );
16364
+
16365
+ Api.register( 'autoFill().enabled()', function () {
16366
+ var ctx = this.context[0];
16367
+
16368
+ return ctx.autoFill ?
16369
+ ctx.autoFill.enabled() :
16370
+ false;
16371
+ } );
16372
+
16373
+ Api.register( 'autoFill().enable()', function ( flag ) {
16374
+ return this.iterator( 'table', function ( ctx ) {
16375
+ if ( ctx.autoFill ) {
16376
+ ctx.autoFill.enable( flag );
16377
+ }
16378
+ } );
16379
+ } );
16380
+
16381
+ Api.register( 'autoFill().disable()', function () {
16382
+ return this.iterator( 'table', function ( ctx ) {
16383
+ if ( ctx.autoFill ) {
16384
+ ctx.autoFill.disable();
16385
+ }
16386
+ } );
16387
+ } );
16388
+
16389
+
16390
+ // Attach a listener to the document which listens for DataTables initialisation
16391
+ // events so we can automatically initialise
16392
+ $(document).on( 'preInit.dt.autofill', function (e, settings, json) {
16393
+ if ( e.namespace !== 'dt' ) {
16394
+ return;
16395
+ }
16396
+
16397
+ var init = settings.oInit.autoFill;
16398
+ var defaults = DataTable.defaults.autoFill;
16399
+
16400
+ if ( init || defaults ) {
16401
+ var opts = $.extend( {}, init, defaults );
16402
+
16403
+ if ( init !== false ) {
16404
+ new AutoFill( settings, opts );
16405
+ }
16406
+ }
16407
+ } );
16408
+
16409
+
16410
+ // Alias for access
16411
+ DataTable.AutoFill = AutoFill;
16412
+ DataTable.AutoFill = AutoFill;
16413
+
16414
+
16415
+ return AutoFill;
16416
+ }));
16417
+
16418
+
16419
+ /*! Buttons for DataTables 1.5.1
16420
+ * ©2016-2017 SpryMedia Ltd - datatables.net/license
16421
+ */
16422
+
16423
+ (function( factory ){
16424
+ if ( typeof define === 'function' && define.amd ) {
16425
+ // AMD
16426
+ define( ['jquery', 'datatables.net'], function ( $ ) {
16427
+ return factory( $, window, document );
16428
+ } );
16429
+ }
16430
+ else if ( typeof exports === 'object' ) {
16431
+ // CommonJS
16432
+ module.exports = function (root, $) {
16433
+ if ( ! root ) {
16434
+ root = window;
16435
+ }
16436
+
16437
+ if ( ! $ || ! $.fn.dataTable ) {
16438
+ $ = require('datatables.net')(root, $).$;
16439
+ }
16440
+
16441
+ return factory( $, root, root.document );
16442
+ };
16443
+ }
16444
+ else {
16445
+ // Browser
16446
+ factory( jQuery, window, document );
16447
+ }
16448
+ }(function( $, window, document, undefined ) {
16449
+ 'use strict';
16450
+ var DataTable = $.fn.dataTable;
16451
+
16452
+
16453
+ // Used for namespacing events added to the document by each instance, so they
16454
+ // can be removed on destroy
16455
+ var _instCounter = 0;
16456
+
16457
+ // Button namespacing counter for namespacing events on individual buttons
16458
+ var _buttonCounter = 0;
16459
+
16460
+ var _dtButtons = DataTable.ext.buttons;
16461
+
16462
+ /**
16463
+ * [Buttons description]
16464
+ * @param {[type]}
16465
+ * @param {[type]}
16466
+ */
16467
+ var Buttons = function( dt, config )
16468
+ {
16469
+ // If there is no config set it to an empty object
16470
+ if ( typeof( config ) === 'undefined' ) {
16471
+ config = {};
16472
+ }
16473
+
16474
+ // Allow a boolean true for defaults
16475
+ if ( config === true ) {
16476
+ config = {};
16477
+ }
16478
+
16479
+ // For easy configuration of buttons an array can be given
16480
+ if ( $.isArray( config ) ) {
16481
+ config = { buttons: config };
16482
+ }
16483
+
16484
+ this.c = $.extend( true, {}, Buttons.defaults, config );
16485
+
16486
+ // Don't want a deep copy for the buttons
16487
+ if ( config.buttons ) {
16488
+ this.c.buttons = config.buttons;
16489
+ }
16490
+
16491
+ this.s = {
16492
+ dt: new DataTable.Api( dt ),
16493
+ buttons: [],
16494
+ listenKeys: '',
16495
+ namespace: 'dtb'+(_instCounter++)
16496
+ };
16497
+
16498
+ this.dom = {
16499
+ container: $('<'+this.c.dom.container.tag+'/>')
16500
+ .addClass( this.c.dom.container.className )
16501
+ };
16502
+
16503
+ this._constructor();
16504
+ };
16505
+
16506
+
16507
+ $.extend( Buttons.prototype, {
16508
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
16509
+ * Public methods
16510
+ */
16511
+
16512
+ /**
16513
+ * Get the action of a button
16514
+ * @param {int|string} Button index
16515
+ * @return {function}
16516
+ *//**
16517
+ * Set the action of a button
16518
+ * @param {node} node Button element
16519
+ * @param {function} action Function to set
16520
+ * @return {Buttons} Self for chaining
16521
+ */
16522
+ action: function ( node, action )
16523
+ {
16524
+ var button = this._nodeToButton( node );
16525
+
16526
+ if ( action === undefined ) {
16527
+ return button.conf.action;
16528
+ }
16529
+
16530
+ button.conf.action = action;
16531
+
16532
+ return this;
16533
+ },
16534
+
16535
+ /**
16536
+ * Add an active class to the button to make to look active or get current
16537
+ * active state.
16538
+ * @param {node} node Button element
16539
+ * @param {boolean} [flag] Enable / disable flag
16540
+ * @return {Buttons} Self for chaining or boolean for getter
16541
+ */
16542
+ active: function ( node, flag ) {
16543
+ var button = this._nodeToButton( node );
16544
+ var klass = this.c.dom.button.active;
16545
+ var jqNode = $(button.node);
16546
+
16547
+ if ( flag === undefined ) {
16548
+ return jqNode.hasClass( klass );
16549
+ }
16550
+
16551
+ jqNode.toggleClass( klass, flag === undefined ? true : flag );
16552
+
16553
+ return this;
16554
+ },
16555
+
16556
+ /**
16557
+ * Add a new button
16558
+ * @param {object} config Button configuration object, base string name or function
16559
+ * @param {int|string} [idx] Button index for where to insert the button
16560
+ * @return {Buttons} Self for chaining
16561
+ */
16562
+ add: function ( config, idx )
16563
+ {
16564
+ var buttons = this.s.buttons;
16565
+
16566
+ if ( typeof idx === 'string' ) {
16567
+ var split = idx.split('-');
16568
+ var base = this.s;
16569
+
16570
+ for ( var i=0, ien=split.length-1 ; i<ien ; i++ ) {
16571
+ base = base.buttons[ split[i]*1 ];
16572
+ }
16573
+
16574
+ buttons = base.buttons;
16575
+ idx = split[ split.length-1 ]*1;
16576
+ }
16577
+
16578
+ this._expandButton( buttons, config, false, idx );
16579
+ this._draw();
16580
+
16581
+ return this;
16582
+ },
16583
+
16584
+ /**
16585
+ * Get the container node for the buttons
16586
+ * @return {jQuery} Buttons node
16587
+ */
16588
+ container: function ()
16589
+ {
16590
+ return this.dom.container;
16591
+ },
16592
+
16593
+ /**
16594
+ * Disable a button
16595
+ * @param {node} node Button node
16596
+ * @return {Buttons} Self for chaining
16597
+ */
16598
+ disable: function ( node ) {
16599
+ var button = this._nodeToButton( node );
16600
+
16601
+ $(button.node).addClass( this.c.dom.button.disabled );
16602
+
16603
+ return this;
16604
+ },
16605
+
16606
+ /**
16607
+ * Destroy the instance, cleaning up event handlers and removing DOM
16608
+ * elements
16609
+ * @return {Buttons} Self for chaining
16610
+ */
16611
+ destroy: function ()
16612
+ {
16613
+ // Key event listener
16614
+ $('body').off( 'keyup.'+this.s.namespace );
16615
+
16616
+ // Individual button destroy (so they can remove their own events if
16617
+ // needed). Take a copy as the array is modified by `remove`
16618
+ var buttons = this.s.buttons.slice();
16619
+ var i, ien;
16620
+
16621
+ for ( i=0, ien=buttons.length ; i<ien ; i++ ) {
16622
+ this.remove( buttons[i].node );
16623
+ }
16624
+
16625
+ // Container
16626
+ this.dom.container.remove();
16627
+
16628
+ // Remove from the settings object collection
16629
+ var buttonInsts = this.s.dt.settings()[0];
16630
+
16631
+ for ( i=0, ien=buttonInsts.length ; i<ien ; i++ ) {
16632
+ if ( buttonInsts.inst === this ) {
16633
+ buttonInsts.splice( i, 1 );
16634
+ break;
16635
+ }
16636
+ }
16637
+
16638
+ return this;
16639
+ },
16640
+
16641
+ /**
16642
+ * Enable / disable a button
16643
+ * @param {node} node Button node
16644
+ * @param {boolean} [flag=true] Enable / disable flag
16645
+ * @return {Buttons} Self for chaining
16646
+ */
16647
+ enable: function ( node, flag )
16648
+ {
16649
+ if ( flag === false ) {
16650
+ return this.disable( node );
16651
+ }
16652
+
16653
+ var button = this._nodeToButton( node );
16654
+ $(button.node).removeClass( this.c.dom.button.disabled );
16655
+
16656
+ return this;
16657
+ },
16658
+
16659
+ /**
16660
+ * Get the instance name for the button set selector
16661
+ * @return {string} Instance name
16662
+ */
16663
+ name: function ()
16664
+ {
16665
+ return this.c.name;
16666
+ },
16667
+
16668
+ /**
16669
+ * Get a button's node
16670
+ * @param {node} node Button node
16671
+ * @return {jQuery} Button element
16672
+ */
16673
+ node: function ( node )
16674
+ {
16675
+ var button = this._nodeToButton( node );
16676
+ return $(button.node);
16677
+ },
16678
+
16679
+ /**
16680
+ * Set / get a processing class on the selected button
16681
+ * @param {boolean} flag true to add, false to remove, undefined to get
16682
+ * @return {boolean|Buttons} Getter value or this if a setter.
16683
+ */
16684
+ processing: function ( node, flag )
16685
+ {
16686
+ var button = this._nodeToButton( node );
16687
+
16688
+ if ( flag === undefined ) {
16689
+ return $(button.node).hasClass( 'processing' );
16690
+ }
16691
+
16692
+ $(button.node).toggleClass( 'processing', flag );
16693
+
16694
+ return this;
16695
+ },
16696
+
16697
+ /**
16698
+ * Remove a button.
16699
+ * @param {node} node Button node
16700
+ * @return {Buttons} Self for chaining
16701
+ */
16702
+ remove: function ( node )
16703
+ {
16704
+ var button = this._nodeToButton( node );
16705
+ var host = this._nodeToHost( node );
16706
+ var dt = this.s.dt;
16707
+
16708
+ // Remove any child buttons first
16709
+ if ( button.buttons.length ) {
16710
+ for ( var i=button.buttons.length-1 ; i>=0 ; i-- ) {
16711
+ this.remove( button.buttons[i].node );
16712
+ }
16713
+ }
16714
+
16715
+ // Allow the button to remove event handlers, etc
16716
+ if ( button.conf.destroy ) {
16717
+ button.conf.destroy.call( dt.button(node), dt, $(node), button.conf );
16718
+ }
16719
+
16720
+ this._removeKey( button.conf );
16721
+
16722
+ $(button.node).remove();
16723
+
16724
+ var idx = $.inArray( button, host );
16725
+ host.splice( idx, 1 );
16726
+
16727
+ return this;
16728
+ },
16729
+
16730
+ /**
16731
+ * Get the text for a button
16732
+ * @param {int|string} node Button index
16733
+ * @return {string} Button text
16734
+ *//**
16735
+ * Set the text for a button
16736
+ * @param {int|string|function} node Button index
16737
+ * @param {string} label Text
16738
+ * @return {Buttons} Self for chaining
16739
+ */
16740
+ text: function ( node, label )
16741
+ {
16742
+ var button = this._nodeToButton( node );
16743
+ var buttonLiner = this.c.dom.collection.buttonLiner;
16744
+ var linerTag = button.inCollection && buttonLiner && buttonLiner.tag ?
16745
+ buttonLiner.tag :
16746
+ this.c.dom.buttonLiner.tag;
16747
+ var dt = this.s.dt;
16748
+ var jqNode = $(button.node);
16749
+ var text = function ( opt ) {
16750
+ return typeof opt === 'function' ?
16751
+ opt( dt, jqNode, button.conf ) :
16752
+ opt;
16753
+ };
16754
+
16755
+ if ( label === undefined ) {
16756
+ return text( button.conf.text );
16757
+ }
16758
+
16759
+ button.conf.text = label;
16760
+
16761
+ if ( linerTag ) {
16762
+ jqNode.children( linerTag ).html( text(label) );
16763
+ }
16764
+ else {
16765
+ jqNode.html( text(label) );
16766
+ }
16767
+
16768
+ return this;
16769
+ },
16770
+
16771
+
16772
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
16773
+ * Constructor
16774
+ */
16775
+
16776
+ /**
16777
+ * Buttons constructor
16778
+ * @private
16779
+ */
16780
+ _constructor: function ()
16781
+ {
16782
+ var that = this;
16783
+ var dt = this.s.dt;
16784
+ var dtSettings = dt.settings()[0];
16785
+ var buttons = this.c.buttons;
16786
+
16787
+ if ( ! dtSettings._buttons ) {
16788
+ dtSettings._buttons = [];
16789
+ }
16790
+
16791
+ dtSettings._buttons.push( {
16792
+ inst: this,
16793
+ name: this.c.name
16794
+ } );
16795
+
16796
+ for ( var i=0, ien=buttons.length ; i<ien ; i++ ) {
16797
+ this.add( buttons[i] );
16798
+ }
16799
+
16800
+ dt.on( 'destroy', function () {
16801
+ that.destroy();
16802
+ } );
16803
+
16804
+ // Global key event binding to listen for button keys
16805
+ $('body').on( 'keyup.'+this.s.namespace, function ( e ) {
16806
+ if ( ! document.activeElement || document.activeElement === document.body ) {
16807
+ // SUse a string of characters for fast lookup of if we need to
16808
+ // handle this
16809
+ var character = String.fromCharCode(e.keyCode).toLowerCase();
16810
+
16811
+ if ( that.s.listenKeys.toLowerCase().indexOf( character ) !== -1 ) {
16812
+ that._keypress( character, e );
16813
+ }
16814
+ }
16815
+ } );
16816
+ },
16817
+
16818
+
16819
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
16820
+ * Private methods
16821
+ */
16822
+
16823
+ /**
16824
+ * Add a new button to the key press listener
16825
+ * @param {object} conf Resolved button configuration object
16826
+ * @private
16827
+ */
16828
+ _addKey: function ( conf )
16829
+ {
16830
+ if ( conf.key ) {
16831
+ this.s.listenKeys += $.isPlainObject( conf.key ) ?
16832
+ conf.key.key :
16833
+ conf.key;
16834
+ }
16835
+ },
16836
+
16837
+ /**
16838
+ * Insert the buttons into the container. Call without parameters!
16839
+ * @param {node} [container] Recursive only - Insert point
16840
+ * @param {array} [buttons] Recursive only - Buttons array
16841
+ * @private
16842
+ */
16843
+ _draw: function ( container, buttons )
16844
+ {
16845
+ if ( ! container ) {
16846
+ container = this.dom.container;
16847
+ buttons = this.s.buttons;
16848
+ }
16849
+
16850
+ container.children().detach();
16851
+
16852
+ for ( var i=0, ien=buttons.length ; i<ien ; i++ ) {
16853
+ container.append( buttons[i].inserter );
16854
+ container.append( ' ' );
16855
+
16856
+ if ( buttons[i].buttons && buttons[i].buttons.length ) {
16857
+ this._draw( buttons[i].collection, buttons[i].buttons );
16858
+ }
16859
+ }
16860
+ },
16861
+
16862
+ /**
16863
+ * Create buttons from an array of buttons
16864
+ * @param {array} attachTo Buttons array to attach to
16865
+ * @param {object} button Button definition
16866
+ * @param {boolean} inCollection true if the button is in a collection
16867
+ * @private
16868
+ */
16869
+ _expandButton: function ( attachTo, button, inCollection, attachPoint )
16870
+ {
16871
+ var dt = this.s.dt;
16872
+ var buttonCounter = 0;
16873
+ var buttons = ! $.isArray( button ) ?
16874
+ [ button ] :
16875
+ button;
16876
+
16877
+ for ( var i=0, ien=buttons.length ; i<ien ; i++ ) {
16878
+ var conf = this._resolveExtends( buttons[i] );
16879
+
16880
+ if ( ! conf ) {
16881
+ continue;
16882
+ }
16883
+
16884
+ // If the configuration is an array, then expand the buttons at this
16885
+ // point
16886
+ if ( $.isArray( conf ) ) {
16887
+ this._expandButton( attachTo, conf, inCollection, attachPoint );
16888
+ continue;
16889
+ }
16890
+
16891
+ var built = this._buildButton( conf, inCollection );
16892
+ if ( ! built ) {
16893
+ continue;
16894
+ }
16895
+
16896
+ if ( attachPoint !== undefined ) {
16897
+ attachTo.splice( attachPoint, 0, built );
16898
+ attachPoint++;
16899
+ }
16900
+ else {
16901
+ attachTo.push( built );
16902
+ }
16903
+
16904
+ if ( built.conf.buttons ) {
16905
+ var collectionDom = this.c.dom.collection;
16906
+ built.collection = $('<'+collectionDom.tag+'/>')
16907
+ .addClass( collectionDom.className )
16908
+ .attr( 'role', 'menu') ;
16909
+ built.conf._collection = built.collection;
16910
+
16911
+ this._expandButton( built.buttons, built.conf.buttons, true, attachPoint );
16912
+ }
16913
+
16914
+ // init call is made here, rather than buildButton as it needs to
16915
+ // be selectable, and for that it needs to be in the buttons array
16916
+ if ( conf.init ) {
16917
+ conf.init.call( dt.button( built.node ), dt, $(built.node), conf );
16918
+ }
16919
+
16920
+ buttonCounter++;
16921
+ }
16922
+ },
16923
+
16924
+ /**
16925
+ * Create an individual button
16926
+ * @param {object} config Resolved button configuration
16927
+ * @param {boolean} inCollection `true` if a collection button
16928
+ * @return {jQuery} Created button node (jQuery)
16929
+ * @private
16930
+ */
16931
+ _buildButton: function ( config, inCollection )
16932
+ {
16933
+ var buttonDom = this.c.dom.button;
16934
+ var linerDom = this.c.dom.buttonLiner;
16935
+ var collectionDom = this.c.dom.collection;
16936
+ var dt = this.s.dt;
16937
+ var text = function ( opt ) {
16938
+ return typeof opt === 'function' ?
16939
+ opt( dt, button, config ) :
16940
+ opt;
16941
+ };
16942
+
16943
+ if ( inCollection && collectionDom.button ) {
16944
+ buttonDom = collectionDom.button;
16945
+ }
16946
+
16947
+ if ( inCollection && collectionDom.buttonLiner ) {
16948
+ linerDom = collectionDom.buttonLiner;
16949
+ }
16950
+
16951
+ // Make sure that the button is available based on whatever requirements
16952
+ // it has. For example, Flash buttons require Flash
16953
+ if ( config.available && ! config.available( dt, config ) ) {
16954
+ return false;
16955
+ }
16956
+
16957
+ var action = function ( e, dt, button, config ) {
16958
+ config.action.call( dt.button( button ), e, dt, button, config );
16959
+
16960
+ $(dt.table().node()).triggerHandler( 'buttons-action.dt', [
16961
+ dt.button( button ), dt, button, config
16962
+ ] );
16963
+ };
16964
+
16965
+ var button = $('<'+buttonDom.tag+'/>')
16966
+ .addClass( buttonDom.className )
16967
+ .attr( 'tabindex', this.s.dt.settings()[0].iTabIndex )
16968
+ .attr( 'aria-controls', this.s.dt.table().node().id )
16969
+ .on( 'click.dtb', function (e) {
16970
+ e.preventDefault();
16971
+
16972
+ if ( ! button.hasClass( buttonDom.disabled ) && config.action ) {
16973
+ action( e, dt, button, config );
16974
+ }
16975
+
16976
+ button.blur();
16977
+ } )
16978
+ .on( 'keyup.dtb', function (e) {
16979
+ if ( e.keyCode === 13 ) {
16980
+ if ( ! button.hasClass( buttonDom.disabled ) && config.action ) {
16981
+ action( e, dt, button, config );
16982
+ }
16983
+ }
16984
+ } );
16985
+
16986
+ // Make `a` tags act like a link
16987
+ if ( buttonDom.tag.toLowerCase() === 'a' ) {
16988
+ button.attr( 'href', '#' );
16989
+ }
16990
+
16991
+ if ( linerDom.tag ) {
16992
+ var liner = $('<'+linerDom.tag+'/>')
16993
+ .html( text( config.text ) )
16994
+ .addClass( linerDom.className );
16995
+
16996
+ if ( linerDom.tag.toLowerCase() === 'a' ) {
16997
+ liner.attr( 'href', '#' );
16998
+ }
16999
+
17000
+ button.append( liner );
17001
+ }
17002
+ else {
17003
+ button.html( text( config.text ) );
17004
+ }
17005
+
17006
+ if ( config.enabled === false ) {
17007
+ button.addClass( buttonDom.disabled );
17008
+ }
17009
+
17010
+ if ( config.className ) {
17011
+ button.addClass( config.className );
17012
+ }
17013
+
17014
+ if ( config.titleAttr ) {
17015
+ button.attr( 'title', text( config.titleAttr ) );
17016
+ }
17017
+
17018
+ if ( config.attr ) {
17019
+ button.attr( config.attr );
17020
+ }
17021
+
17022
+ if ( ! config.namespace ) {
17023
+ config.namespace = '.dt-button-'+(_buttonCounter++);
17024
+ }
17025
+
17026
+ var buttonContainer = this.c.dom.buttonContainer;
17027
+ var inserter;
17028
+ if ( buttonContainer && buttonContainer.tag ) {
17029
+ inserter = $('<'+buttonContainer.tag+'/>')
17030
+ .addClass( buttonContainer.className )
17031
+ .append( button );
17032
+ }
17033
+ else {
17034
+ inserter = button;
17035
+ }
17036
+
17037
+ this._addKey( config );
17038
+
17039
+ return {
17040
+ conf: config,
17041
+ node: button.get(0),
17042
+ inserter: inserter,
17043
+ buttons: [],
17044
+ inCollection: inCollection,
17045
+ collection: null
17046
+ };
17047
+ },
17048
+
17049
+ /**
17050
+ * Get the button object from a node (recursive)
17051
+ * @param {node} node Button node
17052
+ * @param {array} [buttons] Button array, uses base if not defined
17053
+ * @return {object} Button object
17054
+ * @private
17055
+ */
17056
+ _nodeToButton: function ( node, buttons )
17057
+ {
17058
+ if ( ! buttons ) {
17059
+ buttons = this.s.buttons;
17060
+ }
17061
+
17062
+ for ( var i=0, ien=buttons.length ; i<ien ; i++ ) {
17063
+ if ( buttons[i].node === node ) {
17064
+ return buttons[i];
17065
+ }
17066
+
17067
+ if ( buttons[i].buttons.length ) {
17068
+ var ret = this._nodeToButton( node, buttons[i].buttons );
17069
+
17070
+ if ( ret ) {
17071
+ return ret;
17072
+ }
17073
+ }
17074
+ }
17075
+ },
17076
+
17077
+ /**
17078
+ * Get container array for a button from a button node (recursive)
17079
+ * @param {node} node Button node
17080
+ * @param {array} [buttons] Button array, uses base if not defined
17081
+ * @return {array} Button's host array
17082
+ * @private
17083
+ */
17084
+ _nodeToHost: function ( node, buttons )
17085
+ {
17086
+ if ( ! buttons ) {
17087
+ buttons = this.s.buttons;
17088
+ }
17089
+
17090
+ for ( var i=0, ien=buttons.length ; i<ien ; i++ ) {
17091
+ if ( buttons[i].node === node ) {
17092
+ return buttons;
17093
+ }
17094
+
17095
+ if ( buttons[i].buttons.length ) {
17096
+ var ret = this._nodeToHost( node, buttons[i].buttons );
17097
+
17098
+ if ( ret ) {
17099
+ return ret;
17100
+ }
17101
+ }
17102
+ }
17103
+ },
17104
+
17105
+ /**
17106
+ * Handle a key press - determine if any button's key configured matches
17107
+ * what was typed and trigger the action if so.
17108
+ * @param {string} character The character pressed
17109
+ * @param {object} e Key event that triggered this call
17110
+ * @private
17111
+ */
17112
+ _keypress: function ( character, e )
17113
+ {
17114
+ // Check if this button press already activated on another instance of Buttons
17115
+ if ( e._buttonsHandled ) {
17116
+ return;
17117
+ }
17118
+
17119
+ var run = function ( conf, node ) {
17120
+ if ( ! conf.key ) {
17121
+ return;
17122
+ }
17123
+
17124
+ if ( conf.key === character ) {
17125
+ e._buttonsHandled = true;
17126
+ $(node).click();
17127
+ }
17128
+ else if ( $.isPlainObject( conf.key ) ) {
17129
+ if ( conf.key.key !== character ) {
17130
+ return;
17131
+ }
17132
+
17133
+ if ( conf.key.shiftKey && ! e.shiftKey ) {
17134
+ return;
17135
+ }
17136
+
17137
+ if ( conf.key.altKey && ! e.altKey ) {
17138
+ return;
17139
+ }
17140
+
17141
+ if ( conf.key.ctrlKey && ! e.ctrlKey ) {
17142
+ return;
17143
+ }
17144
+
17145
+ if ( conf.key.metaKey && ! e.metaKey ) {
17146
+ return;
17147
+ }
17148
+
17149
+ // Made it this far - it is good
17150
+ e._buttonsHandled = true;
17151
+ $(node).click();
17152
+ }
17153
+ };
17154
+
17155
+ var recurse = function ( a ) {
17156
+ for ( var i=0, ien=a.length ; i<ien ; i++ ) {
17157
+ run( a[i].conf, a[i].node );
17158
+
17159
+ if ( a[i].buttons.length ) {
17160
+ recurse( a[i].buttons );
17161
+ }
17162
+ }
17163
+ };
17164
+
17165
+ recurse( this.s.buttons );
17166
+ },
17167
+
17168
+ /**
17169
+ * Remove a key from the key listener for this instance (to be used when a
17170
+ * button is removed)
17171
+ * @param {object} conf Button configuration
17172
+ * @private
17173
+ */
17174
+ _removeKey: function ( conf )
17175
+ {
17176
+ if ( conf.key ) {
17177
+ var character = $.isPlainObject( conf.key ) ?
17178
+ conf.key.key :
17179
+ conf.key;
17180
+
17181
+ // Remove only one character, as multiple buttons could have the
17182
+ // same listening key
17183
+ var a = this.s.listenKeys.split('');
17184
+ var idx = $.inArray( character, a );
17185
+ a.splice( idx, 1 );
17186
+ this.s.listenKeys = a.join('');
17187
+ }
17188
+ },
17189
+
17190
+ /**
17191
+ * Resolve a button configuration
17192
+ * @param {string|function|object} conf Button config to resolve
17193
+ * @return {object} Button configuration
17194
+ * @private
17195
+ */
17196
+ _resolveExtends: function ( conf )
17197
+ {
17198
+ var dt = this.s.dt;
17199
+ var i, ien;
17200
+ var toConfObject = function ( base ) {
17201
+ var loop = 0;
17202
+
17203
+ // Loop until we have resolved to a button configuration, or an
17204
+ // array of button configurations (which will be iterated
17205
+ // separately)
17206
+ while ( ! $.isPlainObject(base) && ! $.isArray(base) ) {
17207
+ if ( base === undefined ) {
17208
+ return;
17209
+ }
17210
+
17211
+ if ( typeof base === 'function' ) {
17212
+ base = base( dt, conf );
17213
+
17214
+ if ( ! base ) {
17215
+ return false;
17216
+ }
17217
+ }
17218
+ else if ( typeof base === 'string' ) {
17219
+ if ( ! _dtButtons[ base ] ) {
17220
+ throw 'Unknown button type: '+base;
17221
+ }
17222
+
17223
+ base = _dtButtons[ base ];
17224
+ }
17225
+
17226
+ loop++;
17227
+ if ( loop > 30 ) {
17228
+ // Protect against misconfiguration killing the browser
17229
+ throw 'Buttons: Too many iterations';
17230
+ }
17231
+ }
17232
+
17233
+ return $.isArray( base ) ?
17234
+ base :
17235
+ $.extend( {}, base );
17236
+ };
17237
+
17238
+ conf = toConfObject( conf );
17239
+
17240
+ while ( conf && conf.extend ) {
17241
+ // Use `toConfObject` in case the button definition being extended
17242
+ // is itself a string or a function
17243
+ if ( ! _dtButtons[ conf.extend ] ) {
17244
+ throw 'Cannot extend unknown button type: '+conf.extend;
17245
+ }
17246
+
17247
+ var objArray = toConfObject( _dtButtons[ conf.extend ] );
17248
+ if ( $.isArray( objArray ) ) {
17249
+ return objArray;
17250
+ }
17251
+ else if ( ! objArray ) {
17252
+ // This is a little brutal as it might be possible to have a
17253
+ // valid button without the extend, but if there is no extend
17254
+ // then the host button would be acting in an undefined state
17255
+ return false;
17256
+ }
17257
+
17258
+ // Stash the current class name
17259
+ var originalClassName = objArray.className;
17260
+
17261
+ conf = $.extend( {}, objArray, conf );
17262
+
17263
+ // The extend will have overwritten the original class name if the
17264
+ // `conf` object also assigned a class, but we want to concatenate
17265
+ // them so they are list that is combined from all extended buttons
17266
+ if ( originalClassName && conf.className !== originalClassName ) {
17267
+ conf.className = originalClassName+' '+conf.className;
17268
+ }
17269
+
17270
+ // Buttons to be added to a collection -gives the ability to define
17271
+ // if buttons should be added to the start or end of a collection
17272
+ var postfixButtons = conf.postfixButtons;
17273
+ if ( postfixButtons ) {
17274
+ if ( ! conf.buttons ) {
17275
+ conf.buttons = [];
17276
+ }
17277
+
17278
+ for ( i=0, ien=postfixButtons.length ; i<ien ; i++ ) {
17279
+ conf.buttons.push( postfixButtons[i] );
17280
+ }
17281
+
17282
+ conf.postfixButtons = null;
17283
+ }
17284
+
17285
+ var prefixButtons = conf.prefixButtons;
17286
+ if ( prefixButtons ) {
17287
+ if ( ! conf.buttons ) {
17288
+ conf.buttons = [];
17289
+ }
17290
+
17291
+ for ( i=0, ien=prefixButtons.length ; i<ien ; i++ ) {
17292
+ conf.buttons.splice( i, 0, prefixButtons[i] );
17293
+ }
17294
+
17295
+ conf.prefixButtons = null;
17296
+ }
17297
+
17298
+ // Although we want the `conf` object to overwrite almost all of
17299
+ // the properties of the object being extended, the `extend`
17300
+ // property should come from the object being extended
17301
+ conf.extend = objArray.extend;
17302
+ }
17303
+
17304
+ return conf;
17305
+ }
17306
+ } );
17307
+
17308
+
17309
+
17310
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
17311
+ * Statics
17312
+ */
17313
+
17314
+ /**
17315
+ * Show / hide a background layer behind a collection
17316
+ * @param {boolean} Flag to indicate if the background should be shown or
17317
+ * hidden
17318
+ * @param {string} Class to assign to the background
17319
+ * @static
17320
+ */
17321
+ Buttons.background = function ( show, className, fade ) {
17322
+ if ( fade === undefined ) {
17323
+ fade = 400;
17324
+ }
17325
+
17326
+ if ( show ) {
17327
+ $('<div/>')
17328
+ .addClass( className )
17329
+ .css( 'display', 'none' )
17330
+ .appendTo( 'body' )
17331
+ .fadeIn( fade );
17332
+ }
17333
+ else {
17334
+ $('body > div.'+className)
17335
+ .fadeOut( fade, function () {
17336
+ $(this)
17337
+ .removeClass( className )
17338
+ .remove();
17339
+ } );
17340
+ }
17341
+ };
17342
+
17343
+ /**
17344
+ * Instance selector - select Buttons instances based on an instance selector
17345
+ * value from the buttons assigned to a DataTable. This is only useful if
17346
+ * multiple instances are attached to a DataTable.
17347
+ * @param {string|int|array} Instance selector - see `instance-selector`
17348
+ * documentation on the DataTables site
17349
+ * @param {array} Button instance array that was attached to the DataTables
17350
+ * settings object
17351
+ * @return {array} Buttons instances
17352
+ * @static
17353
+ */
17354
+ Buttons.instanceSelector = function ( group, buttons )
17355
+ {
17356
+ if ( ! group ) {
17357
+ return $.map( buttons, function ( v ) {
17358
+ return v.inst;
17359
+ } );
17360
+ }
17361
+
17362
+ var ret = [];
17363
+ var names = $.map( buttons, function ( v ) {
17364
+ return v.name;
17365
+ } );
17366
+
17367
+ // Flatten the group selector into an array of single options
17368
+ var process = function ( input ) {
17369
+ if ( $.isArray( input ) ) {
17370
+ for ( var i=0, ien=input.length ; i<ien ; i++ ) {
17371
+ process( input[i] );
17372
+ }
17373
+ return;
17374
+ }
17375
+
17376
+ if ( typeof input === 'string' ) {
17377
+ if ( input.indexOf( ',' ) !== -1 ) {
17378
+ // String selector, list of names
17379
+ process( input.split(',') );
17380
+ }
17381
+ else {
17382
+ // String selector individual name
17383
+ var idx = $.inArray( $.trim(input), names );
17384
+
17385
+ if ( idx !== -1 ) {
17386
+ ret.push( buttons[ idx ].inst );
17387
+ }
17388
+ }
17389
+ }
17390
+ else if ( typeof input === 'number' ) {
17391
+ // Index selector
17392
+ ret.push( buttons[ input ].inst );
17393
+ }
17394
+ };
17395
+
17396
+ process( group );
17397
+
17398
+ return ret;
17399
+ };
17400
+
17401
+ /**
17402
+ * Button selector - select one or more buttons from a selector input so some
17403
+ * operation can be performed on them.
17404
+ * @param {array} Button instances array that the selector should operate on
17405
+ * @param {string|int|node|jQuery|array} Button selector - see
17406
+ * `button-selector` documentation on the DataTables site
17407
+ * @return {array} Array of objects containing `inst` and `idx` properties of
17408
+ * the selected buttons so you know which instance each button belongs to.
17409
+ * @static
17410
+ */
17411
+ Buttons.buttonSelector = function ( insts, selector )
17412
+ {
17413
+ var ret = [];
17414
+ var nodeBuilder = function ( a, buttons, baseIdx ) {
17415
+ var button;
17416
+ var idx;
17417
+
17418
+ for ( var i=0, ien=buttons.length ; i<ien ; i++ ) {
17419
+ button = buttons[i];
17420
+
17421
+ if ( button ) {
17422
+ idx = baseIdx !== undefined ?
17423
+ baseIdx+i :
17424
+ i+'';
17425
+
17426
+ a.push( {
17427
+ node: button.node,
17428
+ name: button.conf.name,
17429
+ idx: idx
17430
+ } );
17431
+
17432
+ if ( button.buttons ) {
17433
+ nodeBuilder( a, button.buttons, idx+'-' );
17434
+ }
17435
+ }
17436
+ }
17437
+ };
17438
+
17439
+ var run = function ( selector, inst ) {
17440
+ var i, ien;
17441
+ var buttons = [];
17442
+ nodeBuilder( buttons, inst.s.buttons );
17443
+
17444
+ var nodes = $.map( buttons, function (v) {
17445
+ return v.node;
17446
+ } );
17447
+
17448
+ if ( $.isArray( selector ) || selector instanceof $ ) {
17449
+ for ( i=0, ien=selector.length ; i<ien ; i++ ) {
17450
+ run( selector[i], inst );
17451
+ }
17452
+ return;
17453
+ }
17454
+
17455
+ if ( selector === null || selector === undefined || selector === '*' ) {
17456
+ // Select all
17457
+ for ( i=0, ien=buttons.length ; i<ien ; i++ ) {
17458
+ ret.push( {
17459
+ inst: inst,
17460
+ node: buttons[i].node
17461
+ } );
17462
+ }
17463
+ }
17464
+ else if ( typeof selector === 'number' ) {
17465
+ // Main button index selector
17466
+ ret.push( {
17467
+ inst: inst,
17468
+ node: inst.s.buttons[ selector ].node
17469
+ } );
17470
+ }
17471
+ else if ( typeof selector === 'string' ) {
17472
+ if ( selector.indexOf( ',' ) !== -1 ) {
17473
+ // Split
17474
+ var a = selector.split(',');
17475
+
17476
+ for ( i=0, ien=a.length ; i<ien ; i++ ) {
17477
+ run( $.trim(a[i]), inst );
17478
+ }
17479
+ }
17480
+ else if ( selector.match( /^\d+(\-\d+)*$/ ) ) {
17481
+ // Sub-button index selector
17482
+ var indexes = $.map( buttons, function (v) {
17483
+ return v.idx;
17484
+ } );
17485
+
17486
+ ret.push( {
17487
+ inst: inst,
17488
+ node: buttons[ $.inArray( selector, indexes ) ].node
17489
+ } );
17490
+ }
17491
+ else if ( selector.indexOf( ':name' ) !== -1 ) {
17492
+ // Button name selector
17493
+ var name = selector.replace( ':name', '' );
17494
+
17495
+ for ( i=0, ien=buttons.length ; i<ien ; i++ ) {
17496
+ if ( buttons[i].name === name ) {
17497
+ ret.push( {
17498
+ inst: inst,
17499
+ node: buttons[i].node
17500
+ } );
17501
+ }
17502
+ }
17503
+ }
17504
+ else {
17505
+ // jQuery selector on the nodes
17506
+ $( nodes ).filter( selector ).each( function () {
17507
+ ret.push( {
17508
+ inst: inst,
17509
+ node: this
17510
+ } );
17511
+ } );
17512
+ }
17513
+ }
17514
+ else if ( typeof selector === 'object' && selector.nodeName ) {
17515
+ // Node selector
17516
+ var idx = $.inArray( selector, nodes );
17517
+
17518
+ if ( idx !== -1 ) {
17519
+ ret.push( {
17520
+ inst: inst,
17521
+ node: nodes[ idx ]
17522
+ } );
17523
+ }
17524
+ }
17525
+ };
17526
+
17527
+
17528
+ for ( var i=0, ien=insts.length ; i<ien ; i++ ) {
17529
+ var inst = insts[i];
17530
+
17531
+ run( selector, inst );
17532
+ }
17533
+
17534
+ return ret;
17535
+ };
17536
+
17537
+
17538
+ /**
17539
+ * Buttons defaults. For full documentation, please refer to the docs/option
17540
+ * directory or the DataTables site.
17541
+ * @type {Object}
17542
+ * @static
17543
+ */
17544
+ Buttons.defaults = {
17545
+ buttons: [ 'copy', 'excel', 'csv', 'pdf', 'print' ],
17546
+ name: 'main',
17547
+ tabIndex: 0,
17548
+ dom: {
17549
+ container: {
17550
+ tag: 'div',
17551
+ className: 'dt-buttons'
17552
+ },
17553
+ collection: {
17554
+ tag: 'div',
17555
+ className: 'dt-button-collection'
17556
+ },
17557
+ button: {
17558
+ tag: 'button',
17559
+ className: 'dt-button',
17560
+ active: 'active',
17561
+ disabled: 'disabled'
17562
+ },
17563
+ buttonLiner: {
17564
+ tag: 'span',
17565
+ className: ''
17566
+ }
17567
+ }
17568
+ };
17569
+
17570
+ /**
17571
+ * Version information
17572
+ * @type {string}
17573
+ * @static
17574
+ */
17575
+ Buttons.version = '1.5.1';
17576
+
17577
+
17578
+ $.extend( _dtButtons, {
17579
+ collection: {
17580
+ text: function ( dt ) {
17581
+ return dt.i18n( 'buttons.collection', 'Collection' );
17582
+ },
17583
+ className: 'buttons-collection',
17584
+ action: function ( e, dt, button, config ) {
17585
+ var host = button;
17586
+ var collectionParent = $(button).parents('div.dt-button-collection');
17587
+ var hostPosition = host.position();
17588
+ var tableContainer = $( dt.table().container() );
17589
+ var multiLevel = false;
17590
+ var insertPoint = host;
17591
+
17592
+ // Remove any old collection
17593
+ if ( collectionParent.length ) {
17594
+ multiLevel = $('.dt-button-collection').position();
17595
+ insertPoint = collectionParent;
17596
+ $('body').trigger( 'click.dtb-collection' );
17597
+ }
17598
+
17599
+ config._collection
17600
+ .addClass( config.collectionLayout )
17601
+ .css( 'display', 'none' )
17602
+ .insertAfter( insertPoint )
17603
+ .fadeIn( config.fade );
17604
+
17605
+
17606
+ var position = config._collection.css( 'position' );
17607
+
17608
+ if ( multiLevel && position === 'absolute' ) {
17609
+ config._collection.css( {
17610
+ top: multiLevel.top,
17611
+ left: multiLevel.left
17612
+ } );
17613
+ }
17614
+ else if ( position === 'absolute' ) {
17615
+ config._collection.css( {
17616
+ top: hostPosition.top + host.outerHeight(),
17617
+ left: hostPosition.left
17618
+ } );
17619
+
17620
+ // calculate overflow when positioned beneath
17621
+ var tableBottom = tableContainer.offset().top + tableContainer.height();
17622
+ var listBottom = hostPosition.top + host.outerHeight() + config._collection.outerHeight();
17623
+ var bottomOverflow = listBottom - tableBottom;
17624
+
17625
+ // calculate overflow when positioned above
17626
+ var listTop = hostPosition.top - config._collection.outerHeight();
17627
+ var tableTop = tableContainer.offset().top;
17628
+ var topOverflow = tableTop - listTop;
17629
+
17630
+ // if bottom overflow is larger, move to the top because it fits better
17631
+ if (bottomOverflow > topOverflow) {
17632
+ config._collection.css( 'top', hostPosition.top - config._collection.outerHeight() - 5);
17633
+ }
17634
+
17635
+ var listRight = hostPosition.left + config._collection.outerWidth();
17636
+ var tableRight = tableContainer.offset().left + tableContainer.width();
17637
+ if ( listRight > tableRight ) {
17638
+ config._collection.css( 'left', hostPosition.left - ( listRight - tableRight ) );
17639
+ }
17640
+ }
17641
+ else {
17642
+ // Fix position - centre on screen
17643
+ var top = config._collection.height() / 2;
17644
+ if ( top > $(window).height() / 2 ) {
17645
+ top = $(window).height() / 2;
17646
+ }
17647
+
17648
+ config._collection.css( 'marginTop', top*-1 );
17649
+ }
17650
+
17651
+ if ( config.background ) {
17652
+ Buttons.background( true, config.backgroundClassName, config.fade );
17653
+ }
17654
+
17655
+ // Need to break the 'thread' for the collection button being
17656
+ // activated by a click - it would also trigger this event
17657
+ setTimeout( function () {
17658
+ // This is bonkers, but if we don't have a click listener on the
17659
+ // background element, iOS Safari will ignore the body click
17660
+ // listener below. An empty function here is all that is
17661
+ // required to make it work...
17662
+ $('div.dt-button-background').on( 'click.dtb-collection', function () {} );
17663
+
17664
+ $('body').on( 'click.dtb-collection', function (e) {
17665
+ // andSelf is deprecated in jQ1.8, but we want 1.7 compat
17666
+ var back = $.fn.addBack ? 'addBack' : 'andSelf';
17667
+
17668
+ if ( ! $(e.target).parents()[back]().filter( config._collection ).length ) {
17669
+ config._collection
17670
+ .fadeOut( config.fade, function () {
17671
+ config._collection.detach();
17672
+ } );
17673
+
17674
+ $('div.dt-button-background').off( 'click.dtb-collection' );
17675
+ Buttons.background( false, config.backgroundClassName, config.fade );
17676
+
17677
+ $('body').off( 'click.dtb-collection' );
17678
+ dt.off( 'buttons-action.b-internal' );
17679
+ }
17680
+ } );
17681
+ }, 10 );
17682
+
17683
+ if ( config.autoClose ) {
17684
+ dt.on( 'buttons-action.b-internal', function () {
17685
+ $('div.dt-button-background').click();
17686
+ } );
17687
+ }
17688
+ },
17689
+ background: true,
17690
+ collectionLayout: '',
17691
+ backgroundClassName: 'dt-button-background',
17692
+ autoClose: false,
17693
+ fade: 400,
17694
+ attr: {
17695
+ 'aria-haspopup': true
17696
+ }
17697
+ },
17698
+ copy: function ( dt, conf ) {
17699
+ if ( _dtButtons.copyHtml5 ) {
17700
+ return 'copyHtml5';
17701
+ }
17702
+ if ( _dtButtons.copyFlash && _dtButtons.copyFlash.available( dt, conf ) ) {
17703
+ return 'copyFlash';
17704
+ }
17705
+ },
17706
+ csv: function ( dt, conf ) {
17707
+ // Common option that will use the HTML5 or Flash export buttons
17708
+ if ( _dtButtons.csvHtml5 && _dtButtons.csvHtml5.available( dt, conf ) ) {
17709
+ return 'csvHtml5';
17710
+ }
17711
+ if ( _dtButtons.csvFlash && _dtButtons.csvFlash.available( dt, conf ) ) {
17712
+ return 'csvFlash';
17713
+ }
17714
+ },
17715
+ excel: function ( dt, conf ) {
17716
+ // Common option that will use the HTML5 or Flash export buttons
17717
+ if ( _dtButtons.excelHtml5 && _dtButtons.excelHtml5.available( dt, conf ) ) {
17718
+ return 'excelHtml5';
17719
+ }
17720
+ if ( _dtButtons.excelFlash && _dtButtons.excelFlash.available( dt, conf ) ) {
17721
+ return 'excelFlash';
17722
+ }
17723
+ },
17724
+ pdf: function ( dt, conf ) {
17725
+ // Common option that will use the HTML5 or Flash export buttons
17726
+ if ( _dtButtons.pdfHtml5 && _dtButtons.pdfHtml5.available( dt, conf ) ) {
17727
+ return 'pdfHtml5';
17728
+ }
17729
+ if ( _dtButtons.pdfFlash && _dtButtons.pdfFlash.available( dt, conf ) ) {
17730
+ return 'pdfFlash';
17731
+ }
17732
+ },
17733
+ pageLength: function ( dt ) {
17734
+ var lengthMenu = dt.settings()[0].aLengthMenu;
17735
+ var vals = $.isArray( lengthMenu[0] ) ? lengthMenu[0] : lengthMenu;
17736
+ var lang = $.isArray( lengthMenu[0] ) ? lengthMenu[1] : lengthMenu;
17737
+ var text = function ( dt ) {
17738
+ return dt.i18n( 'buttons.pageLength', {
17739
+ "-1": 'Show all rows',
17740
+ _: 'Show %d rows'
17741
+ }, dt.page.len() );
17742
+ };
17743
+
17744
+ return {
17745
+ extend: 'collection',
17746
+ text: text,
17747
+ className: 'buttons-page-length',
17748
+ autoClose: true,
17749
+ buttons: $.map( vals, function ( val, i ) {
17750
+ return {
17751
+ text: lang[i],
17752
+ className: 'button-page-length',
17753
+ action: function ( e, dt ) {
17754
+ dt.page.len( val ).draw();
17755
+ },
17756
+ init: function ( dt, node, conf ) {
17757
+ var that = this;
17758
+ var fn = function () {
17759
+ that.active( dt.page.len() === val );
17760
+ };
17761
+
17762
+ dt.on( 'length.dt'+conf.namespace, fn );
17763
+ fn();
17764
+ },
17765
+ destroy: function ( dt, node, conf ) {
17766
+ dt.off( 'length.dt'+conf.namespace );
17767
+ }
17768
+ };
17769
+ } ),
17770
+ init: function ( dt, node, conf ) {
17771
+ var that = this;
17772
+ dt.on( 'length.dt'+conf.namespace, function () {
17773
+ that.text( text( dt ) );
17774
+ } );
17775
+ },
17776
+ destroy: function ( dt, node, conf ) {
17777
+ dt.off( 'length.dt'+conf.namespace );
17778
+ }
17779
+ };
17780
+ }
17781
+ } );
17782
+
17783
+
17784
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
17785
+ * DataTables API
17786
+ *
17787
+ * For complete documentation, please refer to the docs/api directory or the
17788
+ * DataTables site
17789
+ */
17790
+
17791
+ // Buttons group and individual button selector
17792
+ DataTable.Api.register( 'buttons()', function ( group, selector ) {
17793
+ // Argument shifting
17794
+ if ( selector === undefined ) {
17795
+ selector = group;
17796
+ group = undefined;
17797
+ }
17798
+
17799
+ this.selector.buttonGroup = group;
17800
+
17801
+ var res = this.iterator( true, 'table', function ( ctx ) {
17802
+ if ( ctx._buttons ) {
17803
+ return Buttons.buttonSelector(
17804
+ Buttons.instanceSelector( group, ctx._buttons ),
17805
+ selector
17806
+ );
17807
+ }
17808
+ }, true );
17809
+
17810
+ res._groupSelector = group;
17811
+ return res;
17812
+ } );
17813
+
17814
+ // Individual button selector
17815
+ DataTable.Api.register( 'button()', function ( group, selector ) {
17816
+ // just run buttons() and truncate
17817
+ var buttons = this.buttons( group, selector );
17818
+
17819
+ if ( buttons.length > 1 ) {
17820
+ buttons.splice( 1, buttons.length );
17821
+ }
17822
+
17823
+ return buttons;
17824
+ } );
17825
+
17826
+ // Active buttons
17827
+ DataTable.Api.registerPlural( 'buttons().active()', 'button().active()', function ( flag ) {
17828
+ if ( flag === undefined ) {
17829
+ return this.map( function ( set ) {
17830
+ return set.inst.active( set.node );
17831
+ } );
17832
+ }
17833
+
17834
+ return this.each( function ( set ) {
17835
+ set.inst.active( set.node, flag );
17836
+ } );
17837
+ } );
17838
+
17839
+ // Get / set button action
17840
+ DataTable.Api.registerPlural( 'buttons().action()', 'button().action()', function ( action ) {
17841
+ if ( action === undefined ) {
17842
+ return this.map( function ( set ) {
17843
+ return set.inst.action( set.node );
17844
+ } );
17845
+ }
17846
+
17847
+ return this.each( function ( set ) {
17848
+ set.inst.action( set.node, action );
17849
+ } );
17850
+ } );
17851
+
17852
+ // Enable / disable buttons
17853
+ DataTable.Api.register( ['buttons().enable()', 'button().enable()'], function ( flag ) {
17854
+ return this.each( function ( set ) {
17855
+ set.inst.enable( set.node, flag );
17856
+ } );
17857
+ } );
17858
+
17859
+ // Disable buttons
17860
+ DataTable.Api.register( ['buttons().disable()', 'button().disable()'], function () {
17861
+ return this.each( function ( set ) {
17862
+ set.inst.disable( set.node );
17863
+ } );
17864
+ } );
17865
+
17866
+ // Get button nodes
17867
+ DataTable.Api.registerPlural( 'buttons().nodes()', 'button().node()', function () {
17868
+ var jq = $();
17869
+
17870
+ // jQuery will automatically reduce duplicates to a single entry
17871
+ $( this.each( function ( set ) {
17872
+ jq = jq.add( set.inst.node( set.node ) );
17873
+ } ) );
17874
+
17875
+ return jq;
17876
+ } );
17877
+
17878
+ // Get / set button processing state
17879
+ DataTable.Api.registerPlural( 'buttons().processing()', 'button().processing()', function ( flag ) {
17880
+ if ( flag === undefined ) {
17881
+ return this.map( function ( set ) {
17882
+ return set.inst.processing( set.node );
17883
+ } );
17884
+ }
17885
+
17886
+ return this.each( function ( set ) {
17887
+ set.inst.processing( set.node, flag );
17888
+ } );
17889
+ } );
17890
+
17891
+ // Get / set button text (i.e. the button labels)
17892
+ DataTable.Api.registerPlural( 'buttons().text()', 'button().text()', function ( label ) {
17893
+ if ( label === undefined ) {
17894
+ return this.map( function ( set ) {
17895
+ return set.inst.text( set.node );
17896
+ } );
17897
+ }
17898
+
17899
+ return this.each( function ( set ) {
17900
+ set.inst.text( set.node, label );
17901
+ } );
17902
+ } );
17903
+
17904
+ // Trigger a button's action
17905
+ DataTable.Api.registerPlural( 'buttons().trigger()', 'button().trigger()', function () {
17906
+ return this.each( function ( set ) {
17907
+ set.inst.node( set.node ).trigger( 'click' );
17908
+ } );
17909
+ } );
17910
+
17911
+ // Get the container elements
17912
+ DataTable.Api.registerPlural( 'buttons().containers()', 'buttons().container()', function () {
17913
+ var jq = $();
17914
+ var groupSelector = this._groupSelector;
17915
+
17916
+ // We need to use the group selector directly, since if there are no buttons
17917
+ // the result set will be empty
17918
+ this.iterator( true, 'table', function ( ctx ) {
17919
+ if ( ctx._buttons ) {
17920
+ var insts = Buttons.instanceSelector( groupSelector, ctx._buttons );
17921
+
17922
+ for ( var i=0, ien=insts.length ; i<ien ; i++ ) {
17923
+ jq = jq.add( insts[i].container() );
17924
+ }
17925
+ }
17926
+ } );
17927
+
17928
+ return jq;
17929
+ } );
17930
+
17931
+ // Add a new button
17932
+ DataTable.Api.register( 'button().add()', function ( idx, conf ) {
17933
+ var ctx = this.context;
17934
+
17935
+ // Don't use `this` as it could be empty - select the instances directly
17936
+ if ( ctx.length ) {
17937
+ var inst = Buttons.instanceSelector( this._groupSelector, ctx[0]._buttons );
17938
+
17939
+ if ( inst.length ) {
17940
+ inst[0].add( conf, idx );
17941
+ }
17942
+ }
17943
+
17944
+ return this.button( this._groupSelector, idx );
17945
+ } );
17946
+
17947
+ // Destroy the button sets selected
17948
+ DataTable.Api.register( 'buttons().destroy()', function () {
17949
+ this.pluck( 'inst' ).unique().each( function ( inst ) {
17950
+ inst.destroy();
17951
+ } );
17952
+
17953
+ return this;
17954
+ } );
17955
+
17956
+ // Remove a button
17957
+ DataTable.Api.registerPlural( 'buttons().remove()', 'buttons().remove()', function () {
17958
+ this.each( function ( set ) {
17959
+ set.inst.remove( set.node );
17960
+ } );
17961
+
17962
+ return this;
17963
+ } );
17964
+
17965
+ // Information box that can be used by buttons
17966
+ var _infoTimer;
17967
+ DataTable.Api.register( 'buttons.info()', function ( title, message, time ) {
17968
+ var that = this;
17969
+
17970
+ if ( title === false ) {
17971
+ $('#datatables_buttons_info').fadeOut( function () {
17972
+ $(this).remove();
17973
+ } );
17974
+ clearTimeout( _infoTimer );
17975
+ _infoTimer = null;
17976
+
17977
+ return this;
17978
+ }
17979
+
17980
+ if ( _infoTimer ) {
17981
+ clearTimeout( _infoTimer );
17982
+ }
17983
+
17984
+ if ( $('#datatables_buttons_info').length ) {
17985
+ $('#datatables_buttons_info').remove();
17986
+ }
17987
+
17988
+ title = title ? '<h2>'+title+'</h2>' : '';
17989
+
17990
+ $('<div id="datatables_buttons_info" class="dt-button-info"/>')
17991
+ .html( title )
17992
+ .append( $('<div/>')[ typeof message === 'string' ? 'html' : 'append' ]( message ) )
17993
+ .css( 'display', 'none' )
17994
+ .appendTo( 'body' )
17995
+ .fadeIn();
17996
+
17997
+ if ( time !== undefined && time !== 0 ) {
17998
+ _infoTimer = setTimeout( function () {
17999
+ that.buttons.info( false );
18000
+ }, time );
18001
+ }
18002
+
18003
+ return this;
18004
+ } );
18005
+
18006
+ // Get data from the table for export - this is common to a number of plug-in
18007
+ // buttons so it is included in the Buttons core library
18008
+ DataTable.Api.register( 'buttons.exportData()', function ( options ) {
18009
+ if ( this.context.length ) {
18010
+ return _exportData( new DataTable.Api( this.context[0] ), options );
18011
+ }
18012
+ } );
18013
+
18014
+ // Get information about the export that is common to many of the export data
18015
+ // types (DRY)
18016
+ DataTable.Api.register( 'buttons.exportInfo()', function ( conf ) {
18017
+ if ( ! conf ) {
18018
+ conf = {};
18019
+ }
18020
+
18021
+ return {
18022
+ filename: _filename( conf ),
18023
+ title: _title( conf ),
18024
+ messageTop: _message(this, conf.message || conf.messageTop, 'top'),
18025
+ messageBottom: _message(this, conf.messageBottom, 'bottom')
18026
+ };
18027
+ } );
18028
+
18029
+
18030
+
18031
+ /**
18032
+ * Get the file name for an exported file.
18033
+ *
18034
+ * @param {object} config Button configuration
18035
+ * @param {boolean} incExtension Include the file name extension
18036
+ */
18037
+ var _filename = function ( config )
18038
+ {
18039
+ // Backwards compatibility
18040
+ var filename = config.filename === '*' && config.title !== '*' && config.title !== undefined && config.title !== null && config.title !== '' ?
18041
+ config.title :
18042
+ config.filename;
18043
+
18044
+ if ( typeof filename === 'function' ) {
18045
+ filename = filename();
18046
+ }
18047
+
18048
+ if ( filename === undefined || filename === null ) {
18049
+ return null;
18050
+ }
18051
+
18052
+ if ( filename.indexOf( '*' ) !== -1 ) {
18053
+ filename = $.trim( filename.replace( '*', $('head > title').text() ) );
18054
+ }
18055
+
18056
+ // Strip characters which the OS will object to
18057
+ filename = filename.replace(/[^a-zA-Z0-9_\u00A1-\uFFFF\.,\-_ !\(\)]/g, "");
18058
+
18059
+ var extension = _stringOrFunction( config.extension );
18060
+ if ( ! extension ) {
18061
+ extension = '';
18062
+ }
18063
+
18064
+ return filename + extension;
18065
+ };
18066
+
18067
+ /**
18068
+ * Simply utility method to allow parameters to be given as a function
18069
+ *
18070
+ * @param {undefined|string|function} option Option
18071
+ * @return {null|string} Resolved value
18072
+ */
18073
+ var _stringOrFunction = function ( option )
18074
+ {
18075
+ if ( option === null || option === undefined ) {
18076
+ return null;
18077
+ }
18078
+ else if ( typeof option === 'function' ) {
18079
+ return option();
18080
+ }
18081
+ return option;
18082
+ };
18083
+
18084
+ /**
18085
+ * Get the title for an exported file.
18086
+ *
18087
+ * @param {object} config Button configuration
18088
+ */
18089
+ var _title = function ( config )
18090
+ {
18091
+ var title = _stringOrFunction( config.title );
18092
+
18093
+ return title === null ?
18094
+ null : title.indexOf( '*' ) !== -1 ?
18095
+ title.replace( '*', $('head > title').text() || 'Exported data' ) :
18096
+ title;
18097
+ };
18098
+
18099
+ var _message = function ( dt, option, position )
18100
+ {
18101
+ var message = _stringOrFunction( option );
18102
+ if ( message === null ) {
18103
+ return null;
18104
+ }
18105
+
18106
+ var caption = $('caption', dt.table().container()).eq(0);
18107
+ if ( message === '*' ) {
18108
+ var side = caption.css( 'caption-side' );
18109
+ if ( side !== position ) {
18110
+ return null;
18111
+ }
18112
+
18113
+ return caption.length ?
18114
+ caption.text() :
18115
+ '';
18116
+ }
18117
+
18118
+ return message;
18119
+ };
18120
+
18121
+
18122
+
18123
+
18124
+
18125
+
18126
+
18127
+ var _exportTextarea = $('<textarea/>')[0];
18128
+ var _exportData = function ( dt, inOpts )
18129
+ {
18130
+ var config = $.extend( true, {}, {
18131
+ rows: null,
18132
+ columns: '',
18133
+ modifier: {
18134
+ search: 'applied',
18135
+ order: 'applied'
18136
+ },
18137
+ orthogonal: 'display',
18138
+ stripHtml: true,
18139
+ stripNewlines: true,
18140
+ decodeEntities: true,
18141
+ trim: true,
18142
+ format: {
18143
+ header: function ( d ) {
18144
+ return strip( d );
18145
+ },
18146
+ footer: function ( d ) {
18147
+ return strip( d );
18148
+ },
18149
+ body: function ( d ) {
18150
+ return strip( d );
18151
+ }
18152
+ }
18153
+ }, inOpts );
18154
+
18155
+ var strip = function ( str ) {
18156
+ if ( typeof str !== 'string' ) {
18157
+ return str;
18158
+ }
18159
+
18160
+ // Always remove script tags
18161
+ str = str.replace( /<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, '' );
18162
+
18163
+ if ( config.stripHtml ) {
18164
+ str = str.replace( /<[^>]*>/g, '' );
18165
+ }
18166
+
18167
+ if ( config.trim ) {
18168
+ str = str.replace( /^\s+|\s+$/g, '' );
18169
+ }
18170
+
18171
+ if ( config.stripNewlines ) {
18172
+ str = str.replace( /\n/g, ' ' );
18173
+ }
18174
+
18175
+ if ( config.decodeEntities ) {
18176
+ _exportTextarea.innerHTML = str;
18177
+ str = _exportTextarea.value;
18178
+ }
18179
+
18180
+ return str;
18181
+ };
18182
+
18183
+
18184
+ var header = dt.columns( config.columns ).indexes().map( function (idx) {
18185
+ var el = dt.column( idx ).header();
18186
+ return config.format.header( el.innerHTML, idx, el );
18187
+ } ).toArray();
18188
+
18189
+ var footer = dt.table().footer() ?
18190
+ dt.columns( config.columns ).indexes().map( function (idx) {
18191
+ var el = dt.column( idx ).footer();
18192
+ return config.format.footer( el ? el.innerHTML : '', idx, el );
18193
+ } ).toArray() :
18194
+ null;
18195
+
18196
+ // If Select is available on this table, and any rows are selected, limit the export
18197
+ // to the selected rows. If no rows are selected, all rows will be exported. Specify
18198
+ // a `selected` modifier to control directly.
18199
+ var modifier = $.extend( {}, config.modifier );
18200
+ if ( dt.select && typeof dt.select.info === 'function' && modifier.selected === undefined ) {
18201
+ if ( dt.rows( config.rows, $.extend( { selected: true }, modifier ) ).any() ) {
18202
+ $.extend( modifier, { selected: true } )
18203
+ }
18204
+ }
18205
+
18206
+ var rowIndexes = dt.rows( config.rows, modifier ).indexes().toArray();
18207
+ var selectedCells = dt.cells( rowIndexes, config.columns );
18208
+ var cells = selectedCells
18209
+ .render( config.orthogonal )
18210
+ .toArray();
18211
+ var cellNodes = selectedCells
18212
+ .nodes()
18213
+ .toArray();
18214
+
18215
+ var columns = header.length;
18216
+ var rows = columns > 0 ? cells.length / columns : 0;
18217
+ var body = [ rows ];
18218
+ var cellCounter = 0;
18219
+
18220
+ for ( var i=0, ien=rows ; i<ien ; i++ ) {
18221
+ var row = [ columns ];
18222
+
18223
+ for ( var j=0 ; j<columns ; j++ ) {
18224
+ row[j] = config.format.body( cells[ cellCounter ], i, j, cellNodes[ cellCounter ] );
18225
+ cellCounter++;
18226
+ }
18227
+
18228
+ body[i] = row;
18229
+ }
18230
+
18231
+ return {
18232
+ header: header,
18233
+ footer: footer,
18234
+ body: body
18235
+ };
18236
+ };
18237
+
18238
+
18239
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
18240
+ * DataTables interface
18241
+ */
18242
+
18243
+ // Attach to DataTables objects for global access
18244
+ $.fn.dataTable.Buttons = Buttons;
18245
+ $.fn.DataTable.Buttons = Buttons;
18246
+
18247
+
18248
+
18249
+ // DataTables creation - check if the buttons have been defined for this table,
18250
+ // they will have been if the `B` option was used in `dom`, otherwise we should
18251
+ // create the buttons instance here so they can be inserted into the document
18252
+ // using the API. Listen for `init` for compatibility with pre 1.10.10, but to
18253
+ // be removed in future.
18254
+ $(document).on( 'init.dt plugin-init.dt', function (e, settings) {
18255
+ if ( e.namespace !== 'dt' ) {
18256
+ return;
18257
+ }
18258
+
18259
+ var opts = settings.oInit.buttons || DataTable.defaults.buttons;
18260
+
18261
+ if ( opts && ! settings._buttons ) {
18262
+ new Buttons( settings, opts ).container();
18263
+ }
18264
+ } );
18265
+
18266
+ // DataTables `dom` feature option
18267
+ DataTable.ext.feature.push( {
18268
+ fnInit: function( settings ) {
18269
+ var api = new DataTable.Api( settings );
18270
+ var opts = api.init().buttons || DataTable.defaults.buttons;
18271
+
18272
+ return new Buttons( api, opts ).container();
18273
+ },
18274
+ cFeature: "B"
18275
+ } );
18276
+
18277
+
18278
+ return Buttons;
18279
+ }));
18280
+
18281
+
18282
+ /*! ColReorder 1.4.1
18283
+ * ©2010-2017 SpryMedia Ltd - datatables.net/license
18284
+ */
18285
+
18286
+ /**
18287
+ * @summary ColReorder
18288
+ * @description Provide the ability to reorder columns in a DataTable
18289
+ * @version 1.4.1
18290
+ * @file dataTables.colReorder.js
18291
+ * @author SpryMedia Ltd (www.sprymedia.co.uk)
18292
+ * @contact www.sprymedia.co.uk/contact
18293
+ * @copyright Copyright 2010-2017 SpryMedia Ltd.
18294
+ *
18295
+ * This source file is free software, available under the following license:
18296
+ * MIT license - http://datatables.net/license/mit
18297
+ *
18298
+ * This source file is distributed in the hope that it will be useful, but
18299
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
18300
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
18301
+ *
18302
+ * For details please refer to: http://www.datatables.net
18303
+ */
18304
+ (function( factory ){
18305
+ if ( typeof define === 'function' && define.amd ) {
18306
+ // AMD
18307
+ define( ['jquery', 'datatables.net'], function ( $ ) {
18308
+ return factory( $, window, document );
18309
+ } );
18310
+ }
18311
+ else if ( typeof exports === 'object' ) {
18312
+ // CommonJS
18313
+ module.exports = function (root, $) {
18314
+ if ( ! root ) {
18315
+ root = window;
18316
+ }
18317
+
18318
+ if ( ! $ || ! $.fn.dataTable ) {
18319
+ $ = require('datatables.net')(root, $).$;
18320
+ }
18321
+
18322
+ return factory( $, root, root.document );
18323
+ };
18324
+ }
18325
+ else {
18326
+ // Browser
18327
+ factory( jQuery, window, document );
18328
+ }
18329
+ }(function( $, window, document, undefined ) {
18330
+ 'use strict';
18331
+ var DataTable = $.fn.dataTable;
18332
+
18333
+
18334
+ /**
18335
+ * Switch the key value pairing of an index array to be value key (i.e. the old value is now the
18336
+ * key). For example consider [ 2, 0, 1 ] this would be returned as [ 1, 2, 0 ].
18337
+ * @method fnInvertKeyValues
18338
+ * @param array aIn Array to switch around
18339
+ * @returns array
18340
+ */
18341
+ function fnInvertKeyValues( aIn )
18342
+ {
18343
+ var aRet=[];
18344
+ for ( var i=0, iLen=aIn.length ; i<iLen ; i++ )
18345
+ {
18346
+ aRet[ aIn[i] ] = i;
18347
+ }
18348
+ return aRet;
18349
+ }
18350
+
18351
+
18352
+ /**
18353
+ * Modify an array by switching the position of two elements
18354
+ * @method fnArraySwitch
18355
+ * @param array aArray Array to consider, will be modified by reference (i.e. no return)
18356
+ * @param int iFrom From point
18357
+ * @param int iTo Insert point
18358
+ * @returns void
18359
+ */
18360
+ function fnArraySwitch( aArray, iFrom, iTo )
18361
+ {
18362
+ var mStore = aArray.splice( iFrom, 1 )[0];
18363
+ aArray.splice( iTo, 0, mStore );
18364
+ }
18365
+
18366
+
18367
+ /**
18368
+ * Switch the positions of nodes in a parent node (note this is specifically designed for
18369
+ * table rows). Note this function considers all element nodes under the parent!
18370
+ * @method fnDomSwitch
18371
+ * @param string sTag Tag to consider
18372
+ * @param int iFrom Element to move
18373
+ * @param int Point to element the element to (before this point), can be null for append
18374
+ * @returns void
18375
+ */
18376
+ function fnDomSwitch( nParent, iFrom, iTo )
18377
+ {
18378
+ var anTags = [];
18379
+ for ( var i=0, iLen=nParent.childNodes.length ; i<iLen ; i++ )
18380
+ {
18381
+ if ( nParent.childNodes[i].nodeType == 1 )
18382
+ {
18383
+ anTags.push( nParent.childNodes[i] );
18384
+ }
18385
+ }
18386
+ var nStore = anTags[ iFrom ];
18387
+
18388
+ if ( iTo !== null )
18389
+ {
18390
+ nParent.insertBefore( nStore, anTags[iTo] );
18391
+ }
18392
+ else
18393
+ {
18394
+ nParent.appendChild( nStore );
18395
+ }
18396
+ }
18397
+
18398
+
18399
+ /**
18400
+ * Plug-in for DataTables which will reorder the internal column structure by taking the column
18401
+ * from one position (iFrom) and insert it into a given point (iTo).
18402
+ * @method $.fn.dataTableExt.oApi.fnColReorder
18403
+ * @param object oSettings DataTables settings object - automatically added by DataTables!
18404
+ * @param int iFrom Take the column to be repositioned from this point
18405
+ * @param int iTo and insert it into this point
18406
+ * @param bool drop Indicate if the reorder is the final one (i.e. a drop)
18407
+ * not a live reorder
18408
+ * @param bool invalidateRows speeds up processing if false passed
18409
+ * @returns void
18410
+ */
18411
+ $.fn.dataTableExt.oApi.fnColReorder = function ( oSettings, iFrom, iTo, drop, invalidateRows )
18412
+ {
18413
+ var i, iLen, j, jLen, jen, iCols=oSettings.aoColumns.length, nTrs, oCol;
18414
+ var attrMap = function ( obj, prop, mapping ) {
18415
+ if ( ! obj[ prop ] || typeof obj[ prop ] === 'function' ) {
18416
+ return;
18417
+ }
18418
+
18419
+ var a = obj[ prop ].split('.');
18420
+ var num = a.shift();
18421
+
18422
+ if ( isNaN( num*1 ) ) {
18423
+ return;
18424
+ }
18425
+
18426
+ obj[ prop ] = mapping[ num*1 ]+'.'+a.join('.');
18427
+ };
18428
+
18429
+ /* Sanity check in the input */
18430
+ if ( iFrom == iTo )
18431
+ {
18432
+ /* Pointless reorder */
18433
+ return;
18434
+ }
18435
+
18436
+ if ( iFrom < 0 || iFrom >= iCols )
18437
+ {
18438
+ this.oApi._fnLog( oSettings, 1, "ColReorder 'from' index is out of bounds: "+iFrom );
18439
+ return;
18440
+ }
18441
+
18442
+ if ( iTo < 0 || iTo >= iCols )
18443
+ {
18444
+ this.oApi._fnLog( oSettings, 1, "ColReorder 'to' index is out of bounds: "+iTo );
18445
+ return;
18446
+ }
18447
+
18448
+ /*
18449
+ * Calculate the new column array index, so we have a mapping between the old and new
18450
+ */
18451
+ var aiMapping = [];
18452
+ for ( i=0, iLen=iCols ; i<iLen ; i++ )
18453
+ {
18454
+ aiMapping[i] = i;
18455
+ }
18456
+ fnArraySwitch( aiMapping, iFrom, iTo );
18457
+ var aiInvertMapping = fnInvertKeyValues( aiMapping );
18458
+
18459
+
18460
+ /*
18461
+ * Convert all internal indexing to the new column order indexes
18462
+ */
18463
+ /* Sorting */
18464
+ for ( i=0, iLen=oSettings.aaSorting.length ; i<iLen ; i++ )
18465
+ {
18466
+ oSettings.aaSorting[i][0] = aiInvertMapping[ oSettings.aaSorting[i][0] ];
18467
+ }
18468
+
18469
+ /* Fixed sorting */
18470
+ if ( oSettings.aaSortingFixed !== null )
18471
+ {
18472
+ for ( i=0, iLen=oSettings.aaSortingFixed.length ; i<iLen ; i++ )
18473
+ {
18474
+ oSettings.aaSortingFixed[i][0] = aiInvertMapping[ oSettings.aaSortingFixed[i][0] ];
18475
+ }
18476
+ }
18477
+
18478
+ /* Data column sorting (the column which the sort for a given column should take place on) */
18479
+ for ( i=0, iLen=iCols ; i<iLen ; i++ )
18480
+ {
18481
+ oCol = oSettings.aoColumns[i];
18482
+ for ( j=0, jLen=oCol.aDataSort.length ; j<jLen ; j++ )
18483
+ {
18484
+ oCol.aDataSort[j] = aiInvertMapping[ oCol.aDataSort[j] ];
18485
+ }
18486
+
18487
+ // Update the column indexes
18488
+ oCol.idx = aiInvertMapping[ oCol.idx ];
18489
+ }
18490
+
18491
+ // Update 1.10 optimised sort class removal variable
18492
+ $.each( oSettings.aLastSort, function (i, val) {
18493
+ oSettings.aLastSort[i].src = aiInvertMapping[ val.src ];
18494
+ } );
18495
+
18496
+ /* Update the Get and Set functions for each column */
18497
+ for ( i=0, iLen=iCols ; i<iLen ; i++ )
18498
+ {
18499
+ oCol = oSettings.aoColumns[i];
18500
+
18501
+ if ( typeof oCol.mData == 'number' ) {
18502
+ oCol.mData = aiInvertMapping[ oCol.mData ];
18503
+ }
18504
+ else if ( $.isPlainObject( oCol.mData ) ) {
18505
+ // HTML5 data sourced
18506
+ attrMap( oCol.mData, '_', aiInvertMapping );
18507
+ attrMap( oCol.mData, 'filter', aiInvertMapping );
18508
+ attrMap( oCol.mData, 'sort', aiInvertMapping );
18509
+ attrMap( oCol.mData, 'type', aiInvertMapping );
18510
+ }
18511
+ }
18512
+
18513
+ /*
18514
+ * Move the DOM elements
18515
+ */
18516
+ if ( oSettings.aoColumns[iFrom].bVisible )
18517
+ {
18518
+ /* Calculate the current visible index and the point to insert the node before. The insert
18519
+ * before needs to take into account that there might not be an element to insert before,
18520
+ * in which case it will be null, and an appendChild should be used
18521
+ */
18522
+ var iVisibleIndex = this.oApi._fnColumnIndexToVisible( oSettings, iFrom );
18523
+ var iInsertBeforeIndex = null;
18524
+
18525
+ i = iTo < iFrom ? iTo : iTo + 1;
18526
+ while ( iInsertBeforeIndex === null && i < iCols )
18527
+ {
18528
+ iInsertBeforeIndex = this.oApi._fnColumnIndexToVisible( oSettings, i );
18529
+ i++;
18530
+ }
18531
+
18532
+ /* Header */
18533
+ nTrs = oSettings.nTHead.getElementsByTagName('tr');
18534
+ for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
18535
+ {
18536
+ fnDomSwitch( nTrs[i], iVisibleIndex, iInsertBeforeIndex );
18537
+ }
18538
+
18539
+ /* Footer */
18540
+ if ( oSettings.nTFoot !== null )
18541
+ {
18542
+ nTrs = oSettings.nTFoot.getElementsByTagName('tr');
18543
+ for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
18544
+ {
18545
+ fnDomSwitch( nTrs[i], iVisibleIndex, iInsertBeforeIndex );
18546
+ }
18547
+ }
18548
+
18549
+ /* Body */
18550
+ for ( i=0, iLen=oSettings.aoData.length ; i<iLen ; i++ )
18551
+ {
18552
+ if ( oSettings.aoData[i].nTr !== null )
18553
+ {
18554
+ fnDomSwitch( oSettings.aoData[i].nTr, iVisibleIndex, iInsertBeforeIndex );
18555
+ }
18556
+ }
18557
+ }
18558
+
18559
+ /*
18560
+ * Move the internal array elements
18561
+ */
18562
+ /* Columns */
18563
+ fnArraySwitch( oSettings.aoColumns, iFrom, iTo );
18564
+
18565
+ // regenerate the get / set functions
18566
+ for ( i=0, iLen=iCols ; i<iLen ; i++ ) {
18567
+ oSettings.oApi._fnColumnOptions( oSettings, i, {} );
18568
+ }
18569
+
18570
+ /* Search columns */
18571
+ fnArraySwitch( oSettings.aoPreSearchCols, iFrom, iTo );
18572
+
18573
+ /* Array array - internal data anodes cache */
18574
+ for ( i=0, iLen=oSettings.aoData.length ; i<iLen ; i++ )
18575
+ {
18576
+ var data = oSettings.aoData[i];
18577
+ var cells = data.anCells;
18578
+
18579
+ if ( cells ) {
18580
+ fnArraySwitch( cells, iFrom, iTo );
18581
+
18582
+ // Longer term, should this be moved into the DataTables' invalidate
18583
+ // methods?
18584
+ for ( j=0, jen=cells.length ; j<jen ; j++ ) {
18585
+ if ( cells[j] && cells[j]._DT_CellIndex ) {
18586
+ cells[j]._DT_CellIndex.column = j;
18587
+ }
18588
+ }
18589
+ }
18590
+
18591
+ // For DOM sourced data, the invalidate will reread the cell into
18592
+ // the data array, but for data sources as an array, they need to
18593
+ // be flipped
18594
+ if ( data.src !== 'dom' && $.isArray( data._aData ) ) {
18595
+ fnArraySwitch( data._aData, iFrom, iTo );
18596
+ }
18597
+ }
18598
+
18599
+ /* Reposition the header elements in the header layout array */
18600
+ for ( i=0, iLen=oSettings.aoHeader.length ; i<iLen ; i++ )
18601
+ {
18602
+ fnArraySwitch( oSettings.aoHeader[i], iFrom, iTo );
18603
+ }
18604
+
18605
+ if ( oSettings.aoFooter !== null )
18606
+ {
18607
+ for ( i=0, iLen=oSettings.aoFooter.length ; i<iLen ; i++ )
18608
+ {
18609
+ fnArraySwitch( oSettings.aoFooter[i], iFrom, iTo );
18610
+ }
18611
+ }
18612
+
18613
+ if ( invalidateRows || invalidateRows === undefined )
18614
+ {
18615
+ $.fn.dataTable.Api( oSettings ).rows().invalidate();
18616
+ }
18617
+
18618
+ /*
18619
+ * Update DataTables' event handlers
18620
+ */
18621
+
18622
+ /* Sort listener */
18623
+ for ( i=0, iLen=iCols ; i<iLen ; i++ )
18624
+ {
18625
+ $(oSettings.aoColumns[i].nTh).off('click.DT');
18626
+ this.oApi._fnSortAttachListener( oSettings, oSettings.aoColumns[i].nTh, i );
18627
+ }
18628
+
18629
+
18630
+ /* Fire an event so other plug-ins can update */
18631
+ $(oSettings.oInstance).trigger( 'column-reorder.dt', [ oSettings, {
18632
+ from: iFrom,
18633
+ to: iTo,
18634
+ mapping: aiInvertMapping,
18635
+ drop: drop,
18636
+
18637
+ // Old style parameters for compatibility
18638
+ iFrom: iFrom,
18639
+ iTo: iTo,
18640
+ aiInvertMapping: aiInvertMapping
18641
+ } ] );
18642
+ };
18643
+
18644
+ /**
18645
+ * ColReorder provides column visibility control for DataTables
18646
+ * @class ColReorder
18647
+ * @constructor
18648
+ * @param {object} dt DataTables settings object
18649
+ * @param {object} opts ColReorder options
18650
+ */
18651
+ var ColReorder = function( dt, opts )
18652
+ {
18653
+ var settings = new $.fn.dataTable.Api( dt ).settings()[0];
18654
+
18655
+ // Ensure that we can't initialise on the same table twice
18656
+ if ( settings._colReorder ) {
18657
+ return settings._colReorder;
18658
+ }
18659
+
18660
+ // Allow the options to be a boolean for defaults
18661
+ if ( opts === true ) {
18662
+ opts = {};
18663
+ }
18664
+
18665
+ // Convert from camelCase to Hungarian, just as DataTables does
18666
+ var camelToHungarian = $.fn.dataTable.camelToHungarian;
18667
+ if ( camelToHungarian ) {
18668
+ camelToHungarian( ColReorder.defaults, ColReorder.defaults, true );
18669
+ camelToHungarian( ColReorder.defaults, opts || {} );
18670
+ }
18671
+
18672
+
18673
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
18674
+ * Public class variables
18675
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
18676
+
18677
+ /**
18678
+ * @namespace Settings object which contains customisable information for ColReorder instance
18679
+ */
18680
+ this.s = {
18681
+ /**
18682
+ * DataTables settings object
18683
+ * @property dt
18684
+ * @type Object
18685
+ * @default null
18686
+ */
18687
+ "dt": null,
18688
+
18689
+ /**
18690
+ * Initialisation object used for this instance
18691
+ * @property init
18692
+ * @type object
18693
+ * @default {}
18694
+ */
18695
+ "init": $.extend( true, {}, ColReorder.defaults, opts ),
18696
+
18697
+ /**
18698
+ * Number of columns to fix (not allow to be reordered)
18699
+ * @property fixed
18700
+ * @type int
18701
+ * @default 0
18702
+ */
18703
+ "fixed": 0,
18704
+
18705
+ /**
18706
+ * Number of columns to fix counting from right (not allow to be reordered)
18707
+ * @property fixedRight
18708
+ * @type int
18709
+ * @default 0
18710
+ */
18711
+ "fixedRight": 0,
18712
+
18713
+ /**
18714
+ * Callback function for once the reorder has been done
18715
+ * @property reorderCallback
18716
+ * @type function
18717
+ * @default null
18718
+ */
18719
+ "reorderCallback": null,
18720
+
18721
+ /**
18722
+ * @namespace Information used for the mouse drag
18723
+ */
18724
+ "mouse": {
18725
+ "startX": -1,
18726
+ "startY": -1,
18727
+ "offsetX": -1,
18728
+ "offsetY": -1,
18729
+ "target": -1,
18730
+ "targetIndex": -1,
18731
+ "fromIndex": -1
18732
+ },
18733
+
18734
+ /**
18735
+ * Information which is used for positioning the insert cusor and knowing where to do the
18736
+ * insert. Array of objects with the properties:
18737
+ * x: x-axis position
18738
+ * to: insert point
18739
+ * @property aoTargets
18740
+ * @type array
18741
+ * @default []
18742
+ */
18743
+ "aoTargets": []
18744
+ };
18745
+
18746
+
18747
+ /**
18748
+ * @namespace Common and useful DOM elements for the class instance
18749
+ */
18750
+ this.dom = {
18751
+ /**
18752
+ * Dragging element (the one the mouse is moving)
18753
+ * @property drag
18754
+ * @type element
18755
+ * @default null
18756
+ */
18757
+ "drag": null,
18758
+
18759
+ /**
18760
+ * The insert cursor
18761
+ * @property pointer
18762
+ * @type element
18763
+ * @default null
18764
+ */
18765
+ "pointer": null
18766
+ };
18767
+
18768
+
18769
+ /* Constructor logic */
18770
+ this.s.dt = settings;
18771
+ this.s.dt._colReorder = this;
18772
+ this._fnConstruct();
18773
+
18774
+ return this;
18775
+ };
18776
+
18777
+
18778
+
18779
+ $.extend( ColReorder.prototype, {
18780
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
18781
+ * Public methods
18782
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
18783
+
18784
+ /**
18785
+ * Reset the column ordering to the original ordering that was detected on
18786
+ * start up.
18787
+ * @return {this} Returns `this` for chaining.
18788
+ *
18789
+ * @example
18790
+ * // DataTables initialisation with ColReorder
18791
+ * var table = $('#example').dataTable( {
18792
+ * "sDom": 'Rlfrtip'
18793
+ * } );
18794
+ *
18795
+ * // Add click event to a button to reset the ordering
18796
+ * $('#resetOrdering').click( function (e) {
18797
+ * e.preventDefault();
18798
+ * $.fn.dataTable.ColReorder( table ).fnReset();
18799
+ * } );
18800
+ */
18801
+ "fnReset": function ()
18802
+ {
18803
+ this._fnOrderColumns( this.fnOrder() );
18804
+
18805
+ return this;
18806
+ },
18807
+
18808
+ /**
18809
+ * `Deprecated` - Get the current order of the columns, as an array.
18810
+ * @return {array} Array of column identifiers
18811
+ * @deprecated `fnOrder` should be used in preference to this method.
18812
+ * `fnOrder` acts as a getter/setter.
18813
+ */
18814
+ "fnGetCurrentOrder": function ()
18815
+ {
18816
+ return this.fnOrder();
18817
+ },
18818
+
18819
+ /**
18820
+ * Get the current order of the columns, as an array. Note that the values
18821
+ * given in the array are unique identifiers for each column. Currently
18822
+ * these are the original ordering of the columns that was detected on
18823
+ * start up, but this could potentially change in future.
18824
+ * @return {array} Array of column identifiers
18825
+ *
18826
+ * @example
18827
+ * // Get column ordering for the table
18828
+ * var order = $.fn.dataTable.ColReorder( dataTable ).fnOrder();
18829
+ *//**
18830
+ * Set the order of the columns, from the positions identified in the
18831
+ * ordering array given. Note that ColReorder takes a brute force approach
18832
+ * to reordering, so it is possible multiple reordering events will occur
18833
+ * before the final order is settled upon.
18834
+ * @param {array} [set] Array of column identifiers in the new order. Note
18835
+ * that every column must be included, uniquely, in this array.
18836
+ * @return {this} Returns `this` for chaining.
18837
+ *
18838
+ * @example
18839
+ * // Swap the first and second columns
18840
+ * $.fn.dataTable.ColReorder( dataTable ).fnOrder( [1, 0, 2, 3, 4] );
18841
+ *
18842
+ * @example
18843
+ * // Move the first column to the end for the table `#example`
18844
+ * var curr = $.fn.dataTable.ColReorder( '#example' ).fnOrder();
18845
+ * var first = curr.shift();
18846
+ * curr.push( first );
18847
+ * $.fn.dataTable.ColReorder( '#example' ).fnOrder( curr );
18848
+ *
18849
+ * @example
18850
+ * // Reverse the table's order
18851
+ * $.fn.dataTable.ColReorder( '#example' ).fnOrder(
18852
+ * $.fn.dataTable.ColReorder( '#example' ).fnOrder().reverse()
18853
+ * );
18854
+ */
18855
+ "fnOrder": function ( set, original )
18856
+ {
18857
+ var a = [], i, ien, j, jen;
18858
+ var columns = this.s.dt.aoColumns;
18859
+
18860
+ if ( set === undefined ){
18861
+ for ( i=0, ien=columns.length ; i<ien ; i++ ) {
18862
+ a.push( columns[i]._ColReorder_iOrigCol );
18863
+ }
18864
+
18865
+ return a;
18866
+ }
18867
+
18868
+ // The order given is based on the original indexes, rather than the
18869
+ // existing ones, so we need to translate from the original to current
18870
+ // before then doing the order
18871
+ if ( original ) {
18872
+ var order = this.fnOrder();
18873
+
18874
+ for ( i=0, ien=set.length ; i<ien ; i++ ) {
18875
+ a.push( $.inArray( set[i], order ) );
18876
+ }
18877
+
18878
+ set = a;
18879
+ }
18880
+
18881
+ this._fnOrderColumns( fnInvertKeyValues( set ) );
18882
+
18883
+ return this;
18884
+ },
18885
+
18886
+
18887
+ /**
18888
+ * Convert from the original column index, to the original
18889
+ *
18890
+ * @param {int|array} idx Index(es) to convert
18891
+ * @param {string} dir Transpose direction - `fromOriginal` / `toCurrent`
18892
+ * or `'toOriginal` / `fromCurrent`
18893
+ * @return {int|array} Converted values
18894
+ */
18895
+ fnTranspose: function ( idx, dir )
18896
+ {
18897
+ if ( ! dir ) {
18898
+ dir = 'toCurrent';
18899
+ }
18900
+
18901
+ var order = this.fnOrder();
18902
+ var columns = this.s.dt.aoColumns;
18903
+
18904
+ if ( dir === 'toCurrent' ) {
18905
+ // Given an original index, want the current
18906
+ return ! $.isArray( idx ) ?
18907
+ $.inArray( idx, order ) :
18908
+ $.map( idx, function ( index ) {
18909
+ return $.inArray( index, order );
18910
+ } );
18911
+ }
18912
+ else {
18913
+ // Given a current index, want the original
18914
+ return ! $.isArray( idx ) ?
18915
+ columns[idx]._ColReorder_iOrigCol :
18916
+ $.map( idx, function ( index ) {
18917
+ return columns[index]._ColReorder_iOrigCol;
18918
+ } );
18919
+ }
18920
+ },
18921
+
18922
+
18923
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
18924
+ * Private methods (they are of course public in JS, but recommended as private)
18925
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
18926
+
18927
+ /**
18928
+ * Constructor logic
18929
+ * @method _fnConstruct
18930
+ * @returns void
18931
+ * @private
18932
+ */
18933
+ "_fnConstruct": function ()
18934
+ {
18935
+ var that = this;
18936
+ var iLen = this.s.dt.aoColumns.length;
18937
+ var table = this.s.dt.nTable;
18938
+ var i;
18939
+
18940
+ /* Columns discounted from reordering - counting left to right */
18941
+ if ( this.s.init.iFixedColumns )
18942
+ {
18943
+ this.s.fixed = this.s.init.iFixedColumns;
18944
+ }
18945
+
18946
+ if ( this.s.init.iFixedColumnsLeft )
18947
+ {
18948
+ this.s.fixed = this.s.init.iFixedColumnsLeft;
18949
+ }
18950
+
18951
+ /* Columns discounted from reordering - counting right to left */
18952
+ this.s.fixedRight = this.s.init.iFixedColumnsRight ?
18953
+ this.s.init.iFixedColumnsRight :
18954
+ 0;
18955
+
18956
+ /* Drop callback initialisation option */
18957
+ if ( this.s.init.fnReorderCallback )
18958
+ {
18959
+ this.s.reorderCallback = this.s.init.fnReorderCallback;
18960
+ }
18961
+
18962
+ /* Add event handlers for the drag and drop, and also mark the original column order */
18963
+ for ( i = 0; i < iLen; i++ )
18964
+ {
18965
+ if ( i > this.s.fixed-1 && i < iLen - this.s.fixedRight )
18966
+ {
18967
+ this._fnMouseListener( i, this.s.dt.aoColumns[i].nTh );
18968
+ }
18969
+
18970
+ /* Mark the original column order for later reference */
18971
+ this.s.dt.aoColumns[i]._ColReorder_iOrigCol = i;
18972
+ }
18973
+
18974
+ /* State saving */
18975
+ this.s.dt.oApi._fnCallbackReg( this.s.dt, 'aoStateSaveParams', function (oS, oData) {
18976
+ that._fnStateSave.call( that, oData );
18977
+ }, "ColReorder_State" );
18978
+
18979
+ /* An initial column order has been specified */
18980
+ var aiOrder = null;
18981
+ if ( this.s.init.aiOrder )
18982
+ {
18983
+ aiOrder = this.s.init.aiOrder.slice();
18984
+ }
18985
+
18986
+ /* State loading, overrides the column order given */
18987
+ if ( this.s.dt.oLoadedState && typeof this.s.dt.oLoadedState.ColReorder != 'undefined' &&
18988
+ this.s.dt.oLoadedState.ColReorder.length == this.s.dt.aoColumns.length )
18989
+ {
18990
+ aiOrder = this.s.dt.oLoadedState.ColReorder;
18991
+ }
18992
+
18993
+ /* If we have an order to apply - do so */
18994
+ if ( aiOrder )
18995
+ {
18996
+ /* We might be called during or after the DataTables initialisation. If before, then we need
18997
+ * to wait until the draw is done, if after, then do what we need to do right away
18998
+ */
18999
+ if ( !that.s.dt._bInitComplete )
19000
+ {
19001
+ var bDone = false;
19002
+ $(table).on( 'draw.dt.colReorder', function () {
19003
+ if ( !that.s.dt._bInitComplete && !bDone )
19004
+ {
19005
+ bDone = true;
19006
+ var resort = fnInvertKeyValues( aiOrder );
19007
+ that._fnOrderColumns.call( that, resort );
19008
+ }
19009
+ } );
19010
+ }
19011
+ else
19012
+ {
19013
+ var resort = fnInvertKeyValues( aiOrder );
19014
+ that._fnOrderColumns.call( that, resort );
19015
+ }
19016
+ }
19017
+ else {
19018
+ this._fnSetColumnIndexes();
19019
+ }
19020
+
19021
+ // Destroy clean up
19022
+ $(table).on( 'destroy.dt.colReorder', function () {
19023
+ $(table).off( 'destroy.dt.colReorder draw.dt.colReorder' );
19024
+ $(that.s.dt.nTHead).find( '*' ).off( '.ColReorder' );
19025
+
19026
+ $.each( that.s.dt.aoColumns, function (i, column) {
19027
+ $(column.nTh).removeAttr('data-column-index');
19028
+ } );
19029
+
19030
+ that.s.dt._colReorder = null;
19031
+ that.s = null;
19032
+ } );
19033
+ },
19034
+
19035
+
19036
+ /**
19037
+ * Set the column order from an array
19038
+ * @method _fnOrderColumns
19039
+ * @param array a An array of integers which dictate the column order that should be applied
19040
+ * @returns void
19041
+ * @private
19042
+ */
19043
+ "_fnOrderColumns": function ( a )
19044
+ {
19045
+ var changed = false;
19046
+
19047
+ if ( a.length != this.s.dt.aoColumns.length )
19048
+ {
19049
+ this.s.dt.oInstance.oApi._fnLog( this.s.dt, 1, "ColReorder - array reorder does not "+
19050
+ "match known number of columns. Skipping." );
19051
+ return;
19052
+ }
19053
+
19054
+ for ( var i=0, iLen=a.length ; i<iLen ; i++ )
19055
+ {
19056
+ var currIndex = $.inArray( i, a );
19057
+ if ( i != currIndex )
19058
+ {
19059
+ /* Reorder our switching array */
19060
+ fnArraySwitch( a, currIndex, i );
19061
+
19062
+ /* Do the column reorder in the table */
19063
+ this.s.dt.oInstance.fnColReorder( currIndex, i, true, false );
19064
+
19065
+ changed = true;
19066
+ }
19067
+ }
19068
+
19069
+ $.fn.dataTable.Api( this.s.dt ).rows().invalidate();
19070
+
19071
+ this._fnSetColumnIndexes();
19072
+
19073
+ // Has anything actually changed? If not, then nothing else to do
19074
+ if ( ! changed ) {
19075
+ return;
19076
+ }
19077
+
19078
+ /* When scrolling we need to recalculate the column sizes to allow for the shift */
19079
+ if ( this.s.dt.oScroll.sX !== "" || this.s.dt.oScroll.sY !== "" )
19080
+ {
19081
+ this.s.dt.oInstance.fnAdjustColumnSizing( false );
19082
+ }
19083
+
19084
+ /* Save the state */
19085
+ this.s.dt.oInstance.oApi._fnSaveState( this.s.dt );
19086
+
19087
+ if ( this.s.reorderCallback !== null )
19088
+ {
19089
+ this.s.reorderCallback.call( this );
19090
+ }
19091
+ },
19092
+
19093
+
19094
+ /**
19095
+ * Because we change the indexes of columns in the table, relative to their starting point
19096
+ * we need to reorder the state columns to what they are at the starting point so we can
19097
+ * then rearrange them again on state load!
19098
+ * @method _fnStateSave
19099
+ * @param object oState DataTables state
19100
+ * @returns string JSON encoded cookie string for DataTables
19101
+ * @private
19102
+ */
19103
+ "_fnStateSave": function ( oState )
19104
+ {
19105
+ var i, iLen, aCopy, iOrigColumn;
19106
+ var oSettings = this.s.dt;
19107
+ var columns = oSettings.aoColumns;
19108
+
19109
+ oState.ColReorder = [];
19110
+
19111
+ /* Sorting */
19112
+ if ( oState.aaSorting ) {
19113
+ // 1.10.0-
19114
+ for ( i=0 ; i<oState.aaSorting.length ; i++ ) {
19115
+ oState.aaSorting[i][0] = columns[ oState.aaSorting[i][0] ]._ColReorder_iOrigCol;
19116
+ }
19117
+
19118
+ var aSearchCopy = $.extend( true, [], oState.aoSearchCols );
19119
+
19120
+ for ( i=0, iLen=columns.length ; i<iLen ; i++ )
19121
+ {
19122
+ iOrigColumn = columns[i]._ColReorder_iOrigCol;
19123
+
19124
+ /* Column filter */
19125
+ oState.aoSearchCols[ iOrigColumn ] = aSearchCopy[i];
19126
+
19127
+ /* Visibility */
19128
+ oState.abVisCols[ iOrigColumn ] = columns[i].bVisible;
19129
+
19130
+ /* Column reordering */
19131
+ oState.ColReorder.push( iOrigColumn );
19132
+ }
19133
+ }
19134
+ else if ( oState.order ) {
19135
+ // 1.10.1+
19136
+ for ( i=0 ; i<oState.order.length ; i++ ) {
19137
+ oState.order[i][0] = columns[ oState.order[i][0] ]._ColReorder_iOrigCol;
19138
+ }
19139
+
19140
+ var stateColumnsCopy = $.extend( true, [], oState.columns );
19141
+
19142
+ for ( i=0, iLen=columns.length ; i<iLen ; i++ )
19143
+ {
19144
+ iOrigColumn = columns[i]._ColReorder_iOrigCol;
19145
+
19146
+ /* Columns */
19147
+ oState.columns[ iOrigColumn ] = stateColumnsCopy[i];
19148
+
19149
+ /* Column reordering */
19150
+ oState.ColReorder.push( iOrigColumn );
19151
+ }
19152
+ }
19153
+ },
19154
+
19155
+
19156
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
19157
+ * Mouse drop and drag
19158
+ */
19159
+
19160
+ /**
19161
+ * Add a mouse down listener to a particluar TH element
19162
+ * @method _fnMouseListener
19163
+ * @param int i Column index
19164
+ * @param element nTh TH element clicked on
19165
+ * @returns void
19166
+ * @private
19167
+ */
19168
+ "_fnMouseListener": function ( i, nTh )
19169
+ {
19170
+ var that = this;
19171
+ $(nTh)
19172
+ .on( 'mousedown.ColReorder', function (e) {
19173
+ that._fnMouseDown.call( that, e, nTh );
19174
+ } )
19175
+ .on( 'touchstart.ColReorder', function (e) {
19176
+ that._fnMouseDown.call( that, e, nTh );
19177
+ } );
19178
+ },
19179
+
19180
+
19181
+ /**
19182
+ * Mouse down on a TH element in the table header
19183
+ * @method _fnMouseDown
19184
+ * @param event e Mouse event
19185
+ * @param element nTh TH element to be dragged
19186
+ * @returns void
19187
+ * @private
19188
+ */
19189
+ "_fnMouseDown": function ( e, nTh )
19190
+ {
19191
+ var that = this;
19192
+
19193
+ /* Store information about the mouse position */
19194
+ var target = $(e.target).closest('th, td');
19195
+ var offset = target.offset();
19196
+ var idx = parseInt( $(nTh).attr('data-column-index'), 10 );
19197
+
19198
+ if ( idx === undefined ) {
19199
+ return;
19200
+ }
19201
+
19202
+ this.s.mouse.startX = this._fnCursorPosition( e, 'pageX' );
19203
+ this.s.mouse.startY = this._fnCursorPosition( e, 'pageY' );
19204
+ this.s.mouse.offsetX = this._fnCursorPosition( e, 'pageX' ) - offset.left;
19205
+ this.s.mouse.offsetY = this._fnCursorPosition( e, 'pageY' ) - offset.top;
19206
+ this.s.mouse.target = this.s.dt.aoColumns[ idx ].nTh;//target[0];
19207
+ this.s.mouse.targetIndex = idx;
19208
+ this.s.mouse.fromIndex = idx;
19209
+
19210
+ this._fnRegions();
19211
+
19212
+ /* Add event handlers to the document */
19213
+ $(document)
19214
+ .on( 'mousemove.ColReorder touchmove.ColReorder', function (e) {
19215
+ that._fnMouseMove.call( that, e );
19216
+ } )
19217
+ .on( 'mouseup.ColReorder touchend.ColReorder', function (e) {
19218
+ that._fnMouseUp.call( that, e );
19219
+ } );
19220
+ },
19221
+
19222
+
19223
+ /**
19224
+ * Deal with a mouse move event while dragging a node
19225
+ * @method _fnMouseMove
19226
+ * @param event e Mouse event
19227
+ * @returns void
19228
+ * @private
19229
+ */
19230
+ "_fnMouseMove": function ( e )
19231
+ {
19232
+ var that = this;
19233
+
19234
+ if ( this.dom.drag === null )
19235
+ {
19236
+ /* Only create the drag element if the mouse has moved a specific distance from the start
19237
+ * point - this allows the user to make small mouse movements when sorting and not have a
19238
+ * possibly confusing drag element showing up
19239
+ */
19240
+ if ( Math.pow(
19241
+ Math.pow(this._fnCursorPosition( e, 'pageX') - this.s.mouse.startX, 2) +
19242
+ Math.pow(this._fnCursorPosition( e, 'pageY') - this.s.mouse.startY, 2), 0.5 ) < 5 )
19243
+ {
19244
+ return;
19245
+ }
19246
+ this._fnCreateDragNode();
19247
+ }
19248
+
19249
+ /* Position the element - we respect where in the element the click occured */
19250
+ this.dom.drag.css( {
19251
+ left: this._fnCursorPosition( e, 'pageX' ) - this.s.mouse.offsetX,
19252
+ top: this._fnCursorPosition( e, 'pageY' ) - this.s.mouse.offsetY
19253
+ } );
19254
+
19255
+ /* Based on the current mouse position, calculate where the insert should go */
19256
+ var bSet = false;
19257
+ var lastToIndex = this.s.mouse.toIndex;
19258
+
19259
+ for ( var i=1, iLen=this.s.aoTargets.length ; i<iLen ; i++ )
19260
+ {
19261
+ if ( this._fnCursorPosition(e, 'pageX') < this.s.aoTargets[i-1].x + ((this.s.aoTargets[i].x-this.s.aoTargets[i-1].x)/2) )
19262
+ {
19263
+ this.dom.pointer.css( 'left', this.s.aoTargets[i-1].x );
19264
+ this.s.mouse.toIndex = this.s.aoTargets[i-1].to;
19265
+ bSet = true;
19266
+ break;
19267
+ }
19268
+ }
19269
+
19270
+ // The insert element wasn't positioned in the array (less than
19271
+ // operator), so we put it at the end
19272
+ if ( !bSet )
19273
+ {
19274
+ this.dom.pointer.css( 'left', this.s.aoTargets[this.s.aoTargets.length-1].x );
19275
+ this.s.mouse.toIndex = this.s.aoTargets[this.s.aoTargets.length-1].to;
19276
+ }
19277
+
19278
+ // Perform reordering if realtime updating is on and the column has moved
19279
+ if ( this.s.init.bRealtime && lastToIndex !== this.s.mouse.toIndex ) {
19280
+ this.s.dt.oInstance.fnColReorder( this.s.mouse.fromIndex, this.s.mouse.toIndex, false );
19281
+ this.s.mouse.fromIndex = this.s.mouse.toIndex;
19282
+ this._fnRegions();
19283
+ }
19284
+ },
19285
+
19286
+
19287
+ /**
19288
+ * Finish off the mouse drag and insert the column where needed
19289
+ * @method _fnMouseUp
19290
+ * @param event e Mouse event
19291
+ * @returns void
19292
+ * @private
19293
+ */
19294
+ "_fnMouseUp": function ( e )
19295
+ {
19296
+ var that = this;
19297
+
19298
+ $(document).off( '.ColReorder' );
19299
+
19300
+ if ( this.dom.drag !== null )
19301
+ {
19302
+ /* Remove the guide elements */
19303
+ this.dom.drag.remove();
19304
+ this.dom.pointer.remove();
19305
+ this.dom.drag = null;
19306
+ this.dom.pointer = null;
19307
+
19308
+ /* Actually do the reorder */
19309
+ this.s.dt.oInstance.fnColReorder( this.s.mouse.fromIndex, this.s.mouse.toIndex, true );
19310
+ this._fnSetColumnIndexes();
19311
+
19312
+ /* When scrolling we need to recalculate the column sizes to allow for the shift */
19313
+ if ( this.s.dt.oScroll.sX !== "" || this.s.dt.oScroll.sY !== "" )
19314
+ {
19315
+ this.s.dt.oInstance.fnAdjustColumnSizing( false );
19316
+ }
19317
+
19318
+ /* Save the state */
19319
+ this.s.dt.oInstance.oApi._fnSaveState( this.s.dt );
19320
+
19321
+ if ( this.s.reorderCallback !== null )
19322
+ {
19323
+ this.s.reorderCallback.call( this );
19324
+ }
19325
+ }
19326
+ },
19327
+
19328
+
19329
+ /**
19330
+ * Calculate a cached array with the points of the column inserts, and the
19331
+ * 'to' points
19332
+ * @method _fnRegions
19333
+ * @returns void
19334
+ * @private
19335
+ */
19336
+ "_fnRegions": function ()
19337
+ {
19338
+ var aoColumns = this.s.dt.aoColumns;
19339
+
19340
+ this.s.aoTargets.splice( 0, this.s.aoTargets.length );
19341
+
19342
+ this.s.aoTargets.push( {
19343
+ "x": $(this.s.dt.nTable).offset().left,
19344
+ "to": 0
19345
+ } );
19346
+
19347
+ var iToPoint = 0;
19348
+ var total = this.s.aoTargets[0].x;
19349
+
19350
+ for ( var i=0, iLen=aoColumns.length ; i<iLen ; i++ )
19351
+ {
19352
+ /* For the column / header in question, we want it's position to remain the same if the
19353
+ * position is just to it's immediate left or right, so we only increment the counter for
19354
+ * other columns
19355
+ */
19356
+ if ( i != this.s.mouse.fromIndex )
19357
+ {
19358
+ iToPoint++;
19359
+ }
19360
+
19361
+ if ( aoColumns[i].bVisible && aoColumns[i].nTh.style.display !=='none' )
19362
+ {
19363
+ total += $(aoColumns[i].nTh).outerWidth();
19364
+
19365
+ this.s.aoTargets.push( {
19366
+ "x": total,
19367
+ "to": iToPoint
19368
+ } );
19369
+ }
19370
+ }
19371
+
19372
+ /* Disallow columns for being reordered by drag and drop, counting right to left */
19373
+ if ( this.s.fixedRight !== 0 )
19374
+ {
19375
+ this.s.aoTargets.splice( this.s.aoTargets.length - this.s.fixedRight );
19376
+ }
19377
+
19378
+ /* Disallow columns for being reordered by drag and drop, counting left to right */
19379
+ if ( this.s.fixed !== 0 )
19380
+ {
19381
+ this.s.aoTargets.splice( 0, this.s.fixed );
19382
+ }
19383
+ },
19384
+
19385
+
19386
+ /**
19387
+ * Copy the TH element that is being drags so the user has the idea that they are actually
19388
+ * moving it around the page.
19389
+ * @method _fnCreateDragNode
19390
+ * @returns void
19391
+ * @private
19392
+ */
19393
+ "_fnCreateDragNode": function ()
19394
+ {
19395
+ var scrolling = this.s.dt.oScroll.sX !== "" || this.s.dt.oScroll.sY !== "";
19396
+
19397
+ var origCell = this.s.dt.aoColumns[ this.s.mouse.targetIndex ].nTh;
19398
+ var origTr = origCell.parentNode;
19399
+ var origThead = origTr.parentNode;
19400
+ var origTable = origThead.parentNode;
19401
+ var cloneCell = $(origCell).clone();
19402
+
19403
+ // This is a slightly odd combination of jQuery and DOM, but it is the
19404
+ // fastest and least resource intensive way I could think of cloning
19405
+ // the table with just a single header cell in it.
19406
+ this.dom.drag = $(origTable.cloneNode(false))
19407
+ .addClass( 'DTCR_clonedTable' )
19408
+ .append(
19409
+ $(origThead.cloneNode(false)).append(
19410
+ $(origTr.cloneNode(false)).append(
19411
+ cloneCell[0]
19412
+ )
19413
+ )
19414
+ )
19415
+ .css( {
19416
+ position: 'absolute',
19417
+ top: 0,
19418
+ left: 0,
19419
+ width: $(origCell).outerWidth(),
19420
+ height: $(origCell).outerHeight()
19421
+ } )
19422
+ .appendTo( 'body' );
19423
+
19424
+ this.dom.pointer = $('<div></div>')
19425
+ .addClass( 'DTCR_pointer' )
19426
+ .css( {
19427
+ position: 'absolute',
19428
+ top: scrolling ?
19429
+ $('div.dataTables_scroll', this.s.dt.nTableWrapper).offset().top :
19430
+ $(this.s.dt.nTable).offset().top,
19431
+ height : scrolling ?
19432
+ $('div.dataTables_scroll', this.s.dt.nTableWrapper).height() :
19433
+ $(this.s.dt.nTable).height()
19434
+ } )
19435
+ .appendTo( 'body' );
19436
+ },
19437
+
19438
+
19439
+ /**
19440
+ * Add a data attribute to the column headers, so we know the index of
19441
+ * the row to be reordered. This allows fast detection of the index, and
19442
+ * for this plug-in to work with FixedHeader which clones the nodes.
19443
+ * @private
19444
+ */
19445
+ "_fnSetColumnIndexes": function ()
19446
+ {
19447
+ $.each( this.s.dt.aoColumns, function (i, column) {
19448
+ $(column.nTh).attr('data-column-index', i);
19449
+ } );
19450
+ },
19451
+
19452
+
19453
+ /**
19454
+ * Get cursor position regardless of mouse or touch input
19455
+ * @param {Event} e jQuery Event
19456
+ * @param {string} prop Property to get
19457
+ * @return {number} Value
19458
+ */
19459
+ _fnCursorPosition: function ( e, prop ) {
19460
+ if ( e.type.indexOf('touch') !== -1 ) {
19461
+ return e.originalEvent.touches[0][ prop ];
19462
+ }
19463
+ return e[ prop ];
19464
+ }
19465
+ } );
19466
+
19467
+
19468
+
19469
+
19470
+
19471
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
19472
+ * Static parameters
19473
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
19474
+
19475
+
19476
+ /**
19477
+ * ColReorder default settings for initialisation
19478
+ * @namespace
19479
+ * @static
19480
+ */
19481
+ ColReorder.defaults = {
19482
+ /**
19483
+ * Predefined ordering for the columns that will be applied automatically
19484
+ * on initialisation. If not specified then the order that the columns are
19485
+ * found to be in the HTML is the order used.
19486
+ * @type array
19487
+ * @default null
19488
+ * @static
19489
+ */
19490
+ aiOrder: null,
19491
+
19492
+ /**
19493
+ * Redraw the table's column ordering as the end user draws the column
19494
+ * (`true`) or wait until the mouse is released (`false` - default). Note
19495
+ * that this will perform a redraw on each reordering, which involves an
19496
+ * Ajax request each time if you are using server-side processing in
19497
+ * DataTables.
19498
+ * @type boolean
19499
+ * @default false
19500
+ * @static
19501
+ */
19502
+ bRealtime: true,
19503
+
19504
+ /**
19505
+ * Indicate how many columns should be fixed in position (counting from the
19506
+ * left). This will typically be 1 if used, but can be as high as you like.
19507
+ * @type int
19508
+ * @default 0
19509
+ * @static
19510
+ */
19511
+ iFixedColumnsLeft: 0,
19512
+
19513
+ /**
19514
+ * As `iFixedColumnsRight` but counting from the right.
19515
+ * @type int
19516
+ * @default 0
19517
+ * @static
19518
+ */
19519
+ iFixedColumnsRight: 0,
19520
+
19521
+ /**
19522
+ * Callback function that is fired when columns are reordered. The `column-
19523
+ * reorder` event is preferred over this callback
19524
+ * @type function():void
19525
+ * @default null
19526
+ * @static
19527
+ */
19528
+ fnReorderCallback: null
19529
+ };
19530
+
19531
+
19532
+
19533
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
19534
+ * Constants
19535
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
19536
+
19537
+ /**
19538
+ * ColReorder version
19539
+ * @constant version
19540
+ * @type String
19541
+ * @default As code
19542
+ */
19543
+ ColReorder.version = "1.4.1";
19544
+
19545
+
19546
+
19547
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
19548
+ * DataTables interfaces
19549
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
19550
+
19551
+ // Expose
19552
+ $.fn.dataTable.ColReorder = ColReorder;
19553
+ $.fn.DataTable.ColReorder = ColReorder;
19554
+
19555
+
19556
+ // Register a new feature with DataTables
19557
+ if ( typeof $.fn.dataTable == "function" &&
19558
+ typeof $.fn.dataTableExt.fnVersionCheck == "function" &&
19559
+ $.fn.dataTableExt.fnVersionCheck('1.10.8') )
19560
+ {
19561
+ $.fn.dataTableExt.aoFeatures.push( {
19562
+ "fnInit": function( settings ) {
19563
+ var table = settings.oInstance;
19564
+
19565
+ if ( ! settings._colReorder ) {
19566
+ var dtInit = settings.oInit;
19567
+ var opts = dtInit.colReorder || dtInit.oColReorder || {};
19568
+
19569
+ new ColReorder( settings, opts );
19570
+ }
19571
+ else {
19572
+ table.oApi._fnLog( settings, 1, "ColReorder attempted to initialise twice. Ignoring second" );
19573
+ }
19574
+
19575
+ return null; /* No node for DataTables to insert */
19576
+ },
19577
+ "cFeature": "R",
19578
+ "sFeature": "ColReorder"
19579
+ } );
19580
+ }
19581
+ else {
19582
+ alert( "Warning: ColReorder requires DataTables 1.10.8 or greater - www.datatables.net/download");
19583
+ }
19584
+
19585
+
19586
+ // Attach a listener to the document which listens for DataTables initialisation
19587
+ // events so we can automatically initialise
19588
+ $(document).on( 'preInit.dt.colReorder', function (e, settings) {
19589
+ if ( e.namespace !== 'dt' ) {
19590
+ return;
19591
+ }
19592
+
19593
+ var init = settings.oInit.colReorder;
19594
+ var defaults = DataTable.defaults.colReorder;
19595
+
19596
+ if ( init || defaults ) {
19597
+ var opts = $.extend( {}, init, defaults );
19598
+
19599
+ if ( init !== false ) {
19600
+ new ColReorder( settings, opts );
19601
+ }
19602
+ }
19603
+ } );
19604
+
19605
+
19606
+ // API augmentation
19607
+ $.fn.dataTable.Api.register( 'colReorder.reset()', function () {
19608
+ return this.iterator( 'table', function ( ctx ) {
19609
+ ctx._colReorder.fnReset();
19610
+ } );
19611
+ } );
19612
+
19613
+ $.fn.dataTable.Api.register( 'colReorder.order()', function ( set, original ) {
19614
+ if ( set ) {
19615
+ return this.iterator( 'table', function ( ctx ) {
19616
+ ctx._colReorder.fnOrder( set, original );
19617
+ } );
19618
+ }
19619
+
19620
+ return this.context.length ?
19621
+ this.context[0]._colReorder.fnOrder() :
19622
+ null;
19623
+ } );
19624
+
19625
+ $.fn.dataTable.Api.register( 'colReorder.transpose()', function ( idx, dir ) {
19626
+ return this.context.length && this.context[0]._colReorder ?
19627
+ this.context[0]._colReorder.fnTranspose( idx, dir ) :
19628
+ idx;
19629
+ } );
19630
+
19631
+ $.fn.dataTable.Api.register( 'colReorder.move()', function( from, to, drop, invalidateRows ) {
19632
+ if (this.context.length) {
19633
+ this.context[0]._colReorder.s.dt.oInstance.fnColReorder( from, to, drop, invalidateRows );
19634
+ }
19635
+ return this;
19636
+ } );
19637
+
19638
+
19639
+ return ColReorder;
19640
+ }));
19641
+
19642
+
19643
+ /*! FixedColumns 3.2.4
19644
+ * ©2010-2017 SpryMedia Ltd - datatables.net/license
19645
+ */
19646
+
19647
+ /**
19648
+ * @summary FixedColumns
19649
+ * @description Freeze columns in place on a scrolling DataTable
19650
+ * @version 3.2.4
19651
+ * @file dataTables.fixedColumns.js
19652
+ * @author SpryMedia Ltd (www.sprymedia.co.uk)
19653
+ * @contact www.sprymedia.co.uk/contact
19654
+ * @copyright Copyright 2010-2017 SpryMedia Ltd.
19655
+ *
19656
+ * This source file is free software, available under the following license:
19657
+ * MIT license - http://datatables.net/license/mit
19658
+ *
19659
+ * This source file is distributed in the hope that it will be useful, but
19660
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
19661
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
19662
+ *
19663
+ * For details please refer to: http://www.datatables.net
19664
+ */
19665
+ (function( factory ){
19666
+ if ( typeof define === 'function' && define.amd ) {
19667
+ // AMD
19668
+ define( ['jquery', 'datatables.net'], function ( $ ) {
19669
+ return factory( $, window, document );
19670
+ } );
19671
+ }
19672
+ else if ( typeof exports === 'object' ) {
19673
+ // CommonJS
19674
+ module.exports = function (root, $) {
19675
+ if ( ! root ) {
19676
+ root = window;
19677
+ }
19678
+
19679
+ if ( ! $ || ! $.fn.dataTable ) {
19680
+ $ = require('datatables.net')(root, $).$;
19681
+ }
19682
+
19683
+ return factory( $, root, root.document );
19684
+ };
19685
+ }
19686
+ else {
19687
+ // Browser
19688
+ factory( jQuery, window, document );
19689
+ }
19690
+ }(function( $, window, document, undefined ) {
19691
+ 'use strict';
19692
+ var DataTable = $.fn.dataTable;
19693
+ var _firefoxScroll;
19694
+
19695
+ /**
19696
+ * When making use of DataTables' x-axis scrolling feature, you may wish to
19697
+ * fix the left most column in place. This plug-in for DataTables provides
19698
+ * exactly this option (note for non-scrolling tables, please use the
19699
+ * FixedHeader plug-in, which can fix headers and footers). Key
19700
+ * features include:
19701
+ *
19702
+ * * Freezes the left or right most columns to the side of the table
19703
+ * * Option to freeze two or more columns
19704
+ * * Full integration with DataTables' scrolling options
19705
+ * * Speed - FixedColumns is fast in its operation
19706
+ *
19707
+ * @class
19708
+ * @constructor
19709
+ * @global
19710
+ * @param {object} dt DataTables instance. With DataTables 1.10 this can also
19711
+ * be a jQuery collection, a jQuery selector, DataTables API instance or
19712
+ * settings object.
19713
+ * @param {object} [init={}] Configuration object for FixedColumns. Options are
19714
+ * defined by {@link FixedColumns.defaults}
19715
+ *
19716
+ * @requires jQuery 1.7+
19717
+ * @requires DataTables 1.8.0+
19718
+ *
19719
+ * @example
19720
+ * var table = $('#example').dataTable( {
19721
+ * "scrollX": "100%"
19722
+ * } );
19723
+ * new $.fn.dataTable.fixedColumns( table );
19724
+ */
19725
+ var FixedColumns = function ( dt, init ) {
19726
+ var that = this;
19727
+
19728
+ /* Sanity check - you just know it will happen */
19729
+ if ( ! ( this instanceof FixedColumns ) ) {
19730
+ alert( "FixedColumns warning: FixedColumns must be initialised with the 'new' keyword." );
19731
+ return;
19732
+ }
19733
+
19734
+ if ( init === undefined || init === true ) {
19735
+ init = {};
19736
+ }
19737
+
19738
+ // Use the DataTables Hungarian notation mapping method, if it exists to
19739
+ // provide forwards compatibility for camel case variables
19740
+ var camelToHungarian = $.fn.dataTable.camelToHungarian;
19741
+ if ( camelToHungarian ) {
19742
+ camelToHungarian( FixedColumns.defaults, FixedColumns.defaults, true );
19743
+ camelToHungarian( FixedColumns.defaults, init );
19744
+ }
19745
+
19746
+ // v1.10 allows the settings object to be got form a number of sources
19747
+ var dtSettings = new $.fn.dataTable.Api( dt ).settings()[0];
19748
+
19749
+ /**
19750
+ * Settings object which contains customisable information for FixedColumns instance
19751
+ * @namespace
19752
+ * @extends FixedColumns.defaults
19753
+ * @private
19754
+ */
19755
+ this.s = {
19756
+ /**
19757
+ * DataTables settings objects
19758
+ * @type object
19759
+ * @default Obtained from DataTables instance
19760
+ */
19761
+ "dt": dtSettings,
19762
+
19763
+ /**
19764
+ * Number of columns in the DataTable - stored for quick access
19765
+ * @type int
19766
+ * @default Obtained from DataTables instance
19767
+ */
19768
+ "iTableColumns": dtSettings.aoColumns.length,
19769
+
19770
+ /**
19771
+ * Original outer widths of the columns as rendered by DataTables - used to calculate
19772
+ * the FixedColumns grid bounding box
19773
+ * @type array.<int>
19774
+ * @default []
19775
+ */
19776
+ "aiOuterWidths": [],
19777
+
19778
+ /**
19779
+ * Original inner widths of the columns as rendered by DataTables - used to apply widths
19780
+ * to the columns
19781
+ * @type array.<int>
19782
+ * @default []
19783
+ */
19784
+ "aiInnerWidths": [],
19785
+
19786
+
19787
+ /**
19788
+ * Is the document layout right-to-left
19789
+ * @type boolean
19790
+ */
19791
+ rtl: $(dtSettings.nTable).css('direction') === 'rtl'
19792
+ };
19793
+
19794
+
19795
+ /**
19796
+ * DOM elements used by the class instance
19797
+ * @namespace
19798
+ * @private
19799
+ *
19800
+ */
19801
+ this.dom = {
19802
+ /**
19803
+ * DataTables scrolling element
19804
+ * @type node
19805
+ * @default null
19806
+ */
19807
+ "scroller": null,
19808
+
19809
+ /**
19810
+ * DataTables header table
19811
+ * @type node
19812
+ * @default null
19813
+ */
19814
+ "header": null,
19815
+
19816
+ /**
19817
+ * DataTables body table
19818
+ * @type node
19819
+ * @default null
19820
+ */
19821
+ "body": null,
19822
+
19823
+ /**
19824
+ * DataTables footer table
19825
+ * @type node
19826
+ * @default null
19827
+ */
19828
+ "footer": null,
19829
+
19830
+ /**
19831
+ * Display grid elements
19832
+ * @namespace
19833
+ */
19834
+ "grid": {
19835
+ /**
19836
+ * Grid wrapper. This is the container element for the 3x3 grid
19837
+ * @type node
19838
+ * @default null
19839
+ */
19840
+ "wrapper": null,
19841
+
19842
+ /**
19843
+ * DataTables scrolling element. This element is the DataTables
19844
+ * component in the display grid (making up the main table - i.e.
19845
+ * not the fixed columns).
19846
+ * @type node
19847
+ * @default null
19848
+ */
19849
+ "dt": null,
19850
+
19851
+ /**
19852
+ * Left fixed column grid components
19853
+ * @namespace
19854
+ */
19855
+ "left": {
19856
+ "wrapper": null,
19857
+ "head": null,
19858
+ "body": null,
19859
+ "foot": null
19860
+ },
19861
+
19862
+ /**
19863
+ * Right fixed column grid components
19864
+ * @namespace
19865
+ */
19866
+ "right": {
19867
+ "wrapper": null,
19868
+ "head": null,
19869
+ "body": null,
19870
+ "foot": null
19871
+ }
19872
+ },
19873
+
19874
+ /**
19875
+ * Cloned table nodes
19876
+ * @namespace
19877
+ */
19878
+ "clone": {
19879
+ /**
19880
+ * Left column cloned table nodes
19881
+ * @namespace
19882
+ */
19883
+ "left": {
19884
+ /**
19885
+ * Cloned header table
19886
+ * @type node
19887
+ * @default null
19888
+ */
19889
+ "header": null,
19890
+
19891
+ /**
19892
+ * Cloned body table
19893
+ * @type node
19894
+ * @default null
19895
+ */
19896
+ "body": null,
19897
+
19898
+ /**
19899
+ * Cloned footer table
19900
+ * @type node
19901
+ * @default null
19902
+ */
19903
+ "footer": null
19904
+ },
19905
+
19906
+ /**
19907
+ * Right column cloned table nodes
19908
+ * @namespace
19909
+ */
19910
+ "right": {
19911
+ /**
19912
+ * Cloned header table
19913
+ * @type node
19914
+ * @default null
19915
+ */
19916
+ "header": null,
19917
+
19918
+ /**
19919
+ * Cloned body table
19920
+ * @type node
19921
+ * @default null
19922
+ */
19923
+ "body": null,
19924
+
19925
+ /**
19926
+ * Cloned footer table
19927
+ * @type node
19928
+ * @default null
19929
+ */
19930
+ "footer": null
19931
+ }
19932
+ }
19933
+ };
19934
+
19935
+ if ( dtSettings._oFixedColumns ) {
19936
+ throw 'FixedColumns already initialised on this table';
19937
+ }
19938
+
19939
+ /* Attach the instance to the DataTables instance so it can be accessed easily */
19940
+ dtSettings._oFixedColumns = this;
19941
+
19942
+ /* Let's do it */
19943
+ if ( ! dtSettings._bInitComplete )
19944
+ {
19945
+ dtSettings.oApi._fnCallbackReg( dtSettings, 'aoInitComplete', function () {
19946
+ that._fnConstruct( init );
19947
+ }, 'FixedColumns' );
19948
+ }
19949
+ else
19950
+ {
19951
+ this._fnConstruct( init );
19952
+ }
19953
+ };
19954
+
19955
+
19956
+
19957
+ $.extend( FixedColumns.prototype , {
19958
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
19959
+ * Public methods
19960
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
19961
+
19962
+ /**
19963
+ * Update the fixed columns - including headers and footers. Note that FixedColumns will
19964
+ * automatically update the display whenever the host DataTable redraws.
19965
+ * @returns {void}
19966
+ * @example
19967
+ * var table = $('#example').dataTable( {
19968
+ * "scrollX": "100%"
19969
+ * } );
19970
+ * var fc = new $.fn.dataTable.fixedColumns( table );
19971
+ *
19972
+ * // at some later point when the table has been manipulated....
19973
+ * fc.fnUpdate();
19974
+ */
19975
+ "fnUpdate": function ()
19976
+ {
19977
+ this._fnDraw( true );
19978
+ },
19979
+
19980
+
19981
+ /**
19982
+ * Recalculate the resizes of the 3x3 grid that FixedColumns uses for display of the table.
19983
+ * This is useful if you update the width of the table container. Note that FixedColumns will
19984
+ * perform this function automatically when the window.resize event is fired.
19985
+ * @returns {void}
19986
+ * @example
19987
+ * var table = $('#example').dataTable( {
19988
+ * "scrollX": "100%"
19989
+ * } );
19990
+ * var fc = new $.fn.dataTable.fixedColumns( table );
19991
+ *
19992
+ * // Resize the table container and then have FixedColumns adjust its layout....
19993
+ * $('#content').width( 1200 );
19994
+ * fc.fnRedrawLayout();
19995
+ */
19996
+ "fnRedrawLayout": function ()
19997
+ {
19998
+ this._fnColCalc();
19999
+ this._fnGridLayout();
20000
+ this.fnUpdate();
20001
+ },
20002
+
20003
+
20004
+ /**
20005
+ * Mark a row such that it's height should be recalculated when using 'semiauto' row
20006
+ * height matching. This function will have no effect when 'none' or 'auto' row height
20007
+ * matching is used.
20008
+ * @param {Node} nTr TR element that should have it's height recalculated
20009
+ * @returns {void}
20010
+ * @example
20011
+ * var table = $('#example').dataTable( {
20012
+ * "scrollX": "100%"
20013
+ * } );
20014
+ * var fc = new $.fn.dataTable.fixedColumns( table );
20015
+ *
20016
+ * // manipulate the table - mark the row as needing an update then update the table
20017
+ * // this allows the redraw performed by DataTables fnUpdate to recalculate the row
20018
+ * // height
20019
+ * fc.fnRecalculateHeight();
20020
+ * table.fnUpdate( $('#example tbody tr:eq(0)')[0], ["insert date", 1, 2, 3 ... ]);
20021
+ */
20022
+ "fnRecalculateHeight": function ( nTr )
20023
+ {
20024
+ delete nTr._DTTC_iHeight;
20025
+ nTr.style.height = 'auto';
20026
+ },
20027
+
20028
+
20029
+ /**
20030
+ * Set the height of a given row - provides cross browser compatibility
20031
+ * @param {Node} nTarget TR element that should have it's height recalculated
20032
+ * @param {int} iHeight Height in pixels to set
20033
+ * @returns {void}
20034
+ * @example
20035
+ * var table = $('#example').dataTable( {
20036
+ * "scrollX": "100%"
20037
+ * } );
20038
+ * var fc = new $.fn.dataTable.fixedColumns( table );
20039
+ *
20040
+ * // You may want to do this after manipulating a row in the fixed column
20041
+ * fc.fnSetRowHeight( $('#example tbody tr:eq(0)')[0], 50 );
20042
+ */
20043
+ "fnSetRowHeight": function ( nTarget, iHeight )
20044
+ {
20045
+ nTarget.style.height = iHeight+"px";
20046
+ },
20047
+
20048
+
20049
+ /**
20050
+ * Get data index information about a row or cell in the table body.
20051
+ * This function is functionally identical to fnGetPosition in DataTables,
20052
+ * taking the same parameter (TH, TD or TR node) and returning exactly the
20053
+ * the same information (data index information). THe difference between
20054
+ * the two is that this method takes into account the fixed columns in the
20055
+ * table, so you can pass in nodes from the master table, or the cloned
20056
+ * tables and get the index position for the data in the main table.
20057
+ * @param {node} node TR, TH or TD element to get the information about
20058
+ * @returns {int} If nNode is given as a TR, then a single index is
20059
+ * returned, or if given as a cell, an array of [row index, column index
20060
+ * (visible), column index (all)] is given.
20061
+ */
20062
+ "fnGetPosition": function ( node )
20063
+ {
20064
+ var idx;
20065
+ var inst = this.s.dt.oInstance;
20066
+
20067
+ if ( ! $(node).parents('.DTFC_Cloned').length )
20068
+ {
20069
+ // Not in a cloned table
20070
+ return inst.fnGetPosition( node );
20071
+ }
20072
+ else
20073
+ {
20074
+ // Its in the cloned table, so need to look up position
20075
+ if ( node.nodeName.toLowerCase() === 'tr' ) {
20076
+ idx = $(node).index();
20077
+ return inst.fnGetPosition( $('tr', this.s.dt.nTBody)[ idx ] );
20078
+ }
20079
+ else
20080
+ {
20081
+ var colIdx = $(node).index();
20082
+ idx = $(node.parentNode).index();
20083
+ var row = inst.fnGetPosition( $('tr', this.s.dt.nTBody)[ idx ] );
20084
+
20085
+ return [
20086
+ row,
20087
+ colIdx,
20088
+ inst.oApi._fnVisibleToColumnIndex( this.s.dt, colIdx )
20089
+ ];
20090
+ }
20091
+ }
20092
+ },
20093
+
20094
+
20095
+
20096
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
20097
+ * Private methods (they are of course public in JS, but recommended as private)
20098
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
20099
+
20100
+ /**
20101
+ * Initialisation for FixedColumns
20102
+ * @param {Object} oInit User settings for initialisation
20103
+ * @returns {void}
20104
+ * @private
20105
+ */
20106
+ "_fnConstruct": function ( oInit )
20107
+ {
20108
+ var i, iLen, iWidth,
20109
+ that = this;
20110
+
20111
+ /* Sanity checking */
20112
+ if ( typeof this.s.dt.oInstance.fnVersionCheck != 'function' ||
20113
+ this.s.dt.oInstance.fnVersionCheck( '1.8.0' ) !== true )
20114
+ {
20115
+ alert( "FixedColumns "+FixedColumns.VERSION+" required DataTables 1.8.0 or later. "+
20116
+ "Please upgrade your DataTables installation" );
20117
+ return;
20118
+ }
20119
+
20120
+ if ( this.s.dt.oScroll.sX === "" )
20121
+ {
20122
+ this.s.dt.oInstance.oApi._fnLog( this.s.dt, 1, "FixedColumns is not needed (no "+
20123
+ "x-scrolling in DataTables enabled), so no action will be taken. Use 'FixedHeader' for "+
20124
+ "column fixing when scrolling is not enabled" );
20125
+ return;
20126
+ }
20127
+
20128
+ /* Apply the settings from the user / defaults */
20129
+ this.s = $.extend( true, this.s, FixedColumns.defaults, oInit );
20130
+
20131
+ /* Set up the DOM as we need it and cache nodes */
20132
+ var classes = this.s.dt.oClasses;
20133
+ this.dom.grid.dt = $(this.s.dt.nTable).parents('div.'+classes.sScrollWrapper)[0];
20134
+ this.dom.scroller = $('div.'+classes.sScrollBody, this.dom.grid.dt )[0];
20135
+
20136
+ /* Set up the DOM that we want for the fixed column layout grid */
20137
+ this._fnColCalc();
20138
+ this._fnGridSetup();
20139
+
20140
+ /* Event handlers */
20141
+ var mouseController;
20142
+ var mouseDown = false;
20143
+
20144
+ // When the mouse is down (drag scroll) the mouse controller cannot
20145
+ // change, as the browser keeps the original element as the scrolling one
20146
+ $(this.s.dt.nTableWrapper).on( 'mousedown.DTFC', function (e) {
20147
+ if ( e.button === 0 ) {
20148
+ mouseDown = true;
20149
+
20150
+ $(document).one( 'mouseup', function () {
20151
+ mouseDown = false;
20152
+ } );
20153
+ }
20154
+ } );
20155
+
20156
+ // When the body is scrolled - scroll the left and right columns
20157
+ $(this.dom.scroller)
20158
+ .on( 'mouseover.DTFC touchstart.DTFC', function () {
20159
+ if ( ! mouseDown ) {
20160
+ mouseController = 'main';
20161
+ }
20162
+ } )
20163
+ .on( 'scroll.DTFC', function (e) {
20164
+ if ( ! mouseController && e.originalEvent ) {
20165
+ mouseController = 'main';
20166
+ }
20167
+
20168
+ if ( mouseController === 'main' ) {
20169
+ if ( that.s.iLeftColumns > 0 ) {
20170
+ that.dom.grid.left.liner.scrollTop = that.dom.scroller.scrollTop;
20171
+ }
20172
+ if ( that.s.iRightColumns > 0 ) {
20173
+ that.dom.grid.right.liner.scrollTop = that.dom.scroller.scrollTop;
20174
+ }
20175
+ }
20176
+ } );
20177
+
20178
+ var wheelType = 'onwheel' in document.createElement('div') ?
20179
+ 'wheel.DTFC' :
20180
+ 'mousewheel.DTFC';
20181
+
20182
+ if ( that.s.iLeftColumns > 0 ) {
20183
+ // When scrolling the left column, scroll the body and right column
20184
+ $(that.dom.grid.left.liner)
20185
+ .on( 'mouseover.DTFC touchstart.DTFC', function () {
20186
+ if ( ! mouseDown ) {
20187
+ mouseController = 'left';
20188
+ }
20189
+ } )
20190
+ .on( 'scroll.DTFC', function ( e ) {
20191
+ if ( ! mouseController && e.originalEvent ) {
20192
+ mouseController = 'left';
20193
+ }
20194
+
20195
+ if ( mouseController === 'left' ) {
20196
+ that.dom.scroller.scrollTop = that.dom.grid.left.liner.scrollTop;
20197
+ if ( that.s.iRightColumns > 0 ) {
20198
+ that.dom.grid.right.liner.scrollTop = that.dom.grid.left.liner.scrollTop;
20199
+ }
20200
+ }
20201
+ } )
20202
+ .on( wheelType, function(e) {
20203
+ // Pass horizontal scrolling through
20204
+ var xDelta = e.type === 'wheel' ?
20205
+ -e.originalEvent.deltaX :
20206
+ e.originalEvent.wheelDeltaX;
20207
+ that.dom.scroller.scrollLeft -= xDelta;
20208
+ } );
20209
+ }
20210
+
20211
+ if ( that.s.iRightColumns > 0 ) {
20212
+ // When scrolling the right column, scroll the body and the left column
20213
+ $(that.dom.grid.right.liner)
20214
+ .on( 'mouseover.DTFC touchstart.DTFC', function () {
20215
+ if ( ! mouseDown ) {
20216
+ mouseController = 'right';
20217
+ }
20218
+ } )
20219
+ .on( 'scroll.DTFC', function ( e ) {
20220
+ if ( ! mouseController && e.originalEvent ) {
20221
+ mouseController = 'right';
20222
+ }
20223
+
20224
+ if ( mouseController === 'right' ) {
20225
+ that.dom.scroller.scrollTop = that.dom.grid.right.liner.scrollTop;
20226
+ if ( that.s.iLeftColumns > 0 ) {
20227
+ that.dom.grid.left.liner.scrollTop = that.dom.grid.right.liner.scrollTop;
20228
+ }
20229
+ }
20230
+ } )
20231
+ .on( wheelType, function(e) {
20232
+ // Pass horizontal scrolling through
20233
+ var xDelta = e.type === 'wheel' ?
20234
+ -e.originalEvent.deltaX :
20235
+ e.originalEvent.wheelDeltaX;
20236
+ that.dom.scroller.scrollLeft -= xDelta;
20237
+ } );
20238
+ }
20239
+
20240
+ $(window).on( 'resize.DTFC', function () {
20241
+ that._fnGridLayout.call( that );
20242
+ } );
20243
+
20244
+ var bFirstDraw = true;
20245
+ var jqTable = $(this.s.dt.nTable);
20246
+
20247
+ jqTable
20248
+ .on( 'draw.dt.DTFC', function () {
20249
+ that._fnColCalc();
20250
+ that._fnDraw.call( that, bFirstDraw );
20251
+ bFirstDraw = false;
20252
+ } )
20253
+ .on( 'column-sizing.dt.DTFC', function () {
20254
+ that._fnColCalc();
20255
+ that._fnGridLayout( that );
20256
+ } )
20257
+ .on( 'column-visibility.dt.DTFC', function ( e, settings, column, vis, recalc ) {
20258
+ if ( recalc === undefined || recalc ) {
20259
+ that._fnColCalc();
20260
+ that._fnGridLayout( that );
20261
+ that._fnDraw( true );
20262
+ }
20263
+ } )
20264
+ .on( 'select.dt.DTFC deselect.dt.DTFC', function ( e, dt, type, indexes ) {
20265
+ if ( e.namespace === 'dt' ) {
20266
+ that._fnDraw( false );
20267
+ }
20268
+ } )
20269
+ .on( 'destroy.dt.DTFC', function () {
20270
+ jqTable.off( '.DTFC' );
20271
+
20272
+ $(that.dom.scroller).off( '.DTFC' );
20273
+ $(window).off( '.DTFC' );
20274
+ $(that.s.dt.nTableWrapper).off( '.DTFC' );
20275
+
20276
+ $(that.dom.grid.left.liner).off( '.DTFC '+wheelType );
20277
+ $(that.dom.grid.left.wrapper).remove();
20278
+
20279
+ $(that.dom.grid.right.liner).off( '.DTFC '+wheelType );
20280
+ $(that.dom.grid.right.wrapper).remove();
20281
+ } );
20282
+
20283
+ /* Get things right to start with - note that due to adjusting the columns, there must be
20284
+ * another redraw of the main table. It doesn't need to be a full redraw however.
20285
+ */
20286
+ this._fnGridLayout();
20287
+ this.s.dt.oInstance.fnDraw(false);
20288
+ },
20289
+
20290
+
20291
+ /**
20292
+ * Calculate the column widths for the grid layout
20293
+ * @returns {void}
20294
+ * @private
20295
+ */
20296
+ "_fnColCalc": function ()
20297
+ {
20298
+ var that = this;
20299
+ var iLeftWidth = 0;
20300
+ var iRightWidth = 0;
20301
+
20302
+ this.s.aiInnerWidths = [];
20303
+ this.s.aiOuterWidths = [];
20304
+
20305
+ $.each( this.s.dt.aoColumns, function (i, col) {
20306
+ var th = $(col.nTh);
20307
+ var border;
20308
+
20309
+ if ( ! th.filter(':visible').length ) {
20310
+ that.s.aiInnerWidths.push( 0 );
20311
+ that.s.aiOuterWidths.push( 0 );
20312
+ }
20313
+ else
20314
+ {
20315
+ // Inner width is used to assign widths to cells
20316
+ // Outer width is used to calculate the container
20317
+ var iWidth = th.outerWidth();
20318
+
20319
+ // When working with the left most-cell, need to add on the
20320
+ // table's border to the outerWidth, since we need to take
20321
+ // account of it, but it isn't in any cell
20322
+ if ( that.s.aiOuterWidths.length === 0 ) {
20323
+ border = $(that.s.dt.nTable).css('border-left-width');
20324
+ iWidth += typeof border === 'string' && border.indexOf('px') === -1 ?
20325
+ 1 :
20326
+ parseInt( border, 10 );
20327
+ }
20328
+
20329
+ // Likewise with the final column on the right
20330
+ if ( that.s.aiOuterWidths.length === that.s.dt.aoColumns.length-1 ) {
20331
+ border = $(that.s.dt.nTable).css('border-right-width');
20332
+ iWidth += typeof border === 'string' && border.indexOf('px') === -1 ?
20333
+ 1 :
20334
+ parseInt( border, 10 );
20335
+ }
20336
+
20337
+ that.s.aiOuterWidths.push( iWidth );
20338
+ that.s.aiInnerWidths.push( th.width() );
20339
+
20340
+ if ( i < that.s.iLeftColumns )
20341
+ {
20342
+ iLeftWidth += iWidth;
20343
+ }
20344
+
20345
+ if ( that.s.iTableColumns-that.s.iRightColumns <= i )
20346
+ {
20347
+ iRightWidth += iWidth;
20348
+ }
20349
+ }
20350
+ } );
20351
+
20352
+ this.s.iLeftWidth = iLeftWidth;
20353
+ this.s.iRightWidth = iRightWidth;
20354
+ },
20355
+
20356
+
20357
+ /**
20358
+ * Set up the DOM for the fixed column. The way the layout works is to create a 1x3 grid
20359
+ * for the left column, the DataTable (for which we just reuse the scrolling element DataTable
20360
+ * puts into the DOM) and the right column. In each of he two fixed column elements there is a
20361
+ * grouping wrapper element and then a head, body and footer wrapper. In each of these we then
20362
+ * place the cloned header, body or footer tables. This effectively gives as 3x3 grid structure.
20363
+ * @returns {void}
20364
+ * @private
20365
+ */
20366
+ "_fnGridSetup": function ()
20367
+ {
20368
+ var that = this;
20369
+ var oOverflow = this._fnDTOverflow();
20370
+ var block;
20371
+
20372
+ this.dom.body = this.s.dt.nTable;
20373
+ this.dom.header = this.s.dt.nTHead.parentNode;
20374
+ this.dom.header.parentNode.parentNode.style.position = "relative";
20375
+
20376
+ var nSWrapper =
20377
+ $('<div class="DTFC_ScrollWrapper" style="position:relative; clear:both;">'+
20378
+ '<div class="DTFC_LeftWrapper" style="position:absolute; top:0; left:0;" aria-hidden="true">'+
20379
+ '<div class="DTFC_LeftHeadWrapper" style="position:relative; top:0; left:0; overflow:hidden;"></div>'+
20380
+ '<div class="DTFC_LeftBodyWrapper" style="position:relative; top:0; left:0; overflow:hidden;">'+
20381
+ '<div class="DTFC_LeftBodyLiner" style="position:relative; top:0; left:0; overflow-y:scroll;"></div>'+
20382
+ '</div>'+
20383
+ '<div class="DTFC_LeftFootWrapper" style="position:relative; top:0; left:0; overflow:hidden;"></div>'+
20384
+ '</div>'+
20385
+ '<div class="DTFC_RightWrapper" style="position:absolute; top:0; right:0;" aria-hidden="true">'+
20386
+ '<div class="DTFC_RightHeadWrapper" style="position:relative; top:0; left:0;">'+
20387
+ '<div class="DTFC_RightHeadBlocker DTFC_Blocker" style="position:absolute; top:0; bottom:0;"></div>'+
20388
+ '</div>'+
20389
+ '<div class="DTFC_RightBodyWrapper" style="position:relative; top:0; left:0; overflow:hidden;">'+
20390
+ '<div class="DTFC_RightBodyLiner" style="position:relative; top:0; left:0; overflow-y:scroll;"></div>'+
20391
+ '</div>'+
20392
+ '<div class="DTFC_RightFootWrapper" style="position:relative; top:0; left:0;">'+
20393
+ '<div class="DTFC_RightFootBlocker DTFC_Blocker" style="position:absolute; top:0; bottom:0;"></div>'+
20394
+ '</div>'+
20395
+ '</div>'+
20396
+ '</div>')[0];
20397
+ var nLeft = nSWrapper.childNodes[0];
20398
+ var nRight = nSWrapper.childNodes[1];
20399
+
20400
+ this.dom.grid.dt.parentNode.insertBefore( nSWrapper, this.dom.grid.dt );
20401
+ nSWrapper.appendChild( this.dom.grid.dt );
20402
+
20403
+ this.dom.grid.wrapper = nSWrapper;
20404
+
20405
+ if ( this.s.iLeftColumns > 0 )
20406
+ {
20407
+ this.dom.grid.left.wrapper = nLeft;
20408
+ this.dom.grid.left.head = nLeft.childNodes[0];
20409
+ this.dom.grid.left.body = nLeft.childNodes[1];
20410
+ this.dom.grid.left.liner = $('div.DTFC_LeftBodyLiner', nSWrapper)[0];
20411
+
20412
+ nSWrapper.appendChild( nLeft );
20413
+ }
20414
+
20415
+ if ( this.s.iRightColumns > 0 )
20416
+ {
20417
+ this.dom.grid.right.wrapper = nRight;
20418
+ this.dom.grid.right.head = nRight.childNodes[0];
20419
+ this.dom.grid.right.body = nRight.childNodes[1];
20420
+ this.dom.grid.right.liner = $('div.DTFC_RightBodyLiner', nSWrapper)[0];
20421
+
20422
+ nRight.style.right = oOverflow.bar+"px";
20423
+
20424
+ block = $('div.DTFC_RightHeadBlocker', nSWrapper)[0];
20425
+ block.style.width = oOverflow.bar+"px";
20426
+ block.style.right = -oOverflow.bar+"px";
20427
+ this.dom.grid.right.headBlock = block;
20428
+
20429
+ block = $('div.DTFC_RightFootBlocker', nSWrapper)[0];
20430
+ block.style.width = oOverflow.bar+"px";
20431
+ block.style.right = -oOverflow.bar+"px";
20432
+ this.dom.grid.right.footBlock = block;
20433
+
20434
+ nSWrapper.appendChild( nRight );
20435
+ }
20436
+
20437
+ if ( this.s.dt.nTFoot )
20438
+ {
20439
+ this.dom.footer = this.s.dt.nTFoot.parentNode;
20440
+ if ( this.s.iLeftColumns > 0 )
20441
+ {
20442
+ this.dom.grid.left.foot = nLeft.childNodes[2];
20443
+ }
20444
+ if ( this.s.iRightColumns > 0 )
20445
+ {
20446
+ this.dom.grid.right.foot = nRight.childNodes[2];
20447
+ }
20448
+ }
20449
+
20450
+ // RTL support - swap the position of the left and right columns (#48)
20451
+ if ( this.s.rtl ) {
20452
+ $('div.DTFC_RightHeadBlocker', nSWrapper).css( {
20453
+ left: -oOverflow.bar+'px',
20454
+ right: ''
20455
+ } );
20456
+ }
20457
+ },
20458
+
20459
+
20460
+ /**
20461
+ * Style and position the grid used for the FixedColumns layout
20462
+ * @returns {void}
20463
+ * @private
20464
+ */
20465
+ "_fnGridLayout": function ()
20466
+ {
20467
+ var that = this;
20468
+ var oGrid = this.dom.grid;
20469
+ var iWidth = $(oGrid.wrapper).width();
20470
+ var iBodyHeight = this.s.dt.nTable.parentNode.offsetHeight;
20471
+ var iFullHeight = this.s.dt.nTable.parentNode.parentNode.offsetHeight;
20472
+ var oOverflow = this._fnDTOverflow();
20473
+ var iLeftWidth = this.s.iLeftWidth;
20474
+ var iRightWidth = this.s.iRightWidth;
20475
+ var rtl = $(this.dom.body).css('direction') === 'rtl';
20476
+ var wrapper;
20477
+ var scrollbarAdjust = function ( node, width ) {
20478
+ if ( ! oOverflow.bar ) {
20479
+ // If there is no scrollbar (Macs) we need to hide the auto scrollbar
20480
+ node.style.width = (width+20)+"px";
20481
+ node.style.paddingRight = "20px";
20482
+ node.style.boxSizing = "border-box";
20483
+ }
20484
+ else if ( that._firefoxScrollError() ) {
20485
+ // See the above function for why this is required
20486
+ if ( $(node).height() > 34 ) {
20487
+ node.style.width = (width+oOverflow.bar)+"px";
20488
+ }
20489
+ }
20490
+ else {
20491
+ // Otherwise just overflow by the scrollbar
20492
+ node.style.width = (width+oOverflow.bar)+"px";
20493
+ }
20494
+ };
20495
+
20496
+ // When x scrolling - don't paint the fixed columns over the x scrollbar
20497
+ if ( oOverflow.x )
20498
+ {
20499
+ iBodyHeight -= oOverflow.bar;
20500
+ }
20501
+
20502
+ oGrid.wrapper.style.height = iFullHeight+"px";
20503
+
20504
+ if ( this.s.iLeftColumns > 0 )
20505
+ {
20506
+ wrapper = oGrid.left.wrapper;
20507
+ wrapper.style.width = iLeftWidth+'px';
20508
+ wrapper.style.height = '1px';
20509
+
20510
+ // Swap the position of the left and right columns for rtl (#48)
20511
+ // This is always up against the edge, scrollbar on the far side
20512
+ if ( rtl ) {
20513
+ wrapper.style.left = '';
20514
+ wrapper.style.right = 0;
20515
+ }
20516
+ else {
20517
+ wrapper.style.left = 0;
20518
+ wrapper.style.right = '';
20519
+ }
20520
+
20521
+ oGrid.left.body.style.height = iBodyHeight+"px";
20522
+ if ( oGrid.left.foot ) {
20523
+ oGrid.left.foot.style.top = (oOverflow.x ? oOverflow.bar : 0)+"px"; // shift footer for scrollbar
20524
+ }
20525
+
20526
+ scrollbarAdjust( oGrid.left.liner, iLeftWidth );
20527
+ oGrid.left.liner.style.height = iBodyHeight+"px";
20528
+ oGrid.left.liner.style.maxHeight = iBodyHeight+"px";
20529
+ }
20530
+
20531
+ if ( this.s.iRightColumns > 0 )
20532
+ {
20533
+ wrapper = oGrid.right.wrapper;
20534
+ wrapper.style.width = iRightWidth+'px';
20535
+ wrapper.style.height = '1px';
20536
+
20537
+ // Need to take account of the vertical scrollbar
20538
+ if ( this.s.rtl ) {
20539
+ wrapper.style.left = oOverflow.y ? oOverflow.bar+'px' : 0;
20540
+ wrapper.style.right = '';
20541
+ }
20542
+ else {
20543
+ wrapper.style.left = '';
20544
+ wrapper.style.right = oOverflow.y ? oOverflow.bar+'px' : 0;
20545
+ }
20546
+
20547
+ oGrid.right.body.style.height = iBodyHeight+"px";
20548
+ if ( oGrid.right.foot ) {
20549
+ oGrid.right.foot.style.top = (oOverflow.x ? oOverflow.bar : 0)+"px";
20550
+ }
20551
+
20552
+ scrollbarAdjust( oGrid.right.liner, iRightWidth );
20553
+ oGrid.right.liner.style.height = iBodyHeight+"px";
20554
+ oGrid.right.liner.style.maxHeight = iBodyHeight+"px";
20555
+
20556
+ oGrid.right.headBlock.style.display = oOverflow.y ? 'block' : 'none';
20557
+ oGrid.right.footBlock.style.display = oOverflow.y ? 'block' : 'none';
20558
+ }
20559
+ },
20560
+
20561
+
20562
+ /**
20563
+ * Get information about the DataTable's scrolling state - specifically if the table is scrolling
20564
+ * on either the x or y axis, and also the scrollbar width.
20565
+ * @returns {object} Information about the DataTables scrolling state with the properties:
20566
+ * 'x', 'y' and 'bar'
20567
+ * @private
20568
+ */
20569
+ "_fnDTOverflow": function ()
20570
+ {
20571
+ var nTable = this.s.dt.nTable;
20572
+ var nTableScrollBody = nTable.parentNode;
20573
+ var out = {
20574
+ "x": false,
20575
+ "y": false,
20576
+ "bar": this.s.dt.oScroll.iBarWidth
20577
+ };
20578
+
20579
+ if ( nTable.offsetWidth > nTableScrollBody.clientWidth )
20580
+ {
20581
+ out.x = true;
20582
+ }
20583
+
20584
+ if ( nTable.offsetHeight > nTableScrollBody.clientHeight )
20585
+ {
20586
+ out.y = true;
20587
+ }
20588
+
20589
+ return out;
20590
+ },
20591
+
20592
+
20593
+ /**
20594
+ * Clone and position the fixed columns
20595
+ * @returns {void}
20596
+ * @param {Boolean} bAll Indicate if the header and footer should be updated as well (true)
20597
+ * @private
20598
+ */
20599
+ "_fnDraw": function ( bAll )
20600
+ {
20601
+ this._fnGridLayout();
20602
+ this._fnCloneLeft( bAll );
20603
+ this._fnCloneRight( bAll );
20604
+
20605
+ /* Draw callback function */
20606
+ if ( this.s.fnDrawCallback !== null )
20607
+ {
20608
+ this.s.fnDrawCallback.call( this, this.dom.clone.left, this.dom.clone.right );
20609
+ }
20610
+
20611
+ /* Event triggering */
20612
+ $(this).trigger( 'draw.dtfc', {
20613
+ "leftClone": this.dom.clone.left,
20614
+ "rightClone": this.dom.clone.right
20615
+ } );
20616
+ },
20617
+
20618
+
20619
+ /**
20620
+ * Clone the right columns
20621
+ * @returns {void}
20622
+ * @param {Boolean} bAll Indicate if the header and footer should be updated as well (true)
20623
+ * @private
20624
+ */
20625
+ "_fnCloneRight": function ( bAll )
20626
+ {
20627
+ if ( this.s.iRightColumns <= 0 ) {
20628
+ return;
20629
+ }
20630
+
20631
+ var that = this,
20632
+ i, jq,
20633
+ aiColumns = [];
20634
+
20635
+ for ( i=this.s.iTableColumns-this.s.iRightColumns ; i<this.s.iTableColumns ; i++ ) {
20636
+ if ( this.s.dt.aoColumns[i].bVisible ) {
20637
+ aiColumns.push( i );
20638
+ }
20639
+ }
20640
+
20641
+ this._fnClone( this.dom.clone.right, this.dom.grid.right, aiColumns, bAll );
20642
+ },
20643
+
20644
+
20645
+ /**
20646
+ * Clone the left columns
20647
+ * @returns {void}
20648
+ * @param {Boolean} bAll Indicate if the header and footer should be updated as well (true)
20649
+ * @private
20650
+ */
20651
+ "_fnCloneLeft": function ( bAll )
20652
+ {
20653
+ if ( this.s.iLeftColumns <= 0 ) {
20654
+ return;
20655
+ }
20656
+
20657
+ var that = this,
20658
+ i, jq,
20659
+ aiColumns = [];
20660
+
20661
+ for ( i=0 ; i<this.s.iLeftColumns ; i++ ) {
20662
+ if ( this.s.dt.aoColumns[i].bVisible ) {
20663
+ aiColumns.push( i );
20664
+ }
20665
+ }
20666
+
20667
+ this._fnClone( this.dom.clone.left, this.dom.grid.left, aiColumns, bAll );
20668
+ },
20669
+
20670
+
20671
+ /**
20672
+ * Make a copy of the layout object for a header or footer element from DataTables. Note that
20673
+ * this method will clone the nodes in the layout object.
20674
+ * @returns {Array} Copy of the layout array
20675
+ * @param {Object} aoOriginal Layout array from DataTables (aoHeader or aoFooter)
20676
+ * @param {Object} aiColumns Columns to copy
20677
+ * @param {boolean} events Copy cell events or not
20678
+ * @private
20679
+ */
20680
+ "_fnCopyLayout": function ( aoOriginal, aiColumns, events )
20681
+ {
20682
+ var aReturn = [];
20683
+ var aClones = [];
20684
+ var aCloned = [];
20685
+
20686
+ for ( var i=0, iLen=aoOriginal.length ; i<iLen ; i++ )
20687
+ {
20688
+ var aRow = [];
20689
+ aRow.nTr = $(aoOriginal[i].nTr).clone(events, false)[0];
20690
+
20691
+ for ( var j=0, jLen=this.s.iTableColumns ; j<jLen ; j++ )
20692
+ {
20693
+ if ( $.inArray( j, aiColumns ) === -1 )
20694
+ {
20695
+ continue;
20696
+ }
20697
+
20698
+ var iCloned = $.inArray( aoOriginal[i][j].cell, aCloned );
20699
+ if ( iCloned === -1 )
20700
+ {
20701
+ var nClone = $(aoOriginal[i][j].cell).clone(events, false)[0];
20702
+ aClones.push( nClone );
20703
+ aCloned.push( aoOriginal[i][j].cell );
20704
+
20705
+ aRow.push( {
20706
+ "cell": nClone,
20707
+ "unique": aoOriginal[i][j].unique
20708
+ } );
20709
+ }
20710
+ else
20711
+ {
20712
+ aRow.push( {
20713
+ "cell": aClones[ iCloned ],
20714
+ "unique": aoOriginal[i][j].unique
20715
+ } );
20716
+ }
20717
+ }
20718
+
20719
+ aReturn.push( aRow );
20720
+ }
20721
+
20722
+ return aReturn;
20723
+ },
20724
+
20725
+
20726
+ /**
20727
+ * Clone the DataTable nodes and place them in the DOM (sized correctly)
20728
+ * @returns {void}
20729
+ * @param {Object} oClone Object containing the header, footer and body cloned DOM elements
20730
+ * @param {Object} oGrid Grid object containing the display grid elements for the cloned
20731
+ * column (left or right)
20732
+ * @param {Array} aiColumns Column indexes which should be operated on from the DataTable
20733
+ * @param {Boolean} bAll Indicate if the header and footer should be updated as well (true)
20734
+ * @private
20735
+ */
20736
+ "_fnClone": function ( oClone, oGrid, aiColumns, bAll )
20737
+ {
20738
+ var that = this,
20739
+ i, iLen, j, jLen, jq, nTarget, iColumn, nClone, iIndex, aoCloneLayout,
20740
+ jqCloneThead, aoFixedHeader,
20741
+ dt = this.s.dt;
20742
+
20743
+ /*
20744
+ * Header
20745
+ */
20746
+ if ( bAll )
20747
+ {
20748
+ $(oClone.header).remove();
20749
+
20750
+ oClone.header = $(this.dom.header).clone(true, false)[0];
20751
+ oClone.header.className += " DTFC_Cloned";
20752
+ oClone.header.style.width = "100%";
20753
+ oGrid.head.appendChild( oClone.header );
20754
+
20755
+ /* Copy the DataTables layout cache for the header for our floating column */
20756
+ aoCloneLayout = this._fnCopyLayout( dt.aoHeader, aiColumns, true );
20757
+ jqCloneThead = $('>thead', oClone.header);
20758
+ jqCloneThead.empty();
20759
+
20760
+ /* Add the created cloned TR elements to the table */
20761
+ for ( i=0, iLen=aoCloneLayout.length ; i<iLen ; i++ )
20762
+ {
20763
+ jqCloneThead[0].appendChild( aoCloneLayout[i].nTr );
20764
+ }
20765
+
20766
+ /* Use the handy _fnDrawHead function in DataTables to do the rowspan/colspan
20767
+ * calculations for us
20768
+ */
20769
+ dt.oApi._fnDrawHead( dt, aoCloneLayout, true );
20770
+ }
20771
+ else
20772
+ {
20773
+ /* To ensure that we copy cell classes exactly, regardless of colspan, multiple rows
20774
+ * etc, we make a copy of the header from the DataTable again, but don't insert the
20775
+ * cloned cells, just copy the classes across. To get the matching layout for the
20776
+ * fixed component, we use the DataTables _fnDetectHeader method, allowing 1:1 mapping
20777
+ */
20778
+ aoCloneLayout = this._fnCopyLayout( dt.aoHeader, aiColumns, false );
20779
+ aoFixedHeader=[];
20780
+
20781
+ dt.oApi._fnDetectHeader( aoFixedHeader, $('>thead', oClone.header)[0] );
20782
+
20783
+ for ( i=0, iLen=aoCloneLayout.length ; i<iLen ; i++ )
20784
+ {
20785
+ for ( j=0, jLen=aoCloneLayout[i].length ; j<jLen ; j++ )
20786
+ {
20787
+ aoFixedHeader[i][j].cell.className = aoCloneLayout[i][j].cell.className;
20788
+
20789
+ // If jQuery UI theming is used we need to copy those elements as well
20790
+ $('span.DataTables_sort_icon', aoFixedHeader[i][j].cell).each( function () {
20791
+ this.className = $('span.DataTables_sort_icon', aoCloneLayout[i][j].cell)[0].className;
20792
+ } );
20793
+ }
20794
+ }
20795
+ }
20796
+ this._fnEqualiseHeights( 'thead', this.dom.header, oClone.header );
20797
+
20798
+ /*
20799
+ * Body
20800
+ */
20801
+ if ( this.s.sHeightMatch == 'auto' )
20802
+ {
20803
+ /* Remove any heights which have been applied already and let the browser figure it out */
20804
+ $('>tbody>tr', that.dom.body).css('height', 'auto');
20805
+ }
20806
+
20807
+ if ( oClone.body !== null )
20808
+ {
20809
+ $(oClone.body).remove();
20810
+ oClone.body = null;
20811
+ }
20812
+
20813
+ oClone.body = $(this.dom.body).clone(true)[0];
20814
+ oClone.body.className += " DTFC_Cloned";
20815
+ oClone.body.style.paddingBottom = dt.oScroll.iBarWidth+"px";
20816
+ oClone.body.style.marginBottom = (dt.oScroll.iBarWidth*2)+"px"; /* For IE */
20817
+ if ( oClone.body.getAttribute('id') !== null )
20818
+ {
20819
+ oClone.body.removeAttribute('id');
20820
+ }
20821
+
20822
+ $('>thead>tr', oClone.body).empty();
20823
+ $('>tfoot', oClone.body).remove();
20824
+
20825
+ var nBody = $('tbody', oClone.body)[0];
20826
+ $(nBody).empty();
20827
+ if ( dt.aiDisplay.length > 0 )
20828
+ {
20829
+ /* Copy the DataTables' header elements to force the column width in exactly the
20830
+ * same way that DataTables does it - have the header element, apply the width and
20831
+ * colapse it down
20832
+ */
20833
+ var nInnerThead = $('>thead>tr', oClone.body)[0];
20834
+ for ( iIndex=0 ; iIndex<aiColumns.length ; iIndex++ )
20835
+ {
20836
+ iColumn = aiColumns[iIndex];
20837
+
20838
+ nClone = $(dt.aoColumns[iColumn].nTh).clone(true)[0];
20839
+ nClone.innerHTML = "";
20840
+
20841
+ var oStyle = nClone.style;
20842
+ oStyle.paddingTop = "0";
20843
+ oStyle.paddingBottom = "0";
20844
+ oStyle.borderTopWidth = "0";
20845
+ oStyle.borderBottomWidth = "0";
20846
+ oStyle.height = 0;
20847
+ oStyle.width = that.s.aiInnerWidths[iColumn]+"px";
20848
+
20849
+ nInnerThead.appendChild( nClone );
20850
+ }
20851
+
20852
+ /* Add in the tbody elements, cloning form the master table */
20853
+ $('>tbody>tr', that.dom.body).each( function (z) {
20854
+ var i = that.s.dt.oFeatures.bServerSide===false ?
20855
+ that.s.dt.aiDisplay[ that.s.dt._iDisplayStart+z ] : z;
20856
+ var aTds = that.s.dt.aoData[ i ].anCells || $(this).children('td, th');
20857
+
20858
+ var n = this.cloneNode(false);
20859
+ n.removeAttribute('id');
20860
+ n.setAttribute( 'data-dt-row', i );
20861
+
20862
+ for ( iIndex=0 ; iIndex<aiColumns.length ; iIndex++ )
20863
+ {
20864
+ iColumn = aiColumns[iIndex];
20865
+
20866
+ if ( aTds.length > 0 )
20867
+ {
20868
+ nClone = $( aTds[iColumn] ).clone(true, true)[0];
20869
+ nClone.removeAttribute( 'id' );
20870
+ nClone.setAttribute( 'data-dt-row', i );
20871
+ nClone.setAttribute( 'data-dt-column', dt.oApi._fnVisibleToColumnIndex( dt, iColumn ) );
20872
+ n.appendChild( nClone );
20873
+ }
20874
+ }
20875
+ nBody.appendChild( n );
20876
+ } );
20877
+ }
20878
+ else
20879
+ {
20880
+ $('>tbody>tr', that.dom.body).each( function (z) {
20881
+ nClone = this.cloneNode(true);
20882
+ nClone.className += ' DTFC_NoData';
20883
+ $('td', nClone).html('');
20884
+ nBody.appendChild( nClone );
20885
+ } );
20886
+ }
20887
+
20888
+ oClone.body.style.width = "100%";
20889
+ oClone.body.style.margin = "0";
20890
+ oClone.body.style.padding = "0";
20891
+
20892
+ // Interop with Scroller - need to use a height forcing element in the
20893
+ // scrolling area in the same way that Scroller does in the body scroll.
20894
+ if ( dt.oScroller !== undefined )
20895
+ {
20896
+ var scrollerForcer = dt.oScroller.dom.force;
20897
+
20898
+ if ( ! oGrid.forcer ) {
20899
+ oGrid.forcer = scrollerForcer.cloneNode( true );
20900
+ oGrid.liner.appendChild( oGrid.forcer );
20901
+ }
20902
+ else {
20903
+ oGrid.forcer.style.height = scrollerForcer.style.height;
20904
+ }
20905
+ }
20906
+
20907
+ oGrid.liner.appendChild( oClone.body );
20908
+
20909
+ this._fnEqualiseHeights( 'tbody', that.dom.body, oClone.body );
20910
+
20911
+ /*
20912
+ * Footer
20913
+ */
20914
+ if ( dt.nTFoot !== null )
20915
+ {
20916
+ if ( bAll )
20917
+ {
20918
+ if ( oClone.footer !== null )
20919
+ {
20920
+ oClone.footer.parentNode.removeChild( oClone.footer );
20921
+ }
20922
+ oClone.footer = $(this.dom.footer).clone(true, true)[0];
20923
+ oClone.footer.className += " DTFC_Cloned";
20924
+ oClone.footer.style.width = "100%";
20925
+ oGrid.foot.appendChild( oClone.footer );
20926
+
20927
+ /* Copy the footer just like we do for the header */
20928
+ aoCloneLayout = this._fnCopyLayout( dt.aoFooter, aiColumns, true );
20929
+ var jqCloneTfoot = $('>tfoot', oClone.footer);
20930
+ jqCloneTfoot.empty();
20931
+
20932
+ for ( i=0, iLen=aoCloneLayout.length ; i<iLen ; i++ )
20933
+ {
20934
+ jqCloneTfoot[0].appendChild( aoCloneLayout[i].nTr );
20935
+ }
20936
+ dt.oApi._fnDrawHead( dt, aoCloneLayout, true );
20937
+ }
20938
+ else
20939
+ {
20940
+ aoCloneLayout = this._fnCopyLayout( dt.aoFooter, aiColumns, false );
20941
+ var aoCurrFooter=[];
20942
+
20943
+ dt.oApi._fnDetectHeader( aoCurrFooter, $('>tfoot', oClone.footer)[0] );
20944
+
20945
+ for ( i=0, iLen=aoCloneLayout.length ; i<iLen ; i++ )
20946
+ {
20947
+ for ( j=0, jLen=aoCloneLayout[i].length ; j<jLen ; j++ )
20948
+ {
20949
+ aoCurrFooter[i][j].cell.className = aoCloneLayout[i][j].cell.className;
20950
+ }
20951
+ }
20952
+ }
20953
+ this._fnEqualiseHeights( 'tfoot', this.dom.footer, oClone.footer );
20954
+ }
20955
+
20956
+ /* Equalise the column widths between the header footer and body - body get's priority */
20957
+ var anUnique = dt.oApi._fnGetUniqueThs( dt, $('>thead', oClone.header)[0] );
20958
+ $(anUnique).each( function (i) {
20959
+ iColumn = aiColumns[i];
20960
+ this.style.width = that.s.aiInnerWidths[iColumn]+"px";
20961
+ } );
20962
+
20963
+ if ( that.s.dt.nTFoot !== null )
20964
+ {
20965
+ anUnique = dt.oApi._fnGetUniqueThs( dt, $('>tfoot', oClone.footer)[0] );
20966
+ $(anUnique).each( function (i) {
20967
+ iColumn = aiColumns[i];
20968
+ this.style.width = that.s.aiInnerWidths[iColumn]+"px";
20969
+ } );
20970
+ }
20971
+ },
20972
+
20973
+
20974
+ /**
20975
+ * From a given table node (THEAD etc), get a list of TR direct child elements
20976
+ * @param {Node} nIn Table element to search for TR elements (THEAD, TBODY or TFOOT element)
20977
+ * @returns {Array} List of TR elements found
20978
+ * @private
20979
+ */
20980
+ "_fnGetTrNodes": function ( nIn )
20981
+ {
20982
+ var aOut = [];
20983
+ for ( var i=0, iLen=nIn.childNodes.length ; i<iLen ; i++ )
20984
+ {
20985
+ if ( nIn.childNodes[i].nodeName.toUpperCase() == "TR" )
20986
+ {
20987
+ aOut.push( nIn.childNodes[i] );
20988
+ }
20989
+ }
20990
+ return aOut;
20991
+ },
20992
+
20993
+
20994
+ /**
20995
+ * Equalise the heights of the rows in a given table node in a cross browser way
20996
+ * @returns {void}
20997
+ * @param {String} nodeName Node type - thead, tbody or tfoot
20998
+ * @param {Node} original Original node to take the heights from
20999
+ * @param {Node} clone Copy the heights to
21000
+ * @private
21001
+ */
21002
+ "_fnEqualiseHeights": function ( nodeName, original, clone )
21003
+ {
21004
+ if ( this.s.sHeightMatch == 'none' && nodeName !== 'thead' && nodeName !== 'tfoot' )
21005
+ {
21006
+ return;
21007
+ }
21008
+
21009
+ var that = this,
21010
+ i, iLen, iHeight, iHeight2, iHeightOriginal, iHeightClone,
21011
+ rootOriginal = original.getElementsByTagName(nodeName)[0],
21012
+ rootClone = clone.getElementsByTagName(nodeName)[0],
21013
+ jqBoxHack = $('>'+nodeName+'>tr:eq(0)', original).children(':first'),
21014
+ iBoxHack = jqBoxHack.outerHeight() - jqBoxHack.height(),
21015
+ anOriginal = this._fnGetTrNodes( rootOriginal ),
21016
+ anClone = this._fnGetTrNodes( rootClone ),
21017
+ heights = [];
21018
+
21019
+ for ( i=0, iLen=anClone.length ; i<iLen ; i++ )
21020
+ {
21021
+ iHeightOriginal = anOriginal[i].offsetHeight;
21022
+ iHeightClone = anClone[i].offsetHeight;
21023
+ iHeight = iHeightClone > iHeightOriginal ? iHeightClone : iHeightOriginal;
21024
+
21025
+ if ( this.s.sHeightMatch == 'semiauto' )
21026
+ {
21027
+ anOriginal[i]._DTTC_iHeight = iHeight;
21028
+ }
21029
+
21030
+ heights.push( iHeight );
21031
+ }
21032
+
21033
+ for ( i=0, iLen=anClone.length ; i<iLen ; i++ )
21034
+ {
21035
+ anClone[i].style.height = heights[i]+"px";
21036
+ anOriginal[i].style.height = heights[i]+"px";
21037
+ }
21038
+ },
21039
+
21040
+ /**
21041
+ * Determine if the UA suffers from Firefox's overflow:scroll scrollbars
21042
+ * not being shown bug.
21043
+ *
21044
+ * Firefox doesn't draw scrollbars, even if it is told to using
21045
+ * overflow:scroll, if the div is less than 34px height. See bugs 292284 and
21046
+ * 781885. Using UA detection here since this is particularly hard to detect
21047
+ * using objects - its a straight up rendering error in Firefox.
21048
+ *
21049
+ * @return {boolean} True if Firefox error is present, false otherwise
21050
+ */
21051
+ _firefoxScrollError: function () {
21052
+ if ( _firefoxScroll === undefined ) {
21053
+ var test = $('<div/>')
21054
+ .css( {
21055
+ position: 'absolute',
21056
+ top: 0,
21057
+ left: 0,
21058
+ height: 10,
21059
+ width: 50,
21060
+ overflow: 'scroll'
21061
+ } )
21062
+ .appendTo( 'body' );
21063
+
21064
+ // Make sure this doesn't apply on Macs with 0 width scrollbars
21065
+ _firefoxScroll = (
21066
+ test[0].clientWidth === test[0].offsetWidth && this._fnDTOverflow().bar !== 0
21067
+ );
21068
+
21069
+ test.remove();
21070
+ }
21071
+
21072
+ return _firefoxScroll;
21073
+ }
21074
+ } );
21075
+
21076
+
21077
+
21078
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
21079
+ * Statics
21080
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
21081
+
21082
+ /**
21083
+ * FixedColumns default settings for initialisation
21084
+ * @name FixedColumns.defaults
21085
+ * @namespace
21086
+ * @static
21087
+ */
21088
+ FixedColumns.defaults = /** @lends FixedColumns.defaults */{
21089
+ /**
21090
+ * Number of left hand columns to fix in position
21091
+ * @type int
21092
+ * @default 1
21093
+ * @static
21094
+ * @example
21095
+ * var = $('#example').dataTable( {
21096
+ * "scrollX": "100%"
21097
+ * } );
21098
+ * new $.fn.dataTable.fixedColumns( table, {
21099
+ * "leftColumns": 2
21100
+ * } );
21101
+ */
21102
+ "iLeftColumns": 1,
21103
+
21104
+ /**
21105
+ * Number of right hand columns to fix in position
21106
+ * @type int
21107
+ * @default 0
21108
+ * @static
21109
+ * @example
21110
+ * var table = $('#example').dataTable( {
21111
+ * "scrollX": "100%"
21112
+ * } );
21113
+ * new $.fn.dataTable.fixedColumns( table, {
21114
+ * "rightColumns": 1
21115
+ * } );
21116
+ */
21117
+ "iRightColumns": 0,
21118
+
21119
+ /**
21120
+ * Draw callback function which is called when FixedColumns has redrawn the fixed assets
21121
+ * @type function(object, object):void
21122
+ * @default null
21123
+ * @static
21124
+ * @example
21125
+ * var table = $('#example').dataTable( {
21126
+ * "scrollX": "100%"
21127
+ * } );
21128
+ * new $.fn.dataTable.fixedColumns( table, {
21129
+ * "drawCallback": function () {
21130
+ * alert( "FixedColumns redraw" );
21131
+ * }
21132
+ * } );
21133
+ */
21134
+ "fnDrawCallback": null,
21135
+
21136
+ /**
21137
+ * Height matching algorthim to use. This can be "none" which will result in no height
21138
+ * matching being applied by FixedColumns (height matching could be forced by CSS in this
21139
+ * case), "semiauto" whereby the height calculation will be performed once, and the result
21140
+ * cached to be used again (fnRecalculateHeight can be used to force recalculation), or
21141
+ * "auto" when height matching is performed on every draw (slowest but must accurate)
21142
+ * @type string
21143
+ * @default semiauto
21144
+ * @static
21145
+ * @example
21146
+ * var table = $('#example').dataTable( {
21147
+ * "scrollX": "100%"
21148
+ * } );
21149
+ * new $.fn.dataTable.fixedColumns( table, {
21150
+ * "heightMatch": "auto"
21151
+ * } );
21152
+ */
21153
+ "sHeightMatch": "semiauto"
21154
+ };
21155
+
21156
+
21157
+
21158
+
21159
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
21160
+ * Constants
21161
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
21162
+
21163
+ /**
21164
+ * FixedColumns version
21165
+ * @name FixedColumns.version
21166
+ * @type String
21167
+ * @default See code
21168
+ * @static
21169
+ */
21170
+ FixedColumns.version = "3.2.4";
21171
+
21172
+
21173
+
21174
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
21175
+ * DataTables API integration
21176
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
21177
+
21178
+ DataTable.Api.register( 'fixedColumns()', function () {
21179
+ return this;
21180
+ } );
21181
+
21182
+ DataTable.Api.register( 'fixedColumns().update()', function () {
21183
+ return this.iterator( 'table', function ( ctx ) {
21184
+ if ( ctx._oFixedColumns ) {
21185
+ ctx._oFixedColumns.fnUpdate();
21186
+ }
21187
+ } );
21188
+ } );
21189
+
21190
+ DataTable.Api.register( 'fixedColumns().relayout()', function () {
21191
+ return this.iterator( 'table', function ( ctx ) {
21192
+ if ( ctx._oFixedColumns ) {
21193
+ ctx._oFixedColumns.fnRedrawLayout();
21194
+ }
21195
+ } );
21196
+ } );
21197
+
21198
+ DataTable.Api.register( 'rows().recalcHeight()', function () {
21199
+ return this.iterator( 'row', function ( ctx, idx ) {
21200
+ if ( ctx._oFixedColumns ) {
21201
+ ctx._oFixedColumns.fnRecalculateHeight( this.row(idx).node() );
21202
+ }
21203
+ } );
21204
+ } );
21205
+
21206
+ DataTable.Api.register( 'fixedColumns().rowIndex()', function ( row ) {
21207
+ row = $(row);
21208
+
21209
+ return row.parents('.DTFC_Cloned').length ?
21210
+ this.rows( { page: 'current' } ).indexes()[ row.index() ] :
21211
+ this.row( row ).index();
21212
+ } );
21213
+
21214
+ DataTable.Api.register( 'fixedColumns().cellIndex()', function ( cell ) {
21215
+ cell = $(cell);
21216
+
21217
+ if ( cell.parents('.DTFC_Cloned').length ) {
21218
+ var rowClonedIdx = cell.parent().index();
21219
+ var rowIdx = this.rows( { page: 'current' } ).indexes()[ rowClonedIdx ];
21220
+ var columnIdx;
21221
+
21222
+ if ( cell.parents('.DTFC_LeftWrapper').length ) {
21223
+ columnIdx = cell.index();
21224
+ }
21225
+ else {
21226
+ var columns = this.columns().flatten().length;
21227
+ columnIdx = columns - this.context[0]._oFixedColumns.s.iRightColumns + cell.index();
21228
+ }
21229
+
21230
+ return {
21231
+ row: rowIdx,
21232
+ column: this.column.index( 'toData', columnIdx ),
21233
+ columnVisible: columnIdx
21234
+ };
21235
+ }
21236
+ else {
21237
+ return this.cell( cell ).index();
21238
+ }
21239
+ } );
21240
+
21241
+
21242
+
21243
+
21244
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
21245
+ * Initialisation
21246
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
21247
+
21248
+ // Attach a listener to the document which listens for DataTables initialisation
21249
+ // events so we can automatically initialise
21250
+ $(document).on( 'init.dt.fixedColumns', function (e, settings) {
21251
+ if ( e.namespace !== 'dt' ) {
21252
+ return;
21253
+ }
21254
+
21255
+ var init = settings.oInit.fixedColumns;
21256
+ var defaults = DataTable.defaults.fixedColumns;
21257
+
21258
+ if ( init || defaults ) {
21259
+ var opts = $.extend( {}, init, defaults );
21260
+
21261
+ if ( init !== false ) {
21262
+ new FixedColumns( settings, opts );
21263
+ }
21264
+ }
21265
+ } );
21266
+
21267
+
21268
+
21269
+ // Make FixedColumns accessible from the DataTables instance
21270
+ $.fn.dataTable.FixedColumns = FixedColumns;
21271
+ $.fn.DataTable.FixedColumns = FixedColumns;
21272
+
21273
+ return FixedColumns;
21274
+ }));
21275
+
21276
+
21277
+ /*! FixedHeader 3.1.3
21278
+ * ©2009-2017 SpryMedia Ltd - datatables.net/license
21279
+ */
21280
+
21281
+ /**
21282
+ * @summary FixedHeader
21283
+ * @description Fix a table's header or footer, so it is always visible while
21284
+ * scrolling
21285
+ * @version 3.1.3
21286
+ * @file dataTables.fixedHeader.js
21287
+ * @author SpryMedia Ltd (www.sprymedia.co.uk)
21288
+ * @contact www.sprymedia.co.uk/contact
21289
+ * @copyright Copyright 2009-2017 SpryMedia Ltd.
21290
+ *
21291
+ * This source file is free software, available under the following license:
21292
+ * MIT license - http://datatables.net/license/mit
21293
+ *
21294
+ * This source file is distributed in the hope that it will be useful, but
21295
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
21296
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
21297
+ *
21298
+ * For details please refer to: http://www.datatables.net
21299
+ */
21300
+
21301
+ (function( factory ){
21302
+ if ( typeof define === 'function' && define.amd ) {
21303
+ // AMD
21304
+ define( ['jquery', 'datatables.net'], function ( $ ) {
21305
+ return factory( $, window, document );
21306
+ } );
21307
+ }
21308
+ else if ( typeof exports === 'object' ) {
21309
+ // CommonJS
21310
+ module.exports = function (root, $) {
21311
+ if ( ! root ) {
21312
+ root = window;
21313
+ }
21314
+
21315
+ if ( ! $ || ! $.fn.dataTable ) {
21316
+ $ = require('datatables.net')(root, $).$;
21317
+ }
21318
+
21319
+ return factory( $, root, root.document );
21320
+ };
21321
+ }
21322
+ else {
21323
+ // Browser
21324
+ factory( jQuery, window, document );
21325
+ }
21326
+ }(function( $, window, document, undefined ) {
21327
+ 'use strict';
21328
+ var DataTable = $.fn.dataTable;
21329
+
21330
+
21331
+ var _instCounter = 0;
21332
+
21333
+ var FixedHeader = function ( dt, config ) {
21334
+ // Sanity check - you just know it will happen
21335
+ if ( ! (this instanceof FixedHeader) ) {
21336
+ throw "FixedHeader must be initialised with the 'new' keyword.";
21337
+ }
21338
+
21339
+ // Allow a boolean true for defaults
21340
+ if ( config === true ) {
21341
+ config = {};
21342
+ }
21343
+
21344
+ dt = new DataTable.Api( dt );
21345
+
21346
+ this.c = $.extend( true, {}, FixedHeader.defaults, config );
21347
+
21348
+ this.s = {
21349
+ dt: dt,
21350
+ position: {
21351
+ theadTop: 0,
21352
+ tbodyTop: 0,
21353
+ tfootTop: 0,
21354
+ tfootBottom: 0,
21355
+ width: 0,
21356
+ left: 0,
21357
+ tfootHeight: 0,
21358
+ theadHeight: 0,
21359
+ windowHeight: $(window).height(),
21360
+ visible: true
21361
+ },
21362
+ headerMode: null,
21363
+ footerMode: null,
21364
+ autoWidth: dt.settings()[0].oFeatures.bAutoWidth,
21365
+ namespace: '.dtfc'+(_instCounter++),
21366
+ scrollLeft: {
21367
+ header: -1,
21368
+ footer: -1
21369
+ },
21370
+ enable: true
21371
+ };
21372
+
21373
+ this.dom = {
21374
+ floatingHeader: null,
21375
+ thead: $(dt.table().header()),
21376
+ tbody: $(dt.table().body()),
21377
+ tfoot: $(dt.table().footer()),
21378
+ header: {
21379
+ host: null,
21380
+ floating: null,
21381
+ placeholder: null
21382
+ },
21383
+ footer: {
21384
+ host: null,
21385
+ floating: null,
21386
+ placeholder: null
21387
+ }
21388
+ };
21389
+
21390
+ this.dom.header.host = this.dom.thead.parent();
21391
+ this.dom.footer.host = this.dom.tfoot.parent();
21392
+
21393
+ var dtSettings = dt.settings()[0];
21394
+ if ( dtSettings._fixedHeader ) {
21395
+ throw "FixedHeader already initialised on table "+dtSettings.nTable.id;
21396
+ }
21397
+
21398
+ dtSettings._fixedHeader = this;
21399
+
21400
+ this._constructor();
21401
+ };
21402
+
21403
+
21404
+ /*
21405
+ * Variable: FixedHeader
21406
+ * Purpose: Prototype for FixedHeader
21407
+ * Scope: global
21408
+ */
21409
+ $.extend( FixedHeader.prototype, {
21410
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
21411
+ * API methods
21412
+ */
21413
+
21414
+ /**
21415
+ * Enable / disable the fixed elements
21416
+ *
21417
+ * @param {boolean} enable `true` to enable, `false` to disable
21418
+ */
21419
+ enable: function ( enable )
21420
+ {
21421
+ this.s.enable = enable;
21422
+
21423
+ if ( this.c.header ) {
21424
+ this._modeChange( 'in-place', 'header', true );
21425
+ }
21426
+
21427
+ if ( this.c.footer && this.dom.tfoot.length ) {
21428
+ this._modeChange( 'in-place', 'footer', true );
21429
+ }
21430
+
21431
+ this.update();
21432
+ },
21433
+
21434
+ /**
21435
+ * Set header offset
21436
+ *
21437
+ * @param {int} new value for headerOffset
21438
+ */
21439
+ headerOffset: function ( offset )
21440
+ {
21441
+ if ( offset !== undefined ) {
21442
+ this.c.headerOffset = offset;
21443
+ this.update();
21444
+ }
21445
+
21446
+ return this.c.headerOffset;
21447
+ },
21448
+
21449
+ /**
21450
+ * Set footer offset
21451
+ *
21452
+ * @param {int} new value for footerOffset
21453
+ */
21454
+ footerOffset: function ( offset )
21455
+ {
21456
+ if ( offset !== undefined ) {
21457
+ this.c.footerOffset = offset;
21458
+ this.update();
21459
+ }
21460
+
21461
+ return this.c.footerOffset;
21462
+ },
21463
+
21464
+
21465
+ /**
21466
+ * Recalculate the position of the fixed elements and force them into place
21467
+ */
21468
+ update: function ()
21469
+ {
21470
+ this._positions();
21471
+ this._scroll( true );
21472
+ },
21473
+
21474
+
21475
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
21476
+ * Constructor
21477
+ */
21478
+
21479
+ /**
21480
+ * FixedHeader constructor - adding the required event listeners and
21481
+ * simple initialisation
21482
+ *
21483
+ * @private
21484
+ */
21485
+ _constructor: function ()
21486
+ {
21487
+ var that = this;
21488
+ var dt = this.s.dt;
21489
+
21490
+ $(window)
21491
+ .on( 'scroll'+this.s.namespace, function () {
21492
+ that._scroll();
21493
+ } )
21494
+ .on( 'resize'+this.s.namespace, function () {
21495
+ that.s.position.windowHeight = $(window).height();
21496
+ that.update();
21497
+ } );
21498
+
21499
+ var autoHeader = $('.fh-fixedHeader');
21500
+ if ( ! this.c.headerOffset && autoHeader.length ) {
21501
+ this.c.headerOffset = autoHeader.outerHeight();
21502
+ }
21503
+
21504
+ var autoFooter = $('.fh-fixedFooter');
21505
+ if ( ! this.c.footerOffset && autoFooter.length ) {
21506
+ this.c.footerOffset = autoFooter.outerHeight();
21507
+ }
21508
+
21509
+ dt.on( 'column-reorder.dt.dtfc column-visibility.dt.dtfc draw.dt.dtfc column-sizing.dt.dtfc', function () {
21510
+ that.update();
21511
+ } );
21512
+
21513
+ dt.on( 'destroy.dtfc', function () {
21514
+ dt.off( '.dtfc' );
21515
+ $(window).off( that.s.namespace );
21516
+ } );
21517
+
21518
+ this._positions();
21519
+ this._scroll();
21520
+ },
21521
+
21522
+
21523
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
21524
+ * Private methods
21525
+ */
21526
+
21527
+ /**
21528
+ * Clone a fixed item to act as a place holder for the original element
21529
+ * which is moved into a clone of the table element, and moved around the
21530
+ * document to give the fixed effect.
21531
+ *
21532
+ * @param {string} item 'header' or 'footer'
21533
+ * @param {boolean} force Force the clone to happen, or allow automatic
21534
+ * decision (reuse existing if available)
21535
+ * @private
21536
+ */
21537
+ _clone: function ( item, force )
21538
+ {
21539
+ var dt = this.s.dt;
21540
+ var itemDom = this.dom[ item ];
21541
+ var itemElement = item === 'header' ?
21542
+ this.dom.thead :
21543
+ this.dom.tfoot;
21544
+
21545
+ if ( ! force && itemDom.floating ) {
21546
+ // existing floating element - reuse it
21547
+ itemDom.floating.removeClass( 'fixedHeader-floating fixedHeader-locked' );
21548
+ }
21549
+ else {
21550
+ if ( itemDom.floating ) {
21551
+ itemDom.placeholder.remove();
21552
+ this._unsize( item );
21553
+ itemDom.floating.children().detach();
21554
+ itemDom.floating.remove();
21555
+ }
21556
+
21557
+ itemDom.floating = $( dt.table().node().cloneNode( false ) )
21558
+ .css( 'table-layout', 'fixed' )
21559
+ .removeAttr( 'id' )
21560
+ .append( itemElement )
21561
+ .appendTo( 'body' );
21562
+
21563
+ // Insert a fake thead/tfoot into the DataTable to stop it jumping around
21564
+ itemDom.placeholder = itemElement.clone( false )
21565
+ itemDom.placeholder
21566
+ .find( '*[id]' )
21567
+ .removeAttr( 'id' );
21568
+
21569
+ itemDom.host.prepend( itemDom.placeholder );
21570
+
21571
+ // Clone widths
21572
+ this._matchWidths( itemDom.placeholder, itemDom.floating );
21573
+ }
21574
+ },
21575
+
21576
+ /**
21577
+ * Copy widths from the cells in one element to another. This is required
21578
+ * for the footer as the footer in the main table takes its sizes from the
21579
+ * header columns. That isn't present in the footer so to have it still
21580
+ * align correctly, the sizes need to be copied over. It is also required
21581
+ * for the header when auto width is not enabled
21582
+ *
21583
+ * @param {jQuery} from Copy widths from
21584
+ * @param {jQuery} to Copy widths to
21585
+ * @private
21586
+ */
21587
+ _matchWidths: function ( from, to ) {
21588
+ var get = function ( name ) {
21589
+ return $(name, from)
21590
+ .map( function () {
21591
+ return $(this).width();
21592
+ } ).toArray();
21593
+ };
21594
+
21595
+ var set = function ( name, toWidths ) {
21596
+ $(name, to).each( function ( i ) {
21597
+ $(this).css( {
21598
+ width: toWidths[i],
21599
+ minWidth: toWidths[i]
21600
+ } );
21601
+ } );
21602
+ };
21603
+
21604
+ var thWidths = get( 'th' );
21605
+ var tdWidths = get( 'td' );
21606
+
21607
+ set( 'th', thWidths );
21608
+ set( 'td', tdWidths );
21609
+ },
21610
+
21611
+ /**
21612
+ * Remove assigned widths from the cells in an element. This is required
21613
+ * when inserting the footer back into the main table so the size is defined
21614
+ * by the header columns and also when auto width is disabled in the
21615
+ * DataTable.
21616
+ *
21617
+ * @param {string} item The `header` or `footer`
21618
+ * @private
21619
+ */
21620
+ _unsize: function ( item ) {
21621
+ var el = this.dom[ item ].floating;
21622
+
21623
+ if ( el && (item === 'footer' || (item === 'header' && ! this.s.autoWidth)) ) {
21624
+ $('th, td', el).css( {
21625
+ width: '',
21626
+ minWidth: ''
21627
+ } );
21628
+ }
21629
+ else if ( el && item === 'header' ) {
21630
+ $('th, td', el).css( 'min-width', '' );
21631
+ }
21632
+ },
21633
+
21634
+ /**
21635
+ * Reposition the floating elements to take account of horizontal page
21636
+ * scroll
21637
+ *
21638
+ * @param {string} item The `header` or `footer`
21639
+ * @param {int} scrollLeft Document scrollLeft
21640
+ * @private
21641
+ */
21642
+ _horizontal: function ( item, scrollLeft )
21643
+ {
21644
+ var itemDom = this.dom[ item ];
21645
+ var position = this.s.position;
21646
+ var lastScrollLeft = this.s.scrollLeft;
21647
+
21648
+ if ( itemDom.floating && lastScrollLeft[ item ] !== scrollLeft ) {
21649
+ itemDom.floating.css( 'left', position.left - scrollLeft );
21650
+
21651
+ lastScrollLeft[ item ] = scrollLeft;
21652
+ }
21653
+ },
21654
+
21655
+ /**
21656
+ * Change from one display mode to another. Each fixed item can be in one
21657
+ * of:
21658
+ *
21659
+ * * `in-place` - In the main DataTable
21660
+ * * `in` - Floating over the DataTable
21661
+ * * `below` - (Header only) Fixed to the bottom of the table body
21662
+ * * `above` - (Footer only) Fixed to the top of the table body
21663
+ *
21664
+ * @param {string} mode Mode that the item should be shown in
21665
+ * @param {string} item 'header' or 'footer'
21666
+ * @param {boolean} forceChange Force a redraw of the mode, even if already
21667
+ * in that mode.
21668
+ * @private
21669
+ */
21670
+ _modeChange: function ( mode, item, forceChange )
21671
+ {
21672
+ var dt = this.s.dt;
21673
+ var itemDom = this.dom[ item ];
21674
+ var position = this.s.position;
21675
+
21676
+ // Record focus. Browser's will cause input elements to loose focus if
21677
+ // they are inserted else where in the doc
21678
+ var tablePart = this.dom[ item==='footer' ? 'tfoot' : 'thead' ];
21679
+ var focus = $.contains( tablePart[0], document.activeElement ) ?
21680
+ document.activeElement :
21681
+ null;
21682
+
21683
+ if ( mode === 'in-place' ) {
21684
+ // Insert the header back into the table's real header
21685
+ if ( itemDom.placeholder ) {
21686
+ itemDom.placeholder.remove();
21687
+ itemDom.placeholder = null;
21688
+ }
21689
+
21690
+ this._unsize( item );
21691
+
21692
+ if ( item === 'header' ) {
21693
+ itemDom.host.prepend( this.dom.thead );
21694
+ }
21695
+ else {
21696
+ itemDom.host.append( this.dom.tfoot );
21697
+ }
21698
+
21699
+ if ( itemDom.floating ) {
21700
+ itemDom.floating.remove();
21701
+ itemDom.floating = null;
21702
+ }
21703
+ }
21704
+ else if ( mode === 'in' ) {
21705
+ // Remove the header from the read header and insert into a fixed
21706
+ // positioned floating table clone
21707
+ this._clone( item, forceChange );
21708
+
21709
+ itemDom.floating
21710
+ .addClass( 'fixedHeader-floating' )
21711
+ .css( item === 'header' ? 'top' : 'bottom', this.c[item+'Offset'] )
21712
+ .css( 'left', position.left+'px' )
21713
+ .css( 'width', position.width+'px' );
21714
+
21715
+ if ( item === 'footer' ) {
21716
+ itemDom.floating.css( 'top', '' );
21717
+ }
21718
+ }
21719
+ else if ( mode === 'below' ) { // only used for the header
21720
+ // Fix the position of the floating header at base of the table body
21721
+ this._clone( item, forceChange );
21722
+
21723
+ itemDom.floating
21724
+ .addClass( 'fixedHeader-locked' )
21725
+ .css( 'top', position.tfootTop - position.theadHeight )
21726
+ .css( 'left', position.left+'px' )
21727
+ .css( 'width', position.width+'px' );
21728
+ }
21729
+ else if ( mode === 'above' ) { // only used for the footer
21730
+ // Fix the position of the floating footer at top of the table body
21731
+ this._clone( item, forceChange );
21732
+
21733
+ itemDom.floating
21734
+ .addClass( 'fixedHeader-locked' )
21735
+ .css( 'top', position.tbodyTop )
21736
+ .css( 'left', position.left+'px' )
21737
+ .css( 'width', position.width+'px' );
21738
+ }
21739
+
21740
+ // Restore focus if it was lost
21741
+ if ( focus && focus !== document.activeElement ) {
21742
+ focus.focus();
21743
+ }
21744
+
21745
+ this.s.scrollLeft.header = -1;
21746
+ this.s.scrollLeft.footer = -1;
21747
+ this.s[item+'Mode'] = mode;
21748
+ },
21749
+
21750
+ /**
21751
+ * Cache the positional information that is required for the mode
21752
+ * calculations that FixedHeader performs.
21753
+ *
21754
+ * @private
21755
+ */
21756
+ _positions: function ()
21757
+ {
21758
+ var dt = this.s.dt;
21759
+ var table = dt.table();
21760
+ var position = this.s.position;
21761
+ var dom = this.dom;
21762
+ var tableNode = $(table.node());
21763
+
21764
+ // Need to use the header and footer that are in the main table,
21765
+ // regardless of if they are clones, since they hold the positions we
21766
+ // want to measure from
21767
+ var thead = tableNode.children('thead');
21768
+ var tfoot = tableNode.children('tfoot');
21769
+ var tbody = dom.tbody;
21770
+
21771
+ position.visible = tableNode.is(':visible');
21772
+ position.width = tableNode.outerWidth();
21773
+ position.left = tableNode.offset().left;
21774
+ position.theadTop = thead.offset().top;
21775
+ position.tbodyTop = tbody.offset().top;
21776
+ position.theadHeight = position.tbodyTop - position.theadTop;
21777
+
21778
+ if ( tfoot.length ) {
21779
+ position.tfootTop = tfoot.offset().top;
21780
+ position.tfootBottom = position.tfootTop + tfoot.outerHeight();
21781
+ position.tfootHeight = position.tfootBottom - position.tfootTop;
21782
+ }
21783
+ else {
21784
+ position.tfootTop = position.tbodyTop + tbody.outerHeight();
21785
+ position.tfootBottom = position.tfootTop;
21786
+ position.tfootHeight = position.tfootTop;
21787
+ }
21788
+ },
21789
+
21790
+
21791
+ /**
21792
+ * Mode calculation - determine what mode the fixed items should be placed
21793
+ * into.
21794
+ *
21795
+ * @param {boolean} forceChange Force a redraw of the mode, even if already
21796
+ * in that mode.
21797
+ * @private
21798
+ */
21799
+ _scroll: function ( forceChange )
21800
+ {
21801
+ var windowTop = $(document).scrollTop();
21802
+ var windowLeft = $(document).scrollLeft();
21803
+ var position = this.s.position;
21804
+ var headerMode, footerMode;
21805
+
21806
+ if ( ! this.s.enable ) {
21807
+ return;
21808
+ }
21809
+
21810
+ if ( this.c.header ) {
21811
+ if ( ! position.visible || windowTop <= position.theadTop - this.c.headerOffset ) {
21812
+ headerMode = 'in-place';
21813
+ }
21814
+ else if ( windowTop <= position.tfootTop - position.theadHeight - this.c.headerOffset ) {
21815
+ headerMode = 'in';
21816
+ }
21817
+ else {
21818
+ headerMode = 'below';
21819
+ }
21820
+
21821
+ if ( forceChange || headerMode !== this.s.headerMode ) {
21822
+ this._modeChange( headerMode, 'header', forceChange );
21823
+ }
21824
+
21825
+ this._horizontal( 'header', windowLeft );
21826
+ }
21827
+
21828
+ if ( this.c.footer && this.dom.tfoot.length ) {
21829
+ if ( ! position.visible || windowTop + position.windowHeight >= position.tfootBottom + this.c.footerOffset ) {
21830
+ footerMode = 'in-place';
21831
+ }
21832
+ else if ( position.windowHeight + windowTop > position.tbodyTop + position.tfootHeight + this.c.footerOffset ) {
21833
+ footerMode = 'in';
21834
+ }
21835
+ else {
21836
+ footerMode = 'above';
21837
+ }
21838
+
21839
+ if ( forceChange || footerMode !== this.s.footerMode ) {
21840
+ this._modeChange( footerMode, 'footer', forceChange );
21841
+ }
21842
+
21843
+ this._horizontal( 'footer', windowLeft );
21844
+ }
21845
+ }
21846
+ } );
21847
+
21848
+
21849
+ /**
21850
+ * Version
21851
+ * @type {String}
21852
+ * @static
21853
+ */
21854
+ FixedHeader.version = "3.1.3";
21855
+
21856
+ /**
21857
+ * Defaults
21858
+ * @type {Object}
21859
+ * @static
21860
+ */
21861
+ FixedHeader.defaults = {
21862
+ header: true,
21863
+ footer: false,
21864
+ headerOffset: 0,
21865
+ footerOffset: 0
21866
+ };
21867
+
21868
+
21869
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
21870
+ * DataTables interfaces
21871
+ */
21872
+
21873
+ // Attach for constructor access
21874
+ $.fn.dataTable.FixedHeader = FixedHeader;
21875
+ $.fn.DataTable.FixedHeader = FixedHeader;
21876
+
21877
+
21878
+ // DataTables creation - check if the FixedHeader option has been defined on the
21879
+ // table and if so, initialise
21880
+ $(document).on( 'init.dt.dtfh', function (e, settings, json) {
21881
+ if ( e.namespace !== 'dt' ) {
21882
+ return;
21883
+ }
21884
+
21885
+ var init = settings.oInit.fixedHeader;
21886
+ var defaults = DataTable.defaults.fixedHeader;
21887
+
21888
+ if ( (init || defaults) && ! settings._fixedHeader ) {
21889
+ var opts = $.extend( {}, defaults, init );
21890
+
21891
+ if ( init !== false ) {
21892
+ new FixedHeader( settings, opts );
21893
+ }
21894
+ }
21895
+ } );
21896
+
21897
+ // DataTables API methods
21898
+ DataTable.Api.register( 'fixedHeader()', function () {} );
21899
+
21900
+ DataTable.Api.register( 'fixedHeader.adjust()', function () {
21901
+ return this.iterator( 'table', function ( ctx ) {
21902
+ var fh = ctx._fixedHeader;
21903
+
21904
+ if ( fh ) {
21905
+ fh.update();
21906
+ }
21907
+ } );
21908
+ } );
21909
+
21910
+ DataTable.Api.register( 'fixedHeader.enable()', function ( flag ) {
21911
+ return this.iterator( 'table', function ( ctx ) {
21912
+ var fh = ctx._fixedHeader;
21913
+
21914
+ flag = ( flag !== undefined ? flag : true );
21915
+ if ( fh && flag !== fh.s.enable ) {
21916
+ fh.enable( flag );
21917
+ }
21918
+ } );
21919
+ } );
21920
+
21921
+ DataTable.Api.register( 'fixedHeader.disable()', function ( ) {
21922
+ return this.iterator( 'table', function ( ctx ) {
21923
+ var fh = ctx._fixedHeader;
21924
+
21925
+ if ( fh && fh.s.enable ) {
21926
+ fh.enable( false );
21927
+ }
21928
+ } );
21929
+ } );
21930
+
21931
+ $.each( ['header', 'footer'], function ( i, el ) {
21932
+ DataTable.Api.register( 'fixedHeader.'+el+'Offset()', function ( offset ) {
21933
+ var ctx = this.context;
21934
+
21935
+ if ( offset === undefined ) {
21936
+ return ctx.length && ctx[0]._fixedHeader ?
21937
+ ctx[0]._fixedHeader[el +'Offset']() :
21938
+ undefined;
21939
+ }
21940
+
21941
+ return this.iterator( 'table', function ( ctx ) {
21942
+ var fh = ctx._fixedHeader;
21943
+
21944
+ if ( fh ) {
21945
+ fh[ el +'Offset' ]( offset );
21946
+ }
21947
+ } );
21948
+ } );
21949
+ } );
21950
+
21951
+
21952
+ return FixedHeader;
21953
+ }));
21954
+
21955
+
21956
+ /*! KeyTable 2.3.2
21957
+ * ©2009-2017 SpryMedia Ltd - datatables.net/license
21958
+ */
21959
+
21960
+ /**
21961
+ * @summary KeyTable
21962
+ * @description Spreadsheet like keyboard navigation for DataTables
21963
+ * @version 2.3.2
21964
+ * @file dataTables.keyTable.js
21965
+ * @author SpryMedia Ltd (www.sprymedia.co.uk)
21966
+ * @contact www.sprymedia.co.uk/contact
21967
+ * @copyright Copyright 2009-2017 SpryMedia Ltd.
21968
+ *
21969
+ * This source file is free software, available under the following license:
21970
+ * MIT license - http://datatables.net/license/mit
21971
+ *
21972
+ * This source file is distributed in the hope that it will be useful, but
21973
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
21974
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
21975
+ *
21976
+ * For details please refer to: http://www.datatables.net
21977
+ */
21978
+
21979
+ (function( factory ){
21980
+ if ( typeof define === 'function' && define.amd ) {
21981
+ // AMD
21982
+ define( ['jquery', 'datatables.net'], function ( $ ) {
21983
+ return factory( $, window, document );
21984
+ } );
21985
+ }
21986
+ else if ( typeof exports === 'object' ) {
21987
+ // CommonJS
21988
+ module.exports = function (root, $) {
21989
+ if ( ! root ) {
21990
+ root = window;
21991
+ }
21992
+
21993
+ if ( ! $ || ! $.fn.dataTable ) {
21994
+ $ = require('datatables.net')(root, $).$;
21995
+ }
21996
+
21997
+ return factory( $, root, root.document );
21998
+ };
21999
+ }
22000
+ else {
22001
+ // Browser
22002
+ factory( jQuery, window, document );
22003
+ }
22004
+ }(function( $, window, document, undefined ) {
22005
+ 'use strict';
22006
+ var DataTable = $.fn.dataTable;
22007
+
22008
+
22009
+ var KeyTable = function ( dt, opts ) {
22010
+ // Sanity check that we are using DataTables 1.10 or newer
22011
+ if ( ! DataTable.versionCheck || ! DataTable.versionCheck( '1.10.8' ) ) {
22012
+ throw 'KeyTable requires DataTables 1.10.8 or newer';
22013
+ }
22014
+
22015
+ // User and defaults configuration object
22016
+ this.c = $.extend( true, {},
22017
+ DataTable.defaults.keyTable,
22018
+ KeyTable.defaults,
22019
+ opts
22020
+ );
22021
+
22022
+ // Internal settings
22023
+ this.s = {
22024
+ /** @type {DataTable.Api} DataTables' API instance */
22025
+ dt: new DataTable.Api( dt ),
22026
+
22027
+ enable: true,
22028
+
22029
+ /** @type {bool} Flag for if a draw is triggered by focus */
22030
+ focusDraw: false,
22031
+
22032
+ /** @type {bool} Flag to indicate when waiting for a draw to happen.
22033
+ * Will ignore key presses at this point
22034
+ */
22035
+ waitingForDraw: false,
22036
+
22037
+ /** @type {object} Information about the last cell that was focused */
22038
+ lastFocus: null
22039
+ };
22040
+
22041
+ // DOM items
22042
+ this.dom = {
22043
+
22044
+ };
22045
+
22046
+ // Check if row reorder has already been initialised on this table
22047
+ var settings = this.s.dt.settings()[0];
22048
+ var exisiting = settings.keytable;
22049
+ if ( exisiting ) {
22050
+ return exisiting;
22051
+ }
22052
+
22053
+ settings.keytable = this;
22054
+ this._constructor();
22055
+ };
22056
+
22057
+
22058
+ $.extend( KeyTable.prototype, {
22059
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
22060
+ * API methods for DataTables API interface
22061
+ */
22062
+
22063
+ /**
22064
+ * Blur the table's cell focus
22065
+ */
22066
+ blur: function ()
22067
+ {
22068
+ this._blur();
22069
+ },
22070
+
22071
+ /**
22072
+ * Enable cell focus for the table
22073
+ *
22074
+ * @param {string} state Can be `true`, `false` or `-string navigation-only`
22075
+ */
22076
+ enable: function ( state )
22077
+ {
22078
+ this.s.enable = state;
22079
+ },
22080
+
22081
+ /**
22082
+ * Focus on a cell
22083
+ * @param {integer} row Row index
22084
+ * @param {integer} column Column index
22085
+ */
22086
+ focus: function ( row, column )
22087
+ {
22088
+ this._focus( this.s.dt.cell( row, column ) );
22089
+ },
22090
+
22091
+ /**
22092
+ * Is the cell focused
22093
+ * @param {object} cell Cell index to check
22094
+ * @returns {boolean} true if focused, false otherwise
22095
+ */
22096
+ focused: function ( cell )
22097
+ {
22098
+ var lastFocus = this.s.lastFocus;
22099
+
22100
+ if ( ! lastFocus ) {
22101
+ return false;
22102
+ }
22103
+
22104
+ var lastIdx = this.s.lastFocus.cell.index();
22105
+ return cell.row === lastIdx.row && cell.column === lastIdx.column;
22106
+ },
22107
+
22108
+
22109
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
22110
+ * Constructor
22111
+ */
22112
+
22113
+ /**
22114
+ * Initialise the KeyTable instance
22115
+ *
22116
+ * @private
22117
+ */
22118
+ _constructor: function ()
22119
+ {
22120
+ this._tabInput();
22121
+
22122
+ var that = this;
22123
+ var dt = this.s.dt;
22124
+ var table = $( dt.table().node() );
22125
+
22126
+ // Need to be able to calculate the cell positions relative to the table
22127
+ if ( table.css('position') === 'static' ) {
22128
+ table.css( 'position', 'relative' );
22129
+ }
22130
+
22131
+ // Click to focus
22132
+ $( dt.table().body() ).on( 'click.keyTable', 'th, td', function (e) {
22133
+ if ( that.s.enable === false ) {
22134
+ return;
22135
+ }
22136
+
22137
+ var cell = dt.cell( this );
22138
+
22139
+ if ( ! cell.any() ) {
22140
+ return;
22141
+ }
22142
+
22143
+ that._focus( cell, null, false, e );
22144
+ } );
22145
+
22146
+ // Key events
22147
+ $( document ).on( 'keydown.keyTable', function (e) {
22148
+ that._key( e );
22149
+ } );
22150
+
22151
+ // Click blur
22152
+ if ( this.c.blurable ) {
22153
+ $( document ).on( 'mousedown.keyTable', function ( e ) {
22154
+ // Click on the search input will blur focus
22155
+ if ( $(e.target).parents( '.dataTables_filter' ).length ) {
22156
+ that._blur();
22157
+ }
22158
+
22159
+ // If the click was inside the DataTables container, don't blur
22160
+ if ( $(e.target).parents().filter( dt.table().container() ).length ) {
22161
+ return;
22162
+ }
22163
+
22164
+ // Don't blur in Editor form
22165
+ if ( $(e.target).parents('div.DTE').length ) {
22166
+ return;
22167
+ }
22168
+
22169
+ // Or an Editor date input
22170
+ if ( $(e.target).parents('div.editor-datetime').length ) {
22171
+ return;
22172
+ }
22173
+
22174
+ //If the click was inside the fixed columns container, don't blur
22175
+ if ( $(e.target).parents().filter('.DTFC_Cloned').length ) {
22176
+ return;
22177
+ }
22178
+
22179
+ that._blur();
22180
+ } );
22181
+ }
22182
+
22183
+ if ( this.c.editor ) {
22184
+ var editor = this.c.editor;
22185
+
22186
+ // Need to disable KeyTable when the main editor is shown
22187
+ editor.on( 'open.keyTableMain', function (e, mode, action) {
22188
+ if ( mode !== 'inline' && that.s.enable ) {
22189
+ that.enable( false );
22190
+
22191
+ editor.one( 'close.keyTable', function () {
22192
+ that.enable( true );
22193
+ } );
22194
+ }
22195
+ } );
22196
+
22197
+ if ( this.c.editOnFocus ) {
22198
+ dt.on( 'key-focus.keyTable key-refocus.keyTable', function ( e, dt, cell, orig ) {
22199
+ that._editor( null, orig );
22200
+ } );
22201
+ }
22202
+
22203
+ // Activate Editor when a key is pressed (will be ignored, if
22204
+ // already active).
22205
+ dt.on( 'key.keyTable', function ( e, dt, key, cell, orig ) {
22206
+ that._editor( key, orig );
22207
+ } );
22208
+ }
22209
+
22210
+ // Stave saving
22211
+ if ( dt.settings()[0].oFeatures.bStateSave ) {
22212
+ dt.on( 'stateSaveParams.keyTable', function (e, s, d) {
22213
+ d.keyTable = that.s.lastFocus ?
22214
+ that.s.lastFocus.cell.index() :
22215
+ null;
22216
+ } );
22217
+ }
22218
+
22219
+ // Redraw - retain focus on the current cell
22220
+ dt.on( 'draw.keyTable', function (e) {
22221
+ if ( that.s.focusDraw ) {
22222
+ return;
22223
+ }
22224
+
22225
+ var lastFocus = that.s.lastFocus;
22226
+
22227
+ if ( lastFocus && lastFocus.node && $(lastFocus.node).closest('body') === document.body ) {
22228
+ var relative = that.s.lastFocus.relative;
22229
+ var info = dt.page.info();
22230
+ var row = relative.row + info.start;
22231
+
22232
+ if ( info.recordsDisplay === 0 ) {
22233
+ return;
22234
+ }
22235
+
22236
+ // Reverse if needed
22237
+ if ( row >= info.recordsDisplay ) {
22238
+ row = info.recordsDisplay - 1;
22239
+ }
22240
+
22241
+ that._focus( row, relative.column, true, e );
22242
+ }
22243
+ } );
22244
+
22245
+ dt.on( 'destroy.keyTable', function () {
22246
+ dt.off( '.keyTable' );
22247
+ $( dt.table().body() ).off( 'click.keyTable', 'th, td' );
22248
+ $( document.body )
22249
+ .off( 'keydown.keyTable' )
22250
+ .off( 'click.keyTable' );
22251
+ } );
22252
+
22253
+ // Initial focus comes from state or options
22254
+ var state = dt.state.loaded();
22255
+
22256
+ if ( state && state.keyTable ) {
22257
+ // Wait until init is done
22258
+ dt.one( 'init', function () {
22259
+ var cell = dt.cell( state.keyTable );
22260
+
22261
+ // Ensure that the saved cell still exists
22262
+ if ( cell.any() ) {
22263
+ cell.focus();
22264
+ }
22265
+ } );
22266
+ }
22267
+ else if ( this.c.focus ) {
22268
+ dt.cell( this.c.focus ).focus();
22269
+ }
22270
+ },
22271
+
22272
+
22273
+
22274
+
22275
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
22276
+ * Private methods
22277
+ */
22278
+
22279
+ /**
22280
+ * Blur the control
22281
+ *
22282
+ * @private
22283
+ */
22284
+ _blur: function ()
22285
+ {
22286
+ if ( ! this.s.enable || ! this.s.lastFocus ) {
22287
+ return;
22288
+ }
22289
+
22290
+ var cell = this.s.lastFocus.cell;
22291
+
22292
+ $( cell.node() ).removeClass( this.c.className );
22293
+ this.s.lastFocus = null;
22294
+
22295
+ this._updateFixedColumns(cell.index().column);
22296
+
22297
+ this._emitEvent( 'key-blur', [ this.s.dt, cell ] );
22298
+ },
22299
+
22300
+ /**
22301
+ * Copy text from the focused cell to clipboard
22302
+ *
22303
+ * @private
22304
+ */
22305
+ _clipboardCopy: function ()
22306
+ {
22307
+ var dt = this.s.dt;
22308
+
22309
+ // If there is a cell focused, and there is no other text selected
22310
+ // allow the focused cell's text to be copied to clipboard
22311
+ if ( this.s.lastFocus && window.getSelection && !window.getSelection().toString() ) {
22312
+ var cell = this.s.lastFocus.cell;
22313
+ var text = cell.render('display');
22314
+ var hiddenDiv = $('<div/>')
22315
+ .css( {
22316
+ height: 1,
22317
+ width: 1,
22318
+ overflow: 'hidden',
22319
+ position: 'fixed',
22320
+ top: 0,
22321
+ left: 0
22322
+ } );
22323
+ var textarea = $('<textarea readonly/>')
22324
+ .val( text )
22325
+ .appendTo( hiddenDiv );
22326
+
22327
+ try {
22328
+ hiddenDiv.appendTo( dt.table().container() );
22329
+ textarea[0].focus();
22330
+ textarea[0].select();
22331
+
22332
+ document.execCommand( 'copy' );
22333
+ }
22334
+ catch (e) {}
22335
+
22336
+ hiddenDiv.remove();
22337
+ }
22338
+ },
22339
+
22340
+
22341
+ /**
22342
+ * Get an array of the column indexes that KeyTable can operate on. This
22343
+ * is a merge of the user supplied columns and the visible columns.
22344
+ *
22345
+ * @private
22346
+ */
22347
+ _columns: function ()
22348
+ {
22349
+ var dt = this.s.dt;
22350
+ var user = dt.columns( this.c.columns ).indexes();
22351
+ var out = [];
22352
+
22353
+ dt.columns( ':visible' ).every( function (i) {
22354
+ if ( user.indexOf( i ) !== -1 ) {
22355
+ out.push( i );
22356
+ }
22357
+ } );
22358
+
22359
+ return out;
22360
+ },
22361
+
22362
+
22363
+ /**
22364
+ * Perform excel like navigation for Editor by triggering an edit on key
22365
+ * press
22366
+ *
22367
+ * @param {integer} key Key code for the pressed key
22368
+ * @param {object} orig Original event
22369
+ * @private
22370
+ */
22371
+ _editor: function ( key, orig )
22372
+ {
22373
+ var that = this;
22374
+ var dt = this.s.dt;
22375
+ var editor = this.c.editor;
22376
+
22377
+ // Do nothing if there is already an inline edit in this cell
22378
+ if ( $('div.DTE', this.s.lastFocus.cell.node()).length ) {
22379
+ return;
22380
+ }
22381
+
22382
+ // Don't activate inline editing when the shift key is pressed
22383
+ if ( key === 16 ) {
22384
+ return;
22385
+ }
22386
+
22387
+ orig.stopPropagation();
22388
+
22389
+ // Return key should do nothing - for textareas it would empty the
22390
+ // contents
22391
+ if ( key === 13 ) {
22392
+ orig.preventDefault();
22393
+ }
22394
+
22395
+ editor
22396
+ .one( 'open.keyTable', function () {
22397
+ // Remove cancel open
22398
+ editor.off( 'cancelOpen.keyTable' );
22399
+
22400
+ // Excel style - select all text
22401
+ if ( that.c.editAutoSelect ) {
22402
+ $('div.DTE_Field_InputControl input, div.DTE_Field_InputControl textarea').select();
22403
+ }
22404
+
22405
+ // Reduce the keys the Keys listens for
22406
+ dt.keys.enable( that.c.editorKeys );
22407
+
22408
+ // On blur of the navigation submit
22409
+ dt.one( 'key-blur.editor', function () {
22410
+ if ( editor.displayed() ) {
22411
+ editor.submit();
22412
+ }
22413
+ } );
22414
+
22415
+ // Restore full key navigation on close
22416
+ editor.one( 'close', function () {
22417
+ dt.keys.enable( true );
22418
+ dt.off( 'key-blur.editor' );
22419
+ } );
22420
+ } )
22421
+ .one( 'cancelOpen.keyTable', function () {
22422
+ // `preOpen` can cancel the display of the form, so it
22423
+ // might be that the open event handler isn't needed
22424
+ editor.off( 'open.keyTable' );
22425
+ } )
22426
+ .inline( this.s.lastFocus.cell.index() );
22427
+ },
22428
+
22429
+
22430
+ /**
22431
+ * Emit an event on the DataTable for listeners
22432
+ *
22433
+ * @param {string} name Event name
22434
+ * @param {array} args Event arguments
22435
+ * @private
22436
+ */
22437
+ _emitEvent: function ( name, args )
22438
+ {
22439
+ this.s.dt.iterator( 'table', function ( ctx, i ) {
22440
+ $(ctx.nTable).triggerHandler( name, args );
22441
+ } );
22442
+ },
22443
+
22444
+
22445
+ /**
22446
+ * Focus on a particular cell, shifting the table's paging if required
22447
+ *
22448
+ * @param {DataTables.Api|integer} row Can be given as an API instance that
22449
+ * contains the cell to focus or as an integer. As the latter it is the
22450
+ * visible row index (from the whole data set) - NOT the data index
22451
+ * @param {integer} [column] Not required if a cell is given as the first
22452
+ * parameter. Otherwise this is the column data index for the cell to
22453
+ * focus on
22454
+ * @param {boolean} [shift=true] Should the viewport be moved to show cell
22455
+ * @private
22456
+ */
22457
+ _focus: function ( row, column, shift, originalEvent )
22458
+ {
22459
+ var that = this;
22460
+ var dt = this.s.dt;
22461
+ var pageInfo = dt.page.info();
22462
+ var lastFocus = this.s.lastFocus;
22463
+
22464
+ if ( ! originalEvent) {
22465
+ originalEvent = null;
22466
+ }
22467
+
22468
+ if ( ! this.s.enable ) {
22469
+ return;
22470
+ }
22471
+
22472
+ if ( typeof row !== 'number' ) {
22473
+ // Convert the cell to a row and column
22474
+ var index = row.index();
22475
+ column = index.column;
22476
+ row = dt
22477
+ .rows( { filter: 'applied', order: 'applied' } )
22478
+ .indexes()
22479
+ .indexOf( index.row );
22480
+
22481
+ // For server-side processing normalise the row by adding the start
22482
+ // point, since `rows().indexes()` includes only rows that are
22483
+ // available at the client-side
22484
+ if ( pageInfo.serverSide ) {
22485
+ row += pageInfo.start;
22486
+ }
22487
+ }
22488
+
22489
+ // Is the row on the current page? If not, we need to redraw to show the
22490
+ // page
22491
+ if ( pageInfo.length !== -1 && (row < pageInfo.start || row >= pageInfo.start+pageInfo.length) ) {
22492
+ this.s.focusDraw = true;
22493
+ this.s.waitingForDraw = true;
22494
+
22495
+ dt
22496
+ .one( 'draw', function () {
22497
+ that.s.focusDraw = false;
22498
+ that.s.waitingForDraw = false;
22499
+ that._focus( row, column, undefined, originalEvent );
22500
+ } )
22501
+ .page( Math.floor( row / pageInfo.length ) )
22502
+ .draw( false );
22503
+
22504
+ return;
22505
+ }
22506
+
22507
+ // In the available columns?
22508
+ if ( $.inArray( column, this._columns() ) === -1 ) {
22509
+ return;
22510
+ }
22511
+
22512
+ // De-normalise the server-side processing row, so we select the row
22513
+ // in its displayed position
22514
+ if ( pageInfo.serverSide ) {
22515
+ row -= pageInfo.start;
22516
+ }
22517
+
22518
+ // Get the cell from the current position - ignoring any cells which might
22519
+ // not have been rendered (therefore can't use `:eq()` selector).
22520
+ var cells = dt.cells( null, column, {search: 'applied', order: 'applied'} ).flatten();
22521
+ var cell = dt.cell( cells[ row ] );
22522
+
22523
+ if ( lastFocus ) {
22524
+ // Don't trigger a refocus on the same cell
22525
+ if ( lastFocus.node === cell.node() ) {
22526
+ this._emitEvent( 'key-refocus', [ this.s.dt, cell, originalEvent || null ] );
22527
+ return;
22528
+ }
22529
+
22530
+ // Otherwise blur the old focus
22531
+ this._blur();
22532
+ }
22533
+
22534
+ var node = $( cell.node() );
22535
+ node.addClass( this.c.className );
22536
+
22537
+ this._updateFixedColumns(column);
22538
+
22539
+ // Shift viewpoint and page to make cell visible
22540
+ if ( shift === undefined || shift === true ) {
22541
+ this._scroll( $(window), $(document.body), node, 'offset' );
22542
+
22543
+ var bodyParent = dt.table().body().parentNode;
22544
+ if ( bodyParent !== dt.table().header().parentNode ) {
22545
+ var parent = $(bodyParent.parentNode);
22546
+
22547
+ this._scroll( parent, parent, node, 'position' );
22548
+ }
22549
+ }
22550
+
22551
+ // Event and finish
22552
+ this.s.lastFocus = {
22553
+ cell: cell,
22554
+ node: cell.node(),
22555
+ relative: {
22556
+ row: dt.rows( { page: 'current' } ).indexes().indexOf( cell.index().row ),
22557
+ column: cell.index().column
22558
+ }
22559
+ };
22560
+
22561
+ this._emitEvent( 'key-focus', [ this.s.dt, cell, originalEvent || null ] );
22562
+ dt.state.save();
22563
+ },
22564
+
22565
+
22566
+ /**
22567
+ * Handle key press
22568
+ *
22569
+ * @param {object} e Event
22570
+ * @private
22571
+ */
22572
+ _key: function ( e )
22573
+ {
22574
+ // If we are waiting for a draw to happen from another key event, then
22575
+ // do nothing for this new key press.
22576
+ if ( this.s.waitingForDraw ) {
22577
+ e.preventDefault();
22578
+ return;
22579
+ }
22580
+
22581
+ var enable = this.s.enable;
22582
+ var navEnable = enable === true || enable === 'navigation-only';
22583
+ if ( ! enable ) {
22584
+ return;
22585
+ }
22586
+
22587
+ if ( e.ctrlKey && e.keyCode === 67 ) { // c
22588
+ this._clipboardCopy();
22589
+ return;
22590
+ }
22591
+
22592
+ if ( e.keyCode === 0 || e.ctrlKey || e.metaKey || e.altKey ) {
22593
+ return;
22594
+ }
22595
+
22596
+ // If not focused, then there is no key action to take
22597
+ var lastFocus = this.s.lastFocus;
22598
+ if ( ! lastFocus ) {
22599
+ return;
22600
+ }
22601
+
22602
+ var that = this;
22603
+ var dt = this.s.dt;
22604
+
22605
+ // If we are not listening for this key, do nothing
22606
+ if ( this.c.keys && $.inArray( e.keyCode, this.c.keys ) === -1 ) {
22607
+ return;
22608
+ }
22609
+
22610
+ switch( e.keyCode ) {
22611
+ case 9: // tab
22612
+ // `enable` can be tab-only
22613
+ this._shift( e, e.shiftKey ? 'left' : 'right', true );
22614
+ break;
22615
+
22616
+ case 27: // esc
22617
+ if ( this.s.blurable && enable === true ) {
22618
+ this._blur();
22619
+ }
22620
+ break;
22621
+
22622
+ case 33: // page up (previous page)
22623
+ case 34: // page down (next page)
22624
+ if ( navEnable ) {
22625
+ e.preventDefault();
22626
+
22627
+ dt
22628
+ .page( e.keyCode === 33 ? 'previous' : 'next' )
22629
+ .draw( false );
22630
+ }
22631
+ break;
22632
+
22633
+ case 35: // end (end of current page)
22634
+ case 36: // home (start of current page)
22635
+ if ( navEnable ) {
22636
+ e.preventDefault();
22637
+ var indexes = dt.cells( {page: 'current'} ).indexes();
22638
+ var colIndexes = this._columns();
22639
+
22640
+ this._focus( dt.cell(
22641
+ indexes[ e.keyCode === 35 ? indexes.length-1 : colIndexes[0] ]
22642
+ ), null, true, e );
22643
+ }
22644
+ break;
22645
+
22646
+ case 37: // left arrow
22647
+ if ( navEnable ) {
22648
+ this._shift( e, 'left' );
22649
+ }
22650
+ break;
22651
+
22652
+ case 38: // up arrow
22653
+ if ( navEnable ) {
22654
+ this._shift( e, 'up' );
22655
+ }
22656
+ break;
22657
+
22658
+ case 39: // right arrow
22659
+ if ( navEnable ) {
22660
+ this._shift( e, 'right' );
22661
+ }
22662
+ break;
22663
+
22664
+ case 40: // down arrow
22665
+ if ( navEnable ) {
22666
+ this._shift( e, 'down' );
22667
+ }
22668
+ break;
22669
+
22670
+ default:
22671
+ // Everything else - pass through only when fully enabled
22672
+ if ( enable === true ) {
22673
+ this._emitEvent( 'key', [ dt, e.keyCode, this.s.lastFocus.cell, e ] );
22674
+ }
22675
+ break;
22676
+ }
22677
+ },
22678
+
22679
+
22680
+ /**
22681
+ * Scroll a container to make a cell visible in it. This can be used for
22682
+ * both DataTables scrolling and native window scrolling.
22683
+ *
22684
+ * @param {jQuery} container Scrolling container
22685
+ * @param {jQuery} scroller Item being scrolled
22686
+ * @param {jQuery} cell Cell in the scroller
22687
+ * @param {string} posOff `position` or `offset` - which to use for the
22688
+ * calculation. `offset` for the document, otherwise `position`
22689
+ * @private
22690
+ */
22691
+ _scroll: function ( container, scroller, cell, posOff )
22692
+ {
22693
+ var offset = cell[posOff]();
22694
+ var height = cell.outerHeight();
22695
+ var width = cell.outerWidth();
22696
+
22697
+ var scrollTop = scroller.scrollTop();
22698
+ var scrollLeft = scroller.scrollLeft();
22699
+ var containerHeight = container.height();
22700
+ var containerWidth = container.width();
22701
+
22702
+ // If Scroller is being used, the table can be `position: absolute` and that
22703
+ // needs to be taken account of in the offset. If no Scroller, this will be 0
22704
+ if ( posOff === 'position' ) {
22705
+ offset.top += parseInt( cell.closest('table').css('top'), 10 );
22706
+ }
22707
+
22708
+ // Top correction
22709
+ if ( offset.top < scrollTop ) {
22710
+ scroller.scrollTop( offset.top );
22711
+ }
22712
+
22713
+ // Left correction
22714
+ if ( offset.left < scrollLeft ) {
22715
+ scroller.scrollLeft( offset.left );
22716
+ }
22717
+
22718
+ // Bottom correction
22719
+ if ( offset.top + height > scrollTop + containerHeight && height < containerHeight ) {
22720
+ scroller.scrollTop( offset.top + height - containerHeight );
22721
+ }
22722
+
22723
+ // Right correction
22724
+ if ( offset.left + width > scrollLeft + containerWidth && width < containerWidth ) {
22725
+ scroller.scrollLeft( offset.left + width - containerWidth );
22726
+ }
22727
+ },
22728
+
22729
+
22730
+ /**
22731
+ * Calculate a single offset movement in the table - up, down, left and
22732
+ * right and then perform the focus if possible
22733
+ *
22734
+ * @param {object} e Event object
22735
+ * @param {string} direction Movement direction
22736
+ * @param {boolean} keyBlurable `true` if the key press can result in the
22737
+ * table being blurred. This is so arrow keys won't blur the table, but
22738
+ * tab will.
22739
+ * @private
22740
+ */
22741
+ _shift: function ( e, direction, keyBlurable )
22742
+ {
22743
+ var that = this;
22744
+ var dt = this.s.dt;
22745
+ var pageInfo = dt.page.info();
22746
+ var rows = pageInfo.recordsDisplay;
22747
+ var currentCell = this.s.lastFocus.cell;
22748
+ var columns = this._columns();
22749
+
22750
+ if ( ! currentCell ) {
22751
+ return;
22752
+ }
22753
+
22754
+ var currRow = dt
22755
+ .rows( { filter: 'applied', order: 'applied' } )
22756
+ .indexes()
22757
+ .indexOf( currentCell.index().row );
22758
+
22759
+ // When server-side processing, `rows().indexes()` only gives the rows
22760
+ // that are available at the client-side, so we need to normalise the
22761
+ // row's current position by the display start point
22762
+ if ( pageInfo.serverSide ) {
22763
+ currRow += pageInfo.start;
22764
+ }
22765
+
22766
+ var currCol = dt
22767
+ .columns( columns )
22768
+ .indexes()
22769
+ .indexOf( currentCell.index().column );
22770
+
22771
+ var
22772
+ row = currRow,
22773
+ column = columns[ currCol ]; // row is the display, column is an index
22774
+
22775
+ if ( direction === 'right' ) {
22776
+ if ( currCol >= columns.length - 1 ) {
22777
+ row++;
22778
+ column = columns[0];
22779
+ }
22780
+ else {
22781
+ column = columns[ currCol+1 ];
22782
+ }
22783
+ }
22784
+ else if ( direction === 'left' ) {
22785
+ if ( currCol === 0 ) {
22786
+ row--;
22787
+ column = columns[ columns.length - 1 ];
22788
+ }
22789
+ else {
22790
+ column = columns[ currCol-1 ];
22791
+ }
22792
+ }
22793
+ else if ( direction === 'up' ) {
22794
+ row--;
22795
+ }
22796
+ else if ( direction === 'down' ) {
22797
+ row++;
22798
+ }
22799
+
22800
+ if ( row >= 0 && row < rows && $.inArray( column, columns ) !== -1
22801
+ ) {
22802
+ e.preventDefault();
22803
+
22804
+ this._focus( row, column, true, e );
22805
+ }
22806
+ else if ( ! keyBlurable || ! this.c.blurable ) {
22807
+ // No new focus, but if the table isn't blurable, then don't loose
22808
+ // focus
22809
+ e.preventDefault();
22810
+ }
22811
+ else {
22812
+ this._blur();
22813
+ }
22814
+ },
22815
+
22816
+
22817
+ /**
22818
+ * Create a hidden input element that can receive focus on behalf of the
22819
+ * table
22820
+ *
22821
+ * @private
22822
+ */
22823
+ _tabInput: function ()
22824
+ {
22825
+ var that = this;
22826
+ var dt = this.s.dt;
22827
+ var tabIndex = this.c.tabIndex !== null ?
22828
+ this.c.tabIndex :
22829
+ dt.settings()[0].iTabIndex;
22830
+
22831
+ if ( tabIndex == -1 ) {
22832
+ return;
22833
+ }
22834
+
22835
+ var div = $('<div><input type="text" tabindex="'+tabIndex+'"/></div>')
22836
+ .css( {
22837
+ position: 'absolute',
22838
+ height: 1,
22839
+ width: 0,
22840
+ overflow: 'hidden'
22841
+ } )
22842
+ .insertBefore( dt.table().node() );
22843
+
22844
+ div.children().on( 'focus', function (e) {
22845
+ if ( dt.cell(':eq(0)', {page: 'current'}).any() ) {
22846
+ that._focus( dt.cell(':eq(0)', '0:visible', {page: 'current'}), null, true, e );
22847
+ }
22848
+ } );
22849
+ },
22850
+
22851
+ /**
22852
+ * Update fixed columns if they are enabled and if the cell we are
22853
+ * focusing is inside a fixed column
22854
+ * @param {integer} column Index of the column being changed
22855
+ * @private
22856
+ */
22857
+ _updateFixedColumns: function( column )
22858
+ {
22859
+ var dt = this.s.dt;
22860
+ var settings = dt.settings()[0];
22861
+
22862
+ if ( settings._oFixedColumns ) {
22863
+ var leftCols = settings._oFixedColumns.s.iLeftColumns;
22864
+ var rightCols = settings.aoColumns.length - settings._oFixedColumns.s.iRightColumns;
22865
+
22866
+ if (column < leftCols || column >= rightCols) {
22867
+ dt.fixedColumns().update();
22868
+ }
22869
+ }
22870
+ }
22871
+ } );
22872
+
22873
+
22874
+ /**
22875
+ * KeyTable default settings for initialisation
22876
+ *
22877
+ * @namespace
22878
+ * @name KeyTable.defaults
22879
+ * @static
22880
+ */
22881
+ KeyTable.defaults = {
22882
+ /**
22883
+ * Can focus be removed from the table
22884
+ * @type {Boolean}
22885
+ */
22886
+ blurable: true,
22887
+
22888
+ /**
22889
+ * Class to give to the focused cell
22890
+ * @type {String}
22891
+ */
22892
+ className: 'focus',
22893
+
22894
+ /**
22895
+ * Columns that can be focused. This is automatically merged with the
22896
+ * visible columns as only visible columns can gain focus.
22897
+ * @type {String}
22898
+ */
22899
+ columns: '', // all
22900
+
22901
+ /**
22902
+ * Editor instance to automatically perform Excel like navigation
22903
+ * @type {Editor}
22904
+ */
22905
+ editor: null,
22906
+
22907
+ /**
22908
+ * Option that defines what KeyTable's behaviour will be when used with
22909
+ * Editor's inline editing. Can be `navigation-only` or `tab-only`.
22910
+ * @type {String}
22911
+ */
22912
+ editorKeys: 'navigation-only',
22913
+
22914
+ /**
22915
+ * Set if Editor should automatically select the text in the input
22916
+ * @type {Boolean}
22917
+ */
22918
+ editAutoSelect: true,
22919
+
22920
+ /**
22921
+ * Control if editing should be activated immediately upon focus
22922
+ * @type {Boolean}
22923
+ */
22924
+ editOnFocus: false,
22925
+
22926
+ /**
22927
+ * Select a cell to automatically select on start up. `null` for no
22928
+ * automatic selection
22929
+ * @type {cell-selector}
22930
+ */
22931
+ focus: null,
22932
+
22933
+ /**
22934
+ * Array of keys to listen for
22935
+ * @type {null|array}
22936
+ */
22937
+ keys: null,
22938
+
22939
+ /**
22940
+ * Tab index for where the table should sit in the document's tab flow
22941
+ * @type {integer|null}
22942
+ */
22943
+ tabIndex: null
22944
+ };
22945
+
22946
+
22947
+
22948
+ KeyTable.version = "2.3.2";
22949
+
22950
+
22951
+ $.fn.dataTable.KeyTable = KeyTable;
22952
+ $.fn.DataTable.KeyTable = KeyTable;
22953
+
22954
+
22955
+ DataTable.Api.register( 'cell.blur()', function () {
22956
+ return this.iterator( 'table', function (ctx) {
22957
+ if ( ctx.keytable ) {
22958
+ ctx.keytable.blur();
22959
+ }
22960
+ } );
22961
+ } );
22962
+
22963
+ DataTable.Api.register( 'cell().focus()', function () {
22964
+ return this.iterator( 'cell', function (ctx, row, column) {
22965
+ if ( ctx.keytable ) {
22966
+ ctx.keytable.focus( row, column );
22967
+ }
22968
+ } );
22969
+ } );
22970
+
22971
+ DataTable.Api.register( 'keys.disable()', function () {
22972
+ return this.iterator( 'table', function (ctx) {
22973
+ if ( ctx.keytable ) {
22974
+ ctx.keytable.enable( false );
22975
+ }
22976
+ } );
22977
+ } );
22978
+
22979
+ DataTable.Api.register( 'keys.enable()', function ( opts ) {
22980
+ return this.iterator( 'table', function (ctx) {
22981
+ if ( ctx.keytable ) {
22982
+ ctx.keytable.enable( opts === undefined ? true : opts );
22983
+ }
22984
+ } );
22985
+ } );
22986
+
22987
+ // Cell selector
22988
+ DataTable.ext.selector.cell.push( function ( settings, opts, cells ) {
22989
+ var focused = opts.focused;
22990
+ var kt = settings.keytable;
22991
+ var out = [];
22992
+
22993
+ if ( ! kt || focused === undefined ) {
22994
+ return cells;
22995
+ }
22996
+
22997
+ for ( var i=0, ien=cells.length ; i<ien ; i++ ) {
22998
+ if ( (focused === true && kt.focused( cells[i] ) ) ||
22999
+ (focused === false && ! kt.focused( cells[i] ) )
23000
+ ) {
23001
+ out.push( cells[i] );
23002
+ }
23003
+ }
23004
+
23005
+ return out;
23006
+ } );
23007
+
23008
+
23009
+ // Attach a listener to the document which listens for DataTables initialisation
23010
+ // events so we can automatically initialise
23011
+ $(document).on( 'preInit.dt.dtk', function (e, settings, json) {
23012
+ if ( e.namespace !== 'dt' ) {
23013
+ return;
23014
+ }
23015
+
23016
+ var init = settings.oInit.keys;
23017
+ var defaults = DataTable.defaults.keys;
23018
+
23019
+ if ( init || defaults ) {
23020
+ var opts = $.extend( {}, defaults, init );
23021
+
23022
+ if ( init !== false ) {
23023
+ new KeyTable( settings, opts );
23024
+ }
23025
+ }
23026
+ } );
23027
+
23028
+
23029
+ return KeyTable;
23030
+ }));
23031
+
23032
+
23033
+ /*! Responsive 2.2.1
23034
+ * 2014-2017 SpryMedia Ltd - datatables.net/license
23035
+ */
23036
+
23037
+ /**
23038
+ * @summary Responsive
23039
+ * @description Responsive tables plug-in for DataTables
23040
+ * @version 2.2.1
23041
+ * @file dataTables.responsive.js
23042
+ * @author SpryMedia Ltd (www.sprymedia.co.uk)
23043
+ * @contact www.sprymedia.co.uk/contact
23044
+ * @copyright Copyright 2014-2017 SpryMedia Ltd.
23045
+ *
23046
+ * This source file is free software, available under the following license:
23047
+ * MIT license - http://datatables.net/license/mit
23048
+ *
23049
+ * This source file is distributed in the hope that it will be useful, but
23050
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
23051
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
23052
+ *
23053
+ * For details please refer to: http://www.datatables.net
23054
+ */
23055
+ (function( factory ){
23056
+ if ( typeof define === 'function' && define.amd ) {
23057
+ // AMD
23058
+ define( ['jquery', 'datatables.net'], function ( $ ) {
23059
+ return factory( $, window, document );
23060
+ } );
23061
+ }
23062
+ else if ( typeof exports === 'object' ) {
23063
+ // CommonJS
23064
+ module.exports = function (root, $) {
23065
+ if ( ! root ) {
23066
+ root = window;
23067
+ }
23068
+
23069
+ if ( ! $ || ! $.fn.dataTable ) {
23070
+ $ = require('datatables.net')(root, $).$;
23071
+ }
23072
+
23073
+ return factory( $, root, root.document );
23074
+ };
23075
+ }
23076
+ else {
23077
+ // Browser
23078
+ factory( jQuery, window, document );
23079
+ }
23080
+ }(function( $, window, document, undefined ) {
23081
+ 'use strict';
23082
+ var DataTable = $.fn.dataTable;
23083
+
23084
+
23085
+ /**
23086
+ * Responsive is a plug-in for the DataTables library that makes use of
23087
+ * DataTables' ability to change the visibility of columns, changing the
23088
+ * visibility of columns so the displayed columns fit into the table container.
23089
+ * The end result is that complex tables will be dynamically adjusted to fit
23090
+ * into the viewport, be it on a desktop, tablet or mobile browser.
23091
+ *
23092
+ * Responsive for DataTables has two modes of operation, which can used
23093
+ * individually or combined:
23094
+ *
23095
+ * * Class name based control - columns assigned class names that match the
23096
+ * breakpoint logic can be shown / hidden as required for each breakpoint.
23097
+ * * Automatic control - columns are automatically hidden when there is no
23098
+ * room left to display them. Columns removed from the right.
23099
+ *
23100
+ * In additional to column visibility control, Responsive also has built into
23101
+ * options to use DataTables' child row display to show / hide the information
23102
+ * from the table that has been hidden. There are also two modes of operation
23103
+ * for this child row display:
23104
+ *
23105
+ * * Inline - when the control element that the user can use to show / hide
23106
+ * child rows is displayed inside the first column of the table.
23107
+ * * Column - where a whole column is dedicated to be the show / hide control.
23108
+ *
23109
+ * Initialisation of Responsive is performed by:
23110
+ *
23111
+ * * Adding the class `responsive` or `dt-responsive` to the table. In this case
23112
+ * Responsive will automatically be initialised with the default configuration
23113
+ * options when the DataTable is created.
23114
+ * * Using the `responsive` option in the DataTables configuration options. This
23115
+ * can also be used to specify the configuration options, or simply set to
23116
+ * `true` to use the defaults.
23117
+ *
23118
+ * @class
23119
+ * @param {object} settings DataTables settings object for the host table
23120
+ * @param {object} [opts] Configuration options
23121
+ * @requires jQuery 1.7+
23122
+ * @requires DataTables 1.10.3+
23123
+ *
23124
+ * @example
23125
+ * $('#example').DataTable( {
23126
+ * responsive: true
23127
+ * } );
23128
+ * } );
23129
+ */
23130
+ var Responsive = function ( settings, opts ) {
23131
+ // Sanity check that we are using DataTables 1.10 or newer
23132
+ if ( ! DataTable.versionCheck || ! DataTable.versionCheck( '1.10.10' ) ) {
23133
+ throw 'DataTables Responsive requires DataTables 1.10.10 or newer';
23134
+ }
23135
+
23136
+ this.s = {
23137
+ dt: new DataTable.Api( settings ),
23138
+ columns: [],
23139
+ current: []
23140
+ };
23141
+
23142
+ // Check if responsive has already been initialised on this table
23143
+ if ( this.s.dt.settings()[0].responsive ) {
23144
+ return;
23145
+ }
23146
+
23147
+ // details is an object, but for simplicity the user can give it as a string
23148
+ // or a boolean
23149
+ if ( opts && typeof opts.details === 'string' ) {
23150
+ opts.details = { type: opts.details };
23151
+ }
23152
+ else if ( opts && opts.details === false ) {
23153
+ opts.details = { type: false };
23154
+ }
23155
+ else if ( opts && opts.details === true ) {
23156
+ opts.details = { type: 'inline' };
23157
+ }
23158
+
23159
+ this.c = $.extend( true, {}, Responsive.defaults, DataTable.defaults.responsive, opts );
23160
+ settings.responsive = this;
23161
+ this._constructor();
23162
+ };
23163
+
23164
+ $.extend( Responsive.prototype, {
23165
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
23166
+ * Constructor
23167
+ */
23168
+
23169
+ /**
23170
+ * Initialise the Responsive instance
23171
+ *
23172
+ * @private
23173
+ */
23174
+ _constructor: function ()
23175
+ {
23176
+ var that = this;
23177
+ var dt = this.s.dt;
23178
+ var dtPrivateSettings = dt.settings()[0];
23179
+ var oldWindowWidth = $(window).width();
23180
+
23181
+ dt.settings()[0]._responsive = this;
23182
+
23183
+ // Use DataTables' throttle function to avoid processor thrashing on
23184
+ // resize
23185
+ $(window).on( 'resize.dtr orientationchange.dtr', DataTable.util.throttle( function () {
23186
+ // iOS has a bug whereby resize can fire when only scrolling
23187
+ // See: http://stackoverflow.com/questions/8898412
23188
+ var width = $(window).width();
23189
+
23190
+ if ( width !== oldWindowWidth ) {
23191
+ that._resize();
23192
+ oldWindowWidth = width;
23193
+ }
23194
+ } ) );
23195
+
23196
+ // DataTables doesn't currently trigger an event when a row is added, so
23197
+ // we need to hook into its private API to enforce the hidden rows when
23198
+ // new data is added
23199
+ dtPrivateSettings.oApi._fnCallbackReg( dtPrivateSettings, 'aoRowCreatedCallback', function (tr, data, idx) {
23200
+ if ( $.inArray( false, that.s.current ) !== -1 ) {
23201
+ $('>td, >th', tr).each( function ( i ) {
23202
+ var idx = dt.column.index( 'toData', i );
23203
+
23204
+ if ( that.s.current[idx] === false ) {
23205
+ $(this).css('display', 'none');
23206
+ }
23207
+ } );
23208
+ }
23209
+ } );
23210
+
23211
+ // Destroy event handler
23212
+ dt.on( 'destroy.dtr', function () {
23213
+ dt.off( '.dtr' );
23214
+ $( dt.table().body() ).off( '.dtr' );
23215
+ $(window).off( 'resize.dtr orientationchange.dtr' );
23216
+
23217
+ // Restore the columns that we've hidden
23218
+ $.each( that.s.current, function ( i, val ) {
23219
+ if ( val === false ) {
23220
+ that._setColumnVis( i, true );
23221
+ }
23222
+ } );
23223
+ } );
23224
+
23225
+ // Reorder the breakpoints array here in case they have been added out
23226
+ // of order
23227
+ this.c.breakpoints.sort( function (a, b) {
23228
+ return a.width < b.width ? 1 :
23229
+ a.width > b.width ? -1 : 0;
23230
+ } );
23231
+
23232
+ this._classLogic();
23233
+ this._resizeAuto();
23234
+
23235
+ // Details handler
23236
+ var details = this.c.details;
23237
+
23238
+ if ( details.type !== false ) {
23239
+ that._detailsInit();
23240
+
23241
+ // DataTables will trigger this event on every column it shows and
23242
+ // hides individually
23243
+ dt.on( 'column-visibility.dtr', function (e, ctx, col, vis, recalc) {
23244
+ if ( recalc ) {
23245
+ that._classLogic();
23246
+ that._resizeAuto();
23247
+ that._resize();
23248
+ }
23249
+ } );
23250
+
23251
+ // Redraw the details box on each draw which will happen if the data
23252
+ // has changed. This is used until DataTables implements a native
23253
+ // `updated` event for rows
23254
+ dt.on( 'draw.dtr', function () {
23255
+ that._redrawChildren();
23256
+ } );
23257
+
23258
+ $(dt.table().node()).addClass( 'dtr-'+details.type );
23259
+ }
23260
+
23261
+ dt.on( 'column-reorder.dtr', function (e, settings, details) {
23262
+ that._classLogic();
23263
+ that._resizeAuto();
23264
+ that._resize();
23265
+ } );
23266
+
23267
+ // Change in column sizes means we need to calc
23268
+ dt.on( 'column-sizing.dtr', function () {
23269
+ that._resizeAuto();
23270
+ that._resize();
23271
+ });
23272
+
23273
+ // On Ajax reload we want to reopen any child rows which are displayed
23274
+ // by responsive
23275
+ dt.on( 'preXhr.dtr', function () {
23276
+ var rowIds = [];
23277
+ dt.rows().every( function () {
23278
+ if ( this.child.isShown() ) {
23279
+ rowIds.push( this.id(true) );
23280
+ }
23281
+ } );
23282
+
23283
+ dt.one( 'draw.dtr', function () {
23284
+ that._resizeAuto();
23285
+ that._resize();
23286
+
23287
+ dt.rows( rowIds ).every( function () {
23288
+ that._detailsDisplay( this, false );
23289
+ } );
23290
+ } );
23291
+ });
23292
+
23293
+ dt.on( 'init.dtr', function (e, settings, details) {
23294
+ that._resizeAuto();
23295
+ that._resize();
23296
+
23297
+ // If columns were hidden, then DataTables needs to adjust the
23298
+ // column sizing
23299
+ if ( $.inArray( false, that.s.current ) ) {
23300
+ dt.columns.adjust();
23301
+ }
23302
+ } );
23303
+
23304
+ // First pass - draw the table for the current viewport size
23305
+ this._resize();
23306
+ },
23307
+
23308
+
23309
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
23310
+ * Private methods
23311
+ */
23312
+
23313
+ /**
23314
+ * Calculate the visibility for the columns in a table for a given
23315
+ * breakpoint. The result is pre-determined based on the class logic if
23316
+ * class names are used to control all columns, but the width of the table
23317
+ * is also used if there are columns which are to be automatically shown
23318
+ * and hidden.
23319
+ *
23320
+ * @param {string} breakpoint Breakpoint name to use for the calculation
23321
+ * @return {array} Array of boolean values initiating the visibility of each
23322
+ * column.
23323
+ * @private
23324
+ */
23325
+ _columnsVisiblity: function ( breakpoint )
23326
+ {
23327
+ var dt = this.s.dt;
23328
+ var columns = this.s.columns;
23329
+ var i, ien;
23330
+
23331
+ // Create an array that defines the column ordering based first on the
23332
+ // column's priority, and secondly the column index. This allows the
23333
+ // columns to be removed from the right if the priority matches
23334
+ var order = columns
23335
+ .map( function ( col, idx ) {
23336
+ return {
23337
+ columnIdx: idx,
23338
+ priority: col.priority
23339
+ };
23340
+ } )
23341
+ .sort( function ( a, b ) {
23342
+ if ( a.priority !== b.priority ) {
23343
+ return a.priority - b.priority;
23344
+ }
23345
+ return a.columnIdx - b.columnIdx;
23346
+ } );
23347
+
23348
+ // Class logic - determine which columns are in this breakpoint based
23349
+ // on the classes. If no class control (i.e. `auto`) then `-` is used
23350
+ // to indicate this to the rest of the function
23351
+ var display = $.map( columns, function ( col ) {
23352
+ return col.auto && col.minWidth === null ?
23353
+ false :
23354
+ col.auto === true ?
23355
+ '-' :
23356
+ $.inArray( breakpoint, col.includeIn ) !== -1;
23357
+ } );
23358
+
23359
+ // Auto column control - first pass: how much width is taken by the
23360
+ // ones that must be included from the non-auto columns
23361
+ var requiredWidth = 0;
23362
+ for ( i=0, ien=display.length ; i<ien ; i++ ) {
23363
+ if ( display[i] === true ) {
23364
+ requiredWidth += columns[i].minWidth;
23365
+ }
23366
+ }
23367
+
23368
+ // Second pass, use up any remaining width for other columns. For
23369
+ // scrolling tables we need to subtract the width of the scrollbar. It
23370
+ // may not be requires which makes this sub-optimal, but it would
23371
+ // require another full redraw to make complete use of those extra few
23372
+ // pixels
23373
+ var scrolling = dt.settings()[0].oScroll;
23374
+ var bar = scrolling.sY || scrolling.sX ? scrolling.iBarWidth : 0;
23375
+ var widthAvailable = dt.table().container().offsetWidth - bar;
23376
+ var usedWidth = widthAvailable - requiredWidth;
23377
+
23378
+ // Control column needs to always be included. This makes it sub-
23379
+ // optimal in terms of using the available with, but to stop layout
23380
+ // thrashing or overflow. Also we need to account for the control column
23381
+ // width first so we know how much width is available for the other
23382
+ // columns, since the control column might not be the first one shown
23383
+ for ( i=0, ien=display.length ; i<ien ; i++ ) {
23384
+ if ( columns[i].control ) {
23385
+ usedWidth -= columns[i].minWidth;
23386
+ }
23387
+ }
23388
+
23389
+ // Allow columns to be shown (counting by priority and then right to
23390
+ // left) until we run out of room
23391
+ var empty = false;
23392
+ for ( i=0, ien=order.length ; i<ien ; i++ ) {
23393
+ var colIdx = order[i].columnIdx;
23394
+
23395
+ if ( display[colIdx] === '-' && ! columns[colIdx].control && columns[colIdx].minWidth ) {
23396
+ // Once we've found a column that won't fit we don't let any
23397
+ // others display either, or columns might disappear in the
23398
+ // middle of the table
23399
+ if ( empty || usedWidth - columns[colIdx].minWidth < 0 ) {
23400
+ empty = true;
23401
+ display[colIdx] = false;
23402
+ }
23403
+ else {
23404
+ display[colIdx] = true;
23405
+ }
23406
+
23407
+ usedWidth -= columns[colIdx].minWidth;
23408
+ }
23409
+ }
23410
+
23411
+ // Determine if the 'control' column should be shown (if there is one).
23412
+ // This is the case when there is a hidden column (that is not the
23413
+ // control column). The two loops look inefficient here, but they are
23414
+ // trivial and will fly through. We need to know the outcome from the
23415
+ // first , before the action in the second can be taken
23416
+ var showControl = false;
23417
+
23418
+ for ( i=0, ien=columns.length ; i<ien ; i++ ) {
23419
+ if ( ! columns[i].control && ! columns[i].never && ! display[i] ) {
23420
+ showControl = true;
23421
+ break;
23422
+ }
23423
+ }
23424
+
23425
+ for ( i=0, ien=columns.length ; i<ien ; i++ ) {
23426
+ if ( columns[i].control ) {
23427
+ display[i] = showControl;
23428
+ }
23429
+ }
23430
+
23431
+ // Finally we need to make sure that there is at least one column that
23432
+ // is visible
23433
+ if ( $.inArray( true, display ) === -1 ) {
23434
+ display[0] = true;
23435
+ }
23436
+
23437
+ return display;
23438
+ },
23439
+
23440
+
23441
+ /**
23442
+ * Create the internal `columns` array with information about the columns
23443
+ * for the table. This includes determining which breakpoints the column
23444
+ * will appear in, based upon class names in the column, which makes up the
23445
+ * vast majority of this method.
23446
+ *
23447
+ * @private
23448
+ */
23449
+ _classLogic: function ()
23450
+ {
23451
+ var that = this;
23452
+ var calc = {};
23453
+ var breakpoints = this.c.breakpoints;
23454
+ var dt = this.s.dt;
23455
+ var columns = dt.columns().eq(0).map( function (i) {
23456
+ var column = this.column(i);
23457
+ var className = column.header().className;
23458
+ var priority = dt.settings()[0].aoColumns[i].responsivePriority;
23459
+
23460
+ if ( priority === undefined ) {
23461
+ var dataPriority = $(column.header()).data('priority');
23462
+
23463
+ priority = dataPriority !== undefined ?
23464
+ dataPriority * 1 :
23465
+ 10000;
23466
+ }
23467
+
23468
+ return {
23469
+ className: className,
23470
+ includeIn: [],
23471
+ auto: false,
23472
+ control: false,
23473
+ never: className.match(/\bnever\b/) ? true : false,
23474
+ priority: priority
23475
+ };
23476
+ } );
23477
+
23478
+ // Simply add a breakpoint to `includeIn` array, ensuring that there are
23479
+ // no duplicates
23480
+ var add = function ( colIdx, name ) {
23481
+ var includeIn = columns[ colIdx ].includeIn;
23482
+
23483
+ if ( $.inArray( name, includeIn ) === -1 ) {
23484
+ includeIn.push( name );
23485
+ }
23486
+ };
23487
+
23488
+ var column = function ( colIdx, name, operator, matched ) {
23489
+ var size, i, ien;
23490
+
23491
+ if ( ! operator ) {
23492
+ columns[ colIdx ].includeIn.push( name );
23493
+ }
23494
+ else if ( operator === 'max-' ) {
23495
+ // Add this breakpoint and all smaller
23496
+ size = that._find( name ).width;
23497
+
23498
+ for ( i=0, ien=breakpoints.length ; i<ien ; i++ ) {
23499
+ if ( breakpoints[i].width <= size ) {
23500
+ add( colIdx, breakpoints[i].name );
23501
+ }
23502
+ }
23503
+ }
23504
+ else if ( operator === 'min-' ) {
23505
+ // Add this breakpoint and all larger
23506
+ size = that._find( name ).width;
23507
+
23508
+ for ( i=0, ien=breakpoints.length ; i<ien ; i++ ) {
23509
+ if ( breakpoints[i].width >= size ) {
23510
+ add( colIdx, breakpoints[i].name );
23511
+ }
23512
+ }
23513
+ }
23514
+ else if ( operator === 'not-' ) {
23515
+ // Add all but this breakpoint
23516
+ for ( i=0, ien=breakpoints.length ; i<ien ; i++ ) {
23517
+ if ( breakpoints[i].name.indexOf( matched ) === -1 ) {
23518
+ add( colIdx, breakpoints[i].name );
23519
+ }
23520
+ }
23521
+ }
23522
+ };
23523
+
23524
+ // Loop over each column and determine if it has a responsive control
23525
+ // class
23526
+ columns.each( function ( col, i ) {
23527
+ var classNames = col.className.split(' ');
23528
+ var hasClass = false;
23529
+
23530
+ // Split the class name up so multiple rules can be applied if needed
23531
+ for ( var k=0, ken=classNames.length ; k<ken ; k++ ) {
23532
+ var className = $.trim( classNames[k] );
23533
+
23534
+ if ( className === 'all' ) {
23535
+ // Include in all
23536
+ hasClass = true;
23537
+ col.includeIn = $.map( breakpoints, function (a) {
23538
+ return a.name;
23539
+ } );
23540
+ return;
23541
+ }
23542
+ else if ( className === 'none' || col.never ) {
23543
+ // Include in none (default) and no auto
23544
+ hasClass = true;
23545
+ return;
23546
+ }
23547
+ else if ( className === 'control' ) {
23548
+ // Special column that is only visible, when one of the other
23549
+ // columns is hidden. This is used for the details control
23550
+ hasClass = true;
23551
+ col.control = true;
23552
+ return;
23553
+ }
23554
+
23555
+ $.each( breakpoints, function ( j, breakpoint ) {
23556
+ // Does this column have a class that matches this breakpoint?
23557
+ var brokenPoint = breakpoint.name.split('-');
23558
+ var re = new RegExp( '(min\\-|max\\-|not\\-)?('+brokenPoint[0]+')(\\-[_a-zA-Z0-9])?' );
23559
+ var match = className.match( re );
23560
+
23561
+ if ( match ) {
23562
+ hasClass = true;
23563
+
23564
+ if ( match[2] === brokenPoint[0] && match[3] === '-'+brokenPoint[1] ) {
23565
+ // Class name matches breakpoint name fully
23566
+ column( i, breakpoint.name, match[1], match[2]+match[3] );
23567
+ }
23568
+ else if ( match[2] === brokenPoint[0] && ! match[3] ) {
23569
+ // Class name matched primary breakpoint name with no qualifier
23570
+ column( i, breakpoint.name, match[1], match[2] );
23571
+ }
23572
+ }
23573
+ } );
23574
+ }
23575
+
23576
+ // If there was no control class, then automatic sizing is used
23577
+ if ( ! hasClass ) {
23578
+ col.auto = true;
23579
+ }
23580
+ } );
23581
+
23582
+ this.s.columns = columns;
23583
+ },
23584
+
23585
+
23586
+ /**
23587
+ * Show the details for the child row
23588
+ *
23589
+ * @param {DataTables.Api} row API instance for the row
23590
+ * @param {boolean} update Update flag
23591
+ * @private
23592
+ */
23593
+ _detailsDisplay: function ( row, update )
23594
+ {
23595
+ var that = this;
23596
+ var dt = this.s.dt;
23597
+ var details = this.c.details;
23598
+
23599
+ if ( details && details.type !== false ) {
23600
+ var res = details.display( row, update, function () {
23601
+ return details.renderer(
23602
+ dt, row[0], that._detailsObj(row[0])
23603
+ );
23604
+ } );
23605
+
23606
+ if ( res === true || res === false ) {
23607
+ $(dt.table().node()).triggerHandler( 'responsive-display.dt', [dt, row, res, update] );
23608
+ }
23609
+ }
23610
+ },
23611
+
23612
+
23613
+ /**
23614
+ * Initialisation for the details handler
23615
+ *
23616
+ * @private
23617
+ */
23618
+ _detailsInit: function ()
23619
+ {
23620
+ var that = this;
23621
+ var dt = this.s.dt;
23622
+ var details = this.c.details;
23623
+
23624
+ // The inline type always uses the first child as the target
23625
+ if ( details.type === 'inline' ) {
23626
+ details.target = 'td:first-child, th:first-child';
23627
+ }
23628
+
23629
+ // Keyboard accessibility
23630
+ dt.on( 'draw.dtr', function () {
23631
+ that._tabIndexes();
23632
+ } );
23633
+ that._tabIndexes(); // Initial draw has already happened
23634
+
23635
+ $( dt.table().body() ).on( 'keyup.dtr', 'td, th', function (e) {
23636
+ if ( e.keyCode === 13 && $(this).data('dtr-keyboard') ) {
23637
+ $(this).click();
23638
+ }
23639
+ } );
23640
+
23641
+ // type.target can be a string jQuery selector or a column index
23642
+ var target = details.target;
23643
+ var selector = typeof target === 'string' ? target : 'td, th';
23644
+
23645
+ // Click handler to show / hide the details rows when they are available
23646
+ $( dt.table().body() )
23647
+ .on( 'click.dtr mousedown.dtr mouseup.dtr', selector, function (e) {
23648
+ // If the table is not collapsed (i.e. there is no hidden columns)
23649
+ // then take no action
23650
+ if ( ! $(dt.table().node()).hasClass('collapsed' ) ) {
23651
+ return;
23652
+ }
23653
+
23654
+ // Check that the row is actually a DataTable's controlled node
23655
+ if ( $.inArray( $(this).closest('tr').get(0), dt.rows().nodes().toArray() ) === -1 ) {
23656
+ return;
23657
+ }
23658
+
23659
+ // For column index, we determine if we should act or not in the
23660
+ // handler - otherwise it is already okay
23661
+ if ( typeof target === 'number' ) {
23662
+ var targetIdx = target < 0 ?
23663
+ dt.columns().eq(0).length + target :
23664
+ target;
23665
+
23666
+ if ( dt.cell( this ).index().column !== targetIdx ) {
23667
+ return;
23668
+ }
23669
+ }
23670
+
23671
+ // $().closest() includes itself in its check
23672
+ var row = dt.row( $(this).closest('tr') );
23673
+
23674
+ // Check event type to do an action
23675
+ if ( e.type === 'click' ) {
23676
+ // The renderer is given as a function so the caller can execute it
23677
+ // only when they need (i.e. if hiding there is no point is running
23678
+ // the renderer)
23679
+ that._detailsDisplay( row, false );
23680
+ }
23681
+ else if ( e.type === 'mousedown' ) {
23682
+ // For mouse users, prevent the focus ring from showing
23683
+ $(this).css('outline', 'none');
23684
+ }
23685
+ else if ( e.type === 'mouseup' ) {
23686
+ // And then re-allow at the end of the click
23687
+ $(this).blur().css('outline', '');
23688
+ }
23689
+ } );
23690
+ },
23691
+
23692
+
23693
+ /**
23694
+ * Get the details to pass to a renderer for a row
23695
+ * @param {int} rowIdx Row index
23696
+ * @private
23697
+ */
23698
+ _detailsObj: function ( rowIdx )
23699
+ {
23700
+ var that = this;
23701
+ var dt = this.s.dt;
23702
+
23703
+ return $.map( this.s.columns, function( col, i ) {
23704
+ // Never and control columns should not be passed to the renderer
23705
+ if ( col.never || col.control ) {
23706
+ return;
23707
+ }
23708
+
23709
+ return {
23710
+ title: dt.settings()[0].aoColumns[ i ].sTitle,
23711
+ data: dt.cell( rowIdx, i ).render( that.c.orthogonal ),
23712
+ hidden: dt.column( i ).visible() && !that.s.current[ i ],
23713
+ columnIndex: i,
23714
+ rowIndex: rowIdx
23715
+ };
23716
+ } );
23717
+ },
23718
+
23719
+
23720
+ /**
23721
+ * Find a breakpoint object from a name
23722
+ *
23723
+ * @param {string} name Breakpoint name to find
23724
+ * @return {object} Breakpoint description object
23725
+ * @private
23726
+ */
23727
+ _find: function ( name )
23728
+ {
23729
+ var breakpoints = this.c.breakpoints;
23730
+
23731
+ for ( var i=0, ien=breakpoints.length ; i<ien ; i++ ) {
23732
+ if ( breakpoints[i].name === name ) {
23733
+ return breakpoints[i];
23734
+ }
23735
+ }
23736
+ },
23737
+
23738
+
23739
+ /**
23740
+ * Re-create the contents of the child rows as the display has changed in
23741
+ * some way.
23742
+ *
23743
+ * @private
23744
+ */
23745
+ _redrawChildren: function ()
23746
+ {
23747
+ var that = this;
23748
+ var dt = this.s.dt;
23749
+
23750
+ dt.rows( {page: 'current'} ).iterator( 'row', function ( settings, idx ) {
23751
+ var row = dt.row( idx );
23752
+
23753
+ that._detailsDisplay( dt.row( idx ), true );
23754
+ } );
23755
+ },
23756
+
23757
+
23758
+ /**
23759
+ * Alter the table display for a resized viewport. This involves first
23760
+ * determining what breakpoint the window currently is in, getting the
23761
+ * column visibilities to apply and then setting them.
23762
+ *
23763
+ * @private
23764
+ */
23765
+ _resize: function ()
23766
+ {
23767
+ var that = this;
23768
+ var dt = this.s.dt;
23769
+ var width = $(window).width();
23770
+ var breakpoints = this.c.breakpoints;
23771
+ var breakpoint = breakpoints[0].name;
23772
+ var columns = this.s.columns;
23773
+ var i, ien;
23774
+ var oldVis = this.s.current.slice();
23775
+
23776
+ // Determine what breakpoint we are currently at
23777
+ for ( i=breakpoints.length-1 ; i>=0 ; i-- ) {
23778
+ if ( width <= breakpoints[i].width ) {
23779
+ breakpoint = breakpoints[i].name;
23780
+ break;
23781
+ }
23782
+ }
23783
+
23784
+ // Show the columns for that break point
23785
+ var columnsVis = this._columnsVisiblity( breakpoint );
23786
+ this.s.current = columnsVis;
23787
+
23788
+ // Set the class before the column visibility is changed so event
23789
+ // listeners know what the state is. Need to determine if there are
23790
+ // any columns that are not visible but can be shown
23791
+ var collapsedClass = false;
23792
+ for ( i=0, ien=columns.length ; i<ien ; i++ ) {
23793
+ if ( columnsVis[i] === false && ! columns[i].never && ! columns[i].control ) {
23794
+ collapsedClass = true;
23795
+ break;
23796
+ }
23797
+ }
23798
+
23799
+ $( dt.table().node() ).toggleClass( 'collapsed', collapsedClass );
23800
+
23801
+ var changed = false;
23802
+ var visible = 0;
23803
+
23804
+ dt.columns().eq(0).each( function ( colIdx, i ) {
23805
+ if ( columnsVis[i] === true ) {
23806
+ visible++;
23807
+ }
23808
+
23809
+ if ( columnsVis[i] !== oldVis[i] ) {
23810
+ changed = true;
23811
+ that._setColumnVis( colIdx, columnsVis[i] );
23812
+ }
23813
+ } );
23814
+
23815
+ if ( changed ) {
23816
+ this._redrawChildren();
23817
+
23818
+ // Inform listeners of the change
23819
+ $(dt.table().node()).trigger( 'responsive-resize.dt', [dt, this.s.current] );
23820
+
23821
+ // If no records, update the "No records" display element
23822
+ if ( dt.page.info().recordsDisplay === 0 ) {
23823
+ $('td', dt.table().body()).eq(0).attr('colspan', visible);
23824
+ }
23825
+ }
23826
+ },
23827
+
23828
+
23829
+ /**
23830
+ * Determine the width of each column in the table so the auto column hiding
23831
+ * has that information to work with. This method is never going to be 100%
23832
+ * perfect since column widths can change slightly per page, but without
23833
+ * seriously compromising performance this is quite effective.
23834
+ *
23835
+ * @private
23836
+ */
23837
+ _resizeAuto: function ()
23838
+ {
23839
+ var dt = this.s.dt;
23840
+ var columns = this.s.columns;
23841
+
23842
+ // Are we allowed to do auto sizing?
23843
+ if ( ! this.c.auto ) {
23844
+ return;
23845
+ }
23846
+
23847
+ // Are there any columns that actually need auto-sizing, or do they all
23848
+ // have classes defined
23849
+ if ( $.inArray( true, $.map( columns, function (c) { return c.auto; } ) ) === -1 ) {
23850
+ return;
23851
+ }
23852
+
23853
+ // Need to restore all children. They will be reinstated by a re-render
23854
+ if ( ! $.isEmptyObject( _childNodeStore ) ) {
23855
+ $.each( _childNodeStore, function ( key ) {
23856
+ var idx = key.split('-');
23857
+
23858
+ _childNodesRestore( dt, idx[0]*1, idx[1]*1 );
23859
+ } );
23860
+ }
23861
+
23862
+ // Clone the table with the current data in it
23863
+ var tableWidth = dt.table().node().offsetWidth;
23864
+ var columnWidths = dt.columns;
23865
+ var clonedTable = dt.table().node().cloneNode( false );
23866
+ var clonedHeader = $( dt.table().header().cloneNode( false ) ).appendTo( clonedTable );
23867
+ var clonedBody = $( dt.table().body() ).clone( false, false ).empty().appendTo( clonedTable ); // use jQuery because of IE8
23868
+
23869
+ // Header
23870
+ var headerCells = dt.columns()
23871
+ .header()
23872
+ .filter( function (idx) {
23873
+ return dt.column(idx).visible();
23874
+ } )
23875
+ .to$()
23876
+ .clone( false )
23877
+ .css( 'display', 'table-cell' )
23878
+ .css( 'min-width', 0 );
23879
+
23880
+ // Body rows - we don't need to take account of DataTables' column
23881
+ // visibility since we implement our own here (hence the `display` set)
23882
+ $(clonedBody)
23883
+ .append( $(dt.rows( { page: 'current' } ).nodes()).clone( false ) )
23884
+ .find( 'th, td' ).css( 'display', '' );
23885
+
23886
+ // Footer
23887
+ var footer = dt.table().footer();
23888
+ if ( footer ) {
23889
+ var clonedFooter = $( footer.cloneNode( false ) ).appendTo( clonedTable );
23890
+ var footerCells = dt.columns()
23891
+ .footer()
23892
+ .filter( function (idx) {
23893
+ return dt.column(idx).visible();
23894
+ } )
23895
+ .to$()
23896
+ .clone( false )
23897
+ .css( 'display', 'table-cell' );
23898
+
23899
+ $('<tr/>')
23900
+ .append( footerCells )
23901
+ .appendTo( clonedFooter );
23902
+ }
23903
+
23904
+ $('<tr/>')
23905
+ .append( headerCells )
23906
+ .appendTo( clonedHeader );
23907
+
23908
+ // In the inline case extra padding is applied to the first column to
23909
+ // give space for the show / hide icon. We need to use this in the
23910
+ // calculation
23911
+ if ( this.c.details.type === 'inline' ) {
23912
+ $(clonedTable).addClass( 'dtr-inline collapsed' );
23913
+ }
23914
+
23915
+ // It is unsafe to insert elements with the same name into the DOM
23916
+ // multiple times. For example, cloning and inserting a checked radio
23917
+ // clears the chcecked state of the original radio.
23918
+ $( clonedTable ).find( '[name]' ).removeAttr( 'name' );
23919
+
23920
+ var inserted = $('<div/>')
23921
+ .css( {
23922
+ width: 1,
23923
+ height: 1,
23924
+ overflow: 'hidden',
23925
+ clear: 'both'
23926
+ } )
23927
+ .append( clonedTable );
23928
+
23929
+ inserted.insertBefore( dt.table().node() );
23930
+
23931
+ // The cloned header now contains the smallest that each column can be
23932
+ headerCells.each( function (i) {
23933
+ var idx = dt.column.index( 'fromVisible', i );
23934
+ columns[ idx ].minWidth = this.offsetWidth || 0;
23935
+ } );
23936
+
23937
+ inserted.remove();
23938
+ },
23939
+
23940
+ /**
23941
+ * Set a column's visibility.
23942
+ *
23943
+ * We don't use DataTables' column visibility controls in order to ensure
23944
+ * that column visibility can Responsive can no-exist. Since only IE8+ is
23945
+ * supported (and all evergreen browsers of course) the control of the
23946
+ * display attribute works well.
23947
+ *
23948
+ * @param {integer} col Column index
23949
+ * @param {boolean} showHide Show or hide (true or false)
23950
+ * @private
23951
+ */
23952
+ _setColumnVis: function ( col, showHide )
23953
+ {
23954
+ var dt = this.s.dt;
23955
+ var display = showHide ? '' : 'none'; // empty string will remove the attr
23956
+
23957
+ $( dt.column( col ).header() ).css( 'display', display );
23958
+ $( dt.column( col ).footer() ).css( 'display', display );
23959
+ dt.column( col ).nodes().to$().css( 'display', display );
23960
+
23961
+ // If the are child nodes stored, we might need to reinsert them
23962
+ if ( ! $.isEmptyObject( _childNodeStore ) ) {
23963
+ dt.cells( null, col ).indexes().each( function (idx) {
23964
+ _childNodesRestore( dt, idx.row, idx.column );
23965
+ } );
23966
+ }
23967
+ },
23968
+
23969
+
23970
+ /**
23971
+ * Update the cell tab indexes for keyboard accessibility. This is called on
23972
+ * every table draw - that is potentially inefficient, but also the least
23973
+ * complex option given that column visibility can change on the fly. Its a
23974
+ * shame user-focus was removed from CSS 3 UI, as it would have solved this
23975
+ * issue with a single CSS statement.
23976
+ *
23977
+ * @private
23978
+ */
23979
+ _tabIndexes: function ()
23980
+ {
23981
+ var dt = this.s.dt;
23982
+ var cells = dt.cells( { page: 'current' } ).nodes().to$();
23983
+ var ctx = dt.settings()[0];
23984
+ var target = this.c.details.target;
23985
+
23986
+ cells.filter( '[data-dtr-keyboard]' ).removeData( '[data-dtr-keyboard]' );
23987
+
23988
+ var selector = typeof target === 'number' ?
23989
+ ':eq('+target+')' :
23990
+ target;
23991
+
23992
+ // This is a bit of a hack - we need to limit the selected nodes to just
23993
+ // those of this table
23994
+ if ( selector === 'td:first-child, th:first-child' ) {
23995
+ selector = '>td:first-child, >th:first-child';
23996
+ }
23997
+
23998
+ $( selector, dt.rows( { page: 'current' } ).nodes() )
23999
+ .attr( 'tabIndex', ctx.iTabIndex )
24000
+ .data( 'dtr-keyboard', 1 );
24001
+ }
24002
+ } );
24003
+
24004
+
24005
+ /**
24006
+ * List of default breakpoints. Each item in the array is an object with two
24007
+ * properties:
24008
+ *
24009
+ * * `name` - the breakpoint name.
24010
+ * * `width` - the breakpoint width
24011
+ *
24012
+ * @name Responsive.breakpoints
24013
+ * @static
24014
+ */
24015
+ Responsive.breakpoints = [
24016
+ { name: 'desktop', width: Infinity },
24017
+ { name: 'tablet-l', width: 1024 },
24018
+ { name: 'tablet-p', width: 768 },
24019
+ { name: 'mobile-l', width: 480 },
24020
+ { name: 'mobile-p', width: 320 }
24021
+ ];
24022
+
24023
+
24024
+ /**
24025
+ * Display methods - functions which define how the hidden data should be shown
24026
+ * in the table.
24027
+ *
24028
+ * @namespace
24029
+ * @name Responsive.defaults
24030
+ * @static
24031
+ */
24032
+ Responsive.display = {
24033
+ childRow: function ( row, update, render ) {
24034
+ if ( update ) {
24035
+ if ( $(row.node()).hasClass('parent') ) {
24036
+ row.child( render(), 'child' ).show();
24037
+
24038
+ return true;
24039
+ }
24040
+ }
24041
+ else {
24042
+ if ( ! row.child.isShown() ) {
24043
+ row.child( render(), 'child' ).show();
24044
+ $( row.node() ).addClass( 'parent' );
24045
+
24046
+ return true;
24047
+ }
24048
+ else {
24049
+ row.child( false );
24050
+ $( row.node() ).removeClass( 'parent' );
24051
+
24052
+ return false;
24053
+ }
24054
+ }
24055
+ },
24056
+
24057
+ childRowImmediate: function ( row, update, render ) {
24058
+ if ( (! update && row.child.isShown()) || ! row.responsive.hasHidden() ) {
24059
+ // User interaction and the row is show, or nothing to show
24060
+ row.child( false );
24061
+ $( row.node() ).removeClass( 'parent' );
24062
+
24063
+ return false;
24064
+ }
24065
+ else {
24066
+ // Display
24067
+ row.child( render(), 'child' ).show();
24068
+ $( row.node() ).addClass( 'parent' );
24069
+
24070
+ return true;
24071
+ }
24072
+ },
24073
+
24074
+ // This is a wrapper so the modal options for Bootstrap and jQuery UI can
24075
+ // have options passed into them. This specific one doesn't need to be a
24076
+ // function but it is for consistency in the `modal` name
24077
+ modal: function ( options ) {
24078
+ return function ( row, update, render ) {
24079
+ if ( ! update ) {
24080
+ // Show a modal
24081
+ var close = function () {
24082
+ modal.remove(); // will tidy events for us
24083
+ $(document).off( 'keypress.dtr' );
24084
+ };
24085
+
24086
+ var modal = $('<div class="dtr-modal"/>')
24087
+ .append( $('<div class="dtr-modal-display"/>')
24088
+ .append( $('<div class="dtr-modal-content"/>')
24089
+ .append( render() )
24090
+ )
24091
+ .append( $('<div class="dtr-modal-close">&times;</div>' )
24092
+ .click( function () {
24093
+ close();
24094
+ } )
24095
+ )
24096
+ )
24097
+ .append( $('<div class="dtr-modal-background"/>')
24098
+ .click( function () {
24099
+ close();
24100
+ } )
24101
+ )
24102
+ .appendTo( 'body' );
24103
+
24104
+ $(document).on( 'keyup.dtr', function (e) {
24105
+ if ( e.keyCode === 27 ) {
24106
+ e.stopPropagation();
24107
+
24108
+ close();
24109
+ }
24110
+ } );
24111
+ }
24112
+ else {
24113
+ $('div.dtr-modal-content')
24114
+ .empty()
24115
+ .append( render() );
24116
+ }
24117
+
24118
+ if ( options && options.header ) {
24119
+ $('div.dtr-modal-content').prepend(
24120
+ '<h2>'+options.header( row )+'</h2>'
24121
+ );
24122
+ }
24123
+ };
24124
+ }
24125
+ };
24126
+
24127
+
24128
+ var _childNodeStore = {};
24129
+
24130
+ function _childNodes( dt, row, col ) {
24131
+ var name = row+'-'+col;
24132
+
24133
+ if ( _childNodeStore[ name ] ) {
24134
+ return _childNodeStore[ name ];
24135
+ }
24136
+
24137
+ // https://jsperf.com/childnodes-array-slice-vs-loop
24138
+ var nodes = [];
24139
+ var children = dt.cell( row, col ).node().childNodes;
24140
+ for ( var i=0, ien=children.length ; i<ien ; i++ ) {
24141
+ nodes.push( children[i] );
24142
+ }
24143
+
24144
+ _childNodeStore[ name ] = nodes;
24145
+
24146
+ return nodes;
24147
+ }
24148
+
24149
+ function _childNodesRestore( dt, row, col ) {
24150
+ var name = row+'-'+col;
24151
+
24152
+ if ( ! _childNodeStore[ name ] ) {
24153
+ return;
24154
+ }
24155
+
24156
+ var node = dt.cell( row, col ).node();
24157
+ var store = _childNodeStore[ name ];
24158
+ var parent = store[0].parentNode;
24159
+ var parentChildren = parent.childNodes;
24160
+ var a = [];
24161
+
24162
+ for ( var i=0, ien=parentChildren.length ; i<ien ; i++ ) {
24163
+ a.push( parentChildren[i] );
24164
+ }
24165
+
24166
+ for ( var j=0, jen=a.length ; j<jen ; j++ ) {
24167
+ node.appendChild( a[j] );
24168
+ }
24169
+
24170
+ _childNodeStore[ name ] = undefined;
24171
+ }
24172
+
24173
+
24174
+ /**
24175
+ * Display methods - functions which define how the hidden data should be shown
24176
+ * in the table.
24177
+ *
24178
+ * @namespace
24179
+ * @name Responsive.defaults
24180
+ * @static
24181
+ */
24182
+ Responsive.renderer = {
24183
+ listHiddenNodes: function () {
24184
+ return function ( api, rowIdx, columns ) {
24185
+ var ul = $('<ul data-dtr-index="'+rowIdx+'" class="dtr-details"/>');
24186
+ var found = false;
24187
+
24188
+ var data = $.each( columns, function ( i, col ) {
24189
+ if ( col.hidden ) {
24190
+ $(
24191
+ '<li data-dtr-index="'+col.columnIndex+'" data-dt-row="'+col.rowIndex+'" data-dt-column="'+col.columnIndex+'">'+
24192
+ '<span class="dtr-title">'+
24193
+ col.title+
24194
+ '</span> '+
24195
+ '</li>'
24196
+ )
24197
+ .append( $('<span class="dtr-data"/>').append( _childNodes( api, col.rowIndex, col.columnIndex ) ) )// api.cell( col.rowIndex, col.columnIndex ).node().childNodes ) )
24198
+ .appendTo( ul );
24199
+
24200
+ found = true;
24201
+ }
24202
+ } );
24203
+
24204
+ return found ?
24205
+ ul :
24206
+ false;
24207
+ };
24208
+ },
24209
+
24210
+ listHidden: function () {
24211
+ return function ( api, rowIdx, columns ) {
24212
+ var data = $.map( columns, function ( col ) {
24213
+ return col.hidden ?
24214
+ '<li data-dtr-index="'+col.columnIndex+'" data-dt-row="'+col.rowIndex+'" data-dt-column="'+col.columnIndex+'">'+
24215
+ '<span class="dtr-title">'+
24216
+ col.title+
24217
+ '</span> '+
24218
+ '<span class="dtr-data">'+
24219
+ col.data+
24220
+ '</span>'+
24221
+ '</li>' :
24222
+ '';
24223
+ } ).join('');
24224
+
24225
+ return data ?
24226
+ $('<ul data-dtr-index="'+rowIdx+'" class="dtr-details"/>').append( data ) :
24227
+ false;
24228
+ }
24229
+ },
24230
+
24231
+ tableAll: function ( options ) {
24232
+ options = $.extend( {
24233
+ tableClass: ''
24234
+ }, options );
24235
+
24236
+ return function ( api, rowIdx, columns ) {
24237
+ var data = $.map( columns, function ( col ) {
24238
+ return '<tr data-dt-row="'+col.rowIndex+'" data-dt-column="'+col.columnIndex+'">'+
24239
+ '<td>'+col.title+':'+'</td> '+
24240
+ '<td>'+col.data+'</td>'+
24241
+ '</tr>';
24242
+ } ).join('');
24243
+
24244
+ return $('<table class="'+options.tableClass+' dtr-details" width="100%"/>').append( data );
24245
+ }
24246
+ }
24247
+ };
24248
+
24249
+ /**
24250
+ * Responsive default settings for initialisation
24251
+ *
24252
+ * @namespace
24253
+ * @name Responsive.defaults
24254
+ * @static
24255
+ */
24256
+ Responsive.defaults = {
24257
+ /**
24258
+ * List of breakpoints for the instance. Note that this means that each
24259
+ * instance can have its own breakpoints. Additionally, the breakpoints
24260
+ * cannot be changed once an instance has been creased.
24261
+ *
24262
+ * @type {Array}
24263
+ * @default Takes the value of `Responsive.breakpoints`
24264
+ */
24265
+ breakpoints: Responsive.breakpoints,
24266
+
24267
+ /**
24268
+ * Enable / disable auto hiding calculations. It can help to increase
24269
+ * performance slightly if you disable this option, but all columns would
24270
+ * need to have breakpoint classes assigned to them
24271
+ *
24272
+ * @type {Boolean}
24273
+ * @default `true`
24274
+ */
24275
+ auto: true,
24276
+
24277
+ /**
24278
+ * Details control. If given as a string value, the `type` property of the
24279
+ * default object is set to that value, and the defaults used for the rest
24280
+ * of the object - this is for ease of implementation.
24281
+ *
24282
+ * The object consists of the following properties:
24283
+ *
24284
+ * * `display` - A function that is used to show and hide the hidden details
24285
+ * * `renderer` - function that is called for display of the child row data.
24286
+ * The default function will show the data from the hidden columns
24287
+ * * `target` - Used as the selector for what objects to attach the child
24288
+ * open / close to
24289
+ * * `type` - `false` to disable the details display, `inline` or `column`
24290
+ * for the two control types
24291
+ *
24292
+ * @type {Object|string}
24293
+ */
24294
+ details: {
24295
+ display: Responsive.display.childRow,
24296
+
24297
+ renderer: Responsive.renderer.listHidden(),
24298
+
24299
+ target: 0,
24300
+
24301
+ type: 'inline'
24302
+ },
24303
+
24304
+ /**
24305
+ * Orthogonal data request option. This is used to define the data type
24306
+ * requested when Responsive gets the data to show in the child row.
24307
+ *
24308
+ * @type {String}
24309
+ */
24310
+ orthogonal: 'display'
24311
+ };
24312
+
24313
+
24314
+ /*
24315
+ * API
24316
+ */
24317
+ var Api = $.fn.dataTable.Api;
24318
+
24319
+ // Doesn't do anything - work around for a bug in DT... Not documented
24320
+ Api.register( 'responsive()', function () {
24321
+ return this;
24322
+ } );
24323
+
24324
+ Api.register( 'responsive.index()', function ( li ) {
24325
+ li = $(li);
24326
+
24327
+ return {
24328
+ column: li.data('dtr-index'),
24329
+ row: li.parent().data('dtr-index')
24330
+ };
24331
+ } );
24332
+
24333
+ Api.register( 'responsive.rebuild()', function () {
24334
+ return this.iterator( 'table', function ( ctx ) {
24335
+ if ( ctx._responsive ) {
24336
+ ctx._responsive._classLogic();
24337
+ }
24338
+ } );
24339
+ } );
24340
+
24341
+ Api.register( 'responsive.recalc()', function () {
24342
+ return this.iterator( 'table', function ( ctx ) {
24343
+ if ( ctx._responsive ) {
24344
+ ctx._responsive._resizeAuto();
24345
+ ctx._responsive._resize();
24346
+ }
24347
+ } );
24348
+ } );
24349
+
24350
+ Api.register( 'responsive.hasHidden()', function () {
24351
+ var ctx = this.context[0];
24352
+
24353
+ return ctx._responsive ?
24354
+ $.inArray( false, ctx._responsive.s.current ) !== -1 :
24355
+ false;
24356
+ } );
24357
+
24358
+ Api.registerPlural( 'columns().responsiveHidden()', 'column().responsiveHidden()', function () {
24359
+ return this.iterator( 'column', function ( settings, column ) {
24360
+ return settings._responsive ?
24361
+ settings._responsive.s.current[ column ] :
24362
+ false;
24363
+ }, 1 );
24364
+ } );
24365
+
24366
+
24367
+ /**
24368
+ * Version information
24369
+ *
24370
+ * @name Responsive.version
24371
+ * @static
24372
+ */
24373
+ Responsive.version = '2.2.1';
24374
+
24375
+
24376
+ $.fn.dataTable.Responsive = Responsive;
24377
+ $.fn.DataTable.Responsive = Responsive;
24378
+
24379
+ // Attach a listener to the document which listens for DataTables initialisation
24380
+ // events so we can automatically initialise
24381
+ $(document).on( 'preInit.dt.dtr', function (e, settings, json) {
24382
+ if ( e.namespace !== 'dt' ) {
24383
+ return;
24384
+ }
24385
+
24386
+ if ( $(settings.nTable).hasClass( 'responsive' ) ||
24387
+ $(settings.nTable).hasClass( 'dt-responsive' ) ||
24388
+ settings.oInit.responsive ||
24389
+ DataTable.defaults.responsive
24390
+ ) {
24391
+ var init = settings.oInit.responsive;
24392
+
24393
+ if ( init !== false ) {
24394
+ new Responsive( settings, $.isPlainObject( init ) ? init : {} );
24395
+ }
24396
+ }
24397
+ } );
24398
+
24399
+
24400
+ return Responsive;
24401
+ }));
24402
+
24403
+
24404
+ /*! RowReorder 1.2.3
24405
+ * 2015-2017 SpryMedia Ltd - datatables.net/license
24406
+ */
24407
+
24408
+ /**
24409
+ * @summary RowReorder
24410
+ * @description Row reordering extension for DataTables
24411
+ * @version 1.2.3
24412
+ * @file dataTables.rowReorder.js
24413
+ * @author SpryMedia Ltd (www.sprymedia.co.uk)
24414
+ * @contact www.sprymedia.co.uk/contact
24415
+ * @copyright Copyright 2015-2017 SpryMedia Ltd.
24416
+ *
24417
+ * This source file is free software, available under the following license:
24418
+ * MIT license - http://datatables.net/license/mit
24419
+ *
24420
+ * This source file is distributed in the hope that it will be useful, but
24421
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
24422
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
24423
+ *
24424
+ * For details please refer to: http://www.datatables.net
24425
+ */
24426
+
24427
+ (function( factory ){
24428
+ if ( typeof define === 'function' && define.amd ) {
24429
+ // AMD
24430
+ define( ['jquery', 'datatables.net'], function ( $ ) {
24431
+ return factory( $, window, document );
24432
+ } );
24433
+ }
24434
+ else if ( typeof exports === 'object' ) {
24435
+ // CommonJS
24436
+ module.exports = function (root, $) {
24437
+ if ( ! root ) {
24438
+ root = window;
24439
+ }
24440
+
24441
+ if ( ! $ || ! $.fn.dataTable ) {
24442
+ $ = require('datatables.net')(root, $).$;
24443
+ }
24444
+
24445
+ return factory( $, root, root.document );
24446
+ };
24447
+ }
24448
+ else {
24449
+ // Browser
24450
+ factory( jQuery, window, document );
24451
+ }
24452
+ }(function( $, window, document, undefined ) {
24453
+ 'use strict';
24454
+ var DataTable = $.fn.dataTable;
24455
+
24456
+
24457
+ /**
24458
+ * RowReorder provides the ability in DataTables to click and drag rows to
24459
+ * reorder them. When a row is dropped the data for the rows effected will be
24460
+ * updated to reflect the change. Normally this data point should also be the
24461
+ * column being sorted upon in the DataTable but this does not need to be the
24462
+ * case. RowReorder implements a "data swap" method - so the rows being
24463
+ * reordered take the value of the data point from the row that used to occupy
24464
+ * the row's new position.
24465
+ *
24466
+ * Initialisation is done by either:
24467
+ *
24468
+ * * `rowReorder` parameter in the DataTable initialisation object
24469
+ * * `new $.fn.dataTable.RowReorder( table, opts )` after DataTables
24470
+ * initialisation.
24471
+ *
24472
+ * @class
24473
+ * @param {object} settings DataTables settings object for the host table
24474
+ * @param {object} [opts] Configuration options
24475
+ * @requires jQuery 1.7+
24476
+ * @requires DataTables 1.10.7+
24477
+ */
24478
+ var RowReorder = function ( dt, opts ) {
24479
+ // Sanity check that we are using DataTables 1.10 or newer
24480
+ if ( ! DataTable.versionCheck || ! DataTable.versionCheck( '1.10.8' ) ) {
24481
+ throw 'DataTables RowReorder requires DataTables 1.10.8 or newer';
24482
+ }
24483
+
24484
+ // User and defaults configuration object
24485
+ this.c = $.extend( true, {},
24486
+ DataTable.defaults.rowReorder,
24487
+ RowReorder.defaults,
24488
+ opts
24489
+ );
24490
+
24491
+ // Internal settings
24492
+ this.s = {
24493
+ /** @type {integer} Scroll body top cache */
24494
+ bodyTop: null,
24495
+
24496
+ /** @type {DataTable.Api} DataTables' API instance */
24497
+ dt: new DataTable.Api( dt ),
24498
+
24499
+ /** @type {function} Data fetch function */
24500
+ getDataFn: DataTable.ext.oApi._fnGetObjectDataFn( this.c.dataSrc ),
24501
+
24502
+ /** @type {array} Pixel positions for row insertion calculation */
24503
+ middles: null,
24504
+
24505
+ /** @type {Object} Cached dimension information for use in the mouse move event handler */
24506
+ scroll: {},
24507
+
24508
+ /** @type {integer} Interval object used for smooth scrolling */
24509
+ scrollInterval: null,
24510
+
24511
+ /** @type {function} Data set function */
24512
+ setDataFn: DataTable.ext.oApi._fnSetObjectDataFn( this.c.dataSrc ),
24513
+
24514
+ /** @type {Object} Mouse down information */
24515
+ start: {
24516
+ top: 0,
24517
+ left: 0,
24518
+ offsetTop: 0,
24519
+ offsetLeft: 0,
24520
+ nodes: []
24521
+ },
24522
+
24523
+ /** @type {integer} Window height cached value */
24524
+ windowHeight: 0,
24525
+
24526
+ /** @type {integer} Document outer height cached value */
24527
+ documentOuterHeight: 0,
24528
+
24529
+ /** @type {integer} DOM clone outer height cached value */
24530
+ domCloneOuterHeight: 0
24531
+ };
24532
+
24533
+ // DOM items
24534
+ this.dom = {
24535
+ /** @type {jQuery} Cloned row being moved around */
24536
+ clone: null,
24537
+
24538
+ /** @type {jQuery} DataTables scrolling container */
24539
+ dtScroll: $('div.dataTables_scrollBody', this.s.dt.table().container())
24540
+ };
24541
+
24542
+ // Check if row reorder has already been initialised on this table
24543
+ var settings = this.s.dt.settings()[0];
24544
+ var exisiting = settings.rowreorder;
24545
+ if ( exisiting ) {
24546
+ return exisiting;
24547
+ }
24548
+
24549
+ settings.rowreorder = this;
24550
+ this._constructor();
24551
+ };
24552
+
24553
+
24554
+ $.extend( RowReorder.prototype, {
24555
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
24556
+ * Constructor
24557
+ */
24558
+
24559
+ /**
24560
+ * Initialise the RowReorder instance
24561
+ *
24562
+ * @private
24563
+ */
24564
+ _constructor: function ()
24565
+ {
24566
+ var that = this;
24567
+ var dt = this.s.dt;
24568
+ var table = $( dt.table().node() );
24569
+
24570
+ // Need to be able to calculate the row positions relative to the table
24571
+ if ( table.css('position') === 'static' ) {
24572
+ table.css( 'position', 'relative' );
24573
+ }
24574
+
24575
+ // listen for mouse down on the target column - we have to implement
24576
+ // this rather than using HTML5 drag and drop as drag and drop doesn't
24577
+ // appear to work on table rows at this time. Also mobile browsers are
24578
+ // not supported.
24579
+ // Use `table().container()` rather than just the table node for IE8 -
24580
+ // otherwise it only works once...
24581
+ $(dt.table().container()).on( 'mousedown.rowReorder touchstart.rowReorder', this.c.selector, function (e) {
24582
+ if ( ! that.c.enable ) {
24583
+ return;
24584
+ }
24585
+
24586
+ var tr = $(this).closest('tr');
24587
+ var row = dt.row( tr );
24588
+
24589
+ // Double check that it is a DataTable row
24590
+ if ( row.any() ) {
24591
+ that._emitEvent( 'pre-row-reorder', {
24592
+ node: row.node(),
24593
+ index: row.index()
24594
+ } );
24595
+
24596
+ that._mouseDown( e, tr );
24597
+ return false;
24598
+ }
24599
+ } );
24600
+
24601
+ dt.on( 'destroy.rowReorder', function () {
24602
+ $(dt.table().container()).off( '.rowReorder' );
24603
+ dt.off( '.rowReorder' );
24604
+ } );
24605
+ },
24606
+
24607
+
24608
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
24609
+ * Private methods
24610
+ */
24611
+
24612
+ /**
24613
+ * Cache the measurements that RowReorder needs in the mouse move handler
24614
+ * to attempt to speed things up, rather than reading from the DOM.
24615
+ *
24616
+ * @private
24617
+ */
24618
+ _cachePositions: function ()
24619
+ {
24620
+ var dt = this.s.dt;
24621
+
24622
+ // Frustratingly, if we add `position:relative` to the tbody, the
24623
+ // position is still relatively to the parent. So we need to adjust
24624
+ // for that
24625
+ var headerHeight = $( dt.table().node() ).find('thead').outerHeight();
24626
+
24627
+ // Need to pass the nodes through jQuery to get them in document order,
24628
+ // not what DataTables thinks it is, since we have been altering the
24629
+ // order
24630
+ var nodes = $.unique( dt.rows( { page: 'current' } ).nodes().toArray() );
24631
+ var tops = $.map( nodes, function ( node, i ) {
24632
+ return $(node).position().top - headerHeight;
24633
+ } );
24634
+
24635
+ var middles = $.map( tops, function ( top, i ) {
24636
+ return tops.length < i-1 ?
24637
+ (top + tops[i+1]) / 2 :
24638
+ (top + top + $( dt.row( ':last-child' ).node() ).outerHeight() ) / 2;
24639
+ } );
24640
+
24641
+ this.s.middles = middles;
24642
+ this.s.bodyTop = $( dt.table().body() ).offset().top;
24643
+ this.s.windowHeight = $(window).height();
24644
+ this.s.documentOuterHeight = $(document).outerHeight();
24645
+ },
24646
+
24647
+
24648
+ /**
24649
+ * Clone a row so it can be floated around the screen
24650
+ *
24651
+ * @param {jQuery} target Node to be cloned
24652
+ * @private
24653
+ */
24654
+ _clone: function ( target )
24655
+ {
24656
+ var dt = this.s.dt;
24657
+ var clone = $( dt.table().node().cloneNode(false) )
24658
+ .addClass( 'dt-rowReorder-float' )
24659
+ .append('<tbody/>')
24660
+ .append( target.clone( false ) );
24661
+
24662
+ // Match the table and column widths - read all sizes before setting
24663
+ // to reduce reflows
24664
+ var tableWidth = target.outerWidth();
24665
+ var tableHeight = target.outerHeight();
24666
+ var sizes = target.children().map( function () {
24667
+ return $(this).width();
24668
+ } );
24669
+
24670
+ clone
24671
+ .width( tableWidth )
24672
+ .height( tableHeight )
24673
+ .find('tr').children().each( function (i) {
24674
+ this.style.width = sizes[i]+'px';
24675
+ } );
24676
+
24677
+ // Insert into the document to have it floating around
24678
+ clone.appendTo( 'body' );
24679
+
24680
+ this.dom.clone = clone;
24681
+ this.s.domCloneOuterHeight = clone.outerHeight();
24682
+ },
24683
+
24684
+
24685
+ /**
24686
+ * Update the cloned item's position in the document
24687
+ *
24688
+ * @param {object} e Event giving the mouse's position
24689
+ * @private
24690
+ */
24691
+ _clonePosition: function ( e )
24692
+ {
24693
+ var start = this.s.start;
24694
+ var topDiff = this._eventToPage( e, 'Y' ) - start.top;
24695
+ var leftDiff = this._eventToPage( e, 'X' ) - start.left;
24696
+ var snap = this.c.snapX;
24697
+ var left;
24698
+ var top = topDiff + start.offsetTop;
24699
+
24700
+ if ( snap === true ) {
24701
+ left = start.offsetLeft;
24702
+ }
24703
+ else if ( typeof snap === 'number' ) {
24704
+ left = start.offsetLeft + snap;
24705
+ }
24706
+ else {
24707
+ left = leftDiff + start.offsetLeft;
24708
+ }
24709
+
24710
+ if(top < 0) {
24711
+ top = 0
24712
+ }
24713
+ else if(top + this.s.domCloneOuterHeight > this.s.documentOuterHeight) {
24714
+ top = this.s.documentOuterHeight - this.s.domCloneOuterHeight;
24715
+ }
24716
+
24717
+ this.dom.clone.css( {
24718
+ top: top,
24719
+ left: left
24720
+ } );
24721
+ },
24722
+
24723
+
24724
+ /**
24725
+ * Emit an event on the DataTable for listeners
24726
+ *
24727
+ * @param {string} name Event name
24728
+ * @param {array} args Event arguments
24729
+ * @private
24730
+ */
24731
+ _emitEvent: function ( name, args )
24732
+ {
24733
+ this.s.dt.iterator( 'table', function ( ctx, i ) {
24734
+ $(ctx.nTable).triggerHandler( name+'.dt', args );
24735
+ } );
24736
+ },
24737
+
24738
+
24739
+ /**
24740
+ * Get pageX/Y position from an event, regardless of if it is a mouse or
24741
+ * touch event.
24742
+ *
24743
+ * @param {object} e Event
24744
+ * @param {string} pos X or Y (must be a capital)
24745
+ * @private
24746
+ */
24747
+ _eventToPage: function ( e, pos )
24748
+ {
24749
+ if ( e.type.indexOf( 'touch' ) !== -1 ) {
24750
+ return e.originalEvent.touches[0][ 'page'+pos ];
24751
+ }
24752
+
24753
+ return e[ 'page'+pos ];
24754
+ },
24755
+
24756
+
24757
+ /**
24758
+ * Mouse down event handler. Read initial positions and add event handlers
24759
+ * for the move.
24760
+ *
24761
+ * @param {object} e Mouse event
24762
+ * @param {jQuery} target TR element that is to be moved
24763
+ * @private
24764
+ */
24765
+ _mouseDown: function ( e, target )
24766
+ {
24767
+ var that = this;
24768
+ var dt = this.s.dt;
24769
+ var start = this.s.start;
24770
+
24771
+ var offset = target.offset();
24772
+ start.top = this._eventToPage( e, 'Y' );
24773
+ start.left = this._eventToPage( e, 'X' );
24774
+ start.offsetTop = offset.top;
24775
+ start.offsetLeft = offset.left;
24776
+ start.nodes = $.unique( dt.rows( { page: 'current' } ).nodes().toArray() );
24777
+
24778
+ this._cachePositions();
24779
+ this._clone( target );
24780
+ this._clonePosition( e );
24781
+
24782
+ this.dom.target = target;
24783
+ target.addClass( 'dt-rowReorder-moving' );
24784
+
24785
+ $( document )
24786
+ .on( 'mouseup.rowReorder touchend.rowReorder', function (e) {
24787
+ that._mouseUp(e);
24788
+ } )
24789
+ .on( 'mousemove.rowReorder touchmove.rowReorder', function (e) {
24790
+ that._mouseMove(e);
24791
+ } );
24792
+
24793
+ // Check if window is x-scrolling - if not, disable it for the duration
24794
+ // of the drag
24795
+ if ( $(window).width() === $(document).width() ) {
24796
+ $(document.body).addClass( 'dt-rowReorder-noOverflow' );
24797
+ }
24798
+
24799
+ // Cache scrolling information so mouse move doesn't need to read.
24800
+ // This assumes that the window and DT scroller will not change size
24801
+ // during an row drag, which I think is a fair assumption
24802
+ var scrollWrapper = this.dom.dtScroll;
24803
+ this.s.scroll = {
24804
+ windowHeight: $(window).height(),
24805
+ windowWidth: $(window).width(),
24806
+ dtTop: scrollWrapper.length ? scrollWrapper.offset().top : null,
24807
+ dtLeft: scrollWrapper.length ? scrollWrapper.offset().left : null,
24808
+ dtHeight: scrollWrapper.length ? scrollWrapper.outerHeight() : null,
24809
+ dtWidth: scrollWrapper.length ? scrollWrapper.outerWidth() : null
24810
+ };
24811
+ },
24812
+
24813
+
24814
+ /**
24815
+ * Mouse move event handler - move the cloned row and shuffle the table's
24816
+ * rows if required.
24817
+ *
24818
+ * @param {object} e Mouse event
24819
+ * @private
24820
+ */
24821
+ _mouseMove: function ( e )
24822
+ {
24823
+ this._clonePosition( e );
24824
+
24825
+ // Transform the mouse position into a position in the table's body
24826
+ var bodyY = this._eventToPage( e, 'Y' ) - this.s.bodyTop;
24827
+ var middles = this.s.middles;
24828
+ var insertPoint = null;
24829
+ var dt = this.s.dt;
24830
+ var body = dt.table().body();
24831
+
24832
+ // Determine where the row should be inserted based on the mouse
24833
+ // position
24834
+ for ( var i=0, ien=middles.length ; i<ien ; i++ ) {
24835
+ if ( bodyY < middles[i] ) {
24836
+ insertPoint = i;
24837
+ break;
24838
+ }
24839
+ }
24840
+
24841
+ if ( insertPoint === null ) {
24842
+ insertPoint = middles.length;
24843
+ }
24844
+
24845
+ // Perform the DOM shuffle if it has changed from last time
24846
+ if ( this.s.lastInsert === null || this.s.lastInsert !== insertPoint ) {
24847
+ if ( insertPoint === 0 ) {
24848
+ this.dom.target.prependTo( body );
24849
+ }
24850
+ else {
24851
+ var nodes = $.unique( dt.rows( { page: 'current' } ).nodes().toArray() );
24852
+
24853
+ if ( insertPoint > this.s.lastInsert ) {
24854
+ this.dom.target.insertAfter( nodes[ insertPoint-1 ] );
24855
+ }
24856
+ else {
24857
+ this.dom.target.insertBefore( nodes[ insertPoint ] );
24858
+ }
24859
+ }
24860
+
24861
+ this._cachePositions();
24862
+
24863
+ this.s.lastInsert = insertPoint;
24864
+ }
24865
+
24866
+ this._shiftScroll( e );
24867
+ },
24868
+
24869
+
24870
+ /**
24871
+ * Mouse up event handler - release the event handlers and perform the
24872
+ * table updates
24873
+ *
24874
+ * @param {object} e Mouse event
24875
+ * @private
24876
+ */
24877
+ _mouseUp: function ( e )
24878
+ {
24879
+ var that = this;
24880
+ var dt = this.s.dt;
24881
+ var i, ien;
24882
+ var dataSrc = this.c.dataSrc;
24883
+
24884
+ this.dom.clone.remove();
24885
+ this.dom.clone = null;
24886
+
24887
+ this.dom.target.removeClass( 'dt-rowReorder-moving' );
24888
+ //this.dom.target = null;
24889
+
24890
+ $(document).off( '.rowReorder' );
24891
+ $(document.body).removeClass( 'dt-rowReorder-noOverflow' );
24892
+
24893
+ clearInterval( this.s.scrollInterval );
24894
+ this.s.scrollInterval = null;
24895
+
24896
+ // Calculate the difference
24897
+ var startNodes = this.s.start.nodes;
24898
+ var endNodes = $.unique( dt.rows( { page: 'current' } ).nodes().toArray() );
24899
+ var idDiff = {};
24900
+ var fullDiff = [];
24901
+ var diffNodes = [];
24902
+ var getDataFn = this.s.getDataFn;
24903
+ var setDataFn = this.s.setDataFn;
24904
+
24905
+ for ( i=0, ien=startNodes.length ; i<ien ; i++ ) {
24906
+ if ( startNodes[i] !== endNodes[i] ) {
24907
+ var id = dt.row( endNodes[i] ).id();
24908
+ var endRowData = dt.row( endNodes[i] ).data();
24909
+ var startRowData = dt.row( startNodes[i] ).data();
24910
+
24911
+ if ( id ) {
24912
+ idDiff[ id ] = getDataFn( startRowData );
24913
+ }
24914
+
24915
+ fullDiff.push( {
24916
+ node: endNodes[i],
24917
+ oldData: getDataFn( endRowData ),
24918
+ newData: getDataFn( startRowData ),
24919
+ newPosition: i,
24920
+ oldPosition: $.inArray( endNodes[i], startNodes )
24921
+ } );
24922
+
24923
+ diffNodes.push( endNodes[i] );
24924
+ }
24925
+ }
24926
+
24927
+ // Create event args
24928
+ var eventArgs = [ fullDiff, {
24929
+ dataSrc: dataSrc,
24930
+ nodes: diffNodes,
24931
+ values: idDiff,
24932
+ triggerRow: dt.row( this.dom.target )
24933
+ } ];
24934
+
24935
+ // Emit event
24936
+ this._emitEvent( 'row-reorder', eventArgs );
24937
+
24938
+ var update = function () {
24939
+ if ( that.c.update ) {
24940
+ for ( i=0, ien=fullDiff.length ; i<ien ; i++ ) {
24941
+ var row = dt.row( fullDiff[i].node );
24942
+ var rowData = row.data();
24943
+
24944
+ setDataFn( rowData, fullDiff[i].newData );
24945
+
24946
+ // Invalidate the cell that has the same data source as the dataSrc
24947
+ dt.columns().every( function () {
24948
+ if ( this.dataSrc() === dataSrc ) {
24949
+ dt.cell( fullDiff[i].node, this.index() ).invalidate( 'data' );
24950
+ }
24951
+ } );
24952
+ }
24953
+
24954
+ // Trigger row reordered event
24955
+ that._emitEvent( 'row-reordered', eventArgs );
24956
+
24957
+ dt.draw( false );
24958
+ }
24959
+ };
24960
+
24961
+ // Editor interface
24962
+ if ( this.c.editor ) {
24963
+ // Disable user interaction while Editor is submitting
24964
+ this.c.enable = false;
24965
+
24966
+ this.c.editor
24967
+ .edit(
24968
+ diffNodes,
24969
+ false,
24970
+ $.extend( {submit: 'changed'}, this.c.formOptions )
24971
+ )
24972
+ .multiSet( dataSrc, idDiff )
24973
+ .one( 'submitUnsuccessful.rowReorder', function () {
24974
+ dt.draw( false );
24975
+ } )
24976
+ .one( 'submitSuccess.rowReorder', function () {
24977
+ update();
24978
+ } )
24979
+ .one( 'submitComplete', function () {
24980
+ that.c.enable = true;
24981
+ that.c.editor.off( '.rowReorder' );
24982
+ } )
24983
+ .submit();
24984
+ }
24985
+ else {
24986
+ update();
24987
+ }
24988
+ },
24989
+
24990
+
24991
+ /**
24992
+ * Move the window and DataTables scrolling during a drag to scroll new
24993
+ * content into view.
24994
+ *
24995
+ * This matches the `_shiftScroll` method used in AutoFill, but only
24996
+ * horizontal scrolling is considered here.
24997
+ *
24998
+ * @param {object} e Mouse move event object
24999
+ * @private
25000
+ */
25001
+ _shiftScroll: function ( e )
25002
+ {
25003
+ var that = this;
25004
+ var dt = this.s.dt;
25005
+ var scroll = this.s.scroll;
25006
+ var runInterval = false;
25007
+ var scrollSpeed = 5;
25008
+ var buffer = 65;
25009
+ var
25010
+ windowY = e.pageY - document.body.scrollTop,
25011
+ windowVert,
25012
+ dtVert;
25013
+
25014
+ // Window calculations - based on the mouse position in the window,
25015
+ // regardless of scrolling
25016
+ if ( windowY < buffer ) {
25017
+ windowVert = scrollSpeed * -1;
25018
+ }
25019
+ else if ( windowY > scroll.windowHeight - buffer ) {
25020
+ windowVert = scrollSpeed;
25021
+ }
25022
+
25023
+ // DataTables scrolling calculations - based on the table's position in
25024
+ // the document and the mouse position on the page
25025
+ if ( scroll.dtTop !== null && e.pageY < scroll.dtTop + buffer ) {
25026
+ dtVert = scrollSpeed * -1;
25027
+ }
25028
+ else if ( scroll.dtTop !== null && e.pageY > scroll.dtTop + scroll.dtHeight - buffer ) {
25029
+ dtVert = scrollSpeed;
25030
+ }
25031
+
25032
+ // This is where it gets interesting. We want to continue scrolling
25033
+ // without requiring a mouse move, so we need an interval to be
25034
+ // triggered. The interval should continue until it is no longer needed,
25035
+ // but it must also use the latest scroll commands (for example consider
25036
+ // that the mouse might move from scrolling up to scrolling left, all
25037
+ // with the same interval running. We use the `scroll` object to "pass"
25038
+ // this information to the interval. Can't use local variables as they
25039
+ // wouldn't be the ones that are used by an already existing interval!
25040
+ if ( windowVert || dtVert ) {
25041
+ scroll.windowVert = windowVert;
25042
+ scroll.dtVert = dtVert;
25043
+ runInterval = true;
25044
+ }
25045
+ else if ( this.s.scrollInterval ) {
25046
+ // Don't need to scroll - remove any existing timer
25047
+ clearInterval( this.s.scrollInterval );
25048
+ this.s.scrollInterval = null;
25049
+ }
25050
+
25051
+ // If we need to run the interval to scroll and there is no existing
25052
+ // interval (if there is an existing one, it will continue to run)
25053
+ if ( ! this.s.scrollInterval && runInterval ) {
25054
+ this.s.scrollInterval = setInterval( function () {
25055
+ // Don't need to worry about setting scroll <0 or beyond the
25056
+ // scroll bound as the browser will just reject that.
25057
+ if ( scroll.windowVert ) {
25058
+ document.body.scrollTop += scroll.windowVert;
25059
+ }
25060
+
25061
+ // DataTables scrolling
25062
+ if ( scroll.dtVert ) {
25063
+ var scroller = that.dom.dtScroll[0];
25064
+
25065
+ if ( scroll.dtVert ) {
25066
+ scroller.scrollTop += scroll.dtVert;
25067
+ }
25068
+ }
25069
+ }, 20 );
25070
+ }
25071
+ }
25072
+ } );
25073
+
25074
+
25075
+
25076
+ /**
25077
+ * RowReorder default settings for initialisation
25078
+ *
25079
+ * @namespace
25080
+ * @name RowReorder.defaults
25081
+ * @static
25082
+ */
25083
+ RowReorder.defaults = {
25084
+ /**
25085
+ * Data point in the host row's data source object for where to get and set
25086
+ * the data to reorder. This will normally also be the sorting column.
25087
+ *
25088
+ * @type {Number}
25089
+ */
25090
+ dataSrc: 0,
25091
+
25092
+ /**
25093
+ * Editor instance that will be used to perform the update
25094
+ *
25095
+ * @type {DataTable.Editor}
25096
+ */
25097
+ editor: null,
25098
+
25099
+ /**
25100
+ * Enable / disable RowReorder's user interaction
25101
+ * @type {Boolean}
25102
+ */
25103
+ enable: true,
25104
+
25105
+ /**
25106
+ * Form options to pass to Editor when submitting a change in the row order.
25107
+ * See the Editor `from-options` object for details of the options
25108
+ * available.
25109
+ * @type {Object}
25110
+ */
25111
+ formOptions: {},
25112
+
25113
+ /**
25114
+ * Drag handle selector. This defines the element that when dragged will
25115
+ * reorder a row.
25116
+ *
25117
+ * @type {String}
25118
+ */
25119
+ selector: 'td:first-child',
25120
+
25121
+ /**
25122
+ * Optionally lock the dragged row's x-position. This can be `true` to
25123
+ * fix the position match the host table's, `false` to allow free movement
25124
+ * of the row, or a number to define an offset from the host table.
25125
+ *
25126
+ * @type {Boolean|number}
25127
+ */
25128
+ snapX: false,
25129
+
25130
+ /**
25131
+ * Update the table's data on drop
25132
+ *
25133
+ * @type {Boolean}
25134
+ */
25135
+ update: true
25136
+ };
25137
+
25138
+
25139
+ /*
25140
+ * API
25141
+ */
25142
+ var Api = $.fn.dataTable.Api;
25143
+
25144
+ // Doesn't do anything - work around for a bug in DT... Not documented
25145
+ Api.register( 'rowReorder()', function () {
25146
+ return this;
25147
+ } );
25148
+
25149
+ Api.register( 'rowReorder.enable()', function ( toggle ) {
25150
+ if ( toggle === undefined ) {
25151
+ toggle = true;
25152
+ }
25153
+
25154
+ return this.iterator( 'table', function ( ctx ) {
25155
+ if ( ctx.rowreorder ) {
25156
+ ctx.rowreorder.c.enable = toggle;
25157
+ }
25158
+ } );
25159
+ } );
25160
+
25161
+ Api.register( 'rowReorder.disable()', function () {
25162
+ return this.iterator( 'table', function ( ctx ) {
25163
+ if ( ctx.rowreorder ) {
25164
+ ctx.rowreorder.c.enable = false;
25165
+ }
25166
+ } );
25167
+ } );
25168
+
25169
+
25170
+ /**
25171
+ * Version information
25172
+ *
25173
+ * @name RowReorder.version
25174
+ * @static
25175
+ */
25176
+ RowReorder.version = '1.2.3';
25177
+
25178
+
25179
+ $.fn.dataTable.RowReorder = RowReorder;
25180
+ $.fn.DataTable.RowReorder = RowReorder;
25181
+
25182
+ // Attach a listener to the document which listens for DataTables initialisation
25183
+ // events so we can automatically initialise
25184
+ $(document).on( 'init.dt.dtr', function (e, settings, json) {
25185
+ if ( e.namespace !== 'dt' ) {
25186
+ return;
25187
+ }
25188
+
25189
+ var init = settings.oInit.rowReorder;
25190
+ var defaults = DataTable.defaults.rowReorder;
25191
+
25192
+ if ( init || defaults ) {
25193
+ var opts = $.extend( {}, init, defaults );
25194
+
25195
+ if ( init !== false ) {
25196
+ new RowReorder( settings, opts );
25197
+ }
25198
+ }
25199
+ } );
25200
+
25201
+
25202
+ return RowReorder;
25203
+ }));
25204
+
25205
+
25206
+ /*! Scroller 1.4.4
25207
+ * ©2011-2018 SpryMedia Ltd - datatables.net/license
25208
+ */
25209
+
25210
+ /**
25211
+ * @summary Scroller
25212
+ * @description Virtual rendering for DataTables
25213
+ * @version 1.4.4
25214
+ * @file dataTables.scroller.js
25215
+ * @author SpryMedia Ltd (www.sprymedia.co.uk)
25216
+ * @contact www.sprymedia.co.uk/contact
25217
+ * @copyright Copyright 2011-2018 SpryMedia Ltd.
25218
+ *
25219
+ * This source file is free software, available under the following license:
25220
+ * MIT license - http://datatables.net/license/mit
25221
+ *
25222
+ * This source file is distributed in the hope that it will be useful, but
25223
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
25224
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
25225
+ *
25226
+ * For details please refer to: http://www.datatables.net
25227
+ */
25228
+
25229
+ (function( factory ){
25230
+ if ( typeof define === 'function' && define.amd ) {
25231
+ // AMD
25232
+ define( ['jquery', 'datatables.net'], function ( $ ) {
25233
+ return factory( $, window, document );
25234
+ } );
25235
+ }
25236
+ else if ( typeof exports === 'object' ) {
25237
+ // CommonJS
25238
+ module.exports = function (root, $) {
25239
+ if ( ! root ) {
25240
+ root = window;
25241
+ }
25242
+
25243
+ if ( ! $ || ! $.fn.dataTable ) {
25244
+ $ = require('datatables.net')(root, $).$;
25245
+ }
25246
+
25247
+ return factory( $, root, root.document );
25248
+ };
25249
+ }
25250
+ else {
25251
+ // Browser
25252
+ factory( jQuery, window, document );
25253
+ }
25254
+ }(function( $, window, document, undefined ) {
25255
+ 'use strict';
25256
+ var DataTable = $.fn.dataTable;
25257
+
25258
+
25259
+ /**
25260
+ * Scroller is a virtual rendering plug-in for DataTables which allows large
25261
+ * datasets to be drawn on screen every quickly. What the virtual rendering means
25262
+ * is that only the visible portion of the table (and a bit to either side to make
25263
+ * the scrolling smooth) is drawn, while the scrolling container gives the
25264
+ * visual impression that the whole table is visible. This is done by making use
25265
+ * of the pagination abilities of DataTables and moving the table around in the
25266
+ * scrolling container DataTables adds to the page. The scrolling container is
25267
+ * forced to the height it would be for the full table display using an extra
25268
+ * element.
25269
+ *
25270
+ * Note that rows in the table MUST all be the same height. Information in a cell
25271
+ * which expands on to multiple lines will cause some odd behaviour in the scrolling.
25272
+ *
25273
+ * Scroller is initialised by simply including the letter 'S' in the sDom for the
25274
+ * table you want to have this feature enabled on. Note that the 'S' must come
25275
+ * AFTER the 't' parameter in `dom`.
25276
+ *
25277
+ * Key features include:
25278
+ * <ul class="limit_length">
25279
+ * <li>Speed! The aim of Scroller for DataTables is to make rendering large data sets fast</li>
25280
+ * <li>Full compatibility with deferred rendering in DataTables for maximum speed</li>
25281
+ * <li>Display millions of rows</li>
25282
+ * <li>Integration with state saving in DataTables (scrolling position is saved)</li>
25283
+ * <li>Easy to use</li>
25284
+ * </ul>
25285
+ *
25286
+ * @class
25287
+ * @constructor
25288
+ * @global
25289
+ * @param {object} dt DataTables settings object or API instance
25290
+ * @param {object} [opts={}] Configuration object for FixedColumns. Options
25291
+ * are defined by {@link Scroller.defaults}
25292
+ *
25293
+ * @requires jQuery 1.7+
25294
+ * @requires DataTables 1.10.0+
25295
+ *
25296
+ * @example
25297
+ * $(document).ready(function() {
25298
+ * $('#example').DataTable( {
25299
+ * "scrollY": "200px",
25300
+ * "ajax": "media/dataset/large.txt",
25301
+ * "dom": "frtiS",
25302
+ * "deferRender": true
25303
+ * } );
25304
+ * } );
25305
+ */
25306
+ var Scroller = function ( dt, opts ) {
25307
+ /* Sanity check - you just know it will happen */
25308
+ if ( ! (this instanceof Scroller) ) {
25309
+ alert( "Scroller warning: Scroller must be initialised with the 'new' keyword." );
25310
+ return;
25311
+ }
25312
+
25313
+ if ( opts === undefined ) {
25314
+ opts = {};
25315
+ }
25316
+
25317
+ /**
25318
+ * Settings object which contains customisable information for the Scroller instance
25319
+ * @namespace
25320
+ * @private
25321
+ * @extends Scroller.defaults
25322
+ */
25323
+ this.s = {
25324
+ /**
25325
+ * DataTables settings object
25326
+ * @type object
25327
+ * @default Passed in as first parameter to constructor
25328
+ */
25329
+ "dt": $.fn.dataTable.Api( dt ).settings()[0],
25330
+
25331
+ /**
25332
+ * Pixel location of the top of the drawn table in the viewport
25333
+ * @type int
25334
+ * @default 0
25335
+ */
25336
+ "tableTop": 0,
25337
+
25338
+ /**
25339
+ * Pixel location of the bottom of the drawn table in the viewport
25340
+ * @type int
25341
+ * @default 0
25342
+ */
25343
+ "tableBottom": 0,
25344
+
25345
+ /**
25346
+ * Pixel location of the boundary for when the next data set should be loaded and drawn
25347
+ * when scrolling up the way.
25348
+ * @type int
25349
+ * @default 0
25350
+ * @private
25351
+ */
25352
+ "redrawTop": 0,
25353
+
25354
+ /**
25355
+ * Pixel location of the boundary for when the next data set should be loaded and drawn
25356
+ * when scrolling down the way. Note that this is actually calculated as the offset from
25357
+ * the top.
25358
+ * @type int
25359
+ * @default 0
25360
+ * @private
25361
+ */
25362
+ "redrawBottom": 0,
25363
+
25364
+ /**
25365
+ * Auto row height or not indicator
25366
+ * @type bool
25367
+ * @default 0
25368
+ */
25369
+ "autoHeight": true,
25370
+
25371
+ /**
25372
+ * Number of rows calculated as visible in the visible viewport
25373
+ * @type int
25374
+ * @default 0
25375
+ */
25376
+ "viewportRows": 0,
25377
+
25378
+ /**
25379
+ * setTimeout reference for state saving, used when state saving is enabled in the DataTable
25380
+ * and when the user scrolls the viewport in order to stop the cookie set taking too much
25381
+ * CPU!
25382
+ * @type int
25383
+ * @default 0
25384
+ */
25385
+ "stateTO": null,
25386
+
25387
+ /**
25388
+ * setTimeout reference for the redraw, used when server-side processing is enabled in the
25389
+ * DataTables in order to prevent DoSing the server
25390
+ * @type int
25391
+ * @default null
25392
+ */
25393
+ "drawTO": null,
25394
+
25395
+ heights: {
25396
+ jump: null,
25397
+ page: null,
25398
+ virtual: null,
25399
+ scroll: null,
25400
+
25401
+ /**
25402
+ * Height of rows in the table
25403
+ * @type int
25404
+ * @default 0
25405
+ */
25406
+ row: null,
25407
+
25408
+ /**
25409
+ * Pixel height of the viewport
25410
+ * @type int
25411
+ * @default 0
25412
+ */
25413
+ viewport: null
25414
+ },
25415
+
25416
+ topRowFloat: 0,
25417
+ scrollDrawDiff: null,
25418
+ loaderVisible: false,
25419
+ forceReposition: false
25420
+ };
25421
+
25422
+ // @todo The defaults should extend a `c` property and the internal settings
25423
+ // only held in the `s` property. At the moment they are mixed
25424
+ this.s = $.extend( this.s, Scroller.oDefaults, opts );
25425
+
25426
+ // Workaround for row height being read from height object (see above comment)
25427
+ this.s.heights.row = this.s.rowHeight;
25428
+
25429
+ /**
25430
+ * DOM elements used by the class instance
25431
+ * @private
25432
+ * @namespace
25433
+ *
25434
+ */
25435
+ this.dom = {
25436
+ "force": document.createElement('div'),
25437
+ "scroller": null,
25438
+ "table": null,
25439
+ "loader": null
25440
+ };
25441
+
25442
+ // Attach the instance to the DataTables instance so it can be accessed in
25443
+ // future. Don't initialise Scroller twice on the same table
25444
+ if ( this.s.dt.oScroller ) {
25445
+ return;
25446
+ }
25447
+
25448
+ this.s.dt.oScroller = this;
25449
+
25450
+ /* Let's do it */
25451
+ this._fnConstruct();
25452
+ };
25453
+
25454
+
25455
+
25456
+ $.extend( Scroller.prototype, {
25457
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
25458
+ * Public methods
25459
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
25460
+
25461
+ /**
25462
+ * Calculate the pixel position from the top of the scrolling container for
25463
+ * a given row
25464
+ * @param {int} iRow Row number to calculate the position of
25465
+ * @returns {int} Pixels
25466
+ * @example
25467
+ * $(document).ready(function() {
25468
+ * $('#example').dataTable( {
25469
+ * "sScrollY": "200px",
25470
+ * "sAjaxSource": "media/dataset/large.txt",
25471
+ * "sDom": "frtiS",
25472
+ * "bDeferRender": true,
25473
+ * "fnInitComplete": function (o) {
25474
+ * // Find where row 25 is
25475
+ * alert( o.oScroller.fnRowToPixels( 25 ) );
25476
+ * }
25477
+ * } );
25478
+ * } );
25479
+ */
25480
+ "fnRowToPixels": function ( rowIdx, intParse, virtual )
25481
+ {
25482
+ var pixels;
25483
+
25484
+ if ( virtual ) {
25485
+ pixels = this._domain( 'virtualToPhysical', rowIdx * this.s.heights.row );
25486
+ }
25487
+ else {
25488
+ var diff = rowIdx - this.s.baseRowTop;
25489
+ pixels = this.s.baseScrollTop + (diff * this.s.heights.row);
25490
+ }
25491
+
25492
+ return intParse || intParse === undefined ?
25493
+ parseInt( pixels, 10 ) :
25494
+ pixels;
25495
+ },
25496
+
25497
+
25498
+ /**
25499
+ * Calculate the row number that will be found at the given pixel position
25500
+ * (y-scroll).
25501
+ *
25502
+ * Please note that when the height of the full table exceeds 1 million
25503
+ * pixels, Scroller switches into a non-linear mode for the scrollbar to fit
25504
+ * all of the records into a finite area, but this function returns a linear
25505
+ * value (relative to the last non-linear positioning).
25506
+ * @param {int} iPixels Offset from top to calculate the row number of
25507
+ * @param {int} [intParse=true] If an integer value should be returned
25508
+ * @param {int} [virtual=false] Perform the calculations in the virtual domain
25509
+ * @returns {int} Row index
25510
+ * @example
25511
+ * $(document).ready(function() {
25512
+ * $('#example').dataTable( {
25513
+ * "sScrollY": "200px",
25514
+ * "sAjaxSource": "media/dataset/large.txt",
25515
+ * "sDom": "frtiS",
25516
+ * "bDeferRender": true,
25517
+ * "fnInitComplete": function (o) {
25518
+ * // Find what row number is at 500px
25519
+ * alert( o.oScroller.fnPixelsToRow( 500 ) );
25520
+ * }
25521
+ * } );
25522
+ * } );
25523
+ */
25524
+ "fnPixelsToRow": function ( pixels, intParse, virtual )
25525
+ {
25526
+ var diff = pixels - this.s.baseScrollTop;
25527
+ var row = virtual ?
25528
+ this._domain( 'physicalToVirtual', pixels ) / this.s.heights.row :
25529
+ ( diff / this.s.heights.row ) + this.s.baseRowTop;
25530
+
25531
+ return intParse || intParse === undefined ?
25532
+ parseInt( row, 10 ) :
25533
+ row;
25534
+ },
25535
+
25536
+
25537
+ /**
25538
+ * Calculate the row number that will be found at the given pixel position (y-scroll)
25539
+ * @param {int} iRow Row index to scroll to
25540
+ * @param {bool} [bAnimate=true] Animate the transition or not
25541
+ * @returns {void}
25542
+ * @example
25543
+ * $(document).ready(function() {
25544
+ * $('#example').dataTable( {
25545
+ * "sScrollY": "200px",
25546
+ * "sAjaxSource": "media/dataset/large.txt",
25547
+ * "sDom": "frtiS",
25548
+ * "bDeferRender": true,
25549
+ * "fnInitComplete": function (o) {
25550
+ * // Immediately scroll to row 1000
25551
+ * o.oScroller.fnScrollToRow( 1000 );
25552
+ * }
25553
+ * } );
25554
+ *
25555
+ * // Sometime later on use the following to scroll to row 500...
25556
+ * var oSettings = $('#example').dataTable().fnSettings();
25557
+ * oSettings.oScroller.fnScrollToRow( 500 );
25558
+ * } );
25559
+ */
25560
+ "fnScrollToRow": function ( iRow, bAnimate )
25561
+ {
25562
+ var that = this;
25563
+ var ani = false;
25564
+ var px = this.fnRowToPixels( iRow );
25565
+
25566
+ // We need to know if the table will redraw or not before doing the
25567
+ // scroll. If it will not redraw, then we need to use the currently
25568
+ // displayed table, and scroll with the physical pixels. Otherwise, we
25569
+ // need to calculate the table's new position from the virtual
25570
+ // transform.
25571
+ var preRows = ((this.s.displayBuffer-1)/2) * this.s.viewportRows;
25572
+ var drawRow = iRow - preRows;
25573
+ if ( drawRow < 0 ) {
25574
+ drawRow = 0;
25575
+ }
25576
+
25577
+ if ( (px > this.s.redrawBottom || px < this.s.redrawTop) && this.s.dt._iDisplayStart !== drawRow ) {
25578
+ ani = true;
25579
+ px = this.fnRowToPixels( iRow, false, true );
25580
+
25581
+ // If we need records outside the current draw region, but the new
25582
+ // scrolling position is inside that (due to the non-linear nature
25583
+ // for larger numbers of records), we need to force position update.
25584
+ if ( this.s.redrawTop < px && px < this.s.redrawBottom ) {
25585
+ this.s.forceReposition = true;
25586
+ bAnimate = false;
25587
+ }
25588
+ }
25589
+
25590
+ if ( typeof bAnimate == 'undefined' || bAnimate )
25591
+ {
25592
+ this.s.ani = ani;
25593
+ $(this.dom.scroller).animate( {
25594
+ "scrollTop": px
25595
+ }, function () {
25596
+ // This needs to happen after the animation has completed and
25597
+ // the final scroll event fired
25598
+ setTimeout( function () {
25599
+ that.s.ani = false;
25600
+ }, 25 );
25601
+ } );
25602
+ }
25603
+ else
25604
+ {
25605
+ $(this.dom.scroller).scrollTop( px );
25606
+ }
25607
+ },
25608
+
25609
+
25610
+ /**
25611
+ * Calculate and store information about how many rows are to be displayed
25612
+ * in the scrolling viewport, based on current dimensions in the browser's
25613
+ * rendering. This can be particularly useful if the table is initially
25614
+ * drawn in a hidden element - for example in a tab.
25615
+ * @param {bool} [bRedraw=true] Redraw the table automatically after the recalculation, with
25616
+ * the new dimensions forming the basis for the draw.
25617
+ * @returns {void}
25618
+ * @example
25619
+ * $(document).ready(function() {
25620
+ * // Make the example container hidden to throw off the browser's sizing
25621
+ * document.getElementById('container').style.display = "none";
25622
+ * var oTable = $('#example').dataTable( {
25623
+ * "sScrollY": "200px",
25624
+ * "sAjaxSource": "media/dataset/large.txt",
25625
+ * "sDom": "frtiS",
25626
+ * "bDeferRender": true,
25627
+ * "fnInitComplete": function (o) {
25628
+ * // Immediately scroll to row 1000
25629
+ * o.oScroller.fnScrollToRow( 1000 );
25630
+ * }
25631
+ * } );
25632
+ *
25633
+ * setTimeout( function () {
25634
+ * // Make the example container visible and recalculate the scroller sizes
25635
+ * document.getElementById('container').style.display = "block";
25636
+ * oTable.fnSettings().oScroller.fnMeasure();
25637
+ * }, 3000 );
25638
+ */
25639
+ "fnMeasure": function ( bRedraw )
25640
+ {
25641
+ if ( this.s.autoHeight )
25642
+ {
25643
+ this._fnCalcRowHeight();
25644
+ }
25645
+
25646
+ var heights = this.s.heights;
25647
+
25648
+ if ( heights.row ) {
25649
+ heights.viewport = $.contains(document, this.dom.scroller) ?
25650
+ $(this.dom.scroller).height() :
25651
+ this._parseHeight($(this.dom.scroller).css('height'));
25652
+
25653
+ // If collapsed (no height) use the max-height parameter
25654
+ if ( ! heights.viewport ) {
25655
+ heights.viewport = this._parseHeight($(this.dom.scroller).css('max-height'));
25656
+ }
25657
+
25658
+ this.s.viewportRows = parseInt( heights.viewport / heights.row, 10 )+1;
25659
+ this.s.dt._iDisplayLength = this.s.viewportRows * this.s.displayBuffer;
25660
+ }
25661
+
25662
+ if ( bRedraw === undefined || bRedraw )
25663
+ {
25664
+ this.s.dt.oInstance.fnDraw( false );
25665
+ }
25666
+ },
25667
+
25668
+
25669
+ /**
25670
+ * Get information about current displayed record range. This corresponds to
25671
+ * the information usually displayed in the "Info" block of the table.
25672
+ *
25673
+ * @returns {object} info as an object:
25674
+ * {
25675
+ * start: {int}, // the 0-indexed record at the top of the viewport
25676
+ * end: {int}, // the 0-indexed record at the bottom of the viewport
25677
+ * }
25678
+ */
25679
+ "fnPageInfo": function()
25680
+ {
25681
+ var
25682
+ dt = this.s.dt,
25683
+ iScrollTop = this.dom.scroller.scrollTop,
25684
+ iTotal = dt.fnRecordsDisplay(),
25685
+ iPossibleEnd = Math.ceil(this.fnPixelsToRow(iScrollTop + this.s.heights.viewport, false, this.s.ani));
25686
+
25687
+ return {
25688
+ start: Math.floor(this.fnPixelsToRow(iScrollTop, false, this.s.ani)),
25689
+ end: iTotal < iPossibleEnd ? iTotal-1 : iPossibleEnd-1
25690
+ };
25691
+ },
25692
+
25693
+
25694
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
25695
+ * Private methods (they are of course public in JS, but recommended as private)
25696
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
25697
+
25698
+ /**
25699
+ * Initialisation for Scroller
25700
+ * @returns {void}
25701
+ * @private
25702
+ */
25703
+ "_fnConstruct": function ()
25704
+ {
25705
+ var that = this;
25706
+
25707
+ /* Sanity check */
25708
+ if ( !this.s.dt.oFeatures.bPaginate ) {
25709
+ this.s.dt.oApi._fnLog( this.s.dt, 0, 'Pagination must be enabled for Scroller' );
25710
+ return;
25711
+ }
25712
+
25713
+ /* Insert a div element that we can use to force the DT scrolling container to
25714
+ * the height that would be required if the whole table was being displayed
25715
+ */
25716
+ this.dom.force.style.position = "relative";
25717
+ this.dom.force.style.top = "0px";
25718
+ this.dom.force.style.left = "0px";
25719
+ this.dom.force.style.width = "1px";
25720
+
25721
+ this.dom.scroller = $('div.'+this.s.dt.oClasses.sScrollBody, this.s.dt.nTableWrapper)[0];
25722
+ this.dom.scroller.appendChild( this.dom.force );
25723
+ this.dom.scroller.style.position = "relative";
25724
+
25725
+ this.dom.table = $('>table', this.dom.scroller)[0];
25726
+ this.dom.table.style.position = "absolute";
25727
+ this.dom.table.style.top = "0px";
25728
+ this.dom.table.style.left = "0px";
25729
+
25730
+ // Add class to 'announce' that we are a Scroller table
25731
+ $(this.s.dt.nTableWrapper).addClass('DTS');
25732
+
25733
+ // Add a 'loading' indicator
25734
+ if ( this.s.loadingIndicator )
25735
+ {
25736
+ this.dom.loader = $('<div class="dataTables_processing DTS_Loading">'+this.s.dt.oLanguage.sLoadingRecords+'</div>')
25737
+ .css('display', 'none');
25738
+
25739
+ $(this.dom.scroller.parentNode)
25740
+ .css('position', 'relative')
25741
+ .append( this.dom.loader );
25742
+ }
25743
+
25744
+ /* Initial size calculations */
25745
+ if ( this.s.heights.row && this.s.heights.row != 'auto' )
25746
+ {
25747
+ this.s.autoHeight = false;
25748
+ }
25749
+ this.fnMeasure( false );
25750
+
25751
+ /* Scrolling callback to see if a page change is needed - use a throttled
25752
+ * function for the save save callback so we aren't hitting it on every
25753
+ * scroll
25754
+ */
25755
+ this.s.ingnoreScroll = true;
25756
+ this.s.stateSaveThrottle = this.s.dt.oApi._fnThrottle( function () {
25757
+ that.s.dt.oApi._fnSaveState( that.s.dt );
25758
+ }, 500 );
25759
+ $(this.dom.scroller).on( 'scroll.DTS', function (e) {
25760
+ that._fnScroll.call( that );
25761
+ } );
25762
+
25763
+ /* In iOS we catch the touchstart event in case the user tries to scroll
25764
+ * while the display is already scrolling
25765
+ */
25766
+ $(this.dom.scroller).on('touchstart.DTS', function () {
25767
+ that._fnScroll.call( that );
25768
+ } );
25769
+
25770
+ /* Update the scroller when the DataTable is redrawn */
25771
+ this.s.dt.aoDrawCallback.push( {
25772
+ "fn": function () {
25773
+ if ( that.s.dt.bInitialised ) {
25774
+ that._fnDrawCallback.call( that );
25775
+ }
25776
+ },
25777
+ "sName": "Scroller"
25778
+ } );
25779
+
25780
+ /* On resize, update the information element, since the number of rows shown might change */
25781
+ $(window).on( 'resize.DTS', function () {
25782
+ that.fnMeasure( false );
25783
+ that._fnInfo();
25784
+ } );
25785
+
25786
+ /* Add a state saving parameter to the DT state saving so we can restore the exact
25787
+ * position of the scrolling
25788
+ */
25789
+ var initialStateSave = true;
25790
+ this.s.dt.oApi._fnCallbackReg( this.s.dt, 'aoStateSaveParams', function (oS, oData) {
25791
+ /* Set iScroller to saved scroll position on initialization.
25792
+ */
25793
+ if(initialStateSave && that.s.dt.oLoadedState){
25794
+ oData.iScroller = that.s.dt.oLoadedState.iScroller;
25795
+ oData.iScrollerTopRow = that.s.dt.oLoadedState.iScrollerTopRow;
25796
+ initialStateSave = false;
25797
+ } else {
25798
+ oData.iScroller = that.dom.scroller.scrollTop;
25799
+ oData.iScrollerTopRow = that.s.topRowFloat;
25800
+ }
25801
+ }, "Scroller_State" );
25802
+
25803
+ if ( this.s.dt.oLoadedState ) {
25804
+ this.s.topRowFloat = this.s.dt.oLoadedState.iScrollerTopRow || 0;
25805
+ }
25806
+
25807
+ // Measure immediately. Scroller will have been added using preInit, so
25808
+ // we can reliably do this here. We could potentially also measure on
25809
+ // init complete, which would be useful for cases where the data is Ajax
25810
+ // loaded and longer than a single line.
25811
+ $(this.s.dt.nTable).one( 'init.dt', function () {
25812
+ that.fnMeasure();
25813
+ } );
25814
+
25815
+ /* Destructor */
25816
+ this.s.dt.aoDestroyCallback.push( {
25817
+ "sName": "Scroller",
25818
+ "fn": function () {
25819
+ $(window).off( 'resize.DTS' );
25820
+ $(that.dom.scroller).off('touchstart.DTS scroll.DTS');
25821
+ $(that.s.dt.nTableWrapper).removeClass('DTS');
25822
+ $('div.DTS_Loading', that.dom.scroller.parentNode).remove();
25823
+ $(that.s.dt.nTable).off( 'init.dt' );
25824
+
25825
+ that.dom.table.style.position = "";
25826
+ that.dom.table.style.top = "";
25827
+ that.dom.table.style.left = "";
25828
+ }
25829
+ } );
25830
+ },
25831
+
25832
+
25833
+ /**
25834
+ * Scrolling function - fired whenever the scrolling position is changed.
25835
+ * This method needs to use the stored values to see if the table should be
25836
+ * redrawn as we are moving towards the end of the information that is
25837
+ * currently drawn or not. If needed, then it will redraw the table based on
25838
+ * the new position.
25839
+ * @returns {void}
25840
+ * @private
25841
+ */
25842
+ "_fnScroll": function ()
25843
+ {
25844
+ var
25845
+ that = this,
25846
+ heights = this.s.heights,
25847
+ iScrollTop = this.dom.scroller.scrollTop,
25848
+ iTopRow;
25849
+
25850
+ if ( this.s.skip ) {
25851
+ return;
25852
+ }
25853
+
25854
+ if ( this.s.ingnoreScroll ) {
25855
+ return;
25856
+ }
25857
+
25858
+ /* If the table has been sorted or filtered, then we use the redraw that
25859
+ * DataTables as done, rather than performing our own
25860
+ */
25861
+ if ( this.s.dt.bFiltered || this.s.dt.bSorted ) {
25862
+ this.s.lastScrollTop = 0;
25863
+ return;
25864
+ }
25865
+
25866
+ /* Update the table's information display for what is now in the viewport */
25867
+ this._fnInfo();
25868
+
25869
+ /* We don't want to state save on every scroll event - that's heavy
25870
+ * handed, so use a timeout to update the state saving only when the
25871
+ * scrolling has finished
25872
+ */
25873
+ clearTimeout( this.s.stateTO );
25874
+ this.s.stateTO = setTimeout( function () {
25875
+ that.s.dt.oApi._fnSaveState( that.s.dt );
25876
+ }, 250 );
25877
+
25878
+ /* Check if the scroll point is outside the trigger boundary which would required
25879
+ * a DataTables redraw
25880
+ */
25881
+ if ( this.s.forceReposition || iScrollTop < this.s.redrawTop || iScrollTop > this.s.redrawBottom ) {
25882
+
25883
+ var preRows = Math.ceil( ((this.s.displayBuffer-1)/2) * this.s.viewportRows );
25884
+
25885
+ if ( Math.abs( iScrollTop - this.s.lastScrollTop ) > heights.viewport || this.s.ani || this.s.forceReposition ) {
25886
+ iTopRow = parseInt(this._domain( 'physicalToVirtual', iScrollTop ) / heights.row, 10) - preRows;
25887
+ this.s.topRowFloat = this._domain( 'physicalToVirtual', iScrollTop ) / heights.row;
25888
+ }
25889
+ else {
25890
+ iTopRow = this.fnPixelsToRow( iScrollTop ) - preRows;
25891
+ this.s.topRowFloat = this.fnPixelsToRow( iScrollTop, false );
25892
+ }
25893
+
25894
+ this.s.forceReposition = false;
25895
+
25896
+ if ( iTopRow <= 0 ) {
25897
+ /* At the start of the table */
25898
+ iTopRow = 0;
25899
+ }
25900
+ else if ( iTopRow + this.s.dt._iDisplayLength > this.s.dt.fnRecordsDisplay() ) {
25901
+ /* At the end of the table */
25902
+ iTopRow = this.s.dt.fnRecordsDisplay() - this.s.dt._iDisplayLength;
25903
+ if ( iTopRow < 0 ) {
25904
+ iTopRow = 0;
25905
+ }
25906
+ }
25907
+ else if ( iTopRow % 2 !== 0 ) {
25908
+ // For the row-striping classes (odd/even) we want only to start
25909
+ // on evens otherwise the stripes will change between draws and
25910
+ // look rubbish
25911
+ iTopRow++;
25912
+ }
25913
+
25914
+ if ( iTopRow != this.s.dt._iDisplayStart ) {
25915
+ /* Cache the new table position for quick lookups */
25916
+ this.s.tableTop = $(this.s.dt.nTable).offset().top;
25917
+ this.s.tableBottom = $(this.s.dt.nTable).height() + this.s.tableTop;
25918
+
25919
+ var draw = function () {
25920
+ if ( that.s.scrollDrawReq === null ) {
25921
+ that.s.scrollDrawReq = iScrollTop;
25922
+ }
25923
+
25924
+ that.s.dt._iDisplayStart = iTopRow;
25925
+ that.s.dt.oApi._fnDraw( that.s.dt );
25926
+ };
25927
+
25928
+ /* Do the DataTables redraw based on the calculated start point - note that when
25929
+ * using server-side processing we introduce a small delay to not DoS the server...
25930
+ */
25931
+ if ( this.s.dt.oFeatures.bServerSide ) {
25932
+ clearTimeout( this.s.drawTO );
25933
+ this.s.drawTO = setTimeout( draw, this.s.serverWait );
25934
+ }
25935
+ else {
25936
+ draw();
25937
+ }
25938
+
25939
+ if ( this.dom.loader && ! this.s.loaderVisible ) {
25940
+ this.dom.loader.css( 'display', 'block' );
25941
+ this.s.loaderVisible = true;
25942
+ }
25943
+ }
25944
+ }
25945
+ else {
25946
+ this.s.topRowFloat = this._domain( 'physicalToVirtual', iScrollTop ) / heights.row;
25947
+ }
25948
+
25949
+ this.s.lastScrollTop = iScrollTop;
25950
+ this.s.stateSaveThrottle();
25951
+ },
25952
+
25953
+
25954
+ /**
25955
+ * Convert from one domain to another. The physical domain is the actual
25956
+ * pixel count on the screen, while the virtual is if we had browsers which
25957
+ * had scrolling containers of infinite height (i.e. the absolute value)
25958
+ *
25959
+ * @param {string} dir Domain transform direction, `virtualToPhysical` or
25960
+ * `physicalToVirtual`
25961
+ * @returns {number} Calculated transform
25962
+ * @private
25963
+ */
25964
+ _domain: function ( dir, val )
25965
+ {
25966
+ var heights = this.s.heights;
25967
+ var coeff;
25968
+
25969
+ // If the virtual and physical height match, then we use a linear
25970
+ // transform between the two, allowing the scrollbar to be linear
25971
+ if ( heights.virtual === heights.scroll ) {
25972
+ return val;
25973
+ }
25974
+
25975
+ // Otherwise, we want a non-linear scrollbar to take account of the
25976
+ // redrawing regions at the start and end of the table, otherwise these
25977
+ // can stutter badly - on large tables 30px (for example) scroll might
25978
+ // be hundreds of rows, so the table would be redrawing every few px at
25979
+ // the start and end. Use a simple quadratic to stop this. It does mean
25980
+ // the scrollbar is non-linear, but with such massive data sets, the
25981
+ // scrollbar is going to be a best guess anyway
25982
+ var xMax = (heights.scroll - heights.viewport) / 2;
25983
+ var yMax = (heights.virtual - heights.viewport) / 2;
25984
+
25985
+ coeff = yMax / ( xMax * xMax );
25986
+
25987
+ if ( dir === 'virtualToPhysical' ) {
25988
+ if ( val < yMax ) {
25989
+ return Math.pow(val / coeff, 0.5);
25990
+ }
25991
+ else {
25992
+ val = (yMax*2) - val;
25993
+ return val < 0 ?
25994
+ heights.scroll :
25995
+ (xMax*2) - Math.pow(val / coeff, 0.5);
25996
+ }
25997
+ }
25998
+ else if ( dir === 'physicalToVirtual' ) {
25999
+ if ( val < xMax ) {
26000
+ return val * val * coeff;
26001
+ }
26002
+ else {
26003
+ val = (xMax*2) - val;
26004
+ return val < 0 ?
26005
+ heights.virtual :
26006
+ (yMax*2) - (val * val * coeff);
26007
+ }
26008
+ }
26009
+ },
26010
+
26011
+ /**
26012
+ * Parse CSS height property string as number
26013
+ *
26014
+ * An attempt is made to parse the string as a number. Currently supported units are 'px',
26015
+ * 'vh', and 'rem'. 'em' is partially supported; it works as long as the parent element's
26016
+ * font size matches the body element. Zero is returned for unrecognized strings.
26017
+ * @param {string} cssHeight CSS height property string
26018
+ * @returns {number} height
26019
+ * @private
26020
+ */
26021
+ _parseHeight: function(cssHeight) {
26022
+ var height;
26023
+ var matches = /^([+-]?(?:\d+(?:\.\d+)?|\.\d+))(px|em|rem|vh)$/.exec(cssHeight);
26024
+
26025
+ if (matches === null) {
26026
+ return 0;
26027
+ }
26028
+
26029
+ var value = parseFloat(matches[1]);
26030
+ var unit = matches[2];
26031
+
26032
+ if ( unit === 'px' ) {
26033
+ height = value;
26034
+ }
26035
+ else if ( unit === 'vh' ) {
26036
+ height = ( value / 100 ) * $(window).height();
26037
+ }
26038
+ else if ( unit === 'rem' ) {
26039
+ height = value * parseFloat($(':root').css('font-size'));
26040
+ }
26041
+ else if ( unit === 'em' ) {
26042
+ height = value * parseFloat($('body').css('font-size'));
26043
+ }
26044
+
26045
+ return height ?
26046
+ height :
26047
+ 0;
26048
+ },
26049
+
26050
+
26051
+ /**
26052
+ * Draw callback function which is fired when the DataTable is redrawn. The main function of
26053
+ * this method is to position the drawn table correctly the scrolling container for the rows
26054
+ * that is displays as a result of the scrolling position.
26055
+ * @returns {void}
26056
+ * @private
26057
+ */
26058
+ "_fnDrawCallback": function ()
26059
+ {
26060
+ var
26061
+ that = this,
26062
+ heights = this.s.heights,
26063
+ iScrollTop = this.dom.scroller.scrollTop,
26064
+ iActualScrollTop = iScrollTop,
26065
+ iScrollBottom = iScrollTop + heights.viewport,
26066
+ iTableHeight = $(this.s.dt.nTable).height(),
26067
+ displayStart = this.s.dt._iDisplayStart,
26068
+ displayLen = this.s.dt._iDisplayLength,
26069
+ displayEnd = this.s.dt.fnRecordsDisplay();
26070
+
26071
+ // Disable the scroll event listener while we are updating the DOM
26072
+ this.s.skip = true;
26073
+
26074
+ // Resize the scroll forcing element
26075
+ this._fnScrollForce();
26076
+
26077
+ // Reposition the scrolling for the updated virtual position if needed
26078
+ if ( displayStart === 0 ) {
26079
+ // Linear calculation at the top of the table
26080
+ iScrollTop = this.s.topRowFloat * heights.row;
26081
+ }
26082
+ else if ( displayStart + displayLen >= displayEnd ) {
26083
+ // Linear calculation that the bottom as well
26084
+ iScrollTop = heights.scroll - ((displayEnd - this.s.topRowFloat) * heights.row);
26085
+ }
26086
+ else {
26087
+ // Domain scaled in the middle
26088
+ iScrollTop = this._domain( 'virtualToPhysical', this.s.topRowFloat * heights.row );
26089
+ }
26090
+
26091
+ this.dom.scroller.scrollTop = iScrollTop;
26092
+
26093
+ // Store positional information so positional calculations can be based
26094
+ // upon the current table draw position
26095
+ this.s.baseScrollTop = iScrollTop;
26096
+ this.s.baseRowTop = this.s.topRowFloat;
26097
+
26098
+ // Position the table in the virtual scroller
26099
+ var tableTop = iScrollTop - ((this.s.topRowFloat - displayStart) * heights.row);
26100
+ if ( displayStart === 0 ) {
26101
+ tableTop = 0;
26102
+ }
26103
+ else if ( displayStart + displayLen >= displayEnd ) {
26104
+ tableTop = heights.scroll - iTableHeight;
26105
+ }
26106
+
26107
+ this.dom.table.style.top = tableTop+'px';
26108
+
26109
+ /* Cache some information for the scroller */
26110
+ this.s.tableTop = tableTop;
26111
+ this.s.tableBottom = iTableHeight + this.s.tableTop;
26112
+
26113
+ // Calculate the boundaries for where a redraw will be triggered by the
26114
+ // scroll event listener
26115
+ var boundaryPx = (iScrollTop - this.s.tableTop) * this.s.boundaryScale;
26116
+ this.s.redrawTop = iScrollTop - boundaryPx;
26117
+ this.s.redrawBottom = iScrollTop + boundaryPx > heights.scroll - heights.viewport - heights.row ?
26118
+ heights.scroll - heights.viewport - heights.row :
26119
+ iScrollTop + boundaryPx;
26120
+
26121
+ this.s.skip = false;
26122
+
26123
+ // Restore the scrolling position that was saved by DataTable's state
26124
+ // saving Note that this is done on the second draw when data is Ajax
26125
+ // sourced, and the first draw when DOM soured
26126
+ if ( this.s.dt.oFeatures.bStateSave && this.s.dt.oLoadedState !== null &&
26127
+ typeof this.s.dt.oLoadedState.iScroller != 'undefined' )
26128
+ {
26129
+ // A quirk of DataTables is that the draw callback will occur on an
26130
+ // empty set if Ajax sourced, but not if server-side processing.
26131
+ var ajaxSourced = (this.s.dt.sAjaxSource || that.s.dt.ajax) && ! this.s.dt.oFeatures.bServerSide ?
26132
+ true :
26133
+ false;
26134
+
26135
+ if ( ( ajaxSourced && this.s.dt.iDraw == 2) ||
26136
+ (!ajaxSourced && this.s.dt.iDraw == 1) )
26137
+ {
26138
+ setTimeout( function () {
26139
+ $(that.dom.scroller).scrollTop( that.s.dt.oLoadedState.iScroller );
26140
+ that.s.redrawTop = that.s.dt.oLoadedState.iScroller - (heights.viewport/2);
26141
+
26142
+ // In order to prevent layout thrashing we need another
26143
+ // small delay
26144
+ setTimeout( function () {
26145
+ that.s.ingnoreScroll = false;
26146
+ }, 0 );
26147
+ }, 0 );
26148
+ }
26149
+ }
26150
+ else {
26151
+ that.s.ingnoreScroll = false;
26152
+ }
26153
+
26154
+ // Because of the order of the DT callbacks, the info update will
26155
+ // take precedence over the one we want here. So a 'thread' break is
26156
+ // needed. Only add the thread break if bInfo is set
26157
+ if ( this.s.dt.oFeatures.bInfo ) {
26158
+ setTimeout( function () {
26159
+ that._fnInfo.call( that );
26160
+ }, 0 );
26161
+ }
26162
+
26163
+ // Hide the loading indicator
26164
+ if ( this.dom.loader && this.s.loaderVisible ) {
26165
+ this.dom.loader.css( 'display', 'none' );
26166
+ this.s.loaderVisible = false;
26167
+ }
26168
+ },
26169
+
26170
+
26171
+ /**
26172
+ * Force the scrolling container to have height beyond that of just the
26173
+ * table that has been drawn so the user can scroll the whole data set.
26174
+ *
26175
+ * Note that if the calculated required scrolling height exceeds a maximum
26176
+ * value (1 million pixels - hard-coded) the forcing element will be set
26177
+ * only to that maximum value and virtual / physical domain transforms will
26178
+ * be used to allow Scroller to display tables of any number of records.
26179
+ * @returns {void}
26180
+ * @private
26181
+ */
26182
+ _fnScrollForce: function ()
26183
+ {
26184
+ var heights = this.s.heights;
26185
+ var max = 1000000;
26186
+
26187
+ heights.virtual = heights.row * this.s.dt.fnRecordsDisplay();
26188
+ heights.scroll = heights.virtual;
26189
+
26190
+ if ( heights.scroll > max ) {
26191
+ heights.scroll = max;
26192
+ }
26193
+
26194
+ // Minimum height so there is always a row visible (the 'no rows found'
26195
+ // if reduced to zero filtering)
26196
+ this.dom.force.style.height = heights.scroll > this.s.heights.row ?
26197
+ heights.scroll+'px' :
26198
+ this.s.heights.row+'px';
26199
+ },
26200
+
26201
+
26202
+ /**
26203
+ * Automatic calculation of table row height. This is just a little tricky here as using
26204
+ * initialisation DataTables has tale the table out of the document, so we need to create
26205
+ * a new table and insert it into the document, calculate the row height and then whip the
26206
+ * table out.
26207
+ * @returns {void}
26208
+ * @private
26209
+ */
26210
+ "_fnCalcRowHeight": function ()
26211
+ {
26212
+ var dt = this.s.dt;
26213
+ var origTable = dt.nTable;
26214
+ var nTable = origTable.cloneNode( false );
26215
+ var tbody = $('<tbody/>').appendTo( nTable );
26216
+ var container = $(
26217
+ '<div class="'+dt.oClasses.sWrapper+' DTS">'+
26218
+ '<div class="'+dt.oClasses.sScrollWrapper+'">'+
26219
+ '<div class="'+dt.oClasses.sScrollBody+'"></div>'+
26220
+ '</div>'+
26221
+ '</div>'
26222
+ );
26223
+
26224
+ // Want 3 rows in the sizing table so :first-child and :last-child
26225
+ // CSS styles don't come into play - take the size of the middle row
26226
+ $('tbody tr:lt(4)', origTable).clone().appendTo( tbody );
26227
+ while( $('tr', tbody).length < 3 ) {
26228
+ tbody.append( '<tr><td>&nbsp;</td></tr>' );
26229
+ }
26230
+
26231
+ $('div.'+dt.oClasses.sScrollBody, container).append( nTable );
26232
+
26233
+ // If initialised using `dom`, use the holding element as the insert point
26234
+ var insertEl = this.s.dt.nHolding || origTable.parentNode;
26235
+
26236
+ if ( ! $(insertEl).is(':visible') ) {
26237
+ insertEl = 'body';
26238
+ }
26239
+
26240
+ container.appendTo( insertEl );
26241
+ this.s.heights.row = $('tr', tbody).eq(1).outerHeight();
26242
+
26243
+ container.remove();
26244
+ },
26245
+
26246
+
26247
+ /**
26248
+ * Update any information elements that are controlled by the DataTable based on the scrolling
26249
+ * viewport and what rows are visible in it. This function basically acts in the same way as
26250
+ * _fnUpdateInfo in DataTables, and effectively replaces that function.
26251
+ * @returns {void}
26252
+ * @private
26253
+ */
26254
+ "_fnInfo": function ()
26255
+ {
26256
+ if ( !this.s.dt.oFeatures.bInfo )
26257
+ {
26258
+ return;
26259
+ }
26260
+
26261
+ var
26262
+ dt = this.s.dt,
26263
+ language = dt.oLanguage,
26264
+ iScrollTop = this.dom.scroller.scrollTop,
26265
+ iStart = Math.floor( this.fnPixelsToRow(iScrollTop, false, this.s.ani)+1 ),
26266
+ iMax = dt.fnRecordsTotal(),
26267
+ iTotal = dt.fnRecordsDisplay(),
26268
+ iPossibleEnd = Math.ceil( this.fnPixelsToRow(iScrollTop+this.s.heights.viewport, false, this.s.ani) ),
26269
+ iEnd = iTotal < iPossibleEnd ? iTotal : iPossibleEnd,
26270
+ sStart = dt.fnFormatNumber( iStart ),
26271
+ sEnd = dt.fnFormatNumber( iEnd ),
26272
+ sMax = dt.fnFormatNumber( iMax ),
26273
+ sTotal = dt.fnFormatNumber( iTotal ),
26274
+ sOut;
26275
+
26276
+ if ( dt.fnRecordsDisplay() === 0 &&
26277
+ dt.fnRecordsDisplay() == dt.fnRecordsTotal() )
26278
+ {
26279
+ /* Empty record set */
26280
+ sOut = language.sInfoEmpty+ language.sInfoPostFix;
26281
+ }
26282
+ else if ( dt.fnRecordsDisplay() === 0 )
26283
+ {
26284
+ /* Empty record set after filtering */
26285
+ sOut = language.sInfoEmpty +' '+
26286
+ language.sInfoFiltered.replace('_MAX_', sMax)+
26287
+ language.sInfoPostFix;
26288
+ }
26289
+ else if ( dt.fnRecordsDisplay() == dt.fnRecordsTotal() )
26290
+ {
26291
+ /* Normal record set */
26292
+ sOut = language.sInfo.
26293
+ replace('_START_', sStart).
26294
+ replace('_END_', sEnd).
26295
+ replace('_MAX_', sMax).
26296
+ replace('_TOTAL_', sTotal)+
26297
+ language.sInfoPostFix;
26298
+ }
26299
+ else
26300
+ {
26301
+ /* Record set after filtering */
26302
+ sOut = language.sInfo.
26303
+ replace('_START_', sStart).
26304
+ replace('_END_', sEnd).
26305
+ replace('_MAX_', sMax).
26306
+ replace('_TOTAL_', sTotal) +' '+
26307
+ language.sInfoFiltered.replace(
26308
+ '_MAX_',
26309
+ dt.fnFormatNumber(dt.fnRecordsTotal())
26310
+ )+
26311
+ language.sInfoPostFix;
26312
+ }
26313
+
26314
+ var callback = language.fnInfoCallback;
26315
+ if ( callback ) {
26316
+ sOut = callback.call( dt.oInstance,
26317
+ dt, iStart, iEnd, iMax, iTotal, sOut
26318
+ );
26319
+ }
26320
+
26321
+ var n = dt.aanFeatures.i;
26322
+ if ( typeof n != 'undefined' )
26323
+ {
26324
+ for ( var i=0, iLen=n.length ; i<iLen ; i++ )
26325
+ {
26326
+ $(n[i]).html( sOut );
26327
+ }
26328
+ }
26329
+
26330
+ // DT doesn't actually (yet) trigger this event, but it will in future
26331
+ $(dt.nTable).triggerHandler( 'info.dt' );
26332
+ }
26333
+ } );
26334
+
26335
+
26336
+
26337
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
26338
+ * Statics
26339
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
26340
+
26341
+
26342
+ /**
26343
+ * Scroller default settings for initialisation
26344
+ * @namespace
26345
+ * @name Scroller.defaults
26346
+ * @static
26347
+ */
26348
+ Scroller.defaults = /** @lends Scroller.defaults */{
26349
+ /**
26350
+ * Indicate if Scroller show show trace information on the console or not. This can be
26351
+ * useful when debugging Scroller or if just curious as to what it is doing, but should
26352
+ * be turned off for production.
26353
+ * @type bool
26354
+ * @default false
26355
+ * @static
26356
+ * @example
26357
+ * var oTable = $('#example').dataTable( {
26358
+ * "sScrollY": "200px",
26359
+ * "sDom": "frtiS",
26360
+ * "bDeferRender": true,
26361
+ * "oScroller": {
26362
+ * "trace": true
26363
+ * }
26364
+ * } );
26365
+ */
26366
+ "trace": false,
26367
+
26368
+ /**
26369
+ * Scroller will attempt to automatically calculate the height of rows for it's internal
26370
+ * calculations. However the height that is used can be overridden using this parameter.
26371
+ * @type int|string
26372
+ * @default auto
26373
+ * @static
26374
+ * @example
26375
+ * var oTable = $('#example').dataTable( {
26376
+ * "sScrollY": "200px",
26377
+ * "sDom": "frtiS",
26378
+ * "bDeferRender": true,
26379
+ * "oScroller": {
26380
+ * "rowHeight": 30
26381
+ * }
26382
+ * } );
26383
+ */
26384
+ "rowHeight": "auto",
26385
+
26386
+ /**
26387
+ * When using server-side processing, Scroller will wait a small amount of time to allow
26388
+ * the scrolling to finish before requesting more data from the server. This prevents
26389
+ * you from DoSing your own server! The wait time can be configured by this parameter.
26390
+ * @type int
26391
+ * @default 200
26392
+ * @static
26393
+ * @example
26394
+ * var oTable = $('#example').dataTable( {
26395
+ * "sScrollY": "200px",
26396
+ * "sDom": "frtiS",
26397
+ * "bDeferRender": true,
26398
+ * "oScroller": {
26399
+ * "serverWait": 100
26400
+ * }
26401
+ * } );
26402
+ */
26403
+ "serverWait": 200,
26404
+
26405
+ /**
26406
+ * The display buffer is what Scroller uses to calculate how many rows it should pre-fetch
26407
+ * for scrolling. Scroller automatically adjusts DataTables' display length to pre-fetch
26408
+ * rows that will be shown in "near scrolling" (i.e. just beyond the current display area).
26409
+ * The value is based upon the number of rows that can be displayed in the viewport (i.e.
26410
+ * a value of 1), and will apply the display range to records before before and after the
26411
+ * current viewport - i.e. a factor of 3 will allow Scroller to pre-fetch 1 viewport's worth
26412
+ * of rows before the current viewport, the current viewport's rows and 1 viewport's worth
26413
+ * of rows after the current viewport. Adjusting this value can be useful for ensuring
26414
+ * smooth scrolling based on your data set.
26415
+ * @type int
26416
+ * @default 7
26417
+ * @static
26418
+ * @example
26419
+ * var oTable = $('#example').dataTable( {
26420
+ * "sScrollY": "200px",
26421
+ * "sDom": "frtiS",
26422
+ * "bDeferRender": true,
26423
+ * "oScroller": {
26424
+ * "displayBuffer": 10
26425
+ * }
26426
+ * } );
26427
+ */
26428
+ "displayBuffer": 9,
26429
+
26430
+ /**
26431
+ * Scroller uses the boundary scaling factor to decide when to redraw the table - which it
26432
+ * typically does before you reach the end of the currently loaded data set (in order to
26433
+ * allow the data to look continuous to a user scrolling through the data). If given as 0
26434
+ * then the table will be redrawn whenever the viewport is scrolled, while 1 would not
26435
+ * redraw the table until the currently loaded data has all been shown. You will want
26436
+ * something in the middle - the default factor of 0.5 is usually suitable.
26437
+ * @type float
26438
+ * @default 0.5
26439
+ * @static
26440
+ * @example
26441
+ * var oTable = $('#example').dataTable( {
26442
+ * "sScrollY": "200px",
26443
+ * "sDom": "frtiS",
26444
+ * "bDeferRender": true,
26445
+ * "oScroller": {
26446
+ * "boundaryScale": 0.75
26447
+ * }
26448
+ * } );
26449
+ */
26450
+ "boundaryScale": 0.5,
26451
+
26452
+ /**
26453
+ * Show (or not) the loading element in the background of the table. Note that you should
26454
+ * include the dataTables.scroller.css file for this to be displayed correctly.
26455
+ * @type boolean
26456
+ * @default false
26457
+ * @static
26458
+ * @example
26459
+ * var oTable = $('#example').dataTable( {
26460
+ * "sScrollY": "200px",
26461
+ * "sDom": "frtiS",
26462
+ * "bDeferRender": true,
26463
+ * "oScroller": {
26464
+ * "loadingIndicator": true
26465
+ * }
26466
+ * } );
26467
+ */
26468
+ "loadingIndicator": false
26469
+ };
26470
+
26471
+ Scroller.oDefaults = Scroller.defaults;
26472
+
26473
+
26474
+
26475
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
26476
+ * Constants
26477
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
26478
+
26479
+ /**
26480
+ * Scroller version
26481
+ * @type String
26482
+ * @default See code
26483
+ * @name Scroller.version
26484
+ * @static
26485
+ */
26486
+ Scroller.version = "1.4.4";
26487
+
26488
+
26489
+
26490
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
26491
+ * Initialisation
26492
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
26493
+
26494
+ // Legacy `dom` parameter initialisation support
26495
+ if ( typeof $.fn.dataTable == "function" &&
26496
+ typeof $.fn.dataTableExt.fnVersionCheck == "function" &&
26497
+ $.fn.dataTableExt.fnVersionCheck('1.10.0') )
26498
+ {
26499
+ $.fn.dataTableExt.aoFeatures.push( {
26500
+ "fnInit": function( oDTSettings ) {
26501
+ var init = oDTSettings.oInit;
26502
+ var opts = init.scroller || init.oScroller || {};
26503
+
26504
+ new Scroller( oDTSettings, opts );
26505
+ },
26506
+ "cFeature": "S",
26507
+ "sFeature": "Scroller"
26508
+ } );
26509
+ }
26510
+ else
26511
+ {
26512
+ alert( "Warning: Scroller requires DataTables 1.10.0 or greater - www.datatables.net/download");
26513
+ }
26514
+
26515
+ // Attach a listener to the document which listens for DataTables initialisation
26516
+ // events so we can automatically initialise
26517
+ $(document).on( 'preInit.dt.dtscroller', function (e, settings) {
26518
+ if ( e.namespace !== 'dt' ) {
26519
+ return;
26520
+ }
26521
+
26522
+ var init = settings.oInit.scroller;
26523
+ var defaults = DataTable.defaults.scroller;
26524
+
26525
+ if ( init || defaults ) {
26526
+ var opts = $.extend( {}, init, defaults );
26527
+
26528
+ if ( init !== false ) {
26529
+ new Scroller( settings, opts );
26530
+ }
26531
+ }
26532
+ } );
26533
+
26534
+
26535
+ // Attach Scroller to DataTables so it can be accessed as an 'extra'
26536
+ $.fn.dataTable.Scroller = Scroller;
26537
+ $.fn.DataTable.Scroller = Scroller;
26538
+
26539
+
26540
+ // DataTables 1.10 API method aliases
26541
+ var Api = $.fn.dataTable.Api;
26542
+
26543
+ Api.register( 'scroller()', function () {
26544
+ return this;
26545
+ } );
26546
+
26547
+ // Undocumented and deprecated - is it actually useful at all?
26548
+ Api.register( 'scroller().rowToPixels()', function ( rowIdx, intParse, virtual ) {
26549
+ var ctx = this.context;
26550
+
26551
+ if ( ctx.length && ctx[0].oScroller ) {
26552
+ return ctx[0].oScroller.fnRowToPixels( rowIdx, intParse, virtual );
26553
+ }
26554
+ // undefined
26555
+ } );
26556
+
26557
+ // Undocumented and deprecated - is it actually useful at all?
26558
+ Api.register( 'scroller().pixelsToRow()', function ( pixels, intParse, virtual ) {
26559
+ var ctx = this.context;
26560
+
26561
+ if ( ctx.length && ctx[0].oScroller ) {
26562
+ return ctx[0].oScroller.fnPixelsToRow( pixels, intParse, virtual );
26563
+ }
26564
+ // undefined
26565
+ } );
26566
+
26567
+ // Undocumented and deprecated - use `row().scrollTo()` instead
26568
+ Api.register( 'scroller().scrollToRow()', function ( row, ani ) {
26569
+ this.iterator( 'table', function ( ctx ) {
26570
+ if ( ctx.oScroller ) {
26571
+ ctx.oScroller.fnScrollToRow( row, ani );
26572
+ }
26573
+ } );
26574
+
26575
+ return this;
26576
+ } );
26577
+
26578
+ Api.register( 'row().scrollTo()', function ( ani ) {
26579
+ var that = this;
26580
+
26581
+ this.iterator( 'row', function ( ctx, rowIdx ) {
26582
+ if ( ctx.oScroller ) {
26583
+ var displayIdx = that
26584
+ .rows( { order: 'applied', search: 'applied' } )
26585
+ .indexes()
26586
+ .indexOf( rowIdx );
26587
+
26588
+ ctx.oScroller.fnScrollToRow( displayIdx, ani );
26589
+ }
26590
+ } );
26591
+
26592
+ return this;
26593
+ } );
26594
+
26595
+ Api.register( 'scroller.measure()', function ( redraw ) {
26596
+ this.iterator( 'table', function ( ctx ) {
26597
+ if ( ctx.oScroller ) {
26598
+ ctx.oScroller.fnMeasure( redraw );
26599
+ }
26600
+ } );
26601
+
26602
+ return this;
26603
+ } );
26604
+
26605
+ Api.register( 'scroller.page()', function() {
26606
+ var ctx = this.context;
26607
+
26608
+ if ( ctx.length && ctx[0].oScroller ) {
26609
+ return ctx[0].oScroller.fnPageInfo();
26610
+ }
26611
+ // undefined
26612
+ } );
26613
+
26614
+ return Scroller;
26615
+ }));
26616
+
26617
+
26618
+ /*! Select for DataTables 1.2.5
26619
+ * 2015-2018 SpryMedia Ltd - datatables.net/license/mit
26620
+ */
26621
+
26622
+ /**
26623
+ * @summary Select for DataTables
26624
+ * @description A collection of API methods, events and buttons for DataTables
26625
+ * that provides selection options of the items in a DataTable
26626
+ * @version 1.2.5
26627
+ * @file dataTables.select.js
26628
+ * @author SpryMedia Ltd (www.sprymedia.co.uk)
26629
+ * @contact datatables.net/forums
26630
+ * @copyright Copyright 2015-2018 SpryMedia Ltd.
26631
+ *
26632
+ * This source file is free software, available under the following license:
26633
+ * MIT license - http://datatables.net/license/mit
26634
+ *
26635
+ * This source file is distributed in the hope that it will be useful, but
26636
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
26637
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
26638
+ *
26639
+ * For details please refer to: http://www.datatables.net/extensions/select
26640
+ */
26641
+ (function( factory ){
26642
+ if ( typeof define === 'function' && define.amd ) {
26643
+ // AMD
26644
+ define( ['jquery', 'datatables.net'], function ( $ ) {
26645
+ return factory( $, window, document );
26646
+ } );
26647
+ }
26648
+ else if ( typeof exports === 'object' ) {
26649
+ // CommonJS
26650
+ module.exports = function (root, $) {
26651
+ if ( ! root ) {
26652
+ root = window;
26653
+ }
26654
+
26655
+ if ( ! $ || ! $.fn.dataTable ) {
26656
+ $ = require('datatables.net')(root, $).$;
26657
+ }
26658
+
26659
+ return factory( $, root, root.document );
26660
+ };
26661
+ }
26662
+ else {
26663
+ // Browser
26664
+ factory( jQuery, window, document );
26665
+ }
26666
+ }(function( $, window, document, undefined ) {
26667
+ 'use strict';
26668
+ var DataTable = $.fn.dataTable;
26669
+
26670
+
26671
+ // Version information for debugger
26672
+ DataTable.select = {};
26673
+
26674
+ DataTable.select.version = '1.2.5';
26675
+
26676
+ DataTable.select.init = function ( dt ) {
26677
+ var ctx = dt.settings()[0];
26678
+ var init = ctx.oInit.select;
26679
+ var defaults = DataTable.defaults.select;
26680
+ var opts = init === undefined ?
26681
+ defaults :
26682
+ init;
26683
+
26684
+ // Set defaults
26685
+ var items = 'row';
26686
+ var style = 'api';
26687
+ var blurable = false;
26688
+ var info = true;
26689
+ var selector = 'td, th';
26690
+ var className = 'selected';
26691
+ var setStyle = false;
26692
+
26693
+ ctx._select = {};
26694
+
26695
+ // Initialisation customisations
26696
+ if ( opts === true ) {
26697
+ style = 'os';
26698
+ setStyle = true;
26699
+ }
26700
+ else if ( typeof opts === 'string' ) {
26701
+ style = opts;
26702
+ setStyle = true;
26703
+ }
26704
+ else if ( $.isPlainObject( opts ) ) {
26705
+ if ( opts.blurable !== undefined ) {
26706
+ blurable = opts.blurable;
26707
+ }
26708
+
26709
+ if ( opts.info !== undefined ) {
26710
+ info = opts.info;
26711
+ }
26712
+
26713
+ if ( opts.items !== undefined ) {
26714
+ items = opts.items;
26715
+ }
26716
+
26717
+ if ( opts.style !== undefined ) {
26718
+ style = opts.style;
26719
+ setStyle = true;
26720
+ }
26721
+
26722
+ if ( opts.selector !== undefined ) {
26723
+ selector = opts.selector;
26724
+ }
26725
+
26726
+ if ( opts.className !== undefined ) {
26727
+ className = opts.className;
26728
+ }
26729
+ }
26730
+
26731
+ dt.select.selector( selector );
26732
+ dt.select.items( items );
26733
+ dt.select.style( style );
26734
+ dt.select.blurable( blurable );
26735
+ dt.select.info( info );
26736
+ ctx._select.className = className;
26737
+
26738
+
26739
+ // Sort table based on selected rows. Requires Select Datatables extension
26740
+ $.fn.dataTable.ext.order['select-checkbox'] = function ( settings, col ) {
26741
+ return this.api().column( col, {order: 'index'} ).nodes().map( function ( td ) {
26742
+ if ( settings._select.items === 'row' ) {
26743
+ return $( td ).parent().hasClass( settings._select.className );
26744
+ } else if ( settings._select.items === 'cell' ) {
26745
+ return $( td ).hasClass( settings._select.className );
26746
+ }
26747
+ return false;
26748
+ });
26749
+ };
26750
+
26751
+ // If the init options haven't enabled select, but there is a selectable
26752
+ // class name, then enable
26753
+ if ( ! setStyle && $( dt.table().node() ).hasClass( 'selectable' ) ) {
26754
+ dt.select.style( 'os' );
26755
+ }
26756
+ };
26757
+
26758
+ /*
26759
+
26760
+ Select is a collection of API methods, event handlers, event emitters and
26761
+ buttons (for the `Buttons` extension) for DataTables. It provides the following
26762
+ features, with an overview of how they are implemented:
26763
+
26764
+ ## Selection of rows, columns and cells. Whether an item is selected or not is
26765
+ stored in:
26766
+
26767
+ * rows: a `_select_selected` property which contains a boolean value of the
26768
+ DataTables' `aoData` object for each row
26769
+ * columns: a `_select_selected` property which contains a boolean value of the
26770
+ DataTables' `aoColumns` object for each column
26771
+ * cells: a `_selected_cells` property which contains an array of boolean values
26772
+ of the `aoData` object for each row. The array is the same length as the
26773
+ columns array, with each element of it representing a cell.
26774
+
26775
+ This method of using boolean flags allows Select to operate when nodes have not
26776
+ been created for rows / cells (DataTables' defer rendering feature).
26777
+
26778
+ ## API methods
26779
+
26780
+ A range of API methods are available for triggering selection and de-selection
26781
+ of rows. Methods are also available to configure the selection events that can
26782
+ be triggered by an end user (such as which items are to be selected). To a large
26783
+ extent, these of API methods *is* Select. It is basically a collection of helper
26784
+ functions that can be used to select items in a DataTable.
26785
+
26786
+ Configuration of select is held in the object `_select` which is attached to the
26787
+ DataTables settings object on initialisation. Select being available on a table
26788
+ is not optional when Select is loaded, but its default is for selection only to
26789
+ be available via the API - so the end user wouldn't be able to select rows
26790
+ without additional configuration.
26791
+
26792
+ The `_select` object contains the following properties:
26793
+
26794
+ ```
26795
+ {
26796
+ items:string - Can be `rows`, `columns` or `cells`. Defines what item
26797
+ will be selected if the user is allowed to activate row
26798
+ selection using the mouse.
26799
+ style:string - Can be `none`, `single`, `multi` or `os`. Defines the
26800
+ interaction style when selecting items
26801
+ blurable:boolean - If row selection can be cleared by clicking outside of
26802
+ the table
26803
+ info:boolean - If the selection summary should be shown in the table
26804
+ information elements
26805
+ }
26806
+ ```
26807
+
26808
+ In addition to the API methods, Select also extends the DataTables selector
26809
+ options for rows, columns and cells adding a `selected` option to the selector
26810
+ options object, allowing the developer to select only selected items or
26811
+ unselected items.
26812
+
26813
+ ## Mouse selection of items
26814
+
26815
+ Clicking on items can be used to select items. This is done by a simple event
26816
+ handler that will select the items using the API methods.
26817
+
26818
+ */
26819
+
26820
+
26821
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
26822
+ * Local functions
26823
+ */
26824
+
26825
+ /**
26826
+ * Add one or more cells to the selection when shift clicking in OS selection
26827
+ * style cell selection.
26828
+ *
26829
+ * Cell range is more complicated than row and column as we want to select
26830
+ * in the visible grid rather than by index in sequence. For example, if you
26831
+ * click first in cell 1-1 and then shift click in 2-2 - cells 1-2 and 2-1
26832
+ * should also be selected (and not 1-3, 1-4. etc)
26833
+ *
26834
+ * @param {DataTable.Api} dt DataTable
26835
+ * @param {object} idx Cell index to select to
26836
+ * @param {object} last Cell index to select from
26837
+ * @private
26838
+ */
26839
+ function cellRange( dt, idx, last )
26840
+ {
26841
+ var indexes;
26842
+ var columnIndexes;
26843
+ var rowIndexes;
26844
+ var selectColumns = function ( start, end ) {
26845
+ if ( start > end ) {
26846
+ var tmp = end;
26847
+ end = start;
26848
+ start = tmp;
26849
+ }
26850
+
26851
+ var record = false;
26852
+ return dt.columns( ':visible' ).indexes().filter( function (i) {
26853
+ if ( i === start ) {
26854
+ record = true;
26855
+ }
26856
+
26857
+ if ( i === end ) { // not else if, as start might === end
26858
+ record = false;
26859
+ return true;
26860
+ }
26861
+
26862
+ return record;
26863
+ } );
26864
+ };
26865
+
26866
+ var selectRows = function ( start, end ) {
26867
+ var indexes = dt.rows( { search: 'applied' } ).indexes();
26868
+
26869
+ // Which comes first - might need to swap
26870
+ if ( indexes.indexOf( start ) > indexes.indexOf( end ) ) {
26871
+ var tmp = end;
26872
+ end = start;
26873
+ start = tmp;
26874
+ }
26875
+
26876
+ var record = false;
26877
+ return indexes.filter( function (i) {
26878
+ if ( i === start ) {
26879
+ record = true;
26880
+ }
26881
+
26882
+ if ( i === end ) {
26883
+ record = false;
26884
+ return true;
26885
+ }
26886
+
26887
+ return record;
26888
+ } );
26889
+ };
26890
+
26891
+ if ( ! dt.cells( { selected: true } ).any() && ! last ) {
26892
+ // select from the top left cell to this one
26893
+ columnIndexes = selectColumns( 0, idx.column );
26894
+ rowIndexes = selectRows( 0 , idx.row );
26895
+ }
26896
+ else {
26897
+ // Get column indexes between old and new
26898
+ columnIndexes = selectColumns( last.column, idx.column );
26899
+ rowIndexes = selectRows( last.row , idx.row );
26900
+ }
26901
+
26902
+ indexes = dt.cells( rowIndexes, columnIndexes ).flatten();
26903
+
26904
+ if ( ! dt.cells( idx, { selected: true } ).any() ) {
26905
+ // Select range
26906
+ dt.cells( indexes ).select();
26907
+ }
26908
+ else {
26909
+ // Deselect range
26910
+ dt.cells( indexes ).deselect();
26911
+ }
26912
+ }
26913
+
26914
+ /**
26915
+ * Disable mouse selection by removing the selectors
26916
+ *
26917
+ * @param {DataTable.Api} dt DataTable to remove events from
26918
+ * @private
26919
+ */
26920
+ function disableMouseSelection( dt )
26921
+ {
26922
+ var ctx = dt.settings()[0];
26923
+ var selector = ctx._select.selector;
26924
+
26925
+ $( dt.table().container() )
26926
+ .off( 'mousedown.dtSelect', selector )
26927
+ .off( 'mouseup.dtSelect', selector )
26928
+ .off( 'click.dtSelect', selector );
26929
+
26930
+ $('body').off( 'click.dtSelect' + dt.table().node().id );
26931
+ }
26932
+
26933
+ /**
26934
+ * Attach mouse listeners to the table to allow mouse selection of items
26935
+ *
26936
+ * @param {DataTable.Api} dt DataTable to remove events from
26937
+ * @private
26938
+ */
26939
+ function enableMouseSelection ( dt )
26940
+ {
26941
+ var container = $( dt.table().container() );
26942
+ var ctx = dt.settings()[0];
26943
+ var selector = ctx._select.selector;
26944
+
26945
+ container
26946
+ .on( 'mousedown.dtSelect', selector, function(e) {
26947
+ // Disallow text selection for shift clicking on the table so multi
26948
+ // element selection doesn't look terrible!
26949
+ if ( e.shiftKey || e.metaKey || e.ctrlKey ) {
26950
+ container
26951
+ .css( '-moz-user-select', 'none' )
26952
+ .one('selectstart.dtSelect', selector, function () {
26953
+ return false;
26954
+ } );
26955
+ }
26956
+ } )
26957
+ .on( 'mouseup.dtSelect', selector, function() {
26958
+ // Allow text selection to occur again, Mozilla style (tested in FF
26959
+ // 35.0.1 - still required)
26960
+ container.css( '-moz-user-select', '' );
26961
+ } )
26962
+ .on( 'click.dtSelect', selector, function ( e ) {
26963
+ var items = dt.select.items();
26964
+ var idx;
26965
+
26966
+ // If text was selected (click and drag), then we shouldn't change
26967
+ // the row's selected state
26968
+ if ( window.getSelection ) {
26969
+ var selection = window.getSelection();
26970
+
26971
+ // If the element that contains the selection is not in the table, we can ignore it
26972
+ // This can happen if the developer selects text from the click event
26973
+ if ( ! selection.anchorNode || $(selection.anchorNode).closest('table')[0] === dt.table().node() ) {
26974
+ if ( $.trim(selection.toString()) !== '' ) {
26975
+ return;
26976
+ }
26977
+ }
26978
+ }
26979
+
26980
+ var ctx = dt.settings()[0];
26981
+
26982
+ // Ignore clicks inside a sub-table
26983
+ if ( $(e.target).closest('div.dataTables_wrapper')[0] != dt.table().container() ) {
26984
+ return;
26985
+ }
26986
+
26987
+ var cell = dt.cell( $(e.target).closest('td, th') );
26988
+
26989
+ // Check the cell actually belongs to the host DataTable (so child
26990
+ // rows, etc, are ignored)
26991
+ if ( ! cell.any() ) {
26992
+ return;
26993
+ }
26994
+
26995
+ var event = $.Event('user-select.dt');
26996
+ eventTrigger( dt, event, [ items, cell, e ] );
26997
+
26998
+ if ( event.isDefaultPrevented() ) {
26999
+ return;
27000
+ }
27001
+
27002
+ var cellIndex = cell.index();
27003
+ if ( items === 'row' ) {
27004
+ idx = cellIndex.row;
27005
+ typeSelect( e, dt, ctx, 'row', idx );
27006
+ }
27007
+ else if ( items === 'column' ) {
27008
+ idx = cell.index().column;
27009
+ typeSelect( e, dt, ctx, 'column', idx );
27010
+ }
27011
+ else if ( items === 'cell' ) {
27012
+ idx = cell.index();
27013
+ typeSelect( e, dt, ctx, 'cell', idx );
27014
+ }
27015
+
27016
+ ctx._select_lastCell = cellIndex;
27017
+ } );
27018
+
27019
+ // Blurable
27020
+ $('body').on( 'click.dtSelect' + dt.table().node().id, function ( e ) {
27021
+ if ( ctx._select.blurable ) {
27022
+ // If the click was inside the DataTables container, don't blur
27023
+ if ( $(e.target).parents().filter( dt.table().container() ).length ) {
27024
+ return;
27025
+ }
27026
+
27027
+ // Ignore elements which have been removed from the DOM (i.e. paging
27028
+ // buttons)
27029
+ if ( $(e.target).parents('html').length === 0 ) {
27030
+ return;
27031
+ }
27032
+
27033
+ // Don't blur in Editor form
27034
+ if ( $(e.target).parents('div.DTE').length ) {
27035
+ return;
27036
+ }
27037
+
27038
+ clear( ctx, true );
27039
+ }
27040
+ } );
27041
+ }
27042
+
27043
+ /**
27044
+ * Trigger an event on a DataTable
27045
+ *
27046
+ * @param {DataTable.Api} api DataTable to trigger events on
27047
+ * @param {boolean} selected true if selected, false if deselected
27048
+ * @param {string} type Item type acting on
27049
+ * @param {boolean} any Require that there are values before
27050
+ * triggering
27051
+ * @private
27052
+ */
27053
+ function eventTrigger ( api, type, args, any )
27054
+ {
27055
+ if ( any && ! api.flatten().length ) {
27056
+ return;
27057
+ }
27058
+
27059
+ if ( typeof type === 'string' ) {
27060
+ type = type +'.dt';
27061
+ }
27062
+
27063
+ args.unshift( api );
27064
+
27065
+ $(api.table().node()).trigger( type, args );
27066
+ }
27067
+
27068
+ /**
27069
+ * Update the information element of the DataTable showing information about the
27070
+ * items selected. This is done by adding tags to the existing text
27071
+ *
27072
+ * @param {DataTable.Api} api DataTable to update
27073
+ * @private
27074
+ */
27075
+ function info ( api )
27076
+ {
27077
+ var ctx = api.settings()[0];
27078
+
27079
+ if ( ! ctx._select.info || ! ctx.aanFeatures.i ) {
27080
+ return;
27081
+ }
27082
+
27083
+ if ( api.select.style() === 'api' ) {
27084
+ return;
27085
+ }
27086
+
27087
+ var rows = api.rows( { selected: true } ).flatten().length;
27088
+ var columns = api.columns( { selected: true } ).flatten().length;
27089
+ var cells = api.cells( { selected: true } ).flatten().length;
27090
+
27091
+ var add = function ( el, name, num ) {
27092
+ el.append( $('<span class="select-item"/>').append( api.i18n(
27093
+ 'select.'+name+'s',
27094
+ { _: '%d '+name+'s selected', 0: '', 1: '1 '+name+' selected' },
27095
+ num
27096
+ ) ) );
27097
+ };
27098
+
27099
+ // Internal knowledge of DataTables to loop over all information elements
27100
+ $.each( ctx.aanFeatures.i, function ( i, el ) {
27101
+ el = $(el);
27102
+
27103
+ var output = $('<span class="select-info"/>');
27104
+ add( output, 'row', rows );
27105
+ add( output, 'column', columns );
27106
+ add( output, 'cell', cells );
27107
+
27108
+ var exisiting = el.children('span.select-info');
27109
+ if ( exisiting.length ) {
27110
+ exisiting.remove();
27111
+ }
27112
+
27113
+ if ( output.text() !== '' ) {
27114
+ el.append( output );
27115
+ }
27116
+ } );
27117
+ }
27118
+
27119
+ /**
27120
+ * Initialisation of a new table. Attach event handlers and callbacks to allow
27121
+ * Select to operate correctly.
27122
+ *
27123
+ * This will occur _after_ the initial DataTables initialisation, although
27124
+ * before Ajax data is rendered, if there is ajax data
27125
+ *
27126
+ * @param {DataTable.settings} ctx Settings object to operate on
27127
+ * @private
27128
+ */
27129
+ function init ( ctx ) {
27130
+ var api = new DataTable.Api( ctx );
27131
+
27132
+ // Row callback so that classes can be added to rows and cells if the item
27133
+ // was selected before the element was created. This will happen with the
27134
+ // `deferRender` option enabled.
27135
+ //
27136
+ // This method of attaching to `aoRowCreatedCallback` is a hack until
27137
+ // DataTables has proper events for row manipulation If you are reviewing
27138
+ // this code to create your own plug-ins, please do not do this!
27139
+ ctx.aoRowCreatedCallback.push( {
27140
+ fn: function ( row, data, index ) {
27141
+ var i, ien;
27142
+ var d = ctx.aoData[ index ];
27143
+
27144
+ // Row
27145
+ if ( d._select_selected ) {
27146
+ $( row ).addClass( ctx._select.className );
27147
+ }
27148
+
27149
+ // Cells and columns - if separated out, we would need to do two
27150
+ // loops, so it makes sense to combine them into a single one
27151
+ for ( i=0, ien=ctx.aoColumns.length ; i<ien ; i++ ) {
27152
+ if ( ctx.aoColumns[i]._select_selected || (d._selected_cells && d._selected_cells[i]) ) {
27153
+ $(d.anCells[i]).addClass( ctx._select.className );
27154
+ }
27155
+ }
27156
+ },
27157
+ sName: 'select-deferRender'
27158
+ } );
27159
+
27160
+ // On Ajax reload we want to reselect all rows which are currently selected,
27161
+ // if there is an rowId (i.e. a unique value to identify each row with)
27162
+ api.on( 'preXhr.dt.dtSelect', function () {
27163
+ // note that column selection doesn't need to be cached and then
27164
+ // reselected, as they are already selected
27165
+ var rows = api.rows( { selected: true } ).ids( true ).filter( function ( d ) {
27166
+ return d !== undefined;
27167
+ } );
27168
+
27169
+ var cells = api.cells( { selected: true } ).eq(0).map( function ( cellIdx ) {
27170
+ var id = api.row( cellIdx.row ).id( true );
27171
+ return id ?
27172
+ { row: id, column: cellIdx.column } :
27173
+ undefined;
27174
+ } ).filter( function ( d ) {
27175
+ return d !== undefined;
27176
+ } );
27177
+
27178
+ // On the next draw, reselect the currently selected items
27179
+ api.one( 'draw.dt.dtSelect', function () {
27180
+ api.rows( rows ).select();
27181
+
27182
+ // `cells` is not a cell index selector, so it needs a loop
27183
+ if ( cells.any() ) {
27184
+ cells.each( function ( id ) {
27185
+ api.cells( id.row, id.column ).select();
27186
+ } );
27187
+ }
27188
+ } );
27189
+ } );
27190
+
27191
+ // Update the table information element with selected item summary
27192
+ api.on( 'draw.dtSelect.dt select.dtSelect.dt deselect.dtSelect.dt info.dt', function () {
27193
+ info( api );
27194
+ } );
27195
+
27196
+ // Clean up and release
27197
+ api.on( 'destroy.dtSelect', function () {
27198
+ disableMouseSelection( api );
27199
+ api.off( '.dtSelect' );
27200
+ } );
27201
+ }
27202
+
27203
+ /**
27204
+ * Add one or more items (rows or columns) to the selection when shift clicking
27205
+ * in OS selection style
27206
+ *
27207
+ * @param {DataTable.Api} dt DataTable
27208
+ * @param {string} type Row or column range selector
27209
+ * @param {object} idx Item index to select to
27210
+ * @param {object} last Item index to select from
27211
+ * @private
27212
+ */
27213
+ function rowColumnRange( dt, type, idx, last )
27214
+ {
27215
+ // Add a range of rows from the last selected row to this one
27216
+ var indexes = dt[type+'s']( { search: 'applied' } ).indexes();
27217
+ var idx1 = $.inArray( last, indexes );
27218
+ var idx2 = $.inArray( idx, indexes );
27219
+
27220
+ if ( ! dt[type+'s']( { selected: true } ).any() && idx1 === -1 ) {
27221
+ // select from top to here - slightly odd, but both Windows and Mac OS
27222
+ // do this
27223
+ indexes.splice( $.inArray( idx, indexes )+1, indexes.length );
27224
+ }
27225
+ else {
27226
+ // reverse so we can shift click 'up' as well as down
27227
+ if ( idx1 > idx2 ) {
27228
+ var tmp = idx2;
27229
+ idx2 = idx1;
27230
+ idx1 = tmp;
27231
+ }
27232
+
27233
+ indexes.splice( idx2+1, indexes.length );
27234
+ indexes.splice( 0, idx1 );
27235
+ }
27236
+
27237
+ if ( ! dt[type]( idx, { selected: true } ).any() ) {
27238
+ // Select range
27239
+ dt[type+'s']( indexes ).select();
27240
+ }
27241
+ else {
27242
+ // Deselect range - need to keep the clicked on row selected
27243
+ indexes.splice( $.inArray( idx, indexes ), 1 );
27244
+ dt[type+'s']( indexes ).deselect();
27245
+ }
27246
+ }
27247
+
27248
+ /**
27249
+ * Clear all selected items
27250
+ *
27251
+ * @param {DataTable.settings} ctx Settings object of the host DataTable
27252
+ * @param {boolean} [force=false] Force the de-selection to happen, regardless
27253
+ * of selection style
27254
+ * @private
27255
+ */
27256
+ function clear( ctx, force )
27257
+ {
27258
+ if ( force || ctx._select.style === 'single' ) {
27259
+ var api = new DataTable.Api( ctx );
27260
+
27261
+ api.rows( { selected: true } ).deselect();
27262
+ api.columns( { selected: true } ).deselect();
27263
+ api.cells( { selected: true } ).deselect();
27264
+ }
27265
+ }
27266
+
27267
+ /**
27268
+ * Select items based on the current configuration for style and items.
27269
+ *
27270
+ * @param {object} e Mouse event object
27271
+ * @param {DataTables.Api} dt DataTable
27272
+ * @param {DataTable.settings} ctx Settings object of the host DataTable
27273
+ * @param {string} type Items to select
27274
+ * @param {int|object} idx Index of the item to select
27275
+ * @private
27276
+ */
27277
+ function typeSelect ( e, dt, ctx, type, idx )
27278
+ {
27279
+ var style = dt.select.style();
27280
+ var isSelected = dt[type]( idx, { selected: true } ).any();
27281
+
27282
+ if ( style === 'os' ) {
27283
+ if ( e.ctrlKey || e.metaKey ) {
27284
+ // Add or remove from the selection
27285
+ dt[type]( idx ).select( ! isSelected );
27286
+ }
27287
+ else if ( e.shiftKey ) {
27288
+ if ( type === 'cell' ) {
27289
+ cellRange( dt, idx, ctx._select_lastCell || null );
27290
+ }
27291
+ else {
27292
+ rowColumnRange( dt, type, idx, ctx._select_lastCell ?
27293
+ ctx._select_lastCell[type] :
27294
+ null
27295
+ );
27296
+ }
27297
+ }
27298
+ else {
27299
+ // No cmd or shift click - deselect if selected, or select
27300
+ // this row only
27301
+ var selected = dt[type+'s']( { selected: true } );
27302
+
27303
+ if ( isSelected && selected.flatten().length === 1 ) {
27304
+ dt[type]( idx ).deselect();
27305
+ }
27306
+ else {
27307
+ selected.deselect();
27308
+ dt[type]( idx ).select();
27309
+ }
27310
+ }
27311
+ } else if ( style == 'multi+shift' ) {
27312
+ if ( e.shiftKey ) {
27313
+ if ( type === 'cell' ) {
27314
+ cellRange( dt, idx, ctx._select_lastCell || null );
27315
+ }
27316
+ else {
27317
+ rowColumnRange( dt, type, idx, ctx._select_lastCell ?
27318
+ ctx._select_lastCell[type] :
27319
+ null
27320
+ );
27321
+ }
27322
+ }
27323
+ else {
27324
+ dt[ type ]( idx ).select( ! isSelected );
27325
+ }
27326
+ }
27327
+ else {
27328
+ dt[ type ]( idx ).select( ! isSelected );
27329
+ }
27330
+ }
27331
+
27332
+
27333
+
27334
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
27335
+ * DataTables selectors
27336
+ */
27337
+
27338
+ // row and column are basically identical just assigned to different properties
27339
+ // and checking a different array, so we can dynamically create the functions to
27340
+ // reduce the code size
27341
+ $.each( [
27342
+ { type: 'row', prop: 'aoData' },
27343
+ { type: 'column', prop: 'aoColumns' }
27344
+ ], function ( i, o ) {
27345
+ DataTable.ext.selector[ o.type ].push( function ( settings, opts, indexes ) {
27346
+ var selected = opts.selected;
27347
+ var data;
27348
+ var out = [];
27349
+
27350
+ if ( selected !== true && selected !== false ) {
27351
+ return indexes;
27352
+ }
27353
+
27354
+ for ( var i=0, ien=indexes.length ; i<ien ; i++ ) {
27355
+ data = settings[ o.prop ][ indexes[i] ];
27356
+
27357
+ if ( (selected === true && data._select_selected === true) ||
27358
+ (selected === false && ! data._select_selected )
27359
+ ) {
27360
+ out.push( indexes[i] );
27361
+ }
27362
+ }
27363
+
27364
+ return out;
27365
+ } );
27366
+ } );
27367
+
27368
+ DataTable.ext.selector.cell.push( function ( settings, opts, cells ) {
27369
+ var selected = opts.selected;
27370
+ var rowData;
27371
+ var out = [];
27372
+
27373
+ if ( selected === undefined ) {
27374
+ return cells;
27375
+ }
27376
+
27377
+ for ( var i=0, ien=cells.length ; i<ien ; i++ ) {
27378
+ rowData = settings.aoData[ cells[i].row ];
27379
+
27380
+ if ( (selected === true && rowData._selected_cells && rowData._selected_cells[ cells[i].column ] === true) ||
27381
+ (selected === false && ( ! rowData._selected_cells || ! rowData._selected_cells[ cells[i].column ] ) )
27382
+ ) {
27383
+ out.push( cells[i] );
27384
+ }
27385
+ }
27386
+
27387
+ return out;
27388
+ } );
27389
+
27390
+
27391
+
27392
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
27393
+ * DataTables API
27394
+ *
27395
+ * For complete documentation, please refer to the docs/api directory or the
27396
+ * DataTables site
27397
+ */
27398
+
27399
+ // Local variables to improve compression
27400
+ var apiRegister = DataTable.Api.register;
27401
+ var apiRegisterPlural = DataTable.Api.registerPlural;
27402
+
27403
+ apiRegister( 'select()', function () {
27404
+ return this.iterator( 'table', function ( ctx ) {
27405
+ DataTable.select.init( new DataTable.Api( ctx ) );
27406
+ } );
27407
+ } );
27408
+
27409
+ apiRegister( 'select.blurable()', function ( flag ) {
27410
+ if ( flag === undefined ) {
27411
+ return this.context[0]._select.blurable;
27412
+ }
27413
+
27414
+ return this.iterator( 'table', function ( ctx ) {
27415
+ ctx._select.blurable = flag;
27416
+ } );
27417
+ } );
27418
+
27419
+ apiRegister( 'select.info()', function ( flag ) {
27420
+ if ( info === undefined ) {
27421
+ return this.context[0]._select.info;
27422
+ }
27423
+
27424
+ return this.iterator( 'table', function ( ctx ) {
27425
+ ctx._select.info = flag;
27426
+ } );
27427
+ } );
27428
+
27429
+ apiRegister( 'select.items()', function ( items ) {
27430
+ if ( items === undefined ) {
27431
+ return this.context[0]._select.items;
27432
+ }
27433
+
27434
+ return this.iterator( 'table', function ( ctx ) {
27435
+ ctx._select.items = items;
27436
+
27437
+ eventTrigger( new DataTable.Api( ctx ), 'selectItems', [ items ] );
27438
+ } );
27439
+ } );
27440
+
27441
+ // Takes effect from the _next_ selection. None disables future selection, but
27442
+ // does not clear the current selection. Use the `deselect` methods for that
27443
+ apiRegister( 'select.style()', function ( style ) {
27444
+ if ( style === undefined ) {
27445
+ return this.context[0]._select.style;
27446
+ }
27447
+
27448
+ return this.iterator( 'table', function ( ctx ) {
27449
+ ctx._select.style = style;
27450
+
27451
+ if ( ! ctx._select_init ) {
27452
+ init( ctx );
27453
+ }
27454
+
27455
+ // Add / remove mouse event handlers. They aren't required when only
27456
+ // API selection is available
27457
+ var dt = new DataTable.Api( ctx );
27458
+ disableMouseSelection( dt );
27459
+
27460
+ if ( style !== 'api' ) {
27461
+ enableMouseSelection( dt );
27462
+ }
27463
+
27464
+ eventTrigger( new DataTable.Api( ctx ), 'selectStyle', [ style ] );
27465
+ } );
27466
+ } );
27467
+
27468
+ apiRegister( 'select.selector()', function ( selector ) {
27469
+ if ( selector === undefined ) {
27470
+ return this.context[0]._select.selector;
27471
+ }
27472
+
27473
+ return this.iterator( 'table', function ( ctx ) {
27474
+ disableMouseSelection( new DataTable.Api( ctx ) );
27475
+
27476
+ ctx._select.selector = selector;
27477
+
27478
+ if ( ctx._select.style !== 'api' ) {
27479
+ enableMouseSelection( new DataTable.Api( ctx ) );
27480
+ }
27481
+ } );
27482
+ } );
27483
+
27484
+
27485
+
27486
+ apiRegisterPlural( 'rows().select()', 'row().select()', function ( select ) {
27487
+ var api = this;
27488
+
27489
+ if ( select === false ) {
27490
+ return this.deselect();
27491
+ }
27492
+
27493
+ this.iterator( 'row', function ( ctx, idx ) {
27494
+ clear( ctx );
27495
+
27496
+ ctx.aoData[ idx ]._select_selected = true;
27497
+ $( ctx.aoData[ idx ].nTr ).addClass( ctx._select.className );
27498
+ } );
27499
+
27500
+ this.iterator( 'table', function ( ctx, i ) {
27501
+ eventTrigger( api, 'select', [ 'row', api[i] ], true );
27502
+ } );
27503
+
27504
+ return this;
27505
+ } );
27506
+
27507
+ apiRegisterPlural( 'columns().select()', 'column().select()', function ( select ) {
27508
+ var api = this;
27509
+
27510
+ if ( select === false ) {
27511
+ return this.deselect();
27512
+ }
27513
+
27514
+ this.iterator( 'column', function ( ctx, idx ) {
27515
+ clear( ctx );
27516
+
27517
+ ctx.aoColumns[ idx ]._select_selected = true;
27518
+
27519
+ var column = new DataTable.Api( ctx ).column( idx );
27520
+
27521
+ $( column.header() ).addClass( ctx._select.className );
27522
+ $( column.footer() ).addClass( ctx._select.className );
27523
+
27524
+ column.nodes().to$().addClass( ctx._select.className );
27525
+ } );
27526
+
27527
+ this.iterator( 'table', function ( ctx, i ) {
27528
+ eventTrigger( api, 'select', [ 'column', api[i] ], true );
27529
+ } );
27530
+
27531
+ return this;
27532
+ } );
27533
+
27534
+ apiRegisterPlural( 'cells().select()', 'cell().select()', function ( select ) {
27535
+ var api = this;
27536
+
27537
+ if ( select === false ) {
27538
+ return this.deselect();
27539
+ }
27540
+
27541
+ this.iterator( 'cell', function ( ctx, rowIdx, colIdx ) {
27542
+ clear( ctx );
27543
+
27544
+ var data = ctx.aoData[ rowIdx ];
27545
+
27546
+ if ( data._selected_cells === undefined ) {
27547
+ data._selected_cells = [];
27548
+ }
27549
+
27550
+ data._selected_cells[ colIdx ] = true;
27551
+
27552
+ if ( data.anCells ) {
27553
+ $( data.anCells[ colIdx ] ).addClass( ctx._select.className );
27554
+ }
27555
+ } );
27556
+
27557
+ this.iterator( 'table', function ( ctx, i ) {
27558
+ eventTrigger( api, 'select', [ 'cell', api[i] ], true );
27559
+ } );
27560
+
27561
+ return this;
27562
+ } );
27563
+
27564
+
27565
+ apiRegisterPlural( 'rows().deselect()', 'row().deselect()', function () {
27566
+ var api = this;
27567
+
27568
+ this.iterator( 'row', function ( ctx, idx ) {
27569
+ ctx.aoData[ idx ]._select_selected = false;
27570
+ $( ctx.aoData[ idx ].nTr ).removeClass( ctx._select.className );
27571
+ } );
27572
+
27573
+ this.iterator( 'table', function ( ctx, i ) {
27574
+ eventTrigger( api, 'deselect', [ 'row', api[i] ], true );
27575
+ } );
27576
+
27577
+ return this;
27578
+ } );
27579
+
27580
+ apiRegisterPlural( 'columns().deselect()', 'column().deselect()', function () {
27581
+ var api = this;
27582
+
27583
+ this.iterator( 'column', function ( ctx, idx ) {
27584
+ ctx.aoColumns[ idx ]._select_selected = false;
27585
+
27586
+ var api = new DataTable.Api( ctx );
27587
+ var column = api.column( idx );
27588
+
27589
+ $( column.header() ).removeClass( ctx._select.className );
27590
+ $( column.footer() ).removeClass( ctx._select.className );
27591
+
27592
+ // Need to loop over each cell, rather than just using
27593
+ // `column().nodes()` as cells which are individually selected should
27594
+ // not have the `selected` class removed from them
27595
+ api.cells( null, idx ).indexes().each( function (cellIdx) {
27596
+ var data = ctx.aoData[ cellIdx.row ];
27597
+ var cellSelected = data._selected_cells;
27598
+
27599
+ if ( data.anCells && (! cellSelected || ! cellSelected[ cellIdx.column ]) ) {
27600
+ $( data.anCells[ cellIdx.column ] ).removeClass( ctx._select.className );
27601
+ }
27602
+ } );
27603
+ } );
27604
+
27605
+ this.iterator( 'table', function ( ctx, i ) {
27606
+ eventTrigger( api, 'deselect', [ 'column', api[i] ], true );
27607
+ } );
27608
+
27609
+ return this;
27610
+ } );
27611
+
27612
+ apiRegisterPlural( 'cells().deselect()', 'cell().deselect()', function () {
27613
+ var api = this;
27614
+
27615
+ this.iterator( 'cell', function ( ctx, rowIdx, colIdx ) {
27616
+ var data = ctx.aoData[ rowIdx ];
27617
+
27618
+ data._selected_cells[ colIdx ] = false;
27619
+
27620
+ // Remove class only if the cells exist, and the cell is not column
27621
+ // selected, in which case the class should remain (since it is selected
27622
+ // in the column)
27623
+ if ( data.anCells && ! ctx.aoColumns[ colIdx ]._select_selected ) {
27624
+ $( data.anCells[ colIdx ] ).removeClass( ctx._select.className );
27625
+ }
27626
+ } );
27627
+
27628
+ this.iterator( 'table', function ( ctx, i ) {
27629
+ eventTrigger( api, 'deselect', [ 'cell', api[i] ], true );
27630
+ } );
27631
+
27632
+ return this;
27633
+ } );
27634
+
27635
+
27636
+
27637
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
27638
+ * Buttons
27639
+ */
27640
+ function i18n( label, def ) {
27641
+ return function (dt) {
27642
+ return dt.i18n( 'buttons.'+label, def );
27643
+ };
27644
+ }
27645
+
27646
+ // Common events with suitable namespaces
27647
+ function namespacedEvents ( config ) {
27648
+ var unique = config._eventNamespace;
27649
+
27650
+ return 'draw.dt.DT'+unique+' select.dt.DT'+unique+' deselect.dt.DT'+unique;
27651
+ }
27652
+
27653
+ function enabled ( dt, config ) {
27654
+ if ( $.inArray( 'rows', config.limitTo ) !== -1 && dt.rows( { selected: true } ).any() ) {
27655
+ return true;
27656
+ }
27657
+
27658
+ if ( $.inArray( 'columns', config.limitTo ) !== -1 && dt.columns( { selected: true } ).any() ) {
27659
+ return true;
27660
+ }
27661
+
27662
+ if ( $.inArray( 'cells', config.limitTo ) !== -1 && dt.cells( { selected: true } ).any() ) {
27663
+ return true;
27664
+ }
27665
+
27666
+ return false;
27667
+ }
27668
+
27669
+ var _buttonNamespace = 0;
27670
+
27671
+ $.extend( DataTable.ext.buttons, {
27672
+ selected: {
27673
+ text: i18n( 'selected', 'Selected' ),
27674
+ className: 'buttons-selected',
27675
+ limitTo: [ 'rows', 'columns', 'cells' ],
27676
+ init: function ( dt, node, config ) {
27677
+ var that = this;
27678
+ config._eventNamespace = '.select'+(_buttonNamespace++);
27679
+
27680
+ // .DT namespace listeners are removed by DataTables automatically
27681
+ // on table destroy
27682
+ dt.on( namespacedEvents(config), function () {
27683
+ that.enable( enabled(dt, config) );
27684
+ } );
27685
+
27686
+ this.disable();
27687
+ },
27688
+ destroy: function ( dt, node, config ) {
27689
+ dt.off( config._eventNamespace );
27690
+ }
27691
+ },
27692
+ selectedSingle: {
27693
+ text: i18n( 'selectedSingle', 'Selected single' ),
27694
+ className: 'buttons-selected-single',
27695
+ init: function ( dt, node, config ) {
27696
+ var that = this;
27697
+ config._eventNamespace = '.select'+(_buttonNamespace++);
27698
+
27699
+ dt.on( namespacedEvents(config), function () {
27700
+ var count = dt.rows( { selected: true } ).flatten().length +
27701
+ dt.columns( { selected: true } ).flatten().length +
27702
+ dt.cells( { selected: true } ).flatten().length;
27703
+
27704
+ that.enable( count === 1 );
27705
+ } );
27706
+
27707
+ this.disable();
27708
+ },
27709
+ destroy: function ( dt, node, config ) {
27710
+ dt.off( config._eventNamespace );
27711
+ }
27712
+ },
27713
+ selectAll: {
27714
+ text: i18n( 'selectAll', 'Select all' ),
27715
+ className: 'buttons-select-all',
27716
+ action: function () {
27717
+ var items = this.select.items();
27718
+ this[ items+'s' ]().select();
27719
+ }
27720
+ },
27721
+ selectNone: {
27722
+ text: i18n( 'selectNone', 'Deselect all' ),
27723
+ className: 'buttons-select-none',
27724
+ action: function () {
27725
+ clear( this.settings()[0], true );
27726
+ },
27727
+ init: function ( dt, node, config ) {
27728
+ var that = this;
27729
+ config._eventNamespace = '.select'+(_buttonNamespace++);
27730
+
27731
+ dt.on( namespacedEvents(config), function () {
27732
+ var count = dt.rows( { selected: true } ).flatten().length +
27733
+ dt.columns( { selected: true } ).flatten().length +
27734
+ dt.cells( { selected: true } ).flatten().length;
27735
+
27736
+ that.enable( count > 0 );
27737
+ } );
27738
+
27739
+ this.disable();
27740
+ },
27741
+ destroy: function ( dt, node, config ) {
27742
+ dt.off( config._eventNamespace );
27743
+ }
27744
+ }
27745
+ } );
27746
+
27747
+ $.each( [ 'Row', 'Column', 'Cell' ], function ( i, item ) {
27748
+ var lc = item.toLowerCase();
27749
+
27750
+ DataTable.ext.buttons[ 'select'+item+'s' ] = {
27751
+ text: i18n( 'select'+item+'s', 'Select '+lc+'s' ),
27752
+ className: 'buttons-select-'+lc+'s',
27753
+ action: function () {
27754
+ this.select.items( lc );
27755
+ },
27756
+ init: function ( dt ) {
27757
+ var that = this;
27758
+
27759
+ dt.on( 'selectItems.dt.DT', function ( e, ctx, items ) {
27760
+ that.active( items === lc );
27761
+ } );
27762
+ }
27763
+ };
27764
+ } );
27765
+
27766
+
27767
+
27768
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
27769
+ * Initialisation
27770
+ */
27771
+
27772
+ // DataTables creation - check if select has been defined in the options. Note
27773
+ // this required that the table be in the document! If it isn't then something
27774
+ // needs to trigger this method unfortunately. The next major release of
27775
+ // DataTables will rework the events and address this.
27776
+ $(document).on( 'preInit.dt.dtSelect', function (e, ctx) {
27777
+ if ( e.namespace !== 'dt' ) {
27778
+ return;
27779
+ }
27780
+
27781
+ DataTable.select.init( new DataTable.Api( ctx ) );
27782
+ } );
27783
+
27784
+
27785
+ return DataTable.select;
27786
+ }));
27787
+
27788
+
common/vendor/datatables/datatables.min.css ADDED
@@ -0,0 +1,136 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ * This combined file was created by the DataTables downloader builder:
3
+ * https://datatables.net/download
4
+ *
5
+ * To rebuild or modify this file with the latest versions of the included
6
+ * software please visit:
7
+ * https://datatables.net/download/#dt/dt-1.10.16/af-2.2.2/b-1.5.1/cr-1.4.1/fc-3.2.4/fh-3.1.3/kt-2.3.2/r-2.2.1/rr-1.2.3/sc-1.4.4/sl-1.2.5
8
+ *
9
+ * Included libraries:
10
+ * DataTables 1.10.16, AutoFill 2.2.2, Buttons 1.5.1, ColReorder 1.4.1, FixedColumns 3.2.4, FixedHeader 3.1.3, KeyTable 2.3.2, Responsive 2.2.1, RowReorder 1.2.3, Scroller 1.4.4, Select 1.2.5
11
+ */
12
+
13
+ table.dataTable{width:100%;margin:0 auto;clear:both;border-collapse:separate;border-spacing:0}table.dataTable thead th,table.dataTable tfoot th{font-weight:bold}table.dataTable thead th,table.dataTable thead td{padding:10px 18px;border-bottom:1px solid #111}table.dataTable thead th:active,table.dataTable thead td:active{outline:none}table.dataTable tfoot th,table.dataTable tfoot td{padding:10px 18px 6px 18px;border-top:1px solid #111}table.dataTable thead .sorting,table.dataTable thead .sorting_asc,table.dataTable thead .sorting_desc,table.dataTable thead .sorting_asc_disabled,table.dataTable thead .sorting_desc_disabled{cursor:pointer;*cursor:hand;background-repeat:no-repeat;background-position:center right}table.dataTable thead .sorting{background-image:url("DataTables-1.10.16/images/sort_both.png")}table.dataTable thead .sorting_asc{background-image:url("DataTables-1.10.16/images/sort_asc.png")}table.dataTable thead .sorting_desc{background-image:url("DataTables-1.10.16/images/sort_desc.png")}table.dataTable thead .sorting_asc_disabled{background-image:url("DataTables-1.10.16/images/sort_asc_disabled.png")}table.dataTable thead .sorting_desc_disabled{background-image:url("DataTables-1.10.16/images/sort_desc_disabled.png")}table.dataTable tbody tr{background-color:#ffffff}table.dataTable tbody tr.selected{background-color:#B0BED9}table.dataTable tbody th,table.dataTable tbody td{padding:8px 10px}table.dataTable.row-border tbody th,table.dataTable.row-border tbody td,table.dataTable.display tbody th,table.dataTable.display tbody td{border-top:1px solid #ddd}table.dataTable.row-border tbody tr:first-child th,table.dataTable.row-border tbody tr:first-child td,table.dataTable.display tbody tr:first-child th,table.dataTable.display tbody tr:first-child td{border-top:none}table.dataTable.cell-border tbody th,table.dataTable.cell-border tbody td{border-top:1px solid #ddd;border-right:1px solid #ddd}table.dataTable.cell-border tbody tr th:first-child,table.dataTable.cell-border tbody tr td:first-child{border-left:1px solid #ddd}table.dataTable.cell-border tbody tr:first-child th,table.dataTable.cell-border tbody tr:first-child td{border-top:none}table.dataTable.stripe tbody tr.odd,table.dataTable.display tbody tr.odd{background-color:#f9f9f9}table.dataTable.stripe tbody tr.odd.selected,table.dataTable.display tbody tr.odd.selected{background-color:#acbad4}table.dataTable.hover tbody tr:hover,table.dataTable.display tbody tr:hover{background-color:#f6f6f6}table.dataTable.hover tbody tr:hover.selected,table.dataTable.display tbody tr:hover.selected{background-color:#aab7d1}table.dataTable.order-column tbody tr>.sorting_1,table.dataTable.order-column tbody tr>.sorting_2,table.dataTable.order-column tbody tr>.sorting_3,table.dataTable.display tbody tr>.sorting_1,table.dataTable.display tbody tr>.sorting_2,table.dataTable.display tbody tr>.sorting_3{background-color:#fafafa}table.dataTable.order-column tbody tr.selected>.sorting_1,table.dataTable.order-column tbody tr.selected>.sorting_2,table.dataTable.order-column tbody tr.selected>.sorting_3,table.dataTable.display tbody tr.selected>.sorting_1,table.dataTable.display tbody tr.selected>.sorting_2,table.dataTable.display tbody tr.selected>.sorting_3{background-color:#acbad5}table.dataTable.display tbody tr.odd>.sorting_1,table.dataTable.order-column.stripe tbody tr.odd>.sorting_1{background-color:#f1f1f1}table.dataTable.display tbody tr.odd>.sorting_2,table.dataTable.order-column.stripe tbody tr.odd>.sorting_2{background-color:#f3f3f3}table.dataTable.display tbody tr.odd>.sorting_3,table.dataTable.order-column.stripe tbody tr.odd>.sorting_3{background-color:whitesmoke}table.dataTable.display tbody tr.odd.selected>.sorting_1,table.dataTable.order-column.stripe tbody tr.odd.selected>.sorting_1{background-color:#a6b4cd}table.dataTable.display tbody tr.odd.selected>.sorting_2,table.dataTable.order-column.stripe tbody tr.odd.selected>.sorting_2{background-color:#a8b5cf}table.dataTable.display tbody tr.odd.selected>.sorting_3,table.dataTable.order-column.stripe tbody tr.odd.selected>.sorting_3{background-color:#a9b7d1}table.dataTable.display tbody tr.even>.sorting_1,table.dataTable.order-column.stripe tbody tr.even>.sorting_1{background-color:#fafafa}table.dataTable.display tbody tr.even>.sorting_2,table.dataTable.order-column.stripe tbody tr.even>.sorting_2{background-color:#fcfcfc}table.dataTable.display tbody tr.even>.sorting_3,table.dataTable.order-column.stripe tbody tr.even>.sorting_3{background-color:#fefefe}table.dataTable.display tbody tr.even.selected>.sorting_1,table.dataTable.order-column.stripe tbody tr.even.selected>.sorting_1{background-color:#acbad5}table.dataTable.display tbody tr.even.selected>.sorting_2,table.dataTable.order-column.stripe tbody tr.even.selected>.sorting_2{background-color:#aebcd6}table.dataTable.display tbody tr.even.selected>.sorting_3,table.dataTable.order-column.stripe tbody tr.even.selected>.sorting_3{background-color:#afbdd8}table.dataTable.display tbody tr:hover>.sorting_1,table.dataTable.order-column.hover tbody tr:hover>.sorting_1{background-color:#eaeaea}table.dataTable.display tbody tr:hover>.sorting_2,table.dataTable.order-column.hover tbody tr:hover>.sorting_2{background-color:#ececec}table.dataTable.display tbody tr:hover>.sorting_3,table.dataTable.order-column.hover tbody tr:hover>.sorting_3{background-color:#efefef}table.dataTable.display tbody tr:hover.selected>.sorting_1,table.dataTable.order-column.hover tbody tr:hover.selected>.sorting_1{background-color:#a2aec7}table.dataTable.display tbody tr:hover.selected>.sorting_2,table.dataTable.order-column.hover tbody tr:hover.selected>.sorting_2{background-color:#a3b0c9}table.dataTable.display tbody tr:hover.selected>.sorting_3,table.dataTable.order-column.hover tbody tr:hover.selected>.sorting_3{background-color:#a5b2cb}table.dataTable.no-footer{border-bottom:1px solid #111}table.dataTable.nowrap th,table.dataTable.nowrap td{white-space:nowrap}table.dataTable.compact thead th,table.dataTable.compact thead td{padding:4px 17px 4px 4px}table.dataTable.compact tfoot th,table.dataTable.compact tfoot td{padding:4px}table.dataTable.compact tbody th,table.dataTable.compact tbody td{padding:4px}table.dataTable th.dt-left,table.dataTable td.dt-left{text-align:left}table.dataTable th.dt-center,table.dataTable td.dt-center,table.dataTable td.dataTables_empty{text-align:center}table.dataTable th.dt-right,table.dataTable td.dt-right{text-align:right}table.dataTable th.dt-justify,table.dataTable td.dt-justify{text-align:justify}table.dataTable th.dt-nowrap,table.dataTable td.dt-nowrap{white-space:nowrap}table.dataTable thead th.dt-head-left,table.dataTable thead td.dt-head-left,table.dataTable tfoot th.dt-head-left,table.dataTable tfoot td.dt-head-left{text-align:left}table.dataTable thead th.dt-head-center,table.dataTable thead td.dt-head-center,table.dataTable tfoot th.dt-head-center,table.dataTable tfoot td.dt-head-center{text-align:center}table.dataTable thead th.dt-head-right,table.dataTable thead td.dt-head-right,table.dataTable tfoot th.dt-head-right,table.dataTable tfoot td.dt-head-right{text-align:right}table.dataTable thead th.dt-head-justify,table.dataTable thead td.dt-head-justify,table.dataTable tfoot th.dt-head-justify,table.dataTable tfoot td.dt-head-justify{text-align:justify}table.dataTable thead th.dt-head-nowrap,table.dataTable thead td.dt-head-nowrap,table.dataTable tfoot th.dt-head-nowrap,table.dataTable tfoot td.dt-head-nowrap{white-space:nowrap}table.dataTable tbody th.dt-body-left,table.dataTable tbody td.dt-body-left{text-align:left}table.dataTable tbody th.dt-body-center,table.dataTable tbody td.dt-body-center{text-align:center}table.dataTable tbody th.dt-body-right,table.dataTable tbody td.dt-body-right{text-align:right}table.dataTable tbody th.dt-body-justify,table.dataTable tbody td.dt-body-justify{text-align:justify}table.dataTable tbody th.dt-body-nowrap,table.dataTable tbody td.dt-body-nowrap{white-space:nowrap}table.dataTable,table.dataTable th,table.dataTable td{box-sizing:content-box}.dataTables_wrapper{position:relative;clear:both;*zoom:1;zoom:1}.dataTables_wrapper .dataTables_length{float:left}.dataTables_wrapper .dataTables_filter{float:right;text-align:right}.dataTables_wrapper .dataTables_filter input{margin-left:0.5em}.dataTables_wrapper .dataTables_info{clear:both;float:left;padding-top:0.755em}.dataTables_wrapper .dataTables_paginate{float:right;text-align:right;padding-top:0.25em}.dataTables_wrapper .dataTables_paginate .paginate_button{box-sizing:border-box;display:inline-block;min-width:1.5em;padding:0.5em 1em;margin-left:2px;text-align:center;text-decoration:none !important;cursor:pointer;*cursor:hand;color:#333 !important;border:1px solid transparent;border-radius:2px}.dataTables_wrapper .dataTables_paginate .paginate_button.current,.dataTables_wrapper .dataTables_paginate .paginate_button.current:hover{color:#333 !important;border:1px solid #979797;background-color:white;background:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #fff), color-stop(100%, #dcdcdc));background:-webkit-linear-gradient(top, #fff 0%, #dcdcdc 100%);background:-moz-linear-gradient(top, #fff 0%, #dcdcdc 100%);background:-ms-linear-gradient(top, #fff 0%, #dcdcdc 100%);background:-o-linear-gradient(top, #fff 0%, #dcdcdc 100%);background:linear-gradient(to bottom, #fff 0%, #dcdcdc 100%)}.dataTables_wrapper .dataTables_paginate .paginate_button.disabled,.dataTables_wrapper .dataTables_paginate .paginate_button.disabled:hover,.dataTables_wrapper .dataTables_paginate .paginate_button.disabled:active{cursor:default;color:#666 !important;border:1px solid transparent;background:transparent;box-shadow:none}.dataTables_wrapper .dataTables_paginate .paginate_button:hover{color:white !important;border:1px solid #111;background-color:#585858;background:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #585858), color-stop(100%, #111));background:-webkit-linear-gradient(top, #585858 0%, #111 100%);background:-moz-linear-gradient(top, #585858 0%, #111 100%);background:-ms-linear-gradient(top, #585858 0%, #111 100%);background:-o-linear-gradient(top, #585858 0%, #111 100%);background:linear-gradient(to bottom, #585858 0%, #111 100%)}.dataTables_wrapper .dataTables_paginate .paginate_button:active{outline:none;background-color:#2b2b2b;background:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #2b2b2b), color-stop(100%, #0c0c0c));background:-webkit-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);background:-moz-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);background:-ms-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);background:-o-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);background:linear-gradient(to bottom, #2b2b2b 0%, #0c0c0c 100%);box-shadow:inset 0 0 3px #111}.dataTables_wrapper .dataTables_paginate .ellipsis{padding:0 1em}.dataTables_wrapper .dataTables_processing{position:absolute;top:50%;left:50%;width:100%;height:40px;margin-left:-50%;margin-top:-25px;padding-top:20px;text-align:center;font-size:1.2em;background-color:white;background:-webkit-gradient(linear, left top, right top, color-stop(0%, rgba(255,255,255,0)), color-stop(25%, rgba(255,255,255,0.9)), color-stop(75%, rgba(255,255,255,0.9)), color-stop(100%, rgba(255,255,255,0)));background:-webkit-linear-gradient(left, rgba(255,255,255,0) 0%, rgba(255,255,255,0.9) 25%, rgba(255,255,255,0.9) 75%, rgba(255,255,255,0) 100%);background:-moz-linear-gradient(left, rgba(255,255,255,0) 0%, rgba(255,255,255,0.9) 25%, rgba(255,255,255,0.9) 75%, rgba(255,255,255,0) 100%);background:-ms-linear-gradient(left, rgba(255,255,255,0) 0%, rgba(255,255,255,0.9) 25%, rgba(255,255,255,0.9) 75%, rgba(255,255,255,0) 100%);background:-o-linear-gradient(left, rgba(255,255,255,0) 0%, rgba(255,255,255,0.9) 25%, rgba(255,255,255,0.9) 75%, rgba(255,255,255,0) 100%);background:linear-gradient(to right, rgba(255,255,255,0) 0%, rgba(255,255,255,0.9) 25%, rgba(255,255,255,0.9) 75%, rgba(255,255,255,0) 100%)}.dataTables_wrapper .dataTables_length,.dataTables_wrapper .dataTables_filter,.dataTables_wrapper .dataTables_info,.dataTables_wrapper .dataTables_processing,.dataTables_wrapper .dataTables_paginate{color:#333}.dataTables_wrapper .dataTables_scroll{clear:both}.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody{*margin-top:-1px;-webkit-overflow-scrolling:touch}.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>thead>tr>th,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>thead>tr>td,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>tbody>tr>th,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>tbody>tr>td{vertical-align:middle}.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>thead>tr>th>div.dataTables_sizing,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>thead>tr>td>div.dataTables_sizing,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>tbody>tr>th>div.dataTables_sizing,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>tbody>tr>td>div.dataTables_sizing{height:0;overflow:hidden;margin:0 !important;padding:0 !important}.dataTables_wrapper.no-footer .dataTables_scrollBody{border-bottom:1px solid #111}.dataTables_wrapper.no-footer div.dataTables_scrollHead table.dataTable,.dataTables_wrapper.no-footer div.dataTables_scrollBody>table{border-bottom:none}.dataTables_wrapper:after{visibility:hidden;display:block;content:"";clear:both;height:0}@media screen and (max-width: 767px){.dataTables_wrapper .dataTables_info,.dataTables_wrapper .dataTables_paginate{float:none;text-align:center}.dataTables_wrapper .dataTables_paginate{margin-top:0.5em}}@media screen and (max-width: 640px){.dataTables_wrapper .dataTables_length,.dataTables_wrapper .dataTables_filter{float:none;text-align:center}.dataTables_wrapper .dataTables_filter{margin-top:0.5em}}
14
+
15
+
16
+ div.dt-autofill-handle {
17
+ position: absolute;
18
+ height: 8px;
19
+ width: 8px;
20
+ z-index: 102;
21
+ box-sizing: border-box;
22
+ border: 1px solid #316ad1;
23
+ background: linear-gradient(to bottom, #abcffb 0%, #4989de 100%);
24
+ }
25
+
26
+ div.dt-autofill-select {
27
+ position: absolute;
28
+ z-index: 1001;
29
+ background-color: #4989de;
30
+ background-image: repeating-linear-gradient(45deg, transparent, transparent 5px, rgba(255, 255, 255, 0.5) 5px, rgba(255, 255, 255, 0.5) 10px);
31
+ }
32
+ div.dt-autofill-select.top, div.dt-autofill-select.bottom {
33
+ height: 3px;
34
+ margin-top: -1px;
35
+ }
36
+ div.dt-autofill-select.left, div.dt-autofill-select.right {
37
+ width: 3px;
38
+ margin-left: -1px;
39
+ }
40
+
41
+ div.dt-autofill-list {
42
+ position: fixed;
43
+ top: 50%;
44
+ left: 50%;
45
+ width: 500px;
46
+ margin-left: -250px;
47
+ background-color: white;
48
+ border-radius: 6px;
49
+ box-shadow: 0 0 5px #555;
50
+ border: 2px solid #444;
51
+ z-index: 11;
52
+ box-sizing: border-box;
53
+ padding: 1.5em 2em;
54
+ }
55
+ div.dt-autofill-list ul {
56
+ display: table;
57
+ margin: 0;
58
+ padding: 0;
59
+ list-style: none;
60
+ width: 100%;
61
+ }
62
+ div.dt-autofill-list ul li {
63
+ display: table-row;
64
+ }
65
+ div.dt-autofill-list ul li:last-child div.dt-autofill-question, div.dt-autofill-list ul li:last-child div.dt-autofill-button {
66
+ border-bottom: none;
67
+ }
68
+ div.dt-autofill-list ul li:hover {
69
+ background-color: #f6f6f6;
70
+ }
71
+ div.dt-autofill-list div.dt-autofill-question {
72
+ display: table-cell;
73
+ padding: 0.5em 0;
74
+ border-bottom: 1px solid #ccc;
75
+ }
76
+ div.dt-autofill-list div.dt-autofill-question input[type=number] {
77
+ padding: 6px;
78
+ width: 30px;
79
+ margin: -2px 0;
80
+ }
81
+ div.dt-autofill-list div.dt-autofill-button {
82
+ display: table-cell;
83
+ padding: 0.5em 0;
84
+ border-bottom: 1px solid #ccc;
85
+ }
86
+ div.dt-autofill-list div.dt-autofill-button button {
87
+ color: white;
88
+ margin: 0;
89
+ padding: 6px 12px;
90
+ text-align: center;
91
+ border: 1px solid #2e6da4;
92
+ background-color: #337ab7;
93
+ border-radius: 4px;
94
+ cursor: pointer;
95
+ vertical-align: middle;
96
+ }
97
+
98
+ div.dt-autofill-background {
99
+ position: fixed;
100
+ top: 0;
101
+ left: 0;
102
+ width: 100%;
103
+ height: 100%;
104
+ background: rgba(0, 0, 0, 0.7);
105
+ background: radial-gradient(ellipse farthest-corner at center, rgba(0, 0, 0, 0.3) 0%, rgba(0, 0, 0, 0.7) 100%);
106
+ z-index: 10;
107
+ }
108
+
109
+
110
+ @keyframes dtb-spinner{100%{transform:rotate(360deg)}}@-o-keyframes dtb-spinner{100%{-o-transform:rotate(360deg);transform:rotate(360deg)}}@-ms-keyframes dtb-spinner{100%{-ms-transform:rotate(360deg);transform:rotate(360deg)}}@-webkit-keyframes dtb-spinner{100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@-moz-keyframes dtb-spinner{100%{-moz-transform:rotate(360deg);transform:rotate(360deg)}}div.dt-button-info{position:fixed;top:50%;left:50%;width:400px;margin-top:-100px;margin-left:-200px;background-color:white;border:2px solid #111;box-shadow:3px 3px 8px rgba(0,0,0,0.3);border-radius:3px;text-align:center;z-index:21}div.dt-button-info h2{padding:0.5em;margin:0;font-weight:normal;border-bottom:1px solid #ddd;background-color:#f3f3f3}div.dt-button-info>div{padding:1em}button.dt-button,div.dt-button,a.dt-button{position:relative;display:inline-block;box-sizing:border-box;margin-right:0.333em;margin-bottom:0.333em;padding:0.5em 1em;border:1px solid #999;border-radius:2px;cursor:pointer;font-size:0.88em;line-height:1.6em;color:black;white-space:nowrap;overflow:hidden;background-color:#e9e9e9;background-image:-webkit-linear-gradient(top, #fff 0%, #e9e9e9 100%);background-image:-moz-linear-gradient(top, #fff 0%, #e9e9e9 100%);background-image:-ms-linear-gradient(top, #fff 0%, #e9e9e9 100%);background-image:-o-linear-gradient(top, #fff 0%, #e9e9e9 100%);background-image:linear-gradient(to bottom, #fff 0%, #e9e9e9 100%);filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr='white', EndColorStr='#e9e9e9');-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;text-decoration:none;outline:none}button.dt-button.disabled,div.dt-button.disabled,a.dt-button.disabled{color:#999;border:1px solid #d0d0d0;cursor:default;background-color:#f9f9f9;background-image:-webkit-linear-gradient(top, #fff 0%, #f9f9f9 100%);background-image:-moz-linear-gradient(top, #fff 0%, #f9f9f9 100%);background-image:-ms-linear-gradient(top, #fff 0%, #f9f9f9 100%);background-image:-o-linear-gradient(top, #fff 0%, #f9f9f9 100%);background-image:linear-gradient(to bottom, #fff 0%, #f9f9f9 100%);filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr='#ffffff', EndColorStr='#f9f9f9')}button.dt-button:active:not(.disabled),button.dt-button.active:not(.disabled),div.dt-button:active:not(.disabled),div.dt-button.active:not(.disabled),a.dt-button:active:not(.disabled),a.dt-button.active:not(.disabled){background-color:#e2e2e2;background-image:-webkit-linear-gradient(top, #f3f3f3 0%, #e2e2e2 100%);background-image:-moz-linear-gradient(top, #f3f3f3 0%, #e2e2e2 100%);background-image:-ms-linear-gradient(top, #f3f3f3 0%, #e2e2e2 100%);background-image:-o-linear-gradient(top, #f3f3f3 0%, #e2e2e2 100%);background-image:linear-gradient(to bottom, #f3f3f3 0%, #e2e2e2 100%);filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr='#f3f3f3', EndColorStr='#e2e2e2');box-shadow:inset 1px 1px 3px #999999}button.dt-button:active:not(.disabled):hover:not(.disabled),button.dt-button.active:not(.disabled):hover:not(.disabled),div.dt-button:active:not(.disabled):hover:not(.disabled),div.dt-button.active:not(.disabled):hover:not(.disabled),a.dt-button:active:not(.disabled):hover:not(.disabled),a.dt-button.active:not(.disabled):hover:not(.disabled){box-shadow:inset 1px 1px 3px #999999;background-color:#cccccc;background-image:-webkit-linear-gradient(top, #eaeaea 0%, #ccc 100%);background-image:-moz-linear-gradient(top, #eaeaea 0%, #ccc 100%);background-image:-ms-linear-gradient(top, #eaeaea 0%, #ccc 100%);background-image:-o-linear-gradient(top, #eaeaea 0%, #ccc 100%);background-image:linear-gradient(to bottom, #eaeaea 0%, #ccc 100%);filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr='#eaeaea', EndColorStr='#cccccc')}button.dt-button:hover,div.dt-button:hover,a.dt-button:hover{text-decoration:none}button.dt-button:hover:not(.disabled),div.dt-button:hover:not(.disabled),a.dt-button:hover:not(.disabled){border:1px solid #666;background-color:#e0e0e0;background-image:-webkit-linear-gradient(top, #f9f9f9 0%, #e0e0e0 100%);background-image:-moz-linear-gradient(top, #f9f9f9 0%, #e0e0e0 100%);background-image:-ms-linear-gradient(top, #f9f9f9 0%, #e0e0e0 100%);background-image:-o-linear-gradient(top, #f9f9f9 0%, #e0e0e0 100%);background-image:linear-gradient(to bottom, #f9f9f9 0%, #e0e0e0 100%);filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr='#f9f9f9', EndColorStr='#e0e0e0')}button.dt-button:focus:not(.disabled),div.dt-button:focus:not(.disabled),a.dt-button:focus:not(.disabled){border:1px solid #426c9e;text-shadow:0 1px 0 #c4def1;outline:none;background-color:#79ace9;background-image:-webkit-linear-gradient(top, #bddef4 0%, #79ace9 100%);background-image:-moz-linear-gradient(top, #bddef4 0%, #79ace9 100%);background-image:-ms-linear-gradient(top, #bddef4 0%, #79ace9 100%);background-image:-o-linear-gradient(top, #bddef4 0%, #79ace9 100%);background-image:linear-gradient(to bottom, #bddef4 0%, #79ace9 100%);filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr='#bddef4', EndColorStr='#79ace9')}.dt-button embed{outline:none}div.dt-buttons{position:relative;float:left}div.dt-buttons.buttons-right{float:right}div.dt-button-collection{position:absolute;top:0;left:0;width:150px;margin-top:3px;padding:8px 8px 4px 8px;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.4);background-color:white;overflow:hidden;z-index:2002;border-radius:5px;box-shadow:3px 3px 5px rgba(0,0,0,0.3);z-index:2002;-webkit-column-gap:8px;-moz-column-gap:8px;-ms-column-gap:8px;-o-column-gap:8px;column-gap:8px}div.dt-button-collection button.dt-button,div.dt-button-collection div.dt-button,div.dt-button-collection a.dt-button{position:relative;left:0;right:0;width:100%;display:block;float:none;margin-bottom:4px;margin-right:0}div.dt-button-collection button.dt-button:active:not(.disabled),div.dt-button-collection button.dt-button.active:not(.disabled),div.dt-button-collection div.dt-button:active:not(.disabled),div.dt-button-collection div.dt-button.active:not(.disabled),div.dt-button-collection a.dt-button:active:not(.disabled),div.dt-button-collection a.dt-button.active:not(.disabled){background-color:#dadada;background-image:-webkit-linear-gradient(top, #f0f0f0 0%, #dadada 100%);background-image:-moz-linear-gradient(top, #f0f0f0 0%, #dadada 100%);background-image:-ms-linear-gradient(top, #f0f0f0 0%, #dadada 100%);background-image:-o-linear-gradient(top, #f0f0f0 0%, #dadada 100%);background-image:linear-gradient(to bottom, #f0f0f0 0%, #dadada 100%);filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr='#f0f0f0', EndColorStr='#dadada');box-shadow:inset 1px 1px 3px #666}div.dt-button-collection.fixed{position:fixed;top:50%;left:50%;margin-left:-75px;border-radius:0}div.dt-button-collection.fixed.two-column{margin-left:-150px}div.dt-button-collection.fixed.three-column{margin-left:-225px}div.dt-button-collection.fixed.four-column{margin-left:-300px}div.dt-button-collection>*{-webkit-column-break-inside:avoid;break-inside:avoid}div.dt-button-collection.two-column{width:300px;padding-bottom:1px;-webkit-column-count:2;-moz-column-count:2;-ms-column-count:2;-o-column-count:2;column-count:2}div.dt-button-collection.three-column{width:450px;padding-bottom:1px;-webkit-column-count:3;-moz-column-count:3;-ms-column-count:3;-o-column-count:3;column-count:3}div.dt-button-collection.four-column{width:600px;padding-bottom:1px;-webkit-column-count:4;-moz-column-count:4;-ms-column-count:4;-o-column-count:4;column-count:4}div.dt-button-collection .dt-button{border-radius:0}div.dt-button-background{position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.7);background:-ms-radial-gradient(center, ellipse farthest-corner, rgba(0,0,0,0.3) 0%, rgba(0,0,0,0.7) 100%);background:-moz-radial-gradient(center, ellipse farthest-corner, rgba(0,0,0,0.3) 0%, rgba(0,0,0,0.7) 100%);background:-o-radial-gradient(center, ellipse farthest-corner, rgba(0,0,0,0.3) 0%, rgba(0,0,0,0.7) 100%);background:-webkit-gradient(radial, center center, 0, center center, 497, color-stop(0, rgba(0,0,0,0.3)), color-stop(1, rgba(0,0,0,0.7)));background:-webkit-radial-gradient(center, ellipse farthest-corner, rgba(0,0,0,0.3) 0%, rgba(0,0,0,0.7) 100%);background:radial-gradient(ellipse farthest-corner at center, rgba(0,0,0,0.3) 0%, rgba(0,0,0,0.7) 100%);z-index:2001}@media screen and (max-width: 640px){div.dt-buttons{float:none !important;text-align:center}}button.dt-button.processing,div.dt-button.processing,a.dt-button.processing{color:rgba(0,0,0,0.2)}button.dt-button.processing:after,div.dt-button.processing:after,a.dt-button.processing:after{position:absolute;top:50%;left:50%;width:16px;height:16px;margin:-8px 0 0 -8px;box-sizing:border-box;display:block;content:' ';border:2px solid #282828;border-radius:50%;border-left-color:transparent;border-right-color:transparent;animation:dtb-spinner 1500ms infinite linear;-o-animation:dtb-spinner 1500ms infinite linear;-ms-animation:dtb-spinner 1500ms infinite linear;-webkit-animation:dtb-spinner 1500ms infinite linear;-moz-animation:dtb-spinner 1500ms infinite linear}
111
+
112
+
113
+ table.DTCR_clonedTable.dataTable{position:absolute !important;background-color:rgba(255,255,255,0.7);z-index:202}div.DTCR_pointer{width:1px;background-color:#0259C4;z-index:201}
114
+
115
+
116
+ table.DTFC_Cloned thead,table.DTFC_Cloned tfoot{background-color:white}div.DTFC_Blocker{background-color:white}div.DTFC_LeftWrapper table.dataTable,div.DTFC_RightWrapper table.dataTable{margin-bottom:0;z-index:2}div.DTFC_LeftWrapper table.dataTable.no-footer,div.DTFC_RightWrapper table.dataTable.no-footer{border-bottom:none}
117
+
118
+
119
+ table.fixedHeader-floating{position:fixed !important;background-color:white}table.fixedHeader-floating.no-footer{border-bottom-width:0}table.fixedHeader-locked{position:absolute !important;background-color:white}@media print{table.fixedHeader-floating{display:none}}
120
+
121
+
122
+ table.dataTable th.focus,table.dataTable td.focus{outline:3px solid #3366FF;outline-offset:-1px}
123
+
124
+
125
+ table.dataTable.dtr-inline.collapsed>tbody>tr>td.child,table.dataTable.dtr-inline.collapsed>tbody>tr>th.child,table.dataTable.dtr-inline.collapsed>tbody>tr>td.dataTables_empty{cursor:default !important}table.dataTable.dtr-inline.collapsed>tbody>tr>td.child:before,table.dataTable.dtr-inline.collapsed>tbody>tr>th.child:before,table.dataTable.dtr-inline.collapsed>tbody>tr>td.dataTables_empty:before{display:none !important}table.dataTable.dtr-inline.collapsed>tbody>tr[role="row"]>td:first-child,table.dataTable.dtr-inline.collapsed>tbody>tr[role="row"]>th:first-child{position:relative;padding-left:30px;cursor:pointer}table.dataTable.dtr-inline.collapsed>tbody>tr[role="row"]>td:first-child:before,table.dataTable.dtr-inline.collapsed>tbody>tr[role="row"]>th:first-child:before{top:9px;left:4px;height:14px;width:14px;display:block;position:absolute;color:white;border:2px solid white;border-radius:14px;box-shadow:0 0 3px #444;box-sizing:content-box;text-align:center;text-indent:0 !important;font-family:'Courier New', Courier, monospace;line-height:14px;content:'+';background-color:#31b131}table.dataTable.dtr-inline.collapsed>tbody>tr.parent>td:first-child:before,table.dataTable.dtr-inline.collapsed>tbody>tr.parent>th:first-child:before{content:'-';background-color:#d33333}table.dataTable.dtr-inline.collapsed.compact>tbody>tr>td:first-child,table.dataTable.dtr-inline.collapsed.compact>tbody>tr>th:first-child{padding-left:27px}table.dataTable.dtr-inline.collapsed.compact>tbody>tr>td:first-child:before,table.dataTable.dtr-inline.collapsed.compact>tbody>tr>th:first-child:before{top:5px;left:4px;height:14px;width:14px;border-radius:14px;line-height:14px;text-indent:3px}table.dataTable.dtr-column>tbody>tr>td.control,table.dataTable.dtr-column>tbody>tr>th.control{position:relative;cursor:pointer}table.dataTable.dtr-column>tbody>tr>td.control:before,table.dataTable.dtr-column>tbody>tr>th.control:before{top:50%;left:50%;height:16px;width:16px;margin-top:-10px;margin-left:-10px;display:block;position:absolute;color:white;border:2px solid white;border-radius:14px;box-shadow:0 0 3px #444;box-sizing:content-box;text-align:center;text-indent:0 !important;font-family:'Courier New', Courier, monospace;line-height:14px;content:'+';background-color:#31b131}table.dataTable.dtr-column>tbody>tr.parent td.control:before,table.dataTable.dtr-column>tbody>tr.parent th.control:before{content:'-';background-color:#d33333}table.dataTable>tbody>tr.child{padding:0.5em 1em}table.dataTable>tbody>tr.child:hover{background:transparent !important}table.dataTable>tbody>tr.child ul.dtr-details{display:inline-block;list-style-type:none;margin:0;padding:0}table.dataTable>tbody>tr.child ul.dtr-details>li{border-bottom:1px solid #efefef;padding:0.5em 0}table.dataTable>tbody>tr.child ul.dtr-details>li:first-child{padding-top:0}table.dataTable>tbody>tr.child ul.dtr-details>li:last-child{border-bottom:none}table.dataTable>tbody>tr.child span.dtr-title{display:inline-block;min-width:75px;font-weight:bold}div.dtr-modal{position:fixed;box-sizing:border-box;top:0;left:0;height:100%;width:100%;z-index:100;padding:10em 1em}div.dtr-modal div.dtr-modal-display{position:absolute;top:0;left:0;bottom:0;right:0;width:50%;height:50%;overflow:auto;margin:auto;z-index:102;overflow:auto;background-color:#f5f5f7;border:1px solid black;border-radius:0.5em;box-shadow:0 12px 30px rgba(0,0,0,0.6)}div.dtr-modal div.dtr-modal-content{position:relative;padding:1em}div.dtr-modal div.dtr-modal-close{position:absolute;top:6px;right:6px;width:22px;height:22px;border:1px solid #eaeaea;background-color:#f9f9f9;text-align:center;border-radius:3px;cursor:pointer;z-index:12}div.dtr-modal div.dtr-modal-close:hover{background-color:#eaeaea}div.dtr-modal div.dtr-modal-background{position:fixed;top:0;left:0;right:0;bottom:0;z-index:101;background:rgba(0,0,0,0.6)}@media screen and (max-width: 767px){div.dtr-modal div.dtr-modal-display{width:95%}}
126
+
127
+
128
+ table.dt-rowReorder-float{position:absolute !important;opacity:0.8;table-layout:fixed;outline:2px solid #888;outline-offset:-2px;z-index:2001}tr.dt-rowReorder-moving{outline:2px solid #555;outline-offset:-2px}body.dt-rowReorder-noOverflow{overflow-x:hidden}table.dataTable td.reorder{text-align:center;cursor:move}
129
+
130
+
131
+ div.DTS{display:block !important}div.DTS tbody th,div.DTS tbody td{white-space:nowrap}div.DTS div.DTS_Loading{z-index:1}div.DTS div.dataTables_scrollBody{background:repeating-linear-gradient(45deg, #edeeff, #edeeff 10px, #fff 10px, #fff 20px)}div.DTS div.dataTables_scrollBody table{z-index:2}div.DTS div.dataTables_paginate,div.DTS div.dataTables_length{display:none}
132
+
133
+
134
+ table.dataTable tbody>tr.selected,table.dataTable tbody>tr>.selected{background-color:#B0BED9}table.dataTable.stripe tbody>tr.odd.selected,table.dataTable.stripe tbody>tr.odd>.selected,table.dataTable.display tbody>tr.odd.selected,table.dataTable.display tbody>tr.odd>.selected{background-color:#acbad4}table.dataTable.hover tbody>tr.selected:hover,table.dataTable.hover tbody>tr>.selected:hover,table.dataTable.display tbody>tr.selected:hover,table.dataTable.display tbody>tr>.selected:hover{background-color:#aab7d1}table.dataTable.order-column tbody>tr.selected>.sorting_1,table.dataTable.order-column tbody>tr.selected>.sorting_2,table.dataTable.order-column tbody>tr.selected>.sorting_3,table.dataTable.order-column tbody>tr>.selected,table.dataTable.display tbody>tr.selected>.sorting_1,table.dataTable.display tbody>tr.selected>.sorting_2,table.dataTable.display tbody>tr.selected>.sorting_3,table.dataTable.display tbody>tr>.selected{background-color:#acbad5}table.dataTable.display tbody>tr.odd.selected>.sorting_1,table.dataTable.order-column.stripe tbody>tr.odd.selected>.sorting_1{background-color:#a6b4cd}table.dataTable.display tbody>tr.odd.selected>.sorting_2,table.dataTable.order-column.stripe tbody>tr.odd.selected>.sorting_2{background-color:#a8b5cf}table.dataTable.display tbody>tr.odd.selected>.sorting_3,table.dataTable.order-column.stripe tbody>tr.odd.selected>.sorting_3{background-color:#a9b7d1}table.dataTable.display tbody>tr.even.selected>.sorting_1,table.dataTable.order-column.stripe tbody>tr.even.selected>.sorting_1{background-color:#acbad5}table.dataTable.display tbody>tr.even.selected>.sorting_2,table.dataTable.order-column.stripe tbody>tr.even.selected>.sorting_2{background-color:#aebcd6}table.dataTable.display tbody>tr.even.selected>.sorting_3,table.dataTable.order-column.stripe tbody>tr.even.selected>.sorting_3{background-color:#afbdd8}table.dataTable.display tbody>tr.odd>.selected,table.dataTable.order-column.stripe tbody>tr.odd>.selected{background-color:#a6b4cd}table.dataTable.display tbody>tr.even>.selected,table.dataTable.order-column.stripe tbody>tr.even>.selected{background-color:#acbad5}table.dataTable.display tbody>tr.selected:hover>.sorting_1,table.dataTable.order-column.hover tbody>tr.selected:hover>.sorting_1{background-color:#a2aec7}table.dataTable.display tbody>tr.selected:hover>.sorting_2,table.dataTable.order-column.hover tbody>tr.selected:hover>.sorting_2{background-color:#a3b0c9}table.dataTable.display tbody>tr.selected:hover>.sorting_3,table.dataTable.order-column.hover tbody>tr.selected:hover>.sorting_3{background-color:#a5b2cb}table.dataTable.display tbody>tr:hover>.selected,table.dataTable.display tbody>tr>.selected:hover,table.dataTable.order-column.hover tbody>tr:hover>.selected,table.dataTable.order-column.hover tbody>tr>.selected:hover{background-color:#a2aec7}table.dataTable tbody td.select-checkbox,table.dataTable tbody th.select-checkbox{position:relative}table.dataTable tbody td.select-checkbox:before,table.dataTable tbody td.select-checkbox:after,table.dataTable tbody th.select-checkbox:before,table.dataTable tbody th.select-checkbox:after{display:block;position:absolute;top:1.2em;left:50%;width:12px;height:12px;box-sizing:border-box}table.dataTable tbody td.select-checkbox:before,table.dataTable tbody th.select-checkbox:before{content:' ';margin-top:-6px;margin-left:-6px;border:1px solid black;border-radius:3px}table.dataTable tr.selected td.select-checkbox:after,table.dataTable tr.selected th.select-checkbox:after{content:'\2714';margin-top:-11px;margin-left:-4px;text-align:center;text-shadow:1px 1px #B0BED9, -1px -1px #B0BED9, 1px -1px #B0BED9, -1px 1px #B0BED9}div.dataTables_wrapper span.select-info,div.dataTables_wrapper span.select-item{margin-left:0.5em}@media screen and (max-width: 640px){div.dataTables_wrapper span.select-info,div.dataTables_wrapper span.select-item{margin-left:0;display:block}}
135
+
136
+
common/vendor/datatables/datatables.min.js ADDED
@@ -0,0 +1,466 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ * This combined file was created by the DataTables downloader builder:
3
+ * https://datatables.net/download
4
+ *
5
+ * To rebuild or modify this file with the latest versions of the included
6
+ * software please visit:
7
+ * https://datatables.net/download/#dt/dt-1.10.16/af-2.2.2/b-1.5.1/cr-1.4.1/fc-3.2.4/fh-3.1.3/kt-2.3.2/r-2.2.1/rr-1.2.3/sc-1.4.4/sl-1.2.5
8
+ *
9
+ * Included libraries:
10
+ * DataTables 1.10.16, AutoFill 2.2.2, Buttons 1.5.1, ColReorder 1.4.1, FixedColumns 3.2.4, FixedHeader 3.1.3, KeyTable 2.3.2, Responsive 2.2.1, RowReorder 1.2.3, Scroller 1.4.4, Select 1.2.5
11
+ */
12
+
13
+ /*!
14
+ DataTables 1.10.16
15
+ ©2008-2017 SpryMedia Ltd - datatables.net/license
16
+ */
17
+ (function(h){"function"===typeof define&&define.amd?define(["jquery"],function(E){return h(E,window,document)}):"object"===typeof exports?module.exports=function(E,G){E||(E=window);G||(G="undefined"!==typeof window?require("jquery"):require("jquery")(E));return h(G,E,E.document)}:h(jQuery,window,document)})(function(h,E,G,k){function X(a){var b,c,d={};h.each(a,function(e){if((b=e.match(/^([^A-Z]+?)([A-Z])/))&&-1!=="a aa ai ao as b fn i m o s ".indexOf(b[1]+" "))c=e.replace(b[0],b[2].toLowerCase()),
18
+ d[c]=e,"o"===b[1]&&X(a[e])});a._hungarianMap=d}function I(a,b,c){a._hungarianMap||X(a);var d;h.each(b,function(e){d=a._hungarianMap[e];if(d!==k&&(c||b[d]===k))"o"===d.charAt(0)?(b[d]||(b[d]={}),h.extend(!0,b[d],b[e]),I(a[d],b[d],c)):b[d]=b[e]})}function Ca(a){var b=m.defaults.oLanguage,c=a.sZeroRecords;!a.sEmptyTable&&(c&&"No data available in table"===b.sEmptyTable)&&F(a,a,"sZeroRecords","sEmptyTable");!a.sLoadingRecords&&(c&&"Loading..."===b.sLoadingRecords)&&F(a,a,"sZeroRecords","sLoadingRecords");
19
+ a.sInfoThousands&&(a.sThousands=a.sInfoThousands);(a=a.sDecimal)&&cb(a)}function db(a){A(a,"ordering","bSort");A(a,"orderMulti","bSortMulti");A(a,"orderClasses","bSortClasses");A(a,"orderCellsTop","bSortCellsTop");A(a,"order","aaSorting");A(a,"orderFixed","aaSortingFixed");A(a,"paging","bPaginate");A(a,"pagingType","sPaginationType");A(a,"pageLength","iDisplayLength");A(a,"searching","bFilter");"boolean"===typeof a.sScrollX&&(a.sScrollX=a.sScrollX?"100%":"");"boolean"===typeof a.scrollX&&(a.scrollX=
20
+ a.scrollX?"100%":"");if(a=a.aoSearchCols)for(var b=0,c=a.length;b<c;b++)a[b]&&I(m.models.oSearch,a[b])}function eb(a){A(a,"orderable","bSortable");A(a,"orderData","aDataSort");A(a,"orderSequence","asSorting");A(a,"orderDataType","sortDataType");var b=a.aDataSort;"number"===typeof b&&!h.isArray(b)&&(a.aDataSort=[b])}function fb(a){if(!m.__browser){var b={};m.__browser=b;var c=h("<div/>").css({position:"fixed",top:0,left:-1*h(E).scrollLeft(),height:1,width:1,overflow:"hidden"}).append(h("<div/>").css({position:"absolute",
21
+ top:1,left:1,width:100,overflow:"scroll"}).append(h("<div/>").css({width:"100%",height:10}))).appendTo("body"),d=c.children(),e=d.children();b.barWidth=d[0].offsetWidth-d[0].clientWidth;b.bScrollOversize=100===e[0].offsetWidth&&100!==d[0].clientWidth;b.bScrollbarLeft=1!==Math.round(e.offset().left);b.bBounding=c[0].getBoundingClientRect().width?!0:!1;c.remove()}h.extend(a.oBrowser,m.__browser);a.oScroll.iBarWidth=m.__browser.barWidth}function gb(a,b,c,d,e,f){var g,j=!1;c!==k&&(g=c,j=!0);for(;d!==
22
+ e;)a.hasOwnProperty(d)&&(g=j?b(g,a[d],d,a):a[d],j=!0,d+=f);return g}function Da(a,b){var c=m.defaults.column,d=a.aoColumns.length,c=h.extend({},m.models.oColumn,c,{nTh:b?b:G.createElement("th"),sTitle:c.sTitle?c.sTitle:b?b.innerHTML:"",aDataSort:c.aDataSort?c.aDataSort:[d],mData:c.mData?c.mData:d,idx:d});a.aoColumns.push(c);c=a.aoPreSearchCols;c[d]=h.extend({},m.models.oSearch,c[d]);ja(a,d,h(b).data())}function ja(a,b,c){var b=a.aoColumns[b],d=a.oClasses,e=h(b.nTh);if(!b.sWidthOrig){b.sWidthOrig=
23
+ e.attr("width")||null;var f=(e.attr("style")||"").match(/width:\s*(\d+[pxem%]+)/);f&&(b.sWidthOrig=f[1])}c!==k&&null!==c&&(eb(c),I(m.defaults.column,c),c.mDataProp!==k&&!c.mData&&(c.mData=c.mDataProp),c.sType&&(b._sManualType=c.sType),c.className&&!c.sClass&&(c.sClass=c.className),c.sClass&&e.addClass(c.sClass),h.extend(b,c),F(b,c,"sWidth","sWidthOrig"),c.iDataSort!==k&&(b.aDataSort=[c.iDataSort]),F(b,c,"aDataSort"));var g=b.mData,j=Q(g),i=b.mRender?Q(b.mRender):null,c=function(a){return"string"===
24
+ typeof a&&-1!==a.indexOf("@")};b._bAttrSrc=h.isPlainObject(g)&&(c(g.sort)||c(g.type)||c(g.filter));b._setter=null;b.fnGetData=function(a,b,c){var d=j(a,b,k,c);return i&&b?i(d,b,a,c):d};b.fnSetData=function(a,b,c){return R(g)(a,b,c)};"number"!==typeof g&&(a._rowReadObject=!0);a.oFeatures.bSort||(b.bSortable=!1,e.addClass(d.sSortableNone));a=-1!==h.inArray("asc",b.asSorting);c=-1!==h.inArray("desc",b.asSorting);!b.bSortable||!a&&!c?(b.sSortingClass=d.sSortableNone,b.sSortingClassJUI=""):a&&!c?(b.sSortingClass=
25
+ d.sSortableAsc,b.sSortingClassJUI=d.sSortJUIAscAllowed):!a&&c?(b.sSortingClass=d.sSortableDesc,b.sSortingClassJUI=d.sSortJUIDescAllowed):(b.sSortingClass=d.sSortable,b.sSortingClassJUI=d.sSortJUI)}function Y(a){if(!1!==a.oFeatures.bAutoWidth){var b=a.aoColumns;Ea(a);for(var c=0,d=b.length;c<d;c++)b[c].nTh.style.width=b[c].sWidth}b=a.oScroll;(""!==b.sY||""!==b.sX)&&ka(a);r(a,null,"column-sizing",[a])}function Z(a,b){var c=la(a,"bVisible");return"number"===typeof c[b]?c[b]:null}function $(a,b){var c=
26
+ la(a,"bVisible"),c=h.inArray(b,c);return-1!==c?c:null}function aa(a){var b=0;h.each(a.aoColumns,function(a,d){d.bVisible&&"none"!==h(d.nTh).css("display")&&b++});return b}function la(a,b){var c=[];h.map(a.aoColumns,function(a,e){a[b]&&c.push(e)});return c}function Fa(a){var b=a.aoColumns,c=a.aoData,d=m.ext.type.detect,e,f,g,j,i,h,l,q,t;e=0;for(f=b.length;e<f;e++)if(l=b[e],t=[],!l.sType&&l._sManualType)l.sType=l._sManualType;else if(!l.sType){g=0;for(j=d.length;g<j;g++){i=0;for(h=c.length;i<h;i++){t[i]===
27
+ k&&(t[i]=B(a,i,e,"type"));q=d[g](t[i],a);if(!q&&g!==d.length-1)break;if("html"===q)break}if(q){l.sType=q;break}}l.sType||(l.sType="string")}}function hb(a,b,c,d){var e,f,g,j,i,n,l=a.aoColumns;if(b)for(e=b.length-1;0<=e;e--){n=b[e];var q=n.targets!==k?n.targets:n.aTargets;h.isArray(q)||(q=[q]);f=0;for(g=q.length;f<g;f++)if("number"===typeof q[f]&&0<=q[f]){for(;l.length<=q[f];)Da(a);d(q[f],n)}else if("number"===typeof q[f]&&0>q[f])d(l.length+q[f],n);else if("string"===typeof q[f]){j=0;for(i=l.length;j<
28
+ i;j++)("_all"==q[f]||h(l[j].nTh).hasClass(q[f]))&&d(j,n)}}if(c){e=0;for(a=c.length;e<a;e++)d(e,c[e])}}function M(a,b,c,d){var e=a.aoData.length,f=h.extend(!0,{},m.models.oRow,{src:c?"dom":"data",idx:e});f._aData=b;a.aoData.push(f);for(var g=a.aoColumns,j=0,i=g.length;j<i;j++)g[j].sType=null;a.aiDisplayMaster.push(e);b=a.rowIdFn(b);b!==k&&(a.aIds[b]=f);(c||!a.oFeatures.bDeferRender)&&Ga(a,e,c,d);return e}function ma(a,b){var c;b instanceof h||(b=h(b));return b.map(function(b,e){c=Ha(a,e);return M(a,
29
+ c.data,e,c.cells)})}function B(a,b,c,d){var e=a.iDraw,f=a.aoColumns[c],g=a.aoData[b]._aData,j=f.sDefaultContent,i=f.fnGetData(g,d,{settings:a,row:b,col:c});if(i===k)return a.iDrawError!=e&&null===j&&(J(a,0,"Requested unknown parameter "+("function"==typeof f.mData?"{function}":"'"+f.mData+"'")+" for row "+b+", column "+c,4),a.iDrawError=e),j;if((i===g||null===i)&&null!==j&&d!==k)i=j;else if("function"===typeof i)return i.call(g);return null===i&&"display"==d?"":i}function ib(a,b,c,d){a.aoColumns[c].fnSetData(a.aoData[b]._aData,
30
+ d,{settings:a,row:b,col:c})}function Ia(a){return h.map(a.match(/(\\.|[^\.])+/g)||[""],function(a){return a.replace(/\\\./g,".")})}function Q(a){if(h.isPlainObject(a)){var b={};h.each(a,function(a,c){c&&(b[a]=Q(c))});return function(a,c,f,g){var j=b[c]||b._;return j!==k?j(a,c,f,g):a}}if(null===a)return function(a){return a};if("function"===typeof a)return function(b,c,f,g){return a(b,c,f,g)};if("string"===typeof a&&(-1!==a.indexOf(".")||-1!==a.indexOf("[")||-1!==a.indexOf("("))){var c=function(a,
31
+ b,f){var g,j;if(""!==f){j=Ia(f);for(var i=0,n=j.length;i<n;i++){f=j[i].match(ba);g=j[i].match(U);if(f){j[i]=j[i].replace(ba,"");""!==j[i]&&(a=a[j[i]]);g=[];j.splice(0,i+1);j=j.join(".");if(h.isArray(a)){i=0;for(n=a.length;i<n;i++)g.push(c(a[i],b,j))}a=f[0].substring(1,f[0].length-1);a=""===a?g:g.join(a);break}else if(g){j[i]=j[i].replace(U,"");a=a[j[i]]();continue}if(null===a||a[j[i]]===k)return k;a=a[j[i]]}}return a};return function(b,e){return c(b,e,a)}}return function(b){return b[a]}}function R(a){if(h.isPlainObject(a))return R(a._);
32
+ if(null===a)return function(){};if("function"===typeof a)return function(b,d,e){a(b,"set",d,e)};if("string"===typeof a&&(-1!==a.indexOf(".")||-1!==a.indexOf("[")||-1!==a.indexOf("("))){var b=function(a,d,e){var e=Ia(e),f;f=e[e.length-1];for(var g,j,i=0,n=e.length-1;i<n;i++){g=e[i].match(ba);j=e[i].match(U);if(g){e[i]=e[i].replace(ba,"");a[e[i]]=[];f=e.slice();f.splice(0,i+1);g=f.join(".");if(h.isArray(d)){j=0;for(n=d.length;j<n;j++)f={},b(f,d[j],g),a[e[i]].push(f)}else a[e[i]]=d;return}j&&(e[i]=e[i].replace(U,
33
+ ""),a=a[e[i]](d));if(null===a[e[i]]||a[e[i]]===k)a[e[i]]={};a=a[e[i]]}if(f.match(U))a[f.replace(U,"")](d);else a[f.replace(ba,"")]=d};return function(c,d){return b(c,d,a)}}return function(b,d){b[a]=d}}function Ja(a){return D(a.aoData,"_aData")}function na(a){a.aoData.length=0;a.aiDisplayMaster.length=0;a.aiDisplay.length=0;a.aIds={}}function oa(a,b,c){for(var d=-1,e=0,f=a.length;e<f;e++)a[e]==b?d=e:a[e]>b&&a[e]--; -1!=d&&c===k&&a.splice(d,1)}function ca(a,b,c,d){var e=a.aoData[b],f,g=function(c,d){for(;c.childNodes.length;)c.removeChild(c.firstChild);
34
+ c.innerHTML=B(a,b,d,"display")};if("dom"===c||(!c||"auto"===c)&&"dom"===e.src)e._aData=Ha(a,e,d,d===k?k:e._aData).data;else{var j=e.anCells;if(j)if(d!==k)g(j[d],d);else{c=0;for(f=j.length;c<f;c++)g(j[c],c)}}e._aSortData=null;e._aFilterData=null;g=a.aoColumns;if(d!==k)g[d].sType=null;else{c=0;for(f=g.length;c<f;c++)g[c].sType=null;Ka(a,e)}}function Ha(a,b,c,d){var e=[],f=b.firstChild,g,j,i=0,n,l=a.aoColumns,q=a._rowReadObject,d=d!==k?d:q?{}:[],t=function(a,b){if("string"===typeof a){var c=a.indexOf("@");
35
+ -1!==c&&(c=a.substring(c+1),R(a)(d,b.getAttribute(c)))}},m=function(a){if(c===k||c===i)j=l[i],n=h.trim(a.innerHTML),j&&j._bAttrSrc?(R(j.mData._)(d,n),t(j.mData.sort,a),t(j.mData.type,a),t(j.mData.filter,a)):q?(j._setter||(j._setter=R(j.mData)),j._setter(d,n)):d[i]=n;i++};if(f)for(;f;){g=f.nodeName.toUpperCase();if("TD"==g||"TH"==g)m(f),e.push(f);f=f.nextSibling}else{e=b.anCells;f=0;for(g=e.length;f<g;f++)m(e[f])}if(b=b.firstChild?b:b.nTr)(b=b.getAttribute("id"))&&R(a.rowId)(d,b);return{data:d,cells:e}}
36
+ function Ga(a,b,c,d){var e=a.aoData[b],f=e._aData,g=[],j,i,n,l,q;if(null===e.nTr){j=c||G.createElement("tr");e.nTr=j;e.anCells=g;j._DT_RowIndex=b;Ka(a,e);l=0;for(q=a.aoColumns.length;l<q;l++){n=a.aoColumns[l];i=c?d[l]:G.createElement(n.sCellType);i._DT_CellIndex={row:b,column:l};g.push(i);if((!c||n.mRender||n.mData!==l)&&(!h.isPlainObject(n.mData)||n.mData._!==l+".display"))i.innerHTML=B(a,b,l,"display");n.sClass&&(i.className+=" "+n.sClass);n.bVisible&&!c?j.appendChild(i):!n.bVisible&&c&&i.parentNode.removeChild(i);
37
+ n.fnCreatedCell&&n.fnCreatedCell.call(a.oInstance,i,B(a,b,l),f,b,l)}r(a,"aoRowCreatedCallback",null,[j,f,b])}e.nTr.setAttribute("role","row")}function Ka(a,b){var c=b.nTr,d=b._aData;if(c){var e=a.rowIdFn(d);e&&(c.id=e);d.DT_RowClass&&(e=d.DT_RowClass.split(" "),b.__rowc=b.__rowc?qa(b.__rowc.concat(e)):e,h(c).removeClass(b.__rowc.join(" ")).addClass(d.DT_RowClass));d.DT_RowAttr&&h(c).attr(d.DT_RowAttr);d.DT_RowData&&h(c).data(d.DT_RowData)}}function jb(a){var b,c,d,e,f,g=a.nTHead,j=a.nTFoot,i=0===
38
+ h("th, td",g).length,n=a.oClasses,l=a.aoColumns;i&&(e=h("<tr/>").appendTo(g));b=0;for(c=l.length;b<c;b++)f=l[b],d=h(f.nTh).addClass(f.sClass),i&&d.appendTo(e),a.oFeatures.bSort&&(d.addClass(f.sSortingClass),!1!==f.bSortable&&(d.attr("tabindex",a.iTabIndex).attr("aria-controls",a.sTableId),La(a,f.nTh,b))),f.sTitle!=d[0].innerHTML&&d.html(f.sTitle),Ma(a,"header")(a,d,f,n);i&&da(a.aoHeader,g);h(g).find(">tr").attr("role","row");h(g).find(">tr>th, >tr>td").addClass(n.sHeaderTH);h(j).find(">tr>th, >tr>td").addClass(n.sFooterTH);
39
+ if(null!==j){a=a.aoFooter[0];b=0;for(c=a.length;b<c;b++)f=l[b],f.nTf=a[b].cell,f.sClass&&h(f.nTf).addClass(f.sClass)}}function ea(a,b,c){var d,e,f,g=[],j=[],i=a.aoColumns.length,n;if(b){c===k&&(c=!1);d=0;for(e=b.length;d<e;d++){g[d]=b[d].slice();g[d].nTr=b[d].nTr;for(f=i-1;0<=f;f--)!a.aoColumns[f].bVisible&&!c&&g[d].splice(f,1);j.push([])}d=0;for(e=g.length;d<e;d++){if(a=g[d].nTr)for(;f=a.firstChild;)a.removeChild(f);f=0;for(b=g[d].length;f<b;f++)if(n=i=1,j[d][f]===k){a.appendChild(g[d][f].cell);
40
+ for(j[d][f]=1;g[d+i]!==k&&g[d][f].cell==g[d+i][f].cell;)j[d+i][f]=1,i++;for(;g[d][f+n]!==k&&g[d][f].cell==g[d][f+n].cell;){for(c=0;c<i;c++)j[d+c][f+n]=1;n++}h(g[d][f].cell).attr("rowspan",i).attr("colspan",n)}}}}function N(a){var b=r(a,"aoPreDrawCallback","preDraw",[a]);if(-1!==h.inArray(!1,b))C(a,!1);else{var b=[],c=0,d=a.asStripeClasses,e=d.length,f=a.oLanguage,g=a.iInitDisplayStart,j="ssp"==y(a),i=a.aiDisplay;a.bDrawing=!0;g!==k&&-1!==g&&(a._iDisplayStart=j?g:g>=a.fnRecordsDisplay()?0:g,a.iInitDisplayStart=
41
+ -1);var g=a._iDisplayStart,n=a.fnDisplayEnd();if(a.bDeferLoading)a.bDeferLoading=!1,a.iDraw++,C(a,!1);else if(j){if(!a.bDestroying&&!kb(a))return}else a.iDraw++;if(0!==i.length){f=j?a.aoData.length:n;for(j=j?0:g;j<f;j++){var l=i[j],q=a.aoData[l];null===q.nTr&&Ga(a,l);l=q.nTr;if(0!==e){var t=d[c%e];q._sRowStripe!=t&&(h(l).removeClass(q._sRowStripe).addClass(t),q._sRowStripe=t)}r(a,"aoRowCallback",null,[l,q._aData,c,j]);b.push(l);c++}}else c=f.sZeroRecords,1==a.iDraw&&"ajax"==y(a)?c=f.sLoadingRecords:
42
+ f.sEmptyTable&&0===a.fnRecordsTotal()&&(c=f.sEmptyTable),b[0]=h("<tr/>",{"class":e?d[0]:""}).append(h("<td />",{valign:"top",colSpan:aa(a),"class":a.oClasses.sRowEmpty}).html(c))[0];r(a,"aoHeaderCallback","header",[h(a.nTHead).children("tr")[0],Ja(a),g,n,i]);r(a,"aoFooterCallback","footer",[h(a.nTFoot).children("tr")[0],Ja(a),g,n,i]);d=h(a.nTBody);d.children().detach();d.append(h(b));r(a,"aoDrawCallback","draw",[a]);a.bSorted=!1;a.bFiltered=!1;a.bDrawing=!1}}function S(a,b){var c=a.oFeatures,d=c.bFilter;
43
+ c.bSort&&lb(a);d?fa(a,a.oPreviousSearch):a.aiDisplay=a.aiDisplayMaster.slice();!0!==b&&(a._iDisplayStart=0);a._drawHold=b;N(a);a._drawHold=!1}function mb(a){var b=a.oClasses,c=h(a.nTable),c=h("<div/>").insertBefore(c),d=a.oFeatures,e=h("<div/>",{id:a.sTableId+"_wrapper","class":b.sWrapper+(a.nTFoot?"":" "+b.sNoFooter)});a.nHolding=c[0];a.nTableWrapper=e[0];a.nTableReinsertBefore=a.nTable.nextSibling;for(var f=a.sDom.split(""),g,j,i,n,l,q,k=0;k<f.length;k++){g=null;j=f[k];if("<"==j){i=h("<div/>")[0];
44
+ n=f[k+1];if("'"==n||'"'==n){l="";for(q=2;f[k+q]!=n;)l+=f[k+q],q++;"H"==l?l=b.sJUIHeader:"F"==l&&(l=b.sJUIFooter);-1!=l.indexOf(".")?(n=l.split("."),i.id=n[0].substr(1,n[0].length-1),i.className=n[1]):"#"==l.charAt(0)?i.id=l.substr(1,l.length-1):i.className=l;k+=q}e.append(i);e=h(i)}else if(">"==j)e=e.parent();else if("l"==j&&d.bPaginate&&d.bLengthChange)g=nb(a);else if("f"==j&&d.bFilter)g=ob(a);else if("r"==j&&d.bProcessing)g=pb(a);else if("t"==j)g=qb(a);else if("i"==j&&d.bInfo)g=rb(a);else if("p"==
45
+ j&&d.bPaginate)g=sb(a);else if(0!==m.ext.feature.length){i=m.ext.feature;q=0;for(n=i.length;q<n;q++)if(j==i[q].cFeature){g=i[q].fnInit(a);break}}g&&(i=a.aanFeatures,i[j]||(i[j]=[]),i[j].push(g),e.append(g))}c.replaceWith(e);a.nHolding=null}function da(a,b){var c=h(b).children("tr"),d,e,f,g,j,i,n,l,q,k;a.splice(0,a.length);f=0;for(i=c.length;f<i;f++)a.push([]);f=0;for(i=c.length;f<i;f++){d=c[f];for(e=d.firstChild;e;){if("TD"==e.nodeName.toUpperCase()||"TH"==e.nodeName.toUpperCase()){l=1*e.getAttribute("colspan");
46
+ q=1*e.getAttribute("rowspan");l=!l||0===l||1===l?1:l;q=!q||0===q||1===q?1:q;g=0;for(j=a[f];j[g];)g++;n=g;k=1===l?!0:!1;for(j=0;j<l;j++)for(g=0;g<q;g++)a[f+g][n+j]={cell:e,unique:k},a[f+g].nTr=d}e=e.nextSibling}}}function ra(a,b,c){var d=[];c||(c=a.aoHeader,b&&(c=[],da(c,b)));for(var b=0,e=c.length;b<e;b++)for(var f=0,g=c[b].length;f<g;f++)if(c[b][f].unique&&(!d[f]||!a.bSortCellsTop))d[f]=c[b][f].cell;return d}function sa(a,b,c){r(a,"aoServerParams","serverParams",[b]);if(b&&h.isArray(b)){var d={},
47
+ e=/(.*?)\[\]$/;h.each(b,function(a,b){var c=b.name.match(e);c?(c=c[0],d[c]||(d[c]=[]),d[c].push(b.value)):d[b.name]=b.value});b=d}var f,g=a.ajax,j=a.oInstance,i=function(b){r(a,null,"xhr",[a,b,a.jqXHR]);c(b)};if(h.isPlainObject(g)&&g.data){f=g.data;var n=h.isFunction(f)?f(b,a):f,b=h.isFunction(f)&&n?n:h.extend(!0,b,n);delete g.data}n={data:b,success:function(b){var c=b.error||b.sError;c&&J(a,0,c);a.json=b;i(b)},dataType:"json",cache:!1,type:a.sServerMethod,error:function(b,c){var d=r(a,null,"xhr",
48
+ [a,null,a.jqXHR]);-1===h.inArray(!0,d)&&("parsererror"==c?J(a,0,"Invalid JSON response",1):4===b.readyState&&J(a,0,"Ajax error",7));C(a,!1)}};a.oAjaxData=b;r(a,null,"preXhr",[a,b]);a.fnServerData?a.fnServerData.call(j,a.sAjaxSource,h.map(b,function(a,b){return{name:b,value:a}}),i,a):a.sAjaxSource||"string"===typeof g?a.jqXHR=h.ajax(h.extend(n,{url:g||a.sAjaxSource})):h.isFunction(g)?a.jqXHR=g.call(j,b,i,a):(a.jqXHR=h.ajax(h.extend(n,g)),g.data=f)}function kb(a){return a.bAjaxDataGet?(a.iDraw++,C(a,
49
+ !0),sa(a,tb(a),function(b){ub(a,b)}),!1):!0}function tb(a){var b=a.aoColumns,c=b.length,d=a.oFeatures,e=a.oPreviousSearch,f=a.aoPreSearchCols,g,j=[],i,n,l,k=V(a);g=a._iDisplayStart;i=!1!==d.bPaginate?a._iDisplayLength:-1;var t=function(a,b){j.push({name:a,value:b})};t("sEcho",a.iDraw);t("iColumns",c);t("sColumns",D(b,"sName").join(","));t("iDisplayStart",g);t("iDisplayLength",i);var pa={draw:a.iDraw,columns:[],order:[],start:g,length:i,search:{value:e.sSearch,regex:e.bRegex}};for(g=0;g<c;g++)n=b[g],
50
+ l=f[g],i="function"==typeof n.mData?"function":n.mData,pa.columns.push({data:i,name:n.sName,searchable:n.bSearchable,orderable:n.bSortable,search:{value:l.sSearch,regex:l.bRegex}}),t("mDataProp_"+g,i),d.bFilter&&(t("sSearch_"+g,l.sSearch),t("bRegex_"+g,l.bRegex),t("bSearchable_"+g,n.bSearchable)),d.bSort&&t("bSortable_"+g,n.bSortable);d.bFilter&&(t("sSearch",e.sSearch),t("bRegex",e.bRegex));d.bSort&&(h.each(k,function(a,b){pa.order.push({column:b.col,dir:b.dir});t("iSortCol_"+a,b.col);t("sSortDir_"+
51
+ a,b.dir)}),t("iSortingCols",k.length));b=m.ext.legacy.ajax;return null===b?a.sAjaxSource?j:pa:b?j:pa}function ub(a,b){var c=ta(a,b),d=b.sEcho!==k?b.sEcho:b.draw,e=b.iTotalRecords!==k?b.iTotalRecords:b.recordsTotal,f=b.iTotalDisplayRecords!==k?b.iTotalDisplayRecords:b.recordsFiltered;if(d){if(1*d<a.iDraw)return;a.iDraw=1*d}na(a);a._iRecordsTotal=parseInt(e,10);a._iRecordsDisplay=parseInt(f,10);d=0;for(e=c.length;d<e;d++)M(a,c[d]);a.aiDisplay=a.aiDisplayMaster.slice();a.bAjaxDataGet=!1;N(a);a._bInitComplete||
52
+ ua(a,b);a.bAjaxDataGet=!0;C(a,!1)}function ta(a,b){var c=h.isPlainObject(a.ajax)&&a.ajax.dataSrc!==k?a.ajax.dataSrc:a.sAjaxDataProp;return"data"===c?b.aaData||b[c]:""!==c?Q(c)(b):b}function ob(a){var b=a.oClasses,c=a.sTableId,d=a.oLanguage,e=a.oPreviousSearch,f=a.aanFeatures,g='<input type="search" class="'+b.sFilterInput+'"/>',j=d.sSearch,j=j.match(/_INPUT_/)?j.replace("_INPUT_",g):j+g,b=h("<div/>",{id:!f.f?c+"_filter":null,"class":b.sFilter}).append(h("<label/>").append(j)),f=function(){var b=!this.value?
53
+ "":this.value;b!=e.sSearch&&(fa(a,{sSearch:b,bRegex:e.bRegex,bSmart:e.bSmart,bCaseInsensitive:e.bCaseInsensitive}),a._iDisplayStart=0,N(a))},g=null!==a.searchDelay?a.searchDelay:"ssp"===y(a)?400:0,i=h("input",b).val(e.sSearch).attr("placeholder",d.sSearchPlaceholder).on("keyup.DT search.DT input.DT paste.DT cut.DT",g?Na(f,g):f).on("keypress.DT",function(a){if(13==a.keyCode)return!1}).attr("aria-controls",c);h(a.nTable).on("search.dt.DT",function(b,c){if(a===c)try{i[0]!==G.activeElement&&i.val(e.sSearch)}catch(d){}});
54
+ return b[0]}function fa(a,b,c){var d=a.oPreviousSearch,e=a.aoPreSearchCols,f=function(a){d.sSearch=a.sSearch;d.bRegex=a.bRegex;d.bSmart=a.bSmart;d.bCaseInsensitive=a.bCaseInsensitive};Fa(a);if("ssp"!=y(a)){vb(a,b.sSearch,c,b.bEscapeRegex!==k?!b.bEscapeRegex:b.bRegex,b.bSmart,b.bCaseInsensitive);f(b);for(b=0;b<e.length;b++)wb(a,e[b].sSearch,b,e[b].bEscapeRegex!==k?!e[b].bEscapeRegex:e[b].bRegex,e[b].bSmart,e[b].bCaseInsensitive);xb(a)}else f(b);a.bFiltered=!0;r(a,null,"search",[a])}function xb(a){for(var b=
55
+ m.ext.search,c=a.aiDisplay,d,e,f=0,g=b.length;f<g;f++){for(var j=[],i=0,n=c.length;i<n;i++)e=c[i],d=a.aoData[e],b[f](a,d._aFilterData,e,d._aData,i)&&j.push(e);c.length=0;h.merge(c,j)}}function wb(a,b,c,d,e,f){if(""!==b){for(var g=[],j=a.aiDisplay,d=Oa(b,d,e,f),e=0;e<j.length;e++)b=a.aoData[j[e]]._aFilterData[c],d.test(b)&&g.push(j[e]);a.aiDisplay=g}}function vb(a,b,c,d,e,f){var d=Oa(b,d,e,f),f=a.oPreviousSearch.sSearch,g=a.aiDisplayMaster,j,e=[];0!==m.ext.search.length&&(c=!0);j=yb(a);if(0>=b.length)a.aiDisplay=
56
+ g.slice();else{if(j||c||f.length>b.length||0!==b.indexOf(f)||a.bSorted)a.aiDisplay=g.slice();b=a.aiDisplay;for(c=0;c<b.length;c++)d.test(a.aoData[b[c]]._sFilterRow)&&e.push(b[c]);a.aiDisplay=e}}function Oa(a,b,c,d){a=b?a:Pa(a);c&&(a="^(?=.*?"+h.map(a.match(/"[^"]+"|[^ ]+/g)||[""],function(a){if('"'===a.charAt(0))var b=a.match(/^"(.*)"$/),a=b?b[1]:a;return a.replace('"',"")}).join(")(?=.*?")+").*$");return RegExp(a,d?"i":"")}function yb(a){var b=a.aoColumns,c,d,e,f,g,j,i,h,l=m.ext.type.search;c=!1;
57
+ d=0;for(f=a.aoData.length;d<f;d++)if(h=a.aoData[d],!h._aFilterData){j=[];e=0;for(g=b.length;e<g;e++)c=b[e],c.bSearchable?(i=B(a,d,e,"filter"),l[c.sType]&&(i=l[c.sType](i)),null===i&&(i=""),"string"!==typeof i&&i.toString&&(i=i.toString())):i="",i.indexOf&&-1!==i.indexOf("&")&&(va.innerHTML=i,i=Wb?va.textContent:va.innerText),i.replace&&(i=i.replace(/[\r\n]/g,"")),j.push(i);h._aFilterData=j;h._sFilterRow=j.join(" ");c=!0}return c}function zb(a){return{search:a.sSearch,smart:a.bSmart,regex:a.bRegex,
58
+ caseInsensitive:a.bCaseInsensitive}}function Ab(a){return{sSearch:a.search,bSmart:a.smart,bRegex:a.regex,bCaseInsensitive:a.caseInsensitive}}function rb(a){var b=a.sTableId,c=a.aanFeatures.i,d=h("<div/>",{"class":a.oClasses.sInfo,id:!c?b+"_info":null});c||(a.aoDrawCallback.push({fn:Bb,sName:"information"}),d.attr("role","status").attr("aria-live","polite"),h(a.nTable).attr("aria-describedby",b+"_info"));return d[0]}function Bb(a){var b=a.aanFeatures.i;if(0!==b.length){var c=a.oLanguage,d=a._iDisplayStart+
59
+ 1,e=a.fnDisplayEnd(),f=a.fnRecordsTotal(),g=a.fnRecordsDisplay(),j=g?c.sInfo:c.sInfoEmpty;g!==f&&(j+=" "+c.sInfoFiltered);j+=c.sInfoPostFix;j=Cb(a,j);c=c.fnInfoCallback;null!==c&&(j=c.call(a.oInstance,a,d,e,f,g,j));h(b).html(j)}}function Cb(a,b){var c=a.fnFormatNumber,d=a._iDisplayStart+1,e=a._iDisplayLength,f=a.fnRecordsDisplay(),g=-1===e;return b.replace(/_START_/g,c.call(a,d)).replace(/_END_/g,c.call(a,a.fnDisplayEnd())).replace(/_MAX_/g,c.call(a,a.fnRecordsTotal())).replace(/_TOTAL_/g,c.call(a,
60
+ f)).replace(/_PAGE_/g,c.call(a,g?1:Math.ceil(d/e))).replace(/_PAGES_/g,c.call(a,g?1:Math.ceil(f/e)))}function ga(a){var b,c,d=a.iInitDisplayStart,e=a.aoColumns,f;c=a.oFeatures;var g=a.bDeferLoading;if(a.bInitialised){mb(a);jb(a);ea(a,a.aoHeader);ea(a,a.aoFooter);C(a,!0);c.bAutoWidth&&Ea(a);b=0;for(c=e.length;b<c;b++)f=e[b],f.sWidth&&(f.nTh.style.width=v(f.sWidth));r(a,null,"preInit",[a]);S(a);e=y(a);if("ssp"!=e||g)"ajax"==e?sa(a,[],function(c){var f=ta(a,c);for(b=0;b<f.length;b++)M(a,f[b]);a.iInitDisplayStart=
61
+ d;S(a);C(a,!1);ua(a,c)},a):(C(a,!1),ua(a))}else setTimeout(function(){ga(a)},200)}function ua(a,b){a._bInitComplete=!0;(b||a.oInit.aaData)&&Y(a);r(a,null,"plugin-init",[a,b]);r(a,"aoInitComplete","init",[a,b])}function Qa(a,b){var c=parseInt(b,10);a._iDisplayLength=c;Ra(a);r(a,null,"length",[a,c])}function nb(a){for(var b=a.oClasses,c=a.sTableId,d=a.aLengthMenu,e=h.isArray(d[0]),f=e?d[0]:d,d=e?d[1]:d,e=h("<select/>",{name:c+"_length","aria-controls":c,"class":b.sLengthSelect}),g=0,j=f.length;g<j;g++)e[0][g]=
62
+ new Option("number"===typeof d[g]?a.fnFormatNumber(d[g]):d[g],f[g]);var i=h("<div><label/></div>").addClass(b.sLength);a.aanFeatures.l||(i[0].id=c+"_length");i.children().append(a.oLanguage.sLengthMenu.replace("_MENU_",e[0].outerHTML));h("select",i).val(a._iDisplayLength).on("change.DT",function(){Qa(a,h(this).val());N(a)});h(a.nTable).on("length.dt.DT",function(b,c,d){a===c&&h("select",i).val(d)});return i[0]}function sb(a){var b=a.sPaginationType,c=m.ext.pager[b],d="function"===typeof c,e=function(a){N(a)},
63
+ b=h("<div/>").addClass(a.oClasses.sPaging+b)[0],f=a.aanFeatures;d||c.fnInit(a,b,e);f.p||(b.id=a.sTableId+"_paginate",a.aoDrawCallback.push({fn:function(a){if(d){var b=a._iDisplayStart,i=a._iDisplayLength,h=a.fnRecordsDisplay(),l=-1===i,b=l?0:Math.ceil(b/i),i=l?1:Math.ceil(h/i),h=c(b,i),k,l=0;for(k=f.p.length;l<k;l++)Ma(a,"pageButton")(a,f.p[l],l,h,b,i)}else c.fnUpdate(a,e)},sName:"pagination"}));return b}function Sa(a,b,c){var d=a._iDisplayStart,e=a._iDisplayLength,f=a.fnRecordsDisplay();0===f||-1===
64
+ e?d=0:"number"===typeof b?(d=b*e,d>f&&(d=0)):"first"==b?d=0:"previous"==b?(d=0<=e?d-e:0,0>d&&(d=0)):"next"==b?d+e<f&&(d+=e):"last"==b?d=Math.floor((f-1)/e)*e:J(a,0,"Unknown paging action: "+b,5);b=a._iDisplayStart!==d;a._iDisplayStart=d;b&&(r(a,null,"page",[a]),c&&N(a));return b}function pb(a){return h("<div/>",{id:!a.aanFeatures.r?a.sTableId+"_processing":null,"class":a.oClasses.sProcessing}).html(a.oLanguage.sProcessing).insertBefore(a.nTable)[0]}function C(a,b){a.oFeatures.bProcessing&&h(a.aanFeatures.r).css("display",
65
+ b?"block":"none");r(a,null,"processing",[a,b])}function qb(a){var b=h(a.nTable);b.attr("role","grid");var c=a.oScroll;if(""===c.sX&&""===c.sY)return a.nTable;var d=c.sX,e=c.sY,f=a.oClasses,g=b.children("caption"),j=g.length?g[0]._captionSide:null,i=h(b[0].cloneNode(!1)),n=h(b[0].cloneNode(!1)),l=b.children("tfoot");l.length||(l=null);i=h("<div/>",{"class":f.sScrollWrapper}).append(h("<div/>",{"class":f.sScrollHead}).css({overflow:"hidden",position:"relative",border:0,width:d?!d?null:v(d):"100%"}).append(h("<div/>",
66
+ {"class":f.sScrollHeadInner}).css({"box-sizing":"content-box",width:c.sXInner||"100%"}).append(i.removeAttr("id").css("margin-left",0).append("top"===j?g:null).append(b.children("thead"))))).append(h("<div/>",{"class":f.sScrollBody}).css({position:"relative",overflow:"auto",width:!d?null:v(d)}).append(b));l&&i.append(h("<div/>",{"class":f.sScrollFoot}).css({overflow:"hidden",border:0,width:d?!d?null:v(d):"100%"}).append(h("<div/>",{"class":f.sScrollFootInner}).append(n.removeAttr("id").css("margin-left",
67
+ 0).append("bottom"===j?g:null).append(b.children("tfoot")))));var b=i.children(),k=b[0],f=b[1],t=l?b[2]:null;if(d)h(f).on("scroll.DT",function(){var a=this.scrollLeft;k.scrollLeft=a;l&&(t.scrollLeft=a)});h(f).css(e&&c.bCollapse?"max-height":"height",e);a.nScrollHead=k;a.nScrollBody=f;a.nScrollFoot=t;a.aoDrawCallback.push({fn:ka,sName:"scrolling"});return i[0]}function ka(a){var b=a.oScroll,c=b.sX,d=b.sXInner,e=b.sY,b=b.iBarWidth,f=h(a.nScrollHead),g=f[0].style,j=f.children("div"),i=j[0].style,n=j.children("table"),
68
+ j=a.nScrollBody,l=h(j),q=j.style,t=h(a.nScrollFoot).children("div"),m=t.children("table"),o=h(a.nTHead),p=h(a.nTable),s=p[0],r=s.style,u=a.nTFoot?h(a.nTFoot):null,x=a.oBrowser,T=x.bScrollOversize,Xb=D(a.aoColumns,"nTh"),O,K,P,w,Ta=[],y=[],z=[],A=[],B,C=function(a){a=a.style;a.paddingTop="0";a.paddingBottom="0";a.borderTopWidth="0";a.borderBottomWidth="0";a.height=0};K=j.scrollHeight>j.clientHeight;if(a.scrollBarVis!==K&&a.scrollBarVis!==k)a.scrollBarVis=K,Y(a);else{a.scrollBarVis=K;p.children("thead, tfoot").remove();
69
+ u&&(P=u.clone().prependTo(p),O=u.find("tr"),P=P.find("tr"));w=o.clone().prependTo(p);o=o.find("tr");K=w.find("tr");w.find("th, td").removeAttr("tabindex");c||(q.width="100%",f[0].style.width="100%");h.each(ra(a,w),function(b,c){B=Z(a,b);c.style.width=a.aoColumns[B].sWidth});u&&H(function(a){a.style.width=""},P);f=p.outerWidth();if(""===c){r.width="100%";if(T&&(p.find("tbody").height()>j.offsetHeight||"scroll"==l.css("overflow-y")))r.width=v(p.outerWidth()-b);f=p.outerWidth()}else""!==d&&(r.width=
70
+ v(d),f=p.outerWidth());H(C,K);H(function(a){z.push(a.innerHTML);Ta.push(v(h(a).css("width")))},K);H(function(a,b){if(h.inArray(a,Xb)!==-1)a.style.width=Ta[b]},o);h(K).height(0);u&&(H(C,P),H(function(a){A.push(a.innerHTML);y.push(v(h(a).css("width")))},P),H(function(a,b){a.style.width=y[b]},O),h(P).height(0));H(function(a,b){a.innerHTML='<div class="dataTables_sizing" style="height:0;overflow:hidden;">'+z[b]+"</div>";a.style.width=Ta[b]},K);u&&H(function(a,b){a.innerHTML='<div class="dataTables_sizing" style="height:0;overflow:hidden;">'+
71
+ A[b]+"</div>";a.style.width=y[b]},P);if(p.outerWidth()<f){O=j.scrollHeight>j.offsetHeight||"scroll"==l.css("overflow-y")?f+b:f;if(T&&(j.scrollHeight>j.offsetHeight||"scroll"==l.css("overflow-y")))r.width=v(O-b);(""===c||""!==d)&&J(a,1,"Possible column misalignment",6)}else O="100%";q.width=v(O);g.width=v(O);u&&(a.nScrollFoot.style.width=v(O));!e&&T&&(q.height=v(s.offsetHeight+b));c=p.outerWidth();n[0].style.width=v(c);i.width=v(c);d=p.height()>j.clientHeight||"scroll"==l.css("overflow-y");e="padding"+
72
+ (x.bScrollbarLeft?"Left":"Right");i[e]=d?b+"px":"0px";u&&(m[0].style.width=v(c),t[0].style.width=v(c),t[0].style[e]=d?b+"px":"0px");p.children("colgroup").insertBefore(p.children("thead"));l.scroll();if((a.bSorted||a.bFiltered)&&!a._drawHold)j.scrollTop=0}}function H(a,b,c){for(var d=0,e=0,f=b.length,g,j;e<f;){g=b[e].firstChild;for(j=c?c[e].firstChild:null;g;)1===g.nodeType&&(c?a(g,j,d):a(g,d),d++),g=g.nextSibling,j=c?j.nextSibling:null;e++}}function Ea(a){var b=a.nTable,c=a.aoColumns,d=a.oScroll,
73
+ e=d.sY,f=d.sX,g=d.sXInner,j=c.length,i=la(a,"bVisible"),n=h("th",a.nTHead),l=b.getAttribute("width"),k=b.parentNode,t=!1,m,o,p=a.oBrowser,d=p.bScrollOversize;(m=b.style.width)&&-1!==m.indexOf("%")&&(l=m);for(m=0;m<i.length;m++)o=c[i[m]],null!==o.sWidth&&(o.sWidth=Db(o.sWidthOrig,k),t=!0);if(d||!t&&!f&&!e&&j==aa(a)&&j==n.length)for(m=0;m<j;m++)i=Z(a,m),null!==i&&(c[i].sWidth=v(n.eq(m).width()));else{j=h(b).clone().css("visibility","hidden").removeAttr("id");j.find("tbody tr").remove();var s=h("<tr/>").appendTo(j.find("tbody"));
74
+ j.find("thead, tfoot").remove();j.append(h(a.nTHead).clone()).append(h(a.nTFoot).clone());j.find("tfoot th, tfoot td").css("width","");n=ra(a,j.find("thead")[0]);for(m=0;m<i.length;m++)o=c[i[m]],n[m].style.width=null!==o.sWidthOrig&&""!==o.sWidthOrig?v(o.sWidthOrig):"",o.sWidthOrig&&f&&h(n[m]).append(h("<div/>").css({width:o.sWidthOrig,margin:0,padding:0,border:0,height:1}));if(a.aoData.length)for(m=0;m<i.length;m++)t=i[m],o=c[t],h(Eb(a,t)).clone(!1).append(o.sContentPadding).appendTo(s);h("[name]",
75
+ j).removeAttr("name");o=h("<div/>").css(f||e?{position:"absolute",top:0,left:0,height:1,right:0,overflow:"hidden"}:{}).append(j).appendTo(k);f&&g?j.width(g):f?(j.css("width","auto"),j.removeAttr("width"),j.width()<k.clientWidth&&l&&j.width(k.clientWidth)):e?j.width(k.clientWidth):l&&j.width(l);for(m=e=0;m<i.length;m++)k=h(n[m]),g=k.outerWidth()-k.width(),k=p.bBounding?Math.ceil(n[m].getBoundingClientRect().width):k.outerWidth(),e+=k,c[i[m]].sWidth=v(k-g);b.style.width=v(e);o.remove()}l&&(b.style.width=
76
+ v(l));if((l||f)&&!a._reszEvt)b=function(){h(E).on("resize.DT-"+a.sInstance,Na(function(){Y(a)}))},d?setTimeout(b,1E3):b(),a._reszEvt=!0}function Db(a,b){if(!a)return 0;var c=h("<div/>").css("width",v(a)).appendTo(b||G.body),d=c[0].offsetWidth;c.remove();return d}function Eb(a,b){var c=Fb(a,b);if(0>c)return null;var d=a.aoData[c];return!d.nTr?h("<td/>").html(B(a,c,b,"display"))[0]:d.anCells[b]}function Fb(a,b){for(var c,d=-1,e=-1,f=0,g=a.aoData.length;f<g;f++)c=B(a,f,b,"display")+"",c=c.replace(Yb,
77
+ ""),c=c.replace(/&nbsp;/g," "),c.length>d&&(d=c.length,e=f);return e}function v(a){return null===a?"0px":"number"==typeof a?0>a?"0px":a+"px":a.match(/\d$/)?a+"px":a}function V(a){var b,c,d=[],e=a.aoColumns,f,g,j,i;b=a.aaSortingFixed;c=h.isPlainObject(b);var n=[];f=function(a){a.length&&!h.isArray(a[0])?n.push(a):h.merge(n,a)};h.isArray(b)&&f(b);c&&b.pre&&f(b.pre);f(a.aaSorting);c&&b.post&&f(b.post);for(a=0;a<n.length;a++){i=n[a][0];f=e[i].aDataSort;b=0;for(c=f.length;b<c;b++)g=f[b],j=e[g].sType||
78
+ "string",n[a]._idx===k&&(n[a]._idx=h.inArray(n[a][1],e[g].asSorting)),d.push({src:i,col:g,dir:n[a][1],index:n[a]._idx,type:j,formatter:m.ext.type.order[j+"-pre"]})}return d}function lb(a){var b,c,d=[],e=m.ext.type.order,f=a.aoData,g=0,j,i=a.aiDisplayMaster,h;Fa(a);h=V(a);b=0;for(c=h.length;b<c;b++)j=h[b],j.formatter&&g++,Gb(a,j.col);if("ssp"!=y(a)&&0!==h.length){b=0;for(c=i.length;b<c;b++)d[i[b]]=b;g===h.length?i.sort(function(a,b){var c,e,g,j,i=h.length,k=f[a]._aSortData,m=f[b]._aSortData;for(g=
79
+ 0;g<i;g++)if(j=h[g],c=k[j.col],e=m[j.col],c=c<e?-1:c>e?1:0,0!==c)return"asc"===j.dir?c:-c;c=d[a];e=d[b];return c<e?-1:c>e?1:0}):i.sort(function(a,b){var c,g,j,i,k=h.length,m=f[a]._aSortData,o=f[b]._aSortData;for(j=0;j<k;j++)if(i=h[j],c=m[i.col],g=o[i.col],i=e[i.type+"-"+i.dir]||e["string-"+i.dir],c=i(c,g),0!==c)return c;c=d[a];g=d[b];return c<g?-1:c>g?1:0})}a.bSorted=!0}function Hb(a){for(var b,c,d=a.aoColumns,e=V(a),a=a.oLanguage.oAria,f=0,g=d.length;f<g;f++){c=d[f];var j=c.asSorting;b=c.sTitle.replace(/<.*?>/g,
80
+ "");var i=c.nTh;i.removeAttribute("aria-sort");c.bSortable&&(0<e.length&&e[0].col==f?(i.setAttribute("aria-sort","asc"==e[0].dir?"ascending":"descending"),c=j[e[0].index+1]||j[0]):c=j[0],b+="asc"===c?a.sSortAscending:a.sSortDescending);i.setAttribute("aria-label",b)}}function Ua(a,b,c,d){var e=a.aaSorting,f=a.aoColumns[b].asSorting,g=function(a,b){var c=a._idx;c===k&&(c=h.inArray(a[1],f));return c+1<f.length?c+1:b?null:0};"number"===typeof e[0]&&(e=a.aaSorting=[e]);c&&a.oFeatures.bSortMulti?(c=h.inArray(b,
81
+ D(e,"0")),-1!==c?(b=g(e[c],!0),null===b&&1===e.length&&(b=0),null===b?e.splice(c,1):(e[c][1]=f[b],e[c]._idx=b)):(e.push([b,f[0],0]),e[e.length-1]._idx=0)):e.length&&e[0][0]==b?(b=g(e[0]),e.length=1,e[0][1]=f[b],e[0]._idx=b):(e.length=0,e.push([b,f[0]]),e[0]._idx=0);S(a);"function"==typeof d&&d(a)}function La(a,b,c,d){var e=a.aoColumns[c];Va(b,{},function(b){!1!==e.bSortable&&(a.oFeatures.bProcessing?(C(a,!0),setTimeout(function(){Ua(a,c,b.shiftKey,d);"ssp"!==y(a)&&C(a,!1)},0)):Ua(a,c,b.shiftKey,d))})}
82
+ function wa(a){var b=a.aLastSort,c=a.oClasses.sSortColumn,d=V(a),e=a.oFeatures,f,g;if(e.bSort&&e.bSortClasses){e=0;for(f=b.length;e<f;e++)g=b[e].src,h(D(a.aoData,"anCells",g)).removeClass(c+(2>e?e+1:3));e=0;for(f=d.length;e<f;e++)g=d[e].src,h(D(a.aoData,"anCells",g)).addClass(c+(2>e?e+1:3))}a.aLastSort=d}function Gb(a,b){var c=a.aoColumns[b],d=m.ext.order[c.sSortDataType],e;d&&(e=d.call(a.oInstance,a,b,$(a,b)));for(var f,g=m.ext.type.order[c.sType+"-pre"],j=0,i=a.aoData.length;j<i;j++)if(c=a.aoData[j],
83
+ c._aSortData||(c._aSortData=[]),!c._aSortData[b]||d)f=d?e[j]:B(a,j,b,"sort"),c._aSortData[b]=g?g(f):f}function xa(a){if(a.oFeatures.bStateSave&&!a.bDestroying){var b={time:+new Date,start:a._iDisplayStart,length:a._iDisplayLength,order:h.extend(!0,[],a.aaSorting),search:zb(a.oPreviousSearch),columns:h.map(a.aoColumns,function(b,d){return{visible:b.bVisible,search:zb(a.aoPreSearchCols[d])}})};r(a,"aoStateSaveParams","stateSaveParams",[a,b]);a.oSavedState=b;a.fnStateSaveCallback.call(a.oInstance,a,
84
+ b)}}function Ib(a,b,c){var d,e,f=a.aoColumns,b=function(b){if(b&&b.time){var g=r(a,"aoStateLoadParams","stateLoadParams",[a,b]);if(-1===h.inArray(!1,g)&&(g=a.iStateDuration,!(0<g&&b.time<+new Date-1E3*g)&&!(b.columns&&f.length!==b.columns.length))){a.oLoadedState=h.extend(!0,{},b);b.start!==k&&(a._iDisplayStart=b.start,a.iInitDisplayStart=b.start);b.length!==k&&(a._iDisplayLength=b.length);b.order!==k&&(a.aaSorting=[],h.each(b.order,function(b,c){a.aaSorting.push(c[0]>=f.length?[0,c[1]]:c)}));b.search!==
85
+ k&&h.extend(a.oPreviousSearch,Ab(b.search));if(b.columns){d=0;for(e=b.columns.length;d<e;d++)g=b.columns[d],g.visible!==k&&(f[d].bVisible=g.visible),g.search!==k&&h.extend(a.aoPreSearchCols[d],Ab(g.search))}r(a,"aoStateLoaded","stateLoaded",[a,b])}}c()};if(a.oFeatures.bStateSave){var g=a.fnStateLoadCallback.call(a.oInstance,a,b);g!==k&&b(g)}else c()}function ya(a){var b=m.settings,a=h.inArray(a,D(b,"nTable"));return-1!==a?b[a]:null}function J(a,b,c,d){c="DataTables warning: "+(a?"table id="+a.sTableId+
86
+ " - ":"")+c;d&&(c+=". For more information about this error, please see http://datatables.net/tn/"+d);if(b)E.console&&console.log&&console.log(c);else if(b=m.ext,b=b.sErrMode||b.errMode,a&&r(a,null,"error",[a,d,c]),"alert"==b)alert(c);else{if("throw"==b)throw Error(c);"function"==typeof b&&b(a,d,c)}}function F(a,b,c,d){h.isArray(c)?h.each(c,function(c,d){h.isArray(d)?F(a,b,d[0],d[1]):F(a,b,d)}):(d===k&&(d=c),b[c]!==k&&(a[d]=b[c]))}function Jb(a,b,c){var d,e;for(e in b)b.hasOwnProperty(e)&&(d=b[e],
87
+ h.isPlainObject(d)?(h.isPlainObject(a[e])||(a[e]={}),h.extend(!0,a[e],d)):a[e]=c&&"data"!==e&&"aaData"!==e&&h.isArray(d)?d.slice():d);return a}function Va(a,b,c){h(a).on("click.DT",b,function(b){a.blur();c(b)}).on("keypress.DT",b,function(a){13===a.which&&(a.preventDefault(),c(a))}).on("selectstart.DT",function(){return!1})}function z(a,b,c,d){c&&a[b].push({fn:c,sName:d})}function r(a,b,c,d){var e=[];b&&(e=h.map(a[b].slice().reverse(),function(b){return b.fn.apply(a.oInstance,d)}));null!==c&&(b=h.Event(c+
88
+ ".dt"),h(a.nTable).trigger(b,d),e.push(b.result));return e}function Ra(a){var b=a._iDisplayStart,c=a.fnDisplayEnd(),d=a._iDisplayLength;b>=c&&(b=c-d);b-=b%d;if(-1===d||0>b)b=0;a._iDisplayStart=b}function Ma(a,b){var c=a.renderer,d=m.ext.renderer[b];return h.isPlainObject(c)&&c[b]?d[c[b]]||d._:"string"===typeof c?d[c]||d._:d._}function y(a){return a.oFeatures.bServerSide?"ssp":a.ajax||a.sAjaxSource?"ajax":"dom"}function ha(a,b){var c=[],c=Kb.numbers_length,d=Math.floor(c/2);b<=c?c=W(0,b):a<=d?(c=W(0,
89
+ c-2),c.push("ellipsis"),c.push(b-1)):(a>=b-1-d?c=W(b-(c-2),b):(c=W(a-d+2,a+d-1),c.push("ellipsis"),c.push(b-1)),c.splice(0,0,"ellipsis"),c.splice(0,0,0));c.DT_el="span";return c}function cb(a){h.each({num:function(b){return za(b,a)},"num-fmt":function(b){return za(b,a,Wa)},"html-num":function(b){return za(b,a,Aa)},"html-num-fmt":function(b){return za(b,a,Aa,Wa)}},function(b,c){x.type.order[b+a+"-pre"]=c;b.match(/^html\-/)&&(x.type.search[b+a]=x.type.search.html)})}function Lb(a){return function(){var b=
90
+ [ya(this[m.ext.iApiIndex])].concat(Array.prototype.slice.call(arguments));return m.ext.internal[a].apply(this,b)}}var m=function(a){this.$=function(a,b){return this.api(!0).$(a,b)};this._=function(a,b){return this.api(!0).rows(a,b).data()};this.api=function(a){return a?new s(ya(this[x.iApiIndex])):new s(this)};this.fnAddData=function(a,b){var c=this.api(!0),d=h.isArray(a)&&(h.isArray(a[0])||h.isPlainObject(a[0]))?c.rows.add(a):c.row.add(a);(b===k||b)&&c.draw();return d.flatten().toArray()};this.fnAdjustColumnSizing=
91
+ function(a){var b=this.api(!0).columns.adjust(),c=b.settings()[0],d=c.oScroll;a===k||a?b.draw(!1):(""!==d.sX||""!==d.sY)&&ka(c)};this.fnClearTable=function(a){var b=this.api(!0).clear();(a===k||a)&&b.draw()};this.fnClose=function(a){this.api(!0).row(a).child.hide()};this.fnDeleteRow=function(a,b,c){var d=this.api(!0),a=d.rows(a),e=a.settings()[0],h=e.aoData[a[0][0]];a.remove();b&&b.call(this,e,h);(c===k||c)&&d.draw();return h};this.fnDestroy=function(a){this.api(!0).destroy(a)};this.fnDraw=function(a){this.api(!0).draw(a)};
92
+ this.fnFilter=function(a,b,c,d,e,h){e=this.api(!0);null===b||b===k?e.search(a,c,d,h):e.column(b).search(a,c,d,h);e.draw()};this.fnGetData=function(a,b){var c=this.api(!0);if(a!==k){var d=a.nodeName?a.nodeName.toLowerCase():"";return b!==k||"td"==d||"th"==d?c.cell(a,b).data():c.row(a).data()||null}return c.data().toArray()};this.fnGetNodes=function(a){var b=this.api(!0);return a!==k?b.row(a).node():b.rows().nodes().flatten().toArray()};this.fnGetPosition=function(a){var b=this.api(!0),c=a.nodeName.toUpperCase();
93
+ return"TR"==c?b.row(a).index():"TD"==c||"TH"==c?(a=b.cell(a).index(),[a.row,a.columnVisible,a.column]):null};this.fnIsOpen=function(a){return this.api(!0).row(a).child.isShown()};this.fnOpen=function(a,b,c){return this.api(!0).row(a).child(b,c).show().child()[0]};this.fnPageChange=function(a,b){var c=this.api(!0).page(a);(b===k||b)&&c.draw(!1)};this.fnSetColumnVis=function(a,b,c){a=this.api(!0).column(a).visible(b);(c===k||c)&&a.columns.adjust().draw()};this.fnSettings=function(){return ya(this[x.iApiIndex])};
94
+ this.fnSort=function(a){this.api(!0).order(a).draw()};this.fnSortListener=function(a,b,c){this.api(!0).order.listener(a,b,c)};this.fnUpdate=function(a,b,c,d,e){var h=this.api(!0);c===k||null===c?h.row(b).data(a):h.cell(b,c).data(a);(e===k||e)&&h.columns.adjust();(d===k||d)&&h.draw();return 0};this.fnVersionCheck=x.fnVersionCheck;var b=this,c=a===k,d=this.length;c&&(a={});this.oApi=this.internal=x.internal;for(var e in m.ext.internal)e&&(this[e]=Lb(e));this.each(function(){var e={},g=1<d?Jb(e,a,!0):
95
+ a,j=0,i,e=this.getAttribute("id"),n=!1,l=m.defaults,q=h(this);if("table"!=this.nodeName.toLowerCase())J(null,0,"Non-table node initialisation ("+this.nodeName+")",2);else{db(l);eb(l.column);I(l,l,!0);I(l.column,l.column,!0);I(l,h.extend(g,q.data()));var t=m.settings,j=0;for(i=t.length;j<i;j++){var o=t[j];if(o.nTable==this||o.nTHead.parentNode==this||o.nTFoot&&o.nTFoot.parentNode==this){var s=g.bRetrieve!==k?g.bRetrieve:l.bRetrieve;if(c||s)return o.oInstance;if(g.bDestroy!==k?g.bDestroy:l.bDestroy){o.oInstance.fnDestroy();
96
+ break}else{J(o,0,"Cannot reinitialise DataTable",3);return}}if(o.sTableId==this.id){t.splice(j,1);break}}if(null===e||""===e)this.id=e="DataTables_Table_"+m.ext._unique++;var p=h.extend(!0,{},m.models.oSettings,{sDestroyWidth:q[0].style.width,sInstance:e,sTableId:e});p.nTable=this;p.oApi=b.internal;p.oInit=g;t.push(p);p.oInstance=1===b.length?b:q.dataTable();db(g);g.oLanguage&&Ca(g.oLanguage);g.aLengthMenu&&!g.iDisplayLength&&(g.iDisplayLength=h.isArray(g.aLengthMenu[0])?g.aLengthMenu[0][0]:g.aLengthMenu[0]);
97
+ g=Jb(h.extend(!0,{},l),g);F(p.oFeatures,g,"bPaginate bLengthChange bFilter bSort bSortMulti bInfo bProcessing bAutoWidth bSortClasses bServerSide bDeferRender".split(" "));F(p,g,["asStripeClasses","ajax","fnServerData","fnFormatNumber","sServerMethod","aaSorting","aaSortingFixed","aLengthMenu","sPaginationType","sAjaxSource","sAjaxDataProp","iStateDuration","sDom","bSortCellsTop","iTabIndex","fnStateLoadCallback","fnStateSaveCallback","renderer","searchDelay","rowId",["iCookieDuration","iStateDuration"],
98
+ ["oSearch","oPreviousSearch"],["aoSearchCols","aoPreSearchCols"],["iDisplayLength","_iDisplayLength"]]);F(p.oScroll,g,[["sScrollX","sX"],["sScrollXInner","sXInner"],["sScrollY","sY"],["bScrollCollapse","bCollapse"]]);F(p.oLanguage,g,"fnInfoCallback");z(p,"aoDrawCallback",g.fnDrawCallback,"user");z(p,"aoServerParams",g.fnServerParams,"user");z(p,"aoStateSaveParams",g.fnStateSaveParams,"user");z(p,"aoStateLoadParams",g.fnStateLoadParams,"user");z(p,"aoStateLoaded",g.fnStateLoaded,"user");z(p,"aoRowCallback",
99
+ g.fnRowCallback,"user");z(p,"aoRowCreatedCallback",g.fnCreatedRow,"user");z(p,"aoHeaderCallback",g.fnHeaderCallback,"user");z(p,"aoFooterCallback",g.fnFooterCallback,"user");z(p,"aoInitComplete",g.fnInitComplete,"user");z(p,"aoPreDrawCallback",g.fnPreDrawCallback,"user");p.rowIdFn=Q(g.rowId);fb(p);var u=p.oClasses;h.extend(u,m.ext.classes,g.oClasses);q.addClass(u.sTable);p.iInitDisplayStart===k&&(p.iInitDisplayStart=g.iDisplayStart,p._iDisplayStart=g.iDisplayStart);null!==g.iDeferLoading&&(p.bDeferLoading=
100
+ !0,e=h.isArray(g.iDeferLoading),p._iRecordsDisplay=e?g.iDeferLoading[0]:g.iDeferLoading,p._iRecordsTotal=e?g.iDeferLoading[1]:g.iDeferLoading);var v=p.oLanguage;h.extend(!0,v,g.oLanguage);v.sUrl&&(h.ajax({dataType:"json",url:v.sUrl,success:function(a){Ca(a);I(l.oLanguage,a);h.extend(true,v,a);ga(p)},error:function(){ga(p)}}),n=!0);null===g.asStripeClasses&&(p.asStripeClasses=[u.sStripeOdd,u.sStripeEven]);var e=p.asStripeClasses,x=q.children("tbody").find("tr").eq(0);-1!==h.inArray(!0,h.map(e,function(a){return x.hasClass(a)}))&&
101
+ (h("tbody tr",this).removeClass(e.join(" ")),p.asDestroyStripes=e.slice());e=[];t=this.getElementsByTagName("thead");0!==t.length&&(da(p.aoHeader,t[0]),e=ra(p));if(null===g.aoColumns){t=[];j=0;for(i=e.length;j<i;j++)t.push(null)}else t=g.aoColumns;j=0;for(i=t.length;j<i;j++)Da(p,e?e[j]:null);hb(p,g.aoColumnDefs,t,function(a,b){ja(p,a,b)});if(x.length){var w=function(a,b){return a.getAttribute("data-"+b)!==null?b:null};h(x[0]).children("th, td").each(function(a,b){var c=p.aoColumns[a];if(c.mData===
102
+ a){var d=w(b,"sort")||w(b,"order"),e=w(b,"filter")||w(b,"search");if(d!==null||e!==null){c.mData={_:a+".display",sort:d!==null?a+".@data-"+d:k,type:d!==null?a+".@data-"+d:k,filter:e!==null?a+".@data-"+e:k};ja(p,a)}}})}var T=p.oFeatures,e=function(){if(g.aaSorting===k){var a=p.aaSorting;j=0;for(i=a.length;j<i;j++)a[j][1]=p.aoColumns[j].asSorting[0]}wa(p);T.bSort&&z(p,"aoDrawCallback",function(){if(p.bSorted){var a=V(p),b={};h.each(a,function(a,c){b[c.src]=c.dir});r(p,null,"order",[p,a,b]);Hb(p)}});
103
+ z(p,"aoDrawCallback",function(){(p.bSorted||y(p)==="ssp"||T.bDeferRender)&&wa(p)},"sc");var a=q.children("caption").each(function(){this._captionSide=h(this).css("caption-side")}),b=q.children("thead");b.length===0&&(b=h("<thead/>").appendTo(q));p.nTHead=b[0];b=q.children("tbody");b.length===0&&(b=h("<tbody/>").appendTo(q));p.nTBody=b[0];b=q.children("tfoot");if(b.length===0&&a.length>0&&(p.oScroll.sX!==""||p.oScroll.sY!==""))b=h("<tfoot/>").appendTo(q);if(b.length===0||b.children().length===0)q.addClass(u.sNoFooter);
104
+ else if(b.length>0){p.nTFoot=b[0];da(p.aoFooter,p.nTFoot)}if(g.aaData)for(j=0;j<g.aaData.length;j++)M(p,g.aaData[j]);else(p.bDeferLoading||y(p)=="dom")&&ma(p,h(p.nTBody).children("tr"));p.aiDisplay=p.aiDisplayMaster.slice();p.bInitialised=true;n===false&&ga(p)};g.bStateSave?(T.bStateSave=!0,z(p,"aoDrawCallback",xa,"state_save"),Ib(p,g,e)):e()}});b=null;return this},x,s,o,u,Xa={},Mb=/[\r\n]/g,Aa=/<.*?>/g,Zb=/^\d{2,4}[\.\/\-]\d{1,2}[\.\/\-]\d{1,2}([T ]{1}\d{1,2}[:\.]\d{2}([\.:]\d{2})?)?$/,$b=RegExp("(\\/|\\.|\\*|\\+|\\?|\\||\\(|\\)|\\[|\\]|\\{|\\}|\\\\|\\$|\\^|\\-)",
105
+ "g"),Wa=/[',$£€¥%\u2009\u202F\u20BD\u20a9\u20BArfk]/gi,L=function(a){return!a||!0===a||"-"===a?!0:!1},Nb=function(a){var b=parseInt(a,10);return!isNaN(b)&&isFinite(a)?b:null},Ob=function(a,b){Xa[b]||(Xa[b]=RegExp(Pa(b),"g"));return"string"===typeof a&&"."!==b?a.replace(/\./g,"").replace(Xa[b],"."):a},Ya=function(a,b,c){var d="string"===typeof a;if(L(a))return!0;b&&d&&(a=Ob(a,b));c&&d&&(a=a.replace(Wa,""));return!isNaN(parseFloat(a))&&isFinite(a)},Pb=function(a,b,c){return L(a)?!0:!(L(a)||"string"===
106
+ typeof a)?null:Ya(a.replace(Aa,""),b,c)?!0:null},D=function(a,b,c){var d=[],e=0,f=a.length;if(c!==k)for(;e<f;e++)a[e]&&a[e][b]&&d.push(a[e][b][c]);else for(;e<f;e++)a[e]&&d.push(a[e][b]);return d},ia=function(a,b,c,d){var e=[],f=0,g=b.length;if(d!==k)for(;f<g;f++)a[b[f]][c]&&e.push(a[b[f]][c][d]);else for(;f<g;f++)e.push(a[b[f]][c]);return e},W=function(a,b){var c=[],d;b===k?(b=0,d=a):(d=b,b=a);for(var e=b;e<d;e++)c.push(e);return c},Qb=function(a){for(var b=[],c=0,d=a.length;c<d;c++)a[c]&&b.push(a[c]);
107
+ return b},qa=function(a){var b;a:{if(!(2>a.length)){b=a.slice().sort();for(var c=b[0],d=1,e=b.length;d<e;d++){if(b[d]===c){b=!1;break a}c=b[d]}}b=!0}if(b)return a.slice();b=[];var e=a.length,f,g=0,d=0;a:for(;d<e;d++){c=a[d];for(f=0;f<g;f++)if(b[f]===c)continue a;b.push(c);g++}return b};m.util={throttle:function(a,b){var c=b!==k?b:200,d,e;return function(){var b=this,g=+new Date,j=arguments;d&&g<d+c?(clearTimeout(e),e=setTimeout(function(){d=k;a.apply(b,j)},c)):(d=g,a.apply(b,j))}},escapeRegex:function(a){return a.replace($b,
108
+ "\\$1")}};var A=function(a,b,c){a[b]!==k&&(a[c]=a[b])},ba=/\[.*?\]$/,U=/\(\)$/,Pa=m.util.escapeRegex,va=h("<div>")[0],Wb=va.textContent!==k,Yb=/<.*?>/g,Na=m.util.throttle,Rb=[],w=Array.prototype,ac=function(a){var b,c,d=m.settings,e=h.map(d,function(a){return a.nTable});if(a){if(a.nTable&&a.oApi)return[a];if(a.nodeName&&"table"===a.nodeName.toLowerCase())return b=h.inArray(a,e),-1!==b?[d[b]]:null;if(a&&"function"===typeof a.settings)return a.settings().toArray();"string"===typeof a?c=h(a):a instanceof
109
+ h&&(c=a)}else return[];if(c)return c.map(function(){b=h.inArray(this,e);return-1!==b?d[b]:null}).toArray()};s=function(a,b){if(!(this instanceof s))return new s(a,b);var c=[],d=function(a){(a=ac(a))&&(c=c.concat(a))};if(h.isArray(a))for(var e=0,f=a.length;e<f;e++)d(a[e]);else d(a);this.context=qa(c);b&&h.merge(this,b);this.selector={rows:null,cols:null,opts:null};s.extend(this,this,Rb)};m.Api=s;h.extend(s.prototype,{any:function(){return 0!==this.count()},concat:w.concat,context:[],count:function(){return this.flatten().length},
110
+ each:function(a){for(var b=0,c=this.length;b<c;b++)a.call(this,this[b],b,this);return this},eq:function(a){var b=this.context;return b.length>a?new s(b[a],this[a]):null},filter:function(a){var b=[];if(w.filter)b=w.filter.call(this,a,this);else for(var c=0,d=this.length;c<d;c++)a.call(this,this[c],c,this)&&b.push(this[c]);return new s(this.context,b)},flatten:function(){var a=[];return new s(this.context,a.concat.apply(a,this.toArray()))},join:w.join,indexOf:w.indexOf||function(a,b){for(var c=b||0,
111
+ d=this.length;c<d;c++)if(this[c]===a)return c;return-1},iterator:function(a,b,c,d){var e=[],f,g,j,h,n,l=this.context,m,o,u=this.selector;"string"===typeof a&&(d=c,c=b,b=a,a=!1);g=0;for(j=l.length;g<j;g++){var r=new s(l[g]);if("table"===b)f=c.call(r,l[g],g),f!==k&&e.push(f);else if("columns"===b||"rows"===b)f=c.call(r,l[g],this[g],g),f!==k&&e.push(f);else if("column"===b||"column-rows"===b||"row"===b||"cell"===b){o=this[g];"column-rows"===b&&(m=Ba(l[g],u.opts));h=0;for(n=o.length;h<n;h++)f=o[h],f=
112
+ "cell"===b?c.call(r,l[g],f.row,f.column,g,h):c.call(r,l[g],f,g,h,m),f!==k&&e.push(f)}}return e.length||d?(a=new s(l,a?e.concat.apply([],e):e),b=a.selector,b.rows=u.rows,b.cols=u.cols,b.opts=u.opts,a):this},lastIndexOf:w.lastIndexOf||function(a,b){return this.indexOf.apply(this.toArray.reverse(),arguments)},length:0,map:function(a){var b=[];if(w.map)b=w.map.call(this,a,this);else for(var c=0,d=this.length;c<d;c++)b.push(a.call(this,this[c],c));return new s(this.context,b)},pluck:function(a){return this.map(function(b){return b[a]})},
113
+ pop:w.pop,push:w.push,reduce:w.reduce||function(a,b){return gb(this,a,b,0,this.length,1)},reduceRight:w.reduceRight||function(a,b){return gb(this,a,b,this.length-1,-1,-1)},reverse:w.reverse,selector:null,shift:w.shift,slice:function(){return new s(this.context,this)},sort:w.sort,splice:w.splice,toArray:function(){return w.slice.call(this)},to$:function(){return h(this)},toJQuery:function(){return h(this)},unique:function(){return new s(this.context,qa(this))},unshift:w.unshift});s.extend=function(a,
114
+ b,c){if(c.length&&b&&(b instanceof s||b.__dt_wrapper)){var d,e,f,g=function(a,b,c){return function(){var d=b.apply(a,arguments);s.extend(d,d,c.methodExt);return d}};d=0;for(e=c.length;d<e;d++)f=c[d],b[f.name]="function"===typeof f.val?g(a,f.val,f):h.isPlainObject(f.val)?{}:f.val,b[f.name].__dt_wrapper=!0,s.extend(a,b[f.name],f.propExt)}};s.register=o=function(a,b){if(h.isArray(a))for(var c=0,d=a.length;c<d;c++)s.register(a[c],b);else for(var e=a.split("."),f=Rb,g,j,c=0,d=e.length;c<d;c++){g=(j=-1!==
115
+ e[c].indexOf("()"))?e[c].replace("()",""):e[c];var i;a:{i=0;for(var n=f.length;i<n;i++)if(f[i].name===g){i=f[i];break a}i=null}i||(i={name:g,val:{},methodExt:[],propExt:[]},f.push(i));c===d-1?i.val=b:f=j?i.methodExt:i.propExt}};s.registerPlural=u=function(a,b,c){s.register(a,c);s.register(b,function(){var a=c.apply(this,arguments);return a===this?this:a instanceof s?a.length?h.isArray(a[0])?new s(a.context,a[0]):a[0]:k:a})};o("tables()",function(a){var b;if(a){b=s;var c=this.context;if("number"===
116
+ typeof a)a=[c[a]];else var d=h.map(c,function(a){return a.nTable}),a=h(d).filter(a).map(function(){var a=h.inArray(this,d);return c[a]}).toArray();b=new b(a)}else b=this;return b});o("table()",function(a){var a=this.tables(a),b=a.context;return b.length?new s(b[0]):a});u("tables().nodes()","table().node()",function(){return this.iterator("table",function(a){return a.nTable},1)});u("tables().body()","table().body()",function(){return this.iterator("table",function(a){return a.nTBody},1)});u("tables().header()",
117
+ "table().header()",function(){return this.iterator("table",function(a){return a.nTHead},1)});u("tables().footer()","table().footer()",function(){return this.iterator("table",function(a){return a.nTFoot},1)});u("tables().containers()","table().container()",function(){return this.iterator("table",function(a){return a.nTableWrapper},1)});o("draw()",function(a){return this.iterator("table",function(b){"page"===a?N(b):("string"===typeof a&&(a="full-hold"===a?!1:!0),S(b,!1===a))})});o("page()",function(a){return a===
118
+ k?this.page.info().page:this.iterator("table",function(b){Sa(b,a)})});o("page.info()",function(){if(0===this.context.length)return k;var a=this.context[0],b=a._iDisplayStart,c=a.oFeatures.bPaginate?a._iDisplayLength:-1,d=a.fnRecordsDisplay(),e=-1===c;return{page:e?0:Math.floor(b/c),pages:e?1:Math.ceil(d/c),start:b,end:a.fnDisplayEnd(),length:c,recordsTotal:a.fnRecordsTotal(),recordsDisplay:d,serverSide:"ssp"===y(a)}});o("page.len()",function(a){return a===k?0!==this.context.length?this.context[0]._iDisplayLength:
119
+ k:this.iterator("table",function(b){Qa(b,a)})});var Sb=function(a,b,c){if(c){var d=new s(a);d.one("draw",function(){c(d.ajax.json())})}if("ssp"==y(a))S(a,b);else{C(a,!0);var e=a.jqXHR;e&&4!==e.readyState&&e.abort();sa(a,[],function(c){na(a);for(var c=ta(a,c),d=0,e=c.length;d<e;d++)M(a,c[d]);S(a,b);C(a,!1)})}};o("ajax.json()",function(){var a=this.context;if(0<a.length)return a[0].json});o("ajax.params()",function(){var a=this.context;if(0<a.length)return a[0].oAjaxData});o("ajax.reload()",function(a,
120
+ b){return this.iterator("table",function(c){Sb(c,!1===b,a)})});o("ajax.url()",function(a){var b=this.context;if(a===k){if(0===b.length)return k;b=b[0];return b.ajax?h.isPlainObject(b.ajax)?b.ajax.url:b.ajax:b.sAjaxSource}return this.iterator("table",function(b){h.isPlainObject(b.ajax)?b.ajax.url=a:b.ajax=a})});o("ajax.url().load()",function(a,b){return this.iterator("table",function(c){Sb(c,!1===b,a)})});var Za=function(a,b,c,d,e){var f=[],g,j,i,n,l,m;i=typeof b;if(!b||"string"===i||"function"===
121
+ i||b.length===k)b=[b];i=0;for(n=b.length;i<n;i++){j=b[i]&&b[i].split&&!b[i].match(/[\[\(:]/)?b[i].split(","):[b[i]];l=0;for(m=j.length;l<m;l++)(g=c("string"===typeof j[l]?h.trim(j[l]):j[l]))&&g.length&&(f=f.concat(g))}a=x.selector[a];if(a.length){i=0;for(n=a.length;i<n;i++)f=a[i](d,e,f)}return qa(f)},$a=function(a){a||(a={});a.filter&&a.search===k&&(a.search=a.filter);return h.extend({search:"none",order:"current",page:"all"},a)},ab=function(a){for(var b=0,c=a.length;b<c;b++)if(0<a[b].length)return a[0]=
122
+ a[b],a[0].length=1,a.length=1,a.context=[a.context[b]],a;a.length=0;return a},Ba=function(a,b){var c,d,e,f=[],g=a.aiDisplay;c=a.aiDisplayMaster;var j=b.search;d=b.order;e=b.page;if("ssp"==y(a))return"removed"===j?[]:W(0,c.length);if("current"==e){c=a._iDisplayStart;for(d=a.fnDisplayEnd();c<d;c++)f.push(g[c])}else if("current"==d||"applied"==d)f="none"==j?c.slice():"applied"==j?g.slice():h.map(c,function(a){return-1===h.inArray(a,g)?a:null});else if("index"==d||"original"==d){c=0;for(d=a.aoData.length;c<
123
+ d;c++)"none"==j?f.push(c):(e=h.inArray(c,g),(-1===e&&"removed"==j||0<=e&&"applied"==j)&&f.push(c))}return f};o("rows()",function(a,b){a===k?a="":h.isPlainObject(a)&&(b=a,a="");var b=$a(b),c=this.iterator("table",function(c){var e=b,f;return Za("row",a,function(a){var b=Nb(a);if(b!==null&&!e)return[b];f||(f=Ba(c,e));if(b!==null&&h.inArray(b,f)!==-1)return[b];if(a===null||a===k||a==="")return f;if(typeof a==="function")return h.map(f,function(b){var e=c.aoData[b];return a(b,e._aData,e.nTr)?b:null});
124
+ b=Qb(ia(c.aoData,f,"nTr"));if(a.nodeName){if(a._DT_RowIndex!==k)return[a._DT_RowIndex];if(a._DT_CellIndex)return[a._DT_CellIndex.row];b=h(a).closest("*[data-dt-row]");return b.length?[b.data("dt-row")]:[]}if(typeof a==="string"&&a.charAt(0)==="#"){var i=c.aIds[a.replace(/^#/,"")];if(i!==k)return[i.idx]}return h(b).filter(a).map(function(){return this._DT_RowIndex}).toArray()},c,e)},1);c.selector.rows=a;c.selector.opts=b;return c});o("rows().nodes()",function(){return this.iterator("row",function(a,
125
+ b){return a.aoData[b].nTr||k},1)});o("rows().data()",function(){return this.iterator(!0,"rows",function(a,b){return ia(a.aoData,b,"_aData")},1)});u("rows().cache()","row().cache()",function(a){return this.iterator("row",function(b,c){var d=b.aoData[c];return"search"===a?d._aFilterData:d._aSortData},1)});u("rows().invalidate()","row().invalidate()",function(a){return this.iterator("row",function(b,c){ca(b,c,a)})});u("rows().indexes()","row().index()",function(){return this.iterator("row",function(a,
126
+ b){return b},1)});u("rows().ids()","row().id()",function(a){for(var b=[],c=this.context,d=0,e=c.length;d<e;d++)for(var f=0,g=this[d].length;f<g;f++){var h=c[d].rowIdFn(c[d].aoData[this[d][f]]._aData);b.push((!0===a?"#":"")+h)}return new s(c,b)});u("rows().remove()","row().remove()",function(){var a=this;this.iterator("row",function(b,c,d){var e=b.aoData,f=e[c],g,h,i,n,l;e.splice(c,1);g=0;for(h=e.length;g<h;g++)if(i=e[g],l=i.anCells,null!==i.nTr&&(i.nTr._DT_RowIndex=g),null!==l){i=0;for(n=l.length;i<
127
+ n;i++)l[i]._DT_CellIndex.row=g}oa(b.aiDisplayMaster,c);oa(b.aiDisplay,c);oa(a[d],c,!1);0<b._iRecordsDisplay&&b._iRecordsDisplay--;Ra(b);c=b.rowIdFn(f._aData);c!==k&&delete b.aIds[c]});this.iterator("table",function(a){for(var c=0,d=a.aoData.length;c<d;c++)a.aoData[c].idx=c});return this});o("rows.add()",function(a){var b=this.iterator("table",function(b){var c,f,g,h=[];f=0;for(g=a.length;f<g;f++)c=a[f],c.nodeName&&"TR"===c.nodeName.toUpperCase()?h.push(ma(b,c)[0]):h.push(M(b,c));return h},1),c=this.rows(-1);
128
+ c.pop();h.merge(c,b);return c});o("row()",function(a,b){return ab(this.rows(a,b))});o("row().data()",function(a){var b=this.context;if(a===k)return b.length&&this.length?b[0].aoData[this[0]]._aData:k;b[0].aoData[this[0]]._aData=a;ca(b[0],this[0],"data");return this});o("row().node()",function(){var a=this.context;return a.length&&this.length?a[0].aoData[this[0]].nTr||null:null});o("row.add()",function(a){a instanceof h&&a.length&&(a=a[0]);var b=this.iterator("table",function(b){return a.nodeName&&
129
+ "TR"===a.nodeName.toUpperCase()?ma(b,a)[0]:M(b,a)});return this.row(b[0])});var bb=function(a,b){var c=a.context;if(c.length&&(c=c[0].aoData[b!==k?b:a[0]])&&c._details)c._details.remove(),c._detailsShow=k,c._details=k},Tb=function(a,b){var c=a.context;if(c.length&&a.length){var d=c[0].aoData[a[0]];if(d._details){(d._detailsShow=b)?d._details.insertAfter(d.nTr):d._details.detach();var e=c[0],f=new s(e),g=e.aoData;f.off("draw.dt.DT_details column-visibility.dt.DT_details destroy.dt.DT_details");0<D(g,
130
+ "_details").length&&(f.on("draw.dt.DT_details",function(a,b){e===b&&f.rows({page:"current"}).eq(0).each(function(a){a=g[a];a._detailsShow&&a._details.insertAfter(a.nTr)})}),f.on("column-visibility.dt.DT_details",function(a,b){if(e===b)for(var c,d=aa(b),f=0,h=g.length;f<h;f++)c=g[f],c._details&&c._details.children("td[colspan]").attr("colspan",d)}),f.on("destroy.dt.DT_details",function(a,b){if(e===b)for(var c=0,d=g.length;c<d;c++)g[c]._details&&bb(f,c)}))}}};o("row().child()",function(a,b){var c=this.context;
131
+ if(a===k)return c.length&&this.length?c[0].aoData[this[0]]._details:k;if(!0===a)this.child.show();else if(!1===a)bb(this);else if(c.length&&this.length){var d=c[0],c=c[0].aoData[this[0]],e=[],f=function(a,b){if(h.isArray(a)||a instanceof h)for(var c=0,k=a.length;c<k;c++)f(a[c],b);else a.nodeName&&"tr"===a.nodeName.toLowerCase()?e.push(a):(c=h("<tr><td/></tr>").addClass(b),h("td",c).addClass(b).html(a)[0].colSpan=aa(d),e.push(c[0]))};f(a,b);c._details&&c._details.detach();c._details=h(e);c._detailsShow&&
132
+ c._details.insertAfter(c.nTr)}return this});o(["row().child.show()","row().child().show()"],function(){Tb(this,!0);return this});o(["row().child.hide()","row().child().hide()"],function(){Tb(this,!1);return this});o(["row().child.remove()","row().child().remove()"],function(){bb(this);return this});o("row().child.isShown()",function(){var a=this.context;return a.length&&this.length?a[0].aoData[this[0]]._detailsShow||!1:!1});var bc=/^([^:]+):(name|visIdx|visible)$/,Ub=function(a,b,c,d,e){for(var c=
133
+ [],d=0,f=e.length;d<f;d++)c.push(B(a,e[d],b));return c};o("columns()",function(a,b){a===k?a="":h.isPlainObject(a)&&(b=a,a="");var b=$a(b),c=this.iterator("table",function(c){var e=a,f=b,g=c.aoColumns,j=D(g,"sName"),i=D(g,"nTh");return Za("column",e,function(a){var b=Nb(a);if(a==="")return W(g.length);if(b!==null)return[b>=0?b:g.length+b];if(typeof a==="function"){var e=Ba(c,f);return h.map(g,function(b,f){return a(f,Ub(c,f,0,0,e),i[f])?f:null})}var k=typeof a==="string"?a.match(bc):"";if(k)switch(k[2]){case "visIdx":case "visible":b=
134
+ parseInt(k[1],10);if(b<0){var m=h.map(g,function(a,b){return a.bVisible?b:null});return[m[m.length+b]]}return[Z(c,b)];case "name":return h.map(j,function(a,b){return a===k[1]?b:null});default:return[]}if(a.nodeName&&a._DT_CellIndex)return[a._DT_CellIndex.column];b=h(i).filter(a).map(function(){return h.inArray(this,i)}).toArray();if(b.length||!a.nodeName)return b;b=h(a).closest("*[data-dt-column]");return b.length?[b.data("dt-column")]:[]},c,f)},1);c.selector.cols=a;c.selector.opts=b;return c});u("columns().header()",
135
+ "column().header()",function(){return this.iterator("column",function(a,b){return a.aoColumns[b].nTh},1)});u("columns().footer()","column().footer()",function(){return this.iterator("column",function(a,b){return a.aoColumns[b].nTf},1)});u("columns().data()","column().data()",function(){return this.iterator("column-rows",Ub,1)});u("columns().dataSrc()","column().dataSrc()",function(){return this.iterator("column",function(a,b){return a.aoColumns[b].mData},1)});u("columns().cache()","column().cache()",
136
+ function(a){return this.iterator("column-rows",function(b,c,d,e,f){return ia(b.aoData,f,"search"===a?"_aFilterData":"_aSortData",c)},1)});u("columns().nodes()","column().nodes()",function(){return this.iterator("column-rows",function(a,b,c,d,e){return ia(a.aoData,e,"anCells",b)},1)});u("columns().visible()","column().visible()",function(a,b){var c=this.iterator("column",function(b,c){if(a===k)return b.aoColumns[c].bVisible;var f=b.aoColumns,g=f[c],j=b.aoData,i,n,l;if(a!==k&&g.bVisible!==a){if(a){var m=
137
+ h.inArray(!0,D(f,"bVisible"),c+1);i=0;for(n=j.length;i<n;i++)l=j[i].nTr,f=j[i].anCells,l&&l.insertBefore(f[c],f[m]||null)}else h(D(b.aoData,"anCells",c)).detach();g.bVisible=a;ea(b,b.aoHeader);ea(b,b.aoFooter);xa(b)}});a!==k&&(this.iterator("column",function(c,e){r(c,null,"column-visibility",[c,e,a,b])}),(b===k||b)&&this.columns.adjust());return c});u("columns().indexes()","column().index()",function(a){return this.iterator("column",function(b,c){return"visible"===a?$(b,c):c},1)});o("columns.adjust()",
138
+ function(){return this.iterator("table",function(a){Y(a)},1)});o("column.index()",function(a,b){if(0!==this.context.length){var c=this.context[0];if("fromVisible"===a||"toData"===a)return Z(c,b);if("fromData"===a||"toVisible"===a)return $(c,b)}});o("column()",function(a,b){return ab(this.columns(a,b))});o("cells()",function(a,b,c){h.isPlainObject(a)&&(a.row===k?(c=a,a=null):(c=b,b=null));h.isPlainObject(b)&&(c=b,b=null);if(null===b||b===k)return this.iterator("table",function(b){var d=a,e=$a(c),f=
139
+ b.aoData,g=Ba(b,e),j=Qb(ia(f,g,"anCells")),i=h([].concat.apply([],j)),l,n=b.aoColumns.length,m,o,u,s,r,v;return Za("cell",d,function(a){var c=typeof a==="function";if(a===null||a===k||c){m=[];o=0;for(u=g.length;o<u;o++){l=g[o];for(s=0;s<n;s++){r={row:l,column:s};if(c){v=f[l];a(r,B(b,l,s),v.anCells?v.anCells[s]:null)&&m.push(r)}else m.push(r)}}return m}if(h.isPlainObject(a))return[a];c=i.filter(a).map(function(a,b){return{row:b._DT_CellIndex.row,column:b._DT_CellIndex.column}}).toArray();if(c.length||
140
+ !a.nodeName)return c;v=h(a).closest("*[data-dt-row]");return v.length?[{row:v.data("dt-row"),column:v.data("dt-column")}]:[]},b,e)});var d=this.columns(b,c),e=this.rows(a,c),f,g,j,i,n,l=this.iterator("table",function(a,b){f=[];g=0;for(j=e[b].length;g<j;g++){i=0;for(n=d[b].length;i<n;i++)f.push({row:e[b][g],column:d[b][i]})}return f},1);h.extend(l.selector,{cols:b,rows:a,opts:c});return l});u("cells().nodes()","cell().node()",function(){return this.iterator("cell",function(a,b,c){return(a=a.aoData[b])&&
141
+ a.anCells?a.anCells[c]:k},1)});o("cells().data()",function(){return this.iterator("cell",function(a,b,c){return B(a,b,c)},1)});u("cells().cache()","cell().cache()",function(a){a="search"===a?"_aFilterData":"_aSortData";return this.iterator("cell",function(b,c,d){return b.aoData[c][a][d]},1)});u("cells().render()","cell().render()",function(a){return this.iterator("cell",function(b,c,d){return B(b,c,d,a)},1)});u("cells().indexes()","cell().index()",function(){return this.iterator("cell",function(a,
142
+ b,c){return{row:b,column:c,columnVisible:$(a,c)}},1)});u("cells().invalidate()","cell().invalidate()",function(a){return this.iterator("cell",function(b,c,d){ca(b,c,a,d)})});o("cell()",function(a,b,c){return ab(this.cells(a,b,c))});o("cell().data()",function(a){var b=this.context,c=this[0];if(a===k)return b.length&&c.length?B(b[0],c[0].row,c[0].column):k;ib(b[0],c[0].row,c[0].column,a);ca(b[0],c[0].row,"data",c[0].column);return this});o("order()",function(a,b){var c=this.context;if(a===k)return 0!==
143
+ c.length?c[0].aaSorting:k;"number"===typeof a?a=[[a,b]]:a.length&&!h.isArray(a[0])&&(a=Array.prototype.slice.call(arguments));return this.iterator("table",function(b){b.aaSorting=a.slice()})});o("order.listener()",function(a,b,c){return this.iterator("table",function(d){La(d,a,b,c)})});o("order.fixed()",function(a){if(!a){var b=this.context,b=b.length?b[0].aaSortingFixed:k;return h.isArray(b)?{pre:b}:b}return this.iterator("table",function(b){b.aaSortingFixed=h.extend(!0,{},a)})});o(["columns().order()",
144
+ "column().order()"],function(a){var b=this;return this.iterator("table",function(c,d){var e=[];h.each(b[d],function(b,c){e.push([c,a])});c.aaSorting=e})});o("search()",function(a,b,c,d){var e=this.context;return a===k?0!==e.length?e[0].oPreviousSearch.sSearch:k:this.iterator("table",function(e){e.oFeatures.bFilter&&fa(e,h.extend({},e.oPreviousSearch,{sSearch:a+"",bRegex:null===b?!1:b,bSmart:null===c?!0:c,bCaseInsensitive:null===d?!0:d}),1)})});u("columns().search()","column().search()",function(a,
145
+ b,c,d){return this.iterator("column",function(e,f){var g=e.aoPreSearchCols;if(a===k)return g[f].sSearch;e.oFeatures.bFilter&&(h.extend(g[f],{sSearch:a+"",bRegex:null===b?!1:b,bSmart:null===c?!0:c,bCaseInsensitive:null===d?!0:d}),fa(e,e.oPreviousSearch,1))})});o("state()",function(){return this.context.length?this.context[0].oSavedState:null});o("state.clear()",function(){return this.iterator("table",function(a){a.fnStateSaveCallback.call(a.oInstance,a,{})})});o("state.loaded()",function(){return this.context.length?
146
+ this.context[0].oLoadedState:null});o("state.save()",function(){return this.iterator("table",function(a){xa(a)})});m.versionCheck=m.fnVersionCheck=function(a){for(var b=m.version.split("."),a=a.split("."),c,d,e=0,f=a.length;e<f;e++)if(c=parseInt(b[e],10)||0,d=parseInt(a[e],10)||0,c!==d)return c>d;return!0};m.isDataTable=m.fnIsDataTable=function(a){var b=h(a).get(0),c=!1;if(a instanceof m.Api)return!0;h.each(m.settings,function(a,e){var f=e.nScrollHead?h("table",e.nScrollHead)[0]:null,g=e.nScrollFoot?
147
+ h("table",e.nScrollFoot)[0]:null;if(e.nTable===b||f===b||g===b)c=!0});return c};m.tables=m.fnTables=function(a){var b=!1;h.isPlainObject(a)&&(b=a.api,a=a.visible);var c=h.map(m.settings,function(b){if(!a||a&&h(b.nTable).is(":visible"))return b.nTable});return b?new s(c):c};m.camelToHungarian=I;o("$()",function(a,b){var c=this.rows(b).nodes(),c=h(c);return h([].concat(c.filter(a).toArray(),c.find(a).toArray()))});h.each(["on","one","off"],function(a,b){o(b+"()",function(){var a=Array.prototype.slice.call(arguments);
148
+ a[0]=h.map(a[0].split(/\s/),function(a){return!a.match(/\.dt\b/)?a+".dt":a}).join(" ");var d=h(this.tables().nodes());d[b].apply(d,a);return this})});o("clear()",function(){return this.iterator("table",function(a){na(a)})});o("settings()",function(){return new s(this.context,this.context)});o("init()",function(){var a=this.context;return a.length?a[0].oInit:null});o("data()",function(){return this.iterator("table",function(a){return D(a.aoData,"_aData")}).flatten()});o("destroy()",function(a){a=a||
149
+ !1;return this.iterator("table",function(b){var c=b.nTableWrapper.parentNode,d=b.oClasses,e=b.nTable,f=b.nTBody,g=b.nTHead,j=b.nTFoot,i=h(e),f=h(f),k=h(b.nTableWrapper),l=h.map(b.aoData,function(a){return a.nTr}),o;b.bDestroying=!0;r(b,"aoDestroyCallback","destroy",[b]);a||(new s(b)).columns().visible(!0);k.off(".DT").find(":not(tbody *)").off(".DT");h(E).off(".DT-"+b.sInstance);e!=g.parentNode&&(i.children("thead").detach(),i.append(g));j&&e!=j.parentNode&&(i.children("tfoot").detach(),i.append(j));
150
+ b.aaSorting=[];b.aaSortingFixed=[];wa(b);h(l).removeClass(b.asStripeClasses.join(" "));h("th, td",g).removeClass(d.sSortable+" "+d.sSortableAsc+" "+d.sSortableDesc+" "+d.sSortableNone);f.children().detach();f.append(l);g=a?"remove":"detach";i[g]();k[g]();!a&&c&&(c.insertBefore(e,b.nTableReinsertBefore),i.css("width",b.sDestroyWidth).removeClass(d.sTable),(o=b.asDestroyStripes.length)&&f.children().each(function(a){h(this).addClass(b.asDestroyStripes[a%o])}));c=h.inArray(b,m.settings);-1!==c&&m.settings.splice(c,
151
+ 1)})});h.each(["column","row","cell"],function(a,b){o(b+"s().every()",function(a){var d=this.selector.opts,e=this;return this.iterator(b,function(f,g,h,i,n){a.call(e[b](g,"cell"===b?h:d,"cell"===b?d:k),g,h,i,n)})})});o("i18n()",function(a,b,c){var d=this.context[0],a=Q(a)(d.oLanguage);a===k&&(a=b);c!==k&&h.isPlainObject(a)&&(a=a[c]!==k?a[c]:a._);return a.replace("%d",c)});m.version="1.10.16";m.settings=[];m.models={};m.models.oSearch={bCaseInsensitive:!0,sSearch:"",bRegex:!1,bSmart:!0};m.models.oRow=
152
+ {nTr:null,anCells:null,_aData:[],_aSortData:null,_aFilterData:null,_sFilterRow:null,_sRowStripe:"",src:null,idx:-1};m.models.oColumn={idx:null,aDataSort:null,asSorting:null,bSearchable:null,bSortable:null,bVisible:null,_sManualType:null,_bAttrSrc:!1,fnCreatedCell:null,fnGetData:null,fnSetData:null,mData:null,mRender:null,nTh:null,nTf:null,sClass:null,sContentPadding:null,sDefaultContent:null,sName:null,sSortDataType:"std",sSortingClass:null,sSortingClassJUI:null,sTitle:null,sType:null,sWidth:null,
153
+ sWidthOrig:null};m.defaults={aaData:null,aaSorting:[[0,"asc"]],aaSortingFixed:[],ajax:null,aLengthMenu:[10,25,50,100],aoColumns:null,aoColumnDefs:null,aoSearchCols:[],asStripeClasses:null,bAutoWidth:!0,bDeferRender:!1,bDestroy:!1,bFilter:!0,bInfo:!0,bLengthChange:!0,bPaginate:!0,bProcessing:!1,bRetrieve:!1,bScrollCollapse:!1,bServerSide:!1,bSort:!0,bSortMulti:!0,bSortCellsTop:!1,bSortClasses:!0,bStateSave:!1,fnCreatedRow:null,fnDrawCallback:null,fnFooterCallback:null,fnFormatNumber:function(a){return a.toString().replace(/\B(?=(\d{3})+(?!\d))/g,
154
+ this.oLanguage.sThousands)},fnHeaderCallback:null,fnInfoCallback:null,fnInitComplete:null,fnPreDrawCallback:null,fnRowCallback:null,fnServerData:null,fnServerParams:null,fnStateLoadCallback:function(a){try{return JSON.parse((-1===a.iStateDuration?sessionStorage:localStorage).getItem("DataTables_"+a.sInstance+"_"+location.pathname))}catch(b){}},fnStateLoadParams:null,fnStateLoaded:null,fnStateSaveCallback:function(a,b){try{(-1===a.iStateDuration?sessionStorage:localStorage).setItem("DataTables_"+a.sInstance+
155
+ "_"+location.pathname,JSON.stringify(b))}catch(c){}},fnStateSaveParams:null,iStateDuration:7200,iDeferLoading:null,iDisplayLength:10,iDisplayStart:0,iTabIndex:0,oClasses:{},oLanguage:{oAria:{sSortAscending:": activate to sort column ascending",sSortDescending:": activate to sort column descending"},oPaginate:{sFirst:"First",sLast:"Last",sNext:"Next",sPrevious:"Previous"},sEmptyTable:"No data available in table",sInfo:"Showing _START_ to _END_ of _TOTAL_ entries",sInfoEmpty:"Showing 0 to 0 of 0 entries",
156
+ sInfoFiltered:"(filtered from _MAX_ total entries)",sInfoPostFix:"",sDecimal:"",sThousands:",",sLengthMenu:"Show _MENU_ entries",sLoadingRecords:"Loading...",sProcessing:"Processing...",sSearch:"Search:",sSearchPlaceholder:"",sUrl:"",sZeroRecords:"No matching records found"},oSearch:h.extend({},m.models.oSearch),sAjaxDataProp:"data",sAjaxSource:null,sDom:"lfrtip",searchDelay:null,sPaginationType:"simple_numbers",sScrollX:"",sScrollXInner:"",sScrollY:"",sServerMethod:"GET",renderer:null,rowId:"DT_RowId"};
157
+ X(m.defaults);m.defaults.column={aDataSort:null,iDataSort:-1,asSorting:["asc","desc"],bSearchable:!0,bSortable:!0,bVisible:!0,fnCreatedCell:null,mData:null,mRender:null,sCellType:"td",sClass:"",sContentPadding:"",sDefaultContent:null,sName:"",sSortDataType:"std",sTitle:null,sType:null,sWidth:null};X(m.defaults.column);m.models.oSettings={oFeatures:{bAutoWidth:null,bDeferRender:null,bFilter:null,bInfo:null,bLengthChange:null,bPaginate:null,bProcessing:null,bServerSide:null,bSort:null,bSortMulti:null,
158
+ bSortClasses:null,bStateSave:null},oScroll:{bCollapse:null,iBarWidth:0,sX:null,sXInner:null,sY:null},oLanguage:{fnInfoCallback:null},oBrowser:{bScrollOversize:!1,bScrollbarLeft:!1,bBounding:!1,barWidth:0},ajax:null,aanFeatures:[],aoData:[],aiDisplay:[],aiDisplayMaster:[],aIds:{},aoColumns:[],aoHeader:[],aoFooter:[],oPreviousSearch:{},aoPreSearchCols:[],aaSorting:null,aaSortingFixed:[],asStripeClasses:null,asDestroyStripes:[],sDestroyWidth:0,aoRowCallback:[],aoHeaderCallback:[],aoFooterCallback:[],
159
+ aoDrawCallback:[],aoRowCreatedCallback:[],aoPreDrawCallback:[],aoInitComplete:[],aoStateSaveParams:[],aoStateLoadParams:[],aoStateLoaded:[],sTableId:"",nTable:null,nTHead:null,nTFoot:null,nTBody:null,nTableWrapper:null,bDeferLoading:!1,bInitialised:!1,aoOpenRows:[],sDom:null,searchDelay:null,sPaginationType:"two_button",iStateDuration:0,aoStateSave:[],aoStateLoad:[],oSavedState:null,oLoadedState:null,sAjaxSource:null,sAjaxDataProp:null,bAjaxDataGet:!0,jqXHR:null,json:k,oAjaxData:k,fnServerData:null,
160
+ aoServerParams:[],sServerMethod:null,fnFormatNumber:null,aLengthMenu:null,iDraw:0,bDrawing:!1,iDrawError:-1,_iDisplayLength:10,_iDisplayStart:0,_iRecordsTotal:0,_iRecordsDisplay:0,oClasses:{},bFiltered:!1,bSorted:!1,bSortCellsTop:null,oInit:null,aoDestroyCallback:[],fnRecordsTotal:function(){return"ssp"==y(this)?1*this._iRecordsTotal:this.aiDisplayMaster.length},fnRecordsDisplay:function(){return"ssp"==y(this)?1*this._iRecordsDisplay:this.aiDisplay.length},fnDisplayEnd:function(){var a=this._iDisplayLength,
161
+ b=this._iDisplayStart,c=b+a,d=this.aiDisplay.length,e=this.oFeatures,f=e.bPaginate;return e.bServerSide?!1===f||-1===a?b+d:Math.min(b+a,this._iRecordsDisplay):!f||c>d||-1===a?d:c},oInstance:null,sInstance:null,iTabIndex:0,nScrollHead:null,nScrollFoot:null,aLastSort:[],oPlugins:{},rowIdFn:null,rowId:null};m.ext=x={buttons:{},classes:{},build:"dt/dt-1.10.16/af-2.2.2/b-1.5.1/cr-1.4.1/fc-3.2.4/fh-3.1.3/kt-2.3.2/r-2.2.1/rr-1.2.3/sc-1.4.4/sl-1.2.5",errMode:"alert",feature:[],search:[],selector:{cell:[],column:[],row:[]},internal:{},legacy:{ajax:null},pager:{},renderer:{pageButton:{},header:{}},
162
+ order:{},type:{detect:[],search:{},order:{}},_unique:0,fnVersionCheck:m.fnVersionCheck,iApiIndex:0,oJUIClasses:{},sVersion:m.version};h.extend(x,{afnFiltering:x.search,aTypes:x.type.detect,ofnSearch:x.type.search,oSort:x.type.order,afnSortData:x.order,aoFeatures:x.feature,oApi:x.internal,oStdClasses:x.classes,oPagination:x.pager});h.extend(m.ext.classes,{sTable:"dataTable",sNoFooter:"no-footer",sPageButton:"paginate_button",sPageButtonActive:"current",sPageButtonDisabled:"disabled",sStripeOdd:"odd",
163
+ sStripeEven:"even",sRowEmpty:"dataTables_empty",sWrapper:"dataTables_wrapper",sFilter:"dataTables_filter",sInfo:"dataTables_info",sPaging:"dataTables_paginate paging_",sLength:"dataTables_length",sProcessing:"dataTables_processing",sSortAsc:"sorting_asc",sSortDesc:"sorting_desc",sSortable:"sorting",sSortableAsc:"sorting_asc_disabled",sSortableDesc:"sorting_desc_disabled",sSortableNone:"sorting_disabled",sSortColumn:"sorting_",sFilterInput:"",sLengthSelect:"",sScrollWrapper:"dataTables_scroll",sScrollHead:"dataTables_scrollHead",
164
+ sScrollHeadInner:"dataTables_scrollHeadInner",sScrollBody:"dataTables_scrollBody",sScrollFoot:"dataTables_scrollFoot",sScrollFootInner:"dataTables_scrollFootInner",sHeaderTH:"",sFooterTH:"",sSortJUIAsc:"",sSortJUIDesc:"",sSortJUI:"",sSortJUIAscAllowed:"",sSortJUIDescAllowed:"",sSortJUIWrapper:"",sSortIcon:"",sJUIHeader:"",sJUIFooter:""});var Kb=m.ext.pager;h.extend(Kb,{simple:function(){return["previous","next"]},full:function(){return["first","previous","next","last"]},numbers:function(a,b){return[ha(a,
165
+ b)]},simple_numbers:function(a,b){return["previous",ha(a,b),"next"]},full_numbers:function(a,b){return["first","previous",ha(a,b),"next","last"]},first_last_numbers:function(a,b){return["first",ha(a,b),"last"]},_numbers:ha,numbers_length:7});h.extend(!0,m.ext.renderer,{pageButton:{_:function(a,b,c,d,e,f){var g=a.oClasses,j=a.oLanguage.oPaginate,i=a.oLanguage.oAria.paginate||{},n,l,m=0,o=function(b,d){var k,s,u,r,v=function(b){Sa(a,b.data.action,true)};k=0;for(s=d.length;k<s;k++){r=d[k];if(h.isArray(r)){u=
166
+ h("<"+(r.DT_el||"div")+"/>").appendTo(b);o(u,r)}else{n=null;l="";switch(r){case "ellipsis":b.append('<span class="ellipsis">&#x2026;</span>');break;case "first":n=j.sFirst;l=r+(e>0?"":" "+g.sPageButtonDisabled);break;case "previous":n=j.sPrevious;l=r+(e>0?"":" "+g.sPageButtonDisabled);break;case "next":n=j.sNext;l=r+(e<f-1?"":" "+g.sPageButtonDisabled);break;case "last":n=j.sLast;l=r+(e<f-1?"":" "+g.sPageButtonDisabled);break;default:n=r+1;l=e===r?g.sPageButtonActive:""}if(n!==null){u=h("<a>",{"class":g.sPageButton+
167
+ " "+l,"aria-controls":a.sTableId,"aria-label":i[r],"data-dt-idx":m,tabindex:a.iTabIndex,id:c===0&&typeof r==="string"?a.sTableId+"_"+r:null}).html(n).appendTo(b);Va(u,{action:r},v);m++}}}},s;try{s=h(b).find(G.activeElement).data("dt-idx")}catch(u){}o(h(b).empty(),d);s!==k&&h(b).find("[data-dt-idx="+s+"]").focus()}}});h.extend(m.ext.type.detect,[function(a,b){var c=b.oLanguage.sDecimal;return Ya(a,c)?"num"+c:null},function(a){if(a&&!(a instanceof Date)&&!Zb.test(a))return null;var b=Date.parse(a);
168
+ return null!==b&&!isNaN(b)||L(a)?"date":null},function(a,b){var c=b.oLanguage.sDecimal;return Ya(a,c,!0)?"num-fmt"+c:null},function(a,b){var c=b.oLanguage.sDecimal;return Pb(a,c)?"html-num"+c:null},function(a,b){var c=b.oLanguage.sDecimal;return Pb(a,c,!0)?"html-num-fmt"+c:null},function(a){return L(a)||"string"===typeof a&&-1!==a.indexOf("<")?"html":null}]);h.extend(m.ext.type.search,{html:function(a){return L(a)?a:"string"===typeof a?a.replace(Mb," ").replace(Aa,""):""},string:function(a){return L(a)?
169
+ a:"string"===typeof a?a.replace(Mb," "):a}});var za=function(a,b,c,d){if(0!==a&&(!a||"-"===a))return-Infinity;b&&(a=Ob(a,b));a.replace&&(c&&(a=a.replace(c,"")),d&&(a=a.replace(d,"")));return 1*a};h.extend(x.type.order,{"date-pre":function(a){return Date.parse(a)||-Infinity},"html-pre":function(a){return L(a)?"":a.replace?a.replace(/<.*?>/g,"").toLowerCase():a+""},"string-pre":function(a){return L(a)?"":"string"===typeof a?a.toLowerCase():!a.toString?"":a.toString()},"string-asc":function(a,b){return a<
170
+ b?-1:a>b?1:0},"string-desc":function(a,b){return a<b?1:a>b?-1:0}});cb("");h.extend(!0,m.ext.renderer,{header:{_:function(a,b,c,d){h(a.nTable).on("order.dt.DT",function(e,f,g,h){if(a===f){e=c.idx;b.removeClass(c.sSortingClass+" "+d.sSortAsc+" "+d.sSortDesc).addClass(h[e]=="asc"?d.sSortAsc:h[e]=="desc"?d.sSortDesc:c.sSortingClass)}})},jqueryui:function(a,b,c,d){h("<div/>").addClass(d.sSortJUIWrapper).append(b.contents()).append(h("<span/>").addClass(d.sSortIcon+" "+c.sSortingClassJUI)).appendTo(b);
171
+ h(a.nTable).on("order.dt.DT",function(e,f,g,h){if(a===f){e=c.idx;b.removeClass(d.sSortAsc+" "+d.sSortDesc).addClass(h[e]=="asc"?d.sSortAsc:h[e]=="desc"?d.sSortDesc:c.sSortingClass);b.find("span."+d.sSortIcon).removeClass(d.sSortJUIAsc+" "+d.sSortJUIDesc+" "+d.sSortJUI+" "+d.sSortJUIAscAllowed+" "+d.sSortJUIDescAllowed).addClass(h[e]=="asc"?d.sSortJUIAsc:h[e]=="desc"?d.sSortJUIDesc:c.sSortingClassJUI)}})}}});var Vb=function(a){return"string"===typeof a?a.replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,
172
+ "&quot;"):a};m.render={number:function(a,b,c,d,e){return{display:function(f){if("number"!==typeof f&&"string"!==typeof f)return f;var g=0>f?"-":"",h=parseFloat(f);if(isNaN(h))return Vb(f);h=h.toFixed(c);f=Math.abs(h);h=parseInt(f,10);f=c?b+(f-h).toFixed(c).substring(2):"";return g+(d||"")+h.toString().replace(/\B(?=(\d{3})+(?!\d))/g,a)+f+(e||"")}}},text:function(){return{display:Vb}}};h.extend(m.ext.internal,{_fnExternApiFunc:Lb,_fnBuildAjax:sa,_fnAjaxUpdate:kb,_fnAjaxParameters:tb,_fnAjaxUpdateDraw:ub,
173
+ _fnAjaxDataSrc:ta,_fnAddColumn:Da,_fnColumnOptions:ja,_fnAdjustColumnSizing:Y,_fnVisibleToColumnIndex:Z,_fnColumnIndexToVisible:$,_fnVisbleColumns:aa,_fnGetColumns:la,_fnColumnTypes:Fa,_fnApplyColumnDefs:hb,_fnHungarianMap:X,_fnCamelToHungarian:I,_fnLanguageCompat:Ca,_fnBrowserDetect:fb,_fnAddData:M,_fnAddTr:ma,_fnNodeToDataIndex:function(a,b){return b._DT_RowIndex!==k?b._DT_RowIndex:null},_fnNodeToColumnIndex:function(a,b,c){return h.inArray(c,a.aoData[b].anCells)},_fnGetCellData:B,_fnSetCellData:ib,
174
+ _fnSplitObjNotation:Ia,_fnGetObjectDataFn:Q,_fnSetObjectDataFn:R,_fnGetDataMaster:Ja,_fnClearTable:na,_fnDeleteIndex:oa,_fnInvalidate:ca,_fnGetRowElements:Ha,_fnCreateTr:Ga,_fnBuildHead:jb,_fnDrawHead:ea,_fnDraw:N,_fnReDraw:S,_fnAddOptionsHtml:mb,_fnDetectHeader:da,_fnGetUniqueThs:ra,_fnFeatureHtmlFilter:ob,_fnFilterComplete:fa,_fnFilterCustom:xb,_fnFilterColumn:wb,_fnFilter:vb,_fnFilterCreateSearch:Oa,_fnEscapeRegex:Pa,_fnFilterData:yb,_fnFeatureHtmlInfo:rb,_fnUpdateInfo:Bb,_fnInfoMacros:Cb,_fnInitialise:ga,
175
+ _fnInitComplete:ua,_fnLengthChange:Qa,_fnFeatureHtmlLength:nb,_fnFeatureHtmlPaginate:sb,_fnPageChange:Sa,_fnFeatureHtmlProcessing:pb,_fnProcessingDisplay:C,_fnFeatureHtmlTable:qb,_fnScrollDraw:ka,_fnApplyToChildren:H,_fnCalculateColumnWidths:Ea,_fnThrottle:Na,_fnConvertToWidth:Db,_fnGetWidestNode:Eb,_fnGetMaxLenString:Fb,_fnStringToCss:v,_fnSortFlatten:V,_fnSort:lb,_fnSortAria:Hb,_fnSortListener:Ua,_fnSortAttachListener:La,_fnSortingClasses:wa,_fnSortData:Gb,_fnSaveState:xa,_fnLoadState:Ib,_fnSettingsFromNode:ya,
176
+ _fnLog:J,_fnMap:F,_fnBindAction:Va,_fnCallbackReg:z,_fnCallbackFire:r,_fnLengthOverflow:Ra,_fnRenderer:Ma,_fnDataSource:y,_fnRowAttributes:Ka,_fnCalculateEnd:function(){}});h.fn.dataTable=m;m.$=h;h.fn.dataTableSettings=m.settings;h.fn.dataTableExt=m.ext;h.fn.DataTable=function(a){return h(this).dataTable(a).api()};h.each(m,function(a,b){h.fn.DataTable[a]=b});return h.fn.dataTable});
177
+
178
+
179
+ /*!
180
+ AutoFill 2.2.2
181
+ ©2008-2017 SpryMedia Ltd - datatables.net/license
182
+ */
183
+ (function(e){"function"===typeof define&&define.amd?define(["jquery","datatables.net"],function(l){return e(l,window,document)}):"object"===typeof exports?module.exports=function(l,i){l||(l=window);if(!i||!i.fn.dataTable)i=require("datatables.net")(l,i).$;return e(i,l,l.document)}:e(jQuery,window,document)})(function(e,l,i,q){var k=e.fn.dataTable,p=0,j=function(c,b){if(!k.versionCheck||!k.versionCheck("1.10.8"))throw"Warning: AutoFill requires DataTables 1.10.8 or greater";this.c=e.extend(!0,{},k.defaults.autoFill,
184
+ j.defaults,b);this.s={dt:new k.Api(c),namespace:".autoFill"+p++,scroll:{},scrollInterval:null,handle:{height:0,width:0},enabled:!1};this.dom={handle:e('<div class="dt-autofill-handle"/>'),select:{top:e('<div class="dt-autofill-select top"/>'),right:e('<div class="dt-autofill-select right"/>'),bottom:e('<div class="dt-autofill-select bottom"/>'),left:e('<div class="dt-autofill-select left"/>')},background:e('<div class="dt-autofill-background"/>'),list:e('<div class="dt-autofill-list">'+this.s.dt.i18n("autoFill.info",
185
+ "")+"<ul/></div>"),dtScroll:null,offsetParent:null};this._constructor()};e.extend(j.prototype,{enabled:function(){return this.s.enabled},enable:function(c){var b=this;if(!1===c)return this.disable();this.s.enabled=!0;this._focusListener();this.dom.handle.on("mousedown",function(a){b._mousedown(a);return!1});return this},disable:function(){this.s.enabled=!1;this._focusListenerRemove();return this},_constructor:function(){var c=this,b=this.s.dt,a=e("div.dataTables_scrollBody",this.s.dt.table().container());
186
+ b.settings()[0].autoFill=this;a.length&&(this.dom.dtScroll=a,"static"===a.css("position")&&a.css("position","relative"));!1!==this.c.enable&&this.enable();b.on("destroy.autoFill",function(){c._focusListenerRemove()})},_attach:function(c){var b=this.s.dt,a=b.cell(c).index(),d=this.dom.handle,f=this.s.handle;if(!a||-1===b.columns(this.c.columns).indexes().indexOf(a.column))this._detach();else{this.dom.offsetParent||(this.dom.offsetParent=e(b.table().node()).offsetParent());if(!f.height||!f.width)d.appendTo("body"),
187
+ f.height=d.outerHeight(),f.width=d.outerWidth();b=this._getPosition(c,this.dom.offsetParent);this.dom.attachedTo=c;d.css({top:b.top+c.offsetHeight-f.height,left:b.left+c.offsetWidth-f.width}).appendTo(this.dom.offsetParent)}},_actionSelector:function(c){var b=this,a=this.s.dt,d=j.actions,f=[];e.each(d,function(b,d){d.available(a,c)&&f.push(b)});if(1===f.length&&!1===this.c.alwaysAsk){var h=d[f[0]].execute(a,c);this._update(h,c)}else{var g=this.dom.list.children("ul").empty();f.push("cancel");e.each(f,
188
+ function(f,h){g.append(e("<li/>").append('<div class="dt-autofill-question">'+d[h].option(a,c)+"<div>").append(e('<div class="dt-autofill-button">').append(e('<button class="'+j.classes.btn+'">'+a.i18n("autoFill.button","&gt;")+"</button>").on("click",function(){var f=d[h].execute(a,c,e(this).closest("li"));b._update(f,c);b.dom.background.remove();b.dom.list.remove()}))))});this.dom.background.appendTo("body");this.dom.list.appendTo("body");this.dom.list.css("margin-top",-1*(this.dom.list.outerHeight()/
189
+ 2))}},_detach:function(){this.dom.attachedTo=null;this.dom.handle.detach()},_drawSelection:function(c){var b=this.s.dt,a=this.s.start,d=e(this.dom.start),f=e(c),h={row:b.rows({page:"current"}).nodes().indexOf(f.parent()[0]),column:f.index()},c=b.column.index("toData",h.column);if(b.cell(f).any()&&-1!==b.columns(this.c.columns).indexes().indexOf(c)){this.s.end=h;var g,b=a.row<h.row?d:f;g=a.row<h.row?f:d;c=a.column<h.column?d:f;d=a.column<h.column?f:d;b=this._getPosition(b).top;c=this._getPosition(c).left;
190
+ a=this._getPosition(g).top+g.outerHeight()-b;d=this._getPosition(d).left+d.outerWidth()-c;f=this.dom.select;f.top.css({top:b,left:c,width:d});f.left.css({top:b,left:c,height:a});f.bottom.css({top:b+a,left:c,width:d});f.right.css({top:b,left:c+d,height:a})}},_editor:function(c){var b=this.s.dt,a=this.c.editor;if(a){for(var d={},f=[],e=a.fields(),g=0,i=c.length;g<i;g++)for(var j=0,l=c[g].length;j<l;j++){var o=c[g][j],k=b.settings()[0].aoColumns[o.index.column],n=k.editField;if(n===q)for(var k=k.mData,
191
+ m=0,p=e.length;m<p;m++){var r=a.field(e[m]);if(r.dataSrc()===k){n=r.name();break}}if(!n)throw"Could not automatically determine field data. Please see https://datatables.net/tn/11";d[n]||(d[n]={});k=b.row(o.index.row).id();d[n][k]=o.set;f.push(o.index)}a.bubble(f,!1).multiSet(d).submit()}},_emitEvent:function(c,b){this.s.dt.iterator("table",function(a){e(a.nTable).triggerHandler(c+".dt",b)})},_focusListener:function(){var c=this,b=this.s.dt,a=this.s.namespace,d=null!==this.c.focus?this.c.focus:b.init().keys||
192
+ b.settings()[0].keytable?"focus":"hover";if("focus"===d)b.on("key-focus.autoFill",function(b,a,d){c._attach(d.node())}).on("key-blur.autoFill",function(){c._detach()});else if("click"===d)e(b.table().body()).on("click"+a,"td, th",function(){c._attach(this)}),e(i.body).on("click"+a,function(a){e(a.target).parents().filter(b.table().body()).length||c._detach()});else e(b.table().body()).on("mouseenter"+a,"td, th",function(){c._attach(this)}).on("mouseleave"+a,function(b){e(b.relatedTarget).hasClass("dt-autofill-handle")||
193
+ c._detach()})},_focusListenerRemove:function(){var c=this.s.dt;c.off(".autoFill");e(c.table().body()).off(this.s.namespace);e(i.body).off(this.s.namespace)},_getPosition:function(c,b){var a=e(c),d,f,h=0,g=0;b||(b=e(this.s.dt.table().node()).offsetParent());do{f=a.position();d=a.offsetParent();h+=f.top+d.scrollTop();g+=f.left+d.scrollLeft();if("body"===a.get(0).nodeName.toLowerCase())break;a=d}while(d.get(0)!==b.get(0));return{top:h,left:g}},_mousedown:function(c){var b=this,a=this.s.dt;this.dom.start=
194
+ this.dom.attachedTo;this.s.start={row:a.rows({page:"current"}).nodes().indexOf(e(this.dom.start).parent()[0]),column:e(this.dom.start).index()};e(i.body).on("mousemove.autoFill",function(a){b._mousemove(a)}).on("mouseup.autoFill",function(a){b._mouseup(a)});var d=this.dom.select,a=e(a.table().node()).offsetParent();d.top.appendTo(a);d.left.appendTo(a);d.right.appendTo(a);d.bottom.appendTo(a);this._drawSelection(this.dom.start,c);this.dom.handle.css("display","none");c=this.dom.dtScroll;this.s.scroll=
195
+ {windowHeight:e(l).height(),windowWidth:e(l).width(),dtTop:c?c.offset().top:null,dtLeft:c?c.offset().left:null,dtHeight:c?c.outerHeight():null,dtWidth:c?c.outerWidth():null}},_mousemove:function(c){var b=c.target.nodeName.toLowerCase();"td"!==b&&"th"!==b||(this._drawSelection(c.target,c),this._shiftScroll(c))},_mouseup:function(){e(i.body).off(".autoFill");var c=this.s.dt,b=this.dom.select;b.top.remove();b.left.remove();b.right.remove();b.bottom.remove();this.dom.handle.css("display","block");var b=
196
+ this.s.start,a=this.s.end;if(!(b.row===a.row&&b.column===a.column)){for(var d=this._range(b.row,a.row),b=this._range(b.column,a.column),a=[],f=c.settings()[0],h=f.aoColumns,g=0;g<d.length;g++)a.push(e.map(b,function(a){var a=c.cell(":eq("+d[g]+")",a+":visible",{page:"current"}),b=a.data(),e=a.index(),i=h[e.column].editField;i!==q&&(b=f.oApi._fnGetObjectDataFn(i)(c.row(e.row).data()));return{cell:a,data:b,label:a.data(),index:e}}));this._actionSelector(a);clearInterval(this.s.scrollInterval);this.s.scrollInterval=
197
+ null}},_range:function(c,b){var a=[],d;if(c<=b)for(d=c;d<=b;d++)a.push(d);else for(d=c;d>=b;d--)a.push(d);return a},_shiftScroll:function(c){var b=this,a=this.s.scroll,d=!1,f=c.pageY-i.body.scrollTop,e=c.pageX-i.body.scrollLeft,g,j,k,l;65>f?g=-5:f>a.windowHeight-65&&(g=5);65>e?j=-5:e>a.windowWidth-65&&(j=5);null!==a.dtTop&&c.pageY<a.dtTop+65?k=-5:null!==a.dtTop&&c.pageY>a.dtTop+a.dtHeight-65&&(k=5);null!==a.dtLeft&&c.pageX<a.dtLeft+65?l=-5:null!==a.dtLeft&&c.pageX>a.dtLeft+a.dtWidth-65&&(l=5);g||
198
+ j||k||l?(a.windowVert=g,a.windowHoriz=j,a.dtVert=k,a.dtHoriz=l,d=!0):this.s.scrollInterval&&(clearInterval(this.s.scrollInterval),this.s.scrollInterval=null);!this.s.scrollInterval&&d&&(this.s.scrollInterval=setInterval(function(){if(a.windowVert)i.body.scrollTop=i.body.scrollTop+a.windowVert;if(a.windowHoriz)i.body.scrollLeft=i.body.scrollLeft+a.windowHoriz;if(a.dtVert||a.dtHoriz){var c=b.dom.dtScroll[0];if(a.dtVert)c.scrollTop=c.scrollTop+a.dtVert;if(a.dtHoriz)c.scrollLeft=c.scrollLeft+a.dtHoriz}},
199
+ 20))},_update:function(c,b){if(!1!==c){var a=this.s.dt,d;this._emitEvent("preAutoFill",[a,b]);this._editor(b);if(null!==this.c.update?this.c.update:!this.c.editor){for(var f=0,e=b.length;f<e;f++)for(var g=0,i=b[f].length;g<i;g++)d=b[f][g],d.cell.data(d.set);a.draw(!1)}this._emitEvent("autoFill",[a,b])}}});j.actions={increment:{available:function(c,b){return e.isNumeric(b[0][0].label)},option:function(c){return c.i18n("autoFill.increment",'Increment / decrement each cell by: <input type="number" value="1">')},
200
+ execute:function(c,b,a){for(var c=1*b[0][0].data,a=1*e("input",a).val(),d=0,f=b.length;d<f;d++)for(var h=0,g=b[d].length;h<g;h++)b[d][h].set=c,c+=a}},fill:{available:function(){return!0},option:function(c,b){return c.i18n("autoFill.fill","Fill all cells with <i>"+b[0][0].label+"</i>")},execute:function(c,b){for(var a=b[0][0].data,d=0,e=b.length;d<e;d++)for(var h=0,g=b[d].length;h<g;h++)b[d][h].set=a}},fillHorizontal:{available:function(c,b){return 1<b.length&&1<b[0].length},option:function(c){return c.i18n("autoFill.fillHorizontal",
201
+ "Fill cells horizontally")},execute:function(c,b){for(var a=0,d=b.length;a<d;a++)for(var e=0,h=b[a].length;e<h;e++)b[a][e].set=b[a][0].data}},fillVertical:{available:function(c,b){return 1<b.length&&1<b[0].length},option:function(c){return c.i18n("autoFill.fillVertical","Fill cells vertically")},execute:function(c,b){for(var a=0,d=b.length;a<d;a++)for(var e=0,h=b[a].length;e<h;e++)b[a][e].set=b[0][e].data}},cancel:{available:function(){return!1},option:function(c){return c.i18n("autoFill.cancel",
202
+ "Cancel")},execute:function(){return!1}}};j.version="2.2.2";j.defaults={alwaysAsk:!1,focus:null,columns:"",enable:!0,update:null,editor:null};j.classes={btn:"btn"};var m=e.fn.dataTable.Api;m.register("autoFill()",function(){return this});m.register("autoFill().enabled()",function(){var c=this.context[0];return c.autoFill?c.autoFill.enabled():!1});m.register("autoFill().enable()",function(c){return this.iterator("table",function(b){b.autoFill&&b.autoFill.enable(c)})});m.register("autoFill().disable()",
203
+ function(){return this.iterator("table",function(c){c.autoFill&&c.autoFill.disable()})});e(i).on("preInit.dt.autofill",function(c,b){if("dt"===c.namespace){var a=b.oInit.autoFill,d=k.defaults.autoFill;if(a||d)d=e.extend({},a,d),!1!==a&&new j(b,d)}});k.AutoFill=j;return k.AutoFill=j});
204
+
205
+
206
+ /*!
207
+ Buttons for DataTables 1.5.1
208
+ ©2016-2017 SpryMedia Ltd - datatables.net/license
209
+ */
210
+ (function(d){"function"===typeof define&&define.amd?define(["jquery","datatables.net"],function(o){return d(o,window,document)}):"object"===typeof exports?module.exports=function(o,n){o||(o=window);if(!n||!n.fn.dataTable)n=require("datatables.net")(o,n).$;return d(n,o,o.document)}:d(jQuery,window,document)})(function(d,o,n,l){var i=d.fn.dataTable,x=0,y=0,j=i.ext.buttons,m=function(a,b){"undefined"===typeof b&&(b={});!0===b&&(b={});d.isArray(b)&&(b={buttons:b});this.c=d.extend(!0,{},m.defaults,b);
211
+ b.buttons&&(this.c.buttons=b.buttons);this.s={dt:new i.Api(a),buttons:[],listenKeys:"",namespace:"dtb"+x++};this.dom={container:d("<"+this.c.dom.container.tag+"/>").addClass(this.c.dom.container.className)};this._constructor()};d.extend(m.prototype,{action:function(a,b){var c=this._nodeToButton(a);if(b===l)return c.conf.action;c.conf.action=b;return this},active:function(a,b){var c=this._nodeToButton(a),e=this.c.dom.button.active,c=d(c.node);if(b===l)return c.hasClass(e);c.toggleClass(e,b===l?!0:
212
+ b);return this},add:function(a,b){var c=this.s.buttons;if("string"===typeof b){for(var e=b.split("-"),c=this.s,d=0,g=e.length-1;d<g;d++)c=c.buttons[1*e[d]];c=c.buttons;b=1*e[e.length-1]}this._expandButton(c,a,!1,b);this._draw();return this},container:function(){return this.dom.container},disable:function(a){a=this._nodeToButton(a);d(a.node).addClass(this.c.dom.button.disabled);return this},destroy:function(){d("body").off("keyup."+this.s.namespace);var a=this.s.buttons.slice(),b,c;b=0;for(c=a.length;b<
213
+ c;b++)this.remove(a[b].node);this.dom.container.remove();a=this.s.dt.settings()[0];b=0;for(c=a.length;b<c;b++)if(a.inst===this){a.splice(b,1);break}return this},enable:function(a,b){if(!1===b)return this.disable(a);var c=this._nodeToButton(a);d(c.node).removeClass(this.c.dom.button.disabled);return this},name:function(){return this.c.name},node:function(a){a=this._nodeToButton(a);return d(a.node)},processing:function(a,b){var c=this._nodeToButton(a);if(b===l)return d(c.node).hasClass("processing");
214
+ d(c.node).toggleClass("processing",b);return this},remove:function(a){var b=this._nodeToButton(a),c=this._nodeToHost(a),e=this.s.dt;if(b.buttons.length)for(var h=b.buttons.length-1;0<=h;h--)this.remove(b.buttons[h].node);b.conf.destroy&&b.conf.destroy.call(e.button(a),e,d(a),b.conf);this._removeKey(b.conf);d(b.node).remove();a=d.inArray(b,c);c.splice(a,1);return this},text:function(a,b){var c=this._nodeToButton(a),e=this.c.dom.collection.buttonLiner,e=c.inCollection&&e&&e.tag?e.tag:this.c.dom.buttonLiner.tag,
215
+ h=this.s.dt,g=d(c.node),f=function(a){return"function"===typeof a?a(h,g,c.conf):a};if(b===l)return f(c.conf.text);c.conf.text=b;e?g.children(e).html(f(b)):g.html(f(b));return this},_constructor:function(){var a=this,b=this.s.dt,c=b.settings()[0],e=this.c.buttons;c._buttons||(c._buttons=[]);c._buttons.push({inst:this,name:this.c.name});for(var c=0,h=e.length;c<h;c++)this.add(e[c]);b.on("destroy",function(){a.destroy()});d("body").on("keyup."+this.s.namespace,function(b){if(!n.activeElement||n.activeElement===
216
+ n.body){var c=String.fromCharCode(b.keyCode).toLowerCase();a.s.listenKeys.toLowerCase().indexOf(c)!==-1&&a._keypress(c,b)}})},_addKey:function(a){a.key&&(this.s.listenKeys+=d.isPlainObject(a.key)?a.key.key:a.key)},_draw:function(a,b){a||(a=this.dom.container,b=this.s.buttons);a.children().detach();for(var c=0,e=b.length;c<e;c++)a.append(b[c].inserter),a.append(" "),b[c].buttons&&b[c].buttons.length&&this._draw(b[c].collection,b[c].buttons)},_expandButton:function(a,b,c,e){for(var h=this.s.dt,g=0,
217
+ b=!d.isArray(b)?[b]:b,f=0,q=b.length;f<q;f++){var k=this._resolveExtends(b[f]);if(k)if(d.isArray(k))this._expandButton(a,k,c,e);else{var p=this._buildButton(k,c);if(p){e!==l?(a.splice(e,0,p),e++):a.push(p);if(p.conf.buttons){var u=this.c.dom.collection;p.collection=d("<"+u.tag+"/>").addClass(u.className).attr("role","menu");p.conf._collection=p.collection;this._expandButton(p.buttons,p.conf.buttons,!0,e)}k.init&&k.init.call(h.button(p.node),h,d(p.node),k);g++}}}},_buildButton:function(a,b){var c=
218
+ this.c.dom.button,e=this.c.dom.buttonLiner,h=this.c.dom.collection,g=this.s.dt,f=function(b){return"function"===typeof b?b(g,k,a):b};b&&h.button&&(c=h.button);b&&h.buttonLiner&&(e=h.buttonLiner);if(a.available&&!a.available(g,a))return!1;var q=function(a,b,c,e){e.action.call(b.button(c),a,b,c,e);d(b.table().node()).triggerHandler("buttons-action.dt",[b.button(c),b,c,e])},k=d("<"+c.tag+"/>").addClass(c.className).attr("tabindex",this.s.dt.settings()[0].iTabIndex).attr("aria-controls",this.s.dt.table().node().id).on("click.dtb",
219
+ function(b){b.preventDefault();!k.hasClass(c.disabled)&&a.action&&q(b,g,k,a);k.blur()}).on("keyup.dtb",function(b){b.keyCode===13&&!k.hasClass(c.disabled)&&a.action&&q(b,g,k,a)});"a"===c.tag.toLowerCase()&&k.attr("href","#");e.tag?(h=d("<"+e.tag+"/>").html(f(a.text)).addClass(e.className),"a"===e.tag.toLowerCase()&&h.attr("href","#"),k.append(h)):k.html(f(a.text));!1===a.enabled&&k.addClass(c.disabled);a.className&&k.addClass(a.className);a.titleAttr&&k.attr("title",f(a.titleAttr));a.attr&&k.attr(a.attr);
220
+ a.namespace||(a.namespace=".dt-button-"+y++);e=(e=this.c.dom.buttonContainer)&&e.tag?d("<"+e.tag+"/>").addClass(e.className).append(k):k;this._addKey(a);return{conf:a,node:k.get(0),inserter:e,buttons:[],inCollection:b,collection:null}},_nodeToButton:function(a,b){b||(b=this.s.buttons);for(var c=0,e=b.length;c<e;c++){if(b[c].node===a)return b[c];if(b[c].buttons.length){var d=this._nodeToButton(a,b[c].buttons);if(d)return d}}},_nodeToHost:function(a,b){b||(b=this.s.buttons);for(var c=0,e=b.length;c<
221
+ e;c++){if(b[c].node===a)return b;if(b[c].buttons.length){var d=this._nodeToHost(a,b[c].buttons);if(d)return d}}},_keypress:function(a,b){if(!b._buttonsHandled){var c=function(e){for(var h=0,g=e.length;h<g;h++){var f=e[h].conf,q=e[h].node;if(f.key)if(f.key===a)b._buttonsHandled=!0,d(q).click();else if(d.isPlainObject(f.key)&&f.key.key===a&&(!f.key.shiftKey||b.shiftKey))if(!f.key.altKey||b.altKey)if(!f.key.ctrlKey||b.ctrlKey)if(!f.key.metaKey||b.metaKey)b._buttonsHandled=!0,d(q).click();e[h].buttons.length&&
222
+ c(e[h].buttons)}};c(this.s.buttons)}},_removeKey:function(a){if(a.key){var b=d.isPlainObject(a.key)?a.key.key:a.key,a=this.s.listenKeys.split(""),b=d.inArray(b,a);a.splice(b,1);this.s.listenKeys=a.join("")}},_resolveExtends:function(a){for(var b=this.s.dt,c,e,h=function(c){for(var e=0;!d.isPlainObject(c)&&!d.isArray(c);){if(c===l)return;if("function"===typeof c){if(c=c(b,a),!c)return!1}else if("string"===typeof c){if(!j[c])throw"Unknown button type: "+c;c=j[c]}e++;if(30<e)throw"Buttons: Too many iterations";
223
+ }return d.isArray(c)?c:d.extend({},c)},a=h(a);a&&a.extend;){if(!j[a.extend])throw"Cannot extend unknown button type: "+a.extend;var g=h(j[a.extend]);if(d.isArray(g))return g;if(!g)return!1;c=g.className;a=d.extend({},g,a);c&&a.className!==c&&(a.className=c+" "+a.className);var f=a.postfixButtons;if(f){a.buttons||(a.buttons=[]);c=0;for(e=f.length;c<e;c++)a.buttons.push(f[c]);a.postfixButtons=null}if(f=a.prefixButtons){a.buttons||(a.buttons=[]);c=0;for(e=f.length;c<e;c++)a.buttons.splice(c,0,f[c]);
224
+ a.prefixButtons=null}a.extend=g.extend}return a}});m.background=function(a,b,c){c===l&&(c=400);a?d("<div/>").addClass(b).css("display","none").appendTo("body").fadeIn(c):d("body > div."+b).fadeOut(c,function(){d(this).removeClass(b).remove()})};m.instanceSelector=function(a,b){if(!a)return d.map(b,function(a){return a.inst});var c=[],e=d.map(b,function(a){return a.name}),h=function(a){if(d.isArray(a))for(var f=0,q=a.length;f<q;f++)h(a[f]);else"string"===typeof a?-1!==a.indexOf(",")?h(a.split(",")):
225
+ (a=d.inArray(d.trim(a),e),-1!==a&&c.push(b[a].inst)):"number"===typeof a&&c.push(b[a].inst)};h(a);return c};m.buttonSelector=function(a,b){for(var c=[],e=function(a,b,c){for(var d,f,h=0,g=b.length;h<g;h++)if(d=b[h])f=c!==l?c+h:h+"",a.push({node:d.node,name:d.conf.name,idx:f}),d.buttons&&e(a,d.buttons,f+"-")},h=function(a,b){var f,g,i=[];e(i,b.s.buttons);f=d.map(i,function(a){return a.node});if(d.isArray(a)||a instanceof d){f=0;for(g=a.length;f<g;f++)h(a[f],b)}else if(null===a||a===l||"*"===a){f=0;
226
+ for(g=i.length;f<g;f++)c.push({inst:b,node:i[f].node})}else if("number"===typeof a)c.push({inst:b,node:b.s.buttons[a].node});else if("string"===typeof a)if(-1!==a.indexOf(",")){i=a.split(",");f=0;for(g=i.length;f<g;f++)h(d.trim(i[f]),b)}else if(a.match(/^\d+(\-\d+)*$/))f=d.map(i,function(a){return a.idx}),c.push({inst:b,node:i[d.inArray(a,f)].node});else if(-1!==a.indexOf(":name")){var j=a.replace(":name","");f=0;for(g=i.length;f<g;f++)i[f].name===j&&c.push({inst:b,node:i[f].node})}else d(f).filter(a).each(function(){c.push({inst:b,
227
+ node:this})});else"object"===typeof a&&a.nodeName&&(i=d.inArray(a,f),-1!==i&&c.push({inst:b,node:f[i]}))},g=0,f=a.length;g<f;g++)h(b,a[g]);return c};m.defaults={buttons:["copy","excel","csv","pdf","print"],name:"main",tabIndex:0,dom:{container:{tag:"div",className:"dt-buttons"},collection:{tag:"div",className:"dt-button-collection"},button:{tag:"button",className:"dt-button",active:"active",disabled:"disabled"},buttonLiner:{tag:"span",className:""}}};m.version="1.5.1";d.extend(j,{collection:{text:function(a){return a.i18n("buttons.collection",
228
+ "Collection")},className:"buttons-collection",action:function(a,b,c,e){var h=d(c).parents("div.dt-button-collection"),a=c.position(),g=d(b.table().container()),f=!1,i=c;h.length&&(f=d(".dt-button-collection").position(),i=h,d("body").trigger("click.dtb-collection"));e._collection.addClass(e.collectionLayout).css("display","none").insertAfter(i).fadeIn(e.fade);h=e._collection.css("position");f&&"absolute"===h?e._collection.css({top:f.top,left:f.left}):"absolute"===h?(e._collection.css({top:a.top+c.outerHeight(),
229
+ left:a.left}),f=g.offset().top+g.height(),c=a.top+c.outerHeight()+e._collection.outerHeight()-f,f=a.top-e._collection.outerHeight(),f=g.offset().top-f,c>f&&e._collection.css("top",a.top-e._collection.outerHeight()-5),c=a.left+e._collection.outerWidth(),g=g.offset().left+g.width(),c>g&&e._collection.css("left",a.left-(c-g))):(a=e._collection.height()/2,a>d(o).height()/2&&(a=d(o).height()/2),e._collection.css("marginTop",-1*a));e.background&&m.background(!0,e.backgroundClassName,e.fade);setTimeout(function(){d("div.dt-button-background").on("click.dtb-collection",
230
+ function(){});d("body").on("click.dtb-collection",function(a){var c=d.fn.addBack?"addBack":"andSelf";if(!d(a.target).parents()[c]().filter(e._collection).length){e._collection.fadeOut(e.fade,function(){e._collection.detach()});d("div.dt-button-background").off("click.dtb-collection");m.background(false,e.backgroundClassName,e.fade);d("body").off("click.dtb-collection");b.off("buttons-action.b-internal")}})},10);if(e.autoClose)b.on("buttons-action.b-internal",function(){d("div.dt-button-background").click()})},
231
+ background:!0,collectionLayout:"",backgroundClassName:"dt-button-background",autoClose:!1,fade:400,attr:{"aria-haspopup":!0}},copy:function(a,b){if(j.copyHtml5)return"copyHtml5";if(j.copyFlash&&j.copyFlash.available(a,b))return"copyFlash"},csv:function(a,b){if(j.csvHtml5&&j.csvHtml5.available(a,b))return"csvHtml5";if(j.csvFlash&&j.csvFlash.available(a,b))return"csvFlash"},excel:function(a,b){if(j.excelHtml5&&j.excelHtml5.available(a,b))return"excelHtml5";if(j.excelFlash&&j.excelFlash.available(a,
232
+ b))return"excelFlash"},pdf:function(a,b){if(j.pdfHtml5&&j.pdfHtml5.available(a,b))return"pdfHtml5";if(j.pdfFlash&&j.pdfFlash.available(a,b))return"pdfFlash"},pageLength:function(a){var a=a.settings()[0].aLengthMenu,b=d.isArray(a[0])?a[0]:a,c=d.isArray(a[0])?a[1]:a,e=function(a){return a.i18n("buttons.pageLength",{"-1":"Show all rows",_:"Show %d rows"},a.page.len())};return{extend:"collection",text:e,className:"buttons-page-length",autoClose:!0,buttons:d.map(b,function(a,b){return{text:c[b],className:"button-page-length",
233
+ action:function(b,c){c.page.len(a).draw()},init:function(b,c,d){var e=this,c=function(){e.active(b.page.len()===a)};b.on("length.dt"+d.namespace,c);c()},destroy:function(a,b,c){a.off("length.dt"+c.namespace)}}}),init:function(a,b,c){var d=this;a.on("length.dt"+c.namespace,function(){d.text(e(a))})},destroy:function(a,b,c){a.off("length.dt"+c.namespace)}}}});i.Api.register("buttons()",function(a,b){b===l&&(b=a,a=l);this.selector.buttonGroup=a;var c=this.iterator(!0,"table",function(c){if(c._buttons)return m.buttonSelector(m.instanceSelector(a,
234
+ c._buttons),b)},!0);c._groupSelector=a;return c});i.Api.register("button()",function(a,b){var c=this.buttons(a,b);1<c.length&&c.splice(1,c.length);return c});i.Api.registerPlural("buttons().active()","button().active()",function(a){return a===l?this.map(function(a){return a.inst.active(a.node)}):this.each(function(b){b.inst.active(b.node,a)})});i.Api.registerPlural("buttons().action()","button().action()",function(a){return a===l?this.map(function(a){return a.inst.action(a.node)}):this.each(function(b){b.inst.action(b.node,
235
+ a)})});i.Api.register(["buttons().enable()","button().enable()"],function(a){return this.each(function(b){b.inst.enable(b.node,a)})});i.Api.register(["buttons().disable()","button().disable()"],function(){return this.each(function(a){a.inst.disable(a.node)})});i.Api.registerPlural("buttons().nodes()","button().node()",function(){var a=d();d(this.each(function(b){a=a.add(b.inst.node(b.node))}));return a});i.Api.registerPlural("buttons().processing()","button().processing()",function(a){return a===
236
+ l?this.map(function(a){return a.inst.processing(a.node)}):this.each(function(b){b.inst.processing(b.node,a)})});i.Api.registerPlural("buttons().text()","button().text()",function(a){return a===l?this.map(function(a){return a.inst.text(a.node)}):this.each(function(b){b.inst.text(b.node,a)})});i.Api.registerPlural("buttons().trigger()","button().trigger()",function(){return this.each(function(a){a.inst.node(a.node).trigger("click")})});i.Api.registerPlural("buttons().containers()","buttons().container()",
237
+ function(){var a=d(),b=this._groupSelector;this.iterator(!0,"table",function(c){if(c._buttons)for(var c=m.instanceSelector(b,c._buttons),d=0,h=c.length;d<h;d++)a=a.add(c[d].container())});return a});i.Api.register("button().add()",function(a,b){var c=this.context;c.length&&(c=m.instanceSelector(this._groupSelector,c[0]._buttons),c.length&&c[0].add(b,a));return this.button(this._groupSelector,a)});i.Api.register("buttons().destroy()",function(){this.pluck("inst").unique().each(function(a){a.destroy()});
238
+ return this});i.Api.registerPlural("buttons().remove()","buttons().remove()",function(){this.each(function(a){a.inst.remove(a.node)});return this});var r;i.Api.register("buttons.info()",function(a,b,c){var e=this;if(!1===a)return d("#datatables_buttons_info").fadeOut(function(){d(this).remove()}),clearTimeout(r),r=null,this;r&&clearTimeout(r);d("#datatables_buttons_info").length&&d("#datatables_buttons_info").remove();d('<div id="datatables_buttons_info" class="dt-button-info"/>').html(a?"<h2>"+a+
239
+ "</h2>":"").append(d("<div/>")["string"===typeof b?"html":"append"](b)).css("display","none").appendTo("body").fadeIn();c!==l&&0!==c&&(r=setTimeout(function(){e.buttons.info(!1)},c));return this});i.Api.register("buttons.exportData()",function(a){if(this.context.length){var b=new i.Api(this.context[0]),c=d.extend(!0,{},{rows:null,columns:"",modifier:{search:"applied",order:"applied"},orthogonal:"display",stripHtml:!0,stripNewlines:!0,decodeEntities:!0,trim:!0,format:{header:function(a){return e(a)},
240
+ footer:function(a){return e(a)},body:function(a){return e(a)}}},a),e=function(a){if("string"!==typeof a)return a;a=a.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,"");c.stripHtml&&(a=a.replace(/<[^>]*>/g,""));c.trim&&(a=a.replace(/^\s+|\s+$/g,""));c.stripNewlines&&(a=a.replace(/\n/g," "));c.decodeEntities&&(v.innerHTML=a,a=v.value);return a},a=b.columns(c.columns).indexes().map(function(a){var d=b.column(a).header();return c.format.header(d.innerHTML,a,d)}).toArray(),h=b.table().footer()?
241
+ b.columns(c.columns).indexes().map(function(a){var d=b.column(a).footer();return c.format.footer(d?d.innerHTML:"",a,d)}).toArray():null,g=d.extend({},c.modifier);b.select&&"function"===typeof b.select.info&&g.selected===l&&b.rows(c.rows,d.extend({selected:!0},g)).any()&&d.extend(g,{selected:!0});for(var g=b.rows(c.rows,g).indexes().toArray(),f=b.cells(g,c.columns),g=f.render(c.orthogonal).toArray(),f=f.nodes().toArray(),j=a.length,k=0<j?g.length/j:0,m=[k],o=0,n=0;n<k;n++){for(var r=[j],s=0;s<j;s++)r[s]=
242
+ c.format.body(g[o],n,s,f[o]),o++;m[n]=r}return{header:a,footer:h,body:m}}});i.Api.register("buttons.exportInfo()",function(a){a||(a={});var b;var c=a;b="*"===c.filename&&"*"!==c.title&&c.title!==l&&null!==c.title&&""!==c.title?c.title:c.filename;"function"===typeof b&&(b=b());b===l||null===b?b=null:(-1!==b.indexOf("*")&&(b=d.trim(b.replace("*",d("head > title").text()))),b=b.replace(/[^a-zA-Z0-9_\u00A1-\uFFFF\.,\-_ !\(\)]/g,""),(c=t(c.extension))||(c=""),b+=c);c=t(a.title);c=null===c?null:-1!==c.indexOf("*")?
243
+ c.replace("*",d("head > title").text()||"Exported data"):c;return{filename:b,title:c,messageTop:w(this,a.message||a.messageTop,"top"),messageBottom:w(this,a.messageBottom,"bottom")}});var t=function(a){return null===a||a===l?null:"function"===typeof a?a():a},w=function(a,b,c){b=t(b);if(null===b)return null;a=d("caption",a.table().container()).eq(0);return"*"===b?a.css("caption-side")!==c?null:a.length?a.text():"":b},v=d("<textarea/>")[0];d.fn.dataTable.Buttons=m;d.fn.DataTable.Buttons=m;d(n).on("init.dt plugin-init.dt",
244
+ function(a,b){if("dt"===a.namespace){var c=b.oInit.buttons||i.defaults.buttons;c&&!b._buttons&&(new m(b,c)).container()}});i.ext.feature.push({fnInit:function(a){var a=new i.Api(a),b=a.init().buttons||i.defaults.buttons;return(new m(a,b)).container()},cFeature:"B"});return m});
245
+
246
+
247
+ /*!
248
+ ColReorder 1.4.1
249
+ ©2010-2017 SpryMedia Ltd - datatables.net/license
250
+ */
251
+ (function(f){"function"===typeof define&&define.amd?define(["jquery","datatables.net"],function(o){return f(o,window,document)}):"object"===typeof exports?module.exports=function(o,l){o||(o=window);if(!l||!l.fn.dataTable)l=require("datatables.net")(o,l).$;return f(l,o,o.document)}:f(jQuery,window,document)})(function(f,o,l,r){function q(a){for(var b=[],c=0,e=a.length;c<e;c++)b[a[c]]=c;return b}function p(a,b,c){b=a.splice(b,1)[0];a.splice(c,0,b)}function s(a,b,c){for(var e=[],f=0,d=a.childNodes.length;f<
252
+ d;f++)1==a.childNodes[f].nodeType&&e.push(a.childNodes[f]);b=e[b];null!==c?a.insertBefore(b,e[c]):a.appendChild(b)}var t=f.fn.dataTable;f.fn.dataTableExt.oApi.fnColReorder=function(a,b,c,e,g){var d,h,j,m,i,l=a.aoColumns.length,k;i=function(a,b,d){if(a[b]&&"function"!==typeof a[b]){var c=a[b].split("."),e=c.shift();isNaN(1*e)||(a[b]=d[1*e]+"."+c.join("."))}};if(b!=c)if(0>b||b>=l)this.oApi._fnLog(a,1,"ColReorder 'from' index is out of bounds: "+b);else if(0>c||c>=l)this.oApi._fnLog(a,1,"ColReorder 'to' index is out of bounds: "+
253
+ c);else{j=[];d=0;for(h=l;d<h;d++)j[d]=d;p(j,b,c);var n=q(j);d=0;for(h=a.aaSorting.length;d<h;d++)a.aaSorting[d][0]=n[a.aaSorting[d][0]];if(null!==a.aaSortingFixed){d=0;for(h=a.aaSortingFixed.length;d<h;d++)a.aaSortingFixed[d][0]=n[a.aaSortingFixed[d][0]]}d=0;for(h=l;d<h;d++){k=a.aoColumns[d];j=0;for(m=k.aDataSort.length;j<m;j++)k.aDataSort[j]=n[k.aDataSort[j]];k.idx=n[k.idx]}f.each(a.aLastSort,function(b,c){a.aLastSort[b].src=n[c.src]});d=0;for(h=l;d<h;d++)k=a.aoColumns[d],"number"==typeof k.mData?
254
+ k.mData=n[k.mData]:f.isPlainObject(k.mData)&&(i(k.mData,"_",n),i(k.mData,"filter",n),i(k.mData,"sort",n),i(k.mData,"type",n));if(a.aoColumns[b].bVisible){i=this.oApi._fnColumnIndexToVisible(a,b);m=null;for(d=c<b?c:c+1;null===m&&d<l;)m=this.oApi._fnColumnIndexToVisible(a,d),d++;j=a.nTHead.getElementsByTagName("tr");d=0;for(h=j.length;d<h;d++)s(j[d],i,m);if(null!==a.nTFoot){j=a.nTFoot.getElementsByTagName("tr");d=0;for(h=j.length;d<h;d++)s(j[d],i,m)}d=0;for(h=a.aoData.length;d<h;d++)null!==a.aoData[d].nTr&&
255
+ s(a.aoData[d].nTr,i,m)}p(a.aoColumns,b,c);d=0;for(h=l;d<h;d++)a.oApi._fnColumnOptions(a,d,{});p(a.aoPreSearchCols,b,c);d=0;for(h=a.aoData.length;d<h;d++){m=a.aoData[d];if(k=m.anCells){p(k,b,c);j=0;for(i=k.length;j<i;j++)k[j]&&k[j]._DT_CellIndex&&(k[j]._DT_CellIndex.column=j)}"dom"!==m.src&&f.isArray(m._aData)&&p(m._aData,b,c)}d=0;for(h=a.aoHeader.length;d<h;d++)p(a.aoHeader[d],b,c);if(null!==a.aoFooter){d=0;for(h=a.aoFooter.length;d<h;d++)p(a.aoFooter[d],b,c)}(g||g===r)&&f.fn.dataTable.Api(a).rows().invalidate();
256
+ d=0;for(h=l;d<h;d++)f(a.aoColumns[d].nTh).off("click.DT"),this.oApi._fnSortAttachListener(a,a.aoColumns[d].nTh,d);f(a.oInstance).trigger("column-reorder.dt",[a,{from:b,to:c,mapping:n,drop:e,iFrom:b,iTo:c,aiInvertMapping:n}])}};var i=function(a,b){var c=(new f.fn.dataTable.Api(a)).settings()[0];if(c._colReorder)return c._colReorder;!0===b&&(b={});var e=f.fn.dataTable.camelToHungarian;e&&(e(i.defaults,i.defaults,!0),e(i.defaults,b||{}));this.s={dt:null,init:f.extend(!0,{},i.defaults,b),fixed:0,fixedRight:0,
257
+ reorderCallback:null,mouse:{startX:-1,startY:-1,offsetX:-1,offsetY:-1,target:-1,targetIndex:-1,fromIndex:-1},aoTargets:[]};this.dom={drag:null,pointer:null};this.s.dt=c;this.s.dt._colReorder=this;this._fnConstruct();return this};f.extend(i.prototype,{fnReset:function(){this._fnOrderColumns(this.fnOrder());return this},fnGetCurrentOrder:function(){return this.fnOrder()},fnOrder:function(a,b){var c=[],e,g,d=this.s.dt.aoColumns;if(a===r){e=0;for(g=d.length;e<g;e++)c.push(d[e]._ColReorder_iOrigCol);return c}if(b){d=
258
+ this.fnOrder();e=0;for(g=a.length;e<g;e++)c.push(f.inArray(a[e],d));a=c}this._fnOrderColumns(q(a));return this},fnTranspose:function(a,b){b||(b="toCurrent");var c=this.fnOrder(),e=this.s.dt.aoColumns;return"toCurrent"===b?!f.isArray(a)?f.inArray(a,c):f.map(a,function(a){return f.inArray(a,c)}):!f.isArray(a)?e[a]._ColReorder_iOrigCol:f.map(a,function(a){return e[a]._ColReorder_iOrigCol})},_fnConstruct:function(){var a=this,b=this.s.dt.aoColumns.length,c=this.s.dt.nTable,e;this.s.init.iFixedColumns&&
259
+ (this.s.fixed=this.s.init.iFixedColumns);this.s.init.iFixedColumnsLeft&&(this.s.fixed=this.s.init.iFixedColumnsLeft);this.s.fixedRight=this.s.init.iFixedColumnsRight?this.s.init.iFixedColumnsRight:0;this.s.init.fnReorderCallback&&(this.s.reorderCallback=this.s.init.fnReorderCallback);for(e=0;e<b;e++)e>this.s.fixed-1&&e<b-this.s.fixedRight&&this._fnMouseListener(e,this.s.dt.aoColumns[e].nTh),this.s.dt.aoColumns[e]._ColReorder_iOrigCol=e;this.s.dt.oApi._fnCallbackReg(this.s.dt,"aoStateSaveParams",function(b,
260
+ c){a._fnStateSave.call(a,c)},"ColReorder_State");var g=null;this.s.init.aiOrder&&(g=this.s.init.aiOrder.slice());this.s.dt.oLoadedState&&("undefined"!=typeof this.s.dt.oLoadedState.ColReorder&&this.s.dt.oLoadedState.ColReorder.length==this.s.dt.aoColumns.length)&&(g=this.s.dt.oLoadedState.ColReorder);if(g)if(a.s.dt._bInitComplete)b=q(g),a._fnOrderColumns.call(a,b);else{var d=!1;f(c).on("draw.dt.colReorder",function(){if(!a.s.dt._bInitComplete&&!d){d=true;var b=q(g);a._fnOrderColumns.call(a,b)}})}else this._fnSetColumnIndexes();
261
+ f(c).on("destroy.dt.colReorder",function(){f(c).off("destroy.dt.colReorder draw.dt.colReorder");f(a.s.dt.nTHead).find("*").off(".ColReorder");f.each(a.s.dt.aoColumns,function(a,b){f(b.nTh).removeAttr("data-column-index")});a.s.dt._colReorder=null;a.s=null})},_fnOrderColumns:function(a){var b=!1;if(a.length!=this.s.dt.aoColumns.length)this.s.dt.oInstance.oApi._fnLog(this.s.dt,1,"ColReorder - array reorder does not match known number of columns. Skipping.");else{for(var c=0,e=a.length;c<e;c++){var g=
262
+ f.inArray(c,a);c!=g&&(p(a,g,c),this.s.dt.oInstance.fnColReorder(g,c,!0,!1),b=!0)}f.fn.dataTable.Api(this.s.dt).rows().invalidate();this._fnSetColumnIndexes();b&&((""!==this.s.dt.oScroll.sX||""!==this.s.dt.oScroll.sY)&&this.s.dt.oInstance.fnAdjustColumnSizing(!1),this.s.dt.oInstance.oApi._fnSaveState(this.s.dt),null!==this.s.reorderCallback&&this.s.reorderCallback.call(this))}},_fnStateSave:function(a){var b,c,e,g=this.s.dt.aoColumns;a.ColReorder=[];if(a.aaSorting){for(b=0;b<a.aaSorting.length;b++)a.aaSorting[b][0]=
263
+ g[a.aaSorting[b][0]]._ColReorder_iOrigCol;var d=f.extend(!0,[],a.aoSearchCols);b=0;for(c=g.length;b<c;b++)e=g[b]._ColReorder_iOrigCol,a.aoSearchCols[e]=d[b],a.abVisCols[e]=g[b].bVisible,a.ColReorder.push(e)}else if(a.order){for(b=0;b<a.order.length;b++)a.order[b][0]=g[a.order[b][0]]._ColReorder_iOrigCol;d=f.extend(!0,[],a.columns);b=0;for(c=g.length;b<c;b++)e=g[b]._ColReorder_iOrigCol,a.columns[e]=d[b],a.ColReorder.push(e)}},_fnMouseListener:function(a,b){var c=this;f(b).on("mousedown.ColReorder",
264
+ function(a){c._fnMouseDown.call(c,a,b)}).on("touchstart.ColReorder",function(a){c._fnMouseDown.call(c,a,b)})},_fnMouseDown:function(a,b){var c=this,e=f(a.target).closest("th, td").offset(),g=parseInt(f(b).attr("data-column-index"),10);g!==r&&(this.s.mouse.startX=this._fnCursorPosition(a,"pageX"),this.s.mouse.startY=this._fnCursorPosition(a,"pageY"),this.s.mouse.offsetX=this._fnCursorPosition(a,"pageX")-e.left,this.s.mouse.offsetY=this._fnCursorPosition(a,"pageY")-e.top,this.s.mouse.target=this.s.dt.aoColumns[g].nTh,
265
+ this.s.mouse.targetIndex=g,this.s.mouse.fromIndex=g,this._fnRegions(),f(l).on("mousemove.ColReorder touchmove.ColReorder",function(a){c._fnMouseMove.call(c,a)}).on("mouseup.ColReorder touchend.ColReorder",function(a){c._fnMouseUp.call(c,a)}))},_fnMouseMove:function(a){if(null===this.dom.drag){if(5>Math.pow(Math.pow(this._fnCursorPosition(a,"pageX")-this.s.mouse.startX,2)+Math.pow(this._fnCursorPosition(a,"pageY")-this.s.mouse.startY,2),0.5))return;this._fnCreateDragNode()}this.dom.drag.css({left:this._fnCursorPosition(a,
266
+ "pageX")-this.s.mouse.offsetX,top:this._fnCursorPosition(a,"pageY")-this.s.mouse.offsetY});for(var b=!1,c=this.s.mouse.toIndex,e=1,f=this.s.aoTargets.length;e<f;e++)if(this._fnCursorPosition(a,"pageX")<this.s.aoTargets[e-1].x+(this.s.aoTargets[e].x-this.s.aoTargets[e-1].x)/2){this.dom.pointer.css("left",this.s.aoTargets[e-1].x);this.s.mouse.toIndex=this.s.aoTargets[e-1].to;b=!0;break}b||(this.dom.pointer.css("left",this.s.aoTargets[this.s.aoTargets.length-1].x),this.s.mouse.toIndex=this.s.aoTargets[this.s.aoTargets.length-
267
+ 1].to);this.s.init.bRealtime&&c!==this.s.mouse.toIndex&&(this.s.dt.oInstance.fnColReorder(this.s.mouse.fromIndex,this.s.mouse.toIndex,!1),this.s.mouse.fromIndex=this.s.mouse.toIndex,this._fnRegions())},_fnMouseUp:function(){f(l).off(".ColReorder");null!==this.dom.drag&&(this.dom.drag.remove(),this.dom.pointer.remove(),this.dom.drag=null,this.dom.pointer=null,this.s.dt.oInstance.fnColReorder(this.s.mouse.fromIndex,this.s.mouse.toIndex,!0),this._fnSetColumnIndexes(),(""!==this.s.dt.oScroll.sX||""!==
268
+ this.s.dt.oScroll.sY)&&this.s.dt.oInstance.fnAdjustColumnSizing(!1),this.s.dt.oInstance.oApi._fnSaveState(this.s.dt),null!==this.s.reorderCallback&&this.s.reorderCallback.call(this))},_fnRegions:function(){var a=this.s.dt.aoColumns;this.s.aoTargets.splice(0,this.s.aoTargets.length);this.s.aoTargets.push({x:f(this.s.dt.nTable).offset().left,to:0});for(var b=0,c=this.s.aoTargets[0].x,e=0,g=a.length;e<g;e++)e!=this.s.mouse.fromIndex&&b++,a[e].bVisible&&"none"!==a[e].nTh.style.display&&(c+=f(a[e].nTh).outerWidth(),
269
+ this.s.aoTargets.push({x:c,to:b}));0!==this.s.fixedRight&&this.s.aoTargets.splice(this.s.aoTargets.length-this.s.fixedRight);0!==this.s.fixed&&this.s.aoTargets.splice(0,this.s.fixed)},_fnCreateDragNode:function(){var a=""!==this.s.dt.oScroll.sX||""!==this.s.dt.oScroll.sY,b=this.s.dt.aoColumns[this.s.mouse.targetIndex].nTh,c=b.parentNode,e=c.parentNode,g=e.parentNode,d=f(b).clone();this.dom.drag=f(g.cloneNode(!1)).addClass("DTCR_clonedTable").append(f(e.cloneNode(!1)).append(f(c.cloneNode(!1)).append(d[0]))).css({position:"absolute",
270
+ top:0,left:0,width:f(b).outerWidth(),height:f(b).outerHeight()}).appendTo("body");this.dom.pointer=f("<div></div>").addClass("DTCR_pointer").css({position:"absolute",top:a?f("div.dataTables_scroll",this.s.dt.nTableWrapper).offset().top:f(this.s.dt.nTable).offset().top,height:a?f("div.dataTables_scroll",this.s.dt.nTableWrapper).height():f(this.s.dt.nTable).height()}).appendTo("body")},_fnSetColumnIndexes:function(){f.each(this.s.dt.aoColumns,function(a,b){f(b.nTh).attr("data-column-index",a)})},_fnCursorPosition:function(a,
271
+ b){return-1!==a.type.indexOf("touch")?a.originalEvent.touches[0][b]:a[b]}});i.defaults={aiOrder:null,bRealtime:!0,iFixedColumnsLeft:0,iFixedColumnsRight:0,fnReorderCallback:null};i.version="1.4.1";f.fn.dataTable.ColReorder=i;f.fn.DataTable.ColReorder=i;"function"==typeof f.fn.dataTable&&"function"==typeof f.fn.dataTableExt.fnVersionCheck&&f.fn.dataTableExt.fnVersionCheck("1.10.8")?f.fn.dataTableExt.aoFeatures.push({fnInit:function(a){var b=a.oInstance;a._colReorder?b.oApi._fnLog(a,1,"ColReorder attempted to initialise twice. Ignoring second"):
272
+ (b=a.oInit,new i(a,b.colReorder||b.oColReorder||{}));return null},cFeature:"R",sFeature:"ColReorder"}):alert("Warning: ColReorder requires DataTables 1.10.8 or greater - www.datatables.net/download");f(l).on("preInit.dt.colReorder",function(a,b){if("dt"===a.namespace){var c=b.oInit.colReorder,e=t.defaults.colReorder;if(c||e)e=f.extend({},c,e),!1!==c&&new i(b,e)}});f.fn.dataTable.Api.register("colReorder.reset()",function(){return this.iterator("table",function(a){a._colReorder.fnReset()})});f.fn.dataTable.Api.register("colReorder.order()",
273
+ function(a,b){return a?this.iterator("table",function(c){c._colReorder.fnOrder(a,b)}):this.context.length?this.context[0]._colReorder.fnOrder():null});f.fn.dataTable.Api.register("colReorder.transpose()",function(a,b){return this.context.length&&this.context[0]._colReorder?this.context[0]._colReorder.fnTranspose(a,b):a});f.fn.dataTable.Api.register("colReorder.move()",function(a,b,c,e){this.context.length&&this.context[0]._colReorder.s.dt.oInstance.fnColReorder(a,b,c,e);return this});return i});
274
+
275
+
276
+ /*!
277
+ FixedColumns 3.2.4
278
+ ©2010-2017 SpryMedia Ltd - datatables.net/license
279
+ */
280
+ (function(d){"function"===typeof define&&define.amd?define(["jquery","datatables.net"],function(p){return d(p,window,document)}):"object"===typeof exports?module.exports=function(p,r){p||(p=window);if(!r||!r.fn.dataTable)r=require("datatables.net")(p,r).$;return d(r,p,p.document)}:d(jQuery,window,document)})(function(d,p,r,t){var s=d.fn.dataTable,u,m=function(a,b){var c=this;if(this instanceof m){if(b===t||!0===b)b={};var e=d.fn.dataTable.camelToHungarian;e&&(e(m.defaults,m.defaults,!0),e(m.defaults,
281
+ b));e=(new d.fn.dataTable.Api(a)).settings()[0];this.s={dt:e,iTableColumns:e.aoColumns.length,aiOuterWidths:[],aiInnerWidths:[],rtl:"rtl"===d(e.nTable).css("direction")};this.dom={scroller:null,header:null,body:null,footer:null,grid:{wrapper:null,dt:null,left:{wrapper:null,head:null,body:null,foot:null},right:{wrapper:null,head:null,body:null,foot:null}},clone:{left:{header:null,body:null,footer:null},right:{header:null,body:null,footer:null}}};if(e._oFixedColumns)throw"FixedColumns already initialised on this table";
282
+ e._oFixedColumns=this;e._bInitComplete?this._fnConstruct(b):e.oApi._fnCallbackReg(e,"aoInitComplete",function(){c._fnConstruct(b)},"FixedColumns")}else alert("FixedColumns warning: FixedColumns must be initialised with the 'new' keyword.")};d.extend(m.prototype,{fnUpdate:function(){this._fnDraw(!0)},fnRedrawLayout:function(){this._fnColCalc();this._fnGridLayout();this.fnUpdate()},fnRecalculateHeight:function(a){delete a._DTTC_iHeight;a.style.height="auto"},fnSetRowHeight:function(a,b){a.style.height=
283
+ b+"px"},fnGetPosition:function(a){var b=this.s.dt.oInstance;if(d(a).parents(".DTFC_Cloned").length){if("tr"===a.nodeName.toLowerCase())return a=d(a).index(),b.fnGetPosition(d("tr",this.s.dt.nTBody)[a]);var c=d(a).index(),a=d(a.parentNode).index();return[b.fnGetPosition(d("tr",this.s.dt.nTBody)[a]),c,b.oApi._fnVisibleToColumnIndex(this.s.dt,c)]}return b.fnGetPosition(a)},_fnConstruct:function(a){var b=this;if("function"!=typeof this.s.dt.oInstance.fnVersionCheck||!0!==this.s.dt.oInstance.fnVersionCheck("1.8.0"))alert("FixedColumns "+
284
+ m.VERSION+" required DataTables 1.8.0 or later. Please upgrade your DataTables installation");else if(""===this.s.dt.oScroll.sX)this.s.dt.oInstance.oApi._fnLog(this.s.dt,1,"FixedColumns is not needed (no x-scrolling in DataTables enabled), so no action will be taken. Use 'FixedHeader' for column fixing when scrolling is not enabled");else{this.s=d.extend(!0,this.s,m.defaults,a);a=this.s.dt.oClasses;this.dom.grid.dt=d(this.s.dt.nTable).parents("div."+a.sScrollWrapper)[0];this.dom.scroller=d("div."+
285
+ a.sScrollBody,this.dom.grid.dt)[0];this._fnColCalc();this._fnGridSetup();var c,e=!1;d(this.s.dt.nTableWrapper).on("mousedown.DTFC",function(a){0===a.button&&(e=!0,d(r).one("mouseup",function(){e=!1}))});d(this.dom.scroller).on("mouseover.DTFC touchstart.DTFC",function(){e||(c="main")}).on("scroll.DTFC",function(a){!c&&a.originalEvent&&(c="main");if("main"===c&&(0<b.s.iLeftColumns&&(b.dom.grid.left.liner.scrollTop=b.dom.scroller.scrollTop),0<b.s.iRightColumns))b.dom.grid.right.liner.scrollTop=b.dom.scroller.scrollTop});
286
+ var f="onwheel"in r.createElement("div")?"wheel.DTFC":"mousewheel.DTFC";if(0<b.s.iLeftColumns)d(b.dom.grid.left.liner).on("mouseover.DTFC touchstart.DTFC",function(){e||(c="left")}).on("scroll.DTFC",function(a){!c&&a.originalEvent&&(c="left");"left"===c&&(b.dom.scroller.scrollTop=b.dom.grid.left.liner.scrollTop,0<b.s.iRightColumns&&(b.dom.grid.right.liner.scrollTop=b.dom.grid.left.liner.scrollTop))}).on(f,function(a){b.dom.scroller.scrollLeft-="wheel"===a.type?-a.originalEvent.deltaX:a.originalEvent.wheelDeltaX});
287
+ if(0<b.s.iRightColumns)d(b.dom.grid.right.liner).on("mouseover.DTFC touchstart.DTFC",function(){e||(c="right")}).on("scroll.DTFC",function(a){!c&&a.originalEvent&&(c="right");"right"===c&&(b.dom.scroller.scrollTop=b.dom.grid.right.liner.scrollTop,0<b.s.iLeftColumns&&(b.dom.grid.left.liner.scrollTop=b.dom.grid.right.liner.scrollTop))}).on(f,function(a){b.dom.scroller.scrollLeft-="wheel"===a.type?-a.originalEvent.deltaX:a.originalEvent.wheelDeltaX});d(p).on("resize.DTFC",function(){b._fnGridLayout.call(b)});
288
+ var g=!0,h=d(this.s.dt.nTable);h.on("draw.dt.DTFC",function(){b._fnColCalc();b._fnDraw.call(b,g);g=!1}).on("column-sizing.dt.DTFC",function(){b._fnColCalc();b._fnGridLayout(b)}).on("column-visibility.dt.DTFC",function(a,c,d,e,f){if(f===t||f)b._fnColCalc(),b._fnGridLayout(b),b._fnDraw(!0)}).on("select.dt.DTFC deselect.dt.DTFC",function(a){"dt"===a.namespace&&b._fnDraw(!1)}).on("destroy.dt.DTFC",function(){h.off(".DTFC");d(b.dom.scroller).off(".DTFC");d(p).off(".DTFC");d(b.s.dt.nTableWrapper).off(".DTFC");
289
+ d(b.dom.grid.left.liner).off(".DTFC "+f);d(b.dom.grid.left.wrapper).remove();d(b.dom.grid.right.liner).off(".DTFC "+f);d(b.dom.grid.right.wrapper).remove()});this._fnGridLayout();this.s.dt.oInstance.fnDraw(!1)}},_fnColCalc:function(){var a=this,b=0,c=0;this.s.aiInnerWidths=[];this.s.aiOuterWidths=[];d.each(this.s.dt.aoColumns,function(e,f){var g=d(f.nTh),h;if(g.filter(":visible").length){var i=g.outerWidth();0===a.s.aiOuterWidths.length&&(h=d(a.s.dt.nTable).css("border-left-width"),i+="string"===
290
+ typeof h&&-1===h.indexOf("px")?1:parseInt(h,10));a.s.aiOuterWidths.length===a.s.dt.aoColumns.length-1&&(h=d(a.s.dt.nTable).css("border-right-width"),i+="string"===typeof h&&-1===h.indexOf("px")?1:parseInt(h,10));a.s.aiOuterWidths.push(i);a.s.aiInnerWidths.push(g.width());e<a.s.iLeftColumns&&(b+=i);a.s.iTableColumns-a.s.iRightColumns<=e&&(c+=i)}else a.s.aiInnerWidths.push(0),a.s.aiOuterWidths.push(0)});this.s.iLeftWidth=b;this.s.iRightWidth=c},_fnGridSetup:function(){var a=this._fnDTOverflow(),b;this.dom.body=
291
+ this.s.dt.nTable;this.dom.header=this.s.dt.nTHead.parentNode;this.dom.header.parentNode.parentNode.style.position="relative";var c=d('<div class="DTFC_ScrollWrapper" style="position:relative; clear:both;"><div class="DTFC_LeftWrapper" style="position:absolute; top:0; left:0;" aria-hidden="true"><div class="DTFC_LeftHeadWrapper" style="position:relative; top:0; left:0; overflow:hidden;"></div><div class="DTFC_LeftBodyWrapper" style="position:relative; top:0; left:0; overflow:hidden;"><div class="DTFC_LeftBodyLiner" style="position:relative; top:0; left:0; overflow-y:scroll;"></div></div><div class="DTFC_LeftFootWrapper" style="position:relative; top:0; left:0; overflow:hidden;"></div></div><div class="DTFC_RightWrapper" style="position:absolute; top:0; right:0;" aria-hidden="true"><div class="DTFC_RightHeadWrapper" style="position:relative; top:0; left:0;"><div class="DTFC_RightHeadBlocker DTFC_Blocker" style="position:absolute; top:0; bottom:0;"></div></div><div class="DTFC_RightBodyWrapper" style="position:relative; top:0; left:0; overflow:hidden;"><div class="DTFC_RightBodyLiner" style="position:relative; top:0; left:0; overflow-y:scroll;"></div></div><div class="DTFC_RightFootWrapper" style="position:relative; top:0; left:0;"><div class="DTFC_RightFootBlocker DTFC_Blocker" style="position:absolute; top:0; bottom:0;"></div></div></div></div>')[0],
292
+ e=c.childNodes[0],f=c.childNodes[1];this.dom.grid.dt.parentNode.insertBefore(c,this.dom.grid.dt);c.appendChild(this.dom.grid.dt);this.dom.grid.wrapper=c;0<this.s.iLeftColumns&&(this.dom.grid.left.wrapper=e,this.dom.grid.left.head=e.childNodes[0],this.dom.grid.left.body=e.childNodes[1],this.dom.grid.left.liner=d("div.DTFC_LeftBodyLiner",c)[0],c.appendChild(e));0<this.s.iRightColumns&&(this.dom.grid.right.wrapper=f,this.dom.grid.right.head=f.childNodes[0],this.dom.grid.right.body=f.childNodes[1],this.dom.grid.right.liner=
293
+ d("div.DTFC_RightBodyLiner",c)[0],f.style.right=a.bar+"px",b=d("div.DTFC_RightHeadBlocker",c)[0],b.style.width=a.bar+"px",b.style.right=-a.bar+"px",this.dom.grid.right.headBlock=b,b=d("div.DTFC_RightFootBlocker",c)[0],b.style.width=a.bar+"px",b.style.right=-a.bar+"px",this.dom.grid.right.footBlock=b,c.appendChild(f));if(this.s.dt.nTFoot&&(this.dom.footer=this.s.dt.nTFoot.parentNode,0<this.s.iLeftColumns&&(this.dom.grid.left.foot=e.childNodes[2]),0<this.s.iRightColumns))this.dom.grid.right.foot=f.childNodes[2];
294
+ this.s.rtl&&d("div.DTFC_RightHeadBlocker",c).css({left:-a.bar+"px",right:""})},_fnGridLayout:function(){var a=this,b=this.dom.grid;d(b.wrapper).width();var c=this.s.dt.nTable.parentNode.offsetHeight,e=this.s.dt.nTable.parentNode.parentNode.offsetHeight,f=this._fnDTOverflow(),g=this.s.iLeftWidth,h=this.s.iRightWidth,i="rtl"===d(this.dom.body).css("direction"),k=function(b,c){f.bar?a._firefoxScrollError()?34<d(b).height()&&(b.style.width=c+f.bar+"px"):b.style.width=c+f.bar+"px":(b.style.width=c+20+
295
+ "px",b.style.paddingRight="20px",b.style.boxSizing="border-box")};f.x&&(c-=f.bar);b.wrapper.style.height=e+"px";0<this.s.iLeftColumns&&(e=b.left.wrapper,e.style.width=g+"px",e.style.height="1px",i?(e.style.left="",e.style.right=0):(e.style.left=0,e.style.right=""),b.left.body.style.height=c+"px",b.left.foot&&(b.left.foot.style.top=(f.x?f.bar:0)+"px"),k(b.left.liner,g),b.left.liner.style.height=c+"px",b.left.liner.style.maxHeight=c+"px");0<this.s.iRightColumns&&(e=b.right.wrapper,e.style.width=h+"px",
296
+ e.style.height="1px",this.s.rtl?(e.style.left=f.y?f.bar+"px":0,e.style.right=""):(e.style.left="",e.style.right=f.y?f.bar+"px":0),b.right.body.style.height=c+"px",b.right.foot&&(b.right.foot.style.top=(f.x?f.bar:0)+"px"),k(b.right.liner,h),b.right.liner.style.height=c+"px",b.right.liner.style.maxHeight=c+"px",b.right.headBlock.style.display=f.y?"block":"none",b.right.footBlock.style.display=f.y?"block":"none")},_fnDTOverflow:function(){var a=this.s.dt.nTable,b=a.parentNode,c={x:!1,y:!1,bar:this.s.dt.oScroll.iBarWidth};
297
+ a.offsetWidth>b.clientWidth&&(c.x=!0);a.offsetHeight>b.clientHeight&&(c.y=!0);return c},_fnDraw:function(a){this._fnGridLayout();this._fnCloneLeft(a);this._fnCloneRight(a);null!==this.s.fnDrawCallback&&this.s.fnDrawCallback.call(this,this.dom.clone.left,this.dom.clone.right);d(this).trigger("draw.dtfc",{leftClone:this.dom.clone.left,rightClone:this.dom.clone.right})},_fnCloneRight:function(a){if(!(0>=this.s.iRightColumns)){var b,c=[];for(b=this.s.iTableColumns-this.s.iRightColumns;b<this.s.iTableColumns;b++)this.s.dt.aoColumns[b].bVisible&&
298
+ c.push(b);this._fnClone(this.dom.clone.right,this.dom.grid.right,c,a)}},_fnCloneLeft:function(a){if(!(0>=this.s.iLeftColumns)){var b,c=[];for(b=0;b<this.s.iLeftColumns;b++)this.s.dt.aoColumns[b].bVisible&&c.push(b);this._fnClone(this.dom.clone.left,this.dom.grid.left,c,a)}},_fnCopyLayout:function(a,b,c){for(var e=[],f=[],g=[],h=0,i=a.length;h<i;h++){var k=[];k.nTr=d(a[h].nTr).clone(c,!1)[0];for(var l=0,o=this.s.iTableColumns;l<o;l++)if(-1!==d.inArray(l,b)){var q=d.inArray(a[h][l].cell,g);-1===q?(q=
299
+ d(a[h][l].cell).clone(c,!1)[0],f.push(q),g.push(a[h][l].cell),k.push({cell:q,unique:a[h][l].unique})):k.push({cell:f[q],unique:a[h][l].unique})}e.push(k)}return e},_fnClone:function(a,b,c,e){var f=this,g,h,i,k,l,o,q,n,m,j=this.s.dt;if(e){d(a.header).remove();a.header=d(this.dom.header).clone(!0,!1)[0];a.header.className+=" DTFC_Cloned";a.header.style.width="100%";b.head.appendChild(a.header);n=this._fnCopyLayout(j.aoHeader,c,!0);k=d(">thead",a.header);k.empty();g=0;for(h=n.length;g<h;g++)k[0].appendChild(n[g].nTr);
300
+ j.oApi._fnDrawHead(j,n,!0)}else{n=this._fnCopyLayout(j.aoHeader,c,!1);m=[];j.oApi._fnDetectHeader(m,d(">thead",a.header)[0]);g=0;for(h=n.length;g<h;g++){i=0;for(k=n[g].length;i<k;i++)m[g][i].cell.className=n[g][i].cell.className,d("span.DataTables_sort_icon",m[g][i].cell).each(function(){this.className=d("span.DataTables_sort_icon",n[g][i].cell)[0].className})}}this._fnEqualiseHeights("thead",this.dom.header,a.header);"auto"==this.s.sHeightMatch&&d(">tbody>tr",f.dom.body).css("height","auto");null!==
301
+ a.body&&(d(a.body).remove(),a.body=null);a.body=d(this.dom.body).clone(!0)[0];a.body.className+=" DTFC_Cloned";a.body.style.paddingBottom=j.oScroll.iBarWidth+"px";a.body.style.marginBottom=2*j.oScroll.iBarWidth+"px";null!==a.body.getAttribute("id")&&a.body.removeAttribute("id");d(">thead>tr",a.body).empty();d(">tfoot",a.body).remove();var p=d("tbody",a.body)[0];d(p).empty();if(0<j.aiDisplay.length){h=d(">thead>tr",a.body)[0];for(q=0;q<c.length;q++)l=c[q],o=d(j.aoColumns[l].nTh).clone(!0)[0],o.innerHTML=
302
+ "",k=o.style,k.paddingTop="0",k.paddingBottom="0",k.borderTopWidth="0",k.borderBottomWidth="0",k.height=0,k.width=f.s.aiInnerWidths[l]+"px",h.appendChild(o);d(">tbody>tr",f.dom.body).each(function(a){var a=f.s.dt.oFeatures.bServerSide===false?f.s.dt.aiDisplay[f.s.dt._iDisplayStart+a]:a,b=f.s.dt.aoData[a].anCells||d(this).children("td, th"),e=this.cloneNode(false);e.removeAttribute("id");e.setAttribute("data-dt-row",a);for(q=0;q<c.length;q++){l=c[q];if(b.length>0){o=d(b[l]).clone(true,true)[0];o.removeAttribute("id");
303
+ o.setAttribute("data-dt-row",a);o.setAttribute("data-dt-column",j.oApi._fnVisibleToColumnIndex(j,l));e.appendChild(o)}}p.appendChild(e)})}else d(">tbody>tr",f.dom.body).each(function(){o=this.cloneNode(true);o.className=o.className+" DTFC_NoData";d("td",o).html("");p.appendChild(o)});a.body.style.width="100%";a.body.style.margin="0";a.body.style.padding="0";j.oScroller!==t&&(h=j.oScroller.dom.force,b.forcer?b.forcer.style.height=h.style.height:(b.forcer=h.cloneNode(!0),b.liner.appendChild(b.forcer)));
304
+ b.liner.appendChild(a.body);this._fnEqualiseHeights("tbody",f.dom.body,a.body);if(null!==j.nTFoot){if(e){null!==a.footer&&a.footer.parentNode.removeChild(a.footer);a.footer=d(this.dom.footer).clone(!0,!0)[0];a.footer.className+=" DTFC_Cloned";a.footer.style.width="100%";b.foot.appendChild(a.footer);n=this._fnCopyLayout(j.aoFooter,c,!0);b=d(">tfoot",a.footer);b.empty();g=0;for(h=n.length;g<h;g++)b[0].appendChild(n[g].nTr);j.oApi._fnDrawHead(j,n,!0)}else{n=this._fnCopyLayout(j.aoFooter,c,!1);b=[];j.oApi._fnDetectHeader(b,
305
+ d(">tfoot",a.footer)[0]);g=0;for(h=n.length;g<h;g++){i=0;for(k=n[g].length;i<k;i++)b[g][i].cell.className=n[g][i].cell.className}}this._fnEqualiseHeights("tfoot",this.dom.footer,a.footer)}b=j.oApi._fnGetUniqueThs(j,d(">thead",a.header)[0]);d(b).each(function(a){l=c[a];this.style.width=f.s.aiInnerWidths[l]+"px"});null!==f.s.dt.nTFoot&&(b=j.oApi._fnGetUniqueThs(j,d(">tfoot",a.footer)[0]),d(b).each(function(a){l=c[a];this.style.width=f.s.aiInnerWidths[l]+"px"}))},_fnGetTrNodes:function(a){for(var b=
306
+ [],c=0,d=a.childNodes.length;c<d;c++)"TR"==a.childNodes[c].nodeName.toUpperCase()&&b.push(a.childNodes[c]);return b},_fnEqualiseHeights:function(a,b,c){if(!("none"==this.s.sHeightMatch&&"thead"!==a&&"tfoot"!==a)){var e,f,g=b.getElementsByTagName(a)[0],c=c.getElementsByTagName(a)[0],a=d(">"+a+">tr:eq(0)",b).children(":first");a.outerHeight();a.height();for(var g=this._fnGetTrNodes(g),b=this._fnGetTrNodes(c),h=[],c=0,a=b.length;c<a;c++)e=g[c].offsetHeight,f=b[c].offsetHeight,e=f>e?f:e,"semiauto"==this.s.sHeightMatch&&
307
+ (g[c]._DTTC_iHeight=e),h.push(e);c=0;for(a=b.length;c<a;c++)b[c].style.height=h[c]+"px",g[c].style.height=h[c]+"px"}},_firefoxScrollError:function(){if(u===t){var a=d("<div/>").css({position:"absolute",top:0,left:0,height:10,width:50,overflow:"scroll"}).appendTo("body");u=a[0].clientWidth===a[0].offsetWidth&&0!==this._fnDTOverflow().bar;a.remove()}return u}});m.defaults={iLeftColumns:1,iRightColumns:0,fnDrawCallback:null,sHeightMatch:"semiauto"};m.version="3.2.4";s.Api.register("fixedColumns()",function(){return this});
308
+ s.Api.register("fixedColumns().update()",function(){return this.iterator("table",function(a){a._oFixedColumns&&a._oFixedColumns.fnUpdate()})});s.Api.register("fixedColumns().relayout()",function(){return this.iterator("table",function(a){a._oFixedColumns&&a._oFixedColumns.fnRedrawLayout()})});s.Api.register("rows().recalcHeight()",function(){return this.iterator("row",function(a,b){a._oFixedColumns&&a._oFixedColumns.fnRecalculateHeight(this.row(b).node())})});s.Api.register("fixedColumns().rowIndex()",
309
+ function(a){a=d(a);return a.parents(".DTFC_Cloned").length?this.rows({page:"current"}).indexes()[a.index()]:this.row(a).index()});s.Api.register("fixedColumns().cellIndex()",function(a){a=d(a);if(a.parents(".DTFC_Cloned").length){var b=a.parent().index(),b=this.rows({page:"current"}).indexes()[b],a=a.parents(".DTFC_LeftWrapper").length?a.index():this.columns().flatten().length-this.context[0]._oFixedColumns.s.iRightColumns+a.index();return{row:b,column:this.column.index("toData",a),columnVisible:a}}return this.cell(a).index()});
310
+ d(r).on("init.dt.fixedColumns",function(a,b){if("dt"===a.namespace){var c=b.oInit.fixedColumns,e=s.defaults.fixedColumns;if(c||e)e=d.extend({},c,e),!1!==c&&new m(b,e)}});d.fn.dataTable.FixedColumns=m;return d.fn.DataTable.FixedColumns=m});
311
+
312
+
313
+ /*!
314
+ FixedHeader 3.1.3
315
+ ©2009-2017 SpryMedia Ltd - datatables.net/license
316
+ */
317
+ (function(d){"function"===typeof define&&define.amd?define(["jquery","datatables.net"],function(g){return d(g,window,document)}):"object"===typeof exports?module.exports=function(g,h){g||(g=window);if(!h||!h.fn.dataTable)h=require("datatables.net")(g,h).$;return d(h,g,g.document)}:d(jQuery,window,document)})(function(d,g,h,k){var j=d.fn.dataTable,l=0,i=function(b,a){if(!(this instanceof i))throw"FixedHeader must be initialised with the 'new' keyword.";!0===a&&(a={});b=new j.Api(b);this.c=d.extend(!0,
318
+ {},i.defaults,a);this.s={dt:b,position:{theadTop:0,tbodyTop:0,tfootTop:0,tfootBottom:0,width:0,left:0,tfootHeight:0,theadHeight:0,windowHeight:d(g).height(),visible:!0},headerMode:null,footerMode:null,autoWidth:b.settings()[0].oFeatures.bAutoWidth,namespace:".dtfc"+l++,scrollLeft:{header:-1,footer:-1},enable:!0};this.dom={floatingHeader:null,thead:d(b.table().header()),tbody:d(b.table().body()),tfoot:d(b.table().footer()),header:{host:null,floating:null,placeholder:null},footer:{host:null,floating:null,
319
+ placeholder:null}};this.dom.header.host=this.dom.thead.parent();this.dom.footer.host=this.dom.tfoot.parent();var e=b.settings()[0];if(e._fixedHeader)throw"FixedHeader already initialised on table "+e.nTable.id;e._fixedHeader=this;this._constructor()};d.extend(i.prototype,{enable:function(b){this.s.enable=b;this.c.header&&this._modeChange("in-place","header",!0);this.c.footer&&this.dom.tfoot.length&&this._modeChange("in-place","footer",!0);this.update()},headerOffset:function(b){b!==k&&(this.c.headerOffset=
320
+ b,this.update());return this.c.headerOffset},footerOffset:function(b){b!==k&&(this.c.footerOffset=b,this.update());return this.c.footerOffset},update:function(){this._positions();this._scroll(!0)},_constructor:function(){var b=this,a=this.s.dt;d(g).on("scroll"+this.s.namespace,function(){b._scroll()}).on("resize"+this.s.namespace,function(){b.s.position.windowHeight=d(g).height();b.update()});var e=d(".fh-fixedHeader");!this.c.headerOffset&&e.length&&(this.c.headerOffset=e.outerHeight());e=d(".fh-fixedFooter");
321
+ !this.c.footerOffset&&e.length&&(this.c.footerOffset=e.outerHeight());a.on("column-reorder.dt.dtfc column-visibility.dt.dtfc draw.dt.dtfc column-sizing.dt.dtfc",function(){b.update()});a.on("destroy.dtfc",function(){a.off(".dtfc");d(g).off(b.s.namespace)});this._positions();this._scroll()},_clone:function(b,a){var e=this.s.dt,c=this.dom[b],f="header"===b?this.dom.thead:this.dom.tfoot;!a&&c.floating?c.floating.removeClass("fixedHeader-floating fixedHeader-locked"):(c.floating&&(c.placeholder.remove(),
322
+ this._unsize(b),c.floating.children().detach(),c.floating.remove()),c.floating=d(e.table().node().cloneNode(!1)).css("table-layout","fixed").removeAttr("id").append(f).appendTo("body"),c.placeholder=f.clone(!1),c.placeholder.find("*[id]").removeAttr("id"),c.host.prepend(c.placeholder),this._matchWidths(c.placeholder,c.floating))},_matchWidths:function(b,a){var e=function(a){return d(a,b).map(function(){return d(this).width()}).toArray()},c=function(b,c){d(b,a).each(function(a){d(this).css({width:c[a],
323
+ minWidth:c[a]})})},f=e("th"),e=e("td");c("th",f);c("td",e)},_unsize:function(b){var a=this.dom[b].floating;a&&("footer"===b||"header"===b&&!this.s.autoWidth)?d("th, td",a).css({width:"",minWidth:""}):a&&"header"===b&&d("th, td",a).css("min-width","")},_horizontal:function(b,a){var e=this.dom[b],c=this.s.position,d=this.s.scrollLeft;e.floating&&d[b]!==a&&(e.floating.css("left",c.left-a),d[b]=a)},_modeChange:function(b,a,e){var c=this.dom[a],f=this.s.position,g=d.contains(this.dom["footer"===a?"tfoot":
324
+ "thead"][0],h.activeElement)?h.activeElement:null;if("in-place"===b){if(c.placeholder&&(c.placeholder.remove(),c.placeholder=null),this._unsize(a),"header"===a?c.host.prepend(this.dom.thead):c.host.append(this.dom.tfoot),c.floating)c.floating.remove(),c.floating=null}else"in"===b?(this._clone(a,e),c.floating.addClass("fixedHeader-floating").css("header"===a?"top":"bottom",this.c[a+"Offset"]).css("left",f.left+"px").css("width",f.width+"px"),"footer"===a&&c.floating.css("top","")):"below"===b?(this._clone(a,
325
+ e),c.floating.addClass("fixedHeader-locked").css("top",f.tfootTop-f.theadHeight).css("left",f.left+"px").css("width",f.width+"px")):"above"===b&&(this._clone(a,e),c.floating.addClass("fixedHeader-locked").css("top",f.tbodyTop).css("left",f.left+"px").css("width",f.width+"px"));g&&g!==h.activeElement&&g.focus();this.s.scrollLeft.header=-1;this.s.scrollLeft.footer=-1;this.s[a+"Mode"]=b},_positions:function(){var b=this.s.dt.table(),a=this.s.position,e=this.dom,b=d(b.node()),c=b.children("thead"),f=
326
+ b.children("tfoot"),e=e.tbody;a.visible=b.is(":visible");a.width=b.outerWidth();a.left=b.offset().left;a.theadTop=c.offset().top;a.tbodyTop=e.offset().top;a.theadHeight=a.tbodyTop-a.theadTop;f.length?(a.tfootTop=f.offset().top,a.tfootBottom=a.tfootTop+f.outerHeight(),a.tfootHeight=a.tfootBottom-a.tfootTop):(a.tfootTop=a.tbodyTop+e.outerHeight(),a.tfootBottom=a.tfootTop,a.tfootHeight=a.tfootTop)},_scroll:function(b){var a=d(h).scrollTop(),e=d(h).scrollLeft(),c=this.s.position,f;if(this.s.enable&&(this.c.header&&
327
+ (f=!c.visible||a<=c.theadTop-this.c.headerOffset?"in-place":a<=c.tfootTop-c.theadHeight-this.c.headerOffset?"in":"below",(b||f!==this.s.headerMode)&&this._modeChange(f,"header",b),this._horizontal("header",e)),this.c.footer&&this.dom.tfoot.length))a=!c.visible||a+c.windowHeight>=c.tfootBottom+this.c.footerOffset?"in-place":c.windowHeight+a>c.tbodyTop+c.tfootHeight+this.c.footerOffset?"in":"above",(b||a!==this.s.footerMode)&&this._modeChange(a,"footer",b),this._horizontal("footer",e)}});i.version=
328
+ "3.1.3";i.defaults={header:!0,footer:!1,headerOffset:0,footerOffset:0};d.fn.dataTable.FixedHeader=i;d.fn.DataTable.FixedHeader=i;d(h).on("init.dt.dtfh",function(b,a){if("dt"===b.namespace){var e=a.oInit.fixedHeader,c=j.defaults.fixedHeader;if((e||c)&&!a._fixedHeader)c=d.extend({},c,e),!1!==e&&new i(a,c)}});j.Api.register("fixedHeader()",function(){});j.Api.register("fixedHeader.adjust()",function(){return this.iterator("table",function(b){(b=b._fixedHeader)&&b.update()})});j.Api.register("fixedHeader.enable()",
329
+ function(b){return this.iterator("table",function(a){a=a._fixedHeader;b=b!==k?b:!0;a&&b!==a.s.enable&&a.enable(b)})});j.Api.register("fixedHeader.disable()",function(){return this.iterator("table",function(b){(b=b._fixedHeader)&&b.s.enable&&b.enable(!1)})});d.each(["header","footer"],function(b,a){j.Api.register("fixedHeader."+a+"Offset()",function(b){var c=this.context;return b===k?c.length&&c[0]._fixedHeader?c[0]._fixedHeader[a+"Offset"]():k:this.iterator("table",function(c){if(c=c._fixedHeader)c[a+
330
+ "Offset"](b)})})});return i});
331
+
332
+
333
+ /*!
334
+ KeyTable 2.3.2
335
+ ©2009-2017 SpryMedia Ltd - datatables.net/license
336
+ */
337
+ (function(f){"function"===typeof define&&define.amd?define(["jquery","datatables.net"],function(k){return f(k,window,document)}):"object"===typeof exports?module.exports=function(k,h){k||(k=window);if(!h||!h.fn.dataTable)h=require("datatables.net")(k,h).$;return f(h,k,k.document)}:f(jQuery,window,document)})(function(f,k,h,o){var l=f.fn.dataTable,n=function(a,b){if(!l.versionCheck||!l.versionCheck("1.10.8"))throw"KeyTable requires DataTables 1.10.8 or newer";this.c=f.extend(!0,{},l.defaults.keyTable,
338
+ n.defaults,b);this.s={dt:new l.Api(a),enable:!0,focusDraw:!1,waitingForDraw:!1,lastFocus:null};this.dom={};var c=this.s.dt.settings()[0],d=c.keytable;if(d)return d;c.keytable=this;this._constructor()};f.extend(n.prototype,{blur:function(){this._blur()},enable:function(a){this.s.enable=a},focus:function(a,b){this._focus(this.s.dt.cell(a,b))},focused:function(a){if(!this.s.lastFocus)return!1;var b=this.s.lastFocus.cell.index();return a.row===b.row&&a.column===b.column},_constructor:function(){this._tabInput();
339
+ var a=this,b=this.s.dt,c=f(b.table().node());"static"===c.css("position")&&c.css("position","relative");f(b.table().body()).on("click.keyTable","th, td",function(c){if(!1!==a.s.enable){var d=b.cell(this);d.any()&&a._focus(d,null,!1,c)}});f(h).on("keydown.keyTable",function(b){a._key(b)});if(this.c.blurable)f(h).on("mousedown.keyTable",function(c){f(c.target).parents(".dataTables_filter").length&&a._blur();f(c.target).parents().filter(b.table().container()).length||f(c.target).parents("div.DTE").length||
340
+ f(c.target).parents("div.editor-datetime").length||f(c.target).parents().filter(".DTFC_Cloned").length||a._blur()});if(this.c.editor){var d=this.c.editor;d.on("open.keyTableMain",function(b,c){"inline"!==c&&a.s.enable&&(a.enable(!1),d.one("close.keyTable",function(){a.enable(!0)}))});if(this.c.editOnFocus)b.on("key-focus.keyTable key-refocus.keyTable",function(b,c,d,e){a._editor(null,e)});b.on("key.keyTable",function(b,c,d,e,f){a._editor(d,f)})}if(b.settings()[0].oFeatures.bStateSave)b.on("stateSaveParams.keyTable",
341
+ function(b,c,d){d.keyTable=a.s.lastFocus?a.s.lastFocus.cell.index():null});b.on("draw.keyTable",function(c){if(!a.s.focusDraw){var d=a.s.lastFocus;if(d&&d.node&&f(d.node).closest("body")===h.body){var d=a.s.lastFocus.relative,e=b.page.info(),j=d.row+e.start;0!==e.recordsDisplay&&(j>=e.recordsDisplay&&(j=e.recordsDisplay-1),a._focus(j,d.column,!0,c))}}});b.on("destroy.keyTable",function(){b.off(".keyTable");f(b.table().body()).off("click.keyTable","th, td");f(h.body).off("keydown.keyTable").off("click.keyTable")});
342
+ var e=b.state.loaded();if(e&&e.keyTable)b.one("init",function(){var a=b.cell(e.keyTable);a.any()&&a.focus()});else this.c.focus&&b.cell(this.c.focus).focus()},_blur:function(){if(this.s.enable&&this.s.lastFocus){var a=this.s.lastFocus.cell;f(a.node()).removeClass(this.c.className);this.s.lastFocus=null;this._updateFixedColumns(a.index().column);this._emitEvent("key-blur",[this.s.dt,a])}},_clipboardCopy:function(){var a=this.s.dt;if(this.s.lastFocus&&k.getSelection&&!k.getSelection().toString()){var b=
343
+ this.s.lastFocus.cell.render("display"),c=f("<div/>").css({height:1,width:1,overflow:"hidden",position:"fixed",top:0,left:0}),b=f("<textarea readonly/>").val(b).appendTo(c);try{c.appendTo(a.table().container()),b[0].focus(),b[0].select(),h.execCommand("copy")}catch(d){}c.remove()}},_columns:function(){var a=this.s.dt,b=a.columns(this.c.columns).indexes(),c=[];a.columns(":visible").every(function(a){-1!==b.indexOf(a)&&c.push(a)});return c},_editor:function(a,b){var c=this,d=this.s.dt,e=this.c.editor;
344
+ !f("div.DTE",this.s.lastFocus.cell.node()).length&&16!==a&&(b.stopPropagation(),13===a&&b.preventDefault(),e.one("open.keyTable",function(){e.off("cancelOpen.keyTable");c.c.editAutoSelect&&f("div.DTE_Field_InputControl input, div.DTE_Field_InputControl textarea").select();d.keys.enable(c.c.editorKeys);d.one("key-blur.editor",function(){e.displayed()&&e.submit()});e.one("close",function(){d.keys.enable(!0);d.off("key-blur.editor")})}).one("cancelOpen.keyTable",function(){e.off("open.keyTable")}).inline(this.s.lastFocus.cell.index()))},
345
+ _emitEvent:function(a,b){this.s.dt.iterator("table",function(c){f(c.nTable).triggerHandler(a,b)})},_focus:function(a,b,c,d){var e=this,m=this.s.dt,g=m.page.info(),i=this.s.lastFocus;d||(d=null);if(this.s.enable){if("number"!==typeof a){var j=a.index(),b=j.column,a=m.rows({filter:"applied",order:"applied"}).indexes().indexOf(j.row);g.serverSide&&(a+=g.start)}if(-1!==g.length&&(a<g.start||a>=g.start+g.length))this.s.focusDraw=!0,this.s.waitingForDraw=!0,m.one("draw",function(){e.s.focusDraw=!1;e.s.waitingForDraw=
346
+ !1;e._focus(a,b,o,d)}).page(Math.floor(a/g.length)).draw(!1);else if(-1!==f.inArray(b,this._columns())){g.serverSide&&(a-=g.start);g=m.cells(null,b,{search:"applied",order:"applied"}).flatten();g=m.cell(g[a]);if(i){if(i.node===g.node()){this._emitEvent("key-refocus",[this.s.dt,g,d||null]);return}this._blur()}i=f(g.node());i.addClass(this.c.className);this._updateFixedColumns(b);if(c===o||!0===c)this._scroll(f(k),f(h.body),i,"offset"),c=m.table().body().parentNode,c!==m.table().header().parentNode&&
347
+ (c=f(c.parentNode),this._scroll(c,c,i,"position"));this.s.lastFocus={cell:g,node:g.node(),relative:{row:m.rows({page:"current"}).indexes().indexOf(g.index().row),column:g.index().column}};this._emitEvent("key-focus",[this.s.dt,g,d||null]);m.state.save()}}},_key:function(a){if(this.s.waitingForDraw)a.preventDefault();else{var b=this.s.enable,c=!0===b||"navigation-only"===b;if(b)if(a.ctrlKey&&67===a.keyCode)this._clipboardCopy();else if(!(0===a.keyCode||a.ctrlKey||a.metaKey||a.altKey)&&this.s.lastFocus){var d=
348
+ this.s.dt;if(!(this.c.keys&&-1===f.inArray(a.keyCode,this.c.keys)))switch(a.keyCode){case 9:this._shift(a,a.shiftKey?"left":"right",!0);break;case 27:this.s.blurable&&!0===b&&this._blur();break;case 33:case 34:c&&(a.preventDefault(),d.page(33===a.keyCode?"previous":"next").draw(!1));break;case 35:case 36:c&&(a.preventDefault(),b=d.cells({page:"current"}).indexes(),c=this._columns(),this._focus(d.cell(b[35===a.keyCode?b.length-1:c[0]]),null,!0,a));break;case 37:c&&this._shift(a,"left");break;case 38:c&&
349
+ this._shift(a,"up");break;case 39:c&&this._shift(a,"right");break;case 40:c&&this._shift(a,"down");break;default:!0===b&&this._emitEvent("key",[d,a.keyCode,this.s.lastFocus.cell,a])}}}},_scroll:function(a,b,c,d){var e=c[d](),f=c.outerHeight(),g=c.outerWidth(),i=b.scrollTop(),j=b.scrollLeft(),h=a.height(),a=a.width();"position"===d&&(e.top+=parseInt(c.closest("table").css("top"),10));e.top<i&&b.scrollTop(e.top);e.left<j&&b.scrollLeft(e.left);e.top+f>i+h&&f<h&&b.scrollTop(e.top+f-h);e.left+g>j+a&&g<
350
+ a&&b.scrollLeft(e.left+g-a)},_shift:function(a,b,c){var d=this.s.dt,e=d.page.info(),h=e.recordsDisplay,g=this.s.lastFocus.cell,i=this._columns();if(g){var j=d.rows({filter:"applied",order:"applied"}).indexes().indexOf(g.index().row);e.serverSide&&(j+=e.start);d=d.columns(i).indexes().indexOf(g.index().column);e=i[d];"right"===b?d>=i.length-1?(j++,e=i[0]):e=i[d+1]:"left"===b?0===d?(j--,e=i[i.length-1]):e=i[d-1]:"up"===b?j--:"down"===b&&j++;0<=j&&j<h&&-1!==f.inArray(e,i)?(a.preventDefault(),this._focus(j,
351
+ e,!0,a)):!c||!this.c.blurable?a.preventDefault():this._blur()}},_tabInput:function(){var a=this,b=this.s.dt,c=null!==this.c.tabIndex?this.c.tabIndex:b.settings()[0].iTabIndex;if(-1!=c)f('<div><input type="text" tabindex="'+c+'"/></div>').css({position:"absolute",height:1,width:0,overflow:"hidden"}).insertBefore(b.table().node()).children().on("focus",function(c){b.cell(":eq(0)",{page:"current"}).any()&&a._focus(b.cell(":eq(0)","0:visible",{page:"current"}),null,!0,c)})},_updateFixedColumns:function(a){var b=
352
+ this.s.dt,c=b.settings()[0];if(c._oFixedColumns){var d=c.aoColumns.length-c._oFixedColumns.s.iRightColumns;(a<c._oFixedColumns.s.iLeftColumns||a>=d)&&b.fixedColumns().update()}}});n.defaults={blurable:!0,className:"focus",columns:"",editor:null,editorKeys:"navigation-only",editAutoSelect:!0,editOnFocus:!1,focus:null,keys:null,tabIndex:null};n.version="2.3.2";f.fn.dataTable.KeyTable=n;f.fn.DataTable.KeyTable=n;l.Api.register("cell.blur()",function(){return this.iterator("table",function(a){a.keytable&&
353
+ a.keytable.blur()})});l.Api.register("cell().focus()",function(){return this.iterator("cell",function(a,b,c){a.keytable&&a.keytable.focus(b,c)})});l.Api.register("keys.disable()",function(){return this.iterator("table",function(a){a.keytable&&a.keytable.enable(!1)})});l.Api.register("keys.enable()",function(a){return this.iterator("table",function(b){b.keytable&&b.keytable.enable(a===o?!0:a)})});l.ext.selector.cell.push(function(a,b,c){var b=b.focused,a=a.keytable,d=[];if(!a||b===o)return c;for(var e=
354
+ 0,f=c.length;e<f;e++)(!0===b&&a.focused(c[e])||!1===b&&!a.focused(c[e]))&&d.push(c[e]);return d});f(h).on("preInit.dt.dtk",function(a,b){if("dt"===a.namespace){var c=b.oInit.keys,d=l.defaults.keys;if(c||d)d=f.extend({},d,c),!1!==c&&new n(b,d)}});return n});
355
+
356
+
357
+ /*!
358
+ Responsive 2.2.1
359
+ 2014-2017 SpryMedia Ltd - datatables.net/license
360
+ */
361
+ (function(c){"function"===typeof define&&define.amd?define(["jquery","datatables.net"],function(l){return c(l,window,document)}):"object"===typeof exports?module.exports=function(l,k){l||(l=window);if(!k||!k.fn.dataTable)k=require("datatables.net")(l,k).$;return c(k,l,l.document)}:c(jQuery,window,document)})(function(c,l,k,q){function s(b,a,c){var e=a+"-"+c;if(m[e])return m[e];for(var f=[],b=b.cell(a,c).node().childNodes,a=0,c=b.length;a<c;a++)f.push(b[a]);return m[e]=f}function r(b,a,c){var e=a+
362
+ "-"+c;if(m[e]){for(var b=b.cell(a,c).node(),c=m[e][0].parentNode.childNodes,a=[],f=0,g=c.length;f<g;f++)a.push(c[f]);c=0;for(f=a.length;c<f;c++)b.appendChild(a[c]);m[e]=q}}var o=c.fn.dataTable,j=function(b,a){if(!o.versionCheck||!o.versionCheck("1.10.10"))throw"DataTables Responsive requires DataTables 1.10.10 or newer";this.s={dt:new o.Api(b),columns:[],current:[]};this.s.dt.settings()[0].responsive||(a&&"string"===typeof a.details?a.details={type:a.details}:a&&!1===a.details?a.details={type:!1}:
363
+ a&&!0===a.details&&(a.details={type:"inline"}),this.c=c.extend(!0,{},j.defaults,o.defaults.responsive,a),b.responsive=this,this._constructor())};c.extend(j.prototype,{_constructor:function(){var b=this,a=this.s.dt,d=a.settings()[0],e=c(l).width();a.settings()[0]._responsive=this;c(l).on("resize.dtr orientationchange.dtr",o.util.throttle(function(){var a=c(l).width();a!==e&&(b._resize(),e=a)}));d.oApi._fnCallbackReg(d,"aoRowCreatedCallback",function(e){-1!==c.inArray(!1,b.s.current)&&c(">td, >th",
364
+ e).each(function(e){e=a.column.index("toData",e);!1===b.s.current[e]&&c(this).css("display","none")})});a.on("destroy.dtr",function(){a.off(".dtr");c(a.table().body()).off(".dtr");c(l).off("resize.dtr orientationchange.dtr");c.each(b.s.current,function(a,c){!1===c&&b._setColumnVis(a,!0)})});this.c.breakpoints.sort(function(a,b){return a.width<b.width?1:a.width>b.width?-1:0});this._classLogic();this._resizeAuto();d=this.c.details;!1!==d.type&&(b._detailsInit(),a.on("column-visibility.dtr",function(a,
365
+ c,e,d,h){h&&(b._classLogic(),b._resizeAuto(),b._resize())}),a.on("draw.dtr",function(){b._redrawChildren()}),c(a.table().node()).addClass("dtr-"+d.type));a.on("column-reorder.dtr",function(){b._classLogic();b._resizeAuto();b._resize()});a.on("column-sizing.dtr",function(){b._resizeAuto();b._resize()});a.on("preXhr.dtr",function(){var c=[];a.rows().every(function(){this.child.isShown()&&c.push(this.id(true))});a.one("draw.dtr",function(){b._resizeAuto();b._resize();a.rows(c).every(function(){b._detailsDisplay(this,
366
+ false)})})});a.on("init.dtr",function(){b._resizeAuto();b._resize();c.inArray(false,b.s.current)&&a.columns.adjust()});this._resize()},_columnsVisiblity:function(b){var a=this.s.dt,d=this.s.columns,e,f,g=d.map(function(a,b){return{columnIdx:b,priority:a.priority}}).sort(function(a,b){return a.priority!==b.priority?a.priority-b.priority:a.columnIdx-b.columnIdx}),i=c.map(d,function(a){return a.auto&&null===a.minWidth?!1:!0===a.auto?"-":-1!==c.inArray(b,a.includeIn)}),n=0;e=0;for(f=i.length;e<f;e++)!0===
367
+ i[e]&&(n+=d[e].minWidth);e=a.settings()[0].oScroll;e=e.sY||e.sX?e.iBarWidth:0;a=a.table().container().offsetWidth-e-n;e=0;for(f=i.length;e<f;e++)d[e].control&&(a-=d[e].minWidth);n=!1;e=0;for(f=g.length;e<f;e++){var h=g[e].columnIdx;"-"===i[h]&&(!d[h].control&&d[h].minWidth)&&(n||0>a-d[h].minWidth?(n=!0,i[h]=!1):i[h]=!0,a-=d[h].minWidth)}g=!1;e=0;for(f=d.length;e<f;e++)if(!d[e].control&&!d[e].never&&!i[e]){g=!0;break}e=0;for(f=d.length;e<f;e++)d[e].control&&(i[e]=g);-1===c.inArray(!0,i)&&(i[0]=!0);
368
+ return i},_classLogic:function(){var b=this,a=this.c.breakpoints,d=this.s.dt,e=d.columns().eq(0).map(function(a){var b=this.column(a),e=b.header().className,a=d.settings()[0].aoColumns[a].responsivePriority;a===q&&(b=c(b.header()).data("priority"),a=b!==q?1*b:1E4);return{className:e,includeIn:[],auto:!1,control:!1,never:e.match(/\bnever\b/)?!0:!1,priority:a}}),f=function(a,b){var d=e[a].includeIn;-1===c.inArray(b,d)&&d.push(b)},g=function(c,d,h,g){if(h)if("max-"===h){g=b._find(d).width;d=0;for(h=
369
+ a.length;d<h;d++)a[d].width<=g&&f(c,a[d].name)}else if("min-"===h){g=b._find(d).width;d=0;for(h=a.length;d<h;d++)a[d].width>=g&&f(c,a[d].name)}else{if("not-"===h){d=0;for(h=a.length;d<h;d++)-1===a[d].name.indexOf(g)&&f(c,a[d].name)}}else e[c].includeIn.push(d)};e.each(function(b,e){for(var d=b.className.split(" "),f=!1,j=0,l=d.length;j<l;j++){var k=c.trim(d[j]);if("all"===k){f=!0;b.includeIn=c.map(a,function(a){return a.name});return}if("none"===k||b.never){f=!0;return}if("control"===k){f=!0;b.control=
370
+ !0;return}c.each(a,function(a,b){var c=b.name.split("-"),d=k.match(RegExp("(min\\-|max\\-|not\\-)?("+c[0]+")(\\-[_a-zA-Z0-9])?"));d&&(f=!0,d[2]===c[0]&&d[3]==="-"+c[1]?g(e,b.name,d[1],d[2]+d[3]):d[2]===c[0]&&!d[3]&&g(e,b.name,d[1],d[2]))})}f||(b.auto=!0)});this.s.columns=e},_detailsDisplay:function(b,a){var d=this,e=this.s.dt,f=this.c.details;if(f&&!1!==f.type){var g=f.display(b,a,function(){return f.renderer(e,b[0],d._detailsObj(b[0]))});(!0===g||!1===g)&&c(e.table().node()).triggerHandler("responsive-display.dt",
371
+ [e,b,g,a])}},_detailsInit:function(){var b=this,a=this.s.dt,d=this.c.details;"inline"===d.type&&(d.target="td:first-child, th:first-child");a.on("draw.dtr",function(){b._tabIndexes()});b._tabIndexes();c(a.table().body()).on("keyup.dtr","td, th",function(a){a.keyCode===13&&c(this).data("dtr-keyboard")&&c(this).click()});var e=d.target;c(a.table().body()).on("click.dtr mousedown.dtr mouseup.dtr","string"===typeof e?e:"td, th",function(d){if(c(a.table().node()).hasClass("collapsed")&&c.inArray(c(this).closest("tr").get(0),
372
+ a.rows().nodes().toArray())!==-1){if(typeof e==="number"){var g=e<0?a.columns().eq(0).length+e:e;if(a.cell(this).index().column!==g)return}g=a.row(c(this).closest("tr"));d.type==="click"?b._detailsDisplay(g,false):d.type==="mousedown"?c(this).css("outline","none"):d.type==="mouseup"&&c(this).blur().css("outline","")}})},_detailsObj:function(b){var a=this,d=this.s.dt;return c.map(this.s.columns,function(c,f){if(!c.never&&!c.control)return{title:d.settings()[0].aoColumns[f].sTitle,data:d.cell(b,f).render(a.c.orthogonal),
373
+ hidden:d.column(f).visible()&&!a.s.current[f],columnIndex:f,rowIndex:b}})},_find:function(b){for(var a=this.c.breakpoints,c=0,e=a.length;c<e;c++)if(a[c].name===b)return a[c]},_redrawChildren:function(){var b=this,a=this.s.dt;a.rows({page:"current"}).iterator("row",function(c,e){a.row(e);b._detailsDisplay(a.row(e),!0)})},_resize:function(){var b=this,a=this.s.dt,d=c(l).width(),e=this.c.breakpoints,f=e[0].name,g=this.s.columns,i,n=this.s.current.slice();for(i=e.length-1;0<=i;i--)if(d<=e[i].width){f=
374
+ e[i].name;break}var h=this._columnsVisiblity(f);this.s.current=h;e=!1;i=0;for(d=g.length;i<d;i++)if(!1===h[i]&&!g[i].never&&!g[i].control){e=!0;break}c(a.table().node()).toggleClass("collapsed",e);var j=!1,k=0;a.columns().eq(0).each(function(a,c){!0===h[c]&&k++;h[c]!==n[c]&&(j=!0,b._setColumnVis(a,h[c]))});j&&(this._redrawChildren(),c(a.table().node()).trigger("responsive-resize.dt",[a,this.s.current]),0===a.page.info().recordsDisplay&&c("td",a.table().body()).eq(0).attr("colspan",k))},_resizeAuto:function(){var b=
375
+ this.s.dt,a=this.s.columns;if(this.c.auto&&-1!==c.inArray(!0,c.map(a,function(a){return a.auto}))){c.isEmptyObject(m)||c.each(m,function(a){a=a.split("-");r(b,1*a[0],1*a[1])});b.table().node();var d=b.table().node().cloneNode(!1),e=c(b.table().header().cloneNode(!1)).appendTo(d),f=c(b.table().body()).clone(!1,!1).empty().appendTo(d),g=b.columns().header().filter(function(a){return b.column(a).visible()}).to$().clone(!1).css("display","table-cell").css("min-width",0);c(f).append(c(b.rows({page:"current"}).nodes()).clone(!1)).find("th, td").css("display",
376
+ "");if(f=b.table().footer()){var f=c(f.cloneNode(!1)).appendTo(d),i=b.columns().footer().filter(function(a){return b.column(a).visible()}).to$().clone(!1).css("display","table-cell");c("<tr/>").append(i).appendTo(f)}c("<tr/>").append(g).appendTo(e);"inline"===this.c.details.type&&c(d).addClass("dtr-inline collapsed");c(d).find("[name]").removeAttr("name");d=c("<div/>").css({width:1,height:1,overflow:"hidden",clear:"both"}).append(d);d.insertBefore(b.table().node());g.each(function(c){c=b.column.index("fromVisible",
377
+ c);a[c].minWidth=this.offsetWidth||0});d.remove()}},_setColumnVis:function(b,a){var d=this.s.dt,e=a?"":"none";c(d.column(b).header()).css("display",e);c(d.column(b).footer()).css("display",e);d.column(b).nodes().to$().css("display",e);c.isEmptyObject(m)||d.cells(null,b).indexes().each(function(a){r(d,a.row,a.column)})},_tabIndexes:function(){var b=this.s.dt,a=b.cells({page:"current"}).nodes().to$(),d=b.settings()[0],e=this.c.details.target;a.filter("[data-dtr-keyboard]").removeData("[data-dtr-keyboard]");
378
+ a="number"===typeof e?":eq("+e+")":e;"td:first-child, th:first-child"===a&&(a=">td:first-child, >th:first-child");c(a,b.rows({page:"current"}).nodes()).attr("tabIndex",d.iTabIndex).data("dtr-keyboard",1)}});j.breakpoints=[{name:"desktop",width:Infinity},{name:"tablet-l",width:1024},{name:"tablet-p",width:768},{name:"mobile-l",width:480},{name:"mobile-p",width:320}];j.display={childRow:function(b,a,d){if(a){if(c(b.node()).hasClass("parent"))return b.child(d(),"child").show(),!0}else{if(b.child.isShown())return b.child(!1),
379
+ c(b.node()).removeClass("parent"),!1;b.child(d(),"child").show();c(b.node()).addClass("parent");return!0}},childRowImmediate:function(b,a,d){if(!a&&b.child.isShown()||!b.responsive.hasHidden())return b.child(!1),c(b.node()).removeClass("parent"),!1;b.child(d(),"child").show();c(b.node()).addClass("parent");return!0},modal:function(b){return function(a,d,e){if(d)c("div.dtr-modal-content").empty().append(e());else{var f=function(){g.remove();c(k).off("keypress.dtr")},g=c('<div class="dtr-modal"/>').append(c('<div class="dtr-modal-display"/>').append(c('<div class="dtr-modal-content"/>').append(e())).append(c('<div class="dtr-modal-close">&times;</div>').click(function(){f()}))).append(c('<div class="dtr-modal-background"/>').click(function(){f()})).appendTo("body");
380
+ c(k).on("keyup.dtr",function(a){27===a.keyCode&&(a.stopPropagation(),f())})}b&&b.header&&c("div.dtr-modal-content").prepend("<h2>"+b.header(a)+"</h2>")}}};var m={};j.renderer={listHiddenNodes:function(){return function(b,a,d){var e=c('<ul data-dtr-index="'+a+'" class="dtr-details"/>'),f=!1;c.each(d,function(a,d){d.hidden&&(c('<li data-dtr-index="'+d.columnIndex+'" data-dt-row="'+d.rowIndex+'" data-dt-column="'+d.columnIndex+'"><span class="dtr-title">'+d.title+"</span> </li>").append(c('<span class="dtr-data"/>').append(s(b,
381
+ d.rowIndex,d.columnIndex))).appendTo(e),f=!0)});return f?e:!1}},listHidden:function(){return function(b,a,d){return(b=c.map(d,function(a){return a.hidden?'<li data-dtr-index="'+a.columnIndex+'" data-dt-row="'+a.rowIndex+'" data-dt-column="'+a.columnIndex+'"><span class="dtr-title">'+a.title+'</span> <span class="dtr-data">'+a.data+"</span></li>":""}).join(""))?c('<ul data-dtr-index="'+a+'" class="dtr-details"/>').append(b):!1}},tableAll:function(b){b=c.extend({tableClass:""},b);return function(a,
382
+ d,e){a=c.map(e,function(a){return'<tr data-dt-row="'+a.rowIndex+'" data-dt-column="'+a.columnIndex+'"><td>'+a.title+":</td> <td>"+a.data+"</td></tr>"}).join("");return c('<table class="'+b.tableClass+' dtr-details" width="100%"/>').append(a)}}};j.defaults={breakpoints:j.breakpoints,auto:!0,details:{display:j.display.childRow,renderer:j.renderer.listHidden(),target:0,type:"inline"},orthogonal:"display"};var p=c.fn.dataTable.Api;p.register("responsive()",function(){return this});p.register("responsive.index()",
383
+ function(b){b=c(b);return{column:b.data("dtr-index"),row:b.parent().data("dtr-index")}});p.register("responsive.rebuild()",function(){return this.iterator("table",function(b){b._responsive&&b._responsive._classLogic()})});p.register("responsive.recalc()",function(){return this.iterator("table",function(b){b._responsive&&(b._responsive._resizeAuto(),b._responsive._resize())})});p.register("responsive.hasHidden()",function(){var b=this.context[0];return b._responsive?-1!==c.inArray(!1,b._responsive.s.current):
384
+ !1});p.registerPlural("columns().responsiveHidden()","column().responsiveHidden()",function(){return this.iterator("column",function(b,a){return b._responsive?b._responsive.s.current[a]:!1},1)});j.version="2.2.1";c.fn.dataTable.Responsive=j;c.fn.DataTable.Responsive=j;c(k).on("preInit.dt.dtr",function(b,a){if("dt"===b.namespace&&(c(a.nTable).hasClass("responsive")||c(a.nTable).hasClass("dt-responsive")||a.oInit.responsive||o.defaults.responsive)){var d=a.oInit.responsive;!1!==d&&new j(a,c.isPlainObject(d)?
385
+ d:{})}});return j});
386
+
387
+
388
+ /*!
389
+ RowReorder 1.2.3
390
+ 2015-2017 SpryMedia Ltd - datatables.net/license
391
+ */
392
+ (function(d){"function"===typeof define&&define.amd?define(["jquery","datatables.net"],function(f){return d(f,window,document)}):"object"===typeof exports?module.exports=function(f,g){f||(f=window);if(!g||!g.fn.dataTable)g=require("datatables.net")(f,g).$;return d(g,f,f.document)}:d(jQuery,window,document)})(function(d,f,g,m){var h=d.fn.dataTable,k=function(c,b){if(!h.versionCheck||!h.versionCheck("1.10.8"))throw"DataTables RowReorder requires DataTables 1.10.8 or newer";this.c=d.extend(!0,{},h.defaults.rowReorder,
393
+ k.defaults,b);this.s={bodyTop:null,dt:new h.Api(c),getDataFn:h.ext.oApi._fnGetObjectDataFn(this.c.dataSrc),middles:null,scroll:{},scrollInterval:null,setDataFn:h.ext.oApi._fnSetObjectDataFn(this.c.dataSrc),start:{top:0,left:0,offsetTop:0,offsetLeft:0,nodes:[]},windowHeight:0,documentOuterHeight:0,domCloneOuterHeight:0};this.dom={clone:null,dtScroll:d("div.dataTables_scrollBody",this.s.dt.table().container())};var a=this.s.dt.settings()[0],e=a.rowreorder;if(e)return e;a.rowreorder=this;this._constructor()};
394
+ d.extend(k.prototype,{_constructor:function(){var c=this,b=this.s.dt,a=d(b.table().node());"static"===a.css("position")&&a.css("position","relative");d(b.table().container()).on("mousedown.rowReorder touchstart.rowReorder",this.c.selector,function(a){if(c.c.enable){var i=d(this).closest("tr"),j=b.row(i);if(j.any())return c._emitEvent("pre-row-reorder",{node:j.node(),index:j.index()}),c._mouseDown(a,i),!1}});b.on("destroy.rowReorder",function(){d(b.table().container()).off(".rowReorder");b.off(".rowReorder")})},
395
+ _cachePositions:function(){var c=this.s.dt,b=d(c.table().node()).find("thead").outerHeight(),a=d.unique(c.rows({page:"current"}).nodes().toArray()),e=d.map(a,function(a){return d(a).position().top-b}),a=d.map(e,function(a,b){return e.length<b-1?(a+e[b+1])/2:(a+a+d(c.row(":last-child").node()).outerHeight())/2});this.s.middles=a;this.s.bodyTop=d(c.table().body()).offset().top;this.s.windowHeight=d(f).height();this.s.documentOuterHeight=d(g).outerHeight()},_clone:function(c){var b=d(this.s.dt.table().node().cloneNode(!1)).addClass("dt-rowReorder-float").append("<tbody/>").append(c.clone(!1)),
396
+ a=c.outerWidth(),e=c.outerHeight(),i=c.children().map(function(){return d(this).width()});b.width(a).height(e).find("tr").children().each(function(a){this.style.width=i[a]+"px"});b.appendTo("body");this.dom.clone=b;this.s.domCloneOuterHeight=b.outerHeight()},_clonePosition:function(c){var b=this.s.start,a=this._eventToPage(c,"Y")-b.top,c=this._eventToPage(c,"X")-b.left,e=this.c.snapX,a=a+b.offsetTop,b=!0===e?b.offsetLeft:"number"===typeof e?b.offsetLeft+e:c+b.offsetLeft;0>a?a=0:a+this.s.domCloneOuterHeight>
397
+ this.s.documentOuterHeight&&(a=this.s.documentOuterHeight-this.s.domCloneOuterHeight);this.dom.clone.css({top:a,left:b})},_emitEvent:function(c,b){this.s.dt.iterator("table",function(a){d(a.nTable).triggerHandler(c+".dt",b)})},_eventToPage:function(c,b){return-1!==c.type.indexOf("touch")?c.originalEvent.touches[0]["page"+b]:c["page"+b]},_mouseDown:function(c,b){var a=this,e=this.s.dt,i=this.s.start,j=b.offset();i.top=this._eventToPage(c,"Y");i.left=this._eventToPage(c,"X");i.offsetTop=j.top;i.offsetLeft=
398
+ j.left;i.nodes=d.unique(e.rows({page:"current"}).nodes().toArray());this._cachePositions();this._clone(b);this._clonePosition(c);this.dom.target=b;b.addClass("dt-rowReorder-moving");d(g).on("mouseup.rowReorder touchend.rowReorder",function(b){a._mouseUp(b)}).on("mousemove.rowReorder touchmove.rowReorder",function(b){a._mouseMove(b)});d(f).width()===d(g).width()&&d(g.body).addClass("dt-rowReorder-noOverflow");e=this.dom.dtScroll;this.s.scroll={windowHeight:d(f).height(),windowWidth:d(f).width(),dtTop:e.length?
399
+ e.offset().top:null,dtLeft:e.length?e.offset().left:null,dtHeight:e.length?e.outerHeight():null,dtWidth:e.length?e.outerWidth():null}},_mouseMove:function(c){this._clonePosition(c);for(var b=this._eventToPage(c,"Y")-this.s.bodyTop,a=this.s.middles,e=null,i=this.s.dt,j=i.table().body(),g=0,f=a.length;g<f;g++)if(b<a[g]){e=g;break}null===e&&(e=a.length);if(null===this.s.lastInsert||this.s.lastInsert!==e)0===e?this.dom.target.prependTo(j):(b=d.unique(i.rows({page:"current"}).nodes().toArray()),e>this.s.lastInsert?
400
+ this.dom.target.insertAfter(b[e-1]):this.dom.target.insertBefore(b[e])),this._cachePositions(),this.s.lastInsert=e;this._shiftScroll(c)},_mouseUp:function(){var c=this,b=this.s.dt,a,e,i=this.c.dataSrc;this.dom.clone.remove();this.dom.clone=null;this.dom.target.removeClass("dt-rowReorder-moving");d(g).off(".rowReorder");d(g.body).removeClass("dt-rowReorder-noOverflow");clearInterval(this.s.scrollInterval);this.s.scrollInterval=null;var j=this.s.start.nodes,f=d.unique(b.rows({page:"current"}).nodes().toArray()),
401
+ k={},h=[],l=[],n=this.s.getDataFn,m=this.s.setDataFn;a=0;for(e=j.length;a<e;a++)if(j[a]!==f[a]){var o=b.row(f[a]).id(),s=b.row(f[a]).data(),p=b.row(j[a]).data();o&&(k[o]=n(p));h.push({node:f[a],oldData:n(s),newData:n(p),newPosition:a,oldPosition:d.inArray(f[a],j)});l.push(f[a])}var q=[h,{dataSrc:i,nodes:l,values:k,triggerRow:b.row(this.dom.target)}];this._emitEvent("row-reorder",q);var r=function(){if(c.c.update){a=0;for(e=h.length;a<e;a++){var d=b.row(h[a].node).data();m(d,h[a].newData);b.columns().every(function(){this.dataSrc()===
402
+ i&&b.cell(h[a].node,this.index()).invalidate("data")})}c._emitEvent("row-reordered",q);b.draw(!1)}};this.c.editor?(this.c.enable=!1,this.c.editor.edit(l,!1,d.extend({submit:"changed"},this.c.formOptions)).multiSet(i,k).one("submitUnsuccessful.rowReorder",function(){b.draw(!1)}).one("submitSuccess.rowReorder",function(){r()}).one("submitComplete",function(){c.c.enable=!0;c.c.editor.off(".rowReorder")}).submit()):r()},_shiftScroll:function(c){var b=this,a=this.s.scroll,e=!1,d=c.pageY-g.body.scrollTop,
403
+ f,h;65>d?f=-5:d>a.windowHeight-65&&(f=5);null!==a.dtTop&&c.pageY<a.dtTop+65?h=-5:null!==a.dtTop&&c.pageY>a.dtTop+a.dtHeight-65&&(h=5);f||h?(a.windowVert=f,a.dtVert=h,e=!0):this.s.scrollInterval&&(clearInterval(this.s.scrollInterval),this.s.scrollInterval=null);!this.s.scrollInterval&&e&&(this.s.scrollInterval=setInterval(function(){if(a.windowVert)g.body.scrollTop=g.body.scrollTop+a.windowVert;if(a.dtVert){var c=b.dom.dtScroll[0];if(a.dtVert)c.scrollTop=c.scrollTop+a.dtVert}},20))}});k.defaults={dataSrc:0,
404
+ editor:null,enable:!0,formOptions:{},selector:"td:first-child",snapX:!1,update:!0};var l=d.fn.dataTable.Api;l.register("rowReorder()",function(){return this});l.register("rowReorder.enable()",function(c){c===m&&(c=!0);return this.iterator("table",function(b){b.rowreorder&&(b.rowreorder.c.enable=c)})});l.register("rowReorder.disable()",function(){return this.iterator("table",function(c){c.rowreorder&&(c.rowreorder.c.enable=!1)})});k.version="1.2.3";d.fn.dataTable.RowReorder=k;d.fn.DataTable.RowReorder=
405
+ k;d(g).on("init.dt.dtr",function(c,b){if("dt"===c.namespace){var a=b.oInit.rowReorder,e=h.defaults.rowReorder;if(a||e)e=d.extend({},a,e),!1!==a&&new k(b,e)}});return k});
406
+
407
+
408
+ /*!
409
+ Scroller 1.4.4
410
+ ©2011-2018 SpryMedia Ltd - datatables.net/license
411
+ */
412
+ (function(e){"function"===typeof define&&define.amd?define(["jquery","datatables.net"],function(g){return e(g,window,document)}):"object"===typeof exports?module.exports=function(g,j){g||(g=window);if(!j||!j.fn.dataTable)j=require("datatables.net")(g,j).$;return e(j,g,g.document)}:e(jQuery,window,document)})(function(e,g,j,l){var m=e.fn.dataTable,h=function(a,b){this instanceof h?(b===l&&(b={}),this.s={dt:e.fn.dataTable.Api(a).settings()[0],tableTop:0,tableBottom:0,redrawTop:0,redrawBottom:0,autoHeight:!0,
413
+ viewportRows:0,stateTO:null,drawTO:null,heights:{jump:null,page:null,virtual:null,scroll:null,row:null,viewport:null},topRowFloat:0,scrollDrawDiff:null,loaderVisible:!1,forceReposition:!1},this.s=e.extend(this.s,h.oDefaults,b),this.s.heights.row=this.s.rowHeight,this.dom={force:j.createElement("div"),scroller:null,table:null,loader:null},this.s.dt.oScroller||(this.s.dt.oScroller=this,this._fnConstruct())):alert("Scroller warning: Scroller must be initialised with the 'new' keyword.")};e.extend(h.prototype,
414
+ {fnRowToPixels:function(a,b,c){a=c?this._domain("virtualToPhysical",a*this.s.heights.row):this.s.baseScrollTop+(a-this.s.baseRowTop)*this.s.heights.row;return b||b===l?parseInt(a,10):a},fnPixelsToRow:function(a,b,c){var d=a-this.s.baseScrollTop,a=c?this._domain("physicalToVirtual",a)/this.s.heights.row:d/this.s.heights.row+this.s.baseRowTop;return b||b===l?parseInt(a,10):a},fnScrollToRow:function(a,b){var c=this,d=!1,f=this.fnRowToPixels(a),i=a-(this.s.displayBuffer-1)/2*this.s.viewportRows;0>i&&
415
+ (i=0);if((f>this.s.redrawBottom||f<this.s.redrawTop)&&this.s.dt._iDisplayStart!==i)d=!0,f=this.fnRowToPixels(a,!1,!0),this.s.redrawTop<f&&f<this.s.redrawBottom&&(this.s.forceReposition=!0,b=!1);"undefined"==typeof b||b?(this.s.ani=d,e(this.dom.scroller).animate({scrollTop:f},function(){setTimeout(function(){c.s.ani=!1},25)})):e(this.dom.scroller).scrollTop(f)},fnMeasure:function(a){this.s.autoHeight&&this._fnCalcRowHeight();var b=this.s.heights;b.row&&(b.viewport=e.contains(j,this.dom.scroller)?e(this.dom.scroller).height():
416
+ this._parseHeight(e(this.dom.scroller).css("height")),b.viewport||(b.viewport=this._parseHeight(e(this.dom.scroller).css("max-height"))),this.s.viewportRows=parseInt(b.viewport/b.row,10)+1,this.s.dt._iDisplayLength=this.s.viewportRows*this.s.displayBuffer);(a===l||a)&&this.s.dt.oInstance.fnDraw(!1)},fnPageInfo:function(){var a=this.dom.scroller.scrollTop,b=this.s.dt.fnRecordsDisplay(),c=Math.ceil(this.fnPixelsToRow(a+this.s.heights.viewport,!1,this.s.ani));return{start:Math.floor(this.fnPixelsToRow(a,
417
+ !1,this.s.ani)),end:b<c?b-1:c-1}},_fnConstruct:function(){var a=this;if(this.s.dt.oFeatures.bPaginate){this.dom.force.style.position="relative";this.dom.force.style.top="0px";this.dom.force.style.left="0px";this.dom.force.style.width="1px";this.dom.scroller=e("div."+this.s.dt.oClasses.sScrollBody,this.s.dt.nTableWrapper)[0];this.dom.scroller.appendChild(this.dom.force);this.dom.scroller.style.position="relative";this.dom.table=e(">table",this.dom.scroller)[0];this.dom.table.style.position="absolute";
418
+ this.dom.table.style.top="0px";this.dom.table.style.left="0px";e(this.s.dt.nTableWrapper).addClass("DTS");this.s.loadingIndicator&&(this.dom.loader=e('<div class="dataTables_processing DTS_Loading">'+this.s.dt.oLanguage.sLoadingRecords+"</div>").css("display","none"),e(this.dom.scroller.parentNode).css("position","relative").append(this.dom.loader));this.s.heights.row&&"auto"!=this.s.heights.row&&(this.s.autoHeight=!1);this.fnMeasure(!1);this.s.ingnoreScroll=!0;this.s.stateSaveThrottle=this.s.dt.oApi._fnThrottle(function(){a.s.dt.oApi._fnSaveState(a.s.dt)},
419
+ 500);e(this.dom.scroller).on("scroll.DTS",function(){a._fnScroll.call(a)});e(this.dom.scroller).on("touchstart.DTS",function(){a._fnScroll.call(a)});this.s.dt.aoDrawCallback.push({fn:function(){a.s.dt.bInitialised&&a._fnDrawCallback.call(a)},sName:"Scroller"});e(g).on("resize.DTS",function(){a.fnMeasure(false);a._fnInfo()});var b=!0;this.s.dt.oApi._fnCallbackReg(this.s.dt,"aoStateSaveParams",function(c,d){if(b&&a.s.dt.oLoadedState){d.iScroller=a.s.dt.oLoadedState.iScroller;d.iScrollerTopRow=a.s.dt.oLoadedState.iScrollerTopRow;
420
+ b=false}else{d.iScroller=a.dom.scroller.scrollTop;d.iScrollerTopRow=a.s.topRowFloat}},"Scroller_State");this.s.dt.oLoadedState&&(this.s.topRowFloat=this.s.dt.oLoadedState.iScrollerTopRow||0);e(this.s.dt.nTable).one("init.dt",function(){a.fnMeasure()});this.s.dt.aoDestroyCallback.push({sName:"Scroller",fn:function(){e(g).off("resize.DTS");e(a.dom.scroller).off("touchstart.DTS scroll.DTS");e(a.s.dt.nTableWrapper).removeClass("DTS");e("div.DTS_Loading",a.dom.scroller.parentNode).remove();e(a.s.dt.nTable).off("init.dt");
421
+ a.dom.table.style.position="";a.dom.table.style.top="";a.dom.table.style.left=""}})}else this.s.dt.oApi._fnLog(this.s.dt,0,"Pagination must be enabled for Scroller")},_fnScroll:function(){var a=this,b=this.s.heights,c=this.dom.scroller.scrollTop,d;if(!this.s.skip&&!this.s.ingnoreScroll)if(this.s.dt.bFiltered||this.s.dt.bSorted)this.s.lastScrollTop=0;else{this._fnInfo();clearTimeout(this.s.stateTO);this.s.stateTO=setTimeout(function(){a.s.dt.oApi._fnSaveState(a.s.dt)},250);if(this.s.forceReposition||
422
+ c<this.s.redrawTop||c>this.s.redrawBottom){var f=Math.ceil((this.s.displayBuffer-1)/2*this.s.viewportRows);Math.abs(c-this.s.lastScrollTop)>b.viewport||this.s.ani||this.s.forceReposition?(d=parseInt(this._domain("physicalToVirtual",c)/b.row,10)-f,this.s.topRowFloat=this._domain("physicalToVirtual",c)/b.row):(d=this.fnPixelsToRow(c)-f,this.s.topRowFloat=this.fnPixelsToRow(c,!1));this.s.forceReposition=!1;0>=d?d=0:d+this.s.dt._iDisplayLength>this.s.dt.fnRecordsDisplay()?(d=this.s.dt.fnRecordsDisplay()-
423
+ this.s.dt._iDisplayLength,0>d&&(d=0)):0!==d%2&&d++;if(d!=this.s.dt._iDisplayStart&&(this.s.tableTop=e(this.s.dt.nTable).offset().top,this.s.tableBottom=e(this.s.dt.nTable).height()+this.s.tableTop,b=function(){if(a.s.scrollDrawReq===null)a.s.scrollDrawReq=c;a.s.dt._iDisplayStart=d;a.s.dt.oApi._fnDraw(a.s.dt)},this.s.dt.oFeatures.bServerSide?(clearTimeout(this.s.drawTO),this.s.drawTO=setTimeout(b,this.s.serverWait)):b(),this.dom.loader&&!this.s.loaderVisible))this.dom.loader.css("display","block"),
424
+ this.s.loaderVisible=!0}else this.s.topRowFloat=this._domain("physicalToVirtual",c)/b.row;this.s.lastScrollTop=c;this.s.stateSaveThrottle()}},_domain:function(a,b){var c=this.s.heights,d;if(c.virtual===c.scroll)return b;var e=(c.scroll-c.viewport)/2,i=(c.virtual-c.viewport)/2;d=i/(e*e);if("virtualToPhysical"===a){if(b<i)return Math.pow(b/d,0.5);b=2*i-b;return 0>b?c.scroll:2*e-Math.pow(b/d,0.5)}if("physicalToVirtual"===a){if(b<e)return b*b*d;b=2*e-b;return 0>b?c.virtual:2*i-b*b*d}},_parseHeight:function(a){var b,
425
+ c=/^([+-]?(?:\d+(?:\.\d+)?|\.\d+))(px|em|rem|vh)$/.exec(a);if(null===c)return 0;a=parseFloat(c[1]);c=c[2];"px"===c?b=a:"vh"===c?b=a/100*e(g).height():"rem"===c?b=a*parseFloat(e(":root").css("font-size")):"em"===c&&(b=a*parseFloat(e("body").css("font-size")));return b?b:0},_fnDrawCallback:function(){var a=this,b=this.s.heights,c=this.dom.scroller.scrollTop,d=e(this.s.dt.nTable).height(),f=this.s.dt._iDisplayStart,i=this.s.dt._iDisplayLength,h=this.s.dt.fnRecordsDisplay();this.s.skip=!0;this._fnScrollForce();
426
+ c=0===f?this.s.topRowFloat*b.row:f+i>=h?b.scroll-(h-this.s.topRowFloat)*b.row:this._domain("virtualToPhysical",this.s.topRowFloat*b.row);this.dom.scroller.scrollTop=c;this.s.baseScrollTop=c;this.s.baseRowTop=this.s.topRowFloat;var g=c-(this.s.topRowFloat-f)*b.row;0===f?g=0:f+i>=h&&(g=b.scroll-d);this.dom.table.style.top=g+"px";this.s.tableTop=g;this.s.tableBottom=d+this.s.tableTop;d=(c-this.s.tableTop)*this.s.boundaryScale;this.s.redrawTop=c-d;this.s.redrawBottom=c+d>b.scroll-b.viewport-b.row?b.scroll-
427
+ b.viewport-b.row:c+d;this.s.skip=!1;this.s.dt.oFeatures.bStateSave&&null!==this.s.dt.oLoadedState&&"undefined"!=typeof this.s.dt.oLoadedState.iScroller?((c=(this.s.dt.sAjaxSource||a.s.dt.ajax)&&!this.s.dt.oFeatures.bServerSide?!0:!1)&&2==this.s.dt.iDraw||!c&&1==this.s.dt.iDraw)&&setTimeout(function(){e(a.dom.scroller).scrollTop(a.s.dt.oLoadedState.iScroller);a.s.redrawTop=a.s.dt.oLoadedState.iScroller-b.viewport/2;setTimeout(function(){a.s.ingnoreScroll=!1},0)},0):a.s.ingnoreScroll=!1;this.s.dt.oFeatures.bInfo&&
428
+ setTimeout(function(){a._fnInfo.call(a)},0);this.dom.loader&&this.s.loaderVisible&&(this.dom.loader.css("display","none"),this.s.loaderVisible=!1)},_fnScrollForce:function(){var a=this.s.heights;a.virtual=a.row*this.s.dt.fnRecordsDisplay();a.scroll=a.virtual;1E6<a.scroll&&(a.scroll=1E6);this.dom.force.style.height=a.scroll>this.s.heights.row?a.scroll+"px":this.s.heights.row+"px"},_fnCalcRowHeight:function(){var a=this.s.dt,b=a.nTable,c=b.cloneNode(!1),d=e("<tbody/>").appendTo(c),f=e('<div class="'+
429
+ a.oClasses.sWrapper+' DTS"><div class="'+a.oClasses.sScrollWrapper+'"><div class="'+a.oClasses.sScrollBody+'"></div></div></div>');for(e("tbody tr:lt(4)",b).clone().appendTo(d);3>e("tr",d).length;)d.append("<tr><td>&nbsp;</td></tr>");e("div."+a.oClasses.sScrollBody,f).append(c);a=this.s.dt.nHolding||b.parentNode;e(a).is(":visible")||(a="body");f.appendTo(a);this.s.heights.row=e("tr",d).eq(1).outerHeight();f.remove()},_fnInfo:function(){if(this.s.dt.oFeatures.bInfo){var a=this.s.dt,b=a.oLanguage,c=
430
+ this.dom.scroller.scrollTop,d=Math.floor(this.fnPixelsToRow(c,!1,this.s.ani)+1),f=a.fnRecordsTotal(),i=a.fnRecordsDisplay(),c=Math.ceil(this.fnPixelsToRow(c+this.s.heights.viewport,!1,this.s.ani)),c=i<c?i:c,g=a.fnFormatNumber(d),h=a.fnFormatNumber(c),j=a.fnFormatNumber(f),k=a.fnFormatNumber(i),g=0===a.fnRecordsDisplay()&&a.fnRecordsDisplay()==a.fnRecordsTotal()?b.sInfoEmpty+b.sInfoPostFix:0===a.fnRecordsDisplay()?b.sInfoEmpty+" "+b.sInfoFiltered.replace("_MAX_",j)+b.sInfoPostFix:a.fnRecordsDisplay()==
431
+ a.fnRecordsTotal()?b.sInfo.replace("_START_",g).replace("_END_",h).replace("_MAX_",j).replace("_TOTAL_",k)+b.sInfoPostFix:b.sInfo.replace("_START_",g).replace("_END_",h).replace("_MAX_",j).replace("_TOTAL_",k)+" "+b.sInfoFiltered.replace("_MAX_",a.fnFormatNumber(a.fnRecordsTotal()))+b.sInfoPostFix;(b=b.fnInfoCallback)&&(g=b.call(a.oInstance,a,d,c,f,i,g));d=a.aanFeatures.i;if("undefined"!=typeof d){f=0;for(i=d.length;f<i;f++)e(d[f]).html(g)}e(a.nTable).triggerHandler("info.dt")}}});h.defaults={trace:!1,
432
+ rowHeight:"auto",serverWait:200,displayBuffer:9,boundaryScale:0.5,loadingIndicator:!1};h.oDefaults=h.defaults;h.version="1.4.4";"function"==typeof e.fn.dataTable&&"function"==typeof e.fn.dataTableExt.fnVersionCheck&&e.fn.dataTableExt.fnVersionCheck("1.10.0")?e.fn.dataTableExt.aoFeatures.push({fnInit:function(a){var b=a.oInit;new h(a,b.scroller||b.oScroller||{})},cFeature:"S",sFeature:"Scroller"}):alert("Warning: Scroller requires DataTables 1.10.0 or greater - www.datatables.net/download");e(j).on("preInit.dt.dtscroller",
433
+ function(a,b){if("dt"===a.namespace){var c=b.oInit.scroller,d=m.defaults.scroller;if(c||d)d=e.extend({},c,d),!1!==c&&new h(b,d)}});e.fn.dataTable.Scroller=h;e.fn.DataTable.Scroller=h;var k=e.fn.dataTable.Api;k.register("scroller()",function(){return this});k.register("scroller().rowToPixels()",function(a,b,c){var d=this.context;if(d.length&&d[0].oScroller)return d[0].oScroller.fnRowToPixels(a,b,c)});k.register("scroller().pixelsToRow()",function(a,b,c){var d=this.context;if(d.length&&d[0].oScroller)return d[0].oScroller.fnPixelsToRow(a,
434
+ b,c)});k.register("scroller().scrollToRow()",function(a,b){this.iterator("table",function(c){c.oScroller&&c.oScroller.fnScrollToRow(a,b)});return this});k.register("row().scrollTo()",function(a){var b=this;this.iterator("row",function(c,d){if(c.oScroller){var e=b.rows({order:"applied",search:"applied"}).indexes().indexOf(d);c.oScroller.fnScrollToRow(e,a)}});return this});k.register("scroller.measure()",function(a){this.iterator("table",function(b){b.oScroller&&b.oScroller.fnMeasure(a)});return this});
435
+ k.register("scroller.page()",function(){var a=this.context;if(a.length&&a[0].oScroller)return a[0].oScroller.fnPageInfo()});return h});
436
+
437
+
438
+ /*!
439
+ Select for DataTables 1.2.5
440
+ 2015-2018 SpryMedia Ltd - datatables.net/license/mit
441
+ */
442
+ (function(e){"function"===typeof define&&define.amd?define(["jquery","datatables.net"],function(j){return e(j,window,document)}):"object"===typeof exports?module.exports=function(j,m){j||(j=window);if(!m||!m.fn.dataTable)m=require("datatables.net")(j,m).$;return e(m,j,j.document)}:e(jQuery,window,document)})(function(e,j,m,h){function v(a,c,b){var d;d=function(b,c){if(b>c)var d=c,c=b,b=d;var f=!1;return a.columns(":visible").indexes().filter(function(a){a===b&&(f=!0);return a===c?(f=!1,!0):f})};var f=
443
+ function(b,c){var d=a.rows({search:"applied"}).indexes();if(d.indexOf(b)>d.indexOf(c))var f=c,c=b,b=f;var e=!1;return d.filter(function(a){a===b&&(e=!0);return a===c?(e=!1,!0):e})};!a.cells({selected:!0}).any()&&!b?(d=d(0,c.column),b=f(0,c.row)):(d=d(b.column,c.column),b=f(b.row,c.row));b=a.cells(b,d).flatten();a.cells(c,{selected:!0}).any()?a.cells(b).deselect():a.cells(b).select()}function r(a){var c=a.settings()[0]._select.selector;e(a.table().c