pvbemu/app/toolkit/Component.js

180 lines
5.4 KiB
JavaScript

"use strict";
// Base features for all components
Toolkit.Component = class Component {
// Object constructor
constructor(application, tagname, options) {
options = options || {};
// Configure instance fields
this.application = application;
this.containers = [ this ];
this.display = null;
this.element = document.createElement(tagname);
this.id = this.element.id = Toolkit.id();
this.parent = null;
this.properties = {};
this.resizeListeners = [];
this.resizeObserver = null;
this.visible = "visible" in options ? !!options.visible : true;
// Configure component
this.element.component = this;
this.setSize(
"width" in options ? options.width : null,
"height" in options ? options.height : null
);
this.setVisible(this.visible);
}
///////////////////////////// Public Methods //////////////////////////////
// Add a callback for resize events
addResizeListener(listener) {
if (this.resizeListeners.indexOf(listener) != -1)
return;
if (this.resizeObserver == null) {
this.resizeObserver = new ResizeObserver(()=>this.onresized());
this.resizeObserver.observe(this.element);
}
this.resizeListeners.push(listener);
}
// Retrieve the bounding box of the element
getBounds() {
return this.element.getBoundingClientRect();
}
// Retrieve the display CSS property of the visible element
getDisplay() {
return this.display;
}
// Determine whether the component is visible
isVisible() {
for (let comp = this; comp != null; comp = comp.parent)
if (!comp.visible)
return false;
return true;
}
// Specify the location and size of the component
setBounds(left, top, width, height, minimum) {
this.setLeft (left );
this.setTop (top );
this.setWidth (width , minimum);
this.setHeight(height, minimum);
}
// Specify the display CSS property of the visible element
setDisplay(display) {
this.display = display || null;
this.setVisible(this.visible);
}
// Specify the height of the component
setHeight(height, minimum) {
if (height === null) {
this.element.style.removeProperty("min-height");
this.element.style.removeProperty("height");
} else {
height = typeof height == "number" ?
Math.max(0, height) + "px" : height;
this.element.style.height = height;
if (minimum)
this.element.style.minHeight = height;
else this.element.style.removeProperty("min-height");
}
}
// Specify the horizontal position of the component
setLeft(left) {
if (left === null)
this.element.style.removeProperty("left");
else this.element.style.left =
typeof left == "number" ? left + "px" : left ;
}
// Specify the absolute position of the component
setLocation(left, top) {
this.setLeft(left);
this.setTop (top );
}
// Specify a localization property value
setProperty(key, value) {
this.properties[key] = value;
this.localize();
}
// Specify both the width and the height of the component
setSize(width, height, minimum) {
this.setHeight(height, minimum);
this.setWidth (width , minimum);
}
// Specify the vertical position of the component
setTop(top) {
if (top === null)
this.element.style.removeProperty("top");
else this.element.style.top =
typeof top == "number" ? top + "px" : top ;
}
// Specify whether the component is visible
setVisible(visible) {
this.visible = visible = !!visible;
if (visible) {
if (this.display == null)
this.element.style.removeProperty("display");
else this.element.style.display = this.display;
} else this.element.style.display = "none";
}
// Specify the width of the component
setWidth(width, minimum) {
if (width === null) {
this.element.style.removeProperty("min-width");
this.element.style.removeProperty("width");
} else {
width = typeof width == "number" ?
Math.max(0, width) + "px" : width;
this.element.style.width = width;
if (minimum)
this.element.style.minWidth = width;
else this.element.style.removeProperty("min-width");
}
}
///////////////////////////// Package Methods /////////////////////////////
// Determine whether this component contains another
contains(comp) {
if (comp == null)
return false;
if (comp instanceof Toolkit.Component)
comp = comp.element;
for (let cont of this.containers)
if ((cont instanceof Toolkit.Component ? cont.element : cont)
.contains(comp)) return true;
return false;
}
///////////////////////////// Private Methods /////////////////////////////
// Resize event handler
onresized() {
let bounds = this.getBounds();
for (let listener of this.resizeListeners)
listener(bounds);
}
};