aboutsummaryrefslogtreecommitdiffhomepage
path: root/Digitigrade/Page.php
diff options
context:
space:
mode:
authorwinter2025-03-15 18:35:59 +0000
committerwinter2025-03-15 18:52:54 +0000
commit61b122e88cc6783b4d0cf5142a22002f8e558c60 (patch)
tree847b864a93f716157456891d4526077e5f0b93f7 /Digitigrade/Page.php
parentcb904ef3fb05ab106d5e5e12f6273b8117db4216 (diff)
implement pages
Diffstat (limited to 'Digitigrade/Page.php')
-rw-r--r--Digitigrade/Page.php75
1 files changed, 75 insertions, 0 deletions
diff --git a/Digitigrade/Page.php b/Digitigrade/Page.php
new file mode 100644
index 0000000..963a27d
--- /dev/null
+++ b/Digitigrade/Page.php
@@ -0,0 +1,75 @@
+<?php
+namespace Digitigrade;
+
+use Digitigrade\FormattingProvider\CommonMark;
+use Digitigrade\FormattingProvider\SanitisedHtml;
+use Digitigrade\Model\Note;
+
+class Page implements \JsonSerializable {
+ public string $title;
+ public array $content;
+ /** @var PageLink[] */
+ public array $links;
+
+ public static function create(string $title, array $content) {
+ $page = new self();
+ $page->title = $title;
+ $page->content = $content;
+ $page->links = [];
+ return $page;
+ }
+
+ /**
+ * Gets the best available formatted content (or plain if there aren't any)
+ * and converts it to sanitised HTML
+ * @return string HTML that is hopefully safe to include directly
+ */
+ public function getBestContentAsHtml(): string {
+ if (isset($this->content['text/html'])) {
+ return SanitisedHtml::getInstance()->renderToHtml($this->insertLinks($this->content['text/html'], 'text/html'));
+ } elseif (isset($this->content['text/markdown'])) {
+ return CommonMark::getInstance()->renderToHtml($this->insertLinks($this->content['text/markdown'], 'text/markdown'));
+ }
+ return htmlspecialchars($this->insertLinks($this->content['text/plain'] ?? __('placeholder'), 'text/plain'));
+ }
+
+ private function insertLinks(string $originalContent, string $mediaType): string {
+ $result = $originalContent;
+ $offset = 0;
+
+ foreach ($this->links as $link) {
+ $range = $link->range[$mediaType] ?? null;
+ $targetNote = Note::findByUri($link->target);
+ if ($range == null || $targetNote == null)
+ continue;
+ $target = path_to_uri(htmlspecialchars($targetNote->getLocalUiHref(true)));
+ $before = mb_substr($result, 0, $range->start, 'utf-8');
+ $label = mb_substr($result, $range->start, $range->end - $range->start, 'utf-8');
+ $after = mb_substr($result, $range->end, null, 'utf-8');
+ $startTag = match ($mediaType) {
+ 'text/html' => '<a href="' . htmlspecialchars($target) . '">',
+ 'text/markdown' => '[',
+ 'text/plain' => '',
+ default => ''
+ };
+ $endTag = match ($mediaType) {
+ 'text/html' => '</a>',
+ 'text/markdown' => '](' . htmlspecialchars($target) . ')',
+ 'text/plain' => " ($target)",
+ default => ''
+ };
+ $result = $before . $startTag . $label . $endTag . $after;
+ $offset += strlen($startTag) + strlen($endTag);
+ }
+
+ return $result;
+ }
+
+ public function jsonSerialize(): array {
+ return [
+ 'title' => $this->title,
+ 'content' => $this->content,
+ 'links' => $this->links
+ ];
+ }
+} \ No newline at end of file