Skip to content

Instantly share code, notes, and snippets.

@KeenthemesHub
Created February 12, 2019 16:51
Show Gist options
  • Save KeenthemesHub/9c77b0e0775b959091c008b49f641500 to your computer and use it in GitHub Desktop.
Save KeenthemesHub/9c77b0e0775b959091c008b49f641500 to your computer and use it in GitHub Desktop.
mDatatable dev
'use strict';
(function($) {
var pluginName = 'mDatatable';
var pfx = 'm-';
var util = mUtil;
var app = mApp;
if (typeof util === 'undefined') throw new Error('Util class is required and must be included before ' + pluginName);
// plugin setup
$.fn[pluginName] = function(options) {
if ($(this).length === 0) {
console.log('No ' + pluginName + ' element exist.');
return;
}
// global variables
var datatable = this;
// debug enabled?
// 1) state will be cleared on each refresh
// 2) enable some logs
// 3) etc.
datatable.debug = false;
datatable.API = {
record: null,
value: null,
params: null,
};
var Plugin = {
/********************
** PRIVATE METHODS
********************/
isInit: false,
cellOffset: 110,
iconOffset: 15,
stateId: 'meta',
ajaxParams: {},
init: function(options) {
var isHtmlTable = false;
// data source option empty is normal table
if (options.data.source === null) {
Plugin.extractTable();
isHtmlTable = true;
}
Plugin.setupBaseDOM.call();
Plugin.setupDOM(datatable.table);
// Plugin.spinnerCallback(true);
// set custom query from options
Plugin.setDataSourceQuery(Plugin.getOption('data.source.read.params.query'));
// on event after layout had done setup, show datatable
$(datatable).on(pfx + 'datatable--on-layout-updated', Plugin.afterRender);
if (datatable.debug) Plugin.stateRemove(Plugin.stateId);
// initialize extensions
$.each(Plugin.getOption('extensions'), function(extName, extOptions) {
if (typeof $.fn[pluginName][extName] === 'function')
new $.fn[pluginName][extName](datatable, extOptions);
});
// get data
if (options.data.type === 'remote' || options.data.type === 'local') {
if (options.data.saveState === false
|| options.data.saveState.cookie === false
&& options.data.saveState.webstorage === false) {
Plugin.stateRemove(Plugin.stateId);
}
// get data for local datatable and local table
if (options.data.type === 'local' && typeof options.data.source === 'object') {
datatable.dataSet = datatable.originalDataSet = Plugin.dataMapCallback(options.data.source);
}
Plugin.dataRender();
}
if (!isHtmlTable) {
// if not a html table, setup header
Plugin.setHeadTitle();
if (Plugin.getOption('layout.footer')) {
Plugin.setHeadTitle(datatable.tableFoot);
}
}
// hide header
if (typeof options.layout.header !== 'undefined' &&
options.layout.header === false) {
$(datatable.table).find('thead').remove();
}
// hide footer
if (typeof options.layout.footer !== 'undefined' &&
options.layout.footer === false) {
$(datatable.table).find('tfoot').remove();
}
// for normal and local data type, run layoutUpdate
if (options.data.type === null ||
options.data.type === 'local') {
Plugin.setupCellField.call();
Plugin.setupTemplateCell.call();
// setup nested datatable, if option enabled
Plugin.setupSubDatatable.call();
// setup extra system column properties
Plugin.setupSystemColumn.call();
Plugin.redraw();
}
var width;
var initialWidth = false;
$(window).resize(function() {
// get initial width
if (!initialWidth) {
width = $(this).width();
initialWidth = true;
}
// issue: URL Bar Resizing on mobile, https://developers.google.com/web/updates/2016/12/url-bar-resizing
// trigger datatable resize on width change only
if ($(this).width() !== width) {
width = $(this).width();
Plugin.fullRender();
}
});
$(datatable).height('');
$(Plugin.getOption('search.input')).on('keyup', function(e) {
if (Plugin.getOption('search.onEnter') && e.which !== 13) return;
Plugin.search($(this).val());
});
return datatable;
},
/**
* Extract static HTML table content into datasource
*/
extractTable: function() {
var columns = [];
var headers = $(datatable).find('tr:first-child th').get().map(function(cell, i) {
var field = $(cell).data('field');
if (typeof field === 'undefined') {
field = $(cell).text().trim();
}
var column = {field: field, title: field};
for (var ii in options.columns) {
if (options.columns[ii].field === field) {
column = $.extend(true, {}, options.columns[ii], column);
}
}
columns.push(column);
return field;
});
// auto create columns config
options.columns = columns;
var rowProp = [];
var source = [];
$(datatable).find('tr').each(function() {
if ($(this).find('td').length) {
rowProp.push($(this).prop('attributes'));
}
var td = {};
$(this).find('td').each(function(i, cell) {
td[headers[i]] = cell.innerHTML.trim();
});
if (!util.isEmpty(td)) {
source.push(td);
}
});
options.data.attr.rowProps = rowProp;
options.data.source = source;
},
/**
* One time layout update on init
*/
layoutUpdate: function() {
// setup nested datatable, if option enabled
Plugin.setupSubDatatable.call();
// setup extra system column properties
Plugin.setupSystemColumn.call();
// setup cell hover event
Plugin.setupHover.call();
if (typeof options.detail === 'undefined'
// temporary disable lock column in subtable
&& Plugin.getDepth() === 1) {
// lock columns handler
Plugin.lockTable.call();
}
// Plugin.columnHide.call();
Plugin.resetScroll();
if (!Plugin.isInit) {
// run once dropdown inside datatable
Plugin.dropdownFix();
$(datatable).trigger(pfx + 'datatable--on-init', {table: $(datatable.wrap).attr('id'), options: options});
Plugin.isInit = true;
}
$(datatable).trigger(pfx + 'datatable--on-layout-updated', {table: $(datatable.wrap).attr('id')});
},
lockTable: function() {
var lock = {
lockEnabled: false,
init: function() {
// check if table should be locked columns
lock.lockEnabled = Plugin.lockEnabledColumns();
if (lock.lockEnabled.left.length === 0 &&
lock.lockEnabled.right.length === 0) {
return;
}
lock.enable();
},
enable: function() {
var enableLock = function(tablePart) {
// check if already has lock column
if ($(tablePart).find('.' + pfx + 'datatable__lock').length > 0) {
Plugin.log('Locked container already exist in: ', tablePart);
return;
}
// check if no rows exists
if ($(tablePart).find('.' + pfx + 'datatable__row').length === 0) {
Plugin.log('No row exist in: ', tablePart);
return;
}
// locked div container
var lockLeft = $('<div/>').addClass(pfx + 'datatable__lock ' + pfx + 'datatable__lock--left');
var lockScroll = $('<div/>').addClass(pfx + 'datatable__lock ' + pfx + 'datatable__lock--scroll');
var lockRight = $('<div/>').addClass(pfx + 'datatable__lock ' + pfx + 'datatable__lock--right');
$(tablePart).find('.' + pfx + 'datatable__row').each(function() {
// create new row for lock columns and pass the data
var rowLeft = $('<tr/>').addClass(pfx + 'datatable__row').data('obj', $(this).data('obj')).appendTo(lockLeft);
var rowScroll = $('<tr/>').addClass(pfx + 'datatable__row').data('obj', $(this).data('obj')).appendTo(lockScroll);
var rowRight = $('<tr/>').addClass(pfx + 'datatable__row').data('obj', $(this).data('obj')).appendTo(lockRight);
$(this).find('.' + pfx + 'datatable__cell').each(function() {
var locked = $(this).data('locked');
if (typeof locked !== 'undefined') {
if (typeof locked.left !== 'undefined' || locked === true) {
// default locked to left
$(this).appendTo(rowLeft);
}
if (typeof locked.right !== 'undefined') {
$(this).appendTo(rowRight);
}
} else {
$(this).appendTo(rowScroll);
}
});
// remove old row
$(this).remove();
});
if (lock.lockEnabled.left.length > 0) {
$(datatable.wrap).addClass(pfx + 'datatable--lock');
$(lockLeft).appendTo(tablePart);
}
if (lock.lockEnabled.left.length > 0 || lock.lockEnabled.right.length > 0) {
$(lockScroll).appendTo(tablePart);
}
if (lock.lockEnabled.right.length > 0) {
$(datatable.wrap).addClass(pfx + 'datatable--lock');
$(lockRight).appendTo(tablePart);
}
};
$(datatable.table).find('thead,tbody,tfoot').each(function() {
var tablePart = this;
if ($(this).find('.' + pfx + 'datatable__lock').length === 0) {
$(this).ready(function() {
enableLock(tablePart);
});
}
});
},
};
lock.init();
return lock;
},
/**
* Render everything for resize
*/
fullRender: function() {
$(datatable.tableHead).empty();
Plugin.setHeadTitle();
if (Plugin.getOption('layout.footer')) {
$(datatable.tableFoot).empty();
Plugin.setHeadTitle(datatable.tableFoot);
}
Plugin.spinnerCallback(true);
$(datatable.wrap).removeClass(pfx + 'datatable--loaded');
Plugin.insertData();
},
lockEnabledColumns: function() {
var screen = $(window).width();
var columns = options.columns;
var enabled = {left: [], right: []};
$.each(columns, function(i, column) {
if (typeof column.locked !== 'undefined') {
if (typeof column.locked.left !== 'undefined') {
if (util.getBreakpoint(column.locked.left) <= screen) {
enabled['left'].push(column.locked.left);
}
}
if (typeof column.locked.right !== 'undefined') {
if (util.getBreakpoint(column.locked.right) <= screen) {
enabled['right'].push(column.locked.right);
}
}
}
});
return enabled;
},
/**
* After render event, called by '+pfx+'-datatable--on-layout-updated
* @param e
* @param args
*/
afterRender: function(e, args) {
if (args.table == $(datatable.wrap).attr('id')) {
$(datatable).ready(function() {
if (!Plugin.isLocked()) {
Plugin.redraw();
// work on non locked columns
if (!Plugin.isSubtable() && Plugin.getOption('rows.autoHide') === true) {
Plugin.autoHide();
}
// reset row
$(datatable.table).find('.' + pfx + 'datatable__row').css('height', '');
}
Plugin.rowEvenOdd.call();
// redraw locked columns table
if (Plugin.isLocked()) Plugin.redraw();
$(datatable.tableBody).css('visibility', '');
$(datatable.wrap).addClass(pfx + 'datatable--loaded');
Plugin.scrollbar.call();
Plugin.spinnerCallback(false);
Plugin.sorting.call();
});
}
},
dropdownFix: function() {
var dropdownMenu;
$('body').on('show.bs.dropdown', '.' + pfx + 'datatable .' + pfx + 'datatable__body', function(e) {
dropdownMenu = $(e.target).find('.dropdown-menu');
$('body').append(dropdownMenu.detach());
dropdownMenu.css('display', 'block');
dropdownMenu.position({
'my': 'right top',
'at': 'right bottom',
'of': $(e.relatedTarget),
});
// if datatable is inside modal
if (datatable.closest('.modal').length) {
// increase dropdown z-index
dropdownMenu.css('z-index', '2000');
}
}).on('hide.bs.dropdown', '.' + pfx + 'datatable .' + pfx + 'datatable__body', function(e) {
$(e.target).append(dropdownMenu.detach());
dropdownMenu.hide();
});
},
hoverTimer: 0,
isScrolling: false,
setupHover: function() {
$(window).scroll(function(e) {
// stop hover when scrolling
clearTimeout(Plugin.hoverTimer);
Plugin.isScrolling = true;
});
$(datatable.tableBody).find('.' + pfx + 'datatable__cell').off('mouseenter', 'mouseleave').on('mouseenter', function() {
// reset scroll timer to hover class
Plugin.hoverTimer = setTimeout(function() {
Plugin.isScrolling = false;
}, 200);
if (Plugin.isScrolling) return;
// normal table
var row = $(this).closest('.' + pfx + 'datatable__row').addClass(pfx + 'datatable__row--hover');
var index = $(row).index() + 1;
// lock table
$(row).closest('.' + pfx + 'datatable__lock').parent().find('.' + pfx + 'datatable__row:nth-child(' + index + ')').addClass(pfx + 'datatable__row--hover');
}).on('mouseleave', function() {
// normal table
var row = $(this).closest('.' + pfx + 'datatable__row').removeClass(pfx + 'datatable__row--hover');
var index = $(row).index() + 1;
// look table
$(row).closest('.' + pfx + 'datatable__lock').parent().find('.' + pfx + 'datatable__row:nth-child(' + index + ')').removeClass(pfx + 'datatable__row--hover');
});
},
/**
* Adjust width of locked table containers by resize handler
* @returns {number}
*/
adjustLockContainer: function() {
if (!Plugin.isLocked()) return 0;
// refer to head dimension
var containerWidth = $(datatable.tableHead).width();
var lockLeft = $(datatable.tableHead).find('.' + pfx + 'datatable__lock--left').width();
var lockRight = $(datatable.tableHead).find('.' + pfx + 'datatable__lock--right').width();
if (typeof lockLeft === 'undefined') lockLeft = 0;
if (typeof lockRight === 'undefined') lockRight = 0;
var lockScroll = Math.floor(containerWidth - lockLeft - lockRight);
$(datatable.table).find('.' + pfx + 'datatable__lock--scroll').css('width', lockScroll);
return lockScroll;
},
/**
* todo; not in use
*/
dragResize: function() {
var pressed = false;
var start = undefined;
var startX, startWidth;
$(datatable.tableHead).find('.' + pfx + 'datatable__cell').mousedown(function(e) {
start = $(this);
pressed = true;
startX = e.pageX;
startWidth = $(this).width();
$(start).addClass(pfx + 'datatable__cell--resizing');
}).mousemove(function(e) {
if (pressed) {
var i = $(start).index();
var tableBody = $(datatable.tableBody);
var ifLocked = $(start).closest('.' + pfx + 'datatable__lock');
if (ifLocked) {
var lockedIndex = $(ifLocked).index();
tableBody = $(datatable.tableBody).find('.' + pfx + 'datatable__lock').eq(lockedIndex);
}
$(tableBody).find('.' + pfx + 'datatable__row').each(function(tri, tr) {
$(tr).find('.' + pfx + 'datatable__cell').eq(i).width(startWidth + (e.pageX - startX)).children().width(startWidth + (e.pageX - startX));
});
$(start).children().css('width', startWidth + (e.pageX - startX));
}
}).mouseup(function() {
$(start).removeClass(pfx + 'datatable__cell--resizing');
pressed = false;
});
$(document).mouseup(function() {
$(start).removeClass(pfx + 'datatable__cell--resizing');
pressed = false;
});
},
/**
* To prepare placeholder for table before content is loading
*/
initHeight: function() {
if (options.layout.height && options.layout.scroll) {
var theadHeight = $(datatable.tableHead).find('.' + pfx + 'datatable__row').outerHeight();
var tfootHeight = $(datatable.tableFoot).find('.' + pfx + 'datatable__row').outerHeight();
var bodyHeight = options.layout.height;
if (theadHeight > 0) {
bodyHeight -= theadHeight;
}
if (tfootHeight > 0) {
bodyHeight -= tfootHeight;
}
// scrollbar offset
bodyHeight -= 2;
$(datatable.tableBody).css('max-height', bodyHeight);
// set scrollable area fixed height
$(datatable.tableBody).find('.' + pfx + 'datatable__lock--scroll').css('height', bodyHeight);
}
},
/**
* Setup base DOM (table, thead, tbody, tfoot) and create if not exist.
*/
setupBaseDOM: function() {
// keep original state before datatable initialize
datatable.initialDatatable = $(datatable).clone();
// main element
if ($(datatable).prop('tagName') === 'TABLE') {
// if main init element is <table>, wrap with div
datatable.table = $(datatable).removeClass(pfx + 'datatable').addClass(pfx + 'datatable__table');
if ($(datatable.table).parents('.' + pfx + 'datatable').length === 0) {
datatable.table.wrap($('<div/>').addClass(pfx + 'datatable').addClass(pfx + 'datatable--' + options.layout.theme));
datatable.wrap = $(datatable.table).parent();
}
} else {
// create table
datatable.wrap = $(datatable).addClass(pfx + 'datatable').addClass(pfx + 'datatable--' + options.layout.theme);
datatable.table = $('<table/>').addClass(pfx + 'datatable__table').appendTo(datatable);
}
if (typeof options.layout.class !== 'undefined') {
$(datatable.wrap).addClass(options.layout.class);
}
$(datatable.table).removeClass(pfx + 'datatable--destroyed').css('display', 'block');
// force disable save state
if (typeof $(datatable).attr('id') === 'undefined') {
Plugin.setOption('data.saveState', false);
$(datatable.table).attr('id', util.getUniqueID(pfx + 'datatable--'));
}
// predefine table height
if (Plugin.getOption('layout.minHeight'))
$(datatable.table).css('min-height', Plugin.getOption('layout.minHeight'));
if (Plugin.getOption('layout.height'))
$(datatable.table).css('max-height', Plugin.getOption('layout.height'));
// for normal table load
if (options.data.type === null) {
$(datatable.table).css('width', '').css('display', '');
}
// create table head element
datatable.tableHead = $(datatable.table).find('thead');
if ($(datatable.tableHead).length === 0) {
datatable.tableHead = $('<thead/>').prependTo(datatable.table);
}
// create table head element
datatable.tableBody = $(datatable.table).find('tbody');
if ($(datatable.tableBody).length === 0) {
datatable.tableBody = $('<tbody/>').appendTo(datatable.table);
}
if (typeof options.layout.footer !== 'undefined' &&
options.layout.footer) {
// create table foot element
datatable.tableFoot = $(datatable.table).find('tfoot');
if ($(datatable.tableFoot).length === 0) {
datatable.tableFoot = $('<tfoot/>').appendTo(datatable.table);
}
}
},
/**
* Set column data before table manipulation.
*/
setupCellField: function(tableParts) {
if (typeof tableParts === 'undefined') tableParts = $(datatable.table).children();
var columns = options.columns;
$.each(tableParts, function(part, tablePart) {
$(tablePart).find('.' + pfx + 'datatable__row').each(function(tri, tr) {
// prepare data
$(tr).find('.' + pfx + 'datatable__cell').each(function(tdi, td) {
if (typeof columns[tdi] !== 'undefined') {
$(td).data(columns[tdi]);
}
});
});
});
},
/**
* Set column template callback
* @param tablePart
*/
setupTemplateCell: function(tablePart) {
if (typeof tablePart === 'undefined') tablePart = datatable.tableBody;
var columns = options.columns;
$(tablePart).find('.' + pfx + 'datatable__row').each(function(tri, tr) {
// row data object, if any
var obj = $(tr).data('obj');
if (typeof obj === 'undefined') {
return;
}
// @deprecated in v5.0.6
// obj['getIndex'] = function() {
// return tri;
// };
// @deprecated in v5.0.6
// obj['getDatatable'] = function() {
// return datatable;
// };
// @deprecated in v5.0.6
var rowCallback = Plugin.getOption('rows.callback');
if (typeof rowCallback === 'function') {
rowCallback($(tr), obj, tri);
}
// before template row callback
var beforeTemplate = Plugin.getOption('rows.beforeTemplate');
if (typeof beforeTemplate === 'function') {
beforeTemplate($(tr), obj, tri);
}
// if data object is undefined, collect from table
if (typeof obj === 'undefined') {
obj = {};
$(tr).find('.' + pfx + 'datatable__cell').each(function(tdi, td) {
// get column settings by field
var column = $.grep(columns, function(n, i) {
return $(td).data('field') === n.field;
})[0];
if (typeof column !== 'undefined') {
obj[column['field']] = $(td).text();
}
});
}
$(tr).find('.' + pfx + 'datatable__cell').each(function(tdi, td) {
// get column settings by field
var column = $.grep(columns, function(n, i) {
return $(td).data('field') === n.field;
})[0];
if (typeof column !== 'undefined') {
// column template
if (typeof column.template !== 'undefined') {
var finalValue = '';
// template string
if (typeof column.template === 'string') {
finalValue = Plugin.dataPlaceholder(column.template, obj);
}
// template callback function
if (typeof column.template === 'function') {
finalValue = column.template(obj, tri, datatable);
}
// sanitize using DOMPurify if installed
if (typeof DOMPurify !== 'undefined') {
finalValue = DOMPurify.sanitize(finalValue);
}
var span = document.createElement('span');
span.innerHTML = finalValue;
// insert to cell, wrap with span
$(td).html(span);
// set span overflow
if (typeof column.overflow !== 'undefined') {
$(span).css('overflow', column.overflow);
$(span).css('position', 'relative');
}
}
}
});
// after template row callback
var afterTemplate = Plugin.getOption('rows.afterTemplate');
if (typeof afterTemplate === 'function') {
afterTemplate($(tr), obj, tri);
}
});
},
/**
* Setup extra system column properties
* Note: selector checkbox, subtable toggle
*/
setupSystemColumn: function() {
datatable.dataSet = datatable.dataSet || [];
// no records available
if (datatable.dataSet.length === 0) return;
var columns = options.columns;
$(datatable.tableBody).find('.' + pfx + 'datatable__row').each(function(tri, tr) {
$(tr).find('.' + pfx + 'datatable__cell').each(function(tdi, td) {
// get column settings by field
var column = $.grep(columns, function(n, i) {
return $(td).data('field') === n.field;
})[0];
if (typeof column !== 'undefined') {
var value = $(td).text();
// enable column selector
if (typeof column.selector !== 'undefined' && column.selector !== false) {
// check if checkbox exist
if ($(td).find('.' + pfx + 'checkbox [type="checkbox"]').length > 0) return;
$(td).addClass(pfx + 'datatable__cell--check');
// append checkbox
var chk = $('<label/>').
addClass(pfx + 'checkbox ' + pfx + 'checkbox--single').
append($('<input/>').attr('type', 'checkbox').attr('value', value).on('click', function() {
if ($(this).is(':checked')) {
// add checkbox active row class
Plugin.setActive(this);
} else {
// add checkbox active row class
Plugin.setInactive(this);
}
})).
append('&nbsp;<span></span>');
// checkbox selector has outline style
if (typeof column.selector.class !== 'undefined') {
$(chk).addClass(column.selector.class);
}
$(td).children().html(chk);
}
// enable column subtable toggle
if (typeof column.subtable !== 'undefined' && column.subtable) {
// check if subtable toggle exist
if ($(td).find('.' + pfx + 'datatable__toggle-subtable').length > 0) return;
// append subtable toggle
$(td).
children().
html($('<a/>').
addClass(pfx + 'datatable__toggle-subtable').
attr('href', '#').
attr('data-value', value).
append($('<i/>').addClass(Plugin.getOption('layout.icons.rowDetail.collapse'))));
}
}
});
});
// init checkbox for header/footer
var initCheckbox = function(tr) {
// get column settings by field
var column = $.grep(columns, function(n, i) {
return typeof n.selector !== 'undefined' && n.selector !== false;
})[0];
if (typeof column !== 'undefined') {
// enable column selector
if (typeof column.selector !== 'undefined' && column.selector !== false) {
var td = $(tr).find('[data-field="' + column.field + '"]');
// check if checkbox exist
if ($(td).find('.' + pfx + 'checkbox [type="checkbox"]').length > 0) return;
$(td).addClass(pfx + 'datatable__cell--check');
// append checkbox
var chk = $('<label/>').
addClass(pfx + 'checkbox ' + pfx + 'checkbox--single ' + pfx + 'checkbox--all').
append($('<input/>').attr('type', 'checkbox').on('click', function() {
if ($(this).is(':checked')) {
Plugin.setActiveAll(true);
} else {
Plugin.setActiveAll(false);
}
})).
append('&nbsp;<span></span>');
// checkbox selector has outline style
if (typeof column.selector.class !== 'undefined') {
$(chk).addClass(column.selector.class);
}
$(td).children().html(chk);
}
}
};
if (options.layout.header) {
initCheckbox($(datatable.tableHead).find('.' + pfx + 'datatable__row').first());
}
if (options.layout.footer) {
initCheckbox($(datatable.tableFoot).find('.' + pfx + 'datatable__row').first());
}
},
/**
* Adjust width to match container size
*/
adjustCellsWidth: function() {
// get table width
var containerWidth = $(datatable.tableBody).innerWidth() - Plugin.iconOffset;
// get total number of columns
var columns = $(datatable.tableBody).
find('.' + pfx + 'datatable__row:first-child').
find('.' + pfx + 'datatable__cell').
// exclude expand icon
not('.' + pfx + 'datatable__toggle-detail').
not(':hidden').length;
if (columns > 0) {
// remove reserved sort icon width
containerWidth = containerWidth - (Plugin.iconOffset * columns);
var minWidth = Math.floor(containerWidth / columns);
// minimum width
if (minWidth <= Plugin.cellOffset) {
minWidth = Plugin.cellOffset;
}
$(datatable.table).find('.' + pfx + 'datatable__row').
find('.' + pfx + 'datatable__cell').
// exclude expand icon
not('.' + pfx + 'datatable__toggle-detail').
not(':hidden').each(function(tdi, td) {
var width = minWidth;
var dataWidth = $(td).data('width');
if (typeof dataWidth !== 'undefined') {
width = dataWidth;
}
$(td).children().css('width', Math.ceil(width));
});
}
return datatable;
},
/**
* Adjust height to match container size
*/
adjustCellsHeight: function() {
$.each($(datatable.table).children(), function(part, tablePart) {
var totalRows = $(tablePart).find('.' + pfx + 'datatable__row').first().parent().find('.' + pfx + 'datatable__row').length;
for (var i = 1; i <= totalRows; i++) {
var rows = $(tablePart).find('.' + pfx + 'datatable__row:nth-child(' + i + ')');
if ($(rows).length > 0) {
var maxHeight = Math.max.apply(null, $(rows).map(function() {
return $(this).outerHeight();
}).get());
$(rows).css('height', Math.ceil(maxHeight));
}
}
});
},
/**
* Setup table DOM and classes
*/
setupDOM: function(table) {
// set table classes
$(table).find('> thead').addClass(pfx + 'datatable__head');
$(table).find('> tbody').addClass(pfx + 'datatable__body');
$(table).find('> tfoot').addClass(pfx + 'datatable__foot');
$(table).find('tr').addClass(pfx + 'datatable__row');
$(table).find('tr > th, tr > td').addClass(pfx + 'datatable__cell');
$(table).find('tr > th, tr > td').each(function(i, td) {
if ($(td).find('span').length === 0) {
$(td).wrapInner($('<span/>').css('width', Plugin.cellOffset));
}
});
},
/**
* Default scrollbar
* @returns {{tableLocked: null, init: init, onScrolling: onScrolling}}
*/
scrollbar: function() {
var scroll = {
scrollable: null,
tableLocked: null,
initPosition: null,
init: function() {
var screen = util.getViewPort().width;
// setup scrollable datatable
if (options.layout.scroll) {
// add scrollable datatable class
$(datatable.wrap).addClass(pfx + 'datatable--scroll');
var scrollable = $(datatable.tableBody).find('.' + pfx + 'datatable__lock--scroll');
// check if scrollable area have rows
if ($(scrollable).find('.' + pfx + 'datatable__row').length > 0 && $(scrollable).length > 0) {
scroll.scrollHead = $(datatable.tableHead).find('> .' + pfx + 'datatable__lock--scroll > .' + pfx + 'datatable__row');
scroll.scrollFoot = $(datatable.tableFoot).find('> .' + pfx + 'datatable__lock--scroll > .' + pfx + 'datatable__row');
scroll.tableLocked = $(datatable.tableBody).find('.' + pfx + 'datatable__lock:not(.' + pfx + 'datatable__lock--scroll)');
if (Plugin.getOption('layout.customScrollbar') && util.detectIE() != 10 && screen > util.getBreakpoint('lg')) {
scroll.initCustomScrollbar(scrollable[0]);
} else {
scroll.initDefaultScrollbar(scrollable);
}
} else if ($(datatable.tableBody).find('.' + pfx + 'datatable__row').length > 0) {
scroll.scrollHead = $(datatable.tableHead).find('> .' + pfx + 'datatable__row');
scroll.scrollFoot = $(datatable.tableFoot).find('> .' + pfx + 'datatable__row');
if (Plugin.getOption('layout.customScrollbar') && util.detectIE() != 10 && screen > util.getBreakpoint('lg')) {
scroll.initCustomScrollbar(datatable.tableBody);
} else {
scroll.initDefaultScrollbar(datatable.tableBody);
}
}
}
},
initDefaultScrollbar: function(scrollable) {
// get initial scroll position
scroll.initPosition = $(scrollable).scrollLeft();
$(scrollable).css('overflow', 'auto').off().on('scroll', scroll.onScrolling);
},
onScrolling: function(e) {
var left = $(this).scrollLeft();
var top = $(this).scrollTop();
if (util.isRTL()) {
// deduct initial position for RTL
left = left - scroll.initPosition;
}
$(scroll.scrollHead).css('left', -left);
$(scroll.scrollFoot).css('left', -left);
$(scroll.tableLocked).each(function(i, table) {
if (Plugin.isLocked()) {
// scrollbar offset
top -= 1;
}
$(table).css('top', -top);
});
},
initCustomScrollbar: function(scrollable) {
scroll.scrollable = scrollable;
// create a new instance for table body with scrollbar
Plugin.initScrollbar(scrollable);
// get initial scroll position
scroll.initPosition = $(scrollable).scrollLeft();
$(scrollable).off().on('scroll', scroll.onScrolling);
},
};
scroll.init();
return scroll;
},
/**
* Init custom scrollbar and reset position
* @param element
* @param options
*/
initScrollbar: function(element, options) {
$(datatable.tableBody).css('overflow', '');
if (util.hasClass(element, 'ps')) {
$(element).data('ps').update();
} else {
var ps = new PerfectScrollbar(element);
$(element).data('ps', ps);
// reset perfect scrollbar on resize
$(window).resize(function() {
ps.update();
});
}
},
/**
* Set column title from options.columns settings
*/
setHeadTitle: function(tablePart) {
if (typeof tablePart === 'undefined') tablePart = datatable.tableHead;
tablePart = $(tablePart)[0];
var columns = options.columns;
var row = tablePart.getElementsByTagName('tr')[0];
var ths = tablePart.getElementsByTagName('td');
if (typeof row === 'undefined') {
row = document.createElement('tr');
tablePart.appendChild(row);
}
$.each(columns, function(i, column) {
var th = ths[i];
if (typeof th === 'undefined') {
th = document.createElement('th');
row.appendChild(th);
}
// set column title
if (typeof column['title'] !== 'undefined') {
th.innerHTML = column.title;
th.setAttribute('data-field', column.field);
util.addClass(th, column.class);
// set disable autoHide or force enable
if (typeof column.autoHide !== 'undefined') {
if (column.autoHide !== true) {
th.setAttribute('data-autohide-disabled', column.autoHide);
} else {
th.setAttribute('data-autohide-enabled', column.autoHide);
}
}
$(th).data(column);
}
// set header attr option
if (typeof column.attr !== 'undefined') {
$.each(column.attr, function(key, val) {
th.setAttribute(key, val);
});
}
// apply text align to thead/tfoot
if (typeof column.textAlign !== 'undefined') {
var align = typeof datatable.textAlign[column.textAlign] !== 'undefined' ? datatable.textAlign[column.textAlign] : '';
util.addClass(th, align);
}
});
Plugin.setupDOM(tablePart);
},
/**
* Initiate to get remote or local data via ajax
*/
dataRender: function(action) {
$(datatable.table).siblings('.' + pfx + 'datatable__pager').removeClass(pfx + 'datatable--paging-loaded');
var buildMeta = function() {
datatable.dataSet = datatable.dataSet || [];
Plugin.localDataUpdate();
// local pagination meta
var meta = Plugin.getDataSourceParam('pagination');
if (meta.perpage === 0) {
meta.perpage = options.data.pageSize || 10;
}
meta.total = datatable.dataSet.length;
var start = Math.max(meta.perpage * (meta.page - 1), 0);
var end = Math.min(start + meta.perpage, meta.total);
datatable.dataSet = $(datatable.dataSet).slice(start, end);
return meta;
};
var afterGetData = function(result) {
var localPagingCallback = function(ctx, meta) {
if (!$(ctx.pager).hasClass(pfx + 'datatable--paging-loaded')) {
$(ctx.pager).remove();
ctx.init(meta);
}
$(ctx.pager).off().on(pfx + 'datatable--on-goto-page', function(e) {
$(ctx.pager).remove();
ctx.init(meta);
});
var start = Math.max(meta.perpage * (meta.page - 1), 0);
var end = Math.min(start + meta.perpage, meta.total);
Plugin.localDataUpdate();
datatable.dataSet = $(datatable.dataSet).slice(start, end);
// insert data into table content
Plugin.insertData();
};
$(datatable.wrap).removeClass(pfx + 'datatable--error');
// pagination enabled
if (options.pagination) {
if (options.data.serverPaging && options.data.type !== 'local') {
// server pagination
var serverMeta = Plugin.getObject('meta', result || null);
if (serverMeta !== null) {
Plugin.paging(serverMeta);
} else {
// no meta object from server response, fallback to local pagination
Plugin.paging(buildMeta(), localPagingCallback);
}
} else {
// local pagination can be used by remote data also
Plugin.paging(buildMeta(), localPagingCallback);
}
} else {
// pagination is disabled
Plugin.localDataUpdate();
}
// insert data into table content
Plugin.insertData();
};
// get local datasource
if (options.data.type === 'local'
// for remote json datasource
// || typeof options.data.source.read === 'undefined' && datatable.dataSet !== null
// for remote datasource, server sorting is disabled and data already received from remote
|| options.data.serverSorting === false && action === 'sort'
|| options.data.serverFiltering === false && action === 'search'
) {
setTimeout(function() {
afterGetData();
Plugin.setAutoColumns();
});
return;
}
// getting data from remote only
Plugin.getData().done(afterGetData);
},
/**
* Process ajax data
*/
insertData: function() {
datatable.dataSet = datatable.dataSet || [];
var params = Plugin.getDataSourceParam();
// get row attributes
var pagination = params.pagination;
var start = (Math.max(pagination.page, 1) - 1) * pagination.perpage;
var end = Math.min(pagination.page, pagination.pages) * pagination.perpage;
var rowProps = {};
if (typeof options.data.attr.rowProps !== 'undefined' && options.data.attr.rowProps.length) {
rowProps = options.data.attr.rowProps.slice(start, end);
}
var tableBody = document.createElement('tbody');
tableBody.style.visibility = 'hidden';
var colLength = options.columns.length;
$.each(datatable.dataSet, function(rowIndex, row) {
var tr = document.createElement('tr');
tr.setAttribute('data-row', rowIndex);
// keep data object to row
$(tr).data('obj', row);
if (typeof rowProps[rowIndex] !== 'undefined') {
$.each(rowProps[rowIndex], function() {
tr.setAttribute(this.name, this.value);
});
}
var cellIndex = 0;
var tds = [];
for (var a = 0; a < colLength; a += 1) {
var column = options.columns[a];
var classes = [];
// add sorted class to cells
if (Plugin.getObject('sort.field', params) === column.field) {
classes.push(pfx + 'datatable__cell--sorted');
}
// apply text align
if (typeof column.textAlign !== 'undefined') {
var align = typeof datatable.textAlign[column.textAlign] !== 'undefined' ? datatable.textAlign[column.textAlign] : '';
classes.push(align);
}
// var classAttr = '';
if (typeof column.class !== 'undefined') {
classes.push(column.class);
}
var td = document.createElement('td');
util.addClass(td, classes.join(' '));
td.setAttribute('data-field', column.field);
// set disable autoHide or force enable
if (typeof column.autoHide !== 'undefined') {
if (column.autoHide !== true) {
td.setAttribute('data-autohide-disabled', column.autoHide);
} else {
td.setAttribute('data-autohide-enabled', column.autoHide);
}
}
td.innerHTML = Plugin.getObject(column.field, row);
tr.appendChild(td);
}
tableBody.appendChild(tr);
});
// display no records message
if (datatable.dataSet.length === 0) {
var errorSpan = document.createElement('span');
util.addClass(errorSpan, pfx + 'datatable--error');
errorSpan.innerHTML = Plugin.getOption('translate.records.noRecords');
tableBody.appendChild(errorSpan);
$(datatable.wrap).addClass(pfx + 'datatable--error ' + pfx + 'datatable--loaded');
Plugin.spinnerCallback(false);
}
// replace existing table body
$(datatable.tableBody).replaceWith(tableBody);
datatable.tableBody = tableBody;
// layout update
Plugin.setupDOM(datatable.table);
Plugin.setupCellField([datatable.tableBody]);
Plugin.setupTemplateCell(datatable.tableBody);
Plugin.layoutUpdate();
},
updateTableComponents: function() {
datatable.tableHead = $(datatable.table).children('thead');
datatable.tableBody = $(datatable.table).children('tbody');
datatable.tableFoot = $(datatable.table).children('tfoot');
},
/**
* Call ajax for raw JSON data
*/
getData: function() {
// Plugin.spinnerCallback(true);
var ajaxParams = {
dataType: 'json',
method: 'GET',
data: {},
timeout: Plugin.getOption('data.source.read.timeout') || 30000,
};
if (options.data.type === 'local') {
ajaxParams.url = options.data.source;
}
if (options.data.type === 'remote') {
ajaxParams.url = Plugin.getOption('data.source.read.url');
if (typeof ajaxParams.url !== 'string') ajaxParams.url = Plugin.getOption('data.source.read');
if (typeof ajaxParams.url !== 'string') ajaxParams.url = Plugin.getOption('data.source');
ajaxParams.headers = Plugin.getOption('data.source.read.headers');
ajaxParams.method = Plugin.getOption('data.source.read.method') || 'POST';
var data = Plugin.getDataSourceParam();
// remove if server params is not enabled
if (!Plugin.getOption('data.serverPaging')) {
delete data['pagination'];
}
if (!Plugin.getOption('data.serverSorting')) {
delete data['sort'];
}
ajaxParams.data = $.extend({}, ajaxParams.data, data, Plugin.getOption('data.source.read.params'));
}
return $.ajax(ajaxParams).done(function(response, textStatus, jqXHR) {
datatable.lastResponse = response;
// extendible data map callback for custom datasource
datatable.dataSet = datatable.originalDataSet = Plugin.dataMapCallback(response);
Plugin.setAutoColumns();
$(datatable).trigger(pfx + 'datatable--on-ajax-done', [datatable.dataSet]);
}).fail(function(jqXHR, textStatus, errorThrown) {
$(datatable).trigger(pfx + 'datatable--on-ajax-fail', [jqXHR]);
$(datatable.tableBody).html($('<span/>').addClass(pfx + 'datatable--error').html(Plugin.getOption('translate.records.noRecords')));
$(datatable.wrap).addClass(pfx + 'datatable--error ' + pfx + 'datatable--loaded');
Plugin.spinnerCallback(false);
}).always(function() {
});
},
/**
* Pagination object
* @param meta if null, local pagination, otherwise remote pagination
* @param callback for update data when navigating page
*/
paging: function(meta, callback) {
var pg = {
meta: null,
pager: null,
paginateEvent: null,
pagerLayout: {pagination: null, info: null},
callback: null,
init: function(meta) {
pg.meta = meta;
// parse pagination meta to integer
pg.meta.page = parseInt(pg.meta.page);
pg.meta.pages = parseInt(pg.meta.pages);
pg.meta.perpage = parseInt(pg.meta.perpage);
pg.meta.total = parseInt(pg.meta.total);
// always recount total pages
pg.meta.pages = Math.max(Math.ceil(pg.meta.total / pg.meta.perpage), 1);
// current page must be not over than total pages
if (pg.meta.page > pg.meta.pages) pg.meta.page = pg.meta.pages;
// set unique event name between tables
pg.paginateEvent = Plugin.getTablePrefix();
pg.pager = $(datatable.table).siblings('.' + pfx + 'datatable__pager');
if ($(pg.pager).hasClass(pfx + 'datatable--paging-loaded')) return;
// if class .'+pfx+'datatable--paging-loaded not exist, recreate pagination
$(pg.pager).remove();
// if no pages available
if (pg.meta.pages === 0) return;
// update datasource params
Plugin.setDataSourceParam('pagination', {
page: pg.meta.page,
pages: pg.meta.pages,
perpage: pg.meta.perpage,
total: pg.meta.total,
});
// default callback function, contains remote pagination handler
pg.callback = pg.serverCallback;
// custom callback function
if (typeof callback === 'function') pg.callback = callback;
pg.addPaginateEvent();
pg.populate();
pg.meta.page = Math.max(pg.meta.page || 1, pg.meta.page);
$(datatable).trigger(pg.paginateEvent, pg.meta);
pg.pagingBreakpoint.call();
$(window).resize(pg.pagingBreakpoint);
},
serverCallback: function(ctx, meta) {
Plugin.dataRender();
},
populate: function() {
var icons = Plugin.getOption('layout.icons.pagination');
var title = Plugin.getOption('translate.toolbar.pagination.items.default');
// pager root element
pg.pager = $('<div/>').addClass(pfx + 'datatable__pager ' + pfx + 'datatable--paging-loaded clearfix');
// numbering links
var pagerNumber = $('<ul/>').addClass(pfx + 'datatable__pager-nav');
pg.pagerLayout['pagination'] = pagerNumber;
// pager first/previous button
$('<li/>').
append($('<a/>').
attr('title', title.first).
addClass(pfx + 'datatable__pager-link ' + pfx + 'datatable__pager-link--first').
append($('<i/>').addClass(icons.first)).
on('click', pg.gotoMorePage).
attr('data-page', 1)).
appendTo(pagerNumber);
$('<li/>').
append($('<a/>').
attr('title', title.prev).
addClass(pfx + 'datatable__pager-link ' + pfx + 'datatable__pager-link--prev').
append($('<i/>').addClass(icons.prev)).
on('click', pg.gotoMorePage)).
appendTo(pagerNumber);
// more previous pages
$('<li/>').
append($('<a/>').
attr('title', title.more).
addClass(pfx + 'datatable__pager-link ' + pfx + 'datatable__pager-link--more-prev').
html($('<i/>').addClass(icons.more)).
on('click', pg.gotoMorePage)).
appendTo(pagerNumber);
$('<li/>').append($('<input/>').attr('type', 'text').addClass(pfx + 'pager-input form-control').attr('title', title.input).on('keyup', function() {
// on keyup update [data-page]
$(this).attr('data-page', Math.abs($(this).val()));
}).on('keypress', function(e) {
// on keypressed enter button
if (e.which === 13) pg.gotoMorePage(e);
})).appendTo(pagerNumber);
var pagesNumber = Plugin.getOption('toolbar.items.pagination.pages.desktop.pagesNumber');
var end = Math.ceil(pg.meta.page / pagesNumber) * pagesNumber;
var start = end - pagesNumber;
if (end > pg.meta.pages) {
end = pg.meta.pages;
}
for (var x = start; x < end; x++) {
var pageNumber = x + 1;
$('<li/>').
append($('<a/>').
addClass(pfx + 'datatable__pager-link ' + pfx + 'datatable__pager-link-number').
text(pageNumber).
attr('data-page', pageNumber).
attr('title', pageNumber).
on('click', pg.gotoPage)).
appendTo(pagerNumber);
}
// more next pages
$('<li/>').
append($('<a/>').
attr('title', title.more).
addClass(pfx + 'datatable__pager-link ' + pfx + 'datatable__pager-link--more-next').
html($('<i/>').addClass(icons.more)).
on('click', pg.gotoMorePage)).
appendTo(pagerNumber);
// pager next/last button
$('<li/>').
append($('<a/>').
attr('title', title.next).
addClass(pfx + 'datatable__pager-link ' + pfx + 'datatable__pager-link--next').
append($('<i/>').addClass(icons.next)).
on('click', pg.gotoMorePage)).
appendTo(pagerNumber);
$('<li/>').
append($('<a/>').
attr('title', title.last).
addClass(pfx + 'datatable__pager-link ' + pfx + 'datatable__pager-link--last').
append($('<i/>').addClass(icons.last)).
on('click', pg.gotoMorePage).
attr('data-page', pg.meta.pages)).
appendTo(pagerNumber);
// page info
if (Plugin.getOption('toolbar.items.info')) {
pg.pagerLayout['info'] = $('<div/>').addClass(pfx + 'datatable__pager-info').append($('<span/>').addClass(pfx + 'datatable__pager-detail'));
}
$.each(Plugin.getOption('toolbar.layout'), function(i, layout) {
$(pg.pagerLayout[layout]).appendTo(pg.pager);
});
// page size select
var pageSizeSelect = $('<select/>').
addClass('selectpicker ' + pfx + 'datatable__pager-size').
attr('title', Plugin.getOption('translate.toolbar.pagination.items.default.select')).
attr('data-width', '70px').
val(pg.meta.perpage).
on('change', pg.updatePerpage).
prependTo(pg.pagerLayout['info']);
var pageSizes = Plugin.getOption('toolbar.items.pagination.pageSizeSelect');
// default value here, to fix override option by user
if (pageSizes.length == 0) pageSizes = [10, 20, 30, 50, 100];
$.each(pageSizes, function(i, size) {
var display = size;
if (size === -1) display = Plugin.getOption('translate.toolbar.pagination.items.default.all');
$('<option/>').attr('value', size).html(display).appendTo(pageSizeSelect);
});
// init selectpicker to dropdown
$(datatable).ready(function() {
$('.selectpicker').
selectpicker().
on('hide.bs.select', function() {
// fix dropup arrow icon on hide
$(this).closest('.bootstrap-select').removeClass('dropup');
}).
siblings('.dropdown-toggle').
attr('title', Plugin.getOption('translate.toolbar.pagination.items.default.select'));
});
pg.paste();
},
paste: function() {
// insert pagination based on placement position, top|bottom
$.each($.unique(Plugin.getOption('toolbar.placement')),
function(i, position) {
if (position === 'bottom') {
$(pg.pager).clone(true).insertAfter(datatable.table);
}
if (position === 'top') {
// pager top need some extra space
$(pg.pager).clone(true).addClass(pfx + 'datatable__pager--top').insertBefore(datatable.table);
}
});
},
gotoMorePage: function(e) {
e.preventDefault();
// $(this) is a link of .'+pfx+'datatable__pager-link
if ($(this).attr('disabled') === 'disabled') return false;
var page = $(this).attr('data-page');
// event from text input
if (typeof page === 'undefined') {
page = $(e.target).attr('data-page');
}
pg.openPage(parseInt(page));
return false;
},
gotoPage: function(e) {
e.preventDefault();
// prevent from click same page number
if ($(this).hasClass(pfx + 'datatable__pager-link--active')) return;
pg.openPage(parseInt($(this).data('page')));
},
openPage: function(page) {
// currentPage is 1-based index
pg.meta.page = parseInt(page);
$(datatable).trigger(pg.paginateEvent, pg.meta);
pg.callback(pg, pg.meta);
// update page callback function
$(pg.pager).trigger(pfx + 'datatable--on-goto-page', pg.meta);
},
updatePerpage: function(e) {
e.preventDefault();
// if (Plugin.getOption('layout.height') === null) {
// fix white space, when perpage is set from many records to less records
// $('html, body').animate({scrollTop: $(datatable).position().top});
// }
pg.pager = $(datatable.table).siblings('.' + pfx + 'datatable__pager').removeClass(pfx + 'datatable--paging-loaded');
// on change select page size
if (e.originalEvent) {
pg.meta.perpage = parseInt($(this).val());
}
$(pg.pager).find('select.' + pfx + 'datatable__pager-size').val(pg.meta.perpage).attr('data-selected', pg.meta.perpage);
// update datasource params
Plugin.setDataSourceParam('pagination', {
page: pg.meta.page,
pages: pg.meta.pages,
perpage: pg.meta.perpage,
total: pg.meta.total,
});
// update page callback function
$(pg.pager).trigger(pfx + 'datatable--on-update-perpage', pg.meta);
$(datatable).trigger(pg.paginateEvent, pg.meta);
pg.callback(pg, pg.meta);
// update pagination info
pg.updateInfo.call();
},
addPaginateEvent: function(e) {
// pagination event
$(datatable).off(pg.paginateEvent).on(pg.paginateEvent, function(e, meta) {
Plugin.spinnerCallback(true);
pg.pager = $(datatable.table).siblings('.' + pfx + 'datatable__pager');
var pagerNumber = $(pg.pager).find('.' + pfx + 'datatable__pager-nav');
// set sync active page class
$(pagerNumber).find('.' + pfx + 'datatable__pager-link--active').removeClass(pfx + 'datatable__pager-link--active');
$(pagerNumber).find('.' + pfx + 'datatable__pager-link-number[data-page="' + meta.page + '"]').addClass(pfx + 'datatable__pager-link--active');
// set next and previous link page number
$(pagerNumber).find('.' + pfx + 'datatable__pager-link--prev').attr('data-page', Math.max(meta.page - 1, 1));
$(pagerNumber).find('.' + pfx + 'datatable__pager-link--next').attr('data-page', Math.min(meta.page + 1, meta.pages));
// current page input value sync
$(pg.pager).each(function() {
$(this).find('.' + pfx + 'pager-input[type="text"]').prop('value', meta.page);
});
$(pg.pager).find('.' + pfx + 'datatable__pager-nav').show();
if (meta.pages <= 1) {
// hide pager if has 1 page
$(pg.pager).find('.' + pfx + 'datatable__pager-nav').hide();
}
// update datasource params
Plugin.setDataSourceParam('pagination', {
page: pg.meta.page,
pages: pg.meta.pages,
perpage: pg.meta.perpage,
total: pg.meta.total,
});
$(pg.pager).find('select.' + pfx + 'datatable__pager-size').val(meta.perpage).attr('data-selected', meta.perpage);
// clear active rows
$(datatable.table).find('.' + pfx + 'checkbox > [type="checkbox"]').prop('checked', false);
$(datatable.table).find('.' + pfx + 'datatable__row--active').removeClass(pfx + 'datatable__row--active');
pg.updateInfo.call();
pg.pagingBreakpoint.call();
// Plugin.resetScroll();
});
},
updateInfo: function() {
var start = Math.max(pg.meta.perpage * (pg.meta.page - 1) + 1, 1);
var end = Math.min(start + pg.meta.perpage - 1, pg.meta.total);
// page info update
$(pg.pager).find('.' + pfx + 'datatable__pager-info').find('.' + pfx + 'datatable__pager-detail').html(Plugin.dataPlaceholder(
Plugin.getOption('translate.toolbar.pagination.items.info'), {
start: start,
end: pg.meta.perpage === -1 ? pg.meta.total : end,
pageSize: pg.meta.perpage === -1 ||
pg.meta.perpage >= pg.meta.total
? pg.meta.total
: pg.meta.perpage,
total: pg.meta.total,
}));
},
/**
* Update pagination layout breakpoint
*/
pagingBreakpoint: function() {
// keep page links reference
var pagerNumber = $(datatable.table).siblings('.' + pfx + 'datatable__pager').find('.' + pfx + 'datatable__pager-nav');
if ($(pagerNumber).length === 0) return;
var currentPage = Plugin.getCurrentPage();
var pagerInput = $(pagerNumber).find('.' + pfx + 'pager-input').closest('li');
// reset
$(pagerNumber).find('li').show();
// pagination update
$.each(Plugin.getOption('toolbar.items.pagination.pages'),
function(mode, option) {
if (util.isInResponsiveRange(mode)) {
switch (mode) {
case 'desktop':
case 'tablet':
var end = Math.ceil(currentPage / option.pagesNumber) *
option.pagesNumber;
var start = end - option.pagesNumber;
$(pagerInput).hide();
pg.meta = Plugin.getDataSourceParam('pagination');
pg.paginationUpdate();
break;
case 'mobile':
$(pagerInput).show();
$(pagerNumber).find('.' + pfx + 'datatable__pager-link--more-prev').closest('li').hide();
$(pagerNumber).find('.' + pfx + 'datatable__pager-link--more-next').closest('li').hide();
$(pagerNumber).find('.' + pfx + 'datatable__pager-link-number').closest('li').hide();
break;
}
return false;
}
});
},
/**
* Update pagination number and button display
*/
paginationUpdate: function() {
var pager = $(datatable.table).siblings('.' + pfx + 'datatable__pager').find('.' + pfx + 'datatable__pager-nav'),
pagerMorePrev = $(pager).find('.' + pfx + 'datatable__pager-link--more-prev'),
pagerMoreNext = $(pager).find('.' + pfx + 'datatable__pager-link--more-next'),
pagerFirst = $(pager).find('.' + pfx + 'datatable__pager-link--first'),
pagerPrev = $(pager).find('.' + pfx + 'datatable__pager-link--prev'),
pagerNext = $(pager).find('.' + pfx + 'datatable__pager-link--next'),
pagerLast = $(pager).find('.' + pfx + 'datatable__pager-link--last');
// get visible page
var pagerNumber = $(pager).find('.' + pfx + 'datatable__pager-link-number');
// get page before of first visible
var morePrevPage = Math.max($(pagerNumber).first().data('page') - 1,
1);
$(pagerMorePrev).each(function(i, prev) {
$(prev).attr('data-page', morePrevPage);
});
// show/hide <li>
if (morePrevPage === 1) {
$(pagerMorePrev).parent().hide();
} else {
$(pagerMorePrev).parent().show();
}
// get page after of last visible
var moreNextPage = Math.min($(pagerNumber).last().data('page') + 1,
pg.meta.pages);
$(pagerMoreNext).each(function(i, prev) {
$(pagerMoreNext).attr('data-page', moreNextPage).show();
});
// show/hide <li>
if (moreNextPage === pg.meta.pages
// missing dot fix when last hidden page is one left
&& moreNextPage === $(pagerNumber).last().data('page')) {
$(pagerMoreNext).parent().hide();
} else {
$(pagerMoreNext).parent().show();
}
// begin/end of pages
if (pg.meta.page === 1) {
$(pagerFirst).attr('disabled', true).addClass(pfx + 'datatable__pager-link--disabled');
$(pagerPrev).attr('disabled', true).addClass(pfx + 'datatable__pager-link--disabled');
} else {
$(pagerFirst).removeAttr('disabled').removeClass(pfx + 'datatable__pager-link--disabled');
$(pagerPrev).removeAttr('disabled').removeClass(pfx + 'datatable__pager-link--disabled');
}
if (pg.meta.page === pg.meta.pages) {
$(pagerNext).attr('disabled', true).addClass(pfx + 'datatable__pager-link--disabled');
$(pagerLast).attr('disabled', true).addClass(pfx + 'datatable__pager-link--disabled');
} else {
$(pagerNext).removeAttr('disabled').removeClass(pfx + 'datatable__pager-link--disabled');
$(pagerLast).removeAttr('disabled').removeClass(pfx + 'datatable__pager-link--disabled');
}
// display more buttons
var nav = Plugin.getOption('toolbar.items.pagination.navigation');
if (!nav.first) $(pagerFirst).remove();
if (!nav.prev) $(pagerPrev).remove();
if (!nav.next) $(pagerNext).remove();
if (!nav.last) $(pagerLast).remove();
},
};
pg.init(meta);
return pg;
},
/**
* Hide/show table cell defined by
* options[columns][i][responsive][visible/hidden]
*/
columnHide: function() {
var screen = util.getViewPort().width;
// foreach columns setting
$.each(options.columns, function(i, column) {
if (typeof column.responsive !== 'undefined') {
var field = column.field;
var tds = $.grep($(datatable.table).find('.' + pfx + 'datatable__cell'), function(n, i) {
return field === $(n).data('field');
});
if (util.getBreakpoint(column.responsive.hidden) >= screen) {
$(tds).hide();
} else {
$(tds).show();
}
if (util.getBreakpoint(column.responsive.visible) <= screen) {
$(tds).show();
} else {
$(tds).hide();
}
}
});
},
/**
* Setup sub datatable
*/
setupSubDatatable: function() {
var subTableCallback = Plugin.getOption('detail.content');
if (typeof subTableCallback !== 'function') return;
// subtable already exist
if ($(datatable.table).find('.' + pfx + 'datatable__subtable').length > 0) return;
$(datatable.wrap).addClass(pfx + 'datatable--subtable');
options.columns[0]['subtable'] = true;
// toggle on open sub table
var toggleSubTable = function(e) {
e.preventDefault();
// get parent row of this subtable
var parentRow = $(this).closest('.' + pfx + 'datatable__row');
// get subtable row for sub table
var subTableRow = $(parentRow).next('.' + pfx + 'datatable__row-subtable');
if ($(subTableRow).length === 0) {
// prepare DOM for sub table, each <tr> as parent and add <tr> as child table
subTableRow = $('<tr/>').
addClass(pfx + 'datatable__row-subtable ' + pfx + 'datatable__row-loading').
hide().
append($('<td/>').addClass(pfx + 'datatable__subtable').attr('colspan', Plugin.getTotalColumns()));
$(parentRow).after(subTableRow);
// add class to even row
if ($(parentRow).hasClass(pfx + 'datatable__row--even')) {
$(subTableRow).addClass(pfx + 'datatable__row-subtable--even');
}
}
$(subTableRow).toggle();
var subTable = $(subTableRow).find('.' + pfx + 'datatable__subtable');
// get id from first column of parent row
var primaryKey = $(this).closest('[data-field]:first-child').find('.' + pfx + 'datatable__toggle-subtable').data('value');
var icon = $(this).find('i').removeAttr('class');
// prevent duplicate datatable init
if ($(parentRow).hasClass(pfx + 'datatable__row--subtable-expanded')) {
$(icon).addClass(Plugin.getOption('layout.icons.rowDetail.collapse'));
// remove expand class from parent row
$(parentRow).removeClass(pfx + 'datatable__row--subtable-expanded');
// trigger event on collapse
$(datatable).trigger(pfx + 'datatable--on-collapse-subtable', [parentRow]);
} else {
// expand and run callback function
$(icon).addClass(Plugin.getOption('layout.icons.rowDetail.expand'));
// add expand class to parent row
$(parentRow).addClass(pfx + 'datatable__row--subtable-expanded');
// trigger event on expand
$(datatable).trigger(pfx + 'datatable--on-expand-subtable', [parentRow]);
}
// prevent duplicate datatable init
if ($(subTable).find('.' + pfx + 'datatable').length === 0) {
// get data by primary id
$.map(datatable.dataSet, function(n, i) {
// primary id must be at the first column, otherwise e.data will be undefined
if (primaryKey === n[options.columns[0].field]) {
e.data = n;
return true;
}
return false;
});
// deprecated in v5.0.6
e.detailCell = subTable;
e.parentRow = parentRow;
e.subTable = subTable;
// run callback with event
subTableCallback(e);
$(subTable).children('.' + pfx + 'datatable').on(pfx + 'datatable--on-init', function(e) {
$(subTableRow).removeClass(pfx + 'datatable__row-loading');
});
if (Plugin.getOption('data.type') === 'local') {
$(subTableRow).removeClass(pfx + 'datatable__row-loading');
}
}
};
var columns = options.columns;
$(datatable.tableBody).find('.' + pfx + 'datatable__row').each(function(tri, tr) {
$(tr).find('.' + pfx + 'datatable__cell').each(function(tdi, td) {
// get column settings by field
var column = $.grep(columns, function(n, i) {
return $(td).data('field') === n.field;
})[0];
if (typeof column !== 'undefined') {
var value = $(td).text();
// enable column subtable toggle
if (typeof column.subtable !== 'undefined' && column.subtable) {
// check if subtable toggle exist
if ($(td).find('.' + pfx + 'datatable__toggle-subtable').length > 0) return;
// append subtable toggle
$(td).
html($('<a/>').
addClass(pfx + 'datatable__toggle-subtable').
attr('href', '#').
attr('data-value', value).
attr('title', Plugin.getOption('detail.title')).
on('click', toggleSubTable).
append($('<i/>').css('width', $(td).data('width')).addClass(Plugin.getOption('layout.icons.rowDetail.collapse'))));
}
}
});
});
// $(datatable.tableHead).find('.'+pfx+'-datatable__row').first()
},
/**
* Datasource mapping callback
*/
dataMapCallback: function(raw) {
// static dataset array
var dataSet = raw;
// dataset mapping callback
if (typeof Plugin.getOption('data.source.read.map') === 'function') {
return Plugin.getOption('data.source.read.map')(raw);
} else {
// default data mapping fallback
if (typeof raw !== 'undefined' && typeof raw.data !== 'undefined') {
dataSet = raw.data;
}
}
return dataSet;
},
isSpinning: false,
/**
* BlockUI spinner callback
* @param block
* @param target
*/
spinnerCallback: function(block, target) {
if (typeof target === 'undefined') target = datatable;
// get spinner options
var spinnerOptions = Plugin.getOption('layout.spinner');
// spinner is disabled
if (typeof spinnerOptions === 'undefined' || !spinnerOptions) {
return;
}
if (block) {
if (!Plugin.isSpinning) {
if (typeof spinnerOptions.message !== 'undefined' && spinnerOptions.message === true) {
// use default spinner message from translation
spinnerOptions.message = Plugin.getOption('translate.records.processing');
}
Plugin.isSpinning = true;
if (typeof app !== 'undefined') {
app.block(target, spinnerOptions);
}
}
} else {
Plugin.isSpinning = false;
if (typeof app !== 'undefined') {
app.unblock(target);
}
}
},
/**
* Default sort callback function
* @param data
* @param sort
* @param column
* @returns {*|Array.<T>|{sort, field}|{asc, desc}}
*/
sortCallback: function(data, sort, column) {
var type = column['type'] || 'string';
var format = column['format'] || '';
var field = column['field'];
return $(data).sort(function(a, b) {
var aField = a[field];
var bField = b[field];
switch (type) {
case 'date':
if (typeof moment === 'undefined') {
throw new Error('Moment.js is required.');
}
var diff = moment(aField, format).diff(moment(bField, format));
if (sort === 'asc') {
return diff > 0 ? 1 : diff < 0 ? -1 : 0;
} else {
return diff < 0 ? 1 : diff > 0 ? -1 : 0;
}
break;
case 'number':
if (isNaN(parseFloat(aField)) && aField != null) {
aField = Number(aField.replace(/[^0-9\.-]+/g, ''));
}
if (isNaN(parseFloat(bField)) && bField != null) {
bField = Number(bField.replace(/[^0-9\.-]+/g, ''));
}
aField = parseFloat(aField);
bField = parseFloat(bField);
if (sort === 'asc') {
return aField > bField ? 1 : aField < bField ? -1 : 0;
} else {
return aField < bField ? 1 : aField > bField ? -1 : 0;
}
break;
case 'string':
default:
if (sort === 'asc') {
return aField > bField ? 1 : aField < bField ? -1 : 0;
} else {
return aField < bField ? 1 : aField > bField ? -1 : 0;
}
break;
}
});
},
/**
* Custom debug log
* @param text
* @param obj
*/
log: function(text, obj) {
if (typeof obj === 'undefined') obj = '';
if (datatable.debug) {
console.log(text, obj);
}
},
/**
* Auto hide columnds overflow in row
*/
autoHide: function() {
var hiddenExist = false;
$(datatable.table).find('.' + pfx + 'datatable__cell').show();
// force hide enabled
var hidDefault = $(datatable.table).find('[data-autohide-enabled]');
if (hidDefault.length) {
hiddenExist = true;
hidDefault.hide();
}
$(datatable.tableBody).each(function() {
while ($(this)[0].offsetWidth < $(this)[0].scrollWidth) {
$(datatable.table).find('.' + pfx + 'datatable__row').each(function(i) {
var cell = $(this).find('.' + pfx + 'datatable__cell').not(':hidden').not('[data-autohide-disabled]').last();
$(cell).hide();
hiddenExist = true;
});
}
});
if (!hiddenExist) {
// no column is hidden, skip expand icons
return;
}
var toggleHiddenColumns = function(e) {
e.preventDefault();
var row = $(this).closest('.' + pfx + 'datatable__row');
var detailRow = $(row).next();
if (!$(detailRow).hasClass(pfx + 'datatable__row-detail')) {
$(this).find('i').removeClass(Plugin.getOption('layout.icons.rowDetail.collapse')).addClass(Plugin.getOption('layout.icons.rowDetail.expand'));
var hidden = $(row).find('.' + pfx + 'datatable__cell:hidden').clone().show();
detailRow = $('<tr/>').addClass(pfx + 'datatable__row-detail').insertAfter(row);
var detailRowTd = $('<td/>').addClass(pfx + 'datatable__detail').attr('colspan', Plugin.getTotalColumns()).appendTo(detailRow);
var detailSubTable = $('<table/>');
$(hidden).each(function() {
var field = $(this).data('field');
var column = $.grep(options.columns, function(n, i) {
return field === n.field;
})[0];
$(detailSubTable).
append($('<tr class="' + pfx + 'datatable__row"></tr>').
append($('<td class="' + pfx + 'datatable__cell"></td>').append($('<span/>').append(column.title))).
append(this));
});
$(detailRowTd).append(detailSubTable);
} else {
$(this).find('i').removeClass(Plugin.getOption('layout.icons.rowDetail.expand')).addClass(Plugin.getOption('layout.icons.rowDetail.collapse'));
$(detailRow).remove();
}
};
// toggle show hidden columns
$(datatable.tableBody).find('.' + pfx + 'datatable__row').each(function() {
$(this).
prepend($('<td/>').
addClass(pfx + 'datatable__cell ' + pfx + 'datatable__toggle-detail').
append($('<a/>').
addClass(pfx + 'datatable__toggle-detail').
attr('href', '').
on('click', toggleHiddenColumns).
append('<i class="' + Plugin.getOption('layout.icons.rowDetail.collapse') + '"></i>')));
// check if subtable toggle exist
if ($(datatable.tableHead).find('.' + pfx + 'datatable__toggle-detail').length === 0) {
$(datatable.tableHead).
find('.' + pfx + 'datatable__row').
first().
prepend('<th class="' + pfx + 'datatable__cell ' + pfx + 'datatable__toggle-detail"><span></span></th>');
$(datatable.tableFoot).
find('.' + pfx + 'datatable__row').
first().
prepend('<th class="' + pfx + 'datatable__cell ' + pfx + 'datatable__toggle-detail"><span></span></th>');
} else {
$(datatable.tableHead).find('.' + pfx + 'datatable__toggle-detail').find('span');
}
});
Plugin.adjustCellsWidth.call();
},
/**
* To enable auto columns features for remote data source
*/
setAutoColumns: function() {
if (Plugin.getOption('data.autoColumns')) {
$.each(datatable.dataSet[0], function(k, v) {
var found = $.grep(options.columns, function(n, i) {
return k === n.field;
});
if (found.length === 0) {
options.columns.push({field: k, title: k});
}
});
$(datatable.tableHead).find('.' + pfx + 'datatable__row').remove();
Plugin.setHeadTitle();
if (Plugin.getOption('layout.footer')) {
$(datatable.tableFoot).find('.' + pfx + 'datatable__row').remove();
Plugin.setHeadTitle(datatable.tableFoot);
}
}
},
/********************
** HELPERS
********************/
/**
* Check if table is a locked colums table
*/
isLocked: function() {
return util.hasClass(datatable.wrap[0], pfx + 'datatable--lock') || false;
},
isSubtable: function() {
return util.hasClass(datatable.wrap[0], pfx + 'datatable--subtable') || false;
},
/**
* Get total extra space of an element for width calculation, including
* padding, margin, border
* @param element
* @returns {number}
*/
getExtraSpace: function(element) {
var padding = parseInt($(element).css('paddingRight')) +
parseInt($(element).css('paddingLeft'));
var margin = parseInt($(element).css('marginRight')) +
parseInt($(element).css('marginLeft'));
var border = Math.ceil(
$(element).css('border-right-width').replace('px', ''));
return padding + margin + border;
},
/**
* Insert data of array into {{ }} template placeholder
* @param template
* @param data
* @returns {*}
*/
dataPlaceholder: function(template, data) {
var result = template;
$.each(data, function(key, val) {
result = result.replace('{{' + key + '}}', val);
});
return result;
},
/**
* Get table unique ID
* Note: table unique change each time refreshed
* @param suffix
* @returns {*}
*/
getTableId: function(suffix) {
if (typeof suffix === 'undefined') suffix = '';
var id = $(datatable).attr('id');
if (typeof id === 'undefined') {
id = $(datatable).attr('class').split(' ')[0];
}
return id + suffix;
},
/**
* Get table prefix with depth number
*/
getTablePrefix: function(suffix) {
if (typeof suffix !== 'undefined') suffix = '-' + suffix;
return Plugin.getTableId() + '-' + Plugin.getDepth() + suffix;
},
/**
* Get current table depth of sub table
* @returns {number}
*/
getDepth: function() {
var depth = 0;
var table = datatable.table;
do {
table = $(table).parents('.' + pfx + 'datatable__table');
depth++;
} while ($(table).length > 0);
return depth;
},
/**
* Keep state item
* @param key
* @param value
*/
stateKeep: function(key, value) {
key = Plugin.getTablePrefix(key);
if (Plugin.getOption('data.saveState') === false) return;
if (Plugin.getOption('data.saveState.webstorage') && localStorage) {
localStorage.setItem(key, JSON.stringify(value));
}
if (Plugin.getOption('data.saveState.cookie')) {
Cookies.set(key, JSON.stringify(value));
}
},
/**
* Get state item
* @param key
* @param defValue
*/
stateGet: function(key, defValue) {
key = Plugin.getTablePrefix(key);
if (Plugin.getOption('data.saveState') === false) return;
var value = null;
if (Plugin.getOption('data.saveState.webstorage') && localStorage) {
value = localStorage.getItem(key);
} else {
value = Cookies.get(key);
}
if (typeof value !== 'undefined' && value !== null) {
return JSON.parse(value);
}
},
/**
* Update data in state without clear existing
* @param key
* @param value
*/
stateUpdate: function(key, value) {
var ori = Plugin.stateGet(key);
if (typeof ori === 'undefined' || ori === null) ori = {};
Plugin.stateKeep(key, $.extend({}, ori, value));
},
/**
* Remove state item
* @param key
*/
stateRemove: function(key) {
key = Plugin.getTablePrefix(key);
if (localStorage) {
localStorage.removeItem(key);
}
Cookies.remove(key);
},
/**
* Get total columns.
*/
getTotalColumns: function(tablePart) {
if (typeof tablePart === 'undefined') tablePart = datatable.tableBody;
return $(tablePart).find('.' + pfx + 'datatable__row').first().find('.' + pfx + 'datatable__cell').length;
},
/**
* Get table row. Useful to get row when current table is in lock mode.
* Can be used for both lock and normal table mode.
* By default, returning result will be in a list of <td>.
* @param tablePart
* @param row 1-based index
* @param tdOnly Optional. Default true
* @returns {*}
*/
getOneRow: function(tablePart, row, tdOnly) {
if (typeof tdOnly === 'undefined') tdOnly = true;
// get list of <tr>
var result = $(tablePart).find('.' + pfx + 'datatable__row:not(.' + pfx + 'datatable__row-detail):nth-child(' + row + ')');
if (tdOnly) {
// get list of <td> or <th>
result = result.find('.' + pfx + 'datatable__cell');
}
return result;
},
/**
* Check if element has vertical overflow
* @param element
* @returns {boolean}
*/
hasOverflowY: function(element) {
var children = $(element).find('.' + pfx + 'datatable__row');
var maxHeight = 0;
if (children.length > 0) {
$(children).each(function(tdi, td) {
maxHeight += Math.floor($(td).innerHeight());
});
return maxHeight > $(element).innerHeight();
}
return false;
},
/**
* Sort table row at HTML level by column index.
* todo; Not in use.
* @param header Header sort clicked
* @param sort asc|desc. Optional. Default asc
* @param int Boolean. Optional. Comparison value parse to integer.
* Default false
*/
sortColumn: function(header, sort, int) {
if (typeof sort === 'undefined') sort = 'asc'; // desc
if (typeof int === 'undefined') int = false;
var column = $(header).index();
var rows = $(datatable.tableBody).find('.' + pfx + 'datatable__row');
var hIndex = $(header).closest('.' + pfx + 'datatable__lock').index();
if (hIndex !== -1) {
rows = $(datatable.tableBody).find('.' + pfx + 'datatable__lock:nth-child(' + (hIndex + 1) + ')').find('.' + pfx + 'datatable__row');
}
var container = $(rows).parent();
$(rows).sort(function(a, b) {
var tda = $(a).find('td:nth-child(' + column + ')').text();
var tdb = $(b).find('td:nth-child(' + column + ')').text();
if (int) {
// useful for integer type sorting
tda = parseInt(tda);
tdb = parseInt(tdb);
}
if (sort === 'asc') {
return tda > tdb ? 1 : tda < tdb ? -1 : 0;
} else {
return tda < tdb ? 1 : tda > tdb ? -1 : 0;
}
}).appendTo(container);
},
/**
* Perform sort remote and local
*/
sorting: function() {
var sortObj = {
init: function() {
if (options.sortable) {
$(datatable.tableHead).
find('.' + pfx + 'datatable__cell:not(.' + pfx + 'datatable__cell--check)').
addClass(pfx + 'datatable__cell--sort').
off('click').
on('click', sortObj.sortClick);
// first init
sortObj.setIcon();
}
},
setIcon: function() {
var meta = Plugin.getDataSourceParam('sort');
if ($.isEmptyObject(meta)) return;
var column = Plugin.getColumnByField(meta.field);
// sort is disabled for this column
if (typeof column !== 'undefined' && typeof column.sortable !== 'undefined' && column.sortable === false) return;
// sort icon beside column header
var td = $(datatable.tableHead).find('.' + pfx + 'datatable__cell[data-field="' + meta.field + '"]').attr('data-sort', meta.sort);
var sorting = $(td).find('span');
var icon = $(sorting).find('i');
var icons = Plugin.getOption('layout.icons.sort');
// update sort icon; desc & asc
if ($(icon).length > 0) {
$(icon).removeAttr('class').addClass(icons[meta.sort]);
} else {
$(sorting).append($('<i/>').addClass(icons[meta.sort]));
}
// set sorted class to header on init
$(td).addClass(pfx + 'datatable__cell--sorted');
},
sortClick: function(e) {
var meta = Plugin.getDataSourceParam('sort');
var field = $(this).data('field');
var column = Plugin.getColumnByField(field);
// sort is disabled for this column
if (typeof column.sortable !== 'undefined' && column.sortable === false) return;
// set sorted class to header
$(datatable.tableHead).find('th').removeClass(pfx + 'datatable__cell--sorted');
util.addClass(this, pfx + 'datatable__cell--sorted');
$(datatable.tableHead).find('.' + pfx + 'datatable__cell > span > i').remove();
if (options.sortable) {
Plugin.spinnerCallback(true);
var sort = 'desc';
if (Plugin.getObject('field', meta) === field) {
sort = Plugin.getObject('sort', meta);
}
// toggle sort
sort = typeof sort === 'undefined' || sort === 'desc'
? 'asc'
: 'desc';
// update field and sort params
meta = {field: field, sort: sort};
Plugin.setDataSourceParam('sort', meta);
sortObj.setIcon();
setTimeout(function() {
Plugin.dataRender('sort');
$(datatable).trigger(pfx + 'datatable--on-sort', meta);
}, 300);
}
},
};
sortObj.init();
},
/**
* Update JSON data list linked with sort, filter and pagination.
* Call this method, before using dataSet variable.
* @returns {*|null}
*/
localDataUpdate: function() {
var params = Plugin.getDataSourceParam();
if (typeof datatable.originalDataSet === 'undefined') {
datatable.originalDataSet = datatable.dataSet;
}
var field = Plugin.getObject('sort.field', params);
var sort = Plugin.getObject('sort.sort', params);
var column = Plugin.getColumnByField(field);
if (typeof column !== 'undefined' && Plugin.getOption('data.serverSorting') !== true) {
if (typeof column.sortCallback === 'function') {
datatable.dataSet = column.sortCallback(datatable.originalDataSet, sort, column);
} else {
datatable.dataSet = Plugin.sortCallback(datatable.originalDataSet, sort, column);
}
} else {
datatable.dataSet = datatable.originalDataSet;
}
// if server filter enable, don't pass local filter
if (typeof params.query === 'object' && !Plugin.getOption('data.serverFiltering')) {
params.query = params.query || {};
var nestedSearch = function(obj) {
for (var field in obj) {
if (!obj.hasOwnProperty(field)) continue;
if (typeof obj[field] === 'string') {
if (obj[field].toLowerCase() == search || obj[field].toLowerCase().indexOf(search) !== -1) {
return true;
}
} else if (typeof obj[field] === 'number') {
if (obj[field] === search) {
return true;
}
} else if (typeof obj[field] === 'object') {
if (nestedSearch(obj[field])) {
return true;
}
}
}
return false;
};
var search = $(Plugin.getOption('search.input')).val();
if (typeof search !== 'undefined' && search !== '') {
search = search.toLowerCase();
datatable.dataSet = $.grep(datatable.dataSet, nestedSearch);
// remove generalSearch as we don't need this for next columns filter
delete params.query[Plugin.getGeneralSearchKey()];
}
// remove empty element from array
$.each(params.query, function(k, v) {
if (v === '') {
delete params.query[k];
}
});
// filter array by query
datatable.dataSet = Plugin.filterArray(datatable.dataSet, params.query);
// reset array index
datatable.dataSet = datatable.dataSet.filter(function() {
return true;
});
}
return datatable.dataSet;
},
/**
* Utility helper to filter array by object pair of {key:value}
* @param list
* @param args
* @param operator
* @returns {*}
*/
filterArray: function(list, args, operator) {
if (typeof list !== 'object') {
return [];
}
if (typeof operator === 'undefined') operator = 'AND';
if (typeof args !== 'object') {
return list;
}
operator = operator.toUpperCase();
if ($.inArray(operator, ['AND', 'OR', 'NOT']) === -1) {
return [];
}
var count = Object.keys(args).length;
var filtered = [];
$.each(list, function(key, obj) {
var to_match = obj;
var matched = 0;
$.each(args, function(m_key, m_value) {
m_value = m_value instanceof Array ? m_value : [m_value];
var match_property = Plugin.getObject(m_key, to_match);
if (typeof match_property !== 'undefined') {
var lhs = match_property.toString().toLowerCase();
m_value.forEach(function(item, index) {
if (item.toString().toLowerCase() == lhs || lhs.indexOf(item.toString().toLowerCase()) !== -1) {
matched++;
}
});
}
});
if (('AND' == operator && matched == count) ||
('OR' == operator && matched > 0) ||
('NOT' == operator && 0 == matched)) {
filtered[key] = obj;
}
});
list = filtered;
return list;
},
/**
* Reset lock column scroll to 0 when resize
*/
resetScroll: function() {
if (typeof options.detail === 'undefined' && Plugin.getDepth() === 1) {
$(datatable.table).find('.' + pfx + 'datatable__row').css('left', 0);
$(datatable.table).find('.' + pfx + 'datatable__lock').css('top', 0);
$(datatable.tableBody).scrollTop(0);
}
},
/**
* Get column options by field
* @param field
* @returns {boolean}
*/
getColumnByField: function(field) {
if (typeof field === 'undefined') return;
var result;
$.each(options.columns, function(i, column) {
if (field === column.field) {
result = column;
return false;
}
});
return result;
},
/**
* Get default sort column
*/
getDefaultSortColumn: function() {
var result;
$.each(options.columns, function(i, column) {
if (typeof column.sortable !== 'undefined'
&& $.inArray(column.sortable, ['asc', 'desc']) !== -1) {
result = {sort: column.sortable, field: column.field};
return false;
}
});
return result;
},
/**
* Helper to get element dimensions, when the element is hidden
* @param element
* @param includeMargin
* @returns {{width: number, height: number, innerWidth: number,
* innerHeight: number, outerWidth: number, outerHeight: number}}
*/
getHiddenDimensions: function(element, includeMargin) {
var props = {
position: 'absolute',
visibility: 'hidden',
display: 'block',
},
dim = {
width: 0,
height: 0,
innerWidth: 0,
innerHeight: 0,
outerWidth: 0,
outerHeight: 0,
},
hiddenParents = $(element).parents().addBack().not(':visible');
includeMargin = (typeof includeMargin === 'boolean')
? includeMargin
: false;
var oldProps = [];
hiddenParents.each(function() {
var old = {};
for (var name in props) {
old[name] = this.style[name];
this.style[name] = props[name];
}
oldProps.push(old);
});
dim.width = $(element).width();
dim.outerWidth = $(element).outerWidth(includeMargin);
dim.innerWidth = $(element).innerWidth();
dim.height = $(element).height();
dim.innerHeight = $(element).innerHeight();
dim.outerHeight = $(element).outerHeight(includeMargin);
hiddenParents.each(function(i) {
var old = oldProps[i];
for (var name in props) {
this.style[name] = old[name];
}
});
return dim;
},
getGeneralSearchKey: function() {
var searchInput = $(Plugin.getOption('search.input'));
return $(searchInput).prop('name') || $(searchInput).prop('id');
},
/**
* Get value by dot notation path string and to prevent undefined errors
* @param path String Dot notation path in string
* @param object Object to iterate
* @returns {*}
*/
getObject: function(path, object) {
return path.split('.').reduce(function(obj, i) {
return obj !== null && typeof obj[i] !== 'undefined' ? obj[i] : null;
}, object);
},
/**
* Extend object
* @param obj
* @param path
* @param value
* @returns {*}
*/
extendObj: function(obj, path, value) {
var levels = path.split('.'),
i = 0;
function createLevel(child) {
var name = levels[i++];
if (typeof child[name] !== 'undefined' && child[name] !== null) {
if (typeof child[name] !== 'object' &&
typeof child[name] !== 'function') {
child[name] = {};
}
} else {
child[name] = {};
}
if (i === levels.length) {
child[name] = value;
} else {
createLevel(child[name]);
}
}
createLevel(obj);
return obj;
},
rowEvenOdd: function() {
// row even class
$(datatable.tableBody).find('.' + pfx + 'datatable__row').removeClass(pfx + 'datatable__row--even');
if ($(datatable.wrap).hasClass(pfx + 'datatable--subtable')) {
$(datatable.tableBody).find('.' + pfx + 'datatable__row:not(.' + pfx + 'datatable__row-detail):even').addClass(pfx + 'datatable__row--even');
} else {
$(datatable.tableBody).find('.' + pfx + 'datatable__row:nth-child(even)').addClass(pfx + 'datatable__row--even');
}
},
/********************
** PUBLIC API METHODS
********************/
// delay timer
timer: 0,
/**
* Redraw datatable by recalculating its DOM elements, etc.
* @returns {jQuery}
*/
redraw: function() {
Plugin.adjustCellsWidth.call();
if (Plugin.isLocked()) {
// fix hiding cell width issue
Plugin.scrollbar();
Plugin.resetScroll();
Plugin.adjustCellsHeight.call();
}
Plugin.adjustLockContainer.call();
Plugin.initHeight.call();
return datatable;
},
/**
* Shortcode to reload
* @returns {jQuery}
*/
load: function() {
Plugin.reload();
return datatable;
},
/**
* Datasource reload
* @returns {jQuery}
*/
reload: function() {
var delay = (function() {
return function(callback, ms) {
clearTimeout(Plugin.timer);
Plugin.timer = setTimeout(callback, ms);
};
})();
delay(function() {
// local only. remote pagination will skip this block
if (!options.data.serverFiltering) {
Plugin.localDataUpdate();
}
Plugin.dataRender();
$(datatable).trigger(pfx + 'datatable--on-reloaded');
}, Plugin.getOption('search.delay'));
return datatable;
},
/**
* Get record by record ID
* @param id
* @returns {jQuery}
*/
getRecord: function(id) {
if (typeof datatable.tableBody === 'undefined') datatable.tableBody = $(datatable.table).children('tbody');
$(datatable.tableBody).find('.' + pfx + 'datatable__cell:first-child').each(function(i, cell) {
if (id == $(cell).text()) {
var rowNumber = $(cell).closest('.' + pfx + 'datatable__row').index() + 1;
datatable.API.record = datatable.API.value = Plugin.getOneRow(datatable.tableBody, rowNumber);
return datatable;
}
});
return datatable;
},
/**
* @deprecated in v5.0.6
* Get column of current record ID
* @param columnName
* @returns {jQuery}
*/
getColumn: function(columnName) {
Plugin.setSelectedRecords();
datatable.API.value = $(datatable.API.record).find('[data-field="' + columnName + '"]');
return datatable;
},
/**
* Destroy datatable to original DOM state before datatable was
* initialized
* @returns {jQuery}
*/
destroy: function() {
$(datatable).parent().find('.' + pfx + 'datatable__pager').remove();
var initialDatatable = $(datatable.initialDatatable).addClass(pfx + 'datatable--destroyed').show();
$(datatable).replaceWith(initialDatatable);
datatable = initialDatatable;
$(datatable).trigger(pfx + 'datatable--on-destroy');
Plugin.isInit = false;
initialDatatable = null;
return initialDatatable;
},
/**
* Sort by column field
* @param field
* @param sort
*/
sort: function(field, sort) {
// toggle sort
sort = typeof sort === 'undefined' ? 'asc' : sort;
Plugin.spinnerCallback(true);
// update field and sort params
var meta = {field: field, sort: sort};
Plugin.setDataSourceParam('sort', meta);
setTimeout(function() {
Plugin.dataRender('sort');
$(datatable).trigger(pfx + 'datatable--on-sort', meta);
$(datatable.tableHead).find('.' + pfx + 'datatable__cell > span > i').remove();
}, 300);
return datatable;
},
/**
* @deprecated in v5.0.6
* Get current selected column value
* @returns {jQuery}
*/
getValue: function() {
return $(datatable.API.value).text();
},
/**
* Set checkbox active
* @param cell JQuery selector or checkbox ID
*/
setActive: function(cell) {
if (typeof cell === 'string') {
// set by checkbox id
cell = $(datatable.tableBody).find('.' + pfx + 'checkbox--single > [type="checkbox"][value="' + cell + '"]');
}
$(cell).prop('checked', true);
var ids = [];
$(cell).each(function(i, td) {
// normal table
var row = $(td).closest('tr').addClass(pfx + 'datatable__row--active');
var colIndex = $(row).index() + 1;
// lock table
$(row).closest('tbody').find('tr:nth-child(' + colIndex + ')').not('.' + pfx + 'datatable__row-subtable').addClass(pfx + 'datatable__row--active');
var id = $(td).attr('value');
if (typeof id !== 'undefined') {
ids.push(id);
}
});
$(datatable).trigger(pfx + 'datatable--on-check', [ids]);
},
/**
* Set checkbox inactive
* @param cell JQuery selector or checkbox ID
*/
setInactive: function(cell) {
if (typeof cell === 'string') {
// set by checkbox id
cell = $(datatable.tableBody).find('.' + pfx + 'checkbox--single > [type="checkbox"][value="' + cell + '"]');
}
$(cell).prop('checked', false);
var ids = [];
$(cell).each(function(i, td) {
// normal table
var row = $(td).closest('tr').removeClass(pfx + 'datatable__row--active');
var colIndex = $(row).index() + 1;
// lock table
$(row).closest('tbody').find('tr:nth-child(' + colIndex + ')').not('.' + pfx + 'datatable__row-subtable').removeClass(pfx + 'datatable__row--active');
var id = $(td).attr('value');
if (typeof id !== 'undefined') {
ids.push(id);
}
});
$(datatable).trigger(pfx + 'datatable--on-uncheck', [ids]);
},
/**
* Set all checkboxes active or inactive
* @param active
*/
setActiveAll: function(active) {
var checkboxes = $(datatable.table).
find('> tbody, > thead').
find('tr').not('.' + pfx + 'datatable__row-subtable').
find('.' + pfx + 'datatable__cell--check [type="checkbox"]');
if (active) {
Plugin.setActive(checkboxes);
} else {
Plugin.setInactive(checkboxes);
}
},
/**
* @deprecated in v5.0.6
* Get selected rows which are active
* @returns {jQuery}
*/
setSelectedRecords: function() {
datatable.API.record = $(datatable.tableBody).find('.' + pfx + 'datatable__row--active');
return datatable;
},
/**
* Get selected records
* @returns {null}
*/
getSelectedRecords: function() {
// support old method
Plugin.setSelectedRecords();
datatable.API.record = datatable.rows('.' + pfx + 'datatable__row--active').nodes();
return datatable.API.record;
},
/**
* Get options by dots notation path
* @param path String Dot notation path in string
* @returns {*}
*/
getOption: function(path) {
return Plugin.getObject(path, options);
},
/**
* Set global options nodes by dots notation path
* @param path
* @param object
*/
setOption: function(path, object) {
options = Plugin.extendObj(options, path, object);
},
/**
* Search filter for local & remote
* @param value
* @param columns. Optional list of columns to be filtered.
*/
search: function(value, columns) {
if (typeof columns !== 'undefined') columns = $.makeArray(columns);
var delay = (function() {
return function(callback, ms) {
clearTimeout(Plugin.timer);
Plugin.timer = setTimeout(callback, ms);
};
})();
delay(function() {
// get query parameters
var query = Plugin.getDataSourceQuery();
// search not by columns
if (typeof columns === 'undefined' && typeof value !== 'undefined') {
var key = Plugin.getGeneralSearchKey();
query[key] = value;
}
// search by columns, support multiple columns
if (typeof columns === 'object') {
$.each(columns, function(k, column) {
query[column] = value;
});
// remove empty element from arrays
$.each(query, function(k, v) {
if (v === '' || $.isEmptyObject(v)) {
delete query[k];
}
});
}
Plugin.setDataSourceQuery(query);
// local filter only. remote pagination will skip this block
if (!options.data.serverFiltering) {
Plugin.localDataUpdate();
}
Plugin.dataRender('search');
}, Plugin.getOption('search.delay'));
},
/**
* Set datasource params extract
* @param param
* @param value
*/
setDataSourceParam: function(param, value) {
datatable.API.params = $.extend({}, {
pagination: {page: 1, perpage: Plugin.getOption('data.pageSize')},
sort: Plugin.getDefaultSortColumn(),
query: {},
}, datatable.API.params, Plugin.stateGet(Plugin.stateId));
datatable.API.params = Plugin.extendObj(datatable.API.params, param, value);
Plugin.stateKeep(Plugin.stateId, datatable.API.params);
},
/**
* Get datasource params
* @param param
*/
getDataSourceParam: function(param) {
datatable.API.params = $.extend({}, {
pagination: {page: 1, perpage: Plugin.getOption('data.pageSize')},
sort: Plugin.getDefaultSortColumn(),
query: {},
}, datatable.API.params, Plugin.stateGet(Plugin.stateId));
if (typeof param === 'string') {
return Plugin.getObject(param, datatable.API.params);
}
return datatable.API.params;
},
/**
* Shortcode to datatable.getDataSourceParam('query');
* @returns {*}
*/
getDataSourceQuery: function() {
return Plugin.getDataSourceParam('query') || {};
},
/**
* Shortcode to datatable.setDataSourceParam('query', query);
* @param query
*/
setDataSourceQuery: function(query) {
Plugin.setDataSourceParam('query', query);
},
/**
* Get current page number
* @returns {number}
*/
getCurrentPage: function() {
return $(datatable.table).
siblings('.' + pfx + 'datatable__pager').
last().
find('.' + pfx + 'datatable__pager-nav').
find('.' + pfx + 'datatable__pager-link.' + pfx + 'datatable__pager-link--active').
data('page') || 1;
},
/**
* Get selected dropdown page size
* @returns {*|number}
*/
getPageSize: function() {
return $(datatable.table).siblings('.' + pfx + 'datatable__pager').last().find('select.' + pfx + 'datatable__pager-size').val() || 10;
},
/**
* Get total rows
*/
getTotalRows: function() {
return datatable.API.params.pagination.total;
},
/**
* Get full dataset in grid
* @returns {*|null|Array}
*/
getDataSet: function() {
return datatable.originalDataSet;
},
/**
* @deprecated in v5.0.6
* Hide column by column's field name
* @param fieldName
*/
hideColumn: function(fieldName) {
// add hide option for this column
$.map(options.columns, function(column) {
if (fieldName === column.field) {
column.responsive = {hidden: 'xl'};
}
return column;
});
// hide current displayed column
var tds = $.grep($(datatable.table).find('.' + pfx + 'datatable__cell'), function(n, i) {
return fieldName === $(n).data('field');
});
$(tds).hide();
},
/**
* @deprecated in v5.0.6
* Show column by column's field name
* @param fieldName
*/
showColumn: function(fieldName) {
// add hide option for this column
$.map(options.columns, function(column) {
if (fieldName === column.field) {
delete column.responsive;
}
return column;
});
// hide current displayed column
var tds = $.grep($(datatable.table).find('.' + pfx + 'datatable__cell'), function(n, i) {
return fieldName === $(n).data('field');
});
$(tds).show();
},
nodeTr: [],
nodeTd: [],
nodeCols: [],
recentNode: [],
table: function() {
if (typeof datatable.table !== 'undefined') {
return datatable.table;
}
},
/**
* Select a single row from the table
* @param selector
* @returns {jQuery}
*/
row: function(selector) {
Plugin.rows(selector);
Plugin.nodeTr = Plugin.recentNode = $(Plugin.nodeTr).first();
return datatable;
},
/**
* Select multiple rows from the table
* @param selector
* @returns {jQuery}
*/
rows: function(selector) {
Plugin.nodeTr = Plugin.recentNode = $(datatable.tableBody).find(selector).filter('.' + pfx + 'datatable__row');
return datatable;
},
/**
* Select a single column from the table
* @param index zero-based index
* @returns {jQuery}
*/
column: function(index) {
Plugin.nodeCols = Plugin.recentNode = $(datatable.tableBody).find('.' + pfx + 'datatable__cell:nth-child(' + (index + 1) + ')');
return datatable;
},
/**
* Select multiple columns from the table
* @param selector
* @returns {jQuery}
*/
columns: function(selector) {
var context = datatable.table;
if (Plugin.nodeTr === Plugin.recentNode) {
context = Plugin.nodeTr;
}
var columns = $(context).find('.' + pfx + 'datatable__cell[data-field="' + selector + '"]');
if (columns.length > 0) {
Plugin.nodeCols = Plugin.recentNode = columns;
} else {
Plugin.nodeCols = Plugin.recentNode = $(context).find(selector).filter('.' + pfx + 'datatable__cell');
}
return datatable;
},
cell: function(selector) {
Plugin.cells(selector);
Plugin.nodeTd = Plugin.recentNode = $(Plugin.nodeTd).first();
return datatable;
},
cells: function(selector) {
var cells = $(datatable.tableBody).find('.' + pfx + 'datatable__cell');
if (typeof selector !== 'undefined') {
cells = $(cells).filter(selector);
}
Plugin.nodeTd = Plugin.recentNode = cells;
return datatable;
},
/**
* Delete the selected row from the table
* @returns {jQuery}
*/
remove: function() {
if ($(Plugin.nodeTr.length) && Plugin.nodeTr === Plugin.recentNode) {
$(Plugin.nodeTr).remove();
}
Plugin.layoutUpdate();
return datatable;
},
/**
* Show or hide the columns or rows
*/
visible: function(bool) {
if ($(Plugin.recentNode.length)) {
var locked = Plugin.lockEnabledColumns();
if (Plugin.recentNode === Plugin.nodeCols) {
var index = Plugin.recentNode.index();
if (Plugin.isLocked()) {
var scrollColumns = $(Plugin.recentNode).closest('.' + pfx + 'datatable__lock--scroll').length;
if (scrollColumns) {
// is at center of scrollable area
index += locked.left.length + 1;
} else if ($(Plugin.recentNode).closest('.' + pfx + 'datatable__lock--right').length) {
// is at the right locked table
index += locked.left.length + scrollColumns + 1;
}
}
}
if (bool) {
if (Plugin.recentNode === Plugin.nodeCols) {
delete options.columns[index].responsive;
}
$(Plugin.recentNode).show();
} else {
if (Plugin.recentNode === Plugin.nodeCols) {
Plugin.setOption('columns.' + index + '.responsive', {hidden: 'xl'});
}
$(Plugin.recentNode).hide();
}
Plugin.redraw();
}
},
/**
* Get the the DOM element for the selected rows or columns
* @returns {Array}
*/
nodes: function() {
return Plugin.recentNode;
},
/**
* will be implemented soon
* @returns {jQuery}
*/
dataset: function() {
return datatable;
},
};
/**
* Public API methods can be used directly by datatable
*/
$.each(Plugin, function(funcName, func) {
datatable[funcName] = func;
});
// initialize main datatable plugin
if (typeof options !== 'undefined') {
if (typeof options === 'string') {
var method = options;
datatable = $(this).data(pluginName);
if (typeof datatable !== 'undefined') {
options = datatable.options;
Plugin[method].apply(this, Array.prototype.slice.call(arguments, 1));
}
} else {
if (!datatable.data(pluginName) && !$(this).hasClass(pfx + 'datatable--loaded')) {
datatable.dataSet = null;
datatable.textAlign = {
left: pfx + 'datatable__cell--left',
center: pfx + 'datatable__cell--center',
right: pfx + 'datatable__cell--right',
};
// merge default and user defined options
options = $.extend(true, {}, $.fn[pluginName].defaults, options);
datatable.options = options;
// init plugin process
Plugin.init.apply(this, [options]);
$(datatable.wrap).data(pluginName, datatable);
}
}
} else {
// get existing instance datatable
datatable = $(this).data(pluginName);
if (typeof datatable === 'undefined') {
$.error(pluginName + ' not initialized');
}
options = datatable.options;
}
return datatable;
};
// default options
$.fn[pluginName].defaults = {
// datasource definition
data: {
type: 'local',
source: null,
pageSize: 10, // display records per page
saveState: {
// save datatable state(pagination, filtering, sorting, etc) in cookie or browser webstorage
cookie: false,
webstorage: true,
},
serverPaging: false,
serverFiltering: false,
serverSorting: false,
autoColumns: false,
attr: {
rowProps: [],
},
},
// layout definition
layout: {
theme: 'default', // datatable will support multiple themes and designs
class: pfx + 'datatable--brand', // custom wrapper class
scroll: false, // enable/disable datatable scroll both horizontal and vertical when needed.
height: null, // datatable's body's fixed height
minHeight: 300,
footer: false, // display/hide footer
header: true, // display/hide header
customScrollbar: true, // set false to disable custom scrollbar
// datatable spinner
spinner: {
overlayColor: '#000000',
opacity: 0,
type: 'loader',
state: 'brand',
message: true,
},
// datatable UI icons
icons: {
sort: {asc: 'la la-arrow-up', desc: 'la la-arrow-down'},
pagination: {
next: 'la la-angle-right',
prev: 'la la-angle-left',
first: 'la la-angle-double-left',
last: 'la la-angle-double-right',
more: 'la la-ellipsis-h',
},
rowDetail: {expand: 'fa fa-caret-down', collapse: 'fa fa-caret-right'},
},
},
// column sorting
sortable: true,
// resize column size with mouse drag coming soon)
resizable: false,
// column based filtering (coming soon)
filterable: false,
pagination: true,
// inline and bactch editing (cooming soon)
editable: false,
// columns definition
columns: [],
search: {
// enable trigger search by keyup enter
onEnter: false,
// input text for search
input: null,
// search delay in milliseconds
delay: 400,
},
rows: {
// deprecated
callback: function() {
},
// call before row template
beforeTemplate: function() {
},
// call after row template
afterTemplate: function() {
},
autoHide: true,
},
// toolbar
toolbar: {
// place pagination and displayInfo blocks according to the array order
layout: ['pagination', 'info'],
// toolbar placement can be at top or bottom or both top and bottom repeated
placement: ['bottom'], //'top', 'bottom'
// toolbar items
items: {
// pagination
pagination: {
// pagination type(default or scroll)
type: 'default',
// number of pages to display by breakpoints
pages: {
desktop: {
layout: 'default',
pagesNumber: 5,
},
tablet: {
layout: 'default',
pagesNumber: 3,
},
mobile: {
layout: 'compact',
},
},
// navigation buttons
navigation: {
prev: true, // display prev link
next: true, // display next link
first: true, // display first link
last: true, // display last link
},
// page size select
pageSizeSelect: [], // display dropdown to select pagination size. -1 is used for "ALl" option
},
// records info
info: true,
},
},
// here we will keep all strings and message used by datatable UI so developer can easiliy translate to any language.
// By default the stirngs will be in the plugin source and here can override it
translate: {
records: {
processing: 'Please wait...',
noRecords: 'No records found',
},
toolbar: {
pagination: {
items: {
default: {
first: 'First',
prev: 'Previous',
next: 'Next',
last: 'Last',
more: 'More pages',
input: 'Page number',
select: 'Select page size',
all: 'all',
},
info: 'Showing {{start}} - {{end}} of {{total}}',
},
},
},
},
extensions: {},
};
}(jQuery));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment