1
0
mirror of https://github.com/typemill/typemill.git synced 2025-08-05 13:47:37 +02:00

Merge branch 'tm2' into tm2-dev

This commit is contained in:
trendschau
2023-03-30 14:21:53 +02:00
24 changed files with 697 additions and 656 deletions

File diff suppressed because one or more lines are too long

View File

@@ -6,9 +6,10 @@ 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;
use Typemill\Models\Validation;
use Typemill\Models\Navigation;
use Typemill\Static\Slug;
class ControllerApiAuthorArticle extends Controller
{
@@ -74,7 +75,7 @@ class ControllerApiAuthorArticle extends Controller
}
# if an item is moved to the first level
if($parentKeyTo == '')
if($params['parent_id_to'] == '')
{
# create empty and default values so that the logic below still works
$newFolder = new \stdClass();
@@ -91,7 +92,7 @@ class ControllerApiAuthorArticle extends Controller
}
# if the item has been moved within the same folder
if($parentKeyFrom == $parentKeyTo)
if($params['parent_id_from'] == $params['parent_id_to'])
{
# no need to ping search engines
$ping = false;
@@ -127,14 +128,14 @@ class ControllerApiAuthorArticle extends Controller
$storage = new StorageWrapper('\Typemill\Models\Storage');
foreach($folderContent as $folderItem)
{
if(!$storage->moveFile($folderItem, $newFolder->path, $index))
if(!$storage->moveContentFile($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,
@@ -195,7 +196,7 @@ class ControllerApiAuthorArticle extends Controller
# input validation
$validate = new Validation();
$result = $validate->validateNaviItem($params);
$result = $validate->navigationItem($params);
if(!$result)
{
$response->getBody()->write(json_encode([
@@ -208,7 +209,7 @@ class ControllerApiAuthorArticle extends Controller
# set variables
$urlinfo = $this->c->get('urlinfo');
$langattr = $this->settings['langattr'];
$langattr = $this->settings['langattr'] ?? 'en';
# get navigation
$navigation = new Navigation();
@@ -217,8 +218,8 @@ class ControllerApiAuthorArticle extends Controller
if($params['folder_id'] == 'root')
{
$folderContent = $draftNavigation;
}
else
}
else
{
# get the ids (key path) for item, old folder and new folder
$folderKeyPath = explode('.', $params['folder_id']);
@@ -238,30 +239,28 @@ class ControllerApiAuthorArticle extends Controller
$folderContent = $folder->folderContent;
}
$slug = Slug::createSlug($params['item_name'], $langattr);
$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 : '';
$index = 0;
$writeError = false;
$folderPath = isset($folder) ? $folder->path : '';
$storage = new StorageWrapper('\Typemill\Models\Storage');
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);
$response->getBody()->write(json_encode([
'message' => 'There is already a page with this name. Please choose another name.'
]));
return $response->withHeader('Content-Type', 'application/json')->withStatus(422);
}
if(!$writeYaml->moveElement($folderItem, $folderPath, $index))
# rename files just in case that index is not in line (because file has been moved before)
if(!$storage->moveContentFile($folderItem, $folderPath, $index))
{
$writeError = true;
}
@@ -270,47 +269,63 @@ class ControllerApiAuthorArticle extends Controller
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);
$response->getBody()->write(json_encode([
'message' => 'Something went wrong. Please refresh the page and check, if all folders and files are writable.'
]));
return $response->withHeader('Content-Type', 'application/json')->withStatus(422);
}
# 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']);
$content = json_encode(['# ' . $params['item_name'], 'Content']);
if($this->params['type'] == 'file')
if($params['type'] == 'file')
{
if(!$writeYaml->writeFile($folderPath, $namePath . '.txt', $content))
if(!$storage->writeFile('contentFolder', $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);
$response->getBody()->write(json_encode([
'message' => 'We could not create the file. Please refresh the page and check, if all folders and files are writable.'
]));
return $response->withHeader('Content-Type', 'application/json')->withStatus(422);
}
$storage->updateYaml('contentFolder', $folderPath, $namePath . '.yaml', ['meta' => ['navtitle' => $params['item_name']]]);
}
elseif($this->params['type'] == 'folder')
elseif($params['type'] == 'folder')
{
if(!$writeYaml->checkPath($folderPath . DIRECTORY_SEPARATOR . $namePath))
if(!$storage->checkFolder('contentFolder', $folderPath, $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);
$response->getBody()->write(json_encode([
'message' => 'We could not create the folder. Please refresh the page and check, if all folders and files are writable.'
]));
return $response->withHeader('Content-Type', 'application/json')->withStatus(422);
}
$this->writeCache->writeFile($folderPath . DIRECTORY_SEPARATOR . $namePath, 'index.txt', $content);
$storage->writeFile('contentFolder', $folderPath . DIRECTORY_SEPARATOR . $namePath, 'index.txt', $content);
$storage->updateYaml('contentFolder', $folderPath . DIRECTORY_SEPARATOR . $namePath, 'index.yaml', ['meta' => ['navtitle' => $params['item_name']]]);
# always redirect to a folder
$url = $this->uri->getBaseUrl() . '/tm/content/' . $this->settings['editor'] . $folder->urlRelWoF . '/' . $slug;
# $url = $urlinfo['baseurl'] . '/tm/content/' . $this->settings['editor'] . $folder->urlRelWoF . '/' . $slug;
}
$navigation->clearNavigation();
/*
# get extended structure
$extended = $writeYaml->getYaml('cache', 'structure-extended.yaml');
$extended = $navigation->getExtendedNavigation($urlinfo, $langattr);
# create the url for the item
$urlWoF = $folder->urlRelWoF . '/' . $slug;
# $urlWoF = '/' . $slug;
if($params['folder_id'] == 'root')
{
$urlWoF = '/' . $slug;
}
else
{
$urlWoF = $folder->urlRelWoF . '/' . $slug;
}
# add the navigation name to the item htmlspecialchars needed for french language
$extended[$urlWoF] = ['hide' => false, 'navtitle' => $name];
@@ -331,5 +346,14 @@ class ControllerApiAuthorArticle extends Controller
# $url = $this->uri->getBaseUrl() . '/tm/content/' . $this->settings['editor'] . $folder->urlRelWoF . '/' . $slug;
return $response->withJson(array('data' => $this->structureDraft, 'errors' => false, 'url' => $url));
*/
$response->getBody()->write(json_encode([
'navigation' => $navigation->getDraftNavigation($urlinfo, $langattr),
'message' => '',
'url' => false
]));
return $response->withHeader('Content-Type', 'application/json');
}
}

View File

@@ -42,7 +42,9 @@ class ControllerApiSystemExtensions extends ControllerData
if($params['checked'] == true)
{
$definitions = $storage->getYaml($params['type'] . DIRECTORY_SEPARATOR . $params['name'], $params['name'] . '.yaml');
$folder = ( $params['type'] == 'plugins' ) ? 'pluginFolder' : 'themeFolder';
$definitions = $storage->getYaml($folder, $params['name'], $params['name'] . '.yaml');
if(isset($definitions['license']) && in_array($definitions['license'], ['MAKER', 'BUSINESS']))
{

View File

@@ -5,7 +5,6 @@ namespace Typemill\Controllers;
use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Http\Message\ResponseInterface as Response;
use Typemill\Models\Validation;
use Typemill\Models\StorageWrapper;
use Typemill\Models\License;
class ControllerApiSystemLicense extends ControllerData

View File

@@ -17,7 +17,7 @@ class ControllerApiSystemPlugins extends ControllerData
$pluginname = $params['plugin'];
$plugininput = $params['settings'];
$storage = new StorageWrapper('\Typemill\Models\Storage');
$formdefinitions = $storage->getYaml('plugins' . DIRECTORY_SEPARATOR . $pluginname, $pluginname . '.yaml');
$formdefinitions = $storage->getYaml('pluginFolder', $pluginname, $pluginname . '.yaml');
$plugindata = [];
# validate input

View File

@@ -29,7 +29,7 @@ class ControllerApiSystemSettings extends ControllerData
$params = $request->getParsedBody();
$settingsinput = $params['settings'];
$storage = new StorageWrapper('\Typemill\Models\Storage');
$formdefinitions = $storage->getYaml('system/typemill/settings', 'system.yaml');
$formdefinitions = $storage->getYaml('systemSettings', '', 'system.yaml');
# validate input
$validator = new Validation();

View File

@@ -18,7 +18,7 @@ class ControllerApiSystemThemes extends ControllerData
$themename = $params['theme'];
$themeinput = $params['settings'];
$storage = new StorageWrapper('\Typemill\Models\Storage');
$formdefinitions = $storage->getYaml('themes' . DIRECTORY_SEPARATOR . $themename, $themename . '.yaml');
$formdefinitions = $storage->getYaml('themeFolder', $themename, $themename . '.yaml');
$themedata = [];
# validate input

View File

@@ -18,7 +18,7 @@ class ControllerData extends Controller
{
$storage = new StorageWrapper('\Typemill\Models\Storage');
$mainnavi = $storage->getYaml('system/typemill/settings', 'mainnavi.yaml');
$mainnavi = $storage->getYaml('systemSettings', '', 'mainnavi.yaml');
$allowedmainnavi = [];
@@ -65,7 +65,7 @@ class ControllerData extends Controller
{
$storage = new StorageWrapper('\Typemill\Models\Storage');
$systemnavi = $storage->getYaml('system/typemill/settings', 'systemnavi.yaml');
$systemnavi = $storage->getYaml('systemSettings', '', 'systemnavi.yaml');
$systemnavi = $this->c->get('dispatcher')->dispatch(new OnSystemnaviLoaded($systemnavi), 'onSystemnaviLoaded')->getData();
$allowedsystemnavi = [];
@@ -126,7 +126,7 @@ class ControllerData extends Controller
{
$storage = new StorageWrapper('\Typemill\Models\Storage');
$themeSettings = $storage->getYaml('themes' . DIRECTORY_SEPARATOR . $themeName, $themeName . '.yaml');
$themeSettings = $storage->getYaml('themeFolder', $themeName, $themeName . '.yaml');
# add standard-textarea for custom css
$themeSettings['forms']['fields']['customcss'] = [
@@ -178,7 +178,7 @@ class ControllerData extends Controller
{
$storage = new StorageWrapper('\Typemill\Models\Storage');
$pluginSettings = $storage->getYaml('plugins' . DIRECTORY_SEPARATOR . $pluginName, $pluginName . '.yaml');
$pluginSettings = $storage->getYaml('pluginFolder', $pluginName, $pluginName . '.yaml');
return $pluginSettings;
}
@@ -195,7 +195,7 @@ class ControllerData extends Controller
$storage = new StorageWrapper('\Typemill\Models\Storage');
$userfields = $storage->getYaml('system/typemill/settings', 'user.yaml');
$userfields = $storage->getYaml('systemSettings', '', 'user.yaml');
# if a plugin with a role has been deactivated, then users with the role throw an error, so set them back to member...
if(!$this->c->get('acl')->hasRole($userrole))

View File

@@ -27,7 +27,7 @@ class ControllerWebAuth extends Controller
$input = $request->getParsedBody();
$validation = new Validation();
$settings = $this->c->get('settings');
# $settings = $this->c->get('settings');
if($validation->signin($input))
{
@@ -35,7 +35,9 @@ class ControllerWebAuth extends Controller
if(!$user->setUserWithPassword($input['username']))
{
# return error
$this->c->get('flash')->addMessage('error', 'Ups, wrong password or username, please try again!!');
return $response->withHeader('Location', $this->routeParser->urlFor('auth.show'))->withStatus(302);
}
$userdata = $user->getUserData();

View File

@@ -41,6 +41,8 @@ class ControllerWebAuthor extends Controller
$item = $navigation->getItemWithKeyPath($draftNavigation, explode(".", $pageinfo['keyPath']));
$draftNavigation = $navigation->setActiveNaviItems($draftNavigation, explode(".", $pageinfo['keyPath']));
$mainNavigation = $navigation->getMainNavigation($request->getAttribute('c_userrole'), $this->c->get('acl'), $urlinfo, $this->settings['editor']);
return $this->c->get('view')->render($response, 'content/blox-editor.twig', [
@@ -52,11 +54,7 @@ class ControllerWebAuthor extends Controller
'item' => $item,
'urlinfo' => $urlinfo
]
]);
echo '<pre>';
print_r($draftNavigation);
die();
]);

View File

@@ -11,7 +11,7 @@ class ControllerWebSystem extends ControllerData
public function showSettings($request, $response, $args)
{
$storage = new StorageWrapper('\Typemill\Models\Storage');
$systemfields = $storage->getYaml('system/typemill/settings', 'system.yaml');
$systemfields = $storage->getYaml('systemSettings', '', 'system.yaml');
$translations = $this->c->get('translations');
# add full url for sitemap to settings
@@ -42,7 +42,7 @@ class ControllerWebSystem extends ControllerData
foreach($this->settings['themes'] as $themename => $themeinputs)
{
$themeSettings[$themename] = $themeinputs;
$themeSettings[$themename]['customcss'] = $storage->getFile('cache', $themename . '-custom.css');
$themeSettings[$themename]['customcss'] = $storage->getFile('cacheFolder', '', $themename . '-custom.css');
}
$license = [];
@@ -102,7 +102,7 @@ class ControllerWebSystem extends ControllerData
{
$storage = new StorageWrapper('\Typemill\Models\Storage');
$license = new License();
$licensefields = $storage->getYaml('system/typemill/settings', 'license.yaml');
$licensefields = $storage->getYaml('systemSettings', '', 'license.yaml');
$translations = $this->c->get('translations');
$licensedata = $license->getLicenseData($this->c->get('urlinfo'));

View File

@@ -5,7 +5,7 @@ namespace Typemill\Extensions;
use Twig\Extension\AbstractExtension;
use Twig\TwigFilter;
use Twig\TwigFunction;
use Typemill\Models\WriteYaml;
# use Typemill\Models\WriteYaml;
class TwigLanguageExtension extends AbstractExtension
{

View File

@@ -74,7 +74,7 @@ class License
{
$storage = new StorageWrapper('\Typemill\Models\Storage');
$licensedata = $storage->getYaml('settings', 'license.yaml');
$licensedata = $storage->getYaml('basepath', 'settings', 'license.yaml');
if(!$licensedata)
{
@@ -193,7 +193,7 @@ class License
$signedLicense['license']['email'] = trim($params['email']);
$storage = new StorageWrapper('\Typemill\Models\Storage');
$storage->updateYaml('settings', 'license.yaml', $signedLicense['license']);
$storage->updateYaml('basepath', 'settings', 'license.yaml', $signedLicense['license']);
return true;
}

View File

@@ -5,7 +5,7 @@ namespace Typemill\Models;
use Typemill\Models\StorageWrapper;
use Typemill\Models\Folder;
class Navigation
class Navigation extends Folder
{
private $storage;
@@ -27,11 +27,13 @@ class Navigation
private $basicLiveNavigation = false;
public $activeNavigation = false;
public function __construct()
{
$this->storage = new StorageWrapper('\Typemill\Models\Storage');
$this->naviFolder = 'data' . DIRECTORY_SEPARATOR . 'navigation';
$this->naviFolder = 'navigation';
$this->liveNaviName = 'navi-live.txt';
@@ -63,7 +65,7 @@ class Navigation
foreach($navifiles as $navifile)
{
$result = $this->storage->deleteFile($this->naviFolder, $navifile);
$result = $this->storage->deleteFile('dataFolder', $this->naviFolder, $navifile);
}
return $result;
@@ -71,7 +73,7 @@ class Navigation
public function getMainNavigation($userrole, $acl, $urlinfo, $editor)
{
$mainnavi = $this->storage->getYaml('system/typemill/settings', 'mainnavi.yaml');
$mainnavi = $this->storage->getYaml('systemSettings', '', 'mainnavi.yaml');
$allowedmainnavi = [];
@@ -110,7 +112,7 @@ class Navigation
{
# todo: filter for userrole or username
$this->draftNavigation = $this->storage->getFile($this->naviFolder, $this->draftNaviName, 'unserialize');
$this->draftNavigation = $this->storage->getFile('dataFolder', $this->naviFolder, $this->draftNaviName, 'unserialize');
if($this->draftNavigation)
{
@@ -127,7 +129,7 @@ class Navigation
$draftNavigation = $this->mergeNavigationWithExtended($basicDraftNavigation, $extendedNavigation);
# cache it
$this->storage->writeFile($this->naviFolder, $this->draftNaviName, $draftNavigation, 'serialize');
$this->storage->writeFile('dataFolder', $this->naviFolder, $this->draftNaviName, $draftNavigation, 'serialize');
return $draftNavigation;
}
@@ -144,15 +146,13 @@ class Navigation
# creates a fresh structure with published and non-published pages for the author
public function createBasicDraftNavigation($urlinfo, $language)
{
$folder = new Folder();
# scan the content of the folder
$draftContentTree = $folder->scanFolder($this->storage->getStorageInfo('contentFolder'), $draft = true);
$draftContentTree = $this->scanFolder($this->storage->getFolderPath('contentFolder'), $draft = true);
# if there is content, then get the content details
if(count($draftContentTree) > 0)
{
$draftNavigation = $folder->getFolderContentDetails($draftContentTree, $language, $urlinfo['baseurl'], $urlinfo['basepath']);
$draftNavigation = $this->getFolderContentDetails($draftContentTree, $language, $urlinfo['baseurl'], $urlinfo['basepath']);
return $draftNavigation;
}
@@ -166,7 +166,7 @@ class Navigation
if(!$this->extendedNavigation)
{
# read the extended navi file
$this->extendedNavigation = $this->storage->getYaml($this->naviFolder, $this->extendedNaviName);
$this->extendedNavigation = $this->storage->getYaml('dataFolder', $this->naviFolder, $this->extendedNaviName);
}
if(!$this->extendedNavigation)
@@ -176,7 +176,7 @@ class Navigation
$this->extendedNavigation = $this->createExtendedNavigation($basicDraftNavigation, $extended = NULL);
# cache it
$this->storage->updateYaml($this->naviFolder, $this->extendedNaviName, $this->extendedNavigation);
$this->storage->updateYaml('dataFolder', $this->naviFolder, $this->extendedNaviName, $this->extendedNavigation);
}
return $this->extendedNavigation;
@@ -190,7 +190,7 @@ class Navigation
$extended = [];
}
$contentFolder = $this->storage->getStorageInfo('contentFolder');
$contentFolder = $this->storage->getFolderPath('contentFolder');
foreach ($navigation as $key => $item)
{
@@ -200,7 +200,7 @@ class Navigation
if(file_exists($contentFolder . $filename))
{
# read file
$meta = $this->storage->getYaml($contentFolder, $filename);
$meta = $this->storage->getYaml($contentFolder, '', $filename);
$extended[$item->urlRelWoF]['navtitle'] = isset($meta['meta']['navtitle']) ? $meta['meta']['navtitle'] : '';
$extended[$item->urlRelWoF]['hide'] = isset($meta['meta']['hide']) ? $meta['meta']['hide'] : false;
@@ -208,6 +208,10 @@ class Navigation
$extended[$item->urlRelWoF]['path'] = $item->path;
$extended[$item->urlRelWoF]['keyPath'] = $item->keyPath;
}
else
{
# should we create the yaml file here if it does not exist?
}
if ($item->elementType == 'folder')
{
@@ -250,7 +254,7 @@ class Navigation
foreach($searchArray as $key => $itemKey)
{
$item = isset($navigation[$itemKey]) ? clone($navigation[$itemKey]) : false;
unset($searchArray[$key]);
if(!empty($searchArray) && $item)
{
@@ -261,11 +265,60 @@ class Navigation
return $item;
}
public function getItemForUrlFrontend($folderContentDetails, $url, $result = NULL)
{
foreach($folderContentDetails as $key => $item)
{
# set item active, needed to move item in navigation
if($item->urlRelWoF === $url)
{
$item->active = true;
$result = $item;
}
elseif($item->elementType === "folder")
{
$result = $this->getItemForUrlFrontend($item->folderContent, $url, $result);
}
}
return $result;
}
public function setActiveNaviItems($navigation, array $searchArray)
{
foreach($searchArray as $key => $itemKey)
{
if(isset($navigation[$itemKey]))
{
unset($searchArray[$key]);
# active, if there are no more subitems
if(empty($searchArray))
{
$navigation[$itemKey]->active = true;
}
# activeParent, if there are more subitems
if(!empty($searchArray) && isset($navigation[$itemKey]->folderContent))
{
$navigation[$itemKey]->activeParent = true;
$navigation[$itemKey]->folderContent = $this->setActiveNaviItems($navigation[$itemKey]->folderContent, $searchArray);
}
# break to avoid other items with that key are set active
break;
}
}
return $navigation;
}
############################## TODO
# reads the cached structure with published pages
public function getLiveNavigation()
{
# get the cached navi
$liveNavi = $this->storage->getFile($this->naviFolder, $this->liveNaviName, 'unserialize');
$liveNavi = $this->storage->getFile('naviFolder', $this->naviFolder, $this->liveNaviName, 'unserialize');
# if there is no cached structure
if(!$liveNavi)
@@ -276,13 +329,13 @@ class Navigation
return $liveNavi;
}
################################## TODO
# creates a fresh structure with published pages
private function createNewLiveNavigation($urlinfo, $language)
{
$folder = new Folder();
# scan the content of the folder
$draftNavi = $folder->scanFolder($this->storage->contentFolder, $draft = false);
$draftNavi = $this->scanFolder($this->storage->contentFolder, $draft = false);
# if there is content, then get the content details
if($draftNavi && count($draftNavi) > 0)
@@ -316,7 +369,7 @@ class Navigation
{
# get the extended structure files with changes like navigation title or hidden pages
$yaml = new writeYaml();
$extended = $yaml->getYaml('cache', 'structure-extended.yaml');
$extended = $yaml->getYaml('cacheFolder', '', 'structure-extended.yaml');
if(isset($extended[$item->urlRelWoF]))
{
@@ -327,7 +380,7 @@ class Navigation
unset($extended[$item->urlRelWoF]);
$extended[$newUrl] = $entry;
$yaml->updateYaml('cache', 'structure-extended.yaml', $extended);
$yaml->updateYaml('cacheFolder', '', 'structure-extended.yaml', $extended);
}
return true;
@@ -343,7 +396,7 @@ class Navigation
if($this->item->elementType == "file" && isset($extended[$this->item->urlRelWoF]))
{
unset($extended[$this->item->urlRelWoF]);
$yaml->updateYaml('cache', 'structure-extended.yaml', $extended);
$yaml->updateYaml('cacheFolder', '', 'structure-extended.yaml', $extended);
}
if($this->item->elementType == "folder")
@@ -362,7 +415,7 @@ class Navigation
if($changed)
{
$yaml->updateYaml('cache', 'structure-extended.yaml', $extended);
$yaml->updateYaml('cacheFolder', '', 'structure-extended.yaml', $extended);
}
}
}

View File

@@ -11,6 +11,7 @@ class Yaml extends StorageWrapper
*/
public function getYaml($folderName, $yamlFileName)
{
die('you are useing old class here');
$yaml = $this->getFile($folderName, $yamlFileName);
if($yaml)
@@ -29,6 +30,7 @@ class Yaml extends StorageWrapper
*/
public function updateYaml($folderName, $yamlFileName, $contentArray)
{
die('you are useing old class here');
$yaml = \Symfony\Component\Yaml\Yaml::dump($contentArray,6);
if($this->writeFile($folderName, $yamlFileName, $yaml))
{

View File

@@ -4,41 +4,69 @@ namespace Typemill\Models;
class Storage
{
public $error = false;
public $error = false;
protected $basepath = false;
protected $basepath = false;
protected $tmpFolder = false;
protected $tmpFolder = false;
protected $originalFolder = false;
protected $originalFolder = false;
protected $liveFolder = false;
protected $liveFolder = false;
protected $thumbsFolder = false;
protected $thumbsFolder = false;
protected $customFolder = false;
protected $customFolder = false;
protected $fileFolder = false;
protected $fileFolder = false;
protected $contentFolder = false;
protected $contentFolder = false;
protected $dataFolder = false;
protected $cacheFolder = false;
protected $settingsFolder = false;
protected $themeFolder = false;
protected $pluginFolder = false;
protected $translationFolder = false;
protected $systemSettings = false;
public function __construct()
{
$this->basepath = getcwd() . DIRECTORY_SEPARATOR;
$this->basepath = getcwd() . DIRECTORY_SEPARATOR;
$this->tmpFolder = $this->basepath . 'media' . DIRECTORY_SEPARATOR . 'tmp' . DIRECTORY_SEPARATOR;
$this->tmpFolder = $this->basepath . 'media' . DIRECTORY_SEPARATOR . 'tmp' . DIRECTORY_SEPARATOR;
$this->originalFolder = $this->basepath . 'media' . DIRECTORY_SEPARATOR . 'original' . DIRECTORY_SEPARATOR;
$this->originalFolder = $this->basepath . 'media' . DIRECTORY_SEPARATOR . 'original' . DIRECTORY_SEPARATOR;
$this->liveFolder = $this->basepath . 'media' . DIRECTORY_SEPARATOR . 'live' . DIRECTORY_SEPARATOR;
$this->liveFolder = $this->basepath . 'media' . DIRECTORY_SEPARATOR . 'live' . DIRECTORY_SEPARATOR;
$this->thumbsFolder = $this->basepath . 'media' . DIRECTORY_SEPARATOR . 'thumbs' . DIRECTORY_SEPARATOR;
$this->thumbsFolder = $this->basepath . 'media' . DIRECTORY_SEPARATOR . 'thumbs' . DIRECTORY_SEPARATOR;
$this->customFolder = $this->basepath . 'media' . DIRECTORY_SEPARATOR . 'custom' . DIRECTORY_SEPARATOR;
$this->customFolder = $this->basepath . 'media' . DIRECTORY_SEPARATOR . 'custom' . DIRECTORY_SEPARATOR;
$this->fileFolder = $this->basepath . 'media' . DIRECTORY_SEPARATOR . 'files' . DIRECTORY_SEPARATOR;
$this->fileFolder = $this->basepath . 'media' . DIRECTORY_SEPARATOR . 'files' . DIRECTORY_SEPARATOR;
$this->contentFolder = $this->basepath . 'content';
$this->contentFolder = $this->basepath . 'content';
$this->dataFolder = $this->basepath . 'data';
$this->cacheFolder = $this->basepath . 'cache';
$this->settingsFolder = $this->basepath . 'settings';
$this->pluginFolder = $this->basepath . 'plugins';
$this->themeFolder = $this->basepath . 'themes';
$this->translationFolder = $this->basepath . 'system' . DIRECTORY_SEPARATOR . 'typemill' . DIRECTORY_SEPARATOR . 'author' . DIRECTORY_SEPARATOR . 'translations' . DIRECTORY_SEPARATOR;
$this->systemSettings = $this->basepath . 'system' . DIRECTORY_SEPARATOR . 'typemill' . DIRECTORY_SEPARATOR . 'settings';
}
public function getError()
@@ -46,7 +74,251 @@ class Storage
return $this->error;
}
public function getStorageInfo($item)
public function getFolderPath($location, $folder = NULL)
{
if(isset($this->$location))
{
$path = rtrim($this->$location, DIRECTORY_SEPARATOR);
$path .= DIRECTORY_SEPARATOR;
if($folder && $folder != '')
{
$folder = trim($folder, DIRECTORY_SEPARATOR);
$path .= $folder . DIRECTORY_SEPARATOR;
}
# echo '<pre>';
# echo $path;
return $path;
}
$this->error = "We could not find a folderPath for $location";
return false;
}
public function checkFolder($location, $folder)
{
$folderpath = $this->getFolderPath($location, $folder);
if(!is_dir($folderpath) OR !is_writable($folderpath))
{
$this->error = "The folder $folderpath does not exist or is not writable.";
return false;
}
return true;
}
public function createFolder($location, $folder)
{
$folderpath = $this->getFolderPath($location, $folder);
if(is_dir($folderpath))
{
return true;
}
if(!mkdir($folderpath, 0755, true))
{
$this->error = "Could not create folder $folderpath.";
return false;
}
return true;
}
public function checkFile($location, $folder, $filename)
{
$filepath = $this->getFolderPath($location, $folder) . $filename;
if(!file_exists($filepath))
{
$this->error = "The file $filepath does not exist.";
return false;
}
return true;
}
public function getFile($location, $folder, $filename, $method = NULL)
{
if($this->checkFile($location, $folder, $filename))
{
$filepath = $this->getFolderPath($location) . $folder . DIRECTORY_SEPARATOR . $filename;
$fileContent = file_get_contents($filepath);
# use unserialise or json_decode
if($method && is_callable($method))
{
$fileContent = $method($fileContent);
}
return $fileContent;
}
return false;
}
public function writeFile($location, $folder, $filename, $data, $method = NULL)
{
if(!$this->checkFolder($location, $folder))
{
if(!$this->createFolder($location, $folder))
{
return false;
}
}
$filepath = $this->getFolderPath($location) . $folder . DIRECTORY_SEPARATOR . $filename;
$openfile = @fopen($filepath, "w");
if(!$openfile)
{
$this->error = "Could not open and read the file $filepath";
return false;
}
# serialize, json_decode
if($method && is_callable($method))
{
$data = $method($data);
}
$writefile = fwrite($openfile, $data);
if(!$writefile)
{
$this->error = "Could not write to the file $filepath";
return false;
}
fclose($openfile);
return true;
}
public function renameFile($location, $folder, $oldname, $newname)
{
$oldFilePath = $this->getFolderPath($location) . $folder . DIRECTORY_SEPARATOR . $oldname;
$newFilePath = $this->getFolderPath($location) . $folder . DIRECTORY_SEPARATOR . $newname;
if(!file_exists($oldFilePath))
{
return false;
}
if(!rename($oldFilePath, $newFilePath))
{
return false;
}
return true;
}
public function deleteFile($location, $folder, $filename)
{
if($this->checkFile($location, $folder, $filename))
{
$filepath = $this->getFolderPath($location) . $folder . DIRECTORY_SEPARATOR . $filename;
if(unlink($filepath))
{
return true;
}
$this->error = "We found the file but could not delete $filepath";
}
return false;
}
# used to sort the navigation / files
public function moveContentFile($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->contentFolder . $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;
}
public function getYaml($location, $folder, $filename)
{
$yaml = $this->getFile($location, $folder, $filename);
if($yaml)
{
return \Symfony\Component\Yaml\Yaml::parse($yaml);
}
return false;
}
public function updateYaml($location, $folder, $filename, $contentArray)
{
$yaml = \Symfony\Component\Yaml\Yaml::dump($contentArray,6);
if($this->writeFile($location, $folder, $filename, $yaml))
{
return true;
}
return false;
}
public function getStorageInfoBREAK($item)
{
if(isset($this->$item))
{
@@ -55,7 +327,7 @@ class Storage
return false;
}
public function checkFolder($folder)
public function checkFolderBREAK($folder)
{
$folderpath = $this->basepath . $folder;
@@ -69,7 +341,7 @@ class Storage
return true;
}
public function createFolder($folder)
public function createFolderBREAK($folder)
{
$folderpath = $this->basepath . $folder;
@@ -88,7 +360,7 @@ class Storage
return true;
}
public function checkFile($folder, $filename)
public function checkFileBREAK($folder, $filename)
{
if(!file_exists($this->basepath . $folder . DIRECTORY_SEPARATOR . $filename))
{
@@ -100,8 +372,12 @@ class Storage
return true;
}
public function writeFile($folder, $filename, $data, $method = NULL)
public function writeFileBREAK($folder, $filename, $data, $method = NULL)
{
echo '<pre>';
var_dump($folder);
die();
if(!$this->checkFolder($folder))
{
if(!$this->createFolder($folder))
@@ -139,7 +415,7 @@ class Storage
return true;
}
public function getFile($folder, $filename, $method = NULL)
public function getFileBREAK($folder, $filename, $method = NULL)
{
if($this->checkFile($folder, $filename))
{
@@ -158,9 +434,8 @@ class Storage
return false;
}
public function renameFile($folder, $oldname, $newname)
public function renameFileBREAK($folder, $oldname, $newname)
{
$oldFilePath = $this->basepath . $folder . DIRECTORY_SEPARATOR . $oldname;
$newFilePath = $this->basepath . $folder . DIRECTORY_SEPARATOR . $newname;
@@ -177,7 +452,7 @@ class Storage
return true;
}
public function deleteFile($folder, $filename)
public function deleteFileBREAK($folder, $filename)
{
if($this->checkFile($folder, $filename))
{
@@ -193,7 +468,7 @@ class Storage
}
# used to sort the navigation / files
public function moveFile($item, $folderPath, $index, $date = null)
public function moveContentFileBREAK($item, $folderPath, $index, $date = null)
{
$filetypes = array('md', 'txt', 'yaml');
@@ -204,7 +479,8 @@ class Storage
if($item->elementType == 'folder')
{
$oldPath = $this->basePath . 'content' . $item->path;
$oldPath = $this->contentFolder . $item->path;
if(@rename($oldPath, $newPath))
{
return true;
@@ -237,44 +513,9 @@ class Storage
}
}
return $result;
return $result;
}
/**
* Get the a yaml file.
* @param string $fileName is the name of the Yaml Folder.
* @param string $yamlFileName is the name of the Yaml File.
*/
public function getYaml($folderName, $yamlFileName)
{
$yaml = $this->getFile($folderName, $yamlFileName);
if($yaml)
{
return \Symfony\Component\Yaml\Yaml::parse($yaml);
}
return false;
}
/**
* Writes a yaml file.
* @param string $fileName is the name of the Yaml Folder.
* @param string $yamlFileName is the name of the Yaml File.
* @param array $contentArray is the content as an array.
*/
public function updateYaml($folderName, $yamlFileName, $contentArray)
{
$yaml = \Symfony\Component\Yaml\Yaml::dump($contentArray,6);
if($this->writeFile($folderName, $yamlFileName, $yaml))
{
return true;
}
return false;
}
public function createUniqueImageName($filename, $extension)

View File

@@ -22,7 +22,7 @@ class User
public function setUser(string $username)
{
$this->user = $this->storage->getYaml('settings/users', $username . '.yaml');
$this->user = $this->storage->getYaml('settingsFolder', 'users', $username . '.yaml');
if(!$this->user)
{
@@ -39,7 +39,7 @@ class User
public function setUserWithPassword(string $username)
{
$this->user = $this->storage->getYaml('settings/users', $username . '.yaml');
$this->user = $this->storage->getYaml('settingsFolder', 'users', $username . '.yaml');
if(!$this->user)
{
@@ -103,7 +103,7 @@ class User
{
$params['password'] = $this->generatePassword($params['password']);
if($this->storage->updateYaml('settings/users', $params['username'] . '.yaml', $params))
if($this->storage->updateYaml('settingsFolder', 'users', $params['username'] . '.yaml', $params))
{
$this->deleteUserIndex();
@@ -117,7 +117,7 @@ class User
public function updateUser()
{
if($this->storage->updateYaml('settings/users', $this->user['username'] . '.yaml', $this->user))
if($this->storage->updateYaml('settingsFolder', 'users', $this->user['username'] . '.yaml', $this->user))
{
$this->deleteUserIndex();
@@ -131,7 +131,7 @@ class User
public function deleteUser()
{
if($this->storage->deleteFile('settings/users/', $this->user['username'] . '.yaml'))
if($this->storage->deleteFile('settingsFolder', 'users', $this->user['username'] . '.yaml'))
{
$this->deleteUserIndex();

View File

@@ -59,7 +59,7 @@ class Helpers{
$line .= ';' . $action;
$storage = new StorageWrapper('\Typemill\Models\Storage');
$logfile = $storage->getFile('cache', 'securitylog.txt');
$logfile = $storage->getFile('basepath', 'cache', 'securitylog.txt');
if($logfile)
{
@@ -70,7 +70,7 @@ class Helpers{
$logfile = $line . PHP_EOL;
}
$storage->writeFile('cache', 'securitylog.txt', $logfile);
$storage->writeFile('basepath', 'cache', 'securitylog.txt', $logfile);
}
public static function array_sort($array, $on, $order=SORT_ASC)

View File

@@ -20,7 +20,7 @@ class License
{
$storage = new StorageWrapper('\Typemill\Models\Storage');
$licensedata = $storage->getYaml('settings', 'license.yaml');
$licensedata = $storage->getYaml('basepath', 'settings', 'license.yaml');
if(!$licensedata)
{

View File

@@ -134,7 +134,7 @@ class Settings
$storage = new StorageWrapper('\Typemill\Models\Storage');
$storage->updateYaml('settings', 'settings.yaml', $settings);
$storage->updateYaml('basepath', 'settings', 'settings.yaml', $settings);
}

View File

@@ -29,21 +29,13 @@ class Translations
$plugins_translations = [];
# theme labels selected according to the environment: admin or user
$theme_language_folder = 'themes' . DIRECTORY_SEPARATOR . $settings['theme'] . DIRECTORY_SEPARATOR . 'languages' . DIRECTORY_SEPARATOR . $environment . DIRECTORY_SEPARATOR;
$theme_language_file = $language . '.yaml';
if (file_exists($theme_language_folder . $theme_language_file))
{
$theme_translations = $storage->getYaml($theme_language_folder, $theme_language_file);
}
$theme_language_folder = DIRECTORY_SEPARATOR . $settings['theme'] . DIRECTORY_SEPARATOR . 'languages' . DIRECTORY_SEPARATOR . $environment . DIRECTORY_SEPARATOR;
$theme_translations = $storage->getYaml('themeFolder', $theme_language_folder, $language . '.yaml') ?? [];
if($environment == 'admin')
{
$system_language_folder = 'system' . DIRECTORY_SEPARATOR . 'typemill' . DIRECTORY_SEPARATOR . 'author' . DIRECTORY_SEPARATOR . 'translations' . DIRECTORY_SEPARATOR;
$system_language_file = $language . '.yaml';
if(file_exists($system_language_folder . $system_language_file))
{
$system_translations = $storage->getYaml($system_language_folder, $system_language_file);
}
$system_language_folder = DIRECTORY_SEPARATOR . 'typemill' . DIRECTORY_SEPARATOR . 'author' . DIRECTORY_SEPARATOR . 'translations' . DIRECTORY_SEPARATOR;
$system_translations = $storage->getYaml('translationFolder', $system_language_folder, $language . '.yaml');
# Next change, to provide labels for the admin and user environments.
# There may be plugins that only work in the user environment, only in the admin environment, or in both environments.
@@ -54,12 +46,8 @@ class Translations
{
if(isset($config['active']) && $config['active'])
{
$plugin_language_folder = 'plugins' . DIRECTORY_SEPARATOR . $plugin . DIRECTORY_SEPARATOR . 'languages' . DIRECTORY_SEPARATOR;
$plugin_language_file = $language . '.yaml';
if (file_exists($plugin_language_folder . $plugin_language_file))
{
$plugins_translations[$plugin] = $storage->getYaml($plugin_language_folder, $plugin_language_file);
}
$plugin_language_folder = DIRECTORY_SEPARATOR . $plugin . DIRECTORY_SEPARATOR . 'languages' . DIRECTORY_SEPARATOR;
$plugins_translations[$plugin] = $storage->getYaml('pluginFolder', $plugin_language_folder, $language . '.yaml');
}
}
@@ -69,24 +57,23 @@ class Translations
{
$plugins_translations = array_merge($plugins_translations, $value);
}
}
}
}
}
$translations = [];
if(!empty($plugins_translations))
if(is_array($plugins_translations) && !empty($plugins_translations))
{
$translations = array_merge($translations, $plugins_translations);
}
if(!empty($system_translations))
if(is_array($system_translations) && !empty($system_translations))
{
$translations = array_merge($translations, $system_translations);
}
if(!empty($theme_translations))
if(is_array($theme_translations) && !empty($theme_translations))
{
$translations = array_merge($translations, $theme_translations);
}
return $translations;
}

View File

@@ -661,14 +661,14 @@ video {
bottom: 0px;
}
.left-0 {
left: 0px;
}
.right-0 {
right: 0px;
}
.left-0 {
left: 0px;
}
.top-0 {
top: 0px;
}
@@ -701,15 +701,16 @@ video {
margin: auto;
}
.m-1 {
margin: 0.25rem;
}
.my-2 {
margin-top: 0.5rem;
margin-bottom: 0.5rem;
}
.my-px {
margin-top: 1px;
margin-bottom: 1px;
}
.my-8 {
margin-top: 2rem;
margin-bottom: 2rem;
@@ -740,11 +741,6 @@ video {
margin-bottom: 0.75rem;
}
.mx-1 {
margin-left: 0.25rem;
margin-right: 0.25rem;
}
.mt-6 {
margin-top: 1.5rem;
}
@@ -757,16 +753,16 @@ video {
margin-right: 0.75rem;
}
.mb-1 {
margin-bottom: 0.25rem;
.ml-1 {
margin-left: 0.25rem;
}
.mr-1 {
margin-right: 0.25rem;
}
.mr-4 {
margin-right: 1rem;
.mb-1 {
margin-bottom: 0.25rem;
}
.mt-3 {
@@ -813,18 +809,14 @@ video {
margin-top: 1.75rem;
}
.mr-4 {
margin-right: 1rem;
}
.mr-2 {
margin-right: 0.5rem;
}
.ml-1 {
margin-left: 0.25rem;
}
.-ml-1 {
margin-left: -0.25rem;
}
.block {
display: block;
}
@@ -861,6 +853,10 @@ video {
display: none;
}
.h-5 {
height: 1.25rem;
}
.h-8 {
height: 2rem;
}
@@ -877,10 +873,6 @@ video {
height: 3rem;
}
.h-5 {
height: 1.25rem;
}
.h-80 {
height: 20rem;
}
@@ -905,6 +897,10 @@ video {
width: 100%;
}
.w-5 {
width: 1.25rem;
}
.w-1\/4 {
width: 25%;
}
@@ -929,10 +925,6 @@ video {
width: 0px;
}
.w-5 {
width: 1.25rem;
}
.w-2\/3 {
width: 66.666667%;
}
@@ -1026,10 +1018,6 @@ video {
resize: both;
}
.list-none {
list-style-type: none;
}
.flex-col {
flex-direction: column;
}
@@ -1106,6 +1094,11 @@ video {
border-width: 2px;
}
.border-y {
border-top-width: 1px;
border-bottom-width: 1px;
}
.border-x-8 {
border-left-width: 8px;
border-right-width: 8px;
@@ -1152,14 +1145,24 @@ video {
border-color: rgb(209 213 219 / var(--tw-border-opacity));
}
.border-stone-200 {
--tw-border-opacity: 1;
border-color: rgb(231 229 228 / var(--tw-border-opacity));
}
.border-teal-500 {
--tw-border-opacity: 1;
border-color: rgb(20 184 166 / var(--tw-border-opacity));
}
.border-stone-200 {
.border-stone-100 {
--tw-border-opacity: 1;
border-color: rgb(231 229 228 / var(--tw-border-opacity));
border-color: rgb(245 245 244 / var(--tw-border-opacity));
}
.border-stone-50 {
--tw-border-opacity: 1;
border-color: rgb(250 250 249 / var(--tw-border-opacity));
}
.border-white {
@@ -1187,16 +1190,6 @@ video {
border-color: rgb(255 228 230 / var(--tw-border-opacity));
}
.border-stone-100 {
--tw-border-opacity: 1;
border-color: rgb(245 245 244 / var(--tw-border-opacity));
}
.border-stone-50 {
--tw-border-opacity: 1;
border-color: rgb(250 250 249 / var(--tw-border-opacity));
}
.border-cyan-500 {
--tw-border-opacity: 1;
border-color: rgb(6 182 212 / var(--tw-border-opacity));
@@ -1232,6 +1225,20 @@ video {
background-color: rgb(255 255 255 / var(--tw-bg-opacity));
}
.bg-transparent {
background-color: transparent;
}
.bg-teal-500 {
--tw-bg-opacity: 1;
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-stone-100 {
--tw-bg-opacity: 1;
background-color: rgb(245 245 244 / var(--tw-bg-opacity));
@@ -1247,16 +1254,6 @@ video {
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));
@@ -1272,10 +1269,6 @@ video {
background-color: rgb(250 250 249 / var(--tw-bg-opacity));
}
.bg-transparent {
background-color: transparent;
}
.bg-opacity-90 {
--tw-bg-opacity: 0.9;
}
@@ -1337,6 +1330,11 @@ video {
padding-bottom: 0.75rem;
}
.px-2 {
padding-left: 0.5rem;
padding-right: 0.5rem;
}
.px-8 {
padding-left: 2rem;
padding-right: 2rem;
@@ -1357,28 +1355,43 @@ video {
padding-right: 1rem;
}
.px-2 {
padding-left: 0.5rem;
padding-right: 0.5rem;
}
.px-1 {
padding-left: 0.25rem;
padding-right: 0.25rem;
}
.pl-2 {
padding-left: 0.5rem;
}
.pl-3 {
padding-left: 0.75rem;
}
.pl-2 {
padding-left: 0.5rem;
}
.pl-4 {
padding-left: 1rem;
}
.pl-6 {
padding-left: 1.5rem;
}
.pl-8 {
padding-left: 2rem;
}
.pl-9 {
padding-left: 2.25rem;
}
.pl-10 {
padding-left: 2.5rem;
}
.pl-12 {
padding-left: 3rem;
}
.pr-2 {
padding-right: 0.5rem;
}
@@ -1411,18 +1424,6 @@ video {
padding-bottom: 0.75rem;
}
.pl-4 {
padding-left: 1rem;
}
.pl-8 {
padding-left: 2rem;
}
.pl-12 {
padding-left: 3rem;
}
.text-left {
text-align: left;
}
@@ -1463,11 +1464,6 @@ video {
line-height: 2.25rem;
}
.text-sm {
font-size: 0.875rem;
line-height: 1.25rem;
}
.text-lg {
font-size: 1.125rem;
line-height: 1.75rem;
@@ -1478,6 +1474,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;
@@ -1526,6 +1527,21 @@ video {
color: rgb(225 29 72 / var(--tw-text-opacity));
}
.text-stone-50 {
--tw-text-opacity: 1;
color: rgb(250 250 249 / var(--tw-text-opacity));
}
.text-stone-700 {
--tw-text-opacity: 1;
color: rgb(68 64 60 / var(--tw-text-opacity));
}
.text-stone-500 {
--tw-text-opacity: 1;
color: rgb(120 113 108 / var(--tw-text-opacity));
}
.text-teal-500 {
--tw-text-opacity: 1;
color: rgb(20 184 166 / var(--tw-text-opacity));
@@ -1561,21 +1577,6 @@ 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;
@@ -1585,10 +1586,6 @@ video {
accent-color: #fff;
}
.opacity-0 {
opacity: 0;
}
.opacity-25 {
opacity: 0.25;
}
@@ -1597,6 +1594,10 @@ video {
opacity: 0.75;
}
.opacity-0 {
opacity: 0;
}
.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);
@@ -1659,6 +1660,11 @@ video {
border-bottom-width: 4px;
}
.hover\:border-stone-200:hover {
--tw-border-opacity: 1;
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));
@@ -1674,19 +1680,24 @@ 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 {
.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-teal-500:hover {
--tw-bg-opacity: 1;
background-color: rgb(20 184 166 / var(--tw-bg-opacity));
}
.hover\:bg-stone-200:hover {
--tw-bg-opacity: 1;
background-color: rgb(231 229 228 / var(--tw-bg-opacity));
}
.hover\:bg-stone-900:hover {
@@ -1714,11 +1725,6 @@ video {
background-color: rgb(214 211 209 / var(--tw-bg-opacity));
}
.hover\:bg-stone-200:hover {
--tw-bg-opacity: 1;
background-color: rgb(231 229 228 / var(--tw-bg-opacity));
}
.hover\:bg-rose-700:hover {
--tw-bg-opacity: 1;
background-color: rgb(190 18 60 / var(--tw-bg-opacity));
@@ -1734,24 +1740,9 @@ video {
background-color: rgb(6 182 212 / var(--tw-bg-opacity));
}
.hover\:bg-stone-700:hover {
.hover\:bg-stone-50:hover {
--tw-bg-opacity: 1;
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 {
--tw-text-opacity: 1;
color: rgb(255 255 255 / var(--tw-text-opacity));
background-color: rgb(250 250 249 / var(--tw-bg-opacity));
}
.hover\:text-stone-50:hover {
@@ -1764,6 +1755,11 @@ video {
color: rgb(245 245 244 / var(--tw-text-opacity));
}
.hover\:text-white:hover {
--tw-text-opacity: 1;
color: rgb(255 255 255 / var(--tw-text-opacity));
}
.hover\:underline:hover {
-webkit-text-decoration-line: underline;
text-decoration-line: underline;
@@ -1774,9 +1770,9 @@ video {
border-color: rgb(37 99 235 / var(--tw-border-opacity));
}
.focus\:border-stone-100:focus {
.focus\:border-stone-200:focus {
--tw-border-opacity: 1;
border-color: rgb(245 245 244 / var(--tw-border-opacity));
border-color: rgb(231 229 228 / var(--tw-border-opacity));
}
.focus\:bg-white:focus {
@@ -1784,16 +1780,16 @@ video {
background-color: rgb(255 255 255 / var(--tw-bg-opacity));
}
.focus\:bg-stone-200:focus {
--tw-bg-opacity: 1;
background-color: rgb(231 229 228 / var(--tw-bg-opacity));
}
.focus\:bg-stone-50:focus {
--tw-bg-opacity: 1;
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));

View File

@@ -5,12 +5,12 @@ const navigation = Vue.createApp({
<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="flex w-full my-px border-y border-stone-200 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>
<a class="flex-grow p-1 pl-3 hover:bg-teal-500 hover:text-stone-50 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 class="pl-2 pl-3 pl-4 pl-6 pl-8 pl-9 pl-10 pl-12 pl-15 text-stone-50"></div>
<navilevel :navigation="navigation" :expanded="expanded" />
</div>`,
data: function () {
return {
@@ -59,12 +59,28 @@ const navigation = Vue.createApp({
expandNavigation()
{
this.expanded = this.getFolderNames(this.navigation, []);
localStorage.setItem("expanded", this.expanded.toString());
localStorage.setItem("expanded", this.expanded.toString());
},
collapseNavigation()
{
this.expanded = [];
localStorage.removeItem('expanded');
this.expanded = this.getActiveNames(this.navigation, []);
localStorage.setItem("expanded", this.expanded.toString());
},
getActiveNames(navigation, expanded)
{
for (const item of navigation)
{
if(item.activeParent || item.active)
{
expanded.push(item.name);
}
if (item.elementType == 'folder')
{
this.getActiveNames(item.folderContent, expanded);
}
}
return expanded;
},
getFolderNames(navigation, result)
{
@@ -97,10 +113,11 @@ navigation.component('navilevel',{
:component-data="{
id: parentId ? parentId : false
}"
:expanded="expanded"
>
<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="flex w-full my-px border-b border-stone-200 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 }}
@@ -120,34 +137,28 @@ navigation.component('navilevel',{
</svg>
</div>
</div>
<navilevel v-show="isExpanded(element.name)" v-if="element.elementType == 'folder'" :list="element.folderContent" :navigation="element.folderContent" :parentId="element.keyPath" />
<navilevel v-show="isExpanded(element.name)" v-if="element.elementType == 'folder'" :list="element.folderContent" :navigation="element.folderContent" :parentId="element.keyPath" :expanded="expanded" />
</li>
</template>
<template #footer>
<li>
<div class="flex w-full mb-1 group">
<div class="flex w-full my-px border-b border-stone-200 hover:bg-stone-200 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">
<input :class="getNaviInputLevel(parentId)" class="w-full p-1 bg-transparent border-0 border-stone-100 hover:border-stone-200 focus:border-stone-200 focus:bg-stone-200 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">
<button title="add a file" @click="addItem('file', parentId)" class="text-stone-500 bg-transparent hover:text-stone-100 hover:bg-stone-700 p-1 border-0 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">
<button title="add a folder" @click="addItem('folder', parentId)" class="text-stone-500 bg-transparent hover:text-stone-100 hover:bg-stone-700 p-1 border-0 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>
@@ -160,6 +171,10 @@ navigation.component('navilevel',{
},
parentId: {
default: 'root'
},
expanded: {
type: Array,
required: false
}
},
data: function () {
@@ -194,13 +209,35 @@ navigation.component('navilevel',{
{
getNaviClass(active, activeParent, keyPathArray)
{
var naviclass = 'pl-' + (keyPathArray.length * 2);
var level = 3;
if(keyPathArray.length > 1)
{
var level = keyPathArray.length * 3; // 3, 6, 9, 12, 15
}
let naviclass = 'pl-' + level;
this.navilevel = naviclass;
if(active){ naviclass += " active" }
if(activeParent){ naviclass += " activeParent" }
if(activeParent)
{
naviclass += " activeParent";
}
else if(active)
{
naviclass += " text-stone-50 bg-teal-500";
}
return naviclass;
},
getNaviInputLevel(keyPathArray)
{
var level = 3;
var levelString = String(keyPathArray);
if(levelString != "root")
{
var levelArray = levelString.split(".");
var level = (levelArray.length + 1) * 3; // 3, 6, 9, 12, 15
}
return 'pl-' + level;
},
getUrl(segment)
{
return tmaxios.defaults.baseURL + '/tm/content/visual' + segment;
@@ -211,7 +248,7 @@ navigation.component('navilevel',{
},
isExpanded(name)
{
if(this.$root.expanded.indexOf(name) > -1)
if(this.expanded.indexOf(name) > -1)
{
return true;
}
@@ -317,7 +354,7 @@ navigation.component('navilevel',{
}
if(response.data.navigation)
{
self.items = response.data.navigation;
self.$root.$data.navigation = response.data.navigation;
self.newItem = '';
}
})
@@ -332,304 +369,4 @@ navigation.component('navilevel',{
},
});
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');
*/
navigation.mount('#contentNavigation');