From 040ca53620212d94cf102af44cbb6512e3d19b0a Mon Sep 17 00:00:00 2001 From: rhenck <richard.henck@iqb.hu-berlin.de> Date: Mon, 25 Oct 2021 17:28:17 +0200 Subject: [PATCH] [editor] TextEditor: Add extensions for list styles Before it was done with a dysfunctional hack. Now with proper extensions to existing (tiptap-node-)extensions. Also reads existing style and sets select-element accordingly. --- .../app/text-editor/bulletList-extension.ts | 51 ++++++++++++++++++ .../app/text-editor/orderedList-extension.ts | 53 +++++++++++++++++++ .../rich-text-editor.component.html | 6 ++- .../text-editor/rich-text-editor.component.ts | 18 ++++--- 4 files changed, 119 insertions(+), 9 deletions(-) create mode 100644 projects/editor/src/app/text-editor/bulletList-extension.ts create mode 100644 projects/editor/src/app/text-editor/orderedList-extension.ts diff --git a/projects/editor/src/app/text-editor/bulletList-extension.ts b/projects/editor/src/app/text-editor/bulletList-extension.ts new file mode 100644 index 000000000..27b866053 --- /dev/null +++ b/projects/editor/src/app/text-editor/bulletList-extension.ts @@ -0,0 +1,51 @@ +import { Command } from '@tiptap/core'; +import { Transaction } from 'prosemirror-state'; +import { BulletList } from '@tiptap/extension-bullet-list'; + +declare module '@tiptap/core' { + interface Commands<ReturnType> { + bulletListExtension: { + setBulletListStyle: (newStyle: string) => ReturnType; + }; + } +} + +export const bulletListExtension = BulletList.extend({ + addAttributes() { + return { + listStyle: { + default: 'disc', + parseHTML: element => element.style.listStyleType, + renderHTML: attributes => ({ + style: `list-style: ${attributes.listStyle};` + }) + } + }; + }, + + addCommands() { + const setNodeIndentMarkup = (tr: Transaction, pos: number, newStyle: string): Transaction => { + const node = tr?.doc?.nodeAt(pos); + if (node) { + const nodeAttrs = { ...node.attrs, listStyle: newStyle }; + return tr.setNodeMarkup(pos, node.type, nodeAttrs, node.marks); + } + return tr; + }; + + const applyListStyle: (newStyle: string) => () => Command = + newStyle => () => ({ tr, state, dispatch }) => { + const { selection } = state; + let transaction; + tr.doc.nodesBetween(selection.from, selection.to, (node, pos) => { + transaction = setNodeIndentMarkup(tr, pos, newStyle); + }); + dispatch?.(transaction); + return true; + }; + + return { + setBulletListStyle: (newStyle: string) => applyListStyle(newStyle)() + }; + } +}); diff --git a/projects/editor/src/app/text-editor/orderedList-extension.ts b/projects/editor/src/app/text-editor/orderedList-extension.ts new file mode 100644 index 000000000..fccac3710 --- /dev/null +++ b/projects/editor/src/app/text-editor/orderedList-extension.ts @@ -0,0 +1,53 @@ +import { Command } from '@tiptap/core'; +import { Transaction } from 'prosemirror-state'; +import { OrderedList } from '@tiptap/extension-ordered-list'; + +declare module '@tiptap/core' { + interface Commands<ReturnType> { + orderedListExtension: { + setOrderedListStyle: (newStyle: string) => ReturnType; + }; + } +} + +export const orderedListExtension = OrderedList.extend({ + addAttributes() { + return { + listStyle: { + default: 'decimal', + parseHTML: element => { + return element.style.listStyleType; + }, + renderHTML: attributes => ({ + style: `list-style: ${attributes.listStyle};` + }) + } + }; + }, + + addCommands() { + const setNodeIndentMarkup = (tr: Transaction, pos: number, newStyle: string): Transaction => { + const node = tr?.doc?.nodeAt(pos); + if (node) { + const nodeAttrs = { ...node.attrs, listStyle: newStyle }; + return tr.setNodeMarkup(pos, node.type, nodeAttrs, node.marks); + } + return tr; + }; + + const applyListStyle: (newStyle: string) => () => Command = + newStyle => () => ({ tr, state, dispatch }) => { + const { selection } = state; + let transaction; + tr.doc.nodesBetween(selection.from, selection.to, (node, pos) => { + transaction = setNodeIndentMarkup(tr, pos, newStyle); + }); + dispatch?.(transaction); + return true; + }; + + return { + setOrderedListStyle: (newStyle: string) => applyListStyle(newStyle)() + }; + } +}); diff --git a/projects/editor/src/app/text-editor/rich-text-editor.component.html b/projects/editor/src/app/text-editor/rich-text-editor.component.html index 6dc31b514..5f38c4108 100644 --- a/projects/editor/src/app/text-editor/rich-text-editor.component.html +++ b/projects/editor/src/app/text-editor/rich-text-editor.component.html @@ -160,7 +160,8 @@ <mat-menu #optionsMenu="matMenu"> <mat-form-field> <mat-label>Aufzählungszeichen</mat-label> - <mat-select [value]="'disc'" (click)="$any($event).stopPropagation()" + <mat-select [value]="editor.getAttributes('bulletList').listStyle" + (click)="$any($event).stopPropagation()" (valueChange)="applyListStyle('bulletList', $event)"> <mat-option value="disc">disc</mat-option> <mat-option value="circle">circle</mat-option> @@ -169,7 +170,8 @@ </mat-form-field> <mat-form-field> <mat-label>Aufzählungsnummerierung</mat-label> - <mat-select [value]="'decimal'" (click)="$any($event).stopPropagation()" + <mat-select [value]="editor.getAttributes('orderedList').listStyle" + (click)="$any($event).stopPropagation()" (valueChange)="applyListStyle('orderedList', $event)"> <mat-option value="decimal">decimal</mat-option> <mat-option value="lower-latin">lower-latin</mat-option> diff --git a/projects/editor/src/app/text-editor/rich-text-editor.component.ts b/projects/editor/src/app/text-editor/rich-text-editor.component.ts index 80f33a8ab..7bd795972 100644 --- a/projects/editor/src/app/text-editor/rich-text-editor.component.ts +++ b/projects/editor/src/app/text-editor/rich-text-editor.component.ts @@ -2,7 +2,7 @@ import { Component, EventEmitter, Input, Output, ViewEncapsulation, AfterViewInit } from '@angular/core'; -import { Editor, Extension } from '@tiptap/core'; +import { Editor } from '@tiptap/core'; import StarterKit from '@tiptap/starter-kit'; import { Underline } from '@tiptap/extension-underline'; import { Superscript } from '@tiptap/extension-superscript'; @@ -15,6 +15,8 @@ import { Heading } from '@tiptap/extension-heading'; import { Indent } from './indent'; import { customParagraph } from './paragraph-extension'; import { fontSizeExtension } from './font-size-extension'; +import { bulletListExtension } from './bulletList-extension'; +import { orderedListExtension } from './orderedList-extension'; @Component({ selector: 'app-rich-text-editor', @@ -45,7 +47,9 @@ export class RichTextEditorComponent implements AfterViewInit { levels: [1, 2, 3, 4] }), customParagraph, - fontSizeExtension + fontSizeExtension, + bulletListExtension, + orderedListExtension ] }); @@ -110,11 +114,11 @@ export class RichTextEditorComponent implements AfterViewInit { } applyListStyle(listType: string, style: string): void { - (this.editor.extensionManager.extensions - .filter(ext => ext.name === listType)[0] as Extension).options.HTMLAttributes = - { - style: `list-style-type:${style}` - }; + if (listType === 'bulletList') { + this.editor.commands.setBulletListStyle(style); + } else { + this.editor.commands.setOrderedListStyle(style); + } } toggleHeading(level?: string): void { -- GitLab