Lalle 27d267b4f0
Revert "Typescript and more"
This reverts commit 12483e97c52eb96965811a8e6c4c28cd3c45b19f.
2023-04-16 21:54:11 +02:00

247 lines
6.3 KiB
JavaScript

import Callbacks from '../classes/Callbacks'
// import Test from "../General/Test";
import { g, Conf } from '../globals/globals'
import ImageHost from '../Images/ImageHost'
import ExpandComment from '../Miscellaneous/ExpandComment'
import $ from '../platform/$'
import $$ from '../platform/$$'
import Embedding from './Embedding'
/*
* decaffeinate suggestions:
* DS102: Remove unnecessary code created because of implicit returns
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md
*/
var Linkify = {
init() {
if (!['index', 'thread', 'archive'].includes(g.VIEW) || !Conf['Linkify']) {
return
}
if (Conf['Comment Expansion']) {
ExpandComment.callbacks.push(this.node)
}
Callbacks.Post.push({
name: 'Linkify',
cb: this.node,
})
return Embedding.init()
},
node() {
let link
if (this.isClone) {
return Embedding.events(this)
}
if (!Linkify.regString.test(this.info.comment)) {
return
}
for (link of $$('a', this.nodes.comment)) {
if (g.SITE.isLinkified?.(link)) {
$.addClass(link, 'linkify')
if (ImageHost.useFaster) {
ImageHost.fixLinks([link])
}
Embedding.process(link, this)
}
}
const links = Linkify.process(this.nodes.comment)
if (ImageHost.useFaster) {
ImageHost.fixLinks(links)
}
for (link of links) {
Embedding.process(link, this)
}
},
process(node) {
let length
const test = /[^\s"]+/g
const space = /[\s"]/
const snapshot = $.X('.//br|.//text()', node)
let i = 0
const links = []
while ((node = snapshot.snapshotItem(i++))) {
var result
var { data } = node
if (!data || node.parentElement.nodeName === 'A') {
continue
}
while ((result = test.exec(data))) {
var { index } = result
var endNode = node
var word = result[0]
// End of node, not necessarily end of space-delimited string
if ((length = index + word.length) === data.length) {
var saved
test.lastIndex = 0
while ((saved = snapshot.snapshotItem(i++))) {
var end
if (
saved.nodeName === 'BR' ||
(saved.parentElement.nodeName === 'P' && !saved.previousSibling)
) {
var part1, part2
if (
// link deliberately split
(part1 = word.match(
/(https?:\/\/)?([a-z\d-]+\.)*[a-z\d-]+$/i,
)) &&
(part2 = snapshot
.snapshotItem(i)
?.data?.match(/^(\.[a-z\d-]+)*\//i)) &&
(part1[0] + part2[0]).search(Linkify.regString) === 0
) {
continue
} else {
break
}
}
if (
saved.parentElement.nodeName === 'A' &&
!Linkify.regString.test(word)
) {
break
}
endNode = saved
;({ data } = saved)
if ((end = space.exec(data))) {
// Set our snapshot and regex to start on this node at this position when the loop resumes
word += data.slice(0, end.index)
test.lastIndex = length = end.index
i--
break
} else {
;({ length } = data)
word += data
}
}
}
if (Linkify.regString.test(word)) {
links.push(Linkify.makeRange(node, endNode, index, length))
// <% if (readJSON('/.tests_enabled')) { %>
// if (links.length) {
// Test.assert(() => word === links[links.length - 1]?.toString());
// }
// <% } %>
}
if (!test.lastIndex || node !== endNode) {
break
}
}
}
i = links.length
while (i--) {
links[i] = Linkify.makeLink(links[i])
}
return links
},
regString: new RegExp(
`(\
\
(https?|mailto|git|magnet|ftp|irc):(\
[a-z\\d%/?]\
)\
|\
([-a-z\\d]+[.])+(\
aero|asia|biz|cat|com|coop|dance|info|int|jobs|mobi|moe|museum|name|net|org|post|pro|tel|travel|xxx|xyz|edu|gov|mil|[a-z]{2}\
)([:/]|(?![^\\s"]))\
|\
[\\d]{1,3}\\.[\\d]{1,3}\\.[\\d]{1,3}\\.[\\d]{1,3}\
|\
[-\\w\\d.@]+@[a-z\\d.-]+\\.[a-z\\d]\
)`,
'i',
),
makeRange(startNode, endNode, startOffset, endOffset) {
const range = document.createRange()
range.setStart(startNode, startOffset)
range.setEnd(endNode, endOffset)
return range
},
makeLink(range) {
let t
let encodedDomain
let text = range.toString()
// Clean start of range
let i = text.search(Linkify.regString)
if (i > 0) {
text = text.slice(i)
while (range.startOffset + i >= range.startContainer.data.length) {
i--
}
if (i) {
range.setStart(range.startContainer, range.startOffset + i)
}
}
// Clean end of range
i = 0
while (/[)\]}>.,]/.test((t = text.charAt(text.length - (1 + i))))) {
if (!/[.,]/.test(t) && !(text.match(/[()\[\]{}<>]/g).length % 2)) {
break
}
i++
}
if (i) {
text = text.slice(0, -i)
while (range.endOffset - i < 0) {
i--
}
if (i) {
range.setEnd(range.endContainer, range.endOffset - i)
}
}
// Make our link 'valid' if it is formatted incorrectly.
if (!/((mailto|magnet):|.+:\/\/)/.test(text)) {
text = (/@/.test(text) ? 'mailto:' : 'http://') + text
}
// Decode percent-encoded characters in domain so that they behave consistently across browsers.
if ((encodedDomain = text.match(/^(https?:\/\/[^/]*%[0-9a-f]{2})(.*)$/i))) {
text =
encodedDomain[1].replace(/%([0-9a-f]{2})/gi, function (x, y) {
if (y === '25') {
return x
} else {
return String.fromCharCode(parseInt(y, 16))
}
}) + encodedDomain[2]
}
const a = $.el('a', {
className: 'linkify',
rel: 'noreferrer noopener',
target: '_blank',
href: text,
})
// Insert the range into the anchor, the anchor into the range's DOM location, and destroy the range.
$.add(a, range.extractContents())
range.insertNode(a)
return a
},
}
export default Linkify