diff --git a/public/assets/demo/default/base/scripts.bundle.js b/public/assets/demo/default/base/scripts.bundle.js index 9f8c1962..577261cb 100644 --- a/public/assets/demo/default/base/scripts.bundle.js +++ b/public/assets/demo/default/base/scripts.bundle.js @@ -527,7 +527,7 @@ var mApp = function() { //== Initialize mApp class on document ready $(document).ready(function() { mApp.init(); -}); +}); /** * @class mUtil Metronic base utilize class that privides helper functions */ @@ -875,8 +875,3471 @@ var mUtil = function() { //== Initialize mUtil class on document ready $(document).ready(function() { mUtil.init(); -}); -(function($) { if (typeof mUtil === 'undefined') throw new Error('mUtil is required and must be included before mDatatable.'); // plugin setup $.fn.mDatatable = function(options) { if ($(this).length === 0) throw new Error('No mDatatable element exist.'); // 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, offset: 110, stateId: 'meta', ajaxParams: {}, init: function(options) { 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('m-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.mDatatable[extName] === 'function') new $.fn.mDatatable[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 if (options.data.type === 'local' && typeof options.data.source === 'object') { if (options.data.source === null) { // this is html table Plugin.extractTable(); } datatable.dataSet = datatable.originalDataSet = Plugin.dataMapCallback(options.data.source); } Plugin.dataRender(); } Plugin.setHeadTitle.call(); Plugin.setHeadTitle.call(this, datatable.tableFoot); // for normal table, setup layout right away if (options.data.type === null) { Plugin.setupCellField.call(); Plugin.setupTemplateCell.call(); // setup extra system column properties Plugin.setupSystemColumn.call(); } // 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') { // setup nested datatable, if option enabled Plugin.setupSubDatatable.call(); // setup extra system column properties Plugin.setupSystemColumn.call(); Plugin.redraw(); } $(window).resize(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().toLowerCase()); }); 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 data = $(datatable).find('tr').get().map(function(row) { return $(row).find('td').get().map(function(cell, i) { return $(cell).html(); }); }); var source = []; $.each(data, function(i, row) { if (row.length === 0) return; var td = {}; $.each(row, function(index, value) { td[headers[index]] = value; }); source.push(td); }); 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(); Plugin.columnHide.call(); Plugin.sorting.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(); } if (!Plugin.isInit) { $(datatable).trigger('m-datatable--on-init', {table: $(datatable.wrap).attr('id'), options: options}); Plugin.isInit = true; } $(datatable).trigger('m-datatable--on-layout-updated', {table: $(datatable.wrap).attr('id')}); }, lockTable: function() { // todo; revise lock table responsive 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('.m-datatable__lock').length > 0) { Plugin.log('Locked container already exist in: ', tablePart); return; } // check if no rows exists if ($(tablePart).find('.m-datatable__row').length === 0) { Plugin.log('No row exist in: ', tablePart); return; } // locked div container var lockLeft = $('
'). addClass('m-datatable__lock m-datatable__lock--left'); var lockScroll = $('
'). addClass('m-datatable__lock m-datatable__lock--scroll'); var lockRight = $('
'). addClass('m-datatable__lock m-datatable__lock--right'); $(tablePart).find('.m-datatable__row').each(function() { var rowLeft = $(''). addClass('m-datatable__row'). appendTo(lockLeft); var rowScroll = $(''). addClass('m-datatable__row'). appendTo(lockScroll); var rowRight = $(''). addClass('m-datatable__row'). appendTo(lockRight); $(this).find('.m-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('m-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('m-datatable--lock'); $(lockRight).appendTo(tablePart); } }; $(datatable.table).find('thead,tbody,tfoot').each(function() { var tablePart = this; if ($(this).find('.m-datatable__lock').length === 0) { $(this).ready(function() { enableLock(tablePart); }); } }); }, }; lock.init(); return lock; }, /** * Render everything for resize */ fullRender: function() { // todo; full render datatable for specific condition only Plugin.spinnerCallback(true); $(datatable.wrap).removeClass('m-datatable--loaded'); var lockEnabled = Plugin.lockEnabledColumns(); if (lockEnabled.left.length === 0 && lockEnabled.right.length === 0 && Plugin.isLocked()) { // reset locked table head if not meet the requirements $(datatable.tableHead).empty(); Plugin.setHeadTitle(); if (typeof datatable.tableFoot !== 'undefined') { $(datatable.tableFoot).empty(); Plugin.setHeadTitle(datatable.tableFoot); } } 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 (mUtil.getBreakpoint(column.locked.left) <= screen) { enabled['left'].push(column.locked.left); } } if (typeof column.locked.right !== 'undefined') { if (mUtil.getBreakpoint(column.locked.right) <= screen) { enabled['right'].push(column.locked.right); } } } }); return enabled; }, /** * After render event, called by m-datatable--on-layout-updated * @param e * @param args */ afterRender: function(e, args) { if (args.table == $(datatable.wrap).attr('id')) { if (!Plugin.isLocked()) { Plugin.redraw(); // work on non locked columns if (Plugin.getOption('rows.autoHide')) { Plugin.autoHide(); // reset r $(datatable.table).find('.m-datatable__row').css('height', ''); } } $(datatable).ready(function() { // row even class $(datatable.tableBody).find('.m-datatable__row').removeClass('m-datatable__row--even'); if ($(datatable.wrap).hasClass('m-datatable--subtable')) { $(datatable.tableBody).find('.m-datatable__row:not(.m-datatable__row-detail):even').addClass('m-datatable__row--even'); } else { $(datatable.tableBody).find('.m-datatable__row:nth-child(even)').addClass('m-datatable__row--even'); } // redraw locked columns table if (Plugin.isLocked()) Plugin.redraw(); $(datatable.tableBody).css('visibility', ''); $(datatable.wrap).addClass('m-datatable--loaded'); Plugin.scrollbar.call(); // Plugin.hoverColumn.call(); Plugin.spinnerCallback(false); }); } }, hoverTimer: 0, isScrolling: false, setupHover: function() { $(window).scroll(function(e) { // stop hover when scrolling clearTimeout(Plugin.hoverTimer); Plugin.isScrolling = true; }); $(datatable.tableBody). find('.m-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('.m-datatable__row'). addClass('m-datatable__row--hover'); var index = $(row).index() + 1; // lock table $(row). closest('.m-datatable__lock'). parent(). find('.m-datatable__row:nth-child(' + index + ')'). addClass('m-datatable__row--hover'); }). on('mouseleave', function() { // normal table var row = $(this). closest('.m-datatable__row'). removeClass('m-datatable__row--hover'); var index = $(row).index() + 1; // look table $(row). closest('.m-datatable__lock'). parent(). find('.m-datatable__row:nth-child(' + index + ')'). removeClass('m-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('.m-datatable__lock--left'). width(); var lockRight = $(datatable.tableHead). find('.m-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('.m-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('.m-datatable__cell'). mousedown(function(e) { start = $(this); pressed = true; startX = e.pageX; startWidth = $(this).width(); $(start).addClass('m-datatable__cell--resizing'); }). mousemove(function(e) { if (pressed) { var i = $(start).index(); var tableBody = $(datatable.tableBody); var ifLocked = $(start).closest('.m-datatable__lock'); if (ifLocked) { var lockedIndex = $(ifLocked).index(); tableBody = $(datatable.tableBody). find('.m-datatable__lock'). eq(lockedIndex); } $(tableBody).find('.m-datatable__row').each(function(tri, tr) { $(tr). find('.m-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('m-datatable__cell--resizing'); pressed = false; }); $(document).mouseup(function() { $(start).removeClass('m-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('.m-datatable__row').height(); var tfootHeight = $(datatable.tableFoot).find('.m-datatable__row').height(); var bodyHeight = options.layout.height; if (theadHeight > 0) { bodyHeight -= theadHeight; } if (tfootHeight > 0) { bodyHeight -= tfootHeight; } $(datatable.tableBody).css('max-height', bodyHeight); } }, /** * Setup base DOM (table, thead, tbody, tfoot) and create if not exist. */ setupBaseDOM: function() { // keep original state before mDatatable initialize datatable.initialDatatable = $(datatable).clone(); // main element if ($(datatable).prop('tagName') === 'TABLE') { // if main init element is , wrap with div datatable.table = $(datatable). removeClass('m-datatable'). addClass('m-datatable__table'); if ($(datatable.table).parents('.m-datatable').length === 0) { datatable.table.wrap($('
'). addClass('m-datatable'). addClass('m-datatable--' + options.layout.theme)); datatable.wrap = $(datatable.table).parent(); } } else { // create table datatable.wrap = $(datatable). addClass('m-datatable'). addClass('m-datatable--' + options.layout.theme); datatable.table = $('
'). addClass('m-datatable__table'). appendTo(datatable); } if (typeof options.layout.class !== 'undefined') { $(datatable.wrap).addClass(options.layout.class); } $(datatable.table). removeClass('m-datatable--destroyed'). css('display', 'block'); // force disable save state if (typeof $(datatable).attr('id') === 'undefined') { Plugin.setOption('data.saveState', false); $(datatable.table).attr('id', mUtil.getUniqueID('m-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 = $('').prependTo(datatable.table); } // create table head element datatable.tableBody = $(datatable.table).find('tbody'); if ($(datatable.tableBody).length === 0) { datatable.tableBody = $('').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 = $('').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('.m-datatable__row').each(function(tri, tr) { // prepare data $(tr).find('.m-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('.m-datatable__row').each(function(tri, tr) { // row data object, if any var obj = $(tr).data('obj') || {}; // @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('.m-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('.m-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); } var span = $('').append(finalValue); // insert to cell, wrap with span $(td).html(span); // set span overflow if (typeof column.overflow !== 'undefined') { $(span).css('overflow', column.overflow); } } } }); // 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('.m-datatable__row'). each(function(tri, tr) { $(tr).find('.m-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('.m-checkbox [type="checkbox"]').length > 0) return; $(td).addClass('m-datatable__cell--check'); // append checkbox var chk = $('').appendTo(tablePart); } $.each(columns, function(i, column) { var th = $(ths).eq(i); if ($(th).length === 0) { th = $(''). addClass('m-datatable__body'). css('visibility', 'hidden'); var colLength = options.columns.length; $.each(datatable.dataSet, function(i, row) { // keep data object to row var tr = $('').attr('data-row', i).data('obj', row); var idx = 0; var tdArr = []; for (var a = 0; a < colLength; a += 1) { var column = options.columns[a]; var classes = []; // add sorted class to cells if (params.sort.field === column.field) { classes.push('m-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); } tdArr[idx++] = ' as parent and add as child table subTableRow = $(''). addClass('m-datatable__row-subtable m-datatable__row-loading'). hide(). append($('').addClass('m-datatable__row-detail').insertAfter(row); var detailRowTd = $('
').appendTo(row); } // set column title if (typeof column['title'] !== 'undefined') { $(th). html(column['title']). attr('data-field', column.field). data(column); } // apply text align to thead/tfoot if (typeof column.textAlign !== 'undefined') { var align = typeof datatable.textAlign[column.textAlign] !== 'undefined' ? datatable.textAlign[column.textAlign] : ''; $(th).addClass(align); } }); Plugin.setupDOM(tablePart); }, /** * Initiate to get remote or local data via ajax */ dataRender: function(action) { $(datatable.table). siblings('.m-datatable__pager'). removeClass('m-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('m-datatable--paging-loaded')) { $(ctx.pager).remove(); ctx.init(meta); } $(ctx.pager).off().on('m-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('m-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' ) { afterGetData(); return; } // getting data from remote only Plugin.getData().done(afterGetData); }, /** * Process ajax data */ insertData: function() { datatable.dataSet = datatable.dataSet || []; var params = Plugin.getDataSourceParam(); // todo; fix performance var tableBody = $('
'). addClass('m-datatable--error'). css('width', '100%'). html(Plugin.getOption('translate.records.noRecords')). appendTo(tableBody); $(datatable.wrap).addClass('m-datatable--error m-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() { datatable.ajaxParams = { dataType: 'json', method: 'GET', data: {}, timeout: 30000, }; if (options.data.type === 'local') { datatable.ajaxParams.url = options.data.source; } if (options.data.type === 'remote') { datatable.ajaxParams.url = Plugin.getOption('data.source.read.url'); if (typeof datatable.ajaxParams.url !== 'string') datatable.ajaxParams.url = Plugin.getOption('data.source.read'); if (typeof datatable.ajaxParams.url !== 'string') datatable.ajaxParams.url = Plugin.getOption('data.source'); datatable.ajaxParams.headers = Plugin.getOption('data.source.read.headers'); datatable.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']; } datatable.ajaxParams.data['datatable'] = data; } return $.ajax(datatable.ajaxParams).done(function(response, textStatus, jqXHR) { datatable.lastResponse = response; // extendible data map callback for custom datasource datatable.dataSet = datatable.originalDataSet = Plugin.dataMapCallback(response); $(datatable). trigger('m-datatable--on-ajax-done', [datatable.dataSet]); }).fail(function(jqXHR, textStatus, errorThrown) { Plugin.destroyScroller($(datatable.table).find('.mCustomScrollbar')); $(datatable).trigger('m-datatable--on-ajax-fail', [jqXHR]); $(''). addClass('m-datatable--error'). width('100%'). html(Plugin.getOption('translate.records.noRecords')). appendTo(datatable.tableBody); $(datatable.wrap).addClass('m-datatable--error m-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; // todo; if meta object not exist will cause error // 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('.m-datatable__pager'); if ($(pg.pager).hasClass('m-datatable--paging-loaded')) return; // if class .m-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 = $('
').addClass('m-datatable__pager m-datatable--paging-loaded clearfix'); // numbering links var pagerNumber = $('
'). addClass('m-datatable__subtable'). attr('colspan', Plugin.getTotalColumns())); $(parentRow).after(subTableRow); // add class to even row if ($(parentRow).hasClass('m-datatable__row--even')) { $(subTableRow).addClass('m-datatable__row-subtable--even'); } } $(subTableRow).toggle(); var subTable = $(subTableRow).find('.m-datatable__subtable'); // get id from first column of parent row var primaryKey = $(this). closest('[data-field]:first-child'). find('.m-datatable__toggle-subtable'). data('value'); var icon = $(this).find('i').removeAttr('class'); // prevent duplicate datatable init if ($(parentRow).hasClass('m-datatable__row--subtable-expanded')) { $(icon).addClass(Plugin.getOption('layout.icons.rowDetail.collapse')); // remove expand class from parent row $(parentRow).removeClass('m-datatable__row--subtable-expanded'); // trigger event on collapse $(datatable).trigger('m-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('m-datatable__row--subtable-expanded'); // trigger event on expand $(datatable).trigger('m-datatable--on-expand-subtable', [parentRow]); } // prevent duplicate datatable init if ($(subTable).find('.m-datatable').length === 0) { // get data by primary id $.map(datatable.dataSet, function(n, i) { 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('.m-datatable').on('m-datatable--on-init', function(e) { $(subTableRow).removeClass('m-datatable__row-loading'); }); if (Plugin.getOption('data.type') === 'local') { $(subTableRow).removeClass('m-datatable__row-loading'); } } }; var columns = options.columns; $(datatable.tableBody). find('.m-datatable__row'). each(function(tri, tr) { $(tr).find('.m-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('.m-datatable__toggle-subtable').length > 0) return; // append subtable toggle $(td).html($(''). addClass('m-datatable__toggle-subtable'). attr('href', '#'). attr('data-value', value). attr('title', Plugin.getOption('detail.title')). on('click', toggleSubTable). append($(''). css('width', $(td).data('width')). addClass(Plugin.getOption('layout.icons.rowDetail.collapse')))); } } }); }); // $(datatable.tableHead).find('.m-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.data !== 'undefined') { dataSet = raw.data; } } return dataSet; }, isSpinning: false, /** * BlockUI spinner callback * @param block */ spinnerCallback: function(block) { if (block) { if (!Plugin.isSpinning) { // get spinner options var spinnerOptions = Plugin.getOption('layout.spinner'); if (spinnerOptions.message === true) { // use default spinner message from translation spinnerOptions.message = Plugin.getOption('translate.records.processing'); } Plugin.isSpinning = true; if (typeof mApp !== 'undefined') { mApp.block(datatable, spinnerOptions); } } } else { Plugin.isSpinning = false; if (typeof mApp !== 'undefined') { mApp.unblock(datatable); } } }, /** * Default sort callback function * @param data * @param sort * @param column * @returns {*|Array.|{sort, field}|{asc, desc}} */ sortCallback: function(data, sort, column) { var type = column['type'] || 'string'; var format = column['format'] || ''; var field = column['field']; if (type === 'date' && typeof moment === 'undefined') { throw new Error('Moment.js is required.'); } return $(data).sort(function(a, b) { var aField = a[field]; var bField = b[field]; switch (type) { case 'date': 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() { $(datatable.table).find('.m-datatable__cell').show(); $(datatable.tableBody).each(function() { while ($(this)[0].offsetWidth < $(this)[0].scrollWidth) { $(this).find('.m-datatable__row').each(function(i) { var cell = $(this).find('.m-datatable__cell').not(':hidden').last(); $(cell).hide(); if (i === 0) { $(datatable.tableHead).find('.m-datatable__cell').eq($(cell).index()).hide(); $(datatable.tableFoot).find('.m-datatable__cell').eq($(cell).index()).hide(); } }); } }); var toggleHiddenColumns = function(e) { e.preventDefault(); var row = $(this).closest('.m-datatable__row'); var detailRow = $(row).next(); if (!$(detailRow).hasClass('m-datatable__row-detail')) { $(this).find('i'). removeClass(Plugin.getOption('layout.icons.rowDetail.collapse')). addClass(Plugin.getOption('layout.icons.rowDetail.expand')); var hidden = $(row).find('.m-datatable__cell:hidden').clone().show(); detailRow = $('
'). addClass('m-datatable__detail'). attr('colspan', Plugin.getTotalColumns()).appendTo(detailRow); var detailSubTable = $(''); $(hidden).each(function() { $(detailSubTable). append($(''). append($(''). append($(''). css('width', Plugin.offset). append($(this).data('field')))). 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('.m-datatable__row').each(function() { $(this).prepend($(''); $(datatable.tableFoot). find('.m-datatable__row'). first(). prepend(''); } else { $(datatable.tableHead).find('.m-datatable__toggle-detail').find('span').css('width', '21px'); } }); }, /** * todo; implement hover column */ hoverColumn: function() { $(datatable.tableBody).on('mouseenter', '.m-datatable__cell', function() { var colIdx = $(Plugin.cell(this).nodes()).index(); $(Plugin.cells().nodes()).removeClass('m-datatable__cell--hover'); $(Plugin.column(colIdx).nodes()).addClass('m-datatable__cell--hover'); }); }, /******************** ** HELPERS ********************/ /** * Check if table is a locked colums table */ isLocked: function() { return $(datatable.wrap).hasClass('m-datatable--lock') || false; }, /** * Insert html into table content, take count mCustomScrollbar DOM to prevent replace * @param html * @param tablePart */ replaceTableContent: function(html, tablePart) { if (typeof tablePart === 'undefined') tablePart = datatable.tableBody; if ($(tablePart).hasClass('mCustomScrollbar')) { $(tablePart).find('.mCSB_container').html(html); } else { $(tablePart).html(html); } }, /** * 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('.m-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('.m-datatable__row'). first(). find('.m-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 var result = $(tablePart).find('.m-datatable__row:not(.m-datatable__row-detail):nth-child(' + row + ')'); if (tdOnly) { // get list of '). + addClass('m-datatable__row'). + appendTo(lockLeft); + var rowScroll = $(''). + addClass('m-datatable__row'). + appendTo(lockScroll); + var rowRight = $(''). + addClass('m-datatable__row'). + appendTo(lockRight); + $(this).find('.m-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('m-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('m-datatable--lock'); + $(lockRight).appendTo(tablePart); + } + }; + + $(datatable.table).find('thead,tbody,tfoot').each(function() { + var tablePart = this; + if ($(this).find('.m-datatable__lock').length === 0) { + $(this).ready(function() { + enableLock(tablePart); + }); + } + }); + }, + }; + lock.init(); + return lock; + }, + + /** + * Render everything for resize + */ + fullRender: function() { + // todo; full render datatable for specific condition only + Plugin.spinnerCallback(true); + $(datatable.wrap).removeClass('m-datatable--loaded'); + + var lockEnabled = Plugin.lockEnabledColumns(); + if (lockEnabled.left.length === 0 && + lockEnabled.right.length === 0 && Plugin.isLocked()) { + // reset locked table head if not meet the requirements + $(datatable.tableHead).empty(); + Plugin.setHeadTitle(); + if (typeof datatable.tableFoot !== 'undefined') { + $(datatable.tableFoot).empty(); + Plugin.setHeadTitle(datatable.tableFoot); + } + } + + 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 (mUtil.getBreakpoint(column.locked.left) <= screen) { + enabled['left'].push(column.locked.left); + } + } + if (typeof column.locked.right !== 'undefined') { + if (mUtil.getBreakpoint(column.locked.right) <= screen) { + enabled['right'].push(column.locked.right); + } + } + } + }); + return enabled; + }, + + /** + * After render event, called by m-datatable--on-layout-updated + * @param e + * @param args + */ + afterRender: function(e, args) { + if (args.table == $(datatable.wrap).attr('id')) { + if (!Plugin.isLocked()) { + Plugin.redraw(); + // work on non locked columns + if (Plugin.getOption('rows.autoHide')) { + Plugin.autoHide(); + // reset r + $(datatable.table).find('.m-datatable__row').css('height', ''); + } + } + $(datatable).ready(function() { + // row even class + $(datatable.tableBody).find('.m-datatable__row').removeClass('m-datatable__row--even'); + if ($(datatable.wrap).hasClass('m-datatable--subtable')) { + $(datatable.tableBody).find('.m-datatable__row:not(.m-datatable__row-detail):even').addClass('m-datatable__row--even'); + } else { + $(datatable.tableBody).find('.m-datatable__row:nth-child(even)').addClass('m-datatable__row--even'); + } + + // redraw locked columns table + if (Plugin.isLocked()) Plugin.redraw(); + $(datatable.tableBody).css('visibility', ''); + $(datatable.wrap).addClass('m-datatable--loaded'); + Plugin.scrollbar.call(); + // Plugin.hoverColumn.call(); + Plugin.spinnerCallback(false); + }); + } + }, + + hoverTimer: 0, + isScrolling: false, + setupHover: function() { + $(window).scroll(function(e) { + // stop hover when scrolling + clearTimeout(Plugin.hoverTimer); + Plugin.isScrolling = true; + }); + + $(datatable.tableBody). + find('.m-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('.m-datatable__row'). + addClass('m-datatable__row--hover'); + var index = $(row).index() + 1; + + // lock table + $(row). + closest('.m-datatable__lock'). + parent(). + find('.m-datatable__row:nth-child(' + index + ')'). + addClass('m-datatable__row--hover'); + }). + on('mouseleave', function() { + // normal table + var row = $(this). + closest('.m-datatable__row'). + removeClass('m-datatable__row--hover'); + var index = $(row).index() + 1; + + // look table + $(row). + closest('.m-datatable__lock'). + parent(). + find('.m-datatable__row:nth-child(' + index + ')'). + removeClass('m-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('.m-datatable__lock--left'). + width(); + var lockRight = $(datatable.tableHead). + find('.m-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('.m-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('.m-datatable__cell'). + mousedown(function(e) { + start = $(this); + pressed = true; + startX = e.pageX; + startWidth = $(this).width(); + $(start).addClass('m-datatable__cell--resizing'); + + }). + mousemove(function(e) { + if (pressed) { + var i = $(start).index(); + var tableBody = $(datatable.tableBody); + var ifLocked = $(start).closest('.m-datatable__lock'); + + if (ifLocked) { + var lockedIndex = $(ifLocked).index(); + tableBody = $(datatable.tableBody). + find('.m-datatable__lock'). + eq(lockedIndex); + } + + $(tableBody).find('.m-datatable__row').each(function(tri, tr) { + $(tr). + find('.m-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('m-datatable__cell--resizing'); + pressed = false; + }); + + $(document).mouseup(function() { + $(start).removeClass('m-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('.m-datatable__row').height(); + var tfootHeight = $(datatable.tableFoot).find('.m-datatable__row').height(); + var bodyHeight = options.layout.height; + if (theadHeight > 0) { + bodyHeight -= theadHeight; + } + if (tfootHeight > 0) { + bodyHeight -= tfootHeight; + } + $(datatable.tableBody).css('max-height', bodyHeight); + } + }, + + /** + * Setup base DOM (table, thead, tbody, tfoot) and create if not exist. + */ + setupBaseDOM: function() { + // keep original state before mDatatable initialize + datatable.initialDatatable = $(datatable).clone(); + + // main element + if ($(datatable).prop('tagName') === 'TABLE') { + // if main init element is
').addClass('m-datatable__cell m-datatable__toggle--detail'). append($(''). addClass('m-datatable__toggle-detail'). attr('href', '#'). on('click', toggleHiddenColumns). append($(''). css('width', '21px').// maintain width for both icons expand and collapse addClass(Plugin.getOption('layout.icons.rowDetail.collapse'))))); // check if subtable toggle exist if ($(datatable.tableHead).find('.m-datatable__toggle-detail').length === 0) { $(datatable.tableHead). find('.m-datatable__row'). first(). prepend('. * @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
or result = result.find('.m-datatable__cell'); } return result; }, /** * Check if element has vertical overflow * @param element * @returns {boolean} */ hasOverflowY: function(element) { var children = $(element).find('.m-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('.m-datatable__row'); var hIndex = $(header).closest('.m-datatable__lock').index(); if (hIndex !== -1) { rows = $(datatable.tableBody). find('.m-datatable__lock:nth-child(' + (hIndex + 1) + ')'). find('.m-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('.m-datatable__cell:not(.m-datatable__cell--check)'). addClass('m-datatable__cell--sort'). off('click'). on('click', sortObj.sortClick); // first init sortObj.setIcon(); } }, setIcon: function() { var meta = Plugin.getDataSourceParam('sort'); // sort icon beside column header var td = $(datatable.tableHead). find('.m-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($('').addClass(icons[meta.sort])); } }, 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; $(datatable.tableHead). find('.m-datatable__cell > span > i'). remove(); if (options.sortable) { Plugin.spinnerCallback(true); var sort = 'desc'; if (meta.field === field) { sort = meta.sort; } // 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('m-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 = params.sort.field; var sort = params.sort.sort; var column = Plugin.getColumnByField(field); if (typeof column !== 'undefined') { 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 (typeof params.query === 'object') { params.query = params.query || {}; var search = $(Plugin.getOption('search.input')).val(); if (typeof search !== 'undefined' && search !== '') { search = search.toLowerCase(); datatable.dataSet = $.grep(datatable.dataSet, function(obj) { for (var field in obj) { if (!obj.hasOwnProperty(field)) continue; if (typeof obj[field] === 'string') { if (obj[field].toLowerCase().indexOf(search) > -1) { return true; } } } return false; }); // 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) { if (to_match.hasOwnProperty(m_key) && m_value == to_match[m_key]) { 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('.m-datatable__row').css('left', 0); $(datatable.table).find('.m-datatable__lock').css('top', 0); $(datatable.tableBody).scrollTop(0); } }, /** * Get column options by field * @param field * @returns {boolean} */ getColumnByField: function(field) { 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 = {sort: '', field: ''}; $.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; }, /******************** ** PUBLIC API METHODS ********************/ // delay timer timer: 0, /** * Redraw datatable by recalculating its DOM elements, etc. * @returns {jQuery} */ redraw: function() { Plugin.adjustCellsWidth.call(); 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 === false) { Plugin.localDataUpdate(); } Plugin.dataRender(); $(datatable).trigger('m-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('.m-datatable__cell:first-child').each(function(i, cell) { if (id == $(cell).text()) { var rowNumber = $(cell).closest('.m-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('.m-datatable__pager').remove(); var initialDatatable = $(datatable.initialDatatable).addClass('m-datatable--destroyed').show(); $(datatable).replaceWith(initialDatatable); datatable = initialDatatable; $(datatable).trigger('m-datatable--on-destroy'); Plugin.isInit = false; initialDatatable = null; return initialDatatable; }, /** * Sort by column field * @param field * @param sort */ sort: function(field, sort) { if (typeof sort === 'undefined') sort = 'asc'; $(datatable.tableHead). find('.m-datatable__cell[data-field="' + field + '"]'). trigger('click'); 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('.m-checkbox--single > [type="checkbox"][value="' + cell + '"]'); } $(cell).prop('checked', true); // normal table var row = $(cell). closest('.m-datatable__row'). addClass('m-datatable__row--active'); var index = $(row).index() + 1; // lock table $(row). closest('.m-datatable__lock'). parent(). find('.m-datatable__row:nth-child(' + index + ')'). addClass('m-datatable__row--active'); var ids = []; $(row).each(function(i, td) { var id = $(td).find('.m-checkbox--single:not(.m-checkbox--all) > [type="checkbox"]').val(); if (typeof id !== 'undefined') { ids.push(id); } }); $(datatable).trigger('m-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('.m-checkbox--single > [type="checkbox"][value="' + cell + '"]'); } $(cell).prop('checked', false); // normal table var row = $(cell). closest('.m-datatable__row'). removeClass('m-datatable__row--active'); var index = $(row).index() + 1; // lock table $(row). closest('.m-datatable__lock'). parent(). find('.m-datatable__row:nth-child(' + index + ')'). removeClass('m-datatable__row--active'); var ids = []; $(row).each(function(i, td) { var id = $(td).find('.m-checkbox--single:not(.m-checkbox--all) > [type="checkbox"]').val(); if (typeof id !== 'undefined') { ids.push(id); } }); $(datatable).trigger('m-datatable--on-uncheck', [ids]); }, /** * Set all checkboxes active or inactive * @param active */ setActiveAll: function(active) { // todo; check if child table also will set active? var checkboxes = $(datatable.table).find('.m-datatable__body .m-datatable__row'). find('.m-datatable__cell .m-checkbox [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('.m-datatable__row--active'); return datatable; }, /** * Get selected records * @returns {null} */ getSelectedRecords: function() { // support old method Plugin.setSelectedRecords(); datatable.API.record = datatable.rows('.m-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 === '') { delete query[k]; } }); } Plugin.setDataSourceQuery(query); // local filter only. remote pagination will skip this block if (options.data.serverFiltering === false) { Plugin.localDataUpdate(); } Plugin.dataRender(); }, Plugin.getOption('search.delay')); }, /** * Set datasource params * @param param * @param value */ setDataSourceParam: function(param, value) { var defaultSort = Plugin.getDefaultSortColumn(); datatable.API.params = $.extend({}, { pagination: {page: 1, perpage: Plugin.getOption('data.pageSize')}, sort: {sort: defaultSort.sort, field: defaultSort.field}, 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) { var defaultSort = Plugin.getDefaultSortColumn(); datatable.API.params = $.extend({}, { pagination: {page: 1, perpage: Plugin.getOption('data.pageSize')}, sort: {sort: defaultSort.sort, field: defaultSort.field}, 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('.m-datatable__pager'). last(). find('.m-datatable__pager-nav'). find('.m-datatable__pager-link.m-datatable__pager-link--active'). data('page') || 1; }, /** * Get selected dropdown page size * @returns {*|number} */ getPageSize: function() { return $(datatable.table). siblings('.m-datatable__pager'). last(). find('.m-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('.m-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('.m-datatable__cell'), function(n, i) { return fieldName === $(n).data('field'); }); $(tds).show(); }, destroyScroller: function(element) { if (typeof element === 'undefined') element = datatable.tableBody; $(element).each(function() { if ($(this).hasClass('mCustomScrollbar')) { try { mApp.destroyScroller($(this)); } catch (e) { console.log(e); } } }); }, /** * NEW API */ nodeTr: [], nodeTd: [], nodeCols: [], recentNode: [], table: function() { 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('.m-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('.m-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('.m-datatable__cell[data-field="' + selector + '"]'); if (columns.length > 0) { Plugin.nodeCols = Plugin.recentNode = columns; } else { Plugin.nodeCols = Plugin.recentNode = $(context).find(selector).filter('.m-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('.m-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(); } return datatable; }, /** * Show or hide the columns or rows */ visible: function(bool) { if ($(Plugin.recentNode.length)) { if (bool) { if (Plugin.recentNode === Plugin.nodeCols) { Plugin.setOption('columns.' + Plugin.recentNode.index() + '.responsive', {}); } $(Plugin.recentNode).show(); } else { if (Plugin.recentNode === Plugin.nodeCols) { Plugin.setOption('columns.' + Plugin.recentNode.index() + '.responsive', {hidden: 'xl'}); } $(Plugin.recentNode).hide(); } } }, /** * 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('mDatatable'); if (typeof datatable !== 'undefined') { options = datatable.options; Plugin[method].apply(this, Array.prototype.slice.call(arguments, 1)); } } else { if (!datatable.data('mDatatable') && !$(this).hasClass('m-datatable--loaded')) { datatable.dataSet = null; datatable.textAlign = { left: 'm-datatable__cell--left', center: 'm-datatable__cell--center', right: 'm-datatable__cell--right', }; // merge default and user defined options options = $.extend(true, {}, $.fn.mDatatable.defaults, options); datatable.options = options; // init plugin process Plugin.init.apply(this, [options]); $(datatable).data('mDatatable', datatable); } } } else { // get existing instance datatable datatable = $(this).data('mDatatable'); if (typeof datatable === 'undefined') { $.error('mDatatable not initialized'); } options = datatable.options; } return datatable; }; // default options $.fn.mDatatable.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, }, // layout definition layout: { theme: 'default', // datatable will support multiple themes and designs class: 'm-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 // datatable custom scroll params smoothScroll: { scrollbarShown: true, }, // 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() {}, // auto hide columns, if rows overflow. work on non locked columns autoHide: false, }, // 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: 6, }, 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', }, info: 'Displaying {{start}} - {{end}} of {{total}} records', }, }, }, }, extensions: {}, }; }(jQuery)); +}); +(function($) { + + if (typeof mUtil === 'undefined') throw new Error('mUtil is required and must be included before mDatatable.'); + + // plugin setup + $.fn.mDatatable = function(options) { + if ($(this).length === 0) throw new Error('No mDatatable element exist.'); + + // 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, + offset: 110, + stateId: 'meta', + ajaxParams: {}, + + init: function(options) { + 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('m-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.mDatatable[extName] === 'function') + new $.fn.mDatatable[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 + if (options.data.type === 'local' && + typeof options.data.source === 'object') { + if (options.data.source === null) { + // this is html table + Plugin.extractTable(); + } + datatable.dataSet = datatable.originalDataSet = Plugin.dataMapCallback(options.data.source); + } + Plugin.dataRender(); + } + + Plugin.setHeadTitle.call(); + Plugin.setHeadTitle.call(this, datatable.tableFoot); + + // for normal table, setup layout right away + if (options.data.type === null) { + Plugin.setupCellField.call(); + Plugin.setupTemplateCell.call(); + // setup extra system column properties + Plugin.setupSystemColumn.call(); + } + + // 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') { + // setup nested datatable, if option enabled + Plugin.setupSubDatatable.call(); + // setup extra system column properties + Plugin.setupSystemColumn.call(); + Plugin.redraw(); + } + + $(window).resize(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().toLowerCase()); + }); + + 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 data = $(datatable).find('tr').get().map(function(row) { + return $(row).find('td').get().map(function(cell, i) { + return $(cell).html(); + }); + }); + var source = []; + $.each(data, function(i, row) { + if (row.length === 0) return; + var td = {}; + $.each(row, function(index, value) { + td[headers[index]] = value; + }); + source.push(td); + }); + 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(); + + Plugin.columnHide.call(); + + Plugin.sorting.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(); + } + + if (!Plugin.isInit) { + $(datatable).trigger('m-datatable--on-init', {table: $(datatable.wrap).attr('id'), options: options}); + Plugin.isInit = true; + } + + $(datatable).trigger('m-datatable--on-layout-updated', {table: $(datatable.wrap).attr('id')}); + }, + + lockTable: function() { + // todo; revise lock table responsive + 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('.m-datatable__lock').length > 0) { + Plugin.log('Locked container already exist in: ', tablePart); + return; + } + // check if no rows exists + if ($(tablePart).find('.m-datatable__row').length === 0) { + Plugin.log('No row exist in: ', tablePart); + return; + } + + // locked div container + var lockLeft = $('
'). + addClass('m-datatable__lock m-datatable__lock--left'); + var lockScroll = $('
'). + addClass('m-datatable__lock m-datatable__lock--scroll'); + var lockRight = $('
'). + addClass('m-datatable__lock m-datatable__lock--right'); + + $(tablePart).find('.m-datatable__row').each(function() { + var rowLeft = $('
, wrap with div + datatable.table = $(datatable). + removeClass('m-datatable'). + addClass('m-datatable__table'); + if ($(datatable.table).parents('.m-datatable').length === 0) { + datatable.table.wrap($('
'). + addClass('m-datatable'). + addClass('m-datatable--' + options.layout.theme)); + datatable.wrap = $(datatable.table).parent(); + } + } else { + // create table + datatable.wrap = $(datatable). + addClass('m-datatable'). + addClass('m-datatable--' + options.layout.theme); + datatable.table = $('
'). + addClass('m-datatable__table'). + appendTo(datatable); + } + + if (typeof options.layout.class !== 'undefined') { + $(datatable.wrap).addClass(options.layout.class); + } + + $(datatable.table). + removeClass('m-datatable--destroyed'). + css('display', 'block'); + + // force disable save state + if (typeof $(datatable).attr('id') === 'undefined') { + Plugin.setOption('data.saveState', false); + $(datatable.table).attr('id', mUtil.getUniqueID('m-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 = $('').prependTo(datatable.table); + } + + // create table head element + datatable.tableBody = $(datatable.table).find('tbody'); + if ($(datatable.tableBody).length === 0) { + datatable.tableBody = $('').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 = $('').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('.m-datatable__row').each(function(tri, tr) { + // prepare data + $(tr).find('.m-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('.m-datatable__row').each(function(tri, tr) { + // row data object, if any + var obj = $(tr).data('obj') || {}; + + // @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('.m-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('.m-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); + } + var span = $('').append(finalValue); + // insert to cell, wrap with span + $(td).html(span); + + // set span overflow + if (typeof column.overflow !== 'undefined') { + $(span).css('overflow', column.overflow); + } + } + } + }); + + // 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('.m-datatable__row'). + each(function(tri, tr) { + $(tr).find('.m-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('.m-checkbox [type="checkbox"]').length > 0) return; + $(td).addClass('m-datatable__cell--check'); + // append checkbox + var chk = $('').appendTo(tablePart); + } + $.each(columns, function(i, column) { + var th = $(ths).eq(i); + if ($(th).length === 0) { + th = $(''). + addClass('m-datatable__body'). + css('visibility', 'hidden'); + var colLength = options.columns.length; + + $.each(datatable.dataSet, function(i, row) { + // keep data object to row + var tr = $('').attr('data-row', i).data('obj', row); + var idx = 0; + var tdArr = []; + for (var a = 0; a < colLength; a += 1) { + var column = options.columns[a]; + var classes = []; + // add sorted class to cells + if (params.sort.field === column.field) { + classes.push('m-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); + } + + tdArr[idx++] = ' as parent and add as child table + subTableRow = $(''). + addClass('m-datatable__row-subtable m-datatable__row-loading'). + hide(). + append($('').addClass('m-datatable__row-detail').insertAfter(row); + var detailRowTd = $('
').appendTo(row); + } + // set column title + if (typeof column['title'] !== 'undefined') { + $(th). + html(column['title']). + attr('data-field', column.field). + data(column); + } + // apply text align to thead/tfoot + if (typeof column.textAlign !== 'undefined') { + var align = typeof datatable.textAlign[column.textAlign] !== + 'undefined' ? datatable.textAlign[column.textAlign] : ''; + $(th).addClass(align); + } + }); + Plugin.setupDOM(tablePart); + }, + + /** + * Initiate to get remote or local data via ajax + */ + dataRender: function(action) { + $(datatable.table). + siblings('.m-datatable__pager'). + removeClass('m-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('m-datatable--paging-loaded')) { + $(ctx.pager).remove(); + ctx.init(meta); + } + $(ctx.pager).off().on('m-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('m-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' + ) { + afterGetData(); + return; + } + + // getting data from remote only + Plugin.getData().done(afterGetData); + }, + + /** + * Process ajax data + */ + insertData: function() { + datatable.dataSet = datatable.dataSet || []; + var params = Plugin.getDataSourceParam(); + + // todo; fix performance + var tableBody = $('
'). + addClass('m-datatable--error'). + css('width', '100%'). + html(Plugin.getOption('translate.records.noRecords')). + appendTo(tableBody); + $(datatable.wrap).addClass('m-datatable--error m-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() { + datatable.ajaxParams = { + dataType: 'json', + method: 'GET', + data: {}, + timeout: 30000, + }; + + if (options.data.type === 'local') { + datatable.ajaxParams.url = options.data.source; + } + + if (options.data.type === 'remote') { + datatable.ajaxParams.url = Plugin.getOption('data.source.read.url'); + if (typeof datatable.ajaxParams.url !== 'string') datatable.ajaxParams.url = Plugin.getOption('data.source.read'); + if (typeof datatable.ajaxParams.url !== 'string') datatable.ajaxParams.url = Plugin.getOption('data.source'); + datatable.ajaxParams.headers = Plugin.getOption('data.source.read.headers'); + datatable.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']; + } + datatable.ajaxParams.data['datatable'] = data; + } + + return $.ajax(datatable.ajaxParams).done(function(response, textStatus, jqXHR) { + datatable.lastResponse = response; + // extendible data map callback for custom datasource + datatable.dataSet = datatable.originalDataSet = Plugin.dataMapCallback(response); + $(datatable). + trigger('m-datatable--on-ajax-done', [datatable.dataSet]); + }).fail(function(jqXHR, textStatus, errorThrown) { + Plugin.destroyScroller($(datatable.table).find('.mCustomScrollbar')); + $(datatable).trigger('m-datatable--on-ajax-fail', [jqXHR]); + $(''). + addClass('m-datatable--error'). + width('100%'). + html(Plugin.getOption('translate.records.noRecords')). + appendTo(datatable.tableBody); + $(datatable.wrap).addClass('m-datatable--error m-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; + + // todo; if meta object not exist will cause error + // 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('.m-datatable__pager'); + if ($(pg.pager).hasClass('m-datatable--paging-loaded')) return; + + // if class .m-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 = $('
').addClass('m-datatable__pager m-datatable--paging-loaded clearfix'); + // numbering links + var pagerNumber = $('
'). + addClass('m-datatable__subtable'). + attr('colspan', Plugin.getTotalColumns())); + $(parentRow).after(subTableRow); + // add class to even row + if ($(parentRow).hasClass('m-datatable__row--even')) { + $(subTableRow).addClass('m-datatable__row-subtable--even'); + } + } + + $(subTableRow).toggle(); + + var subTable = $(subTableRow).find('.m-datatable__subtable'); + + // get id from first column of parent row + var primaryKey = $(this). + closest('[data-field]:first-child'). + find('.m-datatable__toggle-subtable'). + data('value'); + + var icon = $(this).find('i').removeAttr('class'); + + // prevent duplicate datatable init + if ($(parentRow).hasClass('m-datatable__row--subtable-expanded')) { + $(icon).addClass(Plugin.getOption('layout.icons.rowDetail.collapse')); + // remove expand class from parent row + $(parentRow).removeClass('m-datatable__row--subtable-expanded'); + // trigger event on collapse + $(datatable).trigger('m-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('m-datatable__row--subtable-expanded'); + // trigger event on expand + $(datatable).trigger('m-datatable--on-expand-subtable', [parentRow]); + } + + // prevent duplicate datatable init + if ($(subTable).find('.m-datatable').length === 0) { + // get data by primary id + $.map(datatable.dataSet, function(n, i) { + 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('.m-datatable').on('m-datatable--on-init', function(e) { + $(subTableRow).removeClass('m-datatable__row-loading'); + }); + if (Plugin.getOption('data.type') === 'local') { + $(subTableRow).removeClass('m-datatable__row-loading'); + } + } + }; + + var columns = options.columns; + $(datatable.tableBody). + find('.m-datatable__row'). + each(function(tri, tr) { + $(tr).find('.m-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('.m-datatable__toggle-subtable').length > 0) return; + // append subtable toggle + $(td).html($(''). + addClass('m-datatable__toggle-subtable'). + attr('href', '#'). + attr('data-value', value). + attr('title', Plugin.getOption('detail.title')). + on('click', toggleSubTable). + append($(''). + css('width', $(td).data('width')). + addClass(Plugin.getOption('layout.icons.rowDetail.collapse')))); + } + } + }); + }); + + // $(datatable.tableHead).find('.m-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.data !== 'undefined') { + dataSet = raw.data; + } + } + return dataSet; + }, + + isSpinning: false, + /** + * BlockUI spinner callback + * @param block + */ + spinnerCallback: function(block) { + if (block) { + if (!Plugin.isSpinning) { + // get spinner options + var spinnerOptions = Plugin.getOption('layout.spinner'); + if (spinnerOptions.message === true) { + // use default spinner message from translation + spinnerOptions.message = Plugin.getOption('translate.records.processing'); + } + Plugin.isSpinning = true; + if (typeof mApp !== 'undefined') { + mApp.block(datatable, spinnerOptions); + } + } + } else { + Plugin.isSpinning = false; + if (typeof mApp !== 'undefined') { + mApp.unblock(datatable); + } + } + }, + + /** + * Default sort callback function + * @param data + * @param sort + * @param column + * @returns {*|Array.|{sort, field}|{asc, desc}} + */ + sortCallback: function(data, sort, column) { + var type = column['type'] || 'string'; + var format = column['format'] || ''; + var field = column['field']; + + if (type === 'date' && typeof moment === 'undefined') { + throw new Error('Moment.js is required.'); + } + + return $(data).sort(function(a, b) { + var aField = a[field]; + var bField = b[field]; + + switch (type) { + case 'date': + 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() { + $(datatable.table).find('.m-datatable__cell').show(); + $(datatable.tableBody).each(function() { + while ($(this)[0].offsetWidth < $(this)[0].scrollWidth) { + $(this).find('.m-datatable__row').each(function(i) { + var cell = $(this).find('.m-datatable__cell').not(':hidden').last(); + $(cell).hide(); + if (i === 0) { + $(datatable.tableHead).find('.m-datatable__cell').eq($(cell).index()).hide(); + $(datatable.tableFoot).find('.m-datatable__cell').eq($(cell).index()).hide(); + } + }); + } + }); + + var toggleHiddenColumns = function(e) { + e.preventDefault(); + + var row = $(this).closest('.m-datatable__row'); + var detailRow = $(row).next(); + + if (!$(detailRow).hasClass('m-datatable__row-detail')) { + $(this).find('i'). + removeClass(Plugin.getOption('layout.icons.rowDetail.collapse')). + addClass(Plugin.getOption('layout.icons.rowDetail.expand')); + + var hidden = $(row).find('.m-datatable__cell:hidden').clone().show(); + + detailRow = $('
'). + addClass('m-datatable__detail'). + attr('colspan', Plugin.getTotalColumns()).appendTo(detailRow); + + var detailSubTable = $(''); + $(hidden).each(function() { + $(detailSubTable). + append($(''). + append($(''). + append($(''). + css('width', Plugin.offset). + append($(this).data('field')))). + 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('.m-datatable__row').each(function() { + $(this).prepend($(''); + $(datatable.tableFoot). + find('.m-datatable__row'). + first(). + prepend(''); + } else { + $(datatable.tableHead).find('.m-datatable__toggle-detail').find('span').css('width', '21px'); + } + }); + }, + + /** + * todo; implement hover column + */ + hoverColumn: function() { + $(datatable.tableBody).on('mouseenter', '.m-datatable__cell', function() { + var colIdx = $(Plugin.cell(this).nodes()).index(); + $(Plugin.cells().nodes()).removeClass('m-datatable__cell--hover'); + $(Plugin.column(colIdx).nodes()).addClass('m-datatable__cell--hover'); + }); + }, + + /******************** + ** HELPERS + ********************/ + + /** + * Check if table is a locked colums table + */ + isLocked: function() { + return $(datatable.wrap).hasClass('m-datatable--lock') || false; + }, + + /** + * Insert html into table content, take count mCustomScrollbar DOM to prevent replace + * @param html + * @param tablePart + */ + replaceTableContent: function(html, tablePart) { + if (typeof tablePart === 'undefined') tablePart = datatable.tableBody; + if ($(tablePart).hasClass('mCustomScrollbar')) { + $(tablePart).find('.mCSB_container').html(html); + } else { + $(tablePart).html(html); + } + }, + + /** + * 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('.m-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('.m-datatable__row'). + first(). + find('.m-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 + var result = $(tablePart).find('.m-datatable__row:not(.m-datatable__row-detail):nth-child(' + row + ')'); + if (tdOnly) { + // get list of
').addClass('m-datatable__cell m-datatable__toggle--detail'). + append($(''). + addClass('m-datatable__toggle-detail'). + attr('href', '#'). + on('click', toggleHiddenColumns). + append($(''). + css('width', '21px').// maintain width for both icons expand and collapse + addClass(Plugin.getOption('layout.icons.rowDetail.collapse'))))); + + // check if subtable toggle exist + if ($(datatable.tableHead).find('.m-datatable__toggle-detail').length === 0) { + $(datatable.tableHead). + find('.m-datatable__row'). + first(). + prepend('. + * @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
or + result = result.find('.m-datatable__cell'); + } + return result; + }, + + /** + * Check if element has vertical overflow + * @param element + * @returns {boolean} + */ + hasOverflowY: function(element) { + var children = $(element).find('.m-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('.m-datatable__row'); + var hIndex = $(header).closest('.m-datatable__lock').index(); + if (hIndex !== -1) { + rows = $(datatable.tableBody). + find('.m-datatable__lock:nth-child(' + (hIndex + 1) + ')'). + find('.m-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('.m-datatable__cell:not(.m-datatable__cell--check)'). + addClass('m-datatable__cell--sort'). + off('click'). + on('click', sortObj.sortClick); + // first init + sortObj.setIcon(); + } + }, + setIcon: function() { + var meta = Plugin.getDataSourceParam('sort'); + // sort icon beside column header + var td = $(datatable.tableHead). + find('.m-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($('').addClass(icons[meta.sort])); + } + }, + 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; + + $(datatable.tableHead). + find('.m-datatable__cell > span > i'). + remove(); + + if (options.sortable) { + Plugin.spinnerCallback(true); + + var sort = 'desc'; + if (meta.field === field) { + sort = meta.sort; + } + + // 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('m-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 = params.sort.field; + var sort = params.sort.sort; + var column = Plugin.getColumnByField(field); + if (typeof column !== 'undefined') { + 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 (typeof params.query === 'object') { + params.query = params.query || {}; + + var search = $(Plugin.getOption('search.input')).val(); + if (typeof search !== 'undefined' && search !== '') { + search = search.toLowerCase(); + datatable.dataSet = $.grep(datatable.dataSet, function(obj) { + for (var field in obj) { + if (!obj.hasOwnProperty(field)) continue; + if (typeof obj[field] === 'string') { + if (obj[field].toLowerCase().indexOf(search) > -1) { + return true; + } + } + } + return false; + }); + // 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) { + if (to_match.hasOwnProperty(m_key) && m_value == to_match[m_key]) { + 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('.m-datatable__row').css('left', 0); + $(datatable.table).find('.m-datatable__lock').css('top', 0); + $(datatable.tableBody).scrollTop(0); + } + }, + + /** + * Get column options by field + * @param field + * @returns {boolean} + */ + getColumnByField: function(field) { + 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 = {sort: '', field: ''}; + $.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; + }, + + /******************** + ** PUBLIC API METHODS + ********************/ + + // delay timer + timer: 0, + + /** + * Redraw datatable by recalculating its DOM elements, etc. + * @returns {jQuery} + */ + redraw: function() { + Plugin.adjustCellsWidth.call(); + 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 === false) { + Plugin.localDataUpdate(); + } + Plugin.dataRender(); + $(datatable).trigger('m-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('.m-datatable__cell:first-child').each(function(i, cell) { + if (id == $(cell).text()) { + var rowNumber = $(cell).closest('.m-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('.m-datatable__pager').remove(); + var initialDatatable = $(datatable.initialDatatable).addClass('m-datatable--destroyed').show(); + $(datatable).replaceWith(initialDatatable); + datatable = initialDatatable; + $(datatable).trigger('m-datatable--on-destroy'); + Plugin.isInit = false; + initialDatatable = null; + return initialDatatable; + }, + + /** + * Sort by column field + * @param field + * @param sort + */ + sort: function(field, sort) { + if (typeof sort === 'undefined') sort = 'asc'; + $(datatable.tableHead). + find('.m-datatable__cell[data-field="' + field + '"]'). + trigger('click'); + 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('.m-checkbox--single > [type="checkbox"][value="' + cell + '"]'); + } + + $(cell).prop('checked', true); + + // normal table + var row = $(cell). + closest('.m-datatable__row'). + addClass('m-datatable__row--active'); + + var index = $(row).index() + 1; + // lock table + $(row). + closest('.m-datatable__lock'). + parent(). + find('.m-datatable__row:nth-child(' + index + ')'). + addClass('m-datatable__row--active'); + + var ids = []; + $(row).each(function(i, td) { + var id = $(td).find('.m-checkbox--single:not(.m-checkbox--all) > [type="checkbox"]').val(); + if (typeof id !== 'undefined') { + ids.push(id); + } + }); + + $(datatable).trigger('m-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('.m-checkbox--single > [type="checkbox"][value="' + cell + '"]'); + } + + $(cell).prop('checked', false); + + // normal table + var row = $(cell). + closest('.m-datatable__row'). + removeClass('m-datatable__row--active'); + var index = $(row).index() + 1; + + // lock table + $(row). + closest('.m-datatable__lock'). + parent(). + find('.m-datatable__row:nth-child(' + index + ')'). + removeClass('m-datatable__row--active'); + + var ids = []; + $(row).each(function(i, td) { + var id = $(td).find('.m-checkbox--single:not(.m-checkbox--all) > [type="checkbox"]').val(); + if (typeof id !== 'undefined') { + ids.push(id); + } + }); + + $(datatable).trigger('m-datatable--on-uncheck', [ids]); + }, + + /** + * Set all checkboxes active or inactive + * @param active + */ + setActiveAll: function(active) { + // todo; check if child table also will set active? + var checkboxes = $(datatable.table).find('.m-datatable__body .m-datatable__row'). + find('.m-datatable__cell .m-checkbox [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('.m-datatable__row--active'); + return datatable; + }, + + /** + * Get selected records + * @returns {null} + */ + getSelectedRecords: function() { + // support old method + Plugin.setSelectedRecords(); + datatable.API.record = datatable.rows('.m-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 === '') { + delete query[k]; + } + }); + } + + Plugin.setDataSourceQuery(query); + + // local filter only. remote pagination will skip this block + if (options.data.serverFiltering === false) { + Plugin.localDataUpdate(); + } + Plugin.dataRender(); + }, Plugin.getOption('search.delay')); + }, + + /** + * Set datasource params + * @param param + * @param value + */ + setDataSourceParam: function(param, value) { + var defaultSort = Plugin.getDefaultSortColumn(); + datatable.API.params = $.extend({}, { + pagination: {page: 1, perpage: Plugin.getOption('data.pageSize')}, + sort: {sort: defaultSort.sort, field: defaultSort.field}, + 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) { + var defaultSort = Plugin.getDefaultSortColumn(); + datatable.API.params = $.extend({}, { + pagination: {page: 1, perpage: Plugin.getOption('data.pageSize')}, + sort: {sort: defaultSort.sort, field: defaultSort.field}, + 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('.m-datatable__pager'). + last(). + find('.m-datatable__pager-nav'). + find('.m-datatable__pager-link.m-datatable__pager-link--active'). + data('page') || 1; + }, + + /** + * Get selected dropdown page size + * @returns {*|number} + */ + getPageSize: function() { + return $(datatable.table). + siblings('.m-datatable__pager'). + last(). + find('.m-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('.m-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('.m-datatable__cell'), function(n, i) { + return fieldName === $(n).data('field'); + }); + $(tds).show(); + }, + + destroyScroller: function(element) { + if (typeof element === 'undefined') element = datatable.tableBody; + $(element).each(function() { + if ($(this).hasClass('mCustomScrollbar')) { + try { + mApp.destroyScroller($(this)); + } catch (e) { + console.log(e); + } + } + }); + }, + + /** + * NEW API + */ + + nodeTr: [], + nodeTd: [], + nodeCols: [], + recentNode: [], + + table: function() { + 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('.m-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('.m-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('.m-datatable__cell[data-field="' + selector + '"]'); + if (columns.length > 0) { + Plugin.nodeCols = Plugin.recentNode = columns; + } else { + Plugin.nodeCols = Plugin.recentNode = $(context).find(selector).filter('.m-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('.m-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(); + } + return datatable; + }, + + /** + * Show or hide the columns or rows + */ + visible: function(bool) { + if ($(Plugin.recentNode.length)) { + if (bool) { + if (Plugin.recentNode === Plugin.nodeCols) { + Plugin.setOption('columns.' + Plugin.recentNode.index() + '.responsive', {}); + } + $(Plugin.recentNode).show(); + } else { + if (Plugin.recentNode === Plugin.nodeCols) { + Plugin.setOption('columns.' + Plugin.recentNode.index() + '.responsive', {hidden: 'xl'}); + } + $(Plugin.recentNode).hide(); + } + } + }, + + /** + * 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('mDatatable'); + if (typeof datatable !== 'undefined') { + options = datatable.options; + Plugin[method].apply(this, Array.prototype.slice.call(arguments, 1)); + } + } else { + if (!datatable.data('mDatatable') && !$(this).hasClass('m-datatable--loaded')) { + datatable.dataSet = null; + datatable.textAlign = { + left: 'm-datatable__cell--left', + center: 'm-datatable__cell--center', + right: 'm-datatable__cell--right', + }; + + // merge default and user defined options + options = $.extend(true, {}, $.fn.mDatatable.defaults, options); + + datatable.options = options; + + // init plugin process + Plugin.init.apply(this, [options]); + + $(datatable).data('mDatatable', datatable); + } + } + } else { + // get existing instance datatable + datatable = $(this).data('mDatatable'); + if (typeof datatable === 'undefined') { + $.error('mDatatable not initialized'); + } + options = datatable.options; + } + + return datatable; + }; + + // default options + $.fn.mDatatable.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, + }, + + // layout definition + layout: { + theme: 'default', // datatable will support multiple themes and designs + class: 'm-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 + + // datatable custom scroll params + smoothScroll: { + scrollbarShown: true, + }, + + // 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() {}, + // auto hide columns, if rows overflow. work on non locked columns + autoHide: false, + }, + + // 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: 6, + }, + 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', + }, + info: 'Displaying {{start}} - {{end}} of {{total}} records', + }, + }, + }, + }, + + extensions: {}, + }; + +}(jQuery)); // jquery extension to add animation class into element jQuery.fn.extend({ animateClass: function(animationName, callback) { @@ -901,7 +4364,7 @@ jQuery.fn.extend({ jQuery(this).css(vendors[i] + 'animation-duration', value); } } -}); +}); (function ($) { // Plugin function $.fn.mDropdown = function (options) { @@ -1474,7 +4937,7 @@ jQuery.fn.extend({ } }); }); -}(jQuery)); +}(jQuery)); (function ($) { // Plugin function $.fn.mExample = function (options) { @@ -1602,7 +5065,7 @@ jQuery.fn.extend({ $.fn.mExample.defaults = { }; -}(jQuery)); +}(jQuery)); (function($) { // Plugin function @@ -1735,7 +5198,7 @@ jQuery.fn.extend({ desktop: false } }; -}(jQuery)); +}(jQuery)); (function($) { // Plugin function @@ -2476,7 +5939,7 @@ jQuery.fn.extend({ } }); }); -}(jQuery)); +}(jQuery)); (function ($) { // Plugin function $.fn.mMessenger = function (options) { @@ -2604,7 +6067,7 @@ jQuery.fn.extend({ $.fn.mMessenger.defaults = { }; -}(jQuery)); +}(jQuery)); (function($) { // plugin setup $.fn.mOffcanvas = function(options) { @@ -2832,7 +6295,7 @@ jQuery.fn.extend({ $.fn.mOffcanvas.defaults = { }; -}(jQuery)); +}(jQuery)); (function ($) { // Plugin function $.fn.mPortlet = function (options) { @@ -3266,7 +6729,7 @@ jQuery.fn.extend({ } } }; -}(jQuery)); +}(jQuery)); (function($) { // Plugin function $.fn.mQuicksearch = function(options) { @@ -3487,7 +6950,7 @@ jQuery.fn.extend({ maxHeight: 300, }; -}(jQuery)); +}(jQuery)); (function($) { // plugin setup $.fn.mScrollTop = function(options) { @@ -3642,7 +7105,7 @@ jQuery.fn.extend({ offset: 300, speed: 600 }; -}(jQuery)); +}(jQuery)); (function($) { // plugin setup $.fn.mToggle = function(options) { @@ -3845,7 +7308,7 @@ jQuery.fn.extend({ togglerState: '', targetState: '' }; -}(jQuery)); +}(jQuery)); (function($) { // plugin setup $.fn.mWizard = function(options) { @@ -4284,17 +7747,17 @@ jQuery.fn.extend({ $.fn.mWizard.defaults = { startStep: 1 }; -}(jQuery)); - - $.fn.markdown.defaults.iconlibrary = 'fa'; +}(jQuery)); + + $.fn.markdown.defaults.iconlibrary = 'fa'; //$.fn.bootstrapSwitch.defaults.size = 'large'; -//$.fn.bootstrapSwitch.defaults.onColor = 'success'; +//$.fn.bootstrapSwitch.defaults.onColor = 'success'; $.fn.timepicker.defaults = $.extend(true, {}, $.fn.timepicker.defaults, { icons: { up: 'la la-angle-up', down: 'la la-angle-down' } -}); +}); jQuery.validator.setDefaults({ errorElement: 'div', //default input error message container errorClass: 'form-control-feedback', // default input error message class @@ -4345,7 +7808,7 @@ jQuery.validator.setDefaults({ group.removeClass('has-danger'); // hide error class group.find('.form-control-feedback').remove(); } -}); +}); Chart.elements.Rectangle.prototype.draw = function() { var ctx = this._chart.ctx; var vm = this._view; @@ -4475,7 +7938,7 @@ Chart.elements.Rectangle.prototype.draw = function() { if (borderWidth) { ctx.stroke(); } -}; +}; (function($) { $.fn.mDatatable = $.fn.mDatatable || {}; @@ -4680,7 +8143,7 @@ Chart.elements.Rectangle.prototype.draw = function() { }, }; -}(jQuery)); +}(jQuery)); //== Set defaults $.notifyDefaults({ @@ -4695,7 +8158,7 @@ $.notifyDefaults({ '' + '' + '' -}); +}); //== Set defaults swal.setDefaults({ width: 400, @@ -4705,7 +8168,7 @@ swal.setDefaults({ confirmButtonColor: null, cancelButtonClass: 'btn btn-secondary m-btn m-btn--custom', cancelButtonColor: null -}); +}); var mLayout = function() { var horMenu; var asideMenu; @@ -4982,8 +8445,8 @@ $(document).ready(function() { mLayout.init(); } }); - - + + var mQuickSidebar = function() { var topbarAside = $('#m_quick_sidebar'); var topbarAsideTabs = $('#m_quick_sidebar_tabs'); diff --git a/public/assets/js/moment.min.js b/public/assets/js/moment.min.js new file mode 100644 index 00000000..1f7c4acb --- /dev/null +++ b/public/assets/js/moment.min.js @@ -0,0 +1 @@ +!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):e.moment=t()}(this,function(){"use strict";function e(){return Qe.apply(null,arguments)}function t(e){return e instanceof Array||"[object Array]"===Object.prototype.toString.call(e)}function n(e){return null!=e&&"[object Object]"===Object.prototype.toString.call(e)}function s(e){return void 0===e}function i(e){return"number"==typeof e||"[object Number]"===Object.prototype.toString.call(e)}function r(e){return e instanceof Date||"[object Date]"===Object.prototype.toString.call(e)}function a(e,t){var n,s=[];for(n=0;n0)for(n=0;n=0?n?"+":"":"-")+Math.pow(10,Math.max(0,i)).toString().substr(1)+s}function P(e,t,n,s){var i=s;"string"==typeof s&&(i=function(){return this[s]()}),e&&(ut[e]=i),t&&(ut[t[0]]=function(){return b(i.apply(this,arguments),t[1],t[2])}),n&&(ut[n]=function(){return this.localeData().ordinal(i.apply(this,arguments),e)})}function W(e){return e.match(/\[[\s\S]/)?e.replace(/^\[|\]$/g,""):e.replace(/\\/g,"")}function H(e,t){return e.isValid()?(t=R(t,e.localeData()),ot[t]=ot[t]||function(e){var t,n,s=e.match(rt);for(t=0,n=s.length;t=0&&at.test(e);)e=e.replace(at,n),at.lastIndex=0,s-=1;return e}function C(e,t,n){Yt[e]=S(t)?t:function(e,s){return e&&n?n:t}}function F(e,t){return o(Yt,e)?Yt[e](t._strict,t._locale):new RegExp(function(e){return U(e.replace("\\","").replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g,function(e,t,n,s,i){return t||n||s||i}))}(e))}function U(e){return e.replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&")}function L(e,t){var n,s=t;for("string"==typeof e&&(e=[e]),i(t)&&(s=function(e,n){n[t]=g(e)}),n=0;n=0&&isFinite(t.getUTCFullYear())&&t.setUTCFullYear(e),t}function B(e,t,n){var s=7+t-n;return-((7+J(e,0,s).getUTCDay()-t)%7)+s-1}function Q(e,t,n,s,i){var r,a,o=1+7*(t-1)+(7+n-s)%7+B(e,s,i);return o<=0?a=V(r=e-1)+o:o>V(e)?(r=e+1,a=o-V(e)):(r=e,a=o),{year:r,dayOfYear:a}}function X(e,t,n){var s,i,r=B(e.year(),t,n),a=Math.floor((e.dayOfYear()-r-1)/7)+1;return a<1?s=a+K(i=e.year()-1,t,n):a>K(e.year(),t,n)?(s=a-K(e.year(),t,n),i=e.year()+1):(i=e.year(),s=a),{week:s,year:i}}function K(e,t,n){var s=B(e,t,n),i=B(e+1,t,n);return(V(e)-s+i)/7}function ee(){function e(e,t){return t.length-e.length}var t,n,s,i,r,a=[],o=[],u=[],d=[];for(t=0;t<7;t++)n=l([2e3,1]).day(t),s=this.weekdaysMin(n,""),i=this.weekdaysShort(n,""),r=this.weekdays(n,""),a.push(s),o.push(i),u.push(r),d.push(s),d.push(i),d.push(r);for(a.sort(e),o.sort(e),u.sort(e),d.sort(e),t=0;t<7;t++)o[t]=U(o[t]),u[t]=U(u[t]),d[t]=U(d[t]);this._weekdaysRegex=new RegExp("^("+d.join("|")+")","i"),this._weekdaysShortRegex=this._weekdaysRegex,this._weekdaysMinRegex=this._weekdaysRegex,this._weekdaysStrictRegex=new RegExp("^("+u.join("|")+")","i"),this._weekdaysShortStrictRegex=new RegExp("^("+o.join("|")+")","i"),this._weekdaysMinStrictRegex=new RegExp("^("+a.join("|")+")","i")}function te(){return this.hours()%12||12}function ne(e,t){P(e,0,0,function(){return this.localeData().meridiem(this.hours(),this.minutes(),t)})}function se(e,t){return t._meridiemParse}function ie(e){return e?e.toLowerCase().replace("_","-"):e}function re(e){var t=null;if(!Xt[e]&&"undefined"!=typeof module&&module&&module.exports)try{t=Jt._abbr;require("./locale/"+e),ae(t)}catch(e){}return Xt[e]}function ae(e,t){var n;return e&&(n=s(t)?ue(e):oe(e,t))&&(Jt=n),Jt._abbr}function oe(e,t){if(null!==t){var n=Qt;if(t.abbr=e,null!=Xt[e])M("defineLocaleOverride","use moment.updateLocale(localeName, config) to change an existing locale. moment.defineLocale(localeName, config) should only be used for creating a new locale See http://momentjs.com/guides/#/warnings/define-locale/ for more info."),n=Xt[e]._config;else if(null!=t.parentLocale){if(null==Xt[t.parentLocale])return Kt[t.parentLocale]||(Kt[t.parentLocale]=[]),Kt[t.parentLocale].push({name:e,config:t}),null;n=Xt[t.parentLocale]._config}return Xt[e]=new k(D(n,t)),Kt[e]&&Kt[e].forEach(function(e){oe(e.name,e.config)}),ae(e),Xt[e]}return delete Xt[e],null}function ue(e){var n;if(e&&e._locale&&e._locale._abbr&&(e=e._locale._abbr),!e)return Jt;if(!t(e)){if(n=re(e))return n;e=[e]}return function(e){for(var t,n,s,i,r=0;r0;){if(s=re(i.slice(0,t).join("-")))return s;if(n&&n.length>=t&&p(i,n,!0)>=t-1)break;t--}r++}return null}(e)}function le(e){var t,n=e._a;return n&&-2===d(e).overflow&&(t=n[xt]<0||n[xt]>11?xt:n[bt]<1||n[bt]>Z(n[Tt],n[xt])?bt:n[Pt]<0||n[Pt]>24||24===n[Pt]&&(0!==n[Wt]||0!==n[Ht]||0!==n[Rt])?Pt:n[Wt]<0||n[Wt]>59?Wt:n[Ht]<0||n[Ht]>59?Ht:n[Rt]<0||n[Rt]>999?Rt:-1,d(e)._overflowDayOfYear&&(tbt)&&(t=bt),d(e)._overflowWeeks&&-1===t&&(t=Ct),d(e)._overflowWeekday&&-1===t&&(t=Ft),d(e).overflow=t),e}function de(e,t,n){return null!=e?e:null!=t?t:n}function he(t){var n,s,i,r,a,o=[];if(!t._d){for(i=function(t){var n=new Date(e.now());return t._useUTC?[n.getUTCFullYear(),n.getUTCMonth(),n.getUTCDate()]:[n.getFullYear(),n.getMonth(),n.getDate()]}(t),t._w&&null==t._a[bt]&&null==t._a[xt]&&function(e){var t,n,s,i,r,a,o,u;if(null!=(t=e._w).GG||null!=t.W||null!=t.E)r=1,a=4,n=de(t.GG,e._a[Tt],X(pe(),1,4).year),s=de(t.W,1),((i=de(t.E,1))<1||i>7)&&(u=!0);else{r=e._locale._week.dow,a=e._locale._week.doy;var l=X(pe(),r,a);n=de(t.gg,e._a[Tt],l.year),s=de(t.w,l.week),null!=t.d?((i=t.d)<0||i>6)&&(u=!0):null!=t.e?(i=t.e+r,(t.e<0||t.e>6)&&(u=!0)):i=r}s<1||s>K(n,r,a)?d(e)._overflowWeeks=!0:null!=u?d(e)._overflowWeekday=!0:(o=Q(n,s,i,r,a),e._a[Tt]=o.year,e._dayOfYear=o.dayOfYear)}(t),null!=t._dayOfYear&&(a=de(t._a[Tt],i[Tt]),(t._dayOfYear>V(a)||0===t._dayOfYear)&&(d(t)._overflowDayOfYear=!0),s=J(a,0,t._dayOfYear),t._a[xt]=s.getUTCMonth(),t._a[bt]=s.getUTCDate()),n=0;n<3&&null==t._a[n];++n)t._a[n]=o[n]=i[n];for(;n<7;n++)t._a[n]=o[n]=null==t._a[n]?2===n?1:0:t._a[n];24===t._a[Pt]&&0===t._a[Wt]&&0===t._a[Ht]&&0===t._a[Rt]&&(t._nextDay=!0,t._a[Pt]=0),t._d=(t._useUTC?J:function(e,t,n,s,i,r,a){var o=new Date(e,t,n,s,i,r,a);return e<100&&e>=0&&isFinite(o.getFullYear())&&o.setFullYear(e),o}).apply(null,o),r=t._useUTC?t._d.getUTCDay():t._d.getDay(),null!=t._tzm&&t._d.setUTCMinutes(t._d.getUTCMinutes()-t._tzm),t._nextDay&&(t._a[Pt]=24),t._w&&void 0!==t._w.d&&t._w.d!==r&&(d(t).weekdayMismatch=!0)}}function ce(e){var t,n,s,i,r,a,o=e._i,u=en.exec(o)||tn.exec(o);if(u){for(d(e).iso=!0,t=0,n=sn.length;t0&&d(t).unusedInput.push(a),o=o.slice(o.indexOf(s)+s.length),l+=s.length),ut[r]?(s?d(t).empty=!1:d(t).unusedTokens.push(r),G(r,s,t)):t._strict&&!s&&d(t).unusedTokens.push(r);d(t).charsLeftOver=u-l,o.length>0&&d(t).unusedInput.push(o),t._a[Pt]<=12&&!0===d(t).bigHour&&t._a[Pt]>0&&(d(t).bigHour=void 0),d(t).parsedDateParts=t._a.slice(0),d(t).meridiem=t._meridiem,t._a[Pt]=function(e,t,n){var s;if(null==n)return t;return null!=e.meridiemHour?e.meridiemHour(t,n):null!=e.isPM?((s=e.isPM(n))&&t<12&&(t+=12),s||12!==t||(t=0),t):t}(t._locale,t._a[Pt],t._meridiem),he(t),le(t)}else me(t);else ce(t)}function ye(o){var l=o._i,y=o._f;return o._locale=o._locale||ue(o._l),null===l||void 0===y&&""===l?c({nullInput:!0}):("string"==typeof l&&(o._i=l=o._locale.preparse(l)),_(l)?new m(le(l)):(r(l)?o._d=l:t(y)?function(e){var t,n,s,i,r;if(0===e._f.length)return d(e).invalidFormat=!0,void(e._d=new Date(NaN));for(i=0;ir&&(t=r),function(e,t,n,s,i){var r=Q(e,t,n,s,i),a=J(r.year,0,r.dayOfYear);return this.year(a.getUTCFullYear()),this.month(a.getUTCMonth()),this.date(a.getUTCDate()),this}.call(this,e,t,n,s,i))}function Ne(e,t){t[Rt]=g(1e3*("0."+e))}function Ge(e){return e}function Ve(e,t,n,s){var i=ue(),r=l().set(s,t);return i[n](r,e)}function Ee(e,t,n){if(i(e)&&(t=e,e=void 0),e=e||"",null!=t)return Ve(e,t,n,"month");var s,r=[];for(s=0;s<12;s++)r[s]=Ve(e,s,n,"month");return r}function Ie(e,t,n,s){"boolean"==typeof e?(i(t)&&(n=t,t=void 0),t=t||""):(n=t=e,e=!1,i(t)&&(n=t,t=void 0),t=t||"");var r=ue(),a=e?r._week.dow:0;if(null!=n)return Ve(t,(n+a)%7,s,"day");var o,u=[];for(o=0;o<7;o++)u[o]=Ve(t,(o+a)%7,s,"day");return u}function Ae(e,t,n,s){var i=xe(t,n);return e._milliseconds+=s*i._milliseconds,e._days+=s*i._days,e._months+=s*i._months,e._bubble()}function je(e){return e<0?Math.floor(e):Math.ceil(e)}function Ze(e){return 4800*e/146097}function ze(e){return 146097*e/4800}function $e(e){return function(){return this.as(e)}}function qe(e){return function(){return this.isValid()?this._data[e]:NaN}}function Je(e){return(e>0)-(e<0)||+e}function Be(){if(!this.isValid())return this.localeData().invalidDate();var e,t,n=An(this._milliseconds)/1e3,s=An(this._days),i=An(this._months);t=y((e=y(n/60))/60),n%=60,e%=60;var r=y(i/12),a=i%=12,o=s,u=t,l=e,d=n?n.toFixed(3).replace(/\.?0+$/,""):"",h=this.asSeconds();if(!h)return"P0D";var c=h<0?"-":"",f=Je(this._months)!==Je(h)?"-":"",m=Je(this._days)!==Je(h)?"-":"",_=Je(this._milliseconds)!==Je(h)?"-":"";return c+"P"+(r?f+r+"Y":"")+(a?f+a+"M":"")+(o?m+o+"D":"")+(u||l||d?"T":"")+(u?_+u+"H":"")+(l?_+l+"M":"")+(d?_+d+"S":"")}var Qe,Xe;Xe=Array.prototype.some?Array.prototype.some:function(e){for(var t=Object(this),n=t.length>>>0,s=0;s68?1900:2e3)};var Ut,Lt=I("FullYear",!0);Ut=Array.prototype.indexOf?Array.prototype.indexOf:function(e){var t;for(t=0;tthis?this:e:c()}),hn=["year","quarter","month","week","day","hour","minute","second","millisecond"];De("Z",":"),De("ZZ",""),C("Z",Dt),C("ZZ",Dt),L(["Z","ZZ"],function(e,t,n){n._useUTC=!0,n._tzm=ke(Dt,e)});var cn=/([\+\-]|\d\d)/gi;e.updateOffset=function(){};var fn=/^(\-|\+)?(?:(\d*)[. ])?(\d+)\:(\d+)(?:\:(\d+)(\.\d*)?)?$/,mn=/^(-|\+)?P(?:([-+]?[0-9,.]*)Y)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)W)?(?:([-+]?[0-9,.]*)D)?(?:T(?:([-+]?[0-9,.]*)H)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)S)?)?$/;xe.fn=ve.prototype,xe.invalid=function(){return xe(NaN)};var _n=We(1,"add"),yn=We(-1,"subtract");e.defaultFormat="YYYY-MM-DDTHH:mm:ssZ",e.defaultFormatUtc="YYYY-MM-DDTHH:mm:ss[Z]";var gn=v("moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.",function(e){return void 0===e?this.localeData():this.locale(e)});P(0,["gg",2],0,function(){return this.weekYear()%100}),P(0,["GG",2],0,function(){return this.isoWeekYear()%100}),Ue("gggg","weekYear"),Ue("ggggg","weekYear"),Ue("GGGG","isoWeekYear"),Ue("GGGGG","isoWeekYear"),Y("weekYear","gg"),Y("isoWeekYear","GG"),x("weekYear",1),x("isoWeekYear",1),C("G",Mt),C("g",Mt),C("GG",mt,dt),C("gg",mt,dt),C("GGGG",pt,ct),C("gggg",pt,ct),C("GGGGG",wt,ft),C("ggggg",wt,ft),N(["gggg","ggggg","GGGG","GGGGG"],function(e,t,n,s){t[s.substr(0,2)]=g(e)}),N(["gg","GG"],function(t,n,s,i){n[i]=e.parseTwoDigitYear(t)}),P("Q",0,"Qo","quarter"),Y("quarter","Q"),x("quarter",7),C("Q",lt),L("Q",function(e,t){t[xt]=3*(g(e)-1)}),P("D",["DD",2],"Do","date"),Y("date","D"),x("date",9),C("D",mt),C("DD",mt,dt),C("Do",function(e,t){return e?t._dayOfMonthOrdinalParse||t._ordinalParse:t._dayOfMonthOrdinalParseLenient}),L(["D","DD"],bt),L("Do",function(e,t){t[bt]=g(e.match(mt)[0])});var pn=I("Date",!0);P("DDD",["DDDD",3],"DDDo","dayOfYear"),Y("dayOfYear","DDD"),x("dayOfYear",4),C("DDD",gt),C("DDDD",ht),L(["DDD","DDDD"],function(e,t,n){n._dayOfYear=g(e)}),P("m",["mm",2],0,"minute"),Y("minute","m"),x("minute",14),C("m",mt),C("mm",mt,dt),L(["m","mm"],Wt);var wn=I("Minutes",!1);P("s",["ss",2],0,"second"),Y("second","s"),x("second",15),C("s",mt),C("ss",mt,dt),L(["s","ss"],Ht);var vn=I("Seconds",!1);P("S",0,0,function(){return~~(this.millisecond()/100)}),P(0,["SS",2],0,function(){return~~(this.millisecond()/10)}),P(0,["SSS",3],0,"millisecond"),P(0,["SSSS",4],0,function(){return 10*this.millisecond()}),P(0,["SSSSS",5],0,function(){return 100*this.millisecond()}),P(0,["SSSSSS",6],0,function(){return 1e3*this.millisecond()}),P(0,["SSSSSSS",7],0,function(){return 1e4*this.millisecond()}),P(0,["SSSSSSSS",8],0,function(){return 1e5*this.millisecond()}),P(0,["SSSSSSSSS",9],0,function(){return 1e6*this.millisecond()}),Y("millisecond","ms"),x("millisecond",16),C("S",gt,lt),C("SS",gt,dt),C("SSS",gt,ht);var Mn;for(Mn="SSSS";Mn.length<=9;Mn+="S")C(Mn,vt);for(Mn="S";Mn.length<=9;Mn+="S")L(Mn,Ne);var Sn=I("Milliseconds",!1);P("z",0,0,"zoneAbbr"),P("zz",0,0,"zoneName");var Dn=m.prototype;Dn.add=_n,Dn.calendar=function(t,n){var s=t||pe(),i=Ye(s,this).startOf("day"),r=e.calendarFormat(this,i)||"sameElse",a=n&&(S(n[r])?n[r].call(this,s):n[r]);return this.format(a||this.localeData().calendar(r,this,pe(s)))},Dn.clone=function(){return new m(this)},Dn.diff=function(e,t,n){var s,i,r;if(!this.isValid())return NaN;if(!(s=Ye(e,this)).isValid())return NaN;switch(i=6e4*(s.utcOffset()-this.utcOffset()),t=O(t)){case"year":r=Re(this,s)/12;break;case"month":r=Re(this,s);break;case"quarter":r=Re(this,s)/3;break;case"second":r=(this-s)/1e3;break;case"minute":r=(this-s)/6e4;break;case"hour":r=(this-s)/36e5;break;case"day":r=(this-s-i)/864e5;break;case"week":r=(this-s-i)/6048e5;break;default:r=this-s}return n?r:y(r)},Dn.endOf=function(e){return void 0===(e=O(e))||"millisecond"===e?this:("date"===e&&(e="day"),this.startOf(e).add(1,"isoWeek"===e?"week":e).subtract(1,"ms"))},Dn.format=function(t){t||(t=this.isUtc()?e.defaultFormatUtc:e.defaultFormat);var n=H(this,t);return this.localeData().postformat(n)},Dn.from=function(e,t){return this.isValid()&&(_(e)&&e.isValid()||pe(e).isValid())?xe({to:this,from:e}).locale(this.locale()).humanize(!t):this.localeData().invalidDate()},Dn.fromNow=function(e){return this.from(pe(),e)},Dn.to=function(e,t){return this.isValid()&&(_(e)&&e.isValid()||pe(e).isValid())?xe({from:this,to:e}).locale(this.locale()).humanize(!t):this.localeData().invalidDate()},Dn.toNow=function(e){return this.to(pe(),e)},Dn.get=function(e){return e=O(e),S(this[e])?this[e]():this},Dn.invalidAt=function(){return d(this).overflow},Dn.isAfter=function(e,t){var n=_(e)?e:pe(e);return!(!this.isValid()||!n.isValid())&&("millisecond"===(t=O(s(t)?"millisecond":t))?this.valueOf()>n.valueOf():n.valueOf()9999?H(n,t?"YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]":"YYYYYY-MM-DD[T]HH:mm:ss.SSSZ"):S(Date.prototype.toISOString)?t?this.toDate().toISOString():new Date(this._d.valueOf()).toISOString().replace("Z",H(n,"Z")):H(n,t?"YYYY-MM-DD[T]HH:mm:ss.SSS[Z]":"YYYY-MM-DD[T]HH:mm:ss.SSSZ")},Dn.inspect=function(){if(!this.isValid())return"moment.invalid(/* "+this._i+" */)";var e="moment",t="";this.isLocal()||(e=0===this.utcOffset()?"moment.utc":"moment.parseZone",t="Z");var n="["+e+'("]',s=0<=this.year()&&this.year()<=9999?"YYYY":"YYYYYY",i=t+'[")]';return this.format(n+s+"-MM-DD[T]HH:mm:ss.SSS"+i)},Dn.toJSON=function(){return this.isValid()?this.toISOString():null},Dn.toString=function(){return this.clone().locale("en").format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ")},Dn.unix=function(){return Math.floor(this.valueOf()/1e3)},Dn.valueOf=function(){return this._d.valueOf()-6e4*(this._offset||0)},Dn.creationData=function(){return{input:this._i,format:this._f,locale:this._locale,isUTC:this._isUTC,strict:this._strict}},Dn.year=Lt,Dn.isLeapYear=function(){return E(this.year())},Dn.weekYear=function(e){return Le.call(this,e,this.week(),this.weekday(),this.localeData()._week.dow,this.localeData()._week.doy)},Dn.isoWeekYear=function(e){return Le.call(this,e,this.isoWeek(),this.isoWeekday(),1,4)},Dn.quarter=Dn.quarters=function(e){return null==e?Math.ceil((this.month()+1)/3):this.month(3*(e-1)+this.month()%3)},Dn.month=$,Dn.daysInMonth=function(){return Z(this.year(),this.month())},Dn.week=Dn.weeks=function(e){var t=this.localeData().week(this);return null==e?t:this.add(7*(e-t),"d")},Dn.isoWeek=Dn.isoWeeks=function(e){var t=X(this,1,4).week;return null==e?t:this.add(7*(e-t),"d")},Dn.weeksInYear=function(){var e=this.localeData()._week;return K(this.year(),e.dow,e.doy)},Dn.isoWeeksInYear=function(){return K(this.year(),1,4)},Dn.date=pn,Dn.day=Dn.days=function(e){if(!this.isValid())return null!=e?this:NaN;var t=this._isUTC?this._d.getUTCDay():this._d.getDay();return null!=e?(e=function(e,t){return"string"!=typeof e?e:isNaN(e)?"number"==typeof(e=t.weekdaysParse(e))?e:null:parseInt(e,10)}(e,this.localeData()),this.add(e-t,"d")):t},Dn.weekday=function(e){if(!this.isValid())return null!=e?this:NaN;var t=(this.day()+7-this.localeData()._week.dow)%7;return null==e?t:this.add(e-t,"d")},Dn.isoWeekday=function(e){if(!this.isValid())return null!=e?this:NaN;if(null!=e){var t=function(e,t){return"string"==typeof e?t.weekdaysParse(e)%7||7:isNaN(e)?null:e}(e,this.localeData());return this.day(this.day()%7?t:t-7)}return this.day()||7},Dn.dayOfYear=function(e){var t=Math.round((this.clone().startOf("day")-this.clone().startOf("year"))/864e5)+1;return null==e?t:this.add(e-t,"d")},Dn.hour=Dn.hours=Bt,Dn.minute=Dn.minutes=wn,Dn.second=Dn.seconds=vn,Dn.millisecond=Dn.milliseconds=Sn,Dn.utcOffset=function(t,n,s){var i,r=this._offset||0;if(!this.isValid())return null!=t?this:NaN;if(null!=t){if("string"==typeof t){if(null===(t=ke(Dt,t)))return this}else Math.abs(t)<16&&!s&&(t*=60);return!this._isUTC&&n&&(i=Oe(this)),this._offset=t,this._isUTC=!0,null!=i&&this.add(i,"m"),r!==t&&(!n||this._changeInProgress?He(this,xe(t-r,"m"),1,!1):this._changeInProgress||(this._changeInProgress=!0,e.updateOffset(this,!0),this._changeInProgress=null)),this}return this._isUTC?r:Oe(this)},Dn.utc=function(e){return this.utcOffset(0,e)},Dn.local=function(e){return this._isUTC&&(this.utcOffset(0,e),this._isUTC=!1,e&&this.subtract(Oe(this),"m")),this},Dn.parseZone=function(){if(null!=this._tzm)this.utcOffset(this._tzm,!1,!0);else if("string"==typeof this._i){var e=ke(St,this._i);null!=e?this.utcOffset(e):this.utcOffset(0,!0)}return this},Dn.hasAlignedHourOffset=function(e){return!!this.isValid()&&(e=e?pe(e).utcOffset():0,(this.utcOffset()-e)%60==0)},Dn.isDST=function(){return this.utcOffset()>this.clone().month(0).utcOffset()||this.utcOffset()>this.clone().month(5).utcOffset()},Dn.isLocal=function(){return!!this.isValid()&&!this._isUTC},Dn.isUtcOffset=function(){return!!this.isValid()&&this._isUTC},Dn.isUtc=Te,Dn.isUTC=Te,Dn.zoneAbbr=function(){return this._isUTC?"UTC":""},Dn.zoneName=function(){return this._isUTC?"Coordinated Universal Time":""},Dn.dates=v("dates accessor is deprecated. Use date instead.",pn),Dn.months=v("months accessor is deprecated. Use month instead",$),Dn.years=v("years accessor is deprecated. Use year instead",Lt),Dn.zone=v("moment().zone is deprecated, use moment().utcOffset instead. http://momentjs.com/guides/#/warnings/zone/",function(e,t){return null!=e?("string"!=typeof e&&(e=-e),this.utcOffset(e,t),this):-this.utcOffset()}),Dn.isDSTShifted=v("isDSTShifted is deprecated. See http://momentjs.com/guides/#/warnings/dst-shifted/ for more information",function(){if(!s(this._isDSTShifted))return this._isDSTShifted;var e={};if(f(e,this),(e=ye(e))._a){var t=e._isUTC?l(e._a):pe(e._a);this._isDSTShifted=this.isValid()&&p(e._a,t.toArray())>0}else this._isDSTShifted=!1;return this._isDSTShifted});var kn=k.prototype;kn.calendar=function(e,t,n){var s=this._calendar[e]||this._calendar.sameElse;return S(s)?s.call(t,n):s},kn.longDateFormat=function(e){var t=this._longDateFormat[e],n=this._longDateFormat[e.toUpperCase()];return t||!n?t:(this._longDateFormat[e]=n.replace(/MMMM|MM|DD|dddd/g,function(e){return e.slice(1)}),this._longDateFormat[e])},kn.invalidDate=function(){return this._invalidDate},kn.ordinal=function(e){return this._ordinal.replace("%d",e)},kn.preparse=Ge,kn.postformat=Ge,kn.relativeTime=function(e,t,n,s){var i=this._relativeTime[n];return S(i)?i(e,t,n,s):i.replace(/%d/i,e)},kn.pastFuture=function(e,t){var n=this._relativeTime[e>0?"future":"past"];return S(n)?n(t):n.replace(/%s/i,t)},kn.set=function(e){var t,n;for(n in e)S(t=e[n])?this[n]=t:this["_"+n]=t;this._config=e,this._dayOfMonthOrdinalParseLenient=new RegExp((this._dayOfMonthOrdinalParse.source||this._ordinalParse.source)+"|"+/\d{1,2}/.source)},kn.months=function(e,n){return e?t(this._months)?this._months[e.month()]:this._months[(this._months.isFormat||Nt).test(n)?"format":"standalone"][e.month()]:t(this._months)?this._months:this._months.standalone},kn.monthsShort=function(e,n){return e?t(this._monthsShort)?this._monthsShort[e.month()]:this._monthsShort[Nt.test(n)?"format":"standalone"][e.month()]:t(this._monthsShort)?this._monthsShort:this._monthsShort.standalone},kn.monthsParse=function(e,t,n){var s,i,r;if(this._monthsParseExact)return function(e,t,n){var s,i,r,a=e.toLocaleLowerCase();if(!this._monthsParse)for(this._monthsParse=[],this._longMonthsParse=[],this._shortMonthsParse=[],s=0;s<12;++s)r=l([2e3,s]),this._shortMonthsParse[s]=this.monthsShort(r,"").toLocaleLowerCase(),this._longMonthsParse[s]=this.months(r,"").toLocaleLowerCase();return n?"MMM"===t?-1!==(i=Ut.call(this._shortMonthsParse,a))?i:null:-1!==(i=Ut.call(this._longMonthsParse,a))?i:null:"MMM"===t?-1!==(i=Ut.call(this._shortMonthsParse,a))?i:-1!==(i=Ut.call(this._longMonthsParse,a))?i:null:-1!==(i=Ut.call(this._longMonthsParse,a))?i:-1!==(i=Ut.call(this._shortMonthsParse,a))?i:null}.call(this,e,t,n);for(this._monthsParse||(this._monthsParse=[],this._longMonthsParse=[],this._shortMonthsParse=[]),s=0;s<12;s++){if(i=l([2e3,s]),n&&!this._longMonthsParse[s]&&(this._longMonthsParse[s]=new RegExp("^"+this.months(i,"").replace(".","")+"$","i"),this._shortMonthsParse[s]=new RegExp("^"+this.monthsShort(i,"").replace(".","")+"$","i")),n||this._monthsParse[s]||(r="^"+this.months(i,"")+"|^"+this.monthsShort(i,""),this._monthsParse[s]=new RegExp(r.replace(".",""),"i")),n&&"MMMM"===t&&this._longMonthsParse[s].test(e))return s;if(n&&"MMM"===t&&this._shortMonthsParse[s].test(e))return s;if(!n&&this._monthsParse[s].test(e))return s}},kn.monthsRegex=function(e){return this._monthsParseExact?(o(this,"_monthsRegex")||q.call(this),e?this._monthsStrictRegex:this._monthsRegex):(o(this,"_monthsRegex")||(this._monthsRegex=It),this._monthsStrictRegex&&e?this._monthsStrictRegex:this._monthsRegex)},kn.monthsShortRegex=function(e){return this._monthsParseExact?(o(this,"_monthsRegex")||q.call(this),e?this._monthsShortStrictRegex:this._monthsShortRegex):(o(this,"_monthsShortRegex")||(this._monthsShortRegex=Et),this._monthsShortStrictRegex&&e?this._monthsShortStrictRegex:this._monthsShortRegex)},kn.week=function(e){return X(e,this._week.dow,this._week.doy).week},kn.firstDayOfYear=function(){return this._week.doy},kn.firstDayOfWeek=function(){return this._week.dow},kn.weekdays=function(e,n){return e?t(this._weekdays)?this._weekdays[e.day()]:this._weekdays[this._weekdays.isFormat.test(n)?"format":"standalone"][e.day()]:t(this._weekdays)?this._weekdays:this._weekdays.standalone},kn.weekdaysMin=function(e){return e?this._weekdaysMin[e.day()]:this._weekdaysMin},kn.weekdaysShort=function(e){return e?this._weekdaysShort[e.day()]:this._weekdaysShort},kn.weekdaysParse=function(e,t,n){var s,i,r;if(this._weekdaysParseExact)return function(e,t,n){var s,i,r,a=e.toLocaleLowerCase();if(!this._weekdaysParse)for(this._weekdaysParse=[],this._shortWeekdaysParse=[],this._minWeekdaysParse=[],s=0;s<7;++s)r=l([2e3,1]).day(s),this._minWeekdaysParse[s]=this.weekdaysMin(r,"").toLocaleLowerCase(),this._shortWeekdaysParse[s]=this.weekdaysShort(r,"").toLocaleLowerCase(),this._weekdaysParse[s]=this.weekdays(r,"").toLocaleLowerCase();return n?"dddd"===t?-1!==(i=Ut.call(this._weekdaysParse,a))?i:null:"ddd"===t?-1!==(i=Ut.call(this._shortWeekdaysParse,a))?i:null:-1!==(i=Ut.call(this._minWeekdaysParse,a))?i:null:"dddd"===t?-1!==(i=Ut.call(this._weekdaysParse,a))?i:-1!==(i=Ut.call(this._shortWeekdaysParse,a))?i:-1!==(i=Ut.call(this._minWeekdaysParse,a))?i:null:"ddd"===t?-1!==(i=Ut.call(this._shortWeekdaysParse,a))?i:-1!==(i=Ut.call(this._weekdaysParse,a))?i:-1!==(i=Ut.call(this._minWeekdaysParse,a))?i:null:-1!==(i=Ut.call(this._minWeekdaysParse,a))?i:-1!==(i=Ut.call(this._weekdaysParse,a))?i:-1!==(i=Ut.call(this._shortWeekdaysParse,a))?i:null}.call(this,e,t,n);for(this._weekdaysParse||(this._weekdaysParse=[],this._minWeekdaysParse=[],this._shortWeekdaysParse=[],this._fullWeekdaysParse=[]),s=0;s<7;s++){if(i=l([2e3,1]).day(s),n&&!this._fullWeekdaysParse[s]&&(this._fullWeekdaysParse[s]=new RegExp("^"+this.weekdays(i,"").replace(".",".?")+"$","i"),this._shortWeekdaysParse[s]=new RegExp("^"+this.weekdaysShort(i,"").replace(".",".?")+"$","i"),this._minWeekdaysParse[s]=new RegExp("^"+this.weekdaysMin(i,"").replace(".",".?")+"$","i")),this._weekdaysParse[s]||(r="^"+this.weekdays(i,"")+"|^"+this.weekdaysShort(i,"")+"|^"+this.weekdaysMin(i,""),this._weekdaysParse[s]=new RegExp(r.replace(".",""),"i")),n&&"dddd"===t&&this._fullWeekdaysParse[s].test(e))return s;if(n&&"ddd"===t&&this._shortWeekdaysParse[s].test(e))return s;if(n&&"dd"===t&&this._minWeekdaysParse[s].test(e))return s;if(!n&&this._weekdaysParse[s].test(e))return s}},kn.weekdaysRegex=function(e){return this._weekdaysParseExact?(o(this,"_weekdaysRegex")||ee.call(this),e?this._weekdaysStrictRegex:this._weekdaysRegex):(o(this,"_weekdaysRegex")||(this._weekdaysRegex=zt),this._weekdaysStrictRegex&&e?this._weekdaysStrictRegex:this._weekdaysRegex)},kn.weekdaysShortRegex=function(e){return this._weekdaysParseExact?(o(this,"_weekdaysRegex")||ee.call(this),e?this._weekdaysShortStrictRegex:this._weekdaysShortRegex):(o(this,"_weekdaysShortRegex")||(this._weekdaysShortRegex=$t),this._weekdaysShortStrictRegex&&e?this._weekdaysShortStrictRegex:this._weekdaysShortRegex)},kn.weekdaysMinRegex=function(e){return this._weekdaysParseExact?(o(this,"_weekdaysRegex")||ee.call(this),e?this._weekdaysMinStrictRegex:this._weekdaysMinRegex):(o(this,"_weekdaysMinRegex")||(this._weekdaysMinRegex=qt),this._weekdaysMinStrictRegex&&e?this._weekdaysMinStrictRegex:this._weekdaysMinRegex)},kn.isPM=function(e){return"p"===(e+"").toLowerCase().charAt(0)},kn.meridiem=function(e,t,n){return e>11?n?"pm":"PM":n?"am":"AM"},ae("en",{dayOfMonthOrdinalParse:/\d{1,2}(th|st|nd|rd)/,ordinal:function(e){var t=e%10;return e+(1===g(e%100/10)?"th":1===t?"st":2===t?"nd":3===t?"rd":"th")}}),e.lang=v("moment.lang is deprecated. Use moment.locale instead.",ae),e.langData=v("moment.langData is deprecated. Use moment.localeData instead.",ue);var Yn=Math.abs,On=$e("ms"),Tn=$e("s"),xn=$e("m"),bn=$e("h"),Pn=$e("d"),Wn=$e("w"),Hn=$e("M"),Rn=$e("y"),Cn=qe("milliseconds"),Fn=qe("seconds"),Un=qe("minutes"),Ln=qe("hours"),Nn=qe("days"),Gn=qe("months"),Vn=qe("years"),En=Math.round,In={ss:44,s:45,m:45,h:22,d:26,M:11},An=Math.abs,jn=ve.prototype;return jn.isValid=function(){return this._isValid},jn.abs=function(){var e=this._data;return this._milliseconds=Yn(this._milliseconds),this._days=Yn(this._days),this._months=Yn(this._months),e.milliseconds=Yn(e.milliseconds),e.seconds=Yn(e.seconds),e.minutes=Yn(e.minutes),e.hours=Yn(e.hours),e.months=Yn(e.months),e.years=Yn(e.years),this},jn.add=function(e,t){return Ae(this,e,t,1)},jn.subtract=function(e,t){return Ae(this,e,t,-1)},jn.as=function(e){if(!this.isValid())return NaN;var t,n,s=this._milliseconds;if("month"===(e=O(e))||"year"===e)return t=this._days+s/864e5,n=this._months+Ze(t),"month"===e?n:n/12;switch(t=this._days+Math.round(ze(this._months)),e){case"week":return t/7+s/6048e5;case"day":return t+s/864e5;case"hour":return 24*t+s/36e5;case"minute":return 1440*t+s/6e4;case"second":return 86400*t+s/1e3;case"millisecond":return Math.floor(864e5*t)+s;default:throw new Error("Unknown unit "+e)}},jn.asMilliseconds=On,jn.asSeconds=Tn,jn.asMinutes=xn,jn.asHours=bn,jn.asDays=Pn,jn.asWeeks=Wn,jn.asMonths=Hn,jn.asYears=Rn,jn.valueOf=function(){return this.isValid()?this._milliseconds+864e5*this._days+this._months%12*2592e6+31536e6*g(this._months/12):NaN},jn._bubble=function(){var e,t,n,s,i,r=this._milliseconds,a=this._days,o=this._months,u=this._data;return r>=0&&a>=0&&o>=0||r<=0&&a<=0&&o<=0||(r+=864e5*je(ze(o)+a),a=0,o=0),u.milliseconds=r%1e3,e=y(r/1e3),u.seconds=e%60,t=y(e/60),u.minutes=t%60,n=y(t/60),u.hours=n%24,a+=y(n/24),i=y(Ze(a)),o+=i,a-=je(ze(i)),s=y(o/12),o%=12,u.days=a,u.months=o,u.years=s,this},jn.clone=function(){return xe(this)},jn.get=function(e){return e=O(e),this.isValid()?this[e+"s"]():NaN},jn.milliseconds=Cn,jn.seconds=Fn,jn.minutes=Un,jn.hours=Ln,jn.days=Nn,jn.weeks=function(){return y(this.days()/7)},jn.months=Gn,jn.years=Vn,jn.humanize=function(e){if(!this.isValid())return this.localeData().invalidDate();var t=this.localeData(),n=function(e,t,n){var s=xe(e).abs(),i=En(s.as("s")),r=En(s.as("m")),a=En(s.as("h")),o=En(s.as("d")),u=En(s.as("M")),l=En(s.as("y")),d=i<=In.ss&&["s",i]||i0,d[4]=n,function(e,t,n,s,i){return i.relativeTime(t||1,!!n,e,s)}.apply(null,d)}(this,!e,t);return e&&(n=t.pastFuture(+this,n)),t.postformat(n)},jn.toISOString=Be,jn.toString=Be,jn.toJSON=Be,jn.locale=Ce,jn.localeData=Fe,jn.toIsoString=v("toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)",Be),jn.lang=gn,P("X",0,0,"unix"),P("x",0,0,"valueOf"),C("x",Mt),C("X",/[+-]?\d+(\.\d{1,3})?/),L("X",function(e,t,n){n._d=new Date(1e3*parseFloat(e,10))}),L("x",function(e,t,n){n._d=new Date(g(e))}),e.version="2.20.1",function(e){Qe=e}(pe),e.fn=Dn,e.min=function(){return we("isBefore",[].slice.call(arguments,0))},e.max=function(){return we("isAfter",[].slice.call(arguments,0))},e.now=function(){return Date.now?Date.now():+new Date},e.utc=l,e.unix=function(e){return pe(1e3*e)},e.months=function(e,t){return Ee(e,t,"months")},e.isDate=r,e.locale=ae,e.invalid=c,e.duration=xe,e.isMoment=_,e.weekdays=function(e,t,n){return Ie(e,t,n,"weekdays")},e.parseZone=function(){return pe.apply(null,arguments).parseZone()},e.localeData=ue,e.isDuration=Me,e.monthsShort=function(e,t){return Ee(e,t,"monthsShort")},e.weekdaysMin=function(e,t,n){return Ie(e,t,n,"weekdaysMin")},e.defineLocale=oe,e.updateLocale=function(e,t){if(null!=t){var n,s,i=Qt;null!=(s=re(e))&&(i=s._config),(n=new k(t=D(i,t))).parentLocale=Xt[e],Xt[e]=n,ae(e)}else null!=Xt[e]&&(null!=Xt[e].parentLocale?Xt[e]=Xt[e].parentLocale:null!=Xt[e]&&delete Xt[e]);return Xt[e]},e.locales=function(){return nt(Xt)},e.weekdaysShort=function(e,t,n){return Ie(e,t,n,"weekdaysShort")},e.normalizeUnits=O,e.relativeTimeRounding=function(e){return void 0===e?En:"function"==typeof e&&(En=e,!0)},e.relativeTimeThreshold=function(e,t){return void 0!==In[e]&&(void 0===t?In[e]:(In[e]=t,"s"===e&&(In.ss=t-1),!0))},e.calendarFormat=function(e,t){var n=e.diff(t,"days",!0);return n<-6?"sameElse":n<-1?"lastWeek":n<0?"lastDay":n<1?"sameDay":n<2?"nextDay":n<7?"nextWeek":"sameElse"},e.prototype=Dn,e.HTML5_FMT={DATETIME_LOCAL:"YYYY-MM-DDTHH:mm",DATETIME_LOCAL_SECONDS:"YYYY-MM-DDTHH:mm:ss",DATETIME_LOCAL_MS:"YYYY-MM-DDTHH:mm:ss.SSS",DATE:"YYYY-MM-DD",TIME:"HH:mm",TIME_SECONDS:"HH:mm:ss",TIME_MS:"HH:mm:ss.SSS",WEEK:"YYYY-[W]WW",MONTH:"YYYY-MM"},e}); \ No newline at end of file diff --git a/src/Entity/CustomerVehicle.php b/src/Entity/CustomerVehicle.php index 60967653..fe1ab9bd 100644 --- a/src/Entity/CustomerVehicle.php +++ b/src/Entity/CustomerVehicle.php @@ -80,15 +80,14 @@ class CustomerVehicle // warranty code // TODO: figure out how to check expiration /** - * @ORM\Column(type="string", length=20) + * @ORM\Column(type="string", length=20, nullable=true) * @Assert\NotBlank() */ protected $warranty_code; // date that battery warranty expires /** - * @ORM\Column(type="date") - * @Assert\NotBlank() + * @ORM\Column(type="date", nullable=true) */ protected $warranty_expiration; @@ -96,7 +95,6 @@ class CustomerVehicle /** * @ORM\ManyToOne(targetEntity="Battery", inversedBy="cust_vehicles") * @ORM\JoinColumn(name="battery_id", referencedColumnName="id") - * @Assert\NotBlank() */ protected $curr_battery; diff --git a/templates/customer/form.html.twig b/templates/customer/form.html.twig index f458f678..020bf319 100644 --- a/templates/customer/form.html.twig +++ b/templates/customer/form.html.twig @@ -13,7 +13,7 @@
-
+
@@ -51,54 +51,52 @@ -
+
-
+
-
+
-
-
- - - Use the format 63xxxxxxxxxx +
+
+ + + Use the format 63xxxxxxxxxx
-
-
- +
+
+
-
-
- - - - -
-
-
- +
+
- +
+
+
+
+
+
+
@@ -186,19 +184,197 @@ } // datetimepicker - $(".datetimepicker").datetimepicker({ - format: "dd MM yyyy - HH:ii P", + $(".date").datetimepicker({ + format: "dd M yyyy - HH:ii P", showMeridian: true, todayHighlight: true, autoclose: true, - pickerPosition: 'bottom-left' + pickerPosition: 'top-left', + bootcssVer: 3, + todayBtn: true }); - // data tables - var options = { + // input mask + $("#mobile-number").inputmask("mask", { + mask: "639999999999", + placeholder: "" + }); + + // initialize arrays + var numberRows = []; + var numberIds = []; + var mfgVehicles = []; + var vehicleRows = []; + var vehicleIds = []; + + {% for number in obj.getMobileNumbers() %} + nrow = { + id: "{{ number.getID() }}", + date_registered: "{{ number.getDateRegistered() }}", + date_confirmed: "{{ number.getDateConfirmed() }}" + }; + + numberRows.push(nrow); + numberIds.push("{{ number.getID() }}"); + {% endfor %} + + {% for cv in obj.getVehicles() %} + {% set vehicle = cv.getVehicle() %} + {% set battery = cv.getCurrentBattery() %} + + vrow = { + id: "{{ cv.getID() }}", + mfg_name: "{{ vehicle.getManufacturer().getName() }}", + make: "{{ vehicle.getMake() }}", + model_year: "{{ cv.getModelYear() }}", + color: "{{ cv.getColor() }}", + status_condition: "{{ cv.getStatusCondition() }}", + fuel_type: "{{ cv.getFuelType() }}", + warranty_code: "{{ cv.getWarrantyCode() }}", + warranty_expiration: "{{ cv.getWarrantyExpiration() ? cv.getWarrantyExpiration()|date('d M Y') }}", + curr_battery_id: "{{ battery.getID() }}", + curr_battery_prod_code: "{{ battery.getProductCode() }}", + curr_battery_manufacturer: "{{ battery.getManufacturer().getName() }}", + flag_motolite_battery: {{ cv.hasMotoliteBattery() }}, + flag_active: {{ cv.isActive() }} + }; + + vehicleRows.push(vrow); + vehicleIds.push("{{ cv.getID() }}"); + {% endfor %} + + vrow = { + id: "123", + mfg_name: "Mitsubishi", + make: "Lancer", + model_year: "1996", + color: "Red", + status_condition: "New", + fuel_type: "Gas", + warranty_code: "12345", + warranty_expiration: "15 Jan 2018", + curr_battery_id: "11", + curr_battery_prod_code: "TESTBATT", + curr_battery_manufacturer: "Motolite", + flag_motolite_battery: 1, + flag_active: 1 + }; + + vehicleRows.push(vrow); + + // add a mobile number to the table + $("#btn-add-mobile-number").click(function() { + var id = $("#mobile-number").val(); + var dateRegistered = moment().format("DD MMM YYYY - hh:mm A"); + var dateConfirmed = $("#date-confirmed").val(); + var index = $("#vehicle").find(":selected").data('index'); + + if (!id) { + swal({ + title: 'Whoops', + text: 'You did not specify a mobile number.', + type: 'warning' + }); + + return true; + } else if (id.toString().length != 12) { + swal({ + title: 'Whoops', + text: 'Invalid mobile number specified.', + type: 'warning' + }); + + return true; + } else if (numberIds.indexOf(id) !== -1) { + swal({ + title: 'Whoops', + text: 'This mobile number is already on the list.', + type: 'warning' + }); + + return true; + } + + // add number to arrays + numberIds.push(id); + numberRows.push({ + id: id, + date_registered: dateRegistered, + date_confirmed: dateConfirmed + }); + + // clear input fields + $("#mobile-number, #date-confirmed").val(""); + + // refresh the data table + numberTable.originalDataSet = numberRows; + numberTable.reload(); + }); + + // add a vehicle to the table + $("#btn-add-vehicle").click(function() { + var id = $("#vehicle").val(); + var index = $("#vehicle").find(":selected").data('index'); + + if (vehicleIds.indexOf(id) !== -1) { + swal({ + title: 'Whoops', + text: 'This vehicle is already on the list.', + type: 'warning' + }); + + return true; + } + + // add vehicle to arrays + vehicleIds.push(id); + vehicleRows.push(mfgVehicles[index]); + + // refresh the data table + vehicleTable.originalDataSet = vehicleRows; + vehicleTable.reload(); + }); + + // remove mobile number from table + $(document).on('click', '.btn-delete', function(e) { + var btn = $(this); + var id = $(this).data('id'); + var table = $(this).closest('table'); + var rowArray; + var rowIds; + var dt; + + if (table.parent().prop('id') == 'data-mobile-numbers') { + rowArray = numberRows; + rowIds = numberIds; + dt = numberTable; + } else { + rowArray = vehicleRows; + rowIds = vehicleIds; + dt = vehicleTable; + } + + $.each(rowArray, function(index, row) { + if (row.id == id) { + rowArray.splice(index, 1); + return false; + } + }); + + // remove from ids + rowIds.splice(rowIds.indexOf(id), 1); + + // reload table + dt.row(btn.parents('tr')).remove(); + dt.originalDataSet = rowArray; + dt.reload(); + }); + + // mobile numbers data table + var numberOptions = { data: { type: 'local', - source: vehicleRows, + source: numberRows, saveState: { cookie: false, webstorage: false @@ -210,23 +386,15 @@ columns: [ { field: 'id', - title: 'ID', - width: 30 + title: 'Mobile Number' }, { - field: 'mfg_name', - title: 'Manufacturer' + field: 'date_registered', + title: 'Date Registered' }, { - field: 'make', - title: 'Make' - }, - { - field: 'model_year_from', - title: 'Year', - template: function (data) { - return data.model_year_from + ' - ' + data.model_year_to; - } + field: 'date_confirmed', + title: 'Date Confirmed' }, { field: 'Actions', @@ -242,7 +410,114 @@ pagination: false }; - var table = $("#data-vehicles").mDatatable(options); + var numberTable = $("#data-mobile-numbers").mDatatable(numberOptions); + + // vehicles data table + var vehicleOptions = { + data: { + type: 'local', + source: vehicleRows, + saveState: { + cookie: false, + webstorage: false + } + }, + layout: { + scroll: true + }, + columns: [ + { + field: 'mfg_name', + title: 'Manufacturer' + }, + { + field: 'make', + title: 'Make' + }, + { + field: 'model_year', + title: 'Year', + template: function (row, index, datatable) { + return '' + } + }, + { + field: 'color', + title: 'Color', + template: function (row, index, datatable) { + return '' + } + }, + { + field: 'status_condition', + title: 'Status', + width: 50 + }, + { + field: 'fuel_type', + title: 'Fuel Type' + }, + { + field: 'warranty_code', + title: 'Warranty Code', + template: function (row, index, datatable) { + return '' + } + }, + { + field: 'warranty_expiration', + title: 'Warranty Expiration', + width: 150, + template: function (row, index, datatable) { + return '' + } + }, + { + field: 'curr_battery', + title: 'Current Battery', + template: function (row, index, datatable) { + return row.curr_battery_manufacturer + ' ' + row.curr_battery_prod_code; + } + }, + { + field: 'flag_motolite_battery', + title: 'Using Motolite battery?', + template: function (row, index, datatable) { + html = ''; + return html; + } + }, + { + field: 'flag_active', + title: 'Is the vehicle active?', + template: function (row, index, datatable) { + html = ''; + return html; + } + }, + { + field: 'Actions', + width: 70, + title: 'Actions', + sortable: false, + overflow: 'visible', + template: function (row, index, datatable) { + return ''; + }, + } + ], + pagination: false + }; + + var vehicleTable = $("#data-vehicles").mDatatable(vehicleOptions); }); -{% endblock %} +{% endblock %} \ No newline at end of file