From ef6b82c8cd1c6503a42068efb190c5222a1a2813 Mon Sep 17 00:00:00 2001 From: Thor Brink Date: Tue, 27 Jan 2026 07:40:15 +0000 Subject: [PATCH 1/2] fix(Fileinput, Imageinput): update labels and button texts for better localization support --- source/php/Component/Fileinput/Fileinput.php | 10 ++--- source/php/Component/Fileinput/fileinput.json | 44 ++++++++++++------ .../partials/template/list.blade.php | 2 +- .../partials/template/preview.blade.php | 2 +- .../php/Component/Imageinput/imageinput.json | 45 +++++++++++++------ 5 files changed, 68 insertions(+), 35 deletions(-) diff --git a/source/php/Component/Fileinput/Fileinput.php b/source/php/Component/Fileinput/Fileinput.php index 1fa567e0..8abd6f3e 100644 --- a/source/php/Component/Fileinput/Fileinput.php +++ b/source/php/Component/Fileinput/Fileinput.php @@ -54,7 +54,7 @@ public function init() $maxFileSize = $this->determineMaxSize($maxSize, $acceptedTypesArray); if (!empty($maxFileSize)) { - $this->data['maxSize'] = ($this->data['lang']->maximumSize ?? 'Maximum size') . ': ' . $maxFileSize . ' MB'; + $this->data['maxSize'] = ($this->data['maximumSizeLabel']) . ': ' . $maxFileSize . ' MB'; $this->data['attributeList']['data-js-file-max-size'] = $maxFileSize; } @@ -124,13 +124,13 @@ private function determineMaxSize(int|string|null $maxSize, array $accept): null private function createAcceptedFilesList(array $accept): string { - return ($this->data['lang']->allowedFiles ?? 'Allowed files') . ': ' . implode(' ', array_map(function ($type) { + return ($this->data['allowedFileTypesLabel']) . ': ' . implode(' ', array_map(function ($type) { if ($type === 'video/*') - return $this->data['lang']->videos ?? 'Videos'; + return $this->data['fileTypeVideosLabel']; if ($type === 'image/*') - return $this->data['lang']->images ?? 'Images'; + return $this->data['fileTypeImagesLabel']; if ($type === 'audio/*') - return $this->data['lang']->audios ?? 'Audios'; + return $this->data['fileTypeAudioLabel']; return $type; }, $accept)); } diff --git a/source/php/Component/Fileinput/fileinput.json b/source/php/Component/Fileinput/fileinput.json index 6cad92e7..ac8b233e 100644 --- a/source/php/Component/Fileinput/fileinput.json +++ b/source/php/Component/Fileinput/fileinput.json @@ -5,10 +5,6 @@ "name": "files", "accept": "audio/*,video/*,image/*", "multiple": false, - "label": "", - "buttonLabel": "Select file", - "buttonRemoveLabel": "Remove file", - "buttonDropLabel": "Drop files here", "preview": false, "maxSize": null, "uploadErrorMessage": null, @@ -16,16 +12,22 @@ "icon": "file_upload", "required": false, "filesMax": 1, - "filesMin": 0 + "filesMin": 0, + "label": "", + "buttonLabel": "Select file", + "buttonRemoveLabel": "Remove file", + "buttonDropLabel": "Drop files here", + "allowedFileTypesLabel": "Allowed files: ", + "fileTypeVideosLabel": "Videos", + "fileTypeImagesLabel": "Images", + "fileTypeAudioLabel": "Audios", + "maximumSizeLabel": "Maximum size" }, "description": { "description": "Additional description or instructions.", "name": "files", "accept": "What file types to accept. Use MIME types. Example: audio/*,video/*,image/*", "multiple": "Allow single or multiple files", - "label": "Label to show on the field", - "buttonLabel": "What text to show on the button", - "buttonRemoveLabel": "What text to show on the remove button", "uploadErrorMessage": "Message to show when upload fails", "uploadErrorMessageMinFiles": "Message to show when minimum number of files is not met", "icon": "@link:component/icon", @@ -33,17 +35,21 @@ "filesMax": "Maximum number of files (int). Foced to 1 if multiple is false. Default 10 for multiple.", "filesMin": "Minimum number of files (int). Default is 0.", "buttonDropLabel": "A label for the drop area", - "maxSize": "Maximum file size allowed in MB. Number (int) in bytes or string (small, medium, large). Default is null (no limit)." + "maxSize": "Maximum file size allowed in MB. Number (int) in bytes or string (small, medium, large). Default is null (no limit).", + "label": "Label to show on the field", + "buttonLabel": "What text to show on the button", + "buttonRemoveLabel": "What text to show on the remove button", + "allowedFileTypesLabel": "Label for allowed file types", + "fileTypeVideosLabel": "Label for video file types", + "fileTypeImagesLabel": "Label for image file types", + "fileTypeAudioLabel": "Label for audio file types", + "maximumSizeLabel": "Maximum size" }, "types": { "description": "string", "name": "string", "accept": "string", "multiple": "boolean", - "label": "string", - "buttonLabel": "string", - "buttonRemoveLabel": "string", - "buttonDropLabel": "string", "uploadErrorMessage": "string", "uploadErrorMessageMinFiles": "string", "icon": "string", @@ -51,7 +57,17 @@ "filesMax": "integer", "filesMin": "integer", "preview": "boolean", - "maxSize": "string|int" + "maxSize": "string|int", + "label": "string", + "buttonLabel": "string", + "buttonRemoveLabel": "string", + "buttonDropLabel": "string", + "allowedFileTypesLabel": "string", + "fileTypeVideosLabel": "string", + "fileTypeImagesLabel": "string", + "fileTypeAudioLabel": "string", + "maximumSizeLabel": "string" + }, "view": "fileinput.blade.php", "dependency": { diff --git a/source/php/Component/Fileinput/partials/template/list.blade.php b/source/php/Component/Fileinput/partials/template/list.blade.php index 6842a974..9d08286e 100644 --- a/source/php/Component/Fileinput/partials/template/list.blade.php +++ b/source/php/Component/Fileinput/partials/template/list.blade.php @@ -30,7 +30,7 @@ $baseClass . '__item-remove-button' ], 'attributeList' => [ - 'aria-label' => $buttonRemoveLabel, + 'aria-label' => $lang->buttonRemoveLabel, 'data-js-file' => 'remove' ] ]) diff --git a/source/php/Component/Fileinput/partials/template/preview.blade.php b/source/php/Component/Fileinput/partials/template/preview.blade.php index 1713d32c..fca74c77 100644 --- a/source/php/Component/Fileinput/partials/template/preview.blade.php +++ b/source/php/Component/Fileinput/partials/template/preview.blade.php @@ -28,7 +28,7 @@ $baseClass . '__item-remove-button' ], 'attributeList' => [ - 'aria-label' => $buttonRemoveLabel, + 'aria-label' => $lang->buttonRemoveLabel, 'data-js-file' => 'remove' ], ]) diff --git a/source/php/Component/Imageinput/imageinput.json b/source/php/Component/Imageinput/imageinput.json index b941e1a8..bdc067d4 100644 --- a/source/php/Component/Imageinput/imageinput.json +++ b/source/php/Component/Imageinput/imageinput.json @@ -5,10 +5,6 @@ "name": "files", "accept": "audio/*,video/*,image/*", "multiple": false, - "label": "", - "buttonLabel": "Select file", - "buttonRemoveLabel": "Remove file", - "buttonDropLabel": "Drop files here", "preview": true, "maxSize": null, "uploadErrorMessage": null, @@ -16,34 +12,45 @@ "icon": "file_upload", "required": false, "filesMax": 1, - "filesMin": 0 + "filesMin": 0, + "label": "", + "buttonLabel": "Select file", + "buttonRemoveLabel": "Remove file", + "buttonDropLabel": "Drop files here", + "allowedFileTypesLabel": "Allowed files: ", + "fileTypeVideosLabel": "Videos", + "fileTypeImagesLabel": "Images", + "fileTypeAudioLabel": "Audios", + "maximumSizeLabel": "Maximum size" }, "description": { "description": "Additional description or instructions.", "name": "files", "accept": "What file types to accept. Use MIME types. Example: audio/*,video/*,image/*", "multiple": "Allow single or multiple files", - "label": "Label to show on the field", - "buttonLabel": "What text to show on the button", - "buttonRemoveLabel": "What text to show on the remove button", "uploadErrorMessage": "Message to show when upload fails", "uploadErrorMessageMinFiles": "Message to show when minimum number of files is not met", "icon": "@link:component/icon", "required": "If field is required", "filesMax": "Maximum number of files (int). Foced to 1 if multiple is false. Default 10 for multiple.", "filesMin": "Minimum number of files (int). Default 0.", + "maxSize": "Maximum file size allowed in MB. Number (int) in bytes or string (small, medium, large). Default is null (no limit).", + "lang": "An object containing language strings for the component.", + "label": "string", + "buttonLabel": "What text to show on the button", + "buttonRemoveLabel": "What text to show on the remove button", "buttonDropLabel": "A label for the drop area", - "maxSize": "Maximum file size allowed in MB. Number (int) in bytes or string (small, medium, large). Default is null (no limit)." + "allowedFileTypesLabel": "Label for allowed file types", + "fileTypeVideosLabel": "Label for video file types", + "fileTypeImagesLabel": "Label for image file types", + "fileTypeAudioLabel": "Label for audio file types", + "maximumSizeLabel": "Maximum size" }, "types": { "description": "string", "name": "string", "accept": "string", "multiple": "boolean", - "label": "string", - "buttonLabel": "string", - "buttonRemoveLabel": "string", - "buttonDropLabel": "string", "uploadErrorMessage": "string", "uploadErrorMessageMinFiles": "string", "icon": "string", @@ -51,7 +58,17 @@ "filesMax": "integer", "filesMin": "integer", "preview": "boolean", - "maxSize": "string|int" + "maxSize": "string|int", + "lang": "object", + "label": "string", + "buttonLabel": "string", + "buttonRemoveLabel": "string", + "buttonDropLabel": "string", + "allowedFileTypesLabel": "string", + "fileTypeVideosLabel": "string", + "fileTypeImagesLabel": "string", + "fileTypeAudioLabel": "string", + "maximumSizeLabel": "string" }, "view": "imageinput.blade.php", "dependency": { From b84fdf842c9b401e645d55d8453b7d8efb229669 Mon Sep 17 00:00:00 2001 From: Thor Brink Date: Tue, 27 Jan 2026 07:47:24 +0000 Subject: [PATCH 2/2] test: use default data --- source/php/Component/BaseController.php | 120 +++++++++--------- .../php/Component/Fileinput/FileinputTest.php | 12 +- 2 files changed, 66 insertions(+), 66 deletions(-) diff --git a/source/php/Component/BaseController.php b/source/php/Component/BaseController.php index 88845a20..a0cb3dd8 100644 --- a/source/php/Component/BaseController.php +++ b/source/php/Component/BaseController.php @@ -13,14 +13,14 @@ class BaseController */ protected $data = array( 'id' => '', //Unique dom id - 'class' => "", //Auto compiled from class list on data fetch - 'baseClass' => "", + 'class' => '', //Auto compiled from class list on data fetch + 'baseClass' => '', 'classList' => [], //An array of class names (push classes here), - 'attribute' => "", + 'attribute' => '', 'attributeList' => [], 'context' => [], 'isBlock' => false, - 'isShortcode' => false + 'isShortcode' => false, ); /** @@ -37,9 +37,8 @@ class BaseController public function __construct( $data, protected CacheInterface $cache, - protected TagSanitizerInterface $tagSanitizer + protected TagSanitizerInterface $tagSanitizer, ) { - //Load input data if (!is_null($data) && is_array($data)) { $this->data = array_merge($this->data, $data); @@ -51,18 +50,18 @@ public function __construct( } elseif (is_string($this->data['context'])) { $this->data['context'] = [ $this->data['context'], - $this->createDefaultContext($this) + $this->createDefaultContext($this), ]; } //Applies a general wp filter if (function_exists('apply_filters')) { - $this->data = apply_filters("ComponentLibrary/Component/Data", $this->data); + $this->data = apply_filters('ComponentLibrary/Component/Data', $this->data); } //Applies a general wp filter if (function_exists('apply_filters')) { - $this->data = apply_filters($this->createFilterName($this) . DIRECTORY_SEPARATOR . "Data", $this->data); + $this->data = apply_filters($this->createFilterName($this) . DIRECTORY_SEPARATOR . 'Data', $this->data); } if (function_exists('apply_filters')) { @@ -108,11 +107,11 @@ public function getData() if (function_exists('apply_filters')) { if (is_array($data) && !empty($data)) { foreach ($data as $key => $item) { - if (!in_array($key, array("data", "classes", 'class'))) { + if (!in_array($key, array('data', 'classes', 'class'))) { $data[$key] = apply_filters( - $this->createFilterName($this) . DIRECTORY_SEPARATOR . ucfirst($key), + $this->createFilterName($this) . DIRECTORY_SEPARATOR . ucfirst($key), $data[$key], - $data['context'] ?? [] + $data['context'] ?? [], ); } } @@ -131,9 +130,9 @@ public function getData() private function getId() { if (isset($this->data['id']) && !empty($this->data['id'])) { - return (string) str_replace(" ", "", ($this->data['id'])); + return (string) str_replace(' ', '', $this->data['id']); } - return ""; + return ''; } /** @@ -149,14 +148,14 @@ public function getUid() return $this->uid = uniqid(); } - /** - * If the slot exists in the data array, and the html property of the slot is not empty, then - * return true - * - * @param slotKey The name of the slot you want to check. - * - * @return a boolean value. - */ + /** + * If the slot exists in the data array, and the html property of the slot is not empty, then + * return true + * + * @param slotKey The name of the slot you want to check. + * + * @return a boolean value. + */ /** * Checks if the specified slot contains data. * @@ -169,7 +168,7 @@ public function slotHasData($slotKey) return false; } - $property = ($slotKey === 'slot') ? 'html' : 'contents'; + $property = $slotKey === 'slot' ? 'html' : 'contents'; $value = $this->accessProtected($this->data[$slotKey], $property); return !empty($value); @@ -180,7 +179,7 @@ private function getNamespaceParts() //Get all parts of the location return explode( "\\", - get_called_class() + get_called_class(), ); } @@ -189,7 +188,7 @@ private function setModifier($class, $modifier) if (!empty($modifier)) { foreach ($modifier as &$value) { if ($value && is_string($value)) { - $class[] = $this->getBaseClass() . '--' . $value; + $class[] = $this->getBaseClass() . '--' . $value; } } } @@ -212,7 +211,7 @@ private function validClassList($classList): bool if (is_array($classList) && !empty($classList)) { foreach ($classList as $classListItem) { - if (strpos($classListItem, " ")) { + if (strpos($classListItem, ' ')) { return false; } if (empty($classListItem)) { @@ -236,9 +235,9 @@ private function getClass($implode = true) 'The parameter classList is not allowed to contain spaces or include empty strings. Multiple classes may be separated by entering a array of items. Please review data inputted: %s', - print_r($this, true) + print_r($this, true), ), - E_USER_WARNING + E_USER_WARNING, ); } @@ -246,36 +245,36 @@ private function getClass($implode = true) if (isset($this->data['classList']) && is_array($this->data['classList'])) { array_unshift( $this->data['classList'], - (string) $this->getBaseClass() + (string) $this->getBaseClass(), ); $class = (array) $this->data['classList']; } else { $class = array(); } - $namespaceParts = $this->getNameSpaceParts(); + $namespaceParts = $this->getNameSpaceParts(); $componentName = end($namespaceParts); //Applies a general wp filter if (function_exists('apply_filters')) { - $modifier = apply_filters("ComponentLibrary/Component/Modifier", [], $this->data['context']); + $modifier = apply_filters('ComponentLibrary/Component/Modifier', [], $this->data['context']); $class = $this->setModifier($class, $modifier); } //Applies component specific wp filter if (function_exists('apply_filters')) { - $modifier = apply_filters("ComponentLibrary/Component/". $componentName ."/Modifier", [], $this->data['context']); + $modifier = apply_filters('ComponentLibrary/Component/' . $componentName . '/Modifier', [], $this->data['context']); $class = $this->setModifier($class, $modifier); } //Applies a general wp filter if (function_exists('apply_filters')) { - $class = apply_filters("ComponentLibrary/Component/Class", $class); + $class = apply_filters('ComponentLibrary/Component/Class', $class); } //Applies component specific wp filter if (function_exists('apply_filters')) { - $class = apply_filters("ComponentLibrary/Component/". $componentName ."/Class", $class, $this->data['context']); + $class = apply_filters('ComponentLibrary/Component/' . $componentName . '/Class', $class, $this->data['context']); } //Return manipulated classes as array @@ -284,7 +283,7 @@ private function getClass($implode = true) } //Return manipulated data array as string - return (string) implode(" ", (array) $class); + return (string) implode(' ', (array) $class); } /** @@ -307,7 +306,7 @@ private function getContainerAware() * * @return string A single css class */ - protected function getBaseClass(string $className = "", bool $isModifier = false): string + protected function getBaseClass(string $className = '', bool $isModifier = false): string { //If base class is specified from component controller then use that if ($this->data['baseClass']) { @@ -318,19 +317,19 @@ protected function getBaseClass(string $className = "", bool $isModifier = false $namespaceParts = $this->getNamespaceParts(); //Separator notation - $separator = ($isModifier ? '--' : '__'); + $separator = $isModifier ? '--' : '__'; //Create array of items return strtolower( implode( - "", + '', [ - "c-", + 'c-', end($namespaceParts), - ($className ? $separator : ''), - $className - ] - ) + $className ? $separator : '', + $className, + ], + ), ); } @@ -345,7 +344,7 @@ private function getAttribute($implode = true) //Add attribute for container awareness if ($this->getContainerAware() == true) { - $attribute['data-observe-resizes'] = ""; + $attribute['data-observe-resizes'] = ''; } //Add id if defined @@ -358,12 +357,12 @@ private function getAttribute($implode = true) //Applies a general wp filter if (function_exists('apply_filters')) { - $attribute = apply_filters($this->createFilterName($this) . DIRECTORY_SEPARATOR . "Attribute", $attribute); + $attribute = apply_filters($this->createFilterName($this) . DIRECTORY_SEPARATOR . 'Attribute', $attribute); } //Applies a general wp filter if (function_exists('apply_filters')) { - $attribute = apply_filters("ComponentLibrary/Component/Attribute", $attribute); + $attribute = apply_filters('ComponentLibrary/Component/Attribute', $attribute); } //Sanitize "broken" css. @@ -395,14 +394,15 @@ private function getAttribute($implode = true) /** * Santitize the id attribute of a component - * - * This will prevent invalid characters and ensure that the id + * + * This will prevent invalid characters and ensure that the id * starts with a letter as required by the HTML spec. - * + * * @param string $id The id to sanitize * @return string The sanitized id */ - public function sanitizeIdAttribute(string $id): string { + public function sanitizeIdAttribute(string $id): string + { // Allow a-z, A-Z, 0-9, -, _, [, ], {, } $id = preg_replace('/[^a-zA-Z0-9\-\_\[\]\{\}]/', '', $id); @@ -425,7 +425,7 @@ public function sanitizeInlineCss($inlineCss) /** * Builds a string of attributes. - * + * * @param array $attributes An array of attributes to be added to the string. * @return string A string of attributes. */ @@ -434,7 +434,7 @@ public static function buildAttributes(array $attributes): string $attributeStrings = []; foreach ($attributes as $key => $value) { - if(is_resource($value) || (!is_string($value) && is_callable($value))) { + if (is_resource($value) || !is_string($value) && is_callable($value)) { continue; } @@ -450,12 +450,12 @@ public static function buildAttributes(array $attributes): string $value = $value ? '1' : '0'; } - if($value === "null" || $value === null) { - $escapedValue = ""; + if ($value === 'null' || $value === null) { + $escapedValue = ''; } else { $escapedValue = htmlspecialchars($value, ENT_QUOTES, 'UTF-8'); } - + $attributeStrings[] = "$key=\"$escapedValue\""; } @@ -471,8 +471,8 @@ function ($v, $k) { return sprintf('%s: %s;', $k, $v); }, array_values($styles), - array_keys($styles) - ) + array_keys($styles), + ), ); } @@ -486,7 +486,7 @@ public function createFilterName($class) //Get all parts of the location $name = explode( "\\", - get_class($class) + get_class($class), ); //Remove duplicates @@ -506,7 +506,7 @@ private function createDefaultContext($class) //Get all parts of the location $name = explode( "\\", - get_class($class) + get_class($class), ); if (isset($name[0])) { @@ -517,7 +517,7 @@ private function createDefaultContext($class) $name = array_unique($name); //Create string - return strtolower(implode(".", $name)); + return strtolower(implode('.', $name)); } /** diff --git a/source/php/Component/Fileinput/FileinputTest.php b/source/php/Component/Fileinput/FileinputTest.php index b761364d..ad098ccc 100644 --- a/source/php/Component/Fileinput/FileinputTest.php +++ b/source/php/Component/Fileinput/FileinputTest.php @@ -39,7 +39,7 @@ public function testSetsMinNumberOfFilesIfProvided() { $cache = static::createCache(); $tagSanitizer = static::createTagSanitizer(); - $fileinput = new Fileinput(static::getData(['filesMin' => 3]), $cache, $tagSanitizer); + $fileinput = new Fileinput(static::getData(['filesMin' => 3, 'filesMax' => 5]), $cache, $tagSanitizer); $resultData = $fileinput->getData(); @@ -84,11 +84,11 @@ public function testThrowsErrorIfMinNumberIsNotAnInteger() private static function getData(array $merge = []): array { - return array_merge([ - 'accept' => '.jpg,.png', - 'filesMax' => 10, - 'maxSize' => 5, - ], $merge); + $jsonFile = __DIR__ . '/fileinput.json'; + $decodedJson = json_decode(file_get_contents($jsonFile), true); + $defaultData = $decodedJson['default'] ?? []; + + return array_merge($defaultData, $merge); } private static function createCache(): CacheInterface