Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make images block nodes #3282

Merged
merged 8 commits into from
Nov 15, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions js/editor.js

Large diffs are not rendered by default.

22 changes: 22 additions & 0 deletions js/editor.js.LICENSE.txt
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,28 @@
*
*/

/*
* @copyright Copyright (c) 2022 Jonas <[email protected]>
*
* @author Jonas <[email protected]>
*
* @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/>.
*
*/

/*
* @copyright Copyright (c) 2022 Max <[email protected]>
*
Expand Down
2 changes: 1 addition & 1 deletion js/editor.js.map

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions js/files-modal.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion js/files-modal.js.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions js/text-files.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion js/text-files.js.map

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions js/text-public.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion js/text-public.js.map

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions js/text-text.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion js/text-text.js.map

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions js/text-viewer.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion js/text-viewer.js.map

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions js/vendors.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion js/vendors.js.map

Large diffs are not rendered by default.

18 changes: 18 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@
"markdown-it": "^13.0.1",
"markdown-it-container": "^3.0.0",
"markdown-it-front-matter": "^0.2.3",
"markdown-it-image-figures": "^2.1.0",
"mitt": "^3.0.0",
"path-normalize": "^6.0.7",
"prosemirror-collab": "^1.3.0",
Expand Down
20 changes: 17 additions & 3 deletions src/components/Editor/MediaHandler.vue
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@
-->

<template>
<div class="editor editor-midia-handler"
data-text-el="editor-midia-handler"
<div class="editor editor-media-handler"
data-text-el="editor-media-handler"
:class="{ draggedOver }"
@image-paste="onPaste"
@dragover.prevent.stop="setDraggedOver(true)"
Expand Down Expand Up @@ -194,7 +194,21 @@ export default {
? this.$editor.chain().focus(position)
: this.$editor.chain()
chain.setImage({ src, alt }).insertContent('<br />').focus().run()
chain.setImage({ src, alt }).run()
const selection = this.$editor.view.state.selection
if (!selection.empty) {
// If inserted image is first element, it is selected and would get overwritten by
// subsequent editor inserts (see tiptap#3355). So unselect the image by placing
// the cursor at the end of the selection.
this.$editor.commands.focus(selection.to)
} else {
// Place the cursor after the inserted image node
this.$editor.commands.focus(selection.to + 2)
}
// Insert a newline to allow placing the cursor in between subsequent images
this.$editor.chain().insertContent('<br />').focus().run()
},
},
}
Expand Down
6 changes: 3 additions & 3 deletions src/extensions/RichText.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import HardBreak from './HardBreak.js'
import Heading from '../nodes/Heading/index.js'
import HorizontalRule from '@tiptap/extension-horizontal-rule'
import Image from './../nodes/Image.js'
import ImageInline from './../nodes/ImageInline.js'
import KeepSyntax from './KeepSyntax.js'
import ListItem from '@tiptap/extension-list-item'
import Mention from './../extensions/Mention.js'
Expand Down Expand Up @@ -82,9 +83,8 @@ export default Extension.create({
TaskItem,
Callout,
Underline,
Image.configure({
inline: true,
}),
Image,
ImageInline,
Dropcursor,
KeepSyntax,
FrontMatter,
Expand Down
2 changes: 2 additions & 0 deletions src/markdownit/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import underline from './underline.js'
import splitMixedLists from './splitMixedLists.js'
import callouts from './callouts.js'
import keepSyntax from './keepSyntax.js'
import implicitFigures from 'markdown-it-image-figures'

const markdownit = MarkdownIt('commonmark', { html: false, breaks: false })
.enable('strikethrough')
Expand All @@ -15,6 +16,7 @@ const markdownit = MarkdownIt('commonmark', { html: false, breaks: false })
.use(callouts)
.use(keepSyntax)
.use(markdownitMentions)
.use(implicitFigures)

// Issue #3370: To preserve softbreaks within md files we preserve all whitespaces, so we must not introduce additional new lines after a <br> element
markdownit.renderer.rules.hardbreak = (tokens, idx, options) => (options.xhtmlOut ? '<br />' : '<br>')
Expand Down
16 changes: 16 additions & 0 deletions src/nodes/Image.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,16 @@ const Image = TiptapImage.extend({

selectable: false,

parseHTML() {
return [
{
tag: this.options.allowBase64
? 'figure img[src]'
: 'figure img[src]:not([src^="data:"])',
},
]
},

renderHTML() {
// Avoid the prosemirror node creation to trigger image loading as we use a custom node view anyways
// Otherwise it would attempt to load the image from the current location before the node view is even initialized
Expand Down Expand Up @@ -83,6 +93,12 @@ const Image = TiptapImage.extend({
]
},

// Append two newlines after image to make it a block image
toMarkdown(state, node) {
state.write('![' + state.esc(node.attrs.alt || '') + '](' + node.attrs.src.replace(/[()]/g, '\\$&')
+ (node.attrs.title ? ' "' + node.attrs.title.replace(/"/g, '\\"') + '"' : '') + ')\n\n')
},

})

export default Image
74 changes: 74 additions & 0 deletions src/nodes/ImageInline.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/*
* @copyright Copyright (c) 2022 Jonas <[email protected]>
*
* @author Jonas <[email protected]>
*
* @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/>.
*
*/

import TiptapImage from '@tiptap/extension-image'
import ImageView from './ImageView.vue'
import { VueNodeViewRenderer } from '@tiptap/vue-2'

// Inline image extension. Needed if markdown contains inline images.
// Not supported to be created from our UI (we default to block images).
const ImageInline = TiptapImage.extend({
name: 'image-inline',

// Lower priority than (block) Image extension
priority: 99,

selectable: false,

parseHTML() {
return [
{
tag: this.options.allowBase64
? 'img[src]'
: 'img[src]:not([src^="data:"])',
},
]
},

addOptions() {
return {
...this.parent?.(),
inline: true,
}
},

// Empty commands, we want only those from (block) Image extension
addCommands() {
return {}
},

// Empty input rules, we want only those from (block) Image extension
addInputRules() {
return []
},

addNodeView() {
return VueNodeViewRenderer(ImageView)
},
Comment on lines +64 to +66
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Somehow the image does not get rendered for me.
I'll add a failing test.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay... turns out i did not have the file in place. But there also was no placeholder icon. We might want to add that.


toMarkdown(state, node) {
state.write('![' + state.esc(node.attrs.alt || '') + '](' + node.attrs.src.replace(/[()]/g, '\\$&')
+ (node.attrs.title ? ' "' + node.attrs.title.replace(/"/g, '\\"') + '"' : '') + ')')
},
})

export default ImageInline
Loading