diff --git a/content/00-welcome/05-todos.txt b/content/00-welcome/05-todos.txt index 9a4099c..9e30b0f 100644 --- a/content/00-welcome/05-todos.txt +++ b/content/00-welcome/05-todos.txt @@ -1 +1 @@ -["# ToDos Version 2","[TOC]","## Visual Editor","* FIXED: File is not published from tmp to media\/files if you save the block.","## Raw Editor","* DONE ready","## Medialib","* Please do next","## Posts","* Setup","## Plugins","* Asset Class","## Frontend","* DONE\n* DONE: Test restrictions","## ToDos","Biig blocks:","* Media Library\n* Posts\n* Recover Password","Small features:","* Sitemap and ping\n* Captcha\n* Clear Cache\n* Security Log\n* Backend fields\n* Proxy\n* DONE: Session handling: csrf fail and session start error if restrictions are active\n* Editor: Warn if open another block","Cleanups:","* Events\n* Error messages\n* Translations","## Select userroles","* Userroles for file restriction: in vue-blox-components loaded via api\n* Userroles for userfields: in php model user getUserFields()\n* Userroles for meta: in php controller apiAuthorMeta getMeta()\n* Plugins and themes: in php model extension getThemeDefinitions()","## License Check","* On activation in apiControllerExtension. It checks the license in yaml.\n* In plugin php code with setPremiumLicense\n* In static plugins, it checks manual premium list and method setPremiumLicense and more "] \ No newline at end of file +["# ToDos Version 2","[TOC]","## Visual Editor","* FIXED: File is not published from tmp to media\/files if you save the block.","## Raw Editor","* DONE ready","## Medialib","* DONE","## Posts","* Setup","## Plugins","* Asset Class","## Frontend","* DONE\n* DONE: Test restrictions","## ToDos","Biig blocks:","* DONE: Media Library\n* Posts\n* Recover Password","Small features:","* Sitemap and ping\n* Captcha\n* Clear Cache\n* Security Log\n* Backend fields\n* Proxy\n* DONE: Session handling: csrf fail and session start error if restrictions are active\n* Editor: Warn if open another block\n* Image generation on the fly\n* Assets","Cleanups:","* Events\n* Error messages\n* Translations","## Select userroles","* Userroles for file restriction: in vue-blox-components loaded via api\n* Userroles for userfields: in php model user getUserFields()\n* Userroles for meta: in php controller apiAuthorMeta getMeta()\n* Plugins and themes: in php model extension getThemeDefinitions()","## License Check","* On activation in apiControllerExtension. It checks the license in yaml.\n* In plugin php code with setPremiumLicense\n* In static plugins, it checks manual premium list and method setPremiumLicense and more "] \ No newline at end of file diff --git a/media/files/filerestrictions.yaml b/media/files/filerestrictions.yaml index 2b22b99..08e86cd 100644 --- a/media/files/filerestrictions.yaml +++ b/media/files/filerestrictions.yaml @@ -1 +1,2 @@ media/files/typemill-v2-navigation.gif: member +media/files/markdown.png: member diff --git a/media/tmp/screenshot-typemill-startpage.png b/media/tmp/screenshot-typemill-startpage.png new file mode 100644 index 0000000..3aef5e2 Binary files /dev/null and b/media/tmp/screenshot-typemill-startpage.png differ diff --git a/system/typemill/Controllers/Controller.php b/system/typemill/Controllers/Controller.php index 60d546e..3d85cbd 100644 --- a/system/typemill/Controllers/Controller.php +++ b/system/typemill/Controllers/Controller.php @@ -32,8 +32,6 @@ abstract class Controller $this->routeParser = $container->get('routeParser'); -# $this->csrf = $container->get('csrf'); - $this->c->get('dispatcher')->dispatch(new OnTwigLoaded(false), 'onTwigLoaded'); } diff --git a/system/typemill/Controllers/ControllerApiAuthorMeta.php b/system/typemill/Controllers/ControllerApiAuthorMeta.php index ec4dd07..45f4460 100644 --- a/system/typemill/Controllers/ControllerApiAuthorMeta.php +++ b/system/typemill/Controllers/ControllerApiAuthorMeta.php @@ -6,10 +6,8 @@ use Psr\Http\Message\ServerRequestInterface as Request; use Psr\Http\Message\ResponseInterface as Response; use Slim\Routing\RouteContext; use Typemill\Models\Validation; -use Typemill\Models\Content; use Typemill\Models\Navigation; use Typemill\Models\Meta; -use Typemill\Static\Slug; class ControllerApiAuthorMeta extends Controller { @@ -97,7 +95,7 @@ class ControllerApiAuthorMeta extends Controller return $response->withHeader('Content-Type', 'application/json'); } - public function updateMetaData(Request $request, Response $response, $args) + public function updateMeta(Request $request, Response $response, $args) { $validRights = $this->validateRights($request->getAttribute('c_userrole'), 'content', 'update'); if(!$validRights) @@ -325,160 +323,6 @@ class ControllerApiAuthorMeta extends Controller } - - - - - - - - - - - - - - - - - - -/* - # get the standard meta-definitions and the meta-definitions from plugins (same for all sites) - public function aggregateMetaDefinitions($folder = null) - { - $metatabs = $this->meta->getMetaDefinitions(); - - # the fields for user or role based access - if(!isset($this->settings['pageaccess']) || $this->settings['pageaccess'] === NULL ) - { - unset($metatabs['meta']['fields']['fieldsetrights']); - } - - # add radio buttons to choose posts or pages for folder. - if(!$folder) - { - unset($metatabs['meta']['fields']['contains']); - } - - echo '
';
-		print_r($metatabs);
-		die();
-
-		# loop through all plugins
-		if(!empty($this->settings['plugins']))
-		{
-			foreach($this->settings['plugins'] as $name => $plugin)
-			{
-				if($plugin['active'])
-				{
-					$pluginSettings = \Typemill\Settings::getObjectSettings('plugins', $name);
-					if($pluginSettings && isset($pluginSettings['metatabs']))
-					{
-						$metatabs = array_merge_recursive($metatabs, $pluginSettings['metatabs']);
-					}
-				}
-			}
-		}
-		
-		# add the meta from theme settings here
-		$themeSettings = \Typemill\Settings::getObjectSettings('themes', $this->settings['theme']);
-		
-		if($themeSettings && isset($themeSettings['metatabs']))
-		{
-			$metatabs = array_merge_recursive($metatabs, $themeSettings['metatabs']);
-		}
-
-		# dispatch meta 
-#		$metatabs 		= $this->c->dispatcher->dispatch('onMetaDefinitionsLoaded', new OnMetaDefinitionsLoaded($metatabs))->getData();
-
-		return $metatabs;
-	}
-*/
-
-
-	public function publishArticle(Request $request, Response $response, $args)
-	{
-		$validRights		= $this->validateRights($request->getAttribute('c_userrole'), 'content', 'update');
-		if(!$validRights)
-		{
-			$response->getBody()->write(json_encode([
-				'message' 	=> 'You do not have enough rights.',
-			]));
-
-			return $response->withHeader('Content-Type', 'application/json')->withStatus(422);			
-		}
-
-		$params 			= $request->getParsedBody();
-		$validate			= new Validation();
-		$validInput 		= $validate->articlePublish($params);
-		if($validInput !== true)
-		{
-			$errors 		= $validate->returnFirstValidationErrors($validInput);
-			$response->getBody()->write(json_encode([
-				'message' 	=> reset($errors),
-				'errors' 	=> $errors
-			]));
-
-			return $response->withHeader('Content-Type', 'application/json')->withStatus(400);
-		}
-
-		$navigation 		= new Navigation();
-		$urlinfo 			= $this->c->get('urlinfo');
-		$item 				= $this->getItem($navigation, $params['url'], $urlinfo);
-		if(!$item)
-		{
-			$response->getBody()->write(json_encode([
-				'message' => 'page not found',
-			]));
-
-			return $response->withHeader('Content-Type', 'application/json')->withStatus(404);
-		}
-
-	    # publish content
-		$content 			= new Content($urlinfo['baseurl']);
-		$draftMarkdown  	= $content->getDraftMarkdown($item);
-		$content->publishMarkdown($item, $draftMarkdown);
-
-		# refresh navigation and item
-	    $navigation->clearNavigation();
-		$draftNavigation 	= $navigation->getDraftNavigation($urlinfo, $this->settings['langattr']);
-		$draftNavigation 	= $navigation->setActiveNaviItems($draftNavigation, $item->keyPathArray);
-		$item 				= $navigation->getItemWithKeyPath($draftNavigation, $item->keyPathArray);
-
-		$response->getBody()->write(json_encode([
-			'navigation'	=> $draftNavigation,
-			'item'			=> $item
-		]));
-
-		return $response->withHeader('Content-Type', 'application/json');
-	}
-
-	# get the standard meta-definitions and the meta-definitions from plugins (same for all sites)
-	public function getMetaDefinitions(Request $request, Response $response, $args)
-	{
-		$validRights		= $this->validateRights($request->getAttribute('c_userrole'), 'content', 'update');
-		if(!$validRights)
-		{
-			$response->getBody()->write(json_encode([
-				'message' 	=> 'You do not have enough rights.',
-			]));
-
-			return $response->withHeader('Content-Type', 'application/json')->withStatus(422);			
-		}
-
-		$metatabs = $this->aggregateMetaDefinitions();
-
-		$response->getBody()->write(json_encode([
-			'definitions'	=> $metatabs
-		]));
-
-		return $response->withHeader('Content-Type', 'application/json');
-	}
-
-
-
-
 	# we have to flatten field definitions for tabs if there are fieldsets in it
 	public function flattenTabFields($tabfields, $flattab, $fieldset = null)
 	{
diff --git a/system/typemill/Controllers/ControllerApiFile.php b/system/typemill/Controllers/ControllerApiFile.php
index 08ce8dc..7aa7294 100644
--- a/system/typemill/Controllers/ControllerApiFile.php
+++ b/system/typemill/Controllers/ControllerApiFile.php
@@ -9,6 +9,57 @@ use Typemill\Models\StorageWrapper;
 
 class ControllerApiFile extends Controller
 {
+	public function getFiles(Request $request, Response $response, $args)
+	{
+		$url 			= $request->getQueryParams()['url'] ?? false;
+		$path 			= $request->getQueryParams()['path'] ?? false;
+		
+		$storage 		= new StorageWrapper('\Typemill\Models\Storage');
+
+		$filelist 		= $storage->getFileList();
+
+		$response->getBody()->write(json_encode([
+			'files' 	=> $filelist,
+		]));
+
+		return $response->withHeader('Content-Type', 'application/json');
+	}
+
+	public function getFile(Request $request, Response $response, $args)
+	{
+		$name 			= $request->getQueryParams()['name'] ?? false;
+
+		# VALIDATE NAME
+
+		if(!$name)
+		{
+			$response->getBody()->write(json_encode([
+				'message' 		=> 'Filename is missing.',
+			]));
+
+			return $response->withHeader('Content-Type', 'application/json')->withStatus(400);
+		}
+
+		$storage 		= new StorageWrapper('\Typemill\Models\Storage');
+
+		$filedetails 	= $storage->getFileDetails($name);
+		
+		if(!$filedetails)
+		{
+			$response->getBody()->write(json_encode([
+				'message' 		=> 'No File found.',
+			]));
+
+			return $response->withHeader('Content-Type', 'application/json')->withStatus(400);
+		}
+
+		$response->getBody()->write(json_encode([
+			'file' 		=> $filedetails,
+		]));
+
+		return $response->withHeader('Content-Type', 'application/json');
+	}
+
 	public function getFileRestrictions(Request $request, Response $response, $args)
 	{
 		$params = $request->getQueryParams();
@@ -238,96 +289,39 @@ class ControllerApiFile extends Controller
 		return $response->withHeader('Content-Type', 'application/json');		
 	}
 
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-	public function getMediaLibFiles(Request $request, Response $response, $args)
-	{
-		# get params from call
-		$this->params 	= $request->getParsedBody();
-		$this->uri 		= $request->getUri()->withUserInfo('');
-
-		$fileProcessor	= new ProcessFile();
-		if(!$fileProcessor->checkFolders())
-		{
-			return $response->withJson(['errors' => 'Please check if your media-folder exists and all folders inside are writable.'], 500);
-		}
-		
-		$filelist 		= $fileProcessor->scanFilesFlat();
-
-		$response->getBody()->write(json_encode([
-			'files' => $filelist
-		]));
-
-		return $response->withHeader('Content-Type', 'application/json')->withStatus(200);
-	}
-
-	public function getFile(Request $request, Response $response, $args)
-	{
-		# get params from call 
-		$this->params 	= $request->getParams();
-		$this->uri 		= $request->getUri()->withUserInfo('');
-
-		$this->setStructureDraft();
-
-		$fileProcessor	= new ProcessFile();
-		if(!$fileProcessor->checkFolders())
-		{
-			return $response->withJson(['errors' => 'Please check if your media-folder exists and all folders inside are writable.'], 500);
-		}
-
-		$fileDetails 	= $fileProcessor->getFileDetails($this->params['name'], $this->structureDraft);
-
-		if($fileDetails)
-		{
-			return $response->withJson(['file' => $fileDetails]);
-		}
-
-		return $response->withJson(['errors' => 'file not found or file name invalid'],404);
-	}
-
-
-
 	public function deleteFile(Request $request, Response $response, $args)
 	{
-		# get params from call 
-		$this->params 	= $request->getParams();
-		$this->uri 		= $request->getUri()->withUserInfo('');
+		$params = $request->getParsedBody();
 
-		# minimum permission is that user is allowed to delete content
-		if(!$this->c->acl->isAllowed($_SESSION['role'], 'content', 'delete'))
+		if(!isset($params['name']))
 		{
-			return $response->withJson(array('data' => false, 'errors' => 'You are not allowed to delete files.'), 403);
+			$response->getBody()->write(json_encode([
+				'message' 		=> 'Filename is missing.'
+			]));
+
+			return $response->withHeader('Content-Type', 'application/json')->withStatus(422);
 		}
 
-		if(!isset($this->params['name']))
+		$storage = new StorageWrapper('\Typemill\Models\Storage');
+
+		$deleted = $storage->deleteMediaFile($params['name']);
+
+		if($deleted)
 		{
-			return $response->withJson(['errors' => 'file name is missing'],500);	
+			$response->getBody()->write(json_encode([
+				'message' 		=> 'File deleted successfully.'
+			]));
+
+			return $response->withHeader('Content-Type', 'application/json');
 		}
 
-		$fileProcessor	= new ProcessFile();
+		$response->getBody()->write(json_encode([
+			'message' 		=> $storage->getError()
+		]));
 
-		if($fileProcessor->deleteFile($this->params['name']))
-		{
-			return $response->withJson(['errors' => false]);
-		}
-
-		return $response->withJson(['errors' => 'could not delete the file'],500);
+		return $response->withHeader('Content-Type', 'application/json')->withStatus(422);
 	}
-
+ 
 	# https://www.sitepoint.com/mime-types-complete-list/
 	# https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types
 	# https://wiki.selfhtml.org/wiki/MIME-Type/%C3%9Cbersicht
diff --git a/system/typemill/Controllers/ControllerApiImage.php b/system/typemill/Controllers/ControllerApiImage.php
index db0b12b..315d2ca 100644
--- a/system/typemill/Controllers/ControllerApiImage.php
+++ b/system/typemill/Controllers/ControllerApiImage.php
@@ -6,6 +6,7 @@ use Psr\Http\Message\ServerRequestInterface as Request;
 use Psr\Http\Message\ResponseInterface as Response;
 use Typemill\Models\ProcessImage;
 use Typemill\Models\StorageWrapper;
+use Typemill\Extensions\ParsedownExtension;
 
 
 # use Typemill\Models\ProcessFile;
@@ -21,6 +22,110 @@ class ControllerApiImage extends Controller
 	# return error messages and display in image component
 	# check if resized is bigger than original, then use original
 
+	public function getPagemedia(Request $request, Response $response, $args)
+	{
+		$url 			= $request->getQueryParams()['url'] ?? false;
+		$path 			= $request->getQueryParams()['path'] ?? false;
+		$pagemedia 		= [];
+
+		if(!$path)
+		{
+			$response->getBody()->write(json_encode([
+				'message' 		=> 'Path is missing.',
+			]));
+
+			return $response->withHeader('Content-Type', 'application/json')->withStatus(400);
+		}
+		
+		$storage 		= new StorageWrapper('\Typemill\Models\Storage');
+
+		$markdown 	= $storage->getFile('contentFolder', '', $path . '.txt');
+		if($markdown)
+		{
+			$markdownArray 	= json_decode($markdown);
+			$parsedown 		= new ParsedownExtension();
+			$markdown 		= $parsedown->arrayBlocksToMarkdown($markdownArray);
+		}
+		else
+		{
+			$markdown = $storage->getFile('contentFolder', '', $path . '.md');
+		}
+
+		$mdmedia 	= $this->findMediaInText($markdown);
+
+		$meta 		= $storage->getFile('contentFolder', '', $path . '.yaml');
+
+		$mtmedia  	= $this->findMediaInText($meta);
+
+		$pagemedia 	= array_merge($mdmedia[2], $mtmedia[2]);
+
+		$response->getBody()->write(json_encode([
+			'pagemedia' 	=> $pagemedia
+		]));
+
+		return $response->withHeader('Content-Type', 'application/json');
+	}
+
+	protected function findMediaInText($text)
+	{
+		preg_match_all('/media\/(live|files)\/(.+?\.[a-zA-Z]{2,4})/', $text, $matches);
+
+		return $matches;
+	}	
+
+	public function getImages(Request $request, Response $response, $args)
+	{
+		$url 			= $request->getQueryParams()['url'] ?? false;
+		$path 			= $request->getQueryParams()['path'] ?? false;
+		$pagemedia 		= [];
+		
+		$storage 		= new StorageWrapper('\Typemill\Models\Storage');
+
+		$imagelist 		= $storage->getImageList();
+
+		$response->getBody()->write(json_encode([
+			'images' 		=> $imagelist
+		]));
+
+		return $response->withHeader('Content-Type', 'application/json');
+	}
+
+	public function getImage(Request $request, Response $response, $args)
+	{
+		$name 			= $request->getQueryParams()['name'] ?? false;
+
+		# VALIDATE NAME
+
+		if(!$name)
+		{
+			$response->getBody()->write(json_encode([
+				'message' 		=> 'Imagename is missing.',
+			]));
+
+			return $response->withHeader('Content-Type', 'application/json')->withStatus(400);
+		}
+
+		$storage 		= new StorageWrapper('\Typemill\Models\Storage');
+
+		$imagedetails 	= $storage->getImageDetails($name);
+		
+		if(!$imagedetails)
+		{
+			$response->getBody()->write(json_encode([
+				'message' 		=> 'No image found.',
+			]));
+
+			return $response->withHeader('Content-Type', 'application/json')->withStatus(400);
+		}
+
+		$response->getBody()->write(json_encode([
+			'image' 		=> $imagedetails,
+		]));
+
+		return $response->withHeader('Content-Type', 'application/json');		
+	}
+	
+
 	public function saveImage(Request $request, Response $response, $args)
 	{
 		$params = $request->getParsedBody();
@@ -283,127 +388,38 @@ class ControllerApiImage extends Controller
 		]));
 
 		return $response->withHeader('Content-Type', 'application/json')->withStatus(500);
-
-
-
-
-
-		
-		$imageData64	= 'data:image/jpeg;base64,' . base64_encode($imageData);
-		$desiredSizes	= ['live' => ['width' => 560, 'height' => 315]];
-		$imageProcessor	= new ProcessImage($this->settings['images']);
-		if(!$imageProcessor->checkFolders())
-		{
-			return $response->withJson(['errors' => ['message' => 'Please check if your media-folder exists and all folders inside are writable.']], 500);
-		}
-
-		$tmpImage		= $imageProcessor->createImage($imageData64, $videoID, $desiredSizes);
-		
-		if(!$tmpImage)
-		{
-			return $response->withJson(array('errors' => 'could not create temporary image'));			
-		}
-		
-		$imageUrl 		= $imageProcessor->publishImage();
-		if($imageUrl)
-		{
-			$this->params['markdown'] = '![' . $class . '-video](' . $imageUrl . ' "click to load video"){#' . $videoID. ' .' . $class . '}';
-
-			$request 	= $request->withParsedBody($this->params);
-			$block = new ControllerAuthorBlockApi($this->c);
-			if($this->params['new'])
-			{
-				return $block->addBlock($request, $response, $args);
-			}
-			return $block->updateBlock($request, $response, $args);
-		}
-		
-		return $response->withJson(array('errors' => 'could not store the preview image'));	
 	}
 
-
-
-
-
-
-
-
-
-	public function getMediaLibImages(Request $request, Response $response, $args)
-	{
-		# get params from call 
-		$this->params 	= $request->getParsedBody();
-		$this->uri 		= $request->getUri()->withUserInfo('');
-
-		$imageProcessor	= new ProcessImage($this->settings['images']);
-		if(!$imageProcessor->checkFolders('images'))
-		{
-			return $response->withJson(['errors' => 'Please check if your media-folder exists and all folders inside are writable.'], 500);
-		}
-		
-		$imagelist 		= $imageProcessor->scanMediaFlat();
-
-		$response->getBody()->write(json_encode([
-			'images' => $imagelist
-		]));
-
-		return $response->withHeader('Content-Type', 'application/json')->withStatus(200);
-	}
-
-	public function getImage(Request $request, Response $response, $args)
-	{
-		# get params from call 
-		$this->params 	= $request->getParsedBody();
-		$this->uri 		= $request->getUri()->withUserInfo('');
-
-		$this->setStructureDraft();
-
-		$imageProcessor	= new ProcessImage($this->settings['images']);
-		if(!$imageProcessor->checkFolders('images'))
-		{
-			return $response->withJson(['errors' => 'Please check if your media-folder exists and all folders inside are writable.'], 500);
-		}
-
-		$imageDetails 	= $imageProcessor->getImageDetails($this->params['name'], $this->structureDraft);
-		
-		if($imageDetails)
-		{
-			return $response->withJson(['image' => $imageDetails]);
-		}
-		
-		return $response->withJson(['errors' => 'Image not found or image name not valid.'], 404);
-	}
-	
 	public function deleteImage(Request $request, Response $response, $args)
 	{
-		# get params from call 
-		$this->params 	= $request->getParams();
-		$this->uri 		= $request->getUri()->withUserInfo('');
+		$params = $request->getParsedBody();
 
-		# minimum permission is that user is allowed to delete content
-		if(!$this->c->acl->isAllowed($_SESSION['role'], 'content', 'delete'))
+		if(!isset($params['name']))
 		{
-			return $response->withJson(array('data' => false, 'errors' => 'You are not allowed to delete images.'), 403);
+			$response->getBody()->write(json_encode([
+				'message' 		=> 'Imagename is missing.'
+			]));
+
+			return $response->withHeader('Content-Type', 'application/json')->withStatus(422);
 		}
 
-		if(!isset($this->params['name']))
+		$storage = new StorageWrapper('\Typemill\Models\Storage');
+
+		$deleted = $storage->deleteImage($params['name']);
+
+		if($deleted)
 		{
-			return $response->withJson(['errors' => 'image name is missing'],500);
+			$response->getBody()->write(json_encode([
+				'message' 		=> 'Image deleted successfully.'
+			]));
+
+			return $response->withHeader('Content-Type', 'application/json');
 		}
 
-		$imageProcessor	= new ProcessImage($this->settings['images']);
-		if(!$imageProcessor->checkFolders('images'))
-		{
-			return $response->withJson(['errors' => 'Please check if your media-folder exists and all folders inside are writable.'], 500);
-		}
+		$response->getBody()->write(json_encode([
+			'message' 		=> $storage->getError()
+		]));
 
-		if($imageProcessor->deleteImage($this->params['name']))
-		{
-			return $response->withJson(['errors' => false]);
-		}
-
-		return $response->withJson(['errors' => 'Oops, looks like we could not delete all sizes of that image.'], 500);
+		return $response->withHeader('Content-Type', 'application/json')->withStatus(422);
 	}
-
-
 }
diff --git a/system/typemill/Models/ProcessFile.php b/system/typemill/Models/ProcessFile.php
index a8d18e1..cb9f0eb 100644
--- a/system/typemill/Models/ProcessFile.php
+++ b/system/typemill/Models/ProcessFile.php
@@ -62,90 +62,4 @@ class ProcessFile extends ProcessAssets
 
 	    return $this->getFullName();
 	}
-
-
-
-
-
-
-	public function deleteFile($name)
-	{
-		# validate name 
-		$name = basename($name);
-
-		if(file_exists($this->fileFolder . $name) && unlink($this->fileFolder . $name))
-		{
-			return true;
-		}
-
-		return false;
-	}
-
-
-	public function deleteFileWithName($name)
-	{
-		# e.g. delete $name = 'logo';
-
-		$name = basename($name);
-
-		if($name != '' && !in_array($name, array(".","..")))
-		{
-			foreach(glob($this->fileFolder . $name) as $file)
-			{
-				unlink($file);
-			}
-		}
-	}
-
-
-	/*
-	* scans content of a folder (without recursion)
-	* vars: folder path as string
-	* returns: one-dimensional array with names of folders and files
-	*/
-	public function scanFilesFlat()
-	{
-		$files 		= scandir($this->fileFolder);
-		$filelist	= array();
-
-		foreach ($files as $key => $name)
-		{
-			if (!in_array($name, array(".","..","filerestrictions.yaml")) && file_exists($this->fileFolder . $name))
-			{
-				$filelist[] = [
-					'name' 		=> $name,
-					'timestamp'	=> filemtime($this->fileFolder . $name),
-					'info'		=> pathinfo($this->fileFolder . $name),
-					'url'		=> 'media/files/' . $name,
-				];
-			}
-		}
-
-		$filelist = Helpers::array_sort($filelist, 'timestamp', SORT_DESC);
-
-		return $filelist;
-	}
-
-
-	public function getFileDetails($name, $structure)
-	{
-		$name = basename($name);
-
-		if (!in_array($name, array(".","..")) && file_exists($this->fileFolder . $name))
-		{
-			$filedetails = [
-				'name' 		=> $name,
-				'timestamp'	=> filemtime($this->fileFolder . $name),
-				'bytes' 	=> filesize($this->fileFolder . $name),
-				'info'		=> pathinfo($this->fileFolder . $name),
-				'url'		=> 'media/files/' . $name,
-				'pages'		=> $this->findPagesWithUrl($structure, $name, $result = [])
-			];
-
-			return $filedetails;
-		}
-
-		return false;
-	}
-
 }
\ No newline at end of file
diff --git a/system/typemill/Models/ProcessImage.php b/system/typemill/Models/ProcessImage.php
index 638d52a..d57eac0 100644
--- a/system/typemill/Models/ProcessImage.php
+++ b/system/typemill/Models/ProcessImage.php
@@ -229,7 +229,6 @@ class ProcessImage extends ProcessAssets
 	}
 
 
-	# publish image function is moved to storage model
 
 
 
@@ -241,62 +240,10 @@ class ProcessImage extends ProcessAssets
 
 
 
-
-
-
-
-
-
-
-
-
-
-
-	# MOVE TO STORAGE ??
-	public function deleteImage($name)
-	{
-		# validate name 
-		$name = basename($name);
-
-		if(!file_exists($this->originalFolder . $name) OR !unlink($this->originalFolder . $name))
-		{
-			$this->errors[] = "We could not delete the original image";
-		}
-
-		if(!file_exists($this->liveFolder . $name) OR !unlink($this->liveFolder . $name))
-		{
-			$this->errors[] = "We could not delete the live image";
-		}
-
-		if(!file_exists($this->thumbFolder . $name) OR !unlink($this->thumbFolder . $name))
-		{
-			$this->errors[] = "we could not delete the thumb image";
-		}
-
-		# delete custom images (resized and grayscaled) array_map('unlink', glob("some/dir/*.txt"));
-		$pathinfo = pathinfo($name);
-		foreach(glob($this->customFolder . $pathinfo['filename'] . '\-*.' . $pathinfo['extension']) as $image)
-		{
-			# you could check if extension is the same here
-			if(!unlink($image))
-			{
-				$this->errors[] = "we could not delete a custom image (grayscale or resized)";
-			}
-		}
-		
-		if(empty($this->errors))
-		{
-			return true;
-		}
-
-		return false;
-	}
-
-
-
 	# in use ??
 	public function deleteImageWithName($name)
 	{
+		die("processImage model deleteImageWithName please check method.");
 		# e.g. delete $name = 'logo...';
 
 		$name = basename($name);
@@ -321,6 +268,8 @@ class ProcessImage extends ProcessAssets
 	# in use ??
 	public function copyImage($name,$sourcefolder,$targetfolder)
 	{
+		die("processImage model copyImage please check method.");
+
 		copy($sourcefolder . $name, $targetfolder . $name);
 	}
 
@@ -389,78 +338,6 @@ class ProcessImage extends ProcessAssets
 
 
 
-	/*
-	* scans content of a folder (without recursion)
-	* vars: folder path as string
-	* returns: one-dimensional array with names of folders and files
-	*/
-	public function scanMediaFlat()
-	{
-		$thumbs 		= array_diff(scandir($this->thumbFolder), array('..', '.'));
-		$imagelist		= array();
-
-		foreach ($thumbs as $key => $name)
-		{
-			if (file_exists($this->liveFolder . $name))
-			{
-				$imagelist[] = [
-					'name' 		=> $name,
-					'timestamp'	=> filemtime($this->liveFolder . $name),
-					'src_thumb'	=> 'media/thumbs/' . $name,
-					'src_live'	=> 'media/live/' . $name,
-				];
-			}
-		}
-
-		$imagelist = Helpers::array_sort($imagelist, 'timestamp', SORT_DESC);
-
-		return $imagelist;
-	}
-
-
-	# get details from existing image for media library
-	public function getImageDetails($name, $structure)
-	{		
-		$name = basename($name);
-
-		if (!in_array($name, array(".","..")) && file_exists($this->liveFolder . $name))
-		{
-			$imageinfo 		= getimagesize($this->liveFolder . $name);
-
-			if(!$imageinfo && pathinfo($this->liveFolder . $name, PATHINFO_EXTENSION) == 'svg')
-			{
-				$imagedetails = [
-					'name' 		=> $name,
-					'timestamp'	=> filemtime($this->liveFolder . $name),
-					'bytes' 	=> filesize($this->liveFolder . $name),
-					'width'		=> '---',
-					'height'	=> '---',
-					'type'		=> 'svg',
-					'src_thumb'	=> 'media/thumbs/' . $name,
-					'src_live'	=> 'media/live/' . $name,
-					'pages'		=> $this->findPagesWithUrl($structure, $name, $result = [])
-				];				
-			}
-			else
-			{
-				$imagedetails = [
-					'name' 		=> $name,
-					'timestamp'	=> filemtime($this->liveFolder . $name),
-					'bytes' 	=> filesize($this->liveFolder . $name),
-					'width'		=> $imageinfo[0],
-					'height'	=> $imageinfo[1],
-					'type'		=> $imageinfo['mime'],
-					'src_thumb'	=> 'media/thumbs/' . $name,
-					'src_live'	=> 'media/live/' . $name,
-					'pages'		=> $this->findPagesWithUrl($structure, $name, $result = [])
-				];
-			}
-
-			return $imagedetails;
-		}
-
-		return false;
-	}
 
 	public function generateThumbs()
 	{
diff --git a/system/typemill/Models/Storage.php b/system/typemill/Models/Storage.php
index 8657acf..f61f710 100644
--- a/system/typemill/Models/Storage.php
+++ b/system/typemill/Models/Storage.php
@@ -2,6 +2,8 @@
 
 namespace Typemill\Models;
 
+use Typemill\Static\Helpers;
+
 class Storage
 {
 	public $error 					= false;
@@ -332,6 +334,11 @@ class Storage
 		return false;
 	}
 
+
+	##################
+	## 	  IMAGES 	##
+	##################
+
 	public function createUniqueImageName($filename, $extension)
 	{
 		$defaultfilename = $filename;
@@ -347,36 +354,6 @@ class Storage
 		return $filename;
 	}
 
-	public function publishFile($name)
-	{
-		$pathinfo = pathinfo($name);
-		if(!$pathinfo)
-		{
-			$this->error = 'Could not read pathinfo.';
-
-			return false;
-		}
-
-		$filename = $pathinfo['filename'] . '.' . $pathinfo['extension'];
-		$filepath = $this->tmpFolder . $filename;
-
-		if(!file_exists($this->tmpFolder . $filename))
-		{
-			$this->error = "We did not find the file in the tmp-folder or could not read it.";
-			return false;
-		}
-
-		$success = rename($this->tmpFolder . $filename, $this->fileFolder . $filename);
-		
-		if($success === true)
-		{
-			# return true;
-			return 'media/files/' . $filename;
-		}
-
-		return false;
-	}
-
 	public function publishImage($name, $noresize = false)
 	{
 		$pathinfo = pathinfo($name);
@@ -489,10 +466,221 @@ class Storage
 
 	}
 
+	public function getImageList()
+	{
+		$thumbs 		= array_diff(scandir($this->thumbsFolder), array('..', '.'));
+		$imagelist		= array();
+
+		foreach ($thumbs as $key => $name)
+		{
+			if (file_exists($this->liveFolder . $name))
+			{
+				$imagelist[] = [
+					'name' 		=> $name,
+					'timestamp'	=> filemtime($this->liveFolder . $name),
+					'src_thumb'	=> 'media/thumbs/' . $name,
+					'src_live'	=> 'media/live/' . $name,
+				];
+			}
+		}
+
+		$imagelist = Helpers::array_sort($imagelist, 'timestamp', SORT_DESC);
+
+		return $imagelist;
+	}
+
+	# get details from existing image for media library
+	public function getImageDetails($name)
+	{		
+		$name = basename($name);
+
+		if (!in_array($name, array(".","..")) && file_exists($this->liveFolder . $name))
+		{
+			$imageinfo 		= getimagesize($this->liveFolder . $name);
+
+			if(!$imageinfo && pathinfo($this->liveFolder . $name, PATHINFO_EXTENSION) == 'svg')
+			{
+				$imagedetails = [
+					'name' 		=> $name,
+					'timestamp'	=> filemtime($this->liveFolder . $name),
+					'bytes' 	=> filesize($this->liveFolder . $name),
+					'width'		=> '---',
+					'height'	=> '---',
+					'type'		=> 'svg',
+					'src_thumb'	=> 'media/thumbs/' . $name,
+					'src_live'	=> 'media/live/' . $name,
+				];
+			}
+			else
+			{
+				$imagedetails = [
+					'name' 		=> $name,
+					'timestamp'	=> filemtime($this->liveFolder . $name),
+					'bytes' 	=> filesize($this->liveFolder . $name),
+					'width'		=> $imageinfo[0],
+					'height'	=> $imageinfo[1],
+					'type'		=> $imageinfo['mime'],
+					'src_thumb'	=> 'media/thumbs/' . $name,
+					'src_live'	=> 'media/live/' . $name,
+				];
+			}
+
+			return $imagedetails;
+		}
+
+		return false;
+	}
+
+	public function deleteImage($name)
+	{
+		# validate name 
+		$name = basename($name);
+
+		if(!file_exists($this->liveFolder . $name) OR !unlink($this->liveFolder . $name))
+		{
+			$this->error .= "We could not delete the live image. ";
+		}
+
+		if(!file_exists($this->thumbsFolder . $name) OR !unlink($this->thumbsFolder . $name))
+		{
+			$this->error .= "We could not delete the thumb image. ";
+		}
+
+		# delete custom images (resized and grayscaled) array_map('unlink', glob("some/dir/*.txt"));
+		$pathinfo = pathinfo($name);
+
+		foreach(glob($this->originalFolder . $pathinfo['filename'] . '\.*') as $image)
+		{
+			# you could check if extension is the same here
+			if(!unlink($image))
+			{
+				$this->error = "We could not delete the original image in $this->originalFolder $image. ";
+			}
+		}
+
+		foreach(glob($this->customFolder . $pathinfo['filename'] . '\-*.' . $pathinfo['extension']) as $image)
+		{
+			# you could check if extension is the same here
+			if(!unlink($image))
+			{
+				$this->error .= "we could not delete a custom image (grayscale or resized). ";
+			}
+		}
+		
+		if(!$this->error)
+		{
+			return true;
+		}
+
+		return false;
+	}
+
+	##################
+	## 	  FILES 	##
+	##################
+
+	public function publishFile($name)
+	{
+		$pathinfo = pathinfo($name);
+		if(!$pathinfo)
+		{
+			$this->error = 'Could not read pathinfo.';
+
+			return false;
+		}
+
+		$filename = $pathinfo['filename'] . '.' . $pathinfo['extension'];
+		$filepath = $this->tmpFolder . $filename;
+
+		if(!file_exists($this->tmpFolder . $filename))
+		{
+			$this->error = "We did not find the file in the tmp-folder or could not read it.";
+			return false;
+		}
+
+		$success = rename($this->tmpFolder . $filename, $this->fileFolder . $filename);
+		
+		if($success === true)
+		{
+			# return true;
+			return 'media/files/' . $filename;
+		}
+
+		return false;
+	}
+
+	public function getFileList()
+	{
+		$files 		= scandir($this->fileFolder);
+		$filelist	= array();
+
+		foreach ($files as $key => $name)
+		{
+			if (!in_array($name, array(".","..","filerestrictions.yaml")) && file_exists($this->fileFolder . $name))
+			{
+				$filelist[] = [
+					'name' 		=> $name,
+					'timestamp'	=> filemtime($this->fileFolder . $name),
+					'bytes' 	=> filesize($this->fileFolder . $name),					
+					'info'		=> pathinfo($this->fileFolder . $name),
+					'url'		=> 'media/files/' . $name,
+				];
+			}
+		}
+
+		$filelist = Helpers::array_sort($filelist, 'timestamp', SORT_DESC);
+
+		return $filelist;
+	}
+
+	public function getFileDetailsBREAK($name)
+	{
+		$name = basename($name);
+
+		if (!in_array($name, array(".","..")) && file_exists($this->fileFolder . $name))
+		{
+			$filedetails = [
+				'name' 		=> $name,
+				'timestamp'	=> filemtime($this->fileFolder . $name),
+				'bytes' 	=> filesize($this->fileFolder . $name),
+				'info'		=> pathinfo($this->fileFolder . $name),
+				'url'		=> 'media/files/' . $name,
+			];
+
+			return $filedetails;
+		}
+
+		return false;
+	}
+
+	public function deleteMediaFile($name)
+	{
+		# validate name 
+		$name = basename($name);
+
+		if(file_exists($this->fileFolder . $name) && unlink($this->fileFolder . $name))
+		{
+			return true;
+		}
+
+		return false;
+	}
 
 
+	public function deleteFileWithName($name)
+	{
+		# e.g. delete $name = 'logo';
 
+		$name = basename($name);
 
+		if($name != '' && !in_array($name, array(".","..")))
+		{
+			foreach(glob($this->fileFolder . $name) as $file)
+			{
+				unlink($file);
+			}
+		}
+	}
 
 
 
diff --git a/system/typemill/author/css/custom.css b/system/typemill/author/css/custom.css
index 1921edd..5e96bd6 100644
--- a/system/typemill/author/css/custom.css
+++ b/system/typemill/author/css/custom.css
@@ -15,6 +15,11 @@
   position: relative;	
 }
 
+
+/********************
+*   VUE     *
+********************/
+
 [v-cloak] {
   display: none;
 }
@@ -22,12 +27,25 @@
 .initial-leave-active {
   transition: opacity 0.2s ease;
 }
-
 .initial-enter-from,
 .initial-leave-to {
   opacity: 0;
 }
 
+
+.fade-enter-active {
+  transition: opacity 0.2s ease;
+}
+.fade-enter-from{
+  opacity: 0;
+}
+.list-enter-active {
+  transition: opacity 0.2s ease;
+}
+.list-enter-from{
+  opacity: 0;
+}
+
 /* CODEAREA */
 
 .codearea{
@@ -449,57 +467,6 @@
   font-weight:300; 
 }
 
-/*** BLOX EDITOR ***
-
-.edit .blox-editor .h1,
-.edit .blox-editor .h2,
-.edit .blox-editor .h3,
-.edit .blox-editor .h4,
-.edit .blox-editor .h5,
-.edit .blox-editor .h6{
-  line-height: 1em;
-  margin-top: 0;
-  margin-bottom: 0; 
-}
-.edit .blox-editor .h1{
-  font-weight: 700; 
-  font-size: 2.2em; 
-  padding-top: 0.6em;
-  padding-bottom: 0.6em;
-}
-.edit .blox-editor .h2{ 
-  font-weight: 700; 
-  font-size: 1.6em; 
-  padding-top: 1.3em; 
-  padding-bottom: 0.6em;
-}
-.edit .blox-editor .h3{ 
-  font-weight: 700; 
-  font-size: 1.3em; 
-  text-transform: none; 
-  padding-top: 1.2em; 
-  padding-bottom: 0.6em;
-}
-.edit .blox-editor .h4{ 
-  font-weight: 700; 
-  font-size: 1.1em; 
-  padding-top: 1.2em; 
-  padding-bottom: 0.6em;
-}
-.edit .blox-editor .h5{ 
-  font-weight: 700; 
-  font-size: 1em; 
-  padding-top: 1.2em; 
-  padding-bottom: 0.6em;
-}
-.edit .blox-editor .h6{ 
-  font-size: 1em; 
-  font-style: italic; 
-  font-weight:300; 
-  padding-top: 1em; 
-  padding-bottom: 0.6em;
-}
-
 
 /************************
 ** INLINE FORMATG BAR  **
@@ -561,320 +528,4 @@
 .blox-editor input.urlinput:focus{
   outline: 0px;
   border: 0px;
-}
-
-
-/*
-.title input{
-  font-size: 2.2em;
-  font-weight: 700;
-  padding: 20px;
-}
-
-
-
-.imageupload{
-  width: 50%;
-  position: relative;
-  display: inline-block;
-  border-right: 1px dotted grey;
-  box-sizing:border-box;
-}
-
-
-.imageselect{
-  width: 50%;
-  position: relative;
-  display: inline-block;
-  box-sizing:border-box;
-  border:0px;
-  padding: 0 0 0 0;
-  margin: 0 0 0 0;
-  min-height: 70px;
-  background: #f9f8f6;
-  font-family: Helvetica, Calibri, Arial, sans-serif;
-}
-.dropbox{
-  min-height: 70px;
-  background: #f9f8f6;
-  padding: 0px;
-  box-sizing: border-box;
-  margin-bottom: 10px; 
-}
-.dropbox p{
-  position: relative;
-  cursor: pointer;
-  line-height: 70px;
-  width: 100%;
-  text-align: center;
-  box-sizing:border-box;
-  padding: 0;
-  margin: 0;
-}
-.dropbox input, .dropbox select{
-  background-color: #fff;
-  width: 80%;
-  margin: 2px 0;
-  display: inline-block;
-}
-.video input{
-  width: 75%;
-  margin: 15px 0;
-}
-.dropbox select{
-  background-image: linear-gradient(45deg, transparent 50%, #444 50%), linear-gradient(135deg, #444 50%, transparent 50%), linear-gradient(to right, #fff, #fff);
-}
-.dropbox label{
-  width: 20%;
-  display: inline-block;
-}
-.video label{
-  text-align: right;
-  padding-right: 10px;
-  box-sizing: border-box;
-}
-.dropbox .imgmeta{
-  padding: 30px;
-  box-sizing: border-box; 
-}
-.dropbox .input-file{
-    opacity: 0;
-    width: 100%;
-    height: 70px;
-    position: absolute;
-    cursor: pointer;
-  z-index: 1;
-}
-.medialib{
-  margin: auto;
-  width: 100%;
-  height: 80%;
-  overflow: auto;
-  background: #f9f8f6;
-  max-width: 1200px;
-}
-.imagecard{
-  margin: 10px;
-  box-shadow:0 2px 5px rgba(22,23,26,.05);
-  display: inline-block;
-  vertical-align: top;
-  background: #fff;
-}
-
-sup{}
-cite{}
-abbr{}
-hr{
-  background: #ddd;
-  height: 2px;
-  margin: 20px 0;
-  border: 0px;
-}
-.setupWrapper a, .setupWrapper a:link, .setupWrapper a:visited
-{
-  text-decoration: none;
-  color: #444;
-}
-.setupWrapper a:focus, .setupWrapper a:hover, .setupWrapper a:active
-{
-  color: #e0474c; 
-}
-.mbfix{ margin-bottom: 0px!important; }
-
-.slugbutton{
-    right: 20px;
-    height: 52px;
-    width: 150px;
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-.blox-body{
-  position: relative;
-  padding: 18px 20px      
-}
-.blox-overlay{
-  position:absolute;
-  display: block;
-  z-index: 10;
-  box-sizing: border-box;
-  top: 0;
-  bottom: 0;
-  left: 0;
-  right: 0;
-  background: #FFF;
-  background: rgba(255,255,255,0.8);  
-}
-.blox-editor{
-  position: relative;
-}
-.blox-buttons{
-  position: absolute;
-    bottom: -15px;
-  text-align: right;
-    right: 25px;
-    width: 200px;
-  z-index: 99;
-}
-.blox-buttons button{
-  display: inline-block;
-  box-sizing: border-box;
-  margin: 2px;
-  padding: 3px 6px;
-  width: 80px;
-  text-align: center;
-  color: #444;
-  background: #f9f8f6;
-  border: 2px solid #fff;
-  border-radius: 2px;
-  font-size: 0.9em;
-}
-.blox-buttons button.edit{
-  background: #70c1b3;
-  color: #fff;
-}
-.blox-buttons button.edit:hover{
-  background: #4D978A;
-}
-.blox-buttons button.cancel:hover{
-  background: #e0474c;
-  color: #fff;
-}
-.blox-buttons button.edit:disabled, .blox-buttons button.cancel:disabled{
-  background: #eee;
-  color: #444;
-  border: 1px solid #eee;
-}
-
-
-.sideaction{
-  position: absolute;
-  top: 0px;
-  font-size: 0.8em;
-  right: -22px;
-}
-.sideaction button{
-  display: block;
-  font-weight: 300;
-  font-size: 0.9em;
-  background: #fff;
-  color: #fff;
-  width: 20px;
-  height: 20px;
-  line-height: 25px;
-  text-align: center;
-  padding: 0px;
-  margin: 1px;
-  border: 0px;
-  border-radius: 1px;
-}
-.blox-wrapper{
-  position: relative;
-}
-.editactive .sideaction button, 
-.blox-wrapper:hover button.add,
-.blox-wrapper:hover button.delete{
-  background-color: #f9f8f6;
-  color: #666;
-}
-.sideaction:hover ~ .background-helper {
-    background-color: #f9f8f6;
-}
-.editactive .background-helper{
-  background-color: transparent!important;
-}
-.blox-wrapper button.add:hover{
-  background: #66b0a3;
-  color: #fff;
-}
-.blox-wrapper button.delete:hover{
-  background: #e0474c;
-  color: #fff;
-}
-
-
-
-.blox-editor textarea{
-  font-family: arial;
-  line-height: 1.5em;
-  font-size: 16px;
-  padding-left: 20px;
-  padding-right: 20px;
-  box-sizing: border-box;
-  min-height: 40px;
-}
-.blox-editor textarea:focus, .blox-editor input:focus{
-  box-shadow: none;
-  outline: none;
-}
-.blox-editor input.mdcontent.h2,.blox-editor input.mdcontent.h3,.blox-editor input.mdcontent.h4,.blox-editor input.mdcontent.h5,.blox-editor input.mdcontent.h6{
-  padding-left: 35px;
-  height: auto;
-}
-.blox-editor input.mdcontent.h2{
-  font-size: 1.6em;
-  font-weight: 700;
-}
-.blox-editor input.mdcontent.h3{
-  font-size: 1.3em;
-  font-weight: 700;
-}
-.blox-editor input.mdcontent.h4{
-  font-size: 1.1em;
-  font-weight: 700;
-}
-.blox-editor input.mdcontent.h5{
-  font-size: 1em;
-  font-weight: 700;
-}
-.blox-editor input.mdcontent.h6{
-  font-size: 1em;
-  font-weight: 300;
-  font-style: italic;
-}
-button.hdown{
-  position: absolute;
-  padding: 8px;
-  top: 1px;
-  bottom: 1px;
-  left: 0px;
-  font-size: 1em;
-  font-weight: 700;
-  border: 0px solid #fff;
-  border-right: 1px solid #fff;
-}
-button.hdown.headline{
-  color: #f9f8f6;
-  background: #66b0a3;  
-}
-.blox-editor .contenttype {
-  position: absolute;
-  top: 15px;
-  left: -25px;
-  color: #666;
-}
-.visible{
-  display: block;
-}
-.hidden{
-  visibility: hidden;
-}
-.hidden .blox:hover{
-  background: #fff;
-}
-.component{
-  position: absolute;
-  width: 100%;
-  z-index:9;
-}
-*/
\ No newline at end of file
+}
\ No newline at end of file
diff --git a/system/typemill/author/css/output.css b/system/typemill/author/css/output.css
index 9e979fc..5737b3a 100644
--- a/system/typemill/author/css/output.css
+++ b/system/typemill/author/css/output.css
@@ -690,6 +690,10 @@ video {
   left: 3rem;
 }
 
+.right-0 {
+  right: 0px;
+}
+
 .-bottom-3 {
   bottom: -0.75rem;
 }
@@ -706,20 +710,16 @@ video {
   left: 50%;
 }
 
-.right-0 {
-  right: 0px;
-}
-
 .bottom-3 {
   bottom: 0.75rem;
 }
 
-.top-1 {
-  top: 0.25rem;
+.top-12 {
+  top: 3rem;
 }
 
-.right-1 {
-  right: 0.25rem;
+.top-10 {
+  top: 2.5rem;
 }
 
 .z-20 {
@@ -776,16 +776,16 @@ video {
   margin-bottom: 0.25rem;
 }
 
-.my-4 {
-  margin-top: 1rem;
-  margin-bottom: 1rem;
-}
-
 .my-3 {
   margin-top: 0.75rem;
   margin-bottom: 0.75rem;
 }
 
+.my-4 {
+  margin-top: 1rem;
+  margin-bottom: 1rem;
+}
+
 .mt-6 {
   margin-top: 1.5rem;
 }
@@ -794,10 +794,6 @@ video {
   margin-bottom: 0.25rem;
 }
 
-.mb-16 {
-  margin-bottom: 4rem;
-}
-
 .mb-2 {
   margin-bottom: 0.5rem;
 }
@@ -830,10 +826,18 @@ video {
   margin-top: 0.5rem;
 }
 
+.mb-16 {
+  margin-bottom: 4rem;
+}
+
 .mr-3 {
   margin-right: 0.75rem;
 }
 
+.mb-8 {
+  margin-bottom: 2rem;
+}
+
 .mt-5 {
   margin-top: 1.25rem;
 }
@@ -846,6 +850,22 @@ video {
   margin-left: 0.5rem;
 }
 
+.ml-5 {
+  margin-left: 1.25rem;
+}
+
+.mr-5 {
+  margin-right: 1.25rem;
+}
+
+.mb-10 {
+  margin-bottom: 2.5rem;
+}
+
+.mt-8 {
+  margin-top: 2rem;
+}
+
 .mb-3 {
   margin-bottom: 0.75rem;
 }
@@ -858,10 +878,6 @@ video {
   margin-top: 1rem;
 }
 
-.mt-8 {
-  margin-top: 2rem;
-}
-
 .mt-7 {
   margin-top: 1.75rem;
 }
@@ -870,10 +886,6 @@ video {
   margin-right: 1rem;
 }
 
-.mb-8 {
-  margin-bottom: 2rem;
-}
-
 .block {
   display: block;
 }
@@ -934,6 +946,14 @@ video {
   height: 2rem;
 }
 
+.h-full {
+  height: 100%;
+}
+
+.h-32 {
+  height: 8rem;
+}
+
 .h-0 {
   height: 0px;
 }
@@ -1030,6 +1050,14 @@ video {
   width: 60%;
 }
 
+.w-3\/4 {
+  width: 75%;
+}
+
+.w-60 {
+  width: 15rem;
+}
+
 .w-0 {
   width: 0px;
 }
@@ -1042,10 +1070,6 @@ video {
   width: 91.666667%;
 }
 
-.w-3\/4 {
-  width: 75%;
-}
-
 .max-w-md {
   max-width: 28rem;
 }
@@ -1058,6 +1082,10 @@ video {
   max-width: 56rem;
 }
 
+.max-w-7xl {
+  max-width: 80rem;
+}
+
 .max-w-6xl {
   max-width: 72rem;
 }
@@ -1136,6 +1164,10 @@ video {
   align-items: center;
 }
 
+.justify-start {
+  justify-content: flex-start;
+}
+
 .justify-end {
   justify-content: flex-end;
 }
@@ -1202,30 +1234,30 @@ video {
   border-right-width: 8px;
 }
 
-.border-l {
-  border-left-width: 1px;
+.border-b-2 {
+  border-bottom-width: 2px;
 }
 
 .border-t {
   border-top-width: 1px;
 }
 
-.border-r {
-  border-right-width: 1px;
-}
-
 .border-r-2 {
   border-right-width: 2px;
 }
 
-.border-b-2 {
-  border-bottom-width: 2px;
-}
-
 .border-b {
   border-bottom-width: 1px;
 }
 
+.border-r {
+  border-right-width: 1px;
+}
+
+.border-l {
+  border-left-width: 1px;
+}
+
 .border-l-4 {
   border-left-width: 4px;
 }
@@ -1246,10 +1278,6 @@ video {
   border-bottom-width: 4px;
 }
 
-.border-l-2 {
-  border-left-width: 2px;
-}
-
 .border-solid {
   border-style: solid;
 }
@@ -1263,11 +1291,6 @@ video {
   border-color: rgb(209 213 219 / var(--tw-border-opacity));
 }
 
-.border-stone-100 {
-  --tw-border-opacity: 1;
-  border-color: rgb(245 245 244 / var(--tw-border-opacity));
-}
-
 .border-stone-200 {
   --tw-border-opacity: 1;
   border-color: rgb(231 229 228 / var(--tw-border-opacity));
@@ -1300,12 +1323,7 @@ video {
 
 .border-stone-100 {
   --tw-border-opacity: 1;
-  border-color: rgb(250 204 21 / var(--tw-border-opacity));
-}
-
-.border-rose-500 {
-  --tw-border-opacity: 1;
-  border-color: rgb(244 63 94 / var(--tw-border-opacity));
+  border-color: rgb(245 245 244 / var(--tw-border-opacity));
 }
 
 .border-rose-500 {
@@ -1397,11 +1415,6 @@ video {
   background-color: rgb(20 184 166 / var(--tw-bg-opacity));
 }
 
-.bg-rose-500 {
-  --tw-bg-opacity: 1;
-  background-color: rgb(244 63 94 / var(--tw-bg-opacity));
-}
-
 .bg-red-100 {
   --tw-bg-opacity: 1;
   background-color: rgb(254 226 226 / var(--tw-bg-opacity));
@@ -1417,6 +1430,15 @@ video {
   background-color: rgb(87 83 78 / var(--tw-bg-opacity));
 }
 
+.bg-rose-500 {
+  --tw-bg-opacity: 1;
+  background-color: rgb(244 63 94 / var(--tw-bg-opacity));
+}
+
+.bg-black\/75 {
+  background-color: rgb(0 0 0 / 0.75);
+}
+
 .bg-yellow-500 {
   --tw-bg-opacity: 1;
   background-color: rgb(234 179 8 / var(--tw-bg-opacity));
@@ -1426,12 +1448,12 @@ video {
   --tw-bg-opacity: 0.9;
 }
 
-.bg-clip-padding {
-  background-clip: padding-box;
+.bg-cover {
+  background-size: cover;
 }
 
-.bg-center {
-  background-position: center;
+.bg-clip-padding {
+  background-clip: padding-box;
 }
 
 .p-3 {
@@ -1483,6 +1505,16 @@ video {
   padding-bottom: 0.75rem;
 }
 
+.px-4 {
+  padding-left: 1rem;
+  padding-right: 1rem;
+}
+
+.py-2 {
+  padding-top: 0.5rem;
+  padding-bottom: 0.5rem;
+}
+
 .px-12 {
   padding-left: 3rem;
   padding-right: 3rem;
@@ -1503,11 +1535,6 @@ video {
   padding-right: 0.5rem;
 }
 
-.py-2 {
-  padding-top: 0.5rem;
-  padding-bottom: 0.5rem;
-}
-
 .px-1 {
   padding-left: 0.25rem;
   padding-right: 0.25rem;
@@ -1523,14 +1550,19 @@ video {
   padding-right: 2rem;
 }
 
+.px-5 {
+  padding-left: 1.25rem;
+  padding-right: 1.25rem;
+}
+
 .px-16 {
   padding-left: 4rem;
   padding-right: 4rem;
 }
 
-.py-12 {
-  padding-top: 3rem;
-  padding-bottom: 3rem;
+.py-16 {
+  padding-top: 4rem;
+  padding-bottom: 4rem;
 }
 
 .py-4 {
@@ -1538,21 +1570,6 @@ video {
   padding-bottom: 1rem;
 }
 
-.px-4 {
-  padding-left: 1rem;
-  padding-right: 1rem;
-}
-
-.px-20 {
-  padding-left: 5rem;
-  padding-right: 5rem;
-}
-
-.py-16 {
-  padding-top: 4rem;
-  padding-bottom: 4rem;
-}
-
 .pr-6 {
   padding-right: 1.5rem;
 }
@@ -1617,14 +1634,22 @@ video {
   padding-top: 0.5rem;
 }
 
-.pt-4 {
-  padding-top: 1rem;
+.pt-6 {
+  padding-top: 1.5rem;
 }
 
 .pb-3 {
   padding-bottom: 0.75rem;
 }
 
+.pt-3 {
+  padding-top: 0.75rem;
+}
+
+.pt-4 {
+  padding-top: 1rem;
+}
+
 .text-left {
   text-align: left;
 }
@@ -1684,11 +1709,6 @@ video {
   line-height: 1.75rem;
 }
 
-.text-2xl {
-  font-size: 1.5rem;
-  line-height: 2rem;
-}
-
 .text-3xl {
   font-size: 1.875rem;
   line-height: 2.25rem;
@@ -1812,11 +1832,6 @@ video {
   color: rgb(244 63 94 / var(--tw-text-opacity));
 }
 
-.text-cyan-500 {
-  --tw-text-opacity: 1;
-  color: rgb(6 182 212 / var(--tw-text-opacity));
-}
-
 .underline {
   -webkit-text-decoration-line: underline;
           text-decoration-line: underline;
@@ -1890,6 +1905,12 @@ video {
   transition-duration: 150ms;
 }
 
+.transition-opacity {
+  transition-property: opacity;
+  transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
+  transition-duration: 150ms;
+}
+
 .\!transition {
   transition-property: color, background-color, border-color, fill, stroke, opacity, box-shadow, transform, filter, -webkit-text-decoration-color, -webkit-backdrop-filter !important;
   transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter !important;
@@ -1910,8 +1931,9 @@ video {
   transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
 }
 
-.hover\:border-b-4:hover {
-  border-bottom-width: 4px;
+.hover\:border-stone-700:hover {
+  --tw-border-opacity: 1;
+  border-color: rgb(68 64 60 / var(--tw-border-opacity));
 }
 
 .hover\:border-stone-200:hover {
@@ -1919,11 +1941,6 @@ video {
   border-color: rgb(231 229 228 / var(--tw-border-opacity));
 }
 
-.hover\:border-stone-700:hover {
-  --tw-border-opacity: 1;
-  border-color: rgb(68 64 60 / var(--tw-border-opacity));
-}
-
 .hover\:border-rose-500:hover {
   --tw-border-opacity: 1;
   border-color: rgb(244 63 94 / var(--tw-border-opacity));
@@ -1974,6 +1991,11 @@ video {
   background-color: rgb(214 211 209 / var(--tw-bg-opacity));
 }
 
+.hover\:bg-rose-700:hover {
+  --tw-bg-opacity: 1;
+  background-color: rgb(190 18 60 / var(--tw-bg-opacity));
+}
+
 .hover\:bg-stone-50:hover {
   --tw-bg-opacity: 1;
   background-color: rgb(250 250 249 / var(--tw-bg-opacity));
@@ -1994,21 +2016,6 @@ video {
   background-color: rgb(202 138 4 / var(--tw-bg-opacity));
 }
 
-.hover\:bg-rose-700:hover {
-  --tw-bg-opacity: 1;
-  background-color: rgb(190 18 60 / var(--tw-bg-opacity));
-}
-
-.hover\:bg-cyan-500:hover {
-  --tw-bg-opacity: 1;
-  background-color: rgb(6 182 212 / var(--tw-bg-opacity));
-}
-
-.hover\:bg-stone-50:hover {
-  --tw-bg-opacity: 1;
-  background-color: rgb(250 250 249 / var(--tw-bg-opacity));
-}
-
 .hover\:text-stone-50:hover {
   --tw-text-opacity: 1;
   color: rgb(250 250 249 / var(--tw-text-opacity));
@@ -2034,6 +2041,10 @@ video {
           text-decoration-line: underline;
 }
 
+.hover\:opacity-100:hover {
+  opacity: 1;
+}
+
 .focus\:border-blue-600:focus {
   --tw-border-opacity: 1;
   border-color: rgb(37 99 235 / var(--tw-border-opacity));
@@ -2084,19 +2095,14 @@ video {
   cursor: not-allowed;
 }
 
-.disabled\:bg-stone-50:disabled {
-  --tw-bg-opacity: 1;
-  background-color: rgb(250 250 249 / var(--tw-bg-opacity));
-}
-
 .disabled\:bg-stone-200:disabled {
   --tw-bg-opacity: 1;
   background-color: rgb(231 229 228 / var(--tw-bg-opacity));
 }
 
-.disabled\:text-stone-900:disabled {
-  --tw-text-opacity: 1;
-  color: rgb(28 25 23 / var(--tw-text-opacity));
+.disabled\:bg-stone-50:disabled {
+  --tw-bg-opacity: 1;
+  background-color: rgb(250 250 249 / var(--tw-bg-opacity));
 }
 
 .disabled\:text-stone-800:disabled {
@@ -2104,6 +2110,11 @@ video {
   color: rgb(41 37 36 / var(--tw-text-opacity));
 }
 
+.disabled\:text-stone-900:disabled {
+  --tw-text-opacity: 1;
+  color: rgb(28 25 23 / var(--tw-text-opacity));
+}
+
 .group:hover .group-hover\:visible {
   visibility: visible;
 }
diff --git a/system/typemill/author/js/vue-blox-components.js b/system/typemill/author/js/vue-blox-components.js
index 1a56b2e..8791ecb 100644
--- a/system/typemill/author/js/vue-blox-components.js
+++ b/system/typemill/author/js/vue-blox-components.js
@@ -1294,6 +1294,9 @@ bloxeditor.component('inline-formats', {
 
 bloxeditor.component('image-component', {
 	props: ['markdown', 'disabled', 'index'],
+	components: {
+		medialib: medialib
+	},	
 	template: `
@@ -1303,13 +1306,14 @@ bloxeditor.component('image-component', {
- + +
@@ -1490,6 +1494,19 @@ bloxeditor.component('image-component', { } }, methods: { + closemedialib() + { + this.showmedialib = false; + }, + addFromMedialibFunction(value) + { + this.imgfile = value; + this.imgpreview = data.urlinfo.baseurl + '/' + value; + this.showmedialib = false; + this.saveimage = false; + + this.createmarkdown(); + }, updatemarkdown(event) { this.$emit('updateMarkdownEvent', event.target.value); @@ -1619,19 +1636,10 @@ bloxeditor.component('image-component', { errors = this.$filters.translate('Maximum size of image caption is 140 characters'); } } - - /* - if(this.noresize === true) - { - imgmarkdown = imgmarkdown + '|noresize'; - } - */ if(errors) { console.info(errors); -// this.$parent.freezePage(); -// publishController.errors.message = errors; } else { @@ -1692,7 +1700,7 @@ bloxeditor.component('image-component', { { this.showresize = false; this.noresize = false; - this.showmedialib = true; + this.showmedialib = true; }, isChecked(classname) { @@ -1806,6 +1814,9 @@ bloxeditor.component('image-component', { bloxeditor.component('file-component', { props: ['markdown', 'disabled', 'index'], + components: { + medialib: medialib + }, template: `
@@ -1825,13 +1836,14 @@ bloxeditor.component('file-component', { {{ $filters.translate('select from medialib') }}
- + +
@@ -1906,6 +1918,18 @@ bloxeditor.component('file-component', { this.getrestriction(); }, methods: { + addFromMedialibFunction(file) + { + this.showmedialib = false; + this.savefile = false; + this.fileurl = file.url; + this.filemeta = true; + this.filetitle = file.name; + this.fileextension = file.info.extension; + + this.createmarkdown(); + this.getrestriction(file.url); + }, openmedialib: function() { this.showmedialib = true; @@ -2168,8 +2192,6 @@ bloxeditor.component('video-component', { }, parseUrl(url) { - alert("parse: " + url); - let urlparts = url.split('?'); let urlParams = new URLSearchParams(urlparts[1]); @@ -2189,7 +2211,6 @@ bloxeditor.component('video-component', { }, updatemarkdown(url) { - alert("update: " + url); this.edited = true; this.url = url; this.parseUrl(url); diff --git a/system/typemill/author/js/vue-medialib.js b/system/typemill/author/js/vue-medialib.js index 35b8a69..f854432 100644 --- a/system/typemill/author/js/vue-medialib.js +++ b/system/typemill/author/js/vue-medialib.js @@ -1,229 +1,320 @@ const medialib = { props: ['parentcomponent'], - template: `
-
-
- -
-
-
- - + template: `
+
+
+
+
+ +
+ + + +
+
+
+
+

Images

+
+ + +
+
+
+

Files

+
+ + +
+
-
-
{{errors}}
- -
- - click to select - -
-
{{ image.name }}
- - +
+
{{errors}}
+
+ +
+ + + + + click to select + + +
+
{{ image.name }}
+
+ + +
+
-
- -
-
-
-
- -
-
-
-
Name
{{ imagedetaildata.name}}
-
URL
{{ getImageUrl(imagedetaildata.src_live)}}
-
-
-
Size
{{ getSize(imagedetaildata.bytes) }}
-
-
-
Dimensions
{{ imagedetaildata.width }}x{{ imagedetaildata.height }} px
-
-
-
Type
{{ imagedetaildata.type }}
-
-
-
Date
{{ getDate(imagedetaildata.timestamp) }}
-
-
-
- - -
-
-
- -
-

Image used in:

- -
No pages found.
'+ -
+
- -
- -
- -
-
-
{{ file.name }}
- - -
-
-
-
-
-
-
-
{{ filedetaildata.info.extension }}
-
-
-
-
Name
{{ filedetaildata.name}}
-
URL
{{ filedetaildata.url}}
-
-
-
Size
{{ getSize(filedetaildata.bytes) }}
-
-
-
Type
{{ filedetaildata.info.extension }}
-
-
-
Date
{{ getDate(filedetaildata.timestamp) }}
+ +
+
+
+
+
-
- - +
+
Name
+
{{ imagedetaildata.name}}
+
URL
+
{{ getImageUrl(imagedetaildata.src_live)}}
+
+
+
Size
+
{{ getSize(imagedetaildata.bytes) }}
+
+
+
Dimensions
+
{{ imagedetaildata.width }}x{{ imagedetaildata.height }} px
+
+
+
Type
+
{{ imagedetaildata.type }}
+
+
+
Date
+
{{ getDate(imagedetaildata.timestamp) }}
+
+
+
+ + +
+
- -
-

File used in:

- -
No pages found.
'+ -
+ +
+ +
+ +
{{ file.info.extension }}
+ + + + click to select + +
+
+
{{ file.name }}
+
+ + +
+
+
+
+ +
+
+
+
+
{{ filedetaildata.info.extension }}
+
+
+
+
Name
+
{{ filedetaildata.name}}
+
URL
+
{{ filedetaildata.url }}
+
+
+
Size
+
{{ getSize(filedetaildata.bytes) }}
+
+
+
Type
+
{{ filedetaildata.info.extension }}
+
+
+
Date
+
{{ getDate(filedetaildata.timestamp) }}
+
+
+
+ + +
+
+ +
+
+
`, data: function(){ return { - imagedata: false, - showimages: true, - imagedetaildata: false, - showimagedetails: false, - filedata: false, - showfiles: false, - filedetaildata: false, - showfiledetails: false, - detailindex: false, - load: false, - baseurl: myaxios.defaults.baseURL, - adminurl: false, - search: '', - errors: false, + active: false, + imagedata: false, + pagemedia: false, + showimages: true, + imagedetaildata: false, + showimagedetails: false, + filedata: false, + showfiles: false, + filedetaildata: false, + showfiledetails: false, + detailindex: false, + load: false, + adminurl: false, + baseurl: data.urlinfo.baseurl, + search: '', + errors: false, } }, mounted: function(){ - + + this.errors = false; + + var self = this; + + tmaxios.get('/api/v1/pagemedia',{ + params: { + 'url': data.urlinfo.route, + 'path': data.item.pathWithoutType + } + }) + .then(function (response) + { + self.pagemedia = response.data.pagemedia; + }) + .catch(function (error) + { + if(error.response) + { + self.errors = error.response.data.errors; + } + }); + if(this.parentcomponent == 'files') { this.showFiles(); + this.active = 'pageFiles'; + } + if(this.parentcomponent == 'images') + { + this.showImages(); + this.active = 'pageImages'; } - - this.errors = false; - var self = this; - - myaxios.get('/api/v1/medialib/images',{ - params: { - 'url': document.getElementById("path").value, - } - }) - .then(function (response) - { - self.imagedata = response.data.images; - }) - .catch(function (error) - { - if(error.response) - { - self.errors = error.response.data.errors; - } - }); }, - computed: { - filteredImages() { + computed: { + filteredImages() { - var searchimages = this.search; - var filteredImages = {}; - var images = this.imagedata; - if(images) - { - Object.keys(images).forEach(function(key) { - var searchindex = key + ' ' + images[key].name; - if(searchindex.toLowerCase().indexOf(searchimages.toLowerCase()) !== -1) - { - filteredImages[key] = images[key]; - } - }); - } - return filteredImages; - }, - filteredFiles() { + var searchimages = this.search; + var filteredImages = {}; + var images = this.imagedata; + var pagemedia = this.pagemedia; + var active = this.active; - var searchfiles = this.search; - var filteredFiles = {}; - var files = this.filedata; - if(files) - { - Object.keys(files).forEach(function(key) { - var searchindex = key + ' ' + files[key].name; - if(searchindex.toLowerCase().indexOf(searchfiles.toLowerCase()) !== -1) - { - filteredFiles[key] = files[key]; - } - }); - } - return filteredFiles; - } - }, + if(images) + { + if(active == 'pageImages') + { + Object.keys(images).forEach(function(key) { + var imagename = images[key].name; + if(pagemedia.indexOf(imagename) !== -1) + { + filteredImages[key] = images[key]; + } + }); + } + else + { + Object.keys(images).forEach(function(key) { + var searchindex = key + ' ' + images[key].name; + if(searchindex.toLowerCase().indexOf(searchimages.toLowerCase()) !== -1) + { + filteredImages[key] = images[key]; + } + }); + } + } + return filteredImages; + }, + filteredFiles() { + + var searchfiles = this.search; + var filteredFiles = {}; + var files = this.filedata; + var pagemedia = this.pagemedia; + var active = this.active; + + if(files) + { + if(active == 'pageFiles') + { + Object.keys(files).forEach(function(key) { + var filename = files[key].name; + if(pagemedia.indexOf(filename) !== -1) + { + filteredFiles[key] = files[key]; + } + }); + } + else + { + Object.keys(files).forEach(function(key) { + var searchindex = key + ' ' + files[key].name; + if(searchindex.toLowerCase().indexOf(searchfiles.toLowerCase()) !== -1) + { + filteredFiles[key] = files[key]; + } + }); + } + } + return filteredFiles; + }, + }, methods: { - isImagesActive: function() + isActive(activestring) { - if(this.showimages) + if(this.active == activestring) { - return 'bg-tm-green white'; + return 'bg-stone-700 text-stone-50'; } - return 'bg-light-gray black'; + return 'bg-stone-200'; }, - isFilesActive: function() - { - if(this.showfiles) - { - return 'bg-tm-green white'; - } - return 'bg-light-gray black'; - }, - closemedialib: function() - { - this.$parent.showmedialib = false; - }, - getBackgroundImage: function(image) + getBackgroundImage(image) { return 'background-image: url(' + this.baseurl + '/' + image.src_thumb + ');width:250px'; }, @@ -231,238 +322,184 @@ const medialib = { { return this.baseurl + '/' + relativeUrl; }, - showImages: function() + showImages(pagesOrAll) { - this.errors = false; - this.showimages = true; - this.showfiles = false; - this.showimagedetails = false; - this.showfiledetails = false; - this.imagedetaildata = false; - this.detailindex = false; - }, - showFiles: function() - { - this.showimages = false; - this.showfiles = true; - this.showimagedetails = false; - this.showfiledetails = false; - this.imagedetaildata = false; - this.filedetaildata = false; - this.detailindex = false; + this.active = pagesOrAll; + this.errors = false; + this.showimages = true; + this.showfiles = false; + this.showimagedetails = false; + this.showfiledetails = false; + this.imagedetaildata = false; + this.detailindex = false; + + if(!this.imagedata) + { + this.errors = false; - if(!this.files) + var imageself = this; + + tmaxios.get('/api/v1/images',{ + params: { + 'url': data.urlinfo.route, + 'path': data.item.pathWithoutType + } + }) + .then(function (response) + { + imageself.imagedata = response.data.images; + }) + .catch(function (error) + { + if(error.response) + { + imageself.errors = error.response.data.errors; + } + }); + } + }, + showFiles(pagesOrAll) + { + this.active = pagesOrAll; + this.showimages = false; + this.showfiles = true; + this.showimagedetails = false; + this.showfiledetails = false; + this.imagedetaildata = false; + this.filedetaildata = false; + this.detailindex = false; + + if(!this.filedata) { this.errors = false; var filesself = this; - myaxios.get('/api/v1/medialib/files',{ - params: { - 'url': document.getElementById("path").value, - 'csrf_name': document.getElementById("csrf_name").value, - 'csrf_value': document.getElementById("csrf_value").value, - } + tmaxios.get('/api/v1/files',{ + params: { + 'url': data.urlinfo.route, + } }) - .then(function (response) - { - filesself.filedata = response.data.files; - }) - .catch(function (error) - { - if(error.response) - { - filesself.errors = error.response.data.errors; - } - }); + .then(function (response) + { + filesself.filedata = response.data.files; + }) + .catch(function (error) + { + if(error.response) + { + filesself.errors = error.response.data.errors; + } + }); } }, - showImageDetails: function(image,index) + showImageDetails(image,index) { - this.errors = false; - this.showimages = false; - this.showfiles = false; - this.showimagedetails = true; - this.detailindex = index; - this.adminurl = myaxios.defaults.baseURL + '/tm/content/visual'; + this.errors = false; + this.showimages = false; + this.showfiles = false; + this.showimagedetails = true; + this.showfiledetails = false; + this.detailindex = index; + this.adminurl = this.baseurl + '/tm/content/visual'; var imageself = this; - myaxios.get('/api/v1/image',{ - params: { - 'url': document.getElementById("path").value, - 'name': image.name, - 'csrf_name': document.getElementById("csrf_name").value, - 'csrf_value': document.getElementById("csrf_value").value, - } - }) - .then(function (response) - { - imageself.imagedetaildata = response.data.image; - }) - .catch(function (error) - { - if(error.response) - { - imageself.errors = error.response.data.errors; - } - }); - }, - showFileDetails: function(file,index) - { - this.errors = false; - this.showimages = false; - this.showfiles = false; - this.showimagedetails = false; - this.showfiledetails = true; - this.detailindex = index; - - this.adminurl = myaxios.defaults.baseURL + '/tm/content/visual'; - - var fileself = this; - - myaxios.get('/api/v1/file',{ - params: { - 'url': document.getElementById("path").value, - 'name': file.name, - 'csrf_name': document.getElementById("csrf_name").value, - 'csrf_value': document.getElementById("csrf_value").value, - } - }) - .then(function (response) - { - fileself.filedetaildata = response.data.file; - }) - .catch(function (error) - { - if(error.response) - { - fileself.errors = error.response.data.errors; - } - }); - }, - selectImage: function(image) - { - this.showImages(); - - if(this.parentcomponent == 'images') - { - var imgmarkdown = {target: {value: '![alt]('+ image.src_live +')' }}; - - this.$parent.imgfile = image.src_live; - this.$parent.imgpreview = this.baseurl + '/' + image.src_live; - this.$parent.imgmeta = true; - - this.$parent.showmedialib = false; - - this.$parent.createmarkdown(image.src_live); -/* this.$parent.updatemarkdown(imgmarkdown, image.src_live); */ - } - if(this.parentcomponent == 'files') - { - var filemarkdown = {target: {value: '[' + image.name + '](' + image.src_live +'){.tm-download}' }}; - - this.$parent.filemeta = true; - this.$parent.filetitle = image.name; - - this.$parent.showmedialib = false; - - this.$parent.updatemarkdown(filemarkdown, image.src_live); - } - }, - selectFile: function(file) - { - /* if image component is open */ - if(this.parentcomponent == 'images') - { - var imgextensions = ['png','jpg', 'jpeg', 'gif', 'svg', 'webp']; - if(imgextensions.indexOf(file.info.extension) == -1) - { - this.errors = "you cannot insert a file into an image component"; - return; + tmaxios.get('/api/v1/image',{ + params: { + 'url': data.urlinfo.route, + 'name': image.name, } - var imgmarkdown = {target: {value: '![alt]('+ file.url +')' }}; - - this.$parent.imgfile = file.url; - this.$parent.imgpreview = this.baseurl + '/' + file.url; - this.$parent.imgmeta = true; - - this.$parent.showmedialib = false; - - this.$parent.createmarkdown(file.url); -/* this.$parent.updatemarkdown(imgmarkdown, file.url);*/ - } - if(this.parentcomponent == 'files') + }) + .then(function (response) { - var filemarkdown = {target: {value: '['+ file.name +']('+ file.url +'){.tm-download file-' + file.info.extension + '}' }}; + imageself.imagedetaildata = response.data.image; + }) + .catch(function (error) + { + if(error.response) + { + imageself.errors = error.response.data.errors; + } + }); + }, + showFileDetails(file,index) + { + this.errors = false; + this.showimages = false; + this.showfiles = false; + this.showimagedetails = false; + this.showfiledetails = true; + this.filedetaildata = file; + this.detailindex = index; + this.adminurl = this.baseurl + '/tm/content/visual'; + }, + selectImage(image) + { + this.$emit('addFromMedialibEvent', image.src_live); + }, + selectFile(file) + { + let extension = file.info.extension.toUpperCase(); + let size = this.getSize(file.bytes); + file.name = file.name + ' (' + extension + ', ' + size + ')'; - this.$parent.showmedialib = false; - - this.$parent.filemeta = true; - this.$parent.filetitle = file.info.filename + ' (' + file.info.extension.toUpperCase() + ')'; - - this.$parent.updatemarkdown(filemarkdown, file.url); - } - this.showFiles(); - }, - removeImage: function(index) + this.$emit('addFromMedialibEvent', file); + }, + removeImage(index) { this.imagedata.splice(index,1); }, - removeFile: function(index) + removeFile(index) { this.filedata.splice(index,1); }, - deleteImage: function(image, index) + deleteImage(image, index) { imageself = this; - myaxios.delete('/api/v1/image',{ - data: { - 'url': document.getElementById("path").value, - 'name': image.name, - 'index': index, - 'csrf_name': document.getElementById("csrf_name").value, - 'csrf_value': document.getElementById("csrf_value").value, - } + tmaxios.delete('/api/v1/image',{ + data: { + 'url': data.urlinfo.route, + 'name': image.name, + 'index': index, + } }) - .then(function (response) - { + .then(function (response) + { imageself.showImages(); - imageself.removeImage(index); - }) - .catch(function (error) - { - if(error.response) - { - imageself.errors = error.response.data.errors; - } - }); + imageself.removeImage(index); + }) + .catch(function (error) + { + if(error.response) + { + imageself.errors = error.response.data.errors; + } + }); }, - deleteFile: function(file, index) + deleteFile(file, index) { fileself = this; - myaxios.delete('/api/v1/file',{ - data: { - 'url': document.getElementById("path").value, - 'name': file.name, - 'index': index, - 'csrf_name': document.getElementById("csrf_name").value, - 'csrf_value': document.getElementById("csrf_value").value, - } + tmaxios.delete('/api/v1/file',{ + data: { + 'url': data.urlinfo.route, + 'name': file.name, + 'index': index, + } }) - .then(function (response) - { - fileself.showFiles(); - fileself.removeFile(index); - }) - .catch(function (error) - { - if(error.response) - { - fileself.errors = error.response.data.errors; - } - }); + .then(function (response) + { + fileself.showFiles(); + fileself.removeFile(index); + }) + .catch(function (error) + { + if(error.response) + { + fileself.errors = error.response.data.errors; + } + }); }, getDate(timestamp) { @@ -480,12 +517,12 @@ const medialib = { }, getSize(bytes) { - var i = Math.floor(Math.log(bytes) / Math.log(1024)), - sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']; + var i = Math.floor(Math.log(bytes) / Math.log(1024)), + sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']; - return (bytes / Math.pow(1024, i)).toFixed(2) * 1 + ' ' + sizes[i]; + return (bytes / Math.pow(1024, i)).toFixed(2) * 1 + ' ' + sizes[i]; }, - isChecked: function(classname) + isChecked(classname) { if(this.imgclass == classname) { diff --git a/system/typemill/author/js/vue-meta.js b/system/typemill/author/js/vue-meta.js index 26a2162..32b73d5 100644 --- a/system/typemill/author/js/vue-meta.js +++ b/system/typemill/author/js/vue-meta.js @@ -121,7 +121,7 @@ const app = Vue.createApp({ this.saved = false; self = this; - tmaxios.post('/api/v1/metadata',{ + tmaxios.post('/api/v1/meta',{ 'url': data.urlinfo.route, 'tab': self.currentTab, 'data': self.formData[self.currentTab] diff --git a/system/typemill/author/layouts/layoutContent.twig b/system/typemill/author/layouts/layoutContent.twig index 432b854..e1c607d 100644 --- a/system/typemill/author/layouts/layoutContent.twig +++ b/system/typemill/author/layouts/layoutContent.twig @@ -60,6 +60,7 @@ + diff --git a/system/typemill/author/layouts/layoutSystem.twig b/system/typemill/author/layouts/layoutSystem.twig index 1bacbb9..8fd5f50 100644 --- a/system/typemill/author/layouts/layoutSystem.twig +++ b/system/typemill/author/layouts/layoutSystem.twig @@ -65,6 +65,7 @@ + diff --git a/system/typemill/routes/api.php b/system/typemill/routes/api.php index 36bf866..514a8a4 100644 --- a/system/typemill/routes/api.php +++ b/system/typemill/routes/api.php @@ -40,18 +40,21 @@ $app->group('/api/v1', function (RouteCollectorProxy $group) use ($acl) { $group->delete('/user', ControllerApiSystemUsers::class . ':deleteUser')->setName('api.user.delete')->add(new ApiAuthorization($acl, 'account', 'delete')); # member # IMAGES + $group->get('/pagemedia', ControllerApiImage::class . ':getPagemedia')->setName('api.image.pagemedia')->add(new ApiAuthorization($acl, 'mycontent', 'read')); + $group->get('/images', ControllerApiImage::class . ':getImages')->setName('api.image.images')->add(new ApiAuthorization($acl, 'mycontent', 'read')); $group->post('/image', ControllerApiImage::class . ':saveImage')->setName('api.image.create')->add(new ApiAuthorization($acl, 'mycontent', 'create')); $group->put('/image', ControllerApiImage::class . ':publishImage')->setName('api.image.publish')->add(new ApiAuthorization($acl, 'mycontent', 'create')); -# $group->get('/image', ControllerApiMedia::class . ':getImage')->setName('api.image.get'); -# $group->delete('/image', ControllerApiMedia::class . ':deleteImage')->setName('api.image.delete'); + $group->get('/image', ControllerApiImage::class . ':getImage')->setName('api.image.get')->add(new ApiAuthorization($acl, 'mycontent', 'read')); + $group->delete('/image', ControllerApiImage::class . ':deleteImage')->setName('api.image.delete')->add(new ApiAuthorization($acl, 'mycontent', 'delete')); # FILES $group->get('/filerestrictions', ControllerApiFile::class . ':getFileRestrictions')->setName('api.file.getrestrictions')->add(new ApiAuthorization($acl, 'mycontent', 'create')); $group->post('/filerestrictions', ControllerApiFile::class . ':updateFileRestrictions')->setName('api.file.updaterestrictions')->add(new ApiAuthorization($acl, 'mycontent', 'create')); $group->post('/file', ControllerApiFile::class . ':uploadFile')->setName('api.file.upload')->add(new ApiAuthorization($acl, 'mycontent', 'create')); $group->put('/file', ControllerApiFile::class . ':publishFile')->setName('api.file.publish')->add(new ApiAuthorization($acl, 'mycontent', 'update')); -# $group->get('/api/v1/file', ControllerAuthorMediaApi::class . ':getFile')->setName('api.file.get')->add(new RestrictApiAccess($container['router'])); -# $app->delete('/api/v1/file', ControllerAuthorMediaApi::class . ':deleteFile')->setName('api.file.delete')->add(new RestrictApiAccess($container['router'])); + $group->get('/files', ControllerApiFile::class . ':getFiles')->setName('api.files.get')->add(new ApiAuthorization($acl, 'mycontent', 'read')); + $group->get('/file', ControllerApiFile::class . ':getFile')->setName('api.file.get')->add(new ApiAuthorization($acl, 'mycontent', 'read')); + $group->delete('/file', ControllerApiFile::class . ':deleteFile')->setName('api.file.delete')->add(new ApiAuthorization($acl, 'mycontent', 'read')); # ARTICLE $group->post('/article/sort', ControllerApiAuthorArticle::class . ':sortArticle')->setName('api.article.sort')->add(new ApiAuthorization($acl, 'content', 'create')); # author @@ -75,9 +78,7 @@ $app->group('/api/v1', function (RouteCollectorProxy $group) use ($acl) { $group->get('/shortcodedata', ControllerApiAuthorShortcode::class . ':getShortcodeData')->setName('api.shortcodedata.get')->add(new ApiAuthorization($acl, 'mycontent', 'view')); # META - $group->get('/metadata', ControllerApiAuthorMeta::class . ':getMetaData')->setName('api.metadata.get')->add(new ApiAuthorization($acl, 'mycontent', 'view')); - $group->get('/metadefinitions', ControllerApiAuthorMeta::class . ':getMetaDefinitions')->setName('api.definitions.get')->add(new ApiAuthorization($acl, 'mycontent', 'view')); - $group->post('/metadata', ControllerApiAuthorMeta::class . ':updateMetaData')->setName('api.metadata.update')->add(new ApiAuthorization($acl, 'mycontent', 'update')); $group->get('/meta', ControllerApiAuthorMeta::class . ':getMeta')->setName('api.meta.get')->add(new ApiAuthorization($acl, 'mycontent', 'view')); + $group->post('/meta', ControllerApiAuthorMeta::class . ':updateMeta')->setName('api.metadata.update')->add(new ApiAuthorization($acl, 'mycontent', 'update')); })->add(new ApiAuthentication()); \ No newline at end of file