diff --git a/src/components/EditorWrapper.vue b/src/components/EditorWrapper.vue index 1ec1d0cb1a2..f160bb0d258 100644 --- a/src/components/EditorWrapper.vue +++ b/src/components/EditorWrapper.vue @@ -74,9 +74,6 @@
- @@ -136,7 +133,6 @@ export default { EditorContent, EditorMidiaHandler, MenuBar, - MenuBubble: () => import(/* webpackChunkName: "editor-rich" */'./MenuBubble.vue'), Reader: () => import(/* webpackChunkName: "editor" */'./Reader.vue'), CollisionResolveDialog: () => import(/* webpackChunkName: "editor" */'./CollisionResolveDialog.vue'), GuestNameDialog: () => import(/* webpackChunkName: "editor-guest" */'./GuestNameDialog.vue'), diff --git a/src/components/Menu/ActionInsertLink.vue b/src/components/Menu/ActionInsertLink.vue new file mode 100644 index 00000000000..58a93b1beb7 --- /dev/null +++ b/src/components/Menu/ActionInsertLink.vue @@ -0,0 +1,203 @@ + + + + diff --git a/src/components/Menu/MenuBar.vue b/src/components/Menu/MenuBar.vue index e2b66036184..d530cc5d806 100644 --- a/src/components/Menu/MenuBar.vue +++ b/src/components/Menu/MenuBar.vue @@ -214,7 +214,7 @@ export default { --background-blur: blur(10px); position: sticky; top: 0; - z-index: 10021; // above modal-header and menububble so menubar is always on top + z-index: 10021; // above modal-header so menubar is always on top background-color: var(--color-main-background-translucent); backdrop-filter: var(--background-blur); max-height: 44px; // important for mobile so that the buttons are always inside the container diff --git a/src/components/Menu/entries.js b/src/components/Menu/entries.js index 9af3dd04a71..4fd21487392 100644 --- a/src/components/Menu/entries.js +++ b/src/components/Menu/entries.js @@ -46,9 +46,11 @@ import { Emoticon, Help, Images, + Link, } from '../icons.js' import EmojiPickerAction from './EmojiPickerAction.vue' import ActionImageUpload from './ActionImageUpload.vue' +import ActionInsertLink from './ActionInsertLink.vue' export default [ { @@ -58,7 +60,7 @@ export default [ keyModifiers: ['ctrl'], icon: Undo, action: (command) => command.undo(), - priority: 5, + priority: 6, }, { key: 'redo', @@ -67,7 +69,7 @@ export default [ keyModifiers: ['ctrl'], icon: Redo, action: (command) => command.redo(), - priority: 11, + priority: 12, }, { key: 'bold', @@ -79,7 +81,7 @@ export default [ action: (command) => { return command.toggleBold() }, - priority: 6, + priority: 7, }, { key: 'italic', @@ -91,7 +93,7 @@ export default [ action: (command) => { return command.toggleItalic() }, - priority: 7, + priority: 8, }, { key: 'underline', @@ -103,7 +105,7 @@ export default [ action: (command) => { return command.toggleUnderline() }, - priority: 14, + priority: 15, }, { key: 'strikethrough', @@ -115,7 +117,7 @@ export default [ action: (command) => { return command.toggleStrike() }, - priority: 15, + priority: 16, }, { key: 'headings', @@ -193,7 +195,7 @@ export default [ action: (command) => { return command.toggleBulletList() }, - priority: 8, + priority: 9, }, { key: 'ordered-list', @@ -205,7 +207,7 @@ export default [ action: (command) => { return command.toggleOrderedList() }, - priority: 9, + priority: 10, }, { key: 'task-list', @@ -213,7 +215,15 @@ export default [ isActive: 'taskList', icon: FormatListCheckbox, action: (command) => command.toggleTaskList(), - priority: 10, + priority: 11, + }, + { + key: 'insert-link', + label: t('text', 'Insert link'), + isActive: 'link', + icon: Link, + component: ActionInsertLink, + priority: 2, }, { key: 'blockquote', @@ -225,7 +235,7 @@ export default [ action: (command) => { return command.toggleBlockquote() }, - priority: 12, + priority: 13, }, { key: 'callouts', @@ -281,7 +291,7 @@ export default [ action: (command) => { return command.toggleCodeBlock() }, - priority: 13, + priority: 14, }, { key: 'table', @@ -291,7 +301,7 @@ export default [ action: (command) => { return command.insertTable() }, - priority: 16, + priority: 17, }, { key: 'emoji-picker', @@ -301,20 +311,20 @@ export default [ action: (command, emojiObject = {}) => { return command.emoji(emojiObject) }, - priority: 4, + priority: 5, }, { key: 'insert-image', label: t('text', 'Insert image'), icon: Images, component: ActionImageUpload, - priority: 2, + priority: 4, }, { key: 'formatting-help', label: t('text', 'Formatting help'), icon: Help, click: (view) => view.$emit('call:help'), - priority: 17, + priority: 18, }, ] diff --git a/src/components/MenuBubble.vue b/src/components/MenuBubble.vue deleted file mode 100644 index 706de84adaf..00000000000 --- a/src/components/MenuBubble.vue +++ /dev/null @@ -1,235 +0,0 @@ - - - - - - - diff --git a/src/components/icons.js b/src/components/icons.js index 926a4d477d8..3aa0572f4a3 100644 --- a/src/components/icons.js +++ b/src/components/icons.js @@ -28,6 +28,7 @@ import MDI_Delete from 'vue-material-design-icons/Delete.vue' import MDI_Document from 'vue-material-design-icons/FileDocument.vue' import MDI_DotsHorizontal from 'vue-material-design-icons/DotsHorizontal.vue' import MDI_Emoticon from 'vue-material-design-icons/EmoticonOutline.vue' +import MDI_FileLink from 'vue-material-design-icons/FileLink.vue' import MDI_Folder from 'vue-material-design-icons/Folder.vue' import MDI_FormatBold from 'vue-material-design-icons/FormatBold.vue' import MDI_FormatHeader1 from 'vue-material-design-icons/FormatHeader1.vue' @@ -48,6 +49,7 @@ import MDI_Image from 'vue-material-design-icons/ImageOutline.vue' import MDI_Images from 'vue-material-design-icons/ImageMultipleOutline.vue' import MDI_Info from 'vue-material-design-icons/Information.vue' import MDI_Link from 'vue-material-design-icons/Link.vue' +import MDI_LinkOff from 'vue-material-design-icons/LinkOff.vue' import MDI_Loading from 'vue-material-design-icons/Loading.vue' import MDI_Lock from 'vue-material-design-icons/Lock.vue' import MDI_Positive from 'vue-material-design-icons/CheckboxMarkedCircle.vue' @@ -62,6 +64,7 @@ import MDI_TrashCan from 'vue-material-design-icons/TrashCan.vue' import MDI_Undo from 'vue-material-design-icons/ArrowULeftTop.vue' import MDI_Upload from 'vue-material-design-icons/Upload.vue' import MDI_Warn from 'vue-material-design-icons/Alert.vue' +import MDI_Web from 'vue-material-design-icons/Web.vue' const DEFAULT_ICON_SIZE = 20 @@ -95,6 +98,7 @@ export const Delete = makeIcon(MDI_Delete) export const Document = makeIcon(MDI_Document) export const DotsHorizontal = makeIcon(MDI_DotsHorizontal) export const Emoticon = makeIcon(MDI_Emoticon) +export const FileLink = makeIcon(MDI_FileLink) export const Folder = makeIcon(MDI_Folder) export const FormatBold = makeIcon(MDI_FormatBold) export const FormatHeader1 = makeIcon(MDI_FormatHeader1) @@ -115,6 +119,7 @@ export const Image = makeIcon(MDI_Image) export const Images = makeIcon(MDI_Images) export const Info = makeIcon(MDI_Info) export const Link = makeIcon(MDI_Link) +export const LinkOff = makeIcon(MDI_LinkOff) export const Lock = makeIcon(MDI_Lock) export const Positive = makeIcon(MDI_Positive) export const Redo = makeIcon(MDI_Redo) @@ -128,3 +133,4 @@ export const TrashCan = makeIcon(MDI_TrashCan) export const Undo = makeIcon(MDI_Undo) export const Upload = makeIcon(MDI_Upload) export const Warn = makeIcon(MDI_Warn) +export const Web = makeIcon(MDI_Web) diff --git a/src/helpers/files.js b/src/helpers/files.js index f4b5625d07e..286f09a7302 100644 --- a/src/helpers/files.js +++ b/src/helpers/files.js @@ -34,6 +34,10 @@ const optimalPath = function(from, to) { while (current[0] === target[0]) { current.shift() target.shift() + // Handle case where target is the current directory + if (current.length === 0 && target.length === 0) { + return '.' + } } const relativePath = current.fill('..').concat(target) const absolutePath = to.split('/') diff --git a/src/helpers/links.js b/src/helpers/links.js index 007c9f791d1..226dabbd72c 100644 --- a/src/helpers/links.js +++ b/src/helpers/links.js @@ -61,8 +61,14 @@ const domHref = function(node) { const [, relPath, id] = match const currentDir = basedir(OCA.Viewer.file) const dir = absolutePath(currentDir, basedir(relPath)) - return generateUrl(`/apps/files/?dir=${dir}&openfile=${id}#relPath=${relPath}`) + if (relPath.length > 1 && relPath.endsWith('/')) { + // is directory + return generateUrl(`/apps/files/?dir=${dir}&fileId=${id}`) + } else { + return generateUrl(`/apps/files/?dir=${dir}&openfile=${id}#relPath=${relPath}`) + } } + return ref } const parseHref = function(dom) { @@ -97,7 +103,7 @@ const openLink = function(event, _attrs) { } if (query.fileId) { // open the direct file link - window.open(generateUrl(`/f/${query.fileId}`)) + window.open(generateUrl(`/f/${query.fileId}`), '_self') return } if (!markdownit.validateLink(htmlHref)) { diff --git a/src/views/RichWorkspace.vue b/src/views/RichWorkspace.vue index 75afe2e2d03..308557dc61d 100644 --- a/src/views/RichWorkspace.vue +++ b/src/views/RichWorkspace.vue @@ -186,7 +186,7 @@ export default { overflow: scroll !important; max-height: calc(40vh - 50px); padding-left: 10px; - padding-bottom: 60px; /* ensure menububble fits below */ + padding-bottom: 10px; } #rich-workspace::v-deep .text-editor__wrapper .ProseMirror {