diff --git a/MANUAL.md b/MANUAL.md
index 7ca064e4..acbfa0a7 100644
--- a/MANUAL.md
+++ b/MANUAL.md
@@ -150,7 +150,7 @@ This panel is also usefull to set up a [page list](#page-list) to include the sa
The Deep Search bar help you to look for words or regular expressions in your pages.
-By default, searching only look in [title](#page-title), [description](#description) and [contents (markdown elements)](#markdown-elements), but the "other" checkbox will allow you to look up in [css](#css), [javascript](#javascript) and [BODY](#body) contents.
+By default, searching only look in [title](#page-title), [description](#description) and [contents (markdown elements)](#content-elements), but the "other" checkbox will allow you to look up in [css](#css), [javascript](#javascript) and [BODY](#body) contents.
Unlike the [filterings options](#options) below, searches can't be saved or used for [page lists](#page-list).
@@ -513,7 +513,7 @@ Where `` and `` are integers beetwen `1` to `6`.
You can set `` and `` values to filters beetwen `` and `` headlines to take care of.
-You can specify an [element](#markdown-elements) to target with the `element` parameter. The summary will only refer to this `element` headlines.
+You can specify an [element](#content-elements) to target with the `element` parameter. The summary will only refer to this `element` headlines.
@@ -534,7 +534,7 @@ It use the same logic as the page filters in the [home view](#home).
*For example, this will print all public pages sorted by creation date in descending order.*
-When you are in the [home view](#home), ajust the filters using the [options panel](#options) to achieve the page selection you desire. Then select "filters" in the [menu](#home-menu), choose options you prefer and hit "generate". You can now copy and paste the code obtainded that way in one of the [elements](#markdown-elements) of a page.
+When you are in the [home view](#home), ajust the filters using the [options panel](#options) to achieve the page selection you desire. Then select "filters" in the [menu](#home-menu), choose options you prefer and hit "generate". You can now copy and paste the code obtainded that way in one of the [elements](#content-elements) of a page.
Display options are :
@@ -594,7 +594,7 @@ This will include a `div` HTML tag and some javascript.
-When you are in the [home view](#home), ajust the filters using the [options panel](#options) to achieve the page selection you desire. Then select "filters" in the [menu](#home-menu), under the "map" title, you can now copy and paste the code obtainded that way in one of the [elements](#markdown-elements) of a page.
+When you are in the [home view](#home), ajust the filters using the [options panel](#options) to achieve the page selection you desire. Then select "filters" in the [menu](#home-menu), under the "map" title, you can now copy and paste the code obtainded that way in one of the [elements](#content-elements) of a page.
**⚠️ this feature is limited to one map per page**
@@ -675,15 +675,19 @@ The most common usage is tu use it as a link `href`. For example, with a publish
The BODY tab allow you to create more complex canvas for your pages.
-It use only HTML.
+It cannot interpret Markdown language, you have to use HTML. But still you can use all the W [inclusions codes](#inclusions).
+
+Depending on whitch page version you use, BODY synthax may be slightly different.
#### Element inclusion
-The main purpose of BODY, is to display [Markdown elements](#markdown-elements) of your page.
+The main purpose of BODY, is to display [contents](#content-elements) of your page.
%%
-Where `` can be `MAIN`, `HEADER`, `ASIDE`, `NAV` or `FOOTER`. This will invoke the selected element into your page's BODY.
+**In pages V1** `` can be `MAIN`, `HEADER`, `ASIDE`, `NAV` or `FOOTER`. This will invoke the selected element into your page's BODY.
+
+**In page V2** `` can only be `CONTENT`
#### External Element inclusion
@@ -691,24 +695,34 @@ Where `` can be `MAIN`, `HEADER`, `ASIDE`, `NAV` or `FOOTER`. This will
%?id=%
-Just specify the [ID](#page-id) of the page [elements](#markdown-elements) you want to include.
+Just specify the [ID](#page-id) of the page [elements](#content-elements) you want to include.
##### concatenate elements
-You can even concatenate differents pages [elements](#markdown-elements), using `+` symbol separating [pages IDs](#page-id). All contents of differents pages elements will be concatenated inside one element.
+
+|page versions |1 |2 |
+|---------------|---|---|
+|support |✔️ |❌ |
+
+**In pages V1**, ou can concatenate differents pages [elements](#content-elements), using `+` symbol separating [pages IDs](#page-id). All contents of differents pages elements will be concatenated inside one element.
%?id=++*%
Where `*` is the page ID of the rendered page.
-
+**In page V2** this is useless as you can simply repeat the simple inclusion syntax multiple times.
#### Rendering options
##### HTML tags
+
+|page versions |1 |2 |
+|---------------|---|---|
+|support |✔️ |❌ |
+
%?tag=(0|1)%
This will determine if HTML tags will be printed around included element. This may be usefull for advanced users to achieve more precise HTML editing.
@@ -723,6 +737,11 @@ This will include the content of the *nav* element of your page, but without any
##### Markdown disable
+
+|page versions |1 |2 |
+|---------------|---|---|
+|support |✔️ |✔️ |
+
%?mardown=(0|1)%
Activate or desactivate [markdonw](#markdown) parser in called ``. By default, Markdown is set to `1`.
@@ -730,6 +749,11 @@ Activate or desactivate [markdonw](#markdown) parser in called ``. By d
##### Header ID
+
+|page versions |1 |2 |
+|---------------|---|---|
+|support |✔️ |✔️ |
+
%?headerid=-%
By default, HTML `#id` are generated for every `
` to `
` headings. You can specify a range of headers outside which no ID will be added.
@@ -739,6 +763,11 @@ You can also set `headerid=0` to totaly disable ID generation for this element.
##### Anchor links in title
+
+|page versions |1 |2 |
+|---------------|---|---|
+|support |✔️ |✔️ |
+
%?headeranchor=(0|1|2)%
This render option is used to add automatic target link to title anchors.
@@ -750,12 +779,22 @@ This settings is deactivated by default.
##### URL linker
+
+|page versions |1 |2 |
+|---------------|---|---|
+|support |✔️ |✔️ |
+
%?urllinker=(0|1)%
URL Linker is a tool that will transform a plain text URL into a link. This can be enabled or disabled specificly for each elements. The default behavior can be set globaly in the [admin panel](#admin).
##### Everylink
+
+|page versions |1 |2 |
+|---------------|---|---|
+|support |✔️ |✔️ |
+
Everylink is an powerfull but surprising feature that will replace everything you type with links.
%?everylink=%
@@ -983,9 +1022,11 @@ This is not an editable metadata. It's a list of all pages that are linked from
#### Content
-##### markdown elements
+##### content elements
+
+**In pages V1**, there are 5 content elements : Main, Nav, Aside, Header, Footer.
-Main, Nav, Aside, Header, Footer
+**In pages V2**, there is only one content element called "content".
##### CSS
diff --git a/app/class/Application.php b/app/class/Application.php
index d50847eb..d698c2ff 100644
--- a/app/class/Application.php
+++ b/app/class/Application.php
@@ -122,6 +122,18 @@ protected function configform()
indicate the subfolder(s) in witch you installed the CMS
+
+
+ Page version
+
+
+ Select the page version you want to use. If you don't know what it means, keep version 2.
+
+
+
diff --git a/app/class/Config.php b/app/class/Config.php
index a7fc71cd..21963e9b 100644
--- a/app/class/Config.php
+++ b/app/class/Config.php
@@ -19,7 +19,8 @@ abstract class Config
protected static $privatepass = false;
protected static $notpublishedpass = false;
protected static $alertcss = false;
- protected static $defaultbody = "%HEADER%\n\n%NAV%\n\n%ASIDE%\n\n%MAIN%\n\n%FOOTER%";
+ protected static $defaultv1body = "%HEADER%\n\n%NAV%\n\n%ASIDE%\n\n%MAIN%\n\n%FOOTER%";
+ protected static $defaultv2body = "%CONTENT%";
protected static $defaultfavicon = '';
protected static $defaultthumbnail = '';
protected static string $suffix = "";
@@ -50,6 +51,9 @@ abstract class Config
/** @var string $lang Default string for pages */
protected static $lang = "en";
+ /** Page version during creation */
+ protected static int $pageversion = Page::V1;
+
public const LANG_MIN = 2;
public const LANG_MAX = 16;
@@ -75,12 +79,16 @@ public static function hydrate(array $datas)
}
}
- public static function readconfig()
+ public static function readconfig(): bool
{
if (file_exists(Model::CONFIG_FILE)) {
$current = file_get_contents(Model::CONFIG_FILE);
$datas = json_decode($current, true);
self::hydrate($datas);
+ // Setup old config file to user page version 1
+ if (isset($datas['pageaversion'])) {
+ self::$pageversion = Page::V1;
+ }
return true;
} else {
return false;
@@ -227,9 +235,23 @@ public static function alertcss()
return self::$alertcss;
}
- public static function defaultbody()
+ /**
+ * @return string Default BODY corrsponding to current Config's page version
+ */
+ public static function defaultbody(): string
+ {
+ $fn = 'defaultv' . self::$pageversion . 'body';
+ return self::$$fn;
+ }
+
+ public static function defaultv1body(): string
+ {
+ return self::$defaultv1body;
+ }
+
+ public static function defaultv2body(): string
{
- return self::$defaultbody;
+ return self::$defaultv2body;
}
public static function defaultfavicon()
@@ -322,6 +344,11 @@ public static function disablejavascript(): bool
return self::$disablejavascript;
}
+ public static function pageversion(): int
+ {
+ return self::$pageversion;
+ }
+
// __________________________________________ S E T ______________________________________
@@ -414,11 +441,31 @@ public static function setalertcss($alertcss)
self::$alertcss = boolval($alertcss);
}
+ /**
+ * Used to convert old Config version. Save
+ * `defaultbody` param as `defaultv1body`.
+ */
public static function setdefaultbody($defaultbody)
{
if (is_string($defaultbody)) {
$defaultbody = crlf2lf($defaultbody);
- self::$defaultbody = $defaultbody;
+ self::$defaultv1body = $defaultbody;
+ }
+ }
+
+ public static function setdefaultv1body($defaultbody)
+ {
+ if (is_string($defaultbody)) {
+ $defaultbody = crlf2lf($defaultbody);
+ self::$defaultv1body = $defaultbody;
+ }
+ }
+
+ public static function setdefaultv2body($defaultbody)
+ {
+ if (is_string($defaultbody)) {
+ $defaultbody = crlf2lf($defaultbody);
+ self::$defaultv2body = $defaultbody;
}
}
@@ -540,4 +587,11 @@ public static function setdisablejavascript($disablejavascript)
{
self::$disablejavascript = boolval($disablejavascript);
}
+
+ public static function setpageversion($pageversion): void
+ {
+ if (key_exists($pageversion, Page::VERSIONS)) {
+ self::$pageversion = $pageversion;
+ }
+ }
}
diff --git a/app/class/Controllerapipage.php b/app/class/Controllerapipage.php
index 463ea913..39359988 100644
--- a/app/class/Controllerapipage.php
+++ b/app/class/Controllerapipage.php
@@ -74,8 +74,7 @@ public function update(string $page)
}
}
$oldpage = clone $this->page;
- $update = new Page($datas);
- if (!is_null($update->id()) && $update->id() !== $this->page->id()) {
+ if (isset($datas['id']) && $datas['id'] !== $this->page->id()) {
$this->shortresponse(400, "Page ID and datas ID doesn't match");
}
$this->page->hydrate($datas);
@@ -111,7 +110,8 @@ public function add(string $page)
http_response_code(405);
exit;
}
- $this->page = new Page(["id" => $page]);
+
+ $this->page = $this->pagemanager->newpage(["id" => $page]);
$this->page->reset();
$this->page->addauthor($this->user->id());
if ($this->pagemanager->add($this->page)) {
@@ -133,7 +133,7 @@ public function put(string $page)
if ($exist && !$this->canedit($this->page)) {
$this->shortresponse(401, 'Page already exist but user cannot update it');
}
- $this->page = new Page(array_merge($this->recievejson(), ['id' => $page]));
+ $this->page = $this->pagemanager->newpage(array_merge($this->recievejson(), ['id' => $page]));
if ($this->pagemanager->update($this->page)) {
http_response_code($exist ? 200 : 201);
} else {
diff --git a/app/class/Controllerinfo.php b/app/class/Controllerinfo.php
index 15bbbf7e..b947507b 100644
--- a/app/class/Controllerinfo.php
+++ b/app/class/Controllerinfo.php
@@ -29,7 +29,7 @@ public function desktop()
} catch (RuntimeException $e) {
try {
$mansrc = Fs::readfile(Model::MAN_FILE);
- $render = new Servicerender($this->router, $this->pagemanager, true);
+ $render = new Servicerenderv2($this->router, $this->pagemanager, true);
$manual = $render->rendermanual($mansrc);
$sum = new Summary(['min' => 2, 'max' => 4, 'sum' => $render->sum()]);
diff --git a/app/class/Controllerpage.php b/app/class/Controllerpage.php
index 9ebe664b..29e50396 100644
--- a/app/class/Controllerpage.php
+++ b/app/class/Controllerpage.php
@@ -32,7 +32,7 @@ public function setpage(string $id, string $route)
http_response_code(308);
$this->routedirect($route, ['page' => $cleanid]);
} else {
- $this->page = new Page(['id' => $cleanid]);
+ $this->page = $this->pagemanager->newpage(['id' => $cleanid]);
}
}
@@ -43,17 +43,18 @@ public function setpage(string $id, string $route)
*/
public function importpage(): bool
{
- if (isset($_SESSION['pageupdate']['id']) && $_SESSION['pageupdate']['id'] == $this->page->id()) {
- $this->page = new Page($_SESSION['pageupdate']);
- unset($_SESSION['pageupdate']);
- return true;
- } else {
- try {
+ try {
+ if (isset($_SESSION['pageupdate']['id']) && $_SESSION['pageupdate']['id'] == $this->page->id()) {
+ $this->page = $this->pagemanager->parsepage($_SESSION['pageupdate']);
+ unset($_SESSION['pageupdate']);
+ return true;
+ } else {
$this->page = $this->pagemanager->get($this->page);
return true;
- } catch (RuntimeException $e) {
- return false;
}
+ } catch (RuntimeException $e) {
+ Logger::errorex($e);
+ return false;
}
}
@@ -239,16 +240,7 @@ public function edit($page)
exit;
}
- $datas['tablist'] = [
- 'main' => $this->page->main(),
- 'css' => $this->page->css(),
- 'header' => $this->page->header(),
- 'nav' => $this->page->nav(),
- 'aside' => $this->page->aside(),
- 'footer' => $this->page->footer(),
- 'body' => $this->page->body(),
- 'javascript' => $this->page->javascript()
- ];
+ $datas['tablist'] = $this->page->tabs();
$datas['faviconlist'] = $this->mediamanager->listfavicon();
$datas['thumbnaillist'] = $this->mediamanager->listthumbnail();
diff --git a/app/class/Element.php b/app/class/Element.php
index 53a814bd..fc84fba6 100644
--- a/app/class/Element.php
+++ b/app/class/Element.php
@@ -2,17 +2,13 @@
namespace Wcms;
-use DomainException;
-
/**
* HTML Element used in pages
*/
-class Element extends Item
+abstract class Element extends Item
{
- protected $fullmatch;
- protected string $type;
- protected $options;
- protected $sources = [];
+ protected string $fullmatch;
+ protected string $options;
protected int $everylink = 0;
protected bool $markdown = true;
protected string $content = '';
@@ -23,8 +19,6 @@ class Element extends Item
protected bool $urllinker;
protected int $headeranchor = self::NOHEADERANCHOR;
- /** @var bool Include element with HTML tags */
- protected bool $tag;
public const NOHEADERANCHOR = 0;
public const HEADERANCHORLINK = 1;
@@ -37,32 +31,7 @@ class Element extends Item
- public function __construct($pageid, $datas = [])
- {
- $this->urllinker = Config::urllinker();
- $this->tag = Config::htmltag();
- $this->hydrate($datas);
- $this->analyse($pageid);
- }
-
- private function analyse(string $pageid)
- {
- if (!empty($this->options)) {
- $this->options = str_replace('*', $pageid, $this->options);
- parse_str($this->options, $datas);
- if (isset($datas['id'])) {
- $this->sources = explode(' ', $datas['id']);
- } else {
- $this->sources = [$pageid];
- }
- $this->hydrate($datas);
- } else {
- $this->sources = [$pageid];
- }
- }
-
-
-
+ abstract protected function analyse(string $pageid);
// ______________________________________________ G E T ________________________________________________________
@@ -73,21 +42,11 @@ public function fullmatch(): string
return $this->fullmatch;
}
- public function type(): string
- {
- return $this->type;
- }
-
public function options(): string
{
return $this->options;
}
- public function sources(): array
- {
- return $this->sources;
- }
-
public function everylink(): int
{
return $this->everylink;
@@ -128,11 +87,6 @@ public function urllinker(): bool
return $this->urllinker;
}
- public function tag(): bool
- {
- return $this->tag;
- }
-
@@ -146,19 +100,6 @@ public function setfullmatch(string $fullmatch)
$this->fullmatch = $fullmatch;
}
- /**
- * @throws DomainException if given type is not an HTML element
- */
- public function settype(string $type)
- {
- $type = strtolower($type);
- if (in_array($type, Model::HTML_ELEMENTS)) {
- $this->type = $type;
- } else {
- throw new DomainException("$type is not a valid Page HTML Element Type");
- }
- }
-
public function setoptions(string $options)
{
if (!empty($options)) {
@@ -208,9 +149,4 @@ public function seturllinker($urllinker)
{
$this->urllinker = boolval($urllinker);
}
-
- public function settag($tag)
- {
- $this->tag = boolval($tag);
- }
}
diff --git a/app/class/Elementv1.php b/app/class/Elementv1.php
new file mode 100644
index 00000000..1f330ad3
--- /dev/null
+++ b/app/class/Elementv1.php
@@ -0,0 +1,69 @@
+tag = Config::htmltag();
+ $this->urllinker = Config::urllinker();
+ $this->fullmatch = $fullmatch;
+ $type = strtolower($type);
+ if (in_array($type, Pagev1::HTML_ELEMENTS)) {
+ $this->type = $type;
+ } else {
+ throw new DomainException("$type is not a valid Page HTML Element Type");
+ }
+ $this->options = $options;
+ $this->analyse($pageid);
+ }
+
+ protected function analyse(string $pageid)
+ {
+ if (!empty($this->options)) {
+ $this->options = str_replace('*', $pageid, $this->options);
+ parse_str($this->options, $datas);
+ if (isset($datas['id'])) {
+ $this->sources = explode(' ', $datas['id']);
+ } else {
+ $this->sources = [$pageid];
+ }
+ $this->hydrate($datas);
+ } else {
+ $this->sources = [$pageid];
+ }
+ }
+
+
+ // ______________________________________________ G E T ________________________________________________________
+
+ public function sources(): array
+ {
+ return $this->sources;
+ }
+
+ public function type(): string
+ {
+ return $this->type;
+ }
+
+ public function tag(): bool
+ {
+ return $this->tag;
+ }
+
+ public function settag($tag)
+ {
+ $this->tag = boolval($tag);
+ }
+}
diff --git a/app/class/Elementv2.php b/app/class/Elementv2.php
new file mode 100644
index 00000000..c1d9fc16
--- /dev/null
+++ b/app/class/Elementv2.php
@@ -0,0 +1,37 @@
+urllinker = Config::urllinker();
+ $this->fullmatch = $fullmatch;
+ $this->id = $pageid;
+ $this->options = $options;
+ $this->analyse($pageid);
+ }
+
+ protected function analyse(string $pageid)
+ {
+ parse_str($this->options, $datas);
+ $this->hydrate($datas);
+ }
+
+
+
+ // ______________________________________________ G E T ________________________________________________________
+
+ public function id(): string
+ {
+ return $this->id;
+ }
+
+ public function setid($id): void
+ {
+ $this->id = $id;
+ }
+}
diff --git a/app/class/Model.php b/app/class/Model.php
index 1d41acc0..19160c6d 100644
--- a/app/class/Model.php
+++ b/app/class/Model.php
@@ -60,11 +60,10 @@ abstract class Model
'linkto',
'visitcount',
'displaycount',
- 'editcount'
+ 'editcount',
+ 'version',
];
- public const HTML_ELEMENTS = ['header', 'nav', 'main', 'aside', 'footer'];
-
public const ID_REGEX = "%[^a-z0-9-_]%";
public const MAX_ID_LENGTH = 64;
public const PASSWORD_MIN_LENGTH = 4;
diff --git a/app/class/Modelpage.php b/app/class/Modelpage.php
index 672cf544..49413739 100644
--- a/app/class/Modelpage.php
+++ b/app/class/Modelpage.php
@@ -6,7 +6,9 @@
use JamesMoss\Flywheel\Document;
use DateTimeImmutable;
use DateTimeInterface;
+use DomainException;
use InvalidArgumentException;
+use RangeException;
use RuntimeException;
class Modelpage extends Modeldb
@@ -37,7 +39,12 @@ public function pagelist(): array
if (empty($this->pagelist)) {
$list = $this->repo->findAll();
foreach ($list as $pagedata) {
- $this->pagelist[$pagedata->id] = new Page($pagedata);
+ $id = $pagedata->id;
+ try {
+ $this->pagelist[$id] = $this->parsepage($pagedata);
+ } catch (RuntimeException $e) {
+ Logger::error("Could not load Page with ID \"$id\" : $e");
+ }
}
}
return $this->pagelist;
@@ -59,7 +66,11 @@ public function pagelistbyid(array $idlist = []): array
$pagelist = [];
foreach ($pagedatalist as $id => $pagedata) {
- $pagelist[$id] = new Page($pagedata);
+ try {
+ $this->pagelist[$id] = $this->parsepage($pagedata);
+ } catch (RuntimeException $e) {
+ Logger::error("Could not load Page with ID \"$id\" : $e");
+ }
}
return $pagelist;
}
@@ -98,11 +109,14 @@ public function get($id): Page
}
if (is_string($id)) {
$pagedata = $this->repo->findById($id);
- if ($pagedata !== false) {
- return new Page($pagedata);
- } else {
+ if ($pagedata === false) {
throw new RuntimeException("Could not find Page with the following ID: \"$id\"");
}
+ try {
+ return $this->parsepage($pagedata);
+ } catch (RuntimeException $e) {
+ throw new RuntimeException("Could not load Page with ID \"$id\": $e");
+ }
} else {
throw new InvalidArgumentException("argument of Modelpage->get() should be a ID string or Page");
}
@@ -141,8 +155,6 @@ public function getfromfile()
return false;
}
- $files = $_FILES;
-
$json = file_get_contents($_FILES['pagefile']['tmp_name']);
$pagedata = json_decode($json, true);
@@ -150,9 +162,11 @@ public function getfromfile()
return false;
}
- $page = new Page($pagedata);
-
- return $page;
+ try {
+ return $this->parsepage($pagedata);
+ } catch (RuntimeException $e) {
+ return false;
+ }
}
/**
@@ -381,7 +395,18 @@ public function renderpage(Page $page, AltoRouter $router): Page
{
$now = new DateTimeImmutable("now", timezone_open("Europe/Paris"));
- $renderengine = new Servicerender($router, $this, Config::externallinkblank(), Config::internallinkblank());
+ $params = [$router, $this, Config::externallinkblank(), Config::internallinkblank()];
+
+ switch ($page->version()) {
+ case Page::V1:
+ $renderengine = new Servicerenderv1(...$params);
+ break;
+ case Page::V2:
+ $renderengine = new Servicerenderv2(...$params);
+ break;
+ default:
+ throw new DomainException('Page version is out of range');
+ }
try {
$html = $renderengine->render($page);
@@ -455,7 +480,8 @@ protected function filter(array $pagelist, Opt $opt): array
$this->flinkto($page, $opt->linkto()) &&
$this->fsince($page, $opt->since()) &&
$this->funtil($page, $opt->until()) &&
- $this->fgeo($page, $opt->geo())
+ $this->fgeo($page, $opt->geo()) &&
+ $this->fversion($page, $opt->version())
) {
$filter[] = $page->id();
}
@@ -656,6 +682,15 @@ protected function fgeo(Page $page, bool $geo)
}
}
+ protected function fversion(Page $page, int $version)
+ {
+ if ($version === 0) {
+ return true;
+ } else {
+ return $page->version() === $version;
+ }
+ }
+
/**
* Search for regex and count occurences
@@ -678,11 +713,9 @@ protected function deepsearch(array $pagelist, string $regex, array $options): a
foreach ($pagelist as $page) {
$count = 0;
if ($options['content']) {
- $count += preg_match($regex, $page->main());
- $count += preg_match($regex, $page->nav());
- $count += preg_match($regex, $page->aside());
- $count += preg_match($regex, $page->header());
- $count += preg_match($regex, $page->footer());
+ foreach ($page->contents() as $content) {
+ $count += preg_match($regex, $page->$content());
+ }
}
if ($options['other']) {
$count += preg_match($regex, $page->body());
@@ -704,4 +737,49 @@ protected function deepsearch(array $pagelist, string $regex, array $options): a
}
return $pageselected;
}
+
+ /**
+ * Create a page
+ *
+ * @param array $datas Page's datas
+ * @return Page V1 or V2 depending of config file setting
+ */
+ public function newpage(array $datas = []): Page
+ {
+ $pageversion = Config::pageversion();
+ switch ($pageversion) {
+ case Page::V1:
+ return new Pagev1($datas);
+
+ case Page::V2:
+ return new Pagev2($datas);
+ }
+ throw new DomainException("Invalid page version allowed to be set in config");
+ }
+
+
+ /**
+ * This function will check for page version in datas and will retrun coresponding page version object
+ * If no version is specified and `content` field is not used, it will return Pagev1
+ *
+ * @param array|object $datas Page's datas
+ * @return Page V1 or V2
+ * @throws RangeException If page version is defined but out of range
+ */
+ public function parsepage($datas = []): Page
+ {
+ $metadatas = is_object($datas) ? get_object_vars($datas) : $datas;
+ if (isset($metadatas['version'])) {
+ switch ($metadatas['version']) {
+ case Page::V1:
+ return new Pagev1($datas);
+
+ case Page::V2:
+ return new Pagev2($datas);
+ }
+ throw new RangeException('Version is specified but out of range');
+ } else {
+ return new Pagev1($datas);
+ }
+ }
}
diff --git a/app/class/Opt.php b/app/class/Opt.php
index 5cc8517c..58017d8f 100644
--- a/app/class/Opt.php
+++ b/app/class/Opt.php
@@ -37,6 +37,8 @@ class Opt extends Item
protected bool $geo = false;
+ protected int $version = 0;
+
protected $pageidlist = [];
/** @var array $pagevarlist List fo every properties of an Page object */
@@ -63,6 +65,7 @@ class Opt extends Item
'since',
'until',
'geo',
+ 'version',
'invert',
'limit'
];
@@ -71,8 +74,7 @@ class Opt extends Item
public function __construct(array $data = [])
{
- $page = new Page();
- $this->pagevarlist = ($page->getobjectvars());
+ $this->pagevarlist = Page::getclassvars();
$this->hydrate($data);
}
@@ -372,6 +374,11 @@ public function geo(): bool
return $this->geo;
}
+ public function version(): int
+ {
+ return $this->version;
+ }
+
public function invert(): bool
{
return $this->invert;
@@ -548,6 +555,14 @@ public function setgeo($geo)
$this->geo = boolval($geo);
}
+ public function setversion($version): void
+ {
+ $version = intval($version);
+ if ($version === 0 || key_exists($version, Page::VERSIONS)) {
+ $this->version = $version;
+ }
+ }
+
public function setinvert($invert)
{
$this->invert = boolval($invert);
diff --git a/app/class/Page.php b/app/class/Page.php
index 10cfdd3a..06d01562 100644
--- a/app/class/Page.php
+++ b/app/class/Page.php
@@ -6,7 +6,7 @@
use DateTimeImmutable;
use DateTimeZone;
-class Page extends Item
+abstract class Page extends Item
{
protected $id;
protected $title;
@@ -22,11 +22,6 @@ class Page extends Item
protected $css;
protected $javascript;
protected $body;
- protected $header;
- protected $main;
- protected $nav;
- protected $aside;
- protected $footer;
protected $externalcss;
protected $customhead;
protected $secure;
@@ -51,17 +46,27 @@ class Page extends Item
protected $password;
protected $postprocessaction;
+ protected int $version;
+
public const LATITUDE_MIN = -90;
public const LATITUDE_MAX = 90;
public const LONGITUDE_MIN = -180;
public const LONGITUDE_MAX = 180;
+ public const V1 = 1;
+ public const V2 = 2;
+
+ public const VERSIONS = [
+ self::V1 => "version 1",
+ self::V2 => "version 2"
+ ];
+
public const PUBLIC = 0;
public const PRIVATE = 1;
public const NOT_PUBLISHED = 2;
public const SECUREMAX = 2;
- public const TABS = ['main', 'css', 'header', 'body', 'nav', 'aside', 'footer', 'javascript'];
+ public const TABS = ['css', 'body', 'javascript'];
public const VAR_DATE = ['date', 'datecreation', 'datemodif', 'daterender'];
public const TEMPLATE_OPTIONS = ['externalcss', 'externaljavascript', 'favicon', 'thumbnail', 'recursivecss'];
@@ -76,13 +81,13 @@ public function __construct($datas = [])
}
/**
- * Return a list of all object vars name as strings
+ * Return a list of all class vars name as strings
*
* @return string[]
*/
- public function getobjectvars(): array
+ public static function getclassvars(): array
{
- return array_keys(get_object_vars($this));
+ return array_keys(get_class_vars(self::class));
}
public function reset()
@@ -103,15 +108,9 @@ public function reset()
$this->setcss('');
$this->setjavascript('');
$this->setbody(Config::defaultbody());
- $this->setheader('');
- $this->setmain('');
- $this->setnav('');
- $this->setaside('');
- $this->setfooter('');
$this->setexternalcss([]);
$this->setcustomhead('');
$this->setsecure(Config::defaultprivacy());
- $this->setinterface('main');
$this->setlinkto([]);
$this->settemplatebody('');
$this->settemplatecss('');
@@ -156,6 +155,26 @@ public function isgeo(): bool
return (!is_null($this->latitude) && !is_null($this->longitude));
}
+ /**
+ * @return string[] Page fields containting content
+ */
+ public function contents(): array
+ {
+ return array_diff($this::TABS, Page::TABS);
+ }
+
+ /**
+ * @return string[] Tabs contents to be included in edit page
+ */
+ public function tabs(): array
+ {
+ $tabs = [];
+ foreach ($this::TABS as $tab) {
+ $tabs[$tab] = $this->$tab;
+ }
+ return $tabs;
+ }
+
// _____________________________________________________ G E T ____________________________________________________
public function id($type = 'string')
@@ -228,6 +247,11 @@ public function daterender($option = 'date')
return $this->datetransform('daterender', $option);
}
+ public function primary($type = ''): string
+ {
+ return '';
+ }
+
public function css($type = 'string')
{
return $this->css;
@@ -242,27 +266,6 @@ public function body($type = 'string')
{
return $this->body;
}
-
- public function header($type = 'string')
- {
- return $this->header;
- }
-
- public function main($type = 'string')
- {
- return $this->main;
- }
-
- public function nav($type = "string")
- {
- return $this->nav;
- }
-
- public function aside($type = "string")
- {
- return $this->aside;
- }
-
public function externalcss($type = "array")
{
return $this->externalcss;
@@ -277,11 +280,6 @@ public function customhead($type = "string")
}
}
- public function footer($type = "string")
- {
- return $this->footer;
- }
-
public function secure($type = 'int')
{
if ($type == 'string') {
@@ -430,6 +428,11 @@ public function postprocessaction($type = 'int'): bool
return $this->postprocessaction;
}
+ public function version($type = 'int'): int
+ {
+ return $this->version;
+ }
+
@@ -608,38 +611,6 @@ public function setbody($body)
}
}
- public function setheader($header)
- {
- if (strlen($header) < self::LENGTH_LONG_TEXT && is_string($header)) {
- $header = crlf2lf($header);
- $this->header = $header;
- }
- }
-
- public function setmain($main)
- {
- if (strlen($main) < self::LENGTH_LONG_TEXT and is_string($main)) {
- $main = crlf2lf($main);
- $this->main = $main;
- }
- }
-
- public function setnav($nav)
- {
- if (strlen($nav) < self::LENGTH_LONG_TEXT and is_string($nav)) {
- $nav = crlf2lf($nav);
- $this->nav = $nav;
- }
- }
-
- public function setaside($aside)
- {
- if (strlen($aside) < self::LENGTH_LONG_TEXT and is_string($aside)) {
- $aside = crlf2lf($aside);
- $this->aside = $aside;
- }
- }
-
public function setexternalcss($externalcss)
{
if (is_array($externalcss)) {
@@ -655,14 +626,6 @@ public function setcustomhead(string $customhead)
}
}
- public function setfooter($footer)
- {
- if (strlen($footer) < self::LENGTH_LONG_TEXT and is_string($footer)) {
- $footer = crlf2lf($footer);
- $this->footer = $footer;
- }
- }
-
public function setsecure($secure)
{
if ($secure >= 0 and $secure <= self::SECUREMAX) {
@@ -672,7 +635,7 @@ public function setsecure($secure)
public function setinterface($interface)
{
- if (in_array($interface, self::TABS)) {
+ if (in_array($interface, $this::TABS)) {
$this->interface = $interface;
}
}
diff --git a/app/class/Pagev1.php b/app/class/Pagev1.php
new file mode 100644
index 00000000..ff3ca5b2
--- /dev/null
+++ b/app/class/Pagev1.php
@@ -0,0 +1,102 @@
+setheader('');
+ $this->setmain('');
+ $this->setnav('');
+ $this->setaside('');
+ $this->setfooter('');
+
+ $this->setinterface('main');
+ }
+
+
+ public function header($type = 'string')
+ {
+ return $this->header;
+ }
+
+ public function main($type = 'string')
+ {
+ return $this->main;
+ }
+
+ public function primary($type = ''): string
+ {
+ return $this->main;
+ }
+
+ public function nav($type = "string")
+ {
+ return $this->nav;
+ }
+
+ public function aside($type = "string")
+ {
+ return $this->aside;
+ }
+
+ public function footer($type = "string")
+ {
+ return $this->footer;
+ }
+
+
+ public function setheader($header)
+ {
+ if (strlen($header) < self::LENGTH_LONG_TEXT && is_string($header)) {
+ $header = crlf2lf($header);
+ $this->header = $header;
+ }
+ }
+
+ public function setmain($main)
+ {
+ if (strlen($main) < self::LENGTH_LONG_TEXT and is_string($main)) {
+ $main = crlf2lf($main);
+ $this->main = $main;
+ }
+ }
+
+ public function setnav($nav)
+ {
+ if (strlen($nav) < self::LENGTH_LONG_TEXT and is_string($nav)) {
+ $nav = crlf2lf($nav);
+ $this->nav = $nav;
+ }
+ }
+
+ public function setaside($aside)
+ {
+ if (strlen($aside) < self::LENGTH_LONG_TEXT and is_string($aside)) {
+ $aside = crlf2lf($aside);
+ $this->aside = $aside;
+ }
+ }
+
+ public function setfooter($footer)
+ {
+ if (strlen($footer) < self::LENGTH_LONG_TEXT and is_string($footer)) {
+ $footer = crlf2lf($footer);
+ $this->footer = $footer;
+ }
+ }
+}
diff --git a/app/class/Pagev2.php b/app/class/Pagev2.php
new file mode 100644
index 00000000..e820441c
--- /dev/null
+++ b/app/class/Pagev2.php
@@ -0,0 +1,38 @@
+setcontent('');
+
+ $this->setinterface('content');
+ }
+
+ public function content($type = ''): string
+ {
+ return $this->content;
+ }
+
+ public function primary($type = ''): string
+ {
+ return $this->content;
+ }
+
+ public function setcontent($content)
+ {
+ if (is_string($content)) {
+ $this->content = $content;
+ }
+ }
+}
diff --git a/app/class/Servicerender.php b/app/class/Servicerender.php
index 58f1abdb..f840f7b1 100644
--- a/app/class/Servicerender.php
+++ b/app/class/Servicerender.php
@@ -15,7 +15,7 @@
use VStelmakh\UrlHighlight\UrlHighlight;
use VStelmakh\UrlHighlight\Validator\Validator;
-class Servicerender
+abstract class Servicerender
{
/** @var AltoRouter */
protected ?AltoRouter $router;
@@ -23,10 +23,7 @@ class Servicerender
/** @var Modelpage */
protected Modelpage $pagemanager;
- /**
- * @var Page Actual page being rendered
- * */
- protected $page;
+ protected Page $page;
/** @var string[] */
protected $linkto = [];
@@ -82,21 +79,15 @@ public function render(Page $page): string
}
/**
- * Render a page MAIN content to be used in RSS feed
+ * Render page's primary content to be used in RSS feed
*
* @param Page $page Page to render
*
- * @return string HTML Parsed MAIN content of a page
+ * @return string HTML Parsed primary content of a page
*
* @todo render absolute media links
*/
- public function rendermain(Page $page): string
- {
- $this->page = $page;
- $element = new Element($page->id(), ['content' => $page->main(), 'type' => "main"]);
- $html = $this->elementparser($element);
- return $this->bodyparser($html);
- }
+ abstract public function renderprimary(Page $page): string;
/**
* Used to convert the markdown user manual to html document
@@ -107,7 +98,7 @@ public function rendermain(Page $page): string
public function rendermanual(string $text): string
{
$text = $this->markdown($text);
- $text = $this->headerid($text, 1, 5, 'main', 0);
+ $text = $this->headerid($text, 1, 5, 0);
return $text;
}
@@ -117,7 +108,7 @@ public function rendermanual(string $text): string
*
* @return string html string
*/
- private function gethmtl()
+ protected function gethmtl()
{
$body = $this->bodyconstructor($this->readbody());
@@ -134,7 +125,7 @@ private function gethmtl()
}
- private function readbody()
+ protected function readbody()
{
if (!empty($this->page->templatebody())) {
$templateid = $this->page->templatebody();
@@ -153,41 +144,22 @@ private function readbody()
/**
- * Analyse BODY, call the corresponding CONTENTs and render everything
+ * Analyse BODY, include basic inclusions
*
* @param string $body as the string BODY of the page
*
* @return string as the full rendered BODY of the page
*/
- private function bodyconstructor(string $body): string
+ protected function bodyconstructor(string $body): string
{
$body = $this->winclusions($body);
-
- // Elements that can be detected
- $types = array_map("strtoupper", Model::HTML_ELEMENTS);
-
- // First level regex
- $regex = implode("|", $types);
-
- $matches = $this->match($body, $regex);
-
- // First, analyse the synthax and call the corresponding methods
- if (!empty($matches)) {
- foreach ($matches as $match) {
- $element = new Element($this->page->id(), $match);
- $element->setcontent($this->getelementcontent($element->sources(), $element->type()));
- $element->setcontent($this->elementparser($element));
- $body = str_replace($element->fullmatch(), $element->content(), $body);
- }
- }
-
return $body;
}
/**
* Return HEAD html element of a page
*/
- private function gethead(): string
+ protected function gethead(): string
{
$id = $this->page->id();
$globalpath = Model::dirtopath(Model::GLOBAL_CSS_FILE);
@@ -284,7 +256,7 @@ private function gethead(): string
* @param Page $page Page being rendered
* @return string HTML to insert into of page
*/
- private function recursivecss(Page $page): string
+ protected function recursivecss(Page $page): string
{
$head = "";
try {
@@ -305,38 +277,10 @@ private function recursivecss(Page $page): string
}
- /**
- * Foreach $sources (pages), this will get the corresponding $type element content
- *
- * @param string[] $sources Array of pages ID
- * @param string $type Type of element
- */
- private function getelementcontent(array $sources, string $type)
- {
- if (!in_array($type, Model::HTML_ELEMENTS)) {
- throw new InvalidArgumentException();
- }
- $content = '';
- $subseparator = "\n\n";
- foreach ($sources as $source) {
- if ($source !== $this->page->id()) {
- try {
- $subcontent = $this->pagemanager->get($source)->$type();
- } catch (RuntimeException $e) {
- $subcontent = $this->page->$type();
- }
- } else {
- $subcontent = $this->page->$type();
- }
- $content .= $subseparator . $subcontent;
- }
- return $content . $subseparator;
- }
-
/**
* Perfom W syntax inclusions
*/
- private function winclusions($text)
+ protected function winclusions($text)
{
$text = $this->date($text);
$text = $this->thumbnail($text);
@@ -354,38 +298,7 @@ private function winclusions($text)
return $text;
}
- private function elementparser(Element $element)
- {
- $content = $element->content();
- $content = $this->winclusions($content);
- if ($element->everylink() > 0) {
- $content = $this->everylink($content, $element->everylink());
- }
- if ($element->markdown()) {
- $content = $this->markdown($content);
- }
- if ($element->headerid()) {
- $content = $this->headerid(
- $content,
- $element->minheaderid(),
- $element->maxheaderid(),
- $element->type(),
- $element->headeranchor()
- );
- }
- if ($element->urllinker()) {
- $content = $this->autourl($content);
- }
- if ($element->tag()) {
- $type = $element->type();
- $content = "\n<{$type}>\n{$content}\n{$type}>\n";
- }
-
- return $content;
- }
-
-
- private function bodyparser(string $html)
+ protected function bodyparser(string $html)
{
$html = $this->summary($html);
@@ -402,7 +315,7 @@ private function bodyparser(string $html)
/**
* Replace `%TITLE%` code with page's title
*/
- private function title($text)
+ protected function title($text)
{
return str_replace('%TITLE%', $this->page->title(), $text);
}
@@ -411,7 +324,7 @@ private function title($text)
/**
* Replace `%DESCRIPTION%` code with page's description
*/
- private function description($text)
+ protected function description($text)
{
return str_replace('%DESCRIPTION%', $this->page->description(), $text);
}
@@ -421,7 +334,7 @@ private function description($text)
*
* @param string $text the page text as html
*/
- private function richlink(string $text): string
+ protected function richlink(string $text): string
{
$text = preg_replace('#\2#', "$3", $text);
return $text;
@@ -432,7 +345,7 @@ private function richlink(string $text): string
*
* This will also include `target=_blank` and `class=external` attributes.
*/
- private function autourl($text): string
+ protected function autourl($text): string
{
$options = ["class" => "external"];
if ($this->externallinkblank) {
@@ -456,7 +369,7 @@ private function autourl($text): string
*
* Keep existing class and remove duplicates or useless spaces in class attribute
*/
- private function htmlparser(string $html): string
+ protected function htmlparser(string $html): string
{
$dom = new DOMDocument('1.0', 'UTF-8');
/** Force UTF-8 encoding for loadHTML by defining it in the content itself with an XML tag that need to be removed later */
@@ -533,7 +446,7 @@ private function htmlparser(string $html): string
/**
* Edit `src` attributes in media HTML tags
*/
- private function sourceparser(DOMNodeList $sourcables): void
+ protected function sourceparser(DOMNodeList $sourcables): void
{
foreach ($sourcables as $sourcable) {
assert($sourcable instanceof DOMElement);
@@ -563,7 +476,7 @@ private function sourceparser(DOMNodeList $sourcables): void
/**
* Replace wiki links [[page_id]] with HTML link
*/
- private function wikiurl(string $text): string
+ protected function wikiurl(string $text): string
{
$rend = $this;
$text = preg_replace_callback(
@@ -591,14 +504,17 @@ function ($matches) use ($rend) {
* @param string $text Input html document to scan
* @param int $min Maximum header deepness to look for. Min = 1 Max = 6 Default = 1
* @param int $max Maximum header deepness to look for. Min = 1 Max = 6 Default = 6
- * @param string $element Name of element being analysed
+ * @param string $element Name of element being analysed. Leave empty if using Markdown field
* @param int $anchormode Mode of anchor link display. see Element HEADERANCHORMODES
*
* @return string text with id in header
*/
- private function headerid(string $text, int $min, int $max, string $element, int $anchormode): string
+ protected function headerid(string $text, int $min, int $max, int $anchormode, string $element = ''): string
{
+ if (empty($element)) {
+ $element = md5($text);
+ }
if ($min > 6 || $min < 1) {
$min = 6;
}
@@ -635,7 +551,7 @@ function ($matches) use ($element, $anchormode) {
return $text;
}
- private function markdown($text)
+ protected function markdown($text)
{
$fortin = new MarkdownExtra();
// id in headers
@@ -655,7 +571,7 @@ private function markdown($text)
*
* @return array Ordered array containing an array of `fullmatch`, `type` and `options`
*/
- private function match(string $text, string $include): array
+ protected function match(string $text, string $include): array
{
preg_match_all('~\%(' . $include . ')(\?([a-zA-Z0-9:\[\]\&=\-_\/\%\+\*\;]*))?\%~', $text, $out);
@@ -673,7 +589,7 @@ private function match(string $text, string $include): array
*
* @return string Output text
*/
- private function automedialist(string $text): string
+ protected function automedialist(string $text): string
{
$matches = $this->match($text, 'MEDIA');
@@ -693,7 +609,7 @@ private function automedialist(string $text): string
*
* @return string Output text
*/
- private function summary(string $text): string
+ protected function summary(string $text): string
{
$matches = $this->match($text, 'SUMMARY');
@@ -712,7 +628,7 @@ private function summary(string $text): string
/**
* Render pages list
*/
- private function pageoptlist(string $text): string
+ protected function pageoptlist(string $text): string
{
$matches = $this->match($text, 'LIST');
foreach ($matches as $match) {
@@ -742,7 +658,7 @@ private function pageoptlist(string $text): string
/**
* Render page maps
*/
- private function pageoptmap(string $text): string
+ protected function pageoptmap(string $text): string
{
$matches = $this->match($text, 'MAP');
foreach ($matches as $match) {
@@ -775,7 +691,7 @@ private function pageoptmap(string $text): string
/**
* Render Random links
*/
- private function randomopt(string $text): string
+ protected function randomopt(string $text): string
{
$matches = $this->match($text, 'RANDOM');
foreach ($matches as $match) {
@@ -810,7 +726,7 @@ private function randomopt(string $text): string
*
* @return string Text with replaced valid %RSS% inclusions
*/
- private function rss(string $text): string
+ protected function rss(string $text): string
{
$this->rsslist = $this->rssmatch($text);
foreach ($this->rsslist as $fullmatch => $bookmark) {
@@ -827,7 +743,7 @@ private function rss(string $text): string
*
* @return Bookmark[] Associative array of bookmarks, using fullmatch as key
*/
- private function rssmatch(string $text): array
+ protected function rssmatch(string $text): array
{
$rsslist = [];
$matches = $this->match($text, "RSS");
@@ -850,7 +766,7 @@ private function rssmatch(string $text): array
- private function date(string $text): string
+ protected function date(string $text): string
{
$dateregex = implode('|', array_keys(Clock::TYPES));
$matches = $this->match($text, $dateregex);
@@ -877,7 +793,7 @@ private function date(string $text): string
*
* @return string The rendered output
*/
- private function thumbnail(string $text): string
+ protected function thumbnail(string $text): string
{
$src = Model::thumbnailpath() . $this->page->thumbnail();
$alt = $this->page->title();
@@ -893,7 +809,7 @@ private function thumbnail(string $text): string
* @param string $text input text
* @return string output text with replaced elements
*/
- private function pageid(string $text): string
+ protected function pageid(string $text): string
{
return str_replace(['%PAGEID%', '%ID%'], $this->page->id(), $text);
}
@@ -903,7 +819,7 @@ private function pageid(string $text): string
* @param string $text input text
* @return string output text with replaced elements
*/
- private function url(string $text): string
+ protected function url(string $text): string
{
return str_replace('%URL%', Config::domain() . $this->upage($this->page->id()), $text);
}
@@ -913,7 +829,7 @@ private function url(string $text): string
* @param string $text input text
* @return string output text with replaced elements
*/
- private function path(string $text): string
+ protected function path(string $text): string
{
return str_replace('%PATH%', $this->upage($this->page->id()), $text);
}
@@ -921,7 +837,7 @@ private function path(string $text): string
/**
* Replace `%AUTHORS%` with a rendered list of authors
*/
- private function authors(string $text): string
+ protected function authors(string $text): string
{
$page = $this->page;
return preg_replace_callback("~\%AUTHORS\%~", function () use ($page) {
@@ -934,7 +850,7 @@ private function authors(string $text): string
/**
* Check if the page need post processing by looking for patterns
*/
- private function checkpostprocessaction(string $text): bool
+ protected function checkpostprocessaction(string $text): bool
{
$counterpaterns = Servicepostprocess::COUNTERS;
$pattern = implode('|', $counterpaterns);
@@ -948,7 +864,7 @@ private function checkpostprocessaction(string $text): bool
*
* @return string Conversion output
*/
- private function everylink(string $text, int $limit): string
+ protected function everylink(string $text, int $limit): string
{
$regex = '~([\w\-_éêèùïüîçà]{' . $limit . ',})(?![^<]*>|[^<>]*<\/)~';
$text = preg_replace_callback($regex, function ($matches) {
@@ -964,7 +880,7 @@ private function everylink(string $text, int $limit): string
*
* @return string text ouput
*/
- private function authenticate(string $text): string
+ protected function authenticate(string $text): string
{
$id = $this->page->id();
$regex = '~\%CONNECT(\?dir=([a-zA-Z0-9-_]+))?\%~';
@@ -1011,7 +927,7 @@ public function user(User $user): string
* @param User[] $users List of User
* @return string List of user in HTML
*/
- private function userlist(array $users): string
+ protected function userlist(array $users): string
{
$html = "";
foreach ($users as $user) {
diff --git a/app/class/Servicerenderv1.php b/app/class/Servicerenderv1.php
new file mode 100644
index 00000000..2c1dbc1f
--- /dev/null
+++ b/app/class/Servicerenderv1.php
@@ -0,0 +1,136 @@
+page = $page;
+ $html = $this->bodyconstructor('%MAIN%');
+ return $this->bodyparser($html);
+ }
+
+ /**
+ * Analyse BODY, call the corresponding CONTENTs and render everything
+ *
+ * @param string $body as the string BODY of the page
+ *
+ * @return string as the full rendered BODY of the page
+ */
+ protected function bodyconstructor(string $body): string
+ {
+ $body = parent::bodyconstructor($body);
+
+ // Elements that can be detected
+ $types = array_map("strtoupper", Pagev1::HTML_ELEMENTS);
+
+ // First level regex
+ $regex = implode("|", $types);
+
+ $matches = $this->match($body, $regex);
+
+ // First, analyse the synthax and call the corresponding methods
+ if (!empty($matches)) {
+ foreach ($matches as $match) {
+ $element = new Elementv1($this->page->id(), $match['fullmatch'], $match['type'], $match['options']);
+ $element->setcontent($this->getelementcontent($element->sources(), $element->type()));
+ $element->setcontent($this->elementparser($element));
+ $body = str_replace($element->fullmatch(), $element->content(), $body);
+ }
+ }
+
+ return $body;
+ }
+
+ protected function elementparser(Elementv1 $element)
+ {
+ $content = $element->content();
+ $content = $this->winclusions($content);
+ if ($element->everylink() > 0) {
+ $content = $this->everylink($content, $element->everylink());
+ }
+ if ($element->markdown()) {
+ $content = $this->markdown($content);
+ }
+ if ($element->headerid()) {
+ $content = $this->headerid(
+ $content,
+ $element->minheaderid(),
+ $element->maxheaderid(),
+ $element->headeranchor(),
+ $element->type()
+ );
+ }
+ if ($element->urllinker()) {
+ $content = $this->autourl($content);
+ }
+ if ($element->tag()) {
+ $type = $element->type();
+ $content = "\n<{$type}>\n{$content}\n{$type}>\n";
+ }
+
+ return $content;
+ }
+
+
+ /**
+ * Foreach $sources (pages), this will get the corresponding $type element content
+ * If ID is not used or if Page is not version 1: fallback to current page Markdown field
+ *
+ * @param string[] $sources Array of pages ID
+ * @param string $type Type of element
+ */
+ protected function getelementcontent(array $sources, string $type): string
+ {
+ if (!in_array($type, Pagev1::HTML_ELEMENTS)) {
+ throw new DomainException("$type is not a valid HTML element type");
+ }
+ $content = '';
+ $subseparator = "\n\n";
+ foreach ($sources as $source) {
+ if ($source !== $this->page->id()) {
+ try {
+ $page = $this->pagemanager->get($source);
+ if ($page instanceof Pagev1) {
+ $subcontent = $page->$type();
+ } else {
+ $subcontent = $this->page->$type();
+ }
+ } catch (RuntimeException $e) {
+ // Page ID is not used
+ $subcontent = $this->page->$type();
+ }
+ } else {
+ $subcontent = $this->page->$type();
+ }
+ $content .= $subseparator . $subcontent;
+ }
+ return $content . $subseparator;
+ }
+}
diff --git a/app/class/Servicerenderv2.php b/app/class/Servicerenderv2.php
new file mode 100644
index 00000000..ed458891
--- /dev/null
+++ b/app/class/Servicerenderv2.php
@@ -0,0 +1,116 @@
+page = $page;
+ $html = $this->bodyconstructor('%CONTENT%');
+ return $this->bodyparser($html);
+ }
+
+
+ /**
+ * Analyse BODY, call the corresponding CONTENTs and render everything
+ *
+ * @param string $body as the string BODY of the page
+ *
+ * @return string as the full rendered BODY of the page
+ */
+ protected function bodyconstructor(string $body): string
+ {
+ $body = parent::bodyconstructor($body);
+
+ $matches = $this->match($body, 'CONTENT');
+
+ // First, analyse the synthax and call the corresponding methods
+ if (!empty($matches)) {
+ foreach ($matches as $match) {
+ $element = new Elementv2($this->page->id(), $match['fullmatch'], $match['options']);
+ $element->setcontent($this->getelementcontent($element->id()));
+ $element->setcontent($this->elementparser($element));
+ $body = str_replace($element->fullmatch(), $element->content(), $body);
+ }
+ }
+
+ return $body;
+ }
+
+ protected function elementparser(Elementv2 $element)
+ {
+ $content = $element->content();
+ $content = $this->winclusions($content);
+ if ($element->everylink() > 0) {
+ $content = $this->everylink($content, $element->everylink());
+ }
+ if ($element->markdown()) {
+ $content = $this->markdown($content);
+ }
+ if ($element->headerid()) {
+ $content = $this->headerid(
+ $content,
+ $element->minheaderid(),
+ $element->maxheaderid(),
+ $element->headeranchor(),
+ );
+ }
+ if ($element->urllinker()) {
+ $content = $this->autourl($content);
+ }
+
+ return $content;
+ }
+
+
+ /**
+ * Get element content by looking for source page ID.
+ * If ID is not used: return empty string
+ * If source page is V1, it will use the MAIN content.
+ *
+ * @param string $source Source Page ID
+ *
+ * @return string Source Page primary content or empty string
+ *
+ * @todo Log errors somewhere
+ */
+ protected function getelementcontent(string $source): string
+ {
+ if ($source === $this->page->id()) {
+ return $this->page->content();
+ } else {
+ try {
+ $page = $this->pagemanager->get($source);
+ return $page->primary();
+ } catch (RuntimeException $e) {
+ // page ID is not used
+ return '';
+ }
+ }
+ }
+}
diff --git a/app/class/Servicerss.php b/app/class/Servicerss.php
index 8f5f5496..28385f2f 100644
--- a/app/class/Servicerss.php
+++ b/app/class/Servicerss.php
@@ -4,9 +4,11 @@
use AltoRouter;
use DateTime;
+use DomainException;
use DOMDocument;
use DOMException;
use DOMText;
+use Exception;
use LogicException;
use RuntimeException;
use Wcms\Exception\Database\Notfoundexception;
@@ -15,7 +17,6 @@
class Servicerss
{
protected AltoRouter $router;
- protected Servicerender $render;
protected Modelpage $pagemanager;
protected Modelbookmark $bookmarkmanager;
@@ -24,7 +25,6 @@ public function __construct(AltoRouter $router)
$this->router = $router;
$this->pagemanager = new Modelpage(Config::pagetable());
$this->bookmarkmanager = new Modelbookmark();
- $this->render = new Servicerender($this->router, $this->pagemanager);
}
/**
@@ -175,7 +175,7 @@ protected function render(array $pagelist, Bookmark $bookmark): string
$content = $xml->createElement("content");
$content->appendChild(
- new DOMText(html_entity_decode($this->mainhtml($page), ENT_QUOTES | ENT_SUBSTITUTE, "UTF-8"))
+ new DOMText(html_entity_decode($this->primaryhtml($page), ENT_QUOTES | ENT_SUBSTITUTE, "UTF-8"))
);
$content->setAttribute("type", "html");
$entry->appendChild($content);
@@ -195,19 +195,33 @@ protected function render(array $pagelist, Bookmark $bookmark): string
*/
protected function href(Page $page): string
{
- return Config::domain() . $this->render->upage($page->id());
+ try {
+ $path = $this->router->generate('pageread', ['page' => $page->id()]);
+ return Config::domain() . $path;
+ } catch (Exception $e) {
+ throw new LogicException($e->getMessage(), $e->getCode(), $e);
+ }
}
/**
- * Get the HTML output of a page
+ * Get the HTML output of the primary content of a page
*
* @param Page $page
- * @return string HTML content parsed from page MAIN
+ * @return string HTML content parsed from page primary field
*/
- protected function mainhtml(Page $page): string
+ protected function primaryhtml(Page $page): string
{
- $render = new Servicerender($this->router, $this->pagemanager);
- return $render->rendermain($page);
+ switch ($page->version()) {
+ case Page::V1:
+ $render = new Servicerenderv1($this->router, $this->pagemanager);
+ break;
+ case Page::V2:
+ $render = new Servicerenderv2($this->router, $this->pagemanager);
+ break;
+ default:
+ throw new DomainException('Page version is out of range');
+ }
+ return $render->renderprimary($page);
}
/**
diff --git a/app/class/Summary.php b/app/class/Summary.php
index 2c890640..74c69bac 100644
--- a/app/class/Summary.php
+++ b/app/class/Summary.php
@@ -142,7 +142,7 @@ public function setsum(array $sum)
public function setelement(string $element)
{
- if (in_array($element, Model::HTML_ELEMENTS)) {
+ if (in_array($element, Pagev1::HTML_ELEMENTS)) {
$this->element = $element;
}
}
diff --git a/app/view/templates/admin.php b/app/view/templates/admin.php
index 33d99d30..671bfb9f 100644
--- a/app/view/templates/admin.php
+++ b/app/view/templates/admin.php
@@ -74,6 +74,8 @@
Page creation
What really happend when you create a new page
+
+
Privacy of new pages
+
Page version
+
+
Choose W page version you want to use when a new page is created.