"use strict"; // Clickable button Toolkit.Button = class Button extends Toolkit.Component { // Object constructor constructor(application, options) { super(application, "div"); options = options || {}; // Configure instance fields this.blurListeners = []; this.clickListeners = []; this.enabled = "enabled" in options ? options.enabled : true; this.focusListeners = []; this.pressed = "pressed" in options ? options.pressed : false; this.tabStop = true; this.text = options.text || ""; this.toggleable = "toggleable"in options?options.toggleable:false; // Configure element this.element.type = "button"; this.element.setAttribute("role", "button"); this.element.style.cursor = "default"; this.element.style.position = "relative"; this.element.style.userSelect = "none"; this.element.addEventListener("blur" , e=>this.onblur (e)); this.element.addEventListener("focus" , e=>this.onfocus (e)); this.element.addEventListener("keydown" , e=>this.onkeydown (e)); this.element.addEventListener("pointerdown", e=>this.onpointerdown(e)); this.element.addEventListener("pointermove", e=>this.onpointermove(e)); this.element.addEventListener("pointerup" , e=>this.onpointerup (e)); // Configure properties this.setEnabled (this.enabled ); this.setPressed (this.pressed ); this.setTabStop (this.tabStop ); this.setText (this.text ); this.setToggleable(this.toggleable); application.addComponent(this); } ///////////////////////////// Public Methods ////////////////////////////// // Add a callback for blur events addBlurListener(listener) { if (this.blurListeners.indexOf(listener) == -1) this.blurListeners.push(listener); } // Add a callback for click events addClickListener(listener) { if (this.clickListeners.indexOf(listener) == -1) this.clickListeners.push(listener); } // Add a callback for focus events addFocusListener(listener) { if (this.focusListeners.indexOf(listener) == -1) this.focusListeners.push(listener); } // Determine whether the component participates in the tab sequence getTabStop() { return this.tabStop; } // Retrieve the control's text getText() { return this.text; } // Determine whether the control is enabled isEnabled() { return this.enabled; } // Determine the toggle button's active state isPressed() { return this.pressed; } // Determine whether the button is a toggle button isToggleable() { return this.toggleable; } // Specify whether the control is enabled setEnabled(enabled) { this.enabled = enabled = !!enabled; if (enabled) this.element.removeAttribute("disabled"); else this.element.setAttribute("disabled", ""); } // Specify whether the component participates in the regular tab sequence setTabStop(tabStop) { this.tabStop = tabStop = !!tabStop; this.element.setAttribute("tabindex", tabStop ? "0" : "-1"); } // Specify the toggle button's active state setPressed(pressed) { this.pressed = pressed = !!pressed; if (this.toggleable) this.element.setAttribute("aria-pressed", pressed); } // Specify the control's text setText(text) { this.text = text || ""; this.localize(); } // Specify whether the button is a toggle button setToggleable(toggleable) { this.toggleable = toggleable = !!toggleable; if (toggleable) this.element.setAttribute("aria-pressed", this.pressed); else this.element.removeAttribute("aria-pressed"); } ///////////////////////////// Private Methods ///////////////////////////// // Actions when the button is activated activate(e) { if (this.toggleable) this.setPressed(!this.pressed); for (let listener of this.clickListeners) listener(e, this); } // Update display text with localized strings localize() { let text = this.text; if (this.application) text = this.application.translate(text, this); this.element.innerText = text; this.element.setAttribute("aria-label", text); } // Blur event handler onblur(e) { for (let listener of this.blurListeners) listener(e, this); this.focusChanged( this, e.relatedTarget ? e.relatedTarget.component : null); } // Focus event handler onfocus(e) { for (let listener of this.focusListeners) listener(e, this); this.focusChanged( e.relatedTarget ? e.relatedTarget.component : null, this); } // Key press event handler onkeydown(e) { // Error checking if (e.key != " " && e.key != "Enter") return; // Configure event e.preventDefault(); e.stopPropagation(); // The button was activated this.activate(e); } // Pointer down event handler onpointerdown(e) { // Error checking if (e.button != 0 || this.element.hasPointerCapture(e.pointerId)) return; // Configure event e.preventDefault(); e.stopPropagation(); // Configure element this.element.focus(); this.element.setPointerCapture(e.pointerId); this.element.setAttribute("active", ""); } // Pointer move event handler onpointermove(e) { // Error checking if (!this.element.hasPointerCapture(e.pointerId)) return; // Configure event e.preventDefault(); e.stopPropagation(); // Working variables let bounds = this.element.getBoundingClientRect(); let active = e.x >= bounds.x && e.x < bounds.x + bounds.width && e.y >= bounds.y && e.y < bounds.y + bounds.height ; // Configure event if (active) this.element.setAttribute("active", ""); else this.element.removeAttribute("active"); } // Pointer up event handler onpointerup(e) { // Error checking if (!this.element.hasPointerCapture(e.pointerId)) return; // Configure event e.preventDefault(); e.stopPropagation(); // Working variables let active = this.element.hasAttribute("active"); // Configure element this.element.releasePointerCapture(e.pointerId); this.element.removeAttribute("active"); // The pointer was released without activating the button if (!active) return; // The button was activated this.activate(e); } };