浏览代码

finished TOC feature

Sebastian 7 年之前
父节点
当前提交
7da2060cae
共有 30 个文件被更改,包括 605 次插入276 次删除
  1. 7 7
      composer.lock
  2. 1 1
      content/3_for-developers/01-quick-start.md
  3. 6 0
      content/4_info/15_markdown-test.md
  4. 5 0
      content/4_info/20_Übermaß.md
  5. 59 0
      system/Assets.php
  6. 2 2
      system/Controllers/Controller.php
  7. 6 4
      system/Controllers/PageController.php
  8. 1 1
      system/Events/LoadPagetreeEvent.php
  9. 1 1
      system/Events/RenderPageEvent.php
  10. 149 0
      system/Extensions/ParsedownExtension.php
  11. 4 4
      system/Models/Folder.php
  12. 43 8
      system/Plugin.php
  13. 19 4
      system/Plugins.php
  14. 53 31
      system/system.php
  15. 126 126
      system/vendor/composer/installed.json
  16. 20 4
      system/vendor/slim/slim/Slim/App.php
  17. 1 2
      system/vendor/slim/slim/Slim/DefaultServicesProvider.php
  18. 1 1
      system/vendor/slim/slim/Slim/Exception/ContainerException.php
  19. 1 1
      system/vendor/slim/slim/Slim/Exception/ContainerValueNotFoundException.php
  20. 7 1
      system/vendor/slim/slim/Slim/Exception/InvalidMethodException.php
  21. 1 1
      system/vendor/slim/slim/Slim/Exception/MethodNotAllowedException.php
  22. 1 1
      system/vendor/slim/slim/Slim/Exception/NotFoundException.php
  23. 1 7
      system/vendor/slim/slim/Slim/Handlers/AbstractError.php
  24. 1 13
      system/vendor/slim/slim/Slim/Handlers/Error.php
  25. 28 0
      system/vendor/slim/slim/Slim/Http/Response.php
  26. 2 0
      system/vendor/slim/slim/Slim/Http/Uri.php
  27. 1 31
      system/vendor/slim/slim/Slim/Route.php
  28. 20 0
      themes/typemill/css/style.css
  29. 38 25
      themes/typemill/partials/layout.twig
  30. 二进制
      typemill-1.0.4.zip

+ 7 - 7
composer.lock

@@ -422,16 +422,16 @@
         },
         {
             "name": "slim/slim",
-            "version": "3.9.0",
+            "version": "3.9.2",
             "source": {
                 "type": "git",
                 "url": "https://github.com/slimphp/Slim.git",
-                "reference": "575a8b53a0a489447915029c69680156cd355304"
+                "reference": "4086d0106cf5a7135c69fce4161fe355a8feb118"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/slimphp/Slim/zipball/575a8b53a0a489447915029c69680156cd355304",
-                "reference": "575a8b53a0a489447915029c69680156cd355304",
+                "url": "https://api.github.com/repos/slimphp/Slim/zipball/4086d0106cf5a7135c69fce4161fe355a8feb118",
+                "reference": "4086d0106cf5a7135c69fce4161fe355a8feb118",
                 "shasum": ""
             },
             "require": {
@@ -489,7 +489,7 @@
                 "micro",
                 "router"
             ],
-            "time": "2017-11-04T08:46:46+00:00"
+            "time": "2017-11-26T19:13:09+00:00"
         },
         {
             "name": "slim/twig-view",
@@ -543,7 +543,7 @@
         },
         {
             "name": "symfony/event-dispatcher",
-            "version": "v3.3.12",
+            "version": "v3.3.13",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/event-dispatcher.git",
@@ -606,7 +606,7 @@
         },
         {
             "name": "symfony/yaml",
-            "version": "v2.8.30",
+            "version": "v2.8.31",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/yaml.git",

+ 1 - 1
content/3_for-developers/01-quick-start.md

@@ -11,7 +11,7 @@ You will find all themes in the `theme` folder of TYPEMILL. Change the  theme in
 There is no theme structure. There are only two files that are required: 
 
 - `index.twig`: All content files will be rendered with this template. 
-- `404.twig`: This is the template for a not found message.  
+- `404.twig`: This is the template for a not found message.
 
 There is another optional template:
 

+ 6 - 0
content/4_info/15_markdown-test.md

@@ -2,6 +2,12 @@
 
 This is just a test file to check, if all the html elements created by the markdown syntax are styled correctly. If you create a new template, please use this page to check your css styling.
 
+## Table of Contents
+
+You can create a table of contents with the [TOC] tag written in a separate line. The TOC-Tag will be replaced with a link-list to all headlines of the page.
+
+[TOC]
+
 ## Inline Elements
 
 This is an ordinary paragraph containing only simple text. 

+ 5 - 0
content/4_info/20_Übermaß.md

@@ -0,0 +1,5 @@
+# Übermaß: A simple encoding test
+
+This is just a test for character encoding. If you see the correct german word "Übermaß" in the left navigation, and if you can click the navigation point to get to this page, then everything works fine. 
+
+I still encourage you to use only english characters to name your content files, because many special characters and many languages won't work. I even doubt, that german or european characters will work in special server environments. So you can try it, but if it does not work, you only option is to avoid special characters in your file-names.

+ 59 - 0
system/Assets.php

@@ -0,0 +1,59 @@
+<?php
+
+namespace Typemill;
+
+class Assets
+{
+	protected $baseUrl;
+	
+	public function __construct($baseUrl)
+	{
+		$this->baseUrl		= $baseUrl;
+		$this->JS 			= array();
+		$this->CSS 			= array();
+		$this->inlineJS		= array();
+		$this->inlineCSS	= array();
+	}
+	
+	public function addCSS(string $CSS)
+	{
+		$CSSpath = __DIR__ . '/../plugins' . $CSS;
+
+		if(file_exists($CSSfile))
+		{
+			$CSSfile = $this->baseUrl . '/plugins' . $CSS;
+			$this->CSS[] = '<link rel="stylesheet" href="' . $CSSfile . '" />';
+		}
+	}
+	
+	public function addInlineCSS($CSS)
+	{
+		$this->inlineCSS[] = '<style>' . $CSS . '</style>';
+	}
+	
+	public function addJS(string $JS)
+	{
+		$JSpath = __DIR__ . '/../plugins' . $JS;
+		
+		if(file_exists($JSpath))
+		{
+			$JSfile = $this->baseUrl . '/plugins' . $JS;
+			$this->JS[] = '<script src="' . $JSfile . '"></script>';
+		}
+	}
+
+	public function addInlineJS($JS)
+	{
+		$this->inlineJS[] = '<script>' . $JS . '</script>';
+	}
+	
+	public function renderCSS()
+	{
+		return implode('<br/>', $this->CSS) . implode('<br/>', $this->inlineCSS);
+	}
+	
+	public function renderJS()
+	{
+		return implode('<br/>', $this->JS) . implode('<br/>', $this->inlineJS);
+	}
+}

+ 2 - 2
system/Controllers/Controller.php

@@ -4,7 +4,7 @@ namespace Typemill\Controllers;
 
 /* Use the slim-container */
 use Interop\Container\ContainerInterface;
-use Typemill\Events\RenderSiteEvent;
+use Typemill\Events\RenderPageEvent;
 
 abstract class Controller
 {
@@ -17,7 +17,7 @@ abstract class Controller
 	
 	protected function render($response, $route, $data)
 	{
-		$data = $this->c->dispatcher->dispatch('beforeRenderSite', new RenderSiteEvent($data))->getData();
+		$data = $this->c->dispatcher->dispatch('onPageRendered', new RenderPageEvent($data))->getData();
 		
 		return $this->c->view->render($response, $route, $data);
 	}

+ 6 - 4
system/Controllers/PageController.php

@@ -9,9 +9,10 @@ use Typemill\Models\WriteYaml;
 use \Symfony\Component\Yaml\Yaml;
 use Typemill\Models\VersionCheck;
 use Typemill\Models\Helpers;
-use Typemill\Events\LoadStructureEvent;
+use Typemill\Events\LoadPagetreeEvent;
 use Typemill\Events\LoadMarkdownEvent;
 use Typemill\Events\ParseHtmlEvent;
+use Typemill\Extensions\ParsedownExtension;
 
 class PageController extends Controller
 {
@@ -63,7 +64,7 @@ class PageController extends Controller
 			}
 			
 			/* dispatch event and let others manipulate the structure */
-			$structure = $this->c->dispatcher->dispatch('onStructureLoaded', new LoadStructureEvent($structure))->getData();
+			$structure = $this->c->dispatcher->dispatch('onPagetreeLoaded', new LoadPagetreeEvent($structure))->getData();
 		}
 		catch (Exception $e)
 		{
@@ -122,7 +123,8 @@ class PageController extends Controller
 		$contentMD = $this->c->dispatcher->dispatch('onMarkdownLoaded', new LoadMarkdownEvent($contentMD))->getData();
 		
 		/* initialize parsedown */
-		$Parsedown = new \ParsedownExtra();
+//		$Parsedown = new \ParsedownExtra();
+		$Parsedown = new ParsedownExtension();
 		
 		/* parse markdown-file to html-string */
 		$contentHTML 	= $Parsedown->text($contentMD);
@@ -141,7 +143,7 @@ class PageController extends Controller
 		*/
 		
 		$route = empty($args) && $settings['startpage'] ? '/cover.twig' : '/index.twig';
-				
+
 		$this->render($response, $route, array('navigation' => $structure, 'content' => $contentHTML, 'item' => $item, 'breadcrumb' => $breadcrumb, 'settings' => $settings, 'title' => $title, 'description' => $description, 'base_url' => $base_url ));
 	}
 	

+ 1 - 1
system/Events/LoadStructureEvent.php → system/Events/LoadPagetreeEvent.php

@@ -8,7 +8,7 @@ use Symfony\Component\EventDispatcher\Event;
  * Event for the folder structure.
  */
  
-class LoadStructureEvent extends Event
+class LoadPagetreeEvent extends Event
 {
     protected $data;
 

+ 1 - 1
system/Events/RenderSiteEvent.php → system/Events/RenderPageEvent.php

@@ -8,7 +8,7 @@ use Symfony\Component\EventDispatcher\Event;
  * Event for the pure content.
  */
 
-class RenderSiteEvent extends Event
+class RenderPageEvent extends Event
 {
     protected $data;
 

+ 149 - 0
system/Extensions/ParsedownExtension.php

@@ -0,0 +1,149 @@
+<?php
+
+namespace Typemill\Extensions;
+
+class ParsedownExtension extends \ParsedownExtra
+{
+	function __construct()
+    {
+		parent::__construct();
+		
+        array_unshift($this->BlockTypes['['], 'TableOfContents');
+    }
+	
+    function text($text)
+    {
+        # make sure no definitions are set
+        $this->DefinitionData = array();
+				
+        # standardize line breaks
+        $text = str_replace(array("\r\n", "\r"), "\n", $text);
+
+        # remove surrounding line breaks
+        $text = trim($text, "\n");
+
+        # split text into lines
+        $lines = explode("\n", $text);
+
+        # iterate through lines to identify blocks
+        $markup = $this->lines($lines);
+
+        # trim line breaks
+        $markup = trim($markup, "\n");
+		
+        if (isset($this->DefinitionData['TableOfContents']))
+        {
+			$TOC = $this->buildTOC($this->headlines);
+			
+			$markup = preg_replace('%(<p[^>]*>\[TOC\]</p>)%i', $TOC, $markup);
+        }
+
+        # merge consecutive dl elements
+
+        $markup = preg_replace('/<\/dl>\s+<dl>\s+/', '', $markup);
+
+        # add footnotes
+		
+        if (isset($this->DefinitionData['Footnote']))
+        {
+            $Element = $this->buildFootnoteElement();
+
+            $markup .= "\n" . $this->element($Element);
+        }
+				
+        return $markup;
+    }
+		
+    # TableOfContents
+
+    protected function blockTableOfContents($line, $block)
+    {
+        if ($line['text'] == '[TOC]')
+        {
+			$this->DefinitionData['TableOfContents'] = true;
+        }
+    }
+
+	
+    #
+    # Header
+	
+	private $headlines 			= array();
+	private $headlinesCount 	= 0;
+	
+    protected function blockHeader($Line)
+    {
+        if (isset($Line['text'][1]))
+        {
+            $level = 1;
+
+            while (isset($Line['text'][$level]) and $Line['text'][$level] === '#')
+            {
+                $level ++;
+            }
+
+            if ($level > 6)
+            {
+                return;
+            }
+
+            $text = trim($Line['text'], '# ');
+
+			$this->headlinesCount++;
+			
+			$Block = array(
+				'element' => array(
+					'name' => 'h' . min(6, $level),
+					'text' => $text,
+					'handler' => 'line',
+					'attributes' => array(
+						'id' => "headline-$this->headlinesCount"
+					)
+				)
+			);
+			
+			$this->headlines[]	= array('level' => $level, 'name' => $Block['element']['name'], 'attribute' => $Block['element']['attributes']['id'], 'text' => $text);
+
+            return $Block;
+        }
+    }
+
+	# build the markup for table of contents 
+	
+	protected function buildTOC($headlines)
+	{
+		
+		$markup = '<ul class="TOC">';
+		
+		foreach($headlines as $key => $headline)
+		{
+			$thisLevel = $headline['level'];
+			$prevLevel = $key > 0 ? $headlines[$key-1]['level'] : 1;
+			$nextLevel = isset($headlines[$key+1]) ? $headlines[$key+1]['level'] : 0;
+			
+			if($thisLevel > $prevLevel)
+			{
+				$markup .= '<ul>';
+			}
+			
+			$markup .= '<li class="' . $headline['name'] . '"><a href="#' . $headline['attribute'] . '">' . $headline['text'] . '</a>';
+			
+			if($thisLevel == $nextLevel)
+			{
+				$markup .= '</li>';
+			}
+			elseif($thisLevel > $nextLevel)
+			{
+				while($thisLevel > $nextLevel)
+				{
+					$markup .= '</li></ul>';
+					$thisLevel--;
+				}
+			}			
+		}
+		
+		$markup .= '</ul>';
+		
+		return $markup;
+	}
+}

+ 4 - 4
system/Models/Folder.php

@@ -59,9 +59,9 @@ class Folder
 				$item->index			= array_search('index.md', $name) === false ? false : true;
 				$item->order 			= count($nameParts) > 1 ? array_shift($nameParts) : NULL;
 				$item->name 			= implode(" ",$nameParts);
-				$item->name				= iconv('ISO-8859-15', 'UTF-8', $item->name);
+				$item->name				= iconv(mb_detect_encoding($item->name, mb_detect_order(), true), "UTF-8", $item->name);
 				$item->slug				= implode("-",$nameParts);
-				$item->slug				= URLify::filter(iconv('ISO-8859-15', 'UTF-8', $item->slug));
+				$item->slug				= URLify::filter(iconv(mb_detect_encoding($item->slug, mb_detect_order(), true), "UTF-8", $item->slug));				
 				$item->path				= $fullPath . DIRECTORY_SEPARATOR . $key;
 				$item->urlRelWoF		= $fullSlugWithoutFolder . '/' . $item->slug;
 				$item->urlRel			= $fullSlugWithFolder . '/' . $item->slug;
@@ -85,9 +85,9 @@ class Folder
 				$item->fileType			= $fileType;
 				$item->order 			= count($nameParts) > 1 ? array_shift($nameParts) : NULL;
 				$item->name 			= implode(" ",$nameParts);
-				$item->name				= iconv('ISO-8859-15', 'UTF-8', $item->name);
+				$item->name				= iconv(mb_detect_encoding($item->name, mb_detect_order(), true), "UTF-8", $item->name);				
 				$item->slug				= implode("-",$nameParts);
-				$item->slug				= URLify::filter(iconv('ISO-8859-15', 'UTF-8', $item->slug));
+				$item->slug				= URLify::filter(iconv(mb_detect_encoding($item->slug, mb_detect_order(), true), "UTF-8", $item->slug));				
 				$item->path				= $fullPath . DIRECTORY_SEPARATOR . $name;
 				$item->key				= $iteration;
 				$item->keyPath			= $keyPath . '.' . $iteration;

+ 43 - 8
system/Plugin.php

@@ -7,9 +7,9 @@ use \Symfony\Component\EventDispatcher\EventSubscriberInterface;
 abstract class Plugin implements EventSubscriberInterface
 {
 	
-	protected $app;
+	private $app;
 	
-	protected $container;
+	private $container;
 
     /**
      * Constructor.
@@ -28,16 +28,51 @@ abstract class Plugin implements EventSubscriberInterface
 	{
 		return $this->container['request']->getUri();
 	}
-				
+	
 	protected function getPath()
 	{
-		$route = $this->container['request']->getUri();
-		return $route->getPath();
+		return $this->container['request']->getUri()->getPath();
+	}
+	
+	protected function getDispatcher()
+	{
+		return $this->$dispatcher;
 	}
 	
-	protected function getDispatcher($dispatcher)
+	protected function addTwigGlobal($name, $class)
 	{
-		return $dispatcher;
+		$this->container->view->getEnvironment()->addGlobal($name, $class);
 	}
 	
-}
+	protected function addTwigFilter($name, $filter)
+	{
+		$filter = new \Twig_SimpleFilter($name, $filter);
+		$this->container->view->getEnvironment()->addFilter($filter);
+	}
+	
+	protected function addTwigFunction($name, $function)
+	{
+		$function = new \Twig_SimpleFunction($name, $function);
+		$this->container->view->getEnvironment()->addFunction($function);		
+	}
+	
+	protected function addJS($JS)
+	{
+		$this->container->assets->addJS($JS);
+	}
+
+	protected function addInlineJS($JS)
+	{
+		$this->container->assets->addInlineJS($JS);
+	}
+	
+	protected function addCSS($CSS)
+	{
+		$this->container->assets->addCSS($CSS);		
+	}
+	
+	protected function addInlineCSS($CSS)
+	{
+		$this->container->assets->addInlineCSS($CSS);		
+	}
+}

+ 19 - 4
system/Plugins.php

@@ -39,16 +39,18 @@ class Plugins
 				/* if they are properly formatted, add them to routes array */
 				foreach($pluginRoutes as $pluginRoute)
 				{
-					if($this->checkRouteArray($pluginRoute))
+					if($this->checkRouteArray($routes,$pluginRoute))
 					{
+						$pluginRoute['route'] = strtolower($pluginRoute['route']);
 						$routes[] = $pluginRoute;
 					}
 				}
 			}
 			elseif(is_array($routes))
 			{
-				if($this->checkRouteArray($pluginRoutes))
+				if($this->checkRouteArray($routes,$pluginRoutes))
 				{
+					$pluginRoutes['route'] = strtolower($pluginRoutes['route']);
 					$routes[] = $pluginRoutes;
 				}
 			}
@@ -66,18 +68,31 @@ class Plugins
 		}
 	}
 	
-	private function checkRouteArray($route)
+	private function checkRouteArray($routes,$route)
 	{
 		if( 
 			isset($route['httpMethod']) AND in_array($route['httpMethod'], array('get','post','put','delete','head','patch','options'))
 			AND isset($route['route']) AND is_string($route['route'])
-			AND isset($route['class']) AND is_string($route['class']))
+			AND isset($route['class']) AND is_string($route['class'])
+			AND !$this->in_array_r(strtolower($route['route']),$routes))
 		{
 			return true;
 		}
 		return false;
 	}
 	
+	private function in_array_r($needle, $haystack, $strict = false) 
+	{		
+		foreach ($haystack as $item)
+		{
+			if (($strict ? $item === $needle : $item == $needle) || (is_array($item) && $this->in_array_r($needle, $item, $strict)))
+			{
+				return true;
+			}
+		}
+		return false;		
+	}
+	
 	private function scanPluginFolder()
 	{
 		$pluginsDir = __DIR__ . '/../plugins';

+ 53 - 31
system/system.php

@@ -27,33 +27,6 @@ $app = new \Slim\App($settings);
 
 $container = $app->getContainer();
 
-/************************
-* 	LOAD TWIG VIEW		*
-************************/
-
-$container['view'] = function ($container) use ($settings){
-	$path = array($settings['settings']['themePath'], $settings['settings']['authorPath']);
-	
-    $view = new \Slim\Views\Twig( $path, [
-		'cache' => false,
-		'autoescape' => false
-    ]);
-    
-    // Instantiate and add Slim specific extension
-    $basePath = rtrim(str_ireplace('index.php', '', $container['request']->getUri()->getBasePath()), '/');
-    $view->addExtension(new Slim\Views\TwigExtension($container['router'], $basePath));
-
-	return $view;
-};
-
-/************************
-* 	LOAD FLASH MESSAGES	*
-************************/
-
-$container['flash'] = function () {
-    return new \Slim\Flash\Messages();
-};
-
 /****************************
 * CREATE EVENT DISPATCHER	*
 ****************************/
@@ -71,18 +44,69 @@ $routes = $middleware	= array();
 foreach($pluginClassNames as $pluginClassName)
 {
 	$routes 			= $plugins->getNewRoutes($pluginClassName, $routes);
-	$middleware[]		= $plugins->getNewMiddleware($pluginClassName);
+	$middleware			= $plugins->getNewMiddleware($pluginClassName, $middleware);
 	
 	$dispatcher->addSubscriber(new $pluginClassName($container, $app));	
 }
 
 $dispatcher->dispatch('onPluginsInitialized');	
 
+/******************************
+* ADD DISPATCHER TO CONTAINER *
+******************************/
+
 $container['dispatcher'] = function($container) use ($dispatcher)
 {
 	return $dispatcher;
 };
 
+/******************************
+* ADD FLASH MESSAGES FOR TIWG *
+******************************/
+
+$container['flash'] = function () 
+{
+    return new \Slim\Flash\Messages();
+};
+
+/********************************
+* ADD ASSET-FUNCTION FOR TWIG	*
+********************************/
+
+$container['assets'] = function($c)
+{	
+	return new \Typemill\Assets($c['request']->getUri()->getBaseUrl());
+};
+
+/************************
+* 	LOAD TWIG VIEW		*
+************************/
+
+$container['view'] = function ($container) use ($settings)
+{
+	$path = array($settings['settings']['themePath'], $settings['settings']['authorPath']);
+	
+    $view = new \Slim\Views\Twig( $path, [
+		'cache' => false,
+		'autoescape' => false
+    ]);
+    
+    // Instantiate and add Slim specific extension
+    $basePath = rtrim(str_ireplace('index.php', '', $container['request']->getUri()->getBasePath()), '/');
+    $view->addExtension(new Slim\Views\TwigExtension($container['router'], $basePath));
+	$view['baseUrl'] = $container['request']->getUri()->getBaseUrl();
+	
+	/* add flash messages to all views */
+	$view->getEnvironment()->addGlobal('flash', $container->flash);
+
+	/* add asset-function to all views */
+	$view->getEnvironment()->addGlobal('assets', $container->assets);
+	
+	return $view;
+};
+
+$container->dispatcher->dispatch('onTwigLoaded');
+
 /************************
 * 	ADD MIDDLEWARE		*
 ************************/
@@ -96,7 +120,5 @@ $container['notFoundHandler'] = function($c)
 * 	ADD ROUTES			*
 ************************/
 
-$timer['before router']=microtime(true);
-
 require __DIR__ . '/Routes/api.php';
-require __DIR__ . '/Routes/web.php';
+require __DIR__ . '/Routes/web.php';

+ 126 - 126
system/vendor/composer/installed.json

@@ -232,79 +232,6 @@
             "dependency injection"
         ]
     },
-    {
-        "name": "slim/slim",
-        "version": "3.9.0",
-        "version_normalized": "3.9.0.0",
-        "source": {
-            "type": "git",
-            "url": "https://github.com/slimphp/Slim.git",
-            "reference": "575a8b53a0a489447915029c69680156cd355304"
-        },
-        "dist": {
-            "type": "zip",
-            "url": "https://api.github.com/repos/slimphp/Slim/zipball/575a8b53a0a489447915029c69680156cd355304",
-            "reference": "575a8b53a0a489447915029c69680156cd355304",
-            "shasum": ""
-        },
-        "require": {
-            "container-interop/container-interop": "^1.2",
-            "nikic/fast-route": "^1.0",
-            "php": ">=5.5.0",
-            "pimple/pimple": "^3.0",
-            "psr/container": "^1.0",
-            "psr/http-message": "^1.0"
-        },
-        "provide": {
-            "psr/http-message-implementation": "1.0"
-        },
-        "require-dev": {
-            "phpunit/phpunit": "^4.0",
-            "squizlabs/php_codesniffer": "^2.5"
-        },
-        "time": "2017-11-04T08:46:46+00:00",
-        "type": "library",
-        "installation-source": "dist",
-        "autoload": {
-            "psr-4": {
-                "Slim\\": "Slim"
-            }
-        },
-        "notification-url": "https://packagist.org/downloads/",
-        "license": [
-            "MIT"
-        ],
-        "authors": [
-            {
-                "name": "Rob Allen",
-                "email": "rob@akrabat.com",
-                "homepage": "http://akrabat.com"
-            },
-            {
-                "name": "Josh Lockhart",
-                "email": "hello@joshlockhart.com",
-                "homepage": "https://joshlockhart.com"
-            },
-            {
-                "name": "Gabriel Manricks",
-                "email": "gmanricks@me.com",
-                "homepage": "http://gabrielmanricks.com"
-            },
-            {
-                "name": "Andrew Smith",
-                "email": "a.smith@silentworks.co.uk",
-                "homepage": "http://silentworks.co.uk"
-            }
-        ],
-        "description": "Slim is a PHP micro framework that helps you quickly write simple yet powerful web applications and APIs",
-        "homepage": "https://slimframework.com",
-        "keywords": [
-            "api",
-            "framework",
-            "micro",
-            "router"
-        ]
-    },
     {
         "name": "twig/twig",
         "version": "v1.35.0",
@@ -372,57 +299,6 @@
             "templating"
         ]
     },
-    {
-        "name": "symfony/yaml",
-        "version": "v2.8.30",
-        "version_normalized": "2.8.30.0",
-        "source": {
-            "type": "git",
-            "url": "https://github.com/symfony/yaml.git",
-            "reference": "d819bf267e901727141fe828ae888486fd21236e"
-        },
-        "dist": {
-            "type": "zip",
-            "url": "https://api.github.com/repos/symfony/yaml/zipball/d819bf267e901727141fe828ae888486fd21236e",
-            "reference": "d819bf267e901727141fe828ae888486fd21236e",
-            "shasum": ""
-        },
-        "require": {
-            "php": ">=5.3.9"
-        },
-        "time": "2017-11-05T15:25:56+00:00",
-        "type": "library",
-        "extra": {
-            "branch-alias": {
-                "dev-master": "2.8-dev"
-            }
-        },
-        "installation-source": "dist",
-        "autoload": {
-            "psr-4": {
-                "Symfony\\Component\\Yaml\\": ""
-            },
-            "exclude-from-classmap": [
-                "/Tests/"
-            ]
-        },
-        "notification-url": "https://packagist.org/downloads/",
-        "license": [
-            "MIT"
-        ],
-        "authors": [
-            {
-                "name": "Fabien Potencier",
-                "email": "fabien@symfony.com"
-            },
-            {
-                "name": "Symfony Community",
-                "homepage": "https://symfony.com/contributors"
-            }
-        ],
-        "description": "Symfony Yaml Component",
-        "homepage": "https://symfony.com"
-    },
     {
         "name": "slim/twig-view",
         "version": "2.3.0",
@@ -674,10 +550,134 @@
             "parser"
         ]
     },
+    {
+        "name": "slim/slim",
+        "version": "3.9.2",
+        "version_normalized": "3.9.2.0",
+        "source": {
+            "type": "git",
+            "url": "https://github.com/slimphp/Slim.git",
+            "reference": "4086d0106cf5a7135c69fce4161fe355a8feb118"
+        },
+        "dist": {
+            "type": "zip",
+            "url": "https://api.github.com/repos/slimphp/Slim/zipball/4086d0106cf5a7135c69fce4161fe355a8feb118",
+            "reference": "4086d0106cf5a7135c69fce4161fe355a8feb118",
+            "shasum": ""
+        },
+        "require": {
+            "container-interop/container-interop": "^1.2",
+            "nikic/fast-route": "^1.0",
+            "php": ">=5.5.0",
+            "pimple/pimple": "^3.0",
+            "psr/container": "^1.0",
+            "psr/http-message": "^1.0"
+        },
+        "provide": {
+            "psr/http-message-implementation": "1.0"
+        },
+        "require-dev": {
+            "phpunit/phpunit": "^4.0",
+            "squizlabs/php_codesniffer": "^2.5"
+        },
+        "time": "2017-11-26T19:13:09+00:00",
+        "type": "library",
+        "installation-source": "dist",
+        "autoload": {
+            "psr-4": {
+                "Slim\\": "Slim"
+            }
+        },
+        "notification-url": "https://packagist.org/downloads/",
+        "license": [
+            "MIT"
+        ],
+        "authors": [
+            {
+                "name": "Rob Allen",
+                "email": "rob@akrabat.com",
+                "homepage": "http://akrabat.com"
+            },
+            {
+                "name": "Josh Lockhart",
+                "email": "hello@joshlockhart.com",
+                "homepage": "https://joshlockhart.com"
+            },
+            {
+                "name": "Gabriel Manricks",
+                "email": "gmanricks@me.com",
+                "homepage": "http://gabrielmanricks.com"
+            },
+            {
+                "name": "Andrew Smith",
+                "email": "a.smith@silentworks.co.uk",
+                "homepage": "http://silentworks.co.uk"
+            }
+        ],
+        "description": "Slim is a PHP micro framework that helps you quickly write simple yet powerful web applications and APIs",
+        "homepage": "https://slimframework.com",
+        "keywords": [
+            "api",
+            "framework",
+            "micro",
+            "router"
+        ]
+    },
+    {
+        "name": "symfony/yaml",
+        "version": "v2.8.31",
+        "version_normalized": "2.8.31.0",
+        "source": {
+            "type": "git",
+            "url": "https://github.com/symfony/yaml.git",
+            "reference": "d819bf267e901727141fe828ae888486fd21236e"
+        },
+        "dist": {
+            "type": "zip",
+            "url": "https://api.github.com/repos/symfony/yaml/zipball/d819bf267e901727141fe828ae888486fd21236e",
+            "reference": "d819bf267e901727141fe828ae888486fd21236e",
+            "shasum": ""
+        },
+        "require": {
+            "php": ">=5.3.9"
+        },
+        "time": "2017-11-05T15:25:56+00:00",
+        "type": "library",
+        "extra": {
+            "branch-alias": {
+                "dev-master": "2.8-dev"
+            }
+        },
+        "installation-source": "dist",
+        "autoload": {
+            "psr-4": {
+                "Symfony\\Component\\Yaml\\": ""
+            },
+            "exclude-from-classmap": [
+                "/Tests/"
+            ]
+        },
+        "notification-url": "https://packagist.org/downloads/",
+        "license": [
+            "MIT"
+        ],
+        "authors": [
+            {
+                "name": "Fabien Potencier",
+                "email": "fabien@symfony.com"
+            },
+            {
+                "name": "Symfony Community",
+                "homepage": "https://symfony.com/contributors"
+            }
+        ],
+        "description": "Symfony Yaml Component",
+        "homepage": "https://symfony.com"
+    },
     {
         "name": "symfony/event-dispatcher",
-        "version": "v3.3.12",
-        "version_normalized": "3.3.12.0",
+        "version": "v3.3.13",
+        "version_normalized": "3.3.13.0",
         "source": {
             "type": "git",
             "url": "https://github.com/symfony/event-dispatcher.git",

+ 20 - 4
system/vendor/slim/slim/Slim/App.php

@@ -52,7 +52,7 @@ class App
      *
      * @var string
      */
-    const VERSION = '3.9.0';
+    const VERSION = '3.9.2';
 
     /**
      * Container
@@ -292,11 +292,29 @@ class App
         $response = $this->container->get('response');
 
         try {
+            ob_start();
             $response = $this->process($this->container->get('request'), $response);
         } catch (InvalidMethodException $e) {
             $response = $this->processInvalidMethod($e->getRequest(), $response);
+        } finally {
+            $output = ob_get_clean();
         }
 
+        if (!empty($output) && $response->getBody()->isWritable()) {
+            $outputBuffering = $this->container->get('settings')['outputBuffering'];
+            if ($outputBuffering === 'prepend') {
+                // prepend output buffer content
+                $body = new Http\Body(fopen('php://temp', 'r+'));
+                $body->write($output . $response->getBody());
+                $response = $response->withBody($body);
+            } elseif ($outputBuffering === 'append') {
+                // append output buffer content
+                $response->getBody()->write($output);
+            }
+        }
+
+        $response = $this->finalize($response);
+
         if (!$silent) {
             $this->respond($response);
         }
@@ -374,13 +392,11 @@ class App
             $response = $this->handlePhpError($e, $request, $response);
         }
 
-        $response = $this->finalize($response);
-
         return $response;
     }
 
     /**
-     * Send the response the client
+     * Send the response to the client
      *
      * @param ResponseInterface $response
      */

+ 1 - 2
system/vendor/slim/slim/Slim/DefaultServicesProvider.php

@@ -153,8 +153,7 @@ class DefaultServicesProvider
              */
             $container['errorHandler'] = function ($container) {
                 return new Error(
-                    $container->get('settings')['displayErrorDetails'],
-                    $container->get('settings')['outputBuffering']
+                    $container->get('settings')['displayErrorDetails']
                 );
             };
         }

+ 1 - 1
system/vendor/slim/slim/Slim/Exception/ContainerException.php

@@ -4,7 +4,7 @@
  *
  * @link      https://github.com/slimphp/Slim
  * @copyright Copyright (c) 2011-2017 Josh Lockhart
- * @license   https://github.com/slimphp/Slim/blob/3.x/LICENSE (MIT License)
+ * @license   https://github.com/slimphp/Slim/blob/3.x/LICENSE.md (MIT License)
  */
 namespace Slim\Exception;
 

+ 1 - 1
system/vendor/slim/slim/Slim/Exception/ContainerValueNotFoundException.php

@@ -4,7 +4,7 @@
  *
  * @link      https://github.com/slimphp/Slim
  * @copyright Copyright (c) 2011-2017 Josh Lockhart
- * @license   https://github.com/slimphp/Slim/blob/3.x/LICENSE (MIT License)
+ * @license   https://github.com/slimphp/Slim/blob/3.x/LICENSE.md (MIT License)
  */
 namespace Slim\Exception;
 

+ 7 - 1
system/vendor/slim/slim/Slim/Exception/InvalidMethodException.php

@@ -1,5 +1,11 @@
 <?php
-
+/**
+ * Slim Framework (https://slimframework.com)
+ *
+ * @link      https://github.com/slimphp/Slim
+ * @copyright Copyright (c) 2011-2017 Josh Lockhart
+ * @license   https://github.com/slimphp/Slim/blob/3.x/LICENSE.md (MIT License)
+ */
 namespace Slim\Exception;
 
 use Psr\Http\Message\ServerRequestInterface;

+ 1 - 1
system/vendor/slim/slim/Slim/Exception/MethodNotAllowedException.php

@@ -4,7 +4,7 @@
  *
  * @link      https://github.com/slimphp/Slim
  * @copyright Copyright (c) 2011-2017 Josh Lockhart
- * @license   https://github.com/slimphp/Slim/blob/3.x/LICENSE (MIT License)
+ * @license   https://github.com/slimphp/Slim/blob/3.x/LICENSE.md (MIT License)
  */
 namespace Slim\Exception;
 

+ 1 - 1
system/vendor/slim/slim/Slim/Exception/NotFoundException.php

@@ -4,7 +4,7 @@
  *
  * @link      https://github.com/slimphp/Slim
  * @copyright Copyright (c) 2011-2017 Josh Lockhart
- * @license   https://github.com/slimphp/Slim/blob/3.x/LICENSE (MIT License)
+ * @license   https://github.com/slimphp/Slim/blob/3.x/LICENSE.md (MIT License)
  */
 namespace Slim\Exception;
 

+ 1 - 7
system/vendor/slim/slim/Slim/Handlers/AbstractError.php

@@ -18,20 +18,14 @@ abstract class AbstractError extends AbstractHandler
      */
     protected $displayErrorDetails;
 
-    /**
-     * @var bool|string
-     */
-    protected $outputBuffering;
-
     /**
      * Constructor
      *
      * @param bool $displayErrorDetails Set to true to display full details
      */
-    public function __construct($displayErrorDetails = false, $outputBuffering = false)
+    public function __construct($displayErrorDetails = false)
     {
         $this->displayErrorDetails = (bool) $displayErrorDetails;
-        $this->outputBuffering = $outputBuffering;
     }
 
     /**

+ 1 - 13
system/vendor/slim/slim/Slim/Handlers/Error.php

@@ -55,19 +55,7 @@ class Error extends AbstractError
         $this->writeToErrorLog($exception);
 
         $body = new Body(fopen('php://temp', 'r+'));
-
-        if ($this->outputBuffering === 'prepend') {
-            // prepend output buffer content
-            $body->write(ob_get_clean() . $output);
-        } elseif ($this->outputBuffering === 'append') {
-            // append output buffer content
-            $body->write($output . ob_get_clean());
-        } else {
-            // outputBuffering is false or some other unknown setting
-            // delete anything in the output buffer.
-            ob_get_clean();
-            $body->write($output);
-        }
+        $body->write($output);
 
         return $response
                 ->withStatus(500)

+ 28 - 0
system/vendor/slim/slim/Slim/Http/Response.php

@@ -249,6 +249,34 @@ class Response extends Message implements ResponseInterface
         return '';
     }
 
+    /*******************************************************************************
+     * Headers
+     ******************************************************************************/
+
+    /**
+     * Return an instance with the provided value replacing the specified header.
+     *
+     * If a Location header is set and the status code is 200, then set the status
+     * code to 302 to mimic what PHP does. See https://github.com/slimphp/Slim/issues/1730
+     *
+     * @param string $name Case-insensitive header field name.
+     * @param string|string[] $value Header value(s).
+     * @return static
+     * @throws \InvalidArgumentException for invalid header names or values.
+     */
+    public function withHeader($name, $value)
+    {
+        $clone = clone $this;
+        $clone->headers->set($name, $value);
+
+        if ($clone->getStatusCode() === 200 && strtolower($name) === 'location') {
+            $clone = $clone->withStatus(302);
+        }
+
+        return $clone;
+    }
+
+
     /*******************************************************************************
      * Body
      ******************************************************************************/

+ 2 - 0
system/vendor/slim/slim/Slim/Http/Uri.php

@@ -381,6 +381,8 @@ class Uri implements UriInterface
         $clone->user = $this->filterUserInfo($user);
         if ($clone->user) {
             $clone->password = $password ? $this->filterUserInfo($password) : '';
+        } else {
+            $clone->password = '';
         }
 
         return $clone;

+ 1 - 31
system/vendor/slim/slim/Slim/Route.php

@@ -8,12 +8,9 @@
  */
 namespace Slim;
 
-use Exception;
-use Throwable;
 use InvalidArgumentException;
 use Psr\Http\Message\ServerRequestInterface;
 use Psr\Http\Message\ResponseInterface;
-use Slim\Exception\SlimException;
 use Slim\Handlers\Strategies\RequestResponse;
 use Slim\Interfaces\InvocationStrategyInterface;
 use Slim\Interfaces\RouteInterface;
@@ -335,22 +332,7 @@ class Route extends Routable implements RouteInterface
         /** @var InvocationStrategyInterface $handler */
         $handler = isset($this->container) ? $this->container->get('foundHandler') : new RequestResponse();
 
-        // invoke route callable
-        if ($this->outputBuffering === false) {
-            $newResponse = $handler($this->callable, $request, $response, $this->arguments);
-        } else {
-            try {
-                ob_start();
-                $newResponse = $handler($this->callable, $request, $response, $this->arguments);
-                $output = ob_get_clean();
-            // @codeCoverageIgnoreStart
-            } catch (Throwable $e) {
-                throw $e;
-            // @codeCoverageIgnoreEnd
-            } catch (Exception $e) {
-                throw $e;
-            }
-        }
+        $newResponse = $handler($this->callable, $request, $response, $this->arguments);
 
         if ($newResponse instanceof ResponseInterface) {
             // if route callback returns a ResponseInterface, then use it
@@ -362,18 +344,6 @@ class Route extends Routable implements RouteInterface
             }
         }
 
-        if (!empty($output) && $response->getBody()->isWritable()) {
-            if ($this->outputBuffering === 'prepend') {
-                // prepend output buffer content
-                $body = new Http\Body(fopen('php://temp', 'r+'));
-                $body->write($output . $response->getBody());
-                $response = $response->withBody($body);
-            } elseif ($this->outputBuffering === 'append') {
-                // append output buffer content
-                $response->getBody()->write($output);
-            }
-        }
-
         return $response;
     }
 }

+ 20 - 0
themes/typemill/css/style.css

@@ -426,6 +426,26 @@ cite{}
 abbr{}
 hr{}
 
+ul.TOC,.TOC ul{
+	list-style: none;
+	padding-left: 0px;
+	margin-left: 0px;
+}
+ul.TOC{
+	background: #f9f8f6;
+	width: 100%;
+	padding: 20px;
+	box-sizing:border-box;
+}
+li.h1{
+	font-weight: 700;
+}
+li.h2, li.h3, li.h4, li.h5, li.h6
+{
+	font-weight: 400;
+	padding-left: 25px;	
+}
+
 /************************
 *  		GitHub Ribbon	*
 ************************/

+ 38 - 25
themes/typemill/partials/layout.twig

@@ -17,10 +17,15 @@
 		<link rel="icon" type="image/png" href="{{ base_url }}/themes/typemill/img/favicon-32x32.png" sizes="32x32" />
 		<link rel="icon" type="image/png" href="{{ base_url }}/themes/typemill/img/favicon-16x16.png" sizes="16x16" />
 
-		<link rel="stylesheet" href="{{ base_url }}/themes/typemill/css/fontello/css/fontello.css" />
-		<link rel="stylesheet" href="{{ base_url }}/themes/typemill/css/normalize.css" />
-		<link rel="stylesheet" href="{{ base_url }}/themes/typemill/js/highlight/styles/default.css" />
-		<link rel="stylesheet" href="{{ base_url }}/themes/typemill/css/style.css" />
+		{% block stylesheets %}
+			<link rel="stylesheet" href="{{ base_url }}/themes/typemill/css/fontello/css/fontello.css" />
+			<link rel="stylesheet" href="{{ base_url }}/themes/typemill/css/normalize.css" />
+			<link rel="stylesheet" href="{{ base_url }}/themes/typemill/js/highlight/styles/default.css" />
+			<link rel="stylesheet" href="{{ base_url }}/themes/typemill/css/style.css" />
+			
+			{{ assets.renderCSS() }}
+			
+		{% endblock %}		
 	</head>
 	<body>
 		<div class="main">
@@ -29,6 +34,7 @@
 			</header>
 			<article>
 				{% block content %}{% endblock %}
+				<small>{{content|rot13}}</small>
 			</article>
 			<aside id="navigation" class="close">
 				<nav>
@@ -36,30 +42,37 @@
 				</nav>
 			</aside>
 			<footer>
+				<p>hello {{ myName() }}</p>
 				{% include 'partials/footer.twig' %}
 			</footer>
 		</div>
-		<script src="{{ base_url }}/themes/typemill/js/highlight/highlight.pack.js"></script>
-		<script>hljs.initHighlightingOnLoad();</script>
-		<script>
-			var menu = document.getElementById("menu"),
-				navi = document.getElementById("navigation");
+		{% block javascripts %}
+		
+			<script src="{{ base_url }}/themes/typemill/js/highlight/highlight.pack.js"></script>
+			<script>hljs.initHighlightingOnLoad();</script>
+			<script>
+				var menu = document.getElementById("menu"),
+					navi = document.getElementById("navigation");
+				
+				if(menu)
+				{
+					menu.addEventListener("click", function(){
+						if(navi.className == "close")
+						{
+							navi.className = "open";
+							menu.className = "active";
+						}
+						else
+						{
+							navi.className = "close";
+							menu.className = "";
+						}
+					});
+				}
+			</script>
 			
-			if(menu)
-			{
-				menu.addEventListener("click", function(){
-					if(navi.className == "close")
-					{
-						navi.className = "open";
-						menu.className = "active";
-					}
-					else
-					{
-						navi.className = "close";
-						menu.className = "";
-					}
-				});
-			}
-		</script>
+			{{ assets.renderJS() }}
+		
+		{% endblock %}		
 	</body>
 </html>

二进制
typemill-1.0.4.zip