diff options
author | Vinicius Reis <vinicius.reis@nextcloud.com> | 2022-04-21 01:34:56 +0300 |
---|---|---|
committer | Vinicius Reis <vinicius.reis@nextcloud.com> | 2022-04-21 01:34:56 +0300 |
commit | 3a22042869eb2a79b55359bd46976c6b72c7e80d (patch) | |
tree | aaab46fdfe6b47f823226211fed335e542cdd26d | |
parent | 9b7ccbe4f790a07cb4662213c42df5041d064ee2 (diff) |
🔀 (#2097): backport to stable24
manually applied from #2316 and #2318
Signed-off-by: Vinicius Reis <vinicius.reis@nextcloud.com>
-rw-r--r-- | cypress/fixtures/empty.md | 0 | ||||
-rw-r--r-- | cypress/integration/links.spec.js | 69 | ||||
-rw-r--r-- | cypress/support/commands.js | 18 | ||||
-rw-r--r-- | src/marks/Link.js | 57 | ||||
-rw-r--r-- | src/plugins/link.js | 55 |
5 files changed, 146 insertions, 53 deletions
diff --git a/cypress/fixtures/empty.md b/cypress/fixtures/empty.md new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/cypress/fixtures/empty.md diff --git a/cypress/integration/links.spec.js b/cypress/integration/links.spec.js new file mode 100644 index 000000000..cff108668 --- /dev/null +++ b/cypress/integration/links.spec.js @@ -0,0 +1,69 @@ +import { randHash } from '../utils/' + +const randUser = randHash() +const fileName = 'empty.md' + +const getEditor = () => cy.get('#viewer #editor .ProseMirror') + +const clearContent = () => getEditor() + .type('{selectall}') + .type('{enter}') + +describe('test link marks', function() { + before(function() { + // Init user + cy.nextcloudCreateUser(randUser, 'password') + cy.login(randUser, 'password') + + // Upload test files + cy.uploadFile('test.md', 'text/markdown') + cy.uploadFile(fileName, 'text/markdown') + }) + + beforeEach(function() { + cy.login(randUser, 'password', { + onBeforeLoad(win) { + cy.stub(win, 'open') + .as('winOpen') + + }, + }) + + cy.openFile(fileName) + }) + + describe('autolink', function() { + beforeEach(clearContent) + it('with protocol', () => { + cy.getFile('test.md') + .then($el => { + const id = $el.data('id') + + const link = `${Cypress.env('baseUrl')}/file-name?fileId=${id}` + getEditor() + .type(link) + + getEditor() + .get(`a[href*="${Cypress.env('baseUrl')}`) + .click({ force: true }) + + cy.get('@winOpen') + .should('have.been.calledOnce') + .should('have.been.calledWithMatch', new RegExp(`/f/${id}$`)) + }) + }) + + it('whithout protocol', () => { + getEditor() + .type('google.com') + + getEditor() + .get('a[href*="google.com"]') + .click({ force: true }) + + cy.get('@winOpen') + .should('have.been.calledOnce') + .should('have.been.calledWith', 'http://google.com/') + }) + }) +}) diff --git a/cypress/support/commands.js b/cypress/support/commands.js index b04170534..80382bbe4 100644 --- a/cypress/support/commands.js +++ b/cypress/support/commands.js @@ -26,7 +26,9 @@ import regeneratorRuntime from "regenerator-runtime"; const url = Cypress.config('baseUrl').replace(/\/index.php\/?$/g, '') Cypress.env('baseUrl', url) -Cypress.Commands.add('login', (user, password, route = '/apps/files') => { +Cypress.Commands.add('login', (user, password, { route, onBeforeLoad } = {}) => { + route = route || '/apps/files' + cy.session(user, function () { cy.visit(route) cy.get('input[name=user]').type(user) @@ -35,7 +37,7 @@ Cypress.Commands.add('login', (user, password, route = '/apps/files') => { cy.url().should('include', route) }) // in case the session already existed but we are on a different route... - cy.visit(route) + cy.visit(route, { onBeforeLoad }) }) Cypress.Commands.add('logout', (route = '/') => { @@ -138,25 +140,25 @@ Cypress.Commands.add('shareFileToUser', (userId, password, path, targetUserId) = }) Cypress.Commands.add('createFolder', dirName => { - cy.window().then( win => { + cy.window().then(win => { win.OC.Files.getClient().createDirectory(dirName) }) }) Cypress.Commands.add('moveFile', (path, destinationPath) => { - cy.window().then( win => { + cy.window().then(win => { win.OC.Files.getClient().move(path, destinationPath) }) }) Cypress.Commands.add('copyFile', (path, destinationPath) => { - cy.window().then( win => { + cy.window().then(win => { win.OC.Files.getClient().copy(path, destinationPath) }) }) Cypress.Commands.add('reloadFileList', () => { - cy.window().then( win => { + cy.window().then(win => { win.OCA?.Files?.App?.fileList?.reload() }) }) @@ -166,6 +168,10 @@ Cypress.Commands.add('openFile', fileName => { cy.wait(250) }) +Cypress.Commands.add('getFile', fileName => { + return cy.get(`#fileList tr[data-file="${fileName}"]`) +}) + Cypress.Commands.add('deleteFile', fileName => { cy.get(`#fileList tr[data-file="${fileName}"] a.name .action-menu`).click() cy.get(`#fileList tr[data-file="${fileName}"] a.name + .popovermenu .action-delete`).click() diff --git a/src/marks/Link.js b/src/marks/Link.js index c754cee4b..a5794a1a6 100644 --- a/src/marks/Link.js +++ b/src/marks/Link.js @@ -20,11 +20,9 @@ * */ -import { generateUrl } from '@nextcloud/router' import TipTapLink from '@tiptap/extension-link' -import { Plugin } from 'prosemirror-state' import { domHref, parseHref } from './../helpers/links' -import markdownit from './../markdownit' +import { clickHandler } from '../plugins/link' const Link = TipTapLink.extend({ @@ -53,53 +51,18 @@ const Link = TipTapLink.extend({ }, 0], addProseMirrorPlugins() { + const plugins = this.parent() + // remove original handle click + .filter(({ key }) => { + return !key.startsWith('handleClickLink') + }) + if (!this.options.openOnClick) { - return [] + return plugins } - return [ - new Plugin({ - props: { - handleClick: (view, pos, event) => { - const attrs = this.editor.getAttributes('link') - - const isLink = event.target instanceof HTMLAnchorElement || event.target.parentElement instanceof HTMLAnchorElement - if (attrs.href && isLink) { - const linkElement = event.target.parentElement instanceof HTMLAnchorElement ? event.target.parentElement : event.target - event.stopPropagation() - const htmlHref = linkElement.href - if (event.button === 0 && !event.ctrlKey && htmlHref.startsWith(window.location.origin)) { - const query = OC.parseQueryString(htmlHref) - const fragment = OC.parseQueryString(htmlHref.split('#').pop()) - if (query.dir && fragment.relPath) { - const filename = fragment.relPath.split('/').pop() - const path = `${query.dir}/${filename}` - document.title = `${filename} - ${OC.theme.title}` - if (window.location.pathname.match(/apps\/files\/$/)) { - // The files app still lacks a popState handler - // to allow for using the back button - // OC.Util.History.pushState('', htmlHref) - } - OCA.Viewer.open({ path }) - return - } - if (query.fileId) { - // open the direct file link - window.open(generateUrl(`/f/${query.fileId}`)) - return - } - } - if (!markdownit.validateLink(htmlHref)) { - console.error('Invalid link', htmlHref) - return - } - - window.open(htmlHref) - } - }, - }, - }), - ] + // add custom click handler + return [...plugins, clickHandler({ editor: this.editor, type: this.type })] }, }) diff --git a/src/plugins/link.js b/src/plugins/link.js new file mode 100644 index 000000000..dde5634c7 --- /dev/null +++ b/src/plugins/link.js @@ -0,0 +1,55 @@ +import { generateUrl } from '@nextcloud/router' +import { Plugin } from 'prosemirror-state' +import markdownit from './../markdownit' + +const clickHandler = ({ editor }) => { + return new Plugin({ + props: { + handleClick: (view, pos, event) => { + const linkElement = event.target.parentElement instanceof HTMLAnchorElement + ? event.target.parentElement + : event.target + + const isLink = linkElement && linkElement instanceof HTMLAnchorElement + + const htmlHref = linkElement?.href + + // is handleable link + if (htmlHref && isLink) { + event.stopPropagation() + + if (event.button === 0 && !event.ctrlKey && htmlHref.startsWith(window.location.origin)) { + const query = OC.parseQueryString(htmlHref) + const fragment = OC.parseQueryString(htmlHref.split('#').pop()) + if (query.dir && fragment.relPath) { + const filename = fragment.relPath.split('/').pop() + const path = `${query.dir}/${filename}` + document.title = `${filename} - ${OC.theme.title}` + if (window.location.pathname.match(/apps\/files\/$/)) { + // The files app still lacks a popState handler + // to allow for using the back button + // OC.Util.History.pushState('', htmlHref) + } + OCA.Viewer.open({ path }) + return + } + if (query.fileId) { + // open the direct file link + window.open(generateUrl(`/f/${query.fileId}`)) + return + } + } + + if (!markdownit.validateLink(htmlHref)) { + console.error('Invalid link', htmlHref) + return + } + + window.open(htmlHref) + } + }, + }, + }) +} + +export { clickHandler } |