1
0

feat: clean shared link in the parsed html if conditions are met

This commit is contained in:
Ayo 2023-01-29 00:39:03 +01:00
parent 0b3d32e821
commit 075a9d115b
5 changed files with 47 additions and 5 deletions

View File

@ -5,15 +5,29 @@ const {
status, status,
newer, newer,
withAction = true, withAction = true,
cleanSharedLink,
} = defineProps<{ } = defineProps<{
status: mastodon.v1.Status | mastodon.v1.StatusEdit status: mastodon.v1.Status | mastodon.v1.StatusEdit
newer?: mastodon.v1.Status newer?: mastodon.v1.Status
withAction?: boolean withAction?: boolean
cleanSharedLink?: string | false
}>() }>()
const { translation } = useTranslation(status, getLanguageCode()) const { translation } = useTranslation(status, getLanguageCode())
const emojisObject = useEmojisFallback(() => status.emojis) const emojisObject = useEmojisFallback(() => status.emojis)
/**
* example status raw content
*
* <p>🔴 trying to code live - come let&#39;s talk <span class="h-card"><a href="https://m.webtoo.ls/@elk" class="u-url mention">@<span>elk</span></a></span> and <a href="https://social.ayco.io/tags/opensource" class="mention hashtag" rel="tag">#<span>opensource</span></a> <a href="https://www.twitch.tv/ayoayco" target="_blank" rel="nofollow noopener noreferrer"><span class="invisible">https://www.</span><span class="">twitch.tv/ayoayco</span><span class="invisible"></span></a></p>
*
*
* "<p>I say something about the link first</p><p><a href=\"https://ayco.io\" target=\"_blank\" rel=\"nofollow noopener noreferrer\"><span class=\"invisible\">https://</span><span class=\"\">ayco.io</span><span class=\"invisible\"></span></a></p>"
*
*/
const vnode = $computed(() => { const vnode = $computed(() => {
if (!status.content) if (!status.content)
return null return null
@ -24,7 +38,9 @@ const vnode = $computed(() => {
collapseMentionLink: !!('inReplyToId' in status && status.inReplyToId), collapseMentionLink: !!('inReplyToId' in status && status.inReplyToId),
status: 'id' in status ? status : undefined, status: 'id' in status ? status : undefined,
inReplyToStatus: newer, inReplyToStatus: newer,
cleanSharedLink,
}) })
return vnode return vnode
}) })
</script> </script>

View File

@ -16,6 +16,10 @@ const filter = $computed(() => filterResult?.filter)
const filterPhrase = $computed(() => filter?.title) const filterPhrase = $computed(() => filter?.title)
const isFiltered = $computed(() => filterPhrase && (context && context !== 'details' ? filter?.context.includes(context) : false)) const isFiltered = $computed(() => filterPhrase && (context && context !== 'details' ? filter?.context.includes(context) : false))
const cleanSharedLink = !status.poll
&& !status.mediaAttachments.length
&& status.card?.url
</script> </script>
<template> <template>
@ -34,7 +38,7 @@ const isFiltered = $computed(() => filterPhrase && (context && context !== 'deta
<template v-else-if="status.spoilerText" #spoiler> <template v-else-if="status.spoilerText" #spoiler>
<p>{{ status.spoilerText }}</p> <p>{{ status.spoilerText }}</p>
</template> </template>
<StatusBody v-if="!status.sensitive || status.spoilerText" :status="status" :newer="newer" :with-action="!isDetails" :class="isDetails ? 'text-xl' : ''" /> <StatusBody v-if="!status.sensitive || status.spoilerText" :clean-shared-link="cleanSharedLink" :status="status" :newer="newer" :with-action="!isDetails" :class="isDetails ? 'text-xl' : ''" />
<StatusTranslation :status="status" /> <StatusTranslation :status="status" />
<StatusPoll v-if="status.poll" :status="status" /> <StatusPoll v-if="status.poll" :status="status" />
<StatusMedia <StatusMedia
@ -45,6 +49,7 @@ const isFiltered = $computed(() => filterPhrase && (context && context !== 'deta
v-if="status.card" v-if="status.card"
:card="status.card" :card="status.card"
:small-picture-only="status.mediaAttachments?.length > 0" :small-picture-only="status.mediaAttachments?.length > 0"
:clean-shared-link="cleanSharedLink"
/> />
<StatusCard <StatusCard
v-if="status.reblog" v-if="status.reblog"

View File

@ -7,15 +7,16 @@ const props = defineProps<{
smallPictureOnly?: boolean smallPictureOnly?: boolean
/** When it is root card in the list, not appear as a child card */ /** When it is root card in the list, not appear as a child card */
root?: boolean root?: boolean
/** Defined when the preview card URL matches the last shared link href attribute */
cleanSharedLink?: string
}>() }>()
const providerName = $computed(() => props.card.providerName ? props.card.providerName : new URL(props.card.url).hostname) const providerName = $computed(() => props.card.providerName ? props.card.providerName : new URL(props.card.url).hostname)
const gitHubCards = $(usePreferences('experimentalGitHubCards')) const gitHubCards = $(usePreferences('experimentalGitHubCards'))
</script> </script>
<template> <template>
<LazyStatusPreviewGitHub v-if="gitHubCards && providerName === 'GitHub'" :card="card" /> <LazyStatusPreviewGitHub v-if="gitHubCards && providerName === 'GitHub'" :card="card" />
<LazyStatusPreviewStackBlitz v-else-if="gitHubCards && providerName === 'stackblitz.com'" :card="card" :small-picture-only="smallPictureOnly" :root="root" /> <LazyStatusPreviewStackBlitz v-else-if="gitHubCards && providerName === 'stackblitz.com'" :card="card" :small-picture-only="smallPictureOnly" :root="root" />
<StatusPreviewCardNormal v-else :card="card" :small-picture-only="smallPictureOnly" :root="root" /> <StatusPreviewCardNormal v-else :card="card" :clean-shared-link="cleanSharedLink" :small-picture-only="smallPictureOnly" :root="root" />
</template> </template>

View File

@ -7,6 +7,8 @@ const props = defineProps<{
smallPictureOnly?: boolean smallPictureOnly?: boolean
/** When it is root card in the list, not appear as a child card */ /** When it is root card in the list, not appear as a child card */
root?: boolean root?: boolean
/** Defined when the preview card URL matches the last shared link href attribute */
cleanSharedLink?: string
}>() }>()
// mastodon's default max og image width // mastodon's default max og image width
@ -19,7 +21,7 @@ const isSquare = $computed(() => (
|| Number(props.card.width || 0) < ogImageWidth || Number(props.card.width || 0) < ogImageWidth
|| Number(props.card.height || 0) < ogImageWidth / 2 || Number(props.card.height || 0) < ogImageWidth / 2
)) ))
const providerName = $computed(() => props.card.providerName ? props.card.providerName : new URL(props.card.url).hostname) const providerName = $computed(() => props.card.providerName ? `${props.card.providerName} · ${props.cleanSharedLink}` : new URL(props.card.url).hostname)
// TODO: handle card.type: 'photo' | 'video' | 'rich'; // TODO: handle card.type: 'photo' | 'video' | 'rich';
const cardTypeIconMap: Record<mastodon.v1.PreviewCardType, string> = { const cardTypeIconMap: Record<mastodon.v1.PreviewCardType, string> = {

View File

@ -16,6 +16,7 @@ export interface ContentParseOptions {
collapseMentionLink?: boolean collapseMentionLink?: boolean
status?: mastodon.v1.Status status?: mastodon.v1.Status
inReplyToStatus?: mastodon.v1.Status inReplyToStatus?: mastodon.v1.Status
cleanSharedLink?: string | false // this is defined when conditions for cleaning the link are met
} }
const sanitizerBasicClasses = filterClasses(/^(h-\S*|p-\S*|u-\S*|dt-\S*|e-\S*|mention|hashtag|ellipsis|invisible)$/u) const sanitizerBasicClasses = filterClasses(/^(h-\S*|p-\S*|u-\S*|dt-\S*|e-\S*|mention|hashtag|ellipsis|invisible)$/u)
@ -84,6 +85,7 @@ export function parseMastodonHTML(
mentions, mentions,
status, status,
inReplyToStatus, inReplyToStatus,
cleanSharedLink,
} = options } = options
if (markdown) { if (markdown) {
@ -127,7 +129,23 @@ export function parseMastodonHTML(
if (collapseMentionLink) if (collapseMentionLink)
transforms.push(transformCollapseMentions(status, inReplyToStatus)) transforms.push(transformCollapseMentions(status, inReplyToStatus))
return transformSync(parse(html), transforms) const node = parse(html) as Node
if (cleanSharedLink) {
const filteredNode = node.children.filter(child => !!child.children) // remove invisible spans
const filteredLength = filteredNode.length
const length = filteredNode[filteredLength - 1].children.length
const lastChild = filteredNode[filteredLength - 1].children[length - 1]
const sharedHref = lastChild.attributes?.href
const match = sharedHref === cleanSharedLink
if (match) {
const index = length - 1
filteredNode[filteredLength - 1].children.splice(index, 1)
}
}
return transformSync(node, transforms)
} }
/** /**