@easyquery/ui
Version:
EasyQuery.JS Community UI widgets
1,158 lines (1,153 loc) • 570 kB
JavaScript
'use strict';
var core$1 = require('@easydata/core');
var core = require('@easyquery/core');
var ui = require('@easydata/ui');
function findHighestZIndex(elem) {
let highest = 0;
while (elem !== null) {
const zindex = document.defaultView.getComputedStyle(elem, null)
.getPropertyValue("z-index");
if (zindex != 'auto') {
const numZIndex = parseInt(zindex);
if (numZIndex > highest) {
highest = numZIndex;
}
}
elem = elem.parentElement;
}
return highest;
}
// simetimes setting focus in the main thread doesn't work correctly (in Firefox). So we need to 'hack' it.
function safeFocus(element) {
setTimeout((el) => {
if (el && el.focus) {
el.focus();
}
}, 100, element);
}
const eqCssPrefix = 'eqjs';
const eqCssMobile = 'eqjs-mobile';
function getMobileCssClass() {
return ui.browserUtils.isMobileMode() ? eqCssMobile : null;
}
/**
* The entities panel wiget, implemented without JQuery.
*/
class EntitiesPanel extends core.Widget {
get cssPrefix() {
return 'eqjs-ep';
}
/**
* The default constructor.
* @param slot The html element.
*/
constructor(slot) {
super(slot);
this.queryChangedCallbackId = null;
this.group = core.WidgetGroup.Model | core.WidgetGroup.Query;
this.panel = slot;
}
getWidgetType() {
return 'entitiesPanel';
}
/**
* Initialize widget.
* @param context The context.
* @param options The options.
*/
init(context, options) {
super.init(context, options);
this.setOptions(options);
this.renderProgressBlock();
}
/**
* Refresh widget implementation
*/
refreshCore() {
this.render();
if (this.options.syncWithColumns) {
this.refreshCheckedStateByColumns();
}
}
onProcessStartCore() {
if (this.options.showIndicatorOnLoad) {
if (!this.progressBlock.parentNode)
this.panel.appendChild(this.progressBlock);
}
}
onProcessEndCore() {
if (this.options.showIndicatorOnLoad) {
if (this.progressBlock.parentNode)
this.panel.removeChild(this.progressBlock);
}
}
destroyCore() {
this.slot.innerHTML = '';
}
setOptions(options) {
this.options = {
showToolbar: true,
syncWithColumns: false,
showSelectAllButton: false,
showClearSelectionButton: true,
showAddColumnButton: true,
showAddConditionButton: true,
showCheckboxes: true,
showTooltips: true,
draggableAttributes: true,
showAttributes: { useInConditions: true, useInResult: true, useInSorting: false },
showFilterBox: false,
filterBoxMode: 0,
showIndicatorOnLoad: true,
attrPlacement: 0,
sortEntities: false,
autoClearSelection: true,
entityRenderedCallback: null,
attributeRenderedCallback: null,
};
if (options) {
core$1.utils.assignDeep(this.options, options);
}
if (this.queryChangedCallbackId) {
const query = this.context.getQuery();
query.removeChangedCallback(this.queryChangedCallbackId);
}
if (this.options.syncWithColumns) {
const query = this.context.getQuery();
this.queryChangedCallbackId = query.addChangedCallback((ev) => {
const edata = ev.data;
if (!edata || (edata.part != core.QueryChangePart.Columns && edata.part != core.QueryChangePart.All)) {
return;
}
this.refreshCheckedStateByColumns();
});
}
}
render() {
let model = this.context.getModel();
this.clear();
this.panel.classList.add(`${this.cssPrefix}-panel`);
this.panel.classList.add(getMobileCssClass());
this.rootEntityBlock = document.createElement('div');
if (model != null && !model.isEmpty()) {
let entTree = model.getEntitiesTree({
addUIC: this.options.showAttributes.useInConditions && !this.options.syncWithColumns,
addUIR: this.options.showAttributes.useInResult,
addUIS: this.options.showAttributes.useInSorting && !this.options.syncWithColumns,
attrPlacement: this.options.attrPlacement,
sortEntities: this.options.sortEntities,
includeRootData: true
});
this.entityTreeBlock = this.renderEntity(entTree, this.rootEntityBlock, 0);
this.panel.appendChild(this.entityTreeBlock);
}
if (this.options.showFilterBox) {
this.createFilterBox();
}
else {
this.rootEntityBlock.style.top = '0';
}
if (this.options.showToolbar && !this.options.syncWithColumns) {
this.createToolPanel();
}
else {
this.rootEntityBlock.style.bottom = '0';
}
}
renderEntity(entity, block, offset) {
let entityBlock;
let entityNode = document.createElement('div');
entityNode.classList.add(`${this.cssPrefix}-entity-node`);
entityNode.classList.add(getMobileCssClass());
let entityChildren = document.createElement('div');
entityChildren.classList.add(`${this.cssPrefix}-entity-children`);
entityChildren.classList.add(getMobileCssClass());
let nodeLabel = document.createElement('label');
nodeLabel.classList.add(`${this.cssPrefix}-entity-node-label`);
let nodeInput = document.createElement('input');
nodeInput.type = 'checkbox';
nodeInput.title = entity.text;
let nodeToggleButton = document.createElement('a');
nodeToggleButton.href = 'javascript:void(0)';
nodeToggleButton.title = `${core$1.i18n.getText("EntityToggle")} ${entity.text}`;
nodeToggleButton.classList.add(`${this.cssPrefix}-entity-node-button`);
let attrNode, attrLabel, attrInput;
let currentOffset = offset;
let isAttributeInTree = (attrId, entityBlock) => {
let res = entityBlock.querySelectorAll(`.${this.cssPrefix}-entity-attr[data-id="${attrId}"]`);
return res.length > 0;
};
if (block) {
entityBlock = block;
entityBlock.innerHTML = '';
}
else {
entityBlock = document.createElement('div');
}
entityBlock.classList.add(`${this.cssPrefix}-entity`);
entityBlock.classList.add(getMobileCssClass());
if (entity.id && entity.id != "") {
nodeLabel.innerText = entity.text;
entityNode.appendChild(nodeLabel); //caption
if (this.options.showCheckboxes) {
nodeLabel.insertBefore(nodeInput, nodeLabel.firstChild);
}
entityNode.insertBefore(nodeToggleButton, entityNode.firstChild);
if (this.options.showTooltips && entity.description) {
nodeLabel.setAttribute('title', entity.description);
}
for (let i = 0; i < currentOffset; i++) {
let divElem = document.createElement('div');
divElem.classList.add(`${this.cssPrefix}-entity-offset`);
entityNode.insertBefore(divElem, entityNode.firstChild);
}
entityBlock.appendChild(entityNode);
entityChildren.hidden = true;
currentOffset++;
}
let itemsLength = entity.items ? entity.items.length : 0;
for (let i = 0; i < itemsLength; i++) {
let item = entity.items[i];
if (item.isEntity) {
entityChildren.appendChild(this.renderEntity(item, null, currentOffset));
}
else {
if (!item.lookupAttr || !(isAttributeInTree(item.lookupAttr, entityChildren))) {
attrLabel = document.createElement('label');
attrLabel.innerText = item.text;
attrLabel.classList.add(`${this.cssPrefix}-entity-attr-label`);
if (this.options.showCheckboxes) {
attrInput = document.createElement('input');
attrInput.type = 'checkbox';
attrInput.title = item.text;
attrLabel.insertBefore(attrInput, attrLabel.firstChild);
if (this.options.syncWithColumns) {
attrInput.addEventListener('change', (ev) => {
const model = this.context.getModel();
const query = this.context.getQuery();
const checkbox = ev.currentTarget;
const attrId = checkbox.parentElement.parentElement.getAttribute('data-id');
if (model.checkAttrProperty(attrId, "useInResult")) {
if (checkbox.checked) {
const attr = model.getAttributeById(attrId);
const column = query.addColumn({
attribute: attr
}, true);
query.fireColumnsChangedEvent(core.QueryChangeAction.Add, column);
}
else {
const columns = query.getColumns()
.filter(col => col.expr.tag === core.ExprTag.EntityAttribute
&& col.expr.value === attrId);
if (columns.length > 0) {
query.removeColumn(columns[0]);
query.fireColumnsChangedEvent(core.QueryChangeAction.Delete, columns[0]);
}
}
}
});
}
}
if (this.options.showTooltips && item.description) {
attrLabel.setAttribute('title', item.description);
}
for (let j = 0; j < currentOffset + 1; j++) {
let divElem = document.createElement('div');
divElem.classList.add(`${this.cssPrefix}-entity-offset`);
attrLabel.insertBefore(divElem, attrLabel.firstChild);
}
attrNode = document.createElement('div');
attrNode.classList.add(`${this.cssPrefix}-entity-attr`);
if (entityNode.innerHTML.length == 0) {
attrNode.classList.add(`${this.cssPrefix}-entity-attr-root`);
}
attrNode.innerHTML = "";
attrNode.appendChild(attrLabel);
attrNode.setAttribute('data-id', item.id);
if (this.options.draggableAttributes && !this.options.syncWithColumns) {
ui.eqDragManager.registerDraggableItem({
element: attrNode,
scope: "entityAttr",
data: { attrId: item.id },
renderer: (dragImage) => {
dragImage.innerHTML = '';
const attrLabel = document.createElement('span');
attrLabel.innerText = item.text;
dragImage.appendChild(attrLabel);
}
});
}
if (this.options.attributeRenderedCallback) {
this.options.attributeRenderedCallback(attrNode);
}
entityChildren.appendChild(attrNode);
}
}
}
if (entityChildren.innerHTML.length) {
entityBlock.appendChild(entityChildren);
nodeToggleButton.addEventListener('click', (event) => {
entityChildren.hidden = !entityChildren.hidden;
let element = event.target;
let className = `${this.cssPrefix}-entity-node-button-open`;
if (element.classList.contains(className)) {
element.classList.remove(className);
}
else {
element.classList.add(className);
}
event.preventDefault();
});
}
if (entityChildren) {
const checkboxes = entityChildren.querySelectorAll(`.${this.cssPrefix}-entity-attr > label > input`);
for (let i = 0; i < checkboxes.length; i++) {
const checkbox = checkboxes[i];
checkbox.addEventListener('click', (event) => {
let element = event.target;
if (element.checked && !nodeInput.checked) {
nodeInput.checked = true;
}
else if (entityChildren.querySelectorAll('input:checked').length === 0) {
nodeInput.checked = false;
}
event.stopPropagation();
});
}
}
nodeInput.addEventListener('click', (event) => {
let element = event.target;
const entities = entityChildren.querySelectorAll('label input');
for (let i = 0; i < entities.length; i++) {
const entity = entities[i];
entity.checked = element.checked;
}
if (this.options.syncWithColumns) {
const query = this.context.getQuery();
const model = this.context.getModel();
const attrList = [];
const attrElems = Array.from(entityChildren.querySelectorAll(`.${this.cssPrefix}-entity-attr`));
for (const elem of attrElems) {
const attrId = elem.getAttribute('data-id');
if (model.checkAttrProperty(attrId, 'useInResult')) {
attrList.push(attrId);
}
}
if (element.checked) {
for (const attrId of attrList) {
query.addColumn({ attributeId: attrId }, true);
}
}
else {
const columns = query.getColumns()
.filter(col => col.expr.tag === core.ExprTag.EntityAttribute
&& attrList.indexOf(col.expr.value) >= 0);
query.removeColumns(columns, null);
}
query.fireColumnsChangedEvent();
}
event.stopPropagation();
});
if (block != this.rootEntityBlock && this.options.entityRenderedCallback) {
this.options.entityRenderedCallback(entityBlock);
}
return entityBlock;
}
createFilterBox() {
this.filterBoxBlock = document.createElement('div');
this.filterBoxBlock.classList.add(`${this.cssPrefix}-filter-box`);
this.filterBoxBlock.classList.add(getMobileCssClass());
this.filterBoxInput = document.createElement('input');
this.filterBoxInput.classList.add(`${this.cssPrefix}-filter-box-input`);
this.filterBoxInput.addEventListener('input', (e) => {
const attrs = this.panel.querySelectorAll(`.${this.cssPrefix}-entity-attr`);
for (let i = 0; i < attrs.length; i++) {
const attr = attrs[i];
attr.hidden = !this.checkFilterAttribute(attr);
}
const entities = this.panel.querySelectorAll(`:scope > .${this.cssPrefix}-entity`);
for (let i = 0; i < entities.length; i++) {
const entity = entities[i];
let attrs = entity.querySelectorAll(`.${this.cssPrefix}-entity-attr`);
let displayAttrCount = 0;
for (let i = 0; i < attrs.length; i++) {
if (attrs[i].style.display !== 'None') {
displayAttrCount++;
}
}
entity.hidden = displayAttrCount === 0;
}
if (this.filterBoxInput.value === '')
this.collapseAll();
else
this.expandAll();
});
this.filterBoxBlock.appendChild(this.filterBoxInput);
this.panel.insertBefore(this.filterBoxBlock, this.panel.firstChild);
}
createToolPanel() {
let defClass = `${this.cssPrefix}-tool-panel`;
let toolPanelBlock = document.createElement('div');
toolPanelBlock.classList.add(defClass);
toolPanelBlock.classList.add(getMobileCssClass());
let toolSelectAll = document.createElement('div');
toolSelectAll.classList.add(`${defClass}-select-all`);
toolSelectAll.title = 'Select all';
let toolDeselectAll = document.createElement('div');
toolDeselectAll.classList.add(`${defClass}-deselect-all`);
toolDeselectAll.title = 'Clear selection';
let toolAddColumns = document.createElement('div');
toolAddColumns.classList.add(`${defClass}-add-columns`);
toolAddColumns.title = 'Add column';
let toolAddCond = document.createElement('div');
toolAddCond.classList.add(`${defClass}-add-cond`);
toolAddCond.title = 'Add condition';
let toolLeftBlock = document.createElement('div');
toolLeftBlock.classList.add(`${defClass}-left-side`);
let toolRightBlock = document.createElement('div');
toolRightBlock.classList.add(`${defClass}-right-side`);
let model = this.context.getModel();
if (this.options.showSelectAllButton) {
toolSelectAll.title = core$1.i18n.getText("ButtonSelectAll");
toolLeftBlock.appendChild(toolSelectAll);
toolSelectAll.addEventListener('click', () => {
this.selectAll();
});
}
if (this.options.showClearSelectionButton) {
toolDeselectAll.title = core$1.i18n.getText("ButtonDeselectAll");
toolLeftBlock.appendChild(toolDeselectAll);
toolDeselectAll.addEventListener('click', () => {
this.deselectAll();
});
}
if (this.options.showAddColumnButton) {
toolAddColumns.title = core$1.i18n.getText("ButtonAddColumns");
toolRightBlock.appendChild(toolAddColumns);
toolAddColumns.addEventListener('click', () => {
const attrElements = this.panel.querySelectorAll(`.${this.cssPrefix}-entity-attr`);
let attrList = [];
let attrId;
const query = this.context.getQuery();
query.fireProcessEvent({
source: self,
status: "start"
});
for (let i = 0; i < attrElements.length; i++) {
const attrElement = attrElements[i];
let input = attrElement.getElementsByTagName('input')[0];
if (input.checked) {
attrId = attrElement.getAttribute('data-id');
if (model.checkAttrProperty(attrId, "useInResult")) {
attrList.push(attrId);
}
}
}
for (let attrId of attrList) {
const attr = model.getAttributeById(attrId);
query.addColumn({
attribute: attr
}, true);
}
query.fireChangedEvent();
if (this.options.autoClearSelection) {
this.deselectAll();
}
query.fireProcessEvent({
source: self,
status: "finish"
});
});
}
if (this.options.showAddConditionButton) {
toolAddCond.title = core$1.i18n.getText("ButtonAddConditions");
toolRightBlock.appendChild(toolAddCond);
toolAddCond.addEventListener('click', () => {
let attrElements = this.panel.querySelectorAll(`.${this.cssPrefix}-entity-attr`);
let attrList = [];
let attrId;
let query = this.context.getQuery();
query.fireProcessEvent({
source: self,
status: "start"
});
for (let i = 0; i < attrElements.length; i++) {
const attrElement = attrElements[i];
let input = attrElement.getElementsByTagName('input')[0];
if (input.checked) {
attrId = attrElement.getAttribute('data-id');
if (model.checkAttrProperty(attrId, "useInConditions")) {
attrList.push(attrId);
}
}
}
for (let attrId of attrList) {
query.addSimpleCondition({
attributeId: attrId
});
}
query.fireChangedEvent();
if (this.options.autoClearSelection) {
this.deselectAll();
}
query.fireProcessEvent({
source: self,
status: "finish"
});
});
}
toolPanelBlock.appendChild(toolLeftBlock);
toolPanelBlock.appendChild(toolRightBlock);
this.panel.appendChild(toolPanelBlock);
}
checkFilterAttribute(attr) {
const inputElem = attr.querySelector('label input');
if (inputElem.checked) {
return true;
}
const labelElem = attr.querySelector('label');
const attrCaption = labelElem.textContent;
if (this.checkFilterText(attrCaption)) {
return true;
}
const entityNode = attr.parentElement.parentElement.querySelector(`.${this.cssPrefix}-entity-node`);
const entityCaption = entityNode.querySelector('label').textContent;
if (this.checkFilterText(entityCaption)) {
return true;
}
return false;
}
checkFilterText(value) {
let filterText = this.filterBoxInput.value;
if (filterText == "")
return true;
if (this.options.filterBoxMode == 0 && value.toLowerCase().indexOf(filterText.toLowerCase()) >= 0)
return true;
if (this.options.filterBoxMode == 1 && value.toLowerCase().indexOf(filterText.toLowerCase()) == 0)
return true;
return false;
}
refreshCheckedStateByColumns() {
this.deselectAll();
const query = this.context.getQuery();
const exprColumns = query.getColumns()
.filter(col => col.expr.tag === core.ExprTag.EntityAttribute);
for (const column of exprColumns) {
const attrNode = this.rootEntityBlock
.querySelector(`.${this.cssPrefix}-entity-attr[data-id="${column.expr.value}"]`);
let checkbox = attrNode.querySelector(`label > input`);
checkbox.checked = true;
let entChildren = attrNode.parentElement;
while (entChildren
&& entChildren.classList
.contains(`${this.cssPrefix}-entity-children`)) {
entChildren.hidden = false;
const entElem = entChildren.parentElement;
if (entElem && entChildren !== entElem.firstElementChild) {
checkbox = entElem.firstElementChild
.querySelector(`label > input`);
checkbox.checked = true;
entChildren = entElem.parentElement;
}
else {
break;
}
}
}
}
expandAll() {
for (let i = 0; i < this.rootEntityBlock.childNodes.length; i++) {
const child = this.rootEntityBlock.childNodes[0];
const childs = child.querySelectorAll(`.${this.cssPrefix}-entity-children`);
for (let j = 0; j < childs.length; j++) {
const elem = childs[j];
elem.hidden = false;
}
}
const nodeButtons = this.rootEntityBlock.querySelectorAll(`.${this.cssPrefix}-entity-node-button`);
for (let i = 0; i < nodeButtons.length; i++) {
const elem = nodeButtons[i];
elem.classList.add(`${this.cssPrefix}-entity-node-button-open`);
}
}
collapseAll() {
for (let i = 0; i < this.rootEntityBlock.childNodes.length; i++) {
const child = this.rootEntityBlock.childNodes[0];
const childs = child.querySelectorAll(`.${this.cssPrefix}-entity-children`);
for (let j = 0; j < childs.length; j++) {
const elem = childs[j];
elem.hidden = true;
}
}
const nodeButtons = this.rootEntityBlock.querySelectorAll(`.${this.cssPrefix}-entity-node-button`);
for (let i = 0; i < nodeButtons.length; i++) {
const elem = nodeButtons[i];
elem.classList.remove(`${this.cssPrefix}-entity-node-button-open`);
}
}
selectAll() {
const inputs = this.entityTreeBlock.querySelectorAll('input');
for (let i = 0; i < inputs.length; i++) {
const input = inputs[i];
input.checked = true;
}
}
deselectAll() {
const inputs = this.entityTreeBlock.querySelectorAll('input');
for (let i = 0; i < inputs.length; i++) {
const input = inputs[i];
input.checked = false;
}
}
renderProgressBlock() {
this.progressBlock = document.createElement('div');
this.progressBlock.classList.add(`${eqCssPrefix}-progress-win8`);
this.progressBlock.classList.add(getMobileCssClass());
this.progressBlock.innerHTML = '<div class="wBall" id="wBall_1"><div class="wInnerBall"></div></div><div class="wBall" id="wBall_2"><div class="wInnerBall"></div></div><div class="wBall" id="wBall_3"><div class="wInnerBall"></div></div><div class="wBall" id="wBall_4"><div class="wInnerBall"></div></div><div class="wBall" id="wBall_5"><div class="wInnerBall"></div></div>';
}
clear() {
this.panel.innerHTML = "";
}
}
exports.ColumnsEditMode = void 0;
(function (ColumnsEditMode) {
/**
* ReadOnly edit mode allows to view columns but doesn't allow to change them.
*/
ColumnsEditMode[ColumnsEditMode["ReadOnly"] = 0] = "ReadOnly";
/**
* FixedList edit mode allows to edit some columns parameters (formats, sorting) and change their order
* but doesn't allow to add or delete columns.
*/
ColumnsEditMode[ColumnsEditMode["FixedList"] = 16] = "FixedList";
/**
* Full edit mode allows to add, delete and change columns in any way.
*/
ColumnsEditMode[ColumnsEditMode["Full"] = 255] = "Full";
})(exports.ColumnsEditMode || (exports.ColumnsEditMode = {}));
exports.ConditionsEditMode = void 0;
(function (ConditionsEditMode) {
/**
* No edit mode means that conditions are not editable at all.
*/
ConditionsEditMode[ConditionsEditMode["Default"] = 0] = "Default";
/**
* ReadOnly edit mode allows to view conditions but doesn't allow to change them, including the condition type, operator, value, etc.
*/
ConditionsEditMode[ConditionsEditMode["ReadOnly"] = 1] = "ReadOnly";
/**
* FixedList edit mode allows to modify some parameters of conditions (like their operators or values) but doesn't allow to add or delete conditions.
*/
ConditionsEditMode[ConditionsEditMode["FixedList"] = 16] = "FixedList";
/**
* Full edit mode allows to add, delete and change conditions in any way.
*/
ConditionsEditMode[ConditionsEditMode["Full"] = 255] = "Full";
})(exports.ConditionsEditMode || (exports.ConditionsEditMode = {}));
class MenuLevel {
get applyItem() {
return this._applyItem;
}
get cssPrefix() {
return 'eqjs-menu';
}
constructor(options) {
this.isFilteringMode = false;
this.showSelected = false;
//menu, items, levelIndex
this.parentMenu = options.menu || null;
this.parentLevel = options.parent || null;
this.parentElement = options.container || document.body;
this.levelIndex = options.levelIndex || 0;
this.levelDiv = null;
this.domWriteItemsId = options.domWriteItemsId || false;
this.menuId = options.menuId || '';
this.itemRenderedCallback = options.itemRenderedCallback || null;
//we need to define special "apply" item for this level
this._applyItem = { id: null, text: null, itemDiv: null };
this.items = options.items || [];
this.activeItem = null;
this.selectedItem = null;
this.initialized = false;
this.showSelected = options.showSelected;
this.updated = 0;
this.renderContent();
}
getItems() {
return this.items;
}
setItems(items) {
this.items = items;
}
renderContent() {
if (!this.items) {
return;
}
//define internal variables used in this function
const itemBgColor = this.parentMenu.style.colors.bgON || "white";
const itemFgColor = this.parentMenu.style.colors.fgON || "black";
this.parentMenu.style.colors.bgOVER || "LightSteelBlue";
const itemFontFamily = this.parentMenu.style.itemStyle.fontFamily || "";
const itemFontSize = this.parentMenu.style.itemStyle.fontSize || "14px";
const multiselect = this.parentMenu.options.multiselect;
const isSubQuery = this.parentMenu.options.isSubQuery;
//add base DIV element which is also used to show the shadow
const baseDivBuilder = ui.domel('div')
.addClass(getMobileCssClass());
if (this.parentMenu.options.useDefaultStyles) {
baseDivBuilder
.setStyle('backgroundColor', itemBgColor)
.setStyle('border', '1px solid')
.setStyle('borderColor', itemBgColor)
.setStyle('backgroundColor', this.parentMenu.style.colors.border)
.setStyle('margin', '-2px 2px 2px -2px')
.setStyle('width', 'auto')
.setStyle('height', 'auto');
}
baseDivBuilder
.setStyle('z-index', this.parentMenu.zIndex)
.setStyle('position', 'absolute')
.setStyle('display', 'none');
let baseDiv = baseDivBuilder.toDOM();
baseDiv['menuLevel'] = this;
const applyItem = this._applyItem;
//if multiselect option is on - then we should add special "apply" item
if (multiselect && this.levelIndex === 0 && this.parentMenu.options.hideButtons !== true) {
this.applyDiv = document.createElement("div");
this.applyDiv.classList.add(`${this.cssPrefix}-applyDiv`);
this.applyDiv['menuItem'] = applyItem;
this.applyBtn = document.createElement('button');
if (this.parentMenu.options.useDefaultStyles) {
this.applyDiv.style.borderBottom = '1px solid';
this.applyDiv.style.padding = '5px';
this.applyDiv.style.marginBottom = '5px';
this.applyBtn.style.padding = '0 5px';
this.applyBtn.style.cursor = "pointer";
}
const applyTextNode = document.createTextNode(this.parentMenu.options.buttons.submit);
this.applyBtn.appendChild(applyTextNode);
this.applyDiv.appendChild(this.applyBtn);
//cancel btn
const cancelBtn = document.createElement('button');
cancelBtn.classList.add(`${this.cssPrefix}-cancel`);
if (this.parentMenu.options.useDefaultStyles) {
cancelBtn.style.padding = '0 5px';
cancelBtn.style.cursor = 'pointer';
cancelBtn.style.marginLeft = '15px';
}
const cancelText = document.createTextNode(this.parentMenu.options.buttons.cancel);
cancelBtn.appendChild(cancelText);
this.applyDiv.appendChild(cancelBtn);
baseDiv.appendChild(this.applyDiv);
applyItem.itemDiv = this.applyDiv;
this.applyBtn.addEventListener('click', () => {
this.submit(this._applyItem);
});
cancelBtn.addEventListener('click', () => {
this.parentMenu.hideMenu();
});
}
// if too many items - then we add a special "search" item
// or there is an options to show always
if (this.parentLevel == null
&& (this.parentMenu.options.searchBoxAlwaysShown || this.items.length >= this.parentMenu.options.showSearchBoxAfter)) {
const searchDivBuilder = ui.domel('div')
.addClass(`${this.cssPrefix}-searchDiv`);
if (this.parentMenu.options.useDefaultStyles) {
searchDivBuilder
.setStyle('border-bottom', '1px solid #666')
.setStyle('background-color', itemBgColor)
.setStyle('border-color', this.parentMenu.style.colors.border);
if (itemFontFamily != "") {
searchDivBuilder.setStyle('font-family', itemFontFamily);
}
searchDivBuilder
.setStyle('font-size', itemFontSize)
.setStyle('color', itemFgColor)
.setStyle('cursor', 'pointer')
.setStyle('text-align', 'left')
.setStyle('padding', '5px');
}
const searchEditBoxBuilder = ui.domel('input')
.id('searchBox')
.name('searchBox')
.type('text')
.size(16)
.addClass(`${this.cssPrefix}-searchBox`)
.on('input', (ev) => {
this.deactivateItem(this.activeItem);
this.renderItems(this.searchBox.value);
})
.on('keydown', (ev) => {
let keyCode = ev.keyCode;
switch (keyCode) {
case 13: //enter
if (this.activeItem) {
this.activeItem.itemDiv.click();
}
break;
case 38: // up
this.moveActiveItemUp();
break;
case 40: // down
this.moveActiveItemDown();
break;
case 39: // right
if (!this.searchBox.value) {
this.openSubLevel(this.activeItem);
}
break;
}
});
if (this.parentMenu.options.useDefaultStyles) {
searchEditBoxBuilder
.setStyle('font-family', 'monospace')
.setStyle('font-size', '8pt')
.setStyle('width', '100%');
}
if (isSubQuery) {
searchEditBoxBuilder.addClass('eqjs-dialog');
}
this.searchBox = searchEditBoxBuilder.toDOM();
this.searchDiv = searchDivBuilder.toDOM();
this.searchDiv.appendChild(this.searchBox);
baseDiv.appendChild(this.searchDiv);
}
const scrollDiv = document.createElement("div");
scrollDiv.tabIndex = 1;
ui.domel(scrollDiv)
.addClass(`${this.cssPrefix}-scrollDiv`)
.addClass(getMobileCssClass());
scrollDiv.style.overflowX = "hidden";
scrollDiv.style.overflowY = "auto";
scrollDiv.style.position = "relative";
baseDiv.appendChild(scrollDiv);
this.levelDiv = baseDiv;
this.scrollDiv = scrollDiv;
if (this.menuId) {
this.levelDiv.id = this.menuId;
}
if (this.parentLevel) {
this.levelDiv.style.zIndex
= this.parentLevel.levelDiv.style.zIndex;
}
this.renderItems();
const scrollDivKeyDownHandler = (event) => {
switch (event.which) {
case 13: // enter
if (this.parentMenu.options.multiselect) {
this.parentMenu.getRootLevel().applyBtn.click();
}
else {
if (this.activeItem) {
this.activeItem.itemDiv.click();
}
}
break;
case 32: // space
if (this.activeItem) {
this.activeItem.itemDiv.click();
}
break;
case 37: // left
if (this.parentLevel && !this.isFilteringMode) {
this.deactivateItem(this.activeItem);
this.parentLevel.focus();
}
break;
case 39: // right
this.openSubLevel(this.activeItem);
break;
case 38: // up
this.moveActiveItemUp();
break;
case 40: // down
this.moveActiveItemDown();
break;
default: return; // exit this handler for other keys
}
event.preventDefault(); // prevent the default action (scroll / move caret)
};
scrollDiv.addEventListener("keydown", scrollDivKeyDownHandler);
if (ui.browserUtils.isMobileMode()) {
this.closeDiv =
ui.domel('div', baseDiv)
.addClass('eqjs-menu-close-btn')
.addText(core$1.i18n.getText('ButtonClose'))
.on('click', () => {
this.parentMenu.hideMenu();
})
.toDOM();
}
}
moveActiveItemDown() {
const items = this.isFilteringMode ? this.filteredItems : this.items;
if (this.activeItem) {
const idx = items.indexOf(this.activeItem);
if (idx < items.length - 1) {
this.activateItem(items[idx + 1], false);
}
}
else {
this.activateItem(items[0], false);
}
}
moveActiveItemUp() {
const items = this.isFilteringMode ? this.filteredItems : this.items;
if (this.activeItem) {
const idx = items.indexOf(this.activeItem);
if (idx > 0) {
this.activateItem(items[idx - 1], false);
}
}
else {
this.activateItem(items[items.length - 1], false);
}
}
openSubLevel(menuItem) {
if (menuItem && menuItem.items && !this.isFilteringMode) {
this.showSubLevel(menuItem);
menuItem.subLevel.activateItem(menuItem.subLevel.items[0]);
}
}
focusScrollDiv() {
this.scrollDiv.focus();
}
turnCheckboxes(items) {
//turn checkboxes on for selected items
for (let i = 0; i < items.length; i++) {
const item = items[i];
if (item.itemCheckbox)
item.itemCheckbox.checked = this.isItemSelected(item);
if (item.items) {
this.turnCheckboxes(item.items);
}
}
}
isItemSelected(item) {
if (item.items) {
for (var i = 0; i < item.items.length; i++) {
if (this.isItemSelected(item.items[i])) {
return true;
}
}
return false;
}
else {
return item.selected;
}
}
setItemSelected(item, value) {
if (item.items) {
for (let i = 0; i < item.items.length; i++) {
this.setItemSelected(item.items[i], value);
}
}
else {
item.selected = value;
}
}
submitItems(items, selectedItems) {
for (let j = 0; j < items.length; j++) {
if (items[j].items) {
this.submitItems(items[j].items, selectedItems);
}
else {
if (items[j].selected) {
selectedItems.push(items[j]);
}
}
}
}
allSubitemsAreFiltered(items, filterCallback) {
for (let i = 0; i < items.length; i++) {
if (filterCallback(items[i]))
return false;
}
return true;
}
isItemDiv(element) {
return element['menuItem'] ? true : false;
}
isLevelDiv(element) {
return element['menuLevel'] ? true : false;
}
getMenuItem(element) {
let el = element;
while (!this.isItemDiv(el)) {
if (this.isLevelDiv(el)) {
throw "Can't get menu item";
}
el = el.parentElement;
}
return el['menuItem'];
}
renderItemsWithoutFilter() {
this.isFilteringMode = false;
const scrollDiv = this.scrollDiv;
const multiselect = this.parentMenu.options.multiselect;
const activateOnMouseOver = this.parentMenu.options.activateOnMouseOver;
const itemFgColor = this.parentMenu.style.colors.fgON || 'black';
this.parentMenu.style.colors.bgOVER || 'LightSteelBlue';
const itemFontSize = this.parentMenu.style.itemStyle.fontSize || '14px';
const itemFilterCallback = this.parentMenu.getItemFilterCallback();
scrollDiv.innerHTML = "";
for (let i = 0; i < this.items.length; i++) {
const item = this.items[i];
if (!item || !item.text)
continue;
if (itemFilterCallback) {
if (!itemFilterCallback(item))
continue;
if (item.items && this.allSubitemsAreFiltered(item.items, itemFilterCallback))
continue;
}
item.data = (propName) => {
return this[propName];
};
if (typeof (item.selected) == "undefined") {
item.selected = false;
}
if (item.selected && this.selectedItem == null) {
this.selectedItem = item;
}
const itemDiv = document.createElement("div");
ui.domel(itemDiv)
.addClass(`${this.cssPrefix}-itemDiv`)
.addClass(getMobileCssClass());
if (item.selected && this.showSelected && !multiselect) {
itemDiv.classList.add(`${this.cssPrefix}-selected`);
}
if (this.domWriteItemsId && this.menuId) {
itemDiv.id = 'item-' + this.menuId + '-' + item.id;
}
scrollDiv.appendChild(itemDiv);
itemDiv['menuItem'] = item;
itemDiv['menuLevel'] = this;
item.itemDiv = itemDiv;
if (this.parentMenu.options.useDefaultStyles) {
itemDiv.style.fontSize = itemFontSize;
itemDiv.style.color = itemFgColor;
itemDiv.style.paddingLeft = "15px";
itemDiv.style.paddingRight = "6px";
itemDiv.style.cursor = "pointer";
}
if (item.text == '---') {
itemDiv.appendChild(document.createElement('hr'));
}
else {
if (multiselect) {
var cb = document.createElement("input");
cb.type = "checkbox";
cb.id = "cb" + item.id;
cb.checked = this.isItemSelected(item);
cb.defaultChecked = this.isItemSelected(item);
itemDiv.appendChild(cb);
item.itemCheckbox = cb;
if (this.parentMenu.options.useDefaultStyles) {
cb.style.margin = "4px 10px 0 0";
cb.style.verticalAlign = "top";
}
}
let itemText = item.text;
if (this.parentMenu.options.showItemIds) {
itemText = item.id + ':' + itemText;
}
const itemTextNode = document.createTextNode(itemText);
itemDiv.appendChild(itemTextNode);
if (item.items && item.items.length > 0) {
itemDiv.classList.add(`${this.cssPrefix}-itemDiv-hasChildren`);
const arrowSpan = document.createElement('span');
arrowSpan.classList.add(`${this.cssPrefix}-itemDiv-arrow`);
itemDiv.appendChild(arrowSpan);
const arrowText = document.createTextNode('>');
arrowSpan.appendChild(arrowText);
}
const itemClickHandler = (ev) => {
const menuItem = this.getMenuItem(ev.target);
if (multiselect) {
if (!menuItem.items || ev.target == menuItem.itemCheckbox) {
const itemSelected = this.isItemSelected(menuItem);
this.setItemSelected(menuItem, !itemSelected);
menuItem.itemCheckbox.checked = !itemSelected;
this.parentMenu.refreshCheckboxes();
}
else {
this.activateItem(menuItem);
}
}
else {
this.activateItem(menuItem);
this.submit(menuItem);
}
return false;
};
itemDiv.removeEventListener("click", itemClickHandler);
itemDiv.addEventListener('click', itemClickHandler);
itemDiv.addEventListener('mouseenter', (ev) => {
const item = this.getMenuItem(ev.target);
this.parentMenu.isCursorInside = true;
if (activateOnMouseOver) {
this.activateItem(item);
}
});
itemDiv.addEventListener('mouseleave', (ev) => {
const item = this.getMenuItem(ev.target);
this.parentMenu.isCursorInside = false;
setTimeout(() => {
if (!this.parentMenu.isCursorInside) {
if (activateOnMouseOver && item == this.activeItem && !item.subLevel) {
this.deactivateItem(item);
}
}
}, 200);
});
}
if (this.itemRenderedCallback) {
this.itemRenderedCallback(this.menuId, itemDiv);
}
}
}
renderItemsWithFilter(filter) {
this.isFilteringMode = true;
const scrollDiv = this.scrollDiv;
scrollDiv.innerHTML = "";
const filterSections = filter.split('>');
const pureFilterTexts = filterSections.map(section => section.replace(/\*/g, ''));
const items = this.filterItems(this.items, filterSections);
this.filteredItems = [];
for (let i = 0; i < items.length; i++) {
this.renderItemWithFilter(items[i], pureFilterTexts, 0);
}
}
matchesFilter(text, regexp) {
if (text && regexp) {
return regexp.test(text);
}
else {
return true;
}
}
filterItems(items, filterSections) {
const resultItems = [];
const filter = filterSections.length > 0 ? filterSections[0] : '';
const restFilterSections = filterSections.length > 1 ? filterSections.slice(1) : filterSections;
const filterRegexp = filter ? new RegExp(filter.replace(/\*/g, '.+?'), 'i') : null;
for (let i = 0; i < items.length; i++) {
const item = items[i];
if (item.items) {
const groupItem = core$1.utils.assign({}, item);
const groupItemMatches = this.matchesFilter(item.text, filterRegexp);
//if we have only one filter section (or an empty filter)
if (filterSections.length < 2) {
//if current group item matches the filter -> show all sub-items
if (groupItemMatches && filterSections.length < 2) {
groupItem.items = core$1.utils.createArrayFrom(item.items);
}
else {
groupItem.items = this.filterItems(item.items, restFilterSections);
}
}
//if we have more than 1 filter section and there is a match -> filter sub-items as well
else if (groupItemMatches) {
groupItem.items = this.filterItems