View | Details | Raw Unified | Return to bug 27467
Collapse All | Expand All

(-)a/koha-tmpl/intranet-tmpl/lib/jquery/plugins/dataTables.keepConditions.js (-1 / +1584 lines)
Line 0 Link Here
0
- 
1
/**
2
 * @summary     KeepConditions
3
 * @updated     11/27/15
4
 * @description Store the status of the DataTable within the URL, making
5
 *              sharing the exact page/length/etc via copy/paste possible
6
 * @version     1.2.0
7
 * @file        dataTables.keepConditions.js
8
 * @author      Justin Hyland (http://www.justinhyland.com)
9
 * @contact     j@linux.com
10
 * @copyright   Copyright 2015 Justin Hyland
11
 * @url         https://github.com/jhyland87/DataTables-Keep-Conditions
12
 *
13
 * License      MIT - http://datatables.net/license/mit
14
 *
15
 * Store the DataTable conditions within the URL hash every time a condition is changed,
16
 * such as the page, length, search or a column order, making it possible to copy/paste
17
 * the URL. Once said URL is loaded, the conditions will be retrieved from the URL hash
18
 * and implemented to the table on dt.init
19
 *
20
 * KeepConditions is compatable with the following settings/extensions/plugins:
21
 *      Pagination          (name: page;     key: p)
22
 *      Page Length         (name: length;   key: l)
23
 *      Table Searching     (name: search;   key: f)
24
 *      Column Sorting      (name: order;    key: o)
25
 *      Scroller Extension  (name: scroller; key: s)
26
 *          http://datatables.net/extensions/scroller/
27
 *      Column Visibility   (name: colvis;   key: v)
28
 *          http://datatables.net/reference/button/colvis/
29
 *      Column Reorder      (name: colorder; key: c)
30
 *          http://datatables.net/extensions/colreorder/
31
 *
32
 * @example
33
 *    // Basic Initialization (All conditions by default)
34
 *    $('#example').DataTable({
35
 *        keepConditions: true
36
 *    });
37
 *
38
 * @example
39
 *    // Basic Initialization (Specifically specifying enabled conditions, individually)
40
 *    $('#example').DataTable({
41
 *        keepConditions: ['order','page','length','search','colvis','colorder','scroller']
42
 *    });
43
 *
44
 * @example
45
 *    // Same as above, only quicker (Using condition keys in string, instead of names)
46
 *    $('#example').DataTable({
47
 *        keepConditions: 'oplfvcs'
48
 *    });
49
 *
50
 * @example
51
 *    // Basic Initialization with "Copy Conditions" button
52
 *    $('#example').DataTable({
53
 *        keepConditions: true,
54
 *        buttons: [
55
 *           'copyConditions'
56
 *        ]
57
 *    });
58
 *
59
 * @example
60
 *    // Initialization with plugins
61
 *    $('#example').DataTable({
62
 *        ajax:           "dataSrc.txt",
63
 *        deferRender:    true,
64
 *        scrollY:        200,
65
 *        scrollCollapse: true,
66
 *        scroller:       true,
67
 *        keepConditions: {
68
 *          conditions: ['order','length','search','scroller']
69
 *        }
70
 *    });
71
 *
72
 * @example
73
 *    // Same as above, but don't attach the auto-update to the events associated to
74
 *    // each condition (since it can also be ran manually via the API methods)
75
 *    $('#example').DataTable({
76
 *        ajax:           "dataSrc.txt",
77
 *        deferRender:    true,
78
 *        scrollY:        200,
79
 *        scrollCollapse: true,
80
 *        scroller:       true,
81
 *        keepConditions: {
82
 *          conditions: 'olfs',
83
 *          attachEvents: false
84
 *        }
85
 *    });
86
 */
87
88
"use strict";
89
90
var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
91
92
function _typeof(obj) { return obj && typeof Symbol !== "undefined" && obj.constructor === Symbol ? "symbol" : typeof obj; }
93
94
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
95
96
var KeepConditions = (function () {
97
    /**
98
     * KeepConditions Constructor
99
     *
100
     * This can be initiated automatically when the keepConditions setting is set in
101
     * the DT initiation settings, or by manually creating a new KeepConditions
102
     * instance via the 'new' keyword. When manually executing new KeepConditions(),
103
     * the user can pass either the DataTables instance, an API instance, or a CSS
104
     * selector for the DataTables instance, the DataTables settings and API are
105
     * extracted from any of the above.
106
     *
107
     * @param   {object}    dtSettings          DataTable settings object, Required to bind KC instance to
108
     *                                          specific DT instance
109
     * @var     {object}    _dtApi              DataTables API Instance
110
     * @var     {object}    _dtSettings         DT Settings
111
     * @var     {object}    _dtDefaults         DataTables default settings
112
     * @var     {array}     _enabledConditions  List of enabled conditions (As in conditions being kept via
113
     *                                          KeepConditions)
114
     */
115
116
    function KeepConditions(dtSettings) {
117
        _classCallCheck(this, KeepConditions);
118
119
        // Check that we were initiated on an actual DataTable (Either by selector,
120
        // a DT instance, or an API instance of a DT)
121
        if (!$.fn.DataTable.isDataTable(dtSettings) && !dtSettings instanceof $.fn.dataTable.Api) {
122
            throw new Error('Failed to initialize KeepConditions plugin on non-datatable object');
123
        }
124
125
        /**
126
         * Retrieve the DataTables API Instance
127
         */
128
        if (dtSettings instanceof $.fn.dataTable.Api) this._dtApi = dtSettings;else this._dtApi = new $.fn.dataTable.Api(dtSettings);
129
130
        /**
131
         * In case this was initiated via something like a CSS selector, reset the settings
132
         * via the API we know is legit
133
         */
134
        dtSettings = this._dtApi.settings()[0];
135
136
        /**
137
         * DataTables settings object for this DT instance
138
         */
139
        this._dtSettings = dtSettings;
140
141
        /**
142
         * Unique table ID of this DT Instance
143
         */
144
        this._tableId = $(this._dtApi.table().node()).attr('id');
145
146
        /**
147
         * DataTables default settings
148
         */
149
        this._dtDefaults = $.fn.dataTable.defaults;
150
151
        /**
152
         * Map of the condition keys to the condition names
153
         */
154
        this._keysToCons = this._keyMap();
155
156
        /**
157
         * Boolean value to determine if the table should be redrawn whenever
158
         * _drawTable( ) is called, should be set to true if any changes are made
159
         * to the table, and the table wasn't redrawn
160
         */
161
        this._shouldDraw = false;
162
163
        /**
164
         * List of enabled conditions, populated when DataTables is initiated
165
         */
166
        this._enabledConditions = [];
167
168
        /**
169
         * Just the namespace to attach/detach events from for DT events. This is added to the
170
         * DT Event namespace, so when we attach/detach functions from the 'draw.dt' event,
171
         * it's then 'draw.dt.keepConditions' (If defaulted)
172
         */
173
        this._eventNamespace = 'keepConditions';
174
175
        /**
176
         * Add this object to the DataTables setting object, so each table can have its own
177
         * unique KeepConditions object, this is what makes it possible to have multiple
178
         * tables using the plugin, on the same page
179
         */
180
        dtSettings.oKeepConditions = this;
181
182
        /**
183
         * Initiate the main KeepConditions plugin functionality, such as parsing the initial
184
         * URL hash value and implementing the results in the table, attaching the enabled
185
         * conditions to be managed to the associated Datatables events, etc etc.
186
         */
187
        this._init();
188
    }
189
190
    // -----------------------------------------------------------
191
192
    /**
193
     * (Hash) Query String
194
     *
195
     * Parse the url query-like string value of the URL hash. EG: #var1=val1&var2=val2
196
     * will result in {var1: 'val1', var2: 'val2'};
197
     *
198
     * @access  public
199
     * @return  object
200
     */
201
202
    _createClass(KeepConditions, [{
203
        key: '_init',
204
205
        // -----------------------------------------------------------
206
207
        /**
208
         * Initiate (Main KeepConditions Plugin Functions)
209
         *
210
         * Initiate the main KeepConditions plugin functionality, such as parsing the initial
211
         * URL hash value and implementing the results in the table, attaching the enabled
212
         * conditions to be managed to the associated Datatables events, etc etc.
213
         *
214
         * @access  private
215
         * @return  {void}
216
         */
217
        value: function _init() {
218
            // Enable any enabled/initiated settings/Extensions/Plugins
219
            this._collectEnabled();
220
221
            // Check if the events should be attached, they can be detached if the keepConditions
222
            // setting is an object, with 'attachEvents' set to false
223
            if (this._dtSettings.oInit.keepConditions === true || typeof this._dtSettings.oInit.keepConditions === 'string' || $.isArray(this._dtSettings.oInit.keepConditions) || $.isPlainObject(this._dtSettings.oInit.keepConditions) && (typeof this._dtSettings.oInit.keepConditions.attachEvents === 'undefined' || this._dtSettings.oInit.keepConditions.attachEvents === true)) this.attachEvents();
224
225
            // Parse the URL hash value, have each condition object process it's associated
226
            // hash element value, re-drawing the table accordingly
227
            this.processHash();
228
        }
229
230
        // -----------------------------------------------------------
231
232
        /**
233
         * Collect Enabled (Conditions)
234
         *
235
         * Set any conditions that are enabled in the keepConditions initial settings, by adding them
236
         * to the enabledConditions
237
         */
238
239
    }, {
240
        key: '_collectEnabled',
241
        value: function _collectEnabled() {
242
            var _this = this;
243
244
            // Loop through all available conditions, checking if enabled
245
            $.each(this.conditions(), function (sCondition, oCondition) {
246
247
                // Check if condition is enabled in plugin settings, and if the table was initialized
248
                // with said setting/extension/plugin (The latter is unique per condition, so each
249
                // condition object has it's own method to check if table was init with condition)
250
                if (!_this._isEnabled(sCondition) || !oCondition.isInit()) return;
251
252
                // Add it to the enabled conditions list/array
253
                _this.enableCondition(sCondition);
254
            });
255
        }
256
257
        // -----------------------------------------------------------
258
259
        /**
260
         * Map (Condition) Keys (To Condition Names)
261
         *
262
         * Executed by _keysToCons to basically map each conditions key to the condition name,
263
         * primarily used to associate the condition keys within the hash string to the condition
264
         * name themselves.
265
         *
266
         * @access  private
267
         * @return  {object}    Returns: { f: 'search', l: 'length', ... }
268
         */
269
270
    }, {
271
        key: '_keyMap',
272
        value: function _keyMap() {
273
            return (function (conditions) {
274
                var ret = {};
275
276
                $.each(conditions, function (name, con) {
277
                    ret[con.key] = name;
278
                });
279
280
                return ret;
281
            })(this.conditions());
282
        }
283
284
        // -----------------------------------------------------------
285
286
        /**
287
         * Is (Specific Condition) Enabled
288
         *
289
         * Check if a specific condition is enabled to be managed via KeepConditions
290
         * plugin. Condition(s) can be enabled if the DT setting 'keepConditions' is
291
         * simply 'true', which would enable all available conditions, or it can be
292
         * a string of condition keys, or an array of condition names, or an object,
293
         * which may contain a 'conditions' property, which can also be either an
294
         * array of enabled conditions, or a string of condition names, or if it is
295
         * undefined, then all available conditions are enabled.
296
         * Note: This does not validate if the associated setting/extension/plugin
297
         * is enabled within DataTables, but rather just set to be managed via
298
         * KeepConditions
299
         *
300
         * @param   {string}    condition   Condition name to validate
301
         * @access  private
302
         * @return  {boolean}
303
         */
304
305
    }, {
306
        key: '_isEnabled',
307
        value: function _isEnabled(condition) {
308
            var options = this._dtSettings.oInit.keepConditions;
309
310
            // If were verifying a condition status by the key...
311
            if (condition.length === 1) {
312
                // Attempt to get the name, if it fails, throw an error..
313
                var name = this.nameByKey(condition);
314
315
                if (!condition) throw new Error('Unable to find an existing condition with the key \'' + condition + '\'');
316
317
                // .. Otherwise, set the condition to the retreived name and continue
318
                condition = name;
319
            }
320
            // If were verifying by the name, and the name wasn't found...
321
            else if (this.conditions(condition) === false) {
322
                    throw new Error('Unable to find an existing condition with the name \'' + condition + '\'');
323
                }
324
325
            // Return the result based on the initial DT 'keepConditions' value, (Details on
326
            // logic process in the above DocBlock comment)
327
            return(
328
                // A) If the initial 'keepConditions' is 'true', just say yes to all conditions
329
                options === true
330
                // If its undefined (This should only happen if KeepConditions is being
331
                // initialized via manually executing: new KeepConditions( table )
332
                 || typeof options === 'undefined'
333
                // B) If the init config is a string of conditions (by keys)..
334
                 || typeof options === 'string' && options.indexOf(this.conditions(condition).key) !== -1
335
                // C) If the init config is an array of enabled conditions..
336
                 || $.isArray(options) && $.inArray(condition, options) !== -1
337
                // D) If the init configs 'conditions' property is an array of conditions..
338
                 || $.isPlainObject(options) && $.isArray(options.conditions) && $.inArray(condition, options.conditions) !== -1
339
                // E) If the init configs 'conditions' property is a string of conditions (by keys)..
340
                 || $.isPlainObject(options) && typeof options.conditions === 'string' && options.conditions.indexOf(this.conditions(condition).key) !== -1
341
            );
342
        }
343
344
        // -----------------------------------------------------------
345
346
        /**
347
         * Redraw the table
348
         *
349
         * This is mainly ran after all the onLoads have done for the conditions, instead of drawing the
350
         * table after each condition is loaded, they will set _shouldDraw to true, then execute this,
351
         * and this will check the _shouldDraw, then draw if necessary, and reset _shouldDraw.
352
         *
353
         * @param   {boolean}   force           Force the draw, regardless of the value of this._shouldDraw
354
         * @param   {boolean}   resetPaging     Reset the paging or not (Sending view to first page)
355
         * @access  private
356
         * @return  {void}
357
         */
358
359
    }, {
360
        key: '_drawTable',
361
        value: function _drawTable(force, resetPaging) {
362
            if (this._shouldDraw === true || force === true) {
363
                this._dtApi.draw(resetPaging === true);
364
                this._shouldDraw = false;
365
            }
366
        }
367
368
        // -----------------------------------------------------------
369
370
    }, {
371
        key: '_lang',
372
        value: function _lang(key, string) {}
373
374
        // -----------------------------------------------------------
375
376
        /**
377
         * Structure Hash (Conditions)
378
         *
379
         * Basically a non-static value of KeepConditions.structureHash(), mainly
380
         * used via the API Methods
381
         *
382
         * @param   {boolean}   retrieve        Return the hash value, as opposed
383
         *                                      to updating the URL hash
384
         * @access  public
385
         * @return  {void|string}   Either returns the hash string, or updates hash
386
         */
387
388
    }, {
389
        key: 'structureHash',
390
        value: function structureHash(retrieve) {
391
            return KeepConditions.structureHash(this._dtSettings, retrieve);
392
        }
393
394
        // -----------------------------------------------------------
395
396
        /**
397
         * Just return DT Settings
398
         */
399
400
    }, {
401
        key: 'dtSettings',
402
        value: function dtSettings() {
403
            return this._dtSettings;
404
        }
405
406
        // -----------------------------------------------------------
407
408
        /**
409
         * Attach (Condition Update) Events
410
         *
411
         * Attach the KeepConditions.structureHash() method to any DT events that may require the hash to
412
         * be updated (such as Col Reordering, Col Sort Order, Draw, etc)
413
         *
414
         * @access  public
415
         * @return  {void}
416
         */
417
418
    }, {
419
        key: 'attachEvents',
420
        value: function attachEvents() {
421
            var _this2 = this;
422
423
            var eventParams = {
424
                dtSettings: this._dtSettings
425
            },
426
                enabledConditions = this.getEnabledConditions();
427
428
            if (enabledConditions === false) throw new Error('No enabled conditions to attach to events');
429
430
            var conditions = this.conditions(enabledConditions);
431
432
            // Loop through all available conditions
433
            $.each(conditions, function (sCondition, oCondition) {
434
                // Attach the method that updates the hash, to the event associated with this condition
435
                _this2._dtApi.on(oCondition.event + '.' + _this2._eventNamespace, eventParams, KeepConditions.structureHash.bind(KeepConditions));
436
            });
437
        }
438
439
        // -----------------------------------------------------------
440
441
        /**
442
         * Detach (Condition Update) Events
443
         *
444
         * Detach the KeepConditions.structureHash() method to any DT events that may require the hash to
445
         * be updated (such as Col Reordering, Col Sort Order, Draw, etc)
446
         *
447
         * @access  public
448
         * @return  {void}
449
         */
450
451
    }, {
452
        key: 'detachEvents',
453
        value: function detachEvents() {
454
            var _this3 = this;
455
456
            var eventParams = {
457
                dtSettings: this._dtSettings
458
            },
459
                enabledConditions = this.getEnabledConditions();
460
461
            if (enabledConditions === false) throw new Error('No enabled conditions to attach to events');
462
463
            var conditions = this.conditions(enabledConditions);
464
465
            // Loop through all available conditions
466
            $.each(conditions, function (sCondition, oCondition) {
467
                // Check if condition is enabled in plugin settings, and if the table was initialized
468
                // with said setting/extension/plugin (The latter is unique per condition, so each
469
                // condition object has it's own method to check if table was init with condition)
470
                if (!_this3._isEnabled(sCondition) || !oCondition.isInit()) return;
471
472
                // Attach the method that updates the hash, to the event associated with this condition
473
                _this3._dtApi.off(oCondition.event + '.' + _this3._eventNamespace);
474
            });
475
        }
476
477
        // -----------------------------------------------------------
478
479
        /**
480
         * Detach (Hash Update from conditions) Event
481
         *
482
         * The KeepConditions.structureHash() method is attached to the events specified by the 'event' property
483
         * for each condition. This method can be used to detach that method from a specific DataTables event,
484
         * which can be specified by giving the condition (which then the event is retrieved), or the exact
485
         * DataTables event (ending in .dt, eg: draw.dt)
486
         *
487
         * @param   {string|array}     condition    Either an array if multiple, or string of single condition(s)
488
         *                                          or DT event(s)
489
         * @access  public
490
         * @return  {void}
491
         */
492
493
    }, {
494
        key: 'detachEvent',
495
        value: function detachEvent(condition) {
496
            var _this4 = this;
497
498
            if (typeof condition === 'undefined') {
499
                console.warn('No condition or event specified for KeepConditions.detachEvent(), nothing is getting detached');
500
501
                return;
502
            }
503
504
            // Retrieve the condition, also to make sure it exists
505
            var oCondition = this.conditions(condition);
506
507
            if (!oCondition) return false;
508
509
            var event;
510
511
            // Single condition or event
512
            if (typeof condition === 'string') {
513
                // If were given the exact event
514
                if (condition.endsWith('.dt')) event = condition;
515
516
                // If were given the condition to retrieve the event name from
517
                else event = oCondition.event;
518
519
                // Detach event callback
520
                this._dtApi.off(event, KeepConditions.structureHash.bind(KeepConditions));
521
            }
522
523
            // Multiple events or conditions
524
            else if ($.isArray(condition) && condition.length > 0) {
525
                    $.each(condition, function (i, c) {
526
                        // If were given the exact event
527
                        if (c.endsWith('.dt')) event = c;
528
529
                        // If were given the condition to retrieve the event name from, make sure it exists
530
                        else if (typeof oCondition[c] !== 'undefined') event = oCondition[c].event;
531
532
                            // Abort if we were given an incorrect condition
533
                            else throw new Error('Unknown condition specified: ' + c);
534
535
                        // Detach event callback
536
                        _this4._dtApi.off(event + '.' + _this4._eventNamespace);
537
                    });
538
                }
539
540
                // Whatever else
541
                else {
542
                        // If we were given something that wasnt caught
543
                        console.warn('Illegal parameter type for KeepConditions.detachEvent(), should be array or string, was: ', typeof condition === 'undefined' ? 'undefined' : _typeof(condition));
544
                    }
545
        }
546
547
        // -----------------------------------------------------------
548
549
        /**
550
         * Attach (Hash Update to conditions) Event
551
         *
552
         * Attach the KeepConditions.structureHash() method to one or more specific event(s), specified either
553
         * by the condition name (search, paging, etc) or the specific event itself (which should end with
554
         * '.dt', EG: draw.dt)
555
         *
556
         * @param   {string|array}     condition    Either an array if multiple, or string of single condition(s)
557
         *                                          or DT event(s)
558
         * @access  public
559
         * @return  {void}
560
         * @todo    Should 'this.enableCondition( sCondition );' be added? Dont think so
561
         */
562
563
    }, {
564
        key: 'attachEvent',
565
        value: function attachEvent(condition) {
566
            var _this5 = this;
567
568
            if (typeof condition === 'undefined') {
569
                console.warn('No condition or event specified for KeepConditions.attachEvent(), nothing is getting attached');
570
571
                return;
572
            }
573
574
            // Data handed to the jQuery event
575
            var eventParams = {
576
                dtSettings: this._dtSettings
577
            };
578
579
            // Retrieve the condition, also to make sure it exists
580
            var oCondition = this.conditions(condition);
581
582
            if (!oCondition) return false;
583
584
            var event;
585
586
            //this._dtApi.on( oCondition.event, eventParams, KeepConditions.structureHash.bind( KeepConditions ) );
587
588
            // Single condition or event
589
            if (typeof condition === 'string') {
590
                // If were given the exact event
591
                if (condition.endsWith('.dt')) event = condition;
592
593
                // If were given the condition to retrieve the event name from
594
                else event = oCondition.event;
595
596
                // Detach event callback
597
                this._dtApi.on(event, eventParams, KeepConditions.structureHash.bind(KeepConditions));
598
            }
599
600
            // Multiple events or conditions
601
            else if ($.isArray(condition) && condition.length > 0) {
602
                    $.each(condition, function (i, c) {
603
                        // If were given the exact event
604
                        if (c.endsWith('.dt')) event = c;
605
606
                        // If were given the condition to retrieve the event name from, make sure it exists
607
                        else if (typeof oCondition[c] !== 'undefined') event = oCondition[c].event;
608
609
                            // Abort if we were given an incorrect condition
610
                            else throw new Error('Unknown condition specified: ' + c);
611
612
                        // Detach event callback
613
                        _this5._dtApi.on(event + '.' + _this5._eventNamespace, KeepConditions.structureHash.bind(KeepConditions));
614
                    });
615
                }
616
617
                // Whatever else
618
                else {
619
                        // If we were given something that wasn't caught
620
                        console.warn('Illegal parameter type for KeepConditions.attachEvent(), should be array or string, was: ' + (typeof condition === 'undefined' ? 'undefined' : _typeof(condition)));
621
                    }
622
        }
623
624
        // -----------------------------------------------------------
625
626
        /**
627
         * Process (Initial) URL Hash
628
         *
629
         * This is executed after KeepConditions has been initiated by DataTables, any conditions
630
         * found in the URL hash will be parsed by the conditions onLoad( ) method (If the condition
631
         * is enabled/initiated), then the table will be redrawn (if needed)
632
         *
633
         * @access  public
634
         * @return  {void}
635
         */
636
637
    }, {
638
        key: 'processHash',
639
        value: function processHash() {
640
            var _this6 = this;
641
642
            // Loop through each element in the hash, until we find an element whos key matches the table ID
643
            $.each(KeepConditions.queryString(), function (table, cons) {
644
                // If somehow thers more than one condition for this table, just take the first one..
645
                if ($.isArray(cons) || $.isPlainObject(cons)) cons = cons[0];
646
647
                // Skip to the next hash element if this one isn't for the current table
648
                if (table !== _this6._tableId) return;
649
650
                // Loop through each condition within the Hash, which is delimited by :
651
                $.each(cons.split(':'), function (i, c) {
652
                    var conKey = c.charAt(0),
653
                        conVal = c.substring(1),
654
                        conName = _this6.nameByKey(conKey),
655
                        oCondition = _this6.conditions()[conName];
656
657
                    // Skip condition if its not enabled
658
                    if ($.inArray(conName, _this6.getEnabledConditions()) === -1) return;
659
660
                    if (typeof oCondition === 'undefined') {
661
                        console.warn('[keepConditions:\' ' + _this6._tableId + '] No condition object found for condition key:', conKey);
662
                        return;
663
                    }
664
665
                    // Have the condition object parse the hash
666
                    oCondition.onLoad(conVal);
667
                });
668
669
                // Draw the table if needed
670
                _this6._drawTable();
671
            });
672
        }
673
674
        // -----------------------------------------------------------
675
676
        /**
677
         * Enable Condition(s)
678
         *
679
         * Enable condition(s) to be managed via KeepConditions plugin - Basically just adds the condition(s) to
680
         * this._enabledConditions. Conditions can be specified by either the full name,
681
         * or the single character condition key
682
         *
683
         * @param   {string|array}  condition       DataTables condition(s) to enable, condition(s) can be
684
         *                                          specified either by the full name, or the condition key
685
         * @param   {boolean}       structureHash   Restructure the hash after said condition has been enabled
686
         * @access  public
687
         * @return  {void}
688
         */
689
690
    }, {
691
        key: 'enableCondition',
692
        value: function enableCondition(condition, structureHash) {
693
            var _this7 = this;
694
695
            var done = false;
696
697
            // Process multiple conditions to enable
698
            if ($.isArray(condition)) {
699
                $.each(condition, function (i, c) {
700
                    // If its a key, then get the name from the key
701
                    if (c.length === 1) c = _this7.nameByKey(c);
702
703
                    if (_this7.conditions(c) !== false) {
704
                        _this7._enabledConditions.push(c);
705
706
                        done = true;
707
                    }
708
                });
709
            } else if (typeof condition === 'string') {
710
                // If its a key, then get the name from the key
711
                if (condition.length === 1) condition = this.nameByKey(condition);
712
713
                if (this.conditions(condition) !== false) {
714
                    this._enabledConditions.push(condition);
715
716
                    done = true;
717
                }
718
            }
719
720
            // If a condition was successfully enabled, and were requested to update the hash, do eeet!
721
            if (structureHash === true && done === true) KeepConditions.structureHash(this._dtSettings, false);
722
        }
723
724
        // -----------------------------------------------------------
725
726
        /**
727
         * Disable Condition(s)
728
         *
729
         * Disable condition(s) from being managed via KeepConditions plugin - Basically just removes the
730
         * condition(s) from this._enabledConditions. Conditions can be specified by either the full name,
731
         * or the single character condition key
732
         *
733
         * @param   {string|array}  condition       DataTables condition(s) to disable, condition(s) can be
734
         *                                          specified either by the full name, or the condition key
735
         * @param   {boolean}       structureHash   Restructure the hash after said condition has been disabled
736
         * @access  public
737
         * @return  {void}
738
         */
739
740
    }, {
741
        key: 'disableCondition',
742
        value: function disableCondition(condition, structureHash) {
743
            var _this8 = this;
744
745
            var done = false;
746
747
            // Process multiple conditions to disable
748
            if ($.isArray(condition)) {
749
                $.each(condition, function (i, c) {
750
                    // If its a key, then get the name from the key
751
                    if (c.length === 1) c = _this8.nameByKey(c);
752
753
                    if (_this8.conditions(c) !== false) {
754
                        _this8._enabledConditions.splice($.inArray(c, _this8._enabledConditions), 1);
755
756
                        done = true;
757
                    }
758
                });
759
            } else if (typeof condition === 'string') {
760
                // If its a key, then get the name from the key
761
                if (condition.length === 1) condition = this.nameByKey(condition);
762
763
                if (this.conditions(condition) !== false) {
764
                    this._enabledConditions.splice($.inArray(condition, this._enabledConditions), 1);
765
766
                    done = true;
767
                }
768
            }
769
770
            // If a condition was successfully disabled, and were requested to update the hash, do eeet!
771
            if (structureHash === true && done === true) KeepConditions.structureHash(this._dtSettings, false);
772
        }
773
774
        // -----------------------------------------------------------
775
776
        /**
777
         * Get Enabled Conditions
778
         *
779
         * Returns a list of conditions being managed via plugin
780
         *
781
         * @access  public
782
         * @return  {array|boolean}     Array of conditions being kept, or false if none
783
         */
784
785
    }, {
786
        key: 'getEnabledConditions',
787
        value: function getEnabledConditions() {
788
            return this._enabledConditions.length > 0 ? $.unique(this._enabledConditions) : false;
789
        }
790
791
        // -----------------------------------------------------------
792
793
        /**
794
         * Condition Name by Key
795
         *
796
         * Return the name of a condition (search, length, colorder), given the key (f, l, c). Useful for
797
         * when referencing conditions using the keys from the hash value
798
         *
799
         * @param   {string}    key     Key of condition (Single alpha value, usually first name of
800
         *                              condition, but not always)
801
         * @access  public
802
         * @return  {string}    Full condition name (name of condition within this.conditions( ) obj)
803
         */
804
805
    }, {
806
        key: 'nameByKey',
807
        value: function nameByKey(key) {
808
            return this._keysToCons[key] || false;
809
        }
810
811
        // -----------------------------------------------------------
812
813
        /**
814
         * Conditions Manager
815
         *
816
         * Manages the object that contains the primary functionality for managing conditions,
817
         * such as checkinf if the condition is enabled via DT, checking if the plugin/extension
818
         * is initiated (if required), checking if hash value is set and valid, creating new hash
819
         * value, etc etc
820
         *
821
         * @param   {string|array|null}     con     Either string of single condition, or array of
822
         *                                          conditions, or null for all conditions
823
         * @access  public
824
         * @return  {object}    Object of objects (conditions)
825
         */
826
827
    }, {
828
        key: 'conditions',
829
        value: function conditions(con) {
830
            var _this9 = this;
831
832
            var _parent = this;
833
834
            /**
835
             * Main conditions object
836
             *
837
             * Each object within this object should be a unique condition that can be
838
             * managed via KeepConditions. The keys need to be the name of the values
839
             * stored within the DT initiation setting 'keepConditions', should conditions
840
             * be specified, instead of just 'true'
841
             */
842
            var conditions = {
843
                /**
844
                 * Table searching (aka Filtering) condition
845
                 */
846
                search: {
847
                    // Hash Key
848
                    key: 'f',
849
850
                    // Event to trigger the hash update for
851
                    event: 'search.dt',
852
853
                    // Check if condition is setup on table
854
                    isInit: function isInit() {
855
                        return typeof _parent._dtSettings.oInit.searching === 'undefined' || _parent._dtSettings.oInit.searching !== false;
856
                    },
857
858
                    // Function to check if a condition exists in the hash, and to process it
859
                    onLoad: function onLoad(hashComponent) {
860
                        if (typeof hashComponent !== 'undefined' && _parent._dtApi.search() !== decodeURIComponent(hashComponent)) {
861
                            _parent._dtApi.search(decodeURIComponent(hashComponent));
862
                            _parent._shouldDraw = true;
863
                        }
864
                    },
865
866
                    // Check if a value for this condition is currently set for the table (and not at default)
867
                    isset: function isset() {
868
                        return _parent._dtApi.search().length !== 0;
869
                    },
870
871
                    // Return the new value to be stored in the hash for this conditions component
872
                    newHashVal: function newHashVal() {
873
                        return encodeURIComponent(_parent._dtApi.search());
874
                    }
875
                },
876
877
                /**
878
                 * Condition: Length
879
                 *
880
                 * @todo Check if the hash value is an existing value in the page length list
881
                 */
882
                length: {
883
                    // Hash Key
884
                    key: 'l',
885
886
                    // Event to trigger the hash update for
887
                    event: 'length.dt',
888
889
                    // Check if condition is setup on table
890
                    isInit: function isInit() {
891
                        return !(_parent._dtSettings.oInit.lengthChange === false || typeof _parent._dtSettings.oInit.lengthChange === 'undefined' && _parent._dtDefaults.bLengthChange === false);
892
                    },
893
894
                    // Function to check if a condition exists in the hash, and to process it
895
                    onLoad: function onLoad(hashComponent) {
896
                        if (typeof hashComponent !== 'undefined') {
897
                            _parent._dtApi.page.len(parseInt(hashComponent));
898
899
                            _parent._shouldDraw = true;
900
                        }
901
                    },
902
903
                    // Check if a value for this condition is currently set for the table (and not at default)
904
                    isset: function isset() {
905
                        return _parent._dtApi.page.len() && _parent._dtApi.page.len() !== (_parent._dtSettings.oInit.pageLength || _parent._dtDefaults.iDisplayLength);
906
                    },
907
908
                    // Return the new value to be stored in the hash for this conditions component
909
                    newHashVal: function newHashVal() {
910
                        return _parent._dtApi.page.len();
911
                    }
912
                },
913
914
                /**
915
                 * Pagination
916
                 */
917
                page: {
918
                    // Hash Key
919
                    key: 'p',
920
921
                    // Event to trigger the hash update for
922
                    event: 'page.dt',
923
924
                    // Check if condition is setup on table
925
                    isInit: function isInit() {
926
                        return !(_parent._dtSettings.oInit.paging === false || typeof _parent._dtSettings.oInit.paging === 'undefined' && _parent._dtDefaults.bPaginate === false);
927
                    },
928
929
                    // Function to check if a condition exists in the hash, and to process it
930
                    onLoad: function onLoad(hashComponent) {
931
                        if (typeof hashComponent !== 'undefined' && parseInt(hashComponent) !== 0) {
932
                            _parent._dtApi.page(parseInt(hashComponent));
933
934
                            _parent._shouldDraw = true;
935
                        }
936
                    },
937
938
                    // Check if a value for this condition is currently set for the table (and not at default)
939
                    isset: function isset() {
940
                        return _parent._dtApi.page.info() && _parent._dtApi.page.info().page !== 0;
941
                    },
942
943
                    // Return the new value to be stored in the hash for this conditions component
944
                    newHashVal: function newHashVal() {
945
                        return _parent._dtApi.page.info().page;
946
                    }
947
                },
948
949
                /**
950
                 * Column Visibility
951
                 */
952
                colvis: {
953
                    // Hash Key
954
                    key: 'v',
955
956
                    // Event to trigger the hash update for
957
                    event: 'column-visibility.dt',
958
959
                    // Colvis is always true, since it's actually just a column setting, nothing more
960
                    isInit: function isInit() {
961
                        return true;
962
                    },
963
964
                    // Function to check if a condition exists in the hash, and to process it
965
                    onLoad: function onLoad(hashComponent) {
966
                        if (typeof hashComponent !== 'undefined') {
967
                            var _ret = (function () {
968
                                var isVis = hashComponent.charAt(0),
969
                                    columns = hashComponent.substring(1).split('.');
970
971
                                // If the header was messed with, just skip the col vis
972
                                if (isVis !== 'f' && isVis !== 't') {
973
                                    console.warn('Unknown ColVis condition visibility value, expected t or f, found:', isVis);
974
                                    return {
975
                                        v: undefined
976
                                    };
977
                                }
978
979
                                _parent._dtApi.columns().indexes().each(function (value, index) {
980
                                    // Parse as visible list
981
                                    if (isVis === 't') {
982
                                        if ($.inArray(value.toString(), columns) === -1) _parent._dtApi.column(value).visible(false);else _parent._dtApi.column(value).visible(true);
983
                                    }
984
                                    // Parse as hidden list
985
                                    else {
986
                                            if ($.inArray(value.toString(), columns) === -1) _parent._dtApi.column(value).visible(true);else _parent._dtApi.column(value).visible(false);
987
                                        }
988
                                });
989
990
                                _parent._shouldDraw = true;
991
                            })();
992
993
                            if ((typeof _ret === 'undefined' ? 'undefined' : _typeof(_ret)) === "object") return _ret.v;
994
                        }
995
                    },
996
997
                    // Check if a value for this condition is currently set for the table (and not at default)
998
                    isset: function isset() {
999
                        return _parent._dtApi.columns().visible().filter(function (v) {
1000
                            return !v;
1001
                        }).any();
1002
                    },
1003
1004
                    // Return the new value to be stored in the hash for this conditions component
1005
                    newHashVal: function newHashVal() {
1006
                        var t = [],
1007
                            // visible
1008
                        f = []; // hidden
1009
1010
                        // Add the visible col indexes to t, and hidden to f
1011
                        _parent._dtApi.columns().visible().each(function (value, index) {
1012
                            if (value === true) t.push(index);else f.push(index);
1013
                        });
1014
1015
                        // If nothings hidden, don't update the hash
1016
                        // @todo What if columns are hidden by default? And viewer wants to unhide all
1017
                        //if ( f.length === 0 ) return false;
1018
1019
                        // If visible column count is greater, then use non-vis
1020
                        if (t.length >= f.length) return 'f' + f.join('.');
1021
1022
                        // Otherwise, use visible count
1023
                        return 't' + t.join('.');
1024
                    }
1025
                },
1026
1027
                /**
1028
                 * Scroller Extension
1029
                 *
1030
                 * Scroll position of the DT instance
1031
                 */
1032
                scroller: {
1033
                    // Hash Key
1034
                    key: 's',
1035
1036
                    // Scroller is ran on every draw event
1037
                    event: 'draw.dt',
1038
1039
                    // Check if condition is setup on table
1040
                    isInit: function isInit() {
1041
                        return typeof _parent._dtSettings.oScroller !== 'undefined';
1042
                    },
1043
1044
                    // Function to check if a condition exists in the hash, and to process it
1045
                    onLoad: function onLoad(hashComponent) {
1046
                        if (parseInt(hashComponent) !== 0) _parent._dtApi.row(parseInt(hashComponent)).scrollTo();
1047
1048
                        // No redraw necessary for scroller
1049
                    },
1050
1051
                    // Check if a value for this condition is currently set for the table (and not at default)
1052
                    isset: function isset() {
1053
                        return Math.trunc(parseInt(_parent._dtSettings.oScroller.s.baseRowTop)) !== 0;
1054
                    },
1055
1056
                    // Return the new value to be stored in the hash for this conditions component
1057
                    newHashVal: function newHashVal() {
1058
                        var scrollPos = Math.trunc(parseInt(_parent._dtSettings.oScroller.s.baseRowTop));
1059
1060
                        return scrollPos !== 0 ? scrollPos : false;
1061
                    }
1062
                },
1063
1064
                /**
1065
                 * Column Sequence Order
1066
                 *
1067
                 * Order of columns as seen in header of table
1068
                 */
1069
                colorder: {
1070
                    // Hash Key
1071
                    key: 'c',
1072
1073
                    // Event to trigger the hash update for
1074
                    event: 'column-reorder.dt',
1075
1076
                    // Check if setting/extension/plugin is setup on table
1077
                    isInit: function isInit() {
1078
                        return typeof _parent._dtSettings._colReorder !== 'undefined';
1079
                    },
1080
1081
                    // Function to check if a condition exists in the hash, and to process it
1082
                    onLoad: function onLoad(hashComponent) {
1083
                        var preSeq = hashComponent.split('.'),
1084
                            res = [];
1085
1086
                        // Check for any array items that are sequences (eg: 2-6)
1087
                        $.each(preSeq, function (is, s) {
1088
                            if (s.indexOf('-') !== -1) {
1089
                                var spl = s.split('-'),
1090
                                    a = parseInt(spl[0]),
1091
                                    b = parseInt(spl[1]);
1092
                                if (a > b) for (var i = a; b < i + 1; i--) {
1093
                                    res.push(i);
1094
                                } else for (var i = a; b > i - 1; i++) {
1095
                                    res.push(i);
1096
                                }
1097
                            } else {
1098
                                res.push(s);
1099
                            }
1100
                        });
1101
1102
                        var hashColOrder = res.map(function (i) {
1103
                            return parseInt(i);
1104
                        });
1105
1106
                        // @todo remove after fixing init issue
1107
                        if (typeof _parent._dtApi.colReorder === 'undefined') return false;
1108
1109
                        if (JSON.stringify(hashColOrder) !== JSON.stringify(_parent._dtApi.colReorder.order())) {
1110
                            _parent._dtApi.colReorder.order(hashColOrder, true);
1111
1112
                            _parent._shouldDraw = true;
1113
                        }
1114
                    },
1115
1116
                    // Check if a value for this condition is currently set for the table (and not at default)
1117
                    isset: function isset() {
1118
                        // @todo remove after fixing init issue
1119
                        if (typeof _parent._dtApi.colReorder === 'undefined') return false;
1120
1121
                        return JSON.stringify(_parent._dtApi.colReorder.order()) !== JSON.stringify(_parent._dtApi.columns().indexes().toArray());
1122
                    },
1123
1124
                    // Return the new value to be stored in the hash for this conditions component
1125
                    newHashVal: function newHashVal() {
1126
                        var sequence = _parent._dtApi.colReorder.order(),
1127
1128
                        // Temp var used to store the previous number, reset on every iteration
1129
                        prev = undefined,
1130
1131
                        // Gets joined by '.' on return
1132
                        result = [],
1133
1134
                        // Current collection if sequenced numbers
1135
                        collection = [],
1136
1137
                        // Return the number in the collection that is i spaces from the end
1138
                        lastInCol = function lastInCol(i) {
1139
                            return collection[collection.length - i];
1140
                        },
1141
1142
                        // Compile the collection (If > 2 characters, then it adds 'first-last',
1143
                        // if its just two characters, then it adds 'first.second'). Then empty
1144
                        // the collection array, and return the newly constructed string
1145
                        compileColl = function compileColl() {
1146
                            var ret = undefined;
1147
1148
                            if (collection.length === 2) ret = collection[0] + '.' + collection[1];else ret = collection[0] + '-' + lastInCol(1);
1149
1150
                            collection = [];
1151
                            return ret;
1152
                        };
1153
1154
                        // Shorten the sequence of numbers (Converting something like
1155
                        // 1, 2, 3, 4 to 1-4, going in both directions
1156
                        $.each(sequence, function (i, s) {
1157
                            s = parseInt(s);
1158
1159
                            // First one just gets added to result
1160
                            if (typeof prev === 'undefined') {
1161
                                result.push(s);
1162
                            }
1163
                            // Anything after the first..
1164
                            else {
1165
                                    // If were on a roll with the sequence..
1166
                                    if (collection.length > 0) {
1167
                                        // Check if were in sequence with the collection (Going positive)
1168
                                        if (lastInCol(1) > lastInCol(2) && s === lastInCol(1) + 1) {
1169
                                            collection.push(s);
1170
                                        }
1171
                                        // Check if were in sequence with the collection (Going negative)
1172
                                        else if (lastInCol(1) < lastInCol(2) && s === lastInCol(1) - 1) {
1173
                                                collection.push(s);
1174
                                            }
1175
                                            // Were running a collection, but this number isnt in sequence, so
1176
                                            // terminate the collection and add the collection and the current
1177
                                            // int to the result array
1178
                                            else {
1179
                                                    result.push(compileColl());
1180
                                                    result.push(s);
1181
                                                }
1182
                                    }
1183
                                    // Otherwise, check if we should start a sequence..
1184
                                    else {
1185
                                            // If this int and the prev are sequential in either direction,
1186
                                            // start the collection
1187
                                            if (s === prev + 1 || s === prev - 1) {
1188
                                                // Pull the last item from the result
1189
                                                result.splice(result.length - 1, 1);
1190
                                                // add it to the collection
1191
                                                collection.push(prev);
1192
                                                collection.push(s);
1193
                                            }
1194
                                            // This number isnt in sequence with the last one, so dont start
1195
                                            // a collection
1196
                                            else {
1197
                                                    result.push(s);
1198
                                                }
1199
                                        }
1200
                                }
1201
1202
                            prev = s;
1203
                        });
1204
1205
                        // Once the $.each loop is done, we need to ensure that
1206
                        // there's no leftover collection numbers
1207
                        if (collection.length > 0) result.push(compileColl());
1208
1209
                        // Result should convert something like '[9,1,2,3,4,8,6,5,0]' to '9.1-4.8-5.0',
1210
                        // which is easily kept in the URL, and converted back later
1211
                        return result.join('.');
1212
                    }
1213
                },
1214
1215
                /**
1216
                 * Column Sorting Order
1217
                 *
1218
                 * Order condition (As in the sorting direction, NOT same as colorder)
1219
                 */
1220
                order: {
1221
                    // Hash Key
1222
                    key: 'o',
1223
1224
                    // Event to trigger the hash update for
1225
                    event: 'order.dt',
1226
1227
                    // Check if at least one column is sortable
1228
                    isInit: function isInit() {
1229
                        var result = false;
1230
1231
                        // Loop through the columns, as soon as one is found to be sortable,
1232
                        // set result to true, and quit the each loop
1233
                        $.each(_this9._dtSettings.aoColumns, function (colIndx, col) {
1234
                            if (col.bSortable === true) {
1235
                                result = true;
1236
                                return false;
1237
                            }
1238
                        });
1239
1240
                        return result;
1241
                    },
1242
1243
                    // Function to check if a condition exists in the hash, and to process it
1244
                    onLoad: function onLoad(hashComponent) {
1245
                        if (typeof hashComponent !== 'undefined') {
1246
                            // Direction keys
1247
                            var dir = { a: 'asc', d: 'desc' };
1248
1249
                            // @todo Should maybe check if the order found is current order?...
1250
1251
                            // Execute the api method to order the column accordingly
1252
                            _parent._dtApi.order([parseInt(hashComponent.substring(1)), dir[hashComponent.charAt(0)]]);
1253
1254
                            _parent._shouldDraw = true;
1255
                        }
1256
                    },
1257
1258
                    // Check if an order is set - and its not the default order
1259
                    isset: function isset() {
1260
                        return _parent._dtApi.order()[0] && JSON.stringify(_parent._dtApi.order()) !== JSON.stringify($.fn.dataTable.defaults.aaSorting);
1261
                    },
1262
1263
                    // Return the new value to be stored in the hash for this conditions component
1264
                    newHashVal: function newHashVal() {
1265
                        return _parent._dtApi.order()[0][1].charAt(0) + _parent._dtApi.order()[0][0];
1266
                    }
1267
                }
1268
            };
1269
1270
            // If retrieving a single condition - Return conditions object without the condition
1271
            // name as key
1272
            if (typeof con === 'string') {
1273
                // Make sure the condition exists
1274
                if (typeof conditions[con] === 'undefined') return false;
1275
                //throw new Error (`Unable to retrieve condition by name: ${con}`);
1276
1277
                return conditions[con];
1278
            }
1279
1280
            // Retrieving an array of conditions - Return an object with condition names as keys
1281
            else if ($.isArray(con) && con.length > 0) {
1282
                    var result = {};
1283
1284
                    $.each(con, function (i, c) {
1285
                        if (typeof conditions[c] === 'undefined') throw new Error('Unable to retrieve condition by name: ' + c);
1286
1287
                        result[c] = conditions[c];
1288
                    });
1289
1290
                    return result;
1291
                }
1292
1293
            // Return all conditions if nothing was requested specifically
1294
            return conditions;
1295
        }
1296
    }], [{
1297
        key: 'queryString',
1298
        value: function queryString() {
1299
            var queryString = {},
1300
                query = window.location.hash.substring(1),
1301
                vars = query.split("&");
1302
1303
            for (var i = 0; i < vars.length; i++) {
1304
                var pair = vars[i].split("=");
1305
                // If first entry with this name
1306
                if (typeof queryString[pair[0]] === 'undefined') queryString[pair[0]] = pair[1];else
1307
                    // If second entry with this name
1308
                    if (typeof queryString[pair[0]] === "string") queryString[pair[0]] = [queryString[pair[0]], pair[1]];
1309
1310
                    // If third or later entry with this name
1311
                    else queryString[pair[0]].push(pair[1]);
1312
            }
1313
1314
            return queryString || false;
1315
        }
1316
1317
        // -----------------------------------------------------------
1318
1319
        /**
1320
         * Structure Hash
1321
         *
1322
         * This is the function that's called when any of the events stored in each
1323
         * condition object gets triggered. There are two variables added to the
1324
         * data of the event object, 'dtApi' and 'dtSettings', explained below.
1325
         * Since this is a static member, any unique table-related data must be
1326
         * handed to it
1327
         *
1328
         * @param   {object}    e_dtSettings    jQuery event (containing data for
1329
         *                                      dtSettings) or dtSettings itself
1330
         * @param   {boolean}   retrieve        Return the hash value, as opposed
1331
         *                                      to updating the URL hash
1332
         * @var     {object}    dtSettings      DataTables instance settings object
1333
         * @var     {object}    dtApi           DataTables instance API object
1334
         * @access  public
1335
         * @return  {void|string}   Either returns the hash string, or updates hash
1336
         */
1337
1338
    }, {
1339
        key: 'structureHash',
1340
        value: function structureHash(e_dtSettings, retrieve) {
1341
            var dtSettings;
1342
1343
            if (!e_dtSettings) throw new Error('Illegal execution of KeepConditions.structureHash()');
1344
1345
            // If we were handed a KeepConditions object, extract the dtSettings from that
1346
            if (e_dtSettings instanceof KeepConditions) dtSettings = e_dtSettings.dtSettings();
1347
1348
            // If this is from a jQuery event, then the data should be handed to us
1349
            else if (typeof e_dtSettings.type !== 'undefined' && typeof e_dtSettings.data.dtSettings !== 'undefined') dtSettings = e_dtSettings.data.dtSettings;
1350
1351
                // If we were handed an instance of the DataTables API, we can get the settings from that
1352
                else if (e_dtSettings instanceof $.fn.dataTable.Api) dtSettings = e_dtSettings.settings()[0];
1353
1354
                    // If its just a Table selector or something, get the new API instance
1355
                    else if ($.fn.DataTable.isDataTable(e_dtSettings)) dtSettings = new $.fn.dataTable.Api(e_dtSettings).settings()[0];else if ($.isPlainObject(e_dtSettings) && _typeof($.isPlainObject(e_dtSettings.oKeepConditions))) dtSettings = e_dtSettings;
1356
1357
                        // Nothing else should be accepted, since the dtSettings is required
1358
                        else throw new Error('Unable to determine what you passed to KeepConditions.structureHash(), should be either an instance of KeepConditions, a proper jQuery event, or a DataTable instance with keepConditions enabled');
1359
1360
            var dtApi = new $.fn.dataTable.Api(dtSettings),
1361
                dtOptions = dtSettings.oInit,
1362
                conditions = dtSettings.oKeepConditions.getEnabledConditions(),
1363
                hashParsed = KeepConditions.queryString(),
1364
                tableID = $(dtApi.table().node()).attr('id'),
1365
                hash = {},
1366
                // End result hash (will be processed into URL hash)
1367
            tableHash = [],
1368
                // The conditions for THIS table
1369
            urlHash = []; // Gets joined by &
1370
1371
            if (typeof conditions === 'undefined' || conditions === false) throw new Error('Couldn\'t get conditions from table settings');
1372
1373
            // Grab all the existing hashes - to carefully not disturb any conditions NOT for this table
1374
            $.each(hashParsed, function (table, cons) {
1375
                // @todo Might still want to continue if !cons, to clear conditions
1376
                if (!table && !cons) return;
1377
1378
                // If this id isn't this table, store the hash and move on
1379
                if (table !== tableID) hash[table] = cons || '';
1380
1381
                // Were ignoring THIS table id because were going to re-create it
1382
            });
1383
1384
            // Loop through each enabled condition, setting the new hash value, if needed
1385
            $.each(conditions, function (i, c) {
1386
                if (dtSettings.oKeepConditions.conditions()[c].isset()) {
1387
                    var conHashVal = dtSettings.oKeepConditions.conditions()[c].newHashVal();
1388
1389
                    // Prevent any elements from being added as - vfundefined:sundefined:oundefined, etc
1390
                    if (typeof conHashVal !== 'undefined' && conHashVal !== false) tableHash.push(dtSettings.oKeepConditions.conditions()[c].key + conHashVal);
1391
                }
1392
            });
1393
1394
            hash[tableID] = tableHash.join(':');
1395
1396
            $.each(hash, function (table, conditions) {
1397
                if (conditions.length > 0) urlHash.push(table + '=' + conditions);
1398
            });
1399
1400
            var newHash = urlHash.join('&');
1401
1402
            // If were just retrieving the hash, then return it...
1403
            if (retrieve === true) return newHash;
1404
1405
            // Otherwise, update the URL Hash. If there is no hash value to update,
1406
            // then just set an underscore, to prevent the page from scrolling to
1407
            // the top
1408
            window.location.hash = newHash || '_';
1409
        }
1410
    }]);
1411
1412
    return KeepConditions;
1413
})();
1414
1415
(function (window, document, $, undefined) {
1416
    // Setting defaults
1417
    $.extend(true, $.fn.dataTable.defaults, {
1418
        language: {
1419
            // Default button related text values
1420
            keepConditions: {
1421
                button: {
1422
                    // When the URL is successfully sent to clipboard
1423
                    btnCopyTitle: 'URL Copied',
1424
                    btnCopyBody: 'The URL with the DataTables conditions has been ' + 'copied to your clipboard',
1425
                    // When clipboard interaction failed, and user needs to manually
1426
                    // copy the selected text in the input
1427
                    btnSelectTitle: 'Copy URL',
1428
                    btnSelectBody: 'Copy be below input to easily share the URL'
1429
                }
1430
            }
1431
        }
1432
    });
1433
1434
    // Auto-initialize KeepConditions on tables having it configured
1435
    $(document).on('init.dt', function (e, dtSettings) {
1436
        if (e.namespace !== 'dt') return;
1437
1438
        if (dtSettings.oInit.keepConditions !== undefined) new KeepConditions(dtSettings);
1439
    });
1440
1441
    /**
1442
     * Attach Events
1443
     *
1444
     * Attach the structureHash method to a DataTables event associated with one or more specified
1445
     * conditions. This will have the URL Hash updated whenever that event is triggered.
1446
     *
1447
     * @param   {string|array}  conditions  Conditions to retrieve events from
1448
     * @return  {object}        DataTables API
1449
     */
1450
    $.fn.dataTable.Api.register('keepConditions.attachEvents()', function (conditions) {
1451
        return this.iterator('table', function (dtSettings) {
1452
            return dtSettings.oKeepConditions.attachEvents();
1453
        });
1454
    });
1455
1456
    /**
1457
     * Detach Events
1458
     *
1459
     * Detach the structureHash method to a DataTables event associated with one or more specified
1460
     * conditions. This will have the URL Hash updated whenever that event is triggered.
1461
     *
1462
     * @param   {string|array}  conditions  Conditions to retrieve events from
1463
     * @return  {object}        DataTables API
1464
     */
1465
    $.fn.dataTable.Api.register('keepConditions.detachEvents()', function (conditions) {
1466
        return this.iterator('table', function (dtSettings) {
1467
            return dtSettings.oKeepConditions.detachEvents();
1468
        });
1469
    });
1470
1471
    /**
1472
     * Structure Hash
1473
     *
1474
     * Structure the hash value for the current conditions on the associated table, and either update
1475
     * the URL hash, or just return the hash string itself.
1476
     *
1477
     * @param   {boolean}   returnHash      Return the hash string (if true), or update the URL hash
1478
     * @return  {string|null}               If returnHash is true, then the hash string is returned
1479
     */
1480
    $.fn.dataTable.Api.register('keepConditions.structureHash()', function (returnHash) {
1481
        return this.context[0].oKeepConditions.structureHash(returnHash);
1482
    });
1483
1484
    /**
1485
     * Enable Condition(s)
1486
     *
1487
     * Enable one or more conditions, which can be specified by the condition key or condition name,
1488
     * and optionally update the URL hash after the condition(s) have been enabled (Adding the settings
1489
     * for the newly enabled condition(s) to the hash).
1490
     *
1491
     * @param   {string|array}  condition   Condition(s) to enable
1492
     * @param   {boolean}       updateHash  If true, the URL hash will be updated
1493
     * @return  {object}        DataTables API
1494
     */
1495
    $.fn.dataTable.Api.register('keepConditions.enableCondition()', function (condition, updateHash) {
1496
        return this.iterator('table', function (dtSettings) {
1497
            return dtSettings.oKeepConditions.enableCondition(condition, updateHash);
1498
        });
1499
    });
1500
1501
    /**
1502
     * Disable Condition(s)
1503
     *
1504
     * Disable one or more conditions, which can be specified by the condition key or condition name,
1505
     * and optionally update the URL hash after the condition(s) have been disabled (removing the settings
1506
     * for the newly disabled condition(s) from the hash).
1507
     *
1508
     * @param   {string|array}  condition   Condition(s) to enable
1509
     * @param   {boolean}       updateHash  If true, the URL hash will be updated
1510
     * @return  {object}        DataTables API
1511
     */
1512
    $.fn.dataTable.Api.register('keepConditions.disableCondition()', function (condition, updateHash) {
1513
        return this.iterator('table', function (dtSettings) {
1514
            return dtSettings.oKeepConditions.disableCondition(condition, updateHash);
1515
        });
1516
    });
1517
1518
    /**
1519
     * Copy Conditions Button
1520
     *
1521
     * This button will attempt to copy the URL with the current table conditions, if the copy
1522
     * fails (which it will in some browsers), then a simple input is shown with the contents
1523
     * being the URL, which should also be selected, the viewer then just has to copy the
1524
     * contents. The URL in the input is not taken from the current document location, because
1525
     * if the hash in the URL is not currently up-to-date, then it may not be the correct version,
1526
     * thus, the KeepConditions.structureHash() is used to retrieve the current hash. The timeouts
1527
     * for the alert dialogs can be configured, as well as the button text and the dialog texts
1528
     */
1529
    $.fn.dataTable.ext.buttons.copyConditions = {
1530
        text: 'Copy Conditions',
1531
        action: function action(e, dt, node, config) {
1532
            var dtLanguage = dt.settings()[0].oLanguage.keepConditions,
1533
                conditionsHash = dt.settings()[0].oKeepConditions.structureHash(true),
1534
                copyThis = document.location.protocol + '//' + document.location.host + (document.location.port.length ? ':' + document.location.port : '') + document.location.pathname + '#' + conditionsHash,
1535
                success,
1536
                language = {
1537
                btnNoHashTitle: dtLanguage.btnNoHashTitle || 'No Conditions',
1538
                btnNoHashBody: dtLanguage.btnNoHashBody || 'Thre are no conditions to be copied',
1539
                btnCopyTitle: dtLanguage.btnCopyTitle || 'URL Copied',
1540
                btnCopyBody: dtLanguage.btnCopyBody || 'The URL with the DataTables conditions has been copied to your clipboard',
1541
                btnSelectTitle: dtLanguage.btnSelectTitle || 'Copy URL',
1542
                btnSelectBody: dtLanguage.btnSelectBody || 'Copy be below input to easily share the URL'
1543
            };
1544
1545
            // If there were no conditions to be copied, then show a notification and don't copy anything
1546
            if (!conditionsHash) {
1547
                dt.buttons.info(language.btnNoHashTitle, language.btnNoHashBody, 3000);
1548
1549
                return;
1550
            }
1551
1552
            // Create the input that will hold the text to select/copy, move it off screen
1553
            $('<input />').val(copyThis).attr('id', 'copyConditions-text').css({
1554
                position: 'absolute',
1555
                left: '-9999px',
1556
                top: (window.pageYOffset || document.documentElement.scrollTop) + 'px'
1557
            }).appendTo('body');
1558
1559
            // Attempt to select the contents (which should be the current URL)
1560
            $('#copyConditions-text').select();
1561
1562
            // Try to execute a 'copy' command, which if successful, show the DT info dialog
1563
            // with a notice
1564
            try {
1565
                document.execCommand('copy');
1566
1567
                dt.buttons.info(language.btnCopyTitle, language.btnCopyBody, config.copyTimeout || 4000);
1568
1569
                success = true;
1570
            }
1571
            // If the copy command was unsuccessful, then show a DT info dialog with an input
1572
            // box, containing the URL
1573
            catch (err) {
1574
                dt.buttons.info(language.btnSelectTitle, language.btnSelectBody + '<br><input id="keepConditions-input" value="' + copyThis + '" style="width:90%;">', config.selectTimeout || 10000);
1575
1576
                // Try to select the contents to make it easier
1577
                $('input#keepConditions-input').select();
1578
            } finally {
1579
                // Remove the select input once this has finished
1580
                $("#copyConditions-text").remove();
1581
            }
1582
        }
1583
    };
1584
})(window, document, jQuery);

Return to bug 27467