From eab2dc741781a876a307490d70a7952f9315da0c Mon Sep 17 00:00:00 2001 From: Michael Wallner Date: Fri, 13 Dec 2013 14:24:31 +0100 Subject: [PATCH] refactoaaar --- mdref/Action.php | 54 +++--- mdref/Finder.php | 29 +++- mdref/Path.php | 43 ++++- mdref/RefEntry.php | 35 ++-- mdref/RefListing.php | 50 +----- nbproject/project.xml | 3 + public/index.css | 13 ++ public/index.js | 372 +++++++++++++++++++++--------------------- views/edit.phtml | 3 + views/footer.phtml | 6 + views/index.phtml | 18 ++ views/layout.phtml | 55 +------ views/mdref.phtml | 14 ++ views/sidebar.phtml | 24 +++ 14 files changed, 393 insertions(+), 326 deletions(-) create mode 100644 views/edit.phtml create mode 100644 views/footer.phtml create mode 100644 views/index.phtml create mode 100644 views/mdref.phtml create mode 100644 views/sidebar.phtml diff --git a/mdref/Action.php b/mdref/Action.php index 223e532..511e3a6 100644 --- a/mdref/Action.php +++ b/mdref/Action.php @@ -6,35 +6,43 @@ use http\Controller\Observer; class Action extends Observer { + private function serveReference(\http\Controller $ctl) { + $payload = $ctl->getPayload(); + $finder = new Finder($this->baseUrl, REFS); + $path = $finder->find(new \http\Url($ctl->getRequest()->getRequestUrl())); + $payload->listing = new RefListing($path, + $finder->glob($path, "/[_a-zA-Z]*.md")); + $payload->title = $payload->listing->getSelf()->formatLink(); + $payload->refs = $finder; + if ($path->isFile()) { + $payload->html = new Markdown($path); + $payload->sublisting = new RefListing($path, + $finder->glob($path, "/[_a-z]*.md")); + return true; + } + } + + private function serveInternal(\http\Controller $ctl) { + $payload = $ctl->getPayload(); + $finder = new Finder($this->baseUrl, ROOT); + $url = new \http\Url($ctl->getRequest()->getRequestUrl()); + $path = $finder->find($url, ""); + if ($path->isFile("")) { + $payload->html = $path->toHtml(); + } else if (strcmp($url, $this->baseUrl)) { + throw new \http\Controller\Exception(404, "Could not find '$path'"); + } + } + function update(\SplSubject $ctl) { /* @var \http\Controller $ctl */ try { - $payload = $ctl->getPayload(); - $request = $ctl->getRequest(); - - $finder = new Finder($this->baseUrl, REFS); - $url = new \http\Url($request->getRequestUrl()); - if (!$path = $finder->find($url)) { - $path = new Path; - } - - $payload->baseUrl = $this->baseUrl; - $payload->requestUrl = $url; - - $payload->listing = new RefListing($path, - $finder->glob($path, "/[_a-zA-Z]*.md")); + $ctl->getPayload()->baseUrl = $this->baseUrl; - if ($path->isFile()) { - $payload->markdown = new Markdown($path); - $payload->sublisting = new RefListing($path, - $finder->glob($path, "/[_a-z]*.md")); - } else if ($path($url)->isFile("")) { - $payload->markdown = $path->toHtml(); - } else if (strcmp($url, $this->baseUrl)) { - throw new \http\Controller\Exception(404, "Could not find '$url'"); + if (!$this->serveReference($ctl)) { + $this->serveInternal($ctl); } } catch (\Exception $e) { - $payload->baseUrl = $this->baseUrl; $ctl->getPayload()->exception = $e; } } diff --git a/mdref/Finder.php b/mdref/Finder.php index 9d1c64c..cf04fbf 100644 --- a/mdref/Finder.php +++ b/mdref/Finder.php @@ -2,6 +2,14 @@ namespace mdref; +/** + * Find markdown reference files in several REFPATH paths. + * + * The base URL is used to extract the relative identifier out of the request + * url in Finder::find(). + * + * Use the created Path of Finder::find() for Finder::glob() to find subrefs. + */ class Finder { /** @@ -29,21 +37,34 @@ class Finder } /** + * Find a markdown reference file in one REFPATH. If nothing could be found + * an empty Path will be returned. + * * @param \http\Url $requestUrl * @return Path */ - function find(\http\Url $requestUrl) { - $file = implode(DIRECTORY_SEPARATOR, - $this->baseUrl->params($requestUrl)); + function find(\http\Url $requestUrl, $ext = ".md") { + $file = implode(DIRECTORY_SEPARATOR, $this->baseUrl->params($requestUrl)); foreach ($this->refs as $base) { $path = new Path($base, $file); - if ($path->isFile()) { + if ($path->isFile($ext)) { return $path; } } + + return new Path; } + /** + * Glob either in a Path's base dir, or, if the path does not have a base + * dir set, in each REFPATH paths. + * + * @param \mdref\Path $path + * @param string $pattern glob pattern + * @param int $flags glob flags + * @return array glob result + */ function glob(Path $path, $pattern, $flags = GLOB_BRACE) { if (strlen($path->getBaseDir())) { return glob($path->getFullPath($pattern), $flags); diff --git a/mdref/Path.php b/mdref/Path.php index b9212d2..efa208a 100644 --- a/mdref/Path.php +++ b/mdref/Path.php @@ -2,6 +2,9 @@ namespace mdref; +/** + * A path made out of a base dir and an thereof relative path name. + */ class Path { /** @@ -16,33 +19,65 @@ class Path */ protected $baseDir = ""; + /** + * @param string $baseDir + * @param string $path + */ function __construct($baseDir = "", $path = "") { $this->baseDir = $baseDir; $this->path = $path; } + /** + * Create a copy of this path with a different path name + * + * @param string $path + * @return \mdref\Path + */ function __invoke($path) { $that = clone $this; $that->path = $path; return $that; } + /** + * Retrurns the full path as string + * @return string + */ function __toString() { return $this->getFullPath(); } + /** + * The base directory + * @return string + */ function getBaseDir() { return $this->baseDir; } + /** + * The path name relative to the base dir + * @return string + */ function getPathName() { return $this->path; } + /** + * The full path + * @param string $ext extension + * @return string + */ function getFullPath($ext = "") { return $this->baseDir . DIRECTORY_SEPARATOR . $this->path . $ext; } + /** + * Retrieve a another subpath within the base dir + * @param type $path + * @return string + */ function getSubPath($path) { return trim(substr($path, strlen($this->baseDir)), DIRECTORY_SEPARATOR); } @@ -52,10 +87,14 @@ class Path } function toHtml() { + $head = sprintf("

%s

\n", htmlspecialchars(basename($this->getPathName()))); if ($this->isFile()) { - return htmlspecialchars(file_get_contents($this->getFullPath())); + $html = htmlspecialchars(file_get_contents($this->getFullPath())); } elseif ($this->isFile("")) { - return htmlspecialchars(file_get_contents($this->getFullPath(""))); + $html = htmlspecialchars(file_get_contents($this->getFullPath(""))); + } else { + throw new \http\Controller\Exception(404, "Not Found: {$this->getPathName()}"); } + return $head . "
" . $html ."
"; } } \ No newline at end of file diff --git a/mdref/RefEntry.php b/mdref/RefEntry.php index f88b43f..32ef3ce 100644 --- a/mdref/RefEntry.php +++ b/mdref/RefEntry.php @@ -21,7 +21,7 @@ class RefEntry function __construct(Path $path, $entry = null) { $this->path = $path; - $this->entry = $entry ?: $path->getPathName(); + $this->entry = trim($entry ?: $path->getPathName(), DIRECTORY_SEPARATOR); } function __destruct() { @@ -32,12 +32,9 @@ class RefEntry function formatUrl() { return htmlspecialchars($this->entry); - return implode("/", explode(DIRECTORY_SEPARATOR, trim(substr( - $this->entry, strlen($this->path->getBaseDir())), - DIRECTORY_SEPARATOR))); } - protected function joinLink(array $parts) { + private function joinLink(array $parts) { $link = ""; $upper = ctype_upper($parts[0][0]);; for ($i = 0; $i < count($parts); ++$i) { @@ -59,19 +56,25 @@ class RefEntry function formatLink($basename = false) { $link = ""; - if (strlen($entry = trim($this->entry, DIRECTORY_SEPARATOR))) { - $parts = explode(DIRECTORY_SEPARATOR, $entry); + if (strlen($this->entry)) { + $parts = explode(DIRECTORY_SEPARATOR, $this->entry); $link = $basename ? end($parts) : $this->joinLink($parts); } return htmlspecialchars($link); } - protected function openFile() { + function getPath() { + $path = $this->path; + $file = $path($this->entry); + return $file; + } + + private function openFile() { if (!is_resource($this->file)) { - $path = $this->path; - $file = $path($this->entry); + $file = $this->getPath(); + if (!$file->isFile()) { - throw new \Exception("Not a file: '$this->entry'"); + throw new \Exception("Not a file: '{$this->entry}'"); } if (!$this->file = fopen($file->getFullPath(".md"), "r")) { throw new \Exception("Could not open {$this->entry}"); @@ -92,4 +95,14 @@ class RefEntry fgets($this->file); return htmlspecialchars(fgets($this->file)); } + + function formatEditUrl() { + $path = $this->path; + $base = current(explode(DIRECTORY_SEPARATOR, $path->getPathName())); + $file = $path($base); + if ($file->isFile(".mdref")) { + return sprintf(file_get_contents($file->getFullPath(".mdref")), + $this->entry); + } + } } \ No newline at end of file diff --git a/mdref/RefListing.php b/mdref/RefListing.php index d718090..fd86b94 100644 --- a/mdref/RefListing.php +++ b/mdref/RefListing.php @@ -16,6 +16,7 @@ class RefListing implements \Countable, \Iterator /** * @param \mdref\Path $path + * @param array $files */ function __construct(Path $path, array $files) { $this->path = $path; @@ -24,28 +25,6 @@ class RefListing implements \Countable, \Iterator }, $files); } - /** - * Copy constructor - * @param mixed $filter callable array filter or fnmatch pattern - * @return \mdref\RefListing - */ - function __invoke($filter) { - die(__METHOD__); - $that = clone $this; - $that->entries = array_filter($that->entries, is_callable($filter) - ? $filter - : function($fn) use ($filter) { - return fnmatch($filter, $fn); - } - ); - return $that; - } - - function __toString() { - return __METHOD__; - return $this->format(substr($this->path, strlen($this->path->getBaseDir()))); - } - function count() { return count($this->entries); } @@ -83,29 +62,4 @@ class RefListing implements \Countable, \Iterator function getSelf() { return new RefEntry($this->path); } - - function format($entry) { - return __METHOD__; - $ns = ""; - if (strlen($entry = trim($entry, DIRECTORY_SEPARATOR))) { - $upper = ctype_upper($entry[0]); - $parts = explode(DIRECTORY_SEPARATOR, $entry); - - for ($i = 0; $i < count($parts); ++$i) { - if (!strlen($parts[$i]) || $parts[$i] === ".") { - continue; - } - if (strlen($ns)) { - if ($upper && !ctype_upper($parts[$i][0])) { - $ns .= "::"; - } else { - $ns .= "\\"; - } - } - $ns .= $parts[$i]; - $upper = ctype_upper($parts[$i][0]); - } - } - return $ns; - } -} \ No newline at end of file +} diff --git a/nbproject/project.xml b/nbproject/project.xml index 5dec217..3f5c5eb 100644 --- a/nbproject/project.xml +++ b/nbproject/project.xml @@ -5,5 +5,8 @@ mdref-autocracy.git + + mdref + diff --git a/public/index.css b/public/index.css index 754f96c..a4493e9 100644 --- a/public/index.css +++ b/public/index.css @@ -26,6 +26,7 @@ body>ul { border-bottom-left-radius: 10px; padding: 0; width: auto; + min-width: 200px; padding-right: 1em; } .sidebar>ul { @@ -37,6 +38,18 @@ body>ul { list-style-type: none; } +.sidebar .edit { + display: block; + position: absolute; + top: 2em; + right: 0.5em; + transform: rotate(45deg); + text-decoration: none; + color: white; + font-weight: bold; + text-shadow: 0 0 5px red; +} + code { display: inline-block; border-radius: 2px; diff --git a/public/index.js b/public/index.js index e0f3ccf..35587b7 100644 --- a/public/index.js +++ b/public/index.js @@ -1,200 +1,194 @@ -function log() { - // console.log.apply(console, arguments); -} +"use strict"; -function is_constant(s) { - s = s.replace(/v\d+(_\d+)?$/, ""); - if (s.length < 2) { - return false; - } - return s.toUpperCase(s) === s; -} - -function is_variable(s) { - return s.substring(0,1) === "$"; -} +$(function() { + var mdref = { + 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; + } -var is_in_string = false; + 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 "ArrayAccess": + case "ArrayObject": + case "ArrayIterator": + case "RecursiveArrayIterator": + case "SplObserver": + case "SplSubject": + case "SplObjectStorage": + return ""; -function type(s, nn) { - var i, j, t; - //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 "ArrayAccess": - case "ArrayObject": - case "ArrayIterator": - case "RecursiveArrayIterator": - case "SplObserver": - case "SplSubject": - case "SplObjectStorage": - return ""; - - // keywords - case "is": - if (nn !== "H1") { - return; - } - case "extends": - case "implements": - if (nn === "H1") { - return "
 "; - } - case "class": - 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 (!is_constant(t) && !is_variable(t)) { - // methods - return ""; - } - } - if (-1 !== (j = s.indexOf("\\")) && s.substr(j+1,1) !== "n") { - return ""; - } - - switch (s.toLowerCase()) { - // variables - default: - if (!is_variable(s)) { - break; - } - // special constants - case "null": - case "true": - case "false": - return ""; - } - - // constants - if (is_constant(s)) { - return ""; - } -} + // keywords + case "is": + if (nn !== "H1") { + return; + } + case "extends": + case "implements": + if (nn === "H1") { + return "
 "; + } + case "class": + 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 ""; + } -function node(s, nn) { - //log("node", s); - - var t; - - if ((t = type(s, nn))) { - return $(t).text(s); - } - return document.createTextNode(s); -} -function wrap(n, nn) { - var $n = $(n) - var a = []; + // 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.indexOf("\\")) && s.substr(j+1,1) !== "n") { + return ""; + } - $n.text().split(/([^a-zA-Z0-9_\\\$:]+)/).forEach(function(v) { - a.push(node(v, nn)); - }); - $n.replaceWith(a); -} -function walk(i, e) { - log("walk", i, e); + switch (s.toLowerCase()) { + // variables + default: + if (!mdref.is_variable(s)) { + break; + } + // special constants + case "null": + case "true": + case "false": + return ""; + } - $.each($.makeArray(e.childNodes), function(i, n) { - switch (n.nodeName) { - case "A": - case "BR": - case "HR": - break; - case "#text": - wrap(n, e.nodeName); - break; - default: - walk(-1, n); - break; - } - }); -} + // constants + if (mdref.is_constant(s)) { + return ""; + } + }, + node: function node(s, nn) { + // mdref.log("node", s); + var t; + if ((t = mdref.type(s, nn))) { + return $(t).text(s); + } + return document.createTextNode(s); + }, + wrap: function wrap(n, nn) { + var $n = $(n) + var a = []; -function blink(c) { - var $c = $(c); - - $c.fadeOut("fast").queue(function(next) { - this.style.color = "red"; - next(); - }).fadeIn("fast").fadeOut("slow").queue(function(next) { - this.style.color = ""; - next(); - }).fadeIn("slow"); -} + $n.text().split(/([^a-zA-Z0-9_\\\$:]+)/).forEach(function(v) { + a.push(mdref.node(v, nn)); + }); + $n.replaceWith(a); + }, + walk: function walk(i, e) { + // mdref.log("walk", i, e); -function hashchange() { - if (location.hash.length > 1) { - var hash = location.hash.substring(1); - var name = 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) { - $(window).scrollTop($(c).offset().top - 100); - scrolled = true; + $.each($.makeArray(e.childNodes), function(i, n) { + switch (n.nodeName) { + case "A": + case "BR": + case "HR": + break; + case "#text": + mdref.wrap(n, e.nodeName); + break; + default: + mdref.walk(-1, n); + break; } - blink(c); - } - } : function(i, c) { - if (c.textContent === hash) { - $(window).scrollTop($(c).offset().top - 100); - blink(c); - return false; - } - }); - } -} + }); + }, + blink: function blink(c) { + var $c = $(c); -$(function() { - $("h1,h2,h3,h4,h5,h6,p,li,code").each(walk); - $(window).on("hashchange", hashchange); - hashchange(); + $c.fadeOut("fast").queue(function(next) { + this.style.color = "red"; + next(); + }).fadeIn("fast").fadeOut("slow").queue(function(next) { + this.style.color = ""; + next(); + }).fadeIn("slow"); + }, + 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; + + $(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; + } + blink(c); + } + } : function(i, c) { + if (c.textContent === hash) { + $(window).scrollTop($(c).offset().top - 100); + blink(c); + return false; + } + }); + } + } + }; + + $("h1,h2,h3,h4,h5,h6,p,li,code").each(mdref.walk); + $(window).on("hashchange", mdref.hashchange); + mdref.hashchange(); }); diff --git a/views/edit.phtml b/views/edit.phtml new file mode 100644 index 0000000..aabbb02 --- /dev/null +++ b/views/edit.phtml @@ -0,0 +1,3 @@ +getSelf()) && ($url = $entry->formatEditUrl())) : ?> + Edit Page + diff --git a/views/footer.phtml b/views/footer.phtml new file mode 100644 index 0000000..12ef7fb --- /dev/null +++ b/views/footer.phtml @@ -0,0 +1,6 @@ + diff --git a/views/index.phtml b/views/index.phtml new file mode 100644 index 0000000..676fe10 --- /dev/null +++ b/views/index.phtml @@ -0,0 +1,18 @@ +

mdref

+ + + + + +

Available References

+ +

formatLink()?>

+
    + find($baseUrl->mod($entry->formatUrl())), $refs->glob($path, "/*.md")) as $entry) : ?> +
  • formatLink()?>
    + readDescription()?>
  • + +
+ + + diff --git a/views/layout.phtml b/views/layout.phtml index 994f7f4..43463ca 100644 --- a/views/layout.phtml +++ b/views/layout.phtml @@ -3,7 +3,7 @@ - <?php if (isset($title)) : ?> + <?php if ($title) : ?> <?= $title ?> - mdref <?php else: ?> mdref @@ -14,61 +14,18 @@ <script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script> </head> <body> - <?php if (isset($listing)) : ?> - <div class="sidebar"> - <ul> - <li>↰ <a href="">Home</a></li> - <?php if (($entry = $listing->getParent())) : ?> - <li>↑ <a href="<?=$entry->formatUrl()?>"><?=$entry->formatLink()?></a></li> - <?php endif; ?> - <?php if (($entry = $listing->getSelf()) && ($link = $entry->formatLink())) : ?> - <ul><li>↻ <?= $link ?> - <?php endif; ?> - <?php if (count($listing)) : ?> - <ul> - <?php foreach ($listing as $entry) : ?> - <li>↳ <a href="<?=$entry->formatUrl()?>"><?=$entry->formatLink()?></a></li> - <?php endforeach; ?> - </ul> - <?php endif; ?> - <?php if (strlen($listing)) : ?> - </li></ul> - <?php endif; ?> - </ul> - </div> - <?php endif; ?> + <?php include __DIR__."/sidebar.phtml" ?> - <?php if (isset($markdown)) : ?> - <?= $markdown ?> - <?php if (isset($sublisting) && count($sublisting)) : ?> - <h2>Functions:</h2> - <ul> - <?php foreach($sublisting as $entry) : ?> - <li> - <h3><a href="<?=$entry->formatUrl()?>"><?=$entry->formatLink(true)?></a></h3> - <p><?=$entry->readDescription()?></p> - <p><?=$entry->readTitle()?></p> - </li> - <?php endforeach; ?> - </ul> - <?php endif; ?> + <?php if (isset($html)) : ?> + <?php include __DIR__."/mdref.phtml" ?> <?php else: ?> - <h1>mdref-v<?php readfile("../VERSION"); ?></h1> - <?php if (isset($exception)) : ?> - <?=\mdref\ExceptionHandler::html($exception, ["h2"], ["p"], ["pre", "style='overflow-x:scroll'"]); ?> - <?php else : ?> - <pre><?= htmlspecialchars(file_get_contents("../LICENSE")); ?></pre> - <?php endif; ?> + <?php include __DIR__."/index.phtml" ?> <?php endif; ?> <div id="disqus_thread"></div> <footer> - <ul> - <li><a href="https://github.com/m6w6/mdref">mdref-v<?php readfile("../VERSION") ?></a></li> - <li><a href="LICENSE">© <?= implode("-", array_unique([2013, idate("Y")])) ?> - All rights reserved.</a></li> - </ul> + <?php include __DIR__."/footer.phtml" ?> </footer> <script src="index.js"></script> </body> diff --git a/views/mdref.phtml b/views/mdref.phtml new file mode 100644 index 0000000..5cec21d --- /dev/null +++ b/views/mdref.phtml @@ -0,0 +1,14 @@ +<?= $html ?> + +<?php if (isset($sublisting) && count($sublisting)) : ?> + <h2>Functions:</h2> + <ul> + <?php foreach($sublisting as $entry) : ?> + <li> + <h3><a href="<?=$entry->formatUrl()?>"><?=$entry->formatLink(true)?></a></h3> + <p><?=$entry->readDescription()?></p> + <p><?=$entry->readTitle()?></p> + </li> + <?php endforeach; ?> + </ul> +<?php endif; ?> diff --git a/views/sidebar.phtml b/views/sidebar.phtml new file mode 100644 index 0000000..f6dccb4 --- /dev/null +++ b/views/sidebar.phtml @@ -0,0 +1,24 @@ +<?php if (isset($listing)) : ?> +<div class="sidebar"> + <?php include __DIR__."/edit.phtml" ?> + <ul> + <li>↰ <a href="">Home</a></li> + <?php if (($entry = $listing->getParent())) : ?> + <li>↑ <a href="<?=$entry->formatUrl()?>"><?=$entry->formatLink()?></a></li> + <?php endif; ?> + <?php if (($entry = $listing->getSelf()) && ($link = $entry->formatLink())) : ?> + <ul><li>↻ <?= $link ?> + <?php endif; ?> + <?php if (count($listing)) : ?> + <ul> + <?php foreach ($listing as $entry) : ?> + <li>↳ <a href="<?=$entry->formatUrl()?>"><?=$entry->formatLink()?></a></li> + <?php endforeach; ?> + </ul> + <?php endif; ?> + <?php if (isset($link) && strlen($link)) : ?> + </li></ul> + <?php endif; ?> + </ul> +</div> +<?php endif; ?> -- 2.30.2