aboutsummaryrefslogtreecommitdiffhomepage
path: root/Digitigrade/Page.php
blob: 963a27dbfdae4d21500d7ee6fb84d631b92c7fbc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
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
        ];
    }
}