/*!
* Bootstrap Data Table Plugin v1.5.5
*
* Author: Jeff Dupont
* ==========================================================
* Copyright 2012
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* ==========================================================
*/
(function($) {
/* DATATABLE CLASS DEFINITION
* ========================== */
var DataTable = function(element, options) {
this.$element = $(element);
this.options = options;
this.pendingRequest = null;
this.enabled = true;
this.columns = [];
this.rows = [];
this.buttons = [];
// this needs to be handled better
this.localStorageId =
"datatable_" + (options.id || options.url.replace(/\W/gi, "_"));
// set the defaults for the column options array
for (var column in this.options.columns) {
// check sortable
if (typeof this.options.columns[column].sortable === undefined)
this.options.columns[column].sortable = true;
}
this.$default = this.$element.children().length
? this.$element.children()
: $("
")
.addClass("alert alert-danger")
.html(i18n.no_results_found);
this.$element.addClass("clearfix");
// clear out the localStorage for this entry
if (localStorage) {
localStorage[this.localStorageId] = "false";
}
if (
this.options.tablePreRender &&
typeof this.options.tablePreRender === "function"
)
this.options.tablePreRender.call(this);
// initialize the toolbar
_initToolbar.call(this);
if (this.options.autoLoad === true) this.render();
};
DataTable.prototype = {
constructor: DataTable,
render: function() {
var o = this.options,
$e = this.$element;
// show loading
this.loading(true);
// reset the columns and rows
this.columns = [];
this.rows = [];
this.buttons = [];
this.$wrapper = undefined;
this.$table = undefined;
this.$header = undefined;
this.$body = undefined;
this.$footer = undefined;
this.$pagination = undefined;
if (this.$toolbar) this.$toolbar.remove();
// add summary on top
this.$summary_table = $("")
.append("").append("
");
// top
this.$top_details = $("").attr("id", "dt-top-details");
// bottom
this.$bottom_details = $("").attr("id", "dt-bottom-details");
// localize the object
var that = this;
// pull in the data from the ajax call
if (o.debug)
console.log(
$.extend({}, o.post, {
currentPage: o.currentPage,
perPage: o.perPage,
sort: o.sort,
filter: o.filter
})
);
if (o.url !== "") {
var req_data = typeof o.post === "function" ? o.post() : o.post;
if (this.pendingRequest) this.pendingRequest.abort();
this.pendingRequest = $.ajax({
url: o.url,
type: "GET",
dataType: "json",
data: $.extend({}, req_data, {
currentPage: o.currentPage,
perPage: o.perPage,
sortColumn: o.sort.length > 0 ? o.sort[0][0] : null,
sortOrder: o.sort.length > 0 ? o.sort[0][1] : null,
filter: o.filter
}),
success: function(res, status, xhr) {
that.pendingRequest = null;
if (o.dataAdapter) res = o.dataAdapter(res, o);
that.resultset = res;
if (!res || res === undefined || !res.data || (res.data.length == 0 && !o.forceTable)) {
showError.call(that, res);
return;
}
// clear out the current elements in the container
$e.empty();
// set the sort and filter configuration
o.sort = res.sort;
o.filter = res.filter;
o.totalRows = res.totalRows;
// set the current page if we're forcing it from the server
if (res.currentPage) o.currentPage = parseInt(res.currentPage);
// retrieve the saved columns
_retrieveColumns.call(that, localStorage[that.localStorageId]);
// append the table
$e.append(that.table());
// append the detail boxes
$e.prepend(that.$top_details);
if (res.summary != undefined) $e.prepend(that.$summary_table);
$e.append(that.$bottom_details);
// render the rest of the table
if (o.showHeader) that.header();
if (o.showFooter) that.footer();
// fill in the table body
that.body();
// render table summary
if (res.summary != undefined) {
// do a validity check summing all percentages
if (res.summary.map(s => s.percentage).reduce((acc, curr) => acc + curr) <= 100) {
// clear the previous state
const $summary = that.$summary_table.find('summary');
$summary.empty();
const colors = ["bg-primary", "bg-secondary", "bg-success", "bg-danger", "bg-warning", "bg-info", "bg-dark"];
const $progresses = $("");
const $list = that.$summary_table.find('div.details > ul');
$list.empty();
// create progresses bars
res.summary.forEach((s) => {
const color = colors.pop();
const $progress = $(``);
$progress.attr('role', 'progressbar');
$progress.css('width', `${s.percentage}%`);
$progress.addClass(color);
$progresses.append($progress);
const $li = $(``);
$li.html(` ${s.label} (${s.percentage}%)`);
$list.append($li);
});
$summary.append($progresses);
}
}
// render the pagination
if (o.showTopPagination && that.pagination())
that.$top_details.append(that.pagination().clone(true));
if (o.showPagination && that.pagination())
that.$bottom_details.append(that.pagination().clone(true));
// update the details for the results
if (!o.hideDetails) that.details();
// initialize the toolbar
_initToolbar.call(that);
// nearly complete... let the user apply any final adjustments
if (o.tableCallback && typeof o.tableCallback === "function")
o.tableCallback.call(that);
that.loading(false);
},
error: function(xhr, status, e) {
that.pendingRequest = null;
if (status !== "abort")
console.error("Datatable: error while loading data: " + e);
showError.call(that, null, status, e);
that.loading(false);
}
});
}
},
loading: function(show) {
var $e = this.$element;
var o = this.options;
if (o.customLoading) {
o.customLoading(this, show);
return;
}
if (!this.$loading) {
this.$loading = $("")
.css({
position: "absolute",
top: parseInt($e.position().top) + 5 + (o.loadingYOffset || 0),
left:
parseInt($e.position().left) +
parseInt($e.css("marginLeft")) +
Math.floor($e.width() / 4),
width: Math.floor($e.width() / 2) + "px"
})
.append(
$("")
.addClass("progress progress-striped")
.append(
$("")
.addClass(
"progress-bar progress-bar-animated progress-bar-info"
)
.attr("style", "width: 50%")
)
)
.appendTo(document.body);
}
if (show) {
$e.css({ opacity: 0.2 });
} else {
$e.css({ opacity: 1 });
this.$loading.remove();
this.$loading = undefined;
}
},
toolbar: function() {
var o = this.options,
$e = this.$element,
that = this;
this.$toolbar = $("").addClass(
"dt-toolbar btn-toolbar float-right"
);
this.$button_group = $("")
.addClass("btn-group")
.appendTo(this.$toolbar);
// add all the custom buttons
for (var i = 0; i < o.buttons.length; i++) {
this.buttons.push(o.buttons[i]);
}
// attach all buttons to the toolbar
$.each(this.buttons, function() {
that.$button_group.append(this);
});
// attach the toolbar to the section header
if (o.sectionHeader) {
this.$section_header = $(o.sectionHeader);
this.$section_header.append(this.$toolbar);
} else if (o.title !== "" && !this.$section_header) {
this.$section_header = $("")
.html(o.title)
.append(this.$toolbar);
$e.before(this.$section_header);
} else {
if (!this.$toolbar_container) {
this.$toolbar_container = $("").addClass(
"dt-toolbar-container clearfix"
);
}
$e.prepend(this.$toolbar_container.append(this.$toolbar));
}
return this.$toolbar;
},
details: function() {
var o = this.options,
res = this.resultset,
start = 0,
end = 0,
that = this;
start = o.currentPage * o.perPage - o.perPage + 1;
if (start < 1) start = 1;
end = o.currentPage * o.perPage;
if (end > o.totalRows) end = o.totalRows;
$(
'
"
).prependTo(this.$bottom_details);
},
table: function() {
var $e = this.$element,
o = this.options;
if (!this.$table_wrapper) {
this.$wrapper = $("").addClass("dt-table-wrapper");
}
if (!this.$table) {
this.$table = $("
").addClass(o.class);
}
this.$wrapper.append(this.$table);
return this.$wrapper;
},
header: function() {
var o = this.options,
res = this.resultset;
if (!this.$header) {
this.$header = $("");
var row = $("
");
// loop through the columns
for (var column in o.columns) {
var $cell = this.column(column),
colprop = $cell.data("column_properties");
// attach the sort click event
if (colprop.sortable && !colprop.custom)
$cell.click(this, this.sort).css({ cursor: "pointer" });
for (var i = 0; i < o.sort.length; i++) {
if (o.sort[i][0] == colprop.field) {
if (o.sort[i][1] == "asc") {
$cell.append($(o.ascending));
colprop.sortOrder = "asc";
} else if (o.sort[i][1] == "desc") {
$cell.append($(o.descending));
colprop.sortOrder = "desc";
}
}
}
row.append($cell);
this.$header.append(row);
this.columns.push($cell);
}
// any final user adjustments to the header
if (o.headerCallback && typeof o.headerCallback === "function")
o.headerCallback.call(this);
this.$table.append(this.$header);
}
return this.$header;
},
footer: function() {
var o = this.options,
res = this.resultset;
if (!this.$footer) {
this.$footer = $("");
// loop through the columns
for (column in o.columns) {
var $cell = $("
");
$cell
.data("cell_properties", o.columns[column])
.addClass(o.columns[column].classname);
this.$footer.append($cell);
}
// any final user adjustments to the footer
if (o.footerCallback && typeof o.footerCallback === "function")
o.footerCallback.call(this, this.resultset.footer);
this.$table.append(this.$footer);
}
return this.$footer;
},
body: function() {
var res = this.resultset,
o = this.options;
if (!this.$body) {
this.$body = $("");
// loop through the results
for (var i = 0; i < res.data.length; i++) {
var row = this.row(res.data[i]);
this.$body.append(row);
this.rows.push(row);
}
if (o.showFilterRow) this.$body.prepend(this.filter());
this.$table.append(this.$body);
}
return this.$body;
},
filter: function() {
var $row = $("
"),
o = this.options,
that = this;
$row.addClass("dt-filter-row");
// loop through the columns
for (var column in o.columns) {
var $cell = $("