Two fixes: redirect target indicators are now more accurate in placing, and images...
authorLanius Trolling <lanius@laniustrolling.dev>
Tue, 18 Jul 2023 17:37:00 +0000 (13:37 -0400)
committerLanius Trolling <lanius@laniustrolling.dev>
Tue, 18 Jul 2023 17:37:00 +0000 (13:37 -0400)
.idea/kotlinc.xml
build.gradle.kts
src/main/kotlin/info/mechyrdia/lore/parser_tags.kt
src/main/kotlin/info/mechyrdia/lore/parser_toc.kt
src/main/resources/static/init.js

index 0fc3113136756acc4597486432227a66d5ebe736..9a55c2de1f41c0bb843e597ca7b85500604c46f7 100644 (file)
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <project version="4">
   <component name="KotlinJpsPluginSettings">
-    <option name="version" value="1.8.10" />
+    <option name="version" value="1.8.22" />
   </component>
 </project>
\ No newline at end of file
index 60b001ce139be7fc6ae439de92f8debc55d93fb8..88c681e0c96c6619db767f21ef6542cfaede89cc 100644 (file)
@@ -24,8 +24,8 @@ buildscript {
 
 plugins {
        java
-       kotlin("jvm") version "1.8.10"
-       kotlin("plugin.serialization") version "1.8.10"
+       kotlin("jvm") version "1.8.22"
+       kotlin("plugin.serialization") version "1.8.22"
        id("com.github.johnrengelman.shadow") version "7.1.2"
        application
 }
@@ -38,23 +38,23 @@ repositories {
 }
 
 dependencies {
-       implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.6.4")
-       implementation("org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.6.4")
-       implementation("org.jetbrains.kotlinx:kotlinx-coroutines-reactive:1.6.4")
-       implementation("org.jetbrains.kotlinx:kotlinx-serialization-core-jvm:1.5.0")
-       implementation("org.jetbrains.kotlinx:kotlinx-serialization-json-jvm:1.5.0")
+       implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.7.2")
+       implementation("org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.7.2")
+       implementation("org.jetbrains.kotlinx:kotlinx-coroutines-reactive:1.7.2")
+       implementation("org.jetbrains.kotlinx:kotlinx-serialization-core-jvm:1.5.1")
+       implementation("org.jetbrains.kotlinx:kotlinx-serialization-json-jvm:1.5.1")
        
-       implementation("io.ktor:ktor-server-core-jvm:2.3.1")
-       implementation("io.ktor:ktor-server-netty-jvm:2.3.1")
+       implementation("io.ktor:ktor-server-core-jvm:2.3.2")
+       implementation("io.ktor:ktor-server-netty-jvm:2.3.2")
        
-       implementation("io.ktor:ktor-server-call-id:2.3.1")
-       implementation("io.ktor:ktor-server-call-logging:2.3.1")
-       implementation("io.ktor:ktor-server-forwarded-header:2.3.1")
-       implementation("io.ktor:ktor-server-html-builder:2.3.1")
-       implementation("io.ktor:ktor-server-sessions-jvm:2.3.1")
-       implementation("io.ktor:ktor-server-status-pages:2.3.1")
+       implementation("io.ktor:ktor-server-call-id:2.3.2")
+       implementation("io.ktor:ktor-server-call-logging:2.3.2")
+       implementation("io.ktor:ktor-server-forwarded-header:2.3.2")
+       implementation("io.ktor:ktor-server-html-builder:2.3.2")
+       implementation("io.ktor:ktor-server-sessions-jvm:2.3.2")
+       implementation("io.ktor:ktor-server-status-pages:2.3.2")
        
-       implementation("org.jetbrains.kotlinx:kotlinx-html-jvm:0.8.1")
+       implementation("org.jetbrains.kotlinx:kotlinx-html-jvm:0.9.0")
        
        implementation("com.samskivert:jmustache:1.15")
        implementation("org.apache.groovy:groovy-jsr223:4.0.10")
index 8aaef54badfe525897b74054378e1f9e39cca20a..4b61fb6228936e01e3f7fb9e8af74c671d33b38a 100644 (file)
@@ -86,37 +86,37 @@ enum class TextParserFormattingTag(val type: TextParserTagType<Unit>) {
        ),
        H1(
                TextParserTagType.Indirect { _, content, _ ->
-                       "<h1>$content</h1><script>window.checkRedirectTarget();</script>"
+                       "<h1>$content</h1><script>window.checkRedirectTarget('');</script>"
                }
        ),
        H2(
                TextParserTagType.Indirect { _, content, _ ->
                        val anchor = headerContentToAnchor(content)
-                       "</section><section><h2><a id='$anchor'></a>$content</h2>"
+                       "</section><section><h2><a id='$anchor'></a>$content</h2><script>window.checkRedirectTarget('#$anchor');</script>"
                }
        ),
        H3(
                TextParserTagType.Indirect { _, content, _ ->
                        val anchor = headerContentToAnchor(content)
-                       "<h3><a id='$anchor'></a>$content</h3>"
+                       "<h3><a id='$anchor'></a>$content</h3><script>window.checkRedirectTarget('#$anchor');</script>"
                }
        ),
        H4(
                TextParserTagType.Indirect { _, content, _ ->
                        val anchor = headerContentToAnchor(content)
-                       "<h4><a id='$anchor'></a>$content</h4>"
+                       "<h4><a id='$anchor'></a>$content</h4><script>window.checkRedirectTarget('#$anchor');</script>"
                }
        ),
        H5(
                TextParserTagType.Indirect { _, content, _ ->
                        val anchor = headerContentToAnchor(content)
-                       "<h5><a id='$anchor'></a>$content</h5>"
+                       "<h5><a id='$anchor'></a>$content</h5><script>window.checkRedirectTarget('#$anchor');</script>"
                }
        ),
        H6(
                TextParserTagType.Indirect { _, content, _ ->
                        val anchor = headerContentToAnchor(content)
-                       "<h6><a id='$anchor'></a>$content</h6>"
+                       "<h6><a id='$anchor'></a>$content</h6><script>window.checkRedirectTarget('#$anchor');</script>"
                }
        ),
        ALIGN(
@@ -147,15 +147,13 @@ enum class TextParserFormattingTag(val type: TextParserTagType<Unit>) {
                        val imageUrl = sanitizeLink(content)
                        
                        val (width, height) = getSizeParam(tagParam)
-                       val sizeAttrs = getImageSizeAttributes(width, height)
                        
-                       if (imageUrl.endsWith(".svg")) {
-                               val imageFile = File(Configuration.CurrentConfiguration.assetDir, "images/$imageUrl")
-                               val imageSvg = imageFile.readText().replace("<svg", "<svg$sizeAttrs")
-                               
-                               imageSvg
-                       } else
-                               "<a class=\"thumb\" href=\"/assets/images/$imageUrl\" title=\"Click to view full size\"><img src=\"/assets/images/$imageUrl\"$sizeAttrs/></a>"
+                       if (imageUrl.endsWith(".svg"))
+                               File(Configuration.CurrentConfiguration.assetDir, "images/$imageUrl")
+                                       .readText()
+                                       .replace("<svg", "<svg${getImageSizeAttributes(width, height)}")
+                       else
+                               "<script>window.appendImageThumb('/assets/images/$imageUrl', '${getImageSizeStyleValue(width, height)}');</script>"
                }
        ),
        MODEL(
@@ -373,7 +371,8 @@ fun getSizeParam(tagParam: String?): Pair<Int?, Int?> = tagParam?.let { resoluti
 } ?: (null to null)
 
 fun getTableSizeAttributes(width: Int?, height: Int?) = (width?.let { " colspan=\"$it\"" } ?: "") + (height?.let { " rowspan=\"$it\"" } ?: "")
-fun getImageSizeAttributes(width: Int?, height: Int?) = " style=\"" + (width?.let { "width: calc(var(--media-size-unit) * $it);" } ?: "") + (height?.let { "height: calc(var(--media-size-unit) * $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 getImageSizeAttributes(width: Int?, height: Int?) = " style=\"${getImageSizeStyleValue(width, height)}\""
 
 val NON_ANCHOR_CHAR = Regex("[^a-zA-Z\\d\\-]")
 val INSIDE_TAG_TEXT = Regex("\\[.*?]")
index e36d3e6a11da96f3b8175892541655b93249cef5..c1e837c02d9e11af048e8ff001166702b8e9a453 100644 (file)
@@ -36,37 +36,37 @@ class TableOfContentsBuilder {
 
 enum class TextParserToCBuilderTag(val type: TextParserTagType<TableOfContentsBuilder>) {
        H1(
-               TextParserTagType.Indirect<TableOfContentsBuilder> { _, content, builder ->
+               TextParserTagType.Indirect { _, content, builder ->
                        builder.add(headerContentToLabel(content), 0, headerContentToAnchor(content))
                        "[h1]$content[/h1]"
                }
        ),
        H2(
-               TextParserTagType.Indirect<TableOfContentsBuilder> { _, content, builder ->
+               TextParserTagType.Indirect { _, content, builder ->
                        builder.add(headerContentToLabel(content), 1, headerContentToAnchor(content))
                        "[h2]$content[/h2]"
                }
        ),
        H3(
-               TextParserTagType.Indirect<TableOfContentsBuilder> { _, content, builder ->
+               TextParserTagType.Indirect { _, content, builder ->
                        builder.add(headerContentToLabel(content), 2, headerContentToAnchor(content))
                        "[h3]$content[/h3]"
                }
        ),
        H4(
-               TextParserTagType.Indirect<TableOfContentsBuilder> { _, content, builder ->
+               TextParserTagType.Indirect { _, content, builder ->
                        builder.add(headerContentToLabel(content), 3, headerContentToAnchor(content))
                        "[h4]$content[/h4]"
                }
        ),
        H5(
-               TextParserTagType.Indirect<TableOfContentsBuilder> { _, content, builder ->
+               TextParserTagType.Indirect { _, content, builder ->
                        builder.add(headerContentToLabel(content), 4, headerContentToAnchor(content))
                        "[h5]$content[/h5]"
                }
        ),
        H6(
-               TextParserTagType.Indirect<TableOfContentsBuilder> { _, content, builder ->
+               TextParserTagType.Indirect { _, content, builder ->
                        builder.add(headerContentToLabel(content), 5, headerContentToAnchor(content))
                        "[h6]$content[/h6]"
                }
index 1f4890bda2e9ee92dd5a95986ee1aeba201c8a10..e73d7bf5282867d7909535003020b88cd84f3554 100644 (file)
                }
        });
 
+       window.appendImageThumb = function (src, sizeStyle) {
+               // Image previewing (1)
+               const imgElement = document.createElement("img");
+               imgElement.src = src;
+               imgElement.setAttribute("title", "Click to view full size");
+               imgElement.setAttribute("style", sizeStyle);
+
+               imgElement.onclick = e => {
+                       e.preventDefault();
+
+                       const thumbView = document.getElementById("thumb-view");
+                       const thumbViewImg = thumbView.getElementsByTagName("img")[0];
+                       thumbViewImg.src = e.currentTarget.src;
+                       thumbView.classList.add("visible");
+               }
+
+               document.currentScript.after(imgElement);
+       };
+
        window.addEventListener("load", function () {
-               // Image previewing
+               // Image previewing (2)
                document.getElementById("thumb-view").addEventListener("click", e => {
                        e.preventDefault();
 
                        e.currentTarget.classList.remove("visible");
                        e.currentTarget.getElementsByTagName("img")[0].src = "";
                });
-
-               const thumbs = document.querySelectorAll("a.thumb");
-               for (const thumb of thumbs) {
-                       thumb.onclick = e => {
-                               e.preventDefault();
-
-                               const thumbView = document.getElementById("thumb-view");
-                               const thumbViewImg = thumbView.getElementsByTagName("img")[0];
-                               thumbViewImg.src = e.currentTarget.getAttribute("href");
-                               thumbView.classList.add("visible");
-                       };
-               }
        });
 
        window.addEventListener("load", function () {
                        pElement.append(aElement);
                        document.currentScript.after(pElement);
                } else {
-                       document.cookie = "REDIRECTED_FROM=" + window.location.pathname + "; SameSite=Lax; Secure";
+                       window.localStorage.setItem("redirectedFrom", window.location.pathname);
                        window.location = redirectTo;
                }
        };
 
-       window.checkRedirectTarget = function () {
-               const redirectSourceValues = document.cookie.split(';').filter(value => value.trim().startsWith("REDIRECTED_FROM="));
-               if (redirectSourceValues.length > 0) {
-                       const redirectSource = new URL(redirectSourceValues[0].trim().substring("REDIRECTED_FROM=".length), window.location.origin);
+       window.checkRedirectTarget = function (anchorHash) {
+               const redirectTargetValue = window.location.hash;
+               if (redirectTargetValue !== anchorHash) return;
+
+               const redirectSourceValue = window.localStorage.getItem("redirectedFrom");
+               if (redirectSourceValue != null) {
+                       const redirectSource = new URL(redirectSourceValue, window.location.origin);
                        if (redirectSource.search.length > 0) {
                                redirectSource.search += "&redirect=no";
                        } else {
                        document.currentScript.after(pElement);
                }
 
-               document.cookie = "REDIRECTED_FROM=; Expires=Thu, 01 Jan 1970 00:00:00 GMT; SameSite=Lax; Secure";
+               window.localStorage.removeItem("redirectedFrom");
        };
 })();