From ba46a6cdffd56d99c191b8fa9a510cf7c6af45bd Mon Sep 17 00:00:00 2001 From: Michael Wallner Date: Wed, 15 Jun 2016 13:00:11 +0200 Subject: [PATCH] permalinks --- mdref/Action.php | 23 ++++++++------- mdref/Entry.php | 70 ++++++++++++++++++++++----------------------- mdref/File.php | 10 +++---- mdref/Reference.php | 15 +++++++--- public/index.css | 10 ++++++- public/index.js | 63 ++++++++++++++++++++++++++++------------ views/index.phtml | 4 +-- views/mdref.phtml | 4 +-- 8 files changed, 121 insertions(+), 78 deletions(-) diff --git a/mdref/Action.php b/mdref/Action.php index 19cf910..df974b9 100644 --- a/mdref/Action.php +++ b/mdref/Action.php @@ -29,7 +29,7 @@ class Action { * @var \http\Url */ private $baseUrl; - + /** * Initialize the reference */ @@ -44,7 +44,7 @@ class Action { function esc($txt) { return htmlspecialchars($txt); } - + /** * Create the view payload * @param \http\Controller $ctl @@ -52,8 +52,9 @@ class Action { */ private function createPayload() { $pld = new \stdClass; - + $pld->esc = "htmlspecialchars"; + $pld->anchor = [$this->reference, "formatAnchor"]; $pld->quick = [$this->reference, "formatString"]; $pld->file = [$this->reference, "formatFile"]; @@ -62,10 +63,10 @@ class Action { $pld->refs = $this->reference; $pld->baseUrl = $this->baseUrl; - + return $pld; } - + /** * Redirect to canononical url * @param string $cnn @@ -75,7 +76,7 @@ class Action { $this->response->setResponseCode(301); $this->response->send(); } - + /** * Serve index.css */ @@ -84,7 +85,7 @@ class Action { $this->response->setBody(new \http\Message\Body(fopen(ROOT."/public/index.css", "r"))); $this->response->send(); } - + /** * Serve index.js */ @@ -93,7 +94,7 @@ class Action { $this->response->setBody(new \http\Message\Body(fopen(ROOT."/public/index.js", "r"))); $this->response->send(); } - + /** * Serve a preset * @param \stdClass $pld @@ -124,7 +125,7 @@ class Action { include ROOT."/views/layout.phtml"; $this->response->send(); } - + public function handle() { try { @@ -144,11 +145,11 @@ class Action { return; } } - + } catch (\Exception $e) { $pld->exception = $e; } $this->serve($pld); } -} \ No newline at end of file +} diff --git a/mdref/Entry.php b/mdref/Entry.php index db858a9..4febd76 100644 --- a/mdref/Entry.php +++ b/mdref/Entry.php @@ -11,31 +11,31 @@ class Entry implements \IteratorAggregate { * @var string */ private $name; - + /** * Split name * @var array */ private $list; - + /** * The containing repository * @var \mdref\Repo */ private $repo; - + /** * The file path, if the refentry exists - * @var type + * @var type */ private $path; - + /** * The file instance of this entry * @var \mdref\File */ private $file; - + /** * @param string $name the compound name of the ref entry, e.g. "pq/Connection/exec" * @param \mdref\Repo $repo the containing repository @@ -46,7 +46,7 @@ class Entry implements \IteratorAggregate { $this->list = explode("/", $name); $this->path = $repo->hasEntry($name); } - + /** * Get the compound name, e.g. "pq/Connection/exec" * @return string @@ -54,7 +54,7 @@ class Entry implements \IteratorAggregate { public function getName() { return $this->name; } - + /** * Get the containing repository * @return \mdref\Repo @@ -62,7 +62,7 @@ class Entry implements \IteratorAggregate { public function getRepo() { return $this->repo; } - + /** * Get the file path, if any * @return string @@ -70,7 +70,7 @@ class Entry implements \IteratorAggregate { public function getPath() { return $this->path; } - + /** * Get the file instance of this entry * @return \mdref\File @@ -81,57 +81,57 @@ class Entry implements \IteratorAggregate { } return $this->file; } - + /** - * Get edit URL + * Get edit URL * @return string */ public function getEditUrl() { return $this->repo->getEditUrl($this->name); } - + /** * Read the title of the ref entry file * @return string */ public function getTitle() { if ($this->isFile()) { - return $this->getFile()->readTitle(); + return trim($this->getFile()->readTitle()); } if ($this->isRoot()) { - return $this->repo->getRootEntry()->getTitle(); + return trim($this->repo->getRootEntry()->getTitle()); } return $this->name; } - + /** * Read the description of the ref entry file * @return string */ public function getDescription() { if ($this->isFile()) { - return $this->getFile()->readDescription(); + return trim($this->getFile()->readDescription()); } if ($this->isRoot()) { - return $this->repo->getRootEntry()->getDescription(); + return trim($this->repo->getRootEntry()->getDescription()); } return $this; } - + /** * Read the intriductory section of the refentry file * @return string */ public function getIntro() { if ($this->isFile()) { - return $this->getFile()->readIntro(); + return trim($this->getFile()->readIntro()); } if ($this->isRoot()) { - return $this->repo->getRootEntry()->getIntro(); + return trim($this->repo->getRootEntry()->getIntro()); } return ""; } - + /** * Check if the refentry exists * @return bool @@ -139,7 +139,7 @@ class Entry implements \IteratorAggregate { public function isFile() { return strlen($this->path) > 0; } - + /** * Check if this is the first entry of the reference tree * @return bool @@ -147,7 +147,7 @@ class Entry implements \IteratorAggregate { public function isRoot() { return count($this->list) === 1; } - + /** * Get the parent ref entry * @return \mdref\Entry @@ -161,7 +161,7 @@ class Entry implements \IteratorAggregate { return $this->repo->getEntry($dirn); } } - + /** * Get the list of parents up-down * @return array @@ -173,7 +173,7 @@ class Entry implements \IteratorAggregate { } return $parents; } - + /** * Guess whether this ref entry is about a function or method * @return bool @@ -182,7 +182,7 @@ class Entry implements \IteratorAggregate { $base = end($this->list); return $base{0} === "_" || ctype_lower($base{0}); } - + /** * Guess whether this ref entry is about a namespace, interface or class * @return bool @@ -191,7 +191,7 @@ class Entry implements \IteratorAggregate { $base = end($this->list); return ctype_upper($base{0}); } - + /** * Display name * @return string @@ -203,11 +203,11 @@ class Entry implements \IteratorAggregate { return $myself; } $parent = end($parts); - + switch ($myself{0}) { case ":": return "★" . substr($myself, 1); - + default: if (!ctype_lower($myself{0}) || ctype_lower($parent{0})) { return $myself; @@ -216,7 +216,7 @@ class Entry implements \IteratorAggregate { return $parent . "::" . $myself; } } - + /** * Get the base name of this ref entry * @return string @@ -224,7 +224,7 @@ class Entry implements \IteratorAggregate { public function getBasename() { return dirname($this->path) . "/" . basename($this->path, ".md"); } - + /** * Guess whether there are any child nodes * @param string $glob @@ -240,7 +240,7 @@ class Entry implements \IteratorAggregate { return is_dir($this->getBasename()); } } - + /** * Guess whether there are namespace/interface/class child nodes * @return bool @@ -248,7 +248,7 @@ class Entry implements \IteratorAggregate { function hasNsClasses() { return $this->hasIterator("/[A-Z]*.md", true); } - + /** * Guess whether there are function/method child nodes * @return bool @@ -256,7 +256,7 @@ class Entry implements \IteratorAggregate { function hasFunctions() { return $this->hasIterator("/[a-z_]*.md"); } - + /** * Implements \IteratorAggregate * @return \mdref\Tree child nodes diff --git a/mdref/File.php b/mdref/File.php index 0ac3da2..4afd3b4 100644 --- a/mdref/File.php +++ b/mdref/File.php @@ -10,7 +10,7 @@ class File { * @var resource */ private $fd; - + /** * Open the file * @param string $path @@ -18,7 +18,7 @@ class File { public function __construct($path) { $this->fd = fopen($path, "rb"); } - + /** * Read the title of the refentry * @return string @@ -28,7 +28,7 @@ class File { return fgets($this->fd); } } - + /** * Read the description of the refentry * @return string @@ -40,7 +40,7 @@ class File { return fgets($this->fd); } } - + /** * Read the first subsection of a global refentry * @return string @@ -49,7 +49,7 @@ class File { $intro = ""; if (0 === fseek($this->fd, 0, SEEK_SET)) { $header = false; - + while (!feof($this->fd)) { if (false === ($line = fgets($this->fd))) { break; diff --git a/mdref/Reference.php b/mdref/Reference.php index 7c22dba..892be7e 100644 --- a/mdref/Reference.php +++ b/mdref/Reference.php @@ -11,7 +11,7 @@ class Reference implements \IteratorAggregate { * @var array */ private $repos = array(); - + /** * @param array $refs list of mdref repository paths */ @@ -21,7 +21,7 @@ class Reference implements \IteratorAggregate { $this->repos[$repo->getName()] = $repo; } } - + /** * Lookup the repo containing a ref entry * @param string $entry requested reference entry, e.g. "pq/Connection/exec" @@ -35,7 +35,7 @@ class Reference implements \IteratorAggregate { } } } - + /** * Implements \IteratorAggregate * @return \ArrayIterator repository list @@ -44,12 +44,19 @@ class Reference implements \IteratorAggregate { return new \ArrayIterator($this->repos); } + public function formatAnchor($anchor) { + if (is_numeric($anchor)) { + return "L$anchor"; + } + return preg_replace("/[^[:alnum:]\.:_]/", ".", $anchor); + } + public function formatString($string) { $md = \MarkdownDocument::createFromString($string); $md->compile(\MarkdownDocument::AUTOLINK); return $md->getHtml(); } - + public function formatFile($file) { $fd = fopen($file, "r"); $md = \MarkdownDocument::createFromStream($fd); diff --git a/public/index.css b/public/index.css index 22417db..4fd8949 100644 --- a/public/index.css +++ b/public/index.css @@ -7,7 +7,7 @@ html, body{ min-height: 100%; } body, code { - font-family: Inconsolata, Monospace, 'Courier New', Courier, monospace; + font-family: Inconsolata, 'Courier New', Courier, monospace; } body { line-height: 1.5; @@ -131,6 +131,14 @@ a[href^="http:"]:after, a[href^="https:"]:after { content: " ⬈"; } +a.permalink { + position: relative; + top: 0; + right: 0; + color: #999999; + opacity: 0.25; +} + .var { color: #800000; } diff --git a/public/index.js b/public/index.js index 4878936..8d6c506 100644 --- a/public/index.js +++ b/public/index.js @@ -129,7 +129,7 @@ $(function() { $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") { @@ -147,6 +147,28 @@ $(function() { 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": @@ -178,29 +200,34 @@ $(function() { }, hashchange: function hashchange() { if (location.hash.length > 1) { - var hash = location.hash.substring(1); - var name = mdref.is_variable(hash) ? ".var" : ".constant"; - var scrolled = false; + 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 (c.textContent.substring(0, hash.length) === hash) { - if (!scrolled) { + $(name).each(hash.substring(hash.length-1) === "_" ? function(i, c) { + if (c.textContent.substring(0, hash.length) === hash) { + if (!scrolled) { + $(window).scrollTop($(c).offset().top - 100); + scrolled = true; + } + mdref.blink(c); + } + } : function(i, c) { + if (c.textContent === hash) { $(window).scrollTop($(c).offset().top - 100); - scrolled = true; + mdref.blink(c); + return false; } - 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 acab9e2..0baafb8 100644 --- a/views/index.phtml +++ b/views/index.phtml @@ -7,10 +7,10 @@ -

+

getTitle()) ?>

getIntro()) ?>
- \ No newline at end of file + diff --git a/views/mdref.phtml b/views/mdref.phtml index a9e34ef..370d8d8 100644 --- a/views/mdref.phtml +++ b/views/mdref.phtml @@ -1,7 +1,7 @@ getPath()) ?> hasFunctions()) : ?> -

Functions:

+

Functions: