fun String.toRawLink() = substringBeforeLast('#') + ".raw"
enum class TextParserRawPageTag(val type: TextParserTagType<Unit>) {
+ B(
+ TextParserTagType.Direct(
+ false,
+ { _, _ -> "<span data-format=\"b\">" },
+ { _ -> "</span>" },
+ )
+ ),
+ I(
+ TextParserTagType.Direct(
+ false,
+ { _, _ -> "<span data-format=\"i\">" },
+ { _ -> "</span>" },
+ )
+ ),
+ U(
+ TextParserTagType.Direct(
+ false,
+ { _, _ -> "<span data-format=\"u\">" },
+ { _ -> "</span>" },
+ )
+ ),
+ S(
+ TextParserTagType.Direct(
+ false,
+ { _, _ -> "<span data-format=\"s\">" },
+ { _ -> "</span>" },
+ )
+ ),
IPA(
TextParserTagType.Direct(
false,
- { _, _ -> "" },
- { _ -> "" },
+ { _, _ -> "<span data-format=\"ipa\">" },
+ { _ -> "</span>" },
)
),
CODE(
TextParserTagType.Direct(
false,
- { _, _ -> "<span style='font-family: monospace'>" },
+ { _, _ -> "<span data-format=\"code\">" },
{ _ -> "</span>" },
)
),
CODE_BLOCK(
TextParserTagType.Direct(
false,
- { _, _ -> "<div style='font-family: monospace'><pre>" },
+ { _, _ -> "<div data-format=\"code\"><pre>" },
{ _ -> "</pre></div>" },
)
),
{ _ -> "</h6>" }
)
),
+ ALIGN(
+ TextParserTagType.Direct(
+ true,
+ { tagParam, _ ->
+ val alignments = setOf("left", "center", "right", "justify")
+ val alignment = tagParam?.takeIf { it in alignments }
+ val styleAttr = alignment?.let { " data-align=\"$it\"" }.orEmpty()
+ "<div$styleAttr>"
+ },
+ { _ -> "</div>" },
+ )
+ ),
ASIDE(
TextParserTagType.Direct(
true,
{ tagParam, _ ->
val floats = setOf("left", "right")
val float = tagParam?.takeIf { it in floats } ?: "right"
- "<div style='float: $float; max-width: 50vw'>"
+ "<div data-aside=\"$float\">"
},
{ _ -> "</div>" },
)
File(Configuration.CurrentConfiguration.assetDir, "images")
.combineSafe(imageUrl)
.readText()
- .replace("<svg", "<svg${getRawImageSizeAttributes(width, height)}")
+ .replaceFirst("<svg", "<svg${getRawImageSizeAttributes(width, height)}")
else
- "<img${getRawImageSizeAttributes(width, height)} src='/assets/images/$imageUrl'/>"
+ "<img${getRawImageSizeAttributes(width, height)} src=\"/assets/images/$imageUrl\"/>"
}
),
MODEL(
TABLE(
TextParserTagType.Direct(
true,
- { _, _ -> "<table style='width: 100%; table-layout: fixed'>" },
+ { _, _ -> "<table>" },
{ _ -> "</table>" },
)
),
val (width, height) = getSizeParam(tagParam)
val sizeAttrs = getTableSizeAttributes(width, height)
- "<td$sizeAttrs style='border: 1px solid #555'>"
+ "<td$sizeAttrs>"
},
{ _ -> "</td>" },
)
val (width, height) = getSizeParam(tagParam)
val sizeAttrs = getTableSizeAttributes(width, height)
- "<th$sizeAttrs style='border: 1px solid #222'>"
+ "<th$sizeAttrs>"
},
{ _ -> "</th>" },
)
{ tagParam, _ ->
val param = tagParam?.let { TextParserState.censorText(it) }
val url = param?.let { if (it.startsWith('/')) "/lore$it" else "./$it" }
- val attr = url?.let { " href=\"${it.toRawLink()}\"" } ?: ""
+ val attr = url?.let { " href=\"${it.toRawLink()}\"" }.orEmpty()
"<a$attr>"
},
val target = TextParserState.censorText(content)
val url = if (target.startsWith('/')) "/lore$target" else "./$target"
- "<a href='${url.toRawLink()}'>Click here for a manual redirect</a>"
+ "<a href=\"${url.toRawLink()}\">Click here for a manual redirect</a>"
}
),
LANG(
TextParserTagType.Direct(
false,
- { _, _ -> "<span style='font-style: italic'>" },
+ { param, _ ->
+ val lang = param?.let { sanitizeLang(it) } ?: "foreign"
+ "<span style=\"lang-$lang\">"
+ },
{ _ -> "</span>" }
)
),
}
}
-fun getRawImageSizeStyleValue(width: Int?, height: Int?) = (width?.let { "width: ${it * 0.25}px;" } ?: "") + (height?.let { "height: ${it * 0.25}px;" } ?: "")
-fun getRawImageSizeAttributes(width: Int?, height: Int?) = " style=\"${getRawImageSizeStyleValue(width, height)}\""
+fun getRawImageSizeStyleValue(width: Int?, height: Int?) = width?.let { "width:${it * 0.25}px;" }.orEmpty() + height?.let { "height:${it * 0.25}px;" }.orEmpty()
+fun getRawImageSizeAttributes(width: Int?, height: Int?) = width?.let { " data-width=\"$it\"" }.orEmpty() + height?.let { " data-height=\"$it\"" }.orEmpty() + " style=\"${getRawImageSizeStyleValue(width, height)}\""
+
+val NON_LANG_CHAR = Regex("[^a-z0-9\\-]")
+fun sanitizeLang(attr: String) = attr.replace(NON_LANG_CHAR, "")
B(
TextParserTagType.Direct(
false,
- { _, _ -> "<span style='font-weight: bold'>" },
+ { _, _ -> "<span style=\"font-weight:bold\">" },
{ _ -> "</span>" },
)
),
I(
TextParserTagType.Direct(
false,
- { _, _ -> "<span style='font-style: italic'>" },
+ { _, _ -> "<span style=\"font-style:italic\">" },
{ _ -> "</span>" },
)
),
U(
TextParserTagType.Direct(
false,
- { _, _ -> "<span style='text-decoration: underline'>" },
+ { _, _ -> "<span style=\"text-decoration:underline\">" },
{ _ -> "</span>" },
)
),
S(
TextParserTagType.Direct(
false,
- { _, _ -> "<span style='text-decoration: line-through'>" },
+ { _, _ -> "<span style=\"text-decoration:line-through\">" },
{ _ -> "</span>" },
)
),
false,
{ tagParam, _ ->
val color = tagParam?.toIntOrNull(16)?.toString(16)?.padStart(6, '0')
- val style = color?.let { " style=\"color: #$it\"" } ?: ""
+ val style = color?.let { " style=\"color:#$it\"" }.orEmpty()
"<span$style>"
},
{ _ -> "</span>" },
IPA(
TextParserTagType.Direct(
false,
- { _, _ -> "<span style='font-family: DejaVu Sans'>" },
+ { _, _ -> "<span style=\"font-family:DejaVu Sans\">" },
{ _ -> "</span>" },
)
),
CODE(
TextParserTagType.Direct(
false,
- { _, _ -> "<span style='font-family: JetBrains Mono'>" },
+ { _, _ -> "<span style=\"font-family:JetBrains Mono\">" },
{ _ -> "</span>" },
)
),
CODE_BLOCK(
TextParserTagType.Direct(
true,
- { _, _ -> "<div style='font-family: JetBrains Mono'><pre>" },
+ { _, _ -> "<div style=\"font-family:JetBrains Mono\"><pre>" },
{ _ -> "</pre></div>" },
)
),
H1(
TextParserTagType.Indirect(true) { _, content, _ ->
- "<h1>$content</h1><script>window.checkRedirectTarget('');</script>"
+ "<h1>$content</h1><script>window.checkRedirectTarget(\"\");</script>"
}
),
H2(
TextParserTagType.Indirect(true) { _, content, _ ->
val anchor = headerContentToAnchor(content)
- "</section><section><h2><a id='$anchor'></a>$content</h2><script>window.checkRedirectTarget('#$anchor');</script>"
+ "</section><section><h2><a id=\"$anchor\"></a>$content</h2><script>window.checkRedirectTarget(\"#$anchor\");</script>"
}
),
H3(
TextParserTagType.Indirect(true) { _, content, _ ->
val anchor = headerContentToAnchor(content)
- "<h3><a id='$anchor'></a>$content</h3><script>window.checkRedirectTarget('#$anchor');</script>"
+ "<h3><a id=\"$anchor\"></a>$content</h3><script>window.checkRedirectTarget(\"#$anchor\");</script>"
}
),
H4(
TextParserTagType.Indirect(true) { _, content, _ ->
val anchor = headerContentToAnchor(content)
- "<h4><a id='$anchor'></a>$content</h4><script>window.checkRedirectTarget('#$anchor');</script>"
+ "<h4><a id=\"$anchor\"></a>$content</h4><script>window.checkRedirectTarget(\"#$anchor\");</script>"
}
),
H5(
TextParserTagType.Indirect(true) { _, content, _ ->
val anchor = headerContentToAnchor(content)
- "<h5><a id='$anchor'></a>$content</h5><script>window.checkRedirectTarget('#$anchor');</script>"
+ "<h5><a id=\"$anchor\"></a>$content</h5><script>window.checkRedirectTarget(\"#$anchor\");</script>"
}
),
H6(
TextParserTagType.Indirect(true) { _, content, _ ->
val anchor = headerContentToAnchor(content)
- "<h6><a id='$anchor'></a>$content</h6><script>window.checkRedirectTarget('#$anchor');</script>"
+ "<h6><a id=\"$anchor\"></a>$content</h6><script>window.checkRedirectTarget(\"#$anchor\");</script>"
}
),
ALIGN(
{ tagParam, _ ->
val alignments = setOf("left", "center", "right", "justify")
val alignment = tagParam?.takeIf { it in alignments }
- val styleAttr = alignment?.let { " style=\"text-align: $it\"" } ?: ""
+ val styleAttr = alignment?.let { " style=\"text-align:$it\"" }.orEmpty()
"<div$styleAttr>"
},
{ _ -> "</div>" },
{ tagParam, _ ->
val floats = setOf("left", "right")
val float = tagParam?.takeIf { it in floats } ?: "right"
- "<div style='float: $float; max-width: var(--aside-width)'>"
+ "<div style=\"float:$float;max-width:var(--aside-width)\">"
},
{ _ -> "</div>" },
)
File(Configuration.CurrentConfiguration.assetDir, "images")
.combineSafe(imageUrl)
.readText()
- .replace("<svg", "<svg${getImageSizeAttributes(width, height)}")
+ .replaceFirst("<svg", "<svg${getImageSizeAttributes(width, height)}")
else
- "<script>window.appendImageThumb('/assets/images/$imageUrl', '${getImageSizeStyleValue(width, height)}');</script>"
+ "<script>window.appendImageThumb(\"/assets/images/$imageUrl\", \"${getImageSizeStyleValue(width, height)}\");</script>"
}
),
MODEL(
{ tagParam, _ ->
val param = tagParam?.let { TextParserState.censorText(it) }
val url = param?.let { if (it.startsWith('/')) "/lore$it" else "./$it" }
- val attr = url?.let { " href=\"$it\"" } ?: ""
+ val attr = url?.let { " href=\"$it\"" }.orEmpty()
"<a$attr>"
},
false,
{ tagParam, _ ->
val url = tagParam?.let { TextParserState.censorText(it) }
- val attr = url?.let { " href=\"$it\"" } ?: ""
+ val attr = url?.let { " href=\"$it\"" }.orEmpty()
"<a$attr>"
},
false,
{ tagParam, _ ->
val url = tagParam?.let { TextParserState.censorText(it) }
- val attr = url?.let { " href=\"$it\" rel=\"ugc nofollow\"" } ?: ""
+ val attr = url?.let { " href=\"$it\" rel=\"ugc nofollow\"" }.orEmpty()
"<a$attr>"
},
val imageUrl = sanitizeExtLink(content)
val (width, height) = getSizeParam(tagParam)
- "<img src='https://i.imgur.com/$imageUrl'${getImageSizeAttributes(width, height)}/>"
+ "<img src=\"https://i.imgur.com/$imageUrl\"${getImageSizeAttributes(width, height)}/>"
}
),
IMGBB(
val imageUrl = sanitizeExtLink(content)
val (width, height) = getSizeParam(tagParam)
- "<img src='https://i.ibb.co/$imageUrl'${getImageSizeAttributes(width, height)}/>"
+ "<img src=\"https://i.ibb.co/$imageUrl\"${getImageSizeAttributes(width, height)}/>"
}
),
parts.getOrNull(0)?.toIntOrNull() to parts.getOrNull(1)?.toIntOrNull()
} ?: (null to null)
-fun getTableSizeAttributes(width: Int?, height: Int?) = (width?.let { " colspan=\"$it\"" } ?: "") + (height?.let { " rowspan=\"$it\"" } ?: "")
-fun getImageSizeStyleValue(width: Int?, height: Int?) = (width?.let { "width: calc(var(--media-size-unit) * $it);" } ?: "") + (height?.let { "height: calc(var(--media-size-unit) * $it);" } ?: "")
+fun getTableSizeAttributes(width: Int?, height: Int?) = width?.let { " colspan=\"$it\"" }.orEmpty() + height?.let { " rowspan=\"$it\"" }.orEmpty()
+fun getImageSizeStyleValue(width: Int?, height: Int?) = width?.let { "width: calc(var(--media-size-unit) * $it);" }.orEmpty() + height?.let { "height: calc(var(--media-size-unit) * $it);" }.orEmpty()
fun getImageSizeAttributes(width: Int?, height: Int?) = " style=\"${getImageSizeStyleValue(width, height)}\""
val NON_ANCHOR_CHAR = Regex("[^a-zA-Z\\d\\-]")