1
0
mirror of https://github.com/php/phd.git synced 2026-03-23 22:52:05 +01:00
Files
archived-phd/phpdotnet/phd/Package/PHP/XHTML.php
2024-02-08 12:46:21 +00:00

930 lines
36 KiB
PHP

<?php
namespace phpdotnet\phd;
abstract class Package_PHP_XHTML extends Package_Generic_XHTML {
private $myelementmap = array(
'acronym' => 'format_suppressed_tags',
'appendix' => 'format_container_chunk',
'article' => 'format_container_chunk',
'book' => 'format_root_chunk',
'chapter' => 'format_container_chunk',
'colophon' => 'format_chunk',
'function' => 'format_function',
'methodname' => 'format_function',
'methodsynopsis' => 'format_methodsynopsis',
'legalnotice' => 'format_chunk',
'part' => 'format_container_chunk',
'partintro' => 'format_partintro',
'preface' => 'format_chunk',
'phpdoc:classref' => 'format_class_chunk',
'phpdoc:exceptionref' => 'format_class_chunk',
'phpdoc:varentry' => 'format_varentry_chunk',
'refentry' => 'format_refentry',
'reference' => 'format_container_chunk',
'refpurpose' => 'format_refpurpose',
'refsynopsisdiv' => 'format_refsynopsisdiv',
'set' => 'format_root_chunk',
'setindex' => 'format_chunk',
'sidebar' => 'blockquote',
'title' => array(
/* DEFAULT */ 'h1',
'article' => 'format_container_chunk_title',
'appendix' => 'format_container_chunk_title',
'chapter' => 'format_container_chunk_title',
'example' => 'format_example_title',
'part' => 'format_container_chunk_title',
'info' => array(
/* DEFAULT */ 'h1',
'article' => 'format_container_chunk_title',
'appendix' => 'format_container_chunk_title',
'chapter' => 'format_container_chunk_title',
'example' => 'format_example_title',
'part' => 'format_container_chunk_title',
'note' => 'format_note_title',
'informaltable' => 'format_table_title',
'table' => 'format_table_title',
),
'formalpara' => 'h5',
'indexdiv' => 'dt',
'legalnotice' => 'h4',
'note' => 'format_note_title',
'phd:toc' => 'strong',
'procedure' => 'strong',
'refsect1' => 'h3',
'refsect2' => 'h4',
'refsect3' => 'h5',
'section' => 'h2',
'sect1' => 'h2',
'sect2' => 'h3',
'sect3' => 'h4',
'sect4' => 'h5',
'segmentedlist' => 'format_table_title',
'simplesect' => 'h3',
'table' => 'format_table_title',
'variablelist' => 'strong',
'varname' => array(
/* DEFAULT */ 'format_suppressed_tags',
'fieldsynopsis' => 'format_fieldsynopsis_varname',
),
),
'type' => array(
/* DEFAULT */ 'format_type',
'methodsynopsis' => 'format_methodsynopsis_type',
'type' => array(
/* DEFAULT */ 'format_type',
'methodsynopsis' => 'format_suppressed_tags',
),
),
'varname' => array(
/* DEFAULT */ 'format_suppressed_tags',
'fieldsynopsis' => 'format_fieldsynopsis_varname',
),
);
private $mytextmap = array(
'acronym' => 'format_acronym_text',
'function' => 'format_function_text',
/** Those are used to retrieve the class/interface name to be able to remove it from method names */
'classname' => [
/* DEFAULT */ 'format_classname_text',
'ooclass' => [
/* DEFAULT */ 'format_classname_text',
/** This is also used by the legacy display to not display the class name at all */
'classsynopsis' => 'format_classsynopsis_ooclass_classname_text',
]
],
'exceptionname' => [
/* DEFAULT */ 'format_classname_text',
'ooexception' => [
/* DEFAULT */ 'format_classname_text',
'classsynopsis' => 'format_classsynopsis_oo_name_text',
]
],
'interfacename' => [
/* DEFAULT */ 'format_classname_text',
'oointerface' => [
/* DEFAULT */ 'format_classname_text',
'classsynopsis' => 'format_classsynopsis_oo_name_text',
]
],
'methodname' => array(
/* DEFAULT */ 'format_function_text',
'constructorsynopsis' => array(
/* DEFAULT */ 'format_classsynopsis_methodsynopsis_methodname_text',
),
'methodsynopsis' => array(
/* DEFAULT */ 'format_classsynopsis_methodsynopsis_methodname_text',
),
'destructorsynopsis' => array(
/* DEFAULT */ 'format_classsynopsis_methodsynopsis_methodname_text',
),
),
'refname' => 'format_refname_text',
'type' => array(
/* DEFAULT */ 'format_type_if_object_or_pseudo_text',
'classsynopsisinfo' => false,
'fieldsynopsis' => 'format_type_if_object_or_pseudo_text',
'methodparam' => 'format_type_if_object_or_pseudo_text',
'methodsynopsis' => 'format_type_methodsynopsis_text',
'type' => array(
/* DEFAULT */ 'format_type_if_object_or_pseudo_text',
'methodsynopsis' => 'format_type_methodsynopsis_text',
),
),
'titleabbrev' => array(
/* DEFAULT */ 'format_suppressed_text',
'phpdoc:classref' => 'format_grep_classname_text',
'phpdoc:exceptionref' => 'format_grep_classname_text',
'refentry' => 'format_grep_classname_text',
),
'varname' => array(
/* DEFAULT */ 'format_varname_text',
'fieldsynopsis' => array(
/* DEFAULT */ false,
'classsynopsis' => 'format_classsynopsis_fieldsynopsis_varname_text',
),
),
);
private $versions = array();
private $acronyms = array();
protected $deprecated = array();
protected $CURRENT_ID;
protected $CURRENT_CHUNK;
/* Current Chunk settings */
protected $cchunk = array();
/* Default Chunk settings */
protected $dchunk = array(
"class_name_ref" => null,
"args" => null,
"fieldsynopsis" => array(
"modifier" => "public",
),
"container_chunk" => null,
"qandaentry" => array(
),
"examples" => 0,
"verinfo" => false,
"refname" => array(),
"alternatives" => array(),
"refsynopsisdiv" => null,
);
/** @var int|null Number of already formatted types in the current compound type */
private $num_types = null;
/** @var string|null The character to separate the current compound type, i.e. "|" or "&" */
private $type_separator = null;
/** @var bool|null Decides whether the union type can be displayed by using "?" */
private $simple_nullable = null;
protected $pihandlers = array(
'dbhtml' => 'PI_DBHTMLHandler',
'dbtimestamp' => 'PI_DBHTMLHandler',
'phpdoc' => 'PI_PHPDOCHandler',
);
public function __construct() {
parent::__construct();
$this->myelementmap = array_merge(parent::getDefaultElementMap(), static::getDefaultElementMap());
$this->mytextmap = array_merge(parent::getDefaultTextMap(), static::getDefaultTextMap());
$this->dchunk = array_merge(parent::getDefaultChunkInfo(), static::getDefaultChunkInfo());
$this->registerPIHandlers($this->pihandlers);
}
public function getDefaultElementMap() {
return $this->myelementmap;
}
public function getDefaultTextMap() {
return $this->mytextmap;
}
public function getDefaultChunkInfo() {
return $this->dchunk;
}
public function loadVersionAcronymInfo() {
$this->versions = self::generateVersionInfo(Config::phpweb_version_filename());
$this->deprecated = self::generateDeprecatedInfo(Config::phpweb_version_filename());
$this->acronyms = self::generateAcronymInfo(Config::phpweb_acronym_filename());
}
public static function generateVersionInfo($filename) {
static $info;
if ($info) {
return $info;
}
if (!is_file($filename)) {
v("Can't find Version information file (%s), skipping!", $filename, E_USER_WARNING);
return array();
}
$r = new \XMLReader;
if (!$r->open($filename)) {
v("Can't open the version info file (%s)", $filename, E_USER_ERROR);
}
$versions = array();
while($r->read()) {
if (
$r->moveToAttribute("name")
&& ($funcname = str_replace(
array("::", "->", "__", "_", '$'),
array("-", "-", "-", "-", ""),
$r->value))
&& $r->moveToAttribute("from")
&& ($from = $r->value)
) {
$versions[strtolower($funcname)] = $from;
$r->moveToElement();
}
}
$r->close();
$info = $versions;
return $versions;
}
// Note that this function differs from generateVersionInfo()!
// Special characters in functions names are replaced to underscores (_),
// not hyphens (-).
protected static function generateDeprecatedInfo($filename) {
static $info;
if ($info) {
return $info;
}
if (!is_file($filename)) {
v("Can't find Version information file (%s), skipping!", $filename, E_USER_WARNING);
return array();
}
$r = new \XMLReader;
if (!$r->open($filename)) {
v("Can't open the version info file (%s)", $filename, E_USER_ERROR);
}
$deprecated = array();
while($r->read()) {
if (
$r->moveToAttribute("name")
&& ($funcname = str_replace(
array("::", "->", "__", "_", '$'),
array("_", "_", "_", "_", ""),
$r->value))
&& $r->moveToAttribute("deprecated")
&& ($value = $r->value)
) {
$deprecated[strtolower($funcname)] = $value;
$r->moveToElement();
}
}
$r->close();
$info = $deprecated;
return $deprecated;
}
public static function generateAcronymInfo($filename) {
static $info;
if ($info) {
return $info;
}
if (!is_file($filename)) {
v("Can't find acronym file (%s), skipping", $filename, E_USER_WARNING);
return array();
}
$r = new \XMLReader;
if (!$r->open($filename)) {
v("Could not open file for accessing acronym information (%s)", $filename, E_USER_ERROR);
}
$acronyms = array();
while ($r->read()) {
if ($r->nodeType != \XMLReader::ELEMENT) {
continue;
}
if ($r->name == "term") {
$r->read();
$k = $r->value;
$acronyms[$k] = "";
} else if ($r->name == "simpara") {
$r->read();
$acronyms[$k] = $r->value;
}
}
$info = $acronyms;
return $acronyms;
}
public function autogenVersionInfo($refnames) {
$verinfo = null;
foreach((array)$refnames as $refname) {
$verinfo = $this->versionInfo($refname);
if ($verinfo) {
break;
}
}
if (!$verinfo) {
$verinfo = $this->autogen("unknownversion");
}
$retval = '<p class="verinfo">(' .(htmlspecialchars($verinfo, ENT_QUOTES, "UTF-8")). ')</p>';
return $retval;
}
public function format_type($open, $tag, $attrs, $props) {
$retval = '';
if ($open) {
if (isset($attrs[Reader::XMLNS_DOCBOOK]["class"])) {
$this->num_types = 0;
$this->simple_nullable = false;
$isUnionType = $attrs[Reader::XMLNS_DOCBOOK]["class"] === "union";
if (
$isUnionType &&
substr_count($props["innerXml"], '<type xmlns="http://docbook.org/ns/docbook">') === 2 &&
strpos($props["innerXml"], '<type xmlns="http://docbook.org/ns/docbook">null</type>') !== false
) {
$this->simple_nullable = true;
$this->type_separator = "";
$retval .= '<span class="type">?</span>';
} else {
$this->type_separator = $isUnionType ? "|" : "&";
}
} elseif (isset($this->num_types)) {
if ($this->num_types > 0) {
$retval .= $this->type_separator;
}
$this->num_types++;
}
$retval .= '<span class="type">';
} else {
if (isset($attrs[Reader::XMLNS_DOCBOOK]["class"])) {
$this->num_types = null;
$this->type_separator = null;
$this->simple_nullable = null;
}
$retval .= '</span>';
}
return $retval;
}
public function format_methodsynopsis_type($open, $tag, $attrs)
{
if ($open && isset($attrs[Reader::XMLNS_DOCBOOK]["class"])) {
$this->cchunk["methodsynopsis"]["type_separator"] = $attrs[Reader::XMLNS_DOCBOOK]["class"] === "union" ? "|" : "&";
}
return "";
}
public function format_refpurpose($open, $tag, $attrs, $props) {
if ($open) {
$retval = "";
if ($this->cchunk["verinfo"]) {
$retval = $this->autogenVersionInfo($this->cchunk["refname"]);
}
$refnames = implode('</span> -- <span class="refname">', $this->cchunk["refname"]);
$retval .= '<p class="refpurpose"><span class="refname">'. $refnames. '</span> &mdash; <span class="dc-title">';
return $retval;
}
return "</span></p>\n";
}
public function format_refsynopsisdiv($open, $tag, $attrs, $props) {
if ($open) {
if (isset($attrs[Reader::XMLNS_DOCBOOK]["role"])) {
$this->cchunk["refsynopsisdiv"] = $attrs[Reader::XMLNS_DOCBOOK]["role"];
$id = $this->CURRENT_ID . "-" . $attrs[Reader::XMLNS_DOCBOOK]["role"];
return '<div id="' . $id . '" class="' . $attrs[Reader::XMLNS_DOCBOOK]["role"] . '">';
}
$id = $this->CURRENT_ID . "-" . $tag;
return '<div id="' . $id . '">';
}
$this->cchunk["refsynopsisdiv"] = $this->dchunk["refsynopsisdiv"];
return "</div>";
}
public function format_partintro($open, $tag, $attrs, $props) {
if ($open) {
$retval = "";
if ($this->cchunk["verinfo"]) {
$retval = $this->autogenVersionInfo($this->cchunk["class_name_ref"]);
}
return '<div class="' . $tag . '">' . $retval;
}
return '</div>';
}
public function format_refname_text($value, $tag) {
$this->cchunk["refname"][] = $this->TEXT($value);
return false;
}
public function format_fieldsynopsis_varname($open, $name, $attrs) {
if ($open) {
$href = "";
if (isset($attrs[Reader::XMLNS_DOCBOOK]["linkend"])) {
$linkto = $attrs[Reader::XMLNS_DOCBOOK]["linkend"];
$href = Format::getFilename($linkto);
if ($this->chunked) {
if ($href != $linkto) {
$href .= "{$this->ext}#{$linkto}";
} else {
$href .= $this->ext;
}
} else {
$href = '#' .$linkto;
}
$href = '<a href="' .$href. '">';
}
if (
$this->cchunk["fieldsynopsis"]["modifier"] == "const" ||
(
$nfo = $this->getChunkInfo() AND $nfo["fieldsynopsis"]["modifier"] == "const"
)
) {
return ' <var class="fieldsynopsis_varname">'.$href;
}
return ' <var class="'.$name.'">'.$href.'$';
}
if (isset($attrs[Reader::XMLNS_DOCBOOK]["linkend"])) {
return '</a></var>';
}
return '</var>';
}
public function format_varname_text($value, $tag) {
$var = $value;
if (($pos = strpos($value, "[")) !== false) {
$var = substr($value, 0, $pos);
}
if (($filename = $this->getVarnameLink($var)) !== null && !in_array($var, $this->cchunk["refname"])) {
$href = $this->chunked ? $filename.$this->ext : "#$filename";
return '<var class="varname"><a href="'.$href.'" class="classname">' .$value. '</a></var>';
}
return '<var class="varname">' .$value. '</var>';
}
public function format_methodsynopsis($open, $name, $attrs, $props) {
if ($open) {
return parent::format_methodsynopsis($open, $name, $attrs, $props);
}
$content = "";
if ($this->params["paramCount"] > 3) {
$content .= "<br>";
}
$content .= ")";
if ($this->cchunk["methodsynopsis"]["returntypes"]) {
$types = [];
$this->type_separator = $this->cchunk["methodsynopsis"]["type_separator"];
if (
$this->type_separator === "|" &&
count($this->cchunk["methodsynopsis"]["returntypes"]) === 2 &&
in_array("null", $this->cchunk["methodsynopsis"]["returntypes"], true)
) {
$this->simple_nullable = true;
$this->type_separator = "";
$types[] = '<span class="type">?</span>';
}
foreach ($this->cchunk["methodsynopsis"]["returntypes"] as $return_type) {
$formatted_type = self::format_type_if_object_or_pseudo_text($return_type, "type");
if ($formatted_type === false) {
$formatted_type = $return_type;
}
if ($formatted_type !== "") {
$types[] = '<span class="type">' . $formatted_type . '</span>';
}
}
$type = implode($this->type_separator ?? '', $types);
if (count($types) > 1) {
$type = '<span class="type">' . $type . '</span>';
}
$content .= ': ' . $type;
$this->simple_nullable = null;
}
$content .= "</div>\n";
$this->cchunk["methodsynopsis"] = $this->dchunk["methodsynopsis"];
return $content;
}
public function format_type_methodsynopsis_text($type, $tagname) {
$this->cchunk["methodsynopsis"]["returntypes"][] = $type;
return "";
}
public function format_type_if_object_or_pseudo_text($type, $tagname) {
if (strtolower($type) === "null" && $this->simple_nullable) {
return "";
}
if (in_array(strtolower($type), array("bool", "int", "double", "boolean", "integer", "float", "string", "array", "object", "resource", "null"))) {
return false;
}
return self::format_type_text($type, $tagname);
}
public function format_type_text($type, $tagname) {
$t = strtr(strtolower($type), ["_" => "-", "\\" => "-"]);
$href = $fragment = "";
switch($t) {
case "bool":
$href = "language.types.boolean";
break;
case "int":
$href = "language.types.integer";
break;
case "double":
$href = "language.types.float";
break;
case "boolean":
case "integer":
case "float":
case "string":
case "array":
case "object":
case "resource":
case "null":
if ($this->simple_nullable) {
return "";
}
case "callable":
case "iterable":
$href = "language.types.$t";
break;
case "mixed":
$href = "language.types.declarations";
$fragment = "language.types.declarations.$t";
break;
default:
/* Check if its a classname. */
$href = Format::getFilename("class.$t");
}
if ($href && $this->chunked) {
return '<a href="' .$href. $this->getExt().($fragment ? "#$fragment" : ""). '" class="' .$tagname. ' ' .$type. '">' .$type. '</a>';
}
if ($href) {
return '<a href="#' .($fragment ? $fragment : $href). '" class="' .$tagname. ' ' .$type. '">' .$type. '</a>';
}
return '<span class="' .$tagname. ' ' .$type. '">' .$type. '</span>';
}
public function format_example_title($open, $name, $attrs, $props) {
if ($props["empty"]) {
return "";
}
if ($open) {
return "<p><strong>" . ($this->autogen('example', $props['lang']) . ++$this->cchunk["examples"]) . " ";
}
return "</strong></p>";
}
public function configureVerInfoAttribute($attrs) {
/* Note role attribute also has usage with "noversion" to not check version availability */
/* TODO This should be migrated to the annotations attribute */
if (isset($attrs[Reader::XMLNS_DOCBOOK]["annotations"])) {
$this->cchunk["verinfo"] = !str_contains($attrs[Reader::XMLNS_DOCBOOK]["annotations"], 'verify_info:false');
} else if (isset($attrs[Reader::XMLNS_DOCBOOK]["role"])) {
$this->cchunk["verinfo"] = !($attrs[Reader::XMLNS_DOCBOOK]["role"] == "noversion");
} else {
$this->cchunk["verinfo"] = true;
}
}
public function versionInfo($funcname) {
$funcname = str_replace(
array("::", "-&gt;", "->", "__", "_", '$', '()'),
array("-", "-", "-", "-", "-", "", ''),
strtolower($funcname));
if(isset($this->versions[$funcname])) {
return $this->versions[$funcname];
}
v("No version info for %s", $funcname, VERBOSE_NOVERSION);
return false;
}
public function deprecationInfo($funcname) {
$funcname = str_replace(
array("::", "-&gt;", "->", "__", "_", '$', '()'),
array("_", "_", "_", "_", "_", "", ''),
strtolower($funcname));
if(isset($this->deprecated[$funcname])) {
return $this->deprecated[$funcname];
}
return false;
}
public function acronymInfo($acronym) {
return isset($this->acronyms[$acronym]) ? $this->acronyms[$acronym] : false;
}
public function format_acronym_text($value, $tag) {
$resolved = $this->acronymInfo($value);
if ($resolved) {
return '<abbr title="' .$resolved. '">' .$value. '</abbr>';
}
return '<abbr>'.$value.'</abbr>';
}
public function format_classsynopsis_fieldsynopsis_varname_text($value, $tag) {
if ($this->cchunk["classsynopsis"]["classname"]) {
if (strpos($value, "::") === false && strpos($value, "->") === false) {
$value = $this->cchunk["classsynopsis"]["classname"] . "->" . $value;
}
}
$display_value = parent::format_classsynopsis_methodsynopsis_methodname_text($value, $tag);
return $this->format_varname_text($display_value, $tag);
}
public function format_classsynopsis_methodsynopsis_methodname_text($value, $tag) {
if ($this->cchunk["classsynopsis"]["classname"]) {
if (strpos($value, "::") === false && strpos($value, "->") === false) {
$value = $this->cchunk["classsynopsis"]["classname"] . "::" . $value;
}
}
$display_value = parent::format_classsynopsis_methodsynopsis_methodname_text($value, $tag);
return $this->format_function_text($value, $tag, $display_value);
}
public function format_function($open, $tag, $attrs, $props) {
if ($open) {
/* TODO Drop support when https://github.com/php/doc-en/pull/2864 has made its way to translations */
if (isset($attrs[Reader::XMLNS_PHD]["args"])) {
$this->cchunk["args"] = $attrs[Reader::XMLNS_PHD]["args"];
}
return '<span class="' . $tag . '">';
}
return "</span>";
}
public function format_function_text($value, $tag, $display_value = null) {
static $non_functions = array(
"echo" => true, "print" => true,
"include" => true, "include_once" => true,
"require" => true, "require_once" => true,
"return" => true,
);
if ($display_value === null) {
$display_value = $value;
if (!isset($non_functions[$value])) {
$args = $this->cchunk["args"];
$this->cchunk["args"] = $this->dchunk["args"];
$display_value .= "($args)";
}
}
if (isset($non_functions[$value])) {
$filename = "function." . str_replace("_", "-", $value);
} else {
$ref = strtolower(str_replace(array("_", "::", "->"), array("-", "-", "-"), $value));
$filename = $this->getRefnameLink($ref);
}
if ($filename !== null) {
if ($this->CURRENT_ID !== $filename) {
$rel = $desc = "";
if ($this->role == "seealso") {
$rel = ' rel="rdfs-seeAlso"';
$desc = " - " . Format::getLongDescription($filename);
}
if ($this->cchunk["refsynopsisdiv"] === "soft-deprecation-notice") {
$this->cchunk["alternatives"][] = $value;
}
$href = $this->chunked ? $filename.$this->ext : "#$filename";
return '<a href="'.$href. '" class="' . $tag . '"'.$rel.'>' .$display_value. '</a>'.$desc;
}
} elseif ($this->CURRENT_ID !== $filename) {
v("No link found for %s", $value, VERBOSE_BROKEN_LINKS);
}
return '<strong>' .$display_value. '</strong>';
}
public function format_grep_classname_text($value, $tag) {
$this->cchunk["class_name_ref"] = strtolower($value);
}
public function format_classsynopsis_ooclass_classname_text($value, $tag) {
$content = parent::format_classsynopsis_ooclass_classname_text($value, $tag);
/** Legacy behaviour for crappy markup */
if ($content === '') {
return '';
}
return $this->format_classname_text($content, $tag);
}
public function format_classsynopsis_oo_name_text($value, $tag) {
$content = parent::format_classsynopsis_oo_name_text($value, $tag);
return $this->format_classname_text($content, $tag);
}
public function format_classname_text($value, $tag) {
if (($filename = $this->getClassnameLink(strtolower($value))) !== null && $this->cchunk["class_name_ref"] !== strtolower($value)) {
$href = $this->chunked ? $filename.$this->ext : "#$filename";
return '<a href="'.$href. '" class="' .$tag. '">' .$value. '</a>';
}
return '<strong class="' .$tag. '">' .$value. '</strong>';
}
/*Chunk Functions*/
private function isChunkedByAttributes(array $attributes): bool {
/* Legacy way to mark chunks */
if (isset($attributes[Reader::XMLNS_PHD]['chunk'])) {
return $attributes[Reader::XMLNS_PHD]['chunk'] != 'false';
} elseif (isset($attributes[Reader::XMLNS_DOCBOOK]['annotations'])) {
/** Annotations attribute is a standard DocBook attribute and could be used for various things */
return !str_contains($attributes[Reader::XMLNS_DOCBOOK]['annotations'], 'chunk:false');
} else {
/* Chunked by default */
return true;
}
}
public function format_container_chunk($open, $name, $attrs, $props) {
$this->CURRENT_CHUNK = $this->CURRENT_ID = $id = $attrs[Reader::XMLNS_XML]["id"] ?? '';
if ($this->isChunkedByAttributes($attrs)) {
$this->cchunk = $this->dchunk;
}
if ($open) {
$this->notify(Render::CHUNK, Render::OPEN);
if ($name != "reference") {
$chunks = Format::getChildren($id);
if (!count($chunks)) {
return '<div id="'.$id.'" class="'.$name.'">';
}
$content = '<h2>'.$this->autogen("toc", $props["lang"]). '</h2><ul class="chunklist chunklist_'.$name.'">';
foreach($chunks as $chunkid) {
$href = $this->chunked ? $chunkid . $this->ext : "#$chunkid";
$content .= '<li><a href="'.$href. '">' .(Format::getShortDescription($chunkid)). '</a></li>';
}
$content .= "</ul>\n";
$this->cchunk["container_chunk"] = $content;
}
return '<div id="'.$id.'" class="'.$name.'">';
}
$this->notify(Render::CHUNK, Render::CLOSE);
$content = "";
if ($name == "reference") {
$chunks = Format::getChildren($id);
if (count($chunks)) {
$content = '<h2>'.$this->autogen("toc", $props["lang"]). '</h2><ul class="chunklist chunklist_reference">';
foreach($chunks as $chunkid) {
$href = $this->chunked ? $chunkid . $this->ext : "#$chunkid";
$content .= '<li><a href="'.$href. '">' .(Format::getShortDescription($chunkid)). '</a> — ' .(Format::getLongDescription($chunkid)). '</li>';
}
$content .= "</ul>\n";
}
}
$content .= "</div>\n";
return $content;
}
public function format_root_chunk($open, $name, $attrs) {
$this->CURRENT_CHUNK = $this->CURRENT_ID = $id = $attrs[Reader::XMLNS_XML]["id"] ?? '';
if ($open) {
$this->notify(Render::CHUNK, Render::OPEN);
return '<div id="'.$id.'" class="'.$name.'">';
}
$this->notify(Render::CHUNK, Render::CLOSE);
$chunks = Format::getChildren($id);
$content = '<ul class="chunklist chunklist_'.$name.'">';
foreach($chunks as $chunkid) {
$href = $this->chunked ? $chunkid . $this->ext : "#$chunkid";
$long = Format::getLongDescription($chunkid);
$short = Format::getShortDescription($chunkid);
if ($long && $short && $long != $short) {
$content .= '<li><a href="' .$href. '">' .$short. '</a> — ' .$long;
} else {
$content .= '<li><a href="' .$href. '">' .($long ? $long : $short). '</a>';
}
$children = Format::getChildren($chunkid);
if (count($children)) {
$content .= '<ul class="chunklist chunklist_'.$name.' chunklist_children">';
foreach(Format::getChildren($chunkid) as $childid) {
$href = $this->chunked ? $childid . $this->ext : "#$childid";
$long = Format::getLongDescription($childid);
$short = Format::getShortDescription($childid);
if ($long && $short && $long != $short) {
$content .= '<li><a href="' .$href. '">' .$short. '</a> — ' .$long. '</li>';
} else {
$content .= '<li><a href="' .$href. '">' .($long ? $long : $short). '</a></li>';
}
}
$content .="</ul>";
}
$content .= "</li>";
}
$content .= "</ul></div>";
return $content;
}
public function format_chunk($open, $name, $attrs, $props) {
if ($open) {
if (isset($attrs[Reader::XMLNS_XML]["id"])) {
$id = $attrs[Reader::XMLNS_XML]["id"];
}
else {
$id = uniqid();
v("Uhm. Can't find an ID for a chunk? - Generating a random one (%s)\n%s", $id, $this->getDebugTree($name, $props), E_USER_WARNING);
}
$this->CURRENT_CHUNK = $this->CURRENT_ID = $id;
if ($this->isChunkedByAttributes($attrs)) {
$this->cchunk = $this->dchunk;
$this->notify(Render::CHUNK, Render::OPEN);
}
if (isset($props["lang"])) {
$this->lang = $props["lang"];
}
if ($name == "refentry") {
$this->configureVerInfoAttribute($attrs);
}
if ($name == "legalnotice") {
return '<div id="legalnotice">';
}
return '<div id="'.$id.'" class="'.$name.'">';
}
if ($this->isChunkedByAttributes($attrs)) {
$this->notify(Render::CHUNK, Render::CLOSE);
}
return '</div>';
}
public function format_container_chunk_title($open, $name, $attrs, $props) {
if ($open) {
return $props["empty"] ? '' : '<h1>';
}
$ret = "";
if (isset($this->cchunk["container_chunk"]) && $this->cchunk["container_chunk"]) {
$ret = $this->cchunk["container_chunk"];
$this->cchunk["container_chunk"] = null;
}
return "</h1>\n" .$ret;
}
public function format_varentry_chunk($open, $name, $attrs, $props) {
return $this->format_chunk($open, "refentry", $attrs, $props);
}
public function format_exception_chunk($open, $name, $attrs, $props) {
return $this->format_container_chunk($open, "reference", $attrs, $props);
}
public function format_refentry($open, $name, $attrs, $props) {
$this->configureVerInfoAttribute($attrs);
/* We overwrite the tag name to continue working with the usual indexing */
if (isset($attrs[Reader::XMLNS_DOCBOOK]['role'])) {
return match ($attrs[Reader::XMLNS_DOCBOOK]['role']) {
'class', 'enum', 'exception' => $this->format_class_chunk($open, 'reference', $attrs, $props),
'variable' => $this->format_chunk($open, 'refentry', $attrs, $props),
default => $this->format_chunk($open, $name, $attrs, $props),
};
}
return $this->format_chunk($open, $name, $attrs, $props);
}
public function format_class_chunk($open, $name, $attrs, $props) {
if ($open) {
$retval = $this->format_container_chunk($open, "reference", $attrs, $props);
/* Classes must have version availability information */
$this->cchunk["verinfo"] = true;
return $retval;
}
return $this->format_container_chunk($open, "reference", $attrs, $props);
}
}