mirror of https://github.com/laurent22/joplin.git
Desktop: Upgrade to TinyMCE v6 (#11652)
parent
cbf81d1257
commit
5782ee6ba1
|
@ -8,7 +8,6 @@
|
|||
import { Node } from '@ephox/dom-globals';
|
||||
import { Arr, Option } from '@ephox/katamari';
|
||||
import { HTMLElement } from '@ephox/sand';
|
||||
import DomQuery from 'tinymce/core/api/dom/DomQuery';
|
||||
import Editor from 'tinymce/core/api/Editor';
|
||||
import Tools from 'tinymce/core/api/util/Tools';
|
||||
import * as NodeType from './NodeType';
|
||||
|
@ -49,7 +48,7 @@ const findParentListItemsNodes = function (editor, elms) {
|
|||
return parentLi ? parentLi : elm;
|
||||
});
|
||||
|
||||
return DomQuery.unique(listItemsElms);
|
||||
return [...new Set(listItemsElms)];
|
||||
};
|
||||
|
||||
const getSelectedListItems = function (editor) {
|
||||
|
@ -89,7 +88,7 @@ const getSelectedListRoots = (editor: Editor): Node[] => {
|
|||
|
||||
const getUniqueListRoots = (editor: Editor, lists: Node[]): Node[] => {
|
||||
const listRoots = Arr.map(lists, (list) => findLastParentListNode(editor, list).getOr(list));
|
||||
return DomQuery.unique(listRoots);
|
||||
return [...new Set(listRoots)];
|
||||
};
|
||||
|
||||
const isList = (editor: Editor): boolean => {
|
||||
|
|
|
@ -48,8 +48,7 @@ const listState = function (editor: Editor, listName, options:any = {}) {
|
|||
|
||||
const register = function (editor: Editor) {
|
||||
const hasPlugin = function (editor, plugin) {
|
||||
const plugins = editor.settings.plugins ? editor.settings.plugins : '';
|
||||
return Tools.inArray(plugins.split(/[ ,]/), plugin) !== -1;
|
||||
return editor.hasPlugin(plugin);
|
||||
};
|
||||
|
||||
const _ = Settings.getLocalizationFunction(editor);
|
||||
|
|
|
@ -24,7 +24,7 @@ import { themeStyle } from '@joplin/lib/theme';
|
|||
import { loadScript } from '../../../utils/loadScript';
|
||||
import bridge from '../../../../services/bridge';
|
||||
import { TinyMceEditorEvents } from './utils/types';
|
||||
import type { Editor } from 'tinymce';
|
||||
import type { Editor, EditorEvent } from 'tinymce';
|
||||
import { joplinCommandToTinyMceCommands, TinyMceCommand } from './utils/joplinCommandToTinyMceCommands';
|
||||
import shouldPasteResources from './utils/shouldPasteResources';
|
||||
import lightTheme from '@joplin/lib/themes/light';
|
||||
|
@ -412,9 +412,11 @@ const TinyMCE = (props: NoteBodyEditorProps, ref: any) => {
|
|||
element.setAttribute('id', 'tinyMceStyle');
|
||||
editorContainerDom.head.appendChild(element);
|
||||
element.appendChild(editorContainerDom.createTextNode(`
|
||||
.joplin-tinymce .tox-editor-header {
|
||||
padding-left: ${styles.leftExtraToolbarContainer.width + styles.leftExtraToolbarContainer.padding * 2}px;
|
||||
padding-right: ${styles.rightExtraToolbarContainer.width + styles.rightExtraToolbarContainer.padding * 2}px;
|
||||
.joplin-tinymce .tox-editor-header.tox-editor-header {
|
||||
margin-left: ${styles.leftExtraToolbarContainer.width + styles.leftExtraToolbarContainer.padding * 2}px;
|
||||
margin-right: ${styles.rightExtraToolbarContainer.width + styles.rightExtraToolbarContainer.padding * 2}px;
|
||||
padding: 0;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.tox .tox-toolbar,
|
||||
|
@ -434,7 +436,8 @@ const TinyMCE = (props: NoteBodyEditorProps, ref: any) => {
|
|||
}
|
||||
|
||||
.tox .tox-dialog__body-content,
|
||||
.tox .tox-collection__item {
|
||||
.tox .tox-collection__item,
|
||||
.tox .tox-insert-table-picker__label {
|
||||
color: ${theme.color};
|
||||
}
|
||||
|
||||
|
@ -473,7 +476,7 @@ const TinyMCE = (props: NoteBodyEditorProps, ref: any) => {
|
|||
*/
|
||||
|
||||
.tox .tox-dialog textarea {
|
||||
font-family: Menlo, Monaco, Consolas, "Courier New", monospace;
|
||||
font-family: Menlo, Monaco, Consolas, "Courier New", monospace !important;
|
||||
}
|
||||
|
||||
.tox .tox-dialog-wrap__backdrop {
|
||||
|
@ -498,6 +501,7 @@ const TinyMCE = (props: NoteBodyEditorProps, ref: any) => {
|
|||
.tox .tox-toolbar-label {
|
||||
color: ${theme.color3} !important;
|
||||
fill: ${theme.color3} !important;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.tox .tox-statusbar a,
|
||||
|
@ -524,6 +528,11 @@ const TinyMCE = (props: NoteBodyEditorProps, ref: any) => {
|
|||
.tox .tox-split-button:focus {
|
||||
background-color: ${theme.backgroundColor3}
|
||||
}
|
||||
|
||||
.tox .tox-tbtn:focus-visible,
|
||||
.tox .tox-split-button:focus-visible {
|
||||
background-color: ${theme.backgroundColorHover3}
|
||||
}
|
||||
|
||||
.tox .tox-tbtn:hover,
|
||||
.tox .tox-menu button:hover > svg {
|
||||
|
@ -560,6 +569,12 @@ const TinyMCE = (props: NoteBodyEditorProps, ref: any) => {
|
|||
.tox .tox-split-button:hover {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
/* Decrease the spacing between groups */
|
||||
.tox .tox-toolbar__group {
|
||||
padding-left: 7px;
|
||||
padding-right: 7px;
|
||||
}
|
||||
|
||||
.tox-tinymce,
|
||||
.tox .tox-toolbar__group,
|
||||
|
@ -628,7 +643,7 @@ const TinyMCE = (props: NoteBodyEditorProps, ref: any) => {
|
|||
|
||||
useEffect(() => {
|
||||
if (!editor) return;
|
||||
editor.setMode(props.disabled ? 'readonly' : 'design');
|
||||
editor.mode.set(props.disabled ? 'readonly' : 'design');
|
||||
}, [editor, props.disabled]);
|
||||
|
||||
// -----------------------------------------------------------------------------------------
|
||||
|
@ -675,14 +690,19 @@ const TinyMCE = (props: NoteBodyEditorProps, ref: any) => {
|
|||
const containerWindow = editorContainerDom.defaultView as any;
|
||||
const editors = await containerWindow.tinymce.init({
|
||||
selector: `#${editorContainer.id}`,
|
||||
|
||||
// Ensures that the "Premium plugins" toolbar option is disabled. See
|
||||
// https://www.tiny.cloud/docs/tinymce/latest/editor-premium-upgrade-promotion/
|
||||
promotion: false,
|
||||
width: '100%',
|
||||
body_class: 'jop-tinymce',
|
||||
height: '100%',
|
||||
resize: false,
|
||||
highlight_on_focus: false,
|
||||
icons: 'Joplin',
|
||||
icons_url: 'gui/NoteEditor/NoteBody/TinyMCE/icons.js',
|
||||
plugins: 'noneditable link joplinLists hr searchreplace codesample table',
|
||||
noneditable_noneditable_class: 'joplin-editable', // Can be a regex too
|
||||
plugins: 'link joplinLists searchreplace codesample table',
|
||||
noneditable_class: 'joplin-editable', // Can be a regex too
|
||||
iframe_aria_text: _('Rich Text editor. Press Escape then Tab to escape focus.'),
|
||||
|
||||
// #p: Pad empty paragraphs with to prevent them from being removed.
|
||||
|
@ -694,7 +714,7 @@ const TinyMCE = (props: NoteBodyEditorProps, ref: any) => {
|
|||
relative_urls: false,
|
||||
branding: false,
|
||||
statusbar: false,
|
||||
target_list: false,
|
||||
link_target_list: false,
|
||||
// Handle the first table row as table header.
|
||||
// https://www.tiny.cloud/docs/plugins/table/#table_header_type
|
||||
table_header_type: 'sectionCells',
|
||||
|
@ -704,13 +724,6 @@ const TinyMCE = (props: NoteBodyEditorProps, ref: any) => {
|
|||
contextmenu: false,
|
||||
browser_spellcheck: true,
|
||||
|
||||
// Work around an issue where images with a base64 SVG data URL would be broken.
|
||||
//
|
||||
// See https://github.com/tinymce/tinymce/issues/3864
|
||||
//
|
||||
// This was fixed in TinyMCE 6.1, so remove it when we upgrade.
|
||||
images_dataimg_filter: (img: HTMLImageElement) => !img.src.startsWith('data:'),
|
||||
|
||||
formats: {
|
||||
joplinHighlight: { inline: 'mark', remove: 'all' },
|
||||
joplinStrikethrough: { inline: 's', remove: 'all' },
|
||||
|
@ -747,14 +760,15 @@ const TinyMCE = (props: NoteBodyEditorProps, ref: any) => {
|
|||
tooltip: _('Inline Code'),
|
||||
icon: 'sourcecode',
|
||||
onAction: function() {
|
||||
editor.execCommand('mceToggleFormat', false, 'code', { class: 'inline-code' });
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
|
||||
editor.execCommand('mceToggleFormat', false, 'code', { class: 'inline-code' } as any);
|
||||
},
|
||||
onSetup: function(api) {
|
||||
api.setActive(editor.formatter.match('code'));
|
||||
const unbind = editor.formatter.formatChanged('code', api.setActive).unbind;
|
||||
const handle = editor.formatter.formatChanged('code', active => api.setActive(active));
|
||||
|
||||
return function() {
|
||||
if (unbind) unbind();
|
||||
handle?.unbind();
|
||||
};
|
||||
},
|
||||
});
|
||||
|
@ -1206,9 +1220,10 @@ const TinyMCE = (props: NoteBodyEditorProps, ref: any) => {
|
|||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
|
||||
const onSetAttrib = (event: any) => {
|
||||
const onSetAttrib = (event: EditorEvent<any>) => {
|
||||
// Dispatch onChange when a link is edited
|
||||
if (event.attrElm[0].nodeName === 'A') {
|
||||
const target = Array.isArray(event.attrElm) ? event.attrElm[0] : event.attrElm;
|
||||
if (target.nodeName === 'A') {
|
||||
if (event.attrName === 'title' || event.attrName === 'href' || event.attrName === 'rel') {
|
||||
onChangeHandler();
|
||||
}
|
||||
|
|
|
@ -886,7 +886,7 @@
|
|||
var parentLi = editor.dom.getParent(elm, 'li,dd,dt', getClosestListRootElm(editor, elm));
|
||||
return parentLi ? parentLi : elm;
|
||||
});
|
||||
return DomQuery.unique(listItemsElms);
|
||||
return [...new Set(listItemsElms)];
|
||||
};
|
||||
var getSelectedListItems = function (editor) {
|
||||
var selectedBlocks = editor.selection.getSelectedBlocks();
|
||||
|
@ -919,7 +919,7 @@
|
|||
var listRoots = map(lists, function (list) {
|
||||
return findLastParentListNode(editor, list).getOr(list);
|
||||
});
|
||||
return DomQuery.unique(listRoots);
|
||||
return [...new Set(listRoots)];
|
||||
};
|
||||
|
||||
var shouldIndentOnTab = function (editor) {
|
||||
|
@ -2119,8 +2119,7 @@
|
|||
};
|
||||
var register$1 = function (editor) {
|
||||
var hasPlugin = function (editor, plugin) {
|
||||
var plugins = editor.settings.plugins ? editor.settings.plugins : '';
|
||||
return Tools.inArray(plugins.split(/[ ,]/), plugin) !== -1;
|
||||
return editor.hasPlugin(plugin);
|
||||
};
|
||||
var _ = getLocalizationFunction(editor);
|
||||
var exec = function (command) {
|
||||
|
|
|
@ -7,6 +7,7 @@ import { Page } from '@playwright/test';
|
|||
const createScanner = (page: Page) => {
|
||||
return new AxeBuilder({ page })
|
||||
.disableRules(['page-has-heading-one'])
|
||||
// Needed because we're using Electron. See https://github.com/dequelabs/axe-core-npm/issues/1141
|
||||
.setLegacyMode(true);
|
||||
};
|
||||
|
||||
|
@ -63,6 +64,12 @@ test.describe('wcag', () => {
|
|||
await mainScreen.noteEditor.noteTitleInput.hover();
|
||||
|
||||
await expectNoViolations(mainWindow);
|
||||
|
||||
// Should not find issues with the Rich Text Editor
|
||||
await mainScreen.noteEditor.toggleEditorsButton.click();
|
||||
await mainScreen.noteEditor.richTextEditor.click();
|
||||
|
||||
await expectNoViolations(mainWindow);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -208,6 +208,6 @@
|
|||
"styled-system": "5.1.5",
|
||||
"taboverride": "4.0.3",
|
||||
"tesseract.js": "5.1.0",
|
||||
"tinymce": "5.10.6"
|
||||
"tinymce": "6.8.5"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -158,4 +158,4 @@ ldaps
|
|||
Bluesky
|
||||
Tebi
|
||||
unwatcher
|
||||
pedr
|
||||
pedr
|
||||
|
|
10
yarn.lock
10
yarn.lock
|
@ -8340,7 +8340,7 @@ __metadata:
|
|||
styled-system: 5.1.5
|
||||
taboverride: 4.0.3
|
||||
tesseract.js: 5.1.0
|
||||
tinymce: 5.10.6
|
||||
tinymce: 6.8.5
|
||||
ts-jest: 29.1.5
|
||||
ts-node: 10.9.2
|
||||
typescript: 5.4.5
|
||||
|
@ -45807,10 +45807,10 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"tinymce@npm:5.10.6":
|
||||
version: 5.10.6
|
||||
resolution: "tinymce@npm:5.10.6"
|
||||
checksum: 806cd733fde872f97d84b22ed267d2ee0404aa003d89b6c295b91867ac8b2bafc99542bf04924f253cf093c920a9da4b37a7ef73a00ff57b2b75490fb9705caf
|
||||
"tinymce@npm:6.8.5":
|
||||
version: 6.8.5
|
||||
resolution: "tinymce@npm:6.8.5"
|
||||
checksum: 7f7ad8dd2b117b8a671f97e41fc094935cfe4d4b525c90e97c6fdb480b19514e334f4360d89f34c04915a928e0cf5264fc1a60559554770452d6fce17b884940
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
|
Loading…
Reference in New Issue