molstar
Version:
A comprehensive macromolecular library.
376 lines • 17.9 kB
JavaScript
"use strict";
/**
* Copyright (c) 2018-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author David Sehnal <david.sehnal@gmail.com>
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.PluginStateSnapshotManager = void 0;
var tslib_1 = require("tslib");
var immutable_1 = require("immutable");
var component_1 = require("../component");
var utf8_1 = require("../../mol-io/common/utf8");
var zip_1 = require("../../mol-util/zip/zip");
var data_source_1 = require("../../mol-util/data-source");
var object_1 = require("../../mol-util/object");
var version_1 = require("../../mol-plugin/version");
var PluginStateSnapshotManager = /** @class */ (function (_super) {
(0, tslib_1.__extends)(PluginStateSnapshotManager, _super);
function PluginStateSnapshotManager(plugin) {
var _this = _super.call(this, {
current: void 0,
entries: (0, immutable_1.List)(),
isPlaying: false,
nextSnapshotDelayInMs: PluginStateSnapshotManager.DefaultNextSnapshotDelayInMs
}) || this;
_this.plugin = plugin;
_this.entryMap = new Map();
_this.events = {
changed: _this.ev()
};
_this.timeoutHandle = void 0;
_this.next = function () { return (0, tslib_1.__awaiter)(_this, void 0, void 0, function () {
var next, snapshot, delay;
return (0, tslib_1.__generator)(this, function (_a) {
switch (_a.label) {
case 0:
this.timeoutHandle = void 0;
next = this.getNextId(this.state.current, 1);
if (!next || next === this.state.current) {
this.stop();
return [2 /*return*/];
}
snapshot = this.setCurrent(next);
return [4 /*yield*/, this.plugin.state.setSnapshot(snapshot)];
case 1:
_a.sent();
delay = typeof snapshot.durationInMs !== 'undefined' ? snapshot.durationInMs : this.state.nextSnapshotDelayInMs;
if (this.state.isPlaying)
this.timeoutHandle = setTimeout(this.next, delay);
return [2 /*return*/];
}
});
}); };
return _this;
// TODO make nextSnapshotDelayInMs editable
}
PluginStateSnapshotManager.prototype.getIndex = function (e) {
return this.state.entries.indexOf(e);
};
PluginStateSnapshotManager.prototype.getEntry = function (id) {
if (!id)
return;
return this.entryMap.get(id);
};
PluginStateSnapshotManager.prototype.remove = function (id) {
var e = this.entryMap.get(id);
if (!e)
return;
this.entryMap.delete(id);
this.updateState({
current: this.state.current === id ? void 0 : this.state.current,
entries: this.state.entries.delete(this.getIndex(e))
});
this.events.changed.next(void 0);
};
PluginStateSnapshotManager.prototype.add = function (e) {
this.entryMap.set(e.snapshot.id, e);
this.updateState({ current: e.snapshot.id, entries: this.state.entries.push(e) });
this.events.changed.next(void 0);
};
PluginStateSnapshotManager.prototype.replace = function (id, snapshot) {
var old = this.getEntry(id);
if (!old)
return;
var idx = this.getIndex(old);
// The id changes here!
var e = PluginStateSnapshotManager.Entry(snapshot, {
name: old.name,
description: old.description
});
this.entryMap.set(snapshot.id, e);
this.updateState({ current: e.snapshot.id, entries: this.state.entries.set(idx, e) });
this.events.changed.next(void 0);
};
PluginStateSnapshotManager.prototype.move = function (id, dir) {
var len = this.state.entries.size;
if (len < 2)
return;
var e = this.getEntry(id);
if (!e)
return;
var from = this.getIndex(e);
var to = (from + dir) % len;
if (to < 0)
to += len;
var f = this.state.entries.get(to);
var entries = this.state.entries.asMutable();
entries.set(to, e);
entries.set(from, f);
this.updateState({ current: e.snapshot.id, entries: entries.asImmutable() });
this.events.changed.next(void 0);
};
PluginStateSnapshotManager.prototype.clear = function () {
if (this.state.entries.size === 0)
return;
this.entryMap.clear();
this.updateState({ current: void 0, entries: (0, immutable_1.List)() });
this.events.changed.next(void 0);
};
PluginStateSnapshotManager.prototype.setCurrent = function (id) {
var e = this.getEntry(id);
if (e) {
this.updateState({ current: id });
this.events.changed.next(void 0);
}
return e && e.snapshot;
};
PluginStateSnapshotManager.prototype.getNextId = function (id, dir) {
var len = this.state.entries.size;
if (!id) {
if (len === 0)
return void 0;
var idx_1 = dir === -1 ? len - 1 : 0;
return this.state.entries.get(idx_1).snapshot.id;
}
var e = this.getEntry(id);
if (!e)
return;
var idx = this.getIndex(e);
if (idx < 0)
return;
idx = (idx + dir) % len;
if (idx < 0)
idx += len;
return this.state.entries.get(idx).snapshot.id;
};
PluginStateSnapshotManager.prototype.setStateSnapshot = function (snapshot) {
return (0, tslib_1.__awaiter)(this, void 0, void 0, function () {
var entries, _i, _a, e, current, entry, next;
return (0, tslib_1.__generator)(this, function (_b) {
switch (_b.label) {
case 0:
if (snapshot.version !== version_1.PLUGIN_VERSION) {
// TODO
// console.warn('state snapshot version mismatch');
}
this.clear();
entries = (0, immutable_1.List)().asMutable();
for (_i = 0, _a = snapshot.entries; _i < _a.length; _i++) {
e = _a[_i];
this.entryMap.set(e.snapshot.id, e);
entries.push(e);
}
current = snapshot.current
? snapshot.current
: snapshot.entries.length > 0
? snapshot.entries[0].snapshot.id
: void 0;
this.updateState({
current: current,
entries: entries.asImmutable(),
isPlaying: false,
nextSnapshotDelayInMs: snapshot.playback ? snapshot.playback.nextSnapshotDelayInMs : PluginStateSnapshotManager.DefaultNextSnapshotDelayInMs
});
this.events.changed.next(void 0);
if (!current)
return [2 /*return*/];
entry = this.getEntry(current);
next = entry && entry.snapshot;
if (!next)
return [2 /*return*/];
return [4 /*yield*/, this.plugin.state.setSnapshot(next)];
case 1:
_b.sent();
if (snapshot.playback && snapshot.playback.isPlaying)
this.play(true);
return [2 /*return*/, next];
}
});
});
};
PluginStateSnapshotManager.prototype.syncCurrent = function (options) {
var snapshot = this.plugin.state.getSnapshot(options === null || options === void 0 ? void 0 : options.params);
if (this.state.entries.size === 0 || !this.state.current) {
this.add(PluginStateSnapshotManager.Entry(snapshot, { name: options === null || options === void 0 ? void 0 : options.name, description: options === null || options === void 0 ? void 0 : options.description }));
}
else {
this.replace(this.state.current, snapshot);
}
};
PluginStateSnapshotManager.prototype.getStateSnapshot = function (options) {
// TODO: diffing and all that fancy stuff
this.syncCurrent(options);
return {
timestamp: +new Date(),
version: version_1.PLUGIN_VERSION,
name: options && options.name,
description: options && options.description,
current: this.state.current,
playback: {
isPlaying: !!(options && options.playOnLoad),
nextSnapshotDelayInMs: this.state.nextSnapshotDelayInMs
},
entries: this.state.entries.valueSeq().toArray()
};
};
PluginStateSnapshotManager.prototype.serialize = function (options) {
return (0, tslib_1.__awaiter)(this, void 0, void 0, function () {
var json, state, zipDataObj, assets, _i, _a, _b, asset, file, _c, _d, _e, index, data, zipFile;
return (0, tslib_1.__generator)(this, function (_f) {
switch (_f.label) {
case 0:
json = JSON.stringify(this.getStateSnapshot({ params: options === null || options === void 0 ? void 0 : options.params }), null, 2);
if (!(!(options === null || options === void 0 ? void 0 : options.type) || options.type === 'json' || options.type === 'molj')) return [3 /*break*/, 1];
return [2 /*return*/, new Blob([json], { type: 'application/json;charset=utf-8' })];
case 1:
state = new Uint8Array((0, utf8_1.utf8ByteCount)(json));
(0, utf8_1.utf8Write)(state, 0, json);
zipDataObj = {
'state.json': state
};
assets = [];
_i = 0, _a = this.plugin.managers.asset.assets;
_f.label = 2;
case 2:
if (!(_i < _a.length)) return [3 /*break*/, 5];
_b = _a[_i], asset = _b.asset, file = _b.file;
assets.push([asset.id, asset]);
_c = zipDataObj;
_d = "assets/" + asset.id;
_e = Uint8Array.bind;
return [4 /*yield*/, file.arrayBuffer()];
case 3:
_c[_d] = new (_e.apply(Uint8Array, [void 0, _f.sent()]))();
_f.label = 4;
case 4:
_i++;
return [3 /*break*/, 2];
case 5:
if (assets.length > 0) {
index = JSON.stringify(assets, null, 2);
data = new Uint8Array((0, utf8_1.utf8ByteCount)(index));
(0, utf8_1.utf8Write)(data, 0, index);
zipDataObj['assets.json'] = data;
}
return [4 /*yield*/, this.plugin.runTask((0, zip_1.Zip)(zipDataObj))];
case 6:
zipFile = _f.sent();
return [2 /*return*/, new Blob([zipFile], { type: 'application/zip' })];
}
});
});
};
PluginStateSnapshotManager.prototype.open = function (file) {
return (0, tslib_1.__awaiter)(this, void 0, void 0, function () {
var fn, data, snapshot, data, assets_1, stateFile, stateData, file_1, json, _a, _b, _i, json_1, _c, id, asset, snapshot, e_1;
return (0, tslib_1.__generator)(this, function (_d) {
switch (_d.label) {
case 0:
_d.trys.push([0, 8, , 9]);
fn = file.name.toLowerCase();
if (!(fn.endsWith('json') || fn.endsWith('molj'))) return [3 /*break*/, 2];
return [4 /*yield*/, this.plugin.runTask((0, data_source_1.readFromFile)(file, 'string'))];
case 1:
data = _d.sent();
snapshot = JSON.parse(data);
if (PluginStateSnapshotManager.isStateSnapshot(snapshot)) {
return [2 /*return*/, this.setStateSnapshot(snapshot)];
}
else if (PluginStateSnapshotManager.isStateSnapshot(snapshot.data)) {
return [2 /*return*/, this.setStateSnapshot(snapshot.data)];
}
else {
this.plugin.state.setSnapshot(snapshot);
}
return [3 /*break*/, 7];
case 2: return [4 /*yield*/, this.plugin.runTask((0, data_source_1.readFromFile)(file, 'zip'))];
case 3:
data = _d.sent();
assets_1 = Object.create(null);
(0, object_1.objectForEach)(data, function (v, k) {
if (k === 'state.json' || k === 'assets.json')
return;
var name = k.substring(k.indexOf('/') + 1);
assets_1[name] = new File([v], name);
});
stateFile = new File([data['state.json']], 'state.json');
return [4 /*yield*/, this.plugin.runTask((0, data_source_1.readFromFile)(stateFile, 'string'))];
case 4:
stateData = _d.sent();
if (!data['assets.json']) return [3 /*break*/, 6];
file_1 = new File([data['assets.json']], 'assets.json');
_b = (_a = JSON).parse;
return [4 /*yield*/, this.plugin.runTask((0, data_source_1.readFromFile)(file_1, 'string'))];
case 5:
json = _b.apply(_a, [_d.sent()]);
for (_i = 0, json_1 = json; _i < json_1.length; _i++) {
_c = json_1[_i], id = _c[0], asset = _c[1];
this.plugin.managers.asset.set(asset, assets_1[id]);
}
_d.label = 6;
case 6:
snapshot = JSON.parse(stateData);
return [2 /*return*/, this.setStateSnapshot(snapshot)];
case 7: return [3 /*break*/, 9];
case 8:
e_1 = _d.sent();
this.plugin.log.error("Reading state: " + e_1);
return [3 /*break*/, 9];
case 9: return [2 /*return*/];
}
});
});
};
PluginStateSnapshotManager.prototype.play = function (delayFirst) {
if (delayFirst === void 0) { delayFirst = false; }
this.updateState({ isPlaying: true });
if (delayFirst) {
var e = this.getEntry(this.state.current);
if (!e) {
this.next();
return;
}
this.events.changed.next(void 0);
var snapshot = e.snapshot;
var delay = typeof snapshot.durationInMs !== 'undefined' ? snapshot.durationInMs : this.state.nextSnapshotDelayInMs;
this.timeoutHandle = setTimeout(this.next, delay);
}
else {
this.next();
}
};
PluginStateSnapshotManager.prototype.stop = function () {
this.updateState({ isPlaying: false });
if (typeof this.timeoutHandle !== 'undefined')
clearTimeout(this.timeoutHandle);
this.timeoutHandle = void 0;
this.events.changed.next(void 0);
};
PluginStateSnapshotManager.prototype.togglePlay = function () {
if (this.state.isPlaying) {
this.stop();
this.plugin.managers.animation.stop();
}
else {
this.play();
}
};
PluginStateSnapshotManager.DefaultNextSnapshotDelayInMs = 1500;
return PluginStateSnapshotManager;
}(component_1.StatefulPluginComponent));
exports.PluginStateSnapshotManager = PluginStateSnapshotManager;
(function (PluginStateSnapshotManager) {
function Entry(snapshot, params) {
return (0, tslib_1.__assign)({ timestamp: +new Date(), snapshot: snapshot }, params);
}
PluginStateSnapshotManager.Entry = Entry;
function isStateSnapshot(x) {
var s = x;
return !!s && !!s.timestamp && !!s.entries;
}
PluginStateSnapshotManager.isStateSnapshot = isStateSnapshot;
})(PluginStateSnapshotManager || (PluginStateSnapshotManager = {}));
exports.PluginStateSnapshotManager = PluginStateSnapshotManager;
//# sourceMappingURL=snapshots.js.map