Initial import of NODEDC BIM Viewer
This commit is contained in:
@@ -0,0 +1,298 @@
|
||||
import {Map} from "./Map.js";
|
||||
|
||||
/** @private */
|
||||
class Controller {
|
||||
|
||||
/**
|
||||
* @protected
|
||||
*/
|
||||
constructor(parent, cfg, server, viewer) {
|
||||
|
||||
this.bimViewer = (parent ? (parent.bimViewer || parent) : this);
|
||||
this.server = parent ? parent.server : server;
|
||||
this.viewer = parent ? parent.viewer : viewer;
|
||||
|
||||
this._children = [];
|
||||
|
||||
if (parent) {
|
||||
parent._children.push(this);
|
||||
}
|
||||
|
||||
this._subIdMap = null; // Subscription subId pool
|
||||
this._subIdEvents = null; // Subscription subIds mapped to event names
|
||||
this._eventSubs = null; // Event names mapped to subscribers
|
||||
this._events = null; // Maps names to events
|
||||
this._eventCallDepth = 0; // Helps us catch stack overflows from recursive events
|
||||
|
||||
this._enabled = null; // Used by #setEnabled() and #getEnabled()
|
||||
this._active = null; // Used by #setActive() and #getActive()
|
||||
}
|
||||
|
||||
/**
|
||||
* Fires an event on this Controller.
|
||||
*
|
||||
* @protected
|
||||
*
|
||||
* @param {String} event The event type name
|
||||
* @param {Object} value The event parameters
|
||||
* @param {Boolean} [forget=false] When true, does not retain for subsequent subscribers
|
||||
*/
|
||||
fire(event, value, forget) {
|
||||
if (!this._events) {
|
||||
this._events = {};
|
||||
}
|
||||
if (!this._eventSubs) {
|
||||
this._eventSubs = {};
|
||||
}
|
||||
if (forget !== true) {
|
||||
this._events[event] = value || true; // Save notification
|
||||
}
|
||||
const subs = this._eventSubs[event];
|
||||
let sub;
|
||||
if (subs) { // Notify subscriptions
|
||||
for (const subId in subs) {
|
||||
if (subs.hasOwnProperty(subId)) {
|
||||
sub = subs[subId];
|
||||
this._eventCallDepth++;
|
||||
if (this._eventCallDepth < 300) {
|
||||
sub.callback.call(sub.scope, value);
|
||||
} else {
|
||||
this.error("fire: potential stack overflow from recursive event '" + event + "' - dropping this event");
|
||||
}
|
||||
this._eventCallDepth--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Subscribes to an event on this Controller.
|
||||
*
|
||||
* The callback is be called with this component as scope.
|
||||
*
|
||||
* @param {String} event The event
|
||||
* @param {Function} callback Called fired on the event
|
||||
* @param {Object} [scope=this] Scope for the callback
|
||||
* @return {String} Handle to the subscription, which may be used to unsubscribe with {@link #off}.
|
||||
*/
|
||||
on(event, callback, scope) {
|
||||
if (!this._events) {
|
||||
this._events = {};
|
||||
}
|
||||
if (!this._subIdMap) {
|
||||
this._subIdMap = new Map(); // Subscription subId pool
|
||||
}
|
||||
if (!this._subIdEvents) {
|
||||
this._subIdEvents = {};
|
||||
}
|
||||
if (!this._eventSubs) {
|
||||
this._eventSubs = {};
|
||||
}
|
||||
let subs = this._eventSubs[event];
|
||||
if (!subs) {
|
||||
subs = {};
|
||||
this._eventSubs[event] = subs;
|
||||
}
|
||||
const subId = this._subIdMap.addItem(); // Create unique subId
|
||||
subs[subId] = {
|
||||
callback: callback,
|
||||
scope: scope || this
|
||||
};
|
||||
this._subIdEvents[subId] = event;
|
||||
const value = this._events[event];
|
||||
if (value !== undefined) { // A publication exists, notify callback immediately
|
||||
callback.call(scope || this, value);
|
||||
}
|
||||
return subId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancels an event subscription that was previously made with {@link Controller#on} or {@link Controller#once}.
|
||||
*
|
||||
* @param {String} subId Subscription ID
|
||||
*/
|
||||
off(subId) {
|
||||
if (subId === undefined || subId === null) {
|
||||
return;
|
||||
}
|
||||
if (!this._subIdEvents) {
|
||||
return;
|
||||
}
|
||||
const event = this._subIdEvents[subId];
|
||||
if (event) {
|
||||
delete this._subIdEvents[subId];
|
||||
const subs = this._eventSubs[event];
|
||||
if (subs) {
|
||||
delete subs[subId];
|
||||
}
|
||||
this._subIdMap.removeItem(subId); // Release subId
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Subscribes to the next occurrence of the given event, then un-subscribes as soon as the event is handled.
|
||||
*
|
||||
* This is equivalent to calling {@link Controller#on}, and then calling {@link Controller#off} inside the callback function.
|
||||
*
|
||||
* @param {String} event Data event to listen to
|
||||
* @param {Function} callback Called when fresh data is available at the event
|
||||
* @param {Object} [scope=this] Scope for the callback
|
||||
*/
|
||||
once(event, callback, scope) {
|
||||
const self = this;
|
||||
const subId = this.on(event,
|
||||
function (value) {
|
||||
self.off(subId);
|
||||
callback.call(scope || this, value);
|
||||
},
|
||||
scope);
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs a console debugging message for this Controller.
|
||||
*
|
||||
* The console message will have this format: *````[LOG] [<component type> <component id>: <message>````*
|
||||
*
|
||||
* @protected
|
||||
*
|
||||
* @param {String} message The message to log
|
||||
*/
|
||||
log(message) {
|
||||
message = "[LOG] " + message;
|
||||
window.console.log(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs a warning for this Controller to the JavaScript console.
|
||||
*
|
||||
* The console message will have this format: *````[WARN] [<component type> =<component id>: <message>````*
|
||||
*
|
||||
* @protected
|
||||
*
|
||||
* @param {String} message The message to log
|
||||
*/
|
||||
warn(message) {
|
||||
message = "[WARN] " + message;
|
||||
window.console.warn(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs an error for this Controller to the JavaScript console.
|
||||
*
|
||||
* The console message will have this format: *````[ERROR] [<component type> =<component id>: <message>````*
|
||||
*
|
||||
* @protected
|
||||
*
|
||||
* @param {String} message The message to log
|
||||
*/
|
||||
error(message) {
|
||||
message = "[ERROR] " + message;
|
||||
window.console.error(message);
|
||||
}
|
||||
|
||||
_mutexActivation(controllers) {
|
||||
const numControllers = controllers.length;
|
||||
for (let i = 0; i < numControllers; i++) {
|
||||
const controller = controllers[i];
|
||||
if (controller) {
|
||||
controller.on("active", (function () {
|
||||
const _i = i;
|
||||
return function (active) {
|
||||
if (!active) {
|
||||
return;
|
||||
}
|
||||
for (let j = 0; j < numControllers; j++) {
|
||||
if (j === _i) {
|
||||
continue;
|
||||
}
|
||||
controllers[j].setActive(false);
|
||||
}
|
||||
};
|
||||
})());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables or disables this Controller.
|
||||
*
|
||||
* Fires an "enabled" event on update.
|
||||
*
|
||||
* @protected
|
||||
* @param {boolean} enabled Whether or not to enable.
|
||||
*/
|
||||
setEnabled(enabled) {
|
||||
if (this._enabled === enabled) {
|
||||
return;
|
||||
}
|
||||
this._enabled = enabled;
|
||||
this.fire("enabled", this._enabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether or not this Controller is enabled.
|
||||
*
|
||||
* @protected
|
||||
*
|
||||
* @returns {boolean}
|
||||
*/
|
||||
getEnabled() {
|
||||
return this._enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Activates or deactivates this Controller.
|
||||
*
|
||||
* Fires an "active" event on update.
|
||||
*
|
||||
* @protected
|
||||
*
|
||||
* @param {boolean} active Whether or not to activate.
|
||||
*/
|
||||
setActive(active) {
|
||||
if (this._active === active) {
|
||||
return;
|
||||
}
|
||||
this._active = active;
|
||||
this.fire("active", this._active);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether or not this Controller is active.
|
||||
*
|
||||
* @protected
|
||||
*
|
||||
* @returns {boolean}
|
||||
*/
|
||||
getActive() {
|
||||
return this._active;
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroys this Controller.
|
||||
*
|
||||
* @protected
|
||||
*
|
||||
*/
|
||||
destroy() {
|
||||
if (this.destroyed) {
|
||||
return;
|
||||
}
|
||||
/**
|
||||
* Fired when this Controller is destroyed.
|
||||
* @event destroyed
|
||||
*/
|
||||
this.fire("destroyed", this.destroyed = true);
|
||||
this._subIdMap = null;
|
||||
this._subIdEvents = null;
|
||||
this._eventSubs = null;
|
||||
this._events = null;
|
||||
this._eventCallDepth = 0;
|
||||
for (let i = 0, len = this._children.length; i < len; i++) {
|
||||
this._children[i].destroy();
|
||||
}
|
||||
this._children = [];
|
||||
}
|
||||
}
|
||||
|
||||
export {Controller};
|
||||
Reference in New Issue
Block a user