Browse Source

imroved download helper and state download

Alexander Rose 5 năm trước cách đây
mục cha
commit
bb07d6ec56
2 tập tin đã thay đổi với 46 bổ sung46 xóa
  1. 3 7
      src/mol-plugin/behavior/static/state.ts
  2. 43 39
      src/mol-util/download.ts

+ 3 - 7
src/mol-plugin/behavior/static/state.ts

@@ -11,6 +11,7 @@ import { PluginStateSnapshotManager } from '../../../mol-plugin/state/snapshots'
 import { PluginStateObject as SO } from '../../state/objects';
 import { getFormattedTime } from '../../../mol-util/date';
 import { readFromFile } from '../../../mol-util/data-source';
+import { download } from '../../../mol-util/download';
 
 export function registerDefault(ctx: PluginContext) {
     SyncBehaviors(ctx);
@@ -163,14 +164,9 @@ export function Snapshots(ctx: PluginContext) {
     });
 
     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);
+        const blob = new Blob([json], {type : 'application/json;charset=utf-8'});
+        download(blob, `mol-star_state_${(name || getFormattedTime())}.json`)
     });
 
     PluginCommands.State.Snapshots.OpenFile.subscribe(ctx, async ({ file }) => {

+ 43 - 39
src/mol-util/download.ts

@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2018-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  */
@@ -11,55 +11,59 @@ function openUrl (url: string) {
     }
 }
 
-export function download (data: Blob|string, downloadName = 'download') {
+function click(node: HTMLAnchorElement) {
+    try {
+        node.dispatchEvent(new MouseEvent('click'))
+    } catch (e) {
+        const evt = document.createEvent('MouseEvents')
+        evt.initMouseEvent('click', true, true, window, 0, 0, 0, 80, 20, false, false, false, false, 0, null)
+        node.dispatchEvent(evt)
+    }
+}
+
+export function download (data: Blob | string, downloadName = 'download') {
     // using ideas from https://github.com/eligrey/FileSaver.js/blob/master/FileSaver.js
 
     if (!data) return
 
-    const ua = window.navigator.userAgent
-    const isSafari = /Safari/i.test(ua)
-    const isChromeIos = /CriOS\/[\d]+/.test(ua)
-
-    const a = document.createElement('a')
+    if ('download' in HTMLAnchorElement.prototype) {
+        const a = document.createElement('a')
+        a.download = downloadName
+        a.rel = 'noopener'
 
-    function open (str: string) {
-        openUrl(isChromeIos ? str : str.replace(/^data:[^;]*;/, 'data:attachment/file;'))
-    }
-
-    if (typeof navigator !== 'undefined' && navigator.msSaveOrOpenBlob) {
-        // native saveAs in IE 10+
-        navigator.msSaveOrOpenBlob(data, downloadName)
-    } else if ((isSafari || isChromeIos) && FileReader) {
-        if (data instanceof Blob) {
-            // no downloading of blob urls in Safari
-            const reader = new FileReader()
-            reader.onloadend = () => open(reader.result as string)
-            reader.readAsDataURL(data)
+        if (typeof data === 'string') {
+            a.href = data;
+            click(a)
         } else {
-            open(data)
+            a.href = URL.createObjectURL(data);
+            setTimeout(() => URL.revokeObjectURL(a.href), 4E4) // 40s
+            setTimeout(() => click(a))
         }
+    } else if (typeof navigator !== 'undefined' && navigator.msSaveOrOpenBlob) {
+        // native saveAs in IE 10+
+        navigator.msSaveOrOpenBlob(data, downloadName)
     } else {
-        let objectUrlCreated = false
-        if (data instanceof Blob) {
-            data = URL.createObjectURL(data)
-            objectUrlCreated = true
-        }
+        const ua = window.navigator.userAgent
+        const isSafari = /Safari/i.test(ua)
+        const isChromeIos = /CriOS\/[\d]+/.test(ua)
 
-        if ('download' in a) {
-            // download link available
-            a.style.display = 'hidden'
-            document.body.appendChild(a)
-            a.href = data
-            a.download = downloadName
-            a.target = '_blank'
-            a.click()
-            document.body.removeChild(a)
-        } else {
-            openUrl(data)
+        const open = (str: string) => {
+            openUrl(isChromeIos ? str : str.replace(/^data:[^;]*;/, 'data:attachment/file;'))
         }
 
-        if (objectUrlCreated) {
-            window.URL.revokeObjectURL(data)
+        if ((isSafari || isChromeIos) && FileReader) {
+            if (data instanceof Blob) {
+                // no downloading of blob urls in Safari
+                const reader = new FileReader()
+                reader.onloadend = () => open(reader.result as string)
+                reader.readAsDataURL(data)
+            } else {
+                open(data)
+            }
+        } else {
+            const url = URL.createObjectURL(data)
+            location.href = url
+            setTimeout(() => URL.revokeObjectURL(url), 4E4) // 40s
         }
     }
 }