diff --git a/.eslintignore b/.eslintignore index 8b320a470..4fb98e8d6 100644 --- a/.eslintignore +++ b/.eslintignore @@ -106,6 +106,9 @@ packages/app-cli/tests/Synchronizer.tags.js.map packages/app-cli/tests/fsDriver.d.ts packages/app-cli/tests/fsDriver.js packages/app-cli/tests/fsDriver.js.map +packages/app-cli/tests/htmlUtils.d.ts +packages/app-cli/tests/htmlUtils.js +packages/app-cli/tests/htmlUtils.js.map packages/app-cli/tests/models_Folder.d.ts packages/app-cli/tests/models_Folder.js packages/app-cli/tests/models_Folder.js.map @@ -847,6 +850,9 @@ packages/lib/fs-driver-base.js.map packages/lib/fs-driver-node.d.ts packages/lib/fs-driver-node.js packages/lib/fs-driver-node.js.map +packages/lib/htmlUtils.d.ts +packages/lib/htmlUtils.js +packages/lib/htmlUtils.js.map packages/lib/import-enex-md-gen.d.ts packages/lib/import-enex-md-gen.js packages/lib/import-enex-md-gen.js.map diff --git a/.gitignore b/.gitignore index 48054820b..8253002d6 100644 --- a/.gitignore +++ b/.gitignore @@ -93,6 +93,9 @@ packages/app-cli/tests/Synchronizer.tags.js.map packages/app-cli/tests/fsDriver.d.ts packages/app-cli/tests/fsDriver.js packages/app-cli/tests/fsDriver.js.map +packages/app-cli/tests/htmlUtils.d.ts +packages/app-cli/tests/htmlUtils.js +packages/app-cli/tests/htmlUtils.js.map packages/app-cli/tests/models_Folder.d.ts packages/app-cli/tests/models_Folder.js packages/app-cli/tests/models_Folder.js.map @@ -834,6 +837,9 @@ packages/lib/fs-driver-base.js.map packages/lib/fs-driver-node.d.ts packages/lib/fs-driver-node.js packages/lib/fs-driver-node.js.map +packages/lib/htmlUtils.d.ts +packages/lib/htmlUtils.js +packages/lib/htmlUtils.js.map packages/lib/import-enex-md-gen.d.ts packages/lib/import-enex-md-gen.js packages/lib/import-enex-md-gen.js.map diff --git a/packages/app-cli/tests/htmlUtils.js b/packages/app-cli/tests/htmlUtils.ts similarity index 88% rename from packages/app-cli/tests/htmlUtils.js rename to packages/app-cli/tests/htmlUtils.ts index 70c2d3ef8..bbe69af9b 100644 --- a/packages/app-cli/tests/htmlUtils.js +++ b/packages/app-cli/tests/htmlUtils.ts @@ -1,6 +1,4 @@ -/* eslint-disable no-unused-vars */ - -const htmlUtils = require('@joplin/lib/htmlUtils.js'); +import htmlUtils from '@joplin/lib/htmlUtils'; describe('htmlUtils', function() { @@ -19,8 +17,8 @@ describe('htmlUtils', function() { ]; for (let i = 0; i < testCases.length; i++) { - const md = testCases[i][0]; - const expected = testCases[i][1]; + const md = testCases[i][0] as string; + const expected = testCases[i][1] as string[]; expect(htmlUtils.extractImageUrls(md).join(' ')).toBe(expected.join(' ')); } @@ -33,19 +31,19 @@ describe('htmlUtils', function() { ['testing', ['http://other.com/img.png'], 'testing'], ]; - const callback = (urls) => { + const callback = (urls: string[]) => { let i = -1; - return function(src) { + return function(_src: string) { i++; return urls[i]; }; }; for (let i = 0; i < testCases.length; i++) { - const md = testCases[i][0]; - const r = htmlUtils.replaceImageUrls(md, callback(testCases[i][1])); - expect(r.trim()).toBe(testCases[i][2].trim()); + const md = testCases[i][0] as string; + const r = htmlUtils.replaceImageUrls(md, callback(testCases[i][1] as string[])); + expect(r.trim()).toBe((testCases[i][2] as string).trim()); } })); diff --git a/packages/app-desktop/gui/ConfigScreen/controls/plugins/PluginsStates.tsx b/packages/app-desktop/gui/ConfigScreen/controls/plugins/PluginsStates.tsx index be49ea0a2..9533172e6 100644 --- a/packages/app-desktop/gui/ConfigScreen/controls/plugins/PluginsStates.tsx +++ b/packages/app-desktop/gui/ConfigScreen/controls/plugins/PluginsStates.tsx @@ -114,7 +114,7 @@ export default function(props: Props) { let cancelled = false; async function fetchPluginIds() { - const pluginIds = await repoApi().canBeUpdatedPlugins(pluginItems as any); + const pluginIds = await repoApi().canBeUpdatedPlugins(pluginItems.map(p => p.manifest)); if (cancelled) return; const conv: Record = {}; pluginIds.forEach(id => conv[id] = true); diff --git a/packages/app-desktop/gui/NoteEditor/utils/contextMenu.ts b/packages/app-desktop/gui/NoteEditor/utils/contextMenu.ts index f65048e53..d6090aea7 100644 --- a/packages/app-desktop/gui/NoteEditor/utils/contextMenu.ts +++ b/packages/app-desktop/gui/NoteEditor/utils/contextMenu.ts @@ -5,6 +5,7 @@ const bridge = require('electron').remote.require('./bridge').default; const Menu = bridge().Menu; const MenuItem = bridge().MenuItem; import Resource from '@joplin/lib/models/Resource'; +import htmlUtils from '@joplin/lib/htmlUtils'; const fs = require('fs-extra'); const { clipboard } = require('electron'); const { toSystemSlashes } = require('@joplin/lib/path-utils'); @@ -47,7 +48,13 @@ function handleCopyToClipboard(options: ContextMenuOptions) { if (options.textToCopy) { clipboard.writeText(options.textToCopy); } else if (options.htmlToCopy) { - clipboard.writeHTML(options.htmlToCopy); + // In that case we need to set both HTML and Text context, otherwise it + // won't be possible to paste the text in, for example, a text editor. + // https://github.com/laurent22/joplin/issues/4441 + clipboard.write({ + text: htmlUtils.stripHtml(options.htmlToCopy), + html: options.htmlToCopy, + }); } } diff --git a/packages/app-desktop/package-lock.json b/packages/app-desktop/package-lock.json index 61d8e6c43..8140a2980 100644 --- a/packages/app-desktop/package-lock.json +++ b/packages/app-desktop/package-lock.json @@ -1,6 +1,6 @@ { "name": "@joplin/app-desktop", - "version": "1.7.9", + "version": "1.7.10", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/packages/app-desktop/package.json b/packages/app-desktop/package.json index 4c6b3d2f3..c9b347358 100644 --- a/packages/app-desktop/package.json +++ b/packages/app-desktop/package.json @@ -1,6 +1,6 @@ { "name": "@joplin/app-desktop", - "version": "1.7.9", + "version": "1.7.10", "description": "Joplin for Desktop", "main": "main.js", "private": true, diff --git a/packages/lib/htmlUtils.js b/packages/lib/htmlUtils.ts similarity index 76% rename from packages/lib/htmlUtils.js rename to packages/lib/htmlUtils.ts index f4a5a7a56..6dd03e400 100644 --- a/packages/lib/htmlUtils.js +++ b/packages/lib/htmlUtils.ts @@ -31,19 +31,20 @@ const selfClosingElements = [ ]; class HtmlUtils { - headAndBodyHtml(doc) { + + public headAndBodyHtml(doc: any) { const output = []; if (doc.head) output.push(doc.head.innerHTML); if (doc.body) output.push(doc.body.innerHTML); return output.join('\n'); } - isSelfClosingTag(tagName) { + public isSelfClosingTag(tagName: string) { return selfClosingElements.includes(tagName.toLowerCase()); } // Returns the **encoded** URLs, so to be useful they should be decoded again before use. - extractImageUrls(html) { + public extractImageUrls(html: string) { if (!html) return []; const output = []; @@ -55,8 +56,8 @@ class HtmlUtils { return output.filter(url => !!url); } - replaceImageUrls(html, callback) { - return this.processImageTags(html, data => { + public replaceImageUrls(html: string, callback: Function) { + return this.processImageTags(html, (data: any) => { const newSrc = callback(data.src); return { type: 'replaceSource', @@ -65,10 +66,10 @@ class HtmlUtils { }); } - processImageTags(html, callback) { + public processImageTags(html: string, callback: Function) { if (!html) return ''; - return html.replace(imageRegex, (v, before, src, after) => { + return html.replace(imageRegex, (_v: string, before: string, src: string, after: string) => { const action = callback({ src: src }); if (!action) return ``; @@ -90,16 +91,16 @@ class HtmlUtils { }); } - prependBaseUrl(html, baseUrl) { + public prependBaseUrl(html: string, baseUrl: string) { if (!html) return ''; - return html.replace(anchorRegex, (v, before, href, after) => { + return html.replace(anchorRegex, (_v: string, before: string, href: string, after: string) => { const newHref = urlUtils.prependBaseUrl(href, baseUrl); return ``; }); } - attributesHtml(attr) { + public attributesHtml(attr: any) { const output = []; for (const n in attr) { @@ -110,10 +111,10 @@ class HtmlUtils { return output.join(' '); } - stripHtml(html) { - const output = []; + public stripHtml(html: string) { + const output: string[] = []; - const tagStack = []; + const tagStack: any[] = []; const currentTag = () => { if (!tagStack.length) return ''; @@ -124,16 +125,16 @@ class HtmlUtils { const parser = new htmlparser2.Parser({ - onopentag: (name) => { + onopentag: (name: string) => { tagStack.push(name.toLowerCase()); }, - ontext: (decodedText) => { + ontext: (decodedText: string) => { if (disallowedTags.includes(currentTag())) return; output.push(decodedText); }, - onclosetag: (name) => { + onclosetag: (name: string) => { if (currentTag() === name.toLowerCase()) tagStack.pop(); }, @@ -146,6 +147,4 @@ class HtmlUtils { } } -const htmlUtils = new HtmlUtils(); - -module.exports = htmlUtils; +export default new HtmlUtils(); diff --git a/packages/lib/import-enex-html-gen.js b/packages/lib/import-enex-html-gen.js index 6151d172e..ef0ac2125 100644 --- a/packages/lib/import-enex-html-gen.js +++ b/packages/lib/import-enex-html-gen.js @@ -1,7 +1,7 @@ const stringToStream = require('string-to-stream'); // const cleanHtml = require('clean-html'); const resourceUtils = require('./resourceUtils.js'); -const { isSelfClosingTag } = require('./htmlUtils'); +const htmlUtils = require('./htmlUtils').default; const Entities = require('html-entities').AllHtmlEntities; const htmlentities = new Entities().encode; @@ -126,7 +126,7 @@ function enexXmlToHtml_(stream, resources) { const nodeAttributes = attributeToLowerCase(node); const checkedHtml = nodeAttributes.checked && nodeAttributes.checked.toLowerCase() == 'true' ? ' checked="checked" ' : ' '; section.lines.push(``); - } else if (isSelfClosingTag(tagName)) { + } else if (htmlUtils.isSelfClosingTag(tagName)) { section.lines.push(`<${tagName}${attributesStr}/>`); } else { section.lines.push(`<${tagName}${attributesStr}>`); @@ -135,7 +135,7 @@ function enexXmlToHtml_(stream, resources) { saxStream.on('closetag', function(node) { const tagName = node ? node.toLowerCase() : node; - if (!isSelfClosingTag(tagName)) section.lines.push(``); + if (!htmlUtils.isSelfClosingTag(tagName)) section.lines.push(``); }); saxStream.on('attribute', function() {}); diff --git a/packages/lib/markupLanguageUtils.ts b/packages/lib/markupLanguageUtils.ts index 0f869cc03..0f22be45d 100644 --- a/packages/lib/markupLanguageUtils.ts +++ b/packages/lib/markupLanguageUtils.ts @@ -3,7 +3,7 @@ import Setting from './models/Setting'; import shim from './shim'; import MarkupToHtml, { MarkupLanguage } from '@joplin/renderer/MarkupToHtml'; -const htmlUtils = require('./htmlUtils'); +import htmlUtils from './htmlUtils'; import Resource from './models/Resource'; export class MarkupLanguageUtils { diff --git a/packages/lib/services/rest/routes/notes.ts b/packages/lib/services/rest/routes/notes.ts index c9ffcdc25..7ddb84e30 100644 --- a/packages/lib/services/rest/routes/notes.ts +++ b/packages/lib/services/rest/routes/notes.ts @@ -16,7 +16,7 @@ import Folder from '../../../models/Folder'; import Note from '../../../models/Note'; import Tag from '../../../models/Tag'; import Resource from '../../../models/Resource'; -const htmlUtils = require('../../../htmlUtils'); +import htmlUtils from '../../../htmlUtils'; import markupLanguageUtils from '../../../markupLanguageUtils'; const mimeUtils = require('../../../mime-utils.js').mime; const md5 = require('md5');