mirror of
https://github.com/typemill/typemill.git
synced 2025-07-18 21:11:13 +02:00
Navigation nearly ready
This commit is contained in:
@@ -1,23 +0,0 @@
|
||||
meta:
|
||||
title: 'Get Help'
|
||||
description: 'If you need any help, then please read the documentation on typemill.net first. Some short video-tutorials are in work right'
|
||||
heroimage: null
|
||||
heroimagealt: null
|
||||
owner: null
|
||||
author: 'Sebastian Schürmanns'
|
||||
allowedrole: null
|
||||
alloweduser: null
|
||||
manualdate: null
|
||||
modified: '2021-06-13'
|
||||
created: null
|
||||
time: null
|
||||
navtitle: ''
|
||||
hide: false
|
||||
seo:
|
||||
heroimage: media/live/bildschirmfoto-zu-2019-08-30-20-46-29.png
|
||||
heroimagealt: Alt-Text
|
||||
customfields:
|
||||
myfield:
|
||||
bla:
|
||||
- text
|
||||
- test
|
15
content/01-cyanine-theme/00-colors-and-fonts.yaml
Normal file
15
content/01-cyanine-theme/00-colors-and-fonts.yaml
Normal file
@@ -0,0 +1,15 @@
|
||||
meta:
|
||||
navtitle: 'colors and fonts'
|
||||
hide: false
|
||||
title: 'Colors and Fonts'
|
||||
description: 'First of all cyanine supports individual logos. If you want to use our logo, then please upload it in the system settings. Cyanine will automatically replace the title text with your logo. '
|
||||
heroimage: null
|
||||
heroimagealt: null
|
||||
owner: null
|
||||
author: trendschau
|
||||
allowedrole: null
|
||||
alloweduser: null
|
||||
manualdate: null
|
||||
modified: '2021-10-04'
|
||||
created: '2020-06-11'
|
||||
time: 20-37-12
|
15
content/01-cyanine-theme/01-landingpage.yaml
Normal file
15
content/01-cyanine-theme/01-landingpage.yaml
Normal file
@@ -0,0 +1,15 @@
|
||||
meta:
|
||||
title: 'The Landingpage'
|
||||
description: "Cyanine provides an optional landingpage with six segments: \nIntro with the content of the home page and an additional link/button.\nInfo with individual markdown content.\nTeaser with two elements. Each element has a headline, a text and a link/button.\nContrast with a headline, text-input and a"
|
||||
heroimage: ''
|
||||
heroimagealt: null
|
||||
owner: trendschau
|
||||
author: 'Sebastian Schürmanns'
|
||||
allowedrole: null
|
||||
alloweduser: null
|
||||
manualdate: null
|
||||
modified: '2021-05-18'
|
||||
created: '2021-06-17'
|
||||
time: 16-23-19
|
||||
navtitle: landingpage
|
||||
hide: false
|
File diff suppressed because one or more lines are too long
@@ -4,11 +4,11 @@
|
||||
noindex: false
|
||||
path: /00-welcome
|
||||
keyPath: 0
|
||||
/welcome/setup-your-website:
|
||||
/welcome/markdown-test:
|
||||
navtitle: ''
|
||||
hide: false
|
||||
noindex: false
|
||||
path: /00-welcome/00-setup-your-website.md
|
||||
path: /00-welcome/00-markdown-test.md
|
||||
keyPath: '0.0'
|
||||
/welcome/manage-access:
|
||||
navtitle: ''
|
||||
@@ -16,23 +16,23 @@
|
||||
noindex: false
|
||||
path: /00-welcome/01-manage-access.md
|
||||
keyPath: '0.1'
|
||||
/welcome/write-content:
|
||||
navtitle: ''
|
||||
hide: false
|
||||
noindex: false
|
||||
path: /00-welcome/02-write-content.md
|
||||
keyPath: '0.2'
|
||||
/welcome/get-help:
|
||||
navtitle: ''
|
||||
hide: false
|
||||
noindex: false
|
||||
path: /00-welcome/03-get-help.md
|
||||
keyPath: '0.3'
|
||||
/welcome/markdown-test:
|
||||
path: /00-welcome/02-get-help.md
|
||||
keyPath: '0.2'
|
||||
/welcome/setup-your-website:
|
||||
navtitle: ''
|
||||
hide: false
|
||||
noindex: false
|
||||
path: /00-welcome/04-markdown-test.md
|
||||
path: /00-welcome/03-setup-your-website.md
|
||||
keyPath: '0.3'
|
||||
/welcome/write-content:
|
||||
navtitle: ''
|
||||
hide: false
|
||||
noindex: false
|
||||
path: /00-welcome/04-write-content.md
|
||||
keyPath: '0.4'
|
||||
/cyanine-theme:
|
||||
navtitle: ''
|
||||
@@ -40,17 +40,17 @@
|
||||
noindex: false
|
||||
path: /01-cyanine-theme
|
||||
keyPath: 1
|
||||
/cyanine-theme/landingpage:
|
||||
navtitle: ''
|
||||
hide: false
|
||||
noindex: false
|
||||
path: /01-cyanine-theme/00-landingpage.md
|
||||
keyPath: '1.0'
|
||||
/cyanine-theme/colors-and-fonts:
|
||||
navtitle: ''
|
||||
hide: false
|
||||
noindex: false
|
||||
path: /01-cyanine-theme/01-colors-and-fonts.md
|
||||
path: /01-cyanine-theme/00-colors-and-fonts.md
|
||||
keyPath: '1.0'
|
||||
/cyanine-theme/landingpage:
|
||||
navtitle: ''
|
||||
hide: false
|
||||
noindex: false
|
||||
path: /01-cyanine-theme/01-landingpage.md
|
||||
keyPath: '1.1'
|
||||
/cyanine-theme/footer:
|
||||
navtitle: ''
|
||||
|
335
system/typemill/Controllers/ControllerApiAuthorArticle.php
Normal file
335
system/typemill/Controllers/ControllerApiAuthorArticle.php
Normal file
@@ -0,0 +1,335 @@
|
||||
<?php
|
||||
|
||||
namespace Typemill\Controllers;
|
||||
|
||||
use Psr\Http\Message\ServerRequestInterface as Request;
|
||||
use Psr\Http\Message\ResponseInterface as Response;
|
||||
use Slim\Routing\RouteContext;
|
||||
|
||||
use Typemill\Models\Navigation;
|
||||
use Typemill\Models\Validation;
|
||||
use Typemill\Models\StorageWrapper;
|
||||
|
||||
class ControllerApiAuthorArticle extends Controller
|
||||
{
|
||||
public function sortArticle(Request $request, Response $response, $args)
|
||||
{
|
||||
$params = $request->getParsedBody();
|
||||
|
||||
# input validation
|
||||
$validate = new Validation();
|
||||
$result = $validate->navigationSort($params);
|
||||
if(!$result)
|
||||
{
|
||||
$response->getBody()->write(json_encode([
|
||||
'message' => 'Data not valid. Please refresh the page and try again.',
|
||||
'errors' => $result
|
||||
]));
|
||||
|
||||
return $response->withHeader('Content-Type', 'application/json')->withStatus(422);
|
||||
}
|
||||
|
||||
# set variables
|
||||
$itemKeyPath = explode('.', $params['item_id']);
|
||||
$parentKeyFrom = explode('.', $params['parent_id_from']);
|
||||
$parentKeyTo = explode('.', $params['parent_id_to']);
|
||||
$urlinfo = $this->c->get('urlinfo');
|
||||
$langattr = $this->settings['langattr'];
|
||||
|
||||
# get navigation
|
||||
$navigation = new Navigation();
|
||||
$draftNavigation = $navigation->getDraftNavigation($urlinfo, $langattr);
|
||||
|
||||
# validate user rights
|
||||
$acl = $this->c->get('acl');
|
||||
|
||||
# if user has no right to update content from others (eg admin or editor)
|
||||
if(!$acl->isAllowed($request->getAttribute('c_userrole'), 'content', 'update'))
|
||||
{
|
||||
# check ownership. This code should nearly never run, because there is no button/interface to trigger it.
|
||||
if(!$this->checkContentOwnership())
|
||||
{
|
||||
$response->getBody()->write(json_encode([
|
||||
'message' => 'You are not allowed to move that content.',
|
||||
'navigation' => $draftNavigation
|
||||
]));
|
||||
|
||||
return $response->withHeader('Content-Type', 'application/json')->withStatus(422);
|
||||
}
|
||||
}
|
||||
|
||||
$item = $navigation->getItemWithKeyPath($draftNavigation, $itemKeyPath);
|
||||
|
||||
$extendedNavigation = $navigation->getExtendedNavigation($urlinfo, $langattr);
|
||||
|
||||
$pageinfo = $extendedNavigation[$params['url']] ?? false;
|
||||
|
||||
if(!$pageinfo)
|
||||
{
|
||||
$response->getBody()->write(json_encode([
|
||||
'message' => 'page not found',
|
||||
]));
|
||||
|
||||
return $response->withHeader('Content-Type', 'application/json')->withStatus(404);
|
||||
}
|
||||
|
||||
# if an item is moved to the first level
|
||||
if($parentKeyTo == '')
|
||||
{
|
||||
# create empty and default values so that the logic below still works
|
||||
$newFolder = new \stdClass();
|
||||
$newFolder->path = '';
|
||||
$folderContent = $draftNavigation;
|
||||
}
|
||||
else
|
||||
{
|
||||
# get the target folder from navigation
|
||||
$newFolder = $navigation->getItemWithKeyPath($draftNavigation, $parentKeyTo);
|
||||
|
||||
# get the content of the target folder
|
||||
$folderContent = $newFolder->folderContent;
|
||||
}
|
||||
|
||||
# if the item has been moved within the same folder
|
||||
if($parentKeyFrom == $parentKeyTo)
|
||||
{
|
||||
# no need to ping search engines
|
||||
$ping = false;
|
||||
|
||||
# get key of item
|
||||
$itemKey = end($itemKeyPath);
|
||||
reset($itemKeyPath);
|
||||
|
||||
# delete item from folderContent
|
||||
unset($folderContent[$itemKey]);
|
||||
}
|
||||
else
|
||||
{
|
||||
# let us ping search engines
|
||||
$ping = true;
|
||||
|
||||
# rename links in extended file
|
||||
#$navigation->renameExtended($item, $newFolder);
|
||||
|
||||
# an active file has been moved to another folder, so send new url with response
|
||||
if($params['active'] == 'active')
|
||||
{
|
||||
$url = $urlinfo['baseurl'] . '/tm/content/' . $this->settings['editor'] . $newFolder->urlRelWoF . '/' . $item->slug;
|
||||
}
|
||||
}
|
||||
|
||||
# add item to newFolder
|
||||
array_splice($folderContent, $params['index_new'], 0, array($item));
|
||||
|
||||
# move and rename files in the new folder
|
||||
$index = 0;
|
||||
$writeError = false;
|
||||
$storage = new StorageWrapper('\Typemill\Models\Storage');
|
||||
foreach($folderContent as $folderItem)
|
||||
{
|
||||
if(!$storage->moveFile($folderItem, $newFolder->path, $index))
|
||||
{
|
||||
$writeError = true;
|
||||
}
|
||||
$index++;
|
||||
}
|
||||
if($writeError)
|
||||
{
|
||||
$response->getBody()->write(json_encode([
|
||||
'message' => 'Something went wrong. Please refresh the page and check, if all folders and files are writable.',
|
||||
'navigation' => $draftNavigation,
|
||||
'url' => false
|
||||
]));
|
||||
|
||||
return $response->withHeader('Content-Type', 'application/json')->withStatus(404);
|
||||
}
|
||||
|
||||
# if everything worked, we have to recreate the navigation
|
||||
$navigation->clearNavigation();
|
||||
|
||||
/*
|
||||
# get item for url and set it active again
|
||||
if(isset($this->params['url']))
|
||||
{
|
||||
$activeItem = Folder::getItemForUrl($this->structureDraft, $this->params['url'], $this->uri->getBaseUrl());
|
||||
}
|
||||
|
||||
# update the structure for website
|
||||
$this->setFreshStructureLive();
|
||||
|
||||
# update the navigation
|
||||
$this->setFreshNavigation();
|
||||
|
||||
# update the sitemap
|
||||
$this->updateSitemap($ping);
|
||||
|
||||
# dispatch event
|
||||
$this->c->dispatcher->dispatch('onPageSorted', new OnPageSorted($this->params));
|
||||
*/
|
||||
|
||||
$response->getBody()->write(json_encode([
|
||||
'navigation' => $navigation->getDraftNavigation($urlinfo, $langattr),
|
||||
'message' => '',
|
||||
'url' => false
|
||||
]));
|
||||
|
||||
return $response->withHeader('Content-Type', 'application/json');
|
||||
}
|
||||
|
||||
public function createArticle(Request $request, Response $response, $args)
|
||||
{
|
||||
# validate user rights
|
||||
$acl = $this->c->get('acl');
|
||||
|
||||
# if user has no right to update content from others (eg admin or editor)
|
||||
if(!$acl->isAllowed($request->getAttribute('c_userrole'), 'mycontent', 'create'))
|
||||
{
|
||||
$response->getBody()->write(json_encode([
|
||||
'message' => 'You are not allowed to create content.',
|
||||
]));
|
||||
|
||||
return $response->withHeader('Content-Type', 'application/json')->withStatus(403);
|
||||
}
|
||||
|
||||
$params = $request->getParsedBody();
|
||||
|
||||
# input validation
|
||||
$validate = new Validation();
|
||||
$result = $validate->validateNaviItem($params);
|
||||
if(!$result)
|
||||
{
|
||||
$response->getBody()->write(json_encode([
|
||||
'message' => 'Input not valid.',
|
||||
'errors' => $result
|
||||
]));
|
||||
|
||||
return $response->withHeader('Content-Type', 'application/json')->withStatus(422);
|
||||
}
|
||||
|
||||
# set variables
|
||||
$urlinfo = $this->c->get('urlinfo');
|
||||
$langattr = $this->settings['langattr'];
|
||||
|
||||
# get navigation
|
||||
$navigation = new Navigation();
|
||||
$draftNavigation = $navigation->getDraftNavigation($urlinfo, $langattr);
|
||||
|
||||
if($params['folder_id'] == 'root')
|
||||
{
|
||||
$folderContent = $draftNavigation;
|
||||
}
|
||||
else
|
||||
{
|
||||
# get the ids (key path) for item, old folder and new folder
|
||||
$folderKeyPath = explode('.', $params['folder_id']);
|
||||
|
||||
# get the item from structure
|
||||
$folder = $navigation->getItemWithKeyPath($draftNavigation, $folderKeyPath);
|
||||
|
||||
if(!$folder)
|
||||
{
|
||||
$response->getBody()->write(json_encode([
|
||||
'message' => 'We could not find this page. Please refresh and try again.'
|
||||
]));
|
||||
|
||||
return $response->withHeader('Content-Type', 'application/json')->withStatus(422);
|
||||
}
|
||||
|
||||
$folderContent = $folder->folderContent;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
$name = $params['item_name'];
|
||||
$slug = Folder::createSlug($this->params['item_name'], $this->settings);
|
||||
|
||||
# initialize index
|
||||
$index = 0;
|
||||
|
||||
# iterate through the whole content of the new folder
|
||||
$writeError = false;
|
||||
$folderPath = isset($folder) ? $folder->path : '';
|
||||
|
||||
foreach($folderContent as $folderItem)
|
||||
{
|
||||
# check, if the same name as new item, then return an error
|
||||
if($folderItem->slug == $slug)
|
||||
{
|
||||
return $response->withJson(array('navigation' => $draftNavigation, 'errors' => 'There is already a page with this name. Please choose another name.', 'url' => $url), 404);
|
||||
}
|
||||
|
||||
if(!$writeYaml->moveElement($folderItem, $folderPath, $index))
|
||||
{
|
||||
$writeError = true;
|
||||
}
|
||||
$index++;
|
||||
}
|
||||
|
||||
if($writeError)
|
||||
{
|
||||
return $response->withJson(array('data' => $this->structureDraft, '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 . '-' . $slug : '0' . $index . '-' . $slug;
|
||||
$folderPath = 'content' . $folder->path;
|
||||
|
||||
# create default content
|
||||
$content = json_encode(['# ' . $name, 'Content']);
|
||||
|
||||
if($this->params['type'] == 'file')
|
||||
{
|
||||
if(!$writeYaml->writeFile($folderPath, $namePath . '.txt', $content))
|
||||
{
|
||||
return $response->withJson(array('data' => $this->structureDraft, '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(!$writeYaml->checkPath($folderPath . DIRECTORY_SEPARATOR . $namePath))
|
||||
{
|
||||
return $response->withJson(array('data' => $this->structureDraft, 'errors' => 'We could not create the folder. Please refresh the page and check, if all folders and files are writable.', 'url' => $url), 404);
|
||||
}
|
||||
$this->writeCache->writeFile($folderPath . DIRECTORY_SEPARATOR . $namePath, 'index.txt', $content);
|
||||
|
||||
# always redirect to a folder
|
||||
$url = $this->uri->getBaseUrl() . '/tm/content/' . $this->settings['editor'] . $folder->urlRelWoF . '/' . $slug;
|
||||
|
||||
}
|
||||
|
||||
# get extended structure
|
||||
$extended = $writeYaml->getYaml('cache', 'structure-extended.yaml');
|
||||
|
||||
# create the url for the item
|
||||
$urlWoF = $folder->urlRelWoF . '/' . $slug;
|
||||
# $urlWoF = '/' . $slug;
|
||||
|
||||
# add the navigation name to the item htmlspecialchars needed for french language
|
||||
$extended[$urlWoF] = ['hide' => false, 'navtitle' => $name];
|
||||
|
||||
# store the extended structure
|
||||
$writeYaml->updateYaml('cache', 'structure-extended.yaml', $extended);
|
||||
|
||||
# update the structure for editor
|
||||
$this->setFreshStructureDraft();
|
||||
|
||||
# get item for url and set it active again
|
||||
if(isset($this->params['url']))
|
||||
{
|
||||
$activeItem = Folder::getItemForUrl($this->structureDraft, $this->params['url'], $this->uri->getBaseUrl());
|
||||
}
|
||||
|
||||
# activate this if you want to redirect after creating the page...
|
||||
# $url = $this->uri->getBaseUrl() . '/tm/content/' . $this->settings['editor'] . $folder->urlRelWoF . '/' . $slug;
|
||||
|
||||
return $response->withJson(array('data' => $this->structureDraft, 'errors' => false, 'url' => $url));
|
||||
}
|
||||
}
|
@@ -40,6 +40,35 @@ class Navigation
|
||||
$this->extendedNaviName = 'navi-extended.txt';
|
||||
}
|
||||
|
||||
public function clearNavigation(array $deleteitems = NULL )
|
||||
{
|
||||
# clear cache
|
||||
$this->extendedNavigation = false;
|
||||
$this->draftNavigation = false;
|
||||
$this->basicDraftNavigation = false;
|
||||
$this->liveNavigation = false;
|
||||
$this->basicLiveNavigation = false;
|
||||
|
||||
# clear files
|
||||
$navifiles = [
|
||||
'extended' => $this->extendedNaviName,
|
||||
'draft' => $this->draftNaviName,
|
||||
'live' => $this->liveNaviName
|
||||
];
|
||||
|
||||
if($deleteitems)
|
||||
{
|
||||
$navifiles = array_intersect_key($navifiles, $deleteitems);
|
||||
}
|
||||
|
||||
foreach($navifiles as $navifile)
|
||||
{
|
||||
$result = $this->storage->deleteFile($this->naviFolder, $navifile);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function getMainNavigation($userrole, $acl, $urlinfo, $editor)
|
||||
{
|
||||
$mainnavi = $this->storage->getYaml('system/typemill/settings', 'mainnavi.yaml');
|
||||
@@ -76,7 +105,6 @@ class Navigation
|
||||
return $allowedmainnavi;
|
||||
}
|
||||
|
||||
|
||||
# get the navigation with draft files for author environment
|
||||
public function getDraftNavigation($urlinfo, $language, $userrole = null, $username = null)
|
||||
{
|
||||
|
@@ -192,9 +192,52 @@ class Storage
|
||||
return false;
|
||||
}
|
||||
|
||||
public function moveFile()
|
||||
# used to sort the navigation / files
|
||||
public function moveFile($item, $folderPath, $index, $date = null)
|
||||
{
|
||||
$filetypes = array('md', 'txt', 'yaml');
|
||||
|
||||
# set new order as string
|
||||
$newOrder = ($index < 10) ? '0' . $index : $index;
|
||||
|
||||
$newPath = $this->contentFolder . $folderPath . DIRECTORY_SEPARATOR . $newOrder . '-' . $item->slug;
|
||||
|
||||
if($item->elementType == 'folder')
|
||||
{
|
||||
$oldPath = $this->basePath . 'content' . $item->path;
|
||||
if(@rename($oldPath, $newPath))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
# create old path but without filetype
|
||||
$oldPath = substr($item->path, 0, strpos($item->path, "."));
|
||||
$oldPath = $this->contentFolder . $oldPath;
|
||||
|
||||
$result = true;
|
||||
|
||||
foreach($filetypes as $filetype)
|
||||
{
|
||||
$oldFilePath = $oldPath . '.' . $filetype;
|
||||
$newFilePath = $newPath . '.' . $filetype;
|
||||
|
||||
#check if file with filetype exists and rename
|
||||
if($oldFilePath != $newFilePath && file_exists($oldFilePath))
|
||||
{
|
||||
if(@rename($oldFilePath, $newFilePath))
|
||||
{
|
||||
$result = $result;
|
||||
}
|
||||
else
|
||||
{
|
||||
$result = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -498,54 +541,5 @@ class Storage
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function moveElement($item, $folderPath, $index, $date = null)
|
||||
{
|
||||
$filetypes = array('md', 'txt', 'yaml');
|
||||
|
||||
# set new order as string
|
||||
$newOrder = ($index < 10) ? '0' . $index : $index;
|
||||
|
||||
# create new path with foldername or filename but without file-type
|
||||
# $newPath = $this->basePath . 'content' . $folderPath . DIRECTORY_SEPARATOR . $newOrder . '-' . str_replace(" ", "-", $item->name);
|
||||
|
||||
$newPath = $this->basePath . 'content' . $folderPath . DIRECTORY_SEPARATOR . $newOrder . '-' . $item->slug;
|
||||
|
||||
if($item->elementType == 'folder')
|
||||
{
|
||||
$oldPath = $this->basePath . 'content' . $item->path;
|
||||
if(@rename($oldPath, $newPath))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
# create old path but without filetype
|
||||
$oldPath = substr($item->path, 0, strpos($item->path, "."));
|
||||
$oldPath = $this->basePath . 'content' . $oldPath;
|
||||
|
||||
$result = true;
|
||||
|
||||
foreach($filetypes as $filetype)
|
||||
{
|
||||
$oldFilePath = $oldPath . '.' . $filetype;
|
||||
$newFilePath = $newPath . '.' . $filetype;
|
||||
|
||||
#check if file with filetype exists and rename
|
||||
if($oldFilePath != $newFilePath && file_exists($oldFilePath))
|
||||
{
|
||||
if(@rename($oldFilePath, $newFilePath))
|
||||
{
|
||||
$result = $result;
|
||||
}
|
||||
else
|
||||
{
|
||||
$result = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
*/
|
||||
}
|
@@ -382,6 +382,66 @@ class Validation
|
||||
return $v->errors();
|
||||
}
|
||||
|
||||
/**
|
||||
* validation for resort navigation
|
||||
*
|
||||
* @param array $params with form data.
|
||||
* @return true or $v->errors with array of errors to use in json-response
|
||||
*/
|
||||
|
||||
public function navigationSort(array $params)
|
||||
{
|
||||
$v = new Validator($params);
|
||||
|
||||
$v->rule('required', ['item_id', 'parent_id_from', 'parent_id_to']);
|
||||
$v->rule('regex', 'item_id', '/^[0-9.]+$/i');
|
||||
$v->rule('regex', 'parent_id_from', '/^[a-zA-Z0-9.]+$/i');
|
||||
$v->rule('regex', 'parent_id_to', '/^[a-zA-Z0-9.]+$/i');
|
||||
$v->rule('integer', 'index_new');
|
||||
$v->rule('integer', 'index_old');
|
||||
|
||||
if($v->validate())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
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', '/^(root)|([0-9.]+)$/i');
|
||||
$v->rule('navigation', 'item_name');
|
||||
$v->rule('lengthBetween', 'item_name', 1, 60);
|
||||
$v->rule('in', 'type', ['file', 'folder']);
|
||||
|
||||
if($v->validate())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return $v->errors();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* validation for system settings
|
||||
@@ -463,80 +523,7 @@ class Validation
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* validation for resort navigation
|
||||
*
|
||||
* @param array $params with form data.
|
||||
* @return true or $v->errors with array of errors to use in json-response
|
||||
*/
|
||||
|
||||
public function navigationSort(array $params)
|
||||
{
|
||||
$v = new Validator($params);
|
||||
|
||||
$v->rule('required', ['item_id', 'parent_id_from', 'parent_id_to']);
|
||||
$v->rule('regex', 'item_id', '/^[0-9.]+$/i');
|
||||
$v->rule('regex', 'parent_id_from', '/^[a-zA-Z0-9.]+$/i');
|
||||
$v->rule('regex', 'parent_id_to', '/^[a-zA-Z0-9.]+$/i');
|
||||
$v->rule('integer', 'index_new');
|
||||
|
||||
if($v->validate())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
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('navigation', 'item_name');
|
||||
$v->rule('lengthBetween', 'item_name', 1, 60);
|
||||
$v->rule('in', 'type', ['file', 'folder']);
|
||||
|
||||
if($v->validate())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return $v->errors();
|
||||
}
|
||||
}
|
||||
|
||||
public function navigationBaseItem(array $params)
|
||||
{
|
||||
$v = new Validator($params);
|
||||
|
||||
$v->rule('required', ['item_name', 'type', 'url']);
|
||||
# $v->rule('noSpecialChars', 'item_name');
|
||||
$v->rule('navigation', 'item_name');
|
||||
$v->rule('lengthBetween', 'item_name', 1, 40);
|
||||
$v->rule('in', 'type', ['file', 'folder']);
|
||||
|
||||
if($v->validate())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return $v->errors();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* validation for dynamic fields ( settings for themes and plugins)
|
||||
|
@@ -5,18 +5,10 @@
|
||||
|
||||
<h1 class="text-3xl font-bold mb-4">{{ translate('Visual Editor') }} </h1>
|
||||
|
||||
<div id="veditor" v-cloak></div>
|
||||
<div id="editor" v-cloak></div>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block javascript %}
|
||||
|
||||
<script src="{{ base_url() }}/system/typemill/author/js/highlight.min.js?v={{ settings.version }}"></script>
|
||||
<script src="{{ base_url() }}/system/typemill/author/js/vue-system.js?v={{ settings.version }}"></script>
|
||||
<script src="{{ base_url() }}/system/typemill/author/js/vue-translate.js?v={{ settings.version }}"></script>
|
||||
<script src="{{ base_url() }}/system/typemill/author/js/vue-shared.js?v={{ settings.version }}"></script>
|
||||
<script>
|
||||
app.mount('#veditor');
|
||||
</script>
|
||||
|
||||
{% endblock %}
|
||||
|
@@ -620,6 +620,14 @@ video {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.visible {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
.invisible {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.static {
|
||||
position: static;
|
||||
}
|
||||
@@ -636,6 +644,11 @@ video {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.sticky {
|
||||
position: -webkit-sticky;
|
||||
position: sticky;
|
||||
}
|
||||
|
||||
.inset-0 {
|
||||
top: 0px;
|
||||
right: 0px;
|
||||
@@ -688,6 +701,10 @@ video {
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.m-1 {
|
||||
margin: 0.25rem;
|
||||
}
|
||||
|
||||
.my-2 {
|
||||
margin-top: 0.5rem;
|
||||
margin-bottom: 0.5rem;
|
||||
@@ -723,28 +740,45 @@ video {
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
.mx-1 {
|
||||
margin-left: 0.25rem;
|
||||
margin-right: 0.25rem;
|
||||
}
|
||||
|
||||
.mt-6 {
|
||||
margin-top: 1.5rem;
|
||||
}
|
||||
|
||||
.mb-1 {
|
||||
margin-bottom: 0.25rem;
|
||||
}
|
||||
|
||||
.mt-3 {
|
||||
margin-top: 0.75rem;
|
||||
}
|
||||
|
||||
.mb-4 {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.mr-3 {
|
||||
margin-right: 0.75rem;
|
||||
}
|
||||
|
||||
.mb-1 {
|
||||
margin-bottom: 0.25rem;
|
||||
}
|
||||
|
||||
.mr-1 {
|
||||
margin-right: 0.25rem;
|
||||
}
|
||||
|
||||
.mr-4 {
|
||||
margin-right: 1rem;
|
||||
}
|
||||
|
||||
.mt-3 {
|
||||
margin-top: 0.75rem;
|
||||
}
|
||||
|
||||
.mb-3 {
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
.mr-3 {
|
||||
margin-right: 0.75rem;
|
||||
.ml-3 {
|
||||
margin-left: 0.75rem;
|
||||
}
|
||||
|
||||
.mt-5 {
|
||||
@@ -771,10 +805,6 @@ video {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
.mt-auto {
|
||||
margin-top: auto;
|
||||
}
|
||||
|
||||
.mt-8 {
|
||||
margin-top: 2rem;
|
||||
}
|
||||
@@ -783,16 +813,16 @@ video {
|
||||
margin-top: 1.75rem;
|
||||
}
|
||||
|
||||
.mr-4 {
|
||||
margin-right: 1rem;
|
||||
}
|
||||
|
||||
.mr-2 {
|
||||
margin-right: 0.5rem;
|
||||
}
|
||||
|
||||
.ml-3 {
|
||||
margin-left: 0.75rem;
|
||||
.ml-1 {
|
||||
margin-left: 0.25rem;
|
||||
}
|
||||
|
||||
.-ml-1 {
|
||||
margin-left: -0.25rem;
|
||||
}
|
||||
|
||||
.block {
|
||||
@@ -839,6 +869,10 @@ video {
|
||||
height: 1.5rem;
|
||||
}
|
||||
|
||||
.h-0 {
|
||||
height: 0px;
|
||||
}
|
||||
|
||||
.h-12 {
|
||||
height: 3rem;
|
||||
}
|
||||
@@ -851,14 +885,6 @@ video {
|
||||
height: 20rem;
|
||||
}
|
||||
|
||||
.h-64 {
|
||||
height: 16rem;
|
||||
}
|
||||
|
||||
.h-0 {
|
||||
height: 0px;
|
||||
}
|
||||
|
||||
.h-48 {
|
||||
height: 12rem;
|
||||
}
|
||||
@@ -879,6 +905,10 @@ video {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.w-1\/4 {
|
||||
width: 25%;
|
||||
}
|
||||
|
||||
.w-2\/5 {
|
||||
width: 40%;
|
||||
}
|
||||
@@ -895,6 +925,10 @@ video {
|
||||
width: 1.5rem;
|
||||
}
|
||||
|
||||
.w-0 {
|
||||
width: 0px;
|
||||
}
|
||||
|
||||
.w-5 {
|
||||
width: 1.25rem;
|
||||
}
|
||||
@@ -931,14 +965,6 @@ video {
|
||||
width: 75%;
|
||||
}
|
||||
|
||||
.w-1\/4 {
|
||||
width: 25%;
|
||||
}
|
||||
|
||||
.w-0 {
|
||||
width: 0px;
|
||||
}
|
||||
|
||||
.max-w-md {
|
||||
max-width: 28rem;
|
||||
}
|
||||
@@ -975,6 +1001,23 @@ video {
|
||||
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
|
||||
}
|
||||
|
||||
@-webkit-keyframes spin {
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
.animate-spin {
|
||||
-webkit-animation: spin 1s linear infinite;
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
|
||||
.cursor-pointer {
|
||||
cursor: pointer;
|
||||
}
|
||||
@@ -983,10 +1026,8 @@ video {
|
||||
resize: both;
|
||||
}
|
||||
|
||||
.appearance-none {
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
appearance: none;
|
||||
.list-none {
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
.flex-col {
|
||||
@@ -1025,12 +1066,6 @@ video {
|
||||
justify-content: space-around;
|
||||
}
|
||||
|
||||
.space-x-8 > :not([hidden]) ~ :not([hidden]) {
|
||||
--tw-space-x-reverse: 0;
|
||||
margin-right: calc(2rem * var(--tw-space-x-reverse));
|
||||
margin-left: calc(2rem * calc(1 - var(--tw-space-x-reverse)));
|
||||
}
|
||||
|
||||
.space-x-4 > :not([hidden]) ~ :not([hidden]) {
|
||||
--tw-space-x-reverse: 0;
|
||||
margin-right: calc(1rem * var(--tw-space-x-reverse));
|
||||
@@ -1076,10 +1111,22 @@ video {
|
||||
border-right-width: 8px;
|
||||
}
|
||||
|
||||
.border-l-4 {
|
||||
border-left-width: 4px;
|
||||
}
|
||||
|
||||
.border-b {
|
||||
border-bottom-width: 1px;
|
||||
}
|
||||
|
||||
.border-b-8 {
|
||||
border-bottom-width: 8px;
|
||||
}
|
||||
|
||||
.border-t-8 {
|
||||
border-top-width: 8px;
|
||||
}
|
||||
|
||||
.border-b-2 {
|
||||
border-bottom-width: 2px;
|
||||
}
|
||||
@@ -1096,18 +1143,6 @@ video {
|
||||
border-right-width: 2px;
|
||||
}
|
||||
|
||||
.border-l-4 {
|
||||
border-left-width: 4px;
|
||||
}
|
||||
|
||||
.border-b-8 {
|
||||
border-bottom-width: 8px;
|
||||
}
|
||||
|
||||
.border-t-8 {
|
||||
border-top-width: 8px;
|
||||
}
|
||||
|
||||
.border-solid {
|
||||
border-style: solid;
|
||||
}
|
||||
@@ -1117,6 +1152,11 @@ video {
|
||||
border-color: rgb(209 213 219 / var(--tw-border-opacity));
|
||||
}
|
||||
|
||||
.border-teal-500 {
|
||||
--tw-border-opacity: 1;
|
||||
border-color: rgb(20 184 166 / var(--tw-border-opacity));
|
||||
}
|
||||
|
||||
.border-stone-200 {
|
||||
--tw-border-opacity: 1;
|
||||
border-color: rgb(231 229 228 / var(--tw-border-opacity));
|
||||
@@ -1137,11 +1177,6 @@ video {
|
||||
border-color: rgb(214 211 209 / var(--tw-border-opacity));
|
||||
}
|
||||
|
||||
.border-teal-500 {
|
||||
--tw-border-opacity: 1;
|
||||
border-color: rgb(20 184 166 / var(--tw-border-opacity));
|
||||
}
|
||||
|
||||
.border-stone-700 {
|
||||
--tw-border-opacity: 1;
|
||||
border-color: rgb(68 64 60 / var(--tw-border-opacity));
|
||||
@@ -1177,11 +1212,6 @@ video {
|
||||
border-right-color: transparent;
|
||||
}
|
||||
|
||||
.border-b-blue-600 {
|
||||
--tw-border-opacity: 1;
|
||||
border-bottom-color: rgb(37 99 235 / var(--tw-border-opacity));
|
||||
}
|
||||
|
||||
.border-b-white {
|
||||
--tw-border-opacity: 1;
|
||||
border-bottom-color: rgb(255 255 255 / var(--tw-border-opacity));
|
||||
@@ -1202,16 +1232,6 @@ video {
|
||||
background-color: rgb(255 255 255 / var(--tw-bg-opacity));
|
||||
}
|
||||
|
||||
.bg-rose-500 {
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(244 63 94 / var(--tw-bg-opacity));
|
||||
}
|
||||
|
||||
.bg-teal-500 {
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(20 184 166 / var(--tw-bg-opacity));
|
||||
}
|
||||
|
||||
.bg-stone-100 {
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(245 245 244 / var(--tw-bg-opacity));
|
||||
@@ -1222,16 +1242,26 @@ video {
|
||||
background-color: rgb(68 64 60 / var(--tw-bg-opacity));
|
||||
}
|
||||
|
||||
.bg-red-100 {
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(254 226 226 / var(--tw-bg-opacity));
|
||||
}
|
||||
|
||||
.bg-stone-200 {
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(231 229 228 / var(--tw-bg-opacity));
|
||||
}
|
||||
|
||||
.bg-rose-500 {
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(244 63 94 / var(--tw-bg-opacity));
|
||||
}
|
||||
|
||||
.bg-teal-500 {
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(20 184 166 / var(--tw-bg-opacity));
|
||||
}
|
||||
|
||||
.bg-red-100 {
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(254 226 226 / var(--tw-bg-opacity));
|
||||
}
|
||||
|
||||
.bg-stone-900 {
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(28 25 23 / var(--tw-bg-opacity));
|
||||
@@ -1242,6 +1272,10 @@ video {
|
||||
background-color: rgb(250 250 249 / var(--tw-bg-opacity));
|
||||
}
|
||||
|
||||
.bg-transparent {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.bg-opacity-90 {
|
||||
--tw-bg-opacity: 0.9;
|
||||
}
|
||||
@@ -1254,6 +1288,10 @@ video {
|
||||
background-position: center;
|
||||
}
|
||||
|
||||
.p-1 {
|
||||
padding: 0.25rem;
|
||||
}
|
||||
|
||||
.p-2 {
|
||||
padding: 0.5rem;
|
||||
}
|
||||
@@ -1274,10 +1312,6 @@ video {
|
||||
padding: 1.5rem;
|
||||
}
|
||||
|
||||
.p-1 {
|
||||
padding: 0.25rem;
|
||||
}
|
||||
|
||||
.py-5 {
|
||||
padding-top: 1.25rem;
|
||||
padding-bottom: 1.25rem;
|
||||
@@ -1333,6 +1367,10 @@ video {
|
||||
padding-right: 0.25rem;
|
||||
}
|
||||
|
||||
.pl-2 {
|
||||
padding-left: 0.5rem;
|
||||
}
|
||||
|
||||
.pl-3 {
|
||||
padding-left: 0.75rem;
|
||||
}
|
||||
@@ -1361,8 +1399,8 @@ video {
|
||||
padding-top: 0.5rem;
|
||||
}
|
||||
|
||||
.pl-8 {
|
||||
padding-left: 2rem;
|
||||
.pb-4 {
|
||||
padding-bottom: 1rem;
|
||||
}
|
||||
|
||||
.pt-4 {
|
||||
@@ -1373,12 +1411,16 @@ video {
|
||||
padding-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
.pr-8 {
|
||||
padding-right: 2rem;
|
||||
.pl-4 {
|
||||
padding-left: 1rem;
|
||||
}
|
||||
|
||||
.pb-4 {
|
||||
padding-bottom: 1rem;
|
||||
.pl-8 {
|
||||
padding-left: 2rem;
|
||||
}
|
||||
|
||||
.pl-12 {
|
||||
padding-left: 3rem;
|
||||
}
|
||||
|
||||
.text-left {
|
||||
@@ -1416,6 +1458,16 @@ video {
|
||||
line-height: 1rem;
|
||||
}
|
||||
|
||||
.text-3xl {
|
||||
font-size: 1.875rem;
|
||||
line-height: 2.25rem;
|
||||
}
|
||||
|
||||
.text-sm {
|
||||
font-size: 0.875rem;
|
||||
line-height: 1.25rem;
|
||||
}
|
||||
|
||||
.text-lg {
|
||||
font-size: 1.125rem;
|
||||
line-height: 1.75rem;
|
||||
@@ -1426,21 +1478,11 @@ video {
|
||||
line-height: 1.75rem;
|
||||
}
|
||||
|
||||
.text-sm {
|
||||
font-size: 0.875rem;
|
||||
line-height: 1.25rem;
|
||||
}
|
||||
|
||||
.text-2xl {
|
||||
font-size: 1.5rem;
|
||||
line-height: 2rem;
|
||||
}
|
||||
|
||||
.text-3xl {
|
||||
font-size: 1.875rem;
|
||||
line-height: 2.25rem;
|
||||
}
|
||||
|
||||
.font-normal {
|
||||
font-weight: 400;
|
||||
}
|
||||
@@ -1519,27 +1561,42 @@ video {
|
||||
color: rgb(6 182 212 / var(--tw-text-opacity));
|
||||
}
|
||||
|
||||
.text-stone-700 {
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(68 64 60 / var(--tw-text-opacity));
|
||||
}
|
||||
|
||||
.text-stone-200 {
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(231 229 228 / var(--tw-text-opacity));
|
||||
}
|
||||
|
||||
.text-stone-500 {
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(120 113 108 / var(--tw-text-opacity));
|
||||
}
|
||||
|
||||
.underline {
|
||||
-webkit-text-decoration-line: underline;
|
||||
text-decoration-line: underline;
|
||||
}
|
||||
|
||||
.accent-pink-300 {
|
||||
accent-color: #f9a8d4;
|
||||
}
|
||||
|
||||
.accent-white {
|
||||
accent-color: #fff;
|
||||
}
|
||||
|
||||
.accent-teal-500 {
|
||||
accent-color: #14b8a6;
|
||||
}
|
||||
|
||||
.opacity-0 {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.opacity-25 {
|
||||
opacity: 0.25;
|
||||
}
|
||||
|
||||
.opacity-75 {
|
||||
opacity: 0.75;
|
||||
}
|
||||
|
||||
.shadow-lg {
|
||||
--tw-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
|
||||
--tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);
|
||||
@@ -1598,26 +1655,6 @@ video {
|
||||
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
||||
}
|
||||
|
||||
.checked\:bg-white:checked {
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(255 255 255 / var(--tw-bg-opacity));
|
||||
}
|
||||
|
||||
.checked\:bg-blue-500:checked {
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(59 130 246 / var(--tw-bg-opacity));
|
||||
}
|
||||
|
||||
.checked\:bg-teal-500:checked {
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(20 184 166 / var(--tw-bg-opacity));
|
||||
}
|
||||
|
||||
.checked\:text-white:checked {
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(255 255 255 / var(--tw-text-opacity));
|
||||
}
|
||||
|
||||
.hover\:border-b-4:hover {
|
||||
border-bottom-width: 4px;
|
||||
}
|
||||
@@ -1637,11 +1674,21 @@ video {
|
||||
border-color: rgb(20 184 166 / var(--tw-border-opacity));
|
||||
}
|
||||
|
||||
.hover\:border-stone-50:hover {
|
||||
--tw-border-opacity: 1;
|
||||
border-color: rgb(250 250 249 / var(--tw-border-opacity));
|
||||
}
|
||||
|
||||
.hover\:bg-gray-200:hover {
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(229 231 235 / var(--tw-bg-opacity));
|
||||
}
|
||||
|
||||
.hover\:bg-stone-50:hover {
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(250 250 249 / var(--tw-bg-opacity));
|
||||
}
|
||||
|
||||
.hover\:bg-stone-900:hover {
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(28 25 23 / var(--tw-bg-opacity));
|
||||
@@ -1687,9 +1734,19 @@ video {
|
||||
background-color: rgb(6 182 212 / var(--tw-bg-opacity));
|
||||
}
|
||||
|
||||
.hover\:bg-stone-50:hover {
|
||||
.hover\:bg-stone-700:hover {
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(250 250 249 / var(--tw-bg-opacity));
|
||||
background-color: rgb(68 64 60 / var(--tw-bg-opacity));
|
||||
}
|
||||
|
||||
.hover\:bg-stone-500:hover {
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(120 113 108 / var(--tw-bg-opacity));
|
||||
}
|
||||
|
||||
.hover\:bg-teal-500:hover {
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(20 184 166 / var(--tw-bg-opacity));
|
||||
}
|
||||
|
||||
.hover\:text-white:hover {
|
||||
@@ -1697,6 +1754,16 @@ video {
|
||||
color: rgb(255 255 255 / var(--tw-text-opacity));
|
||||
}
|
||||
|
||||
.hover\:text-stone-50:hover {
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(250 250 249 / var(--tw-text-opacity));
|
||||
}
|
||||
|
||||
.hover\:text-stone-100:hover {
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(245 245 244 / var(--tw-text-opacity));
|
||||
}
|
||||
|
||||
.hover\:underline:hover {
|
||||
-webkit-text-decoration-line: underline;
|
||||
text-decoration-line: underline;
|
||||
@@ -1707,6 +1774,11 @@ video {
|
||||
border-color: rgb(37 99 235 / var(--tw-border-opacity));
|
||||
}
|
||||
|
||||
.focus\:border-stone-100:focus {
|
||||
--tw-border-opacity: 1;
|
||||
border-color: rgb(245 245 244 / var(--tw-border-opacity));
|
||||
}
|
||||
|
||||
.focus\:bg-white:focus {
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(255 255 255 / var(--tw-bg-opacity));
|
||||
@@ -1717,6 +1789,11 @@ video {
|
||||
background-color: rgb(250 250 249 / var(--tw-bg-opacity));
|
||||
}
|
||||
|
||||
.focus\:bg-stone-100:focus {
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(245 245 244 / var(--tw-bg-opacity));
|
||||
}
|
||||
|
||||
.focus\:text-gray-700:focus {
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(55 65 81 / var(--tw-text-opacity));
|
||||
@@ -1738,6 +1815,10 @@ video {
|
||||
background-color: rgb(250 250 249 / var(--tw-bg-opacity));
|
||||
}
|
||||
|
||||
.group:hover .group-hover\:visible {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
.dark\:text-gray-400 {
|
||||
--tw-text-opacity: 1;
|
||||
|
2
system/typemill/author/js/sortable.min.js
vendored
Normal file
2
system/typemill/author/js/sortable.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
635
system/typemill/author/js/vue-contentnavi.js
Normal file
635
system/typemill/author/js/vue-contentnavi.js
Normal file
@@ -0,0 +1,635 @@
|
||||
const navigation = Vue.createApp({
|
||||
template: `
|
||||
<div class="mr-3">
|
||||
<div class="flex w-100 mb-4">
|
||||
<button class="w-1/2 ml-1 hover:bg-stone-700 hover:text-stone-50 border border-stone-200 px-2 py-1 transition duration-100" @click.prevent="collapseNavigation()">collapse all</button>
|
||||
<button class="w-1/2 mr-1 hover:bg-stone-700 hover:text-stone-50 border border-stone-200 px-2 py-1 transition duration-100" @click.prevent="expandNavigation()">expand all</button>
|
||||
</div>
|
||||
<div class="flex w-full mb-1 font-bold">
|
||||
<div class="border-l-4 border-teal-500 published"></div>
|
||||
<a class="flex-grow p-1 hover:bg-teal-500 hover:text-stone-50 pl-2 text-bold transition duration-100" :href="getHomeUrl()">Home</a>
|
||||
</div>
|
||||
<div class="pl-2 pl-4 pl-8 pl-12"></div>
|
||||
<navilevel :navigation="navigation" />
|
||||
</div>`,
|
||||
data: function () {
|
||||
return {
|
||||
navigation: data.navigation,
|
||||
isExpended: false,
|
||||
expanded: [],
|
||||
}
|
||||
},
|
||||
mounted: function(){
|
||||
var expanded = localStorage.getItem('expanded');
|
||||
if(expanded !== null)
|
||||
{
|
||||
var expandedArray = expanded.split(',');
|
||||
var expandedLength = expandedArray.length;
|
||||
var cleanExpandedArray = [];
|
||||
for(var i = 0; i < expandedLength; i++)
|
||||
{
|
||||
if(typeof expandedArray[i] === 'string' && expandedArray[i] != '')
|
||||
{
|
||||
cleanExpandedArray.push(expandedArray[i]);
|
||||
}
|
||||
}
|
||||
this.expanded = expanded.split(',');
|
||||
}
|
||||
eventBus.$on('toggleFolder', this.toggleFolder);
|
||||
},
|
||||
methods: {
|
||||
getHomeUrl()
|
||||
{
|
||||
return tmaxios.defaults.baseURL + '/tm/content/visual';
|
||||
},
|
||||
toggleFolder: function(name)
|
||||
{
|
||||
var index = this.expanded.indexOf(name);
|
||||
if (index > -1)
|
||||
{
|
||||
this.expanded.splice(index, 1);
|
||||
// this.expandNavigation = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.expanded.push(name);
|
||||
}
|
||||
localStorage.setItem("expanded", this.expanded.toString());
|
||||
},
|
||||
expandNavigation()
|
||||
{
|
||||
this.expanded = this.getFolderNames(this.navigation, []);
|
||||
localStorage.setItem("expanded", this.expanded.toString());
|
||||
},
|
||||
collapseNavigation()
|
||||
{
|
||||
this.expanded = [];
|
||||
localStorage.removeItem('expanded');
|
||||
},
|
||||
getFolderNames(navigation, result)
|
||||
{
|
||||
for (const item of navigation)
|
||||
{
|
||||
if (item.elementType == 'folder')
|
||||
{
|
||||
result.push(item.name);
|
||||
this.getFolderNames(item.folderContent, result);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
navigation.component('draggable', vuedraggable);
|
||||
|
||||
navigation.component('navilevel',{
|
||||
template: `
|
||||
<draggable
|
||||
@start="onStart"
|
||||
@end="onEnd"
|
||||
:move="checkMove"
|
||||
:list="navigation"
|
||||
v-bind="dragOptions"
|
||||
class="dragArea"
|
||||
tag="ul"
|
||||
item-key="keyPath"
|
||||
:component-data="{
|
||||
id: parentId ? parentId : false
|
||||
}"
|
||||
>
|
||||
<template #item="{ element }">
|
||||
<li :class="element.elementType" :id="element.keyPath" :data-url="element.urlRelWoF" :data-active="element.active">
|
||||
<div class="flex w-full mb-1 relative" :class="element.elementType == 'folder' ? 'font-bold' : ''">
|
||||
<div class="border-l-4 border-teal-500" :class="element.status"></div>
|
||||
<a :href="getUrl(element.urlRelWoF)" class="flex-grow p-1 hover:bg-teal-500 hover:text-stone-50" :class="getNaviClass(element.active, element.activeParent, element.keyPathArray)">
|
||||
{{ element.name }}
|
||||
</a>
|
||||
<div v-if="load == element.keyPath" class="p-1 absolute right-0">
|
||||
<svg class="animate-spin h-5 w-5 text-stone-700" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
|
||||
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
|
||||
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div v-if="element.elementType == 'folder'" class=" p-1 bg-transparent absolute right-0" @click="callToggle(element.name)">
|
||||
<svg v-if="isExpanded(element.name)" class="icon icon-cheveron-up">
|
||||
<use xlink:href="#icon-cheveron-up"></use>
|
||||
</svg>
|
||||
<svg v-else class="icon icon-cheveron-down">
|
||||
<use xlink:href="#icon-cheveron-down"></use>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<navilevel v-show="isExpanded(element.name)" v-if="element.elementType == 'folder'" :list="element.folderContent" :navigation="element.folderContent" :parentId="element.keyPath" />
|
||||
</li>
|
||||
</template>
|
||||
<template #footer>
|
||||
<li>
|
||||
<div class="flex w-full mb-1 group">
|
||||
<div class="border-l-4 border-stone-200"></div>
|
||||
<div class="flex-grow">
|
||||
<input :class="navilevel" class="w-full p-1 bg-stone-50 border-2 border-stone-50 focus:outline-none" placeholder="..." v-model="newItem">
|
||||
</div>
|
||||
<!-- <div class="w-1/4 invisible group-hover:visible"> -->
|
||||
<div class="flex">
|
||||
<button title="add a file" @click="addItem('file', parentId)" class="text-stone-500 bg-stone-100 hover:text-stone-100 hover:bg-stone-700 p-1 border-2 border-stone-50 transition duration-100">
|
||||
<svg class="h-5 w-5" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 28">
|
||||
<path fill="currentColor" d="M22.937 5.938c0.578 0.578 1.062 1.734 1.062 2.562v18c0 0.828-0.672 1.5-1.5 1.5h-21c-0.828 0-1.5-0.672-1.5-1.5v-25c0-0.828 0.672-1.5 1.5-1.5h14c0.828 0 1.984 0.484 2.562 1.062zM16 2.125v5.875h5.875c-0.094-0.266-0.234-0.531-0.344-0.641l-4.891-4.891c-0.109-0.109-0.375-0.25-0.641-0.344zM22 26v-16h-6.5c-0.828 0-1.5-0.672-1.5-1.5v-6.5h-12v24h20zM6 12.5c0-0.281 0.219-0.5 0.5-0.5h11c0.281 0 0.5 0.219 0.5 0.5v1c0 0.281-0.219 0.5-0.5 0.5h-11c-0.281 0-0.5-0.219-0.5-0.5v-1zM17.5 16c0.281 0 0.5 0.219 0.5 0.5v1c0 0.281-0.219 0.5-0.5 0.5h-11c-0.281 0-0.5-0.219-0.5-0.5v-1c0-0.281 0.219-0.5 0.5-0.5h11zM17.5 20c0.281 0 0.5 0.219 0.5 0.5v1c0 0.281-0.219 0.5-0.5 0.5h-11c-0.281 0-0.5-0.219-0.5-0.5v-1c0-0.281 0.219-0.5 0.5-0.5h11z"></path>
|
||||
</svg>
|
||||
</button>
|
||||
<button title="add a folder" @click="addItem('folder', parentId)" class="text-stone-500 bg-stone-100 hover:text-stone-100 hover:bg-stone-700 p-1 border-2 border-stone-50 transition duration-100">
|
||||
<svg class="h-5 w-5" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 28">
|
||||
<path fill="currentColor" d="M24 20.5v-11c0-0.828-0.672-1.5-1.5-1.5h-11c-0.828 0-1.5-0.672-1.5-1.5v-1c0-0.828-0.672-1.5-1.5-1.5h-5c-0.828 0-1.5 0.672-1.5 1.5v15c0 0.828 0.672 1.5 1.5 1.5h19c0.828 0 1.5-0.672 1.5-1.5zM26 9.5v11c0 1.922-1.578 3.5-3.5 3.5h-19c-1.922 0-3.5-1.578-3.5-3.5v-15c0-1.922 1.578-3.5 3.5-3.5h5c1.922 0 3.5 1.578 3.5 3.5v0.5h10.5c1.922 0 3.5 1.578 3.5 3.5z"></path>
|
||||
</svg>
|
||||
</button>
|
||||
<!-- <button title="add a link" @click="addItem('link', parentId)" class="text-stone-500 bg-stone-100 hover:text-stone-100 hover:bg-stone-700 p-1 border-2 border-stone-50 transition duration-100">
|
||||
<svg class="h-5 w-5" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 32 32">
|
||||
<path fill="currentColor" d="M13.757 19.868c-0.416 0-0.832-0.159-1.149-0.476-2.973-2.973-2.973-7.81 0-10.783l6-6c1.44-1.44 3.355-2.233 5.392-2.233s3.951 0.793 5.392 2.233c2.973 2.973 2.973 7.81 0 10.783l-2.743 2.743c-0.635 0.635-1.663 0.635-2.298 0s-0.635-1.663 0-2.298l2.743-2.743c1.706-1.706 1.706-4.481 0-6.187-0.826-0.826-1.925-1.281-3.094-1.281s-2.267 0.455-3.094 1.281l-6 6c-1.706 1.706-1.706 4.481 0 6.187 0.635 0.635 0.635 1.663 0 2.298-0.317 0.317-0.733 0.476-1.149 0.476z"></path>
|
||||
<path fill="currentColor" d="M8 31.625c-2.037 0-3.952-0.793-5.392-2.233-2.973-2.973-2.973-7.81 0-10.783l2.743-2.743c0.635-0.635 1.664-0.635 2.298 0s0.635 1.663 0 2.298l-2.743 2.743c-1.706 1.706-1.706 4.481 0 6.187 0.826 0.826 1.925 1.281 3.094 1.281s2.267-0.455 3.094-1.281l6-6c1.706-1.706 1.706-4.481 0-6.187-0.635-0.635-0.635-1.663 0-2.298s1.663-0.635 2.298 0c2.973 2.973 2.973 7.81 0 10.783l-6 6c-1.44 1.44-3.355 2.233-5.392 2.233z"></path>
|
||||
</svg>
|
||||
</button> -->
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</template>
|
||||
</draggable>`,
|
||||
props: {
|
||||
navigation: {
|
||||
type: Array,
|
||||
required: true
|
||||
},
|
||||
parentId: {
|
||||
default: 'root'
|
||||
}
|
||||
},
|
||||
data: function () {
|
||||
return {
|
||||
navilevel: '',
|
||||
load: '?',
|
||||
freeze: false,
|
||||
newItem: '',
|
||||
format: /[@#*()=\[\]{};:"\\|,.<>\/]/,
|
||||
}
|
||||
},
|
||||
computed:
|
||||
{
|
||||
dragOptions()
|
||||
{
|
||||
return {
|
||||
animation: 150,
|
||||
group: "file",
|
||||
disabled: this.freeze,
|
||||
ghostClass: "ghost",
|
||||
};
|
||||
},
|
||||
|
||||
// this.value when input = v-model
|
||||
// this.list when input != v-model
|
||||
realValue()
|
||||
{
|
||||
return this.value ? this.value : this.list;
|
||||
}
|
||||
},
|
||||
methods:
|
||||
{
|
||||
getNaviClass(active, activeParent, keyPathArray)
|
||||
{
|
||||
var naviclass = 'pl-' + (keyPathArray.length * 2);
|
||||
this.navilevel = naviclass;
|
||||
if(active){ naviclass += " active" }
|
||||
if(activeParent){ naviclass += " activeParent" }
|
||||
|
||||
return naviclass;
|
||||
},
|
||||
getUrl(segment)
|
||||
{
|
||||
return tmaxios.defaults.baseURL + '/tm/content/visual' + segment;
|
||||
},
|
||||
callToggle(name)
|
||||
{
|
||||
eventBus.$emit('toggleFolder', name);
|
||||
},
|
||||
isExpanded(name)
|
||||
{
|
||||
if(this.$root.expanded.indexOf(name) > -1)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
onStart(evt)
|
||||
{
|
||||
/* delete error messages if exist */
|
||||
// publishController.errors.message = false;
|
||||
},
|
||||
checkMove(evt)
|
||||
{
|
||||
/* do we want to keep that restriction, no folder into folders? */
|
||||
if(evt.dragged.classList.contains('folder') && evt.from.parentNode.id != evt.to.parentNode.id)
|
||||
{
|
||||
console.info("moved folder to another folder");
|
||||
return false;
|
||||
}
|
||||
if(evt.dragged.dataset.active == 'active' && !editor.draftDisabled)
|
||||
{
|
||||
console.info("moved page is active, save your changes first");
|
||||
// publishController.errors.message = "Please save your changes before you move the file";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
onEnd(evt)
|
||||
{
|
||||
if(evt.from.parentNode.id == evt.to.parentNode.id && evt.oldIndex == evt.newIndex)
|
||||
{
|
||||
return
|
||||
}
|
||||
this.freeze = true;
|
||||
this.load = evt.item.id;
|
||||
|
||||
var self = this;
|
||||
|
||||
// self.errors = {title: false, content: false, message: false};
|
||||
|
||||
tmaxios.post('/api/v1/article/sort',{
|
||||
'item_id': evt.item.id,
|
||||
'parent_id_from': evt.from.parentNode.id,
|
||||
'parent_id_to': evt.to.parentNode.id,
|
||||
'index_old': evt.oldIndex,
|
||||
'index_new': evt.newIndex,
|
||||
'active': evt.item.dataset.active,
|
||||
'url': evt.item.dataset.url,
|
||||
// 'url': document.getElementById("path").value,
|
||||
// 'csrf_name': document.getElementById("csrf_name").value,
|
||||
// 'csrf_value': document.getElementById("csrf_value").value,
|
||||
})
|
||||
.then(function (response)
|
||||
{
|
||||
self.load = '?';
|
||||
self.freeze = false;
|
||||
|
||||
if(response.data.url)
|
||||
{
|
||||
window.location.replace(response.data.url);
|
||||
}
|
||||
if(response.data.navigation)
|
||||
{
|
||||
self.$root.$data.navigation = response.data.navigation;
|
||||
}
|
||||
})
|
||||
.catch(function (error)
|
||||
{
|
||||
if(error.response.data.errors.message)
|
||||
{
|
||||
// publishController.errors.message = error.response.data.errors;
|
||||
}
|
||||
});
|
||||
},
|
||||
addItem(type, parent)
|
||||
{
|
||||
// publishController.errors.message = false;
|
||||
if(this.format.test(this.newItem) || !this.newItem || this.newItem.length > 40)
|
||||
{
|
||||
// publishController.errors.message = 'Special Characters are not allowed. Length between 1 and 40.';
|
||||
return;
|
||||
}
|
||||
|
||||
self = this;
|
||||
|
||||
self.freeze = true;
|
||||
// self.errors = {title: false, content: false, message: false};
|
||||
|
||||
tmaxios.post('/api/v1/article',{
|
||||
'item_name': this.newItem,
|
||||
'folder_id': parent,
|
||||
'type': type,
|
||||
// 'url': document.getElementById("path").value,
|
||||
// 'csrf_name': document.getElementById("csrf_name").value,
|
||||
// 'csrf_value': document.getElementById("csrf_value").value,
|
||||
})
|
||||
.then(function (response) {
|
||||
|
||||
self.freeze = false;
|
||||
|
||||
if(response.data.url)
|
||||
{
|
||||
window.location.replace(response.data.url);
|
||||
}
|
||||
if(response.data.navigation)
|
||||
{
|
||||
self.items = response.data.navigation;
|
||||
self.newItem = '';
|
||||
}
|
||||
})
|
||||
.catch(function (error)
|
||||
{
|
||||
// publishController.errors.message = error.response.data.errors;
|
||||
});
|
||||
},
|
||||
emitter(value) {
|
||||
this.$emit("input", value);
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
navigation.mount('#contentNavigation');
|
||||
|
||||
/*
|
||||
data: function () {
|
||||
return {
|
||||
title: "Navigation",
|
||||
navigation: data.navigation,
|
||||
homepage: false,
|
||||
editormode: 'visual',
|
||||
freeze: false,
|
||||
modalWindow: false,
|
||||
format: /[@#*()=\[\]{};:"\\|,.<>\/]/,
|
||||
folderName: '',
|
||||
showForm: false,
|
||||
newItem: '',
|
||||
collapse: [],
|
||||
}
|
||||
},
|
||||
|
||||
<draggable class="navi-list list-none" tag="ul"
|
||||
@start="onStart"
|
||||
@end="onEnd"
|
||||
:list="items"
|
||||
:move="checkMove"
|
||||
group="file"
|
||||
animation="150"
|
||||
:disabled="freeze"
|
||||
item-key="items.length">
|
||||
<navilevel
|
||||
v-for="item in items"
|
||||
ref="draggit"
|
||||
:freeze="freeze"
|
||||
:name="item.name"
|
||||
:hide="item.hide"
|
||||
:active="item.active"
|
||||
:parent="item.activeParent"
|
||||
:level="item.keyPath"
|
||||
:root="root"
|
||||
:url="item.urlRelWoF"
|
||||
:id="item.keyPath"
|
||||
:key="item.keyPath"
|
||||
:elementtype="item.elementType"
|
||||
:contains="item.contains"
|
||||
:filetype="item.fileType"
|
||||
:status="item.status"
|
||||
:folder="item.folderContent"
|
||||
:collapse="collapse"
|
||||
></navilevel>
|
||||
</draggable>
|
||||
data: function () {
|
||||
return {
|
||||
title: "Navigation",
|
||||
items: data.navigation,
|
||||
homepage: false,
|
||||
editormode: 'visual',
|
||||
freeze: false,
|
||||
modalWindow: false,
|
||||
format: /[@#*()=\[\]{};:"\\|,.<>\/]/,
|
||||
folderName: '',
|
||||
showForm: false,
|
||||
newItem: '',
|
||||
collapse: [],
|
||||
}
|
||||
},
|
||||
checkMove: function(evt){
|
||||
/* this.$refs.draggit[0].checkMove(evt); *
|
||||
if(evt.dragged.classList.contains('folder') && evt.from.parentNode.id != evt.to.parentNode.id)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(evt.dragged.firstChild.className == 'active' && !editor.draftDisabled)
|
||||
{
|
||||
publishController.errors.message = "Please save your changes before you move the file";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
onStart: function(evt){
|
||||
this.$refs.draggit[0].onStart(evt);
|
||||
},
|
||||
onEnd: function(evt){
|
||||
this.$refs.draggit[0].onEnd(evt);
|
||||
},
|
||||
addFile : function(type)
|
||||
{
|
||||
publishController.errors.message = false;
|
||||
|
||||
if(this.format.test(this.newItem) || !this.newItem || this.newItem.length > 40)
|
||||
{
|
||||
publishController.errors.message = 'Special Characters are not allowed. Length between 1 and 40.';
|
||||
return;
|
||||
}
|
||||
|
||||
self = this;
|
||||
|
||||
self.freeze = true;
|
||||
self.errors = {title: false, content: false, message: false};
|
||||
|
||||
myaxios.post('/api/v1/baseitem',{
|
||||
'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,
|
||||
})
|
||||
.then(function (response) {
|
||||
|
||||
self.freeze = false;
|
||||
|
||||
if(response.data.url)
|
||||
{
|
||||
window.location.replace(response.data.url);
|
||||
}
|
||||
if(response.data.data)
|
||||
{
|
||||
self.items = response.data.data;
|
||||
self.newItem = '';
|
||||
self.showForm = false;
|
||||
}
|
||||
})
|
||||
.catch(function (error)
|
||||
{
|
||||
publishController.errors.message = error.response.data.errors;
|
||||
});
|
||||
},
|
||||
getNavi: function()
|
||||
{
|
||||
publishController.errors.message = false;
|
||||
|
||||
var self = this;
|
||||
|
||||
self.freeze = true;
|
||||
self.errors = {title: false, content: false, message: false};
|
||||
|
||||
var activeItem = document.getElementById("path").value;
|
||||
|
||||
var url = this.root + '/api/v1/navigation?url=' + activeItem;
|
||||
var method = 'GET';
|
||||
|
||||
myaxios.get('/api/v1/navigation',{
|
||||
params: {
|
||||
'url': activeItem,
|
||||
'csrf_name': document.getElementById("csrf_name").value,
|
||||
'csrf_value': document.getElementById("csrf_value").value,
|
||||
}
|
||||
})
|
||||
.then(function (response) {
|
||||
|
||||
self.freeze = false;
|
||||
if(response.data.data)
|
||||
{
|
||||
self.items = response.data.data;
|
||||
self.newItem = '';
|
||||
self.homepage = response.data.homepage;
|
||||
}
|
||||
})
|
||||
.catch(function (error)
|
||||
{
|
||||
if(error.response.data.errors)
|
||||
{
|
||||
publishController.errors.message = error.response.data.errors;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
checkMove : function(evt)
|
||||
{
|
||||
if(evt.dragged.classList.contains('folder') && evt.from.parentNode.id != evt.to.parentNode.id)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(evt.dragged.firstChild.className == 'active' && !editor.draftDisabled)
|
||||
{
|
||||
publishController.errors.message = "Please save your changes before you move the file";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
onStart : function(evt)
|
||||
{
|
||||
/* delete error messages if exist *
|
||||
publishController.errors.message = false;
|
||||
},
|
||||
getUrl : function(root, url)
|
||||
{
|
||||
return root + '/tm/content/' + this.$root.$data.editormode + url;
|
||||
},
|
||||
checkActive : function(active,parent)
|
||||
{
|
||||
if(active && !parent)
|
||||
{
|
||||
return 'active';
|
||||
}
|
||||
return 'inactive';
|
||||
},
|
||||
|
||||
checkActive : function(active,parent)
|
||||
{
|
||||
if(active && !parent)
|
||||
{
|
||||
return 'active';
|
||||
}
|
||||
return 'inactive';
|
||||
},
|
||||
addFile : function(type)
|
||||
{
|
||||
publishController.errors.message = false;
|
||||
|
||||
if(this.format.test(this.newItem) || !this.newItem || this.newItem.length > 40)
|
||||
{
|
||||
publishController.errors.message = 'Special Characters are not allowed. Length between 1 and 40.';
|
||||
return;
|
||||
}
|
||||
|
||||
self = this;
|
||||
|
||||
self.freeze = true;
|
||||
self.errors = {title: false, content: false, message: false};
|
||||
|
||||
myaxios.post('/api/v1/baseitem',{
|
||||
'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,
|
||||
})
|
||||
.then(function (response) {
|
||||
|
||||
self.freeze = false;
|
||||
|
||||
if(response.data.url)
|
||||
{
|
||||
window.location.replace(response.data.url);
|
||||
}
|
||||
if(response.data.data)
|
||||
{
|
||||
self.items = response.data.data;
|
||||
self.newItem = '';
|
||||
self.showForm = false;
|
||||
}
|
||||
})
|
||||
.catch(function (error)
|
||||
{
|
||||
publishController.errors.message = error.response.data.errors;
|
||||
});
|
||||
},
|
||||
|
||||
addFile : function(type)
|
||||
{
|
||||
publishController.errors.message = false;
|
||||
|
||||
if(this.$root.$data.format.test(this.newItem) || !this.newItem || this.newItem.length > 60)
|
||||
{
|
||||
publishController.errors.message = 'Special Characters are not allowed. Length between 1 and 60.';
|
||||
return;
|
||||
}
|
||||
|
||||
var self = this;
|
||||
|
||||
self.$root.$data.freeze = true;
|
||||
self.errors = {title: false, content: false, message: false};
|
||||
|
||||
myaxios.post('/api/v1/article',{
|
||||
'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,
|
||||
})
|
||||
.then(function (response) {
|
||||
|
||||
self.$root.$data.freeze = false;
|
||||
|
||||
if(response.data.url)
|
||||
{
|
||||
window.location.replace(response.data.url);
|
||||
}
|
||||
if(response.data.data)
|
||||
{
|
||||
// evt.item.classList.remove("load");
|
||||
self.$root.$data.items = response.data.data;
|
||||
self.newItem = '';
|
||||
self.showForm = false;
|
||||
}
|
||||
})
|
||||
.catch(function (error)
|
||||
{
|
||||
if(error.response.data.errors)
|
||||
{
|
||||
publishController.errors.message = error.response.data.errors;
|
||||
}
|
||||
});
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
navigation.mount('#contentNavigation');
|
||||
*/
|
2
system/typemill/author/js/vuedraggable.umd.min.js
vendored
Normal file
2
system/typemill/author/js/vuedraggable.umd.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@@ -36,7 +36,7 @@
|
||||
|
||||
<div class="max-w-6xl m-auto mt-7 flex justify-between" id="main" data-url="{{ base_url() }}">
|
||||
<aside class="w-1/4">
|
||||
{% include 'partials/contentNavi.twig' %}
|
||||
<div id="contentNavigation" v-cloak></div>
|
||||
</aside>
|
||||
<article class="w-3/4 bg-stone-50 shadow-md p-8">
|
||||
{% block content %}{% endblock %}
|
||||
@@ -59,6 +59,9 @@
|
||||
</script>
|
||||
<script src="{{ base_url() }}/system/typemill/author/js/vue.js?v={{ settings.version }}"></script>
|
||||
<script src="{{ base_url() }}/system/typemill/author/js/vue-eventbus.js?v={{ settings.version }}"></script>
|
||||
<script src="{{ base_url() }}/system/typemill/author/js/sortable.min.js?v={{ settings.version }}"></script>
|
||||
<script src="{{ base_url() }}/system/typemill/author/js/vuedraggable.umd.min.js?v={{ settings.version }}"></script>
|
||||
<script type="module" src="{{ base_url() }}/system/typemill/author/js/vue-contentnavi.js?v={{ settings.version }}"></script>
|
||||
|
||||
{% block javascript %}{% endblock %}
|
||||
|
||||
|
@@ -177,6 +177,12 @@
|
||||
<symbol id="icon-square-brackets" viewBox="0 0 21 21">
|
||||
<path d="M 4.791 18.885 L 4.791 20.518 L 0 20.518 L 0 0 L 4.791 0 L 4.791 1.622 L 2.052 1.622 L 2.052 18.885 L 4.791 18.885 Z M 20.958 0 L 20.958 20.518 L 16.178 20.518 L 16.178 18.885 L 18.906 18.885 L 18.906 1.622 L 16.178 1.622 L 16.178 0 L 20.958 0 Z M 6.542 4.952 A 1.326 1.326 0 0 0 6.404 5.11 Q 6.102 5.516 6.102 6.166 A 2.167 2.167 0 0 0 6.15 6.638 A 1.453 1.453 0 0 0 6.553 7.38 A 1.472 1.472 0 0 0 7.616 7.82 A 1.702 1.702 0 0 0 7.626 7.82 A 1.445 1.445 0 0 0 8.669 7.385 Q 9.109 6.95 9.109 6.166 A 2.149 2.149 0 0 0 9.058 5.685 A 1.429 1.429 0 0 0 8.658 4.958 A 1.482 1.482 0 0 0 7.595 4.522 Q 6.982 4.522 6.542 4.952 Z M 12.311 4.952 A 1.326 1.326 0 0 0 12.173 5.11 Q 11.87 5.516 11.87 6.166 A 2.167 2.167 0 0 0 11.919 6.638 A 1.453 1.453 0 0 0 12.321 7.38 A 1.472 1.472 0 0 0 13.385 7.82 A 1.702 1.702 0 0 0 13.394 7.82 A 1.445 1.445 0 0 0 14.437 7.385 Q 14.878 6.95 14.878 6.166 A 2.149 2.149 0 0 0 14.827 5.685 A 1.429 1.429 0 0 0 14.427 4.958 A 1.482 1.482 0 0 0 13.363 4.522 Q 12.751 4.522 12.311 4.952 Z M 9.06 14.192 A 1.427 1.427 0 0 0 8.653 13.455 Q 8.196 13.02 7.584 13.02 A 1.442 1.442 0 0 0 6.542 13.449 A 1.326 1.326 0 0 0 6.404 13.607 Q 6.102 14.013 6.102 14.663 A 2.679 2.679 0 0 0 6.102 14.698 Q 6.105 14.959 6.16 15.18 A 1.407 1.407 0 0 0 6.542 15.866 A 1.455 1.455 0 0 0 7.595 16.296 Q 8.207 16.296 8.658 15.866 A 1.405 1.405 0 0 0 9.056 15.154 A 2.131 2.131 0 0 0 9.109 14.663 A 2.134 2.134 0 0 0 9.06 14.192 Z M 14.829 14.192 A 1.427 1.427 0 0 0 14.421 13.455 Q 13.965 13.02 13.353 13.02 A 1.442 1.442 0 0 0 12.311 13.449 A 1.326 1.326 0 0 0 12.173 13.607 Q 11.87 14.013 11.87 14.663 A 2.679 2.679 0 0 0 11.87 14.698 Q 11.874 14.959 11.928 15.18 A 1.407 1.407 0 0 0 12.311 15.866 A 1.455 1.455 0 0 0 13.363 16.296 Q 13.976 16.296 14.427 15.866 A 1.405 1.405 0 0 0 14.825 15.154 A 2.131 2.131 0 0 0 14.878 14.663 A 2.134 2.134 0 0 0 14.829 14.192 Z" />
|
||||
</symbol>
|
||||
<symbol id="icon-cheveron-down" viewBox="0 0 20 20">
|
||||
<path d="M9.293 12.95l0.707 0.707 5.657-5.657-1.414-1.414-4.243 4.242-4.243-4.242-1.414 1.414z"></path>
|
||||
</symbol>
|
||||
<symbol id="icon-cheveron-up" viewBox="0 0 20 20">
|
||||
<path d="M10.707 7.050l-0.707-0.707-5.657 5.657 1.414 1.414 4.243-4.242 4.243 4.242 1.414-1.414z"></path>
|
||||
</symbol>
|
||||
{{ assets.renderSvg() }}
|
||||
<defs>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 28 KiB |
@@ -12,6 +12,7 @@ use Typemill\Controllers\ControllerApiSystemExtensions;
|
||||
use Typemill\Controllers\ControllerApiSystemLicense;
|
||||
use Typemill\Controllers\ControllerApiSystemUsers;
|
||||
use Typemill\Controllers\ControllerApiImage;
|
||||
use Typemill\Controllers\ControllerApiAuthorArticle;
|
||||
|
||||
$app->group('/api/v1', function (RouteCollectorProxy $group) use ($acl) {
|
||||
|
||||
@@ -40,6 +41,10 @@ $app->group('/api/v1', function (RouteCollectorProxy $group) use ($acl) {
|
||||
$group->put('/image', ControllerApiMedia::class . ':publishImage')->setName('api.image.publish');
|
||||
$group->delete('/image', ControllerApiMedia::class . ':deleteImage')->setName('api.image.delete');
|
||||
|
||||
# ARTICLE
|
||||
$group->post('/article/sort', ControllerApiAuthorArticle::class . ':sortArticle')->setName('api.article.sort')->add(new ApiAuthorization($acl, 'content', 'view')); # author
|
||||
$group->post('/article', ControllerApiAuthorArticle::class . ':createArticle')->setName('api.article.create')->add(new ApiAuthorization($acl, 'content', 'view')); # author
|
||||
|
||||
})->add(new ApiAuthentication());
|
||||
|
||||
|
||||
|
@@ -6,14 +6,18 @@ member:
|
||||
- 'view'
|
||||
- 'update'
|
||||
- 'delete'
|
||||
author:
|
||||
name: author
|
||||
contributor:
|
||||
name: contributor
|
||||
inherits: member
|
||||
permissions:
|
||||
mycontent:
|
||||
- 'view'
|
||||
- 'create'
|
||||
- 'update'
|
||||
author:
|
||||
name: author
|
||||
inherits: contributor
|
||||
permissions:
|
||||
content:
|
||||
- 'view'
|
||||
editor:
|
||||
|
@@ -8,7 +8,8 @@ module.exports = {
|
||||
},
|
||||
opacity: {
|
||||
'0': '0',
|
||||
}
|
||||
},
|
||||
visibility: ["group-hover"],
|
||||
},
|
||||
},
|
||||
plugins: [],
|
||||
|
Reference in New Issue
Block a user