Skip to content

Commit

Permalink
Merge pull request #5313 from nextcloud/tmp/interactive-preview
Browse files Browse the repository at this point in the history
Add interactive flag to reference widgets
  • Loading branch information
juliushaertl authored Feb 19, 2024
2 parents a20ac24 + db1ec2d commit 060e8e5
Show file tree
Hide file tree
Showing 5 changed files with 142 additions and 11 deletions.
4 changes: 2 additions & 2 deletions src/css/prosemirror.scss
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ div.ProseMirror {
padding: .5em 0;
}

p.paragraph-content {
p .paragraph-content {
margin-bottom: 1em;
line-height: 150%;
}
Expand Down Expand Up @@ -248,7 +248,7 @@ div.ProseMirror {
position: relative;
padding-left: 3px;

p.paragraph-content {
p .paragraph-content {
margin-bottom: 0.5em;
}
}
Expand Down
10 changes: 4 additions & 6 deletions src/nodes/Paragraph.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
import TiptapParagraph from '@tiptap/extension-paragraph'
import { VueNodeViewRenderer } from '@tiptap/vue-2'
import ParagraphView from './ParagraphView.vue'

const Paragraph = TiptapParagraph.extend({

addOptions() {
return {
HTMLAttributes: {
class: 'paragraph-content',
},
}
addNodeView() {
return VueNodeViewRenderer(ParagraphView)
},

parseHTML() {
Expand Down
133 changes: 133 additions & 0 deletions src/nodes/ParagraphView.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
<!--
- @copyright Copyright (c) 2019 Julius Härtl <jus@bitgrid.net>
-
- @author Julius Härtl <jus@bitgrid.net>
-
- @license GNU AGPL version 3 or any later version
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Affero General Public License as
- published by the Free Software Foundation, either version 3 of the
- License, or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-->

<template>
<NodeViewWrapper class="vue-component" as="p">
<NodeViewContent class="paragraph-content" />
<NcReferenceList v-if="isLoggedIn && text"
:text="text"
:limit="1"
:interactive="true"
contenteditable="false" />
</NodeViewWrapper>
</template>

<script>
import { NodeViewContent, nodeViewProps, NodeViewWrapper } from '@tiptap/vue-2'
import { getCurrentUser } from '@nextcloud/auth'
import { NcReferenceList } from '@nextcloud/vue/dist/Components/NcRichText.js'
import debounce from 'debounce'
export default {
name: 'ParagraphView',
components: {
NodeViewWrapper,
NodeViewContent,
NcReferenceList,
},
props: nodeViewProps,
data() {
return {
text: null,
isLoggedIn: getCurrentUser(),
}
},
watch: {
node: {
handler(newNode) {
if (!newNode?.textContent) {
this.text = ''
return
}
this.debouncedUpdateText(newNode)
},
},
},
beforeCreate() {
this.debouncedUpdateText = debounce((newNode) => {
this.text = this.getTextReference(this.node)
}, 500)
},
created() {
this.text = this.getTextReference(this.node)
},
beforeUnmount() {
this.debouncedUpdateText?.cancel()
},
methods: {
getTextReference(node) {
if (!node?.childCount) {
return null
}
// Only regard paragraphs with exactly one text node (ignoring whitespace-only nodes)
let textNode
for (let i = 0; i < node.childCount; i++) {
const childNode = node.child(i)
// Disregard paragraphs with non-text nodes
if (childNode.type.name !== 'text') {
return null
}
// Ignore children with empty text
if (!childNode.textContent.trim()) {
continue
}
// Disregard paragraphs with more than one text nodes
if (textNode) {
return null
}
textNode = childNode
}
// Check if the text node is a link
const linkMark = textNode?.marks.find((m) => m.type.name === 'link')
const href = linkMark?.attrs?.href
const PATTERN = /(^)(https?:\/\/)((?:[-A-Z0-9+_]+\.)+[-A-Z]+(?:\/[-A-Z0-9+&@#%?=~_|!:,.;()]*)*)($)/ig
if ((new RegExp(PATTERN)).test(href)) {
return href
}
return null
},
},
}
</script>
<style lang="scss" scoped>
:deep(div.widgets--list a.widget-default) {
color: var(--color-main-text);
padding: 0;
text-decoration: none;
max-width: calc(100vw - 56px);
}
:deep(.widget-default--details) {
overflow:hidden;
p {
margin-bottom: 4px !important;
}
}
</style>
2 changes: 1 addition & 1 deletion src/tests/nodes/Table.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,5 +78,5 @@ function editorWithContent(content) {
}

function formatHTML(html) {
return html.replaceAll('><', '>\n<').replace(/\n$/, '').replace('<p>', '<p class="paragraph-content">')
return html.replaceAll('><', '>\n<').replace(/\n$/, '')
}
4 changes: 2 additions & 2 deletions src/tests/tiptap.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ const renderedHTML = ( markdown ) => {
describe('TipTap', () => {
it('render softbreaks', () => {
const markdown = 'This\nis\none\nparagraph'
expect(renderedHTML(markdown)).toEqual(`<p class="paragraph-content">${markdown}</p>`)
expect(renderedHTML(markdown)).toEqual(`<p>${markdown}</p>`)
})

it('render hardbreak', () => {
const markdown = 'Hard line break \nNext Paragraph'
expect(renderedHTML(markdown)).toEqual('<p class="paragraph-content">Hard line break<br>Next Paragraph</p>')
expect(renderedHTML(markdown)).toEqual('<p>Hard line break<br>Next Paragraph</p>')
})
})

0 comments on commit 060e8e5

Please sign in to comment.