Explorar o código

Version 1.2.15: Beautiful Math Refactored

Trendschau %!s(int64=6) %!d(string=hai) anos
pai
achega
3fce3a5c61
Modificáronse 36 ficheiros con 723 adicións e 249 borrados
  1. 1 1
      cache/lastCache.txt
  2. 17 8
      content/00-Welcome/03-Markdown-Test.md
  3. 0 0
      content/baseItem.txt
  4. 1 1
      content/index.md
  5. BIN=BIN
      media/live/SYKMLbMfD_M-live.jpeg
  6. BIN=BIN
      media/live/c-PyqAz6XyU-live.jpeg
  7. BIN=BIN
      media/original/SYKMLbMfD_M-original.jpeg
  8. BIN=BIN
      media/original/c-PyqAz6XyU-original.jpeg
  9. 6 3
      plugins/math/math.php
  10. 1 1
      plugins/math/math.yaml
  11. 0 0
      plugins/math/public/katex.min.css
  12. 0 0
      plugins/math/public/katex.min.js
  13. 0 10
      settings/README.md
  14. 22 1
      system/Controllers/ContentApiController.php
  15. 13 11
      system/Controllers/ContentBackendController.php
  16. 31 0
      system/Controllers/ContentController.php
  17. 4 4
      system/Controllers/PageController.php
  18. 6 2
      system/Controllers/SettingsController.php
  19. 2 2
      system/Controllers/SetupController.php
  20. 91 120
      system/Extensions/ParsedownExtension.php
  21. 165 0
      system/Extensions/ParsedownMath.php
  22. 39 11
      system/Models/Folder.php
  23. 1 0
      system/Routes/Api.php
  24. 36 15
      system/Settings.php
  25. 1 1
      system/author/auth/welcome.twig
  26. 30 10
      system/author/css/style.css
  27. 2 1
      system/author/editor/editor-blox.twig
  28. 57 30
      system/author/js/lazy-video.js
  29. 138 3
      system/author/js/vue-blox.js
  30. 34 1
      system/author/js/vue-navi.js
  31. 3 0
      system/author/js/vue-publishcontroller.js
  32. 6 0
      system/author/layouts/layoutBlox.twig
  33. 6 5
      system/author/partials/editorNavi.twig
  34. 5 5
      system/system.php
  35. 3 1
      themes/typemill/css/style.css
  36. 2 2
      themes/typemill/partials/layout.twig

+ 1 - 1
cache/lastCache.txt

@@ -1 +1 @@
-1558126279
+1559660578

+ 17 - 8
content/00-Welcome/03-Markdown-Test.md

@@ -263,7 +263,7 @@ Let us create some `<?php inlineCode(); ?>` and now let us check, if a codeblock
 
 
 ````
 ````
 Use four apostroph like this:  
 Use four apostroph like this:  
-\````
+\````
 <?php
 <?php
 	$welcome = 'Hello World!';
 	$welcome = 'Hello World!';
 	echo $welcome;
 	echo $welcome;
@@ -276,21 +276,30 @@ Use four apostroph like this:
 Please activate the math-plugin to use mathematical expressions with LaTeX syntax. You can choose between MathJax or the newer KaTeX library. MathJax is included from a CDN, KaTeX is included in the plugin. So if you don't want to fetch code from a CDN, use KaTeX instead. The markdown syntax in TYPEMILL is the same for both libraries.
 Please activate the math-plugin to use mathematical expressions with LaTeX syntax. You can choose between MathJax or the newer KaTeX library. MathJax is included from a CDN, KaTeX is included in the plugin. So if you don't want to fetch code from a CDN, use KaTeX instead. The markdown syntax in TYPEMILL is the same for both libraries.
 
 
 ````
 ````
-Use inline LaTeX  ``x = \int_{0^1}^1(-b \pm \sqrt{b^2-4ac})/(2a)`` with two backtipps like this.
+Write inline math with \(...\) or $...$ syntax.
+inline $x = \int_{0^1}^1(-b \pm \sqrt{b^2-4ac})/(2a)$ math
+inline \(x = \int_{0^1}^1(-b \pm \sqrt{b^2-4ac})/(2a)\) math
 ````
 ````
 
 
-Use inline LaTeX ``x = \int_{0^1}^1(-b \pm \sqrt{b^2-4ac})/(2a)`` like this. 
+inline $x = \int_{0^1}^1(-b \pm \sqrt{b^2-4ac})/(2a)$ math
+
+inline \(x = \int_{0^1}^1(-b \pm \sqrt{b^2-4ac})/(2a)\) math
 
 
 ````
 ````
-Or specify latex sytnax for a code-block like this:  
-​````latex
+Write display math with $$...$$ or \[...\] syntax.  
+$$
 x = \int_{0^1}^1(-b \pm \sqrt{b^2-4ac})/(2a)
 x = \int_{0^1}^1(-b \pm \sqrt{b^2-4ac})/(2a)
-​````  
+$$
+\[
+x = \int_{0^1}^1(-b \pm \sqrt{b^2-4ac})/(2a)
+\]
 ````
 ````
 
 
-​````latex
+$$
 x = \int_{0^1}^1(-b \pm \sqrt{b^2-4ac})/(2a)
 x = \int_{0^1}^1(-b \pm \sqrt{b^2-4ac})/(2a)
-​````
+$$
+
+Das war es dann aber auch.
 
 
 [^1]: Thank you for scrolling.
 [^1]: Thank you for scrolling.
 [^2]: This is the end of the page.
 [^2]: This is the end of the page.

+ 0 - 0
content/baseItem.txt


+ 1 - 1
content/index.md

@@ -1,4 +1,4 @@
 # Typemill
 # Typemill
 
 
-*Typemill is a user-friendly and lightweight open source CMS for publishing text-works like prose, lyrics, manuals, documentations, studies and more. Just download and start.*
+*Typemill is a user-friendly and lightweight open source CMS for publishing text-works like prose, lyrics, manuals, documentations, studies and more. Just download and start.* edkit
 
 

BIN=BIN
media/live/SYKMLbMfD_M-live.jpeg


BIN=BIN
media/live/c-PyqAz6XyU-live.jpeg


BIN=BIN
media/original/SYKMLbMfD_M-original.jpeg


BIN=BIN
media/original/c-PyqAz6XyU-original.jpeg


+ 6 - 3
plugins/math/math.php

@@ -37,8 +37,11 @@ class Math extends Plugin
 			$this->addJS('/math/public/auto-render.min.js');
 			$this->addJS('/math/public/auto-render.min.js');
 			$this->addCSS('/math/public/katex.min.css');
 			$this->addCSS('/math/public/katex.min.css');
 
 
-			/* initialize autorendering of page */
-			$this->addInlineJs('renderMathInElement(document.body);');
-		}		
+			/* initialize autorendering of page only in frontend */
+			if (strpos($this->getPath(), 'tm/content') === false) 
+			{
+				$this->addInlineJs('renderMathInElement(document.body);');
+			}
+		}
 	}
 	}
 }
 }

+ 1 - 1
plugins/math/math.yaml

@@ -1,5 +1,5 @@
 name: Math
 name: Math
-version: 1.0.1
+version: 1.0.2
 description: Adds support for katex and mathjax.
 description: Adds support for katex and mathjax.
 author: Sebastian Schürmanns
 author: Sebastian Schürmanns
 homepage: https://mathjax.org/
 homepage: https://mathjax.org/

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 0
plugins/math/public/katex.min.css


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 0
plugins/math/public/katex.min.js


+ 0 - 10
settings/README.md

@@ -1,10 +0,0 @@
-Settings are generated during the setup of the system.
-
-If you are a developer, you can manually add the settings
-
-````
-displayErrorDetails: true
-````
-
-This will display the php errors during the developement process. Do not forget to disable the settings for the live environment (delete it or set it to false).
-

+ 22 - 1
system/Controllers/ContentApiController.php

@@ -502,7 +502,28 @@ class ContentApiController extends ContentController
 
 
 		return $response->withJson(array('data' => $this->structure, 'errors' => false, 'url' => $url));
 		return $response->withJson(array('data' => $this->structure, 'errors' => false, 'url' => $url));
 	}
 	}
-	
+
+	public function getNavigation(Request $request, Response $response, $args)
+	{
+		# get params from call
+		$this->params 	= $request->getParams();
+		$this->uri 		= $request->getUri();
+
+		# set structure
+		if(!$this->setStructure($draft = true, $cache = false)){ return $response->withJson(array('data' => false, 'errors' => $this->errors, 'url' => $url), 404); }
+
+		# set information for homepage
+		$this->setHomepage();
+
+		# get item for url and set it active again
+		if(isset($this->params['url']))
+		{
+			$activeItem = Folder::getItemForUrl($this->structure, $this->params['url']);
+		}
+
+		return $response->withJson(array('data' => $this->structure, 'homepage' => $this->homepage, 'errors' => false));
+	}
+
 	public function getArticleMarkdown(Request $request, Response $response, $args)
 	public function getArticleMarkdown(Request $request, Response $response, $args)
 	{
 	{
 		/* get params from call */
 		/* get params from call */

+ 13 - 11
system/Controllers/ContentBackendController.php

@@ -23,10 +23,13 @@ class ContentBackendController extends ContentController
 		# get params from call
 		# get params from call
 		$this->uri 		= $request->getUri();
 		$this->uri 		= $request->getUri();
 		$this->params	= isset($args['params']) ? ['url' => $this->uri->getBasePath() . '/' . $args['params']] : ['url' => $this->uri->getBasePath()];
 		$this->params	= isset($args['params']) ? ['url' => $this->uri->getBasePath() . '/' . $args['params']] : ['url' => $this->uri->getBasePath()];
-				
+		
 		# set structure
 		# set structure
 		if(!$this->setStructure($draft = true)){ return $this->renderIntern404($response, array( 'navigation' => true, 'content' => $this->errors )); }
 		if(!$this->setStructure($draft = true)){ return $this->renderIntern404($response, array( 'navigation' => true, 'content' => $this->errors )); }
 		
 		
+		# set information for homepage
+		$this->setHomepage();
+
 		# set item
 		# set item
 		if(!$this->setItem()){ return $this->renderIntern404($response, array( 'navigation' => $this->structure, 'settings' => $this->settings, 'content' => $this->errors )); }
 		if(!$this->setItem()){ return $this->renderIntern404($response, array( 'navigation' => $this->structure, 'settings' => $this->settings, 'content' => $this->errors )); }
 		
 		
@@ -72,11 +75,11 @@ class ContentBackendController extends ContentController
 			}
 			}
 		}
 		}
 
 
-		return $this->render($response, 'editor/editor-raw.twig', array('navigation' => $this->structure, 'title' => $title, 'content' => $content, 'item' => $this->item, 'settings' => $this->settings ));
+		return $this->render($response, 'editor/editor-raw.twig', array('navigation' => $this->structure, 'homepage' => $this->homepage, 'title' => $title, 'content' => $content, 'item' => $this->item, 'settings' => $this->settings ));
 	}
 	}
 	
 	
 	/**
 	/**
-	* Show Content for raw editor
+	* Show Content for blox editor
 	* 
 	* 
 	* @param obj $request the slim request object
 	* @param obj $request the slim request object
 	* @param obj $response the slim response object
 	* @param obj $response the slim response object
@@ -85,20 +88,19 @@ class ContentBackendController extends ContentController
 	
 	
 	public function showBlox(Request $request, Response $response, $args)
 	public function showBlox(Request $request, Response $response, $args)
 	{
 	{
-		
 		# get params from call
 		# get params from call
 		$this->uri 		= $request->getUri();
 		$this->uri 		= $request->getUri();
 		$this->params	= isset($args['params']) ? ['url' => $this->uri->getBasePath() . '/' . $args['params']] : ['url' => $this->uri->getBasePath()];
 		$this->params	= isset($args['params']) ? ['url' => $this->uri->getBasePath() . '/' . $args['params']] : ['url' => $this->uri->getBasePath()];
-		
+
 		# set structure
 		# set structure
 		if(!$this->setStructure($draft = true)){ return $this->renderIntern404($response, array( 'navigation' => true, 'content' => $this->errors )); }
 		if(!$this->setStructure($draft = true)){ return $this->renderIntern404($response, array( 'navigation' => true, 'content' => $this->errors )); }
-		
+
+		# set information for homepage
+		$this->setHomepage();
+
 		# set item
 		# set item
 		if(!$this->setItem()){ return $this->renderIntern404($response, array( 'navigation' => $this->structure, 'settings' => $this->settings, 'content' => $this->errors )); }
 		if(!$this->setItem()){ return $this->renderIntern404($response, array( 'navigation' => $this->structure, 'settings' => $this->settings, 'content' => $this->errors )); }
-		
-		# get the breadcrumb (here we need it only to mark the actual item active in navigation)
-		$breadcrumb = isset($this->item->keyPathArray) ? Folder::getBreadcrumb($this->structure, $this->item->keyPathArray) : false;
-		
+
 		# set the status for published and drafted
 		# set the status for published and drafted
 		$this->setPublishStatus();
 		$this->setPublishStatus();
 		
 		
@@ -148,7 +150,7 @@ class ContentBackendController extends ContentController
 			unset($content[0]);			
 			unset($content[0]);			
 		}
 		}
 
 
-		return $this->render($response, 'editor/editor-blox.twig', array('navigation' => $this->structure, 'title' => $title, 'content' => $content, 'item' => $this->item, 'settings' => $this->settings ));
+		return $this->render($response, 'editor/editor-blox.twig', array('navigation' => $this->structure, 'homepage' => $this->homepage, 'title' => $title, 'content' => $content, 'item' => $this->item, 'settings' => $this->settings ));
 	}
 	}
 	
 	
 	public function showEmpty(Request $request, Response $response, $args)
 	public function showEmpty(Request $request, Response $response, $args)

+ 31 - 0
system/Controllers/ContentController.php

@@ -36,6 +36,9 @@ abstract class ContentController
 	# holds the name of the structure-file without drafts for live site 
 	# holds the name of the structure-file without drafts for live site 
 	protected $structureLiveName;
 	protected $structureLiveName;
 	
 	
+	# holds informations about the homepage
+	protected $homepage;
+
 	# hold the page-item as an object
 	# hold the page-item as an object
 	protected $item;
 	protected $item;
 	
 	
@@ -188,6 +191,34 @@ abstract class ContentController
 		return true;
 		return true;
 	}
 	}
 
 
+	protected function setHomepage()
+	{
+		$contentFolder = Folder::scanFolderFlat($this->settings['rootPath'] . $this->settings['contentFolder']);
+
+		if(array_search('index.md', $contentFolder))
+		{
+			$md = true;
+			$status = 'published';
+		}
+		if(array_search('index.txt', $contentFolder))
+		{
+			$txt = true;
+			$status = 'unpublished';
+		}
+		if(isset($txt) && isset($md))
+		{
+			$status = 'modified';
+		}
+
+		$active = false;
+		if($this->params['url'] == '/' || $this->params['url'] == $this->uri->getBasePath() )
+		{
+			$active = 'active';
+		}
+
+		$this->homepage = ['status' => $status, 'active' => $active];
+	}
+
 	protected function setItem()
 	protected function setItem()
 	{
 	{
 		# if it is the homepage
 		# if it is the homepage

+ 4 - 4
system/Controllers/PageController.php

@@ -103,7 +103,7 @@ class PageController extends Controller
 			$item = $this->c->dispatcher->dispatch('onItemLoaded', new OnItemLoaded($item))->getData();
 			$item = $this->c->dispatcher->dispatch('onItemLoaded', new OnItemLoaded($item))->getData();
 			
 			
 			/* check if url is a folder. If so, check if there is an index-file in that folder */
 			/* check if url is a folder. If so, check if there is an index-file in that folder */
-			if($item->elementType == 'folder' && $item->index)
+			if($item->elementType == 'folder')
 			{
 			{
 				$filePath = $pathToContent . $item->path . DIRECTORY_SEPARATOR . 'index.md';
 				$filePath = $pathToContent . $item->path . DIRECTORY_SEPARATOR . 'index.md';
 			}
 			}
@@ -126,7 +126,7 @@ class PageController extends Controller
 		
 		
 		/* initialize parsedown */
 		/* initialize parsedown */
 		$parsedown 		= new ParsedownExtension();
 		$parsedown 		= new ParsedownExtension();
-
+		
 		/* set safe mode to escape javascript and html in markdown */
 		/* set safe mode to escape javascript and html in markdown */
 		$parsedown->setSafeMode(true);
 		$parsedown->setSafeMode(true);
 
 
@@ -136,7 +136,7 @@ class PageController extends Controller
 		
 		
 		/* get the first image from content array */
 		/* get the first image from content array */
 		$firstImage		= $this->getFirstImage($contentArray);
 		$firstImage		= $this->getFirstImage($contentArray);
-		
+
 		$itemUrl 		= isset($item->urlRel) ? $item->urlRel : false;
 		$itemUrl 		= isset($item->urlRel) ? $item->urlRel : false;
 		
 		
 		/* parse markdown-content-array to content-string */
 		/* parse markdown-content-array to content-string */
@@ -175,7 +175,7 @@ class PageController extends Controller
 		}
 		}
 		
 		
 		$route = empty($args) && $settings['startpage'] ? '/cover.twig' : '/index.twig';
 		$route = empty($args) && $settings['startpage'] ? '/cover.twig' : '/index.twig';
-		
+
 		return $this->render($response, $route, array('navigation' => $structure, 'content' => $contentHTML, 'item' => $item, 'breadcrumb' => $breadcrumb, 'settings' => $settings, 'title' => $title, 'description' => $description, 'base_url' => $base_url, 'image' => $firstImage ));
 		return $this->render($response, $route, array('navigation' => $structure, 'content' => $contentHTML, 'item' => $item, 'breadcrumb' => $breadcrumb, 'settings' => $settings, 'title' => $title, 'description' => $description, 'base_url' => $base_url, 'image' => $firstImage ));
 	}
 	}
 
 

+ 6 - 2
system/Controllers/SettingsController.php

@@ -216,7 +216,7 @@ class SettingsController extends Controller
 			$uri 			= $request->getUri();
 			$uri 			= $request->getUri();
 			$base_url		= $uri->getBaseUrl();
 			$base_url		= $uri->getBaseUrl();
 
 
-			# security, users should not be able to fake post with settings from other typemill pages.
+			# users should not be able to fake post with settings from other typemill pages.
 			if(!isset($referer[0]) OR $referer[0] !== $base_url . '/tm/themes' )
 			if(!isset($referer[0]) OR $referer[0] !== $base_url . '/tm/themes' )
 			{
 			{
 				$this->c->flash->addMessage('error', 'illegal referer');
 				$this->c->flash->addMessage('error', 'illegal referer');
@@ -232,7 +232,11 @@ class SettingsController extends Controller
 			
 			
 			if(isset($themeSettings['settings']['images']))
 			if(isset($themeSettings['settings']['images']))
 			{	
 			{	
-				$userSettings 	= ['images' => $themeSettings['settings']['images']];
+				# get the default settings
+				$defaultSettings = \Typemill\Settings::getDefaultSettings();
+				
+				# merge the default image settings with the theme image settings, delete all others (image settings from old theme)
+				$userSettings['images'] = array_merge($defaultSettings['images'], $themeSettings['settings']['images']);
 			}
 			}
 			
 			
 			/* set theme name and delete theme settings from user settings for the case, that the new theme has no settings */
 			/* set theme name and delete theme settings from user settings for the case, that the new theme has no settings */

+ 2 - 2
system/Controllers/SetupController.php

@@ -54,8 +54,8 @@ class SetupController extends Controller
 					/* login user */
 					/* login user */
 					$user->login($username);
 					$user->login($username);
 
 
-					/* store updated settings */
-					\Typemill\Settings::createSettings(array('setup' => false));
+					# create initial settings file
+					\Typemill\Settings::createSettings();
 					
 					
 					return $response->withRedirect($this->c->router->pathFor('setup.welcome'));
 					return $response->withRedirect($this->c->router->pathFor('setup.welcome'));
 				}
 				}

+ 91 - 120
system/Extensions/ParsedownExtension.php

@@ -10,14 +10,19 @@ class ParsedownExtension extends \ParsedownExtra
     {
     {
 		parent::__construct();
 		parent::__construct();
 
 
-		# mathjax support
-        $this->InlineTypes['`'][] = 'MathJaxLaTeX';
-        $this->BlockTypes['`'][] = 'FencedMathJaxLaTeX';
-		
+        # math support
+        $this->BlockTypes['\\'][] = 'Math';
+        $this->BlockTypes['$'][] = 'Math';
+        
+        $this->InlineTypes['\\'][] = 'Math';
+        $this->InlineTypes['$'][] = 'Math';
+        $this->inlineMarkerList .= '\\';
+        $this->inlineMarkerList .= '$';
+
 		# table of content support
 		# table of content support
         array_unshift($this->BlockTypes['['], 'TableOfContents');
         array_unshift($this->BlockTypes['['], 'TableOfContents');
     }
     }
-		
+	
 	public function text($text)
 	public function text($text)
 	{
 	{
         $Elements = $this->textElements($text);
         $Elements = $this->textElements($text);
@@ -72,7 +77,7 @@ class ParsedownExtension extends \ParsedownExtra
 
 
         return $footnotes;
         return $footnotes;
     }
     }
-			
+
     # TableOfContents
     # TableOfContents
 
 
     protected function blockTableOfContents($line, $block)
     protected function blockTableOfContents($line, $block)
@@ -125,8 +130,8 @@ class ParsedownExtension extends \ParsedownExtra
         }
         }
     }
     }
 	
 	
-	# build the markup for table of contents 
-	
+    # build the markup for table of contents 
+    
 	public function buildTOC($headlines)
 	public function buildTOC($headlines)
 	{
 	{
 		$markup = '<ul class="TOC">';
 		$markup = '<ul class="TOC">';
@@ -165,40 +170,23 @@ class ParsedownExtension extends \ParsedownExtra
 
 
     #
     #
     # Footnote Marker
     # Footnote Marker
+    # add absolute url
 
 
     protected function inlineFootnoteMarker($Excerpt)
     protected function inlineFootnoteMarker($Excerpt)
     {
     {
-        if (preg_match('/^\[\^(.+?)\]/', $Excerpt['text'], $matches))
-        {
-            $name = $matches[1];
 
 
-            if ( ! isset($this->DefinitionData['Footnote'][$name]))
-            {
-                return;
-            }
+        $element = parent::inlineFootnoteMarker($Excerpt);
 
 
-            $this->DefinitionData['Footnote'][$name]['count'] ++;
-
-            if ( ! isset($this->DefinitionData['Footnote'][$name]['number']))
-            {
-                $this->DefinitionData['Footnote'][$name]['number'] = ++ $this->footnoteCount; # » &
-            }
+        if ( ! isset($element))
+        {
+            return null;
+        }
+   
+        $href = $element['element']['element']['attributes']['href'];
 
 
-            $Element = array(
-                'name' => 'sup',
-                'attributes' => array('id' => 'fnref'.$this->DefinitionData['Footnote'][$name]['count'].':'.$name),
-                'element' => array(
-                    'name' => 'a',
-                    'attributes' => array('href' => $this->relurl . '#fn:' . $name, 'class' => 'footnote-ref'),
-                    'text' => $this->DefinitionData['Footnote'][$name]['number'],
-                ),
-            );
+        $element['element']['element']['attributes']['href'] = $this->relurl . $href;
 
 
-            return array(
-                'extent' => strlen($matches[0]),
-                'element' => $Element,
-            );
-        }
+        return $element;
     }
     }
 	
 	
 	public $footnoteCount = 0;
 	public $footnoteCount = 0;
@@ -295,129 +283,112 @@ class ParsedownExtension extends \ParsedownExtra
 
 
         return $Element;
         return $Element;
     }
     }
-	
-	# math support. Check https://github.com/aidantwoods/parsedown/blob/mathjaxlatex/ParsedownExtensionMathJaxLaTeX.php
+    
+    # Inline Math
+    # check https://github.com/BenjaminHoegh/ParsedownMath
+    # check https://github.com/cben/mathdown/wiki/math-in-markdown
 
 
-    protected function inlineCode($Excerpt)
+    protected function inlineMath($Excerpt)
     {
     {
-        $marker = $Excerpt['text'][0];
-        if (preg_match('/^('.$marker.')[ ]*(.+?)[ ]*(?<!'.$marker.')\1(?!'.$marker.')/s', $Excerpt['text'], $matches))
+        if(preg_match('/^(?<!\\\\)(?<!\\\\\()\\\\\((.*?)(?<!\\\\\()\\\\\)(?!\\\\\))/s', $Excerpt['text'], $matches) OR preg_match('/\$(?!\$)([^ ][^\$\n]+)(?<! )\$(?![1-9])/s', $Excerpt['text'], $matches))
         {
         {
-            $text = $matches[2];
-            $text = preg_replace("/[ ]*\n/", ' ', $text);
             return array(
             return array(
                 'extent' => strlen($matches[0]),
                 'extent' => strlen($matches[0]),
                 'element' => array(
                 'element' => array(
-                    'name' => 'code',
-                    'text' => $text,
+                    'text' => '\(' . $matches[1] . '\)',
                 ),
                 ),
-            );
+            );        
         }
         }
-    }	
-	
-    protected function inlineMathJaxLaTeX($Excerpt)
+    }
+    
+    protected $specialCharacters = array(
+        '\\', '`', '*', '_', '{', '}', '[', ']', '(', ')', '<', '>', '#', '+', '-', '.', '!', '|', '~', '^', '='
+    );
+
+    //
+    // Inline Escape
+    // -------------------------------------------------------------------------
+    protected function inlineEscapeSequence($Excerpt)
     {
     {
-        $marker = $Excerpt['text'][0];
-        if (preg_match('/^('.$marker.'{2,})[ ]*(.+?)[ ]*(?<!'.$marker.')\1(?!'.$marker.')/s', $Excerpt['text'], $matches))
-        {
-            $text = $matches[2];
-            $text = htmlspecialchars($text, ENT_NOQUOTES, 'UTF-8');
-            $text = preg_replace("/[ ]*\n/", ' ', $text);
+        if (isset($Excerpt['text'][1]) 
+            && in_array($Excerpt['text'][1], $this->specialCharacters) 
+            && !preg_match('/(?<!\\\\)((?<!\\\\\()\\\\\((?!\\\\\())(.*?)(?<!\\\\)(?<!\\\\\()((?<!\\\\\))\\\\\)(?!\\\\\)))(?!\\\\\()/s', $Excerpt['text'])
+            && !preg_match('/\$(?!\$)([^ ][^\$\n]+)(?<! )\$(?![1-9])/s', $Excerpt['text'])
+        ){
             return array(
             return array(
-                'extent' => strlen($matches[0]),
                 'element' => array(
                 'element' => array(
-                    'name' => 'span',
-                    'text' => '\('.$text.'\)',
+                    'rawHtml' => $Excerpt['text'][1],
                 ),
                 ),
+                'extent' => 2,
             );
             );
         }
         }
     }
     }
-	
-    #
-    # Fenced Code
-    protected function blockFencedCode($Line)
+
+    # Block Math
+    protected function blockMath($Line)
     {
     {
-        if (preg_match('/^(['.$Line['text'][0].']{3,})[ ]*([\w-]+)?[ ]*$/', $Line['text'], $matches))
-        {
-            $Element = array(
-                'name' => 'code',
+        $Block = array(
+            'element' => array(
                 'text' => '',
                 'text' => '',
-            );
-			
-            if (isset($matches[2]))
-            {
-                if (strtolower($matches[2]) === 'latex')
-                {
-                    return;
-                }
-                $class = 'language-'.$matches[2];
-                $Element['attributes'] = array(
-                    'class' => $class,
-                );
-            }
-            $Block = array(
-                'char' => $Line['text'][0],
-                'openerLength' => mb_strlen($matches[1]),
-                'element' => array(
-                    'name' => 'pre',
-                    'element' => $Element,
-                ),
-            );
-			
+            ),
+        );
+        if (preg_match('/^(?<!\\\\)(\\\\\[)(?!.)$/', $Line['text'])) 
+        {
+            $Block['end'] = '\]';
             return $Block;
             return $Block;
-        }
-    }
-
-    #
-    # Fenced MathJax
-    protected function blockFencedMathJaxLaTeX($Line)
-    {
-        if (preg_match('/^['.$Line['text'][0].']{3,}[ ]*([\w-]+)?[ ]*$/', $Line['text'], $matches))
+        } 
+        elseif (preg_match('/^(?<!\\\\)(\$\$)(?!.)$/', $Line['text']))
         {
         {
-            if ( ! isset($matches[1]) or strtolower($matches[1]) !== 'latex')
-            {
-                return;
-            }
-            $Block = array(
-                'char' => $Line['text'][0],
-                'element' => array(
-                    'name' => 'span',
-                    'text' => '',
-                ),
-            );
+            $Block['end'] = '$$';
             return $Block;
             return $Block;
         }
         }
     }
     }
-	
-    protected function blockFencedMathJaxLaTeXContinue($Line, $Block)
+   
+    // ~
+    protected function blockMathContinue($Line, $Block)
     {
     {
-
-		if (isset($Block['complete']))
+        if (isset($Block['complete'])) 
         {
         {
             return;
             return;
         }
         }
-        if (isset($Block['interrupted']))
+        if (isset($Block['interrupted'])) 
         {
         {
-            $Block['element']['text'] .= "\n";
+            $Block['element']['text'] .= str_repeat("\n", $Block['interrupted']);
             unset($Block['interrupted']);
             unset($Block['interrupted']);
         }
         }
-        if (preg_match('/^'.$Block['char'].'{3,}[ ]*$/', $Line['text']))
+        if ($Block['end'] === '\]' && preg_match('/^(?<!\\\\)(\\\\\])$/', $Line['text']))
+        {
+            $Block['complete'] = true;
+            $Block['latex'] = true;
+            $Block['element']['name'] = 'div';
+            $Block['element']['text'] = "\\[".$Block['element']['text']."\n\\]";
+            $Block['element']['attributes'] = array('class' => 'math');
+
+            return $Block;
+        } 
+        elseif ($Block['end'] === '$$' && preg_match('/^(?<!\\\\)(\$\$)$/', $Line['text'])) 
         {
         {
-            $Block['element']['text'] = substr($Block['element']['text'], 1);
             $Block['complete'] = true;
             $Block['complete'] = true;
+            $Block['latex'] = true;
+            $Block['element']['name'] = 'div';
+            $Block['element']['text'] = "$$".$Block['element']['text']."\n$$";
+            $Block['element']['attributes'] = array('class' => 'math');
+
             return $Block;
             return $Block;
         }
         }
-        $Block['element']['text'] .= "\n".$Line['body'];;
+
+        $Block['element']['text'] .= "\n" . $Line['body'];
+        
+        // ~
         return $Block;
         return $Block;
     }
     }
-	
-    protected function blockFencedMathJaxLaTeXComplete($Block)
+
+    // ~
+    protected function blockMathComplete($Block)
     {
     {
-        $text = $Block['element']['text'];
-        $Block['element']['text'] = "\$\$\n" . $text . "\n\$\$";
         return $Block;
         return $Block;
     }
     }
-	
+        
 	# advanced attribute data, check parsedown extra plugin: https://github.com/tovic/parsedown-extra-plugin
 	# advanced attribute data, check parsedown extra plugin: https://github.com/tovic/parsedown-extra-plugin
     protected function parseAttributeData($text) {
     protected function parseAttributeData($text) {
         // Allow compact attributes ...
         // Allow compact attributes ...

+ 165 - 0
system/Extensions/ParsedownMath.php

@@ -0,0 +1,165 @@
+<?php
+
+namespace Typemill\Extensions;
+
+class ParsedownMath extends \ParsedownExtra
+{
+    const VERSION = '1.0';
+
+    public function __construct()
+    {
+
+        if (version_compare(parent::version, '1.7.1') < 0) {
+            # die('need version 1.7.1');
+            # throw new Exception('ParsedownMath requires a later version of Parsedown');
+        }
+
+        // Blocks
+        $this->BlockTypes['\\'][] = 'Math';
+        $this->BlockTypes['$'][] = 'Math';
+
+        // Inline
+        $this->InlineTypes['\\'][] = 'Math';
+        $this->inlineMarkerList .= '\\';
+    }
+
+    // Setters
+
+    protected $mathMode = true;
+
+    public function enableMath($input = true)
+    {
+        $this->mathMode = $input;
+
+        if ($input == false) {
+            return $this;
+        }
+
+        return $this;
+    }
+
+
+    // -------------------------------------------------------------------------
+    // -----------------------         Inline         --------------------------
+    // -------------------------------------------------------------------------
+
+
+    //
+    // Inline Math
+    // -------------------------------------------------------------------------
+
+    protected function inlineMath($Excerpt)
+    {
+        if (!$this->mathMode) {
+            return;
+        }
+
+        // if (preg_match('/^(?<!\\\\)((?<!\\\\\()\\\\\((?!\\\\\())(.*?)(?<!\\\\)(?<!\\\\\()((?<!\\\\\))\\\\\)(?!\\\\\)))(?!\\\\\()/s', $Excerpt['text'], $matches)) {
+        if (preg_match('/^(?<!\\\\)(?<!\\\\\()\\\\\((.*?)(?<!\\\\\()\\\\\)(?!\\\\\))/s', $Excerpt['text'], $matches)) {
+            return array(
+                'extent' => strlen($matches[0]),
+                'element' => array(
+                    'text' =>  $matches[0]
+                ),
+            );
+        }
+    }
+
+    protected $specialCharacters = array(
+        '\\', '`', '*', '_', '{', '}', '[', ']', '(', ')', '<', '>', '#', '+', '-', '.', '!', '|', '~', '^', '='
+    );
+
+
+    //
+    // Inline Escape
+    // -------------------------------------------------------------------------
+
+    protected function inlineEscapeSequence($Excerpt)
+    {
+        $Element = array(
+            'element' => array(
+                'rawHtml' => $Excerpt['text'][1],
+            ),
+            'extent' => 2,
+        );
+
+        if ($this->mathMode) {
+            if (isset($Excerpt['text'][1]) && in_array($Excerpt['text'][1], $this->specialCharacters) && !preg_match('/(?<!\\\\)((?<!\\\\\()\\\\\((?!\\\\\())(.*?)(?<!\\\\)(?<!\\\\\()((?<!\\\\\))\\\\\)(?!\\\\\)))(?!\\\\\()/s', $Excerpt['text'])) {
+                return $Element;
+            }
+        } else {
+            if (isset($Excerpt['text'][1]) && in_array($Excerpt['text'][1], $this->specialCharacters)) {
+                return $Element;
+            }
+        }
+    }
+
+
+
+    // -------------------------------------------------------------------------
+    // -----------------------         Blocks         --------------------------
+    // -------------------------------------------------------------------------
+
+
+    //
+    // Block Math
+    // --------------------------------------------------------------------------
+
+    protected function blockMath($Line)
+    {
+        $Block = array(
+            'element' => array(
+                'text' => '',
+            ),
+        );
+
+        if (preg_match('/^(?<!\\\\)(\\\\\[)(?!.)$/', $Line['text'])) {
+            $Block['end'] = '\]';
+            return $Block;
+        } elseif (preg_match('/^(?<!\\\\)(\$\$)(?!.)$/', $Line['text'])) {
+            $Block['end'] = '$$';
+            return $Block;
+        }
+    }
+
+    // ~
+
+    protected function blockMathContinue($Line, $Block)
+    {
+        if (isset($Block['complete'])) {
+            return;
+        }
+
+        if (isset($Block['interrupted'])) {
+            $Block['element']['text'] .= str_repeat("\n", $Block['interrupted']);
+
+            unset($Block['interrupted']);
+        }
+
+        if (preg_match('/^(?<!\\\\)(\\\\\])$/', $Line['text']) && $Block['end'] === '\]') {
+            $Block['complete'] = true;
+            $Block['latex'] = true;
+            $Block['element']['text'] = "\\[".$Block['element']['text']."\\]";
+            return $Block;
+        } elseif (preg_match('/^(?<!\\\\)(\$\$)$/', $Line['text']) && $Block['end'] === '$$') {
+            $Block['complete'] = true;
+            $Block['latex'] = true;
+            $Block['element']['text'] = "$$".$Block['element']['text']."$$";
+            return $Block;
+        }
+
+
+        $Block['element']['text'] .= "\n" . $Line['body'];
+
+        // ~
+
+        return $Block;
+    }
+
+    // ~
+
+    protected function blockMathComplete($Block)
+    {
+        return $Block;
+    }
+}

+ 39 - 11
system/Models/Folder.php

@@ -43,16 +43,18 @@ class Folder
 	{
 	{
 		$folderItems 	= scandir($folderPath);
 		$folderItems 	= scandir($folderPath);
 		$folderContent 	= array();
 		$folderContent 	= array();
-		
+
+		# if it is the live version and if it is a folder that is not published, then do not show the folder and its content.
+		if(!$draft && !in_array('index.md', $folderItems)){ return false; }
+
 		foreach ($folderItems as $key => $item)
 		foreach ($folderItems as $key => $item)
 		{
 		{
 			if (!in_array($item, array(".","..")))
 			if (!in_array($item, array(".","..")))
 			{
 			{
 				if (is_dir($folderPath . DIRECTORY_SEPARATOR . $item))
 				if (is_dir($folderPath . DIRECTORY_SEPARATOR . $item))
 				{
 				{
-					/* TODO: if folder is empty or folder has only txt files, continue */
 					$subFolder 					= $item;
 					$subFolder 					= $item;
-					$folderContent[$subFolder] 	= self::scanFolder($folderPath . DIRECTORY_SEPARATOR . $subFolder, $draft);					
+					$folderContent[$subFolder] 	= self::scanFolder($folderPath . DIRECTORY_SEPARATOR . $subFolder, $draft);
 				}
 				}
 				else
 				else
 				{
 				{
@@ -69,6 +71,7 @@ class Folder
 						if(isset($last) && ($last == implode($nameParts)) )
 						if(isset($last) && ($last == implode($nameParts)) )
 						{
 						{
 							array_pop($folderContent);
 							array_pop($folderContent);
+							$item = $item . 'md';
 						}
 						}
 						$folderContent[] = $item;
 						$folderContent[] = $item;
 					}
 					}
@@ -91,7 +94,7 @@ class Folder
 		$contentDetails 	= [];
 		$contentDetails 	= [];
 		$iteration 			= 0;
 		$iteration 			= 0;
 		$chapternr 			= 1;
 		$chapternr 			= 1;
-		
+
 		foreach($folderContent as $key => $name)
 		foreach($folderContent as $key => $name)
 		{
 		{
 			$item = new \stdClass();
 			$item = new \stdClass();
@@ -100,19 +103,26 @@ class Folder
 			{
 			{
 				$nameParts = self::getStringParts($key);
 				$nameParts = self::getStringParts($key);
 				
 				
-				$fileType = false; 
-				if(array_search('index.md', $name))
+				$fileType = '';
+				if(in_array('index.md', $name))
 				{
 				{
 					$fileType = 'md';
 					$fileType = 'md';
+					$status = 'published';
 				}
 				}
-				elseif(array_search('index.txt', $name))
+				if(in_array('index.txt', $name))
 				{
 				{
 					$fileType = 'txt';
 					$fileType = 'txt';
+					$status = 'unpublished';
+				}
+				if(in_array('index.txtmd', $name))
+				{
+					$fileType = 'txt';
+					$status = 'modified';
 				}
 				}
 
 
 				$item->originalName 	= $key;
 				$item->originalName 	= $key;
 				$item->elementType		= 'folder';
 				$item->elementType		= 'folder';
-				$item->index			= $fileType;
+				$item->status			= $status;
 				$item->fileType			= $fileType;
 				$item->fileType			= $fileType;
 				$item->order 			= count($nameParts) > 1 ? array_shift($nameParts) : NULL;
 				$item->order 			= count($nameParts) > 1 ? array_shift($nameParts) : NULL;
 				$item->name 			= implode(" ",$nameParts);
 				$item->name 			= implode(" ",$nameParts);
@@ -134,14 +144,32 @@ class Folder
 			}
 			}
 			else
 			else
 			{
 			{
+				# do not use files in base folder (only folders are allowed)
+				if(!isset($keyPath)) continue;
+
+				# do not use index files
+				if($name == 'index.md' || $name == 'index.txt' || $name == 'index.txtmd' ) continue;
+
 				$nameParts 				= self::getStringParts($name);
 				$nameParts 				= self::getStringParts($name);
 				$fileType 				= array_pop($nameParts);
 				$fileType 				= array_pop($nameParts);
 				
 				
-				# if($name == 'index.md' || $fileType !== 'md' ) continue;
-				if($name == 'index.md' || $name == 'index.txt' ) continue;
-													
+				if($fileType == 'md')
+				{
+					$status = 'published';
+				}
+				elseif($fileType == 'txt')
+				{
+					$status = 'unpublished';
+				}
+				else
+				{
+					$fileType = 'txt';
+					$status = 'modified';
+				}
+
 				$item->originalName 	= $name;
 				$item->originalName 	= $name;
 				$item->elementType		= 'file';
 				$item->elementType		= 'file';
+				$item->status 			= $status;
 				$item->fileType			= $fileType;
 				$item->fileType			= $fileType;
 				$item->order 			= count($nameParts) > 1 ? array_shift($nameParts) : NULL;
 				$item->order 			= count($nameParts) > 1 ? array_shift($nameParts) : NULL;
 				$item->name 			= implode(" ",$nameParts);
 				$item->name 			= implode(" ",$nameParts);

+ 1 - 0
system/Routes/Api.php

@@ -16,6 +16,7 @@ $app->put('/api/v1/article', ContentApiController::class . ':updateArticle')->se
 $app->delete('/api/v1/article', ContentApiController::class . ':deleteArticle')->setName('api.article.delete')->add(new RestrictApiAccess($container['router']));
 $app->delete('/api/v1/article', ContentApiController::class . ':deleteArticle')->setName('api.article.delete')->add(new RestrictApiAccess($container['router']));
 $app->post('/api/v1/article/sort', ContentApiController::class . ':sortArticle')->setName('api.article.sort')->add(new RestrictApiAccess($container['router']));
 $app->post('/api/v1/article/sort', ContentApiController::class . ':sortArticle')->setName('api.article.sort')->add(new RestrictApiAccess($container['router']));
 $app->post('/api/v1/basefolder', ContentApiController::class . ':createBaseFolder')->setName('api.basefolder.create')->add(new RestrictApiAccess($container['router']));
 $app->post('/api/v1/basefolder', ContentApiController::class . ':createBaseFolder')->setName('api.basefolder.create')->add(new RestrictApiAccess($container['router']));
+$app->get('/api/v1/navigation', ContentApiController::class . ':getNavigation')->setName('api.navigation.get')->add(new RestrictApiAccess($container['router']));
 
 
 $app->post('/api/v1/block', ContentApiController::class . ':addBlock')->setName('api.block.add')->add(new RestrictApiAccess($container['router']));
 $app->post('/api/v1/block', ContentApiController::class . ':addBlock')->setName('api.block.add')->add(new RestrictApiAccess($container['router']));
 $app->put('/api/v1/block', ContentApiController::class . ':updateBlock')->setName('api.block.update')->add(new RestrictApiAccess($container['router']));
 $app->put('/api/v1/block', ContentApiController::class . ':updateBlock')->setName('api.block.update')->add(new RestrictApiAccess($container['router']));

+ 36 - 15
system/Settings.php

@@ -14,17 +14,12 @@ class Settings
 		if($userSettings)
 		if($userSettings)
 		{
 		{
 			$settings 			= array_merge($defaultSettings, $userSettings);
 			$settings 			= array_merge($defaultSettings, $userSettings);
-			$settings['setup'] 	= false; 
 		}
 		}
-		
-		$settings['images']		= isset($userSettings['images']) ? array_merge($defaultSettings['images'], $userSettings['images']) : $defaultSettings['images'];
-		$settings['themePath'] 	= $settings['rootPath'] . $settings['themeFolder'] . DIRECTORY_SEPARATOR . $settings['theme'];
-		$settings['version']	= $defaultSettings['version'];
-		
+				
 		return array('settings' => $settings);
 		return array('settings' => $settings);
 	}
 	}
 	
 	
-	private static function getDefaultSettings()
+	public static function getDefaultSettings()
 	{
 	{
 		$rootPath = __DIR__ . DIRECTORY_SEPARATOR .  '..' . DIRECTORY_SEPARATOR;
 		$rootPath = __DIR__ . DIRECTORY_SEPARATOR .  '..' . DIRECTORY_SEPARATOR;
 		
 		
@@ -75,28 +70,54 @@ class Settings
 		return $objectSettings;
 		return $objectSettings;
 	}
 	}
 	
 	
-	public static function createSettings($settings)
-	{		
+	public static function createSettings()
+	{
 		$yaml = new Models\WriteYaml();
 		$yaml = new Models\WriteYaml();
 		
 		
-		/* write settings to yaml */
-		if($yaml->updateYaml('settings', 'settings.yaml', $settings))
-		{ 
+		# create initial settings file with only setup false
+		if($yaml->updateYaml('settings', 'settings.yaml', array('setup' => false)))
+		{
 			return true; 
 			return true; 
 		}
 		}
 		return false;
 		return false;
 	}
 	}
-	
+
 	public static function updateSettings($settings)
 	public static function updateSettings($settings)
 	{
 	{
+		# only allow if usersettings already exists (setup has been done)
 		$userSettings 	= self::getUserSettings();
 		$userSettings 	= self::getUserSettings();
 		
 		
 		if($userSettings)
 		if($userSettings)
 		{
 		{
-			$yaml 		= new Models\WriteYaml();
-			$settings 	= array_merge($userSettings, $settings);
+			# whitelist settings that can be stored in usersettings (values are not relevant here, only keys)			
+			$allowedUserSettings = ['displayErrorDetails' => false,
+									'title' => false,
+									'copyright' => false,
+									'language' => false,
+									'startpage' => false,
+									'author' => false,
+									'year' => false,
+									'theme' => false,
+									'editor' => false,
+									'setup' => false,
+									'welcome' => false,
+									'images' => false,
+									'plugins' => false,
+									'themes' => false,
+									'latestVersion' => false 
+								];
+
+			# cleanup the existing usersettings
+			$userSettings = array_intersect_key($userSettings, $allowedUserSettings);
+
+			# cleanup the new settings passed as an argument
+			$settings 	= array_intersect_key($settings, $allowedUserSettings);
 			
 			
+			# merge usersettings with new settings
+			$settings 	= array_merge($userSettings, $settings);
+
 			/* write settings to yaml */
 			/* write settings to yaml */
+			$yaml = new Models\WriteYaml();
 			$yaml->updateYaml('settings', 'settings.yaml', $settings);					
 			$yaml->updateYaml('settings', 'settings.yaml', $settings);					
 		}
 		}
 	}
 	}

+ 1 - 1
system/author/auth/welcome.twig

@@ -11,7 +11,7 @@
 				<h1>Hurra!</h1>
 				<h1>Hurra!</h1>
 				<p>Your account has been created and you are logged in now.</p>
 				<p>Your account has been created and you are logged in now.</p>
 				<p><strong>Next step:</strong> Visit the author panel and setup your new website. You can configure the system, choose themes and add plugins.</p>
 				<p><strong>Next step:</strong> Visit the author panel and setup your new website. You can configure the system, choose themes and add plugins.</p>
-				<p><strong>New:</strong> Table of content (TOC) are nice and helpful for long content pages and now the table of content will magically update while you write your page in the visual editor. Fancy stuff!!</p>
+				<p><strong>New:</strong> Write beautiful math formulas with markdown with direct preview in the visual editor. We completely refactored it!!</p>
 				<p><strong>Get help:</strong> If you have any questions, please consult the <a target="_blank" href="https://typemill.net/typemill"><i class="icon-link-ext"></i> docs</a> or open a new issue on <a target="_blank" href="https://github.com/typemill/typemill"><i class="icon-link-ext"></i> github</a>.</p>
 				<p><strong>Get help:</strong> If you have any questions, please consult the <a target="_blank" href="https://typemill.net/typemill"><i class="icon-link-ext"></i> docs</a> or open a new issue on <a target="_blank" href="https://github.com/typemill/typemill"><i class="icon-link-ext"></i> github</a>.</p>
 			</div>
 			</div>
 			<a class="button" href="{{ path_for('settings.show') }}">Configure your website</a>
 			<a class="button" href="{{ path_for('settings.show') }}">Configure your website</a>

+ 30 - 10
system/author/css/style.css

@@ -223,14 +223,19 @@ li.menu-item{
 	position: absolute;
 	position: absolute;
 	width: 4px;
 	width: 4px;
 	height: 100%;
 	height: 100%;
+	max-height: 32px;
 	left: -10px;
 	left: -10px;
 	border-top: 1px solid #f9f8f6; 
 	border-top: 1px solid #f9f8f6; 
 	border-bottom: 1px solid #f9f8f6;
 	border-bottom: 1px solid #f9f8f6;
 }
 }
-.status.md{
+.status.published{
 	background:#66b0a3;
 	background:#66b0a3;
 }
 }
-.status.txt{
+.status.modified{
+/*	background: #FFD700; */
+	background: #FFA500;
+}
+.status.unpublished{
 	background:#cc4146;
 	background:#cc4146;
 }
 }
 .navi-item i.icon-resize-full-alt,
 .navi-item i.icon-resize-full-alt,
@@ -283,15 +288,17 @@ span.level-5{ padding-left: 70px; }
 	height: 0px;
 	height: 0px;
 	overflow: hidden;
 	overflow: hidden;
 }
 }
-a.addNaviLink, a.addNaviLink:link, a.addNaviLink:visited{
+.addNaviItem a, .addNaviItem a:link, .addNaviItem a:visited{
 	padding: 3px 0;
 	padding: 3px 0;
 	margin: 0;
 	margin: 0;
 	width: auto;
 	width: auto;
 	background: transparent;
 	background: transparent;
 	color: #e0474c;
 	color: #e0474c;
 }
 }
-a.addNaviLink:focus, a.addNaviLink:hover, a.addNaviLink:active{
+.addNaviItem a:focus,.addNaviItem a:hover,.addNaviItem a:active{
 	text-decoration: underline;
 	text-decoration: underline;
+	background: transparent;
+	color: #e0474c;	
 }
 }
 .addNaviForm input{
 .addNaviForm input{
 	min-height: 0px;
 	min-height: 0px;
@@ -357,7 +364,9 @@ footer{
 	text-align: center;
 	text-align: center;
 	padding: 20px 0;
 	padding: 20px 0;
 }
 }
-
+.math{
+	white-space: pre;
+}
 /********************
 /********************
 *  	SETUP FORM 	    *
 *  	SETUP FORM 	    *
 ********************/
 ********************/
@@ -1988,18 +1997,25 @@ hr{
 	padding-left: 25px;	
 	padding-left: 25px;	
 }
 }
 .blox a, .blox a:link, .blox a:visited,
 .blox a, .blox a:link, .blox a:visited,
-footer a, footer a:link, footer a:visited,
-.setupContent a, .setupContent a:link, .setupContent a:visited
+footer a, footer a:link, footer a:visited
 { 
 { 
 	text-decoration: none; 
 	text-decoration: none; 
 	color: #e0474c; 
 	color: #e0474c; 
 }
 }
 .blox a:focus, .blox a:hover, .blox a:active,
 .blox a:focus, .blox a:hover, .blox a:active,
-footer a:focus, footer a:hover, footer a:active,
-.setupContent a:focus, .setupContent a:hover, .setupContent a:active
+footer a:focus, footer a:hover, footer a:active
 { 
 { 
 	text-decoration: underline;
 	text-decoration: underline;
 }
 }
+.setupContent a, .setupContent a:link, .setupContent a:visited
+{
+	text-decoration: none;
+	color: #444;
+}
+.setupContent a:focus, .setupContent a:hover, .setupContent a:active
+{
+	color: #e0474c; 
+}
 .blox .TOC li:before{ color: #bbb; }
 .blox .TOC li:before{ color: #bbb; }
 
 
 
 
@@ -2253,7 +2269,11 @@ footer a:focus, footer a:hover, footer a:active,
 	.menu-item a:hover:before, .menu-item a:focus:before, .menu-item a:active:before, .menu-item a.active:before{
 	.menu-item a:hover:before, .menu-item a:focus:before, .menu-item a:active:before, .menu-item a.active:before{
 		border-left-color: #e0474c;
 		border-left-color: #e0474c;
 	}
 	}
-	
+	.addNaviItem a:focus,.addNaviItem a:hover,.addNaviItem a:active{
+		text-decoration: underline;
+		background: transparent;
+		color: #e0474c;	
+	}	
 	.card .medium{
 	.card .medium{
 		padding: 0px 20px;
 		padding: 0px 20px;
 	}
 	}

+ 2 - 1
system/author/editor/editor-blox.twig

@@ -44,6 +44,7 @@
 								<button class="format-item" @click.prevent="setData( $event, 'toc-component' )" :data-id="index" :id="'blox-' + index" title="table of contents"><i class="icon-list-alt"></i></button>
 								<button class="format-item" @click.prevent="setData( $event, 'toc-component' )" :data-id="index" :id="'blox-' + index" title="table of contents"><i class="icon-list-alt"></i></button>
 								<button class="format-item" @click.prevent="setData( $event, 'hr-component' )" :data-id="index" :id="'blox-' + index" title="horizontal line"><i class="icon-minus"></i></button>
 								<button class="format-item" @click.prevent="setData( $event, 'hr-component' )" :data-id="index" :id="'blox-' + index" title="horizontal line"><i class="icon-minus"></i></button>
 								<button class="format-item" @click.prevent="setData( $event, 'code-component' )" :data-id="index" :id="'blox-' + index" title="code block"><i class="icon-code"></i></button>
 								<button class="format-item" @click.prevent="setData( $event, 'code-component' )" :data-id="index" :id="'blox-' + index" title="code block"><i class="icon-code"></i></button>
+								<button class="format-item" @click.prevent="setData( $event, 'math-component' )" :data-id="index" :id="'blox-' + index" title="math block"><i class="icon-math"></i></button>
 							</div>
 							</div>
 						</content-block>
 						</content-block>
 					</draggable>
 					</draggable>
@@ -63,7 +64,7 @@
 						<button class="format-item" @click.prevent="setData( $event, 'toc-component' )" data-id="99999" id="blox-99999" title="table of contents"><i class="icon-list-alt"></i></button>
 						<button class="format-item" @click.prevent="setData( $event, 'toc-component' )" data-id="99999" id="blox-99999" title="table of contents"><i class="icon-list-alt"></i></button>
 						<button class="format-item" @click.prevent="setData( $event, 'hr-component' )" data-id="99999" id="blox-99999" title="horizontal line"><i class="icon-minus"></i></button>
 						<button class="format-item" @click.prevent="setData( $event, 'hr-component' )" data-id="99999" id="blox-99999" title="horizontal line"><i class="icon-minus"></i></button>
 						<button class="format-item" @click.prevent="setData( $event, 'code-component' )" data-id="99999" id="blox-99999" title="code block"><i class="icon-code"></i></button>
 						<button class="format-item" @click.prevent="setData( $event, 'code-component' )" data-id="99999" id="blox-99999" title="code block"><i class="icon-code"></i></button>
-				<!--	<button class="format-item" @click.prevent="setData( $event, 'math-component' )" data-id="99999" id="blox-99999" title="math"><i class="icon-math"></i></button>  -->
+						<button class="format-item" @click.prevent="setData( $event, 'math-component' )" data-id="99999" id="blox-99999" title="math"><i class="icon-math"></i></button>
 					</content-block>
 					</content-block>
 				</div>
 				</div>
 				
 				

+ 57 - 30
system/author/js/lazy-video.js

@@ -1,34 +1,61 @@
-( function() {
 
 
-    var youtube = document.querySelectorAll( ".youtube" );
-    
-    for (var i = 0; i < youtube.length; i++)
+let typemillUtilities = {
+
+	setYoutubeItems: function()
 	{
 	{
-		var thisyoutube = youtube[i];		
-		thisyoutube.parentNode.classList.add("video-container");
-		
-		var playbutton = document.createElement("button");
-		playbutton.classList.add("play-video");
-		playbutton.value = "Play";
+		this.youtubeItems = document.querySelectorAll( ".youtube" );
+	},
+	addYoutubePlayButtons: function(){
+		if(this.youtubeItems)
+		{
+			for(var i = 0; i < this.youtubeItems.length; i++)
+			{
+				var youtubeItem = this.youtubeItems[i];
+				this.addYoutubePlayButton(youtubeItem);
+			}	
+		}	
+	},
+
+	addYoutubePlayButton: function(element)
+	{
+		console.info(element.parentNode);
+		element.parentNode.classList.add("video-container");
 		
 		
-		thisyoutube.parentNode.appendChild(playbutton);
+		var youtubePlaybutton = document.createElement("button");
+		youtubePlaybutton.classList.add("play-video");
+		youtubePlaybutton.value = "Play";
+
+		element.parentNode.appendChild(youtubePlaybutton);	
+	},
+
+	start: function(){
+		this.setYoutubeItems();
+		this.addYoutubePlayButtons();
+		this.listenToYoutube();
+	},
+
+	listenToYoutube: function(){
+		document.addEventListener('click', function (event) {
+
+			if (event.target.matches('.play-video')) {
+
+				var youtubeID = event.target.parentNode.getElementsByClassName('youtube')[0].id;
+
+				event.preventDefault();
+				event.stopPropagation();
+
+				var iframe = document.createElement( "iframe" );
 		
 		
-		playbutton.addEventListener( "click", function(event)
-		{
-			event.preventDefault();
-			event.stopPropagation();
-			
-			var iframe = document.createElement( "iframe" );
-
-			iframe.setAttribute( "frameborder", "0" );
-			iframe.setAttribute( "allowfullscreen", "" );
-			iframe.setAttribute( "width", "560" );
-			iframe.setAttribute( "height", "315" );
-			iframe.setAttribute( "src", "https://www.youtube.com/embed/" + thisyoutube.id + "?rel=0&showinfo=0&autoplay=1" );
-
-			var videocontainer = thisyoutube.parentNode
-			videocontainer.innerHTML = "";
-			videocontainer.appendChild( iframe );
-		})(thisyoutube);
-    };
-} )();
+				iframe.setAttribute( "frameborder", "0" );
+				iframe.setAttribute( "allowfullscreen", "" );
+				iframe.setAttribute( "width", "560" );
+				iframe.setAttribute( "height", "315" );
+				iframe.setAttribute( "src", "https://www.youtube-nocookie.com/embed/" + youtubeID + "?rel=0&showinfo=0&autoplay=1" );
+	
+				var videocontainer = event.target.parentNode;
+				videocontainer.innerHTML = "";
+				videocontainer.appendChild( iframe );
+			}
+		}, true);	
+	},
+};

+ 138 - 3
system/author/js/vue-blox.js

@@ -158,7 +158,7 @@ const contentComponent = Vue.component('content-block', {
 		},
 		},
  		submitBlock: function(){
  		submitBlock: function(){
 			var emptyline = /^\s*$(?:\r\n?|\n)/gm;
 			var emptyline = /^\s*$(?:\r\n?|\n)/gm;
-			if(this.componentType == "code-component"){ }
+			if(this.componentType == "code-component" || this.componentType == "math-component"){ }
 			else if(this.componentType == "ulist-component" || this.componentType == "olist-component")
 			else if(this.componentType == "ulist-component" || this.componentType == "olist-component")
 			{
 			{
 				var listend = (this.componentType == "ulist-component") ? '* \n' : '1. \n';
 				var listend = (this.componentType == "ulist-component") ? '* \n' : '1. \n';
@@ -266,6 +266,8 @@ const contentComponent = Vue.component('content-block', {
 						}
 						}
 						else
 						else
 						{
 						{
+							var thisBlockType = self.$root.$data.blockType;
+
 							self.switchToPreviewMode();
 							self.switchToPreviewMode();
 							
 							
 							if(self.$root.$data.blockId == 99999)
 							if(self.$root.$data.blockId == 99999)
@@ -307,13 +309,26 @@ const contentComponent = Vue.component('content-block', {
 							{
 							{
 								self.$root.$data.html.splice(result.toc.id, 1, result.toc);
 								self.$root.$data.html.splice(result.toc.id, 1, result.toc);
 							}
 							}
+
+							/* check math here */
+							self.$root.checkMath(result.id);
+
+							/* check youtube here */
+							if(thisBlockType == "video-component" || thisBlockType == "image-component")
+							{
+								self.$root.checkVideo(result.id);
+							}
+
+							/* update the navigation and mark navigation item as modified */
+							navi.getNavi();
+
 						}
 						}
 					}
 					}
 					else if(httpStatus != 200)
 					else if(httpStatus != 200)
 					{
 					{
 						self.activatePage();
 						self.activatePage();
 						publishController.errors.message = "Sorry, something went wrong. Please refresh the page and try again.";
 						publishController.errors.message = "Sorry, something went wrong. Please refresh the page and try again.";
-					}					
+					}	
 				}, method, url, params);
 				}, method, url, params);
 			}
 			}
 		},
 		},
@@ -367,6 +382,9 @@ const contentComponent = Vue.component('content-block', {
 						{
 						{
 							self.$root.$data.html.splice(result.toc.id, 1, result.toc);
 							self.$root.$data.html.splice(result.toc.id, 1, result.toc);
 						}
 						}
+						
+						/* update the navigation and mark navigation item as modified */
+						navi.getNavi();
 					}
 					}
 				}
 				}
 			}, method, url, params);
 			}, method, url, params);
@@ -967,6 +985,49 @@ const definitionComponent = Vue.component('definition-component', {
 	},
 	},
 })
 })
 
 
+const mathComponent = Vue.component('math-component', {
+	props: ['compmarkdown', 'disabled'],
+	template: '<div>' + 
+				'<input type="hidden" ref="markdown" :value="compmarkdown" :disabled="disabled" @input="updatemarkdown" />' +	
+				'<div class="contenttype"><i class="icon-math"></i></div>' +
+				'<textarea class="mdcontent" ref="markdown" v-model="mathblock" :disabled="disabled" @input="createmarkdown"></textarea>' + 
+				'</div>',
+	data: function(){
+		return {
+			mathblock: ''
+		}
+	},
+	mounted: function(){
+		this.$refs.markdown.focus();
+		if(this.compmarkdown)
+		{
+			var dollarMath = new RegExp(/^\$\$[\S\s]+\$\$$/m);
+			var bracketMath = new RegExp(/^\\\[[\S\s]+\\\]$/m);
+
+			if(dollarMath.test(this.compmarkdown) || bracketMath.test(this.compmarkdown))
+			{
+				var mathExpression = this.compmarkdown.substring(2,this.compmarkdown.length-2);
+				this.mathblock = mathExpression.trim(); 
+			}
+		}
+		this.$nextTick(function () {
+			autosize(document.querySelectorAll('textarea'));
+		});
+	},
+	methods: {
+		createmarkdown: function(event)
+		{
+			this.codeblock = event.target.value;
+			var codeblock = '$$\n' + event.target.value + '\n$$';
+			this.updatemarkdown(codeblock);
+		},
+		updatemarkdown: function(codeblock)
+		{
+			this.$emit('updatedMarkdown', codeblock);
+		},
+	},
+})
+
 const videoComponent = Vue.component('video-component', {
 const videoComponent = Vue.component('video-component', {
 	props: ['compmarkdown', 'disabled', 'load'],
 	props: ['compmarkdown', 'disabled', 'load'],
 	template: '<div class="video dropbox">' +
 	template: '<div class="video dropbox">' +
@@ -1275,6 +1336,7 @@ let editor = new Vue({
 		'olist-component': olistComponent,
 		'olist-component': olistComponent,
 		'table-component': tableComponent,
 		'table-component': tableComponent,
 		'definition-component': definitionComponent,
 		'definition-component': definitionComponent,
+		'math-component': mathComponent,
 	},
 	},
 	data: {
 	data: {
 		root: document.getElementById("main").dataset.url,
 		root: document.getElementById("main").dataset.url,
@@ -1351,6 +1413,24 @@ let editor = new Vue({
 				else
 				else
 				{
 				{
 					self.markdown = result.data;
 					self.markdown = result.data;
+					
+					/* make math plugin working */
+					if (typeof renderMathInElement === "function") { 
+						self.$nextTick(function () {
+							renderMathInElement(document.body);
+						});		
+					}
+
+					/* check for youtube videos */
+					if (typeof typemillUtilities !== "undefined")
+					{
+						setTimeout(function(){ 
+							self.$nextTick(function () 
+							{
+								typemillUtilities.start();
+							});
+						}, 200);
+					}
 				}
 				}
 			}
 			}
 		}, method, url, params);
 		}, method, url, params);
@@ -1405,6 +1485,12 @@ let editor = new Vue({
 						
 						
 						publishController.publishDisabled = false;
 						publishController.publishDisabled = false;
 						publishController.publishResult = "";
 						publishController.publishResult = "";
+
+						/* update the navigation and mark navigation item as modified */
+						navi.getNavi();
+
+						/* update the math if plugin is there */
+						self.checkMath(params.new_index+1);
 					}
 					}
 				}
 				}
 			}, method, url, params);
 			}, method, url, params);
@@ -1467,7 +1553,13 @@ let editor = new Vue({
 				case "[":
 				case "[":
 					if(secondChar == "!" && thirdChar == "[") { return "image-component" } else { return "markdown-component" }
 					if(secondChar == "!" && thirdChar == "[") { return "image-component" } else { return "markdown-component" }
 					break;
 					break;
-				case "`":
+				case "\\":
+					if(secondChar == "["){ return "math-component" } else { return "markdown-component"; }
+					break;
+				case "$":
+						if(secondChar == "$"){ return "math-component" } else { return "markdown-component"; }
+						break;
+					case "`":
 					if(secondChar == "`" && thirdChar == "`") { return "code-component" } else { return "markdown-component" }
 					if(secondChar == "`" && thirdChar == "`") { return "code-component" } else { return "markdown-component" }
 					break;
 					break;
 				case "*":
 				case "*":
@@ -1479,5 +1571,48 @@ let editor = new Vue({
 					return 'markdown-component';
 					return 'markdown-component';
 			}
 			}
 		},
 		},
+		checkMath(elementid)
+		{
+				/* make math plugin working */
+				if (typeof renderMathInElement === "function")
+				{
+					self.$nextTick(function () {
+						renderMathInElement(document.getElementById("blox-"+elementid));
+					});
+				}
+				if (typeof MathJax !== false) { 
+					self.$nextTick(function () {
+						MathJax.Hub.Queue(["Typeset",MathJax.Hub,"blox-"+elementid]);
+					});
+				}
+		},
+		initiateVideo()
+		{
+			/* check for youtube videos */
+			if (typeof typemillUtilities !== "undefined")
+			{
+				this.$nextTick(function () {
+						typemillUtilities.start();
+				});
+			}
+		},
+		checkVideo(elementid)
+		{
+			/* check for youtube videos */
+			var element = document.getElementById("blox-"+elementid);
+			if(element && typeof typemillUtilities !== "undefined")
+			{
+				imageElement = element.getElementsByClassName("youtube");
+				if(imageElement[0])
+				{
+					setTimeout(function(){ 
+						self.$nextTick(function () 
+						{
+								typemillUtilities.addYoutubePlayButton(imageElement[0]);
+						});
+					}, 300);
+				}
+			}
+		}
 	}
 	}
 });
 });

+ 34 - 1
system/author/js/vue-navi.js

@@ -1,6 +1,6 @@
 const navcomponent = Vue.component('navigation', {
 const navcomponent = Vue.component('navigation', {
 	template: '#navigation-template',
 	template: '#navigation-template',
-	props: ['name', 'newItem', 'parent', 'active', 'filetype', 'elementtype', 'element', 'folder', 'level', 'url', 'root', 'freeze'],
+	props: ['homepage', 'name', 'newItem', 'parent', 'active', 'filetype', 'status', 'elementtype', 'element', 'folder', 'level', 'url', 'root', 'freeze'],
 	data: function () {
 	data: function () {
 		return {
 		return {
 			showForm: false,
 			showForm: false,
@@ -175,6 +175,7 @@ let navi = new Vue({
 		return {
 		return {
 			title: "Navigation",
 			title: "Navigation",
 			items: JSON.parse(document.getElementById("data-navi").dataset.navi),
 			items: JSON.parse(document.getElementById("data-navi").dataset.navi),
+			homepage: JSON.parse(document.getElementById("data-navi").dataset.homepage),
 			editormode: document.getElementById("data-navi").dataset.editormode,
 			editormode: document.getElementById("data-navi").dataset.editormode,
 			root: document.getElementById("main").dataset.url,
 			root: document.getElementById("main").dataset.url,
 			freeze: false,
 			freeze: false,
@@ -242,6 +243,38 @@ let navi = new Vue({
 					}
 					}
 				}
 				}
 			}, method, url, newFolder );
 			}, method, url, newFolder );
+		},
+		getNavi: function()
+		{
+			publishController.errors.message = false;
+
+			var self = this;
+			
+			self.freeze = true;
+			self.errors = {title: false, content: false, message: false};
+
+			var activeItem = document.getElementById("path").value;
+			var url = this.root + '/api/v1/navigation?url=' + activeItem;
+			var method 	= 'GET';
+
+			sendJson(function(response, httpStatus)
+			{
+				if(response)
+				{
+					self.freeze = false;
+					var result = JSON.parse(response);
+					
+					if(result.errors)
+					{
+						publishController.errors.message = result.errors;
+					}
+					if(result.data)
+					{
+						self.items = result.data;
+						self.homepage = result.homepage;						
+					}
+				}
+			}, method, url, activeItem );
 		}
 		}
 	}
 	}
 })
 })

+ 3 - 0
system/author/js/vue-publishcontroller.js

@@ -72,6 +72,7 @@ let publishController = new Vue({
 						self.publishStatus = false;
 						self.publishStatus = false;
 						self.publishLabel = "online";
 						self.publishLabel = "online";
 						self.publishLabelMobile = "ON";
 						self.publishLabelMobile = "ON";
+						navi.getNavi();
 					}
 					}
 				}
 				}
 				else if(httpStatus != 200)
 				else if(httpStatus != 200)
@@ -121,6 +122,7 @@ let publishController = new Vue({
 					else
 					else
 					{
 					{
 						self.draftResult = 'success';
 						self.draftResult = 'success';
+						navi.getNavi();
 					}
 					}
 				}
 				}
 				else if(httpStatus != 200)
 				else if(httpStatus != 200)
@@ -177,6 +179,7 @@ let publishController = new Vue({
 						self.publishLabel = "offline";
 						self.publishLabel = "offline";
 						self.publishLabelMobile = "OFF";
 						self.publishLabelMobile = "OFF";
 						self.publishDisabled = false;
 						self.publishDisabled = false;
+						navi.getNavi();
 					}
 					}
 				}
 				}
 			}, method, url, this.form );
 			}, method, url, this.form );

+ 6 - 0
system/author/layouts/layoutBlox.twig

@@ -21,6 +21,9 @@
 		<link rel="stylesheet" href="{{ base_url }}/system/author/css/normalize.css" />
 		<link rel="stylesheet" href="{{ base_url }}/system/author/css/normalize.css" />
 		<link rel="stylesheet" href="{{ base_url }}/system/author/css/style.css?20190517" />
 		<link rel="stylesheet" href="{{ base_url }}/system/author/css/style.css?20190517" />
 		<link rel="stylesheet" href="{{ base_url }}/system/author/css/color-picker.min.css" />
 		<link rel="stylesheet" href="{{ base_url }}/system/author/css/color-picker.min.css" />
+
+		{{ assets.renderCSS() }}
+
 	</head>
 	</head>
 	<body>	
 	<body>	
 		<header class="main-header">
 		<header class="main-header">
@@ -45,5 +48,8 @@
 		<script src="{{ base_url }}/system/author/js/vue-blox.js?20190517"></script>
 		<script src="{{ base_url }}/system/author/js/vue-blox.js?20190517"></script>
 		<script src="{{ base_url }}/system/author/js/vue-navi.js?20190517"></script>
 		<script src="{{ base_url }}/system/author/js/vue-navi.js?20190517"></script>
 		<script src="{{ base_url }}/system/author/js/lazy-video.js?20190517"></script>
 		<script src="{{ base_url }}/system/author/js/lazy-video.js?20190517"></script>
+
+		{{ assets.renderJS() }}
+
 	</body>
 	</body>
 </html>
 </html>

+ 6 - 5
system/author/partials/editorNavi.twig

@@ -1,14 +1,15 @@
 <nav id="sidebar-menu" class="sidebar-menu--content">
 <nav id="sidebar-menu" class="sidebar-menu--content">
-	<div id="data-navi" data-navi='{{ navigation|json_encode() }}' data-editormode="{{settings.editor}}"></div>
+	<div id="data-navi" data-navi='{{ navigation|json_encode() }}' data-homepage='{{ homepage|json_encode() }}' data-editormode="{{settings.editor}}"></div>
 	<div id="mobile-menu" class="menu-action">Menu <span class="button-arrow"></span></div>
 	<div id="mobile-menu" class="menu-action">Menu <span class="button-arrow"></span></div>
 	<div id="navi" class="content-navi" v-model="freeze" v-cloak>
 	<div id="navi" class="content-navi" v-model="freeze" v-cloak>
 		<div class="navi-list">
 		<div class="navi-list">
 			<div class="navi-item folder">
 			<div class="navi-item folder">
-				<a href="{{ base_url }}/tm/content/{{ settings.editor }}"><i class="icon-home"></i><span class="level-1">Homepage</span></a>
+				<div class="status" :class="homepage.status"></div>
+				<a href="{{ base_url }}/tm/content/{{ settings.editor }}" :class="homepage.active"><i class="icon-home"></i><span class="level-1">Homepage</span></a>
 			</div>
 			</div>
 		</div>
 		</div>
 		<draggable :element="'ul'" class="navi-list" :list="items" @start="onStart" @end="onEnd" :options="{group:{ name:'folder'}, animation: 150, 'disabled': freeze }">
 		<draggable :element="'ul'" class="navi-list" :list="items" @start="onStart" @end="onEnd" :options="{group:{ name:'folder'}, animation: 150, 'disabled': freeze }">
-			<navigation ref="draggit" v-for="item in items" :freeze="freeze" :name="item.name" :active="item.active" :parent="item.activeParent" :level="item.keyPath" :root="root" :url="item.urlRelWoF" v-bind:id="item.keyPath" :key="item.keyPath" :elementtype="item.elementType" :filetype="item.fileType" :folder="item.folderContent"></navigation>
+			<navigation ref="draggit" v-for="item in items" :freeze="freeze" :name="item.name" :active="item.active" :parent="item.activeParent" :level="item.keyPath" :root="root" :url="item.urlRelWoF" v-bind:id="item.keyPath" :key="item.keyPath" :elementtype="item.elementType" :filetype="item.fileType" :status="item.status" :folder="item.folderContent"></navigation>
 		</draggable>
 		</draggable>
 		<ul class="navi-list addBaseFolder">
 		<ul class="navi-list addBaseFolder">
 			<li class="navi-item file">
 			<li class="navi-item file">
@@ -25,10 +26,10 @@
 {% verbatim %}
 {% verbatim %}
 	<template id="navigation-template">
 	<template id="navigation-template">
 		<li class="navi-item" :class="elementtype">
 		<li class="navi-item" :class="elementtype">
-			<div class="status" :class="filetype"></div>
+			<div class="status" :class="status"></div>
 			<a v-bind:href="getUrl(root, url)" :class="checkActive(active,parent)"><i :class="getIcon(elementtype, filetype)"></i><span :class="getLevel(level)">{{ name }}</span><i class="icon-move"></i></a>
 			<a v-bind:href="getUrl(root, url)" :class="checkActive(active,parent)"><i :class="getIcon(elementtype, filetype)"></i><span :class="getLevel(level)">{{ name }}</span><i class="icon-move"></i></a>
 			<draggable v-if="folder" :element="'ul'" class="navi-list" :list="folder" :move="checkMove" @start="onStart" @end="onEnd" :options="{group:{ name:'file'}, animation: 150, 'disabled': freeze }">
 			<draggable v-if="folder" :element="'ul'" class="navi-list" :list="folder" :move="checkMove" @start="onStart" @end="onEnd" :options="{group:{ name:'file'}, animation: 150, 'disabled': freeze }">
-				<navigation ref="draggit" v-for="item in folder" :freeze="freeze" :name="item.name" :active="item.active" :parent="item.activeParent" :level="item.keyPath" :url="item.urlRelWoF" :root="root" v-bind:id="item.keyPath" :key="item.keyPath" :filetype="item.fileType" :elementtype="item.elementType" :folder="item.folderContent"></navigation>
+				<navigation ref="draggit" v-for="item in folder" :freeze="freeze" :name="item.name" :active="item.active" :parent="item.activeParent" :level="item.keyPath" :url="item.urlRelWoF" :root="root" v-bind:id="item.keyPath" :key="item.keyPath" :filetype="item.fileType" :status="item.status" :elementtype="item.elementType" :folder="item.folderContent"></navigation>
 			</draggable>
 			</draggable>
 			<ul v-if="folder" class="navi-list"><li class="navi-item file"><i class="icon-plus"></i><span :class="getLevel(level + '.0')" class="addNaviItem"><a class="addNaviLink" href="#" @click.prevent="toggleForm">add item</a></span><transition name="fade"><div v-if="showForm" class="addNaviForm"><input v-model="newItem"><button class="b-left" @click="addFile('file')">add file</button><button class="b-right" @click="addFile('folder')">add folder</button></div></transition></li></ul>
 			<ul v-if="folder" class="navi-list"><li class="navi-item file"><i class="icon-plus"></i><span :class="getLevel(level + '.0')" class="addNaviItem"><a class="addNaviLink" href="#" @click.prevent="toggleForm">add item</a></span><transition name="fade"><div v-if="showForm" class="addNaviForm"><input v-model="newItem"><button class="b-left" @click="addFile('file')">add file</button><button class="b-right" @click="addFile('folder')">add folder</button></div></transition></li></ul>
 		</li>
 		</li>

+ 5 - 5
system/system.php

@@ -50,13 +50,13 @@ $container = $app->getContainer();
 * LOAD & UPDATE PLUGINS *
 * LOAD & UPDATE PLUGINS *
 ************************/
 ************************/
 
 
-$plugins 					= new Typemill\Plugins();
-$pluginNames				= $plugins->load();
+$plugins 				= new Typemill\Plugins();
+$pluginNames		= $plugins->load();
 $pluginSettings = $routes = $middleware	= array();
 $pluginSettings = $routes = $middleware	= array();
 
 
 foreach($pluginNames as $pluginName)
 foreach($pluginNames as $pluginName)
 {
 {
-	$className			= $pluginName['className'];
+	$className	= $pluginName['className'];
 	$name				= $pluginName['name'];
 	$name				= $pluginName['name'];
 		
 		
 	# check if plugin is in the settings already
 	# check if plugin is in the settings already
@@ -81,13 +81,13 @@ foreach($pluginNames as $pluginName)
 	if($pluginSettings[$name]['active'])
 	if($pluginSettings[$name]['active'])
 	{
 	{
 		$routes 			= $plugins->getNewRoutes($className, $routes);
 		$routes 			= $plugins->getNewRoutes($className, $routes);
-		$middleware			= $plugins->getNewMiddleware($className, $middleware);
+		$middleware		= $plugins->getNewMiddleware($className, $middleware);
 		
 		
 		$dispatcher->addSubscriber(new $className($container));
 		$dispatcher->addSubscriber(new $className($container));
 	}
 	}
 }
 }
 
 
-# if plugins in settings are not empty, then a plugin has been removed
+# if plugins in original settings are not empty now, then a plugin has been removed
 if(!empty($settings['settings']['plugins'])){ $refreshSettings = true; }
 if(!empty($settings['settings']['plugins'])){ $refreshSettings = true; }
 
 
 # update the settings in all cases
 # update the settings in all cases

+ 3 - 1
themes/typemill/css/style.css

@@ -494,7 +494,9 @@ pre{
 	max-width: 100%;
 	max-width: 100%;
 	overflow-x: auto;
 	overflow-x: auto;
 }
 }
-
+.math{
+	white-space: pre;
+}
 table{
 table{
 	width: 100%;
 	width: 100%;
 	border-collapse: collapse;
 	border-collapse: collapse;

+ 2 - 2
themes/typemill/partials/layout.twig

@@ -58,8 +58,8 @@
 		{% block javascripts %}
 		{% block javascripts %}
 
 
 			<script src="{{ base_url }}/themes/typemill/js/script.js"></script>
 			<script src="{{ base_url }}/themes/typemill/js/script.js"></script>
-			<script src="{{ base_url }}/system/author/js/lazy-video.js"></script>
-
+			<script src="{{ base_url }}/system/author/js/lazy-video.js?20190602"></script>
+			<script>typemillUtilities.start();</script>
 			{{ assets.renderJS() }}
 			{{ assets.renderJS() }}
 		
 		
 		{% endblock %}		
 		{% endblock %}		

Algúns arquivos non se mostraron porque demasiados arquivos cambiaron neste cambio