소스 검색

Version 1.2.5: Create Pages

Sebastian 6 년 전
부모
커밋
77985ccacb
85개의 변경된 파일619개의 추가작업 그리고 158개의 파일을 삭제
  1. 1 1
      cache/lastCache.txt
  2. 0 0
      content/00-typemill/00-use-cases.md
  3. 1 1
      content/00-typemill/01-roadmap.md
  4. 0 0
      content/00-typemill/02-features.md
  5. 0 0
      content/01-getting-started/00-system-requirements.md
  6. 0 0
      content/01-getting-started/01-installation.md
  7. 2 1
      content/01-getting-started/02-settings.md
  8. 0 0
      content/01-getting-started/03-update.md
  9. 0 0
      content/01-getting-started/index.md
  10. 0 1
      content/02-for writers/00-quick start.txt
  11. 1 0
      content/02-for-writers/00-quick start.md
  12. 0 0
      content/02-for-writers/01-author panel.md
  13. 0 0
      content/02-for-writers/02-naming files and folders.md
  14. 0 0
      content/02-for-writers/03-folder structure.md
  15. 0 0
      content/02-for-writers/04-mardown.md
  16. 0 0
      content/02-for-writers/05-google sitemap.md
  17. 0 0
      content/02-for-writers/06-themes.md
  18. 0 0
      content/02-for-writers/07-plugins.md
  19. 0 0
      content/02-for-writers/08-forgot password.md
  20. 0 0
      content/02-for-writers/index.md
  21. 0 0
      content/03-for-theme-developers/00-quick start.md
  22. 0 0
      content/03-for-theme-developers/01-theme structure.md
  23. 0 0
      content/03-for-theme-developers/02-theme meta.md
  24. 0 0
      content/03-for-theme-developers/03-asset tags.md
  25. 0 0
      content/03-for-theme-developers/04-twig.md
  26. 0 0
      content/03-for-theme-developers/05-theme variables/00-content.md
  27. 0 0
      content/03-for-theme-developers/05-theme variables/01-title.md
  28. 0 0
      content/03-for-theme-developers/05-theme variables/02-description.md
  29. 0 0
      content/03-for-theme-developers/05-theme variables/03-image.md
  30. 0 0
      content/03-for-theme-developers/05-theme variables/04-base url.md
  31. 0 0
      content/03-for-theme-developers/05-theme variables/05-item.md
  32. 0 0
      content/03-for-theme-developers/05-theme variables/06-breadcrumb.md
  33. 0 0
      content/03-for-theme-developers/05-theme variables/07-navigation.md
  34. 0 0
      content/03-for-theme-developers/05-theme variables/08-settings.md
  35. 0 0
      content/03-for-theme-developers/05-theme variables/index.md
  36. 0 0
      content/03-for-theme-developers/index.md
  37. 0 0
      content/04-for-plugin-developers/00-intro.md
  38. 0 0
      content/04-for-plugin-developers/01-tutorial/00-cookie consent plugin.md
  39. 0 0
      content/04-for-plugin-developers/01-tutorial/01-write the yaml file.md
  40. 0 0
      content/04-for-plugin-developers/01-tutorial/02-write the php file.md
  41. 0 0
      content/04-for-plugin-developers/01-tutorial/03-add methods.md
  42. 0 0
      content/04-for-plugin-developers/01-tutorial/04-create the structure.md
  43. 0 0
      content/04-for-plugin-developers/01-tutorial/05-add twig template.md
  44. 0 0
      content/04-for-plugin-developers/01-tutorial/06-add default values.md
  45. 0 0
      content/04-for-plugin-developers/01-tutorial/07-use variables in twig.md
  46. 0 0
      content/04-for-plugin-developers/01-tutorial/08-make variables editable.md
  47. 0 0
      content/04-for-plugin-developers/01-tutorial/index.md
  48. 0 0
      content/04-for-plugin-developers/02-documentation/00-file structure.md
  49. 0 0
      content/04-for-plugin-developers/02-documentation/01-configuration file.md
  50. 0 0
      content/04-for-plugin-developers/02-documentation/02-field overview.md
  51. 0 0
      content/04-for-plugin-developers/02-documentation/03-basic php file.md
  52. 0 0
      content/04-for-plugin-developers/02-documentation/04-event overview.md
  53. 0 0
      content/04-for-plugin-developers/02-documentation/05-method overview.md
  54. 0 0
      content/04-for-plugin-developers/02-documentation/06-routes.md
  55. 0 0
      content/04-for-plugin-developers/02-documentation/07-middleware.md
  56. 0 0
      content/04-for-plugin-developers/02-documentation/index.md
  57. 0 0
      content/04-for-plugin-developers/index.md
  58. 0 0
      content/05-info/00-release-notes.md
  59. 0 0
      content/05-info/01-usage-and-licence.md
  60. 0 0
      content/05-info/02-Imprint-and-privacy.md
  61. 0 0
      content/05-info/03-markdown-test.md
  62. 203 11
      system/Controllers/ContentApiController.php
  63. 2 2
      system/Controllers/ContentBackendController.php
  64. 60 9
      system/Controllers/ContentController.php
  65. 37 0
      system/Models/Validation.php
  66. 5 56
      system/Models/Write.php
  67. 5 1
      system/Routes/Api.php
  68. 24 24
      system/author/css/fontello/config.json
  69. 2 2
      system/author/css/fontello/css/fontello-codes.css
  70. 3 3
      system/author/css/fontello/css/fontello-embedded.css
  71. 2 2
      system/author/css/fontello/css/fontello-ie7-codes.css
  72. 2 2
      system/author/css/fontello/css/fontello-ie7.css
  73. 9 9
      system/author/css/fontello/css/fontello.css
  74. 7 7
      system/author/css/fontello/demo.html
  75. BIN
      system/author/css/fontello/font/fontello.eot
  76. 2 2
      system/author/css/fontello/font/fontello.svg
  77. BIN
      system/author/css/fontello/font/fontello.ttf
  78. BIN
      system/author/css/fontello/font/fontello.woff
  79. BIN
      system/author/css/fontello/font/fontello.woff2
  80. 64 3
      system/author/css/style.css
  81. 10 0
      system/author/intern404.twig
  82. 2 2
      system/author/js/vue-editor.js
  83. 128 15
      system/author/js/vue-navi.js
  84. 34 0
      system/author/layouts/layoutBlank.twig
  85. 13 4
      system/author/partials/editorNavi.twig

+ 1 - 1
cache/lastCache.txt

@@ -1 +1 @@
-1537594730
+1538860826

+ 0 - 0
content/00-typemill/00-use cases.md → content/00-typemill/00-use-cases.md


+ 1 - 1
content/00-typemill/02-roadmap.md → content/00-typemill/01-roadmap.md

@@ -1,6 +1,6 @@
 # Roadmap
 # Roadmap
 
 
-There are a lot of plans for future releases of TYPEMILL, but it also follows the concept of simplicity. To prevent TYPEMILL from becomming a feature soup, it will strictly focus on the writers needs. 
+There are a lot of plans for future releases of TYPEMILL, but it also follows the concept of simplicity. To prevent TYPEMILL from becomming a feature soup, it will strictly focus on the writers needs.
 
 
 Here are some **milestones** of the past:
 Here are some **milestones** of the past:
 
 

+ 0 - 0
content/00-typemill/01-features.md → content/00-typemill/02-features.md


+ 0 - 0
content/01-getting started/00-system requirements.md → content/01-getting-started/00-system-requirements.md


+ 0 - 0
content/01-getting started/02-installation.md → content/01-getting-started/01-installation.md


+ 2 - 1
content/01-getting started/03-settings.md → content/01-getting-started/02-settings.md

@@ -1,6 +1,6 @@
 # Settings
 # Settings
 
 
-As of Version 1.1.3 you can edit all settings in the new author panel of TYPEMILL. Just visit the url `yourwebsite.com/tm/login` and go to settings after the login. There you can edit:
+As of Version 1.1.3 you can edit all settings in the new author panel of TYPEMILL. Just visit the url `yourwebsite.com/tm/login` and go to settings after the login. There you can edit: 
 
 
 * The system (basic settings).
 * The system (basic settings).
 * Themes (choose themes and configure it).
 * Themes (choose themes and configure it).
@@ -13,6 +13,7 @@ All settings are stored in the `\settings` folder of TYPEMILL. It is not recomme
 
 
 There are some settings that are not available via the author panel. Most of them are not really useful, but if you are a developer and if you develop a theme or a plugin locally, you probably want to display a detailed error report. To do so, simply add the following line to the settings.yaml: 
 There are some settings that are not available via the author panel. Most of them are not really useful, but if you are a developer and if you develop a theme or a plugin locally, you probably want to display a detailed error report. To do so, simply add the following line to the settings.yaml: 
 
 
+
 ````
 ````
 displayErrorDetails: true
 displayErrorDetails: true
 ````
 ````

+ 0 - 0
content/01-getting started/04-update.md → content/01-getting-started/03-update.md


+ 0 - 0
content/01-getting started/index.md → content/01-getting-started/index.md


+ 0 - 1
content/02-for writers/00-quick start.txt

@@ -1 +0,0 @@
-["# Quick Start for Writers","You are a pro and don't want to read the whole manual? No problem, this is a quick overview:","- **Setup**: Login to your system and setup the system, the themes and the plugins in the author panel.\n- **Content**: Organize your content in folders and markdown files and put them in the `\\content` folder of TYPEMILL. \n- **Markdown**: Use the Markdown syntax for your content files. Markdown Extra (e.g. tables, footnotes) is supported, too.\n- **Naming conventions**: Use prefixes like `01-` or `aa_` to sort your folders and files.\n- **Index files**: Add an `index.md` file to a folder to create content for the folder itself.\n- **F5**: After some changes, use the `F5` key to refresh the navigation manually.\n- **Lean back** and let TYPEMILL create a nice website for you.","\nThe TYPEMILL system ships with this user manual in the content folder. Check how the files are written and how the folders are organized."]

+ 1 - 0
content/02-for writers/00-quick start.md → content/02-for-writers/00-quick start.md

@@ -10,4 +10,5 @@ You are a pro and don't want to read the whole manual? No problem, this is a qui
 - **F5**: After some changes, use the `F5` key to refresh the navigation manually.
 - **F5**: After some changes, use the `F5` key to refresh the navigation manually.
 - **Lean back** and let TYPEMILL create a nice website for you.
 - **Lean back** and let TYPEMILL create a nice website for you.
 
 
+
 The TYPEMILL system ships with this user manual in the content folder. Check how the files are written and how the folders are organized.
 The TYPEMILL system ships with this user manual in the content folder. Check how the files are written and how the folders are organized.

+ 0 - 0
content/02-for writers/01-author panel.md → content/02-for-writers/01-author panel.md


+ 0 - 0
content/02-for writers/02-naming files and folders.md → content/02-for-writers/02-naming files and folders.md


+ 0 - 0
content/02-for writers/03-folder structure.md → content/02-for-writers/03-folder structure.md


+ 0 - 0
content/02-for writers/04-mardown.md → content/02-for-writers/04-mardown.md


+ 0 - 0
content/02-for writers/05-google sitemap.md → content/02-for-writers/05-google sitemap.md


+ 0 - 0
content/02-for writers/06-themes.md → content/02-for-writers/06-themes.md


+ 0 - 0
content/02-for writers/07-plugins.md → content/02-for-writers/07-plugins.md


+ 0 - 0
content/02-for writers/08-forgot password.md → content/02-for-writers/08-forgot password.md


+ 0 - 0
content/02-for writers/index.md → content/02-for-writers/index.md


+ 0 - 0
content/03-for theme developers/00-quick start.md → content/03-for-theme-developers/00-quick start.md


+ 0 - 0
content/03-for theme developers/01-theme structure.md → content/03-for-theme-developers/01-theme structure.md


+ 0 - 0
content/03-for theme developers/02-theme meta.md → content/03-for-theme-developers/02-theme meta.md


+ 0 - 0
content/03-for theme developers/03-asset tags.md → content/03-for-theme-developers/03-asset tags.md


+ 0 - 0
content/03-for theme developers/04-twig.md → content/03-for-theme-developers/04-twig.md


+ 0 - 0
content/03-for theme developers/05-theme variables/00-content.md → content/03-for-theme-developers/05-theme variables/00-content.md


+ 0 - 0
content/03-for theme developers/05-theme variables/01-title.md → content/03-for-theme-developers/05-theme variables/01-title.md


+ 0 - 0
content/03-for theme developers/05-theme variables/02-description.md → content/03-for-theme-developers/05-theme variables/02-description.md


+ 0 - 0
content/03-for theme developers/05-theme variables/03-image.md → content/03-for-theme-developers/05-theme variables/03-image.md


+ 0 - 0
content/03-for theme developers/05-theme variables/04-base url.md → content/03-for-theme-developers/05-theme variables/04-base url.md


+ 0 - 0
content/03-for theme developers/05-theme variables/05-item.md → content/03-for-theme-developers/05-theme variables/05-item.md


+ 0 - 0
content/03-for theme developers/05-theme variables/06-breadcrumb.md → content/03-for-theme-developers/05-theme variables/06-breadcrumb.md


+ 0 - 0
content/03-for theme developers/05-theme variables/07-navigation.md → content/03-for-theme-developers/05-theme variables/07-navigation.md


+ 0 - 0
content/03-for theme developers/05-theme variables/08-settings.md → content/03-for-theme-developers/05-theme variables/08-settings.md


+ 0 - 0
content/03-for theme developers/05-theme variables/index.md → content/03-for-theme-developers/05-theme variables/index.md


+ 0 - 0
content/03-for theme developers/index.md → content/03-for-theme-developers/index.md


+ 0 - 0
content/04-for plugin developers/00-intro.md → content/04-for-plugin-developers/00-intro.md


+ 0 - 0
content/04-for plugin developers/01-tutorial/00-cookie consent plugin.md → content/04-for-plugin-developers/01-tutorial/00-cookie consent plugin.md


+ 0 - 0
content/04-for plugin developers/01-tutorial/01-write the yaml file.md → content/04-for-plugin-developers/01-tutorial/01-write the yaml file.md


+ 0 - 0
content/04-for plugin developers/01-tutorial/02-write the php file.md → content/04-for-plugin-developers/01-tutorial/02-write the php file.md


+ 0 - 0
content/04-for plugin developers/01-tutorial/03-add methods.md → content/04-for-plugin-developers/01-tutorial/03-add methods.md


+ 0 - 0
content/04-for plugin developers/01-tutorial/04-create the structure.md → content/04-for-plugin-developers/01-tutorial/04-create the structure.md


+ 0 - 0
content/04-for plugin developers/01-tutorial/05-add twig template.md → content/04-for-plugin-developers/01-tutorial/05-add twig template.md


+ 0 - 0
content/04-for plugin developers/01-tutorial/06-add default values.md → content/04-for-plugin-developers/01-tutorial/06-add default values.md


+ 0 - 0
content/04-for plugin developers/01-tutorial/07-use variables in twig.md → content/04-for-plugin-developers/01-tutorial/07-use variables in twig.md


+ 0 - 0
content/04-for plugin developers/01-tutorial/08-make variables editable.md → content/04-for-plugin-developers/01-tutorial/08-make variables editable.md


+ 0 - 0
content/04-for plugin developers/01-tutorial/index.md → content/04-for-plugin-developers/01-tutorial/index.md


+ 0 - 0
content/04-for plugin developers/02-documentation/00-file structure.md → content/04-for-plugin-developers/02-documentation/00-file structure.md


+ 0 - 0
content/04-for plugin developers/02-documentation/01-configuration file.md → content/04-for-plugin-developers/02-documentation/01-configuration file.md


+ 0 - 0
content/04-for plugin developers/02-documentation/02-field overview.md → content/04-for-plugin-developers/02-documentation/02-field overview.md


+ 0 - 0
content/04-for plugin developers/02-documentation/03-basic php file.md → content/04-for-plugin-developers/02-documentation/03-basic php file.md


+ 0 - 0
content/04-for plugin developers/02-documentation/04-event overview.md → content/04-for-plugin-developers/02-documentation/04-event overview.md


+ 0 - 0
content/04-for plugin developers/02-documentation/05-method overview.md → content/04-for-plugin-developers/02-documentation/05-method overview.md


+ 0 - 0
content/04-for plugin developers/02-documentation/06-routes.md → content/04-for-plugin-developers/02-documentation/06-routes.md


+ 0 - 0
content/04-for plugin developers/02-documentation/07-middleware.md → content/04-for-plugin-developers/02-documentation/07-middleware.md


+ 0 - 0
content/04-for plugin developers/02-documentation/index.md → content/04-for-plugin-developers/02-documentation/index.md


+ 0 - 0
content/04-for plugin developers/index.md → content/04-for-plugin-developers/index.md


+ 0 - 0
content/05-info/00-release notes.md → content/05-info/00-release-notes.md


+ 0 - 0
content/05-info/01-usage and licence.md → content/05-info/01-usage-and-licence.md


+ 0 - 0
content/05-info/02-Imprint and privacy.md → content/05-info/02-Imprint-and-privacy.md


+ 0 - 0
content/05-info/03-markdown test.md → content/05-info/03-markdown-test.md


+ 203 - 11
system/Controllers/ContentApiController.php

@@ -11,7 +11,7 @@ use Typemill\Extensions\ParsedownExtension;
 class ContentApiController extends ContentController
 class ContentApiController extends ContentController
 {
 {
 	public function publishArticle(Request $request, Response $response, $args)
 	public function publishArticle(Request $request, Response $response, $args)
-	{
+	{		
 		# get params from call 
 		# get params from call 
 		$this->params 	= $request->getParams();
 		$this->params 	= $request->getParams();
 		$this->uri 		= $request->getUri();
 		$this->uri 		= $request->getUri();
@@ -40,7 +40,10 @@ class ContentApiController extends ContentController
 			# update the file
 			# update the file
 			$delete = $this->deleteContentFiles(['txt']);
 			$delete = $this->deleteContentFiles(['txt']);
 			
 			
-			# update the structure
+			# update the internal structure
+			$this->setStructure($draft = true, $cache = false);
+			
+			# update the public structure
 			$this->setStructure($draft = false, $cache = false);
 			$this->setStructure($draft = false, $cache = false);
 
 
 			return $response->withJson(['success'], 200);
 			return $response->withJson(['success'], 200);
@@ -52,7 +55,7 @@ class ContentApiController extends ContentController
 	}
 	}
 
 
 	public function unpublishArticle(Request $request, Response $response, $args)
 	public function unpublishArticle(Request $request, Response $response, $args)
-	{
+	{		
 		# get params from call 
 		# get params from call 
 		$this->params 	= $request->getParams();
 		$this->params 	= $request->getParams();
 		$this->uri 		= $request->getUri();
 		$this->uri 		= $request->getUri();
@@ -99,6 +102,9 @@ class ContentApiController extends ContentController
 		
 		
 		if($delete)
 		if($delete)
 		{
 		{
+			# update the internal structure
+			$this->setStructure($draft = true, $cache = false);
+			
 			# update the live structure
 			# update the live structure
 			$this->setStructure($draft = false, $cache = false);
 			$this->setStructure($draft = false, $cache = false);
 			
 			
@@ -116,28 +122,50 @@ class ContentApiController extends ContentController
 		$this->params 	= $request->getParams();
 		$this->params 	= $request->getParams();
 		$this->uri 		= $request->getUri();
 		$this->uri 		= $request->getUri();
 
 
+		# set url to base path initially
+		$url = $this->uri->getBaseUrl() . '/tm/content';
+		
 		# set structure
 		# set structure
 		if(!$this->setStructure($draft = true)){ return $response->withJson($this->errors, 404); }
 		if(!$this->setStructure($draft = true)){ return $response->withJson($this->errors, 404); }
 
 
-		# set item 
+		# set item
 		if(!$this->setItem()){ return $response->withJson($this->errors, 404); }
 		if(!$this->setItem()){ return $response->withJson($this->errors, 404); }
 		
 		
-		# update the file
-		$delete = $this->deleteContentFiles(['md','txt']);
-		
+		if($this->item->elementType == 'file')
+		{
+			$delete = $this->deleteContentFiles(['md','txt']);
+		}
+		elseif($this->item->elementType == 'folder')
+		{
+			$delete = $this->deleteContentFolder();
+		}
+
 		if($delete)
 		if($delete)
 		{
 		{
+			# check if it is a subfile or subfolder and set the redirect-url to the parent item
+			if(count($this->item->keyPathArray) > 1)
+			{
+				# get the parent item
+				$parentItem = Folder::getParentItem($this->structure, $this->item->keyPathArray);
+
+				if($parentItem)
+				{
+					# an active file has been moved to another folder
+					$url .= $parentItem->urlRelWoF;
+				}
+			}
+			
 			# update the live structure
 			# update the live structure
 			$this->setStructure($draft = false, $cache = false);
 			$this->setStructure($draft = false, $cache = false);
-			
+				
 			#update the backend structure
 			#update the backend structure
 			$this->setStructure($draft = true, $cache = false);
 			$this->setStructure($draft = true, $cache = false);
 			
 			
-			return $response->withJson(['success'], 200);
+			return $response->withJson(array('data' => $this->structure, 'errors' => false, 'url' => $url), 200);
 		}
 		}
 		else
 		else
 		{
 		{
-			return $response->withJson(['errors' => ['message' => "Could not delete some files. Please check if the files exists and are writable"]], 404);
+			return $response->withJson(array('data' => $this->structure, 'errors' => $this->errors), 404); 
 		}
 		}
 	}
 	}
 	
 	
@@ -174,6 +202,9 @@ class ContentApiController extends ContentController
 		/* update the file */
 		/* update the file */
 		if($this->write->writeFile($this->settings['contentFolder'], $this->path, $contentJson))
 		if($this->write->writeFile($this->settings['contentFolder'], $this->path, $contentJson))
 		{
 		{
+			# update the internal structure
+			$this->setStructure($draft = true, $cache = false);
+			
 			return $response->withJson(['success'], 200);
 			return $response->withJson(['success'], 200);
 		}
 		}
 		else
 		else
@@ -278,10 +309,171 @@ class ContentApiController extends ContentController
 		
 		
 		return $response->withJson(array('data' => $internalStructure, 'errors' => false, 'url' => $url));
 		return $response->withJson(array('data' => $internalStructure, 'errors' => false, 'url' => $url));
 	}
 	}
+	
+	public function createArticle(Request $request, Response $response, $args)
+	{
+		# get params from call
+		$this->params 	= $request->getParams();
+		$this->uri 		= $request->getUri();
+		
+		# url is only needed, if an active page is moved
+		$url 			= false;
+		
+		# set structure
+		if(!$this->setStructure($draft = true)){ return $response->withJson(array('data' => false, 'errors' => $this->errors, 'url' => $url), 404); }
+		
+		# validate input
+		if(!$this->validateNaviItem()){ return $response->withJson(array('data' => $this->structure, 'errors' => 'Special Characters not allowed. Length between 1 and 20 chars.', 'url' => $url), 422); }
+		
+		# get the ids (key path) for item, old folder and new folder
+		$folderKeyPath 	= explode('.', $this->params['folder_id']);
+		
+		# get the item from structure
+		$folder			= Folder::getItemWithKeyPath($this->structure, $folderKeyPath);
 
 
-	public function createBlock(Request $request, Response $response, $args)
+		if(!$folder){ return $response->withJson(array('data' => $this->structure, 'errors' => 'We could not find this page. Please refresh and try again.', 'url' => $url), 404); }
+		
+		# Rename all files within the folder to make sure, that namings and orders are correct
+		# get the content of the target folder
+		$folderContent	= $folder->folderContent;
+		
+		# create the name for the new item
+		$nameParts = Folder::getStringParts($this->params['item_name']);		
+		$name 		= implode("-", $nameParts);
+		$slug		= $name;
+				
+		# initialize index
+		$index = 0;		
+		
+		# initialise write object
+		$write = new Write();
+
+		# iterate through the whole content of the new folder
+		$writeError = false;
+		
+		foreach($folderContent as $folderItem)
+		{
+			# check, if the same name as new item, then return an error
+			if($folderItem->slug == $slug)
+			{
+				return $response->withJson(array('data' => $this->structure, 'errors' => 'There is already a page with this name. Please choose another name.', 'url' => $url), 404);
+			}
+			
+			if(!$write->moveElement($folderItem, $folder->path, $index))
+			{
+				$writeError = true;
+			}
+			$index++;
+		}
+
+		if($writeError){ return $response->withJson(array('data' => $this->structure, 'errors' => 'Something went wrong. Please refresh the page and check, if all folders and files are writable.', 'url' => $url), 404); }
+
+		# add prefix number to the name
+		$namePath 	= $index > 9 ? $index . '-' . $name : '0' . $index . '-' . $name;
+		$folderPath	= 'content' . $folder->path;
+		
+		if($this->params['type'] == 'file')
+		{
+			if(!$write->writeFile($folderPath, $namePath . '.txt', ''))
+			{
+				return $response->withJson(array('data' => $this->structure, 'errors' => 'We could not create the file. Please refresh the page and check, if all folders and files are writable.', 'url' => $url), 404);
+			}
+		}
+		elseif($this->params['type'] == 'folder')
+		{
+			if(!$write->checkPath($folderPath . DIRECTORY_SEPARATOR . $namePath))
+			{
+				return $response->withJson(array('data' => $this->structure, 'errors' => 'We could not create the folder. Please refresh the page and check, if all folders and files are writable.', 'url' => $url), 404);
+			}
+			$write->writeFile($folderPath . DIRECTORY_SEPARATOR . $namePath, 'index.txt', '');
+		}
+		
+		# update the structure for editor
+		$this->setStructure($draft = true, $cache = false);
+
+		# get item for url and set it active again
+		if(isset($this->params['url']))
+		{
+			$activeItem = Folder::getItemForUrl($this->structure, $this->params['url']);
+		}
+
+		# activate this if you want to redirect after creating the page...
+		# $url = $this->uri->getBaseUrl() . '/tm/content' . $folder->urlRelWoF . '/' . $name;
+		
+		return $response->withJson(array('data' => $this->structure, 'errors' => false, 'url' => $url));
+	}
+
+	public function createBaseFolder(Request $request, Response $response, $args)
 	{
 	{
+		# get params from call
+		$this->params 	= $request->getParams();
+		$this->uri 		= $request->getUri();
 		
 		
+		# url is only needed, if an active page is moved
+		$url 			= false;
+		
+		# set structure
+		if(!$this->setStructure($draft = true)){ return $response->withJson(array('data' => false, 'errors' => $this->errors, 'url' => $url), 404); }
+		
+		# validate input
+		#if(!$this->validateBaseFolder()){ return $response->withJson(array('data' => $this->structure, 'errors' => 'Special Characters not allowed. Length between 1 and 20 chars.', 'url' => $url), 422); }
+				
+		# create the name for the new item
+		$nameParts 	= Folder::getStringParts($this->params['item_name']);		
+		$name 		= implode("-", $nameParts);
+		$slug		= $name;
+
+		# initialize index
+		$index = 0;		
+		
+		# initialise write object
+		$write = new Write();
+
+		# iterate through the whole content of the new folder
+		$writeError = false;
+		
+		foreach($this->structure as $folder)
+		{
+			# check, if the same name as new item, then return an error
+			if($folder->slug == $slug)
+			{
+				return $response->withJson(array('data' => $this->structure, 'errors' => 'There is already a page with this name. Please choose another name.', 'url' => $url), 404);
+			}
+			
+			if(!$write->moveElement($folder, '', $index))
+			{
+				$writeError = true;
+			}
+			$index++;
+		}
+
+		if($writeError){ return $response->withJson(array('data' => $this->structure, 'errors' => 'Something went wrong. Please refresh the page and check, if all folders and files are writable.', 'url' => $url), 404); }
+
+		# add prefix number to the name
+		$namePath 	= $index > 9 ? $index . '-' . $name : '0' . $index . '-' . $name;
+		$folderPath	= 'content';
+		
+		if(!$write->checkPath($folderPath . DIRECTORY_SEPARATOR . $namePath))
+		{
+			return $response->withJson(array('data' => $this->structure, 'errors' => 'We could not create the folder. Please refresh the page and check, if all folders and files are writable.', 'url' => $url), 404);
+		}
+		$write->writeFile($folderPath . DIRECTORY_SEPARATOR . $namePath, 'index.txt', '');
+		
+		# update the structure for editor
+		$this->setStructure($draft = true, $cache = false);
+
+		# 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, 'errors' => false, 'url' => $url));
+	}
+	
+	
+	public function createBlock(Request $request, Response $response, $args)
+	{
 		/* get params from call */
 		/* get params from call */
 		$this->params 	= $request->getParams();
 		$this->params 	= $request->getParams();
 		$this->uri 		= $request->getUri();
 		$this->uri 		= $request->getUri();

+ 2 - 2
system/Controllers/ContentBackendController.php

@@ -25,10 +25,10 @@ class ContentBackendController extends ContentController
 		$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->render404($response, array( 'navigation' => true, 'content' => $this->errors )); }
+		if(!$this->setStructure($draft = true)){ return $this->renderIntern404($response, array( 'navigation' => true, 'content' => $this->errors )); }
 		
 		
 		# set item
 		# set item
-		if(!$this->setItem()){ return $this->render404($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)
 		# 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;
 		$breadcrumb = isset($this->item->keyPathArray) ? Folder::getBreadcrumb($this->structure, $this->item->keyPathArray) : false;

+ 60 - 9
system/Controllers/ContentController.php

@@ -22,7 +22,7 @@ abstract class ContentController
 	protected $uri;
 	protected $uri;
 	
 	
 	# holds the errors to output in frontend 
 	# holds the errors to output in frontend 
-	protected $errors;
+	protected $errors = false;
 	
 	
 	# holds a write object to write files 
 	# holds a write object to write files 
 	protected $write;
 	protected $write;
@@ -81,6 +81,11 @@ abstract class ContentController
 		return $this->c->view->render($response->withStatus(404), '/404.twig', $data);
 		return $this->c->view->render($response->withStatus(404), '/404.twig', $data);
 	}
 	}
 	
 	
+	protected function renderIntern404($response, $data = NULL)
+	{
+		return $this->c->view->render($response->withStatus(404), '/intern404.twig', $data);
+	}	
+		
 	protected function validateEditorInput()
 	protected function validateEditorInput()
 	{
 	{
 		$validate = new Validation();
 		$validate = new Validation();
@@ -106,6 +111,19 @@ abstract class ContentController
 		}
 		}
 		return true;
 		return true;
 	}
 	}
+
+	protected function validateNaviItem()
+	{
+		$validate = new Validation();
+		$vResult = $validate->navigationItem($this->params);
+		
+		if(is_array($vResult))
+		{
+			$this->errors = ['errors' => $vResult];
+			return false;
+		}
+		return true;
+	}
 	
 	
 	protected function setStructure($draft = false, $cache = true)
 	protected function setStructure($draft = false, $cache = true)
 	{
 	{
@@ -176,6 +194,7 @@ abstract class ContentController
 			}
 			}
 			elseif($item->elementType == 'folder')
 			elseif($item->elementType == 'folder')
 			{
 			{
+				$item->pathWithoutItem		= $item->path;
 				$item->path 				= $item->path . DIRECTORY_SEPARATOR . 'index';
 				$item->path 				= $item->path . DIRECTORY_SEPARATOR . 'index';
 				$item->pathWithoutType		= $item->path;
 				$item->pathWithoutType		= $item->path;
 			}
 			}
@@ -221,24 +240,56 @@ abstract class ContentController
 		}
 		}
 	}
 	}
 		
 		
-	protected function deleteContentFiles($fileTypes)
+	protected function deleteContentFiles($fileTypes, $folder = false)
 	{
 	{
 		$basePath = $this->settings['rootPath'] . $this->settings['contentFolder'];
 		$basePath = $this->settings['rootPath'] . $this->settings['contentFolder'];
-		
+
 		foreach($fileTypes as $fileType)
 		foreach($fileTypes as $fileType)
 		{
 		{
-			if(file_exists($basePath . $this->item->pathWithoutType . '.' . $fileType))
+			if(file_exists($basePath . $this->item->pathWithoutType . '.' . $fileType) && !unlink($basePath . $this->item->pathWithoutType . '.' . $fileType) )
 			{
 			{
-				unlink($basePath . $this->item->pathWithoutType . '.' . $fileType);
-				
-				# if file could not be deleted
-				# $this->errors = ['errors' => ['message' => 'Could not delete files, please check, if files are writable.']];
-			}			
+				$this->errors = ['message' => 'We could not delete the file, please check, if the file is writable.'];				
+			}
+		}
+		
+		if($this->errors)
+		{
+			return false;
 		}
 		}
 		
 		
 		return true;
 		return true;
 	}
 	}
 	
 	
+	protected function deleteContentFolder()
+	{
+		$basePath = $this->settings['rootPath'] . $this->settings['contentFolder'];
+		$path = $basePath . $this->item->pathWithoutItem;
+
+		if(file_exists($path))
+		{
+			$files = array_diff(scandir($path), array('.', '..'));
+			
+			# check if there are folders first, then stop the operation
+			foreach ($files as $file)
+			{
+				if(is_dir(realpath($path) . DIRECTORY_SEPARATOR . $file))
+				{
+					$this->errors = ['message' => 'Please delete the sub-folder first.'];
+				}
+			}
+
+			if(!$this->errors)
+			{
+				foreach ($files as $file)
+				{
+					unlink(realpath($path) . DIRECTORY_SEPARATOR . $file);
+				}
+				return rmdir($path);
+			}
+		}
+		return false;
+	}
+	
 	protected function setContent()
 	protected function setContent()
 	{		
 	{		
 		# if the file exists
 		# if the file exists

+ 37 - 0
system/Models/Validation.php

@@ -54,6 +54,16 @@ class Validation
 			if(!$email){ return false; }
 			if(!$email){ return false; }
 			return true;
 			return true;
 		}, 'unknown');
 		}, 'unknown');
+
+		Validator::addRule('noSpecialChars', function($field, $value, array $params, array $fields)
+		{
+			$format = '/[!@#$%^&*()_+=\[\]{};\':"\\|,.<>\/?]/';
+			if ( preg_match($format, $value))
+			{
+				return false;
+			}
+			return true;
+		}, 'contains special characters');
 		
 		
 		Validator::addRule('noHTML', function($field, $value, array $params, array $fields)
 		Validator::addRule('noHTML', function($field, $value, array $params, array $fields)
 		{
 		{
@@ -241,6 +251,33 @@ class Validation
 			return $v->errors();
 			return $v->errors();
 		}
 		}
 	}
 	}
+
+	/**
+	* validation for new navigation items
+	* 
+	* @param array $params with form data.
+	* @return true or $v->errors with array of errors to use in json-response
+	*/
+
+	public function navigationItem(array $params)
+	{
+		$v = new Validator($params);
+						
+		$v->rule('required', ['folder_id', 'item_name', 'type', 'url']);
+		$v->rule('regex', 'folder_id', '/^[0-9.]+$/i');
+		$v->rule('noSpecialChars', 'item_name');
+		$v->rule('lengthBetween', 'item_name', 1, 20);
+		$v->rule('in', 'type', ['file', 'folder']);
+		
+		if($v->validate()) 
+		{
+			return true;
+		} 
+		else
+		{
+			return $v->errors();
+		}
+	}	
 	
 	
 	/**
 	/**
 	* validation for dynamic fields ( settings for themes and plugins)
 	* validation for dynamic fields ( settings for themes and plugins)

+ 5 - 56
system/Models/Write.php

@@ -15,7 +15,7 @@ class Write
 	public function checkPath($folder)
 	public function checkPath($folder)
 	{
 	{
 		$folderPath = $this->basePath . $folder;
 		$folderPath = $this->basePath . $folder;
-		
+				
 		if(!is_dir($folderPath))
 		if(!is_dir($folderPath))
 		{
 		{
 			if(@mkdir($folderPath, 0774, true))
 			if(@mkdir($folderPath, 0774, true))
@@ -55,6 +55,7 @@ class Write
 		if($this->checkPath($folder))
 		if($this->checkPath($folder))
 		{
 		{
 			$filePath 	= $this->basePath . $folder . DIRECTORY_SEPARATOR . $file;
 			$filePath 	= $this->basePath . $folder . DIRECTORY_SEPARATOR . $file;
+			
 			$openFile 	= @fopen($filePath, "w");
 			$openFile 	= @fopen($filePath, "w");
 			
 			
 			if(!$openFile)
 			if(!$openFile)
@@ -79,7 +80,7 @@ class Write
 		}
 		}
 		return false;
 		return false;
 	}
 	}
-
+	
 	public function moveElement($item, $folderPath, $index)
 	public function moveElement($item, $folderPath, $index)
 	{
 	{
 		$filetypes			= array('md', 'txt');
 		$filetypes			= array('md', 'txt');
@@ -88,7 +89,7 @@ class Write
 		$newOrder			= ($index < 10) ? '0' . $index : $index;
 		$newOrder			= ($index < 10) ? '0' . $index : $index;
 
 
 		# create new path with foldername or filename but without file-type
 		# create new path with foldername or filename but without file-type
-		$newPath 			= $this->basePath . 'content' . $folderPath . DIRECTORY_SEPARATOR . $newOrder . '-' . $item->name;
+		$newPath 			= $this->basePath . 'content' . $folderPath . DIRECTORY_SEPARATOR . $newOrder . '-' . str_replace(" ", "-", $item->name);
 		
 		
 		if($item->elementType == 'folder')
 		if($item->elementType == 'folder')
 		{
 		{
@@ -125,58 +126,6 @@ class Write
 			}
 			}
 		}
 		}
 
 
-		return $result;
-		
-		/*
-		if($item->elementType == 'folder')
-		{
-			$newName		= $newOrder . '-' . $item->name;
-		}
-		else
-		{
-			$newName		= $newOrder . '-' . $item->name . '.' . $item->fileType;
-		}
-		
-		$oldPath			= $this->basePath . 'content' . $item->path;
-		$newPath 			= $this->basePath . 'content' . $folderPath . DIRECTORY_SEPARATOR . $newName;
-
-		if(@rename($oldPath, $newPath))
-		{
-			$result = true;
-		}
-		
-		foreach($filetypes as $filetype)
-		{
-			#check if file exists
-			if(file_exists($oldPath))
-			{
-
-			}
-		}
-		
-		
-		# if it is a txt file, check, if there is a corresponding .md file and move it
-		if($result && $item->elementType == 'file' && $item->fileType == 'txt')
-		{
-			$result = false;
-			
-			$oldPath		= substr($item->path, 0, strpos($item->path, "."));
-			$oldPath		= $this->basePath . 'content' . $oldPath . '.md';
-
-			if(file_exists($oldPath))
-			{
-				$newName			= $newOrder . '-' . $item->name . '.md';
-				$newPath 			= $this->basePath . 'content' . $folderPath . DIRECTORY_SEPARATOR . $newName;
-				
-				if(@rename($oldPath, $newPath))
-				{
-					$result = true;
-				}
-			}
-		}
-		
-		return $result;
-		*/
-		
+		return $result;		
 	}
 	}
 }
 }

+ 5 - 1
system/Routes/Api.php

@@ -6,9 +6,13 @@ use Typemill\Controllers\ContentApiController;
 use Typemill\Middleware\RestrictApiAccess;
 use Typemill\Middleware\RestrictApiAccess;
 
 
 $app->get('/api/v1/themes', SettingsController::class . ':getThemeSettings')->setName('api.themes')->add(new RestrictApiAccess($container['router']));
 $app->get('/api/v1/themes', SettingsController::class . ':getThemeSettings')->setName('api.themes')->add(new RestrictApiAccess($container['router']));
+
 $app->post('/api/v1/article/publish', ContentApiController::class . ':publishArticle')->setName('api.article.publish')->add(new RestrictApiAccess($container['router']));
 $app->post('/api/v1/article/publish', ContentApiController::class . ':publishArticle')->setName('api.article.publish')->add(new RestrictApiAccess($container['router']));
 $app->delete('/api/v1/article/unpublish', ContentApiController::class . ':unpublishArticle')->setName('api.article.unpublish')->add(new RestrictApiAccess($container['router']));
 $app->delete('/api/v1/article/unpublish', ContentApiController::class . ':unpublishArticle')->setName('api.article.unpublish')->add(new RestrictApiAccess($container['router']));
+$app->post('/api/v1/article', ContentApiController::class . ':createArticle')->setName('api.article.create')->add(new RestrictApiAccess($container['router']));
 $app->put('/api/v1/article', ContentApiController::class . ':updateArticle')->setName('api.article.update')->add(new RestrictApiAccess($container['router']));
 $app->put('/api/v1/article', ContentApiController::class . ':updateArticle')->setName('api.article.update')->add(new RestrictApiAccess($container['router']));
 $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/block', ContentBackendController::class . ':createBlock')->setName('api.block.create')->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/block', ContentBackendController::class . ':createBlock')->setName('api.block.create')->add(new RestrictApiAccess($container['router']));

+ 24 - 24
system/author/css/fontello/config.json

@@ -6,24 +6,6 @@
   "units_per_em": 1000,
   "units_per_em": 1000,
   "ascent": 850,
   "ascent": 850,
   "glyphs": [
   "glyphs": [
-    {
-      "uid": "5408be43f7c42bccee419c6be53fdef5",
-      "css": "doc-text",
-      "code": 61686,
-      "src": "fontawesome"
-    },
-    {
-      "uid": "b091a8bd0fdade174951f17d936f51e4",
-      "css": "folder-empty",
-      "code": 61716,
-      "src": "fontawesome"
-    },
-    {
-      "uid": "6533bdc16ab201eb3f3b27ce989cab33",
-      "css": "folder-open-empty",
-      "code": 61717,
-      "src": "fontawesome"
-    },
     {
     {
       "uid": "e99461abfef3923546da8d745372c995",
       "uid": "e99461abfef3923546da8d745372c995",
       "css": "cog",
       "css": "cog",
@@ -36,6 +18,18 @@
       "code": 59393,
       "code": 59393,
       "src": "fontawesome"
       "src": "fontawesome"
     },
     },
+    {
+      "uid": "8b9e6a8dd8f67f7c003ed8e7e5ee0857",
+      "css": "off",
+      "code": 59394,
+      "src": "fontawesome"
+    },
+    {
+      "uid": "d7271d490b71df4311e32cdacae8b331",
+      "css": "home",
+      "code": 59395,
+      "src": "fontawesome"
+    },
     {
     {
       "uid": "e15f0d620a7897e2035c18c80142f6d9",
       "uid": "e15f0d620a7897e2035c18c80142f6d9",
       "css": "link-ext",
       "css": "link-ext",
@@ -49,15 +43,21 @@
       "src": "fontawesome"
       "src": "fontawesome"
     },
     },
     {
     {
-      "uid": "8b9e6a8dd8f67f7c003ed8e7e5ee0857",
-      "css": "off",
-      "code": 59394,
+      "uid": "5408be43f7c42bccee419c6be53fdef5",
+      "css": "doc-text",
+      "code": 61686,
       "src": "fontawesome"
       "src": "fontawesome"
     },
     },
     {
     {
-      "uid": "d7271d490b71df4311e32cdacae8b331",
-      "css": "home",
-      "code": 59395,
+      "uid": "b091a8bd0fdade174951f17d936f51e4",
+      "css": "folder-empty",
+      "code": 61716,
+      "src": "fontawesome"
+    },
+    {
+      "uid": "44e04715aecbca7f266a17d5a7863c68",
+      "css": "plus",
+      "code": 59396,
       "src": "fontawesome"
       "src": "fontawesome"
     }
     }
   ]
   ]

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

@@ -3,8 +3,8 @@
 .icon-picture:before { content: '\e801'; } /* '' */
 .icon-picture:before { content: '\e801'; } /* '' */
 .icon-off:before { content: '\e802'; } /* '' */
 .icon-off:before { content: '\e802'; } /* '' */
 .icon-home:before { content: '\e803'; } /* '' */
 .icon-home:before { content: '\e803'; } /* '' */
+.icon-plus:before { content: '\e804'; } /* '' */
 .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-folder-open-empty:before { content: '\f115'; } /* '' */
+.icon-folder-empty:before { content: '\f114'; } /* '' */

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 3 - 3
system/author/css/fontello/css/fontello-embedded.css


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

@@ -3,8 +3,8 @@
 .icon-picture { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe801;&nbsp;'); }
 .icon-picture { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe801;&nbsp;'); }
 .icon-off { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe802;&nbsp;'); }
 .icon-off { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe802;&nbsp;'); }
 .icon-home { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe803;&nbsp;'); }
 .icon-home { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe803;&nbsp;'); }
+.icon-plus { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe804;&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-folder-open-empty { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf115;&nbsp;'); }
+.icon-folder-empty { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf114;&nbsp;'); }

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

@@ -14,8 +14,8 @@
 .icon-picture { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe801;&nbsp;'); }
 .icon-picture { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe801;&nbsp;'); }
 .icon-off { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe802;&nbsp;'); }
 .icon-off { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe802;&nbsp;'); }
 .icon-home { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe803;&nbsp;'); }
 .icon-home { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe803;&nbsp;'); }
+.icon-plus { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe804;&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-folder-open-empty { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf115;&nbsp;'); }
+.icon-folder-empty { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf114;&nbsp;'); }

+ 9 - 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?55717473');
-  src: url('../font/fontello.eot?55717473#iefix') format('embedded-opentype'),
-       url('../font/fontello.woff2?55717473') format('woff2'),
-       url('../font/fontello.woff?55717473') format('woff'),
-       url('../font/fontello.ttf?55717473') format('truetype'),
-       url('../font/fontello.svg?55717473#fontello') format('svg');
+  src: url('../font/fontello.eot?95383779');
+  src: url('../font/fontello.eot?95383779#iefix') format('embedded-opentype'),
+       url('../font/fontello.woff2?95383779') format('woff2'),
+       url('../font/fontello.woff?95383779') format('woff'),
+       url('../font/fontello.ttf?95383779') format('truetype'),
+       url('../font/fontello.svg?95383779#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?55717473#fontello') format('svg');
+    src: url('../font/fontello.svg?95383779#fontello') format('svg');
   }
   }
 }
 }
 */
 */
@@ -59,8 +59,8 @@
 .icon-picture:before { content: '\e801'; } /* '' */
 .icon-picture:before { content: '\e801'; } /* '' */
 .icon-off:before { content: '\e802'; } /* '' */
 .icon-off:before { content: '\e802'; } /* '' */
 .icon-home:before { content: '\e803'; } /* '' */
 .icon-home:before { content: '\e803'; } /* '' */
+.icon-plus:before { content: '\e804'; } /* '' */
 .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-folder-open-empty:before { content: '\f115'; } /* '' */
+.icon-folder-empty:before { content: '\f114'; } /* '' */

+ 7 - 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?16979120');
-      src: url('./font/fontello.eot?16979120#iefix') format('embedded-opentype'),
-           url('./font/fontello.woff?16979120') format('woff'),
-           url('./font/fontello.ttf?16979120') format('truetype'),
-           url('./font/fontello.svg?16979120#fontello') format('svg');
+      src: url('./font/fontello.eot?67933592');
+      src: url('./font/fontello.eot?67933592#iefix') format('embedded-opentype'),
+           url('./font/fontello.woff?67933592') format('woff'),
+           url('./font/fontello.ttf?67933592') format('truetype'),
+           url('./font/fontello.svg?67933592#fontello') format('svg');
       font-weight: normal;
       font-weight: normal;
       font-style: normal;
       font-style: normal;
     }
     }
@@ -304,13 +304,13 @@ body {
         <div class="the-icons span3" title="Code: 0xe803"><i class="demo-icon icon-home">&#xe803;</i> <span class="i-name">icon-home</span><span class="i-code">0xe803</span></div>
         <div class="the-icons span3" title="Code: 0xe803"><i class="demo-icon icon-home">&#xe803;</i> <span class="i-name">icon-home</span><span class="i-code">0xe803</span></div>
       </div>
       </div>
       <div class="row">
       <div class="row">
+        <div class="the-icons span3" title="Code: 0xe804"><i class="demo-icon icon-plus">&#xe804;</i> <span class="i-name">icon-plus</span><span class="i-code">0xe804</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 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>
       </div>
       <div class="row">
       <div class="row">
-        <div class="the-icons span3" title="Code: 0xf115"><i class="demo-icon icon-folder-open-empty">&#xf115;</i> <span class="i-name">icon-folder-open-empty</span><span class="i-code">0xf115</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>
       </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>

BIN
system/author/css/fontello/font/fontello.eot


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

@@ -14,6 +14,8 @@
 
 
 <glyph glyph-name="home" unicode="&#xe803;" d="M786 296v-267q0-15-11-25t-25-11h-214v214h-143v-214h-214q-15 0-25 11t-11 25v267q0 1 0 2t0 2l321 264 321-264q1-1 1-4z m124 39l-34-41q-5-5-12-6h-2q-7 0-12 3l-386 322-386-322q-7-4-13-3-7 1-12 6l-35 41q-4 6-3 13t6 12l401 334q18 15 42 15t43-15l136-113v108q0 8 5 13t13 5h107q8 0 13-5t5-13v-227l122-102q6-4 6-12t-4-13z" horiz-adv-x="928.6" />
 <glyph glyph-name="home" unicode="&#xe803;" d="M786 296v-267q0-15-11-25t-25-11h-214v214h-143v-214h-214q-15 0-25 11t-11 25v267q0 1 0 2t0 2l321 264 321-264q1-1 1-4z m124 39l-34-41q-5-5-12-6h-2q-7 0-12 3l-386 322-386-322q-7-4-13-3-7 1-12 6l-35 41q-4 6-3 13t6 12l401 334q18 15 42 15t43-15l136-113v108q0 8 5 13t13 5h107q8 0 13-5t5-13v-227l122-102q6-4 6-12t-4-13z" horiz-adv-x="928.6" />
 
 
+<glyph glyph-name="plus" unicode="&#xe804;" 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="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" />
@@ -21,8 +23,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="folder-open-empty" unicode="&#xf115;" d="M994 331q0 19-30 19h-607q-22 0-48-12t-39-29l-164-203q-11-13-11-22 0-20 30-20h607q23 0 48 13t40 29l164 203q10 12 10 22z m-637 90h429v90q0 22-16 38t-38 15h-321q-23 0-38 16t-16 38v36q0 22-15 38t-38 15h-179q-22 0-38-15t-16-38v-476l143 175q25 30 65 49t78 19z m708-90q0-35-25-67l-165-203q-24-30-65-49t-78-19h-607q-51 0-88 37t-37 88v536q0 51 37 88t88 37h179q51 0 88-37t37-88v-18h303q52 0 88-37t37-88v-90h107q30 0 56-13t37-40q8-17 8-37z" horiz-adv-x="1071.4" />
 </font>
 </font>
 </defs>
 </defs>
 </svg>
 </svg>

BIN
system/author/css/fontello/font/fontello.ttf


BIN
system/author/css/fontello/font/fontello.woff


BIN
system/author/css/fontello/font/fontello.woff2


+ 64 - 3
system/author/css/style.css

@@ -212,7 +212,7 @@ li.menu-item{
 	padding: 0px;
 	padding: 0px;
 	position: relative;
 	position: relative;
 }
 }
-.navi-item i.icon-doc-text, .navi-item i.icon-folder-empty, .navi-item i.icon-home{
+.navi-item i.icon-doc-text, .navi-item i.icon-folder-empty, .navi-item i.icon-home, .navi-item i.icon-plus{
 	display: inline-block;
 	display: inline-block;
 	position: absolute;
 	position: absolute;
 	top: 0px;
 	top: 0px;
@@ -220,6 +220,10 @@ li.menu-item{
 	color: #ccc;
 	color: #ccc;
 	padding: 7px 2px 7px;
 	padding: 7px 2px 7px;
 }
 }
+.navi-item i.txt{
+	background: #e0474c;
+	color: #fff;
+}
 .navi-item i.icon-resize-full-alt{
 .navi-item i.icon-resize-full-alt{
 	position: absolute;
 	position: absolute;
 	right: 5px;
 	right: 5px;
@@ -231,7 +235,6 @@ li.menu-item{
 	padding: 7px 0;
 	padding: 7px 0;
 	width: 100%;
 	width: 100%;
 	margin-bottom: 2px;
 	margin-bottom: 2px;
-	box-shadow: 0 0 1px #ddd;
 	text-decoration: none;
 	text-decoration: none;
 	color: #444;
 	color: #444;
 	background: #fff;
 	background: #fff;
@@ -261,6 +264,64 @@ span.level-3{ padding-left: 50px; }
 span.level-4{ padding-left: 60px; }
 span.level-4{ padding-left: 60px; }
 span.level-5{ padding-left: 70px; }
 span.level-5{ padding-left: 70px; }
 
 
+.addNaviItem{
+	padding: 5px;
+	display: block;
+}
+.addNaviItem .hide{
+	height: 0px;
+	overflow: hidden;
+}
+a.addNaviLink, a.addNaviLink:link, a.addNaviLink:visited{
+	padding: 3px 0;
+	margin: 0;
+	width: auto;
+	background: transparent;
+	color: #e0474c;
+}
+a.addNaviLink:focus, a.addNaviLink:hover, a.addNaviLink:active{
+	text-decoration: underline;
+}
+.addNaviForm input{
+	min-height: 0px;
+	width: 100%;
+	background: #fff;
+	padding: 7px;
+	outline: 1px solid #efefef;
+}
+.addNaviForm button{
+	display: inline-block;
+	box-sizing: border-box;
+	margin: 5px 0 10px;
+	padding: 5px;
+	background: #e0474c;
+	color: #f9f8f6;
+	width: 50%;
+	border: 0px;
+	border-radius: 2px;
+}
+.addNaviForm button.fullWidth{
+	width: 100%;
+}
+.addNaviForm button:hover{
+	background: #cc4146;
+}
+.addNaviForm button.b-left{
+	border-right: 1px solid #f9f8f6;
+}
+.addNaviForm button.b-right{
+	border-left: 1px solid #f9f8f6;
+}
+.fade-enter-active {
+  transition: opacity 0.25s ease-out;
+}
+.fade-leave-active{
+  transition: opacity 0.1s ease-out;	
+}
+.fade-enter, .fade-leave-to {
+  opacity: 0;
+}
+
 /********************
 /********************
 *   	CONTENT		*
 *   	CONTENT		*
 ********************/
 ********************/
@@ -1393,7 +1454,7 @@ label .help, .label .help{
 	span.level-3{ padding-left: 35px; }
 	span.level-3{ padding-left: 35px; }
 	span.level-4{ padding-left: 50px; }
 	span.level-4{ padding-left: 50px; }
 	span.level-5{ padding-left: 65px; }
 	span.level-5{ padding-left: 65px; }
-	.navi-item i.icon-doc-text, .navi-item i.icon-folder-empty, .navi-item i.icon-home{
+	.navi-item i.icon-doc-text, .navi-item i.icon-folder-empty, .navi-item i.icon-home, .navi-item i.icon-plus{
 		left: -27px;
 		left: -27px;
 	}	
 	}	
 	fieldset.plugin{
 	fieldset.plugin{

+ 10 - 0
system/author/intern404.twig

@@ -0,0 +1,10 @@
+{% extends 'layouts/layoutBlank.twig' %}
+
+{% block title %}ERROR 404: Page not found{% endblock %}
+
+{% block content %}
+
+	<h1>Not Found</h1>
+	<p>Sorry, but we did not find the page that you are looking for.</p>
+	
+{% endblock %}

+ 2 - 2
system/author/js/vue-editor.js

@@ -168,10 +168,10 @@ let editor = new Vue({
 						self.modalWindow = "modal";
 						self.modalWindow = "modal";
 						if(result.errors.message){ self.errors.message = result.errors.message };
 						if(result.errors.message){ self.errors.message = result.errors.message };
 					}
 					}
-					else
+					else if(result.url)
 					{
 					{
 						self.modalWindow = "modal";
 						self.modalWindow = "modal";
-						window.location.replace(self.root + '/tm/content');
+						window.location.replace(result.url);
 					}
 					}
 				}
 				}
 			}, method, url, this.form );
 			}, method, url, this.form );

+ 128 - 15
system/author/js/vue-navi.js

@@ -1,6 +1,11 @@
 const navcomponent = Vue.component('navigation', {
 const navcomponent = Vue.component('navigation', {
 	template: '#navigation-template',
 	template: '#navigation-template',
-	props: ['name', 'parent', 'active', 'filetype', 'element', 'folder', 'level', 'url', 'root', 'freeze'],
+	props: ['name', 'newItem', 'parent', 'active', 'filetype', 'elementtype', 'element', 'folder', 'level', 'url', 'root', 'freeze'],
+	data: function () {
+		return {
+			showForm: false
+		}
+	},
 	methods: {
 	methods: {
 		checkMove : function(evt)
 		checkMove : function(evt)
 		{			
 		{			
@@ -26,14 +31,14 @@ const navcomponent = Vue.component('navigation', {
 				'item_id': 			evt.item.id,
 				'item_id': 			evt.item.id,
 				'parent_id_from': 	evt.from.parentNode.id, 
 				'parent_id_from': 	evt.from.parentNode.id, 
 				'parent_id_to': 	evt.to.parentNode.id, 
 				'parent_id_to': 	evt.to.parentNode.id, 
-				'index_old': 		evt.oldIndex, 
+				'index_old': 		evt.oldIndex,
 				'index_new': 		evt.newIndex,
 				'index_new': 		evt.newIndex,
 				'active':			evt.item.firstChild.className,
 				'active':			evt.item.firstChild.className,
 				'url':				document.getElementById("path").value,
 				'url':				document.getElementById("path").value,
 				'csrf_name': 		document.getElementById("csrf_name").value,
 				'csrf_name': 		document.getElementById("csrf_name").value,
 				'csrf_value':		document.getElementById("csrf_value").value,				
 				'csrf_value':		document.getElementById("csrf_value").value,				
 			};
 			};
-			
+						
 			if(locator.parent_id_from == locator.parent_id_to && locator.index_old == locator.index_new)
 			if(locator.parent_id_from == locator.parent_id_to && locator.index_old == locator.index_new)
 			{
 			{
 				return
 				return
@@ -82,15 +87,15 @@ const navcomponent = Vue.component('navigation', {
 			level = level.split('.').length;
 			level = level.split('.').length;
 			return 'level-' + level;
 			return 'level-' + level;
 		},
 		},
-		getIcon : function(filetype)
+		getIcon : function(elementtype, filetype)
 		{
 		{
-			if(filetype == 'file')
+			if(elementtype == 'file')
 			{
 			{
-				return 'icon-doc-text'
+				return 'icon-doc-text ' + filetype
 			}
 			}
-			if(filetype == 'folder')
+			if(elementtype == 'folder')
 			{
 			{
-				return 'icon-folder-empty'
+				return 'icon-folder-empty ' + filetype
 			}
 			}
 		},
 		},
 		checkActive : function(active,parent)
 		checkActive : function(active,parent)
@@ -100,7 +105,64 @@ const navcomponent = Vue.component('navigation', {
 				return 'active';
 				return 'active';
 			}
 			}
 			return 'inactive';
 			return 'inactive';
-		}
+		},
+		toggleForm : function()
+		{
+			this.showForm = !this.showForm;
+		},
+		addFile : function(type)
+		{
+			editor.errors.message = false;
+
+			if(this.$root.$data.format.test(this.newItem) || !this.newItem || this.newItem.length > 20)
+			{ 
+				editor.errors.message = 'Special Characters are not allowed. Length between 1 and 20.';
+				return;
+			}
+			
+			var newItem = {
+				'folder_id': 		this.$el.id,
+				'item_name': 		this.newItem,
+				'type':				type,
+				'url':				document.getElementById("path").value,
+				'csrf_name': 		document.getElementById("csrf_name").value,
+				'csrf_value':		document.getElementById("csrf_value").value,
+			};
+			
+			// evt.item.classList.add("load");
+			
+			var self = this;
+			
+			self.$root.$data.freeze = true;
+			self.errors = {title: false, content: false, message: false};
+			
+			var url = this.root + '/api/v1/article';
+			var method 	= 'POST';
+
+			sendJson(function(response, httpStatus)
+			{
+				if(response)
+				{
+					self.$root.$data.freeze = false;
+					var result = JSON.parse(response);
+					
+					if(result.errors)
+					{
+						editor.errors.message = result.errors;
+					}
+					if(result.url)
+					{
+						window.location.replace(result.url);
+					}
+					if(result.data)
+					{
+						// evt.item.classList.remove("load");
+						self.$root.$data.items = result.data;						
+						self.showForm = false;
+					}
+				}
+			}, method, url, newItem );
+		},
 	}
 	}
 })
 })
 
 
@@ -109,12 +171,16 @@ let navi = new Vue({
 	components: {
 	components: {
 		'navcomponent': navcomponent,
 		'navcomponent': navcomponent,
 	},
 	},
-	data: {
-		title: "Navigation",
-		items: JSON.parse(document.getElementById("data-navi").dataset.navi),
-		root: document.getElementById("main").dataset.url,
-		freeze: false,
-		modalWindow: "modal hide",		
+	data: function () {
+		return {
+			title: "Navigation",
+			items: JSON.parse(document.getElementById("data-navi").dataset.navi),
+			root: document.getElementById("main").dataset.url,
+			freeze: false,
+			modalWindow: "modal hide",
+			format: /[!@#$%^&*()_+=\[\]{};':"\\|,.<>\/?]/,
+			folderName: '',
+		}
 	},
 	},
 	methods:{
 	methods:{
 		onStart: function(evt){
 		onStart: function(evt){
@@ -129,5 +195,52 @@ let navi = new Vue({
 		hideModal: function(e){
 		hideModal: function(e){
 			this.modalWindow = "modal";
 			this.modalWindow = "modal";
 		},
 		},
+		addFolder: function()
+		{
+			editor.errors.message = false;
+
+			if(this.format.test(this.folderName) || this.folderName < 1 || this.folderName.length > 20)
+			{ 
+				editor.errors.message = 'Special Characters are not allowed. Length between 1 and 20.';
+				return;
+			}
+			
+			var newFolder = {
+				'item_name': 		this.folderName,
+				'url':				document.getElementById("path").value,
+				'csrf_name': 		document.getElementById("csrf_name").value,
+				'csrf_value':		document.getElementById("csrf_value").value,
+			};
+						
+			var self = this;
+			
+			self.freeze = true;
+			self.errors = {title: false, content: false, message: false};
+			
+			var url = this.root + '/api/v1/basefolder';
+			var method 	= 'POST';
+
+			sendJson(function(response, httpStatus)
+			{
+				if(response)
+				{
+					self.freeze = false;
+					var result = JSON.parse(response);
+					
+					if(result.errors)
+					{
+						editor.errors.message = result.errors;
+					}
+					if(result.url)
+					{
+						window.location.replace(result.url);
+					}
+					if(result.data)
+					{
+						self.items = result.data;						
+					}
+				}
+			}, method, url, newFolder );
+		}
 	}
 	}
 })
 })

+ 34 - 0
system/author/layouts/layoutBlank.twig

@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<html lang="en">
+	<head>
+		<meta charset="UTF-8">
+		<title>{% block title %}{% endblock %}</title>
+		<meta name="viewport" content="width=device-width, initial-scale=1.0" />
+
+		<meta name="description" content="Configure your TYPEMILL website"/>
+		
+		<meta name="msapplication-TileColor" content="#F9F8F6" />
+		<meta name="msapplication-TileImage" content="{{ base_url }}/system/author/img/mstile-144x144.png" />		
+		<link rel="icon" type="image/png" href="{{ base_url }}/system/author/img/favicon-32x32.png" sizes="32x32" />
+		<link rel="icon" type="image/png" href="{{ base_url }}/system/author/img/favicon-16x16.png" sizes="16x16" />
+		<link rel="apple-touch-icon-precomposed" sizes="144x144" href="{{ base_url }}/system/author/img/apple-touch-icon-144x144.png" />
+		<link rel="apple-touch-icon-precomposed" sizes="152x152" href="{{ base_url }}/system/author/img/apple-touch-icon-152x152.png" />		
+		
+		<link rel="stylesheet" href="{{ base_url }}/system/author/css/fontello/css/fontello.css" />
+		<link rel="stylesheet" href="{{ base_url }}/system/author/css/normalize.css" />
+		<link rel="stylesheet" href="{{ base_url }}/system/author/css/style.css" />
+	</head>
+	<body>	
+		<header class="main-header">
+			{% include 'partials/navi.twig' %}
+		</header>
+		{% include 'partials/flash.twig' %}
+		<div class="main" id="main" data-url="{{ base_url }}">
+			<aside class="sidebar"></aside>
+			<article>
+				{% block content %}{% endblock %}
+			</article>
+			<footer></footer>
+		</div>
+	</body>
+</html>

+ 13 - 4
system/author/partials/editorNavi.twig

@@ -9,8 +9,17 @@
 			</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" :filetype="item.elementType" :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" :folder="item.folderContent"></navigation>
 		</draggable>
 		</draggable>
+		<ul class="navi-list addBaseFolder">
+			<li class="navi-item file">
+				<i class="icon-plus"></i>
+				<div class="addNaviForm">
+					<input type="text" v-model="folderName" />
+					<button class="fullWidth" @click="addFolder">add folder to base level</button>
+				</div>
+			</li>
+		</ul>
 		
 		
 		<div id="modalWindow" :class="modalWindow">
 		<div id="modalWindow" :class="modalWindow">
 			<div class="modalInner wide">
 			<div class="modalInner wide">
@@ -32,11 +41,11 @@
 
 
 {% verbatim %}
 {% verbatim %}
 	<template id="navigation-template">
 	<template id="navigation-template">
-		<li class="navi-item" :class="filetype"><a v-bind:href="getUrl(root, url)" :class="checkActive(active,parent)"><i :class="getIcon(filetype)"></i><span :class="getLevel(level)">{{ name }}</span><i class="icon-resize-full-alt"></i></a>
+		<li class="navi-item" :class="elementtype"><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-resize-full-alt"></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.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" :elementtype="item.elementType" :folder="item.folderContent"></navigation>
 			</draggable>
 			</draggable>
-		<!--	<div v-if="folder">+ add</div> -->
+			<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>
 	</template>
 	</template>
 {% endverbatim %}
 {% endverbatim %}

이 변경점에서 너무 많은 파일들이 변경되어 몇몇 파일들은 표시되지 않았습니다.