| Current Path : /var/www/element/data/www/revenuestory.ru/bitrix/js/ui/entity-selector/src/item/ |
| Current File : /var/www/element/data/www/revenuestory.ru/bitrix/js/ui/entity-selector/src/item/item-node.js |
import { ajax as Ajax, Cache, Dom, Runtime, Tag, Type, Browser, Event } from 'main.core';
import { OrderedArray } from 'main.core.collections';
import { Loader } from 'main.loader';
import ItemNodeComparator from './item-node-comparator';
import Highlighter from '../search/highlighter';
import ItemBadge from './item-badge';
import MatchField from '../search/match-field';
import TextNode from '../common/text-node';
import Animation from '../common/animation';
import Item from './item';
import encodeUrl from '../common/encode-url';
import type Tab from '../dialog/tabs/tab';
import type Dialog from '../dialog/dialog';
import type { ItemOptions } from './item-options';
import type { ItemNodeOptions } from './item-node-options';
import type { ItemBadgeOptions } from './item-badge-options';
import type { TextNodeOptions } from '../common/text-node-options';
import type { CaptionOptions } from './caption-options';
import type { BadgesOptions } from './badges-options';
import type { AvatarOptions } from './avatar-options';
export class RenderMode
{
static PARTIAL = 'partial';
static OVERRIDE = 'override';
}
export default class ItemNode
{
item: Item = null;
tab: Tab = null;
cache = new Cache.MemoryCache();
parentNode: ItemNode = null;
children: OrderedArray<ItemNode> = null;
childItems: WeakMap<Item, ItemNode> = new WeakMap(); // for the fast access
loaded: boolean = false;
dynamic: boolean = false;
dynamicPromise: ?Promise = null;
loader: Loader = null;
open: boolean = false;
autoOpen: boolean = false;
focused: boolean = false;
renderMode: RenderMode = RenderMode.PARTIAL;
title: ?TextNode = null;
subtitle: ?TextNode = null;
supertitle: ?TextNode = null;
caption: ?TextNode = null;
captionOptions: CaptionOptions = {};
avatar: ?string = null;
avatarOptions: ?AvatarOptions = null;
link: ?string = null;
linkTitle: ?TextNode = null;
textColor: ?string = null;
badges: ItemBadgeOptions[] = null;
badgesOptions: BadgesOptions = {};
hidden: boolean = false;
highlights: MatchField[] = [];
rendered: false;
renderWithDebounce = Runtime.debounce(this.render, 50, this);
constructor(item: Item, nodeOptions: ItemNodeOptions)
{
const options: ItemNodeOptions = Type.isPlainObject(nodeOptions) ? nodeOptions : {};
if (Type.isObject(item))
{
this.item = item;
}
let comparator = null;
if (Type.isFunction(options.itemOrder))
{
comparator = options.itemOrder;
}
else if (Type.isPlainObject(options.itemOrder))
{
comparator = ItemNodeComparator.makeMultipleComparator(options.itemOrder);
}
this.children = new OrderedArray(comparator);
this.renderMode = options.renderMode === RenderMode.OVERRIDE ? RenderMode.OVERRIDE : RenderMode.PARTIAL;
if (this.renderMode === RenderMode.OVERRIDE)
{
this.setTitle('');
this.setSubtitle('');
this.setSupertitle('');
this.setCaption('');
this.setLinkTitle('');
this.avatar = '';
this.avatarOptions = {
bgSize: null,
bgColor: null,
bgImage: null,
border: null,
borderRadius: null,
};
this.textColor = '';
this.link = '';
this.badges = [];
this.captionOptions = {
fitContent: null,
maxWidth: null,
};
this.badgesOptions = {
fitContent: null,
maxWidth: null,
};
}
this.setTitle(options.title);
this.setSubtitle(options.subtitle);
this.setSupertitle(options.supertitle);
this.setCaption(options.caption);
this.setCaptionOptions(options.captionOptions);
this.setAvatar(options.avatar);
this.setAvatarOptions(options.avatarOptions);
this.setTextColor(options.textColor);
this.setLink(options.link);
this.setLinkTitle(options.linkTitle);
this.setBadges(options.badges);
this.setBadgesOptions(options.badgesOptions);
this.setDynamic(options.dynamic);
this.setOpen(options.open);
}
getItem(): Item
{
return this.item;
}
isRoot(): boolean
{
return this.getParentNode() === null;
}
getDialog(): Dialog
{
return this.getTab().getDialog();
}
setTab(tab: Tab): void
{
this.tab = tab;
}
getTab(): Tab
{
return this.tab;
}
getParentNode(): ?ItemNode
{
return this.parentNode;
}
setParentNode(parentNode: ItemNode): void
{
this.parentNode = parentNode;
}
getNextSibling(): ?ItemNode
{
if (!this.getParentNode())
{
return null;
}
const siblings = this.getParentNode().getChildren();
const index = siblings.getIndex(this);
return siblings.getByIndex(index + 1);
}
getPreviousSibling(): ?ItemNode
{
if (!this.getParentNode())
{
return null;
}
const siblings = this.getParentNode().getChildren();
const index = siblings.getIndex(this);
return siblings.getByIndex(index - 1);
}
addChildren(children: ItemOptions[]): void
{
if (!Type.isArray(children))
{
return;
}
children.forEach((childOptions: ItemOptions) => {
delete childOptions.tabs;
const childItem = this.getDialog().addItem(childOptions);
const childNode = this.addItem(childItem, childOptions.nodeOptions);
childNode.addChildren(childOptions.children);
});
}
addChild(child: ItemNode): ItemNode
{
if (!(child instanceof ItemNode))
{
throw new Error('EntitySelector.ItemNode: an item must be an instance of EntitySelector.ItemNode.');
}
if (this.isChildOf(child) || child === this)
{
throw new Error('EntitySelector.ItemNode: a child item cannot be a parent of current item.');
}
if (this.getChildren().has(child) || this.childItems.has(child.getItem()))
{
return null;
}
this.getChildren().add(child);
this.childItems.set(child.getItem(), child);
child.setTab(this.getTab());
child.setParentNode(this);
if (this.isRendered())
{
this.renderWithDebounce();
}
return child;
}
getDepthLevel(): number
{
return this.isRoot() ? 0 : this.getParentNode().getDepthLevel() + 1;
}
addItem(item: Item, nodeOptions: ItemNodeOptions): ItemNode
{
let itemNode = this.childItems.get(item);
if (!itemNode)
{
itemNode = item.createNode(nodeOptions);
this.addChild(itemNode);
}
return itemNode;
}
addItems(items: Item[] | Array<[Item, ItemNodeOptions]>): void
{
if (Type.isArray(items))
{
this.disableRender();
items.forEach((item: Item | [Item, ItemNodeOptions]) => {
if (Type.isArray(item) && item.length === 2)
{
this.addItem(item[0], item[1]);
}
else if (item instanceof Item)
{
this.addItem(item);
}
});
this.enableRender();
if (this.isRendered())
{
this.renderWithDebounce();
}
}
}
hasItem(item: Item): boolean
{
return this.childItems.has(item);
}
removeChild(child: ItemNode): boolean
{
if (!this.getChildren().has(child))
{
return false;
}
child.removeChildren();
if (child.isFocused())
{
child.unfocus();
}
child.setParentNode(null);
child.getItem().removeNode(child);
this.getChildren().delete(child);
this.childItems.delete(child.getItem());
if (this.isRendered())
{
Dom.remove(child.getOuterContainer());
}
return true;
}
removeChildren(): void
{
if (!this.hasChildren())
{
return;
}
this.getChildren().forEach((node: ItemNode) => {
node.removeChildren();
if (node.isFocused())
{
node.unfocus();
}
node.setParentNode(null);
node.getItem().removeNode(node);
});
this.getChildren().clear();
this.childItems = new WeakMap();
if (this.isRendered())
{
if (Browser.isIE())
{
Dom.clean(this.getChildrenContainer());
}
else
{
this.getChildrenContainer().textContent = '';
}
}
}
hasChild(child: ItemNode): boolean
{
return this.getChildren().has(child);
}
isChildOf(parent: ItemNode): boolean
{
let parentNode = this.getParentNode();
while (parentNode !== null)
{
if (parentNode === parent)
{
return true;
}
parentNode = parentNode.getParentNode();
}
return false;
}
getFirstChild(): ?ItemNode
{
return this.children.getFirst();
}
getLastChild(): ?ItemNode
{
return this.children.getLast();
}
getChildren(): OrderedArray<ItemNode>
{
return this.children;
}
hasChildren(): boolean
{
return this.children.count() > 0;
}
loadChildren(): Promise
{
if (!this.isDynamic())
{
throw new Error('EntitySelector.ItemNode.loadChildren: an item node is not dynamic.');
}
if (this.dynamicPromise)
{
return this.dynamicPromise;
}
this.dynamicPromise = Ajax.runAction('ui.entityselector.getChildren', {
json: {
parentItem: this.getItem().getAjaxJson(),
dialog: this.getDialog().getAjaxJson()
},
getParameters: {
context: this.getDialog().getContext()
}
});
this.dynamicPromise.then((response) => {
if (response && response.data && Type.isPlainObject(response.data.dialog))
{
this.addChildren(response.data.dialog.items);
this.render();
}
this.loaded = true;
});
this.dynamicPromise.catch((error) => {
this.loaded = false;
this.dynamicPromise = null;
console.error(error);
});
return this.dynamicPromise;
}
setOpen(open: boolean): void
{
if (Type.isBoolean(open))
{
if (open && this.isDynamic() && !this.isLoaded())
{
this.setAutoOpen(true);
}
else
{
this.open = open;
}
}
}
isOpen(): boolean
{
return this.open;
}
isAutoOpen(): boolean
{
return this.autoOpen && this.isDynamic() && !this.isLoaded();
}
setAutoOpen(autoOpen: boolean): void
{
if (Type.isBoolean(autoOpen))
{
this.autoOpen = autoOpen;
}
}
setDynamic(dynamic: boolean): void
{
if (Type.isBoolean(dynamic))
{
this.dynamic = dynamic;
}
}
isDynamic(): boolean
{
return this.dynamic;
}
isLoaded(): boolean
{
return this.loaded;
}
getLoader(): Loader
{
if (this.loader === null)
{
this.loader = new Loader({
target: this.getIndicatorContainer(),
size: 30
});
}
return this.loader;
}
showLoader(): void
{
void this.getLoader().show();
Dom.addClass(this.getIndicatorContainer(), 'ui-selector-item-indicator-hidden');
}
hideLoader(): void
{
void this.getLoader().hide();
Dom.removeClass(this.getIndicatorContainer(), 'ui-selector-item-indicator-hidden');
}
destroyLoader(): void
{
this.getLoader().destroy();
this.loader = null;
Dom.removeClass(this.getIndicatorContainer(), 'ui-selector-item-indicator-hidden');
}
expand(): void
{
if (this.isOpen() || (!this.hasChildren() && !this.isDynamic()))
{
return;
}
if (this.isDynamic() && !this.isLoaded())
{
this.loadChildren().then(() => {
this.destroyLoader();
this.expand();
});
this.showLoader();
return;
}
Dom.addClass(this.getOuterContainer(), 'ui-selector-item-box-open');
Dom.style(this.getChildrenContainer(), 'height', '0px');
Dom.style(this.getChildrenContainer(), 'opacity', 0);
requestAnimationFrame(() => {
requestAnimationFrame(() => {
Dom.style(this.getChildrenContainer(), 'height', `${this.getChildrenContainer().scrollHeight}px`);
Dom.style(this.getChildrenContainer(), 'opacity', 1);
Animation.handleTransitionEnd(this.getChildrenContainer(), 'height').then(() => {
Dom.style(this.getChildrenContainer(), 'height', null);
Dom.style(this.getChildrenContainer(), 'opacity', null);
Dom.addClass(this.getOuterContainer(), 'ui-selector-item-box-open');
this.setOpen(true);
});
});
});
}
collapse(): void
{
if (!this.isOpen())
{
return;
}
Dom.style(this.getChildrenContainer(), 'height', `${this.getChildrenContainer().offsetHeight}px`);
requestAnimationFrame(() => {
requestAnimationFrame(() => {
Dom.style(this.getChildrenContainer(), 'height', '0px');
Dom.style(this.getChildrenContainer(), 'opacity', 0);
Animation.handleTransitionEnd(this.getChildrenContainer(), 'height').then(() => {
Dom.style(this.getChildrenContainer(), 'height', null);
Dom.style(this.getChildrenContainer(), 'opacity', null);
Dom.removeClass(this.getOuterContainer(), 'ui-selector-item-box-open');
this.setOpen(false);
});
});
});
}
render(appendChildren = false): void
{
if (this.isRoot())
{
this.renderRoot(appendChildren);
return;
}
const titleNode = this.getTitleNode();
if (titleNode)
{
titleNode.renderTo(this.getTitleContainer());
}
else
{
this.getTitleContainer().textContent = '';
}
const supertitleNode = this.getSupertitleNode();
if (supertitleNode)
{
supertitleNode.renderTo(this.getSupertitleContainer());
}
else
{
this.getSupertitleContainer().textContent = '';
}
const subtitleNode = this.getSubtitleNode();
if (subtitleNode)
{
subtitleNode.renderTo(this.getSubtitleContainer());
}
else
{
this.getSubtitleContainer().textContent = '';
}
const captionNode = this.getCaptionNode();
if (captionNode)
{
captionNode.renderTo(this.getCaptionContainer());
}
else
{
this.getCaptionContainer().textContent = '';
}
const captionFitContent = this.getCaptionOption('fitContent');
if (Type.isBoolean(captionFitContent))
{
Dom.style(this.getCaptionContainer(), 'flex-shrink', captionFitContent ? 0 : null);
}
const captionMaxWidth = this.getCaptionOption('maxWidth');
if (Type.isString(captionMaxWidth) || Type.isNumber(captionMaxWidth))
{
Dom.style(
this.getCaptionContainer(),
'max-width',
Type.isNumber(captionMaxWidth) ? `${captionMaxWidth}px` : captionMaxWidth
);
}
if (Type.isStringFilled(this.getTextColor()))
{
this.getTitleContainer().style.color = this.getTextColor();
}
else
{
this.getTitleContainer().style.removeProperty('color');
}
const avatar = this.getAvatar();
if (Type.isStringFilled(avatar))
{
this.getAvatarContainer().style.backgroundImage = `url('${encodeUrl(avatar)}')`;
}
else
{
const bgImage = this.getAvatarOption('bgImage');
if (Type.isStringFilled(bgImage))
{
this.getAvatarContainer().style.backgroundImage = bgImage;
}
else
{
this.getAvatarContainer().style.removeProperty('background-image');
}
}
const bgColor = this.getAvatarOption('bgColor');
if (Type.isStringFilled(bgColor))
{
this.getAvatarContainer().style.backgroundColor = bgColor;
}
else
{
this.getAvatarContainer().style.removeProperty('background-color');
}
const bgSize = this.getAvatarOption('bgSize');
if (Type.isStringFilled(bgSize))
{
this.getAvatarContainer().style.backgroundSize = bgSize;
}
else
{
this.getAvatarContainer().style.removeProperty('background-size');
}
const border = this.getAvatarOption('border');
if (Type.isStringFilled(border))
{
this.getAvatarContainer().style.border = border;
}
else
{
this.getAvatarContainer().style.removeProperty('border');
}
const borderRadius = this.getAvatarOption('borderRadius');
if (Type.isStringFilled(borderRadius))
{
this.getAvatarContainer().style.borderRadius = borderRadius;
}
else
{
this.getAvatarContainer().style.removeProperty('border-radius');
}
Dom.clean(this.getBadgeContainer());
this.getBadges().forEach((badge: ItemBadge) => {
badge.renderTo(this.getBadgeContainer());
});
const badgesFitContent = this.getBadgesOption('fitContent');
if (Type.isBoolean(badgesFitContent))
{
Dom.style(this.getBadgeContainer(), 'flex-shrink', badgesFitContent ? 0 : null);
}
const badgesMaxWidth = this.getBadgesOption('maxWidth');
if (Type.isString(badgesMaxWidth) || Type.isNumber(badgesMaxWidth))
{
Dom.style(
this.getBadgeContainer(),
'max-width',
Type.isNumber(badgesMaxWidth) ? `${badgesMaxWidth}px` : badgesMaxWidth
);
}
const linkTitleNode = this.getLinkTitleNode();
if (linkTitleNode)
{
linkTitleNode.renderTo(this.getLinkTextContainer());
}
else
{
this.getLinkTextContainer().textContent = '';
}
if (this.hasChildren() || this.isDynamic())
{
Dom.addClass(this.getOuterContainer(), 'ui-selector-item-box-has-children');
if (this.getDepthLevel() >= this.getTab().getItemMaxDepth())
{
Dom.addClass(this.getOuterContainer(), 'ui-selector-item-box-max-depth');
}
}
else if (this.getOuterContainer().classList.contains('ui-selector-item-box-has-children'))
{
Dom.removeClass(
this.getOuterContainer(),
['ui-selector-item-box-has-children', 'ui-selector-item-box-max-depth']
);
}
if (this.hasChildren())
{
const hasVisibleChild = this.getChildren().getAll().some((child: ItemNode) => {
return child.isHidden() !== true;
});
if (!hasVisibleChild)
{
this.#setHidden(true);
}
}
this.toggleVisibility();
this.highlight();
this.renderChildren(appendChildren);
if (this.isAutoOpen())
{
this.setAutoOpen(false);
requestAnimationFrame(() => {
requestAnimationFrame(() => {
this.expand();
});
});
}
this.rendered = true;
}
/**
* @private
*/
renderRoot(appendChildren = false): void
{
this.renderChildren(appendChildren);
this.rendered = true;
const stub = this.getTab().getStub();
if (stub && stub.isAutoShow() && (this.getDialog().isLoaded() || !this.getDialog().hasDynamicLoad()))
{
if (this.hasChildren())
{
stub.hide();
}
else
{
stub.show();
}
}
}
/**
* @private
*/
renderChildren(appendChildren = false): void
{
if (!appendChildren)
{
if (Browser.isIE())
{
Dom.clean(this.getChildrenContainer());
}
else
{
this.getChildrenContainer().textContent = '';
}
}
if (this.hasChildren())
{
let previousSibling: ItemNode = null;
this.getChildren().forEach((child: ItemNode) => {
child.render(appendChildren);
const container = child.getOuterContainer();
if (!appendChildren)
{
Dom.append(container, this.getChildrenContainer());
}
if (!container.parentNode)
{
if (previousSibling !== null)
{
Dom.insertAfter(container, previousSibling.getOuterContainer());
}
else
{
Dom.append(container, this.getChildrenContainer());
}
}
previousSibling = child;
});
}
}
isRendered(): boolean
{
return this.rendered && this.getDialog() && this.getDialog().isRendered();
}
enableRender(): void
{
this.rendered = true;
}
disableRender(): void
{
this.rendered = false;
}
getRenderMode(): RenderMode
{
return this.renderMode;
}
isHidden(): boolean
{
return this.hidden === true || this.getItem().isHidden() === true;
}
setHidden(flag: boolean): void
{
if (!Type.isBoolean(flag) || this.isRoot())
{
return;
}
this.#setHidden(flag);
if (this.isRendered())
{
this.toggleVisibility();
let parentNode = this.getParentNode();
const isHidden = this.isHidden();
while (parentNode.isRoot() === false)
{
if (isHidden)
{
const hasVisibleChild = parentNode.getChildren().getAll().some((child: ItemNode) => {
return child.isHidden() !== true;
});
if (!hasVisibleChild)
{
parentNode.#setHidden(true);
}
parentNode.toggleVisibility();
}
else
{
parentNode.#setHidden(false);
parentNode.toggleVisibility();
if (parentNode.isHidden())
{
break;
}
}
parentNode = parentNode.getParentNode();
}
}
}
#setHidden(flag: boolean): void
{
if (Type.isBoolean(flag) && !this.isRoot())
{
this.hidden = flag;
}
}
toggleVisibility(): boolean
{
if (this.isHidden())
{
Dom.addClass(this.getOuterContainer(), '--hidden');
}
else if (this.getOuterContainer().classList.contains('--hidden'))
{
Dom.removeClass(this.getOuterContainer(), '--hidden');
}
}
getTitle(): string
{
const titleNode = this.getTitleNode();
return titleNode !== null ? titleNode.getText() : null;
}
getTitleNode(): ?TextNode
{
return this.title !== null ? this.title: this.getItem().getTitleNode();
}
setTitle(title: string | TextNodeOptions): void
{
if (Type.isString(title) || Type.isPlainObject(title))
{
this.title = new TextNode(title);
}
else if (title === null)
{
this.title = null;
}
}
getSubtitle(): ?string
{
const subtitleNode = this.getSubtitleNode();
return subtitleNode !== null ? subtitleNode.getText() : null;
}
getSubtitleNode(): ?TextNode
{
return this.subtitle !== null ? this.subtitle: this.getItem().getSubtitleNode();
}
setSubtitle(subtitle: string | TextNodeOptions): void
{
if (Type.isString(subtitle) || Type.isPlainObject(subtitle))
{
this.subtitle = new TextNode(subtitle);
}
else if (subtitle === null)
{
this.subtitle = null;
}
}
getSupertitle(): ?string
{
const supertitleNode = this.getSupertitleNode();
return supertitleNode !== null ? supertitleNode.getText() : null;
}
getSupertitleNode(): ?TextNode
{
return this.supertitle !== null ? this.supertitle: this.getItem().getSupertitleNode();
}
setSupertitle(supertitle: string | TextNodeOptions): void
{
if (Type.isString(supertitle) || Type.isPlainObject(supertitle))
{
this.supertitle = new TextNode(supertitle);
}
else if (supertitle === null)
{
this.supertitle = null;
}
}
getCaption(): ?string
{
const caption = this.getCaptionNode();
return caption !== null ? caption.getText() : null;
}
getCaptionNode(): ?TextNode
{
return this.caption !== null ? this.caption: this.getItem().getCaptionNode();
}
setCaption(caption: string | TextNodeOptions): void
{
if (Type.isString(caption) || Type.isPlainObject(caption))
{
this.caption = new TextNode(caption);
}
else if (caption === null)
{
this.caption = null;
}
}
getCaptionOption(option: string): string | boolean | number | null
{
if (!Type.isUndefined(this.captionOptions[option]))
{
return this.captionOptions[option];
}
return this.getItem().getCaptionOption(option);
}
setCaptionOption(option: string, value: string | boolean | number | null): void
{
if (Type.isStringFilled(option) && !Type.isUndefined(value))
{
this.captionOptions[option] = value;
}
}
setCaptionOptions(options: {[key: string]: any } | null): void
{
if (Type.isPlainObject(options))
{
Object.keys(options).forEach((option: string) => {
this.setCaptionOption(option, options[option]);
});
}
}
getAvatar(): ?string
{
return this.avatar !== null ? this.avatar : this.getItem().getAvatar();
}
setAvatar(avatar: ?string): void
{
if (Type.isString(avatar) || avatar === null)
{
this.avatar = avatar;
}
}
getAvatarOption(option: $Keys<AvatarOptions>): string | boolean | number | null
{
return (
this.avatarOptions === null || Type.isUndefined(this.avatarOptions[option])
? this.getItem().getAvatarOption(option)
: this.avatarOptions[option]
);
}
setAvatarOption(option: $Keys<AvatarOptions>, value: string | boolean | number | null): void
{
if (Type.isStringFilled(option) && !Type.isUndefined(value))
{
if (this.avatarOptions === null)
{
this.avatarOptions = {};
}
this.avatarOptions[option] = value;
}
}
setAvatarOptions(avatarOptions: AvatarOptions): void
{
if (Type.isPlainObject(avatarOptions))
{
Object.keys(avatarOptions).forEach((option: string) => {
this.setAvatarOption(option, avatarOptions[option]);
});
}
}
getTextColor(): ?string
{
return this.textColor !== null ? this.textColor : this.getItem().getTextColor();
}
setTextColor(textColor: ?string): void
{
if (Type.isString(textColor) || textColor === null)
{
this.textColor = textColor;
}
}
getLink(): ?string
{
return this.link !== null ? this.getItem().replaceMacros(this.link) : this.getItem().getLink();
}
setLink(link: string): void
{
if (Type.isString(link) || link === null)
{
this.link = link;
}
}
getLinkTitle(): ?string
{
const linkTitle = this.getLinkTitleNode();
return linkTitle !== null ? linkTitle.getText() : null;
}
getLinkTitleNode(): ?TextNode
{
return this.linkTitle !== null ? this.linkTitle: this.getItem().getLinkTitleNode();
}
setLinkTitle(title: string | TextNodeOptions): void
{
if (Type.isString(title) || Type.isPlainObject(title))
{
this.linkTitle = new TextNode(title);
}
else if (title === null)
{
this.linkTitle = null;
}
}
getBadges(): ItemBadge[]
{
return this.badges !== null ? this.badges : this.getItem().getBadges();
}
setBadges(badges: ?ItemBadgeOptions[]): void
{
if (Type.isArray(badges))
{
this.badges = [];
badges.forEach(badge => {
this.badges.push(new ItemBadge(badge));
});
}
else if (badges === null)
{
this.badges = null;
}
}
getBadgesOption(option: string): string | boolean | number | null
{
if (!Type.isUndefined(this.badgesOptions[option]))
{
return this.badgesOptions[option];
}
return this.getItem().getBadgesOption(option);
}
setBadgesOption(option: string, value: string | boolean | number | null): void
{
if (Type.isStringFilled(option) && !Type.isUndefined(value))
{
this.badgesOptions[option] = value;
}
}
setBadgesOptions(options: {[key: string]: any } | null): void
{
if (Type.isPlainObject(options))
{
Object.keys(options).forEach((option: string) => {
this.setBadgesOption(option, options[option]);
});
}
}
getOuterContainer(): HTMLElement
{
return this.cache.remember('outer-container', () => {
let className = '';
if (this.hasChildren() || this.isDynamic())
{
className += ' ui-selector-item-box-has-children';
if (this.getDepthLevel() >= this.getTab().getItemMaxDepth())
{
className += ' ui-selector-item-box-max-depth';
}
}
else if (this.getItem().isSelected())
{
className += ' ui-selector-item-box-selected';
}
if (this.isOpen())
{
className += ' ui-selector-item-box-open';
}
const div = document.createElement('div');
div.className = `ui-selector-item-box${className}`;
div.appendChild(this.getContainer());
div.appendChild(this.getChildrenContainer());
return div;
});
}
getChildrenContainer(): HTMLElement
{
if (this.isRoot() && this.getTab())
{
return this.getTab().getItemsContainer();
}
return this.cache.remember('children-container', () => {
const div = document.createElement('div');
div.className = 'ui-selector-item-children';
return div;
});
}
getContainer(): HTMLElement
{
return this.cache.remember('container', () => {
const div = document.createElement('div');
div.className = 'ui-selector-item';
Event.bind(div, 'click', this.handleClick.bind(this))
Event.bind(div, 'mouseenter', this.handleMouseEnter.bind(this))
Event.bind(div, 'mouseleave', this.handleMouseLeave.bind(this))
div.appendChild(this.getAvatarContainer());
div.appendChild(this.getTitlesContainer());
div.appendChild(this.getIndicatorContainer());
if (Type.isStringFilled(this.getLink()))
{
div.appendChild(this.getLinkContainer());
}
return div;
});
}
getAvatarContainer(): HTMLElement
{
return this.cache.remember('avatar', () => {
const div = document.createElement('div');
div.className = 'ui-selector-item-avatar';
return div;
});
}
getTitlesContainer(): HTMLElement
{
return this.cache.remember('titles', () => {
const div = document.createElement('div');
div.className = 'ui-selector-item-titles';
div.appendChild(this.getSupertitleContainer());
div.appendChild(this.getTitleBoxContainer());
div.appendChild(this.getSubtitleContainer());
return div;
});
}
getTitleBoxContainer(): HTMLElement
{
return this.cache.remember('title-box', () => {
const div = document.createElement('div');
div.className = 'ui-selector-item-title-box';
div.appendChild(this.getTitleContainer());
div.appendChild(this.getBadgeContainer());
div.appendChild(this.getCaptionContainer());
return div;
});
}
getTitleContainer(): HTMLElement
{
return this.cache.remember('title', () => {
const div = document.createElement('div');
div.className = 'ui-selector-item-title';
return div;
});
}
getSubtitleContainer(): HTMLElement
{
return this.cache.remember('subtitle', () => {
const div = document.createElement('div');
div.className = 'ui-selector-item-subtitle';
return div;
});
}
getSupertitleContainer(): HTMLElement
{
return this.cache.remember('supertitle', () => {
const div = document.createElement('div');
div.className = 'ui-selector-item-supertitle';
return div;
});
}
getCaptionContainer(): HTMLElement
{
return this.cache.remember('caption', () => {
const div = document.createElement('div');
div.className = 'ui-selector-item-caption';
return div;
});
}
getIndicatorContainer(): HTMLElement
{
return this.cache.remember('indicator', () => {
const div = document.createElement('div');
div.className = 'ui-selector-item-indicator';
return div;
});
}
getBadgeContainer(): HTMLElement
{
return this.cache.remember('badge', () => {
const div = document.createElement('div');
div.className = 'ui-selector-item-badges';
return div;
});
}
getLinkContainer(): HTMLElement
{
return this.cache.remember('link', () => {
const anchor: HTMLAnchorElement = document.createElement('a');
anchor.className = 'ui-selector-item-link';
anchor.href = this.getLink();
anchor.target = '_blank';
anchor.title = '';
Event.bind(anchor, 'click', this.handleLinkClick.bind(this));
anchor.appendChild(this.getLinkTextContainer());
return anchor;
});
}
getLinkTextContainer(): HTMLElement
{
return this.cache.remember('link-text', () => {
const span = document.createElement('span');
span.className = 'ui-selector-item-link-text';
return span;
});
}
showLink(): void
{
if (Type.isStringFilled(this.getLink()))
{
Dom.addClass(this.getLinkContainer(), 'ui-selector-item-link--show');
requestAnimationFrame(() => {
requestAnimationFrame(() => {
Dom.addClass(this.getLinkContainer(), 'ui-selector-item-link--animate');
});
});
}
}
hideLink(): void
{
if (Type.isStringFilled(this.getLink()))
{
Dom.removeClass(
this.getLinkContainer(), ['ui-selector-item-link--show', 'ui-selector-item-link--animate']
);
}
}
setHighlights(highlights: MatchField[]): void
{
this.highlights = highlights;
}
getHighlights(): MatchField[]
{
return this.highlights;
}
highlight(): void
{
this.getHighlights().forEach(matchField => {
const field = matchField.getField();
const fieldName = field.getName();
if (field.isCustom())
{
const text = this.getItem().getCustomData().get(fieldName);
this.getSubtitleContainer().innerHTML = Highlighter.mark(text, matchField.getMatches());
}
else if (field.getName() === 'title')
{
this.getTitleContainer().innerHTML =
Highlighter.mark(this.getItem().getTitleNode(), matchField.getMatches())
;
}
else if (field.getName() === 'subtitle')
{
this.getSubtitleContainer().innerHTML =
Highlighter.mark(this.getItem().getSubtitleNode(), matchField.getMatches())
;
}
else if (field.getName() === 'supertitle')
{
this.getSupertitleContainer().innerHTML =
Highlighter.mark(this.getItem().getSupertitleNode(), matchField.getMatches())
;
}
});
}
select(): void
{
if (this.hasChildren() || this.isDynamic())
{
return;
}
Dom.addClass(this.getOuterContainer(), 'ui-selector-item-box-selected');
}
deselect(): void
{
if (this.hasChildren() || this.isDynamic())
{
return;
}
Dom.removeClass(this.getOuterContainer(), 'ui-selector-item-box-selected');
}
focus(): void
{
if (this.isFocused())
{
return;
}
this.focused = true;
Dom.addClass(this.getOuterContainer(), 'ui-selector-item-box-focused');
this.getDialog().emit('ItemNode:onFocus', { node: this });
}
unfocus(): void
{
if (!this.isFocused())
{
return;
}
this.focused = false;
Dom.removeClass(this.getOuterContainer(), 'ui-selector-item-box-focused');
this.getDialog().emit('ItemNode:onUnfocus', { node: this });
}
isFocused(): boolean
{
return this.focused;
}
click(): void
{
if (this.hasChildren() || this.isDynamic())
{
if (this.isOpen())
{
this.collapse();
}
else
{
this.expand();
}
}
else
{
if (this.getItem().isSelected())
{
if (this.getItem().isDeselectable())
{
this.getItem().deselect();
}
if (this.getDialog().shouldHideOnDeselect())
{
this.getDialog().hide();
}
}
else
{
this.getItem().select();
if (this.getDialog().shouldClearSearchOnSelect())
{
this.getDialog().clearSearch();
}
if (this.getDialog().shouldHideOnSelect())
{
this.getDialog().hide();
}
}
}
this.getDialog().focusSearch();
}
scrollIntoView(): void
{
const tabContainer = this.getTab().getContainer();
const nodeContainer = this.getContainer();
const tabRect = Dom.getPosition(tabContainer);
const nodeRect = Dom.getPosition(nodeContainer);
const margin = 9; // 'ui-selector-items' padding - 'ui-selector-item' margin = 10 - 1
if (nodeRect.top < tabRect.top) // scroll up
{
tabContainer.scrollTop -= (tabRect.top - nodeRect.top + margin);
}
else if (nodeRect.bottom > tabRect.bottom) // scroll down
{
tabContainer.scrollTop += nodeRect.bottom - tabRect.bottom + margin;
}
}
#makeEllipsisTitle(): void
{
if (this.constructor.#isEllipsisActive(this.getTitleContainer()))
{
this.getContainer().setAttribute(
'title',
this.constructor.#sanitizeTitle(this.getTitleContainer().textContent)
);
}
else
{
Dom.attr(this.getContainer(), 'title', null);
}
const containers = [
this.getSupertitleContainer(),
this.getSubtitleContainer(),
this.getCaptionContainer(),
...this.getBadges().map((badge: ItemBadge) => badge.getContainer(this.getBadgeContainer()))
];
containers.forEach(container => {
if (this.constructor.#isEllipsisActive(container))
{
container.setAttribute('title', this.constructor.#sanitizeTitle(container.textContent));
}
else
{
Dom.attr(container, 'title', null);
}
});
}
static #isEllipsisActive(element: HTMLElement): boolean
{
return element.offsetWidth < element.scrollWidth;
}
static #sanitizeTitle(text: string)
{
return text.replace(/[\t ]+/gm, ' ').replace(/\n+/gm, '\n').trim();
}
handleClick(): void
{
this.click();
}
handleLinkClick(event: MouseEvent): void
{
this.getDialog().emit('ItemNode:onLinkClick', { node: this, event });
event.stopPropagation();
}
handleMouseEnter(): void
{
this.focus();
this.showLink();
this.#makeEllipsisTitle();
}
handleMouseLeave(): void
{
this.unfocus();
this.hideLink();
}
}