Merge remote-tracking branch 'refs/remotes/origin/master'
authorMichael Wallner <mike@php.net>
Tue, 17 Dec 2013 10:50:53 +0000 (11:50 +0100)
committerMichael Wallner <mike@php.net>
Tue, 17 Dec 2013 10:50:53 +0000 (11:50 +0100)
24 files changed:
.gitignore
.htaccess [deleted file]
composer.json [new file with mode: 0644]
composer.lock [new file with mode: 0644]
index.css [deleted file]
index.js [deleted file]
index.php [deleted file]
mdref/Action.php [new file with mode: 0644]
mdref/ExceptionHandler.php [new file with mode: 0644]
mdref/Finder.php [new file with mode: 0644]
mdref/Markdown.php [new file with mode: 0644]
mdref/Path.php [new file with mode: 0644]
mdref/RefEntry.php [new file with mode: 0644]
mdref/RefListing.php [new file with mode: 0644]
public/.htaccess [new file with mode: 0644]
public/index.css [new file with mode: 0644]
public/index.js [new file with mode: 0644]
public/index.php [new file with mode: 0644]
views/edit.phtml [new file with mode: 0644]
views/footer.phtml [new file with mode: 0644]
views/index.phtml [new file with mode: 0644]
views/layout.phtml [new file with mode: 0644]
views/mdref.phtml [new file with mode: 0644]
views/sidebar.phtml [new file with mode: 0644]

index 1d3e81325d0ad1fcb47f9e1995c6648c7d0e4414..40b7eda78c8e121dc3a93eb1a2ec7e0f99f2f12c 100644 (file)
@@ -1 +1 @@
-geany_run_script.sh
+/nbproject/
diff --git a/.htaccess b/.htaccess
deleted file mode 100644 (file)
index df161a8..0000000
--- a/.htaccess
+++ /dev/null
@@ -1,2 +0,0 @@
-RewriteEngine On
-RewriteRule ^ index.php [L]
diff --git a/composer.json b/composer.json
new file mode 100644 (file)
index 0000000..2a36108
--- /dev/null
@@ -0,0 +1,5 @@
+{
+    "require": {
+        "m6w6/autocracy": "dev-master"
+    }
+}
diff --git a/composer.lock b/composer.lock
new file mode 100644 (file)
index 0000000..11a05e8
--- /dev/null
@@ -0,0 +1,65 @@
+{
+    "_readme": [
+        "This file locks the dependencies of your project to a known state",
+        "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file"
+    ],
+    "hash": "0147473751b895f221e765fd6fb1fc2b",
+    "packages": [
+        {
+            "name": "m6w6/autocracy",
+            "version": "dev-master",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/m6w6/autocracy.git",
+                "reference": "b6830cfce3dc276bf67288a7c6bfe64ffd290e21"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/m6w6/autocracy/zipball/b6830cfce3dc276bf67288a7c6bfe64ffd290e21",
+                "reference": "b6830cfce3dc276bf67288a7c6bfe64ffd290e21",
+                "shasum": ""
+            },
+            "type": "library",
+            "autoload": {
+                "psr-0": {
+                    "http\\Controller": "lib"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-2-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Michael Wallner",
+                    "email": "mike@php.net"
+                }
+            ],
+            "description": "http\\Controller preserves your autocracy",
+            "homepage": "http://github.com/m6w6/autocracy",
+            "keywords": [
+                "controller",
+                "http",
+                "pecl",
+                "pecl_http"
+            ],
+            "time": "2013-10-22 11:41:09"
+        }
+    ],
+    "packages-dev": [
+
+    ],
+    "aliases": [
+
+    ],
+    "minimum-stability": "stable",
+    "stability-flags": {
+        "m6w6/autocracy": 20
+    },
+    "platform": [
+
+    ],
+    "platform-dev": [
+
+    ]
+}
diff --git a/index.css b/index.css
deleted file mode 100644 (file)
index a48ac00..0000000
--- a/index.css
+++ /dev/null
@@ -1,162 +0,0 @@
-* { 
-       font-size: 99.9%;
-}
-
-body, code {
-       font-family: Inconsolata, Monospace, 'Courier New', Courier, monospace;
-}
-body {
-       font-size: 1.5em;
-       margin: 0;
-       padding: 0;
-       color: #3f3f3f;
-}
-
-body>* {
-       margin-left: 1em;
-}
-body>ul {
-       margin-left: 2em;
-}
-
-.sidebar {
-       font-size: .9em;
-       float: right;
-       background: #f0f0f0;
-       border-bottom-left-radius: 10px;
-       padding: 0;
-       width: auto;
-       padding-right: 1em;
-}
-.sidebar>ul {
-}
-.sidebar ul {
-       margin-left: 1em;
-       padding: 0;
-       list-style-type: none;
-}
-
-code { 
-       display: inline-block;
-       border-radius: 2px;
-       padding: 0px 2px 2px 2px;
-       background: #e0e0e0;
-       color: #606060;
-       box-shadow: 0 0 1px #999;
-}
-
-code code {
-       display: inline;
-       padding: 0;
-       background: transparent;
-       border: none;
-       box-shadow: none;
-}
-
-pre>code {
-       padding: 1em;
-}
-pre>code, pre>code code {
-       background: #333;
-       color: #eee;
-}
-
-p, pre {
-       margin: 1em 2em;
-}
-
-blockquote {
-       border-top: 1px solid #800000;
-       border-bottom: 1px solid #800000;
-       background: #ffe4e1;
-       margin: 2em 0;
-}
-
-ul {
-       margin-bottom: 2em;
-}
-li {
-       margin-bottom: .5em;
-}
-a, h1 code>a {
-       color: #2f4f4f;
-}
-a:hover {
-       text-decoration: none;
-}
-
-.var {
-       color: #800000;
-}
-.constant {
-       color: #2e8b57;
-}
-
-h1 {
-       line-height: 1.5;
-}
-h1 code {
-       font-weight: normal;
-       font-size: .9em;
-       line-height: 1.33;
-}
-
-footer, h1, li h3 {
-       background: #708090;
-       color: #f5f5dc;
-}
-
-footer, h1 {
-       margin: 0;
-       padding: 1em;
-}
-
-li h3 {
-       border-radius: 4px;
-       display: inline-block;
-       width: auto;
-       padding: .2em;
-       margin: .5em 0 0 0;
-}
-
-h1 .constant, pre>code .consant, li h3 .constant {
-       color: #98fb98;
-}
-
-h1 .var, pre>code .var, li h3 .var {
-       color: #f4a460;
-}
-
-footer a, h1 a, pre>code a, li h3 a {
-       color: #b0e0e6;
-}
-
-li h3 a {
-       text-decoration: none;
-}
-li h3 a:hover {
-       text-decoration: underline;
-}
-
-#disqus_thread {
-       margin-top: 8em;
-       margin-right: 2em;
-}
-
-footer {
-       font-size: smaller;
-       text-align: center;
-       clear: both;
-       margin-top: 8em;
-}
-
-footer ul {
-       margin: 0;
-       padding: 0;
-}
-
-footer li {
-       list-style-type: none;
-       display: inline-block;
-       margin: 0 1em;
-}
diff --git a/index.js b/index.js
deleted file mode 100644 (file)
index e0f3ccf..0000000
--- a/index.js
+++ /dev/null
@@ -1,200 +0,0 @@
-function log() {
-       // console.log.apply(console, arguments);
-}
-
-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) === "$";
-}
-
-var is_in_string = false;
-
-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 "<code>";
-               
-       // keywords
-       case "is":
-               if (nn !== "H1") {
-                       return;
-               }
-       case "extends":
-       case "implements":
-               if (nn === "H1") {
-                       return "<br>&nbsp;<em>";
-               }
-       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 "<em>";
-       }
-       
-       // class members
-       if (-1 !== (i = s.indexOf("::"))) {
-               t = s.substring(i+2);
-               if (!is_constant(t) && !is_variable(t)) {
-                       // methods
-                       return "<a href=\"" + s.replace(/::|\\/g, "/") + "\">";
-               }
-       }
-       if (-1 !== (j = s.indexOf("\\")) && s.substr(j+1,1) !== "n") {
-               return "<a href=\"" + s.replace(/\\/g, "/").replace(/::|$/, "#") + "\">";
-       }
-       
-       switch (s.toLowerCase()) {
-       // variables
-       default:
-               if (!is_variable(s)) {
-                       break;
-               }
-       // special constants
-       case "null":
-       case "true":
-       case "false":
-               return "<span class=\"var\">";
-       }
-       
-       // constants
-       if (is_constant(s)) {
-               return "<span class=\"constant\">";
-       }
-}
-
-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 = [];
-
-       $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);
-
-       $.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;
-               }
-       });
-}
-
-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");
-}
-
-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;
-                               }
-                               blink(c);
-                       }
-               } : function(i, c) {
-                       if (c.textContent === hash) {
-                               $(window).scrollTop($(c).offset().top - 100);
-                               blink(c);
-                               return false;
-                       }
-               });
-       }
-}
-
-$(function() {
-       $("h1,h2,h3,h4,h5,h6,p,li,code").each(walk);
-       $(window).on("hashchange", hashchange);
-       hashchange();
-});
diff --git a/index.php b/index.php
deleted file mode 100644 (file)
index 0dd361f..0000000
--- a/index.php
+++ /dev/null
@@ -1,256 +0,0 @@
-<?php
-
-error_reporting(E_ALL &~ E_DEPRECATED);
-
-function cut(array $lines, array $specs) {
-       $delim = "[[:space:]]+";
-       $bytes = [];
-       $fields= [];
-       
-       foreach ($specs as $spec => $value) {
-               switch ($spec) {
-               case "d":
-                       $delim = $value;
-                       break;
-               case "b":
-                       $bytes = $value;
-                       break;
-               case "f":
-                       $fields = $value;
-                       break;
-               }
-       }
-       
-       $result = [];
-       if ($bytes) {
-               $func = "substr";
-       } else {
-               $func = function($a, $o = 0, $l = 0) {
-                       return join(" ", array_slice($a, $o, $l ? $l+1 : count($a)-$o));
-               };
-       }
-       foreach ($lines as $line) {
-               if ($bytes) {
-                       $spec = $bytes;
-               } else {
-                       $line = split($delim, $line);
-                       $spec = $fields;
-               }
-               
-               if ($spec[0] == "-") {
-                       $result[] = $func($line, 0, $spec[1]);
-               } elseif ($spec[1] == "-") {
-                       if (empty($spec[2])) {
-                               $result[] = $func($line, $spec[0]);
-                       } else {
-                               $result[] = $func($line, $spec[0], $spec[2]-$spec[0]);
-                       }
-               } else {
-                       $result[] = $line{$spec[0]};
-               }
-       }
-       return $result;
-}
-
-function head($file, $lines = 1) {
-       $ld = [];
-       if (is_resource($file) || ($file = fopen($file, "r"))) {
-               while ($lines--) {
-                       $ld[] = fgets($file);
-               }
-       }
-       return $ld;
-}
-
-function ns($path) {
-       $ns = "";
-       $parts = explode("/", $path);
-       $upper = ctype_upper($path[0]);
-       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;
-       return str_replace("/", "\\", str_replace("//", "/", trim($file, "/.")));
-}
-
-function urlpath($dir, $file) {
-       return (strlen($dir) ? $dir . "/" : "") . basename($file, ".md");
-}
-
-function email($email) {
-       if (preg_match("/^([^<]+) <([^>]+)>/", $email, $matches)) {
-               list(, $name, $mail) = $matches;
-               return sprintf('<a href="mailto:%s">%s</a>', 
-                       htmlspecialchars($mail), 
-                       htmlspecialchars($name));
-       }
-       var_dump(sscanf($email, "%s <%s>"));
-}
-
-function ls($dir) {
-       $dir = rtrim(is_dir($dir) ? $dir : dirname($dir) ."/". basename($dir, ".md"), "/");
-       printf("<ul>\n");
-       printf("<li>&lArr; <a href=>Home</a></li>\n");
-       if ($dir !== "." && ($dn = dirname($dir)) !== ".") {
-               printf("<li>&uArr; <a href=%s>%s</a></li>\n", 
-                       urlpath($dir, ".."),
-                       ns($dn));
-       }
-       if (is_dir($dir)) {
-               if ($dir !== ".") {
-                       printf("<ul>\n<li>&nbsp; %s</li>\n", ns($dir));
-               }
-               if (($glob = glob("$dir/[_a-zA-Z]*.md"))) {
-                       printf("<ul>\n");
-                       foreach ($glob as $file) {
-                               printf("<li>&rArr; <a href=\"%s\">%s</a></li>\n", 
-                                       urlpath($dir, $file),
-                                       ns("$dir/".basename($file, ".md")));
-                       }
-                       printf("</ul>\n");
-               }
-               if ($dir !== ".") {
-                       printf("</ul>\n");
-               }
-       }
-       
-       printf("</ul>\n");
-}
-
-function ml($file) {
-       $pi = pathinfo($file);
-       if (!isset($pi["extension"])) {
-               return;
-       }
-       if ($pi["extension"] !== "md") {
-               return;
-       }
-       $dir = $pi["dirname"] . "/" . $pi["filename"];
-       if (($glob = glob("$dir/[_a-z]*.md"))) {
-       printf("<h2>%s:</h2>\n", !ctype_upper($pi["filename"][0]) ?
-               "Functions" : "Methods");
-               printf("<ul>\n");
-               foreach ($glob as $file) {
-                       printf("<li><h3><a href=\"%s\">%s</a></h3><p>%s</p><p>%s</p></li>\n",
-                               urlpath($dir, $file),
-                               basename($file, ".md"),
-                               @end(head($file, 3)),
-                               join(" ", cut(head($file), ["f"=>"1-"]))
-                       );
-               }
-               printf("</ul>\n");
-       }
-}
-
-function md($file, $res) {
-       $file = rtrim($file, "/");
-       if (is_file($file) || is_file($file .= ".md")) {
-               $pi = pathinfo($file);
-               
-               switch (@$pi["extension"]) {
-               case "md":
-                       $r = fopen($file, "r");
-                       $md = MarkdownDocument::createFromStream($r);
-                       $md->compile(MarkdownDocument::AUTOLINK|MarkdownDocument::TOC);
-                       print $md->getHtml();
-                       fclose($r);
-                       ml($file);
-                       break;
-               case null:
-                       printf("<h1>%s</h1>", basename($file));
-                       printf("<pre>%s</pre>\n", htmlspecialchars(file_get_contents($file)));
-                       break;
-               }
-       } else {
-               $res->setResponseCode(404);
-               printf("<h1>Not Found</h1>\n");
-               printf("<blockquote><p>Sorry, I could not find <code>%s/%s</code>.</p></blockquote>", dirname($file), basename($file, ".md"));
-       }
-}
-
-chdir(__DIR__);
-$t = ["css"=>"text/css", "js"=>"application/javascript"];
-$r = new http\Env\Request;
-$u = new http\Url($r->getRequestUrl());
-$s = new http\Env\Response;
-$b = dirname($_SERVER["SCRIPT_NAME"]);
-$p = ".". substr($u->path, strlen($b));
-
-switch($p) {
-case "./index.php":
-       exit;
-case "./index.js":
-case "./index.css":
-       $s->setHeader("Content-type", $t[pathinfo($p, PATHINFO_EXTENSION)]);
-       $s->setBody(new http\Message\Body(fopen($p, "r")));
-       $s->send();
-       exit;
-}
-
-ob_start($s);
-
-?>
-<!doctype html>
-<html>
-<head>
-       <meta charset="utf-8">
-       <title><?=ns($p)?></title>
-       <base href="<?=new http\Url($b, null, http\Url::FROM_ENV | (http\Url::STRIP_ALL & ~http\Url::STRIP_PATH))  ?>/">
-       <link rel="stylesheet" href="index.css">
-       <script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script> 
-</head>
-<body>
-       <div class="sidebar">
-               <?php ls($p); ?>
-       </div>
-       <?php if ($p === "./") : ?>
-               <h1>Quick Markdown Documentation Browser</h1>
-               <p><a href="https://github.com/m6w6/mdref">mdref-v<?php readfile("VERSION")?></a></p>
-               <pre><?php
-                       ob_start(function($s) {
-                               return htmlspecialchars($s);
-                       });
-                       readfile("LICENSE");
-                       ob_end_flush();
-               ?></pre>
-       <?php else: ?>
-               <?php md($p, $s); ?>
-       <?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">&copy; <?= implode("-", array_unique([2013,idate("Y")]))?></a></li>
-               </ul>
-       </footer>
-       <script src="index.js"></script>
-       <?php if ($_SERVER["SERVER_NAME"] != "localhost") : ?>
-    <script>
-        var disqus_shortname = 'mdref';
-        var disqus_identifier = '<?=$p?>';
-        (function() {
-            var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
-            dsq.src = '//' + disqus_shortname + '.disqus.com/embed.js';
-            (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
-        })();
-    </script>
-    <?php endif; ?>
-</body>
-</html>
-<?php
-
-ob_end_flush();
-$s->send();
diff --git a/mdref/Action.php b/mdref/Action.php
new file mode 100644 (file)
index 0000000..462e35b
--- /dev/null
@@ -0,0 +1,56 @@
+<?php
+
+namespace mdref;
+
+use http\Controller\Observer;
+
+/**
+ * The sole action controller of mdref
+ */
+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'");
+               }
+       }
+
+       /**
+        * Implements \SplObserver
+        * @param \SplSubject $ctl
+        */
+       function update(\SplSubject $ctl) {
+               /* @var \http\Controller $ctl */
+               try {
+                       $ctl->getPayload()->baseUrl = $this->baseUrl;
+
+                       if (!$this->serveReference($ctl)) {
+                               $this->serveInternal($ctl);
+                       }
+               } catch (\Exception $e) {
+                       $ctl->getPayload()->exception = $e;
+               }
+       }
+}
diff --git a/mdref/ExceptionHandler.php b/mdref/ExceptionHandler.php
new file mode 100644 (file)
index 0000000..0edf728
--- /dev/null
@@ -0,0 +1,58 @@
+<?php
+
+namespace mdref;
+
+use http\Env as HTTP;
+
+/**
+ * mdref exception handler
+ */
+class ExceptionHandler
+{
+       function __construct() {
+               set_exception_handler($this);
+               set_error_handler($this);
+       }
+       
+       function __invoke($e, $msg = null) {
+               if ($e instanceof \Exception) {
+                       try {
+                               echo static::html($e);
+                       } catch (\Exception $ignore) {
+                               HTTP::sendStatusCode(500);
+                       }
+               } else {
+                       throw new \Exception($msg, $e);
+               }
+               return true;
+       }
+       
+       /**
+        * Format an exception as HTML and send appropriate exception info as HTTP headers
+        * @param \Exception $e
+        * @param array $title_tag
+        * @param array $message_tag
+        * @param array $trace_tag
+        * @return string
+        */
+       static function html(\Exception $e, array $title_tag = ["h1"], array $message_tag = ["p"], array $trace_tag = ["pre", "style='font-size:smaller'"]) {
+               if ($e instanceof \http\Controller\Exception) {
+                       $code = $e->getCode() ?: 500;
+                       foreach ($e->getHeaders() as $key => $val) {
+                               HTTP::sendResponseHeader($key, $val);
+                       }
+               } else {
+                       $code = 500;
+               }
+               HTTP::setResponseCode($code);
+               $name = HTTP::getResponseStatusForCode($code);
+               $html = sprintf("<%s>%s</%s>\n<%s>%s</%s>\n",
+                               implode(" ", $title_tag), $name, $title_tag[0],
+                               implode(" ", $message_tag), $e->getMessage(), $message_tag[0]);
+               if ($trace_tag) {
+                       $html .= sprintf("<%s>%s</%s>\n",
+                                       implode(" ", $trace_tag), $e->getTraceAsString(), $trace_tag[0]);
+               }
+               return $html;
+       }
+}
\ No newline at end of file
diff --git a/mdref/Finder.php b/mdref/Finder.php
new file mode 100644 (file)
index 0000000..e5cb7fb
--- /dev/null
@@ -0,0 +1,87 @@
+<?php
+
+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
+{
+       /**
+        * Base URL
+        * @var \http\Controller\Url 
+        */
+       protected $baseUrl;
+       
+       /**
+        * Reference paths
+        * @var array
+        */
+       protected $refs = array();
+       
+       /**
+        * @param \http\Controller\Url $baseUrl
+        * @param mixed $paths array or string of paths with markdown references
+        */
+       function __construct(\http\Controller\Url $baseUrl, $paths = ".") {
+               if (!is_array($paths)) {
+                       $paths = explode(PATH_SEPARATOR, $paths);
+               }
+               $this->refs = $paths;
+               $this->baseUrl = $baseUrl;
+       }
+       
+       /**
+        * @return \http\Controller\Url
+        */
+       function getBaseUrl() {
+               return $this->baseUrl;
+       }
+       
+       /**
+        * 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, $ext = ".md") {
+               $file = implode(DIRECTORY_SEPARATOR, $this->baseUrl->params($requestUrl));
+               
+               foreach ($this->refs as $base) {
+                       $path = new Path($base, $file);
+                       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);
+               }
+               $glob = array();
+               foreach ($this->refs as $ref) {
+                       $glob = array_merge($glob, array_map(function ($fn) use ($ref) {
+                               return substr($fn, strlen($ref));
+                       }, glob($ref . $pattern, $flags)));
+               }
+               return $glob;
+       }
+}
diff --git a/mdref/Markdown.php b/mdref/Markdown.php
new file mode 100644 (file)
index 0000000..6d761c2
--- /dev/null
@@ -0,0 +1,34 @@
+<?php
+
+namespace mdref;
+
+class Markdown
+{
+       /**
+        * @var \mdref\Path
+        */
+       protected $path;
+       
+       /**
+        * @param \mdref\Path $path
+        */
+       function __construct(Path $path) {
+               $this->path = $path;
+       }
+       
+       /**
+        * @return string
+        */
+       function __toString() {
+               try {
+                       $r = fopen($this->path->getFullPath(".md"), "r");
+                       $md = \MarkdownDocument::createFromStream($r);
+                       $md->compile(\MarkdownDocument::AUTOLINK | \MarkdownDocument::TOC);
+                       $html = $md->getHtml();
+                       fclose($r);
+               } catch (\Exception $e) {
+                       $html = ExceptionHandler::html($e);
+               }
+               return $html;
+       }
+}
diff --git a/mdref/Path.php b/mdref/Path.php
new file mode 100644 (file)
index 0000000..efa208a
--- /dev/null
@@ -0,0 +1,100 @@
+<?php
+
+namespace mdref;
+
+/**
+ * A path made out of a base dir and an thereof relative path name.
+ */
+class Path
+{
+       /**
+        * Computed path
+        * @var string
+        */
+       protected $path = "";
+       
+       /**
+        * The base directory where path is located
+        * @var string
+        */
+       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);
+       }
+       
+       function isFile($ext = ".md") {
+               return is_file($this->getFullPath($ext));
+       }
+       
+       function toHtml() {
+               $head = sprintf("<h1>%s</h1>\n", htmlspecialchars(basename($this->getPathName())));
+               if ($this->isFile()) {
+                       $html = htmlspecialchars(file_get_contents($this->getFullPath()));
+               } elseif ($this->isFile("")) {
+                       $html = htmlspecialchars(file_get_contents($this->getFullPath("")));
+               } else {
+                       throw new \http\Controller\Exception(404, "Not Found: {$this->getPathName()}");
+               }
+               return $head . "<pre>" . $html ."</pre>"; 
+       }
+}
\ No newline at end of file
diff --git a/mdref/RefEntry.php b/mdref/RefEntry.php
new file mode 100644 (file)
index 0000000..9db99f7
--- /dev/null
@@ -0,0 +1,162 @@
+<?php
+
+namespace mdref;
+
+/**
+ * The RefEntry class represents a reference entry, i.e. a .md file
+ */
+class RefEntry
+{
+       /**
+        * @var \mdref\Path
+        */
+       protected $path;
+       
+       /**
+        * @var string
+        */
+       protected $entry;
+       
+       /**
+        * @var resource
+        */
+       protected $file;
+       
+       /**
+        * @param \mdref\Path $path
+        * @param type $entry
+        */
+       function __construct(Path $path, $entry = null) {
+               $this->path = $path;
+               $this->entry = trim($entry ?: $path->getPathName(), DIRECTORY_SEPARATOR);
+       }
+       
+       /**
+        * Clean up the file handle
+        */
+       function __destruct() {
+               if (is_resource($this->file)) {
+                       fclose($this->file);
+               }
+       }
+       
+       /**
+        * Format as URL
+        * @return string
+        */
+       function formatUrl() {
+               return htmlspecialchars($this->entry);
+       }
+       
+       private function joinLink(array $parts) {
+               $link = "";
+               $upper = ctype_upper($parts[0][0]);;
+               for ($i = 0; $i < count($parts); ++$i) {
+                       if (!strlen($parts[$i]) || $parts[$i] === ".") {
+                               continue;
+                       }
+                       if (strlen($link)) {
+                               if ($upper && !ctype_upper($parts[$i][0])) {
+                                       $link .= "::";
+                               } else {
+                                       $link .= "\\";
+                               }
+                       }
+                       $link .= $parts[$i];
+                       $upper = ctype_upper($parts[$i][0]);
+               }
+               return $link;
+       }
+
+       /**
+        * Format as link text
+        * @param bool $basename whether to use the basename only
+        * @return string
+        */
+       function formatLink($basename = false) {
+               $link = "";
+               if (strlen($this->entry)) {
+                       $parts = explode(DIRECTORY_SEPARATOR, $this->entry);
+                       $link = $basename ? end($parts) : $this->joinLink($parts);
+               }
+               return htmlspecialchars($link);
+       }
+       
+       /**
+        * Create a consolidated Path of this entry
+        * @return \mdref\Path
+        */
+       function getPath() {
+               $path = $this->path;
+               $file = $path($this->entry);
+               return $file;
+       }
+       
+       private function openFile() {
+               if (!is_resource($this->file)) {
+                       $file = $this->getPath();
+                       
+                       if (!$file->isFile()) {
+                               throw new \Exception("Not a file: '{$file}'");
+                       }
+                       if (!$this->file = fopen($file->getFullPath(".md"), "r")) {
+                               throw new \Exception("Could not open {$file}");
+                       }
+               }
+       }
+       
+       /**
+        * Read the title of the refentry
+        * @return string
+        */
+       function readTitle() {
+               $this->openFile();
+               fseek($this->file, 1, SEEK_SET);
+               return htmlspecialchars(fgets($this->file));
+       }
+       
+       /**
+        * Read the description of the refentry
+        * @return string
+        */
+       function readDescription() {
+               $this->openFile();
+               fseek($this->file, 0, SEEK_SET);
+               fgets($this->file);
+               fgets($this->file);
+               return htmlspecialchars(fgets($this->file));
+       }
+       
+       /**
+        * Format a "Edit me" URL. The project reference top directory needs a 
+        * Â»name«.mdref file besides its Â»name«.md entry point with the edit URL
+        * printf template as content. The sole printf argument is the relative 
+        * path of the entry.
+        * @return string
+        */
+       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);
+               }
+       }
+       
+       /**
+        * Recurse into the reference tree
+        * @param \mdref\Finder $refs
+        * @param string $pattern
+        * @param callable $cb
+        */
+       function recurse(Finder $refs, $pattern, callable $cb) {
+               $path = $refs->find($refs->getBaseUrl()->mod($this->entry));
+               foreach (new RefListing($path, $refs->glob($path, $pattern)) as $entry) {
+                       /* @var $entry RefEntry */
+                       $cb($entry, $pattern, function($entry, $pattern) use ($refs, $cb) {
+                               $entry->recurse($refs, $pattern, $cb);
+                       });
+               }
+       }
+}
diff --git a/mdref/RefListing.php b/mdref/RefListing.php
new file mode 100644 (file)
index 0000000..3816be2
--- /dev/null
@@ -0,0 +1,98 @@
+<?php
+
+namespace mdref;
+
+/**
+ * A list of markdown reference files
+ */
+class RefListing implements \Countable, \Iterator
+{
+       /**
+        * @var \mdref\Path
+        */
+       protected $path;
+       
+       /**
+        * @var array
+        */
+       protected $entries;
+       
+       /**
+        * @param \mdref\Path $path
+        * @param array $files
+        */
+       function __construct(Path $path, array $files) {
+               $this->path = $path;
+               $this->entries = array_map(function($fn) {
+                       return substr(trim($fn, DIRECTORY_SEPARATOR), 0, -3);
+               }, $files);
+       }
+       
+       /**
+        * Implements \Countable
+        * @return int
+        */
+       function count() {
+               return count($this->entries);
+       }
+       
+       /**
+        * Implements \Iterator
+        */
+       function rewind() {
+               reset($this->entries);
+       }
+       
+       /**
+        * Implements \Iterator
+        * @return bool
+        */
+       function valid() {
+               return null !== key($this->entries);
+       }
+       
+       /**
+        * Implements \Iterator
+        * @return string
+        */
+       function key() {
+               return $this->path->getSubPath(current($this->entries));
+       }
+       
+       /**
+        * Implements \Iterator
+        */
+       function next() {
+               next($this->entries);
+       }
+
+       /**
+        * Implements \Iterator
+        * @return \mdref\RefEntry
+        */
+       function current() {
+               return new RefEntry($this->path, $this->key());//$this->format($this->key());
+       }
+       
+       /**
+        * Get the parent reference entry
+        * @return null|\mdref\RefEntry
+        */
+       function getParent() {
+               switch ($parent = dirname($this->path->getPathName())) {
+                       case ".":
+                       case "":
+                               return null;
+                       default:
+                               return new RefEntry($this->path, $parent);
+               }
+       }
+       
+       /**
+        * Get the reference entry this reflist is based of
+        * @return \mdref\RefEntry
+        */
+       function getSelf() {
+               return new RefEntry($this->path);
+       }
+}
diff --git a/public/.htaccess b/public/.htaccess
new file mode 100644 (file)
index 0000000..affb2a0
--- /dev/null
@@ -0,0 +1,6 @@
+RewriteEngine On
+RewriteCond %{REQUEST_FILENAME} -f [OR]
+RewriteCond %{REQUEST_FILENAME} -d [OR]
+RewriteCond %{REQUEST_FILENAME} -l
+RewriteRule ^ - [L]
+RewriteRule ^ index.php [L]
diff --git a/public/index.css b/public/index.css
new file mode 100644 (file)
index 0000000..2f86d66
--- /dev/null
@@ -0,0 +1,188 @@
+* { 
+       font-size: 99.9%;
+}
+
+body, code {
+       font-family: Inconsolata, Monospace, 'Courier New', Courier, monospace;
+}
+body {
+       font-size: 1.5em;
+       margin: 0;
+       padding: 0;
+       color: #3f3f3f;
+}
+
+body>* {
+       margin-left: 1em;
+}
+body>ul {
+       margin-left: 2em;
+}
+
+.sidebar {
+       font-size: .9em;
+       float: right;
+       background: #f0f0f0;
+       border-bottom-left-radius: 10px;
+       padding: 0;
+       width: auto;
+       min-width: 200px;
+       padding-right: 1em;
+}
+.sidebar>ul {
+}
+.sidebar ul {
+       margin-left: 1em;
+       margin-top: .5em;
+       padding: 0;
+       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;
+       padding: 0px 2px 2px 2px;
+       background: #e0e0e0;
+       color: #606060;
+       box-shadow: 0 0 1px #999;
+}
+
+code code {
+       display: inline;
+       padding: 0;
+       background: transparent;
+       border: none;
+       box-shadow: none;
+}
+
+pre>code {
+       padding: 1em;
+}
+pre>code, pre>code code {
+       background: #333;
+       color: #eee;
+}
+
+p, pre {
+       margin: 1em 2em;
+}
+
+li>p {
+       margin: 1em 0;
+}
+
+blockquote {
+       border-top: 1px solid #800000;
+       border-bottom: 1px solid #800000;
+       background: #ffe4e1;
+       margin: 2em 0;
+}
+
+ul {
+       margin-bottom: 2em;
+}
+li {
+       margin-bottom: .5em;
+}
+a, h1 code>a {
+       color: #2f4f4f;
+}
+a:hover {
+       text-decoration: none;
+}
+
+.var {
+       color: #800000;
+}
+.constant {
+       color: #2e8b57;
+}
+
+h1 {
+       line-height: 1.5;
+}
+h1 code {
+       font-weight: normal;
+       font-size: .9em;
+       line-height: 1.33;
+}
+
+footer, h1, li h3 {
+       background: #708090;
+       color: #f5f5dc;
+}
+
+footer, h1 {
+       margin: 0;
+       padding: 1em;
+}
+
+li h3 {
+       border-radius: 4px;
+       display: inline-block;
+       width: auto;
+       padding: .2em;
+       margin: .5em 0 0 0;
+}
+
+h1 .constant, pre>code .consant, li h3 .constant {
+       color: #98fb98;
+}
+
+h1 .var, pre>code .var, li h3 .var {
+       color: #f4a460;
+}
+
+footer a, h1 a, pre>code a, li h3 a {
+       color: #b0e0e6;
+}
+
+li h3 a {
+       text-decoration: none;
+}
+li h3 a:hover {
+       text-decoration: underline;
+}
+
+#disqus_thread {
+       margin-top: 8em;
+       margin-right: 2em;
+}
+
+footer {
+       font-size: smaller;
+       text-align: center;
+       clear: both;
+       margin-top: 8em;
+}
+
+footer ul {
+       margin: 0;
+       padding: 0;
+}
+
+footer li {
+       list-style-type: none;
+       display: inline-block;
+       margin: 0 1em;
+}
+
+footer a {
+       text-decoration: none;
+}
+
+footer a:hover {
+       text-decoration: underline;
+}
\ No newline at end of file
diff --git a/public/index.js b/public/index.js
new file mode 100644 (file)
index 0000000..62ccba6
--- /dev/null
@@ -0,0 +1,194 @@
+"use strict";
+
+$(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;
+                       }
+
+                       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 "<code>";
+
+                       // keywords
+                       case "is":
+                               if (nn !== "H1") {
+                                       return;
+                               }
+                       case "extends":
+                       case "implements":
+                               if (nn === "H1") {
+                                       return "<br>&nbsp;<em>";
+                               }
+                       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 "<em>";
+                       }
+
+                       // class members
+                       if (-1 !== (i = s.indexOf("::"))) {
+                               t = s.substring(i+2);
+                               if (!mdref.is_constant(t) && !mdref.is_variable(t)) {
+                                       // methods
+                                       return "<a href=\"" + s.replace(/::|\\/g, "/") + "\">";
+                               }
+                       }
+                       if (-1 !== (j = s.indexOf("\\")) && s.substr(j+1,1) !== "n") {
+                               return "<a href=\"" + s.replace(/\\/g, "/").replace(/::|$/, "#") + "\">";
+                       }
+
+                       switch (s.toLowerCase()) {
+                       // variables
+                       default:
+                               if (!mdref.is_variable(s)) {
+                                       break;
+                               }
+                       // special constants
+                       case "null":
+                       case "true":
+                       case "false":
+                               return "<span class=\"var\">";
+                       }
+
+                       // constants
+                       if (mdref.is_constant(s)) {
+                               return "<span class=\"constant\">";
+                       }
+               },
+               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 = [];
+
+                       $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);
+
+                       $.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: 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");
+               },
+               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;
+                                               }
+                                               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").each(mdref.walk);
+       $(window).on("hashchange", mdref.hashchange);
+       mdref.hashchange();
+});
diff --git a/public/index.php b/public/index.php
new file mode 100644 (file)
index 0000000..d4518cd
--- /dev/null
@@ -0,0 +1,25 @@
+<?php
+
+define("ROOT", dirname(__DIR__));
+define("REFS", getenv("REFPATH") ?: implode(PATH_SEPARATOR, glob(ROOT."/refs/*")));
+
+$loader = require __DIR__ . "/../vendor/autoload.php";
+/* @var $loader \Composer\Autoload\ClassLoader */
+$loader->add("mdref", ROOT);
+
+use http\Controller;
+use http\Controller\Url;
+use http\Controller\Observer\Layout;
+
+use mdref\ExceptionHandler;
+use mdref\Action;
+
+new ExceptionHandler;
+
+$ctl = new Controller;
+$ctl->setDependency("baseUrl", new Url)
+       ->attach(new Action)
+       ->attach(new Layout)
+       ->notify()
+       ->getResponse()
+       ->send();
diff --git a/views/edit.phtml b/views/edit.phtml
new file mode 100644 (file)
index 0000000..aabbb02
--- /dev/null
@@ -0,0 +1,3 @@
+<?php if (isset($listing) && ($entry = $listing->getSelf()) && ($url = $entry->formatEditUrl())) : ?>
+       <a class="edit" href="<?=$url?>">Edit Page</a>
+<?php endif; ?>
diff --git a/views/footer.phtml b/views/footer.phtml
new file mode 100644 (file)
index 0000000..12ef7fb
--- /dev/null
@@ -0,0 +1,6 @@
+<ul>
+       <li><a href="https://github.com/m6w6/mdref">mdref-v<?php readfile(__DIR__."/../VERSION") ?></a></li>
+       <li><a href="LICENSE">&copy; <?= implode("-", array_unique([2013, idate("Y")])) ?>
+               All rights reserved.</a></li>
+       <li><?php include __DIR__."/edit.phtml" ?></li>
+</ul>
diff --git a/views/index.phtml b/views/index.phtml
new file mode 100644 (file)
index 0000000..dbd3017
--- /dev/null
@@ -0,0 +1,20 @@
+<h1>mdref</h1>
+
+<?php if (isset($exception)) : ?>
+       <?=\mdref\ExceptionHandler::html($exception, ["h2"], ["p"], ["pre", "style='overflow-x:scroll'"]); ?>
+<?php else : ?>
+       <?php if (isset($listing) && count($listing)) : ?>
+               <h2>Available References</h2>
+               <?php foreach ($listing as $entry) : ?>
+                       <h3><a href="<?=$entry->formatUrl()?>"><?=$entry->formatLink()?></a></h3>
+                       <?php $entry->recurse($refs, "/*.md", function($entry, $pattern, callable $recursor) { ?>
+                       <ul>
+                               <li><p><a href="<?=$entry->formatUrl()?>"><?=$entry->formatLink()?></a></p>
+                                       <?=$entry->readDescription()?>
+                                       <?php $recursor($entry, "/[A-Z]*.md") ?>
+                               </li>
+                       </ul>
+                       <?php }); ?>
+               <?php endforeach; ?>
+       <?php endif; ?>
+<?php endif; ?>
diff --git a/views/layout.phtml b/views/layout.phtml
new file mode 100644 (file)
index 0000000..43463ca
--- /dev/null
@@ -0,0 +1,32 @@
+<!doctype html>
+<html>
+       <head>
+               <meta charset="utf-8">
+               <title>
+                       <?php if ($title) : ?>
+                               <?= $title ?> - mdref
+                       <?php else: ?>
+                               mdref
+                       <?php endif; ?>
+               </title>
+               <base href="<?= $baseUrl ?>">
+               <link rel="stylesheet" href="index.css">
+               <script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
+       </head>
+       <body>
+               <?php include __DIR__."/sidebar.phtml" ?>
+               
+               <?php if (isset($html)) : ?>
+                       <?php include __DIR__."/mdref.phtml" ?>
+               <?php else: ?>
+                       <?php include __DIR__."/index.phtml" ?>
+               <?php endif; ?>
+
+               <div id="disqus_thread"></div>
+
+               <footer>
+                       <?php include __DIR__."/footer.phtml" ?>
+               </footer>
+               <script src="index.js"></script>
+       </body>
+</html>
diff --git a/views/mdref.phtml b/views/mdref.phtml
new file mode 100644 (file)
index 0000000..5cec21d
--- /dev/null
@@ -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 (file)
index 0000000..f6dccb4
--- /dev/null
@@ -0,0 +1,24 @@
+<?php if (isset($listing)) : ?>
+<div class="sidebar">
+       <?php include __DIR__."/edit.phtml" ?>
+       <ul>
+               <li>&lsh; <a href="">Home</a></li>
+               <?php if (($entry = $listing->getParent())) : ?>
+                       <li>&uarr; <a href="<?=$entry->formatUrl()?>"><?=$entry->formatLink()?></a></li>
+               <?php endif; ?>
+               <?php if (($entry = $listing->getSelf()) && ($link = $entry->formatLink())) : ?>
+                       <ul><li>&circlearrowright; <?= $link ?>
+               <?php endif; ?>
+               <?php if (count($listing)) : ?>
+                       <ul>
+                               <?php foreach ($listing as $entry) : ?>
+                               <li>&rdsh; <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; ?>