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

V2.4.0 Refactor cached navigation to improve performance

This commit is contained in:
trendschau
2024-04-14 21:25:36 +02:00
parent f1212164b7
commit a4c32dd4d7
19 changed files with 756 additions and 483 deletions

View File

@@ -1,6 +1,6 @@
# Setup Your Website
Typemill provides detailed settings, and you have access to nearly all settings in the author panel. Learn the basics in this short video: mod
Typemill provides detailed settings, and you have access to nearly all settings in the author panel. Learn the basics in this short video:
![youtube-video](media/live/youtube-7yvlwxjl9dc.jpeg "click to load video"){#7yvlwXJL9dc .youtube}

View File

@@ -3,10 +3,10 @@ meta:
title: 'Setup your website'
description: ' You will find all configurations and settings under the main navigation point settings with the following sub-navigation:'
owner: Sebastian
manualdate: '2023-11-22'
author: Sebastian
manualdate: '2024-11-04'
modified: '2023-10-23'
created: '2023-06-12'
time: 15-18-48
hide: false
noindex: false
author: Sebastian

View File

@@ -29,6 +29,9 @@ Headlines are simply done with hash chars like this:
### Third Level Headline
A third headline is more decent and lower prioritized than a second level headline.
@@ -57,6 +60,9 @@ A paragraph is a simple text-block separated with a new line above and below.
A paragraph is a simple text-block separated with a new line above and below.
## Soft Linebreak
@@ -73,6 +79,9 @@ He said: "again"
For a soft linebreak (eg. for dialoges in literature), add two spaces at the end of a line and use a simple return.
She said: "Hello"
@@ -91,6 +100,9 @@ For bold text use two **asterix** or two __underscores__.
For italic text use one *asterix* or one _underscore_.
For bold text use two **asterix** or two __underscores__.
@@ -115,6 +127,9 @@ For an ordered list use whatever number you want and add a dot:
For an unordered list use a dash
* like
@@ -143,6 +158,9 @@ Easily created for example with three dashes like this:
Easily created for example with three dashes like this:
---
@@ -163,6 +181,9 @@ You can even use a download-link like []()
This is an ordinary [Link](http://typemill.net).
Links can also be [relative](/info).
@@ -194,6 +215,9 @@ The same rules as with links, but with a !
The same rules as with links, but with a !
![](media/tmp/kai-dahms-v0nbnxlwjzk-3unsp-1.webp)
@@ -216,6 +240,9 @@ You can link an image with a nested syntax like this:
You can link an image with a nested syntax like this:
[![alt-text](media/files/markdown.png){.imgClass}](https://typemill.net)
@@ -238,6 +265,9 @@ You can controll the image position with the classes .left, .right and .middle l
![](media/tmp/kai-dahms-v0nbnxlwjzk-3unsp-1.webp)
The first image should float on the left side of this paragraph. This might not work with all themes. If you are a theme developer, please ensure that you support the image classes "left", "right" and "center". You can add these classes manually in the raw mode or you can assign them in the visual mode when you edit a picture (double click on it to open the dialog). Images in a separate line are rendered with the html5 elements `figure` and `figcapture`.
@@ -265,6 +295,9 @@ There are always some women and men with wise words
There always some women and men with wise words
> But I usually don't read them, to be honest.
@@ -285,6 +318,9 @@ Add the footnote text at the bottom of the page like this:
You can write footnotes[^1] with markdown.
Scroll down to the end of the page[^2] and look for the footnotes.
@@ -304,6 +340,9 @@ Footnotes won't work with the visual editor right now, so please use the raw mod
You won't see the abbreviation directly, but if you write HTML or W3C somewhere, then you can see the tooltip with the explanation.
*[HTML]: Hyper Text Markup Language
@@ -325,6 +364,9 @@ Orange
Apple
: Pomaceous fruit of plants of the genus Malus in
the family Rosaceae.
@@ -363,6 +405,9 @@ You can create different notices if you add a '!', '!!', '!!!', '!!!!' before a
| Name | Usage |
|---|---|
| My Name | For Me |
@@ -380,6 +425,9 @@ Let us create some `<?php inlineCode(); ?>` like this
Let us create some `<?php inlineCode(); ?>` and now let us check, if a codeblock works:
````
@@ -398,6 +446,9 @@ Use four apostroph like this:
## Math
Please activate the math-plugin to use mathematical expressions with LaTeX syntax. You can choose between MathJax or the newer KaTeX library. MathJax is included from a CDN, KaTeX is included in the plugin. So if you don't want to fetch code from a CDN, use KaTeX instead. The markdown syntax in TYPEMILL is the same for both libraries.
@@ -414,6 +465,9 @@ inline \(x = \int_{0^1}^1(-b \pm \sqrt{b^2-4ac})/(2a)\) math
inline $x = \int_{0^1}^1(-b \pm \sqrt{b^2-4ac})/(2a)$ math
inline \(x = \int_{0^1}^1(-b \pm \sqrt{b^2-4ac})/(2a)\) math
@@ -434,6 +488,9 @@ x = \int_{0^1}^1(-b \pm \sqrt{b^2-4ac})/(2a)
$$
x = \int_{0^1}^1(-b \pm \sqrt{b^2-4ac})/(2a)
$$

View File

@@ -1,4 +1,4 @@
# Welcome
Great that you give Typemill a try!! Typemill is a simple Flat File Content Management System (CMS). We (the community) work hard to provide the best author experience with easy and intuitive authoring tools. But Typemill is still in early development and it is likely that not everything will work perfectly out of the box. If you miss something or if you have ideas for improvements, then post a new issue on [GitHub](https://github.com/typemill/typemill/issues).mb
Great that you give Typemill a try!! Typemill is a simple Flat File Content Management System (CMS). We (the community) work hard to provide the best author experience with easy and intuitive authoring tools. But Typemill is still in early development and it is likely that not everything will work perfectly out of the box. If you miss something or if you have ideas for improvements, then post a new issue on [GitHub](https://github.com/typemill/typemill/issues).

View File

@@ -0,0 +1,9 @@
meta:
navtitle: 'content elements'
owner: Sebastian
created: '2023-06-12'
time: 22-36-50
modified: '2021-11-24'
title: 'Cyanine provides a lot of other settings for your content area. For example:'
description: "\nAdd an edit-button for github, gitlab or other plattforms.\nShow the author.\nShow the publish date.\nShow the chapter numbers in the navigation.\n"
author: Sebastian

View File

@@ -1,6 +1,6 @@
# The Cyanine Theme
Cyanine is the modern, lightweight and flexible standard theme for Typemill. You can activate a landingpage, setup different content sections for the landingpage and order them like you want. You can also change the colors, fonts and other details. To configure the theme, login to the system (/tm/login), go to the theme settings (/tm/themes) and choose the theme "Cyanine".
Cyanine is the modern, lightweight and flexible standard theme for Typemill. You can activate a landingpage, setup different content sections for the landingpage and order them like you want. You can also change the colors, fonts and other details. To configure the theme, login to the system (/tm/login), go to the theme settings (/tm/themes) and choose the theme "Cyanine"
If Cyanine does not fit to your needs, then you can also choose another theme in the [theme store](https://themes.typemill.net) of Typemill.

File diff suppressed because one or more lines are too long

View File

@@ -1,66 +0,0 @@
/welcome:
navtitle: welcome
hide: false
noindex: false
path: /00-welcome
keyPath: 0
/welcome/setup-your-website:
navtitle: 'setup your website'
hide: false
noindex: false
path: /00-welcome/00-setup-your-website.md
keyPath: '0.0'
/welcome/write-content:
navtitle: 'write content'
hide: false
noindex: false
path: /00-welcome/01-write-content.md
keyPath: '0.1'
/welcome/manage-access:
navtitle: 'manage access'
hide: false
noindex: false
path: /00-welcome/02-manage-access.md
keyPath: '0.2'
/welcome/get-help:
navtitle: 'get help'
hide: false
noindex: false
path: /00-welcome/03-get-help.md
keyPath: '0.3'
/welcome/markdown-test:
navtitle: 'markdown test'
hide: false
noindex: false
path: /00-welcome/04-markdown-test.md
keyPath: '0.4'
/cyanine-theme:
navtitle: 'cyanine theme'
hide: false
noindex: false
path: /01-cyanine-theme
keyPath: 1
/cyanine-theme/landingpage:
navtitle: landingpage
hide: false
noindex: true
path: /01-cyanine-theme/00-landingpage.md
keyPath: '1.0'
/cyanine-theme/colors-and-fonts:
navtitle: 'colors and fonts'
hide: false
noindex: false
path: /01-cyanine-theme/01-colors-and-fonts.md
keyPath: '1.1'
/cyanine-theme/footer:
navtitle: footer
hide: false
noindex: false
path: /01-cyanine-theme/02-footer.md
keyPath: '1.2'
/cyanine-theme/content-elements:
navtitle: 'content elements'
hide: false
noindex: false
path: /01-cyanine-theme/03-content-elements.md
keyPath: '1.3'

View File

@@ -28,18 +28,6 @@ abstract class Controller
$this->c->get('dispatcher')->dispatch(new OnTwigLoaded(false), 'onTwigLoaded');
}
/*
public function getCsrfData($request)
{
$nameKey = $this->csrf->getTokenNameKey();
$valueKey = $this->csrf->getTokenValueKey();
return [
$nameKey => $request->getAttribute($nameKey),
$valueKey => $request->getAttribute($valueKey)
];
}
*/
protected function settingActive($setting)
{
if(isset($this->settings[$setting]) && $this->settings[$setting])
@@ -65,16 +53,23 @@ abstract class Controller
protected function getItem($navigation, $url, $urlinfo)
{
die('getItem in controller');
$url = $this->removeEditorFromUrl($url);
$langattr = $this->settings['langattr'];
if($url == '/')
{
$keyPathArray = [''];
return $navigation->getHomepageItem($urlinfo['baseurl']);
}
else
{
$langattr = $this->settings['langattr'];
# get the first level navigation
$firstLevel = $navigation->getExtendedNavigation($urlinfo, $langattr, '/');
$extendedNavigation = $navigation->getExtendedNavigation($urlinfo, $langattr);
$pageinfo = $extendedNavigation[$url] ?? false;
@@ -88,15 +83,46 @@ abstract class Controller
}
$draftNavigation = $navigation->getDraftNavigation($urlinfo, $langattr);
$draftNavigation = $navigation->getFullDraftNavigation($urlinfo, $langattr);
$item = $navigation->getItemWithKeyPath($draftNavigation, $keyPathArray, $urlinfo['basepath']);
return $item;
}
}
/*
protected function getFolderForItem($item)
{
if(count($item->keyPathArray) > 1)
{
$segments = explode('/', $item->path);
return $segments[1];
}
# it is a base-item
return '/';
}
*/
protected function getFolderForItem($item)
{
die('moved getFolderForItem from controller to navigation');
$segments = explode('/', $item->path);
# we always return base (parent) folder, so for base folder /myfolder the parent is '/'. Makes sure that base-level navigation in navigation cache is deleted
if(isset($segments[2]))
{
return $segments[1];
}
return 'navi-draft';
}
protected function removeEditorFromUrl($url)
{
die('moved removeEditorFromUrl from controller to navigation');
$url = trim($url, '/');
$url = str_replace('tm/content/visual', '', $url);
@@ -107,6 +133,8 @@ abstract class Controller
return '/' . $url;
}
protected function addDatasets(array $formDefinitions)
{
foreach($formDefinitions as $fieldname => $field)

View File

@@ -37,9 +37,10 @@ class ControllerApiAuthorArticle extends Controller
return $response->withHeader('Content-Type', 'application/json')->withStatus(400);
}
$navigation = new Navigation();
$urlinfo = $this->c->get('urlinfo');
$item = $this->getItem($navigation, $params['url'], $urlinfo);
$langattr = $this->settings['langattr'];
$navigation = new Navigation();
$item = $navigation->getItemForUrl($params['url'], $urlinfo, $langattr);
if(!$item)
{
$response->getBody()->write(json_encode([
@@ -78,14 +79,18 @@ class ControllerApiAuthorArticle extends Controller
return $response->withHeader('Content-Type', 'application/json')->withStatus(500);
}
# refresh navigation and item
$navigation->clearNavigation();
$draftNavigation = $navigation->getDraftNavigation($urlinfo, $this->settings['langattr']);
$naviFileName = $navigation->getNaviFileNameForPath($item->path);
$navigation->clearNavigation([$naviFileName]);
$draftNavigation = $navigation->getFullDraftNavigation($urlinfo, $this->settings['langattr']);
$draftNavigation = $navigation->setActiveNaviItemsWithKeyPath($draftNavigation, $item->keyPathArray);
$item = $navigation->getItemWithKeyPath($draftNavigation, $item->keyPathArray);
$sitemap = new Sitemap();
$sitemap->updateSitemap($draftNavigation, $urlinfo);
if(!isset($this->settings['disableSitemap']) OR !$this->settings['disableSitemap'])
{
$sitemap = new Sitemap();
$sitemap->updateSitemap($draftNavigation, $urlinfo);
}
# META is important e.g. for newsletter, so send it, too
$meta = new Meta();
@@ -130,9 +135,10 @@ class ControllerApiAuthorArticle extends Controller
return $response->withHeader('Content-Type', 'application/json')->withStatus(400);
}
$navigation = new Navigation();
$urlinfo = $this->c->get('urlinfo');
$item = $this->getItem($navigation, $params['url'], $urlinfo);
$langattr = $this->settings['langattr'];
$navigation = new Navigation();
$item = $navigation->getItemForUrl($params['url'], $urlinfo, $langattr);
if(!$item)
{
$response->getBody()->write(json_encode([
@@ -163,14 +169,18 @@ class ControllerApiAuthorArticle extends Controller
$draftMarkdown = $content->getDraftMarkdown($item);
$content->unpublishMarkdown($item, $draftMarkdown);
# refresh navigation and item
$navigation->clearNavigation();
$draftNavigation = $navigation->getDraftNavigation($urlinfo, $this->settings['langattr']);
$naviFileName = $navigation->getNaviFileNameForPath($item->path);
$navigation->clearNavigation([$naviFileName]);
$draftNavigation = $navigation->getFullDraftNavigation($urlinfo, $this->settings['langattr']);
$draftNavigation = $navigation->setActiveNaviItemsWithKeyPath($draftNavigation, $item->keyPathArray);
$item = $navigation->getItemWithKeyPath($draftNavigation, $item->keyPathArray);
$sitemap = new Sitemap();
$sitemap->updateSitemap($draftNavigation, $urlinfo);
if(!isset($this->settings['disableSitemap']) OR !$this->settings['disableSitemap'])
{
$sitemap = new Sitemap();
$sitemap->updateSitemap($draftNavigation, $urlinfo);
}
# check if it is a folder and if the folder has published pages.
$message = false;
@@ -213,9 +223,10 @@ class ControllerApiAuthorArticle extends Controller
return $response->withHeader('Content-Type', 'application/json')->withStatus(400);
}
$navigation = new Navigation();
$urlinfo = $this->c->get('urlinfo');
$item = $this->getItem($navigation, $params['url'], $urlinfo);
$langattr = $this->settings['langattr'];
$navigation = new Navigation();
$item = $navigation->getItemForUrl($params['url'], $urlinfo, $langattr);
if(!$item)
{
$response->getBody()->write(json_encode([
@@ -247,12 +258,13 @@ class ControllerApiAuthorArticle extends Controller
$markdownArray = $content->markdownTextToArray($markdown);
$content->saveDraftMarkdown($item, $markdownArray);
# refresh navigation and item
$navigation->clearNavigation();
$draftNavigation = $navigation->getDraftNavigation($urlinfo, $this->settings['langattr']);
$naviFileName = $navigation->getNaviFileNameForPath($item->path);
$navigation->clearNavigation([$naviFileName]);
$draftNavigation = $navigation->getFullDraftNavigation($urlinfo, $this->settings['langattr']);
$draftNavigation = $navigation->setActiveNaviItemsWithKeyPath($draftNavigation, $item->keyPathArray);
$item = $navigation->getItemWithKeyPath($draftNavigation, $item->keyPathArray);
# refresh content
$draftMarkdown = $content->getDraftMarkdown($item);
$draftMarkdownHtml = $content->addDraftHtml($draftMarkdown);
@@ -282,9 +294,10 @@ class ControllerApiAuthorArticle extends Controller
return $response->withHeader('Content-Type', 'application/json')->withStatus(400);
}
$navigation = new Navigation();
$urlinfo = $this->c->get('urlinfo');
$item = $this->getItem($navigation, $params['url'], $urlinfo);
$langattr = $this->settings['langattr'];
$navigation = new Navigation();
$item = $navigation->getItemForUrl($params['url'], $urlinfo, $langattr);
if(!$item)
{
$response->getBody()->write(json_encode([
@@ -316,14 +329,18 @@ class ControllerApiAuthorArticle extends Controller
$markdownArray = $content->markdownTextToArray($markdown);
$content->publishMarkdown($item, $markdownArray);
# refresh navigation and item
$navigation->clearNavigation();
$draftNavigation = $navigation->getDraftNavigation($urlinfo, $this->settings['langattr']);
$naviFileName = $navigation->getNaviFileNameForPath($item->path);
$navigation->clearNavigation([$naviFileName]);
$draftNavigation = $navigation->getFullDraftNavigation($urlinfo, $this->settings['langattr']);
$draftNavigation = $navigation->setActiveNaviItemsWithKeyPath($draftNavigation, $item->keyPathArray);
$item = $navigation->getItemWithKeyPath($draftNavigation, $item->keyPathArray);
$sitemap = new Sitemap();
$sitemap->updateSitemap($draftNavigation, $urlinfo);
if(!isset($this->settings['disableSitemap']) OR !$this->settings['disableSitemap'])
{
$sitemap = new Sitemap();
$sitemap->updateSitemap($draftNavigation, $urlinfo);
}
# refresh content
$draftMarkdown = $content->getDraftMarkdown($item);
@@ -368,9 +385,10 @@ class ControllerApiAuthorArticle extends Controller
return $response->withHeader('Content-Type', 'application/json')->withStatus(400);
}
$navigation = new Navigation();
$urlinfo = $this->c->get('urlinfo');
$item = $this->getItem($navigation, $params['url'], $urlinfo);
$langattr = $this->settings['langattr'];
$navigation = new Navigation();
$item = $navigation->getItemForUrl($params['url'], $urlinfo, $langattr);
if(!$item)
{
$response->getBody()->write(json_encode([
@@ -400,9 +418,10 @@ class ControllerApiAuthorArticle extends Controller
$content = new Content($urlinfo['baseurl'], $this->settings, $this->c->get('dispatcher'));
$content->deleteDraft($item);
# refresh navigation and item
$navigation->clearNavigation();
$draftNavigation = $navigation->getDraftNavigation($urlinfo, $this->settings['langattr']);
$naviFileName = $navigation->getNaviFileNameForPath($item->path);
$navigation->clearNavigation([$naviFileName]);
$draftNavigation = $navigation->getFullDraftNavigation($urlinfo, $this->settings['langattr']);
$draftNavigation = $navigation->setActiveNaviItemsWithKeyPath($draftNavigation, $item->keyPathArray);
$item = $navigation->getItemWithKeyPath($draftNavigation, $item->keyPathArray);
@@ -441,7 +460,7 @@ class ControllerApiAuthorArticle extends Controller
# get navigation
$navigation = new Navigation();
$draftNavigation = $navigation->getDraftNavigation($urlinfo, $langattr);
$draftNavigation = $navigation->getFullDraftNavigation($urlinfo, $langattr);
if($params['folder_id'] == 'root')
{
if($params['item_name'] == 'tm')
@@ -557,10 +576,15 @@ class ControllerApiAuthorArticle extends Controller
# $url = $urlinfo['baseurl'] . '/tm/content/' . $this->settings['editor'] . $folder->urlRelWoF . '/' . $slug;
}
$navigation->clearNavigation();
$itempath = $folderPath . DIRECTORY_SEPARATOR . $namePath;
$naviFileName = $navigation->getNaviFileNameForPath($itempath);
$navigation->clearNavigation([$naviFileName, $naviFileName . '-extended']);
$draftNavigation = $navigation->getFullDraftNavigation($urlinfo, $this->settings['langattr']);
$response->getBody()->write(json_encode([
'navigation' => $navigation->getDraftNavigation($urlinfo, $langattr),
'navigation' => $draftNavigation,
'message' => '',
'url' => false
]));
@@ -590,7 +614,7 @@ class ControllerApiAuthorArticle extends Controller
# get navigation
$navigation = new Navigation();
$draftNavigation = $navigation->getDraftNavigation($urlinfo, $langattr);
$draftNavigation = $navigation->getFullDraftNavigation($urlinfo, $langattr);
if($params['folder_id'] == 'root')
{
$folderContent = $draftNavigation;
@@ -669,9 +693,13 @@ class ControllerApiAuthorArticle extends Controller
return $response->withHeader('Content-Type', 'application/json')->withStatus(402);
}
$navigation->clearNavigation();
$draftNavigation = $navigation->getDraftNavigation($urlinfo, $langattr);
$item = $navigation->getItemWithKeyPath($draftNavigation, $folderKeyPath);
$itempath = $folderPath . DIRECTORY_SEPARATOR . $namePath;
$naviFileName = $navigation->getNaviFileNameForPath($itempath);
$navigation->clearNavigation([$naviFileName, $naviFileName . '-extended']);
$draftNavigation = $navigation->getFullDraftNavigation($urlinfo, $this->settings['langattr']);
$draftNavigation = $navigation->setActiveNaviItemsWithKeyPath($draftNavigation, $item->keyPathArray);
$item = $navigation->getItemWithKeyPath($draftNavigation, $item->keyPathArray);
$response->getBody()->write(json_encode([
'navigation' => $draftNavigation,
@@ -697,9 +725,10 @@ class ControllerApiAuthorArticle extends Controller
return $response->withHeader('Content-Type', 'application/json')->withStatus(400);
}
$navigation = new Navigation();
$urlinfo = $this->c->get('urlinfo');
$item = $this->getItem($navigation, $params['url'], $urlinfo);
$langattr = $this->settings['langattr'];
$navigation = new Navigation();
$item = $navigation->getItemForUrl($params['url'], $urlinfo, $langattr);
if(!$item)
{
$response->getBody()->write(json_encode([
@@ -730,11 +759,11 @@ class ControllerApiAuthorArticle extends Controller
if($parentUrl == '/')
{
$parentItem = new \stdClass;
$parentItem->folderContent = $navigation->getDraftNavigation($urlinfo, $this->settings['langattr']);
$parentItem->folderContent = $navigation->getDraftNavigation($urlinfo, $this->settings['langattr'], '/');
}
else
{
$parentItem = $this->getItem($navigation, $parentUrl, $urlinfo);
$parentItem = $navigation->getItemForUrl($parentUrl, $urlinfo, $langattr);
}
foreach($parentItem->folderContent as $sibling)
@@ -750,11 +779,19 @@ class ControllerApiAuthorArticle extends Controller
}
$navigation->renameItem($item, $params['slug']);
$navigation->clearNavigation();
$draftNavigation = $navigation->getDraftNavigation($urlinfo, $this->settings['langattr']);
$sitemap = new Sitemap();
$sitemap->updateSitemap($draftNavigation, $urlinfo);
$naviFileName = $navigation->getNaviFileNameForPath($item->path);
$navigation->clearNavigation([$naviFileName, $naviFileName . '-extended']);
$draftNavigation = $navigation->getFullDraftNavigation($urlinfo, $this->settings['langattr']);
$draftNavigation = $navigation->setActiveNaviItemsWithKeyPath($draftNavigation, $item->keyPathArray);
$item = $navigation->getItemWithKeyPath($draftNavigation, $item->keyPathArray);
if(!isset($this->settings['disableSitemap']) OR !$this->settings['disableSitemap'])
{
$sitemap = new Sitemap();
$sitemap->updateSitemap($draftNavigation, $urlinfo);
}
# create the new url for redirects
$newUrlRel = str_replace($item->slug, $params['slug'], $item->urlRelWoF);
@@ -791,18 +828,15 @@ class ControllerApiAuthorArticle extends Controller
return $response->withHeader('Content-Type', 'application/json')->withStatus(400);
}
# set variables
$urlinfo = $this->c->get('urlinfo');
$langattr = $this->settings['langattr'] ?? 'en';
$itemKeyPath = explode('.', $params['item_id']);
$parentKeyFrom = explode('.', $params['parent_id_from']);
$parentKeyTo = explode('.', $params['parent_id_to']);
# get navigation
$navigation = new Navigation();
$draftNavigation = $navigation->getDraftNavigation($urlinfo, $langattr);
$item = $navigation->getItemWithKeyPath($draftNavigation, $itemKeyPath);
$urlinfo = $this->c->get('urlinfo');
$langattr = $this->settings['langattr'];
$navigation = new Navigation();
$item = $navigation->getItemForUrl($params['url'], $urlinfo, $langattr);
if(!$item)
{
$response->getBody()->write(json_encode([
@@ -826,8 +860,9 @@ class ControllerApiAuthorArticle extends Controller
return $response->withHeader('Content-Type', 'application/json')->withStatus(403);
}
}
}
/*
$extendedNavigation = $navigation->getExtendedNavigation($urlinfo, $langattr);
$pageinfo = $extendedNavigation[$params['url']] ?? false;
if(!$pageinfo)
@@ -838,6 +873,9 @@ class ControllerApiAuthorArticle extends Controller
return $response->withHeader('Content-Type', 'application/json')->withStatus(404);
}
*/
$draftNavigation = $navigation->getFullDraftNavigation($urlinfo, $langattr);
$clearFullNavi = true;
# if an item is moved to the first level
if($params['parent_id_to'] == '')
@@ -859,6 +897,10 @@ class ControllerApiAuthorArticle extends Controller
# if the item has been moved within the same folder
if($params['parent_id_from'] == $params['parent_id_to'])
{
# we do not have to generate the full navigation, only this part
$clearFullNavi = false;
$naviFileName = $navigation->getNaviFileNameForPath($item->path);
# get key of item
$itemKey = end($itemKeyPath);
reset($itemKeyPath);
@@ -902,11 +944,22 @@ class ControllerApiAuthorArticle extends Controller
}
# refresh navigation and item
$navigation->clearNavigation();
$draftNavigation = $navigation->getDraftNavigation($urlinfo, $langattr);
if($clearFullNavi)
{
$navigation->clearNavigation();
}
else
{
$navigation->clearNavigation([$naviFileName, $naviFileName . '-extended']);
}
$draftNavigation = $navigation->getFullDraftNavigation($urlinfo, $langattr);
$sitemap = new Sitemap();
$sitemap->updateSitemap($draftNavigation, $urlinfo);
# update the sitemap
if(!isset($this->settings['disableSitemap']) OR !$this->settings['disableSitemap'])
{
$sitemap = new Sitemap();
$sitemap->updateSitemap($draftNavigation, $urlinfo);
}
$this->c->get('dispatcher')->dispatch(new OnPageSorted($params), 'onPageSorted');
@@ -935,9 +988,10 @@ class ControllerApiAuthorArticle extends Controller
return $response->withHeader('Content-Type', 'application/json')->withStatus(400);
}
$navigation = new Navigation();
$urlinfo = $this->c->get('urlinfo');
$item = $this->getItem($navigation, $params['url'], $urlinfo);
$langattr = $this->settings['langattr'];
$navigation = new Navigation();
$item = $navigation->getItemForUrl($params['url'], $urlinfo, $langattr);
if(!$item)
{
$response->getBody()->write(json_encode([
@@ -992,12 +1046,16 @@ class ControllerApiAuthorArticle extends Controller
return $response->withHeader('Content-Type', 'application/json')->withStatus(500);
}
# refresh navigation
$navigation->clearNavigation();
$draftNavigation = $navigation->getDraftNavigation($urlinfo, $this->settings['langattr']);
$naviFileName = $navigation->getNaviFileNameForPath($item->path);
$navigation->clearNavigation([$naviFileName, $naviFileName . '-extended']);
$sitemap = new Sitemap();
$sitemap->updateSitemap($draftNavigation, $urlinfo);
$draftNavigation = $navigation->getFullDraftNavigation($urlinfo, $this->settings['langattr']);
if(!isset($this->settings['disableSitemap']) OR !$this->settings['disableSitemap'])
{
$sitemap = new Sitemap();
$sitemap->updateSitemap($draftNavigation, $urlinfo);
}
# check if it is a subfile or subfolder and set the redirect-url to the parent item
$url = $urlinfo['baseurl'] . '/tm/content/' . $this->settings['editor'];

View File

@@ -30,9 +30,10 @@ class ControllerApiAuthorBlock extends Controller
return $response->withHeader('Content-Type', 'application/json')->withStatus(400);
}
$navigation = new Navigation();
$urlinfo = $this->c->get('urlinfo');
$item = $this->getItem($navigation, $params['url'], $urlinfo);
$langattr = $this->settings['langattr'];
$navigation = new Navigation();
$item = $navigation->getItemForUrl($params['url'], $urlinfo, $langattr);
if(!$item)
{
$response->getBody()->write(json_encode([
@@ -100,12 +101,13 @@ class ControllerApiAuthorBlock extends Controller
# if it was published before, then we need to refresh the navigation
if($item->status == 'published')
{
$navigation->clearNavigation();
$naviFileName = $navigation->getNaviFileNameForPath($item->path);
$navigation->clearNavigation([$naviFileName]);
$draftNavigation = $navigation->getDraftNavigation($urlinfo, $this->settings['langattr']);
$draftNavigation = $navigation->getFullDraftNavigation($urlinfo, $this->settings['langattr']);
$draftNavigation = $navigation->setActiveNaviItemsWithKeyPath($draftNavigation, $item->keyPathArray);
$item = $navigation->getItemWithKeyPath($draftNavigation, $item->keyPathArray);
$response->getBody()->write(json_encode([
'content' => $draftMarkdownHtml,
'navigation' => $draftNavigation,
@@ -140,9 +142,10 @@ class ControllerApiAuthorBlock extends Controller
return $response->withHeader('Content-Type', 'application/json')->withStatus(400);
}
$navigation = new Navigation();
$urlinfo = $this->c->get('urlinfo');
$item = $this->getItem($navigation, $params['url'], $urlinfo);
$langattr = $this->settings['langattr'];
$navigation = new Navigation();
$item = $navigation->getItemForUrl($params['url'], $urlinfo, $langattr);
if(!$item)
{
$response->getBody()->write(json_encode([
@@ -199,9 +202,10 @@ class ControllerApiAuthorBlock extends Controller
# if it was published before, then we need to refresh the navigation
if($item->status == 'published')
{
$navigation->clearNavigation();
$naviFileName = $navigation->getNaviFileNameForPath($item->path);
$navigation->clearNavigation([$naviFileName]);
$draftNavigation = $navigation->getDraftNavigation($urlinfo, $this->settings['langattr']);
$draftNavigation = $navigation->getFullDraftNavigation($urlinfo, $this->settings['langattr']);
$draftNavigation = $navigation->setActiveNaviItemsWithKeyPath($draftNavigation, $item->keyPathArray);
$item = $navigation->getItemWithKeyPath($draftNavigation, $item->keyPathArray);
@@ -239,9 +243,10 @@ class ControllerApiAuthorBlock extends Controller
return $response->withHeader('Content-Type', 'application/json')->withStatus(400);
}
$navigation = new Navigation();
$urlinfo = $this->c->get('urlinfo');
$item = $this->getItem($navigation, $params['url'], $urlinfo);
$langattr = $this->settings['langattr'];
$navigation = new Navigation();
$item = $navigation->getItemForUrl($params['url'], $urlinfo, $langattr);
if(!$item)
{
$response->getBody()->write(json_encode([
@@ -311,9 +316,10 @@ class ControllerApiAuthorBlock extends Controller
# if it was published before, then we need to refresh the navigation
if($item->status == 'published')
{
$navigation->clearNavigation();
$naviFileName = $navigation->getNaviFileNameForPath($item->path);
$navigation->clearNavigation([$naviFileName]);
$draftNavigation = $navigation->getDraftNavigation($urlinfo, $this->settings['langattr']);
$draftNavigation = $navigation->getFullDraftNavigation($urlinfo, $this->settings['langattr']);
$draftNavigation = $navigation->setActiveNaviItemsWithKeyPath($draftNavigation, $item->keyPathArray);
$item = $navigation->getItemWithKeyPath($draftNavigation, $item->keyPathArray);
@@ -351,9 +357,10 @@ class ControllerApiAuthorBlock extends Controller
return $response->withHeader('Content-Type', 'application/json')->withStatus(400);
}
$navigation = new Navigation();
$urlinfo = $this->c->get('urlinfo');
$item = $this->getItem($navigation, $params['url'], $urlinfo);
$langattr = $this->settings['langattr'];
$navigation = new Navigation();
$item = $navigation->getItemForUrl($params['url'], $urlinfo, $langattr);
if(!$item)
{
$response->getBody()->write(json_encode([
@@ -414,9 +421,10 @@ class ControllerApiAuthorBlock extends Controller
# if it was published before, then we need to refresh the navigation
if($item->status == 'published')
{
$navigation->clearNavigation();
$naviFileName = $navigation->getNaviFileNameForPath($item->path);
$navigation->clearNavigation([$naviFileName]);
$draftNavigation = $navigation->getDraftNavigation($urlinfo, $this->settings['langattr']);
$draftNavigation = $navigation->getFullDraftNavigation($urlinfo, $this->settings['langattr']);
$draftNavigation = $navigation->setActiveNaviItemsWithKeyPath($draftNavigation, $item->keyPathArray);
$item = $navigation->getItemWithKeyPath($draftNavigation, $item->keyPathArray);

View File

@@ -17,9 +17,10 @@ class ControllerApiAuthorMeta extends Controller
{
$url = $request->getQueryParams()['url'] ?? false;
$navigation = new Navigation();
$urlinfo = $this->c->get('urlinfo');
$item = $this->getItem($navigation, $url, $urlinfo);
$langattr = $this->settings['langattr'];
$navigation = new Navigation();
$item = $navigation->getItemForUrl($url, $urlinfo, $langattr);
if(!$item)
{
$response->getBody()->write(json_encode([
@@ -125,9 +126,10 @@ class ControllerApiAuthorMeta extends Controller
return $response->withHeader('Content-Type', 'application/json')->withStatus(400);
}
$navigation = new Navigation();
$urlinfo = $this->c->get('urlinfo');
$item = $this->getItem($navigation, $params['url'], $urlinfo);
$langattr = $this->settings['langattr'];
$navigation = new Navigation();
$item = $navigation->getItemForUrl($params['url'], $urlinfo, $langattr);
if(!$item)
{
$response->getBody()->write(json_encode([
@@ -193,47 +195,11 @@ class ControllerApiAuthorMeta extends Controller
return $response->withHeader('Content-Type', 'application/json')->withStatus(400);
}
/*
$errors = [];
# take the user input data and iterate over all fields and values
foreach($params['data'] as $fieldname => $fieldvalue)
{
# get the corresponding field definition from original plugin settings
$fielddefinition = $tabdefinitions[$fieldname] ?? false;
if(!$fielddefinition)
{
$errors[$tab][$fieldname] = Translations::translate('This field is not defined');
}
else
{
# validate user input for this field
$result = $validate->field($fieldname, $fieldvalue, $fielddefinition);
if($result !== true)
{
$errors[$params['tab']][$fieldname] = $result[$fieldname][0];
}
}
}
# return validation errors
if(!empty($errors))
{
$response->getBody()->write(json_encode([
'message' => Translations::translate('Please correct your input.'),
'errors' => $errors
]));
return $response->withHeader('Content-Type', 'application/json')->withStatus(400);
}
*/
# extended
$navigation = new Navigation();
$extended = $navigation->getExtendedNavigation($urlinfo, $this->settings['langattr']);
$navigation = new Navigation();
$naviFileName = $navigation->getNaviFileNameForPath($item->path);
$extended = $navigation->getExtendedNavigation($urlinfo, $this->settings['langattr'], $naviFileName);
$draftNavigation = false;
$updateDraftNavi = false;
if($params['tab'] == 'meta')
{
@@ -262,11 +228,13 @@ class ControllerApiAuthorMeta extends Controller
$renameresults = $meta->renamePost($item->pathWithoutType, $newPathWithoutType);
$navigation->clearNavigation();
# make sure the whole navigation with base-navigation and folder-navigation is updated. Bad for performance but rare case
$navigation->clearNavigation();
# WE HAVE TO REGENERATE ITEM AND NAVIGATION
$draftNavigation = $navigation->getDraftNavigation($urlinfo, $this->settings['langattr']);
$item = $navigation->getItemWithKeyPath($draftNavigation, $item->keyPathArray);
# RECREATE ITEM AND NAVIGATION, because we rename filename first and later update the meta-content
$draftNavigation = $navigation->getFullDraftNavigation($urlinfo, $this->settings['langattr']);
$draftNavigation = $navigation->setActiveNaviItemsWithKeyPath($draftNavigation, $item->keyPathArray);
$item = $navigation->getItemWithKeyPath($draftNavigation, $item->keyPathArray);
}
}
@@ -300,7 +268,17 @@ class ControllerApiAuthorMeta extends Controller
return $response->withHeader('Content-Type', 'application/json')->withStatus(500);
}
$navigation->clearNavigation();
# this will only update the basic draft navigation but we also have to update the folder navigation
# $navigation->clearNavigation([$naviFileName, $naviFileName. "-extened"]);
# other solution:
# $fakeFolderpath = $item->getPath;
# $fakeFolderpath .= '/getMyParent';
# $naviFolderName = $navigation->getNaviFileNameForPath($fakeFolderPath);
# $navigation->clearNavigation([$naviFolderName, $naviFolderName. "-extened"]);
# clear the whole navigation to make sure that folder navigation is recreated correctly
$navigation->clearNavigation();
$updateDraftNavi = true;
}
# normalize the meta-input
@@ -315,7 +293,8 @@ class ControllerApiAuthorMeta extends Controller
&& isset($extended[$item->urlRelWoF])
)
{
$navigation->clearNavigation();
$navigation->clearNavigation([$naviFileName, $naviFileName . '-extended']);
$updateDraftNavi = true;
}
elseif(
# check if navtitle or hide-value has been changed
@@ -326,10 +305,11 @@ class ControllerApiAuthorMeta extends Controller
($this->hasChanged($params['data'], $metadata['meta'], 'noindex'))
)
{
$navigation->clearNavigation();
$navigation->clearNavigation([$naviFileName, $naviFileName . '-extended']);
$updateDraftNavi = true;
}
}
# add the new/edited metadata
$metadata[$params['tab']] = $validated['data'];
@@ -338,9 +318,12 @@ class ControllerApiAuthorMeta extends Controller
if($store === true)
{
$draftNavigation = $navigation->getDraftNavigation($urlinfo, $this->settings['langattr']);
$draftNavigation = $navigation->setActiveNaviItemsWithKeyPath($draftNavigation, $item->keyPathArray);
$item = $navigation->getItemWithKeyPath($draftNavigation, $item->keyPathArray);
if($updateDraftNavi)
{
$draftNavigation = $navigation->getFullDraftNavigation($urlinfo, $this->settings['langattr']);
$draftNavigation = $navigation->setActiveNaviItemsWithKeyPath($draftNavigation, $item->keyPathArray);
$item = $navigation->getItemWithKeyPath($draftNavigation, $item->keyPathArray);
}
$response->getBody()->write(json_encode([
'navigation' => $draftNavigation,

View File

@@ -24,7 +24,7 @@ class ControllerWebAuthor extends Controller
$langattr = $this->settings['langattr'];
$navigation = new Navigation();
$draftNavigation = $navigation->getDraftNavigation($urlinfo, $langattr);
$draftNavigation = $navigation->getFullDraftNavigation($urlinfo, $langattr);
$home = $navigation->getHomepageItem($urlinfo['baseurl']);
if($url == '/')
@@ -34,9 +34,7 @@ class ControllerWebAuthor extends Controller
}
else
{
$extendedNavigation = $navigation->getExtendedNavigation($urlinfo, $langattr);
$pageinfo = $extendedNavigation[$url] ?? false;
$pageinfo = $navigation->getPageInfoForUrl($url, $urlinfo, $langattr);
if(!$pageinfo)
{
return $this->c->get('view')->render($response->withStatus(404), '404.twig', [
@@ -47,9 +45,6 @@ class ControllerWebAuthor extends Controller
$keyPathArray = explode(".", $pageinfo['keyPath']);
# extend : $request->getAttribute('c_userrole')
# $draftNavigation = $navigation->getDraftNavigation($urlinfo, $langattr);
$draftNavigation = $navigation->setActiveNaviItemsWithKeyPath($draftNavigation, $keyPathArray);
$draftNavigation = $this->c->get('dispatcher')->dispatch(new OnPagetreeLoaded($draftNavigation), 'onPagetreeLoaded')->getData();
@@ -95,7 +90,7 @@ class ControllerWebAuthor extends Controller
$langattr = $this->settings['langattr'];
$navigation = new Navigation();
$draftNavigation = $navigation->getDraftNavigation($urlinfo, $langattr);
$draftNavigation = $navigation->getFullDraftNavigation($urlinfo, $langattr);
$home = $navigation->getHomepageItem($urlinfo['baseurl']);
if($url == '/')
@@ -105,9 +100,7 @@ class ControllerWebAuthor extends Controller
}
else
{
$extendedNavigation = $navigation->getExtendedNavigation($urlinfo, $langattr);
$pageinfo = $extendedNavigation[$url] ?? false;
$pageinfo = $navigation->getPageInfoForUrl($url, $urlinfo, $langattr);
if(!$pageinfo)
{
return $this->c->get('view')->render($response->withStatus(404), '404.twig', [
@@ -119,7 +112,6 @@ class ControllerWebAuthor extends Controller
$keyPathArray = explode(".", $pageinfo['keyPath']);
# extend : $request->getAttribute('c_userrole')
$draftNavigation = $navigation->getDraftNavigation($urlinfo, $langattr);
$draftNavigation = $navigation->setActiveNaviItemsWithKeyPath($draftNavigation, $keyPathArray);
$draftNavigation = $this->c->get('dispatcher')->dispatch(new OnPagetreeLoaded($draftNavigation), 'onPagetreeLoaded')->getData();

View File

@@ -31,7 +31,7 @@ class ControllerWebFrontend extends Controller
# GET THE NAVIGATION
$navigation = new Navigation();
$draftNavigation = $navigation->getDraftNavigation($urlinfo, $langattr);
$draftNavigation = $navigation->getFullDraftNavigation($urlinfo, $langattr);
$home = false;
# GET THE PAGINATION
@@ -52,9 +52,8 @@ class ControllerWebFrontend extends Controller
}
else
{
$extendedNavigation = $navigation->getExtendedNavigation($urlinfo, $langattr);
$pageinfo = $extendedNavigation[$url] ?? false;
$pageinfo = $navigation->getPageInfoForUrl($url, $urlinfo, $langattr);
if(!$pageinfo)
{
@@ -96,14 +95,12 @@ class ControllerWebFrontend extends Controller
}
}
# GET THE LIVE NAVIGATION (keyPathArray does not match here!!!)
$liveNavigation = $navigation->getLiveNavigation($urlinfo, $langattr);
$liveNavigation = $navigation->generateLiveNavigationFromDraft($draftNavigation);
# STRIP OUT HIDDEN PAGES
$liveNavigation = $navigation->removeHiddenPages($liveNavigation);
# SET PAGEs ACTIVE
# $liveNavigation = $navigation->setActiveNaviItems($liveNavigation, $breadcrumb);
$liveNavigation = $navigation->setActiveNaviItemsWithKeyPath($liveNavigation, $item->keyPathArray);
# DISPATCH LIVE NAVIGATION

View File

@@ -6,40 +6,13 @@ use \URLify;
class Folder
{
/*
* scans content of a folder (without recursion)
* vars: folder path as string
* returns: one-dimensional array with names of folders and files
*/
public function scanFolderFlat($folderPath)
{
$folderItems = scandir($folderPath);
$folderContent = array();
foreach ($folderItems as $key => $item)
{
if (!in_array($item, array(".","..")))
{
$nameParts = $this->getStringParts($item);
$fileType = array_pop($nameParts);
if($fileType == 'md' OR $fileType == 'txt' )
{
$folderContent[] = $item;
}
}
}
return $folderContent;
}
/*
* scans content of a folder recursively
* vars: folder path as string
* $folderPath as string
* $flat true scans no subfolder or string scans only subfolder with that string
* returns: multi-dimensional array with names of folders and files
*/
public function scanFolder($folderPath)
public function scanFolder($folderPath, $flat = NULL)
{
$folderItems = scandir($folderPath);
$folderContent = array();
@@ -50,11 +23,32 @@ class Folder
{
if (is_dir($folderPath . DIRECTORY_SEPARATOR . $item))
{
if($flat)
{
if($flat === $item)
{
$folderContent[$item] = $this->scanFolder($folderPath . DIRECTORY_SEPARATOR . $item);
}
else
{
# We need to include the index.txt or index.md for the folder
$index = 'index.';
if( file_exists($folderPath . DIRECTORY_SEPARATOR . $item . DIRECTORY_SEPARATOR . 'index.txt') )
{
$index .= 'txt';
}
if( file_exists($folderPath . DIRECTORY_SEPARATOR . $item . DIRECTORY_SEPARATOR . 'index.md') )
{
$index .= 'md';
}
$subFolder = $item;
$folderPublished = file_exists($folderPath . DIRECTORY_SEPARATOR . $item . DIRECTORY_SEPARATOR . 'index.md');
$folderContent[$subFolder] = $this->scanFolder($folderPath . DIRECTORY_SEPARATOR . $subFolder);
$folderContent[$item] = [$index];
}
}
else
{
$folderContent[$item] = $this->scanFolder($folderPath . DIRECTORY_SEPARATOR . $item);
}
}
else
{
@@ -105,6 +99,7 @@ class Folder
$nameParts = $this->getStringParts($key);
$fileType = '';
$status = 'undefined';
if(in_array('index.md', $name))
{
$fileType = 'md';
@@ -150,7 +145,12 @@ class Folder
rsort($name);
}
$item->folderContent = $this->getFolderContentDetails($name, $language, $baseUrl, $item->urlRel, $item->urlRelWoF, $item->path, $item->keyPath, $item->chapter);
$item->folderContent = [];
if(!empty($name))
{
$item->folderContent = $this->getFolderContentDetails($name, $language, $baseUrl, $item->urlRel, $item->urlRelWoF, $item->path, $item->keyPath, $item->chapter);
}
}
elseif($name)
{
@@ -209,7 +209,7 @@ class Folder
public function getFolderContentType($folder, $yamlpath)
{
# check if folder is empty or has only index.yaml-file. This is a rare case so make it quick and dirty
if(count($folder) == 1)
if(count($folder) <= 1)
{
# check if in folder yaml file contains "posts", then return posts
$folderyamlpath = getcwd() . DIRECTORY_SEPARATOR . 'content' . DIRECTORY_SEPARATOR . $yamlpath;

View File

@@ -12,23 +12,9 @@ class Navigation extends Folder
private $naviFolder;
private $liveNaviName;
private $draftNaviName;
private $extendedNaviName;
private $extendedNavigation = false;
private $draftNavigation = false;
private $basicDraftNavigation = false;
private $liveNavigation = false;
private $basicLiveNavigation = false;
public $activeNavigation = false;
private $DS;
public function __construct()
{
@@ -36,42 +22,9 @@ class Navigation extends Folder
$this->naviFolder = 'navigation';
$this->liveNaviName = 'navi-live.txt';
$this->draftNaviName = 'draft-navi';
$this->draftNaviName = 'navi-draft.txt';
$this->extendedNaviName = 'navi-extended.txt';
}
# use array ['extended' => true, 'draft' => true, 'live' => true] to clear files
public function clearNavigation(array $deleteitems = NULL )
{
$result = false;
# clear cache
$this->extendedNavigation = false;
$this->draftNavigation = false;
$this->basicDraftNavigation = false;
$this->liveNavigation = false;
$this->basicLiveNavigation = false;
$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('dataFolder', $this->naviFolder, $navifile);
}
return $result;
$this->DS = DIRECTORY_SEPARATOR;
}
public function getMainNavigation($userrole, $acl, $urlinfo, $editor)
@@ -148,85 +101,278 @@ class Navigation extends Folder
return $allowedsystemnavi;
}
# get the navigation with draft files for author environment
public function getDraftNavigation($urlinfo, $language, $userrole = null, $username = null)
# use array ['extended' => true, 'draft' => true, 'live' => true] to clear files
public function clearNavigation($deleteItems = NULL)
{
# todo: filter for userrole or username
$result = false;
$this->draftNavigation = $this->storage->getFile('dataFolder', $this->naviFolder, $this->draftNaviName, 'unserialize');
$dataPath = $this->storage->getFolderPath('dataFolder');
$naviPath = $dataPath . DIRECTORY_SEPARATOR . $this->naviFolder;
$naviFiles = scandir($naviPath);
if($this->draftNavigation)
if($deleteItems)
{
return $this->draftNavigation;
# replace the placeholder '/' for a base-item with the cached base navigation
foreach ($deleteItems as &$value)
{
if ($value === '/')
{
$value = $this->draftNaviName;
}
else
{
$value .= '.txt';
}
}
$naviFiles = array_intersect($naviFiles, $deleteItems);
}
# if there is no cached navi, create a basic new draft navi
$basicDraftNavigation = $this->getBasicDraftNavigation($urlinfo, $language);
foreach($naviFiles as $naviFile)
{
if (!in_array($naviFile, array(".","..")) && substr($naviFile, 0, 1) != '.')
{
$result = $this->storage->deleteFile('dataFolder', $this->naviFolder, $naviFile);
}
}
# get the extended navigation with additional infos from the meta-files like title or hidden pages
$extendedNavigation = $this->getExtendedNavigation($urlinfo, $language);
return $result;
}
# merge the basic draft navi with the extended infos from meta-files
$draftNavigation = $this->mergeNavigationWithExtended($basicDraftNavigation, $extendedNavigation);
# cache it
$this->storage->writeFile('dataFolder', $this->naviFolder, $this->draftNaviName, $draftNavigation, 'serialize');
public function getItemForUrl($url, $urlinfo, $langattr)
{
$url = $this->removeEditorFromUrl($url);
if($url == '/')
{
return $this->getHomepageItem($urlinfo['baseurl']);
}
$pageinfo = $this->getPageInfoForUrl($url, $urlinfo, $langattr);
if(!$pageinfo)
{
return false;
}
$foldername = $this->getFirstUrlSegment($pageinfo['path']);
$draftNavigation = $this->getDraftNavigation($urlinfo, $langattr, $foldername);
if(!$draftNavigation)
{
return false;
}
$keyPathArray = explode(".", $pageinfo['keyPath']);
$item = $this->getItemWithKeyPath($draftNavigation, $keyPathArray);
return $item;
}
public function getPageInfoForUrl($url, $urlinfo, $langattr)
{
# get the first level navigation
$firstLevelExtended = $this->getExtendedNavigation($urlinfo, $langattr, '/');
$firstUrlSegment = $this->getFirstUrlSegment($url);
$firstUrlSegment = '/' . $firstUrlSegment;
$pageinfo = $firstLevelExtended[$firstUrlSegment] ?? false;
# first level does not exist
if(!$pageinfo)
{
return false;
}
# url is first level
if($url == $firstUrlSegment)
{
return $pageinfo;
}
$foldername = trim($pageinfo['path'], $this->DS);
$extendedNavigation = $this->getExtendedNavigation($urlinfo, $langattr, $foldername);
$pageinfo = $extendedNavigation[$url] ?? false;
if(!$pageinfo)
{
return false;
}
return $pageinfo;
}
private function removeEditorFromUrl($url)
{
$url = trim($url, '/');
$url = str_replace('tm/content/visual', '', $url);
$url = str_replace('tm/content/raw', '', $url);
$url = trim($url, '/');
return '/' . $url;
}
public function getFirstUrlSegment($url)
{
$segments = explode('/', $url);
if(isset($segments[1]))
{
return $segments[1];
}
return '';
}
public function getNaviFileNameForPath($path)
{
$segments = explode($this->DS, $path);
# navi-file-name for a base-folder is draftNaviName where first level items are cached.
if(isset($segments[2]))
{
return $segments[1];
}
return $this->draftNaviName;
}
public function getLiveNavigation($urlinfo, $langattr)
{
$draftNavigation = $this->getFullDraftNavigation($urlinfo, $langattr);
$liveNavigation = $this->generateLiveNavigationFromDraft($draftNavigation);
$liveNavigation = $this->removeHiddenPages($liveNavigation);
return $liveNavigation;
}
# ASK FOR THE FULL DRAFT NAVIGATION AND MERGE ALL SEPARATED NAVIGATIONS
public function getFullDraftNavigation($urlinfo, $language, $userrole = null, $username = null)
{
# get first level
$draftNavigation = $this->getDraftNavigation($urlinfo, $language, '/');
foreach($draftNavigation as $key => $item)
{
if($item->elementType == 'folder')
{
$subfolder = $this->getDraftNavigation($urlinfo, $language, $item->originalName);
$draftNavigation[$key]->folderContent = $subfolder[$key]->folderContent;
}
}
return $draftNavigation;
}
public function getBasicDraftNavigation($urlinfo, $language)
# ASK FOR A STATIC DRAFT NAVIGATION AND CREATE ONE IF NOT THERE
public function getDraftNavigation($urlinfo, $language, $foldername)
{
if(!$this->basicDraftNavigation)
{
$this->basicDraftNavigation = $this->createBasicDraftNavigation($urlinfo, $language);
}
return $this->basicDraftNavigation;
}
$draftFileName = $this->getDraftFileName($foldername);
$extendedFileName = $this->getExtendedFileName($foldername);
# creates a fresh structure with published and non-published pages for the author
public function createBasicDraftNavigation($urlinfo, $language)
{
# scan the content of the folder
$draftContentTree = $this->scanFolder($this->storage->getFolderPath('contentFolder'), $draft = true);
$draftNavigation = $this->getDraftNavigationFile($draftFileName);
# if there is content, then get the content details
if(count($draftContentTree) > 0)
if($draftNavigation)
{
$draftNavigation = $this->getFolderContentDetails($draftContentTree, $language, $urlinfo['baseurl'], $urlinfo['basepath']);
return $draftNavigation;
}
return false;
}
# get the navigation with draft files for author environment
public function getLiveNavigation($urlinfo, $language, $userrole = null, $username = null)
{
# todo: filter for userrole or username
$this->liveNavigation = $this->storage->getFile('dataFolder', $this->naviFolder, $this->liveNaviName, 'unserialize');
if($this->liveNavigation)
$rawDraftNavigation = $this->generateRawDraftNavigation($urlinfo, $language, $foldername);
if(!$rawDraftNavigation)
{
return $this->liveNavigation;
return false;
}
$draftNavigation = $this->getDraftNavigation($urlinfo, $language);
$extendedNavigation = $this->getExtendedNavigationFile($extendedFileName);
if(!$extendedNavigation)
{
$extendedNavigation = $this->generateExtendedFromDraft($rawDraftNavigation);
$basicLiveNavigation = $this->generateLiveNavigationFromDraft($draftNavigation);
if(!$extendedNavigation)
{
return false;
}
$this->storeStaticNavigation($extendedFileName, $extendedNavigation);
}
# get the extended navigation with additional infos from the meta-files like title or hidden pages
$extendedNavigation = $this->getExtendedNavigation($urlinfo, $language);
$draftNavigation = $this->mergeExtendedWithDraft($rawDraftNavigation, $extendedNavigation);
if(!$draftNavigation)
{
return false;
}
$this->storeStaticNavigation($draftFileName, $draftNavigation);
# merge the basic draft navi with the extended infos from meta-files
$liveNavigation = $this->mergeNavigationWithExtended($basicLiveNavigation, $extendedNavigation);
return $draftNavigation;
}
# cache it
$this->storage->writeFile('dataFolder', $this->naviFolder, $this->liveNaviName, $liveNavigation, 'serialize');
public function getExtendedNavigation($urlinfo, $language, $foldername)
{
$draftFileName = $this->getDraftFileName($foldername);
$extendedFileName = $this->getExtendedFileName($foldername);
return $liveNavigation;
$extendedNavigation = $this->getExtendedNavigationFile($extendedFileName);
if($extendedNavigation)
{
return $extendedNavigation;
}
$draftNavigation = $this->getDraftNavigationFile($draftFileName);
if(!$draftNavigation)
{
# we have to create and store extended and draft in this case
$rawDraftNavigation = $this->generateRawDraftNavigation($urlinfo, $language, $foldername);
if(!$rawDraftNavigation)
{
return false;
}
$extendedNavigation = $this->generateExtendedFromDraft($rawDraftNavigation);
if(!$extendedNavigation)
{
return false;
}
$this->storeStaticNavigation($extendedFileName, $extendedNavigation);
$draftNavigation = $this->mergeExtendedWithDraft($rawDraftNavigation, $extendedNavigation);
if(!$draftNavigation)
{
return false;
}
$this->storeStaticNavigation($draftFileName, $draftNavigation);
return $extendedNavigation;
}
# we only have to create and store extended in this case
$extendedNavigation = $this->generateExtendedFromDraft($draftNavigation);
if(!$extendedNavigation)
{
return false;
}
$this->storeStaticNavigation($extendedFileName, $extendedNavigation);
return $extendedNavigation;
}
public function generateLiveNavigationFromDraft($draftNavigation)
@@ -255,57 +401,69 @@ class Navigation extends Folder
return $draftNavigation;
}
/*
public function getBasicLiveNavigation($urlinfo, $language)
private function storeStaticNavigation($filename, $data)
{
if(!$this->basicLiveNavigation)
if($filename == '.txt' OR $filename == '-extended.txt')
{
$this->basicLiveNavigation = $this->createBasicLiveNavigation($urlinfo, $language);
return false;
}
return $this->basicLiveNavigation;
}
public function createBasicLiveNavigation($urlinfo, $language)
{
# scan the content of the folder
$liveContentTree = $this->scanFolder($this->storage->getFolderPath('contentFolder'), $draft = false);
# if there is content, then get the content details
if(count($liveContentTree) > 0)
if($this->storage->writeFile('dataFolder', $this->naviFolder, $filename, $data, 'serialize'))
{
$liveNavigation = $this->getFolderContentDetails($liveContentTree, $language, $urlinfo['baseurl'], $urlinfo['basepath']);
return $liveNavigation;
return true;
}
return false;
}
*/
# get the extended navigation with additional infos from the meta-files like title or hidden pages
public function getExtendedNavigation($urlinfo, $language)
# gets the cached draft navigation of a folder or of the first level
private function getDraftNavigationFile($filename)
{
if(!$this->extendedNavigation)
$draftNavigation = $this->storage->getFile('dataFolder', $this->naviFolder, $filename, 'unserialize');
if($draftNavigation)
{
# read the extended navi file
$this->extendedNavigation = $this->storage->getYaml('dataFolder', $this->naviFolder, $this->extendedNaviName);
return $draftNavigation;
}
if(!$this->extendedNavigation)
{
$basicDraftNavigation = $this->getBasicDraftNavigation($urlinfo, $language);
return false;
}
$this->extendedNavigation = $this->createExtendedNavigation($basicDraftNavigation, $extended = NULL);
# cache it
$this->storage->updateYaml('dataFolder', $this->naviFolder, $this->extendedNaviName, $this->extendedNavigation);
# generates a raw draft navigation
private function generateRawDraftNavigation($urlinfo, $language, $foldername = false)
{
# convert basefolder '/' to true
$flat = ($foldername == '/') ? true : $foldername;
# scan the content of the folder
$draftContentTree = $this->scanFolder($this->storage->getFolderPath('contentFolder'), $flat);
# if there is content, then get the content details
if(count($draftContentTree) > 0)
{
$draftNavigation = $this->getFolderContentDetails($draftContentTree, $language, $urlinfo['baseurl'], $urlinfo['basepath']);
return $draftNavigation;
}
return $this->extendedNavigation;
return false;
}
# get the extended Navigation file for a folder or base
private function getExtendedNavigationFile($filename)
{
$extendedNavigation = $this->storage->getFile('dataFolder', $this->naviFolder, $filename, 'unserialize');
if($extendedNavigation)
{
return $extendedNavigation;
}
return false;
}
# reads all meta-files and creates an array with url => ['hide' => bool, 'navtitle' => 'bla']
public function createExtendedNavigation($navigation, $extended = NULL)
private function generateExtendedFromDraft($navigation, $extended = NULL)
{
if(!$extended)
{
@@ -337,30 +495,30 @@ class Navigation extends Folder
if ($item->elementType == 'folder')
{
$extended = $this->createExtendedNavigation($item->folderContent, $extended);
$extended = $this->generateExtendedFromDraft($item->folderContent, $extended);
}
}
return $extended;
}
# merge a basic navigation (live or draft) with extended information from meta
public function mergeNavigationWithExtended($navigation, $extended)
# takes a draft navigation and extended navigation and merges both
private function mergeExtendedWithDraft($draftNavigation, $extendedNavigation)
{
$mergedNavigation = [];
foreach($navigation as $key => $item)
foreach($draftNavigation as $key => $item)
{
if($extended && isset($extended[$item->urlRelWoF]))
if($extendedNavigation && isset($extendedNavigation[$item->urlRelWoF]))
{
$item->name = ($extended[$item->urlRelWoF]['navtitle'] != '') ? $extended[$item->urlRelWoF]['navtitle'] : $item->name;
$item->hide = ($extended[$item->urlRelWoF]['hide'] === true) ? true : false;
$item->noindex = (isset($extended[$item->urlRelWoF]['noindex']) && $extended[$item->urlRelWoF]['noindex'] === true) ? true : false;
$item->name = ($extendedNavigation[$item->urlRelWoF]['navtitle'] != '') ? $extendedNavigation[$item->urlRelWoF]['navtitle'] : $item->name;
$item->hide = ($extendedNavigation[$item->urlRelWoF]['hide'] === true) ? true : false;
$item->noindex = (isset($extendedNavigation[$item->urlRelWoF]['noindex']) && $extendedNavigation[$item->urlRelWoF]['noindex'] === true) ? true : false;
}
if($item->elementType == 'folder')
{
$item->folderContent = $this->mergeNavigationWithExtended($item->folderContent, $extended);
$item->folderContent = $this->mergeExtendedWithDraft($item->folderContent, $extendedNavigation);
}
$mergedNavigation[$key] = $item;
@@ -369,6 +527,30 @@ class Navigation extends Folder
return $mergedNavigation;
}
protected function getDraftFileName($foldername)
{
$draftFileName = $foldername;
if($draftFileName == '/')
{
$draftFileName = $this->draftNaviName;
}
return $draftFileName . '.txt';
}
protected function getExtendedFileName($foldername)
{
$draftFileName = $foldername;
if($draftFileName == '/')
{
$draftFileName = $this->draftNaviName;
}
return $draftFileName . '-extended.txt';
}
public function getItemWithKeyPath($navigation, array $searchArray, $baseUrl = null)
{
$item = false;
@@ -393,64 +575,6 @@ class Navigation extends Folder
return $item;
}
# NOT IN USE ANYMORE BUT KEEP IT
public function getItemWithUrl($navigation, $url, $result = NULL)
{
foreach($navigation as $key => $item)
{
# set item active, needed to move item in navigation
if($item->urlRelWoF === $url)
{
$result = $item;
break;
}
elseif($item->elementType === "folder")
{
$result = self::getItemWithUrl($item->folderContent, $url, $result);
if($result)
{
break;
}
}
}
return $result;
}
# NOT IN USE ANYMORE BUT KEEP IT
public function setActiveNaviItems($navigation, $breadcrumb)
{
if($breadcrumb)
{
foreach($breadcrumb as $crumbkey => $page)
{
foreach($navigation as $itemkey => $item)
{
if($page->urlRelWoF == $item->urlRelWoF)
{
unset($breadcrumb[$crumbkey]);
if(empty($breadcrumb))
{
$navigation[$itemkey]->active = true;
}
elseif(isset($navigation[$itemkey]->folderContent))
{
$navigation[$itemkey]->activeParent = true;
$navigation[$itemkey]->folderContent = $this->setActiveNaviItems($navigation[$itemkey]->folderContent, $breadcrumb);
}
break;
}
}
}
}
return $navigation;
}
# used with scan folder that keeps index from draft version
public function setActiveNaviItemsWithKeyPath($navigation, array $searchArray)
{
@@ -681,8 +805,73 @@ class Navigation extends Folder
return $flat;
}
# NOT IN USE ANYMORE BUT KEEP IT
public function getItemWithUrl($navigation, $url, $result = NULL)
{
die('getItemWithURL in navigation model not in use.');
foreach($navigation as $key => $item)
{
# set item active, needed to move item in navigation
if($item->urlRelWoF === $url)
{
$result = $item;
break;
}
elseif($item->elementType === "folder")
{
$result = self::getItemWithUrl($item->folderContent, $url, $result);
if($result)
{
break;
}
}
}
return $result;
}
# NOT IN USE ANYMORE BUT KEEP IT
public function setActiveNaviItems($navigation, $breadcrumb)
{
die('setActiveNaviItems in navigation model not in use.');
if($breadcrumb)
{
foreach($breadcrumb as $crumbkey => $page)
{
foreach($navigation as $itemkey => $item)
{
if($page->urlRelWoF == $item->urlRelWoF)
{
unset($breadcrumb[$crumbkey]);
if(empty($breadcrumb))
{
$navigation[$itemkey]->active = true;
}
elseif(isset($navigation[$itemkey]->folderContent))
{
$navigation[$itemkey]->activeParent = true;
$navigation[$itemkey]->folderContent = $this->setActiveNaviItems($navigation[$itemkey]->folderContent, $breadcrumb);
}
break;
}
}
}
}
return $navigation;
}
# NOT IN USE ANYMORE
public function getLastItemOfFolder($folder)
{
die('getLastItemOfFolder in navimodel not in use.');
$lastItem = end($folder->folderContent);
if(is_object($lastItem) && $lastItem->elementType == 'folder' && !empty($lastItem->folderContent))
{

View File

@@ -66,6 +66,8 @@ const bloxeditor = Vue.createApp({
},
onEnd(evt)
{
self = this;
tmaxios.put('/api/v1/block/move',{
'url': data.urlinfo.route,
'index_old': evt.oldIndex,
@@ -74,12 +76,24 @@ const bloxeditor = Vue.createApp({
.then(function (response)
{
self.content = response.data.content;
if(response.data.navigation)
{
eventBus.$emit('navigation', response.data.navigation);
}
if(response.data.item)
{
eventBus.$emit('item', response.data.item);
}
})
.catch(function (error)
{
if(error.response)
{
eventBus.$emit('publishermessage', error.response.data.message);
let message = handleErrorMessage(error);
if(message)
{
eventBus.$emit('publishermessage', message);
}
}
});
},

View File

@@ -57,6 +57,11 @@ fieldsetsystem:
css: lg:w-half
disabled: true
description: 'Submit the url above in google search console to support indexing.'
disableSitemap:
type: checkbox
css: lg:w-half
label: 'Disable Sitemap Generation'
checkboxlabel: 'Disable Sitemap generation to improve the performance for publish action.'
fieldsetmedia:
type: fieldset
legend: Media