UNPKG

mj-context-menu

Version:
209 lines 7.09 kB
import * as MenuUtil from './menu_util.js'; import { HtmlClasses } from './html_classes.js'; import { AbstractMenu } from './abstract_menu.js'; import { Info } from './info.js'; export class SelectionMenu extends AbstractMenu { static fromJson(factory, { title: title, values: values, variable: variable }, sb) { const selection = new this(sb); const tit = factory.get('label')(factory, { content: title || '', id: title || 'id' }, selection); const rul = factory.get('rule')(factory, {}, selection); const radios = values.map((x) => factory.get('radio')(factory, { content: x, variable: variable, id: x }, selection)); const items = [tit, rul].concat(radios); selection.items = items; return selection; } constructor(anchor) { super(); this.anchor = anchor; this.className = HtmlClasses['SELECTIONMENU']; this.variablePool = this.anchor.menu.pool; this.baseMenu = this.anchor.menu; } generateHtml() { super.generateHtml(); this.items.forEach((item) => item.html.classList.add(HtmlClasses['SELECTIONITEM'])); } display() { } right(event) { this.anchor.right(event); } left(event) { this.anchor.left(event); } } export class SelectionBox extends Info { static fromJson(factory, { title: title, signature: signature, selections: selections, order: order, grid: grid }, ctxt) { const sb = new this(title, signature, order, grid); sb.attachMenu(ctxt); const sels = selections.map((x) => factory.get('selectionMenu')(factory, x, sb)); sb.selections = sels; return sb; } constructor(title, signature, style = "none", grid = "vertical") { super(title, null, signature); this.style = style; this.grid = grid; this._selections = []; this.prefix = 'ctxt-selection'; this._balanced = true; } attachMenu(menu) { this.menu = menu; } get selections() { return this._selections; } set selections(selections) { this._selections = []; selections.forEach((x) => this.addSelection(x)); } addSelection(selection) { selection.anchor = this; this._selections.push(selection); } rowDiv(sels) { const div = document.createElement('div'); this.contentDiv.appendChild(div); const rects = sels.map((sel) => { div.appendChild(sel.html); if (!sel.html.id) { sel.html.id = this.prefix + MenuUtil.counter(); } return sel.html.getBoundingClientRect(); }); const column = rects.map((x) => x.width); const width = column.reduce((x, y) => x + y, 0); const height = rects.reduce((x, y) => Math.max(x, y.height), 0); div.classList.add(HtmlClasses['SELECTIONDIVIDER']); div.setAttribute('style', 'height: ' + height + 'px;'); return [div, width, height, column]; } display() { super.display(); this.order(); if (!this.selections.length) { return; } const outerDivs = []; let maxWidth = 0; let balancedColumn = []; const chunks = this.getChunkSize(this.selections.length); for (let i = 0; i < this.selections.length; i += chunks) { const sels = this.selections.slice(i, i + chunks); const [div, width, height, column] = this.rowDiv(sels); outerDivs.push(div); maxWidth = Math.max(maxWidth, width); sels.forEach((sel) => (sel.html.style.height = height + 'px')); balancedColumn = this.combineColumn(balancedColumn, column); } if (this._balanced) { this.balanceColumn(outerDivs, balancedColumn); maxWidth = balancedColumn.reduce((x, y) => x + y, 20); } outerDivs.forEach((div) => (div.style.width = maxWidth + 'px')); } getChunkSize(size) { switch (this.grid) { case "square": return Math.floor(Math.sqrt(size)); case "horizontal": return Math.floor(size / SelectionBox.chunkSize); case "vertical": default: return SelectionBox.chunkSize; } } balanceColumn(divs, column) { divs.forEach((div) => { const children = Array.from(div.children); for (let i = 0, child; (child = children[i]); i++) { child.style.width = column[i] + 'px'; } }); } combineColumn(col1, col2) { let result = []; let i = 0; while (col1[i] || col2[i]) { if (!col1[i]) { result = result.concat(col2.slice(i)); break; } if (!col2[i]) { result = result.concat(col1.slice(i)); break; } result.push(Math.max(col1[i], col2[i])); i++; } return result; } left(event) { this.move(event, (index) => (index === 0 ? this.selections.length : index) - 1); } right(event) { this.move(event, (index) => index === this.selections.length - 1 ? 0 : index + 1); } generateHtml() { super.generateHtml(); this.html.classList.add(HtmlClasses['SELECTION']); } generateContent() { const div = super.generateContent(); div.classList.add(HtmlClasses['SELECTIONBOX']); div.removeAttribute('tabindex'); return div; } findSelection(event) { const target = event.target; let selection = null; if (target.id) { selection = this.selections.find((x) => x.html.id === target.id); } if (!selection) { const id = target.parentElement.id; selection = this.selections.find((x) => x.html.id === id); } return selection; } move(event, isNext) { const selection = this.findSelection(event); if (selection.focused) { selection.focused.unfocus(); } const index = this.selections.indexOf(selection); const next = isNext(index); this.selections[next].focus(); } order() { this.selections.sort(SelectionBox.orderMethod.get(this.style)); } toJson() { return { type: '' }; } } SelectionBox.chunkSize = 4; SelectionBox.orderMethod = new Map([ [ "alphabetical", (x, y) => x.items[0].content.localeCompare(y.items[0].content) ], ["none", (_x, _y) => 1], [ "decreasing", (x, y) => { const xl = x.items.length; const yl = y.items.length; return xl < yl ? 1 : yl < xl ? -1 : 0; } ], [ "increasing", (x, y) => { const xl = x.items.length; const yl = y.items.length; return xl < yl ? -1 : yl < xl ? 1 : 0; } ] ]); //# sourceMappingURL=selection_box.js.map