lang/markdown/ PtWikiRendererParsedown1Php


<?php
include_once("BaseClasses.php");
include_once("Parsedown.php");
include_once("grads.php");
include_once("bugs.php");

/*
"/a4b64aa751cf795de53f23be2049cb5223ee8907ad6fc8130825c1f3b20a8d5a6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b\]/"
P
*/
function make_gradient_bg_css(array $colours, string $direction="to bottom", string $repeat="no-repeat") 
{  
  $n = count($colours);
  if( $n < 1 ) {
    return null;
  }
  $bg = array();
  array_push($bg,$colours[$n-1]);
  if( $n > 1 ) {
    $gradient_points = array();
    for($i = 0; $i < $n; $i++) {
      $pc = round($i*(100.0/($n-1)));
      array_push($gradient_points,"$colours[$i] ${pc}%");
    }
    $direction = "to bottom";
    $gradient = "linear-gradient($direction, ".implode(", ",$gradient_points).")";
    array_push($bg,$gradient);
  }
  $css = "background: url('/marble2.png'), ".implode(" ",$bg)." $repeat;";
  return $css;
}
function make_gradient_background() {    
  if( file_exists("grad.txt") ) {
    $lines = file("grad.txt");
    $line = $lines[0];
    $bg_colours = preg_split("/[\\s,]+/",trim($line));
  } else {
    $bg_colours = pseudo_random_gradient(getcwd());
  }
  $css_bg = make_gradient_bg_css($bg_colours);
  $last_colour = $bg_colours[count($bg_colours)-1];
  $r = hexdec(substr($last_colour,1,2));
  $g = hexdec(substr($last_colour,3,2));
  $b = hexdec(substr($last_colour,5,2));
  if( (($r + $g + $b) / 3) > 128 ) {
    $light_bg = true;
  } else {
    $light_bg = false;
  }
  $css = "
body {
  $css_bg
}
";
  if( $light_bg ) {
    $css .= "footer {
  color: black;
}
footer a {
  color: #007;
}
footer a:visited {
  color: #01a;
}
";

  } else {
    $css .= "footer {
  color: hsl(0,0%,80%);
}
footer a {
  color: white;
}
footer a:visited {
  color: #dde;
}
";
  }
  $style = "<style media='screen'>
$css
</style>";
  return $style;
}
class WikiRendererParsedown1 extends WikiRenderer {
  public function __construct() {
    $this->protected = array();
    $this->protected_prefix = strtolower(hash("sha256",time()));
  }
  public function render_view(array $vars): void {
    $word = $vars["WIKI_WORD"];
    $source = $vars["WIKI_PAGE_SOURCE"];

    $vars["WIKI::FAVICON"] = '<link rel="icon" type="image/x-icon" href="/purple_tree_wiki_favicon.png">';
    if( file_exists("favicon.png") ) {
      $vars["WIKI::FAVICON"] = '<link rel="icon" type="image/x-icon" href="favicon.png">';
    }
    if( file_exists("favicon_view.png") ) {
      $vars["WIKI::FAVICON"] = '<link rel="icon" type="image/x-icon" href="favicon_view.png">';
    }

    if( file_exists("bug.png") ) {
      #$vars["BUG_BUG"] = '<img class="bug" height="256px" src="bug.png" style="position: absolute; z-index: 1; right: 3em; top: 1em;"/>';
      $vars["BUG_BUG"] = '<img class="bug" height="'.BUG_HEIGHT.'" src="bug.png"/>';
    } else if(file_exists("nobug") ) {
      $vars["BUG_BUG"] = "";
    } else {
      $vars["BUG_BUG"] = get_random_bug(getcwd());
    }

    # convert tags
    if( preg_match("@^tags:(.*)$@m",$source,$m) ) {
      $tags = preg_split("@\s+@",trim($m[1]));
      $source = explode("\n",$source,2)[1];
      $t = [];
      foreach($tags as $tag) {
        switch($tag[0]) {
          case "#":
            $cls = "hashtag";
            $x = substr($tag,1);
            $h = "<a href='/tag/$x'>$tag</a>";
            break;
          case "%":
            $cls = "category";
            $h = "<a href='#'>$tag</a>";
            break;
          case "@":
            $cls = "user";
            $h = "<a href='#'>$tag</a>";
            break;
          default:
            $cls = "other";
            $h = "<a href='#'>$tag</a>";
        }
        array_push($t,"<li class='$cls'>$h</li>");
        $x = implode("\n",$t);
        $y = "<ul class='hashtags'>\n".$x."\n</ul>\n";
        $vars["TAGS_TAGS"] = $y;
      }
    } else {
      $vars["TAGS_TAGS"] = "";
    }
    $opts = [];
    if( preg_match("@^options:(.*)$@m",$source,$m) ) {
      $optsrc = preg_split("@\s+@",trim($m[1]));
      $source = explode("\n",$source,2)[1];
      foreach($optsrc as $opt) {
        [$a,$b] = explode("=",$opt,2);
        $opts[$a] = $b;
      }
    }
    #var_dump($opts);
    $mathjax = true;
    if( array_key_exists("mathjax",$opts) ) {
      $m = strtolower($opts["mathjax"]);
      if( $m == "false" || $m == "no" ) {
        $mathjax = false;
      }
    }
    $this->mathjax = $mathjax;
    $abcjs = false;
    if( array_key_exists("abc",$opts) ) {
      $m = strtolower($opts["abc"]);
      if( $m == "true" || $m == "yes" ) {
        $abcjs = true;
      }
    }
    $this->abcjs = $abcjs;
    if( $mathjax ) {
      $vars["WIKI::MathJax"] = "<script>
MathJax = {
  tex: {
    inlineMath: [['\\\a4b64aa751cf795de53f23be2049cb5223ee8907ad6fc8130825c1f3b20a8d5a7902699be42c8a8e46fbbb4501726517e86b22c56a189f7625a6da49081b2451']],
    displayMath: [['\\\a4b64aa751cf795de53f23be2049cb5223ee8907ad6fc8130825c1f3b20a8d5ad4735e3a265e16eee03f59718b9b5d03019c07d8b6c51f90da3a666eec13ab35']]
  },
  svg: {
    fontCache: 'global'
  }
};
</script>
<script type='text/javascript' id='MathJax-script' async
  src='https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-svg.js'>
</script>
";
    } else {
      $vars["WIKI::MathJax"] = "";
    }
    if( $abcjs ) {
      $vars["WIKI::AbcJs"] = "<script src='/js/abcjs-basic-min.js'></script>
<script src='/js/abc-auto.js'></script>";
    } else {
      $vars["WIKI::AbcJs"] = "";
    }
    #echo "<pre>\n"; var_dump($vars); echo "</pre>\n";

    $vars["GRAD_GRAD"] = make_gradient_background();

    $source = preg_replace_callback("/^(```nohighlight\\s(.*?)^```)/ms",[$this,"protect_nohighlight_cb"],$source);
    if( $this->abcjs ) {
      $source = preg_replace_callback("/^(```abc\\s(.*?)^```)/ms",[$this,"protect_abc_cb"],$source);
    }
    $source = preg_replace_callback("/^(```(.*?)^```)/ms",[$this,"protect_block_cb"],$source);
    $source = preg_replace_callback("/(`+)(.*?)(\\1)/s",[$this,"protect_backquote_cb"],$source);
    $source = preg_replace_callback(HEADER_REGEX,[$this,"protect_header"],$source);
    $source = preg_replace_callback(YOUTUBE_REGEX,[$this,"protect_youtube"],$source);
    $source = preg_replace_callback(MD_IMGLINK_REGEX,[$this,"protect_mdimglink_cb"],$source);
    $source = preg_replace_callback(OB_LINK_REGEX,[$this,"protect_oblink_cb"],$source);
    $source = preg_replace_callback('@a4b64aa751cf795de53f23be2049cb5223ee8907ad6fc8130825c1f3b20a8d5a4e07408562bedb8b60ce05c1decfe3ad16b72230967de01f640b7e4729b49fce]*)\]a4b64aa751cf795de53f23be2049cb5223ee8907ad6fc8130825c1f3b20a8d5a2c624232cdd221771294dfbb310aca000a0df6ac8b66b696d90ef06fdefb64a3@',[$this,"protect_unwiki_cb"],$source);
    $source = preg_replace_callback(MD_LINK_QUOTE_REGEX,[$this,"protect_mdlink_quote_cb"],$source);
    $source = preg_replace_callback(MD_LINK_REGEX,[$this,"protect_mdlink_cb"],$source);
    $source = preg_replace_callback(URL_REGEX,[$this,"protect_url_cb"],$source);
    $source = preg_replace_callback(WIKIWORD_REGEX, [$this,"WikiWord_to_link"],$source);
    foreach($this->protected as $id => $string) {
      $source = str_replace($id,$string,$source);
    }
    #echo "<!--\n";
    #var_dump($source);
    #echo "-->\n";
    $vars['WIKI_PAGE_SOURCE'] = $source;
    $this->render_view_real($vars);
  }
  public function render_view_real(array $vars): void {
    $source = $vars['WIKI_PAGE_SOURCE'];

    #echo "<!-- render view real\n";
    #var_dump($source);
    #echo "-->\n";
    # protect a4b64aa751cf795de53f23be2049cb5223ee8907ad6fc8130825c1f3b20a8d5a19581e27de7ced00ff1ce50b2047e7a567c76b1cbaebabe5ef03f7c3017bb5b7 and a4b64aa751cf795de53f23be2049cb5223ee8907ad6fc8130825c1f3b20a8d5a4b227777d4dd1fc61c6f884f48641d02b4d121d3fd328cb08b5531fcacdabf8a from Parsedown
    $source = str_replace('\a4b64aa751cf795de53f23be2049cb5223ee8907ad6fc8130825c1f3b20a8d5aef2d127de37b942baad06145e54b0c619a1f22327b2ebbcfbec78f5564afe39d',HEXVISION,$source);
    $source = str_replace('\a4b64aa751cf795de53f23be2049cb5223ee8907ad6fc8130825c1f3b20a8d5a4a44dc15364204a80fe80e9039455cc1608281820fe2b24f1e5233ade6af1dd5',FRYTHEEWELL,$source);
    $source = str_replace('\\{',COOKLITTLEPIGGY,$source);
    $source = str_replace('\\}',COOKTHEEWELL,$source);

    $this->protected = [];
    if( $this->abcjs ) {
      $source = preg_replace_callback("/^(?:```abc\\s(.*?)^```)/ms",[$this,"protect_abc_pd_cb"],$source);
    }

    $parsedown = new Parsedown();
    $result = $parsedown->text($source);

    foreach($this->protected as $id => $string) {
      $result = str_replace($id,$string,$result);
    }

    $result = str_replace(MRFLIBBLE,'\a4b64aa751cf795de53f23be2049cb5223ee8907ad6fc8130825c1f3b20a8d5ae7f6c011776e8db7cd330b54174fd76f7d0216b612387a5ffcfb81e6f0919683',$result);
    $result = str_replace(FRYLITTLEPIGGY,'\a4b64aa751cf795de53f23be2049cb5223ee8907ad6fc8130825c1f3b20a8d5a4fc82b26aecb47d2868c4efbe3581732a3e7cbcc6c2efb32062c08170a05eeb8',$result);
    $result = str_replace(COOKLITTLEPIGGY,'\\{',$result);
    $result = str_replace(COOKTHEEWELL,'\\}',$result);

    $result = preg_replace("/(?<=[^-])---(?=[^-])/","&mdash;",$result);
    $result = preg_replace("/(?<=[^-])--(?=[^-])/","&ndash;",$result);

    $vars["WIKI_PAGE_BODY"] = $result;
    if( preg_match("/Mobile/",$_SERVER["HTTP_USER_AGENT"]) ) {
      $template = file_get_contents("view_template_mob.html");
    } else {
      $template = file_get_contents("view_template_md.html");
    }
    $this->render_template($template,$vars);
  }
  public function render_edit(array $vars): void {

    $vars["WIKI::FAVICON"] = '<link rel="icon" type="image/x-icon" href="/purple_tree_edit_favicon.png">';
    if( file_exists("favicon.png") ) {
      $vars["WIKI::FAVICON"] = '<link rel="icon" type="image/x-icon" href="favicon.png">';
    }
    if( file_exists("favicon_edit.png") ) {
      $vars["WIKI::FAVICON"] = '<link rel="icon" type="image/x-icon" href="favicon_edit.png">';
    }

    $vars["GRAD_GRAD"] = make_gradient_background();
    if( $vars["WIKI_ERROR_STRING"] ) {
      $vars["WIKI_ERROR_MESSAGE"] = $this->format_error_message($vars["WIKI_ERROR_STRING"]);
    } else {
      $vars["WIKI_ERROR_MESSAGE"] = "";
    }

    $template = file_get_contents("edit_template_mob.html");
    $this->render_template($template,$vars);
  }
  public function render_versions(array $vars): void {
    $versions = $vars['WIKI_VERSIONS'];
    $word = $vars['WIKI_WORD'];
    $body = "";
    if( count($versions) == 0) {
      $this->vars['WIKI_PAGE_SOURCE'] = "Word $word has no versions.";
    } else {
      foreach( $versions as $version) {
        $body .= "1. [".date(DATE_COOKIE,intval($version))."]($word?version=$version)\n";
      }
      $body .= "1. [current]($word)\n";
    }
    $parsedown = new Parsedown();
    $rendered = $parsedown->text($body);

    $vars["WIKI_PAGE_BODY"] = $rendered;
    $template = file_get_contents("versions_template_md.html");
    $this->render_template($template,$vars);
  }
  private function protect(string $content): string {
    $protid = strtolower(hash("sha256",$this->protect_count++));
    $key = $this->protected_prefix.$protid; # generate unique string
    $this->protected[$key] = $content;
    return $key;
  }
  private function protect_cb(array $match): string {
    return $this->protect($match[0]);
  }
  private function protect_nohighlight_cb(array $match): string {
    return $this->protect($match[2]);
  }
  private function protect_abc_cb(array $match): string { # protect ABC from WikiWord
    return $this->protect($match[0]);
  }
  private function protect_abc_pd_cb(array $match): string { # protect ABC from Parsedown, convert to div.abc
    return $this->protect("<div class='abc'>\n$match[1]\n</div>");
  }
  private function protect_header(array $match): string {
    return $this->protect($match[0]);
  }
  private function protect_youtube(array $match): string {
    return $this->protect($match[0]);
  }
  private function protect_url_cb(array $match): string {
    #echo "url: $match[0]<br/>\n";
    return $this->protect($match[0]);
  }
  private function protect_mdimglink_cb(array $match): string {
    #echo "mdimglink: $match[0]<br/>\n";
    return $this->protect($match[0]);
  }
  private function protect_mdlink_cb(array $match): string {
    #echo "mdlink: $match[0]<br/>\n";
    return $this->protect($match[0]);
  }
  private function protect_unwiki_cb(array $match): string {
    #echo "mdlink: $match[0]<br/>\n";
    return $this->protect($match[1]);
  }
  private function protect_oblink_cb(array $match): string {
    #echo "mdlink: $match[0]<br/>\n";
    $l = $match[1];
    $t = preg_replace("@[^a-zA-Z0-9._/-]+@","",$l);
    if( strlen($t) == 0 ) {
      return $this->protect("");
    }
    if( ! preg_match("@/@",$t) && ! preg_match(WIKIWORD_REGEX,$t) ) {
      if( ! preg_match('@\.@',$t) ) {
        # not a filename: make into PageSomething format
        if( ! preg_match("@[A-Z]@",$t ) ) {
          # ensure at least one capital
          if( preg_match("@[a-z]@",$t) ) {
            # is a lowercase letter we can uppercase
            $t = preg_replace_callback('/^(.*?)([a-z])(.*)$/',function($m) { return $m[1].strtoupper($m[2]).$m[3]; }, $t);
          } else {
            $t = "N".$t; # basically a number
          }
        }
        $t = "Page".$t;
      }
    }
    return $this->protect("[$l]($t)");
  }
  private function protect_mdlink_quote_cb(array $match): string {
    #echo "mdlink quote: $match[0] :: $match[1] $match[2]<br/>\n";
    return $this->protect("[$match[1]]($match[2])");
  }
  private function protect_block_cb(array $match): string {
    #echo "block: $match[0]<br/>\n";
    return $this->protect($match[0]);
  }
  private function protect_backquote_cb(array $match): string {
    #echo "backquote: $match[0]<br/>\n";
    return $this->protect($match[0]);
  }
  private function WikiWord_to_link(array $match): string {
    $word = $match[0];
    return "[$word]($word)";
  }
  private function edit_link(string $word): string {
    return "<div class='edit_link'><a href='$word?edit'>Edit</a></div>";
  }
  private function render_template(string $template, array $vars): void {
    foreach($vars as $key => $value) {
      if( is_string($value) ) { # silently ignore array vars
        $template = str_replace($key,$value,$template);
      }
    }
    echo $template;
    exit();
  }
  private function format_error_message(string $err_msg): string {
    return "<p class='error'>$err_msg</p>\n";
  }
}