From 3718f2fe2d07b154ab4dc9b215daf21096b9e86f Mon Sep 17 00:00:00 2001 From: haszi Date: Sat, 24 Feb 2024 04:00:32 +0100 Subject: [PATCH] Enable nested roles (#103) * Enable nested roles Refactor role to be an array instead of a string to allow nesting of roles. Use the indent method to format constant list tables. Add tests for regular, table formatted and nested role containing variablelists. * Make role property private Add methods to push, pop and get role, and use these for all role accesses. Make underlying $role array private. Add comment on $role array being a LIFO stack. --------- Co-authored-by: haszi --- phpdotnet/phd/Format/Abstract/XHTML.php | 21 +++-- phpdotnet/phd/Package/Generic/XHTML.php | 70 ++++++++-------- phpdotnet/phd/Package/PEAR/XHTML.php | 24 +++--- phpdotnet/phd/Package/PHP/XHTML.php | 2 +- tests/php/data/variablelist_rendering_001.xml | 40 ++++++++++ tests/php/variablelist_rendering_001.phpt | 79 +++++++++++++++++++ 6 files changed, 179 insertions(+), 57 deletions(-) create mode 100644 tests/php/data/variablelist_rendering_001.xml create mode 100644 tests/php/variablelist_rendering_001.phpt diff --git a/phpdotnet/phd/Format/Abstract/XHTML.php b/phpdotnet/phd/Format/Abstract/XHTML.php index 07938cba..c2ddd71d 100644 --- a/phpdotnet/phd/Format/Abstract/XHTML.php +++ b/phpdotnet/phd/Format/Abstract/XHTML.php @@ -2,7 +2,9 @@ namespace phpdotnet\phd; abstract class Format_Abstract_XHTML extends Format { - public $role = false; + + /** @var array Last In First Out stack of roles */ + private array $role = []; /* XHTMLPhDFormat */ protected $openPara = 0; @@ -39,14 +41,14 @@ public function UNDEF($open, $name, $attrs, $props) { } public function CDATA($str) { - switch($this->role) { + switch($this->getRole()) { case '': return '
'
                 . htmlspecialchars($str, ENT_QUOTES, "UTF-8")
                 . '
'; default: - return '
' - . $this->highlight(trim($str), $this->role, 'xhtml') + return '
' + . $this->highlight(trim($str), $this->getRole(), 'xhtml') . '
'; } } @@ -123,6 +125,15 @@ public function restorePara() { } } -} + protected function pushRole(?string $role): void { + $this->role[] = $role; + } + protected function getRole(): ?string { + return end($this->role); + } + protected function popRole(): ?string { + return array_pop($this->role); + } +} diff --git a/phpdotnet/phd/Package/Generic/XHTML.php b/phpdotnet/phd/Package/Generic/XHTML.php index 7fda77b1..d6aa8597 100644 --- a/phpdotnet/phd/Package/Generic/XHTML.php +++ b/phpdotnet/phd/Package/Generic/XHTML.php @@ -705,29 +705,25 @@ public function format_option($open, $name, $attrs) { if(!isset($attrs[Reader::XMLNS_DOCBOOK]["role"])) { $attrs[Reader::XMLNS_DOCBOOK]["role"] = "unknown"; } - $this->role = $role = $attrs[Reader::XMLNS_DOCBOOK]["role"]; - return ''; + $this->pushRole($attrs[Reader::XMLNS_DOCBOOK]["role"]); + return ''; } - $this->role = null; + $this->popRole(); return ""; } public function format_literal($open, $name, $attrs) { if ($open) { - if (isset($attrs[Reader::XMLNS_DOCBOOK]["role"])) { - $this->role = $attrs[Reader::XMLNS_DOCBOOK]["role"]; - } else { - $this->role = false; - } + $this->pushRole($attrs[Reader::XMLNS_DOCBOOK]["role"] ?? null); return ''; } - $this->role = false; + $this->popRole(); return ''; } public function format_literal_text($value, $tag) { - switch ($this->role) { + switch ($this->getRole()) { case 'infdec': $value = (float)$value; $p = strpos($value, '.'); @@ -930,18 +926,18 @@ public function format_refsect($open, $name, $attrs) { if(!isset($attrs[Reader::XMLNS_DOCBOOK]["role"])) { $attrs[Reader::XMLNS_DOCBOOK]["role"] = "unknown-" . ++$role; } - $this->role = $role = $attrs[Reader::XMLNS_DOCBOOK]["role"]; + $this->pushRole($attrs[Reader::XMLNS_DOCBOOK]["role"]); if (isset($attrs[Reader::XMLNS_XML]["id"])) { $id = $attrs[Reader::XMLNS_XML]["id"]; } else { - $id = $name. "-" . $this->CURRENT_CHUNK . "-" . $role; + $id = $name. "-" . $this->CURRENT_CHUNK . "-" . $this->getRole(); } - return '
'; + return '
'; } - $this->role = null; + $this->popRole(); return "
\n"; } @@ -1495,24 +1491,29 @@ public function format_step($open, $name, $attrs) { public function format_variablelist($open, $name, $attrs, $props) { if ($open) { if (isset($attrs[Reader::XMLNS_DOCBOOK]["role"])) { - $this->role = $attrs[Reader::XMLNS_DOCBOOK]["role"]; + $this->pushRole($attrs[Reader::XMLNS_DOCBOOK]["role"]); } $classStr = $headerStr = $idStr = ''; if (isset($attrs[Reader::XMLNS_XML]["id"])) { $idStr = ' id="' . $attrs[Reader::XMLNS_XML]["id"] . '"'; } - if ($this->role === 'constant_list') { + if ($this->getRole() === 'constant_list') { $tagName = 'table'; $classStr = ' class="doctable table"'; - $headerStr = "\n\n" . $this->autogen('Constants', $props['lang']) . "\n" . $this->autogen('Description', $props['lang']) . "\n"; + $headerStr = "\n" . $this->indent($props["depth"] + 1) . "\n" + . $this->indent($props["depth"] + 2) . "" + . $this->autogen('Constants', $props['lang']) . "\n" + . $this->indent($props["depth"] + 2) . "" + . $this->autogen('Description', $props['lang']) . "\n" + . $this->indent($props["depth"] + 1) . ""; } else { $tagName = 'dl'; } return '<' . $tagName . $idStr . $classStr . '>' . $headerStr; } - $tagName = ($this->role === 'constant_list') ? 'table' : 'dl'; - $this->role = false; - return "\n"; + $tagName = ($this->getRole() === 'constant_list') ? 'table' : 'dl'; + $this->popRole(); + return ""; } public function format_varlistentry($open, $name, $attrs) { if ($open) { @@ -1521,29 +1522,29 @@ public function format_varlistentry($open, $name, $attrs) { } else { unset($this->cchunk['varlistentry']['id']); } - return ($this->role === 'constant_list') ? '' : ''; + return ($this->getRole() === 'constant_list') ? '' : ''; } - return ($this->role === 'constant_list') ? '' : ''; + return ($this->getRole() === 'constant_list') ? '' : ''; } public function format_varlistentry_term($open, $name, $attrs, $props) { - $tagName = ($this->role === 'constant_list') ? 'td' : 'dt'; + $tagName = ($this->getRole() === 'constant_list') ? 'td' : 'dt'; if ($open) { if (isset($this->cchunk['varlistentry']['id'])) { $id = $this->cchunk['varlistentry']['id']; unset($this->cchunk['varlistentry']['id']); return '<' . $tagName . ' id="' . $id . '">'; } else { - return "<" . $tagName . ">\n"; + return "<" . $tagName . ">"; } } - return "\n"; + return ""; } public function format_varlistentry_listitem($open, $name, $attrs) { - $tagName = ($this->role === 'constant_list') ? 'td' : 'dd'; + $tagName = ($this->getRole() === 'constant_list') ? 'td' : 'dd'; if ($open) { - return "<" . $tagName . ">\n"; + return "<" . $tagName . ">"; } - return "\n"; + return ""; } public function format_term($open, $name, $attrs, $props) { if ($open) { @@ -1586,15 +1587,10 @@ public function format_example_content($open, $name, $attrs) { } public function format_programlisting($open, $name, $attrs) { if ($open) { - if (isset($attrs[Reader::XMLNS_DOCBOOK]["role"])) { - $this->role = $attrs[Reader::XMLNS_DOCBOOK]["role"]; - } else { - $this->role = false; - } - + $this->pushRole($attrs[Reader::XMLNS_DOCBOOK]["role"] ?? null); return '
'; } - $this->role = false; + $this->popRole(); return "
\n"; } public function format_programlisting_text($value, $tag) { @@ -1704,9 +1700,9 @@ public function format_table_title($open, $name, $attrs, $props) } public function format_variablelist_title($open, $name, $attrs, $props) { if ($open) { - return ($this->role === 'constant_list') ? "" : ""; + return ($this->getRole() === 'constant_list') ? "" : ""; } - return ($this->role === 'constant_list') ? "" : ""; + return ($this->getRole() === 'constant_list') ? "" : ""; } public function format_mediaobject($open, $name, $attrs) { diff --git a/phpdotnet/phd/Package/PEAR/XHTML.php b/phpdotnet/phd/Package/PEAR/XHTML.php index 5fd02475..fdfef226 100755 --- a/phpdotnet/phd/Package/PEAR/XHTML.php +++ b/phpdotnet/phd/Package/PEAR/XHTML.php @@ -683,16 +683,12 @@ public function format_programlisting($open, $name, $attrs) { if ($open) { $this->trim = true; - if (isset($attrs[Reader::XMLNS_DOCBOOK]['role'])) { - $this->role = $attrs[Reader::XMLNS_DOCBOOK]['role']; - } else { - $this->role = ''; - } + $this->pushRole($attrs[Reader::XMLNS_DOCBOOK]['role'] ?? ''); - return '
getRole() ? $this->getRole() . 'code' : 'programlisting') . '">'; } - $this->role = false; + $this->popRole(); $this->trim = false; return '
'; @@ -710,7 +706,7 @@ public function format_programlisting($open, $name, $attrs) */ public function format_programlisting_text($value, $tag) { - switch($this->role) { + switch($this->getRole()) { case 'php': if (strrpos($value, '')) { return $this->highlight(trim($value), 'php', 'xhtml'); @@ -719,7 +715,7 @@ public function format_programlisting_text($value, $tag) } break; default: - return $this->highlight(trim($value), $this->role, 'xhtml'); + return $this->highlight(trim($value), $this->getRole(), 'xhtml'); } } @@ -760,26 +756,26 @@ public function CDATA($str) if ($this->trim) { $str = rtrim($str); } - if (!$this->role) { + if (!$this->getRole()) { return str_replace( array("\n", ' '), array('
', ' '), htmlspecialchars($str, ENT_QUOTES, 'UTF-8') ); } - switch ($this->role) { + switch ($this->getRole()) { case 'php': if (strrpos($str, '')) { - $str = $this->highlight(trim($str), $this->role, 'xhtml'); + $str = $this->highlight(trim($str), $this->getRole(), 'xhtml'); } else { - $str = $this->highlight("", $this->role, 'xhtml'); + $str = $this->highlight("", $this->getRole(), 'xhtml'); } break; case '': $str = htmlspecialchars($str, ENT_QUOTES, 'UTF-8'); break; default: - $str = $this->highlight($str, $this->role, 'xhtml'); + $str = $this->highlight($str, $this->getRole(), 'xhtml'); break; } diff --git a/phpdotnet/phd/Package/PHP/XHTML.php b/phpdotnet/phd/Package/PHP/XHTML.php index 4b2928f0..6e4ba5a4 100644 --- a/phpdotnet/phd/Package/PHP/XHTML.php +++ b/phpdotnet/phd/Package/PHP/XHTML.php @@ -843,7 +843,7 @@ public function format_function_text($value, $tag, $display_value = null) { if ($filename !== null) { if ($this->CURRENT_ID !== $filename) { $rel = $desc = ""; - if ($this->role == "seealso") { + if ($this->getRole() === "seealso") { $rel = ' rel="rdfs-seeAlso"'; $desc = " - " . Format::getLongDescription($filename); } diff --git a/tests/php/data/variablelist_rendering_001.xml b/tests/php/data/variablelist_rendering_001.xml new file mode 100644 index 00000000..501daca1 --- /dev/null +++ b/tests/php/data/variablelist_rendering_001.xml @@ -0,0 +1,40 @@ + + + +
+ 1. Variablelist with no role + + + VARIABLELIST_TEST_CONSTANT + + + Description of constant + + + + +
+ +
+ 2. Variablelist with role="constant_list" + + + VARIABLELIST_TEST_CONSTANT_IN_CONSTANT_LIST + + + literal will add its own "role" + + + + + VARIABLELIST_TEST_CONSTANT_IN_CONSTANT_LIST2 + + + Role should have not been overwritten by literal + + + + +
+ +
diff --git a/tests/php/variablelist_rendering_001.phpt b/tests/php/variablelist_rendering_001.phpt new file mode 100644 index 00000000..5855f264 --- /dev/null +++ b/tests/php/variablelist_rendering_001.phpt @@ -0,0 +1,79 @@ +--TEST-- +Variablelist rendering 001 +--FILE-- + true, + "xml_root" => dirname($xml_file), + "xml_file" => $xml_file, + "output_dir" => __DIR__ . "/output/", +); + +$extra = array( + "lang_dir" => __PHDDIR__ . "phpdotnet/phd/data/langs/", + "phpweb_version_filename" => dirname($xml_file) . '/version.xml', + "phpweb_acronym_filename" => dirname($xml_file) . '/acronyms.xml', +); + +$render = new TestRender($formatclass, $opts, $extra); + +if (Index::requireIndexing() && !file_exists($opts["output_dir"])) { + mkdir($opts["output_dir"], 0755); +} + +$render->run(); +?> +--EXPECTF-- +Filename: variablelist-rendering.html +Content: +
+ +
+

%d. Variablelist with no role

+
+ +
VARIABLELIST_TEST_CONSTANT
+
+ + Description of constant + +
+ +
+
+ +
+

%d. Variablelist with role="constant_list"

+ + + + + + + + + + + + + +
ConstantsDescription
VARIABLELIST_TEST_CONSTANT_IN_CONSTANT_LIST + + literal will add its own "role" + +
VARIABLELIST_TEST_CONSTANT_IN_CONSTANT_LIST2 + + Role should have not been overwritten by literal + +
+
+ +