Skip to content

Commit

Permalink
Extract link handlers to hook
Browse files Browse the repository at this point in the history
  • Loading branch information
Gargron committed Jun 18, 2024
1 parent 6a1d94c commit 6e80bca
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 149 deletions.
81 changes: 81 additions & 0 deletions app/javascript/hooks/useLinks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { useEffect, useRef, useCallback } from 'react';

import { useHistory } from 'react-router-dom';

import { openURL } from 'mastodon/actions/search';
import { useAppDispatch } from 'mastodon/store';

export const useLinks = (canary: unknown) => {
const ref = useRef<HTMLDivElement>(null);
const history = useHistory();
const dispatch = useAppDispatch();

const handleHashtagClick = useCallback(
(e: MouseEvent) => {
const { currentTarget } = e;
if (!(currentTarget instanceof HTMLElement)) return;

if (e.button === 0 && !(e.ctrlKey || e.metaKey)) {
const { textContent } = currentTarget;
if (!textContent) return;

e.preventDefault();
history.push(`/tags/${textContent.replace(/^#/, '')}`);
}
},
[history],
);

const handleMentionClick = useCallback(
(e: MouseEvent) => {
const { currentTarget } = e;

if (!(currentTarget instanceof HTMLAnchorElement)) return;

if (e.button === 0 && !(e.ctrlKey || e.metaKey)) {
e.preventDefault();

dispatch(
openURL(currentTarget.href, history, () => {
window.location.href = currentTarget.href;
}),
);
}
},
[dispatch, history],
);

useEffect(() => {
if (!ref.current) {
return;
}

const links = ref.current.querySelectorAll<HTMLAnchorElement>('a');

for (const link of links) {
if (
link.textContent?.[0] === '#' ||
link.previousSibling?.textContent?.endsWith('#')
) {
link.addEventListener('click', handleHashtagClick, false);
} else if (link.classList.contains('mention')) {
link.addEventListener('click', handleMentionClick, false);
}
}

return () => {
for (const link of links) {
if (
link.textContent?.[0] === '#' ||
link.previousSibling?.textContent?.endsWith('#')
) {
link.removeEventListener('click', handleHashtagClick);
} else if (link.classList.contains('mention')) {
link.removeEventListener('click', handleMentionClick);
}
}
};
}, [canary, handleHashtagClick, handleMentionClick]);

return ref;
};
75 changes: 2 additions & 73 deletions app/javascript/mastodon/components/account_bio.tsx
Original file line number Diff line number Diff line change
@@ -1,81 +1,10 @@
import { useEffect, useRef, useCallback } from 'react';

import { useHistory } from 'react-router-dom';

import { openURL } from 'mastodon/actions/search';
import { useAppDispatch } from 'mastodon/store';
import { useLinks } from 'mastodon/../hooks/useLinks';

export const AccountBio: React.FC<{
note: string;
className: string;
}> = ({ note, className }) => {
const ref = useRef<HTMLDivElement>(null);
const history = useHistory();
const dispatch = useAppDispatch();

const handleHashtagClick = useCallback(
(e: MouseEvent) => {
const { currentTarget } = e;
if (!(currentTarget instanceof HTMLElement)) return;
const { textContent } = currentTarget;

if (textContent && e.button === 0 && !(e.ctrlKey || e.metaKey)) {
e.preventDefault();
history.push(`/tags/${textContent.replace(/^#/, '')}`);
}
},
[history],
);

const handleMentionClick = useCallback(
(e: MouseEvent) => {
const { currentTarget } = e;
if (!(currentTarget instanceof HTMLAnchorElement)) return;

if (e.button === 0 && !(e.ctrlKey || e.metaKey)) {
e.preventDefault();

dispatch(
openURL(currentTarget.href, history, () => {
window.location.href = currentTarget.href;
}),
);
}
},
[dispatch, history],
);

useEffect(() => {
if (ref.current === null) {
return;
}

const links = ref.current.querySelectorAll<HTMLAnchorElement>('a');

for (const link of links) {
if (
link.textContent?.[0] === '#' ||
link.previousSibling?.textContent?.endsWith('#')
) {
link.addEventListener('click', handleHashtagClick, false);
} else if (link.classList.contains('mention')) {
link.addEventListener('click', handleMentionClick, false);
}
}

return () => {
for (const link of links) {
if (
link.textContent?.[0] === '#' ||
link.previousSibling?.textContent?.endsWith('#')
) {
link.removeEventListener('click', handleHashtagClick);
} else if (link.classList.contains('mention')) {
link.removeEventListener('click', handleMentionClick);
}
}
};
}, [note, handleHashtagClick, handleMentionClick]);
const ref = useLinks(note);

if (note.length === 0 || note === '<p></p>') {
return null;
Expand Down
77 changes: 2 additions & 75 deletions app/javascript/mastodon/components/account_fields.tsx
Original file line number Diff line number Diff line change
@@ -1,87 +1,14 @@
import { useEffect, useRef, useCallback } from 'react';

import classNames from 'classnames';
import { useHistory } from 'react-router-dom';

import CheckIcon from '@/material-icons/400-24px/check.svg?react';
import { openURL } from 'mastodon/actions/search';
import { useLinks } from 'mastodon/../hooks/useLinks';
import { Icon } from 'mastodon/components/icon';
import type { Account } from 'mastodon/models/account';
import { useAppDispatch } from 'mastodon/store';

export const AccountFields: React.FC<{
fields: Account['fields'];
}> = ({ fields }) => {
const ref = useRef<HTMLDivElement>(null);
const history = useHistory();
const dispatch = useAppDispatch();

const handleHashtagClick = useCallback(
(e: MouseEvent) => {
const { currentTarget } = e;
if (!(currentTarget instanceof HTMLElement)) return;

if (e.button === 0 && !(e.ctrlKey || e.metaKey)) {
const { textContent } = currentTarget;
if (!textContent) return;

e.preventDefault();
history.push(`/tags/${textContent.replace(/^#/, '')}`);
}
},
[history],
);

const handleMentionClick = useCallback(
(e: MouseEvent) => {
const { currentTarget } = e;

if (!(currentTarget instanceof HTMLAnchorElement)) return;

if (e.button === 0 && !(e.ctrlKey || e.metaKey)) {
e.preventDefault();

dispatch(
openURL(currentTarget.href, history, () => {
window.location.href = currentTarget.href;
}),
);
}
},
[dispatch, history],
);

useEffect(() => {
if (!ref.current) {
return;
}

const links = ref.current.querySelectorAll<HTMLAnchorElement>('a');

for (const link of links) {
if (
link.textContent?.[0] === '#' ||
link.previousSibling?.textContent?.endsWith('#')
) {
link.addEventListener('click', handleHashtagClick, false);
} else if (link.classList.contains('mention')) {
link.addEventListener('click', handleMentionClick, false);
}
}

return () => {
for (const link of links) {
if (
link.textContent?.[0] === '#' ||
link.previousSibling?.textContent?.endsWith('#')
) {
link.removeEventListener('click', handleHashtagClick);
} else if (link.classList.contains('mention')) {
link.removeEventListener('click', handleMentionClick);
}
}
};
}, [fields, handleHashtagClick, handleMentionClick]);
const ref = useLinks(fields);

if (fields.size === 0) {
return null;
Expand Down
2 changes: 1 addition & 1 deletion app/javascript/styles/mastodon-light/variables.scss
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ $emojis-requiring-inversion: 'chains';
--dropdown-border-color: #d9e1e8;
--dropdown-background-color: #fff;
--modal-border-color: #d9e1e8;
--modal-background-color: #fff;
--modal-background-color: var(--background-color-tint);
--background-border-color: #d9e1e8;
--background-color: #fff;
--background-color-tint: rgba(255, 255, 255, 90%);
Expand Down

0 comments on commit 6e80bca

Please sign in to comment.