1
0
mirror of https://github.com/laurent22/joplin.git synced 2024-12-21 09:38:01 +02:00

Desktop: Fixes #8485: Note imported from Web Clipper is broken after being saved from the Rich Text editor

This commit is contained in:
Laurent Cozic 2023-07-26 17:36:21 +01:00
parent abe479d03f
commit 637a0eac7f
5 changed files with 67 additions and 21 deletions

View File

@ -845,6 +845,7 @@ packages/plugins/ToggleSidebars/api/index.js
packages/plugins/ToggleSidebars/api/types.js packages/plugins/ToggleSidebars/api/types.js
packages/plugins/ToggleSidebars/src/index.js packages/plugins/ToggleSidebars/src/index.js
packages/react-native-saf-x/src/index.js packages/react-native-saf-x/src/index.js
packages/renderer/HtmlToHtml.test.js
packages/renderer/HtmlToHtml.js packages/renderer/HtmlToHtml.js
packages/renderer/InMemoryCache.js packages/renderer/InMemoryCache.js
packages/renderer/MarkupToHtml.js packages/renderer/MarkupToHtml.js

1
.gitignore vendored
View File

@ -830,6 +830,7 @@ packages/plugins/ToggleSidebars/api/index.js
packages/plugins/ToggleSidebars/api/types.js packages/plugins/ToggleSidebars/api/types.js
packages/plugins/ToggleSidebars/src/index.js packages/plugins/ToggleSidebars/src/index.js
packages/react-native-saf-x/src/index.js packages/react-native-saf-x/src/index.js
packages/renderer/HtmlToHtml.test.js
packages/renderer/HtmlToHtml.js packages/renderer/HtmlToHtml.js
packages/renderer/InMemoryCache.js packages/renderer/InMemoryCache.js
packages/renderer/MarkupToHtml.js packages/renderer/MarkupToHtml.js

View File

@ -3,7 +3,7 @@ import { FormNote, defaultFormNote, ResourceInfos } from './types';
import { clearResourceCache, attachedResources } from './resourceHandling'; import { clearResourceCache, attachedResources } from './resourceHandling';
import AsyncActionQueue from '@joplin/lib/AsyncActionQueue'; import AsyncActionQueue from '@joplin/lib/AsyncActionQueue';
import { handleResourceDownloadMode } from './resourceHandling'; import { handleResourceDownloadMode } from './resourceHandling';
import HtmlToHtml from '@joplin/renderer/HtmlToHtml'; import { splitHtml } from '@joplin/renderer/HtmlToHtml';
import Setting from '@joplin/lib/models/Setting'; import Setting from '@joplin/lib/models/Setting';
import usePrevious from '../../hooks/usePrevious'; import usePrevious from '../../hooks/usePrevious';
import ResourceEditWatcher from '@joplin/lib/services/ResourceEditWatcher/index'; import ResourceEditWatcher from '@joplin/lib/services/ResourceEditWatcher/index';
@ -73,8 +73,7 @@ export default function useFormNote(dependencies: HookDependencies) {
let originalCss = ''; let originalCss = '';
if (n.markup_language === MarkupToHtml.MARKUP_LANGUAGE_HTML) { if (n.markup_language === MarkupToHtml.MARKUP_LANGUAGE_HTML) {
const htmlToHtml = new HtmlToHtml(); const splitted = splitHtml(n.body);
const splitted = htmlToHtml.splitHtml(n.body);
originalCss = splitted.css; originalCss = splitted.css;
} }

View File

@ -0,0 +1,44 @@
import { splitHtml, SplittedHtml } from './HtmlToHtml';
describe('HtmlToHtml', () => {
test('should split an HTML string into HTML and CSS', () => {
const testCases: [string, SplittedHtml][] = [
[
'',
{
html: '',
css: '',
},
],
[
'<style>b { font-weight: bold; }</style>\n<div>hello</div>\n<p>another line</p>',
{
html: '\n<div>hello</div>\n<p>another line</p>',
css: 'b { font-weight: bold; }',
},
],
[
'<STYLE>b { font-weight: bold; }</STYLE>\n<div>hello</div>',
{
html: '\n<div>hello</div>',
css: 'b { font-weight: bold; }',
},
],
[
'<html><head><STYLE>b { font-weight: bold; }</STYLE></head>\n<div>hello</div>',
{
html: '<html><head><STYLE>b { font-weight: bold; }</STYLE></head>\n<div>hello</div>',
css: '',
},
],
];
for (const t of testCases) {
const [input, expected] = t;
const actual = splitHtml(input);
expect(actual).toEqual(expected);
}
});
});

View File

@ -1,10 +1,6 @@
import htmlUtils from './htmlUtils'; import htmlUtils from './htmlUtils';
import linkReplacement from './MdToHtml/linkReplacement'; import linkReplacement from './MdToHtml/linkReplacement';
import utils, { ItemIdToUrlHandler } from './utils'; import utils, { ItemIdToUrlHandler } from './utils';
// TODO: fix
// import Setting from '@joplin/lib/models/Setting';
// const { themeStyle } = require('@joplin/lib/theme');
import InMemoryCache from './InMemoryCache'; import InMemoryCache from './InMemoryCache';
import { RenderResult } from './MarkupToHtml'; import { RenderResult } from './MarkupToHtml';
const md5 = require('md5'); const md5 = require('md5');
@ -14,6 +10,11 @@ const md5 = require('md5');
// relatively small. // relatively small.
const inMemoryCache = new InMemoryCache(10); const inMemoryCache = new InMemoryCache(10);
export interface SplittedHtml {
html: string;
css: string;
}
interface FsDriver { interface FsDriver {
// eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied // eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied
writeFile: Function; writeFile: Function;
@ -79,19 +80,6 @@ export default class HtmlToHtml {
return this.fsDriver_; return this.fsDriver_;
} }
public splitHtml(html: string) {
const trimmedHtml = trimStart(html);
if (trimmedHtml.indexOf('<style>') !== 0) return { html: html, css: '' };
const closingIndex = trimmedHtml.indexOf('</style>');
if (closingIndex < 0) return { html: html, css: '' };
return {
html: trimmedHtml.substr(closingIndex + 8),
css: trimmedHtml.substr(7, closingIndex),
};
}
public async allAssets(/* theme*/): Promise<any[]> { public async allAssets(/* theme*/): Promise<any[]> {
return []; // TODO return []; // TODO
} }
@ -166,7 +154,7 @@ export default class HtmlToHtml {
let cssStrings: string[] = []; let cssStrings: string[] = [];
if (options.splitted) { if (options.splitted) {
const splitted = this.splitHtml(html); const splitted = splitHtml(html);
cssStrings = [splitted.css].concat(cssStrings); cssStrings = [splitted.css].concat(cssStrings);
const output: RenderResult = { const output: RenderResult = {
@ -191,3 +179,16 @@ export default class HtmlToHtml {
}; };
} }
} }
const splitHtmlRegex = /^<style>([\s\S]*)<\/style>([\s\S]*)$/i;
// This function is designed to handle the narrow case of HTML generated by the
// HtmlToHtml class and used by the Rich Text editor, and that's with the STYLE
// tag at the top, followed by the HTML code. If it's anything else, we don't
// try to handle it and return the whole HTML code.
export const splitHtml = (html: string): SplittedHtml => {
const trimmedHtml = trimStart(html);
const result = trimmedHtml.match(splitHtmlRegex);
if (!result) return { html, css: '' };
return { html: result[2], css: result[1] };
};