]>
Commit | Line | Data |
---|---|---|
31f18b77 FG |
1 | /*! ColVis 1.1.2 |
2 | * ©2010-2015 SpryMedia Ltd - datatables.net/license | |
3 | */ | |
4 | ||
5 | /** | |
6 | * @summary ColVis | |
7 | * @description Controls for column visibility in DataTables | |
8 | * @version 1.1.2 | |
9 | * @file dataTables.colReorder.js | |
10 | * @author SpryMedia Ltd (www.sprymedia.co.uk) | |
11 | * @contact www.sprymedia.co.uk/contact | |
12 | * @copyright Copyright 2010-2015 SpryMedia Ltd. | |
13 | * | |
14 | * This source file is free software, available under the following license: | |
15 | * MIT license - http://datatables.net/license/mit | |
16 | * | |
17 | * This source file is distributed in the hope that it will be useful, but | |
18 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | |
19 | * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details. | |
20 | * | |
21 | * For details please refer to: http://www.datatables.net | |
22 | */ | |
23 | ||
24 | (function(window, document, undefined) { | |
25 | ||
26 | ||
27 | var factory = function( $, DataTable ) { | |
28 | "use strict"; | |
29 | ||
30 | /** | |
31 | * ColVis provides column visibility control for DataTables | |
32 | * | |
33 | * @class ColVis | |
34 | * @constructor | |
35 | * @param {object} DataTables settings object. With DataTables 1.10 this can | |
36 | * also be and API instance, table node, jQuery collection or jQuery selector. | |
37 | * @param {object} ColVis configuration options | |
38 | */ | |
39 | var ColVis = function( oDTSettings, oInit ) | |
40 | { | |
41 | /* Santiy check that we are a new instance */ | |
42 | if ( !this.CLASS || this.CLASS != "ColVis" ) | |
43 | { | |
44 | alert( "Warning: ColVis must be initialised with the keyword 'new'" ); | |
45 | } | |
46 | ||
47 | if ( typeof oInit == 'undefined' ) | |
48 | { | |
49 | oInit = {}; | |
50 | } | |
51 | ||
52 | var camelToHungarian = $.fn.dataTable.camelToHungarian; | |
53 | if ( camelToHungarian ) { | |
54 | camelToHungarian( ColVis.defaults, ColVis.defaults, true ); | |
55 | camelToHungarian( ColVis.defaults, oInit ); | |
56 | } | |
57 | ||
58 | ||
59 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | |
60 | * Public class variables | |
61 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | |
62 | ||
63 | /** | |
64 | * @namespace Settings object which contains customisable information for | |
65 | * ColVis instance. Augmented by ColVis.defaults | |
66 | */ | |
67 | this.s = { | |
68 | /** | |
69 | * DataTables settings object | |
70 | * @property dt | |
71 | * @type Object | |
72 | * @default null | |
73 | */ | |
74 | "dt": null, | |
75 | ||
76 | /** | |
77 | * Customisation object | |
78 | * @property oInit | |
79 | * @type Object | |
80 | * @default passed in | |
81 | */ | |
82 | "oInit": oInit, | |
83 | ||
84 | /** | |
85 | * Flag to say if the collection is hidden | |
86 | * @property hidden | |
87 | * @type boolean | |
88 | * @default true | |
89 | */ | |
90 | "hidden": true, | |
91 | ||
92 | /** | |
93 | * Store the original visibility settings so they could be restored | |
94 | * @property abOriginal | |
95 | * @type Array | |
96 | * @default [] | |
97 | */ | |
98 | "abOriginal": [] | |
99 | }; | |
100 | ||
101 | ||
102 | /** | |
103 | * @namespace Common and useful DOM elements for the class instance | |
104 | */ | |
105 | this.dom = { | |
106 | /** | |
107 | * Wrapper for the button - given back to DataTables as the node to insert | |
108 | * @property wrapper | |
109 | * @type Node | |
110 | * @default null | |
111 | */ | |
112 | "wrapper": null, | |
113 | ||
114 | /** | |
115 | * Activation button | |
116 | * @property button | |
117 | * @type Node | |
118 | * @default null | |
119 | */ | |
120 | "button": null, | |
121 | ||
122 | /** | |
123 | * Collection list node | |
124 | * @property collection | |
125 | * @type Node | |
126 | * @default null | |
127 | */ | |
128 | "collection": null, | |
129 | ||
130 | /** | |
131 | * Background node used for shading the display and event capturing | |
132 | * @property background | |
133 | * @type Node | |
134 | * @default null | |
135 | */ | |
136 | "background": null, | |
137 | ||
138 | /** | |
139 | * Element to position over the activation button to catch mouse events when using mouseover | |
140 | * @property catcher | |
141 | * @type Node | |
142 | * @default null | |
143 | */ | |
144 | "catcher": null, | |
145 | ||
146 | /** | |
147 | * List of button elements | |
148 | * @property buttons | |
149 | * @type Array | |
150 | * @default [] | |
151 | */ | |
152 | "buttons": [], | |
153 | ||
154 | /** | |
155 | * List of group button elements | |
156 | * @property groupButtons | |
157 | * @type Array | |
158 | * @default [] | |
159 | */ | |
160 | "groupButtons": [], | |
161 | ||
162 | /** | |
163 | * Restore button | |
164 | * @property restore | |
165 | * @type Node | |
166 | * @default null | |
167 | */ | |
168 | "restore": null | |
169 | }; | |
170 | ||
171 | /* Store global reference */ | |
172 | ColVis.aInstances.push( this ); | |
173 | ||
174 | /* Constructor logic */ | |
175 | this.s.dt = $.fn.dataTable.Api ? | |
176 | new $.fn.dataTable.Api( oDTSettings ).settings()[0] : | |
177 | oDTSettings; | |
178 | ||
179 | this._fnConstruct( oInit ); | |
180 | return this; | |
181 | }; | |
182 | ||
183 | ||
184 | ||
185 | ColVis.prototype = { | |
186 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | |
187 | * Public methods | |
188 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | |
189 | ||
190 | /** | |
191 | * Get the ColVis instance's control button so it can be injected into the | |
192 | * DOM | |
193 | * @method button | |
194 | * @returns {node} ColVis button | |
195 | */ | |
196 | button: function () | |
197 | { | |
198 | return this.dom.wrapper; | |
199 | }, | |
200 | ||
201 | /** | |
202 | * Alias of `rebuild` for backwards compatibility | |
203 | * @method fnRebuild | |
204 | */ | |
205 | "fnRebuild": function () | |
206 | { | |
207 | this.rebuild(); | |
208 | }, | |
209 | ||
210 | /** | |
211 | * Rebuild the list of buttons for this instance (i.e. if there is a column | |
212 | * header update) | |
213 | * @method fnRebuild | |
214 | */ | |
215 | rebuild: function () | |
216 | { | |
217 | /* Remove the old buttons */ | |
218 | for ( var i=this.dom.buttons.length-1 ; i>=0 ; i-- ) { | |
219 | this.dom.collection.removeChild( this.dom.buttons[i] ); | |
220 | } | |
221 | this.dom.buttons.splice( 0, this.dom.buttons.length ); | |
222 | this.dom.groupButtons.splice(0, this.dom.groupButtons.length); | |
223 | ||
224 | if ( this.dom.restore ) { | |
225 | this.dom.restore.parentNode( this.dom.restore ); | |
226 | } | |
227 | ||
228 | /* Re-add them (this is not the optimal way of doing this, it is fast and effective) */ | |
229 | this._fnAddGroups(); | |
230 | this._fnAddButtons(); | |
231 | ||
232 | /* Update the checkboxes */ | |
233 | this._fnDrawCallback(); | |
234 | }, | |
235 | ||
236 | ||
237 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | |
238 | * Private methods (they are of course public in JS, but recommended as private) | |
239 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | |
240 | ||
241 | /** | |
242 | * Constructor logic | |
243 | * @method _fnConstruct | |
244 | * @returns void | |
245 | * @private | |
246 | */ | |
247 | "_fnConstruct": function ( init ) | |
248 | { | |
249 | this._fnApplyCustomisation( init ); | |
250 | ||
251 | var that = this; | |
252 | var i, iLen; | |
253 | this.dom.wrapper = document.createElement('div'); | |
254 | this.dom.wrapper.className = "ColVis"; | |
255 | ||
256 | this.dom.button = $( '<button />', { | |
257 | 'class': !this.s.dt.bJUI ? | |
258 | "ColVis_Button ColVis_MasterButton" : | |
259 | "ColVis_Button ColVis_MasterButton ui-button ui-state-default" | |
260 | } ) | |
261 | .append( '<span>'+this.s.buttonText+'</span>' ) | |
262 | .bind( this.s.activate=="mouseover" ? "mouseover" : "click", function (e) { | |
263 | e.preventDefault(); | |
264 | that._fnCollectionShow(); | |
265 | } ) | |
266 | .appendTo( this.dom.wrapper )[0]; | |
267 | ||
268 | this.dom.catcher = this._fnDomCatcher(); | |
269 | this.dom.collection = this._fnDomCollection(); | |
270 | this.dom.background = this._fnDomBackground(); | |
271 | ||
272 | this._fnAddGroups(); | |
273 | this._fnAddButtons(); | |
274 | ||
275 | /* Store the original visibility information */ | |
276 | for ( i=0, iLen=this.s.dt.aoColumns.length ; i<iLen ; i++ ) | |
277 | { | |
278 | this.s.abOriginal.push( this.s.dt.aoColumns[i].bVisible ); | |
279 | } | |
280 | ||
281 | /* Update on each draw */ | |
282 | this.s.dt.aoDrawCallback.push( { | |
283 | "fn": function () { | |
284 | that._fnDrawCallback.call( that ); | |
285 | }, | |
286 | "sName": "ColVis" | |
287 | } ); | |
288 | ||
289 | /* If columns are reordered, then we need to update our exclude list and | |
290 | * rebuild the displayed list | |
291 | */ | |
292 | $(this.s.dt.oInstance).bind( 'column-reorder.dt', function ( e, oSettings, oReorder ) { | |
293 | for ( i=0, iLen=that.s.aiExclude.length ; i<iLen ; i++ ) { | |
294 | that.s.aiExclude[i] = oReorder.aiInvertMapping[ that.s.aiExclude[i] ]; | |
295 | } | |
296 | ||
297 | var mStore = that.s.abOriginal.splice( oReorder.iFrom, 1 )[0]; | |
298 | that.s.abOriginal.splice( oReorder.iTo, 0, mStore ); | |
299 | ||
300 | that.fnRebuild(); | |
301 | } ); | |
302 | ||
303 | $(this.s.dt.oInstance).bind( 'destroy.dt', function () { | |
304 | $(that.dom.wrapper).remove(); | |
305 | } ); | |
306 | ||
307 | // Set the initial state | |
308 | this._fnDrawCallback(); | |
309 | }, | |
310 | ||
311 | ||
312 | /** | |
313 | * Apply any customisation to the settings from the DataTables initialisation | |
314 | * @method _fnApplyCustomisation | |
315 | * @returns void | |
316 | * @private | |
317 | */ | |
318 | "_fnApplyCustomisation": function ( init ) | |
319 | { | |
320 | $.extend( true, this.s, ColVis.defaults, init ); | |
321 | ||
322 | // Slightly messy overlap for the camelCase notation | |
323 | if ( ! this.s.showAll && this.s.bShowAll ) { | |
324 | this.s.showAll = this.s.sShowAll; | |
325 | } | |
326 | ||
327 | if ( ! this.s.restore && this.s.bRestore ) { | |
328 | this.s.restore = this.s.sRestore; | |
329 | } | |
330 | ||
331 | // CamelCase to Hungarian for the column groups | |
332 | var groups = this.s.groups; | |
333 | var hungarianGroups = this.s.aoGroups; | |
334 | if ( groups ) { | |
335 | for ( var i=0, ien=groups.length ; i<ien ; i++ ) { | |
336 | if ( groups[i].title ) { | |
337 | hungarianGroups[i].sTitle = groups[i].title; | |
338 | } | |
339 | if ( groups[i].columns ) { | |
340 | hungarianGroups[i].aiColumns = groups[i].columns; | |
341 | } | |
342 | } | |
343 | } | |
344 | }, | |
345 | ||
346 | ||
347 | /** | |
348 | * On each table draw, check the visibility checkboxes as needed. This allows any process to | |
349 | * update the table's column visibility and ColVis will still be accurate. | |
350 | * @method _fnDrawCallback | |
351 | * @returns void | |
352 | * @private | |
353 | */ | |
354 | "_fnDrawCallback": function () | |
355 | { | |
356 | var columns = this.s.dt.aoColumns; | |
357 | var buttons = this.dom.buttons; | |
358 | var groups = this.s.aoGroups; | |
359 | var button; | |
360 | ||
361 | for ( var i=0, ien=buttons.length ; i<ien ; i++ ) { | |
362 | button = buttons[i]; | |
363 | ||
364 | if ( button.__columnIdx !== undefined ) { | |
365 | $('input', button).prop( 'checked', columns[ button.__columnIdx ].bVisible ); | |
366 | } | |
367 | } | |
368 | ||
369 | var allVisible = function ( columnIndeces ) { | |
370 | for ( var k=0, kLen=columnIndeces.length ; k<kLen ; k++ ) | |
371 | { | |
372 | if ( columns[columnIndeces[k]].bVisible === false ) { return false; } | |
373 | } | |
374 | return true; | |
375 | }; | |
376 | var allHidden = function ( columnIndeces ) { | |
377 | for ( var m=0 , mLen=columnIndeces.length ; m<mLen ; m++ ) | |
378 | { | |
379 | if ( columns[columnIndeces[m]].bVisible === true ) { return false; } | |
380 | } | |
381 | return true; | |
382 | }; | |
383 | ||
384 | for ( var j=0, jLen=groups.length ; j<jLen ; j++ ) | |
385 | { | |
386 | if ( allVisible(groups[j].aiColumns) ) | |
387 | { | |
388 | $('input', this.dom.groupButtons[j]).prop('checked', true); | |
389 | $('input', this.dom.groupButtons[j]).prop('indeterminate', false); | |
390 | } | |
391 | else if ( allHidden(groups[j].aiColumns) ) | |
392 | { | |
393 | $('input', this.dom.groupButtons[j]).prop('checked', false); | |
394 | $('input', this.dom.groupButtons[j]).prop('indeterminate', false); | |
395 | } | |
396 | else | |
397 | { | |
398 | $('input', this.dom.groupButtons[j]).prop('indeterminate', true); | |
399 | } | |
400 | } | |
401 | }, | |
402 | ||
403 | ||
404 | /** | |
405 | * Loop through the groups (provided in the settings) and create a button for each. | |
406 | * @method _fnAddgroups | |
407 | * @returns void | |
408 | * @private | |
409 | */ | |
410 | "_fnAddGroups": function () | |
411 | { | |
412 | var nButton; | |
413 | ||
414 | if ( typeof this.s.aoGroups != 'undefined' ) | |
415 | { | |
416 | for ( var i=0, iLen=this.s.aoGroups.length ; i<iLen ; i++ ) | |
417 | { | |
418 | nButton = this._fnDomGroupButton( i ); | |
419 | this.dom.groupButtons.push( nButton ); | |
420 | this.dom.buttons.push( nButton ); | |
421 | this.dom.collection.appendChild( nButton ); | |
422 | } | |
423 | } | |
424 | }, | |
425 | ||
426 | ||
427 | /** | |
428 | * Loop through the columns in the table and as a new button for each one. | |
429 | * @method _fnAddButtons | |
430 | * @returns void | |
431 | * @private | |
432 | */ | |
433 | "_fnAddButtons": function () | |
434 | { | |
435 | var | |
436 | nButton, | |
437 | columns = this.s.dt.aoColumns; | |
438 | ||
439 | if ( $.inArray( 'all', this.s.aiExclude ) === -1 ) { | |
440 | for ( var i=0, iLen=columns.length ; i<iLen ; i++ ) | |
441 | { | |
442 | if ( $.inArray( i, this.s.aiExclude ) === -1 ) | |
443 | { | |
444 | nButton = this._fnDomColumnButton( i ); | |
445 | nButton.__columnIdx = i; | |
446 | this.dom.buttons.push( nButton ); | |
447 | } | |
448 | } | |
449 | } | |
450 | ||
451 | if ( this.s.order === 'alpha' ) { | |
452 | this.dom.buttons.sort( function ( a, b ) { | |
453 | var titleA = columns[ a.__columnIdx ].sTitle; | |
454 | var titleB = columns[ b.__columnIdx ].sTitle; | |
455 | ||
456 | return titleA === titleB ? | |
457 | 0 : | |
458 | titleA < titleB ? | |
459 | -1 : | |
460 | 1; | |
461 | } ); | |
462 | } | |
463 | ||
464 | if ( this.s.restore ) | |
465 | { | |
466 | nButton = this._fnDomRestoreButton(); | |
467 | nButton.className += " ColVis_Restore"; | |
468 | this.dom.buttons.push( nButton ); | |
469 | } | |
470 | ||
471 | if ( this.s.showAll ) | |
472 | { | |
473 | nButton = this._fnDomShowXButton( this.s.showAll, true ); | |
474 | nButton.className += " ColVis_ShowAll"; | |
475 | this.dom.buttons.push( nButton ); | |
476 | } | |
477 | ||
478 | if ( this.s.showNone ) | |
479 | { | |
480 | nButton = this._fnDomShowXButton( this.s.showNone, false ); | |
481 | nButton.className += " ColVis_ShowNone"; | |
482 | this.dom.buttons.push( nButton ); | |
483 | } | |
484 | ||
485 | $(this.dom.collection).append( this.dom.buttons ); | |
486 | }, | |
487 | ||
488 | ||
489 | /** | |
490 | * Create a button which allows a "restore" action | |
491 | * @method _fnDomRestoreButton | |
492 | * @returns {Node} Created button | |
493 | * @private | |
494 | */ | |
495 | "_fnDomRestoreButton": function () | |
496 | { | |
497 | var | |
498 | that = this, | |
499 | dt = this.s.dt; | |
500 | ||
501 | return $( | |
502 | '<li class="ColVis_Special '+(dt.bJUI ? 'ui-button ui-state-default' : '')+'">'+ | |
503 | this.s.restore+ | |
504 | '</li>' | |
505 | ) | |
506 | .click( function (e) { | |
507 | for ( var i=0, iLen=that.s.abOriginal.length ; i<iLen ; i++ ) | |
508 | { | |
509 | that.s.dt.oInstance.fnSetColumnVis( i, that.s.abOriginal[i], false ); | |
510 | } | |
511 | that._fnAdjustOpenRows(); | |
512 | that.s.dt.oInstance.fnAdjustColumnSizing( false ); | |
513 | that.s.dt.oInstance.fnDraw( false ); | |
514 | } )[0]; | |
515 | }, | |
516 | ||
517 | ||
518 | /** | |
519 | * Create a button which allows show all and show node actions | |
520 | * @method _fnDomShowXButton | |
521 | * @returns {Node} Created button | |
522 | * @private | |
523 | */ | |
524 | "_fnDomShowXButton": function ( str, action ) | |
525 | { | |
526 | var | |
527 | that = this, | |
528 | dt = this.s.dt; | |
529 | ||
530 | return $( | |
531 | '<li class="ColVis_Special '+(dt.bJUI ? 'ui-button ui-state-default' : '')+'">'+ | |
532 | str+ | |
533 | '</li>' | |
534 | ) | |
535 | .click( function (e) { | |
536 | for ( var i=0, iLen=that.s.abOriginal.length ; i<iLen ; i++ ) | |
537 | { | |
538 | if (that.s.aiExclude.indexOf(i) === -1) | |
539 | { | |
540 | that.s.dt.oInstance.fnSetColumnVis( i, action, false ); | |
541 | } | |
542 | } | |
543 | that._fnAdjustOpenRows(); | |
544 | that.s.dt.oInstance.fnAdjustColumnSizing( false ); | |
545 | that.s.dt.oInstance.fnDraw( false ); | |
546 | } )[0]; | |
547 | }, | |
548 | ||
549 | ||
550 | /** | |
551 | * Create the DOM for a show / hide group button | |
552 | * @method _fnDomGroupButton | |
553 | * @param {int} i Group in question, order based on that provided in settings | |
554 | * @returns {Node} Created button | |
555 | * @private | |
556 | */ | |
557 | "_fnDomGroupButton": function ( i ) | |
558 | { | |
559 | var | |
560 | that = this, | |
561 | dt = this.s.dt, | |
562 | oGroup = this.s.aoGroups[i]; | |
563 | ||
564 | return $( | |
565 | '<li class="ColVis_Special '+(dt.bJUI ? 'ui-button ui-state-default' : '')+'">'+ | |
566 | '<label>'+ | |
567 | '<input type="checkbox" />'+ | |
568 | '<span>'+oGroup.sTitle+'</span>'+ | |
569 | '</label>'+ | |
570 | '</li>' | |
571 | ) | |
572 | .click( function (e) { | |
573 | var showHide = !$('input', this).is(":checked"); | |
574 | if ( e.target.nodeName.toLowerCase() !== "li" ) | |
575 | { | |
576 | showHide = ! showHide; | |
577 | } | |
578 | ||
579 | for ( var j=0 ; j < oGroup.aiColumns.length ; j++ ) | |
580 | { | |
581 | that.s.dt.oInstance.fnSetColumnVis( oGroup.aiColumns[j], showHide ); | |
582 | } | |
583 | } )[0]; | |
584 | }, | |
585 | ||
586 | ||
587 | /** | |
588 | * Create the DOM for a show / hide button | |
589 | * @method _fnDomColumnButton | |
590 | * @param {int} i Column in question | |
591 | * @returns {Node} Created button | |
592 | * @private | |
593 | */ | |
594 | "_fnDomColumnButton": function ( i ) | |
595 | { | |
596 | var | |
597 | that = this, | |
598 | column = this.s.dt.aoColumns[i], | |
599 | dt = this.s.dt; | |
600 | ||
601 | var title = this.s.fnLabel===null ? | |
602 | column.sTitle : | |
603 | this.s.fnLabel( i, column.sTitle, column.nTh ); | |
604 | ||
605 | return $( | |
606 | '<li '+(dt.bJUI ? 'class="ui-button ui-state-default"' : '')+'>'+ | |
607 | '<label>'+ | |
608 | '<input type="checkbox" />'+ | |
609 | '<span>'+title+'</span>'+ | |
610 | '</label>'+ | |
611 | '</li>' | |
612 | ) | |
613 | .click( function (e) { | |
614 | var showHide = !$('input', this).is(":checked"); | |
615 | if ( e.target.nodeName.toLowerCase() !== "li" ) | |
616 | { | |
617 | if ( e.target.nodeName.toLowerCase() == "input" || that.s.fnStateChange === null ) | |
618 | { | |
619 | showHide = ! showHide; | |
620 | } | |
621 | } | |
622 | ||
623 | /* Need to consider the case where the initialiser created more than one table - change the | |
624 | * API index that DataTables is using | |
625 | */ | |
626 | var oldIndex = $.fn.dataTableExt.iApiIndex; | |
627 | $.fn.dataTableExt.iApiIndex = that._fnDataTablesApiIndex.call(that); | |
628 | ||
629 | // Optimisation for server-side processing when scrolling - don't do a full redraw | |
630 | if ( dt.oFeatures.bServerSide ) | |
631 | { | |
632 | that.s.dt.oInstance.fnSetColumnVis( i, showHide, false ); | |
633 | that.s.dt.oInstance.fnAdjustColumnSizing( false ); | |
634 | if (dt.oScroll.sX !== "" || dt.oScroll.sY !== "" ) | |
635 | { | |
636 | that.s.dt.oInstance.oApi._fnScrollDraw( that.s.dt ); | |
637 | } | |
638 | that._fnDrawCallback(); | |
639 | } | |
640 | else | |
641 | { | |
642 | that.s.dt.oInstance.fnSetColumnVis( i, showHide ); | |
643 | } | |
644 | ||
645 | $.fn.dataTableExt.iApiIndex = oldIndex; /* Restore */ | |
646 | ||
647 | if ( that.s.fnStateChange !== null ) | |
648 | { | |
649 | if ( e.target.nodeName.toLowerCase() == "span" ) | |
650 | { | |
651 | e.preventDefault(); | |
652 | } | |
653 | that.s.fnStateChange.call( that, i, showHide ); | |
654 | } | |
655 | } )[0]; | |
656 | }, | |
657 | ||
658 | ||
659 | /** | |
660 | * Get the position in the DataTables instance array of the table for this | |
661 | * instance of ColVis | |
662 | * @method _fnDataTablesApiIndex | |
663 | * @returns {int} Index | |
664 | * @private | |
665 | */ | |
666 | "_fnDataTablesApiIndex": function () | |
667 | { | |
668 | for ( var i=0, iLen=this.s.dt.oInstance.length ; i<iLen ; i++ ) | |
669 | { | |
670 | if ( this.s.dt.oInstance[i] == this.s.dt.nTable ) | |
671 | { | |
672 | return i; | |
673 | } | |
674 | } | |
675 | return 0; | |
676 | }, | |
677 | ||
678 | ||
679 | /** | |
680 | * Create the element used to contain list the columns (it is shown and | |
681 | * hidden as needed) | |
682 | * @method _fnDomCollection | |
683 | * @returns {Node} div container for the collection | |
684 | * @private | |
685 | */ | |
686 | "_fnDomCollection": function () | |
687 | { | |
688 | return $('<ul />', { | |
689 | 'class': !this.s.dt.bJUI ? | |
690 | "ColVis_collection" : | |
691 | "ColVis_collection ui-buttonset ui-buttonset-multi" | |
692 | } ) | |
693 | .css( { | |
694 | 'display': 'none', | |
695 | 'opacity': 0, | |
696 | 'position': ! this.s.bCssPosition ? | |
697 | 'absolute' : | |
698 | '' | |
699 | } )[0]; | |
700 | }, | |
701 | ||
702 | ||
703 | /** | |
704 | * An element to be placed on top of the activate button to catch events | |
705 | * @method _fnDomCatcher | |
706 | * @returns {Node} div container for the collection | |
707 | * @private | |
708 | */ | |
709 | "_fnDomCatcher": function () | |
710 | { | |
711 | var | |
712 | that = this, | |
713 | nCatcher = document.createElement('div'); | |
714 | nCatcher.className = "ColVis_catcher"; | |
715 | ||
716 | $(nCatcher).click( function () { | |
717 | that._fnCollectionHide.call( that, null, null ); | |
718 | } ); | |
719 | ||
720 | return nCatcher; | |
721 | }, | |
722 | ||
723 | ||
724 | /** | |
725 | * Create the element used to shade the background, and capture hide events (it is shown and | |
726 | * hidden as needed) | |
727 | * @method _fnDomBackground | |
728 | * @returns {Node} div container for the background | |
729 | * @private | |
730 | */ | |
731 | "_fnDomBackground": function () | |
732 | { | |
733 | var that = this; | |
734 | ||
735 | var background = $('<div></div>') | |
736 | .addClass( 'ColVis_collectionBackground' ) | |
737 | .css( 'opacity', 0 ) | |
738 | .click( function () { | |
739 | that._fnCollectionHide.call( that, null, null ); | |
740 | } ); | |
741 | ||
742 | /* When considering a mouse over action for the activation, we also consider a mouse out | |
743 | * which is the same as a mouse over the background - without all the messing around of | |
744 | * bubbling events. Use the catcher element to avoid messing around with bubbling | |
745 | */ | |
746 | if ( this.s.activate == "mouseover" ) | |
747 | { | |
748 | background.mouseover( function () { | |
749 | that.s.overcollection = false; | |
750 | that._fnCollectionHide.call( that, null, null ); | |
751 | } ); | |
752 | } | |
753 | ||
754 | return background[0]; | |
755 | }, | |
756 | ||
757 | ||
758 | /** | |
759 | * Show the show / hide list and the background | |
760 | * @method _fnCollectionShow | |
761 | * @returns void | |
762 | * @private | |
763 | */ | |
764 | "_fnCollectionShow": function () | |
765 | { | |
766 | var that = this, i, iLen, iLeft; | |
767 | var oPos = $(this.dom.button).offset(); | |
768 | var nHidden = this.dom.collection; | |
769 | var nBackground = this.dom.background; | |
770 | var iDivX = parseInt(oPos.left, 10); | |
771 | var iDivY = parseInt(oPos.top + $(this.dom.button).outerHeight(), 10); | |
772 | ||
773 | if ( ! this.s.bCssPosition ) | |
774 | { | |
775 | nHidden.style.top = iDivY+"px"; | |
776 | nHidden.style.left = iDivX+"px"; | |
777 | } | |
778 | ||
779 | $(nHidden).css( { | |
780 | 'display': 'block', | |
781 | 'opacity': 0 | |
782 | } ); | |
783 | ||
784 | nBackground.style.bottom ='0px'; | |
785 | nBackground.style.right = '0px'; | |
786 | ||
787 | var oStyle = this.dom.catcher.style; | |
788 | oStyle.height = $(this.dom.button).outerHeight()+"px"; | |
789 | oStyle.width = $(this.dom.button).outerWidth()+"px"; | |
790 | oStyle.top = oPos.top+"px"; | |
791 | oStyle.left = iDivX+"px"; | |
792 | ||
793 | document.body.appendChild( nBackground ); | |
794 | document.body.appendChild( nHidden ); | |
795 | document.body.appendChild( this.dom.catcher ); | |
796 | ||
797 | /* This results in a very small delay for the end user but it allows the animation to be | |
798 | * much smoother. If you don't want the animation, then the setTimeout can be removed | |
799 | */ | |
800 | $(nHidden).animate({"opacity": 1}, that.s.iOverlayFade); | |
801 | $(nBackground).animate({"opacity": 0.1}, that.s.iOverlayFade, 'linear', function () { | |
802 | /* In IE6 if you set the checked attribute of a hidden checkbox, then this is not visually | |
803 | * reflected. As such, we need to do it here, once it is visible. Unbelievable. | |
804 | */ | |
805 | if ( $.browser && $.browser.msie && $.browser.version == "6.0" ) | |
806 | { | |
807 | that._fnDrawCallback(); | |
808 | } | |
809 | }); | |
810 | ||
811 | /* Visual corrections to try and keep the collection visible */ | |
812 | if ( !this.s.bCssPosition ) | |
813 | { | |
814 | iLeft = ( this.s.sAlign=="left" ) ? | |
815 | iDivX : | |
816 | iDivX - $(nHidden).outerWidth() + $(this.dom.button).outerWidth(); | |
817 | ||
818 | nHidden.style.left = iLeft+"px"; | |
819 | ||
820 | var iDivWidth = $(nHidden).outerWidth(); | |
821 | var iDivHeight = $(nHidden).outerHeight(); | |
822 | var iDocWidth = $(document).width(); | |
823 | ||
824 | if ( iLeft + iDivWidth > iDocWidth ) | |
825 | { | |
826 | nHidden.style.left = (iDocWidth-iDivWidth)+"px"; | |
827 | } | |
828 | } | |
829 | ||
830 | this.s.hidden = false; | |
831 | }, | |
832 | ||
833 | ||
834 | /** | |
835 | * Hide the show / hide list and the background | |
836 | * @method _fnCollectionHide | |
837 | * @returns void | |
838 | * @private | |
839 | */ | |
840 | "_fnCollectionHide": function ( ) | |
841 | { | |
842 | var that = this; | |
843 | ||
844 | if ( !this.s.hidden && this.dom.collection !== null ) | |
845 | { | |
846 | this.s.hidden = true; | |
847 | ||
848 | $(this.dom.collection).animate({"opacity": 0}, that.s.iOverlayFade, function (e) { | |
849 | this.style.display = "none"; | |
850 | } ); | |
851 | ||
852 | $(this.dom.background).animate({"opacity": 0}, that.s.iOverlayFade, function (e) { | |
853 | document.body.removeChild( that.dom.background ); | |
854 | document.body.removeChild( that.dom.catcher ); | |
855 | } ); | |
856 | } | |
857 | }, | |
858 | ||
859 | ||
860 | /** | |
861 | * Alter the colspan on any fnOpen rows | |
862 | */ | |
863 | "_fnAdjustOpenRows": function () | |
864 | { | |
865 | var aoOpen = this.s.dt.aoOpenRows; | |
866 | var iVisible = this.s.dt.oApi._fnVisbleColumns( this.s.dt ); | |
867 | ||
868 | for ( var i=0, iLen=aoOpen.length ; i<iLen ; i++ ) { | |
869 | aoOpen[i].nTr.getElementsByTagName('td')[0].colSpan = iVisible; | |
870 | } | |
871 | } | |
872 | }; | |
873 | ||
874 | ||
875 | ||
876 | ||
877 | ||
878 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | |
879 | * Static object methods | |
880 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | |
881 | ||
882 | /** | |
883 | * Rebuild the collection for a given table, or all tables if no parameter given | |
884 | * @method ColVis.fnRebuild | |
885 | * @static | |
886 | * @param object oTable DataTable instance to consider - optional | |
887 | * @returns void | |
888 | */ | |
889 | ColVis.fnRebuild = function ( oTable ) | |
890 | { | |
891 | var nTable = null; | |
892 | if ( typeof oTable != 'undefined' ) | |
893 | { | |
894 | nTable = $.fn.dataTable.Api ? | |
895 | new $.fn.dataTable.Api( oTable ).table().node() : | |
896 | oTable.fnSettings().nTable; | |
897 | } | |
898 | ||
899 | for ( var i=0, iLen=ColVis.aInstances.length ; i<iLen ; i++ ) | |
900 | { | |
901 | if ( typeof oTable == 'undefined' || nTable == ColVis.aInstances[i].s.dt.nTable ) | |
902 | { | |
903 | ColVis.aInstances[i].fnRebuild(); | |
904 | } | |
905 | } | |
906 | }; | |
907 | ||
908 | ||
909 | ColVis.defaults = { | |
910 | /** | |
911 | * Mode of activation. Can be 'click' or 'mouseover' | |
912 | * @property activate | |
913 | * @type string | |
914 | * @default click | |
915 | */ | |
916 | active: 'click', | |
917 | ||
918 | /** | |
919 | * Text used for the button | |
920 | * @property buttonText | |
921 | * @type string | |
922 | * @default Show / hide columns | |
923 | */ | |
924 | buttonText: 'Show / hide columns', | |
925 | ||
926 | /** | |
927 | * List of columns (integers) which should be excluded from the list | |
928 | * @property aiExclude | |
929 | * @type array | |
930 | * @default [] | |
931 | */ | |
932 | aiExclude: [], | |
933 | ||
934 | /** | |
935 | * Show restore button | |
936 | * @property bRestore | |
937 | * @type boolean | |
938 | * @default false | |
939 | */ | |
940 | bRestore: false, | |
941 | ||
942 | /** | |
943 | * Restore button text | |
944 | * @property sRestore | |
945 | * @type string | |
946 | * @default Restore original | |
947 | */ | |
948 | sRestore: 'Restore original', | |
949 | ||
950 | /** | |
951 | * Show Show-All button | |
952 | * @property bShowAll | |
953 | * @type boolean | |
954 | * @default false | |
955 | */ | |
956 | bShowAll: false, | |
957 | ||
958 | /** | |
959 | * Show All button text | |
960 | * @property sShowAll | |
961 | * @type string | |
962 | * @default Restore original | |
963 | */ | |
964 | sShowAll: 'Show All', | |
965 | ||
966 | /** | |
967 | * Position of the collection menu when shown - align "left" or "right" | |
968 | * @property sAlign | |
969 | * @type string | |
970 | * @default left | |
971 | */ | |
972 | sAlign: 'left', | |
973 | ||
974 | /** | |
975 | * Callback function to tell the user when the state has changed | |
976 | * @property fnStateChange | |
977 | * @type function | |
978 | * @default null | |
979 | */ | |
980 | fnStateChange: null, | |
981 | ||
982 | /** | |
983 | * Overlay animation duration in mS | |
984 | * @property iOverlayFade | |
985 | * @type integer|false | |
986 | * @default 500 | |
987 | */ | |
988 | iOverlayFade: 500, | |
989 | ||
990 | /** | |
991 | * Label callback for column names. Takes three parameters: 1. the | |
992 | * column index, 2. the column title detected by DataTables and 3. the | |
993 | * TH node for the column | |
994 | * @property fnLabel | |
995 | * @type function | |
996 | * @default null | |
997 | */ | |
998 | fnLabel: null, | |
999 | ||
1000 | /** | |
1001 | * Indicate if the column list should be positioned by Javascript, | |
1002 | * visually below the button or allow CSS to do the positioning | |
1003 | * @property bCssPosition | |
1004 | * @type boolean | |
1005 | * @default false | |
1006 | */ | |
1007 | bCssPosition: false, | |
1008 | ||
1009 | /** | |
1010 | * Group buttons | |
1011 | * @property aoGroups | |
1012 | * @type array | |
1013 | * @default [] | |
1014 | */ | |
1015 | aoGroups: [], | |
1016 | ||
1017 | /** | |
1018 | * Button ordering - 'alpha' (alphabetical) or 'column' (table column | |
1019 | * order) | |
1020 | * @property order | |
1021 | * @type string | |
1022 | * @default column | |
1023 | */ | |
1024 | order: 'column' | |
1025 | }; | |
1026 | ||
1027 | ||
1028 | ||
1029 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | |
1030 | * Static object properties | |
1031 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | |
1032 | ||
1033 | /** | |
1034 | * Collection of all ColVis instances | |
1035 | * @property ColVis.aInstances | |
1036 | * @static | |
1037 | * @type Array | |
1038 | * @default [] | |
1039 | */ | |
1040 | ColVis.aInstances = []; | |
1041 | ||
1042 | ||
1043 | ||
1044 | ||
1045 | ||
1046 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | |
1047 | * Constants | |
1048 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | |
1049 | ||
1050 | /** | |
1051 | * Name of this class | |
1052 | * @constant CLASS | |
1053 | * @type String | |
1054 | * @default ColVis | |
1055 | */ | |
1056 | ColVis.prototype.CLASS = "ColVis"; | |
1057 | ||
1058 | ||
1059 | /** | |
1060 | * ColVis version | |
1061 | * @constant VERSION | |
1062 | * @type String | |
1063 | * @default See code | |
1064 | */ | |
1065 | ColVis.VERSION = "1.1.2"; | |
1066 | ColVis.prototype.VERSION = ColVis.VERSION; | |
1067 | ||
1068 | ||
1069 | ||
1070 | ||
1071 | ||
1072 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | |
1073 | * Initialisation | |
1074 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | |
1075 | ||
1076 | /* | |
1077 | * Register a new feature with DataTables | |
1078 | */ | |
1079 | if ( typeof $.fn.dataTable == "function" && | |
1080 | typeof $.fn.dataTableExt.fnVersionCheck == "function" && | |
1081 | $.fn.dataTableExt.fnVersionCheck('1.7.0') ) | |
1082 | { | |
1083 | $.fn.dataTableExt.aoFeatures.push( { | |
1084 | "fnInit": function( oDTSettings ) { | |
1085 | var init = oDTSettings.oInit; | |
1086 | var colvis = new ColVis( oDTSettings, init.colVis || init.oColVis || {} ); | |
1087 | return colvis.button(); | |
1088 | }, | |
1089 | "cFeature": "C", | |
1090 | "sFeature": "ColVis" | |
1091 | } ); | |
1092 | } | |
1093 | else | |
1094 | { | |
1095 | alert( "Warning: ColVis requires DataTables 1.7 or greater - www.datatables.net/download"); | |
1096 | } | |
1097 | ||
1098 | ||
1099 | // Make ColVis accessible from the DataTables instance | |
1100 | $.fn.dataTable.ColVis = ColVis; | |
1101 | $.fn.DataTable.ColVis = ColVis; | |
1102 | ||
1103 | ||
1104 | return ColVis; | |
1105 | }; // /factory | |
1106 | ||
1107 | ||
1108 | // Define as an AMD module if possible | |
1109 | if ( typeof define === 'function' && define.amd ) { | |
1110 | define( ['jquery', 'datatables'], factory ); | |
1111 | } | |
1112 | else if ( typeof exports === 'object' ) { | |
1113 | // Node/CommonJS | |
1114 | factory( require('jquery'), require('datatables') ); | |
1115 | } | |
1116 | else if ( jQuery && !jQuery.fn.dataTable.ColVis ) { | |
1117 | // Otherwise simply initialise as normal, stopping multiple evaluation | |
1118 | factory( jQuery, jQuery.fn.dataTable ); | |
1119 | } | |
1120 | ||
1121 | ||
1122 | })(window, document); | |
1123 |