@progress/kendo-ui
Version:
This package is part of the [Kendo UI for jQuery](http://www.telerik.com/kendo-ui) suite.
14,402 lines • 635 kB
JavaScript
require("./kendo.icons.js");
require("./kendo.badge.js");
require("./kendo.html.button.js");
require("./kendo.data-T0mqWOrQ.js");
require("./kendo.selectable.js");
require("./kendo.textbox.js");
require("./kendo.editable.js");
require("./kendo.form.js");
require("./kendo.window.js");
require("./kendo.ooxml.js");
require("./kendo.excel.js");
require("./kendo.groupable.js");
require("./kendo.reorderable.js");
require("./kendo.resizable.js");
require("./kendo.sortable.js");
require("./kendo.menu.js");
require("./kendo.toolbar.js");
require("./kendo.switch.js");
require("./kendo.pager.js");
require("./kendo.pane.js");
require("./kendo.filtermenu.js");
require("./kendo.columnmenu.js");
require("./kendo.columnsorter.js");
require("./kendo.aiprompt-B8fknJle.js");
require("./kendo.filtercell.js");
require("./kendo.pdf.js");
require("./kendo.csv.js");
require("./kendo.dialog.js");
require("./kendo.smartbox.js");
require("./kendo.loader.js");
require("./kendo.html.loadercontainer.js");
const require_loaderContainer = require("./loaderContainer-DYINJiua.js");
//#region ../src/grid/contextmenu.js
(function($, undefined) {
var kendo = window.kendo, ContextMenu = kendo.ui.ContextMenu, extend = $.extend, encode = kendo.htmlEncode;
var ACTION = "action";
var GridContextMenu = ContextMenu.extend({
init: function(element, options) {
var that = this;
ContextMenu.fn.init.call(that, element, options);
that._overrideTemplates();
that._extendItems();
that.bind("select", that._onSelect.bind(that));
that.bind("open", that._onOpen.bind(that));
ContextMenu.fn.endInit.call(that);
},
_overrideTemplates: function() {
this.templates.sprite = ({ icon, spriteCssClass }) => `${icon || spriteCssClass ? kendo.ui.icon({
icon: encode(icon || ""),
iconClass: encode(spriteCssClass || "")
}) : ""}`;
},
defaultItems: {
"separator": {
name: "separator",
separator: true
},
"create": {
name: "create",
text: "Add",
icon: "plus",
command: "AddCommand",
rules: "isEditable"
},
"edit": {
name: "edit",
text: "Edit",
icon: "pencil",
command: "EditCommand",
rules: "isEditable"
},
"destroy": {
name: "destroy",
text: "Delete",
icon: "trash",
command: "DeleteCommand",
rules: "isEditable"
},
"select": {
name: "select",
text: "Select",
icon: "table-body",
rules: "isSelectable",
items: [
{
name: "selectRow",
text: "Row",
icon: "table-row-groups",
command: "SelectRowCommand"
},
{
name: "selectAllRows",
text: "All rows",
icon: "grid",
command: "SelectAllRowsCommand"
},
{
name: "clearSelection",
text: "Clear selection",
icon: "table-unmerge",
softRules: "hasSelection",
command: "ClearSelectionCommand"
}
]
},
"copySelection": {
name: "copySelection",
text: "Copy selection",
icon: "page-header-section",
rules: "isSelectable",
softRules: "hasSelection",
command: "CopySelectionCommand",
options: "withHeaders"
},
"copySelectionNoHeaders": {
name: "copySelectionNoHeaders",
text: "Copy selection (No Headers)",
icon: "file-txt",
rules: "isSelectable",
softRules: "hasSelection",
command: "CopySelectionCommand"
},
"paste": {
name: "paste",
text: "Paste (use CTRL/⌘ + V)",
rules: "allowPaste",
softRules: "alwaysDisabled",
icon: "clipboard"
},
"reorderRow": {
name: "reorderRow",
text: "Reorder row",
icon: "caret-alt-expand",
rules: "isRowReorderable",
softRules: "isSorted",
items: [
{
name: "reorderRowUp",
text: "Up",
icon: "chevron-up",
command: "ReorderRowCommand",
options: "dir:up"
},
{
name: "reorderRowDown",
text: "Down",
icon: "chevron-down",
command: "ReorderRowCommand",
options: "dir:down"
},
{
name: "reorderRowTop",
text: "Top",
icon: "caret-alt-to-top",
command: "ReorderRowCommand",
options: "dir:top"
},
{
name: "reorderRowBottom",
text: "Bottom",
icon: "caret-alt-to-bottom",
command: "ReorderRowCommand",
options: "dir:bottom"
}
]
},
"exportPDF": {
name: "exportPDF",
text: "Export to PDF",
icon: "file-pdf",
command: "ExportPDFCommand"
},
"exportExcel": {
name: "exportExcel",
text: "Export to Excel",
icon: "file-excel",
items: [
{
name: "exportToExcelAll",
text: "All",
command: "ExportExcelCommand"
},
{
name: "exportToExcelSelection",
text: "Selection",
command: "ExportExcelCommand",
softRules: "hasSelection",
options: "selection,withHeaders"
},
{
name: "exportToExcelSelectionNoHeaders",
text: "Selection (No Headers)",
softRules: "hasSelection",
command: "ExportExcelCommand",
options: "selection"
}
]
},
"exportCSV": {
name: "exportCSV",
text: "Export to CSV",
icon: "file-csv",
items: [
{
name: "exportToCSVAll",
text: "All",
command: "ExportCSVCommand"
},
{
name: "exportToCSVSelection",
text: "Selection",
command: "ExportCSVCommand",
softRules: "hasSelection",
options: "selection,withHeaders"
},
{
name: "exportToCSVSelectionNoHeaders",
text: "Selection (No Headers)",
softRules: "hasSelection",
command: "ExportCSVCommand",
options: "selection"
}
]
},
"sortAsc": {
name: "sortAsc",
text: "Sort Ascending",
icon: "sort-asc-small",
rules: "isSortable",
command: "SortCommand",
options: "dir:asc"
},
"sortDesc": {
name: "sortDesc",
text: "Sort Descending",
icon: "sort-desc-small",
rules: "isSortable",
command: "SortCommand",
options: "dir:desc"
},
"moveGroupPrevious": {
name: "moveGroupPrevious",
text: "Move previous",
icon: "arrow-left",
rules: "isGroupable",
softRules: "canMoveGroupPrev",
command: "MoveGroupCommand",
options: "dir:prev"
},
"moveGroupNext": {
name: "moveGroupNext",
text: "Move next",
icon: "arrow-right",
rules: "isGroupable",
softRules: "canMoveGroupNext",
command: "MoveGroupCommand",
options: "dir:next"
},
"pinRow": {
name: "pinRow",
text: "Pin row",
icon: "pin",
rules: "isPinnable",
items: [
{
name: "pinTop",
text: "Pin row to top",
icon: "pin-top",
command: "PinTopCommand"
},
{
name: "pinBottom",
text: "Pin row to bottom",
icon: "pin-bottom",
command: "PinBottomCommand"
},
{
name: "unpin",
text: "Unpin row",
icon: "unpin",
command: "UnpinCommand"
}
]
}
},
events: ContextMenu.fn.events.concat([ACTION]),
_onSelect: function(ev) {
var command = $(ev.item).data("command");
var options = $(ev.item).data("options");
options = options ? options.split(",").map((val) => {
if (val.indexOf(":") > -1) {
var [key, val] = val.split(":");
return { [key || "_"]: val };
}
return { [val]: true };
}).reduce((acc, v) => Object.assign(acc, v), {}) : {};
var target = $(ev.target);
if (!command) return;
this.action({
command,
options: Object.assign(options, { target })
});
},
_onOpen: function(ev) {
var menu = ev.sender, items = menu.options.items, elTarget = $(ev.event ? ev.event.target : null);
if (!items && $.isEmptyObject(this.defaultItems) || elTarget.closest(".k-grid-column-menu").length) {
ev.preventDefault();
return;
}
this._toggleSeparatorVisibility();
menu.element.find(`[${kendo.attr("soft-rules")}]`).each((i, item) => {
var rules = $(item).attr(kendo.attr("soft-rules")).split(";");
menu.enable(item, this._validateSoftRules(rules, elTarget));
});
},
_toggleSeparatorVisibility: function() {
this.element.find(".k-item.k-separator").filter((i, item) => {
var prev = $(item).prev(".k-item:not(.k-separator)");
var next = $(item).next(".k-item:not(.k-separator)");
return !(prev.length && next.length);
}).hide();
},
_extendItems: function() {
var that = this, items = that.options.items, item, isBuiltInTool;
if (items && items.length) for (var i = 0; i < items.length; i++) {
item = items[i];
isBuiltInTool = $.isPlainObject(item) && Object.keys(item).length === 1 && item.name;
if (isBuiltInTool) item = item.name;
if ($.isPlainObject(item)) that._append(item);
else if (that.defaultItems[item]) {
item = that.defaultItems[item];
that._append(item);
} else if (typeof item === "string") {
item = {
name: item,
text: item,
spriteCssClass: item,
command: item + "Command"
};
that._append(item);
}
}
else for (var key in that.defaultItems) {
item = that.defaultItems[key];
that._append(item);
}
},
_extendItem: function(item) {
var that = this, messages = that.options.messages, attr = item.attr || {};
if (item.command) attr[kendo.attr("command")] = item.command;
if (item.options) attr[kendo.attr("options")] = item.options;
if (item.softRules) attr[kendo.attr("soft-rules")] = item.softRules;
if (item.items) for (var j = 0; j < item.items.length; j++) item.items.forEach((subItem) => {
that._extendItem(subItem);
});
extend(item, {
text: messages.commands[item.name],
icon: item.icon || "",
spriteCssClass: item.spriteCssClass || "",
attr,
uid: kendo.guid()
});
},
_validateSoftRules: function(rules, target) {
if (!rules || !(rules && rules.length)) return true;
for (var i = 0; i < rules.length; i++) if (!this._readState(rules[i], target)) return false;
return true;
},
_validateRules: function(tool) {
var rules = tool.rules ? tool.rules.split(";") : [];
if (!rules.length) return true;
for (var i = 0; i < rules.length; i++) if (!this._readState(rules[i])) return false;
return true;
},
_readState: function(state, target) {
var states = this.options.states;
if (kendo.isFunction(states[state])) return states[state](target);
else return states[state];
},
_append: function(item) {
var that = this;
that._extendItem(item);
if (that._validateRules(item)) that.append(item);
},
action: function(args) {
this.trigger(ACTION, args);
}
});
kendo.ui.grid = kendo.ui.grid || {};
extend(kendo.ui.grid, { ContextMenu: GridContextMenu });
})(window.kendo.jQuery);
//#endregion
//#region ../src/grid/commands.js
(function($, undefined) {
const kendo = window.kendo, extend = $.extend;
const Command = kendo.Class.extend({ init: function(options) {
this.options = options;
this.grid = options.grid;
} });
const MoveGroupCommand = Command.extend({ exec: function() {
const that = this, groupable = that.grid.groupable, options = that.options, target = options.target.closest(".k-chip"), method = options.dir === "next" ? "after" : "before";
(options.dir === "next" ? target.next() : target.prev())[method](target);
groupable._change();
} });
const SortCommand = Command.extend({ exec: function() {
const that = this, grid = that.grid, dataSource = grid.dataSource, options = that.options, dir = options.dir, field = grid._getCellField(options.target), multipleMode = grid.options.sortable.mode && grid.options.sortable.mode === "multiple", compare = grid.options.compare;
let length, idx, sort = dataSource.sort() || [];
if (multipleMode) {
for (idx = 0, length = sort.length; idx < length; idx++) if (sort[idx].field === field) {
sort.splice(idx, 1);
break;
}
sort.push({
field,
dir,
compare
});
} else sort = [{
field,
dir,
compare
}];
dataSource.sort(sort);
} });
const AddCommand = Command.extend({ exec: function() {
this.grid.addRow();
} });
const EditCommand = Command.extend({ exec: function() {
const that = this, grid = that.grid, inCellMode = grid._editMode() === "incell", target = inCellMode ? that.options.target : that.options.target.closest("tr");
if (inCellMode) grid.editCell(target);
else grid.editRow(target);
} });
const DeleteCommand = Command.extend({ exec: function() {
const that = this, grid = that.grid, target = that.options.target.closest("tr");
grid.removeRow(target);
} });
const CopySelectionCommand = Command.extend({ exec: function() {
const that = this, grid = that.grid, withHeaders = that.options.withHeaders;
grid.copySelectionToClipboard(withHeaders);
} });
const SelectRowCommand = Command.extend({ exec: function() {
const that = this, grid = that.grid, selectMode = kendo.ui.Selectable.parseOptions(grid.options.selectable), target = that.options.target.closest("tr");
grid.select(selectMode.cell ? target.find("td") : target);
} });
const SelectAllRowsCommand = Command.extend({ exec: function() {
const grid = this.grid, selectMode = kendo.ui.Selectable.parseOptions(grid.options.selectable), rows = grid.items();
grid.select(selectMode.cell ? rows.find("td") : rows);
} });
const ClearSelectionCommand = Command.extend({ exec: function() {
this.grid.clearSelection();
} });
const ReorderRowCommand = Command.extend({ exec: function() {
const that = this, grid = that.grid, dir = that.options.dir, target = that.options.target.closest("tr"), index = target.index();
let newIndex;
switch (dir) {
case "up":
newIndex = index - 1;
break;
case "down":
newIndex = index + 2;
break;
case "top":
newIndex = 0;
break;
case "bottom":
newIndex = grid.items().length;
break;
}
grid.reorderRowTo(target, newIndex);
} });
const ExportPDFCommand = Command.extend({ exec: function() {
this.grid.saveAsPDF();
} });
const ExportExcelCommand = Command.extend({ exec: function() {
const that = this, selection = that.options.selection, withHeaders = that.options.withHeaders, grid = that.grid;
if (selection) grid.exportSelectedToExcel(withHeaders);
else grid.saveAsExcel();
} });
const ExportCSVCommand = Command.extend({ exec: function() {
const selection = this.options.selection;
const withHeaders = this.options.withHeaders;
const grid = this.grid;
if (selection) grid.exportSelectedToCSV(withHeaders);
else grid.saveAsCSV();
} });
const PinTopCommand = Command.extend({ exec: function() {
const grid = this.grid;
const target = this.options.target.closest("tr");
grid.pinRows(target, "top");
} });
const PinBottomCommand = Command.extend({ exec: function() {
const grid = this.grid;
const target = this.options.target.closest("tr");
grid.pinRows(target, "bottom");
} });
const UnpinCommand = Command.extend({ exec: function() {
const grid = this.grid;
const target = this.options.target.closest("tr");
grid.unpinRows(target);
} });
kendo.ui.grid = kendo.ui.grid || {};
extend(kendo.ui.grid, {
GridCommand: Command,
commands: {
SortCommand,
AddCommand,
EditCommand,
DeleteCommand,
CopySelectionCommand,
SelectRowCommand,
SelectAllRowsCommand,
ClearSelectionCommand,
ReorderRowCommand,
ExportPDFCommand,
ExportExcelCommand,
ExportCSVCommand,
MoveGroupCommand,
PinTopCommand,
PinBottomCommand,
UnpinCommand
}
});
})(window.kendo.jQuery);
//#endregion
//#region ../src/grid/sticky-groups.js
const GROUPING_ROW = "k-grouping-row";
function closeRange(entry, footerIndex, lastChildIndex) {
return {
headerIndex: entry.headerIndex,
footerIndex,
firstChildIndex: entry.headerIndex + 1,
lastChildIndex,
level: entry.level,
collapsed: entry.collapsed
};
}
function buildGroupRangeMap(tbody, skipOffset, lockedTbody) {
skipOffset = skipOffset || 0;
const ranges = [];
const stack = [];
const rows = tbody.children;
const lockedRows = lockedTbody ? lockedTbody.children : null;
const rowCount = rows.length;
for (let i = 0; i < rowCount; i++) {
const row = rows[i];
const isGroupHeader = row.classList.contains(GROUPING_ROW);
const isGroupFooter = row.classList.contains("k-group-footer");
const globalIndex = skipOffset + i;
if (isGroupHeader) {
const levelRow = lockedRows ? lockedRows[i] : row;
const level = levelRow.querySelectorAll(".k-group-cell").length;
const collapsed = !!levelRow.querySelector("td[aria-expanded='false']");
for (let s = stack.length - 1; s >= 0; s--) if (stack[s].level >= level) {
ranges.push(closeRange(stack[s], null, globalIndex - 1));
stack.splice(s, 1);
}
stack.push({
headerIndex: globalIndex,
level,
collapsed
});
} else if (isGroupFooter) {
if (stack.length > 0) {
const closedHeader = stack.pop();
ranges.push(closeRange(closedHeader, globalIndex, globalIndex - 1));
}
}
}
for (let r = 0; r < stack.length; r++) ranges.push(closeRange(stack[r], null, skipOffset + rowCount - 1));
const map = {};
for (let m = 0; m < ranges.length; m++) map[ranges[m].headerIndex] = ranges[m];
return map;
}
function computeStickyHeaderItems(groupRanges, firstVisibleIndex, rawFirstVisibleIndex, allHeaderIndices) {
const stickyHeaders = [];
const footerThreshold = rawFirstVisibleIndex !== void 0 ? rawFirstVisibleIndex : firstVisibleIndex;
const bestHeaderPerLevel = /* @__PURE__ */ new Map();
for (const range of Object.values(groupRanges)) {
if (range.collapsed) continue;
if (range.headerIndex < firstVisibleIndex) {
let groupEnd;
if (range.footerIndex !== null && allHeaderIndices) {
groupEnd = range.footerIndex;
for (let h = 0; h < allHeaderIndices.length; h++) if (allHeaderIndices[h] > range.footerIndex) {
groupEnd = allHeaderIndices[h] - 1;
break;
}
} else groupEnd = range.footerIndex !== null ? range.footerIndex : range.lastChildIndex;
if (groupEnd > range.headerIndex && groupEnd >= footerThreshold) {
const existing = bestHeaderPerLevel.get(range.level);
if (!existing || range.headerIndex > existing.headerIndex) bestHeaderPerLevel.set(range.level, range);
}
}
}
const levels = Array.from(bestHeaderPerLevel.keys()).sort((a, b) => a - b);
for (const lvl of levels) stickyHeaders.push(bestHeaderPerLevel.get(lvl));
return stickyHeaders;
}
function computeStickyFooterItems(groupRanges, lastVisibleIndex) {
const stickyFooters = [];
const bestFooterPerLevel = /* @__PURE__ */ new Map();
for (const range of Object.values(groupRanges)) {
if (range.footerIndex === null || range.collapsed) continue;
if (range.footerIndex > lastVisibleIndex && range.headerIndex <= lastVisibleIndex) {
const existing = bestFooterPerLevel.get(range.level);
if (!existing || range.footerIndex < existing.footerIndex) bestFooterPerLevel.set(range.level, range);
}
}
const levels = Array.from(bestFooterPerLevel.keys()).sort((a, b) => b - a);
for (const lvl of levels) stickyFooters.push(bestFooterPerLevel.get(lvl));
return stickyFooters;
}
function getStickyRows(containerEl) {
const wrap = containerEl.querySelector(".k-grid-header-wrap, .k-grid-footer-wrap");
const tbody = wrap ? wrap.querySelector("table > tbody") : containerEl.querySelector(":scope > table > tbody");
return {
rows: tbody ? tbody.children : [],
heightTarget: containerEl
};
}
function clearRowTransforms(tr) {
tr.style.transform = "";
tr.style.clipPath = "";
tr.style.display = "";
}
function applyHeaderPushTransforms(containerEl, pushOffsets) {
const { rows: trs, heightTarget } = getStickyRows(containerEl);
let totalVisibleHeight = 0;
let hasPush = false;
for (let i = 0; i < trs.length && i < pushOffsets.length; i++) {
const tr = trs[i];
const rowH = tr.getBoundingClientRect().height || tr.offsetHeight;
const push = pushOffsets[i];
if (push < 0) {
hasPush = true;
const absPush = -push;
const visibleHeight = Math.max(rowH - absPush, 0);
totalVisibleHeight += visibleHeight;
if (visibleHeight <= 0) {
tr.style.display = "none";
tr.style.transform = "";
tr.style.clipPath = "";
} else {
tr.style.display = "";
tr.style.transform = `translateY(${push}px)`;
tr.style.clipPath = `inset(${absPush}px 0 0 0)`;
}
} else {
totalVisibleHeight += rowH;
clearRowTransforms(tr);
}
}
if (hasPush) {
const cs = getComputedStyle(heightTarget);
const border = (parseFloat(cs.borderTopWidth) || 0) + (parseFloat(cs.borderBottomWidth) || 0);
heightTarget.style.height = `${Math.max(totalVisibleHeight - border, 0)}px`;
} else heightTarget.style.height = "";
}
function applyFooterPushTransforms(containerEl, pushOffsets) {
const { rows: trs, heightTarget } = getStickyRows(containerEl);
let totalVisibleHeight = 0;
let hasPush = false;
let totalShrink = 0;
const rowHeights = [];
for (let i = 0; i < trs.length && i < pushOffsets.length; i++) {
const rowH = trs[i].getBoundingClientRect().height || trs[i].offsetHeight;
rowHeights.push(rowH);
const push = pushOffsets[i];
if (push > 0) {
hasPush = true;
const visibleH = Math.max(rowH - push, 0);
totalVisibleHeight += visibleH;
totalShrink += rowH - visibleH;
} else totalVisibleHeight += rowH;
}
for (let j = 0; j < trs.length && j < pushOffsets.length; j++) {
const tr = trs[j];
const pushVal = pushOffsets[j];
const rH = rowHeights[j];
if (pushVal > 0) {
if (Math.max(rH - pushVal, 0) <= 0) tr.style.clipPath = "inset(0 0 100% 0)";
else tr.style.clipPath = `inset(0 0 ${pushVal}px 0)`;
tr.style.transform = "";
} else if (hasPush) {
tr.style.transform = `translateY(${-totalShrink}px)`;
tr.style.clipPath = "";
} else clearRowTransforms(tr);
}
if (hasPush) {
const cs = getComputedStyle(heightTarget);
const border = (parseFloat(cs.borderTopWidth) || 0) + (parseFloat(cs.borderBottomWidth) || 0);
heightTarget.style.height = `${Math.max(totalVisibleHeight - border, 0)}px`;
} else heightTarget.style.height = "";
}
function resetStickyTransforms(containerEl) {
const { rows: trs, heightTarget } = getStickyRows(containerEl);
for (let i = 0; i < trs.length; i++) clearRowTransforms(trs[i]);
heightTarget.style.height = "";
}
function stickyItemsChanged(current, prev) {
if (current.length !== prev.length) return true;
for (let i = 0; i < current.length; i++) if (current[i].headerIndex !== prev[i].headerIndex) return true;
return false;
}
function findStickyChildRow(tbody, range, skipOffset, reverse) {
const start = reverse ? range.lastChildIndex : range.firstChildIndex;
const end = reverse ? range.firstChildIndex : range.lastChildIndex;
const step = reverse ? -1 : 1;
for (let i = start; reverse ? i >= end : i <= end; i += step) {
const row = tbody.children[i - skipOffset];
if (row) return row;
}
return null;
}
function stickyParentPadding(stickyRows, items, range) {
let padding = 0;
for (let i = 0; i < items.length; i++) if (items[i].level < range.level) padding += stickyRows[i] ? stickyRows[i].offsetHeight || 36 : 36;
return padding;
}
function buildStickyRowMetrics(tbody, skipOffset) {
const rows = tbody.children;
const rowCount = rows.length;
const rowTops = new Array(rowCount);
const rowHeightsArr = new Array(rowCount);
let lastVisibleBottom = 0;
for (let i = 0; i < rowCount; i++) {
const h = rows[i].offsetHeight;
if (h > 0) {
rowTops[i] = rows[i].offsetTop;
lastVisibleBottom = rowTops[i] + h;
} else rowTops[i] = lastVisibleBottom;
rowHeightsArr[i] = h;
}
const totalRowCount = skipOffset + rowCount;
const getRowHeight = (index) => {
const local = index - skipOffset;
return local >= 0 && local < rowCount ? rowHeightsArr[local] : 36;
};
const getRowOffset = (index) => {
const local = index - skipOffset;
if (local >= 0 && local < rowCount) return rowTops[local];
if (rowCount === 0) return;
if (local < 0) return rowTops[0] + local * 36;
return rowTops[rowCount - 1] + rowHeightsArr[rowCount - 1] + (local - rowCount) * 36;
};
const findFirstVisible = (effectiveTop) => {
let lo = 0, hi = rowCount;
while (lo < hi) {
const mid = lo + hi >> 1;
if (rowTops[mid] + rowHeightsArr[mid] <= effectiveTop) lo = mid + 1;
else hi = mid;
}
return lo < rowCount ? skipOffset + lo : skipOffset;
};
const findFirstAtTop = (effectiveTop) => {
let lo = 0, hi = rowCount;
while (lo < hi) {
const mid = lo + hi >> 1;
if (rowTops[mid] < effectiveTop) lo = mid + 1;
else hi = mid;
}
return lo < rowCount ? skipOffset + lo : skipOffset;
};
const findLastVisible = (effectiveBottom) => {
let lo = 0, hi = rowCount - 1;
while (lo <= hi) {
const mid = lo + hi >> 1;
if (rowTops[mid] + rowHeightsArr[mid] <= effectiveBottom) lo = mid + 1;
else hi = mid - 1;
}
return hi >= 0 ? skipOffset + hi : skipOffset + rowCount - 1;
};
return {
getRowHeight,
getRowOffset,
findFirstVisible,
findFirstAtTop,
findLastVisible,
totalRowCount
};
}
function convergeStickyHeaders(metrics, groupRanges, scrollTop) {
const { getRowHeight, getRowOffset, findFirstVisible, findFirstAtTop, totalRowCount } = metrics;
const rawFirstVisibleIndex = Math.min(findFirstVisible(scrollTop), totalRowCount - 1);
let stickyHeaderHeight = 0;
let headerPushOffsets = [];
let stickyHeaders = [];
const allHeaderIndices = Object.keys(groupRanges).map(Number).sort((a, b) => a - b);
const computeHeaderPush = (ranges) => {
const offsets = [];
let cumHeight = 0;
for (let ci = 0; ci < ranges.length; ci++) {
const range = ranges[ci];
const rowH = getRowHeight(range.headerIndex);
let push = 0;
let boundaryIndex;
if (range.footerIndex !== null) {
boundaryIndex = range.footerIndex + 1;
for (let h = 0; h < allHeaderIndices.length; h++) if (allHeaderIndices[h] > range.footerIndex) {
boundaryIndex = allHeaderIndices[h];
break;
}
} else boundaryIndex = range.lastChildIndex + 1;
const boundaryOffset = getRowOffset(boundaryIndex);
if (boundaryOffset !== void 0) {
const slotBottom = cumHeight + rowH;
const boundaryRelative = boundaryOffset - scrollTop;
if (boundaryRelative < slotBottom) push = boundaryRelative - slotBottom;
}
offsets.push(push);
cumHeight += Math.max(rowH + push, 0);
}
return {
totalHeight: cumHeight,
offsets
};
};
const seenFirstVisible = /* @__PURE__ */ new Set();
while (true) {
const firstVisibleIndex = Math.min(findFirstAtTop(scrollTop + Math.max(stickyHeaderHeight, 0)), totalRowCount - 1);
const isHeaderCycle = seenFirstVisible.has(firstVisibleIndex);
seenFirstVisible.add(firstVisibleIndex);
const result = computeStickyHeaderItems(groupRanges, firstVisibleIndex, rawFirstVisibleIndex, allHeaderIndices);
const headerPush = computeHeaderPush(result);
const headerConverged = !stickyItemsChanged(result, stickyHeaders) && Math.abs(headerPush.totalHeight - stickyHeaderHeight) < 1;
stickyHeaders = result;
stickyHeaderHeight = headerPush.totalHeight;
headerPushOffsets = headerPush.offsets;
if (headerConverged || isHeaderCycle) break;
}
return {
items: stickyHeaders,
pushOffsets: headerPushOffsets
};
}
function convergeStickyFooters(metrics, groupRanges, scrollTop, viewportHeight) {
const { getRowHeight, getRowOffset, findLastVisible, totalRowCount } = metrics;
let stickyFooterHeight = 0;
let footerPushOffsets = [];
let stickyFooters = [];
const computeFooterPush = (ranges) => {
const offsets = [];
let cumHeight = 0;
for (let ci = ranges.length - 1; ci >= 0; ci--) {
const range = ranges[ci];
const rowH = getRowHeight(range.footerIndex);
let push = 0;
const boundaryOffset = getRowOffset(range.headerIndex);
if (boundaryOffset !== void 0) {
const boundaryBottom = boundaryOffset + getRowHeight(range.headerIndex);
const slotTop = scrollTop + viewportHeight - cumHeight - rowH;
if (boundaryBottom > slotTop) push = boundaryBottom - slotTop;
}
offsets[ci] = push;
cumHeight += Math.max(rowH - push, 0);
}
return {
totalHeight: cumHeight,
offsets
};
};
const seenLastVisible = /* @__PURE__ */ new Set();
while (true) {
const effectiveLastVisible = Math.min(findLastVisible(scrollTop + viewportHeight - stickyFooterHeight), totalRowCount - 1);
const isFooterCycle = seenLastVisible.has(effectiveLastVisible);
seenLastVisible.add(effectiveLastVisible);
const footerResult = computeStickyFooterItems(groupRanges, effectiveLastVisible);
const footerPush = computeFooterPush(footerResult);
const footerConverged = !stickyItemsChanged(footerResult, stickyFooters) && Math.abs(footerPush.totalHeight - stickyFooterHeight) < 1;
stickyFooters = footerResult;
stickyFooterHeight = footerPush.totalHeight;
footerPushOffsets = footerPush.offsets;
if (footerConverged || isFooterCycle) break;
}
return {
items: stickyFooters,
pushOffsets: footerPushOffsets
};
}
function syncColgroup(targetTable, sourceTable) {
if (!targetTable) return;
const existing = targetTable.querySelector(":scope > colgroup");
const source = sourceTable.querySelector(":scope > colgroup");
if (source) {
const sourceCols = source.children;
if (existing && existing.children.length === sourceCols.length) {
const targetCols = existing.children;
for (let i = 0; i < sourceCols.length; i++) {
const w = sourceCols[i].style.width;
if (w) {
if (targetCols[i].style.width !== w) targetCols[i].style.width = w;
} else if (targetCols[i].style.width) targetCols[i].style.width = "";
}
} else {
if (existing) existing.remove();
targetTable.prepend(source.cloneNode(true));
}
} else if (existing) existing.remove();
targetTable.style.width = sourceTable.style.width || sourceTable.getBoundingClientRect().width + "px";
}
function renderStickyRowsHtml(sourceRows, items, indexProp, skipOffset) {
let html = "";
for (let i = 0; i < items.length; i++) {
const row = sourceRows[items[i][indexProp] - skipOffset];
if (row) html += `<tr class='${row.className}'>${row.innerHTML}</tr>`;
}
return html;
}
const STICKY_CONTAINER_CLASS = "k-grid-sticky-container";
function createStickyTable(tableClass, sizeClass) {
const table = document.createElement("table");
table.className = tableClass + " k-grid-table k-table" + (sizeClass ? " " + sizeClass : "");
const tbody = document.createElement("tbody");
tbody.className = "k-table-tbody";
table.appendChild(tbody);
return table;
}
function createStickyGroupContainer(tableClass, sizeClass, extraClasses) {
const div = document.createElement("div");
div.className = STICKY_CONTAINER_CLASS + (extraClasses ? " " + extraClasses : "");
div.setAttribute("aria-hidden", "true");
const table = createStickyTable(tableClass, sizeClass);
div.appendChild(table);
return {
container: div,
table
};
}
function createStickyGroupLockedContainer(tableClass, sizeClass) {
const div = document.createElement("div");
div.className = "k-grid-content-locked";
const table = createStickyTable(tableClass, sizeClass);
div.appendChild(table);
return {
container: div,
table
};
}
//#endregion
//#region ../src/grid/pinned-rows.js
const PINNED_CONTAINER_CLASS = "k-grid-pinned-container";
const PINNED_WRAP_CLASS = "k-grid-pinned-wrap";
const PINNED_SOURCE_CLASS = "k-pinned-source";
const kendo$1 = window.kendo;
const $ = kendo$1.jQuery;
function createPinnedContainer(position, sizeClass) {
const isBottom = position === "bottom";
const container = document.createElement("div");
container.className = PINNED_CONTAINER_CLASS + (isBottom ? " k-pos-bottom" : "");
const wrap = document.createElement("div");
wrap.className = PINNED_WRAP_CLASS;
const table = document.createElement("table");
table.className = "k-grid-table k-table" + (sizeClass ? " " + sizeClass : "");
table.setAttribute("aria-label", isBottom ? "Pinned bottom rows" : "Pinned top rows");
const tbody = document.createElement("tbody");
tbody.className = "k-table-tbody";
table.appendChild(tbody);
wrap.appendChild(table);
container.appendChild(wrap);
return {
container,
wrap,
table,
tbody
};
}
function syncPinnedColgroups(sourceTable, topTable, bottomTable) {
if (!sourceTable) return;
const syncColgroupOnly = (target, src) => {
const existing = target.querySelector(":scope > colgroup");
if (existing) existing.remove();
const srcColgroup = src.querySelector(":scope > colgroup");
if (srcColgroup) target.prepend(srcColgroup.cloneNode(true));
};
if (topTable) syncColgroupOnly(topTable, sourceTable);
if (bottomTable) syncColgroupOnly(bottomTable, sourceTable);
}
function syncPinnedScroll(source, content, topWrap, bottomWrap) {
const scrollLeft = source.scrollLeft;
if (content && content !== source && content.scrollLeft !== scrollLeft) content.scrollLeft = scrollLeft;
if (topWrap && topWrap !== source && topWrap.scrollLeft !== scrollLeft) topWrap.scrollLeft = scrollLeft;
if (bottomWrap && bottomWrap !== source && bottomWrap.scrollLeft !== scrollLeft) bottomWrap.scrollLeft = scrollLeft;
}
function getRowPinPosition(dataItem, topRows, bottomRows, idField) {
if (!idField || !dataItem) return "none";
const key = dataItem[idField];
if (topRows.some((r) => r[idField] === key)) return "top";
if (bottomRows.some((r) => r[idField] === key)) return "bottom";
return "none";
}
function resolveInitialPinnedRows(pinnable, idField, dataSourceGet) {
if (!pinnable || typeof pinnable !== "object" || !pinnable.top && !pinnable.bottom) return null;
if (!idField) return null;
const resolve = (ids) => {
if (!Array.isArray(ids)) return [];
return ids.map((id) => dataSourceGet(id)).filter((item) => !!item);
};
return {
top: resolve(pinnable.top),
bottom: resolve(pinnable.bottom)
};
}
function markPinnedSourceRows(tbody, topRows, bottomRows, idField) {
if (!tbody) return;
const $tbody = $(tbody);
$tbody.find("tr.k-pinned-source").removeClass(PINNED_SOURCE_CLASS);
if (!idField) return;
[...topRows, ...bottomRows].forEach((pinnedItem) => {
const uid = pinnedItem.uid;
if (uid) $tbody.find(`tr[data-uid="${uid}"]`).addClass(PINNED_SOURCE_CLASS);
});
}
function togglePinMenuItems(menuElement, position, pinRowLocation, messages) {
const $menu = $(menuElement);
const pinTop = $menu.find("[data-command=PinTopCommand]").closest(".k-menu-item");
const pinBottom = $menu.find("[data-command=PinBottomCommand]").closest(".k-menu-item");
const unpin = $menu.find("[data-command=UnpinCommand]").closest(".k-menu-item");
if (pinRowLocation && pinRowLocation !== "both") {
const parentItem = pinTop.closest(".k-menu-group").closest(".k-menu-item");
pinTop.hide();
pinBottom.hide();
unpin.hide();
if (parentItem.length) {
parentItem.children(".k-menu-group, .k-animation-container").hide();
parentItem.find("> .k-link .k-menu-expand-arrow, > .k-link > .k-menu-expand-arrow-icon").hide();
const linkText = parentItem.find("> .k-link .k-menu-link-text");
if (position !== "none") {
parentItem.show();
parentItem.attr(kendo$1.attr("command"), "UnpinCommand");
parentItem.data("command", "UnpinCommand");
if (linkText.length && messages) linkText.text(messages.unpin);
} else {
parentItem.show();
const cmd = pinRowLocation === "top" ? "PinTopCommand" : "PinBottomCommand";
parentItem.attr(kendo$1.attr("command"), cmd);
parentItem.data("command", cmd);
if (linkText.length && messages) linkText.text(messages.pinRow);
}
}
} else {
pinTop.toggle(position !== "top");
pinBottom.toggle(position !== "bottom");
unpin.toggle(position !== "none");
}
}
function destroyPinnedContainer(wrapEl, containerEl) {
if (wrapEl) $(wrapEl).off("scroll");
if (containerEl) $(containerEl).remove();
}
function refreshPinnedReferences(topRows, bottomRows, dataSourceData, idField) {
if (!idField) return {
top: topRows,
bottom: bottomRows
};
const findById = (id) => {
for (let i = 0; i < dataSourceData.length; i++) if (dataSourceData[i][idField] == id) return dataSourceData[i];
return null;
};
const refresh = (items) => items.map((item) => {
return findById(item[idField]) || null;
}).filter((item) => item !== null);
return {
top: refresh(topRows),
bottom: refresh(bottomRows)
};
}
function syncPinnedTableWidths(sourceTable, topTable, bottomTable) {
if (!sourceTable) return;
const width = sourceTable.style.width;
if (width) {
if (topTable) topTable.style.width = width;
if (bottomTable) bottomTable.style.width = width;
}
}
function syncPinnedLockedWidths(lockedWidth, contentWidth, topLocked, bottomLocked, topContent, bottomContent) {
if (topLocked) topLocked.style.width = lockedWidth;
if (bottomLocked) bottomLocked.style.width = lockedWidth;
if (topContent) topContent.style.width = contentWidth;
if (bottomContent) bottomContent.style.width = contentWidth;
}
function createPinnedLockedContent(sizeClass) {
const container = document.createElement("div");
container.className = "k-grid-content-locked";
const table = document.createElement("table");
table.className = "k-grid-table k-table" + (sizeClass ? " " + sizeClass : "");
const colgroup = document.createElement("colgroup");
const tbody = document.createElement("tbody");
tbody.className = "k-table-tbody";
table.appendChild(colgroup);
table.appendChild(tbody);
container.appendChild(table);
return {
container,
table,
tbody
};
}
function flattenRowSpans(html) {
if (html.indexOf("rowspan") === -1 && html.indexOf("rowSpan") === -1 && html.indexOf("hidden") === -1) return html;
const temp = document.createElement("table");
const tempBody = document.createElement("tbody");
temp.appendChild(tempBody);
tempBody.innerHTML = html;
const rows = tempBody.querySelectorAll("tr");
const rowCount = rows.length;
for (let r = 0; r < rowCount; r++) {
const cells = rows[r].querySelectorAll("td");
for (let c = 0; c < cells.length; c++) {
const cell = cells[c];
if (cell.hasAttribute("rowspan")) cell.removeAttribute("rowspan");
if (cell.hasAttribute("hidden")) {
cell.removeAttribute("hidden");
cell.style.display = "";
}
}
}
return tempBody.innerHTML;
}
function applyPinnedAria(containers, getByUid, idField) {
containers.forEach((p) => {
if (!p || !p.tbody) return;
p.tbody.attr("role", "rowgroup");
p.tbody.children("tr").each((_, el) => {
const row = $(el);
row.attr("role", "row");
const uid = row.data("uid");
if (uid) {
if (getByUid(uid) && idField) row.attr("aria-label", "Pinned row");
}
row.children("td").attr("role", "gridcell");
});
if (p.lockedTbody) {
p.lockedTbody.attr("role", "rowgroup");
p.lockedTbody.children("tr").each((_, el) => {
const row = $(el);
row.attr("role", "row");
row.children("td").attr("role", "gridcell");
});
}
});
}
//#endregion
//#region ../src/kendo.grid.js
const __meta__ = {
id: "grid",
name: "Grid",
category: "web",
description: "The Grid widget displays tabular data and offers rich support for interacting with data,including paging, sorting, grouping, and selection.",
depends: [
"data",
"columnsorter",
"sortable",
"toolbar",
"html.button",
"icons",
"menu",
"loader",
"html.loadercontainer",
"badge",
"aiprompt",
"smartbox"
],
features: [
{
id: "grid-editing",
name: "Editing",
description: "Support for record editing",
depends: [
"editable",
"window",
"textbox",
"form"
]
},
{
id: "grid-filtering",
name: "Filtering",
description: "Support for record filtering",
depends: ["filtermenu"]
},
{
id: "grid-columnmenu",
name: "Column menu",
description: "Support for header column menu",
depends: ["columnmenu"]
},
{
id: "grid-grouping",
name: "Grouping",
description: "Support for grid grouping",
depends: ["groupable"]
},
{
id: "grid-filtercell",
name: "Row filter",
description: "Support for grid header filtering",
depends: ["filtercell"]
},
{
id: "grid-paging",
name: "Paging",
description: "Support for grid paging",
depends: ["pager"]
},
{
id: "grid-selection",
name: "Selection",
description: "Support for row selection",
depends: ["selectable"]
},
{
id: "grid-column-reorder",
name: "Column reordering",
description: "Support for column reordering",
depends: ["reorderable"]
},
{
id: "grid-column-resize",
name: "Column resizing",
description: "Support for column resizing",
depends: ["resizable"]
},
{
id: "grid-mobile",
name: "Grid adaptive rendering",
description: "Support for adaptive rendering",
depends: [
"dialog",
"pane",
"switch"
]
},
{
id: "grid-excel-export",
name: "Excel export",
description: "Export grid data as Excel spreadsheet",
depends: ["excel"]
},
{
id: "grid-pdf-export",
name: "PDF export",
description: "Export grid data as PDF",
depends: ["pdf", "drawing"]
},
{
id: "grid-csv-export",
name: "CSV export",
description: "Export grid data as CSV",
depends: ["csv"]
}
]
};
(function($, undefined) {
let kendo = window.kendo, ui = kendo.ui, DataSource = kendo.data.DataSource, ObservableObject = kendo.data.ObservableObject, tbodySupportsInnerHtml = kendo.support.tbodyInnerHtml, activeElement = kendo._activeElement, Widget = ui.Widget, outerWidth = kendo._outerWidth, outerHeight = kendo._outerHeight, keys = kendo.keys, getType = kendo.type, isPlainObject = $.isPlainObject, extend = $.extend, map = $.map, grep = $.grep, isArray = Array.isArray, inArray = $.inArray, push = Array.prototype.push, isFunction = kendo.isFunction, encode = kendo.htmlEncode, isEmptyObject = $.isEmptyObject, contains = $.contains, math = Math, DOT = ".", PROGRESS = "progress", ERROR = "error", HIERARCHY_CELL_CLASS = "k-hierarchy-cell", DATA_CELL = ":not(.k-group-cell):not([" + kendo.attr("virtual") + "]):not(.k-hierarchy-cell:not(:has([ref-grid-expand-detail],[ref-grid-collapse-detail]))):visible", DATA_CELL_HIDDENINCLUDED = ":not([" + kendo.attr("virtual") + "]):not(.k-hierarchy-cell:not(:has([ref-grid-expand-detail],[ref-grid-collapse-detail])))", SELECTION_CELL_SELECTOR = "tbody>tr:not(.k-grouping-row):not(.k-detail-row):not(.k-group-footer):not([data-skeleton-row]) > td:not(.k-group-cell):not(.k-hierarchy-cell)", STACKED_CELL_SELECTOR = "tbody>tr:not(.k-grouping-row):not(.k-detail-row):not(.k-group-footer):not([data-skeleton-row]) > td:not(.k-group-cell):not(.k-hierarchy-cell) div.k-grid-stack-cell", NAVROW = "tr:not(.k-footer-template):visible", NAVCELL = ":not(.k-group-cell):not(.k-detail-cell):not(.k-hierarchy-cell):visible", ITEMROW = "tr:not(.k-grouping-row):not(.k-detail-row):not(.k-footer-template):not(.k-group-footer):visible", COLGROUP = "col:not(.k-group-col, .k-hierarchy-col)", HEADERCELLS = "th.k-header:not(.k-group-cell):not(.k-hierarchy-cell)", CARET_ALT_DOWN = "a[class*='-i-chevron-down']", CARET_ALT_RIGHT = "a[class*='-i-chevron-right']", CARET_ALT_RIGHT_CACHE = CARET_ALT_RIGHT, CARET_ALT_LEFT = "a[class*='-i-chevron-left']", WRAPPER = ".k-grid", STACKED = "k-grid-stack", NS = ".kendoGrid", INPUT_SELECTORS = ":button,a,:input,a>.k-icon,a>.k-svg-icon,textarea,span.k-select,span.k-icon,span.k-svg-icon,span.k-svg-icon>svg,span.k-svg-icon>svg>path,span.k-link,label.k-checkbox-label,.k-input,.k-multiselect-wrap,.k-picker-wrap,.k-picker-wrap>.k-selected-color,.k-tool-icon,.k-dropdownlist,.k-switch-thumb,.k-switch-track,.k-switch-label-off,.k-switch-label-on", EDIT = "edit", BEFOREEDIT = "beforeEdit", SAVE = "save", REMOVE = "remove", DETAILINIT = "detailInit", FILTERMENUINIT = "filterMenuInit", COLUMNMENUINIT = "columnMenuInit", FILTERMENUOPEN = "filterMenuOpen", COLUMNMENUOPEN = "columnMenuOpen", CELLCLOSE = "cellClose", CHANGING = "changing", CHANGE = "change", COLUMNHIDE = "columnHide", COLUMNSHOW = "columnShow", SAVECHANGES = "saveChanges", DATABOUND = "dataBound", DETAILEXPAND = "detailExpand", DETAILCOLLAPSE = "detailCollapse", ITEM_CHANGE = "itemchange", PAGE = "page", PAGING = "paging", PASTE = "paste", SCROLL = "scroll", SYNC = "sync", LOAD_START = "loadStart", LOAD_END = "loadEnd", REQUESTEND = "requestEnd", FOCUSED = "k-focus", HIGHLIGHTED = "k-highlighted", HOVER = "k-hover", ACTIVE = "k-active", FOCUSABLE = ":kendoFocusable", FOCUSABLE_GRID_ELEMENT_SELECTORS = ".k-command-cell,.k-select-checkbox,.k-grid-stack-cell[tabindex]", SELECTED = "k-selected", CHECKBOX = "k-checkbox", CHECKBOXINPUT = "input[data-role='checkbox'].k-select-checkbox.k-checkbox", NORECORDSCLASS = "k-grid-norecords", SORTED_CLASS = "k-sorted", HEADER_CLASS = "k-header", STICKY_CELL_CLASS = "k-grid-content-sticky", STICKY_HEADER_CLASS = "k-grid-header-sticky", STICKY_FOOTER_CLASS = "k-grid-footer-sticky", STICKY_HEADER_NO_BORDER_CLASS = "k-grid-no-left-border", STICKY_GROUP_HEADER_TABLE_CLASS = "k-grid-group-sticky-header-table", STICKY_GROUP_FOOTER_TABLE_CLASS = "k-grid-group-sticky-footer-table", STACKED_TEMPLATE_WRAPPER_CLASS = "k-grid-column-template", PINCELLCLASS = "k-pin-cell", GROUPING_ROW = "k-grouping-row", ROWRESIZE = "rowResize", COLUMNRESIZE = "columnResize", COLUMNREORDER = "columnReorder", COLUMNLOCK = "columnLock", COLUMNUNLOCK = "columnUnlock", COLUMNSTICK = "columnStick", COLUMNUNSTICK = "columnUnstick", ROWREORDER = "rowReorder", ROWPIN = "rowPin", ROWUNPIN = "rowUnpin", NAVIGATE = "navigate", HEIGHT = "height", WIDTH = "width", AUTO = "auto", TABINDEX = "tabIndex", FUNCTION = "function", STRING = "string", BOTTOM = "bottom", CONTAINER_FOR = "container-for", FIELD = "field", INPUT = "input", INCELL = "incell", INLINE = "inline", UNIQUE_ID = "uid", MINCOLSPANVALUE = 1, COLSPAN = "colSpan", OVERFLOW = "overflow", HIDDEN = "hidden", SORT = "sort", GROUP_SORT = "group-sort", DELETECONFIRM = "Are you sure you want to delete this record?", NORECORDS = "No records available.", CONFIRMDELETE = "Delete", CANCELDELETE = "Cancel", COLLAPSE = "Collapse", EXPAND = "Expand", ID = "id", PX = "px", TR = "tr", TH = "th", TD = "td", DIV = "div", ARIA_LABEL = "aria-label", ARIA_OWNS = "aria-owns", ARIA_ROWCOUNT = "aria-rowcount", ARIA_COLCOUNT = "aria-colcount", ARIA_CONTROLS = "aria-controls", ARIA_COLINDEX = "aria-colindex", ARIA_ROWINDEX = "aria-rowindex", ARIA_EXPANDED = "aria-expanded", ARIA_CHECKED = "aria-checked", ARIA_ACTIVEDESCENDANT = "aria-activedescendant", ROLE = "role", NONE = "none", ROW = "row", ROWGROUP = "rowgroup", COLUMNHEADER = "columnheader", GRIDCELL = "gridcell", formatRegExp = /(\}|\#)/gi, nonDataCellsRegExp = /* @__PURE__ */ new RegExp("(^|[\\x20\\t\\r\\n\\f])(k-group-cell|k-hierarchy-cell)([\\x20\\t\\r\\n\\f]|$)"), filterRowRegExp = /* @__PURE__ */ new RegExp("(^|[\\x20\\t\\r\\n\\f])(k-filter-row)([\\x20\\t\\r\\n\\f]|$)"), COMMANDBUTTONTMPL = ({ className, attr, text }) => `<button type="button" class="${className}" ${attr}>${kendo.htmlEncode(text)}</button>`, DEFAULTSELECTCOLUMNTMPL = (size, ariaLabel, label) => `<span class="k-checkbox-wrap"><input tabindex="-1" class="k-select-checkbox ${CHECKBOX} ${size}" data-role="checkbox" aria-label="${ariaLabel}" aria-checked="false" type="checkbox"></span>${label ? `<label class="k-checkbox-label">${label}</label>` : ""}`, SELECTCOLUMNTMPL = ({ size }) => DEFAULTSELECTCOLUMNTMPL(size, "Select row"), SELECTCOLUMNHEADERTMPL = ({ size, label }) => DEFAULTSELECTCOLUMNTMPL(size, "Select all rows", label), DRAGHANDLECOLUMNTMPL = () => kendo.ui.icon("reorder"), PINNABLECOLUMNTMPL = () => `<span class="${PINCELLCLASS}">${kendo.ui.icon("pin")}</span>`, DEFAULTHEADERTEMPLATE = ({ text }) => `<span class="k-cell-inner"><span class="k-link"><span class="k-column-title">${text}</span></span></span>`, isRtl = false, browser = kendo.support.browser;
var isIE11 = browser.msie && browser.version === 11;
var isMac = /Mac OS/.test(navigator.userAgent);
var classNames = {
content: "k-content",
scrollContainer: "k-scroll-container",
headerCellInner: "k-cell-inner"
};
var GroupsPager;
const defaultBodyContextMenu = [
"copySelection",
"copySelectionNoHeaders",
"paste",
"separator",
"create",
"edit",
"destroy",
"select",
"separator",
"reorderRow",
"pinRow",
"exportPDF",
"exportExcel",
"exportCSV",
"separator"
];
const defaultHeadContextMenu = [
"sortAsc",
"sortDesc",
"separator"
];
const defaultGroupsContextMenu = [
"moveGroupPrevious",
"moveGroupNext",
"separator"
];
const editableToolbarItemsSelector = [
".k-grid-edit-command",
".k-grid-remove-command",
".k-grid-save-changes",
".k-grid-cancel-changes",
".k-grid-cancel-command",
".k-grid-save-command"
].join(", ");
const defaultActionSheetFooterButtons = function(messages) {
return {
sort: [{
command: "clear-sort",
text: messages.clearButtons ? messages.clearButtons.clearSorting : "Clear Sorting",
size: "large",
icon: "x"
}, {
command: "done",
text: messages.applyButtons ? messages.applyButtons.applySorting : "Done",
size: "large",
themeColor: "primary",
icon: "check"
}],
group: [{
command: "clear-group",
text: messages.clearButtons ? messages.clearButtons.clearGrouping : "Clear Grouping",
size: "large",
icon: "x"
}, {
command: "done",
text: messages.applyButtons ? messages.applyButtons.applyGrouping : "Done",
size: "large",
themeColor: "primary",
icon: "check"
}],
filter: [{
command: "clear-filter",
text: messages.clearButtons ? messages.clearButtons.clearFiltering : "Clear All Filters",
size: "large",
icon: "filter-clear"
}],
"column-chooser": [{
text: messages.clearButtons ? messages.clearButtons.columnChooserReset : "Reset",
icon: "arrow-rotate-ccw"
}, {
text: messages.applyButtons ? messages.applyButtons.columnChooserApply : "Apply",
themeColor: "primary",
icon: "check"
}]
};
};
if (ui.Pager) GroupsPager = ui.Pager.extend({
init: function(element, options) {
ui.Pager.fn.init.call(this, element, extend(true, {}, { messages: ui.Pager.prototype.options.messages }, options));
this.dataSource.options.useRanges = true;
this.dataSource._omitPrefetch = true;
ui.Pager.fn.endInit.call(this);
},
options: { name: "GroupsPager" },
totalPages: function() {
var that = this;
return Math.ceil((that._collapsedTotal() || 0) / (that.pageSize() || 1));
},
_collapsedTotal: function() {
var dataSource = this.dataSource;
return dataSource ? dataSource.groupsTotal(true) || 0 : 0;
}
});
var VirtualScrollable = Widget.extend({
init: function(element, options) {
var that = this;
Widget.fn.init.call(that, element, options);
that._refreshHandler = that.refresh.bind(that);
that.setDataSource(options.dataSource);
that.wrap();
Widget.fn.endInit.call(that);
},
setDataSource: function(dataSource) {
var that = this;
if (that.dataSource) that.dataSource.unbind(CHANGE, that._refreshHandler);
that.dataSource = dataSource;
that.dataSource.bind(CHANGE, that._refreshHandler);
that.dataSource.options.useRanges = true;
that.dataSource.options.virtual = true;
},
options: {
name: "VirtualScrollable",
itemHeight: $.noop,
prefetch: true,
maxScrollHeight: 25e4
},
events: [
PAGING,
PAGE,
SCROLL,
LOAD_START,
LOAD_END
],
destroy: function() {
var that = this;
Widget.fn.destroy.call(that);
that.dataSource.unbind(CHANGE, that._refreshHandler);
that.wrapper.add(that.verticalScrollbar).off(NS);
clearTimeout(that._timeout);
if (that._scrollingTimeout) clearTimeout(that._scrollingTimeout);
if (that.drag) {
that.drag.destroy();
that.drag = null;
}
that.wrapper = that.element = that.verticalScrollbar = null;
that._refreshHandler = null;
},
wrap: function() {
var that = this, scrollbar = kendo.support.scrollbar() + 1, element = that.element, wrapper;
element.css({
width: AUTO,
overflow: "hidden"
}).css(isRtl ? "padding-left" : "padding-right", scrollbar);
that.content = element.children().first();
wrapper = that.wrapper = that.content.wrap("<div class=\"k-virtual-scrollable-wrap\"/>").parent().on("DOMMouseScroll.kendoGrid mousewheel.kendoGrid", that._wheelScroll.bind(that));
that._wrapper();
if (kendo.support.kineticScrollNeeded || kendo.support.touch) {
that.wrapper.css("touch-action", NONE);
that.drag = new kendo.UserEvents(that.wrapper, {
global: true,
allowSelection: true,
start: function(e) {
e.sender.capture();
},
move: function(e) {
that.verticalScrollbar.scrollTop(that.verticalScrollbar.scrollTop() - e.y.delta);
kendo.scrollLeft(wrapper, kendo.scrollLeft(wrapper) - e.x.delta);
e.preventDefault();
}
});
}
that.verticalScrollbar = $("<div class=\"k-scrollbar k-scrollbar-vertical\" tabindex=\"-1\"/>").css({ width: scrollbar }).appendTo(element).on("scroll.kendoGrid", that._scroll.bind(that));
},
_wrapper: function() {
var that = this;
if (isIE11) {
that.wrapper.css({ "overflow-y": SCROLL });
that.element.css(isRtl ? "padding-left" : "padding-right", 0);
}
},
_wheelScroll: function(e) {
if (e.ctrlKey) return;
var scrollbar = this.verticalScrollbar, scrollTop = scrollbar.scrollTop(), delta = kendo.wheelDeltaY(e);
if (delta && !(delta > 0 && scrollTop === 0) && !(delta < 0 && scrollTop + scrollbar[0].clientHeight == scrollbar[0].scrollHeight)) {
e.preventDefault();
this.verticalScrollbar.scrollTop(scrollTop + -delta);
}
},
_scroll: function(e) {
var that = this, delayLoading = !that.options.prefetch, scrollTop = e.currentTarget.scrollTop, dataSource = that.dataSource, rowHeight = that.itemHeight, skip = dataSource.skip() || 0, start = that._rangeStart || skip, height = that.element.innerHeight(), isScrollingUp = !!(that._scrollbarTop && that._scrollbarTop > scrollTop), firstItemIndex = math.max(math.floor(scrollTop / rowHeight), 0), lastItemOffset = isScrollingUp ? math.ceil(height / rowHeight) : math.floor(height / rowHeight), lastItemIndex = math.max(firstItemIndex + lastItemOffset, 0);
if (that._preventScroll) {
that._preventScroll = false;
return;
}
that._prevScrollTop = that._scrollTop;
that._scrollTop = scrollTop - start * rowHeight;
that._scrollbarTop = scrollTop;
that._scrolling = delayLoading;
if (!that._fetch(firstItemIndex, lastItemIndex, isScrollingUp)) that.wrapper[0].scrollTop = that._scrollTop;
that.trigger(SCROLL);
if (delayLoading) {
if (that._scrollingTimeout) clearTimeout(that._scrollingTimeout);
that._scrollingTimeout = setTimeout(function() {
that._scrolling = false;
that._page(that._rangeStart, that.dataSource.take());
}, 100);
}
},
scrollToTop: function() {
this._scrollTo(0);
},
scrollToBottom: function() {
var scrollbar = this.verticalScrollbar;
this._scrollTo(scrollbar[0].scrollHeight - scrollbar.height());
},
_scrollWrapperToTop: function() {
this.wrapper.scrollTop(0);
},
_scrollWrapperToBottom: function() {
this.wrapper.scrollTop(this.wrapper[0].scrollHeight);
},
_scrollWrapperOnColumnResize: function() {
var that = this;
var wrapper = this.wrapper;
var initialScrollTop = wrapper.scrollTop();
if (wrapper[0].scrollWidth > wrapper[0].clientWidth) {
if (!that._wrapperScrolled && initialScrollTop || that._isScrolledToBottom()) {
wrapper.scrollTop(initialScrollTop + kendo.support.scrollbar());
that._scrollTop = wrapper.scrollTop();
that._wrapperScrolled = true;
}
} else if (that._wrapperScrolled) {
if (!that._isWrapperScrolledToBottom()) {
wrapper.scrollTop(initialScrollTop - kendo.support.scrollbar());
that._scrollTop = wrapper.scrollTop();
}
that._wrapperScrolled = false;
}
},
_scrollTo: function(scrollTop, programmaticScrollPosition) {
var that = this;
var scrollbar = that.verticalScrollbar;
if (scrollbar.scrollTop() !== scrollTop) that._preventScroll = true;
that.wrapper.scrollTop(scrollTop);
that._scrollTop = that.wrapper.scrollTop();
scrollbar.scrollTop(programmaticScrollPosition ?? scrollTop);
that._scrollbarTop = scrollbar.scrollTop();
},
_isScrolledToTop: function() {
return this.verticalScrollbar.scrollTop() === 0;
},
_isScrolledToBottom: function() {
var scrollbar = this.verticalScrollbar;
var scrollTop = scrollbar.scrollTop();
return scrollTop > 0 && scrollTop >= parseInt(scrollbar[0].scrollHeight - scrollbar.height(), 10);
},
_isWrapperScrolledToBottom: function() {
var wrapper = this.wrapper;
return wrapper.scrollTop() >= parseInt(wrapper[0].scrollHeight - wrapper.height(), 10);
},
itemIndex: function(rowIndex) {
return (this._rangeStart || this.dataSource.skip() || 0) + rowIndex;
},
position: function(index) {
var rangeStart = this._rangeStart || this.dataSource.skip() || 0;
var pageSize = this.dataSource.pageSize();
var result;
if (index > rangeStart) result = index - rangeStart;
else result = rangeStart - index - 1;
return result > pageSize ? pageSize : result;
},
scrollIntoView: function(row) {
var container = this.wrapper[0];
var containerHeight = container.clientHeight;
var containerScroll = !this._isScrolledToBottom() ? this._scrollTop || container.scrollTop : container.scrollTop;
var elementOffset = row[0].offsetTop;
var elementHeight = row[0].offsetHeight;
if (containerScroll > elementOffset) this.verticalScrollbar[0].scrollTop -= containerHeight / 2;
else if (elementOffset + elementHeight >= containerScroll + containerHeight) this.verticalScrollbar[0].scrollTop += containerHeight / 2;
},
_fetch: function(firstItemIndex, lastItemIndex, scrollingUp) {
var that = this, dataSource = that.dataSource, itemHeight = that.itemHeight, take = dataSource.take(), rangeStart = that._rangeStart || dataSource.skip() || 0, currentSkip = math.floor(firstItemIndex / take) * take, fetching = false, prefetchAt = .33;
var scrollbar = that.verticalScrollbar;
var webkitCorrection = browser.webkit ? 1 : 0;
var total = dataSource._isGroupPaged() ? dataSource.groupsTotal(true) : dataSource.total();
if (firstItemIndex < rangeStart) {
fetching = true;
if (that._alwaysScrollTop) {
rangeStart = math.min(firstItemIndex, total - take);
that._scrollTop = 0;
} else {
rangeStart = math.max(0, lastItemIndex - take);
that._scrollTop = scrollbar.scrollTop() - rangeStart * itemHeight;
}
that._page(rangeStart, take);
} else if (lastItemIndex >= rangeStart + take && !scrollingUp) {
fetching = true;
rangeStart = math.min(firstItemIndex, total - take);
if (scrollbar.scrollTop() >= scrollbar[0].scrollHeight - scrollbar[0].offsetHeight - webkitCorrection) that._scrollTop = that.wrapper[0].scrollHeight - that.wrapper[0].offsetHeight;
else if (that.dataSource._isGroupPaged() && firstItemIndex >= total - take) that._scrollTop = that.wrapper[0].scrollHeight - that.wrapper[0].offsetHeight - (that._scrollTop - that._prevScrollTop);
else if (that._alwaysScrollTop) that._scrollTop = 0;
else that._scrollTop = itemHeight;
that._page(rangeStart, take);
} else if (!that._fetching && that.options.prefetch) {
if (firstItemIndex < currentSkip + take - take * prefetchAt && firstItemIndex > take) dataSource.prefetch(currentSkip - take, take, $.noop);
if (lastItemIndex > currentSkip + take * prefetchAt) dataSource.prefetch(currentSkip + take, take, $.noop);
}
return fetching;
},
fetching: function() {
return this._fetching;
},
_page: function(skip, take, callback) {
var that = this, delayLoading = !that.options.prefetch, dataSource = that.dataSource, isGroupPaged = dataSource._isGroupPaged();
callback = isFunction(callback) ? callback : $.noop;
if (that.trigger(PAGING, {
skip,
take
})) return;
clearTimeout(that._timeout);
that._fetching = true;
that._rangeStart = skip;
if (isGroupPaged && dataSource._groupRangeExists(skip, skip + take) || !isGroupPaged && dataSource.inRange(skip, take)) {
that.trigger(LOAD_START);
dataSource.range(skip, take, function() {
that.trigger(LOAD_END);
callback();
that.trigger(PAGE);
}, "page");
} else {
if (!delayLoading) that.trigger(LOAD_START);
that._timeout = setTimeout(function() {
if (!that._scrolling) {
if (delayLoading) that.trigger(LOAD_START);
dataSource.range(skip, take, function() {
that.trigger(LOAD_END);
callback();
that.trigger(PAGE);
});
}
}, 100);
}
},
repaintScrollbar: function(shouldScrollWrapper) {
var that = this, maxHeight = that.options.maxScrollHeight, dataSource = that.dataSource, scrollbar = !kendo.support.kineticScrollNeeded ? kendo.support.scrollbar() : 0, wrapperElement = that.wrapper[0], totalHeight, itemHeight;
var wasScrolledToBottom = that._isScrolledToBottom();
itemHeight = that.itemHeight = that.options.itemHeight() || 0;
var addScrollBarHeight = wrapperElement.scrollWidth > wrapperElement.offsetWidth ? scrollbar : 0;
totalHeight = (dataSource._isGroupPaged() ? dataSource.groupsTotal(true) : dataSource.total()) * itemHeight + addScrollBarHeight;
var divElements = $(new Array(math.floor(totalHeight / maxHeight) + 1).join("<div></div>")).css({
width: "1px",
height: `${maxHeight}px`
});
if (totalHeight % maxHeight) divElements = divElements.add($("<div></div>").css({
width: "1px",
height: `${totalHeight % maxHeight}px`
}));
that.verticalScrollbar.empty().append(divElements);
if (wasScrolledToBottom && !that._isScrolledToBottom() && !that.dataSource._isGroupPaged()) that.scrollToBottom();
if (typeof that._scrollTop !== "undefined" && !!shouldScrollWrapper) {
wrapperElement.scrollTop = that._scrollTop;
that._scrollWrapperOnColumnResize();
}
},
refresh: function(e) {
var that = this, dataSource = that.dataSource, rangeStart = that._rangeStart;
var action = (e || {}).action;
var shouldScrollWrapper = that._isScrolledToBottom() || !action || action !== ITEM_CHANGE && action !== REMOVE && action !== SYNC;
that.trigger(LOAD_END);
clearTimeout(that._timeout);
that.repaintScrollbar(shouldScrollWrapper);
if (that.drag) that.drag.cancel();
if (typeof rangeStart !== "undefined" && !that._fetching) {
if (!action || action !== SYNC && action !== ITEM_CHANGE && action !== "expandGroup") that._rangeStart = dataSource.skip();
if (dataSource.page() === 1 && (!action || action !== SYNC && action !== ITEM_CHANGE && action !== "expandGroup" && action !== "collapseGroup")) that.verticalScrollbar[0].scrollTop = 0;
}
if (that._programmaticallyScrolling && that._programmaticallyScrolling.state() !== "resolved") that._programmaticallyScrolling.resolve();
if (that._alwaysScrollTop) delete that._alwaysScrollTop;
that._fetching = false;
}
});
function flattenFilterDescriptors(filters) {
if (!filters || !Array.isArray(filters.filters)) return [];
const flattened = [];
function processFilter(filter) {
if (filter.logic && filter.filters) filter.filters.forEach(processFilter);
else if (filter.field && filter.operator) flattened.push({ ...filter });
}
filters.filters.forEach(processFilter);
return flattened;
}
function flattenGroupDescriptors(groups) {
if (!groups || !Array.isArray(groups)) return [];
const flattened = [];
function processGroup(group) {
flattened.push({ ...group });
if (group.items && Array.isArray(group.items)) group.items.forEach((item) => {
if (item.items) processGroup(item);
});
}
groups.forEach(processGroup);
return flattened;
}
function flattenSortDescriptors(sorts) {
if (!sorts || !Array.isArray(sorts)) return [];
return sorts;
}
function hasInvalidDescriptor(descriptors, key) {
let flatFunction = {
sort: flattenSortDescriptors,
filter: flattenFilterDescriptors,
group: flattenGroupDescriptors
}[key];
if (!flatFunction) return false;
return flatFunction(descriptors).some((item) => !item.field);
}
function attrEquals(attrName, attrValue) {
return "[" + kendo.attr(attrName) + "=" + attrValue + "]";
}
function groupCells(count) {
return new Array(count + 1).join("<td class=\"k-group-cell k-table-group-td k-table-td\"> </td>");
}
function cellsExcludingSpecialColumns(cells) {
return cells.filter((i, cell) => {
const $cell = $(cell);
const hasCheckbox = $cell.children(".k-select-checkbox").length > 0;
const hasWrappedCheckbox = $cell.find("> .k-checkbox-wrap > .k-select-checkbox").length > 0;
return $cell.attr("[ref-grid-drag-cell]") === undefined && !$cell.hasClass("k-command-cell") && !hasCheckbox && !hasWrappedCheckbox;
});
}
function stringifyAttributes(attributes) {
var attr, result = " ";
if (attributes) {
if (typeof attributes === STRING) return attributes;
for (attr in attributes) if (attributes[attr] !== "") result += attr + "=\"" + attributes[attr] + "\"";
}
return result;
}
function parseDate(value, fields) {
if (!fields) return value;
return value.map((descriptor) => ({
...descriptor,
logic: (descriptor?.logic || descriptor?.logicalOperator || "and").toLowerCase(),
filters: descriptor?.filters?.map((filter) => {
const field = filter.field;
if (fields && fields[field]) {
if (fields[field].type.toLowerCase() === "date") return {
...filter,
value: new Date(filter.value)
};
}
return filter;
})
})) || [];
}
function syncFooterColsWidthsWithHeader(header, footer) {
const headerCols = header.parent().find(">colgroup>col:not(.k-group-col):not(.k-hierarchy-col)");
const footerCols = footer.find(">.k-grid-footer-wrap>table>colgroup>col:not(.k-group-col):not(.k-hierarchy-col)");
if (headerCols.length && footerCols.length === headerCols.length) headerCols.each(function(i) {
const width = this.style.width;
if (width) footerCols.eq(i).css("width", width);
});
const headerGroupCols = header.parent().find(">colgroup>.k-group-col");
const footerGroupCols = footer.find(">.k-grid-footer-wrap>table>colgroup>.k-group-col");
if (headerGroupCols.length && footerGroupCols.length === headerGroupCols.length) headerGroupCols.each(function(i) {
const width = this.style.width;
if (width) footerGroupCols[i].style.width = width;
});
}
const defaultCommands = {
aiassistant: {
text: "",
icon: "sparkles",
rounded: "full",
className: "k-grid-ai-assistant-tool",
themeColor: "primary"
},
create: {
text: "Add",
className: "k-grid-add",
iconClass: "k-i-plus"
},
cancel: {
text: "Cancel changes",
className: "k-grid-cancel-changes",
iconClass: "k-i-cancel"
},
save: {
text: "Save changes",
className: "k-grid-save-changes",
iconClass: "k-i-check"
},
selectall: { text: "Select all" },
destroy: {
text: "Delete",
className: "k-grid-remove-command",
iconClass: "k-i-trash"
},
edit: {
text: "Edit",
className: "k-grid-edit-command",
iconClass: "k-i-pencil"
},
update: {
text: "Save",
className: "k-grid-save-command",
iconClass: "k-i-save"
},
canceledit: {
text: "Cancel",
className: "k-grid-cancel-command",
iconClass: "k-i-cancel"
},
excel: {
text: "Export to Excel",
className: "k-grid-excel",
iconClass: "k-i-file-excel"
},
pdf: {
text: "Export to PDF",
className: "k-grid-pdf",
iconClass: "k-i-file-pdf"
},
csv: {
text: "Export to CSV",
className: "k-grid-csv",
iconClass: "k-i-file-csv"
},
search: {
text: "Search...",
className: "k-grid-search"
},
columns: {
text: "Columns",
type: "button",
icon: "columns",
fillMode: "flat",
overflow: "never",
className: "k-grid-column-menu",
attr: { "aria-haspopup": "menu" }
},
columnchooser: {
text: "Columns",
type: "button",
icon: "columns",
overflow: "never",
className: "k-grid-column-chooser",
attr: { "aria-haspopup": "menu" }
},
sort: {
text: "Sort",
type: "button",
icon: "arrows-swap",
overflow: "never",
className: "k-grid-sort-tool",
attr: { "aria-haspopup": "menu" },
clearButton: true
},
filter: {
text: "Filter",
type: "button",
icon: "filter",
overflow: "never",
className: "k-grid-filter-tool",
attr: { "aria-haspopup": "menu" },
clearButton: true
},
group: {
text: "Group",
type: "button",
icon: "group",
overflow: "never",
className: "k-grid-group-tool",
attr: { "aria-haspopup": "menu" },
clearButton: true
},
smartbox: {
overflow: "never",
template: () => `<input ref-grid-smartbox-input data-role="smartbox" />`
}
};
const supportedAIDataSourceCommands = {
"GridSort": "sort",
"GridClearSort": "sort",
"GridFilter": "filter",
"GridClearFilter": "filter",
"GridGroup": "group",
"GridClearGroup": "group",
"GridPage": "page",
"GridPageSize": "pageSize"
};
const supportedAIGridCommands = {
"GridHighlight": "highlight",
"GridClearHighlight": "highlight",
"GridSelect": "select",
"GridClearSelect": "select",
"GridColumnResize": "resizeColumn",
"GridColumnHide": "hideColumn",
"GridColumnShow": "showColumn",
"GridColumnLock": "lockColumn",
"GridColumnUnlock": "unlockColumn",
"GridColumnReorder": "reorderColumn",
"GridExportPDF": "_exportPdf",
"GridExportExcel": "_exportExcel",
"GridExportCSV": "_exportCsv"
};
const placeholderId = kendo.guid();
function resolveCommandText(command, messages) {
if (!command) return "";
const defaultText = defaultCommands[command.name?.toLowerCase()]?.text;
const messageText = messages[command.name?.toLowerCase()];
const hasCustomText = typeof command.text === STRING && command.text.trim() !== defaultText;
const hasMessageText = messageText && messageText !== defaultText;
if (isPlainObject(command.text)) return command.text;
let resolvedText = defaultText || command.text || "";
if (hasMessageText) resolvedText = messageText;
if (hasCustomText) resolvedText = command.text;
return resolvedText;
}
function promptPlaceholderOptions(messages) {
return {
id: placeholderId,
prompt: "",
output: messages?.outputPlaceholder,
skipHeader: true,
skipActions: true
};
}
function cursor(context, value) {
$("th, th .k-grid-filter-menu, th .k-link", context).add(document.body).css("cursor", value);
}
function reorder(selector, source, dest, before, count) {
var sourceIndex = source;
source = $();
count = count || 1;
for (var idx = 0; idx < count; idx++) source = source.add(selector.eq(sourceIndex + idx));
if (typeof dest == "number") source[before ? "insertBefore" : "insertAfter"](selector.eq(dest));
else source.appendTo(dest);
}
function elements(lockedContent, content, filter) {
return $(lockedContent).add(content).find(filter);
}
function attachCustomCommandEvent(context, container, commands) {
var idx, length, command, commandName;
commands = !isArray(commands) ? [commands] : commands;
for (idx = 0, length = commands.length; idx < length; idx++) {
command = commands[idx];
if (isPlainObject(command) && command.click) {
commandName = command.name || command.text;
container.on("click.kendoGrid", ".k-grid-" + (commandName || "").replace(/\s/g, ""), { commandName }, command.click.bind(context));
}
}
}
function normalizeColumns(columns, encoded, hide, locked, parentIds) {
return map(columns, function(column) {
column = typeof column === STRING ? { field: column } : column;
var hidden;
column.parentIds = parentIds;
if (column.attributes instanceof Function) column._attributesFunction = column.attributes;
if (!isVisible(column) || hide) {
column.attributes = addHiddenStyle(column.attributes);
column.footerAttributes = addHiddenStyle(column.footerAttributes);
column.headerAttributes = addHiddenStyle(column.headerAttributes);
hidden = true;
} else if (isVisible(column) || !hide) {
column.attributes = removeHiddenStyle(column.attributes);
column.footerAttributes = removeHiddenStyle(column.footerAttributes);
column.headerAttributes = removeHiddenStyle(column.headerAttributes);
hidden = undefined;
}
var uid = kendo.guid();
if (locked && !column.locked) column.locked = locked;
column.headerAttributes = extend({ headers: parentIds }, column.headerAttributes);
if (!column.headerAttributes.id) {
column.headerAttributes = extend({ id: uid }, column.headerAttributes);
column.uid = uid;
} else column.uid = uid = column.headerAttributes.id;
if (column.columns) column.columns = normalizeColumns(column.columns, encoded, hidden, column.locked, parentIds ? parentIds + " " + uid : uid);
return extend({
encoded,
hidden,
locked
}, column);
});
}
function columnParent(column, columns) {
var parents = [];
columnParents(column, columns, parents);
return parents[parents.length - 1];
}
function columnParents(column, columns, parents) {
parents = parents || [];
for (var idx = 0; idx < columns.length; idx++) if (column === columns[idx]) return true;
else if (columns[idx].columns) {
var inserted = parents.length;
parents.push(columns[idx]);
if (!columnParents(column, columns[idx].columns, parents)) parents.splice(inserted, parents.length - inserted);
else return true;
}
return false;
}
function setColumnVisibility(column, visible) {
setVisibility(column, visible, visible);
}
function addElementsToTab(elements) {
elements.attr(TABINDEX, 1);
}
function removeElementsFromTab(elements) {
elements.removeAttr(TABINDEX);
}
function setVisibility(column, visible, show) {
var method = show ? removeHiddenStyle : addHiddenStyle;
column.hidden = !visible;
column.attributes = method(column.attributes);
column.footerAttributes = method(column.footerAttributes);
column.headerAttributes = method(column.headerAttributes);
}
function setColumnMediaVisibility(column, visible) {
setColumnMatchesMedia(column);
var hideByMedia = column._hideByMedia;
setVisibility(column, visible, hideByMedia ? column.matchesMedia : visible);
}
function setColumnMatchesMedia(column) {
column.matchesMedia = columnMatchesMedia(column);
}
function columnMatchesMedia(column) {
return column && (isUndefined(column.media) || !isUndefined(column.media) && kendo.matchesMedia(column.media));
}
function isCellVisible() {
return this.style.display !== NONE && !this.classList.contains("k-hidden");
}
function isElementVisible(element) {
return $(element)[0].style.display !== NONE && !$(element)[0].classList.contains("k-hidden");
}
function isVisible(column) {
return visibleColumns([column]).length > 0;
}
function visibleColumns(columns) {
return grep(columns, function(column) {
var result = !column.hidden && column.matchesMedia !== false;
if (result && column.columns) result = visibleColumns(column.columns).length > 0;
return result;
});
}
function columnsWithMedia(columns) {
var result = [];
var column;
for (var i = 0; i < columns.length; i++) {
column = columns[i];
if (!isUndefined(column.media)) {
if (!isUndefined(column.minScreenWidth)) throw new Error("Using 'media' and 'minScreenWidth' options at the same time is not supported.");
result.push(column);
}
if (column.columns) result = result.concat(columnsWithMedia(column.columns));
}
return result;
}
function isUndefined(value) {
return typeof value === "undefined";
}
function toJQuery(elements) {
return $(elements).map(function() {
return this.toArray();
});
}
function updateCellRowSpan(cell, columns, sourceLockedColumnsCount) {
var lockedColumnDepth = depth(lockedColumns(columns));
var nonLockedColumnDepth = depth(nonLockedColumns(columns));
var rowSpan = cell.rowSpan;
if (sourceLockedColumnsCount) if (lockedColumnDepth > nonLockedColumnDepth) cell.rowSpan = rowSpan - (lockedColumnDepth - nonLockedColumnDepth) || 1;
else cell.rowSpan = rowSpan + (nonLockedColumnDepth - lockedColumnDepth);
else if (lockedColumnDepth > nonLockedColumnDepth) cell.rowSpan = rowSpan + (lockedColumnDepth - nonLockedColumnDepth);
else cell.rowSpan = rowSpan - (nonLockedColumnDepth - lockedColumnDepth) || 1;
}
function findColumnByField(columns, field) {
for (var i = 0; i < columns.length; i++) if (columns[i].field == field) return columns[i];
}
function getMergedAIDescriptors(previousDescriptors, newDescriptors, key) {
let shouldContinue;
newDescriptors.forEach((newDescriptor) => {
shouldContinue = false;
let index;
const matchingPreviousDescriptor = previousDescriptors.find((prevDescriptor, i) => {
if (prevDescriptor.field === newDescriptor.field) {
index = i;
return true;
}
});
if (matchingPreviousDescriptor && key === "group") {
shouldContinue = true;
return;
}
if (matchingPreviousDescriptor) previousDescriptors.splice(index, 1);
previousDescriptors.push(newDescriptor);
});
return {
descriptors: previousDescriptors,
shouldContinue
};
}
function getEnabledAICommands(options, dataSource, checkBoxSelection) {
const sortable = options?.sortable || options?.columnMenu?.sortable;
const filterable = options?.filterable || options?.columnMenu?.filterable;
const selectable = options?.selectable || checkBoxSelection;
const groupable = options?.groupable?.enabled || options?.groupable || dataSource._groupPaging;
return {
"GridSort": sortable,
"GridClearSort": sortable,
"GridFilter": filterable,
"GridClearFilter": filterable,
"GridGroup": groupable,
"GridClearGroup": groupable,
"GridSelect": selectable,
"GridClearSelect": selectable,
"GridColumnResize": options?.resizable || options?.resizable?.columns,
"GridColumnReorder": options?.reorderable || options?.reorderable?.columns,
"GridPage": options?.scrollable?.virtual && options?.scrollable?.virtual === "columns" && options?.pageable || !options?.scrollable?.endless && options?.pageable || options?.pageable,
"GridPageSize": true,
"GridColumnHide": true,
"GridColumnShow": true,
"GridColumnLock": true,
"GridColumnUnlock": true
};
}
function getToolbarRegex({ mode, hasSelected, hasChanges, editContainerVisible, differentSelectionThanEditing, _editableIsClosing, _isEditableEnabled, options }) {
const editableCommands = /\b(k-grid-edit-command|k-grid-remove-command|k-grid-save-changes|k-grid-cancel-changes|k-grid-cancel-command|k-grid-save-command)\b/;
const commands = [];
if (!_isEditableEnabled || !options.editable) return editableCommands;
if (!hasSelected) {
commands.push("k-grid-edit-command");
commands.push("k-grid-remove-command");
}
if (hasSelected && (mode === "incell" || mode === "inline" && !differentSelectionThanEditing)) commands.push("k-grid-edit-command");
if (!hasChanges) {
commands.push("k-grid-save-changes");
commands.push("k-grid-cancel-changes");
}
if (mode !== "inline" || !editContainerVisible || editContainerVisible && _editableIsClosing) {
commands.push("k-grid-save-command");
commands.push("k-grid-cancel-command");
}
let regex = "";
if (commands.length) {
regex = commands.join("|");
regex = `\\b(${regex})\\b`;
return new RegExp(regex);
}
return regex;
}
function moveCellsBetweenContainers(sources, target, leafs, columns, container, destination, groups, action) {
var sourcesDepth = depth(sources);
var targetDepth = depth([target]);
if (sourcesDepth > targetDepth) {
var groupCells = new Array(groups + 1).join("<th class=\"k-group-cell k-header k-table-th\" scope=\"col\"> </th>");
var rows = destination.children(":not(.k-filter-row)");
$(new Array(sourcesDepth - targetDepth + 1).join("<tr class='k-table-row'>" + groupCells + "</tr>")).insertAfter(rows.last());
}
addRowSpanValue(destination, sourcesDepth - targetDepth);
moveCells(leafs, columns, container, destination, action);
}
function updateCellIndex(thead, columns, offset) {
offset = offset || 0;
var position;
var cell;
var allColumns = columns;
columns = leafColumns(columns);
var cells = {};
var rows = thead.find(">tr:not(.k-filter-row)");
var filter = function() {
var el = $(this);
return !el.hasClass("k-group-cell") && !el.hasClass("k-hierarchy-cell");
};
for (var idx = 0, length = columns.length; idx < length; idx++) {
position = columnPosition(columns[idx], allColumns);
if (!cells[position.row]) cells[position.row] = rows.eq(position.row).find(".k-header").filter(filter);
cell = cells[position.row].eq(position.cell);
cell.attr(kendo.attr("index"), offset + idx);
}
return columns.length;
}
function depth(columns) {
var result = 1;
var max = 0;
for (var idx = 0; idx < columns.length; idx++) if (columns[idx].columns) {
var temp = depth(columns[idx].columns);
if (temp > max) max = temp;
}
return result + max;
}
function moveCells(leafs, columns, container, destination, action) {
var sourcePosition = columnVisiblePosition(leafs[0], columns);
var ths = container.find(">tr:not(.k-filter-row)").eq(sourcePosition.row).children("th.k-header:not(.k-group-cell)");
var t = $();
var sourceIndex = sourcePosition.cell;
var idx;
for (idx = 0; idx < leafs.length; idx++) t = t.add(ths.eq(sourceIndex + idx));
destination.find(">tr:not(.k-filter-row)").eq(sourcePosition.row)[action](t);
var children = [];
for (idx = 0; idx < leafs.length; idx++) if (leafs[idx].columns) children = children.concat(leafs[idx].columns);
if (children.length) moveCells(children, columns, container, destination, action);
}
function columnPosition(column, columns, row, cellCounts) {
var result;
var idx;
row = row || 0;
cellCounts = cellCounts || {};
cellCounts[row] = cellCounts[row] || 0;
for (idx = 0; idx < columns.length; idx++) {
if (columns[idx] == column) {
result = {
cell: cellCounts[row],
row
};
break;
} else if (columns[idx].columns) {
result = columnPosition(column, columns[idx].columns, row + 1, cellCounts);
if (result) break;
}
cellCounts[row]++;
}
return result;
}
function findParentColumnWithChildren(columns, index, source, rtl) {
var target;
var locked = !!source.locked;
var targetLocked;
do {
target = columns[index];
index += rtl ? 1 : -1;
targetLocked = !!target.locked;
} while (target && index > -1 && index < columns.length && target != source && !target.columns && targetLocked === locked);
return target;
}
function decorateCellWithClass(html, skipTdClass) {
let element = html;
let classes = element.match(/class=["][^"]+/g);
if (classes) {
const cssClasses = classes[0].split("\"").pop();
element = element.replace(cssClasses, cssClasses + (skipTdClass ? "" : " k-table-td "));
} else element = element.replace("<td", "<td class='k-table-td'");
return element;
}
function findReorderTarget(columns, target, source, before, masterColumns) {
if (target.columns) {
target = target.columns;
return target[before ? 0 : target.length - 1];
} else {
var parent = columnParent(target, columns);
var parentColumns;
if (parent) parentColumns = parent.columns;
else parentColumns = columns;
var index = inArray(target, parentColumns);
if (index === 0 && before) index++;
else if (index == parentColumns.length - 1 && !before || !source.locked && !target.columns && !before) index--;
else if (index > 0 || index === 0 && !before) index++;
var sourceIndex = inArray(source, parentColumns);
target = findParentColumnWithChildren(parentColumns, index, source, sourceIndex > index);
var targetIndex = inArray(target, masterColumns);
if (target.columns && (!targetIndex || targetIndex === parentColumns.length - 1)) return null;
if (target && target != source && target.columns) return findReorderTarget(columns, target, source, before, masterColumns);
}
return null;
}
function columnVisiblePosition(column, columns, row, cellCounts) {
var result;
var idx;
row = row || 0;
cellCounts = cellCounts || {};
cellCounts[row] = cellCounts[row] || 0;
for (idx = 0; idx < columns.length; idx++) {
if (columns[idx] == column) {
result = {
cell: cellCounts[row],
row
};
break;
} else if (columns[idx].columns) {
result = columnVisiblePosition(column, columns[idx].columns, row + 1, cellCounts);
if (result) break;
}
if (!columns[idx].hidden) cellCounts[row]++;
}
return result;
}
function flatColumnsInDomOrder(columns) {
return flatColumns(lockedColumns(columns)).concat(flatColumns(nonLockedColumns(columns)));
}
function targetParentContainerIndex(flatColumns, columns, sourceIndex, targetIndex) {
var column = flatColumns[sourceIndex];
var target = flatColumns[targetIndex];
var parent = columnParent(column, columns);
columns = parent ? parent.columns : columns;
return inArray(target, columns);
}
function flatColumns(columns) {
var result = [];
var children = [];
for (var idx = 0; idx < columns.length; idx++) {
result.push(columns[idx]);
if (columns[idx].columns) children = children.concat(columns[idx].columns);
}
if (children.length) result = result.concat(flatColumns(children));
return result;
}
function hiddenLeafColumnsCount(columns) {
var counter = 0;
var column;
for (var idx = 0; idx < columns.length; idx++) {
column = columns[idx];
if (column.columns) counter += hiddenLeafColumnsCount(column.columns);
else if (column.hidden) counter++;
}
return counter;
}
function sumWidths(cols) {
var width = 0;
for (var idx = 0, length = cols.length; idx < length; idx++) if (!cols[idx].hidden) width += parseInt(cols[idx].width, 10);
return width;
}
function columnsWidth(cols) {
var colWidth, width = 0;
for (var idx = 0, length = cols.length; idx < length; idx++) {
colWidth = cols[idx].style.width;
if (colWidth && colWidth.indexOf("%") == -1) width += parseInt(colWidth, 10);
}
return width;
}
function removeRowSpanValue(container, count) {
var cells = container.find("tr:not(.k-filter-row) th:not(.k-group-cell,.k-hierarchy-cell)");
var rowSpan;
for (var idx = 0; idx < cells.length; idx++) {
rowSpan = cells[idx].rowSpan;
if (rowSpan > 1) cells[idx].rowSpan = rowSpan - count || 1;
}
}
function addRowSpanValue(container, count) {
var cells = container.find("tr:not(.k-filter-row) th:not(.k-group-cell,.k-hierarchy-cell)");
for (var idx = 0; idx < cells.length; idx++) cells[idx].rowSpan += count;
}
function removeEmptyRows(container) {
var rows = container.find("tr:not(.k-filter-row)");
var emptyRowsCount = rows.filter(function() {
return !$(this).children().length;
}).remove().length;
var cells = rows.find("th:not(.k-group-cell,.k-hierarchy-cell)");
for (var idx = 0; idx < cells.length; idx++) if (cells[idx].rowSpan > 1) cells[idx].rowSpan -= emptyRowsCount;
return rows.length - emptyRowsCount;
}
function mapColumnToCellRows(columns, cells, rows, rowIndex, offset) {
var idx, row, length, children = [];
for (idx = 0, length = columns.length; idx < length; idx++) {
row = rows[rowIndex] || [];
row.push(cells.eq(offset + idx));
rows[rowIndex] = row;
if (columns[idx].columns) children = children.concat(columns[idx].columns);
}
if (children.length) mapColumnToCellRows(children, cells, rows, rowIndex + 1, offset + columns.length);
}
function setLeftAndRightStyles(element, left, right) {
element.css({
"left": left,
"right": right
});
}
function createColumnAttribute(column, attribute, property) {
column[attribute] = column[attribute] || {};
column[attribute][property] = column[attribute][property] || "";
}
function addColumnAttribute(column, attribute, property, value) {
createColumnAttribute(column, attribute, property);
if (column[attribute][property] !== "") column[attribute][property] += " " + value;
else column[attribute][property] = value;
}
function removeColumnAttribute(column, attribute, property, value, removeAttributeProperty) {
createColumnAttribute(column, attribute, property);
if (removeAttributeProperty) delete column[attribute][property];
else column[attribute][property] = column[attribute][property].replace(value, "");
}
function lockedColumns(columns) {
return grep(columns, function(column) {
return column.locked;
});
}
function nonLockedColumns(columns) {
return grep(columns, function(column) {
return !column.locked;
});
}
function stickyColumns(columns) {
return grep(columns, function(column) {
return column.sticky && !column.locked;
});
}
function visibleStickyColumns(columns) {
return grep(columns, function(column) {
return column.sticky && !column.locked && isVisible(column);
});
}
function visibleNonLockedColumns(columns) {
return grep(columns, function(column) {
return !column.locked && isVisible(column);
});
}
function visibleLockedColumns(columns) {
return grep(columns, function(column) {
return column.locked && isVisible(column);
});
}
function visibleLeafColumns(columns) {
var result = [];
for (var idx = 0; idx < columns.length; idx++) {
if (columns[idx].hidden) continue;
if (columns[idx].columns) result = result.concat(visibleLeafColumns(columns[idx].columns));
else result.push(columns[idx]);
}
return result;
}
function visibleLeafExportColumns(columns) {
var result = [];
for (var idx = 0; idx < columns.length; idx++) {
if (columns[idx].hidden) continue;
if (columns[idx].columns) result = result.concat(visibleLeafColumns(columns[idx].columns));
else result.push({
field: columns[idx].field,
width: columns[idx].width,
values: columns[idx].values,
title: columns[idx].title
});
}
return result;
}
function childColumns(columns) {
var result = [];
for (var idx = 0; idx < columns.length; idx++) if (columns[idx].columns) result = result.concat(columns[idx].columns);
return result;
}
function visibleChildColumns(columns) {
var result = childColumns(columns);
result = result.filter(function(e) {
return !e.hidden;
});
return result;
}
function leafColumns(columns) {
var result = [];
for (var idx = 0; idx < columns.length; idx++) {
if (!columns[idx].columns) {
result.push(columns[idx]);
continue;
}
result = result.concat(leafColumns(columns[idx].columns));
}
return result;
}
function getColumnsFields(columns) {
var result = [];
columns = leafColumns(columns);
for (var idx = 0; idx < columns.length; idx++) if (typeof columns[idx] === "string") result.push(columns[idx]);
else if (columns[idx].field) result.push(columns[idx].field);
return result;
}
function getAllColumns(columns) {
var result = [];
for (var idx = 0; idx < columns.length; idx++) {
result.push(columns[idx]);
if (columns[idx].columns) result = result.concat(getAllColumns(columns[idx].columns));
}
return result;
}
function createMultiHeaderTitle(gridInstance, col) {
const separator = col.multiHeaderSeparator || " / ";
const columns = getAllColumns(gridInstance.columns);
const parentTitles = col.parentIds.split(" ").map((id) => {
let parent = columns.find((c) => c.uid === id);
return parent ? parent.title || parent.field || "" : "";
});
parentTitles.push(col.title || col.field);
return parentTitles.join(separator);
}
function editField(column, adaptive) {
return {
field: column.field,
title: column.title,
format: column.format,
editor: column.editor,
values: column.values,
editorOptions: extend(true, {
format: column.format,
adaptiveMode: adaptive
}, column.editorOptions),
label: column.title || column.field || ""
};
}
function leafDataCells(container) {
var rows = container.find(">tr:not(.k-filter-row)");
var filter = function() {
var el = $(this);
return !el.hasClass("k-group-cell") && !el.hasClass("k-hierarchy-cell");
};
var cells = $();
if (rows.length > 1) cells = rows.find("th").filter(filter).filter(function() {
return this.rowSpan > 1;
});
cells = cells.add(rows.last().find("th").filter(filter));
var indexAttr = kendo.attr("index");
return [].sort.call(cells, function(a, b) {
a = $(a);
b = $(b);
var indexA = a.attr(indexAttr);
var indexB = b.attr(indexAttr);
if (indexA === undefined) indexA = $(a).index();
if (indexB === undefined) indexB = $(b).index();
indexA = parseInt(indexA, 10);
indexB = parseInt(indexB, 10);
return indexA > indexB ? 1 : indexA < indexB ? -1 : 0;
});
}
function parentColumnsCells(cell) {
var container = cell.closest("table");
var result = $().add(cell);
var row = cell.closest(TR);
var headerRows = container.find("tr:not(.k-filter-row)");
var level = headerRows.index(row);
if (level > 0) {
var parentCellsWithChildren = headerRows.eq(level - 1).find("th:not(.k-group-cell,.k-hierarchy-cell)").filter(function() {
return !$(this).attr("rowspan");
});
var offset = 0;
var index = row.find("th:not(.k-group-cell,.k-hierarchy-cell)").index(cell);
var prevCells = cell.prevAll(":not(.k-group-cell,.k-hierarchy-cell)").filter(function() {
return this.colSpan > 1;
});
for (var idx = 0; idx < prevCells.length; idx++) offset += prevCells[idx].colSpan || 1;
index += Math.max(offset - 1, 0);
offset = 0;
for (idx = 0; idx < parentCellsWithChildren.length; idx++) {
var parentCell = parentCellsWithChildren.eq(idx);
if (parentCell.attr("data-colspan")) offset += parentCell[0].getAttribute("data-colspan");
else offset += 1;
if (index >= idx && index < offset) {
result = parentColumnsCells(parentCell).add(result);
break;
}
}
}
return result;
}
function childColumnsCells(cell) {
var container = cell.closest("thead");
var result = $().add(cell);
var row = cell.closest(TR);
var headerRows = container.find("tr:not(.k-filter-row)");
var level = headerRows.index(row) + cell[0].rowSpan;
var colSpanAttr = kendo.attr("colspan");
if (level <= headerRows.length - 1) {
var child = row.next();
var prevCells = cell.prevAll(":not(.k-group-cell,.k-hierarchy-cell)");
var idx;
prevCells = prevCells.filter(function() {
return !this.rowSpan || this.rowSpan === 1;
});
var offset = 0;
for (idx = 0; idx < prevCells.length; idx++) offset += parseInt(prevCells.eq(idx).attr(colSpanAttr), 10) || 1;
var cells = child.find("th:not(.k-group-cell,.k-hierarchy-cell)");
var colSpan = parseInt(cell.attr(colSpanAttr), 10) || 1;
idx = 0;
while (idx < colSpan) {
child = cells.eq(idx + offset);
result = result.add(childColumnsCells(child));
var value = parseInt(child.attr(colSpanAttr), 10);
if (value > 1) colSpan -= value - 1;
idx++;
}
}
return result;
}
function appendContent(tbody, table, html, size) {
var placeholder, tmp = tbody;
if (tbodySupportsInnerHtml) {
let $html = $(html);
kendo.applyStylesFromKendoAttributes($html, [
"display",
"left",
"right"
]);
tbody.empty();
$html.each((_, el) => tbody[0].appendChild(el));
} else {
placeholder = document.createElement(DIV);
placeholder.innerHTML = "<table class='k-grid-table k-table'><tbody class='k-table-tbody'>" + html + "</tbody></table>";
$(placeholder).find("table").addClass(kendo.getValidCssClass("k-table-", "size", size));
tbody = placeholder.firstChild.firstChild;
table[0].replaceChild(tbody, tmp[0]);
tbody = $(tbody);
}
return tbody;
}
function addHiddenStyle(attr) {
attr = attr || {};
let kendoStyleAttrObject = {};
kendoStyleAttrObject[kendo.attr("style-display")] = "none";
return extend({}, attr, kendoStyleAttrObject);
}
function hasHiddenStyle(attr) {
attr = attr || {};
return !!attr[kendo.attr("style-display")];
}
function removeHiddenStyle(attr) {
attr = attr || {};
delete attr[kendo.attr("style-display")];
return attr;
}
function normalizeCols(table, visibleColumns, hasDetails, groups, stacked) {
var colgroup = table.find(">colgroup"), width, groupColWidths = [], cols = stacked ? ["<col>"] : map(visibleColumns, function(column) {
width = column.width;
if (width && parseInt(width, 10) !== 0) return kendo.format(`<col ${kendo.attr("style-width")}="{0}" ${column.draggable ? "class=k-drag-col" : ""} />`, typeof width === STRING ? width : width + PX);
if (column.draggable) return "<col class='k-drag-col' />";
return "<col />";
});
if (!stacked && (hasDetails || colgroup.find(".k-hierarchy-col").length)) cols.splice(0, 0, "<col class=\"k-hierarchy-col\" />");
colgroup.find(".k-group-col").each(function(i) {
if (this.style.width) groupColWidths[i] = this.style.width;
});
if (colgroup.length) colgroup.remove();
colgroup = $(new Array(groups + 1).join("<col class=\"k-group-col\">") + cols.join(""));
kendo.applyStylesFromKendoAttributes(colgroup, ["width"]);
if (!colgroup.is("colgroup")) colgroup = $("<colgroup/>").append(colgroup);
table.prepend(colgroup);
if (groupColWidths.length) table.find(">colgroup>.k-group-col").each(function(i) {
if (groupColWidths[i]) this.style.width = groupColWidths[i];
});
}
function normalizeHeaderCells(container, columns) {
var lastIndex = 0;
var idx, len;
var th = container.find("th:not(.k-group-cell)");
for (idx = 0, len = columns.length; idx < len; idx++) if (columns[idx].locked) {
th.eq(idx).insertBefore(th.eq(lastIndex));
th = container.find("th:not(.k-group-cell)");
lastIndex++;
}
}
function convertToObject(array) {
var result = {}, item, idx, length;
for (idx = 0, length = array.length; idx < length; idx++) {
item = array[idx];
result[item.value] = item.text;
}
return result;
}
function formatGroupValue(value, format, columnValues, encoded) {
let groupValue = columnValues && columnValues.length && isPlainObject(columnValues[0]) && "value" in columnValues[0] ? convertToObject(columnValues)[value] : value;
groupValue = groupValue != null ? groupValue : "";
let usedValue = encoded === false ? groupValue : kendo.htmlEncode(groupValue);
return format ? kendo.format(format, usedValue) : usedValue;
}
function setCellVisibility(cells, index, visible) {
var pad = 0, state, cell = cells[pad];
while (cell) {
state = visible ? true : cell.style.display !== NONE;
if (visible && cell.classList.contains("k-hidden")) cell.classList.remove("k-hidden");
if (state && !nonDataCellsRegExp.test(cell.className) && --index < 0) {
cell.style.display = visible ? "" : NONE;
break;
}
cell = cells[++pad];
}
}
function hideColumnCells(rows, columnIndex) {
var idx = 0, length = rows.length, cell, row;
for (; idx < length; idx += 1) {
row = rows.eq(idx);
if (row.is(".k-grouping-row,.k-detail-row")) {
cell = row.children(":not(.k-group-cell):first,.k-detail-cell").last();
cell.attr("colspan", parseInt(cell.attr("colspan"), 10) - 1);
} else {
if (row.hasClass("k-grid-edit-row") && (cell = row.children(".k-edit-container")[0])) {
cell = $(cell);
cell.attr("colspan", parseInt(cell.attr("colspan"), 10) - 1);
cell.find("col").eq(columnIndex).remove();
row = cell.find(TR).first();
}
setCellVisibility(row[0].cells, columnIndex, false);
}
}
}
function groupRows(data) {
var result = [];
var item;
for (var idx = 0; idx < data.length; idx++) {
item = data[idx];
if (!("field" in item && "value" in item && "items" in item)) break;
result.push(item);
if (item.hasSubgroups) result = result.concat(groupRows(item.items));
}
return result;
}
function groupFooters(data) {
var result = [];
var item;
for (var idx = 0; idx < data.length; idx++) {
item = data[idx];
if (!("field" in item && "value" in item && "items" in item)) break;
if (item.hasSubgroups) result = result.concat(groupFooters(item.items));
result.push(item.aggregates);
}
return result;
}
function showColumnCells(rows, columnIndex) {
var idx = 0, length = rows.length, cell, row, columns;
for (; idx < length; idx += 1) {
row = rows.eq(idx);
if (row.is(".k-grouping-row,.k-detail-row")) {
cell = row.children(":not(.k-group-cell):first,.k-detail-cell").last();
cell.attr("colspan", parseInt(cell.attr("colspan"), 10) + 1);
} else {
if (row.hasClass("k-grid-edit-row") && (cell = row.children(".k-edit-container")[0])) {
cell = $(cell);
cell.attr("colspan", parseInt(cell.attr("colspan"), 10) + 1);
normalizeCols(cell.find(">form>table"), visibleColumns(columns), false, 0);
row = cell.find(TR).first();
}
setCellVisibility(row[0].cells, columnIndex, true);
}
}
}
function updateColspan(toAdd, toRemove, num) {
num = num || 1;
var item, idx, length;
for (idx = 0, length = toAdd.length; idx < length; idx++) {
item = toAdd.eq(idx).children(":not([hidden])").last();
item.attr("colspan", parseInt(item.attr("colspan"), 10) + num);
item = toRemove.eq(idx).children(":not([hidden])").last();
item.attr("colspan", parseInt(item.attr("colspan"), 10) - num);
}
}
function tableWidth(table) {
var idx, length, width = 0;
var cols = table.find(">colgroup>col");
for (idx = 0, length = cols.length; idx < length; idx += 1) width += parseInt(cols[idx].style.width, 10);
return width;
}
function getDefaultAIRequestConfig(prompt, columns) {
return {
"role": "user",
"contents": [{
"$type": "text",
"text": prompt
}],
"columns": columns.map((col) => {
let colType;
if (col.selectable) colType = "checkbox";
else if (col.command) colType = "command";
else if (col.draggable) colType = "draggable";
const colConfig = {
...col,
"id": `${col.uid}`
};
if (colType) colConfig.type = colType;
return colConfig;
})
};
}
function aiPromptDefaultOutputGetter(response, messages, isRowSelection) {
const commands = response?.commands || [];
const messagesSeparator = "• ";
const isError = response?.status;
const outputMessages = commands.map((cmd, i) => {
const selectionProtectedMessage = messagesSeparator + messages.invalidSelection;
if (cmd?.type === "GridSelect") {
const hasCells = Object.keys(cmd?.select.cells).length;
if (hasCells && isRowSelection && cmd?.select?.filters.length) {
cmd.skipCommand = true;
return selectionProtectedMessage;
}
if (!hasCells && !isRowSelection && cmd?.select?.filters.length) {
cmd.skipCommand = true;
return selectionProtectedMessage;
}
}
return cmd?.message ? messagesSeparator + cmd?.message : "";
});
let output = [];
if (isError) output.push(messages.error + ` ${response.status} ${response.statusText}`);
else if (response && response.message) output.push(response.message);
else {
output.push(messages.success);
if (outputMessages) output.push(...outputMessages);
}
return output.join("/n");
}
function prepareAICommands(commands, multiple) {
const mergedCommands = [];
let lastUniqueCommand;
if (!commands) return;
for (let i = 0; i < commands.length; i++) {
const command = commands[i];
if (!command || !command.type) continue;
const key = supportedAIDataSourceCommands[command.type];
if (key === "filter" || key === "sort" && !multiple) {
mergedCommands.push(command);
continue;
}
if (key) {
if (lastUniqueCommand && lastUniqueCommand.type !== command.type) {
mergedCommands.push(lastUniqueCommand);
lastUniqueCommand = null;
}
if (!lastUniqueCommand) lastUniqueCommand = command;
else if (command[key] !== undefined) {
if (!Array.isArray(lastUniqueCommand[key])) lastUniqueCommand[key] = [lastUniqueCommand[key]];
lastUniqueCommand[key].push(command[key]);
lastUniqueCommand = {
...lastUniqueCommand,
[key]: lastUniqueCommand[key]
};
}
} else {
if (lastUniqueCommand) {
mergedCommands.push(lastUniqueCommand);
lastUniqueCommand = null;
}
mergedCommands.push(command);
}
}
if (lastUniqueCommand) mergedCommands.push(lastUniqueCommand);
return mergedCommands;
}
function handleAIResponseOutput(output, ai, skeletonID) {
if (!ai._requestInProgress || !ai.options.service) return;
const outputObjects = ai.outputObjects;
ai.updatePromptOutputContent(output.output, skeletonID);
ai.element.find("[data-id='" + skeletonID + "']").attr("data-id", output.outputId);
const value = outputObjects.get(skeletonID);
outputObjects.delete(skeletonID);
if (value) {
value.id = output.outputId;
value.data.id = output.outputId;
outputObjects.set(output.outputId, value);
}
ai.promptOutputs = ai.promptOutputs.map((item) => {
if (item.id === skeletonID) item.id = output.outputId;
return item;
});
ai.stopStreaming();
ai._requestInProgress = false;
}
function processAIOutputMessage(message) {
const startIndex = message.indexOf("Column '");
const valueStart = startIndex + 8;
const endIndex = message.indexOf("'", valueStart);
return {
uid: message.substring(valueStart, endIndex),
originalText: message.substring(startIndex, endIndex + 1)
};
}
const aiPromptOutputTemplate = (message, messages, columns) => {
const messageData = processAIOutputMessage(message);
const col = columns.find((c) => c.uid === messageData?.uid);
if (col) {
const originalText = messageData?.originalText;
const replacementText = `Column '${col.title || col.field}'`;
message = message.replace(originalText, replacementText);
}
if (message.includes(messages.error)) return `<p class="k-text-error">${kendo.htmlEncode(message)}</p>`;
else return `<div class="k-card-text">${kendo.htmlEncode(message)}</div>`;
};
var Grid = kendo.ui.DataBoundWidget.extend({
init: function(element, options, events) {
var that = this;
options = isArray(options) ? { dataSource: options } : options;
Widget.fn.init.call(that, element, options);
if (events) that._events = events;
isRtl = kendo.support.isRtl(element);
CARET_ALT_RIGHT = isRtl ? CARET_ALT_LEFT : CARET_ALT_RIGHT_CACHE;
that._element();
that._ariaId();
that._columns($.extend(true, [], that.options.columns));
that._bindMediaQueries();
if (that._foreignKeyPromises) $.when.apply(null, that._foreignKeyPromises).then(function() {
that._foreignKeyPromises = null;
that._continueInit();
});
else that._continueInit();
},
_continueInit: function() {
var that = this;
that._dataSource();
that._stickyColumns();
that._tbody();
that._thead();
that._rowResizing();
that._groupable();
that._toolbar();
that._initToolbarItemsPopups();
that._ai();
that._pageable();
if (!that._isPinnable()) that._setContentHeight();
that._scrollableHeightApplied = true;
that._templates();
that._navigatable();
that._initSelectableAggregates();
that._selectable();
that._initPinnedRowSelection();
that._initPinnedRowEditing();
that._statusBar();
that._clipboard();
that._paste();
that._details();
that._editable();
that._attachCustomCommandsEvent();
that._adaptiveColumns();
that._minScreenSupport();
if (that.options.autoBind) that.dataSource.fetch();
else {
that._group = that._groups() > 0;
that._footer();
}
that._setInitialRtlScrollPosition();
if (that.options.contextMenu) that._initContextMenu();
if (that.lockedContent) {
that.wrapper.addClass("k-grid-lockedcolumns");
that._resizeHandler = function() {
that.resize();
};
$(window).on("resize.kendoGrid", that._resizeHandler);
}
that._initLoader();
kendo.notify(that);
if (that._showWatermarkOverlay) that._showWatermarkOverlay(that.wrapper[0]);
},
events: [
CHANGE,
CHANGING,
"dataBinding",
"cancel",
DATABOUND,
DETAILEXPAND,
DETAILCOLLAPSE,
DETAILINIT,
FILTERMENUINIT,
FILTERMENUOPEN,
COLUMNMENUINIT,
COLUMNMENUOPEN,
EDIT,
BEFOREEDIT,
SAVE,
REMOVE,
SAVECHANGES,
CELLCLOSE,
ROWRESIZE,
COLUMNRESIZE,
COLUMNREORDER,
COLUMNSHOW,
COLUMNHIDE,
COLUMNLOCK,
COLUMNUNLOCK,
COLUMNSTICK,
COLUMNUNSTICK,
ROWREORDER,
ROWPIN,
ROWUNPIN,
NAVIGATE,
PASTE,
"page",
"sort",
"filter",
"group",
"groupExpand",
"groupCollapse",
"kendoKeydown"
],
setDataSource: function(dataSource) {
var that = this;
var scrollable = that.options.scrollable;
var scrollableContent;
that.options.dataSource = dataSource;
that._dataSource();
that._pageable();
that._thead();
that._rowResizing();
if (scrollable) if (scrollable.virtual) {
scrollableContent = that.content.find(">.k-virtual-scrollable-wrap");
kendo.scrollLeft(scrollableContent, leftMostPosition(scrollableContent, isRtl));
} else {
scrollableContent = that.tbody;
kendo.scrollLeft(that.content, leftMostPosition(scrollableContent, isRtl));
}
if (that.options.groupable) that._groupable();
if (that.virtualScrollable) that.virtualScrollable.setDataSource(that.options.dataSource);
if (that.options.navigatable) that._navigatable();
if (that.options.selectable) {
that._selectable();
that._initPinnedRowSelection();
}
that._initPinnedRowEditing();
if (that.options.autoBind) that.dataSource.fetch();
else that._footer();
},
options: {
name: "Grid",
adaptiveMode: "none",
ai: null,
columns: [],
toolbar: null,
autoBind: true,
filterable: false,
scrollable: true,
sortable: false,
selectable: false,
allowCopy: false,
allowPaste: false,
navigatable: false,
pageable: false,
persistSelection: false,
editable: false,
encodeTitles: false,
groupable: false,
rowTemplate: "",
altRowTemplate: "",
pinnedRowTemplate: null,
statusBarTemplate: null,
search: false,
noRecords: false,
dataSource: {},
height: null,
resizable: false,
reorderable: false,
columnMenu: false,
detailTemplate: null,
contextMenu: false,
pinnable: false,
columnResizeHandleWidth: 3,
size: undefined,
mobile: "",
loaderType: "loadingPanel",
dataLayoutMode: "columns",
stackedLayoutSettings: {},
messages: {
loader: {
loading: "Loading...",
exporting: "Exporting..."
},
editable: {
cancelDelete: CANCELDELETE,
confirmation: DELETECONFIRM,
confirmDelete: CONFIRMDELETE
},
commands: {
create: defaultCommands.create.text,
cancel: defaultCommands.cancel.text,
save: defaultCommands.save.text,
destroy: defaultCommands.destroy.text,
add: "Add new record",
edit: defaultCommands.edit.text,
update: defaultCommands.update.text,
canceledit: defaultCommands.canceledit.text,
excel: defaultCommands.excel.text,
pdf: defaultCommands.pdf.text,
csv: defaultCommands.csv.text,
search: defaultCommands.search.text,
columns: defaultCommands.columns.text,
select: "Select",
selectall: defaultCommands.selectall.text,
sort: defaultCommands.sort.text,
filter: defaultCommands.filter.text,
group: defaultCommands.group.text,
columnchooser: defaultCommands.columnchooser.text,
selectRow: "Select Row",
selectAllRows: "All rows",
clearSelection: "Clear selection",
copySelection: "Copy selection",
copySelectionNoHeaders: "Copy selection (No Headers)",
paste: "Paste (use CTRL/⌘ + V)",
reorderRow: "Reorder row",
reorderRowUp: "Up",
reorderRowDown: "Down",
reorderRowTop: "Top",
reorderRowBottom: "Bottom",
exportPdf: "Export to PDF",
exportExcel: "Export to Excel",
exportCSV: "Export to CSV",
exportToCSVAll: "All",
exportToCSVSelection: "Selection",
exportToCSVSelectionNoHeaders: "Selection (No Headers)",
exportToExcelAll: "All",
exportToExcelSelection: "Selection",
exportToExcelSelectionNoHeaders: "Selection (No Headers)",
sortAsc: "Sort Ascending",
sortDesc: "Sort Descending",
moveGroupPrevious: "Move previous",
moveGroupNext: "Move next",
pinRow: "Pin row",
pinTop: "Pin row to top",
pinBottom: "Pin row to bottom",
unpin: "Unpin row"
},
details: {
expand: "Expand Details",
collapse: "Collapse Details"
},
ai: {
outputPlaceholder: "No AI output available",
success: "Data is:",
error: "Operation is not successful. Error:",
invalidSelection: "This selection mode is not currently enabled. Please enable the appropriate selection option in the grid configuration.",
promptPlaceholder: "Enter your AI prompt here..."
},
noRecords: NORECORDS,
expandCollapseColumnHeader: "",
groupHeader: "Press ctrl + space to group",
ungroupHeader: "Press ctrl + space to ungroup",
itemsSelected: "items selected",
dragHandleLabel: "Drag row",
toolbarLabel: "grid toolbar",
groupingHeaderLabel: "grid grouping header",
filterCellTitle: "filter cell",
clearButtons: {
clearFiltering: "Clear All Filters",
clearSorting: "Clear Sorting",
clearGrouping: "Clear Grouping",
columnChooserReset: "Reset"
},
applyButtons: {
applySorting: "Done",
applyGrouping: "Done",
columnChooserApply: "Apply"
}
},
width: null
},
destroy: function() {
var that = this, element, reorderableInstance;
if (that.smallMQL) that.smallMQL.destroy();
if (that.mediumMQL) that.mediumMQL.destroy();
if (that.largeMQL) that.largeMQL.destroy();
that._destroyColumnAttachments();
that._unbindToolbarTools();
that._destroyStickyGroups();
that._destroyPinnedRows();
Widget.fn.destroy.call(that);
if (this._navigatableTables) {
this._navigatableTables.off(NS);
this._navigatableTables = null;
this._headertables = null;
}
if (that._resizeHandler) $(window).off("resize.kendoGrid", that._resizeHandler);
if (that._aiAssistant) {
that._aiAssistant?.destroy();
that._aiAssistant = null;
}
if (that._aiAssistantWindow) {
that._aiAssistantWindow?.destroy();
that._aiAssistantWindow = null;
}
if (that.pager && that.pager.element) that.pager.destroy();
if (that._timer) clearTimeout(that._timer);
if (that._progressTimeOut) clearTimeout(that._progressTimeOut);
if (that._collapseGroupsTimeOut) clearTimeout(that._collapseGroupsTimeOut);
if (that._endlessFetchTimeOut) clearTimeout(that._endlessFetchTimeOut);
that.pager = null;
that._destroyGroupable();
reorderableInstance = that.wrapper.data("kendoReorderable");
if (reorderableInstance) reorderableInstance.destroy();
reorderableInstance = that.tbody ? that.tbody.data("kendoReorderable") : null;
if (reorderableInstance) reorderableInstance.destroy();
if (that.allowPaste) {
(that.content || that.table).off("paste.kendoGrid", that.pasteHandler);
that.unbind(that.pasteHandler);
}
if (that.pasteActionsDropDownList) {
that.pasteActionsDropDownList.destroy();
that.pasteActionsDropDownList = null;
}
if (that.selectable && that.selectable.element) {
that.selectable.destroy();
that.clearArea();
that._selectedIds = null;
if (that.copyHandler) {
that.wrapper.off("keydown", that.copyHandler);
that.unbind(that.copyHandler);
}
if (that.updateClipBoardState) {
that.unbind(that.updateClipBoardState);
that.updateClipBoardState = null;
}
if (that.clearAreaHandler) that.wrapper.off("keyup", that.clearAreaHandler);
}
that.selectable = null;
that._selectableAggregatesOptions = null;
if (that.resizable) {
that.resizable.destroy();
if (that._resizeUserEvents) {
if (that._resizeHandleDocumentClickHandler) $(document).off("click", that._resizeHandleDocumentClickHandler);
that._resizeUserEvents.destroy();
that._resizeUserEvents = null;
}
that.resizable = null;
}
that._destroyRowResizing();
that._destroyVirtualScrollable();
if (that.editableUserEvents) {
that.editableUserEvents.destroy();
that.editableUserEvents = null;
}
if (that._lockedContentUserEvents) {
that._lockedContentUserEvents.destroy();
that._lockedContentUserEvents = null;
}
that._destroyEditable();
if (that.dataSource) {
that.dataSource.unbind(CHANGE, that._refreshHandler).unbind(PROGRESS, that._progressHandler).unbind(ERROR, that._errorHandler).unbind(SORT, that._clearSortClasses);
that._refreshHandler = that._progressHandler = that._errorHandler = that._sortHandler = null;
}
element = that.element.add(that.wrapper).add(that.table).add(that.thead).add(that.wrapper.find(">.k-grid-toolbar"));
if (that.content) element = element.add(that.content).add(that.content.find(">.k-virtual-scrollable-wrap"));
if (that.scrollables && that.scrollables.first()) element = element.add(that.scrollables.first());
if (that.lockedHeader) that._removeLockedContainers();
if (that.pane) that.pane.destroy();
if (that._isMobile) {
that.wrapper.off("transitionend.kendoGrid");
that.wrapper.off("contextmenu.kendoGrid");
}
if (that.minScreenResizeHandler) $(window).off("resize", that.minScreenResizeHandler);
that._detachColumnMediaResizeHandler();
if (that._draggableInstance && that._draggableInstance.element) that._draggableInstance.destroy();
that._draggableInstance = null;
if (that._draggableRowsInstance && that._draggableRowsInstance.element) that._draggableRowsInstance.destroy();
if (that.tbodyContextMenu) that.tbodyContextMenu.destroy();
if (that.theadContextMenu) that.theadContextMenu.destroy();
if (that.loader) that.loader.destroy();
that._draggableRowsInstance = null;
element.off(NS);
element[0].kendoBindingTarget = null;
kendo.destroy(that.wrapper);
that.rowTemplate = that.altRowTemplate = that.lockedRowTemplate = that.lockedAltRowTemplate = that.detailTemplate = that.footerTemplate = that.groupFooterTemplate = that.lockedGroupFooterTemplate = that.noRecordsTemplate = null;
that.scrollables = that.thead = that.tbody = that.element = that.table = that.content = that.statusBar = that.footer = that.wrapper = that.lockedTable = that.lockedContent = that.lockedHeader = that.lockedFooter = that._groupableClickHandler = that._groupRows = that._setContentWidthHandler = that.loaderOverlay = that.wrapperClone = null;
},
getOptions: function() {
var options = this.options;
options.dataSource = null;
var result = extend(true, {}, this.options);
result.columns = kendo.deepExtend([], this.columns);
var dataSource = this.dataSource;
var initialData = dataSource.options.data && dataSource._data;
dataSource.options.data = null;
result.dataSource = $.extend(true, {}, dataSource.options);
dataSource.options.data = initialData;
result.dataSource.data = initialData;
result.dataSource.page = dataSource.page();
result.dataSource.filter = $.extend(true, {}, dataSource.filter());
result.dataSource.pageSize = dataSource.pageSize();
result.dataSource.sort = dataSource.sort();
result.dataSource.group = dataSource.group();
result.dataSource.aggregate = dataSource.aggregate();
if (result.dataSource.transport) result.dataSource.transport.dataSource = null;
if (result.pageable && result.pageable.pageSize) result.pageable.pageSize = dataSource.pageSize();
return result;
},
setOptions: function(options) {
var currentOptions = this.getOptions(), element = this.element;
if (currentOptions.size) {
const size = kendo.getValidCssClass("k-grid-", "size", currentOptions.size);
element.removeClass(size);
}
kendo.deepExtend(currentOptions, options);
if (!options.dataSource) currentOptions.dataSource = this.dataSource;
else if (options.dataSource.filter) currentOptions.dataSource.filter = options.dataSource.filter;
var wrapper = this.wrapper;
var events = this._events;
this.destroy();
this._footerWidth = null;
this.options = null;
if (this._isMobile) {
var mobileWrapper = wrapper.closest(kendo.roleSelector("pane")).parent();
mobileWrapper.after(wrapper);
mobileWrapper.remove();
wrapper.removeClass("k-grid-mobile");
}
if (wrapper[0] !== element[0]) {
wrapper.before(element);
wrapper.remove();
}
element.empty();
this.init(element, currentOptions, events);
this._setEvents(currentOptions);
},
items: function() {
if (this.lockedContent) return this._items(this.tbody).add(this._items(this.lockedTable.children("tbody")));
else return this._items(this.tbody);
},
_items: function(container, includeGroupRows) {
return container.children().filter(function() {
var tr = $(this);
return (includeGroupRows ? !tr.hasClass("k-detail-row") : !tr.hasClass(GROUPING_ROW)) && !tr.hasClass("k-detail-row") && !tr.hasClass("k-group-footer");
});
},
dataItems: function() {
var dataItems = kendo.ui.DataBoundWidget.fn.dataItems.call(this);
if (this.lockedContent) {
var n = dataItems.length, tmp = new Array(2 * n);
for (var i = n; --i >= 0;) tmp[i] = tmp[i + n] = dataItems[i];
dataItems = tmp;
}
return dataItems;
},
_destroyColumnAttachments: function() {
var that = this;
that.resizeHandle = null;
if (!that.thead) return;
that.thead.add(that.lockedHeader).find("th").each(function() {
var th = $(this), filterMenu = th.data("kendoFilterMenu"), sortable = th.data("kendoColumnSorter"), columnMenu = th.data("kendoColumnMenu");
if (filterMenu) filterMenu.destroy();
if (sortable) sortable.destroy();
if (columnMenu) columnMenu.destroy();
});
},
_setInitialRtlScrollPosition: function() {
const that = this;
if (isRtl && that.scrollables) kendo.scrollLeft(that.scrollables, 0);
},
_attachCustomCommandsEvent: function() {
var that = this, columns = leafColumns(that.columns || []), command, idx, length;
for (idx = 0, length = columns.length; idx < length; idx++) {
command = columns[idx].command;
if (command) attachCustomCommandEvent(that, that.wrapper, command);
}
},
_bindMediaQueries: function() {
const that = this;
if (that.options.adaptiveMode === "auto") {
that.largeMQL = kendo.mediaQuery("large");
that.mediumMQL = kendo.mediaQuery("medium");
that.smallMQL = kendo.mediaQuery("small");
const handler = (fullscreen, handler) => {
if (that._editMode() !== "popup") return;
const checkActionSheet = fullscreen === true || fullscreen === false;
let popup;
if (that._editContainer) popup = that._editContainer && that._editContainer.data(handler);
if (!popup) {
const reverseHandler = handler === "kendoActionSheet" ? "kendoWindow" : "kendoActionSheet";
popup = that._editContainer && that._editContainer.data(reverseHandler);
}
if (checkActionSheet) {
if (popup && popup.fullscreen && popup.visible()) {
that._showAdaptiveView = true;
popup.fullscreen(fullscreen);
} else if (popup) {
that._showAdaptiveView = false;
that._destroyEditable(true);
}
} else if (popup && popup.fullscreen) popup.close();
};
that.smallMQL.onEnter(() => {
handler(true, "kendoActionSheet");
});
that.mediumMQL.onEnter(() => {
handler(false, "kendoActionSheet");
});
that.largeMQL.onEnter(() => {
handler(null, "kendoWindow");
});
} else {
that.smallMQL && that.smallMQL.destroy();
that.mediumMQL && that.mediumMQL.destroy();
that.largeMQL && that.largeMQL.destroy();
that._showAdaptiveView = false;
}
},
_aria: function() {
var wrapper = this.wrapper, gridRole = this._hasDetails() ? "treegrid" : this.options.navigatable ? "grid" : null, table = this.table, toolbar = wrapper.find(".k-grid-toolbar"), groupingHeader = wrapper.find(".k-grouping-header"), gridId = this._ariaGridId(), tableTabindex = table.attr(TABINDEX), tbodyId, headerGroupId, footerGroupId, tableOwned, stacked = this._isStackedMode(), numberOfFixedRows = !stacked && this.thead.find(TR).length + this.wrapper.find(".k-grid-footer-wrap table tr").length, trailingColumns = this._trailingColumns(), virtual = this.virtualScroll, pageable = this.options.pageable, rowsCount;
table.attr(TABINDEX, tableTabindex >= 0 ? tableTabindex : 0);
if (gridRole) table.attr(ROLE, gridRole);
const tbody = table.find("tbody");
const thead = table.find("thead");
const tfoot = table.find("tfoot");
const tr = table.find(TR);
if (tbody.find(TR).length > 0) tbody.attr(ROLE, ROWGROUP);
if (thead.find(`${TR} ${TH}`).length > 0) thead.attr(ROLE, ROWGROUP);
if (tfoot.find(TR).length > 0) tfoot.attr(ROLE, ROWGROUP);
if (tr.children().length > 0) tr.attr(ROLE, ROW);
table.find("th").attr(ROLE, COLUMNHEADER);
table.find("td").attr(ROLE, GRIDCELL);
if (pageable && this.dataSource.totalPages() > 1 || virtual && virtual.rows) {
if (this._groups() > 0) rowsCount = -1;
else if (this._hasDetails()) rowsCount = numberOfFixedRows + this.dataSource.total() * 2;
else rowsCount = numberOfFixedRows + this.dataSource.total();
table.attr(ARIA_ROWCOUNT, rowsCount);
} else if (this._hasDetails()) {
if (this._groups() > 0) rowsCount = -1;
else rowsCount = numberOfFixedRows + this.dataSource.total() * 2;
table.attr(ARIA_ROWCOUNT, rowsCount);
}
if (rowsCount && rowsCount > 0) this._ariaRowIndex();
if (!stacked && (virtual && virtual.columns || !table.attr(ARIA_COLCOUNT) && (table.find("td:not([group-header-spanned-hidden]):hidden").length > 0 || wrapper.find(".k-grid-content-locked td:not([group-header-spanned-hidden]):hidden").length > 0))) {
table.attr(ARIA_COLCOUNT, trailingColumns + leafColumns(this.columns).length);
this._ariaColumnIndex();
}
if (this.pager) this.pager.element.attr(ARIA_CONTROLS, gridId);
toolbar.attr({
role: "toolbar",
"aria-label": this.options.messages.toolbarLabel,
"aria-controls": gridId
});
groupingHeader.attr({
role: "toolbar",
"aria-label": this.options.messages.groupingHeaderLabel,
"aria-controls": gridId
});
headerGroupId = !stacked ? this._ariaHeaderFooter("header", "thead", "th, td", COLUMNHEADER) : "";
footerGroupId = this._ariaHeaderFooter("footer", "tfoot", "td", GRIDCELL);
if (!stacked && wrapper.find(".k-grid-content-locked").length > 0) this._ariaLockedContent();
if (!!headerGroupId || !!footerGroupId) {
tbodyId = this.tbody.attr(ID) || kendo.guid();
tableOwned = [
headerGroupId,
tbodyId,
footerGroupId
].join(" ");
this.tbody.attr(ID, tbodyId);
table.attr(ARIA_OWNS, tableOwned);
}
if (this.options.groupable) this._ariaGroupTitles();
},
_ariaColumnIndex: function() {
var trailingColumns = this._trailingColumns(), dataVirtual = this.tbody?.find(">tr").last().find("> td[data-virtual]"), headerRows = this.thead?.find(">tr").not(".k-filter-row"), lockedHeaderRows = this.wrapper?.find(".k-grid-header-locked thead > tr").not(".k-filter-row"), firstIndex = Number.MAX_VALUE, lastIndex = 0, lockedLastIndex = 0, previousVirtual = 0, nextVirtual = 0, previousIndex, i, cells, dataIndex, cellsIndex, eachHeaderCell = function(j, cell) {
var current = cell.getAttribute("data-index"), currentIndex = Number(current), lockedParent = $(cell).closest(".k-grid-header-locked");
if (lockedParent.length === 0 && currentIndex < firstIndex) firstIndex = currentIndex;
if (lockedParent.length > 0 && lockedLastIndex < currentIndex) lockedLastIndex = currentIndex;
if (lockedParent.length === 0 && lastIndex < currentIndex) lastIndex = currentIndex;
if (current !== null) {
cell.setAttribute(ARIA_COLINDEX, Number(currentIndex) + 1);
previousIndex = Number(currentIndex) + 1 + cell.getAttribute("colspan");
} else {
cell.setAttribute(ARIA_COLINDEX, previousIndex + 1);
previousIndex = previousIndex + cell.getAttribute("colspan");
}
};
if (dataVirtual.length === 2) {
previousVirtual = Number(dataVirtual[0].getAttribute("colspan"));
nextVirtual = Number(dataVirtual[1].getAttribute("colspan"));
} else if (dataVirtual.length === 1 && dataVirtual.prev().length === 0) previousVirtual = Number(dataVirtual[0].getAttribute("colspan"));
else if (dataVirtual.length === 1 && dataVirtual.prev().length === 1) nextVirtual = Number(dataVirtual[0].getAttribute("colspan"));
for (i = 0; i < lockedHeaderRows.length; i++) {
previousIndex = 0;
lockedHeaderRows.eq(i).find("th").each(eachHeaderCell);
}
for (i = 0; i < headerRows.length; i++) {
previousIndex = 0;
headerRows.eq(i).find("th").each(eachHeaderCell);
}
for (i = 0; i <= lockedLastIndex; i++) {
dataIndex = i + trailingColumns;
cells = this.wrapper.find(".k-grid-content-locked tbody > tr > td:nth-child(" + (i + 1) + ")");
cells.attr(ARIA_COLINDEX, dataIndex + 1);
}
for (i = previousVirtual; i <= lastIndex - firstIndex - nextVirtual; i++) {
if (previousVirtual === 0) cellsIndex = i + 1;
else cellsIndex = i - previousVirtual + 2;
dataIndex = firstIndex + i + trailingColumns;
cells = this.tbody.find("> tr > td:nth-child(" + cellsIndex + ")");
cells.attr(ARIA_COLINDEX, dataIndex + 1);
}
},
_ariaGroupTitles: function() {
var that = this, groups = that.dataSource.group(), ths = that.wrapper.find(".k-grid-header th");
ths.each(function(i, el) {
if (el.getAttribute("title") === that.options.messages.ungroupHeader) el.setAttribute("title", that.options.messages.groupHeader);
});
if (groups && groups.length > 0) groups.forEach(function(group) {
var field = group.field, el = ths.filter("[" + kendo.attr("field") + "='" + field + "']");
if (el.attr("title") === that.options.messages.groupHeader) el.attr("title", that.options.messages.ungroupHeader);
});
},
_ariaHeaderFooter: function(type, group, el, role) {
var that = this, wrapper = that.wrapper, table = wrapper.find(".k-grid-" + type + " .k-grid-" + type + "-wrap table"), lockedTable = wrapper.find(".k-grid-" + type + " .k-grid-" + type + "-locked table"), groupId = "", rowGroup;
if (table.length > 0) {
rowGroup = table.find(group + ", tbody");
groupId = rowGroup.attr(ID) || kendo.guid();
table.attr(ROLE, NONE);
const tr = table.find(TR);
if (tr.children().length > 0) {
tr.attr(ROLE, ROW);
rowGroup.attr(ROLE, ROWGROUP);
}
table.find(el).attr(ROLE, role);
rowGroup.attr({ id: groupId });
}
if (lockedTable.length > 0) that._ariaLocked(type, group, el, role);
lockedTable.find("td").attr(ROLE, GRIDCELL);
table.find("td").attr(ROLE, GRIDCELL);
return groupId;
},
_ariaId: function() {
var id = this.element.attr(ID) || "aria";
if (id) this._cellId = id + "_active_cell";
},
_ariaGridId: function() {
var table = this.table, gridId = table.attr(ID);
if (!gridId) {
gridId = kendo.guid();
table.attr(ID, gridId);
}
return gridId;
},
_ariaLocked: function(type, group, el, role) {
var that = this, wrapper = that.wrapper, table = wrapper.find(".k-grid-" + type + " .k-grid-" + type + "-wrap table"), lockedTable = wrapper.find(".k-grid-" + type + " .k-grid-" + type + "-locked table"), rows = table.find(TR), lockedRows = lockedTable.find(TR);
lockedTable.attr(ROLE, NONE);
lockedTable.find(group + ", tbody").attr(ROLE, NONE);
lockedRows.attr(ROLE, NONE);
lockedTable.find(el).attr(ROLE, role);
rows.each(function(i, row) {
var ownedCells = [];
ownedCells = that._cellsIds(lockedRows.eq(i).find(el), "locked_" + type, i);
ownedCells = ownedCells.concat(that._cellsIds($(row).find(el), type, i));
row.setAttribute(ARIA_OWNS, ownedCells.join(" "));
});
},
_ariaLockedContent: function() {
var that = this, tableRows = that.table.find(TR), lockedTable = that.wrapper.find(".k-grid-content-locked table"), lockedRows = lockedTable.find(TR);
lockedTable.attr(ROLE, NONE);
lockedTable.find("tbody").attr(ROLE, NONE);
lockedRows.attr(ROLE, NONE);
lockedTable.find("td").attr(ROLE, GRIDCELL);
tableRows.each(function(i, row) {
var ownedCells = [];
ownedCells = that._cellsIds(lockedRows.eq(i).find("td"), "locked_datacell", i);
ownedCells = ownedCells.concat(that._cellsIds($(row).find("td"), "datacell", i));
row.setAttribute(ARIA_OWNS, ownedCells.join(" "));
});
},
_ariaAddHiddenColIndex: function() {
var virtualScroll = this.virtualScroll || {}, columns = this.columns, table = this.table, leafColsCount = leafColumns(columns).length;
if (!virtualScroll.columns && !table.attr(ARIA_COLCOUNT)) {
this._ariaColumnIndex();
table.attr(ARIA_COLCOUNT, leafColsCount);
}
},
_ariaRemoveHiddenColIndex: function() {
var virtualScroll = this.virtualScroll || {}, columns = this.columns, leafColsCount = leafColumns(columns).length;
if (!virtualScroll.columns && leafColsCount === visibleLeafColumns(this.columns).length) {
this.wrapper.find("td, th").removeAttr(ARIA_COLINDEX);
this.table.removeAttr(ARIA_COLCOUNT);
}
},
_ariaRowIndex: function() {
var headerRows = !this._isStackedMode() && this.thead.find(">tr"), numberOfHeaderRows = headerRows ? headerRows.length : 0, bodyRows = this.tbody.find(">tr"), footerRows = this.wrapper.find(".k-grid-footer-wrap tfoot > tr"), totalNumberOfItems = this.dataSource.total(), previousItems = this.dataSource.skip() || 0, currentIndex = 1, previousMaster = false, i, currentRow;
if (this._hasDetails()) {
totalNumberOfItems = totalNumberOfItems * 2;
previousItems = previousItems * 2;
}
for (i = 0; i < numberOfHeaderRows; i++) headerRows.eq(i).attr(ARIA_ROWINDEX, currentIndex + i);
currentIndex = numberOfHeaderRows + previousItems;
for (i = 0; i < bodyRows.length; i++) {
currentRow = bodyRows.eq(i);
if (this._hasDetails() && currentRow.hasClass("k-master-row")) {
if (previousMaster) currentIndex = currentIndex + 2;
else currentIndex = currentIndex + 1;
previousMaster = true;
} else {
currentIndex = currentIndex + 1;
previousMaster = false;
}
currentRow.attr(ARIA_ROWINDEX, currentIndex);
}
currentIndex = numberOfHeaderRows + totalNumberOfItems + 1;
for (i = 0; i < footerRows.length; i++) footerRows.eq(i).attr(ARIA_ROWINDEX, currentIndex + i);
},
_cellsIds: function(elements, prefix, i) {
var ownedCells = [], gridId = this._ariaGridId();
elements.each(function(j, cell) {
var id = cell.getAttribute(ID) || gridId + "_" + prefix + "_" + i + "_" + j;
cell.setAttribute(ID, id);
ownedCells.push(id);
});
return ownedCells;
},
_trailingColumns: function() {
return this._groups() + (this._hasDetails() ? 1 : 0);
},
_element: function() {
const that = this;
let table = that.element;
if (!table.is("table")) {
if (that.options.scrollable) table = that.element.find("> .k-grid-content > table");
else table = that.element.children("table");
if (!table.length) table = $("<table />").appendTo(that.element);
}
table.addClass("k-grid-table k-table");
table.addClass(kendo.getValidCssClass("k-table-", "size", that.options.size));
that.table = table;
that._wrapper();
},
_createResizeHandle: function(container, th) {
var that = this;
var indicatorWidth = that.options.columnResizeHandleWidth;
var scrollable = that.options.scrollable;
var resizeHandle = that.resizeHandle;
var halfResizeHandle = indicatorWidth * 3 / 2;
var rtlCorrection = 0;
var headerWrap;
var ieCorrection;
var webkitCorrection;
var firefoxCorrection;
var leftMargin;
var leftBorderWidth;
var scrollLeft;
var left;
var top;
if (resizeHandle && that.lockedContent && resizeHandle.data("th")[0] !== th[0]) {
resizeHandle.off(NS).remove();
resizeHandle = null;
}
if (!resizeHandle) {
resizeHandle = that.resizeHandle = $("<div class=\"k-resize-handle\"><div class=\"k-resize-handle-inner\"></div></div>");
container.append(resizeHandle);
}
scrollLeft = kendo.scrollLeft(container);
if (isRtl && (browser.mozilla || browser.webkit && browser.version >= 85)) scrollLeft = scrollLeft * -1;
leftBorderWidth = parseFloat(container.css("borderLeftWidth"));
left = th.offset().left + scrollLeft - parseFloat(th.css("marginLeft")) - (container.offset().left + leftBorderWidth);
if (!isRtl) left += th[0].offsetWidth;
else if (scrollable) {
rtlCorrection = left <= scrollLeft ? halfResizeHandle : 0;
headerWrap = th.closest(".k-grid-header-wrap, .k-grid-header-locked");
headerWrap[0].scrollWidth - headerWrap[0].offsetWidth;
leftMargin = parseFloat(headerWrap.css("marginLeft"));
ieCorrection = browser.msie ? 2 * kendo.scrollLeft(headerWrap) + leftBorderWidth - leftMargin - rtlCorrection : 0;
webkitCorrection = -rtlCorrection;
firefoxCorrection = browser.mozilla ? leftBorderWidth - leftMargin - rtlCorrection : 0;
left -= webkitCorrection + firefoxCorrection + ieCorrection;
}
top = th.offset().top - parseFloat(th.css("marginTop")) - (container.offset().top + parseFloat(container.css("borderTopWidth")));
resizeHandle.css({
top,
left: left - halfResizeHandle,
height: outerHeight(th),
width: indicatorWidth * 3 - rtlCorrection
}).data("th", th).show();
resizeHandle.off("dblclick.kendoGrid").on("dblclick.kendoGrid", function() {
that._autoFitLeafColumn(parseInt(th.attr(kendo.attr("index")), 10));
});
},
_positionColumnResizeHandle: function() {
var that = this, lockedHead = that.lockedHeader ? that.lockedHeader.find("thead").first() : $();
if (that.thead) that.thead.add(lockedHead).on("mousemove.kendoGrid", "tr:not(.k-filter-row) > th:not([data-resizable=false])", function(e) {
var button = typeof e.buttons !== "undefined" ? e.buttons : e.which || e.button;
var th = $(this);
if (th.hasClass("k-group-cell") || th.hasClass("k-hierarchy-cell")) return;
if (typeof button !== "undefined" && button !== 0) return;
if (th[0].hasAttribute(kendo.attr(COLSPAN))) return;
that._createResizeHandle(th.closest(DIV), th);
});
},
_resizeHandleDocumentClick: function(e) {
if ($(e.target).closest(".k-column-active").length) return;
$(document).off(e);
this._resetResizeHandleHeader();
this._hideResizeHandle();
},
_resetResizeHandleHeader: function() {
var th;
if (!this.resizeHandle) return;
th = $(this.resizeHandle).data("th");
if (th) {
th.find(".k-link").find(".k-icon,.k-svg-icon").show();
th.find(".k-sort-order").show();
th.find(".k-grid-column-menu").show();
th.find(".k-grid-filter-menu").show();
}
},
_hideResizeHandle: function() {
if (this.resizeHandle) {
this.resizeHandle.data("th").removeClass("k-column-active");
if (this.lockedContent && !(this._isMobile || kendo.support.mobileOS)) {
this.resizeHandle.off(NS).remove();
this.resizeHandle = null;
} else this.resizeHandle.hide();
}
},
_positionColumnResizeHandleTouch: function() {
var that = this, lockedHead = that.lockedHeader ? that.lockedHeader.find("thead").first() : $();
that._resizeUserEvents = new kendo.UserEvents(lockedHead.add(that.thead), {
filter: "th:not(.k-group-cell):not(.k-hierarchy-cell)",
threshold: 10,
minHold: 500,
hold: function(e) {
var th = $(e.target);
e.preventDefault();
if (that.resizeHandle) {
that.resizeHandle.data("th").removeClass("k-column-active");
that._resetResizeHandleHeader();
}
th.addClass("k-column-active");
th.find(".k-link").find(".k-icon,.k-svg-icon").hide();
th.find(".k-sort-order").hide();
th.find(".k-grid-column-menu").hide();
th.find(".k-grid-filter-menu").hide();
that._createResizeHandle(th.closest(DIV), th);
if (!that._resizeHandleDocumentClickHandler) that._resizeHandleDocumentClickHandler = that._resizeHandleDocumentClick.bind(that);
$(document).on("click", that._resizeHandleDocumentClickHandler);
}
});
},
resizeColumn: function(column, columnWidth) {
var that = this;
var isLocked = !!column.locked;
var isHidden = !!column.hidden;
var options = this.options;
var scrollbar = !kendo.support.mobileOS ? kendo.support.scrollbar() : 0;
var index = isLocked ? inArray(column, visibleLockedColumns(visibleLeafColumns(that.columns))) : inArray(column, visibleNonLockedColumns(visibleLeafColumns(that.columns)));
var contentTable = isLocked ? that.lockedTable : that.table;
var footer = that.footer || $();
var columnMinWidth = column.minResizableWidth || 10;
var gridWidth = isLocked ? outerWidth(contentTable.find("tbody")) : outerWidth(that.tbody);
var col;
if (this._isStackedMode()) return;
var header = isLocked ? that.lockedHeader.find("table") : that.thead.closest("table");
if (isHidden) {
column.width = columnWidth > columnMinWidth ? columnWidth : columnMinWidth;
return;
}
if (that.footer && that.lockedContent) footer = isLocked ? that.footer.children(".k-grid-footer-locked") : that.footer.children(".k-grid-footer-wrap");
if (options.scrollable) col = header.find("col:not(.k-group-col,.k-hierarchy-col)").eq(index).add(contentTable.children("colgroup").find("col:not(.k-group-col):not(.k-hierarchy-col)").eq(index)).add(footer.find("colgroup").find("col:not(.k-group-col):not(.k-hierarchy-col)").eq(index));
else col = contentTable.find("colgroup").find("col:not(.k-group-col):not(.k-hierarchy-col)").eq(index);
if (options.scrollable) {
var constrain = false;
var totalWidth = that.wrapper.width() - scrollbar;
var width = columnWidth = columnWidth > columnMinWidth ? columnWidth : columnMinWidth;
if (isLocked && gridWidth - columnWidth + width > totalWidth) {
width = columnWidth + (totalWidth - gridWidth - scrollbar * 2);
if (width < 0) width = columnWidth;
constrain = true;
}
if (width > 10 && width >= columnMinWidth) {
col.css("width", width);
if (gridWidth) {
if (constrain) width = totalWidth - scrollbar * 2;
else width = gridWidth + (columnWidth - column.width);
contentTable.add(header).add(footer).css("width", width);
if (!isLocked) that._footerWidth = width;
}
}
that._scrollVirtualWrapperOnColumnResize();
} else if (columnWidth > 10 && columnWidth >= columnMinWidth) col.css("width", columnWidth);
column.width = columnWidth;
that._applyLockedContainersWidth();
that._syncLockedContentHeight();
that._syncLockedHeaderHeight();
that._updateStickyColumns();
that._syncStickyGroupColgroups();
that._syncPinnedColgroups();
that._syncPinnedTableWidths();
that._syncPinnedLockedWidths();
},
_adjustColWidths: function(contentTable, header, footer, gridWidth, extraTables) {
const colWidths = {};
contentTable.add(header).add(footer).css("width", gridWidth);
if (extraTables && extraTables.length) extraTables.css("width", gridWidth);
contentTable.add(header).add(footer).find("col").each((i, col) => {
colWidths[i] = $(col).css("width");
});
contentTable.add(header).add(footer).find("col").each((i, col) => {
$(col).css("width", colWidths[i]);
});
if (extraTables && extraTables.length) extraTables.each(function() {
$(this).find("col").each((i, col) => {
if (colWidths[i]) $(col).css("width", colWidths[i]);
});
});
},
_resizable: function() {
var that = this, options = that.options, container, columnStart, columnWidth, columnMinWidth, gridWidth, isMobile = that._isMobile || kendo.support.mobileOS, scrollbar = !kendo.support.mobileOS ? kendo.support.scrollbar() : 0, isLocked, pinnedTables, col, th;
if (!that._isStackedMode() && (options.resizable === true || options.resizable && options.resizable.columns === true)) {
container = options.scrollable ? that.wrapper.find(".k-grid-header-wrap").first() : that.wrapper;
if (isMobile) that._positionColumnResizeHandleTouch(container);
else that._positionColumnResizeHandle(container);
if (that.resizable) that.resizable.destroy();
that.resizable = new ui.Resizable(container.add(that.lockedHeader), {
handle: (!!options.scrollable ? "" : ">") + ".k-resize-handle",
hint: function(handle) {
return $("<div class=\"k-grid-resize-indicator\" />").css({ height: outerHeight(handle.data("th")) + that.tbody.attr("clientHeight") });
},
start: function(e) {
th = $(e.currentTarget).data("th");
if (isMobile) that._hideResizeHandle();
let header = th.closest("table"), index = $.inArray(th[0], leafDataCells(th.closest("thead")).filter(":visible"));
isLocked = header.parent().hasClass("k-grid-header-locked");
let contentTable = isLocked ? that.lockedTable : that.table, footer = that.footer || $();
if (that.footer && that.lockedContent) footer = isLocked ? that.footer.children(".k-grid-footer-locked") : that.footer.children(".k-grid-footer-wrap");
let footerTable = footer.find("table");
cursor(that.wrapper, "col-resize");
if (options.scrollable) col = header.find("col:not(.k-group-col):not(.k-hierarchy-col)").eq(index).add(contentTable.children("colgroup").find("col:not(.k-group-col):not(.k-hierarchy-col)").eq(index)).add(footer.find("colgroup").find("col:not(.k-group-col):not(.k-hierarchy-col)").eq(index));
else col = contentTable.children("colgroup").find("col:not(.k-group-col):not(.k-hierarchy-col)").eq(index);
pinnedTables = $();
const pinnedColSelector = "col:not(.k-group-col):not(.k-hierarchy-col)";
const pinnedTableKey = isLocked ? "lockedTable" : "table";
[that._pinnedTop, that._pinnedBottom].forEach((p) => {
if (p && p[pinnedTableKey]) {
col = col.add(p[pinnedTableKey].find("colgroup").find(pinnedColSelector).eq(index));
pinnedTables = pinnedTables.add(p[pinnedTableKey]);
}
});
let columns = $.map(that.columns, function(a) {
return !a.hidden && (isLocked && a.locked || !isLocked && !a.locked) ? a : null;
});
columnStart = e.x.location;
columnWidth = outerWidth(th);
columnMinWidth = leafColumns(columns)[index].minResizableWidth || 10;
gridWidth = isLocked ? outerWidth(contentTable.children("tbody")) : outerWidth(that.tbody);
if (browser.webkit) that.wrapper.addClass("k-grid-column-resizing");
that._adjustColWidths(contentTable, header, footerTable, gridWidth, pinnedTables);
},
resize: function(e) {
var rtlMultiplier = isRtl ? -1 : 1, currentWidth = columnWidth + e.x.location * rtlMultiplier - columnStart * rtlMultiplier;
if (options.scrollable) {
var footer;
if (isLocked && that.lockedFooter) footer = that.lockedFooter.children("table");
else if (that.footer) footer = that.footer.find(">.k-grid-footer-wrap>table");
if (!footer || !footer[0]) footer = $();
var header = th.closest("table");
var contentTable = isLocked ? that.lockedTable : that.table;
var constrain = false;
var totalWidth = that.wrapper.width() - scrollbar;
var width = currentWidth;
if (isLocked && gridWidth - columnWidth + width > totalWidth) {
width = columnWidth + (totalWidth - gridWidth - scrollbar * 2);
if (width < 0) width = currentWidth;
constrain = true;
}
if (width > 10 && width >= columnMinWidth) {
col.css("width", width);
if (gridWidth) {
if (constrain) width = totalWidth - scrollbar * 2;
else width = gridWidth + e.x.location * rtlMultiplier - columnStart * rtlMultiplier;
contentTable.add(header).add(footer).add(pinnedTables).css("width", width);
if (!isLocked) that._footerWidth = width;
}
}
that._scrollVirtualWrapperOnColumnResize();
} else if (currentWidth > 10 && currentWidth >= columnMinWidth) col.css("width", currentWidth);
},
resizeend: function() {
var newWidth = outerWidth(th), column, header;
cursor(that.wrapper, "");
if (browser.webkit) that.wrapper.removeClass("k-grid-column-resizing");
if (th && columnWidth != newWidth) {
header = that.lockedHeader ? that.lockedHeader.find("thead").first().find(TR).first().add(that.thead.find(TR).first()) : th.parent();
let index = parseInt(th.attr(kendo.attr("index")), 10);
if (isNaN(index)) index = header.find("th:not(.k-group-cell):not(.k-hierarchy-cell)").index(th);
column = leafColumns(that.columns)[index];
const resizeTable = th.closest("table");
if (resizeTable.find("col.k-group-col").length) {
const visibleColumns = leafColumns($.map(that.columns, function(col) {
return !col.hidden && (isLocked && col.locked || !isLocked && !col.locked) ? col : null;
}));
const resizedColIndex = $.inArray(column, visibleColumns);
resizeTable.find("col:not(.k-group-col):not(.k-hierarchy-col)").each(function(idx) {
if (visibleColumns[idx] && idx !== resizedColIndex) visibleColumns[idx].width = parseFloat(this.style.width || $(this).css("width"));
});
}
column.width = newWidth;
that.trigger(COLUMNRESIZE, {
column,
oldWidth: columnWidth,
newWidth
});
that._applyLockedContainersWidth(true);
that._syncLockedContentHeight();
that._syncLockedHeaderHeight();
that._updateStickyColumns();
that._syncStickyGroupColgroups();
that._syncPinnedColgroups();
that._syncPinnedTableWidths();
that._syncPinnedLockedWidths();
}
that._resetResizeHandleHeader();
that._hideResizeHandle();
th = null;
}
});
}
},
_addLockedRowResizing: function(tr) {
var index = tr.index();
return this.lockedTable.find(TR).eq(index).add(this.tbody.find(TR).eq(index));
},
_getMinRowHeight: function(row) {
var minHeight = 0;
row.each((i, el) => {
var currentMinHeight;
el.style.height = "";
currentMinHeight = outerHeight(el);
if (currentMinHeight > minHeight) minHeight = currentMinHeight;
});
return minHeight;
},
_cacheRowHeight: function(rows, height) {
var that = this;
if (!that._cachedRowsHeight) that._cachedRowsHeight = {};
rows.each((i, el) => {
var uid = el.getAttribute("data-uid");
that._cachedRowsHeight[uid] = height;
});
},
_clearCachedRowsHeight: function(rows) {
var that = this;
if (rows && that._cachedRowsHeight) rows.each((i, el) => {
var uid = el.getAttribute("data-uid");
delete that._cachedRowsHeight[uid];
});
else that._cachedRowsHeight = null;
},
_mapCachedRowsHeight: function(method, target) {
var input = this._cachedRowsHeight, ds = this.dataSource, output = {};
Object.keys(input).forEach((key) => {
var item = ds[method](key);
if (item) output[item[target]] = input[key];
});
this._cachedRowsHeight = output;
},
_rowResizerDblClick: function() {
var that = this, resizer = that.rowResizer, row = resizer.data(TR), oldHeight = outerHeight(row), newHeight, rows;
if (row.hasClass(SELECTED)) rows = that.select();
else rows = row;
if (that.lockedTable) {
row = that._addLockedRowResizing(row);
if (row.hasClass(SELECTED)) rows = that.lockedTable.find(".k-selected");
else rows = that.lockedTable.find(TR).eq(row.index());
rows.each((i, el) => {
var rowIndex = el.rowIndex, rowPair = $(el).add(that.tbody.find(TR).eq(rowIndex)), pairMinHeight = that._getMinRowHeight(rowPair);
rowPair.css(HEIGHT, pairMinHeight);
});
} else rows.css(HEIGHT, AUTO);
that._clearCachedRowsHeight(rows);
resizer.removeClass(HOVER);
resizer.removeClass(ACTIVE);
newHeight = outerHeight(row);
if (oldHeight != newHeight) that.trigger(ROWRESIZE, {
row,
rows,
oldHeight,
newHeight
});
},
_setupRowResizer(resizer, row, top) {
resizer.data(TR, row).css({ top });
},
_attachRowResizerEvents: function() {
var rowResizer = this.rowResizer, delay = 200, isIn = false;
rowResizer.on("mousedown.kendoGrid", (e) => {
if (e.button === 0) {
rowResizer.removeClass(HOVER);
rowResizer.addClass(ACTIVE);
}
}).on("mouseup.kendoGrid", (e) => {
if (e.button === 0) {
rowResizer.removeClass(ACTIVE);
rowResizer.addClass(HOVER);
}
}).on("mouseenter.kendoGrid", () => {
isIn = true;
setTimeout(() => {
if (isIn) rowResizer.addClass(HOVER);
}, delay);
}).on("mouseleave.kendoGrid", () => {
isIn = false;
rowResizer.removeClass(HOVER);
});
},
_getResizerTop: function(tr, container) {
var resizer = this.rowResizer, inner = resizer.find(".k-row-resizer")[0], paddingTop = parseInt(getComputedStyle(resizer[0]).paddingTop);
return tr.offset().top - parseFloat(tr.css("marginTop")) - (container.offset().top + parseFloat(container.css("borderTopWidth"))) - inner.clientHeight - paddingTop + container.scrollTop();
},
_getResizerContainer: function() {
var container = this.tbody.closest(DIV);
if (this.lockedTable) container = container.closest(".k-grid-container");
return container;
},
_createRowResizer: function(e) {
var that = this, tr = $(e.currentTarget), targetHeight = e.currentTarget.clientHeight, positionIntarget = e.offsetY, rowResizer = that.rowResizer, previousRow = tr.prev("tr:visible"), container = that._getResizerContainer(), top;
if (!rowResizer) {
rowResizer = that.rowResizer = $("<div class=\"k-resizer-wrap\"><div class=\"k-row-resizer\"></div></div>");
container.append(rowResizer);
that._attachRowResizerEvents();
rowResizer.off("dblclick.kendoGrid").on("dblclick.kendoGrid", that._rowResizerDblClick.bind(that));
}
top = that._getResizerTop(tr, container);
if (previousRow.length !== 0 && targetHeight / 2 > positionIntarget) {
if (!previousRow.hasClass(GROUPING_ROW)) that._setupRowResizer(rowResizer, previousRow, top);
} else if (!tr.hasClass(GROUPING_ROW)) that._setupRowResizer(rowResizer, tr, top + targetHeight);
},
_detachRowResizerEvents: function() {
this.rowResizer.off("mousedown.kendoGrid").off("mouseup.kendoGrid").off("mouseenter.kendoGrid").off("mouseleave.kendoGrid");
},
_mapResizedRows: function(rows, multiSelectionLocked, newHeight) {
var that = this;
rows.each((i, el) => {
var minHeight;
if (multiSelectionLocked) {
var rowIndex = el.rowIndex, pairNew = newHeight, pairMin = 0, rowPair = $(el).add(that.tbody.find(TR).eq(rowIndex));
rowPair.each((i, r) => {
var currentMinHeight;
r.style.height = "";
currentMinHeight = outerHeight(r);
if (currentMinHeight > pairMin) pairMin = currentMinHeight;
});
if (pairNew < pairMin) {
pairNew = pairMin;
that._clearCachedRowsHeight(rowPair.eq(0));
} else that._cacheRowHeight(rowPair.eq(0), pairNew);
rowPair.css(HEIGHT, pairNew);
} else {
el.style.height = "";
minHeight = outerHeight(el);
if (newHeight > minHeight) {
el.style.height = newHeight + PX;
that._cacheRowHeight($(el), newHeight);
} else that._clearCachedRowsHeight($(el));
}
});
},
_rowResizing: function() {
var that = this, options = that.options, container, rowStart, rowHeight, tr;
if (options.resizable && options.resizable.rows === true) {
that.tbody.parent().add(that.lockedTable).on("mousemove.kendoGrid", ".k-grid-footer tr, .k-table-tbody tr", that._createRowResizer.bind(that));
if (that.rowResizing) that.rowResizing.destroy();
container = that._getResizerContainer();
that.rowResizing = new ui.Resizable(container, {
handle: ".k-resizer-wrap",
start: function(e) {
tr = $(e.currentTarget).data(TR);
if (that.lockedTable) tr = that._addLockedRowResizing(tr);
tr.addClass(HOVER);
that._detachRowResizerEvents();
rowStart = e.y.location;
rowHeight = outerHeight(tr);
},
resize: function(e) {
var newHeight = rowHeight + e.y.location - rowStart, minHeight = 0;
if (tr.length > 1) minHeight = that._getMinRowHeight(tr);
if (newHeight < minHeight) newHeight = minHeight;
tr.css("height", newHeight);
that._setupRowResizer(that.rowResizer, tr, that._getResizerTop(tr, container) + newHeight);
},
resizeend: function() {
var newHeight = outerHeight(tr), multiSelectionLocked = false, rows;
if (tr.hasClass(SELECTED)) {
rows = that.select();
if (tr.length > 1 && rows.length > tr.length) {
rows = that.lockedTable.find(".k-selected").not(tr);
multiSelectionLocked = true;
}
} else rows = tr;
that._mapResizedRows(rows, multiSelectionLocked, newHeight);
tr.removeClass(HOVER);
that.rowResizer.removeClass(ACTIVE);
that.rowResizer.addClass(HOVER);
that._attachRowResizerEvents();
if (multiSelectionLocked) rows = that.select();
if (rowHeight != newHeight) that.trigger(ROWRESIZE, {
row: tr,
rows,
oldHeight: rowHeight,
newHeight
});
tr = null;
}
});
}
},
_draggable: function() {
var that = this, reorderable = that.options.reorderable;
if (reorderable === true || reorderable && reorderable.columns) {
if (that._draggableInstance) that._draggableInstance.destroy();
var header = that.wrapper.children(".k-grid-header");
header.addClass("k-grid-draggable-header");
that._draggableInstance = that.wrapper.kendoDraggable({
group: kendo.guid(),
autoScroll: true,
filter: that.content ? ".k-grid-header:first th.k-header:not(.k-group-cell):not(.k-hierarchy-cell)" : "table:first>.k-grid-header th.k-header:not(.k-group-cell):not(.k-hierarchy-cell)",
dragstart: function() {
header.children(".k-grid-header-wrap").off("scroll.kendoGridscrolling").on("scroll.kendoGridscrolling", function(e) {
if (that.virtualScrollable) kendo.scrollLeft(that.content.find(">.k-virtual-scrollable-wrap"), this.scrollLeft);
else kendo.scrollLeft(that.scrollables.not(e.currentTarget), this.scrollLeft);
});
},
dragend: function() {
that._resetResizeHandleHeader();
header.children(".k-grid-header-wrap").off("scroll.kendoGridscrolling");
},
drag: function() {
that._hideResizeHandle();
},
hint: function(target) {
var title = target.attr(kendo.attr("title"));
if (title) title = kendo.htmlEncode(title);
return $("<div class=\"k-reorder-clue k-drag-clue\" />").html(title || target.attr(kendo.attr("field")) || target.text()).prepend(kendo.ui.icon({
icon: "cancel",
iconClass: "k-drag-status"
}));
}
}).data("kendoDraggable");
}
},
_reorderable: function() {
let that = this, reorderable = that.options.reorderable;
if (reorderable === true || reorderable && reorderable.columns) {
if (that.wrapper.data("kendoReorderable")) that.wrapper.data("kendoReorderable").destroy();
that.wrapper.kendoReorderable({
draggable: that._draggableInstance,
dropFilter: HEADERCELLS,
allowDropAfterLastItem: true,
dragOverContainers: function(sourceIndex, targetIndex) {
let columns = flatColumnsInDomOrder(that.columns);
return columns[sourceIndex].lockable !== false && targetParentContainerIndex(columns, that.columns, sourceIndex, targetIndex) > -1;
},
inSameContainer: function(e) {
let sourceParent = $(e.source).parent()[0], targetParent = $(e.target).parent()[0], sourceIndex = e.sourceIndex, targetIndex = e.targetIndex, flatColumns = flatColumnsInDomOrder(that.columns), lockable = flatColumns && flatColumns[sourceIndex] && !!flatColumns[sourceIndex].lockable;
if (that._isLocked() && lockable) {
sourceParent = $(e.source.closest(".k-grid-header"))[0];
targetParent = $(e.target.closest(".k-grid-header"))[0];
}
return sourceParent === targetParent && targetParentContainerIndex(flatColumns, that.columns, sourceIndex, targetIndex) > -1;
},
change: function(e) {
let columns = flatColumnsInDomOrder(that.columns);
let column = columns[e.oldIndex];
let newIndex = targetParentContainerIndex(columns, that.columns, e.oldIndex, e.newIndex);
that.trigger(COLUMNREORDER, {
newIndex,
oldIndex: inArray(column, columns),
column
});
that.reorderColumn(newIndex, column, e.position === "before");
}
});
}
},
_reorderHeader: function(sources, target, before, container) {
var that = this;
var sourcePosition = columnPosition(sources[0], that.columns);
var destPosition = columnPosition(target, that.columns);
var action;
var ths;
var leafs = [];
for (var idx = 0; idx < sources.length; idx++) if (sources[idx].columns) leafs = leafs.concat(sources[idx].columns);
if (container) ths = elements(container, container, "tr:eq(" + sourcePosition.row + ")>th.k-header:not(.k-group-cell,.k-hierarchy-cell)");
else ths = elements(that.lockedHeader, that.thead, "tr:eq(" + sourcePosition.row + ")>th.k-header:not(.k-group-cell,.k-hierarchy-cell)");
var sourceLockedColumns = lockedColumns(sources).length;
var targetLockedColumns = lockedColumns([target]).length;
if (leafs.length) {
if (sourceLockedColumns > 0 && targetLockedColumns === 0) {
action = "prepend";
moveCellsBetweenContainers(sources, target, leafs, that.columns, that.lockedHeader.find("thead"), that.thead, this._groups(), action);
} else if (sourceLockedColumns === 0 && targetLockedColumns > 0) {
action = destPosition.cell === 0 && sources[0].columns && !target.columns && !that._group ? "prepend" : "append";
moveCellsBetweenContainers(sources, target, leafs, nonLockedColumns(that.columns), that.thead, that.lockedHeader.find("thead"), this._groups(), action);
}
if (target.columns || sourcePosition.cell - destPosition.cell > 1 || destPosition.cell - sourcePosition.cell > 1) {
target = findReorderTarget(that.columns, target, sources[0], before, that.columns);
if (target) if (sourceLockedColumns > 0 && targetLockedColumns === 0) that._reorderHeader(leafs, target, before, that.thead);
else if (sourceLockedColumns === 0 && targetLockedColumns > 0) that._reorderHeader(leafs, target, before, that.lockedHead);
else that._reorderHeader(leafs, target, before);
}
} else if (sourceLockedColumns !== targetLockedColumns) updateCellRowSpan(ths[sourcePosition.cell], that.columns, sourceLockedColumns);
reorder(ths, sourcePosition.cell, destPosition.cell, before, sources.length);
},
_reorderContent: function(sources, destination, before) {
var that = this;
var lockedRows = $();
var source = sources[0];
var visibleSources = visibleColumns(sources);
var sourceIndex = inArray(source, leafColumns(that.columns));
var destIndex = inArray(destination, leafColumns(that.columns));
var colSourceIndex = inArray(visibleSources[0], visibleLeafColumns(that.columns));
var colDest = inArray(destination, visibleLeafColumns(that.columns));
var lockedCount = lockedColumns(that.columns).length;
var isLocked = !!destination.locked;
var footer = that.footer || that.wrapper.find(".k-grid-footer");
var headerCol = footerCol = colDest, footerCol, beforeVisibleColumn;
if (destination.hidden) {
var columnsArray = isLocked ? lockedColumns(that.columns) : nonLockedColumns(that.columns);
if (visibleColumns(columnsArray).length > 0) {
headerCol = footerCol = colDest = this._findClosestVisibleColumnIndex(columnsArray, destIndex);
beforeVisibleColumn = visibleColumns(columnsArray.slice(destIndex)).length > 0;
} else if (isLocked) {
colDest = that.lockedTable.find("colgroup");
headerCol = that.lockedHeader.find("colgroup");
footerCol = $(that.lockedFooter).find(">table>colgroup");
} else {
colDest = that.tbody.prev();
headerCol = that.thead.prev();
footerCol = footer.find(".k-grid-footer-wrap").find(">table>colgroup");
}
}
if (that._hasFilterRow()) reorder(that.wrapper.find(".k-filter-row td:not(.k-group-cell,.k-hierarchy-cell)"), sourceIndex, destIndex, before, sources.length);
if (colSourceIndex >= 0) reorder(elements(that.lockedHeader, that.thead.prev(), COLGROUP), colSourceIndex, headerCol, beforeVisibleColumn ? beforeVisibleColumn : before, visibleSources.length);
if (that.options.scrollable) {
if (colSourceIndex >= 0 && !that._hasVirtualColumns()) reorder(elements(that.lockedTable, that.tbody.prev(), COLGROUP), colSourceIndex, colDest, beforeVisibleColumn ? beforeVisibleColumn : before, visibleSources.length);
}
if (footer && footer.length) {
if (colSourceIndex >= 0) reorder(elements(that.lockedFooter, footer.find(".k-grid-footer-wrap"), ">table>colgroup>col:not(.k-group-col,.k-hierarchy-col)"), colSourceIndex, footerCol, beforeVisibleColumn ? beforeVisibleColumn : before, visibleSources.length);
reorder(footer.find(".k-footer-template>td:not(.k-group-cell,.k-hierarchy-cell)"), sourceIndex, destIndex, before, sources.length);
}
var rows = that.tbody.children(":not(.k-grouping-row,.k-detail-row)");
if (that.lockedTable) {
if (lockedCount > destIndex) {
if (lockedCount <= sourceIndex) updateColspan(that.lockedTable.find(">tbody>tr.k-grouping-row:not([hidden])"), that.table.find(">tbody>tr.k-grouping-row:not([hidden])"), sources.length);
} else if (lockedCount > sourceIndex) updateColspan(that.table.find(">tbody>tr.k-grouping-row:not([hidden])"), that.lockedTable.find(">tbody>tr.k-grouping-row:not([hidden])"), sources.length);
lockedRows = that.lockedTable.find(">tbody>tr:not(.k-grouping-row,.k-detail-row)");
}
for (var idx = 0, length = rows.length; idx < length; idx += 1) reorder(elements(lockedRows[idx], rows[idx], ">td:not(.k-group-cell,.k-hierarchy-cell)"), sourceIndex, destIndex, before, sources.length);
},
_findClosestVisibleColumnIndex: function(columns, columnIndex) {
var closestVisibleColumn = visibleColumns(visibleColumns(columns.slice(columnIndex)).length > 0 ? columns.slice(columnIndex) : columns.slice(0, columnIndex + 1).reverse())[0];
return inArray(closestVisibleColumn, visibleColumns(this.columns));
},
_autoFitLeafColumn: function(leafIndex) {
this.autoFitColumn(leafColumns(this.columns)[leafIndex]);
},
_hasReorderableRows: function() {
return this.options.reorderable && this.options.reorderable.rows;
},
_draggableRows: function() {
var that = this, selectable = that._checkBoxSelection || that.options.selectable && !kendo.ui.Selectable.parseOptions(that.options.selectable).cell, clickMoveClick = false, isMobile = !!(that._isMobile || kendo.support.mobileOS);
if (that._draggableRowsInstance) that._draggableRowsInstance.destroy();
if (this.options.reorderable.rows.clickMoveClick !== false && this._hasDragHandleColumn) clickMoveClick = true;
that._draggableRowsInstance = that.tbody.kendoDraggable({
holdToDrag: isMobile,
showHintOnHold: isMobile,
preventOsHoldFeatures: isMobile,
group: "row-draggable",
autoScroll: true,
filter: (selectable ? " > .k-selected" : " > tr:not(.k-grouping-row):not(.k-detail-row):not(.k-footer-template):not(.k-group-footer):visible") + (that._hasDragHandleColumn ? " > [ref-grid-drag-cell]" : ":not(:has([data-container-for]))"),
hint: function(target) {
var hint = $("<div class=\"k-reorder-clue k-drag-clue\">" + kendo.ui.icon({
icon: "cancel",
iconClass: "k-drag-status"
}) + "</div>");
if (selectable && that.select().length > 1 && that.lockedContent) hint.append("<span>" + that.select().length / 2 + " " + encode(that.options.messages.itemsSelected) + "</span>");
else if (selectable && that.select().length > 1 && !that.lockedContent) hint.append("<span>" + that.select().length + " " + encode(that.options.messages.itemsSelected) + "</span>");
else {
var clone = target.closest(ITEMROW).clone();
clone.find("td.k-command-cell").remove();
clone.find("td").each(function(index, elm) {
hint.append("<span>" + elm.innerText.replace(/<(\/?)script([^>]*)>/gi, "") + " </span>");
});
}
return hint;
},
clickMoveClick,
cursorOffset: {
top: 0,
left: 0
}
}).data("kendoDraggable");
},
_reorderableRows: function() {
var that = this, selectable = that._checkBoxSelection || that.options.selectable && !kendo.ui.Selectable.parseOptions(that.options.selectable).cell;
if (that.tbody.data("kendoReorderable")) that.tbody.data("kendoReorderable").destroy();
that.tbody.kendoReorderable({
smartPosition: false,
draggable: that._draggableRowsInstance,
dragOverContainers: function(sourceIndex, targetIndex) {
var result = true, target = $(ITEMROW, that.content).eq(targetIndex);
if (selectable) result = !target.is(".k-selected");
return result;
},
inSameContainer: function(e) {
if (selectable) return !$(e.target).is(".k-selected");
return true;
},
dropFilter: "> tr:not(.k-grouping-row):not(.k-detail-row):not(.k-footer-template):not(.k-group-footer):visible",
allowIcon: "insert-middle",
orientation: "vertical",
reorderDropCue: $("<div class=\"k-drop-hint k-drop-hint-h\"><div class=\"k-drop-hint-start\"></div><div class=\"k-drop-hint-line\"></div></div>"),
positionDropCue: function(reorderDropCue, dropTarget) {
var firstCellLeft = kendo.getOffset(dropTarget.children(DATA_CELL).eq(0)).left;
reorderDropCue.css({
transform: "translate(0,-50%)",
left: firstCellLeft
});
},
externalDraggable: function(e) {
var draggable = e.draggable;
if (draggable) return draggable;
},
change: function(e) {
that._triggerRowRorder(e);
}
});
},
_triggerRowRorder: function(e) {
var that = this, args = {
newIndex: e.position === "after" ? e.newIndex + 1 : e.newIndex,
oldIndex: e.oldIndex
}, row = e.element, selectable = that._checkBoxSelection || that.options.selectable && !kendo.ui.Selectable.parseOptions(that.options.selectable).cell;
if (selectable && that.select().length > 1) args = extend(args, { rows: that.select() });
else args = extend(args, { row });
if (!that.trigger(ROWREORDER, args)) that.reorderRows(selectable ? that.select() : row, args.newIndex);
},
reorderRowTo: function(row, index) {
var that = this, item = that.dataItem(row), oldIndex = row.index();
if (index < 0 || index === oldIndex) return;
if (!that.trigger(ROWREORDER, {
row,
oldIndex: row.index(),
newIndex: index
})) {
that._rowDropping = true;
that.dataSource.pushMove(index, [item]);
that._rowDropping = false;
if (that._isPinnable()) that._renderPinnedRows();
}
},
reorderRows: function(rows, index) {
var that = this, dataSource = that.dataSource, rowsLength = that.tbody.children(ITEMROW).length, targetItem = that.dataItem(that.tbody.children(ITEMROW).eq(index)), items = rows.toArray().map(function(row) {
let dataItem = that.dataItem(row);
dataItem._isMoved = true;
return dataItem;
});
if (!targetItem) {
targetItem = that.dataItem(that.tbody.children(ITEMROW).eq(rowsLength - 1));
index = dataSource.indexOf(targetItem) + 1;
} else index = dataSource.indexOf(targetItem);
if (index >= 0) {
that._rowDropping = true;
dataSource.pushMove(index, items);
that._rowDropping = false;
if (that._isPinnable()) that._renderPinnedRows();
}
},
autoFitColumns: function(columns) {
var that = this;
columns = columns || that.columns;
for (var i = 0; i < columns.length; i++) {
var column = columns[i];
if (column.columns) that.autoFitColumns(column.columns);
else that.autoFitColumn(column);
}
},
autoFitColumn: function(column) {
var that = this, options = that.options, columns = that.columns, index, th, headerTable, leafCols, isLocked, visibleLocked = that.lockedHeader ? leafDataCells(that.lockedHeader.find(">table>thead")).filter(isCellVisible).length : 0, col, minWidth, contentDiv, scrollLeft, notGroupOrHierarchyCol = "col:not(.k-group-col):not(.k-hierarchy-col)", notGroupOrHierarchyVisibleCell = "td:visible:not(.k-group-cell):not(.k-hierarchy-cell)", thWidth;
if (typeof column == "number") column = columns[column];
else if (isPlainObject(column)) column = grep(flatColumns(columns), function(item) {
return item === column;
})[0];
else column = grep(flatColumns(columns), function(item) {
return item.field === column;
})[0];
if (!column || !isVisible(column)) return;
leafCols = leafColumns(columns);
minWidth = column.minResizableWidth;
index = inArray(column, leafCols);
isLocked = column.locked;
if (isLocked) headerTable = that.lockedHeader.children("table");
else headerTable = that.thead.parent();
th = headerTable.find("[data-index='" + index + "']");
th.find("a.k-grid-column-menu, a.k-grid-filter-menu");
var contentTable = isLocked ? that.lockedTable : that.table, footer = that.footer || $();
if (that.footer && that.lockedContent) footer = isLocked ? that.footer.children(".k-grid-footer-locked") : that.footer.children(".k-grid-footer-wrap");
var footerTable = footer.find("table").first();
if (that.lockedHeader && !isLocked) index -= visibleLocked;
for (var j = 0; j < leafCols.length; j++) if (leafCols[j] === column) break;
else if (leafCols[j].hidden) index--;
if (options.scrollable) {
col = headerTable.find(notGroupOrHierarchyCol).eq(index).add(contentTable.children("colgroup").find(notGroupOrHierarchyCol).eq(index)).add(footerTable.find("colgroup").find(notGroupOrHierarchyCol).eq(index));
if (!isLocked) {
contentDiv = contentTable.parent();
scrollLeft = kendo.scrollLeft(contentDiv);
}
if (that._hasVirtualColumns()) index = inArray(column, that.virtualCols);
} else col = contentTable.children("colgroup").find(notGroupOrHierarchyCol).eq(index);
var tables = headerTable.add(contentTable).add(footerTable);
if (browser.safari) th.css("white-space", "initial");
var oldColumnWidth = outerWidth(th);
col.width("");
tables.css("table-layout", "fixed");
col.width(AUTO);
tables.addClass("k-autofitting");
tables.css("table-layout", "");
thWidth = outerWidth(th);
var newColumnWidth = Math.ceil(Math.max(thWidth, outerWidth(contentTable.find("tr:not(.k-grouping-row)").eq(0).children(notGroupOrHierarchyVisibleCell).eq(index)), outerWidth(footerTable.find(TR).eq(0).children(notGroupOrHierarchyVisibleCell).eq(index)))) + 1;
if (minWidth && minWidth > newColumnWidth) newColumnWidth = minWidth;
col.width(newColumnWidth);
column.width = newColumnWidth;
if (browser.safari) th.css("white-space", "");
if (options.scrollable) {
var cols = headerTable.find("col"), colWidth, totalWidth = 0;
for (var idx = 0, length = cols.length; idx < length; idx += 1) {
colWidth = cols[idx].style.width;
if (colWidth && colWidth.indexOf("%") == -1) totalWidth += parseInt(colWidth, 10);
else if (cols.eq(idx).hasClass("k-group-col")) totalWidth += parseInt(cols.eq(idx).width(), 10);
else {
totalWidth = 0;
break;
}
}
if (totalWidth) tables.each(function() {
this.style.width = totalWidth + PX;
});
}
tables.removeClass("k-autofitting");
if (scrollLeft) kendo.scrollLeft(contentDiv, scrollLeft);
that.trigger(COLUMNRESIZE, {
column,
oldWidth: oldColumnWidth,
newWidth: newColumnWidth
});
that._applyLockedContainersWidth();
that._syncLockedContentHeight();
that._syncLockedHeaderHeight();
that._updateStickyColumns();
that._syncStickyGroupColgroups();
},
reorderColumn: function(destIndex, column, before) {
var that = this, parent = columnParent(column, that.columns), columns = parent ? parent.columns : that.columns, sourceIndex = inArray(column, columns), destColumn = columns[destIndex], virtualScroll = that.virtualScroll || {}, lockChanged, isLocked = !!destColumn.locked, lockedCount = lockedColumns(that.columns).length, groupHeaderColumnTemplateColumns = grep(leafColumns(that.columns), function(column) {
return column.groupHeaderColumnTemplate;
});
if (that._isStackedMode()) return;
if (sourceIndex === destIndex) return;
if (!column.locked && isLocked && nonLockedColumns(that.columns).length == 1) return;
if (column.locked && !isLocked && lockedCount == 1) return;
that._hideResizeHandle();
if (before === undefined) before = destIndex < sourceIndex;
var sourceColumns = [column];
that._reorderHeader(sourceColumns, destColumn, before);
if (that.lockedHeader) {
removeEmptyRows(that.thead);
removeEmptyRows(that.lockedHeader);
}
if (destColumn.columns) {
destColumn = leafColumns(destColumn.columns);
destColumn = destColumn[before ? 0 : destColumn.length - 1];
}
if (column.columns) sourceColumns = leafColumns(column.columns);
that._reorderContent(sourceColumns, destColumn, before);
lockChanged = !!column.locked;
lockChanged = lockChanged != isLocked;
column.locked = isLocked;
columns.splice(before ? destIndex : destIndex + 1, 0, column);
columns.splice(sourceIndex < destIndex ? sourceIndex : sourceIndex + 1, 1);
that._updateLockedCols();
that._updateCols();
that._templates();
that._updateColumnCellIndex();
that._updateColumnSorters();
if (groupHeaderColumnTemplateColumns.length > 0) that._renderGroupRows();
that._updateTablesWidth();
that._applyLockedContainersWidth();
that._syncLockedHeaderHeight();
that._syncLockedContentHeight();
that._updateFirstColumnClass();
that._updateStickyColumns();
that._syncStickyGroupColgroups();
that._renderPinnedRows();
if (virtualScroll.columns) that.refresh();
if (!lockChanged) return;
if (isLocked) that.trigger(COLUMNLOCK, { column });
else that.trigger(COLUMNUNLOCK, { column });
},
_updateColumnCellIndex: function() {
var header;
var offset = 0;
if (this.lockedHeader) {
header = this.lockedHeader.find("thead");
offset = updateCellIndex(header, lockedColumns(this.columns));
}
updateCellIndex(this.thead, nonLockedColumns(this.columns), offset);
},
lockColumn: function(column) {
var columns = this.columns;
if (typeof column == "number") column = columns[column];
else column = grep(columns, function(item) {
return item.field === column;
})[0];
if (!column || column.locked || column.hidden) return;
if (column.sticky) this.unstickColumn(columns.indexOf(column));
var index = lockedColumns(columns).length - 1;
this.reorderColumn(index, column, false);
},
unlockColumn: function(column) {
var columns = this.columns;
if (typeof column == "number") column = columns[column];
else column = grep(columns, function(item) {
return item.field === column;
})[0];
if (!column || !column.locked || column.hidden) return;
var index = lockedColumns(columns).length;
this.reorderColumn(index, column, true);
},
stickColumn: function(column) {
var columns = this.columns;
if (typeof column == "number") column = columns[column];
else column = grep(columns, function(item) {
return item.field === column;
})[0];
if (!column || column.sticky || column.hidden) return;
if (column.locked) {
this.unlockColumn(columns.indexOf(column));
if (column.locked) return;
}
column.sticky = true;
this._updateStickyColumns();
},
unstickColumn: function(column) {
var columns = this.columns;
if (typeof column == "number") column = columns[column];
else column = grep(columns, function(item) {
return item.field === column;
})[0];
if (!column || !column.sticky || column.locked || column.hidden) return;
this._removeStickyAttributes([column]);
this._removeStickyStyles(stickyColumns(columns));
column.sticky = false;
this._updateStickyColumns();
if (this._anyStickyColumns() === 0) {
this._templates();
if (this._hasFilterRow()) this._updateStickyFilterCells();
}
},
cellIndex: function(td) {
const that = this;
var lockedColumnOffset = 0;
const selector = that._isStackedMode() ? "div.k-grid-stack-cell" : "td";
if (this.lockedTable && !$.contains(this.lockedTable[0], td[0])) lockedColumnOffset = leafColumns(lockedColumns(this.columns)).length;
return $(td).parent().children(selector + ":not(.k-group-cell,.k-hierarchy-cell)").index(td) + lockedColumnOffset;
},
_modelForContainer: function(container) {
container = $(container);
if (!container.is(TR) && this._editMode() !== "popup") container = container.closest(TR);
var id = container.attr(kendo.attr("uid")) || container.find("[ref='popup-edit-form']").attr(kendo.attr("uid"));
return this.dataSource.getByUid(id);
},
_calculateColumnIndex: function(cell) {
if (this._hasVirtualColumns()) {
let virtualOffset = parseInt($(cell).closest(TR).find("td").first().attr("colspan"), 10);
virtualOffset = virtualOffset > 1 ? virtualOffset - 1 : 0;
const dataField = cell.data("field");
return (this.thead?.find("th[data-field='" + dataField + "']")).data("index") ?? this.cellIndex(cell) + virtualOffset;
}
return this.cellIndex(cell);
},
_editable: function() {
let that = this, editable = that.options.editable, handler = function() {
let target = activeElement(), cell = that._editContainer;
if (cell && cell[0] && !$.contains(cell[0], target) && cell[0] !== target && !$(target).closest(".k-animation-container").length) if (that.editable.end()) {
that.closeCell();
that._toggleToolbarEditingItemsVisibility();
} else that._scrollVirtualWrapper();
}, mobileOS = kendo.support.mobileOS, useDoubleTapEditing = !!(that._isMobile || mobileOS), userEventsPreventDefault = mobileOS && mobileOS.ios && (mobileOS.browser === "chrome" || mobileOS.browser === "edge");
that._isEditableEnabled = that._isEditableEnabled !== undefined ? that._isEditableEnabled : !editable.readonly;
const stacked = that._isStackedMode();
if (!that._isEditableEnabled) that._removeEditableClickHandlers();
if (editable && that._isEditableEnabled) {
if (that._editMode() === "incell") {
that.table.add(that.lockedTable).on("mousedown.kendoGrid", "tr:not(.k-footer-template):visible>:not(.k-group-cell):not(.k-detail-cell):not(.k-hierarchy-cell):visible", function(e) {
let target = $(e.target);
if (that._editMode() === "incell" && target.hasClass("k-checkbox") && target.prev().attr(kendo.attr("bind"))) e.preventDefault();
});
if (editable.update !== false) {
if (isMac) that.wrapper.on("click.kendoGrid", ".k-edit-cell > input[type='checkbox']", function(e) {
$(e.target).trigger("focus");
}).on("click.kendoGrid", ".k-edit-cell", function(e) {
if (!$(e.target).is("input")) $(e.currentTarget).find("input[type='checkbox']").trigger("focus");
}).on("mousedown.kendoGrid", "tr:not(.k-grouping-row) > td", function(e) {
var editContainer = that._editContainer;
if (editContainer && editContainer[0] && ($.contains(editContainer[0], e.target) || editContainer[0] === e.target)) that._mousedownOnEditCell = true;
else that._mousedownOnEditCell = false;
});
that.editableUserEvents = new kendo.UserEvents(that.wrapper, {
filter: stacked ? ".k-grid-stack-row:not(.k-grouping-row) div.k-grid-stack-cell" : "tr:not(.k-grouping-row) > td",
allowSelection: true,
preventDefault: userEventsPreventDefault,
supportDoubleTap: useDoubleTapEditing,
fastTap: useDoubleTapEditing,
[useDoubleTapEditing ? "doubleTap" : "tap"]: function(e) {
var td = $(e.target), isLockedCell = that.lockedTable && td.closest("table")[0] === that.lockedTable[0];
that._mousedownOnEditCell = false;
if (td.hasClass("k-hierarchy-cell") || td.hasClass("k-detail-cell") || td.hasClass("k-group-cell") || td.hasClass("k-edit-cell") || td.hasClass("k-drag-cell") || td.hasClass("k-grid-stack-edit-cell") || td.has(".k-grid-remove-command").length || td.closest("tbody")[0] !== that.tbody[0] && !isLockedCell || $(e.target).is(":input")) return;
let index;
if (stacked) index = td.parent().children().index(td);
if (that.editable) if (that.editable.end()) {
$(activeElement()).trigger("blur");
that.closeCell();
if (!that._requestInProgress) that.editCell(td, index);
} else that._scrollVirtualWrapper();
else that.editCell(td, index);
}
});
that.wrapper.on("focusin.kendoGrid", function() {
if (!$.contains(this, activeElement())) {
clearTimeout(that._timer);
that._timer = null;
}
}).on("focusout.kendoGrid", function(e) {
var shouldCloseCell = true;
if (isMac && that._mousedownOnEditCell || that._virtualColScroll) shouldCloseCell = false;
that._mousedownOnEditCell = false;
if (shouldCloseCell) that._timer = setTimeout(function() {
handler();
}, 1);
});
}
} else if (editable.update !== false) {
that._editCommandClickHandler = that._editCommandClick.bind(that);
that.wrapper.on("click.kendoGrid", "tbody>tr:not(.k-detail-row,.k-grouping-row):visible .k-grid-edit-command", that._editCommandClickHandler);
if (that._isVirtualInlineEditable()) that.wrapper.on("focusout.kendoGrid", "tr:not(.k-grouping-row) > td", function() {
if (that.editable && !that.editable.end()) that._scrollVirtualWrapper();
});
}
that._removeCommandClickHandler = that._removeCommandClick.bind(that);
that.wrapper.on("click.kendoGrid", "tbody>tr:not(.k-detail-row,.k-grouping-row):visible .k-grid-remove-command", that._removeCommandClickHandler);
}
},
_getLastSelectedItemModel: function() {
const that = this;
if (!that.options.selectable) return;
const selectedData = that.getSelectedData();
if (!selectedData || !selectedData.length) return;
const selected = selectedData[selectedData.length - 1];
return that.dataSource.getByUid(selected.uid);
},
_removeToolbarClick: function(e) {
if (e.event) {
e.event.preventDefault();
e.event.stopPropagation();
} else e.preventDefault();
const that = this;
const model = this._getLastSelectedItemModel();
if (!model) return;
const row = that.tbody.children("[" + kendo.attr("uid") + "=" + model.uid + "]");
that.removeRow(row);
},
_editToolbarClick: function(e) {
if (e.event) {
e.event.preventDefault();
e.event.stopPropagation();
} else e.preventDefault();
const that = this;
if (that._editMode() === "incell") return;
const model = this._getLastSelectedItemModel();
if (!model) return;
that.editRow(model);
},
_editCommandClick: function(e) {
let that = this, element = $(e.currentTarget);
if (!that._belongsToGrid(element)) return;
e.preventDefault();
that.editRow(element.closest(TR));
},
_removeCommandClick: function(e) {
let that = this, editable = that.options.editable, element = $(e.currentTarget);
if (!that._belongsToGrid(element)) return;
if (editable.destroy !== false) {
e.preventDefault();
e.stopPropagation();
that.removeRow(element.closest(TR));
} else {
e.stopPropagation();
if (!that._confirmation()) e.preventDefault();
}
that._toggleToolbarEditingItemsVisibility();
},
editCell: function(cell, index) {
cell = $(cell);
let that = this, colIndex = index === 0 || index ? index : that._calculateColumnIndex(cell), column = leafColumns(that.columns)[colIndex], model = that._modelForContainer(cell);
const stacked = that._isStackedMode();
const editClass = stacked ? "k-grid-stack-edit-cell" : "k-edit-cell";
let isPinnedCell = cell.closest(".k-grid-pinned-container").length > 0;
let pinnedUid, pinnedCellIndex;
if (!isPinnedCell && cell[0] && !cell[0].isConnected && cell.closest("tr").data("uid")) isPinnedCell = true;
if (isPinnedCell) {
pinnedUid = cell.closest("tr").data("uid");
pinnedCellIndex = cell.parent().children("td").index(cell);
}
that.closeCell();
if (isPinnedCell && pinnedUid) {
const pinnedRow = that.wrapper.find(".k-grid-pinned-container tr[data-uid='" + pinnedUid + "']");
if (pinnedRow.length) cell = pinnedRow.children("td").eq(pinnedCellIndex);
}
const cellToEdit = stacked ? cell.find(".k-grid-stack-content") : cell;
if (model && isColumnEditable(column, model) && !column.command) {
if (that.trigger(BEFOREEDIT, { model })) return;
that._attachModelChange(model);
that._editContainer = cellToEdit;
if (that._shouldClearEditableState) that._clearEditableState();
cell.addClass(editClass);
const skipFocus = (that._isVirtualIncellEditable() || that._hasVirtualColumns()) && that._editableState;
that.editable = cellToEdit.kendoEditable({
fields: editField(column, that._isAdaptive() ? "auto" : "none"),
model,
size: that.options.size,
target: that,
change: function(e) {
if (that.trigger(SAVE, {
values: e.values,
container: cell,
model
})) e.preventDefault();
},
skipFocus
}).data("kendoEditable");
let tr = cell.closest(TR);
if (!stacked) tr.addClass("k-grid-edit-row");
if (model.new === true && !stacked) {
tr.addClass("k-grid-add-row");
delete model.new;
}
if (that.lockedContent) {
adjustRowHeight(tr[0], that._relatedRow(tr).addClass("k-grid-edit-row")[0]);
if (tr.hasClass("k-grid-add-row")) that._relatedRow(tr).addClass("k-grid-add-row");
that._syncLockedScroll();
}
if (isPinnedCell && that.options.navigatable) that._setCurrent(cell, false, true);
that.trigger(EDIT, {
container: cell,
model
});
that._toggleToolbarEditingItemsVisibility();
}
},
enableEditing: function() {
let that = this, toolbar = that.wrapper.find(".k-grid-toolbar");
if (!that._isEditableEnabled) {
that._isEditableEnabled = true;
that._editable();
let addButton = toolbar.find(".k-grid-add").getKendoButton();
let editButton = toolbar.find(".k-grid-edit-command").getKendoButton();
let removeButton = toolbar.find(".k-grid-remove-command").getKendoButton();
let cancelChangesButton = toolbar.find(".k-grid-cancel-changes").getKendoButton();
let saveChangesButton = toolbar.find(".k-grid-save-changes").getKendoButton();
let cancelButton = toolbar.find(".k-grid-cancel-command").getKendoButton();
let saveButton = toolbar.find(".k-grid-save-command").getKendoButton();
if (addButton) addButton.bind("click", that._createClickHandler);
if (editButton) editButton.bind("click", that._editClickHandler);
if (removeButton) removeButton.bind("click", that._destroyClickHandler);
if (cancelChangesButton) cancelChangesButton.bind("click", that._cancelClickHandler);
if (saveChangesButton) saveChangesButton.bind("click", that._saveClickHandler);
if (cancelButton) cancelButton.bind("click", that._editCancelClickHandler);
if (saveButton) saveButton.bind("click", that._updateClickHandler);
}
that._toggleToolbarEditingItemsVisibility();
},
disableEditing: function() {
let that = this;
if (that._isEditableEnabled) {
if (that._editMode() === "incell") that.closeCell();
else that.cancelRow();
that._clearEditableState();
that._destroyEditable();
if (that.editableUserEvents) {
that.editableUserEvents.destroy();
that.editableUserEvents = null;
}
that._removeEditableClickHandlers();
that._isEditableEnabled = false;
that._toggleToolbarEditingItemsVisibility();
}
},
_removeEditableClickHandlers: function() {
let that = this, toolbar = that.wrapper.find(".k-grid-toolbar");
that.wrapper.off("click.kendoGrid", "tbody>tr:not(.k-detail-row,.k-grouping-row):visible .k-grid-edit-command", that._editCommandClickHandler);
that.wrapper.off("click.kendoGrid", "tbody>tr:not(.k-detail-row,.k-grouping-row):visible .k-grid-remove-command", that._removeCommandClickHandler);
toolbar.off("click.kendoGrid", ".k-grid-add", that._createClickHandler);
toolbar.off("click.kendoGrid", ".k-grid-edit-command", that._editClickHandler);
toolbar.off("click.kendoGrid", ".k-grid-remove-command", that._destroyClickHandler);
let addButton = toolbar.find(".k-grid-add").getKendoButton();
let editButton = toolbar.find(".k-grid-edit-command").getKendoButton();
let removeButton = toolbar.find(".k-grid-remove-command").getKendoButton();
let cancelChangesButton = toolbar.find(".k-grid-cancel-changes").getKendoButton();
let saveChangesButton = toolbar.find(".k-grid-save-changes").getKendoButton();
let cancelButton = toolbar.find(".k-grid-cancel-command").getKendoButton();
let saveButton = toolbar.find(".k-grid-save-command").getKendoButton();
if (addButton) addButton.unbind("click");
if (editButton) editButton.unbind("click");
if (removeButton) removeButton.unbind("click");
if (cancelChangesButton) cancelChangesButton.unbind("click");
if (saveChangesButton) saveChangesButton.unbind("click");
if (cancelButton) cancelButton.unbind("click");
if (saveButton) saveButton.unbind("click");
that._editCommandClickHandler = null;
that._removeCommandClickHandler = null;
},
_adjustLockedHorizontalScrollBar: function() {
var table = this.table, content = table.parent();
var scrollbar = table[0].offsetWidth > content[0].clientWidth ? kendo.support.scrollbar() : 0;
this.lockedContent.height(content[0].offsetHeight - scrollbar);
},
_syncLockedScroll: function() {
this.lockedContent[0].scrollTop = this.content[0].scrollTop;
if (this.virtualScrollable) this.lockedContent[0].scrollTop = this.wrapper.find(".k-virtual-scrollable-wrap")[0].scrollTop;
},
_syncLockedContentHeight: function() {
if (this.lockedTable) {
if (!this.touchScroller) this._adjustLockedHorizontalScrollBar();
this._adjustRowsHeight(this.table, this.lockedTable);
}
},
_syncLockedHeaderHeight: function() {
if (this.lockedHeader) {
var lockedTable = this.lockedHeader.children("table");
var table = this.thead.parent();
this._adjustRowsHeight(lockedTable, table);
syncTableHeight(lockedTable, table);
}
},
_syncLockedFooterHeight: function() {
if (this.lockedFooter && this.footer && this.footer.length) this._adjustRowsHeight(this.lockedFooter.children("table"), this.footer.find(".k-grid-footer-wrap > table"));
},
_destroyEditable: function() {
let that = this;
const component = that._editContainer && that._editContainer.length && that._editContainer.closest(".k-window").length ? "kendoWindow" : "kendoActionSheet";
let destroy = function() {
if (that.editable) {
let container = that.editView ? that.editView.element : that._editContainer;
let window = that._editContainer.data(component);
if (container) {
if (window) container = window.wrapper;
container.off("click.kendoGrid", ".k-grid-cancel-command, button[ref-cancel-button], [ref-actionsheet-action-button]:not(.k-button-primary)", that._editCancelClickHandler);
container.off("click.kendoGrid", ".k-grid-save-command, button[ref-update-button], [ref-actionsheet-action-button].k-button-primary", that._editUpdateClickHandler);
}
that._detachModelChange();
that.editable.destroy();
that.editable = null;
if (window) window.destroy();
that._editContainer = null;
that._destroyEditView();
that._editableIsClosing = null;
}
};
if (that.editable) if (that._editMode() === "popup" && !that._isMobile) if (that._editableIsClosing) that._editContainer.data(component).bind("deactivate", destroy);
else {
that._editableIsClosing = true;
that._editContainer.data(component).bind("deactivate", destroy).close();
}
else destroy();
if (that._confirmDialog) {
that._confirmDialog.close();
that._confirmDialog.destroy();
that._confirmDialog = null;
}
},
_destroyEditView: function() {
if (this.editView) {
this.editView.purge();
this.editView = null;
this.pane.navigate("");
}
},
_attachModelChange: function(model) {
var that = this;
that._modelChangeHandler = function(e) {
that._modelChange({
field: e.field,
model: this
});
};
model.bind("change", that._modelChangeHandler);
},
_detachModelChange: function() {
var that = this, container = that._editContainer, model = that._modelForContainer(container);
if (model) model.unbind(CHANGE, that._modelChangeHandler);
},
closeCell: function(isCancel) {
let that = this, cell = that._editContainer, column, tr, model, errors;
if (!cell) return;
model = that._modelForContainer(cell);
if (isCancel && that.trigger("cancel", {
container: cell,
model
})) return;
const stacked = that._isStackedMode();
const editClass = stacked ? "k-grid-stack-edit-cell" : "k-edit-cell";
const editCell = cell.closest(DOT + editClass);
that.trigger(CELLCLOSE, {
type: isCancel ? "cancel" : "save",
model,
container: cell
});
const index = stacked ? editCell.parent().children().index(editCell) : that._calculateColumnIndex(cell);
if (stacked) editCell.removeClass(editClass);
else cell.removeClass(editClass);
column = leafColumns(that.columns)[index];
errors = that.editable && that.editable.validatable && that.editable.validatable.errors();
if (isCancel && model.dirtyFields && model.dirtyFields[column.field] && errors.length) delete model.dirtyFields[column.field];
tr = cell.closest(TR).removeClass("k-grid-edit-row");
if (tr.hasClass("k-grid-add-row")) tr.removeClass("k-grid-add-row");
if (that.lockedContent) {
const relatedTr = that._relatedRow(tr);
relatedTr.removeClass("k-grid-edit-row");
if (relatedTr.hasClass("k-grid-add-row")) relatedTr.removeClass("k-grid-add-row");
}
that._destroyEditable();
that._displayCell(cell, column, model);
if (that._shouldClearEditableState) that._clearEditableState();
that.trigger("itemChange", {
item: tr,
data: model,
ns: ui
});
if (that._activeStackedCell) that._setCurrentStackedCell(cell);
if (that.lockedContent) {
const rowUID = tr && tr.data("uid");
const heightValue = (that._cachedRowsHeight && that._cachedRowsHeight[rowUID]) ?? "";
adjustRowHeight(tr.css(HEIGHT, heightValue)[0], that._relatedRow(tr).css(HEIGHT, heightValue)[0]);
}
that._renderPinnedRows();
},
_displayCell: function(cell, column, dataItem) {
var that = this, state = {
storage: {},
count: 0
}, settings = extend({}, kendo.Template, that.options.templateSettings), tmpl = kendo.template(that._cellTmpl(column, state), settings);
if (state.count > 0) tmpl = tmpl.bind(state.storage);
cell.empty().html(tmpl(dataItem));
},
removeRow: function(row) {
if (!this._confirmation(row)) return;
this._removeRow(row);
},
_removeRow: function(row) {
var that = this, model, modelId, key, schema, mode = that._editMode();
if (mode !== "incell") that.cancelRow();
row = $(row);
if (that.lockedContent) row = row.add(that._relatedRow(row));
row = row.hide();
if (that.dataSource._isGroupPaged()) that._removeGroupIfEmpty(row);
model = that._modelForContainer(row);
if (model != undefined && model.hasOwnProperty("_isMoved")) delete model._isMoved;
if (model && !that.trigger(REMOVE, {
row,
model
})) {
schema = that.dataSource.options.schema;
if (that._selectedIds && schema && schema.model) {
modelId = that._getSchemaIdField();
key = model[modelId];
delete that._selectedIds[key];
}
that.dataSource.remove(model);
if (mode === "inline" || mode === "popup") that.dataSource.sync();
} else if (mode === "incell") that._destroyEditable();
},
_editMode: function() {
let mode = "incell", editable = this.options.editable;
if (editable !== true) if (typeof editable == "string") mode = editable;
else mode = editable.mode || mode;
return mode;
},
editRow: function(row) {
let model, that = this;
if (row instanceof ObservableObject) model = row;
else {
row = $(row);
model = that._modelForContainer(row);
}
let mode = that._editMode();
let container;
const isPinnedRow = row instanceof $ && row.closest(".k-grid-pinned-container").length > 0;
that.cancelRow();
if (model) {
if (isPinnedRow) row = that.wrapper.find(".k-grid-pinned-container tr[" + kendo.attr("uid") + "=" + model.uid + "]");
else row = that.tbody.children("[" + kendo.attr("uid") + "=" + model.uid + "]");
that._attachModelChange(model);
if (mode === "popup") that._createPopupEditor(model);
else if (mode === "inline") that._createInlineEditor(row, model);
else if (mode === "incell") {
const stacked = that._isStackedMode();
(stacked ? row.find(".k-grid-stack-cell:not(.k-command-cell):not(.k-drag-cell)") : row.children(DATA_CELL)).each(function() {
let cell = $(this);
const index = stacked ? cell.parent().children().index(cell) : that._calculateColumnIndex(cell);
let column = leafColumns(that.columns)[index];
model = that._modelForContainer(cell);
if (model && (!model.editable || model.editable(column.field)) && column.field && !column.selectable && !column.draggable && !column.pinnable) {
that.editCell(cell, index);
return false;
}
});
}
if (that.editView) container = that.editView.element;
else if (mode === "popup") container = that._editContainer?.parent();
else container = that._editContainer;
if (container) {
if (!this._editCancelClickHandler) this._editCancelClickHandler = this._editCancelClick.bind(this);
container.on("click.kendoGrid", ".k-grid-cancel-command, button[ref-cancel-button], [ref-actionsheet-action-button]:not(.k-button-primary)", this._editCancelClickHandler);
if (!this._editUpdateClickHandler) this._editUpdateClickHandler = this._editUpdateClick.bind(this);
container.on("click.kendoGrid", ".k-grid-save-command, button[ref-update-button], [ref-actionsheet-action-button].k-button-primary", this._editUpdateClickHandler);
}
that._toggleToolbarEditingItemsVisibility();
}
},
_editUpdateClick: function(e) {
e.preventDefault();
if (e.stopPropagation) e.stopPropagation();
else if (e.event && e.event.stopPropagation) e.event.stopPropagation();
this.saveRow();
this._preventOnCloseEditableChanges = this._editMode() === "popup";
this.one(DATABOUND, () => {
this._toggleToolbarEditingItemsVisibility();
});
},
_editCancelClick: function(e) {
var that = this;
var navigatable = that.options.navigatable;
var model = that.editable.options.model;
var container = that.editView ? that.editView.element : that._editContainer;
e.preventDefault();
if (e.stopPropagation) e.stopPropagation();
else if (e.event && e.event.stopPropagation) e.event.stopPropagation();
if (that.trigger("cancel", {
container,
model
})) return;
var currentIndex = that.items().index($(that.current()).parent());
that.cancelRow();
if (navigatable) {
that._setCurrent(that.items().eq(currentIndex).children().filter(NAVCELL).first());
focusTable(that.table, true);
}
this._toggleToolbarEditingItemsVisibility();
},
_editFields: function(columns, model) {
var fields = [];
var column;
for (var idx = 0; idx < columns.length; idx++) {
column = columns[idx];
if (column.selectable || column.command) continue;
if (isColumnEditable(column, model)) fields.push(editField(column, this._isAdaptive() ? "auto" : "none"));
}
return fields;
},
_createPopupEditor: function(model) {
var that = this;
var html = "<div " + kendo.attr("uid") + "=\"" + model.uid + "\" ref=\"popup-edit-form\"><" + (that._isMobile ? "ul class=\"k-edit-form-container k-listgroup k-listgroup-flush\">" : "div class=\"k-edit-form-container\">");
var column;
var command;
var idx;
var length;
var tmpl;
var updateText;
var cancelText;
var updateIconClass;
var cancelIconClass;
var tempCommand;
var columns = leafColumns(that.columns);
var attr;
var editMenuGuid = kendo.guid();
var editable = that.options.editable;
var template = editable.template;
var options = isPlainObject(editable) ? editable.window : {};
var settings = extend({}, kendo.Template, that.options.templateSettings);
var state;
var container;
var buttonsHTML;
const isAdaptive = that._isAdaptive();
if (that.trigger(BEFOREEDIT, { model })) return;
options = options || {};
if (template) {
if (typeof template === STRING) template = kendo.unescape(template);
html += kendo.template(template, settings)(model);
for (idx = 0, length = columns.length; idx < length; idx++) {
column = columns[idx];
if (column.command) {
tempCommand = getCommand(column.command, "edit");
if (tempCommand) command = tempCommand;
}
}
} else for (idx = 0, length = columns.length; idx < length; idx++) {
column = columns[idx];
if (column.selectable) continue;
if (!column.command) {
if (that._isMobile) {
html += "<li class=\"k-item k-listgroup-item\">";
if (isColumnEditable(column, model)) {
html += "<label class=\"k-label k-listgroup-form-row\">";
html += "<span class=\"k-item-title k-listgroup-form-field-label\">" + (column.title && (that.options.encodeTitles ? htmlEncode(column.title, true) : column.title) || column.field || "") + "</span>";
html += "<div class=\"k-listgroup-form-field-wrapper\" id=\"" + column.field + "_" + editMenuGuid + "\" " + kendo.attr("container-for") + "=\"" + column.field + "\"></div>";
html += "</label>";
} else {
state = {
storage: {},
count: 0
};
tmpl = kendo.template(that._cellTmpl(column, state), settings);
if (state.count > 0) tmpl = tmpl.bind(state.storage);
html += "<label class=\"k-label k-listgroup-form-row k-no-click\">";
html += "<span class=\"k-item-title k-listgroup-form-field-label\">" + (column.title && (that.options.encodeTitles ? htmlEncode(column.title, true) : column.title) || column.field || "") + "</span>";
html += "<span class=\"k-no-editor k-listgroup-form-field-wrapper\">" + tmpl(model) + "</span>";
html += "</label>";
}
html += "</li>";
}
} else if (column.command) {
tempCommand = getCommand(column.command, "edit");
if (tempCommand) command = tempCommand;
}
}
if (command) {
if (isPlainObject(command)) {
if (isPlainObject(command.text)) {
updateText = command.text.update;
cancelText = command.text.cancel;
}
if (isPlainObject(command.iconClass)) {
updateIconClass = command.iconClass.update;
cancelIconClass = command.iconClass.cancel;
}
if (command.attr) attr = command.attr;
}
}
if (!cancelText) cancelText = that.options.messages.commands.canceledit;
if (!updateText) updateText = that.options.messages.commands.update;
if (!that._isMobile) {
let updateButton = $(that._createButton({
name: "update",
text: updateText,
attr,
iconClass: updateIconClass,
skipCommandClass: true,
skipTabIndex: true
})).attr("ref-update-button", "");
let cancelButton = $(that._createButton({
name: "canceledit",
text: cancelText,
attr,
iconClass: cancelIconClass,
skipCommandClass: true,
skipTabIndex: true
})).attr("ref-cancel-button", "");
html += "</div>";
if (isAdaptive) {
const editTitle = that.options.messages.commands.edit || "Edit record";
const addTitle = that.options.messages.commands.add || "Add new record";
container = that._editContainer = $(html).appendTo("body").eq(0).kendoActionSheet({
modal: true,
adaptive: true,
title: model.id ? editTitle : addTitle,
fullscreen: that.smallMQL.mediaQueryList.matches,
closeButton: true,
actionButtons: [{
text: cancelText,
icon: "cancel"
}, {
text: updateText,
icon: "save",
themeColor: "primary"
}],
open: function(e) {
e.sender.element.removeClass("k-popup");
that.editable.element.focus();
},
close: function(e) {
e.sender.element.trigger("focus");
if (!that._preventOnCloseEditableChanges) {
if (that.trigger("cancel", {
container,
model
})) {
e.preventDefault();
return;
}
}
var currentIndex = that.items().index($(that.current()).parent());
if (!that._preventOnCloseEditableChanges) {
that._editableIsClosing = true;
that.cancelRow(false, true);
}
if (that.options.navigatable) if (that._isStackedMode()) that._setCurrentStackedCell();
else {
that._setCurrent(that.items().eq(currentIndex).children().filter(NAVCELL).first());
focusTable(that.table, true);
}
that._toggleToolbarEditingItemsVisibility();
}
});
} else container = that._editContainer = $(html).appendTo(that.wrapper).eq(0).kendoWindow(extend({
modal: true,
resizable: false,
draggable: true,
title: that.options.messages.commands.edit || "Edit",
_footerTemplate: () => `<div class="k-actions k-actions-start k-actions-horizontal k-window-actions">` + updateButton[0].outerHTML + cancelButton[0].outerHTML + `</div>`,
visible: false,
close: function(e) {
if (e.userTriggered) {
e.sender.element.trigger("focus");
if (that.trigger("cancel", {
container,
model
})) {
e.preventDefault();
return;
}
var currentIndex = that.items().index($(that.current()).parent());
that._editableIsClosing = true;
that.cancelRow();
that._toggleToolbarEditingItemsVisibility();
if (that._isStackedMode()) that._setCurrentStackedCell();
else {
that._setCurrent(that.items().eq(currentIndex).children().filter(NAVCELL).first());
focusTable(that.table, true);
}
}
}
}, options));
} else {
html += "</ul></div>";
let cancelText = encode(that.options.messages.commands.cancel);
let updateText = encode(that.options.messages.commands.update);
that.editView = that.pane.append("<div data-" + kendo.ns + "role=\"view\" class=\"k-grid-edit-form\"><div data-" + kendo.ns + " class=\"k-appbar k-appbar-primary\">" + kendo.html.renderButton(`<button class="k-header-cancel k-grid-cancel-command" title="${cancelText}" aria-label="${cancelText}"></button>`, {
fillMode: "flat",
icon: "chevron-left"
}) + `<span class="k-spacer"></span><span>${encode(that.options.messages.commands.edit || "Edit")}</span><span class="k-spacer"></span>` + kendo.html.renderButton(`<button class="k-header-done k-grid-save-command" title="${updateText}" aria-label="${updateText}"></button>`, {
fillMode: "flat",
icon: "check"
}) + "</div><div data-" + kendo.ns + "role=\"content\" class=\"" + classNames.content + "\">" + html + "</div></div>");
container = that._editContainer = that.editView.element.find("[ref='popup-edit-form']");
}
if (!template && !that._isMobile) {
that.editable = new ui.Form(that._editContainer.find(".k-edit-form-container"), {
items: that._editFields(columns, model),
buttonsTemplate: () => "",
formData: model,
size: that._isAdaptive() ? "large" : "medium"
}).editable;
that._editContainer.append(buttonsHTML);
if (isAdaptive) that.editable.element.removeClass("k-edit-form-container");
} else {
that.editable = that._editContainer.kendoEditable({
fields: that._isMobile && !template ? that._editFields(columns, model) : null,
model,
clearContainer: false,
target: that,
skipFocus: true
}).data("kendoEditable");
if (isAdaptive) that.editable.element.find(".k-edit-form-container").removeClass("k-edit-form-container");
}
that._openPopUpEditor(isAdaptive);
that.trigger(EDIT, {
container,
model
});
},
_openPopUpEditor: function(isAdaptive) {
var that = this;
const component = isAdaptive ? "kendoActionSheet" : "kendoWindow";
var editor = that._editContainer ? that._editContainer.data(component) : null;
var windowOptions = (that.options.editable || {}).window || {};
if (!this._isMobile) {
if (editor) {
if (!isAdaptive && !windowOptions.position) editor.center();
else if (isAdaptive) editor.fullscreen(that.smallMQL.mediaQueryList.matches);
editor.open();
}
} else this.pane.navigate(this.editView, this._editAnimation);
},
_createInlineEditor: function(row, model) {
var that = this;
var column;
var cell;
var command;
var fields = [];
const stacked = that._isStackedMode();
if (that.trigger(BEFOREEDIT, { model })) return;
if (that.lockedContent) row = row.add(that._relatedRow(row));
let cells = stacked ? row.children(":not(.k-group-cell,.k-hierarchy-cell)").find(".k-grid-stack-cell:not(.k-drag-cell)") : row.children(":not(.k-group-cell,.k-hierarchy-cell,.k-drag-cell)");
const columns = stacked ? leafColumns(visibleColumns(that.columns)) : leafColumns(that.columns);
if (that.options.navigatable && stacked) removeElementsFromTab(cells);
cells.each(function() {
cell = $(this);
column = columns[that._calculateColumnIndex(cell)];
if (!column) return;
if (!column.command && isColumnEditable(column, model)) {
fields.push(editField(column, that._isAdaptive() ? "auto" : "none"));
let target = stacked ? cell.children(".k-grid-stack-content") : cell;
target.attr(kendo.attr("container-for"), column.field);
target.empty();
} else if (column.command) {
command = getCommand(column.command, "edit");
if (command) {
cell.empty();
var updateText, cancelText, updateIconClass, cancelIconClass, attr;
if (isPlainObject(command)) {
if (isPlainObject(command.text)) {
updateText = command.text.update;
cancelText = command.text.cancel;
}
if (isPlainObject(command.iconClass)) {
updateIconClass = command.iconClass.update;
cancelIconClass = command.iconClass.cancel;
}
if (command.attr) attr = command.attr;
}
$(that._createButton({
name: "update",
text: updateText,
attr,
iconClass: updateIconClass,
skipTabIndex: true
}) + that._createButton({
name: "canceledit",
text: cancelText,
attr,
iconClass: cancelIconClass,
skipTabIndex: true
})).appendTo(cell);
}
}
});
that._editContainer = row;
that._editContainer.addClass("k-grid-edit-row");
if (model.new === true) {
that._editContainer.addClass("k-grid-add-row");
delete model.new;
}
if (that._shouldClearEditableState) that._clearEditableState();
that.editable = new kendo.ui.Editable(that._editContainer, {
target: that,
fields,
size: that.options.size,
model,
skipFocus: that._isVirtualInlineEditable() && that._editableState && (that._editableState.field ? true : false) || that._hasVirtualColumns(),
clearContainer: false
});
if (row.length > 1) {
adjustRowHeight(row[0], row[1]);
that._applyLockedContainersWidth(true);
}
if (stacked) cells.addClass("k-grid-stack-edit-cell");
that.trigger(EDIT, {
container: row,
model
});
},
cancelRow: function(notify) {
var that = this, container = that._editContainer, model;
if (container) {
model = that._modelForContainer(container);
if (!model || notify && that.trigger("cancel", {
container,
model
})) return;
that._destroyEditable();
that.dataSource.cancelChanges(model);
that._clearEditableState();
if (that._editMode() !== "popup") that._displayRow(container);
else that._displayRow(that.tbody.find("[" + kendo.attr("uid") + "=" + model.uid + "]"));
that._renderPinnedRows();
that._aria();
}
},
saveRow: function() {
var that = this;
var container = this._editContainer;
var model = this._modelForContainer(container);
var deferred = $.Deferred();
var valid;
if (!container || !this.editable) return deferred.resolve().promise();
valid = that.editable && that.editable.end();
if (!valid || this.trigger(SAVE, {
container,
model
})) {
if (!valid) that._scrollVirtualWrapper();
return deferred.reject().promise();
}
if (this._editMode() === "popup") {
const selector = "[ref-update-button]";
let uploadButton = container.find(selector);
if (!uploadButton?.length) uploadButton = container.parent().find(selector);
if (uploadButton?.length) uploadButton?.addClass("k-disabled").attr("aria-disabled", true);
}
that._clearEditableState();
return this.dataSource.sync();
},
_displayRow: function(row) {
var that = this, model = that._modelForContainer(row), related, newRow, nextRow, isSelected = row.hasClass(SELECTED), isAlt = row.hasClass("k-table-alt-row");
if (model) {
if (that.lockedContent) {
related = $((isAlt ? that.lockedAltRowTemplate : that.lockedRowTemplate)(model));
kendo.applyStylesFromKendoAttributes(related, ["display"]);
that._relatedRow(row.last()).replaceWith(related);
}
newRow = $((isAlt ? that.altRowTemplate : that.rowTemplate)(model));
if (!row.is(":visible")) newRow.hide();
kendo.applyStylesFromKendoAttributes(newRow, ["display"]);
if (that._anyStickyColumns()) kendo.applyStylesFromKendoAttributes(newRow, ["left", "right"]);
row.replaceWith(newRow);
that.trigger("itemChange", {
item: newRow,
data: model,
ns: ui
});
if (related && related.length) that.trigger("itemChange", {
item: related,
data: model,
ns: ui
});
if (isSelected && (that.options.selectable || that._checkBoxSelection)) that.select(newRow.add(related));
if (related) adjustRowHeight(newRow[0], related[0]);
nextRow = newRow.next();
if (nextRow.hasClass("k-detail-row") && nextRow.is(":visible")) if (that._isStackedMode()) {
const expandBtn = newRow.find("[ref=\"expand-detail-button\"]");
if (expandBtn.length) expandBtn.replaceWith($(kendo.html.renderButton(`<button tabindex='-1' ref="collapse-detail-button" aria-label="${COLLAPSE}">${kendo.htmlEncode(that.options.messages.details.collapse)}</button>`, {
icon: "minus",
fillMode: "flat",
themeColor: "primary"
})));
} else {
const iconEl = newRow.find(".k-hierarchy-cell .k-icon,.k-hierarchy-cell .k-svg-icon");
if (iconEl.length) kendo.ui.icon(iconEl, { icon: "chevron-down" });
}
}
},
_showMessage: function(messages, row) {
var that = this;
if (!that._isMobile) return window.confirm(messages.title);
(that._confirmDialog = new kendo.ui.Confirm($("<div />").appendTo(document.body), {
modal: { preventScroll: true },
closable: false,
title: false,
content: messages.title,
messages: {
okText: messages.confirmDelete,
cancel: messages.cancelDelete
},
open: function() {
if (that.content) {
that.content.data(OVERFLOW, that.content.css(OVERFLOW));
that.content.css(OVERFLOW, HIDDEN);
}
},
close: function() {
if (that.content) that.content.css(OVERFLOW, that.content.data(OVERFLOW));
}
})).result.done(function() {
that._removeRow(row);
}).fail(function() {
var confirmDialog = that._confirmDialog;
if (confirmDialog) {
confirmDialog.close();
confirmDialog.destroy();
}
});
return false;
},
_confirmation: function(row) {
var that = this, editable = that.options.editable, confirmation = editable === true || typeof editable === STRING ? that.options.messages.editable.confirmation : editable.confirmation;
if (isPlainObject(editable) && typeof editable.mode === STRING && typeof confirmation !== FUNCTION && typeof confirmation !== STRING && confirmation !== false) confirmation = that.options.messages.editable.confirmation;
if (confirmation !== false && confirmation != null) {
if (typeof confirmation === FUNCTION) confirmation = confirmation(that._modelForContainer(row));
return that._showMessage({
confirmDelete: editable.confirmDelete || that.options.messages.editable.confirmDelete,
cancelDelete: editable.cancelDelete || that.options.messages.editable.cancelDelete,
title: confirmation === true ? that.options.messages.editable.confirmation : confirmation
}, row);
}
return true;
},
cancelChanges: function() {
var that = this;
if (that._cachedRowsHeight) {
that._mapCachedRowsHeight("getByUid", "id");
that._shouldMapHights = true;
}
that.dataSource.cancelChanges();
if (that._isVirtualEditable()) that._virtualPageToTop(function() {
that.virtualScrollable.scrollToTop();
});
},
saveChanges: function() {
var that = this;
var valid = that.editable && that.editable.end();
if ((valid || !that.editable) && !that.trigger(SAVECHANGES)) that.dataSource.sync();
else if (!valid) that._scrollVirtualWrapper();
},
addRow: function() {
var that = this, index, dataSource = that.dataSource, mode = that._editMode(), createAt = that.options.editable.createAt || "", pageSize = dataSource.pageSize(), view = dataSource.view() || [];
var createAtBottom = createAt.toLowerCase() === BOTTOM;
var model;
var virtualEditable = that._isVirtualEditable();
if (that.editable && that.editable.end() || !that.editable) {
if (mode != "incell") that.cancelRow();
index = dataSource.indexOf(view[0]);
if (createAtBottom) {
index += view.length;
if (pageSize && !dataSource.options.serverPaging && pageSize <= view.length) index -= 1;
}
if (index < 0) if (dataSource.page() > dataSource.totalPages()) index = (dataSource.page() - 1) * pageSize;
else index = 0;
if (that.options.navigatable && mode == "incell") that._removeCurrent();
if (virtualEditable) that._virtualAddRow();
else {
model = dataSource.insert(index, {});
model.new = true;
that._editModel(model);
}
} else that._scrollVirtualWrapper();
},
_editModel: function(model) {
var that = this;
var createAt = that.options.editable.createAt || "";
var mode = that._editMode();
if (model) {
var id = model.uid, row = (that.lockedContent ? that.lockedTable : that.table).find("tr[" + kendo.attr("uid") + "=" + id + "]");
const stacked = that._isStackedMode();
const cells = stacked ? row.find("td:not(.k-group-cell,.k-hierarchy-cell) .k-grid-stack-cell:not(.k-command-cell)") : row.children("td:not(.k-group-cell,.k-hierarchy-cell)");
const index = that._firstEditableColumnIndex(row);
const cell = cells.eq(index);
if (mode === "inline" && row.length) that.editRow(row);
else if (mode === "popup") that.editRow(model);
else if (cell.length) that.editCell(cell, stacked && index);
if (createAt.toLowerCase() == "bottom" && that.lockedContent) that.lockedContent[0].scrollTop = that.content[0].scrollTop = that.table[0].offsetHeight;
}
},
_virtualAddRow: function() {
var that = this;
var createAtBottom = (that.options.editable.createAt || "").toLowerCase() === BOTTOM;
that._clearEditableState();
if (createAtBottom) that._virtualAddRowAtBottom();
else that._virtualAddRowAtTop();
},
_virtualAddRowAtTop: function() {
var that = this;
var dataSource = that.dataSource;
var virtualScrollable = that.virtualScrollable;
var model;
if (dataSource.page() === 1) {
model = dataSource.insert(0, {});
model.new = true;
that._editModel(model);
virtualScrollable.scrollToTop();
} else that._virtualPageToTop(function() {
model = dataSource.insert(0, {});
model.new = true;
that._editModel(model);
virtualScrollable.scrollToTop();
});
},
_virtualAddRowAtBottom: function() {
var that = this;
var dataSource = that.dataSource;
var virtualScrollable = that.virtualScrollable;
var index = dataSource.total();
var model;
if (dataSource.at(index - 1) instanceof ObservableObject) {
model = dataSource.insert(index, {});
model.new = true;
that._virtualPageToBottom(function() {
that._editModel(model);
virtualScrollable.scrollToBottom();
});
} else that._virtualPageToBottom(function() {
model = dataSource.insert(index, {});
model.new = true;
that._editModel(model);
virtualScrollable.scrollToBottom();
});
},
_virtualPageToTop: function(callback) {
var that = this;
that._virtualPage(0, that.dataSource.take(), function() {
callback();
});
},
_virtualPageToBottom: function(callback) {
var that = this;
var dataSource = that.dataSource;
var take = dataSource.take();
var total = dataSource.total();
var skip = total > take ? total - take : 0;
that._virtualPage(skip, take, function() {
callback();
});
},
_virtualPage: function(skip, take, callback) {
var that = this;
if (that._isVirtualEditable()) {
that.virtualScrollable._preventScroll = true;
that.virtualScrollable._page(skip, take, callback);
}
},
_firstEditableColumnIndex: function(container) {
var that = this, column, columns = leafColumns(that.columns), idx, length, model = that._modelForContainer(container);
for (idx = 0, length = columns.length; idx < length; idx++) {
column = columns[idx];
if (model && (!model.editable || model.editable(column.field)) && !column.command && column.field && column.hidden !== true) return idx;
}
return -1;
},
_clickAdd: function(e) {
if (e.preventDefault) e.preventDefault();
this.addRow();
this._toggleToolbarEditingItemsVisibility();
},
_clickCancel: function(e) {
if (e.preventDefault) e.preventDefault();
this.cancelChanges();
this._toggleToolbarEditingItemsVisibility();
},
_clickExcel: function(e) {
const that = this;
if (e.preventDefault) e.preventDefault();
that._exportExcel();
},
_exportExcel: function(doneCallback) {
const that = this;
const deferred = $.Deferred();
that._isExport = true;
that._progress(true);
setTimeout(() => {
that.saveAsExcel(deferred);
deferred.always(() => {
that._progress(false);
that._isExport = false;
if (doneCallback && typeof doneCallback === FUNCTION) doneCallback();
});
}, 1);
},
_clickPdf: function(e) {
var that = this;
if (e.preventDefault) e.preventDefault();
that._exportPdf();
},
_exportPdf: function(doneCallback) {
const that = this;
that._isExport = true;
that._pdfInitialized = true;
that._progress(true);
var promise = that.saveAsPDF();
if (promise) promise.done(function() {
that._progress(false);
that._isExport = false;
that._pdfInitialized = false;
if (doneCallback && typeof doneCallback === FUNCTION) doneCallback();
});
else {
that._progress(false);
that._isExport = false;
that._pdfInitialized = false;
}
},
_clickCsv: function(e) {
if (e.preventDefault) e.preventDefault();
this._exportCsv();
},
_exportCsv: function(doneCallback) {
const that = this;
that._isExport = true;
that._progress(true);
setTimeout(() => {
const csvColumns = that._getCSVColumnsInfo();
that.toCSVString().then(function(csvString) {
const eventData = { csv: csvString };
if (!that.trigger("csvExport", eventData)) that._saveCSVToFile(eventData.csv, csvColumns.names);
that._progress(false);
that._isExport = false;
if (doneCallback && typeof doneCallback === FUNCTION) doneCallback();
});
}, 1);
},
_clickSave: function(e) {
if (e.preventDefault) e.preventDefault();
this.saveChanges();
},
_searchInput: function(e) {
var that = this, input = e.currentTarget;
clearTimeout(that._searchTimeOut);
that._searchTimeOut = setTimeout(function() {
that._search(input.value);
}, 300);
},
_pasteToolbarDropDown: function() {
var that = this;
if (that.wrapper.find(".k-grid-paste-action").length) that.pasteActionsDropDownList = that.wrapper.find(".k-grid-paste-action").kendoDropDownList({
dataSource: [{
value: "insert",
text: "Paste (Insert)"
}, {
value: "replace",
text: "Paste (Replace)"
}],
dataTextField: "text",
dataValueField: "value",
_allowFilterPaste: false
}).data("kendoDropDownList");
},
_pushExpression: function(filters, field, value) {
var that = this, isServerFiltering = that.dataSource.options.serverFiltering, defaultOperators = {
string: "contains",
number: "gte",
date: "gte",
enums: "eq",
boolean: "eq"
}, name = field.name || field, operator = field.operator, modelInfo = that.dataSource.reader.model && that.dataSource.reader.model.fields, fieldInfo = modelInfo && modelInfo[name], parseFn = fieldInfo && fieldInfo.parse, expression = {
field: name,
operator: operator || defaultOperators.string,
value
};
if ((operator || isServerFiltering) && fieldInfo && kendo.isFunction(parseFn) && parseFn(value) !== null) extend(expression, {
operator: operator || defaultOperators[fieldInfo.type],
value: parseFn(value)
});
if (isServerFiltering && fieldInfo && kendo.isFunction(parseFn) && parseFn(value) === null) return;
filters.push(expression);
},
_hasTool: function(selector) {
const tool = this.wrapper.find(`.k-grid-toolbar ${selector}`);
return {
present: tool.length > 0,
tool
};
},
_initToolbarItemsPopups: function() {
const that = this;
const columnsToolbarButton = that._hasTool(".k-toolbar-button.k-grid-column-menu[ref-toolbar-tool]");
const sortToolbarButton = that._hasTool(".k-toolbar-button.k-grid-sort-tool[ref-toolbar-tool]");
const filterToolbarTool = that._hasTool(".k-toolbar-button.k-grid-filter-tool[ref-toolbar-tool]");
const columnChooserTool = that._hasTool(".k-toolbar-button.k-grid-column-chooser[ref-toolbar-tool]");
const groupToolbarTool = that._hasTool(".k-toolbar-button.k-grid-group-tool[ref-toolbar-tool]");
const smartBoxTool = that._hasTool("[ref-grid-smartbox-input]");
if (columnsToolbarButton.present) that._globalColumnsMenu(columnsToolbarButton.tool);
if (columnChooserTool.present) that._columnChooserTool(columnChooserTool.tool);
if (sortToolbarButton.present) {
that._toggleBadge(sortToolbarButton.tool, that.dataSource.sort());
that._sortToolbarTool(sortToolbarButton.tool);
}
if (filterToolbarTool.present) {
that._toggleBadge(filterToolbarTool.tool, that.dataSource.filter());
that._filterToolbarTool(filterToolbarTool.tool);
}
if (groupToolbarTool.present) {
const groups = that.dataSource.group();
that._toggleBadge(groupToolbarTool.tool, groups && groups.length);
that._groupToolbarTool(groupToolbarTool.tool);
}
if (smartBoxTool.present) that._smartBoxTool(smartBoxTool.tool);
},
_unbindToolbarTools: function() {
this.wrapper.find(`
.k-toolbar-button.k-grid-column-menu[ref-toolbar-tool],
.k-toolbar-button.k-grid-sort-tool[ref-toolbar-tool],
.k-toolbar-button.k-grid-filter-tool[ref-toolbar-tool],
.k-toolbar-button.k-grid-column-chooser[ref-toolbar-tool],
.k-toolbar-button.k-grid-group-tool[ref-toolbar-tool],
.k-toolbar-button.k-grid-ai-assistant-tool[ref-toolbar-tool]
`).each(function() {
$(this).off("click.kendoGrid");
});
},
_ai: function() {
const that = this;
const hasAiTool = that._hasTool(".k-toolbar-button.k-grid-ai-assistant-tool[ref-toolbar-tool]");
if (hasAiTool.present) that._initAiAssistantWindow(hasAiTool.tool);
},
_defaultSearch: function(value) {
const that = this;
const smartBoxOptions = that.options.smartBox || {};
let searchFields = null;
if (smartBoxOptions && smartBoxOptions.searchSettings && smartBoxOptions.searchSettings.enabled !== false) searchFields = smartBoxOptions.searchSettings.searchFields || null;
that._search(value, searchFields);
},
_smartBoxTool: function(tool) {
const that = this;
const smartBoxOptions = that.options.smartBox || {};
if (!tool.length) return;
smartBoxOptions.size = that.options.size;
smartBoxOptions.rounded = "full";
if (smartBoxOptions.aiAssistantSettings) {
let serviceOptions = smartBoxOptions.aiAssistantSettings?.service || that.options.ai?.service || null;
smartBoxOptions.aiAssistantSettings.service = serviceOptions;
if (serviceOptions) {
serviceOptions = extend(true, { data: (prompt) => getDefaultAIRequestConfig(prompt, flatColumnsInDomOrder(that.columns)) }, serviceOptions);
smartBoxOptions.aiAssistantSettings.service = serviceOptions;
const userAiResponseHandler = smartBoxOptions.aiAssistantResponseSuccess;
smartBoxOptions.aiAssistantResponseSuccess = function(e) {
if (typeof userAiResponseHandler === "function") userAiResponseHandler.call(this, e);
if (!e.isDefaultPrevented()) that.handleAIResponse(e.response);
};
}
}
const userSearchHandler = smartBoxOptions.search;
smartBoxOptions.search = function(e) {
if (typeof userSearchHandler === "function") userSearchHandler.call(this, e);
if (!e.isDefaultPrevented()) that._defaultSearch(e.searchValue);
};
tool.kendoSmartBox(smartBoxOptions);
const smartBox = tool.data("kendoSmartBox");
if (smartBox) that._smartBox = smartBox;
},
_search: function(value, explicitFields) {
const that = this;
if (that._searchTimeOut) that._searchTimeOut = null;
const options = that.options;
const searchFields = explicitFields || (options.search ? options.search.fields : null);
let expression = {
filters: [],
logic: "or"
};
let fields = searchFields;
if (!fields) fields = getColumnsFields(options.columns);
if (that.dataSource.options.endless) {
that.dataSource.options.endless = null;
that._endlessPageSize = that.dataSource.options.pageSize;
}
if (value) for (let i = 0; i < fields.length; i++) that._pushExpression(expression.filters, fields[i], value);
else expression = {};
that.dataSource.filter(expression);
},
_toolbar: function() {
var that = this, wrapper = that.wrapper, toolbar = that.options.toolbar, container, items;
if (toolbar) {
that._createClickHandler = that._addClickHandler = that._clickAdd.bind(that);
that._editClickHandler = that._editToolbarClick.bind(that);
that._destroyClickHandler = that._removeToolbarClick.bind(that);
that._editCancelClickHandler = that._editCancelClick.bind(that);
that._updateClickHandler = that._editUpdateClick.bind(that);
that._cancelClickHandler = that._clickCancel.bind(that);
that._saveClickHandler = that._clickSave.bind(that);
that._excelClickHandler = that._clickExcel.bind(that);
that._pdfClickHandler = that._clickPdf.bind(that);
that._csvClickHandler = that._clickCsv.bind(that);
that._serachHandler = that._searchInput.bind(that);
container = that.wrapper.find(".k-grid-toolbar");
if (!container.length) {
container = $("<div class=\"k-grid-toolbar k-toolbar\" />").prependTo(wrapper);
if (typeof toolbar === STRING || isFunction(toolbar)) {
if (typeof toolbar === STRING) toolbar = kendo.template(toolbar).bind(that);
container.html(toolbar({ grid: that }));
that._attachToolbarClicks();
} else if (isArray(toolbar)) {
items = that._processItems(toolbar);
container.kendoToolBar({
navigateOnTab: !that.options.navigatable,
size: that.options.size,
items
});
} else if (isPlainObject(toolbar)) container.kendoToolBar({
navigateOnTab: !that.options.navigatable,
size: that.options.size,
items: that._processItems(toolbar.items || []),
overflow: toolbar.overflow
});
} else that._attachToolbarClicks();
if (that._checkBoxSelection) container.on("click.kendoGrid", ".k-select-checkbox", that._headerCheckboxClick.bind(that));
container.on("input.kendoGrid", ".k-grid-search input", this._serachHandler);
if (toolbar.overflow && toolbar.overflow.mode === "section") {
const toolbarElement = container.data("kendoToolBar");
toolbarElement.bind("overflowOpen", function() {
const itemsToCheck = toolbarElement.overflowSection.element.find(".k-toolbar-items-list");
that._toggleToolbarEditingItemsVisibility(itemsToCheck?.children(editableToolbarItemsSelector));
});
}
that._toggleToolbarEditingItemsVisibility();
}
},
_toggleToolbarEditingItemsVisibility: function(itemsToCheck) {
const that = this;
const hasChanges = that.dataSource.hasChanges() || that.element.find(".k-dirty").length > 0;
const toolbar = that.wrapper.find(".k-grid-toolbar");
if (!toolbar.length) return;
let toolbarItems;
if (that.options.toolbar && that.options.toolbar.overflow && that.options.toolbar.overflow.mode === "scroll") toolbarItems = toolbar.find(".k-toolbar-items").children(editableToolbarItemsSelector);
else if (itemsToCheck) toolbarItems = itemsToCheck;
else toolbarItems = toolbar.children(editableToolbarItemsSelector);
const showInactive = that.options.toolbar && that.options.toolbar.showInactiveTools || false;
const mode = that._editMode();
const editContainerVisible = that._editContainer && that._editContainer.length > 0 && that._editContainer.is(":visible");
const method = showInactive ? (element) => {
element.attr("aria-disabled", true);
element.addClass("k-disabled");
} : (element) => element.hide();
const selected = that.select();
const hasSelected = selected.length > 0;
const differentSelectionThanEditing = hasSelected && that._editContainer && that._editContainer.length > 0 && that._editContainer.is(":visible") && that._editContainer[0].getAttribute(kendo.attr("uid")) !== selected[selected.length - 1].getAttribute(kendo.attr("uid"));
const regex = getToolbarRegex({
mode,
hasSelected,
hasChanges,
editContainerVisible,
differentSelectionThanEditing: !differentSelectionThanEditing && differentSelectionThanEditing !== false ? true : differentSelectionThanEditing,
_editableIsClosing: that._editableIsClosing || false,
_isEditableEnabled: that._isEditableEnabled || false,
options: that.options
});
toolbarItems.show().removeClass("k-disabled").attr("aria-disabled", "false");
toolbarItems.each(function() {
const element = $(this);
const identifier = element.attr("class");
if (element.hasClass(FOCUSED)) {
element.removeClass(FOCUSED);
focusTable(that.table, true);
}
if (identifier && regex && regex.test(identifier)) method(element);
});
},
_attachToolbarClicks: function() {
var editable = this.options.editable, container = this.wrapper.find(".k-grid-toolbar");
if (editable && editable.create !== false) container.on("click.kendoGrid", ".k-grid-add", this._createClickHandler).on("click.kendoGrid", ".k-grid-cancel-changes", this._cancelClickHandler).on("click.kendoGrid", ".k-grid-save-changes", this._saveClickHandler);
if (editable && editable.update !== false) container.on("click.kendoGrid", ".k-grid-edit-command", this._editClickHandler).on("click.kendoGrid", ".k-grid-save-command", this._updateClickHandler).on("click.kendoGrid", ".k-grid-cancel-command", this._editCancelClickHandler);
if (editable.destroy !== false) container.on("click.kendoGrid", ".k-grid-remove-command", this._destroyClickHandler);
container.on("click.kendoGrid", ".k-grid-excel", this._excelClickHandler);
container.on("click.kendoGrid", ".k-grid-pdf", this._pdfClickHandler);
container.on("click.kendoGrid", ".k-grid-csv", this._csvClickHandler);
},
_processItems: function(tools) {
var that = this, options = that.options, items = [], messages = this.options.messages.commands, itemsCollectionHasSpacer = false;
tools.map((t) => {
var command, searchText, icon, className, inputSize, template = "";
if (typeof t === "string") {
command = t.toLowerCase();
t = {};
if (command !== "aiassistant") t.text = messages[command] || command;
} else {
command = t.name || t.text || "";
let isPredefinedTool = defaultCommands[command.toLowerCase()];
if (isPredefinedTool) command = command.toLowerCase();
if (command !== "aiassistant") {
const defaultText = isPredefinedTool ? resolveCommandText(t, messages) : t.text || command;
t.text = t.text === "" ? "" : defaultText;
}
}
if (!itemsCollectionHasSpacer && (command === "search" || command === "columns")) {
itemsCollectionHasSpacer = true;
items.push({ type: "spacer" });
}
if (command.toLowerCase() === "selectall") {
const label = t.text;
t.template = t.template || kendo.template(SELECTCOLUMNHEADERTMPL)({
size: kendo.getValidCssClass("k-checkbox-", "size", that.options.size),
label
});
}
if (command === "search") {
searchText = htmlEncode(t.text || messages.search, true);
icon = t.icon || t.iconClass || "search";
inputSize = kendo.getValidCssClass("k-input-", "size", that.options.size);
template += `<span class='k-searchbox k-input ${inputSize} k-grid-search'>`;
template += kendo.ui.icon({
icon,
iconClass: "k-input-icon"
});
template += "<input autocomplete='off' placeholder='" + searchText + "' title='" + searchText + "' aria-label='" + searchText + "' class='k-input-inner' />";
template += "</span>";
items.push({
name: "search",
overflow: "never",
template
});
} else if (command === "smartbox") items.push(extend({}, defaultCommands.smartbox, t, {}));
else if (command === "paste" && options.allowPaste) items.push({ template: "<input class='k-grid-paste-action' />" });
else {
if (!command && !(isPlainObject(t) && t.template)) throw new Error("Custom commands should have name specified");
t = extend({ type: "button" }, defaultCommands[command], t);
className = t.className || "k-grid-" + (command || "").replace(/\s/g, "");
t.attributes = that._processAttr(t.attr);
delete t.attr;
if (!!className) {
if (t.attributes["class"] === undefined) t.attributes["class"] = "";
t.attributes["class"] += " " + className;
}
if (t.template) delete t.type;
if (!!that["_" + command + "ClickHandler"]) t.click = that["_" + command + "ClickHandler"];
if (command === "canceledit") t.click = that._editCancelClickHandler;
items.push(t);
}
});
return items;
},
_processAttr: function(attr) {
var attributes = {}, attrArray;
if (typeof attr === STRING && attr.length > 0) {
attrArray = attr.split(" ");
attrArray.map((a) => {
var keyValue = a.split("=");
if (keyValue.length === 2) attributes[keyValue[0]] = keyValue[1].replaceAll("\"", "").replaceAll("'", "");
});
} else if (isPlainObject(attr)) attributes = attr;
return attributes;
},
_createButton: function(command) {
var button, template = command.template || COMMANDBUTTONTMPL, commandName = typeof command === STRING ? command : command.name || command.text, className = defaultCommands[commandName] ? defaultCommands[commandName].className : "k-grid-" + (commandName || "").replace(/\s/g, ""), options = {
className: command.skipCommandClass ? "" : className,
text: commandName,
attr: command.skipTabIndex ? "" : "tabindex=-1",
iconClass: "",
size: command.size || this.options.size
}, messages = this.options.messages.commands, attributeClassMatch;
if (!commandName && !(isPlainObject(command) && command.template)) throw new Error("Custom commands should have name specified");
if (isPlainObject(command)) {
command = extend(true, {}, command);
command.text = resolveCommandText(command, messages);
if (command.className && inArray(options.className, command.className.split(" ")) < 0) command.className += " " + options.className;
else if (command.className === undefined) command.className = options.className;
if (command.className.indexOf("k-primary") > -1) {
command.className = command.className.replace("k-primary", "");
command.themeColor = "primary";
}
if (commandName === "edit") {
command = extend(true, {}, command);
command.text = isPlainObject(command.text) ? command.text.edit : command.text;
command.iconClass = isPlainObject(command.iconClass) ? command.iconClass.edit : command.iconClass;
}
if (command.attr) {
if (isPlainObject(command.attr)) command.attr = stringifyAttributes(command.attr);
if (command.attr instanceof Function) {
let compiledAttributes = command.attr(command);
command.attr = stringifyAttributes(compiledAttributes);
}
if (typeof command.attr === STRING) {
attributeClassMatch = command.attr.match(/class="(.+?)"/);
if (attributeClassMatch && inArray(attributeClassMatch[1], command.className.split(" ")) < 0) command.className += " " + attributeClassMatch[1];
}
}
const additionalOptions = {};
if (commandName === "edit" || commandName === "update") additionalOptions.themeColor = "primary";
if (commandName === "destroy") additionalOptions.iconClass = "k-i-x";
options = extend(true, options, defaultCommands[commandName], additionalOptions, command);
} else {
const additionalOptions = { text: messages[commandName] };
if (commandName === "edit" || commandName === "update") additionalOptions.themeColor = "primary";
if (commandName === "destroy") additionalOptions.iconClass = "k-i-x";
options = extend(true, options, defaultCommands[commandName], additionalOptions);
}
button = kendo.template(template)(options);
if (!command.template) return kendo.html.renderButton($(button), options);
else return button;
},
_hasFooters: function() {
return !!this.footerTemplate || !!this.groupFooterTemplate || this.footer && this.footer.length > 0 || this.wrapper.find(".k-grid-footer").length > 0;
},
_groupable: function() {
var that = this;
if (that._groupableClickHandler) that.table.add(that.lockedTable).off("click.kendoGrid", that._groupableClickHandler);
else that._groupableClickHandler = function(e) {
var element = $(this), groupRow = element.closest(TR);
var group = that._groupRows ? that._groupRows[that.wrapper.find(".k-grouping-row").index(groupRow)] : {};
if (element.is(CARET_ALT_DOWN)) {
if (!that.trigger("groupCollapse", {
group,
element: groupRow
})) that.collapseGroup(groupRow);
} else if (!that.trigger("groupExpand", {
group,
element: groupRow
})) that.expandGroup(groupRow);
e.preventDefault();
e.stopPropagation();
};
if (that._isLocked()) that.lockedTable.on("click.kendoGrid", ".k-grouping-row " + CARET_ALT_RIGHT + ", .k-grouping-row a[class*='-i-chevron-down']", that._groupableClickHandler);
else that.table.on("click.kendoGrid", ".k-grouping-row " + CARET_ALT_RIGHT + ", .k-grouping-row a[class*='-i-chevron-down']", that._groupableClickHandler);
that._attachGroupable();
},
_toggleGroupableHeader: function(condition) {
const that = this;
const groupable = that.options.groupable;
const header = that.wrapper.find("div.k-grouping-header");
if (!(groupable && groupable.enabled !== false) || !header.length) return;
if (condition) header.removeClass("k-hidden");
else header.addClass("k-hidden");
},
_attachGroupable: function() {
var that = this, wrapper = that.wrapper, groupable = that.options.groupable, draggables = "th.k-header:not(.k-group-cell):not(.k-hierarchy-cell)[" + kendo.attr("field") + "]", filter = that.content ? ".k-grid-header:first " + draggables : "table:first>.k-grid-header " + draggables;
const stacked = that._isStackedMode();
if (stacked) filter = ".k-grid-stack-cell[data-field]";
if (groupable && groupable.enabled !== false) {
if (!wrapper.has("div.k-grouping-header")[0]) $("<div/>").addClass("k-grouping-header").prependTo(wrapper);
if (that.groupable) that._destroyGroupable();
if (browser.chrome) {
wrapper.find("div.k-grouping-header").css("touch-action", NONE);
wrapper.find(filter).css("touch-action", NONE);
}
that.wrapper.children(".k-grid-header").addClass("k-grid-draggable-header");
that.groupable = new ui.Groupable(wrapper, extend({}, groupable, {
draggable: !stacked ? that._draggableInstance : false,
groupContainer: ">div.k-grouping-header",
dataSource: that.dataSource,
draggableElements: !stacked ? filter : false,
filter,
size: that.options.size,
allowDrag: that.options.reorderable,
enableContextMenu: !!that.options.contextMenu,
removeGroup: function(e) {
that._showUngroupedColumn(e);
},
change: function(e) {
if (that.trigger("group", { groups: e.groups })) e.preventDefault();
else {
that._clearEditableState();
that._hideGroupedColumns(e.groups);
if (that.dataSource.options.endless) that._resetEndless();
}
},
_groupableFieldsData: stacked && that.columns
}));
if (stacked) that._toggleGroupableHeader(that.dataSource.group().length > 0);
that._addGroupableOptionsToHeader();
}
},
_showUngroupedColumn: function(group) {
var columns = leafColumns(this.columns);
var i;
for (i = 0; i < columns.length; i++) if (columns[i].uid == group.colID && columns[i].hideOnGroup) this.showColumn(columns[i]);
},
_hideGroupedColumns: function(groups) {
if (!groups) return;
var columns = leafColumns(this.columns);
var fields = [];
var i;
for (i = 0; i < groups.length; i++) if (groups[i].colID) fields.push(groups[i].colID);
for (i = 0; i < columns.length; i++) if (fields.indexOf(columns[i].uid) >= 0 && columns[i].hideOnGroup) this.hideColumn(columns[i]);
},
_resetEndless: function() {
var that = this;
that.dataSource.options.endless = null;
that._endlessPageSize = that.dataSource.options.pageSize;
that.dataSource._skip = 0;
that.dataSource._pageSize = that.dataSource._take = that._endlessPageSize;
that.dataSource._page = 1;
},
_addGroupableOptionsToHeader: function() {
var that = this;
var columns = flatColumns(that.columns);
var columnFieldMap = {};
var headerCells = that._headerCells();
var cellFieldAttr = "";
var headerCell;
var columnOptions;
var i;
for (i = 0; i < columns.length; i++) {
columns[i].field;
columnFieldMap[columns[i].field] = columns[i];
}
for (i = 0; i < headerCells.length; i++) {
headerCell = headerCells.eq(i);
cellFieldAttr = headerCell.attr(kendo.attr(FIELD));
columnOptions = columnFieldMap[cellFieldAttr];
if (columnOptions && columnOptions.groupable && columnOptions.groupable.sort) headerCell.data(GROUP_SORT, columnOptions.groupable.sort);
}
},
_destroyGroupable: function() {
var that = this;
if (that.groupable && that.groupable.element) that.groupable.element.kendoGroupable("destroy");
that.groupable = null;
that._removeGroupableOptionsFromHeader();
},
_hasStickyGroupHeaders: function() {
const groupable = this.options.groupable;
return groupable && groupable.stickyHeaders && this.options.scrollable;
},
_hasStickyGroupFooters: function() {
const groupable = this.options.groupable;
return groupable && groupable.stickyFooters && this.options.scrollable;
},
_isPinnable: function() {
return !!this.options.pinnable && !!this.options.scrollable;
},
_getPinnableRowLocation: function() {
const p = this.options.pinnable;
return isPlainObject(p) && p.pinRowLocation || "both";
},
_getIsRowPinnable: function() {
const p = this.options.pinnable;
return isPlainObject(p) && typeof p.isRowPinnable === FUNCTION ? p.isRowPinnable : null;
},
_checkRowPinnable: function(dataItem) {
const fn = this._getIsRowPinnable();
if (!fn) return true;
return !!fn({ dataItem });
},
_initPinColumn: function() {
const that = this;
const messages = that.options.messages.commands;
const pinRowLocation = that._getPinnableRowLocation();
if (pinRowLocation !== "both") {
that.wrapper.on("click.kendoGrid", ".k-pin-cell", function(e) {
const uid = $(e.target).closest(".k-pin-cell").closest("tr").data("uid");
const dataItem = uid ? that.dataSource.getByUid(uid) : null;
if (!dataItem || !that._checkRowPinnable(dataItem)) return;
if (that._getRowPinPosition(dataItem) !== "none") that.unpinRows(dataItem);
else that.pinRows(dataItem, pinRowLocation);
});
return;
}
that._pinMenu = new kendo.ui.ContextMenu($("<ul></ul>"), {
target: that.wrapper,
filter: ".k-pin-cell",
showOn: "click",
copyAnchorStyles: false,
open: function(e) {
const uid = $(e.target).closest(".k-pin-cell").closest("tr").data("uid");
const dataItem = uid ? that.dataSource.getByUid(uid) : null;
if (!dataItem || !that._checkRowPinnable(dataItem)) {
e.preventDefault();
return;
}
const position = that._getRowPinPosition(dataItem);
const items = that._pinMenu.element.find(".k-menu-item");
items.filter("[data-action=top]").toggle(position !== "top");
items.filter("[data-action=bottom]").toggle(position !== "bottom");
items.filter("[data-action=unpin]").toggle(position !== "none");
},
select: function(e) {
const action = $(e.item).data("action");
const uid = $(e.target).closest(".k-pin-cell").closest("tr").data("uid");
const dataItem = uid ? that.dataSource.getByUid(uid) : null;
if (!dataItem) return;
if (action === "unpin") that.unpinRows(dataItem);
else if (action === "top") that.pinRows(dataItem, "top");
else if (action === "bottom") that.pinRows(dataItem, "bottom");
}
});
that._pinMenu.append([
{
text: messages.pinTop,
icon: "pin-top",
attr: { "data-action": "top" }
},
{
text: messages.pinBottom,
icon: "pin-bottom",
attr: { "data-action": "bottom" }
},
{
text: messages.unpin,
icon: "unpin",
attr: { "data-action": "unpin" }
}
]);
},
_updatePinColumnIcons: function() {
const that = this;
if (!that._isPinnable()) return;
that.wrapper.find(`.${PINCELLCLASS}`).each((_, el) => {
const span = $(el);
const row = span.closest("tr");
const dataItem = that.dataItem(row);
if (!dataItem) return;
if (!that._checkRowPinnable(dataItem)) {
span.empty();
return;
}
const position = that._getRowPinPosition(dataItem);
const iconName = position !== "none" ? "unpin" : "pin";
const iconClass = position !== "none" ? "k-action-icon" : "";
span.empty().append(kendo.ui.icon({
icon: iconName,
iconClass
}));
});
},
pinRows: function(targets, position) {
const that = this;
if (!arguments.length) return {
top: (that._pinnedTopRows || []).slice(),
bottom: (that._pinnedBottomRows || []).slice()
};
const items = Array.isArray(targets) ? targets : [targets];
for (let i = 0; i < items.length; i++) {
let dataItem = items[i];
if (!(dataItem instanceof kendo.data.ObservableObject)) dataItem = that.dataItem($(dataItem));
if (dataItem) that._changePinState(dataItem, position || "bottom", ROWPIN);
}
},
unpinRows: function(targets) {
const that = this;
const items = Array.isArray(targets) ? targets : [targets];
for (let i = 0; i < items.length; i++) {
let dataItem = items[i];
if (!(dataItem instanceof kendo.data.ObservableObject)) dataItem = that.dataItem($(dataItem));
if (dataItem) that._changePinState(dataItem, null, ROWUNPIN);
}
},
_getRowPinPosition: function(dataItem) {
return getRowPinPosition(dataItem, this._pinnedTopRows, this._pinnedBottomRows, this._getSchemaIdField());
},
_changePinState: function(dataItem, position, eventName) {
const that = this;
const idField = that._getSchemaIdField();
if (!idField || !dataItem || !that._isPinnable()) return;
if (dataItem.rowType && dataItem.rowType !== "data") return;
if (position && !that._checkRowPinnable(dataItem)) return;
if (position && that._getRowPinPosition(dataItem) === position) return;
const key = dataItem[idField];
let newTop = (that._pinnedTopRows || []).filter((r) => r[idField] !== key);
let newBottom = (that._pinnedBottomRows || []).filter((r) => r[idField] !== key);
if (position === "top") newTop = [...newTop, dataItem];
if (position === "bottom") newBottom = [...newBottom, dataItem];
const e = {
pinnedTopRows: newTop,
pinnedBottomRows: newBottom,
dataItem,
position
};
if (!that.trigger(eventName, e)) {
that._pinnedTopRows = newTop;
that._pinnedBottomRows = newBottom;
that._renderPinnedRows();
}
},
_initPinnedRows: function() {
const that = this;
if (!that._isPinnable()) return;
if (!that._pinnedTopRows && !that._pinnedBottomRows) {
that._pinnedTopRows = [];
that._pinnedBottomRows = [];
that._resolveInitialPinnedRows();
}
},
_resolveInitialPinnedRows: function() {
const that = this;
const result = resolveInitialPinnedRows(that.options.pinnable, that._getSchemaIdField(), (id) => that.dataSource.get(id));
if (result) {
that._pinnedTopRows = result.top;
that._pinnedBottomRows = result.bottom;
}
},
_refreshPinnedReferences: function() {
const that = this;
const result = refreshPinnedReferences(that._pinnedTopRows, that._pinnedBottomRows, that.dataSource.data(), that._getSchemaIdField());
that._pinnedTopRows = result.top;
that._pinnedBottomRows = result.bottom;
},
_createPinnedContainer: function(position) {
const els = createPinnedContainer(position, kendo.getValidCssClass("k-table-", "size", this.options.size));
return {
container: $(els.container),
wrap: $(els.wrap),
table: $(els.table),
tbody: $(els.tbody)
};
},
_createPinnedLockedContent: function() {
const els = createPinnedLockedContent(kendo.getValidCssClass("k-table-", "size", this.options.size));
return {
container: $(els.container),
table: $(els.table),
tbody: $(els.tbody)
};
},
_ensurePinnedContainers: function() {
const that = this;
const gridContainer = that.content ? that.content.parent() : null;
if (!gridContainer || !gridContainer.length || !that._isPinnable()) return;
if (!that._pinnedScrollbarSynced) {
that._pinnedScrollbarSynced = true;
that._pinnedScrollbarPadding = kendo.support.scrollbar() + "px";
}
const containers = ["_pinnedTop", "_pinnedBottom"];
[{
prop: containers[0],
position: "top",
insert: "insertBefore"
}, {
prop: containers[1],
position: "bottom",
insert: "insertAfter"
}].forEach((cfg) => {
if (!that[cfg.prop]) {
const p = that._createPinnedContainer(cfg.position);
that[cfg.prop] = p;
p.container[0].style.paddingInlineEnd = that._pinnedScrollbarPadding;
p.wrap[0].style.boxSizing = "content-box";
p.container[cfg.insert](gridContainer);
p.wrap.on("scroll.kendoGrid", (e) => {
that._syncPinnedScroll(e.target);
});
if (that._hasDetails()) that._bindPinnedDetailHandler(p.table);
}
});
if (that._isLocked() && that.lockedContent) containers.forEach((p) => {
const reference = that[p];
if (!reference.locked) {
const content = $("<div class=\"k-grid-content\"/>");
reference.table.before(content);
content.append(reference.table);
reference.content = content;
const locked = that._createPinnedLockedContent();
reference.locked = locked.container;
reference.lockedTable = locked.table;
reference.lockedTbody = locked.tbody;
reference.content.before(reference.locked);
reference.content.on("scroll.kendoGrid", (e) => {
that._syncPinnedScroll(e.target);
});
}
});
},
_bindPinnedDetailHandler: function(table) {
const that = this;
const selector = `.k-hierarchy-cell ${CARET_ALT_RIGHT}, .k-hierarchy-cell ${CARET_ALT_DOWN}`;
table.on("click.kendoGrid", selector, function(e) {
that._toggleDetails($(this));
e.preventDefault();
return false;
});
},
_syncPinnedScroll: function(source) {
const that = this;
if (that._isSyncingPinnedScroll) return;
const top = that._pinnedTop;
const bottom = that._pinnedBottom;
that._isSyncingPinnedScroll = true;
syncPinnedScroll(source, that.content ? that.content[0] : null, (top && (top.content || top.wrap) || $())[0] || null, (bottom && (bottom.content || bottom.wrap) || $())[0] || null);
that._isSyncingPinnedScroll = false;
},
_syncPinnedColgroups: function() {
const that = this;
const top = that._pinnedTop;
const bottom = that._pinnedBottom;
syncPinnedColgroups(that.table ? that.table[0] : null, top && top.table ? top.table[0] : null, bottom && bottom.table ? bottom.table[0] : null);
if (that._isLocked() && that.lockedTable) syncPinnedColgroups(that.lockedTable[0], top && top.lockedTable ? top.lockedTable[0] : null, bottom && bottom.lockedTable ? bottom.lockedTable[0] : null);
},
_syncPinnedTableWidths: function() {
const that = this;
const top = that._pinnedTop;
const bottom = that._pinnedBottom;
syncPinnedTableWidths(that.table ? that.table[0] : null, top && top.table ? top.table[0] : null, bottom && bottom.table ? bottom.table[0] : null);
if (that._isLocked() && that.lockedTable) syncPinnedTableWidths(that.lockedTable[0], top && top.lockedTable ? top.lockedTable[0] : null, bottom && bottom.lockedTable ? bottom.lockedTable[0] : null);
},
_syncPinnedLockedWidths: function() {
const that = this;
if (!that._isLocked() || !that.lockedContent) return;
const top = that._pinnedTop;
const bottom = that._pinnedBottom;
syncPinnedLockedWidths(that.lockedContent[0].style.width || that.lockedContent[0].offsetWidth + "px", that.content[0].clientWidth + "px", top && top.locked ? top.locked[0] : null, bottom && bottom.locked ? bottom.locked[0] : null, top && top.content ? top.content[0] : null, bottom && bottom.content ? bottom.content[0] : null);
},
_buildPinnedRowHtml: function(dataItem, locked, alt) {
const that = this;
if (!dataItem || !dataItem.uid) return "";
let row;
if (locked) {
const lockedRowTemplate = that.lockedRowTemplate ? that.lockedRowTemplate(dataItem) : that.rowTemplate(dataItem);
row = alt && that.lockedAltRowTemplate ? that.lockedAltRowTemplate(dataItem) : lockedRowTemplate;
} else row = alt && that.altRowTemplate ? that.altRowTemplate(dataItem) : that.rowTemplate(dataItem);
if (typeof that.options.pinnedRowTemplate === "function") return that.options.pinnedRowTemplate({
dataItem,
row
});
return row;
},
_stripPinnedDetailToggles: function(tbody) {
if (!tbody || !tbody.length || !this._hasDetails()) return;
tbody.find(".k-hierarchy-cell").empty().removeAttr("aria-expanded").attr("aria-hidden", "true");
},
_stripPinnedDragHandles: function(tbody) {
if (!tbody || !tbody.length || !this._hasReorderableRows()) return;
tbody.find(".k-drag-cell").empty().removeAttr("aria-label").removeAttr("ref-grid-drag-cell").removeClass("k-drag-cell").css("cursor", "");
},
_getSortedPinnedRows: function(rows) {
const sort = this.dataSource.sort();
if (!sort || !sort.length) return rows;
return new kendo.data.Query(rows).sort(sort).toArray();
},
_renderPinnedRows: function() {
const that = this;
if (!that._isPinnable()) return;
that._refreshPinnedReferences();
const hasTopRows = that._pinnedTopRows.length > 0;
const hasBottomRows = that._pinnedBottomRows.length > 0;
const hasPinnedRows = hasTopRows || hasBottomRows;
if (!hasPinnedRows && !that._pinnedTop && !that._pinnedBottom) return;
that._ensurePinnedContainers();
const top = that._pinnedTop;
const bottom = that._pinnedBottom;
if (!top || !bottom) return;
that._syncPinnedColgroups();
that._syncPinnedTableWidths();
that._markPinnedSourceRows();
let pinnedNavInfo = null;
if (hasPinnedRows && that.options.navigatable && that._current && that._current.length) {
const cur = that._current;
if (that._isPinnedContainer(cur)) pinnedNavInfo = {
uid: cur.closest("tr").data("uid"),
cellIndex: cur.parent().children("td").index(cur),
position: that._pinnedPosition(cur)
};
}
that._pinnedNavInfo = pinnedNavInfo;
const topRows = hasTopRows ? that._getSortedPinnedRows(that._pinnedTopRows) : [];
const bottomRows = hasBottomRows ? that._getSortedPinnedRows(that._pinnedBottomRows) : [];
const topHtml = hasTopRows ? flattenRowSpans(topRows.map((item, idx) => that._buildPinnedRowHtml(item, false, idx % 2 === 1)).join("")) : "";
const bottomHtml = hasBottomRows ? flattenRowSpans(bottomRows.map((item, idx) => that._buildPinnedRowHtml(item, false, idx % 2 === 1)).join("")) : "";
top.tbody.html(topHtml);
bottom.tbody.html(bottomHtml);
that._stripPinnedDetailToggles(top.tbody);
that._stripPinnedDetailToggles(bottom.tbody);
that._stripPinnedDragHandles(top.tbody);
that._stripPinnedDragHandles(bottom.tbody);
kendo.applyStylesFromKendoAttributes(top.tbody, [
"display",
"left",
"right"
]);
kendo.applyStylesFromKendoAttributes(bottom.tbody, [
"display",
"left",
"right"
]);
if (that._isStackedMode()) {
const layoutSettings = that._getStackedLayoutSettings();
const pinnedStackedRows = top.tbody.find(".k-grid-stack-row").add(bottom.tbody.find(".k-grid-stack-row"));
if (layoutSettings.colClass) pinnedStackedRows.addClass(layoutSettings.colClass);
else if (layoutSettings.colsConfig) pinnedStackedRows.css("grid-template-columns", layoutSettings.colsConfig);
}
if (that._isLocked() && that.lockedRowTemplate) {
const topLockedHtml = flattenRowSpans(topRows.map((item, idx) => that._buildPinnedRowHtml(item, true, idx % 2 === 1)).join(""));
const bottomLockedHtml = flattenRowSpans(bottomRows.map((item, idx) => that._buildPinnedRowHtml(item, true, idx % 2 === 1)).join(""));
top.lockedTbody.html(topLockedHtml);
bottom.lockedTbody.html(bottomLockedHtml);
that._stripPinnedDetailToggles(top.lockedTbody);
that._stripPinnedDetailToggles(bottom.lockedTbody);
that._stripPinnedDragHandles(top.lockedTbody);
that._stripPinnedDragHandles(bottom.lockedTbody);
that._syncPinnedLockedWidths();
}
top.container.toggleClass("k-hidden", that._pinnedTopRows.length === 0);
bottom.container.toggleClass("k-hidden", that._pinnedBottomRows.length === 0);
that._setContentHeight();
that._syncLockedContentHeight();
if (that.content && that.content[0]) that._syncPinnedScroll(that.content[0]);
that._updatePinColumnIcons();
if (hasPinnedRows) {
that._syncPinnedSelection();
that._syncPinnedHighlight();
that._syncPinnedNavigation();
that._applyPinnedAria();
}
},
_syncPinnedSelection: function() {
const that = this;
if (!that._isPinnable() || !that.options.selectable) return;
const isCell = kendo.ui.Selectable.parseOptions(that.options.selectable).cell;
const selected = that.select();
const selectedKeys = {};
selected.each((_, el) => {
const $el = $(el);
const uid = isCell ? $el.closest("tr").data("uid") : $el.data("uid");
if (uid) selectedKeys[isCell ? `${uid}_${$el.index()}` : uid] = true;
});
const selector = isCell ? "tr > td" : "tr";
const toggle = (el) => {
const $el = $(el);
const uid = isCell ? $el.closest("tr").data("uid") : $el.data("uid");
$el.toggleClass(SELECTED, !!selectedKeys[isCell ? `${uid}_${$el.index()}` : uid]);
};
[that._pinnedTop, that._pinnedBottom].forEach((p) => {
if (!p || !p.tbody) return;
p.tbody.find(selector).each((_, el) => toggle(el));
if (p.lockedTbody) p.lockedTbody.find(selector).each((_, el) => toggle(el));
});
},
_syncPinnedHighlight: function() {
const that = this;
if (!that._isPinnable()) return;
const highlighted = that._highlightedItems;
const highlightedUids = {};
const highlightedCells = {};
if (highlighted && highlighted.length) highlighted.each((_, el) => {
const $el = $(el);
if ($el.is("tr")) {
const uid = $el.data("uid");
if (uid) highlightedUids[uid] = true;
} else if ($el.is("td")) {
const uid = $el.closest("tr").data("uid");
if (uid) {
if (!highlightedCells[uid]) highlightedCells[uid] = [];
highlightedCells[uid].push($el.index());
}
}
});
const applyRowHighlight = (el) => {
const row = $(el);
const uid = row.data("uid");
row.toggleClass(HIGHLIGHTED, !!highlightedUids[uid]);
row.children("td").removeClass(HIGHLIGHTED);
if (highlightedCells[uid]) highlightedCells[uid].forEach((idx) => {
row.children("td").eq(idx).addClass(HIGHLIGHTED);
});
};
const applyHighlight = (tbody) => {
tbody.children("tr").each((_, el) => applyRowHighlight(el));
};
[that._pinnedTop, that._pinnedBottom].forEach((p) => {
if (!p || !p.tbody) return;
applyHighlight(p.tbody);
if (p.lockedTbody) applyHighlight(p.lockedTbody);
});
},
_isPinnedContainer: function(cell) {
return cell && cell.closest(".k-grid-pinned-container").length > 0;
},
_applyPinnedAria: function() {
const that = this;
applyPinnedAria([that._pinnedTop, that._pinnedBottom], (uid) => that.dataSource.getByUid(uid), that._getSchemaIdField());
},
_syncPinnedNavigation: function() {
const that = this;
const current = that._current;
const info = that._pinnedNavInfo;
if (!info || !current || !current.length || !that.options.navigatable) return;
that._pinnedNavInfo = null;
const p = info.position === "top" ? that._pinnedTop : that._pinnedBottom;
if (!p || !p.tbody) return;
const newRow = p.tbody.children(`tr[data-uid='${info.uid}']`);
if (newRow.length) {
const newCell = newRow.children("td").eq(info.cellIndex);
if (newCell.length) that._updateCurrentAttr(current, newCell);
}
},
_pinnedPosition: function(cell) {
return cell.closest(`.${PINNED_CONTAINER_CLASS}`).hasClass("k-pos-bottom") ? "bottom" : "top";
},
_pinnedVerticalCell: function(current, down) {
const row = current.parent();
const rows = row.parent().children(NAVROW);
const rowIndex = rows.index(row);
const cellIndex = Math.max(row.children(DATA_CELL_HIDDENINCLUDED).index(current), this._lastCellIndex || 0);
let nextRow;
if (down) nextRow = rowIndex < rows.length - 1 ? rows.eq(rowIndex + 1) : $();
else nextRow = rowIndex > 0 ? rows.eq(rowIndex - 1) : $();
if (!nextRow.length) return $();
const cells = nextRow.children(DATA_CELL_HIDDENINCLUDED);
return cells.length > cellIndex ? cells.eq(cellIndex) : cells.last();
},
_pinnedBoundaryCellByPosition: function(position, first, cellIndex, navCellIndex) {
const p = position === "top" ? this._pinnedTop : this._pinnedBottom;
if (!p || !p.tbody) return $();
const rows = p.tbody.children(NAVROW);
if (!rows.length) return $();
const row = first ? rows.first() : rows.last();
if (navCellIndex) {
const navCells = row.children(NAVCELL);
return navCells.length > cellIndex ? navCells.eq(cellIndex) : navCells.last();
}
const cells = row.children(DATA_CELL_HIDDENINCLUDED);
let cell = cells.length > cellIndex ? cells.eq(cellIndex) : cells.last();
if (cell.is(".k-group-cell")) cell = cell.nextAll("td").not(".k-group-cell").not(":hidden").first();
return cell;
},
_initPinnedRowEditing: function() {
const that = this;
if (!that._isPinnable() || !that.options.editable) return;
if (that._editMode() === "incell") that.wrapper.on("mousedown.kendoGrid", ".k-grid-pinned-container td", function(e) {
if ($(e.target).closest(".k-pin-cell").length || $(e.target).is(":input")) return;
const pinnedCell = $(this);
const uid = pinnedCell.closest("tr").data("uid");
if (!uid || pinnedCell.hasClass("k-edit-cell")) return;
e.preventDefault();
clearTimeout(that._timer);
that._timer = null;
if (that.options.selectable) {
const selOpts = kendo.ui.Selectable.parseOptions(that.options.selectable);
const sourceRow = that.tbody.children("tr[data-uid=\"" + uid + "\"]");
if (sourceRow.length) {
let source;
if (selOpts.cell) source = sourceRow.children("td").eq(pinnedCell.index());
else source = sourceRow;
if (source.length) {
if (selOpts.multiple && !e.ctrlKey && !e.metaKey && !e.shiftKey) that.clearSelection();
that.select(source);
that._syncPinnedSelection();
}
}
}
if (that.editable) {
if (!that.editable.end()) return;
}
that.editCell(pinnedCell);
});
},
_initPinnedRowSelection: function() {
const that = this;
if (!that._isPinnable() || !that.options.selectable) return;
const selectableOptions = kendo.ui.Selectable.parseOptions(that.options.selectable);
const selector = selectableOptions.cell ? ".k-grid-pinned-container td" : ".k-grid-pinned-container tr";
that.wrapper.on("click.kendoGrid", selector, function(e) {
if ($(e.target).closest(".k-pin-cell").length) return;
const pinnedTarget = $(this);
const uid = (selectableOptions.cell ? pinnedTarget.closest("tr") : pinnedTarget).data("uid");
if (!uid) return;
const sourceRow = that.tbody.children(`tr[data-uid="${uid}"]`);
if (!sourceRow.length) return;
let source;
if (selectableOptions.cell) source = sourceRow.children("td").eq(pinnedTarget.index());
else source = sourceRow;
if (!source.length) return;
const toggleOff = source.hasClass(SELECTED) && (e.ctrlKey || e.metaKey);
if (selectableOptions.multiple && !e.ctrlKey && !e.metaKey && !e.shiftKey) that.clearSelection();
if (toggleOff) {
let target = source;
if (that._isLocked()) target = target.add(selectableOptions.cell ? that._relatedCell(source) : that._relatedRow(source));
that.selectable._unselect(target);
that.selectable.trigger(CHANGE);
} else that.select(source);
that._syncPinnedSelection();
});
},
_markPinnedSourceRows: function() {
const that = this;
if (!that._isPinnable() || !that.tbody) return;
const idField = that._getSchemaIdField();
markPinnedSourceRows(that.tbody[0], that._pinnedTopRows, that._pinnedBottomRows, idField);
if (that._isLocked() && that.lockedTable) markPinnedSourceRows(that.lockedTable.children("tbody")[0], that._pinnedTopRows, that._pinnedBottomRows, idField);
},
_destroyPinnedRows: function() {
const that = this;
if (that._pinnedTop) {
if (that._pinnedTop.wrap) that._pinnedTop.wrap.off("scroll.kendoGrid");
if (that._pinnedTop.content) that._pinnedTop.content.off("scroll.kendoGrid");
destroyPinnedContainer(null, that._pinnedTop.container);
}
that._pinnedTop = null;
if (that._pinnedBottom) {
if (that._pinnedBottom.wrap) that._pinnedBottom.wrap.off("scroll.kendoGrid");
if (that._pinnedBottom.content) that._pinnedBottom.content.off("scroll.kendoGrid");
destroyPinnedContainer(null, that._pinnedBottom.container);
}
that._pinnedBottom = null;
if (that._pinMenu) {
that._pinMenu.destroy();
that._pinMenu = null;
}
},
_createStickyGroupContainer: function(tableClass, extraClasses) {
const result = createStickyGroupContainer(tableClass, kendo.getValidCssClass("k-table-", "size", this.options.size), extraClasses);
return {
container: $(result.container),
table: $(result.table)
};
},
_removeStickyGroupContainer: function(containerProp, tableProp, unbindClick) {
if (this[containerProp]) {
if (unbindClick) this[containerProp].off("click.kendoGrid");
this[containerProp].remove();
this[containerProp] = null;
this[tableProp] = null;
}
},
_syncStickyColgroup: function(targetTable, sourceTable) {
syncColgroup(targetTable ? targetTable[0] : null, sourceTable[0]);
},
_initStickyGroups: function() {
const that = this;
const gridContainer = that.content ? that.content.parent() : null;
if (!gridContainer || !gridContainer.length) return;
if (that._hasStickyGroupHeaders() && !that._stickyGroupHeaderContainer) {
const { container, table } = that._createStickyGroupContainer(STICKY_GROUP_HEADER_TABLE_CLASS);
that._stickyGroupHeaderContainer = container;
that._stickyGroupHeaderTable = table;
container.addClass("k-hidden").prependTo(gridContainer);
}
if (that._hasStickyGroupFooters() && !that._stickyGroupFooterContainer) {
const { container, table } = that._createStickyGroupContainer(STICKY_GROUP_FOOTER_TABLE_CLASS, "k-pos-bottom");
that._stickyGroupFooterContainer = container;
that._stickyGroupFooterTable = table;
container.addClass("k-hidden").appendTo(gridContainer);
}
that._stickyHeaderItems = [];
that._stickyFooterItems = [];
if (!that._stickyGroupsScrollHandler) that._stickyGroupsScrollHandler = () => {
that._updateStickyGroups();
};
if (!that._stickyGroupsClickHandler) that._stickyGroupsClickHandler = (e) => {
const target = $(e.target).closest(`${CARET_ALT_DOWN}, ${CARET_ALT_RIGHT}`);
if (!target.length) return;
const stickyRow = target.closest("tr.k-grouping-row");
if (!stickyRow.length) return;
const rowIndex = stickyRow.parent().children().index(stickyRow);
const items = that._stickyHeaderItems;
if (!items || rowIndex >= items.length) return;
const resolved = that._resolveStickyGroupRows(items[rowIndex].headerIndex);
if (!resolved) return;
that._toggleStickyGroup(target, resolved.groupRow);
that._scrollToStickyGroupRow(resolved.originalRow);
e.preventDefault();
e.stopPropagation();
};
if (that._stickyGroupHeaderContainer) that._stickyGroupHeaderContainer.off("click.kendoGrid").on("click.kendoGrid", that._stickyGroupsClickHandler);
if (!that._stickyGroupResizeHandler) {
that._stickyGroupResizeHandler = () => {
that.resize();
};
$(window).on("resize.kendoGrid", that._stickyGroupResizeHandler);
}
that._initStickyGroupKeyboardNav();
},
_initStickyGroupKeyboardNav: function() {
const that = this;
if (!that.options.navigatable) return;
const containers = [];
if (that._stickyGroupHeaderContainer) containers.push({
el: that._stickyGroupHeaderContainer,
type: "header"
});
if (that._stickyGroupFooterContainer) containers.push({
el: that._stickyGroupFooterContainer,
type: "footer"
});
for (const { el, type } of containers) {
el.off("mousedown.kendoGridnav");
el.removeAttr("tabindex");
el.on("mousedown.kendoGridnav", "td", (e) => {
if ($(e.target).closest(`${CARET_ALT_DOWN}, ${CARET_ALT_RIGHT}`).length) return;
const cell = $(e.currentTarget);
const row = cell.closest("tr");
that._focusStickyRow(row, type, cell);
e.preventDefault();
});
}
},
_stickyGroupVirtualOffset: function() {
return this.virtualScrollable ? this.virtualScrollable._rangeStart || this.dataSource.skip() || 0 : 0;
},
_resolveStickyGroupRows: function(headerIndex) {
const that = this;
const skipOffset = that._stickyGroupVirtualOffset();
const originalRow = $(that.tbody[0].children[headerIndex - skipOffset]);
if (!originalRow.length) return null;
let groupRow = originalRow;
if (that._isLocked() && that.lockedTable) groupRow = $(that.lockedTable.find(">tbody")[0].children[headerIndex - skipOffset]);
return {
originalRow,
groupRow
};
},
_toggleStickyGroup: function(toggle, groupRow) {
const that = this;
const isCollapse = toggle.is(CARET_ALT_DOWN);
const eventName = isCollapse ? "groupCollapse" : "groupExpand";
const group = that._groupRows ? that._groupRows[that.wrapper.find(".k-grouping-row").index(groupRow)] : {};
if (!that.trigger(eventName, {
group,
element: groupRow
})) if (isCollapse) that.collapseGroup(groupRow);
else that.expandGroup(groupRow);
},
_scrollToStickyGroupRow: function(originalRow) {
const that = this;
that._stickyHeaderItems = [];
that._stickyFooterItems = [];
const scrollContainer = that.content[0];
if (scrollContainer) scrollContainer.scrollTop = originalRow[0].offsetTop;
that._updateStickyGroups();
const hc = that._stickyGroupHeaderContainer;
if (hc && !hc.hasClass("k-hidden") && scrollContainer) {
const stickyH = hc[0].offsetHeight;
if (stickyH > 0) {
scrollContainer.scrollTop = originalRow[0].offsetTop - stickyH;
if (that._isLocked() && that.lockedContent) that.lockedContent[0].scrollTop = scrollContainer.scrollTop;
that._updateStickyGroups();
}
}
},
_navigateStickyHorizontal: function(focusedRow, focusedCell, containerType, keyCode) {
const that = this;
const navCells = focusedRow.children(NAVCELL);
const cellIdx = navCells.index(focusedCell);
const nextIdx = keyCode === keys.RIGHT ? cellIdx + 1 : cellIdx - 1;
if (nextIdx >= 0 && nextIdx < navCells.length) {
focusedCell.removeClass(FOCUSED);
const nextCell = navCells.eq(nextIdx);
nextCell.addClass(FOCUSED);
that._stickyGroupFocusState.cell = nextCell;
} else if (that.lockedTable) {
const container = containerType === "header" ? that._stickyGroupHeaderContainer : that._stickyGroupFooterContainer;
const lockedWrapper = container.children(".k-grid-content-locked");
const nonLockedClass = containerType === "header" ? ".k-grid-header-wrap" : ".k-grid-footer-wrap";
const nonLockedWrapper = container.children(nonLockedClass);
const isInLocked = focusedRow.closest(".k-grid-content-locked").length > 0;
const rowIdx = focusedRow.parent().children("tr").index(focusedRow);
let targetRow, targetCell;
if (keyCode === keys.RIGHT && isInLocked) {
targetRow = nonLockedWrapper.find("tbody > tr").eq(rowIdx);
targetCell = targetRow.children(NAVCELL).first();
} else if (keyCode === keys.LEFT && !isInLocked) {
targetRow = lockedWrapper.find("tbody > tr").eq(rowIdx);
targetCell = targetRow.children(NAVCELL).last();
}
if (targetCell && targetCell.length) {
focusedCell.removeClass(FOCUSED);
targetCell.addClass(FOCUSED);
that._stickyGroupFocusState.cell = targetCell;
that._stickyGroupFocusState.row = targetRow;
}
}
},
_handleStickyGroupKeyDown: function(e) {
const isVertical = e.keyCode === keys.DOWN || e.keyCode === keys.UP;
const isHorizontal = e.keyCode === keys.LEFT || e.keyCode === keys.RIGHT;
const isEnter = e.keyCode === keys.ENTER;
if (!isVertical && !isHorizontal && !isEnter) return false;
const that = this;
const focusState = that._stickyGroupFocusState;
if (!focusState) return false;
let focusedCell = focusState.cell;
let focusedRow = focusState.row;
let containerType = focusState.type;
if (isEnter && containerType === "header") {
const toggle = focusedRow.find(`${CARET_ALT_DOWN}, ${CARET_ALT_RIGHT}`);
if (toggle.length) {
const rowIdx = focusedRow.parent().children("tr").index(focusedRow);
const cellIdx = focusedRow.children(NAVCELL).index(focusedCell);
const items = that._stickyHeaderItems;
if (items && rowIdx < items.length) {
const resolved = that._resolveStickyGroupRows(items[rowIdx].headerIndex);
if (resolved) {
that._toggleStickyGroup(toggle, resolved.groupRow);
that._scrollToStickyGroupRow(resolved.originalRow);
that._clearStickyGroupFocus();
const targetCell = resolved.groupRow.children(NAVCELL).eq(Math.min(cellIdx, resolved.groupRow.children(NAVCELL).length - 1));
that._setCurrent(targetCell.length ? targetCell : resolved.groupRow.children(DATA_CELL).first());
}
}
}
e.preventDefault();
e.stopImmediatePropagation();
return true;
}
if (isHorizontal) {
that._navigateStickyHorizontal(focusedRow, focusedCell, containerType, e.keyCode);
e.preventDefault();
e.stopImmediatePropagation();
return true;
}
if (e.keyCode === keys.DOWN) that._exitStickyContainer(focusedRow, containerType, "down");
else that._exitStickyContainer(focusedRow, containerType, "up");
e.preventDefault();
e.stopImmediatePropagation();
return true;
},
_focusStickyRow: function(row, type, targetCell) {
const that = this;
if (!(type === "header" ? that._stickyGroupHeaderContainer : that._stickyGroupFooterContainer)) return;
that._clearStickyGroupFocus();
let cell;
if (targetCell && targetCell.length && targetCell.is(NAVCELL)) cell = targetCell;
else {
cell = row.children("td[colspan]");
if (!cell.length) cell = row.children(NAVCELL).first();
}
if (cell.length) {
cell.addClass(FOCUSED);
that._stickyGroupFocusState = {
cell,
row,
type
};
}
that._removeCurrent();
that._stickyGroupFocusing = true;
focusTable(that.table, true);
that._stickyGroupFocusing = false;
},
_clearStickyGroupFocus: function() {
if (this._stickyGroupHeaderContainer) this._stickyGroupHeaderContainer.find(".k-focus").removeClass(FOCUSED);
if (this._stickyGroupFooterContainer) this._stickyGroupFooterContainer.find(".k-focus").removeClass(FOCUSED);
this._stickyGroupFocusState = null;
},
_scrollStickyExitRow: function(targetRow, isLocked, scrollContainer, type) {
const scrollRow = this._stickyScrollRow(targetRow, isLocked);
if (!scrollRow) return;
if (type === "header") {
const stickyH = this._stickyGroupHeaderContainer ? this._stickyGroupHeaderContainer[0].offsetHeight : 0;
scrollContainer.scrollTop = Math.max(scrollRow.offsetTop - stickyH, 0);
} else {
const stickyH = this._stickyGroupFooterContainer ? this._stickyGroupFooterContainer[0].offsetHeight : 0;
scrollContainer.scrollTop = Math.max(scrollRow.offsetTop + scrollRow.offsetHeight - scrollContainer.clientHeight + stickyH, 0);
}
},
_stickyScrollRow: function(targetRow, isLocked) {
if (!isLocked) return targetRow;
const idx = Array.prototype.indexOf.call(targetRow.parentNode.children, targetRow);
return this.tbody[0] && this.tbody[0].children[idx];
},
_exitStickyFocusToCell: function(targetRow, scrollIntoView) {
const that = this;
const focusState = that._stickyGroupFocusState;
let cellIdx = 0;
if (scrollIntoView && focusState && focusState.cell) cellIdx = focusState.row.children(NAVCELL).index(focusState.cell);
that._clearStickyGroupFocus();
if (that._stickyGroupsScrollHandler) that._stickyGroupsScrollHandler();
const navCells = $(targetRow).children(NAVCELL);
const cell = navCells.eq(Math.min(cellIdx, navCells.length - 1));
if (cell.length) {
that._setCurrent(cell, false, true);
if (scrollIntoView) targetRow.scrollIntoView({ block: "nearest" });
}
},
_scrollToStickyGroup: function(stickyRow, type) {
const that = this;
const items = type === "header" ? that._stickyHeaderItems : that._stickyFooterItems;
const rowIdx = stickyRow.parent().children("tr").index(stickyRow);
if (!items || rowIdx < 0 || rowIdx >= items.length) return;
const range = items[rowIdx];
const skipOffset = that._stickyGroupVirtualOffset();
const scrollContainer = that._stickyScrollContainer();
if (!scrollContainer) return;
const realRowIndex = range.headerIndex;
const tbody = that.lockedTable && stickyRow.closest(".k-grid-content-locked").length > 0 ? that.lockedTable.find(">tbody")[0] : that.tbody[0];
const realRow = tbody && tbody.children[realRowIndex - skipOffset];
if (!realRow) return;
const parentPadding = stickyParentPadding(stickyRow.parent().children("tr"), items, range);
scrollContainer.scrollTop = Math.max(realRow.offsetTop - parentPadding, 0);
that._clearStickyGroupFocus();
if (that._stickyGroupsScrollHandler) that._stickyGroupsScrollHandler();
let targetRow = null;
for (let i = range.firstChildIndex; i <= range.lastChildIndex; i++) {
const row = tbody.children[i - skipOffset];
if (row && !row.classList.contains("k-grouping-row")) {
targetRow = row;
break;
}
}
if (!targetRow) targetRow = tbody.children[range.firstChildIndex - skipOffset] || realRow;
const cell = $(targetRow).children(NAVCELL).first();
if (cell.length) that._setCurrent(cell, false, true);
},
_redirectToStickyContainer: function(next) {
this._ensureStickyNavTargetVisible(next);
return false;
},
_ensureStickyNavTargetVisible: function(next) {
const that = this;
if (!next || !next.length) return;
const row = next.parent();
const skipOffset = that._stickyGroupVirtualOffset();
const rowGlobalIndex = row.index() + skipOffset;
if (row.hasClass(GROUPING_ROW) && that._stickyHeaderItems && that._stickyHeaderItems.length) {
for (let i = 0; i < that._stickyHeaderItems.length; i++) if (that._stickyHeaderItems[i].headerIndex === rowGlobalIndex) {
if (that._isRowObscuredByStickyHeader(row)) that._scrollRealGroupRowIntoView(row, that._stickyHeaderItems[i], "header");
return;
}
}
if (row.hasClass("k-group-footer") && that._stickyFooterItems && that._stickyFooterItems.length) {
for (let i = 0; i < that._stickyFooterItems.length; i++) if (that._stickyFooterItems[i].footerIndex === rowGlobalIndex) {
if (that._isRowObscuredByStickyFooter(row)) that._scrollRealGroupRowIntoView(row, that._stickyFooterItems[i], "footer");
return;
}
}
},
_scrollRealGroupRowIntoView: function(row, range, type) {
const that = this;
const scrollContainer = that._stickyScrollContainer();
if (!scrollContainer) return;
const container = type === "header" ? that._stickyGroupHeaderContainer : that._stickyGroupFooterContainer;
if (!container) return;
const items = type === "header" ? that._stickyHeaderItems : that._stickyFooterItems;
const parentPadding = stickyParentPadding(container.find("tbody > tr"), items, range);
const rowEl = row[0];
if (type === "header") scrollContainer.scrollTop = Math.max(rowEl.offsetTop - parentPadding, 0);
else {
const viewportH = scrollContainer.clientHeight;
scrollContainer.scrollTop = Math.max(rowEl.offsetTop + rowEl.offsetHeight - viewportH + parentPadding, 0);
}
that._updateStickyGroups();
const targetProp = type === "header" ? "headerIndex" : "footerIndex";
const targetValue = range[targetProp];
let safety = 4;
while (safety-- > 0) {
if (!(type === "header" ? that._stickyHeaderItems : that._stickyFooterItems).some(function(it) {
return it[targetProp] === targetValue;
})) break;
if (type === "header") scrollContainer.scrollTop = Math.max(Math.floor(scrollContainer.scrollTop) - 1, 0);
else scrollContainer.scrollTop = Math.floor(scrollContainer.scrollTop) + 1;
that._updateStickyGroups();
}
},
_isRowObscuredByStickyHeader: function(row) {
const stickyEl = this._stickyGroupHeaderContainer && this._stickyGroupHeaderContainer[0];
if (!stickyEl || this._stickyGroupHeaderContainer.hasClass("k-hidden")) return false;
const rowRect = row[0].getBoundingClientRect();
const stickyRect = stickyEl.getBoundingClientRect();
return rowRect.top < stickyRect.bottom;
},
_isRowObscuredByStickyFooter: function(row) {
const stickyEl = this._stickyGroupFooterContainer && this._stickyGroupFooterContainer[0];
if (!stickyEl || this._stickyGroupFooterContainer.hasClass("k-hidden")) return false;
const rowRect = row[0].getBoundingClientRect();
const stickyRect = stickyEl.getBoundingClientRect();
return rowRect.bottom > stickyRect.top;
},
_exitStickyContainer: function(focusedRow, type, direction) {
const that = this;
const items = type === "header" ? that._stickyHeaderItems : that._stickyFooterItems;
const rowIdx = focusedRow.parent().children("tr").index(focusedRow);
if (!items || rowIdx < 0 || rowIdx >= items.length) return;
const range = items[rowIdx];
const skipOffset = that._stickyGroupVirtualOffset();
const scrollContainer = that._stickyScrollContainer();
if (!scrollContainer) return;
const isLocked = that.lockedTable && focusedRow.closest(".k-grid-content-locked").length > 0;
const tbody = isLocked ? that.lockedTable.find(">tbody")[0] : that.tbody[0];
let realRowIndex;
if (type === "header") realRowIndex = range.headerIndex;
else realRowIndex = range.footerIndex !== null ? range.footerIndex : range.lastChildIndex;
const realRow = tbody && tbody.children[realRowIndex - skipOffset];
if (!realRow) return;
let targetRow = realRow;
if (type === "header" && direction === "down") {
targetRow = findStickyChildRow(tbody, range, skipOffset, false) || realRow;
const parentPadding = stickyParentPadding(focusedRow.parent().children("tr"), items, range);
const hDownIdx = realRowIndex - skipOffset;
const hDownRow = isLocked ? that.tbody[0] && that.tbody[0].children[hDownIdx] : realRow;
if (hDownRow) {
scrollContainer.scrollTop = Math.max(hDownRow.offsetTop - parentPadding, 0);
that._updateStickyGroups();
let safety = 4;
while (safety-- > 0 && that._stickyHeaderItems.some(function(it) {
return it.headerIndex === range.headerIndex;
})) {
scrollContainer.scrollTop = Math.max(Math.floor(scrollContainer.scrollTop) - 1, 0);
that._updateStickyGroups();
}
}
} else if (type === "header" && direction === "up") {
const prevIdx = range.headerIndex - 1 - skipOffset;
if (prevIdx >= 0 && tbody.children[prevIdx]) {
targetRow = tbody.children[prevIdx];
that._scrollStickyExitRow(targetRow, isLocked, scrollContainer, "header");
that._updateStickyGroups();
const hc = that._stickyGroupHeaderContainer;
if (hc && !hc.hasClass("k-hidden")) {
const scrollRow = that._stickyScrollRow(targetRow, isLocked);
if (scrollRow) {
const newStickyH = hc[0].offsetHeight;
scrollContainer.scrollTop = Math.max(scrollRow.offsetTop - newStickyH, 0);
}
}
} else {
if (that._isStackedMode()) return;
if (that._isPinnable() && that._pinnedTopRows && that._pinnedTopRows.length) {
const focusState = that._stickyGroupFocusState;
let cellIdx = 0;
if (focusState && focusState.cell) cellIdx = focusState.row.children(NAVCELL).index(focusState.cell);
scrollContainer.scrollTop = 0;
that._clearStickyGroupFocus();
const pinnedCell = that._pinnedBoundaryCellByPosition("top", false, cellIdx, true);
if (pinnedCell.length) {
focusTable(that.table, true);
that._setCurrent(pinnedCell);
return;
}
}
scrollContainer.scrollTop = 0;
const theadEl = isLocked ? that.lockedHeader && that.lockedHeader.find("thead") : that.thead;
if (theadEl && theadEl.length) that._exitStickyFocusToCell(theadEl.find("tr:last > th").filter(NAVCELL).parent()[0]);
return;
}
} else if (type === "footer" && direction === "up") {
targetRow = findStickyChildRow(tbody, range, skipOffset, true) || realRow;
that._scrollStickyExitRow(targetRow, isLocked, scrollContainer, "footer");
} else if (type === "footer" && direction === "down") {
const nextIdx = (range.footerIndex !== null ? range.footerIndex : range.lastChildIndex) + 1 - skipOffset;
if (nextIdx < tbody.children.length && tbody.children[nextIdx]) targetRow = tbody.children[nextIdx];
else if (that._isPinnable() && that._pinnedBottomRows && that._pinnedBottomRows.length) {
const focusState = that._stickyGroupFocusState;
let cellIdx = 0;
if (focusState && focusState.cell) cellIdx = focusState.row.children(NAVCELL).index(focusState.cell);
that._clearStickyGroupFocus();
const pinnedCell = that._pinnedBoundaryCellByPosition("bottom", true, cellIdx, true);
if (pinnedCell.length) {
focusTable(that.table, true);
that._setCurrent(pinnedCell);
if (isLocked && that.lockedContent) that.lockedContent[0].scrollTop = scrollContainer.scrollTop;
return;
}
}
}
if (isLocked && that.lockedContent) that.lockedContent[0].scrollTop = scrollContainer.scrollTop;
that._exitStickyFocusToCell(targetRow, type !== "header");
},
_destroyStickyGroups: function() {
const that = this;
that._removeStickyGroupContainer("_stickyGroupLockedHeaderContainer", "_stickyGroupLockedHeaderTable", true);
that._removeStickyGroupContainer("_stickyGroupLockedFooterContainer", "_stickyGroupLockedFooterTable");
that._removeStickyGroupContainer("_stickyGroupHeaderContainer", "_stickyGroupHeaderTable", true);
that._removeStickyGroupContainer("_stickyGroupFooterContainer", "_stickyGroupFooterTable");
that._stickyHeaderItems = [];
that._stickyFooterItems = [];
that._stickyGroupsScrollHandler = null;
that._stickyGroupsClickHandler = null;
if (that._stickyGroupResizeHandler) {
$(window).off("resize.kendoGrid", that._stickyGroupResizeHandler);
that._stickyGroupResizeHandler = null;
}
if (that.content && that.content[0]) {
that.content[0].style.scrollPaddingTop = "";
that.content[0].style.scrollPaddingBottom = "";
}
},
_syncStickyGroupColgroups: function() {
const that = this;
that._syncStickyColgroup(that._stickyGroupHeaderTable, that.table);
that._syncStickyColgroup(that._stickyGroupFooterTable, that.table);
if (that.lockedTable) {
that._syncStickyColgroup(that._stickyGroupLockedHeaderTable, that.lockedTable);
that._syncStickyColgroup(that._stickyGroupLockedFooterTable, that.lockedTable);
}
if (that._stickyHeaderItems && that._stickyHeaderItems.length) that._renderStickyHeaderRows(that._stickyHeaderItems);
if (that._stickyFooterItems && that._stickyFooterItems.length) that._renderStickyFooterRows(that._stickyFooterItems);
if (that.lockedTable) {
if (that._stickyGroupHeaderTable && that._stickyGroupLockedHeaderTable) that._adjustRowsHeight(that._stickyGroupHeaderTable, that._stickyGroupLockedHeaderTable);
if (that._stickyGroupFooterTable && that._stickyGroupLockedFooterTable) that._adjustRowsHeight(that._stickyGroupFooterTable, that._stickyGroupLockedFooterTable);
}
},
_initStickyGroupLockedContainers: function() {
const that = this;
if (!that._isLocked() || !that.lockedContent) return;
that._initStickyGroupLockedContainer("header");
that._initStickyGroupLockedContainer("footer");
},
_initStickyGroupLockedContainer: function(type) {
const that = this;
const isHeader = type === "header";
const hasItems = isHeader ? that._hasStickyGroupHeaders() : that._hasStickyGroupFooters();
const container = isHeader ? that._stickyGroupHeaderContainer : that._stickyGroupFooterContainer;
const lockedContainer = isHeader ? that._stickyGroupLockedHeaderContainer : that._stickyGroupLockedFooterContainer;
if (!hasItems || !container || lockedContainer) return;
const tableClass = isHeader ? STICKY_GROUP_HEADER_TABLE_CLASS : STICKY_GROUP_FOOTER_TABLE_CLASS;
const wrapClass = isHeader ? "k-grid-header-wrap" : "k-grid-footer-wrap";
const mainTable = isHeader ? that._stickyGroupHeaderTable : that._stickyGroupFooterTable;
const result = createStickyGroupLockedContainer(tableClass, kendo.getValidCssClass("k-table-", "size", that.options.size));
const lockedDiv = $(result.container);
const lockedTable = $(result.table);
mainTable.wrap(`<div class="${wrapClass}"></div>`);
container.prepend(lockedDiv);
if (isHeader) {
that._stickyGroupLockedHeaderContainer = lockedDiv;
that._stickyGroupLockedHeaderTable = lockedTable;
lockedDiv.on("click.kendoGrid", that._stickyGroupsClickHandler);
} else {
that._stickyGroupLockedFooterContainer = lockedDiv;
that._stickyGroupLockedFooterTable = lockedTable;
}
},
_stickyScrollContainer: function() {
if (this.virtualScrollable) return this.virtualScrollable.wrapper[0];
return this.content ? this.content[0] : null;
},
_applyStickyGroupVisibility: function(type, items, pushOffsets) {
const that = this;
const isHeader = type === "header";
const $container = isHeader ? that._stickyGroupHeaderContainer : that._stickyGroupFooterContainer;
const $lockedContainer = isHeader ? that._stickyGroupLockedHeaderContainer : that._stickyGroupLockedFooterContainer;
const container = $container[0];
const lockedContainer = $lockedContainer ? $lockedContainer[0] : null;
const changed = stickyItemsChanged(items, isHeader ? that._stickyHeaderItems || [] : that._stickyFooterItems || []);
const shouldShow = items.length > 0;
const applyTransforms = isHeader ? applyHeaderPushTransforms : applyFooterPushTransforms;
if (!shouldShow) {
$container.addClass("k-hidden");
resetStickyTransforms(container);
if (lockedContainer) {
$lockedContainer.addClass("k-hidden");
resetStickyTransforms(lockedContainer);
}
} else if (!changed) {
$container.removeClass("k-hidden");
applyTransforms(container, pushOffsets);
if (lockedContainer) {
$lockedContainer.removeClass("k-hidden");
applyTransforms(lockedContainer, pushOffsets);
}
} else {
if (isHeader) that._stickyHeaderItems = items;
else that._stickyFooterItems = items;
$container.removeClass("k-hidden");
if (lockedContainer) $lockedContainer.removeClass("k-hidden");
that._syncStickyGroupColgroups();
applyTransforms(container, pushOffsets);
if (lockedContainer) applyTransforms(lockedContainer, pushOffsets);
}
},
_syncStickyGroupScrollState: function(scrollContainer) {
const that = this;
if (!scrollContainer) return;
if (that.lockedContent) {
const lockedWidthPx = that.lockedContent[0].style.width;
if (lockedWidthPx && that._stickyGroupLockedHeaderContainer) that._stickyGroupLockedHeaderContainer[0].style.width = lockedWidthPx;
if (lockedWidthPx && that._stickyGroupLockedFooterContainer) that._stickyGroupLockedFooterContainer[0].style.width = lockedWidthPx;
}
const contentScrollLeft = scrollContainer.scrollLeft;
let headerScrollTarget = null;
if (that._stickyGroupHeaderContainer) headerScrollTarget = that.lockedContent ? that._stickyGroupHeaderContainer.children(".k-grid-header-wrap")[0] : that._stickyGroupHeaderContainer[0];
let footerScrollTarget = null;
if (that._stickyGroupFooterContainer) footerScrollTarget = that.lockedContent ? that._stickyGroupFooterContainer.children(".k-grid-footer-wrap")[0] : that._stickyGroupFooterContainer[0];
if (headerScrollTarget && headerScrollTarget.scrollLeft !== contentScrollLeft) headerScrollTarget.scrollLeft = contentScrollLeft;
if (footerScrollTarget && footerScrollTarget.scrollLeft !== contentScrollLeft) footerScrollTarget.scrollLeft = contentScrollLeft;
const scrollbarMargin = kendo.support.scrollbar() + "px";
if (that._stickyGroupHeaderContainer) that._stickyGroupHeaderContainer[0].style.marginInlineEnd = `var(--kendo-scrollbar-width, ${scrollbarMargin})`;
if (that._stickyGroupFooterContainer) that._stickyGroupFooterContainer[0].style.marginInlineEnd = `var(--kendo-scrollbar-width, ${scrollbarMargin})`;
const headerH = that._stickyGroupHeaderContainer ? that._stickyGroupHeaderContainer[0].offsetHeight : 0;
const footerH = that._stickyGroupFooterContainer ? that._stickyGroupFooterContainer[0].offsetHeight : 0;
scrollContainer.style.scrollPaddingTop = headerH > 0 ? `${headerH}px` : "";
scrollContainer.style.scrollPaddingBottom = footerH > 0 ? `${footerH}px` : "";
},
_updateStickyGroups: function() {
const that = this;
const isHeaderEnabled = that._hasStickyGroupHeaders();
const isFooterEnabled = that._hasStickyGroupFooters();
if (!isHeaderEnabled && !isFooterEnabled) return;
if (that._isLocked() && that.lockedContent && !that._stickyGroupLockedHeaderContainer) {
that._initStickyGroupLockedContainers();
that._syncStickyGroupColgroups();
}
const tbody = that.tbody ? that.tbody[0] : null;
const scrollContainer = that._stickyScrollContainer();
if (!tbody || !scrollContainer || !tbody.children.length) return;
if (that._groups() <= 0) {
if (that._stickyGroupHeaderContainer) that._stickyGroupHeaderContainer.addClass("k-hidden");
if (that._stickyGroupFooterContainer) that._stickyGroupFooterContainer.addClass("k-hidden");
if (that._stickyGroupLockedHeaderContainer) that._stickyGroupLockedHeaderContainer.addClass("k-hidden");
if (that._stickyGroupLockedFooterContainer) that._stickyGroupLockedFooterContainer.addClass("k-hidden");
return;
}
const skipOffset = that._stickyGroupVirtualOffset();
const groupRanges = buildGroupRangeMap(tbody, skipOffset, that.lockedTable ? that.lockedTable.find(">tbody")[0] : null);
if (!Object.keys(groupRanges).length) return;
const metrics = buildStickyRowMetrics(tbody, skipOffset);
const scrollTop = scrollContainer.scrollTop;
const viewportHeight = scrollContainer.clientHeight;
if (isHeaderEnabled && that._stickyGroupHeaderContainer) {
const { items, pushOffsets } = convergeStickyHeaders(metrics, groupRanges, scrollTop);
that._applyStickyGroupVisibility("header", items, pushOffsets);
}
if (isFooterEnabled && that._stickyGroupFooterContainer) {
const { items, pushOffsets } = convergeStickyFooters(metrics, groupRanges, scrollTop, viewportHeight);
that._applyStickyGroupVisibility("footer", items, pushOffsets);
const hasHorizontalScrollbar = scrollContainer.scrollWidth > scrollContainer.clientWidth;
that._stickyGroupFooterContainer[0].style.marginBlockEnd = hasHorizontalScrollbar ? `var(--kendo-scrollbar-width, ${kendo.support.scrollbar()}px)` : "";
}
that._syncStickyGroupScrollState(scrollContainer);
},
_renderStickyRows: function(items, indexProp, table, lockedTable) {
const that = this;
const tbody = table.find(">tbody");
const skipOffset = that._stickyGroupVirtualOffset();
tbody.html(renderStickyRowsHtml(that.tbody[0].children, items, indexProp, skipOffset));
kendo.applyStylesFromKendoAttributes(tbody, [
"display",
"left",
"right"
]);
if (lockedTable && that.lockedTable) {
const lockedTbody = lockedTable.find(">tbody");
const lockedRows = that.lockedTable.find(">tbody")[0].children;
lockedTbody.html(renderStickyRowsHtml(lockedRows, items, indexProp, skipOffset));
kendo.applyStylesFromKendoAttributes(lockedTbody, [
"display",
"left",
"right"
]);
}
},
_renderStickyHeaderRows: function(stickyHeaders) {
this._renderStickyRows(stickyHeaders, "headerIndex", this._stickyGroupHeaderTable, this._stickyGroupLockedHeaderTable);
},
_renderStickyFooterRows: function(stickyFooters) {
this._renderStickyRows(stickyFooters, "footerIndex", this._stickyGroupFooterTable, this._stickyGroupLockedFooterTable);
},
_removeGroupableOptionsFromHeader: function() {
var headerCells = this._headerCells();
for (var i = 0; i < headerCells.length; i++) headerCells.eq(i).removeData(GROUP_SORT);
},
_continuousItems: function(filter, cell) {
if (!this.lockedContent) return;
var that = this;
var elements = that.table.add(that.lockedTable);
var lockedItems = $(filter, elements[0]);
var nonLockedItems = $(filter, elements[1]);
var columns = cell ? lockedColumns(leafColumns(that.columns)).length : 1;
var nonLockedColumns = cell ? leafColumns(that.columns).length - columns : 1;
var result = [];
for (var idx = 0; idx < lockedItems.length; idx += columns) {
push.apply(result, lockedItems.slice(idx, idx + columns));
push.apply(result, [].splice.call(nonLockedItems, 0, nonLockedColumns));
}
return result;
},
_selectable: function() {
var that = this, multi, cell, notString = [], isLocked = that._isLocked(), selectable = that.options.selectable, hasSkeletonLoader = that.options.loaderType === "skeleton";
if (selectable && !selectable.checkboxSelection) {
if (that.selectable) that.selectable.destroy();
that._selectedIds = {};
selectable = kendo.ui.Selectable.parseOptions(selectable);
multi = selectable.multiple;
cell = selectable.cell;
if (that._hasDetails()) notString[notString.length] = ".k-detail-row";
if (that.options.groupable || that._hasFooters() || that._groups()) notString[notString.length] = ".k-grouping-row,.k-group-footer";
if (hasSkeletonLoader) notString[notString.length] = "[data-skeleton-row]";
notString = notString.join(",");
if (notString !== "") notString = ":not(" + notString + ")";
var elements = that.table;
if (isLocked) elements = elements.add(that.lockedTable);
const cellSelector = that._isStackedMode() ? STACKED_CELL_SELECTOR : SELECTION_CELL_SELECTOR;
var filter = ">" + (cell ? cellSelector : "tbody>tr" + notString);
that.selectable = new kendo.ui.Selectable(elements, {
allowPaste: that.options.allowPaste,
filter,
aria: true,
multiple: multi,
holdToDrag: !!(that._isMobile || kendo.support.mobileOS),
toggleable: !!(that._isMobile || kendo.support.mobileOS),
dragToSelect: that.options.selectable && that.options.selectable.dragToSelect,
changing: function(e) {
if (that.trigger(CHANGING, {
target: e.target,
originalEvent: e.originalEvent
})) e.preventDefault();
},
change: function(e) {
var selectedValues;
if (!cell) that._persistSelectedRows();
if (that._checkBoxSelection) {
selectedValues = that.selectable.value();
that._uncheckCheckBoxes();
that._checkRows(selectedValues);
if (selectedValues.length && selectedValues.length === that.items().length) that._toggleHeaderCheckState(true);
else that._toggleHeaderCheckState(false);
}
that._calculateAggregatesForSelected();
if (that._editMode() !== "incell") that._toggleToolbarEditingItemsVisibility();
that._syncPinnedSelection();
if (e.event) that.trigger(CHANGE, { cellAggregates: that._cellAggregates });
},
useAllItems: isLocked && multi && cell,
relatedTarget: function(items) {
if (cell || !isLocked) return;
var related;
var result = $();
for (var idx = 0, length = items.length; idx < length; idx++) {
related = that._relatedRow(items[idx]);
if (inArray(related[0], items) < 0) result = result.add(related);
}
return result;
},
continuousItems: function() {
return that._continuousItems(filter, cell);
},
ignoreOverlapped: that.options.selectable && that.options.selectable.ignoreOverlapped,
addIdToRanges: true
});
if (that.options.navigatable) elements.on("keydown.kendoGrid", function(e) {
var current = that.current();
var target = e.target;
var eventObject = { event: e };
var triggerChange;
var triggerChanging;
var lastSelection;
if (!current) return;
if (e.keyCode === keys.SPACEBAR && !e.shiftKey && $.inArray(target, elements) > -1 && !current.is(".k-grid-stack-edit-cell,.k-edit-cell,.k-header") && current.parent().is(":not(.k-grouping-row,.k-detail-row,.k-group-footer)")) {
e.preventDefault();
e.stopPropagation();
current = cell ? current : current.parent();
triggerChange = !current.hasClass(SELECTED) || that.selectable.value().length > 1;
triggerChanging = triggerChange || multi && current.hasClass(SELECTED) && e.ctrlKey;
if (triggerChanging && that.trigger(CHANGING, {
target: current,
originalEvent: e
})) return;
if (isLocked && !cell) current = current.add(that._relatedRow(current));
if (multi) {
if (!e.ctrlKey) that.selectable.clear();
else if (current.hasClass(SELECTED)) {
that._deselectCheckRows(current);
that._calculateAggregatesForSelected();
that.trigger(CHANGE, { cellAggregates: that._cellAggregates });
return;
}
} else that.selectable.clear();
if (!cell) that.selectable._lastActive = current;
that.selectable.value(current);
if (triggerChange) {
that._calculateAggregatesForSelected();
that.trigger(CHANGE, { cellAggregates: that._cellAggregates });
}
that._syncPinnedSelection();
} else if (!cell && ($(target).is("td") || $(target).is("table") && inArray(target, this._navigatableTables)) && (e.shiftKey && e.keyCode == keys.LEFT || e.shiftKey && e.keyCode == keys.RIGHT || e.shiftKey && e.keyCode == keys.UP || e.shiftKey && e.keyCode == keys.DOWN || e.keyCode === keys.SPACEBAR && e.shiftKey)) {
e.preventDefault();
e.stopPropagation();
current = current.parent();
if (that.trigger(CHANGING, {
target: current,
originalEvent: e
})) return;
lastSelection = that.selectable.value();
if (isLocked) current = current.add(that._relatedRow(current));
if (multi) {
if (!that.selectable._lastActive) that.selectable._lastActive = current;
that.selectable.selectRange(that.selectable._firstSelectee(), current);
if (!compareElements(lastSelection, that.selectable.value())) that.trigger(CHANGE, eventObject);
} else if (!current.hasClass(SELECTED)) {
that.selectable.clear();
that.selectable.value(current);
that._calculateAggregatesForSelected();
that.trigger(CHANGE, { cellAggregates: that._cellAggregates });
}
that._syncPinnedSelection();
}
});
}
},
_pasteReplaceHandler: function(plain) {
var that = this, rows, current, currentRow, currentRowUid, currentField, uids = [];
current = that.select().first();
if (that._isStackedMode() || !current.length) return;
if (current.is(TR)) current = current.children(TD).first();
rows = plain.split("\n").filter((f) => f);
currentRow = current.closest("tr");
currentField = that.thead.find("th:eq(" + current.index() + ")").data("field");
currentRowUid = currentRow.data("uid");
uids.push(currentRowUid);
currentRow.nextAll(ITEMROW).slice(0, rows.length - 1).each((i, item) => {
uids.push($(item).data("uid"));
});
that._executePaste(rows, uids, null, currentField);
},
_pasteInsertHandler: function(plain) {
var that = this, dataSource = that.dataSource, rows, current = that.select().first(), currentRow, dataItemIndex, dataItem;
if (!current.length) return;
if (current.is(TR)) current = current.children(TD).first();
rows = plain.split("\n").filter((f) => f);
currentRow = current.closest("tr");
dataItem = that.dataItem(currentRow);
dataItemIndex = dataSource.indexOf(dataItem) + 1;
that._executePaste(rows, null, dataItemIndex, null);
},
_executePaste: function(rows, uids, index, currentField) {
var that = this, dataSource = that.dataSource, update = uids || false, dataItem, row, cells, cell, column, field, selectedUids = that._getSelectedRowUids(), selectedColumnFields = that._getSelectedColumnFields(), changedItems = [], visibleColumns = visibleLeafColumns(that.columns).filter((col) => !col.selectable && !col.draggable & !col.command), startingIndex = currentField && visibleColumns.map((c) => c.field).indexOf(currentField);
if (rows.length === 1 && rows[0].split(" ").length === 1 && update) for (let j = 0; j < selectedUids.length; j++) {
const uid = selectedUids[j];
dataItem = dataSource.getByUid(uid);
cell = rows[0].split(" ")[0];
for (let j = 0; j < selectedColumnFields.length; j++) {
field = selectedColumnFields[j];
if (dataItem && cell) dataItem.set(field, cell);
}
if (dataItem && dataItem.dirty) changedItems.push(dataItem);
}
else for (let i = 0; i < rows.length; i++) {
row = rows[i];
cells = row.split(" ");
dataItem = update ? dataSource.getByUid(uids[i]) : dataSource.insert(index + i, {});
for (let j = 0; j < cells.length; j++) {
cell = cells[j].replace(/\r/, "");
column = visibleColumns[j + startingIndex || 0];
if (column && dataItem && cell) {
field = column.field;
dataItem.set(field, cell);
}
}
if (dataItem && dataItem.dirty) changedItems.push(dataItem);
}
that.trigger(PASTE, {
items: changedItems,
type: update ? "replace" : "insert"
});
},
_pasteKeyboardHandler: function(e) {
var that = this, current = that.current(), clipBoardData = e.originalEvent.clipboardData, operation = that.pasteActionsDropDownList && that.pasteActionsDropDownList.value() || "insert", rowUid, cellIndex, plain;
if ($(e.target).is(".k-grid-stack-edit-cell input:visible,.k-edit-cell input:visible")) return;
if (clipBoardData) {
e.preventDefault();
plain = clipBoardData.getData("text").trimEnd();
if (isEmptyString(plain)) plain = " ";
if (current && current.length) {
cellIndex = current.index();
rowUid = current.closest(TR).data("uid");
}
if (operation === "replace") that._pasteReplaceHandler(plain);
if (operation === "insert") that._pasteInsertHandler(plain);
if (cellIndex && rowUid) {
that._currentRowIndex = that.wrapper.find("tr[data-uid='" + rowUid + "']").index();
that._restoreCurrent(cellIndex);
}
}
},
_paste: function() {
var that = this, options = that.options, selectable = options.selectable;
if (options.allowPaste && selectable) {
that.pasteHandler = that._pasteKeyboardHandler.bind(that);
(that.content || that.table).on("paste.kendoGrid", that.pasteHandler);
if (that.options.toolbar) that._pasteToolbarDropDown();
}
},
_clipboard: function() {
var options = this.options;
if (options.selectable && options.allowCopy) {
var grid = this;
if (!options.navigatable) {
grid.table.attr(TABINDEX, 0);
grid.table.add(grid.lockedTable).on("mousedown.kendoGrid keydown.kendoGrid", ".k-detail-cell", function(e) {
if (e.target !== e.currentTarget) e.stopImmediatePropagation();
}).on("mousedown.kendoGrid", "tr:not(.k-footer-template):visible>:not(.k-group-cell):not(.k-detail-cell):not(.k-hierarchy-cell):visible", tableClick.bind(grid));
}
grid.copyHandler = grid.copySelection.bind(grid);
grid.updateClipBoardState = function() {
if (grid.areaClipBoard) grid.areaClipBoard.val(grid.getTSV()).trigger("focus").select();
};
const container = grid.content || grid.table;
grid.bind("change", grid.updateClipBoardState);
container.on("keydown", grid.copyHandler);
grid.clearAreaHandler = grid.clearArea.bind(grid);
container.on("keyup", grid.clearAreaHandler);
}
},
copySelectionToClipboard: function(includeHeaders) {
this._createAreaClipBoard();
this.areaClipBoard.val(this.getTSV(includeHeaders)).trigger("focus").select();
document.execCommand("copy");
},
copySelection: function(e) {
if (e instanceof jQuery.Event && !(e.ctrlKey || e.metaKey) || !(e.keyCode === 67 && (e.ctrlKey || e.metaKey)) || $(e.target).is("input:visible,textarea:visible") || window.getSelection && window.getSelection().toString() || document.selection && document.selection.createRange().text) return;
this._createAreaClipBoard();
this.areaClipBoard.val(this.getTSV()).trigger("focus").select();
},
_createAreaClipBoard: function() {
if (!this.areaClipBoard) this.areaClipBoard = $("<textarea />").css({
position: "fixed",
top: "50%",
left: "50%",
opacity: 0,
width: 0,
height: 0
}).appendTo(this.wrapper);
},
getTSV: function(includeHeaders) {
var grid = this;
var selected = grid.select();
var delimeter = " ";
var allowCopy = grid.options.allowCopy;
var onlyVisible = true;
var hasLockedCols = grid._isLocked() && lockedColumns(grid.columns).length;
if ($.isPlainObject(allowCopy) && allowCopy.delimeter) delimeter = allowCopy.delimeter;
var text = "";
if (selected.length) {
if (selected.eq(0).is(TR)) selected = selected.find("td:not(.k-group-cell)");
if (onlyVisible) selected.filter(":visible");
var result = [];
var cellsOffset = this.columns.length;
var lockedCols = grid._isLocked() && lockedColumns(grid.columns).length;
var inLockedArea = true;
var fields = [];
var field;
var columns = visibleLeafColumns(this.columns);
$.each(selected, function(idx, cell) {
cell = $(cell);
field = grid._getCellField(cell, hasLockedCols);
if (columns.findIndex((c) => c.field === field) === -1) return;
var rowIndex = cell.closest(TR).index();
var cellIndex = cell.index();
if (onlyVisible) cellIndex -= cell.prevAll(":hidden").length;
if (lockedCols && inLockedArea) inLockedArea = $.contains(grid.lockedTable[0], cell[0]);
if (grid._groups() && inLockedArea) cellIndex -= grid._groups();
cellIndex = inLockedArea ? cellIndex : cellIndex + lockedCols;
if (field) fields[cellIndex] = field;
if (cellsOffset > cellIndex) cellsOffset = cellIndex;
var cellText = cell.text();
if (!result[rowIndex]) result[rowIndex] = [];
result[rowIndex][cellIndex] = cellText;
});
var rowsOffset = result.length;
result = $.each(result, function(idx, val) {
if (val) {
result[idx] = val.slice(cellsOffset);
if (rowsOffset > idx) rowsOffset = idx;
}
});
if (includeHeaders && fields.length) {
result.splice(rowsOffset, 0, fields.map(function(field) {
return getTitle(field, columns);
}));
var headerIndex = result.findIndex(function(el) {
return el !== undefined;
});
result[headerIndex] = result[headerIndex].slice(cellsOffset);
}
$.each(result.slice(rowsOffset), function(idx, val) {
if (val) text += val.join(delimeter) + "\r\n";
else text += "\r\n";
});
}
return text;
},
clearArea: function(e) {
if (this.areaClipBoard && e && e.target === this.areaClipBoard[0]) focusTable(this.table, true);
if (this.areaClipBoard) {
this.areaClipBoard.remove();
this.areaClipBoard = null;
}
},
_adaptiveColumns: function() {
var that = this;
if (that._anyColumnHasMediaQuery()) {
that._setColumnsMediaVisibility(that.columns);
that._attachColumnMediaResizeHandler();
}
},
_anyColumnHasMediaQuery: function() {
return this._columnsWithMediaQuery().length;
},
_columnsWithMediaQuery: function() {
return columnsWithMedia(this.columns);
},
_attachColumnMediaResizeHandler: function() {
var that = this;
that._detachColumnMediaResizeHandler();
that._columnMediaResizeHandler = that._onColumnMediaResize.bind(that);
$(window).on("resize.kendoGrid", that._columnMediaResizeHandler);
},
_detachColumnMediaResizeHandler: function() {
var that = this;
if (that._columnMediaResizeHandler) $(window).off("resize.kendoGrid", that._columnMediaResizeHandler);
},
_onColumnMediaResize: function() {
var that = this;
that._setColumnsMediaVisibility(that.columns);
that._setContentMediaWidth();
},
_setColumnsMediaVisibility: function(columns) {
var cols = columns || [];
for (var i = 0; i < cols.length; i++) this._setColumnMediaVisibility(cols[i]);
},
_setColumnMediaVisibility: function(column) {
var that = this;
if (isUndefined(column.media)) that._setColumnsMediaVisibility(column.columns);
else if (columnMatchesMedia(column)) {
that._showColumnByMedia(column);
if (!column.hidden) that._setColumnsMediaVisibility(column.columns);
} else that._hideColumnByMedia(column);
},
_showColumnByMedia: function(column) {
if (!column.hidden) this.showColumn(column);
setColumnMatchesMedia(column);
},
_hideColumnByMedia: function(column) {
var initiallyHidden = column.hidden;
if (!initiallyHidden) {
column._hideByMedia = true;
this.hideColumn(column);
column._hideByMedia = false;
column.hidden = initiallyHidden;
}
setColumnMatchesMedia(column);
},
_setContentMediaWidth: function() {
var that = this;
var options = that.options;
var isLocked = that._isLocked();
var footer;
if (options.scrollable && (options.resizable === true || options.resizable && options.resizable.columns === true)) {
if (isLocked && that.lockedFooter) footer = that.lockedFooter.children("table");
else if (that.footer) footer = that.footer.find(">.k-grid-footer-wrap>table");
if (!footer || !footer[0]) footer = $();
var header = isLocked ? that.wrapper.find(".k-grid-header-locked").find("table") : that.wrapper.find(".k-grid-header").find("table");
var contentTable = isLocked ? that.lockedTable : that.table;
var headerColumns = header.find("th");
var headerColgroup = header.find("colgroup");
var headerColumnsCount = headerColumns.length;
var visibleHeaderColumnsCount = headerColumns.filter(isCellVisible).length;
var hiddenHeaderColumnsCount = headerColumns.length - visibleHeaderColumnsCount;
var totalHeaderWidth = 0;
if (header[0].style.width !== "" && parseFloat(header[0].style.width) !== totalHeaderWidth) {
var currentHeaderWidth = header.css(WIDTH);
for (var i = 0; i < headerColumnsCount; i++) if (isElementVisible(headerColumns[i])) {
var columnWidth;
var cellIndex = Math.max(i, i - hiddenHeaderColumnsCount);
var colgroupChild = headerColgroup.children()[cellIndex];
var columnStyleWidth = colgroupChild ? colgroupChild.style.width : "";
if (columnStyleWidth !== "") columnWidth = parseFloat(columnStyleWidth);
else {
header.css(WIDTH, AUTO);
columnWidth = outerWidth(headerColumns.eq(i));
header.css(WIDTH, currentHeaderWidth);
}
totalHeaderWidth += columnWidth;
}
contentTable.css("width", totalHeaderWidth - 1);
header.css("width", totalHeaderWidth);
footer.css("width", totalHeaderWidth);
that._updateStickyColumns();
}
}
},
_minScreenSupport: function() {
if (this.hideMinScreenCols()) {
this.minScreenResizeHandler = this.hideMinScreenCols.bind(this);
$(window).on("resize", this.minScreenResizeHandler);
}
},
hideMinScreenCols: function() {
var cols = this.columns, screenWidth = window.innerWidth > 0 ? window.innerWidth : screen.width;
return this._iterateMinScreenCols(cols, screenWidth);
},
_iterateMinScreenCols: function(cols, screenWidth) {
var any = false;
for (var i = 0; i < cols.length; i++) {
var col = cols[i];
var minWidth = col.minScreenWidth;
if (minWidth !== undefined && minWidth !== null) {
any = true;
if (minWidth > screenWidth) this.hideColumn(col);
else this.showColumn(col);
}
if (!col.hidden && col.columns) any = this._iterateMinScreenCols(col.columns, screenWidth) || any;
}
return any;
},
_stickyColumns: function() {
var that = this;
if (that._anyStickyColumns()) that._setStickyColumns(false);
},
_updateStickyColumns: function() {
var that = this;
var groupHeaderColumnTemplateColumns = grep(leafColumns(that.columns), function(column) {
return column.groupHeaderColumnTemplate;
});
if (that._anyStickyColumns()) {
that._setStickyColumns(true);
that._templates();
if (groupHeaderColumnTemplateColumns.length > 0) that._renderGroupRows();
if (that._hasFilterRow()) that._updateStickyFilterCells();
}
if (that._hasStickyGroupHeaders() || that._hasStickyGroupFooters()) that._syncStickyGroupColgroups();
},
_updateStickyFilterCells: function() {
var filterCells = this.thead.find(".k-filter-row").find("td:not(.k-group-cell,.k-hierarchy-cell)");
if (filterCells.length) filterCells.each(function() {
var th = $(this);
var column = th.data("column");
if (column.sticky) {
if (isPlainObject(column.stickyStyle)) th.css({
left: column.stickyStyle.left || "",
right: column.stickyStyle.right || ""
});
th.addClass(STICKY_HEADER_CLASS);
} else {
th.css({
left: "",
right: ""
});
th.removeClass(STICKY_HEADER_CLASS);
}
});
},
_anyStickyColumns: function() {
var that = this;
if (!that.tbody) return false;
return !that._isStackedMode() && stickyColumns(that.columns).length;
},
_setStickyColumns: function(updateStyles) {
var that = this;
var columns = stickyColumns(that.columns);
var visibleColumns = visibleStickyColumns(that.columns);
var stickyWidths = that._calculateStickyWidths(visibleColumns);
that._removeStickyAttributes(columns);
that._setStickyClassAttributes(columns);
that._setStickyStyleAttributes(visibleColumns, stickyWidths, updateStyles);
if (updateStyles) that._setStickyStyles(visibleColumns, stickyWidths);
},
_calculateStickyWidths: function(columns, initialLeftWidth, initialRightWidth) {
var that = this;
var i;
var column;
var columnWidth;
var nextColumnLeft;
var nextColumnRight;
var left = isRtl ? "right" : "left";
var right = isRtl ? "left" : "right";
var stickyWidths = {
left: new Array(columns.length).fill(initialLeftWidth ? initialLeftWidth : 0),
right: new Array(columns.length).fill(initialRightWidth ? initialRightWidth : 0)
};
for (i = 0; i < columns.length - 1; i++) {
column = columns[i];
columnWidth = that._sumColumnWidth(column);
nextColumnLeft = columnWidth + stickyWidths[left][i];
stickyWidths[left][i + 1] = nextColumnLeft;
}
for (i = columns.length - 1; i > 0; i--) {
column = columns[i];
columnWidth = that._sumColumnWidth(column);
nextColumnRight = columnWidth + stickyWidths[right][i];
stickyWidths[right][i - 1] = nextColumnRight;
}
return stickyWidths;
},
_setStickyClassAttributes: function(columns, masterIndex) {
var that = this;
var i;
var column;
for (i = 0; i < columns.length; i++) {
column = columns[i];
if (column.columns) {
if (!masterIndex && i) masterIndex = i;
that._setStickyClassAttributes(childColumns([column]), masterIndex);
}
if (masterIndex) addColumnAttribute(column, "headerAttributes", "class", STICKY_HEADER_NO_BORDER_CLASS);
addColumnAttribute(column, "attributes", "class", STICKY_CELL_CLASS);
addColumnAttribute(column, "headerAttributes", "class", STICKY_HEADER_CLASS);
addColumnAttribute(column, "footerAttributes", "class", STICKY_FOOTER_CLASS);
}
},
_setStickyStyleAttributes: function(columns, stickyWidths, updateStyles) {
var that = this;
var i;
var column;
var stickyLeft;
var stickyRight;
var stickyStyle;
var childCols;
var childStickyWidths;
for (i = 0; i < columns.length; i++) {
column = columns[i];
stickyLeft = stickyWidths.left[i];
stickyRight = stickyWidths.right[i];
stickyStyle = {
left: stickyLeft + "px",
right: stickyRight + "px"
};
if (column.columns) {
childCols = visibleChildColumns([column]);
childStickyWidths = that._calculateStickyWidths(childCols, stickyLeft, stickyRight);
that._setStickyStyleAttributes(childCols, childStickyWidths, updateStyles);
if (updateStyles) that._setStickyStyles(childCols, childStickyWidths);
}
addColumnAttribute(column, "attributes", kendo.attr("style-left"), stickyStyle.left);
addColumnAttribute(column, "attributes", kendo.attr("style-right"), stickyStyle.right);
addColumnAttribute(column, "headerAttributes", kendo.attr("style-left"), stickyStyle.left);
addColumnAttribute(column, "headerAttributes", kendo.attr("style-right"), stickyStyle.right);
addColumnAttribute(column, "footerAttributes", kendo.attr("style-left"), stickyStyle.left);
addColumnAttribute(column, "footerAttributes", kendo.attr("style-right"), stickyStyle.right);
column.stickyStyle = stickyStyle;
}
},
_removeStickyAttributes: function(columns) {
var that = this;
var i;
var cellClassRegExp = /* @__PURE__ */ new RegExp("(\\s*k-grid-content-sticky)*", "ig");
var headerClassRegExp = /* @__PURE__ */ new RegExp("(\\s*k-grid-header-sticky)*", "ig");
var footerClassRegExp = /* @__PURE__ */ new RegExp("(\\s*k-grid-footer-sticky)*", "ig");
var headerClassNoBorderRegExp = /* @__PURE__ */ new RegExp("(\\s*k-grid-no-left-border)*", "ig");
var column;
for (i = 0; i < columns.length; i++) {
column = columns[i];
if (column.columns) that._removeStickyAttributes(childColumns([column]));
removeColumnAttribute(column, "attributes", "class", cellClassRegExp);
removeColumnAttribute(column, "attributes", kendo.attr("style-left"), "", true);
removeColumnAttribute(column, "attributes", kendo.attr("style-right"), "", true);
removeColumnAttribute(column, "headerAttributes", "class", headerClassRegExp);
removeColumnAttribute(column, "headerAttributes", "class", headerClassNoBorderRegExp);
removeColumnAttribute(column, "headerAttributes", kendo.attr("style-left"), "", true);
removeColumnAttribute(column, "headerAttributes", kendo.attr("style-right"), "", true);
removeColumnAttribute(column, "footerAttributes", "class", footerClassRegExp);
removeColumnAttribute(column, "footerAttributes", kendo.attr("style-left"), "", true);
removeColumnAttribute(column, "footerAttributes", kendo.attr("style-right"), "", true);
}
},
_setStickyStyles: function(columns, stickyWidths) {
var that = this;
var i;
var j;
var leafsCols = leafColumns(nonLockedColumns(that.columns));
var rows = that.tbody.children(":not(.k-detail-row)");
var row;
var column;
var columnIndex;
var left;
var right;
var header;
var footer;
var groupHeader;
var cell;
for (i = 0; i < columns.length; i++) {
column = columns[i];
left = stickyWidths.left[i];
right = stickyWidths.right[i];
columnIndex = leafsCols.indexOf(column);
header = that._getColumnHeader(column);
header.addClass(STICKY_HEADER_CLASS);
if (column.headerAttributes["class"] && column.headerAttributes["class"].indexOf(STICKY_HEADER_NO_BORDER_CLASS) !== -1) header.addClass(STICKY_HEADER_NO_BORDER_CLASS);
setLeftAndRightStyles(header, left, right);
if (column.columns) continue;
if (that.footer) {
footer = that.footer.find(".k-grid-footer-wrap tr.k-footer-template").children().filter(":not(.k-group-cell,.k-hierarchy-cell)").eq(columnIndex);
footer.addClass(STICKY_FOOTER_CLASS);
setLeftAndRightStyles(footer, left, right);
}
for (j = 0; j < rows.length; j++) {
row = $(rows[j]);
if (row.hasClass(GROUPING_ROW)) {
groupHeader = row.find("." + column.groupHeaderColumnTemplateClass);
groupHeader.addClass(STICKY_CELL_CLASS);
setLeftAndRightStyles(groupHeader, left, right);
} else {
cell = row.children().filter(":not(.k-group-cell,.k-hierarchy-cell)").eq(columnIndex);
cell.addClass(STICKY_CELL_CLASS);
setLeftAndRightStyles(cell, left, right);
}
}
}
},
_removeStickyStyles: function(columns) {
var that = this;
var i;
var j;
var leafsCols = leafColumns(nonLockedColumns(that.columns));
var rows = that.tbody.children(":not(.k-detail-row)");
var row;
var column;
var columnIndex;
var header;
var footer;
var groupHeader;
var cell;
for (i = 0; i < columns.length; i++) {
column = columns[i];
columnIndex = leafsCols.indexOf(column);
header = that._getColumnHeader(column);
header.removeClass(STICKY_HEADER_CLASS);
header.removeClass(STICKY_HEADER_NO_BORDER_CLASS);
setLeftAndRightStyles(header, "", "");
if (column.columns) {
that._removeStickyStyles(column.columns);
continue;
}
if (column.footerTemplate && that.footer) {
footer = that.footer.find(".k-grid-footer-wrap tr.k-footer-template").children().filter(":not(.k-group-cell,.k-hierarchy-cell)").eq(columnIndex);
footer.removeClass(STICKY_FOOTER_CLASS);
setLeftAndRightStyles(footer, "", "");
}
for (j = 0; j < rows.length; j++) {
row = $(rows[j]);
if (row.hasClass(GROUPING_ROW)) {
groupHeader = row.find("." + column.groupHeaderColumnTemplateClass);
groupHeader.removeClass(STICKY_CELL_CLASS);
setLeftAndRightStyles(groupHeader, "", "");
} else {
cell = row.children().filter(":not(.k-group-cell,.k-hierarchy-cell)").eq(columnIndex);
cell.removeClass(STICKY_CELL_CLASS);
setLeftAndRightStyles(cell, "", "");
}
}
}
},
_getColumnHeader: function(column) {
var that = this;
return $("#" + column.headerAttributes.id).length ? $("#" + column.headerAttributes.id) : $("#" + that._cellId);
},
_sumColumnWidth: function(column) {
var that = this;
var width = 0;
if (column.columns) width = that._sumCurrentWidths(leafColumns([column]));
else width = that._sumCurrentWidths([column]);
return width;
},
_sumCurrentWidths: function(cols) {
var that = this;
var width = 0;
var colWidth = 0;
var col;
var header;
var i;
var length = cols.length;
for (i = 0; i < length; i++) {
col = cols[i];
header = that._getColumnHeader(col);
if (!col.hidden && columnMatchesMedia(col)) {
colWidth = header.is(":visible") ? header.outerWidth() : col.width;
width += colWidth ? parseInt(colWidth, 10) : 0;
}
}
return width;
},
_belongsToGrid: function(element) {
return this.wrapper[0] === element.closest(WRAPPER)[0];
},
getSelectedData: function() {
const that = this;
const selectable = that.selectable;
const checkboxSelection = that._checkBoxSelection;
const visibleColumns = visibleLeafColumns(that.columns);
let result = [];
if (selectable) {
const selectedRanges = that.selectable?.selectedRanges();
const selectedRangeNames = Object.keys(selectedRanges);
const selectedSingleItems = that.selectable?.selectedSingleItems();
for (var idx = 0; idx < selectedRangeNames.length; idx++) result = result.concat(that._mapSelectionToData(selectedRanges[selectedRangeNames[idx]], visibleColumns, null, true));
if (selectedSingleItems.length) result = result.concat(that._mapSelectionToData(selectedSingleItems, visibleColumns, null, true));
return result;
}
if (checkboxSelection) {
const selectedRows = that.tbody.find("tr.k-selected").toArray().map(function(elem) {
return $(elem);
});
if (selectedRows.length) result = that._mapSelectionToData(selectedRows, visibleColumns, null, true);
}
return result;
},
getSelectedDataByKeys: function() {
var that = this, dataSource = that.dataSource, keys = that.selectedKeyNames(), visibleColumns = visibleLeafColumns(that.columns), key, dataItem, result = {};
var columnMapHandler = function(col) {
var result = {};
if (!col.field) return;
result[col.field] = dataItem[col.field];
return result;
};
for (let i = 0; i < keys.length; i++) {
key = keys[i];
dataItem = dataSource.get(key);
if (dataItem) result[dataItem.uid] = $.extend.apply({}, visibleColumns.map(columnMapHandler));
}
return Object.keys(result).map(function(id) {
return result[id];
});
},
exportSelectedToExcel: function(includeHeaders) {
if (!kendo.excel || !kendo.ooxml) throw new Error("The excel export functionality depends on both kendo.excel.js and kendo.ooxml.js scripts, please make sure they are included.");
var that = this;
var excel = this.options.excel || {};
var visibleColumns = visibleLeafColumns(that.columns);
var exporter = new kendo.excel.ExcelExporter({});
var columnHandler = function() {
return { autoWidth: true };
};
var book = { sheets: [{
columns: Array.apply(0, Array(visibleColumns.length)).map(columnHandler),
rows: [],
freezePane: {},
filter: false
}] };
var selectedRanges = that.selectable.selectedRanges();
var selectedRangeNames = Object.keys(selectedRanges);
var selectedSingleItems = that.selectable.selectedSingleItems();
var idx;
var exportData = [];
var hasLockedCols = that._isLocked() && lockedColumns(that.columns).length;
var sortHandler = exportDataSort.bind(that);
for (idx = 0; idx < selectedRangeNames.length; idx++) exportData = exportData.concat(that._mapSelectionToData(selectedRanges[selectedRangeNames[idx]], visibleColumns, isExcelExportableColumn));
if (exportData.length) that._addRangeSelectionRows(book, exporter, exportData, includeHeaders);
exportData = selectedSingleItems.length ? that._mapSelectionToData(selectedSingleItems, visibleColumns, isExcelExportableColumn) : [];
if (exportData.length) {
if (hasLockedCols) exportData = exportData.sort(sortHandler);
that._addSingleSelectionRows(book, exporter, exportData, includeHeaders);
}
if (book.sheets[0].rows.length) {
var workbook = new kendo.ooxml.Workbook(book);
if (!workbook.options) workbook.options = {};
workbook.options.skipCustomHeight = true;
workbook.toDataURLAsync().then(function(dataURI) {
kendo.saveAs({
dataURI,
fileName: book.fileName || excel.fileName,
proxyURL: excel.proxyURL,
forceProxy: excel.forceProxy
});
});
}
},
exportSelectedToCSV: function(includeHeaders) {
const selectedItems = this._getSelectedRowData();
if (selectedItems.length) return this._saveCSVData(selectedItems, includeHeaders);
},
_getSelectedRowData: function() {
if (!this.selectable && !this._checkBoxSelection) return [];
const that = this;
const selected = this.select();
const seen = {};
const items = [];
const selectedKeys = that.options.persistSelection ? that.selectedKeyNames() : [];
if (selected.length && !selected.eq(0).is(TR)) return [];
if (selectedKeys.length) {
for (let idx = 0; idx < selectedKeys.length; idx++) {
const item = that.dataSource.get(selectedKeys[idx]);
if (item && !seen[item.uid]) {
seen[item.uid] = true;
items.push(item.toJSON());
}
}
return items;
}
selected.each(function() {
const row = this.nodeName === "TR" ? $(this) : $(this).closest("tr");
const item = that.dataItem(row);
if (item && !seen[item.uid]) {
seen[item.uid] = true;
items.push(item.toJSON());
}
});
return items;
},
_addSingleSelectionRows: function(book, exporter, data, includeHeaders) {
var idx = 0;
var visibleColumns = visibleLeafExportColumns(this.columns);
var item;
const exporterInstance = exporter._instance ?? exporter;
for (idx = 0; idx < data.length; idx++) {
item = data[idx];
exporter.data = [item];
this._setExporterColumns(exporterInstance, visibleColumns, item);
this._createExportRows(book, exporterInstance, includeHeaders);
}
},
_addRangeSelectionRows: function(book, exporter, data, includeHeaders) {
var visibleColumns = visibleLeafExportColumns(this.columns);
const exporterInstance = exporter._instance ?? exporter;
exporter.data = data;
this._setExporterColumns(exporterInstance, visibleColumns, data[0]);
this._createExportRows(book, exporterInstance, includeHeaders);
},
_createExportRows: function(book, exporter, includeHeaders) {
const exporterInstance = exporter._instance ?? exporter;
book.sheets[0].rows = book.sheets[0].rows.concat(includeHeaders ? exporterInstance._rows() : exporterInstance._dataRows(exporterInstance.data, 0));
},
_setExporterColumns: function(exporter, columns, item) {
const exporterInstance = exporter._instance ?? exporter;
exporterInstance.columns = exporterInstance.options.columns = $.map(columns.filter(function(col) {
return Object.keys(item).indexOf(col.field) >= 0;
}), exporterInstance._prepareColumn);
},
_mapSelectionToData: function(elements, visibleColumns, columnsFilter, ignoreOffset) {
var that = this;
var isRowSelection = elements[0][0].nodeName === "TR";
var dataItem;
var result = {};
var element;
var curr;
var field;
var columnMapHandler = function(col) {
var result = {};
if (!col.field || columnsFilter && !columnsFilter(col)) return;
result[col.field] = dataItem[col.field];
return result;
};
var hasLockedCols = that._isLocked() && lockedColumns(that.columns).length;
var column;
for (var i = 0; i < elements.length; i++) {
element = elements[i];
dataItem = that.dataItem(isRowSelection ? element : element.closest(TR));
if (isRowSelection) result[dataItem.uid] = $.extend.apply({}, visibleColumns.map(columnMapHandler));
else {
field = that._getCellField(element, hasLockedCols, ignoreOffset);
if (!field) continue;
curr = result[dataItem.uid];
if (!curr) curr = result[dataItem.uid] = {};
column = findColumnByField(visibleColumns, field);
if (!column || columnsFilter && !columnsFilter(column)) continue;
curr[field] = dataItem[field];
}
}
return Object.keys(result).map(function(id) {
result[id].uid = id;
return result[id];
});
},
_getCellField: function(cell, hasLockedCols, ignoreOffset) {
const grid = this;
const inLockedArea = hasLockedCols && $.contains(grid.lockedTable[0], cell[0]);
const fieldAttr = kendo.attr("field");
const index = kendo.attr("index");
const lockedOffset = inLockedArea ? 0 : hasLockedCols;
let indexOffset = 0;
if (ignoreOffset) indexOffset = grid._trailingColumns();
if (grid._isStackedMode()) return grid.table.find("div.k-grid-stack-cell[" + index + "='" + (cell.index() - indexOffset) + "']").attr(fieldAttr);
else if (hasLockedCols) return grid.element.find(".k-grid-header-" + (inLockedArea ? "locked" : "wrap") + " th[" + index + "='" + (cell.index() + lockedOffset) + "']").attr(fieldAttr);
else return grid.thead && grid.thead.find("th[" + index + "='" + (cell.index() - indexOffset) + "']").attr(fieldAttr);
},
_relatedRow: function(row) {
var lockedTable = this.lockedTable;
row = $(row);
if (!lockedTable) return row;
var table = row.closest(this.table.add(this.lockedTable));
var index = table.find(">tbody>tr").index(row);
table = table[0] === this.table[0] ? lockedTable : this.table;
return table.find(">tbody>tr").eq(index);
},
_relatedCell: function(cell) {
var lockedTable = this.lockedTable;
cell = $(cell);
if (!lockedTable) return cell;
var table = cell.closest(this.table.add(this.lockedTable));
var index = table.find(">tbody>tr>td").index(cell);
table = table[0] === this.table[0] ? lockedTable : this.table;
return table.find(">tbody>tr>td").index(index);
},
clearSelection: function() {
var that = this;
if (that.selectable && !that._checkBoxSelection) that.selectable.clear();
if (that._hasAISelection) delete that._hasAISelection;
if (that._checkBoxSelection) {
that._deselectCheckRows(that.select());
return;
}
if (that.options.persistSelection) that._persistSelectedRows();
else that._selectedIds = {};
},
clearHighlight: function() {
const that = this;
if (that._highlightDescriptors) delete that._highlightDescriptors;
if (that._highlightedItems && that._highlightedItems.length) {
that._highlightedItems.removeClass(HIGHLIGHTED);
delete that._highlightedItems;
}
if (that._hasAIHighlight) delete that._hasAIHighlight;
that._syncPinnedHighlight();
},
_getElementsToProcess: function(data) {
const that = this;
const columns = that.columns;
const lockedColumns = [];
const nonLockedCols = [];
const elements = [];
const rowSelector = (uid) => `tr[data-uid='${uid}']`;
const getColIndex = (cols, field) => cols.length && cols.findIndex((col) => col.field === field);
grep(columns, (col) => {
if (col.locked) lockedColumns.push(col);
else nonLockedCols.push(col);
});
Object.entries(data).forEach(([key, value]) => {
if (!key) return;
const item = that.dataSource.get(key);
if (!item) return;
let row = that.tbody.find(rowSelector(item.uid));
if (value === true) elements.push(row);
else if (typeof value === "object") Object.keys(value).forEach((field) => {
if (!field && !value[field]) return;
let isLockedCell = false;
let columnIndex = getColIndex(nonLockedCols, field);
if (columnIndex === -1) {
columnIndex = getColIndex(lockedColumns, field);
isLockedCell = true;
}
if (isLockedCell) row = that._relatedRow(row);
const td = row.find(`td:eq(${columnIndex})`);
if (td.length) {
elements.push(td);
row = that.tbody.find(rowSelector(item.uid));
}
});
});
return elements;
},
_getElementsToHighlight: function(data) {
return this._getElementsToProcess(data);
},
_getElementsToSelect: function(data) {
return this._getElementsToProcess(data);
},
_restoreHighlight: function() {
const that = this;
const highlightDescriptors = that._highlightDescriptors;
if (!highlightDescriptors || !Object.keys(highlightDescriptors).length) return;
that.highlight(highlightDescriptors);
},
_persistHighlight: function(element) {
const that = this;
const highlightDescriptor = {};
const isRow = element.is("tr");
const idField = that.options.dataSource?.schema?.model?.id || "id";
const uid = (isRow ? element : element.closest("tr")).data("uid");
const item = that.dataSource.getByUid(uid);
if (!item) return;
const key = item[idField];
if (isRow) highlightDescriptor[key] = true;
else {
const field = that._getCellField(element, that._isLocked(), true);
if (!field) return;
highlightDescriptor[key] = field;
}
if (that._highlightDescriptors) that._highlightDescriptors = that._mergeHighlightDescriptor(that._highlightDescriptors, highlightDescriptor);
else that._highlightDescriptors = highlightDescriptor;
},
_mergeHighlightDescriptor: function(existingDescriptors, newDescriptor) {
const merged = {};
let key, existingValue, newValue;
for (key in existingDescriptors) merged[key] = existingDescriptors[key];
for (key in newDescriptor) {
existingValue = merged[key];
newValue = newDescriptor[key];
if (existingValue === undefined) merged[key] = newValue;
else if (newValue === true) merged[key] = true;
else if (typeof newValue === "object" && newValue !== null && typeof existingValue === "object" && existingValue !== null) merged[key] = extend({}, existingValue, newValue);
else merged[key] = existingValue;
}
return merged;
},
highlight: function(data) {
const that = this;
const lockedContainer = that.lockedTable;
const isEmptyArray = Array.isArray(data) && !data.length;
if (!data && !isEmptyArray) return that._highlightedItems || $();
if (isEmptyArray) {
that.clearHighlight();
return;
}
const keys = typeof data === "object" && !Array.isArray(data) ? Object.keys(data) : [];
const isHighlightDescriptor = keys.length && that.dataSource.get(keys[0]);
let itemsToHighlight;
if (isHighlightDescriptor) {
that._highlightDescriptors = that._mergeHighlightDescriptor(that._highlightDescriptors || {}, data);
itemsToHighlight = that._getElementsToHighlight(data);
} else itemsToHighlight = Array.isArray(data) ? data : [data];
const highlightRelatedRow = (item) => {
const targetIsRow = item.is("tr");
let relatedItem;
if (!item) return;
if (targetIsRow && lockedContainer?.length) {
relatedItem = that._relatedRow(item);
item = item.add(relatedItem);
}
return item;
};
itemsToHighlight.forEach(function(item) {
const target = highlightRelatedRow($(item));
if (target && !isHighlightDescriptor) that._persistHighlight(target);
if (target?.length) {
if (that._highlightedItems && that._highlightedItems.index(target) !== -1) return;
target.addClass(HIGHLIGHTED);
if (that._highlightedItems) that._highlightedItems = that._highlightedItems.add(target);
else that._highlightedItems = target;
}
});
that._syncPinnedHighlight();
},
select: function(items) {
var that = this, selectable = that.selectable, cell = kendo.ui.Selectable.parseOptions(this.options.selectable).cell;
items = that.table.add(that.lockedTable).find(items);
if (items.length) {
if (selectable && !selectable.options.multiple) {
selectable.clear();
items = items.first();
}
if (that._isLocked()) items = items.add(items.map(function() {
if (cell) return that._relatedCell(this);
else return that._relatedRow(this);
}));
if (selectable && !that._checkBoxSelection) selectable.value(items);
else {
that._checkRows(items);
if (that.select().length === that.items().length) that._toggleHeaderCheckState(true);
}
if (!cell) that._persistSelectedRows();
that._syncPinnedSelection();
return;
}
return selectable ? selectable.value() : that.items().filter(".k-selected");
},
_initSelectableAggregates: function() {
var that = this;
if (!that.options.selectable) return;
if (!that._selectableAggregatesOptions) that._selectableAggregatesOptions = that._parseSelectableAggregatesOptions();
if (that._selectableAggregatesOptions.count) that._cellAggregates = { count: 0 };
},
_calculateAggregatesForSelected: function() {
var that = this, options = that.options, selectedData = that.getSelectedDataByKeys(), selectable = that.options.selectable, cellAggregates = selectable.cellAggregates, cellsLength = visibleLeafColumns(that.columns).filter((col) => !col.selectable && !col.draggable & !col.command).length, columnFields = getColumnsFields(options.columns), isCellSelection = kendo.ui.Selectable.parseOptions(selectable).cell, dataItem, type, value, numberAggregates = [], dateAggregates = [], booleanAggregates = [], count, min, max, sum, average, earliest, latest, isTrue, isFalse;
if (!cellAggregates) return;
if (isCellSelection) selectedData = that.getSelectedData();
cellAggregates = that._selectableAggregatesOptions;
for (let i = 0; i < selectedData.length; i++) {
dataItem = selectedData[i];
for (let j = 0; j < columnFields.length; j++) {
value = dataItem[columnFields[j]];
type = getType(value);
switch (type) {
case "number":
numberAggregates.push(value);
break;
case "date":
dateAggregates.push(value);
break;
case "boolean":
booleanAggregates.push(value);
break;
default: break;
}
}
}
if (cellAggregates.count) count = isCellSelection ? cellsExcludingSpecialColumns(that.select()).length : selectedData.length * cellsLength;
if (numberAggregates.length) {
max = cellAggregates.max ? numberAggregates.reduce((acc, current) => Math.max(acc, current)) : null;
min = cellAggregates.min ? numberAggregates.reduce((acc, current) => Math.min(acc, current)) : null;
sum = cellAggregates.sum ? numberAggregates.reduce((acc, current) => acc + current) : null;
average = cellAggregates.average ? numberAggregates.reduce((acc, current) => acc + current) / numberAggregates.length : null;
}
if (dateAggregates.length) {
earliest = cellAggregates.earliest ? dateAggregates.reduce((acc, current) => new Date(Math.min(acc, current))) : null;
latest = cellAggregates.latest ? dateAggregates.reduce((acc, current) => new Date(Math.max(acc, current))) : null;
}
if (booleanAggregates.length) {
isTrue = cellAggregates.isTrue ? booleanAggregates.filter((b) => b === true).length : null;
isFalse = cellAggregates.isFalse ? booleanAggregates.filter((b) => b === false).length : null;
}
that._cellAggregates = {
count,
max,
min,
sum,
average,
earliest,
latest,
isTrue,
isFalse
};
if (that.statusBar) that._statusBar();
},
_parseSelectableAggregatesOptions: function() {
var cellAggregates = this.options.selectable.cellAggregates, result = {};
if (isArray(cellAggregates)) {
for (let i = 0; i < cellAggregates.length; i++) result[cellAggregates[i]] = true;
return result;
}
return {
count: true,
min: true,
max: true,
sum: true,
average: true,
earliest: true,
latest: true,
isTrue: true,
isFalse: true
};
},
_toggleHeaderCheckState: function(checked) {
const that = this;
const stacked = that._isStackedMode();
const toolbar = that.wrapper.find(".k-toolbar");
const selectAllTool = toolbar.find(CHECKBOXINPUT);
let container = stacked ? toolbar : that.thead.add(that.lockedHeader);
let checkboxSelector = stacked ? CHECKBOXINPUT : "tr input[data-role='checkbox'].k-select-checkbox.k-checkbox";
const toggleState = (element, state) => {
if (element.length) {
const ariaLabel = state ? "Deselect all rows" : "Select all rows";
element.prop("checked", state).attr(ARIA_CHECKED, state).attr(ARIA_LABEL, ariaLabel);
}
};
if (stacked) toggleState(selectAllTool, checked);
else {
toggleState(container.find(checkboxSelector), checked);
toggleState(selectAllTool, checked);
}
},
_uncheckCheckBoxes: function() {
var that = this;
that.table.add(that.lockedTable).find("tbody input[data-role='checkbox'].k-select-checkbox.k-checkbox").attr(ARIA_CHECKED, false).prop("checked", false).attr(ARIA_LABEL, "Select row");
},
_deselectCheckRows: function(items) {
var that = this, rangeSelectedAttr = kendo.attr("range-selected");
items = that.table.add(that.lockedTable).find(items);
if (that._isLocked()) items = items.add(items.map(function() {
return that._relatedRow(this);
}));
items.each(function() {
$(this).removeClass(SELECTED).removeAttr(rangeSelectedAttr).find(CHECKBOXINPUT).attr(ARIA_CHECKED, false).prop("checked", false).attr(ARIA_LABEL, "Select row");
});
that._toggleHeaderCheckState(false);
that._persistSelectedRows();
},
_checkRows: function(items) {
items.each(function() {
$(this).addClass(SELECTED).find(CHECKBOXINPUT).prop("checked", true).attr(ARIA_LABEL, "Deselect row").attr(ARIA_CHECKED, true);
});
},
_persistSelectedRows: function() {
var that = this, key, dataItem, allRows = that.items(), schema = that.dataSource.options.schema, modelId, selectedViewIds = {};
if (!schema || !schema.model || !that._data) return;
modelId = that._getSchemaIdField();
if (!modelId) return;
if (!kendo.ui.Selectable.parseOptions(that.options.selectable).multiple && !that._checkBoxSelection) that._selectedIds = {};
that.select().each(function() {
dataItem = that.dataItem(this);
selectedViewIds[dataItem[modelId]] = true;
});
for (var i = 0; i < allRows.length; i++) {
dataItem = that.dataItem(allRows[i]);
key = dataItem[modelId];
if (selectedViewIds[key]) that._selectedIds[key] = true;
else delete that._selectedIds[key];
}
},
selectedKeyNames: function() {
var that = this, ids = [];
for (var property in that._selectedIds) ids.push(property);
ids.sort();
return ids;
},
_updateCurrentAttr: function(current, next, skipFocus) {
var headerId = $(current).data("headerId");
var nextId;
var descId;
$(current).removeClass(FOCUSED);
this.table.removeAttr(ARIA_ACTIVEDESCENDANT);
if (headerId) {
headerId = headerId.replace(this._cellId, "");
$(current).attr(ID, headerId);
} else $(current).removeAttr(ID);
nextId = next.attr(ID);
if (nextId != this._cellId) next.data("headerId", nextId);
if (!!nextId) descId = nextId;
else next.attr(ID, this._cellId);
if (!skipFocus) next.addClass(FOCUSED);
this.table.attr(ARIA_ACTIVEDESCENDANT, descId || this._cellId);
this._current = next;
},
_scrollCurrent: function() {
const current = this._current;
const scrollable = this.options.scrollable;
if (!current || !scrollable) return;
var row = current.parent();
var tableContainer = row.closest("table").parent();
var isInLockedContainer = tableContainer.is(".k-grid-content-locked,.k-grid-header-locked");
var isInContent = tableContainer.is(".k-grid-content-locked,.k-grid-content,.k-virtual-scrollable-wrap");
var scrollableContainer = $(this.content).find(">.k-virtual-scrollable-wrap").addBack().last()[0];
if (isInContent) if (this.virtualScroll) {
var rowIndex = Math.max(inArray(row[0], this._items(row.parent())), 0);
if (this.virtualScroll.rows) {
this._rowVirtualIndex = this.virtualScrollable.itemIndex(rowIndex);
this.virtualScrollable.scrollIntoView(row);
} else {
this._rowVirtualIndex = rowIndex;
this._scrollTo(this._relatedRow(row)[0], scrollableContainer);
}
} else this._scrollTo(this._relatedRow(row)[0], scrollableContainer);
if (this.lockedContent) this.lockedContent[0].scrollTop = scrollableContainer.scrollTop;
if (!isInLockedContainer) this._scrollTo(current[0], scrollableContainer);
},
_findGroupedItem: function(data, id, idField) {
const that = this;
let item;
for (let i = 0; i < data.length; i++) {
const group = data[i];
if (group.field === idField) {
if (group.value === id) if (group.items[0].uid && group.items[0][idField]) item = group.items[0];
else item = that._findGroupedItem(group.items, id, idField);
} else if (group.items[0].uid && group.items[0][idField]) item = group.items.find((item) => item[idField] === id);
else item = that._findGroupedItem(group.items, id, idField);
if (item) return item;
}
},
_findClosestGroupingRow: function(htmlRow, rowsCount, hiddenGroupingRows) {
const that = this;
const hasGroupingRows = that.options.groupable && that.dataSource.group().length > 0;
let i = rowsCount ? rowsCount : 0;
let j = hiddenGroupingRows ? hiddenGroupingRows : 0;
if (!hasGroupingRows || !htmlRow) return {
targetRow: htmlRow,
rowsToTarget: i,
hiddenGroupingRows: j
};
const prevSibling = $(htmlRow.previousSibling);
if (prevSibling && prevSibling.hasClass(GROUPING_ROW)) {
let result = {
targetRow: prevSibling,
rowsToTarget: i,
hiddenGroupingRows: j
};
if (prevSibling.css("display") === "none") result = that._findClosestGroupingRow(prevSibling[0], i, j + 1);
return result;
} else {
const result = that._findClosestGroupingRow(prevSibling[0], i + 1, j);
if (result) return {
targetRow: result.targetRow,
rowsToTarget: result.rowsToTarget,
hiddenGroupingRows: j
};
}
},
_checkItemAlreadyLoaded: function(id, idField) {
const ranges = this.dataSource._ranges;
let item;
for (let i = 0; i < ranges.length; i++) {
item = ranges[i].data.find((item) => item[idField] === id);
if (item) return {
loadedItem: item,
page: i
};
}
},
scrollToItem: function(id, callback) {
const that = this, options = that.options, dataSource = that.dataSource, groups = dataSource.group(), pageSize = dataSource.pageSize(), idField = that._getSchemaIdField(), scrollable = options.scrollable, scrollableContainer = that.wrapper.find(".k-grid-content.k-auto-scrollable"), rowHeight = kendo._outerHeight(that.tbody.find(`tr:not(.${GROUPING_ROW})`)), isVirtual = scrollable && scrollable.virtual && (scrollable.virtual === "rows" || scrollable.virtual === true);
let rootGroupingRow = options.groupable && that.wrapper.find(`.${GROUPING_ROW}:first-child`);
let previouslyScrolledItems = {};
let targetRowIsHidden = false;
let groupingRowHeight = 0;
if (that._scrolledItems) previouslyScrolledItems = that._scrolledItems;
if (isVirtual && groups.length === 0) that.virtualScrollable._alwaysScrollTop = true;
if (!id || !idField) return;
const currentView = dataSource.view();
let item = currentView.find((item) => item[idField] == id);
if (groups.length > 0) {
item = that._findGroupedItem(currentView, id, idField);
groupingRowHeight = kendo._outerHeight(rootGroupingRow[0]);
}
if (!item && isVirtual) {
if (!that.virtualScrollable._programmaticallyScrolling || that.virtualScrollable._programmaticallyScrolling.state() === "resolved") that.virtualScrollable._programmaticallyScrolling = $.Deferred();
callback && typeof callback === "function" && callback({ success: (index) => {
let itemIndex = index;
itemIndex = typeof itemIndex !== "number" ? Number(itemIndex) : itemIndex;
if (isNaN(itemIndex)) return;
const serverPaging = dataSource.options.serverPaging;
let page = math.floor(itemIndex / pageSize);
if (serverPaging) {
const itemLoaded = that._checkItemAlreadyLoaded(id, idField);
if (itemLoaded) page = itemLoaded.page;
}
const allRows = scrollableContainer.find(TR);
const lastRowOffsetTop = allRows[allRows.length - 1].offsetTop;
const pageEndOffset = pageSize / allRows.length * lastRowOffsetTop;
const itemsToTarget = itemIndex - page * pageSize - 1;
const scrollPosition = page * pageEndOffset + itemsToTarget * rowHeight;
that._scrollingUp = that.virtualScrollable.verticalScrollbar.scrollTop() > scrollPosition;
that._scrollOffset = scrollPosition;
that.virtualScrollable._scrollTo(scrollPosition);
that.virtualScrollable.verticalScrollbar.trigger(SCROLL);
return that.virtualScrollable._programmaticallyScrolling.done(() => {
that.scrollToItem(id);
});
} });
return;
}
const uid = item && item.uid;
if (!uid) return;
let element = $(`[data-uid=${uid}]`);
let { targetRow, rowsToTarget, hiddenGroupingRows } = that._findClosestGroupingRow(element[0]);
if (!element || !targetRow) return;
else if (groups.length > 0 && element.css("display") === "none") {
element = targetRow;
targetRowIsHidden = true;
}
const hiddenGroupingRowsOffset = targetRowIsHidden ? hiddenGroupingRows * groupingRowHeight + rowHeight : 0;
let wrapperPosition = element[0].offsetTop - ((rowsToTarget + groups.length) * groupingRowHeight - hiddenGroupingRowsOffset);
let scrollPosition = wrapperPosition;
if (isVirtual) {
if (previouslyScrolledItems && previouslyScrolledItems[id]) {
const scrollerPosition = Math.floor(that.virtualScrollable.verticalScrollbar.scrollTop());
const prevScrollDown = Math.floor(previouslyScrolledItems[id].scrollingDownOffset);
const prevScrollUp = Math.floor(previouslyScrolledItems[id].scrollingUpOffset);
if (scrollerPosition === prevScrollUp || scrollerPosition === prevScrollDown) return;
that._scrollingUp = scrollerPosition > scrollPosition;
if (that._scrollingUp) scrollPosition = prevScrollUp ?? scrollPosition;
else scrollPosition = prevScrollDown ?? scrollPosition;
}
if (that._scrollOffset) if (!that._scrollingUp) scrollPosition += that._scrollOffset;
else {
if (that._scrollOffset === wrapperPosition) that._scrollOffset += rowHeight;
scrollPosition = wrapperPosition - that.virtualScrollable._scrollTop + that._scrollOffset;
}
that.virtualScrollable._scrollTo(wrapperPosition, scrollPosition);
if (!previouslyScrolledItems[id]) previouslyScrolledItems[id] = {};
if (that._scrollingUp) {
if (previouslyScrolledItems[id] && !previouslyScrolledItems[id].scrollingUpOffset) previouslyScrolledItems[id].scrollingUpOffset = scrollPosition;
} else if (previouslyScrolledItems[id] && !previouslyScrolledItems[id].scrollingDownOffset) previouslyScrolledItems[id].scrollingDownOffset = scrollPosition;
} else scrollableContainer.scrollTop(scrollPosition);
if (that.virtualScrollable) {
if (that._scrollOffset) delete that._scrollOffset;
if (that._scrollingUp) delete that._scrollingUp;
}
that._scrolledItems = previouslyScrolledItems;
},
current: function(next) {
return this._setCurrent(next, true);
},
_setCurrent: function(next, preventTrigger, preventScroll, skipFocus) {
var current = this._current;
next = $(next);
if (current && next && current.length && next.length && current.closest(".k-filter-row").length > 0 && next.closest(".k-filter-row").length === 0) this._filterFocusable().attr(TABINDEX, -1);
if (next.length) {
if (!current || current[0] !== next[0]) {
var parent = next.parent();
parent.children(DATA_CELL);
var colspan = parseInt(parent.children().first().attr("colspan"), 10);
if (this._hasVirtualColumns()) {
var virtualSiblings = parent.children(DATA_CELL_HIDDENINCLUDED).not(".k-group-cell");
this._virtualCellIndex = (colspan > 1 ? colspan : 0) + virtualSiblings.index(next);
}
this._updateCurrentAttr(current, next, skipFocus);
if (!preventScroll) this._scrollCurrent();
if (!preventTrigger) this.trigger(NAVIGATE, { element: next });
}
}
if (next && next.length) this._lastCellIndex = next.parent().children(".k-group-cell, .k-grid-stack-content," + DATA_CELL_HIDDENINCLUDED).index(next);
this._updateSelctCheckbox(current, next);
return this._current;
},
_removeCurrent: function() {
if (this._current) {
this._current.removeClass(FOCUSED);
this._current = null;
}
},
_updateSelctCheckbox: function(current, next) {
var nextCheckbox;
if (next && next.length) {
nextCheckbox = next.find(".k-select-checkbox");
if (nextCheckbox.length > 0) nextCheckbox.trigger("focus");
else if (current && current.find(".k-select-checkbox").length > 0) focusTable(this.table, true);
}
},
_stickyScrollInsets: function() {
return {
top: this._stickyGroupHeaderContainer ? Math.ceil(this._stickyGroupHeaderContainer[0].getBoundingClientRect().height) : 0,
bottom: this._stickyGroupFooterContainer ? Math.ceil(this._stickyGroupFooterContainer[0].getBoundingClientRect().height) : 0
};
},
_scrollTo: function(element, container) {
var elementToLowercase = element.tagName.toLowerCase();
var isHorizontal = elementToLowercase === "td" || elementToLowercase === "th";
var table = $(element).closest("table")[0];
var elementOffsetDir = element[isHorizontal ? "offsetWidth" : "offsetHeight"];
var containerScroll = container[isHorizontal ? "scrollLeft" : "scrollTop"];
var containerOffsetDir = container[isHorizontal ? "clientWidth" : "clientHeight"];
var elementOffset = $(element).css("position") === "relative" && isRtl && isHorizontal ? Math.abs(table.offsetLeft - element.offsetLeft) : element[isHorizontal ? "offsetLeft" : "offsetTop"];
var bottomDistance = elementOffset + elementOffsetDir;
var result = 0;
var ieCorrection = 0;
var firefoxCorrection = 0;
var stickyTopOffset = 0;
var stickyBottomOffset = 0;
if (!isHorizontal) {
const insets = this._stickyScrollInsets();
stickyTopOffset = insets.top;
stickyBottomOffset = insets.bottom;
}
if (isRtl && isHorizontal) {
if (browser.msie || browser.edge) ieCorrection = table.offsetLeft;
else if (browser.mozilla || browser.webkit && browser.version > 85) firefoxCorrection = table.offsetLeft - kendo.support.scrollbar();
}
containerScroll = Math.abs(containerScroll + ieCorrection - firefoxCorrection);
if (containerScroll + stickyTopOffset > elementOffset) result = elementOffset - stickyTopOffset;
else if (bottomDistance > containerScroll + containerOffsetDir - stickyBottomOffset) if (elementOffsetDir <= containerOffsetDir) result = bottomDistance - containerOffsetDir + stickyBottomOffset;
else result = elementOffset - stickyTopOffset;
else result = containerScroll;
result = Math.max(0, Math.abs(result + ieCorrection) + firefoxCorrection);
const scrollProp = isHorizontal ? "scrollLeft" : "scrollTop";
const previous = container[scrollProp];
container[scrollProp] = result;
if (!isHorizontal && previous !== result && (this._hasStickyGroupHeaders() || this._hasStickyGroupFooters())) {
this._updateStickyGroups();
const updated = this._stickyScrollInsets();
if (updated.top !== stickyTopOffset || updated.bottom !== stickyBottomOffset) {
if (containerScroll + updated.top > elementOffset) result = elementOffset - updated.top;
else if (bottomDistance > result + containerOffsetDir - updated.bottom) {
if (elementOffsetDir <= containerOffsetDir) result = bottomDistance - containerOffsetDir + updated.bottom;
}
container[scrollProp] = Math.max(0, result);
}
}
},
_navigatable: function() {
var that = this;
if (!that.options.navigatable) return;
const stacked = that._isStackedMode();
var dataTables = that.table.add(that.lockedTable);
var headerTables = !stacked && that.thead.parent().add($(">table", that.lockedHeader));
var tables = dataTables;
if (that.options.scrollable) tables = tables.add(headerTables);
this._navigatableTables = tables;
if (headerTables) this._headertables = headerTables;
tables.off("mousedown.kendoGrid focus.kendoGrid focusout.kendoGrid keydown.kendoGrid");
if (headerTables) headerTables.find("a.k-link").attr("tabIndex", -1);
dataTables.on("keydown.kendoGrid", ".k-detail-cell", function(e) {
if (e.target !== e.currentTarget) e.stopImmediatePropagation();
});
tables.on(kendo.support.touch ? "touchstart.kendoGrid" : "mousedown.kendoGrid", "tr:not(.k-footer-template):visible>:not(.k-group-cell):not(.k-detail-cell):not(.k-hierarchy-cell):visible", tableClick.bind(that)).on("focus.kendoGrid", that._tableFocus.bind(that)).on("focusout.kendoGrid", that._tableBlur.bind(that)).on("keydown.kendoGrid", that, that._tableKeyDown.bind(that));
that.wrapper.on(kendo.support.touch ? "touchstart.kendoGrid" : "mousedown.kendoGrid", ".k-grid-pinned-container tr:not(.k-footer-template):visible>:not(.k-group-cell):not(.k-detail-cell):not(.k-hierarchy-cell):visible", tableClick.bind(that));
that.wrapper.on("keydown.kendoGrid", ".k-grid-pinned-container", that._tableKeyDown.bind(that));
that._filterFocusable().on("focus", that._filterFocus.bind(that));
},
_filterFocus: function(e) {
var header = e.target.closest("th");
this._filterFocusable().attr(TABINDEX, 0);
this._setCurrent(header);
$(header).removeClass(FOCUSED);
},
_tableFocus: function() {
var current = this.current();
var table = this.lockedTable ? this.lockedTable : this.table;
if (!this._stickyGroupFocusing) {
this._clearStickyGroupFocus();
if (current && current.is(":visible")) current.addClass(FOCUSED);
else if (this._virtualColScroll) this._setCurrent(table.find(NAVROW).first().children(NAVCELL).first(), true, true);
else this._setCurrent(table.find(NAVROW).first().children(NAVCELL).first());
}
this.table.attr(TABINDEX, 0);
},
_tableBlur: function() {
var current = this.current();
if (current) current.removeClass(FOCUSED);
this._clearStickyGroupFocus();
},
_findCellIndex: function(columns, startIndex, reversed) {
var cellIndex;
var i;
if (reversed) for (i = startIndex; i >= 0; i--) {
cellIndex = i;
if (!columns[i].hidden) break;
}
else for (i = startIndex; i < columns.length; i++) {
cellIndex = i;
if (!columns[i].hidden) break;
}
return cellIndex;
},
_scrollToColumn: function(key, e) {
if (this._virtualCellIndex === undefined) return false;
var that = this;
var cellIndex = that._virtualCellIndex;
var leafsCols = leafColumns(nonLockedColumns(that.columns));
var scrollWidth = 0;
if (key == (isRtl ? keys.LEFT : keys.RIGHT) && cellIndex !== leafsCols.length - 1) cellIndex = that._findCellIndex(leafsCols, cellIndex + 1);
else if (key == (isRtl ? keys.RIGHT : keys.LEFT) && cellIndex) cellIndex = that._findCellIndex(leafsCols, cellIndex - 1, true);
else if (key == keys.HOME) cellIndex = that._findCellIndex(leafsCols, 0);
else if (key == keys.END) cellIndex = that._findCellIndex(leafsCols, leafsCols.length - 1, true);
for (var i = 0; i < cellIndex; i++) scrollWidth += leafsCols[i].width;
that._virtualCellIndex = cellIndex;
if (e) {
e.preventDefault();
e.stopPropagation();
}
let scrollable = that.content;
if (that._hasVirtualRows() && that._hasVirtualColumns()) scrollable = that.virtualScrollable.wrapper;
kendo.scrollLeft(scrollable, scrollWidth);
return true;
},
_tableKeyDown: function(e) {
if (this._handleStickyGroupKeyDown(e)) return;
let current = this.current(), currentTable = current && current.closest(".k-grid-table")[0], virtualScroll = this.virtualScroll || {}, requestInProgress = this.virtualScrollable && this.virtualScrollable.fetching(), target = $(e.target), canHandle = !e.isDefaultPrevented() && (!target.is(":button,a,:input:not(.k-select-checkbox),a>.k-icon,a>.k-svg-icon") || this._isFocusableGridElement(current) && !target.closest(".k-grid-stack-edit-cell").length);
if (e.altKey && e.keyCode == keys.DOWN) {
this.current().find(".k-grid-filter-menu, .k-grid-column-menu").click();
e.stopImmediatePropagation();
return;
}
if (requestInProgress) {
e.preventDefault();
return;
}
if (virtualScroll.columns && (!current || !document.body.contains(current[0])) && this._scrollToColumn(e.keyCode, e)) return;
if (!current) current = $(this.lockedTable).add(this.options.scrollable ? this.table : this.tbody).find(NAVROW).first().children(NAVCELL).first();
if (!current.length) return;
var handled = false;
if (!e.isDefaultPrevented() && e.keyCode === keys.F10) handled = this._focusToolbar();
if (canHandle && e.keyCode == keys.UP) handled = this._moveUp(current, e.shiftKey, e.ctrlKey);
if (canHandle && e.keyCode == keys.DOWN) handled = this._moveDown(current, e.shiftKey, e.ctrlKey);
if (canHandle && e.keyCode == (isRtl ? keys.LEFT : keys.RIGHT)) handled = this._moveRight(current, e.altKey, e.shiftKey, e.ctrlKey, currentTable);
if (canHandle && e.keyCode == (isRtl ? keys.RIGHT : keys.LEFT)) handled = this._moveLeft(current, e.altKey, e.shiftKey, e.ctrlKey, currentTable);
if (canHandle && e.keyCode == keys.PAGEDOWN) handled = this._handlePageDown();
if (canHandle && e.keyCode == keys.PAGEUP) handled = this._handlePageUp();
if (canHandle && e.keyCode == keys.HOME) handled = this._handleHome(current, e.ctrlKey);
if (canHandle && e.keyCode == keys.END) handled = this._handleEnd(current, e.ctrlKey);
if (canHandle && e.keyCode == keys.SPACEBAR) handled = this._handleSpaceKey(current, e.ctrlKey);
if (e.keyCode == keys.ENTER || e.keyCode == keys.F2) handled = this._handleEnterKey(current, currentTable, target, e.keyCode == keys.F2);
if (e.keyCode == keys.ESC) handled = this._handleEscKey(current);
if (e.keyCode == keys.TAB) handled = this._handleTabKey(current, currentTable, e.shiftKey, target);
if (e.keyCode === keys.DELETE || e.keyCode === keys.BACKSPACE) handled = this._handleDeletion(e);
if (handled) {
e.preventDefault();
e.stopPropagation();
}
},
_focusToolbar: function() {
var focusable = this.wrapper.find(".k-grid-toolbar [tabindex=0]");
if (focusable.length > 0) {
focusable.first().addClass(".k-focus").trigger("focus");
return true;
}
return false;
},
_focusFocusable: function(current, next, preventTrigger, preventScroll, eventData) {
this._ensureStickyNavTargetVisible(next);
let focusable = this._isFocusableGridElement(next) && next.find(FOCUSABLE);
if (!focusable || !focusable.length) {
if (next.is(FOCUSABLE)) focusable = next;
}
if (this._containerHasActiveElement(current) && current.find(FOCUSABLE).length !== 1 || !next.length) return;
focusTable(this.table, true);
this._setCurrent(next, preventTrigger, preventScroll);
if (focusable.length === 1 && !focusable.is("table")) {
focusable.trigger("focus");
eventData?.preventDefault();
}
},
_containerHasActiveElement: function(container) {
return container.find(activeElement()).length;
},
_isFocusableGridElement: function(element) {
if (!element) return false;
return element.is(FOCUSABLE_GRID_ELEMENT_SELECTORS) || element.has(FOCUSABLE_GRID_ELEMENT_SELECTORS).length;
},
_moveLeft: function(current, altKey, shiftKey, ctrlKey, currentTable) {
var next, index;
var row = current.parent();
var container = row.parent();
if (altKey) if (row.hasClass(GROUPING_ROW)) this.collapseGroup(row);
else this.collapseRow(row);
else if (ctrlKey && current.is(".k-header") && this.options.reorderable) this._moveColumn(current, true);
else {
index = container.find(NAVROW).index(row);
next = this._prevHorizontalCell(container, current, index);
if (!next[0] && !this._containerHasActiveElement(current)) if (shiftKey) if (this.lockedTable) {
next = this._relatedRow(row);
if ($.contains(this.lockedTable[0], row[0])) next = next.prevAll(ITEMROW).first();
next = next.children(DATA_CELL).last();
} else next = this._tabNext(current, currentTable, true);
else {
container = this._horizontalContainer(container);
next = this._prevHorizontalCell(container, current, index);
if (next[0] !== current[0]) focusTable(this.table, true);
}
this._focusFocusable(current, next);
}
return true;
},
_moveRight: function(current, altKey, shiftKey, ctrlKey, currentTable) {
var next, index;
var row = current.parent();
var container = row.parent();
if (altKey) if (row.hasClass(GROUPING_ROW)) this.expandGroup(row);
else this.expandRow(row);
else if (ctrlKey && current.is(".k-header") && this.options.reorderable) this._moveColumn(current, false);
else {
index = container.find(NAVROW).index(row);
next = this._nextHorizontalCell(container, current, index);
if ((!next[0] || next[0] === current[0]) && !this._containerHasActiveElement(current)) if (shiftKey) if (this.lockedTable) {
next = this._relatedRow(row);
if ($.contains(this.table[0], row[0])) next = next.nextAll(ITEMROW).first();
next = next.children(DATA_CELL).first();
} else next = this._tabNext(current, currentTable, false);
else {
container = this._horizontalContainer(container, true);
next = this._nextHorizontalCell(container, current, index);
if (next[0] !== current[0]) focusTable(this.table, true);
}
this._focusFocusable(current, next);
}
return true;
},
_moveUp: function(current, shiftKey, ctrlKey) {
var container = current.parent().parent();
var next, cellIndex, index, oldIndex;
if (this._isPinnedContainer(current)) {
const pos = this._pinnedPosition(current);
const ci = Math.max(current.parent().children(DATA_CELL_HIDDENINCLUDED).index(current), this._lastCellIndex || 0);
next = this._pinnedVerticalCell(current, false);
if (!next.length) {
if (pos === "top") {
const theadContainer = this.thead;
if (theadContainer && theadContainer.length) {
if (theadContainer.children(NAVROW).last().length) {
const groupOffset = current.parent().children(".k-group-cell").length;
next = leafDataCells(theadContainer).eq(ci - groupOffset);
}
}
} else if (pos === "bottom") {
const bodyRows = this.tbody.children(NAVROW);
if (bodyRows.length) {
const cells = bodyRows.last().children(DATA_CELL_HIDDENINCLUDED);
next = cells.length > ci ? cells.eq(ci) : cells.last();
}
}
}
if (next && next.length) {
const tmp = this._lastCellIndex || 0;
focusTable(this.table, true);
this._setCurrent(this._findVisibleCell(next));
this._lastCellIndex = tmp;
}
return true;
}
if (shiftKey) {
next = current.parent();
next = next.prevAll(ITEMROW).first();
next = current.parent().is(ITEMROW) ? next.children().eq(current.index()) : next.children(DATA_CELL).last();
} else if (ctrlKey && current.parent().is(ITEMROW) && this._hasReorderableRows()) {
cellIndex = current.index();
next = current.parent();
next = next.prevAll(ITEMROW).first();
index = this.tbody.children(ITEMROW).index(next);
oldIndex = this.tbody.children(ITEMROW).index(current.parent());
if (index >= 0 && !this.trigger(ROWREORDER, {
oldIndex,
newIndex: index,
row: current.parent()
})) {
this.reorderRows(current.parent(), index);
next = this.tbody.children(ITEMROW).eq(index).children().eq(cellIndex);
}
} else {
next = this._prevVerticalCell(container, current);
if (!next[0]) {
const isInTbody = container[0] === this.tbody[0];
if (this._isPinnable() && isInTbody && this._pinnedTopRows && this._pinnedTopRows.length) {
const ci = Math.max(current.parent().children(DATA_CELL_HIDDENINCLUDED).index(current), this._lastCellIndex || 0);
next = this._pinnedBoundaryCellByPosition("top", false, ci);
}
if (!next || !next[0]) {
this._lastCellIndex = 0;
container = this._verticalContainer(container, true);
next = this._prevVerticalCell(container, current);
if (next.is(":hidden")) next = next.nextAll().not(":hidden").first();
if (next[0]) focusTable(this.table, true);
}
}
}
var tmp = this._lastCellIndex || 0;
if (!this._isStackedMode()) this._focusFocusable(current, next);
else {
focusTable(this.table, true);
this._setCurrent(next);
}
this._lastCellIndex = tmp;
return true;
},
_moveDown: function(current, shiftKey, ctrlKey) {
var container = current.parent().parent();
var next, cellIndex, index, oldIndex;
if (this._isPinnedContainer(current)) {
const pos = this._pinnedPosition(current);
const ci = Math.max(current.parent().children(DATA_CELL_HIDDENINCLUDED).index(current), this._lastCellIndex || 0);
next = this._pinnedVerticalCell(current, true);
if (!next.length) {
if (pos === "top") {
const bodyRows = this.tbody.children(NAVROW);
if (bodyRows.length) {
const cells = bodyRows.first().children(DATA_CELL_HIDDENINCLUDED);
next = cells.length > ci ? cells.eq(ci) : cells.last();
}
}
}
if (next && next.length) {
const tmp = this._lastCellIndex || 0;
focusTable(this.table, true);
this._setCurrent(this._findVisibleCell(next));
this._lastCellIndex = tmp;
}
return true;
}
if (shiftKey) {
next = current.parent();
next = next.nextAll(ITEMROW).first();
next = current.parent().is(ITEMROW) ? next.children().eq(current.index()) : next.children(DATA_CELL).first();
} else if (ctrlKey && current.parent().is(ITEMROW) && this._hasReorderableRows()) {
cellIndex = current.index();
next = current.parent();
next = next.nextAll(ITEMROW).first();
index = this.tbody.children(ITEMROW).index(next);
oldIndex = this.tbody.children(ITEMROW).index(current.parent());
if (index >= 0 && !this.trigger(ROWREORDER, {
oldIndex,
newIndex: index,
row: current.parent()
})) {
this.reorderRows(current.parent(), index + 1);
next = this.tbody.children(ITEMROW).eq(index).children().eq(cellIndex);
}
} else {
next = this._nextVerticalCell(container, current);
if (!next[0]) {
const isInThead = container.is("thead");
const isInTbody = container[0] === this.tbody[0];
if (this._isPinnable() && isInThead && this._pinnedTopRows && this._pinnedTopRows.length) {
const ci = Math.max(current.parent().children(DATA_CELL_HIDDENINCLUDED).index(current), this._lastCellIndex || 0);
next = this._pinnedBoundaryCellByPosition("top", true, ci);
} else if (this._isPinnable() && isInTbody) {
const ci = Math.max(current.parent().children(DATA_CELL_HIDDENINCLUDED).index(current), this._lastCellIndex || 0);
next = this._pinnedBoundaryCellByPosition("bottom", true, ci);
}
if (!next || !next[0]) {
this._lastCellIndex = 0;
container = this._verticalContainer(container);
next = this._nextVerticalCell(container, current);
if (next[0]) focusTable(this.table, true);
}
}
}
var tmp = this._lastCellIndex || 0;
if (!this._isStackedMode()) this._focusFocusable(current, this._findVisibleCell(next));
else {
focusTable(this.table, true);
this._setCurrent(this._findVisibleCell(next));
}
this._lastCellIndex = tmp;
return true;
},
_moveColumn: function(current, isLeft) {
var elements = this.wrapper.data().kendoReorderable.element.find(this._draggableInstance.options.filter + ":visible");
var columns = visibleColumns(flatColumnsInDomOrder(this.columns));
var oldIndex = elements.index($(current));
var offset = isLeft ? -1 : 1;
var column = columns[oldIndex];
var newIndex = targetParentContainerIndex(columns, this.columns, oldIndex, oldIndex + offset);
if (newIndex >= 0) {
this.reorderColumn(newIndex, column, isLeft);
this.trigger(COLUMNREORDER, {
newIndex,
oldIndex,
column
});
}
},
_handleHome: function(current, ctrl) {
const that = this;
let row = current.parent();
const rowContainer = row.parent();
const isInLockedTable = that.lockedTable && that.lockedTable.children("tbody")[0] === rowContainer[0];
const isInBody = rowContainer[0] === that.tbody[0];
let prev;
const hasVirtualColumns = that._hasVirtualColumns();
const hasVirtualRows = that._hasVirtualRows();
const isScrolledToStart = (hasVirtualRows ? that.virtualScrollable.wrapper : that.content).scrollLeft() === 0;
if (hasVirtualColumns && hasVirtualRows && ctrl) {
that._focusVirtualCell(true, hasVirtualColumns && !isScrolledToStart);
return true;
}
if (hasVirtualColumns) {
if (isScrolledToStart) that._setCurrent(that.table.find(ITEMROW).first().children(NAVCELL).first());
else that._forceScrollVirtualColumn(keys.HOME, ctrl);
return true;
}
if (hasVirtualRows && ctrl) {
that._focusVirtualCell(true);
return true;
}
if (ctrl) if (that._isPinnable() && that._pinnedTopRows && that._pinnedTopRows.length) prev = that._pinnedBoundaryCellByPosition("top", true, 0);
else if (that.lockedTable) prev = that.lockedTable.find(ITEMROW).first().children(NAVCELL).first();
else prev = that.table.find(ITEMROW).first().children(NAVCELL).first();
else if (isInBody || isInLockedTable) {
if (isInBody && this.lockedTable) row = that._relatedRow(row);
prev = row.children(DATA_CELL).first();
} else if (that._isPinnedContainer(current)) prev = row.children(DATA_CELL).first();
if (prev && prev.length) {
that._setCurrent(prev);
return true;
}
},
_setCurrentVirtualCell: function(focusFirst) {
const that = this;
if (focusFirst) this._setCurrent(that.table.find(ITEMROW).first().children(NAVCELL).first());
else this._setCurrent(that.table.find(ITEMROW).last().children(NAVCELL).last());
},
_forceScrollVirtualColumn: function(key, condition, setboth) {
const that = this;
if (setboth) {
that._shouldFocusInLastRow = !condition;
that._shouldFocusInFirstRow = condition;
} else if (key === keys.HOME) that._shouldFocusInFirstRow = condition;
else that._shouldFocusInLastRow = condition;
that.one(DATABOUND, function() {
if (setboth) that.one(DATABOUND, function() {
that._setCurrentVirtualCell(condition);
});
if (that._shouldFocusInLastRow) {
that.content.scrollTop(that.content[0].scrollHeight);
delete that._shouldFocusInLastRow;
}
if (that._shouldFocusInFirstRow) {
that.content.scrollTop(0);
delete that._shouldFocusInFirstRow;
}
});
that._scrollToColumn(key);
},
_focusVirtualCell: function(first, scrollColumn) {
const that = this;
const scrollbar = this.virtualScrollable.verticalScrollbar;
const isScrolledToBottom = Math.ceil(scrollbar.scrollTop() + scrollbar.innerHeight()) >= scrollbar[0].scrollHeight;
const isScrollToTop = this.virtualScrollable.verticalScrollbar.scrollTop() === 0;
const scrollbarCondition = first ? isScrollToTop : isScrolledToBottom;
const key = first ? keys.HOME : keys.END;
if (scrollbarCondition) if (scrollColumn) that._forceScrollVirtualColumn(key, first, true);
else that._setCurrentVirtualCell(first);
else {
if (that.dataSource.group().length === 0) that.virtualScrollable._alwaysScrollTop = true;
const scrollPosition = first ? 0 : scrollbar[0].scrollHeight;
that.one(DATABOUND, function() {
if (scrollColumn) that._forceScrollVirtualColumn(key, first, true);
else {
that._setCurrentVirtualCell(first);
if (that._shouldFocusInLastRow) delete that._shouldFocusInLastRow;
if (that._shouldFocusInFirstRow) delete that._shouldFocusInFirstRow;
}
});
scrollbar.scrollTop(scrollPosition);
scrollbar.trigger(SCROLL);
}
},
_handleEnd: function(current, ctrl) {
const that = this;
let row = current.parent();
const rowContainer = row.parent();
const isInLockedTable = that.lockedTable && that.lockedTable.children("tbody")[0] === rowContainer[0];
const isInBody = rowContainer[0] === that.tbody[0];
let next;
const hasVirtualColumns = that._hasVirtualColumns();
const hasVirtualRows = that._hasVirtualRows();
const scrollable = hasVirtualRows ? that.virtualScrollable.wrapper : that.content;
const isScrolledToEnd = scrollable.scrollLeft() + scrollable.innerWidth() >= scrollable[0].scrollWidth;
if (hasVirtualColumns && hasVirtualRows && ctrl) {
that._focusVirtualCell(false, hasVirtualColumns && !isScrolledToEnd);
return true;
}
if (hasVirtualColumns) {
if (isScrolledToEnd) that._setCurrent(that.table.find(ITEMROW).last().children(NAVCELL).last());
else that._forceScrollVirtualColumn(keys.END, ctrl);
return true;
}
if (hasVirtualRows && ctrl) {
that._focusVirtualCell(false);
return true;
}
if (ctrl) if (that._isPinnable() && that._pinnedBottomRows && that._pinnedBottomRows.length) next = that._pinnedBottom.tbody.children(NAVROW).last().children(NAVCELL).last();
else next = that.table.find(ITEMROW).last().children(NAVCELL).last();
else if (isInBody || isInLockedTable) {
if (!isInBody && this.lockedTable) row = that._relatedRow(row);
next = row.children(DATA_CELL).last();
} else if (that._isPinnedContainer(current)) next = row.children(DATA_CELL).last();
if (next && next.length) {
that._setCurrent(next);
return true;
}
},
_handlePageDown: function() {
if (!this.options.pageable) return false;
this.dataSource.page(this.dataSource.page() + 1);
return true;
},
_handlePageUp: function() {
if (!this.options.pageable) return false;
this.dataSource.page(this.dataSource.page() - 1);
return true;
},
_handleTabKey: function(current, currentTable, shiftKey, target) {
const isInCell = this.options.editable && this._editMode() == "incell";
let cell = $(activeElement()).closest(".k-grid-stack-edit-cell,.k-edit-cell");
let filterFocusable;
const stacked = this._isStackedMode();
const isTargetFocusable = target.is(FOCUSABLE);
const isTargetNotTable = !target.is("table");
const focusStackedCell = stacked && target.is(".k-grid-stack-cell");
const stackedParent = !focusStackedCell && target.closest(".k-grid-stack-cell");
const isCurrentFocusableGridElement = this._isFocusableGridElement(current);
const isNotInEditMode = !isInEdit(current);
const initialTarget = target;
let hasMultipleFocusableElements;
if (stacked) {
if (focusStackedCell) hasMultipleFocusableElements = target.parent().find(".k-grid-stack-cell").length > 1;
else if (stackedParent && stackedParent.length) hasMultipleFocusableElements = stackedParent.find(FOCUSABLE).length > 1;
} else hasMultipleFocusableElements = current.find(FOCUSABLE).length > 1;
if (!cell[0] && isTargetFocusable && isTargetNotTable && hasMultipleFocusableElements && isCurrentFocusableGridElement && isNotInEditMode) {
if (!stacked && (target.is(":last-child") && !shiftKey || target.is(":first-child") && shiftKey)) {
focusTable(this.table, true);
return true;
}
if (shiftKey) target = target.prev(FOCUSABLE);
else target = target.next(FOCUSABLE);
if (focusStackedCell && !target.length) {
const focusableSiblings = initialTarget.parent().find(".k-grid-stack-cell");
if (shiftKey && initialTarget.is(":first-child")) target = focusableSiblings.last();
if (!shiftKey && initialTarget.is(":last-child")) target = focusableSiblings.first();
} else if (!target.length && !focusStackedCell) {
const closestStackedCell = initialTarget.closest(".k-grid-stack-cell");
if (shiftKey && initialTarget.is(":first-child")) target = closestStackedCell;
if (!shiftKey && initialTarget.is(":last-child")) target = closestStackedCell.find(FOCUSABLE).first();
}
if (stacked && target.is(".k-grid-stack-cell")) this._currentStackedCell(target, true);
else target.trigger("focus");
return true;
}
if (this.options.editable && this._editMode() === "inline" && this._editContainer && this.lockedTable) {
const currentEditCell = $(activeElement()).closest("td,th");
const currentRow = currentEditCell.closest(TR);
if (currentEditCell.length && this._editContainer.filter(currentRow).length) {
const adjacentRow = this._relatedRow(currentRow);
const editCells = ($.contains(this.lockedTable[0], currentRow[0]) ? currentRow.add(adjacentRow) : adjacentRow.add(currentRow)).children(":not(.k-group-cell,.k-hierarchy-cell,.k-drag-cell)");
const adjacentCellIndex = editCells.index(currentEditCell) + (shiftKey ? -1 : 1);
if (adjacentCellIndex < 0 || adjacentCellIndex >= editCells.length) return false;
const adjacentCell = editCells.eq(adjacentCellIndex);
if (adjacentCell.length && adjacentCell.closest("table")[0] !== currentEditCell.closest("table")[0]) {
const focusable = adjacentCell.find(FOCUSABLE).filter(":visible").not("button,[tabindex='-1']");
this._setCurrent(adjacentCell);
focusTable(this.table, true);
if (focusable.length) focusable.eq(shiftKey ? focusable.length - 1 : 0).trigger("focus");
else adjacentCell.trigger("focus");
return true;
}
}
}
if (stacked && !focusStackedCell && !cell[0] || !isInCell || current.is("th") || (this.options.scrollable ? this._headertables && this._headertables.filter(currentTable).length : this.thead && this.thead.filter(target).length)) {
if (current.parent().hasClass("k-filter-row")) {
filterFocusable = this._filterFocusable();
if (!shiftKey && filterFocusable[filterFocusable.length - 1] === document.activeElement) {
filterFocusable.first().trigger("focus");
return true;
} else if (shiftKey && filterFocusable[0] === document.activeElement) {
filterFocusable.last().trigger("focus");
return true;
}
}
return false;
}
if (cell[0] && cell[0] !== current[0]) current = cell;
cell = this._tabNext(current, currentTable, shiftKey);
if (cell[0] === current[0]) return false;
if (cell.length && this._isEditableEnabled) {
if (this._isPinnedContainer(cell)) {
const uid = cell.closest("tr").data("uid");
const ci = cell.parent().children("td").index(cell);
if (this.editable) {
var active = $(activeElement());
if (this._editContainer && $.contains(this._editContainer[0], active[0])) active.trigger("blur");
if (this.editable && this.editable.end()) this.closeCell();
}
const pinnedRow = this.wrapper.find(".k-grid-pinned-container tr[data-uid='" + uid + "']");
if (pinnedRow.length) cell = pinnedRow.children("td").eq(ci);
this._setCurrent(cell);
focusTable(this.table, true);
this.editCell(cell);
return true;
}
this._handleEditing(current, cell, cell.closest("table"));
return true;
}
return false;
},
_handleDeletion: function(e) {
const that = this;
const current = that.current();
const activeElementInstance = $(activeElement());
const stackedCondition = !that._isStackedMode() ? !activeElementInstance.is("table") : !that._currentStackedCell();
if (!(that._isEditableEnabled !== undefined ? that._isEditableEnabled && that.options.editable : that.options.editable) || isInEdit(current) || stackedCondition || !current.closest("tbody").length || !current.closest(".k-master-row").length) return false;
that._removeCommandClick({
currentTarget: current,
preventDefault: e.preventDefault,
stopPropagation: e.stopPropagation
});
return true;
},
_handleEscKey: function(current) {
const active = activeElement();
const isInCell = this._editMode() == "incell";
const stacked = this._isStackedMode();
const activeElementInstance = $(active);
const stackedParent = !activeElementInstance.is(".k-grid-stack-cell") ? activeElementInstance.closest(".k-grid-stack-cell") : $();
const cell = stacked ? activeElementInstance : current;
const targetIsInsideStackedCell = stackedParent && stackedParent.length > 0;
const isStackedCell = stacked && cell.is(".k-grid-stack-cell");
if (!isInEdit(stackedParent.length ? stackedParent : cell)) {
if (isStackedCell || !targetIsInsideStackedCell && current.has(active).length && !(this._isFocusableGridElement(current) && current.find(FOCUSABLE).length === 1)) {
focusTable(this.table, true);
delete this._activeStackedCell;
return true;
}
if (targetIsInsideStackedCell) {
stackedParent.trigger("focus");
return true;
}
if (current.parent().hasClass("k-filter-row")) {
this._filterFocusable().attr(TABINDEX, -1);
focusTable(this.table, true);
return true;
}
return false;
}
if (isInCell) {
this.closeCell(true);
if (stacked && targetIsInsideStackedCell) {
addElementsToTab(stackedParent.parent().children(".k-grid-stack-cell"));
this._currentStackedCell(stackedParent, true);
}
} else {
var currentIndex = $(current).closest(TR).index();
if (active) active.blur();
this.cancelRow(true);
if (currentIndex >= 0) {
const lastActiveStackedCell = this._currentStackedCell();
if (stacked && lastActiveStackedCell) {
const cell = this.tbody.find(TR).eq(currentIndex).find(".k-grid-stack-cell").eq(lastActiveStackedCell.index);
this._setCurrentStackedCell(cell);
} else {
const target = this.items().eq(currentIndex).children(NAVCELL).first();
this._setCurrent(target);
}
}
}
if (!stacked) focusTable(this.table, true);
return !stacked;
},
_toggleCurrent: function(current, editable, hasDetails) {
const that = this;
const row = current.parent();
if (current.is(".k-command-cell")) return false;
if (row.is(".k-filter-row")) return false;
const pinCell = current.find(".k-pin-cell");
if (pinCell.length) {
const isPinned = that._isPinnedContainer(current);
const pinnedPosition = isPinned ? that._pinnedPosition(current) : null;
const pinnedRowIndex = isPinned ? current.parent().index() : -1;
if (that._pinMenu) {
const uid = row.data("uid");
const cellIndex = current.index();
that._pinMenu.one("close", function() {
setTimeout(function() {
that._restorePinFocus(isPinned, pinnedPosition, pinnedRowIndex, uid, cellIndex);
});
});
that._pinMenu.open(pinCell[0], undefined, true);
} else {
const uid = row.data("uid");
const cellIndex = current.index();
pinCell.trigger("click");
that._restorePinFocus(isPinned, pinnedPosition, pinnedRowIndex, uid, cellIndex);
}
return true;
}
if (row.is(".k-grouping-row")) {
row.find(".k-icon,.k-svg-icon").first().click();
return true;
}
if (!editable && hasDetails) {
const selector = that._isStackedMode() ? `[ref="expand-detail-button"], [ref="collapse-detail-button"]` : ".k-icon,.k-svg-icon";
row.find(selector).first().click();
return true;
}
return false;
},
_restorePinFocus: function(isPinned, position, rowIndex, uid, cellIndex) {
const that = this;
let cell;
if (!isPinned) {
const newRow = that.tbody.find("tr[data-uid='" + uid + "']");
cell = newRow.length ? newRow.children("td").eq(cellIndex) : that._current;
} else if (position === "top") {
const container = that._pinnedTop;
const rows = container && container.tbody ? container.tbody.children("tr") : $();
if (rows.length > 0) {
let targetIndex = Math.min(rowIndex, rows.length - 1);
if (rowIndex > 0) targetIndex = rowIndex - 1;
cell = rows.eq(targetIndex).children("td").first();
} else cell = that.tbody.children(ITEMROW).first().children("td").first();
} else {
const container = that._pinnedBottom;
const rows = container && container.tbody ? container.tbody.children("tr") : $();
if (rows.length > 0) {
let targetIndex = Math.min(rowIndex, rows.length - 1);
cell = rows.eq(targetIndex).children("td").first();
} else cell = that.tbody.children(ITEMROW).last().children("td").first();
}
if (cell && cell.length) {
that.table.trigger("focus");
that._setCurrent(cell);
}
},
_handleSpaceKey: function(current, ctrlKey) {
var that = this;
if (!ctrlKey || !that.groupable || !current.hasClass(HEADER_CLASS)) return;
var descriptors = that.groupable.descriptors();
var field = current.attr(kendo.attr("field"));
var aggregates = that.groupable.aggregates();
if (that.groupable._canDrag(current)) descriptors.push({
field,
dir: "asc",
aggregates: aggregates || []
});
else descriptors = $.grep(descriptors, function(item) {
return item.field !== field;
});
if (that.trigger("group", { groups: descriptors })) return;
that.dataSource.group(descriptors);
return true;
},
_hasStackedModeDetailsButton: function(cell) {
return cell.find(`[ref="expand-detail-button"], [ref="collapse-detail-button"]`).length > 0;
},
_currentStackedCell: function(current, triggerFocus) {
const that = this;
if (!current || !current.length) return that._activeStackedCell;
that._activeStackedCell = {
cell: current,
index: current.index()
};
if (triggerFocus && current.length) current.trigger("focus");
},
_handleEnterKey: function(current, currentTable, target, isF2) {
const that = this;
var editable = this.options.editable && this.options.editable.update !== false;
var container = target.closest("td");
var hasDetails = this._hasDetails();
var link, filterFocusable;
const stacked = that._isStackedMode();
const skipToEditing = stacked && isF2 && that._editMode() !== "incell";
const editClass = stacked ? "k-grid-stack-edit-cell" : "k-edit-cell";
const focusIsInStackedCell = stacked && (target.is(".k-grid-stack-cell") || target.parent().is(".k-grid-stack-cell") || target.closest(".k-grid-stack-cell").length > 0);
if (!target.is("table") && !$.contains(current[0], target[0])) current = container;
if (current.is("th")) {
link = current.find(".k-link");
if (current.has($(activeElement())).length > 0) return false;
else if (link.length) link.click();
else if (current.parent().hasClass("k-filter-row")) {
filterFocusable = this._filterFocusable();
filterFocusable.attr(TABINDEX, 0);
current.find(":kendoFocusable").first().trigger("focus");
} else current.find(CHECKBOXINPUT).trigger("focus");
return true;
}
if (!skipToEditing) {
if (!focusIsInStackedCell && this._toggleCurrent(current, editable, hasDetails)) return true;
if (focusIsInStackedCell && that._hasStackedModeDetailsButton(target)) {
this._toggleCurrent(current, false, true);
return true;
}
let focusableSelector = ":kendoFocusable";
if (stacked && !focusIsInStackedCell) addElementsToTab(current.find(".k-grid-stack-cell"));
var focusable = (focusIsInStackedCell ? target : current).find(focusableSelector).first();
if (focusable[0] && (focusIsInStackedCell || !current.hasClass(editClass) && current.hasClass("k-focus"))) {
if (!focusIsInStackedCell) that._currentStackedCell(focusable, true);
else focusable.trigger("focus");
return true;
}
}
if (editable && !target.is(":button,.k-button,textarea")) {
if (!container[0]) container = current;
if (stacked && target.is(".k-grid-stack-cell")) that._currentStackedCell(target);
if (focusIsInStackedCell) if (!target.is(".k-grid-stack-cell")) container = target.closest(".k-grid-stack-cell");
else container = target;
if (this._isEditableEnabled) this._handleEditing(container, false, currentTable);
return true;
}
return false;
},
_nextHorizontalCell: function(table, current, originalIndex) {
if (!current.nextAll(DATA_CELL).length) {
var rows = table.find(NAVROW);
if (rows.index(current.parent()) == -1) {
if (current.hasClass(HEADER_CLASS)) {
var headerRows = [];
mapColumnToCellRows([lockedColumns(this.columns)[0]], childColumnsCells(rows.eq(0).children(":visible").first()), headerRows, 0, 0);
if (headerRows[originalIndex]) return headerRows[originalIndex][0];
return current;
}
if (current.parent().hasClass("k-filter-row")) return rows.last().children(DATA_CELL).first();
return this._findVisibleCell(rows.eq(originalIndex).children(DATA_CELL + ",[hidden]").first());
}
}
return this._findVisibleCell(current.nextAll(DATA_CELL + ",[hidden]").eq(0));
},
_prevHorizontalCell: function(table, current, originalIndex) {
var cells = current.prevAll(DATA_CELL);
if (!cells.length) {
var rows = table.find(NAVROW);
if (rows.index(current.parent()) == -1) {
if (current.hasClass(HEADER_CLASS)) {
var headerRows = [];
var columns = lockedColumns(this.columns);
mapColumnToCellRows([columns[columns.length - 1]], childColumnsCells(rows.eq(0).children().last()), headerRows, 0, 0);
if (headerRows[originalIndex]) return headerRows[originalIndex][0];
return current;
}
if (current.parent().hasClass("k-filter-row")) return rows.last().children(DATA_CELL).last();
return rows.eq(originalIndex).children(DATA_CELL).last();
}
}
cells = current.prevAll(DATA_CELL + ",[hidden]");
let cellToFocus = this._findVisibleCell(cells.first());
if (cellToFocus.is(".k-group-cell")) return cellToFocus.next(DATA_CELL);
return cellToFocus;
},
_currentDataIndex: function(table, current) {
var index = current.attr("data-index");
if (!index) return undefined;
var lockedColumnsCount = lockedColumns(this.columns).length;
if (lockedColumnsCount && !table.closest(DIV).hasClass("k-grid-content-locked")[0]) return index - lockedColumnsCount;
return index;
},
_findVisibleCell: function($cell) {
var col = $cell.index();
var row = $cell.closest("tr").index();
var $newFocus;
if ($cell.is("[hidden]")) {
$newFocus = $cell.prevAll(":not([hidden])").first();
var hiddenCount = $cell.prevUntil(":not([hidden])", "[hidden]").length;
if (!$newFocus.attr("colspan") || $newFocus.attr("colspan") > 1 && $newFocus.attr("colspan") <= hiddenCount + 1) {
$newFocus = $cell.prevAll("[hidden]").last();
if ($newFocus.length === 0) return $cell.closest("tr").prevAll().find(`td:nth-of-type(${col + 1}):visible`).last();
while (!$newFocus.attr("rowspan") && !($newFocus.attr("rowspan") > 1 && $newFocus.attr("rowspan") != row - $newFocus.closest("tr").index()) && Math.abs($newFocus.index() - col) != $newFocus.attr("colspan")) {
$newFocus = $newFocus.closest("tr").prevAll().find("td, th").eq(col).first();
if ($newFocus.length === 0) {
$newFocus = $cell;
break;
}
}
}
} else $newFocus = $cell;
return $newFocus;
},
_prevVerticalCell: function(container, current) {
var cells;
var row = current.parent();
var rows = container.children(NAVROW);
var rowIndex = rows.index(row);
var index = this._currentDataIndex(container, current);
if (index || current.hasClass(HEADER_CLASS)) {
cells = parentColumnsCells(current);
return cells.eq(cells.length - 2);
}
index = Math.max(row.children(DATA_CELL_HIDDENINCLUDED).index(current), this._lastCellIndex || 0);
if (row.hasClass("k-filter-row")) {
let offset = rows.last().children(".k-group-cell").length;
return leafDataCells(container).filter(isCellVisible).eq(Math.max(0, index - offset));
}
if (rowIndex == -1) {
if (this._hasVirtualColumns()) index = this._virtualCellIndex;
row = container.find("tr.k-filter-row:visible");
if (!row[0]) {
if ((this._hasDetails() || current.parent().find(".k-hierarchy-cell").length) && index) index--;
let offset = 0;
if (current.parent().is(".k-table-group-row")) offset = rows.last().children(".k-group-cell").length;
return leafDataCells(container).eq(Math.max(0, index - offset));
} else if (this._hasDetails()) index--;
} else row = rowIndex === 0 ? $() : rows.eq(rowIndex - 1);
cells = row.children(DATA_CELL_HIDDENINCLUDED);
if (cells.length > index) {
let nextCell = cells.eq(index);
if (nextCell.is(".k-group-cell")) nextCell = nextCell.nextAll("td").not(".k-group-cell").not(":hidden").first();
return this._findVisibleCell(nextCell);
}
return cells.eq(0);
},
_nextVerticalCell: function(container, current) {
var cells;
var originalRow;
var row = originalRow = current.closest(TR);
var rows = container.children(NAVROW);
var rowIndex = rows.index(row);
var index = this._currentDataIndex(container, current);
var virtualScroll = this.virtualScroll || {};
var colspan;
if (rowIndex != -1 && index === undefined && current.hasClass(HEADER_CLASS)) return childColumnsCells(current).eq(1);
index = index ? parseInt(index, 10) : row.children(DATA_CELL_HIDDENINCLUDED).index(current);
index = Math.max(index, this._lastCellIndex || 0);
if (rowIndex == -1) {
row = rows.eq(0);
if (virtualScroll.columns) {
colspan = parseInt(row.children().first().attr("colspan"), 10);
index = this._virtualCellIndex - (colspan > 1 ? colspan : 0);
}
if (this._hasDetails() || row.find(".k-hierarchy-cell").length) index++;
if (row.hasClass("k-table-group-row")) index += originalRow.children(".k-group-cell").length;
} else row = rows.eq(rowIndex + current[0].rowSpan);
cells = row.children(".k-group-cell," + DATA_CELL_HIDDENINCLUDED);
let cellToFocus = cells.eq(0);
if (cells.length > index) cellToFocus = cells.eq(index);
if (cellToFocus.is(".k-group-cell")) cellToFocus = cellToFocus.nextAll("td").not(".k-group-cell").not(":hidden").first();
return cellToFocus;
},
_verticalContainer: function(container, up) {
var table = container.parent();
var length = this._navigatableTables.length;
var step = Math.floor(length / 2);
var index = inArray(table[0], this._navigatableTables);
if (up) step *= -1;
index += step;
if (index >= 0 || index < length) table = this._navigatableTables.eq(index);
return table.find(up ? ">thead" : ">tbody");
},
_filterFocusable: function() {
return this.wrapper.find(".k-filter-row").find(".k-dropdownlist, .k-input .k-input-inner:visible, input[type='radio']:visible, input[type='checkbox']:visible");
},
_horizontalContainer: function(container, right) {
var length = this._navigatableTables.length;
if (length <= 2) return container;
var table = container.parent();
var index = inArray(table[0], this._navigatableTables);
index += right ? 1 : -1;
if (right && (index == 2 || index == length)) return container;
if (!right && (index == 1 || index < 0)) return container;
return this._navigatableTables.eq(index).find("thead, tbody");
},
_tabNext: function(current, currentTable, back) {
var switchRow = true;
var next = back ? current.prevAll(DATA_CELL).first() : current.nextAll(":visible").first();
if (!next.length) {
next = current.parent();
if (this.lockedTable) {
switchRow = back && currentTable == this.lockedTable[0] || !back && currentTable == this.table[0];
next = this._relatedRow(next);
}
if (switchRow) {
if (this._hasVirtualColumns()) return current;
next = next[back ? "prevAll" : "nextAll"]("tr:not(.k-grouping-row):not(.k-detail-row):visible").first();
}
if (!next.length && this._isPinnable()) {
next = this._tabNextPinnedBoundary(current, back);
if (next && next.length) return next;
}
if (back) next = next.children(DATA_CELL).last();
else next = next.children(DATA_CELL).first();
}
return next;
},
_tabNextPinnedBoundary: function(current, back) {
if (this._isPinnedContainer(current)) {
const pos = this._pinnedPosition(current);
if (!back) {
if (pos === "top") {
const bodyRows = this.tbody.children(NAVROW);
if (bodyRows.length) return bodyRows.first().children(DATA_CELL).first();
}
} else if (pos === "top") {
if ((this.thead ? this.thead.children(NAVROW) : $()).length) return leafDataCells(this.thead).last();
} else if (pos === "bottom") {
const bodyRows = this.tbody.children(NAVROW);
if (bodyRows.length) return bodyRows.last().children(DATA_CELL).last();
}
} else if (current.closest("tbody")[0] === this.tbody[0]) {
if (!back && this._pinnedBottomRows && this._pinnedBottomRows.length) return this._pinnedBoundaryCellByPosition("bottom", true, 0);
else if (back && this._pinnedTopRows && this._pinnedTopRows.length) {
const p = this._pinnedTop;
if (p && p.tbody) {
const lastRow = p.tbody.children(NAVROW).last();
if (lastRow.length) return lastRow.children(DATA_CELL).last();
}
}
}
return $();
},
_handleEditing: function(current, next, table) {
var that = this, active = $(activeElement()), mode = that._editMode(), isIE = browser.msie, editContainer = that._editContainer, focusable, editable = that.options.editable && that.options.editable.update !== false, isEdited;
const stacked = that._isStackedMode();
const isStackedCell = current.is(".k-grid-stack-cell");
table = $(table);
if (mode == "incell") {
const editClass = stacked ? "k-grid-stack-edit-cell" : "k-edit-cell";
isEdited = current.hasClass(editClass);
} else isEdited = isStackedCell ? current.hasClass("k-grid-stack-edit-cell") : current.parent().hasClass("k-grid-edit-row");
if (that.editable) {
if ($.contains(editContainer[0], active[0])) {
active.trigger("blur");
if (isIE) active.trigger("blur");
}
if (!that.editable && !isStackedCell) {
focusTable(that.table);
return;
}
if (that.editable.end()) if (mode == "incell") that.closeCell();
else {
that.saveRow();
isEdited = true;
}
else {
if (stacked && isStackedCell) return that._setCurrentStackedCell(current);
if (mode == "incell") that._setCurrent(editContainer);
else that._setCurrent(editContainer.children().filter(DATA_CELL).first());
focusable = editContainer.find(":kendoFocusable").first()[0];
if (focusable) focusable.focus();
return;
}
}
if (next) that._setCurrent(next);
if (!isStackedCell) focusTable(that.table, true);
if (!editable) return;
if (!isEdited && !next || next) if (mode === INCELL) {
if (!(stacked ? current.find("[ref='expand-detail-button'], [ref='collapse-detail-button']").length : $(that.current()).hasClass(HIERARCHY_CELL_CLASS))) {
const stacked = that._isStackedMode();
const cell = stacked ? current : that.current();
if (stacked && cell.is(".k-command-cell")) return;
that.editCell(cell, stacked && cell.parent().children().index(cell));
}
} else that.editRow(that.current().parent());
that._toggleToolbarEditingItemsVisibility();
},
_wrapper: function() {
var that = this, table = that.table, height = that.options.height, width = that.options.width, wrapper = that.element;
if (!wrapper.is(DIV)) wrapper = wrapper.wrap("<div/>").parent();
that.wrapper = wrapper.addClass("k-grid " + kendo.getValidCssClass("k-grid-", "size", that.options.size));
if (that._isStackedMode()) that.wrapper.addClass(STACKED);
else that.wrapper.removeClass(STACKED);
if (height) {
that.wrapper.css(HEIGHT, height);
table.css(HEIGHT, AUTO);
}
if (width) that.wrapper.css(WIDTH, width);
that._initMobile();
},
_initContextMenu: function() {
var that = this, options = that.options, groupsContextMenu = isPlainObject(options.contextMenu) && isArray(options.contextMenu.groups) ? { items: options.contextMenu.groups } : { items: defaultGroupsContextMenu }, tbodyContextMenu = isPlainObject(options.contextMenu) && isArray(options.contextMenu.body) ? { items: options.contextMenu.body } : { items: defaultBodyContextMenu }, theadContextMenu = isPlainObject(options.contextMenu) && isArray(options.contextMenu.head) ? { items: options.contextMenu.head } : { items: defaultHeadContextMenu };
var mainOptions = isPlainObject(options.contextMenu) ? options.contextMenu : {};
tbodyContextMenu = extend({}, {
messages: options.messages,
target: that.wrapper,
filter: ".k-grid-content .k-table-td, .k-grid-content-locked .k-table-td, .k-grid-pinned-container .k-table-td, .k-table-tbody .k-table-td",
copyAnchorStyles: false,
action: that._action.bind(that),
states: that._buildStates()
}, mainOptions, tbodyContextMenu);
theadContextMenu = extend({}, {
messages: options.messages,
target: that.thead,
filter: ".k-table-th",
action: that._action.bind(that),
states: that._buildStates()
}, mainOptions, theadContextMenu);
if (that.groupable) groupsContextMenu = extend({}, {
showOn: "click",
target: that.groupable.groupContainer,
filter: ".k-groupable-context-menu",
messages: options.messages,
action: that._action.bind(that),
states: that._buildStates()
}, mainOptions, groupsContextMenu);
that.tbodyContextMenu = new ui.grid.ContextMenu("<ul></ul>", tbodyContextMenu);
that.theadContextMenu = new ui.grid.ContextMenu("<ul></ul>", theadContextMenu);
that.groupsContextMenu = !!that.groupable && new ui.grid.ContextMenu("<ul></ul>", groupsContextMenu);
if (that._isPinnable() && that.tbodyContextMenu) {
const menu = that.tbodyContextMenu;
const origOnOpen = menu._onOpen.bind(menu);
const pinRowLocation = that._getPinnableRowLocation();
let pinnedMenuContext = false;
menu.unbind("open");
menu.bind("open", function(ev) {
origOnOpen(ev);
if (!ev.event || ev.isDefaultPrevented && ev.isDefaultPrevented()) {
if (pinnedMenuContext) {
const reorderItem = menu.element.find("[data-command=ReorderRowCommand]").closest(".k-menu-group").closest(".k-menu-item");
if (reorderItem.length) menu.enable(reorderItem, false);
}
return;
}
const row = $(ev.event.target).closest("tr");
const dataItem = row.length ? that.dataItem(row) : null;
const position = dataItem ? that._getRowPinPosition(dataItem) : "none";
pinnedMenuContext = row.closest(".k-grid-pinned-container").length > 0;
togglePinMenuItems(menu.element[0], position, pinRowLocation, that.options.messages.commands);
const pinItems = menu.element.find("[data-command=PinTopCommand],[data-command=PinBottomCommand],[data-command=UnpinCommand]").closest(".k-menu-item");
const parentItem = pinItems.closest(".k-menu-group").closest(".k-menu-item");
const rowPinnable = !dataItem || that._checkRowPinnable(dataItem);
menu.enable(pinItems, rowPinnable);
if (parentItem.length) menu.enable(parentItem, rowPinnable);
const reorderItem = menu.element.find("[data-command=ReorderRowCommand]").closest(".k-menu-group").closest(".k-menu-item");
if (reorderItem.length && pinnedMenuContext) menu.enable(reorderItem, false);
});
if (pinRowLocation !== "both") menu.bind("select", function(ev) {
const cmd = $(ev.item).data("command");
if (cmd === "PinTopCommand" || cmd === "PinBottomCommand" || cmd === "UnpinCommand") menu.close();
});
}
},
_buildStates: function() {
var that = this;
return {
isEditable: that.options.editable,
isSelectable: that.options.selectable,
isSortable: that.options.sortable,
isRowReorderable: isPlainObject(that.options.reorderable) ? that.options.reorderable.rows : that.options.reorderable,
isGroupable: that.options.groupable,
isPinnable: that._isPinnable(),
allowPaste: that.options.allowPaste,
alwaysDisabled: false,
hasSelection: () => this.select() ? this.select().length > 0 : false,
isSorted: () => !(this.dataSource.sort() ? this.dataSource.sort().length > 0 : false),
canMoveGroupPrev: (target) => {
return $(target).closest(".k-chip").index() > 0;
},
canMoveGroupNext: (target) => {
var length = $(target).closest(".k-chip-list").children().length - 1;
return $(target).closest(".k-chip").index() < length;
}
};
},
_action: function(args) {
var commandName = args.command, commandOptions = extend({ grid: this }, args.options);
return new ui.grid.commands[commandName](commandOptions).exec();
},
_initMobile: function() {
var options = this.options;
var that = this;
this._isMobile = that.options.adaptiveMode !== "auto" && options.mobile === true && kendo.support.mobileOS || options.mobile === "phone" || options.mobile === "tablet";
if (kendo.support.mobileOS) this.wrapper.addClass("k-grid-mobile");
if (this._isMobile) {
var html = this.wrapper.wrap("<div data-" + kendo.ns + "stretch=\"true\" data-" + kendo.ns + "role=\"view\" data-" + kendo.ns + "init-widgets=\"false\"></div>").parent();
this.pane = this._createPane(html);
this.view = this.pane.view();
if (options.height) this.pane.element.parent().css(HEIGHT, options.height);
else this.pane.element.parent().css(HEIGHT, this.wrapper[0].style.height);
this._editAnimation = "slide";
that.wrapper.on("transitionend.kendoGrid", function(e) {
e.stopPropagation();
});
that.wrapper.on("contextmenu.kendoGrid", "th a", function(e) {
e.preventDefault();
return false;
});
this.view.bind("showStart", function() {
if (that._isLocked()) {
that._updateTablesWidth();
that._applyLockedContainersWidth();
that._syncLockedContentHeight();
that._syncLockedHeaderHeight();
that._syncLockedFooterHeight();
}
});
}
},
_createPane: function(html) {
return kendo.Pane.wrap(html, { viewEngine: { viewOptions: {
renderOnInit: true,
wrap: false,
wrapInSections: true,
detachOnHide: false,
detachOnDestroy: false
} } });
},
_initLoader: function(options) {
var that = this, defaultOptions = {
size: "medium",
messages: { exporting: "Exporting..." }
};
defaultOptions = $.extend({}, defaultOptions, options);
that.loader = $("<div></div>").kendoLoader(defaultOptions).data("kendoLoader");
that._loaderContainer = require_loaderContainer.useLoaderContainer.bind(that);
},
_tbody: function() {
var that = this, table = that.table, tbody = table.find(">tbody");
if (!tbody.length) tbody = $("<tbody/>").appendTo(table);
tbody.addClass("k-table-tbody");
that.tbody = tbody;
},
_scrollable: function() {
var that = this, header, table, options = that.options, scrollable = options.scrollable, virtualScroll = scrollable !== true && scrollable.virtual ? parseVirtualSettings(scrollable.virtual) : null, scrollbar = !kendo.support.kineticScrollNeeded || virtualScroll && virtualScroll.rows ? kendo.support.scrollbar() : 0, headerWrap;
const stacked = that._isStackedMode();
if (scrollable) {
if (!stacked) {
header = that.wrapper.children(".k-grid-header");
if (!header[0]) header = $("<div class=\"k-grid-header\" />").insertBefore(that.table);
header.css(isRtl ? "padding-left" : "padding-right", scrollable.virtual ? scrollbar + 1 : scrollbar);
table = $("<table role=\"none\" class=\"k-grid-header-table k-table\"/>");
table.addClass(kendo.getValidCssClass("k-table-", "size", options.size));
table.width(that.table[0].style.width);
}
if (!stacked) {
table.append(that.thead);
header.empty().append($("<div class=\"k-grid-header-wrap k-auto-scrollable\" />").append(table));
}
that.content = that.table.parent();
that.virtualScroll = virtualScroll;
if (that.content.is(".k-virtual-scrollable-wrap, ." + classNames.scrollContainer)) that.content = that.content.parent();
if (!that.content.is(".k-grid-content, .k-virtual-scrollable-wrap")) that.content = that.table.wrap("<div class=\"k-grid-content k-auto-scrollable\" />").parent();
if (!that.content.parent().hasClass("k-grid-container")) that.content.wrap("<div class='k-grid-container' />").parent();
if (virtualScroll && virtualScroll.rows && !that.virtualScrollable) that._createVirtualScrollable();
if (virtualScroll && virtualScroll.columns) that.table.add(that.thead.parent()).css({ width: sumWidths(visibleLeafColumns(visibleNonLockedColumns(that.columns))) });
if (!stacked) {
headerWrap = header.children(".k-grid-header-wrap");
that.scrollables = headerWrap.add(that.content);
} else that.scrollables = that.content;
var footer = that.wrapper.find(".k-grid-footer");
if (footer.length) that.scrollables = that.scrollables.add(footer.children(".k-grid-footer-wrap"));
if (!stacked) headerWrap.off("scroll.kendoGrid").on("scroll.kendoGrid", function(e) {
if (that._scrollLeft !== this.scrollLeft) kendo.scrollLeft(that.scrollables.not(e.currentTarget), this.scrollLeft);
});
if (virtualScroll && virtualScroll.rows) that.content.find(">.k-virtual-scrollable-wrap").off("scroll.kendoGrid").on("scroll.kendoGrid", function() {
var isScrollingLeft = this.scrollLeft != that._scrollLeft;
that._scrollLeft = this.scrollLeft;
kendo.scrollLeft(that.scrollables, this.scrollLeft);
if (that.lockedContent) that.lockedContent[0].scrollTop = this.scrollTop;
if (virtualScroll.columns && isScrollingLeft) that.refresh();
if (that._stickyGroupsScrollHandler) that._stickyGroupsScrollHandler();
if (that._isPinnable()) that._syncPinnedScroll(this);
});
else {
var endless = scrollable.endless;
var originalPageSize = that.dataSource.options.pageSize;
if (endless) that._endlessPageSize = originalPageSize;
that.content.off("scroll.kendoGrid").on("scroll.kendoGrid", function(e) {
var isScrollingLeft = this.scrollLeft != that._scrollLeft;
that._scrollLeft = this.scrollLeft;
kendo.scrollLeft(that.scrollables.not(e.currentTarget), that._scrollLeft);
if (that.lockedContent && e.currentTarget == that.content[0]) that.lockedContent[0].scrollTop = this.scrollTop;
if (endless) {
if (this.scrollTop + this.clientHeight - this.scrollHeight >= -10 && !that._endlessFetchInProgress && that._endlessPageSize < that.dataSource.total()) {
that._skipRerenderItemsCount = that._endlessPageSize;
that._endlessPageSize = that._endlessPageSize + originalPageSize;
that.dataSource.options.endless = true;
that._endlessFetchInProgress = true;
that.dataSource.pageSize(that._endlessPageSize);
}
}
if (virtualScroll && virtualScroll.columns && isScrollingLeft) {
that._virtualColScroll = true;
that._cacheEditableState();
that.refresh();
that._restoreEditableState();
that._virtualColScroll = false;
}
if (that.rowResizer) that.rowResizer.css("left", e.currentTarget.scrollLeft + "px");
if (that._stickyGroupsScrollHandler) that._stickyGroupsScrollHandler();
if (that._isPinnable()) that._syncPinnedScroll(e.currentTarget);
});
var touchScroller = that.content.data("kendoTouchScroller");
if (touchScroller) touchScroller.destroy();
touchScroller = kendo.touchScroller(that.content);
if (touchScroller && touchScroller.movable) {
that.touchScroller = touchScroller;
touchScroller.movable.bind("change", function(e) {
kendo.scrollLeft(that.scrollables, -e.sender.x);
if (that.lockedContent) that.lockedContent.scrollTop(-e.sender.y);
});
that.one(DATABOUND, function(e) {
e.sender.wrapper.addClass("k-grid-backface");
});
}
}
that._initStickyGroups();
}
},
_createVirtualScrollable: function() {
var that = this;
if (that.virtualScrollable) that.virtualScrollable.destroy();
that.virtualScrollable = new VirtualScrollable(that.content, {
dataSource: that.dataSource,
itemHeight: function() {
return that._averageRowHeight();
},
page: function() {
that._restoreEditableState();
},
scroll: function() {
that._focusEditable();
},
loadStart: function() {
that._progress(true);
},
loadEnd: function() {
that._progress(false);
}
});
that.virtualScrollable.bind(PAGING, that._onVirtualPaging.bind(that));
},
_onVirtualPaging: function() {
var that = this;
that._cacheEditableState();
if (that._isVirtualIncellEditable()) {
that._shouldClearEditableState = false;
that.closeCell();
that._shouldClearEditableState = true;
}
},
_isVirtualEditable: function() {
return this._isVirtualIncellEditable() || this._isVirtualInlineEditable() || this._isVirtualPopupEditable();
},
_isVirtualInlineEditable: function() {
return this.virtualScrollable && this._editMode() === INLINE;
},
_isVirtualIncellEditable: function() {
return this.virtualScrollable && this._editMode() === INCELL;
},
_isVirtualPopupEditable: function() {
return this.virtualScrollable && this._editMode() === "popup";
},
_hasVirtualColumns: function() {
return (this.virtualScroll || {}).columns ? true : false;
},
_hasVirtualRows: function() {
return (this.virtualScroll || {}).rows ? true : false;
},
_scrollVirtualWrapper: function() {
var that = this;
var scrollable = that.virtualScrollable;
if (that._isVirtualInlineEditable() || that._isVirtualIncellEditable()) {
if (scrollable._isScrolledToBottom()) scrollable._scrollWrapperToBottom();
else if (scrollable._isScrolledToTop()) scrollable._scrollWrapperToTop();
}
},
_scrollVirtualWrapperOnColumnResize: function() {
var virtualScrollable = this.virtualScrollable;
if (virtualScrollable) virtualScrollable._scrollWrapperOnColumnResize();
},
_restoreEditableState: function() {
var that = this;
var editableState = that._editableState || {};
var editedModel = editableState.model;
var dataSource = that.dataSource;
var inlineMode = that._isVirtualInlineEditable();
var incellMode = that._isVirtualIncellEditable();
var virtualColumns = that._hasVirtualColumns();
var row;
var cell;
if ((inlineMode || incellMode || virtualColumns) && editedModel && dataSource._getByUid(editedModel.uid, dataSource.view())) {
if (that._editMode() === INLINE) {
that._shouldClearEditableState = false;
that.editRow(editedModel);
if (!virtualColumns) that._focusEditable();
} else if (that._editMode() === INCELL) {
const stacked = that._isStackedMode();
row = that.tbody.children(attrEquals(UNIQUE_ID, editedModel.uid));
cell = stacked ? $(row).find(".k-grid-stack-cell:not(.k-drag-cell):not(.k-command-cell)" + attrEquals(FIELD, editableState.field)) : $(row).children(attrEquals(FIELD, editableState.field));
if (cell[0]) {
that._shouldClearEditableState = false;
that.editCell(cell, stacked && cell.parent().children().index(cell));
if (!virtualColumns) that._focusEditable();
}
}
}
that._shouldClearEditableState = true;
},
_focusEditable: function() {
var that = this;
var editedField = (that._editableState || {}).field;
var editContainer = that._editContainer;
if (editContainer && editContainer.length && !contains(editContainer[0], activeElement()) && that._canFocusEditable()) {
if (that._isVirtualInlineEditable() || that._hasVirtualColumns()) editContainer.find(attrEquals(CONTAINER_FOR, editedField)).find(FOCUSABLE).eq(0).trigger("focus");
else if (that._isVirtualIncellEditable() || that._hasVirtualColumns()) editContainer.find(FOCUSABLE).eq(0).trigger("focus");
}
},
_canFocusEditable: function() {
var that = this;
return (that._isVirtualIncellEditable() || that._isVirtualInlineEditable() || that._hasVirtualColumns()) && (isElementVisibleInWrapper((that.virtualScrollable || {}).wrapper, that._editContainer) || isElementVisibleInWrapper(that.content, that._editContainer));
},
_cacheEditableState: function() {
var that = this;
var editContainer = that._editContainer;
var editedModel = editContainer ? that._modelForContainer(editContainer) : null;
var inlineMode = that._isVirtualInlineEditable();
var incellMode = that._isVirtualIncellEditable();
var virtualColumns = that._hasVirtualColumns();
var active;
var widget;
var value;
if ((inlineMode || incellMode || virtualColumns) && editedModel) {
that._clearEditableState();
active = $(activeElement());
if (editContainer && active[0] && contains(editContainer[0], active[0])) {
active.change();
widget = kendo.widgetInstance(active, kendo.ui);
if (widget && isFunction(widget.value) && active.is(INPUT)) {
value = active.val();
if (active.is("[type='checkbox'")) value = active.is(":checked");
widget.value(value);
widget.trigger(CHANGE);
}
}
if (that._editMode() === INLINE) that._editableState = {
model: editedModel,
field: active.closest("[" + kendo.attr(CONTAINER_FOR) + "]").attr(kendo.attr(CONTAINER_FOR))
};
else if (that._editMode() === INCELL) that._editableState = {
model: editedModel,
field: editContainer.attr(kendo.attr(FIELD))
};
}
},
_clearSortClasses: function() {
var that = this, content = that.content || that.table, lockedContent = that.lockedContent;
if (content) content.find(COLGROUP).removeClass(SORTED_CLASS);
if (lockedContent) lockedContent.find(COLGROUP).removeClass(SORTED_CLASS);
},
_clearEditableState: function() {
var that = this;
if (that.virtualScrollable || that.virtualScroll && that._hasVirtualColumns()) that._editableState = null;
},
_destroyVirtualScrollable: function() {
var that = this;
that._clearEditableState();
if (that.virtualScrollable && that.virtualScrollable.element) that.virtualScrollable.destroy();
that.virtualScrollable = null;
},
_destroyRowResizing: function() {
if (this.rowResizing) {
this.rowResizing.destroy();
this.rowResizing = null;
}
if (this.rowResizer) {
this._detachRowResizerEvents();
this.rowResizer.off("dblclick.kendoGrid");
this.rowResizer = null;
this._clearCachedRowsHeight();
}
},
_renderNoRecordsContent: function() {
var that = this;
if (that.options.noRecords) {
var noRecordsElement = that.table.parent().children(".k-grid-norecords");
if (noRecordsElement.length) noRecordsElement.remove();
if (!that.dataSource || !that.dataSource.view().length) {
noRecordsElement = $(that.noRecordsTemplate({ grid: that }));
kendo.applyStylesFromKendoAttributes(noRecordsElement, ["margin", "position"]);
noRecordsElement.insertAfter(that.table);
}
}
},
_setContentWidth: function(scrollLeft) {
var that = this, hiddenDivClass = "k-grid-content-expander", hiddenDiv = "<div class=\"" + hiddenDivClass + "\"></div>", resizable = that.resizable, expander;
if (that.options.scrollable && that.wrapper.is(":visible")) {
expander = that.table.parent().children("." + hiddenDivClass);
that._setContentWidthHandler = that._setContentWidth.bind(that);
if (!that.dataSource || !that.dataSource.view().length) {
if (!expander[0]) {
expander = $(hiddenDiv).appendTo(that.table.parent());
if (resizable) resizable.bind("resize", that._setContentWidthHandler);
}
if (that.thead) {
expander.width(that.thead.width());
if (!isNaN(parseFloat(scrollLeft, 10))) kendo.scrollLeft(that.content, scrollLeft);
}
} else if (expander[0]) {
expander.remove();
if (resizable) resizable.unbind("resize", that._setContentWidthHandler);
}
that._applyLockedContainersWidth(true);
that._syncLockedContentHeight();
if (that.lockedHeader && that.table[0].clientWidth === 0) that.table[0].style.width = "1px";
}
},
_applyLockedContainersWidth: function(calculateGroupWidth) {
if (this.options.scrollable && this.lockedHeader) {
let headerTable = this.thead.parent(), headerWrap = headerTable.parent(), contentWidth = this.wrapper[0].clientWidth, groups = this._groups(), scrollbar = kendo.support.scrollbar(), cols = this.lockedHeader.find(">table>colgroup>col:not(.k-group-col, .k-hierarchy-col)"), nonLockedCols = headerTable.find(">colgroup>col:not(.k-group-col, .k-hierarchy-col)"), width = columnsWidth(cols), nonLockedColsWidth = columnsWidth(nonLockedCols), footerWrap;
if (groups > 0 && calculateGroupWidth) width += outerWidth(this.lockedHeader.find(".k-group-cell").first()) * groups;
if (width >= contentWidth) width = contentWidth - 3 * scrollbar;
this.lockedHeader.add(this.lockedContent).width(width);
headerWrap[0].style.width = headerWrap.parent().width() - width - 2 + PX;
headerTable.add(this.table).width(nonLockedColsWidth);
if (this.virtualScrollable && !isIE11) contentWidth -= scrollbar;
this.content[0].style.width = contentWidth - width - 1 + PX;
if (this.lockedFooter && this.lockedFooter.length) {
this.lockedFooter.width(width);
footerWrap = this.footer.find(".k-grid-footer-wrap");
footerWrap[0].style.width = headerWrap[0].clientWidth + PX;
footerWrap.children().first().width(nonLockedColsWidth);
}
}
},
_setContentHeight: function() {
var that = this, options = that.options, height, header = that.wrapper.children(".k-grid-header"), scrollbar = kendo.support.scrollbar();
var scrollableHeight = (options.scrollable || {}).height;
if (options.scrollable && that.wrapper.is(":visible")) {
if (scrollableHeight && that.content[0].style.height === "" && !that._scrollableHeightApplied) that.content[0].style.height = scrollableHeight;
height = that.wrapper.innerHeight();
height -= outerHeight(header);
if (that.pager && that.pager.element.is(":visible")) height -= outerHeight(that.pager.element);
if (options.groupable) height -= outerHeight(that.wrapper.children(".k-grouping-header:not(.k-hidden)"));
if (options.toolbar) height -= outerHeight(that.wrapper.children(".k-grid-toolbar"));
if (that.footerTemplate) height -= outerHeight(that.wrapper.children(".k-grid-footer"));
if (that.statusBar) height -= outerHeight(that.wrapper.children(".k-selection-aggregates"));
that.wrapper.find(".k-grid-pinned-container:not(.k-hidden)").each(function() {
height -= outerHeight($(this).find(".k-grid-table")[0] || this);
});
var isGridHeightSet = function(el) {
var initialHeight, newHeight;
if (el[0].style.height) return true;
else initialHeight = el.height();
el.height(AUTO);
newHeight = el.height();
if (initialHeight != newHeight) {
el.height("");
return true;
}
el.height("");
return false;
};
if (isGridHeightSet(that.wrapper)) if (height > scrollbar * 2) {
if (that.lockedContent) {
scrollbar = that.table[0].offsetWidth > that.table.parent()[0].clientWidth ? scrollbar : 0;
that.lockedContent.height(height - scrollbar);
}
that.content.height(height);
} else that.content.height(scrollbar * 2 + 1);
}
},
_averageRowHeight: function() {
var that = this, itemsCount = that._items(that.tbody, true).length, rowHeight = that._rowHeight;
if (itemsCount === 0) return rowHeight;
if (!that._rowHeight) {
that._rowHeight = rowHeight = outerHeight(that.table) / itemsCount;
that._sum = rowHeight;
that._measures = 1;
}
var currentRowHeight = outerHeight(that.table) / itemsCount;
if (rowHeight !== currentRowHeight) {
that._measures++;
that._sum += currentRowHeight;
that._rowHeight = that._sum / that._measures;
}
return rowHeight;
},
_dataSource: function() {
var that = this, options = that.options, pageable, dataSource = options.dataSource;
dataSource = isArray(dataSource) ? { data: dataSource } : dataSource;
if (isPlainObject(dataSource)) {
extend(dataSource, {
table: that.table,
fields: that.columns
});
pageable = options.pageable;
if (isPlainObject(pageable) && pageable.pageSize !== undefined) dataSource.pageSize = pageable.pageSize;
}
if (that.dataSource && that._refreshHandler) that.dataSource.unbind(CHANGE, that._refreshHandler).unbind(PROGRESS, that._progressHandler).unbind(REQUESTEND, that._requestEndHandler).unbind(ERROR, that._errorHandler).unbind(SORT, that._sortHandler);
else {
that._refreshHandler = that.refresh.bind(that);
that._progressHandler = that._requestStart.bind(that);
that._requestEndHandler = that._requestEnd.bind(that);
that._errorHandler = that._error.bind(that);
that._sortHandler = that._clearSortClasses.bind(that);
}
that.dataSource = DataSource.create(dataSource).bind(CHANGE, that._refreshHandler).bind(PROGRESS, that._progressHandler).bind(REQUESTEND, that._requestEndHandler).bind(ERROR, that._errorHandler).bind(SORT, that._sortHandler);
},
_error: function() {
this._progress(false);
this._requestInProgress = false;
},
_requestStart: function() {
this._progress(true);
this._requestInProgress = true;
},
_requestEnd: function() {
this._requestInProgress = false;
},
_modelChange: function(e) {
var that = this, tbody = that.tbody, model = e.model, row = that.tbody.find("tr[" + kendo.attr("uid") + "=" + model.uid + "]"), relatedRow, cell, column, isAlt = row.hasClass("k-table-alt-row"), tmp, idx = that._items(tbody).index(row), isLocked = that.lockedContent, selectable, selectableRow, childCells, originalCells, length;
const stacked = that._isStackedMode();
if (isLocked) relatedRow = that._relatedRow(row);
if ((stacked ? row.add(relatedRow).find(".k-grid-stack-cell:not(.k-drag-cell):not(.k-command-cell)") : row.add(relatedRow).children(".k-edit-cell")).length && !that.options.rowTemplate) (stacked ? row.add(relatedRow).children(":not(.k-group-cell,.k-hierarchy-cell)").find(".k-grid-stack-cell:not(.k-drag-cell):not(.k-command-cell)") : row.add(relatedRow).children(":not(.k-group-cell,.k-hierarchy-cell)")).each(function() {
cell = $(this);
const isDetailCell = cell.find("[ref='collapse-detail-button'],[ref='expand-detail-button']").length > 0;
if (stacked && (cell.hasClass("k-command-cell") || isDetailCell)) return;
column = leafColumns(that.columns)[that._calculateColumnIndex(cell)];
if (column?.field === e.field) {
const editClass = stacked ? "k-grid-stack-edit-cell" : "k-edit-cell";
if (!cell.hasClass(editClass)) {
const target = stacked ? cell.find(".k-grid-stack-content") : cell;
that._displayCell(target, column, model);
} else cell.addClass("k-dirty-cell");
}
});
else if (!row.hasClass("k-grid-edit-row")) {
selectableRow = $().add(row);
if (isLocked) {
tmp = (isAlt ? that.lockedAltRowTemplate : that.lockedRowTemplate)(model);
selectableRow = selectableRow.add(relatedRow);
relatedRow.replaceWith(tmp);
}
tmp = (isAlt ? that.altRowTemplate : that.rowTemplate)(model);
let tmpResult = $(tmp);
kendo.applyStylesFromKendoAttributes(tmpResult, ["display"]);
row.replaceWith(tmpResult);
tmp = that._items(tbody).eq(idx);
if (isLocked) {
row = row.add(relatedRow);
relatedRow = that._relatedRow(tmp)[0];
adjustRowHeight(tmp[0], relatedRow);
tmp = tmp.add(relatedRow);
}
selectable = that.options.selectable;
if ((selectable || that._checkBoxSelection) && row.hasClass(SELECTED)) that.select(tmp);
originalCells = selectableRow.children(":not(.k-group-cell,.k-hierarchy-cell)");
childCells = tmp.children(":not(.k-group-cell,.k-hierarchy-cell)");
for (idx = 0, length = that.columns.length; idx < length; idx++) {
column = that.columns[idx];
cell = stacked ? childCells.find().eq(idx) : childCells.eq(idx);
if (selectable && originalCells.eq(idx).hasClass(SELECTED)) cell.addClass(SELECTED);
}
that.trigger("itemChange", {
item: tmp,
data: model,
ns: ui
});
}
if (!that._editContainer || !that._editContainer.closest(".k-grid-pinned-container").length) that._renderPinnedRows();
that._toggleToolbarEditingItemsVisibility();
},
_pageable: function() {
var that = this, pagerWrap, pageable = that.options.pageable, size = that.options.size, navigatable = that.options.navigatable;
if (pageable) {
pagerWrap = that.wrapper.children("div.k-grid-pager");
if (!pagerWrap.length) pagerWrap = $("<div class=\"k-pager k-grid-pager\"/>");
if (pageable.position === "top") pagerWrap.prependTo(that.wrapper).addClass("k-grid-pager-top");
else pagerWrap.appendTo(that.wrapper);
if (that.pager) that.pager.destroy();
let adaptive = that.options.adaptiveMode;
if (that.options.adaptiveMode === "auto") {
if (pageable && typeof pageable === "object" && pageable.adaptiveMode) adaptive = pageable.adaptiveMode;
}
if (typeof pageable === "object" && pageable instanceof kendo.ui.Pager) that.pager = pageable;
else if (that.dataSource._groupPaging) that.pager = new GroupsPager(pagerWrap, extend({}, pageable, {
dataSource: that.dataSource,
navigatable,
size,
adaptiveMode: adaptive
}));
else that.pager = new kendo.ui.Pager(pagerWrap, extend({}, pageable, {
dataSource: that.dataSource,
navigatable,
size,
adaptiveMode: adaptive
}));
that.pager.bind("pageChange", function(e) {
if (that.trigger("page", { page: e.index })) e.preventDefault();
});
that._togglePagerVisibility();
}
},
_statusBar: function() {
var that = this, options = that.options, wrapper = that.wrapper, statusBarTemplate = options.statusBarTemplate, content = "";
if (statusBarTemplate) if (!that.statusBar) {
content += "<div class=\"k-selection-aggregates k-grid-selection-aggregates\">";
content += statusBarTemplate({ aggregates: that._cellAggregates });
content += "</div>";
if (options.scrollable) that.statusBar = $(content).insertAfter(wrapper.find(".k-grid-container"));
else that.statusBar = $(content).insertAfter(wrapper.find(".k-grid-table"));
} else that.statusBar.html(statusBarTemplate({ aggregates: that._cellAggregates }));
},
_footer: function() {
var that = this, aggregates = that.dataSource.aggregates(), html = "", footerTemplate = that.footerTemplate, options = that.options, footerWrap, footer = that.footer || that.wrapper.find(".k-grid-footer");
if (footerTemplate) {
html = $(that._wrapFooter(footerTemplate(aggregates)));
kendo.applyStylesFromKendoAttributes(html, [
"display",
"left",
"right"
]);
if (footer.length) {
var tmp = html;
footer.replaceWith(tmp);
footer = that.footer = tmp;
} else if (options.scrollable) {
if (that.statusBar) that.footer = html.insertBefore(that.statusBar);
else if (options.pageable && options.pageable.position !== "top") that.footer = html.insertBefore(that.wrapper.children("div.k-grid-pager"));
else that.footer = html.appendTo(that.wrapper);
footer = that.footer;
} else footer = that.footer = html.insertAfter(that.tbody);
} else if (footer && !that.footer) that.footer = footer;
if (footer.length) {
if (options.scrollable) {
footerWrap = footer.attr(TABINDEX, -1).children(".k-grid-footer-wrap");
that.scrollables = $(that.scrollables.filter(function() {
return !$(this).is(".k-grid-footer-wrap");
}).toArray()).add(footerWrap);
}
if (that._footerWidth) footer.find("table").css("width", that._footerWidth);
if (that.thead && !that.lockedContent) syncFooterColsWidthsWithHeader(that.thead, footer);
if (footerWrap) {
var offset = kendo.scrollLeft(that.content);
if (options.scrollable !== true && that.virtualScroll && that.virtualScroll.rows) offset = kendo.scrollLeft(that.wrapper.find(".k-virtual-scrollable-wrap"));
kendo.scrollLeft(footerWrap, offset);
}
}
if (that.lockedContent) {
that._appendLockedColumnFooter();
that._applyLockedContainersWidth();
that._syncLockedFooterHeight();
}
},
_wrapFooter: function(footerRow) {
var that = this, html = "", table, scrollbar = !kendo.support.mobileOS ? kendo.support.scrollbar() : 0;
if (that.options.scrollable) {
html = $("<div class=\"k-grid-footer\"><div class=\"k-grid-footer-wrap\"><table class=\"k-table k-grid-footer-table\"><tfoot class=\"k-table-tfoot\">" + footerRow + "</tfoot></table></div></div>");
table = html.find("table");
table.addClass(kendo.getValidCssClass("k-table-", "size", that.options.size));
that._appendCols(table);
html.css(isRtl ? "padding-left" : "padding-right", scrollbar);
return html;
}
return "<tfoot class=\"k-grid-footer k-table-tfoot\">" + footerRow + "</tfoot>";
},
_actionsheetFooterActionsTemplate: function(buttonsConfig) {
let buttonsHtml = "";
buttonsConfig.forEach((buttonOptions) => {
const command = buttonOptions.command;
const text = buttonOptions.text;
buttonsHtml += kendo.html.renderButton(`<button data-command=${command}>${text}</button>`, buttonOptions);
});
return buttonsHtml;
},
_isAdaptive: function() {
const that = this;
return that.options.adaptiveMode === "auto" && (that.smallMQL.mediaQueryList.matches || that.mediumMQL.mediaQueryList.matches);
},
_isStackedMode: function() {
return this.options.dataLayoutMode === "stacked";
},
_toolPopup: function(cell) {
return cell.popup && cell.popup.wrapper;
},
_filterToolbarTool: function(cell) {
const that = this;
const columns = leafColumns(that.columns);
const options = that.options;
const clearFilterButton = (cell) => {
const clearFilterSelector = that._isAdaptive() ? "[ref-actionsheet-action-button]" : "[ref='clear-filter']";
return that._toolPopup(cell)?.find(clearFilterSelector);
};
const toolbarFilterOptions = that._toolbarOptionsForTool("filter");
function content({ isAdaptive }) {
let content = "";
for (let i = 0; i < columns.length; i++) {
const column = columns[i];
if (!(options.filterable && column.filterable !== false) || column.command || column.draggable || column.selectable || column.pinnable) continue;
content += `<div class="k-columnmenu-item-wrapper">`;
content += `<div class="k-columnmenu-item-content k-columns-item" ref="filter" tabindex="0" data-field="${column.field}" data-index=${column.index || i || 0}></div>`;
content += `</div>`;
}
if ((!toolbarFilterOptions || toolbarFilterOptions.clearButton) && !isAdaptive) {
content += `<div class="k-actions k-actions-stretched k-actions-horizontal k-column-menu-footer">`;
content += kendo.html.renderButton(`<button ref="clear-filter">${defaultActionSheetFooterButtons(that.options.messages).filter[0].text}</button>`, { icon: "filter-clear" });
content += "</div>";
}
return content;
}
const menu = cell.data("kendoColumnMenu");
if (menu) {
menu.wrapper.off("click.kendoGrid");
menu.element.off("click.kendoGrid");
menu.destroy();
}
const filterable = options.filterable && that.options.columnMenu.filterable !== false ? extend(true, { pane: that.pane }, options.filterable) : false;
if (!filterable) return;
const menuOptions = {
dataSource: that.dataSource,
columns: false,
sortable: false,
filterable,
hideAutoSizeColumn: true,
owner: that,
adaptiveMode: that.options.adaptiveMode,
encodeTitles: that.options.encodeTitles,
componentType: "modern",
_actionsheet: {
actionButtons: defaultActionSheetFooterButtons(that.options.messages).filter,
title: "Filter by",
closeButton: true,
ref: "filter-view"
},
closeCallback: function(e) {
e.removeClass(SELECTED);
const popupElement = that._toolPopup(cell);
if (popupElement.length) popupElement.find(".k-focus").removeClass("k-focus");
cell.element.focus();
},
init: function(e) {
cell.wrapper.attr("ref", "filter-tool");
if (!that._showAdaptiveView) for (var idx = 0, length = columns.length; idx < length; idx++) {
const column = columns[idx];
const field = column.field;
if (!(options.filterable && column.filterable !== false && !column.draggable && !column.selectable && !column.command && !column.pinnable)) continue;
const element = cell.wrapper.find(`.k-columns-item[data-field="${field}"]`);
that._initFilterMenuForColumn(column, element);
}
},
contentTemplate: content,
filtering: function(e) {
if (that.trigger("filter", {
filter: e.filter,
field: e.field
})) e.preventDefault();
else {
that._clearEditableState();
if (that.dataSource.options.endless) that._resetEndless();
}
}
};
cell = cell.kendoColumnMenu(menuOptions).data("kendoColumnMenu");
cell.element.bind("click.kendoGrid", function(e) {
if (cell.popup && cell.popup._closing) return;
$(e.currentTarget).addClass(SELECTED);
clearFilterButton(cell)?.toggleClass("k-disabled", !cell.dataSource._filter);
});
const filterToolHandler = function(e) {
const cell = e.sender.wrapper && e.sender.wrapper.find(".k-grid-filter-tool")?.data("kendoColumnMenu");
const filters = cell.dataSource._filter;
const field = e.field;
let isRemoveFilter = !e.filter;
let condition;
const filteredFields = filters && filters.filters;
if (isRemoveFilter && filteredFields && filteredFields.length && !filteredFields.find((descriptor) => descriptor.filters && descriptor.filters.length ? descriptor.filters[0].field === field : descriptor.field === field)) return;
const expansionPanel = cell.wrapper.find(`.k-columns-item[data-field='${field}']`);
const headerElement = expansionPanel?.closest(".k-expander")?.find(".k-columnmenu-item");
if (filters && filters.filters.length) if (isRemoveFilter) condition = filteredFields.filter((descriptor) => descriptor.field !== field).length > 0;
else condition = !isRemoveFilter;
else if (!isRemoveFilter) condition = true;
if (expansionPanel.length) expansionPanel.data("kendoExpansionPanel").toggle(false);
clearFilterButton(cell)?.toggleClass("k-disabled", !condition);
that._toggleColumnMenuFilterIndicator(headerElement, !isRemoveFilter);
that._toggleBadge(cell.element, condition);
};
that.unbind("filter", filterToolHandler);
that.bind("filter", filterToolHandler);
cell.bind("open", function() {
const popupElement = that._toolPopup(cell);
if (popupElement.length) {
popupElement.focus();
const clearFilterBtn = clearFilterButton(cell);
const filters = cell.dataSource._filter && cell.dataSource._filter.filters;
if (filters && filters.length) filters.forEach((descriptor) => {
const field = descriptor.field || descriptor.filters[0].field;
const headerElement = cell.wrapper.find(`.k-columns-item[data-field='${field}']`)?.closest(".k-expander")?.find(".k-columnmenu-item");
that._toggleColumnMenuFilterIndicator(headerElement, true);
});
if (clearFilterBtn.length) {
clearFilterBtn.off("mousedown.kendoGrid");
clearFilterBtn.on("mousedown.kendoGrid", function() {
that.dataSource.filter([]);
that._toggleBadge(cell.element, false);
cell.wrapper.find(".k-columnmenu-indicators").remove();
clearFilterBtn.toggleClass("k-disabled", true);
cell.popup.close();
});
}
}
});
},
_initFilterMenuForColumn: function(column, element) {
const that = this;
let filterable = that._hasFilterMenu();
let filterMenu;
if (element.length) {
filterMenu = element.data("kendoFilterMenu");
if (filterMenu) filterMenu.destroy();
filterMenu = element.data("kendoFilterMultiCheck");
if (filterMenu) filterMenu.destroy();
var columnFilterable = column.filterable;
var options = extend({}, filterable, columnFilterable, {
appendToElement: true,
componentType: "modern",
dataSource: that.dataSource,
values: column.values,
format: column.format,
title: column.title || column.field,
pane: that.pane,
adaptiveMode: that.options.adaptiveMode,
change: function(e) {
if (that.trigger("filter", {
filter: e.filter,
field: e.field
})) e.preventDefault();
else {
that._clearEditableState();
if (that.dataSource.options.endless) that._resetEndless();
}
}
});
if (columnFilterable && columnFilterable.messages) options.messages = extend(true, {}, filterable.messages, columnFilterable.messages);
if (columnFilterable && columnFilterable.dataSource) {
options.forceUnique = false;
options.checkSource = columnFilterable.dataSource;
}
if (columnFilterable && columnFilterable.multi) return element.kendoFilterMultiCheck(options).data("kendoFilterMultiCheck");
else return element.kendoFilterMenu(options).data("kendoFilterMenu");
}
},
_isRowSelection: function() {
const that = this;
const selectable = that.options.selectable;
if (!selectable && !that._checkBoxSelection) return false;
if (selectable === true || selectable === "multiple" || selectable === "single" || selectable?.mode === "multiple" || selectable?.mode === "single" || that._checkBoxSelection) return true;
if (isPlainObject(selectable)) {
const mode = selectable.mode;
return mode ? typeof mode === "string" && mode.includes("row") : false;
}
if (typeof selectable === "string") return selectable.includes("row");
return false;
},
_isSingleSelectionEnabled: function() {
const selectable = this.options.selectable;
if (!selectable) return false;
if (selectable === true || selectable === "single" || selectable?.mode === "single" || selectable === "row" || selectable?.mode === "row" || selectable === "cell" || selectable?.mode === "cell") return true;
if (isPlainObject(selectable)) {
const mode = selectable.mode;
return mode ? typeof mode === "string" && mode.includes("single") : false;
}
if (typeof selectable === "string") return selectable.includes("single");
return false;
},
_initAiPrompt: function() {
const that = this;
const aiOptions = that.options.ai;
const promptConfig = aiOptions?.aiAssistant || {};
const messages = that.options.messages?.ai;
let aiService = aiOptions?.service;
const defaults = {
data: (prompt) => getDefaultAIRequestConfig(prompt, flatColumnsInDomOrder(that.columns)),
outputGetter: (response) => aiPromptDefaultOutputGetter(response, messages, that._isRowSelection())
};
if (aiOptions?.service) {
const serviceIsString = typeof aiOptions.service === "string";
const url = serviceIsString ? aiOptions.service : aiOptions.service.url;
if (url) aiService = {
...defaults,
...!serviceIsString ? aiOptions.service : {},
url
};
}
const skeletonID = "skeleton" + kendo.guid();
const aiAssistant = that._aiAssistant = $("<div></div>").kendoAIPrompt($.extend(true, {
service: aiService,
speechToText: true,
promptTextArea: {
resize: "none",
rows: 3,
placeholder: messages?.promptPlaceholder || "",
fillMode: "outline",
maxLength: 1e3
},
outputTemplate: (data) => {
return data.output.output?.split("/n").map((line) => aiPromptOutputTemplate(line, messages, flatColumnsInDomOrder(that.columns))).join("");
},
views: [{
type: "prompt",
buttonIcon: "sparkles",
themeColor: "primary",
footerTemplate: () => `<div class="k-actions k-actions-start k-actions-horizontal k-prompt-actions">${kendo.html.renderButton(`<button ref-ai-apply-button>Apply</button>`, {
themeColor: "primary",
icon: "table-wizard",
rounded: "full"
})}</div>`
}, {
type: "output",
themeColor: "primary",
isStreaming: true,
isLoading: true
}],
promptRequest: (e) => {
if (!aiAssistant.options.service) return;
aiAssistant.activeView("output");
aiAssistant.removePromptOutput(placeholderId);
aiAssistant.addPromptOutput({
id: skeletonID,
prompt: e.prompt,
output: "",
isLoading: true,
isStreaming: true
});
aiAssistant._requestInProgress = true;
aiAssistant.transport.options.requestStart = null;
},
promptResponse: (e) => {
e.preventDefault();
const output = e;
handleAIResponseOutput(output, aiAssistant, skeletonID);
if (output && output.response) that.handleAIResponse(output.response);
if (aiOptions.autoClose === false) return;
that._aiAssistantWindow?.close();
},
promptRequestCancel: () => {
aiAssistant.removePromptOutput(skeletonID);
if (!aiAssistant.outputObjects.size) aiAssistant.addPromptOutput(promptPlaceholderOptions(messages));
aiAssistant._requestInProgress = false;
}
}, promptConfig)).data("kendoAIPrompt");
if (aiAssistant?.transport) aiAssistant.transport.options.error = function(res) {
res.response.abort();
handleAIResponseOutput({
output: res.output,
outputId: res.id
}, aiAssistant, skeletonID);
};
that._aiAssistantWindow.element.append(that._aiAssistant.element);
that._aiAssistantWindow.wrapper.addClass("k-grid-assistant-window");
},
handleAIResponse: function(response) {
const that = this;
const fields = that.dataSource.options.schema?.model?.fields;
const multipleSortable = that.options.sortable?.mode === "multiple" || that.options.sortable?.mode === "mixed";
const commands = prepareAICommands(response?.commands, multipleSortable);
const allColumns = flatColumnsInDomOrder(that.columns);
const enabled = getEnabledAICommands(that.options, that.dataSource, that._checkBoxSelection);
if (commands) for (let i = 0; i < commands.length; i++) {
const command = commands[i];
const type = command?.type;
const commandKey = supportedAIDataSourceCommands[type] || supportedAIGridCommands[type];
const isPageCommand = commandKey === "page" || commandKey === "pageSize";
let isClearValue = !command[commandKey];
let value;
if (supportedAIDataSourceCommands[type]) {
const hasPreviousValue = that.dataSource[commandKey]();
if (isPageCommand) value = command[commandKey];
else {
value = isClearValue ? [] : command[commandKey];
value = Array.isArray(value) ? value : [value];
}
if (!(isClearValue || !isClearValue && !hasInvalidDescriptor(value, commandKey))) continue;
if (isClearValue && !hasPreviousValue) continue;
if (enabled[type]) {
if (!isClearValue && commandKey === "filter") value = parseDate(value, fields);
if (commandKey === "sort" && !multipleSortable) {
that.dataSource[commandKey](value);
continue;
}
if (hasPreviousValue && !isClearValue && !isPageCommand) {
const previousValue = Array.isArray(hasPreviousValue) ? hasPreviousValue : [hasPreviousValue];
if (commandKey === "filter") value = previousValue.map((v) => ({
...v,
filters: [...v.filters, value[0]]
}));
else {
const config = getMergedAIDescriptors(previousValue, value, commandKey);
if (config.shouldContinue) continue;
value = config.descriptors;
}
}
that.dataSource[commandKey](value);
}
}
if (supportedAIGridCommands[type]) {
value = isClearValue ? [] : command[commandKey];
value = Array.isArray(value) ? value : [value];
if (commandKey === "highlight") {
that.clearHighlight();
if (!isClearValue) {
that._hasAIHighlight = value;
that._applyAIHighlight(value);
}
continue;
}
if (commandKey === "select" && enabled[type] && !command.skipCommand) {
that.clearSelection();
if (!isClearValue) {
that._hasAISelection = value;
that._applyAISelection(value);
}
continue;
}
if (commandKey === "_exportPdf" || commandKey === "_exportExcel" || commandKey === "_exportCsv") {
const responseWithRemainingCommands = { commands: commands.slice(i + 1) };
const customFileName = command.fileName;
that._changeAIExportFileName(commandKey, customFileName, true);
that[commandKey](() => {
that._changeAIExportFileName(commandKey, customFileName, false);
that.handleAIResponse(responseWithRemainingCommands);
});
break;
}
if (enabled[type]) {
const identifier = command.id;
const width = kendo.parseFloat(command.size);
const position = command.position ?? command.index;
const useIndex = commandKey === "lockColumn" || commandKey === "unlockColumn";
let colIndex;
const col = allColumns.find((col, idx) => {
if (col.uid === identifier) {
colIndex = idx;
return col;
}
});
const column = useIndex ? colIndex : col;
const isMultiColumnHeader = allColumns.length > that.columns.length;
if (column) {
let firstArgument = position ?? column;
let secondArgument = position !== undefined ? column : width;
let reorderPosition;
if (isMultiColumnHeader && commandKey === "reorderColumn") {
firstArgument = targetParentContainerIndex(allColumns, that.columns, colIndex, position);
reorderPosition = colIndex > position ? "before" : "after";
}
that[commandKey](firstArgument, secondArgument, reorderPosition);
}
}
}
}
},
getAIRequest: function(prompt) {
return getDefaultAIRequestConfig(prompt, flatColumnsInDomOrder(this.columns));
},
_changeAIExportFileName: function(commandKey, customFileName, toggle) {
const that = this;
let exportConfig;
if (commandKey === "_exportPdf") exportConfig = {
optionName: "pdf",
variableName: "_aiPdfFilename"
};
else if (commandKey === "_exportCsv") exportConfig = {
optionName: "csv",
variableName: "_aiCsvFilename"
};
else exportConfig = {
optionName: "excel",
variableName: "_aiExcelFilename"
};
if (!toggle) {
if (commandKey !== "_exportPdf" && commandKey !== "_exportExcel" && commandKey !== "_exportCsv") return;
that.options[exportConfig.optionName].fileName = that[exportConfig.variableName];
delete that[exportConfig.variableName];
return;
}
let originalName = that.options?.[exportConfig.optionName]?.fileName;
if (customFileName) {
that[exportConfig.variableName] = originalName;
that.options[exportConfig.optionName].fileName = customFileName;
}
},
_bindAIPrompt: function() {
const that = this;
const aiOptions = that.options.ai;
const aiAssistant = that._aiAssistant;
const getGenerateOutputButton = (element) => element.find("[ref-ai-apply-button]");
aiAssistant.element.on("input.kendoGrid", "[ref-prompt-input]", (e) => {
const button = getGenerateOutputButton(aiAssistant.element);
const value = $(e.currentTarget).val();
button.toggleClass("k-disabled", !value || value.trim() === "");
});
if (aiOptions?.aiAssistant?.promptSuggestions) aiAssistant.element.on("click.kendoGrid", ".k-suggestion", (e) => {
getGenerateOutputButton(aiAssistant.element).toggleClass("k-disabled", false);
});
aiAssistant.element.on("click.kendoGrid", "[ref-ai-apply-button]", () => {
const prompt = aiAssistant.element.find("[ref-prompt-input]").getKendoTextArea().value();
const promptView = aiAssistant._selectedView;
const eventArgs = {
prompt,
isRetry: false,
history: []
};
if (promptView?.service) eventArgs.service = promptView.service;
aiAssistant.trigger("promptRequest", eventArgs);
if (aiAssistant.transport) aiAssistant.transport.read({
prompt: eventArgs.prompt,
history: eventArgs.history,
isRetry: false,
service: promptView?.service
});
});
if (aiAssistant?.speechToTextButton) aiAssistant.speechToTextButton.bind("result", function() {
getGenerateOutputButton(aiAssistant.element).toggleClass("k-disabled", false);
});
},
_unbindAIPrompt: function() {
const aiAssistant = this._aiAssistant;
aiAssistant?.element?.off("input.kendoGrid");
aiAssistant?.element?.off("click.kendoGrid");
},
_prepareAIDataForSelectOrHighlight: function(value) {
const that = this;
const schema = that.dataSource.options.schema;
const idField = schema?.model?.id || "id";
const fields = schema?.model?.fields;
value = parseDate(value, fields);
return that.dataSource.parseHighlightDescriptors(value, idField);
},
_applyAIHighlight: function(value) {
const that = this;
const data = that._prepareAIDataForSelectOrHighlight(value);
that.highlight(data);
},
_applyAISelection: function(value) {
const that = this;
const data = that._prepareAIDataForSelectOrHighlight(value);
that._getElementsToSelect(data).forEach((item) => that.select(item));
},
_initAiAssistantWindow: function(cell) {
const that = this;
const aiOptions = that.options.ai;
const skipInitialization = aiOptions && aiOptions === true || aiOptions === false;
const userConfig = aiOptions?.aiAssistantWindow || {};
const customContent = userConfig?.content;
const windowOptions = {
modal: false,
resizable: false,
title: "AI Assistant",
visible: false,
actions: [
"Minimize",
"Maximize",
"Close"
],
position: {
top: outerHeight(cell) + cell.offset().top,
left: cell.offset().left + cell.outerWidth() / 2
},
width: 437,
...userConfig,
open: function(e) {
if (userConfig.open) userConfig.open(e);
if (e._defaultPrevented) return;
const ai = that._aiAssistant;
if (ai && ai.element) {
const messages = that.options.messages?.ai;
if (!ai.outputObjects.size) ai.addPromptOutput(promptPlaceholderOptions(messages));
ai.activeView("prompt");
const button = ai.element.find("[ref-ai-apply-button]");
const value = ai.element.find("[ref-prompt-input]").val();
if (that._aiAssistant) that._bindAIPrompt();
button.toggleClass("k-disabled", !value || value.trim() === "");
}
},
close: function(e) {
if (userConfig.close) userConfig.close(e);
if (e._defaultPrevented) return;
if (e.userTriggered) {
e.sender.element.trigger("focus");
var currentIndex = that.items().index($(that.current()).parent());
that._toggleToolbarEditingItemsVisibility();
if (that.options.navigatable && that.current()) {
that._setCurrent(that.items().eq(currentIndex).children().filter(NAVCELL).first());
focusTable(that.table, true);
}
}
if (that._aiAssistant) {
if (!aiOptions?.keepOutputHistory) that._aiAssistant?.clearOutput();
that._unbindAIPrompt();
}
}
};
if (!skipInitialization) {
that._aiAssistantWindow = $("<div></div>").kendoWindow(windowOptions).data("kendoWindow");
if (!customContent) that._initAiPrompt();
}
cell.bind("click.kendoGrid", function(e) {
if (!that._aiAssistantWindow) return;
if (that._aiAssistantWindow.element.is(":visible")) that._aiAssistantWindow.close();
else that._aiAssistantWindow.open();
});
},
_toolbarOptionsForTool: function(toolName) {
const options = this.options;
let toolbarItems = [];
if (Array.isArray(options.toolbar)) toolbarItems = options.toolbar;
else if (options.toolbar && options.toolbar.items) toolbarItems = options.toolbar.items;
return extend({}, defaultCommands[toolName], toolbarItems.find((item) => item.name === toolName));
},
_groupToolbarTool: function(cell) {
const that = this;
const options = that.options;
const clearGroupButton = (cell) => {
const clearGroupSelector = that._isAdaptive() ? "[ref-actionsheet-action-button]:not('.k-button-primary')" : "[ref='clear-group']";
return that._toolPopup(cell)?.find(clearGroupSelector);
};
let menu;
let menuOptions;
if (!(options.groupable && options.groupable.enabled !== false || that.dataSource._groupPaging)) return;
menu = cell.data("kendoColumnMenu");
if (menu) {
menu.wrapper.off("click.kendoGrid");
menu.element.off("click.kendoGrid");
menu.destroy();
}
const toolbarGroupOptions = that._toolbarOptionsForTool("group");
toolbarGroupOptions.reorderButtons = true;
const indicator = ({ isAdaptive, isFirstItem, isLastItem }) => `<span class="k-group-menu-item-actions">
${toolbarGroupOptions.reorderButtons ? `<span class="k-group-menu-item-action k-group-menu-item-up-action ${isFirstItem ? "k-disabled" : ""}" ${isFirstItem ? "aria-disabled=true" : "aria-disabled=false"}>
${kendo.ui.icon($("<span></span>"), {
icon: "chevron-up",
size: isAdaptive ? "large" : "medium"
})}
</span>
<span class="k-group-menu-item-action k-group-menu-item-down-action ${isLastItem ? "k-disabled" : ""}" ${isLastItem ? "aria-disabled=true" : "aria-disabled=false"}>
${kendo.ui.icon($("<span></span>"), {
icon: "chevron-down",
size: isAdaptive ? "large" : "medium"
})}
</span>` : `<span class="k-group-menu-item-action k-group-menu-item-drag-action">
${kendo.ui.icon($("<span></span>"), {
icon: "handle-drag-dots",
size: isAdaptive ? "large" : "medium"
})}
</span>`}
</span>`;
const itemTemplate = (column, action, options) => {
const isAdaptive = that._isAdaptive();
const title = column.title || column.field || "";
return `<div class="k-group-menu-item" data-field="${column.field}" data-index="${options && options.index || column.index || "0"}" tabindex="0">
${options && options.renderIndicator ? indicator({
isAdaptive,
isFirstItem: options.isFirstItem,
isLastItem: options.isLastItem
}) : ""}
<span class="k-group-item-text">${title}</span>
<span class="k-spacer"></span>
<span class="k-group-menu-item-actions">
<span class="k-group-menu-item-action ${action.actionClass}">
${kendo.ui.icon($("<span></span>"), {
...action,
size: isAdaptive ? "large" : "medium"
})}
</span>
</span>
</div>`;
};
const content = ({ columns }) => {
const isAdaptive = that._isAdaptive();
let content = `<div class="k-group-menu"><div class='k-group-menu-item-wrap'>`;
columns.forEach((column) => {
if (!isColumnGroupable(that, column) || column.command || column._originalObject.selectable) return;
content += itemTemplate(column, {
icon: "plus-circle",
actionClass: "k-group-menu-item-add-action"
});
});
content += `</div>`;
if ((!toolbarGroupOptions || toolbarGroupOptions.clearButton) && !isAdaptive) content += `<div class="k-actions k-actions-stretched k-actions-horizontal k-column-menu-footer">
${kendo.html.renderButton(`<button ref="clear-group">${defaultActionSheetFooterButtons(that.options.messages).group[0].text}</button>`, { icon: "x" })}
</div>`;
content += `</div>`;
return content;
};
menuOptions = {
dataSource: that.dataSource,
columns: false,
sortable: false,
filterable: false,
hideAutoSizeColumn: false,
owner: that,
adaptiveMode: that.options.adaptiveMode,
encodeTitles: that.options.encodeTitles,
componentType: "modern",
_actionsheet: {
actionButtons: defaultActionSheetFooterButtons(that.options.messages).group,
title: "Group by",
ref: "group-view",
closeButton: {
icon: "check",
themeColor: "primary"
}
},
init: function(e) {
const element = cell.wrapper.find(".k-group-menu");
element.attr("ref", "group-tool");
if (cell._showAdaptiveView) {
element.unwrap();
element.removeClass("k-group-menu-md").addClass("k-group-menu-lg");
} else cell.wrapper.removeClass("k-column-menu");
element.find(".k-group-menu-item").on("click.kendoGrid", `.k-group-menu-item-remove-action, .k-group-menu-item-add-action`, function(e) {
that._groupItemClickHandler(e, cell, {
itemTemplate,
indicator
});
});
that._syncGroupingTool(e, cell, that.dataSource.group(), {
itemTemplate,
indicator
});
},
closeCallback: function(e) {
e.removeClass(SELECTED);
const popupElement = that._toolPopup(cell);
if (popupElement.length) popupElement.find(".k-focus").removeClass("k-focus");
cell.element.focus();
},
contentTemplate: content
};
let oldGroups = that.dataSource.group() || [];
cell = cell.kendoColumnMenu(menuOptions).data("kendoColumnMenu");
const groupToolHandler = function(e) {
const that = this;
const cell = e.sender.wrapper && e.sender.wrapper.find(".k-grid-group-tool")?.data("kendoColumnMenu");
const groups = e.groups || that.dataSource.group() || [];
const clearButton = clearGroupButton(cell);
const groupedData = oldGroups.length > groups.length ? oldGroups : groups;
that._syncGroupingTool(e, cell, groupedData, {
itemTemplate,
indicator
});
that._toggleBadge(cell.element, groups.length > 0);
clearButton?.toggleClass("k-disabled", !groups.length);
oldGroups = groups;
};
that.unbind("group", groupToolHandler);
that.bind("group", groupToolHandler);
cell.element.on("click.kendoGrid", function(e) {
if (cell.popup && cell.popup._closing) return;
$(e.currentTarget).addClass(SELECTED);
});
cell.bind("open", function() {
const clearButton = clearGroupButton(cell);
const currentGroups = that.dataSource.group() || [];
const getWrapper = () => cell._showAdaptiveView ? that._toolPopup(cell) : cell.wrapper;
const wrapper = getWrapper();
const groupContainer = wrapper?.find("[ref='group-container']");
if (wrapper && !currentGroups.length && groupContainer && groupContainer.length && groupContainer.children().length) {
const ungroupedContainer = wrapper.find(".k-group-menu-item-wrap").not("[ref='group-container']");
groupContainer.children(".k-group-menu-item").each(function() {
const item = $(this);
item.find(".k-group-menu-item-up-action, .k-group-menu-item-down-action").parent().remove();
const removeAction = item.find(".k-group-menu-item-remove-action");
if (removeAction.length) {
removeAction.removeClass("k-group-menu-item-remove-action").addClass("k-group-menu-item-add-action");
const icon = removeAction.find("[class*='k-svg-i-']");
if (icon.length) icon.replaceWith(kendo.ui.icon($("<span></span>"), {
icon: "plus-circle",
size: that._isAdaptive() ? "large" : "medium"
}));
}
ungroupedContainer.append(item);
});
if (groupContainer.data("kendoReorderable")) groupContainer.data("kendoReorderable").destroy();
groupContainer.remove();
oldGroups = [];
}
if (clearButton.length) {
clearButton.off("mousedown.kendoGrid");
clearButton.on("mousedown.kendoGrid", function() {
that.dataSource.group([]);
that.groupable.trigger(CHANGE, { groups: [] });
that._toggleBadge(cell.element, false);
clearButton?.toggleClass("k-disabled", true);
cell.popup.close();
});
clearButton.toggleClass("k-disabled", !currentGroups.length);
}
});
},
_toggleReorderButtonsDisabledState: function(item, isFirstItem, isLastItem) {
const disabled = "k-disabled";
if (!item.length) return;
const firstReorderButton = item.find(".k-group-menu-item-actions .k-group-menu-item-up-action");
if (firstReorderButton.length) {
if (isFirstItem && !firstReorderButton.hasClass(disabled)) {
firstReorderButton.addClass(disabled);
firstReorderButton.attr("aria-disabled", true);
} else if (!isFirstItem && firstReorderButton.hasClass(disabled)) {
firstReorderButton.removeClass(disabled);
firstReorderButton.attr("aria-disabled", false);
}
const prevItem = firstReorderButton.next();
if (prevItem.length) {
if (isLastItem && !prevItem.hasClass(disabled)) {
prevItem.addClass(disabled);
prevItem.attr("aria-disabled", true);
} else if (!isLastItem && prevItem.hasClass(disabled)) {
prevItem.removeClass(disabled);
prevItem.attr("aria-disabled", false);
}
}
}
},
_syncGroupingTool: function(ev, cell, groupedData, templates) {
const that = this;
const groups = ev.groups || that.dataSource.group() || [];
const getWrapper = () => cell._showAdaptiveView ? that._toolPopup(cell) : cell.wrapper;
const containerClass = "k-group-menu-item-wrap";
const findContainers = () => getWrapper()?.find(`.${containerClass}`);
const wrapper = getWrapper();
let containers = findContainers();
if (cell._draggableInstance && cell._triggeredReordering) {
delete cell._triggeredReordering;
return;
}
if (containers && containers.length) {
groupedData.forEach((group, i) => {
const item = wrapper.find(`.k-group-menu-item[data-field='${group.field}']`);
const index = item.data("index");
const action = item.find(".k-group-menu-item-add-action").length ? "remove" : "add";
const shouldAdd = action === "remove";
const actionClass = `k-group-menu-item-${action}-action`;
const parentContainer = item.parent();
containers = findContainers();
let isFirstItem = groups && groups.length ? groups[0]?.field === group.field : false;
let isLastItem = groups && groups.length ? groups[groups.length - 1].field === group.field : false;
that._toggleReorderButtonsDisabledState(item, isFirstItem, isLastItem);
const isRemoveAction = !groups.find((descriptor) => descriptor.field === group.field);
if (!isRemoveAction && parentContainer.is("[ref='group-container']")) return;
let container;
if (containers && containers.length === 2) container = shouldAdd ? containers.first() : containers.last();
else {
container = $(`<div class="${containerClass}" ${shouldAdd ? "ref=\"group-container" : ""}"></div>`);
const method = shouldAdd ? "prepend" : "append";
const containersWrapper = containers.first().parent();
const clearBtn = containersWrapper.find("[ref='clear-group']");
if (clearBtn.length && !shouldAdd) clearBtn.parent().before(container);
else if (containersWrapper.length) containersWrapper[method](container);
}
const column = leafColumns(that.columns)[index];
const shouldAddDragIndicator = !isRemoveAction && groups.length > 1;
const templateOptions = {
renderIndicator: shouldAddDragIndicator,
index,
isFirstItem,
isLastItem
};
const groupedItem = $(templates.itemTemplate(column, {
icon: shouldAdd ? "x-circle" : "plus-circle",
actionClass
}, templateOptions));
item.remove();
if (containers.length === 2 && !parentContainer.children().length) {
if (parentContainer.data("kendoReorderable")) parentContainer.data("kendoReorderable")?.destroy();
parentContainer.remove();
}
if (shouldAdd) {
if (shouldAddDragIndicator) {
const firstItem = container.children().first();
if (firstItem.find(".k-group-menu-item-actions")?.length === 1) firstItem.prepend(templates.indicator({
isAdaptive: that._isAdaptive(),
isFirstItem: true,
isLastItem: false
}));
}
container.append(groupedItem);
} else {
const nextItem = container.find(`.k-group-menu-item[data-index="${index + 1}"]`);
if (groups.length === 1) parentContainer.children().first().find(".k-group-menu-item-actions:first-of-type").remove();
if (nextItem.length) nextItem.before(groupedItem);
else container.append(groupedItem);
}
container.find(groupedItem).on("click.kendoGrid", `.k-group-menu-item-remove-action, .k-group-menu-item-add-action`, function(e) {
that._groupItemClickHandler(e, cell);
});
});
containers = findContainers();
if (containers && containers.length) {
const dragIndicators = containers.first().find(".k-group-menu-item-drag-action");
const reorderButtons = containers.first().find(".k-group-menu-item-up-action, .k-group-menu-item-down-action");
const container = containers.first();
const hasContainer = container.is("[ref='group-container']");
const initDragInstance = dragIndicators.length;
const initButtonsReordering = reorderButtons.length;
if (hasContainer && initButtonsReordering) reorderButtons.each(function() {
const button = $(this);
button.unbind("click.kendoGrid");
button.bind("click.kendoGrid", (e) => that._buttonClickReorderHandler(e, cell));
});
else if (hasContainer && initDragInstance) {
that._groupToolDraggableInstance(cell, container);
that._groupToolReorderableInstance(cell, container);
}
}
}
},
_buttonClickReorderHandler: function(e, cell) {
e.preventDefault();
e.stopPropagation();
const that = this;
const itemSelector = ".k-group-menu-item";
const clicked = $(e.currentTarget);
const element = clicked.closest(itemSelector);
const position = clicked.hasClass("k-group-menu-item-up-action") ? "before" : "after";
const evData = {
element,
target: position === "before" ? element.prev(itemSelector) : element.next(itemSelector),
position
};
that._handleGroupReordering(evData, cell);
},
_groupToolDraggableInstance: function(cell, container) {
const isMobile = this._isMobile;
cell._draggableInstance = container.kendoDraggable({
holdToDrag: isMobile,
showHintOnHold: isMobile,
preventOsHoldFeatures: isMobile,
group: "group-item-draggable",
autoScroll: true,
filter: ".k-group-menu-item-drag-action",
hint: function(target) {
return $("<div class=\"k-reorder-clue k-drag-clue\">" + kendo.ui.icon({
icon: "cancel",
iconClass: "k-drag-status"
}) + "</div>");
},
clickMoveClick: false,
cursorOffset: {
top: 0,
left: 0
}
}).data("kendoDraggable");
},
_groupToolReorderableInstance: function(cell, container) {
const that = this;
const itemSelector = ".k-group-menu-item";
if (container && container.data("kendoReorderable")) container.data("kendoReorderable").destroy();
container.kendoReorderable({
smartPosition: false,
draggable: cell._draggableInstance,
dragOverContainers: function(sourceIndex, targetIndex) {
var result = true;
$(itemSelector).eq(targetIndex);
return result;
},
dropFilter: "> .k-group-menu-item",
allowIcon: "insert-middle",
orientation: "vertical",
reorderDropCue: $("<div class=\"k-drop-hint k-drop-hint-h\"><div class=\"k-drop-hint-start\"></div><div class=\"k-drop-hint-line\"></div></div>"),
positionDropCue: function(reorderDropCue) {
reorderDropCue.css({ transform: "translate(0,-50%)" });
},
externalDraggable: function(e) {
var draggable = e.draggable;
if (draggable) return draggable;
},
change: function(e) {
that._handleGroupReordering(e, cell);
}
});
},
_handleGroupReordering: function(e, cell) {
const element = e.element;
const newSibling = e.target;
const method = e.position === "before" ? "insertBefore" : "insertAfter";
const descriptors = this.groupable.descriptors();
element[method](newSibling);
const items = element.parent().children();
const newDescriptors = [];
for (let i = 0; i < items.length; i++) {
const field = $(items[i]).data("field");
const descriptor = descriptors.find((d) => d.field === field);
if (descriptor) newDescriptors.push(descriptor);
}
cell._triggeredReordering = true;
this.dataSource.group(newDescriptors);
this.groupable.trigger(CHANGE, { groups: newDescriptors });
},
_groupItemClickHandler: function(e, cell) {
const that = this;
const item = $(e.currentTarget).closest(".k-group-menu-item");
const shouldAdd = ($(e.currentTarget).find(".k-icon")?.attr("class").includes("plus-circle") ? "remove" : "add") === "remove";
const index = item.data("index");
let descriptors = that.groupable.descriptors();
if (!descriptors.length) descriptors = that.dataSource.group();
const column = leafColumns(that.columns)[index];
if (shouldAdd) descriptors.push({
field: column.field,
dir: "asc",
aggregates: that.groupable.aggregates() || [],
colID: column.uid,
compare: column.sortable && column.sortable.compare || that.groupable.sort && that.groupable.sort.compare
});
else descriptors = descriptors.filter((descriptor) => descriptor.field !== column.field);
that.dataSource.group(descriptors);
that.groupable.trigger(CHANGE, { groups: descriptors });
},
_sortToolbarTool: function(cell) {
const that = this;
const options = that.options;
const selectorClass = "k-columnmenu-indicators";
const isAdaptive = that._isAdaptive();
const clearSortButton = (cell) => {
const clearSortSelector = that._isAdaptive() ? "[ref-actionsheet-action-button]:not('.k-button-primary')" : "[ref='clear-sort']";
return that._toolPopup(cell)?.find(clearSortSelector);
};
let menu;
let menuOptions;
const toolbarSortOptions = that._toolbarOptionsForTool("sort");
menu = cell.data("kendoColumnMenu");
if (menu) {
menu.wrapper.off("click.kendoGrid");
menu.element.off("click.kendoGrid");
menu.destroy();
}
function content({ columns, isAdaptive }) {
let content = `<div class="k-columnmenu-item-wrapper">`;
columns.forEach((column) => {
if (column.sortable === false || column.command || column._originalObject.draggable || column._originalObject.selectable) return;
content += `<div class="k-columnmenu-item" tabindex="0" data-field="${column.field}">${column.title || column.field || ""}</div>`;
});
content += "</div>";
if ((!toolbarSortOptions || toolbarSortOptions.clearButton) && !isAdaptive) {
content += `<div class="k-actions k-actions-stretched k-actions-horizontal k-column-menu-footer">`;
content += kendo.html.renderButton(`<button ref="clear-sort">${defaultActionSheetFooterButtons(that.options.messages).sort[0].text}</button>`, { icon: "x" });
content += "</div>";
}
return content;
}
const sortable = options.columnMenu.sortable !== false && options.sortable !== false ? extend({}, options.sortable, { allowUnsort: false }) : false;
if (!sortable) return;
menuOptions = {
dataSource: that.dataSource,
columns: false,
sortable,
filterable: false,
hideAutoSizeColumn: true,
owner: that,
adaptiveMode: that.options.adaptiveMode,
encodeTitles: that.options.encodeTitles,
componentType: "modern",
_actionsheet: {
actionButtons: defaultActionSheetFooterButtons(that.options.messages).sort,
title: "Sort by",
ref: "sort-view",
closeButton: {
icon: "check",
themeColor: "primary"
}
},
init: function(e) {
cell.wrapper.attr("ref", "sort-tool");
},
closeCallback: function(e) {
e.removeClass(SELECTED);
const popupElement = that._toolPopup(cell);
if (popupElement.length) popupElement.find(".k-focus").removeClass("k-focus");
cell.element.focus();
},
sort: function(e) {
const preventClose = e.preventClose;
cell._preventClose = that.options.sortable.mode === "multiple" || preventClose;
if (that.trigger("sort", { sort: e.sort })) e.preventDefault();
else {
that._clearEditableState();
if (that.dataSource.options.endless) that._resetEndless();
}
},
contentTemplate: content
};
cell = cell.kendoColumnMenu(menuOptions).data("kendoColumnMenu");
const sortToolHandler = function(e) {
const cell = e.sender.wrapper && e.sender.wrapper.find(".k-grid-sort-tool")?.data("kendoColumnMenu");
const sortFields = e.sender.dataSource._sortFields;
const isArray = Array.isArray(e.sort);
const field = e.sort.field;
const isMultiSortingEnabled = e.sender.options.sortable && (e.sender.options.sortable.mode === "multiple" || e.sender.options.sortable.mode === "mixed");
let condition;
let isUnsortEvent = e.sort.dir === undefined;
if (isArray) condition = e.sort.length;
else if (sortFields && Object.keys(sortFields).length) condition = !isUnsortEvent || isUnsortEvent && Object.keys(sortFields).length - 1 > 0;
else condition = !isUnsortEvent;
that._toggleBadge(cell.element, condition);
const element = cell.wrapper.find(`.k-columnmenu-item[data-field='${field}']`);
let indicatorsWrapper = element.find(".k-columnmenu-indicators");
if (isUnsortEvent) indicatorsWrapper.remove();
else {
if (!isMultiSortingEnabled) indicatorsWrapper = cell.wrapper.find(".k-columnmenu-indicators");
if (indicatorsWrapper.length) indicatorsWrapper.remove();
element.append(that._renderIndicator(`sort-${e.sort.dir}-small`));
}
clearSortButton(cell)?.toggleClass("k-disabled", !condition);
};
that.unbind("sort", sortToolHandler);
that.bind("sort", sortToolHandler);
cell.bind("open", function() {
const popupElement = that._toolPopup(cell);
if (popupElement.length) {
popupElement.focus();
const clearSortBtn = clearSortButton(cell);
const items = popupElement.find(".k-columnmenu-item");
if (clearSortBtn.length) {
clearSortBtn.off("mousedown.kendoGrid");
clearSortBtn.on("mousedown.kendoGrid", function() {
that.dataSource.sort([]);
that._toggleBadge(cell.element, false);
clearSortButton(cell)?.toggleClass("k-disabled", true);
cell.wrapper.find(".k-columnmenu-indicators").remove();
cell.close();
});
}
if (items.length) {
popupElement.off("click.kendoGrid");
popupElement.on("click.kendoGrid", ".k-columnmenu-item", function(e) {
const currentTarget = $(e.currentTarget);
const field = currentTarget.data("field");
const unsort = that._toggleColumnMenuSortIndicator(currentTarget);
const isMixed = that.options.sortable && that.options.sortable.mode === "mixed";
const hasCtrlKey = e.originalEvent.ctrlKey;
cell.field = field;
cell._sortHandler({
item: currentTarget,
allowUnsort: unsort,
allowSelectedState: false,
isMixed,
hasCtrlKey
});
that._toggleSortIndexes(that.dataSource._sortFields && Object.keys(that.dataSource._sortFields).length > 1, cell, selectorClass);
});
}
}
});
cell.element.on("click.kendoGrid", function(e) {
if (cell.popup && cell.popup._closing) return;
$(e.currentTarget).addClass(SELECTED);
const sortFields = cell.dataSource._sortFields;
const condition = sortFields && Object.keys(sortFields).length;
const shouldRenderIndexes = Object.keys(sortFields).length > 1;
if (condition) Object.keys(sortFields).forEach((sortField) => {
const element = cell.wrapper.find(`.k-columnmenu-item[data-field='${sortField}']`);
const indicator = element.find(".k-columnmenu-indicators");
if (indicator.length) indicator.remove();
element.append(that._renderIndicator(`sort-${sortFields[sortField].dir}-small`));
});
that._toggleSortIndexes(shouldRenderIndexes, cell, selectorClass, isAdaptive);
clearSortButton(cell)?.toggleClass("k-disabled", !condition);
});
},
_toggleSortIndexes: function(condition, cell, selector) {
const that = this;
if (!(that.options.sortable && that.options.sortable.showIndexes)) return;
const indicators = cell.wrapper.find(`.${selector}`);
let sortFields = cell.dataSource && cell.dataSource._sortFields;
if (!indicators.length) return;
if (condition) indicators.each((index, indicator) => {
const field = $(indicator).closest(".k-columnmenu-item").data("field");
const sortField = sortFields[field];
const sortIndex = $(indicator).parent().find(".k-sort-index");
if (!sortIndex.length) if (sortField.index) $(indicator).append(`<span class='k-sort-index'>${sortField.index}</span>`);
else $(indicator).append(`<span class='k-sort-index'>${index + 1}</span>`);
else sortIndex.text(sortField.index);
});
else cell.wrapper.find(".k-sort-index").remove();
},
_columnChooserTool: function(cell) {
const that = this;
const templateRef = "column-chooser";
function content(config) {
const template = config._defaultContents()[templateRef];
return template(config);
}
const menu = cell.data("kendoColumnMenu");
if (menu) {
menu.wrapper.off("click.kendoGrid");
menu.element.off("click.kendoGrid");
menu.destroy();
}
const menuOptions = {
dataSource: that.dataSource,
columns: true,
sortable: false,
filterable: false,
hideAutoSizeColumn: true,
owner: that,
adaptiveMode: that.options.adaptiveMode,
encodeTitles: that.options.encodeTitles,
messages: {
reset: that.options.messages.clearButtons ? that.options.messages.clearButtons.columnChooserReset : "Reset",
apply: that.options.messages.applyButtons ? that.options.messages.applyButtons.columnChooserApply : "Apply"
},
componentType: "modern",
contentTemplate: content,
_actionsheet: {
actionButtons: defaultActionSheetFooterButtons(that.options.messages)[templateRef],
title: "Column visibility",
subtitle: "Selected fields are visible",
closeButton: true,
ref: `${templateRef}-view`
},
init: function(e) {
cell.wrapper.attr("ref", "column-chooser-tool");
if (cell._showAdaptiveView) cell.popup._content.find(`[ref='${templateRef}']`).unwrap();
else cell.wrapper.removeClass("k-column-menu");
},
closeCallback: function(e) {
e.removeClass(SELECTED);
const popupElement = that._toolPopup(cell);
if (popupElement.length) popupElement.find(".k-focus").removeClass("k-focus");
if (cell && cell._showAdaptiveView) cell._applyColumnVisibility();
cell.element.focus();
}
};
cell = cell.kendoColumnMenu(menuOptions).data("kendoColumnMenu");
cell.element.bind("click", function(e) {
if (cell.popup && cell.popup._closing) return;
$(e.currentTarget).addClass(SELECTED);
});
cell.bind("open", function() {
const popupElement = that._toolPopup(cell);
if (popupElement.length) popupElement.find(".k-checkbox")?.first()?.focus();
});
},
_toggleBadge: function(cell, condition) {
const badgeContainer = cell.closest(`.k-badge-container`);
const badge = badgeContainer.length && badgeContainer.find(".k-badge");
const overflowProp = cell.data("overflow");
if (!badge.length && condition) cell.wrap(`<div class='k-badge-container' ${overflowProp ? "data-overflow=" + overflowProp : ""}></div>`).parent().append($("<span></span>").kendoBadge({
round: "full",
position: "edge",
align: "top end",
themeColor: "primary",
cutoutBorder: true
}));
else if (!condition && badge.length) {
badge.remove();
cell.unwrap(".k-badge-container");
}
},
_toggleColumnMenuFilterIndicator: function(element, condition) {
const that = this;
const indicatorWrapper = element.find(".k-columnmenu-indicators");
const spacer = element.find(".k-spacer");
if (condition && spacer.length) {
if (indicatorWrapper && indicatorWrapper.length) return;
spacer.before(that._renderIndicator("filter"));
} else if (indicatorWrapper && indicatorWrapper.length) indicatorWrapper.remove();
},
_toggleColumnMenuSortIndicator: function(element) {
const that = this;
const indicatorWrapper = element.find(".k-columnmenu-indicators");
const sortIndex = element.find(".k-sort-index");
let unsort;
let action = !sortIndex.length ? "append" : "before";
if (indicatorWrapper && indicatorWrapper.length) {
const indicator = indicatorWrapper.find(".k-icon");
if (indicator.length && indicatorWrapper.attr("data-sort-dir") === "desc") {
indicatorWrapper.remove();
unsort = true;
} else {
indicator.remove();
indicatorWrapper[action](that._renderIndicator("sort-desc-small"));
unsort = false;
}
} else {
element[action](that._renderIndicator("sort-asc-small"));
unsort = false;
}
return unsort;
},
_renderIndicator: function(icon) {
let sortDir = "";
if (icon === "sort-asc-small") sortDir = "asc";
else if (icon === "sort-desc-small") sortDir = "desc";
const indicator = $("<span></span>");
if (sortDir) indicator.attr("ref", `sort-${sortDir}`);
return $("<span class='k-columnmenu-indicators'></span>").attr("data-sort-dir", sortDir).append(kendo.ui.icon(indicator, { icon }));
},
_globalColumnsMenu: function(cell) {
var that = this, menu, columns = leafColumns(that.columns), columnMenu = that.options.columnMenu, menuOptions, initCallback = function(e) {
if (that._isAdaptive()) e.sender.popup.wrapper.find(".k-expanded [ref=columns-visibility]").data("handler").toggle(false);
that.trigger(COLUMNMENUINIT, {
field: e.field,
container: e.container
});
}, openCallback = function(e) {
that.trigger(COLUMNMENUOPEN, {
field: e.field,
container: e.container
});
}, closeCallback = function() {
cell.trigger("focus");
};
if (columnMenu) {
if (typeof columnMenu == "boolean") columnMenu = {};
that._setColumnsMediaVisibility(columns);
let toggleable = !!(columnMenu.autoSize || columnMenu.clearAllFilters);
menu = cell.data("kendoColumnMenu");
if (menu) menu.destroy();
let columnsExpanderOptions = {
toggleable,
expanded: columnMenu.expanded || true,
animation: false,
hideExpanderIndicator: !toggleable
};
menuOptions = {
dataSource: that.dataSource,
columns: columnMenu.columns,
sortable: false,
filterable: false,
clearAllFilters: columnMenu.clearAllFilters,
messages: columnMenu.messages,
hideAutoSizeColumn: true,
owner: that,
closeCallback,
init: initCallback,
open: openCallback,
pane: that.options.adaptiveMode !== "auto" && that.pane,
autoSize: columnMenu.autoSize,
encodeTitles: that.options.encodeTitles,
componentType: "modern",
adaptiveMode: "auto",
columnsExpanderOptions
};
cell.kendoColumnMenu(menuOptions);
}
},
_columnMenu: function() {
var that = this, menu, columns = leafColumns(that.columns), column, options = that.options, columnMenu = options.columnMenu, menuOptions, sortable, filterable, cells, hasMultiColumnHeaders = grep(that.columns, function(item) {
return item.columns !== undefined;
}).length > 0, hasLockableColumns = grep(that.columns, function(item) {
return item.lockable !== false;
}).length > 0, hasStickableColumns = grep(that.columns, function(item) {
return item.stickable === true;
}).length > 0, isMobile = this._isMobile, initCallback = function(e) {
that.trigger(COLUMNMENUINIT, {
field: e.field,
container: e.container
});
}, openCallback = function(e) {
that.trigger(COLUMNMENUOPEN, {
field: e.field,
container: e.container
});
}, closeCallback = function() {
focusTable(that.table, true);
}, stickCallback = function(e) {
that.trigger(COLUMNSTICK, { column: e.column });
}, unstickCallback = function(e) {
that.trigger(COLUMNUNSTICK, { column: e.column });
}, sortHandler = function(e) {
if (that.trigger("sort", { sort: e.sort })) e.preventDefault();
else {
that._clearEditableState();
if (that.dataSource.options.endless) that._resetEndless();
}
}, filterHandler = function(e) {
if (that.trigger("filter", {
filter: e.filter,
field: e.field
})) e.preventDefault();
else {
that._clearEditableState();
if (that.dataSource.options.endless) that._resetEndless();
}
};
if (columnMenu && !that._isStackedMode()) {
if (typeof columnMenu == "boolean") columnMenu = {};
that._setColumnsMediaVisibility(columns);
cells = leafDataCells(that.thead);
for (var idx = 0, length = cells.length; idx < length; idx++) {
column = columns[idx];
var cell = cells.eq(idx);
if (column.columnMenu !== false && !column.command && (column.field || cell.attr("data-" + kendo.ns + "field"))) {
menu = cell.data("kendoColumnMenu");
if (menu) menu.destroy();
sortable = column.sortable !== false && columnMenu.sortable !== false && options.sortable !== false ? extend({}, options.sortable, { compare: (column.sortable || {}).compare }) : false;
filterable = options.filterable && column.filterable !== false && columnMenu.filterable !== false ? extend(true, { pane: that.pane }, options.filterable, column.filterable) : false;
if (column.filterable && column.filterable.dataSource) {
filterable.forceUnique = false;
filterable.checkSource = column.filterable.dataSource;
}
if (filterable) filterable.format = column.format;
const isAdaptive = that.options.adaptiveMode !== "auto" ? columnMenu.adaptiveMode || that.options.adaptiveMode : that.options.adaptiveMode;
menuOptions = {
dataSource: that.dataSource,
values: column.values,
columns: columnMenu.columns,
sortable,
filterable,
messages: columnMenu.messages,
owner: that,
adaptiveMode: isAdaptive,
adaptiveTitle: column.title || column.field,
closeCallback,
init: initCallback,
open: openCallback,
stick: stickCallback,
unstick: unstickCallback,
pane: that.options.adaptiveMode !== "auto" && that.pane,
sort: sortHandler,
filtering: filterHandler,
filter: isMobile ? ":not(.k-column-active)" : "",
autoSize: columnMenu.autoSize,
hasLockableColumns: lockedColumns(columns).length > 0 && hasLockableColumns && !hasMultiColumnHeaders,
hasStickableColumns: hasStickableColumns && !hasMultiColumnHeaders,
encodeTitles: that.options.encodeTitles,
componentType: columnMenu.componentType,
appendTo: DOT + classNames.headerCellInner,
reorderable: options.reorderable === true || options.reorderable && options.reorderable.columns,
groupable: that.options.groupable && that.options.groupable.enabled !== false && column.groupable !== false
};
cell.kendoColumnMenu(menuOptions);
}
}
}
},
_headerCells: function() {
return $(this.thead).find("th").filter(function() {
var th = $(this);
return !th.hasClass("k-group-cell") && !th.hasClass("k-hierarchy-cell");
});
},
_hasFilterMenu: function() {
var filterable = this.options.filterable;
if (filterable && typeof filterable.mode == STRING && filterable.mode.indexOf("menu") == -1) return false;
return filterable;
},
_filterable: function() {
var that = this, columns = leafColumns(that.columns), filterMenu, cells, cell, filterInit = function(e) {
that.trigger(FILTERMENUINIT, {
field: e.field,
container: e.container
});
}, closeCallback = function() {
focusTable(that.table, true);
}, filterHandler = function(e) {
if (that.trigger("filter", {
filter: e.filter,
field: e.field
})) e.preventDefault();
else {
that._clearEditableState();
if (that.dataSource.options.endless) that._resetEndless();
}
}, filterOpen = function(e) {
that.trigger(FILTERMENUOPEN, {
field: e.field,
container: e.container
});
}, filterable = that._hasFilterMenu();
if (filterable && !that.options.columnMenu && !that._isStackedMode()) {
cells = leafDataCells(that.thead);
for (var idx = 0, length = cells.length; idx < length; idx++) {
cell = cells.eq(idx);
if (columns[idx].filterable !== false && !columns[idx].command && (columns[idx].field || cell.attr("data-" + kendo.ns + "field"))) {
filterMenu = cell.data("kendoFilterMenu");
if (filterMenu) filterMenu.destroy();
filterMenu = cell.data("kendoFilterMultiCheck");
if (filterMenu) filterMenu.destroy();
var columnFilterable = columns[idx].filterable;
var options = extend({}, filterable, columnFilterable, {
dataSource: that.dataSource,
values: columns[idx].values,
format: columns[idx].format,
closeCallback,
title: columns[idx].title || columns[idx].field,
init: filterInit,
open: filterOpen,
pane: that.pane,
change: filterHandler,
appendTo: DOT + classNames.headerCellInner,
adaptiveMode: that.options.adaptiveMode
});
if (columnFilterable && columnFilterable.messages) options.messages = extend(true, {}, filterable.messages, columnFilterable.messages);
if (columnFilterable && columnFilterable.dataSource) {
options.forceUnique = false;
options.checkSource = columnFilterable.dataSource;
}
if (columnFilterable && columnFilterable.multi) cell.kendoFilterMultiCheck(options);
else cell.kendoFilterMenu(options);
}
}
}
},
_filterRow: function() {
var that = this;
if (!that._hasFilterRow()) return;
var settings;
var columns = leafColumns(that.columns), filterable = that.options.filterable, rowheader = that.thead.find(".k-filter-row"), filterHandler = function(e) {
if (that.trigger("filter", {
filter: e.filter,
field: e.field
})) e.preventDefault();
else {
that._clearEditableState();
if (that.dataSource.options.endless) that._resetEndless();
}
};
this._updateHeader(that._groups());
for (var i = 0; i < columns.length; i++) {
var suggestDataSource, col = columns[i], operators = that.options.filterable.operators, customDataSource = false, td = $("<td class='k-table-td' title='" + that.options.messages.filterCellTitle + "'/>"), field = col.field;
if (col.hidden) td.hide();
rowheader.append(td);
if (field && col.filterable !== false) {
var cellOptions = col.filterable && col.filterable.cell || {};
suggestDataSource = that.options.dataSource;
if (suggestDataSource instanceof DataSource) suggestDataSource = that.options.dataSource.options;
var messages = extend(true, {}, filterable.messages);
if (col.filterable) extend(true, messages, col.filterable.messages);
if (cellOptions.enabled === false) {
td.html(" ");
continue;
}
if (cellOptions.dataSource) {
suggestDataSource = cellOptions.dataSource;
customDataSource = true;
}
if (col.filterable && col.filterable.operators) operators = col.filterable.operators;
settings = {
column: col,
dataSource: that.dataSource,
suggestDataSource,
customDataSource,
field,
messages,
size: that.options.size,
values: col.values,
template: cellOptions.template,
delay: cellOptions.delay,
inputWidth: cellOptions.inputWidth,
suggestionOperator: cellOptions.suggestionOperator,
minLength: cellOptions.minLength,
dataTextField: cellOptions.dataTextField,
operator: cellOptions.operator,
operators,
showOperators: cellOptions.showOperators,
change: filterHandler,
adaptiveMode: that.options.adaptiveMode
};
$("<span/>").attr(kendo.attr("field"), field).appendTo(td).kendoFilterCell(settings);
} else td.html(" ");
td.data("column", col);
}
this._filterFocusable().attr(TABINDEX, -1);
},
_sortable: function() {
var that = this, columns = leafColumns(that.columns), column, sorterInstance, cell, sortable = that.options.sortable, sortHandler = function(e) {
if (that.trigger("sort", { sort: e.sort })) e.preventDefault();
else that._clearEditableState();
};
if (sortable && !that._isStackedMode()) {
var cells = leafDataCells(that.thead);
for (var idx = 0, length = cells.length; idx < length; idx++) {
column = columns[idx];
if (column.sortable !== false && !column.command && column.field) {
cell = cells.eq(idx);
sorterInstance = cell.data("kendoColumnSorter");
if (sorterInstance) sorterInstance.destroy();
cell.attr("data-" + kendo.ns + "field", column.field).kendoColumnSorter(extend({}, sortable, column.sortable, {
dataSource: that.dataSource,
aria: true,
filter: ":not(.k-column-active)",
change: sortHandler
}));
}
}
cells = null;
}
},
_columns: function(columns) {
var that = this, table = that.table, encoded, cols = table.find("col"), lockedCols, headerRows = that.element.find("thead tr"), dataSource = that.options.dataSource, draggableColumns;
columns = columns.length ? columns : map(table.find("th:not(.k-group-cell):not(.k-hierarchy-cell)"), function(th, idx) {
th = $(th);
var sortable = th.attr(kendo.attr("sortable")), filterable = th.attr(kendo.attr("filterable")), type = th.attr(kendo.attr("type")), groupable = th.attr(kendo.attr("groupable")), field = th.attr(kendo.attr("field")), title = th.attr(kendo.attr("title")), columnMenu = th.attr(kendo.attr("column-menu")), menu = th.attr(kendo.attr("menu"));
if (!field) field = th.text().replace(/\s|[^A-z0-9]/g, "");
return {
field,
type,
title,
sortable: sortable !== "false",
filterable: filterable !== "false",
groupable: groupable !== "false",
menu: menu !== "false",
columnMenu: columnMenu !== "false",
template: th.attr(kendo.attr("template")),
width: cols.eq(idx).css(WIDTH)
};
});
encoded = !(that.table.find("tbody tr").length > 0 && (!dataSource || !dataSource.transport));
if (that.options.scrollable && !that._isStackedMode()) {
var initialColumns = columns;
lockedCols = lockedColumns(columns);
columns = nonLockedColumns(columns);
if (lockedCols.length > 0 && columns.length === 0) throw new Error("There should be at least one non locked column");
normalizeHeaderCells(that.element.find("tr:has(th)").first(), initialColumns);
columns = lockedCols.concat(columns);
}
if (headerRows.length && columns.length) that._updateColumnIDs(columns, headerRows.first());
that.columns = normalizeColumns(columns, encoded);
if ($.grep(leafColumns(that.columns), function(col) {
return col.selectable;
}).length) {
that._selectedIds = {};
that._checkBoxSelection = true;
that.wrapper.on("click.kendoGrid", "tbody > tr input[data-role='checkbox'].k-select-checkbox.k-checkbox", that._checkboxClick.bind(that));
that.wrapper.on("click.kendoGrid", "thead > tr input[data-role='checkbox'].k-select-checkbox.k-checkbox", that._headerCheckboxClick.bind(that));
}
draggableColumns = $.grep(leafColumns(that.columns), function(col) {
return col.draggable;
});
if (draggableColumns.length) {
that._hasDragHandleColumn = true;
for (var i = 0; i < draggableColumns.length; i++) draggableColumns[i].headerAttributes = $.extend({ "aria-label": that.options.messages.dragHandleLabel }, draggableColumns[i].headerAttributes);
}
if ($.grep(leafColumns(that.columns), function(col) {
return col.pinnable;
}).length) that._initPinColumn();
that._foreignKeyBindings(flatColumns(that.columns));
},
_foreignKeyBindings: function(columns) {
var that = this;
var length = columns.length;
var column;
for (var i = 0; i < length; i++) {
column = columns[i];
if (column.dataSource) that._fetchForeignKeyValues(column);
}
},
_fetchForeignKeyValues: function(column) {
var that = this;
var promise = $.Deferred();
that._hasBoundForeignKey = true;
column.dataSource = DataSource.create(column.dataSource);
if (!that._foreignKeyPromises) that._foreignKeyPromises = [];
that._foreignKeyPromises.push(promise);
column.dataSource.fetch().then(function() {
column.values = column.dataSource.data().map(function(item) {
return {
value: item[column.dataValueField],
text: item[column.dataTextField]
};
});
promise.resolve();
});
},
_updateColumnIDs: function(columns, tr) {
if (!columns.length) return;
var ths = tr.find("th:not(.k-group-cell):not(.k-hierarchy-cell)");
var id;
for (var i = 0; i < columns.length; i++) {
id = ths.eq(i).attr(ID);
if (id) columns[i].headerAttributes = extend(columns[i].headerAttributes, { id });
}
this._updateColumnIDs(childColumns(columns), tr.next());
},
_headerCheckboxClick: function(e) {
var that = this, checkBox = $(e.target), checked = checkBox.prop("checked");
if (!that._belongsToGrid(checkBox)) return;
if (that.trigger(CHANGING, {
target: checkBox,
originalEvent: e
})) {
e.preventDefault();
return;
}
if (checked) that.select(that.items());
else that.clearSelection();
that._calculateAggregatesForSelected();
that.trigger(CHANGE, { cellAggregates: that._cellAggregates });
},
_checkboxClick: function(e) {
var that = this, row = $(e.target).closest(TR), isSelecting = !row.hasClass(SELECTED);
if (!that._belongsToGrid(row)) return;
if (that.trigger(CHANGING, {
target: row,
originalEvent: e
})) {
e.preventDefault();
return;
}
if (isSelecting) that.select(row);
else that._deselectCheckRows(row);
that._calculateAggregatesForSelected();
that.trigger(CHANGE, { cellAggregates: that._cellAggregates });
},
_groups: function() {
var group = this.dataSource.group();
return group ? group.length : 0;
},
_getStackedLayoutSettings: function() {
const layoutSetting = this.options.stackedLayoutSettings;
const stackedColsConfig = layoutSetting && layoutSetting.cols;
let config = [];
let colClass = "";
if (stackedColsConfig) {
if (Array.isArray(stackedColsConfig)) {
for (let i = 0; i < stackedColsConfig.length; i++) if (typeof stackedColsConfig[i] === "object") {
const width = stackedColsConfig[i].width;
if (!width && width !== 0) continue;
if (typeof width === "number") config.push(`${width}px`);
if (typeof width === "string") config.push(width);
} else if (typeof stackedColsConfig[i] === "number") config.push(`${stackedColsConfig[i]}px`);
else if (typeof stackedColsConfig[i] === "string") config.push(stackedColsConfig[i]);
} else if (typeof stackedColsConfig === "number") colClass = `k-grid-cols-${stackedColsConfig}`;
}
return {
colClass,
colsConfig: config.join(" ")
};
},
_tmpl: function(rowTemplate, columns, alt, skipGroupCells) {
var that = this, settings = extend({}, kendo.Template, that.options.templateSettings), idx, length = columns.length, state = {
storage: {},
count: 0
}, column, hasDetails = that._hasDetails(), groups = that._groups();
var fieldAttr = kendo.attr("field");
var field;
var classAttribute;
var compiledAttributes;
let rowTemplateFunc;
if (!rowTemplate) {
rowTemplateFunc = (data) => {
var uid = length ? ` ${kendo.attr("uid")}="${kendo.getter("uid")(data)}"` : "";
var rowTemplateResult = `<tr class="${alt ? "k-table-row k-table-alt-row " : "k-table-row "}k-master-row"${uid}>`;
if (groups > 0 && !skipGroupCells) rowTemplateResult += groupCells(groups);
if (hasDetails) rowTemplateResult += "<td class=\"k-hierarchy-cell k-table-td\" aria-expanded=\"false\">" + kendo.ui.icon($(`<a ref-grid-expand-detail href="#" ${ARIA_LABEL}="${EXPAND}" tabindex="-1"></a>`), { icon: `chevron-${isRtl ? "left" : "right"}` }) + "</td>";
for (idx = 0; idx < length; idx++) {
column = columns[idx];
column.template;
field = column.field;
compiledAttributes = {};
let dirtyCellTemplate;
if (that._editMode() && field) {
column.attributes = column.attributes || {};
if (that.virtualScroll) column.attributes[fieldAttr] = field;
dirtyCellTemplate = that._dirtyCellTemplate(field)(data);
}
if (column.colSpan && column.colSpan > 0 && hasHiddenStyle(column.attributes)) column.attributes = removeHiddenStyle(column.attributes);
else if (!column.colSpan && column.hidden) column.attributes = addHiddenStyle(column.attributes);
if (column.command) {
column.attributes = column.attributes || {};
classAttribute = column.attributes["class"];
if (typeof classAttribute !== "undefined") {
if (classAttribute.indexOf("k-command-cell") < 0) column.attributes["class"] += " k-command-cell ";
} else column.attributes["class"] = " k-command-cell ";
}
if (column.draggable) {
column.attributes = column.attributes || {};
if (typeof column.attributes["class"] !== "undefined") {
if (column.attributes["class"].indexOf("k-drag-cell") < 0) column.attributes["class"] += " k-drag-cell ";
} else column.attributes["class"] = " k-drag-cell ";
if (!column.attributes["ref-grid-drag-cell"]) column.attributes["ref-grid-drag-cell"] = true;
if (typeof column.attributes[ARIA_LABEL] === "undefined") column.attributes[ARIA_LABEL] = that.options.messages.dragHandleLabel;
if (typeof column.attributes.style !== "undefined") {
if (column.attributes.style.indexOf("cursor: move;") < 0) column.attributes.style += " cursor: move;";
} else column.attributes.style = "cursor: move;";
}
if (column._attributesFunction) compiledAttributes = column._attributesFunction(data);
let attributes = extend({}, column.attributes, compiledAttributes);
if (dirtyCellTemplate) {
attributes["class"] = attributes["class"] || "";
attributes["class"] += dirtyCellTemplate;
}
let columnAttributes = stringifyAttributes(attributes);
let colSpanAttributes = "";
if (column.colSpan) {
if (column.colSpan > 1) colSpanAttributes += " " + kendo.attr("virtual");
colSpanAttributes += ` colSpan="${column.colSpan}"`;
}
rowTemplateResult += decorateCellWithClass(`<td${columnAttributes}${colSpanAttributes}>`);
rowTemplateResult += column.selectable ? kendo.template(SELECTCOLUMNTMPL)({ size: kendo.getValidCssClass("k-checkbox-", "size", that.options.size) }) : that._cellTmpl(column, state)(data);
rowTemplateResult += "</td>";
}
rowTemplateResult += "</tr>";
return rowTemplateResult;
};
if (that._isStackedMode()) rowTemplateFunc = (data) => {
columns = leafColumns(visibleColumns(columns));
length = columns.length;
const uid = length ? ` ${kendo.attr("uid")}="${kendo.getter("uid")(data)}"` : "";
let rowTemplateResult = `<tr class="${alt ? "k-table-row k-table-alt-row " : "k-table-row "}k-master-row"${uid}>`;
if (groups > 0 && !skipGroupCells) rowTemplateResult += groupCells(groups);
rowTemplateResult += `<td class="k-table-td">
<div class="k-grid-stack-row">
`;
for (idx = 0; idx < length; idx++) {
column = columns[idx];
column.template;
field = column.field;
compiledAttributes = {};
const showHideColumnOnGroup = groups > 0 && that.dataSource.group().find((g) => g.field === field) && column.hideOnGroup;
let dirtyCellTemplate;
if (showHideColumnOnGroup) continue;
if (that._editMode() && field) {
column.attributes = column.attributes || {};
if (that.virtualScroll) column.attributes[fieldAttr] = field;
dirtyCellTemplate = that._dirtyCellTemplate(field)(data);
}
if (column.colSpan && column.colSpan > 0 && hasHiddenStyle(column.attributes)) column.attributes = removeHiddenStyle(column.attributes);
else if (!column.colSpan && column.hidden) column.attributes = addHiddenStyle(column.attributes);
column.attributes["class"] = "k-grid-stack-cell";
if (column.title) column.attributes[kendo.attr("title")] = column.title;
if (column.aggregates) column.attributes[kendo.attr("aggregates")] = column.aggregates;
let shouldRenderStackedContent = !column.selectable;
let shouldRenderStackedHeader = !column.selectable;
if (column.command) {
column.attributes = column.attributes || {};
classAttribute = column.attributes["class"];
if (typeof classAttribute !== "undefined") {
if (classAttribute.indexOf("k-command-cell") < 0) column.attributes["class"] += " k-command-cell";
} else column.attributes["class"] = "k-command-cell";
shouldRenderStackedHeader = column.title && column.title !== " ";
shouldRenderStackedContent = true;
}
if (column.draggable) {
shouldRenderStackedHeader = false;
shouldRenderStackedContent = true;
column.attributes = column.attributes || {};
if (typeof column.attributes["class"] !== "undefined") {
if (column.attributes["class"].indexOf("k-drag-cell") < 0) column.attributes["class"] += " k-drag-cell";
} else column.attributes["class"] = "k-drag-cell";
if (!column.attributes["ref-grid-drag-cell"]) column.attributes["ref-grid-drag-cell"] = true;
if (typeof column.attributes[ARIA_LABEL] === "undefined") column.attributes[ARIA_LABEL] = that.options.messages.dragHandleLabel;
if (typeof column.attributes.style !== "undefined") {
if (column.attributes.style.indexOf("cursor: move;") < 0) column.attributes.style += " cursor: move;";
} else column.attributes.style = "cursor: move;";
}
if (column._attributesFunction) compiledAttributes = column._attributesFunction(data);
let attributes = extend({}, column.attributes, compiledAttributes);
if (dirtyCellTemplate) {
attributes["class"] = attributes["class"] || "";
attributes["class"] += dirtyCellTemplate;
}
let columnAttributes = stringifyAttributes(attributes);
let colSpanAttributes = "";
if (column.colSpan) {
if (column.colSpan > 1) colSpanAttributes += " " + kendo.attr("virtual");
colSpanAttributes += ` colSpan="${column.colSpan}"`;
}
const title = column.parentIds ? createMultiHeaderTitle(that, column) : column.title || column.field || "";
rowTemplateResult += decorateCellWithClass(`<div${columnAttributes}${colSpanAttributes} ${column.field ? `data-field=${column.field}` : ""} data-index=${idx}>`, true);
if (shouldRenderStackedHeader) rowTemplateResult += `<div class="k-grid-stack-header">${title}</div>`;
if (shouldRenderStackedContent) rowTemplateResult += `<div class="k-grid-stack-content">`;
rowTemplateResult += column.selectable ? kendo.template(SELECTCOLUMNTMPL)({ size: kendo.getValidCssClass("k-checkbox-", "size", that.options.size) }) : that._cellTmpl(column, state)(data);
if (shouldRenderStackedContent) rowTemplateResult += `</div>`;
rowTemplateResult += "</div>";
}
if (hasDetails) rowTemplateResult += `<div class="k-grid-stack-cell">
<div class="k-grid-stack-content">
${kendo.html.renderButton(`<button tabindex='-1' ref="expand-detail-button">${that.options.messages.details.expand}</button>`, {
icon: "plus",
fillMode: "flat",
themeColor: "primary"
})}
</div>
</div>`;
rowTemplateResult += "</div></td></tr>";
return rowTemplateResult;
};
}
rowTemplate = kendo.template(rowTemplate || rowTemplateFunc, settings);
if (state.count > 0) return rowTemplate.bind(state.storage);
return rowTemplate;
},
_dirtyCellTemplate: function(field) {
return (data) => {
if (field && data && data.dirty && data.dirtyFields) return (field.charAt(0) === "[" ? kendo.getter(field)(data.dirtyFields) : data.dirtyFields[field]) ? " k-dirty-cell" : "";
return "";
};
},
_headerCellText: function(column) {
var that = this, settings = extend({}, kendo.Template, that.options.templateSettings), template = column.headerTemplate, type = typeof template, text = column.title && (that.options.encodeTitles ? htmlEncode(column.title) : column.title) || htmlEncode(column.field || "");
if (type === FUNCTION) text = kendo.template(template, settings)({});
else if (type === STRING) text = template;
return text;
},
_cellTmpl: function(column, state) {
var that = this, settings = extend({}, kendo.Template, that.options.templateSettings), template = column.template, field = column.field, idx, length, format = column.format, type = typeof template, columnValues = column.values;
if (column.command) {
if (isArray(column.command)) return (data) => {
let html = "";
for (idx = 0, length = column.command.length; idx < length; idx++) if (column.command[idx].visible) html += column.command[idx].visible(data) ? that._createButton(column.command[idx]) : "";
else html += that._createButton(column.command[idx]);
return html;
};
return () => that._createButton(column.command);
}
if (column.selectable) return SELECTCOLUMNTMPL;
if (column.draggable) return DRAGHANDLECOLUMNTMPL;
if (column.pinnable) {
const isRowPinnableFn = that._getIsRowPinnable();
if (isRowPinnableFn) return (data) => {
if (!isRowPinnableFn({ dataItem: data })) return `<span class="${PINCELLCLASS}"></span>`;
return PINNABLECOLUMNTMPL();
};
return PINNABLECOLUMNTMPL;
}
return (data) => {
let html = that._dirtyIndicatorTemplate(field)(data);
if (type === FUNCTION) {
state.storage["tmpl" + state.count] = template;
html += template(data);
state.count++;
} else if (type === STRING) html += kendo.template(template, settings)(data);
else if (columnValues && columnValues.length && isPlainObject(columnValues[0]) && "value" in columnValues[0] && field) {
var f = convertToObject(columnValues)[settings.useWithBlock ? kendo.getter(field)(data) : field];
html += encode(f != null ? f : "");
} else {
let fieldValue = "";
if (field) {
field = kendo.getter(field)(data);
fieldValue = field == null ? "" : field;
}
if (format) fieldValue = kendo.format(format.replace(formatRegExp, "$1"), fieldValue);
html += column.encoded ? encode(fieldValue) : fieldValue;
}
return html;
};
},
_dirtyIndicatorTemplate: function(field) {
return (data) => {
if (field && data && data.dirty && data.dirtyFields) return (field.charAt(0) === "[" ? kendo.getter(field)(data.dirtyFields) : data.dirtyFields[field]) ? "<span class=\"k-dirty\"></span>" : "";
return "";
};
},
_virtualCols: function(columns) {
var that = this;
var visibleColumns = $.grep(columns, function(c) {
return !c.hidden;
});
var widths = $.map(visibleColumns, function(c) {
return parseInt(c.width, 10);
});
var scrollLeft = that.virtualScrollable ? kendo.scrollLeft(that.content.find(">.k-virtual-scrollable-wrap")) : kendo.scrollLeft(that.content);
var tableWidth = outerWidth(that.content);
var sumOfWidths = sumWidths(visibleColumns);
var colsToRender = [];
var firstColspan = 0;
var lastColspan = 0;
var hiddenColumns = 0;
var idx = 0;
var widthOfHiddenColumns = 0;
var considerNext;
for (idx = 0; idx < visibleColumns.length; idx++) {
considerNext = idx < widths.length - 1 ? widths[idx + 1] : 0;
if (widthOfHiddenColumns + widths[idx] + 2 * considerNext < scrollLeft) {
if (widths[idx]) hiddenColumns++;
widthOfHiddenColumns += widths[idx];
} else {
firstColspan = 1 + hiddenColumns;
break;
}
}
hiddenColumns = 0;
widthOfHiddenColumns = 0;
for (var i = visibleColumns.length - 1; i >= 0; i--) if (widthOfHiddenColumns + 3 * widths[i] < sumOfWidths - tableWidth - scrollLeft) {
if (widths[i]) hiddenColumns++;
widthOfHiddenColumns += widths[i];
} else {
lastColspan = 1 + hiddenColumns;
for (var j = idx; j <= i; j++) {
if (visibleColumns[j].locked) continue;
colsToRender.push(visibleColumns[j]);
if (visibleColumns[j].colSpan) delete visibleColumns[j].colSpan;
}
colsToRender[0].colSpan = firstColspan;
colsToRender[colsToRender.length - 1].colSpan = lastColspan;
break;
}
that.virtualCols = colsToRender;
return colsToRender;
},
_templates: function() {
var that = this, options = that.options, dataSource = that.dataSource, groups = dataSource.group(), footer = that.footer || that.wrapper.find(".k-grid-footer"), aggregates = dataSource.aggregate(), stacked = that._isStackedMode(), columnLeafs = leafColumns(that.columns), columnsLocked = leafColumns(lockedColumns(that.columns)), leafsCols = options.scrollable ? leafColumns(nonLockedColumns(that.columns)) : columnLeafs, columns = (that.virtualScroll || {}).columns ? that._virtualCols(leafsCols) : leafsCols, groupHeaderColumnTemplateLockedColumns = grep(visibleColumns(columnsLocked), function(column, index) {
return column.groupHeaderColumnTemplate && index !== 0;
}), groupHeaderColumnTemplateNonLockedColumns = grep(visibleColumns(columns), function(column) {
return column.groupHeaderColumnTemplate;
});
if (options.scrollable && columnsLocked.length && !stacked) {
if (options.rowTemplate || options.altRowTemplate) throw new Error("Having both row template and locked columns is not supported");
that.rowTemplate = that._tmpl(options.rowTemplate, columns, false, true);
that.altRowTemplate = that._tmpl(options.altRowTemplate || options.rowTemplate, columns, true, true);
that.lockedRowTemplate = that._tmpl(options.rowTemplate, columnsLocked);
that.lockedAltRowTemplate = that._tmpl(options.altRowTemplate || options.rowTemplate, columnsLocked, true);
} else {
that.rowTemplate = that._tmpl(options.rowTemplate, stacked ? that.columns : columns);
that.altRowTemplate = that._tmpl(options.altRowTemplate || options.rowTemplate, stacked ? that.columns : columns, true);
}
if (that._hasDetails()) that.detailTemplate = that._detailTmpl(options.detailTemplate || (() => ""));
if (that._group && !isEmptyObject(aggregates) || !isEmptyObject(aggregates) && !footer.length || grep(columnLeafs, function(column) {
return column.footerTemplate;
}).length) that.footerTemplate = that._footerTmpl(columnLeafs, aggregates, "footerTemplate", "k-footer-template k-table-row");
if (groups && grep(columnLeafs, function(column) {
return column.groupFooterTemplate;
}).length) {
aggregates = $.map(groups, function(g) {
return g.aggregates;
});
that.groupFooterTemplate = that._footerTmpl(columns, aggregates, "groupFooterTemplate", "k-group-footer k-table-row", columnsLocked.length);
if (options.scrollable && columnsLocked.length) that.lockedGroupFooterTemplate = that._footerTmpl(columnsLocked, aggregates, "groupFooterTemplate", "k-group-footer k-table-row");
}
if (groups && (groupHeaderColumnTemplateLockedColumns.length || groupHeaderColumnTemplateNonLockedColumns.length)) {
aggregates = $.map(groups, function(g) {
return g.aggregates;
});
that.groupHeaderColumnTemplate = that._groupHeaderTmpl(visibleColumns(columns), aggregates, "groupHeaderColumnTemplate", "k-table-group-row k-grouping-row k-table-row", columnsLocked.length, groupHeaderColumnTemplateNonLockedColumns);
if (options.scrollable && columnsLocked.length) that.lockedGroupHeaderColumnTemplate = that._groupHeaderTmpl(visibleColumns(columnsLocked), aggregates, "groupHeaderColumnTemplate", "k-table-group-row k-grouping-row k-table-row", 0, groupHeaderColumnTemplateLockedColumns);
} else {
that.groupHeaderColumnTemplate = null;
that.lockedGroupHeaderColumnTemplate = null;
}
if (that.options.noRecords) that.noRecordsTemplate = that._noRecordsTmpl();
},
_noRecordsTmpl: function() {
var wrapper = "<div class=\"{0}\">{1}</div>";
var defaultTemplate = "<div class=\"k-grid-norecords-template\"{1}>{0}</div>";
var scrollableNoGridHeightStyles = this.options.scrollable && !this.wrapper[0].style.height ? ` ${kendo.attr("style-margin")}="0 auto" ${kendo.attr("style-position")}="static"` : "";
var state = {
storage: {},
count: 0
};
var settings = $.extend({}, kendo.Template, this.options.templateSettings);
settings.paramName;
var template;
var type;
var tmpl;
let resultTemplate;
if (this.options.noRecords.template) template = this.options.noRecords.template;
else template = kendo.format(defaultTemplate, this.options.messages.noRecords, scrollableNoGridHeightStyles);
type = typeof template;
if (type === "function") {
let currentCustomTemplate = state.storage["tmpl" + state.count] = template;
state.count++;
resultTemplate = (data) => kendo.format(wrapper, NORECORDSCLASS, currentCustomTemplate(data));
} else if (type === "string") resultTemplate = this.options.noRecords.template ? kendo.format(wrapper, NORECORDSCLASS, template) : () => kendo.format(wrapper, NORECORDSCLASS, template);
tmpl = kendo.template(resultTemplate, settings);
if (state.count > 0) tmpl = tmpl.bind(state.storage);
return tmpl;
},
_footerTmpl: function(columns, aggregates, templateName, rowClass, skipGroupCells) {
var that = this, settings = extend({}, kendo.Template, that.options.templateSettings), paramName = settings.paramName, idx, length, template, type, storage = {}, count = 0, scope = {}, groups = that._groups(), fieldsMap = that.dataSource._emptyAggregates(aggregates), column;
const stacked = that._isStackedMode();
let footerTemplateFunction = (data) => {
let html = "<tr class=\"" + rowClass + "\">";
if (groups > 0 && !skipGroupCells) html += groupCells(groups);
if (that._hasDetails() && !stacked) html += "<td class=\"k-hierarchy-cell k-table-td\"> </td>";
const columnsToCheck = columns;
if (stacked) {
html += decorateCellWithClass("<td>");
html += `<div class="${STACKED_TEMPLATE_WRAPPER_CLASS}">`;
for (idx = 0, length = columnsToCheck.length; idx < length; idx++) {
column = columnsToCheck[idx];
template = column[templateName];
type = typeof template;
if (template) {
if (type !== FUNCTION) {
scope = fieldsMap[column.field] ? extend({}, settings, { paramName: paramName + "['" + column.field + "']" }) : {};
template = kendo.template(template, scope);
}
storage["tmpl" + count] = template;
html += template(data);
count++;
}
}
html += "</div></td>";
} else for (idx = 0, length = columnsToCheck.length; idx < length; idx++) {
column = columnsToCheck[idx];
template = column[templateName];
type = typeof template;
html += decorateCellWithClass("<td" + stringifyAttributes(column.footerAttributes) + ">");
if (template) {
if (type !== FUNCTION) {
scope = fieldsMap[column.field] ? extend({}, settings, { paramName: paramName + "['" + column.field + "']" }) : {};
template = kendo.template(template, scope);
}
storage["tmpl" + count] = template;
html += template(data);
count++;
} else html += " ";
html += "</td>";
}
html += "</tr>";
return html;
};
let resultTemplate = kendo.template(footerTemplateFunction, settings);
if (count > 0) return resultTemplate.bind(storage);
return resultTemplate;
},
_groupHeaderTmpl: function(columns, aggregates, templateName, rowClass, skipGroupCells, groupHeaderColumnTemplateColumns) {
var that = this, settings = extend({}, kendo.Template, that.options.templateSettings), paramName = settings.paramName, html = "", idx, length, template, type, storage = {}, count = 0, scope = {}, fieldsMap = that.dataSource._emptyAggregates(aggregates), column, headerTemplateIndex = groupHeaderColumnTemplateColumns.length ? inArray(groupHeaderColumnTemplateColumns[0], columns) : -1, groupHeaderColumnTemplateClass;
if (headerTemplateIndex < 0) return;
const stacked = that._isStackedMode();
var groupHeaderTemplFunc = (data) => {
let aggregatesHTML = "";
var resultHtml = "<tr data-group-uid=\"" + data.uid + "\" class=\"" + rowClass + "\">";
if (!skipGroupCells) for (var i = 0; i < data.groupCells; i++) resultHtml += "<td class=\"k-table-td k-group-cell\"> </td>";
const columnsToCheck = columns;
if (stacked) {
aggregatesHTML += `<div class="${STACKED_TEMPLATE_WRAPPER_CLASS}">`;
for (idx = headerTemplateIndex, length = columnsToCheck.length; idx < length; idx++) {
column = columnsToCheck[idx];
template = column[templateName];
type = typeof template;
if (template) {
if (type !== FUNCTION) {
scope = fieldsMap[column.field] ? extend({}, settings, { paramName: paramName + "['" + column.field + "']" }) : {};
template = kendo.template(template, scope);
}
storage["tmpl" + count] = template;
aggregatesHTML += storage["tmpl" + count](data);
count++;
}
}
aggregatesHTML += "</div>";
}
if (that._hasDetails() && !stacked) resultHtml += "<td class=\"k-table-td k-hierarchy-cell\"> </td>";
if (headerTemplateIndex < MINCOLSPANVALUE && groupHeaderColumnTemplateColumns.length <= 1 && !skipGroupCells) {
resultHtml += !skipGroupCells ? groupCellBuilder(columnsToCheck.length, stacked, aggregatesHTML)(data) : "";
return resultHtml;
}
if (headerTemplateIndex < MINCOLSPANVALUE) {
headerTemplateIndex = !skipGroupCells ? 1 : 0;
resultHtml += !skipGroupCells ? groupCellBuilder(headerTemplateIndex, stacked, aggregatesHTML)(data) : "";
} else resultHtml += !skipGroupCells ? groupCellBuilder(headerTemplateIndex, stacked, aggregatesHTML)(data) : groupCellLockedContentBuilder(headerTemplateIndex);
if (!stacked) for (idx = headerTemplateIndex, length = columnsToCheck.length; idx < length; idx++) {
column = columnsToCheck[idx];
template = column[templateName];
type = typeof template;
if (column.sticky) {
let stickyAttributes = "";
groupHeaderColumnTemplateClass = column.groupHeaderColumnTemplateClass || "";
if (!groupHeaderColumnTemplateClass) groupHeaderColumnTemplateClass = column.groupHeaderColumnTemplateClass = "group-header-column-template-" + kendo.guid();
if (isPlainObject(column.stickyStyle)) stickyAttributes = `${column.stickyStyle.left ? `${kendo.attr("style-left")}="${column.stickyStyle.left}"` : ""} ${column.stickyStyle.right ? `${kendo.attr("style-right")}="${column.stickyStyle.right}"` : ""}`;
resultHtml += `<td class="k-table-td ${STICKY_CELL_CLASS} ${groupHeaderColumnTemplateClass}" ${stickyAttributes}>`;
} else resultHtml += "<td class='k-table-td'>";
if (template) {
if (type !== FUNCTION) {
scope = fieldsMap[column.field] ? extend({}, settings, { paramName: paramName + "['" + column.field + "']" }) : {};
template = kendo.template(template, scope);
}
storage["tmpl" + count] = template;
resultHtml += storage["tmpl" + count](data);
count++;
} else resultHtml += " ";
resultHtml += "</td>";
}
resultHtml += "</tr>";
return resultHtml;
};
html = kendo.template(groupHeaderTemplFunc, settings);
if (count > 0) return html.bind(storage);
return html;
},
_detailTmpl: function(template) {
var that = this, settings = extend({}, kendo.Template, that.options.templateSettings);
settings.paramName;
var templateFunctionStorage = {}, templateFunctionCount = 0, groups = that._groups(), stacked = that._isStackedMode(), colspan = stacked ? that.table.find("col").length : visibleColumns(leafColumns(that.columns)).length, type = typeof template;
let detailTemplateFunction = (data) => {
let html = "<tr role=\"row\" class=\"k-detail-row k-table-row\">";
if (groups > 0) html += groupCells(groups);
if (!stacked) html += `<td role="gridcell" class="k-hierarchy-cell k-table-td"></td>`;
html += `<td role="gridcell" class="k-detail-cell k-table-td" ${colspan ? ` colspan="${colspan}"` : ""}>`;
if (type === FUNCTION) {
templateFunctionStorage["tmpl" + templateFunctionCount] = template;
html += template(data);
templateFunctionCount++;
} else html += kendo.template(template, settings)(data);
html += "</td></tr>";
return html;
};
let resultTemplate = kendo.template(detailTemplateFunction, settings);
if (templateFunctionCount > 0) return resultTemplate.bind(templateFunctionStorage);
return resultTemplate;
},
_hasDetails: function() {
var that = this;
return that.options.detailTemplate !== null || (that._events[DETAILINIT] || []).length;
},
_hasFilterRow: function() {
var filterable = this.options.filterable;
var hasFiltering = filterable && typeof filterable.mode == STRING && filterable.mode.indexOf(ROW) != -1;
var columns = this.columns;
var columnsWithoutFiltering = $.grep(columns, function(col) {
return col.filterable === false;
});
if (this._isStackedMode() || columns.length && columnsWithoutFiltering.length == columns.length) hasFiltering = false;
return hasFiltering;
},
_details: function() {
var that = this;
if (that.options.scrollable && that._hasDetails() && lockedColumns(that.columns).length) throw new Error("Having both detail template and locked columns is not supported");
const stacked = that._isStackedMode();
const selector = stacked ? `[ref="expand-detail-button"], [ref="collapse-detail-button"]` : ".k-hierarchy-cell " + CARET_ALT_RIGHT + ", .k-hierarchy-cell a[class*='-i-chevron-down']";
that.table.on("click.kendoGrid", selector, function(e) {
var button = $(this);
if (stacked) that._toggleStackedDetails(button);
else that._toggleDetails(button);
e.preventDefault();
return false;
});
},
_setCurrentStackedCell: function(cell) {
const that = this;
const currentIndex = cell ? $(cell).closest(TR).index() : that._currentRowIndex;
const currentStackedCell = that._currentStackedCell();
if (!currentStackedCell || !that.options.navigatable) return;
if (currentIndex >= 0) {
let target;
let stackedCellIndex = currentStackedCell && currentStackedCell.index;
target = that.table.find(`${TR}:eq(${currentIndex}) .k-grid-stack-cell`).eq(stackedCellIndex);
if (target.length) {
if (target.attr("tabindex") === "-1" || !target.attr("tabindex")) addElementsToTab(target.parent().children());
that._currentStackedCell(target, true);
}
}
},
_toggleStackedDetails: function(button, omitAnimation) {
const that = this;
const cell = button.closest(".k-grid-stack-cell");
const content = cell.find(".k-grid-stack-content");
const expanding = button.is(`[ref="expand-detail-button"]`);
const masterRow = button.closest("tr.k-master-row");
const ariaLabelText = expanding ? COLLAPSE : EXPAND;
button.remove();
let buttonInstance;
if (!expanding) buttonInstance = kendo.html.renderButton(`<button tabindex='-1' ref="expand-detail-button" aria-label=${ariaLabelText}>${kendo.htmlEncode(that.options.messages.details.expand)}</button>`, {
icon: "plus",
fillMode: "flat",
themeColor: "primary"
});
else buttonInstance = kendo.html.renderButton(`<button tabindex='-1' ref="collapse-detail-button" aria-label=${ariaLabelText}>${kendo.htmlEncode(that.options.messages.details.collapse)}</button>`, {
icon: `minus`,
fillMode: "flat",
themeColor: "primary"
});
content.append(buttonInstance);
that._addDetailRow(masterRow, expanding, omitAnimation);
that._setCurrentStackedCell(cell);
},
_addDetailRow: function(masterRow, expanding, omitAnimation) {
const that = this;
const detailTemplate = that.detailTemplate;
const masterRowIndex = masterRow.attr(ARIA_ROWINDEX);
const hasDetails = that._hasDetails();
let detailRow = masterRow.next();
let data;
if (detailRow.hasClass("k-hidden")) detailRow.removeClass("k-hidden");
if (hasDetails && !detailRow.hasClass("k-detail-row")) {
data = that.dataItem(masterRow);
detailRow = $(detailTemplate(data)).addClass(masterRow.hasClass("k-table-alt-row") ? "k-table-alt-row" : "").insertAfter(masterRow);
if (masterRowIndex || masterRowIndex === 0) detailRow.attr(ARIA_ROWINDEX, Number(masterRowIndex) + 1);
that.trigger(DETAILINIT, {
masterRow,
detailRow,
data,
detailCell: detailRow.find(".k-detail-cell")
});
}
that.trigger(expanding ? DETAILEXPAND : DETAILCOLLAPSE, {
masterRow,
detailRow
});
if (omitAnimation) toggleRow(detailRow, expanding);
else detailRow.toggle(expanding);
},
_toggleDetails: function(button, omitAnimation) {
var that = this, cell = button.closest("td.k-hierarchy-cell"), expanding = button.is(CARET_ALT_RIGHT), masterRow = button.closest("tr.k-master-row"), ariaLabelText = expanding ? COLLAPSE : EXPAND, ariaExpandText = expanding ? "true" : "false";
if (!expanding) {
kendo.ui.icon(button, { icon: `chevron-${isRtl ? "left" : "right"}` });
button.removeAttr("ref-grid-collapse-detail").attr("ref-grid-expand-detail", true);
} else {
kendo.ui.icon(button, { icon: "chevron-down" });
button.removeAttr("ref-grid-expand-detail").attr("ref-grid-collapse-detail", true);
}
button.attr(ARIA_LABEL, ariaLabelText);
cell.attr(ARIA_EXPANDED, ariaExpandText);
that._addDetailRow(masterRow, expanding, omitAnimation);
},
dataItem: function(tr) {
tr = $(tr)[0];
if (!tr) return null;
if ($(tr).closest(".k-grid-pinned-container").length) {
const uid = $(tr).attr(kendo.attr("uid"));
if (uid) return this.dataSource.getByUid(uid);
return null;
}
const rows = this.tbody.children(), classesRegEx = /k-grouping-row|k-detail-row|k-group-footer/, idx = tr.sectionRowIndex;
let j, correctIdx;
correctIdx = idx;
for (j = 0; j < idx; j++) if (classesRegEx.test(rows[j].className)) correctIdx--;
return this._data[correctIdx];
},
expandRow: function(tr, omitAnimation) {
var button = $(tr).find("> td " + CARET_ALT_RIGHT);
if (button.length) this._toggleDetails(button, omitAnimation);
},
collapseRow: function(tr, omitAnimation) {
var button = $(tr).find("> td a[class*='-i-chevron-down']");
if (button.length) this._toggleDetails(button, omitAnimation);
},
_createHeaderCells: function(columns, rowSpan) {
var that = this, idx, th, text, html = "", length, title, columnMenu = that.options.columnMenu, sortable = that.options.sortable, filterable = that._hasFilterMenu(), messages = that.options.messages, leafs = leafColumns(that.columns), groups = that.dataSource.group(), field;
for (idx = 0, length = columns.length; idx < length; idx++) {
th = columns[idx].column || columns[idx];
text = that._headerCellText(th);
title = th.title;
field = "";
let index = inArray(th, leafs);
let currentTh = "";
if (th.selectable) {
currentTh += "<th scope='col'" + stringifyAttributes(th.headerAttributes);
if (rowSpan && !columns[idx].colSpan) currentTh += " rowspan='" + rowSpan + "'";
if (index > -1) currentTh += kendo.attr("index") + "='" + index + "'";
text = th.headerTemplate ? text : kendo.template(SELECTCOLUMNHEADERTMPL)({ size: kendo.getValidCssClass("k-checkbox-", "size", that.options.size) });
currentTh += ">" + text + "</th>";
} else if (th.draggable) {
currentTh += "<th class='k-header' ref-grid-drag-cell scope='col'" + stringifyAttributes(th.headerAttributes);
if (rowSpan && !columns[idx].colSpan) currentTh += " rowspan='" + rowSpan + "'";
if (index > -1) currentTh += kendo.attr("index") + "='" + index + "'";
text = th.headerTemplate ? text : "";
currentTh += ">" + text + "</th>";
} else if (th.command) {
currentTh += "<th scope='col'" + stringifyAttributes(th.headerAttributes);
if (rowSpan && !columns[idx].colSpan) currentTh += " rowspan='" + rowSpan + "'";
if (index > -1) currentTh += kendo.attr("index") + "='" + index + "'";
currentTh += ">" + (!text || text === " " ? text : kendo.template(DEFAULTHEADERTEMPLATE)({ text })) + "</th>";
} else {
if (th.field) field = kendo.attr("field") + "='" + th.field + "' ";
currentTh += "<th scope='col' " + field;
if (columnMenu && th.field && th.menu !== false) currentTh += " aria-haspopup='menu'";
else if (filterable && th.filterable !== false && !th.command) currentTh += " aria-haspopup='dialog'";
if (rowSpan && !columns[idx].colSpan) currentTh += " rowspan='" + rowSpan + "'";
if (columns[idx].colSpan > 1) {
currentTh += "colspan=\"" + (columns[idx].colSpan - hiddenLeafColumnsCount(th.columns)) + "\" ";
currentTh += kendo.attr("colspan") + "='" + columns[idx].colSpan + "'";
} else if (columns[idx].colSpan === 1) currentTh += kendo.attr("colspan") + "='" + columns[idx].colSpan + "'";
if (title) {
title = title && (that.options.encodeTitles ? htmlEncode(title, true) : title);
currentTh += kendo.attr("title") + "=\"" + title + "\" ";
}
if (th.groupable !== undefined) currentTh += kendo.attr("groupable") + "='" + th.groupable + "' ";
if (isColumnGroupable(that, th) && (!th.headerAttributes || !th.headerAttributes.title)) {
currentTh += "title='";
currentTh += isGroupedBy(groups, th.field) ? messages.ungroupHeader : messages.groupHeader;
currentTh += "' ";
}
if (th.aggregates && th.aggregates.length) currentTh += kendo.attr("aggregates") + "='" + th.aggregates + "'";
if (index > -1) currentTh += kendo.attr("index") + "='" + index + "'";
currentTh += stringifyAttributes(th.headerAttributes);
text = kendo.template(DEFAULTHEADERTEMPLATE)({ text });
currentTh += ">" + text + "</th>";
}
var thClasses = "k-table-th" + (sortable && th.sortable !== false && !th.command && !th.selectable && !th.draggable && th.field ? " k-sortable" : "");
if (that.options.resizable) html += $(currentTh).attr("data-resizable", (th.resizable !== false).toString()).addClass(thClasses)[0].outerHTML;
else html += $(currentTh).addClass(thClasses)[0].outerHTML;
}
return html;
},
_appendLockedColumnContent: function() {
var columns = this.columns, idx, colgroup = this.table.find("colgroup"), cols = colgroup.find(COLGROUP), length, lockedCols = $(), skipHiddenCount = 0, container, colSpan, spanIdx, colOffset = 0;
for (idx = 0, length = columns.length; idx < length; idx++) if (columns[idx].locked) if (isVisible(columns[idx])) {
colSpan = 1;
if (columns[idx].columns) colSpan = leafColumns(columns[idx].columns).length - hiddenLeafColumnsCount(columns[idx].columns);
colSpan = colSpan || 1;
for (spanIdx = 0; spanIdx < colSpan; spanIdx++) lockedCols = lockedCols.add(cols.eq(idx + colOffset + spanIdx - skipHiddenCount));
colOffset += colSpan - 1;
} else skipHiddenCount++;
container = $("<div class=\"k-grid-content-locked\"><table class=\"k-grid-table k-table\"><colgroup></colgroup><tbody class=\"k-table-tbody\"></tbody></table></div>");
colgroup.detach();
container.find("colgroup").append(lockedCols);
colgroup.insertBefore(this.table.find("tbody"));
this.lockedContent = container.insertBefore(this.content);
this.lockedTable = container.children("table");
this.lockedTable.addClass(kendo.getValidCssClass("k-table-", "size", this.options.size));
},
_appendLockedColumnFooter: function() {
var that = this;
var footer = that.footer;
var cells = footer.find(".k-footer-template>td");
var cols = footer.find(".k-grid-footer-wrap>table>colgroup>col");
var html = $("<div class=\"k-grid-footer-locked\"><table class=\"k-grid-footer-table k-table\"><colgroup></colgroup><tfoot class=\"k-table-tfoot\"><tr class=\"k-footer-template k-table-row\"></tr></tfoot></table></div>");
var idx, length;
var groups = that._groups();
var lockedCells = $(), lockedCols = $();
html.find("table").addClass(kendo.getValidCssClass("k-table-", "size", this.options.size));
lockedCells = lockedCells.add(cells.filter(".k-group-cell"));
for (idx = 0, length = leafColumns(lockedColumns(that.columns)).length; idx < length; idx++) lockedCells = lockedCells.add(cells.eq(idx + groups));
lockedCols = lockedCols.add(cols.filter(".k-group-col"));
for (idx = 0, length = visibleColumns(leafColumns(visibleLockedColumns(that.columns))).length; idx < length; idx++) lockedCols = lockedCols.add(cols.eq(idx + groups));
lockedCells.appendTo(html.find(TR));
lockedCols.appendTo(html.find("colgroup"));
that.lockedFooter = html.prependTo(footer);
},
_appendLockedColumnHeader: function(container) {
var that = this, columns = this.columns, idx, html, length, colgroup, tr, trFilter, table, header, filtercellCells, rows = [], skipHiddenCount = 0, cols = $(), hasFilterRow = that._hasFilterRow(), filterCellOffset = 0, filterCells = $(), cell, leafColumnsCount = 0, cells = $();
colgroup = that.thead.prev().find(COLGROUP);
header = that.thead.find(TR).first().find(".k-header:not(.k-group-cell,.k-hierarchy-cell)");
filtercellCells = that.thead.find(".k-filter-row").find("td:not(.k-group-cell,.k-hierarchy-cell)");
var colOffset = 0;
for (idx = 0, length = columns.length; idx < length; idx++) {
if (columns[idx].locked) {
cell = header.eq(idx);
leafColumnsCount = leafColumns(columns[idx].columns || []).length;
if (isVisible(columns[idx])) {
var colSpan = null;
if (columns[idx].columns) colSpan = leafColumnsCount - hiddenLeafColumnsCount(columns[idx].columns);
colSpan = colSpan || 1;
for (var spanIdx = 0; spanIdx < colSpan; spanIdx++) cols = cols.add(colgroup.eq(idx + colOffset + spanIdx - skipHiddenCount));
colOffset += colSpan - 1;
}
mapColumnToCellRows([columns[idx]], childColumnsCells(cell), rows, 0, 0);
leafColumnsCount = leafColumnsCount || 1;
for (var j = 0; j < leafColumnsCount; j++) filterCells = filterCells.add(filtercellCells.eq(filterCellOffset + j));
filterCellOffset += leafColumnsCount;
}
if (columns[idx].columns) skipHiddenCount += hiddenLeafColumnsCount(columns[idx].columns);
if (!isVisible(columns[idx])) skipHiddenCount++;
}
if (rows.length) {
html = "<div class=\"k-grid-header-locked\"><table class=\"k-grid-header-table k-table\"><colgroup></colgroup><thead class=\"k-table-thead\">";
html += new Array(rows.length + 1).join("<tr class='k-table-row'></tr>");
html += (hasFilterRow ? "<tr class=\"k-filter-row k-table-row\"></tr>" : "") + "</thead></table></div>";
table = $(html);
table.find(".k-grid-header-locked").css("width", "1px");
table.find("table").addClass(kendo.getValidCssClass("k-table-", "size", that.options.size));
colgroup = table.find("colgroup");
colgroup.append(that.thead.prev().find("col.k-group-col").add(cols));
tr = table.find("thead tr:not(.k-filter-row)");
for (idx = 0, length = rows.length; idx < length; idx++) {
cells = toJQuery(rows[idx]);
tr.eq(idx).append(that.thead.find(TR).eq(idx).find(".k-group-cell").add(cells));
}
var count = removeEmptyRows(this.thead);
if (rows.length < count) removeRowSpanValue(table, count - rows.length);
trFilter = table.find(".k-filter-row");
trFilter.append(that.thead.find(".k-filter-row .k-group-cell").add(filterCells));
this.lockedHeader = table.prependTo(container);
this.thead.find(".k-group-cell").remove();
return true;
}
return false;
},
_removeLockedContainers: function() {
var elements = this.lockedHeader.add(this.lockedContent).add(this.lockedFooter);
kendo.destroy(elements);
elements.off(NS).remove();
this.lockedHeader = this.lockedContent = this.lockedFooter = null;
this.selectable = null;
},
_thead: function() {
var that = this, columns = that.columns, hasDetails = that._hasDetails() && columns.length, hasFilterRow = that._hasFilterRow(), idx, html = "", thead = that.table.find(">thead"), hasTHead = that.element.find("thead").first().length > 0, headerContent = that.options.messages.expandCollapseColumnHeader, tr;
const isStacked = that._isStackedMode();
if (!isStacked) {
if (!thead.length) thead = $("<thead/>").insertBefore(that.tbody);
thead.addClass("k-table-thead");
if (that.lockedHeader && that.thead) {
tr = that.thead.find("tr:has(th):not(.k-filter-row)").html("");
tr.remove();
tr = $();
that._removeLockedContainers();
} else if (hasTHead) tr = that.element.find("thead").first().find("tr:has(th):not(.k-filter-row)");
else tr = that.element.find("tr:has(th)").first();
if (!tr.length) {
tr = thead.children().first();
if (!tr.length) {
var rows = [{
rowSpan: 1,
cells: [],
index: 0
}];
that._prepareColumns(rows, columns);
for (idx = 0; idx < rows.length; idx++) {
html += "<tr class='k-table-row'>";
if (hasDetails) html += "<th class=\"k-hierarchy-cell k-table-th\" scope=\"col\">" + headerContent + "</th>";
html += that._createHeaderCells(rows[idx].cells, rows[idx].rowSpan);
html += "</tr>";
}
tr = $(html);
kendo.applyStylesFromKendoAttributes(tr, [
"display",
"left",
"right"
]);
}
} else {
for (idx = 0; idx < columns.length; idx++) {
let columnIndex = inArray(columns[idx], leafColumns(columns));
let cell = leafDataCells(tr.parent()).filter("th:not(.k-group-cell):not(.k-hierarchy-cell)").eq(columnIndex);
cell.addClass("k-table-th");
const cellElement = cell[0];
const cellChildNodes = cellElement?.childNodes || [];
if (cellChildNodes.length === 1 && cellChildNodes[0].nodeType === 3) cell.html(DEFAULTHEADERTEMPLATE({ text: htmlEncode(cell.text()) }));
if (columns[idx].hidden && columnIndex >= 0) {
if (cellElement) cellElement.style.display = NONE;
}
}
that._updateHeadersAttr(childColumns(columns));
}
if (hasFilterRow) {
var filterRow = $("<tr/>");
filterRow.addClass("k-filter-row k-table-row");
if (hasDetails || tr.find(".k-hierarchy-cell").length) filterRow.prepend("<td class=\"k-table-td k-hierarchy-cell\"> </td>");
var existingFilterRow = (that.thead || thead).find(".k-filter-row");
if (existingFilterRow.length) {
kendo.destroy(existingFilterRow);
existingFilterRow.remove();
}
thead.append(filterRow);
}
if (!tr.children().length) {
html = "";
if (hasDetails) html += "<th class=\"k-hierarchy-cell k-table-th\" scope=\"col\"> </th>";
html += that._createHeaderCells(columns);
tr.html(html);
} else if (hasDetails && !tr.find(".k-hierarchy-cell")[0]) tr.prepend("<th class=\"k-hierarchy-cell k-table-th\" scope=\"col\">" + (headerContent ? headerContent : " ") + "</th>");
const th = tr.find(TH);
th.addClass(HEADER_CLASS);
if (th.length > 0) thead.attr(ROLE, ROWGROUP);
if (!that.options.scrollable) thead.addClass("k-grid-header");
tr.find("script").remove().end().prependTo(thead);
if (that.thead) that._destroyColumnAttachments();
that.thead = thead;
}
that._sortable();
that._filterable();
that._filterRow();
that._scrollable();
that._columnMenu();
var syncHeight;
var hasLockedColumns = this.options.scrollable && lockedColumns(this.columns).length;
if (hasLockedColumns && !isStacked) {
syncHeight = that._appendLockedColumnHeader(that.thead.closest(".k-grid-header"));
that._appendLockedColumnContent();
that.lockedContent.on("DOMMouseScroll.kendoGrid mousewheel.kendoGrid", that._wheelScroll.bind(that));
if (kendo.support.touch) that._lockedContentUserEvents = new kendo.UserEvents(that.lockedContent, { move: function(e) {
that.content.scrollTop(that.content.scrollTop() + -e.y.delta);
e.preventDefault();
} });
that._updateLockedCols();
}
that._updateCols();
if (!isStacked) {
that._updateColumnCellIndex();
that._updateFirstColumnClass();
}
that._resizable();
that._draggable();
that._reorderable();
if (!isStacked) {
that._updateHeader(that._groups());
that._updateStickyColumns();
}
if (hasLockedColumns && !isStacked) {
if (syncHeight) that._syncLockedHeaderHeight();
that._applyLockedContainersWidth();
}
},
_retrieveFirstColumn: function(columns, rows) {
var result = $();
if (rows.length && columns[0]) {
var column = columns[0];
while (column.columns && column.columns.length) {
column = column.columns[0];
rows = rows.filter(":not(:first)");
}
result = result.add(rows);
}
return result;
},
_updateFirstColumnClass: function() {
var that = this, columns = that.columns || [];
if (!(that._hasDetails() && columns.length) && !that._groups()) {
var tr = that.thead.find(">tr:not(.k-filter-row):not(:first)");
columns = nonLockedColumns(columns);
var rows = that._retrieveFirstColumn(columns, tr);
if (that._isLocked()) {
tr = that.lockedHeader.find("thead>tr:not(.k-filter-row):not(:first)");
columns = lockedColumns(that.columns);
rows = rows.add(that._retrieveFirstColumn(columns, tr));
}
rows.each(function() {
var ths = $(this).find("th");
ths.removeClass("k-first");
ths.eq(0).addClass("k-first");
});
}
},
_prepareColumns: function(rows, columns, parentCell, parentRow) {
var row = parentRow || rows[rows.length - 1];
var childRow = rows[row.index + 1];
var totalColSpan = 0;
for (var idx = 0; idx < columns.length; idx++) {
var cell = {
column: columns[idx],
colSpan: 0
};
row.cells.push(cell);
if (columns[idx].columns && columns[idx].columns.length) {
if (!childRow) {
childRow = {
rowSpan: 0,
cells: [],
index: rows.length
};
rows.push(childRow);
}
cell.colSpan = columns[idx].columns.length;
this._prepareColumns(rows, columns[idx].columns, cell, childRow);
totalColSpan += cell.colSpan - 1;
row.rowSpan = rows.length - row.index;
}
}
if (parentCell) parentCell.colSpan += totalColSpan;
},
_wheelScroll: function(e) {
if (e.ctrlKey) return;
var content = this.content;
if (this.virtualScroll && this.virtualScroll.rows) content = this.virtualScrollable.verticalScrollbar;
var scrollTop = content.scrollTop(), delta = kendo.wheelDeltaY(e);
if (delta) {
if (content[0].scrollHeight > content[0].clientHeight && (content[0].scrollTop < content[0].scrollHeight - content[0].clientHeight && delta < 0 || content[0].scrollTop > 0 && delta > 0)) e.preventDefault();
content.scrollTop(scrollTop + -delta);
}
},
_isLocked: function() {
return this.lockedHeader != null;
},
_updateHeaderCols: function() {
var table = this.thead.parent().add(this.table);
if (this._isLocked()) normalizeCols(table, visibleLeafColumns(visibleNonLockedColumns(this.columns)), this._hasDetails(), 0);
else normalizeCols(table, visibleLeafColumns(visibleColumns(this.columns)), this._hasDetails(), 0);
},
_updateColumnSorters: function() {
var that = this;
var cells = leafDataCells(that.thead);
var columns = leafColumns(that.columns);
var column;
var cell;
var sorterInstance;
if (!that.options.sortable) return;
for (var idx = 0, length = cells.length; idx < length; idx++) {
column = columns[idx];
if (column.sortable !== false && !column.command && column.field) {
cell = cells.eq(idx);
sorterInstance = cell.data("kendoColumnSorter");
if (sorterInstance) sorterInstance.refresh();
}
}
},
_updateHeadersAttr: function(columns) {
if (!columns.length) return;
var that = this;
for (var i = 0; i < columns.length; i++) if (columns[i].headerAttributes) that.element.find("[id='" + columns[i].headerAttributes.id + "']").attr("headers", columns[i].headerAttributes.headers);
that._updateHeadersAttr(childColumns(columns));
},
_updateCols: function(table) {
const that = this;
const defaultTable = that._isStackedMode() ? that.table : that.thead.parent().add(that.table);
table = table || defaultTable;
this._appendCols(table, this._isLocked());
},
_updateLockedCols: function(table) {
if (this._isLocked()) {
table = table || this.lockedHeader.find("table").add(this.lockedTable);
normalizeCols(table, visibleLeafColumns(visibleLockedColumns(this.columns)), this._hasDetails(), this._groups());
}
},
_appendCols: function(table, locked) {
if (locked) normalizeCols(table, visibleLeafColumns(visibleNonLockedColumns(this.columns)), this._hasDetails(), 0);
else normalizeCols(table, visibleLeafColumns(visibleColumns(this.columns)), this._hasDetails(), this._groups(), this._isStackedMode());
},
_autoColumns: function(schema) {
if (schema && schema.toJSON) {
var that = this, field, encoded;
schema = schema.toJSON();
encoded = !(that.table.find("tbody tr").length > 0 && (!that.dataSource || !that.dataSource.transport));
for (field in schema) that.columns.push({
field,
encoded,
headerAttributes: { id: kendo.guid() }
});
that._thead();
that._templates();
}
},
_setRowCachedHeight: function(row, uid) {
var cachedHeight = this._cachedRowsHeight[uid], $row;
if (cachedHeight) {
$row = $(row);
$row[0].style.height = cachedHeight + "px";
row = $row.prop("outerHTML");
}
return row;
},
_rowsHtml: function(data, templates) {
var that = this, html = "", idx, rowTemplate = templates.rowTemplate, altRowTemplate = templates.altRowTemplate, cachedHeights = that._cachedRowsHeight, length, row;
for (idx = 0, length = data.length; idx < length; idx++) {
if (that._skipRerenderItemsCount > 0) that._skipRerenderItemsCount--;
else {
if (idx % 2) row = altRowTemplate(data[idx]);
else row = rowTemplate(data[idx]);
if (cachedHeights) row = that._setRowCachedHeight(row, data[idx].uid);
html += row;
}
that._data.push(data[idx]);
}
return html;
},
_groupData: function(group, skipFooter, firstColumn) {
var footerDefaults = this._groupAggregatesDefaultObject || {}, groupItems = group.items, aggregates = extend({}, footerDefaults, group.aggregates), headerData = extend({}, {
field: group.field,
value: group.value,
items: groupItems,
aggregates
}, group.aggregates[firstColumn ? firstColumn.field : group.field]), footerData = {};
if (!skipFooter) for (var aggregate in aggregates) footerData[aggregate] = extend({}, aggregates[aggregate], { group: {
field: group.field,
value: group.value,
items: groupItems
} });
return extend({}, footerData, headerData);
},
_removeGroupIfEmpty: function(row) {
var that = this, itemsCount, subgroupsCount, length = that.dataSource._group.length;
for (var i = 0; i < length; i++) {
row = row.prev();
itemsCount = +row.attr("data-group-item-count");
subgroupsCount = +row.attr("data-sub-group-count");
if (itemsCount == 1 || subgroupsCount == 1) row.hide();
}
},
_groupRowHtml: function(group, colspan, level, groupHeaderBuilder, templates, skipColspan, skipLastGroup, isLockedTable) {
var that = this, html = "", idx, length, isLocked = that.lockedContent != null, field = group.field, column = grep(leafColumns(that.columns), function(column) {
return column.field == field;
})[0] || {}, firstColumn = visibleColumns(that.columns)[0], firstVisibleColumnGroupHeaderTemplate = firstColumn ? firstColumn.groupHeaderColumnTemplate : null, template = column.groupHeaderTemplate ? column.groupHeaderTemplate : firstVisibleColumnGroupHeaderTemplate, text = (column.title && (that.options.encodeTitles ? htmlEncode(column.title, true) : column.title) || htmlEncode(field, true)) + ": " + formatGroupValue(group.value, column.format, column.values, column.encoded), groupItems = group.currentItems || group.items, groups = that._groups(), groupFooterTemplate = templates.groupFooterTemplate, groupHeaderColumnTemplate = templates.groupHeaderColumnTemplate, groupData, isGroupPaged = that.dataSource._isGroupPaged(), expanded = isGroupPaged ? that.dataSource._groupsState[group.uid] : true;
if (that.options.editable && group.items && group.items[0] && group.items[0].isNew && group.items[0].isNew()) expanded = true;
if (templates.groupFooterTemplate || templates.groupHeaderColumnTemplate || column.groupHeaderTemplate || that._isStackedMode()) groupData = that._groupData(group, false, !column.groupHeaderTemplate && visibleColumns(that.columns)[0].groupHeaderColumnTemplate ? visibleColumns(that.columns)[0] : false);
if (template && !skipColspan) text = typeof template === FUNCTION ? template(groupData) : kendo.template(template)(groupData);
if (!that._skipRerenderItemsCount) if (!group.excludeHeader) html += groupHtmlBuilder({
groupHeaderColumnTemplate,
groupHeaderBuilder,
colspan,
templateColspan: groups - level,
groupData,
level,
text,
expanded,
group,
isGroupPaged,
stacked: that._isStackedMode()
});
else if (isLocked) group.excludeHeader = isLockedTable ? false : true;
else group.excludeHeader = false;
else groupHeaderBuilder(colspan, level, text, expanded, group.uid, isGroupPaged, that._isStackedMode());
if (expanded) if (group.hasSubgroups) for (idx = 0, length = groupItems.length; idx < length; idx++) html += that._groupRowHtml(groupItems[idx], skipColspan ? colspan : colspan - 1, level + 1, groupHeaderBuilder, templates, skipColspan, skipLastGroup && idx === groupItems.length - 1, isLockedTable);
else html += that._rowsHtml(groupItems, templates);
if (groupFooterTemplate) if (skipLastGroup) {
if (!inArray(group.value, that._skippedGroups)) that._skippedGroups.push(group.value);
} else {
if (that._skippedGroups.length && that._skippedGroups[0] === group.value) that._skippedGroups.shift();
if (!that._skipRerenderItemsCount) html += groupFooterTemplate(groupData);
}
return html;
},
collapseGroup: function(group) {
var level, that = this, groupToCollapse = group, footerCount = this.options.groupable.showFooter ? 0 : 1, offset, relatedGroup = $(), idx, length, tr;
group = $(group);
level = group.find(".k-group-cell").length;
if (this.dataSource._isGroupPaged()) {
var groupUid = group.attr("data-group-uid");
var groupObject = that.dataSource._getGroupByUid(groupUid);
var currentGroupCount = that.dataSource._calculateGroupsTotal([groupObject], true);
var groupCountAfterCollapse;
that.dataSource._groupsState[groupUid] = false;
groupCountAfterCollapse = that.dataSource._calculateGroupsTotal([groupObject], true);
that.dataSource._serverGroupsTotal -= currentGroupCount - groupCountAfterCollapse;
that._progress(true);
that.dataSource.range(that.dataSource._currentRangeStart, that.dataSource.take(), function() {
that._progress(false);
}, "collapseGroup");
return;
}
if (this._isLocked()) if (!group.closest(DIV).hasClass("k-grid-content-locked")) {
relatedGroup = group.nextAll(TR);
group = this.lockedTable.find(">tbody>tr").eq(group.index());
} else relatedGroup = this.tbody.children(TR).eq(group.index()).nextAll(TR);
if (group.find(CARET_ALT_DOWN).length) kendo.ui.icon(group.find(CARET_ALT_DOWN), { icon: `chevron-${isRtl ? "left" : "right"}` });
group.find("td[aria-expanded='true']").first().attr(ARIA_EXPANDED, false).find("a").attr(ARIA_LABEL, EXPAND);
group = group.nextAll(TR);
var toHide = [];
for (idx = 0, length = group.length; idx < length; idx++) {
tr = group.eq(idx);
offset = tr.find(".k-group-cell").length;
if (tr.hasClass(GROUPING_ROW)) footerCount++;
else if (tr.hasClass("k-group-footer")) footerCount--;
if (offset <= level || tr.hasClass("k-group-footer") && footerCount < 0) break;
if (relatedGroup.length) toHide.push(relatedGroup[idx]);
toHide.push(tr[0]);
}
$(toHide).hide();
if (this.options.scrollable.endless && this.content) {
clearTimeout(that._collapseGroupsTimeOut);
that._collapseGroupsTimeOut = setTimeout(function() {
that.content.scroll();
that._groupToCollapse = groupToCollapse;
});
}
if (that._hasStickyGroupHeaders() || that._hasStickyGroupFooters()) that._updateStickyGroups();
},
expandGroup: function(group) {
group = $(group);
var that = this, showFooter = that.options.groupable.showFooter, level, tr, offset, relatedGroup = $(), idx, length, footersVisibility = [], groupsCount = 1;
level = group.find(".k-group-cell").length;
if (this.dataSource._isGroupPaged()) {
var groupUid = group.attr("data-group-uid");
var groupObject = that.dataSource._getGroupByUid(groupUid);
var groupCount = that.dataSource._calculateGroupsTotal([groupObject], true);
var groupCountAfterExpand;
that.dataSource._groupsState[groupUid] = true;
if (groupObject.items && groupObject.items.length) {
groupCountAfterExpand = that.dataSource._calculateGroupsTotal([groupObject], true);
that.dataSource._serverGroupsTotal += groupCountAfterExpand - groupCount;
}
that._progress(true);
that.dataSource.range(that.dataSource._currentRangeStart, that.dataSource.take(), function() {
that._progress(false);
}, "expandGroup");
return;
}
if (this._isLocked()) if (!group.closest(DIV).hasClass("k-grid-content-locked")) {
relatedGroup = group.nextAll(TR);
group = this.lockedTable.find(">tbody>tr").eq(group.index());
} else relatedGroup = this.tbody.children(TR).eq(group.index()).nextAll(TR);
if (group.find(CARET_ALT_RIGHT).length) kendo.ui.icon(group.find(CARET_ALT_RIGHT), { icon: "chevron-down" });
group.find("td[aria-expanded='false']").first().attr(ARIA_EXPANDED, true).find("a").attr(ARIA_LABEL, COLLAPSE);
group = group.nextAll(TR);
for (idx = 0, length = group.length; idx < length; idx++) {
tr = group.eq(idx);
offset = tr.find(".k-group-cell").length;
if (offset <= level) break;
if (offset == level + 1 && !tr.hasClass("k-detail-row")) {
tr.show();
relatedGroup.eq(idx).show();
if (tr.hasClass(GROUPING_ROW) && tr.find(".k-icon,.k-svg-icon").is(CARET_ALT_DOWN)) that.expandGroup(tr);
if (tr.hasClass("k-master-row") && tr.find(".k-icon,.k-svg-icon").is(CARET_ALT_DOWN)) {
tr.next().show();
relatedGroup.eq(idx + 1).show();
}
}
if (tr.hasClass(GROUPING_ROW)) {
if (showFooter) footersVisibility.push(tr.is(":visible"));
groupsCount++;
}
if (tr.hasClass("k-group-footer")) {
if (showFooter) {
var toggleVisibility = footersVisibility.pop();
tr.toggle(toggleVisibility);
relatedGroup.eq(idx).toggle(toggleVisibility);
}
if (groupsCount == 1) {
tr.show();
relatedGroup.eq(idx).show();
} else groupsCount--;
}
}
if (level === 0 && that.options.scrollable.endless && this._isLocked() || !that.options.scrollable.endless && this._isLocked()) that._syncLockedContentHeight();
if (that._hasStickyGroupHeaders() || that._hasStickyGroupFooters()) that._updateStickyGroups();
},
_updateHeader: function(groups) {
var that = this, container = that._isLocked() ? that.lockedHeader.find("thead") : that.thead, filterCells = container.find("tr.k-filter-row").find("td.k-group-cell").length, length = container.find(TR).first().find("th.k-group-cell").length, rows = container.children("tr:not(:first)").filter(function() {
return !$(this).children(":visible").length;
});
if (groups > length) {
$(new Array(groups - length + 1).join("<th class=\"k-group-cell k-header k-table-th\" scope=\"col\">" + encode(that.options.messages.expandCollapseColumnHeader) + "</th>")).prependTo(container.children("tr:not(.k-filter-row)"));
if (that.element.is(":visible")) rows.find("th.k-group-cell").hide();
} else if (groups < length) container.find(TR).each(function() {
$(this).find(".k-group-cell").eq(groups).remove();
$(this).find(".k-group-cell").slice(groups).remove();
});
if (groups > filterCells) $(new Array(groups - filterCells + 1).join("<td class=\"k-group-cell k-table-group-td k-table-td\"> </td>")).prependTo(container.find(".k-filter-row"));
},
_firstDataItem: function(data, grouped) {
if (data && grouped) if (data.hasSubgroups) data = this._firstDataItem(data.items[0], grouped);
else data = data.items[0];
return data;
},
_updateTablesWidth: function() {
var that = this, tables;
if (!that._isLocked()) return;
tables = $(">.k-grid-footer>.k-grid-footer-wrap>table", that.wrapper).add(that.thead.parent()).add(that.table);
that._footerWidth = tableWidth(tables.eq(0));
tables.width(that._footerWidth);
tables = $(">.k-grid-footer>.k-grid-footer-locked>table", that.wrapper).add(that.lockedHeader.find(">table")).add(that.lockedTable);
tables.width(tableWidth(tables.eq(0)));
},
hideColumn: function(column) {
var that = this, cell, tables, idx, cols, colWidth, position, width = 0, headerCellIndex, length, footer = that.footer || that.wrapper.find(".k-grid-footer"), virtualScroll = that.virtualScroll || {}, columns = that.columns, visibleLocked = that.lockedHeader ? leafDataCells(that.lockedHeader.find(">table>thead")).filter(isCellVisible).length : 0, columnIndex, groupHeaderColumnTemplateColumns, columnsToHide;
if (!Array.isArray(column)) columnsToHide = [column];
else columnsToHide = column;
columnsToHide.forEach((column) => {
groupHeaderColumnTemplateColumns = grep(leafColumns(that.columns), function(column) {
return column.groupHeaderColumnTemplate;
});
if (typeof column == "number") column = columns[column];
else if (isPlainObject(column)) column = grep(flatColumns(columns), function(item) {
return item === column;
})[0];
else column = grep(flatColumns(columns), function(item) {
return item.field === column;
})[0];
if (!column || !isVisible(column)) return;
if (that._isStackedMode()) {
that._stackedColumnVisibility(column, "hide");
that.trigger(COLUMNHIDE, { column });
return;
}
var setColumnVisibility = that._columnVisibilitySetter(column);
if (column.columns && column.columns.length) {
position = columnVisiblePosition(column, columns);
setColumnVisibility(column, false);
setCellVisibility(elements($(">table>thead", that.lockedHeader), that.thead, ">tr:eq(" + position.row + ")>th"), position.cell, false);
for (idx = 0; idx < column.columns.length; idx++) this.hideColumn(column.columns[idx]);
that._ariaAddHiddenColIndex();
that.trigger(COLUMNHIDE, { column });
return;
}
columnIndex = inArray(column, visibleColumns(leafColumns(columns)));
setColumnVisibility(column, false);
that._setParentsVisibility(column, false);
that._templates();
that._updateCols();
that._updateLockedCols();
var container = that.thead;
headerCellIndex = columnIndex;
if (that.lockedHeader && visibleLocked > columnIndex) container = that.lockedHeader.find(">table>thead");
else headerCellIndex -= visibleLocked;
cell = leafDataCells(container).filter(isCellVisible).eq(headerCellIndex);
cell[0].style.display = NONE;
setCellVisibility(elements($(">table>thead", that.lockedHeader), that.thead, ">tr.k-filter-row>td"), columnIndex, false);
if (footer[0]) {
that._updateCols(footer.find(">.k-grid-footer-wrap>table"));
that._updateLockedCols(footer.find(">.k-grid-footer-locked>table"));
setCellVisibility(footer.find(".k-footer-template>td"), columnIndex, false);
}
if (virtualScroll.columns && !column.locked) {
that._updateContentWidth();
that._renderPinnedRows();
that.trigger(COLUMNHIDE, { column });
return;
}
if (that.lockedTable && visibleLocked > columnIndex) hideColumnCells(that.lockedTable.find(">tbody>tr"), columnIndex);
else hideColumnCells(that.tbody.children(), columnIndex - visibleLocked);
if (that.lockedTable) {
that._updateTablesWidth();
that._applyLockedContainersWidth();
that._syncLockedContentHeight();
that._syncLockedHeaderHeight();
that._syncLockedFooterHeight();
} else {
cols = that.thead ? that.thead.prev().find("col") : [];
for (idx = 0, length = cols.length; idx < length; idx += 1) {
colWidth = cols[idx].style.width;
if (cols[idx].className.indexOf("k-hierarchy-col") > -1) {
width += outerWidth(cols[idx]);
continue;
}
if (cols[idx].className.indexOf("k-group-col") > -1) {
width += outerWidth(cols[idx]);
continue;
}
if (colWidth && colWidth.indexOf("%") == -1) width += parseInt(colWidth, 10);
else {
width = 0;
break;
}
}
tables = that.wrapper.find(">.k-grid-header table").first().add(that.wrapper.find(">.k-grid-footer table").first()).add(that.table);
that._footerWidth = null;
if (width) {
tables.each(function() {
this.style.width = width + PX;
});
that._footerWidth = width;
that._setContentWidth();
}
}
that._updateFirstColumnClass();
that._updateStickyColumns();
that._ariaAddHiddenColIndex();
if (groupHeaderColumnTemplateColumns.length > 0) that._renderGroupRows();
that._renderPinnedRows();
if (that._hasStickyGroupHeaders() || that._hasStickyGroupFooters()) that._syncStickyGroupColgroups();
that.trigger(COLUMNHIDE, { column });
});
},
_stackedColumnVisibility: function(column, method) {
const that = this;
const field = column.field;
let index;
if (that.columns.length) {
for (let i = 0; i < that.columns.length; i++) if (that.columns[i].field === field) {
index = i;
break;
}
if (index || index === 0) {
that.table.find(".k-grid-stack-cell[data-index='" + index + "']").each(function() {
const cell = $(this);
if (!cell.closest(".k-detail-row").length) cell[method]();
});
setColumnVisibility(column, method === "show");
}
}
},
_setParentsVisibility: function(column, visible) {
var that = this;
var columns = that.columns;
var idx;
var parents = [];
var parent;
var position;
var cell;
var colSpan;
var setColumnVisibility = that._columnVisibilitySetter(column);
var predicate = visible ? function(p) {
return visibleColumns(p.columns).length && p.hidden;
} : function(p) {
return !visibleColumns(p.columns).length && !p.hidden;
};
if (columnParents(column, columns, parents) && parents.length) for (idx = parents.length - 1; idx >= 0; idx--) {
parent = parents[idx];
position = columnPosition(parent, columns);
cell = elements($(">table>thead", this.lockedHeader), this.thead, ">tr:eq(" + position.row + ")>th:not(.k-group-cell):not(.k-hierarchy-cell)").eq(position.cell);
if (predicate(parent)) {
setColumnVisibility(parent, visible);
cell[0].style.display = visible ? "" : NONE;
}
if (cell.filter("[" + kendo.attr("colspan") + "]").length) {
colSpan = parseInt(cell.attr(kendo.attr("colspan")), 10);
cell[0].colSpan = colSpan - hiddenLeafColumnsCount(parent.columns) || 1;
}
}
},
_updateContentWidth: function() {
const that = this;
that.table.add(that.thead ? that.thead.parent() : $()).css({ width: sumWidths(visibleLeafColumns(visibleNonLockedColumns(that.columns))) });
that.refresh();
},
showColumn: function(column) {
var that = this, idx, length, cell, tables, width, headerCellIndex, position, colWidth, cols, columns = that.columns, virtualScroll = that.virtualScroll || {}, footer = that.footer || that.wrapper.find(".k-grid-footer"), lockedColumnsCount = that.lockedHeader ? leafDataCells(that.lockedHeader.find(">table>thead")).length : 0, columnIndex, originalColumn, columnLeafIndex, groupHeaderColumnTemplateColumns, columnsToShow;
if (!Array.isArray(column)) columnsToShow = [column];
else columnsToShow = column;
columnsToShow.forEach((column) => {
groupHeaderColumnTemplateColumns = grep(leafColumns(that.columns), function(column) {
return column.groupHeaderColumnTemplate;
});
if (typeof column == "number") {
columnIndex = column;
column = columns[column];
} else if (isPlainObject(column)) $.each(flatColumns(columns), function(index, item) {
if (item === column) {
column = item;
columnIndex = index;
return false;
}
});
else $.each(flatColumns(columns), function(index, item) {
if (item.field === column) {
column = item;
columnIndex = index;
return false;
}
});
if (!column || isVisible(column)) return;
if (that._isStackedMode()) {
that._stackedColumnVisibility(column, "show");
that.trigger(COLUMNSHOW, { column });
return;
}
var setColumnVisibility = that._columnVisibilitySetter(column);
if (column.columns && column.columns.length) {
position = columnPosition(column, columns);
originalColumn = flatColumns(that.options.columns)[columnIndex];
setColumnVisibility(column, true);
setCellVisibility(elements($(">table>thead", that.lockedHeader), that.thead, ">tr:eq(" + position.row + ")>th"), position.cell, true);
for (idx = 0; idx < column.columns.length; idx++) if (!originalColumn.columns[idx].hidden) this.showColumn(column.columns[idx]);
that._ariaRemoveHiddenColIndex();
that.trigger(COLUMNSHOW, { column });
return;
}
columnLeafIndex = inArray(column, leafColumns(columns));
setColumnVisibility(column, true);
that._setParentsVisibility(column, true);
that._templates();
that._updateCols();
that._updateLockedCols();
var container = that.thead;
headerCellIndex = columnLeafIndex;
if (that.lockedHeader && lockedColumnsCount > columnLeafIndex) container = that.lockedHeader.find(">table>thead");
else headerCellIndex -= lockedColumnsCount;
cell = leafDataCells(container).eq(headerCellIndex);
cell[0].style.display = "";
cell[0].classList.remove("k-hidden");
setCellVisibility(elements($(">table>thead", that.lockedHeader), that.thead, ">tr.k-filter-row>td"), columnLeafIndex, true);
if (footer[0]) {
that._updateCols(footer.find(">.k-grid-footer-wrap>table"));
that._updateLockedCols(footer.find(">.k-grid-footer-locked>table"));
setCellVisibility(footer.find(".k-footer-template>td"), columnLeafIndex, true);
}
if (virtualScroll.columns && !column.locked) {
that._updateContentWidth();
that._renderPinnedRows();
that.trigger(COLUMNSHOW, { column });
return;
}
if (that.lockedTable && lockedColumnsCount > columnLeafIndex) showColumnCells(that.lockedTable.find(">tbody>tr"), columnLeafIndex);
else showColumnCells(that.tbody.children(), columnLeafIndex - lockedColumnsCount);
if (that.lockedTable) {
that._updateTablesWidth();
that._applyLockedContainersWidth();
that._syncLockedContentHeight();
that._syncLockedHeaderHeight();
} else {
tables = that.wrapper.find(">.k-grid-header table").first().add(that.wrapper.find(">.k-grid-footer table").first()).add(that.table);
if (!column.width) tables.width("");
else {
width = 0;
cols = that.thead.prev().find("col");
for (idx = 0, length = cols.length; idx < length; idx += 1) {
colWidth = cols[idx].style.width;
if (cols[idx].className.indexOf("k-hierarchy-col") > -1) {
width += outerWidth(cols[idx]);
continue;
}
if (cols[idx].className.indexOf("k-group-col") > -1) {
width += outerWidth(cols[idx]);
continue;
}
if (colWidth.indexOf("%") > -1) {
width = 0;
break;
}
width += parseInt(colWidth, 10);
}
that._footerWidth = null;
if (width) {
tables.each(function() {
this.style.width = width + PX;
});
that._footerWidth = width;
that._setContentWidth();
}
}
}
that._updateFirstColumnClass();
that._updateStickyColumns();
if (groupHeaderColumnTemplateColumns.length > 0) that._renderGroupRows();
that._renderPinnedRows();
if (that._hasStickyGroupHeaders() || that._hasStickyGroupFooters()) that._syncStickyGroupColgroups();
that._ariaRemoveHiddenColIndex();
that.trigger(COLUMNSHOW, { column });
});
},
_columnVisibilitySetter: function(column) {
if (isUndefined((column || {}).media)) return setColumnVisibility;
else return setColumnMediaVisibility;
},
_buildSkeleton: function() {
const visibleColumns = this.virtualCols ? this.virtualCols : visibleLeafColumns(this.columns);
const pageSize = this.dataSource.pageSize() || this.dataSource.total();
const groups = this._groups();
const stacked = this._isStackedMode();
let loaderHTML = "";
let colspan;
let columnsCount = stacked ? 1 : visibleColumns.length + groups;
if (this._hasDetails() && !stacked) columnsCount++;
if (this._hasVirtualColumns()) colspan = parseInt(this.content.find(TR).first().find("td").first().attr("colspan"), 10);
for (var i = 0; i < pageSize; i++) {
loaderHTML += "<tr class='k-table-row' data-skeleton-row>";
for (var j = 0; j < columnsCount; j++) if (colspan && !j) loaderHTML += "<td colspan='" + colspan + "'><span class='k-skeleton k-skeleton-text k-skeleton-pulse k-table-td'></span></td>";
else loaderHTML += "<td><span class='k-skeleton k-skeleton-text k-skeleton-pulse k-table-td'></span></td>";
loaderHTML += "</tr>";
}
return loaderHTML;
},
_progress: function(toggle) {
var element = this.element;
var endless = this.options.scrollable && this.options.scrollable.endless;
var loaderType = this.options.loaderType;
var isVirtualization = this.options.scrollable && this.options.scrollable.virtual;
var skeleton;
if (isVirtualization) element = this.content;
else if (this._editContainer && this._editMode() === "popup") element = this._editContainer;
else if (this.lockedContent || endless) element = this.wrapper;
else if (this.element.is("table")) element = this.element.parent();
else if (this.content && this.content.length) element = this.content;
if (loaderType == "skeleton" && !this._isExport) {
const tbody = element.find("tbody");
if (toggle) {
skeleton = this._buildSkeleton();
if (endless) this._currentEndlessRows = tbody.children(":not([data-skeleton-row])");
tbody.empty().append(skeleton);
} else if (endless) {
element.find("[data-skeleton-row]").remove();
tbody.prepend(this._currentEndlessRows);
} else element.find(".k-skeleton").closest("tbody").empty();
} else if (this._isExport) this._loaderContainer(toggle, { message: this.options.messages.loader.exporting });
else if (endless && toggle) kendo.ui.progress(element, toggle, {
height: this.content.height(),
top: this.content.parent()[0].offsetTop,
opacity: true
});
else kendo.ui.progress(element, toggle);
},
_resize: function(size, force) {
this._syncLockedContentHeight();
this._syncLockedHeaderHeight();
if (this.content) {
this._setContentWidth();
this._setContentHeight();
}
if (this.lockedTable) this._syncLockedScroll();
if (this.virtualScrollable && (force || this._rowHeight)) {
if (force) this._rowHeight = null;
this.virtualScrollable.repaintScrollbar();
}
if (this.pager && this.pager.element) this.pager.resize(force);
if (this._anyStickyColumns()) this._updateStickyColumns(false);
if (this._hasStickyGroupHeaders() || this._hasStickyGroupFooters()) {
this._syncStickyGroupColgroups();
this._syncStickyGroupScrollState(this.content[0]);
}
if (this._isPinnable() && this.content && this.content[0]) {
this._syncPinnedLockedWidths();
this._syncPinnedScroll(this.content[0]);
}
},
_isActiveInTable: function() {
var active = activeElement();
if (!active) return false;
return this.table[0] === active || $.contains(this.table[0], active) || this._isLocked() && (this.lockedTable[0] === active || $.contains(this.lockedTable[0], active));
},
refresh: function(e) {
var that = this, data = that.dataSource.view(), navigatable = that.options.navigatable, virtualScroll = that.virtualScroll || {}, currentIndex, current = $(that.current()), isCurrentInHeader = false, groups = that._groups(), colspan = groups + visibleLeafColumns(visibleColumns(that.columns)).length, hasMultiColumnHeaders = grep(that.columns, function(item) {
return item.columns !== undefined;
}).length > 0, contentScrollLeft, cachedItemsToSkip, multiColumnHeaderIndex = 0, hasGroups = that.dataSource.group() && that.dataSource.group().length > 0;
const stacked = that._isStackedMode();
if (e && e.action === "itemchange" && (that.editable || that.options.scrollable.endless)) {
if (this._editMode() != "popup" || this._editMode() === "popup" && !that._editableIsClosing) return;
}
if (that._shouldMapHights) {
that._mapCachedRowsHeight("get", "uid");
that._shouldMapHights = false;
}
if (virtualScroll.columns) that._templates();
if (e && e.action === "remove" && that.editable && that.editable.options.model && inArray(that.editable.options.model, e.items) > -1) that.editable.options.model.unbind(CHANGE, that._modelChangeHandler);
e = e || {};
if (that.trigger("dataBinding", {
action: e.action || "rebind",
index: e.index,
items: e.items
})) return;
if (e.action === SYNC && that._isVirtualEditable()) {
that._destroyEditable();
that._clearEditableState();
}
if (!that._endlessFetchInProgress) {
const component = that._isAdaptive() ? "kendoActionSheet" : "kendoWindow";
if (navigatable && (that._isActiveInTable() || that._editContainer && that._editContainer.data(component))) {
isCurrentInHeader = current.is("th");
currentIndex = isCurrentInHeader ? current.parent().children(":not(.k-group-cell)").index(current[0]) : Math.max(that.cellIndex(current), 0);
if (isCurrentInHeader && hasMultiColumnHeaders) multiColumnHeaderIndex = current.parent().index();
}
that._destroyEditable();
}
if (that.options.scrollable && that.options.scrollable.endless && !that._pdfInitialized) {
clearTimeout(that._progressTimeOut);
that._progressTimeOut = setTimeout(function() {
if (!that._endlessFetchInProgress) {
that._progress(false);
if (stacked) that._toggleGroupableHeader(hasGroups);
}
}, 250);
} else if (!that._isExport) {
that._progress(false);
if (stacked) that._toggleGroupableHeader(hasGroups);
}
if (current.length && current.closest(that.wrapper).length) that._currentRowIndex = current.parent().index();
that._hideResizeHandle();
that._data = [];
if (!that.columns.length) {
that._autoColumns(that._firstDataItem(data[0], groups));
colspan = groups + that.columns.length;
}
that._group = groups > 0 || that._group;
if (that._group) {
that._templates();
that._updateCols();
that._updateLockedCols();
if (!that._virtualColScroll && !stacked) that._updateHeader(groups);
that._group = groups > 0;
that._groupRows = groupRows(data);
}
if (that.content) contentScrollLeft = kendo.scrollLeft(that.content);
const hasGroupAggregateTemplate = that.dataSource.group()?.some((g) => g.aggregates) && that.columns?.some((c) => c.groupFooterTemplate || c.groupHeaderTemplate);
if (that.options.loaderType !== "skeleton" && e && e.action === "sync" && e.partialUpdate && e.changedItems && e.changedItems.length && !hasGroupAggregateTemplate) {
that._data = that.dataSource.flatView();
e.changedItems.forEach((changedItem) => {
const row = that.tbody.find("[" + kendo.attr("uid") + "=" + changedItem.uid + "]");
if (that._editMode() === INCELL && that.dataSource.options.autoSync && that.dataSource.isLocalTransport()) that.trigger(CELLCLOSE, {
type: "save",
model: e.changedItems[0],
container: row.find(".k-edit-cell")
});
that._displayRow(row);
});
that._progress(false);
if (stacked) that._toggleGroupableHeader(hasGroups);
that._destroyEditable();
} else {
cachedItemsToSkip = that._skipRerenderItemsCount;
that._renderContent(data, colspan, groups);
if (that.options.scrollable && that.options.scrollable.endless && this.lockedContent) that._skipRerenderItemsCount = cachedItemsToSkip;
that._renderLockedContent(data, colspan, groups);
}
if (!that._virtualColScroll) {
that._footer();
that._renderNoRecordsContent();
that._togglePagerVisibility();
if (!that._isPinnable()) that._setContentHeight();
that._setContentWidth(that.content && contentScrollLeft);
}
if (that.lockedTable) if (virtualScroll.rows) that.content.find(">.k-virtual-scrollable-wrap").trigger("scroll");
else if (that.touchScroller) that.touchScroller.movable.trigger("change");
else {
that.wrapper.one("scroll", function(e) {
e.stopPropagation();
});
that.content.trigger("scroll");
}
if (!that._endlessFetchInProgress && !that._rowDropping) if (stacked && that.options.navigatable) that._setCurrentStackedCell();
else {
const currentIsLockedHeader = that._isLocked() && current.closest(".k-grid-header-locked").length && isCurrentInHeader;
that._restoreCurrent(currentIndex, isCurrentInHeader, multiColumnHeaderIndex, currentIsLockedHeader);
}
if (that.touchScroller) that.touchScroller.contentResized();
if (that.selectable) that.selectable.resetTouchEvents();
if (that._checkBoxSelection) that._toggleHeaderCheckState(false);
if (that.options.persistSelection && (that.selectable && !kendo.ui.Selectable.parseOptions(that.options.selectable).cell || that._checkBoxSelection) && (that.items().length || that.dataSource._isGroupPaged())) that._restoreSelection();
that._restoreHighlight();
if (that._hasAIHighlight) that._applyAIHighlight(that._hasAIHighlight);
if (that._hasAISelection && !that._isSingleSelectionEnabled()) that._applyAISelection(that._hasAISelection);
if (!that.options.persistSelection) that._selectedIds = {};
if (that._hasReorderableRows()) {
that._draggableRows();
that._reorderableRows();
}
if (that.options.selectable && that.options.selectable.cellAggregates) that._calculateAggregatesForSelected();
if (stacked) {
const layoutSettings = that._getStackedLayoutSettings();
const stackedRows = that.tbody.find(".k-grid-stack-row");
if (layoutSettings.colClass) stackedRows.addClass(layoutSettings.colClass);
else if (layoutSettings.colsConfig) stackedRows.css("grid-template-columns", layoutSettings.colsConfig);
}
that._toggleToolbarEditingItemsVisibility();
that._aria();
if (that._hasStickyGroupHeaders() || that._hasStickyGroupFooters()) {
that._stickyHeaderItems = [];
that._stickyFooterItems = [];
that._syncStickyGroupColgroups();
that._updateStickyGroups();
}
if (that._isPinnable() && !that._rowDropping) {
that._initPinnedRows();
that._renderPinnedRows();
}
that.trigger(DATABOUND);
},
_getSchemaIdField: function() {
const model = this.dataSource.options.schema.model;
return isFunction(model) ? model.fn.idField : model && model.id;
},
_restoreCurrent: function(currentIndex, isCurrentInHeader, multiColumnHeaderIndex, isLocked) {
if (currentIndex === undefined || currentIndex < 0) return;
this._removeCurrent();
if (isCurrentInHeader) {
const container = isLocked ? this.lockedHeader : this.thead;
this._setCurrent(container.find(`tr:eq(${multiColumnHeaderIndex}) th:not(.k-group-cell)`).eq(currentIndex), false, this._hasVirtualColumns());
} else {
var rowIndex = 0;
var virtualScroll = this.virtualScroll || {};
if (this._rowVirtualIndex) if (virtualScroll.rows) rowIndex = this.virtualScrollable.position(this._rowVirtualIndex);
else rowIndex = this._rowVirtualIndex;
else if (this._currentRowIndex) rowIndex = this._currentRowIndex;
else currentIndex = 0;
var row = $();
var colspan;
if (this.lockedTable) if (this._shouldFocusInLastRow) row = this.lockedTable.find(">tbody>tr").last();
else if (this._shouldFocusInFirstRow) row = this.lockedTable.find(">tbody>tr").first();
else row = this.lockedTable.find(">tbody>tr").eq(rowIndex);
let nonLockedRow;
if (this._shouldFocusInLastRow) nonLockedRow = this.tbody.children().last();
else if (this._shouldFocusInFirstRow) nonLockedRow = this.tbody.children().first();
else nonLockedRow = this.tbody.children().eq(rowIndex);
row = row.add(nonLockedRow);
if (this._hasVirtualColumns()) {
colspan = parseInt(row.find("td").first().attr("colspan"), 10);
currentIndex = this._virtualCellIndex - (colspan > 1 ? colspan - 1 : 0);
}
var td = row.find(">td:not(.k-group-cell):not(.k-hierarchy-cell)").eq(currentIndex);
if (!td.length || currentIndex < 0) return;
if (this._hasVirtualColumns()) this._setCurrent(td, true, true);
else this._setCurrent(td);
}
if (this._current) focusTable(this.table, true);
},
_restoreSelection: function() {
var that = this, allRows = that.items(), selectedRows, id = that._getSchemaIdField();
selectedRows = grep(allRows, function(row) {
var dataItemKey = that.dataItem(row)[id];
if (that._selectedIds[dataItemKey]) return row;
});
that.select(selectedRows);
},
_getSelectedRowUids: function() {
var that = this, selected = that.select(), row, uid, result = [];
for (let i = 0; i < selected.length; i++) {
row = $(selected[i]);
if (kendo.ui.Selectable.parseOptions(that.options.selectable).cell) row = row.closest(TR);
uid = row.data("uid");
if (result.indexOf(uid) === -1) result.push(uid);
}
return result;
},
_getSelectedColumnFields: function() {
var that = this, selected = that.select(), field, index, visibleColumns = visibleLeafColumns(that.columns).filter((col) => !col.selectable && !col.draggable & !col.command), result = [];
if (!kendo.ui.Selectable.parseOptions(that.options.selectable).cell) return visibleColumns.map((vc) => vc.field);
for (let i = 0; i < selected.length; i++) {
index = $(selected[i]).index();
field = that.thead.find("th:eq(" + index + ")").data("field");
if (result.indexOf(field) === -1) result.push(field);
}
return result;
},
_cleanupDetailItems: function() {
var that = this;
if (that._hasDetails()) that.tbody.find(".k-detail-cell").empty();
},
_renderContent: function(data, colspan, groups) {
var that = this, idx, length, html = "", isLocked = that.lockedContent != null, endlessAppend = null, skipLastGroup, flatViewLength, scrollable = that.options.scrollable, templates = {
rowTemplate: that.rowTemplate,
altRowTemplate: that.altRowTemplate,
groupFooterTemplate: that.groupFooterTemplate,
groupHeaderColumnTemplate: that.groupHeaderColumnTemplate
};
const stacked = that._isStackedMode();
if (scrollable && scrollable.endless && !that.dataSource.options.endless) {
that._skipRerenderItemsCount = 0;
if (that.content) that.content[0].scrollTop = 0;
}
endlessAppend = that._skipRerenderItemsCount > 0;
colspan = isLocked ? colspan - visibleLeafColumns(visibleLockedColumns(that.columns)).length : colspan;
if (stacked) colspan = that.table.find("col").length;
if (groups > 0) {
colspan = isLocked ? colspan - groups : colspan;
if (that.detailTemplate && !stacked) colspan++;
if (that.groupFooterTemplate) that._groupAggregatesDefaultObject = that.dataSource.aggregates();
if (that.options.scrollable.endless) flatViewLength = that.dataSource.flatView().length;
for (idx = 0, length = data.length; idx < length; idx++) {
if (!that._skippedGroups) that._skippedGroups = [];
skipLastGroup = flatViewLength && idx === data.length - 1 && flatViewLength !== that.dataSource.total();
html += that._groupRowHtml(data[idx], colspan, 0, isLocked ? groupRowLockedContentBuilder : groupRowBuilder, templates, isLocked, skipLastGroup, false);
}
} else html += that._rowsHtml(data, templates);
if (endlessAppend) {
that.tbody.append(html);
kendo.applyStylesFromKendoAttributes(that.tbody, [
"display",
"left",
"right"
]);
clearTimeout(that._endlessFetchTimeOut);
that._endlessFetchTimeOut = setTimeout(function() {
if (that._groupToCollapse) {
that.collapseGroup(that._groupToCollapse);
that._groupToCollapse = null;
}
});
that._endlessFetchInProgress = null;
} else that.tbody = appendContent(that.tbody, that.table, html, this.options.size);
},
_renderGroupRows: function() {
var that = this, data = that._groupRows, groupRows = that.wrapper.find(".k-grouping-row"), groups = that._groups(), groupRowBuilderFunc, isLocked = that.lockedContent != null, columns, colspan, group, field, column, template, text, groupHeaderData, tableContainer, isInLockedContainer, prevElement, newGroupRowElement, currentRow, level, groupHeaderColumnTemplate, firstColumnGroupData;
groupRows.each(function(index, row) {
currentRow = $(row);
tableContainer = currentRow.closest("table").parent();
isInLockedContainer = tableContainer.is(".k-grid-content-locked");
columns = isInLockedContainer ? visibleLeafColumns(visibleColumns(lockedColumns(that.columns))) : visibleLeafColumns(visibleColumns(nonLockedColumns(that.columns)));
level = currentRow.find(".k-group-cell").length;
if (isLocked) {
groupRowBuilderFunc = isInLockedContainer ? groupRowBuilder : groupRowLockedContentBuilder;
colspan = isInLockedContainer ? columns.length + groups - level : columns.length;
} else {
groupRowBuilderFunc = groupRowBuilder;
colspan = columns.length + groups - level;
}
group = index >= data.length ? data[index - data.length] : data[index];
field = group.field;
column = grep(leafColumns(that.columns), function(column) {
return column.field == field;
})[0] || {};
firstColumnGroupData = !column.groupHeaderTemplate && visibleColumns(that.columns)[0].groupHeaderColumnTemplate ? visibleColumns(that.columns)[0] : false;
template = column.groupHeaderTemplate ? column.groupHeaderTemplate : visibleColumns(that.columns)[0].groupHeaderColumnTemplate;
text = (column.title && (that.options.encodeTitles ? htmlEncode(column.title, true) : column.title) || htmlEncode(field, true)) + ": " + formatGroupValue(group.value, column.format, column.values, column.encoded);
groups = groups;
groupHeaderData = that._groupData(group, false, firstColumnGroupData);
groupHeaderColumnTemplate = isInLockedContainer ? that.lockedGroupHeaderColumnTemplate : that.groupHeaderColumnTemplate;
if (template) text = typeof template === FUNCTION ? template(groupHeaderData) : kendo.template(template)(groupHeaderData);
prevElement = currentRow.prev().length ? currentRow.prev() : currentRow.parent();
newGroupRowElement = $(groupHeaderColumnTemplate ? groupHeaderColumnTemplate(extend({}, groupHeaderData, {
groupCells: level,
colspan: groups - level,
text
})) : groupRowBuilderFunc(colspan, level, text, null, null, null, isRtl, that._isStackedMode()));
kendo.applyStylesFromKendoAttributes(newGroupRowElement, [
"display",
"left",
"right"
]);
if (prevElement.is("tbody")) prevElement.prepend(newGroupRowElement);
else prevElement.after(newGroupRowElement);
currentRow.remove();
});
},
_renderLockedContent: function(data, colspan, groups) {
var html = "", idx, length, skipLastGroup, endlessAppend = null, flatViewLength, templates = {
rowTemplate: this.lockedRowTemplate,
altRowTemplate: this.lockedAltRowTemplate,
groupFooterTemplate: this.lockedGroupFooterTemplate,
groupHeaderColumnTemplate: this.lockedGroupHeaderColumnTemplate
};
if (this.lockedContent) {
var table = this.lockedTable;
endlessAppend = this._skipRerenderItemsCount > 0;
if (groups > 0) {
colspan = colspan - visibleColumns(leafColumns(nonLockedColumns(this.columns))).length;
if (this.options.scrollable.endless) flatViewLength = this.dataSource.flatView().length;
for (idx = 0, length = data.length; idx < length; idx++) {
skipLastGroup = flatViewLength && idx === data.length - 1 && flatViewLength !== this.dataSource.total();
html += this._groupRowHtml(data[idx], colspan, 0, groupRowBuilder, templates, false, skipLastGroup, true);
}
} else html = this._rowsHtml(data, templates);
if (endlessAppend) table.children("tbody").append(html);
else appendContent(table.children("tbody"), table, html, this.options.size);
this._syncLockedContentHeight();
}
},
_togglePagerVisibility: function() {
if (this.options.pageable.alwaysVisible === false) this.wrapper.find(".k-grid-pager").toggle(this.dataSource.total() >= this.dataSource.pageSize());
},
_adjustRowsHeight: function(table1, table2) {
var rows = table1[0].rows, length = rows.length, idx, rows2 = table2[0].rows, containers = table1.add(table2), containersLength = containers.length, heights = [];
for (idx = 0; idx < length; idx++) {
if (!rows2[idx]) break;
if (rows[idx].style.height) rows[idx].style.height = rows2[idx].style.height = "";
}
for (idx = 0; idx < length; idx++) {
if (!rows2[idx]) break;
var offsetHeight1 = rows[idx].getBoundingClientRect().height;
var offsetHeight2 = rows2[idx].getBoundingClientRect().height;
var height = 0;
if (offsetHeight1 > offsetHeight2) height = offsetHeight1;
else if (offsetHeight1 < offsetHeight2) height = offsetHeight2;
heights.push(height);
}
for (idx = 0; idx < containersLength; idx++) containers[idx].style.display = NONE;
for (idx = 0; idx < length; idx++) if (heights[idx]) rows[idx].style.height = rows2[idx].style.height = heights[idx] + PX;
for (idx = 0; idx < containersLength; idx++) containers[idx].style.display = "";
}
});
if (kendo.ExcelMixin) kendo.ExcelMixin.extend(Grid.prototype);
if (kendo.CSVMixin) kendo.CSVMixin.extend(Grid.prototype);
if (kendo.PDFMixin) {
kendo.PDFMixin.extend(Grid.prototype);
Grid.prototype._drawPDF_autoPageBreak = function(progress) {
var grid = this;
var result = new $.Deferred();
var dataSource = grid.dataSource;
var allPages = grid.options.pdf.allPages;
var origBody = grid.wrapper.find("> table > tbody, .k-grid-content > table > tbody").first();
var cont = $("<div>").css({
position: "absolute",
left: -1e4,
top: -1e4
});
var clone;
grid.toggleUnexportableColumns(grid.columns);
clone = grid.wrapper.clone().css({
height: AUTO,
width: AUTO
}).appendTo(cont);
clone.find(".k-grid-content").css({
height: AUTO,
width: AUTO,
overflow: "visible"
});
clone.find("> table, .k-grid-header table, .k-grid-content > table, .k-grid-footer table").css({
height: AUTO,
width: "100%",
overflow: "visible"
});
clone.find(".k-grid-pager, .k-grid-toolbar, .k-grouping-header").remove();
clone.find(".k-grid-header, .k-grid-footer, .k-auto-scrollable").css({ paddingRight: 0 });
var body = clone.find("> table > tbody, .k-grid-content > table > tbody").first().empty();
var startingPage = dataSource.page();
function resolve() {
if (allPages && startingPage !== undefined) {
dataSource.one("change", draw);
dataSource.page(startingPage);
} else {
grid.refresh();
draw();
}
}
function draw() {
cont.appendTo(document.body);
var options = $.extend({}, grid.options.pdf, {
_destructive: true,
progress: function(p) {
progress.notify({
page: p.page,
pageNumber: p.pageNum,
progress: .5 + p.pageNum / p.totalPages / 2,
totalPages: p.totalPages
});
}
});
kendo.drawing.drawDOM(clone, options).always(function() {
cont.remove();
}).then(function(group) {
result.resolve(group);
grid.toggleUnexportableColumns(grid.columns, true);
}).fail(function(err) {
result.reject(err);
});
}
function renderPage() {
var pageNum = dataSource.page();
var totalPages = allPages ? dataSource.totalPages() : 1;
body.append(origBody.children("tr:not(.k-detail-row)"));
if (pageNum < totalPages) dataSource.page(pageNum + 1);
else {
dataSource.unbind("change", renderPage);
resolve();
}
}
if (allPages) {
dataSource.bind("change", renderPage);
dataSource.page(1);
} else renderPage();
return result.promise();
};
Grid.prototype.toggleUnexportableColumns = function(columns, restore) {
var length = columns.length;
var column;
var exportable;
var visibleInExport;
var visibleInExportOnly;
for (var i = 0; i < length; i++) {
column = columns[i];
exportable = column.exportable;
if (!restore) {
if (typeof column.exportable === "object") exportable = column.exportable.pdf;
visibleInExport = !column.hidden && exportable !== false;
visibleInExportOnly = column.hidden && exportable === true;
exportable = visibleInExport || visibleInExportOnly;
if (!exportable && !column.hidden) {
column._toggledDuringExport = true;
this.hideColumn(column);
} else if (exportable && column.hidden) {
column._toggledDuringExport = true;
this.showColumn(column);
} else if (exportable && column.columns) this.toggleUnexportableColumns(column.columns);
} else if (column._toggledDuringExport) {
column._toggledDuringExport = false;
if (column.hidden) this.showColumn(column);
else this.hideColumn(column);
} else if (column.columns) this.toggleUnexportableColumns(column.columns, restore);
}
};
Grid.prototype._drawPDF = function(progress) {
var grid = this;
if (grid.options.pdf.paperSize && grid.options.pdf.paperSize != AUTO) return grid._drawPDF_autoPageBreak(progress);
var result = new $.Deferred();
var dataSource = grid.dataSource;
var allPages = grid.options.pdf.allPages;
var doc = new kendo.drawing.Group();
var startingPage = dataSource.page();
function resolve() {
if (allPages && startingPage !== undefined) {
dataSource.unbind("change", exportPage);
dataSource.one("change", function() {
result.resolve(doc);
});
dataSource.page(startingPage);
} else result.resolve(doc);
}
function exportPage() {
grid.toggleUnexportableColumns(grid.columns);
grid._drawPDFShadow({ width: grid.wrapper.width() }, { avoidLinks: grid.options.pdf.avoidLinks }).done(function(group) {
var pageNum = dataSource.page();
var totalPages = allPages ? dataSource.totalPages() : 1;
var args = {
page: group,
pageNumber: pageNum,
progress: pageNum / totalPages,
totalPages
};
grid.toggleUnexportableColumns(grid.columns, true);
progress.notify(args);
doc.append(args.page);
if (pageNum < totalPages) dataSource.page(pageNum + 1);
else resolve();
}).fail(function(err) {
result.reject(err);
});
}
if (allPages) {
dataSource.bind("change", exportPage);
dataSource.page(1);
} else exportPage();
return result.promise();
};
}
function syncTableHeight(table1, table2) {
table1 = table1[0];
table2 = table2[0];
if (table1.rows.length !== table2.rows.length) {
var lockedHeigth = table1.offsetHeight;
var tableHeigth = table2.offsetHeight;
var row;
var diff;
if (lockedHeigth > tableHeigth) {
row = table2.rows[table2.rows.length - 1];
if (filterRowRegExp.test(row.className)) row = table2.rows[table2.rows.length - 2];
diff = lockedHeigth - tableHeigth;
} else {
row = table1.rows[table1.rows.length - 1];
if (filterRowRegExp.test(row.className)) row = table1.rows[table1.rows.length - 2];
diff = tableHeigth - lockedHeigth;
}
row.style.height = row.offsetHeight + diff + PX;
}
}
function adjustRowHeight(row1, row2) {
var height;
var offsetHeight1 = row1.offsetHeight;
var offsetHeight2 = row2.offsetHeight;
if (offsetHeight1 > offsetHeight2) height = offsetHeight1 + PX;
else if (offsetHeight1 < offsetHeight2) height = offsetHeight2 + PX;
if (height) row1.style.height = row2.style.height = height;
}
function getCommand(commands, name) {
var idx, length, command;
if (typeof commands === STRING && commands === name) return commands;
if (isPlainObject(commands) && commands.name === name) return commands;
if (isArray(commands)) for (idx = 0, length = commands.length; idx < length; idx++) {
command = commands[idx];
if (typeof command === STRING && command === name || command.name === name) return command;
}
return null;
}
function compareElements(element, toCompare) {
if (element.length !== toCompare.length) return false;
for (var i = 0; i < element.length; i++) if (element[i] !== toCompare[i]) return false;
return true;
}
function focusTable(table, direct) {
if (!table || table.length === 0) return;
if (direct === true) {
table = $(table);
var scrollLeft = kendo.scrollLeft(table.parent());
kendo.focusElement(table);
kendo.scrollLeft(table.parent(), scrollLeft);
} else $(table).one("focusin", function(e) {
e.preventDefault();
}).trigger("focus");
}
function isColumnGroupable(grid, column) {
return grid.options.groupable && (column.groupable || column.groupable === undefined);
}
function isGroupedBy(groups, field) {
return !!$.grep(groups, function(item) {
return item.field === field;
}).length;
}
function isColumnEditable(column, model) {
if (!column.field || column.selectable) return false;
if (model.editable && !model.editable(column.field)) return false;
if (column.editable && !column.editable(model)) return false;
return true;
}
function isInputElement(element) {
return $(element).is(INPUT_SELECTORS) || $(element).is("div[contenteditable=true]");
}
function tableClick(e) {
var that = this, currentTarget = $(e.currentTarget), isHeader = currentTarget.is("th"), table = this.table.add(this.lockedTable), headerTable = this.thead && this.thead.parent().add($(">table", this.lockedHeader)), isInput = isInputElement(e.target), preventScroll = $(e.target).is(".k-checkbox"), target = $(e.target), currentTable = currentTarget.closest("table")[0];
if (!that._isStackedMode() && isInput && currentTarget.find(kendo.roleSelector("filtercell")).length) {
this._setCurrent(currentTarget, null, null, true);
return;
}
if (currentTable !== table[0] && currentTable !== table[1] && currentTable !== headerTable[0] && currentTable !== headerTable[1]) {
if (!currentTarget.closest(".k-grid-pinned-container").length) return;
}
if (target.is(CARET_ALT_RIGHT + ",a[class*='-i-chevron-down'],[ref='expand-detail-button'], [ref='collapse-detail-button']")) return;
if (this.options.navigatable) this._setCurrent(currentTarget, false, preventScroll);
if (isHeader || !isInput) setTimeout(function() {
var activeEl = $(kendo._activeElement());
if ((activeEl.hasClass("k-widget") || activeEl.hasClass("k-dropdownlist") || activeEl.is(".k-upload .k-upload-button")) && !activeEl.hasClass("k-grid-pager") || activeEl.hasClass("k-select-checkbox")) return;
if (that.table && (activeEl.is(CHECKBOXINPUT) || !isInputElement(kendo._activeElement()) || !$.contains(currentTable, kendo._activeElement()))) focusTable(that.table[0], true);
});
if (isHeader && !kendo.support.touch) e.preventDefault();
}
function leftMostPosition(element, rtl) {
if (!rtl) return 0;
var result = 0;
if (kendo.support.browser.webkit) result = element.width();
return result;
}
function parseVirtualSettings(options) {
var asLowerString;
if (typeof options === "string") {
asLowerString = options.toLowerCase();
if (asLowerString === "true") return { rows: true };
else return {
rows: asLowerString.indexOf("rows") > -1,
columns: asLowerString.indexOf("columns") > -1
};
} else if (options === true) return { rows: true };
}
function isElementVisibleInWrapper(wrapper, element) {
var offsetTop;
var halfHeight;
if (!wrapper) return false;
element = $(element);
if (element[0] && contains(wrapper[0], element[0])) {
offsetTop = element.offset().top - wrapper.offset().top;
halfHeight = element.outerHeight() / 2;
if ((offsetTop >= 0 || math.abs(offsetTop) <= halfHeight) && math.floor(offsetTop + halfHeight) <= wrapper.height()) return true;
}
return false;
}
function isInEdit(cell) {
return cell && (cell.hasClass("k-edit-cell") || cell.parent().hasClass("k-grid-edit-row") || cell.hasClass("k-grid-stack-edit-cell"));
}
function groupHtmlBuilder({ groupHeaderColumnTemplate, groupHeaderBuilder, colspan, templateColspan, groupData, level, text, expanded, group, isGroupPaged, stacked }) {
var html;
if (groupHeaderColumnTemplate) html = groupHeaderColumnTemplate(extend({}, groupData, {
groupCells: level,
colspan: templateColspan,
text,
expanded,
isRtl,
uid: group.uid
}));
else html = groupHeaderBuilder(colspan, level, text, expanded, group.uid, isGroupPaged, isRtl, stacked);
return html;
}
function groupCellBuilder(headerTemplateIndex, stacked, aggregates) {
return ({ colspan, text, expanded, isRtl }) => {
let length = colspan + headerTemplateIndex > 0 ? colspan + headerTemplateIndex : 0;
let collapsedClass = `chevron-${isRtl ? "left" : "right"}`;
return `<td class="k-table-td" colspan="${colspan + headerTemplateIndex}"><p class="k-reset">` + kendo.ui.icon($(`<a href="\\#" tabindex="-1" ${ARIA_LABEL}="${expanded ? COLLAPSE : EXPAND}"></a>`), { icon: expanded ? "chevron-down" : collapsedClass }) + text + `</p>${aggregates || ""}</td>${!stacked ? new Array(length).join("<td hidden group-header-spanned-hidden></td>") : ""}`;
};
}
function groupCellLockedContentBuilder(headerTemplateIndex) {
return "<td class=\"k-table-td\" colspan=\"" + headerTemplateIndex + `"><p class="k-reset"> </p></td>${new Array(headerTemplateIndex).join("<td hidden group-header-spanned-hidden></td>")}`;
}
function groupRowBuilder(colspan, level, text, expanded, uid, includeAdditionalData, isRtl, stacked, aggregates) {
const chevronDirectionIcon = `chevron-${isRtl ? "left" : "right"}`;
return "<tr " + (includeAdditionalData ? "data-group-uid=\"" + uid + "\"" : "") + "class=\"k-table-group-row k-grouping-row k-table-row\">" + groupCells(level) + "<td class=\"k-table-td\" colspan=\"" + colspan + "\" aria-expanded=\"" + !!expanded + "\"><p class=\"k-reset\">" + kendo.ui.icon($("<a href=\"#\" tabindex=\"-1\" aria-label=\"" + (expanded ? COLLAPSE : EXPAND) + "\"></a>"), { icon: expanded ? "chevron-down" : chevronDirectionIcon }) + text + `</p>${aggregates || ""}</td>${!stacked ? new Array(colspan).join("<td hidden group-header-spanned-hidden></td>") : ""}</tr>`;
}
function groupRowLockedContentBuilder(colspan) {
return "<tr class=\"k-table-group-row k-grouping-row k-table-row\"><td class=\"k-table-td\" colspan=\"" + colspan + `" aria-expanded="true"><p class="k-reset"> </p></td>${new Array(colspan).join("<td hidden group-header-spanned-hidden></td>")}</tr>`;
}
function toggleRow(row, visible) {
row = $(row)[0];
if (visible) row.style.display = "";
else row.style.display = NONE;
}
function htmlEncode(value, backslashEscapeQuotes) {
return ("" + value).replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, function(match) {
if (backslashEscapeQuotes) return "\\" + match;
return """;
}).replace(/'/g, "'");
}
function isEmptyString(value) {
return !/\S/.test(value);
}
function getTitle(field, columns) {
return columns.filter(function(col) {
return col.field === field;
})[0].title || field;
}
function exportDataSort(a, b) {
return this.dataSource.indexOf(this.dataSource.getByUid(a.uid)) - this.dataSource.indexOf(this.dataSource.getByUid(b.uid));
}
function isExcelExportableColumn(column) {
return !(column.exportable === false || column.exportable && column.exportable.excel === false);
}
ui.plugin(Grid);
ui.plugin(VirtualScrollable);
extend(kendo.ui.grid, {
defaultBodyContextMenu,
defaultHeadContextMenu,
defaultGroupsContextMenu
});
})(window.kendo.jQuery);
var kendo_grid_default = kendo;
//#endregion
Object.defineProperty(exports, "__meta__", {
enumerable: true,
get: function() {
return __meta__;
}
});
Object.defineProperty(exports, "kendo_grid_default", {
enumerable: true,
get: function() {
return kendo_grid_default;
}
});