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