From 30d31c323b7acad585d2641dfc80f9e1fb9665da Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Sat, 16 May 2020 09:41:35 +0200 Subject: [PATCH] Improve UX on custom header input (#7207) --- CHANGELOG | 1 + plugins/managesieve/Changelog | 1 + .../lib/Roundcube/rcube_sieve_engine.php | 68 ++++++++++++------- plugins/managesieve/managesieve.js | 23 ++++--- skins/elastic/ui.js | 36 +++++----- 5 files changed, 73 insertions(+), 56 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index a092c3688..131dff2b6 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -11,6 +11,7 @@ CHANGELOG Roundcube Webmail - Extract RFC2231 attachment name from message headers (#6729, #6783) - Archive: Added options to split archive by year or year+month and folder (#7216) - Managesieve: Allow display name with email address in vacation :from field (#6760) +- Managesieve: Improve UX on custom header input (#7207) - Password: Added 'pwned' password strength driver (#7274) - Add support for SameSite cookie attribute via session_samesite option (req PHP >= 7.3.0) (#6772) - Elastic: Display a special icon for other users and shared namespace roots (#5012) diff --git a/plugins/managesieve/Changelog b/plugins/managesieve/Changelog index d39181cea..af4765c32 100644 --- a/plugins/managesieve/Changelog +++ b/plugins/managesieve/Changelog @@ -1,3 +1,4 @@ +- Improve UX on custom header input (#7207) - Allow display name with email address in vacation :from field (#6760) - Replace "Filter disabled" with "Filter enabled" (#7028) - Fix so modifier type select wasn't hidden after hiding modifier select on header change diff --git a/plugins/managesieve/lib/Roundcube/rcube_sieve_engine.php b/plugins/managesieve/lib/Roundcube/rcube_sieve_engine.php index 72afcd069..eb57a0ad7 100644 --- a/plugins/managesieve/lib/Roundcube/rcube_sieve_engine.php +++ b/plugins/managesieve/lib/Roundcube/rcube_sieve_engine.php @@ -1773,11 +1773,17 @@ class rcube_sieve_engine } // custom header and variable inputs - $aout .= $this->list_input($id, 'custom_header', $custom, isset($custom), - $this->error_class($id, 'test', 'header', 'custom_header'), 15) . "\n"; - - $aout .= $this->list_input($id, 'custom_var', $customv, isset($customv), - $this->error_class($id, 'test', 'header', 'custom_var'), 15) . "\n"; + $aout .= $this->list_input($id, 'custom_header', $custom, 15, false, array( + 'disabled' => !isset($custom), + 'class' => $this->error_class($id, 'test', 'header', 'custom_header'), + 'placeholder' => $this->plugin->gettext('headername'), + 'title' => $this->plugin->gettext('headername'), + )) . "\n"; + + $aout .= $this->list_input($id, 'custom_var', $customv, 15, false, array( + 'disabled' => !isset($customv), + 'class' => $this->error_class($id, 'test', 'header', 'custom_var') + )) . "\n"; $test = self::rule_test($rule); $target = ''; @@ -1830,9 +1836,10 @@ class rcube_sieve_engine } $tout .= $this->match_type_selector('rule_op', $id, $test, $rule['test']); - $tout .= $this->list_input($id, 'rule_target', $target, - $rule['test'] != 'size' && $rule['test'] != 'exists' && $rule['test'] != 'duplicate', - $this->error_class($id, 'test', 'target', 'rule_target')) . "\n"; + $tout .= $this->list_input($id, 'rule_target', $target, null, false, array( + 'disabled' => $rule['test'] == 'size' || $rule['test'] == 'exists' || $rule['test'] == 'duplicate', + 'class' => $this->error_class($id, 'test', 'target', 'rule_target') + )) . "\n"; $select_size_op = new html_select(array('name' => "_rule_size_op[$id]", 'id' => 'rule_size_op'.$id, 'class' => 'input-group-prepend')); $select_size_op->add(rcube::Q($this->plugin->gettext('filterover')), 'over'); @@ -1920,8 +1927,9 @@ class rcube_sieve_engine $mout .= ''; } @@ -2256,8 +2264,9 @@ class rcube_sieve_engine 'class' => $this->error_class($id, 'action', 'from', 'action_from'), )); $out .= '
' .rcube::Q($this->plugin->gettext('vacationaddr')) . '
'; - $out .= $this->list_input($id, 'action_addresses', $action['addresses'], true, - $this->error_class($id, 'action', 'addresses', 'action_addresses'), 30) + $out .= $this->list_input($id, 'action_addresses', $action['addresses'], 30, false, array( + 'class' => $this->error_class($id, 'action', 'addresses', 'action_addresses') + )) . html::a(array('href' => '#', 'onclick' => rcmail_output::JS_OBJECT_NAME . ".managesieve_vacation_addresses($id)"), rcube::Q($this->plugin->gettext('filladdresses'))); $out .= '
' . rcube::Q($this->plugin->gettext('vacationinterval')) . '
'; @@ -2311,8 +2320,10 @@ class rcube_sieve_engine . rcube::Q($this->plugin->gettext('flag'.$fidx))) . '
'; } - $flout .= $this->list_input($id, 'action_flags', $custom_flags, true, - $this->error_class($id, 'action', 'flag', 'action_flags_flag'), null, false, "action_flags_flag{$id}"); + $flout .= $this->list_input($id, 'action_flags', $custom_flags, null, false, array( + 'class' => $this->error_class($id, 'action', 'flag', 'action_flags_flag'), + 'id' => "action_flags_flag{$id}" + )); $out .= html::div(array( 'id' => 'action_flags' . $id, @@ -2426,9 +2437,10 @@ class rcube_sieve_engine $out .= '
' . rcube::Q($this->plugin->gettext('notifyimportance')) . '
'; $out .= $select_importance->show($action['importance'] ? (int) $action['importance'] : 2); $out .= '
' - .'' . rcube::Q($this->plugin->gettext('notifyoptions')) . '
' - .$this->list_input($id, 'action_notifyoption', (array)$action['options'], true, - $this->error_class($id, 'action', 'options', 'action_notifyoption'), 30) . '
'; + . '' . rcube::Q($this->plugin->gettext('notifyoptions')) . '
' + . $this->list_input($id, 'action_notifyoption', (array) $action['options'], 30, false, array( + 'class' => $this->error_class($id, 'action', 'options', 'action_notifyoption') + )) . ''; $out .= ''; if (in_array('editheader', $this->exts)) { @@ -2484,8 +2496,9 @@ class rcube_sieve_engine 'class' => $this->error_class($id, 'action', 'name', 'action_delheader_name'), )); $out .= '

'; - $out .= $this->list_input($id, 'action_delheader_value', $action['value'], true, - $this->error_class($id, 'action', 'value', 'action_delheader_value')) . "\n"; + $out .= $this->list_input($id, 'action_delheader_value', $action['value'], null, false, array( + 'class' => $this->error_class($id, 'action', 'value', 'action_delheader_value') + )) . "\n"; $out .= '
'; $out .= html::span('label input-group-prepend', html::label(array( 'class' => 'input-group-text', 'for' => 'action_delheader_op'.$id), rcube::Q($this->plugin->gettext('headermatchtype')))); @@ -2606,22 +2619,25 @@ class rcube_sieve_engine $this->rc->output->add_script($script, 'docready'); } - protected function list_input($id, $name, $value, $enabled, $class, $size = null, $hidden = false, $elem_id = null) + protected function list_input($id, $name, $value, $size = null, $hidden = false, $attrib = array()) { $value = (array) $value; $value = array_map(array('rcube', 'Q'), $value); $value = implode("\n", $value); - return html::tag('textarea', array( + $attrib = array_merge($attrib, array( 'data-type' => 'list', 'data-size' => $size, 'data-hidden' => $hidden ?: null, 'name' => '_' . $name . '[' . $id . ']', - 'id' => $elem_id ?: ($name.$id), - 'disabled' => !$enabled, - 'class' => $class, 'style' => 'display:none', - ), $value); + )); + + if (empty($attrib['id'])) { + $attrib['id'] = $name . $id; + } + + return html::tag('textarea', $attrib, $value); } /** @@ -3062,7 +3078,7 @@ class rcube_sieve_engine 'name' => "_{$name}[$id]", 'id' => "{$name}{$id}", 'style' => 'display:' .(!in_array($rule, array('size', 'duplicate')) ? 'inline' : 'none'), - 'class' => 'operator_selector', + 'class' => 'operator_selector col-6', 'onchange' => "{$name}_select(this, '{$id}')", )); diff --git a/plugins/managesieve/managesieve.js b/plugins/managesieve/managesieve.js index c2fd7a536..59ba0750e 100644 --- a/plugins/managesieve/managesieve.js +++ b/plugins/managesieve/managesieve.js @@ -814,7 +814,7 @@ function smart_field_init(field) // add input rows $.each(list, function(i, v) { - area.append(smart_field_row(v, field.name, i, $(field).data('size'))); + area.append(smart_field_row(v, i, field)); }); area.attr('id', id); @@ -837,25 +837,26 @@ function smart_field_init(field) } }; -function smart_field_row(value, name, idx, size) +function smart_field_row(value, idx, field) { // build row element content var input, content = '' + '', elem = $(content), - attrs = {value: value, name: name + '[]'}; - - if (size) - attrs.size = size; + attrs = { + value: value, + name: field.name + '[]', + size: $(field).data('size'), + title: field.title, + placeholder: $(field).attr('placeholder') + }; - input = $('input', elem).attr(attrs).keydown(function(e) { + input = elem.find('input').attr(attrs).keydown(function(e) { var input = $(this); // element creation event (on Enter) if (e.which == 13) { - var name = input.attr('name').replace(/\[\]$/, ''), - dt = (new Date()).getTime(), - elem = smart_field_row('', name, dt, size); + var elem = smart_field_row('', (new Date()).getTime(), field); input.parent().after(elem); $('input', elem).focus(); @@ -904,7 +905,7 @@ function smart_field_reset(field, data) // add input rows $.each(list, function(i, v) { - area.append(smart_field_row(v, field.name, i, $(field).data('size'))); + area.append(smart_field_row(v, i, field)); }); } diff --git a/skins/elastic/ui.js b/skins/elastic/ui.js index 427f39be4..65ac3fc24 100644 --- a/skins/elastic/ui.js +++ b/skins/elastic/ui.js @@ -3836,7 +3836,7 @@ function rcube_elastic_ui() // add input rows $.each(list, function(i, v) { - smart_field_row_add($('.content', area), v, field.name, i, $(field).data('size')); + smart_field_row_add($('.content', area), v, i, field); }); area.attr('id', id); @@ -3862,28 +3862,26 @@ function rcube_elastic_ui() } }; - function smart_field_row_add(area, value, name, idx, size, after) + function smart_field_row_add(area, value, idx, field, after) { // build row element content - var input, elem = $('
' + var input, + elem = $('
' + '' + '' - + '
'), - attrs = {value: value, name: name + '[]'}; - - if (size) { - attrs.size = size; - } - - input = $('input', elem).attr(attrs) + + '
'); + + input = elem.find('input').attr({ + value: value, + name: field.name + '[]', + size: $(field).data('size'), + title: field.title, + placeholder: field.placeholder + }) .keydown(function(e) { - var input = $(this); - // element creation event (on Enter) if (e.which == 13) { - var name = input.attr('name').replace(/\[\]$/, ''), - dt = (new Date()).getTime(), - elem = smart_field_row_add(area, '', name, dt, size, input.parent()); + var elem = smart_field_row_add(area, '', (new Date()).getTime(), field, input.parent()); $('input', elem).focus(); } @@ -3907,7 +3905,7 @@ function rcube_elastic_ui() }); // element deletion event - $('a.reset', elem).click(function() { + elem.find('a.reset').click(function() { var record = $(this.parentNode.parentNode); if (area.children().length > 1) { @@ -3919,7 +3917,7 @@ function rcube_elastic_ui() } }); - $(elem).find('input,a') + elem.find('input,a') .on('focus', function() { area.addClass('focused'); }) .on('blur', function() { area.removeClass('focused'); }); @@ -3944,7 +3942,7 @@ function rcube_elastic_ui() // add input rows $.each(list, function(i, v) { - smart_field_row_add(area, v, field.name, i, $(field).data('size')); + smart_field_row_add(area, v, i, field); }); };