Skip to content

Commit 397bb94

Browse files
committed
Move sortable table utility functions to base
1 parent 9ca1527 commit 397bb94

2 files changed

Lines changed: 257 additions & 253 deletions

File tree

htdocs/js/pages/Base.class.js

Lines changed: 257 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3314,4 +3314,261 @@ Page.Base = class Base extends Page {
33143314
}
33153315
}
33163316

3317+
//
3318+
// Sortble grid stuff
3319+
//
3320+
3321+
getSortedTableRows(id) {
3322+
// get sorted (and filtered!) table rows
3323+
var opts = this.tables[id];
3324+
var sort_by = opts.sort_by;
3325+
var sort_dir = opts.sort_dir;
3326+
var sort_type = 'number';
3327+
if (opts.rows.length && (typeof(opts.rows[0][sort_by]) == 'string')) sort_type = 'string';
3328+
3329+
// apply filter
3330+
var rows = [];
3331+
if (typeof(opts.filter) == 'function') {
3332+
// custom filter function
3333+
rows = opts.rows.filter( opts.filter );
3334+
}
3335+
else {
3336+
// default string regex match
3337+
var filter_re = new RegExp( escape_regexp(opts.filter) || '.*', 'i' );
3338+
rows = opts.rows.filter( function(row) {
3339+
var blob = hash_values_to_array(row).join(' ');
3340+
return !!blob.match( filter_re );
3341+
} );
3342+
}
3343+
3344+
// apply custom sort
3345+
rows.sort( function(a, b) {
3346+
if (sort_type == 'number') {
3347+
return( (a[sort_by] - b[sort_by]) * sort_dir );
3348+
}
3349+
else {
3350+
return( a[sort_by].toString().localeCompare(b[sort_by]) * sort_dir );
3351+
}
3352+
});
3353+
3354+
return rows;
3355+
}
3356+
3357+
updateTableRows(id, rows) {
3358+
// replace sorted table rows, redraw
3359+
var opts = this.tables[id];
3360+
if (rows) opts.rows = rows;
3361+
3362+
var disp_rows = this.getSortedTableRows( opts.id );
3363+
3364+
// redraw pagination thing
3365+
this.div.find('#st_hinfo_' + opts.id).html(
3366+
this.getTableHeaderInfo(id, disp_rows)
3367+
);
3368+
3369+
// redraw rows
3370+
this.div.find('#st_' + opts.id).html(
3371+
this.getTableColumnHTML( opts.id ) +
3372+
this.getTableContentHTML( opts.id, disp_rows )
3373+
);
3374+
}
3375+
3376+
applyTableFilter(elem) {
3377+
// key typed in table filter box, redraw
3378+
var id = $(elem).data('id');
3379+
var opts = this.tables[id];
3380+
opts.filter = $(elem).val();
3381+
3382+
var disp_rows = this.getSortedTableRows( opts.id );
3383+
3384+
// redraw pagination thing
3385+
this.div.find('#st_hinfo_' + opts.id).html(
3386+
this.getTableHeaderInfo(id, disp_rows)
3387+
);
3388+
3389+
// redraw rows
3390+
this.div.find('#st_' + opts.id).html(
3391+
this.getTableColumnHTML( opts.id ) +
3392+
this.getTableContentHTML( opts.id, disp_rows )
3393+
);
3394+
}
3395+
3396+
getTableHeaderInfo(id, disp_rows) {
3397+
// construct HTML for sortable table header info widget
3398+
var opts = this.tables[id];
3399+
var rows = opts.rows;
3400+
var html = '';
3401+
3402+
if (disp_rows.length < rows.length) {
3403+
html += commify(disp_rows.length) + ' of ' + commify(rows.length) + ' ' + pluralize(opts.item_name, rows.length) + '';
3404+
}
3405+
else {
3406+
html += commify(rows.length) + ' ' + pluralize(opts.item_name, rows.length) + '';
3407+
}
3408+
3409+
var bold_idx = opts.column_ids.indexOf( opts.sort_by );
3410+
html += ', sorted by ' + opts.column_labels[bold_idx] + '';
3411+
html += ' <i class="mdi mdi-menu-' + ((opts.sort_dir == 1) ? 'up' : 'down') + '"></i>';
3412+
// html += ((opts.sort_dir == 1) ? ' ascending' : ' descending');
3413+
3414+
return html;
3415+
}
3416+
3417+
getTableColumnHTML(id) {
3418+
// construct HTML for sortable table column headers (THs)
3419+
var opts = this.tables[id];
3420+
var html = '';
3421+
html += '<ul class="grid_row_header">';
3422+
3423+
opts.column_ids.forEach( function(col_id, idx) {
3424+
var col_label = opts.column_labels[idx];
3425+
if (!col_id) {
3426+
html += '<div>' + col_label + '</div>';
3427+
return;
3428+
}
3429+
var classes = ['st_col_header'];
3430+
var icon = '';
3431+
if (col_id == opts.sort_by) {
3432+
classes.push('active');
3433+
icon = ' <i class="mdi mdi-menu-' + ((opts.sort_dir == 1) ? 'up' : 'down') + '"></i>';
3434+
}
3435+
html += '<div class="' + classes.join(' ') + '" data-id="' + opts.id + '" data-col="' + col_id + '" onClick="$P().toggleTableSort(this)">' + col_label + icon + '</div>';
3436+
});
3437+
3438+
html += '</ul>';
3439+
return html;
3440+
}
3441+
3442+
getTableContentHTML(id, disp_rows) {
3443+
// construct HTML for sortable table content (rows)
3444+
var opts = this.tables[id];
3445+
var html = '';
3446+
var bold_idx = opts.column_ids.indexOf( opts.sort_by );
3447+
3448+
var len = disp_rows.length;
3449+
var max_rows = config.max_table_rows || 0;
3450+
var chopped = 0;
3451+
if (max_rows && (disp_rows.length > max_rows)) {
3452+
chopped = disp_rows.length - max_rows;
3453+
len = max_rows;
3454+
}
3455+
3456+
for (var idx = 0; idx < len; idx++) {
3457+
var row = disp_rows[idx];
3458+
var tds = opts.callback(row, idx);
3459+
html += '<ul class="grid_row ' + (tds.className || '') + '">';
3460+
for (var idy = 0, ley = tds.length; idy < ley; idy++) {
3461+
html += '<div' + ((bold_idx == idy) ? ' style="font-weight:bold"' : '') + '>' + tds[idy] + '</div>';
3462+
}
3463+
html += '</ul>';
3464+
} // foreach row
3465+
3466+
if (!disp_rows.length) {
3467+
html += '<ul class="grid_row_empty"><div style="grid-column: 1 / -1;">';
3468+
html += 'No ' + pluralize(opts.item_name) + ' found.';
3469+
html += '</div></ul>';
3470+
}
3471+
else if (chopped) {
3472+
html += '<ul class="grid_row_more"><div style="grid-column: 1 / -1;">';
3473+
html += `(${commify(chopped)} more ${pluralize(opts.item_name, chopped)} not shown)`;
3474+
html += '</div></ul>';
3475+
}
3476+
3477+
return html;
3478+
}
3479+
3480+
toggleTableSort(elem) {
3481+
var id = $(elem).data('id');
3482+
var col_id = $(elem).data('col');
3483+
var opts = this.tables[id];
3484+
3485+
// swap sort dir or change sort column
3486+
if (col_id == opts.sort_by) {
3487+
// swap dir
3488+
opts.sort_dir *= -1;
3489+
}
3490+
else {
3491+
// same sort dir but change column
3492+
opts.sort_by = col_id;
3493+
}
3494+
3495+
var disp_rows = this.getSortedTableRows( opts.id );
3496+
3497+
// redraw pagination thing
3498+
this.div.find('#st_hinfo_' + opts.id).html(
3499+
this.getTableHeaderInfo(id, disp_rows)
3500+
);
3501+
3502+
// redraw grid
3503+
this.div.find('#st_' + opts.id).html(
3504+
this.getTableColumnHTML(id) +
3505+
this.getTableContentHTML( opts.id, disp_rows )
3506+
);
3507+
}
3508+
3509+
getSortableTable(rows, opts, callback) {
3510+
// get HTML for sortable and filterable table
3511+
// opts: { id, item_name, sort_by, sort_dir, filter, column_ids, column_labels }
3512+
var self = this;
3513+
var html = '';
3514+
if (!this.tables) this.tables = {};
3515+
3516+
// retrieve previous settings if applicable
3517+
if (this.tables[ opts.id ]) {
3518+
if (this.tables[ opts.id ].filter) opts.filter = this.tables[ opts.id ].filter;
3519+
if (this.tables[ opts.id ].sort_by) opts.sort_by = this.tables[ opts.id ].sort_by;
3520+
if (this.tables[ opts.id ].sort_dir) opts.sort_dir = this.tables[ opts.id ].sort_dir;
3521+
}
3522+
3523+
// save in page for resort / filtering
3524+
opts.rows = rows;
3525+
opts.callback = callback;
3526+
this.tables[ opts.id ] = opts;
3527+
3528+
var disp_rows = this.getSortedTableRows( opts.id );
3529+
3530+
if (!opts.hide_pagination) {
3531+
// pagination
3532+
html += '<div class="data_grid_pagination">';
3533+
3534+
html += '<div style="text-align:left" id="st_hinfo_' + opts.id + '">';
3535+
html += this.getTableHeaderInfo( opts.id, disp_rows );
3536+
html += '</div>';
3537+
3538+
html += '<div style="text-align:center">';
3539+
html += '&nbsp;';
3540+
html += '</div>';
3541+
3542+
html += '<div style="text-align:right">';
3543+
html += 'Page 1 of 1';
3544+
html += '</div>';
3545+
3546+
html += '</div>';
3547+
3548+
html += '<div style="margin-top:5px;">';
3549+
}
3550+
else {
3551+
// no pagination
3552+
html += '<div>';
3553+
}
3554+
3555+
var tattrs = opts.attribs || {};
3556+
if (opts.class) tattrs.class = opts.class;
3557+
if (!tattrs.class) {
3558+
tattrs.class = 'data_grid';
3559+
if (opts.item_name.match(/^\w+$/)) tattrs.class += ' ' + opts.item_name + '_grid';
3560+
}
3561+
if (!tattrs.style) tattrs.style = '';
3562+
tattrs.style += 'grid-template-columns: repeat(' + opts.column_ids.length + ', auto);';
3563+
html += '<div id="st_' + opts.id + '" ' + compose_attribs(tattrs) + '>';
3564+
3565+
html += this.getTableColumnHTML( opts.id );
3566+
html += this.getTableContentHTML( opts.id, disp_rows );
3567+
3568+
html += '</div>'; // scroll wrapper
3569+
html += '</div>'; // grid
3570+
3571+
return html;
3572+
}
3573+
33173574
};

0 commit comments

Comments
 (0)