Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nextcloud/text.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVinicius Reis <vinicius.reis@nextcloud.com>2022-04-21 01:34:56 +0300
committerVinicius Reis <vinicius.reis@nextcloud.com>2022-04-21 01:34:56 +0300
commit3a22042869eb2a79b55359bd46976c6b72c7e80d (patch)
treeaaab46fdfe6b47f823226211fed335e542cdd26d
parent9b7ccbe4f790a07cb4662213c42df5041d064ee2 (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.md0
-rw-r--r--cypress/integration/links.spec.js69
-rw-r--r--cypress/support/commands.js18
-rw-r--r--src/marks/Link.js57
-rw-r--r--src/plugins/link.js55
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 }