derby
Version:
MVC framework making it easy to write realtime, collaborative applications that run in both Node.js and browsers.
244 lines (243 loc) • 9.11 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.Context = exports.ContextMeta = void 0;
function noop() { }
/**
* Properties and methods which are globally inherited for the entire page
*/
var ContextMeta = /** @class */ (function () {
function ContextMeta() {
this.addBinding = noop;
this.removeBinding = noop;
this.removeNode = noop;
this.addItemContext = noop;
this.removeItemContext = noop;
this.views = null;
this.idNamespace = '';
this.idCount = 0;
this.pending = [];
this.pauseCount = 0;
}
return ContextMeta;
}());
exports.ContextMeta = ContextMeta;
var Context = /** @class */ (function () {
function Context(meta, controller, parent, unbound, expression) {
// Required properties //
// Properties which are globally inherited for the entire page
this.meta = meta;
// The page or component. Must have a `model` property with a `data` property
this.controller = controller;
// Optional properties //
// Containing context
this.parent = parent;
// Boolean set to true when bindings should be ignored
this.unbound = unbound;
// The expression for a block
this.expression = expression;
// Alias name for the given expression
this.alias = expression && expression.meta && expression.meta.as;
// Alias name for the index or iterated key
this.keyAlias = expression && expression.meta && expression.meta.keyAs;
// For Context::eachChild
// The context of the each at render time
this.item = null;
// For Context::viewChild
// Reference to the current view
this.view = null;
// Attribute values passed to the view instance
this.attributes = null;
// MarkupHooks to be called after insert into DOM of component
this.hooks = null;
// MarkupHooks to be called immediately before init of component
this.initHooks = null;
// For Context::closureChild
// Reference to another context established at render time by ContextClosure
this.closure = null;
// Used in EventModel
this._id = null;
this._eventModels = null;
}
/**
* Generate unique Id
*
* @returns namespaced Id
*/
Context.prototype.id = function () {
var count = ++this.meta.idCount;
return this.meta.idNamespace + '_' + count.toString(36);
};
Context.prototype.addBinding = function (binding) {
// Don't add bindings that wrap list items. Only their outer range is needed
if (binding.itemFor)
return;
var expression = binding.template.expression;
// Don't rerender in unbound sections
if (expression ? expression.isUnbound(this) : this.unbound)
return;
// Don't rerender to changes in a with expression
if (expression && expression.meta && expression.meta.blockType === 'with')
return;
this.meta.addBinding(binding);
};
Context.prototype.removeBinding = function (binding) {
this.meta.removeBinding(binding);
};
Context.prototype.removeNode = function (node) {
var bindItemStart = node.$bindItemStart;
if (bindItemStart) {
this.meta.removeItemContext(bindItemStart.context);
}
var component = node.$component;
if (component) {
node.$component = null;
if (!component.singleton) {
component.destroy();
}
}
var destroyListeners = node.$destroyListeners;
if (destroyListeners) {
node.$destroyListeners = null;
for (var i = 0, len = destroyListeners.length; i < len; i++) {
destroyListeners[i]();
}
}
};
Context.prototype.child = function (expression) {
// Set or inherit the binding mode
var blockType = expression.meta && expression.meta.blockType;
var unbound = (blockType === 'unbound') ? true :
(blockType === 'bound') ? false :
this.unbound;
return new Context(this.meta, this.controller, this, unbound, expression);
};
Context.prototype.componentChild = function (component) {
return new Context(this.meta, component, this, this.unbound);
};
/**
* Make a context for an item in an each block
*
* @param expression
* @param item
* @returns new Context
*/
Context.prototype.eachChild = function (expression, item) {
var context = new Context(this.meta, this.controller, this, this.unbound, expression);
context.item = item;
this.meta.addItemContext(context);
return context;
};
Context.prototype.viewChild = function (view, attributes, hooks, initHooks) {
var context = new Context(this.meta, this.controller, this, this.unbound);
context.view = view;
context.attributes = attributes;
context.hooks = hooks;
context.initHooks = initHooks;
return context;
};
Context.prototype.closureChild = function (closure) {
var context = new Context(this.meta, this.controller, this, this.unbound);
context.closure = closure;
return context;
};
Context.prototype.forRelative = function (expression) {
// eslint-disable-next-line @typescript-eslint/no-this-alias
var context = this;
while (context && context.expression === expression || context.view) {
context = context.parent;
}
return context;
};
// Returns the closest context which defined the named alias
Context.prototype.forAlias = function (alias) {
// eslint-disable-next-line @typescript-eslint/no-this-alias
var context = this;
while (context) {
if (context.alias === alias || context.keyAlias === alias)
return context;
context = context.parent;
}
};
// Returns the closest containing context for a view attribute name or nothing
Context.prototype.forAttribute = function (attribute) {
// eslint-disable-next-line @typescript-eslint/no-this-alias
var context = this;
while (context) {
// Find the closest context associated with a view
if (context.view) {
var attributes = context.attributes;
if (!attributes)
return;
if (Object.prototype.hasOwnProperty.call(attributes, attribute))
return context;
// If the attribute isn't found, but the attributes inherit, continue
// looking in the next closest view context
if (!attributes.inherit && !attributes.extend)
return;
}
context = context.parent;
}
};
Context.prototype.forViewParent = function () {
// eslint-disable-next-line @typescript-eslint/no-this-alias
var context = this;
while (context) {
// When a context with a `closure` property is encountered, skip to its
// parent context rather than returning the nearest view's. This reference
// is created by wrapping a template in a ContextClosure template
if (context.closure)
return context.closure.parent;
// Find the closest view and return the containing context
if (context.view)
return context.parent;
context = context.parent;
}
};
/**
* Gets the current `context` view or closest `context.parent` view
*
* @returns view
*/
Context.prototype.getView = function () {
// eslint-disable-next-line @typescript-eslint/no-this-alias
var context = this;
while (context) {
// Find the closest view
if (context.view)
return context.view;
context = context.parent;
}
};
// Returns the `this` value for a context
Context.prototype.get = function () {
var value = (this.expression) ?
this.expression.get(this) :
this.controller.model.data;
if (this.item != null) {
return value && value[this.item];
}
return value;
};
Context.prototype.pause = function () {
this.meta.pauseCount++;
};
Context.prototype.unpause = function () {
if (--this.meta.pauseCount)
return;
this.flush();
};
Context.prototype.flush = function () {
var pending = this.meta.pending;
var len = pending.length;
if (!len)
return;
this.meta.pending = [];
for (var i = 0; i < len; i++) {
pending[i]();
}
};
Context.prototype.queue = function (cb) {
this.meta.pending.push(cb);
};
return Context;
}());
exports.Context = Context;