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() {
['', ['http://other.com/img.png'], ''],
];
- 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(`${tagName}>`);
+ if (!htmlUtils.isSelfClosingTag(tagName)) section.lines.push(`${tagName}>`);
});
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');