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:
parent
abe479d03f
commit
637a0eac7f
@ -845,6 +845,7 @@ packages/plugins/ToggleSidebars/api/index.js
|
||||
packages/plugins/ToggleSidebars/api/types.js
|
||||
packages/plugins/ToggleSidebars/src/index.js
|
||||
packages/react-native-saf-x/src/index.js
|
||||
packages/renderer/HtmlToHtml.test.js
|
||||
packages/renderer/HtmlToHtml.js
|
||||
packages/renderer/InMemoryCache.js
|
||||
packages/renderer/MarkupToHtml.js
|
||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -830,6 +830,7 @@ packages/plugins/ToggleSidebars/api/index.js
|
||||
packages/plugins/ToggleSidebars/api/types.js
|
||||
packages/plugins/ToggleSidebars/src/index.js
|
||||
packages/react-native-saf-x/src/index.js
|
||||
packages/renderer/HtmlToHtml.test.js
|
||||
packages/renderer/HtmlToHtml.js
|
||||
packages/renderer/InMemoryCache.js
|
||||
packages/renderer/MarkupToHtml.js
|
||||
|
@ -3,7 +3,7 @@ import { FormNote, defaultFormNote, ResourceInfos } from './types';
|
||||
import { clearResourceCache, attachedResources } from './resourceHandling';
|
||||
import AsyncActionQueue from '@joplin/lib/AsyncActionQueue';
|
||||
import { handleResourceDownloadMode } from './resourceHandling';
|
||||
import HtmlToHtml from '@joplin/renderer/HtmlToHtml';
|
||||
import { splitHtml } from '@joplin/renderer/HtmlToHtml';
|
||||
import Setting from '@joplin/lib/models/Setting';
|
||||
import usePrevious from '../../hooks/usePrevious';
|
||||
import ResourceEditWatcher from '@joplin/lib/services/ResourceEditWatcher/index';
|
||||
@ -73,8 +73,7 @@ export default function useFormNote(dependencies: HookDependencies) {
|
||||
let originalCss = '';
|
||||
|
||||
if (n.markup_language === MarkupToHtml.MARKUP_LANGUAGE_HTML) {
|
||||
const htmlToHtml = new HtmlToHtml();
|
||||
const splitted = htmlToHtml.splitHtml(n.body);
|
||||
const splitted = splitHtml(n.body);
|
||||
originalCss = splitted.css;
|
||||
}
|
||||
|
||||
|
44
packages/renderer/HtmlToHtml.test.ts
Normal file
44
packages/renderer/HtmlToHtml.test.ts
Normal 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);
|
||||
}
|
||||
});
|
||||
|
||||
});
|
@ -1,10 +1,6 @@
|
||||
import htmlUtils from './htmlUtils';
|
||||
import linkReplacement from './MdToHtml/linkReplacement';
|
||||
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 { RenderResult } from './MarkupToHtml';
|
||||
const md5 = require('md5');
|
||||
@ -14,6 +10,11 @@ const md5 = require('md5');
|
||||
// relatively small.
|
||||
const inMemoryCache = new InMemoryCache(10);
|
||||
|
||||
export interface SplittedHtml {
|
||||
html: string;
|
||||
css: string;
|
||||
}
|
||||
|
||||
interface FsDriver {
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied
|
||||
writeFile: Function;
|
||||
@ -79,19 +80,6 @@ export default class HtmlToHtml {
|
||||
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[]> {
|
||||
return []; // TODO
|
||||
}
|
||||
@ -166,7 +154,7 @@ export default class HtmlToHtml {
|
||||
let cssStrings: string[] = [];
|
||||
|
||||
if (options.splitted) {
|
||||
const splitted = this.splitHtml(html);
|
||||
const splitted = splitHtml(html);
|
||||
cssStrings = [splitted.css].concat(cssStrings);
|
||||
|
||||
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] };
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user