Implement "one click" attachment upload (#5024)

pull/5393/head^2
Aleksander Machniak 8 years ago
parent c65bb121eb
commit 43f3c5fb2a

@ -1,6 +1,7 @@
CHANGELOG Roundcube Webmail CHANGELOG Roundcube Webmail
=========================== ===========================
- Implement "one click" attachment upload (#5024)
- Squirrelmail_usercopy: Add option to define character set of data files - Squirrelmail_usercopy: Add option to define character set of data files
- Removed useless 'created' column from 'session' table (#5389) - Removed useless 'created' column from 'session' table (#5389)
- Dropped legacy browsers support (#5167) - Dropped legacy browsers support (#5167)

@ -1821,6 +1821,9 @@ EOF;
// Disable autocapitalization on iPad/iPhone (#1488609) // Disable autocapitalization on iPad/iPhone (#1488609)
$attrib['autocapitalize'] = 'off'; $attrib['autocapitalize'] = 'off';
$form_name = !empty($attrib['form']) ? $attrib['form'] : 'form';
unset($attrib['form']);
// set atocomplete attribute // set atocomplete attribute
$user_attrib = $autocomplete > 0 ? array() : array('autocomplete' => 'off'); $user_attrib = $autocomplete > 0 ? array() : array('autocomplete' => 'off');
$host_attrib = $autocomplete > 0 ? array() : array('autocomplete' => 'off'); $host_attrib = $autocomplete > 0 ? array() : array('autocomplete' => 'off');
@ -1859,7 +1862,6 @@ EOF;
+ $attrib + $host_attrib); + $attrib + $host_attrib);
} }
$form_name = !empty($attrib['form']) ? $attrib['form'] : 'form';
$this->add_gui_object('loginform', $form_name); $this->add_gui_object('loginform', $form_name);
// create HTML table with two cols // create HTML table with two cols

@ -4756,13 +4756,16 @@ function rcube_webmail()
// count files and size on capable browser // count files and size on capable browser
var size = 0, numfiles = 0; var size = 0, numfiles = 0;
$('input[type=file]', form).each(function(i, field) { $.each($(form).get(0).elements || [], function() {
var files = field.files ? field.files.length : (field.value ? 1 : 0); if (this.type != 'file')
return;
var i, files = this.files ? this.files.length : (this.value ? 1 : 0);
// check file size // check file size
if (field.files) { if (this.files) {
for (var i=0; i < files; i++) for (i=0; i < files; i++)
size += field.files[i].size; size += this.files[i].size;
} }
numfiles += files; numfiles += files;

@ -218,7 +218,8 @@ class html
$attr = array('for' => $attr); $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', 'type','name','value','size','tabindex','autocapitalize','required',
'autocomplete','checked','onchange','onclick','disabled','readonly', 'autocomplete','checked','onchange','onclick','disabled','readonly',
'spellcheck','results','maxlength','src','multiple','accept', 'spellcheck','results','maxlength','src','multiple','accept',
'placeholder','autofocus','pattern' 'placeholder','autofocus','pattern','form',
); );
/** /**

@ -1629,7 +1629,7 @@ function rcmail_compose_attachment_list($attrib)
function rcmail_compose_attachment_form($attrib) function rcmail_compose_attachment_form($attrib)
{ {
global $OUTPUT, $RCMAIL; global $RCMAIL;
// set defaults // set defaults
$attrib += array('id' => 'rcmUploadbox', 'buttons' => 'yes'); $attrib += array('id' => 'rcmUploadbox', 'buttons' => 'yes');
@ -1637,28 +1637,52 @@ function rcmail_compose_attachment_form($attrib)
// Get filesize, enable upload progress bar // Get filesize, enable upload progress bar
$max_filesize = $RCMAIL->upload_init(); $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')); $button = new html_inputfield(array('type' => 'button'));
$content = html::div(null, rcmail_compose_attachment_field()) $content = html::div(null, rcmail_compose_attachment_field()) . $hint;
. html::div('hint', $RCMAIL->gettext(array('name' => 'maxuploadsize', 'vars' => array('size' => $max_filesize))));
if (rcube_utils::get_boolean($attrib['buttons'])) { if (rcube_utils::get_boolean($attrib['buttons'])) {
$content .= html::div('buttons', $content .= html::div('buttons',
$button->show($RCMAIL->gettext('close'), array('class' => 'button', 'onclick' => "$('#$attrib[id]').hide()")) . ' ' . $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( return html::div($attrib, $RCMAIL->output->form_tag($form_attr, $content));
'id' => $attrib['id'] . 'Frm',
'name' => 'uploadform',
'method' => 'post',
'enctype' => 'multipart/form-data'
), $content
));
$OUTPUT->add_gui_object('uploadform', $attrib['id'] . 'Frm');
return $out;
} }

@ -1364,6 +1364,11 @@ div.message-partheaders .headers-table td.header {
color: #888; color: #888;
} }
#compose-attachments .hint {
color: #666;
margin: 0 0 8px;
}
#composeview-bottom .formbuttons.floating { #composeview-bottom .formbuttons.floating {
position: absolute; position: absolute;
width: auto; width: auto;

@ -181,8 +181,20 @@ input.mainaction {
font-weight: bold; font-weight: bold;
} }
input.smart-upload {
visibility: hidden;
width: 1px;
height: 1px;
opacity: 0;
}
/** link buttons **/ /** link buttons **/
input.smart-upload + label {
cursor: pointer;
}
input.smart-upload + label,
a.button, a.button,
.buttongroup { .buttongroup {
display: inline-block; display: inline-block;
@ -206,6 +218,8 @@ a.button,
white-space: nowrap; white-space: nowrap;
} }
input.smart-upload:focus + label,
input.smart-upload + label:focus,
a.button:focus, a.button:focus,
input.button:focus { input.button:focus {
border-color: #4fadd5; border-color: #4fadd5;

@ -30,7 +30,7 @@
<a href="#languages" class="dropbuttontip" id="spellmenulink" onclick="UI.toggle_popup('spellmenu',event);return false" aria-haspopup="true" aria-expanded="false" tabindex="2">Select Spell Language</a> <a href="#languages" class="dropbuttontip" id="spellmenulink" onclick="UI.toggle_popup('spellmenu',event);return false" aria-haspopup="true" aria-expanded="false" tabindex="2">Select Spell Language</a>
</span> </span>
<roundcube:endif /> <roundcube:endif />
<roundcube:button name="addattachment" type="link" class="button attach" label="attach" title="addattachment" onclick="UI.show_uploadform(event);return false" aria-haspopup="true" aria-expanded="false"tabindex="2" /> <roundcube:button name="addattachment" type="link" class="button attach" label="attach" title="addattachment" onclick="$('#uploadformbtn').click(); return false" aria-haspopup="true" aria-expanded="false" tabindex="2" />
<roundcube:button command="insert-sig" type="link" class="button insertsig disabled" classAct="button insertsig" label="signature" title="insertsignature" tabindex="2" /> <roundcube:button command="insert-sig" type="link" class="button insertsig disabled" classAct="button insertsig" label="signature" title="insertsignature" tabindex="2" />
<a href="#responses" class="button responses" label="responses" title="<roundcube:label name='insertresponse' />" id="responsesmenulink" unselectable="on" onmousedown="return false" onclick="UI.toggle_popup('responsesmenu',event);return false" tabindex="2" aria-haspopup="true" aria-expanded="false" aria-owns="textresponsesmenu"><roundcube:label name="responses" /></a> <a href="#responses" class="button responses" label="responses" title="<roundcube:label name='insertresponse' />" id="responsesmenulink" unselectable="on" onmousedown="return false" onclick="UI.toggle_popup('responsesmenu',event);return false" tabindex="2" aria-haspopup="true" aria-expanded="false" aria-owns="textresponsesmenu"><roundcube:label name="responses" /></a>
<roundcube:button command="compose-encrypted" type="link" class="button encrypt disabled" classAct="button encrypt" classSel="button encrypt selected" label="encrypt" title="encryptmessagemailvelope" tabindex="2" style="display:none" /> <roundcube:button command="compose-encrypted" type="link" class="button encrypt disabled" classAct="button encrypt" classSel="button encrypt selected" label="encrypt" title="encryptmessagemailvelope" tabindex="2" style="display:none" />
@ -175,8 +175,8 @@
</div> </div>
<div id="compose-attachments" class="rightcol" role="region" aria-labelledby="aria-label-composeattachments"> <div id="compose-attachments" class="rightcol" role="region" aria-labelledby="aria-label-composeattachments">
<h2 id="aria-label-composeattachments" class="voice"><roundcube:label name="attachments" /></h2> <h2 id="aria-label-composeattachments" class="voice"><roundcube:label name="attachments" /></h2>
<div style="text-align:center; margin-bottom:20px"> <div style="text-align:center; margin-bottom:10px">
<roundcube:button name="addattachment" type="input" class="button" classSel="button pressed" label="addattachment" onclick="UI.show_uploadform(event);return false" tabindex="1" /> <roundcube:object name="composeAttachmentForm" id="uploadform" smart-button="yes" tabindex="1" />
</div> </div>
<roundcube:object name="composeAttachmentList" id="attachment-list" class="attachmentslist" tabindex="1" /> <roundcube:object name="composeAttachmentList" id="attachment-list" class="attachmentslist" tabindex="1" />
<roundcube:object name="fileDropArea" id="compose-attachments" /> <roundcube:object name="fileDropArea" id="compose-attachments" />
@ -198,15 +198,6 @@
</div><!-- end mainscreen --> </div><!-- end mainscreen -->
<div id="upload-dialog" class="propform popupdialog" title="<roundcube:label name='addattachment' />" aria-hidden="true">
<h2 id="aria-label-uploaddialog" class="voice"><roundcube:label name="arialabelattachmentuploadform" /></h2>
<roundcube:object name="composeAttachmentForm" id="uploadform" buttons="no" />
<div class="formbuttons">
<roundcube:button command="send-attachment" type="input" class="button mainaction" label="upload" />
<roundcube:button name="close" type="input" class="button" label="cancel" onclick="UI.show_uploadform()" />
</div>
</div>
<div id="spellmenu" class="popupmenu" aria-hidden="true"></div> <div id="spellmenu" class="popupmenu" aria-hidden="true"></div>
<div id="responsesmenu" class="popupmenu" aria-hidden="true"> <div id="responsesmenu" class="popupmenu" aria-hidden="true">

Loading…
Cancel
Save