All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.woojiahao.modifiers.figure.FigureNodeRenderer.kt Maven / Gradle / Ivy

package com.github.woojiahao.modifiers.figure

import com.github.woojiahao.modifiers.figure.FigureNodeRenderer.DestinationType.*
import com.vladsch.flexmark.ast.Image
import com.vladsch.flexmark.html.CustomNodeRenderer
import com.vladsch.flexmark.html.HtmlWriter
import com.vladsch.flexmark.html.renderer.NodeRenderer
import com.vladsch.flexmark.html.renderer.NodeRenderingHandler
import com.vladsch.flexmark.util.ast.Node
import kotlinx.html.*
import kotlinx.html.stream.appendHTML
import java.io.File
import java.net.MalformedURLException
import java.net.URI

class FigureNodeRenderer(private val markdownFile: File) : NodeRenderer {

  private enum class DestinationType { WEB, RELATIVE_LOCAL, ABSOLUTE_LOCAL }

  private val urlSeparator = "/"

  private val String?.destinationType: DestinationType
    get() {
      this ?: return WEB

      with(URI(replace("\\", urlSeparator))) {
        return try {
          toURL()
          WEB
        } catch (e: Exception) {
          when (e) {
            is MalformedURLException -> ABSOLUTE_LOCAL
            is IllegalArgumentException -> RELATIVE_LOCAL
            else -> throw e
          }
        }
      }
    }

  override fun getNodeRenderingHandlers() =
    hashSetOf>(
      object : NodeRenderingHandler(
        Image::class.java,
        CustomNodeRenderer { image, _, writer -> render(image, writer) }
      ) {}
    )

  fun render(node: Image, html: HtmlWriter) {
    val src = node.url.unescape() ?: return
    val alt = node.title.unescape() ?: return

    val destinationType = src.destinationType

    val processedDestination = when (destinationType) {
      RELATIVE_LOCAL -> processLocalFileLocation(src)
      else -> src
    }

    val imageNode = generateImage(alt, processedDestination, destinationType)

    html.raw(imageNode)
    html.line()
  }

  private fun generateImage(alt: String, src: String, destinationType: DestinationType) =
    if (alt.isEmpty()) loadImage(alt, src, destinationType)
    else loadImageWithCaption(alt, src, destinationType)

  private fun loadImage(alt: String, src: String, destinationType: DestinationType) =
    createImageTag(alt, src, destinationType)

  private fun loadImageWithCaption(alt: String, src: String, destinationType: DestinationType) =
    StringBuilder().appendHTML().figure {
      unsafe {
        +createImageTag(alt, src, destinationType)
      }
      br { }
      figcaption {
        +alt
      }
      br { }
    }.toString()

  private fun createImageTag(alt: String, src: String, destinationType: DestinationType) =
    StringBuilder().appendHTML().img {
      this.src = src
      if (alt.isNotEmpty()) this.alt = alt
      classes = setOf(when (destinationType) {
        RELATIVE_LOCAL, ABSOLUTE_LOCAL -> "local"
        else -> ""
      })
    }.toString()

  private fun processLocalFileLocation(localFilePath: String): String {
    val localPath = markdownFile
      .parent
      .replace("\\", urlSeparator)
      .split(urlSeparator)
      .toMutableList()

    localFilePath.split(urlSeparator).forEach {
      // The string compared has a tendency to change to "src/main" when the file location is changed,
      // it should be ".."
      if (it == "..") localPath.removeAt(localPath.size - 1)
      else localPath += it
    }

    return localPath.joinToString(urlSeparator)
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy