Bug 8099: DataTables integration in acquisition module [2]
[koha.git] / koha-tmpl / intranet-tmpl / prog / en / js / datatables.js
1 // These default options are for translation but can be used
2 // for any other datatables settings
3 // MSG_DT_* variables comes from datatables-strings.inc
4 // To use it, write:
5 //  $("#table_id").dataTable($.extend(true, {}, dataTableDefaults, {
6 //      // other settings
7 //  } ) );
8 var dataTablesDefaults = {
9     "oLanguage": {
10         "oPaginate": {
11             "sFirst"    : window.MSG_DT_FIRST || "First",
12             "sLast"     : window.MSG_DT_LAST || "Last",
13             "sNext"     : window.MSG_DT_NEXT || "Next",
14             "sPrevious" : window.MSG_DT_PREVIOUS || "Previous"
15         },
16         "sEmptyTable"       : window.MSG_DT_EMPTY_TABLE || "No data available in table",
17         "sInfo"             : window.MSG_DT_INFO || "Showing _START_ to _END_ of _TOTAL_ entries",
18         "sInfoEmpty"        : window.MSG_DT_INFO_EMPTY || "No entries to show",
19         "sInfoFiltered"     : window.MSG_DT_INFO_FILTERED || "(filtered from _MAX_ total entries)",
20         "sLengthMenu"       : window.MSG_DT_LENGTH_MENU || "Show _MENU_ entries",
21         "sLoadingRecords"   : window.MSG_DT_LOADING_RECORDS || "Loading...",
22         "sProcessing"       : window.MSG_DT_PROCESSING || "Processing...",
23         "sSearch"           : window.MSG_DT_SEARCH || "Search:",
24         "sZeroRecords"      : window.MSG_DT_ZERO_RECORDS || "No matching records found"
25     },
26     "sDom": '<"top pager"ilpf>t<"bottom pager"ip>'
27 };
28
29
30 // Return an array of string containing the values of a particular column
31 $.fn.dataTableExt.oApi.fnGetColumnData = function ( oSettings, iColumn, bUnique, bFiltered, bIgnoreEmpty ) {
32     // check that we have a column id
33     if ( typeof iColumn == "undefined" ) return new Array();
34     // by default we only wany unique data
35     if ( typeof bUnique == "undefined" ) bUnique = true;
36     // by default we do want to only look at filtered data
37     if ( typeof bFiltered == "undefined" ) bFiltered = true;
38     // by default we do not wany to include empty values
39     if ( typeof bIgnoreEmpty == "undefined" ) bIgnoreEmpty = true;
40     // list of rows which we're going to loop through
41     var aiRows;
42     // use only filtered rows
43     if (bFiltered == true) aiRows = oSettings.aiDisplay;
44     // use all rows
45     else aiRows = oSettings.aiDisplayMaster; // all row numbers
46
47     // set up data array
48     var asResultData = new Array();
49     for (var i=0,c=aiRows.length; i<c; i++) {
50         iRow = aiRows[i];
51         var aData = this.fnGetData(iRow);
52         var sValue = aData[iColumn];
53         // ignore empty values?
54         if (bIgnoreEmpty == true && sValue.length == 0) continue;
55         // ignore unique values?
56         else if (bUnique == true && jQuery.inArray(sValue, asResultData) > -1) continue;
57         // else push the value onto the result data array
58         else asResultData.push(sValue);
59     }
60     return asResultData;
61 }
62
63 // List of unbind keys (Ctrl, Alt, Direction keys, etc.)
64 // These keys must not launch filtering
65 var blacklist_keys = new Array(0, 16, 17, 18, 37, 38, 39, 40);
66
67 // Set a filtering delay for global search field
68 jQuery.fn.dataTableExt.oApi.fnSetFilteringDelay = function ( oSettings, iDelay ) {
69     /*
70      * Inputs:      object:oSettings - dataTables settings object - automatically given
71      *              integer:iDelay - delay in milliseconds
72      * Usage:       $('#example').dataTable().fnSetFilteringDelay(250);
73      * Author:      Zygimantas Berziunas (www.zygimantas.com) and Allan Jardine
74      * License:     GPL v2 or BSD 3 point style
75      * Contact:     zygimantas.berziunas /AT\ hotmail.com
76      */
77     var
78         _that = this,
79         iDelay = (typeof iDelay == 'undefined') ? 250 : iDelay;
80
81     this.each( function ( i ) {
82         $.fn.dataTableExt.iApiIndex = i;
83         var
84             $this = this,
85             oTimerId = null,
86             sPreviousSearch = null,
87             anControl = $( 'input', _that.fnSettings().aanFeatures.f );
88
89         anControl.unbind( 'keyup.DT' ).bind( 'keyup.DT', function(event) {
90             var $$this = $this;
91             if (blacklist_keys.indexOf(event.keyCode) != -1) {
92                 return this;
93             }else if ( event.keyCode == '13' ) {
94                 $.fn.dataTableExt.iApiIndex = i;
95                 _that.fnFilter( $(this).val() );
96             } else {
97                 if (sPreviousSearch === null || sPreviousSearch != anControl.val()) {
98                     window.clearTimeout(oTimerId);
99                     sPreviousSearch = anControl.val();
100                     oTimerId = window.setTimeout(function() {
101                         $.fn.dataTableExt.iApiIndex = i;
102                         _that.fnFilter( anControl.val() );
103                     }, iDelay);
104                 }
105             }
106         });
107
108         return this;
109     } );
110     return this;
111 }
112
113 // Add a filtering delay on general search and on all input (with a class 'filter')
114 jQuery.fn.dataTableExt.oApi.fnAddFilters = function ( oSettings, sClass, iDelay ) {
115     var table = this;
116     this.fnSetFilteringDelay(iDelay);
117     var filterTimerId = null;
118     $("input."+sClass).keyup(function(event) {
119       if (blacklist_keys.indexOf(event.keyCode) != -1) {
120         return this;
121       }else if ( event.keyCode == '13' ) {
122         table.fnFilter( $(this).val(), $(this).attr('data-column_num') );
123       } else {
124         window.clearTimeout(filterTimerId);
125         var input = this;
126         filterTimerId = window.setTimeout(function() {
127           table.fnFilter($(input).val(), $(input).attr('data-column_num'));
128         }, iDelay);
129       }
130     });
131 }
132
133 // Useful if you want to filter on dates with 2 inputs (start date and end date)
134 // You have to include calendar.inc to use it
135 function dt_add_rangedate_filter(begindate_id, enddate_id, dateCol) {
136     $.fn.dataTableExt.afnFiltering.push(
137         function( oSettings, aData, iDataIndex ) {
138
139             var beginDate = Date_from_syspref($("#"+begindate_id).val()).getTime();
140             var endDate   = Date_from_syspref($("#"+enddate_id).val()).getTime();
141
142             var data = Date_from_syspref(aData[dateCol]).getTime();
143
144             if ( !parseInt(beginDate) && ! parseInt(endDate) ) {
145                 return true;
146             }
147             else if ( beginDate <= data && !parseInt(endDate) ) {
148                 return true;
149             }
150             else if ( data <= endDate && !parseInt(beginDate) ) {
151                 return true;
152             }
153             else if ( beginDate <= data && data <= endDate) {
154                 return true;
155             }
156             return false;
157         }
158     );
159 }
160
161 //Sorting for dates (uk format)
162 function dt_add_type_uk_date() {
163   jQuery.fn.dataTableExt.aTypes.unshift(
164     function ( sData )
165     {
166       if (sData.match(/(0[1-9]|[12][0-9]|3[01])\/(0[1-9]|1[012])\/(19|20|21)\d\d/))
167       {
168         return 'uk_date';
169       }
170       return null;
171     }
172   );
173
174   jQuery.fn.dataTableExt.oSort['uk_date-asc']  = function(a,b) {
175     var re = /(\d{2}\/\d{2}\/\d{4})/;
176     a.match(re);
177     var ukDatea = RegExp.$1.split("/");
178     b.match(re);
179     var ukDateb = RegExp.$1.split("/");
180
181     var x = (ukDatea[2] + ukDatea[1] + ukDatea[0]) * 1;
182     var y = (ukDateb[2] + ukDateb[1] + ukDateb[0]) * 1;
183
184     return ((x < y) ? -1 : ((x > y) ?  1 : 0));
185   };
186
187   jQuery.fn.dataTableExt.oSort['uk_date-desc'] = function(a,b) {
188     var re = /(\d{2}\/\d{2}\/\d{4})/;
189     a.match(re);
190     var ukDatea = RegExp.$1.split("/");
191     b.match(re);
192     var ukDateb = RegExp.$1.split("/");
193
194     var x = (ukDatea[2] + ukDatea[1] + ukDatea[0]) * 1;
195     var y = (ukDateb[2] + ukDateb[1] + ukDateb[0]) * 1;
196
197     return ((x < y) ? 1 : ((x > y) ?  -1 : 0));
198   };
199 }
200
201 // Sorting on html contains
202 // <a href="foo.pl">bar</a> sort on 'bar'
203 function dt_overwrite_html_sorting_localeCompare() {
204     jQuery.fn.dataTableExt.oSort['html-asc']  = function(a,b) {
205         a = a.replace(/<.*?>/g, "").replace(/\s+/g, " ");
206         b = b.replace(/<.*?>/g, "").replace(/\s+/g, " ");
207         if (typeof(a.localeCompare == "function")) {
208            return a.localeCompare(b);
209         } else {
210            return (a > b) ? 1 : ((a < b) ? -1 : 0);
211         }
212     };
213
214     jQuery.fn.dataTableExt.oSort['html-desc'] = function(a,b) {
215         a = a.replace(/<.*?>/g, "").replace(/\s+/g, " ");
216         b = b.replace(/<.*?>/g, "").replace(/\s+/g, " ");
217         if(typeof(b.localeCompare == "function")) {
218             return b.localeCompare(a);
219         } else {
220             return (b > a) ? 1 : ((b < a) ? -1 : 0);
221         }
222     };
223
224     jQuery.fn.dataTableExt.oSort['num-html-asc']  = function(a,b) {
225         var x = a.replace( /<.*?>/g, "" );
226         var y = b.replace( /<.*?>/g, "" );
227         x = parseFloat( x );
228         y = parseFloat( y );
229         return ((x < y) ? -1 : ((x > y) ?  1 : 0));
230     };
231
232     jQuery.fn.dataTableExt.oSort['num-html-desc'] = function(a,b) {
233         var x = a.replace( /<.*?>/g, "" );
234         var y = b.replace( /<.*?>/g, "" );
235         x = parseFloat( x );
236         y = parseFloat( y );
237         return ((x < y) ?  1 : ((x > y) ? -1 : 0));
238     };
239 }
240
241 // Sorting on string without accentued characters
242 function dt_overwrite_string_sorting_localeCompare() {
243     jQuery.fn.dataTableExt.oSort['string-asc']  = function(a,b) {
244         a = a.replace(/<.*?>/g, "").replace(/\s+/g, " ");
245         b = b.replace(/<.*?>/g, "").replace(/\s+/g, " ");
246         if (typeof(a.localeCompare == "function")) {
247            return a.localeCompare(b);
248         } else {
249            return (a > b) ? 1 : ((a < b) ? -1 : 0);
250         }
251     };
252
253     jQuery.fn.dataTableExt.oSort['string-desc'] = function(a,b) {
254         a = a.replace(/<.*?>/g, "").replace(/\s+/g, " ");
255         b = b.replace(/<.*?>/g, "").replace(/\s+/g, " ");
256         if(typeof(b.localeCompare == "function")) {
257             return b.localeCompare(a);
258         } else {
259             return (b > a) ? 1 : ((b < a) ? -1 : 0);
260         }
261     };
262 }
263
264 // Replace a node with a html and js contain.
265 function replace_html( original_node, type ) {
266     switch ( $(original_node).attr('data-type') ) {
267         case "range_dates":
268             var id = $(original_node).attr("data-id");
269             var format = $(original_node).attr("data-format");
270             replace_html_date( original_node, id, format );
271             break;
272         default:
273             alert("_(This node can't be replaced)");
274     }
275 }
276
277 // Replace a node with a "From [date] To [date]" element
278 // Used on tfoot > td
279 function replace_html_date( original_node, id, format ) {
280     var node = $('<span style="white-space:nowrap">' + _("From") + '<input type="text" id="' + id + 'from" readonly="readonly" placeholder=\'' + _("Pick date") + '\' size="7" /><a title="Delete this filter" style="cursor:pointer" onclick=\'$("#' + id + 'from").val("").change();\' >&times;</a></span><br/><span style="white-space:nowrap">' + _("To") + '<input type="text" id="' + id + 'to" readonly="readonly" placeholder=\'' + _("Pick date") + '\' size="7" /><a title="Delete this filter" style="cursor:pointer" onclick=\'$("#' + id + 'to").val("").change();\' >&times;</a></span>');
281     $(original_node).replaceWith(node);
282     var script = document.createElement( 'script' );
283     script.type = 'text/javascript';
284     var script_content = "Calendar.setup({";
285     script_content += "    inputField: \"" + id + "from\",";
286     script_content += "    ifFormat: \"" + format + "\",";
287     script_content += "    button: \"" + id + "from\",";
288     script_content += "    onClose: function(){ $(\"#" + id + "from\").change(); this.hide();}";
289     script_content += "  });";
290     script_content += "  Calendar.setup({";
291     script_content += "    inputField: \"" + id + "to\",";
292     script_content += "    ifFormat: \"" + format + "\",";
293     script_content += "    button: \"" + id + "to\",";
294     script_content += "    onClose: function(){ $(\"#" + id + "to\").change(); this.hide();}";
295     script_content += "  });";
296     script.text = script_content;
297     $(original_node).append( script );
298 }
299
300 $.fn.dataTableExt.oPagination.four_button = {
301     /*
302      * Function: oPagination.four_button.fnInit
303      * Purpose:  Initalise dom elements required for pagination with a list of the pages
304      * Returns:  -
305      * Inputs:   object:oSettings - dataTables settings object
306      *           node:nPaging - the DIV which contains this pagination control
307      *           function:fnCallbackDraw - draw function which must be called on update
308      */
309     "fnInit": function ( oSettings, nPaging, fnCallbackDraw )
310     {
311         nFirst = document.createElement( 'span' );
312         nPrevious = document.createElement( 'span' );
313         nNext = document.createElement( 'span' );
314         nLast = document.createElement( 'span' );
315
316 /*        nFirst.appendChild( document.createTextNode( oSettings.oLanguage.oPaginate.sFirst ) );
317         nPrevious.appendChild( document.createTextNode( oSettings.oLanguage.oPaginate.sPrevious ) );
318         nNext.appendChild( document.createTextNode( oSettings.oLanguage.oPaginate.sNext ) );
319         nLast.appendChild( document.createTextNode( oSettings.oLanguage.oPaginate.sLast ) );*/
320
321         nFirst.className = "paginate_button first";
322         nPrevious.className = "paginate_button previous";
323         nNext.className="paginate_button next";
324         nLast.className = "paginate_button last";
325
326         nPaging.appendChild( nFirst );
327         nPaging.appendChild( nPrevious );
328         nPaging.appendChild( nNext );
329         nPaging.appendChild( nLast );
330
331         $(nFirst).click( function () {
332             oSettings.oApi._fnPageChange( oSettings, "first" );
333             fnCallbackDraw( oSettings );
334         } );
335
336         $(nPrevious).click( function() {
337             oSettings.oApi._fnPageChange( oSettings, "previous" );
338             fnCallbackDraw( oSettings );
339         } );
340
341         $(nNext).click( function() {
342             oSettings.oApi._fnPageChange( oSettings, "next" );
343             fnCallbackDraw( oSettings );
344         } );
345
346         $(nLast).click( function() {
347             oSettings.oApi._fnPageChange( oSettings, "last" );
348             fnCallbackDraw( oSettings );
349         } );
350
351         /* Disallow text selection */
352         $(nFirst).bind( 'selectstart', function () { return false; } );
353         $(nPrevious).bind( 'selectstart', function () { return false; } );
354         $(nNext).bind( 'selectstart', function () { return false; } );
355         $(nLast).bind( 'selectstart', function () { return false; } );
356     },
357
358     /*
359      * Function: oPagination.four_button.fnUpdate
360      * Purpose:  Update the list of page buttons shows
361      * Returns:  -
362      * Inputs:   object:oSettings - dataTables settings object
363      *           function:fnCallbackDraw - draw function which must be called on update
364      */
365     "fnUpdate": function ( oSettings, fnCallbackDraw )
366     {
367         if ( !oSettings.aanFeatures.p )
368         {
369             return;
370         }
371
372         /* Loop over each instance of the pager */
373         var an = oSettings.aanFeatures.p;
374         for ( var i=0, iLen=an.length ; i<iLen ; i++ )
375         {
376             var buttons = an[i].getElementsByTagName('span');
377             if ( oSettings._iDisplayStart === 0 )
378             {
379                 buttons[0].className = "paginate_disabled_first";
380                 buttons[1].className = "paginate_disabled_previous";
381             }
382             else
383             {
384                 buttons[0].className = "paginate_enabled_first";
385                 buttons[1].className = "paginate_enabled_previous";
386             }
387
388             if ( oSettings.fnDisplayEnd() == oSettings.fnRecordsDisplay() )
389             {
390                 buttons[2].className = "paginate_disabled_next";
391                 buttons[3].className = "paginate_disabled_last";
392             }
393             else
394             {
395                 buttons[2].className = "paginate_enabled_next";
396                 buttons[3].className = "paginate_enabled_last";
397             }
398         }
399     }
400 };