diff --git a/ElectronClient/app/gui/NoteText.jsx b/ElectronClient/app/gui/NoteText.jsx index 63177b259..28efa7890 100644 --- a/ElectronClient/app/gui/NoteText.jsx +++ b/ElectronClient/app/gui/NoteText.jsx @@ -6,6 +6,7 @@ const Search = require('lib/models/Search.js'); const { time } = require('lib/time-utils.js'); const Setting = require('lib/models/Setting.js'); const { IconButton } = require('./IconButton.min.js'); +const { urlDecode } = require('lib/string-utils'); const Toolbar = require('./Toolbar.min.js'); const { connect } = require('react-redux'); const { _ } = require('lib/locale.js'); @@ -569,7 +570,12 @@ class NoteTextComponent extends React.Component { throw new Error('Unsupported item type: ' + item.type_); } } else if (urlUtils.urlProtocol(msg)) { - require('electron').shell.openExternal(msg); + if (msg.indexOf('file://') === 0) { + // When using the file:// protocol, openExternal doesn't work (does nothing) with URL-encoded paths + require('electron').shell.openExternal(urlDecode(msg)); + } else { + require('electron').shell.openExternal(msg); + } } else { bridge().showErrorMessageBox(_('Unsupported link or message: %s', msg)); } diff --git a/ElectronClient/app/gui/note-viewer/index.html b/ElectronClient/app/gui/note-viewer/index.html index 342df9221..3b66f3136 100644 --- a/ElectronClient/app/gui/note-viewer/index.html +++ b/ElectronClient/app/gui/note-viewer/index.html @@ -276,6 +276,15 @@ } }); + // Prevent URLs added via tags from being opened within the application itself + document.addEventListener('click', function(event) { + const t = event.target; + if (t && t.nodeName === 'A' && !t.hasAttribute('data-from-md')) { + event.preventDefault(); + ipcProxySendToHost(t.getAttribute('href')); + } + }); + // Disable drag and drop otherwise it's possible to drop a URL // on it and it will open in the view as a website. document.addEventListener('drop', function(e) { diff --git a/ReactNativeClient/lib/MdToHtml.js b/ReactNativeClient/lib/MdToHtml.js index d7c0f8fb0..15ea78b89 100644 --- a/ReactNativeClient/lib/MdToHtml.js +++ b/ReactNativeClient/lib/MdToHtml.js @@ -102,7 +102,7 @@ class MdToHtml { const href = this.getAttr_(attrs, 'src'); if (!Resource.isResourceUrl(href)) { - return ''; + return ''; } const resourceId = Resource.urlToId(href); @@ -118,7 +118,7 @@ class MdToHtml { if (Resource.isSupportedImageMimeType(mime)) { let src = './' + Resource.filename(resource); if (this.resourceBaseUrl_ !== null) src = this.resourceBaseUrl_ + src; - let output = ''; + let output = ''; return output; } @@ -167,7 +167,7 @@ class MdToHtml { } const js = options.postMessageSyntax + "(" + JSON.stringify(href) + "); return false;"; - let output = "" + icon; + let output = "" + icon; return output; } @@ -487,7 +487,7 @@ class MdToHtml { while (renderedBody.indexOf('mJOPm') >= 0) { renderedBody = renderedBody.replace(/mJOPmCHECKBOXm([A-Z]+)m(\d+)m/, function(v, type, index) { const js = options.postMessageSyntax + "('checkboxclick:" + type + ':' + index + "'); this.classList.contains('tick') ? this.classList.remove('tick') : this.classList.add('tick'); return false;"; - return '' + '' + ''; + return '' + '' + ''; }); if (loopCount++ >= 9999) break; } diff --git a/ReactNativeClient/lib/string-utils.js b/ReactNativeClient/lib/string-utils.js index 13256d901..780ac000c 100644 --- a/ReactNativeClient/lib/string-utils.js +++ b/ReactNativeClient/lib/string-utils.js @@ -206,4 +206,8 @@ function toTitleCase(string) { return string.charAt(0).toUpperCase() + string.slice(1); } +function urlDecode(string) { + return decodeURIComponent((string+'').replace(/\+/g, '%20')); +} + module.exports = { removeDiacritics, escapeFilename, wrap, splitCommandString, padLeft, toTitleCase }; \ No newline at end of file