UNPKG

jquery-grid

Version:

jQuery Grid by Gijgo.com is a plug-in for the jQuery Javascript library. It is a very fast and extandable datagrid, and will add advanced interaction controls to any HTML table. This plugin has build-in integration with Bootstrap and Material Design. Free

1,307 lines (1,119 loc) 156 kB
/* * Gijgo Grid v1.9.13 * http://gijgo.com/grid * * Copyright 2014, 2019 gijgo.com * Released under the MIT license */ /* global window alert jQuery gj */ /** */ gj.grid = { plugins: {}, messages: {} }; gj.grid.config = { base: { /** The data source for the grid. */ dataSource: undefined, /** An array that holds the configurations of each column from the grid. */ columns: [], /** Auto generate column for each field in the datasource when set to true. */ autoGenerateColumns: false, /** An object that holds the default configuration settings of each column from the grid. */ defaultColumnSettings: { /** If set to true the column will not be displayed in the grid. By default all columns are displayed. */ hidden: false, /** The width of the column. Numeric values are treated as pixels. * If the width is undefined the width of the column is not set and depends on the with of the table(grid). */ width: undefined, /** Indicates if the column is sortable. * If set to true the user can click the column header and sort the grid by the column source field. */ sortable: false, /** Indicates the type of the column. */ type: 'text', /** The caption that is going to be displayed in the header of the grid. */ title: undefined, /** The field name to which the column is bound. * If the column.title is not defined this value is used as column.title. */ field: undefined, /** This setting control the alignment of the text in the cell. */ align: undefined, /** The name(s) of css class(es) that are going to be applied to all cells inside that column, except the header cell. */ cssClass: undefined, /** The name(s) of css class(es) that are going to be applied to the header cell of that column. */ headerCssClass: undefined, /** The text for the cell tooltip. */ tooltip: undefined, /** Css class for icon that is going to be in use for the cell. * This setting can be in use only with combination of type icon. */ icon: undefined, /** Configuration object with event names as keys and functions as values that are going to be bind to each cell from the column. * Each function is going to receive event information as a parameter with info in the 'data' field for id, field name and record data. */ events: undefined, /** Format the date when the type of the column is date. */ format: 'mm/dd/yyyy', /** Number of decimal digits after the decimal point. */ decimalDigits: undefined, /** Template for the content in the column. * Use curly brackets '{}' to wrap the names of data source columns from server response. */ tmpl: undefined, /** If set to true stop event propagation when event occur. */ stopPropagation: false, /** A renderer is an 'interceptor' function which can be used to transform data (value, appearance, etc.) before it is rendered. */ renderer: undefined, /** Function which can be used to customize filtering with local data (javascript sourced data). */ filter: undefined }, mapping: { /** The name of the object in the server response, that contains array with records, that needs to be display in the grid. */ dataField: 'records', /** The name of the object in the server response, that contains the number of all records on the server. */ totalRecordsField: 'total' }, params: {}, paramNames: { /** The name of the parameter that is going to send the name of the column for sorting. * The "sortable" setting for at least one column should be enabled in order this parameter to be in use. */ sortBy: 'sortBy', /** The name of the parameter that is going to send the direction for sorting. * The "sortable" setting for at least one column should be enabled in order this parameter to be in use. */ direction: 'direction' }, /** The name of the UI library that is going to be in use. Currently we support Bootstrap 3, Bootstrap 4 and Material Design. */ uiLibrary: 'materialdesign', /** The name of the icons library that is going to be in use. Currently we support Material Icons, Font Awesome and Glyphicons. */ iconsLibrary: 'materialicons', /** The type of the row selection.<br/> * If the type is set to multiple the user will be able to select more then one row from the grid. */ selectionType: 'single', /** The type of the row selection mechanism. */ selectionMethod: 'basic', /** When this setting is enabled the content of the grid will be loaded automatically after the creation of the grid. */ autoLoad: true, /** The text that is going to be displayed if the grid is empty. */ notFoundText: undefined, /** Width of the grid. */ width: undefined, /** Minimum width of the grid. */ minWidth: undefined, /** This configuration option manage the behaviour of the header row height. * Auto scale if set to to 'autogrow'. All body rows are with the same height if set to 'fixed'. */ headerRowHeight: 'fixed', /** This configuration option manage the behaviour of the body row height. * Auto scale if set to to 'autogrow'. All body rows are with the same height if set to 'fixed'. */ bodyRowHeight: 'autogrow', /** The size of the font in the grid. */ fontSize: undefined, /** Name of column that contains the record id. */ primaryKey: undefined, /** The language that needs to be in use. */ locale: 'en-us', defaultIconColumnWidth: 70, defaultCheckBoxColumnWidth: 70, style: { wrapper: 'gj-grid-wrapper', table: 'gj-grid gj-grid-md', loadingCover: 'gj-grid-loading-cover', loadingText: 'gj-grid-loading-text', header: { cell: undefined, sortable: 'gj-cursor-pointer gj-unselectable' }, content: { rowSelected: 'gj-grid-md-select' } }, icons: { asc: '▲', desc: '▼' } }, bootstrap: { style: { wrapper: 'gj-grid-wrapper', table: 'gj-grid gj-grid-bootstrap gj-grid-bootstrap-3 table table-bordered table-hover', content: { rowSelected: 'active' } }, iconsLibrary: 'glyphicons', defaultIconColumnWidth: 34, defaultCheckBoxColumnWidth: 36 }, bootstrap4: { style: { wrapper: 'gj-grid-wrapper', table: 'gj-grid gj-grid-bootstrap gj-grid-bootstrap-4 table table-bordered table-hover', content: { rowSelected: 'active' } }, defaultIconColumnWidth: 42, defaultCheckBoxColumnWidth: 44 }, materialicons: { icons: { asc: '<i class="gj-icon arrow-upward" />', desc: '<i class="gj-icon arrow-downward" />' } }, fontawesome: { icons: { asc: '<i class="fa fa-sort-amount-asc" aria-hidden="true"></i>', desc: '<i class="fa fa-sort-amount-desc" aria-hidden="true"></i>' } }, glyphicons: { icons: { asc: '<span class="glyphicon glyphicon-sort-by-alphabet" />', desc: '<span class="glyphicon glyphicon-sort-by-alphabet-alt" />' } } }; /** */ gj.grid.events = { /** * Event fires before addition of an empty row to the grid. */ beforeEmptyRowInsert: function ($grid, $row) { return $grid.triggerHandler('beforeEmptyRowInsert', [$row]); }, /** * Event fired before data binding takes place. * */ dataBinding: function ($grid, records) { return $grid.triggerHandler('dataBinding', [records]); }, /** * Event fires after the loading of the data in the grid. * */ dataBound: function ($grid, records, totalRecords) { return $grid.triggerHandler('dataBound', [records, totalRecords]); }, /** * Event fires after insert of a row in the grid during the loading of the data. */ rowDataBound: function ($grid, $row, id, record) { return $grid.triggerHandler('rowDataBound', [$row, id, record]); }, /** * Event fires after insert of a cell in the grid during the loading of the data * */ cellDataBound: function ($grid, $displayEl, id, column, record) { return $grid.triggerHandler('cellDataBound', [$displayEl, id, column, record]); }, /** * Event fires on selection of row * */ rowSelect: function ($grid, $row, id, record) { return $grid.triggerHandler('rowSelect', [$row, id, record]); }, /** * Event fires on un selection of row * */ rowUnselect: function ($grid, $row, id, record) { return $grid.triggerHandler('rowUnselect', [$row, id, record]); }, /** * Event fires before deletion of row in the grid. */ rowRemoving: function ($grid, $row, id, record) { return $grid.triggerHandler('rowRemoving', [$row, id, record]); }, /** * Event fires when the grid.destroy method is called. * */ destroying: function ($grid) { return $grid.triggerHandler('destroying'); }, /** * Event fires when column is hidding * */ columnHide: function ($grid, column) { return $grid.triggerHandler('columnHide', [column]); }, /** * Event fires when column is showing * */ columnShow: function ($grid, column) { return $grid.triggerHandler('columnShow', [column]); }, /** * Event fires when grid is initialized. * */ initialized: function ($grid) { return $grid.triggerHandler('initialized'); }, /** * Event fires when the grid data is filtered. * */ dataFiltered: function ($grid, records) { return $grid.triggerHandler('dataFiltered', [records]); } }; /*global gj $*/ gj.grid.methods = { init: function (jsConfig) { gj.widget.prototype.init.call(this, jsConfig, 'grid'); gj.grid.methods.initialize(this); if (this.data('autoLoad')) { this.reload(); } return this; }, getConfig: function (jsConfig, type) { var config = gj.widget.prototype.getConfig.call(this, jsConfig, type); gj.grid.methods.setDefaultColumnConfig(config.columns, config.defaultColumnSettings); return config; }, setDefaultColumnConfig: function (columns, defaultColumnSettings) { var column, i; if (columns && columns.length) { for (i = 0; i < columns.length; i++) { column = $.extend(true, {}, defaultColumnSettings); $.extend(true, column, columns[i]); columns[i] = column; } } }, getHTMLConfig: function () { var result = gj.widget.prototype.getHTMLConfig.call(this); result.columns = []; this.find('thead > tr > th').each(function () { var $el = $(this), title = $el.text(), config = gj.widget.prototype.getHTMLConfig.call($el); config.title = title; if (!config.field) { config.field = title; } if (config.events) { config.events = gj.grid.methods.eventsParser(config.events); } result.columns.push(config); }); return result; }, eventsParser: function (events) { var result = {}, list, i, key, func, position; list = events.split(','); for (i = 0; i < list.length; i++) { position = list[i].indexOf(':'); if (position > 0) { key = $.trim(list[i].substr(0, position)); func = $.trim(list[i].substr(position + 1, list[i].length)); result[key] = eval('window.' + func); //window[func]; //TODO: eveluate functions from string } } return result; }, initialize: function ($grid) { var data = $grid.data(), $wrapper = $grid.parent('div[data-role="wrapper"]'); gj.grid.methods.localization(data); if ($wrapper.length === 0) { $wrapper = $('<div data-role="wrapper" />').addClass(data.style.wrapper); //The css class needs to be added before the wrapping, otherwise doesn't work. $grid.wrap($wrapper); } else { $wrapper.addClass(data.style.wrapper); } if (data.width) { $grid.parent().css('width', data.width); } if (data.minWidth) { $grid.css('min-width', data.minWidth); } if (data.fontSize) { $grid.css('font-size', data.fontSize); } if (data.headerRowHeight === 'autogrow') { $grid.addClass('autogrow-header-row'); } if (data.bodyRowHeight === 'fixed') { $grid.addClass('fixed-body-rows'); } $grid.addClass(data.style.table); if ('checkbox' === data.selectionMethod) { data.columns.splice(gj.grid.methods.getColumnPositionNotInRole($grid), 0, { title: '', width: data.defaultCheckBoxColumnWidth, align: 'center', type: 'checkbox', role: 'selectRow', events: { click: function (e) { gj.grid.methods.setSelected($grid, e.data.id, $(this).closest('tr')); } }, headerCssClass: 'gj-grid-select-all', stopPropagation: true }); } if ($grid.children('tbody').length === 0) { $grid.append($('<tbody/>')); } gj.grid.methods.renderHeader($grid); gj.grid.methods.appendEmptyRow($grid, '&nbsp;'); gj.grid.events.initialized($grid); }, localization: function (data) { if (!data.notFoundText) { data.notFoundText = gj.grid.messages[data.locale].NoRecordsFound; } }, renderHeader: function ($grid) { var data, columns, style, $thead, $row, $cell, $title, i, $checkAllBoxes; data = $grid.data(); columns = data.columns; style = data.style.header; $thead = $grid.children('thead'); if ($thead.length === 0) { $thead = $('<thead />'); $grid.prepend($thead); } $row = $('<tr data-role="caption" />'); for (i = 0; i < columns.length; i += 1) { $cell = $('<th data-field="' + (columns[i].field || '') + '" />'); if (columns[i].width) { $cell.attr('width', columns[i].width); } else if (columns[i].type === 'checkbox') { $cell.attr('width', data.defaultIconColumnWidth); } $cell.addClass(style.cell); if (columns[i].headerCssClass) { $cell.addClass(columns[i].headerCssClass); } $cell.css('text-align', columns[i].align || 'left'); if ('checkbox' === data.selectionMethod && 'multiple' === data.selectionType && 'checkbox' === columns[i].type && 'selectRow' === columns[i].role) { $checkAllBoxes = $cell.find('input[data-role="selectAll"]'); if ($checkAllBoxes.length === 0) { $checkAllBoxes = $('<input type="checkbox" data-role="selectAll" />'); $cell.append($checkAllBoxes); $checkAllBoxes.checkbox({ uiLibrary: data.uiLibrary }); } $checkAllBoxes.off('click').on('click', function () { if (this.checked) { $grid.selectAll(); } else { $grid.unSelectAll(); } }); } else { $title = $('<div data-role="title"/>').html(typeof (columns[i].title) === 'undefined' ? columns[i].field : columns[i].title); $cell.append($title); if (columns[i].sortable) { $title.addClass(style.sortable); $title.on('click', gj.grid.methods.createSortHandler($grid, columns[i])); } } if (columns[i].hidden) { $cell.hide(); } $row.append($cell); } $thead.empty().append($row); }, createSortHandler: function ($grid, column) { return function () { var data, params = {}; if ($grid.count() > 0) { data = $grid.data(); params[data.paramNames.sortBy] = column.field; column.direction = (column.direction === 'asc' ? 'desc' : 'asc'); params[data.paramNames.direction] = column.direction; $grid.reload(params); } }; }, updateHeader: function ($grid) { var $sortIcon, $cellTitle, data = $grid.data(), sortBy = data.params[data.paramNames.sortBy], direction = data.params[data.paramNames.direction]; $grid.find('thead tr th [data-role="sorticon"]').remove(); if (sortBy) { position = gj.grid.methods.getColumnPosition($grid.data('columns'), sortBy); if (position > -1) { $cellTitle = $grid.find('thead tr th:eq(' + position + ') div[data-role="title"]'); $sortIcon = $('<div data-role="sorticon" class="gj-unselectable" />').append(('desc' === direction) ? data.icons.desc : data.icons.asc); $cellTitle.after($sortIcon); } } }, useHtmlDataSource: function ($grid, data) { var dataSource = [], i, j, $cells, record, $rows = $grid.find('tbody tr[data-role != "empty"]'); for (i = 0; i < $rows.length; i++) { $cells = $($rows[i]).find('td'); record = {}; for (j = 0; j < $cells.length; j++) { record[data.columns[j].field] = $($cells[j]).html(); } dataSource.push(record); } data.dataSource = dataSource; }, startLoading: function ($grid) { var $tbody, $cover, $loading, width, height, top, data; gj.grid.methods.stopLoading($grid); data = $grid.data(); if (0 === $grid.outerHeight()) { return; } $tbody = $grid.children('tbody'); width = $tbody.outerWidth(false); height = $tbody.outerHeight(false); top = Math.abs($grid.parent().offset().top - $tbody.offset().top); $cover = $('<div data-role="loading-cover" />').addClass(data.style.loadingCover).css({ width: width, height: height, top: top }); $loading = $('<div data-role="loading-text">' + gj.grid.messages[data.locale].Loading + '</div>').addClass(data.style.loadingText); $loading.insertAfter($grid); $cover.insertAfter($grid); $loading.css({ top: top + (height / 2) - ($loading.outerHeight(false) / 2), left: (width / 2) - ($loading.outerWidth(false) / 2) }); }, stopLoading: function ($grid) { $grid.parent().find('div[data-role="loading-cover"]').remove(); $grid.parent().find('div[data-role="loading-text"]').remove(); }, appendEmptyRow: function ($grid, caption) { var data, $row, $cell, $wrapper; data = $grid.data(); $row = $('<tr data-role="empty"/>'); $cell = $('<td/>').css({ width: '100%', 'text-align': 'center' }); $cell.attr('colspan', gj.grid.methods.countVisibleColumns($grid)); $wrapper = $('<div />').html(caption || data.notFoundText); $cell.append($wrapper); $row.append($cell); gj.grid.events.beforeEmptyRowInsert($grid, $row); $grid.append($row); }, autoGenerateColumns: function ($grid, records) { var names, value, type, i, data = $grid.data(); data.columns = []; if (records.length > 0) { names = Object.getOwnPropertyNames(records[0]); for (i = 0; i < names.length; i++) { value = records[0][names[i]]; type = 'text'; if (value) { if (typeof value === 'number') { type = 'number'; } else if (value.indexOf('/Date(') > -1) { type = 'date'; } } data.columns.push({ field: names[i], type: type }); } gj.grid.methods.setDefaultColumnConfig(data.columns, data.defaultColumnSettings); } gj.grid.methods.renderHeader($grid); }, loadData: function ($grid) { var data, records, i, recLen, rowCount, $tbody, $rows, $row; data = $grid.data(); records = $grid.getAll(); gj.grid.events.dataBinding($grid, records); recLen = records.length; gj.grid.methods.stopLoading($grid); if (data.autoGenerateColumns) { gj.grid.methods.autoGenerateColumns($grid, records); } $tbody = $grid.children('tbody'); if ('checkbox' === data.selectionMethod && 'multiple' === data.selectionType) { $grid.find('thead input[data-role="selectAll"]').prop('checked', false); } $tbody.children('tr').not('[data-role="row"]').remove(); if (0 === recLen) { $tbody.empty(); gj.grid.methods.appendEmptyRow($grid); } $rows = $tbody.children('tr'); rowCount = $rows.length; for (i = 0; i < rowCount; i++) { if (i < recLen) { $row = $rows.eq(i); gj.grid.methods.renderRow($grid, $row, records[i], i); } else { $tbody.find('tr[data-role="row"]:gt(' + (i - 1) + ')').remove(); break; } } for (i = rowCount; i < recLen; i++) { gj.grid.methods.renderRow($grid, null, records[i], i); } gj.grid.events.dataBound($grid, records, data.totalRecords); }, getId: function (record, primaryKey, position) { return (primaryKey && record[primaryKey]) ? record[primaryKey] : position; }, renderRow: function ($grid, $row, record, position) { var id, $cell, i, data, mode; data = $grid.data(); if (!$row || $row.length === 0) { mode = 'create'; $row = $('<tr data-role="row"/>'); $grid.children('tbody').append($row); } else { mode = 'update'; $row.removeClass(data.style.content.rowSelected).removeAttr('data-selected').off('click'); } id = gj.grid.methods.getId(record, data.primaryKey, (position + 1)); $row.attr('data-position', position + 1); if (data.selectionMethod !== 'checkbox') { $row.on('click', gj.grid.methods.createRowClickHandler($grid, id)); } for (i = 0; i < data.columns.length; i++) { if (mode === 'update') { $cell = $row.find('td:eq(' + i + ')'); gj.grid.methods.renderCell($grid, $cell, data.columns[i], record, id); } else { $cell = gj.grid.methods.renderCell($grid, null, data.columns[i], record, id); $row.append($cell); } } gj.grid.events.rowDataBound($grid, $row, id, record); }, renderCell: function ($grid, $cell, column, record, id, mode) { var $displayEl, key; if (!$cell || $cell.length === 0) { $cell = $('<td/>'); $displayEl = $('<div data-role="display" />'); column.align && $cell.css('text-align', column.align); column.cssClass && $cell.addClass(column.cssClass); $cell.append($displayEl); mode = 'create'; } else { $displayEl = $cell.find('div[data-role="display"]'); mode = 'update'; } gj.grid.methods.renderDisplayElement($grid, $displayEl, column, record, id, mode); //remove all event handlers if ('update' === mode) { $cell.off(); $displayEl.off(); } if (column.events) { for (key in column.events) { if (column.events.hasOwnProperty(key)) { $cell.on(key, { id: id, field: column.field, record: record }, gj.grid.methods.createCellEventHandler(column, column.events[key])); } } } if (column.hidden) { $cell.hide(); } gj.grid.events.cellDataBound($grid, $displayEl, id, column, record); return $cell; }, createCellEventHandler: function (column, func) { return function (e) { if (column.stopPropagation) { e.stopPropagation(); } func.call(this, e); }; }, renderDisplayElement: function ($grid, $displayEl, column, record, id, mode) { var text, $checkbox; if ('checkbox' === column.type && gj.checkbox) { if ('create' === mode) { $checkbox = $('<input type="checkbox" />').val(id).prop('checked', (record[column.field] ? true : false)); column.role && $checkbox.attr('data-role', column.role); $displayEl.append($checkbox); $checkbox.checkbox({ uiLibrary: $grid.data('uiLibrary') }); if (column.role === 'selectRow') { $checkbox.on('click', function () { return false; }); } else { $checkbox.prop('disabled', true); } } else { $displayEl.find('input[type="checkbox"]').val(id).prop('checked', (record[column.field] ? true : false)); } } else if ('icon' === column.type) { if ('create' === mode) { $displayEl.append($('<span/>').addClass(column.icon).css({ cursor: 'pointer' })); $grid.data().uiLibrary === 'bootstrap' && $displayEl.children('span').addClass('glyphicon'); column.stopPropagation = true; } } else if (column.tmpl) { text = column.tmpl; column.tmpl.replace(/\{(.+?)\}/g, function ($0, $1) { text = text.replace($0, gj.grid.methods.formatText(record[$1], column)); }); $displayEl.html(text); } else if (column.renderer && typeof (column.renderer) === 'function') { text = column.renderer(record[column.field], record, $displayEl.parent(), $displayEl, id, $grid); if (text) { $displayEl.html(text); } } else { record[column.field] = gj.grid.methods.formatText(record[column.field], column); if (!column.tooltip && record[column.field]) { $displayEl.attr('title', record[column.field]); } $displayEl.html(record[column.field]); } if (column.tooltip && 'create' === mode) { $displayEl.attr('title', column.tooltip); } }, formatText: function (text, column) { if (text && ['date', 'time', 'datetime'].indexOf(column.type) > -1) { text = gj.core.formatDate(gj.core.parseDate(text, column.format), column.format); } else { text = (typeof (text) === 'undefined' || text === null) ? '' : text.toString(); } if (column.decimalDigits && text) { text = parseFloat(text).toFixed(column.decimalDigits); } return text; }, setRecordsData: function ($grid, response) { var records = [], totalRecords = 0, data = $grid.data(); if ($.isArray(response)) { records = response; totalRecords = response.length; } else if (data && data.mapping && $.isArray(response[data.mapping.dataField])) { records = response[data.mapping.dataField]; totalRecords = response[data.mapping.totalRecordsField]; if (!totalRecords || isNaN(totalRecords)) { totalRecords = 0; } } $grid.data('records', records); $grid.data('totalRecords', totalRecords); return records; }, createRowClickHandler: function ($grid, id) { return function () { gj.grid.methods.setSelected($grid, id, $(this)); }; }, selectRow: function ($grid, data, $row, id) { var $checkbox; $row.addClass(data.style.content.rowSelected); $row.attr('data-selected', 'true'); if ('checkbox' === data.selectionMethod) { $checkbox = $row.find('input[type="checkbox"][data-role="selectRow"]'); $checkbox.length && !$checkbox.prop('checked') && $checkbox.prop('checked', true); if ('multiple' === data.selectionType && $grid.getSelections().length === $grid.count(false)) { $grid.find('thead input[data-role="selectAll"]').prop('checked', true); } } return gj.grid.events.rowSelect($grid, $row, id, $grid.getById(id)); }, unselectRow: function ($grid, data, $row, id) { var $checkbox; if ($row.attr('data-selected') === 'true') { $row.removeClass(data.style.content.rowSelected); if ('checkbox' === data.selectionMethod) { $checkbox = $row.find('td input[type="checkbox"][data-role="selectRow"]'); $checkbox.length && $checkbox.prop('checked') && $checkbox.prop('checked', false); if ('multiple' === data.selectionType) { $grid.find('thead input[data-role="selectAll"]').prop('checked', false); } } $row.removeAttr('data-selected'); return gj.grid.events.rowUnselect($grid, $row, id, $grid.getById(id)); } }, setSelected: function ($grid, id, $row) { var data = $grid.data(); if (!$row || !$row.length) { $row = gj.grid.methods.getRowById($grid, id); } if ($row) { if ($row.attr('data-selected') === 'true') { gj.grid.methods.unselectRow($grid, data, $row, id); } else { if ('single' === data.selectionType) { $row.siblings('[data-selected="true"]').each(function () { var $row = $(this), id = gj.grid.methods.getId($row, data.primaryKey, $row.data('position')); gj.grid.methods.unselectRow($grid, data, $row, id); }); } gj.grid.methods.selectRow($grid, data, $row, id); } } return $grid; }, selectAll: function ($grid) { var data = $grid.data(); $grid.find('tbody tr[data-role="row"]').each(function () { var $row = $(this), position = $row.data('position'), record = $grid.get(position), id = gj.grid.methods.getId(record, data.primaryKey, position); gj.grid.methods.selectRow($grid, data, $row, id); }); $grid.find('thead input[data-role="selectAll"]').prop('checked', true); return $grid; }, unSelectAll: function ($grid) { var data = $grid.data(); $grid.find('tbody tr').each(function () { var $row = $(this), position = $row.data('position'), record = $grid.get(position), id = gj.grid.methods.getId(record, data.primaryKey, position); gj.grid.methods.unselectRow($grid, data, $row, id); $row.find('input[type="checkbox"][data-role="selectRow"]').prop('checked', false); }); $grid.find('thead input[data-role="selectAll"]').prop('checked', false); return $grid; }, getSelected: function ($grid) { var result = null, selections, record, position; selections = $grid.find('tbody>tr[data-selected="true"]'); if (selections.length > 0) { position = $(selections[0]).data('position'); record = $grid.get(position); result = gj.grid.methods.getId(record, $grid.data().primaryKey, position); } return result; }, getSelectedRows: function ($grid) { var data = $grid.data(); return $grid.find('tbody>tr[data-selected="true"]'); }, getSelections: function ($grid) { var result = [], position, record, data = $grid.data(), $selections = gj.grid.methods.getSelectedRows($grid); if (0 < $selections.length) { $selections.each(function () { position = $(this).data('position'); record = $grid.get(position); result.push(gj.grid.methods.getId(record, data.primaryKey, position)); }); } return result; }, getById: function ($grid, id) { var result = null, i, primaryKey = $grid.data('primaryKey'), records = $grid.data('records'); if (primaryKey) { for (i = 0; i < records.length; i++) { if (records[i][primaryKey] == id) { result = records[i]; break; } } } else { result = $grid.get(id); } return result; }, getRecVPosById: function ($grid, id) { var result = id, i, data = $grid.data(); if (data.primaryKey) { for (i = 0; i < data.dataSource.length; i++) { if (data.dataSource[i][data.primaryKey] == id) { result = i; break; } } } return result; }, getRowById: function ($grid, id) { var records = $grid.getAll(false), primaryKey = $grid.data('primaryKey'), $result = undefined, position, i; if (primaryKey) { for (i = 0; i < records.length; i++) { if (records[i][primaryKey] == id) { position = i + 1; break; } } } else { position = id; } if (position) { $result = $grid.children('tbody').children('tr[data-position="' + position + '"]'); } return $result; }, getByPosition: function ($grid, position) { return $grid.getAll(false)[position - 1]; }, getColumnPosition: function (columns, field) { var position = -1, i; for (i = 0; i < columns.length; i++) { if (columns[i].field === field) { position = i; break; } } return position; }, getColumnInfo: function ($grid, field) { var i, result = {}, data = $grid.data(); for (i = 0; i < data.columns.length; i += 1) { if (data.columns[i].field === field) { result = data.columns[i]; break; } } return result; }, getCell: function ($grid, id, field) { var position, $row, $result = null; position = gj.grid.methods.getColumnPosition($grid.data('columns'), field); if (position > -1) { $row = gj.grid.methods.getRowById($grid, id); $result = $row.find('td:eq(' + position + ') div[data-role="display"]'); } return $result; }, setCellContent: function ($grid, id, field, value) { var column, $displayEl = gj.grid.methods.getCell($grid, id, field); if ($displayEl) { $displayEl.empty(); if (typeof (value) === 'object') { $displayEl.append(value); } else { column = gj.grid.methods.getColumnInfo($grid, field); gj.grid.methods.renderDisplayElement($grid, $displayEl, column, $grid.getById(id), id, 'update'); } } }, clone: function (source) { var target = []; $.each(source, function () { target.push(this.clone()); }); return target; }, getAll: function ($grid) { return $grid.data('records'); }, countVisibleColumns: function ($grid) { var columns, count, i; columns = $grid.data().columns; count = 0; for (i = 0; i < columns.length; i++) { if (columns[i].hidden !== true) { count++; } } return count; }, clear: function ($grid, showNotFoundText) { var data = $grid.data(); $grid.xhr && $grid.xhr.abort(); $grid.children('tbody').empty(); data.records = []; gj.grid.methods.stopLoading($grid); gj.grid.methods.appendEmptyRow($grid, showNotFoundText ? data.notFoundText : '&nbsp;'); gj.grid.events.dataBound($grid, [], 0); return $grid; }, render: function ($grid, response) { if (response) { gj.grid.methods.setRecordsData($grid, response); gj.grid.methods.updateHeader($grid); gj.grid.methods.loadData($grid); } return $grid; }, filter: function ($grid) { var field, column, data = $grid.data(), records = data.dataSource.slice(); if (data.params[data.paramNames.sortBy]) { column = gj.grid.methods.getColumnInfo($grid, data.params[data.paramNames.sortBy]); records.sort(column.sortable.sorter ? column.sortable.sorter(column.direction, column) : gj.grid.methods.createDefaultSorter(column.direction, column.field)); } for (field in data.params) { if (data.params[field] && !data.paramNames[field]) { column = gj.grid.methods.getColumnInfo($grid, field); records = $.grep(records, function (record) { var value = record[field] || '', searchStr = data.params[field] || ''; return column && typeof (column.filter) === 'function' ? column.filter(value, searchStr) : (value.toUpperCase().indexOf(searchStr.toUpperCase()) > -1); }); } } gj.grid.events.dataFiltered($grid, records); return records; }, createDefaultSorter: function (direction, field) { return function (recordA, recordB) { var a = (recordA[field] || '').toString(), b = (recordB[field] || '').toString(); return (direction === 'asc') ? a.localeCompare(b) : b.localeCompare(a); }; }, destroy: function ($grid, keepTableTag, keepWrapperTag) { var data = $grid.data(); if (data) { gj.grid.events.destroying($grid); gj.grid.methods.stopLoading($grid); $grid.xhr && $grid.xhr.abort(); $grid.off(); if (keepWrapperTag === false && $grid.parent('div[data-role="wrapper"]').length > 0) { $grid.unwrap(); } $grid.removeData(); if (keepTableTag === false) { $grid.remove(); } else { $grid.removeClass().empty(); } $grid.removeAttr('data-type'); } return $grid; }, showColumn: function ($grid, field) { var data = $grid.data(), position = gj.grid.methods.getColumnPosition(data.columns, field), $cells; if (position > -1) { $grid.find('thead>tr').each(function() { $(this).children('th').eq(position).show(); }); $.each($grid.find('tbody>tr'), function () { $(this).children('td').eq(position).show(); }); data.columns[position].hidden = false; $cells = $grid.find('tbody > tr[data-role="empty"] > td'); if ($cells && $cells.length) { $cells.attr('colspan', gj.grid.methods.countVisibleColumns($grid)); } gj.grid.events.columnShow($grid, data.columns[position]); } return $grid; }, hideColumn: function ($grid, field) { var data = $grid.data(), position = gj.grid.methods.getColumnPosition(data.columns, field), $cells; if (position > -1) { $grid.find('thead>tr').each(function () { $(this).children('th').eq(position).hide(); }); $.each($grid.find('tbody>tr'), function () { $(this).children('td').eq(position).hide(); }); data.columns[position].hidden = true; $cells = $grid.find('tbody > tr[data-role="empty"] > td'); if ($cells && $cells.length) { $cells.attr('colspan', gj.grid.methods.countVisibleColumns($grid)); } gj.grid.events.columnHide($grid, data.columns[position]); } return $grid; }, isLastRecordVisible: function () { return true; }, addRow: function ($grid, record) { var data = $grid.data(); data.totalRecords = $grid.data('totalRecords') + 1; gj.grid.events.dataBinding($grid, [record]); data.records.push(record); if ($.isArray(data.dataSource)) { data.dataSource.push(record); } if (data.totalRecords === 1) { $grid.children('tbody').empty(); } if (gj.grid.methods.isLastRecordVisible($grid)) { gj.grid.methods.renderRow($grid, null, record, $grid.count() - 1); } gj.grid.events.dataBound($grid, [record], data.totalRecords); return $grid; }, updateRow: function ($grid, id, record) { var $row = gj.grid.methods.getRowById($grid, id), data = $grid.data(), position; data.records[$row.data('position') - 1] = record; if ($.isArray(data.dataSource)) { position = gj.grid.methods.getRecVPosById($grid, id); data.dataSource[position] = record; } gj.grid.methods.renderRow($grid, $row, record, $row.index()); return $grid; }, removeRow: function ($grid, id) { var position, data = $grid.data(), $row = gj.grid.methods.getRowById($grid, id); gj.grid.events.rowRemoving($grid, $row, id, $grid.getById(id)); if ($.isArray(data.dataSource)) { position = gj.grid.methods.getRecVPosById($grid, id); data.dataSource.splice(position, 1); } $grid.reload(); return $grid; }, count: function ($grid, includeAllRecords) { return includeAllRecords ? $grid.data().totalRecords : $grid.getAll().length; }, getColumnPositionByRole: function ($grid, role) { var i, result, columns = $grid.data('columns'); for (i = 0; i < columns.length; i++) { if (columns[i].role === role) { result = i; break; } } return result; }, getColumnPositionNotInRole: function ($grid) { var i, result = 0, columns = $grid.data('columns'); for (i = 0; i < columns.length; i++) { if (!columns[i].role) { result = i; break; } } return result; } }; /** */ gj.grid.widget = function ($grid, jsConfig) { var self = this, methods = gj.grid.methods; /** * Reload the data in the grid from a data source. */ self.reload = function (params) { methods.startLoading(this); return gj.widget.prototype.reload.call(this, params); }; /** * Clear the content in the grid. */ self.clear = function (showNotFoundText) { return methods.clear(this, showNotFoundText); }; /** * Return the number of records in the grid. By default return only the records that are visible in the grid. */ self.count = function (includeAllRecords) { return methods.count(this, includeAllRecords); }; /** * Render data in the grid */ self.render = function (response) { return methods.render($grid, response); }; /** * Destroy the grid. This method remove all data from the grid and all events attached to the grid. */ self.destroy = function (keepTableTag, keepWrapperTag) { return methods.destroy(this, keepTableTag, keepWrapperTag); }; /** * Select a row from the grid based on id parameter. */ self.setSelected = function (id) { return methods.setSelected(this, id); }; /** * Return the id of the selected record. * If the multiple selection method is one this method is going to return only the id of the first selected record. */ self.getSelected = function () { return methods.getSelected(this); }; /** * Return an array with the ids of the selected record. */ self.getSelections = function () { return methods.getSelections(this); }; /** * Select all records from the grid. */ self.selectAll = function () { return methods.selectAll(this); }; /** * Unselect all records from the grid. */ self.unSelectAll = function () { return methods.unSelectAll(this); }; /** * Return record by id of the record. */ self.getById = function (id) { return methods.getById(this, id); }; /** * Return record from the grid based on position. */ self.get = function (position) { return methods.getByPosition(this, position); }; /** * Return an array with all records presented in the grid. */ self.getAll = function (includeAllRecords) { return methods.getAll(this, includeAllRecords); }; /** * Show hidden column. */ self.showColumn = function (field) { return methods.showColumn(this, field); }; /** * Hide column from the grid. */ self.hideColumn = function (field) { return methods.hideColumn(this, field); }; /** * Add new row to the grid. */ self.addRow = function (record) { return methods.addRow(this, record); }; /** * Update row data. */ self.updateRow = function (id, record) { return methods.updateRow(this, id, record); }; //TODO: needs to be removed self.setCellContent = function (id, index, value) { methods.setCellContent(this, id, index, value); }; /** * Remove row from the grid */ self.removeRow = function (id) { return methods.removeRow(this, id); }; $.extend($grid, self); if ('grid' !== $grid.attr('data-type')) { methods.init.call($grid, jsConfig); } return $grid; } gj.grid.widget.prototype = new gj.widget(); gj.grid.widget.constructor = gj.grid.widget; gj.grid.widget.prototype.getConfig = gj.grid.method