Merge branch 'main' into feature/new-highlight-extension

# Conflicts:
#	packages/core/src/commands/toggleMark.ts
This commit is contained in:
Hans Pagel
2020-10-27 20:36:22 +01:00
164 changed files with 4827 additions and 2779 deletions

View File

@@ -1,6 +1,5 @@
<template>
<div>
BUG: Headings cant be transformed to a bullet or ordered list.
<div v-if="editor">
<button @click="editor.chain().focus().bold().run()" :class="{ 'is-active': editor.isActive('bold') }">
bold
@@ -89,25 +88,24 @@ export default {
Hi there,
</h2>
<p>
this is a basic <em>basic</em> example of <strong>tiptap</strong>. Sure, there are all kind of basic text styles youd probably expect from a text editor. But wait until you see the bullet lists:
this is a basic <em>basic</em> example of <strong>tiptap</strong>. Sure, there are all kind of basic text styles youd probably expect from a text editor. But wait until you see the lists:
</p>
<ul>
<li>
With one …
Thats a bullet list with one …
</li>
<li>
… or two list items.
</li>
<li>
And yes, even more.
</li>
</ul>
<p>
Isnt that great? But wait, theres more. Lets try a code block:
Isnt that great? And all of that is editable. But wait, theres more. Lets try a code block:
</p>
<pre><code class="language-css">body { display: none; }</code></pre>
<pre><code class="language-css">body {
display: none;
}</code></pre>
<p>
I know, I know, its impressive. Give it a try and click a little bit around. But dont forget to check the other examples too.
I know, I know, this is impressive. Its only the tip of the iceberg though. Give it a try and click a little bit around. Dont forget to check the other examples too.
</p>
<blockquote>
Wow, thats amazing. Good work, boy! 👏

View File

@@ -11,7 +11,7 @@ context('/examples/export-html-or-json', () => {
it('should return json', () => {
cy.get('.ProseMirror').then(([{ editor }]) => {
const json = editor.json()
const json = editor.getJSON()
expect(json).to.deep.equal({
type: 'document',
@@ -32,7 +32,7 @@ context('/examples/export-html-or-json', () => {
it('should return html', () => {
cy.get('.ProseMirror').then(([{ editor }]) => {
const html = editor.html()
const html = editor.getHTML()
expect(html).to.equal('<p>Example Text</p>')
})

View File

@@ -1,12 +1,12 @@
<template>
<div>
<div class="actions">
<button class="button" @click="clearContent">
Clear Content
</button>
<button class="button" @click="setContent">
Set Content
</button>
<button class="button" @click="clearContent">
Clear Content
</button>
</div>
<editor-content :editor="editor" />
@@ -50,22 +50,17 @@ export default {
})
// Get the initial content …
this.json = this.editor.json()
this.html = this.editor.html()
this.json = this.editor.getJSON()
this.html = this.editor.getHTML()
// … and get the content after every change.
this.editor.on('update', () => {
this.json = this.editor.json()
this.html = this.editor.html()
this.json = this.editor.getJSON()
this.html = this.editor.getHTML()
})
},
methods: {
clearContent() {
this.editor.clearContent(true)
this.editor.focus()
},
setContent() {
// You can pass a JSON document …
this.editor.setContent({
@@ -87,6 +82,11 @@ export default {
// Its likely that youd like to focus the Editor after most commands.
this.editor.focus()
},
clearContent() {
this.editor.clearContent(true)
this.editor.focus()
},
},
beforeDestroy() {

View File

@@ -4,10 +4,6 @@ context('/examples/focus', () => {
})
it('should have class', () => {
cy.get('.ProseMirror').then(([{ editor }]) => {
editor.focus('start')
cy.get('.ProseMirror p:first').should('have.class', 'has-focus')
})
cy.get('.ProseMirror p:first').should('have.class', 'has-focus')
})
})

View File

@@ -1,5 +1,5 @@
<template>
<div class="editor">
<div>
<editor-content :editor="editor" />
</div>
</template>
@@ -10,6 +10,8 @@ import Document from '@tiptap/extension-document'
import Paragraph from '@tiptap/extension-paragraph'
import Text from '@tiptap/extension-text'
import Code from '@tiptap/extension-code'
import BulletList from '@tiptap/extension-bullet-list'
import ListItem from '@tiptap/extension-list-item'
import Focus from '@tiptap/extension-focus'
export default {
@@ -30,6 +32,8 @@ export default {
Paragraph(),
Text(),
Code(),
BulletList(),
ListItem(),
Focus({
className: 'has-focus',
nested: true,
@@ -38,12 +42,11 @@ export default {
autoFocus: true,
content: `
<p>
The focus extension adds custom classes to focused nodes. By default, itll add a <code>has-focus</code> class, even to nested nodes:
The focus extension adds a class to the focused node only. That enables you to add a custom styling to just that node. By default, itll add <code>.has-focus</code>, even to nested nodes.
</p>
<pre><code>{ className: 'has-focus', nested: true }</code></pre>
<ul>
<li>With <code>nested: true</code> nested elements like this list item will be focused.</li>
<li>Otherwise the whole list will get the focus class, even if only a single list item is selected.</li>
<li>Nested elements (like this list item) will be focused with the default setting of <code>nested: true</code>.</li>
<li>Otherwise the whole list will get the focus class, even when just a single list item is selected.</li>
</ul>
`,
})

View File

@@ -39,10 +39,13 @@ export default {
],
content: `
<p>
Wow, this editor has support for links to the whole <a href="https://en.wikipedia.org/wiki/World_Wide_Web" target="_self">world wide web</a>. We tested a lot of URLs and I think you can add *every URL* you want. Isnt that cool? Lets try <a href="https://statamic.com/" target="_self">another one!</a> Yep, seems to work.
Wow, this editor has support for links to the whole <a href="https://en.wikipedia.org/wiki/World_Wide_Web">world wide web</a>. We tested a lot of URLs and I think you can add *every URL* you want. Isnt that cool? Lets try <a href="https://statamic.com/">another one!</a> Yep, seems to work.
</p>
<p>
By default every link will get a \`rel="noopener noreferrer nofollow"\` attribute. Its configurable though.
By default every link will get a [rel="noopener noreferrer nofollow"] attribute <a href="https://web.dev/external-anchors-use-rel-noopener/">for security reasons</a>. Its configurable though.
</p>
<p>
Ah, and links open in a new tab by default, but thats also - yes, youve guessed it - configurable.
</p>
`,
})

View File

@@ -21,19 +21,19 @@ export default {
mounted() {
this.editor = new Editor({
content: `
<p>
This is a radically reduced version of tiptap. It has only support for a document, paragraphs and text. Thats it. Its probably too much for real minimalists though.
</p>
<p>
The paragraph extension is not literally required, but you need at least one node. That node can be something different, for example to render a task list and only that task list.
</p>
`,
extensions: [
Document(),
Paragraph(),
Text(),
],
content: `
<p>
This is a radically reduced version of tiptap. It has only support for a document, paragraphs and text. Thats it. Its probably too much for real minimalists though.
</p>
<p>
The paragraph extension is not really required, but you need at least one node. Sure, that node can be something different. Youll mostly likely want to add a paragraph though.
</p>
`,
})
},

View File

@@ -28,7 +28,10 @@ export default {
editable: this.editable,
content: `
<p>
This text is <strong>read-only</strong>. You are not able to edit something. <a href="https://ueber.io/">Links to fancy websites</a> are still working.
This text is <strong>read-only</strong>. No matter what you try, you are not able to edit something. Okay, if you toggle the checkbox above youll be able to edit the text.
</p>
<p>
If you want to check the state, you can call <code>editor.isEditable()</code>.
</p>
`,
extensions: defaultExtensions(),
@@ -60,5 +63,6 @@ export default {
[contenteditable=false] {
color: #999;
cursor: not-allowed;
}
</style>

View File

@@ -10,6 +10,20 @@ context('/api/extensions/blockquote', () => {
})
})
it('should parse blockquote tags correctly', () => {
cy.get('.ProseMirror').then(([{ editor }]) => {
editor.setContent('<blockquote><p>Example Text</p></blockquote>')
expect(editor.getHTML()).to.eq('<blockquote><p>Example Text</p></blockquote>')
})
})
it('should parse blockquote tags without paragraphs correctly', () => {
cy.get('.ProseMirror').then(([{ editor }]) => {
editor.setContent('<blockquote>Example Text</blockquote>')
expect(editor.getHTML()).to.eq('<blockquote><p>Example Text</p></blockquote>')
})
})
it('the button should make the selected line a blockquote', () => {
cy.get('.ProseMirror blockquote')
.should('not.exist')

View File

@@ -10,6 +10,36 @@ context('/api/extensions/bold', () => {
})
})
it('should transform b tags to strong tags', () => {
cy.get('.ProseMirror').then(([{ editor }]) => {
editor.setContent('<p><b>Example Text</b></p>')
expect(editor.getHTML()).to.eq('<p><strong>Example Text</strong></p>')
})
})
it('sould omit b tags with normal font weight inline style', () => {
cy.get('.ProseMirror').then(([{ editor }]) => {
editor.setContent('<p><b style="font-weight: normal">Example Text</b></p>')
expect(editor.getHTML()).to.eq('<p>Example Text</p>')
})
})
it('should transform any tag with bold inline style to strong tags', () => {
cy.get('.ProseMirror').then(([{ editor }]) => {
editor.setContent('<p><span style="font-weight: bold">Example Text</span></p>')
expect(editor.getHTML()).to.eq('<p><strong>Example Text</strong></p>')
editor.setContent('<p><span style="font-weight: bolder">Example Text</span></p>')
expect(editor.getHTML()).to.eq('<p><strong>Example Text</strong></p>')
editor.setContent('<p><span style="font-weight: 500">Example Text</span></p>')
expect(editor.getHTML()).to.eq('<p><strong>Example Text</strong></p>')
editor.setContent('<p><span style="font-weight: 900">Example Text</span></p>')
expect(editor.getHTML()).to.eq('<p><strong>Example Text</strong></p>')
})
})
it('the button should make the selected text bold', () => {
cy.get('.demo__preview button:first')
.click()

View File

@@ -10,6 +10,20 @@ context('/api/extensions/bullet-list', () => {
})
})
it('should parse unordered lists correctly', () => {
cy.get('.ProseMirror').then(([{ editor }]) => {
editor.setContent('<ul><li><p>Example Text</p></li></ul>')
expect(editor.getHTML()).to.eq('<ul><li><p>Example Text</p></li></ul>')
})
})
it('should parse unordered lists without paragraphs correctly', () => {
cy.get('.ProseMirror').then(([{ editor }]) => {
editor.setContent('<ul><li>Example Text</li></ul>')
expect(editor.getHTML()).to.eq('<ul><li><p>Example Text</p></li></ul>')
})
})
it('the button should make the selected line a bullet list item', () => {
cy.get('.ProseMirror ul')
.should('not.exist')

View File

@@ -10,6 +10,16 @@ context('/api/extensions/code', () => {
})
})
it('should parse code tags correctly', () => {
cy.get('.ProseMirror').then(([{ editor }]) => {
editor.setContent('<p><code>Example Text</code></p>')
expect(editor.getHTML()).to.eq('<p><code>Example Text</code></p>')
editor.setContent('<code>Example Text</code>')
expect(editor.getHTML()).to.eq('<p><code>Example Text</code></p>')
})
})
it('should mark the selected text as inline code', () => {
cy.get('.demo__preview button:first')
.click()
@@ -32,4 +42,11 @@ context('/api/extensions/code', () => {
cy.get('.ProseMirror code')
.should('not.exist')
})
it('should make inline code from the markdown shortcut', () => {
cy.get('.ProseMirror')
.type('`Example`')
.find('code')
.should('contain', 'Example')
})
})

View File

@@ -10,6 +10,20 @@ context('/api/extensions/code-block', () => {
})
})
it('should parse code blocks correctly', () => {
cy.get('.ProseMirror').then(([{ editor }]) => {
editor.setContent('<pre><code>Example Text</code></pre>')
expect(editor.getHTML()).to.eq('<pre><code>Example Text</code></pre>')
})
})
it('should parse code blocks with language correctly', () => {
cy.get('.ProseMirror').then(([{ editor }]) => {
editor.setContent('<pre><code class="language-css">Example Text</code></pre>')
expect(editor.getHTML()).to.eq('<pre><code class="language-css">Example Text</code></pre>')
})
})
it('the button should make the selected line a code block', () => {
cy.get('.demo__preview button:first')
.click()
@@ -39,36 +53,25 @@ context('/api/extensions/code-block', () => {
it('the keyboard shortcut should make the selected line a code block', () => {
cy.get('.ProseMirror')
.trigger('keydown', { shiftKey: true, ctrlKey: true, key: '\\' })
.trigger('keydown', { shiftKey: true, modKey: true, key: 'c' })
.find('pre')
.should('contain', 'Example Text')
})
it('the keyboard shortcut should toggle the code block', () => {
cy.get('.ProseMirror')
.trigger('keydown', { shiftKey: true, ctrlKey: true, key: '\\' })
.trigger('keydown', { shiftKey: true, modKey: true, key: 'c' })
.find('pre')
.should('contain', 'Example Text')
cy.get('.ProseMirror')
.type('{selectall}')
.trigger('keydown', { shiftKey: true, ctrlKey: true, key: '\\' })
.trigger('keydown', { shiftKey: true, modKey: true, key: 'c' })
cy.get('.ProseMirror pre')
.should('not.exist')
})
it('should make a code block from markdown shortcuts', () => {
cy.get('.ProseMirror').then(([{ editor }]) => {
editor.clearContent()
cy.get('.ProseMirror')
.type('``` Code')
.find('pre>code')
.should('contain', 'Code')
})
})
it('should parse the language from a HTML code block', () => {
cy.get('.ProseMirror').then(([{ editor }]) => {
editor.setContent('<pre><code class="language-css">body { display: none; }</code></pre>')
@@ -79,7 +82,29 @@ context('/api/extensions/code-block', () => {
})
})
it('should make a code block for js', () => {
it('should make a code block from backtick markdown shortcuts', () => {
cy.get('.ProseMirror').then(([{ editor }]) => {
editor.clearContent()
cy.get('.ProseMirror')
.type('``` Code')
.find('pre>code')
.should('contain', 'Code')
})
})
it('should make a code block from tilde markdown shortcuts', () => {
cy.get('.ProseMirror').then(([{ editor }]) => {
editor.clearContent()
cy.get('.ProseMirror')
.type('~~~ Code')
.find('pre>code')
.should('contain', 'Code')
})
})
it('should make a code block for js with backticks', () => {
cy.get('.ProseMirror').then(([{ editor }]) => {
editor.clearContent()
@@ -89,4 +114,15 @@ context('/api/extensions/code-block', () => {
.should('contain', 'Code')
})
})
it('should make a code block for js with tildes', () => {
cy.get('.ProseMirror').then(([{ editor }]) => {
editor.clearContent()
cy.get('.ProseMirror')
.type('~~~js Code')
.find('pre>code.language-js')
.should('contain', 'Code')
})
})
})

View File

@@ -2,4 +2,25 @@ context('/api/extensions/document', () => {
before(() => {
cy.visit('/api/extensions/document')
})
beforeEach(() => {
cy.get('.ProseMirror').then(([{ editor }]) => {
editor.setContent('<p></p>')
})
})
it('should return the document in as json', () => {
cy.get('.ProseMirror').then(([{ editor }]) => {
const json = editor.getJSON()
expect(json).to.deep.equal({
type: 'document',
content: [
{
type: 'paragraph',
},
],
})
})
})
})

View File

@@ -9,6 +9,20 @@ context('/api/extensions/hard-break', () => {
})
})
it('should parse hard breaks correctly', () => {
cy.get('.ProseMirror').then(([{ editor }]) => {
editor.setContent('<p>Example<br>Text</p>')
expect(editor.getHTML()).to.eq('<p>Example<br>Text</p>')
})
})
it('should parse hard breaks with self-closing tag correctly', () => {
cy.get('.ProseMirror').then(([{ editor }]) => {
editor.setContent('<p>Example<br />Text</p>')
expect(editor.getHTML()).to.eq('<p>Example<br>Text</p>')
})
})
it('the button should add a line break', () => {
cy.get('.ProseMirror br')
.should('not.exist')
@@ -20,7 +34,7 @@ context('/api/extensions/hard-break', () => {
.should('exist')
})
it('the default keyboard shortcut should add a line break', () => {
it.skip('the default keyboard shortcut should add a line break', () => {
cy.get('.ProseMirror br')
.should('not.exist')

View File

@@ -10,6 +10,28 @@ context('/api/extensions/heading', () => {
})
})
const headings = [
'<h1>Example Text</h1>',
'<h2>Example Text</h2>',
'<h3>Example Text</h3>',
]
headings.forEach(html => {
it(`should parse headings correctly (${html})`, () => {
cy.get('.ProseMirror').then(([{ editor }]) => {
editor.setContent(html)
expect(editor.getHTML()).to.eq(html)
})
})
})
it('should omit disabled heading levels', () => {
cy.get('.ProseMirror').then(([{ editor }]) => {
editor.setContent('<h4>Example Text</h4>')
expect(editor.getHTML()).to.eq('<p>Example Text</p>')
})
})
it('the button should make the selected line a h1', () => {
cy.get('.ProseMirror h1')
.should('not.exist')

View File

@@ -9,6 +9,20 @@ context('/api/extensions/horizontal-rule', () => {
})
})
it('should parse horizontal rules correctly', () => {
cy.get('.ProseMirror').then(([{ editor }]) => {
editor.setContent('<p>Example Text</p><hr>')
expect(editor.getHTML()).to.eq('<p>Example Text</p><hr>')
})
})
it('should parse horizontal rules with self-closing tag correctly', () => {
cy.get('.ProseMirror').then(([{ editor }]) => {
editor.setContent('<p>Example Text</p><hr />')
expect(editor.getHTML()).to.eq('<p>Example Text</p><hr>')
})
})
it('the button should add a horizontal rule', () => {
cy.get('.ProseMirror hr')
.should('not.exist')

View File

@@ -0,0 +1,45 @@
<template>
<div v-if="editor">
<editor-content :editor="editor" />
</div>
</template>
<script>
import { Editor } from '@tiptap/core'
import { EditorContent } from '@tiptap/vue'
import Document from '@tiptap/extension-document'
import Paragraph from '@tiptap/extension-paragraph'
import Text from '@tiptap/extension-text'
import Image from '@tiptap/extension-image'
export default {
components: {
EditorContent,
},
data() {
return {
editor: null,
}
},
mounted() {
this.editor = new Editor({
extensions: [
Document(),
Paragraph(),
Text(),
Image(),
],
content: `
<p>This is basic example of implementing images. Try to drop new images here. Reordering also works.</p>
<img src="https://66.media.tumblr.com/dcd3d24b79d78a3ee0f9192246e727f1/tumblr_o00xgqMhPM1qak053o1_400.gif" />
`,
})
},
beforeDestroy() {
this.editor.destroy()
},
}
</script>

View File

@@ -10,6 +10,27 @@ context('/api/extensions/italic', () => {
})
})
it('i tags should be transformed to em tags', () => {
cy.get('.ProseMirror').then(([{ editor }]) => {
editor.setContent('<p><i>Example Text</i></p>')
expect(editor.getHTML()).to.eq('<p><em>Example Text</em></p>')
})
})
it('i tags with normal font style should be omitted', () => {
cy.get('.ProseMirror').then(([{ editor }]) => {
editor.setContent('<p><i style="font-style: normal">Example Text</i></p>')
expect(editor.getHTML()).to.eq('<p>Example Text</p>')
})
})
it('generic tags with italic style should be transformed to strong tags', () => {
cy.get('.ProseMirror').then(([{ editor }]) => {
editor.setContent('<p><span style="font-style: italic">Example Text</span></p>')
expect(editor.getHTML()).to.eq('<p><em>Example Text</em></p>')
})
})
it('the button should make the selected text italic', () => {
cy.get('.demo__preview button:first')
.click()

View File

@@ -10,6 +10,27 @@ context('/api/extensions/link', () => {
})
})
it('should parse a tags correctly', () => {
cy.get('.ProseMirror').then(([{ editor }]) => {
editor.setContent('<p><a href="#">Example Text</a></p>')
expect(editor.getHTML()).to.eq('<p><a href="#" target="_blank" rel="noopener noreferrer nofollow">Example Text</a></p>')
})
})
it('should parse a tags with target attribute correctly', () => {
cy.get('.ProseMirror').then(([{ editor }]) => {
editor.setContent('<p><a href="#" target="_self">Example Text</a></p>')
expect(editor.getHTML()).to.eq('<p><a href="#" target="_self" rel="noopener noreferrer nofollow">Example Text</a></p>')
})
})
it('should parse a tags with rel attribute correctly', () => {
cy.get('.ProseMirror').then(([{ editor }]) => {
editor.setContent('<p><a href="#" rel="follow">Example Text</a></p>')
expect(editor.getHTML()).to.eq('<p><a href="#" target="_blank" rel="noopener noreferrer nofollow">Example Text</a></p>')
})
})
it('the button should add a link to the selected text', () => {
cy.window().then(win => {
cy.stub(win, 'prompt').returns('https://tiptap.dev')

View File

@@ -10,6 +10,20 @@ context('/api/extensions/ordered-list', () => {
})
})
it('should parse ordered lists correctly', () => {
cy.get('.ProseMirror').then(([{ editor }]) => {
editor.setContent('<ol><li><p>Example Text</p></li></ol>')
expect(editor.getHTML()).to.eq('<ol><li><p>Example Text</p></li></ol>')
})
})
it('should parse ordered lists without paragraphs correctly', () => {
cy.get('.ProseMirror').then(([{ editor }]) => {
editor.setContent('<ol><li>Example Text</li></ol>')
expect(editor.getHTML()).to.eq('<ol><li><p>Example Text</p></li></ol>')
})
})
it('the button should make the selected line a ordered list item', () => {
cy.get('.ProseMirror ol')
.should('not.exist')

View File

@@ -38,10 +38,15 @@ export default {
ListItem(),
],
content: `
<ul>
<ol>
<li>A list item</li>
<li>And another one</li>
</ul>
</ol>
<ol start="5">
<li>This item starts at 5</li>
<li>And another one</li>
</ol>
`,
})
},

View File

@@ -9,6 +9,19 @@ context('/api/extensions/paragraph', () => {
})
})
it('should parse paragraphs correctly', () => {
cy.get('.ProseMirror').then(([{ editor }]) => {
editor.setContent('<p>Example Text</p>')
expect(editor.getHTML()).to.eq('<p>Example Text</p>')
editor.setContent('<p><x-unknown>Example Text</x-unknown></p>')
expect(editor.getHTML()).to.eq('<p>Example Text</p>')
editor.setContent('<p style="display: block;">Example Text</p>')
expect(editor.getHTML()).to.eq('<p>Example Text</p>')
})
})
it('text should be wrapped in a paragraph by default', () => {
cy.get('.ProseMirror')
.type('Example Text')

View File

@@ -10,6 +10,34 @@ context('/api/extensions/strike', () => {
})
})
it('should parse s tags correctly', () => {
cy.get('.ProseMirror').then(([{ editor }]) => {
editor.setContent('<p><s>Example Text</s></p>')
expect(editor.getHTML()).to.eq('<p><s>Example Text</s></p>')
})
})
it('should transform del tags to s tags', () => {
cy.get('.ProseMirror').then(([{ editor }]) => {
editor.setContent('<p><del>Example Text</del></p>')
expect(editor.getHTML()).to.eq('<p><s>Example Text</s></p>')
})
})
it('should transform strike tags to s tags', () => {
cy.get('.ProseMirror').then(([{ editor }]) => {
editor.setContent('<p><strike>Example Text</strike></p>')
expect(editor.getHTML()).to.eq('<p><s>Example Text</s></p>')
})
})
it('should transform any tag with text decoration line through to s tags', () => {
cy.get('.ProseMirror').then(([{ editor }]) => {
editor.setContent('<p><span style="text-decoration: line-through">Example Text</span></p>')
expect(editor.getHTML()).to.eq('<p><s>Example Text</s></p>')
})
})
it('the button should strike the selected text', () => {
cy.get('.demo__preview button:first')
.click()
@@ -51,7 +79,7 @@ context('/api/extensions/strike', () => {
it('should make a striked text from the markdown shortcut', () => {
cy.get('.ProseMirror')
.type('~Strike~')
.type('~~Strike~~')
.find('s')
.should('contain', 'Strike')
})

View File

@@ -0,0 +1,18 @@
context('/api/extensions/text', () => {
before(() => {
cy.visit('/api/extensions/text')
})
beforeEach(() => {
cy.get('.ProseMirror').then(([{ editor }]) => {
editor.clearContent()
})
})
it('text should be wrapped in a paragraph by default', () => {
cy.get('.ProseMirror')
.type('Example Text')
.find('p')
.should('contain', 'Example Text')
})
})

View File

@@ -0,0 +1,57 @@
<template>
<div v-if="editor">
<button @click="editor.chain().focus().textAlign('left').run()">
left
</button>
<button @click="editor.chain().focus().textAlign('center').run()">
center
</button>
<button @click="editor.chain().focus().textAlign('right').run()">
right
</button>
<editor-content :editor="editor" />
</div>
</template>
<script>
import { Editor } from '@tiptap/core'
import { EditorContent } from '@tiptap/vue'
import Document from '@tiptap/extension-document'
import Paragraph from '@tiptap/extension-paragraph'
import Heading from '@tiptap/extension-heading'
import Text from '@tiptap/extension-text'
import TextAlign from '@tiptap/extension-text-align'
export default {
components: {
EditorContent,
},
data() {
return {
editor: null,
}
},
mounted() {
this.editor = new Editor({
extensions: [
Document(),
Paragraph(),
Text(),
Heading(),
TextAlign(),
],
content: `
<h2>Heading</h2>
<p style="text-align: center">first paragraph</p>
<p style="text-align: right">second paragraph</p>
`,
})
},
beforeDestroy() {
this.editor.destroy()
},
}
</script>

View File

@@ -10,6 +10,20 @@ context('/api/extensions/underline', () => {
})
})
it('should parse u tags correctly', () => {
cy.get('.ProseMirror').then(([{ editor }]) => {
editor.setContent('<p><u>Example Text</u></p>')
expect(editor.getHTML()).to.eq('<p><u>Example Text</u></p>')
})
})
it('should transform any tag with text decoration underline to u tags', () => {
cy.get('.ProseMirror').then(([{ editor }]) => {
editor.setContent('<p><span style="text-decoration: underline">Example Text</span></p>')
expect(editor.getHTML()).to.eq('<p><u>Example Text</u></p>')
})
})
it('the button should underline the selected text', () => {
cy.get('.demo__preview button:first')
.click()

View File

@@ -19,7 +19,7 @@ export const Editor = ({
content: value,
...props,
}).on('transaction', () => {
onChange(e.json())
onChange(e.getJSON())
})
setEditor(e)