@web-atoms/core
Version:
559 lines (558 loc) • 19.4 kB
JavaScript
System.register(["tslib", "../App", "../core/types", "../di/Inject", "./AtomDisposableList", "./AtomWatcher", "./Bind", "./Hacks", "./InheritedProperty", "./PropertyMap", "./XNode"], function (_export, _context) {
"use strict";
var __decorate, __metadata, __param, App, ArrayHelper, CancelToken, ignoreValue, Inject, AtomDisposableList, AtomWatcher, bindSymbol, visitDescendents, watchProperty, InheritedProperty, PropertyMap, isControl, isFactorySymbol, xnodeSymbol, PropertyBinding, _a, _b, localBindSymbol, localXNodeSymbol, AtomComponent;
_export("PropertyBinding", void 0);
return {
setters: [function (_tslib) {
__decorate = _tslib.__decorate;
__metadata = _tslib.__metadata;
__param = _tslib.__param;
}, function (_App) {
App = _App.App;
}, function (_coreTypes) {
ArrayHelper = _coreTypes.ArrayHelper;
CancelToken = _coreTypes.CancelToken;
ignoreValue = _coreTypes.ignoreValue;
}, function (_diInject) {
Inject = _diInject.Inject;
}, function (_AtomDisposableList) {
AtomDisposableList = _AtomDisposableList.AtomDisposableList;
}, function (_AtomWatcher) {
AtomWatcher = _AtomWatcher.AtomWatcher;
}, function (_Bind) {
bindSymbol = _Bind.bindSymbol;
}, function (_Hacks) {
visitDescendents = _Hacks.visitDescendents;
watchProperty = _Hacks.watchProperty;
}, function (_InheritedProperty) {
InheritedProperty = _InheritedProperty.InheritedProperty;
}, function (_PropertyMap) {
PropertyMap = _PropertyMap.PropertyMap;
}, function (_XNode) {
isControl = _XNode.isControl;
isFactorySymbol = _XNode.isFactorySymbol;
xnodeSymbol = _XNode.xnodeSymbol;
}],
execute: function () {
localBindSymbol = bindSymbol;
localXNodeSymbol = xnodeSymbol;
_export("AtomComponent", AtomComponent = class AtomComponent {
get vsProps() {
return undefined;
}
constructor(app, element = null) {
this.app = app;
this.mInvalidated = 0;
this.mPendingPromises = {};
this.disposables = new AtomDisposableList();
this.bindings = [];
this.eventHandlers = [];
this.element = element;
this.element.atomControl = this;
const a = this.beginEdit();
this.preCreate();
this.create();
app.callLater(() => a.dispose());
}
bind(element, name, path, twoWays, valueFunc, source) {
const binding = new PropertyBinding(this, element, name, path, twoWays, valueFunc, source);
this.bindings.push(binding);
return {
dispose: () => {
binding.dispose();
ArrayHelper.remove(this.bindings, x => x === binding);
}
};
}
unbind(element, name) {
const toDelete = this.bindings.filter(x => x.element === element && (!name || x.name === name));
for (const iterator of toDelete) {
iterator.dispose();
ArrayHelper.remove(this.bindings, x => x === iterator);
}
}
bindEvent(element, name, method, key, capture) {
if (!element) {
return;
}
if (!method) {
return;
}
const be = {
element,
name,
handler: method
};
if (key) {
be.key = key;
}
const handler = e => {
var _c;
try {
let r = method(e);
e.executed = true;
if (r) {
const originalReturn = r;
r = r.then ? r : Promise.resolve(r);
e.promise = e.promise ? e.promise.then(() => r) : r;
if (originalReturn.catch) {
return originalReturn.catch(c => {
var _c;
if (CancelToken.isCancelled(c !== null && c !== void 0 ? c : "Unknown error")) {
return;
}
alert((_c = c.stack) !== null && _c !== void 0 ? _c : c);
});
}
return r;
}
} catch (error) {
if (CancelToken.isCancelled(error)) {
return;
}
alert((_c = error.stack) !== null && _c !== void 0 ? _c : error);
}
};
element.addEventListener(name, handler, capture);
be.disposable = {
dispose: () => {
element.removeEventListener(name, handler, capture);
be.disposable.dispose = () => undefined;
}
};
this.eventHandlers.push(be);
return {
dispose: () => {
be.disposable.dispose();
ArrayHelper.remove(this.eventHandlers, e => e.disposable === be.disposable);
}
};
}
unbindEvent(element, name, method, key) {
const deleted = [];
for (const be of this.eventHandlers) {
if (element && be.element !== element) {
return;
}
if (key && be.key !== key) {
return;
}
if (name && be.name !== name) {
return;
}
if (method && be.handler !== method) {
return;
}
be.disposable.dispose();
be.handler = null;
be.element = null;
be.name = null;
be.key = null;
deleted.push(() => this.eventHandlers.remove(be));
}
for (const iterator of deleted) {
iterator();
}
}
hasProperty(name) {
if (/^(data|viewModel|localViewModel|element)$/.test(name)) {
return true;
}
const map = PropertyMap.from(this);
if (map.map[name]) {
return true;
}
if (this[name] !== undefined) {
return true;
}
return false;
}
setPrimitiveValue(element, name, value) {
const p = value;
if (p && p.then && p.catch) {
console.warn(`Do not bind promises, instead use Bind.oneWayAsync`);
this.mPendingPromises[name] = p;
p.then(r => {
if (this.mPendingPromises[name] !== p) {
return;
}
this.mPendingPromises[name] = null;
this.setPrimitiveValue(element, name, r);
}).catch(e => {
if (this.mPendingPromises[name] !== p) {
return;
}
this.mPendingPromises[name] = null;
console.error(e);
});
return;
}
if (/^(viewModel|localViewModel)$/.test(name)) {
this[name] = value;
return;
}
if ((!element || element === this.element) && this.hasProperty(name)) {
this.runAfterInit(() => {
this[name] = value;
});
} else {
this.setElementValue(element, name, value);
}
}
setLocalValue(element, name, value) {
const p = value;
if (p && p.then && p.catch) {
console.warn(`Do not bind promises, instead use Bind.oneWayAsync`);
this.mPendingPromises[name] = p;
p.then(r => {
if (this.mPendingPromises[name] !== p) {
return;
}
this.mPendingPromises[name] = null;
this.setLocalValue(element, name, r);
}).catch(e => {
if (this.mPendingPromises[name] !== p) {
return;
}
this.mPendingPromises[name] = null;
console.error(e);
});
return;
}
if ((!element || element === this.element) && Reflect.has(this, name)) {
this[name] = value;
} else {
this.setElementValue(element, name, value);
}
}
dispose(e) {
if (this.mInvalidated) {
clearTimeout(this.mInvalidated);
this.mInvalidated = 0;
}
visitDescendents(e || this.element, (ex, ac) => {
if (ac) {
ac.dispose();
return false;
}
return true;
});
if (!e) {
this.unbindEvent(null, null, null);
for (const binding of this.bindings) {
binding.dispose();
}
this.bindings.length = 0;
this.bindings = null;
const e1 = this.element;
if (typeof e1.dispose === "function") {
e1.dispose();
}
this.element = null;
const lvm = this.localViewModel;
if (lvm && lvm.dispose) {
lvm.dispose();
this.localViewModel = null;
}
const vm = this.viewModel;
if (vm && vm.dispose) {
vm.dispose();
this.viewModel = null;
}
this.disposables.dispose();
this.pendingInits = null;
}
}
onPropertyChanged(name) {}
beginEdit() {
this.pendingInits = [];
const a = this.pendingInits;
return {
dispose: () => {
if (this.pendingInits == null) {
return;
}
this.pendingInits = null;
if (a) {
for (const iterator of a) {
iterator();
}
}
this.invalidate();
}
};
}
invalidate() {
if (this.mInvalidated) {
clearTimeout(this.mInvalidated);
}
this.mInvalidated = setTimeout(() => {
this.mInvalidated = 0;
this.app.callLater(() => {
this.onUpdateUI();
});
}, 5);
}
onUpdateUI() {}
runAfterInit(f) {
if (this.pendingInits) {
this.pendingInits.push(f);
} else {
f();
}
}
registerDisposable(d) {
return this.disposables.add(d);
}
render(node, e = this.element, creator = this.creator || this) {
const app = this.app;
const attr = node.attributes;
if (attr) {
for (const key in attr) {
if (attr.hasOwnProperty(key)) {
const item = attr[key];
const isObject = typeof item === "object";
if (isObject && item !== null) {
const localSymbol = item[localBindSymbol];
if (localSymbol) {
localSymbol(key, this, e, creator);
continue;
}
const localXNode = item[localXNodeSymbol];
if (localXNode) {
if (item.isTemplate) {
this.setLocalValue(e, key, this.toTemplate(app, item, creator));
continue;
}
this.setLocalValue(e, key, this.createNode(app, null, item, creator));
continue;
}
}
this.setLocalValue(e, key, item);
}
}
}
const children = node.children;
if (children === void 0) {
return;
}
for (const iterator of children) {
if (!iterator) {
continue;
}
if (!iterator[localXNodeSymbol]) {
e.appendChild(document.createTextNode(iterator.toString()));
continue;
}
if (iterator.isProperty) {
if (iterator.isTemplate) {
this.setLocalValue(e, iterator.name, this.toTemplate(app, iterator.children[0], creator));
continue;
}
this.createNode(app, e, iterator, creator);
continue;
}
const t = iterator.attributes && iterator.attributes.template;
if (t) {
console.warn(`This path is deprecated, check who is calling it.`);
this.setLocalValue(e, t, this.toTemplate(app, iterator, creator));
continue;
}
this.createNode(app, e, iterator, creator);
}
}
extractControlProperties(x, name = "div") {
const a = x.attributes;
const extracted = {};
if (typeof x.name === "function" && this instanceof x.name) {
x.name = name;
}
if (a) {
for (const key in a) {
if (Object.prototype.hasOwnProperty.call(a, key)) {
if (Reflect.has(this, key)) {
const element = a[key];
extracted[key] = element;
delete a[key];
}
}
}
}
return extracted;
}
create() {}
preCreate() {}
setElementValue(element, name, value) {
element[name] = value;
}
resolve(c, selfName) {
const result = this.app.resolve(c, true);
if (selfName) {
if (typeof selfName === "function") {
this.runAfterInit(() => {
const v = selfName();
if (v) {
for (const key in v) {
if (v.hasOwnProperty(key)) {
const element = v[key];
result[key] = element;
}
}
}
});
} else {
result[selfName] = this;
}
}
return result;
}
pushInit() {
this.runAfterInit(() => {
var _c, _d, _e;
(_e = (_d = (_c = this).init) === null || _d === void 0 ? void 0 : _d.call(_c)) === null || _e === void 0 ? void 0 : _e.catch(error => CancelToken.isCancelled(error) ? void 0 : console.error(error));
});
}
});
_a = isControl;
_b = isFactorySymbol;
AtomComponent[_a] = true;
AtomComponent[_b] = true;
__decorate([InheritedProperty, __metadata("design:type", Object)], AtomComponent.prototype, "data", void 0);
__decorate([InheritedProperty, __metadata("design:type", Object)], AtomComponent.prototype, "viewModel", void 0);
__decorate([InheritedProperty, __metadata("design:type", Object)], AtomComponent.prototype, "localViewModel", void 0);
_export("AtomComponent", AtomComponent = __decorate([__param(0, Inject), __metadata("design:paramtypes", [App, Object])], AtomComponent));
_export("PropertyBinding", PropertyBinding = class PropertyBinding {
constructor(target, element, name, path, twoWays, valueFunc, source) {
this.target = target;
this.element = element;
this.name = name;
this.twoWays = twoWays;
this.source = source;
this.isTwoWaySetup = false;
this.name = name;
this.twoWays = twoWays;
this.target = target;
this.element = element;
this.isRunning = false;
if (valueFunc) {
if (typeof valueFunc !== "function") {
this.fromSourceToTarget = valueFunc.fromSource;
this.fromTargetToSource = valueFunc.fromTarget;
} else {
this.fromSourceToTarget = valueFunc;
}
}
this.watcher = new AtomWatcher(target, path, (...v) => {
if (this.isRunning) {
return;
}
if (this.disposed) {
return;
}
for (const iterator of v) {
if (iterator === undefined) {
return;
}
}
const cv = this.fromSourceToTarget ? this.fromSourceToTarget.apply(this, v) : v[0];
if (cv === ignoreValue) {
return;
}
this.isRunning = true;
try {
if (this.target instanceof AtomComponent) {
this.target.setLocalValue(this.element, this.name, cv);
} else {
this.target[name] = cv;
}
} finally {
this.isRunning = false;
}
}, source);
this.path = this.watcher.path;
if (this.target instanceof AtomComponent) {
this.target.runAfterInit(() => {
if (!this.watcher) {
return;
}
this.watcher.init(true);
if (twoWays) {
this.setupTwoWayBinding();
}
});
} else {
this.watcher.init(true);
if (twoWays) {
this.setupTwoWayBinding();
}
}
}
setupTwoWayBinding() {
if (this.target instanceof AtomComponent) {
if (this.element && (this.element !== this.target.element || !this.target.hasProperty(this.name))) {
let events = [];
if (typeof this.twoWays !== "boolean") {
events = this.twoWays;
}
this.twoWaysDisposable = watchProperty(this.element, this.name, events, v => {
this.setInverseValue(v);
});
return;
}
}
const watcher = new AtomWatcher(this.target, [[this.name]], (...values) => {
if (this.isTwoWaySetup) {
this.setInverseValue(values[0]);
}
});
watcher.init(true);
this.isTwoWaySetup = true;
this.twoWaysDisposable = watcher;
}
setInverseValue(value) {
if (!this.twoWays) {
throw new Error("This Binding is not two ways.");
}
if (this.disposed) {
return;
}
if (this.isRunning) {
return;
}
this.isRunning = true;
try {
const first = this.path[0];
const length = first.length;
let v = this.target;
let i = 0;
let name;
for (i = 0; i < length - 1; i++) {
name = first[i].name;
if (name === "this") {
v = this.source || this.target;
} else {
v = v[name];
}
if (!v) {
return;
}
}
name = first[i].name;
v[name] = this.fromTargetToSource ? this.fromTargetToSource.call(this, value) : value;
} finally {
this.isRunning = false;
}
}
dispose() {
var _c;
(_c = this.twoWaysDisposable) === null || _c === void 0 ? void 0 : _c.dispose();
this.twoWaysDisposable = undefined;
this.watcher.dispose();
this.disposed = true;
this.watcher = null;
}
});
}
};
});
//# sourceMappingURL=AtomComponent.js.map