/** * This is the base class for components. The purpose is to abstract away several * common idioms to make derived components simpler. * * Usage: * function Component(gristDoc) { * Base.call(this, gristDoc); * ... * } * Base.setBaseFor(Component); * * To create an object: * var obj = Component.create(constructor_args...); */ /* global $ */ var dispose = require('../lib/dispose'); /** * gristDoc may be null when there is no active document. */ function Base(gristDoc) { this.gristDoc = gristDoc; this._debugName = this.constructor.name + '[' + Base._nextObjectId + ']'; // TODO: devise a logging system that allows turning on/off different debug tags and levels. //console.log(this._debugName, "Base constructor"); this._eventNamespace = '.Events_' + (Base._nextObjectId++); this._eventSources = []; this.autoDisposeCallback(this.clearEvents); } Base._nextObjectId = 1; /** * Sets ctor to inherit prototype methods from Base. * @param {function} ctor Constructor function which needs to inherit Base's prototype. */ Base.setBaseFor = function(ctor) { ctor.prototype = Object.create(Base.prototype, { constructor: { value: ctor, enumerable: false, writable: true, configurable: true } }); dispose.makeDisposable(ctor); }; /** * Subscribe to eventType on source, similarly to $(source).on(eventType, optSelector, method). * In fact, this uses JQuery internally. The convenience is that it allows unsubscribing in bulk. * Also, method is called with the context of `this`. */ Base.prototype.onEvent = function(source, eventType, optSelector, method) { if (typeof optSelector != 'string') { method = optSelector; optSelector = null; } if (this._eventSources.indexOf(source) === -1) this._eventSources.push(source); var self = this; $(source).on(eventType + this._eventNamespace, optSelector, function(event_args) { Array.prototype.unshift.call(arguments, this); // Unshift is generic enough for 'arguments'. if (self._eventSources) return method.apply(self, arguments); }); }; /** * Unsubscribes this object from eventType on source, similarly to $(source).off(eventType). */ Base.prototype.clearEvent = function(source, eventType) { $(source).off(eventType + this._eventNamespace); }; /** * Unsubscribes this object from all events that it subscribed to via onEvent(). */ Base.prototype.clearEvents = function() { var sources = this._eventSources; for (var i = 0; i < sources.length; i++) { $(sources[i]).off(this._eventNamespace); } this._eventSources.length = 0; }; module.exports = Base;