diff --git a/.eslintignore b/.eslintignore index 7ffa660f61..686414f27c 100644 --- a/.eslintignore +++ b/.eslintignore @@ -62,6 +62,7 @@ packages/app-mobile/locales packages/app-mobile/node_modules packages/app-mobile/pluginAssets/ packages/fork-* +!packages/fork-uslug packages/default-plugins/plugin-base-repo/ packages/default-plugins/plugin-sources/ packages/htmlpack/dist/ @@ -924,6 +925,8 @@ packages/editor/CodeMirror/editorCommands/duplicateLine.js packages/editor/CodeMirror/editorCommands/editorCommands.js packages/editor/CodeMirror/editorCommands/insertLineAfter.test.js packages/editor/CodeMirror/editorCommands/insertLineAfter.js +packages/editor/CodeMirror/editorCommands/jumpToHash.test.js +packages/editor/CodeMirror/editorCommands/jumpToHash.js packages/editor/CodeMirror/editorCommands/sortSelectedLines.test.js packages/editor/CodeMirror/editorCommands/sortSelectedLines.js packages/editor/CodeMirror/editorCommands/supportsCommand.js @@ -1002,6 +1005,8 @@ packages/fork-htmlparser2/src/__tests__/events.js packages/fork-htmlparser2/src/__tests__/stream.js packages/fork-htmlparser2/src/index.spec.js packages/fork-htmlparser2/src/index.js +packages/fork-uslug/lib/uslug.test.js +packages/fork-uslug/lib/uslug.js packages/generator-joplin/generators/app/templates/api/index.js packages/generator-joplin/generators/app/templates/api/noteListType.js packages/generator-joplin/generators/app/templates/api/types.js diff --git a/.gitignore b/.gitignore index 2a0b0a1620..84efad54ad 100644 --- a/.gitignore +++ b/.gitignore @@ -899,6 +899,8 @@ packages/editor/CodeMirror/editorCommands/duplicateLine.js packages/editor/CodeMirror/editorCommands/editorCommands.js packages/editor/CodeMirror/editorCommands/insertLineAfter.test.js packages/editor/CodeMirror/editorCommands/insertLineAfter.js +packages/editor/CodeMirror/editorCommands/jumpToHash.test.js +packages/editor/CodeMirror/editorCommands/jumpToHash.js packages/editor/CodeMirror/editorCommands/sortSelectedLines.test.js packages/editor/CodeMirror/editorCommands/sortSelectedLines.js packages/editor/CodeMirror/editorCommands/supportsCommand.js @@ -977,6 +979,8 @@ packages/fork-htmlparser2/src/__tests__/events.js packages/fork-htmlparser2/src/__tests__/stream.js packages/fork-htmlparser2/src/index.spec.js packages/fork-htmlparser2/src/index.js +packages/fork-uslug/lib/uslug.test.js +packages/fork-uslug/lib/uslug.js packages/generator-joplin/generators/app/templates/api/index.js packages/generator-joplin/generators/app/templates/api/noteListType.js packages/generator-joplin/generators/app/templates/api/types.js diff --git a/packages/app-cli/tests/support/plugins/content_script/src/markdownItTestPlugin.ts b/packages/app-cli/tests/support/plugins/content_script/src/markdownItTestPlugin.ts index d781ae21f9..de880a1e6b 100644 --- a/packages/app-cli/tests/support/plugins/content_script/src/markdownItTestPlugin.ts +++ b/packages/app-cli/tests/support/plugins/content_script/src/markdownItTestPlugin.ts @@ -13,13 +13,6 @@ export default function(context) { const token = tokens[idx]; if (token.info !== 'justtesting') return defaultRender(tokens, idx, options, env, self); - const postMessageWithResponseTest = ` - webviewApi.postMessage('${contentScriptId}', 'justtesting').then(function(response) { - console.info('Got response in content script: ' + response); - }); - return false; - `; - // Rich text editor support: // The joplin-editable and joplin-source CSS classes mark the generated div // as a region that needs special processing when converting back to markdown. @@ -38,14 +31,23 @@ export default function(context) { ${richTextEditorMetadata}

JUST TESTING:

${markdownIt.utils.escapeHtml(leftPad(token.content.trim(), 10, 'x'))}

-

Click to post a message "justtesting" to plugin and check the response in the console

+

+ + Click to post a message "justtesting" to plugin and check the response in the console + +

`; }; }, assets: function() { return [ - { name: 'markdownItTestPlugin.css' } + { name: 'markdownItTestPlugin.css' }, + { name: 'markdownItTestPluginRuntime.js' }, ]; }, } diff --git a/packages/app-cli/tests/support/plugins/content_script/src/markdownItTestPluginRuntime.js b/packages/app-cli/tests/support/plugins/content_script/src/markdownItTestPluginRuntime.js new file mode 100644 index 0000000000..b3c0150ad0 --- /dev/null +++ b/packages/app-cli/tests/support/plugins/content_script/src/markdownItTestPluginRuntime.js @@ -0,0 +1,14 @@ +const addClickHandlers = () => { + const postMessageLinks = document.querySelectorAll('.post-message-link'); + for (const link of postMessageLinks) { + const contentScriptId = link.getAttribute('data-content-script-id'); + link.onclick = async () => { + const response = await webviewApi.postMessage(contentScriptId, 'justtesting'); + link.textContent = 'Got response in content script: ' + response; + }; + } +}; + +document.addEventListener('joplin-noteDidUpdate', () => { + addClickHandlers(); +}); diff --git a/packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/CodeMirror.tsx b/packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/CodeMirror.tsx index 27e1a0987c..0ac8e45b71 100644 --- a/packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/CodeMirror.tsx +++ b/packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/CodeMirror.tsx @@ -167,7 +167,9 @@ const CodeMirror = (props: NoteBodyEditorProps, ref: ForwardedRef { if (options.type === ScrollOptionTypes.Hash) { if (!webviewRef.current) return; - webviewRef.current.send('scrollToHash', options.value as string); + const hash: string = options.value; + webviewRef.current.send('scrollToHash', hash); + editorRef.current.jumpToHash(hash); } else if (options.type === ScrollOptionTypes.Percent) { const percent = options.value as number; setEditorPercentScroll(percent); diff --git a/packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/TinyMCE.tsx b/packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/TinyMCE.tsx index 01ed279071..0dc1265dd2 100644 --- a/packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/TinyMCE.tsx +++ b/packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/TinyMCE.tsx @@ -43,6 +43,7 @@ import useKeyboardRefocusHandler from './utils/useKeyboardRefocusHandler'; import useDocument from '../../../hooks/useDocument'; import useEditDialog from './utils/useEditDialog'; import useEditDialogEventListeners from './utils/useEditDialogEventListeners'; +import Setting from '@joplin/lib/models/Setting'; import useTextPatternsLookup from './utils/useTextPatternsLookup'; const logger = Logger.create('TinyMCE'); @@ -728,6 +729,25 @@ const TinyMCE = (props: NoteBodyEditorProps, ref: any) => { language_url: ['en_US', 'en_GB'].includes(language) ? undefined : `${bridge().vendorDir()}/lib/tinymce/langs/${language}`, toolbar: toolbar.join(' '), localization_function: _, + // See https://www.tiny.cloud/docs/tinymce/latest/tinymce-and-csp/#content_security_policy + content_security_policy: Setting.value('featureFlag.richText.useStrictContentSecurityPolicy') ? [ + // Media: *: Allow users to include images and videos from the internet (e.g. ![](http://example.com/image.png)). + // Media: blob: Allow loading images/videos/audio from blob URLs. The Rich Text Editor + // replaces certain base64 URLs with blob URLs. + // Media: data: Allow loading images and other media from data: URLs + 'default-src \'self\'', + 'img-src \'self\' blob: data: *', // Images + 'media-src \'self\' blob: data: *', // Audio and video players + + // Disallow certain unused features + 'child-src \'none\'', // Should not contain sub-frames + 'object-src \'none\'', // Objects can be used for script injection + 'form-action \'none\'', // No submitting forms + + // Styles: unsafe-inline: TinyMCE uses inline style="" styles. + // Styles: *: Allow users to include styles from the internet (e.g.