"use strict"; // Box that can contain other components Toolkit.Panel = class Panel extends Toolkit.Component { // Object constructor constructor(application, options) { super(application, "div", options); options = options || {}; // Configure instance fields this.alignCross = "start"; this.alignMain = "start"; this.application = application; this.children = []; this.columns = null; this.direction = "row"; this.focusable = "focusable" in options ? !!options.focusable:false; this.hollow = "hollow" in options ? !!options.hollow : true; this.layout = null; this.name = options.name || ""; this.overflowX = options.overflowX || "hidden"; this.overflowY = options.overflowY || "hidden"; this.rows = null; this.wrap = false; // Configure properties this.setFocusable(this.focusable); this.setHollow (this.hollow); this.setLayout (options.layout || null, options); this.setName (this.name); this.setOverflow (this.overflowX, this.overflowY); if (this.application && this.focusable) this.application.addComponent(this); } ///////////////////////////// Public Methods ////////////////////////////// // Add a component as a child of this container add(component, index) { // Determine the ordinal position of the element within the container index = !(typeof index == "number") ? this.children.length : Math.floor(Math.min(Math.max(0, index), this.children.length)); // Add the component to the container let ref = this.children[index] || null; component.parent = this; this.element.insertBefore(component.element, ref == null ? null : ref.element); this.children.splice(index, 0, component); return component; } // Request focus on the appropriate element focus() { if (this.focusable) this.element.focus(); } // Retrieve the component's accessible name getName() { return this.name; } // Determine whether the component is focusable isFocusable() { return this.focusable; } // Determine whether the component is hollow isHollow() { return this.hollow; } // Create a Button and associate it with the application newButton(options) { return new Toolkit.Button(this.application, options); } // Create a CheckBox and associate it with the application newCheckBox(options) { return new Toolkit.CheckBox(this.application, options); } // Create a Label and associate it with the application newLabel(options) { return new Toolkit.Label(this.application, options); } // Create a MenuBar and associate it with the application newMenuBar(options) { return new Toolkit.MenuBar(this.application, options); } // Create a Panel and associate it with the application newPanel(options) { return new Toolkit.Panel(this.application, options); } // Create a RadioButton and associate it with the application newRadioButton(options) { return new Toolkit.RadioButton(this.application, options); } // Create a Splitter and associate it with the application newSplitter(options) { return new Toolkit.Splitter(this.application, options); } // Create a TextBox and associate it with the application newTextBox(options) { return new Toolkit.TextBox(this.application, options); } // Create a Window and associate it with the application newWindow(options) { return new Toolkit.Window(this.application, options); } // Determine the index of the next visible child nextChild(index) { for (let x = 0; x <= this.children.length; x++) { index = (index + 1) % this.children.length; let comp = this.children[index]; if (comp.isVisible()) return index; } return -1; } // Determine the index of the previous visible child previousChild(index) { for (let x = 0; x <= this.children.length; x++) { index = (index + this.children.length - 1) % this.children.length; let comp = this.children[index]; if (comp.isVisible()) return index; } return -1; } // Remove a component from the container remove(component) { // Locate the component in the children let index = this.children.indexOf(component); if (index == -1) return; // Remove the component component.parent = null; component.element.remove(); this.children.splice(index, 1); } // Specify whether the component is focusable setFocusable(focusable) { this.focusable = focusable = !!focusable; if (focusable) { this.element.setAttribute("tabindex", "0"); this.application && this.application.addComponent(this); } else { this.element.removeAttribute("aria-label"); this.element.removeAttribute("tabindex"); this.application && this.application.removeComponent(this); } } // Specify whether the component is hollow setHollow(hollow) { this.hollow = hollow = !!hollow; if (hollow) { this.element.style.minHeight = "0"; this.element.style.minWidth = "0"; } else { this.element.style.removeProperty("min-height"); this.element.style.removeProperty("min-width" ); } } // Configure the element's layout setLayout(layout, options) { // Configure instance fields this.layout = layout; // Processing by layout options = options || {}; switch (layout) { case "block" : this.setBlockLayout (options); break; case "desktop": this.setDesktopLayout(options); break; case "flex" : this.setFlexLayout (options); break; case "grid" : this.setGridLayout (options); break; default : this.setNullLayout (options); break; } } // Specify the component's accessible name setName(name) { this.name = name || ""; if (this.focusable) this.localize(); } // Configure the panel's overflow scrolling behavior setOverflow(x, y) { this.element.style.overflowX = this.overflowX = x || "hidden"; this.element.style.overflowY = this.overflowY = y || this.overflowX; } // Specify the semantic role of the panel setRole(role) { if (!role) this.element.removeAttribute("role"); else this.element.setAttribute("role", "" + role); } ///////////////////////////// Package Methods ///////////////////////////// // Move a window to the foreground bringToFront(wnd) { for (let child of this.children) child.element.style.zIndex = child == wnd ? "1" : "0"; } // Update display text with localized strings localize() { let name = this.name; if (this.application) name = this.application.translate(name, this); this.element.setAttribute("aria-label", name); } ///////////////////////////// Private Methods ///////////////////////////// // Resize event handler onresize(desktop) { // Error checking if (this.layout != "desktop") return; // Ensure all child windows are visible in the viewport for (let wnd of this.children) { if (!wnd.isVisible()) continue; let bounds = wnd.getBounds(); wnd.contain( bounds.x - desktop.x, bounds.y - desktop.y, desktop, bounds ); } } // Configure a block layout setBlockLayout(options) { // Configure instance fields this.layout = "block"; // Configure element this.setDisplay("block"); } // Configure a desktop layout setDesktopLayout(options) { // Configure instance fields this.layout = "desktop"; // Configure element this.setDisplay("block"); this.element.style.position = "relative"; if (this.resizeObserver == null) this.addResizeListener(b=>this.onresize(b)); } // Configure a flex layout setFlexLayout(options) { // Configure instance fields this.alignCross = options.alignCross || "start"; this.alignMain = options.alignMain || "start"; this.direction = options.direction || this.direction; this.layout = "flex"; this.wrap = !!options.wrap; // Working variables let alignCross = this.alignCross; let alignMain = this.alignMain; if (alignCross == "start" || alignCross == "end") alignCross = "flex-" + alignCross; if (alignMain == "start" || alignMain == "end") alignMain = "flex-" + alignMain; // Configure element this.setDisplay("flex"); this.element.style.alignItems = alignCross; this.element.style.flexDirection = this.direction; this.element.style.justifyContent = alignMain; this.element.style.flexWrap = this.wrap ? "wrap" : "nowrap"; } // Configure a grid layout setGridLayout(options) { // Configure instance fields this.columns = options.columns || null; this.layout = "grid"; this.rows = options.rows || null; // Configure element this.setDisplay("grid"); if (this.columns == null) this.element.style.removeProperty("grid-template-columns"); else this.element.style.gridTemplateColumns = this.columns; if (this.rows == null) this.element.style.removeProperty("grid-template-rows"); else this.element.style.gridTemplateRows = this.rows; } // Configure a null layout setNullLayout(options) { // Configure instance fields this.layout = null; // Configure element this.setDisplay(null); this.element.style.removeProperty("align-items" ); this.element.style.removeProperty("flex-wrap" ); this.element.style.removeProperty("grid-template-columns"); this.element.style.removeProperty("grid-template-rows" ); this.element.style.removeProperty("justify-content" ); this.element.style.removeProperty("flex-direction" ); } };