molstar
Version:
A comprehensive macromolecular library.
205 lines (204 loc) • 10 kB
JavaScript
/**
* Copyright (c) 2018-2023 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.registerDefault = registerDefault;
exports.SyncBehaviors = SyncBehaviors;
exports.SetCurrentObject = SetCurrentObject;
exports.Update = Update;
exports.ApplyAction = ApplyAction;
exports.RemoveObject = RemoveObject;
exports.ToggleExpanded = ToggleExpanded;
exports.ToggleVisibility = ToggleVisibility;
exports.setSubtreeVisibility = setSubtreeVisibility;
exports.Highlight = Highlight;
exports.ClearHighlights = ClearHighlights;
exports.Snapshots = Snapshots;
const structure_1 = require("../../../mol-model/structure");
const snapshots_1 = require("../../../mol-plugin-state/manager/snapshots");
const objects_1 = require("../../../mol-plugin-state/objects");
const mol_state_1 = require("../../../mol-state");
const date_1 = require("../../../mol-util/date");
const download_1 = require("../../../mol-util/download");
const url_1 = require("../../../mol-util/url");
const commands_1 = require("../../commands");
const config_1 = require("../../config");
function registerDefault(ctx) {
SyncBehaviors(ctx);
SetCurrentObject(ctx);
Update(ctx);
ApplyAction(ctx);
RemoveObject(ctx);
ToggleExpanded(ctx);
ToggleVisibility(ctx);
Highlight(ctx);
ClearHighlights(ctx);
Snapshots(ctx);
}
function SyncBehaviors(ctx) {
ctx.state.events.object.created.subscribe(o => {
if (!objects_1.PluginStateObject.isBehavior(o.obj))
return;
o.obj.data.register(o.ref);
});
ctx.state.events.object.removed.subscribe(o => {
var _a, _b, _c, _d;
if (!objects_1.PluginStateObject.isBehavior(o.obj))
return;
(_b = (_a = o.obj.data).unregister) === null || _b === void 0 ? void 0 : _b.call(_a);
(_d = (_c = o.obj.data).dispose) === null || _d === void 0 ? void 0 : _d.call(_c);
});
ctx.state.events.object.updated.subscribe(o => {
var _a, _b, _c, _d;
if (o.action === 'recreate') {
if (o.oldObj && objects_1.PluginStateObject.isBehavior(o.oldObj)) {
(_b = (_a = o.oldObj.data).unregister) === null || _b === void 0 ? void 0 : _b.call(_a);
(_d = (_c = o.oldObj.data).dispose) === null || _d === void 0 ? void 0 : _d.call(_c);
}
if (o.obj && objects_1.PluginStateObject.isBehavior(o.obj))
o.obj.data.register(o.ref);
}
});
}
function SetCurrentObject(ctx) {
commands_1.PluginCommands.State.SetCurrentObject.subscribe(ctx, ({ state, ref }) => state.setCurrent(ref));
}
function Update(ctx) {
commands_1.PluginCommands.State.Update.subscribe(ctx, ({ state, tree, options }) => ctx.runTask(state.updateTree(tree, options)));
}
function ApplyAction(ctx) {
commands_1.PluginCommands.State.ApplyAction.subscribe(ctx, ({ state, action, ref }) => ctx.runTask(state.applyAction(action.action, action.params, ref)));
}
function RemoveObject(ctx) {
function remove(state, ref) {
const tree = state.build().delete(ref);
return ctx.runTask(state.updateTree(tree));
}
commands_1.PluginCommands.State.RemoveObject.subscribe(ctx, ({ state, ref, removeParentGhosts }) => {
if (removeParentGhosts) {
const tree = state.tree;
let curr = tree.transforms.get(ref);
if (curr.parent === ref)
return remove(state, ref);
while (true) {
const children = tree.children.get(curr.parent);
if (curr.parent === curr.ref || children.size > 1)
return remove(state, curr.ref);
const parent = tree.transforms.get(curr.parent);
// TODO: should this use "cell state" instead?
if (!parent.state.isGhost)
return remove(state, curr.ref);
curr = parent;
}
}
else {
return remove(state, ref);
}
});
}
function ToggleExpanded(ctx) {
commands_1.PluginCommands.State.ToggleExpanded.subscribe(ctx, ({ state, ref }) => state.updateCellState(ref, ({ isCollapsed }) => ({ isCollapsed: !isCollapsed })));
}
function ToggleVisibility(ctx) {
commands_1.PluginCommands.State.ToggleVisibility.subscribe(ctx, ({ state, ref }) => setSubtreeVisibility(state, ref, !state.cells.get(ref).state.isHidden));
}
function setSubtreeVisibility(state, root, value) {
mol_state_1.StateTree.doPreOrder(state.tree, state.transforms.get(root), { state, value }, setVisibilityVisitor);
}
function setVisibilityVisitor(t, tree, ctx) {
ctx.state.updateCellState(t.ref, { isHidden: ctx.value });
}
function Highlight(ctx) {
commands_1.PluginCommands.Interactivity.Object.Highlight.subscribe(ctx, ({ state, ref }) => {
if (!ctx.canvas3d || ctx.isBusy)
return;
ctx.managers.interactivity.lociHighlights.clearHighlights();
const refs = typeof ref === 'string' ? [ref] : ref;
for (const r of refs) {
const cell = state.cells.get(r);
if (!cell)
continue;
if (objects_1.PluginStateObject.Molecule.Structure.is(cell.obj)) {
ctx.managers.interactivity.lociHighlights.highlight({ loci: structure_1.Structure.Loci(cell.obj.data) }, false);
}
else if (cell && objects_1.PluginStateObject.isRepresentation3D(cell.obj)) {
const { repr } = cell.obj.data;
for (const loci of repr.getAllLoci()) {
ctx.managers.interactivity.lociHighlights.highlight({ loci, repr }, false);
}
}
else if (objects_1.PluginStateObject.Molecule.Structure.Selections.is(cell.obj)) {
for (const entry of cell.obj.data) {
ctx.managers.interactivity.lociHighlights.highlight({ loci: entry.loci }, false);
}
}
}
// TODO: highlight volumes?
// TODO: select structures of subtree?
});
}
function ClearHighlights(ctx) {
commands_1.PluginCommands.Interactivity.ClearHighlights.subscribe(ctx, () => {
ctx.managers.interactivity.lociHighlights.clearHighlights();
});
}
function Snapshots(ctx) {
ctx.config.set(config_1.PluginConfig.State.CurrentServer, ctx.config.get(config_1.PluginConfig.State.DefaultServer));
commands_1.PluginCommands.State.Snapshots.Clear.subscribe(ctx, () => {
ctx.managers.snapshot.clear();
});
commands_1.PluginCommands.State.Snapshots.Remove.subscribe(ctx, ({ id }) => {
ctx.managers.snapshot.remove(id);
});
commands_1.PluginCommands.State.Snapshots.Add.subscribe(ctx, async ({ key, name, description, descriptionFormat, params }) => {
var _a;
const snapshot = ctx.state.getSnapshot(params);
const image = ((_a = params === null || params === void 0 ? void 0 : params.image) !== null && _a !== void 0 ? _a : ctx.state.snapshotParams.value.image) ? await snapshots_1.PluginStateSnapshotManager.getCanvasImageAsset(ctx, `${snapshot.id}-image.png`) : undefined;
const entry = snapshots_1.PluginStateSnapshotManager.Entry(snapshot, { key, name, description, descriptionFormat, image });
ctx.managers.snapshot.add(entry);
});
commands_1.PluginCommands.State.Snapshots.Replace.subscribe(ctx, async ({ id, params }) => {
var _a;
const snapshot = ctx.state.getSnapshot(params);
const image = ((_a = params === null || params === void 0 ? void 0 : params.image) !== null && _a !== void 0 ? _a : ctx.state.snapshotParams.value.image) ? await snapshots_1.PluginStateSnapshotManager.getCanvasImageAsset(ctx, `${snapshot.id}-image.png`) : undefined;
ctx.managers.snapshot.replace(id, ctx.state.getSnapshot(params), { image });
});
commands_1.PluginCommands.State.Snapshots.Move.subscribe(ctx, ({ id, dir }) => {
ctx.managers.snapshot.move(id, dir);
});
commands_1.PluginCommands.State.Snapshots.Apply.subscribe(ctx, ({ id }) => {
const snapshot = ctx.managers.snapshot.setCurrent(id);
if (!snapshot)
return;
return ctx.state.setSnapshot(snapshot);
});
commands_1.PluginCommands.State.Snapshots.Upload.subscribe(ctx, async ({ name, description, playOnLoad, serverUrl, params }) => {
return fetch((0, url_1.urlCombine)(serverUrl, `set?name=${encodeURIComponent(name || '')}&description=${encodeURIComponent(description || '')}`), {
method: 'POST',
mode: 'cors',
referrer: 'no-referrer',
headers: { 'Content-Type': 'application/json; charset=utf-8' },
body: JSON.stringify(await ctx.managers.snapshot.getStateSnapshot({ name, description, playOnLoad }))
});
});
commands_1.PluginCommands.State.Snapshots.Fetch.subscribe(ctx, async ({ url }) => {
const json = await ctx.runTask(ctx.fetch({ url, type: 'json' })); // fetch(url, { referrer: 'no-referrer' });
await ctx.managers.snapshot.setStateSnapshot(json.data);
});
commands_1.PluginCommands.State.Snapshots.DownloadToFile.subscribe(ctx, async ({ name, type, params }) => {
const filename = `mol-star_state_${(name || (0, date_1.getFormattedTime)())}.${type === 'json' ? 'molj' : 'molx'}`;
const data = await ctx.managers.snapshot.serialize({ type, params });
(0, download_1.download)(data, `${filename}`);
});
commands_1.PluginCommands.State.Snapshots.OpenFile.subscribe(ctx, ({ file }) => {
return ctx.managers.snapshot.open(file);
});
commands_1.PluginCommands.State.Snapshots.OpenUrl.subscribe(ctx, async ({ url, type }) => {
const data = await ctx.runTask(ctx.fetch({ url, type: 'binary' }));
return ctx.managers.snapshot.open(new File([data], `state.${type}`));
});
}
;