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