[CLEANUP] EXT:backend/Classes/Wizard/*.php
[Packages/TYPO3.CMS.git] / typo3 / sysext / backend / Classes / Controller / Wizard / ColorpickerController.php
1 <?php
2 namespace TYPO3\CMS\Backend\Controller\Wizard;
3
4 /*
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16
17 use TYPO3\CMS\Backend\Template\DocumentTemplate;
18 use TYPO3\CMS\Backend\Utility\BackendUtility;
19 use TYPO3\CMS\Core\Utility\GeneralUtility;
20
21 /**
22 * Script Class for colorpicker wizard
23 *
24 * @author Mathias Schreiber <schreiber@wmdb.de>
25 * @author Peter Kühn <peter@kuehn.com>
26 * @author Kasper Skårhøj <typo3@typo3.com>
27 */
28 class ColorpickerController extends AbstractWizardController {
29
30 /**
31 * Wizard parameters, coming from FormEngine linking to the wizard.
32 *
33 * @var array
34 */
35 public $P;
36
37 /**
38 * Value of the current color picked.
39 *
40 * @var string
41 */
42 public $colorValue;
43
44 /**
45 * Serialized functions for changing the field...
46 * Necessary to call when the value is transferred to the FormEngine since the form might
47 * need to do internal processing. Otherwise the value is simply not be saved.
48 *
49 * @var string
50 */
51 public $fieldChangeFunc;
52
53 /**
54 * @var string
55 */
56 protected $fieldChangeFuncHash;
57
58 /**
59 * Form name (from opener script)
60 *
61 * @var string
62 */
63 public $fieldName;
64
65 /**
66 * Field name (from opener script)
67 *
68 * @var string
69 */
70 public $formName;
71
72 /**
73 * ID of element in opener script for which to set color.
74 *
75 * @var string
76 */
77 public $md5ID;
78
79 /**
80 * Internal: If FALSE, a frameset is rendered, if TRUE the content of the picker script.
81 *
82 * @var int
83 */
84 public $showPicker;
85
86 /**
87 * @var string
88 */
89 public $HTMLcolorList = 'aqua,black,blue,fuchsia,gray,green,lime,maroon,navy,olive,purple,red,silver,teal,yellow,white';
90
91 /**
92 * @var string
93 */
94 public $pickerImage = '';
95
96 /**
97 * Error message if image not found.
98 *
99 * @var string
100 */
101 public $imageError = '';
102
103 /**
104 * Document template object
105 *
106 * @var DocumentTemplate
107 */
108 public $doc;
109
110 /**
111 * @var string
112 */
113 public $content;
114
115 /**
116 * @var string
117 */
118 protected $exampleImg;
119
120 /**
121 * Constructor
122 */
123 public function __construct() {
124 $this->getLanguageService()->includeLLFile('EXT:lang/locallang_wizards.xlf');
125 $GLOBALS['SOBE'] = $this;
126
127 $this->init();
128 }
129
130 /**
131 * Initialises the Class
132 *
133 * @return void
134 */
135 protected function init() {
136 // Setting GET vars (used in frameset script):
137 $this->P = GeneralUtility::_GP('P');
138 // Setting GET vars (used in colorpicker script):
139 $this->colorValue = GeneralUtility::_GP('colorValue');
140 $this->fieldChangeFunc = GeneralUtility::_GP('fieldChangeFunc');
141 $this->fieldChangeFuncHash = GeneralUtility::_GP('fieldChangeFuncHash');
142 $this->fieldName = GeneralUtility::_GP('fieldName');
143 $this->formName = GeneralUtility::_GP('formName');
144 $this->md5ID = GeneralUtility::_GP('md5ID');
145 $this->exampleImg = GeneralUtility::_GP('exampleImg');
146 // Resolving image (checking existence etc.)
147 $this->imageError = '';
148 if ($this->exampleImg) {
149 $this->pickerImage = GeneralUtility::getFileAbsFileName($this->exampleImg, 1, 1);
150 if (!$this->pickerImage || !@is_file($this->pickerImage)) {
151 $this->imageError = 'ERROR: The image, "' . $this->exampleImg . '", could not be found!';
152 }
153 }
154 $update = '';
155 if ($this->areFieldChangeFunctionsValid()) {
156 // Setting field-change functions:
157 $fieldChangeFuncArr = unserialize($this->fieldChangeFunc);
158 unset($fieldChangeFuncArr['alert']);
159 foreach ($fieldChangeFuncArr as $v) {
160 $update .= '
161 parent.opener.' . $v;
162 }
163 }
164 // Initialize document object:
165 $this->doc = GeneralUtility::makeInstance(DocumentTemplate::class);
166 $this->doc->backPath = $this->getBackPath();
167 $this->doc->JScode = $this->doc->wrapScriptTags('
168 function checkReference() { //
169 if (parent.opener && parent.opener.document && parent.opener.document.' . $this->formName . ' && parent.opener.document.' . $this->formName . '["' . $this->fieldName . '"]) {
170 return parent.opener.document.' . $this->formName . '["' . $this->fieldName . '"];
171 } else {
172 close();
173 }
174 }
175 function changeBGcolor(color) { // Changes the color in the table sample back in the TCEform.
176 if (parent.opener.document.layers) {
177 parent.opener.document.layers["' . $this->md5ID . '"].bgColor = color;
178 } else if (parent.opener.document.all) {
179 parent.opener.document.all["' . $this->md5ID . '"].style.background = color;
180 } else if (parent.opener.document.getElementById && parent.opener.document.getElementById("' . $this->md5ID . '")) {
181 parent.opener.document.getElementById("' . $this->md5ID . '").bgColor = color;
182 }
183 }
184 function setValue(input) { //
185 var field = checkReference();
186 if (field) {
187 field.value = input;
188 ' . $update . '
189 changeBGcolor(input);
190 }
191 }
192 function getValue() { //
193 var field = checkReference();
194 return field.value;
195 }
196 ');
197 // Start page:
198 $this->content .= $this->doc->startPage($this->getLanguageService()->getLL('colorpicker_title'));
199 }
200
201 /**
202 * Main Method, rendering either colorpicker or frameset depending on ->showPicker
203 *
204 * @return void
205 */
206 public function main() {
207 // Show frameset by default:
208 if (!GeneralUtility::_GP('showPicker')) {
209 $this->frameSet();
210 } else {
211 // Putting together the items into a form:
212 $content = '
213 <form name="colorform" method="post" action="' . htmlspecialchars(BackendUtility::getModuleUrl('wizard_colorpicker')) . '">
214 ' . $this->colorMatrix() . '
215 ' . $this->colorList() . '
216 ' . $this->colorImage() . '
217
218 <!-- Value box: -->
219 <p class="c-head">' . $this->getLanguageService()->getLL('colorpicker_colorValue', TRUE) . '</p>
220 <table border="0" cellpadding="0" cellspacing="3">
221 <tr>
222 <td>
223 <input type="text" ' . $this->doc->formWidth(7) . ' maxlength="10" name="colorValue" value="' . htmlspecialchars($this->colorValue) . '" />
224 </td>
225 <td style="background-color:' . htmlspecialchars($this->colorValue) . '; border: 1px solid black;">
226 <span style="color: black;">' . $this->getLanguageService()->getLL('colorpicker_black', TRUE) . '</span>&nbsp;<span style="color: white;">' . $this->getLanguageService()->getLL('colorpicker_white', TRUE) . '</span>
227 </td>
228 <td>
229 <input class="btn btn-default" type="submit" name="save_close" value="' . $this->getLanguageService()->getLL('colorpicker_setClose', TRUE) . '" />
230 </td>
231 </tr>
232 </table>
233
234 <!-- Hidden fields with values that has to be kept constant -->
235 <input type="hidden" name="showPicker" value="1" />
236 <input type="hidden" name="fieldChangeFunc" value="' . htmlspecialchars($this->fieldChangeFunc) . '" />
237 <input type="hidden" name="fieldChangeFuncHash" value="' . htmlspecialchars($this->fieldChangeFuncHash) . '" />
238 <input type="hidden" name="fieldName" value="' . htmlspecialchars($this->fieldName) . '" />
239 <input type="hidden" name="formName" value="' . htmlspecialchars($this->formName) . '" />
240 <input type="hidden" name="md5ID" value="' . htmlspecialchars($this->md5ID) . '" />
241 <input type="hidden" name="exampleImg" value="' . htmlspecialchars($this->exampleImg) . '" />
242 </form>';
243 // If the save/close button is clicked, then close:
244 if (GeneralUtility::_GP('save_close')) {
245 $content .= $this->doc->wrapScriptTags('
246 setValue(' . GeneralUtility::quoteJSvalue($this->colorValue) . ');
247 parent.close();
248 ');
249 }
250 // Output:
251 $this->content .= $this->doc->section($this->getLanguageService()->getLL('colorpicker_title'), $content, 0, 1);
252 }
253 }
254
255 /**
256 * Returns the sourcecode to the browser
257 *
258 * @return void
259 */
260 public function printContent() {
261 $this->content .= $this->doc->endPage();
262 $this->content = $this->doc->insertStylesAndJS($this->content);
263 echo $this->content;
264 }
265
266 /**
267 * Returns a frameset so our JavaScript Reference isn't lost
268 * Took some brains to figure this one out ;-)
269 * If Peter wouldn't have been I would've gone insane...
270 *
271 * @return void
272 */
273 public function frameSet() {
274 $this->getDocumentTemplate()->JScode = $this->getDocumentTemplate()->wrapScriptTags('
275 if (!window.opener) {
276 alert("ERROR: Sorry, no link to main window... Closing");
277 close();
278 }
279 ');
280 $this->getDocumentTemplate()->startPage($this->getLanguageService()->getLL('colorpicker_title'));
281
282 // URL for the inner main frame:
283 $url = BackendUtility::getModuleUrl(
284 'wizard_colorpicker',
285 array(
286 'showPicker' => 1,
287 'colorValue' => $this->P['currentValue'],
288 'fieldName' => $this->P['itemName'],
289 'formName' => $this->P['formName'],
290 'exampleImg' => $this->P['exampleImg'],
291 'md5ID' => $this->P['md5ID'],
292 'fieldChangeFunc' => serialize($this->P['fieldChangeFunc']),
293 'fieldChangeFuncHash' => $this->P['fieldChangeFuncHash'],
294 )
295 );
296 $this->content = $this->getDocumentTemplate()->getPageRenderer()->render(\TYPO3\CMS\Core\Page\PageRenderer::PART_HEADER) . '
297 <frameset rows="*,1" framespacing="0" frameborder="0" border="0">
298 <frame name="content" src="' . htmlspecialchars($url) . '" marginwidth="0" marginheight="0" frameborder="0" scrolling="auto" noresize="noresize" />
299 <frame name="menu" src="' . htmlspecialchars(BackendUtility::getModuleUrl('dummy')) . '" marginwidth="0" marginheight="0" frameborder="0" scrolling="no" noresize="noresize" />
300 </frameset>
301 </html>';
302 }
303
304 /************************************
305 *
306 * Rendering of various color selectors
307 *
308 ************************************/
309 /**
310 * Creates a color matrix table
311 *
312 * @return string
313 */
314 public function colorMatrix() {
315 $steps = 51;
316 // Get colors:
317 $color = array();
318 for ($rr = 0; $rr < 256; $rr += $steps) {
319 for ($gg = 0; $gg < 256; $gg += $steps) {
320 for ($bb = 0; $bb < 256; $bb += $steps) {
321 $color[] = '#' . substr(('0' . dechex($rr)), -2) . substr(('0' . dechex($gg)), -2) . substr(('0' . dechex($bb)), -2);
322 }
323 }
324 }
325 // Traverse colors:
326 $columns = 24;
327 $rows = 0;
328 $tRows = array();
329 while (isset($color[$columns * $rows])) {
330 $tCells = array();
331 for ($i = 0; $i < $columns; $i++) {
332 $tCells[] = '
333 <td bgcolor="' . $color[($columns * $rows + $i)] . '" onclick="document.colorform.colorValue.value = ' . GeneralUtility::quoteJSvalue($color[($columns * $rows + $i)]) . '; document.colorform.submit();" title="' . $color[($columns * $rows + $i)] . '">&nbsp;&nbsp;</td>';
334 }
335 $tRows[] = '
336 <tr>' . implode('', $tCells) . '
337 </tr>';
338 $rows++;
339 }
340 $table = '
341 <p class="c-head">' . $this->getLanguageService()->getLL('colorpicker_fromMatrix', TRUE) . '</p>
342 <table border="0" cellpadding="1" cellspacing="1" style="width:100%; border: 1px solid black; cursor:crosshair;">' . implode('', $tRows) . '
343 </table>';
344 return $table;
345 }
346
347 /**
348 * Creates a selector box with all HTML color names.
349 *
350 * @return string
351 */
352 public function colorList() {
353 // Initialize variables:
354 $colors = explode(',', $this->HTMLcolorList);
355 $currentValue = strtolower($this->colorValue);
356 $opt = array();
357 $opt[] = '<option value=""></option>';
358 // Traverse colors, making option tags for selector box.
359 foreach ($colors as $colorName) {
360 $opt[] = '<option style="background-color: ' . $colorName . ';" value="' . htmlspecialchars($colorName) . '"' . ($currentValue === $colorName ? ' selected="selected"' : '') . '>' . htmlspecialchars($colorName) . '</option>';
361 }
362 // Compile selector box and return result:
363 $output = '
364 <p class="c-head">' . $this->getLanguageService()->getLL('colorpicker_fromList', TRUE) . '</p>
365 <select onchange="document.colorform.colorValue.value = this.options[this.selectedIndex].value; document.colorform.submit(); return false;">
366 ' . implode('
367 ', $opt) . '
368 </select><br />';
369 return $output;
370 }
371
372 /**
373 * Creates a color image selector
374 *
375 * @return string
376 */
377 public function colorImage() {
378 // Handling color-picker image if any:
379 if (!$this->imageError) {
380 if ($this->pickerImage) {
381 if (GeneralUtility::_POST('coords_x')) {
382 /* @var $image \TYPO3\CMS\Core\Imaging\GraphicalFunctions */
383 $image = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Imaging\GraphicalFunctions::class);
384 $this->colorValue = '#' . $this->getIndex($image->imageCreateFromFile($this->pickerImage), GeneralUtility::_POST('coords_x'), GeneralUtility::_POST('coords_y'));
385 }
386 $pickerFormImage = '
387 <p class="c-head">' . $this->getLanguageService()->getLL('colorpicker_fromImage', TRUE) . '</p>
388 <input type="image" src="../' . \TYPO3\CMS\Core\Utility\PathUtility::stripPathSitePrefix($this->pickerImage) . '" name="coords" style="cursor:crosshair;" /><br />';
389 } else {
390 $pickerFormImage = '';
391 }
392 } else {
393 $pickerFormImage = '
394 <p class="c-head">' . htmlspecialchars($this->imageError) . '</p>';
395 }
396 return $pickerFormImage;
397 }
398
399 /**
400 * Gets the HTML (Hex) Color Code for the selected pixel of an image
401 * This method handles the correct imageResource no matter what format
402 *
403 * @param resource $im Valid ImageResource returned by \TYPO3\CMS\Core\Imaging\GraphicalFunctions::imageCreateFromFile
404 * @param int $x X-Coordinate of the pixel that should be checked
405 * @param int $y Y-Coordinate of the pixel that should be checked
406 * @return string HEX RGB value for color
407 * @see colorImage()
408 */
409 public function getIndex($im, $x, $y) {
410 $rgb = ImageColorAt($im, $x, $y);
411 $colorRgb = imagecolorsforindex($im, $rgb);
412 $index['r'] = dechex($colorRgb['red']);
413 $index['g'] = dechex($colorRgb['green']);
414 $index['b'] = dechex($colorRgb['blue']);
415 $hexValue = array();
416 foreach ($index as $value) {
417 if (strlen($value) === 1) {
418 $hexValue[] = strtoupper('0' . $value);
419 } else {
420 $hexValue[] = strtoupper($value);
421 }
422 }
423 $hex = implode('', $hexValue);
424 return $hex;
425 }
426
427 /**
428 * Determines whether submitted field change functions are valid
429 * and are coming from the system and not from an external abuse.
430 *
431 * @return bool Whether the submitted field change functions are valid
432 */
433 protected function areFieldChangeFunctionsValid() {
434 return $this->fieldChangeFunc && $this->fieldChangeFuncHash && $this->fieldChangeFuncHash === GeneralUtility::hmac($this->fieldChangeFunc);
435 }
436
437 }