Files
Website/resources/js/editor/TipTap.js
2024-04-22 18:16:33 +10:00

160 lines
5.6 KiB
JavaScript

import Link from "@tiptap/extension-link";
import {Editor} from "@tiptap/core";
import StarterKit from "@tiptap/starter-kit";
import Highlight from "@tiptap/extension-highlight";
import TextAlign from "@tiptap/extension-text-align";
import Typography from "@tiptap/extension-typography";
import {ColorHighlighter} from "./ColourHighter.js";
import {SmileyReplacer} from "./SmileyReplacer.js";
import {Small} from "./Small.js";
import {ExtraSmall} from "./ExtraSmall.js";
import {Box} from "./Box.js";
const editorToggleLink = (editor) => {
const previousUrl = editor.getAttributes('link').href
const url = window.prompt('URL', previousUrl)
if (url === null) {
return
}
if (url === '') {
editor.chain().focus().extendMarkRange('link').unsetLink().run()
return
}
editor.chain().focus().extendMarkRange('link').setLink({ href: url }).run()
}
const CustomLink = Link.extend({
addKeyboardShortcuts() {
return {
'Mod-k': () => editorToggleLink(this.editor)
}
}
});
document.addEventListener('alpine:init', () => {
Alpine.data('editor', (content) => {
let editor // Alpine's reactive engine automatically wraps component properties in proxy objects. Attempting to use a proxied editor instance to apply a transaction will cause a "Range Error: Applying a mismatched transaction", so be sure to unwrap it using Alpine.raw(), or simply avoid storing your editor as a component property, as shown in this example.
return {
updatedAt: Date.now(), // force Alpine to rerender on selection change
content: SM.decodeHtml(content),
init() {
const _this = this
editor = new Editor({
element: this.$refs.element,
extensions: [
StarterKit,
Highlight,
CustomLink.configure({
rel: 'noopener noreferrer',
openOnClick: 'whenNotEditable',
}),
TextAlign.configure({
types: ['heading', 'paragraph', 'small', 'extraSmall'],
}),
Typography,
ColorHighlighter,
SmileyReplacer,
Small,
ExtraSmall,
Box
],
content: content,
onCreate({editor}) {
_this.updatedAt = Date.now()
},
onUpdate({editor}) {
_this.updatedAt = Date.now()
_this.content = editor.getHTML()
},
onSelectionUpdate({editor}) {
_this.updatedAt = Date.now()
}
})
},
isLoaded() {
return editor
},
isActive(type, opts = {}) {
return editor.isActive(type, opts)
},
toggleHeading(opts) {
editor.chain().toggleHeading(opts).focus().run()
},
toggleBold() {
editor.chain().toggleBold().focus().run()
},
toggleItalic() {
editor.chain().toggleItalic().focus().run()
},
toggleUnderline() {
editor.chain().toggleUnderline().focus().run()
},
toggleStrike() {
editor.chain().toggleStrike().focus().run()
},
setParagraph() {
editor.chain().setParagraph().focus().run()
},
toggleCode() {
editor.chain().toggleCode().focus().run()
},
toggleBulletList() {
editor.chain().toggleBulletList().focus().run()
},
toggleOrderedList() {
editor.chain().toggleOrderedList().focus().run()
},
toggleBlockquote() {
editor.chain().toggleBlockquote().focus().run()
},
toggleCodeBlock() {
editor.chain().toggleCodeBlock().focus().run()
},
toggleLink() {
editorToggleLink(editor)
},
clearLink() {
editor.chain().focus().extendMarkRange('link').unsetLink().run()
},
toggleHighlight() {
editor.chain().toggleHighlight().focus().run()
},
toggleSubscript() {
editor.chain().toggleSubscript().focus().run()
},
toggleSuperscript() {
editor.chain().toggleSuperscript().focus().run()
},
undo() {
editor.chain().undo().focus().run()
},
redo() {
editor.chain().redo().focus().run()
},
unsetAllMarks() {
editor.chain().focus().unsetAllMarks().run()
},
clearNotes() {
editor.chain().focus().clearNodes().run()
},
setTextAlign(value) {
editor.chain().setTextAlign(value).focus().run()
},
setSmall() {
editor.chain().focus().setSmall().run()
},
setExtraSmall() {
editor.chain().focus().setExtraSmall().run()
},
toggleBox(opts) {
editor.chain().toggleBox(opts).focus().run()
},
}
})
})