Browse Source

mol-plugin: Save & open state from a JSON file

David Sehnal 6 years ago
parent
commit
d6241491bc

+ 31 - 0
src/mol-plugin/behavior/static/state.ts

@@ -11,6 +11,8 @@ import { PluginStateSnapshotManager } from 'mol-plugin/state/snapshots';
 import { PluginStateObject as SO, PluginStateObject } from '../../state/objects';
 import { EmptyLoci, EveryLoci } from 'mol-model/loci';
 import { Structure } from 'mol-model/structure';
+import { getFormattedTime } from 'mol-util/date';
+import { readFromFile } from 'mol-util/data-source';
 
 export function registerDefault(ctx: PluginContext) {
     SyncBehaviors(ctx);
@@ -134,4 +136,33 @@ export function Snapshots(ctx: PluginContext) {
         const json = await req.json();
         return ctx.state.setSnapshot(json.data);
     });
+
+    PluginCommands.State.Snapshots.DownloadToFile.subscribe(ctx, ({ name }) => {
+        const element = document.createElement('a');
+        const json = JSON.stringify(ctx.state.getSnapshot(), null, 2);
+        element.setAttribute('href', 'data:application/json;charset=utf-8,' + encodeURIComponent(json));
+        element.setAttribute('download', `mol-star_state_${(name || getFormattedTime())}.json`);
+        element.style.display = 'none';
+        document.body.appendChild(element);
+        element.click();
+        document.body.removeChild(element);
+    });
+
+    PluginCommands.State.Snapshots.OpenFile.subscribe(ctx, async ({ file }) => {
+        try {
+            const data = await readFromFile(file, 'string').run();
+            const json = JSON.parse(data as string);
+            await ctx.state.setSnapshot(json);
+        } catch (e) {
+            ctx.log.error(`Reading JSON state: ${e}`);
+        }
+        // const element = document.createElement('a');
+        // const json = JSON.stringify(ctx.state.getSnapshot(), null, 2);
+        // element.setAttribute('href', 'data:application/json;charset=utf-8,' + encodeURIComponent(json));
+        // element.setAttribute('download', `mol-star_state_${(name || getFormattedTime())}.json`);
+        // element.style.display = 'none';
+        // document.body.appendChild(element);
+        // element.click();
+        // document.body.removeChild(element);
+    });
 }

+ 4 - 1
src/mol-plugin/command.ts

@@ -32,7 +32,10 @@ export const PluginCommands = {
             Clear: PluginCommand<{}>({ isImmediate: true }),
 
             Upload: PluginCommand<{ name?: string, description?: string, serverUrl: string }>({ isImmediate: true }),
-            Fetch: PluginCommand<{ url: string }>()
+            Fetch: PluginCommand<{ url: string }>(),
+
+            DownloadToFile: PluginCommand<{ name?: string }>({ isImmediate: true }),
+            OpenFile: PluginCommand<{ file: File }>({ isImmediate: true }),
         }
     },
     Camera: {

+ 16 - 0
src/mol-plugin/ui/state.tsx

@@ -61,6 +61,16 @@ class StateSnapshotControls extends PluginComponent<{ serverUrl: string, serverC
         UploadedEvent.next();
     }
 
+    download = () => {
+        PluginCommands.State.Snapshots.DownloadToFile.dispatch(this.plugin, { name: this.state.name });
+    }
+
+    open = (e: React.ChangeEvent<HTMLInputElement>) => {
+        if (!e.target.files || !e.target.files![0]) return;
+
+        PluginCommands.State.Snapshots.OpenFile.dispatch(this.plugin, { file: e.target.files![0] });
+    }
+
     render() {
         return <div>
             <ParameterControls params={StateSnapshotControls.Params} values={this.state} onEnter={this.add} onChange={p => {
@@ -73,6 +83,12 @@ class StateSnapshotControls extends PluginComponent<{ serverUrl: string, serverC
                 <button className='msp-btn msp-btn-block msp-form-control' onClick={this.upload} disabled={this.state.isUploading}>Upload</button>
                 <button className='msp-btn msp-btn-block msp-form-control' onClick={this.clear}>Clear</button>
             </div>
+            <div className='msp-btn-row-group'>
+                <button className='msp-btn msp-btn-block msp-form-control' onClick={this.download}>Download JSON</button>
+                <div className='msp-btn msp-btn-block msp-btn-action msp-loader-msp-btn-file'>
+                    {'Open JSON'} <input onChange={this.open} type='file' multiple={false} accept='.json' />
+                </div>
+            </div>
         </div>;
     }
 }

+ 11 - 0
src/mol-util/date.ts

@@ -6,4 +6,15 @@
 
 export function dateToUtcString(date: Date) {
     return date.toISOString().replace(/T/, ' ').replace(/\..+/, '');
+}
+
+export function getFormattedTime() {
+    const today = new Date();
+    const y = today.getFullYear();
+    const m = today.getMonth() + 1;
+    const d = today.getDate();
+    const h = today.getHours();
+    const mi = today.getMinutes();
+    const s = today.getSeconds();
+    return y + '-' + m + '-' + d + '-' + h + '-' + mi + '-' + s;
 }