From 39fc11339647f1f220457f37dfbff9159e9537f1 Mon Sep 17 00:00:00 2001 From: Daniel Date: Sun, 3 Feb 2019 21:12:27 +0300 Subject: [PATCH 1/7] Set download attribute on download link. --- src/article/editor/DownloadSupplementaryFileTool.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/article/editor/DownloadSupplementaryFileTool.js b/src/article/editor/DownloadSupplementaryFileTool.js index efe26288b..392bb0cd9 100644 --- a/src/article/editor/DownloadSupplementaryFileTool.js +++ b/src/article/editor/DownloadSupplementaryFileTool.js @@ -5,6 +5,9 @@ export default class DownloadSupplementaryFileTool extends Tool { render ($$) { let el = super.render($$) let link = $$('a').ref('link') + // Note: download attribute instructs browsers to download a URL instead of navigating to it + // but only for same-origin URLs, e.g. it will not work for remote images + .attr('download', '') // ATTENTION: stop propagation, otherwise infinite loop .on('click', domHelpers.stop) // Note: in the browser version we want to open the download in a new tab From a0187a9bab1801dee9f4773dbd5045ab7f13e324 Mon Sep 17 00:00:00 2001 From: Daniel Date: Sun, 3 Feb 2019 23:19:39 +0300 Subject: [PATCH 2/7] Open remote files in a new tab of browser. --- src/article/editor/DownloadSupplementaryFileTool.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/article/editor/DownloadSupplementaryFileTool.js b/src/article/editor/DownloadSupplementaryFileTool.js index 392bb0cd9..42df3bccb 100644 --- a/src/article/editor/DownloadSupplementaryFileTool.js +++ b/src/article/editor/DownloadSupplementaryFileTool.js @@ -5,15 +5,11 @@ export default class DownloadSupplementaryFileTool extends Tool { render ($$) { let el = super.render($$) let link = $$('a').ref('link') - // Note: download attribute instructs browsers to download a URL instead of navigating to it - // but only for same-origin URLs, e.g. it will not work for remote images + // Downloads a non-remote urls .attr('download', '') // ATTENTION: stop propagation, otherwise infinite loop .on('click', domHelpers.stop) - // Note: in the browser version we want to open the download in a new tab - if (!platform.inElectron) { - link.attr('target', '_blank') - } + el.append(link) return el } @@ -42,6 +38,10 @@ export default class DownloadSupplementaryFileTool extends Tool { this.refs.link.el.attr({ 'href': url }) + // Note: in the browser version we want to open remote files in a new tab + if (!platform.inElectron && !isLocal) { + this.refs.link.attr('target', '_blank') + } this.refs.link.el.click() } } From a62363bc737baec75be7cf3d36bc45f29a9f5049 Mon Sep 17 00:00:00 2001 From: Daniel Date: Mon, 4 Feb 2019 01:29:42 +0300 Subject: [PATCH 3/7] Download supplementary files. --- app/main.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/app/main.js b/app/main.js index 73411f8bc..ff7ab7226 100644 --- a/app/main.js +++ b/app/main.js @@ -5,7 +5,7 @@ const url = require('url') const fsExtra = require('fs-extra') const { - app, dialog, shell, protocol, + app, dialog, shell, protocol, session, BrowserWindow, Menu, ipcMain } = electron const DEBUG = process.env.DEBUG @@ -37,6 +37,12 @@ app.on('ready', () => { if (error) console.error('Failed to register protocol') }) + // Download files + session.defaultSession.on('will-download', (event, item) => { + let location = dialog.showSaveDialog({ defaultPath: item.getFilename() }) + item.setSavePath(location) + }) + createMenu() // look if there is a 'dar' file in the args that does exist From 8f3f8e00cbc55a7b16db255eac948019eea076f3 Mon Sep 17 00:00:00 2001 From: Daniel Date: Mon, 4 Feb 2019 17:20:06 +0300 Subject: [PATCH 4/7] Handle file save canceling. --- app/main.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/main.js b/app/main.js index ff7ab7226..73231f0da 100644 --- a/app/main.js +++ b/app/main.js @@ -40,7 +40,11 @@ app.on('ready', () => { // Download files session.defaultSession.on('will-download', (event, item) => { let location = dialog.showSaveDialog({ defaultPath: item.getFilename() }) - item.setSavePath(location) + if (location) { + item.setSavePath(location) + } else { + event.preventDefault() + } }) createMenu() From a01448b408ed4a58bdc52cee368065ddfed61e34 Mon Sep 17 00:00:00 2001 From: Oliver Buchtala Date: Tue, 5 Feb 2019 06:14:15 +0100 Subject: [PATCH 5/7] Add node to command state of download tool. --- .../editor/DownloadSupplementaryFileCommand.js | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/article/editor/DownloadSupplementaryFileCommand.js b/src/article/editor/DownloadSupplementaryFileCommand.js index 1ab9243eb..e646878c7 100644 --- a/src/article/editor/DownloadSupplementaryFileCommand.js +++ b/src/article/editor/DownloadSupplementaryFileCommand.js @@ -6,14 +6,23 @@ import { Command } from 'substance' */ export default class DownloadSupplementaryFileCommand extends Command { getCommandState (params, context) { - const xpath = params.selectionState.xpath + const selectionState = params.selectionState + const xpath = selectionState.xpath if (xpath.length > 0) { const selectedType = xpath[xpath.length - 1].type - return { disabled: selectedType !== 'supplementary-file' } + if (selectedType === 'supplementary-file') { + return { + disabled: false, + // leaving the node, so that the tool can apply different + // strategies for local vs remote files + node: selectionState.node + } + } } return { disabled: true } } execute (params, context) { + // Nothing: downloading is implemented via native download hooks } } From 7ebb8caa9646dc8293edbee3f3f5d8fd7657d354 Mon Sep 17 00:00:00 2001 From: Oliver Buchtala Date: Tue, 5 Feb 2019 06:14:40 +0100 Subject: [PATCH 6/7] Improve DownloadSupplementaryFileTool. --- .../editor/DownloadSupplementaryFileTool.js | 38 ++++++++++++++----- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/src/article/editor/DownloadSupplementaryFileTool.js b/src/article/editor/DownloadSupplementaryFileTool.js index 42df3bccb..f7dbdad44 100644 --- a/src/article/editor/DownloadSupplementaryFileTool.js +++ b/src/article/editor/DownloadSupplementaryFileTool.js @@ -5,11 +5,26 @@ export default class DownloadSupplementaryFileTool extends Tool { render ($$) { let el = super.render($$) let link = $$('a').ref('link') - // Downloads a non-remote urls - .attr('download', '') // ATTENTION: stop propagation, otherwise infinite loop .on('click', domHelpers.stop) + // Downloading is a bit involved: + // In electron, everything can be done with one solution, + // handling a 'will-download' event, which is triggered when the `download` + // attribute is present. + // For the browser, the `download` attribute works only for files from the same + // origin. For remote files the best we can do at the moment, is opening + // a new tab, and let the browser deal with it. + // TODO: if this feature is important, one idea is that the DAR server could + // provide an end-point to provide download-urls, and act as a proxy to + // cirvumvent the CORS problem. + const isLocal = this._isLocal() + if (platform.inElectron || isLocal) { + link.attr('download', '') + } else { + link.attr('target', '_blank') + } + el.append(link) return el } @@ -26,10 +41,8 @@ export default class DownloadSupplementaryFileTool extends Tool { _triggerDownload () { const archive = this.context.archive - const editorSession = this.context.editorSession - const selectionState = editorSession.getSelectionState() - const node = selectionState.node - const isLocal = !node.remote + const node = this._getNode() + const isLocal = this._isLocal() let url = node.href if (isLocal) { url = archive.getDownloadLink(node.href) @@ -38,11 +51,16 @@ export default class DownloadSupplementaryFileTool extends Tool { this.refs.link.el.attr({ 'href': url }) - // Note: in the browser version we want to open remote files in a new tab - if (!platform.inElectron && !isLocal) { - this.refs.link.attr('target', '_blank') - } this.refs.link.el.click() } } + + _getNode () { + return this.props.commandState.node + } + + _isLocal () { + let node = this._getNode() + return (!node || !node.remote) + } } From e062d4230bb39ab464383289228c6ac5aa41868c Mon Sep 17 00:00:00 2001 From: Daniel Date: Tue, 5 Feb 2019 13:12:15 +0300 Subject: [PATCH 7/7] Put a comment about dialog cancelation. --- app/main.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/main.js b/app/main.js index 73231f0da..57374d914 100644 --- a/app/main.js +++ b/app/main.js @@ -40,6 +40,8 @@ app.on('ready', () => { // Download files session.defaultSession.on('will-download', (event, item) => { let location = dialog.showSaveDialog({ defaultPath: item.getFilename() }) + // If there is no location came from dialog it means cancelation and + // we should prevent default action to close dialog without error if (location) { item.setSavePath(location) } else {