Merge branch '3.1' into 5.2
[GitHub/WoltLab/WCF.git] / wcfsetup / install / files / lib / acp / form / BBCodeAddForm.class.php
1 <?php
2 namespace wcf\acp\form;
3 use wcf\data\bbcode\attribute\BBCodeAttributeAction;
4 use wcf\data\bbcode\BBCode;
5 use wcf\data\bbcode\BBCodeAction;
6 use wcf\data\bbcode\BBCodeEditor;
7 use wcf\form\AbstractForm;
8 use wcf\system\exception\UserInputException;
9 use wcf\system\language\I18nHandler;
10 use wcf\system\Regex;
11 use wcf\system\WCF;
12 use wcf\util\StringUtil;
13
14 /**
15 * Shows the bbcode add form.
16 *
17 * @author Tim Duesterhus
18 * @copyright 2001-2019 WoltLab GmbH
19 * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
20 * @package WoltLabSuite\Core\Acp\Form
21 */
22 class BBCodeAddForm extends AbstractForm {
23 /**
24 * @inheritDoc
25 */
26 public $activeMenuItem = 'wcf.acp.menu.link.bbcode.add';
27
28 /**
29 * allowed child bbcodes
30 * @var string
31 */
32 public $allowedChildren = 'all';
33
34 /**
35 * list of attributes
36 * @var object[]
37 */
38 public $attributes = [];
39
40 /**
41 * tag name
42 * @var string
43 */
44 public $bbcodeTag = '';
45
46 /**
47 * editor button label
48 * @var string
49 */
50 public $buttonLabel = '';
51
52 /**
53 * class name
54 * @var string
55 */
56 public $className = '';
57
58 /**
59 * closing html tag
60 * @var string
61 */
62 public $htmlClose = '';
63
64 /**
65 * opening html tag
66 * @var string
67 */
68 public $htmlOpen = '';
69
70 /**
71 * true if bbcode is a block element
72 * @var boolean
73 */
74 public $isBlockElement = false;
75
76 /**
77 * true, if bbcode contains source code
78 * @var boolean
79 */
80 public $isSourceCode = false;
81
82 /**
83 * @inheritDoc
84 */
85 public $neededPermissions = ['admin.content.bbcode.canManageBBCode'];
86
87 /**
88 * @inheritDoc
89 */
90 public $templateName = 'bbcodeAdd';
91
92 /**
93 * show editor button
94 * @var boolean
95 */
96 public $showButton = false;
97
98 /**
99 * wysiwyg editor icon
100 * @var string
101 */
102 public $wysiwygIcon = '';
103
104 /**
105 * @inheritDoc
106 */
107 public function readParameters() {
108 parent::readParameters();
109
110 I18nHandler::getInstance()->register('buttonLabel');
111 }
112
113 /**
114 * @inheritDoc
115 */
116 public function readFormParameters() {
117 parent::readFormParameters();
118
119 if (isset($_POST['allowedChildren'])) $this->allowedChildren = StringUtil::trim($_POST['allowedChildren']);
120 if (isset($_POST['attributes'])) $this->attributes = $_POST['attributes'];
121 if (isset($_POST['bbcodeTag'])) $this->bbcodeTag = mb_strtolower(StringUtil::trim($_POST['bbcodeTag']));
122 if (isset($_POST['className'])) $this->className = StringUtil::trim($_POST['className']);
123 if (isset($_POST['htmlClose'])) $this->htmlClose = StringUtil::trim($_POST['htmlClose']);
124 if (isset($_POST['htmlOpen'])) $this->htmlOpen = StringUtil::trim($_POST['htmlOpen']);
125 if (isset($_POST['isBlockElement'])) $this->isBlockElement = true;
126 if (isset($_POST['isSourceCode'])) $this->isSourceCode = true;
127 if (isset($_POST['showButton'])) $this->showButton = true;
128 if (isset($_POST['wysiwygIcon'])) $this->wysiwygIcon = StringUtil::trim($_POST['wysiwygIcon']);
129
130 $attributeNo = 0;
131 foreach ($this->attributes as $key => $val) {
132 $val['attributeNo'] = $attributeNo++;
133 $val['required'] = (int) isset($val['required']);
134 $val['useText'] = (int) isset($val['useText']);
135 $this->attributes[$key] = (object) $val;
136 }
137
138 I18nHandler::getInstance()->readValues();
139 $this->readButtonLabelFormParameter();
140 }
141
142 /**
143 * Reads the form parameter for the button label.
144 */
145 protected function readButtonLabelFormParameter() {
146 if (I18nHandler::getInstance()->isPlainValue('buttonLabel')) $this->buttonLabel = I18nHandler::getInstance()->getValue('buttonLabel');
147 }
148
149 /**
150 * @inheritDoc
151 */
152 public function validate() {
153 parent::validate();
154
155 // tag name must not be empty
156 if (empty($this->bbcodeTag)) {
157 throw new UserInputException('bbcodeTag');
158 }
159
160 // tag may only contain alphanumeric chars
161 if (!Regex::compile('^[a-z0-9]+$', Regex::CASE_INSENSITIVE)->match($this->bbcodeTag)) {
162 throw new UserInputException('bbcodeTag', 'invalid');
163 }
164
165 // disallow the Pseudo-BBCodes all and none
166 if ($this->bbcodeTag == 'all' || $this->bbcodeTag == 'none') {
167 throw new UserInputException('bbcodeTag', 'invalid');
168 }
169
170 // check whether the tag is in use
171 $this->validateBBCodeTagUsage();
172
173 // validate class
174 if (!empty($this->className) && !class_exists($this->className)) {
175 throw new UserInputException('className', 'notFound');
176 }
177
178 // validate attributes
179 foreach ($this->attributes as $attribute) {
180 // Check whether the pattern is a valid regex
181 if (!Regex::compile($attribute->validationPattern)->isValid()) {
182 throw new UserInputException('attributeValidationPattern'.$attribute->attributeNo, 'invalid');
183 }
184 }
185
186 // button
187 if ($this->showButton) {
188 // validate label
189 if (!I18nHandler::getInstance()->validateValue('buttonLabel')) {
190 if (I18nHandler::getInstance()->isPlainValue('buttonLabel')) {
191 throw new UserInputException('buttonLabel');
192 }
193 else {
194 throw new UserInputException('buttonLabel', 'multilingual');
195 }
196 }
197
198 // validate image path
199 if (empty($this->wysiwygIcon)) {
200 throw new UserInputException('wysiwygIcon');
201 }
202 }
203 else {
204 $this->buttonLabel = '';
205 }
206 }
207
208 /**
209 * Validates the bbcode tag usage.
210 * @throws UserInputException
211 */
212 protected function validateBBCodeTagUsage() {
213 $bbcode = BBCode::getBBCodeByTag($this->bbcodeTag);
214 if ($bbcode->bbcodeID) {
215 throw new UserInputException('bbcodeTag', 'inUse');
216 }
217 }
218
219 /**
220 * @inheritDoc
221 */
222 public function save() {
223 parent::save();
224
225 // save bbcode
226 $this->objectAction = new BBCodeAction([], 'create', ['data' => array_merge($this->additionalFields, [
227 'bbcodeTag' => $this->bbcodeTag,
228 'buttonLabel' => $this->buttonLabel,
229 'className' => $this->className,
230 'htmlOpen' => $this->htmlOpen,
231 'htmlClose' => $this->htmlClose,
232 'isBlockElement' => $this->isBlockElement ? 1 : 0,
233 'isSourceCode' => $this->isSourceCode ? 1 : 0,
234 'packageID' => 1,
235 'showButton' => $this->showButton ? 1 : 0,
236 'wysiwygIcon' => $this->wysiwygIcon
237 ])]);
238 $returnValues = $this->objectAction->executeAction();
239 foreach ($this->attributes as $attribute) {
240 $attributeAction = new BBCodeAttributeAction([], 'create', ['data' => [
241 'bbcodeID' => $returnValues['returnValues']->bbcodeID,
242 'attributeNo' => $attribute->attributeNo,
243 'attributeHtml' => $attribute->attributeHtml,
244 'validationPattern' => $attribute->validationPattern,
245 'required' => $attribute->required,
246 'useText' => $attribute->useText
247 ]]);
248 $attributeAction->executeAction();
249 }
250
251 if ($this->showButton && !I18nHandler::getInstance()->isPlainValue('buttonLabel')) {
252 $bbcodeID = $returnValues['returnValues']->bbcodeID;
253 I18nHandler::getInstance()->save('buttonLabel', 'wcf.editor.button.button'.$bbcodeID, 'wcf.editor', 1);
254
255 // update button label
256 $bbcodeEditor = new BBCodeEditor($returnValues['returnValues']);
257 $bbcodeEditor->update([
258 'buttonLabel' => 'wcf.editor.button.button'.$bbcodeID
259 ]);
260 }
261
262 $this->saved();
263
264 // reset values
265 $this->bbcodeTag = $this->htmlOpen = $this->htmlClose = $this->className = $this->buttonLabel = $this->wysiwygIcon = '';
266 $this->attributes = [];
267 $this->isBlockElement = $this->isSourceCode = $this->showButton = false;
268
269 I18nHandler::getInstance()->reset();
270
271 // show success message
272 WCF::getTPL()->assign('success', true);
273 }
274
275 /**
276 * @inheritDoc
277 */
278 public function assignVariables() {
279 parent::assignVariables();
280
281 I18nHandler::getInstance()->assignVariables();
282
283 WCF::getTPL()->assign([
284 'action' => 'add',
285 'attributes' => $this->attributes,
286 'bbcodeTag' => $this->bbcodeTag,
287 'buttonLabel' => $this->buttonLabel,
288 'className' => $this->className,
289 'htmlOpen' => $this->htmlOpen,
290 'htmlClose' => $this->htmlClose,
291 'isBlockElement' => $this->isBlockElement,
292 'isSourceCode' => $this->isSourceCode,
293 'showButton' => $this->showButton,
294 'wysiwygIcon' => $this->wysiwygIcon
295 ]);
296 }
297 }