1 | <?php |
||||||
2 | |||||||
3 | namespace Sunnysideup\SelectedColourPicker\Model\Fields; |
||||||
4 | |||||||
5 | use BimTheBam\NativeColorInput\Form\Field\ColorField; |
||||||
6 | use Fromholdio\ColorPalette\Fields\ColorPaletteField; |
||||||
7 | use SilverStripe\Core\Config\Config; |
||||||
8 | use SilverStripe\Forms\FormField; |
||||||
9 | use SilverStripe\Forms\LiteralField; |
||||||
10 | use SilverStripe\ORM\FieldType\DBField; |
||||||
11 | use Sunnysideup\SelectedColourPicker\Forms\SelectedColourPickerFormFieldDropdown; |
||||||
12 | use Sunnysideup\SelectedColourPicker\ViewableData\SelectedColourPickerFormFieldSwatches; |
||||||
13 | use TractorCow\Colorpicker\Color; |
||||||
14 | |||||||
15 | class DBColour extends Color |
||||||
16 | { |
||||||
17 | protected const DEFAULT_COLOURS = [ |
||||||
18 | '#FF0000' => 'Red', |
||||||
19 | '#0000FF' => 'Blue', |
||||||
20 | '#00FF00' => 'Green', |
||||||
21 | ]; |
||||||
22 | |||||||
23 | /** |
||||||
24 | * please set. |
||||||
25 | * |
||||||
26 | * @var string` |
||||||
27 | */ |
||||||
28 | protected const CSS_CLASS_PREFIX = 'db-colour'; |
||||||
29 | |||||||
30 | /** |
||||||
31 | * please set. |
||||||
32 | * |
||||||
33 | * @var bool |
||||||
34 | */ |
||||||
35 | protected const IS_LIMITED_TO_OPTIONS = true; |
||||||
36 | |||||||
37 | /** |
||||||
38 | * please set. |
||||||
39 | * |
||||||
40 | * @var bool |
||||||
41 | */ |
||||||
42 | protected const IS_BG_COLOUR = true; |
||||||
43 | |||||||
44 | protected static $object_cache = []; |
||||||
45 | private static $colour_picker_field_class_name = SelectedColourPickerFormFieldDropdown::class; |
||||||
46 | |||||||
47 | /** |
||||||
48 | * please set |
||||||
49 | * must be defined as #AABB99 (hex codes). |
||||||
50 | * Needs to be set like this: |
||||||
51 | * ```php |
||||||
52 | * [ |
||||||
53 | * '#fff000' => 'My Colour 1', |
||||||
54 | * '#fff000' => 'My Colour 2', |
||||||
55 | * ]. |
||||||
56 | * |
||||||
57 | * ``` |
||||||
58 | * |
||||||
59 | * @var array |
||||||
60 | */ |
||||||
61 | private static $colours = []; |
||||||
62 | |||||||
63 | /** |
||||||
64 | * You can link colours to other colours. |
||||||
65 | * e.g. |
||||||
66 | * ```php |
||||||
67 | * '#ffffff' => [ |
||||||
68 | * 'link' => '#000000', |
||||||
69 | * 'foreground' => '#000000', |
||||||
70 | * 'background' => '#000000', |
||||||
71 | * ], |
||||||
72 | * '#aabbcc' => [ |
||||||
73 | * 'link' => '#123123', |
||||||
74 | * 'foreground' => '#123312', |
||||||
75 | * 'somethingelse' => '#000000', |
||||||
76 | * ], |
||||||
77 | * ```. |
||||||
78 | * |
||||||
79 | * @var array |
||||||
80 | */ |
||||||
81 | private static $linked_colours = []; |
||||||
82 | |||||||
83 | private static $casting = [ |
||||||
84 | // related colours |
||||||
85 | 'FontColour' => 'Varchar', |
||||||
86 | 'BackgroundColour' => 'Varchar', |
||||||
87 | 'ReadableColour' => 'Varchar', |
||||||
88 | 'RelatedColourByName' => 'Varchar', |
||||||
89 | 'Inverted' => 'Varchar', |
||||||
90 | // css |
||||||
91 | 'CssVariableDefinition' => 'HTMLText', |
||||||
92 | 'CssClass' => 'Varchar', |
||||||
93 | 'CssClassAlternative' => 'Boolean', |
||||||
94 | // booleans |
||||||
95 | 'IsDarkColour' => 'Boolean', |
||||||
96 | 'IsLightColour' => 'Boolean', |
||||||
97 | |||||||
98 | 'Nice' => 'HTMLText', |
||||||
99 | ]; |
||||||
100 | |||||||
101 | public function __construct($name = null, $options = []) |
||||||
102 | { |
||||||
103 | parent::__construct($name, $options); |
||||||
104 | } |
||||||
105 | |||||||
106 | public static function my_colours(): array |
||||||
107 | { |
||||||
108 | return static::get_colour_as_db_field('')->getColours(); |
||||||
109 | } |
||||||
110 | |||||||
111 | public static function get_swatches_field(string $name, string $value): LiteralField |
||||||
112 | { |
||||||
113 | return SelectedColourPickerFormFieldSwatches::get_swatches_field( |
||||||
114 | (string) $name, |
||||||
115 | (string) $value, |
||||||
116 | static::my_colours(), |
||||||
117 | static::IS_BG_COLOUR |
||||||
118 | ); |
||||||
119 | } |
||||||
120 | |||||||
121 | /** |
||||||
122 | * @param string $title |
||||||
123 | * |
||||||
124 | * @return FormField |
||||||
125 | */ |
||||||
126 | public static function get_dropdown_field(string $name, ?string $title = '', ?bool $isBackgroundColour = null) |
||||||
127 | { |
||||||
128 | if (null === $isBackgroundColour) { |
||||||
129 | $isBackgroundColour = static::IS_BG_COLOUR; |
||||||
130 | } |
||||||
131 | $className = Config::inst()->get(static::class, 'colour_picker_field_class_name'); |
||||||
132 | |||||||
133 | return $className::create( |
||||||
134 | $name, |
||||||
135 | $title |
||||||
136 | ) |
||||||
137 | ->setSource(static::my_colours()) |
||||||
138 | ->setLimitedToOptions(static::IS_LIMITED_TO_OPTIONS) |
||||||
139 | ->setIsBgColour($isBackgroundColour) |
||||||
140 | ; |
||||||
141 | } |
||||||
142 | |||||||
143 | public static function get_colours_for_dropdown(?bool $isBackgroundColour = null): ?array |
||||||
144 | { |
||||||
145 | if (null === $isBackgroundColour) { |
||||||
146 | $isBackgroundColour = static::IS_BG_COLOUR; |
||||||
147 | } |
||||||
148 | $colours = static::my_colours(); |
||||||
149 | if (! empty($colours)) { |
||||||
150 | $array = []; |
||||||
151 | |||||||
152 | foreach ($colours as $code => $label) { |
||||||
153 | $textcolour = static::get_font_colour((string) $code); |
||||||
154 | if ($isBackgroundColour) { |
||||||
155 | $array[$code] = [ |
||||||
156 | 'label' => $label, |
||||||
157 | 'background_css' => $code, |
||||||
158 | 'colour_css' => $textcolour, |
||||||
159 | 'sample_text' => 'Aa', |
||||||
160 | ]; |
||||||
161 | } else { |
||||||
162 | $array[$code] = [ |
||||||
163 | 'label' => $label, |
||||||
164 | 'background_css' => $textcolour, |
||||||
165 | 'colour_css' => $code, |
||||||
166 | 'sample_text' => 'Aa', |
||||||
167 | ]; |
||||||
168 | } |
||||||
169 | } |
||||||
170 | |||||||
171 | return $array; |
||||||
172 | } |
||||||
173 | |||||||
174 | return null; |
||||||
175 | } |
||||||
176 | |||||||
177 | /** |
||||||
178 | * Detects if the given colour is light. |
||||||
179 | * |
||||||
180 | * @param string $colour HEX colour code |
||||||
181 | */ |
||||||
182 | public static function get_font_colour(?string $colour = null, ?string $name = '') |
||||||
183 | { |
||||||
184 | if (! $colour) { |
||||||
185 | $colour = '#ffffff'; |
||||||
186 | } |
||||||
187 | $colour = static::is_light_colour((string) $colour) ? '#000000' : '#ffffff'; |
||||||
188 | |||||||
189 | return static::get_colour_as_db_field($colour, $name); |
||||||
190 | } |
||||||
191 | |||||||
192 | /** |
||||||
193 | * @param string $colour HEX colour code |
||||||
194 | */ |
||||||
195 | public static function is_dark_colour(?string $colour = ''): bool |
||||||
196 | { |
||||||
197 | return static::is_light_colour((string) $colour) ? false : true; |
||||||
198 | } |
||||||
199 | |||||||
200 | /** |
||||||
201 | * Detects if the given colour is light. |
||||||
202 | * |
||||||
203 | * @param string $colour HEX colour code |
||||||
204 | */ |
||||||
205 | public static function is_light_colour(?string $colour = ''): bool |
||||||
206 | { |
||||||
207 | return static::get_colour_as_db_field($colour) |
||||||
0 ignored issues
–
show
Bug
introduced
by
![]() |
|||||||
208 | ->Luminance() > 0.5; |
||||||
209 | } |
||||||
210 | |||||||
211 | public static function check_colour(?string $colour, ?bool $isBackgroundColour = false): string |
||||||
212 | { |
||||||
213 | $colour = strtolower($colour); |
||||||
0 ignored issues
–
show
It seems like
$colour can also be of type null ; however, parameter $string of strtolower() does only seem to accept string , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
214 | if ('transparent' === $colour) { |
||||||
215 | return 'transparent'; |
||||||
216 | } |
||||||
217 | if (! strpos($colour, '#')) { |
||||||
218 | $colour = '#' . $colour; |
||||||
219 | } |
||||||
220 | if (! $colour) { |
||||||
221 | if ($isBackgroundColour) { |
||||||
222 | $colour = '#ffffff'; |
||||||
223 | } else { |
||||||
224 | $colour = '#000000'; |
||||||
225 | } |
||||||
226 | } |
||||||
227 | |||||||
228 | return $colour; |
||||||
229 | } |
||||||
230 | |||||||
231 | public function scaffoldFormField($title = null, $params = null) |
||||||
232 | { |
||||||
233 | $array = static::get_colours_for_dropdown(); |
||||||
234 | if (empty($array)) { |
||||||
235 | return ColorField::create($this->name, $title); |
||||||
236 | } |
||||||
237 | |||||||
238 | return ColorPaletteField::create($this->name, $title, static::get_colours_for_dropdown()); |
||||||
239 | } |
||||||
240 | |||||||
241 | public function getReadableColour(): static |
||||||
242 | { |
||||||
243 | // Remove '#' if it's present |
||||||
244 | return static::get_font_colour((string) $this->value, $this->name); |
||||||
245 | } |
||||||
246 | |||||||
247 | public function Inverted(): static |
||||||
248 | { |
||||||
249 | // Ensure the colour is 6 characters long |
||||||
250 | $colour = str_pad(ltrim($this->value, '#'), 6, '0', STR_PAD_RIGHT); |
||||||
251 | |||||||
252 | // Convert the colour to decimal |
||||||
253 | $colour = hexdec($colour); |
||||||
254 | |||||||
255 | // Invert the colour |
||||||
256 | $colour = 0xFFFFFF - $colour; |
||||||
257 | |||||||
258 | // Convert the colour back to hex |
||||||
259 | $colour = dechex($colour); |
||||||
0 ignored issues
–
show
$colour of type double is incompatible with the type integer expected by parameter $num of dechex() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
260 | |||||||
261 | // Ensure the colour is 6 characters long |
||||||
262 | $colour = str_pad($colour, 6, '0', STR_PAD_LEFT); |
||||||
263 | |||||||
264 | return static::get_colour_as_db_field($colour, $this->name); |
||||||
265 | } |
||||||
266 | |||||||
267 | public function getRelatedColourByName(string $relatedName): static |
||||||
268 | { |
||||||
269 | $relatedColours = $this->getRelatedColours($this->value); |
||||||
0 ignored issues
–
show
The call to
Sunnysideup\SelectedColo...ur::getRelatedColours() has too many arguments starting with $this->value .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue. If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above. ![]() |
|||||||
270 | $colour = $relatedColours[$relatedName] ?? 'error'; |
||||||
271 | |||||||
272 | return static::get_colour_as_db_field($colour, $this->name); |
||||||
273 | } |
||||||
274 | |||||||
275 | public function getCssVariableDefinition(?string $rootElement = ':root'): string |
||||||
276 | { |
||||||
277 | $style = PHP_EOL . '<style>'; |
||||||
278 | $style .= PHP_EOL . $rootElement; |
||||||
279 | $style .= PHP_EOL . '{'; |
||||||
280 | $style .= $this->getCssVarLine(); |
||||||
281 | if (static::IS_BG_COLOUR) { |
||||||
282 | $readableColourObj = $this->getReadableColour(); |
||||||
283 | $style .= $readableColourObj->getCssVarLine('-font'); |
||||||
284 | } |
||||||
285 | foreach ($this->getRelatedColours() as $name => $relatedColour) { |
||||||
286 | $relatedColourObj = self::get_colour_as_db_field($relatedColour, $this->name); |
||||||
287 | $style .= $relatedColourObj->getCssVarLine($name); |
||||||
288 | $relatedColourObjReadable = $relatedColourObj->getReadableColour(); |
||||||
289 | $style .= $relatedColourObjReadable->getCssVarLine($name . '-font'); |
||||||
290 | } |
||||||
291 | $style .= PHP_EOL . '}'; |
||||||
292 | $style .= PHP_EOL . '</style>'; |
||||||
293 | |||||||
294 | return $style; |
||||||
295 | } |
||||||
296 | |||||||
297 | public function getCssVarLine(?string $name = '', ?string $prefix = '--colour-'): string |
||||||
298 | { |
||||||
299 | $variableName = ' ' . $prefix; |
||||||
300 | $variableName .= $name ?: $this->kebabCase($this->getName()); |
||||||
301 | return PHP_EOL . $variableName . ': ' . $this->getValue() . ';'; |
||||||
302 | } |
||||||
303 | |||||||
304 | public function getCssClass(?bool $isTransparent = false): string |
||||||
305 | { |
||||||
306 | $colours = $this->getColours(); |
||||||
307 | if ($isTransparent) { |
||||||
308 | $name = 'transparent'; |
||||||
309 | } else { |
||||||
310 | $name = $colours[$this->value] ?? 'colour-error'; |
||||||
311 | } |
||||||
312 | |||||||
313 | return $this->classCleanup($name); |
||||||
314 | } |
||||||
315 | |||||||
316 | public function getCssClassAlternative(?bool $isTransparent = false): string |
||||||
317 | { |
||||||
318 | if ($isTransparent) { |
||||||
319 | $name = 'ffffff00'; |
||||||
320 | } else { |
||||||
321 | $name = $this->value ?: 'no-colour'; |
||||||
322 | } |
||||||
323 | |||||||
324 | return $this->classCleanup($name); |
||||||
325 | } |
||||||
326 | |||||||
327 | public function getIsLightColour(): bool |
||||||
328 | { |
||||||
329 | return static::is_light_colour($this->value); |
||||||
330 | } |
||||||
331 | |||||||
332 | public function getNice() |
||||||
333 | { |
||||||
334 | $html = ' |
||||||
335 | <div |
||||||
336 | style=" |
||||||
337 | width: 40px; |
||||||
338 | height: 40px; |
||||||
339 | border-radius: 40px; |
||||||
340 | background-color: ' . $this->getBackgroundColour() . '!important; |
||||||
341 | color: ' . $this->getFontColour() . '!important; |
||||||
342 | border: 1px solid ' . $this->getFontColour() . '!important; |
||||||
343 | text-align: center; |
||||||
344 | display: table-cell; |
||||||
345 | display: flex; |
||||||
346 | flex-direction: column; |
||||||
347 | justify-content: center; |
||||||
348 | " |
||||||
349 | >Aa</div> '; |
||||||
350 | |||||||
351 | return DBField::create_field('HTMLText', $html); |
||||||
352 | } |
||||||
353 | |||||||
354 | public function getIsDarkColour(): bool |
||||||
355 | { |
||||||
356 | return static::is_light_colour($this->value) ? false : true; |
||||||
357 | } |
||||||
358 | |||||||
359 | public function getFontColour(): string |
||||||
360 | { |
||||||
361 | if (self::IS_BG_COLOUR) { |
||||||
362 | return (string) self::get_font_colour($this->value); |
||||||
363 | } |
||||||
364 | |||||||
365 | return (string) $this->value; |
||||||
366 | } |
||||||
367 | |||||||
368 | public function getBackgroundColour(): string |
||||||
369 | { |
||||||
370 | if (self::IS_BG_COLOUR) { |
||||||
371 | return (string) $this->value; |
||||||
372 | } |
||||||
373 | |||||||
374 | return (string) self::get_font_colour($this->value); |
||||||
375 | } |
||||||
376 | |||||||
377 | public function getColours(): array |
||||||
378 | { |
||||||
379 | return $this->Config()->get('colours'); |
||||||
380 | } |
||||||
381 | |||||||
382 | protected function getMyColours(): array |
||||||
383 | { |
||||||
384 | $colours = $this->getColours(); |
||||||
385 | |||||||
386 | return empty($colours) ? static::DEFAULT_COLOURS : $colours; |
||||||
387 | } |
||||||
388 | |||||||
389 | protected function getRelatedColours(): array |
||||||
390 | { |
||||||
391 | $relatedColoursForAllColours = Config::inst()->get(static::class, 'linked_colours'); |
||||||
392 | |||||||
393 | return $relatedColoursForAllColours[$this->value] ?? []; |
||||||
394 | } |
||||||
395 | |||||||
396 | protected static function get_colour_as_db_field(string $colour, ?string $name = '') |
||||||
397 | { |
||||||
398 | $cacheKey = $colour . '_' . $name . '_' . static::class; |
||||||
399 | if (! $colour || ! isset(static::$object_cache[$cacheKey])) { |
||||||
400 | static::$object_cache[$cacheKey] = DBField::create_field(static::class, $colour, $name); |
||||||
401 | } |
||||||
402 | |||||||
403 | return static::$object_cache[$cacheKey]; |
||||||
404 | } |
||||||
405 | |||||||
406 | protected function kebabCase(string $string) |
||||||
407 | { |
||||||
408 | return strtolower(preg_replace('/(?<!^)[A-Z]/', '-$0', $string)); |
||||||
409 | } |
||||||
410 | |||||||
411 | private function classCleanup(string $name): string |
||||||
412 | { |
||||||
413 | $name = str_replace('#', '', $name); |
||||||
414 | $name = preg_replace('#[^A-Za-z0-9]#', '-', $name); |
||||||
415 | |||||||
416 | return static::CSS_CLASS_PREFIX . '-' . trim(trim(strtolower($name), '-')); |
||||||
417 | } |
||||||
418 | } |
||||||
419 |