Skip to content

Commit 239dbcb

Browse files
authored
Fixes configurable swatch color picker in legacy admin theme (#4218)
* Fixes 4217 * Button size
1 parent 1c3d0c9 commit 239dbcb

File tree

3 files changed

+309
-5
lines changed

3 files changed

+309
-5
lines changed

app/design/adminhtml/default/default/template/eav/attribute/options.phtml

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
* Attribute options control
1919
*
2020
* @see Mage_Eav_Block_Adminhtml_Attribute_Edit_Options_Abstract
21-
* @var $this Mage_Eav_Block_Adminhtml_Attribute_Edit_Options_Abstract
21+
* @var Mage_Eav_Block_Adminhtml_Attribute_Edit_Options_Abstract $this
2222
*/
2323
?>
2424
<div>
@@ -82,8 +82,10 @@
8282
<?php if ($this->isConfigurableSwatchesEnabled()): ?>
8383
<td style="position:relative">
8484
<input type="hidden" disabled class="swatch-value" name="option[swatch][{{id}}]" value="{{swatch}}" />
85-
<input type="color" class="input-color-html5 validate-hex-color-hash {{swatch_class}}" value="{{swatch}}" />
86-
<span class="swatch-delete" data-msg-delete="<?php echo $this->escapeHtml($this->__('Are you sure to delete this fallback color?')) ?>">X</span>
85+
<input type="color" class="input-color-html5 validate-hex-color-hash {{swatch_class}}" value="{{swatch}}" />
86+
<button title="Delete Swatch" type="button" class="scalable delete icon-btn swatch-delete" data-msg-delete="<?php echo $this->escapeHtml($this->__('Are you sure to delete this fallback color?')) ?>">
87+
<span><span><span>X</span></span></span>
88+
</button>
8789
</td>
8890
<?php endif ?>
8991
<?php foreach ($this->getStores() as $_store): ?>
@@ -114,7 +116,9 @@ var templateText =
114116
'<td style="position:relative">'+
115117
'<input type="hidden" disabled class="swatch-value" name="option[swatch][{{id}}]" value="{{swatch}}" />'+
116118
'<input type="color" class="swatch-option input-color-html5 validate-hex-color-hash {{swatch_class}}" value="{{swatch}}" />'+
117-
'<span class="swatch-delete" data-msg-delete="<?php echo Mage::helper('core')->jsQuoteEscape($this->__('Are you sure to delete this fallback color?')); ?>">X</span>'+
119+
'<button title="Delete Swatch" type="button" class="scalable delete icon-btn swatch-delete" data-msg-delete="<?php echo Mage::helper('core')->jsQuoteEscape($this->__('Are you sure to delete this fallback color?')); ?>">'+
120+
'<span><span><span>X</span></span></span>'+
121+
'</button>'+
118122
'</td>'+
119123
<?php endif ?>
120124
<?php foreach ($this->getStores() as $_store): ?>
@@ -148,6 +152,7 @@ var attributeOption = {
148152
data.intype = optionDefaultInputType;
149153
}
150154
if (!data.swatch) {
155+
data.swatch = '#ffffff';
151156
data.swatch_class = 'swatch-disabled';
152157
}
153158
let newHTML = this.template.evaluate(data);
@@ -188,7 +193,7 @@ var attributeOption = {
188193
}
189194
},
190195
swatchremove : function(event){
191-
if (!confirm(event.target.getAttribute('data-msg-delete'))) {
196+
if (!confirm(event.target.closest('button').getAttribute('data-msg-delete'))) {
192197
return;
193198
}
194199
let element = event.target.closest('tr');
Lines changed: 269 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,269 @@
1+
<?php
2+
/**
3+
* OpenMage
4+
*
5+
* This source file is subject to the Academic Free License (AFL 3.0)
6+
* that is bundled with this package in the file LICENSE_AFL.txt.
7+
* It is also available at https://opensource.org/license/afl-3-0-php
8+
*
9+
* @category design
10+
* @package default_default
11+
* @copyright Copyright (c) 2006-2020 Magento, Inc. (https://www.magento.com)
12+
* @copyright Copyright (c) 2021-2024 The OpenMage Contributors (https://www.openmage.org)
13+
* @license https://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
14+
*/
15+
?>
16+
<?php
17+
/**
18+
* Attribute options control
19+
*
20+
* @see Mage_Eav_Block_Adminhtml_Attribute_Edit_Options_Abstract
21+
* @var Mage_Eav_Block_Adminhtml_Attribute_Edit_Options_Abstract $this
22+
*/
23+
?>
24+
<div>
25+
<ul class="messages">
26+
<li class="notice-msg">
27+
<ul>
28+
<li><?php echo $this->__('If you do not specify an option value for a specific store view then the default (Admin) value will be used.') ?></li>
29+
</ul>
30+
</li>
31+
</ul>
32+
</div>
33+
34+
<div class="entity-edit">
35+
<div class="entry-edit-head">
36+
<h4 class="icon-head head-edit-form fieldset-legend"><?php echo $this->__('Manage Titles (Size, Color, etc.)') ?></h4>
37+
</div>
38+
<div class="box">
39+
<div class="hor-scroll">
40+
<table class="dynamic-grid" cellspacing="0" id="attribute-labels-table">
41+
<tr>
42+
<?php foreach ($this->getStores() as $_store): ?>
43+
<th><?php echo $this->escapeHtml($_store->getName()); ?></th>
44+
<?php endforeach ?>
45+
</tr>
46+
<tr>
47+
<?php $_labels = $this->getLabelValues() ?>
48+
<?php foreach ($this->getStores() as $_store): ?>
49+
<td>
50+
<input class="input-text<?php if($_store->getId()==0): ?> required-option<?php endif ?>" type="text" name="frontend_label[<?php echo $_store->getId() ?>]" value="<?php echo $this->escapeHtml($_labels[$_store->getId()]); ?>"<?php if ($this->getReadOnly()):?> disabled="disabled"<?php endif ?>/>
51+
</td>
52+
<?php endforeach ?>
53+
</tr>
54+
</table>
55+
</div>
56+
</div>
57+
</div>
58+
<br/>
59+
<div class="entity-edit" id="matage-options-panel">
60+
<div class="entry-edit-head">
61+
<h4 class="icon-head head-edit-form fieldset-legend"><?php echo $this->__('Manage Options (values of your attribute)') ?></h4>
62+
</div>
63+
<div class="box">
64+
<div class="hor-scroll">
65+
<table class="dynamic-grid" cellspacing="0" cellpadding="0">
66+
<tr id="attribute-options-table">
67+
<?php if ($this->isConfigurableSwatchesEnabled()): ?>
68+
<th><?php echo $this->escapeHtml($this->__('Swatch')) ?></th>
69+
<?php endif ?>
70+
<?php foreach ($this->getStores() as $_store): ?>
71+
<th><?php echo $this->escapeHtml($_store->getName()); ?></th>
72+
<?php endforeach ?>
73+
<th><?php echo $this->__('Position') ?></th>
74+
<th class="nobr a-center"><?php echo $this->escapeHtml($this->__('Is Default')) ?></th>
75+
<th>
76+
<?php if (!$this->getReadOnly()):?>
77+
<?php echo $this->getAddNewButtonHtml() ?>
78+
<?php endif ?>
79+
</th>
80+
</tr>
81+
<tr class="no-display template" id="row-template">
82+
<?php if ($this->isConfigurableSwatchesEnabled()): ?>
83+
<td style="position:relative">
84+
<input type="hidden" disabled class="swatch-value" name="option[swatch][{{id}}]" value="{{swatch}}" />
85+
<input type="color" class="input-color-html5 validate-hex-color-hash {{swatch_class}}" value="{{swatch}}" />
86+
<span class="swatch-delete" data-msg-delete="<?php echo $this->escapeHtml($this->__('Are you sure to delete this fallback color?')) ?>">X</span>
87+
</td>
88+
<?php endif ?>
89+
<?php foreach ($this->getStores() as $_store): ?>
90+
<td><input name="option[value][{{id}}][<?php echo $_store->getId() ?>]" value="{{store<?php echo $_store->getId() ?>}}" class="input-text<?php if($_store->getId()==0): ?> required-option<?php endif ?>" type="text" <?php if ($this->getReadOnly()):?> disabled="disabled"<?php endif ?>/></td>
91+
<?php endforeach ?>
92+
<td class="a-center"><input class="input-text" type="text" name="option[order][{{id}}]" value="{{sort_order}}" <?php if ($this->getReadOnly()):?> disabled="disabled"<?php endif ?>/></td>
93+
<td><input class="input-radio" type="radio" name="default[]" value="{{id}}" <?php if ($this->getReadOnly()):?> disabled="disabled"<?php endif ?>/></td>
94+
<td class="a-left">
95+
<input type="hidden" class="delete-flag" name="option[delete][{{id}}]" value="" />
96+
<?php if (!$this->getReadOnly()):?>
97+
<?php echo $this->getDeleteButtonHtml() ?>
98+
<?php endif ?>
99+
</td>
100+
</tr>
101+
</table>
102+
</div>
103+
<input type="hidden" id="option-count-check" value="" />
104+
</div>
105+
</div>
106+
<script type="text/javascript">
107+
//<![CDATA[
108+
var optionDefaultInputType = 'radio';
109+
110+
// IE removes quotes from element.innerHTML whenever it thinks they're not needed, which breaks html.
111+
var templateText =
112+
'<tr class="option-row" title="ID: {{id}}">'+
113+
<?php if ($this->isConfigurableSwatchesEnabled()): ?>
114+
'<td style="position:relative">'+
115+
'<input type="hidden" disabled class="swatch-value" name="option[swatch][{{id}}]" value="{{swatch}}" />'+
116+
'<input type="color" class="swatch-option input-color-html5 validate-hex-color-hash {{swatch_class}}" value="{{swatch}}" />'+
117+
'<span class="swatch-delete" data-msg-delete="<?php echo Mage::helper('core')->jsQuoteEscape($this->__('Are you sure to delete this fallback color?')); ?>">X</span>'+
118+
'</td>'+
119+
<?php endif ?>
120+
<?php foreach ($this->getStores() as $_store): ?>
121+
'<td><input name="option[value][{{id}}][<?php echo $_store->getId() ?>]" value="{{store<?php echo $_store->getId() ?>}}" class="input-text<?php if($_store->getId()==0): ?> required-option<?php endif ?>" type="text" <?php if ($this->getReadOnly()):?> disabled="disabled"<?php endif ?>/><\/td>'+
122+
<?php endforeach ?>
123+
'<td><input class="input-text" type="text" name="option[order][{{id}}]" value="{{sort_order}}" <?php if ($this->getReadOnly()):?> disabled="disabled"<?php endif ?>/><\/td>'+
124+
'<td class="a-center"><input class="input-radio" type="{{intype}}" name="default[]" value="{{id}}" {{checked}} <?php if ($this->getReadOnly()):?> disabled="disabled"<?php endif ?>/><\/td>'+
125+
'<td class="a-left" id="delete_button_container_{{id}}">'+
126+
'<input type="hidden" class="delete-flag" name="option[delete][{{id}}]" value="" />'+
127+
<?php if (!$this->getReadOnly()):?>
128+
'<?php echo Mage::helper('core')->jsQuoteEscape($this->getDeleteButtonHtml()) ?>'+
129+
<?php endif ?>
130+
'<\/td>'+
131+
'<\/tr>';
132+
133+
var attributeOption = {
134+
table : document.getElementById('attribute-options-table'),
135+
templateSyntax : /(^|.|\r|\n)({{(\w+)}})/,
136+
templateText : templateText,
137+
itemCount : 0,
138+
totalItems : 0,
139+
isReadOnly: <?php echo (int)$this->getReadOnly(); ?>,
140+
add : function(data) {
141+
this.template = new Template(this.templateText, this.templateSyntax);
142+
let isNewOption = false;
143+
if (!data.id) {
144+
data.id = 'option_' + this.itemCount;
145+
isNewOption = true;
146+
}
147+
if (!data.intype) {
148+
data.intype = optionDefaultInputType;
149+
}
150+
if (!data.swatch) {
151+
data.swatch = '#ffffff';
152+
data.swatch_class = 'swatch-disabled';
153+
}
154+
let newHTML = this.template.evaluate(data);
155+
this.table.insertAdjacentHTML('afterend', newHTML);
156+
if (isNewOption && !this.isReadOnly) {
157+
this.enableNewOptionDeleteButton(data.id);
158+
}
159+
this.bindRemoveButtons();
160+
this.bindSwatchButtons();
161+
this.bindSwatchRemoveButtons();
162+
this.itemCount++;
163+
this.totalItems++;
164+
this.updateItemsCountField();
165+
},
166+
remove : function(event){
167+
let element = event.target.closest('tr');
168+
if (element) {
169+
let elementFlags = element.querySelectorAll('.delete-flag');
170+
if (elementFlags.length > 0) {
171+
elementFlags[0].value = 1;
172+
}
173+
174+
element.classList.add('no-display', 'template');
175+
this.totalItems--;
176+
this.updateItemsCountField();
177+
}
178+
},
179+
swatch : function(event){
180+
let element = event.target.closest('tr');
181+
if (element) {
182+
let elementSwatchValue = element.querySelector('.swatch-value');
183+
if (elementSwatchValue) {
184+
elementSwatchValue.disabled = false;
185+
elementSwatchValue.value = event.target.value;
186+
}
187+
188+
event.target.classList.remove('swatch-disabled');
189+
}
190+
},
191+
swatchremove : function(event){
192+
if (!confirm(event.target.getAttribute('data-msg-delete'))) {
193+
return;
194+
}
195+
let element = event.target.closest('tr');
196+
if (element) {
197+
let elementSwatchValue = element.querySelector('.swatch-value');
198+
if (elementSwatchValue) {
199+
elementSwatchValue.disabled = false;
200+
elementSwatchValue.value = '';
201+
}
202+
203+
let elementSwatchOption = element.querySelector('.swatch-option');
204+
if (elementSwatchOption) {
205+
elementSwatchOption.value = '';
206+
elementSwatchOption.classList.add('swatch-disabled');
207+
}
208+
}
209+
},
210+
updateItemsCountField: function() {
211+
let optionCountCheck = document.getElementById('option-count-check');
212+
optionCountCheck.value = this.totalItems > 0 ? '1' : '';
213+
},
214+
enableNewOptionDeleteButton: function(id) {
215+
document.querySelectorAll('#delete_button_container_' + id + ' button').forEach(function(button) {
216+
button.disabled = false;
217+
button.classList.remove('disabled');
218+
});
219+
},
220+
bindRemoveButtons: function() {
221+
let buttons = document.querySelectorAll('.delete-option');
222+
buttons.forEach(function(button) {
223+
if (!button.binded) {
224+
button.binded = true;
225+
button.addEventListener('click', attributeOption.remove.bind(attributeOption));
226+
}
227+
});
228+
},
229+
bindSwatchButtons: function() {
230+
let buttons = document.querySelectorAll('.swatch-option');
231+
buttons.forEach(function(button) {
232+
if (!button.dataset.binded) {
233+
button.dataset.binded = true;
234+
button.addEventListener('change', attributeOption.swatch.bind(attributeOption));
235+
}
236+
});
237+
},
238+
bindSwatchRemoveButtons: function() {
239+
let buttons = document.querySelectorAll('.swatch-delete');
240+
buttons.forEach(function(button) {
241+
if (!button.binded) {
242+
button.binded = true;
243+
button.addEventListener('click', attributeOption.swatchremove.bind(attributeOption));
244+
}
245+
});
246+
}
247+
}
248+
let rowTemplate = document.getElementById('row-template');
249+
if (rowTemplate) {
250+
rowTemplate.remove();
251+
}
252+
attributeOption.bindRemoveButtons();
253+
let addNewOptionButton = document.getElementById('add_new_option_button');
254+
if (addNewOptionButton) {
255+
addNewOptionButton.addEventListener('click', attributeOption.add.bind(attributeOption));
256+
}
257+
Validation.addAllThese([
258+
['required-option', '<?php echo $this->jsQuoteEscape($this->__('Failed')) ?>', function(v) {
259+
return !Validation.get('IsEmpty').test(v);
260+
}]]);
261+
Validation.addAllThese([
262+
['required-options-count', '<?php echo $this->jsQuoteEscape($this->__('Options is required')) ?>', function(v) {
263+
return !Validation.get('IsEmpty').test(v);
264+
}]]);
265+
<?php foreach ($this->getOptionValues() as $_value): ?>
266+
attributeOption.add(<?php echo $_value->toJson() ?>);
267+
<?php endforeach ?>
268+
//]]>
269+
</script>

skin/adminhtml/default/default/boxes.css

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -492,6 +492,36 @@ button.icon-btn span { text-indent:-999em; display:block; width:16px; padding:0;
492492
.buttons-set { margin:0 0 10px; }
493493
.buttons-set button { margin-right:5px; }
494494

495+
/* SWATCHES */
496+
td:has(input.swatch-option) {
497+
display: flex;
498+
gap: 2px;
499+
.swatch-option {
500+
width: 26px !important;
501+
height: 21px;
502+
}
503+
}
504+
505+
td:has(input.swatch-disabled) {
506+
background-image: url('data:image/svg+xml,<svg id="e5490f2e-3f54-4acd-9496-57eed667c240" data-name="Livello 1" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 28.41093 28.29249"><title>placeholder</title><rect x="1.20546" y="1.08375" width="26" height="26" fill="%23fff" stroke="%23ccc" stroke-miterlimit="10"/><line x1="0.70546" y1="27.58375" x2="27.70546" y2="0.70875" fill="none" stroke="%23ff003a" stroke-miterlimit="10" stroke-width="2"/></svg>');
507+
background-repeat: no-repeat;
508+
outline: 1px solid #c8c8c8;
509+
border: 1px solid #fff;
510+
padding: 0;
511+
margin: 2px;
512+
width: 24px;
513+
height: 19px;
514+
display: block;
515+
background-position: center center;
516+
border-radius: 2px;
517+
518+
.swatch-option {
519+
opacity: 0;
520+
}
521+
.swatch-delete {
522+
display: none;
523+
}
524+
}
495525

496526
/* SWITCHER
497527
*******************************************************************************/

0 commit comments

Comments
 (0)