diff --git a/README.md b/README.md index 310aaf9ba7b..c8016d324f9 100644 --- a/README.md +++ b/README.md @@ -175,6 +175,7 @@ Most important changes will be listed here, all other changes since `19.4.0` can - bug fixes and PHP 7.x, 8.0, 8.1 and 8.2 compatibility - added config cache for system.xml ([#1916](https://github.com/OpenMage/magento-lts/pull/1916)) +- added frontend_type color ([#2945](https://github.com/OpenMage/magento-lts/pull/2945)) - search for "NULL" in backend grids ([#1203](https://github.com/OpenMage/magento-lts/pull/1203)) - removed `lib/flex` containing unused ActionScript "file uploader" files ([#2271](https://github.com/OpenMage/magento-lts/pull/2271)) - Mage_Catalog_Model_Resource_Abstract::getAttributeRawValue() now returns `'0'` instead of `false` if the value stored in the database is `0` ([#572](https://github.com/OpenMage/magento-lts/pull/572)) diff --git a/app/code/core/Mage/Adminhtml/Block/System/Config/Form.php b/app/code/core/Mage/Adminhtml/Block/System/Config/Form.php index d12954eb095..846ada27472 100644 --- a/app/code/core/Mage/Adminhtml/Block/System/Config/Form.php +++ b/app/code/core/Mage/Adminhtml/Block/System/Config/Form.php @@ -298,8 +298,10 @@ public function initFields($fieldset, $group, $section, $fieldPrefix = '', $labe . Mage::helper($helperName)->__((string)$element->label); $hint = (string)$element->hint ? Mage::helper($helperName)->__((string)$element->hint) : ''; - if ($element->backend_model) { - $model = Mage::getModel((string)$element->backend_model); + $helper = Mage::helper('adminhtml/config'); + $backendClass = $helper->getBackendModelByFieldConfig($element); + if ($backendClass) { + $model = Mage::getModel($backendClass); if (!$model instanceof Mage_Core_Model_Config_Data) { Mage::throwException('Invalid config field backend model: ' . (string)$element->backend_model); } diff --git a/app/code/core/Mage/Adminhtml/Helper/Config.php b/app/code/core/Mage/Adminhtml/Helper/Config.php new file mode 100644 index 00000000000..30b748919d8 --- /dev/null +++ b/app/code/core/Mage/Adminhtml/Helper/Config.php @@ -0,0 +1,88 @@ + + */ +class Mage_Adminhtml_Helper_Config extends Mage_Core_Helper_Abstract +{ + protected $_moduleName = 'Mage_Adminhtml'; + + /** + * Return information array of input types + * + * @param string $inputType + * @return array + */ + public function getInputTypes(string $inputType = null): array + { + $inputTypes = [ + 'color' => [ + 'backend_model' => 'adminhtml/system_config_backend_color' + ] + ]; + + if (is_null($inputType)) { + return $inputTypes; + } elseif (isset($inputTypes[$inputType])) { + return $inputTypes[$inputType]; + } + return []; + } + + /** + * Return default backend model by input type + * + * @param string $inputType + * @return string|null + */ + public function getBackendModelByInputType(string $inputType): ?string + { + $inputTypes = $this->getInputTypes(); + if (!empty($inputTypes[$inputType]['backend_model'])) { + return $inputTypes[$inputType]['backend_model']; + } + return null; + } + + /** + * Get field backend model by field config node + * + * @param Varien_Simplexml_Element $fieldConfig + * @return string|null + */ + public function getBackendModelByFieldConfig(Varien_Simplexml_Element $fieldConfig): ?string + { + if (isset($fieldConfig->backend_model)) { + return (string)$fieldConfig->backend_model; + } + if (isset($fieldConfig->frontend_type)) { + return $this->getBackendModelByInputType((string)$fieldConfig->frontend_type); + } + return null; + } +} diff --git a/app/code/core/Mage/Adminhtml/Model/Config/Data.php b/app/code/core/Mage/Adminhtml/Model/Config/Data.php index 4b31b79f733..a1c0848a2fe 100644 --- a/app/code/core/Mage/Adminhtml/Model/Config/Data.php +++ b/app/code/core/Mage/Adminhtml/Model/Config/Data.php @@ -129,6 +129,7 @@ public function save() ? $fieldData['value'] : null; } + $helper = Mage::helper('adminhtml/config'); foreach ($groupData['fields'] as $field => $fieldData) { $field = ltrim($field, '/'); $fieldConfig = $sections->descend($section . '/groups/' . $group . '/fields/' . $field); @@ -143,10 +144,7 @@ public function save() } } - /** - * Get field backend model - */ - $backendClass = (isset($fieldConfig->backend_model)) ? $fieldConfig->backend_model : false; + $backendClass = $helper->getBackendModelByFieldConfig($fieldConfig); if (!$backendClass) { $backendClass = 'core/config_data'; } diff --git a/app/code/core/Mage/Adminhtml/Model/System/Config/Backend/Color.php b/app/code/core/Mage/Adminhtml/Model/System/Config/Backend/Color.php new file mode 100644 index 00000000000..62f40005486 --- /dev/null +++ b/app/code/core/Mage/Adminhtml/Model/System/Config/Backend/Color.php @@ -0,0 +1,67 @@ + + */ +class Mage_Adminhtml_Model_System_Config_Backend_Color extends Mage_Core_Model_Config_Data +{ + /** + * @throws Mage_Core_Exception + * @return $this + */ + protected function _beforeSave() + { + /** @var Mage_Core_Model_Config_Element $config */ + $config = $this->getFieldConfig(); + + $validate = []; + if (isset($config->validate)) { + $validate = array_map('trim', explode(' ', $config->validate)); + } + + if (!(string)$this->getValue() && !in_array('required-entry', $validate)) { + return $this; + } + + $with_hash = true; + if (isset($config->with_hash)) { + $with_hash = $config->is('with_hash', true); + } + + if ($with_hash) { + $regex = Varien_Data_Form_Element_Color::VALIDATION_REGEX_WITH_HASH; + $errorMessage = 'Color must be in hexadecimal format with the hash character'; + } else { + $regex = Varien_Data_Form_Element_Color::VALIDATION_REGEX_WITHOUT_HASH; + $errorMessage = 'Color must be in hexadecimal format without the hash character'; + } + + if (!(bool)preg_match($regex, (string)$this->getValue())) { + Mage::throwException(Mage::helper('adminhtml')->__($errorMessage)); + } + + return $this; + } +} diff --git a/app/locale/en_US/Mage_Adminhtml.csv b/app/locale/en_US/Mage_Adminhtml.csv index a237d1b4d0b..74df8c51392 100644 --- a/app/locale/en_US/Mage_Adminhtml.csv +++ b/app/locale/en_US/Mage_Adminhtml.csv @@ -237,6 +237,8 @@ "Clear","Clear" "Close","Close" "Code","Code" +"Color must be in hexadecimal format with the hash character","Color must be in hexadecimal format with the hash character" +"Color must be in hexadecimal format without the hash character","Color must be in hexadecimal format without the hash character" "Comment text field cannot be empty.","Comment text field cannot be empty." "Complete","Complete" "Config form fieldset clone model required to be able to clone fields","Config form fieldset clone model required to be able to clone fields" @@ -751,6 +753,8 @@ "Please enter a valid value, ex: 10,20,30","Please enter a valid value, ex: 10,20,30" "Please enter a valid zip code.","Please enter a valid zip code." "Please enter a valid zip code. For example 90602 or 90602-1234.","Please enter a valid zip code. For example 90602 or 90602-1234." +"Please enter a valid hexadecimal color. For example ff0000.","Please enter a valid hexadecimal color. For example ff0000." +"Please enter a valid hexadecimal color with hash. For example #ff0000.","Please enter a valid hexadecimal color with hash. For example #ff0000." "Please enter another credit card number to complete your purchase.","Please enter another credit card number to complete your purchase." "Please enter password","Please enter password" "Please enter password to confirm rollback.","Please enter password to confirm rollback." diff --git a/js/prototype/validation.js b/js/prototype/validation.js index 91a14cb0fec..ccca878ed91 100644 --- a/js/prototype/validation.js +++ b/js/prototype/validation.js @@ -480,6 +480,12 @@ Validation.addAllThese([ return result; }], + ['validate-hex-color', 'Please enter a valid hexadecimal color. For example ff0000.', function (v) { + return Validation.get('IsEmpty').test(v) || /^[a-f0-9]{6}$/i.test(v) + }], + ['validate-hex-color-hash', 'Please enter a valid hexadecimal color with hash. For example #ff0000.', function (v) { + return Validation.get('IsEmpty').test(v) || /^#[a-f0-9]{6}$/i.test(v) + }], ['validate-alpha', 'Please use letters only (a-z or A-Z) in this field.', function (v) { return Validation.get('IsEmpty').test(v) || /^[a-zA-Z]+$/.test(v) }], diff --git a/lib/Varien/Data/Form/Element/Color.php b/lib/Varien/Data/Form/Element/Color.php new file mode 100644 index 00000000000..d9a22d7c56c --- /dev/null +++ b/lib/Varien/Data/Form/Element/Color.php @@ -0,0 +1,79 @@ + + */ +class Varien_Data_Form_Element_Color extends Varien_Data_Form_Element_Abstract +{ + public const VALIDATION_REGEX_WITH_HASH = '/^#[a-f0-9]{6}$/i'; + public const VALIDATION_REGEX_WITHOUT_HASH = '/^[a-f0-9]{6}$/i'; + + /** + * @param array $attributes + */ + public function __construct($attributes = []) + { + parent::__construct($attributes); + $this->setType('text'); + $this->setExtType('textfield'); + } + + /** + * @return array + */ + public function getHtmlAttributes() + { + return ['type', 'title', 'class', 'style', 'oninput', 'disabled', 'readonly', 'tabindex']; + } + + /** + * @return string + */ + public function getElementHtml() + { + $id = $this->getHtmlId(); + $with_hash = strtolower((string) ($this->original_data['with_hash'] ?? 1)); + + if (!empty($with_hash) && $with_hash !== 'false' && $with_hash !== 'off') { + $oninput = "document.getElementById('{$id}').value = this.value"; + $regex = self::VALIDATION_REGEX_WITH_HASH; + $this->setOninput("document.getElementById('{$id}:html5').value = {$regex}.test(this.value) ? this.value : '#000000'"); + $this->addClass('validate-hex-color-hash'); + } else { + $oninput = "document.getElementById('{$id}').value = this.value.substring(1)"; + $regex = self::VALIDATION_REGEX_WITHOUT_HASH; + $this->setOninput("document.getElementById('{$id}:html5').value = {$regex}.test(this.value) ? '#'+this.value : '#000000'"); + $this->addClass('validate-hex-color'); + } + + $html = '' . "\n"; + + $this->addClass('input-color'); + $html .= parent::getElementHtml(); + return $html; + } +} diff --git a/skin/adminhtml/default/default/boxes.css b/skin/adminhtml/default/default/boxes.css index 786c8f0eb88..56d8779ec74 100644 --- a/skin/adminhtml/default/default/boxes.css +++ b/skin/adminhtml/default/default/boxes.css @@ -343,9 +343,11 @@ label.inline { float:none !important; width:auto !imp #coupon_container .entry-edit { min-width:310px; } /* Form Elements */ -input.input-text,textarea,select { border-width:1px; border-style:solid; border-color:#aaa #c8c8c8 #c8c8c8 #aaa; background:#fff; font:12px arial, helvetica, sans-serif; } +input.input-text,input.input-color,textarea,select { border-width:1px; border-style:solid; border-color:#aaa #c8c8c8 #c8c8c8 #aaa; background:#fff; font:12px arial, helvetica, sans-serif; } select { min-height:17px; /* to set the height for empty selects */ } input.input-text,textarea { padding:2px; } +input.input-color { padding:2px; width:222px !important; } +input.input-color-html5 { width:48px !important; } input.qty { width:40px !important; } input.item-qty { width:22px !important; } input.price { width:50px !important; text-align:right; }