diff --git a/phpdotnet/phd/Package/Generic/XHTML.php b/phpdotnet/phd/Package/Generic/XHTML.php index 7e3b1fcf..e3035c15 100644 --- a/phpdotnet/phd/Package/Generic/XHTML.php +++ b/phpdotnet/phd/Package/Generic/XHTML.php @@ -63,15 +63,6 @@ abstract class Package_Generic_XHTML extends Format_Abstract_XHTML { 'caution' => 'format_admonition', 'citation' => 'format_citation', 'citerefentry' => 'span', - 'classname' => array( - /* DEFAULT */ 'span', - 'ooclass' => array( - /* DEFAULT */ 'strong', - 'classsynopsisinfo' => 'format_classsynopsisinfo_ooclass_classname', - ), - ), - 'classsynopsis' => 'format_classsynopsis', - 'classsynopsisinfo' => 'format_classsynopsisinfo', 'code' => 'code', 'collab' => 'span', 'collabname' => 'span', @@ -157,22 +148,45 @@ abstract class Package_Generic_XHTML extends Format_Abstract_XHTML { 'note' => 'format_note', 'orgname' => 'span', 'othercredit' => 'format_div', + /** Class Synopsis related tags */ + 'classsynopsis' => 'format_classsynopsis', + 'classsynopsisinfo' => 'format_classsynopsisinfo', 'ooclass' => array( /* DEFAULT */ 'span', - 'classsynopsis' => 'format_div', + 'classsynopsis' => 'format_classsynopsis_generic_oo_tag', ), + 'ooexception' => [ + /* DEFAULT */ 'span', + 'classsynopsis' => 'format_classsynopsis_generic_oo_tag', + ], 'oointerface' => array( /* DEFAULT */ 'span', - 'classsynopsisinfo' => 'format_classsynopsisinfo_oointerface', + 'classsynopsis' => 'format_classsynopsis_generic_oo_tag', + 'classsynopsisinfo' => 'format_classsynopsisinfo_oointerface', ), + 'classname' => [ + /* DEFAULT */ 'span', + 'ooclass' => [ + /* DEFAULT */ 'span', + 'classsynopsis' => 'format_classsynopsis_ooclass_classname', + 'classsynopsisinfo' => 'format_classsynopsisinfo_ooclass_classname', + ], + ], + 'exceptionname' => [ + /* DEFAULT */ 'span', + 'ooexception' => [ + /* DEFAULT */ 'span', + 'classsynopsis' => 'format_classsynopsis_ooclass_classname', + ], + ], 'interfacename' => array( /* DEFAULT */ 'span', 'oointerface' => array( /* DEFAULT */ 'span', + 'classsynopsis' => 'format_classsynopsis_oointerface_interfacename', 'classsynopsisinfo' => 'format_classsynopsisinfo_oointerface_interfacename', ), ), - 'exceptionname' => 'span', 'option' => 'format_option', 'orderedlist' => 'format_orderedlist', 'para' => array( @@ -379,13 +393,29 @@ abstract class Package_Generic_XHTML extends Format_Abstract_XHTML { /* DEFAULT */ false, 'fieldsynopsis' => 'format_fieldsynopsis_modifier_text', ), - 'classname' => array( - /* DEFAULT */ false, - 'ooclass' => array( + /** Those are used to retrieve the class/interface name to be able to remove it from method names */ + 'classname' => [ + /* DEFAULT */ false, + 'ooclass' => [ /* DEFAULT */ false, + /** This is also used by the legacy display to not display the class name at all */ 'classsynopsis' => 'format_classsynopsis_ooclass_classname_text', - ), - ), + ] + ], + 'exceptionname' => [ + /* DEFAULT */ false, + 'ooexception' => [ + /* DEFAULT */ false, + 'classsynopsis' => 'format_classsynopsis_oo_name_text', + ] + ], + 'interfacename' => [ + /* DEFAULT */ false, + 'oointerface' => [ + /* DEFAULT */ false, + 'classsynopsis' => 'format_classsynopsis_oo_name_text', + ] + ], 'methodname' => array( /* DEFAULT */ false, 'constructorsynopsis' => array( @@ -422,11 +452,14 @@ abstract class Package_Generic_XHTML extends Format_Abstract_XHTML { protected $cchunk = array(); /* Default Chunk variables */ private $dchunk = array( - "classsynopsis" => array( - "close" => false, - "classname" => false, - "interface" => false, // bool: true when in interface - ), + "classsynopsis" => [ + "close" => false, + "classname" => false, + "interface" => false, // bool: true when in interface + "ooclass" => false, + "oointerface" => false, + "legacy" => true, // legacy rendering + ], "classsynopsisinfo" => array( "implements" => false, "ooclass" => false, @@ -896,6 +929,7 @@ public function format_refsect($open, $name, $attrs) { return "\n"; } + /** Legacy rendering functions for class synopsis tags that wraps the definition in a class synopsis info tag */ public function format_classsynopsisinfo_oointerface($open, $name, $attrs) { if ($open) { if ($this->cchunk["classsynopsisinfo"]["ooclass"] === false) { @@ -971,29 +1005,150 @@ public function format_classsynopsisinfo($open, $name, $attrs) if (isset($attrs[Reader::XMLNS_DOCBOOK]["role"]) && $attrs[Reader::XMLNS_DOCBOOK]["role"] == "comment") { return ' */'; } + + assert($this->cchunk["classsynopsis"]["legacy"] === true); $this->cchunk["classsynopsis"]["close"] = true; return ' {'; } - public function format_classsynopsis($open, $name, $attrs) { + /** This method is common between both legacy and new rendering for setting up the classname in the current chunk */ + public function format_classsynopsis_ooclass_classname_text($value, $tag) { + /** If this is not defined this is the first ooclass/oointerface/ooexception and thus needs to + * set the class name to be able to remove it from the methods + */ + if (!$this->cchunk["classsynopsis"]["classname"]) { + $this->cchunk["classsynopsis"]["classname"] = $value; + } + // Do not render outside ooclass class name in legacy rendering. + if ($this->cchunk["classsynopsis"]["legacy"]) { + return ''; + } + return $this->TEXT($value); + } + + /** Class synopsis rendering for new/better markup */ + public function format_classsynopsis_oo_name_text($value, $tag) { + /** If this is not defined this is the first ooclass/oointerface/ooexception and thus needs to + * set the class name to be able to remove it from the methods + */ + if (!$this->cchunk["classsynopsis"]["classname"]) { + $this->cchunk["classsynopsis"]["classname"] = $value; + } + return $this->TEXT($value); + } + + public function format_classsynopsis_oointerface_interfacename($open, $name, $attrs, $props) + { + if ($this->cchunk["classsynopsis"]["legacy"] === true) { + return $this->transformFromMap($open, 'strong', $name, $attrs, $props); + } + if ($open) { - // Think this just needs to be set on open and it will persist - // Will remove comment after review - if ( - isset($attrs[Reader::XMLNS_DOCBOOK]["class"]) && - $attrs[Reader::XMLNS_DOCBOOK]["class"] == "interface" - ) { - $this->cchunk["classsynopsis"]["interface"] = true; + /* If there has been a class prior this means that we are the first implementing interface + * thus mark the oointerface as already been rendered as the primary tag */ + if ($this->cchunk["classsynopsis"]["ooclass"] === true) { + $this->cchunk["classsynopsis"]["oointerface"] = true; } + /** Actual interface name in bold */ + if ($this->cchunk["classsynopsis"]["oointerface"] === false) { - return '
'; + return 'interface ' . $this->transformFromMap($open, 'strong', $name, $attrs, $props); + } + /* Whitespace for next word */ + return ' '; + } + /** Actual interface name in bold */ + if ($this->cchunk["classsynopsis"]["oointerface"] === false) { + $this->cchunk["classsynopsis"]["oointerface"] = true; + return ''; } + /** We don't wrap extended interface in a tag */ + if ($this->cchunk["classsynopsis"]['nb_list'] > 1) { + return ','; + } + return ''; + } + + public function format_classsynopsis_ooclass_classname($open, $name, $attrs, $props) + { + if ($this->cchunk["classsynopsis"]["legacy"] === true) { + return $this->transformFromMap($open, 'strong', $name, $attrs, $props); + } + + if ($open) { + /** Actual class name in bold */ + if ($this->cchunk["classsynopsis"]["ooclass"] === false) { + /** We force the name: parameter to 'classname' to not break CSS expectations for exceptionanme tags */ + return 'class ' . $this->transformFromMap($open, 'strong', 'classname', $attrs, $props); + } + /* Whitespace for next word */ + return ' '; + } + /** Actual class name in bold */ + if ($this->cchunk["classsynopsis"]["ooclass"] === false) { + $this->cchunk["classsynopsis"]["ooclass"] = true; + return ''; + } + /** We don't wrap extended class in a tag */ + return ''; + } + + public function format_classsynopsis_generic_oo_tag($open, $name, $attrs, $props) + { + if ($this->cchunk["classsynopsis"]["legacy"] === true) { + return $this->transformFromMap($open, 'span', $name, $attrs, $props); + } + + /* Close list of classes + interfaces by "opening" class def with { */ + if (!$open) { + if (--$this->cchunk["classsynopsis"]['nb_list'] === 0) { + return ' {
'; + } + } + return ''; + } + + public function format_classsynopsis($open, $name, $attrs, $props) { + $this->cchunk["classsynopsis"] = $this->dchunk["classsynopsis"]; + + /** Legacy presentation does not use the class attribute */ + $this->cchunk["classsynopsis"]['legacy'] = !isset($attrs[Reader::XMLNS_DOCBOOK]["class"]); + + if ($this->cchunk["classsynopsis"]['legacy']) { + if ($open) { + // Think this just needs to be set on open and it will persist + // Will remove comment after review + if ( + isset($attrs[Reader::XMLNS_DOCBOOK]["class"]) && + $attrs[Reader::XMLNS_DOCBOOK]["class"] == "interface" + ) { + $this->cchunk["classsynopsis"]["interface"] = true; + } + + return '
'; + } - if ($this->cchunk["classsynopsis"]["close"] === true) { - $this->cchunk["classsynopsis"]["close"] = false; + /* Just always force the ending } to close the class as an opening { should always be present + if ($this->cchunk["classsynopsis"]["close"] === true) { + $this->cchunk["classsynopsis"]["close"] = false; + return "}
"; + } + return ""; + */ return "}"; } - return ""; + + /* New rendering for more sensible markup: + * We open a fake classsynopsisinfo div to not break the CSS expectations */ + if ($open) { + $occurrences = substr_count($props['innerXml'], '') + + substr_count($props['innerXml'], '') + + substr_count($props['innerXml'], ''); + $this->cchunk["classsynopsis"]['nb_list'] = $occurrences; + return '
'; + } else { + return '}
'; + } } public function format_classsynopsis_methodsynopsis_methodname_text($value, $tag) { @@ -1018,10 +1173,6 @@ public function format_classsynopsis_methodsynopsis_methodname_text($value, $tag return $method; } - public function format_classsynopsis_ooclass_classname_text($value, $tag) { - $this->cchunk["classsynopsis"]["classname"] = $value; - return $this->TEXT($value); - } public function format_fieldsynopsis($open, $name, $attrs) { $this->cchunk["fieldsynopsis"] = $this->dchunk["fieldsynopsis"]; diff --git a/phpdotnet/phd/Package/PHP/XHTML.php b/phpdotnet/phd/Package/PHP/XHTML.php index fdd2dee7..a1b42d33 100644 --- a/phpdotnet/phd/Package/PHP/XHTML.php +++ b/phpdotnet/phd/Package/PHP/XHTML.php @@ -7,13 +7,6 @@ abstract class Package_PHP_XHTML extends Package_Generic_XHTML { 'appendix' => 'format_container_chunk', 'article' => 'format_container_chunk', 'book' => 'format_root_chunk', - 'classname' => array( - /* DEFAULT */ 'span', - 'ooclass' => array( - /* DEFAULT */ 'format_suppressed_tags', - 'classsynopsisinfo' => 'format_classsynopsisinfo_ooclass_classname', - ), - ), 'chapter' => 'format_container_chunk', 'colophon' => 'format_chunk', 'function' => 'format_function', @@ -90,15 +83,29 @@ abstract class Package_PHP_XHTML extends Package_Generic_XHTML { private $mytextmap = array( 'acronym' => 'format_acronym_text', 'function' => 'format_function_text', - 'interfacename' => 'format_classname_text', - 'exceptionname' => 'format_classname_text', - 'classname' => array( - /* DEFAULT */ 'format_classname_text', - 'ooclass' => array( - /* DEFAULT */ 'format_classname_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( @@ -708,8 +715,17 @@ public function format_grep_classname_text($value, $tag) { } public function format_classsynopsis_ooclass_classname_text($value, $tag) { - /* intentionally not return the value, it will be printed out by "soon" */ - parent::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) { diff --git a/phpdotnet/phd/Render.php b/phpdotnet/phd/Render.php index 4117b4f4..a588dc99 100644 --- a/phpdotnet/phd/Render.php +++ b/phpdotnet/phd/Render.php @@ -72,8 +72,12 @@ public function execute(Reader $r) { /* {{{ */ $innerXml = ""; if ( - ($open && $r->name === "type") || - ($open && in_array($r->name, ["methodsynopsis", "constructorsynopsis", "destructorsynopsis"], true)) + $open && + ( + $r->name === "type" || + $r->name === "classsynopsis" || + in_array($r->name, ["methodsynopsis", "constructorsynopsis", "destructorsynopsis"], true) + ) ) { $innerXml = $r->readInnerXml(); } @@ -113,7 +117,7 @@ public function execute(Reader $r) { /* {{{ */ continue; } - if (strncmp($tag ?? '', "format_", 7) !== 0) { + if (/* !($tag instanceof \Closure) && */ !str_starts_with($tag ?? '', "format_")) { $data = $format->transformFromMap($open, $tag, $name, $attrs, $props); } else { $data = $format->{$tag}($open, $name, $attrs, $props);