2021-04-02 21:29:46 +02:00
|
|
|
|
<?php declare(strict_types=1);
|
2021-03-16 13:49:11 +01:00
|
|
|
|
|
|
|
|
|
namespace htmgem;
|
|
|
|
|
|
|
|
|
|
mb_internal_encoding("UTF-8");
|
|
|
|
|
mb_regex_encoding("UTF-8");
|
|
|
|
|
|
2021-04-11 21:35:55 +02:00
|
|
|
|
/**
|
|
|
|
|
* Resolve $path interpretating / . and ..
|
|
|
|
|
* @param $path str
|
|
|
|
|
* @returns "/" if .. goes above the limit
|
|
|
|
|
*/
|
|
|
|
|
function resolve_path($path) {
|
|
|
|
|
if (empty($path)) return "";
|
|
|
|
|
$absolute = "/"==$path[0];
|
|
|
|
|
$parts = array_filter(explode("/", $path), 'strlen');
|
|
|
|
|
$chuncks = array();
|
|
|
|
|
foreach ($parts as $part) {
|
|
|
|
|
if ('.' == $part) continue;
|
|
|
|
|
if ('..' == $part) {
|
|
|
|
|
if (is_null(array_pop($chuncks))) return "/";
|
|
|
|
|
} else {
|
|
|
|
|
$chuncks[] = $part;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
$output = implode("/", $chuncks);
|
|
|
|
|
if ($absolute) $output = "/".$output;
|
|
|
|
|
return $output;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Splits link (without .. or .) into parts along with direct url access.
|
|
|
|
|
* @param url
|
|
|
|
|
*
|
|
|
|
|
* Ex. /dir1/dir2/page.gmi
|
|
|
|
|
* --> "dir1" --> "/dir1"
|
|
|
|
|
* --> "dir2" --> "/dir1/dir2"
|
|
|
|
|
* --> "page.gmi" --> "/dir2/page.gmi"
|
|
|
|
|
*/
|
|
|
|
|
function split_path_links($path, $prefix="") {
|
|
|
|
|
$parts = array_filter(explode("/", $path), 'strlen');
|
|
|
|
|
if (empty($parts)) return array();
|
|
|
|
|
if ("/"==$path[0])
|
|
|
|
|
$stack = "/";
|
|
|
|
|
else
|
|
|
|
|
$stack = "";
|
|
|
|
|
$output = array();
|
|
|
|
|
$slash = "";
|
|
|
|
|
foreach ($parts as $part) {
|
|
|
|
|
$stack .= $slash.$part;
|
|
|
|
|
$output[$part] = $prefix.$stack;
|
|
|
|
|
$slash = "/";
|
|
|
|
|
}
|
|
|
|
|
return $output;
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-16 13:49:11 +01:00
|
|
|
|
/**
|
2021-03-16 20:54:10 +01:00
|
|
|
|
* Parses the gemtext and generates the internal format version
|
|
|
|
|
* @param str $fileContents the gemtext to parse
|
2021-03-16 13:49:11 +01:00
|
|
|
|
*/
|
2021-03-16 20:54:10 +01:00
|
|
|
|
function gemtextParser($fileContents) {
|
2021-03-24 10:34:17 +01:00
|
|
|
|
if (empty($fileContents)) return array();
|
|
|
|
|
$fileContents = rtrim($fileContents); // removes last empty line
|
2021-04-11 21:35:55 +02:00
|
|
|
|
$fileLines = mb_split("\n|\r\n?", $fileContents); // Unix, Mac, Windows line feeds
|
2021-03-16 13:49:11 +01:00
|
|
|
|
$mode = null;
|
2021-03-16 20:54:10 +01:00
|
|
|
|
$current = array();
|
2021-03-16 13:49:11 +01:00
|
|
|
|
foreach ($fileLines as $line) {
|
|
|
|
|
$reDoCount = 0;
|
|
|
|
|
$mode_textAttributes_temp = false;
|
|
|
|
|
while (true) {
|
2021-03-16 20:54:10 +01:00
|
|
|
|
/* The continue instruction is used to make another turn when there is a transition
|
|
|
|
|
* between two modes. */
|
|
|
|
|
if ($reDoCount>1) {
|
|
|
|
|
die("HtmGem: Too many loops, mode == '$mode'");
|
2021-03-16 13:49:11 +01:00
|
|
|
|
}
|
|
|
|
|
$reDoCount += 1;
|
|
|
|
|
$line1 = substr($line, 0, 1); // $line can be modified
|
|
|
|
|
$line2 = substr($line, 0, 2); // in the meantime.
|
|
|
|
|
$line3 = substr($line, 0, 3);
|
|
|
|
|
if (is_null($mode)) {
|
2021-03-16 20:54:10 +01:00
|
|
|
|
if ('^^^' == $line3) {
|
|
|
|
|
yield array("mode" => "^^^");
|
2021-03-16 13:49:11 +01:00
|
|
|
|
} elseif ("#" == $line1) {
|
2021-03-24 10:34:17 +01:00
|
|
|
|
preg_match("/^(#{1,3})\s*(.+)?/", $line, $matches);
|
2021-04-02 21:29:46 +02:00
|
|
|
|
yield array("mode" => $matches[1], "title" => trim($matches[2]??""));
|
2021-03-16 13:49:11 +01:00
|
|
|
|
} elseif ("=>" == $line2) {
|
2021-03-16 20:54:10 +01:00
|
|
|
|
preg_match("/^=>\s*([^\s]+)(?:\s+(.*))?$/", $line, $matches);
|
2021-04-02 21:29:46 +02:00
|
|
|
|
yield array("mode" => "=>", "link" => trim($matches[1]??""), "text" => trim($matches[2]??""));
|
2021-03-16 13:49:11 +01:00
|
|
|
|
} elseif ("```" == $line3) {
|
|
|
|
|
preg_match("/^```\s*(.*)$/", $line, $matches);
|
2021-03-16 20:54:10 +01:00
|
|
|
|
$current = array("mode" => "```", "alt" => trim($matches[1]), "texts" => array());
|
|
|
|
|
$mode="```";
|
2021-03-16 13:49:11 +01:00
|
|
|
|
} elseif (">" == $line1) {
|
2021-03-16 20:54:10 +01:00
|
|
|
|
preg_match("/^>\s*(.*)$/", $line, $matches);
|
|
|
|
|
$current = array("mode" => ">", "texts" => array(trim($matches[1])));
|
|
|
|
|
$mode = ">";
|
2021-03-16 13:49:11 +01:00
|
|
|
|
} elseif ("*" == $line1) {
|
2021-03-16 20:54:10 +01:00
|
|
|
|
preg_match("/^\*\s*(.*)$/", $line, $matches);
|
|
|
|
|
$current = array("mode" => "*", "texts" => array(trim($matches[1])));
|
|
|
|
|
$mode = "*";
|
2021-03-16 13:49:11 +01:00
|
|
|
|
} else {
|
2021-03-16 20:54:10 +01:00
|
|
|
|
// text_line
|
2021-03-24 10:34:17 +01:00
|
|
|
|
yield array("mode"=>"", "text" => rtrim($line));
|
2021-03-16 13:49:11 +01:00
|
|
|
|
}
|
|
|
|
|
} else {
|
2021-03-16 20:54:10 +01:00
|
|
|
|
if ("```"==$mode) {
|
2021-03-16 13:49:11 +01:00
|
|
|
|
if ("```" == $line3) {
|
2021-03-16 20:54:10 +01:00
|
|
|
|
yield $current;
|
|
|
|
|
$current = array();
|
2021-03-16 13:49:11 +01:00
|
|
|
|
$mode = null;
|
|
|
|
|
} else {
|
2021-03-24 10:34:17 +01:00
|
|
|
|
$current["texts"] []= rtrim($line); // No ltrim() as it’s a preformated text!
|
2021-03-16 13:49:11 +01:00
|
|
|
|
}
|
2021-03-16 20:54:10 +01:00
|
|
|
|
} elseif (">"==$mode) {
|
2021-03-16 13:49:11 +01:00
|
|
|
|
if (">" == $line1) {
|
2021-03-16 20:54:10 +01:00
|
|
|
|
preg_match("/^>\s*(.*)$/", $line, $matches);
|
|
|
|
|
$current["texts"] []= trim($matches[1]);
|
2021-03-16 13:49:11 +01:00
|
|
|
|
} else {
|
2021-03-16 20:54:10 +01:00
|
|
|
|
yield $current;
|
|
|
|
|
$current = array();
|
2021-03-16 13:49:11 +01:00
|
|
|
|
$mode = null;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2021-03-16 20:54:10 +01:00
|
|
|
|
} elseif ("*"==$mode) {
|
2021-03-16 13:49:11 +01:00
|
|
|
|
if ("*" == $line1) {
|
2021-03-16 20:54:10 +01:00
|
|
|
|
preg_match("/^\*\s*(.*)$/", $line, $matches);
|
|
|
|
|
$current["texts"] []= trim($matches[1]);
|
2021-03-16 13:49:11 +01:00
|
|
|
|
} else {
|
2021-03-16 20:54:10 +01:00
|
|
|
|
yield $current;
|
|
|
|
|
$current = array();
|
2021-03-16 13:49:11 +01:00
|
|
|
|
$mode = null;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
die("Unexpected mode: $mode!");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break; // exits the while(true) as no continue occured
|
|
|
|
|
} // while(true)
|
2021-03-16 20:54:10 +01:00
|
|
|
|
}// foreach
|
|
|
|
|
if ($current) yield $current; # File ends before the block.
|
|
|
|
|
} // gemtextParser
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Translates the internal format into a gemtext.
|
|
|
|
|
* Uses cases:
|
|
|
|
|
*
|
|
|
|
|
* - test suites
|
|
|
|
|
* - serialisation easier with a text content
|
|
|
|
|
* - normalization (trimming spaces for instance)
|
|
|
|
|
*/
|
|
|
|
|
class GemtextTranslate_gemtext {
|
|
|
|
|
|
|
|
|
|
function __construct($parsedGemtext) {
|
2021-03-24 10:34:17 +01:00
|
|
|
|
if (empty($parsedGemtext)) $parsedGemtext = "";
|
|
|
|
|
// to delete the last empty lines
|
|
|
|
|
$parsedGemtext = rtrim($parsedGemtext);
|
|
|
|
|
// The text must be parsed
|
|
|
|
|
$this->parsedGemtext = gemtextParser($parsedGemtext);
|
2021-03-16 20:54:10 +01:00
|
|
|
|
$this->translate();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected function translate() {
|
2021-03-19 17:39:42 +01:00
|
|
|
|
$output = "";
|
2021-03-16 20:54:10 +01:00
|
|
|
|
foreach ($this->parsedGemtext as $node) {
|
|
|
|
|
$mode = $node["mode"];
|
|
|
|
|
switch($mode) {
|
|
|
|
|
case "":
|
2021-03-19 17:39:42 +01:00
|
|
|
|
$output .= $node["text"]."\n";
|
2021-03-16 20:54:10 +01:00
|
|
|
|
break;
|
|
|
|
|
case "*":
|
|
|
|
|
foreach ($node["texts"] as $text) {
|
2021-03-19 17:39:42 +01:00
|
|
|
|
$output .= "* $text\n";
|
2021-03-16 20:54:10 +01:00
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case "```":
|
2021-03-24 10:34:17 +01:00
|
|
|
|
$alt = $node["alt"];
|
|
|
|
|
if (empty($alt))
|
|
|
|
|
$output .= "```\n";
|
|
|
|
|
else
|
|
|
|
|
$output .= "``` $alt\n";
|
2021-03-16 20:54:10 +01:00
|
|
|
|
foreach ($node["texts"] as $text) {
|
2021-03-19 17:39:42 +01:00
|
|
|
|
$output .= "$text\n";
|
2021-03-16 20:54:10 +01:00
|
|
|
|
}
|
2021-03-19 17:39:42 +01:00
|
|
|
|
$output .= "```\n";
|
2021-03-16 20:54:10 +01:00
|
|
|
|
break;
|
|
|
|
|
case ">":
|
|
|
|
|
foreach ($node["texts"] as $text) {
|
2021-03-24 10:34:17 +01:00
|
|
|
|
if (empty($text))
|
|
|
|
|
$output .= ">\n";
|
|
|
|
|
else
|
|
|
|
|
$output .= "> $text\n";
|
2021-03-16 20:54:10 +01:00
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case "=>":
|
|
|
|
|
$linkText = $node["text"];
|
2021-03-24 10:34:17 +01:00
|
|
|
|
$link = $node["link"];
|
2021-03-16 20:54:10 +01:00
|
|
|
|
if (!empty($linkText)) $linkText = " $linkText";
|
2021-03-24 10:34:17 +01:00
|
|
|
|
if (!empty($link)) $link = " $link";
|
|
|
|
|
$output .= "=>".$link.$linkText."\n";
|
2021-03-16 20:54:10 +01:00
|
|
|
|
break;
|
|
|
|
|
case "#":
|
|
|
|
|
case "##":
|
|
|
|
|
case "###":
|
2021-03-19 17:39:42 +01:00
|
|
|
|
$output .= "$mode ".$node["title"]."\n";
|
2021-03-16 20:54:10 +01:00
|
|
|
|
break;
|
|
|
|
|
case "^^^":
|
2021-03-19 17:39:42 +01:00
|
|
|
|
$output .= "^^^\n";
|
2021-03-16 20:54:10 +01:00
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
die("Unknown mode: '{$node["mode"]}'\n");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-19 17:39:42 +01:00
|
|
|
|
$this->translatedGemtext = $output;
|
2021-03-16 20:54:10 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function __toString() {
|
|
|
|
|
return $this->translatedGemtext;
|
|
|
|
|
}
|
|
|
|
|
} // GemtextTranslate_gemtext
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Translates the internal format to HTML
|
|
|
|
|
*/
|
|
|
|
|
class GemtextTranslate_html {
|
|
|
|
|
|
|
|
|
|
protected $cssList = array();
|
|
|
|
|
protected $pageTitle = "";
|
|
|
|
|
public $translatedGemtext;
|
|
|
|
|
|
2021-04-11 21:35:55 +02:00
|
|
|
|
/**
|
|
|
|
|
* @param $parsedGemtext the gemtext internal format
|
|
|
|
|
* @param $textDecoration bool to interpret or not the text decoration
|
|
|
|
|
* @param $urlPrefix the prefix to prepend if the URL rewriting is not on
|
|
|
|
|
* @param $currentPageDir the current directory, to be used without URL rewriting
|
|
|
|
|
*/
|
|
|
|
|
function __construct($parsedGemtext, $textDecoration=true, $urlPrefix=null, $currentPageDir=null) {
|
|
|
|
|
$this->urlPrefix = $urlPrefix;
|
|
|
|
|
$this->currentPageDir = $currentPageDir;
|
2021-03-24 10:34:17 +01:00
|
|
|
|
if (empty($parsedGemtext)) $parsedGemtext = "";
|
|
|
|
|
// to delete the last empty lines
|
|
|
|
|
$parsedGemtext = rtrim($parsedGemtext);
|
|
|
|
|
// The text must be parsed
|
|
|
|
|
$parsedGemtext = gemtextParser($parsedGemtext);
|
2021-03-16 20:54:10 +01:00
|
|
|
|
$this->parsedGemtext = $parsedGemtext;
|
2021-03-19 17:49:00 +01:00
|
|
|
|
$this->translate($textDecoration);
|
2021-03-16 20:54:10 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function addCss($css) {
|
|
|
|
|
$this->cssList []= $css;
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-02 21:00:09 +02:00
|
|
|
|
function getCss() { return $this->cssList; }
|
|
|
|
|
function getTitle() { return $this->pageTitle; }
|
|
|
|
|
|
2021-03-16 20:54:10 +01:00
|
|
|
|
const NARROW_NO_BREAK_SPACE = " ";
|
|
|
|
|
const DASHES
|
|
|
|
|
="‒" # U+2012 Figure Dash
|
|
|
|
|
."–" # U+2013 En Dash
|
|
|
|
|
."—" # U+2014 Em Dash
|
|
|
|
|
."⸺" # U+2E3A Two-Em Dash
|
|
|
|
|
."⸻" # U+2E3B Three-Em Dash (Three times larger than a single char)
|
|
|
|
|
;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Replaces markups things like __underlined__ to <u>underlined</u>.
|
|
|
|
|
* @param $instruction the characters to replace, ex. _
|
|
|
|
|
* @param $markup the markup to replace to, ex. "u" to get <u>…</u>
|
|
|
|
|
* @param &$text where to replace.
|
|
|
|
|
*/
|
|
|
|
|
protected static function markupPreg($instruction, $markup, &$text) {
|
|
|
|
|
$output = $text;
|
|
|
|
|
|
|
|
|
|
# Replaces couples "__word__" into "<i>word</i>".
|
|
|
|
|
$output = mb_ereg_replace("${instruction}(.+?)${instruction}", "<{$markup}>\\1</{$markup}>", $output);
|
|
|
|
|
|
|
|
|
|
# Replaces a remaining __ into "<i>…</i>" to the end of the line.
|
|
|
|
|
$output = mb_ereg_replace("${instruction}(.+)?", "<{$markup}>\\1</{$markup}>", $output);
|
|
|
|
|
|
|
|
|
|
$text = $output;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Adds text attributes sucj as underline, bold, … to $line
|
|
|
|
|
* @param $line the line to process
|
|
|
|
|
*/
|
|
|
|
|
protected static function addTextDecoration(&$line) {
|
|
|
|
|
self::markupPreg("__", "u", $line);
|
|
|
|
|
self::markupPreg("\*\*", "strong", $line);
|
|
|
|
|
self::markupPreg("//", "em", $line);
|
|
|
|
|
self::markupPreg("~~", "del", $line);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Prepares the raw text to be displayed in HTML environment:
|
|
|
|
|
* * Escapes the HTML entities yet contained in the Gemtext.
|
|
|
|
|
* * Puts thin unbrakable spaces before some characters.
|
|
|
|
|
* @param $text1, $text2 texts to process
|
|
|
|
|
*/
|
|
|
|
|
protected static function htmlPrepare(&$text) {
|
|
|
|
|
if (empty($text)) {
|
|
|
|
|
$text = " ";
|
|
|
|
|
} else {
|
2021-03-20 15:00:24 +01:00
|
|
|
|
$text = htmlspecialchars($text, ENT_HTML5|ENT_QUOTES, "UTF-8", true);
|
2021-03-16 20:54:10 +01:00
|
|
|
|
$text = mb_ereg_replace("\ ([?!:;»€$])", self::NARROW_NO_BREAK_SPACE."\\1", $text);
|
|
|
|
|
$text = mb_ereg_replace("([«])\ ", "\\1".self::NARROW_NO_BREAK_SPACE, $text); # Espace fine insécable
|
|
|
|
|
|
|
|
|
|
# Warning: using a monospace font editor may not display dashes as they should be!
|
|
|
|
|
# Adds no-break spaces to stick the (EM/EN dashes) to words : aaaaaa – bb – ccccc ==> aaaaaa –$bb$– ccccc
|
|
|
|
|
$text = mb_ereg_replace("([".self::DASHES."]) ([^".self::DASHES.".]+) ([".self::DASHES."])", "\\1".self::NARROW_NO_BREAK_SPACE."\\2".self::NARROW_NO_BREAK_SPACE."\\3", $text);
|
|
|
|
|
|
|
|
|
|
# Adds no-break space to stick the (EM/EN dashes) to words : aaaaaa – bb. ==> aaaaaa –$bb.
|
|
|
|
|
$text = mb_ereg_replace("([—–]) ([^.]+)\.", "\\1".self::NARROW_NO_BREAK_SPACE."\\2.", $text);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-25 23:00:48 +01:00
|
|
|
|
protected static function spacesCompress(&$text) {
|
|
|
|
|
# Replaces several spaces (0x20) by only one
|
2022-07-28 21:50:52 +02:00
|
|
|
|
if (empty($text)) $text = "";
|
2021-03-25 23:00:48 +01:00
|
|
|
|
$text = preg_replace("/ +/", " ", $text);
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-16 20:54:10 +01:00
|
|
|
|
public function translate($textDecoration=true) {
|
2021-03-19 17:39:42 +01:00
|
|
|
|
$output = "";
|
2021-03-16 20:54:10 +01:00
|
|
|
|
foreach ($this->parsedGemtext as $node) {
|
|
|
|
|
$mode = $node["mode"];
|
|
|
|
|
switch($mode) {
|
|
|
|
|
case "":
|
|
|
|
|
$text = $node["text"];
|
2021-03-25 23:00:48 +01:00
|
|
|
|
self::spacesCompress($text);
|
2021-03-16 20:54:10 +01:00
|
|
|
|
self::htmlPrepare($text);
|
|
|
|
|
if ($textDecoration) self::addTextDecoration($text);
|
2021-03-19 17:39:42 +01:00
|
|
|
|
$output .= "<p>$text</p>\n";
|
2021-03-16 20:54:10 +01:00
|
|
|
|
break;
|
|
|
|
|
case "*":
|
2021-03-19 17:39:42 +01:00
|
|
|
|
$output .= "<ul>\n";
|
2021-03-16 20:54:10 +01:00
|
|
|
|
foreach ($node["texts"] as $text) {
|
2021-03-25 23:00:48 +01:00
|
|
|
|
self::spacesCompress($text);
|
2021-03-16 20:54:10 +01:00
|
|
|
|
self::htmlPrepare($text);
|
|
|
|
|
if ($textDecoration) self::addTextDecoration($text);
|
2021-03-19 17:39:42 +01:00
|
|
|
|
$output .= "<li>$text\n";
|
2021-03-16 20:54:10 +01:00
|
|
|
|
}
|
2021-03-19 17:39:42 +01:00
|
|
|
|
$output .= "</ul>\n";
|
2021-03-16 20:54:10 +01:00
|
|
|
|
break;
|
|
|
|
|
case "```":
|
|
|
|
|
$text = implode("\n", $node["texts"]);
|
|
|
|
|
self::htmlPrepare($text);
|
2021-04-05 11:36:14 +02:00
|
|
|
|
$alt = $node["alt"];
|
|
|
|
|
$output .= "<pre alt='$alt'>\n$text\n</pre>\n";
|
2021-03-16 20:54:10 +01:00
|
|
|
|
break;
|
|
|
|
|
case ">":
|
2021-03-25 12:22:39 +01:00
|
|
|
|
$output .= "<blockquote>\n";
|
|
|
|
|
foreach ($node["texts"] as $text) {
|
2021-03-25 23:00:48 +01:00
|
|
|
|
self::spacesCompress($text);
|
2021-03-25 12:22:39 +01:00
|
|
|
|
self::htmlPrepare($text);
|
|
|
|
|
if ($textDecoration) self::addTextDecoration($text);
|
|
|
|
|
$output .= "<p>$text</p>\n";
|
|
|
|
|
}
|
|
|
|
|
$output .= "</blockquote>\n";
|
2021-03-16 20:54:10 +01:00
|
|
|
|
break;
|
|
|
|
|
case "=>":
|
|
|
|
|
$link = $node["link"];
|
|
|
|
|
$linkText = $node["text"];
|
|
|
|
|
if (empty($linkText)) {
|
|
|
|
|
$linkText = $link;
|
|
|
|
|
self::htmlPrepare($linkText);
|
|
|
|
|
} else {
|
2021-03-25 23:00:48 +01:00
|
|
|
|
self::spacesCompress($linkText);
|
2021-03-20 15:00:24 +01:00
|
|
|
|
// Don't double encode, just escapes quotes, "<" and ">".
|
|
|
|
|
// So "I'm>" becomes "I'>". The & remains untouched.
|
|
|
|
|
$link = htmlspecialchars($link, ENT_HTML5|ENT_QUOTES, "UTF-8", false);
|
2021-03-16 20:54:10 +01:00
|
|
|
|
self::htmlPrepare($linkText);
|
|
|
|
|
if ($textDecoration) self::addTextDecoration($linkText);
|
|
|
|
|
}
|
|
|
|
|
preg_match("/^([^:]+):/", $link, $matches);
|
2021-04-02 23:48:02 +02:00
|
|
|
|
$protocol = @$matches[1]??"local";
|
|
|
|
|
if ("local"==$protocol) {
|
2021-04-11 21:35:55 +02:00
|
|
|
|
if (!is_null($this->urlPrefix)) { // No URL rewriting
|
|
|
|
|
$link = $this->currentPageDir."/".$link;
|
|
|
|
|
$link = resolve_path($link);
|
|
|
|
|
$link = $this->urlPrefix.$link;
|
2021-03-28 21:50:36 +02:00
|
|
|
|
}
|
2021-04-02 23:48:02 +02:00
|
|
|
|
$newWindow = "";
|
|
|
|
|
} else {
|
|
|
|
|
$newWindow = "target='_blank' ";
|
2021-03-28 21:50:36 +02:00
|
|
|
|
}
|
2021-04-02 23:48:02 +02:00
|
|
|
|
$output .= "<p><a {$newWindow}class='$protocol' href='$link'>$linkText</a></p>\n";
|
2021-03-16 20:54:10 +01:00
|
|
|
|
break;
|
|
|
|
|
case "#":
|
|
|
|
|
$title = $node["title"];
|
2021-03-25 23:00:48 +01:00
|
|
|
|
self::spacesCompress($linkText);
|
2021-03-16 20:54:10 +01:00
|
|
|
|
self::htmlPrepare($title);
|
|
|
|
|
if (empty($this->pageTitle)) $this->pageTitle = $title;
|
2021-03-19 17:39:42 +01:00
|
|
|
|
$output .= "<h1>$title</h1>\n";
|
2021-03-16 20:54:10 +01:00
|
|
|
|
break;
|
|
|
|
|
case "##":
|
|
|
|
|
$title = $node["title"];
|
2021-03-25 23:00:48 +01:00
|
|
|
|
self::spacesCompress($linkText);
|
2021-03-16 20:54:10 +01:00
|
|
|
|
self::htmlPrepare($title);
|
2021-03-19 17:39:42 +01:00
|
|
|
|
$output .= "<h2>$title</h2>\n";
|
2021-03-16 20:54:10 +01:00
|
|
|
|
break;
|
|
|
|
|
case "###":
|
|
|
|
|
$title = $node["title"];
|
2021-03-25 23:00:48 +01:00
|
|
|
|
self::spacesCompress($linkText);
|
2021-03-16 20:54:10 +01:00
|
|
|
|
self::htmlPrepare($title);
|
2021-03-19 17:39:42 +01:00
|
|
|
|
$output .= "<h3>$title</h3>\n";
|
2021-03-16 20:54:10 +01:00
|
|
|
|
break;
|
|
|
|
|
case "^^^":
|
2021-03-19 17:49:00 +01:00
|
|
|
|
$textDecoration = !$textDecoration;
|
2021-03-16 20:54:10 +01:00
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
die("Unknown mode: '{$node["mode"]}'\n");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-19 17:39:42 +01:00
|
|
|
|
$this->translatedGemtext = $output;
|
2021-03-16 20:54:10 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // GemTextTranslate_html
|
2021-03-16 13:49:11 +01:00
|
|
|
|
|
|
|
|
|
?>
|