diff --git a/dist/jquery.bootgrid-1.1.4.zip b/dist/jquery.bootgrid-1.1.4.zip index 06c4c73..5105c7c 100644 Binary files a/dist/jquery.bootgrid-1.1.4.zip and b/dist/jquery.bootgrid-1.1.4.zip differ diff --git a/dist/jquery.bootgrid.css b/dist/jquery.bootgrid.css index a2df310..63a6bdd 100644 --- a/dist/jquery.bootgrid.css +++ b/dist/jquery.bootgrid.css @@ -1,6 +1,6 @@ /*! - * jQuery Bootgrid v1.1.4 - 11/23/2014 - * Copyright (c) 2014 Rafael Staib (http://www.jquery-bootgrid.com) + * jQuery Bootgrid v1.1.4 - 04/10/2015 + * Copyright (c) 2015 Rafael Staib (http://www.jquery-bootgrid.com) * Licensed under MIT http://www.opensource.org/licenses/MIT */ .bootgrid-header, diff --git a/dist/jquery.bootgrid.js b/dist/jquery.bootgrid.js index ffda62a..8ebddc8 100644 --- a/dist/jquery.bootgrid.js +++ b/dist/jquery.bootgrid.js @@ -1,6 +1,6 @@ /*! - * jQuery Bootgrid v1.1.4 - 11/23/2014 - * Copyright (c) 2014 Rafael Staib (http://www.jquery-bootgrid.com) + * jQuery Bootgrid v1.1.4 - 04/10/2015 + * Copyright (c) 2015 Rafael Staib (http://www.jquery-bootgrid.com) * Licensed under MIT http://www.opensource.org/licenses/MIT */ ;(function ($, window, undefined) @@ -8,1741 +8,1752 @@ /*jshint validthis: true */ "use strict"; - // GRID INTERNAL FIELDS - // ==================== +// GRID INTERNAL FIELDS +// ==================== - var namespace = ".rs.jquery.bootgrid"; +var namespace = ".rs.jquery.bootgrid"; - // GRID INTERNAL FUNCTIONS - // ===================== +// GRID INTERNAL FUNCTIONS +// ===================== - function appendRow(row) - { - var that = this; - - function exists(item) - { - return that.identifier && item[that.identifier] === row[that.identifier]; - } - - if (!this.rows.contains(exists)) - { - this.rows.push(row); - return true; - } - - return false; - } +function appendRow(row) +{ + var that = this; - function getParams(context) + function exists(item) { - return (context) ? $.extend({}, this.cachedParams, { ctx: context }) : - this.cachedParams; + return that.identifier && item[that.identifier] === row[that.identifier]; } - function getRequest() + if (!this.rows.contains(exists)) { - var request = { - current: this.current, - rowCount: this.rowCount, - sort: this.sort, - searchPhrase: this.searchPhrase - }, - post = this.options.post; - - post = ($.isFunction(post)) ? post() : post; - return this.options.requestHandler($.extend(true, request, post)); + this.rows.push(row); + return true; } - function getCssSelector(css) - { - return "." + $.trim(css).replace(/\s+/gm, "."); - } + return false; +} + +function getParams(context) +{ + return (context) ? $.extend({}, this.cachedParams, { ctx: context }) : + this.cachedParams; +} - function getUrl() +function getRequest() +{ + var request = { + current: this.current, + rowCount: this.rowCount, + sort: this.sort, + searchPhrase: this.searchPhrase + }, + post = this.options.post; + + post = ($.isFunction(post)) ? post() : post; + return this.options.requestHandler($.extend(true, request, post)); +} + +function getCssSelector(css) +{ + return "." + $.trim(css).replace(/\s+/gm, "."); +} + +function getUrl() +{ + var url = this.options.url; + return ($.isFunction(url)) ? url() : url; +} + +function init() +{ + this.element.trigger("initialize" + namespace); + + loadColumns.call(this); // Loads columns from HTML thead tag + this.selection = this.options.selection && this.identifier != null; + loadRows.call(this); // Loads rows from HTML tbody tag if ajax is false + prepareTable.call(this); + renderTableHeader.call(this); + renderSearchField.call(this); + renderActions.call(this); + loadData.call(this); + + this.element.trigger("initialized" + namespace); +} + +function highlightAppendedRows(rows) +{ + if (this.options.highlightRows) { - var url = this.options.url; - return ($.isFunction(url)) ? url() : url; + // todo: implement } +} - function init() - { - this.element.trigger("initialize" + namespace); - - loadColumns.call(this); // Loads columns from HTML thead tag - this.selection = this.options.selection && this.identifier != null; - loadRows.call(this); // Loads rows from HTML tbody tag if ajax is false - prepareTable.call(this); - renderTableHeader.call(this); - renderSearchField.call(this); - renderActions.call(this); - loadData.call(this); +function isVisible(column) +{ + return column.visible; +} - this.element.trigger("initialized" + namespace); - } +function loadColumns() +{ + var that = this, + firstHeadRow = this.element.find("thead > tr").first(), + sorted = false; - function highlightAppendedRows(rows) + /*jshint -W018*/ + firstHeadRow.children().each(function () { - if (this.options.highlightRows) + var $this = $(this), + data = $this.data(), + column = { + id: data.columnId, + identifier: that.identifier == null && data.identifier || false, + converter: that.options.converters[data.converter || data.type] || that.options.converters["string"], + text: $this.text(), + align: data.align || "left", + headerAlign: data.headerAlign || "left", + cssClass: data.cssClass || "", + headerCssClass: data.headerCssClass || "", + title: data.title || "", + formatter: that.options.formatters[data.formatter] || null, + order: (!sorted && (data.order === "asc" || data.order === "desc")) ? data.order : null, + searchable: !(data.searchable === false), // default: true + sortable: !(data.sortable === false), // default: true + visible: !(data.visible === false), // default: true + html: !(data.html === true) // default: false, recomended to use in conjunction with data-sortable="false" + }; + that.columns.push(column); + if (column.order != null) { - // todo: implement + that.sort[column.id] = column.order; } - } - function isVisible(column) + // Prevents multiple identifiers + if (column.identifier) + { + that.identifier = column.id; + that.converter = column.converter; + } + + // ensures that only the first order will be applied in case of multi sorting is disabled + if (!that.options.multiSort && column.order !== null) + { + sorted = true; + } + }); + /*jshint +W018*/ +} + +/* +response = { + current: 1, + rowCount: 10, + rows: [{}, {}], + sort: [{ "columnId": "asc" }], + total: 101 +} +*/ + +function loadData() +{ + var that = this, + request = getRequest.call(this), + url = getUrl.call(this); + + if (this.options.ajax && (url == null || typeof url !== "string" || url.length === 0)) { - return column.visible; + throw new Error("Url setting must be a none empty string or a function that returns one."); } - function loadColumns() + this.element._bgBusyAria(true).trigger("load" + namespace); + showLoading.call(this); + + function containsPhrase(row) { - var that = this, - firstHeadRow = this.element.find("thead > tr").first(), - sorted = false; + var column, + searchPattern = new RegExp(that.searchPhrase, (that.options.caseSensitive) ? "g" : "gi"); - /*jshint -W018*/ - firstHeadRow.children().each(function () + for (var i = 0; i < that.columns.length; i++) { - var $this = $(this), - data = $this.data(), - column = { - id: data.columnId, - identifier: that.identifier == null && data.identifier || false, - converter: that.options.converters[data.converter || data.type] || that.options.converters["string"], - text: $this.text(), - align: data.align || "left", - headerAlign: data.headerAlign || "left", - cssClass: data.cssClass || "", - headerCssClass: data.headerCssClass || "", - formatter: that.options.formatters[data.formatter] || null, - order: (!sorted && (data.order === "asc" || data.order === "desc")) ? data.order : null, - searchable: !(data.searchable === false), // default: true - sortable: !(data.sortable === false), // default: true - visible: !(data.visible === false) // default: true - }; - that.columns.push(column); - if (column.order != null) - { - that.sort[column.id] = column.order; - } - - // Prevents multiple identifiers - if (column.identifier) - { - that.identifier = column.id; - that.converter = column.converter; - } - - // ensures that only the first order will be applied in case of multi sorting is disabled - if (!that.options.multiSort && column.order !== null) + column = that.columns[i]; + if (column.searchable && column.visible && + column.converter.to(row[column.id]).search(searchPattern) > -1) { - sorted = true; + return true; } - }); - /*jshint +W018*/ - } + } - /* - response = { - current: 1, - rowCount: 10, - rows: [{}, {}], - sort: [{ "columnId": "asc" }], - total: 101 + return false; } - */ - function loadData() + function update(rows, total) { - var that = this, - request = getRequest.call(this), - url = getUrl.call(this); + that.currentRows = rows; + that.total = total; + that.totalPages = Math.ceil(total / that.rowCount); - if (this.options.ajax && (url == null || typeof url !== "string" || url.length === 0)) + if (!that.options.keepSelection) { - throw new Error("Url setting must be a none empty string or a function that returns one."); + that.selectedRows = []; } - this.element._bgBusyAria(true).trigger("load" + namespace); - showLoading.call(this); - - function containsPhrase(row) - { - var column, - searchPattern = new RegExp(that.searchPhrase, (that.options.caseSensitive) ? "g" : "gi"); + renderRows.call(that, rows); + renderInfos.call(that); + renderPagination.call(that); - for (var i = 0; i < that.columns.length; i++) - { - column = that.columns[i]; - if (column.searchable && column.visible && - column.converter.to(row[column.id]).search(searchPattern) > -1) - { - return true; - } - } + that.element._bgBusyAria(false).trigger("loaded" + namespace); + } - return false; + if (this.options.ajax) + { + // aborts the previous ajax request if not already finished or failed + if (that.xqr) + { + that.xqr.abort(); } - function update(rows, total) + that.xqr = $.post(url, request, function (response) { - that.currentRows = rows; - that.total = total; - that.totalPages = Math.ceil(total / that.rowCount); + that.xqr = null; - if (!that.options.keepSelection) + if (typeof (response) === "string") { - that.selectedRows = []; + response = $.parseJSON(response); } - renderRows.call(that, rows); - renderInfos.call(that); - renderPagination.call(that); - - that.element._bgBusyAria(false).trigger("loaded" + namespace); - } + response = that.options.responseHandler(response); - if (this.options.ajax) + that.current = response.current; + update(response.rows, response.total); + }).fail(function (jqXHR, textStatus, errorThrown) { - // aborts the previous ajax request if not already finished or failed - if (that.xqr) - { - that.xqr.abort(); - } - - that.xqr = $.post(url, request, function (response) - { - that.xqr = null; - - if (typeof (response) === "string") - { - response = $.parseJSON(response); - } + that.xqr = null; - response = that.options.responseHandler(response); - - that.current = response.current; - update(response.rows, response.total); - }).fail(function (jqXHR, textStatus, errorThrown) - { - that.xqr = null; - - if (textStatus !== "abort") - { - renderNoResultsRow.call(that); // overrides loading mask - that.element._bgBusyAria(false).trigger("loaded" + namespace); - } - }); - } - else - { - var rows = (this.searchPhrase.length > 0) ? this.rows.where(containsPhrase) : this.rows, - total = rows.length; - if (this.rowCount !== -1) + if (textStatus !== "abort") { - rows = rows.page(this.current, this.rowCount); + renderNoResultsRow.call(that); // overrides loading mask + that.element._bgBusyAria(false).trigger("loaded" + namespace); } - - // todo: improve the following comment - // setTimeout decouples the initialization so that adding event handlers happens before - window.setTimeout(function () { update(rows, total); }, 10); + }); + } + else + { + var rows = (this.searchPhrase.length > 0) ? this.rows.where(containsPhrase) : this.rows, + total = rows.length; + if (this.rowCount !== -1) + { + rows = rows.page(this.current, this.rowCount); } + + // todo: improve the following comment + // setTimeout decouples the initialization so that adding event handlers happens before + window.setTimeout(function () { update(rows, total); }, 10); } +} - function loadRows() +function loadRows() +{ + if (!this.options.ajax) { - if (!this.options.ajax) + var that = this, + rows = this.element.find("tbody > tr"); + + rows.each(function () { - var that = this, - rows = this.element.find("tbody > tr"); + var $this = $(this), + cells = $this.children("td"), + row = {}; - rows.each(function () + $.each(that.columns, function (i, column) { - var $this = $(this), - cells = $this.children("td"), - row = {}; - - $.each(that.columns, function (i, column) + if (column.html === true) { row[column.id] = column.converter.from(cells.eq(i).text()); - }); - - appendRow.call(that, row); + } + else + { + row[column.id] = column.converter.from(cells.eq(i).html()); + } }); - this.total = this.rows.length; - this.totalPages = (this.rowCount === -1) ? 1 : - Math.ceil(this.total / this.rowCount); - - sortRows.call(this); - } - } + appendRow.call(that, row); + }); - function prepareTable() - { - var tpl = this.options.templates, - wrapper = (this.element.parent().hasClass(this.options.css.responsiveTable)) ? - this.element.parent() : this.element; + this.total = this.rows.length; + this.totalPages = (this.rowCount === -1) ? 1 : + Math.ceil(this.total / this.rowCount); - this.element.addClass(this.options.css.table); + sortRows.call(this); + } +} - // checks whether there is an tbody element; otherwise creates one - if (this.element.children("tbody").length === 0) - { - this.element.append(tpl.body); - } +function prepareTable() +{ + var tpl = this.options.templates, + wrapper = (this.element.parent().hasClass(this.options.css.responsiveTable)) ? + this.element.parent() : this.element; - if (this.options.navigation & 1) - { - this.header = $(tpl.header.resolve(getParams.call(this, { id: this.element._bgId() + "-header" }))); - wrapper.before(this.header); - } + this.element.addClass(this.options.css.table); - if (this.options.navigation & 2) - { - this.footer = $(tpl.footer.resolve(getParams.call(this, { id: this.element._bgId() + "-footer" }))); - wrapper.after(this.footer); - } + // checks whether there is an tbody element; otherwise creates one + if (this.element.children("tbody").length === 0) + { + this.element.append(tpl.body); } - function renderActions() + if (this.options.navigation & 1) { - if (this.options.navigation !== 0) - { - var css = this.options.css, - selector = getCssSelector(css.actions), - headerActions = this.header.find(selector), - footerActions = this.footer.find(selector); - - if ((headerActions.length + footerActions.length) > 0) - { - var that = this, - tpl = this.options.templates, - actions = $(tpl.actions.resolve(getParams.call(this))); - - // Refresh Button - if (this.options.ajax) - { - var refreshIcon = tpl.icon.resolve(getParams.call(this, { iconCss: css.iconRefresh })), - refresh = $(tpl.actionButton.resolve(getParams.call(this, - { content: refreshIcon, text: this.options.labels.refresh }))) - .on("click" + namespace, function (e) - { - // todo: prevent multiple fast clicks (fast click detection) - e.stopPropagation(); - that.current = 1; - loadData.call(that); - }); - actions.append(refresh); - } - - // Row count selection - renderRowCountSelection.call(this, actions); - - // Column selection - renderColumnSelection.call(this, actions); + this.header = $(tpl.header.resolve(getParams.call(this, { id: this.element._bgId() + "-header" }))); + wrapper.before(this.header); + } - replacePlaceHolder.call(this, headerActions, actions, 1); - replacePlaceHolder.call(this, footerActions, actions, 2); - } - } + if (this.options.navigation & 2) + { + this.footer = $(tpl.footer.resolve(getParams.call(this, { id: this.element._bgId() + "-footer" }))); + wrapper.after(this.footer); } +} - function renderColumnSelection(actions) +function renderActions() +{ + if (this.options.navigation !== 0) { - if (this.options.columnSelection && this.columns.length > 1) + var css = this.options.css, + selector = getCssSelector(css.actions), + headerActions = this.header.find(selector), + footerActions = this.footer.find(selector); + + if ((headerActions.length + footerActions.length) > 0) { var that = this, - css = this.options.css, tpl = this.options.templates, - icon = tpl.icon.resolve(getParams.call(this, { iconCss: css.iconColumns })), - dropDown = $(tpl.actionDropDown.resolve(getParams.call(this, { content: icon }))), - selector = getCssSelector(css.dropDownItem), - checkboxSelector = getCssSelector(css.dropDownItemCheckbox), - itemsSelector = getCssSelector(css.dropDownMenuItems); + actions = $(tpl.actions.resolve(getParams.call(this))); - $.each(this.columns, function (i, column) + // Refresh Button + if (this.options.ajax) { - var item = $(tpl.actionDropDownCheckboxItem.resolve(getParams.call(that, - { name: column.id, label: column.text, checked: column.visible }))) - .on("click" + namespace, selector, function (e) + var refreshIcon = tpl.icon.resolve(getParams.call(this, { iconCss: css.iconRefresh })), + refresh = $(tpl.actionButton.resolve(getParams.call(this, + { content: refreshIcon, text: this.options.labels.refresh }))) + .on("click" + namespace, function (e) { + // todo: prevent multiple fast clicks (fast click detection) e.stopPropagation(); - - var $this = $(this), - checkbox = $this.find(checkboxSelector); - if (!checkbox.prop("disabled")) - { - column.visible = checkbox.prop("checked"); - var enable = that.columns.where(isVisible).length > 1; - $this.parents(itemsSelector).find(selector + ":has(" + checkboxSelector + ":checked)") - ._bgEnableAria(enable).find(checkboxSelector)._bgEnableField(enable); - - that.element.find("tbody").empty(); // Fixes an column visualization bug - renderTableHeader.call(that); - loadData.call(that); - } + that.current = 1; + loadData.call(that); }); - dropDown.find(getCssSelector(css.dropDownMenuItems)).append(item); - }); - actions.append(dropDown); + actions.append(refresh); + } + + // Row count selection + renderRowCountSelection.call(this, actions); + + // Column selection + renderColumnSelection.call(this, actions); + + replacePlaceHolder.call(this, headerActions, actions, 1); + replacePlaceHolder.call(this, footerActions, actions, 2); } } +} - function renderInfos() +function renderColumnSelection(actions) +{ + if (this.options.columnSelection && this.columns.length > 1) { - if (this.options.navigation !== 0) + var that = this, + css = this.options.css, + tpl = this.options.templates, + icon = tpl.icon.resolve(getParams.call(this, { iconCss: css.iconColumns })), + dropDown = $(tpl.actionDropDown.resolve(getParams.call(this, { content: icon }))), + selector = getCssSelector(css.dropDownItem), + checkboxSelector = getCssSelector(css.dropDownItemCheckbox), + itemsSelector = getCssSelector(css.dropDownMenuItems); + + $.each(this.columns, function (i, column) { - var selector = getCssSelector(this.options.css.infos), - headerInfos = this.header.find(selector), - footerInfos = this.footer.find(selector); + var item = $(tpl.actionDropDownCheckboxItem.resolve(getParams.call(that, + { name: column.id, label: column.text, checked: column.visible }))) + .on("click" + namespace, selector, function (e) + { + e.stopPropagation(); - if ((headerInfos.length + footerInfos.length) > 0) - { - var end = (this.current * this.rowCount), - infos = $(this.options.templates.infos.resolve(getParams.call(this, { - end: (this.total === 0 || end === -1 || end > this.total) ? this.total : end, - start: (this.total === 0) ? 0 : (end - this.rowCount + 1), - total: this.total - }))); - - replacePlaceHolder.call(this, headerInfos, infos, 1); - replacePlaceHolder.call(this, footerInfos, infos, 2); - } - } + var $this = $(this), + checkbox = $this.find(checkboxSelector); + if (!checkbox.prop("disabled")) + { + column.visible = checkbox.prop("checked"); + var enable = that.columns.where(isVisible).length > 1; + $this.parents(itemsSelector).find(selector + ":has(" + checkboxSelector + ":checked)") + ._bgEnableAria(enable).find(checkboxSelector)._bgEnableField(enable); + + that.element.find("tbody").empty(); // Fixes an column visualization bug + renderTableHeader.call(that); + loadData.call(that); + } + }); + dropDown.find(getCssSelector(css.dropDownMenuItems)).append(item); + }); + actions.append(dropDown); } +} - function renderNoResultsRow() +function renderInfos() +{ + if (this.options.navigation !== 0) { - var tbody = this.element.children("tbody").first(), - tpl = this.options.templates, - count = this.columns.where(isVisible).length; + var selector = getCssSelector(this.options.css.infos), + headerInfos = this.header.find(selector), + footerInfos = this.footer.find(selector); - if (this.selection) + if ((headerInfos.length + footerInfos.length) > 0) { - count = count + 1; + var end = (this.current * this.rowCount), + infos = $(this.options.templates.infos.resolve(getParams.call(this, { + end: (this.total === 0 || end === -1 || end > this.total) ? this.total : end, + start: (this.total === 0) ? 0 : (end - this.rowCount + 1), + total: this.total + }))); + + replacePlaceHolder.call(this, headerInfos, infos, 1); + replacePlaceHolder.call(this, footerInfos, infos, 2); } - tbody.html(tpl.noResults.resolve(getParams.call(this, { columns: count }))); } +} + +function renderNoResultsRow() +{ + var tbody = this.element.children("tbody").first(), + tpl = this.options.templates, + count = this.columns.where(isVisible).length; - function renderPagination() + if (this.selection) { - if (this.options.navigation !== 0) - { - var selector = getCssSelector(this.options.css.pagination), - headerPagination = this.header.find(selector)._bgShowAria(this.rowCount !== -1), - footerPagination = this.footer.find(selector)._bgShowAria(this.rowCount !== -1); + count = count + 1; + } + tbody.html(tpl.noResults.resolve(getParams.call(this, { columns: count }))); +} + +function renderPagination() +{ + if (this.options.navigation !== 0) + { + var selector = getCssSelector(this.options.css.pagination), + headerPagination = this.header.find(selector)._bgShowAria(this.rowCount !== -1), + footerPagination = this.footer.find(selector)._bgShowAria(this.rowCount !== -1); - if (this.rowCount !== -1 && (headerPagination.length + footerPagination.length) > 0) + if (this.rowCount !== -1 && (headerPagination.length + footerPagination.length) > 0) + { + var tpl = this.options.templates, + current = this.current, + totalPages = this.totalPages, + pagination = $(tpl.pagination.resolve(getParams.call(this))), + offsetRight = totalPages - current, + offsetLeft = (this.options.padding - current) * -1, + startWith = ((offsetRight >= this.options.padding) ? + Math.max(offsetLeft, 1) : + Math.max((offsetLeft - this.options.padding + offsetRight), 1)), + maxCount = this.options.padding * 2 + 1, + count = (totalPages >= maxCount) ? maxCount : totalPages; + + renderPaginationItem.call(this, pagination, "first", "«", "first") + ._bgEnableAria(current > 1); + renderPaginationItem.call(this, pagination, "prev", "<", "prev") + ._bgEnableAria(current > 1); + + for (var i = 0; i < count; i++) { - var tpl = this.options.templates, - current = this.current, - totalPages = this.totalPages, - pagination = $(tpl.pagination.resolve(getParams.call(this))), - offsetRight = totalPages - current, - offsetLeft = (this.options.padding - current) * -1, - startWith = ((offsetRight >= this.options.padding) ? - Math.max(offsetLeft, 1) : - Math.max((offsetLeft - this.options.padding + offsetRight), 1)), - maxCount = this.options.padding * 2 + 1, - count = (totalPages >= maxCount) ? maxCount : totalPages; - - renderPaginationItem.call(this, pagination, "first", "«", "first") - ._bgEnableAria(current > 1); - renderPaginationItem.call(this, pagination, "prev", "<", "prev") - ._bgEnableAria(current > 1); - - for (var i = 0; i < count; i++) - { - var pos = i + startWith; - renderPaginationItem.call(this, pagination, pos, pos, "page-" + pos) - ._bgEnableAria()._bgSelectAria(pos === current); - } + var pos = i + startWith; + renderPaginationItem.call(this, pagination, pos, pos, "page-" + pos) + ._bgEnableAria()._bgSelectAria(pos === current); + } - if (count === 0) - { - renderPaginationItem.call(this, pagination, 1, 1, "page-" + 1) - ._bgEnableAria(false)._bgSelectAria(); - } + if (count === 0) + { + renderPaginationItem.call(this, pagination, 1, 1, "page-" + 1) + ._bgEnableAria(false)._bgSelectAria(); + } - renderPaginationItem.call(this, pagination, "next", ">", "next") - ._bgEnableAria(totalPages > current); - renderPaginationItem.call(this, pagination, "last", "»", "last") - ._bgEnableAria(totalPages > current); + renderPaginationItem.call(this, pagination, "next", ">", "next") + ._bgEnableAria(totalPages > current); + renderPaginationItem.call(this, pagination, "last", "»", "last") + ._bgEnableAria(totalPages > current); - replacePlaceHolder.call(this, headerPagination, pagination, 1); - replacePlaceHolder.call(this, footerPagination, pagination, 2); - } + replacePlaceHolder.call(this, headerPagination, pagination, 1); + replacePlaceHolder.call(this, footerPagination, pagination, 2); } } +} - function renderPaginationItem(list, uri, text, markerCss) - { - var that = this, - tpl = this.options.templates, - css = this.options.css, - values = getParams.call(this, { css: markerCss, text: text, uri: "#" + uri }), - item = $(tpl.paginationItem.resolve(values)) - .on("click" + namespace, getCssSelector(css.paginationButton), function (e) +function renderPaginationItem(list, uri, text, markerCss) +{ + var that = this, + tpl = this.options.templates, + css = this.options.css, + values = getParams.call(this, { css: markerCss, text: text, uri: "#" + uri }), + item = $(tpl.paginationItem.resolve(values)) + .on("click" + namespace, getCssSelector(css.paginationButton), function (e) + { + e.stopPropagation(); + + var $this = $(this), + parent = $this.parent(); + if (!parent.hasClass("active") && !parent.hasClass("disabled")) { - e.stopPropagation(); + var commandList = { + first: 1, + prev: that.current - 1, + next: that.current + 1, + last: that.totalPages + }; + var command = $this.attr("href").substr(1); + that.current = commandList[command] || +command; // + converts string to int + loadData.call(that); + } + $this.trigger("blur"); + }); - var $this = $(this), - parent = $this.parent(); - if (!parent.hasClass("active") && !parent.hasClass("disabled")) - { - var commandList = { - first: 1, - prev: that.current - 1, - next: that.current + 1, - last: that.totalPages - }; - var command = $this.attr("href").substr(1); - that.current = commandList[command] || +command; // + converts string to int - loadData.call(that); - } - $this.trigger("blur"); - }); + list.append(item); + return item; +} - list.append(item); - return item; - } +function renderRowCountSelection(actions) +{ + var that = this, + rowCountList = this.options.rowCount; - function renderRowCountSelection(actions) + function getText(value) { - var that = this, - rowCountList = this.options.rowCount; + return (value === -1) ? that.options.labels.all : value; + } - function getText(value) - { - return (value === -1) ? that.options.labels.all : value; - } + if ($.isArray(rowCountList)) + { + var css = this.options.css, + tpl = this.options.templates, + dropDown = $(tpl.actionDropDown.resolve(getParams.call(this, { content: this.rowCount }))), + menuSelector = getCssSelector(css.dropDownMenu), + menuTextSelector = getCssSelector(css.dropDownMenuText), + menuItemsSelector = getCssSelector(css.dropDownMenuItems), + menuItemSelector = getCssSelector(css.dropDownItemButton); - if ($.isArray(rowCountList)) + $.each(rowCountList, function (index, value) { - var css = this.options.css, - tpl = this.options.templates, - dropDown = $(tpl.actionDropDown.resolve(getParams.call(this, { content: this.rowCount }))), - menuSelector = getCssSelector(css.dropDownMenu), - menuTextSelector = getCssSelector(css.dropDownMenuText), - menuItemsSelector = getCssSelector(css.dropDownMenuItems), - menuItemSelector = getCssSelector(css.dropDownItemButton); + var item = $(tpl.actionDropDownItem.resolve(getParams.call(that, + { text: getText(value), uri: "#" + value }))) + ._bgSelectAria(value === that.rowCount) + .on("click" + namespace, menuItemSelector, function (e) + { + e.preventDefault(); - $.each(rowCountList, function (index, value) - { - var item = $(tpl.actionDropDownItem.resolve(getParams.call(that, - { text: getText(value), uri: "#" + value }))) - ._bgSelectAria(value === that.rowCount) - .on("click" + namespace, menuItemSelector, function (e) + var $this = $(this), + newRowCount = +$this.attr("href").substr(1); + if (newRowCount !== that.rowCount) { - e.preventDefault(); - - var $this = $(this), - newRowCount = +$this.attr("href").substr(1); - if (newRowCount !== that.rowCount) + // todo: sophisticated solution needed for calculating which page is selected + that.current = 1; // that.rowCount === -1 ---> All + that.rowCount = newRowCount; + $this.parents(menuItemsSelector).children().each(function () { - // todo: sophisticated solution needed for calculating which page is selected - that.current = 1; // that.rowCount === -1 ---> All - that.rowCount = newRowCount; - $this.parents(menuItemsSelector).children().each(function () - { - var $item = $(this), - currentRowCount = +$item.find(menuItemSelector).attr("href").substr(1); - $item._bgSelectAria(currentRowCount === newRowCount); - }); - $this.parents(menuSelector).find(menuTextSelector).text(getText(newRowCount)); - loadData.call(that); - } - }); - dropDown.find(menuItemsSelector).append(item); - }); - actions.append(dropDown); - } + var $item = $(this), + currentRowCount = +$item.find(menuItemSelector).attr("href").substr(1); + $item._bgSelectAria(currentRowCount === newRowCount); + }); + $this.parents(menuSelector).find(menuTextSelector).text(getText(newRowCount)); + loadData.call(that); + } + }); + dropDown.find(menuItemsSelector).append(item); + }); + actions.append(dropDown); } +} - function renderRows(rows) +function renderRows(rows) +{ + if (rows.length > 0) { - if (rows.length > 0) + var that = this, + css = this.options.css, + tpl = this.options.templates, + tbody = this.element.children("tbody").first(), + allRowsSelected = true, + html = "", + cells = "", + rowAttr = "", + rowCss = ""; + + $.each(rows, function (index, row) { - var that = this, - css = this.options.css, - tpl = this.options.templates, - tbody = this.element.children("tbody").first(), - allRowsSelected = true, - html = "", - cells = "", - rowAttr = "", - rowCss = ""; - - $.each(rows, function (index, row) - { - cells = ""; - rowAttr = " data-row-id=\"" + ((that.identifier == null) ? index : row[that.identifier]) + "\""; - rowCss = ""; + cells = ""; + rowAttr = " data-row-id=\"" + ((that.identifier == null) ? index : row[that.identifier]) + "\""; + rowCss = ""; - if (that.selection) + if (that.selection) + { + var selected = ($.inArray(row[that.identifier], that.selectedRows) !== -1), + selectBox = tpl.select.resolve(getParams.call(that, + { type: "checkbox", value: row[that.identifier], checked: selected })); + cells += tpl.cell.resolve(getParams.call(that, { content: selectBox, css: css.selectCell })); + allRowsSelected = (allRowsSelected && selected); + if (selected) { - var selected = ($.inArray(row[that.identifier], that.selectedRows) !== -1), - selectBox = tpl.select.resolve(getParams.call(that, - { type: "checkbox", value: row[that.identifier], checked: selected })); - cells += tpl.cell.resolve(getParams.call(that, { content: selectBox, css: css.selectCell })); - allRowsSelected = (allRowsSelected && selected); - if (selected) - { - rowCss += css.selected; - rowAttr += " aria-selected=\"true\""; - } + rowCss += css.selected; + rowAttr += " aria-selected=\"true\""; } + } - $.each(that.columns, function (j, column) - { - if (column.visible) - { - var value = ($.isFunction(column.formatter)) ? - column.formatter.call(that, column, row) : - column.converter.to(row[column.id]), - cssClass = (column.cssClass.length > 0) ? " " + column.cssClass : ""; - cells += tpl.cell.resolve(getParams.call(that, { - content: (value == null || value === "") ? " " : value, - css: ((column.align === "right") ? css.right : (column.align === "center") ? - css.center : css.left) + cssClass })); - } - }); - - if (rowCss.length > 0) + $.each(that.columns, function (j, column) + { + if (column.visible) { - rowAttr += " class=\"" + rowCss + "\""; + var value = ($.isFunction(column.formatter)) ? + column.formatter.call(that, column, row) : + column.converter.to(row[column.id]), + cssClass = (column.cssClass.length > 0) ? " " + column.cssClass : "", + title = (column.title.length > 0) ? "" + column.title : ""; + cells += tpl.cell.resolve(getParams.call(that, { + content: (value == null || value === "") ? " " : value, + title: (title == null || title === "") ? "" : title, + css: ((column.align === "right") ? css.right : (column.align === "center") ? + css.center : css.left) + cssClass })); } - html += tpl.row.resolve(getParams.call(that, { attr: rowAttr, cells: cells })); }); - // sets or clears multi selectbox state - that.element.find("thead " + getCssSelector(that.options.css.selectBox)) - .prop("checked", allRowsSelected); + if (rowCss.length > 0) + { + rowAttr += " class=\"" + rowCss + "\""; + } + html += tpl.row.resolve(getParams.call(that, { attr: rowAttr, cells: cells })); + }); - tbody.html(html); + // sets or clears multi selectbox state + that.element.find("thead " + getCssSelector(that.options.css.selectBox)) + .prop("checked", allRowsSelected); - registerRowEvents.call(this, tbody); - } - else - { - renderNoResultsRow.call(this); - } - } + tbody.html(html); - function registerRowEvents(tbody) + registerRowEvents.call(this, tbody); + } + else { - var that = this, - selectBoxSelector = getCssSelector(this.options.css.selectBox); - - if (this.selection) - { - tbody.off("click" + namespace, selectBoxSelector) - .on("click" + namespace, selectBoxSelector, function(e) - { - e.stopPropagation(); - - var $this = $(this), - id = that.converter.from($this.val()); + renderNoResultsRow.call(this); + } +} - if ($this.prop("checked")) - { - that.select([id]); - } - else - { - that.deselect([id]); - } - }); - } +function registerRowEvents(tbody) +{ + var that = this, + selectBoxSelector = getCssSelector(this.options.css.selectBox); - tbody.off("click" + namespace, "> tr") - .on("click" + namespace, "> tr", function(e) + if (this.selection) + { + tbody.off("click" + namespace, selectBoxSelector) + .on("click" + namespace, selectBoxSelector, function(e) { e.stopPropagation(); var $this = $(this), - id = (that.identifier == null) ? $this.data("row-id") : - that.converter.from($this.data("row-id") + ""), - row = (that.identifier == null) ? that.currentRows[id] : - that.currentRows.first(function (item) { return item[that.identifier] === id; }); + id = that.converter.from($this.val()); - if (that.selection && that.options.rowSelect) + if ($this.prop("checked")) { - if ($this.hasClass(that.options.css.selected)) - { - that.deselect([id]); - } - else - { - that.select([id]); - } + that.select([id]); + } + else + { + that.deselect([id]); } - - that.element.trigger("click" + namespace, [that.columns, row]); }); } - function renderSearchField() - { - if (this.options.navigation !== 0) + tbody.off("click" + namespace, "> tr") + .on("click" + namespace, "> tr", function(e) { - var css = this.options.css, - selector = getCssSelector(css.search), - headerSearch = this.header.find(selector), - footerSearch = this.footer.find(selector); + e.stopPropagation(); + + var $this = $(this), + id = (that.identifier == null) ? $this.data("row-id") : + that.converter.from($this.data("row-id") + ""), + row = (that.identifier == null) ? that.currentRows[id] : + that.currentRows.first(function (item) { return item[that.identifier] === id; }); + + if (that.selection && that.options.rowSelect) + { + if ($this.hasClass(that.options.css.selected)) + { + that.deselect([id]); + } + else + { + that.select([id]); + } + } - if ((headerSearch.length + footerSearch.length) > 0) + that.element.trigger("click" + namespace, [that.columns, row]); + }); +} + +function renderSearchField() +{ + if (this.options.navigation !== 0) + { + var css = this.options.css, + selector = getCssSelector(css.search), + headerSearch = this.header.find(selector), + footerSearch = this.footer.find(selector); + + if ((headerSearch.length + footerSearch.length) > 0) + { + var that = this, + tpl = this.options.templates, + timer = null, // fast keyup detection + currentValue = "", + searchFieldSelector = getCssSelector(css.searchField), + search = $(tpl.search.resolve(getParams.call(this))), + searchField = (search.is(searchFieldSelector)) ? search : + search.find(searchFieldSelector); + + searchField.on("keyup" + namespace, function (e) { - var that = this, - tpl = this.options.templates, - timer = null, // fast keyup detection - currentValue = "", - searchFieldSelector = getCssSelector(css.searchField), - search = $(tpl.search.resolve(getParams.call(this))), - searchField = (search.is(searchFieldSelector)) ? search : - search.find(searchFieldSelector); - - searchField.on("keyup" + namespace, function (e) + e.stopPropagation(); + var newValue = $(this).val(); + if (currentValue !== newValue) { - e.stopPropagation(); - var newValue = $(this).val(); - if (currentValue !== newValue) + currentValue = newValue; + window.clearTimeout(timer); + timer = window.setTimeout(function () { - currentValue = newValue; - window.clearTimeout(timer); - timer = window.setTimeout(function () - { - that.search(newValue); - }, 250); - } - }); + that.search(newValue); + }, 250); + } + }); - replacePlaceHolder.call(this, headerSearch, search, 1); - replacePlaceHolder.call(this, footerSearch, search, 2); - } + replacePlaceHolder.call(this, headerSearch, search, 1); + replacePlaceHolder.call(this, footerSearch, search, 2); } } +} - function renderTableHeader() +function renderTableHeader() +{ + var that = this, + headerRow = this.element.find("thead > tr"), + css = this.options.css, + tpl = this.options.templates, + html = "", + sorting = this.options.sorting; + + if (this.selection) { - var that = this, - headerRow = this.element.find("thead > tr"), - css = this.options.css, - tpl = this.options.templates, - html = "", - sorting = this.options.sorting; + var selectBox = (this.options.multiSelect) ? + tpl.select.resolve(getParams.call(that, { type: "checkbox", value: "all" })) : ""; + html += tpl.rawHeaderCell.resolve(getParams.call(that, { content: selectBox, + css: css.selectCell })); + } - if (this.selection) + $.each(this.columns, function (index, column) + { + if (column.visible) { - var selectBox = (this.options.multiSelect) ? - tpl.select.resolve(getParams.call(that, { type: "checkbox", value: "all" })) : ""; - html += tpl.rawHeaderCell.resolve(getParams.call(that, { content: selectBox, - css: css.selectCell })); + var sortOrder = that.sort[column.id], + iconCss = ((sorting && sortOrder && sortOrder === "asc") ? css.iconUp : + (sorting && sortOrder && sortOrder === "desc") ? css.iconDown : ""), + icon = tpl.icon.resolve(getParams.call(that, { iconCss: iconCss })), + align = column.headerAlign, + cssClass = (column.headerCssClass.length > 0) ? " " + column.headerCssClass : ""; + html += tpl.headerCell.resolve(getParams.call(that, { + column: column, icon: icon, sortable: sorting && column.sortable && css.sortable || "", + css: ((align === "right") ? css.right : (align === "center") ? + css.center : css.left) + cssClass })); } + }); - $.each(this.columns, function (index, column) - { - if (column.visible) - { - var sortOrder = that.sort[column.id], - iconCss = ((sorting && sortOrder && sortOrder === "asc") ? css.iconUp : - (sorting && sortOrder && sortOrder === "desc") ? css.iconDown : ""), - icon = tpl.icon.resolve(getParams.call(that, { iconCss: iconCss })), - align = column.headerAlign, - cssClass = (column.headerCssClass.length > 0) ? " " + column.headerCssClass : ""; - html += tpl.headerCell.resolve(getParams.call(that, { - column: column, icon: icon, sortable: sorting && column.sortable && css.sortable || "", - css: ((align === "right") ? css.right : (align === "center") ? - css.center : css.left) + cssClass })); - } - }); + headerRow.html(html); - headerRow.html(html); + // todo: create a own function for that piece of code + if (sorting) + { + var sortingSelector = getCssSelector(css.sortable), + iconSelector = getCssSelector(css.icon); + headerRow.off("click" + namespace, sortingSelector) + .on("click" + namespace, sortingSelector, function (e) + { + e.preventDefault(); + var $this = $(this), + columnId = $this.data("column-id") || $this.parents("th").first().data("column-id"), + sortOrder = that.sort[columnId], + icon = $this.find(iconSelector); - // todo: create a own function for that piece of code - if (sorting) - { - var sortingSelector = getCssSelector(css.sortable), - iconSelector = getCssSelector(css.icon); - headerRow.off("click" + namespace, sortingSelector) - .on("click" + namespace, sortingSelector, function (e) + if (!that.options.multiSort) { - e.preventDefault(); - var $this = $(this), - columnId = $this.data("column-id") || $this.parents("th").first().data("column-id"), - sortOrder = that.sort[columnId], - icon = $this.find(iconSelector); - - if (!that.options.multiSort) - { - $this.parents("tr").first().find(iconSelector).removeClass(css.iconDown + " " + css.iconUp); - that.sort = {}; - } + $this.parents("tr").first().find(iconSelector).removeClass(css.iconDown + " " + css.iconUp); + that.sort = {}; + } - if (sortOrder && sortOrder === "asc") - { - that.sort[columnId] = "desc"; - icon.removeClass(css.iconUp).addClass(css.iconDown); - } - else if (sortOrder && sortOrder === "desc") + if (sortOrder && sortOrder === "asc") + { + that.sort[columnId] = "desc"; + icon.removeClass(css.iconUp).addClass(css.iconDown); + } + else if (sortOrder && sortOrder === "desc") + { + if (that.options.multiSort) { - if (that.options.multiSort) + var newSort = {}; + for (var key in that.sort) { - var newSort = {}; - for (var key in that.sort) + if (key !== columnId) { - if (key !== columnId) - { - newSort[key] = that.sort[key]; - } + newSort[key] = that.sort[key]; } - that.sort = newSort; - icon.removeClass(css.iconDown); - } - else - { - that.sort[columnId] = "asc"; - icon.removeClass(css.iconDown).addClass(css.iconUp); } + that.sort = newSort; + icon.removeClass(css.iconDown); } else { that.sort[columnId] = "asc"; - icon.addClass(css.iconUp); + icon.removeClass(css.iconDown).addClass(css.iconUp); } - - sortRows.call(that); - loadData.call(that); - }); - } - - // todo: create a own function for that piece of code - if (this.selection && this.options.multiSelect) - { - var selectBoxSelector = getCssSelector(css.selectBox); - headerRow.off("click" + namespace, selectBoxSelector) - .on("click" + namespace, selectBoxSelector, function(e) + } + else { - e.stopPropagation(); + that.sort[columnId] = "asc"; + icon.addClass(css.iconUp); + } - if ($(this).prop("checked")) - { - that.select(); - } - else - { - that.deselect(); - } - }); - } + sortRows.call(that); + loadData.call(that); + }); } - function replacePlaceHolder(placeholder, element, flag) + // todo: create a own function for that piece of code + if (this.selection && this.options.multiSelect) { - if (this.options.navigation & flag) - { - placeholder.each(function (index, item) + var selectBoxSelector = getCssSelector(css.selectBox); + headerRow.off("click" + namespace, selectBoxSelector) + .on("click" + namespace, selectBoxSelector, function(e) { - // todo: check how append is implemented. Perhaps cloning here is superfluous. - $(item).before(element.clone(true)).remove(); + e.stopPropagation(); + + if ($(this).prop("checked")) + { + that.select(); + } + else + { + that.deselect(); + } }); - } } +} - function showLoading() +function replacePlaceHolder(placeholder, element, flag) +{ + if (this.options.navigation & flag) { - var tpl = this.options.templates, - thead = this.element.children("thead").first(), - tbody = this.element.children("tbody").first(), - firstCell = tbody.find("tr > td").first(), - padding = (this.element.height() - thead.height()) - (firstCell.height() + 20), - count = this.columns.where(isVisible).length; - - if (this.selection) + placeholder.each(function (index, item) { - count = count + 1; - } - tbody.html(tpl.loading.resolve(getParams.call(this, { columns: count }))); - if (this.rowCount !== -1 && padding > 0) - { - tbody.find("tr > td").css("padding", "20px 0 " + padding + "px"); - } + // todo: check how append is implemented. Perhaps cloning here is superfluous. + $(item).before(element.clone(true)).remove(); + }); } +} - function sortRows() +function showLoading() +{ + var tpl = this.options.templates, + thead = this.element.children("thead").first(), + tbody = this.element.children("tbody").first(), + firstCell = tbody.find("tr > td").first(), + padding = (this.element.height() - thead.height()) - (firstCell.height() + 20), + count = this.columns.where(isVisible).length; + + if (this.selection) { - var sortArray = []; + count = count + 1; + } + tbody.html(tpl.loading.resolve(getParams.call(this, { columns: count }))); + if (this.rowCount !== -1 && padding > 0) + { + tbody.find("tr > td").css("padding", "20px 0 " + padding + "px"); + } +} - function sort(x, y, current) - { - current = current || 0; - var next = current + 1, - item = sortArray[current]; +function sortRows() +{ + var sortArray = []; - function sortOrder(value) - { - return (item.order === "asc") ? value : value * -1; - } + function sort(x, y, current) + { + current = current || 0; + var next = current + 1, + item = sortArray[current]; - return (x[item.id] > y[item.id]) ? sortOrder(1) : - (x[item.id] < y[item.id]) ? sortOrder(-1) : - (sortArray.length > next) ? sort(x, y, next) : 0; + function sortOrder(value) + { + return (item.order === "asc") ? value : value * -1; } - if (!this.options.ajax) - { - var that = this; + return (x[item.id] > y[item.id]) ? sortOrder(1) : + (x[item.id] < y[item.id]) ? sortOrder(-1) : + (sortArray.length > next) ? sort(x, y, next) : 0; + } - for (var key in this.sort) - { - if (this.options.multiSort || sortArray.length === 0) - { - sortArray.push({ - id: key, - order: this.sort[key] - }); - } - } + if (!this.options.ajax) + { + var that = this; - if (sortArray.length > 0) + for (var key in this.sort) + { + if (this.options.multiSort || sortArray.length === 0) { - this.rows.sort(sort); + sortArray.push({ + id: key, + order: this.sort[key] + }); } } + + if (sortArray.length > 0) + { + this.rows.sort(sort); + } + } } - // GRID PUBLIC CLASS DEFINITION - // ==================== +// GRID PUBLIC CLASS DEFINITION +// ==================== + +/** + * Represents the jQuery Bootgrid plugin. + * + * @class Grid + * @constructor + * @param element {Object} The corresponding DOM element. + * @param options {Object} The options to override default settings. + * @chainable + **/ +var Grid = function(element, options) +{ + this.element = $(element); + this.origin = this.element.clone(); + this.options = $.extend(true, {}, Grid.defaults, this.element.data(), options); + // overrides rowCount explicitly because deep copy ($.extend) leads to strange behaviour + var rowCount = this.options.rowCount = this.element.data().rowCount || options.rowCount || this.options.rowCount; + this.columns = []; + this.current = 1; + this.currentRows = []; + this.identifier = null; // The first column ID that is marked as identifier + this.selection = false; + this.converter = null; // The converter for the column that is marked as identifier + this.rowCount = ($.isArray(rowCount)) ? rowCount[0] : rowCount; + this.rows = []; + this.searchPhrase = ""; + this.selectedRows = []; + this.sort = {}; + this.total = 0; + this.totalPages = 0; + this.cachedParams = { + lbl: this.options.labels, + css: this.options.css, + ctx: {} + }; + this.header = null; + this.footer = null; + this.xqr = null; + + // todo: implement cache +}; + +/** + * An object that represents the default settings. + * There are two ways to override the sub-properties. + * Either by doing it generally (global) or on initialization. + * + * @static + * @class defaults + * @for Grid + * @example + * // Global approach + * $.bootgrid.defaults.selection = true; + * @example + * // Initialization approach + * $("#bootgrid").bootgrid({ selection = true }); + **/ +Grid.defaults = { + navigation: 3, // it's a flag: 0 = none, 1 = top, 2 = bottom, 3 = both (top and bottom) + padding: 2, // page padding (pagination) + columnSelection: true, + rowCount: [10, 25, 50, -1], // rows per page int or array of int (-1 represents "All") /** - * Represents the jQuery Bootgrid plugin. + * Enables row selection (to enable multi selection see also `multiSelect`). Default value is `false`. * - * @class Grid - * @constructor - * @param element {Object} The corresponding DOM element. - * @param options {Object} The options to override default settings. - * @chainable + * @property selection + * @type Boolean + * @default false + * @for defaults + * @since 1.0.0 **/ - var Grid = function(element, options) - { - this.element = $(element); - this.origin = this.element.clone(); - this.options = $.extend(true, {}, Grid.defaults, this.element.data(), options); - // overrides rowCount explicitly because deep copy ($.extend) leads to strange behaviour - var rowCount = this.options.rowCount = this.element.data().rowCount || options.rowCount || this.options.rowCount; - this.columns = []; - this.current = 1; - this.currentRows = []; - this.identifier = null; // The first column ID that is marked as identifier - this.selection = false; - this.converter = null; // The converter for the column that is marked as identifier - this.rowCount = ($.isArray(rowCount)) ? rowCount[0] : rowCount; - this.rows = []; - this.searchPhrase = ""; - this.selectedRows = []; - this.sort = {}; - this.total = 0; - this.totalPages = 0; - this.cachedParams = { - lbl: this.options.labels, - css: this.options.css, - ctx: {} - }; - this.header = null; - this.footer = null; - this.xqr = null; - - // todo: implement cache - }; + selection: false, /** - * An object that represents the default settings. - * There are two ways to override the sub-properties. - * Either by doing it generally (global) or on initialization. + * Enables multi selection (`selection` must be set to `true` as well). Default value is `false`. * - * @static - * @class defaults - * @for Grid - * @example - * // Global approach - * $.bootgrid.defaults.selection = true; - * @example - * // Initialization approach - * $("#bootgrid").bootgrid({ selection = true }); + * @property multiSelect + * @type Boolean + * @default false + * @for defaults + * @since 1.0.0 **/ - Grid.defaults = { - navigation: 3, // it's a flag: 0 = none, 1 = top, 2 = bottom, 3 = both (top and bottom) - padding: 2, // page padding (pagination) - columnSelection: true, - rowCount: [10, 25, 50, -1], // rows per page int or array of int (-1 represents "All") - - /** - * Enables row selection (to enable multi selection see also `multiSelect`). Default value is `false`. - * - * @property selection - * @type Boolean - * @default false - * @for defaults - * @since 1.0.0 - **/ - selection: false, - - /** - * Enables multi selection (`selection` must be set to `true` as well). Default value is `false`. - * - * @property multiSelect - * @type Boolean - * @default false - * @for defaults - * @since 1.0.0 - **/ - multiSelect: false, + multiSelect: false, - /** - * Enables entire row click selection (`selection` must be set to `true` as well). Default value is `false`. - * - * @property rowSelect - * @type Boolean - * @default false - * @for defaults - * @since 1.1.0 - **/ - rowSelect: false, + /** + * Enables entire row click selection (`selection` must be set to `true` as well). Default value is `false`. + * + * @property rowSelect + * @type Boolean + * @default false + * @for defaults + * @since 1.1.0 + **/ + rowSelect: false, - /** - * Defines whether the row selection is saved internally on filtering, paging and sorting - * (even if the selected rows are not visible). - * - * @property keepSelection - * @type Boolean - * @default false - * @for defaults - * @since 1.1.0 - **/ - keepSelection: false, + /** + * Defines whether the row selection is saved internally on filtering, paging and sorting + * (even if the selected rows are not visible). + * + * @property keepSelection + * @type Boolean + * @default false + * @for defaults + * @since 1.1.0 + **/ + keepSelection: false, - highlightRows: false, // highlights new rows (find the page of the first new row) - sorting: true, - multiSort: false, - ajax: false, // todo: find a better name for this property to differentiate between client-side and server-side data + highlightRows: false, // highlights new rows (find the page of the first new row) + sorting: true, + multiSort: false, + ajax: false, // todo: find a better name for this property to differentiate between client-side and server-side data - /** - * Enriches the request object with additional properties. Either a `PlainObject` or a `Function` - * that returns a `PlainObject` can be passed. Default value is `{}`. - * - * @property post - * @type Object|Function - * @default function (request) { return request; } - * @for defaults - * @deprecated Use instead `requestHandler` - **/ - post: {}, // or use function () { return {}; } (reserved properties are "current", "rowCount", "sort" and "searchPhrase") + /** + * Enriches the request object with additional properties. Either a `PlainObject` or a `Function` + * that returns a `PlainObject` can be passed. Default value is `{}`. + * + * @property post + * @type Object|Function + * @default function (request) { return request; } + * @for defaults + * @deprecated Use instead `requestHandler` + **/ + post: {}, // or use function () { return {}; } (reserved properties are "current", "rowCount", "sort" and "searchPhrase") - /** - * Sets the data URL to a data service (e.g. a REST service). Either a `String` or a `Function` - * that returns a `String` can be passed. Default value is `""`. - * - * @property url - * @type String|Function - * @default "" - * @for defaults - **/ - url: "", // or use function () { return ""; } + /** + * Sets the data URL to a data service (e.g. a REST service). Either a `String` or a `Function` + * that returns a `String` can be passed. Default value is `""`. + * + * @property url + * @type String|Function + * @default "" + * @for defaults + **/ + url: "", // or use function () { return ""; } - /** - * Defines whether the search is case sensitive or insensitive. - * - * @property caseSensitive - * @type Boolean - * @default true - * @for defaults - * @since 1.1.0 - **/ - caseSensitive: true, + /** + * Defines whether the search is case sensitive or insensitive. + * + * @property caseSensitive + * @type Boolean + * @default true + * @for defaults + * @since 1.1.0 + **/ + caseSensitive: true, - // note: The following properties should not be used via data-api attributes + // note: The following properties should not be used via data-api attributes - /** - * Transforms the JSON request object in what ever is needed on the server-side implementation. - * - * @property requestHandler - * @type Function - * @default function (request) { return request; } - * @for defaults - * @since 1.1.0 - **/ - requestHandler: function (request) { return request; }, + /** + * Transforms the JSON request object in what ever is needed on the server-side implementation. + * + * @property requestHandler + * @type Function + * @default function (request) { return request; } + * @for defaults + * @since 1.1.0 + **/ + requestHandler: function (request) { return request; }, - /** - * Transforms the response object into the expected JSON response object. - * - * @property responseHandler - * @type Function - * @default function (response) { return response; } - * @for defaults - * @since 1.1.0 - **/ - responseHandler: function (response) { return response; }, + /** + * Transforms the response object into the expected JSON response object. + * + * @property responseHandler + * @type Function + * @default function (response) { return response; } + * @for defaults + * @since 1.1.0 + **/ + responseHandler: function (response) { return response; }, - /** - * A list of converters. - * - * @property converters - * @type Object - * @for defaults - * @since 1.0.0 - **/ - converters: { - numeric: { - from: function (value) { return +value; }, // converts from string to numeric - to: function (value) { return value + ""; } // converts from numeric to string - }, - string: { - // default converter - from: function (value) { return value; }, - to: function (value) { return value; } - } + /** + * A list of converters. + * + * @property converters + * @type Object + * @for defaults + * @since 1.0.0 + **/ + converters: { + numeric: { + from: function (value) { return +value; }, // converts from string to numeric + to: function (value) { return value + ""; } // converts from numeric to string }, + string: { + // default converter + from: function (value) { return value; }, + to: function (value) { return value; } + } + }, - /** - * Contains all css classes. - * - * @property css - * @type Object - * @for defaults - **/ - css: { - actions: "actions btn-group", // must be a unique class name or constellation of class names within the header and footer - center: "text-center", - columnHeaderAnchor: "column-header-anchor", // must be a unique class name or constellation of class names within the column header cell - columnHeaderText: "text", - dropDownItem: "dropdown-item", // must be a unique class name or constellation of class names within the actionDropDown, - dropDownItemButton: "dropdown-item-button", // must be a unique class name or constellation of class names within the actionDropDown - dropDownItemCheckbox: "dropdown-item-checkbox", // must be a unique class name or constellation of class names within the actionDropDown - dropDownMenu: "dropdown btn-group", // must be a unique class name or constellation of class names within the actionDropDown - dropDownMenuItems: "dropdown-menu pull-right", // must be a unique class name or constellation of class names within the actionDropDown - dropDownMenuText: "dropdown-text", // must be a unique class name or constellation of class names within the actionDropDown - footer: "bootgrid-footer container-fluid", - header: "bootgrid-header container-fluid", - icon: "icon glyphicon", - iconColumns: "glyphicon-th-list", - iconDown: "glyphicon-chevron-down", - iconRefresh: "glyphicon-refresh", - iconUp: "glyphicon-chevron-up", - infos: "infos", // must be a unique class name or constellation of class names within the header and footer, - left: "text-left", - pagination: "pagination", // must be a unique class name or constellation of class names within the header and footer - paginationButton: "button", // must be a unique class name or constellation of class names within the pagination - - /** - * CSS class to select the parent div which activates responsive mode. - * - * @property responsiveTable - * @type String - * @default "table-responsive" - * @for css - * @since 1.1.0 - **/ - responsiveTable: "table-responsive", - - right: "text-right", - search: "search form-group", // must be a unique class name or constellation of class names within the header and footer - searchField: "search-field form-control", - selectBox: "select-box", // must be a unique class name or constellation of class names within the entire table - selectCell: "select-cell", // must be a unique class name or constellation of class names within the entire table - - /** - * CSS class to highlight selected rows. - * - * @property selected - * @type String - * @default "active" - * @for css - * @since 1.1.0 - **/ - selected: "active", - - sortable: "sortable", - table: "bootgrid-table table" - }, + /** + * Contains all css classes. + * + * @property css + * @type Object + * @for defaults + **/ + css: { + actions: "actions btn-group", // must be a unique class name or constellation of class names within the header and footer + center: "text-center", + columnHeaderAnchor: "column-header-anchor", // must be a unique class name or constellation of class names within the column header cell + columnHeaderText: "text", + dropDownItem: "dropdown-item", // must be a unique class name or constellation of class names within the actionDropDown, + dropDownItemButton: "dropdown-item-button", // must be a unique class name or constellation of class names within the actionDropDown + dropDownItemCheckbox: "dropdown-item-checkbox", // must be a unique class name or constellation of class names within the actionDropDown + dropDownMenu: "dropdown btn-group", // must be a unique class name or constellation of class names within the actionDropDown + dropDownMenuItems: "dropdown-menu pull-right", // must be a unique class name or constellation of class names within the actionDropDown + dropDownMenuText: "dropdown-text", // must be a unique class name or constellation of class names within the actionDropDown + footer: "bootgrid-footer container-fluid", + header: "bootgrid-header container-fluid", + icon: "icon glyphicon", + iconColumns: "glyphicon-th-list", + iconDown: "glyphicon-chevron-down", + iconRefresh: "glyphicon-refresh", + iconUp: "glyphicon-chevron-up", + infos: "infos", // must be a unique class name or constellation of class names within the header and footer, + left: "text-left", + pagination: "pagination", // must be a unique class name or constellation of class names within the header and footer + paginationButton: "button", // must be a unique class name or constellation of class names within the pagination /** - * A dictionary of formatters. + * CSS class to select the parent div which activates responsive mode. * - * @property formatters - * @type Object - * @for defaults - * @since 1.0.0 + * @property responsiveTable + * @type String + * @default "table-responsive" + * @for css + * @since 1.1.0 **/ - formatters: {}, + responsiveTable: "table-responsive", - /** - * Contains all labels. - * - * @property labels - * @type Object - * @for defaults - **/ - labels: { - all: "All", - infos: "Showing {{ctx.start}} to {{ctx.end}} of {{ctx.total}} entries", - loading: "Loading...", - noResults: "No results found!", - refresh: "Refresh", - search: "Search" - }, + right: "text-right", + search: "search form-group", // must be a unique class name or constellation of class names within the header and footer + searchField: "search-field form-control", + selectBox: "select-box", // must be a unique class name or constellation of class names within the entire table + selectCell: "select-cell", // must be a unique class name or constellation of class names within the entire table /** - * Contains all templates. + * CSS class to highlight selected rows. * - * @property templates - * @type Object - * @for defaults + * @property selected + * @type String + * @default "active" + * @for css + * @since 1.1.0 **/ - templates: { - actionButton: "", - actionDropDown: "