From fe3f95e569b61ddbd18bad5a2930115988eefcdc Mon Sep 17 00:00:00 2001 From: Zac Spitzer Date: Mon, 12 Oct 2015 12:08:01 +1100 Subject: [PATCH 01/13] Update internal.js there is no need to clone() here, it creates a memory leak as it's not attached the to DOM and therefore isn't removed by remove() --- src/internal.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/internal.js b/src/internal.js index 9b9bba4..1d7984e 100644 --- a/src/internal.js +++ b/src/internal.js @@ -873,7 +873,7 @@ function replacePlaceHolder(placeholder, element) placeholder.each(function (index, item) { // todo: check how append is implemented. Perhaps cloning here is superfluous. - $(item).before(element.clone(true)).remove(); + $(item).before(element).remove(); }); } @@ -945,4 +945,4 @@ function sortRows() this.rows.sort(sort); } } -} \ No newline at end of file +} From 1225b4a0475bcf57fc88dc9f98d284299f466ff2 Mon Sep 17 00:00:00 2001 From: Zac Spitzer Date: Fri, 30 Oct 2015 14:29:05 +1100 Subject: [PATCH 02/13] Add an event columnToggle Trigger an event when columns are toggled on or off --- src/internal.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/internal.js b/src/internal.js index 1d7984e..5ed0af8 100644 --- a/src/internal.js +++ b/src/internal.js @@ -393,6 +393,7 @@ function renderColumnSelection(actions) that.element.find("tbody").empty(); // Fixes an column visualization bug renderTableHeader.call(that); loadData.call(that); + that.element.trigger("columnToggle" + namespace, column); } }); dropDown.find(getCssSelector(css.dropDownMenuItems)).append(item); From 2d26feab84017344a679b45f5bbfdb54149941ae Mon Sep 17 00:00:00 2001 From: Zac Spitzer Date: Thu, 15 Sep 2016 11:48:17 +0200 Subject: [PATCH 03/13] Drastically faster templating approach The current templating approach is really inefficient, as it recursively loops thru every passed available variable for substituion and applies a regex for each one. It's much faster to initially parse the template and then only process those strings which are actually present in the template. This revised implementation both caches the parsed templates and then only processes the string which are present. The performance improvement is quite drastic, especially with large tables. A large table was previously taking 15s to render in Chrome, now takes less than 1s with this approach --- src/extensions.js | 74 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 54 insertions(+), 20 deletions(-) diff --git a/src/extensions.js b/src/extensions.js index cb37139..4956360 100644 --- a/src/extensions.js +++ b/src/extensions.js @@ -65,32 +65,66 @@ if (!String.prototype.resolve) return value; } }; + + var _templateCache = {}; + var getTemplate = function(template){ + if (!_templateCache.hasOwnProperty(template)){ + var str = template.split(/{([^{}]+)}/g); + + for (var i = 0; i < str.length; i++){ + var s = str[i]; + var hasStart = (s.charAt(0) === "}"); + var hasEnd = (s.charAt(s.length - 1) === "{"); + if (hasStart) + s = s.substr(1); + if (hasEnd) + s = s.substr(0, s.length - 1); + + if (hasStart || hasEnd){ + str[i] = s; //plain old html + } else { + str[i] = { + token: str[i], + key: s.split(".") + }; + } + } + _templateCache[template] = str; + } + return _templateCache[template]; + }; String.prototype.resolve = function (substitutes, prefixes) { - var result = this; - $.each(substitutes, function (key, value) - { - if (value != null && typeof value !== "function") - { - if (typeof value === "object") - { - var keys = (prefixes) ? $.extend([], prefixes) : []; - keys.push(key); - result = result.resolve(value, keys) + ""; - } + var str = getTemplate(this); + var result = ""; + for (var i = 0; i < str.length; i++){ + if (typeof str[i] === "object"){ + var key = str[i].key; + // now we have a variable to be substitued + if (substitutes.hasOwnProperty(key[0])) + var v = substitutes[key[0]]; else - { - if (formatter && formatter[key] && typeof formatter[key] === "function") - { - value = formatter[key](value); + continue; + + for (var k = 1; k < key.length; k++){ + if (v.hasOwnProperty(key[k])){ + v = v[key[k]]; + } else { + v = null; + break; } - key = (prefixes) ? prefixes.join(".") + "." + key : key; - var pattern = new RegExp("\\{\\{" + key + "\\}\\}", "gm"); - result = result.replace(pattern, (value.replace) ? value.replace(/\$/gi, "$") : value); } + var formatter_key = key[key.length-1]; + if (formatter && formatter[formatter_key] && typeof formatter[formatter_key] === "function"){ + result += formatter[formatter_key](v); + } else { + result += v; + } + } else { + result += str[i]; // plain old html } - }); + } return result; }; } @@ -167,4 +201,4 @@ if (!Array.prototype.propValues) } return result; }; -} \ No newline at end of file +} From d33185db250f7e109d80ba0cb49b69d1bffc0f1a Mon Sep 17 00:00:00 2001 From: Zac Spitzer Date: Thu, 15 Sep 2016 11:55:46 +0200 Subject: [PATCH 04/13] Update extensions.js --- src/extensions.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/extensions.js b/src/extensions.js index 4956360..968da4d 100644 --- a/src/extensions.js +++ b/src/extensions.js @@ -101,9 +101,10 @@ if (!String.prototype.resolve) for (var i = 0; i < str.length; i++){ if (typeof str[i] === "object"){ var key = str[i].key; + var v = ""; // now we have a variable to be substitued if (substitutes.hasOwnProperty(key[0])) - var v = substitutes[key[0]]; + v = substitutes[key[0]]; else continue; From 8d11d27a72c6b5d73d9a4d0c686296c457456802 Mon Sep 17 00:00:00 2001 From: Zac Spitzer Date: Thu, 15 Sep 2016 12:00:50 +0200 Subject: [PATCH 05/13] lint clean up --- src/extensions.js | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/extensions.js b/src/extensions.js index 968da4d..cab961c 100644 --- a/src/extensions.js +++ b/src/extensions.js @@ -76,11 +76,16 @@ if (!String.prototype.resolve) var hasStart = (s.charAt(0) === "}"); var hasEnd = (s.charAt(s.length - 1) === "{"); if (hasStart) + { s = s.substr(1); + } if (hasEnd) + { s = s.substr(0, s.length - 1); + } - if (hasStart || hasEnd){ + if (hasStart || hasEnd) + { str[i] = s; //plain old html } else { str[i] = { @@ -104,9 +109,13 @@ if (!String.prototype.resolve) var v = ""; // now we have a variable to be substitued if (substitutes.hasOwnProperty(key[0])) + { v = substitutes[key[0]]; + } else + { continue; + } for (var k = 1; k < key.length; k++){ if (v.hasOwnProperty(key[k])){ From f7cfe39c2c7ede5e8cc285a7d159c34ddb396b8c Mon Sep 17 00:00:00 2001 From: Zac Spitzer Date: Fri, 9 Dec 2016 11:45:21 +1100 Subject: [PATCH 06/13] move label infos templated string into templates rather than needing to recursively process every string, move the templated string for infos into the template definitions --- src/public.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/public.js b/src/public.js index 16c5c44..16c001f 100644 --- a/src/public.js +++ b/src/public.js @@ -334,7 +334,10 @@ Grid.defaults = { **/ labels: { all: "All", - infos: "Showing {{ctx.start}} to {{ctx.end}} of {{ctx.total}} entries", + showing: "Showing", + to: "to", + of: "of", + entries: "entries", loading: "Loading...", noResults: "No results found!", refresh: "Refresh", @@ -406,7 +409,7 @@ Grid.defaults = { header: "

", headerCell: "{{ctx.column.text}}{{ctx.icon}}", icon: "", - infos: "
{{lbl.infos}}
", + infos: "
{{lbl.showing}} {{ctx.start}} {{lbl.to}} {{ctx.end}} {{lbl.of}} {{ctx.total}} {{lbl.entries}}
", loading: "{{lbl.loading}}", noResults: "{{lbl.noResults}}", pagination: "
    ", @@ -853,4 +856,4 @@ Grid.prototype.getTotalPageCount = function() Grid.prototype.getTotalRowCount = function() { return this.total; -}; \ No newline at end of file +}; From 0c66fe29a5e89de7b352c364b8143bc7defeb0d8 Mon Sep 17 00:00:00 2001 From: Zac Spitzer Date: Sat, 10 Dec 2016 13:26:50 +1100 Subject: [PATCH 07/13] added more append options + timing added buttons to append 10, 100 and 1000 rows with logging of rendering time (on screen and to console) --- demo/index.htm | 68 +++++++++++++++++++++++++++++++++++++------------- 1 file changed, 50 insertions(+), 18 deletions(-) diff --git a/demo/index.htm b/demo/index.htm index ae13225..5f8ee8b 100644 --- a/demo/index.htm +++ b/demo/index.htm @@ -47,7 +47,6 @@
    - @@ -61,12 +60,20 @@ + +
    + + + + +
    + - - + + @@ -193,22 +200,47 @@ }); } + var timerKey = 'initRender'; + var timerStart = null; + $("#grid").on("loaded.rs.jquery.bootgrid", function (e){ + if (timerKey) + console.timeEnd(timerKey); + if (timerStart) + $(".loading").text("rendered time: " + (new Date().getTime() - timerStart) + "ms"); + timerKey = null; + timerStart = null; + }); + + function startTimer(key){ + $(".loading").html(timerKey + "loading..."); + console.time(timerKey); + timerStart = new Date(); + } + + startTimer(timerKey); init(); - - $("#append").on("click", function () + appendCounter = 100; + + $(".append").on("click", function (e) { - $("#grid").bootgrid("append", [{ - id: 0, - sender: "hh@derhase.de", - received: "Gestern", - link: "" - }, - { - id: 12, - sender: "er@fsdfs.de", - received: "Heute", - link: "" - }]); + var data = []; + var rows = $(e.target).data('rows'); + for (var i=0; i < rows; i++) + { + var row = { + id: i+appendCounter, + sender: "sample@example.com", + received: new Date(new Date().getTime()+(i*24*60*60*1000)).toString(), + link: "link", + status: "status" + i, + hidden: (i % 2 === 0) ? "yes" : "no" + }; + data.push(row); + } + appendCounter = appendCounter + rows; + timerKey = "[appendData: " + rows + " rows] "; + startTimer(timerKey); + $("#grid").bootgrid("append", data); }); $("#clear").on("click", function () @@ -275,4 +307,4 @@ }); - \ No newline at end of file + From e96981a203da92d72403190773380e1dd7f0fc1c Mon Sep 17 00:00:00 2001 From: Zac Spitzer Date: Sat, 10 Dec 2016 14:06:54 +1100 Subject: [PATCH 08/13] avoid null result don't set the replacement value to null when a property doesn't exist --- src/extensions.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/extensions.js b/src/extensions.js index cab961c..591b37e 100644 --- a/src/extensions.js +++ b/src/extensions.js @@ -121,7 +121,7 @@ if (!String.prototype.resolve) if (v.hasOwnProperty(key[k])){ v = v[key[k]]; } else { - v = null; + v = ""; break; } } From 52e55ad0259f20bb27ef883efb6e8925fc20c75b Mon Sep 17 00:00:00 2001 From: Zac Spitzer Date: Sat, 10 Dec 2016 14:12:13 +1100 Subject: [PATCH 09/13] test to compare final results added back in the old method and evaluate the template string using both approaches, log out to console any different results found --- src/extensions.js | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/src/extensions.js b/src/extensions.js index 591b37e..1e70467 100644 --- a/src/extensions.js +++ b/src/extensions.js @@ -98,6 +98,37 @@ if (!String.prototype.resolve) } return _templateCache[template]; }; + + // ONLY FOR TESTING + String.prototype.resolve_old = function (substitutes, prefixes) + { + var result = this; + + $.each(substitutes, function (key, value) + { + if (value != null && typeof value !== "function") + { + if (typeof value === "object") + { + var keys = (prefixes) ? $.extend([], prefixes) : []; + keys.push(key); + result = result.resolve_old(value, keys) + ""; + } + else + { + if (formatter && formatter[key] && typeof formatter[key] === "function") + { + value = formatter[key](value); + } + key = (prefixes) ? prefixes.join(".") + "." + key : key; + var pattern = new RegExp("\\{\\{" + key + "\\}\\}", "gm"); + result = result.replace(pattern, (value.replace) ? value.replace(/\$/gi, "$") : value); + } + } + }); + + return result; + }; String.prototype.resolve = function (substitutes, prefixes) { @@ -135,6 +166,13 @@ if (!String.prototype.resolve) result += str[i]; // plain old html } } + // ONLY FOR TESTING, remove for release or testing performance of individal approaches + var result_old = this.resolve_old(substitutes, prefixes); + if (result !== result_old){ + console.warn("Different templating result"); + console.log("new: ", result); + console.log("old: ", result_old); + } return result; }; } From cef18bcdc3ce544f29fcf5d3ef8b44a28a7ebeb4 Mon Sep 17 00:00:00 2001 From: Zac Spitzer Date: Sat, 10 Dec 2016 19:28:36 +1100 Subject: [PATCH 10/13] refactor out prototypes refactored functions out from string and array protoypes included appendRow changes from #285 (50% faster in Chrome, 10% Edge, 15% FF) --- dist/jquery.bootgrid.js | 377 ++++++++++++++++++++++-------------- dist/jquery.bootgrid.min.js | 6 - src/internal.js | 86 ++++---- src/public.js | 21 +- test/tests-extensions.js | 4 +- 5 files changed, 287 insertions(+), 207 deletions(-) delete mode 100644 dist/jquery.bootgrid.min.js diff --git a/dist/jquery.bootgrid.js b/dist/jquery.bootgrid.js index 4f27d44..a67deb9 100644 --- a/dist/jquery.bootgrid.js +++ b/dist/jquery.bootgrid.js @@ -1,6 +1,6 @@ /*! - * jQuery Bootgrid v1.3.1 - 09/11/2015 - * Copyright (c) 2014-2015 Rafael Staib (http://www.jquery-bootgrid.com) + * jQuery Bootgrid v1.3.1 - 12/10/2016 + * Copyright (c) 2014-2016 Rafael Staib (http://www.jquery-bootgrid.com) * Licensed under MIT http://www.opensource.org/licenses/MIT */ ;(function ($, window, undefined) @@ -25,7 +25,7 @@ return that.identifier && item[that.identifier] === row[that.identifier]; } - if (!this.rows.contains(exists)) + if (!arrayContains(this.rows, exists)) { this.rows.push(row); return true; @@ -34,6 +34,20 @@ return false; } + function appendRows(rows) + { + var that = this; + + var appendedRows = rows.slice(); + appendedRows.filter(function(item) { + return !(that.identifier && item[that.identifier] === rows[that.identifier]); + }); + + this.rows = this.rows.concat(appendedRows); + + return appendedRows; + } + function findFooterAndHeaderItems(selector) { var footer = (this.footer) ? this.footer.find(selector) : $(), @@ -127,7 +141,7 @@ sortable: !(data.sortable === false), // default: true visible: !(data.visible === false), // default: true visibleInSelection: !(data.visibleInSelection === false), // default: true - width: ($.isNumeric(data.width)) ? data.width + "px" : + width: ($.isNumeric(data.width)) ? data.width + "px" : (typeof(data.width) === "string") ? data.width : null }; that.columns.push(column); @@ -254,11 +268,11 @@ } else { - var rows = (this.searchPhrase.length > 0) ? this.rows.where(containsPhrase) : this.rows, + var rows = (this.searchPhrase.length > 0) ? arrayWhere(this.rows, containsPhrase) : this.rows, total = rows.length; if (this.rowCount !== -1) { - rows = rows.page(this.current, this.rowCount); + rows = arrayPage(rows, this.current, this.rowCount); } // todo: improve the following comment @@ -273,7 +287,7 @@ { var that = this, rows = this.element.find("tbody > tr"); - + var convertedRows = []; rows.each(function () { var $this = $(this), @@ -285,9 +299,9 @@ row[column.id] = column.converter.from(cells.eq(i).text()); }); - appendRow.call(that, row); + convertedRows.push(row); }); - + appendRows.call(that, convertedRows); setTotals.call(this, this.rows.length); sortRows.call(this); } @@ -316,13 +330,13 @@ if (this.options.navigation & 1) { - this.header = $(tpl.header.resolve(getParams.call(this, { id: this.element._bgId() + "-header" }))); + this.header = $(template(tpl.header, getParams.call(this, { id: this.element._bgId() + "-header" }))); wrapper.before(this.header); } if (this.options.navigation & 2) { - this.footer = $(tpl.footer.resolve(getParams.call(this, { id: this.element._bgId() + "-footer" }))); + this.footer = $(template(tpl.footer, getParams.call(this, { id: this.element._bgId() + "-footer" }))); wrapper.after(this.footer); } } @@ -339,13 +353,13 @@ { var that = this, tpl = this.options.templates, - actions = $(tpl.actions.resolve(getParams.call(this))); + actions = $(template(tpl.actions, 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, + var refreshIcon = template(tpl.icon, getParams.call(this, { iconCss: css.iconRefresh })), + refresh = $(template(tpl.actionButton, getParams.call(this, { content: refreshIcon, text: this.options.labels.refresh }))) .on("click" + namespace, function (e) { @@ -375,8 +389,8 @@ 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 }))), + icon = template(tpl.icon, getParams.call(this, { iconCss: css.iconColumns })), + dropDown = $(template(tpl.actionDropDown, getParams.call(this, { content: icon }))), selector = getCssSelector(css.dropDownItem), checkboxSelector = getCssSelector(css.dropDownItemCheckbox), itemsSelector = getCssSelector(css.dropDownMenuItems); @@ -385,24 +399,25 @@ { if (column.visibleInSelection) { - var item = $(tpl.actionDropDownCheckboxItem.resolve(getParams.call(that, + var item = $(template(tpl.actionDropDownCheckboxItem, getParams.call(that, { name: column.id, label: column.text, checked: column.visible }))) .on("click" + namespace, selector, function (e) { 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; + var enable = arrayWhere(that.columns, 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.element.trigger("columnToggle" + namespace, column); } }); dropDown.find(getCssSelector(css.dropDownMenuItems)).append(item); @@ -422,7 +437,7 @@ if (infoItems.length > 0) { var end = (this.current * this.rowCount), - infos = $(this.options.templates.infos.resolve(getParams.call(this, { + infos = $(template(this.options.templates.infos, 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 @@ -437,13 +452,13 @@ { var tbody = this.element.children("tbody").first(), tpl = this.options.templates, - count = this.columns.where(isVisible).length; + count = arrayWhere(this.columns, isVisible).length; if (this.selection) { count = count + 1; } - tbody.html(tpl.noResults.resolve(getParams.call(this, { columns: count }))); + tbody.html(template(tpl.noResults, getParams.call(this, { columns: count }))); } function renderPagination() @@ -458,7 +473,7 @@ var tpl = this.options.templates, current = this.current, totalPages = this.totalPages, - pagination = $(tpl.pagination.resolve(getParams.call(this))), + pagination = $(template(tpl.pagination, getParams.call(this))), offsetRight = totalPages - current, offsetLeft = (this.options.padding - current) * -1, startWith = ((offsetRight >= this.options.padding) ? @@ -501,7 +516,7 @@ tpl = this.options.templates, css = this.options.css, values = getParams.call(this, { css: markerCss, text: text, page: page }), - item = $(tpl.paginationItem.resolve(values)) + item = $(template(tpl.paginationItem, values)) .on("click" + namespace, getCssSelector(css.paginationButton), function (e) { e.stopPropagation(); @@ -542,7 +557,7 @@ { var css = this.options.css, tpl = this.options.templates, - dropDown = $(tpl.actionDropDown.resolve(getParams.call(this, { content: getText(this.rowCount) }))), + dropDown = $(template(tpl.actionDropDown, getParams.call(this, { content: getText(this.rowCount) }))), menuSelector = getCssSelector(css.dropDownMenu), menuTextSelector = getCssSelector(css.dropDownMenuText), menuItemsSelector = getCssSelector(css.dropDownMenuItems), @@ -550,7 +565,7 @@ $.each(rowCountList, function (index, value) { - var item = $(tpl.actionDropDownItem.resolve(getParams.call(that, + var item = $(template(tpl.actionDropDownItem, getParams.call(that, { text: getText(value), action: value }))) ._bgSelectAria(value === that.rowCount) .on("click" + namespace, menuItemSelector, function (e) @@ -600,9 +615,9 @@ if (that.selection) { var selected = ($.inArray(row[that.identifier], that.selectedRows) !== -1), - selectBox = tpl.select.resolve(getParams.call(that, + selectBox = template(tpl.select, getParams.call(that, { type: "checkbox", value: row[that.identifier], checked: selected })); - cells += tpl.cell.resolve(getParams.call(that, { content: selectBox, css: css.selectCell })); + cells += template(tpl.cell, getParams.call(that, { content: selectBox, css: css.selectCell })); allRowsSelected = (allRowsSelected && selected); if (selected) { @@ -625,7 +640,7 @@ 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, { + cells += template(tpl.cell, getParams.call(that, { content: (value == null || value === "") ? " " : value, css: ((column.align === "right") ? css.right : (column.align === "center") ? css.center : css.left) + cssClass, @@ -637,7 +652,7 @@ { rowAttr += " class=\"" + rowCss + "\""; } - html += tpl.row.resolve(getParams.call(that, { attr: rowAttr, cells: cells })); + html += template(tpl.row, getParams.call(that, { attr: rowAttr, cells: cells })); }); // sets or clears multi selectbox state @@ -722,7 +737,7 @@ timer = null, // fast keyup detection currentValue = "", searchFieldSelector = getCssSelector(css.searchField), - search = $(tpl.search.resolve(getParams.call(this))), + search = $(template(tpl.search, getParams.call(this))), searchField = (search.is(searchFieldSelector)) ? search : search.find(searchFieldSelector); @@ -771,8 +786,8 @@ if (this.selection) { var selectBox = (this.options.multiSelect) ? - tpl.select.resolve(getParams.call(that, { type: "checkbox", value: "all" })) : ""; - html += tpl.rawHeaderCell.resolve(getParams.call(that, { content: selectBox, + template(tpl.select, getParams.call(that, { type: "checkbox", value: "all" })) : ""; + html += template(tpl.rawHeaderCell, getParams.call(that, { content: selectBox, css: css.selectCell })); } @@ -783,10 +798,10 @@ var sortOrder = that.sortDictionary[column.id], iconCss = ((sorting && sortOrder && sortOrder === "asc") ? css.iconUp : (sorting && sortOrder && sortOrder === "desc") ? css.iconDown : ""), - icon = tpl.icon.resolve(getParams.call(that, { iconCss: iconCss })), + icon = template(tpl.icon, getParams.call(that, { iconCss: iconCss })), align = column.headerAlign, cssClass = (column.headerCssClass.length > 0) ? " " + column.headerCssClass : ""; - html += tpl.headerCell.resolve(getParams.call(that, { + html += template(tpl.headerCell, 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, @@ -883,7 +898,7 @@ placeholder.each(function (index, item) { // todo: check how append is implemented. Perhaps cloning here is superfluous. - $(item).before(element.clone(true)).remove(); + $(item).before(element).remove(); }); } @@ -900,13 +915,13 @@ tbody = that.element.children("tbody").first(), firstCell = tbody.find("tr > td").first(), padding = (that.element.height() - thead.height()) - (firstCell.height() + 20), - count = that.columns.where(isVisible).length; + count = arrayWhere(that.columns, isVisible).length; if (that.selection) { count = count + 1; } - tbody.html(tpl.loading.resolve(getParams.call(that, { columns: count }))); + tbody.html(template(tpl.loading, getParams.call(that, { columns: count }))); if (that.rowCount !== -1 && padding > 0) { tbody.find("tr > td").css("padding", "20px 0 " + padding + "px"); @@ -1087,7 +1102,7 @@ * @for searchSettings **/ delay: 250, - + /** * The characters to type before the search gets executed. * @@ -1293,7 +1308,10 @@ **/ labels: { all: "All", - infos: "Showing {{ctx.start}} to {{ctx.end}} of {{ctx.total}} entries", + showing: "Showing", + to: "to", + of: "of", + entries: "entries", loading: "Loading...", noResults: "No results found!", refresh: "Refresh", @@ -1335,7 +1353,7 @@ * @for statusMapping **/ 2: "warning", - + /** * Specifies a dangerous or potentially negative action. * @@ -1365,7 +1383,7 @@ header: "

    ", headerCell: "
    ", icon: "", - infos: "
    {{lbl.infos}}
    ", + infos: "
    {{lbl.showing}} {{ctx.start}} {{lbl.to}} {{ctx.end}} {{lbl.of}} {{ctx.total}} {{lbl.entries}}
    ", loading: "", noResults: "", pagination: "
      ", @@ -1392,14 +1410,7 @@ } else { - var appendedRows = []; - for (var i = 0; i < rows.length; i++) - { - if (appendRow.call(this, rows[i])) - { - appendedRows.push(rows[i]); - } - } + var appendedRows = appendRows.call(this, rows); sortRows.call(this); highlightAppendedRows.call(this, appendedRows); loadData.call(this); @@ -1519,7 +1530,7 @@ }; /** - * Searches in all rows for a specific phrase (but only in visible cells). + * Searches in all rows for a specific phrase (but only in visible cells). * The search filter will be reseted, if no argument is provided. * * @method search @@ -1555,7 +1566,7 @@ { if (this.selection) { - rowIds = rowIds || this.currentRows.propValues(this.identifier); + rowIds = rowIds || arrayPropValues(this.currentRows, this.identifier); var id, i, selectedRows = []; @@ -1621,7 +1632,7 @@ { if (this.selection) { - rowIds = rowIds || this.currentRows.propValues(this.identifier); + rowIds = rowIds || arrayPropValues(this.currentRows, this.identifier); var id, i, pos, deselectedRows = []; @@ -1664,7 +1675,7 @@ }; /** - * Sorts the rows by a given sort descriptor dictionary. + * Sorts the rows by a given sort descriptor dictionary. * The sort filter will be reseted, if no argument is provided. * * @method sort @@ -1825,8 +1836,8 @@ _bgBusyAria: function(busy) { - return (busy == null || busy) ? - this._bgAria("busy", "true") : + return (busy == null || busy) ? + this._bgAria("busy", "true") : this._bgAria("busy", "false"); }, @@ -1837,29 +1848,29 @@ _bgEnableAria: function (enable) { - return (enable == null || enable) ? - this.removeClass("disabled")._bgAria("disabled", "false") : + return (enable == null || enable) ? + this.removeClass("disabled")._bgAria("disabled", "false") : this.addClass("disabled")._bgAria("disabled", "true"); }, _bgEnableField: function (enable) { - return (enable == null || enable) ? - this.removeAttr("disabled") : + return (enable == null || enable) ? + this.removeAttr("disabled") : this.attr("disabled", "disable"); }, _bgShowAria: function (show) { - return (show == null || show) ? + return (show == null || show) ? this.show()._bgAria("hidden", "false") : this.hide()._bgAria("hidden", "true"); }, _bgSelectAria: function (select) { - return (select == null || select) ? - this.addClass("active")._bgAria("selected", "true") : + return (select == null || select) ? + this.addClass("active")._bgAria("selected", "true") : this.removeClass("active")._bgAria("selected", "false"); }, @@ -1869,121 +1880,189 @@ } }); - if (!String.prototype.resolve) - { - var formatter = { - "checked": function(value) + var formatter = { + "checked": function(value) + { + if (typeof value === "boolean") { - if (typeof value === "boolean") + return (value) ? "checked=\"checked\"" : ""; + } + return value; + } + }; + + var _templateCache = {}; + var getTemplate = function(template){ + if (!_templateCache.hasOwnProperty(template)){ + var str = template.split(/{([^{}]+)}/g); + + for (var i = 0; i < str.length; i++){ + var s = str[i]; + var hasStart = (s.charAt(0) === "}"); + var hasEnd = (s.charAt(s.length - 1) === "{"); + if (hasStart) + { + s = s.substr(1); + } + if (hasEnd) { - return (value) ? "checked=\"checked\"" : ""; + s = s.substr(0, s.length - 1); + } + + if (hasStart || hasEnd) + { + str[i] = s; //plain old html + } else { + str[i] = { + token: str[i], + key: s.split(".") + }; } - return value; } - }; + _templateCache[template] = str; + } + return _templateCache[template]; + }; + /* + // ONLY FOR TESTING + String.prototype.resolve_old = function (substitutes, prefixes) + { + var result = this; - String.prototype.resolve = function (substitutes, prefixes) + $.each(substitutes, function (key, value) { - var result = this; - $.each(substitutes, function (key, value) + if (value != null && typeof value !== "function") { - if (value != null && typeof value !== "function") + if (typeof value === "object") { - if (typeof value === "object") - { - var keys = (prefixes) ? $.extend([], prefixes) : []; - keys.push(key); - result = result.resolve(value, keys) + ""; - } - else + var keys = (prefixes) ? $.extend([], prefixes) : []; + keys.push(key); + result = result.resolve_old(value, keys) + ""; + } + else + { + if (formatter && formatter[key] && typeof formatter[key] === "function") { - if (formatter && formatter[key] && typeof formatter[key] === "function") - { - value = formatter[key](value); - } - key = (prefixes) ? prefixes.join(".") + "." + key : key; - var pattern = new RegExp("\\{\\{" + key + "\\}\\}", "gm"); - result = result.replace(pattern, (value.replace) ? value.replace(/\$/gi, "$") : value); + value = formatter[key](value); } + key = (prefixes) ? prefixes.join(".") + "." + key : key; + var pattern = new RegExp("\\{\\{" + key + "\\}\\}", "gm"); + result = result.replace(pattern, (value.replace) ? value.replace(/\$/gi, "$") : value); } - }); - return result; - }; - } + } + }); - if (!Array.prototype.first) + return result; + }; + */ + var template = function (template, substitutes, prefixes) { - Array.prototype.first = function (condition) - { - for (var i = 0; i < this.length; i++) - { - var item = this[i]; - if (condition(item)) + var str = getTemplate(template); + var result = ""; + for (var i = 0; i < str.length; i++){ + if (typeof str[i] === "object"){ + var key = str[i].key; + var v = ""; + // now we have a variable to be substitued + if (substitutes.hasOwnProperty(key[0])) { - return item; + v = substitutes[key[0]]; + } + else + { + continue; } - } - return null; - }; - } - if (!Array.prototype.contains) + for (var k = 1; k < key.length; k++){ + if (v.hasOwnProperty(key[k])){ + v = v[key[k]]; + } else { + v = ""; + break; + } + } + var formatter_key = key[key.length-1]; + if (formatter && formatter[formatter_key] && typeof formatter[formatter_key] === "function"){ + result += formatter[formatter_key](v); + } else { + result += v; + } + } else { + result += str[i]; // plain old html + } + } + // ONLY FOR TESTING + /* + var result_old = this.resolve_old(substitutes, prefixes); + if (result !== result_old){ + console.warn("Difference templating result"); + console.log(result); + console.log(result_old); + } + */ + return result; + }; + /* + var arrayFirst = function (arr, condition) { - Array.prototype.contains = function (condition) + for (var i = 0; i < arr.length; i++) { - for (var i = 0; i < this.length; i++) + var item = arr[i]; + if (condition(item)) { - var item = this[i]; - if (condition(item)) - { - return true; - } + return item; } - return false; - }; - } - - if (!Array.prototype.page) + } + return null; + }; + */ + var arrayContains = function (arr, condition) { - Array.prototype.page = function (page, size) + for (var i = 0; i < arr.length; i++) { - var skip = (page - 1) * size, - end = skip + size; - return (this.length > skip) ? - (this.length > end) ? this.slice(skip, end) : - this.slice(skip) : []; - }; - } + var item = arr[i]; + if (condition(item)) + { + return true; + } + } + return false; + }; + + var arrayPage = function (arr, page, size) + { + var skip = (page - 1) * size, + end = skip + size; + return (arr.length > skip) ? + (arr.length > end) ? arr.slice(skip, end) : + arr.slice(skip) : []; + }; + - if (!Array.prototype.where) + var arrayWhere = function (arr, condition) { - Array.prototype.where = function (condition) + var result = []; + for (var i = 0; i < arr.length; i++) { - var result = []; - for (var i = 0; i < this.length; i++) + var item = arr[i]; + if (condition(item)) { - var item = this[i]; - if (condition(item)) - { - result.push(item); - } + result.push(item); } - return result; - }; - } + } + return result; + }; + - if (!Array.prototype.propValues) + var arrayPropValues = function (arr, propName) { - Array.prototype.propValues = function (propName) + var result = []; + for (var i = 0; i < arr.length; i++) { - var result = []; - for (var i = 0; i < this.length; i++) - { - result.push(this[i][propName]); - } - return result; - }; - } + result.push(arr[i][propName]); + } + return result; + }; // GRID PLUGIN DEFINITION // ===================== diff --git a/dist/jquery.bootgrid.min.js b/dist/jquery.bootgrid.min.js deleted file mode 100644 index b84a714..0000000 --- a/dist/jquery.bootgrid.min.js +++ /dev/null @@ -1,6 +0,0 @@ -/*! - * jQuery Bootgrid v1.3.1 - 09/11/2015 - * Copyright (c) 2014-2015 Rafael Staib (http://www.jquery-bootgrid.com) - * Licensed under MIT http://www.opensource.org/licenses/MIT - */ -!function(a,b,c){"use strict";function d(a){function b(b){return c.identifier&&b[c.identifier]===a[c.identifier]}var c=this;return this.rows.contains(b)?!1:(this.rows.push(a),!0)}function e(b){var c=this.footer?this.footer.find(b):a(),d=this.header?this.header.find(b):a();return a.merge(c,d)}function f(b){return b?a.extend({},this.cachedParams,{ctx:b}):this.cachedParams}function g(){var b={current:this.current,rowCount:this.rowCount,sort:this.sortDictionary,searchPhrase:this.searchPhrase},c=this.options.post;return c=a.isFunction(c)?c():c,this.options.requestHandler(a.extend(!0,b,c))}function h(b){return"."+a.trim(b).replace(/\s+/gm,".")}function i(){var b=this.options.url;return a.isFunction(b)?b():b}function j(){this.element.trigger("initialize"+H),m.call(this),this.selection=this.options.selection&&null!=this.identifier,o.call(this),q.call(this),C.call(this),A.call(this),r.call(this),n.call(this),this.element.trigger("initialized"+H)}function k(a){this.options.highlightRows}function l(a){return a.visible}function m(){var b=this,c=this.element.find("thead > tr").first(),d=!1;c.children().each(function(){var c=a(this),e=c.data(),f={id:e.columnId,identifier:null==b.identifier&&e.identifier||!1,converter:b.options.converters[e.converter||e.type]||b.options.converters.string,text:c.text(),align:e.align||"left",headerAlign:e.headerAlign||"left",cssClass:e.cssClass||"",headerCssClass:e.headerCssClass||"",formatter:b.options.formatters[e.formatter]||null,order:d||"asc"!==e.order&&"desc"!==e.order?null:e.order,searchable:!(e.searchable===!1),sortable:!(e.sortable===!1),visible:!(e.visible===!1),visibleInSelection:!(e.visibleInSelection===!1),width:a.isNumeric(e.width)?e.width+"px":"string"==typeof e.width?e.width:null};b.columns.push(f),null!=f.order&&(b.sortDictionary[f.id]=f.order),f.identifier&&(b.identifier=f.id,b.converter=f.converter),b.options.multiSort||null===f.order||(d=!0)})}function n(){function c(a){for(var b,c=new RegExp(e.searchPhrase,e.options.caseSensitive?"g":"gi"),d=0;d-1)return!0;return!1}function d(a,b){e.currentRows=a,p.call(e,b),e.options.keepSelection||(e.selectedRows=[]),y.call(e,a),t.call(e),v.call(e),e.element._bgBusyAria(!1).trigger("loaded"+H)}var e=this;if(this.element._bgBusyAria(!0).trigger("load"+H),F.call(this),this.options.ajax){var f=g.call(this),h=i.call(this);if(null==h||"string"!=typeof h||0===h.length)throw new Error("Url setting must be a none empty string or a function that returns one.");this.xqr&&this.xqr.abort();var j={url:h,data:f,success:function(b){e.xqr=null,"string"==typeof b&&(b=a.parseJSON(b)),b=e.options.responseHandler(b),e.current=b.current,d(b.rows,b.total)},error:function(a,b,c){e.xqr=null,"abort"!==b&&(u.call(e),e.element._bgBusyAria(!1).trigger("loaded"+H))}};j=a.extend(this.options.ajaxSettings,j),this.xqr=a.ajax(j)}else{var k=this.searchPhrase.length>0?this.rows.where(c):this.rows,l=k.length;-1!==this.rowCount&&(k=k.page(this.current,this.rowCount)),b.setTimeout(function(){d(k,l)},10)}}function o(){if(!this.options.ajax){var b=this,c=this.element.find("tbody > tr");c.each(function(){var c=a(this),e=c.children("td"),f={};a.each(b.columns,function(a,b){f[b.id]=b.converter.from(e.eq(a).text())}),d.call(b,f)}),p.call(this,this.rows.length),G.call(this)}}function p(a){this.total=a,this.totalPages=-1===this.rowCount?1:Math.ceil(this.total/this.rowCount)}function q(){var b=this.options.templates,c=this.element.parent().hasClass(this.options.css.responsiveTable)?this.element.parent():this.element;this.element.addClass(this.options.css.table),0===this.element.children("tbody").length&&this.element.append(b.body),1&this.options.navigation&&(this.header=a(b.header.resolve(f.call(this,{id:this.element._bgId()+"-header"}))),c.before(this.header)),2&this.options.navigation&&(this.footer=a(b.footer.resolve(f.call(this,{id:this.element._bgId()+"-footer"}))),c.after(this.footer))}function r(){if(0!==this.options.navigation){var b=this.options.css,c=h(b.actions),d=e.call(this,c);if(d.length>0){var g=this,i=this.options.templates,j=a(i.actions.resolve(f.call(this)));if(this.options.ajax){var k=i.icon.resolve(f.call(this,{iconCss:b.iconRefresh})),l=a(i.actionButton.resolve(f.call(this,{content:k,text:this.options.labels.refresh}))).on("click"+H,function(a){a.stopPropagation(),g.current=1,n.call(g)});j.append(l)}x.call(this,j),s.call(this,j),E.call(this,d,j)}}}function s(b){if(this.options.columnSelection&&this.columns.length>1){var c=this,d=this.options.css,e=this.options.templates,g=e.icon.resolve(f.call(this,{iconCss:d.iconColumns})),i=a(e.actionDropDown.resolve(f.call(this,{content:g}))),j=h(d.dropDownItem),k=h(d.dropDownItemCheckbox),m=h(d.dropDownMenuItems);a.each(this.columns,function(b,g){if(g.visibleInSelection){var o=a(e.actionDropDownCheckboxItem.resolve(f.call(c,{name:g.id,label:g.text,checked:g.visible}))).on("click"+H,j,function(b){b.stopPropagation();var d=a(this),e=d.find(k);if(!e.prop("disabled")){g.visible=e.prop("checked");var f=c.columns.where(l).length>1;d.parents(m).find(j+":has("+k+":checked)")._bgEnableAria(f).find(k)._bgEnableField(f),c.element.find("tbody").empty(),C.call(c),n.call(c)}});i.find(h(d.dropDownMenuItems)).append(o)}}),b.append(i)}}function t(){if(0!==this.options.navigation){var b=h(this.options.css.infos),c=e.call(this,b);if(c.length>0){var d=this.current*this.rowCount,g=a(this.options.templates.infos.resolve(f.call(this,{end:0===this.total||-1===d||d>this.total?this.total:d,start:0===this.total?0:d-this.rowCount+1,total:this.total})));E.call(this,c,g)}}}function u(){var a=this.element.children("tbody").first(),b=this.options.templates,c=this.columns.where(l).length;this.selection&&(c+=1),a.html(b.noResults.resolve(f.call(this,{columns:c})))}function v(){if(0!==this.options.navigation){var b=h(this.options.css.pagination),c=e.call(this,b)._bgShowAria(-1!==this.rowCount);if(-1!==this.rowCount&&c.length>0){var d=this.options.templates,g=this.current,i=this.totalPages,j=a(d.pagination.resolve(f.call(this))),k=i-g,l=-1*(this.options.padding-g),m=k>=this.options.padding?Math.max(l,1):Math.max(l-this.options.padding+k,1),n=2*this.options.padding+1,o=i>=n?n:i;w.call(this,j,"first","«","first")._bgEnableAria(g>1),w.call(this,j,"prev","<","prev")._bgEnableAria(g>1);for(var p=0;o>p;p++){var q=p+m;w.call(this,j,q,q,"page-"+q)._bgEnableAria()._bgSelectAria(q===g)}0===o&&w.call(this,j,1,1,"page-1")._bgEnableAria(!1)._bgSelectAria(),w.call(this,j,"next",">","next")._bgEnableAria(i>g),w.call(this,j,"last","»","last")._bgEnableAria(i>g),E.call(this,c,j)}}}function w(b,c,d,e){var g=this,i=this.options.templates,j=this.options.css,k=f.call(this,{css:e,text:d,page:c}),l=a(i.paginationItem.resolve(k)).on("click"+H,h(j.paginationButton),function(b){b.stopPropagation(),b.preventDefault();var c=a(this),d=c.parent();if(!d.hasClass("active")&&!d.hasClass("disabled")){var e={first:1,prev:g.current-1,next:g.current+1,last:g.totalPages},f=c.data("page");g.current=e[f]||f,n.call(g)}c.trigger("blur")});return b.append(l),l}function x(b){function c(a){return-1===a?d.options.labels.all:a}var d=this,e=this.options.rowCount;if(a.isArray(e)){var g=this.options.css,i=this.options.templates,j=a(i.actionDropDown.resolve(f.call(this,{content:c(this.rowCount)}))),k=h(g.dropDownMenu),l=h(g.dropDownMenuText),m=h(g.dropDownMenuItems),o=h(g.dropDownItemButton);a.each(e,function(b,e){var g=a(i.actionDropDownItem.resolve(f.call(d,{text:c(e),action:e})))._bgSelectAria(e===d.rowCount).on("click"+H,o,function(b){b.preventDefault();var e=a(this),f=e.data("action");f!==d.rowCount&&(d.current=1,d.rowCount=f,e.parents(m).children().each(function(){var b=a(this),c=b.find(o).data("action");b._bgSelectAria(c===f)}),e.parents(k).find(l).text(c(f)),n.call(d))});j.find(m).append(g)}),b.append(j)}}function y(b){if(b.length>0){var c=this,d=this.options.css,e=this.options.templates,g=this.element.children("tbody").first(),i=!0,j="";a.each(b,function(b,g){var h="",k=' data-row-id="'+(null==c.identifier?b:g[c.identifier])+'"',l="";if(c.selection){var m=-1!==a.inArray(g[c.identifier],c.selectedRows),n=e.select.resolve(f.call(c,{type:"checkbox",value:g[c.identifier],checked:m}));h+=e.cell.resolve(f.call(c,{content:n,css:d.selectCell})),i=i&&m,m&&(l+=d.selected,k+=' aria-selected="true"')}var o=null!=g.status&&c.options.statusMapping[g.status];o&&(l+=o),a.each(c.columns,function(b,i){if(i.visible){var j=a.isFunction(i.formatter)?i.formatter.call(c,i,g):i.converter.to(g[i.id]),k=i.cssClass.length>0?" "+i.cssClass:"";h+=e.cell.resolve(f.call(c,{content:null==j||""===j?" ":j,css:("right"===i.align?d.right:"center"===i.align?d.center:d.left)+k,style:null==i.width?"":"width:"+i.width+";"}))}}),l.length>0&&(k+=' class="'+l+'"'),j+=e.row.resolve(f.call(c,{attr:k,cells:h}))}),c.element.find("thead "+h(c.options.css.selectBox)).prop("checked",i),g.html(j),z.call(this,g)}else u.call(this)}function z(b){var c=this,d=h(this.options.css.selectBox);this.selection&&b.off("click"+H,d).on("click"+H,d,function(b){b.stopPropagation();var d=a(this),e=c.converter.from(d.val());d.prop("checked")?c.select([e]):c.deselect([e])}),b.off("click"+H,"> tr").on("click"+H,"> tr",function(b){b.stopPropagation();var d=a(this),e=null==c.identifier?d.data("row-id"):c.converter.from(d.data("row-id")+""),f=null==c.identifier?c.currentRows[e]:c.currentRows.first(function(a){return a[c.identifier]===e});c.selection&&c.options.rowSelect&&(d.hasClass(c.options.css.selected)?c.deselect([e]):c.select([e])),c.element.trigger("click"+H,[c.columns,f])})}function A(){if(0!==this.options.navigation){var c=this.options.css,d=h(c.search),g=e.call(this,d);if(g.length>0){var i=this,j=this.options.templates,k=null,l="",m=h(c.searchField),n=a(j.search.resolve(f.call(this))),o=n.is(m)?n:n.find(m);o.on("keyup"+H,function(c){c.stopPropagation();var d=a(this).val();(l!==d||13===c.which&&""!==d)&&(l=d,(13===c.which||0===d.length||d.length>=i.options.searchSettings.characters)&&(b.clearTimeout(k),k=b.setTimeout(function(){B.call(i,d)},i.options.searchSettings.delay)))}),E.call(this,g,n)}}}function B(a){this.searchPhrase!==a&&(this.current=1,this.searchPhrase=a,n.call(this))}function C(){var b=this,c=this.element.find("thead > tr"),d=this.options.css,e=this.options.templates,g="",i=this.options.sorting;if(this.selection){var j=this.options.multiSelect?e.select.resolve(f.call(b,{type:"checkbox",value:"all"})):"";g+=e.rawHeaderCell.resolve(f.call(b,{content:j,css:d.selectCell}))}if(a.each(this.columns,function(a,c){if(c.visible){var h=b.sortDictionary[c.id],j=i&&h&&"asc"===h?d.iconUp:i&&h&&"desc"===h?d.iconDown:"",k=e.icon.resolve(f.call(b,{iconCss:j})),l=c.headerAlign,m=c.headerCssClass.length>0?" "+c.headerCssClass:"";g+=e.headerCell.resolve(f.call(b,{column:c,icon:k,sortable:i&&c.sortable&&d.sortable||"",css:("right"===l?d.right:"center"===l?d.center:d.left)+m,style:null==c.width?"":"width:"+c.width+";"}))}}),c.html(g),i){var k=h(d.sortable);c.off("click"+H,k).on("click"+H,k,function(c){c.preventDefault(),D.call(b,a(this)),G.call(b),n.call(b)})}if(this.selection&&this.options.multiSelect){var l=h(d.selectBox);c.off("click"+H,l).on("click"+H,l,function(c){c.stopPropagation(),a(this).prop("checked")?b.select():b.deselect()})}}function D(a){var b=this.options.css,c=h(b.icon),d=a.data("column-id")||a.parents("th").first().data("column-id"),e=this.sortDictionary[d],f=a.find(c);if(this.options.multiSort||(a.parents("tr").first().find(c).removeClass(b.iconDown+" "+b.iconUp),this.sortDictionary={}),e&&"asc"===e)this.sortDictionary[d]="desc",f.removeClass(b.iconUp).addClass(b.iconDown);else if(e&&"desc"===e)if(this.options.multiSort){var g={};for(var i in this.sortDictionary)i!==d&&(g[i]=this.sortDictionary[i]);this.sortDictionary=g,f.removeClass(b.iconDown)}else this.sortDictionary[d]="asc",f.removeClass(b.iconDown).addClass(b.iconUp);else this.sortDictionary[d]="asc",f.addClass(b.iconUp)}function E(b,c){b.each(function(b,d){a(d).before(c.clone(!0)).remove()})}function F(){var a=this;b.setTimeout(function(){if("true"===a.element._bgAria("busy")){var b=a.options.templates,c=a.element.children("thead").first(),d=a.element.children("tbody").first(),e=d.find("tr > td").first(),g=a.element.height()-c.height()-(e.height()+20),h=a.columns.where(l).length;a.selection&&(h+=1),d.html(b.loading.resolve(f.call(a,{columns:h}))),-1!==a.rowCount&&g>0&&d.find("tr > td").css("padding","20px 0 "+g+"px")}},250)}function G(){function a(c,d,e){function f(a){return"asc"===h.order?a:-1*a}e=e||0;var g=e+1,h=b[e];return c[h.id]>d[h.id]?f(1):c[h.id]g?a(c,d,g):0}var b=[];if(!this.options.ajax){for(var c in this.sortDictionary)(this.options.multiSort||0===b.length)&&b.push({id:c,order:this.sortDictionary[c]});b.length>0&&this.rows.sort(a)}}var H=".rs.jquery.bootgrid",I=function(b,c){this.element=a(b),this.origin=this.element.clone(),this.options=a.extend(!0,{},I.defaults,this.element.data(),c);var d=this.options.rowCount=this.element.data().rowCount||c.rowCount||this.options.rowCount;this.columns=[],this.current=1,this.currentRows=[],this.identifier=null,this.selection=!1,this.converter=null,this.rowCount=a.isArray(d)?d[0]:d,this.rows=[],this.searchPhrase="",this.selectedRows=[],this.sortDictionary={},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};if(I.defaults={navigation:3,padding:2,columnSelection:!0,rowCount:[10,25,50,-1],selection:!1,multiSelect:!1,rowSelect:!1,keepSelection:!1,highlightRows:!1,sorting:!0,multiSort:!1,searchSettings:{delay:250,characters:1},ajax:!1,ajaxSettings:{method:"POST"},post:{},url:"",caseSensitive:!0,requestHandler:function(a){return a},responseHandler:function(a){return a},converters:{numeric:{from:function(a){return+a},to:function(a){return a+""}},string:{from:function(a){return a},to:function(a){return a}}},css:{actions:"actions btn-group",center:"text-center",columnHeaderAnchor:"column-header-anchor",columnHeaderText:"text",dropDownItem:"dropdown-item",dropDownItemButton:"dropdown-item-button",dropDownItemCheckbox:"dropdown-item-checkbox",dropDownMenu:"dropdown btn-group",dropDownMenuItems:"dropdown-menu pull-right",dropDownMenuText:"dropdown-text",footer:"bootgrid-footer container-fluid",header:"bootgrid-header container-fluid",icon:"icon glyphicon",iconColumns:"glyphicon-th-list",iconDown:"glyphicon-chevron-down",iconRefresh:"glyphicon-refresh",iconSearch:"glyphicon-search",iconUp:"glyphicon-chevron-up",infos:"infos",left:"text-left",pagination:"pagination",paginationButton:"button",responsiveTable:"table-responsive",right:"text-right",search:"search form-group",searchField:"search-field form-control",selectBox:"select-box",selectCell:"select-cell",selected:"active",sortable:"sortable",table:"bootgrid-table table"},formatters:{},labels:{all:"All",infos:"Showing {{ctx.start}} to {{ctx.end}} of {{ctx.total}} entries",loading:"Loading...",noResults:"No results found!",refresh:"Refresh",search:"Search"},statusMapping:{0:"success",1:"info",2:"warning",3:"danger"},templates:{actionButton:'',actionDropDown:'
      ',actionDropDownItem:'
    • {{ctx.text}}
    • ',actionDropDownCheckboxItem:'
    • ',actions:'
      ',body:"
      ",cell:'',footer:'

      ',header:'

      ',headerCell:'',icon:'',infos:'
      {{lbl.infos}}
      ',loading:'',noResults:'',pagination:'
        ',paginationItem:'
      • {{ctx.text}}
      • ',rawHeaderCell:'',row:"{{ctx.cells}}",search:'
        ',select:''}},I.prototype.append=function(a){if(this.options.ajax);else{for(var b=[],c=0;c0&&(this.options.multiSelect||1!==e.length);)if(c=b.pop(),-1===a.inArray(c,this.selectedRows))for(d=0;d0){var f=h(this.options.css.selectBox),g=this.selectedRows.length>=this.currentRows.length;for(d=0;!this.options.keepSelection&&g&&d tr "+f+":checked").trigger("click"+H),d=0;d tr[data-row-id="'+this.selectedRows[d]+'"]').addClass(this.options.css.selected)._bgAria("selected","true").find(f).prop("checked",!0);this.element.trigger("selected"+H,[e])}}return this},I.prototype.deselect=function(b){if(this.selection){b=b||this.currentRows.propValues(this.identifier);for(var c,d,e,f=[];b.length>0;)if(c=b.pop(),e=a.inArray(c,this.selectedRows),-1!==e)for(d=0;d0){var g=h(this.options.css.selectBox);for(this.element.find("thead "+g).prop("checked",!1),d=0;d tr[data-row-id="'+f[d][this.identifier]+'"]').removeClass(this.options.css.selected)._bgAria("selected","false").find(g).prop("checked",!1);this.element.trigger("deselected"+H,[f])}}return this},I.prototype.sort=function(b){var c=b?a.extend({},b):{};return c===this.sortDictionary?this:(this.sortDictionary=c,C.call(this),G.call(this),n.call(this),this)},I.prototype.getColumnSettings=function(){return a.merge([],this.columns)},I.prototype.getCurrentPage=function(){return this.current},I.prototype.getCurrentRows=function(){return a.merge([],this.currentRows)},I.prototype.getRowCount=function(){return this.rowCount},I.prototype.getSearchPhrase=function(){return this.searchPhrase},I.prototype.getSelectedRows=function(){return a.merge([],this.selectedRows)},I.prototype.getSortDictionary=function(){return a.extend({},this.sortDictionary)},I.prototype.getTotalPageCount=function(){return this.totalPages},I.prototype.getTotalRowCount=function(){return this.total},a.fn.extend({_bgAria:function(a,b){return b?this.attr("aria-"+a,b):this.attr("aria-"+a)},_bgBusyAria:function(a){return null==a||a?this._bgAria("busy","true"):this._bgAria("busy","false")},_bgRemoveAria:function(a){return this.removeAttr("aria-"+a)},_bgEnableAria:function(a){return null==a||a?this.removeClass("disabled")._bgAria("disabled","false"):this.addClass("disabled")._bgAria("disabled","true")},_bgEnableField:function(a){return null==a||a?this.removeAttr("disabled"):this.attr("disabled","disable")},_bgShowAria:function(a){return null==a||a?this.show()._bgAria("hidden","false"):this.hide()._bgAria("hidden","true")},_bgSelectAria:function(a){return null==a||a?this.addClass("active")._bgAria("selected","true"):this.removeClass("active")._bgAria("selected","false")},_bgId:function(a){return a?this.attr("id",a):this.attr("id")}}),!String.prototype.resolve){var J={checked:function(a){return"boolean"==typeof a?a?'checked="checked"':"":a}};String.prototype.resolve=function(b,c){var d=this;return a.each(b,function(b,e){if(null!=e&&"function"!=typeof e)if("object"==typeof e){var f=c?a.extend([],c):[];f.push(b),d=d.resolve(e,f)+""}else{J&&J[b]&&"function"==typeof J[b]&&(e=J[b](e)),b=c?c.join(".")+"."+b:b;var g=new RegExp("\\{\\{"+b+"\\}\\}","gm");d=d.replace(g,e.replace?e.replace(/\$/gi,"$"):e)}}),d}}Array.prototype.first||(Array.prototype.first=function(a){for(var b=0;bc?this.length>d?this.slice(c,d):this.slice(c):[]}),Array.prototype.where||(Array.prototype.where=function(a){for(var b=[],c=0;c 0) ? this.rows.where(containsPhrase) : this.rows, + var rows = (this.searchPhrase.length > 0) ? arrayWhere(this.rows, containsPhrase) : this.rows, total = rows.length; if (this.rowCount !== -1) { - rows = rows.page(this.current, this.rowCount); + rows = arrayPage(rows, this.current, this.rowCount); } // todo: improve the following comment @@ -263,7 +277,7 @@ function loadRows() { var that = this, rows = this.element.find("tbody > tr"); - + var convertedRows = []; rows.each(function () { var $this = $(this), @@ -275,9 +289,9 @@ function loadRows() row[column.id] = column.converter.from(cells.eq(i).text()); }); - appendRow.call(that, row); + convertedRows.push(row); }); - + appendRows.call(that, convertedRows); setTotals.call(this, this.rows.length); sortRows.call(this); } @@ -306,13 +320,13 @@ function prepareTable() if (this.options.navigation & 1) { - this.header = $(tpl.header.resolve(getParams.call(this, { id: this.element._bgId() + "-header" }))); + this.header = $(template(tpl.header, getParams.call(this, { id: this.element._bgId() + "-header" }))); wrapper.before(this.header); } if (this.options.navigation & 2) { - this.footer = $(tpl.footer.resolve(getParams.call(this, { id: this.element._bgId() + "-footer" }))); + this.footer = $(template(tpl.footer, getParams.call(this, { id: this.element._bgId() + "-footer" }))); wrapper.after(this.footer); } } @@ -329,13 +343,13 @@ function renderActions() { var that = this, tpl = this.options.templates, - actions = $(tpl.actions.resolve(getParams.call(this))); + actions = $(template(tpl.actions, 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, + var refreshIcon = template(tpl.icon, getParams.call(this, { iconCss: css.iconRefresh })), + refresh = $(template(tpl.actionButton, getParams.call(this, { content: refreshIcon, text: this.options.labels.refresh }))) .on("click" + namespace, function (e) { @@ -365,8 +379,8 @@ function renderColumnSelection(actions) 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 }))), + icon = template(tpl.icon, getParams.call(this, { iconCss: css.iconColumns })), + dropDown = $(template(tpl.actionDropDown, getParams.call(this, { content: icon }))), selector = getCssSelector(css.dropDownItem), checkboxSelector = getCssSelector(css.dropDownItemCheckbox), itemsSelector = getCssSelector(css.dropDownMenuItems); @@ -375,21 +389,21 @@ function renderColumnSelection(actions) { if (column.visibleInSelection) { - var item = $(tpl.actionDropDownCheckboxItem.resolve(getParams.call(that, + var item = $(template(tpl.actionDropDownCheckboxItem, getParams.call(that, { name: column.id, label: column.text, checked: column.visible }))) .on("click" + namespace, selector, function (e) { 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; + var enable = arrayWhere(that.columns, 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); @@ -413,7 +427,7 @@ function renderInfos() if (infoItems.length > 0) { var end = (this.current * this.rowCount), - infos = $(this.options.templates.infos.resolve(getParams.call(this, { + infos = $(template(this.options.templates.infos, 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 @@ -428,13 +442,13 @@ function renderNoResultsRow() { var tbody = this.element.children("tbody").first(), tpl = this.options.templates, - count = this.columns.where(isVisible).length; + count = arrayWhere(this.columns, isVisible).length; if (this.selection) { count = count + 1; } - tbody.html(tpl.noResults.resolve(getParams.call(this, { columns: count }))); + tbody.html(template(tpl.noResults, getParams.call(this, { columns: count }))); } function renderPagination() @@ -449,7 +463,7 @@ function renderPagination() var tpl = this.options.templates, current = this.current, totalPages = this.totalPages, - pagination = $(tpl.pagination.resolve(getParams.call(this))), + pagination = $(template(tpl.pagination, getParams.call(this))), offsetRight = totalPages - current, offsetLeft = (this.options.padding - current) * -1, startWith = ((offsetRight >= this.options.padding) ? @@ -492,7 +506,7 @@ function renderPaginationItem(list, page, text, markerCss) tpl = this.options.templates, css = this.options.css, values = getParams.call(this, { css: markerCss, text: text, page: page }), - item = $(tpl.paginationItem.resolve(values)) + item = $(template(tpl.paginationItem, values)) .on("click" + namespace, getCssSelector(css.paginationButton), function (e) { e.stopPropagation(); @@ -533,7 +547,7 @@ function renderRowCountSelection(actions) { var css = this.options.css, tpl = this.options.templates, - dropDown = $(tpl.actionDropDown.resolve(getParams.call(this, { content: getText(this.rowCount) }))), + dropDown = $(template(tpl.actionDropDown, getParams.call(this, { content: getText(this.rowCount) }))), menuSelector = getCssSelector(css.dropDownMenu), menuTextSelector = getCssSelector(css.dropDownMenuText), menuItemsSelector = getCssSelector(css.dropDownMenuItems), @@ -541,7 +555,7 @@ function renderRowCountSelection(actions) $.each(rowCountList, function (index, value) { - var item = $(tpl.actionDropDownItem.resolve(getParams.call(that, + var item = $(template(tpl.actionDropDownItem, getParams.call(that, { text: getText(value), action: value }))) ._bgSelectAria(value === that.rowCount) .on("click" + namespace, menuItemSelector, function (e) @@ -591,9 +605,9 @@ function renderRows(rows) if (that.selection) { var selected = ($.inArray(row[that.identifier], that.selectedRows) !== -1), - selectBox = tpl.select.resolve(getParams.call(that, + selectBox = template(tpl.select, getParams.call(that, { type: "checkbox", value: row[that.identifier], checked: selected })); - cells += tpl.cell.resolve(getParams.call(that, { content: selectBox, css: css.selectCell })); + cells += template(tpl.cell, getParams.call(that, { content: selectBox, css: css.selectCell })); allRowsSelected = (allRowsSelected && selected); if (selected) { @@ -616,7 +630,7 @@ function renderRows(rows) 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, { + cells += template(tpl.cell, getParams.call(that, { content: (value == null || value === "") ? " " : value, css: ((column.align === "right") ? css.right : (column.align === "center") ? css.center : css.left) + cssClass, @@ -628,7 +642,7 @@ function renderRows(rows) { rowAttr += " class=\"" + rowCss + "\""; } - html += tpl.row.resolve(getParams.call(that, { attr: rowAttr, cells: cells })); + html += template(tpl.row, getParams.call(that, { attr: rowAttr, cells: cells })); }); // sets or clears multi selectbox state @@ -713,7 +727,7 @@ function renderSearchField() timer = null, // fast keyup detection currentValue = "", searchFieldSelector = getCssSelector(css.searchField), - search = $(tpl.search.resolve(getParams.call(this))), + search = $(template(tpl.search, getParams.call(this))), searchField = (search.is(searchFieldSelector)) ? search : search.find(searchFieldSelector); @@ -762,8 +776,8 @@ function renderTableHeader() if (this.selection) { var selectBox = (this.options.multiSelect) ? - tpl.select.resolve(getParams.call(that, { type: "checkbox", value: "all" })) : ""; - html += tpl.rawHeaderCell.resolve(getParams.call(that, { content: selectBox, + template(tpl.select, getParams.call(that, { type: "checkbox", value: "all" })) : ""; + html += template(tpl.rawHeaderCell, getParams.call(that, { content: selectBox, css: css.selectCell })); } @@ -774,10 +788,10 @@ function renderTableHeader() var sortOrder = that.sortDictionary[column.id], iconCss = ((sorting && sortOrder && sortOrder === "asc") ? css.iconUp : (sorting && sortOrder && sortOrder === "desc") ? css.iconDown : ""), - icon = tpl.icon.resolve(getParams.call(that, { iconCss: iconCss })), + icon = template(tpl.icon, getParams.call(that, { iconCss: iconCss })), align = column.headerAlign, cssClass = (column.headerCssClass.length > 0) ? " " + column.headerCssClass : ""; - html += tpl.headerCell.resolve(getParams.call(that, { + html += template(tpl.headerCell, 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, @@ -891,13 +905,13 @@ function showLoading() tbody = that.element.children("tbody").first(), firstCell = tbody.find("tr > td").first(), padding = (that.element.height() - thead.height()) - (firstCell.height() + 20), - count = that.columns.where(isVisible).length; + count = arrayWhere(that.columns, isVisible).length; if (that.selection) { count = count + 1; } - tbody.html(tpl.loading.resolve(getParams.call(that, { columns: count }))); + tbody.html(template(tpl.loading, getParams.call(that, { columns: count }))); if (that.rowCount !== -1 && padding > 0) { tbody.find("tr > td").css("padding", "20px 0 " + padding + "px"); diff --git a/src/public.js b/src/public.js index 16c001f..032ffb3 100644 --- a/src/public.js +++ b/src/public.js @@ -128,7 +128,7 @@ Grid.defaults = { * @for searchSettings **/ delay: 250, - + /** * The characters to type before the search gets executed. * @@ -379,7 +379,7 @@ Grid.defaults = { * @for statusMapping **/ 2: "warning", - + /** * Specifies a dangerous or potentially negative action. * @@ -436,14 +436,7 @@ Grid.prototype.append = function(rows) } else { - var appendedRows = []; - for (var i = 0; i < rows.length; i++) - { - if (appendRow.call(this, rows[i])) - { - appendedRows.push(rows[i]); - } - } + var appendedRows = appendRows.call(this, rows); sortRows.call(this); highlightAppendedRows.call(this, appendedRows); loadData.call(this); @@ -563,7 +556,7 @@ Grid.prototype.remove = function(rowIds) }; /** - * Searches in all rows for a specific phrase (but only in visible cells). + * Searches in all rows for a specific phrase (but only in visible cells). * The search filter will be reseted, if no argument is provided. * * @method search @@ -599,7 +592,7 @@ Grid.prototype.select = function(rowIds) { if (this.selection) { - rowIds = rowIds || this.currentRows.propValues(this.identifier); + rowIds = rowIds || arrayPropValues(this.currentRows, this.identifier); var id, i, selectedRows = []; @@ -665,7 +658,7 @@ Grid.prototype.deselect = function(rowIds) { if (this.selection) { - rowIds = rowIds || this.currentRows.propValues(this.identifier); + rowIds = rowIds || arrayPropValues(this.currentRows, this.identifier); var id, i, pos, deselectedRows = []; @@ -708,7 +701,7 @@ Grid.prototype.deselect = function(rowIds) }; /** - * Sorts the rows by a given sort descriptor dictionary. + * Sorts the rows by a given sort descriptor dictionary. * The sort filter will be reseted, if no argument is provided. * * @method sort diff --git a/test/tests-extensions.js b/test/tests-extensions.js index f0e5994..64d21d6 100644 --- a/test/tests-extensions.js +++ b/test/tests-extensions.js @@ -13,7 +13,7 @@ test("String.resolve basic (one dimension) test", 1, function () stringToResolve = "{{first}} {{second}}"; // when - var result = stringToResolve.resolve(values); + var result = template(stringToResolve, values); // then equal(result, "test case", "Valid string"); @@ -38,7 +38,7 @@ test("String.resolve advanced (n dimension) test", 1, function () stringToResolve = "{{first.sub}} {{second}} {{third.more}} {{third.adv.test}} {{third.case}}"; // when - var result = stringToResolve.resolve(values); + var result = template(stringToResolve, values); // then equal(result, "this is a more advanced test case", "Valid string"); From 10197d27453e4b80163ee67ec26ba319c0d7bc72 Mon Sep 17 00:00:00 2001 From: Zac Spitzer Date: Sat, 10 Dec 2016 19:32:37 +1100 Subject: [PATCH 11/13] Revert "refactor out prototypes" This reverts commit cef18bcdc3ce544f29fcf5d3ef8b44a28a7ebeb4. --- dist/jquery.bootgrid.js | 377 ++++++++++++++---------------------- dist/jquery.bootgrid.min.js | 6 + src/internal.js | 86 ++++---- src/public.js | 21 +- test/tests-extensions.js | 4 +- 5 files changed, 207 insertions(+), 287 deletions(-) create mode 100644 dist/jquery.bootgrid.min.js diff --git a/dist/jquery.bootgrid.js b/dist/jquery.bootgrid.js index a67deb9..4f27d44 100644 --- a/dist/jquery.bootgrid.js +++ b/dist/jquery.bootgrid.js @@ -1,6 +1,6 @@ /*! - * jQuery Bootgrid v1.3.1 - 12/10/2016 - * Copyright (c) 2014-2016 Rafael Staib (http://www.jquery-bootgrid.com) + * jQuery Bootgrid v1.3.1 - 09/11/2015 + * Copyright (c) 2014-2015 Rafael Staib (http://www.jquery-bootgrid.com) * Licensed under MIT http://www.opensource.org/licenses/MIT */ ;(function ($, window, undefined) @@ -25,7 +25,7 @@ return that.identifier && item[that.identifier] === row[that.identifier]; } - if (!arrayContains(this.rows, exists)) + if (!this.rows.contains(exists)) { this.rows.push(row); return true; @@ -34,20 +34,6 @@ return false; } - function appendRows(rows) - { - var that = this; - - var appendedRows = rows.slice(); - appendedRows.filter(function(item) { - return !(that.identifier && item[that.identifier] === rows[that.identifier]); - }); - - this.rows = this.rows.concat(appendedRows); - - return appendedRows; - } - function findFooterAndHeaderItems(selector) { var footer = (this.footer) ? this.footer.find(selector) : $(), @@ -141,7 +127,7 @@ sortable: !(data.sortable === false), // default: true visible: !(data.visible === false), // default: true visibleInSelection: !(data.visibleInSelection === false), // default: true - width: ($.isNumeric(data.width)) ? data.width + "px" : + width: ($.isNumeric(data.width)) ? data.width + "px" : (typeof(data.width) === "string") ? data.width : null }; that.columns.push(column); @@ -268,11 +254,11 @@ } else { - var rows = (this.searchPhrase.length > 0) ? arrayWhere(this.rows, containsPhrase) : this.rows, + var rows = (this.searchPhrase.length > 0) ? this.rows.where(containsPhrase) : this.rows, total = rows.length; if (this.rowCount !== -1) { - rows = arrayPage(rows, this.current, this.rowCount); + rows = rows.page(this.current, this.rowCount); } // todo: improve the following comment @@ -287,7 +273,7 @@ { var that = this, rows = this.element.find("tbody > tr"); - var convertedRows = []; + rows.each(function () { var $this = $(this), @@ -299,9 +285,9 @@ row[column.id] = column.converter.from(cells.eq(i).text()); }); - convertedRows.push(row); + appendRow.call(that, row); }); - appendRows.call(that, convertedRows); + setTotals.call(this, this.rows.length); sortRows.call(this); } @@ -330,13 +316,13 @@ if (this.options.navigation & 1) { - this.header = $(template(tpl.header, getParams.call(this, { id: this.element._bgId() + "-header" }))); + this.header = $(tpl.header.resolve(getParams.call(this, { id: this.element._bgId() + "-header" }))); wrapper.before(this.header); } if (this.options.navigation & 2) { - this.footer = $(template(tpl.footer, getParams.call(this, { id: this.element._bgId() + "-footer" }))); + this.footer = $(tpl.footer.resolve(getParams.call(this, { id: this.element._bgId() + "-footer" }))); wrapper.after(this.footer); } } @@ -353,13 +339,13 @@ { var that = this, tpl = this.options.templates, - actions = $(template(tpl.actions, getParams.call(this))); + actions = $(tpl.actions.resolve(getParams.call(this))); // Refresh Button if (this.options.ajax) { - var refreshIcon = template(tpl.icon, getParams.call(this, { iconCss: css.iconRefresh })), - refresh = $(template(tpl.actionButton, getParams.call(this, + 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) { @@ -389,8 +375,8 @@ var that = this, css = this.options.css, tpl = this.options.templates, - icon = template(tpl.icon, getParams.call(this, { iconCss: css.iconColumns })), - dropDown = $(template(tpl.actionDropDown, getParams.call(this, { content: icon }))), + 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); @@ -399,25 +385,24 @@ { if (column.visibleInSelection) { - var item = $(template(tpl.actionDropDownCheckboxItem, getParams.call(that, + 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(); - + var $this = $(this), checkbox = $this.find(checkboxSelector); if (!checkbox.prop("disabled")) { column.visible = checkbox.prop("checked"); - var enable = arrayWhere(that.columns, isVisible).length > 1; + 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.element.trigger("columnToggle" + namespace, column); } }); dropDown.find(getCssSelector(css.dropDownMenuItems)).append(item); @@ -437,7 +422,7 @@ if (infoItems.length > 0) { var end = (this.current * this.rowCount), - infos = $(template(this.options.templates.infos, getParams.call(this, { + 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 @@ -452,13 +437,13 @@ { var tbody = this.element.children("tbody").first(), tpl = this.options.templates, - count = arrayWhere(this.columns, isVisible).length; + count = this.columns.where(isVisible).length; if (this.selection) { count = count + 1; } - tbody.html(template(tpl.noResults, getParams.call(this, { columns: count }))); + tbody.html(tpl.noResults.resolve(getParams.call(this, { columns: count }))); } function renderPagination() @@ -473,7 +458,7 @@ var tpl = this.options.templates, current = this.current, totalPages = this.totalPages, - pagination = $(template(tpl.pagination, getParams.call(this))), + pagination = $(tpl.pagination.resolve(getParams.call(this))), offsetRight = totalPages - current, offsetLeft = (this.options.padding - current) * -1, startWith = ((offsetRight >= this.options.padding) ? @@ -516,7 +501,7 @@ tpl = this.options.templates, css = this.options.css, values = getParams.call(this, { css: markerCss, text: text, page: page }), - item = $(template(tpl.paginationItem, values)) + item = $(tpl.paginationItem.resolve(values)) .on("click" + namespace, getCssSelector(css.paginationButton), function (e) { e.stopPropagation(); @@ -557,7 +542,7 @@ { var css = this.options.css, tpl = this.options.templates, - dropDown = $(template(tpl.actionDropDown, getParams.call(this, { content: getText(this.rowCount) }))), + dropDown = $(tpl.actionDropDown.resolve(getParams.call(this, { content: getText(this.rowCount) }))), menuSelector = getCssSelector(css.dropDownMenu), menuTextSelector = getCssSelector(css.dropDownMenuText), menuItemsSelector = getCssSelector(css.dropDownMenuItems), @@ -565,7 +550,7 @@ $.each(rowCountList, function (index, value) { - var item = $(template(tpl.actionDropDownItem, getParams.call(that, + var item = $(tpl.actionDropDownItem.resolve(getParams.call(that, { text: getText(value), action: value }))) ._bgSelectAria(value === that.rowCount) .on("click" + namespace, menuItemSelector, function (e) @@ -615,9 +600,9 @@ if (that.selection) { var selected = ($.inArray(row[that.identifier], that.selectedRows) !== -1), - selectBox = template(tpl.select, getParams.call(that, + selectBox = tpl.select.resolve(getParams.call(that, { type: "checkbox", value: row[that.identifier], checked: selected })); - cells += template(tpl.cell, getParams.call(that, { content: selectBox, css: css.selectCell })); + cells += tpl.cell.resolve(getParams.call(that, { content: selectBox, css: css.selectCell })); allRowsSelected = (allRowsSelected && selected); if (selected) { @@ -640,7 +625,7 @@ column.formatter.call(that, column, row) : column.converter.to(row[column.id]), cssClass = (column.cssClass.length > 0) ? " " + column.cssClass : ""; - cells += template(tpl.cell, getParams.call(that, { + 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, @@ -652,7 +637,7 @@ { rowAttr += " class=\"" + rowCss + "\""; } - html += template(tpl.row, getParams.call(that, { attr: rowAttr, cells: cells })); + html += tpl.row.resolve(getParams.call(that, { attr: rowAttr, cells: cells })); }); // sets or clears multi selectbox state @@ -737,7 +722,7 @@ timer = null, // fast keyup detection currentValue = "", searchFieldSelector = getCssSelector(css.searchField), - search = $(template(tpl.search, getParams.call(this))), + search = $(tpl.search.resolve(getParams.call(this))), searchField = (search.is(searchFieldSelector)) ? search : search.find(searchFieldSelector); @@ -786,8 +771,8 @@ if (this.selection) { var selectBox = (this.options.multiSelect) ? - template(tpl.select, getParams.call(that, { type: "checkbox", value: "all" })) : ""; - html += template(tpl.rawHeaderCell, getParams.call(that, { content: selectBox, + tpl.select.resolve(getParams.call(that, { type: "checkbox", value: "all" })) : ""; + html += tpl.rawHeaderCell.resolve(getParams.call(that, { content: selectBox, css: css.selectCell })); } @@ -798,10 +783,10 @@ var sortOrder = that.sortDictionary[column.id], iconCss = ((sorting && sortOrder && sortOrder === "asc") ? css.iconUp : (sorting && sortOrder && sortOrder === "desc") ? css.iconDown : ""), - icon = template(tpl.icon, getParams.call(that, { iconCss: iconCss })), + icon = tpl.icon.resolve(getParams.call(that, { iconCss: iconCss })), align = column.headerAlign, cssClass = (column.headerCssClass.length > 0) ? " " + column.headerCssClass : ""; - html += template(tpl.headerCell, getParams.call(that, { + 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, @@ -898,7 +883,7 @@ placeholder.each(function (index, item) { // todo: check how append is implemented. Perhaps cloning here is superfluous. - $(item).before(element).remove(); + $(item).before(element.clone(true)).remove(); }); } @@ -915,13 +900,13 @@ tbody = that.element.children("tbody").first(), firstCell = tbody.find("tr > td").first(), padding = (that.element.height() - thead.height()) - (firstCell.height() + 20), - count = arrayWhere(that.columns, isVisible).length; + count = that.columns.where(isVisible).length; if (that.selection) { count = count + 1; } - tbody.html(template(tpl.loading, getParams.call(that, { columns: count }))); + tbody.html(tpl.loading.resolve(getParams.call(that, { columns: count }))); if (that.rowCount !== -1 && padding > 0) { tbody.find("tr > td").css("padding", "20px 0 " + padding + "px"); @@ -1102,7 +1087,7 @@ * @for searchSettings **/ delay: 250, - + /** * The characters to type before the search gets executed. * @@ -1308,10 +1293,7 @@ **/ labels: { all: "All", - showing: "Showing", - to: "to", - of: "of", - entries: "entries", + infos: "Showing {{ctx.start}} to {{ctx.end}} of {{ctx.total}} entries", loading: "Loading...", noResults: "No results found!", refresh: "Refresh", @@ -1353,7 +1335,7 @@ * @for statusMapping **/ 2: "warning", - + /** * Specifies a dangerous or potentially negative action. * @@ -1383,7 +1365,7 @@ header: "

        ", headerCell: "
        ", icon: "", - infos: "
        {{lbl.showing}} {{ctx.start}} {{lbl.to}} {{ctx.end}} {{lbl.of}} {{ctx.total}} {{lbl.entries}}
        ", + infos: "
        {{lbl.infos}}
        ", loading: "", noResults: "", pagination: "
          ", @@ -1410,7 +1392,14 @@ } else { - var appendedRows = appendRows.call(this, rows); + var appendedRows = []; + for (var i = 0; i < rows.length; i++) + { + if (appendRow.call(this, rows[i])) + { + appendedRows.push(rows[i]); + } + } sortRows.call(this); highlightAppendedRows.call(this, appendedRows); loadData.call(this); @@ -1530,7 +1519,7 @@ }; /** - * Searches in all rows for a specific phrase (but only in visible cells). + * Searches in all rows for a specific phrase (but only in visible cells). * The search filter will be reseted, if no argument is provided. * * @method search @@ -1566,7 +1555,7 @@ { if (this.selection) { - rowIds = rowIds || arrayPropValues(this.currentRows, this.identifier); + rowIds = rowIds || this.currentRows.propValues(this.identifier); var id, i, selectedRows = []; @@ -1632,7 +1621,7 @@ { if (this.selection) { - rowIds = rowIds || arrayPropValues(this.currentRows, this.identifier); + rowIds = rowIds || this.currentRows.propValues(this.identifier); var id, i, pos, deselectedRows = []; @@ -1675,7 +1664,7 @@ }; /** - * Sorts the rows by a given sort descriptor dictionary. + * Sorts the rows by a given sort descriptor dictionary. * The sort filter will be reseted, if no argument is provided. * * @method sort @@ -1836,8 +1825,8 @@ _bgBusyAria: function(busy) { - return (busy == null || busy) ? - this._bgAria("busy", "true") : + return (busy == null || busy) ? + this._bgAria("busy", "true") : this._bgAria("busy", "false"); }, @@ -1848,29 +1837,29 @@ _bgEnableAria: function (enable) { - return (enable == null || enable) ? - this.removeClass("disabled")._bgAria("disabled", "false") : + return (enable == null || enable) ? + this.removeClass("disabled")._bgAria("disabled", "false") : this.addClass("disabled")._bgAria("disabled", "true"); }, _bgEnableField: function (enable) { - return (enable == null || enable) ? - this.removeAttr("disabled") : + return (enable == null || enable) ? + this.removeAttr("disabled") : this.attr("disabled", "disable"); }, _bgShowAria: function (show) { - return (show == null || show) ? + return (show == null || show) ? this.show()._bgAria("hidden", "false") : this.hide()._bgAria("hidden", "true"); }, _bgSelectAria: function (select) { - return (select == null || select) ? - this.addClass("active")._bgAria("selected", "true") : + return (select == null || select) ? + this.addClass("active")._bgAria("selected", "true") : this.removeClass("active")._bgAria("selected", "false"); }, @@ -1880,189 +1869,121 @@ } }); - var formatter = { - "checked": function(value) - { - if (typeof value === "boolean") + if (!String.prototype.resolve) + { + var formatter = { + "checked": function(value) { - return (value) ? "checked=\"checked\"" : ""; - } - return value; - } - }; - - var _templateCache = {}; - var getTemplate = function(template){ - if (!_templateCache.hasOwnProperty(template)){ - var str = template.split(/{([^{}]+)}/g); - - for (var i = 0; i < str.length; i++){ - var s = str[i]; - var hasStart = (s.charAt(0) === "}"); - var hasEnd = (s.charAt(s.length - 1) === "{"); - if (hasStart) - { - s = s.substr(1); - } - if (hasEnd) + if (typeof value === "boolean") { - s = s.substr(0, s.length - 1); - } - - if (hasStart || hasEnd) - { - str[i] = s; //plain old html - } else { - str[i] = { - token: str[i], - key: s.split(".") - }; + return (value) ? "checked=\"checked\"" : ""; } + return value; } - _templateCache[template] = str; - } - return _templateCache[template]; - }; - /* - // ONLY FOR TESTING - String.prototype.resolve_old = function (substitutes, prefixes) - { - var result = this; + }; - $.each(substitutes, function (key, value) + String.prototype.resolve = function (substitutes, prefixes) { - if (value != null && typeof value !== "function") + var result = this; + $.each(substitutes, function (key, value) { - if (typeof value === "object") - { - var keys = (prefixes) ? $.extend([], prefixes) : []; - keys.push(key); - result = result.resolve_old(value, keys) + ""; - } - else + if (value != null && typeof value !== "function") { - if (formatter && formatter[key] && typeof formatter[key] === "function") + if (typeof value === "object") { - value = formatter[key](value); + var keys = (prefixes) ? $.extend([], prefixes) : []; + keys.push(key); + result = result.resolve(value, keys) + ""; } - key = (prefixes) ? prefixes.join(".") + "." + key : key; - var pattern = new RegExp("\\{\\{" + key + "\\}\\}", "gm"); - result = result.replace(pattern, (value.replace) ? value.replace(/\$/gi, "$") : value); - } - } - }); - - return result; - }; - */ - var template = function (template, substitutes, prefixes) - { - var str = getTemplate(template); - var result = ""; - for (var i = 0; i < str.length; i++){ - if (typeof str[i] === "object"){ - var key = str[i].key; - var v = ""; - // now we have a variable to be substitued - if (substitutes.hasOwnProperty(key[0])) - { - v = substitutes[key[0]]; - } - else - { - continue; - } - - for (var k = 1; k < key.length; k++){ - if (v.hasOwnProperty(key[k])){ - v = v[key[k]]; - } else { - v = ""; - break; + else + { + if (formatter && formatter[key] && typeof formatter[key] === "function") + { + value = formatter[key](value); + } + key = (prefixes) ? prefixes.join(".") + "." + key : key; + var pattern = new RegExp("\\{\\{" + key + "\\}\\}", "gm"); + result = result.replace(pattern, (value.replace) ? value.replace(/\$/gi, "$") : value); } } - var formatter_key = key[key.length-1]; - if (formatter && formatter[formatter_key] && typeof formatter[formatter_key] === "function"){ - result += formatter[formatter_key](v); - } else { - result += v; - } - } else { - result += str[i]; // plain old html - } - } - // ONLY FOR TESTING - /* - var result_old = this.resolve_old(substitutes, prefixes); - if (result !== result_old){ - console.warn("Difference templating result"); - console.log(result); - console.log(result_old); - } - */ - return result; - }; - /* - var arrayFirst = function (arr, condition) + }); + return result; + }; + } + + if (!Array.prototype.first) { - for (var i = 0; i < arr.length; i++) + Array.prototype.first = function (condition) { - var item = arr[i]; - if (condition(item)) + for (var i = 0; i < this.length; i++) { - return item; + var item = this[i]; + if (condition(item)) + { + return item; + } } - } - return null; - }; - */ - var arrayContains = function (arr, condition) + return null; + }; + } + + if (!Array.prototype.contains) { - for (var i = 0; i < arr.length; i++) + Array.prototype.contains = function (condition) { - var item = arr[i]; - if (condition(item)) + for (var i = 0; i < this.length; i++) { - return true; + var item = this[i]; + if (condition(item)) + { + return true; + } } - } - return false; - }; + return false; + }; + } - var arrayPage = function (arr, page, size) + if (!Array.prototype.page) { - var skip = (page - 1) * size, - end = skip + size; - return (arr.length > skip) ? - (arr.length > end) ? arr.slice(skip, end) : - arr.slice(skip) : []; - }; - + Array.prototype.page = function (page, size) + { + var skip = (page - 1) * size, + end = skip + size; + return (this.length > skip) ? + (this.length > end) ? this.slice(skip, end) : + this.slice(skip) : []; + }; + } - var arrayWhere = function (arr, condition) + if (!Array.prototype.where) { - var result = []; - for (var i = 0; i < arr.length; i++) + Array.prototype.where = function (condition) { - var item = arr[i]; - if (condition(item)) + var result = []; + for (var i = 0; i < this.length; i++) { - result.push(item); + var item = this[i]; + if (condition(item)) + { + result.push(item); + } } - } - return result; - }; - + return result; + }; + } - var arrayPropValues = function (arr, propName) + if (!Array.prototype.propValues) { - var result = []; - for (var i = 0; i < arr.length; i++) + Array.prototype.propValues = function (propName) { - result.push(arr[i][propName]); - } - return result; - }; + var result = []; + for (var i = 0; i < this.length; i++) + { + result.push(this[i][propName]); + } + return result; + }; + } // GRID PLUGIN DEFINITION // ===================== diff --git a/dist/jquery.bootgrid.min.js b/dist/jquery.bootgrid.min.js new file mode 100644 index 0000000..b84a714 --- /dev/null +++ b/dist/jquery.bootgrid.min.js @@ -0,0 +1,6 @@ +/*! + * jQuery Bootgrid v1.3.1 - 09/11/2015 + * Copyright (c) 2014-2015 Rafael Staib (http://www.jquery-bootgrid.com) + * Licensed under MIT http://www.opensource.org/licenses/MIT + */ +!function(a,b,c){"use strict";function d(a){function b(b){return c.identifier&&b[c.identifier]===a[c.identifier]}var c=this;return this.rows.contains(b)?!1:(this.rows.push(a),!0)}function e(b){var c=this.footer?this.footer.find(b):a(),d=this.header?this.header.find(b):a();return a.merge(c,d)}function f(b){return b?a.extend({},this.cachedParams,{ctx:b}):this.cachedParams}function g(){var b={current:this.current,rowCount:this.rowCount,sort:this.sortDictionary,searchPhrase:this.searchPhrase},c=this.options.post;return c=a.isFunction(c)?c():c,this.options.requestHandler(a.extend(!0,b,c))}function h(b){return"."+a.trim(b).replace(/\s+/gm,".")}function i(){var b=this.options.url;return a.isFunction(b)?b():b}function j(){this.element.trigger("initialize"+H),m.call(this),this.selection=this.options.selection&&null!=this.identifier,o.call(this),q.call(this),C.call(this),A.call(this),r.call(this),n.call(this),this.element.trigger("initialized"+H)}function k(a){this.options.highlightRows}function l(a){return a.visible}function m(){var b=this,c=this.element.find("thead > tr").first(),d=!1;c.children().each(function(){var c=a(this),e=c.data(),f={id:e.columnId,identifier:null==b.identifier&&e.identifier||!1,converter:b.options.converters[e.converter||e.type]||b.options.converters.string,text:c.text(),align:e.align||"left",headerAlign:e.headerAlign||"left",cssClass:e.cssClass||"",headerCssClass:e.headerCssClass||"",formatter:b.options.formatters[e.formatter]||null,order:d||"asc"!==e.order&&"desc"!==e.order?null:e.order,searchable:!(e.searchable===!1),sortable:!(e.sortable===!1),visible:!(e.visible===!1),visibleInSelection:!(e.visibleInSelection===!1),width:a.isNumeric(e.width)?e.width+"px":"string"==typeof e.width?e.width:null};b.columns.push(f),null!=f.order&&(b.sortDictionary[f.id]=f.order),f.identifier&&(b.identifier=f.id,b.converter=f.converter),b.options.multiSort||null===f.order||(d=!0)})}function n(){function c(a){for(var b,c=new RegExp(e.searchPhrase,e.options.caseSensitive?"g":"gi"),d=0;d-1)return!0;return!1}function d(a,b){e.currentRows=a,p.call(e,b),e.options.keepSelection||(e.selectedRows=[]),y.call(e,a),t.call(e),v.call(e),e.element._bgBusyAria(!1).trigger("loaded"+H)}var e=this;if(this.element._bgBusyAria(!0).trigger("load"+H),F.call(this),this.options.ajax){var f=g.call(this),h=i.call(this);if(null==h||"string"!=typeof h||0===h.length)throw new Error("Url setting must be a none empty string or a function that returns one.");this.xqr&&this.xqr.abort();var j={url:h,data:f,success:function(b){e.xqr=null,"string"==typeof b&&(b=a.parseJSON(b)),b=e.options.responseHandler(b),e.current=b.current,d(b.rows,b.total)},error:function(a,b,c){e.xqr=null,"abort"!==b&&(u.call(e),e.element._bgBusyAria(!1).trigger("loaded"+H))}};j=a.extend(this.options.ajaxSettings,j),this.xqr=a.ajax(j)}else{var k=this.searchPhrase.length>0?this.rows.where(c):this.rows,l=k.length;-1!==this.rowCount&&(k=k.page(this.current,this.rowCount)),b.setTimeout(function(){d(k,l)},10)}}function o(){if(!this.options.ajax){var b=this,c=this.element.find("tbody > tr");c.each(function(){var c=a(this),e=c.children("td"),f={};a.each(b.columns,function(a,b){f[b.id]=b.converter.from(e.eq(a).text())}),d.call(b,f)}),p.call(this,this.rows.length),G.call(this)}}function p(a){this.total=a,this.totalPages=-1===this.rowCount?1:Math.ceil(this.total/this.rowCount)}function q(){var b=this.options.templates,c=this.element.parent().hasClass(this.options.css.responsiveTable)?this.element.parent():this.element;this.element.addClass(this.options.css.table),0===this.element.children("tbody").length&&this.element.append(b.body),1&this.options.navigation&&(this.header=a(b.header.resolve(f.call(this,{id:this.element._bgId()+"-header"}))),c.before(this.header)),2&this.options.navigation&&(this.footer=a(b.footer.resolve(f.call(this,{id:this.element._bgId()+"-footer"}))),c.after(this.footer))}function r(){if(0!==this.options.navigation){var b=this.options.css,c=h(b.actions),d=e.call(this,c);if(d.length>0){var g=this,i=this.options.templates,j=a(i.actions.resolve(f.call(this)));if(this.options.ajax){var k=i.icon.resolve(f.call(this,{iconCss:b.iconRefresh})),l=a(i.actionButton.resolve(f.call(this,{content:k,text:this.options.labels.refresh}))).on("click"+H,function(a){a.stopPropagation(),g.current=1,n.call(g)});j.append(l)}x.call(this,j),s.call(this,j),E.call(this,d,j)}}}function s(b){if(this.options.columnSelection&&this.columns.length>1){var c=this,d=this.options.css,e=this.options.templates,g=e.icon.resolve(f.call(this,{iconCss:d.iconColumns})),i=a(e.actionDropDown.resolve(f.call(this,{content:g}))),j=h(d.dropDownItem),k=h(d.dropDownItemCheckbox),m=h(d.dropDownMenuItems);a.each(this.columns,function(b,g){if(g.visibleInSelection){var o=a(e.actionDropDownCheckboxItem.resolve(f.call(c,{name:g.id,label:g.text,checked:g.visible}))).on("click"+H,j,function(b){b.stopPropagation();var d=a(this),e=d.find(k);if(!e.prop("disabled")){g.visible=e.prop("checked");var f=c.columns.where(l).length>1;d.parents(m).find(j+":has("+k+":checked)")._bgEnableAria(f).find(k)._bgEnableField(f),c.element.find("tbody").empty(),C.call(c),n.call(c)}});i.find(h(d.dropDownMenuItems)).append(o)}}),b.append(i)}}function t(){if(0!==this.options.navigation){var b=h(this.options.css.infos),c=e.call(this,b);if(c.length>0){var d=this.current*this.rowCount,g=a(this.options.templates.infos.resolve(f.call(this,{end:0===this.total||-1===d||d>this.total?this.total:d,start:0===this.total?0:d-this.rowCount+1,total:this.total})));E.call(this,c,g)}}}function u(){var a=this.element.children("tbody").first(),b=this.options.templates,c=this.columns.where(l).length;this.selection&&(c+=1),a.html(b.noResults.resolve(f.call(this,{columns:c})))}function v(){if(0!==this.options.navigation){var b=h(this.options.css.pagination),c=e.call(this,b)._bgShowAria(-1!==this.rowCount);if(-1!==this.rowCount&&c.length>0){var d=this.options.templates,g=this.current,i=this.totalPages,j=a(d.pagination.resolve(f.call(this))),k=i-g,l=-1*(this.options.padding-g),m=k>=this.options.padding?Math.max(l,1):Math.max(l-this.options.padding+k,1),n=2*this.options.padding+1,o=i>=n?n:i;w.call(this,j,"first","«","first")._bgEnableAria(g>1),w.call(this,j,"prev","<","prev")._bgEnableAria(g>1);for(var p=0;o>p;p++){var q=p+m;w.call(this,j,q,q,"page-"+q)._bgEnableAria()._bgSelectAria(q===g)}0===o&&w.call(this,j,1,1,"page-1")._bgEnableAria(!1)._bgSelectAria(),w.call(this,j,"next",">","next")._bgEnableAria(i>g),w.call(this,j,"last","»","last")._bgEnableAria(i>g),E.call(this,c,j)}}}function w(b,c,d,e){var g=this,i=this.options.templates,j=this.options.css,k=f.call(this,{css:e,text:d,page:c}),l=a(i.paginationItem.resolve(k)).on("click"+H,h(j.paginationButton),function(b){b.stopPropagation(),b.preventDefault();var c=a(this),d=c.parent();if(!d.hasClass("active")&&!d.hasClass("disabled")){var e={first:1,prev:g.current-1,next:g.current+1,last:g.totalPages},f=c.data("page");g.current=e[f]||f,n.call(g)}c.trigger("blur")});return b.append(l),l}function x(b){function c(a){return-1===a?d.options.labels.all:a}var d=this,e=this.options.rowCount;if(a.isArray(e)){var g=this.options.css,i=this.options.templates,j=a(i.actionDropDown.resolve(f.call(this,{content:c(this.rowCount)}))),k=h(g.dropDownMenu),l=h(g.dropDownMenuText),m=h(g.dropDownMenuItems),o=h(g.dropDownItemButton);a.each(e,function(b,e){var g=a(i.actionDropDownItem.resolve(f.call(d,{text:c(e),action:e})))._bgSelectAria(e===d.rowCount).on("click"+H,o,function(b){b.preventDefault();var e=a(this),f=e.data("action");f!==d.rowCount&&(d.current=1,d.rowCount=f,e.parents(m).children().each(function(){var b=a(this),c=b.find(o).data("action");b._bgSelectAria(c===f)}),e.parents(k).find(l).text(c(f)),n.call(d))});j.find(m).append(g)}),b.append(j)}}function y(b){if(b.length>0){var c=this,d=this.options.css,e=this.options.templates,g=this.element.children("tbody").first(),i=!0,j="";a.each(b,function(b,g){var h="",k=' data-row-id="'+(null==c.identifier?b:g[c.identifier])+'"',l="";if(c.selection){var m=-1!==a.inArray(g[c.identifier],c.selectedRows),n=e.select.resolve(f.call(c,{type:"checkbox",value:g[c.identifier],checked:m}));h+=e.cell.resolve(f.call(c,{content:n,css:d.selectCell})),i=i&&m,m&&(l+=d.selected,k+=' aria-selected="true"')}var o=null!=g.status&&c.options.statusMapping[g.status];o&&(l+=o),a.each(c.columns,function(b,i){if(i.visible){var j=a.isFunction(i.formatter)?i.formatter.call(c,i,g):i.converter.to(g[i.id]),k=i.cssClass.length>0?" "+i.cssClass:"";h+=e.cell.resolve(f.call(c,{content:null==j||""===j?" ":j,css:("right"===i.align?d.right:"center"===i.align?d.center:d.left)+k,style:null==i.width?"":"width:"+i.width+";"}))}}),l.length>0&&(k+=' class="'+l+'"'),j+=e.row.resolve(f.call(c,{attr:k,cells:h}))}),c.element.find("thead "+h(c.options.css.selectBox)).prop("checked",i),g.html(j),z.call(this,g)}else u.call(this)}function z(b){var c=this,d=h(this.options.css.selectBox);this.selection&&b.off("click"+H,d).on("click"+H,d,function(b){b.stopPropagation();var d=a(this),e=c.converter.from(d.val());d.prop("checked")?c.select([e]):c.deselect([e])}),b.off("click"+H,"> tr").on("click"+H,"> tr",function(b){b.stopPropagation();var d=a(this),e=null==c.identifier?d.data("row-id"):c.converter.from(d.data("row-id")+""),f=null==c.identifier?c.currentRows[e]:c.currentRows.first(function(a){return a[c.identifier]===e});c.selection&&c.options.rowSelect&&(d.hasClass(c.options.css.selected)?c.deselect([e]):c.select([e])),c.element.trigger("click"+H,[c.columns,f])})}function A(){if(0!==this.options.navigation){var c=this.options.css,d=h(c.search),g=e.call(this,d);if(g.length>0){var i=this,j=this.options.templates,k=null,l="",m=h(c.searchField),n=a(j.search.resolve(f.call(this))),o=n.is(m)?n:n.find(m);o.on("keyup"+H,function(c){c.stopPropagation();var d=a(this).val();(l!==d||13===c.which&&""!==d)&&(l=d,(13===c.which||0===d.length||d.length>=i.options.searchSettings.characters)&&(b.clearTimeout(k),k=b.setTimeout(function(){B.call(i,d)},i.options.searchSettings.delay)))}),E.call(this,g,n)}}}function B(a){this.searchPhrase!==a&&(this.current=1,this.searchPhrase=a,n.call(this))}function C(){var b=this,c=this.element.find("thead > tr"),d=this.options.css,e=this.options.templates,g="",i=this.options.sorting;if(this.selection){var j=this.options.multiSelect?e.select.resolve(f.call(b,{type:"checkbox",value:"all"})):"";g+=e.rawHeaderCell.resolve(f.call(b,{content:j,css:d.selectCell}))}if(a.each(this.columns,function(a,c){if(c.visible){var h=b.sortDictionary[c.id],j=i&&h&&"asc"===h?d.iconUp:i&&h&&"desc"===h?d.iconDown:"",k=e.icon.resolve(f.call(b,{iconCss:j})),l=c.headerAlign,m=c.headerCssClass.length>0?" "+c.headerCssClass:"";g+=e.headerCell.resolve(f.call(b,{column:c,icon:k,sortable:i&&c.sortable&&d.sortable||"",css:("right"===l?d.right:"center"===l?d.center:d.left)+m,style:null==c.width?"":"width:"+c.width+";"}))}}),c.html(g),i){var k=h(d.sortable);c.off("click"+H,k).on("click"+H,k,function(c){c.preventDefault(),D.call(b,a(this)),G.call(b),n.call(b)})}if(this.selection&&this.options.multiSelect){var l=h(d.selectBox);c.off("click"+H,l).on("click"+H,l,function(c){c.stopPropagation(),a(this).prop("checked")?b.select():b.deselect()})}}function D(a){var b=this.options.css,c=h(b.icon),d=a.data("column-id")||a.parents("th").first().data("column-id"),e=this.sortDictionary[d],f=a.find(c);if(this.options.multiSort||(a.parents("tr").first().find(c).removeClass(b.iconDown+" "+b.iconUp),this.sortDictionary={}),e&&"asc"===e)this.sortDictionary[d]="desc",f.removeClass(b.iconUp).addClass(b.iconDown);else if(e&&"desc"===e)if(this.options.multiSort){var g={};for(var i in this.sortDictionary)i!==d&&(g[i]=this.sortDictionary[i]);this.sortDictionary=g,f.removeClass(b.iconDown)}else this.sortDictionary[d]="asc",f.removeClass(b.iconDown).addClass(b.iconUp);else this.sortDictionary[d]="asc",f.addClass(b.iconUp)}function E(b,c){b.each(function(b,d){a(d).before(c.clone(!0)).remove()})}function F(){var a=this;b.setTimeout(function(){if("true"===a.element._bgAria("busy")){var b=a.options.templates,c=a.element.children("thead").first(),d=a.element.children("tbody").first(),e=d.find("tr > td").first(),g=a.element.height()-c.height()-(e.height()+20),h=a.columns.where(l).length;a.selection&&(h+=1),d.html(b.loading.resolve(f.call(a,{columns:h}))),-1!==a.rowCount&&g>0&&d.find("tr > td").css("padding","20px 0 "+g+"px")}},250)}function G(){function a(c,d,e){function f(a){return"asc"===h.order?a:-1*a}e=e||0;var g=e+1,h=b[e];return c[h.id]>d[h.id]?f(1):c[h.id]g?a(c,d,g):0}var b=[];if(!this.options.ajax){for(var c in this.sortDictionary)(this.options.multiSort||0===b.length)&&b.push({id:c,order:this.sortDictionary[c]});b.length>0&&this.rows.sort(a)}}var H=".rs.jquery.bootgrid",I=function(b,c){this.element=a(b),this.origin=this.element.clone(),this.options=a.extend(!0,{},I.defaults,this.element.data(),c);var d=this.options.rowCount=this.element.data().rowCount||c.rowCount||this.options.rowCount;this.columns=[],this.current=1,this.currentRows=[],this.identifier=null,this.selection=!1,this.converter=null,this.rowCount=a.isArray(d)?d[0]:d,this.rows=[],this.searchPhrase="",this.selectedRows=[],this.sortDictionary={},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};if(I.defaults={navigation:3,padding:2,columnSelection:!0,rowCount:[10,25,50,-1],selection:!1,multiSelect:!1,rowSelect:!1,keepSelection:!1,highlightRows:!1,sorting:!0,multiSort:!1,searchSettings:{delay:250,characters:1},ajax:!1,ajaxSettings:{method:"POST"},post:{},url:"",caseSensitive:!0,requestHandler:function(a){return a},responseHandler:function(a){return a},converters:{numeric:{from:function(a){return+a},to:function(a){return a+""}},string:{from:function(a){return a},to:function(a){return a}}},css:{actions:"actions btn-group",center:"text-center",columnHeaderAnchor:"column-header-anchor",columnHeaderText:"text",dropDownItem:"dropdown-item",dropDownItemButton:"dropdown-item-button",dropDownItemCheckbox:"dropdown-item-checkbox",dropDownMenu:"dropdown btn-group",dropDownMenuItems:"dropdown-menu pull-right",dropDownMenuText:"dropdown-text",footer:"bootgrid-footer container-fluid",header:"bootgrid-header container-fluid",icon:"icon glyphicon",iconColumns:"glyphicon-th-list",iconDown:"glyphicon-chevron-down",iconRefresh:"glyphicon-refresh",iconSearch:"glyphicon-search",iconUp:"glyphicon-chevron-up",infos:"infos",left:"text-left",pagination:"pagination",paginationButton:"button",responsiveTable:"table-responsive",right:"text-right",search:"search form-group",searchField:"search-field form-control",selectBox:"select-box",selectCell:"select-cell",selected:"active",sortable:"sortable",table:"bootgrid-table table"},formatters:{},labels:{all:"All",infos:"Showing {{ctx.start}} to {{ctx.end}} of {{ctx.total}} entries",loading:"Loading...",noResults:"No results found!",refresh:"Refresh",search:"Search"},statusMapping:{0:"success",1:"info",2:"warning",3:"danger"},templates:{actionButton:'',actionDropDown:'
          ',actionDropDownItem:'
        • {{ctx.text}}
        • ',actionDropDownCheckboxItem:'
        • ',actions:'
          ',body:"
          ",cell:'',footer:'

          ',header:'

          ',headerCell:'',icon:'',infos:'
          {{lbl.infos}}
          ',loading:'',noResults:'',pagination:'
            ',paginationItem:'
          • {{ctx.text}}
          • ',rawHeaderCell:'',row:"{{ctx.cells}}",search:'
            ',select:''}},I.prototype.append=function(a){if(this.options.ajax);else{for(var b=[],c=0;c0&&(this.options.multiSelect||1!==e.length);)if(c=b.pop(),-1===a.inArray(c,this.selectedRows))for(d=0;d0){var f=h(this.options.css.selectBox),g=this.selectedRows.length>=this.currentRows.length;for(d=0;!this.options.keepSelection&&g&&d tr "+f+":checked").trigger("click"+H),d=0;d tr[data-row-id="'+this.selectedRows[d]+'"]').addClass(this.options.css.selected)._bgAria("selected","true").find(f).prop("checked",!0);this.element.trigger("selected"+H,[e])}}return this},I.prototype.deselect=function(b){if(this.selection){b=b||this.currentRows.propValues(this.identifier);for(var c,d,e,f=[];b.length>0;)if(c=b.pop(),e=a.inArray(c,this.selectedRows),-1!==e)for(d=0;d0){var g=h(this.options.css.selectBox);for(this.element.find("thead "+g).prop("checked",!1),d=0;d tr[data-row-id="'+f[d][this.identifier]+'"]').removeClass(this.options.css.selected)._bgAria("selected","false").find(g).prop("checked",!1);this.element.trigger("deselected"+H,[f])}}return this},I.prototype.sort=function(b){var c=b?a.extend({},b):{};return c===this.sortDictionary?this:(this.sortDictionary=c,C.call(this),G.call(this),n.call(this),this)},I.prototype.getColumnSettings=function(){return a.merge([],this.columns)},I.prototype.getCurrentPage=function(){return this.current},I.prototype.getCurrentRows=function(){return a.merge([],this.currentRows)},I.prototype.getRowCount=function(){return this.rowCount},I.prototype.getSearchPhrase=function(){return this.searchPhrase},I.prototype.getSelectedRows=function(){return a.merge([],this.selectedRows)},I.prototype.getSortDictionary=function(){return a.extend({},this.sortDictionary)},I.prototype.getTotalPageCount=function(){return this.totalPages},I.prototype.getTotalRowCount=function(){return this.total},a.fn.extend({_bgAria:function(a,b){return b?this.attr("aria-"+a,b):this.attr("aria-"+a)},_bgBusyAria:function(a){return null==a||a?this._bgAria("busy","true"):this._bgAria("busy","false")},_bgRemoveAria:function(a){return this.removeAttr("aria-"+a)},_bgEnableAria:function(a){return null==a||a?this.removeClass("disabled")._bgAria("disabled","false"):this.addClass("disabled")._bgAria("disabled","true")},_bgEnableField:function(a){return null==a||a?this.removeAttr("disabled"):this.attr("disabled","disable")},_bgShowAria:function(a){return null==a||a?this.show()._bgAria("hidden","false"):this.hide()._bgAria("hidden","true")},_bgSelectAria:function(a){return null==a||a?this.addClass("active")._bgAria("selected","true"):this.removeClass("active")._bgAria("selected","false")},_bgId:function(a){return a?this.attr("id",a):this.attr("id")}}),!String.prototype.resolve){var J={checked:function(a){return"boolean"==typeof a?a?'checked="checked"':"":a}};String.prototype.resolve=function(b,c){var d=this;return a.each(b,function(b,e){if(null!=e&&"function"!=typeof e)if("object"==typeof e){var f=c?a.extend([],c):[];f.push(b),d=d.resolve(e,f)+""}else{J&&J[b]&&"function"==typeof J[b]&&(e=J[b](e)),b=c?c.join(".")+"."+b:b;var g=new RegExp("\\{\\{"+b+"\\}\\}","gm");d=d.replace(g,e.replace?e.replace(/\$/gi,"$"):e)}}),d}}Array.prototype.first||(Array.prototype.first=function(a){for(var b=0;bc?this.length>d?this.slice(c,d):this.slice(c):[]}),Array.prototype.where||(Array.prototype.where=function(a){for(var b=[],c=0;c 0) ? arrayWhere(this.rows, containsPhrase) : this.rows, + var rows = (this.searchPhrase.length > 0) ? this.rows.where(containsPhrase) : this.rows, total = rows.length; if (this.rowCount !== -1) { - rows = arrayPage(rows, this.current, this.rowCount); + rows = rows.page(this.current, this.rowCount); } // todo: improve the following comment @@ -277,7 +263,7 @@ function loadRows() { var that = this, rows = this.element.find("tbody > tr"); - var convertedRows = []; + rows.each(function () { var $this = $(this), @@ -289,9 +275,9 @@ function loadRows() row[column.id] = column.converter.from(cells.eq(i).text()); }); - convertedRows.push(row); + appendRow.call(that, row); }); - appendRows.call(that, convertedRows); + setTotals.call(this, this.rows.length); sortRows.call(this); } @@ -320,13 +306,13 @@ function prepareTable() if (this.options.navigation & 1) { - this.header = $(template(tpl.header, getParams.call(this, { id: this.element._bgId() + "-header" }))); + this.header = $(tpl.header.resolve(getParams.call(this, { id: this.element._bgId() + "-header" }))); wrapper.before(this.header); } if (this.options.navigation & 2) { - this.footer = $(template(tpl.footer, getParams.call(this, { id: this.element._bgId() + "-footer" }))); + this.footer = $(tpl.footer.resolve(getParams.call(this, { id: this.element._bgId() + "-footer" }))); wrapper.after(this.footer); } } @@ -343,13 +329,13 @@ function renderActions() { var that = this, tpl = this.options.templates, - actions = $(template(tpl.actions, getParams.call(this))); + actions = $(tpl.actions.resolve(getParams.call(this))); // Refresh Button if (this.options.ajax) { - var refreshIcon = template(tpl.icon, getParams.call(this, { iconCss: css.iconRefresh })), - refresh = $(template(tpl.actionButton, getParams.call(this, + 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) { @@ -379,8 +365,8 @@ function renderColumnSelection(actions) var that = this, css = this.options.css, tpl = this.options.templates, - icon = template(tpl.icon, getParams.call(this, { iconCss: css.iconColumns })), - dropDown = $(template(tpl.actionDropDown, getParams.call(this, { content: icon }))), + 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); @@ -389,21 +375,21 @@ function renderColumnSelection(actions) { if (column.visibleInSelection) { - var item = $(template(tpl.actionDropDownCheckboxItem, getParams.call(that, + 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(); - + var $this = $(this), checkbox = $this.find(checkboxSelector); if (!checkbox.prop("disabled")) { column.visible = checkbox.prop("checked"); - var enable = arrayWhere(that.columns, isVisible).length > 1; + 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); @@ -427,7 +413,7 @@ function renderInfos() if (infoItems.length > 0) { var end = (this.current * this.rowCount), - infos = $(template(this.options.templates.infos, getParams.call(this, { + 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 @@ -442,13 +428,13 @@ function renderNoResultsRow() { var tbody = this.element.children("tbody").first(), tpl = this.options.templates, - count = arrayWhere(this.columns, isVisible).length; + count = this.columns.where(isVisible).length; if (this.selection) { count = count + 1; } - tbody.html(template(tpl.noResults, getParams.call(this, { columns: count }))); + tbody.html(tpl.noResults.resolve(getParams.call(this, { columns: count }))); } function renderPagination() @@ -463,7 +449,7 @@ function renderPagination() var tpl = this.options.templates, current = this.current, totalPages = this.totalPages, - pagination = $(template(tpl.pagination, getParams.call(this))), + pagination = $(tpl.pagination.resolve(getParams.call(this))), offsetRight = totalPages - current, offsetLeft = (this.options.padding - current) * -1, startWith = ((offsetRight >= this.options.padding) ? @@ -506,7 +492,7 @@ function renderPaginationItem(list, page, text, markerCss) tpl = this.options.templates, css = this.options.css, values = getParams.call(this, { css: markerCss, text: text, page: page }), - item = $(template(tpl.paginationItem, values)) + item = $(tpl.paginationItem.resolve(values)) .on("click" + namespace, getCssSelector(css.paginationButton), function (e) { e.stopPropagation(); @@ -547,7 +533,7 @@ function renderRowCountSelection(actions) { var css = this.options.css, tpl = this.options.templates, - dropDown = $(template(tpl.actionDropDown, getParams.call(this, { content: getText(this.rowCount) }))), + dropDown = $(tpl.actionDropDown.resolve(getParams.call(this, { content: getText(this.rowCount) }))), menuSelector = getCssSelector(css.dropDownMenu), menuTextSelector = getCssSelector(css.dropDownMenuText), menuItemsSelector = getCssSelector(css.dropDownMenuItems), @@ -555,7 +541,7 @@ function renderRowCountSelection(actions) $.each(rowCountList, function (index, value) { - var item = $(template(tpl.actionDropDownItem, getParams.call(that, + var item = $(tpl.actionDropDownItem.resolve(getParams.call(that, { text: getText(value), action: value }))) ._bgSelectAria(value === that.rowCount) .on("click" + namespace, menuItemSelector, function (e) @@ -605,9 +591,9 @@ function renderRows(rows) if (that.selection) { var selected = ($.inArray(row[that.identifier], that.selectedRows) !== -1), - selectBox = template(tpl.select, getParams.call(that, + selectBox = tpl.select.resolve(getParams.call(that, { type: "checkbox", value: row[that.identifier], checked: selected })); - cells += template(tpl.cell, getParams.call(that, { content: selectBox, css: css.selectCell })); + cells += tpl.cell.resolve(getParams.call(that, { content: selectBox, css: css.selectCell })); allRowsSelected = (allRowsSelected && selected); if (selected) { @@ -630,7 +616,7 @@ function renderRows(rows) column.formatter.call(that, column, row) : column.converter.to(row[column.id]), cssClass = (column.cssClass.length > 0) ? " " + column.cssClass : ""; - cells += template(tpl.cell, getParams.call(that, { + 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, @@ -642,7 +628,7 @@ function renderRows(rows) { rowAttr += " class=\"" + rowCss + "\""; } - html += template(tpl.row, getParams.call(that, { attr: rowAttr, cells: cells })); + html += tpl.row.resolve(getParams.call(that, { attr: rowAttr, cells: cells })); }); // sets or clears multi selectbox state @@ -727,7 +713,7 @@ function renderSearchField() timer = null, // fast keyup detection currentValue = "", searchFieldSelector = getCssSelector(css.searchField), - search = $(template(tpl.search, getParams.call(this))), + search = $(tpl.search.resolve(getParams.call(this))), searchField = (search.is(searchFieldSelector)) ? search : search.find(searchFieldSelector); @@ -776,8 +762,8 @@ function renderTableHeader() if (this.selection) { var selectBox = (this.options.multiSelect) ? - template(tpl.select, getParams.call(that, { type: "checkbox", value: "all" })) : ""; - html += template(tpl.rawHeaderCell, getParams.call(that, { content: selectBox, + tpl.select.resolve(getParams.call(that, { type: "checkbox", value: "all" })) : ""; + html += tpl.rawHeaderCell.resolve(getParams.call(that, { content: selectBox, css: css.selectCell })); } @@ -788,10 +774,10 @@ function renderTableHeader() var sortOrder = that.sortDictionary[column.id], iconCss = ((sorting && sortOrder && sortOrder === "asc") ? css.iconUp : (sorting && sortOrder && sortOrder === "desc") ? css.iconDown : ""), - icon = template(tpl.icon, getParams.call(that, { iconCss: iconCss })), + icon = tpl.icon.resolve(getParams.call(that, { iconCss: iconCss })), align = column.headerAlign, cssClass = (column.headerCssClass.length > 0) ? " " + column.headerCssClass : ""; - html += template(tpl.headerCell, getParams.call(that, { + 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, @@ -905,13 +891,13 @@ function showLoading() tbody = that.element.children("tbody").first(), firstCell = tbody.find("tr > td").first(), padding = (that.element.height() - thead.height()) - (firstCell.height() + 20), - count = arrayWhere(that.columns, isVisible).length; + count = that.columns.where(isVisible).length; if (that.selection) { count = count + 1; } - tbody.html(template(tpl.loading, getParams.call(that, { columns: count }))); + tbody.html(tpl.loading.resolve(getParams.call(that, { columns: count }))); if (that.rowCount !== -1 && padding > 0) { tbody.find("tr > td").css("padding", "20px 0 " + padding + "px"); diff --git a/src/public.js b/src/public.js index 032ffb3..16c001f 100644 --- a/src/public.js +++ b/src/public.js @@ -128,7 +128,7 @@ Grid.defaults = { * @for searchSettings **/ delay: 250, - + /** * The characters to type before the search gets executed. * @@ -379,7 +379,7 @@ Grid.defaults = { * @for statusMapping **/ 2: "warning", - + /** * Specifies a dangerous or potentially negative action. * @@ -436,7 +436,14 @@ Grid.prototype.append = function(rows) } else { - var appendedRows = appendRows.call(this, rows); + var appendedRows = []; + for (var i = 0; i < rows.length; i++) + { + if (appendRow.call(this, rows[i])) + { + appendedRows.push(rows[i]); + } + } sortRows.call(this); highlightAppendedRows.call(this, appendedRows); loadData.call(this); @@ -556,7 +563,7 @@ Grid.prototype.remove = function(rowIds) }; /** - * Searches in all rows for a specific phrase (but only in visible cells). + * Searches in all rows for a specific phrase (but only in visible cells). * The search filter will be reseted, if no argument is provided. * * @method search @@ -592,7 +599,7 @@ Grid.prototype.select = function(rowIds) { if (this.selection) { - rowIds = rowIds || arrayPropValues(this.currentRows, this.identifier); + rowIds = rowIds || this.currentRows.propValues(this.identifier); var id, i, selectedRows = []; @@ -658,7 +665,7 @@ Grid.prototype.deselect = function(rowIds) { if (this.selection) { - rowIds = rowIds || arrayPropValues(this.currentRows, this.identifier); + rowIds = rowIds || this.currentRows.propValues(this.identifier); var id, i, pos, deselectedRows = []; @@ -701,7 +708,7 @@ Grid.prototype.deselect = function(rowIds) }; /** - * Sorts the rows by a given sort descriptor dictionary. + * Sorts the rows by a given sort descriptor dictionary. * The sort filter will be reseted, if no argument is provided. * * @method sort diff --git a/test/tests-extensions.js b/test/tests-extensions.js index 64d21d6..f0e5994 100644 --- a/test/tests-extensions.js +++ b/test/tests-extensions.js @@ -13,7 +13,7 @@ test("String.resolve basic (one dimension) test", 1, function () stringToResolve = "{{first}} {{second}}"; // when - var result = template(stringToResolve, values); + var result = stringToResolve.resolve(values); // then equal(result, "test case", "Valid string"); @@ -38,7 +38,7 @@ test("String.resolve advanced (n dimension) test", 1, function () stringToResolve = "{{first.sub}} {{second}} {{third.more}} {{third.adv.test}} {{third.case}}"; // when - var result = template(stringToResolve, values); + var result = stringToResolve.resolve(values); // then equal(result, "this is a more advanced test case", "Valid string"); From 94e1e5b54ac8f3140ba867298adbae0c10a02f72 Mon Sep 17 00:00:00 2001 From: Zac Spitzer Date: Sat, 10 Dec 2016 19:37:36 +1100 Subject: [PATCH 12/13] refactor out base prototypes remove prototypes from string and array merge in appendRow #285 improves Chrome 50%, FF 15%, Edge 10% --- src/extensions.js | 319 ++++++++++++++++++--------------------- src/internal.js | 86 ++++++----- src/public.js | 21 +-- test/tests-extensions.js | 4 +- 4 files changed, 204 insertions(+), 226 deletions(-) diff --git a/src/extensions.js b/src/extensions.js index 1e70467..e32ab1c 100644 --- a/src/extensions.js +++ b/src/extensions.js @@ -9,8 +9,8 @@ $.fn.extend({ _bgBusyAria: function(busy) { - return (busy == null || busy) ? - this._bgAria("busy", "true") : + return (busy == null || busy) ? + this._bgAria("busy", "true") : this._bgAria("busy", "false"); }, @@ -21,29 +21,29 @@ $.fn.extend({ _bgEnableAria: function (enable) { - return (enable == null || enable) ? - this.removeClass("disabled")._bgAria("disabled", "false") : + return (enable == null || enable) ? + this.removeClass("disabled")._bgAria("disabled", "false") : this.addClass("disabled")._bgAria("disabled", "true"); }, _bgEnableField: function (enable) { - return (enable == null || enable) ? - this.removeAttr("disabled") : + return (enable == null || enable) ? + this.removeAttr("disabled") : this.attr("disabled", "disable"); }, _bgShowAria: function (show) { - return (show == null || show) ? + return (show == null || show) ? this.show()._bgAria("hidden", "false") : this.hide()._bgAria("hidden", "true"); }, _bgSelectAria: function (select) { - return (select == null || select) ? - this.addClass("active")._bgAria("selected", "true") : + return (select == null || select) ? + this.addClass("active")._bgAria("selected", "true") : this.removeClass("active")._bgAria("selected", "false"); }, @@ -53,200 +53,171 @@ $.fn.extend({ } }); -if (!String.prototype.resolve) -{ - var formatter = { - "checked": function(value) +var formatter = { + "checked": function(value) + { + if (typeof value === "boolean") { - if (typeof value === "boolean") + return (value) ? "checked=\"checked\"" : ""; + } + return value; + } +}; + +var _templateCache = {}; +var getTemplate = function(template){ + if (!_templateCache.hasOwnProperty(template)){ + var str = template.split(/{([^{}]+)}/g); + + for (var i = 0; i < str.length; i++){ + var s = str[i]; + var hasStart = (s.charAt(0) === "}"); + var hasEnd = (s.charAt(s.length - 1) === "{"); + if (hasStart) { - return (value) ? "checked=\"checked\"" : ""; + s = s.substr(1); + } + if (hasEnd) + { + s = s.substr(0, s.length - 1); } - return value; - } - }; - - var _templateCache = {}; - var getTemplate = function(template){ - if (!_templateCache.hasOwnProperty(template)){ - var str = template.split(/{([^{}]+)}/g); - - for (var i = 0; i < str.length; i++){ - var s = str[i]; - var hasStart = (s.charAt(0) === "}"); - var hasEnd = (s.charAt(s.length - 1) === "{"); - if (hasStart) - { - s = s.substr(1); - } - if (hasEnd) - { - s = s.substr(0, s.length - 1); - } - if (hasStart || hasEnd) - { - str[i] = s; //plain old html - } else { - str[i] = { - token: str[i], - key: s.split(".") - }; - } + if (hasStart || hasEnd) + { + str[i] = s; //plain old html + } else { + str[i] = { + token: str[i], + key: s.split(".") + }; } - _templateCache[template] = str; } - return _templateCache[template]; - }; - - // ONLY FOR TESTING - String.prototype.resolve_old = function (substitutes, prefixes) - { - var result = this; + _templateCache[template] = str; + } + return _templateCache[template]; +}; +/* +// ONLY FOR TESTING +var String.prototype.resolve_old = function (substitutes, prefixes) +{ + var result = this; - $.each(substitutes, function (key, value) + $.each(substitutes, function (key, value) + { + if (value != null && typeof value !== "function") { - if (value != null && typeof value !== "function") + if (typeof value === "object") { - if (typeof value === "object") - { - var keys = (prefixes) ? $.extend([], prefixes) : []; - keys.push(key); - result = result.resolve_old(value, keys) + ""; - } - else - { - if (formatter && formatter[key] && typeof formatter[key] === "function") - { - value = formatter[key](value); - } - key = (prefixes) ? prefixes.join(".") + "." + key : key; - var pattern = new RegExp("\\{\\{" + key + "\\}\\}", "gm"); - result = result.replace(pattern, (value.replace) ? value.replace(/\$/gi, "$") : value); - } + var keys = (prefixes) ? $.extend([], prefixes) : []; + keys.push(key); + result = result.resolve_old(value, keys) + ""; } - }); - - return result; - }; - - String.prototype.resolve = function (substitutes, prefixes) - { - var str = getTemplate(this); - var result = ""; - for (var i = 0; i < str.length; i++){ - if (typeof str[i] === "object"){ - var key = str[i].key; - var v = ""; - // now we have a variable to be substitued - if (substitutes.hasOwnProperty(key[0])) - { - v = substitutes[key[0]]; - } - else + else + { + if (formatter && formatter[key] && typeof formatter[key] === "function") { - continue; + value = formatter[key](value); } - - for (var k = 1; k < key.length; k++){ - if (v.hasOwnProperty(key[k])){ - v = v[key[k]]; - } else { - v = ""; - break; - } - } - var formatter_key = key[key.length-1]; - if (formatter && formatter[formatter_key] && typeof formatter[formatter_key] === "function"){ - result += formatter[formatter_key](v); - } else { - result += v; - } - } else { - result += str[i]; // plain old html + key = (prefixes) ? prefixes.join(".") + "." + key : key; + var pattern = new RegExp("\\{\\{" + key + "\\}\\}", "gm"); + result = result.replace(pattern, (value.replace) ? value.replace(/\$/gi, "$") : value); } } - // ONLY FOR TESTING, remove for release or testing performance of individal approaches - var result_old = this.resolve_old(substitutes, prefixes); - if (result !== result_old){ - console.warn("Different templating result"); - console.log("new: ", result); - console.log("old: ", result_old); - } - return result; - }; -} + }); -if (!Array.prototype.first) + return result; +}; +*/ +var template = function (template, substitutes, prefixes) { - Array.prototype.first = function (condition) - { - for (var i = 0; i < this.length; i++) - { - var item = this[i]; - if (condition(item)) + var str = getTemplate(template); + var result = ""; + for (var i = 0; i < str.length; i++){ + if (typeof str[i] === "object"){ + var key = str[i].key; + var v = ""; + // now we have a variable to be substitued + if (substitutes.hasOwnProperty(key[0])) { - return item; + v = substitutes[key[0]]; + } + else + { + continue; } - } - return null; - }; -} -if (!Array.prototype.contains) + for (var k = 1; k < key.length; k++){ + if (v.hasOwnProperty(key[k])){ + v = v[key[k]]; + } else { + v = ""; + break; + } + } + var formatter_key = key[key.length-1]; + if (formatter && formatter[formatter_key] && typeof formatter[formatter_key] === "function"){ + result += formatter[formatter_key](v); + } else { + result += v; + } + } else { + result += str[i]; // plain old html + } + } + // ONLY FOR TESTING + /* + var result_old = this.resolve_old(substitutes, prefixes); + if (result !== result_old){ + console.warn("Difference templating result"); + console.log(result); + console.log(result_old); + } +*/ + return result; +}; +var arrayContains = function (arr, condition) { - Array.prototype.contains = function (condition) + for (var i = 0; i < arr.length; i++) { - for (var i = 0; i < this.length; i++) + var item = arr[i]; + if (condition(item)) { - var item = this[i]; - if (condition(item)) - { - return true; - } + return true; } - return false; - }; -} + } + return false; +}; -if (!Array.prototype.page) +var arrayPage = function (arr, page, size) { - Array.prototype.page = function (page, size) - { - var skip = (page - 1) * size, - end = skip + size; - return (this.length > skip) ? - (this.length > end) ? this.slice(skip, end) : - this.slice(skip) : []; - }; -} - -if (!Array.prototype.where) + var skip = (page - 1) * size, + end = skip + size; + return (arr.length > skip) ? + (arr.length > end) ? arr.slice(skip, end) : + arr.slice(skip) : []; +}; + +var arrayWhere = function (arr, condition) { - Array.prototype.where = function (condition) + var result = []; + for (var i = 0; i < arr.length; i++) { - var result = []; - for (var i = 0; i < this.length; i++) + var item = arr[i]; + if (condition(item)) { - var item = this[i]; - if (condition(item)) - { - result.push(item); - } + result.push(item); } - return result; - }; -} + } + return result; +}; -if (!Array.prototype.propValues) +var arrayPropValues = function (arr, propName) { - Array.prototype.propValues = function (propName) + var result = []; + for (var i = 0; i < arr.length; i++) { - var result = []; - for (var i = 0; i < this.length; i++) - { - result.push(this[i][propName]); - } - return result; - }; -} + result.push(arr[i][propName]); + } + return result; +}; + diff --git a/src/internal.js b/src/internal.js index 5ed0af8..a141fa3 100644 --- a/src/internal.js +++ b/src/internal.js @@ -15,7 +15,7 @@ function appendRow(row) return that.identifier && item[that.identifier] === row[that.identifier]; } - if (!this.rows.contains(exists)) + if (!arrayContains(this.rows, exists)) { this.rows.push(row); return true; @@ -24,6 +24,20 @@ function appendRow(row) return false; } +function appendRows(rows) +{ + var that = this; + + var appendedRows = rows.slice(); + appendedRows.filter(function(item) { + return !(that.identifier && item[that.identifier] === rows[that.identifier]); + }); + + this.rows = this.rows.concat(appendedRows); + + return appendedRows; +} + function findFooterAndHeaderItems(selector) { var footer = (this.footer) ? this.footer.find(selector) : $(), @@ -117,7 +131,7 @@ function loadColumns() sortable: !(data.sortable === false), // default: true visible: !(data.visible === false), // default: true visibleInSelection: !(data.visibleInSelection === false), // default: true - width: ($.isNumeric(data.width)) ? data.width + "px" : + width: ($.isNumeric(data.width)) ? data.width + "px" : (typeof(data.width) === "string") ? data.width : null }; that.columns.push(column); @@ -244,11 +258,11 @@ function loadData() } else { - var rows = (this.searchPhrase.length > 0) ? this.rows.where(containsPhrase) : this.rows, + var rows = (this.searchPhrase.length > 0) ? arrayWhere(this.rows, containsPhrase) : this.rows, total = rows.length; if (this.rowCount !== -1) { - rows = rows.page(this.current, this.rowCount); + rows = arrayPage(rows, this.current, this.rowCount); } // todo: improve the following comment @@ -263,7 +277,7 @@ function loadRows() { var that = this, rows = this.element.find("tbody > tr"); - + var convertedRows = []; rows.each(function () { var $this = $(this), @@ -275,9 +289,9 @@ function loadRows() row[column.id] = column.converter.from(cells.eq(i).text()); }); - appendRow.call(that, row); + convertedRows.push(row); }); - + appendRows.call(that, convertedRows); setTotals.call(this, this.rows.length); sortRows.call(this); } @@ -306,13 +320,13 @@ function prepareTable() if (this.options.navigation & 1) { - this.header = $(tpl.header.resolve(getParams.call(this, { id: this.element._bgId() + "-header" }))); + this.header = $(template(tpl.header, getParams.call(this, { id: this.element._bgId() + "-header" }))); wrapper.before(this.header); } if (this.options.navigation & 2) { - this.footer = $(tpl.footer.resolve(getParams.call(this, { id: this.element._bgId() + "-footer" }))); + this.footer = $(template(tpl.footer, getParams.call(this, { id: this.element._bgId() + "-footer" }))); wrapper.after(this.footer); } } @@ -329,13 +343,13 @@ function renderActions() { var that = this, tpl = this.options.templates, - actions = $(tpl.actions.resolve(getParams.call(this))); + actions = $(template(tpl.actions, 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, + var refreshIcon = template(tpl.icon, getParams.call(this, { iconCss: css.iconRefresh })), + refresh = $(template(tpl.actionButton, getParams.call(this, { content: refreshIcon, text: this.options.labels.refresh }))) .on("click" + namespace, function (e) { @@ -365,8 +379,8 @@ function renderColumnSelection(actions) 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 }))), + icon = template(tpl.icon, getParams.call(this, { iconCss: css.iconColumns })), + dropDown = $(template(tpl.actionDropDown, getParams.call(this, { content: icon }))), selector = getCssSelector(css.dropDownItem), checkboxSelector = getCssSelector(css.dropDownItemCheckbox), itemsSelector = getCssSelector(css.dropDownMenuItems); @@ -375,21 +389,21 @@ function renderColumnSelection(actions) { if (column.visibleInSelection) { - var item = $(tpl.actionDropDownCheckboxItem.resolve(getParams.call(that, + var item = $(template(tpl.actionDropDownCheckboxItem, getParams.call(that, { name: column.id, label: column.text, checked: column.visible }))) .on("click" + namespace, selector, function (e) { 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; + var enable = arrayWhere(that.columns, 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); @@ -413,7 +427,7 @@ function renderInfos() if (infoItems.length > 0) { var end = (this.current * this.rowCount), - infos = $(this.options.templates.infos.resolve(getParams.call(this, { + infos = $(template(this.options.templates.infos, 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 @@ -428,13 +442,13 @@ function renderNoResultsRow() { var tbody = this.element.children("tbody").first(), tpl = this.options.templates, - count = this.columns.where(isVisible).length; + count = arrayWhere(this.columns, isVisible).length; if (this.selection) { count = count + 1; } - tbody.html(tpl.noResults.resolve(getParams.call(this, { columns: count }))); + tbody.html(template(tpl.noResults, getParams.call(this, { columns: count }))); } function renderPagination() @@ -449,7 +463,7 @@ function renderPagination() var tpl = this.options.templates, current = this.current, totalPages = this.totalPages, - pagination = $(tpl.pagination.resolve(getParams.call(this))), + pagination = $(template(tpl.pagination, getParams.call(this))), offsetRight = totalPages - current, offsetLeft = (this.options.padding - current) * -1, startWith = ((offsetRight >= this.options.padding) ? @@ -492,7 +506,7 @@ function renderPaginationItem(list, page, text, markerCss) tpl = this.options.templates, css = this.options.css, values = getParams.call(this, { css: markerCss, text: text, page: page }), - item = $(tpl.paginationItem.resolve(values)) + item = $(template(tpl.paginationItem, values)) .on("click" + namespace, getCssSelector(css.paginationButton), function (e) { e.stopPropagation(); @@ -533,7 +547,7 @@ function renderRowCountSelection(actions) { var css = this.options.css, tpl = this.options.templates, - dropDown = $(tpl.actionDropDown.resolve(getParams.call(this, { content: getText(this.rowCount) }))), + dropDown = $(template(tpl.actionDropDown, getParams.call(this, { content: getText(this.rowCount) }))), menuSelector = getCssSelector(css.dropDownMenu), menuTextSelector = getCssSelector(css.dropDownMenuText), menuItemsSelector = getCssSelector(css.dropDownMenuItems), @@ -541,7 +555,7 @@ function renderRowCountSelection(actions) $.each(rowCountList, function (index, value) { - var item = $(tpl.actionDropDownItem.resolve(getParams.call(that, + var item = $(template(tpl.actionDropDownItem, getParams.call(that, { text: getText(value), action: value }))) ._bgSelectAria(value === that.rowCount) .on("click" + namespace, menuItemSelector, function (e) @@ -591,9 +605,9 @@ function renderRows(rows) if (that.selection) { var selected = ($.inArray(row[that.identifier], that.selectedRows) !== -1), - selectBox = tpl.select.resolve(getParams.call(that, + selectBox = template(tpl.select, getParams.call(that, { type: "checkbox", value: row[that.identifier], checked: selected })); - cells += tpl.cell.resolve(getParams.call(that, { content: selectBox, css: css.selectCell })); + cells += template(tpl.cell, getParams.call(that, { content: selectBox, css: css.selectCell })); allRowsSelected = (allRowsSelected && selected); if (selected) { @@ -616,7 +630,7 @@ function renderRows(rows) 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, { + cells += template(tpl.cell, getParams.call(that, { content: (value == null || value === "") ? " " : value, css: ((column.align === "right") ? css.right : (column.align === "center") ? css.center : css.left) + cssClass, @@ -628,7 +642,7 @@ function renderRows(rows) { rowAttr += " class=\"" + rowCss + "\""; } - html += tpl.row.resolve(getParams.call(that, { attr: rowAttr, cells: cells })); + html += template(tpl.row, getParams.call(that, { attr: rowAttr, cells: cells })); }); // sets or clears multi selectbox state @@ -713,7 +727,7 @@ function renderSearchField() timer = null, // fast keyup detection currentValue = "", searchFieldSelector = getCssSelector(css.searchField), - search = $(tpl.search.resolve(getParams.call(this))), + search = $(template(tpl.search, getParams.call(this))), searchField = (search.is(searchFieldSelector)) ? search : search.find(searchFieldSelector); @@ -762,8 +776,8 @@ function renderTableHeader() if (this.selection) { var selectBox = (this.options.multiSelect) ? - tpl.select.resolve(getParams.call(that, { type: "checkbox", value: "all" })) : ""; - html += tpl.rawHeaderCell.resolve(getParams.call(that, { content: selectBox, + template(tpl.select, getParams.call(that, { type: "checkbox", value: "all" })) : ""; + html += template(tpl.rawHeaderCell, getParams.call(that, { content: selectBox, css: css.selectCell })); } @@ -774,10 +788,10 @@ function renderTableHeader() var sortOrder = that.sortDictionary[column.id], iconCss = ((sorting && sortOrder && sortOrder === "asc") ? css.iconUp : (sorting && sortOrder && sortOrder === "desc") ? css.iconDown : ""), - icon = tpl.icon.resolve(getParams.call(that, { iconCss: iconCss })), + icon = template(tpl.icon, getParams.call(that, { iconCss: iconCss })), align = column.headerAlign, cssClass = (column.headerCssClass.length > 0) ? " " + column.headerCssClass : ""; - html += tpl.headerCell.resolve(getParams.call(that, { + html += template(tpl.headerCell, 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, @@ -891,13 +905,13 @@ function showLoading() tbody = that.element.children("tbody").first(), firstCell = tbody.find("tr > td").first(), padding = (that.element.height() - thead.height()) - (firstCell.height() + 20), - count = that.columns.where(isVisible).length; + count = arrayWhere(that.columns, isVisible).length; if (that.selection) { count = count + 1; } - tbody.html(tpl.loading.resolve(getParams.call(that, { columns: count }))); + tbody.html(template(tpl.loading, getParams.call(that, { columns: count }))); if (that.rowCount !== -1 && padding > 0) { tbody.find("tr > td").css("padding", "20px 0 " + padding + "px"); diff --git a/src/public.js b/src/public.js index 16c001f..032ffb3 100644 --- a/src/public.js +++ b/src/public.js @@ -128,7 +128,7 @@ Grid.defaults = { * @for searchSettings **/ delay: 250, - + /** * The characters to type before the search gets executed. * @@ -379,7 +379,7 @@ Grid.defaults = { * @for statusMapping **/ 2: "warning", - + /** * Specifies a dangerous or potentially negative action. * @@ -436,14 +436,7 @@ Grid.prototype.append = function(rows) } else { - var appendedRows = []; - for (var i = 0; i < rows.length; i++) - { - if (appendRow.call(this, rows[i])) - { - appendedRows.push(rows[i]); - } - } + var appendedRows = appendRows.call(this, rows); sortRows.call(this); highlightAppendedRows.call(this, appendedRows); loadData.call(this); @@ -563,7 +556,7 @@ Grid.prototype.remove = function(rowIds) }; /** - * Searches in all rows for a specific phrase (but only in visible cells). + * Searches in all rows for a specific phrase (but only in visible cells). * The search filter will be reseted, if no argument is provided. * * @method search @@ -599,7 +592,7 @@ Grid.prototype.select = function(rowIds) { if (this.selection) { - rowIds = rowIds || this.currentRows.propValues(this.identifier); + rowIds = rowIds || arrayPropValues(this.currentRows, this.identifier); var id, i, selectedRows = []; @@ -665,7 +658,7 @@ Grid.prototype.deselect = function(rowIds) { if (this.selection) { - rowIds = rowIds || this.currentRows.propValues(this.identifier); + rowIds = rowIds || arrayPropValues(this.currentRows, this.identifier); var id, i, pos, deselectedRows = []; @@ -708,7 +701,7 @@ Grid.prototype.deselect = function(rowIds) }; /** - * Sorts the rows by a given sort descriptor dictionary. + * Sorts the rows by a given sort descriptor dictionary. * The sort filter will be reseted, if no argument is provided. * * @method sort diff --git a/test/tests-extensions.js b/test/tests-extensions.js index f0e5994..64d21d6 100644 --- a/test/tests-extensions.js +++ b/test/tests-extensions.js @@ -13,7 +13,7 @@ test("String.resolve basic (one dimension) test", 1, function () stringToResolve = "{{first}} {{second}}"; // when - var result = stringToResolve.resolve(values); + var result = template(stringToResolve, values); // then equal(result, "test case", "Valid string"); @@ -38,7 +38,7 @@ test("String.resolve advanced (n dimension) test", 1, function () stringToResolve = "{{first.sub}} {{second}} {{third.more}} {{third.adv.test}} {{third.case}}"; // when - var result = stringToResolve.resolve(values); + var result = template(stringToResolve, values); // then equal(result, "this is a more advanced test case", "Valid string"); From f9ee37f58a3a93f86529f770f54794699e043576 Mon Sep 17 00:00:00 2001 From: Zac Spitzer Date: Sat, 10 Dec 2016 19:53:16 +1100 Subject: [PATCH 13/13] remove appendRow no longer needed since appendRows --- src/internal.js | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/src/internal.js b/src/internal.js index a141fa3..febc364 100644 --- a/src/internal.js +++ b/src/internal.js @@ -6,24 +6,6 @@ var namespace = ".rs.jquery.bootgrid"; // GRID INTERNAL FUNCTIONS // ===================== -function appendRow(row) -{ - var that = this; - - function exists(item) - { - return that.identifier && item[that.identifier] === row[that.identifier]; - } - - if (!arrayContains(this.rows, exists)) - { - this.rows.push(row); - return true; - } - - return false; -} - function appendRows(rows) { var that = this;
            IDSenderIDSender Received Link Status {{ctx.column.text}}{{ctx.icon}}
            {{lbl.loading}}
            {{lbl.noResults}}
            {{ctx.content}}{{ctx.column.text}}{{ctx.icon}}
            {{lbl.loading}}
            {{lbl.noResults}}
            {{ctx.content}}
            {{ctx.column.text}}{{ctx.icon}}
            {{lbl.loading}}
            {{lbl.noResults}}
            {{ctx.content}}{{ctx.column.text}}{{ctx.icon}}
            {{lbl.loading}}
            {{lbl.noResults}}
            {{ctx.content}}