feat: set target="_blank" on every anchor element in text blocks; closes #179

This commit is contained in:
Hossein Mehrabi 2023-09-05 23:53:12 +03:30
parent 9e7dad6b8d
commit ce6af994ea
No known key found for this signature in database
GPG Key ID: 45C04964191AFAA1
4 changed files with 43 additions and 9 deletions

View File

@ -53,6 +53,7 @@ const EpisodeChannelContainer = styled.div`
align-items: center;
margin-top: 32px;
margin-bottom: 32px;
flex-wrap: wrap;
${(props) => lsdUtils.breakpoint(props.theme, 'xs', 'down')} {
margin-top: 24px;

View File

@ -66,6 +66,8 @@ const SearchBox = (props: SearchBoxProps) => {
showModeSwitch = true,
} = props
const hydrated = useHydrated()
const [filterTags, setFilterTags] = useQueryParam(
'topic',
withDefault(ArrayParam, []),
@ -96,14 +98,9 @@ const SearchBox = (props: SearchBoxProps) => {
const [whereResultsStick, setWhereResultsStick] = useState(0)
const [showDetails, setShowDetails] = useState(false)
const [detailsTop, setDetailsTop] = useState(0)
const [mounted, setMounted] = useState(false)
const [focused, setFocused] = useState(false)
const [showClear, setShowClear] = useState(false)
useEffect(() => {
setMounted(true)
return () => setMounted(false)
}, [])
const handleViewChange = async (n: string) => {
setView(n)
onViewChange(n)
@ -185,8 +182,6 @@ const SearchBox = (props: SearchBoxProps) => {
// if (query !== queryInput) setQuery(queryInput)
// }, [focused, query, queryInput])
const hydrated = useHydrated()
return (
<Container
className={enlargeQuery ? 'active' : ''}

View File

@ -1,4 +1,5 @@
import { LPE } from '../../../types/lpe.types'
import { setAttributeOnHTML } from '../../../utils/html.utils'
import { convertToIframe } from '../../../utils/string.utils'
import { UnbodyResGoogleDocData, UnbodyResTextBlockData } from '../unbody.types'
import { UnbodyDataTypeConfig } from './types'
@ -16,7 +17,7 @@ export const TextBlockDataType: UnbodyDataTypeConfig<
isMatch: (helpers, data, original, root) => data.__typename === 'TextBlock',
transform: (helpers, data, original, root) => {
const { text = '', html = '' } = data
let { text = '', html = '' } = data
const labels: LPE.Post.ContentBlockLabel[] = []
let embed: LPE.Post.TextBlockEmbed | null = null
@ -67,10 +68,23 @@ export const TextBlockDataType: UnbodyDataTypeConfig<
}
}
// set target="_blank" on anchor elements
{
const matches = Array.from(
html.matchAll(/<a[^>]*href="http[^>]*"[^>]*>/gi),
)
for (const match of matches) {
const [anchorHTML] = match
const newAnchorHTML = setAttributeOnHTML(anchorHTML, 'target', '_blank')
html = html.replace(anchorHTML, newAnchorHTML)
}
}
return {
id: data?._additional?.id || `${data.order}`,
type: 'text',
html: data.html,
html,
text: data.text || '',
classNames: data.classNames,
footnotes: data.footnotesObj,

View File

@ -38,6 +38,30 @@ export function extractAttributeFromHTML(
)
}
export const setAttributeOnHTML = (
html: string,
attribute: string,
value: string,
) => {
let result = html.trim()
const tagName = html.match(/^<([\w])+/)?.[0]?.slice(1)!
const current = extractAttributeFromHTML(html, attribute)
if (current) {
const currentAttribute = `${attribute}="${current}"`
const index = html.indexOf(currentAttribute)
result =
result.slice(0, index) + result.slice(index + currentAttribute.length + 1)
}
result = `<${tagName} ${attribute}="${value}"${result.slice(
tagName.length + 1,
)}`
return result
}
export const isAuthorsParagraph = (html: string) => {
const regex = /<a\s+[^>]*href="mailto:([^"]+)"[^>]*>([^<]+)<\/a>/g
const matches = html.match(regex)