UNPKG

web-atoms-core

Version:
218 lines • 8.42 kB
(function (factory) { if (typeof module === "object" && typeof module.exports === "object") { var v = factory(require, exports); if (v !== undefined) module.exports = v; } else if (typeof define === "function" && define.amd) { define(["require", "exports", "./AtomBinder", "./ExpressionParser"], factory); } })(function (require, exports) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var AtomBinder_1 = require("./AtomBinder"); var ExpressionParser_1 = require("./ExpressionParser"); var ObjectProperty = /** @class */ (function () { function ObjectProperty(name) { this.name = name; } ObjectProperty.prototype.toString = function () { return this.name; }; return ObjectProperty; }()); exports.ObjectProperty = ObjectProperty; /** * * * @export * @class AtomWatcher * @implements {IDisposable} * @template T */ var AtomWatcher = /** @class */ (function () { /** * Creates an instance of AtomWatcher. * * let w = new AtomWatcher(this, x => x.data.fullName = `${x.data.firstName} ${x.data.lastName}`); * * You must dispose `w` in order to avoid memory leaks. * Above method will set fullName whenever, data or its firstName,lastName property is modified. * * AtomWatcher will assign null if any expression results in null in single property path. * * In order to avoid null, you can rewrite above expression as, * * let w = new AtomWatcher(this, * x => { * if(x.data.firstName && x.data.lastName){ * x.data.fullName = `${x.data.firstName} ${x.data.lastName}` * } * }); * * @param {T} target - Target on which watch will be set to observe given set of properties * @param {(PathList[] | ((x:T) => any))} path - Path is either lambda expression or array of * property path to watch, if path was lambda, it will be executed when any of * members will modify * @param {Function} onChanged - This function will be executed when any member in path is updated * @memberof AtomWatcher */ function AtomWatcher(target, path, onChanged, source) { var _this = this; this.source = source; this.isExecuting = false; this.target = target; this.forValidation = true; if (path instanceof Function) { var f = path; path = ExpressionParser_1.parsePath(path); this.func = onChanged || f; this.funcText = f.toString(); } else { this.func = onChanged; } this.runEvaluate = function () { _this.evaluate(); }; this.runEvaluate.watcher = this; this.path = path.map(function (x) { return x.map(function (y) { return new ObjectProperty(y); }); }); if (!this.path.length) { // tslint:disable-next-line:no-debugger debugger; // tslint:disable-next-line:no-console console.warn("There is nothing to watch, do not use one way binding without any binding expression"); } } AtomWatcher.prototype.toString = function () { return this.func.toString(); }; /** * This will dispose and unregister all watchers * * @memberof AtomWatcher */ AtomWatcher.prototype.dispose = function () { if (!this.path) { return; } for (var _i = 0, _a = this.path; _i < _a.length; _i++) { var p = _a[_i]; for (var _b = 0, p_1 = p; _b < p_1.length; _b++) { var op = p_1[_b]; if (op.watcher) { op.watcher.dispose(); op.watcher = null; op.target = null; } } } // tslint:disable-next-line:no-string-literal // this["disposedPath"] = this.path; this.func = null; // this.path.length = 0; this.path = null; this.source = null; }; /** * Initialize the path targets * @param evaluate if true, evaluate entire watch expression and run onChange method */ AtomWatcher.prototype.init = function (evaluate) { if (evaluate) { this.evaluate(true); } else { for (var _i = 0, _a = this.path; _i < _a.length; _i++) { var iterator = _a[_i]; this.evaluatePath(this.target, iterator); } } }; AtomWatcher.prototype.evaluatePath = function (target, path) { // console.log(`\tevaluatePath: ${path.map(op=>op.name).join(", ")}`); var newTarget = null; for (var _i = 0, path_1 = path; _i < path_1.length; _i++) { var p = path_1[_i]; if (this.source && p.name === "this") { target = this.source; continue; } newTarget = target[p.name]; if (!p.target) { if (p.watcher) { p.watcher.dispose(); } p.watcher = AtomBinder_1.AtomBinder.watch(target, p.name, this.runEvaluate); } else if (p.target !== target) { if (p.watcher) { p.watcher.dispose(); } p.watcher = AtomBinder_1.AtomBinder.watch(target, p.name, this.runEvaluate); } p.target = target; target = newTarget; if (newTarget === undefined || newTarget === null) { break; } } return newTarget; }; /** * * * @param {boolean} [force] * @returns {*} * @memberof AtomWatcher */ AtomWatcher.prototype.evaluate = function (force) { if (!this.path) { // this watcher may have been disposed... // tslint:disable-next-line:no-console console.warn("Watcher is not disposed properly, please watch for any memory leak"); return; } if (this.isExecuting) { return; } var disposeWatchers = []; this.isExecuting = true; try { var values = []; var logs = []; for (var _i = 0, _a = this.path; _i < _a.length; _i++) { var p = _a[_i]; values.push(this.evaluatePath(this.target, p)); } // if (force === true) { // this.forValidation = false; // } // if (this.forValidation) { // const x: boolean = true; // if (values.find( (x1) => x1 ? true : false)) { // this.forValidation = false; // } else { // return; // } // } try { this.func.apply(this.target, values); } catch (e) { // tslint:disable-next-line:no-console console.warn(e); } } finally { this.isExecuting = false; for (var _b = 0, disposeWatchers_1 = disposeWatchers; _b < disposeWatchers_1.length; _b++) { var d = disposeWatchers_1[_b]; d.dispose(); } } }; return AtomWatcher; }()); exports.AtomWatcher = AtomWatcher; }); //# sourceMappingURL=AtomWatcher.js.map