Commit | Line | Data |
---|---|---|
5158aa21 | 1 | <?php |
71212588 | 2 | namespace wcf\system\form\builder\field\wysiwyg; |
0dc68d99 MS |
3 | use wcf\data\IMessageQuoteAction; |
4 | use wcf\data\object\type\ObjectTypeCache; | |
71212588 | 5 | use wcf\system\form\builder\field\AbstractFormField; |
76d761f6 | 6 | use wcf\system\form\builder\field\data\processor\CustomFormFieldDataProcessor; |
71212588 MS |
7 | use wcf\system\form\builder\field\IMaximumLengthFormField; |
8 | use wcf\system\form\builder\field\IMinimumLengthFormField; | |
71212588 MS |
9 | use wcf\system\form\builder\field\TMaximumLengthFormField; |
10 | use wcf\system\form\builder\field\TMinimumLengthFormField; | |
5158aa21 MS |
11 | use wcf\system\form\builder\field\validation\FormFieldValidationError; |
12 | use wcf\system\form\builder\IFormDocument; | |
26e502ba MS |
13 | use wcf\system\form\builder\IObjectTypeFormNode; |
14 | use wcf\system\form\builder\TObjectTypeFormNode; | |
5158aa21 | 15 | use wcf\system\html\input\HtmlInputProcessor; |
0dc68d99 | 16 | use wcf\system\message\quote\MessageQuoteManager; |
5158aa21 MS |
17 | use wcf\util\StringUtil; |
18 | ||
19 | /** | |
20 | * Implementation of a form field for wysiwyg editors. | |
21 | * | |
22 | * @author Matthias Schmidt | |
7b7b9764 | 23 | * @copyright 2001-2019 WoltLab GmbH |
5158aa21 MS |
24 | * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php> |
25 | * @package WoltLabSuite\Core\System\Form\Builder\Field | |
dd2d8c0c | 26 | * @since 5.2 |
5158aa21 | 27 | */ |
71212588 | 28 | class WysiwygFormField extends AbstractFormField implements IMaximumLengthFormField, IMinimumLengthFormField, IObjectTypeFormNode { |
5158aa21 MS |
29 | use TMaximumLengthFormField; |
30 | use TMinimumLengthFormField; | |
71212588 | 31 | use TObjectTypeFormNode; |
5158aa21 MS |
32 | |
33 | /** | |
34 | * identifier used to autosave the field value; if empty, autosave is disabled | |
35 | * @var string | |
36 | */ | |
9299c8e5 | 37 | protected $autosaveId = ''; |
5158aa21 | 38 | |
71212588 MS |
39 | /** |
40 | * input processor containing the wysiwyg text | |
41 | * @var HtmlInputProcessor | |
42 | */ | |
43 | protected $htmlInputProcessor; | |
44 | ||
5158aa21 MS |
45 | /** |
46 | * last time the field has been edited; if `0`, the last edit time is unknown | |
47 | * @var int | |
48 | */ | |
9299c8e5 | 49 | protected $lastEditTime = 0; |
5158aa21 MS |
50 | |
51 | /** | |
0dc68d99 MS |
52 | * quote-related data used to create the JavaScript quote manager |
53 | * @var null|array | |
54 | */ | |
55 | protected $quoteData; | |
56 | ||
57 | /** | |
58 | * is `true` if this form field supports attachments, otherwise `false` | |
71212588 | 59 | * @var boolean |
5158aa21 | 60 | */ |
71212588 MS |
61 | protected $supportAttachments = false; |
62 | ||
63 | /** | |
0dc68d99 | 64 | * is `true` if this form field supports mentions, otherwise `false` |
71212588 MS |
65 | * @var boolean |
66 | */ | |
67 | protected $supportMentions = false; | |
5158aa21 | 68 | |
0dc68d99 MS |
69 | /** |
70 | * is `true` if this form field supports quotes, otherwise `false` | |
71 | * @var boolean | |
72 | */ | |
73 | protected $supportQuotes = false; | |
74 | ||
5158aa21 MS |
75 | /** |
76 | * @inheritDoc | |
77 | */ | |
78 | protected $templateName = '__wysiwygFormField'; | |
79 | ||
80 | /** | |
81 | * Sets the identifier used to autosave the field value and returns this field. | |
82 | * | |
83 | * @param string $autosaveId identifier used to autosave field value | |
26e502ba | 84 | * @return WysiwygFormField this field |
5158aa21 | 85 | */ |
020e6570 | 86 | public function autosaveId($autosaveId) { |
9299c8e5 | 87 | $this->autosaveId = $autosaveId; |
5158aa21 MS |
88 | |
89 | return $this; | |
90 | } | |
91 | ||
0dc68d99 MS |
92 | /** |
93 | * @inheritDoc | |
94 | */ | |
95 | public function cleanup() { | |
96 | MessageQuoteManager::getInstance()->saved(); | |
97 | } | |
98 | ||
5158aa21 MS |
99 | /** |
100 | * Returns the identifier used to autosave the field value. If autosave is disabled, | |
9d68d5b2 | 101 | * an empty string is returned. |
5158aa21 MS |
102 | * |
103 | * @return string | |
104 | */ | |
7b43decd | 105 | public function getAutosaveId() { |
9299c8e5 | 106 | return $this->autosaveId; |
5158aa21 MS |
107 | } |
108 | ||
0dc68d99 MS |
109 | /** |
110 | * @inheritDoc | |
111 | */ | |
112 | public function getHtml() { | |
113 | if ($this->supportsQuotes()) { | |
114 | MessageQuoteManager::getInstance()->assignVariables(); | |
115 | } | |
116 | ||
117 | return parent::getHtml(); | |
118 | } | |
119 | ||
5158aa21 MS |
120 | /** |
121 | * @inheritDoc | |
122 | */ | |
7b43decd | 123 | public function getObjectTypeDefinition() { |
5158aa21 MS |
124 | return 'com.woltlab.wcf.message'; |
125 | } | |
126 | ||
127 | /** | |
128 | * Returns the last time the field has been edited. If no last edit time has | |
129 | * been set, `0` is returned. | |
130 | * | |
131 | * @return int | |
132 | */ | |
7b43decd | 133 | public function getLastEditTime() { |
9299c8e5 | 134 | return $this->lastEditTime; |
5158aa21 MS |
135 | } |
136 | ||
0dc68d99 MS |
137 | /** |
138 | * Returns all quote data or specific quote data if an argument is given. | |
139 | * | |
140 | * @param null|string $index quote data index | |
141 | * @return string[]|string | |
142 | * | |
143 | * @throws \BadMethodCallException if quotes are not supported for this field | |
144 | * @throws \InvalidArgumentException if unknown quote data is requested | |
145 | */ | |
146 | public function getQuoteData($index = null) { | |
147 | if (!$this->supportQuotes()) { | |
148 | throw new \BadMethodCallException("Quotes are not supported."); | |
149 | } | |
150 | ||
151 | if ($index === null) { | |
152 | return $this->quoteData; | |
153 | } | |
154 | ||
155 | if (!isset($this->quoteData[$index])) { | |
156 | throw new \InvalidArgumentException("Unknown quote data '{$index}'."); | |
157 | } | |
158 | ||
159 | return $this->quoteData[$index]; | |
160 | } | |
161 | ||
5158aa21 MS |
162 | /** |
163 | * @inheritDoc | |
164 | */ | |
7b43decd | 165 | public function hasSaveValue() { |
071fff89 | 166 | return false; |
5158aa21 MS |
167 | } |
168 | ||
169 | /** | |
170 | * Sets the last time this field has been edited and returns this field. | |
171 | * | |
172 | * @param int $lastEditTime last time field has been edited | |
26e502ba | 173 | * @return WysiwygFormField this field |
5158aa21 | 174 | */ |
020e6570 | 175 | public function lastEditTime($lastEditTime) { |
9299c8e5 | 176 | $this->lastEditTime = $lastEditTime; |
5158aa21 MS |
177 | |
178 | return $this; | |
179 | } | |
180 | ||
181 | /** | |
182 | * @inheritDoc | |
183 | */ | |
7b43decd | 184 | public function populate() { |
5158aa21 MS |
185 | parent::populate(); |
186 | ||
187 | $this->getDocument()->getDataHandler()->add(new CustomFormFieldDataProcessor('wysiwyg', function(IFormDocument $document, array $parameters) { | |
8bdbb251 | 188 | if ($this->checkDependencies()) { |
f3a825e9 | 189 | $parameters[$this->getObjectProperty() . '_htmlInputProcessor'] = $this->htmlInputProcessor; |
8bdbb251 | 190 | } |
5158aa21 MS |
191 | |
192 | return $parameters; | |
193 | })); | |
194 | ||
195 | return $this; | |
196 | } | |
0dc68d99 MS |
197 | |
198 | /** | |
199 | * Sets the data required for advanced quote support for when quotable content is present | |
200 | * on the active page and returns this field. | |
201 | * | |
202 | * Calling this method automatically enables quote support for this field. | |
203 | * | |
204 | * @param string $objectType name of the relevant `com.woltlab.wcf.message.quote` object type | |
205 | * @param string $actionClass action class implementing `wcf\data\IMessageQuoteAction` | |
206 | * @param string[] $selectors selectors for the quotable content (required keys: `container`, `messageBody`, and `messageContent`) | |
207 | * @return static | |
208 | * | |
209 | * @throws \InvalidArgumentException if any of the given arguments is invalid | |
210 | */ | |
211 | public function quoteData($objectType, $actionClass, array $selectors = []) { | |
212 | if (ObjectTypeCache::getInstance()->getObjectTypeByName('com.woltlab.wcf.message.quote', $objectType) === null) { | |
213 | throw new \InvalidArgumentException("Unknown message quote object type '{$objectType}'."); | |
214 | } | |
215 | ||
216 | if (!class_exists($actionClass)) { | |
217 | throw new \InvalidArgumentException("Unknown class '{$actionClass}'"); | |
218 | } | |
219 | if (!is_subclass_of($actionClass, IMessageQuoteAction::class)) { | |
220 | throw new \InvalidArgumentException("'{$actionClass}' does not implement '" . IMessageQuoteAction::class . "'."); | |
221 | } | |
222 | ||
223 | if (!empty($selectors)) { | |
224 | foreach (['container', 'messageBody', 'messageContent'] as $selector) { | |
225 | if (!isset($selectors[$selector])) { | |
226 | throw new \InvalidArgumentException("Missing selector '{$selector}'."); | |
227 | } | |
228 | } | |
229 | } | |
230 | ||
231 | $this->supportQuotes(); | |
232 | ||
233 | $this->quoteData = [ | |
234 | 'actionClass' => $actionClass, | |
235 | 'objectType' => $objectType, | |
236 | 'selectors' => $selectors | |
237 | ]; | |
238 | ||
239 | return $this; | |
240 | } | |
5158aa21 MS |
241 | |
242 | /** | |
243 | * @inheritDoc | |
244 | */ | |
7b43decd | 245 | public function readValue() { |
4b683ecd MS |
246 | if ($this->getDocument()->hasRequestData($this->getPrefixedId())) { |
247 | $value = $this->getDocument()->getRequestData($this->getPrefixedId()); | |
248 | ||
249 | if (is_string($value)) { | |
9299c8e5 | 250 | $this->value = StringUtil::trim($value); |
4b683ecd | 251 | } |
5158aa21 MS |
252 | } |
253 | ||
0dc68d99 MS |
254 | if ($this->supportsQuotes()) { |
255 | MessageQuoteManager::getInstance()->readFormParameters(); | |
256 | } | |
257 | ||
5158aa21 MS |
258 | return $this; |
259 | } | |
260 | ||
71212588 MS |
261 | /** |
262 | * Sets if the form field supports attachments and returns this field. | |
263 | * | |
264 | * @param boolean $supportAttachments | |
26e502ba | 265 | * @return WysiwygFormField this field |
71212588 MS |
266 | */ |
267 | public function supportAttachments($supportAttachments = true) { | |
268 | $this->supportAttachments = $supportAttachments; | |
269 | ||
270 | return $this; | |
271 | } | |
272 | ||
273 | /** | |
274 | * Sets if the form field supports mentions and returns this field. | |
275 | * | |
276 | * @param boolean $supportMentions | |
26e502ba | 277 | * @return WysiwygFormField this field |
71212588 MS |
278 | */ |
279 | public function supportMentions($supportMentions = true) { | |
280 | $this->supportMentions = $supportMentions; | |
281 | ||
282 | return $this; | |
283 | } | |
284 | ||
0dc68d99 MS |
285 | /** |
286 | * Sets if the form field supports quotes and returns this field. | |
287 | * | |
288 | * @param boolean $supportQuotes | |
289 | * @return WysiwygFormField this field | |
290 | */ | |
291 | public function supportQuotes($supportQuotes = true) { | |
292 | $this->supportQuotes = $supportQuotes; | |
293 | ||
294 | if (!$this->supportsQuotes()) { | |
295 | // unset previously set quote data | |
296 | $this->quoteData = null; | |
297 | } | |
298 | else { | |
299 | MessageQuoteManager::getInstance()->readParameters(); | |
300 | } | |
301 | ||
302 | return $this; | |
303 | } | |
304 | ||
71212588 MS |
305 | /** |
306 | * Returns `true` if the form field supports attachments and returns `false` otherwise. | |
307 | * | |
308 | * Important: If this method returns `true`, it does not necessarily mean that attachment | |
309 | * support will also work as that is the task of `WysiwygAttachmentFormField`. This method | |
310 | * is primarily relevant to inform the JavaScript API that the field supports attachments | |
311 | * so that the relevant editor plugin is loaded. | |
312 | * | |
313 | * By default, attachments are not supported. | |
314 | * | |
315 | * @return boolean | |
316 | */ | |
317 | public function supportsAttachments() { | |
318 | return $this->supportAttachments; | |
319 | } | |
320 | ||
321 | /** | |
322 | * Returns `true` if the form field supports mentions and returns `false` otherwise. | |
323 | * | |
324 | * By default, mentions are not supported. | |
325 | * | |
326 | * @return boolean | |
327 | */ | |
328 | public function supportsMentions() { | |
329 | return $this->supportMentions; | |
330 | } | |
331 | ||
0dc68d99 MS |
332 | /** |
333 | * Returns `true` if the form field supports quotes and returns `false` otherwise. | |
334 | * | |
a11099b7 | 335 | * By default, quotes are not supported. |
0dc68d99 MS |
336 | * |
337 | * @return boolean | |
338 | */ | |
339 | public function supportsQuotes() { | |
477f6668 | 340 | return $this->supportQuotes; |
0dc68d99 MS |
341 | } |
342 | ||
5158aa21 MS |
343 | /** |
344 | * @inheritDoc | |
345 | */ | |
346 | public function validate() { | |
6fc348d5 MS |
347 | $this->htmlInputProcessor = new HtmlInputProcessor(); |
348 | $this->htmlInputProcessor->process($this->getValue(), $this->getObjectType()->objectType); | |
349 | ||
350 | if ($this->isRequired() && $this->htmlInputProcessor->appearsToBeEmpty()) { | |
5158aa21 MS |
351 | $this->addValidationError(new FormFieldValidationError('empty')); |
352 | } | |
353 | else { | |
6fc348d5 MS |
354 | $message = $this->htmlInputProcessor->getTextContent(); |
355 | $this->validateMinimumLength($message); | |
356 | $this->validateMaximumLength($message); | |
5158aa21 MS |
357 | } |
358 | ||
5158aa21 MS |
359 | parent::validate(); |
360 | } | |
361 | } |