@progress/kendo-ui
Version:
This package is part of the [Kendo UI for jQuery](http://www.telerik.com/kendo-ui) suite.
553 lines (552 loc) • 22.8 kB
JavaScript
Object.defineProperties(exports, {
__esModule: { value: true },
[Symbol.toStringTag]: { value: "Module" }
});
require("./kendo.icons.js");
require("./kendo.userevents.js");
//#region ../src/kendo.drawer.js
const __meta__ = {
id: "drawer",
name: "Drawer",
category: "web",
description: "The Kendo Drawer widget provides slide to reveal sidebar",
depends: ["userevents", "icons"]
};
(function($, undefined) {
const kendo = window.kendo, Widget = kendo.ui.Widget, SHOW = "show", HIDE = "hide", FOCUSED = "k-focus", keys = kendo.keys, ITEMCLICK = "itemClick", KENDO_KEYDOWN = "kendoKeydown", TABINDEX = "tabIndex", PUSH = "push", OVERLAY = "overlay", LEFT = "left", RIGHT = "right", DRAWER_ITEMS_CLASS = "k-drawer-items";
const Drawer = kendo.ui.Widget.extend({
init: function(element, options) {
const that = this;
let userEvents;
that._originalItems = options && options.items;
Widget.fn.init.call(this, element, options);
options = that.options;
that._element(element);
that._wrapper(element);
that._navigatable();
that.position();
that._mode();
if (options.mini) that._miniMode();
that._initDrawerItems();
if (options.mini && options.mode != PUSH) that._setBodyOffset();
userEvents = this.userEvents = new kendo.UserEvents(options.mode != PUSH ? $(document.body) : this.drawerContainer, {
fastTap: true,
allowSelection: true
});
that.tap = function(e) {
let isParentItem = false;
if ($.contains(that.drawerItemsWrapper.filter(".k-drawer-items")[0], e.event.target)) {
const tappedItem = $(e.event.target).closest("[data-role='drawer-item']");
isParentItem = tappedItem.length > 0 && tappedItem.find(".k-drawer-toggle").length > 0;
that._itemClick(e);
}
if (!isParentItem && options.autoCollapse && that.visible && !that.trigger("hide", { sender: this })) {
that.hide();
e.preventDefault();
}
};
if (this.options.swipeToOpen) {
userEvents.bind("start", (e) => that._start(e));
userEvents.bind("move", (e) => that._update(e));
userEvents.bind("end", (e) => that._end(e));
userEvents.bind("tap", that.tap);
} else userEvents.bind("press", that.tap);
if (options.minHeight && options.mode == PUSH) that.drawerContainer.css("min-height", options.minHeight);
if (that._showWatermarkOverlay) that._showWatermarkOverlay(that.drawerContainer[0]);
if (options.expanded) {
that._removeTransition();
that.show();
}
kendo.ui.Widget.fn.endInit.call(that);
},
_element: function() {
const that = this;
const element = that.element;
const options = that.options;
that.contentElement = element.children().wrapAll("<div class='k-drawer-content'></div>").parent();
if (options.template instanceof Function) that.drawerElement = $(options.template());
else if (options.template) that.drawerElement = $(options.template);
else if (options.items && options.items.length) that.drawerElement = $(that._renderItems(options.items, 0));
else that.drawerElement = $(options.template);
element.addClass("k-drawer");
},
_renderItems: function(items, level) {
const renderInline = arguments[2] === true;
const isMini = arguments[3] === true;
const html = [];
if (!renderInline) html.push("<ul class='k-drawer-items'>");
items.forEach((item) => {
item = item || {};
if (item.separator) {
html.push("<li data-role='drawer-separator'></li>");
return;
}
const itemTemplate = isMini ? item.miniTemplate : item.template;
const hasChildren = item.items && item.items.length;
if (itemTemplate instanceof Function) {
html.push(itemTemplate(item));
if (hasChildren) html.push(this._renderItems(item.items, level + 1, true, isMini));
return;
}
let icon = "";
if (item.icon) icon = kendo.ui.icon({ icon: item.icon });
const classNames = [];
let disabledAttribute = "";
let toggleIcon = "";
if (item.enabled === false) {
classNames.push("k-disabled");
disabledAttribute = " aria-disabled='true'";
}
if (item.cssClass) classNames.push(kendo.htmlEncode(item.cssClass));
if (hasChildren) toggleIcon = `<span class='k-spacer'></span><span class='k-drawer-toggle'>${kendo.ui.icon({ icon: this._hasSelectedDescendant(item) ? "chevron-up" : "chevron-down" })}</span>`;
const classAttribute = classNames.length ? ` class='${classNames.join(" ")}'` : "";
const itemText = item.text != null ? item.text : "";
html.push(`<li data-role='drawer-item' data-level='${level}'${classAttribute}${disabledAttribute}>${icon}${isMini ? "" : `<span class='k-item-text'>${kendo.htmlEncode(itemText)}</span>`}${toggleIcon}</li>`);
if (hasChildren) html.push(this._renderItems(item.items, level + 1, true, isMini));
});
if (!renderInline) html.push("</ul>");
return html.join("");
},
_generatedItems: function(items) {
let generatedItems = [];
(items || []).forEach((item) => {
item = item || {};
if (!item.separator) generatedItems.push(item);
if (item.items && item.items.length) generatedItems = generatedItems.concat(this._generatedItems(item.items));
});
return generatedItems;
},
_itemMapEntry: function(item) {
return (this._itemsMap || []).find((entry) => entry.element === item[0]);
},
_hasSelectedDescendant: function(item) {
return (item && item.items || []).some((child) => {
child = child || {};
return !child.separator && (child.selected || this._hasSelectedDescendant(child));
});
},
_navigatable: function() {
const element = this.element;
element.find("[data-role='drawer-item']").first().parent().attr("role", "menubar").attr("aria-orientation", "vertical");
if (!this.options.navigatable) return;
element.attr(TABINDEX, 0).on("focus.kendoDrawer", this._focus.bind(this)).on("focusout.kendoDrawer", this._blur.bind(this)).on("keydown.kendoDrawer", this, this._keyDown.bind(this));
},
_blur: function() {
if (this._current) this._current.removeClass(FOCUSED);
},
_focus: function() {
this._setCurrent(this._current ? this._current : this.drawerItemsWrapper.find("[data-role='drawer-item']").eq(0));
},
_setCurrent: function(current) {
const id = kendo.guid();
const next = $(current);
if (this._current) {
$(this._current).removeClass(FOCUSED).removeAttr("id");
this.drawerItemsWrapper.removeAttr("aria-activedescendant");
}
next.attr("id", id).addClass(FOCUSED);
this.drawerItemsWrapper.attr("aria-activedescendant", id);
this._current = next;
},
_keyDown: function(e) {
let handled = false;
const current = this._current;
let next;
if (e.keyCode == keys.UP) {
handled = true;
next = current.prevAll("[data-role='drawer-item']").first();
if (next.length) this._setCurrent(next);
else this._setCurrent(current.parent().find("[data-role='drawer-item']").last());
}
if (e.keyCode == keys.DOWN) {
handled = true;
next = current.nextAll("[data-role='drawer-item']").first();
if (next.length) this._setCurrent(next);
else this._setCurrent(current.parent().find("[data-role='drawer-item']").first());
}
if (e.keyCode == keys.HOME) {
handled = true;
this._setCurrent(this.drawerItemsWrapper.find("[data-role='drawer-item']").eq(0));
}
if (e.keyCode == keys.END) {
handled = true;
this._setCurrent(this.drawerItemsWrapper.find("[data-role='drawer-item']").last());
}
if (e.keyCode == keys.SPACEBAR || e.keyCode == keys.ENTER) {
handled = true;
this.tap({
event: { target: current[0] },
preventDefault: $.noop
});
}
if (e.keyCode == keys.ESC) {
handled = true;
this.hide();
}
if (handled) e.preventDefault();
},
_wrapper: function() {
const options = this.options;
const drawerElement = this.drawerElement;
const element = this.element;
const contentElement = this.contentElement;
const drawerItemsWrapper = this.drawerItemsWrapper = drawerElement;
const drawerWrapper = this.drawerWrapper = drawerItemsWrapper.wrapAll("<div class='k-drawer-wrapper'></div>").parent();
const drawerContainer = this.drawerContainer = element.wrap("<div class='k-drawer-container'></div>").parent();
drawerElement.filter("ul").addClass(DRAWER_ITEMS_CLASS);
if (options.mini) {
if (options.mini.width) drawerWrapper.width(options.mini.width);
} else drawerWrapper.width(0);
drawerContainer.append(contentElement);
element.append(drawerWrapper);
},
_addTransition: function() {
this.drawerWrapper.css("transition", "all .3s ease-out");
},
_removeTransition: function() {
this.drawerWrapper.css("transition", "none");
},
_setBodyOffset: function() {
const overlayMiniOffset = this.element.outerWidth();
if (this.leftPositioned) $(document.body).css("padding-left", overlayMiniOffset);
else $(document.body).css("padding-right", overlayMiniOffset);
},
_initDrawerItems: function() {
const options = this.options;
const drawerItemsWrapper = this.drawerItemsWrapper;
const drawerItems = drawerItemsWrapper.find("[data-role='drawer-item']");
const separatorItems = drawerItemsWrapper.find("[data-role='drawer-separator']");
let selectedItemIndex = -1;
let generatedItems;
const generatedMiniItems = !!this._miniTemplate && !!options.items && options.items.length && !options.template && !(options.mini && options.mini.template);
drawerItems.addClass("k-drawer-item").attr("role", "menuitem");
separatorItems.addClass("k-drawer-item k-drawer-separator").attr("role", "separator");
this._itemsMap = null;
if (options.items && options.items.length && !options.template) {
generatedItems = this._generatedItems(this._originalItems || options.items);
if (!(options.mini && options.mini.template)) this._itemsMap = [];
drawerItems.each((index, element) => {
const dataItem = generatedItems[index];
if (!dataItem) return;
if (dataItem.attr && !(generatedMiniItems && dataItem.miniTemplate instanceof Function || !generatedMiniItems && dataItem.template instanceof Function)) {
const attrCopy = $.extend({}, dataItem.attr);
if (attrCopy["class"]) {
$(element).addClass(attrCopy["class"]);
delete attrCopy["class"];
}
$(element).attr(attrCopy);
}
if (this._itemsMap) this._itemsMap.push({
element,
dataItem
});
if (selectedItemIndex < 0 && dataItem.selected) selectedItemIndex = index;
});
if (selectedItemIndex >= 0 && !(this._selectedItemIndex >= 0)) this._selectedItemIndex = selectedItemIndex;
}
this._toggleLevelClasses(!!this.visible);
if (options.items && options.items.length && !options.template) {
this._collapseAllChildren(drawerItems);
if (this._itemsMap) drawerItems.each((i, item) => {
const entry = this._itemMapEntry($(item));
if (entry && entry.dataItem && entry.dataItem.expanded) this._expandItem($(item), drawerItems, i);
});
if (this._selectedItemIndex >= 0) this._expandAncestors(drawerItems, this._selectedItemIndex);
}
drawerItems.each((i, item) => {
const dataItemText = generatedMiniItems && generatedItems[i] && generatedItems[i].text;
item.setAttribute("aria-label", dataItemText || item.textContent.trim());
});
if (this._selectedItemIndex >= 0) {
drawerItems.removeClass("k-selected");
drawerItems.eq(this._selectedItemIndex).addClass("k-selected");
}
},
_toggleLevelClasses: function(flag) {
this.drawerItemsWrapper.find("[data-role='drawer-item']").each((i, item) => {
const levelClass = "k-level-" + ($(item).data("level") || 0);
$(item).toggleClass(levelClass, flag);
});
},
_mode: function() {
const options = this.options;
const drawerContainer = this.drawerContainer;
if (options.mode == PUSH) drawerContainer.addClass("k-drawer-push");
else {
drawerContainer.addClass("k-drawer-overlay");
const overlayContainer = this.overlayContainer = $("<div class=\"k-overlay\"></div>");
overlayContainer.hide();
drawerContainer.prepend(overlayContainer);
}
},
_miniMode: function() {
const options = this.options;
const drawerContainer = this.drawerContainer;
const miniWidth = options.mini.width;
let miniTemplate = this._miniTemplate = options.mini.template;
const drawerItemsWrapper = this.drawerItemsWrapper;
const drawerWrapper = this.drawerWrapper;
drawerContainer.addClass("k-drawer-mini");
if (!miniTemplate && options.items && options.items.length && !options.template) miniTemplate = this._miniTemplate = this._renderItems(options.items, 0, true, true);
if (miniTemplate) if (miniTemplate instanceof Function) drawerItemsWrapper.html($(miniTemplate()));
else drawerItemsWrapper.html($(miniTemplate));
if (miniWidth) drawerWrapper.width(miniWidth);
this.minWidth = options.mini.width || this.drawerWrapper.width();
},
setOptions: function(options) {
const that = this;
let hasItems;
let itemContent;
let isMiniState;
let drawerItems;
Widget.fn.setOptions.call(that, options);
if (!("items" in options)) return;
that._originalItems = options.items;
if (that.options.template) return;
hasItems = that.options.items && that.options.items.length;
itemContent = hasItems ? that._renderItems(that.options.items, 0, true) : "";
isMiniState = that.options.mini && that.drawerContainer.hasClass("k-drawer-mini");
if (that.options.mini) if (that.options.mini.template) that._miniTemplate = that.options.mini.template;
else that._miniTemplate = hasItems ? that._renderItems(that.options.items, 0, true, true) : "";
else that._miniTemplate = null;
if (isMiniState && that._miniTemplate) if (that._miniTemplate instanceof Function) that.drawerItemsWrapper.html($(that._miniTemplate()));
else that.drawerItemsWrapper.html($(that._miniTemplate));
else that.drawerItemsWrapper.html(itemContent);
that._current = null;
that._selectedItemIndex = -1;
that._itemsMap = null;
that._initDrawerItems();
drawerItems = that.drawerItemsWrapper.find("[data-role='drawer-item']");
drawerItems.removeClass("k-selected");
that._selectItem();
},
show: function() {
const drawerWrapper = this.drawerWrapper;
const drawerContainer = this.drawerContainer;
const options = this.options;
const isExpanded = drawerContainer.hasClass("k-drawer-expanded");
const miniTemplate = this._miniTemplate;
const drawerItemsWrapper = this.drawerItemsWrapper;
if (!isExpanded) {
drawerContainer.addClass("k-drawer-expanded");
this.visible = true;
}
if (miniTemplate) {
if (options.template) {
const tpl = options.template instanceof Function ? options.template() : options.template;
drawerItemsWrapper.html(tpl);
} else drawerItemsWrapper.html(this._renderItems(this._originalItems || options.items, 0, true));
this._initDrawerItems();
this._selectItem();
}
drawerWrapper.width(options.width);
if (options.mini) drawerContainer.removeClass("k-drawer-mini");
if (options.mode === OVERLAY) {
this.overlayContainer.show();
this.visible = true;
}
this._toggleLevelClasses(true);
},
hide: function() {
const drawerWrapper = this.drawerWrapper;
const drawerContainer = this.drawerContainer;
const options = this.options;
const drawerItemsWrapper = this.drawerItemsWrapper;
const miniTemplate = this._miniTemplate;
const miniWidth = options.mini && options.mini.width;
this._addTransition();
if (this._miniTemplate) {
drawerItemsWrapper.html(miniTemplate);
this._initDrawerItems();
this._selectItem();
}
if (options.mini) {
drawerContainer.addClass("k-drawer-mini");
if (miniWidth) drawerWrapper.width(miniWidth);
else drawerWrapper.width("");
} else drawerWrapper.width(0);
if (this.visible) {
drawerContainer.removeClass("k-drawer-expanded");
this.visible = false;
}
if (options.mode === OVERLAY) this.overlayContainer.hide();
this._toggleLevelClasses(false);
},
position: function(value) {
const options = this.options;
const position = value || options.position;
if (position == RIGHT) {
this.element.removeClass("k-drawer-start");
this.element.addClass("k-drawer-end");
} else {
this.element.removeClass("k-drawer-end");
this.element.addClass("k-drawer-start");
}
this.leftPositioned = position === LEFT;
},
_start: function(e) {
const options = this.options;
const drawerItemsWrapper = this.drawerItemsWrapper;
const userEvents = e.sender;
if (Math.abs(e.x.velocity) < Math.abs(e.y.velocity) || kendo.triggeredByInput(e.event)) {
userEvents.cancel();
return;
}
if (this.drawerMini) drawerItemsWrapper.html(this.drawerElement);
this._removeTransition();
if (options.mode != PUSH) this.overlayContainer.show();
},
_update: function(e) {
if (this.options.mode == PUSH) this._push(e);
else this._overlay(e);
},
_end: function(e) {
const velocity = e.x.velocity;
const options = this.options;
const pastHalf = this.drawerWrapper.width() > options.width / 2;
const velocityThreshold = .8;
let shouldShow;
this._addTransition();
if (this.leftPositioned) shouldShow = velocity > -.8 && (velocity > velocityThreshold || pastHalf);
else shouldShow = velocity < velocityThreshold && (velocity < -.8 || pastHalf);
if (shouldShow) if (this.trigger("show", { sender: this })) {
e.preventDefault();
this.hide();
} else this.show();
else if (this.trigger("hide", { sender: this })) {
e.preventDefault();
this.show();
} else this.hide();
},
_overlay: function(moveEventArgs) {
const options = this.options;
const minWidth = options.mini && options.mini.width || this.minWidth || 0;
const drawerWrapper = this.drawerWrapper;
const updatedPosition = drawerWrapper.width() + (this.leftPositioned ? moveEventArgs.x.delta : -moveEventArgs.x.delta);
const limitedPosition = Math.min(Math.max(updatedPosition, minWidth), options.width);
moveEventArgs.event.preventDefault();
moveEventArgs.event.stopPropagation();
drawerWrapper.width(limitedPosition);
},
_push: function(moveEventArgs) {
const options = this.options;
const minWidth = options.mini && options.mini.width || this.minWidth || 0;
const drawerWrapper = this.drawerWrapper;
const updatedPosition = drawerWrapper.width() + (this.leftPositioned ? moveEventArgs.x.delta : -moveEventArgs.x.delta);
const limitedPosition = Math.min(Math.max(updatedPosition, minWidth), options.width);
moveEventArgs.event.preventDefault();
moveEventArgs.event.stopPropagation();
drawerWrapper.width(limitedPosition);
},
_selectItem: function(item) {
const drawerItems = this.drawerItemsWrapper.find("[data-role='drawer-item']");
let itemMapEntry;
let selectedItemIndex;
if (item) {
item.addClass("k-selected");
itemMapEntry = this._itemMapEntry(item);
this.trigger("itemClick", {
item,
dataItem: itemMapEntry && itemMapEntry.dataItem,
sender: this
});
this._selectedItemIndex = drawerItems.index(item);
return;
}
selectedItemIndex = this._selectedItemIndex;
if (selectedItemIndex >= 0) drawerItems.eq(selectedItemIndex).addClass("k-selected");
},
_collapseAllChildren: function(drawerItems) {
drawerItems.each((_, item) => {
if (parseInt($(item).data("level") || 0, 10) > 0) $(item).hide();
});
},
_expandItem: function(item, drawerItems, itemIndex) {
const level = parseInt(item.data("level") || 0, 10);
item.addClass("k-expanded");
const toggleChrome = item.find(".k-drawer-toggle");
if (toggleChrome.length) toggleChrome.html(kendo.ui.icon({ icon: "chevron-up" }));
for (let i = itemIndex + 1; i < drawerItems.length; i++) {
const childItem = drawerItems.eq(i);
const childLevel = parseInt(childItem.data("level") || 0, 10);
if (childLevel <= level) break;
if (childLevel === level + 1) childItem.show();
}
},
_expandAncestors: function(drawerItems, selectedIndex) {
const selectedLevel = parseInt(drawerItems.eq(selectedIndex).data("level") || 0, 10);
if (selectedLevel === 0) return;
let currentLevel = selectedLevel;
for (let i = selectedIndex - 1; i >= 0; i--) {
const item = drawerItems.eq(i);
const level = parseInt(item.data("level") || 0, 10);
if (level < currentLevel) {
this._expandItem(item, drawerItems, i);
currentLevel = level;
if (level === 0) break;
}
}
},
_toggleChildren: function(item) {
const level = parseInt(item.data("level") || 0, 10);
const drawerItems = this.drawerItemsWrapper.find("[data-role='drawer-item']");
const itemIndex = drawerItems.index(item);
const isExpanded = item.hasClass("k-expanded");
const toggleChrome = item.find(".k-drawer-toggle");
if (isExpanded) {
item.removeClass("k-expanded");
for (let i = itemIndex + 1; i < drawerItems.length; i++) {
const childItem = drawerItems.eq(i);
if (parseInt(childItem.data("level") || 0, 10) <= level) break;
childItem.hide();
if (childItem.hasClass("k-expanded")) {
childItem.removeClass("k-expanded");
childItem.find(".k-drawer-toggle").html(kendo.ui.icon({ icon: "chevron-down" }));
}
}
if (toggleChrome.length) toggleChrome.html(kendo.ui.icon({ icon: "chevron-down" }));
} else this._expandItem(item, drawerItems, itemIndex);
},
_itemClick: function(e) {
const that = this;
const item = $(e.event.target).closest("[data-role='drawer-item']");
if (!item || !item.length || item.hasClass("k-disabled")) return;
that.drawerItemsWrapper.find("[data-role='drawer-item']").removeClass("k-selected");
that._selectItem(item);
if (that.options.navigatable) that._setCurrent(item);
if (!that.options.template && item.find(".k-drawer-toggle").length) that._toggleChildren(item);
},
destroy: function() {
if (this.options.mode != PUSH) if (this.leftPositioned) $(document.body).css("padding-left", 0);
else $(document.body).css("padding-right", 0);
Widget.fn.destroy.call(this);
this.userEvents.destroy();
kendo.destroy(this.element);
this.element = this.drawerWrapper = this.drawerElement = this.drawerContainer = this.drawerItemsWrapper = this._itemsMap = this._miniTemplate = this._originalItems = null;
},
options: {
name: "Drawer",
autoCollapse: true,
expanded: false,
items: null,
position: LEFT,
mode: "overlay",
swipeToOpen: true,
width: 280,
mini: false,
navigatable: false,
template: ""
},
events: [
HIDE,
SHOW,
ITEMCLICK,
KENDO_KEYDOWN
]
});
kendo.ui.plugin(Drawer);
})(window.kendo.jQuery);
var kendo_drawer_default = kendo;
//#endregion
exports.__meta__ = __meta__;
exports.default = kendo_drawer_default;