@progress/kendo-ui
Version:
This package is part of the [Kendo UI for jQuery](http://www.telerik.com/kendo-ui) suite.
1,418 lines (1,164 loc) • 86.7 kB
JavaScript
import './kendo.data.js';
import './kendo.treeview.draganddrop.js';
import './kendo.html.input.js';
import './kendo.icons.js';
import './kendo.core.js';
import './kendo.licensing.js';
import '@progress/kendo-licensing';
import './kendo.data.odata.js';
import './kendo.data.xml.js';
import './kendo.draganddrop.js';
import './kendo.userevents.js';
import './kendo.html.base.js';
import './kendo.html.icon.js';
import '@progress/kendo-svg-icons';
const __meta__ = {
id: "treeview",
name: "TreeView",
category: "web",
description: "The TreeView widget displays hierarchical data in a traditional tree structure,with support for interactive drag-and-drop operations.",
depends: [ "data", "html.input", "icons" ],
features: [{
id: "treeview-dragging",
name: "Drag & Drop",
description: "Support for drag & drop",
depends: [ "treeview.draganddrop" ]
}]
};
(function($, undefined$1) {
var kendo = window.kendo,
ui = kendo.ui,
data = kendo.data,
encode = kendo.htmlEncode,
sanitizeLink = kendo.sanitizeLink,
extend = $.extend,
template = kendo.template,
isArray = Array.isArray,
Widget = ui.Widget,
HierarchicalDataSource = data.HierarchicalDataSource,
keys = kendo.keys,
NS = ".kendoTreeView",
TEMP_NS = ".kendoTreeViewTemp",
SELECT = "select",
CHECK = "check",
NAVIGATE = "navigate",
EXPAND = "expand",
CHANGE = "change",
ERROR = "error",
CHECKED = "checked",
INDETERMINATE = "indeterminate",
COLLAPSE = "collapse",
DRAGSTART = "dragstart",
PROGRESS = "progress",
DRAG = "drag",
DROP = "drop",
DRAGEND = "dragend",
DATABOUND = "dataBound",
ITEMSLOADED = "itemsLoaded",
LOADCOMPLETED = "loadCompleted",
REQUESTEND = "requestEnd",
CLICK = "click",
KENDOKEYDOWN = "kendoKeydown",
UNDEFINED = "undefined",
KSTATEHOVER = "k-hover",
KTREEVIEW = "k-treeview",
VISIBLE = ":visible",
NODE = ".k-treeview-item",
ICON = "k-icon",
TOGGLE_ICON_ELM = `<span></span>`,
STRING = "string",
ARIA_CHECKED = "aria-checked",
ARIA_SELECTED = "aria-selected",
ARIA_DISABLED = "aria-disabled",
ARIA_EXPANDED = "aria-expanded",
ARIA_ACTIVEDESCENDANT = "aria-activedescendant",
ARIA_BUSY = "aria-busy",
DISABLED = "k-disabled",
TreeView,
subGroup, nodeContents, nodeIcon,
spriteRe,
bindings = {
text: "dataTextField",
url: "dataUrlField",
spriteCssClass: "dataSpriteCssClassField",
imageUrl: "dataImageUrlField",
attr: "dataAttrField",
imageAttr: "dataImageAttrField",
contentAttr: "dataContentAttrField",
linkAttr: "dataLinkAttrField",
},
isJQueryInstance = function(obj) {
return (obj instanceof kendo.jQuery) || (window.jQuery && obj instanceof window.jQuery);
},
isDomElement = function(o) {
return (
typeof HTMLElement === "object" ? o instanceof HTMLElement : //DOM2
o && typeof o === "object" && o.nodeType === 1 && typeof o.nodeName === STRING
);
};
const treeViewItemDefaultClasses = {
item: "k-treeview-item",
image: "k-image",
contentText: "k-treeview-leaf-text"
};
function contentChild(filter) {
return function(node) {
var result = node.children(".k-animation-container");
if (!result.length) {
result = node;
}
return result.children(filter);
};
}
subGroup = contentChild(".k-treeview-group");
nodeContents = contentChild(".k-treeview-group,.k-content");
nodeIcon = function(node) {
return node.children("div").find(`.k-treeview-toggle > span:first`);
};
function checkboxes(node) {
return node.find(".k-checkbox-wrap:first input[type=checkbox]");
}
function insertAction(indexOffset) {
return function(nodeData, referenceNode) {
referenceNode = referenceNode.closest(NODE);
var group = referenceNode.parent(),
parentNode;
if (group.parent().is("li")) {
parentNode = group.parent();
}
return this._dataSourceMove(nodeData, group, parentNode, function(dataSource, model) {
var referenceItem = this.dataItem(referenceNode);
var referenceNodeIndex = referenceItem && referenceNode.parent().children().length !== referenceItem.parent().length ? referenceItem.parent().indexOf(referenceItem) : referenceNode.index();
return this._insert(dataSource.data(), model, referenceNodeIndex + indexOffset);
});
};
}
spriteRe = /k-sprite/;
function moveContents(node, container) {
var tmp;
while (node && node.nodeName.toLowerCase() != "ul") {
tmp = node;
node = node.nextSibling;
if (tmp.nodeType == 3) {
tmp.nodeValue = kendo.trim(tmp.nodeValue);
}
if (spriteRe.test(tmp.className)) {
container.insertBefore(tmp, container.firstChild);
} else {
container.appendChild(tmp);
}
}
}
function updateNodeHtml(node) {
var wrapper = node.children("div"),
group = node.children("ul"),
toggleButton = wrapper.find(`.k-treeview-toggle > span`),
checkbox = node.children("input[type=checkbox]"),
innerWrapper = wrapper.children(".k-treeview-leaf");
if (node.hasClass("k-treeview")) {
return;
}
if (!wrapper.length) {
wrapper = $("<div />").prependTo(node);
}
if (!toggleButton.length && group.length) {
toggleButton = $(`<span class='k-treeview-toggle'>${TOGGLE_ICON_ELM}</span>`).prependTo(wrapper);
} else if (!group.length || !group.children().length) {
toggleButton.parent().remove();
group.remove();
node.removeAttr(ARIA_EXPANDED);
}
if (checkbox.length) {
$("<span class='k-checkbox-wrap' />").appendTo(wrapper).append(checkbox);
}
if (!innerWrapper.length) {
innerWrapper = node.children("a").eq(0).addClass("k-treeview-leaf k-link");
if (!innerWrapper.length) {
innerWrapper = $("<span class='k-treeview-leaf' />");
}
innerWrapper.appendTo(wrapper);
if (wrapper.length) {
moveContents(wrapper[0].nextSibling, innerWrapper[0]);
}
}
}
TreeView = kendo.ui.DataBoundWidget.extend({
init: function(element, options) {
var that = this,
inferred = false,
hasDataSource = options && !!options.dataSource,
list;
if (isArray(options)) {
options = { dataSource: options };
}
if (options && typeof options.loadOnDemand == UNDEFINED && isArray(options.dataSource)) {
options.loadOnDemand = false;
}
Widget.prototype.init.call(that, element, options);
element = that.element;
options = that.options;
that._dataSourceUids = {};
list = (element.is("ul") && element) ||
(element.hasClass(KTREEVIEW) && element.children("ul"));
inferred = !hasDataSource && list.length;
if (inferred) {
options.dataSource.list = list;
}
that._animation();
that._accessors();
that._templates();
// render treeview if it's not already rendered
if (!element.hasClass(KTREEVIEW)) {
that._wrapper();
if (list) {
that.root = element;
that._group(that.wrapper);
}
} else {
// otherwise just initialize properties
that.wrapper = element;
that.root = element.children("ul").eq(0);
}
that._applyCssClasses();
that._tabindex();
that.wrapper.find(">ul").attr("role", "tree");
that._dataSource(inferred);
that._attachEvents();
that._dragging();
if (!inferred) {
if (options.autoBind) {
that._progress(true);
that.dataSource.fetch(this._attemptLoadCompleted.bind(this));
}
else {
that._progressHandler = that._requestStart.bind(that);
that.dataSource.bind(PROGRESS, that._progressHandler);
}
} else {
that._syncHtmlAndDataSource();
}
if (options.checkboxes && options.checkboxes.checkChildren) {
that.updateIndeterminate();
}
if (that.element[0].id) {
that._ariaId = kendo.format("{0}_tv_active", that.element[0].id);
} else {
that._ariaId = kendo.guid() + "_tv_active";
}
kendo.notify(that);
},
_attachEvents: function() {
var that = this,
clickableItems = ".k-treeview-leaf:not(.k-selected,.k-disabled)",
MOUSEENTER = "mouseenter";
that._clickHandler = that._click.bind(that);
that.wrapper
.on(MOUSEENTER + NS, ".k-treeview-leaf.k-selected", function(e) { e.preventDefault(); })
.on(MOUSEENTER + NS, clickableItems, function() { $(this).addClass(KSTATEHOVER); })
.on("mouseleave" + NS, clickableItems, function() { $(this).removeClass(KSTATEHOVER); })
.on(CLICK + NS, clickableItems, that._clickHandler)
.on("dblclick" + NS, ".k-treeview-leaf:not(.k-disabled)", that._toggleButtonClick.bind(that))
.on(CLICK + NS, `.k-treeview-toggle .${ICON}`, that._toggleButtonClick.bind(that))
.on("keydown" + NS, that, that._keydown.bind(that))
.on("keypress" + NS, that._keypress.bind(that))
.on("focus" + NS, that._focus.bind(that))
.on("blur" + NS, that._blur.bind(that))
.on("mousedown" + NS, `.k-treeview-leaf,.k-checkbox-wrap :checkbox,.k-treeview-toggle .${ICON}`, that._mousedown.bind(that))
.on("change" + NS, ".k-checkbox-wrap :checkbox", that._checkboxChange.bind(that))
.on("click" + NS, ".k-request-retry", that._retryRequest.bind(that))
.on("click" + NS, ".k-link.k-disabled", function(e) { e.preventDefault(); })
.on("click" + NS, function(e) {
var target = $(e.target);
if (!target.is(":kendoFocusable") && !target.find("input,select,textarea,button,object").is(":kendoFocusable")) {
that.focus();
}
});
},
_requestStart: function() {
this._progress(true);
},
_syncHtmlAndDataSource: function(root, dataSource) {
root = root || this.root;
dataSource = dataSource || this.dataSource;
var data = dataSource.view(),
uidAttr = kendo.attr("uid"),
expandedAttr = kendo.attr("expanded"),
checkboxesEnabled = this.options.checkboxes,
items = root.children("li"),
i,
item,
dataItem,
uid,
itemCheckbox;
for (i = 0; i < items.length; i++) {
dataItem = data[i];
uid = dataItem.uid;
item = items.eq(i);
item.attr("role", "treeitem")
.attr(uidAttr, uid)
.attr(ARIA_SELECTED, item.hasClass("k-selected"));
dataItem.expanded = item.attr(expandedAttr) === "true";
if (dataItem.hasChildren) {
item.attr(ARIA_EXPANDED, dataItem.expanded);
}
if (checkboxesEnabled) {
itemCheckbox = checkboxes(item);
dataItem.checked = itemCheckbox.prop(CHECKED);
itemCheckbox.attr("id", "_" + uid);
itemCheckbox.next(".k-checkbox-label").attr("for", "_" + uid);
item.attr(ARIA_CHECKED, item.checked);
}
this._syncHtmlAndDataSource(item.children("ul"), dataItem.children);
}
},
_animation: function() {
var options = this.options,
animationOptions = options.animation,
hasCollapseAnimation = animationOptions.collapse && "effects" in animationOptions.collapse,
collapse = extend({}, animationOptions.expand, animationOptions.collapse);
if (!hasCollapseAnimation) {
collapse = extend(collapse, { reverse: true });
}
if (animationOptions === false) {
animationOptions = {
expand: { effects: {} },
collapse: { hide: true, effects: {} }
};
}
animationOptions.collapse = extend(collapse, { hide: true });
options.animation = animationOptions;
},
_dragging: function() {
var enabled = this.options.dragAndDrop;
var dragging = this.dragging;
if (enabled && !dragging) {
var widget = this;
this.dragging = new ui.HierarchicalDragAndDrop(this.element, {
reorderable: true,
autoScroll: this.options.autoScroll,
filter: "div:not(.k-disabled) .k-treeview-leaf",
allowedContainers: ".k-treeview",
itemSelector: ".k-treeview .k-treeview-item",
hintText: this._hintText.bind(this),
clickMoveClick: this.options.dragAndDrop.clickMoveClick === true ? true : false,
contains: function(source, destination) {
return $.contains(source, destination);
},
dropHintContainer: function(item) {
return item;
},
itemFromTarget: function(target) {
var item = target.closest(".k-treeview-top,.k-treeview-mid,.k-treeview-bot");
return {
item: item,
content: target.closest(".k-treeview-leaf"),
first: item.hasClass("k-treeview-top"),
last: item.hasClass("k-treeview-bot")
};
},
dropPositionFrom: function(dropHint) {
return dropHint.prevAll(".k-treeview-leaf").length > 0 ? "after" : "before";
},
dragstart: function(source) {
widget.wrapper.attr(kendo.attr("scrollable"), false);
return widget.trigger(DRAGSTART, { sourceNode: source[0] });
},
drag: function(options) {
widget.trigger(DRAG, {
originalEvent: options.originalEvent,
sourceNode: options.source[0],
dropTarget: options.target[0],
pageY: options.pageY,
pageX: options.pageX,
statusClass: options.status,
setStatusClass: options.setStatus
});
},
drop: function(options) {
var dropTarget = $(options.dropTarget);
var navigationTarget = dropTarget.closest("a");
if (navigationTarget && navigationTarget.attr("href")) {
widget._tempPreventNavigation(navigationTarget);
}
return widget.trigger(DROP, {
originalEvent: options.originalEvent,
sourceNode: options.source,
destinationNode: options.destination,
valid: options.valid,
setValid: function(state) {
this.valid = state;
options.setValid(state);
},
dropTarget: options.dropTarget,
dropPosition: options.position
});
},
dragend: function(options) {
var source = options.source;
var destination = options.destination;
var position = options.position;
widget.wrapper.removeAttr(kendo.attr("scrollable"));
function triggerDragEnd(source) {
if (widget.options.checkboxes && widget.options.checkboxes.checkChildren) {
widget.updateIndeterminate();
}
widget.current(source);
widget.element.focus();
widget.trigger(DRAGEND, {
originalEvent: options.originalEvent,
sourceNode: source && source[0],
destinationNode: destination[0],
dropPosition: position
});
}
// perform reorder / move
// different handling is necessary because append might be async in remote bound tree
if (position == "over") {
widget.append(source, destination, triggerDragEnd);
} else {
if (position == "before") {
source = widget.insertBefore(source, destination);
} else if (position == "after") {
source = widget.insertAfter(source, destination);
}
triggerDragEnd(source);
}
}
});
} else if (!enabled && dragging) {
dragging.destroy();
this.dragging = null;
}
},
_tempPreventNavigation: function(node) {
node.on(CLICK + NS + TEMP_NS, function(ev) {
ev.preventDefault();
node.off(CLICK + NS + TEMP_NS);
});
},
_hintText: function(node) {
return this.templates.dragClue({
item: this.dataItem(node),
treeview: this.options
});
},
_templates: function() {
let that = this,
options = that.options,
fieldAccessor = that._fieldAccessor.bind(that);
if (options.template && typeof options.template == STRING) {
options.template = template(options.template);
} else if (!options.template) {
options.template = ({ item }) => {
let text = fieldAccessor("text")(item);
let contentAttributes = fieldAccessor("contentAttr")(item);
if (typeof item.encoded != 'undefined' && item.encoded === false) {
return `<span ${that.templates.contentCssAttributes(contentAttributes)}>${text}</span>`;
}
return `<span ${that.templates.contentCssAttributes(contentAttributes)}>${encode(text)}</span>`;
};
}
that._checkboxes();
that.templates = {
setAttributes: function(item) {
return that.templates.setDefaultClasses(treeViewItemDefaultClasses.item, item.attr);
},
cssClass: function(group, item) {
var result = "",
index = item.index,
groupLength = group.length - 1;
if (group.firstLevel && index === 0) {
result += "k-treeview-top ";
}
if (index === 0 && index != groupLength) {
result += (result.indexOf("k-treeview-top") != -1) ? "" : "k-treeview-top";
} else if (index == groupLength) {
result += "k-treeview-bot";
} else {
result += "k-treeview-mid";
}
return result;
},
textClass: function(item, isLink) {
var result = "k-treeview-leaf";
if (isLink) {
result += " k-link";
}
if (item.enabled === false) {
result += " k-disabled";
}
if (item.selected === true) {
result += " k-selected";
}
return result;
},
checkboxClass: function(item) {
var result = "k-checkbox";
if (item.enabled === false) {
result += " k-disabled";
}
return result;
},
toggleButtonClass: function(item) {
var result = "k-treeview-toggle";
if (item.enabled === false) {
result += " k-disabled";
}
return result;
},
toggleIcon: function(icon, item) {
if (item.expanded !== true) {
return ui.icon(icon, { icon: `caret-alt-${kendo.support.isRtl(that.element) ? 'left' : 'right'}` });
} else {
return ui.icon(icon, { icon: 'caret-alt-down' });
}
},
groupAttributes: function(group) {
var attributes = "";
if (!group.firstLevel) {
attributes = "role='group'";
}
return attributes + (group.expanded !== true ? ` ${kendo.attr("style-display")}="none"` : "");
},
groupCssClass: function(group) {
var cssClass = "k-treeview-group";
if (group.firstLevel) {
cssClass += " k-treeview-lines";
}
return cssClass;
},
dragClue: (data) => data.treeview.template(data),
group: (data) =>
`<ul class='${data.r.groupCssClass(data.group)}'${data.r.groupAttributes(data.group)}>` +
data.renderItems(data) +
`</ul>`,
itemContent: (data) => {
let imageUrl = fieldAccessor("imageUrl")(data.item);
let imgAttributes = fieldAccessor("imageAttr")(data.item);
let spriteCssClass = fieldAccessor("spriteCssClass")(data.item);
let result = "";
if (imageUrl) {
result += `<img ${that.templates.imageCssAttributes(imgAttributes)} alt='' src='${imageUrl}'>`;
}
if (spriteCssClass) {
result += `<span class='k-sprite ${spriteCssClass}'></span>`;
}
result += data.treeview.template(data);
return result;
},
itemElement: (data) => {
let item = data.item,
r = data.r;
let url = fieldAccessor("url")(item),
tag = url ? 'a' : 'span',
textAttr = url ? ' href="' + sanitizeLink(url) + '"' : '';
let result = `<div class="${r.cssClass(data.group, item)}">`;
if (item.hasChildren) {
result += `<span class='${r.toggleButtonClass(item)}'>` +
r.toggleIcon($(TOGGLE_ICON_ELM), item) +
`</span>`;
}
if (data.treeview.checkboxes) {
result += `<span class='k-checkbox-wrap' role='presentation'>` +
data.treeview.checkboxes.template(data) +
`</span>`;
}
result += `<${tag} ${r.linkCssAttributes(item, !!url)} ${textAttr}>` +
r.itemContent(data) +
`</${tag}>`;
result += "</div>";
return result;
},
item: (data) => {
var item = data.item,
r = data.r;
var result =
`<li role='treeitem'` +
`${kendo.attr("uid")}="${item.uid}"` +
`${r.setAttributes(item.toJSON ? item.toJSON() : item)} `;
if (data.treeview.checkboxes) {
result +=
`aria-checked="${item.checked ? 'true' : 'false'}" `;
}
result +=
`aria-selected="${item.selected ? 'true' : 'false'}" ` +
`${item.enabled === false ? 'aria-disabled="true"' : ''}`;
if (item.hasChildren) {
result += `aria-expanded="${item.expanded ? "true" : "false"}" `;
}
result +=
`data-expanded="${item.expanded ? "true" : "false"}" >` +
r.itemElement(data) +
`</li>`;
return result;
},
loading: ({ messages }) =>
`<div class='k-icon k-i-loading'></div> ${encode(messages.loading)}`,
retry: ({ messages }) =>
`${encode(messages.requestFailed)} ` +
`<button class='k-button k-button-md k-rounded-md k-button-solid k-button-solid-base k-request-retry'><span class='k-button-text'>${encode(messages.retry)}</span></button>`,
imageCssAttributes: function(imgAttributes) {
return that.templates.setDefaultClasses(treeViewItemDefaultClasses.image, imgAttributes);
},
contentCssAttributes: function(contentAttributes) {
return that.templates.setDefaultClasses(treeViewItemDefaultClasses.contentText, contentAttributes);
},
linkCssAttributes: function(item, isLink) {
return that.templates.setDefaultClasses(this.textClass(item, isLink), fieldAccessor("linkAttr")(item));
},
setDefaultClasses: function(defaultClasses, attributes) {
attributes = attributes && attributes.toJSON ? attributes.toJSON() : attributes || {};
if (!attributes['class']) {
attributes['class'] = defaultClasses;
} else {
attributes['class'] += " " + defaultClasses;
}
return that.templates.stringifyAttributes(attributes);
},
stringifyAttributes: function(attributes) {
let result = "";
for (let attr in attributes) {
if (attributes.hasOwnProperty(attr)) {
result += attr + "=\"" + attributes[attr] + "\" ";
}
}
return result;
}
};
},
items: function() {
return this.element.find(".k-treeview-item > div:first-child");
},
setDataSource: function(dataSource) {
var options = this.options;
options.dataSource = dataSource;
this._dataSourceUids = {};
this._dataSource();
if (options.checkboxes && options.checkboxes.checkChildren) {
this.dataSource.one("change", this.updateIndeterminate.bind(this, null));
}
if (this.options.autoBind) {
this.dataSource.fetch(this._attemptLoadCompleted.bind(this));
}
},
_bindDataSource: function() {
var that = this;
that._refreshHandler = that.refresh.bind(that);
that._errorHandler = that._error.bind(that);
that._loadCompletedHandler = that._loadCompleted.bind(that);
that._requestEndHandler = that._dsRequestEnd.bind(that);
that._loadedNodes = [];
that.dataSource.bind(CHANGE, that._refreshHandler);
that.dataSource.bind(ERROR, that._errorHandler);
that.dataSource.bind(ITEMSLOADED, that._loadCompletedHandler);
that.dataSource.bind(REQUESTEND, that._requestEndHandler);
},
_dsRequestEnd: function(e) {
var that = this;
setTimeout(function() {
if (e.type === "read" && !that._loadCompletedFired) {
that._attemptLoadCompleted();
}
});
},
_loadCompleted: function(e) {
var that = this;
that._loadedNodes = that._loadedNodes.concat(e.nodes);
if (!that.dataSource.loading() && that.options.loadOnDemand === false) {
that.trigger(LOADCOMPLETED, { nodes: that._loadedNodes });
that._loadedNodes = [];
}
},
_attemptLoadCompleted: function() { // If there are no items to be loaded ensure event is triggered on dataBound
var that = this,
items = that.dataSource.view(),
current, i;
if (that.options.loadOnDemand === false) {
for (i = 0; i < items.length; i++) {
current = items[i];
if (current.hasChildren && (!current.children || !current.children.data() || current.children.data().length === 0)) {
return;
}
}
that._loadCompletedFired = true;
that.trigger(LOADCOMPLETED, { nodes: [] });
}
},
_unbindDataSource: function() {
var dataSource = this.dataSource;
if (dataSource) {
dataSource.unbind(CHANGE, this._refreshHandler);
dataSource.unbind(PROGRESS, this._progressHandler);
dataSource.unbind(ERROR, this._errorHandler);
dataSource.unbind(ITEMSLOADED, this._loadCompletedHandler);
dataSource.unbind(REQUESTEND, this._requestEndHandler);
}
},
_dataSource: function(silentRead) {
var that = this,
options = that.options,
dataSource = options.dataSource;
function recursiveRead(data) {
for (var i = 0; i < data.length; i++) {
data[i]._initChildren();
data[i].children.fetch();
recursiveRead(data[i].children.view());
}
}
dataSource = isArray(dataSource) ? { data: dataSource } : dataSource;
that._unbindDataSource();
if (!dataSource.fields) {
dataSource.fields = [
{ field: "text" },
{ field: "url" },
{ field: "spriteCssClass" },
{ field: "imageUrl" }
];
}
that.dataSource = dataSource = HierarchicalDataSource.create(dataSource);
if (silentRead) {
dataSource.fetch();
recursiveRead(dataSource.view());
}
that._bindDataSource();
},
events: [
DRAGSTART,
DRAG,
DROP,
DRAGEND,
DATABOUND,
LOADCOMPLETED,
EXPAND,
COLLAPSE,
SELECT,
CHANGE,
NAVIGATE,
CHECK,
KENDOKEYDOWN
],
options: {
name: "TreeView",
dataSource: {},
animation: {
expand: {
effects: "expand:vertical",
duration: 200
}, collapse: {
duration: 100
}
},
messages: {
loading: "Loading...",
requestFailed: "Request failed.",
retry: "Retry"
},
dragAndDrop: false,
checkboxes: false,
autoBind: true,
autoScroll: false,
loadOnDemand: true,
template: "",
dataTextField: null,
size: "medium"
},
_accessors: function() {
var that = this,
options = that.options,
i, field, textField,
element = that.element;
for (i in bindings) {
field = options[bindings[i]];
textField = element.attr(kendo.attr(i + "-field"));
if (!field && textField) {
field = textField;
}
if (!field) {
field = i;
}
if (!isArray(field)) {
field = [field];
}
options[bindings[i]] = field;
}
},
// generates accessor function for a given field name, honoring the data*Field arrays
_fieldAccessor: function(fieldName) {
var fieldBindings = this.options[bindings[fieldName]],
count = fieldBindings.length;
return (function(item) {
if (count === 0) {
return kendo.getter(fieldName)(item);
}
return $.map(fieldBindings, function(x) {
return function(d) { return kendo.getter(x)(d); };
})[Math.min(item.level(), count - 1)](item);
});
},
setOptions: function(options) {
Widget.fn.setOptions.call(this, options);
this._animation();
this._dragging();
this._accessors();
this._templates();
},
_trigger: function(eventName, node) {
return this.trigger(eventName, {
node: node.closest(NODE)[0]
});
},
_setChecked: function(datasource, value) {
if (!datasource || !kendo.isFunction(datasource.view)) {
return;
}
for (var i = 0, nodes = datasource.view(); i < nodes.length; i++) {
if (nodes[i].enabled !== false) {
this._setCheckedValue(nodes[i], value);
}
if (nodes[i].children) {
this._setChecked(nodes[i].children, value);
}
}
},
_setCheckedValue: function(node, value) {
node[CHECKED] = value;
},
_setIndeterminate: function(node) {
var group = subGroup(node),
siblings, length,
all = true,
i;
if (!group.length) {
return;
}
siblings = checkboxes(group.children());
length = siblings.length;
if (!length) {
return;
} else if (length > 1) {
for (i = 1; i < length; i++) {
if (siblings[i].checked != siblings[i - 1].checked ||
siblings[i].indeterminate || siblings[i - 1].indeterminate) {
all = false;
break;
}
}
} else {
all = !siblings[0].indeterminate;
}
node.attr(ARIA_CHECKED, all ? siblings[0].checked : "mixed");
return checkboxes(node)
.data(INDETERMINATE, !all)
.prop(INDETERMINATE, !all)
.prop(CHECKED, all && siblings[0].checked);
},
updateIndeterminate: function(node) {
// top-down update of inital indeterminate state for all nodes
node = node || this.wrapper;
var subnodes = subGroup(node).children();
var i;
var checkbox;
var dataItem;
if (subnodes.length) {
for (i = 0; i < subnodes.length; i++) {
this.updateIndeterminate(subnodes.eq(i));
}
if (node.is(".k-treeview")) {
return;
}
checkbox = this._setIndeterminate(node);
dataItem = this.dataItem(node);
if (checkbox && checkbox.prop(CHECKED)) {
dataItem.checked = true;
} else {
if (dataItem) {
delete dataItem.checked;
}
}
}
},
_bubbleIndeterminate: function(node, skipDownward) {
// bottom-up setting of indeterminate state of parent nodes
if (!node.length) {
return;
}
if (!skipDownward) {
//update the indeterminate state of the node itself
this.updateIndeterminate(node);
}
var parentNode = this.parent(node),
checkbox;
if (parentNode.length) {
this._setIndeterminate(parentNode);
checkbox = parentNode.children("div").find(".k-checkbox-wrap input[type=checkbox]");
this._skip = true;
if (checkbox.prop(INDETERMINATE) === false) {
this.dataItem(parentNode).set(CHECKED, checkbox.prop(CHECKED));
} else {
// delete this.dataItem(parentNode).checked;
this.dataItem(parentNode).set(CHECKED, false);
}
this._skip = false;
this._bubbleIndeterminate(parentNode, true);
}
},
_checkboxChange: function(e) {
var that = this;
var checkbox = $(e.target);
var isChecked = checkbox.prop(CHECKED);
var node = checkbox.closest(NODE);
var dataItem = this.dataItem(node);
if (this._preventChange) {
return;
}
if (dataItem.checked != isChecked) {
dataItem.set(CHECKED, isChecked);
node.attr(ARIA_CHECKED, isChecked);
this._trigger(CHECK, node);
}
if (checkbox.is(":focus")) {
that._trigger(NAVIGATE, node);
that.focus();
}
},
_toggleButtonClick: function(e) {
var node = $(e.currentTarget).closest(NODE);
if (node.is("[aria-disabled='true']")) {
return;
}
this.toggle(node);
},
_mousedown: function(e) {
var that = this;
var currentTarget = $(e.currentTarget);
var node = $(e.currentTarget).closest(NODE);
var browser = kendo.support.browser;
if (node.is("[aria-disabled='true']")) {
return;
}
//IE does not trigger change for indeterminate checkboxes
if ((browser.msie || browser.edge) && currentTarget.is(":checkbox")) {
if (currentTarget.prop(INDETERMINATE)) {
that._preventChange = false;
currentTarget.prop(CHECKED, !currentTarget.prop(CHECKED));
currentTarget.trigger(CHANGE);
currentTarget.on(CLICK + NS, function(e) {
e.preventDefault();
});
that._preventChange = true;
} else {
currentTarget.off(CLICK + NS);
that._preventChange = false;
}
}
that._clickTarget = node;
that.current(node);
},
_focusable: function(node) {
return node && node.length && node.is(":visible") && !node.find(".k-treeview-leaf").first().hasClass(DISABLED);
},
_focus: function() {
var current = this.select(),
clickTarget = this._clickTarget;
// suppress initial focus state on touch devices (until keyboard is used)
if (kendo.support.touch) {
return;
}
if (clickTarget && clickTarget.length) {
current = clickTarget;
}
if (!this._focusable(current)) {
current = this.current();
}
if (!this._focusable(current)) {
current = this._nextVisible($());
}
this.current(current);
},
focus: function() {
var wrapper = this.wrapper,
scrollContainer = wrapper[0],
containers = [],
offsets = [],
documentElement = document.documentElement,
i;
do {
scrollContainer = scrollContainer.parentNode;
if (scrollContainer.scrollHeight > scrollContainer.clientHeight) {
containers.push(scrollContainer);
offsets.push(scrollContainer.scrollTop);
}
} while (scrollContainer != documentElement);
kendo.focusElement(wrapper);
for (i = 0; i < containers.length; i++) {
containers[i].scrollTop = offsets[i];
}
},
_blur: function() {
this.current().find(".k-treeview-leaf").first().removeClass("k-focus");
},
_enabled: function(node) {
return !node.children("div").children(".k-treeview-leaf").hasClass(DISABLED);
},
parent: function(node) {
var wrapperRe = /\bk-treeview\b(?!-)/,
itemRe = /\bk-treeview-item\b/,
result,
skipSelf;
if (typeof node == STRING) {
node = this.element.find(node);
}
if (!isDomElement(node)) {
node = node[0];
}
skipSelf = itemRe.test(node.className);
do {
node = node.parentNode;
if (itemRe.test(node.className)) {
if (skipSelf) {
result = node;
} else {
skipSelf = true;
}
}
} while (!wrapperRe.test(node.className) && !result);
return $(result);
},
_nextVisible: function(node) {
var that = this,
expanded = that._expanded(node),
result;
function nextParent(node) {
while (node.length && !node.next().length) {
node = that.parent(node);
}
if (node.next().length) {
return node.next();
} else {
return node;
}
}
if (!node.length || !node.is(":visible")) {
result = that.root.children().eq(0);
} else if (expanded) {
result = subGroup(node).children().first();
// expanded node with no children
if (!result.length) {
result = nextParent(node);
}
} else {
result = nextParent(node);
}
return result;
},
_previousVisible: function(node) {
var that = this,
lastChild,
result;
if (!node.length || node.prev().length) {
if (node.length) {
result = node.prev();
} else {
result = that.root.children().last();
}
while (that._expanded(result)) {
lastChild = subGroup(result).children().last();
if (!lastChild.length) {
break;
}
result = lastChild;
}
} else {
result = that.parent(node) || node;
}
return result;
},
scrollTo: function(item) {
if (item && item.length > 0) {
item[0].scrollIntoView({ block: "nearest" });
}
},
_keydown: function(e) {
var that = this,
key = e.keyCode,
target,
focused = that.current(),
expanded = that._expanded(focused),
checkbox = focused.find(".k-checkbox-wrap").first().find(":checkbox"),
rtl = kendo.support.isRtl(that.element);
if (e.target != e.currentTarget) {
return;
}
if ((!rtl && key == keys.RIGHT) || (rtl && key == keys.LEFT)) {
if (expanded) {
target = that._nextVisible(focused);
} else if (!focused.find(".k-treeview-leaf").first().hasClass(DISABLED)) {
that.expand(focused);
}
} else if ((!rtl && key == keys.LEFT) || (rtl && key == keys.RIGHT)) {
if (expanded && !focused.find(".k-treeview-leaf").first().hasClass(DISABLED)) {
that.collapse(focused);
} else {
target = that.parent(focused);
if (!that._enabled(target)) {
target = undefined$1;
}
}
} else if (key == keys.DOWN) {
target = that._nextVisible(focused);
} else if (key == keys.UP) {
target = that._previousVisible(focused);
} else if (key == keys.HOME) {
target = that._nextVisible($());
} else if (key == keys.END) {
target = that._previousVisible($());
} else if (key == keys.ENTER && !focused.find(".k-treeview-leaf").first().hasClass(DISABLED)) {
if (!focused.find(".k-treeview-leaf").first().hasClass("k-selected")) {
if (!that._trigger(SELECT, focused)) {
that.select(focused);
}
}
} else if (key == keys.SPACEBAR && checkbox.length) {
if (!focused.find(".k-treeview-leaf").first().hasClass(DISABLED)) {
checkbox.prop(CHECKED, !checkbox.prop(CHECKED))
.data(INDETERMINATE, false)
.prop(INDETERMINATE, false);
that._checkboxChange({ target: checkbox });
}
target = focused;
}
if (target) {
e.preventDefault();
if (focused[0] != target[0]) {
that._trigger(NAVIGATE, target);
that.current(target);
that.scrollTo(target);
}
}
},
_keypress: function(e) {
var that = this;
var delay = 300;
var focusedNode = that.current().get(0);
var matchToFocus;
var key = e.key;
var isPrintable = key.length === 1;
if (!isPrintable) {
return;
}
if (!that._match) {
that._match = "";
}
that._match += key;
clearTimeout(that._matchTimer);
that._matchTimer = setTimeout(function() {
that._match = "";
}, delay);
matchToFocus = focusedNode &&
that._matchNextByText(
Array.prototype.indexOf.call(that.element.find(".k-treeview-item"),
focusedNode), that._match
);
if (!matchToFocus.length) {
matchToFocus = that._matchNextByText(-1, that._match);
}