UNPKG

molstar

Version:

A comprehensive macromolecular library.

273 lines (272 loc) 11.8 kB
/** * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author David Sehnal <david.sehnal@gmail.com> */ import { __assign } from "tslib"; import { StateTree } from '../tree/immutable'; import { StateObjectCell, StateObjectSelector, StateObjectRef } from '../object'; import { StateTransform } from '../transform'; import { produce } from 'immer'; export { StateBuilder }; var StateBuilder; (function (StateBuilder) { function buildTree(state) { if (!state.state || state.state.tree === state.editInfo.sourceTree) { return state.tree.asImmutable(); } // The tree has changed in the meantime, we need to reapply the changes! var tree = state.state.tree.asTransient(); for (var _i = 0, _a = state.actions; _i < _a.length; _i++) { var a = _a[_i]; switch (a.kind) { case 'add': tree.add(a.transform); break; case 'update': tree.setParams(a.ref, a.params); break; case 'delete': tree.remove(a.ref); break; case 'insert': { var children = tree.children.get(a.ref).toArray(); tree.add(a.transform); for (var _b = 0, children_1 = children; _b < children_1.length; _b++) { var c = children_1[_b]; tree.changeParent(c, a.transform.ref); } break; } } } state.editInfo.sourceTree = state.tree; return tree.asImmutable(); } function is(obj) { return !!obj && typeof obj.getTree === 'function'; } StateBuilder.is = is; function isTo(obj) { return !!obj && typeof obj.getTree === 'function' && typeof obj.ref === 'string'; } StateBuilder.isTo = isTo; // type ToFromCell<C extends StateObjectCell> = C extends StateObjectCell<infer A, StateTransform<infer T extends StateTransformer>> ? To<A, any>: never var Root = /** @class */ (function () { function Root(tree, state) { this.state = { state: state, tree: tree.asTransient(), actions: [], editInfo: { applied: false, sourceTree: tree, count: 0, lastUpdate: void 0 } }; } Object.defineProperty(Root.prototype, "editInfo", { get: function () { return this.state.editInfo; }, enumerable: false, configurable: true }); Object.defineProperty(Root.prototype, "currentTree", { get: function () { return this.state.tree; }, enumerable: false, configurable: true }); Root.prototype.to = function (refOrCellOrSelector) { var ref = typeof refOrCellOrSelector === 'string' ? refOrCellOrSelector : StateObjectCell.is(refOrCellOrSelector) ? refOrCellOrSelector.transform.ref : refOrCellOrSelector.ref; return new To(this.state, ref, this); }; Root.prototype.toRoot = function () { return new To(this.state, this.state.tree.root.ref, this); }; Root.prototype.delete = function (obj) { var ref = StateObjectRef.resolveRef(obj); if (!ref || !this.state.tree.transforms.has(ref)) return this; this.editInfo.count++; this.state.tree.remove(ref); this.state.actions.push({ kind: 'delete', ref: ref }); return this; }; Root.prototype.getTree = function () { return buildTree(this.state); }; Root.prototype.commit = function (options) { if (!this.state.state) throw new Error('Cannot commit template tree'); return this.state.state.runTask(this.state.state.updateTree(this, options)); }; return Root; }()); StateBuilder.Root = Root; var To = /** @class */ (function () { function To(state, ref, root) { this.state = state; this.root = root; this.ref = ref; if (!this.state.tree.transforms.has(ref)) { throw new Error("Could not find node '".concat(ref, "'.")); } } Object.defineProperty(To.prototype, "editInfo", { get: function () { return this.state.editInfo; }, enumerable: false, configurable: true }); Object.defineProperty(To.prototype, "selector", { get: function () { return new StateObjectSelector(this.ref, this.state.state); }, enumerable: false, configurable: true }); To.prototype.getApplyRoot = function () { return StateTree.getDecoratorRoot(this.state.tree, this.ref); }; /** * Apply the transformed to the parent node * If no params are specified (params <- undefined), default params are lazily resolved. */ To.prototype.apply = function (tr, params, options) { if (tr.definition.isDecorator) { return this.insert(tr, params, options); } var applyRoot = this.getApplyRoot(); var t = tr.apply(applyRoot, params, options); this.state.tree.add(t); this.editInfo.count++; this.editInfo.lastUpdate = t.ref; this.state.actions.push({ kind: 'add', transform: t }); return new To(this.state, t.ref, this.root); }; /** * If the ref is present, the transform is applied. * Otherwise a transform with the specifed ref is created. */ To.prototype.applyOrUpdate = function (ref, tr, params, options) { if (this.state.tree.transforms.has(ref)) { var to = this.to(ref); if (params) to.update(params); return to; } else { return this.apply(tr, params, __assign(__assign({}, options), { ref: ref })); } }; /** * Apply the transformed to the parent node * If no params are specified (params <- undefined), default params are lazily resolved. * The transformer cannot be a decorator to be able to use this. */ To.prototype.applyOrUpdateTagged = function (tags, tr, params, options) { if (tr.definition.isDecorator) { throw new Error("Can't use applyOrUpdateTagged on decorator transformers."); } var applyRoot = this.getApplyRoot(); var children = this.state.tree.children.get(applyRoot).values(); while (true) { var child = children.next(); if (child.done) break; var tr_1 = this.state.tree.transforms.get(child.value); if (tr_1 && StateTransform.hasTags(tr_1, tags)) { var to = this.to(child.value); to.updateTagged(params, tagsUnion(tr_1.tags, tags, options && options.tags)); return to; } } var t = tr.apply(applyRoot, params, __assign(__assign({}, options), { tags: tagsUnion(tags, options && options.tags) })); this.state.tree.add(t); this.editInfo.count++; this.editInfo.lastUpdate = t.ref; this.state.actions.push({ kind: 'add', transform: t }); return new To(this.state, t.ref, this.root); }; /** * A helper to greate a group-like state object and keep the current type. */ To.prototype.group = function (tr, params, options) { return this.apply(tr, params, options); }; /** * Inserts a new transform that does not change the object type and move the original children to it. */ To.prototype.insert = function (tr, params, options) { // cache the children var children = this.state.tree.children.get(this.ref).toArray(); // add the new node var t = tr.apply(this.ref, params, options); this.state.tree.add(t); // move the original children to the new node for (var _i = 0, children_2 = children; _i < children_2.length; _i++) { var c = children_2[_i]; this.state.tree.changeParent(c, t.ref); } this.editInfo.count++; this.editInfo.lastUpdate = t.ref; this.state.actions.push({ kind: 'insert', ref: this.ref, transform: t }); return new To(this.state, t.ref, this.root); }; To.prototype.updateTagged = function (params, tags) { if (this.state.tree.setParams(this.ref, params) || this.state.tree.setTags(this.ref, tags)) { this.editInfo.count++; this.editInfo.lastUpdate = this.ref; this.state.actions.push({ kind: 'update', ref: this.ref, params: params }); } }; To.prototype.update = function (paramsOrTransformer, provider) { var params; if (provider) { var old = this.state.tree.transforms.get(this.ref); params = produce(old.params, provider); } else { params = typeof paramsOrTransformer === 'function' ? produce(this.state.tree.transforms.get(this.ref).params, paramsOrTransformer) : paramsOrTransformer; } if (this.state.tree.setParams(this.ref, params)) { this.editInfo.count++; this.editInfo.lastUpdate = this.ref; this.state.actions.push({ kind: 'update', ref: this.ref, params: params }); } return this.root; }; To.prototype.to = function (ref) { return this.root.to(ref); }; To.prototype.toRoot = function () { return this.root.toRoot(); }; To.prototype.delete = function (ref) { return this.root.delete(ref); }; To.prototype.getTree = function () { return buildTree(this.state); }; /** Returns selector to this node. */ To.prototype.commit = function (options) { if (!this.state.state) throw new Error('Cannot commit template tree'); return this.state.state.runTask(this.state.state.updateTree(this, options)); }; return To; }()); StateBuilder.To = To; })(StateBuilder || (StateBuilder = {})); function tagsUnion() { var arrays = []; for (var _i = 0; _i < arguments.length; _i++) { arrays[_i] = arguments[_i]; } var set = void 0; var ret = []; for (var _a = 0, arrays_1 = arrays; _a < arrays_1.length; _a++) { var xs = arrays_1[_a]; if (!xs) continue; if (!set) set = new Set(); if (typeof xs === 'string') { if (set.has(xs)) continue; set.add(xs); ret.push(xs); } else { for (var _b = 0, xs_1 = xs; _b < xs_1.length; _b++) { var x = xs_1[_b]; if (set.has(x)) continue; set.add(x); ret.push(x); } } } return ret; }