",
select: ""
}
};
/**
* Appends rows.
*
* @method append
* @param rows {Array} An array of rows to append
* @chainable
**/
Grid.prototype.append = function(rows)
{
if (this.options.ajax)
{
// todo: implement ajax PUT
}
else
{
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);
this.element.trigger("appended" + namespace, [appendedRows]);
}
return this;
};
/**
* Removes all rows.
*
* @method clear
* @chainable
**/
Grid.prototype.clear = function()
{
if (this.options.ajax)
{
// todo: implement ajax POST
}
else
{
var removedRows = $.extend([], this.rows);
this.rows = [];
this.current = 1;
this.total = 0;
loadData.call(this);
this.element.trigger("cleared" + namespace, [removedRows]);
}
return this;
};
/**
* Removes the control functionality completely and transforms the current state to the initial HTML structure.
*
* @method destroy
* @chainable
**/
Grid.prototype.destroy = function()
{
// todo: this method has to be optimized (the complete initial state must be restored)
$(window).off(namespace);
if (this.options.navigation & 1)
{
this.header.remove();
}
if (this.options.navigation & 2)
{
if (this.footer) {
this.footer.remove();
}
}
this.element.before(this.origin).remove();
return this;
};
/**
* Resets the state and reloads rows.
*
* @method reload
* @chainable
**/
Grid.prototype.reload = function()
{
this.current = 1; // reset
loadData.call(this);
return this;
};
/**
* Removes rows by ids. Removes selected rows if no ids are provided.
*
* @method remove
* @param [rowsIds] {Array} An array of rows ids to remove
* @chainable
**/
Grid.prototype.remove = function(rowIds)
{
if (this.identifier != null)
{
var that = this;
if (this.options.ajax)
{
// todo: implement ajax DELETE
}
else
{
rowIds = rowIds || this.selectedRows;
var id,
removedRows = [];
for (var i = 0; i < rowIds.length; i++)
{
id = rowIds[i];
for (var j = 0; j < this.rows.length; j++)
{
if (this.rows[j][this.identifier] === id)
{
removedRows.push(this.rows[j]);
this.rows.splice(j, 1);
break;
}
}
}
this.current = 1; // reset
loadData.call(this);
this.element.trigger("removed" + namespace, [removedRows]);
}
}
return this;
};
/**
* 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
* @param [phrase] {String} The phrase to search for
* @chainable
**/
Grid.prototype.search = function(phrase)
{
phrase = phrase || "";
if (this.searchPhrase !== phrase)
{
var selector = getCssSelector(this.options.css.searchField),
searchFields = findFooterAndHeaderItems.call(this, selector);
searchFields.val(phrase);
}
executeSearch.call(this, phrase);
return this;
};
/**
* Selects rows by ids. Selects all visible rows if no ids are provided.
* In server-side scenarios only visible rows are selectable.
*
* @method select
* @param [rowsIds] {Array} An array of rows ids to select
* @chainable
**/
Grid.prototype.select = function(rowIds)
{
if (this.selection)
{
rowIds = rowIds || this.currentRows.propValues(this.identifier);
var id, i,
selectedRows = [];
while (rowIds.length > 0 && !(!this.options.multiSelect && selectedRows.length === 1))
{
id = rowIds.pop();
if ($.inArray(id, this.selectedRows) === -1)
{
for (i = 0; i < this.currentRows.length; i++)
{
if (this.currentRows[i][this.identifier] === id)
{
selectedRows.push(this.currentRows[i]);
this.selectedRows.push(id);
break;
}
}
}
}
if (selectedRows.length > 0)
{
var selectBoxSelector = getCssSelector(this.options.css.selectBox),
selectMultiSelectBox = this.selectedRows.length >= this.currentRows.length;
i = 0;
while (!this.options.keepSelection && selectMultiSelectBox && i < this.currentRows.length)
{
selectMultiSelectBox = ($.inArray(this.currentRows[i++][this.identifier], this.selectedRows) !== -1);
}
this.element.find("thead " + selectBoxSelector).prop("checked", selectMultiSelectBox);
if (!this.options.multiSelect)
{
this.element.find("tbody > tr " + selectBoxSelector + ":checked")
.trigger("click" + namespace);
}
for (i = 0; i < this.selectedRows.length; i++)
{
this.element.find("tbody > tr[data-row-id=\"" + this.selectedRows[i] + "\"]")
.addClass(this.options.css.selected)._bgAria("selected", "true")
.find(selectBoxSelector).prop("checked", true);
}
this.element.trigger("selected" + namespace, [selectedRows]);
}
}
return this;
};
/**
* Deselects rows by ids. Deselects all visible rows if no ids are provided.
* In server-side scenarios only visible rows are deselectable.
*
* @method deselect
* @param [rowsIds] {Array} An array of rows ids to deselect
* @chainable
**/
Grid.prototype.deselect = function(rowIds)
{
if (this.selection)
{
rowIds = rowIds || this.currentRows.propValues(this.identifier);
var id, i, pos,
deselectedRows = [];
while (rowIds.length > 0)
{
id = rowIds.pop();
pos = $.inArray(id, this.selectedRows);
if (pos !== -1)
{
for (i = 0; i < this.currentRows.length; i++)
{
if (this.currentRows[i][this.identifier] === id)
{
deselectedRows.push(this.currentRows[i]);
this.selectedRows.splice(pos, 1);
break;
}
}
}
}
if (deselectedRows.length > 0)
{
var selectBoxSelector = getCssSelector(this.options.css.selectBox);
this.element.find("thead " + selectBoxSelector).prop("checked", false);
for (i = 0; i < deselectedRows.length; i++)
{
this.element.find("tbody > tr[data-row-id=\"" + deselectedRows[i][this.identifier] + "\"]")
.removeClass(this.options.css.selected)._bgAria("selected", "false")
.find(selectBoxSelector).prop("checked", false);
}
this.element.trigger("deselected" + namespace, [deselectedRows]);
}
}
return this;
};
/**
* Sorts the rows by a given sort descriptor dictionary.
* The sort filter will be reseted, if no argument is provided.
*
* @method sort
* @param [dictionary] {Object} A sort descriptor dictionary that contains the sort information
* @chainable
**/
Grid.prototype.sort = function(dictionary)
{
var values = (dictionary) ? $.extend({}, dictionary) : {};
if (values === this.sortDictionary)
{
return this;
}
this.sortDictionary = values;
renderTableHeader.call(this);
sortRows.call(this);
loadData.call(this);
return this;
};
/**
* Gets a list of the column settings.
* This method returns only for the first grid instance a value.
* Therefore be sure that only one grid instance is catched by your selector.
*
* @method getColumnSettings
* @return {Array} Returns a list of the column settings.
* @since 1.2.0
**/
Grid.prototype.getColumnSettings = function()
{
return $.merge([], this.columns);
};
/**
* Gets the current page index.
* This method returns only for the first grid instance a value.
* Therefore be sure that only one grid instance is catched by your selector.
*
* @method getCurrentPage
* @return {Number} Returns the current page index.
* @since 1.2.0
**/
Grid.prototype.getCurrentPage = function()
{
return this.current;
};
/**
* Gets the current rows.
* This method returns only for the first grid instance a value.
* Therefore be sure that only one grid instance is catched by your selector.
*
* @method getCurrentPage
* @return {Array} Returns the current rows.
* @since 1.2.0
**/
Grid.prototype.getCurrentRows = function()
{
return $.merge([], this.currentRows);
};
/**
* Gets a number represents the row count per page.
* This method returns only for the first grid instance a value.
* Therefore be sure that only one grid instance is catched by your selector.
*
* @method getRowCount
* @return {Number} Returns the row count per page.
* @since 1.2.0
**/
Grid.prototype.getRowCount = function()
{
return this.rowCount;
};
/**
* Gets the actual search phrase.
* This method returns only for the first grid instance a value.
* Therefore be sure that only one grid instance is catched by your selector.
*
* @method getSearchPhrase
* @return {String} Returns the actual search phrase.
* @since 1.2.0
**/
Grid.prototype.getSearchPhrase = function()
{
return this.searchPhrase;
};
/**
* Gets the complete list of currently selected rows.
* This method returns only for the first grid instance a value.
* Therefore be sure that only one grid instance is catched by your selector.
*
* @method getSelectedRows
* @return {Array} Returns all selected rows.
* @since 1.2.0
**/
Grid.prototype.getSelectedRows = function()
{
return $.merge([], this.selectedRows);
};
/**
* Gets the sort dictionary which represents the state of column sorting.
* This method returns only for the first grid instance a value.
* Therefore be sure that only one grid instance is catched by your selector.
*
* @method getSortDictionary
* @return {Object} Returns the sort dictionary.
* @since 1.2.0
**/
Grid.prototype.getSortDictionary = function()
{
return $.extend({}, this.sortDictionary);
};
/**
* Gets a number represents the total page count.
* This method returns only for the first grid instance a value.
* Therefore be sure that only one grid instance is catched by your selector.
*
* @method getTotalPageCount
* @return {Number} Returns the total page count.
* @since 1.2.0
**/
Grid.prototype.getTotalPageCount = function()
{
return this.totalPages;
};
/**
* Gets a number represents the total row count.
* This method returns only for the first grid instance a value.
* Therefore be sure that only one grid instance is catched by your selector.
*
* @method getTotalRowCount
* @return {Number} Returns the total row count.
* @since 1.2.0
**/
Grid.prototype.getTotalRowCount = function()
{
return this.total;
};
// GRID COMMON TYPE EXTENSIONS
// ============
$.fn.extend({
_bgAria: function (name, value)
{
return (value) ? this.attr("aria-" + name, value) : this.attr("aria-" + name);
},
_bgBusyAria: function(busy)
{
return (busy == null || busy) ?
this._bgAria("busy", "true") :
this._bgAria("busy", "false");
},
_bgRemoveAria: function (name)
{
return this.removeAttr("aria-" + name);
},
_bgEnableAria: function (enable)
{
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") :
this.attr("disabled", "disable");
},
_bgShowAria: function (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") :
this.removeClass("active")._bgAria("selected", "false");
},
_bgId: function (id)
{
return (id) ? this.attr("id", id) : this.attr("id");
}
});
if (!String.prototype.resolve)
{
var formatter = {
"checked": function(value)
{
if (typeof value === "boolean")
{
return (value) ? "checked=\"checked\"" : "";
}
return value;
}
};
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) + "";
}
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;
};
}
if (!Array.prototype.first)
{
Array.prototype.first = function (condition)
{
for (var i = 0; i < this.length; i++)
{
var item = this[i];
if (condition(item))
{
return item;
}
}
return null;
};
}
if (!Array.prototype.contains)
{
Array.prototype.contains = function (condition)
{
for (var i = 0; i < this.length; i++)
{
var item = this[i];
if (condition(item))
{
return true;
}
}
return false;
};
}
if (!Array.prototype.page)
{
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)
{
Array.prototype.where = function (condition)
{
var result = [];
for (var i = 0; i < this.length; i++)
{
var item = this[i];
if (condition(item))
{
result.push(item);
}
}
return result;
};
}
if (!Array.prototype.propValues)
{
Array.prototype.propValues = function (propName)
{
var result = [];
for (var i = 0; i < this.length; i++)
{
result.push(this[i][propName]);
}
return result;
};
}
// GRID PLUGIN DEFINITION
// =====================
var old = $.fn.bootgrid;
$.fn.bootgrid = function (option)
{
var args = Array.prototype.slice.call(arguments, 1),
returnValue = null,
elements = this.each(function (index)
{
var $this = $(this),
instance = $this.data(namespace),
options = typeof option === "object" && option;
if (!instance && option === "destroy")
{
return;
}
if (!instance)
{
$this.data(namespace, (instance = new Grid(this, options)));
init.call(instance);
}
if (typeof option === "string")
{
if (option.indexOf("get") === 0 && index === 0)
{
returnValue = instance[option].apply(instance, args);
}
else if (option.indexOf("get") !== 0)
{
return instance[option].apply(instance, args);
}
}
});
return (typeof option === "string" && option.indexOf("get") === 0) ? returnValue : elements;
};
$.fn.bootgrid.Constructor = Grid;
// GRID NO CONFLICT
// ===============
$.fn.bootgrid.noConflict = function ()
{
$.fn.bootgrid = old;
return this;
};
// GRID DATA-API
// ============
$("[data-toggle=\"bootgrid\"]").bootgrid();
})(jQuery, window);
function windowHeight() {
setTimeout(() => $(window).scrollTop($('.bootgrid-header').offset().top), 5);
}