BIMviewer

Форк
0
/
Controller.js 
298 строк · 8.4 Кб
1
import {Map} from "./Map.js";
2

3
/** @private */
4
class Controller {
5

6
    /**
7
     * @protected
8
     */
9
    constructor(parent, cfg, server, viewer) {
10

11
        this.bimViewer = (parent ? (parent.bimViewer || parent) : this);
12
        this.server = parent ? parent.server : server;
13
        this.viewer = parent ? parent.viewer : viewer;
14

15
        this._children = [];
16

17
        if (parent) {
18
            parent._children.push(this);
19
        }
20

21
        this._subIdMap = null; // Subscription subId pool
22
        this._subIdEvents = null; // Subscription subIds mapped to event names
23
        this._eventSubs = null; // Event names mapped to subscribers
24
        this._events = null; // Maps names to events
25
        this._eventCallDepth = 0; // Helps us catch stack overflows from recursive events
26

27
        this._enabled = null; // Used by #setEnabled() and #getEnabled()
28
        this._active = null; // Used by #setActive() and #getActive()
29
    }
30

31
    /**
32
     * Fires an event on this Controller.
33
     *
34
     * @protected
35
     *
36
     * @param {String} event The event type name
37
     * @param {Object} value The event parameters
38
     * @param {Boolean} [forget=false] When true, does not retain for subsequent subscribers
39
     */
40
    fire(event, value, forget) {
41
        if (!this._events) {
42
            this._events = {};
43
        }
44
        if (!this._eventSubs) {
45
            this._eventSubs = {};
46
        }
47
        if (forget !== true) {
48
            this._events[event] = value || true; // Save notification
49
        }
50
        const subs = this._eventSubs[event];
51
        let sub;
52
        if (subs) { // Notify subscriptions
53
            for (const subId in subs) {
54
                if (subs.hasOwnProperty(subId)) {
55
                    sub = subs[subId];
56
                    this._eventCallDepth++;
57
                    if (this._eventCallDepth < 300) {
58
                        sub.callback.call(sub.scope, value);
59
                    } else {
60
                        this.error("fire: potential stack overflow from recursive event '" + event + "' - dropping this event");
61
                    }
62
                    this._eventCallDepth--;
63
                }
64
            }
65
        }
66
    }
67

68
    /**
69
     * Subscribes to an event on this Controller.
70
     *
71
     * The callback is be called with this component as scope.
72
     *
73
     * @param {String} event The event
74
     * @param {Function} callback Called fired on the event
75
     * @param {Object} [scope=this] Scope for the callback
76
     * @return {String} Handle to the subscription, which may be used to unsubscribe with {@link #off}.
77
     */
78
    on(event, callback, scope) {
79
        if (!this._events) {
80
            this._events = {};
81
        }
82
        if (!this._subIdMap) {
83
            this._subIdMap = new Map(); // Subscription subId pool
84
        }
85
        if (!this._subIdEvents) {
86
            this._subIdEvents = {};
87
        }
88
        if (!this._eventSubs) {
89
            this._eventSubs = {};
90
        }
91
        let subs = this._eventSubs[event];
92
        if (!subs) {
93
            subs = {};
94
            this._eventSubs[event] = subs;
95
        }
96
        const subId = this._subIdMap.addItem(); // Create unique subId
97
        subs[subId] = {
98
            callback: callback,
99
            scope: scope || this
100
        };
101
        this._subIdEvents[subId] = event;
102
        const value = this._events[event];
103
        if (value !== undefined) { // A publication exists, notify callback immediately
104
            callback.call(scope || this, value);
105
        }
106
        return subId;
107
    }
108

109
    /**
110
     * Cancels an event subscription that was previously made with {@link Controller#on} or {@link Controller#once}.
111
     *
112
     * @param {String} subId Subscription ID
113
     */
114
    off(subId) {
115
        if (subId === undefined || subId === null) {
116
            return;
117
        }
118
        if (!this._subIdEvents) {
119
            return;
120
        }
121
        const event = this._subIdEvents[subId];
122
        if (event) {
123
            delete this._subIdEvents[subId];
124
            const subs = this._eventSubs[event];
125
            if (subs) {
126
                delete subs[subId];
127
            }
128
            this._subIdMap.removeItem(subId); // Release subId
129
        }
130
    }
131

132
    /**
133
     * Subscribes to the next occurrence of the given event, then un-subscribes as soon as the event is handled.
134
     *
135
     * This is equivalent to calling {@link Controller#on}, and then calling {@link Controller#off} inside the callback function.
136
     *
137
     * @param {String} event Data event to listen to
138
     * @param {Function} callback Called when fresh data is available at the event
139
     * @param {Object} [scope=this] Scope for the callback
140
     */
141
    once(event, callback, scope) {
142
        const self = this;
143
        const subId = this.on(event,
144
            function (value) {
145
                self.off(subId);
146
                callback.call(scope || this, value);
147
            },
148
            scope);
149
    }
150

151
    /**
152
     * Logs a console debugging message for this Controller.
153
     *
154
     * The console message will have this format: *````[LOG] [<component type> <component id>: <message>````*
155
     *
156
     * @protected
157
     *
158
     * @param {String} message The message to log
159
     */
160
    log(message) {
161
        message = "[LOG] " + message;
162
        window.console.log(message);
163
    }
164

165
    /**
166
     * Logs a warning for this Controller to the JavaScript console.
167
     *
168
     * The console message will have this format: *````[WARN] [<component type> =<component id>: <message>````*
169
     *
170
     * @protected
171
     *
172
     * @param {String} message The message to log
173
     */
174
    warn(message) {
175
        message = "[WARN] " + message;
176
        window.console.warn(message);
177
    }
178

179
    /**
180
     * Logs an error for this Controller to the JavaScript console.
181
     *
182
     * The console message will have this format: *````[ERROR] [<component type> =<component id>: <message>````*
183
     *
184
     * @protected
185
     *
186
     * @param {String} message The message to log
187
     */
188
    error(message) {
189
        message = "[ERROR] " + message;
190
        window.console.error(message);
191
    }
192

193
    _mutexActivation(controllers) {
194
        const numControllers = controllers.length;
195
        for (let i = 0; i < numControllers; i++) {
196
            const controller = controllers[i];
197
            if (controller) {
198
                controller.on("active", (function () {
199
                    const _i = i;
200
                    return function (active) {
201
                        if (!active) {
202
                            return;
203
                        }
204
                        for (let j = 0; j < numControllers; j++) {
205
                            if (j === _i) {
206
                                continue;
207
                            }
208
                            controllers[j].setActive(false);
209
                        }
210
                    };
211
                })());
212
            }
213
        }
214
    }
215

216
    /**
217
     * Enables or disables this Controller.
218
     *
219
     * Fires an "enabled" event on update.
220
     *
221
     * @protected
222
     * @param {boolean} enabled Whether or not to enable.
223
     */
224
    setEnabled(enabled) {
225
        if (this._enabled === enabled) {
226
            return;
227
        }
228
        this._enabled = enabled;
229
        this.fire("enabled", this._enabled);
230
    }
231

232
    /**
233
     * Gets whether or not this Controller is enabled.
234
     *
235
     * @protected
236
     *
237
     * @returns {boolean}
238
     */
239
    getEnabled() {
240
        return this._enabled;
241
    }
242

243
    /**
244
     * Activates or deactivates this Controller.
245
     *
246
     * Fires an "active" event on update.
247
     *
248
     * @protected
249
     *
250
     * @param {boolean} active Whether or not to activate.
251
     */
252
    setActive(active) {
253
        if (this._active === active) {
254
            return;
255
        }
256
        this._active = active;
257
        this.fire("active", this._active);
258
    }
259

260
    /**
261
     * Gets whether or not this Controller is active.
262
     *
263
     * @protected
264
     *
265
     * @returns {boolean}
266
     */
267
    getActive() {
268
        return this._active;
269
    }
270

271
    /**
272
     * Destroys this Controller.
273
     *
274
     * @protected
275
     *
276
     */
277
    destroy() {
278
        if (this.destroyed) {
279
            return;
280
        }
281
        /**
282
         * Fired when this Controller is destroyed.
283
         * @event destroyed
284
         */
285
        this.fire("destroyed", this.destroyed = true);
286
        this._subIdMap = null;
287
        this._subIdEvents = null;
288
        this._eventSubs = null;
289
        this._events = null;
290
        this._eventCallDepth = 0;
291
        for (let i = 0, len = this._children.length; i < len; i++) {
292
            this._children[i].destroy();
293
        }
294
        this._children = [];
295
    }
296
}
297

298
export {Controller};

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.