Skip to content

Commit

Permalink
Added validation check for colourpicker form widget
Browse files Browse the repository at this point in the history
  • Loading branch information
jaxwilko committed Dec 12, 2023
1 parent 517f65d commit 7f5d792
Show file tree
Hide file tree
Showing 3 changed files with 167 additions and 1 deletion.
39 changes: 38 additions & 1 deletion modules/backend/formwidgets/ColorPicker.php
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,16 @@ class ColorPicker extends FormWidgetBase
*/
public $formats = 'hex';

/**
* @var array|string[] Patterns to validate colour string on save
*/
protected array $validationPatterns = [
'cmyk' => '/^cmyk\((\d{1,2}\.?\d{0,2}%,? ?){4}\)$/',
'hex' => '/^#[\w\d]{6}$/',
'hsl' => '/^hsla\((\d{1,3}\.?\d{0,2}%?, ?){3}\d\.?\d{0,2}?\)$/',
'rgb' => '/^rgba\((\d{1,3}\.?\d{0,2}, ?){3}\d\.?\d{0,2}?\)$/'
];

//
// Object properties
//
Expand Down Expand Up @@ -244,6 +254,33 @@ protected function loadAssets()
*/
public function getSaveValue($value)
{
return strlen($value) ? $value : null;
if (!strlen($value)) {
return null;
}

switch (is_array($this->formats) ? 'all' : $this->formats) {
case 'cmyk':
case 'hex':
case 'hsl':
case 'rgb':
if (!preg_match($this->validationPatterns[$this->formats], $value)) {
throw new ApplicationException(Lang::get('backend::lang.field.colors_invalid_input'));
}
break;
case 'all':
$valid = false;
foreach ($this->validationPatterns as $pattern) {
if (preg_match($pattern, $value)) {
$valid = true;
break;
}
}
if (!$valid) {
throw new ApplicationException(Lang::get('backend::lang.field.colors_invalid_input'));
}
break;
}

return $value;
}
}
1 change: 1 addition & 0 deletions modules/backend/lang/en/lang.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
'options_method_not_exists' => "The model class :model must define a method :method() returning options for the ':field' form field.",
'options_static_method_invalid_value' => "The static method ':method()' on :class did not return a valid options array.",
'colors_method_not_exists' => "The model class :model must define a method :method() returning html color HEX codes for the ':field' form field.",
'colors_invalid_input' => 'The color value supplied failed to meet expectations, please try again.',
],
'widget' => [
'not_registered' => "A widget class name ':name' has not been registered",
Expand Down
128 changes: 128 additions & 0 deletions modules/backend/tests/formwidgets/ColorPickerTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
<?php

namespace Backend\Tests\FormWidgets;

use Backend\Classes\Controller;
use Backend\Classes\FormField;
use Backend\FormWidgets\ColorPicker;
use System\Tests\Bootstrap\PluginTestCase;
use Winter\Storm\Exception\ApplicationException;

class ColorPickerTest extends PluginTestCase
{
public function testDefaultSaveValue(): void
{
$widget = $this->makeWidget();

// Default only expects hex
$this->assertEquals('#3498DB', $widget->getSaveValue('#3498DB'));

// Getting a non-hex value should throw an exception
$this->expectException(ApplicationException::class);
$widget->getSaveValue('rgba(51.9, 152, 219, 1)');

// Test a bunch of hex values
$this->assertEquals('#3498DB', $widget->getSaveValue('#3498DB'));
$this->assertEquals('#2980B9', $widget->getSaveValue('#2980B9'));
$this->assertEquals('#9B59B6', $widget->getSaveValue('#9B59B6'));
}

public function testRgbSaveValue(): void
{
$widget = $this->makeWidget([
'formats' => 'rgb'
]);

// Config specifies only rgb
$this->assertEquals('rgba(51.9, 152, 219, 1)', $widget->getSaveValue('rgba(51.9, 152, 219, 1)'));

// Getting a non-rgb value should throw an exception
$this->expectException(ApplicationException::class);
$widget->getSaveValue('#3498DB');

// Test a bunch of rgb values
$this->assertEquals('rgba(1, 1, 1, 1)', $widget->getSaveValue('rgba(1, 1, 1, 1)'));
$this->assertEquals('rgba(155, 89, 182, 0.5)', $widget->getSaveValue('rgba(155, 89, 182, 0.5)'));
$this->assertEquals('rgba(1, 89, 182, 0.55)', $widget->getSaveValue('rgba(1, 89, 182, 0.55)'));
}

public function testCmykSaveValue(): void
{
$widget = $this->makeWidget([
'formats' => 'cmyk'
]);

// Config specifies only cmyk
$this->assertEquals('cmyk(76.3%, 30.6%, 0%, 14.1%)', $widget->getSaveValue('cmyk(76.3%, 30.6%, 0%, 14.1%)'));

// Getting a non-cmyk value should throw an exception
$this->expectException(ApplicationException::class);
$widget->getSaveValue('#3498DB');

// Test a bunch of cmyk values
$this->assertEquals('cmyk(14.8%, 51.1%, 0%, 28.6%)', $widget->getSaveValue('cmyk(14.8%, 51.1%, 0%, 28.6%)'));
$this->assertEquals('cmyk(17%, 60.75%, 0%, 32.22%)', $widget->getSaveValue('cmyk(17%, 60.75%, 0%, 32.22%)'));
$this->assertEquals('cmyk(17.9%, 60.75%, 0%, 32.2%)', $widget->getSaveValue('cmyk(17.9%, 60.75%, 0%, 32.2%)'));
}

public function testHslaSaveValue(): void
{
$widget = $this->makeWidget([
'formats' => 'hsl'
]);

// Config specifies only hsl
$this->assertEquals('hsla(204.1, 69.9%, 53.1%, 1)', $widget->getSaveValue('hsla(204.1, 69.9%, 53.1%, 1)'));

// Getting a non-hsl value should throw an exception
$this->expectException(ApplicationException::class);
$widget->getSaveValue('#3498DB');

// Test a bunch of hsl values
$this->assertEquals('hsla(282.3, 43.6%, 47.2%, 1)', $widget->getSaveValue('hsla(282.3, 43.6%, 47.2%, 1)'));
$this->assertEquals('hsla(282.3, 43.6%, 47.2%, 0.1)', $widget->getSaveValue('hsla(282.3, 43.6%, 47.2%, 0.1)'));
$this->assertEquals('hsla(282, 43.6%, 47.2%, 0.1)', $widget->getSaveValue('hsla(282, 43.6%, 47.2%, 0.1)'));
$this->assertEquals('hsla(282, 43.56%, 47.2%, 0.1)', $widget->getSaveValue('hsla(282, 43.56%, 47.2%, 0.1)'));
$this->assertEquals('hsla(282.22, 43%, 47.2%, 0.1)', $widget->getSaveValue('hsla(282.22, 43%, 47.2%, 0.1)'));
}

public function testAllSaveValue(): void
{
$widget = $this->makeWidget([
'formats' => 'all'
]);

// Config allows for any valid format
$this->assertEquals('#3498DB', $widget->getSaveValue('#3498DB'));
$this->assertEquals('rgba(51.9, 152, 219, 1)', $widget->getSaveValue('rgba(51.9, 152, 219, 1)'));
$this->assertEquals('cmyk(76.3%, 30.6%, 0%, 14.1%)', $widget->getSaveValue('cmyk(76.3%, 30.6%, 0%, 14.1%)'));
$this->assertEquals('hsla(204.1, 69.9%, 53.1%, 1)', $widget->getSaveValue('hsla(204.1, 69.9%, 53.1%, 1)'));

// Getting a invalid value should throw an exception
$this->expectException(ApplicationException::class);
$widget->getSaveValue('#Winter Is Awesome');

$this->expectException(ApplicationException::class);
$widget->getSaveValue('rgba(51.9, 152, 219, 1) -- test');

$this->expectException(ApplicationException::class);
$widget->getSaveValue('Test(51.9, 152, 219, 1)');
}

public function testAllowCustomSaveValue(): void
{
$widget = $this->makeWidget([
'formats' => 'custom'
]);

// Config allows for any format
$this->assertEquals('rgba(51.9, 152, 219, 1)', $widget->getSaveValue('rgba(51.9, 152, 219, 1)'));
$this->assertEquals('#Winter Is Awesome', $widget->getSaveValue('#Winter Is Awesome'));
$this->assertEquals('Test(51.9, 152, 219, 1)', $widget->getSaveValue('Test(51.9, 152, 219, 1)'));
}

protected function makeWidget(array $config = []): ColorPicker
{
return new ColorPicker(new Controller(), new FormField('test', 'Test'), $config);
}
}

0 comments on commit 7f5d792

Please sign in to comment.