blob: f738144ae5618554ff1f07566c94139e66d2123f [file] [log] [blame]
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001'use strict';
2
3function tableInit(ctx){
4
5 if (ctx.url.length === 0) {
6 throw "No url supplied for retreiving data";
7 }
8
9 var tableChromeDone = false;
10 var tableTotal = 0;
11
12 var tableParams = {
13 limit : 25,
14 page : 1,
15 orderby : null,
16 filter : null,
17 search : null,
18 };
19
20 var defaultHiddenCols = [];
21
22 var table = $("#" + ctx.tableName);
23
24 /* if we're loading clean from a url use it's parameters as the default */
25 var urlParams = libtoaster.parseUrlParams();
26
27 /* Merge the tableParams and urlParams object properties */
28 tableParams = $.extend(tableParams, urlParams);
29
30 /* Now fix the types that .extend changed for us */
31 tableParams.limit = Number(tableParams.limit);
32 tableParams.page = Number(tableParams.page);
33
34 loadData(tableParams);
35
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050036 // clicking on this set of elements removes the search
37 var clearSearchElements = $('.remove-search-btn-'+ctx.tableName +
38 ', .show-all-'+ctx.tableName);
39
Patrick Williamsc124f4f2015-09-15 14:41:29 -050040 function loadData(tableParams){
41 $.ajax({
42 type: "GET",
43 url: ctx.url,
44 data: tableParams,
45 headers: { 'X-CSRFToken' : $.cookie('csrftoken')},
46 success: function(tableData) {
47 updateTable(tableData);
Patrick Williamsf1e5d692016-03-30 15:21:19 -050048 window.history.replaceState(null, null,
49 libtoaster.dumpsUrlParams(tableParams));
Patrick Williamsc124f4f2015-09-15 14:41:29 -050050 }
51 });
52 }
53
54 function updateTable(tableData) {
55 var tableBody = table.children("tbody");
56 var pagination = $('#pagination-'+ctx.tableName);
57 var paginationBtns = pagination.children('ul');
58 var tableContainer = $("#table-container-"+ctx.tableName);
59
60 tableContainer.css("visibility", "hidden");
61 /* To avoid page re-layout flicker when paging set fixed height */
62 table.css("padding-bottom", table.height());
63
64 /* Reset table components */
65 tableBody.html("");
66 paginationBtns.html("");
67
68 if (tableParams.search)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050069 clearSearchElements.show();
Patrick Williamsc124f4f2015-09-15 14:41:29 -050070 else
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050071 clearSearchElements.hide();
Patrick Williamsc124f4f2015-09-15 14:41:29 -050072
73 $('.table-count-' + ctx.tableName).text(tableData.total);
74 tableTotal = tableData.total;
75
76 if (tableData.total === 0){
77 tableContainer.hide();
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050078 if ($("#no-results-special-"+ctx.tableName).length > 0) {
79 /* use this page's special no-results form instead of the default */
80 $("#no-results-search-input-"+ctx.tableName).val(tableParams.search);
81 $("#no-results-special-"+ctx.tableName).show();
82 $("#results-found-"+ctx.tableName).hide();
83 } else {
Patrick Williamsc124f4f2015-09-15 14:41:29 -050084 $("#new-search-input-"+ctx.tableName).val(tableParams.search);
85 $("#no-results-"+ctx.tableName).show();
86 }
87 table.trigger("table-done", [tableData.total, tableParams]);
88
89 return;
Patrick Williamsc124f4f2015-09-15 14:41:29 -050090 } else {
91 tableContainer.show();
92 $("#no-results-"+ctx.tableName).hide();
93 }
94
95 setupTableChrome(tableData);
96
97 /* Add table data rows */
98 var column_index;
99 for (var i in tableData.rows){
100 /* only display if the column is display-able */
101 var row = $("<tr></tr>");
102 column_index = -1;
103 for (var key_j in tableData.rows[i]){
104
105 /* if we have a static: version of a key, prefer the static: version for rendering */
106 var orig_key_j = key_j;
107
108 if (key_j.indexOf("static:") === 0) {
109 if (key_j.substr("static:".length) in tableData.rows[i]) {
110 continue;
111 }
112 orig_key_j = key_j.substr("static:".length)
113 } else if (("static:" + key_j) in tableData.rows[i]) {
114 key_j = "static:" + key_j;
115 }
116
117 /* we skip over un-displayable column entries */
118 column_index += 1;
119 if (! tableData.columns[column_index].displayable) {
120 continue;
121 }
122
123 var td = $("<td></td>");
124 td.prop("class", orig_key_j);
125 if (tableData.rows[i][key_j]){
126 td.html(tableData.rows[i][key_j]);
127 }
128 row.append(td);
129 }
130 tableBody.append(row);
131
132 /* If we have layerbtns then initialise them */
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500133 layerBtnsInit();
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500134
135 /* If we have popovers initialise them now */
136 $('td > a.btn').popover({
137 html:true,
138 placement:'left',
139 container:'body',
140 trigger:'manual'
141 }).click(function(e){
142 $('td > a.btn').not(this).popover('hide');
143 /* ideally we would use 'toggle' here
144 * but it seems buggy in our Bootstrap version
145 */
146 $(this).popover('show');
147 e.stopPropagation();
148 });
149
150 /* enable help information tooltip */
151 $(".get-help").tooltip({container:'body', html:true, delay:{show:300}});
152 }
153
154 /* Setup the pagination controls */
155
156 var start = tableParams.page - 2;
157 var end = tableParams.page + 2;
158 var numPages = Math.ceil(tableData.total/tableParams.limit);
159
160 if (numPages > 1){
161 if (tableParams.page < 3)
162 end = 5;
163
164 for (var page_i=1; page_i <= numPages; page_i++){
165 if (page_i >= start && page_i <= end){
166 var btn = $('<li><a href="#" class="page">'+page_i+'</a></li>');
167
168 if (page_i === tableParams.page){
169 btn.addClass("active");
170 }
171
172 /* Add the click handler */
173 btn.click(pageButtonClicked);
174 paginationBtns.append(btn);
175 }
176 }
177 }
178
179 loadColumnsPreference();
180
181 table.css("padding-bottom", 0);
182 tableContainer.css("visibility", "visible");
183
184 table.trigger("table-done", [tableData.total, tableParams]);
185 }
186
187 function setupTableChrome(tableData){
188 if (tableChromeDone === true)
189 return;
190
191 var tableHeadRow = table.find("thead");
192 var editColMenu = $("#table-chrome-"+ctx.tableName).find(".editcol");
193
194 tableHeadRow.html("");
195 editColMenu.html("");
196
197 if (!tableParams.orderby && tableData.default_orderby){
198 tableParams.orderby = tableData.default_orderby;
199 }
200
201 /* Add table header and column toggle menu */
202 for (var i in tableData.columns){
203 var col = tableData.columns[i];
204 if (col.displayable === false) {
205 continue;
206 }
207 var header = $("<th></th>");
208 header.prop("class", col.field_name);
209
210 /* Setup the help text */
211 if (col.help_text.length > 0) {
212 var help_text = $('<i class="icon-question-sign get-help"> </i>');
213 help_text.tooltip({title: col.help_text});
214 header.append(help_text);
215 }
216
217 /* Setup the orderable title */
218 if (col.orderable) {
219 var title = $('<a href=\"#\" ></a>');
220
221 title.data('field-name', col.field_name);
222 title.text(col.title);
223 title.click(sortColumnClicked);
224
225 header.append(title);
226
227 header.append(' <i class="icon-caret-down" style="display:none"></i>');
228 header.append(' <i class="icon-caret-up" style="display:none"></i>');
229
230 /* If we're currently ordered setup the visual indicator */
231 if (col.field_name === tableParams.orderby ||
232 '-' + col.field_name === tableParams.orderby){
233 header.children("a").addClass("sorted");
234
235 if (tableParams.orderby.indexOf("-") === -1){
236 header.find('.icon-caret-down').show();
237 } else {
238 header.find('.icon-caret-up').show();
239 }
240 }
241
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500242 if (col.field_name === tableData.default_orderby){
243 title.addClass("default-orderby");
244 }
245
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500246 } else {
247 /* Not orderable */
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500248 header.css("font-weight", "normal");
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500249 header.append('<span class="muted">' + col.title + '</span> ');
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500250 }
251
252 /* Setup the filter button */
253 if (col.filter_name){
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500254 var filterBtn = $('<a href="#" role="button" data-filter-on="' + col.filter_name + '" class="pull-right btn btn-mini" data-toggle="modal"><i class="icon-filter filtered"></i></a>');
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500255
256 filterBtn.data('filter-name', col.filter_name);
257 filterBtn.prop('id', col.filter_name);
258 filterBtn.click(filterOpenClicked);
259
260 /* If we're currently being filtered setup the visial indicator */
261 if (tableParams.filter &&
262 tableParams.filter.match('^'+col.filter_name)) {
263
264 filterBtnActive(filterBtn, true);
265 }
266 header.append(filterBtn);
267 }
268
269 /* Done making the header now add it */
270 tableHeadRow.append(header);
271
272 /* Now setup the checkbox state and click handler */
273 var toggler = $('<li><label class="checkbox">'+col.title+'<input type="checkbox" id="checkbox-'+ col.field_name +'" class="col-toggle" value="'+col.field_name+'" /></label></li>');
274
275 var togglerInput = toggler.find("input");
276
277 togglerInput.attr("checked","checked");
278
279 /* If we can hide the column enable the checkbox action */
280 if (col.hideable){
281 togglerInput.click(colToggleClicked);
282 } else {
283 toggler.find("label").addClass("muted");
284 togglerInput.attr("disabled", "disabled");
285 }
286
287 if (col.hidden) {
288 defaultHiddenCols.push(col.field_name);
289 }
290
291 editColMenu.append(toggler);
292 } /* End for each column */
293
294 tableChromeDone = true;
295 }
296
297 /* Toggles the active state of the filter button */
298 function filterBtnActive(filterBtn, active){
299 if (active) {
300 filterBtn.addClass("btn-primary");
301
302 filterBtn.tooltip({
303 html: true,
304 title: '<button class="btn btn-small btn-primary" onClick=\'$("#clear-filter-btn-'+ ctx.tableName +'").click();\'>Clear filter</button>',
305 placement: 'bottom',
306 delay: {
307 hide: 1500,
308 show: 400,
309 },
310 });
311 } else {
312 filterBtn.removeClass("btn-primary");
313 filterBtn.tooltip('destroy');
314 }
315 }
316
317 /* Display or hide table columns based on the cookie preference or defaults */
318 function loadColumnsPreference(){
319 var cookie_data = $.cookie("cols");
320
321 if (cookie_data) {
322 var cols_hidden = JSON.parse($.cookie("cols"));
323
324 /* For each of the columns check if we should hide them
325 * also update the checked status in the Edit columns menu
326 */
327 $("#"+ctx.tableName+" th").each(function(){
328 for (var i in cols_hidden){
329 if ($(this).hasClass(cols_hidden[i])){
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500330 table.find("."+cols_hidden[i]).hide();
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500331 $("#checkbox-"+cols_hidden[i]).removeAttr("checked");
332 }
333 }
334 });
335 } else {
336 /* Disable these columns by default when we have no columns
337 * user setting.
338 */
339 for (var i in defaultHiddenCols) {
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500340 table.find("."+defaultHiddenCols[i]).hide();
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500341 $("#checkbox-"+defaultHiddenCols[i]).removeAttr("checked");
342 }
343 }
344 }
345
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500346 function sortColumnClicked(e){
347 e.preventDefault();
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500348
349 /* We only have one sort at a time so remove any existing sort indicators */
350 $("#"+ctx.tableName+" th .icon-caret-down").hide();
351 $("#"+ctx.tableName+" th .icon-caret-up").hide();
352 $("#"+ctx.tableName+" th a").removeClass("sorted");
353
354 var fieldName = $(this).data('field-name');
355
356 /* if we're already sorted sort the other way */
357 if (tableParams.orderby === fieldName &&
358 tableParams.orderby.indexOf('-') === -1) {
359 tableParams.orderby = '-' + $(this).data('field-name');
360 $(this).parent().children('.icon-caret-up').show();
361 } else {
362 tableParams.orderby = $(this).data('field-name');
363 $(this).parent().children('.icon-caret-down').show();
364 }
365
366 $(this).addClass("sorted");
367
368 loadData(tableParams);
369 }
370
371 function pageButtonClicked(e) {
372 tableParams.page = Number($(this).text());
373 loadData(tableParams);
374 /* Stop page jumps when clicking on # links */
375 e.preventDefault();
376 }
377
378 /* Toggle a table column */
379 function colToggleClicked (){
380 var col = $(this).val();
381 var disabled_cols = [];
382
383 if ($(this).prop("checked")) {
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500384 table.find("."+col).show();
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500385 } else {
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500386 table.find("."+col).hide();
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500387 /* If we're ordered by the column we're hiding remove the order by */
388 if (col === tableParams.orderby ||
389 '-' + col === tableParams.orderby){
390 tableParams.orderby = null;
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500391 $("#"+ctx.tableName +" .default-orderby").click();
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500392 }
393 }
394
395 /* Update the cookie with the unchecked columns */
396 $(".col-toggle").not(":checked").map(function(){
397 disabled_cols.push($(this).val());
398 });
399
400 $.cookie("cols", JSON.stringify(disabled_cols));
401 }
402
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500403 /**
404 * Create the DOM/JS for the client side of a TableFilterActionToggle
405 * or TableFilterActionDay
406 *
407 * filterName: (string) internal name for the filter action
408 * filterActionData: (object)
409 * filterActionData.count: (number) The number of items this filter will
410 * show when selected
411 *
412 * NB this triggers a filtervalue event each time its radio button is checked
413 */
414 function createActionRadio(filterName, filterActionData) {
415 var hasNoRecords = (Number(filterActionData.count) == 0);
416
417 var actionStr = '<div class="radio">' +
418 '<input type="radio" name="filter"' +
419 ' value="' + filterName + '"';
420
421 if (hasNoRecords) {
422 actionStr += ' disabled="disabled"';
423 }
424
425 actionStr += ' id="' + filterName + '">' +
426 '<input type="hidden" name="filter_value" value="on"' +
427 ' data-value-for="' + filterName + '">' +
428 '<label class="filter-title' +
429 (hasNoRecords ? ' muted' : '') + '"' +
430 ' for="' + filterName + '">' +
431 filterActionData.title +
432 ' (' + filterActionData.count + ')' +
433 '</label>' +
434 '</div>';
435
436 var action = $(actionStr);
437
438 // fire the filtervalue event from this action when the radio button
439 // is active so that the apply button can be enabled
440 action.find('[type="radio"]').change(function () {
441 if ($(this).is(':checked')) {
442 action.trigger('filtervalue', 'on');
443 }
444 });
445
446 return action;
447 }
448
449 /**
450 * Create the DOM/JS for the client side of a TableFilterActionDateRange
451 *
452 * filterName: (string) internal name for the filter action
453 * filterValue: (string) from,to date range in format yyyy-mm-dd,yyyy-mm-dd;
454 * used to select the current values for the from/to datepickers;
455 * if this is partial (e.g. "yyyy-mm-dd,") only the applicable datepicker
456 * will have a date pre-selected; if empty, neither will
457 * filterActionData: (object) data for generating the action's HTML
458 * filterActionData.title: label for the radio button
459 * filterActionData.max: (string) maximum date for the pickers, in ISO 8601
460 * datetime format
461 * filterActionData.min: (string) minimum date for the pickers, ISO 8601
462 * datetime
463 *
464 * NB this triggers a filtervalue event each time its radio button is checked
465 */
466 function createActionDateRange(filterName, filterValue, filterActionData) {
467 var action = $('<div class="radio">' +
468 '<input type="radio" name="filter"' +
469 ' value="' + filterName + '" ' +
470 ' id="' + filterName + '">' +
471 '<input type="hidden" name="filter_value" value=""' +
472 ' data-value-for="' + filterName + '">' +
473 '<label class="filter-title"' +
474 ' for="' + filterName + '">' +
475 filterActionData.title +
476 '</label>' +
477 '<input type="text" maxlength="10" class="input-small"' +
478 ' data-date-from-for="' + filterName + '">' +
479 '<span class="help-inline">to</span>' +
480 '<input type="text" maxlength="10" class="input-small"' +
481 ' data-date-to-for="' + filterName + '">' +
482 '<span class="help-inline get-help">(yyyy-mm-dd)</span>' +
483 '</div>');
484
485 var radio = action.find('[type="radio"]');
486 var value = action.find('[data-value-for]');
487
488 // make the datepickers for the range
489 var options = {
490 dateFormat: 'yy-mm-dd',
491 maxDate: new Date(filterActionData.max),
492 minDate: new Date(filterActionData.min)
493 };
494
495 // create date pickers, setting currently-selected from and to dates
496 var selectedFrom = null;
497 var selectedTo = null;
498
499 var selectedFromAndTo = [];
500 if (filterValue) {
501 selectedFromAndTo = filterValue.split(',');
502 }
503
504 if (selectedFromAndTo.length == 2) {
505 selectedFrom = selectedFromAndTo[0];
506 selectedTo = selectedFromAndTo[1];
507 }
508
509 options.defaultDate = selectedFrom;
510 var inputFrom =
511 action.find('[data-date-from-for]').datepicker(options);
512 inputFrom.val(selectedFrom);
513
514 options.defaultDate = selectedTo;
515 var inputTo =
516 action.find('[data-date-to-for]').datepicker(options);
517 inputTo.val(selectedTo);
518
519 // set filter_value based on date pickers when
520 // one of their values changes; if either from or to are unset,
521 // the new value is null;
522 // this triggers a 'filter_value-change' event on the action's element,
523 // which is used to determine the disabled/enabled state of the "Apply"
524 // button
525 var changeHandler = function () {
526 var fromValue = inputFrom.val();
527 var toValue = inputTo.val();
528
529 var newValue = undefined;
530 if (fromValue !== '' && toValue !== '') {
531 newValue = fromValue + ',' + toValue;
532 }
533
534 value.val(newValue);
535
536 // if this action is selected, fire an event for the new range
537 if (radio.is(':checked')) {
538 action.trigger('filtervalue', newValue);
539 }
540 };
541
542 inputFrom.change(changeHandler);
543 inputTo.change(changeHandler);
544
545 // check the associated radio button on clicking a date picker
546 var checkRadio = function () {
547 radio.prop('checked', 'checked');
548
549 // checking the radio button this way doesn't cause the "change"
550 // event to fire, so we manually call the changeHandler
551 changeHandler();
552 };
553
554 inputFrom.focus(checkRadio);
555 inputTo.focus(checkRadio);
556
557 // selecting a date in a picker constrains the date you can
558 // set in the other picker
559 inputFrom.change(function () {
560 inputTo.datepicker('option', 'minDate', inputFrom.val());
561 });
562
563 inputTo.change(function () {
564 inputFrom.datepicker('option', 'maxDate', inputTo.val());
565 });
566
567 // checking the radio input causes the "Apply" button disabled state to
568 // change, depending on which from/to dates are supplied
569 radio.change(changeHandler);
570
571 return action;
572 }
573
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500574 function filterOpenClicked(){
575 var filterName = $(this).data('filter-name');
576
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500577 /* We need to pass in the current search so that the filter counts take
578 * into account the current search term
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500579 */
580 var params = {
581 'name' : filterName,
582 'search': tableParams.search,
583 'cmd': 'filterinfo',
584 };
585
586 $.ajax({
587 type: "GET",
588 url: ctx.url,
589 data: params,
590 headers: { 'X-CSRFToken' : $.cookie('csrftoken')},
591 success: function (filterData) {
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500592 /*
593 filterData structure:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500594
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500595 {
596 title: '<title for the filter popup>',
597 filter_actions: [
598 {
599 title: '<label for radio button inside the popup>',
600 name: '<name of the filter action>',
601 count: <number of items this filter will show>,
602 ... additional data for the action ...
603 }
604 ]
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500605 }
606
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500607 each filter_action gets a radio button; the value of this is
608 set to filterName + ':' + filter_action.name; e.g.
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500609
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500610 in_current_project:in_project
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500611
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500612 specifies the "in_project" action of the "in_current_project"
613 filter
614
615 the filterName is set on the column filter icon, and corresponds
616 to a value in the table's filter map
617
618 when the filter popup's "Apply" button is clicked, the
619 value for the radio button which is checked is passed in the
620 querystring, along with a filter_value, and applied to the
621 queryset on the table
622 */
623 var filterActionRadios = $('#filter-actions-' + ctx.tableName);
624 var filterApplyBtn = $('[data-role="filter-apply"]');
625
626 var setApplyButtonState = function (e, filterActionValue) {
627 if (filterActionValue !== undefined) {
628 filterApplyBtn.removeAttr('disabled');
629 }
630 else {
631 filterApplyBtn.attr('disabled', 'disabled');
632 }
633 };
634
635 $('#filter-modal-title-' + ctx.tableName).text(filterData.title);
636
637 filterActionRadios.empty();
638
639 // create a radio button + form elements for each action associated
640 // with the filter on this column of the table
641 for (var i in filterData.filter_actions) {
642 var action = null;
643 var filterActionData = filterData.filter_actions[i];
644 var filterName = filterData.name + ':' +
645 filterActionData.action_name;
646
647 if (filterActionData.type === 'toggle' ||
648 filterActionData.type === 'day') {
649 action = createActionRadio(filterName, filterActionData);
650 }
651 else if (filterActionData.type === 'daterange') {
652 // current values for the from/to dates
653 var filterValue = tableParams.filter_value;
654
655 action = createActionDateRange(
656 filterName,
657 filterValue,
658 filterActionData
659 );
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500660 }
661
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500662 if (action) {
663 // Setup the current selected filter; default to 'all' if
664 // no current filter selected
665 var radioInput = action.children('input[name="filter"]');
666 if ((tableParams.filter &&
667 tableParams.filter === radioInput.val()) ||
668 filterActionData.action_name == 'all') {
669 radioInput.prop("checked", "checked");
670 }
671
672 filterActionRadios.append(action);
673
674 // if the action's filter_value changes but is falsy, disable
675 // the "Apply" button
676 action.on('filtervalue', setApplyButtonState);
677 }
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500678 }
679
680 $('#filter-modal-'+ctx.tableName).modal('show');
681 }
682 });
683 }
684
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500685 /* Allow pages to trigger reload event */
686 table.on('reload', function(e, newTableParams){
687 if (newTableParams)
688 loadData(newTableParams);
689 else
690 loadData(tableParams)
691 });
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500692
693 $(".get-help").tooltip({container:'body', html:true, delay:{show:300}});
694
695 /* Keep the Edit columns menu open after click by eating the event */
696 $('.dropdown-menu').click(function(e) {
697 e.stopPropagation();
698 });
699
700 $(".pagesize-"+ctx.tableName).val(tableParams.limit);
701
702 /* page size selector */
703 $(".pagesize-"+ctx.tableName).change(function(e){
704 tableParams.limit = Number(this.value);
705 if ((tableParams.page * tableParams.limit) > tableTotal)
706 tableParams.page = 1;
707
708 loadData(tableParams);
709 /* sync the other selectors on the page */
710 $(".pagesize-"+ctx.tableName).val(this.value);
711 e.preventDefault();
712 });
713
714 $("#search-submit-"+ctx.tableName).click(function(e){
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500715 e.preventDefault();
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500716 var searchTerm = $("#search-input-"+ctx.tableName).val();
717
718 tableParams.page = 1;
719 tableParams.search = searchTerm;
720
721 /* If a filter was active we remove it */
722 if (tableParams.filter) {
723 var filterBtn = $("#" + tableParams.filter.split(":")[0]);
724 filterBtnActive(filterBtn, false);
725 tableParams.filter = null;
726 }
727
728 loadData(tableParams);
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500729 });
730
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500731 clearSearchElements.click(function(e){
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500732 e.preventDefault();
733
734 tableParams.page = 1;
735 tableParams.search = null;
736 loadData(tableParams);
737
738 $("#search-input-"+ctx.tableName).val("");
739 $(this).hide();
740 });
741
742 $("#search-input-"+ctx.tableName).keyup(function(e){
743 if (e.which === 13)
744 $('#search-submit-'+ctx.tableName).click();
745 });
746
747 /* Stop page jumps when clicking on # links */
748 $('a[href="#"]').click(function(e){
749 e.preventDefault();
750 });
751
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500752 $("#clear-filter-btn-"+ctx.tableName).click(function(e){
753 e.preventDefault();
754
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500755 var filterBtn = $("#" + tableParams.filter.split(":")[0]);
756 filterBtnActive(filterBtn, false);
757
758 tableParams.filter = null;
759 loadData(tableParams);
760 });
761
762 $("#filter-modal-form-"+ctx.tableName).submit(function(e){
763 e.preventDefault();
764
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500765 /* remove active status from all filter buttons so that only one filter
766 can be active at a time */
767 $('[data-filter-on]').each(function (index, filterBtn) {
768 filterBtnActive($(filterBtn), false);
769 });
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500770
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500771 // checked radio button
772 var checkedFilter = $(this).find("input[name='filter']:checked");
773 tableParams.filter = checkedFilter.val();
774
775 // hidden field holding the value for the checked filter
776 var checkedFilterValue = $(this).find("input[data-value-for='" +
777 tableParams.filter + "']");
778 tableParams.filter_value = checkedFilterValue.val();
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500779
780 /* All === remove filter */
781 if (tableParams.filter.match(":all$")) {
782 tableParams.filter = null;
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500783 tableParams.filter_value = null;
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500784 } else {
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500785 var filterBtn = $("#" + tableParams.filter.split(":")[0]);
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500786 filterBtnActive(filterBtn, true);
787 }
788
789 loadData(tableParams);
790
791 $(this).parent().modal('hide');
792 });
793}