瀏覽代碼

Version 1.2.7: Reorder Content

Sebastian 6 年之前
父節點
當前提交
2633ab69be

+ 1 - 1
.gitignore

@@ -4,8 +4,8 @@ plugins/demo
 plugins/disqus
 plugins/disqus
 plugins/download
 plugins/download
 plugins/finalwords
 plugins/finalwords
-plugins/version
 plugins/textadds
 plugins/textadds
+plugins/version
 settings/settings.yaml
 settings/settings.yaml
 settings/users
 settings/users
 system/vendor
 system/vendor

+ 1 - 1
cache/lastCache.txt

@@ -1 +1 @@
-1540919595
+1541750318

+ 23 - 0
content/00-Welcome/00-Setup.md

@@ -0,0 +1,23 @@
+# Setup the System
+
+Typemil is a flat file cms that runs out of the box without a complicated installation process. You can create a user account with the [simple setup page](/setup) and then login to the author panel. In the author panel, you can configure your page, use plugins, choose a theme and edit your content.
+
+## If it does not work
+
+If you face any problems, then please make sure, that your system meets these requirements:
+
+- PHP version 7+.
+- Apache Server.
+- The module `mod_rewrite` and `htaccess`.
+
+If you run a linux-systems like Debian or Ubuntu, then please double check that `mod_rewrite` or `htaccess` are activated. Check this issue on GitHub for help.
+
+Please make the following folders writable with permission 774 (you can use your ftp-software for it):
+
+- Cache
+- Content
+- Media
+- Settings
+
+If you still get an error, then you can post an issue on [GitHub](https://github.com/trendschau/typemill).
+

+ 1 - 0
content/00-Welcome/01-demo.txt

@@ -0,0 +1 @@
+["# demo page","Typemil is a flat file cms that runs out of the box without a complicated installation process. You can create a user account with the [simple setup page](\/setup) and then login to the author panel. In the author panel, you can configure your page, use plugins, choose a theme and edit your content.","## Headline","* This is\n* A list"]

+ 0 - 0
content/00-Welcome/00-Write-Content.md → content/00-Welcome/02-Write-Content.md


+ 0 - 0
content/00-Welcome/01-Get-Help.md → content/00-Welcome/03-Get-Help.md


+ 1 - 0
content/00-Welcome/index.txt

@@ -0,0 +1 @@
+["# Welcome to Typemill","Great that you give Typemill a try!! Typemill is a small open source cms and a project in work. You will probably miss some important features, but I am working hard to add everything that is needed for a really productive little writing-system.","Before you start, please read the short introduction about \"writing content\". Or simply play around, I hope that Typemill is already quite intuitive to use..."]

+ 98 - 12
system/Controllers/ContentApiController.php

@@ -602,26 +602,32 @@ class ContentApiController extends ContentController
 		# if it is a new content-block
 		# if it is a new content-block
 		if($this->params['block_id'] == 99999)
 		if($this->params['block_id'] == 99999)
 		{
 		{
-			# update the markdown block in the page content
-			$pageMarkdown[] = $blockMarkdown;
-			$id = (count($pageMarkdown)-1);
+			# set the id of the markdown-block (it will be one more than the actual array, so count is perfect) 
+			$id = count($pageMarkdown);
+			
+			# set the id with prefix "blox-"
 			$blockId = 'blox-' . $id;
 			$blockId = 'blox-' . $id;
+			
+			# add the new markdown block to the page content
+			$pageMarkdown[] = $blockMarkdown;			
 		}
 		}
 		elseif(!isset($pageMarkdown[$this->params['block_id']]))
 		elseif(!isset($pageMarkdown[$this->params['block_id']]))
 		{
 		{
-			# return error
+			# if the block does not exists, return an error
 			return $response->withJson(array('data' => false, 'errors' => 'The ID of the content-block is wrong.'), 404);
 			return $response->withJson(array('data' => false, 'errors' => 'The ID of the content-block is wrong.'), 404);
 		}
 		}
 		elseif($this->params['block_id'] == 0)
 		elseif($this->params['block_id'] == 0)
 		{
 		{
-			# update the markdown block in the page content
+			# if it is the title, then delete the "# " if it exists
 			$blockMarkdown = trim($blockMarkdown, "# ");
 			$blockMarkdown = trim($blockMarkdown, "# ");
 			
 			
+			# store the markdown-headline in a separate variable
 			$blockMarkdownTitle = '# ' . $blockMarkdown;
 			$blockMarkdownTitle = '# ' . $blockMarkdown;
 			
 			
-			$pageMarkdown[$this->params['block_id']] = $blockMarkdownTitle;
-			$id = $this->params['block_id'];
-			$blockId = $this->params['block_id'];
+			# add the markdown-headline to the page-markdown
+			$pageMarkdown[0] = $blockMarkdownTitle;
+			$id = 0;
+			$blockId = 0;
 		}
 		}
 		else
 		else
 		{
 		{
@@ -635,7 +641,7 @@ class ContentApiController extends ContentController
 		$pageJson = json_encode($pageMarkdown);
 		$pageJson = json_encode($pageMarkdown);
 
 
 		# set path for the file (or folder)
 		# set path for the file (or folder)
-		$this->setItemPath('txt');		
+		$this->setItemPath('txt');
 	
 	
 		/* update the file */
 		/* update the file */
 		if($this->write->writeFile($this->settings['contentFolder'], $this->path, $pageJson))
 		if($this->write->writeFile($this->settings['contentFolder'], $this->path, $pageJson))
@@ -666,6 +672,83 @@ class ContentApiController extends ContentController
 
 
 		return $response->withJson(array('content' => $blockHTML, 'markdown' => $blockMarkdown, 'blockId' => $blockId, 'id' => $id, 'errors' => false));
 		return $response->withJson(array('content' => $blockHTML, 'markdown' => $blockMarkdown, 'blockId' => $blockId, 'id' => $id, 'errors' => false));
 	}
 	}
+	
+	public function moveBlock(Request $request, Response $response, $args)
+	{
+		# get params from call
+		$this->params 	= $request->getParams();
+		$this->uri 		= $request->getUri();
+
+		# validate input 
+		# if(!$this->validateBlockInput()){ return $response->withJson($this->errors,422); }
+		
+		# set structure
+		if(!$this->setStructure($draft = true)){ return $response->withJson(array('data' => false, 'errors' => $this->errors), 404); }
+		
+		# set item 
+		if(!$this->setItem()){ return $response->withJson($this->errors, 404); }
+
+		# set the status for published and drafted
+		$this->setPublishStatus();
+
+		# set path
+		$this->setItemPath($this->item->fileType);
+
+		# read content from file
+		if(!$this->setContent()){ return $response->withJson(array('data' => false, 'errors' => $this->errors), 404); }
+
+		# make it more clear which content we have
+		$pageMarkdown = $this->content;
+		
+		if($pageMarkdown == '')
+		{
+			$pageMarkdown = [];
+		}
+
+		# initialize parsedown extension
+		$parsedown = new ParsedownExtension();
+
+		# if content is not an array, then transform it
+		if(!is_array($pageMarkdown))
+		{
+			# turn markdown into an array of markdown-blocks
+			$pageMarkdown = $parsedown->markdownToArrayBlocks($pageMarkdown);
+		}
+
+		$oldIndex = ($this->params['old_index'] + 1);
+		$newIndex = ($this->params['new_index'] + 1);
+		
+		if(!isset($pageMarkdown[$oldIndex]))
+		{
+			# if the block does not exists, return an error
+			return $response->withJson(array('data' => false, 'errors' => 'The ID of the content-block is wrong.'), 404);
+		}
+				
+		$extract = array_splice($pageMarkdown, $oldIndex, 1);
+		array_splice($pageMarkdown, $newIndex, 0, $extract);
+			
+		# encode the content into json
+		$pageJson = json_encode($pageMarkdown);
+
+		# set path for the file (or folder)
+		$this->setItemPath('txt');
+	
+		/* update the file */
+		if($this->write->writeFile($this->settings['contentFolder'], $this->path, $pageJson))
+		{
+			# update the internal structure
+			$this->setStructure($draft = true, $cache = false);
+		}
+		else
+		{
+			return $response->withJson(['errors' => ['message' => 'Could not write to file. Please check if the file is writable']], 404);
+		}
+	
+		# if it is the title, then delete the "# " if it exists
+		$pageMarkdown[0] = trim($pageMarkdown[0], "# ");
+
+		return $response->withJson(array('markdown' => $pageMarkdown, 'errors' => false));
+	}
 
 
 	public function deleteBlock(Request $request, Response $response, $args)
 	public function deleteBlock(Request $request, Response $response, $args)
 	{
 	{
@@ -713,10 +796,12 @@ class ContentApiController extends ContentController
 		unset($this->content[$this->params['block_id']]);
 		unset($this->content[$this->params['block_id']]);
 		$this->content = array_values($this->content);
 		$this->content = array_values($this->content);
 
 
+		$pageMarkdown = $this->content;
+		
 		# delete markdown from title
 		# delete markdown from title
-		if(isset($this->content[0]))
+		if(isset($pageMarkdown[0]))
 		{
 		{
-			$this->content[0] = trim($this->content[0], "# ");
+			$pageMarkdown[0] = trim($pageMarkdown[0], "# ");
 		}
 		}
 		
 		
 		# encode the content into json
 		# encode the content into json
@@ -735,6 +820,7 @@ class ContentApiController extends ContentController
 		{
 		{
 			return $response->withJson(['errors' => ['message' => 'Could not write to file. Please check if the file is writable']], 404);
 			return $response->withJson(['errors' => ['message' => 'Could not write to file. Please check if the file is writable']], 404);
 		}
 		}
-		return $response->withJson(array('markdown' => $this->content, 'errors' => false));
+				
+		return $response->withJson(array('markdown' => $pageMarkdown, 'errors' => false));
 	}
 	}
 }
 }

+ 5 - 2
system/Controllers/ContentBackendController.php

@@ -111,7 +111,6 @@ class ContentBackendController extends ContentController
 		if(!$this->setContent()){ return $this->renderIntern404($response, array( 'navigation' => $this->structure, 'settings' => $this->settings, 'content' => $this->errors )); }
 		if(!$this->setContent()){ return $this->renderIntern404($response, array( 'navigation' => $this->structure, 'settings' => $this->settings, 'content' => $this->errors )); }
 
 
 		$content = $this->content;
 		$content = $this->content;
-		$title = false;
 
 
 		if($content == '')
 		if($content == '')
 		{
 		{
@@ -136,7 +135,11 @@ class ContentBackendController extends ContentController
 			/* parse markdown-content-array to content-string */
 			/* parse markdown-content-array to content-string */
 			$content[$key]	= $parsedown->markup($contentArray);			
 			$content[$key]	= $parsedown->markup($contentArray);			
 		}
 		}
-		
+
+		# extract title and delete from content array, array will start at 1 after that.
+		$title = $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, 'title' => $title, 'content' => $content, 'item' => $this->item, 'settings' => $this->settings ));
 	}
 	}
 	
 	

+ 4 - 4
system/Controllers/PageController.php

@@ -132,7 +132,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);
-		
+				
 		/* parse markdown-content-array to content-string */
 		/* parse markdown-content-array to content-string */
 		$contentHTML	= $parsedown->markup($contentArray);
 		$contentHTML	= $parsedown->markup($contentArray);
 		$contentHTML 	= $this->c->dispatcher->dispatch('onHtmlLoaded', new OnHtmlLoaded($contentHTML))->getData();
 		$contentHTML 	= $this->c->dispatcher->dispatch('onHtmlLoaded', new OnHtmlLoaded($contentHTML))->getData();
@@ -216,11 +216,11 @@ class PageController extends Controller
 		foreach($contentBlocks as $block)
 		foreach($contentBlocks as $block)
 		{
 		{
 			/* is it a paragraph? */
 			/* is it a paragraph? */
-			if(isset($block['element']['name']) && $block['element']['name'] == 'p')
+			if(isset($block['name']) && $block['name'] == 'p')
 			{
 			{
-				if(isset($block['element']['handler']['argument']) && substr($block['element']['handler']['argument'], 0, 2) == '![' )
+				if(isset($block['handler']['argument']) && substr($block['handler']['argument'], 0, 2) == '![' )
 				{
 				{
-					return $block['element']['handler']['argument'];	
+					return $block['handler']['argument'];	
 				}
 				}
 			}
 			}
 		}
 		}

+ 24 - 0
system/Extensions/TwigMarkdownExtension.php

@@ -0,0 +1,24 @@
+<?php
+
+namespace Typemill\Extensions;
+
+use Typemill\Extensions\ParsedownExtension;
+
+class TwigMarkdownExtension extends \Twig_Extension
+{
+	public function getFunctions()
+	{
+		return [
+			new \Twig_SimpleFunction('markdown', array($this, 'renderMarkdown' ))
+		];
+	}
+		
+	public function renderMarkdown($markdown)
+	{		
+		$parsedown = new ParsedownExtension();
+		
+		$markdownArray = $parsedown->text($markdown);
+		
+		return $parsedown->markup($markdownArray);
+	}
+}

+ 2 - 1
system/Routes/Api.php

@@ -17,4 +17,5 @@ $app->post('/api/v1/article/sort', ContentApiController::class . ':sortArticle')
 $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->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']));
-$app->delete('/api/v1/block', ContentApiController::class . ':deleteBlock')->setName('api.block.delete')->add(new RestrictApiAccess($container['router']));
+$app->delete('/api/v1/block', ContentApiController::class . ':deleteBlock')->setName('api.block.delete')->add(new RestrictApiAccess($container['router']));
+$app->put('/api/v1/moveblock', ContentApiController::class . ':moveBlock')->setName('api.block.move')->add(new RestrictApiAccess($container['router']));

+ 21 - 9
system/author/css/fontello/config.json

@@ -6,12 +6,6 @@
   "units_per_em": 1000,
   "units_per_em": 1000,
   "ascent": 850,
   "ascent": 850,
   "glyphs": [
   "glyphs": [
-    {
-      "uid": "c5845105a87df2ee1999826d90622f6a",
-      "css": "paragraph",
-      "code": 61917,
-      "src": "fontawesome"
-    },
     {
     {
       "uid": "f9cbf7508cd04145ade2800169959eef",
       "uid": "f9cbf7508cd04145ade2800169959eef",
       "css": "font",
       "css": "font",
@@ -60,6 +54,12 @@
       "code": 61618,
       "code": 61618,
       "src": "fontawesome"
       "src": "fontawesome"
     },
     },
+    {
+      "uid": "5408be43f7c42bccee419c6be53fdef5",
+      "css": "doc-text",
+      "code": 61686,
+      "src": "fontawesome"
+    },
     {
     {
       "uid": "b091a8bd0fdade174951f17d936f51e4",
       "uid": "b091a8bd0fdade174951f17d936f51e4",
       "css": "folder-empty",
       "css": "folder-empty",
@@ -67,9 +67,21 @@
       "src": "fontawesome"
       "src": "fontawesome"
     },
     },
     {
     {
-      "uid": "5408be43f7c42bccee419c6be53fdef5",
-      "css": "doc-text",
-      "code": 61686,
+      "uid": "d3b3f17bc3eb7cd809a07bbd4d178bee",
+      "css": "resize-vertical",
+      "code": 59398,
+      "src": "fontawesome"
+    },
+    {
+      "uid": "6605ee6441bf499ffa3c63d3c7409471",
+      "css": "move",
+      "code": 61511,
+      "src": "fontawesome"
+    },
+    {
+      "uid": "5211af474d3a9848f67f945e2ccaf143",
+      "css": "cancel",
+      "code": 59399,
       "src": "fontawesome"
       "src": "fontawesome"
     }
     }
   ]
   ]

+ 4 - 2
system/author/css/fontello/css/fontello-codes.css

@@ -5,8 +5,10 @@
 .icon-off:before { content: '\e803'; } /* '' */
 .icon-off:before { content: '\e803'; } /* '' */
 .icon-home:before { content: '\e804'; } /* '' */
 .icon-home:before { content: '\e804'; } /* '' */
 .icon-plus:before { content: '\e805'; } /* '' */
 .icon-plus:before { content: '\e805'; } /* '' */
+.icon-resize-vertical:before { content: '\e806'; } /* '' */
+.icon-cancel:before { content: '\e807'; } /* '' */
+.icon-move:before { content: '\f047'; } /* '' */
 .icon-link-ext:before { content: '\f08e'; } /* '' */
 .icon-link-ext:before { content: '\f08e'; } /* '' */
 .icon-resize-full-alt:before { content: '\f0b2'; } /* '' */
 .icon-resize-full-alt:before { content: '\f0b2'; } /* '' */
 .icon-doc-text:before { content: '\f0f6'; } /* '' */
 .icon-doc-text:before { content: '\f0f6'; } /* '' */
-.icon-folder-empty:before { content: '\f114'; } /* '' */
-.icon-paragraph:before { content: '\f1dd'; } /* '' */
+.icon-folder-empty:before { content: '\f114'; } /* '' */

文件差異過大導致無法顯示
+ 3 - 3
system/author/css/fontello/css/fontello-embedded.css


+ 4 - 2
system/author/css/fontello/css/fontello-ie7-codes.css

@@ -5,8 +5,10 @@
 .icon-off { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe803;&nbsp;'); }
 .icon-off { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe803;&nbsp;'); }
 .icon-home { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe804;&nbsp;'); }
 .icon-home { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe804;&nbsp;'); }
 .icon-plus { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe805;&nbsp;'); }
 .icon-plus { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe805;&nbsp;'); }
+.icon-resize-vertical { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe806;&nbsp;'); }
+.icon-cancel { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe807;&nbsp;'); }
+.icon-move { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf047;&nbsp;'); }
 .icon-link-ext { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf08e;&nbsp;'); }
 .icon-link-ext { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf08e;&nbsp;'); }
 .icon-resize-full-alt { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0b2;&nbsp;'); }
 .icon-resize-full-alt { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0b2;&nbsp;'); }
 .icon-doc-text { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0f6;&nbsp;'); }
 .icon-doc-text { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0f6;&nbsp;'); }
-.icon-folder-empty { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf114;&nbsp;'); }
-.icon-paragraph { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf1dd;&nbsp;'); }
+.icon-folder-empty { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf114;&nbsp;'); }

+ 4 - 2
system/author/css/fontello/css/fontello-ie7.css

@@ -16,8 +16,10 @@
 .icon-off { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe803;&nbsp;'); }
 .icon-off { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe803;&nbsp;'); }
 .icon-home { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe804;&nbsp;'); }
 .icon-home { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe804;&nbsp;'); }
 .icon-plus { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe805;&nbsp;'); }
 .icon-plus { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe805;&nbsp;'); }
+.icon-resize-vertical { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe806;&nbsp;'); }
+.icon-cancel { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe807;&nbsp;'); }
+.icon-move { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf047;&nbsp;'); }
 .icon-link-ext { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf08e;&nbsp;'); }
 .icon-link-ext { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf08e;&nbsp;'); }
 .icon-resize-full-alt { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0b2;&nbsp;'); }
 .icon-resize-full-alt { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0b2;&nbsp;'); }
 .icon-doc-text { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0f6;&nbsp;'); }
 .icon-doc-text { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0f6;&nbsp;'); }
-.icon-folder-empty { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf114;&nbsp;'); }
-.icon-paragraph { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf1dd;&nbsp;'); }
+.icon-folder-empty { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf114;&nbsp;'); }

+ 11 - 9
system/author/css/fontello/css/fontello.css

@@ -1,11 +1,11 @@
 @font-face {
 @font-face {
   font-family: 'fontello';
   font-family: 'fontello';
-  src: url('../font/fontello.eot?94639617');
-  src: url('../font/fontello.eot?94639617#iefix') format('embedded-opentype'),
-       url('../font/fontello.woff2?94639617') format('woff2'),
-       url('../font/fontello.woff?94639617') format('woff'),
-       url('../font/fontello.ttf?94639617') format('truetype'),
-       url('../font/fontello.svg?94639617#fontello') format('svg');
+  src: url('../font/fontello.eot?89525311');
+  src: url('../font/fontello.eot?89525311#iefix') format('embedded-opentype'),
+       url('../font/fontello.woff2?89525311') format('woff2'),
+       url('../font/fontello.woff?89525311') format('woff'),
+       url('../font/fontello.ttf?89525311') format('truetype'),
+       url('../font/fontello.svg?89525311#fontello') format('svg');
   font-weight: normal;
   font-weight: normal;
   font-style: normal;
   font-style: normal;
 }
 }
@@ -15,7 +15,7 @@
 @media screen and (-webkit-min-device-pixel-ratio:0) {
 @media screen and (-webkit-min-device-pixel-ratio:0) {
   @font-face {
   @font-face {
     font-family: 'fontello';
     font-family: 'fontello';
-    src: url('../font/fontello.svg?94639617#fontello') format('svg');
+    src: url('../font/fontello.svg?89525311#fontello') format('svg');
   }
   }
 }
 }
 */
 */
@@ -61,8 +61,10 @@
 .icon-off:before { content: '\e803'; } /* '' */
 .icon-off:before { content: '\e803'; } /* '' */
 .icon-home:before { content: '\e804'; } /* '' */
 .icon-home:before { content: '\e804'; } /* '' */
 .icon-plus:before { content: '\e805'; } /* '' */
 .icon-plus:before { content: '\e805'; } /* '' */
+.icon-resize-vertical:before { content: '\e806'; } /* '' */
+.icon-cancel:before { content: '\e807'; } /* '' */
+.icon-move:before { content: '\f047'; } /* '' */
 .icon-link-ext:before { content: '\f08e'; } /* '' */
 .icon-link-ext:before { content: '\f08e'; } /* '' */
 .icon-resize-full-alt:before { content: '\f0b2'; } /* '' */
 .icon-resize-full-alt:before { content: '\f0b2'; } /* '' */
 .icon-doc-text:before { content: '\f0f6'; } /* '' */
 .icon-doc-text:before { content: '\f0f6'; } /* '' */
-.icon-folder-empty:before { content: '\f114'; } /* '' */
-.icon-paragraph:before { content: '\f1dd'; } /* '' */
+.icon-folder-empty:before { content: '\f114'; } /* '' */

+ 11 - 7
system/author/css/fontello/demo.html

@@ -229,11 +229,11 @@ body {
 }
 }
 @font-face {
 @font-face {
       font-family: 'fontello';
       font-family: 'fontello';
-      src: url('./font/fontello.eot?32756715');
-      src: url('./font/fontello.eot?32756715#iefix') format('embedded-opentype'),
-           url('./font/fontello.woff?32756715') format('woff'),
-           url('./font/fontello.ttf?32756715') format('truetype'),
-           url('./font/fontello.svg?32756715#fontello') format('svg');
+      src: url('./font/fontello.eot?63828600');
+      src: url('./font/fontello.eot?63828600#iefix') format('embedded-opentype'),
+           url('./font/fontello.woff?63828600') format('woff'),
+           url('./font/fontello.ttf?63828600') format('truetype'),
+           url('./font/fontello.svg?63828600#fontello') format('svg');
       font-weight: normal;
       font-weight: normal;
       font-style: normal;
       font-style: normal;
     }
     }
@@ -306,13 +306,17 @@ body {
       <div class="row">
       <div class="row">
         <div class="the-icons span3" title="Code: 0xe804"><i class="demo-icon icon-home">&#xe804;</i> <span class="i-name">icon-home</span><span class="i-code">0xe804</span></div>
         <div class="the-icons span3" title="Code: 0xe804"><i class="demo-icon icon-home">&#xe804;</i> <span class="i-name">icon-home</span><span class="i-code">0xe804</span></div>
         <div class="the-icons span3" title="Code: 0xe805"><i class="demo-icon icon-plus">&#xe805;</i> <span class="i-name">icon-plus</span><span class="i-code">0xe805</span></div>
         <div class="the-icons span3" title="Code: 0xe805"><i class="demo-icon icon-plus">&#xe805;</i> <span class="i-name">icon-plus</span><span class="i-code">0xe805</span></div>
+        <div class="the-icons span3" title="Code: 0xe806"><i class="demo-icon icon-resize-vertical">&#xe806;</i> <span class="i-name">icon-resize-vertical</span><span class="i-code">0xe806</span></div>
+        <div class="the-icons span3" title="Code: 0xe807"><i class="demo-icon icon-cancel">&#xe807;</i> <span class="i-name">icon-cancel</span><span class="i-code">0xe807</span></div>
+      </div>
+      <div class="row">
+        <div class="the-icons span3" title="Code: 0xf047"><i class="demo-icon icon-move">&#xf047;</i> <span class="i-name">icon-move</span><span class="i-code">0xf047</span></div>
         <div class="the-icons span3" title="Code: 0xf08e"><i class="demo-icon icon-link-ext">&#xf08e;</i> <span class="i-name">icon-link-ext</span><span class="i-code">0xf08e</span></div>
         <div class="the-icons span3" title="Code: 0xf08e"><i class="demo-icon icon-link-ext">&#xf08e;</i> <span class="i-name">icon-link-ext</span><span class="i-code">0xf08e</span></div>
         <div class="the-icons span3" title="Code: 0xf0b2"><i class="demo-icon icon-resize-full-alt">&#xf0b2;</i> <span class="i-name">icon-resize-full-alt</span><span class="i-code">0xf0b2</span></div>
         <div class="the-icons span3" title="Code: 0xf0b2"><i class="demo-icon icon-resize-full-alt">&#xf0b2;</i> <span class="i-name">icon-resize-full-alt</span><span class="i-code">0xf0b2</span></div>
+        <div class="the-icons span3" title="Code: 0xf0f6"><i class="demo-icon icon-doc-text">&#xf0f6;</i> <span class="i-name">icon-doc-text</span><span class="i-code">0xf0f6</span></div>
       </div>
       </div>
       <div class="row">
       <div class="row">
-        <div class="the-icons span3" title="Code: 0xf0f6"><i class="demo-icon icon-doc-text">&#xf0f6;</i> <span class="i-name">icon-doc-text</span><span class="i-code">0xf0f6</span></div>
         <div class="the-icons span3" title="Code: 0xf114"><i class="demo-icon icon-folder-empty">&#xf114;</i> <span class="i-name">icon-folder-empty</span><span class="i-code">0xf114</span></div>
         <div class="the-icons span3" title="Code: 0xf114"><i class="demo-icon icon-folder-empty">&#xf114;</i> <span class="i-name">icon-folder-empty</span><span class="i-code">0xf114</span></div>
-        <div class="the-icons span3" title="Code: 0xf1dd"><i class="demo-icon icon-paragraph">&#xf1dd;</i> <span class="i-name">icon-paragraph</span><span class="i-code">0xf1dd</span></div>
       </div>
       </div>
     </div>
     </div>
     <div class="container footer">Generated by <a href="http://fontello.com">fontello.com</a></div>
     <div class="container footer">Generated by <a href="http://fontello.com">fontello.com</a></div>

二進制
system/author/css/fontello/font/fontello.eot


+ 6 - 2
system/author/css/fontello/font/fontello.svg

@@ -18,6 +18,12 @@
 
 
 <glyph glyph-name="plus" unicode="&#xe805;" d="M786 439v-107q0-22-16-38t-38-15h-232v-233q0-22-16-37t-38-16h-107q-22 0-38 16t-15 37v233h-232q-23 0-38 15t-16 38v107q0 23 16 38t38 16h232v232q0 22 15 38t38 16h107q23 0 38-16t16-38v-232h232q23 0 38-16t16-38z" horiz-adv-x="785.7" />
 <glyph glyph-name="plus" unicode="&#xe805;" d="M786 439v-107q0-22-16-38t-38-15h-232v-233q0-22-16-37t-38-16h-107q-22 0-38 16t-15 37v233h-232q-23 0-38 15t-16 38v107q0 23 16 38t38 16h232v232q0 22 15 38t38 16h107q23 0 38-16t16-38v-232h232q23 0 38-16t16-38z" horiz-adv-x="785.7" />
 
 
+<glyph glyph-name="resize-vertical" unicode="&#xe806;" d="M393 671q0-14-11-25t-25-10h-71v-572h71q15 0 25-10t11-25-11-25l-143-143q-10-11-25-11t-25 11l-143 143q-10 10-10 25t10 25 25 10h72v572h-72q-14 0-25 10t-10 25 10 26l143 142q11 11 25 11t25-11l143-142q11-11 11-26z" horiz-adv-x="428.6" />
+
+<glyph glyph-name="cancel" unicode="&#xe807;" d="M724 112q0-22-15-38l-76-76q-16-15-38-15t-38 15l-164 165-164-165q-16-15-38-15t-38 15l-76 76q-16 16-16 38t16 38l164 164-164 164q-16 16-16 38t16 38l76 76q16 16 38 16t38-16l164-164 164 164q16 16 38 16t38-16l76-76q15-15 15-38t-15-38l-164-164 164-164q15-15 15-38z" horiz-adv-x="785.7" />
+
+<glyph glyph-name="move" unicode="&#xf047;" d="M1000 350q0-14-11-25l-142-143q-11-11-26-11t-25 11-10 25v72h-215v-215h72q14 0 25-10t11-25-11-25l-143-143q-10-11-25-11t-25 11l-143 143q-11 10-11 25t11 25 25 10h72v215h-215v-72q0-14-10-25t-25-11-25 11l-143 143q-11 11-11 25t11 25l143 143q10 11 25 11t25-11 10-25v-72h215v215h-72q-14 0-25 10t-11 25 11 26l143 142q11 11 25 11t25-11l143-142q11-11 11-26t-11-25-25-10h-72v-215h215v72q0 14 10 25t25 11 26-11l142-143q11-10 11-25z" horiz-adv-x="1000" />
+
 <glyph glyph-name="link-ext" unicode="&#xf08e;" d="M786 332v-178q0-67-47-114t-114-47h-464q-67 0-114 47t-47 114v464q0 66 47 113t114 48h393q7 0 12-5t5-13v-36q0-8-5-13t-12-5h-393q-37 0-63-26t-27-63v-464q0-37 27-63t63-27h464q37 0 63 27t26 63v178q0 8 5 13t13 5h36q8 0 13-5t5-13z m214 482v-285q0-15-11-25t-25-11-25 11l-98 98-364-364q-5-6-13-6t-12 6l-64 64q-6 5-6 12t6 13l364 364-98 98q-11 11-11 25t11 25 25 11h285q15 0 25-11t11-25z" horiz-adv-x="1000" />
 <glyph glyph-name="link-ext" unicode="&#xf08e;" d="M786 332v-178q0-67-47-114t-114-47h-464q-67 0-114 47t-47 114v464q0 66 47 113t114 48h393q7 0 12-5t5-13v-36q0-8-5-13t-12-5h-393q-37 0-63-26t-27-63v-464q0-37 27-63t63-27h464q37 0 63 27t26 63v178q0 8 5 13t13 5h36q8 0 13-5t5-13z m214 482v-285q0-15-11-25t-25-11-25 11l-98 98-364-364q-5-6-13-6t-12 6l-64 64q-6 5-6 12t6 13l364 364-98 98q-11 11-11 25t11 25 25 11h285q15 0 25-11t11-25z" horiz-adv-x="1000" />
 
 
 <glyph glyph-name="resize-full-alt" unicode="&#xf0b2;" d="M716 548l-198-198 198-198 80 80q17 18 39 8 22-9 22-33v-250q0-14-10-25t-26-11h-250q-23 0-32 23-10 21 7 38l81 81-198 198-198-198 80-81q17-17 8-38-10-23-33-23h-250q-15 0-25 11t-11 25v250q0 24 22 33 22 10 39-8l80-80 198 198-198 198-80-80q-11-11-25-11-7 0-14 3-22 9-22 33v250q0 14 11 25t25 11h250q23 0 33-23 9-21-8-38l-80-81 198-198 198 198-81 81q-17 17-7 38 9 23 32 23h250q15 0 26-11t10-25v-250q0-24-22-33-7-3-14-3-14 0-25 11z" horiz-adv-x="857.1" />
 <glyph glyph-name="resize-full-alt" unicode="&#xf0b2;" d="M716 548l-198-198 198-198 80 80q17 18 39 8 22-9 22-33v-250q0-14-10-25t-26-11h-250q-23 0-32 23-10 21 7 38l81 81-198 198-198-198 80-81q17-17 8-38-10-23-33-23h-250q-15 0-25 11t-11 25v250q0 24 22 33 22 10 39-8l80-80 198 198-198 198-80-80q-11-11-25-11-7 0-14 3-22 9-22 33v250q0 14 11 25t25 11h250q23 0 33-23 9-21-8-38l-80-81 198-198 198 198-81 81q-17 17-7 38 9 23 32 23h250q15 0 26-11t10-25v-250q0-24-22-33-7-3-14-3-14 0-25 11z" horiz-adv-x="857.1" />
@@ -25,8 +31,6 @@
 <glyph glyph-name="doc-text" unicode="&#xf0f6;" d="M819 638q16-16 27-42t11-50v-642q0-23-15-38t-38-16h-750q-23 0-38 16t-16 38v892q0 23 16 38t38 16h500q22 0 49-11t42-27z m-248 136v-210h210q-5 17-12 23l-175 175q-6 7-23 12z m215-853v572h-232q-23 0-38 16t-16 37v233h-429v-858h715z m-572 483q0 7 5 12t13 5h393q8 0 13-5t5-12v-36q0-8-5-13t-13-5h-393q-8 0-13 5t-5 13v36z m411-125q8 0 13-5t5-13v-36q0-8-5-13t-13-5h-393q-8 0-13 5t-5 13v36q0 8 5 13t13 5h393z m0-143q8 0 13-5t5-13v-36q0-8-5-13t-13-5h-393q-8 0-13 5t-5 13v36q0 8 5 13t13 5h393z" horiz-adv-x="857.1" />
 <glyph glyph-name="doc-text" unicode="&#xf0f6;" d="M819 638q16-16 27-42t11-50v-642q0-23-15-38t-38-16h-750q-23 0-38 16t-16 38v892q0 23 16 38t38 16h500q22 0 49-11t42-27z m-248 136v-210h210q-5 17-12 23l-175 175q-6 7-23 12z m215-853v572h-232q-23 0-38 16t-16 37v233h-429v-858h715z m-572 483q0 7 5 12t13 5h393q8 0 13-5t5-12v-36q0-8-5-13t-13-5h-393q-8 0-13 5t-5 13v36z m411-125q8 0 13-5t5-13v-36q0-8-5-13t-13-5h-393q-8 0-13 5t-5 13v36q0 8 5 13t13 5h393z m0-143q8 0 13-5t5-13v-36q0-8-5-13t-13-5h-393q-8 0-13 5t-5 13v36q0 8 5 13t13 5h393z" horiz-adv-x="857.1" />
 
 
 <glyph glyph-name="folder-empty" unicode="&#xf114;" d="M857 118v393q0 22-15 38t-38 15h-393q-23 0-38 16t-16 38v36q0 22-15 38t-38 15h-179q-22 0-38-15t-16-38v-536q0-22 16-38t38-16h679q22 0 38 16t15 38z m72 393v-393q0-51-37-88t-88-37h-679q-51 0-88 37t-37 88v536q0 51 37 88t88 37h179q51 0 88-37t37-88v-18h375q51 0 88-37t37-88z" horiz-adv-x="928.6" />
 <glyph glyph-name="folder-empty" unicode="&#xf114;" d="M857 118v393q0 22-15 38t-38 15h-393q-23 0-38 16t-16 38v36q0 22-15 38t-38 15h-179q-22 0-38-15t-16-38v-536q0-22 16-38t38-16h679q22 0 38 16t15 38z m72 393v-393q0-51-37-88t-88-37h-679q-51 0-88 37t-37 88v536q0 51 37 88t88 37h179q51 0 88-37t37-88v-18h375q51 0 88-37t37-88z" horiz-adv-x="928.6" />
-
-<glyph glyph-name="paragraph" unicode="&#xf1dd;" d="M713 745v-41q0-16-10-34t-24-18q-28 0-30-1-14-3-18-17-1-6-1-36v-643q0-14-11-24t-24-10h-60q-14 0-24 10t-10 24v680h-80v-680q0-14-9-24t-25-10h-60q-14 0-24 10t-10 24v277q-82 7-137 33-70 33-107 100-36 65-36 145 0 92 50 159 49 66 116 89 62 21 233 21h267q14 0 24-10t10-24z" horiz-adv-x="714.3" />
 </font>
 </font>
 </defs>
 </defs>
 </svg>
 </svg>

二進制
system/author/css/fontello/font/fontello.ttf


二進制
system/author/css/fontello/font/fontello.woff


二進制
system/author/css/fontello/font/fontello.woff2


+ 16 - 6
system/author/css/style.css

@@ -1394,22 +1394,32 @@ label .help, .label .help{
 	border: 1px solid #e0474c;
 	border: 1px solid #e0474c;
 	color: #eee;
 	color: #eee;
 }
 }
-.blox-editor button.delete{
+.blox-editor .sideaction{
 	position: absolute;
 	position: absolute;
-	right: 1px;
-	top: 1px;
-	font-weight: 700;
+	right: -22px;
+	top: 0px;
+}
+.blox-editor button.delete, .blox-editor .icon-resize-full-alt{
+	display: block;
+	font-weight: 300;
+	font-size: 0.9em;
 	background: #fff;
 	background: #fff;
 	color: #fff;
 	color: #fff;
+	width: 20px;
+	height: 20px;
+	line-height: 20px;
+	text-align: center;
+	padding: 0px;
+	margin: 0px 0px 1px;
 	border: 0px;
 	border: 0px;
-	border-radius: 2px;
-	padding: 2px 4px;
+	border-radius: 1px;
 }
 }
 .blox-editor:hover button.delete{
 .blox-editor:hover button.delete{
 	background: #e0474c;
 	background: #e0474c;
 	color: #fff;
 	color: #fff;
 }
 }
 .blox-editor button.delete:hover{
 .blox-editor button.delete:hover{
+	cursor: pointer;
 	background: #cc4146;
 	background: #cc4146;
 }
 }
 .blox-editor button.edit:disabled, .blox-editor button.cancel:disabled{
 .blox-editor button.edit:disabled, .blox-editor button.cancel:disabled{

+ 11 - 11
system/author/editor/editor-blox.twig

@@ -6,24 +6,24 @@
 	<div class="formWrapper">
 	<div class="formWrapper">
 		
 		
 		<section id="blox">
 		<section id="blox">
-
-			<div class="blox-title"></div>
 			
 			
 			<div class="blox-body">
 			<div class="blox-body">
+			
+				<content-block class="title" :body="false">
+					<div class="blox title" @click="setData( $event, 'text-markdown')" data-id="0" id="blox-0">{{ title }}</div>
+				</content-block>
+
+				<div id="sortblox">
 				
 				
-				{% for id, block in content %}
-					{% if loop.first %}
-						<content-block class="title" :body="false">
-							<div class="blox title" @click="setData( $event, 'text-markdown')" data-id="{{ id }}" id="blox-{{id}}">{{block}}</div>
-						</content-block>						
-					{% else %}
+					{% for id, block in content %}
 						<content-block :body="true">
 						<content-block :body="true">
 							<div class="blox" @click="setData( $event, 'textarea-markdown' )" data-id="{{ id }}" id="blox-{{id}}">{{block}}</div>
 							<div class="blox" @click="setData( $event, 'textarea-markdown' )" data-id="{{ id }}" id="blox-{{id}}">{{block}}</div>
 						</content-block>
 						</content-block>
-					{% endif %}
-				{% endfor %}
+					{% endfor %}
 
 
-				<content-block :body="true" v-for="newBlock in newBlocks"><div class="blox" @click="setData( $event, 'textarea-markdown' )" :data-id="newBlock.id" :id="newBlock.blockId" v-html="newBlock.content"></div></content-block>
+					<content-block :body="true" v-for="newBlock in newBlocks"><div class="blox" @click="setData( $event, 'textarea-markdown' )" :data-id="newBlock.id" :id="newBlock.blockId" v-html="newBlock.content"></div></content-block>
+				
+				</div>
 				
 				
 				<div class="format-bar">
 				<div class="format-bar">
 					<content-block :body="false">
 					<content-block :body="false">

+ 23 - 1
system/author/js/author.js

@@ -301,4 +301,26 @@
 			
 			
 			
 			
 		})(thisTarget);		
 		})(thisTarget);		
-    }
+    }
+	
+	/**
+	 * Element.closest() polyfill
+	 * https://developer.mozilla.org/en-US/docs/Web/API/Element/closest#Polyfill
+	 */
+	if (!Element.prototype.closest) {
+		if (!Element.prototype.matches) {
+			Element.prototype.matches = Element.prototype.msMatchesSelector || Element.prototype.webkitMatchesSelector;
+		}
+		Element.prototype.closest = function (s) {
+			var el = this;
+			var ancestor = this;
+			if (!document.documentElement.contains(el)) return null;
+			do {
+				if (ancestor.matches(s)) return ancestor;
+				ancestor = ancestor.parentElement;
+			} while (ancestor !== null);
+			return null;
+		};
+	}
+
+	

+ 106 - 4
system/author/js/vue-blox.js

@@ -11,7 +11,7 @@ const contentComponent = Vue.component('content-block', {
 	},
 	},
 	methods: {
 	methods: {
 		getData: function()
 		getData: function()
-		{			
+		{
 			self = this;
 			self = this;
 			
 			
 			if(self.$root.$data.freeze == false && self.$root.$data.blockType != '')
 			if(self.$root.$data.freeze == false && self.$root.$data.blockType != '')
@@ -21,7 +21,25 @@ const contentComponent = Vue.component('content-block', {
 				this.edit = true;
 				this.edit = true;
 				this.compmarkdown = self.$root.$data.blockMarkdown;
 				this.compmarkdown = self.$root.$data.blockMarkdown;
 				this.componentType = self.$root.$data.blockType;
 				this.componentType = self.$root.$data.blockType;
+				self.$root.sortable.option("disabled",true);
 			}
 			}
+			/*
+				window.addEventListener('click', function(e)
+				{
+					if (!e.target.closest('.editactive'))
+					{
+						console.info('not found');
+						publishController.errors.message = false;
+						
+						this.preview = 'visible';
+						this.edit = false;
+						this.compmarkdown = '';
+						self.componentType = false;
+						self.$root.$data.freeze = false;
+						self.$root.sortable.option("disabled",false);
+					}
+				});
+			*/
 		},
 		},
 		cancelBlock: function()
 		cancelBlock: function()
 		{
 		{
@@ -32,6 +50,7 @@ const contentComponent = Vue.component('content-block', {
 			this.componentType = false;
 			this.componentType = false;
 			self = this;
 			self = this;
 			self.$root.$data.freeze = false;
 			self.$root.$data.freeze = false;
+			self.$root.sortable.option("disabled",false);
 		},
 		},
  		submitBlock: function(e){
  		submitBlock: function(e){
 			var emptyline = /^\s*$(?:\r\n?|\n)/gm;
 			var emptyline = /^\s*$(?:\r\n?|\n)/gm;
@@ -47,9 +66,11 @@ const contentComponent = Vue.component('content-block', {
 					this.componentType = false;
 					this.componentType = false;
 					self = this;
 					self = this;
 					self.$root.$data.freeze = false;
 					self.$root.$data.freeze = false;
+					self.$root.sortable.option("disabled",false);
 				}
 				}
 				else
 				else
 				{
 				{
+					self.$root.sortable.option("disabled",false);
 					this.saveBlock();
 					this.saveBlock();
 				}
 				}
 			}
 			}
@@ -129,8 +150,9 @@ const contentComponent = Vue.component('content-block', {
 			}, method, url, params);
 			}, method, url, params);
 		},
 		},
 		deleteBlock: function(event)
 		deleteBlock: function(event)
-		{
-			var bloxeditor = event.target.parentElement;
+		{	
+			var bloxeditor = event.target.parentElement.parentElement;
+			console.info(bloxeditor);
 			var bloxid = bloxeditor.getElementsByClassName('blox')[0].dataset.id;
 			var bloxid = bloxeditor.getElementsByClassName('blox')[0].dataset.id;
 			bloxeditor.id = "delete-"+bloxid;
 			bloxeditor.id = "delete-"+bloxid;
 			
 			
@@ -181,6 +203,7 @@ const contentComponent = Vue.component('content-block', {
 						var length = blox.length;
 						var length = blox.length;
 						for (var i = 0; i < length; i++ ) {
 						for (var i = 0; i < length; i++ ) {
 							blox[i].id = "blox-" + i;
 							blox[i].id = "blox-" + i;
+							blox[i].dataset.id = i;
 						}
 						}
 
 
 						self.$root.$data.freeze = false;
 						self.$root.$data.freeze = false;
@@ -195,7 +218,26 @@ const contentComponent = Vue.component('content-block', {
 			}, method, url, params);
 			}, method, url, params);
 		},
 		},
 	},
 	},
-	template: '<div class="blox-editor"><div><div @keyup.enter="submitBlock" @click="getData"><transition name="fade-editor"><component :disabled="disabled" :compmarkdown="compmarkdown" @updatedMarkdown="compmarkdown = $event" :is="componentType"></component></transition><div :class="preview"><slot></slot></div></div><div class="blox-buttons" v-if="edit"><button class="edit" :disabled="disabled" @click.prevent="saveBlock">save</button><button class="cancel" :disabled="disabled" @click.prevent="cancelBlock">cancel</button></div><button v-if="body" class="delete" :disabled="disabled" title="delete content-block" @click.prevent="deleteBlock($event)">x</button></div></div>',
+	/*
+	mounted: function() {
+		var self = this;
+		
+		self.sortable = new Sortable(sortblox, {
+			animation: 150,
+			onEnd: function (evt) {
+				var params = {
+					'url':			document.getElementById("path").value,
+					'old_index': 	evt.oldIndex,
+					'new_index':	evt.newIndex,
+					'csrf_name': 	document.getElementById("csrf_name").value,
+					'csrf_value':	document.getElementById("csrf_value").value,
+				};
+				self.moveBlock(params);
+			},
+		});
+	},
+	*/
+	template: '<div class="blox-editor"><div :class="{ editactive: edit }"><div @keyup.enter="submitBlock" @click="getData"><transition name="fade-editor"><component :disabled="disabled" :compmarkdown="compmarkdown" @updatedMarkdown="compmarkdown = $event" :is="componentType"></component></transition><div :class="preview"><slot></slot></div></div><div class="blox-buttons" v-if="edit"><button class="edit" :disabled="disabled" @click.prevent="saveBlock">save</button><button class="cancel" :disabled="disabled" @click.prevent="cancelBlock">cancel</button></div><div class="sideaction" v-if="body"><button class="delete" :disabled="disabled" title="delete content-block" @click.prevent="deleteBlock($event)"><i class="icon-cancel"></i></button></div></div></div>',
 })
 })
 
 
 const textareaComponent = Vue.component('textarea-markdown', {
 const textareaComponent = Vue.component('textarea-markdown', {
@@ -291,6 +333,20 @@ let editor = new Vue({
 				}
 				}
 			}
 			}
 		}, method, url, params);
 		}, method, url, params);
+		
+		self.sortable = new Sortable(sortblox, {
+			animation: 150,
+			onEnd: function (evt) {
+				var params = {
+					'url':			document.getElementById("path").value,
+					'old_index': 	evt.oldIndex,
+					'new_index':	evt.newIndex,
+					'csrf_name': 	document.getElementById("csrf_name").value,
+					'csrf_value':	document.getElementById("csrf_value").value,
+				};
+				self.moveBlock(params);
+			},
+		});		
 	},
 	},
 	methods: {
 	methods: {
 		setData: function(event, blocktype, body)
 		setData: function(event, blocktype, body)
@@ -299,5 +355,51 @@ let editor = new Vue({
 			this.blockType = blocktype;
 			this.blockType = blocktype;
 			this.blockMarkdown = this.markdown[this.blockId];
 			this.blockMarkdown = this.markdown[this.blockId];
 		},
 		},
+		moveBlock: function(params)
+		{
+			publishController.errors.message = false;
+
+			var url = this.root + '/api/v1/moveblock';
+		
+			var self = this;			
+						
+			var method 	= 'PUT';
+			
+			sendJson(function(response, httpStatus)
+			{
+				if(httpStatus == 400)
+				{
+				}
+				if(response)
+				{
+				
+					var result = JSON.parse(response);
+
+					if(result.errors)
+					{
+						publishController.errors.message = result.errors;
+						publishController.publishDisabled = false;
+						return false;
+					}
+					else
+					{
+						var blox = document.getElementsByClassName("blox");
+						var length = blox.length;
+						for (var i = 0; i < length; i++ ) {
+							blox[i].id = "blox-" + i;
+							blox[i].dataset.id = i;
+						}
+
+						self.freeze = false;
+						self.markdown = result.markdown;
+						self.blockMarkdown = '';
+						self.blockType = '';
+
+						publishController.publishDisabled = false;
+						publishController.publishResult = "";
+					}
+				}
+			}, method, url, params);			
+		},
 	}
 	}
 });
 });

+ 1 - 0
system/system.php

@@ -164,6 +164,7 @@ $container['view'] = function ($container)
     $view->addExtension(new Slim\Views\TwigExtension($container['router'], $basePath));
     $view->addExtension(new Slim\Views\TwigExtension($container['router'], $basePath));
 	$view->addExtension(new Twig_Extension_Debug());
 	$view->addExtension(new Twig_Extension_Debug());
     $view->addExtension(new Typemill\Extensions\TwigUserExtension());
     $view->addExtension(new Typemill\Extensions\TwigUserExtension());
+	$view->addExtension(new Typemill\Extensions\TwigMarkdownExtension());	
 	
 	
 	/* use {{ base_url() }} in twig templates */
 	/* use {{ base_url() }} in twig templates */
 	$view['base_url']	 = $container['request']->getUri()->getBaseUrl();
 	$view['base_url']	 = $container['request']->getUri()->getBaseUrl();

部分文件因文件數量過多而無法顯示