From a94ecb1009610a763dd74a7eebc4754b6643d832 Mon Sep 17 00:00:00 2001 From: Michael Wallner Date: Thu, 27 Jan 2022 16:01:02 +0100 Subject: [PATCH] move formatting from JS to PHP --- .github/workflows/publish.yml | 5 +- composer.json | 11 +- mdref/Action.php | 4 + mdref/File.php | 6 +- mdref/Formatter.php | 171 ++++++++++++++++++++++++-- mdref/Formatter/Discount.php | 32 ----- mdref/Formatter/League.php | 59 --------- mdref/Formatter/Wrapper.php | 224 ++++++++++++++++++++++++++++++++++ mdref/Generator/Cls.php | 10 +- mdref/Generator/Func.php | 21 ++++ mdref/Reference.php | 20 ++- public/index.css | 17 ++- public/index.js | 199 +----------------------------- views/index.phtml | 3 + views/mdref.phtml | 3 + 15 files changed, 472 insertions(+), 313 deletions(-) delete mode 100644 mdref/Formatter/Discount.php delete mode 100644 mdref/Formatter/League.php create mode 100644 mdref/Formatter/Wrapper.php diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 40591da..bb0413e 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -38,6 +38,9 @@ jobs: path: refs/raphf - name: Install dependencies run: | + v=8.0; for b in "" ize -config; do \ + sudo update-alternatives --set php$b /usr/bin/php$b$v; \ + done sudo apt-get update -y sudo apt-get install -y \ php-cli \ @@ -75,7 +78,7 @@ jobs: ../bin/ref2stub ../refs/$ext done - uses: crazy-max/ghaction-github-pages@v2 - if: success() + if: false env: GH_PAT: ${{ secrets.PUBLISH_SECRET }} with: diff --git a/composer.json b/composer.json index a66e582..e82c81f 100644 --- a/composer.json +++ b/composer.json @@ -20,15 +20,14 @@ } }, "require": { - "php": "^7.4 || ^8.0", + "php": "^8.0", "ext-ctype": "*", + "ext-dom": "*", + "ext-libxml": "*", "ext-filter": "*", "ext-pcre": "*", - "ext-http": "^3.2 || ^4.2", - "league/commonmark": "^2.0", + "ext-http": "^4.2", + "league/commonmark": "~2.1.0", "phpdocumentor/reflection-docblock": "^5.3" - }, - "suggests": { - "ext-discount": "A Markdown renderer is needed, this is the preferred one." } } diff --git a/mdref/Action.php b/mdref/Action.php index 3addfa0..0c48dd6 100644 --- a/mdref/Action.php +++ b/mdref/Action.php @@ -77,6 +77,10 @@ class Action { $pld->ref = $this->baseUrl->pathinfo( $this->baseUrl->mod($this->request->getRequestUrl())); + $pld->markup = function($page) use($pld) { + return $this->reference->getFormatter()->markup($page, $pld); + }; + $pld->refs = $this->reference; $pld->baseUrl = $this->baseUrl; diff --git a/mdref/File.php b/mdref/File.php index 3c1ca0a..0ca2bd8 100644 --- a/mdref/File.php +++ b/mdref/File.php @@ -50,7 +50,7 @@ class File { * @return string * @throws Exception */ - public function readDescription() : ?string { + public function readDescription() : string { if (!$this->rewind()) { throw Exception::fromLastError(); } @@ -58,7 +58,7 @@ class File { && (false !== fgets($this->fd))) { return fgets($this->fd); } - return null; + return ""; } /** @@ -67,7 +67,7 @@ class File { * @return string * @throws Exception */ - public function readFullDescription() : ?string { + public function readFullDescription() : string { $desc = $this->readDescription(); while (false !== ($line = fgets($this->fd))) { if ($line[0] === "#") { diff --git a/mdref/Formatter.php b/mdref/Formatter.php index ecde240..95a276f 100644 --- a/mdref/Formatter.php +++ b/mdref/Formatter.php @@ -2,19 +2,170 @@ namespace mdref; -use function class_exists; +use DOMDocument; +use DOMElement; +use DOMNode; +use League\CommonMark\GithubFlavoredMarkdownConverter; +use League\CommonMark\MarkdownConverter; +use League\CommonMark\Normalizer; +use League\CommonMark\Extension; +use mdref\Formatter\Wrapper; -abstract class Formatter { - abstract function formatString(string $string) : string; - abstract function formatFile(string $file) : string; +class Formatter { + public function __construct( + protected ?MarkdownConverter $md = null, + protected ?Wrapper $wrapper = null, + ) { + if (!$this->md) { + $this->md = new GithubFlavoredMarkdownConverter([ + "slug_normalizer" => [ + "instance" => new class($this) implements Normalizer\TextNormalizerInterface { + protected $formatter; + function __construct(Formatter $fmt) { + $this->formatter = $fmt; + } + function normalize(string $text, $context = null) : string { + return $this->formatter->formatSlug($text); + } + } + ], + ]); + $this->md->getEnvironment()->addExtension( + new Extension\DescriptionList\DescriptionListExtension + ); + $this->md->getEnvironment()->addExtension( + new Extension\Attributes\AttributesExtension + ); + } + if (!$this->wrapper) { + $this->wrapper = new Wrapper($this); + } + } + + public function formatString(string $string) : string { + return $this->md->convertToHtml($string); + } + + public function formatFile(string $file) : string { + $string = file_get_contents($file); + if ($string === false) { + throw Exception::fromLastError(); + } + return $this->md->convertToHtml($string); + } + + /** + * Format a simplified url slug + * @param string $string input text, like a heading + * @return string the simplified slug + */ + public function formatSlug(string $string) : string { + return preg_replace("/[^\$[:alnum:]:._-]+/", ".", $string); + } + + /** + * @param string $page HTML content + * @param object $pld Action payload + * @return string marked up HTML content + */ + public function markup(string $page, $pld) : string { + $dom = new DOMDocument("1.0", "utf-8"); + $dom->formatOutput = true; + $dom->loadHTML("\n \n" . $page, LIBXML_HTML_NOIMPLIED); + foreach ($dom->childNodes as $node) { + $this->walk($node, $pld); + } + $html = ""; + foreach ($dom->childNodes as $child) { + $html .= $dom->saveHTML($child); + } + return $html; + } + + public function createPermaLink(DOMElement $node, string $slug, $pld) { + if (strlen($slug)) { + $node->setAttribute("id", $slug); + } + $perm = $node->ownerDocument->createElement("a"); + $perm->setAttribute("class", "permalink"); + $perm->setAttribute("href", "$pld->ref#$slug"); + $perm->textContent = "#"; + return $perm; + } + + protected function walk(DOMNode $node, $pld) { + switch ($node->nodeType) { + case XML_ELEMENT_NODE: + $this->walkElement($node, $pld); + break; + case XML_TEXT_NODE: + $this->wrapper->wrap($node, $pld); + break; + default: + break; + } + } + + protected function highlightCode(DOMElement $node) { + foreach (["default", "comment", "html", "keyword", "string"] as $type) { + ini_set("highlight.$type", "inherit\" class=\"$type"); + } + $code = highlight_string($node->textContent, true); + $temp = new DOMDocument("1.0", "utf-8"); + $temp->loadHTML($code, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD); + return $node->ownerDocument->importNode($temp->firstChild, true); + } - static function factory() : Formatter { - if (class_exists("League\\CommonMark\\GithubFlavoredMarkdownConverter", true)) { - return new Formatter\League; + protected function walkElement(DOMElement $node, $pld) { + switch ($node->tagName) { + case "h1": + $perm = $this->createPermaLink($node, "", $pld); + $node->insertBefore($perm, $node->firstChild); + $pld->currentSection = null; + break; + case "h2": + $pld->currentSection = $this->formatSlug($node->textContent); + case "h3": + case "h4": + case "h5": + case "h6": + $slug = $this->formatSlug($node->textContent); + $perm = $this->createPermaLink($node, $slug, $pld); + $node->appendChild($perm); + break; + case "span": + if (!empty($pld->currentSection) && $node->hasAttribute("class")) { + switch ($pld->currentSection) { + case "Properties:": + case "Constants:": + switch ($node->getAttribute("class")) { + case "constant": + case "var": + $slug = $this->formatSlug($node->textContent); + $perm = $this->createPermaLink($node, $slug, $pld); + $node->insertBefore($perm); + break; + } + break; + } + } + case "a": + case "br": + case "hr": + case "em": + return; // ! + case "code": + if ($node->parentNode && $node->parentNode->nodeName === "pre") { + $code = $this->highlightCode($node); + $this->walk($code, $pld); + $node->parentNode->replaceChild($code, $node); + } + return; // ! } - if (extension_loaded("discount")) { - return new Formatter\Discount; + + // suck it out, because we're modifying the DOM + foreach (iterator_to_array($node->childNodes) as $child) { + $this->walk($child, $pld); } - throw new \Exception("No Markdown implementation found"); } } diff --git a/mdref/Formatter/Discount.php b/mdref/Formatter/Discount.php deleted file mode 100644 index c787c7a..0000000 --- a/mdref/Formatter/Discount.php +++ /dev/null @@ -1,32 +0,0 @@ -compile(\MarkdownDocument::AUTOLINK); - return $md->getHtml(); - } - - function formatFile(string $file) : string { - $fd = fopen($file, "r"); - if (!$fd) { - throw Exception::fromLastError(); - } - - $md = \MarkdownDocument::createFromStream($fd); - $md->compile(\MarkdownDocument::AUTOLINK | \MarkdownDocument::TOC); - $html = $md->getHtml(); - - fclose($fd); - - return $html; - } -} diff --git a/mdref/Formatter/League.php b/mdref/Formatter/League.php deleted file mode 100644 index 60ff7d4..0000000 --- a/mdref/Formatter/League.php +++ /dev/null @@ -1,59 +0,0 @@ -md = new GithubFlavoredMarkdownConverter([ - "slug_normalizer" => [ - "instance" => new class implements Normalizer\TextNormalizerInterface { - function normalize(string $text, $context = null) : string { - return preg_replace("/[^[:alnum:]:._-]/", ".", $text); - } - } - ], - "heading_permalink" => [ - "html_class" => "permalink", - "id_prefix" => "", - "fragment_prefix" => "", - "title" => "", - "symbol" => "#", - "insert" => "after", - "min_heading_level" => 2, - ] - ]); - $this->md->getEnvironment()->addExtension( - new Extension\DescriptionList\DescriptionListExtension - ); - $this->md->getEnvironment()->addExtension( - new Extension\HeadingPermalink\HeadingPermalinkExtension - ); - $this->md->getEnvironment()->addExtension( - new Extension\Attributes\AttributesExtension - ); - } - - function formatString(string $string) : string { - return $this->md->convertToHtml($string); - } - - function formatFile(string $file) : string { - $string = file_get_contents($file); - if ($string === false) { - throw Exception::fromLastError(); - } - return $this->md->convertToHtml($string); - } -} diff --git a/mdref/Formatter/Wrapper.php b/mdref/Formatter/Wrapper.php new file mode 100644 index 0000000..400de29 --- /dev/null +++ b/mdref/Formatter/Wrapper.php @@ -0,0 +1,224 @@ + ["void", "mixed"], + "language.types.%s" => ["null", "boolean", "integer", "float", "string", "resource", "array", "callable", "iterable"], + "language.types.null" => ["NULL"], + "language.types.boolean" => ["true", "TRUE", "false", "FALSE", "bool", "BOOL"], + "language.types.integer" => ["int", "long"], + "language.types.float" => ["double", "real"], + "language.types.object" => ["stdClass"], + "language.types.callable" => ["callback"], + "language.types.enumerations" => ["enum"], + "language.references" => ["reference"], + ]; + protected $exts = ["standard", "core", "spl", "json", "date"]; + + function __construct( + protected Formatter $fmt + ) {} + + public function wrap(DOMText $node, $pld) : void { + $nodes = []; + + $split = "[&?\(\)\|\"'\s\][\.,-]+"; + $items = preg_split("/($split)/", $node->textContent, 0, PREG_SPLIT_DELIM_CAPTURE); + foreach ($items as $item) { + if (preg_match("/^($split|[[:punct:]+])*$/", $item)) { + $nodes[] = $node->ownerDocument->createTextNode($item); + continue; + } + + $new = $this->wrapType($node, $item, $pld) + ?: $this->wrapKeyWord($node, $item, $pld) + ?: $this->wrapSpecial($node, $item, $pld); + if (is_array($new)) { + foreach ($new as $n) + $nodes[] = $n; + } elseif ($new) { + $nodes[] = $new; + } else { + $nodes[] = $node->ownerDocument->createTextNode($item); + } + } + if ($nodes) { + $parent = $node->parentNode; + $new_node = array_pop($nodes); + $parent->replaceChild($new_node, $node); + foreach ($nodes as $prev_node) { + $parent->insertBefore($prev_node, $new_node); + } + } + } + + protected function getType(string $item) : ?string { + static $types; + if (!$types) { + foreach ($this->types as $doc => $list) foreach ($list as $type) { + $types[$type] = sprintf($this->docref, sprintf($doc, $type)); + } + foreach ($this->exts as $ext) foreach ((new ReflectionExtension($ext))->getClassNames() as $class) { + $types[$class] = sprintf($this->docref, "class." . strtolower($class)); + } + } + + $item = trim($item, "\\"); + if (!isset($types[$item])) { + return null; + } + return $types[$item]; + } + protected function wrapType(DOMText $node, string $item, $pld) : ?DOMNode { + if (!($type = $this->getType($item))) { + return null; + } + $a = $node->ownerDocument->createElement("a"); + $a->setAttribute("href", $type); + $a->textContent = $item; + $code = $node->ownerDocument->createElement("code"); + $code->insertBefore($a); + return $code; + } + + protected function wrapKeyword(DOMText $node, string $item, $pld) : DomNode|array|null { + switch ($item) { + case "is": + if ($node->parentNode->nodeName !== "h1") { + break; + } + case "extends": + case "implements": + if ($node->parentNode->nodeName === "h1") { + $nodes = [ + $node->ownerDocument->createElement("br"), + $node->ownerDocument->createEntityReference("nbsp"), + $new = $node->ownerDocument->createElement("em") + ]; + $new->textContent = $item; + return $nodes; + } + case "class": + case "enum": + case "interface": + case "namespace": + case "public": + case "protected": + case "private": + case "static": + case "final": + case "abstract": + case "self": + case "parent": + $new = $node->ownerDocument->createElement("em"); + $new->textContent = $item; + return $new; + } + return null; + } + + protected function isFirstDeclaration(DOMNode $node, string $item, bool $is_slug = false) : bool { + return $node->parentNode->nodeName === "li" + && !$node->ownerDocument->getElementById($is_slug ? $item : $this->fmt->formatSlug($item)); + } + + protected function isVar(string $item) : bool { + return str_starts_with($item, "\$"); + } + + protected function wrapVar(DOMNode $node, string $item, $pld) : DOMNode { + $ele = $node->ownerDocument->createElement("span"); + $ele->setAttribute("class", "var"); + $ele->textContent = $item; + + if (!empty($pld->currentSection)) { + $slug = $this->fmt->formatSlug($item); + if ($this->isFirstDeclaration($node, $slug, true)) { + $perm = $this->fmt->createPermaLink($ele, $slug, $pld); + $ele->insertBefore($perm); + } + } + return $ele; + } + + protected function isNamespaced(DOMNode $node, string $item, $pld) : bool { + return str_contains($item, "\\") || str_contains($item, "::"); + } + + protected function wrapNamespaced(DOMNode $node, string $item, $pld) : ?DOMNode { + $href = preg_replace("/\\\\|::/", "/", trim($item, "\\:")); + $canonical = null; + $repo = $pld->refs->getRepoForEntry($href, $canonical); + + if ($repo) { + if (!empty($canonical)) { + $href = $canonical; + } + $link = $node->ownerDocument->createElement("a"); + $link->setAttribute("href", $href); + $link->textContent = $item; + return $link; + } + + $hash = basename($href); + $href = dirname($href); + $repo = $pld->refs->getRepoForEntry($href, $canonical); + if ($repo) { + if (!empty($canonical)) { + $href = $canonical; + } + $link = $node->ownerDocument->createElement("a"); + $link->setAttribute("href", "$href#$hash"); + $link->textContent = $item; + return $link; + } + + return null; + } + + protected function wrapConstant(DOMNode $node, string $item, $pld) : ?DOMNode { + $strict = "_"; + if (!empty($pld->currentSection)) { + switch ($pld->currentSection) { + case "Properties:": + case "Constants:": + $strict = ""; + break; + } + } + if (preg_match("/^[A-Z]({$strict}[A-Z0-9_v])+\$/", $item)) { + // assume some constant + $span = $node->ownerDocument->createElement("span"); + $span->setAttribute("class", "constant"); + $span->textContent = $item; + if (!$strict && $pld->currentSection === "Constants:" && $node->parentNode->nodeName === "li" && $node->parentNode->firstChild === $node) { + $perm = $this->createPermaLink($span, $this->formatSlug($item), $pld); + $span->insertBefore($perm); + } + return $span; + } + + return null; + } + + protected function wrapSpecial(DOMNode $node, string $item, $pld) : ?DOMNode { + if ($this->isVar($item)) { + if (($ele = $this->wrapVar($node, $item, $pld))) { + return $ele; + } + } + if ($this->isNamespaced($node, $item, $pld)) { + if (($ele = $this->wrapNamespaced($node, $item, $pld))) { + return $ele; + } + } + return $this->wrapConstant($node, $item, $pld); + } +} diff --git a/mdref/Generator/Cls.php b/mdref/Generator/Cls.php index 5292c6d..8c463e2 100644 --- a/mdref/Generator/Cls.php +++ b/mdref/Generator/Cls.php @@ -31,7 +31,15 @@ endif; if (($parent = $ref->getParentClass())) : ?> extends getName() ?>getInterfaceNames())) : sort($implements); +if (($implements = $ref->getInterfaceNames())) : + foreach ($implements as $index => $iface) : + foreach ($implements as $implemented) : + if ($iface !== $implemented && is_subclass_of($implemented, $iface)) : + unset($implements[$index]); + endif; + endforeach; + endforeach; + sort($implements); ?> implements diff --git a/mdref/Generator/Func.php b/mdref/Generator/Func.php index f31941a..dfee0e7 100644 --- a/mdref/Generator/Func.php +++ b/mdref/Generator/Func.php @@ -91,4 +91,25 @@ endif; ?> +getTagsWithTypeByName("throws"))) : +?> + +## Throws: + +* getType() + ?>getDescription()?->getBodyTemplate()) : + ?>, getDescription() + ?> + + repos[$repo->getName()] = $repo; } - $this->fmt = $fmt ?: Formatter::factory(); + $this->fmt = $fmt ?: new Formatter; + } + + /** + * Get the formatter. + * @return Formatter + */ + public function getFormatter() : Formatter { + return $this->fmt; } /** @@ -62,7 +70,7 @@ class Reference implements IteratorAggregate { * @param string $anchor * @return string */ - public function formatAnchor(string $anchor) : string { + public function formatAnchor(string $anchor, string $location = null) : string { if (is_numeric($anchor)) { return "L$anchor"; } @@ -74,8 +82,8 @@ class Reference implements IteratorAggregate { * @return string * @throws \Exception, Exception */ - public function formatString(string $string) : string { - return $this->fmt->formatString($string); + public function formatString(string $string, string $location = null) : string { + return $this->fmt->formatString($string, $location); } /** @@ -83,7 +91,7 @@ class Reference implements IteratorAggregate { * @return string * @throws \Exception, Exception */ - public function formatFile(string $file) : string { - return $this->fmt->formatFile($file); + public function formatFile(string $file, string $location = null) : string { + return $this->fmt->formatFile($file, $location); } } diff --git a/public/index.css b/public/index.css index c0204cd..063b6a1 100644 --- a/public/index.css +++ b/public/index.css @@ -96,7 +96,16 @@ pre>code { pre>code, pre>code code { background: #333; - color: #eee; + color: ghostwhite; +} +pre>code .comment { + color: darkorange !important; +} +pre>code .string { + color: darkseagreen !important; +} +pre>code .keyword { + color: darkgray !important; } p, pre, table, dl { @@ -152,6 +161,12 @@ a:hover { a[href^="http:"]:after, a[href^="https:"]:after { content: " ⬈"; } +code>a { + text-decoration: none; +} +code a[href^="http:"]:after, code a[href^="https:"]:after { + content: ""; +} a.permalink { position: relative; diff --git a/public/index.js b/public/index.js index 5124ffe..5c4d8f1 100644 --- a/public/index.js +++ b/public/index.js @@ -5,190 +5,6 @@ $(function() { log: function log() { console.log.apply(console, arguments); }, - is_constant: function is_constant(s) { - s = s.replace(/v\d+(_\d+)?$/, ""); - if (s.length < 2) { - return false; - } - return s.toUpperCase(s) === s; - }, - is_variable: function is_variable(s) { - return s.substring(0,1) === "$"; - }, - type: function type(s, nn) { - var i, j, t; - // mdref.log("type", s); - // nothing - if (!s.match(/[a-zA-Z]/)) { - return; - } - - switch (s) { - // types - case "void": - case "bool": - case "int": - case "float": - case "string": - case "resource": - case "array": - case "object": - case "callable": - case "mixed": - // Zend/SPL - case "stdClass": - case "Exception": - case "ErrorException": - case "RuntimeException": - case "UnexpectedValueException": - case "DomainException": - case "InvalidArgumentException": - case "BadMethodCallException": - case "Closure": - case "Generator": - case "Countable": - case "Serializable": - case "Traversable": - case "Iterator": - case "IteratorAggregate": - case "RecursiveIterator": - case "ArrayAccess": - case "ArrayObject": - case "ArrayIterator": - case "RecursiveArrayIterator": - case "SeekableIterator": - case "SplObserver": - case "SplSubject": - case "SplObjectStorage": - case "JsonSerializable": - return ""; - - // keywords - case "is": - if (nn !== "H1") { - return; - } - case "extends": - case "implements": - if (nn === "H1") { - return "
 "; - } - case "class": - case "enum": - case "interface": - case "namespace": - case "public": - case "protected": - case "private": - case "static": - case "final": - case "abstract": - case "self": - case "parent": - // phrases - case "Optional": - case "optional": - return ""; - } - - // class members - if (-1 !== (i = s.indexOf("::"))) { - t = s.substring(i+2); - if (!mdref.is_constant(t) && !mdref.is_variable(t)) { - // methods - return ""; - } - } - if (-1 !== (j = s.lastIndexOf("\\")) && s.substr(j+1,1) !== "n") { - t = s.substring(j+1); - if (!mdref.is_constant(t) || s.match(/\\/g).length <= 1) { - return ""; - } - return ""; - } - - switch (s.toLowerCase()) { - // variables - default: - if (!mdref.is_variable(s)) { - break; - } - // special constants - case "null": - case "true": - case "false": - return ""; - } - - // constants - if (mdref.is_constant(s)) { - return ""; - } - }, - wrap: function wrap(n, nn) { - var $n = $(n) - var a = []; - - $n.text().split(/([^a-zA-Z0-9_\\\$:]+)/).forEach(function(v) { - var t; - - if ((t = mdref.type(v.replace(/:$/, ""), nn))) { - a.push($(t).text(v)); - } else if (a.length && a[a.length-1].nodeName === "#text") { - /* if we already have a text node and the next is also gonna be a text - * node, then join them, becuase chrome v30+ or something eats whitespace - * for breakfast, lunch and dinner! - */ - a[a.length-1].textContent += v; - } else { - a.push(document.createTextNode(v)); - } - }); - $n.replaceWith(a); - }, - walk: function walk(i, e) { - // mdref.log("walk", i, e); - - switch (e.nodeName) { - case "H1": - case "H2": - case "H3": - case "H4": - case "H5": - case "H6": - if (e.id.length) { - var href = document.location.pathname; - var perm = $("#"); - if (e.nodeName === "H1") { - perm.prependTo(e); - } else { - perm.attr("href", function(i, href) { - return href + e.id; - }); - perm.appendTo(e); - } - } - break; - } - - $.each($.makeArray(e.childNodes), function(i, n) { - switch (n.nodeName) { - case "A": - case "BR": - case "HR": - case "EM": - case "CODE": - case "SPAN": - break; - case "#text": - mdref.wrap(n, e.nodeName); - break; - default: - mdref.walk(-1, n); - break; - } - }); - }, blink: function blink(c) { var $c = $(c); @@ -202,15 +18,17 @@ $(function() { }, hashchange: function hashchange() { if (location.hash.length > 1) { + var hash = decodeURIComponent(location.hash.substring(1)); var e; if ((e = document.getElementById(location.hash.substring(1)))) { mdref.blink(e); } else { - var hash = location.hash.substring(1); - var name = mdref.is_variable(hash) ? ".var" : ".constant"; var scrolled = false; - $(name).each(hash.substring(hash.length-1) === "_" ? function(i, c) { + if (hash.substring(hash.length-1) === "*") { + hash = hash.substring(0, hash.length-1); + } + $((hash.substring(0,1) === "$") ? ".var" : ".constant").each(function(i, c) { if (c.textContent.substring(0, hash.length) === hash) { if (!scrolled) { $(window).scrollTop($(c).offset().top - 100); @@ -218,19 +36,12 @@ $(function() { } mdref.blink(c); } - } : function(i, c) { - if (c.textContent === hash) { - $(window).scrollTop($(c).offset().top - 100); - mdref.blink(c); - return false; - } }); } } } }; - $("h1,h2,h3,h4,h5,h6,p,li,code,td").each(mdref.walk); $(window).on("hashchange", mdref.hashchange); mdref.hashchange(); diff --git a/views/index.phtml b/views/index.phtml index db2accd..d2bd1fe 100644 --- a/views/index.phtml +++ b/views/index.phtml @@ -1,3 +1,4 @@ +

mdref

@@ -20,3 +21,5 @@ + + diff --git a/views/mdref.phtml b/views/mdref.phtml index c05ad78..2739f91 100644 --- a/views/mdref.phtml +++ b/views/mdref.phtml @@ -1,3 +1,4 @@ + getPath()) ?> @@ -40,3 +41,5 @@ + + -- 2.30.2