Skip to content

Commit

Permalink
Merge pull request #5158 from nextcloud/feat/link_preview_click
Browse files Browse the repository at this point in the history
Link bubble menu to preview and edit links
  • Loading branch information
mejo- authored Jan 30, 2024
2 parents b991d98 + b73181a commit a084306
Show file tree
Hide file tree
Showing 19 changed files with 757 additions and 341 deletions.
113 changes: 71 additions & 42 deletions cypress/e2e/nodes/Links.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,65 +20,101 @@ describe('test link marks', function() {
cy.openFile(fileName, { force: true })
})

describe('link preview', function() {
it('shows a link preview', () => {
cy.getContent().type('https://nextcloud.com')
cy.getContent().type('{enter}')
describe('link bubble', function() {
it('shows a link preview in the bubble after clicking link', () => {
const link = 'https://nextcloud.com/'
cy.getContent()
.type(`${link}{enter}`)

cy.getContent()
.find('.widgets--list', { timeout: 10000 })
.find(`a[href*="${link}"]`)
.click()

cy.get('.link-view-bubble .widget-default', { timeout: 10000 })
.find('.widget-default--name')
.contains('Nextcloud')
.click({ force: true })
})

it('does not show a link preview for links within a paragraph', () => {
cy.getContent().type('Please visit https://nextcloud.com')
cy.getContent().type('{enter}')
it('shows a link preview in the bubble after browsing to link', () => {
const link = 'https://nextcloud.com/'
cy.getContent()
.type(`${link}{enter}`)
cy.getContent()
.type('{upArrow}')

cy.getContent()
.find('.widgets--list', { timeout: 10000 })
.should('not.exist')
.find(`a[href*="${link}"]`)

cy.get('.link-view-bubble .widget-default', { timeout: 10000 })
.find('.widget-default--name')
.contains('Nextcloud')
})
})

describe('autolink', function() {
it('with protocol to files app and fileId', () => {
cy.getFile(fileName)
.then($el => {
const id = $el.data('id')
it('allows to edit a link in the bubble', () => {
cy.getContent()
.type('https://example.org{enter}')
cy.getContent()
.type('{upArrow}{rightArrow}')

const link = `${Cypress.env('baseUrl')}/apps/files/file-name?fileId=${id}`
cy.clearContent()
cy.getContent()
.type(`${link}{enter}`)
cy.get('.link-view-bubble button[title="Edit link"]')
.click()

cy.getContent()
.find(`a[href*="${Cypress.env('baseUrl')}"]`)
.click({ force: true })
cy.get('.link-view-bubble input')
.type('{selectAll}https://nextcloud.com')

cy.get('@winOpen')
.should('have.been.calledOnce')
.should('have.been.calledWithMatch', new RegExp(`/f/${id}$`))
})
cy.get('.link-view-bubble button[title="Save changes"]')
.click()

cy.getContent()
.find('a[href*="https://nextcloud.com"]')

})

it('allows to remove a link in the bubble', () => {
const link = 'https://nextcloud.com'
cy.getContent()
.type(`${link}{enter}`)
cy.getContent()
.type('{upArrow}{rightArrow}')

cy.get('.link-view-bubble button[title="Remove link"]')
.click()

cy.getContent()
.find(`a[href*="${link}"]`)
.should('not.exist')

})

it('Ctrl-click on a link opens a new tab', () => {
const link = 'https://nextcloud.com/'
cy.getContent()
.type(`${link}{enter}`)

cy.getContent()
.find(`a[href*="${link}"]`)
.click({ ctrlKey: true })

cy.get('@winOpen')
.should('have.been.calledOnce')
.should('have.been.calledWith', link)
})
})

it('with protocol and fileId', () => {
describe('autolink', function() {
it('with protocol to files app and fileId', () => {
cy.getFile(fileName)
.then($el => {
const id = $el.data('id')
const id = $el.data('cyFilesListRowFileid')

const link = `${Cypress.env('baseUrl')}/file-name?fileId=${id}`
const link = `${Cypress.env('baseUrl')}/apps/files/?dir=/&openfile=${id}#relPath=/${fileName}`
cy.clearContent()
cy.getContent()
.type(`${link}{enter}`)

cy.getContent()
.find(`a[href*="${Cypress.env('baseUrl')}"]`)
.click({ force: true })

cy.get('@winOpen')
.should('have.been.calledOnce')
.should('have.been.calledWithMatch', new RegExp(`${Cypress.env('baseUrl')}/file-name\\?fileId=${id}$`))
})
})

Expand Down Expand Up @@ -115,10 +151,6 @@ describe('test link marks', function() {
.get(`a[href*="${url}"]`)
.should('have.text', text) // ensure correct text used
.click({ force: true })

cy.get('@winOpen')
.should('have.been.calledOnce')
.should('have.been.calledWith', url)
}

beforeEach(cy.clearContent)
Expand Down Expand Up @@ -151,7 +183,6 @@ describe('test link marks', function() {
return cy.getContent()
.find(`a[href*="${encodeURIComponent(filename)}"]`)
.should('have.text', text === undefined ? filename : text)
.click({ force: true })
}

beforeEach(() => cy.clearContent())
Expand All @@ -176,8 +207,6 @@ describe('test link marks', function() {
cy.getFile(fileName).then($el => {
cy.getContent().type(`${text}{selectAll}`)
checkLinkFile('dummy folder', text, true)
cy.get('@winOpen')
.should('have.been.calledOnce')
})
})
})
Expand Down
9 changes: 7 additions & 2 deletions cypress/e2e/workspace.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -174,8 +174,13 @@ describe('Workspace', function() {
.and('contains', `dir=/${this.testFolder}/sub-folder/alpha`)
.and('contains', '#relPath=sub-folder/alpha/test.md')

cy.getEditor()
.find('a').click()
cy.getContent()
.type('{leftArrow}')

cy.get('.link-view-bubble .widget-file', { timeout: 10000 })
.find('.widget-file--title')
.contains('test.md')
.click({ force: true })

cy.getModal()
.find('.modal-header')
Expand Down
9 changes: 0 additions & 9 deletions src/components/Editor.provider.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ export const IS_RICH_EDITOR = Symbol('editor:is-rich-editor')
export const IS_RICH_WORKSPACE = Symbol('editor:is-rich-woskapace')
export const SYNC_SERVICE = Symbol('sync:service')
export const EDITOR_UPLOAD = Symbol('editor:upload')
export const HOOK_LINK_CLICK = Symbol('hook:link-click')
export const HOOK_MENTION_SEARCH = Symbol('hook:mention-search')
export const HOOK_MENTION_INSERT = Symbol('hook:mention-insert')

Expand Down Expand Up @@ -117,11 +116,3 @@ export const useMentionHook = {
},
},
}
export const useLinkClickHook = {
inject: {
$linkHookClick: {
from: HOOK_LINK_CLICK,
default: null,
},
},
}
10 changes: 1 addition & 9 deletions src/components/Editor/MarkdownContentEditor.vue
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ import { Editor } from '@tiptap/core'
/* eslint-disable import/no-named-as-default */
import History from '@tiptap/extension-history'
import { getCurrentUser } from '@nextcloud/auth'
import { ATTACHMENT_RESOLVER, EDITOR, IS_RICH_EDITOR, useLinkClickHook } from '../Editor.provider.js'
import { ATTACHMENT_RESOLVER, EDITOR, IS_RICH_EDITOR } from '../Editor.provider.js'
import { createMarkdownSerializer } from '../../extensions/Markdown.js'
import AttachmentResolver from '../../services/AttachmentResolver.js'
import markdownit from '../../markdownit/index.js'
Expand All @@ -52,7 +52,6 @@ import ContentContainer from './ContentContainer.vue'
export default {
name: 'MarkdownContentEditor',
components: { ContentContainer, ReadonlyBar, MenuBar, MainContainer, Wrapper },
mixins: [useLinkClickHook],
provide() {
const val = {}

Expand Down Expand Up @@ -136,13 +135,6 @@ export default {
return [
RichText.configure({
component: this,
link: this?.$linkHookClick
? {
onClick: (event, attrs) => {
return this?.$linkHookClick?.(event, attrs)
},
}
: undefined,
extensions: [
History,
],
Expand Down
Loading

0 comments on commit a084306

Please sign in to comment.