@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.)
hq.recaptime.dev/wiki/Phorge
phorge
phabricator
1<?php
2
3/**
4 * Simple API for rendering blocks of Remarkup.
5 *
6 * Example usage:
7 *
8 * $fancy_text = new PHUIRemarkupView($viewer, $raw_remarkup);
9 * $view->appendChild($fancy_text);
10 *
11 */
12final class PHUIRemarkupView extends AphrontView {
13
14 private $corpus;
15 private $contextObject;
16 private $options;
17 private $oneoff;
18 private $generateTableOfContents;
19
20 // TODO: In the long run, rules themselves should define available options.
21 // For now, just define constants here so we can more easily replace things
22 // later once this is cleaned up.
23 const OPTION_PRESERVE_LINEBREAKS = 'preserve-linebreaks';
24 const OPTION_GENERATE_TOC = 'header.generate-toc';
25
26 public function __construct(PhabricatorUser $viewer, $corpus) {
27 $this->setViewer($viewer);
28 $this->corpus = $corpus;
29 }
30
31 public function setContextObject($context_object) {
32 $this->contextObject = $context_object;
33 return $this;
34 }
35
36 public function getContextObject() {
37 return $this->contextObject;
38 }
39
40 public function setRemarkupOption($key, $value) {
41 $this->options[$key] = $value;
42 return $this;
43 }
44
45 public function setRemarkupOptions(array $options) {
46 foreach ($options as $key => $value) {
47 $this->setRemarkupOption($key, $value);
48 }
49 return $this;
50 }
51
52 public function setGenerateTableOfContents($generate) {
53 $this->generateTableOfContents = $generate;
54 return $this;
55 }
56
57 public function getGenerateTableOfContents() {
58 return $this->generateTableOfContents;
59 }
60
61 public function getTableOfContents() {
62 return $this->oneoff->getTableOfContents();
63 }
64
65 public function render() {
66 $viewer = $this->getViewer();
67 $corpus = $this->corpus;
68 $context = $this->getContextObject();
69
70 $options = $this->options;
71
72 $oneoff = id(new PhabricatorMarkupOneOff())
73 ->setContent($corpus)
74 ->setContentCacheFragment($this->getContentCacheFragment());
75
76 if ($options) {
77 $oneoff->setEngine($this->getEngine());
78 } else {
79 $oneoff->setPreserveLinebreaks(true);
80 }
81
82 $generate_toc = $this->getGenerateTableOfContents();
83 $oneoff->setGenerateTableOfContents($generate_toc);
84 $this->oneoff = $oneoff;
85
86 $content = PhabricatorMarkupEngine::renderOneObject(
87 $oneoff,
88 'default',
89 $viewer,
90 $context);
91
92 return $content;
93 }
94
95 private function getEngine() {
96 $options = $this->options;
97 $viewer = $this->getViewer();
98
99 $viewer_key = $viewer->getCacheFragment();
100 $engine_key = $this->getEngineCacheFragment();
101
102 $cache = PhabricatorCaches::getRequestCache();
103 $cache_key = "remarkup.engine({$viewer_key}, {$engine_key})";
104
105 $engine = $cache->getKey($cache_key);
106 if (!$engine) {
107 $engine = PhabricatorMarkupEngine::newMarkupEngine($options);
108 $cache->setKey($cache_key, $engine);
109 }
110
111 return $engine;
112 }
113
114 private function getEngineCacheFragment() {
115 $options = $this->options;
116
117 ksort($options);
118
119 $engine_key = serialize($options);
120 $engine_key = PhabricatorHash::digestForIndex($engine_key);
121
122 return $engine_key;
123 }
124
125 private function getContentCacheFragment() {
126 $corpus = $this->corpus;
127
128 $content_fragment = PhabricatorHash::digestForIndex($corpus);
129 $options_fragment = array(
130 'toc' => $this->getGenerateTableOfContents(),
131 );
132 $options_fragment = serialize($options_fragment);
133 $options_fragment = PhabricatorHash::digestForIndex($options_fragment);
134
135 return "remarkup({$content_fragment}, {$options_fragment})";
136 }
137
138}