You've already forked joplin
mirror of
https://github.com/laurent22/joplin.git
synced 2025-12-20 23:30:05 +02:00
Mobile: Rich Text Editor: Add button for creating tables (#13645)
This commit is contained in:
@@ -1145,6 +1145,7 @@ packages/editor/ProseMirror/utils/dom/showModal.js
|
||||
packages/editor/ProseMirror/utils/extractSelectedLinesTo.test.js
|
||||
packages/editor/ProseMirror/utils/extractSelectedLinesTo.js
|
||||
packages/editor/ProseMirror/utils/forEachHeading.js
|
||||
packages/editor/ProseMirror/utils/insertRenderedMarkdown.js
|
||||
packages/editor/ProseMirror/utils/jumpToHash.js
|
||||
packages/editor/ProseMirror/utils/makeLinksClickableInElement.js
|
||||
packages/editor/ProseMirror/utils/postprocessEditorOutput.test.js
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1117,6 +1117,7 @@ packages/editor/ProseMirror/utils/dom/showModal.js
|
||||
packages/editor/ProseMirror/utils/extractSelectedLinesTo.test.js
|
||||
packages/editor/ProseMirror/utils/extractSelectedLinesTo.js
|
||||
packages/editor/ProseMirror/utils/forEachHeading.js
|
||||
packages/editor/ProseMirror/utils/insertRenderedMarkdown.js
|
||||
packages/editor/ProseMirror/utils/jumpToHash.js
|
||||
packages/editor/ProseMirror/utils/makeLinksClickableInElement.js
|
||||
packages/editor/ProseMirror/utils/postprocessEditorOutput.test.js
|
||||
|
||||
@@ -20,6 +20,8 @@ const builtInCommandNames = [
|
||||
EditorCommandType.ToggleBulletedList,
|
||||
EditorCommandType.ToggleCheckList,
|
||||
'-',
|
||||
`editor.${EditorCommandType.InsertTable}`,
|
||||
'-',
|
||||
EditorCommandType.IndentLess,
|
||||
EditorCommandType.IndentMore,
|
||||
`editor.${EditorCommandType.SwapLineDown}`,
|
||||
|
||||
@@ -9,6 +9,12 @@ const markdownEditorOnlyCommands = [
|
||||
EditorCommandType.SwapLineDown,
|
||||
].map(command => `editor.${command}`);
|
||||
|
||||
|
||||
|
||||
const richTextEditorOnlyCommands = [
|
||||
EditorCommandType.InsertTable,
|
||||
].map(command => `editor.${command}`);
|
||||
|
||||
export const visibleCondition = (commandName: string) => {
|
||||
const output = [];
|
||||
|
||||
@@ -16,6 +22,10 @@ export const visibleCondition = (commandName: string) => {
|
||||
output.push('!richTextEditorVisible');
|
||||
}
|
||||
|
||||
if (richTextEditorOnlyCommands.includes(commandName)) {
|
||||
output.push('!markdownEditorPaneVisible');
|
||||
}
|
||||
|
||||
return output.join(' && ');
|
||||
};
|
||||
|
||||
@@ -102,6 +112,11 @@ const declarations: CommandDeclaration[] = [
|
||||
label: () => _('Task list'),
|
||||
iconName: 'material format-list-checks',
|
||||
},
|
||||
{
|
||||
name: `editor.${EditorCommandType.InsertTable}`,
|
||||
label: () => _('Table'),
|
||||
iconName: 'material table',
|
||||
},
|
||||
{
|
||||
name: EditorCommandType.IndentLess,
|
||||
label: () => _('Decrease indent level'),
|
||||
|
||||
@@ -45,6 +45,15 @@ const editorCommands: Record<EditorCommandType, EditorCommandFunction> = {
|
||||
[EditorCommandType.ToggleHeading4]: toggleHeaderLevel(4),
|
||||
[EditorCommandType.ToggleHeading5]: toggleHeaderLevel(5),
|
||||
[EditorCommandType.InsertHorizontalRule]: insertHorizontalRule,
|
||||
[EditorCommandType.InsertTable]: editor => {
|
||||
replaceSelectionCommand(editor, [
|
||||
'',
|
||||
'| | |',
|
||||
'|----|----|',
|
||||
'| | |',
|
||||
'',
|
||||
].join('\n'));
|
||||
},
|
||||
|
||||
[EditorCommandType.ScrollSelectionIntoView]: editor => {
|
||||
editor.dispatch(editor.state.update({
|
||||
|
||||
@@ -77,4 +77,20 @@ describe('ProseMirror/commands', () => {
|
||||
expect(jumpToHash('test-heading-2')).toBe(true);
|
||||
expect(editor.state.selection.$anchor.parent.textContent).toBe('Test heading 2');
|
||||
});
|
||||
|
||||
test('textTable should insert a table', () => {
|
||||
const editor = createTestEditor({ html: '<p></p>' });
|
||||
|
||||
commands[EditorCommandType.InsertTable](editor.state, editor.dispatch, editor);
|
||||
|
||||
expect(editor.state.doc.toJSON()).toMatchObject({
|
||||
content: [{
|
||||
content: [
|
||||
{ type: 'table_row' },
|
||||
{ type: 'table_row' },
|
||||
],
|
||||
type: 'table',
|
||||
}],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -12,8 +12,9 @@ import { EditorEventType } from '../../events';
|
||||
import extractSelectedLinesTo from '../utils/extractSelectedLinesTo';
|
||||
import { EditorView } from 'prosemirror-view';
|
||||
import jumpToHash from '../utils/jumpToHash';
|
||||
import canReplaceSelectionWith from '../utils/canReplaceSelectionWith';
|
||||
import focusEditor from './focusEditor';
|
||||
import insertRenderedMarkdown from '../utils/insertRenderedMarkdown';
|
||||
import canReplaceSelectionWith from '../utils/canReplaceSelectionWith';
|
||||
|
||||
type Dispatch = (tr: Transaction)=> void;
|
||||
type ExtendedCommand = (state: EditorState, dispatch: Dispatch, view?: EditorView, options?: string[])=> boolean;
|
||||
@@ -74,7 +75,6 @@ const toggleCode: Command = (state, dispatch, view) => {
|
||||
return toggleMark(schema.marks.code)(state, dispatch, view) || setBlockType(schema.nodes.paragraph)(state, dispatch, view);
|
||||
};
|
||||
|
||||
|
||||
const listItemTypes = [schema.nodes.list_item, schema.nodes.task_list_item];
|
||||
|
||||
const commands: Record<EditorCommandType, ExtendedCommand|null> = {
|
||||
@@ -86,24 +86,17 @@ const commands: Record<EditorCommandType, ExtendedCommand|null> = {
|
||||
[EditorCommandType.ToggleItalicized]: toggleMark(schema.marks.emphasis),
|
||||
[EditorCommandType.ToggleCode]: toggleCode,
|
||||
[EditorCommandType.ToggleMath]: (state, _dispatch, view) => {
|
||||
const renderer = getEditorApi(state).renderer;
|
||||
const selectedText = state.doc.textBetween(state.selection.from, state.selection.to);
|
||||
|
||||
const block = selectedText.includes('\n');
|
||||
const nodeType = block ? schema.nodes.joplinEditableBlock : schema.nodes.joplinEditableInline;
|
||||
|
||||
if (canReplaceSelectionWith(state.selection, nodeType)) {
|
||||
void (async () => {
|
||||
const separator = block ? '$$' : '$';
|
||||
const rendered = await renderer.renderMarkupToHtml(`${separator}${selectedText}${separator}`, {
|
||||
forceMarkdown: true,
|
||||
isFullPageRender: false,
|
||||
});
|
||||
|
||||
if (view) {
|
||||
view.pasteHTML(rendered.html);
|
||||
const separator = block ? '$$' : '$';
|
||||
void insertRenderedMarkdown(view,
|
||||
`${separator}${selectedText}${separator}`,
|
||||
);
|
||||
}
|
||||
})();
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -121,6 +114,29 @@ const commands: Record<EditorCommandType, ExtendedCommand|null> = {
|
||||
[EditorCommandType.ToggleHeading4]: toggleHeading(4),
|
||||
[EditorCommandType.ToggleHeading5]: toggleHeading(5),
|
||||
[EditorCommandType.InsertHorizontalRule]: null,
|
||||
[EditorCommandType.InsertTable]: (state, dispatch, view) => {
|
||||
if (view) {
|
||||
// See https://github.com/ProseMirror/prosemirror-tables/issues/91
|
||||
const tr = state.tr.replaceSelectionWith(
|
||||
schema.nodes.table.create(null, [
|
||||
schema.nodes.table_row.create(null, [
|
||||
schema.nodes.table_header.createAndFill(),
|
||||
schema.nodes.table_header.createAndFill(),
|
||||
]),
|
||||
schema.nodes.table_row.create(null, [
|
||||
schema.nodes.table_cell.createAndFill(),
|
||||
schema.nodes.table_cell.createAndFill(),
|
||||
]),
|
||||
]),
|
||||
);
|
||||
|
||||
if (dispatch) {
|
||||
dispatch(tr);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
[EditorCommandType.ToggleSearch]: (state, dispatch, view) => {
|
||||
const command = setSearchVisible(!getSearchVisible(state));
|
||||
return command(state, dispatch, view);
|
||||
|
||||
17
packages/editor/ProseMirror/utils/insertRenderedMarkdown.ts
Normal file
17
packages/editor/ProseMirror/utils/insertRenderedMarkdown.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import { EditorView } from 'prosemirror-view';
|
||||
import { getEditorApi } from '../plugins/joplinEditorApiPlugin';
|
||||
|
||||
const insertRenderedMarkdown = async (
|
||||
view: EditorView,
|
||||
markdown: string,
|
||||
) => {
|
||||
const renderer = getEditorApi(view.state).renderer;
|
||||
|
||||
const rendered = await renderer.renderMarkupToHtml(markdown, {
|
||||
forceMarkdown: true,
|
||||
isFullPageRender: false,
|
||||
});
|
||||
view.pasteHTML(rendered.html);
|
||||
};
|
||||
|
||||
export default insertRenderedMarkdown;
|
||||
@@ -30,6 +30,7 @@ export enum EditorCommandType {
|
||||
ToggleHeading5 = 'textHeading5',
|
||||
|
||||
InsertHorizontalRule = 'textHorizontalRule',
|
||||
InsertTable = 'textTable',
|
||||
|
||||
// Find commands
|
||||
ToggleSearch = 'textSearch',
|
||||
|
||||
Reference in New Issue
Block a user