web-atoms-core
Version:
557 lines • 23.4 kB
JavaScript
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
return function (target, key) { decorator(target, key, paramIndex); }
};
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
(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", "../App", "../Atom", "../core/AtomBinder", "../core/AtomDisposableList", "../core/AtomWatcher", "../core/BindableProperty", "../di/Inject", "./baseTypes"], factory);
}
})(function (require, exports) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var App_1 = require("../App");
var Atom_1 = require("../Atom");
var AtomBinder_1 = require("../core/AtomBinder");
var AtomDisposableList_1 = require("../core/AtomDisposableList");
var AtomWatcher_1 = require("../core/AtomWatcher");
var BindableProperty_1 = require("../core/BindableProperty");
var Inject_1 = require("../di/Inject");
var baseTypes_1 = require("./baseTypes");
function runDecoratorInits() {
var v = this.constructor.prototype;
if (!v) {
return;
}
var ris = v._$_inits;
if (ris) {
for (var _i = 0, ris_1 = ris; _i < ris_1.length; _i++) {
var ri = ris_1[_i];
ri.call(this, this);
}
}
}
function privateInit() {
return __awaiter(this, void 0, void 0, function () {
var _i, _a, i, pi, _b, pi_1, iterator;
var _this = this;
return __generator(this, function (_c) {
switch (_c.label) {
case 0:
_c.trys.push([0, , 3, 4]);
return [4 /*yield*/, Atom_1.Atom.postAsync(this.app, function () { return __awaiter(_this, void 0, void 0, function () {
return __generator(this, function (_a) {
runDecoratorInits.apply(this);
return [2 /*return*/];
});
}); })];
case 1:
_c.sent();
return [4 /*yield*/, Atom_1.Atom.postAsync(this.app, function () { return __awaiter(_this, void 0, void 0, function () {
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.init()];
case 1:
_a.sent();
this.onReady();
return [2 /*return*/];
}
});
}); })];
case 2:
_c.sent();
if (this.postInit) {
for (_i = 0, _a = this.postInit; _i < _a.length; _i++) {
i = _a[_i];
i();
}
this.postInit = null;
}
return [3 /*break*/, 4];
case 3:
pi = this.pendingInits;
this.pendingInits = null;
for (_b = 0, pi_1 = pi; _b < pi_1.length; _b++) {
iterator = pi_1[_b];
iterator();
}
return [7 /*endfinally*/];
case 4: return [2 /*return*/];
}
});
});
}
/**
* Useful only for Unit testing, this function will await till initialization is
* complete and all pending functions are executed
*/
function waitForReady(vm) {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
if (!vm.pendingInits) return [3 /*break*/, 2];
return [4 /*yield*/, Atom_1.Atom.delay(100)];
case 1:
_a.sent();
return [3 /*break*/, 0];
case 2: return [2 /*return*/];
}
});
});
}
exports.waitForReady = waitForReady;
/**
* ViewModel class supports initialization and supports {@link IDisposable} dispose pattern.
* @export
* @class AtomViewModel
*/
var AtomViewModel = /** @class */ (function () {
function AtomViewModel(app) {
var _this = this;
this.app = app;
this.disposables = null;
this.validations = [];
this.pendingInits = [];
this.mShouldValidate = false;
this.app.runAsync(function () { return privateInit.apply(_this); });
}
Object.defineProperty(AtomViewModel.prototype, "isReady", {
/**
* If it returns true, it means all pending initializations have finished
*/
get: function () {
return this.pendingInits === null;
},
enumerable: true,
configurable: true
});
Object.defineProperty(AtomViewModel.prototype, "errors", {
get: function () {
var e = [];
if (!this.mShouldValidate) {
return e;
}
for (var _i = 0, _a = this.validations; _i < _a.length; _i++) {
var v = _a[_i];
if (!v.initialized) {
return e;
}
var error = this[v.name];
if (error) {
e.push({ name: v.name, error: error });
}
}
return e;
},
enumerable: true,
configurable: true
});
Object.defineProperty(AtomViewModel.prototype, "parent", {
/**
* Returns parent AtomViewModel if it was initialized with one. This property is also
* useful when you open an popup or window. Whenever a popup/window is opened, ViewModel
* associated with the UI element that opened this popup/window becomes parent of ViewModel
* of popup/window.
*/
get: function () {
return this.mParent;
},
set: function (v) {
var _this = this;
if (this.mParent && this.mParent.mChildren) {
this.mParent.mChildren.remove(this);
}
this.mParent = v;
if (v) {
var c_1 = v.mChildren || (v.mChildren = []);
c_1.add(this);
this.registerDisposable({
dispose: function () {
c_1.remove(_this);
}
});
}
},
enumerable: true,
configurable: true
});
Object.defineProperty(AtomViewModel.prototype, "isValid", {
/**
* Returns true if all validations didn't return any error. All validations
* are decorated with @{@link Validate} decorator.
*/
get: function () {
var valid = true;
var validateWasFalse = this.mShouldValidate === false;
this.mShouldValidate = true;
for (var _i = 0, _a = this.validations; _i < _a.length; _i++) {
var v = _a[_i];
if (!v.initialized) {
v.watcher.init(true);
v.initialized = true;
}
if (this[v.name]) {
if (validateWasFalse) {
AtomBinder_1.AtomBinder.refreshValue(this, v.name);
}
valid = false;
}
}
if (this.mChildren) {
for (var _b = 0, _c = this.mChildren; _b < _c.length; _b++) {
var child = _c[_b];
if (!child.isValid) {
valid = false;
}
}
}
AtomBinder_1.AtomBinder.refreshValue(this, "errors");
return valid;
},
enumerable: true,
configurable: true
});
/**
* Resets validations and all errors are removed.
* @param resetChildren reset child view models as well. Default is true.
*/
AtomViewModel.prototype.resetValidations = function (resetChildren) {
if (resetChildren === void 0) { resetChildren = true; }
this.mShouldValidate = false;
for (var _i = 0, _a = this.validations; _i < _a.length; _i++) {
var v = _a[_i];
this.refresh(v.name);
}
if (resetChildren && this.mChildren) {
for (var _b = 0, _c = this.mChildren; _b < _c.length; _b++) {
var iterator = _c[_b];
iterator.resetValidations(resetChildren);
}
}
};
/**
* Runs function after initialization is complete.
* @param f function to execute
*/
AtomViewModel.prototype.runAfterInit = function (f) {
if (this.pendingInits) {
this.pendingInits.push(f);
return;
}
f();
};
// /**
// * Binds source property to target property with optional two ways
// * @param target target whose property will be set
// * @param propertyName name of target property
// * @param source source to read property from
// * @param path property path of source
// * @param twoWays optional, two ways {@link IValueConverter}
// */
// public bind(
// target: any,
// propertyName: string,
// source: any,
// path: string[][],
// twoWays?: IValueConverter | ((v: any) => any) ): IDisposable {
// const pb = new PropertyBinding(
// target,
// null,
// propertyName,
// path,
// (twoWays && typeof twoWays !== "function") ? true : false , twoWays, source);
// return this.registerDisposable(pb);
// }
/**
* Refreshes bindings associated with given property name
* @param name name of property
*/
AtomViewModel.prototype.refresh = function (name) {
AtomBinder_1.AtomBinder.refreshValue(this, name);
};
/**
* Put your asynchronous initialization here
*
* @returns {Promise<any>}
* @memberof AtomViewModel
*/
// tslint:disable-next-line:no-empty
AtomViewModel.prototype.init = function () {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
return [2 /*return*/];
});
});
};
/**
* dispose method will be called when attached view will be disposed or
* when a new view model will be assigned to view, old view model will be disposed.
*
* @memberof AtomViewModel
*/
AtomViewModel.prototype.dispose = function () {
if (this.disposables) {
this.disposables.dispose();
}
};
// /**
// * Internal method, do not use, instead use errors.hasErrors()
// *
// * @memberof AtomViewModel
// */
// public runValidation(): void {
// for (const v of this.validations) {
// v.watcher.evaluate(true);
// }
// }
/**
* Register a disposable to be disposed when view model will be disposed.
*
* @protected
* @param {IDisposable} d
* @memberof AtomViewModel
*/
AtomViewModel.prototype.registerDisposable = function (d) {
this.disposables = this.disposables || new AtomDisposableList_1.AtomDisposableList();
return this.disposables.add(d);
};
// tslint:disable-next-line:no-empty
AtomViewModel.prototype.onReady = function () { };
/**
* Execute given expression whenever any bindable expression changes
* in the expression.
*
* For correct generic type resolution, target must always be `this`.
*
* this.setupWatch(() => {
* if(!this.data.fullName){
* this.data.fullName = `${this.data.firstName} ${this.data.lastName}`;
* }
* });
*
* @protected
* @template T
* @param {() => any} ft
* @returns {IDisposable}
* @memberof AtomViewModel
*/
AtomViewModel.prototype.setupWatch = function (ft, proxy, forValidation, name) {
var d = new AtomWatcher_1.AtomWatcher(this, ft, proxy, this);
if (forValidation) {
this.validations = this.validations || [];
this.validations.push({ name: name, watcher: d, initialized: false });
}
else {
d.init();
}
return this.registerDisposable(d);
};
// tslint:disable-next-line:no-empty
AtomViewModel.prototype.onPropertyChanged = function (name) { };
AtomViewModel = __decorate([
__param(0, Inject_1.Inject),
__metadata("design:paramtypes", [App_1.App])
], AtomViewModel);
return AtomViewModel;
}());
exports.AtomViewModel = AtomViewModel;
/**
* Receive messages for given channel
* @param {(string | RegExp)} channel
* @returns {Function}
*/
function Receive() {
var channel = [];
for (var _i = 0; _i < arguments.length; _i++) {
channel[_i] = arguments[_i];
}
return function (target, key) {
baseTypes_1.registerInit(target, function (vm) {
// tslint:disable-next-line:ban-types
var fx = vm[key];
var a = function (ch, d) {
var p = fx.call(vm, ch, d);
if (p && p.then && p.catch) {
p.catch(function (e) {
// tslint:disable-next-line: no-console
console.warn(e);
});
}
};
var ivm = vm;
for (var _i = 0, channel_1 = channel; _i < channel_1.length; _i++) {
var c = channel_1[_i];
ivm.registerDisposable(ivm.app.subscribe(c, a));
}
});
};
}
exports.Receive = Receive;
function BindableReceive() {
var channel = [];
for (var _i = 0; _i < arguments.length; _i++) {
channel[_i] = arguments[_i];
}
return function (target, key) {
var bp = BindableProperty_1.BindableProperty(target, key);
baseTypes_1.registerInit(target, function (vm) {
var fx = function (cx, m) {
vm[key] = m;
};
var ivm = vm;
for (var _i = 0, channel_2 = channel; _i < channel_2.length; _i++) {
var c = channel_2[_i];
ivm.registerDisposable(ivm.app.subscribe(c, fx));
}
});
return bp;
};
}
exports.BindableReceive = BindableReceive;
function BindableBroadcast() {
var channel = [];
for (var _i = 0; _i < arguments.length; _i++) {
channel[_i] = arguments[_i];
}
return function (target, key) {
var bp = BindableProperty_1.BindableProperty(target, key);
baseTypes_1.registerInit(target, function (vm) {
var fx = function (t) {
var v = vm[key];
for (var _i = 0, channel_3 = channel; _i < channel_3.length; _i++) {
var c = channel_3[_i];
vm.app.broadcast(c, v);
}
};
var d = new AtomWatcher_1.AtomWatcher(vm, [key.split(".")], fx);
d.init();
vm.registerDisposable(d);
});
return bp;
};
}
exports.BindableBroadcast = BindableBroadcast;
function Watch(target, key, descriptor) {
baseTypes_1.registerInit(target, function (vm) {
var ivm = vm;
if (descriptor && descriptor.get) {
ivm.setupWatch(descriptor.get, function () {
vm.refresh(key.toString());
});
return;
}
ivm.setupWatch(vm[key]);
});
}
exports.Watch = Watch;
/**
* Cached watch must be used with async getters to avoid reloading of
* resources unless the properties referenced are changed
* @param target ViewModel
* @param key name of property
* @param descriptor descriptor of property
*/
function CachedWatch(target, key, descriptor) {
var getMethod = descriptor.get;
descriptor.get = (function () { return null; });
baseTypes_1.registerInit(target, function (vm) {
var ivm = vm;
var fieldName = "_" + key;
Object.defineProperty(ivm, key, {
enumerable: true,
configurable: true,
get: function () {
var c = ivm[fieldName] || (ivm[fieldName] = {
value: getMethod.apply(ivm)
});
return c.value;
}
});
ivm.setupWatch(getMethod, function () {
ivm[fieldName] = null;
AtomBinder_1.AtomBinder.refreshValue(ivm, key);
});
});
}
exports.CachedWatch = CachedWatch;
function Validate(target, key, descriptor) {
// tslint:disable-next-line:ban-types
var getMethod = descriptor.get;
// // trick is to change property descriptor...
// delete target[key];
descriptor.get = function () { return null; };
// // replace it with dummy descriptor...
// Object.defineProperty(target, key, descriptor);
baseTypes_1.registerInit(target, function (vm) {
var initialized = { i: false };
var ivm = vm;
Object.defineProperty(ivm, key, {
enumerable: true,
configurable: true,
get: function () {
if (vm.mShouldValidate && initialized.i) {
return getMethod.apply(this);
}
return null;
}
});
ivm.setupWatch(getMethod, function () {
// descriptor.get = getMethod;
// Object.defineProperty(target, key, descriptor);
initialized.i = true;
vm.refresh(key.toString());
}, true, key.toString());
return;
});
}
exports.Validate = Validate;
});
//# sourceMappingURL=AtomViewModel.js.map