diff --git a/CHANGELOG b/CHANGELOG
index d8c580ef6..c81f35fca 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,6 +1,7 @@
CHANGELOG Roundcube Webmail
===========================
+- Implement "one click" attachment upload (#5024)
- Squirrelmail_usercopy: Add option to define character set of data files
- Removed useless 'created' column from 'session' table (#5389)
- Dropped legacy browsers support (#5167)
diff --git a/program/include/rcmail_output_html.php b/program/include/rcmail_output_html.php
index daec191a4..8a0dbd3c3 100644
--- a/program/include/rcmail_output_html.php
+++ b/program/include/rcmail_output_html.php
@@ -1821,6 +1821,9 @@ EOF;
// Disable autocapitalization on iPad/iPhone (#1488609)
$attrib['autocapitalize'] = 'off';
+ $form_name = !empty($attrib['form']) ? $attrib['form'] : 'form';
+ unset($attrib['form']);
+
// set atocomplete attribute
$user_attrib = $autocomplete > 0 ? array() : array('autocomplete' => 'off');
$host_attrib = $autocomplete > 0 ? array() : array('autocomplete' => 'off');
@@ -1859,7 +1862,6 @@ EOF;
+ $attrib + $host_attrib);
}
- $form_name = !empty($attrib['form']) ? $attrib['form'] : 'form';
$this->add_gui_object('loginform', $form_name);
// create HTML table with two cols
diff --git a/program/js/app.js b/program/js/app.js
index 6a74f2576..e7093553d 100644
--- a/program/js/app.js
+++ b/program/js/app.js
@@ -4756,13 +4756,16 @@ function rcube_webmail()
// count files and size on capable browser
var size = 0, numfiles = 0;
- $('input[type=file]', form).each(function(i, field) {
- var files = field.files ? field.files.length : (field.value ? 1 : 0);
+ $.each($(form).get(0).elements || [], function() {
+ if (this.type != 'file')
+ return;
+
+ var i, files = this.files ? this.files.length : (this.value ? 1 : 0);
// check file size
- if (field.files) {
- for (var i=0; i < files; i++)
- size += field.files[i].size;
+ if (this.files) {
+ for (i=0; i < files; i++)
+ size += this.files[i].size;
}
numfiles += files;
diff --git a/program/lib/Roundcube/html.php b/program/lib/Roundcube/html.php
index dd814ef76..25c4657b4 100644
--- a/program/lib/Roundcube/html.php
+++ b/program/lib/Roundcube/html.php
@@ -218,7 +218,8 @@ class html
$attr = array('for' => $attr);
}
- return self::tag('label', $attr, $cont, array_merge(self::$common_attrib, array('for')));
+ return self::tag('label', $attr, $cont, array_merge(self::$common_attrib,
+ array('for','onkeypress')));
}
/**
@@ -395,7 +396,7 @@ class html_inputfield extends html
'type','name','value','size','tabindex','autocapitalize','required',
'autocomplete','checked','onchange','onclick','disabled','readonly',
'spellcheck','results','maxlength','src','multiple','accept',
- 'placeholder','autofocus','pattern'
+ 'placeholder','autofocus','pattern','form',
);
/**
diff --git a/program/steps/mail/compose.inc b/program/steps/mail/compose.inc
index 10a9b09c0..d10db525b 100644
--- a/program/steps/mail/compose.inc
+++ b/program/steps/mail/compose.inc
@@ -1629,7 +1629,7 @@ function rcmail_compose_attachment_list($attrib)
function rcmail_compose_attachment_form($attrib)
{
- global $OUTPUT, $RCMAIL;
+ global $RCMAIL;
// set defaults
$attrib += array('id' => 'rcmUploadbox', 'buttons' => 'yes');
@@ -1637,28 +1637,52 @@ function rcmail_compose_attachment_form($attrib)
// Get filesize, enable upload progress bar
$max_filesize = $RCMAIL->upload_init();
+ $hint = html::div('hint', $RCMAIL->gettext(array('name' => 'maxuploadsize', 'vars' => array('size' => $max_filesize))));
+ $event = rcmail_output::JS_OBJECT_NAME . ".command('send-attachment', this.form)";
+ $form_id = $attrib['id'] . 'Frm';
+ $form_attr = array(
+ 'id' => $form_id,
+ 'name' => 'uploadform',
+ 'method' => 'post',
+ 'enctype' => 'multipart/form-data'
+ );
+
+ $RCMAIL->output->add_gui_object('uploadform', $form_id);
+
+ if (rcube_utils::get_boolean($attrib['smart-button'])) {
+ $form = $RCMAIL->output->form_tag($form_attr);
+ $RCMAIL->output->add_footer($form);
+
+ $input_attrs = $attrib + array(
+ // Note: Chrome sometimes executes onchange event on Cancel, make sure a file was selected
+ 'onchange' => "if ((this.files && this.files.length) || (!this.files && this.value)) $event",
+ 'form' => $form_id,
+ 'class' => 'smart-upload',
+ 'tabindex' => '-1',
+ );
+
+ $label_attrs = array(
+ 'for' => $attrib['id'],
+ 'id' => $attrib['id'] . 'btn',
+ 'tabindex' => $attrib['tabindex'],
+ 'onkeypress' => 'if (event.keyCode == 13) this.click()',
+ );
+
+ return $hint . rcmail_compose_attachment_field($input_attrs)
+ . html::label($label_attrs, $RCMAIL->gettext('addattachment'));
+ }
+
$button = new html_inputfield(array('type' => 'button'));
- $content = html::div(null, rcmail_compose_attachment_field())
- . html::div('hint', $RCMAIL->gettext(array('name' => 'maxuploadsize', 'vars' => array('size' => $max_filesize))));
+ $content = html::div(null, rcmail_compose_attachment_field()) . $hint;
if (rcube_utils::get_boolean($attrib['buttons'])) {
$content .= html::div('buttons',
$button->show($RCMAIL->gettext('close'), array('class' => 'button', 'onclick' => "$('#$attrib[id]').hide()")) . ' ' .
- $button->show($RCMAIL->gettext('upload'), array('class' => 'button mainaction', 'onclick' => rcmail_output::JS_OBJECT_NAME . ".command('send-attachment', this.form)"))
+ $button->show($RCMAIL->gettext('upload'), array('class' => 'button mainaction', 'onclick' => $event))
);
}
- $out = html::div($attrib, $OUTPUT->form_tag(array(
- 'id' => $attrib['id'] . 'Frm',
- 'name' => 'uploadform',
- 'method' => 'post',
- 'enctype' => 'multipart/form-data'
- ), $content
- ));
-
- $OUTPUT->add_gui_object('uploadform', $attrib['id'] . 'Frm');
-
- return $out;
+ return html::div($attrib, $RCMAIL->output->form_tag($form_attr, $content));
}
diff --git a/skins/larry/mail.css b/skins/larry/mail.css
index 823a2a8f8..23c852a7a 100644
--- a/skins/larry/mail.css
+++ b/skins/larry/mail.css
@@ -1364,6 +1364,11 @@ div.message-partheaders .headers-table td.header {
color: #888;
}
+#compose-attachments .hint {
+ color: #666;
+ margin: 0 0 8px;
+}
+
#composeview-bottom .formbuttons.floating {
position: absolute;
width: auto;
diff --git a/skins/larry/styles.css b/skins/larry/styles.css
index a5bd8fad9..8473f6352 100644
--- a/skins/larry/styles.css
+++ b/skins/larry/styles.css
@@ -181,8 +181,20 @@ input.mainaction {
font-weight: bold;
}
+input.smart-upload {
+ visibility: hidden;
+ width: 1px;
+ height: 1px;
+ opacity: 0;
+}
+
/** link buttons **/
+input.smart-upload + label {
+ cursor: pointer;
+}
+
+input.smart-upload + label,
a.button,
.buttongroup {
display: inline-block;
@@ -206,6 +218,8 @@ a.button,
white-space: nowrap;
}
+input.smart-upload:focus + label,
+input.smart-upload + label:focus,
a.button:focus,
input.button:focus {
border-color: #4fadd5;
diff --git a/skins/larry/templates/compose.html b/skins/larry/templates/compose.html
index c00ca082a..533a135a1 100644
--- a/skins/larry/templates/compose.html
+++ b/skins/larry/templates/compose.html
@@ -30,7 +30,7 @@
Select Spell Language