mirror of
https://github.com/coracle-social/coracle.git
synced 2024-09-18 19:23:40 +00:00
Clean up and improve content parsing
This commit is contained in:
parent
26ba4fba71
commit
0896623253
@ -114,14 +114,11 @@ export const fromParentOffset = (element, offset): [HTMLElement, number] => {
|
||||
}
|
||||
|
||||
export const extractUrls = content => {
|
||||
const regex = /(https?:\/\/)?[-a-z0-9@:%._\+~#=\.]+\.[a-z]{1,6}[-a-z0-9@:%_\+.~#?!&//=;]*/gi
|
||||
const urls = content.match(regex)
|
||||
const regex = /((http|ws)s?:\/\/)?[-a-z0-9@:%_\+~#=\.]+\.[a-z]{1,6}[-a-z0-9:%_\+~#\?!&\/=;\.]*/gi
|
||||
const urls = content.match(regex) || []
|
||||
|
||||
return (
|
||||
(urls || [])
|
||||
// Skip decimals like 3.5 and ellipses which have more than one dot in a row
|
||||
.filter(url => !url.match(/^[\d\.]+$/) && !url.match(/\.{2}/))
|
||||
)
|
||||
// Skip stuff like 3.5 or U.S. and ellipses which have more than one dot in a row
|
||||
return urls.filter(url => !url.match(/^[.\.]+$/) && !url.match(/\.{2}/))
|
||||
}
|
||||
|
||||
export const renderContent = content => {
|
||||
|
@ -8,7 +8,7 @@
|
||||
import {quantify} from "hurdak/lib/hurdak"
|
||||
import {Tags, findRootId, findReplyId, displayPerson, isLike} from "src/util/nostr"
|
||||
import {formatTimestamp, now, tryJson, formatSats, fetchJson} from "src/util/misc"
|
||||
import {extractUrls, isMobile} from "src/util/html"
|
||||
import {isMobile} from "src/util/html"
|
||||
import {invoiceAmount} from "src/util/lightning"
|
||||
import QRCode from "src/partials/QRCode.svelte"
|
||||
import ImageInput from "src/partials/ImageInput.svelte"
|
||||
@ -17,12 +17,12 @@
|
||||
import Content from "src/partials/Content.svelte"
|
||||
import PersonSummary from "src/views/person/PersonSummary.svelte"
|
||||
import Popover from "src/partials/Popover.svelte"
|
||||
import PersonCircle from "src/partials/PersonCircle.svelte"
|
||||
import RelayCard from "src/views/relays/RelayCard.svelte"
|
||||
import Modal from "src/partials/Modal.svelte"
|
||||
import Preview from "src/partials/Preview.svelte"
|
||||
import Anchor from "src/partials/Anchor.svelte"
|
||||
import {toast, modal} from "src/app/ui"
|
||||
import {renderNote} from "src/app"
|
||||
import Compose from "src/partials/Compose.svelte"
|
||||
import Card from "src/partials/Card.svelte"
|
||||
import user from "src/agent/user"
|
||||
@ -35,7 +35,7 @@
|
||||
import cmd from "src/agent/cmd"
|
||||
import {routes} from "src/app/ui"
|
||||
import {publishWithToast} from "src/app"
|
||||
import PersonCircle from "src/partials/PersonCircle.svelte"
|
||||
import NoteContent from "src/views/notes/NoteContent.svelte"
|
||||
|
||||
export let note
|
||||
export let depth = 0
|
||||
@ -58,7 +58,6 @@
|
||||
const {profile, canPublish, mutes} = user
|
||||
const timestamp = formatTimestamp(note.created_at)
|
||||
const borderColor = invertColors ? "gray-6" : "gray-7"
|
||||
const links = extractUrls(note.content)
|
||||
const showEntire = anchorId === note.id
|
||||
const interactive = !anchorId || !showEntire
|
||||
const person = watch("people", () => getPersonWithFallback(note.pubkey))
|
||||
@ -402,14 +401,7 @@
|
||||
You have muted this note.
|
||||
</p>
|
||||
{:else}
|
||||
<div class="flex flex-col gap-2 overflow-hidden text-ellipsis">
|
||||
<p>{@html renderNote(note, {showEntire})}</p>
|
||||
{#if user.getSetting("showMedia") && links.length > 0}
|
||||
<button class="inline-block" on:click={e => e.stopPropagation()}>
|
||||
<Preview url={last(links)} />
|
||||
</button>
|
||||
{/if}
|
||||
</div>
|
||||
<NoteContent {note} {showEntire} />
|
||||
{/if}
|
||||
<div class="flex justify-between text-gray-1">
|
||||
<div
|
||||
|
87
src/views/notes/NoteContent.svelte
Normal file
87
src/views/notes/NoteContent.svelte
Normal file
@ -0,0 +1,87 @@
|
||||
<script lang="ts">
|
||||
import {last, uniq, trim} from "ramda"
|
||||
import {doPipe, ellipsize} from "hurdak/lib/hurdak"
|
||||
import {extractUrls, escapeHtml} from "src/util/html"
|
||||
import {displayPerson} from "src/util/nostr"
|
||||
import Preview from "src/partials/Preview.svelte"
|
||||
import user from "src/agent/user"
|
||||
import {getPersonWithFallback} from "src/agent/tables"
|
||||
import {routes} from "src/app/ui"
|
||||
|
||||
const canPreview = url => url.match("\.(jpg|jpeg|png|gif|mov|mp4)")
|
||||
|
||||
export let note
|
||||
export let showEntire
|
||||
|
||||
const links = uniq(extractUrls(note.content))
|
||||
const content = doPipe(note.content, [
|
||||
trim,
|
||||
escapeHtml,
|
||||
c => (showEntire || c.length < 800 ? c : ellipsize(c, 400)),
|
||||
c => {
|
||||
// Pad content with whitespace to simplify our regular expressions
|
||||
c = `<br>${c}<br>`
|
||||
|
||||
for (let url of links) {
|
||||
// It's common for punctuation to end a url, trim it off
|
||||
if (url.match(/[\.\?,:]$/)) {
|
||||
url = url.slice(0, -1)
|
||||
}
|
||||
|
||||
const href = url.includes("://") ? url : "https://" + url
|
||||
const display = url.replace(/(http|ws)s?:\/\/(www\.)?/, "").replace(/[\.\/?;,:]$/, "")
|
||||
const escaped = url.replace(/([.*+?^${}()|[\]\\])/g, "\\$1")
|
||||
const wsRegex = new RegExp(`<br>${escaped}<br>`, "g")
|
||||
const slashRegex = new RegExp(`\/${escaped}`, "g")
|
||||
|
||||
// Skip stuff that's just at the end of a filepath
|
||||
if (c.match(slashRegex)) {
|
||||
continue
|
||||
}
|
||||
|
||||
// If the url is on its own line, remove it entirely
|
||||
if (c.match(wsRegex) && canPreview(url)) {
|
||||
c = c.replace(wsRegex, '')
|
||||
continue
|
||||
}
|
||||
|
||||
// Avoid matching urls inside quotes to avoid double-replacing
|
||||
const quoteRegex = new RegExp(`([^"]*)(${escaped})([^"]*)`, "g")
|
||||
|
||||
const $a = document.createElement("a")
|
||||
|
||||
$a.href = href
|
||||
$a.target = "_blank"
|
||||
$a.className = "underline"
|
||||
$a.innerText = ellipsize(display, 50)
|
||||
|
||||
c = c.replace(quoteRegex, `$1${$a.outerHTML}$3`)
|
||||
}
|
||||
|
||||
return c.trim()
|
||||
},
|
||||
// Mentions
|
||||
c =>
|
||||
c.replace(/#\[(\d+)\]/g, (tag, i) => {
|
||||
if (!note.tags[parseInt(i)]) {
|
||||
return tag
|
||||
}
|
||||
|
||||
const pubkey = note.tags[parseInt(i)][1]
|
||||
const person = getPersonWithFallback(pubkey)
|
||||
const name = displayPerson(person)
|
||||
const path = routes.person(pubkey)
|
||||
|
||||
return `@<a href="${path}" class="underline">${name}</a>`
|
||||
}),
|
||||
])
|
||||
</script>
|
||||
|
||||
<div class="flex flex-col gap-2 overflow-hidden text-ellipsis">
|
||||
<p>{@html content}</p>
|
||||
{#if user.getSetting("showMedia") && links.length > 0}
|
||||
<button class="inline-block" on:click={e => e.stopPropagation()}>
|
||||
<Preview url={last(links)} />
|
||||
</button>
|
||||
{/if}
|
||||
</div>
|
Loading…
Reference in New Issue
Block a user