From 15603981f8309d979465c40175f9b3cd4f6617b4 Mon Sep 17 00:00:00 2001 From: shpuld Date: Wed, 30 Jan 2019 19:15:35 +0200 Subject: [PATCH] Capture clicks on statuses to hijack mention clicks, match mention href to user somehow --- src/components/status/status.js | 15 ++++- src/components/status/status.vue | 4 +- .../mention_matcher/mention_matcher.js | 9 +++ .../mention_matcher/mention_matcher.spec.js | 63 +++++++++++++++++++ 4 files changed, 88 insertions(+), 3 deletions(-) create mode 100644 src/services/mention_matcher/mention_matcher.js create mode 100644 test/unit/specs/services/mention_matcher/mention_matcher.spec.js diff --git a/src/components/status/status.js b/src/components/status/status.js index 558125dff1..e268ddaa08 100644 --- a/src/components/status/status.js +++ b/src/components/status/status.js @@ -9,6 +9,7 @@ import LinkPreview from '../link-preview/link-preview.vue' import { filter, find } from 'lodash' import { highlightClass, highlightStyle } from '../../services/user_highlighter/user_highlighter.js' import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator' +import { mentionMatchesUrl } from 'src/services/mention_matcher/mention_matcher.js' const Status = { name: 'Status', @@ -237,11 +238,23 @@ const Status = { return 'icon-globe' } }, - linkClicked ({target}) { + linkClicked (event) { + let { target } = event if (target.tagName === 'SPAN') { target = target.parentNode } if (target.tagName === 'A') { + if (target.className.match(/mention/)) { + const href = target.getAttribute('href') + const attn = this.status.attentions.find(attn => mentionMatchesUrl(attn, href)) + if (attn) { + event.stopPropagation() + event.preventDefault() + const link = this.generateUserProfileLink(attn.id, attn.screen_name) + this.$router.push(link) + return + } + } window.open(target.href, '_blank') } }, diff --git a/src/components/status/status.vue b/src/components/status/status.vue index d88428c7aa..45100a4666 100644 --- a/src/components/status/status.vue +++ b/src/components/status/status.vue @@ -24,9 +24,9 @@
- + - +
diff --git a/src/services/mention_matcher/mention_matcher.js b/src/services/mention_matcher/mention_matcher.js new file mode 100644 index 0000000000..2c1ed97064 --- /dev/null +++ b/src/services/mention_matcher/mention_matcher.js @@ -0,0 +1,9 @@ + +export const mentionMatchesUrl = (attention, url) => { + if (url === attention.statusnet_profile_url) { + return true + } + const [namepart, instancepart] = attention.screen_name.split('@') + const matchstring = new RegExp('://' + instancepart + '/.*' + namepart + '$', 'g') + return !!url.match(matchstring) +} diff --git a/test/unit/specs/services/mention_matcher/mention_matcher.spec.js b/test/unit/specs/services/mention_matcher/mention_matcher.spec.js new file mode 100644 index 0000000000..4f6f58fff3 --- /dev/null +++ b/test/unit/specs/services/mention_matcher/mention_matcher.spec.js @@ -0,0 +1,63 @@ +import * as MentionMatcher from 'src/services/mention_matcher/mention_matcher.js' + +const localAttn = () => ({ + id: 123, + is_local: true, + name: 'Guy', + screen_name: 'person', + statusnet_profile_url: 'https://instance.com/users/person' +}) + +const externalAttn = () => ({ + id: 123, + is_local: false, + name: 'Guy', + screen_name: 'person@instance.com', + statusnet_profile_url: 'https://instance.com/users/person' +}) + +describe('MentionMatcher', () => { + describe.only('mentionMatchesUrl', () => { + it('should match local mention', () => { + const attention = localAttn() + const url = 'https://instance.com/users/person' + + expect(MentionMatcher.mentionMatchesUrl(attention, url)).to.eql(true) + }) + + it('should not match a local mention with same name but different instance', () => { + const attention = localAttn() + const url = 'https://website.com/users/person' + + expect(MentionMatcher.mentionMatchesUrl(attention, url)).to.eql(false) + }) + + it('should match external pleroma mention', () => { + const attention = externalAttn() + const url = 'https://instance.com/users/person' + + expect(MentionMatcher.mentionMatchesUrl(attention, url)).to.eql(true) + }) + + it('should not match external pleroma mention with same name but different instance', () => { + const attention = externalAttn() + const url = 'https://website.com/users/person' + + expect(MentionMatcher.mentionMatchesUrl(attention, url)).to.eql(false) + }) + + it('should match external mastodon mention', () => { + const attention = externalAttn() + const url = 'https://instance.com/@person' + + expect(MentionMatcher.mentionMatchesUrl(attention, url)).to.eql(true) + }) + + it('should not match external mastodon mention with same name but different instance', () => { + const attention = externalAttn() + const url = 'https://website.com/@person' + + expect(MentionMatcher.mentionMatchesUrl(attention, url)).to.eql(false) + }) + }) +})