Merge branch '5.2' into 5.3
[GitHub/WoltLab/WCF.git] / wcfsetup / install / files / lib / acp / form / StyleEditForm.class.php
CommitLineData
6c80f0df
AE
1<?php
2namespace wcf\acp\form;
3use wcf\data\style\Style;
4use wcf\data\style\StyleAction;
5use wcf\form\AbstractForm;
6use wcf\system\exception\IllegalLinkException;
268a850d 7use wcf\system\exception\UserInputException;
1b6a0dfc
TD
8use wcf\system\file\upload\UploadFile;
9use wcf\system\file\upload\UploadHandler;
aa5fecb3 10use wcf\system\language\I18nHandler;
268a850d 11use wcf\system\style\StyleCompiler;
6c80f0df 12use wcf\system\WCF;
5c7386a0 13use wcf\util\FileUtil;
6c80f0df
AE
14
15/**
16 * Shows the style edit form.
17 *
18 * @author Alexander Ebert
7b7b9764 19 * @copyright 2001-2019 WoltLab GmbH
6c80f0df 20 * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
e71525e4 21 * @package WoltLabSuite\Core\Acp\Form
6c80f0df
AE
22 */
23class StyleEditForm extends StyleAddForm {
24 /**
0fcfe5f6 25 * @inheritDoc
6c80f0df 26 */
f02cfd96 27 public $activeMenuItem = 'wcf.acp.menu.link.style.list';
6c80f0df 28
6c80f0df
AE
29 /**
30 * style object
4e25add7 31 * @var Style
6c80f0df 32 */
2e572b29 33 public $style;
6c80f0df
AE
34
35 /**
36 * style id
37 * @var integer
38 */
39 public $styleID = 0;
40
41 /**
0fcfe5f6 42 * @inheritDoc
6c80f0df
AE
43 */
44 public function readParameters() {
45 if (isset($_REQUEST['id'])) $this->styleID = intval($_REQUEST['id']);
46 $this->style = new Style($this->styleID);
47 if (!$this->style->styleID) {
48 throw new IllegalLinkException();
49 }
50
51 parent::readParameters();
52 }
53
bfbc0267
AE
54 /**
55 * @inheritDoc
56 */
57 public function validate() {
58 parent::validate();
59
60 if (!$this->style->isTainted) {
61 $this->parseOverrides('overrideScssCustom');
62 }
63 }
64
268a850d 65 /**
66 * @inheritDoc
67 */
68 public function validateIndividualScss() {
69 $variables = $this->variables;
70 if (!$this->style->isTainted) {
71 $variables['individualScss'] = Style::joinLessVariables($variables['individualScss'], $variables['individualScssCustom']);
72 $variables['overrideScss'] = Style::joinLessVariables($variables['overrideScss'], $variables['overrideScssCustom']);
73
74 unset($variables['individualScssCustom']);
75 unset($variables['overrideScssCustom']);
76 }
77
78 $variables = array_merge(StyleCompiler::getDefaultVariables(), $variables);
79
5c7386a0 80 $this->styleTestFileDir = FileUtil::getTemporaryFilename('style_');
81 FileUtil::makePath($this->styleTestFileDir);
268a850d 82
3eff1581 83 $result = StyleCompiler::getInstance()->testStyle($this->styleTestFileDir, $this->styleName, $this->apiVersion, $this->style->imagePath, $variables);
5c7386a0 84
85 if ($result !== null) {
1b1f7fbe 86 rmdir($this->styleTestFileDir);
87
268a850d 88 throw new UserInputException('individualScss', [
5c7386a0 89 'message' => $result->getMessage(),
268a850d 90 ]);
91 }
92 }
93
6147a666
AE
94 /**
95 * @inheritDoc
96 */
97 protected function enforcePackageNameRestriction() {
98 if ($this->style->isTainted) {
99 parent::enforcePackageNameRestriction();
100 }
101 }
102
811f5a93
AE
103 /**
104 * @inheritDoc
105 */
106 protected function validateApiVersion() {
107 if ($this->style->isTainted) {
108 parent::validateApiVersion();
109 }
110 else {
111 $this->apiVersion = $this->style->apiVersion;
112 }
113 }
114
6c80f0df 115 /**
0fcfe5f6 116 * @inheritDoc
6c80f0df
AE
117 */
118 protected function readStyleVariables() {
119 $this->variables = $this->style->getVariables();
120
121 // fix empty values ~""
122 foreach ($this->variables as &$variableValue) {
123 if ($variableValue == '~""') {
124 $variableValue = '';
125 }
126 }
127 unset($variableValue);
90b4b964
AE
128
129 if (!$this->style->isTainted) {
97ec0367
MW
130 $tmp = Style::splitLessVariables($this->variables['individualScss']);
131 $this->variables['individualScss'] = $tmp['preset'];
132 $this->variables['individualScssCustom'] = $tmp['custom'];
90b4b964 133
97ec0367
MW
134 $tmp = Style::splitLessVariables($this->variables['overrideScss']);
135 $this->variables['overrideScss'] = $tmp['preset'];
136 $this->variables['overrideScssCustom'] = $tmp['custom'];
90b4b964 137 }
5c1f7926 138
1ecaac09 139 if ($this->variables['pageLogo'] && file_exists($this->style->getAssetPath().$this->variables['pageLogo'])) {
5c1f7926
TD
140 $file = new UploadFile($this->style->getAssetPath().$this->variables['pageLogo'], basename($this->variables['pageLogo']), true, true, true);
141 UploadHandler::getInstance()->registerFilesByField('pageLogo', [
142 $file,
143 ]);
144 }
1ecaac09 145 if ($this->variables['pageLogoMobile'] && file_exists($this->style->getAssetPath().$this->variables['pageLogoMobile'])) {
5c1f7926
TD
146 $file = new UploadFile($this->style->getAssetPath().$this->variables['pageLogoMobile'], basename($this->variables['pageLogoMobile']), true, true, true);
147 UploadHandler::getInstance()->registerFilesByField('pageLogoMobile', [
148 $file,
149 ]);
150 }
90b4b964
AE
151 }
152
153 /**
0fcfe5f6 154 * @inheritDoc
90b4b964
AE
155 */
156 protected function setVariables() {
157 parent::setVariables();
158
159 if (!$this->style->isTainted) {
97ec0367
MW
160 $this->specialVariables[] = 'individualScssCustom';
161 $this->specialVariables[] = 'overrideScssCustom';
90b4b964 162 }
6c80f0df
AE
163 }
164
165 /**
0fcfe5f6 166 * @inheritDoc
6c80f0df
AE
167 */
168 public function readData() {
169 parent::readData();
170
aa5fecb3
AE
171 I18nHandler::getInstance()->setOptions('styleDescription', PACKAGE_ID, $this->style->styleDescription, 'wcf.style.styleDescription\d+');
172
6c80f0df 173 if (empty($_POST)) {
811f5a93 174 $this->apiVersion = $this->style->apiVersion;
6c80f0df
AE
175 $this->authorName = $this->style->authorName;
176 $this->authorURL = $this->style->authorURL;
177 $this->copyright = $this->style->copyright;
90b4b964 178 $this->isTainted = $this->style->isTainted;
6c80f0df 179 $this->license = $this->style->license;
90b4b964 180 $this->packageName = $this->style->packageName;
6c80f0df
AE
181 $this->styleDate = $this->style->styleDate;
182 $this->styleDescription = $this->style->styleDescription;
183 $this->styleName = $this->style->styleName;
184 $this->styleVersion = $this->style->styleVersion;
185 $this->templateGroupID = $this->style->templateGroupID;
1ecaac09 186 if ($this->style->image && file_exists(WCF_DIR.'images/'.$this->style->image)) {
0825059e 187 $file = new UploadFile(WCF_DIR.'images/'.$this->style->image, $this->style->image, true, true, false);
1b6a0dfc
TD
188 UploadHandler::getInstance()->registerFilesByField('image', [
189 $file,
190 ]);
191 }
1ecaac09 192 if ($this->style->image2x && file_exists(WCF_DIR.'images/'.$this->style->image2x)) {
0825059e 193 $file = new UploadFile(WCF_DIR.'images/'.$this->style->image2x, $this->style->image2x, true, true, false);
1b6a0dfc
TD
194 UploadHandler::getInstance()->registerFilesByField('image2x', [
195 $file,
196 ]);
197 }
1ecaac09 198 if ($this->style->coverPhotoExtension && file_exists($this->style->getCoverPhotoLocation())) {
0825059e
TD
199 $file = new UploadFile($this->style->getCoverPhotoLocation(), $this->style->getCoverPhoto(), true, true, false);
200 UploadHandler::getInstance()->registerFilesByField('coverPhoto', [
201 $file,
202 ]);
203 }
95d803b7
TD
204 if ($this->style->hasFavicon) {
205 foreach (['png', 'jpg', 'gif'] as $extension) {
17271890 206 $filename = "favicon-template.".$extension;
a6e7a5ef
TD
207 if (file_exists($this->style->getAssetPath().$filename)) {
208 $file = new UploadFile($this->style->getAssetPath().$filename, $filename, true, true, false);
95d803b7
TD
209 UploadHandler::getInstance()->registerFilesByField('favicon', [
210 $file,
211 ]);
212 break;
213 }
214 }
95d803b7 215 }
908e40a3
TD
216
217 UploadHandler::getInstance()->registerFilesByField('customAssets', array_map(function ($filename) {
218 return new UploadFile($filename, basename($filename), false, true, true);
219 }, glob($this->style->getAssetPath().'custom/*')));
6c80f0df
AE
220 }
221 }
222
223 /**
0fcfe5f6 224 * @inheritDoc
6c80f0df
AE
225 */
226 public function save() {
e79f851c 227 AbstractForm::save();
6c80f0df 228
939a7c76 229 if (!$this->style->isTainted) {
97ec0367
MW
230 $this->variables['individualScss'] = Style::joinLessVariables($this->variables['individualScss'], $this->variables['individualScssCustom']);
231 $this->variables['overrideScss'] = Style::joinLessVariables($this->variables['overrideScss'], $this->variables['overrideScssCustom']);
90b4b964 232
97ec0367
MW
233 unset($this->variables['individualScssCustom']);
234 unset($this->variables['overrideScssCustom']);
939a7c76 235 }
90b4b964 236
c4593f20
AE
237 // Remove control characters that break the SCSS parser, see https://stackoverflow.com/a/23066553
238 $this->variables['individualScss'] = preg_replace('/[^\PC\s]/u', '', $this->variables['individualScss']);
239
058cbd6a
MS
240 $this->objectAction = new StyleAction([$this->style], 'update', [
241 'data' => array_merge($this->additionalFields, [
6c80f0df
AE
242 'styleName' => $this->styleName,
243 'templateGroupID' => $this->templateGroupID,
6c80f0df
AE
244 'styleVersion' => $this->styleVersion,
245 'styleDate' => $this->styleDate,
6c80f0df 246 'copyright' => $this->copyright,
90b4b964 247 'packageName' => $this->packageName,
6c80f0df
AE
248 'license' => $this->license,
249 'authorName' => $this->authorName,
811f5a93
AE
250 'authorURL' => $this->authorURL,
251 'apiVersion' => $this->apiVersion
058cbd6a 252 ]),
1b6a0dfc 253 'uploads' => $this->uploads,
cc17f302 254 'removedUploads' => $this->removedUploads,
908e40a3 255 'customAssets' => $this->customAssets,
6c80f0df 256 'tmpHash' => $this->tmpHash,
908e40a3 257 'variables' => $this->variables,
058cbd6a 258 ]);
6c80f0df
AE
259 $this->objectAction->executeAction();
260
5c7386a0 261 // save compiled style
262 if ($this->styleTestFileDir && file_exists($this->styleTestFileDir . '/style.css') && file_exists($this->styleTestFileDir . '/style-rtl.css')) {
263 $styleFilename = StyleCompiler::getFilenameForStyle($this->style);
264 rename($this->styleTestFileDir . '/style.css', $styleFilename . '.css');
265 rename($this->styleTestFileDir . '/style-rtl.css', $styleFilename . '-rtl.css');
266
267 rmdir($this->styleTestFileDir);
268 }
269
aa5fecb3
AE
270 // save description
271 I18nHandler::getInstance()->save('styleDescription', $this->style->styleDescription, 'wcf.style');
272
6c80f0df
AE
273 // call saved event
274 $this->saved();
275
276 // reload style object to update preview image
277 $this->style = new Style($this->style->styleID);
278
939a7c76
AE
279 if (!$this->style->isTainted) {
280 $tmp = Style::splitLessVariables($this->variables['individualScss']);
281 $this->variables['individualScss'] = $tmp['preset'];
282 $this->variables['individualScssCustom'] = $tmp['custom'];
283
284 $tmp = Style::splitLessVariables($this->variables['overrideScss']);
285 $this->variables['overrideScss'] = $tmp['preset'];
286 $this->variables['overrideScssCustom'] = $tmp['custom'];
287 }
288
6c80f0df
AE
289 WCF::getTPL()->assign('success', true);
290 }
291
292 /**
0fcfe5f6 293 * @inheritDoc
6c80f0df
AE
294 */
295 public function assignVariables() {
296 parent::assignVariables();
297
aa5fecb3
AE
298 I18nHandler::getInstance()->assignVariables(!empty($_POST));
299
058cbd6a 300 WCF::getTPL()->assign([
6c80f0df 301 'action' => 'edit',
939a7c76 302 'isTainted' => $this->style->isTainted,
6c80f0df 303 'style' => $this->style,
87fc5501 304 'styleID' => $this->styleID,
058cbd6a 305 ]);
6c80f0df
AE
306 }
307}