diff --git a/phpdotnet/phd/Package/PHP/Factory.php b/phpdotnet/phd/Package/PHP/Factory.php index 57e968f6..27dec178 100644 --- a/phpdotnet/phd/Package/PHP/Factory.php +++ b/phpdotnet/phd/Package/PHP/Factory.php @@ -3,6 +3,7 @@ class Package_PHP_Factory extends Format_Factory { private $formats = array( + 'searchable' => 'Package_PHP_SearchableXHTML', 'xhtml' => 'Package_PHP_ChunkedXHTML', 'bigxhtml' => 'Package_PHP_BigXHTML', 'php' => 'Package_PHP_Web', diff --git a/phpdotnet/phd/Package/PHP/SearchableXHTML.php b/phpdotnet/phd/Package/PHP/SearchableXHTML.php new file mode 100644 index 00000000..28fa5a3b --- /dev/null +++ b/phpdotnet/phd/Package/PHP/SearchableXHTML.php @@ -0,0 +1,352 @@ +registerFormatName("PHP-Searchable-XHTML"); + } + + + protected function writeJsonIndex() + { + parent::writeJsonIndex(); + + $entries = $this->processCombinedJsonIndex(); + file_put_contents( + $this->getOutputDir() . "search-combined.json", + json_encode($entries) + ); + $entries = 'var localSearchIndexes = '. json_encode($entries) .';'; + file_put_contents( + $this->getOutputDir() . "search-combined.js", + $entries + ); + $this->outputHandler->v("Combined Index written", VERBOSE_FORMAT_RENDERING); + } + + private function processCombinedJsonIndex(): array + { + $entries = []; + foreach ($this->indexes as $index) { + if (!$index["chunk"]) { + continue; + } + + if ($index["sdesc"] === "" && $index["ldesc"] !== "") { + $index["sdesc"] = $index["ldesc"]; + $bookOrSet = $this->findParentBookOrSet($index['parent_id']); + if ($bookOrSet) { + $index["ldesc"] = Format::getLongDescription( + $bookOrSet['docbook_id'] + ); + } + } + + $nameParts = explode('::', $index['sdesc']); + $methodName = array_pop($nameParts); + + $type = 'General'; + switch ($index['element']) { + case "phpdoc:varentry": + $type = "Variable"; + break; + + case "refentry": + $type = "Function"; + break; + + case "phpdoc:exceptionref": + $type = "Exception"; + break; + + case "phpdoc:classref": + $type = "Class"; + break; + + case "set": + case "book": + case "reference": + $type = "Extension"; + break; + } + + $entries[] = [ + 'id' => $index['filename'], + 'name' => $index['sdesc'], + 'description' => html_entity_decode($index['ldesc']), + 'tag' => $index['element'], + 'type' => $type, + 'methodName' => $methodName, + ]; + } + return $entries; + } + + /** + * Finds the closest parent book or set in the index hierarchy. + */ + private function findParentBookOrSet(string $id): ?array + { + // array_key_exists() to guard against undefined array keys, either for + // root elements (no parent) or in case the index structure is broken. + while (array_key_exists($id, $this->indexes)) { + $parent = $this->indexes[$id]; + $element = $parent['element']; + + if ($element === 'book' || $element === 'set') { + return $parent; + } + + $id = $parent['parent_id']; + } + + return null; + } + + public function header($id) + { + // https://feathericons.com search + $searchIcon = << + SVG; + + $searchNav = << + + + + HTML; + + $title = Format::getLongDescription($id); + static $cssLinks = null; + if ($cssLinks === null) { + $cssLinks = $this->createCSSLinks(); + } + $header = <<
+ + + + + $title +{$cssLinks} + + +HEADER; + $nextLink = $prevLink = $upLink = ''; + if ($prevId = Format::getPrevious($id)) { + $prev = array( + "href" => $this->getFilename($prevId) . $this->getExt(), + "desc" => $this->getShortDescription($prevId), + ); + $prevLink = "
  • « {$prev["desc"]}
  • "; + } + if ($nextId = Format::getNext($id)) { + $next = array( + "href" => $this->getFilename($nextId) . $this->getExt(), + "desc" => $this->getShortDescription($nextId), + ); + $nextLink = "
  • {$next["desc"]} »
  • "; + } + if ($parentId = Format::getParent($id)) { + $up = array( + "href" => $this->getFilename($parentId) . $this->getExt(), + "desc" => $this->getShortDescription($parentId), + ); + if ($up['href'] != 'index.html') { + $upLink = "
  • {$up["desc"]}
  • "; + } + } + + $nav = <<