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

.circumflex-markeven.2.0.2.source-code.blocks.scala Maven / Gradle / Ivy

package ru.circumflex.markeven

import java.io._
import java.util.regex._

class LinkDefinition(val url: StringEx, val title: StringEx) {
  url.replaceAll("*", "*").replaceAll("_", "_").trim
  title.replaceAll("*", "*").replaceAll("_", "_").replaceAll("\"", """).trim

  def toLink(linkText: CharSequence): StringEx = {
    val result = new StringEx(" 0) result.append(" title=\"").append(title).append("\"")
    result.append(">").append(linkText).append("")
    return result
  }

  def toImageLink(alt: CharSequence): StringEx = {
    val result = new StringEx(" 0) result.append(" title=\"").append(title).append("\"")
    if (alt.length > 0) result.append(" alt=\"").append(alt).append("\"")
    result.append("/>")
    return result
  }
}

class Selector(val id: String = "", val classes: Seq[String] = Nil) {
  override val toString = {
    var result = ""
    if (id != "") result += " id=\"" + id + "\""
    if (classes.size > 0)
      result += " class=\"" + classes.mkString(" ") + "\""
    result
  }
}

abstract class Block(val text: StringEx, val selector: Selector) {
  def element: String
  def toHtml(mp: MarkevenProcessor): StringEx = {
    val content = processContent(mp)
    val result = new StringEx(mp.currentIndent)
        .append("<")
        .append(element)
        .append(selector.toString)
        .append(attributes)
    if (text.length == 0) result.append("/>")
    else result.append(">")
        .append(content)
        .append("")
    return result
  }
  def writeHtml(mp: MarkevenProcessor, out: Writer): Unit =
    out.write(toHtml(mp).toString)
  def processContent(mp: MarkevenProcessor): StringEx = text
  def attributes = ""
}

abstract class NestedMarkupBlock(text: StringEx, selector: Selector)
    extends Block(text, selector) {
  def trimPattern: Option[Pattern]

  override def processContent(mp: MarkevenProcessor): StringEx = {
    // perform line trimming
    trimPattern.map(p => text.replaceAll(p, ""))
    // clean blank lines
    mp.cleanEmptyLines(text)
    // read nested blocks
    val blocks = mp.readBlocks(text)
    // do not wrap single paragraph
    if (blocks.size == 1 && unwrapBlock_?(blocks(0)))
      return blocks(0).processContent(mp)
    else return new StringEx(mp.newLine).append(mp.formHtml(blocks, true)).append(mp.currentIndent)
  }

  def unwrapBlock_?(block: Block): Boolean = block.isInstanceOf[ParagraphBlock]
}

abstract class ListBlock(text: StringEx, selector: Selector, val baseline: Int)
    extends NestedMarkupBlock(text, selector) {

  def splitPattern: Pattern

  override def processContent(mp: MarkevenProcessor): StringEx = {
    // strip whitespace from every line if first element was indented
    if (baseline > 0)
      text.replaceAll(regexes.outdent(baseline), "")
    // clean blank lines
    mp.cleanEmptyLines(text)
    // read list item blocks
    val blocks = text.split(splitPattern).map { s =>
      val selector = mp.stripSelector(s)
      val indent = trimPattern.map(p => s.replaceFirst(p, "")).getOrElse(0)
      if (indent > 0) s.replaceAll(regexes.outdent(indent), "")
      new ListItemBlock(s, selector)
    }
    return new StringEx(mp.newLine).append(mp.formHtml(blocks, true)).append(mp.currentIndent)
  }

}

object EmptyBlock extends Block(new StringEx(""), new Selector()) {
  def element = ""
  override def processContent(mp: MarkevenProcessor) = text
  override def toHtml(mp: MarkevenProcessor) = text
  override def writeHtml(mp: MarkevenProcessor, out: Writer): Unit = {}
}

class InlineHtmlBlock(text: StringEx)
    extends Block(text, new Selector) {
  def element = ""
  override def toHtml(mp: MarkevenProcessor): StringEx = text
}

class HorizontalRulerBlock(selector: Selector)
    extends Block(new StringEx(""), selector) {
  def element = "hr"
}

class ParagraphBlock(text: StringEx, selector: Selector)
    extends Block(text, selector) {
  def element = "p"
  override def processContent(mp: MarkevenProcessor): StringEx = mp.transform(text)
}

class HeadingBlock(text: StringEx, selector: Selector, val level: Int)
    extends Block(text, selector) {
  def element = "h" + level
  override def processContent(mp: MarkevenProcessor): StringEx = mp.transform(text)
}

class CodeBlock(text: StringEx, selector: Selector)
    extends Block(text, selector) {
  def element = "code"
  override def toHtml(mp: MarkevenProcessor): StringEx = new StringEx(mp.currentIndent)
      .append("")
      .append(processContent(mp).buffer)
      .append("
") override def processContent(mp: MarkevenProcessor): StringEx = mp.encodeChars(text.replaceAll(regexes.outdent(4), "")) } class UnorderedListBlock(text: StringEx, selector: Selector, baseline: Int) extends ListBlock(text, selector, baseline) { def element = "ul" def trimPattern = Some(regexes.t_ul) def splitPattern = regexes.s_ul } class OrderedListBlock(text: StringEx, selector: Selector, baseline: Int) extends ListBlock(text, selector, baseline) { def element = "ol" def trimPattern = Some(regexes.t_ol) def splitPattern = regexes.s_ol } class ListItemBlock(text: StringEx, selector: Selector) extends NestedMarkupBlock(text, selector) { def trimPattern = None def element = "li" override def unwrapBlock_?(block: Block): Boolean = block.isInstanceOf[ParagraphBlock] || block.isInstanceOf[SectionBlock] } class BlockquoteBlock(text: StringEx, selector: Selector) extends NestedMarkupBlock(text, selector) { def trimPattern = Some(regexes.t_blockquote) def element = "blockquote" } class SectionBlock(text: StringEx, selector: Selector) extends NestedMarkupBlock(text, selector) { def trimPattern = Some(regexes.t_div) def element = "div" } class TableBlock(text: StringEx, selector: Selector) extends Block(text, selector) { var widthAttr: String = "" def element = "table" override def attributes = widthAttr override def processContent(mp: MarkevenProcessor): StringEx = { val chunks = new ChunkIterator(text.split(regexes.lines)) if (chunks.size < 3) // no table content return new StringEx("") val result = new StringEx("") // first line determines width if (chunks.next.endsWith(">")) widthAttr = " width=\"100%\"" // next line determines column count var cells = parseCells(mp, chunks.next) val cols = cells.size var align: Seq[String] = Nil val l = chunks.next // see if we got heading if (l.matches(regexes.tableSeparatorLine) && chunks.hasNext) { // we have a heading; but let's parse separator first align = l.split(regexes.tableCellSplit).map { a => val v = a.trim if (v.startsWith(":") && v.endsWith(":")) " align=\"center\"" else if (v.startsWith(":")) " align=\"left\"" else if (v.endsWith(":")) " align=\"right\"" else "" } // let's also flush heading mp.increaseIndent result.append(mp.newLine).append(mp.currentIndent).append("") mp.increaseIndent result.append(mp.newLine).append(mp.currentIndent).append("") mp.increaseIndent cells.foreach(th => result.append(mp.newLine).append(mp.currentIndent).append("") .append(mp.transform(th)).append("")) mp.decreaseIndent result.append(mp.newLine).append(mp.currentIndent).append("") mp.decreaseIndent result.append(mp.newLine).append(mp.currentIndent).append("") mp.decreaseIndent // read first body cells for correct positioning cells = parseCells(mp, chunks.next) } else chunks.stepBack // correct align data to match colsize align = align.take(cols).padTo(cols, "") // process body mp.increaseIndent result.append(mp.newLine).append(mp.currentIndent).append("") mp.increaseIndent while (chunks.hasNext) { result.append(mp.newLine).append(mp.currentIndent).append("") mp.increaseIndent var i = 0 cells.take(cols).padTo(cols, "").foreach { td => result.append(mp.newLine).append(mp.currentIndent).append("").append(td).append("") i += 1 } mp.decreaseIndent result.append(mp.newLine).append(mp.currentIndent).append("") // evaluate next row val l = chunks.next if (chunks.hasNext) cells = parseCells(mp, l) } // now close body and we're done mp.decreaseIndent result.append(mp.newLine).append(mp.currentIndent).append("") mp.decreaseIndent result.append(mp.newLine).append(mp.currentIndent) return result } def parseCells(mp: MarkevenProcessor, s: StringEx): Seq[StringEx] = s.replaceAll(regexes.t_tr, "") .split(regexes.tableCellSplit).map { s => mp.transform(s) } }



© 2015 - 2025 Weber Informatics LLC | Privacy Policy