diff --git a/src/components/Editor.vue b/src/components/Editor.vue
index 76893fca873..a3df9cdb451 100644
--- a/src/components/Editor.vue
+++ b/src/components/Editor.vue
@@ -58,6 +58,7 @@
+
import { NcActions, NcActionButton, NcActionInput } from '@nextcloud/vue'
import { getLinkWithPicker } from '@nextcloud/vue/dist/Components/NcRichText.js'
-import { FilePickerType, getFilePickerBuilder } from '@nextcloud/dialogs'
import { generateUrl } from '@nextcloud/router'
import { loadState } from '@nextcloud/initial-state'
@@ -76,6 +75,7 @@ import { Document, Loading, LinkOff, Web, Shape } from '../icons.js'
import { BaseActionEntry } from './BaseActionEntry.js'
import { useFileMixin } from '../Editor.provider.js'
import { useMenuIDMixin } from './MenuBar.provider.js'
+import { buildFilePicker } from '../../helpers/filePicker.js'
export default {
name: 'ActionInsertLink',
@@ -122,12 +122,7 @@ export default {
this.startPath = this.relativePath.split('/').slice(0, -1).join('/')
}
- const filePicker = getFilePickerBuilder(t('text', 'Select file or folder to link to'))
- .startAt(this.startPath)
- .allowDirectories(true)
- .setMultiSelect(false)
- .setType(FilePickerType.Choose)
- .build()
+ const filePicker = buildFilePicker(this.startPath)
filePicker.pick()
.then((file) => {
@@ -173,42 +168,9 @@ export default {
* @param {string} text Text part of the link
*/
setLink(url, text) {
- // Heuristics for determining if we need a https:// prefix.
- const noPrefixes = [
- /^[a-zA-Z]+:/, // url with protocol ("mailTo:email@domain.tld")
- /^\//, // absolute path
- /\?fileId=/, // relative link with fileId
- /^\.\.?\//, // relative link starting with ./ or ../
- /^[^.]*[/$]/, // no dots before first '/' - not a domain name
- /^#/, // url fragment
- ]
- if (url && !noPrefixes.find(regex => url.match(regex))) {
- url = 'https://' + url
- }
-
- // Avoid issues when parsing urls later on in markdown that might be entered in an invalid format (e.g. "mailto: example@example.com")
- const href = url.replaceAll(' ', '%20')
- const chain = this.$editor.chain()
- // Check if any text is selected, if not insert the link using the given text property
- if (this.$editor.view.state?.selection.empty) {
- chain.insertContent({
- type: 'paragraph',
- content: [{
- type: 'text',
- marks: [{
- type: 'link',
- attrs: {
- href,
- },
- }],
- text,
- }],
- })
- } else {
- chain.setLink({ href })
- }
- chain.focus().run()
+ this.$editor.chain().setOrInsertLink(url, text).focus().run()
},
+
/**
* Remove link markup at current position
* Triggered by the "remove link" button
diff --git a/src/components/SuggestionsBar.vue b/src/components/SuggestionsBar.vue
new file mode 100644
index 00000000000..5f966e35f9c
--- /dev/null
+++ b/src/components/SuggestionsBar.vue
@@ -0,0 +1,156 @@
+
+
+
+
+
+
+ {{ t('text', 'Link to file or folder') }}
+
+
+
+
+
+
+ {{ t('text', 'Upload') }}
+
+
+
+
+
+
+ {{ t('text', 'Insert Table') }}
+
+
+
+
+
+
+ {{ t('text', 'Smart Picker') }}
+
+
+
+
+
+
+
diff --git a/src/helpers/filePicker.js b/src/helpers/filePicker.js
new file mode 100644
index 00000000000..497e87b1079
--- /dev/null
+++ b/src/helpers/filePicker.js
@@ -0,0 +1,15 @@
+/**
+ * SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+import { FilePickerType, getFilePickerBuilder } from '@nextcloud/dialogs'
+
+export const buildFilePicker = (startPath) => {
+ return getFilePickerBuilder(t('text', 'Select file or folder to link to'))
+ .startAt(startPath)
+ .allowDirectories(true)
+ .setMultiSelect(false)
+ .setType(FilePickerType.Choose)
+ .build()
+}
diff --git a/src/marks/Link.js b/src/marks/Link.js
index 1878f43958b..6a2259018b1 100644
--- a/src/marks/Link.js
+++ b/src/marks/Link.js
@@ -7,6 +7,7 @@ import { markInputRule } from '@tiptap/core'
import TipTapLink from '@tiptap/extension-link'
import { domHref, parseHref } from './../helpers/links.js'
import { linkClicking } from '../plugins/links.js'
+import { getLinkWithPicker } from '@nextcloud/vue/dist/Components/NcRichText.js'
const PROTOCOLS_TO_LINK_TO = ['http:', 'https:', 'mailto:', 'tel:']
@@ -88,6 +89,50 @@ const Link = TipTapLink.extend({
]
},
+ addCommands() {
+ return {
+ /**
+ * Check if any text is selected, if not insert the link using the given text property
+ *
+ * @param {string} url href attribute of the link
+ * @param {string} text Text part of the link
+ */
+ setOrInsertLink: (url, text) => ({ state, chain }) => {
+ // Heuristics for determining if we need a https:// prefix.
+ const noPrefixes = [
+ /^[a-zA-Z]+:/, // url with protocol ("mailTo:email@domain.tld")
+ /^\//, // absolute path
+ /\?fileId=/, // relative link with fileId
+ /^\.\.?\//, // relative link starting with ./ or ../
+ /^[^.]*[/$]/, // no dots before first '/' - not a domain name
+ /^#/, // url fragment
+ ]
+ if (url && !noPrefixes.find(regex => url.match(regex))) {
+ url = 'https://' + url
+ }
+ // Avoid issues when parsing urls later on in markdown that might be entered in an invalid format (e.g. "mailto: example@example.com")
+ const href = url.replaceAll(' ', '%20')
+ if (state.selection.empty) {
+ return chain().insertContent({
+ type: 'paragraph',
+ content: [{
+ type: 'text',
+ marks: [{
+ type: 'link',
+ attrs: {
+ href,
+ },
+ }],
+ text,
+ }],
+ }).run()
+ } else {
+ return chain().setLink({ href }).run()
+ }
+ },
+ }
+ },
+
addProseMirrorPlugins() {
const plugins = this.parent()
// remove upstream link click handle plugin