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 @@ -