--- /dev/null
+Michael Wallner <mike@php.net>
--- /dev/null
+Copyright (c) 2013, Michael Wallner <mike@php.net>.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
--- /dev/null
+<?php
+
+namespace mdref;
+
+use http\Controller\Observer;
+
+class Action extends Observer
+{
+ 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"));
+
+ 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'");
+ }
+ } catch (\Exception $e) {
+ $payload->baseUrl = $this->baseUrl;
+ $ctl->getPayload()->exception = $e;
+ }
+ }
+}
--- /dev/null
+<?php
+
+namespace mdref;
+
+use http\Env as HTTP;
+
+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;
+ }
+
+ 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
--- /dev/null
+<?php
+
+namespace mdref;
+
+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;
+ }
+
+ /**
+ * @param \http\Url $requestUrl
+ * @return Path
+ */
+ function find(\http\Url $requestUrl) {
+ $file = implode(DIRECTORY_SEPARATOR,
+ $this->baseUrl->params($requestUrl));
+
+ foreach ($this->refs as $base) {
+ $path = new Path($base, $file);
+ if ($path->isFile()) {
+ return $path;
+ }
+ }
+ }
+
+ 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;
+ }
+}
--- /dev/null
+<?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;
+ }
+}
--- /dev/null
+<?php
+
+namespace mdref;
+
+class Path
+{
+ /**
+ * Computed path
+ * @var string
+ */
+ protected $path = "";
+
+ /**
+ * The base directory where path is located
+ * @var string
+ */
+ protected $baseDir = "";
+
+ function __construct($baseDir = "", $path = "") {
+ $this->baseDir = $baseDir;
+ $this->path = $path;
+ }
+
+ function __invoke($path) {
+ $that = clone $this;
+ $that->path = $path;
+ return $that;
+ }
+
+ function __toString() {
+ return $this->getFullPath();
+ }
+
+ function getBaseDir() {
+ return $this->baseDir;
+ }
+
+ function getPathName() {
+ return $this->path;
+ }
+
+ function getFullPath($ext = "") {
+ return $this->baseDir . DIRECTORY_SEPARATOR . $this->path . $ext;
+ }
+
+ function getSubPath($path) {
+ return trim(substr($path, strlen($this->baseDir)), DIRECTORY_SEPARATOR);
+ }
+
+ function isFile($ext = ".md") {
+ return is_file($this->getFullPath($ext));
+ }
+
+ function toHtml() {
+ if ($this->isFile()) {
+ return htmlspecialchars(file_get_contents($this->getFullPath()));
+ } elseif ($this->isFile("")) {
+ return htmlspecialchars(file_get_contents($this->getFullPath("")));
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+<?php
+
+namespace mdref;
+
+class RefEntry
+{
+ /**
+ * @var \mdref\Path
+ */
+ protected $path;
+
+ /**
+ * @var string
+ */
+ protected $entry;
+
+ /**
+ * @var resource
+ */
+ protected $file;
+
+ function __construct(Path $path, $entry = null) {
+ $this->path = $path;
+ $this->entry = $entry ?: $path->getPathName();
+ }
+
+ function __destruct() {
+ if (is_resource($this->file)) {
+ fclose($this->file);
+ }
+ }
+
+ 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) {
+ $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;
+ }
+
+ function formatLink($basename = false) {
+ $link = "";
+ if (strlen($entry = trim($this->entry, DIRECTORY_SEPARATOR))) {
+ $parts = explode(DIRECTORY_SEPARATOR, $entry);
+ $link = $basename ? end($parts) : $this->joinLink($parts);
+ }
+ return htmlspecialchars($link);
+ }
+
+ protected function openFile() {
+ if (!is_resource($this->file)) {
+ $path = $this->path;
+ $file = $path($this->entry);
+ if (!$file->isFile()) {
+ throw new \Exception("Not a file: '$this->entry'");
+ }
+ if (!$this->file = fopen($file->getFullPath(".md"), "r")) {
+ throw new \Exception("Could not open {$this->entry}");
+ }
+ }
+ }
+
+ function readTitle() {
+ $this->openFile();
+ fseek($this->file, 1, SEEK_SET);
+ return htmlspecialchars(fgets($this->file));
+ }
+
+ function readDescription() {
+ $this->openFile();
+ fseek($this->file, 0, SEEK_SET);
+ fgets($this->file);
+ fgets($this->file);
+ return htmlspecialchars(fgets($this->file));
+ }
+}
\ No newline at end of file
<?php
-class RefListing
+namespace mdref;
+
+class RefListing implements \Countable, \Iterator
{
- function __construct($dir) {
-
+ /**
+ * @var \mdref\Path
+ */
+ protected $path;
+
+ /**
+ * @var array
+ */
+ protected $entries;
+
+ /**
+ * @param \mdref\Path $path
+ */
+ function __construct(Path $path, array $files) {
+ $this->path = $path;
+ $this->entries = array_map(function($fn) {
+ return substr(trim($fn, DIRECTORY_SEPARATOR), 0, -3);
+ }, $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);
+ }
+
+ function rewind() {
+ reset($this->entries);
+ }
+
+ function valid() {
+ return null !== key($this->entries);
+ }
+
+ function key() {
+ return $this->path->getSubPath(current($this->entries));
+ }
+
+ function next() {
+ next($this->entries);
+ }
+
+ function current() {
+ return new RefEntry($this->path, $this->key());//$this->format($this->key());
+ }
+
+ function getParent() {
+ switch ($parent = dirname($this->path->getPathName())) {
+ case ".":
+ case "":
+ return null;
+ default:
+ return new RefEntry($this->path, $parent);
+ }
+ }
+
+ 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
+++ /dev/null
-<?php
-
-namespace controllers;
-
-use http\Controller\Action;
-
-abstract class AppController extends Action
-{
- protected function init() {
- parent::init();
-
- $this->payload->title = "mdref";
- $this->payload->listing = 123;
- }
-}
\ No newline at end of file
+++ /dev/null
-<?php
-
-namespace controllers;
-
-class IndexController extends AppController
-{
- function indexAction() {
- }
-}
+++ /dev/null
-<?php
-
-namespace controllers;
-
-class RefController extends AppController
-{
- function indexAction() {
-
- }
-}
\ No newline at end of file
+++ /dev/null
-index
\ No newline at end of file
+++ /dev/null
-<!doctype html>
-<html>
- <head>
- <meta charset="utf-8">
- <title><?= $title ?></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>
- <div class="sidebar">
- <?= $listing ?>
- </div>
-
- <?= $content ?>
-
- <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")]))?></a></li>
- </ul>
- </footer>
- <script src="index.js"></script>
- </body>
-</html>
--- /dev/null
+RewriteEngine On
+RewriteCond %{REQUEST_FILENAME} -f [OR]
+RewriteCond %{REQUEST_FILENAME} -d [OR]
+RewriteCond %{REQUEST_FILENAME} -l
+RewriteRule ^ - [L]
+RewriteRule ^ index.php [L]
}
.sidebar ul {
margin-left: 1em;
+ margin-top: .5em;
padding: 0;
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
<?php
-while (ob_get_level() && ob_end_clean());
+
+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("controllers", __DIR__ . "/../mdref");
+$loader->add("mdref", ROOT);
use http\Controller;
use http\Controller\Url;
-
-use http\Controller\Observer\Callback;
-use http\Controller\Observer\Params;
-use http\Controller\Observer\Action;
-use http\Controller\Observer\View;
use http\Controller\Observer\Layout;
+use mdref\ExceptionHandler;
+use mdref\Action;
-$url = new Url;
+new ExceptionHandler;
$ctl = new Controller;
-$ctl->setDependency("baseUrl", $url);
-
-$ctl->attach(new Params\Action);
-$ctl->attach(new Action(["controllerPrefix" => "controllers\\"]));
-$ctl->attach(new Callback(function(\http\Controller $ctl) use ($url) {
- $ctl->getPayload()->baseUrl = $url;
-}));
-$ctl->attach(new View(["directory" => __DIR__ . "/../mdref/views"]));
-$ctl->attach(new Layout(["directory" => __DIR__ . "/../mdref/views"]));
-
-$response = $ctl->notify()->getResponse();
-$response->send();
+$ctl->setDependency("baseUrl", new Url)
+ ->attach(new Action)
+ ->attach(new Layout)
+ ->notify()
+ ->getResponse()
+ ->send();
--- /dev/null
+<!doctype html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title><?= $title ?></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>
+ <div class="sidebar">
+ <?= $listing ?>
+ </div>
+
+ <?= $content ?>
+
+ <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")]))?></a></li>
+ </ul>
+ </footer>
+ <script src="index.js"></script>
+ </body>
+</html>