web-atoms-mvvm
Version:
MVVM, REST Json Service, Message Subscriptions for Web Atoms
1,375 lines • 117 kB
JavaScript
/**
* Easy and Simple Dependency Injection
*/
var WebAtoms;
(function (WebAtoms) {
var DIFactory = /** @class */ (function () {
function DIFactory(key, factory, transient) {
this.transient = transient;
this.factory = factory;
this.key = key;
}
DIFactory.prototype.resolve = function () {
if (this.transient) {
return this.factory();
}
return this.instance || (this.instance = this.factory());
};
DIFactory.prototype.push = function (factory, transient) {
this.stack = this.stack || [];
this.stack.push({
factory: this.factory,
instance: this.instance,
transient: this.transient
});
this.transient = transient;
this.instance = undefined;
this.factory = factory;
};
DIFactory.prototype.pop = function () {
if (!(this.stack && this.stack.length)) {
throw new Error("Stack in DIFactory is empty");
}
var obj = this.stack.pop();
this.factory = obj.factory;
this.transient = obj.transient;
this.instance = obj.instance;
};
return DIFactory;
}());
/**
* @export
* @class DI
*/
var DI = /** @class */ (function () {
function DI() {
}
/**
* @static
* @template T
* @param {new () => T} key
* @param {() => T} factory
* @param {boolean} [transient=false] - If true, always new instance will be created
* @memberof DI
*/
DI.register = function (key, factory, transient) {
if (transient === void 0) { transient = false; }
var k = key;
var existing = DI.factory[k];
if (existing) {
throw new Error("Factory for " + key.name + " is already registered");
}
DI.factory[k] = new DIFactory(key, factory, transient);
};
/**
* @static
* @template T
* @param {new () => T} c
* @returns {T}
* @memberof DI
*/
DI.resolve = function (c) {
var f = DI.factory[c];
if (!f) {
throw new Error("No factory registered for " + c);
}
return f.resolve();
};
/**
* Use this for unit testing, this will push existing
* DI factory and all instances will be resolved with
* given instance
*
* @static
* @param {*} key
* @param {*} instance
* @memberof DI
*/
DI.push = function (key, instance) {
var f = DI.factory[key];
if (!f) {
DI.register(key, function () { return instance; });
}
else {
f.push(function () { return instance; }, true);
}
};
/**
* @static
* @param {*} key
* @memberof DI
*/
DI.pop = function (key) {
var f = DI.factory[key];
if (f) {
f.pop();
}
};
DI.factory = {};
return DI;
}());
WebAtoms.DI = DI;
/**
* This decorator will register given class as singleton instance on DI.
* @example
* @DIGlobal
* class BackendService{
* }
* @export
* @param {new () => any} c
* @returns
*/
function DIGlobal(c) {
DI.register(c, function () { return new c(); });
return c;
}
WebAtoms.DIGlobal = DIGlobal;
/**
* This decorator will register given class as transient instance on DI.
* @example
* @DIAlwaysNew
* class StringHelper{
* }
* @export
* @param {new () => any} c
* @returns
*/
function DIAlwaysNew(c) {
DI.register(c, function () { return new c(); }, true);
return c;
}
WebAtoms.DIAlwaysNew = DIAlwaysNew;
})(WebAtoms || (WebAtoms = {}));
var DIGlobal = WebAtoms.DIGlobal;
var DIAlwaysNew = WebAtoms.DIAlwaysNew;
// tslint:disable
function classCreator__(name, basePrototype, classConstructor, classPrototype, classProperties, thisPrototype, thisProperties) {
var baseClass = basePrototype ? basePrototype.constructor : null;
var old = classConstructor || (function () { });
var cp = classProperties;
var f = null;
if (baseClass) {
if (classProperties) {
f = function () {
this.constructor = classPrototype;
for (var k in cp) {
this["_" + k] = cp[k];
}
baseClass.apply(this, arguments);
this.__typeName = name;
//var cp = Atom.clone(classProperties);
old.apply(this, arguments);
};
}
else {
f = function () {
this.constructor = classPrototype;
baseClass.apply(this, arguments);
this.__typeName = name;
old.apply(this, arguments);
};
}
var bpt = baseClass.prototype;
// extend
for (var k in bpt) {
if (classPrototype[k])
continue;
if (bpt.hasOwnProperty(k)) {
var pd = Object.getOwnPropertyDescriptor(bpt, k);
if (!pd) {
classPrototype[k] = bpt[k];
}
else {
Object.defineProperty(classPrototype, k, pd);
}
}
}
}
else {
if (classProperties) {
f = function () {
this.__typeName = name;
//var cp = Atom.clone(classProperties);
for (var k in cp) {
this["_" + k] = cp[k];
}
old.apply(this, arguments);
};
}
else {
f = function () {
this.__typeName = name;
old.apply(this, arguments);
};
}
}
if (classProperties) {
for (var k in classProperties) {
if (!classPrototype["get_" + k]) {
classPrototype["get_" + k] = createProperty("_" + k, true);
}
if (!classPrototype["set_" + k]) {
classPrototype["set_" + k] = createProperty("_" + k);
}
}
}
for (var k in classPrototype) {
if (/^get\_/.test(k)) {
var gx = classPrototype[k];
var nx = k.substr(4);
var sx = classPrototype["set_" + nx];
Object.defineProperty(classPrototype, nx, {
get: gx,
set: sx ? createProperty("_" + nx, false, nx) : undefined,
enumerable: true,
configurable: true
});
}
}
f.__typeName = name;
if (baseClass) {
f.__baseType = baseClass;
// var fx = f;
// function __() {
// var args = [];
// for (var _i = 0; _i < arguments.length; _i++) {
// args[_i] = arguments[_i];
// }
// fx.call(this, args);
// this.constructor = classPrototype;
// }
// __.prototype = basePrototype;
// f = new __();
f.prototype = basePrototype;
f = new f();
}
else {
f.prototype = classPrototype;
f.prototype.constructor = f;
}
//f.constructor = classPrototype;
if (!classPrototype.hasOwnProperty("toString")) {
f.prototype.toString = function () {
return name;
};
}
mapLibrary(/\./.test(name) ? name : 'WebAtoms.' + name, window, f);
return f;
}
;
/// <reference path="__di.ts" />
var __extends = (this && this.__extends) || (function () {
var extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
if (location) {
Atom.designMode = /file/i.test(location.protocol);
}
/**
* This decorator will mark given property as bindable, it will define
* getter and setter, and in the setter, it will refresh the property.
*
* class Customer{
*
* @bindableProperty
* firstName:string;
*
* }
*
* @param {*} target
* @param {string} key
*/
function bindableProperty(target, key) {
// property value
var _val = this[key];
var keyName = "_" + key;
this[keyName] = _val;
// property getter
var getter = function () {
// console.log(`Get: ${key} => ${_val}`);
return this[keyName];
};
// property setter
var setter = function (newVal) {
// console.log(`Set: ${key} => ${newVal}`);
// debugger;
var oldValue = this[keyName];
// tslint:disable-next-line:triple-equals
if (oldValue == newVal) {
return;
}
this[keyName] = newVal;
// only if this is not an AtomControl...
if (!(this._element && this._element.atomControl === this)) {
var c = this._$_supressRefresh;
if (!(c && c[key])) {
Atom.refresh(this, key);
}
}
if (this.onPropertyChanged) {
this.onPropertyChanged(key);
}
};
// delete property
if (delete this[key]) {
// create new property with getter and setter
Object.defineProperty(target, key, {
get: getter,
set: setter,
enumerable: true,
configurable: true
});
// tslint:disable-next-line:no-string-literal
if (target.constructor.prototype["get_atomParent"]) {
target["get_" + key] = getter;
target["set_" + key] = setter;
}
}
}
Atom.bindable = function (e) {
if (!e) {
return e;
}
if (e instanceof Array) {
throw new TypeError("Invalid object, try to use AtomList instead of Atom.bindable");
}
if (typeof e === "string" || e.constructor === String) {
return e;
}
if (typeof e === "number" || e.constructor === Number) {
return e;
}
if (e.constructor === Date) {
return e;
}
var self = e;
if (e._$_isBindable) {
return e;
}
var keys = Object.keys(e);
e._$_isBindable = true;
for (var _i = 0, keys_1 = keys; _i < keys_1.length; _i++) {
var key = keys_1[_i];
var k = key;
var v = e[key];
var vk = "_" + key;
e[vk] = v;
delete e[key];
Object.defineProperty(e, key, {
get: function () { return this[vk]; },
set: function (v) {
this[vk] = v;
Atom.refresh(this, k);
},
enumerable: true
});
}
return e;
};
Atom.controlToElement = function (type, tagName) {
if (tagName === void 0) { tagName = "div"; }
if (!type) {
return undefined;
}
var name = "";
if (!(typeof type === "string")) {
// tslint:disable-next-line:no-string-literal
name = type["__typeName"];
}
else {
name = type;
}
var div = document.createElement("div");
div.setAttribute("atom-type", name);
return div;
};
var WebAtoms;
(function (WebAtoms) {
/**
*
*
* @export
* @class CancelToken
*/
var CancelToken = /** @class */ (function () {
function CancelToken() {
this.listeners = [];
}
Object.defineProperty(CancelToken.prototype, "cancelled", {
get: function () {
return this._cancelled;
},
enumerable: true,
configurable: true
});
CancelToken.prototype.cancel = function () {
this._cancelled = true;
for (var _i = 0, _a = this.listeners; _i < _a.length; _i++) {
var fx = _a[_i];
fx();
}
};
CancelToken.prototype.reset = function () {
this._cancelled = false;
this.listeners.length = 0;
};
CancelToken.prototype.registerForCancel = function (f) {
if (this._cancelled) {
f();
this.cancel();
return;
}
this.listeners.push(f);
};
return CancelToken;
}());
WebAtoms.CancelToken = CancelToken;
var AtomModel = /** @class */ (function () {
function AtomModel() {
}
AtomModel.prototype.refresh = function (name) {
Atom.refresh(this, name);
};
return AtomModel;
}());
WebAtoms.AtomModel = AtomModel;
/**
* Though you can directly call methods of view model in binding expression,
* but we recommend using AtomCommand for two reasons.
*
* First one, it has enabled bindable property, which can be used to enable/disable UI.
* AtomButton already has `command` and `commandParameter` property which automatically
* binds execution and disabling the UI.
*
* Second one, it has busy bindable property, which can be used to display a busy indicator
* when corresponding action is a promise and it is yet not resolved.
*
* @export
* @class AtomCommand
* @extends {AtomModel}
* @template T
*/
var AtomCommand = /** @class */ (function (_super) {
__extends(AtomCommand, _super);
function AtomCommand(action) {
var _this = _super.call(this) || this;
_this.isMVVMAtomCommand = true;
_this._enabled = true;
_this._busy = false;
_this.action = action;
_this.execute = function (p) {
if (_this.enabled) {
_this.executeAction(p);
}
};
return _this;
}
Object.defineProperty(AtomCommand.prototype, "enabled", {
/**
*
*
* @type {boolean}
* @memberof AtomCommand
*/
get: function () {
return this._enabled;
},
set: function (v) {
this._enabled = v;
this.refresh("enabled");
},
enumerable: true,
configurable: true
});
Object.defineProperty(AtomCommand.prototype, "busy", {
/**
*
*
* @type {boolean}
* @memberof AtomCommand
*/
get: function () {
return this._busy;
},
set: function (v) {
this._busy = v;
this.refresh("busy");
},
enumerable: true,
configurable: true
});
AtomCommand.prototype.executeAction = function (p) {
var _this = this;
if (this._busy) {
return;
}
this.busy = true;
var result = this.action(p);
if (result) {
if (result.catch) {
result.catch(function (error) {
_this.busy = false;
if (error !== "cancelled") {
console.error(error);
Atom.showError(error);
}
});
return;
}
if (result.then) {
result.then(function () {
_this.busy = false;
});
return;
}
}
this.busy = false;
};
return AtomCommand;
}(AtomModel));
WebAtoms.AtomCommand = AtomCommand;
})(WebAtoms || (WebAtoms = {}));
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
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) : new P(function (resolve) { resolve(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 = y[op[0] & 2 ? "return" : op[0] ? "throw" : "next"]) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [0, 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 };
}
};
var WebAtoms;
(function (WebAtoms) {
/**
* DisposableAction holds an action that
* will be executed when dispose will be called.
*
* subscribe(m,f):AtomDisposable{
* //...
* //subscribe to something...
* //...
* return new AtomDisposable(()=>{
*
* //...
* //unsubscribe from something
* //
*
* });
* }
*
* User can simply call dispose to make sure subscription was unsubscribed.
*
* @export
* @class DisposableAction
* @implements {AtomDisposable}
*/
var DisposableAction = /** @class */ (function () {
function DisposableAction(f) {
this.f = f;
}
DisposableAction.prototype.dispose = function () {
this.f();
};
return DisposableAction;
}());
WebAtoms.DisposableAction = DisposableAction;
// tslint:disable-next-line
var AtomUI = window["AtomUI"];
// tslint:disable-next-line
var oldCreateControl = AtomUI.createControl;
// tslint:disable-next-line
AtomUI.createControl = function (element, type, data, newScope) {
if (type) {
if (type.constructor === String || (typeof type) === "string") {
var t = WebAtoms[type] || Atom.get(window, type);
if (t) {
type = t;
}
}
}
return oldCreateControl.call(Atom, element, type, data, newScope);
};
Atom.post = function (f) {
WebAtoms.dispatcher.callLater(f);
};
Atom.postAsync = function (f) {
var _this = this;
return new Promise(function (resolve, reject) {
WebAtoms.dispatcher.callLater(function () { return __awaiter(_this, void 0, void 0, function () {
var p, e_1;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
_a.trys.push([0, 3, , 4]);
p = f();
if (!(p && p.then && p.catch)) return [3 /*break*/, 2];
return [4 /*yield*/, p];
case 1:
_a.sent();
_a.label = 2;
case 2:
resolve();
return [3 /*break*/, 4];
case 3:
e_1 = _a.sent();
reject(e_1);
return [3 /*break*/, 4];
case 4: return [2 /*return*/];
}
});
}); });
});
};
Atom.using = function (d, f) {
try {
f();
}
finally {
d.dispose();
}
};
Atom.usingAsync = function (d, f) {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
_a.trys.push([0, , 2, 3]);
return [4 /*yield*/, f()];
case 1:
_a.sent();
return [3 /*break*/, 3];
case 2:
d.dispose();
return [7 /*endfinally*/];
case 3: return [2 /*return*/];
}
});
});
};
Atom.watch = function (item, property, f) {
AtomBinder.add_WatchHandler(item, property, f);
return new DisposableAction(function () {
AtomBinder.remove_WatchHandler(item, property, f);
});
};
Atom.delay = function (n, ct) {
return new Promise(function (resolve, reject) {
var t = setTimeout(function () {
resolve();
}, (n));
if (ct) {
ct.registerForCancel(function () {
clearTimeout(t);
reject("cancelled");
});
}
});
};
var AtomHandler = /** @class */ (function () {
function AtomHandler(message) {
this.message = message;
this.list = new Array();
}
return AtomHandler;
}());
var AtomMessageAction = /** @class */ (function () {
function AtomMessageAction(msg, a) {
this.message = msg;
this.action = a;
}
return AtomMessageAction;
}());
WebAtoms.AtomMessageAction = AtomMessageAction;
/**
* Device (usually browser), instance of which supports
* singleton instance to provide broadcast/messaging
*
* @export
* @class AtomDevice
*/
var AtomDevice = /** @class */ (function () {
function AtomDevice() {
this.bag = {};
}
/**
* This method will run any asynchronous method
* and it will display an error if it will fail
* asynchronously
*
* @template T
* @param {() => Promise<T>} tf
* @memberof AtomDevice
*/
AtomDevice.prototype.runAsync = function (tf) {
var task = tf();
task.catch(function (error) {
console.error(error);
Atom.showError(error);
});
// tslint:disable-next-line
task.then(function () { });
};
/**
* Broadcast given data to channel, only within the current window.
*
* @param {string} channel
* @param {*} data
* @returns
* @memberof AtomDevice
*/
AtomDevice.prototype.broadcast = function (channel, data) {
var ary = this.bag[channel];
if (!ary) {
return;
}
for (var _i = 0, _a = ary.list; _i < _a.length; _i++) {
var entry = _a[_i];
entry.call(this, channel, data);
}
};
/**
* Subscribe for given channel with action that will be
* executed when anyone will broadcast (this only works within the
* current browser window)
*
* This method returns a disposable, when you call `.dispose()` it will
* unsubscribe for current subscription
*
* @param {string} channel
* @param {AtomAction} action
* @returns {AtomDisposable} Disposable that supports removal of subscription
* @memberof AtomDevice
*/
AtomDevice.prototype.subscribe = function (channel, action) {
var _this = this;
var ary = this.bag[channel];
if (!ary) {
ary = new AtomHandler(channel);
this.bag[channel] = ary;
}
ary.list.push(action);
return new DisposableAction(function () {
ary.list = ary.list.filter(function (a) { return a !== action; });
if (!ary.list.length) {
_this.bag[channel] = null;
}
});
};
/**
*
*
* @static
* @type {AtomDevice}
* @memberof AtomDevice
*/
AtomDevice.instance = new AtomDevice();
return AtomDevice;
}());
WebAtoms.AtomDevice = AtomDevice;
})(WebAtoms || (WebAtoms = {}));
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 WebAtoms;
(function (WebAtoms) {
var AtomPageView = /** @class */ (function (_super) {
__extends(AtomPageView, _super);
function AtomPageView(e) {
var _this = _super.call(this, e) || this;
_this.disposables = [];
_this.stack = [];
_this.keepStack = true;
_this.current = null;
_this.currentDisposable = null;
e.style.position = "relative";
_this.backCommand = function () {
_this.onBackCommand();
};
return _this;
}
AtomPageView.prototype.onBackCommand = function () {
if (!this.stack.length) {
console.warn("FrameStack is empty !!");
return;
}
var ctrl = this.current;
var e = ctrl._element;
ctrl.dispose();
e.remove();
this.current = this.stack.pop();
this.current._element.style.display = "";
};
AtomPageView.prototype.canChange = function () {
return __awaiter(this, void 0, void 0, function () {
var ctrl, vm;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
if (!this.current) {
return [2 /*return*/, true];
}
ctrl = this.current;
vm = ctrl.viewModel;
if (!vm.closeWarning) return [3 /*break*/, 2];
return [4 /*yield*/, WebAtoms.WindowService.instance.confirm(vm.closeWarning, "Are you sure?")];
case 1:
if (_a.sent()) {
return [2 /*return*/, true];
}
return [2 /*return*/, false];
case 2: return [2 /*return*/, true];
}
});
});
};
AtomPageView.prototype.push = function (ctrl) {
if (this.current) {
if (this.keepStack) {
this.current._element.style.display = "none";
this.stack.push(this.current);
}
else {
var c1 = this.current;
var e = c1._element;
c1.dispose();
e.remove();
}
}
var element = ctrl._element;
element.style.position = "absolute";
element.style.top =
element.style.bottom =
element.style.left =
element.style.right = "0";
this._element.appendChild(element);
this.current = ctrl;
};
AtomPageView.prototype.init = function () {
var _this = this;
_super.prototype.init.call(this);
this.disposables.push(Atom.watch(this, "url", function () {
_this.load(_this.url);
}));
};
AtomPageView.prototype.dispose = function (e) {
_super.prototype.dispose.call(this, e);
if (!e) {
for (var _i = 0, _a = this.disposables; _i < _a.length; _i++) {
var d = _a[_i];
d.dispose();
}
this.disposables = [];
}
};
AtomPageView.prototype.createControl = function (c, vmt, q) {
var div = document.createElement("div");
div.id = this._element.id + "_" + (this.stack.length + 1);
var ctrl = AtomUI.createControl(div, c);
div.setAttribute("atom-local-scope", "true");
var vm = null;
if (vmt) {
vm = new (vmt)(q);
ctrl.viewModel = vm;
}
ctrl.init();
return ctrl;
};
AtomPageView.prototype.load = function (url) {
return __awaiter(this, void 0, void 0, function () {
var _this = this;
var uri, fragments, scope, vm, _i, fragments_1, f, q, ctrl;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.canChange()];
case 1:
if (!(_a.sent())) {
return [2 /*return*/];
}
uri = new AtomUri(url);
fragments = uri.path.split(".")
.map(function (f) { return _this.toUpperCase(f); });
scope = window;
vm = null;
for (_i = 0, fragments_1 = fragments; _i < fragments_1.length; _i++) {
f = fragments_1[_i];
vm = scope[f + "ViewModel"];
if (!vm) {
vm = scope[f + "Model"];
}
scope = scope[f];
if (!scope) {
throw new Error("No " + f + " in " + url + " found.");
}
}
q = uri.query;
ctrl = this.createControl(scope, vm, q);
Atom.post(function () {
vm = ctrl.viewModel;
if (vm) {
if (vm instanceof WebAtoms.AtomPageViewModel) {
var pvm = vm;
pvm.pageId = ctrl._element.id;
}
}
});
this.push(ctrl);
return [2 /*return*/];
}
});
});
};
AtomPageView.prototype.toUpperCase = function (s) {
return s.split("-")
.filter(function (t) { return t; })
.map(function (t) { return t.substr(0, 1).toUpperCase() + t.substr(1); })
.join("");
};
__decorate([
bindableProperty
], AtomPageView.prototype, "url", void 0);
__decorate([
bindableProperty
], AtomPageView.prototype, "keepStack", void 0);
__decorate([
bindableProperty
], AtomPageView.prototype, "current", void 0);
return AtomPageView;
}(WebAtoms.AtomControl));
WebAtoms.AtomPageView = AtomPageView;
})(WebAtoms || (WebAtoms = {}));
var WebAtoms;
(function (WebAtoms) {
/**
*
*
* @export
* @class AtomList
* @extends {Array<T>}
* @template T
*/
var AtomList = /** @class */ (function (_super) {
__extends(AtomList, _super);
function AtomList() {
var _this = _super.call(this) || this;
_this._start = 0;
_this._total = 0;
_this._size = 10;
// tslint:disable-next-line
_this["__proto__"] = AtomList.prototype;
_this.next = function () {
_this.start = _this.start + _this.size;
};
_this.prev = function () {
if (_this.start >= _this.size) {
_this.start = _this.start - _this.size;
}
};
return _this;
}
Object.defineProperty(AtomList.prototype, "start", {
get: function () {
return this._start;
},
set: function (v) {
if (v === this._start) {
return;
}
this._start = v;
Atom.refresh(this, "start");
},
enumerable: true,
configurable: true
});
Object.defineProperty(AtomList.prototype, "total", {
get: function () {
return this._total;
},
set: function (v) {
if (v === this._total) {
return;
}
this._total = v;
Atom.refresh(this, "total");
},
enumerable: true,
configurable: true
});
Object.defineProperty(AtomList.prototype, "size", {
get: function () {
return this._size;
},
set: function (v) {
if (v === this._size) {
return;
}
this._size = v;
Atom.refresh(this, "size");
},
enumerable: true,
configurable: true
});
/**
* Adds the item in the list and refresh bindings
* @param {T} item
* @returns {number}
* @memberof AtomList
*/
AtomList.prototype.add = function (item) {
var i = this.length;
var n = this.push(item);
AtomBinder.invokeItemsEvent(this, "add", i, item);
Atom.refresh(this, "length");
return n;
};
/**
* Add given items in the list and refresh bindings
* @param {Array<T>} items
* @memberof AtomList
*/
AtomList.prototype.addAll = function (items) {
for (var _i = 0, items_1 = items; _i < items_1.length; _i++) {
var item = items_1[_i];
var i = this.length;
this.push(item);
AtomBinder.invokeItemsEvent(this, "add", i, item);
Atom.refresh(this, "length");
}
// tslint:disable-next-line:no-string-literal
var t = items["total"];
if (t) {
this.total = t;
}
};
/**
* Replaces list with given items, use this
* to avoid flickering in screen
* @param {T[]} items
* @memberof AtomList
*/
AtomList.prototype.replace = function (items, start, size) {
this.length = items.length;
for (var i = 0; i < items.length; i++) {
this[i] = items[i];
}
this.refresh();
// tslint:disable-next-line:no-string-literal
var t = items["total"];
if (t) {
this.total = t;
}
if (start !== undefined) {
this.start = start;
}
if (size !== undefined) {
this.size = size;
}
};
/**
* Inserts given number in the list at position `i`
* and refreshes the bindings.
* @param {number} i
* @param {T} item
* @memberof AtomList
*/
AtomList.prototype.insert = function (i, item) {
var n = this.splice(i, 0, item);
AtomBinder.invokeItemsEvent(this, "add", i, item);
Atom.refresh(this, "length");
};
/**
* Removes item at given index i and refresh the bindings
* @param {number} i
* @memberof AtomList
*/
AtomList.prototype.removeAt = function (i) {
var item = this[i];
this.splice(i, 1);
AtomBinder.invokeItemsEvent(this, "remove", i, item);
Atom.refresh(this, "length");
};
/**
* Removes given item or removes all items that match
* given lambda as true and refresh the bindings
* @param {(T | ((i:T) => boolean))} item
* @returns {boolean} `true` if any item was removed
* @memberof AtomList
*/
AtomList.prototype.remove = function (item) {
if (item instanceof Function) {
var index = 0;
var removed = false;
for (var _i = 0, _a = this; _i < _a.length; _i++) {
var it = _a[_i];
if (item(it)) {
this.removeAt(index);
removed = true;
}
index++;
}
return removed;
}
var n = this.indexOf(item);
if (n !== -1) {
this.removeAt(n);
return true;
}
return false;
};
/**
* Removes all items from the list and refreshes the bindings
* @memberof AtomList
*/
AtomList.prototype.clear = function () {
this.length = 0;
this.refresh();
};
AtomList.prototype.refresh = function () {
AtomBinder.invokeItemsEvent(this, "refresh", -1, null);
Atom.refresh(this, "length");
};
AtomList.prototype.watch = function (f) {
var _this = this;
AtomBinder.add_CollectionChanged(this, f);
return new WebAtoms.DisposableAction(function () {
AtomBinder.remove_CollectionChanged(_this, f);
});
};
return AtomList;
}(Array));
WebAtoms.AtomList = AtomList;
// tslint:disable
Array.prototype["add"] = AtomList.prototype.add;
Array.prototype["addAll"] = AtomList.prototype.addAll;
Array.prototype["clear"] = AtomList.prototype.clear;
Array.prototype["refresh"] = AtomList.prototype.refresh;
Array.prototype["remove"] = AtomList.prototype.remove;
Array.prototype["removeAt"] = AtomList.prototype.removeAt;
Array.prototype["watch"] = AtomList.prototype.watch;
})(WebAtoms || (WebAtoms = {}));
/// <reference path="atom-device.ts"/>
/// <reference path="atom-command.ts"/>
var WebAtoms;
(function (WebAtoms) {
/**
*
*
* @export
* @class AtomViewModel
* @extends {AtomModel}
*/
var AtomViewModel = /** @class */ (function (_super) {
__extends(AtomViewModel, _super);
function AtomViewModel() {
var _this = _super.call(this) || this;
_this._channelPrefix = "";
_this._isReady = false;
_this.validations = [];
WebAtoms.AtomDevice.instance.runAsync(function () { return _this.privateInit(); });
return _this;
}
Object.defineProperty(AtomViewModel.prototype, "channelPrefix", {
get: function () {
return this._channelPrefix;
},
set: function (v) {
this._channelPrefix = v;
var temp = this.subscriptions;
if (temp) {
this.subscriptions = [];
for (var _i = 0, temp_1 = temp; _i < temp_1.length; _i++) {
var s = temp_1[_i];
s.disposable.dispose();
}
for (var _a = 0, temp_2 = temp; _a < temp_2.length; _a++) {
var s1 = temp_2[_a];
this.subscribe(s.channel, s.action);
}
}
Atom.refresh(this, "channelPrefix");
},
enumerable: true,
configurable: true
});
Object.defineProperty(AtomViewModel.prototype, "isReady", {
get: function () {
return this._isReady;
},
enumerable: true,
configurable: true
});
AtomViewModel.prototype.privateInit = function () {
return __awaiter(this, void 0, void 0, function () {
var _this = this;
var _i, _a, i;
return __generator(this, function (_b) {
switch (_b.label) {
case 0:
_b.trys.push([0, , 3, 4]);
return [4 /*yield*/, Atom.postAsync(function () { return __awaiter(_this, void 0, void 0, function () {
return __generator(this, function (_a) {
this.runDecoratorInits();
return [2 /*return*/];
});
}); })];
case 1:
_b.sent();
return [4 /*yield*/, Atom.postAsync(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:
_b.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:
this._isReady = true;
return [7 /*endfinally*/];
case 4: return [2 /*return*/];
}
});
});
};
AtomViewModel.prototype.waitForReady = function () {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
if (!!this._isReady) return [3 /*break*/, 2];
return [4 /*yield*/, Atom.delay(100)];
case 1:
_a.sent();
return [3 /*break*/, 0];
case 2: return [2 /*return*/];
}
});
});
};
// tslint:disable-next-line:no-empty
AtomViewModel.prototype.onReady = function () { };
AtomViewModel.prototype.runDecoratorInits = function () {
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);
}
}
};
/**
* Internal method, do not use, instead use errors.hasErrors()
*
* @memberof AtomViewModel
*/
AtomViewModel.prototype.validate = function () {
for (var _i = 0, _a = this.validations; _i < _a.length; _i++) {
var v = _a[_i];
v.evaluate(true);
}
};
/**
* Adds validation expression to be executed when any bindable expression is updated.
*
* `target` must always be set to `this`.
*
* this.addValidation(() => {
* this.errors.nameError = this.data.firstName ? "" : "Name cannot be empty";
* });
*
* Only difference here is, validation will not kick in first time, where else watch will
* be invoked as soon as it is setup.
*
* Validation will be invoked when any bindable property in given expression is updated.
*
* Validation can be invoked explicitly only by calling `errors.hasErrors()`.
*
* @protected
* @template T
* @param {() => any} ft
* @returns {AtomDisposable}
* @memberof AtomViewModel
*/
AtomViewModel.prototype.addValidation = function () {
var _this = this;
var fts = [];
for (var _i = 0; _i < arguments.length; _i++) {
fts[_i] = arguments[_i];
}
var ds = [];
for (var _a = 0, fts_1 = fts; _a < fts_1.length; _a++) {
var ft = fts_1[_a];
var d = new WebAtoms.AtomWatcher(this, ft, false, true);
this.validations.push(d);
this.registerDisposable(d);
ds.push(d);
}
return new WebAtoms.DisposableAction(function () {
_this.disposables = _this.disposables.filter(function (f) { return !ds.find(function (fd) { return f === fd; }); });
for (var _i = 0, ds_1 = ds; _i < ds_1.length; _i++) {
var dispsoable = ds_1[_i];
dispsoable.dispose();
}
});
};
/**
* Execute given expression whenever any bindable expression changes
* in the expression.
*
* For correct generic type resolution, target must always be `this`.
*
* this.watch(() => {
* if(!this.data.fullName){
* this.data.fullName = `${this.data.firstName} ${this.data.lastName}`;
* }
* });