From 646b64107a578d228a23d5b82923fb794fdb9c55 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Fri, 30 May 2014 08:32:06 +0200 Subject: Implemented Text Editor widget that integrates all operations on textareas including HTML editor and spellchecking --- program/steps/settings/edit_identity.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'program/steps/settings') diff --git a/program/steps/settings/edit_identity.inc b/program/steps/settings/edit_identity.inc index 3f7b6a58a..e43a7bb60 100644 --- a/program/steps/settings/edit_identity.inc +++ b/program/steps/settings/edit_identity.inc @@ -96,7 +96,7 @@ function rcube_identity_form($attrib) 'spellcheck' => true), 'html_signature' => array('type' => 'checkbox', 'label' => $RCMAIL->gettext('htmlsignature'), - 'onclick' => 'return rcmail_toggle_editor(this, \'rcmfd_signature\');'), + 'onclick' => 'return rcmail.command(\'toggle-editor\', {id: \'rcmfd_signature\', html: this.checked}, \'\', event)'), )) ); -- cgit v1.2.3 From 77043f8469ba8e7b64af5b0192b0297ded5c615f Mon Sep 17 00:00:00 2001 From: Thomas Bruederli Date: Tue, 3 Jun 2014 19:13:54 +0200 Subject: Apply accessibility improvements to the settings section --- plugins/managesieve/skins/larry/managesieve.css | 8 +- program/include/rcmail.php | 7 +- program/localization/en_US/labels.inc | 4 + program/steps/settings/edit_folder.inc | 3 +- program/steps/settings/func.inc | 2 +- program/steps/settings/responses.inc | 2 +- skins/larry/includes/footer.html | 1 + skins/larry/includes/settingstabs.html | 8 +- skins/larry/settings.css | 101 ++++++++++++------------ skins/larry/templates/addressbook.html | 4 +- skins/larry/templates/folders.html | 25 +++--- skins/larry/templates/identities.html | 12 +-- skins/larry/templates/importcontacts.html | 2 +- skins/larry/templates/responses.html | 12 +-- skins/larry/templates/settings.html | 11 ++- skins/larry/ui.js | 4 +- 16 files changed, 117 insertions(+), 89 deletions(-) (limited to 'program/steps/settings') diff --git a/plugins/managesieve/skins/larry/managesieve.css b/plugins/managesieve/skins/larry/managesieve.css index 1f954caf2..2172c60b2 100644 --- a/plugins/managesieve/skins/larry/managesieve.css +++ b/plugins/managesieve/skins/larry/managesieve.css @@ -417,11 +417,13 @@ body.iframe.mail #filter-form /* vacation form */ -#settings-sections span.vacation a { - background: url(images/vacation_icons.png) no-repeat 7px 1px; +#settings-sections .vacation a { + background-image: url(images/vacation_icons.png); + background-repeat: no-repeat; + background-position: 7px 1px; } -#settings-sections span.vacation.selected a { +#settings-sections .vacation.selected a { background-position: 7px -23px; } diff --git a/program/include/rcmail.php b/program/include/rcmail.php index 8e66e85e7..5a5d4cb83 100644 --- a/program/include/rcmail.php +++ b/program/include/rcmail.php @@ -1088,14 +1088,17 @@ class rcmail extends rcube } else { foreach ($table_data as $row_data) { - $class = !empty($row_data['class']) ? $row_data['class'] : ''; + $class = !empty($row_data['class']) ? $row_data['class'] : null; + if (!empty($attrib['rowclass'])) + $class = trim($class . ' ' . $attrib['rowclass']); $rowid = 'rcmrow' . rcube_utils::html_identifier($row_data[$id_col]); $table->add_row(array('id' => $rowid, 'class' => $class)); // format each col foreach ($a_show_cols as $col) { - $table->add($col, $this->Q(is_array($row_data[$col]) ? $row_data[$col][0] : $row_data[$col])); + $val = is_array($row_data[$col]) ? $row_data[$col][0] : $row_data[$col]; + $table->add($col, empty($attrib['ishtml']) ? $this->Q($val) : $val); } } } diff --git a/program/localization/en_US/labels.inc b/program/localization/en_US/labels.inc index 2b44ac188..9d3863497 100644 --- a/program/localization/en_US/labels.inc +++ b/program/localization/en_US/labels.inc @@ -474,6 +474,7 @@ $labels['miscfolding'] = 'RFC 2047/2231 (MS Outlook)'; $labels['2047folding'] = 'Full RFC 2047 (other)'; $labels['force7bit'] = 'Use MIME encoding for 8-bit characters'; $labels['advancedoptions'] = 'Advanced options'; +$labels['toggleadvancedoptions'] = 'Toggle advanced options'; $labels['focusonnewmessage'] = 'Focus browser window on new message'; $labels['checkallfolders'] = 'Check all folders for new messages'; $labels['displaynext'] = 'After message delete/move display the next message'; @@ -605,6 +606,9 @@ $labels['arialabelattachmentpreview'] = 'Attachment preview'; $labels['ariasummarycomposecontacts'] = 'List of contacts and groups to select as recipients'; $labels['arialabelcontactexportoptions'] = 'Contact export options'; $labels['arialabelabookgroupoptions'] = 'Addressbook/group options'; +$labels['arialabelpreferencesform'] = 'Preferences form'; +$labels['arialabelidentityeditfrom'] = 'Identity edit form'; +$labels['arialabelresonseeditfrom'] = 'Response edit form'; $labels['helplistnavigation'] = 'List keyboard navigation'; $labels['helplistkeyboardnavigation'] = "Arrows up/down: Move row focus/selection. diff --git a/program/steps/settings/edit_folder.inc b/program/steps/settings/edit_folder.inc index 6b7bd08d2..c61ac6da9 100644 --- a/program/steps/settings/edit_folder.inc +++ b/program/steps/settings/edit_folder.inc @@ -132,6 +132,7 @@ function rcmail_folder_form($attrib) } $select = $RCMAIL->folder_selector(array( + 'id' => '_parent', 'name' => '_parent', 'noselection' => '---', 'realnames' => false, @@ -155,7 +156,7 @@ function rcmail_folder_form($attrib) // Settings: threading if ($threading_supported && ($mbox_imap == 'INBOX' || (!$options['noselect'] && !$options['is_root']))) { - $select = new html_select(array('name' => '_viewmode', 'id' => '_listmode')); + $select = new html_select(array('name' => '_viewmode', 'id' => '_viewmode')); $select->add($RCMAIL->gettext('list'), 0); $select->add($RCMAIL->gettext('threads'), 1); diff --git a/program/steps/settings/func.inc b/program/steps/settings/func.inc index bccd9caa8..5da01b757 100644 --- a/program/steps/settings/func.inc +++ b/program/steps/settings/func.inc @@ -343,7 +343,7 @@ function rcmail_user_prefs($current = null) if (is_array($meta) && $meta['name']) { $skinname = $meta['name']; $author_link = $meta['url'] ? html::a(array('href' => $meta['url'], 'target' => '_blank'), rcube::Q($meta['author'])) : rcube::Q($meta['author']); - $license_link = $meta['license-url'] ? html::a(array('href' => $meta['license-url'], 'target' => '_blank'), rcube::Q($meta['license'])) : rcube::Q($meta['license']); + $license_link = $meta['license-url'] ? html::a(array('href' => $meta['license-url'], 'target' => '_blank', 'tabindex' => '-1'), rcube::Q($meta['license'])) : rcube::Q($meta['license']); } $skinnames[] = mb_strtolower($skinname); diff --git a/program/steps/settings/responses.inc b/program/steps/settings/responses.inc index 06093b3b8..ddd1924fe 100644 --- a/program/steps/settings/responses.inc +++ b/program/steps/settings/responses.inc @@ -95,7 +95,7 @@ function rcmail_responses_list($attrib) { global $RCMAIL, $OUTPUT; - $attrib += array('id' => 'rcmresponseslist', 'tagname' => 'table', 'cols' => 1); + $attrib += array('id' => 'rcmresponseslist', 'tagname' => 'table'); $plugin = $RCMAIL->plugins->exec_hook('responses_list', array( 'list' => $RCMAIL->get_compose_responses(true), diff --git a/skins/larry/includes/footer.html b/skins/larry/includes/footer.html index f421ec5b0..6cd3e62d1 100644 --- a/skins/larry/includes/footer.html +++ b/skins/larry/includes/footer.html @@ -6,6 +6,7 @@ var UI = new rcube_mail_ui(); $(document).ready(function(){ UI.set('errortitle', ''); + UI.set('toggleoptions', ''); UI.init(); }); diff --git a/skins/larry/includes/settingstabs.html b/skins/larry/includes/settingstabs.html index e62695848..d43e8f075 100644 --- a/skins/larry/includes/settingstabs.html +++ b/skins/larry/includes/settingstabs.html @@ -1,7 +1,9 @@ -
-

+ diff --git a/skins/larry/settings.css b/skins/larry/settings.css index 675ef9973..0517f3c3a 100644 --- a/skins/larry/settings.css +++ b/skins/larry/settings.css @@ -70,7 +70,7 @@ width: 20px; height: 18px; background: url('images/listicons.png') 0 -1157px no-repeat; - text-indent: 1000px; + text-indent: -5000px; overflow: hidden; } @@ -78,9 +78,10 @@ background-position: -24px -1137px; } -#sections-table tbody td.section, -#settings-sections span.listitem a, -#settings-sections span.tablink a { +#sections-table td.section, +#sections-table .listitem span, +#settings-sections .listitem a, +#settings-sections .tablink a { padding-left: 36px; background-image: url(images/listicons.png); background-position: -100px 0; @@ -88,120 +89,120 @@ } /* note: support span.tablink because this is used by plugins */ -#settings-sections span.listitem a, -#settings-sections span.tablink a { +#settings-sections .listitem a, +#settings-sections .tablink a { background-position: 6px -862px; } -#settings-sections span.selected a, -#settings-sections span.tablink.selected a { +#settings-sections .selected a, +#settings-sections .tablink.selected a { background-position: 6px -887px; } -#settings-sections span.preferences a { +#settings-sections .preferences a { background-position: 6px -431px; } -#settings-sections span.preferences.selected a { +#settings-sections .preferences.selected a { background-position: 6px -455px; } -#settings-sections span.folders a, -#sections-table #rcmrowfolders td.section { +#settings-sections .folders a, +#sections-table #rcmrowfolders .section { background-position: 6px 2px; } -#settings-sections span.folders.selected a, -#sections-table #rcmrowfolders.selected td.section { +#settings-sections .folders.selected a, +#sections-table #rcmrowfolders.selected .section { background-position: 6px -22px; } -#settings-sections span.identities a { +#settings-sections .identities a { background-position: 6px -478px; } -#settings-sections span.identities.selected a { +#settings-sections .identities.selected a { background-position: 6px -502px; } -#settings-sections span.filter a { +#settings-sections .filter a { background-position: 6px -1746px; } -#settings-sections span.filter.selected a { +#settings-sections .filter.selected a { background-position: 6px -1770px; } -#settings-sections span.password a { +#settings-sections .password a { background-position: 6px -1795px; } -#settings-sections span.password.selected a { +#settings-sections .password.selected a { background-position: 6px -1819px; } -#settings-sections span.responses a { +#settings-sections .responses a { background-position: 6px -1972px; } -#settings-sections span.responses.selected a { +#settings-sections .responses.selected a { background-position: 6px -1996px; } -#sections-table #rcmrowgeneral td.section { - background-position: 6px -573px; +#sections-table #rcmrowgeneral .section { + background-position: 4px -573px; } -#sections-table #rcmrowgeneral.selected td.section { - background-position: 6px -598px; +#sections-table #rcmrowgeneral.selected .section { + background-position: 4px -598px; } -#sections-table #rcmrowmailbox td.section { - background-position: 6px -621px; +#sections-table #rcmrowmailbox .section { + background-position: 4px -621px; } -#sections-table #rcmrowmailbox.selected td.section { - background-position: 6px -646px; +#sections-table #rcmrowmailbox.selected .section { + background-position: 4px -646px; } -#sections-table #rcmrowcompose td.section { - background-position: 6px -670px; +#sections-table #rcmrowcompose .section { + background-position: 4px -670px; } -#sections-table #rcmrowcompose.selected td.section { - background-position: 6px -695px; +#sections-table #rcmrowcompose.selected .section { + background-position: 4px -695px; } -#sections-table #rcmrowmailview td.section { - background-position: 6px -718px; +#sections-table #rcmrowmailview .section { + background-position: 4px -718px; } -#sections-table #rcmrowmailview.selected td.section { - background-position: 6px -742px; +#sections-table #rcmrowmailview.selected .section { + background-position: 4px -742px; } -#sections-table #rcmrowaddressbook td.section { - background-position: 6px -766px; +#sections-table #rcmrowaddressbook .section { + background-position: 4px -766px; } -#sections-table #rcmrowaddressbook.selected td.section { - background-position: 6px -791px; +#sections-table #rcmrowaddressbook.selected .section { + background-position: 4px -791px; } -#sections-table #rcmrowserver td.section { - background-position: 6px -814px; +#sections-table #rcmrowserver .section { + background-position: 4px -814px; } -#sections-table #rcmrowserver.selected td.section { - background-position: 6px -838px; +#sections-table #rcmrowserver.selected .section { + background-position: 4px -838px; } -#sections-table #rcmrowcalendar td.section { - background-position: 6px -526px; +#sections-table #rcmrowcalendar .section { + background-position: 4px -526px; } -#sections-table #rcmrowcalendar.selected td.section { - background-position: 6px -550px; +#sections-table #rcmrowcalendar.selected .section { + background-position: 4px -550px; } #folderslist, diff --git a/skins/larry/templates/addressbook.html b/skins/larry/templates/addressbook.html index c9aa5acad..e1101e648 100644 --- a/skins/larry/templates/addressbook.html +++ b/skins/larry/templates/addressbook.html @@ -84,10 +84,10 @@
-
+
-
+
diff --git a/skins/larry/templates/folders.html b/skins/larry/templates/folders.html index 56396bf1d..ffb0a7ee1 100644 --- a/skins/larry/templates/folders.html +++ b/skins/larry/templates/folders.html @@ -10,9 +10,11 @@
+

:

+ -
+

@@ -20,11 +22,22 @@
+ + +
@@ -37,14 +50,6 @@
-
-
    -
  • -
  • - -
-
- diff --git a/skins/larry/templates/identities.html b/skins/larry/templates/identities.html index e3d2cc842..91f7f8f71 100644 --- a/skins/larry/templates/identities.html +++ b/skins/larry/templates/identities.html @@ -10,23 +10,25 @@
+

:

+ -
+
-

+

- +
- +
- +
diff --git a/skins/larry/templates/importcontacts.html b/skins/larry/templates/importcontacts.html index a670d0354..2bc1d4a26 100644 --- a/skins/larry/templates/importcontacts.html +++ b/skins/larry/templates/importcontacts.html @@ -15,7 +15,7 @@
-

+

diff --git a/skins/larry/templates/responses.html b/skins/larry/templates/responses.html index 8e6884539..503ed2177 100644 --- a/skins/larry/templates/responses.html +++ b/skins/larry/templates/responses.html @@ -10,23 +10,25 @@
+

:

+ -
+
-

+

- +
- +
- +
diff --git a/skins/larry/templates/settings.html b/skins/larry/templates/settings.html index 08df7686e..406b9c9b3 100644 --- a/skins/larry/templates/settings.html +++ b/skins/larry/templates/settings.html @@ -10,19 +10,22 @@
+

:

+
-
+ -
+
- +
diff --git a/skins/larry/ui.js b/skins/larry/ui.js index ff0b2e41a..6385e73b1 100644 --- a/skins/larry/ui.js +++ b/skins/larry/ui.js @@ -273,7 +273,9 @@ function rcube_mail_ui() orientation:'v', relative:true, start:266, min:180, size:12 }).init(); } else if (rcmail.env.action == 'edit-prefs') { - $('') + $('') + .text(env.toggleoptions) + .attr('title', env.toggleoptions) .addClass('advanced-toggle') .appendTo('#preferences-details fieldset.advanced legend'); -- cgit v1.2.3 From 4a9a0e1f0fc1977e067806e49b7ce5fa8c47dab5 Mon Sep 17 00:00:00 2001 From: David Carter Date: Fri, 6 Jun 2014 11:29:40 +0100 Subject: The following: program/steps/mail/compose.inc :: rcmail_store_target_selection() program/steps/settings/edit_folder.inc :: rcmail_folder_form() both try to localise mailbox names. Push the logic down into the folder_selector() method which can use: $this->config->get('show_real_foldernames') to decide the correct default behaviour. Clients functions and methods can still override by adding 'realnames' named parameter to the folder_selector() call. The obvious example is the Settings -> Preferences -> Special Folders screen. --- program/include/rcmail.php | 3 ++- program/steps/settings/edit_folder.inc | 1 - 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'program/steps/settings') diff --git a/program/include/rcmail.php b/program/include/rcmail.php index 1a227927e..f4689215c 100644 --- a/program/include/rcmail.php +++ b/program/include/rcmail.php @@ -1325,7 +1325,8 @@ class rcmail extends rcube */ public function folder_selector($p = array()) { - $p += array('maxlength' => 100, 'realnames' => false, 'is_escaped' => true); + $realnames = $this->config->get('show_real_foldernames'); + $p += array('maxlength' => 100, 'realnames' => $realnames, 'is_escaped' => true); $a_mailboxes = array(); $storage = $this->get_storage(); diff --git a/program/steps/settings/edit_folder.inc b/program/steps/settings/edit_folder.inc index c61ac6da9..30a187fc4 100644 --- a/program/steps/settings/edit_folder.inc +++ b/program/steps/settings/edit_folder.inc @@ -135,7 +135,6 @@ function rcmail_folder_form($attrib) 'id' => '_parent', 'name' => '_parent', 'noselection' => '---', - 'realnames' => false, 'maxlength' => 150, 'unsubscribed' => true, 'skip_noinferiors' => true, -- cgit v1.2.3 From 1e22cb1e86d1e4c9e689d2e5bca7beccb380742a Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Sat, 14 Jun 2014 17:54:36 +0200 Subject: Unify some labels --- program/localization/en_US/labels.inc | 20 ++++++++++---------- program/steps/addressbook/edit.inc | 2 ++ program/steps/settings/edit_identity.inc | 2 +- program/steps/settings/edit_response.inc | 2 +- program/steps/settings/func.inc | 2 +- skins/classic/templates/addressbook.html | 2 +- skins/classic/templates/compose.html | 2 +- skins/larry/templates/addressbook.html | 4 ++-- skins/larry/templates/compose.html | 2 +- skins/larry/templates/contactedit.html | 5 +---- skins/larry/templates/identities.html | 2 +- skins/larry/templates/responses.html | 2 +- 12 files changed, 23 insertions(+), 24 deletions(-) (limited to 'program/steps/settings') diff --git a/program/localization/en_US/labels.inc b/program/localization/en_US/labels.inc index 21c774b97..ba8fe2e40 100644 --- a/program/localization/en_US/labels.inc +++ b/program/localization/en_US/labels.inc @@ -255,9 +255,10 @@ $labels['restoremessage'] = 'Restore message?'; $labels['responses'] = 'Responses'; $labels['insertresponse'] = 'Insert a response'; $labels['manageresponses'] = 'Manage responses'; -$labels['savenewresponse'] = 'Save new response'; -$labels['editresponses'] = 'Edit responses'; +$labels['newresponse'] = 'Create new response'; +$labels['addresponse'] = 'Add response'; $labels['editresponse'] = 'Edit response'; +$labels['editresponses'] = 'Edit responses'; $labels['responsename'] = 'Name'; $labels['responsetext'] = 'Response Text'; @@ -353,7 +354,7 @@ $labels['typeblog'] = 'Blog'; $labels['typeprofile'] = 'Profile'; $labels['addfield'] = 'Add field...'; -$labels['addcontact'] = 'Add new contact'; +$labels['addcontact'] = 'Add contact'; $labels['editcontact'] = 'Edit contact'; $labels['contacts'] = 'Contacts'; $labels['contactproperties'] = 'Contact properties'; @@ -370,7 +371,7 @@ $labels['addphoto'] = 'Add'; $labels['replacephoto'] = 'Replace'; $labels['uploadphoto'] = 'Upload photo'; -$labels['newcontact'] = 'Create new contact card'; +$labels['newcontact'] = 'Create new contact'; $labels['deletecontact'] = 'Delete selected contacts'; $labels['composeto'] = 'Compose mail to'; $labels['contactsfromto'] = 'Contacts $from to $to of $count'; @@ -379,7 +380,7 @@ $labels['export'] = 'Export'; $labels['exportall'] = 'Export all'; $labels['exportsel'] = 'Export selected'; $labels['exportvcards'] = 'Export contacts in vCard format'; -$labels['newcontactgroup'] = 'Create new contact group'; +$labels['newgroup'] = 'Create new group'; $labels['grouprename'] = 'Rename group'; $labels['groupdelete'] = 'Delete group'; $labels['groupremoveselected'] = 'Remove selected contacts from group'; @@ -417,11 +418,10 @@ $labels['userpreferences'] = 'User preferences'; $labels['editpreferences'] = 'Edit user preferences'; $labels['identities'] = 'Identities'; -$labels['manageidentities'] = 'Manage identities for this account'; -$labels['newidentity'] = 'New identity'; - -$labels['newitem'] = 'New item'; -$labels['edititem'] = 'Edit item'; +$labels['manageidentities'] = 'Manage identities'; +$labels['newidentity'] = 'Create new identity'; +$labels['addidentity'] = 'Add identity'; +$labels['editidentity'] = 'Edit identity'; $labels['preferhtml'] = 'Display HTML'; $labels['defaultcharset'] = 'Default Character Set'; diff --git a/program/steps/addressbook/edit.inc b/program/steps/addressbook/edit.inc index 0fc753056..27d26791b 100644 --- a/program/steps/addressbook/edit.inc +++ b/program/steps/addressbook/edit.inc @@ -69,6 +69,8 @@ $OUTPUT->add_handlers(array( 'filedroparea' => 'rcmail_photo_drop_area', )); +$OUTPUT->set_pagetitle($RCMAIL->gettext(($RCMAIL->action == 'add' ? 'addcontact' : 'editcontact'))); + if ($RCMAIL->action == 'add' && $OUTPUT->template_exists('contactadd')) { $OUTPUT->send('contactadd'); } diff --git a/program/steps/settings/edit_identity.inc b/program/steps/settings/edit_identity.inc index e43a7bb60..20f822027 100644 --- a/program/steps/settings/edit_identity.inc +++ b/program/steps/settings/edit_identity.inc @@ -54,7 +54,7 @@ $OUTPUT->add_handler('identityform', 'rcube_identity_form'); $OUTPUT->set_env('identities_level', IDENTITIES_LEVEL); $OUTPUT->add_label('deleteidentityconfirm'); -$OUTPUT->set_pagetitle($RCMAIL->gettext(($RCMAIL->action == 'add-identity' ? 'newidentity' : 'edititem'))); +$OUTPUT->set_pagetitle($RCMAIL->gettext(($RCMAIL->action == 'add-identity' ? 'addidentity' : 'editidentity'))); if ($RCMAIL->action == 'add-identity' && $OUTPUT->template_exists('identityadd')) { $OUTPUT->send('identityadd'); diff --git a/program/steps/settings/edit_response.inc b/program/steps/settings/edit_response.inc index 6d3c3dc41..10dec1096 100644 --- a/program/steps/settings/edit_response.inc +++ b/program/steps/settings/edit_response.inc @@ -72,7 +72,7 @@ if ($RCMAIL->action == 'save-response' && isset($_POST['_name']) && !$RESPONSE_R $OUTPUT->set_env('readonly', !empty($RESPONSE_RECORD['static'])); $OUTPUT->add_handler('responseform', 'rcube_response_form'); -$OUTPUT->set_pagetitle($RCMAIL->gettext($RCMAIL->action == 'add-response' ? 'savenewresponse' : 'editresponse')); +$OUTPUT->set_pagetitle($RCMAIL->gettext($RCMAIL->action == 'add-response' ? 'addresponse' : 'editresponse')); $OUTPUT->send('responseedit'); diff --git a/program/steps/settings/func.inc b/program/steps/settings/func.inc index 8f9cf090f..89103ee44 100644 --- a/program/steps/settings/func.inc +++ b/program/steps/settings/func.inc @@ -1332,7 +1332,7 @@ function rcmail_settings_tabs($attrib) array('command' => 'preferences', 'type' => 'link', 'label' => 'preferences', 'title' => 'editpreferences'), array('command' => 'folders', 'type' => 'link', 'label' => 'folders', 'title' => 'managefolders'), array('command' => 'identities', 'type' => 'link', 'label' => 'identities', 'title' => 'manageidentities'), - array('command' => 'responses', 'type' => 'link', 'label' => 'responses', 'title' => 'editresponses'), + array('command' => 'responses', 'type' => 'link', 'label' => 'responses', 'title' => 'manageresponses'), ); // get all identites from DB and define list of cols to be displayed diff --git a/skins/classic/templates/addressbook.html b/skins/classic/templates/addressbook.html index 98658f28b..53995860d 100644 --- a/skins/classic/templates/addressbook.html +++ b/skins/classic/templates/addressbook.html @@ -63,7 +63,7 @@
diff --git a/skins/classic/templates/compose.html b/skins/classic/templates/compose.html index 4705600c7..19b22bc69 100644 --- a/skins/classic/templates/compose.html +++ b/skins/classic/templates/compose.html @@ -202,7 +202,7 @@
  • -
  • +
  • diff --git a/skins/larry/templates/addressbook.html b/skins/larry/templates/addressbook.html index e1101e648..0ce036850 100644 --- a/skins/larry/templates/addressbook.html +++ b/skins/larry/templates/addressbook.html @@ -67,7 +67,7 @@
    @@ -99,7 +99,7 @@
    - + diff --git a/skins/larry/templates/compose.html b/skins/larry/templates/compose.html index 98ef2963c..83a47913e 100644 --- a/skins/larry/templates/compose.html +++ b/skins/larry/templates/compose.html @@ -212,7 +212,7 @@ -
  • +
  • diff --git a/skins/larry/templates/contactedit.html b/skins/larry/templates/contactedit.html index b7aafed31..da7953eae 100644 --- a/skins/larry/templates/contactedit.html +++ b/skins/larry/templates/contactedit.html @@ -6,10 +6,7 @@ -

    - - -

    +

    diff --git a/skins/larry/templates/identities.html b/skins/larry/templates/identities.html index 91f7f8f71..5878155c6 100644 --- a/skins/larry/templates/identities.html +++ b/skins/larry/templates/identities.html @@ -22,7 +22,7 @@
    - +
    diff --git a/skins/larry/templates/responses.html b/skins/larry/templates/responses.html index 503ed2177..538a025f0 100644 --- a/skins/larry/templates/responses.html +++ b/skins/larry/templates/responses.html @@ -22,7 +22,7 @@
    - +
    -- cgit v1.2.3 From cd01dc027b8fb9cc4ce7237fbb8e7359c4a5d47e Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Sat, 21 Jun 2014 15:41:40 +0200 Subject: Add option to set default message list mode - default_list_mode (#1487312) --- CHANGELOG | 1 + config/defaults.inc.php | 9 ++++++--- program/steps/mail/func.inc | 7 +++++-- program/steps/settings/edit_folder.inc | 6 ++++-- program/steps/settings/folders.inc | 7 ++++--- program/steps/settings/save_folder.inc | 14 +++++--------- 6 files changed, 25 insertions(+), 19 deletions(-) (limited to 'program/steps/settings') diff --git a/CHANGELOG b/CHANGELOG index 0b15aaf47..43c2504bb 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,7 @@ CHANGELOG Roundcube Webmail =========================== +- Add option to set default message list mode - default_list_mode (#1487312) - Close "no subject" prompt with Enter key (#1489580) - Add config option to specify IMAP connection socket parameters - imap_conn_options (#1489948) - Password: Add option to force new users to change their password (#1486884) diff --git a/config/defaults.inc.php b/config/defaults.inc.php index c20a06bf7..71a2e4277 100644 --- a/config/defaults.inc.php +++ b/config/defaults.inc.php @@ -978,9 +978,12 @@ $config['check_all_folders'] = false; // If true, after message delete/move, the next message will be displayed $config['display_next'] = true; -// 0 - Do not expand threads -// 1 - Expand all threads automatically -// 2 - Expand only threads with unread messages +// Default messages listing mode. One of 'threads' or 'list'. +$config['default_list_mode'] = 'list'; + +// 0 - Do not expand threads +// 1 - Expand all threads automatically +// 2 - Expand only threads with unread messages $config['autoexpand_threads'] = 0; // When replying: diff --git a/program/steps/mail/func.inc b/program/steps/mail/func.inc index ac343ad5a..e8bf5e1fd 100644 --- a/program/steps/mail/func.inc +++ b/program/steps/mail/func.inc @@ -166,6 +166,7 @@ function rcmail_init_env() { global $RCMAIL; + $default_threading = $RCMAIL->config->get('default_list_mode', 'list') == 'threads'; $a_threading = $RCMAIL->config->get('message_threading', array()); $message_sort_col = $RCMAIL->config->get('message_sort_col'); $message_sort_order = $RCMAIL->config->get('message_sort_order'); @@ -205,13 +206,15 @@ function rcmail_init_env() $RCMAIL->storage->set_page($_SESSION['page'] = 1); } - unset($a_threading[$_SESSION['mbox']]); + $a_threading[$_SESSION['mbox']] = false; } $RCMAIL->user->save_prefs(array('message_threading' => $a_threading)); } - $RCMAIL->storage->set_threading($a_threading[$_SESSION['mbox']]); + $threading = isset($a_threading[$_SESSION['mbox']]) ? $a_threading[$_SESSION['mbox']] : $default_threading; + + $RCMAIL->storage->set_threading($threading); } /** diff --git a/program/steps/settings/edit_folder.inc b/program/steps/settings/edit_folder.inc index 30a187fc4..87a45fa8d 100644 --- a/program/steps/settings/edit_folder.inc +++ b/program/steps/settings/edit_folder.inc @@ -163,8 +163,10 @@ function rcmail_folder_form($attrib) $value = (int) $_POST['_viewmode']; } else if (strlen($mbox_imap)) { - $a_threaded = $RCMAIL->config->get('message_threading', array()); - $value = (int) isset($a_threaded[$mbox_imap]); + $a_threaded = $RCMAIL->config->get('message_threading', array()); + $default_mode = $RCMAIL->config->get('default_list_mode', 'list'); + + $value = (int) (isset($a_threaded[$mbox_imap]) ? $a_threaded[$mbox_imap] : $default_mode == 'threads'); } $form['props']['fieldsets']['settings']['content']['viewmode'] = array( diff --git a/program/steps/settings/folders.inc b/program/steps/settings/folders.inc index 1bcfb4cfc..8b74a59e1 100644 --- a/program/steps/settings/folders.inc +++ b/program/steps/settings/folders.inc @@ -406,16 +406,17 @@ function rcmail_rename_folder($oldname, $newname) $a_threaded = (array) $RCMAIL->config->get('message_threading', array()); $oldprefix = '/^' . preg_quote($oldname . $delimiter, '/') . '/'; - foreach (array_keys($a_threaded) as $key) { + foreach ($a_threaded as $key => $val) { if ($key == $oldname) { unset($a_threaded[$key]); - $a_threaded[$newname] = true; + $a_threaded[$newname] = $val; } else if (preg_match($oldprefix, $key)) { unset($a_threaded[$key]); - $a_threaded[preg_replace($oldprefix, $newname.$delimiter, $key)] = true; + $a_threaded[preg_replace($oldprefix, $newname.$delimiter, $key)] = $val; } } + $RCMAIL->user->save_prefs(array('message_threading' => $a_threaded)); // #1488692: update session diff --git a/program/steps/settings/save_folder.inc b/program/steps/settings/save_folder.inc index d1449bb38..a054224f1 100644 --- a/program/steps/settings/save_folder.inc +++ b/program/steps/settings/save_folder.inc @@ -115,15 +115,13 @@ if (!$error && !strlen($old)) { if (isset($_POST['_viewmode'])) { $a_threaded = (array) $RCMAIL->config->get('message_threading', array()); - if ($_POST['_viewmode']) - $a_threaded[$folder['name']] = true; - else - unset($a_threaded[$folder['name']]); + $a_threaded[$folder['name']] = (bool) $_POST['_viewmode']; $RCMAIL->user->save_prefs(array('message_threading' => $a_threaded)); } rcmail_update_folder_row($folder['name'], null, $folder['subscribe'], $folder['class']); + $OUTPUT->show_message('foldercreated', 'confirmation'); // reset folder preview frame $OUTPUT->command('subscription_select'); @@ -167,14 +165,12 @@ else if (!$error) { } else if (preg_match($oldprefix, $key)) { unset($a_threaded[$key]); - $a_threaded[preg_replace($oldprefix, $folder['name'].$delimiter, $key)] = true; + $a_threaded[preg_replace($oldprefix, $folder['name'].$delimiter, $key)] = $val; } } } - if ($_POST['_viewmode']) - $a_threaded[$folder['name']] = true; - else - unset($a_threaded[$folder['name']]); + + $a_threaded[$folder['name']] = (bool) $_POST['_viewmode']; $RCMAIL->user->save_prefs(array('message_threading' => $a_threaded)); } -- cgit v1.2.3 From 3cc1afa1c2f30bfebb30146795e50172947b4b5f Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Sun, 29 Jun 2014 16:35:18 +0200 Subject: Support images in HTML signatures (#1488676) This enables image button and file browser in html editor for signatures --- CHANGELOG | 1 + config/defaults.inc.php | 4 ++ program/include/rcmail.php | 79 +++++++++++++++++++++++++++++++- program/js/app.js | 15 +++--- program/js/editor.js | 16 +++++-- program/steps/mail/attachments.inc | 63 +------------------------ program/steps/settings/edit_identity.inc | 10 ++++ program/steps/settings/func.inc | 1 + program/steps/settings/save_identity.inc | 34 +++++++++++++- 9 files changed, 149 insertions(+), 74 deletions(-) (limited to 'program/steps/settings') diff --git a/CHANGELOG b/CHANGELOG index e4a02ad4f..b73ee3f19 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,7 @@ CHANGELOG Roundcube Webmail =========================== +- Support images in HTML signatures (#1488676) - Display full quota information in popup (#1485769, #1486604) - Mail compose: Selecting contact inserts recipient to previously focused input - to/cc/bcc accordingly (#1489684) - Add option to set default message list mode - default_list_mode (#1487312) diff --git a/config/defaults.inc.php b/config/defaults.inc.php index 71a2e4277..e7cb1e3aa 100644 --- a/config/defaults.inc.php +++ b/config/defaults.inc.php @@ -481,6 +481,10 @@ $config['mdn_use_from'] = false; // 4 - one identity with possibility to edit only signature $config['identities_level'] = 0; +// Maximum size of uploaded image in kilobytes +// Images (in html signatures) are stored in database as data URIs +$config['identity_image_size'] = 64; + // Mimetypes supported by the browser. // attachments of these types will open in a preview window // either a comma-separated list or an array: 'text/plain,text/html,text/xml,image/jpeg,image/gif,image/png,application/pdf' diff --git a/program/include/rcmail.php b/program/include/rcmail.php index 0151020c7..54d0d88e6 100644 --- a/program/include/rcmail.php +++ b/program/include/rcmail.php @@ -1944,8 +1944,10 @@ class rcmail extends rcube /** * Initializes file uploading interface. + * + * @param $int Optional maximum file size in bytes */ - public function upload_init() + public function upload_init($max_size = null) { // Enable upload progress bar if ($seconds = $this->config->get('upload_progress')) { @@ -1973,6 +1975,10 @@ class rcmail extends rcube $max_filesize = $max_postsize; } + if ($max_size && $max_size < $max_filesize) { + $max_filesize = $max_size; + } + $this->output->set_env('max_filesize', $max_filesize); $max_filesize = $this->show_bytes($max_filesize); $this->output->set_env('filesizeerror', $this->gettext(array( @@ -1981,6 +1987,77 @@ class rcmail extends rcube return $max_filesize; } + /** + * Outputs uploaded file content (with image thumbnails support + * + * @param array $file Upload file data + */ + public function display_uploaded_file($file) + { + if (empty($file)) { + return; + } + + $file = $this->plugins->exec_hook('attachment_display', $file); + + if ($file['status']) { + if (empty($file['size'])) { + $file['size'] = $file['data'] ? strlen($file['data']) : @filesize($file['path']); + } + + // generate image thumbnail for file browser in HTML editor + if (!empty($_GET['_thumbnail'])) { + $temp_dir = $this->config->get('temp_dir'); + $thumbnail_size = 80; + list(,$ext) = explode('/', $file['mimetype']); + $mimetype = $file['mimetype']; + $file_ident = $file['id'] . ':' . $file['mimetype'] . ':' . $file['size']; + $cache_basename = $temp_dir . '/' . md5($file_ident . ':' . $this->user->ID . ':' . $thumbnail_size); + $cache_file = $cache_basename . '.' . $ext; + + // render thumbnail image if not done yet + if (!is_file($cache_file)) { + if (!$file['path']) { + $orig_name = $filename = $cache_basename . '.orig.' . $ext; + file_put_contents($orig_name, $file['data']); + } + else { + $filename = $file['path']; + } + + $image = new rcube_image($filename); + if ($imgtype = $image->resize($thumbnail_size, $cache_file, true)) { + $mimetype = 'image/' . $imgtype; + + if ($orig_name) { + unlink($orig_name); + } + } + } + + if (is_file($cache_file)) { + // cache for 1h + $this->output->future_expire_header(3600); + header('Content-Type: ' . $mimetype); + header('Content-Length: ' . filesize($cache_file)); + + readfile($cache_file); + exit; + } + } + + header('Content-Type: ' . $file['mimetype']); + header('Content-Length: ' . $file['size']); + + if ($file['data']) { + echo $file['data']; + } + else if ($file['path']) { + readfile($file['path']); + } + } + } + /** * Initializes client-side autocompletion. */ diff --git a/program/js/app.js b/program/js/app.js index 8f2065635..3b5ff0422 100644 --- a/program/js/app.js +++ b/program/js/app.js @@ -4083,6 +4083,14 @@ function rcube_webmail() if (upload_id) this.triggerEvent('fileuploaded', {name: name, attachment: att, id: upload_id}); + if (!this.env.attachments) + this.env.attachments = {}; + + if (upload_id && this.env.attachments[upload_id]) + delete this.env.attachments[upload_id]; + + this.env.attachments[name] = att; + if (!this.gui_objects.attachmentlist) return false; @@ -4112,11 +4120,6 @@ function rcube_webmail() var tabindex = $(this.gui_objects.attachmentlist).attr('data-tabindex') || '0'; li.find('a').attr('tabindex', tabindex); - if (upload_id && this.env.attachments[upload_id]) - delete this.env.attachments[upload_id]; - - this.env.attachments[name] = att; - return true; }; @@ -7563,7 +7566,7 @@ function rcube_webmail() $(form).attr({ target: frame_name, - action: this.url(action, { _id:this.env.compose_id||'', _uploadid:ts }), + action: this.url(action, {_id: this.env.compose_id || '', _uploadid: ts, _from: this.env.action}), method: 'POST'}) .attr(form.encoding ? 'encoding' : 'enctype', 'multipart/form-data') .submit(); diff --git a/program/js/editor.js b/program/js/editor.js index dfd3e27ea..0dd8fef9a 100644 --- a/program/js/editor.js +++ b/program/js/editor.js @@ -65,10 +65,12 @@ function rcube_text_editor(config, id) // minimal editor if (config.mode == 'identity') { $.extend(conf, { - plugins: 'autolink charmap code colorpicker hr link paste tabfocus textcolor', + plugins: 'autolink charmap code colorpicker hr image link paste tabfocus textcolor', toolbar: 'bold italic underline alignleft aligncenter alignright alignjustify' - + ' | outdent indent charmap hr link unlink code forecolor' - + ' | fontselect fontsizeselect' + + ' | outdent indent charmap hr link unlink image code forecolor' + + ' | fontselect fontsizeselect', + file_browser_callback: function(name, url, type, win) { ref.file_browser_callback(name, url, type); }, + file_browser_callback_types: 'image' }); } // full-featured editor @@ -610,6 +612,8 @@ function rcube_text_editor(config, id) } }); } + + // @todo: upload progress indicator }; // close file browser window @@ -652,7 +656,9 @@ function rcube_text_editor(config, id) } if (rx.test(file.mimetype)) { - var href = rcmail.env.comm_path+'&_id='+rcmail.env.compose_id+'&_action=display-attachment&_file='+file_id, + var path = rcmail.env.comm_path + '&_from=' + rcmail.env.action, + action = rcmail.env.compose_id ? '&_id=' + rcmail.env.compose_id + '&_action=display-attachment' : '&_action=upload-display', + href = path + action + '&_file=' + file_id, img = $('').attr({title: file.name, src: img_src ? img_src : href + '&_thumbnail=1'}); return $('
  • ').attr({tabindex: 0}) @@ -686,7 +692,7 @@ function rcube_text_editor(config, id) this.hack_file_input = function(elem, clone_form) { var link = $(elem), - file = $(''), + file = $('').attr('name', '_files[]'), form = $('
    ').attr({method: 'post', enctype: 'multipart/form-data'}), offset = link.offset(); diff --git a/program/steps/mail/attachments.inc b/program/steps/mail/attachments.inc index fd122c5c1..5eaa655e3 100644 --- a/program/steps/mail/attachments.inc +++ b/program/steps/mail/attachments.inc @@ -38,7 +38,7 @@ if (!$COMPOSE) { // remove an attachment -if ($RCMAIL->action=='remove-attachment') { +if ($RCMAIL->action == 'remove-attachment') { $id = 'undefined'; if (preg_match('/^rcmfile(\w+)$/', $_POST['_file'], $regs)) { @@ -67,66 +67,7 @@ if ($RCMAIL->action == 'display-attachment') { $id = $regs[1]; } - if ($attachment = $COMPOSE['attachments'][$id]) { - $attachment = $RCMAIL->plugins->exec_hook('attachment_display', $attachment); - } - - if ($attachment['status']) { - if (empty($attachment['size'])) { - $attachment['size'] = $attachment['data'] ? strlen($attachment['data']) : @filesize($attachment['path']); - } - - // generate image thumbnail for file browser in HTML editor - if (!empty($_GET['_thumbnail'])) { - $temp_dir = $RCMAIL->config->get('temp_dir'); - $thumbnail_size = 80; - list(,$ext) = explode('/', $attachment['mimetype']); - $mimetype = $attachment['mimetype']; - $file_ident = $attachment['id'] . ':' . $attachment['mimetype'] . ':' . $attachment['size']; - $cache_basename = $temp_dir . '/' . md5($file_ident . ':' . $RCMAIL->user->ID . ':' . $thumbnail_size); - $cache_file = $cache_basename . '.' . $ext; - - // render thumbnail image if not done yet - if (!is_file($cache_file)) { - if (!$attachment['path']) { - $orig_name = $filename = $cache_basename . '.orig.' . $ext; - file_put_contents($orig_name, $attachment['data']); - } - else { - $filename = $attachment['path']; - } - - $image = new rcube_image($filename); - if ($imgtype = $image->resize($thumbnail_size, $cache_file, true)) { - $mimetype = 'image/' . $imgtype; - - if ($orig_name) { - unlink($orig_name); - } - } - } - - if (is_file($cache_file)) { - // cache for 1h - $RCMAIL->output->future_expire_header(3600); - header('Content-Type: ' . $mimetype); - header('Content-Length: ' . filesize($cache_file)); - - readfile($cache_file); - exit; - } - } - - header('Content-Type: ' . $attachment['mimetype']); - header('Content-Length: ' . $attachment['size']); - - if ($attachment['data']) { - echo $attachment['data']; - } - else if ($attachment['path']) { - readfile($attachment['path']); - } - } + $RCMAIL->display_uploaded_file($COMPOSE['attachments'][$id]); exit; } diff --git a/program/steps/settings/edit_identity.inc b/program/steps/settings/edit_identity.inc index 20f822027..34fe9798f 100644 --- a/program/steps/settings/edit_identity.inc +++ b/program/steps/settings/edit_identity.inc @@ -176,5 +176,15 @@ function rcube_identity_form($attrib) $out .= $form_end; + // add image upload form + $max_filesize = $RCMAIL->upload_init($RCMAIL->config->get('identity_image_size', 64) * 1024); + $upload_form_id = 'identityImageUpload'; + + $out .= '' + . html::div('hint', $RCMAIL->gettext(array('name' => 'maxuploadsize', 'vars' => array('size' => $max_filesize)))) + . '
    '; + + $RCMAIL->output->add_gui_object('uploadform', $upload_form_id); + return $out; } diff --git a/program/steps/settings/func.inc b/program/steps/settings/func.inc index 89103ee44..7ccbfa4a5 100644 --- a/program/steps/settings/func.inc +++ b/program/steps/settings/func.inc @@ -44,6 +44,7 @@ $RCMAIL->register_action_map(array( 'add-response' => 'edit_response.inc', 'save-response' => 'edit_response.inc', 'delete-response' => 'responses.inc', + 'upload-display' => 'upload.inc', )); diff --git a/program/steps/settings/save_identity.inc b/program/steps/settings/save_identity.inc index 77245b988..de0c84c91 100644 --- a/program/steps/settings/save_identity.inc +++ b/program/steps/settings/save_identity.inc @@ -79,8 +79,11 @@ foreach ($email_checks as $email) { } } -// XSS protection in HTML signature (#1489251) if (!empty($save_data['signature']) && !empty($save_data['html_signature'])) { + // replace uploaded images with data URIs + $save_data['signature'] = rcmail_attach_images($save_data['signature']); + + // XSS protection in HTML signature (#1489251) $save_data['signature'] = rcmail_wash_html($save_data['signature']); // clear POST data of signature, we want to use safe content @@ -190,6 +193,35 @@ else { } +/** + * Attach uploaded images into signature as data URIs + */ +function rcmail_attach_images($html) +{ + global $RCMAIL; + + $offset = 0; + $regexp = '/\s(poster|src)\s*=\s*[\'"]*\S+upload-display\S+file=rcmfile([0-9]+)[\s\'"]*/'; + + while (preg_match($regexp, $html, $matches, 0, $offset)) { + $file_id = $matches[2]; + $data_uri = ' '; + + if ($file_id && ($file = $_SESSION['identity']['files'][$file_id])) { + $file = $RCMAIL->plugins->exec_hook('attachment_get', $file); + + $data_uri .= 'src="data:' . $file['mimetype'] . ';base64,'; + $data_uri .= base64_encode($file['data'] ? $file['data'] : file_get_contents($file['path'])); + $data_uri .= '" '; + } + + $html = str_replace($matches[0], $data_uri, $html); + $offset += strlen($data_uri) - strlen($matches[0]) + 1; + } + + return $html; +} + /** * Sanity checks/cleanups on HTML body of signature */ -- cgit v1.2.3 From b0f816fa4b7db7db2f853698e6668ffad16b0a9b Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Sun, 29 Jun 2014 17:59:03 +0200 Subject: Add forgotten file (for image uploads handling) --- program/steps/settings/upload.inc | 144 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 144 insertions(+) create mode 100644 program/steps/settings/upload.inc (limited to 'program/steps/settings') diff --git a/program/steps/settings/upload.inc b/program/steps/settings/upload.inc new file mode 100644 index 000000000..8d338ebb9 --- /dev/null +++ b/program/steps/settings/upload.inc @@ -0,0 +1,144 @@ + | + +-----------------------------------------------------------------------+ +*/ + +// Upload progress update +if (!empty($_GET['_progress'])) { + $RCMAIL->upload_progress(); +} + +$from = rcube_utils::get_input_value('_from', rcube_utils::INPUT_GET); +$type = str_replace('edit-', '', $from); + +if ($RCMAIL->action == 'upload-display') { + $id = 'undefined'; + + if (preg_match('/^rcmfile(\w+)$/', $_GET['_file'], $regs)) { + $id = $regs[1]; + } + + $RCMAIL->display_uploaded_file($_SESSION[$type]['files'][$id]); + + exit; +} + + +// Supported image format types +$IMAGE_TYPES = explode(',', 'jpeg,jpg,jp2,tiff,tif,bmp,eps,gif,png,png8,png24,png32,svg,ico'); + +// clear all stored output properties (like scripts and env vars) +$OUTPUT->reset(); + +$max_size = $RCMAIL->config->get($type . '_image_size', 64) * 1024; +$post_size = $RCMAIL->show_bytes(parse_bytes(ini_get('upload_max_filesize'))); +$uploadid = rcube_utils::get_input_value('_uploadid', rcube_utils::INPUT_GET); + + +if (is_array($_FILES['_files']['tmp_name'])) { + $multiple = count($_FILES['_files']['tmp_name']) > 1; + + foreach ($_FILES['_files']['tmp_name'] as $i => $filepath) { + // Process uploaded attachment if there is no error + $err = $_FILES['_files']['error'][$i]; + + if (!$err) { + if ($max_size < $_FILES['_files']['size'][$i]) { + $err = 'size_error'; + } + // check image file type + else { + $image = new rcube_image($filepath); + $imageprop = $image->props(); + + if (!in_array(strtolower($imageprop['type']), $IMAGE_TYPES)) { + $err = 'type_error'; + } + } + } + + // save uploaded image in storage backend + if (!$err) { + $attachment = $RCMAIL->plugins->exec_hook('attachment_upload', array( + 'path' => $filepath, + 'size' => $_FILES['_files']['size'][$i], + 'name' => $_FILES['_files']['name'][$i], + 'mimetype' => 'image/' . $imageprop['type'], + 'group' => $type, + )); + } + + if (!$err && $attachment['status'] && !$attachment['abort']) { + $id = $attachment['id']; + + // store new file in session + unset($attachment['status'], $attachment['abort']); + $RCMAIL->session->append($type . '.files', $id, $attachment); + + $content = rcube::Q($attachment['name']); + + $OUTPUT->command('add2attachment_list', "rcmfile$id", array( + 'html' => $content, + 'name' => $attachment['name'], + 'mimetype' => $attachment['mimetype'], + 'classname' => rcube_utils::file2class($attachment['mimetype'], $attachment['name']), + 'complete' => true + ), + $uploadid + ); + } + else { + if ($err == 'type_error') { + $msg = $RCMAIL->gettext('invalidimageformat'); + } + else if ($err == 'size_error') { + $msg = $RCMAIL->gettext(array('name' => 'filesizeerror', 'vars' => array('size' => $max_size))); + } + else if ($err == UPLOAD_ERR_INI_SIZE || $err == UPLOAD_ERR_FORM_SIZE) { + $msg = $RCMAIL->gettext(array('name' => 'filesizeerror', 'vars' => array('size' => $post_size))); + } + else if ($attachment['error']) { + $msg = $attachment['error']; + } + else { + $msg = $RCMAIL->gettext('fileuploaderror'); + } + + $OUTPUT->command('display_message', $msg, 'error'); + } + } +} +else if ($_SERVER['REQUEST_METHOD'] == 'POST') { + // if filesize exceeds post_max_size then $_FILES array is empty, + // show filesizeerror instead of fileuploaderror + if ($maxsize = ini_get('post_max_size')) { + $msg = $RCMAIL->gettext(array( + 'name' => 'filesizeerror', + 'vars' => array('size' => $RCMAIL->show_bytes(parse_bytes($maxsize))) + )); + } + else { + $msg = $RCMAIL->gettext('fileuploaderror'); + } + + $OUTPUT->command('display_message', $msg, 'error'); + $OUTPUT->command('remove_from_attachment_list', $uploadid); +} + +$OUTPUT->send('iframe'); -- cgit v1.2.3 From b8bcca7033b3d10eb7da4b7a1f9987ee9e25a45b Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Mon, 30 Jun 2014 12:26:15 +0200 Subject: Display quota information for current folder not INBOX only (#1487993) --- CHANGELOG | 1 + program/include/rcmail.php | 30 ++++++++++++++++++++++-------- program/steps/mail/check_recent.inc | 5 +++-- program/steps/mail/copy.inc | 16 ++++++++++------ program/steps/mail/folders.inc | 4 ++-- program/steps/mail/list.inc | 9 ++++++++- program/steps/mail/move_del.inc | 15 +++++++++------ program/steps/mail/search.inc | 16 ++++++++++++---- program/steps/settings/edit_folder.inc | 4 ++++ program/steps/settings/folders.inc | 4 ++-- 10 files changed, 73 insertions(+), 31 deletions(-) (limited to 'program/steps/settings') diff --git a/CHANGELOG b/CHANGELOG index b73ee3f19..4730642ef 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,7 @@ CHANGELOG Roundcube Webmail =========================== +- Display quota information for current folder not INBOX only (#1487993) - Support images in HTML signatures (#1488676) - Display full quota information in popup (#1485769, #1486604) - Mail compose: Selecting contact inserts recipient to previously focused input - to/cc/bcc accordingly (#1489684) diff --git a/program/include/rcmail.php b/program/include/rcmail.php index 54d0d88e6..b105eb892 100644 --- a/program/include/rcmail.php +++ b/program/include/rcmail.php @@ -1678,9 +1678,9 @@ class rcmail extends rcube } - public function quota_content($attrib = null) + public function quota_content($attrib = null, $folder = null) { - $quota = $this->storage->get_quota(); + $quota = $this->storage->get_quota($folder); $quota = $this->plugins->exec_hook('quota', $quota); $quota_result = (array) $quota; @@ -1748,6 +1748,10 @@ class rcmail extends rcube unset($quota_result['all']); } + if ($folder !== null && $folder !== '') { + $quota_result['folder'] = $folder; + } + return $quota_result; } @@ -2170,11 +2174,13 @@ class rcmail extends rcube /** * Returns message UID(s) and IMAP folder(s) from GET/POST data * - * @param string UID value to decode - * @param string Default mailbox value (if not encoded in UIDs) + * @param string UID value to decode + * @param string Default mailbox value (if not encoded in UIDs) + * @param bool Will be set to True if multi-folder request + * * @return array List of message UIDs per folder */ - public static function get_uids($uids = null, $mbox = null) + public static function get_uids($uids = null, $mbox = null, &$is_multifolder = false) { // message UID (or comma-separated list of IDs) is provided in // the form of -[,-]* @@ -2191,6 +2197,7 @@ class rcmail extends rcube // special case: * if ($_uid == '*' && is_object($_SESSION['search'][1]) && $_SESSION['search'][1]->multi) { + $is_multifolder = true; // extract the full list of UIDs per folder from the search set foreach ($_SESSION['search'][1]->sets as $subset) { $mbox = $subset->get_parameters('MAILBOX'); @@ -2204,12 +2211,19 @@ class rcmail extends rcube // create a per-folder UIDs array foreach ((array)$_uid as $uid) { list($uid, $mbox) = explode('-', $uid, 2); - if (!strlen($mbox)) + if (!strlen($mbox)) { $mbox = $_mbox; - if ($uid == '*') + } + else { + $is_multifolder = true; + } + + if ($uid == '*') { $result[$mbox] = $uid; - else + } + else { $result[$mbox][] = $uid; + } } } diff --git a/program/steps/mail/check_recent.inc b/program/steps/mail/check_recent.inc index 70f4c03a6..b95819415 100644 --- a/program/steps/mail/check_recent.inc +++ b/program/steps/mail/check_recent.inc @@ -77,12 +77,13 @@ foreach ($a_mailboxes as $mbox_name) { if ($search_request && isset($_SESSION['search'])) { unset($search_request); // only do this once $_SESSION['search'] = $RCMAIL->storage->refresh_search(); - if ($_SESSION['search'][1]->multi) + if ($_SESSION['search'][1]->multi) { $mbox_name = ''; + } } if (!empty($_POST['_quota'])) { - $OUTPUT->command('set_quota', $RCMAIL->quota_content()); + $OUTPUT->command('set_quota', $RCMAIL->quota_content(null, $mbox_name)); } $OUTPUT->set_env('exists', $RCMAIL->storage->count($mbox_name, 'EXISTS', true)); diff --git a/program/steps/mail/copy.inc b/program/steps/mail/copy.inc index 86586d34d..585310d47 100644 --- a/program/steps/mail/copy.inc +++ b/program/steps/mail/copy.inc @@ -24,15 +24,19 @@ if (!$OUTPUT->ajax_call) { return; } -// move messages +// copy messages if (!empty($_POST['_uid']) && strlen($_POST['_target_mbox'])) { - $target = rcube_utils::get_input_value('_target_mbox', rcube_utils::INPUT_POST, true); + $target = rcube_utils::get_input_value('_target_mbox', rcube_utils::INPUT_POST, true); + $sources = array(); - foreach (rcmail::get_uids() as $mbox => $uids) { - if ($mbox === $target) + foreach (rcmail::get_uids(null, null, $multifolder) as $mbox => $uids) { + if ($mbox === $target) { $copied++; - else + } + else { $copied += (int)$RCMAIL->storage->copy_message($uids, $target, $mbox); + $sources[] = $mbox; + } } if (!$copied) { @@ -47,7 +51,7 @@ if (!empty($_POST['_uid']) && strlen($_POST['_target_mbox'])) { rcmail_send_unread_count($target, true); - $OUTPUT->command('set_quota', $RCMAIL->quota_content()); + $OUTPUT->command('set_quota', $RCMAIL->quota_content(null, $multifolder ? $sources[0] : 'INBOX')); } // unknown action or missing query param else { diff --git a/program/steps/mail/folders.inc b/program/steps/mail/folders.inc index 519a41fdd..49bf25377 100644 --- a/program/steps/mail/folders.inc +++ b/program/steps/mail/folders.inc @@ -35,7 +35,7 @@ if ($RCMAIL->action == 'expunge') { $OUTPUT->show_message('folderexpunged', 'confirmation'); if (!empty($_REQUEST['_reload'])) { - $OUTPUT->command('set_quota', $RCMAIL->quota_content()); + $OUTPUT->command('set_quota', $RCMAIL->quota_content(null, $mbox)); $OUTPUT->command('message_list.clear'); $RCMAIL->action = 'list'; return; @@ -69,7 +69,7 @@ else if ($RCMAIL->action == 'purge') { $OUTPUT->command('message_list.clear'); $OUTPUT->command('set_rowcount', rcmail_get_messagecount_text(), $mbox); $OUTPUT->command('set_unread_count', $mbox, 0); - $OUTPUT->command('set_quota', $RCMAIL->quota_content()); + $OUTPUT->command('set_quota', $RCMAIL->quota_content(null, $mbox)); rcmail_set_unseen_count($mbox, 0); // set trash folder state diff --git a/program/steps/mail/list.inc b/program/steps/mail/list.inc index 496c95146..2dcc40d17 100644 --- a/program/steps/mail/list.inc +++ b/program/steps/mail/list.inc @@ -68,6 +68,8 @@ if ($_SESSION['search_filter'] && $_SESSION['search_filter'] != 'ALL') { $OUTPUT->set_env('search_request', $search_request); $OUTPUT->set_env('search_filter', $_SESSION['search_filter']); + + $multifolder = is_a($_SESSION['search'][1], 'rcube_result_multifolder'); } // fetch message headers @@ -96,12 +98,13 @@ rcmail_send_unread_count($mbox_name, !empty($_REQUEST['_refresh']), $unseen); // update message count display $pages = ceil($count/$RCMAIL->storage->get_pagesize()); +$page = $count ? $RCMAIL->storage->get_page() : 1; $exists = $RCMAIL->storage->count($mbox_name, 'EXISTS', true); $OUTPUT->set_env('messagecount', $count); $OUTPUT->set_env('pagecount', $pages); $OUTPUT->set_env('threading', $threading); -$OUTPUT->set_env('current_page', $count ? $RCMAIL->storage->get_page() : 1); +$OUTPUT->set_env('current_page', $page); $OUTPUT->set_env('exists', $exists); $OUTPUT->command('set_rowcount', rcmail_get_messagecount_text($count), $mbox_name); @@ -143,5 +146,9 @@ if ($mbox_name === $RCMAIL->config->get('trash_mbox')) { $OUTPUT->command('set_trash_count', $exists); } +if ($page == 1) { + $OUTPUT->command('set_quota', $RCMAIL->quota_content(null, $multifolder ? 'INBOX' : $mbox_name)); +} + // send response $OUTPUT->send(); diff --git a/program/steps/mail/move_del.inc b/program/steps/mail/move_del.inc index d98d49d1f..81d476b2e 100644 --- a/program/steps/mail/move_del.inc +++ b/program/steps/mail/move_del.inc @@ -27,6 +27,7 @@ if (!$OUTPUT->ajax_call) $threading = (bool) $RCMAIL->storage->get_threading(); $old_count = $RCMAIL->storage->count(NULL, $threading ? 'THREADS' : 'ALL'); $old_pages = ceil($old_count / $RCMAIL->storage->get_pagesize()); +$sources = array(); $trash = $RCMAIL->config->get('trash_mbox'); @@ -36,12 +37,13 @@ if ($RCMAIL->action == 'move' && !empty($_POST['_uid']) && strlen($_POST['_targe $trash = $RCMAIL->config->get('trash_mbox'); $success = true; - foreach (rcmail::get_uids() as $mbox => $uids) { + foreach (rcmail::get_uids(null, null, multifolder) as $mbox => $uids) { if ($mbox === $target) { $count += count($uids); } else if ($RCMAIL->storage->move_message($uids, $target, $mbox)) { $count += count($uids); + $sources[] = $mbox; } else { $success = false; @@ -69,10 +71,11 @@ if ($RCMAIL->action == 'move' && !empty($_POST['_uid']) && strlen($_POST['_targe } } // delete messages -else if ($RCMAIL->action=='delete' && !empty($_POST['_uid'])) { - foreach (rcmail::get_uids() as $mbox => $uids) { - $del += (int)$RCMAIL->storage->delete_message($uids, $mbox); - $count += count($uids); +else if ($RCMAIL->action == 'delete' && !empty($_POST['_uid'])) { + foreach (rcmail::get_uids(null, null, $multifolder) as $mbox => $uids) { + $del += (int)$RCMAIL->storage->delete_message($uids, $mbox); + $count += count($uids); + $sources[] = $mbox; } if (!$del) { @@ -146,7 +149,7 @@ else { rcmail_send_unread_count($target, true); } - $OUTPUT->command('set_quota', $RCMAIL->quota_content()); + $OUTPUT->command('set_quota', $RCMAIL->quota_content(null, $multifolder ? $sources[0] : 'INBOX')); $OUTPUT->command('set_rowcount', rcmail_get_messagecount_text($msg_count), $mbox); if ($threading) { diff --git a/program/steps/mail/search.inc b/program/steps/mail/search.inc index 4aa22e14b..b50593480 100644 --- a/program/steps/mail/search.inc +++ b/program/steps/mail/search.inc @@ -127,8 +127,9 @@ if ($search_str) { } else if ($scope == 'sub') { $mboxes = $RCMAIL->storage->list_folders_subscribed($mbox, '*', 'mail'); - if ($mbox != 'INBOX' && $mboxes[0] == 'INBOX') + if ($mbox != 'INBOX' && $mboxes[0] == 'INBOX') { array_shift($mboxes); + } } $result = $RCMAIL->storage->search($mboxes, $search_str, $imap_charset, $sort_column); @@ -144,7 +145,7 @@ if ($search_str) { $_SESSION['last_text_search'] = $str; } $_SESSION['search_request'] = $search_request; -$_SESSION['search_scope'] = $scope; +$_SESSION['search_scope'] = $scope; // Get the headers @@ -181,10 +182,13 @@ else if ($result->incomplete) { else { $OUTPUT->show_message('searchnomatch', 'notice'); $OUTPUT->set_env('multifolder_listing', (bool)$result->multi); - if ($result->multi && $scope == 'all') + if ($result->multi && $scope == 'all') { $OUTPUT->command('select_folder', ''); + } } +$OUTPUT->set_pagetitle($RCMAIL->gettext(array('name' => 'searchfor', 'vars' => array('q' => $str)))); + // update message count display $OUTPUT->set_env('search_request', $search_str ? $search_request : ''); $OUTPUT->set_env('search_filter', $_SESSION['search_filter']); @@ -193,5 +197,9 @@ $OUTPUT->set_env('messagecount', $count); $OUTPUT->set_env('pagecount', ceil($count/$RCMAIL->storage->get_pagesize())); $OUTPUT->set_env('exists', $mbox === null ? 0 : $RCMAIL->storage->count($mbox, 'EXISTS')); $OUTPUT->command('set_rowcount', rcmail_get_messagecount_text($count, 1), $mbox); -$OUTPUT->set_pagetitle($RCMAIL->gettext(array('name' => 'searchfor', 'vars' => array('q' => $str)))); + +if (!$result->incomplete) { + $OUTPUT->command('set_quota', $RCMAIL->quota_content(null, $result->multi ? 'INBOX' : $mbox)); +} + $OUTPUT->send(); diff --git a/program/steps/settings/edit_folder.inc b/program/steps/settings/edit_folder.inc index 87a45fa8d..51f4d8d72 100644 --- a/program/steps/settings/edit_folder.inc +++ b/program/steps/settings/edit_folder.inc @@ -290,6 +290,10 @@ function rcmail_folder_form($attrib) $RCMAIL->output->set_env('messagecount', (int) $msgcount); + if ($mbox_imap !== null && empty($_POST)) { + $RCMAIL->output->command('parent.set_quota', $RCMAIL->quota_content(null, $mbox_imap)); + } + return $out; } diff --git a/program/steps/settings/folders.inc b/program/steps/settings/folders.inc index 8b74a59e1..33b2b0624 100644 --- a/program/steps/settings/folders.inc +++ b/program/steps/settings/folders.inc @@ -134,7 +134,7 @@ else if ($RCMAIL->action == 'purge') { $success = $STORAGE->delete_message('*', $mbox); $delete = true; } - // copy to Trash + // move to Trash else { $success = $STORAGE->move_message('1:*', $trash_mbox, $mbox); $delete = false; @@ -144,7 +144,7 @@ else if ($RCMAIL->action == 'purge') { $OUTPUT->set_env('messagecount', 0); if ($delete) { $OUTPUT->show_message('folderpurged', 'confirmation'); - $OUTPUT->command('set_quota', $RCMAIL->quota_content()); + $OUTPUT->command('set_quota', $RCMAIL->quota_content(null, $mbox)); } else { $OUTPUT->show_message('messagemoved', 'confirmation'); -- cgit v1.2.3 From 9fa8368b01b9cee5fcc97d9c267e2308296501e2 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Mon, 30 Jun 2014 13:56:06 +0200 Subject: Support images drag-n-drop into image browser dialog in html signature editor --- program/js/app.js | 2 +- program/js/editor.js | 16 +++++++++++++--- program/steps/settings/edit_identity.inc | 2 +- program/steps/settings/upload.inc | 14 +++++++------- 4 files changed, 22 insertions(+), 12 deletions(-) (limited to 'program/steps/settings') diff --git a/program/js/app.js b/program/js/app.js index 3b5ff0422..db9a2ff5f 100644 --- a/program/js/app.js +++ b/program/js/app.js @@ -7629,7 +7629,7 @@ function rcube_webmail() $.ajax({ type: 'POST', dataType: 'json', - url: ref.url(ref.env.filedrop.action||'upload', { _id:ref.env.compose_id||ref.env.cid||'', _uploadid:ts, _remote:1 }), + url: ref.url(ref.env.filedrop.action || 'upload', {_id: ref.env.compose_id||ref.env.cid||'', _uploadid: ts, _remote: 1, _from: ref.env.action}), contentType: formdata ? false : 'multipart/form-data; boundary=' + boundary, processData: false, timeout: 0, // disable default timeout set in ajaxSetup() diff --git a/program/js/editor.js b/program/js/editor.js index 0dd8fef9a..3b49968a7 100644 --- a/program/js/editor.js +++ b/program/js/editor.js @@ -589,8 +589,14 @@ function rcube_text_editor(config, id) this.hack_file_input(elem, rcmail.gui_objects.uploadform); // enable drag-n-drop area - if (rcmail.gui_objects.filedrop && rcmail.env.filedrop && ((window.XMLHttpRequest && XMLHttpRequest.prototype && XMLHttpRequest.prototype.sendAsBinary) || window.FormData)) { - rcmail.env.old_file_drop = rcmail.gui_objects.filedrop; + if ((window.XMLHttpRequest && XMLHttpRequest.prototype && XMLHttpRequest.prototype.sendAsBinary) || window.FormData) { + if (!rcmail.env.filedrop) { + rcmail.env.filedrop = {}; + } + if (rcmail.gui_objects.filedrop) { + rcmail.env.old_file_drop = rcmail.gui_objects.filedrop; + } + rcmail.gui_objects.filedrop = $('#image-selector-form'); rcmail.gui_objects.filedrop.addClass('droptarget') .bind('dragover dragleave', function(e) { @@ -639,6 +645,10 @@ function rcube_text_editor(config, id) return; } + if (rcmail.file_upload_id) { + rcmail.set_busy(false, null, rcmail.file_upload_id); + } + var rx, img_src; switch (rcmail.env.file_browser_type) { @@ -692,7 +702,7 @@ function rcube_text_editor(config, id) this.hack_file_input = function(elem, clone_form) { var link = $(elem), - file = $('').attr('name', '_files[]'), + file = $('').attr('name', '_file[]'), form = $('
    ').attr({method: 'post', enctype: 'multipart/form-data'}), offset = link.offset(); diff --git a/program/steps/settings/edit_identity.inc b/program/steps/settings/edit_identity.inc index 34fe9798f..cd7ba5fa6 100644 --- a/program/steps/settings/edit_identity.inc +++ b/program/steps/settings/edit_identity.inc @@ -52,7 +52,7 @@ else { $OUTPUT->include_script('list.js'); $OUTPUT->add_handler('identityform', 'rcube_identity_form'); $OUTPUT->set_env('identities_level', IDENTITIES_LEVEL); -$OUTPUT->add_label('deleteidentityconfirm'); +$OUTPUT->add_label('deleteidentityconfirm', 'uploading'); $OUTPUT->set_pagetitle($RCMAIL->gettext(($RCMAIL->action == 'add-identity' ? 'addidentity' : 'editidentity'))); diff --git a/program/steps/settings/upload.inc b/program/steps/settings/upload.inc index 8d338ebb9..41e19f8fa 100644 --- a/program/steps/settings/upload.inc +++ b/program/steps/settings/upload.inc @@ -51,15 +51,15 @@ $post_size = $RCMAIL->show_bytes(parse_bytes(ini_get('upload_max_filesize'))); $uploadid = rcube_utils::get_input_value('_uploadid', rcube_utils::INPUT_GET); -if (is_array($_FILES['_files']['tmp_name'])) { - $multiple = count($_FILES['_files']['tmp_name']) > 1; +if (is_array($_FILES['_file']['tmp_name'])) { + $multiple = count($_FILES['_file']['tmp_name']) > 1; - foreach ($_FILES['_files']['tmp_name'] as $i => $filepath) { + foreach ($_FILES['_file']['tmp_name'] as $i => $filepath) { // Process uploaded attachment if there is no error - $err = $_FILES['_files']['error'][$i]; + $err = $_FILES['_file']['error'][$i]; if (!$err) { - if ($max_size < $_FILES['_files']['size'][$i]) { + if ($max_size < $_FILES['_file']['size'][$i]) { $err = 'size_error'; } // check image file type @@ -77,8 +77,8 @@ if (is_array($_FILES['_files']['tmp_name'])) { if (!$err) { $attachment = $RCMAIL->plugins->exec_hook('attachment_upload', array( 'path' => $filepath, - 'size' => $_FILES['_files']['size'][$i], - 'name' => $_FILES['_files']['name'][$i], + 'size' => $_FILES['_file']['size'][$i], + 'name' => $_FILES['_file']['name'][$i], 'mimetype' => 'image/' . $imageprop['type'], 'group' => $type, )); -- cgit v1.2.3 From c6447e2ce289188493590ec0d5449fa3692eed08 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Wed, 2 Jul 2014 13:03:22 +0200 Subject: Use treelist widget for folders list in Settings/Folders (#1489648) --- .../subscriptions_option/subscriptions_option.php | 4 +- program/js/app.js | 129 ++++++++------------- program/js/treelist.js | 67 +++++++++-- program/steps/settings/folders.inc | 70 ++++++----- program/steps/settings/func.inc | 2 + skins/classic/common.css | 1 + skins/classic/functions.js | 6 +- skins/classic/mail.css | 8 -- skins/classic/settings.css | 55 ++++----- skins/classic/templates/folders.html | 4 +- skins/larry/settings.css | 23 ++-- skins/larry/templates/folders.html | 2 +- skins/larry/ui.js | 4 +- 13 files changed, 193 insertions(+), 182 deletions(-) (limited to 'program/steps/settings') diff --git a/plugins/subscriptions_option/subscriptions_option.php b/plugins/subscriptions_option/subscriptions_option.php index 130f16a8b..5b926f2af 100644 --- a/plugins/subscriptions_option/subscriptions_option.php +++ b/plugins/subscriptions_option/subscriptions_option.php @@ -86,7 +86,9 @@ class subscriptions_option extends rcube_plugin { $rcmail = rcmail::get_instance(); if (!$rcmail->config->get('use_subscriptions', true)) { - $args['table']->remove_column('subscribed'); + foreach ($args['list'] as $idx => $data) { + $args['list'][$idx]['content'] = preg_replace('/]+>/', '', $data['content']); + } } return $args; } diff --git a/program/js/app.js b/program/js/app.js index db9a2ff5f..2b9c3f0d7 100644 --- a/program/js/app.js +++ b/program/js/app.js @@ -1856,9 +1856,6 @@ function rcube_webmail() && !this.env.mailboxes[id].virtual && (this.env.mailboxes[id].id != this.env.mailbox || this.is_multifolder_listing())) ? 1 : 0; - case 'settings': - return id != this.env.mailbox ? 1 : 0; - case 'addressbook': var target; if (id != this.env.source && (target = this.env.contactfolders[id])) { @@ -5765,62 +5762,38 @@ function rcube_webmail() this.last_sub_rx = RegExp('['+delim+']?[^'+delim+']+$'); - this.subscription_list = new rcube_list_widget(this.gui_objects.subscriptionlist, - {multiselect:false, draggable:true, keyboard:true, toggleselect:true}); - this.subscription_list - .addEventListener('select', function(o){ ref.subscription_select(o); }) - .addEventListener('dragstart', function(o){ ref.drag_active = true; }) - .addEventListener('dragend', function(o){ ref.subscription_move_folder(o); }) - .addEventListener('initrow', function (row) { - row.obj.onmouseover = function() { ref.focus_subscription(row.id); }; - row.obj.onmouseout = function() { ref.unfocus_subscription(row.id); }; - }) - .init() - .focus(); - - $('#mailboxroot') - .mouseover(function(){ ref.focus_subscription(this.id); }) - .mouseout(function(){ ref.unfocus_subscription(this.id); }) - }; - - this.focus_subscription = function(id) - { - var row, folder; + this.subscription_list = new rcube_treelist_widget(this.gui_objects.subscriptionlist, { + selectable: true + }); - if (this.drag_active && this.env.mailbox && (row = document.getElementById(id))) - if (this.env.subscriptionrows[id] && - (folder = this.env.subscriptionrows[id][0]) !== null - ) { - if (this.check_droptarget(folder) && - !this.env.subscriptionrows[this.get_folder_row_id(this.env.mailbox)][2] && - folder != this.env.mailbox.replace(this.last_sub_rx, '') && - !folder.startsWith(this.env.mailbox + this.env.delimiter) - ) { - this.env.dstfolder = folder; - $(row).addClass('droptarget'); + this.subscription_list + .addEventListener('select', function(node) { ref.subscription_select(node.id); }) + .draggable({cancel: '#mailboxroot'}) + .droppable({ + // @todo: find better way, accept callback is executed for every folder + // on the list when dragging starts (and stops), this is slow, but + // I didn't find a method to check droptarget on over event + accept: function(node) { + var source = ref.env.subscriptionrows[$(node).attr('id')], + dest = ref.env.subscriptionrows[this.id], + source_name = source[0], + dest_name = dest[0]; + + return !source[2] + && dest_name != source_name.replace(ref.last_sub_rx, '') + && !dest_name.startsWith(source_name + ref.env.delimiter); + }, + drop: function(e, ui) { + ref.subscription_move_folder(ui.draggable.attr('id'), this.id); } - } - }; - - this.unfocus_subscription = function(id) - { - var row = $('#'+id); - - this.env.dstfolder = null; - - if (row.length && this.env.subscriptionrows[id]) - row.removeClass('droptarget'); - else - $(this.subscription_list.frame).removeClass('droptarget'); + }); }; - this.subscription_select = function(list) + this.subscription_select = function(id) { - var id, folder; + var folder; - if (list && (id = list.get_single_selection()) && - (folder = this.env.subscriptionrows['rcmrow'+id]) - ) { + if (id && id != 'mailboxroot' && (folder = this.env.subscriptionrows[id])) { this.env.mailbox = folder[0]; this.show_folder(folder[0]); this.enable_command('delete-folder', !folder[2]); @@ -5832,24 +5805,21 @@ function rcube_webmail() } }; - this.subscription_move_folder = function(list) + this.subscription_move_folder = function(from, to) { - if (this.env.mailbox && this.env.dstfolder !== null && - this.env.dstfolder != this.env.mailbox && - this.env.dstfolder != this.env.mailbox.replace(this.last_sub_rx, '') - ) { - var path = this.env.mailbox.split(this.env.delimiter), + var source = this.env.subscriptionrows[from][0]; + dest = this.env.subscriptionrows[to][0]; + + if (source && dest !== null && source != dest && dest != source.replace(this.last_sub_rx, '')) { + var path = source.split(this.env.delimiter), basename = path.pop(), - newname = this.env.dstfolder === '' ? basename : this.env.dstfolder + this.env.delimiter + basename; + newname = dest === '' ? basename : dest + this.env.delimiter + basename; - if (newname != this.env.mailbox) { - this.http_post('rename-folder', {_folder_oldname: this.env.mailbox, _folder_newname: newname}, this.set_busy(true, 'foldermoving')); - this.subscription_list.draglayer.hide(); + if (newname != source) { + this.http_post('rename-folder', {_folder_oldname: source, _folder_newname: newname}, + this.set_busy(true, 'foldermoving')); } } - - this.drag_active = false; - this.unfocus_subscription(this.get_folder_row_id(this.env.dstfolder)); }; // tell server to create and subscribe a new mailbox @@ -5865,8 +5835,7 @@ function rcube_webmail() folder = this.env.subscriptionrows[id][0]; if (folder && confirm(this.get_label('deletefolderconfirm'))) { - var lock = this.set_busy(true, 'folderdeleting'); - this.http_post('delete-folder', {_mbox: folder}, lock); + this.http_post('delete-folder', {_mbox: folder}, this.set_busy(true, 'folderdeleting')); } }; @@ -5878,9 +5847,9 @@ function rcube_webmail() var row, n, tmp, tmp_name, rowid, collator, folders = [], list = [], slist = [], - tbody = this.gui_objects.subscriptionlist.tBodies[0], - refrow = $('tr', tbody).get(1), - id = 'rcmrow'+((new Date).getTime()); + list_element = $(this.gui_objects.subscriptionlist), + refrow = $('li', list_element).get(1), + id = 'rcmli'+((new Date).getTime()); if (!refrow) { // Refresh page if we don't have a table row to clone @@ -5895,7 +5864,7 @@ function rcube_webmail() row.attr({id: id, 'class': class_name}); // set folder name - row.find('td:first').html(display_name); + $('.name', row).html(display_name); // update subscription checkbox $('input[name="_subscribed[]"]', row).val(name) @@ -5966,12 +5935,13 @@ function rcube_webmail() // add row to the table if (rowid) - $('#'+rowid).after(row); + $('#' + rowid).after(row); else - row.appendTo(tbody); + list_element.append(row); // update list widget - this.subscription_list.clear_selection(); + this.subscription_list.select(); + if (!skip_init) this.init_subscription_list(); @@ -5988,11 +5958,11 @@ function rcube_webmail() if (!this.gui_objects.subscriptionlist) { if (this.is_framed) return parent.rcmail.replace_folder_row(oldfolder, newfolder, display_name, is_protected, class_name); + return false; } var i, n, len, name, dispname, oldrow, tmprow, row, level, - tbody = this.gui_objects.subscriptionlist.tBodies[0], folders = this.env.subscriptionrows, id = this.get_folder_row_id(oldfolder), prefix_len = oldfolder.length, @@ -6003,7 +5973,6 @@ function rcube_webmail() // no renaming, only update class_name if (oldfolder == newfolder) { $('#'+id).attr('class', class_name || ''); - this.subscription_list.focus(); return; } @@ -6040,7 +6009,7 @@ function rcube_webmail() for (i=level; i<0; i++) dispname = '    ' + dispname; } - row.find('td:first').html(dispname); + $('.name', row).html(dispname); this.env.subscriptionrows[id][1] = dispname; } } @@ -6068,8 +6037,8 @@ function rcube_webmail() this._remove_folder_row = function(id) { - this.subscription_list.remove_row(id.replace(/^rcmrow/, '')); - $('#'+id).remove(); + this.subscription_list.remove(id.replace(/^rcmli/, '')); + $('#' + id).remove(); delete this.env.subscriptionrows[id]; }; diff --git a/program/js/treelist.js b/program/js/treelist.js index b2d838e13..1e6061770 100644 --- a/program/js/treelist.js +++ b/program/js/treelist.js @@ -46,7 +46,7 @@ function rcube_treelist_widget(node, p) scroll_speed: 20, save_state: false, keyboard: true, - check_droptarget: function(node){ return !node.virtual } + check_droptarget: function(node) { return !node.virtual; } }, p || {}); var container = $(node), @@ -67,6 +67,7 @@ function rcube_treelist_widget(node, p) searchfield, tree_state, ui_droppable, + ui_draggable, list_id = (container.attr('id') || p.id_prefix || '0'), me = this; @@ -83,6 +84,7 @@ function rcube_treelist_widget(node, p) this.drag_end = drag_end; this.intersects = intersects; this.droppable = droppable; + this.draggable = draggable; this.update = update_node; this.insert = insert; this.remove = remove; @@ -108,7 +110,11 @@ function rcube_treelist_widget(node, p) e.stopPropagation(); }); - container.on('click', 'li', function(e){ + container.on('click', 'li', function(e) { + // do not select record on checkbox/input click + if ($(e.target).is('input')) + return true; + var node = p.selectable ? indexbyid[dom2id($(this))] : null; if (node && !node.virtual) { select(node.id); @@ -232,6 +238,9 @@ function rcube_treelist_widget(node, p) selection = null; } + if (!id) + return; + var li = id2dom(id, true); if (li.length) { li.addClass('selected').attr('aria-selected', 'true'); @@ -708,6 +717,7 @@ function rcube_treelist_widget(node, p) { var domid = p.id_encode ? p.id_encode(id) : id, suffix = search_active && !real ? '--xsR' : ''; + return $('#' + p.id_prefix + domid + suffix, container); } @@ -850,6 +860,11 @@ function rcube_treelist_widget(node, p) */ function drag_start() { + if (drag_active) + return; + + drag_active = true; + var li, item, height, pos = container.offset(); @@ -857,7 +872,6 @@ function rcube_treelist_widget(node, p) list_scroll_top = container.parent().scrollTop(); pos.top += list_scroll_top; - drag_active = true; box_coords = { x1: pos.left, y1: pos.top, @@ -920,6 +934,9 @@ function rcube_treelist_widget(node, p) */ function drag_end() { + if (!drag_active) + return; + drag_active = false; scroll_timer = null; @@ -950,7 +967,7 @@ function rcube_treelist_widget(node, p) } /** - * Determine if the given mouse coords intersect the list and one if its items + * Determine if the given mouse coords intersect the list and one of its items */ function intersects(mouse, highlight) { @@ -970,8 +987,8 @@ function rcube_treelist_widget(node, p) } // check intersection with visible list items - var pos, node; - for (var id in item_coords) { + var id, pos, node; + for (id in item_coords) { pos = item_coords[id]; if (mouse.x >= pos.x1 && mouse.x < pos.x2 && mouse.top >= pos.y1 && mouse.top < pos.y2) { node = indexbyid[id]; @@ -1024,7 +1041,14 @@ function rcube_treelist_widget(node, p) */ function droppable(opts) { - var my_opts = $.extend({ greedy: true, hoverClass: 'droptarget', addClasses:false }, opts); + if (!opts) opts = {}; + + var my_opts = $.extend({ + greedy: true, + tolerance: 'pointer', + hoverClass: 'droptarget', + addClasses: false + }, opts); my_opts.activate = function(e, ui) { drag_start(); @@ -1046,7 +1070,34 @@ function rcube_treelist_widget(node, p) opts.over(e, ui); }; - $('li:not(.virtual)', container).droppable(my_opts); + $(selector ? selector : 'li:not(.virtual)', container).droppable(my_opts); + + return this; + } + + /** + * Wrapper for jQuery.UI.draggable() activation on this widget + * + * @param object Options as passed to regular .draggable() function + */ + function draggable(opts) + { + if (!opts) opts = {}; + + var my_opts = $.extend({ + appendTo: 'body', + iframeFix: true, + addClasses: false, + cursorAt: {left: -20, top: 5}, + helper: function(e) { + return $('
    ').attr('id', 'rcmdraglayer') + .text($.trim($(e.target).first().text())); + } + }, opts); + + $('li:not(.virtual)', container).draggable(my_opts); + + return this; } } diff --git a/program/steps/settings/folders.inc b/program/steps/settings/folders.inc index 33b2b0624..ad5f37d95 100644 --- a/program/steps/settings/folders.inc +++ b/program/steps/settings/folders.inc @@ -177,11 +177,9 @@ if ($OUTPUT->ajax_call) { } $OUTPUT->set_pagetitle($RCMAIL->gettext('folders')); -$OUTPUT->include_script('list.js'); $OUTPUT->set_env('prefix_ns', $STORAGE->get_namespace('prefix')); -if ($STORAGE->get_capability('QUOTA')) { - $OUTPUT->set_env('quota', true); -} +$OUTPUT->set_env('quota', (bool) $STORAGE->get_capability('QUOTA')); +$OUTPUT->include_script('treelist.js'); // add some labels to client $OUTPUT->add_label('deletefolderconfirm', 'purgefolderconfirm', 'folderdeleting', @@ -205,15 +203,8 @@ function rcube_subscription_form($attrib) list($form_start, $form_end) = get_form_tags($attrib, 'folders'); unset($attrib['form']); - if (!$attrib['id']) + if (!$attrib['id']) { $attrib['id'] = 'rcmSubscriptionlist'; - - $table = new html_table(); - - if ($attrib['noheader'] !== true && $attrib['noheader'] != "true") { - // add table header - $table->add_header('name', $RCMAIL->gettext('foldername')); - $table->add_header('subscribed', ''); } $STORAGE = $RCMAIL->get_storage(); @@ -227,7 +218,6 @@ function rcube_subscription_form($attrib) $namespace = $STORAGE->get_namespace(); $special_folders = array_flip(array_merge(array('inbox' => 'INBOX'), $STORAGE->get_special_folders())); $protect_default = $RCMAIL->config->get('protect_default_folders'); - $a_js_folders = array(); $seen = array(); $list_folders = array(); @@ -272,19 +262,15 @@ function rcube_subscription_form($attrib) unset($seen); - // add drop-target representing 'root' - $table->add_row(array('id' => 'mailboxroot', 'class' => 'virtual root')); - $table->add('name', ' '); - $table->add(null, ' '); - - $a_js_folders['mailboxroot'] = array('', '', true); - $checkbox_subscribe = new html_checkbox(array( 'name' => '_subscribed[]', 'title' => $RCMAIL->gettext('changesubscription'), 'onclick' => rcmail_output::JS_OBJECT_NAME.".command(this.checked?'subscribe':'unsubscribe',this.value)", )); + $js_folders = array(); + $folders = array(); + // create list of available folders foreach ($list_folders as $i => $folder) { $idx = $i + 1; @@ -292,7 +278,7 @@ function rcube_subscription_form($attrib) $subscribed = $sub_key !== false; $protected = $protect_default && isset($special_folders[$folder['id']]); $noselect = false; - $classes = array($i%2 ? 'even' : 'odd'); + $classes = array('listitem'); $folder_utf8 = rcube_charset::convert($folder['id'], 'UTF7-IMAP'); $display_folder = str_repeat('    ', $folder['level']) @@ -352,25 +338,45 @@ function rcube_subscription_form($attrib) } } - $table->add_row(array('id' => 'rcmrow'.$idx, 'class' => join(' ', $classes), - 'foldername' => $folder['id'])); + $row_id = 'rcmli' . $idx; + $folders[$row_id] = array( + 'folder' => $folder_utf8, + 'display' => $display_folder, + 'class' => join(' ', $classes), + 'folder_imap' => $folder['id'], + 'subscribed' => $subscribed, + 'protected' => $protected || $folder['virtual'], + 'content' => html::a(array('class' => 'name', 'href' => '#_' . $row_id), $display_folder) + . $checkbox_subscribe->show(($subscribed ? $folder_utf8 : ''), + array('value' => $folder_utf8, 'disabled' => $disabled ? 'disabled' : '')) + ); + } - $table->add('name', $display_folder); - $table->add('subscribed', $checkbox_subscribe->show(($subscribed ? $folder_utf8 : ''), - array('value' => $folder_utf8, 'disabled' => $disabled ? 'disabled' : ''))); + $plugin = $RCMAIL->plugins->exec_hook('folders_list', array('list' => $folders)); - $a_js_folders['rcmrow'.$idx] = array($folder_utf8, - $display_folder, $protected || $folder['virtual']); + // add drop-target representing 'root' + $roots = array( + 'mailboxroot' => array( + 'folder' => '', + 'display' => '', + 'protected' => true, + 'class' => 'root', + 'content' => html::span('name', ' ') + ) + ); + $folders = array_merge($roots, $plugin['list']); + + while (list($key, $data) = each($folders)) { + $js_folders[$key] = array($data['folder'], $data['display'], $data['protected']); + $folders[$key] = html::tag('li', array('id' => $key, 'class' => $data['class']), $data['content']); } - $RCMAIL->plugins->exec_hook('folders_list', array('table' => $table)); - $OUTPUT->add_gui_object('subscriptionlist', $attrib['id']); - $OUTPUT->set_env('subscriptionrows', $a_js_folders); + $OUTPUT->set_env('subscriptionrows', $js_folders); $OUTPUT->set_env('defaultfolders', array_keys($special_folders)); $OUTPUT->set_env('delimiter', $delimiter); - return $form_start . $table->show($attrib) . $form_end; + return $form_start . html::tag('ul', $attrib, implode("\n", $folders)) . $form_end; } function rcmail_folder_frame($attrib) diff --git a/program/steps/settings/func.inc b/program/steps/settings/func.inc index 7ccbfa4a5..40b70b119 100644 --- a/program/steps/settings/func.inc +++ b/program/steps/settings/func.inc @@ -1309,6 +1309,8 @@ function rcmail_update_folder_row($name, $oldname=null, $subscribe=false, $class $display_name = str_repeat('    ', $level) . rcube::Q($protected ? $RCMAIL->localize_foldername($name) : rcube_charset::convert($foldersplit[$level], 'UTF7-IMAP')); + $class_name = trim($class_name . ' listitem'); + if ($oldname === null) { $OUTPUT->command('add_folder_row', $name_utf8, $display_name, $protected, $subscribe, false, $class_name); diff --git a/skins/classic/common.css b/skins/classic/common.css index d28f2871c..13f4e6483 100644 --- a/skins/classic/common.css +++ b/skins/classic/common.css @@ -723,6 +723,7 @@ ul.treelist li font-size: 11px; border-bottom: 1px solid #EBEBEB; white-space: nowrap; + overflow: hidden; } ul.treelist li a diff --git a/skins/classic/functions.js b/skins/classic/functions.js index 7f2b8b4fb..b521be3bb 100644 --- a/skins/classic/functions.js +++ b/skins/classic/functions.js @@ -751,6 +751,8 @@ function rcube_layer(id, attributes) /** * Scroller + * + * @deprecated Use treelist widget */ function rcmail_scroller(list, top, bottom) { @@ -1010,9 +1012,5 @@ function rcube_init_mail_ui() rcmail.addEventListener('afterupload-photo', function(){ rcmail_ui.show_popup('uploadform', false); }) .gui_object('dragmenu', 'dragmenu'); } - else if (rcmail.env.task == 'settings') { - if (rcmail.gui_objects.subscriptionlist) - new rcmail_scroller('#folderlist-content', '#folderlist-title', '#folderlist-footer'); - } }); } diff --git a/skins/classic/mail.css b/skins/classic/mail.css index f9e5e4b9c..58db795cb 100644 --- a/skins/classic/mail.css +++ b/skins/classic/mail.css @@ -409,14 +409,6 @@ background-color: #FFF; } -#mailboxlist li -{ - display: block; - position: relative; - font-size: 11px; - border-bottom: 1px solid #EBEBEB; -} - #mailboxlist li ul li:last-child { border-bottom: 0 none; diff --git a/skins/classic/settings.css b/skins/classic/settings.css index acd0b9fd0..3b084de87 100644 --- a/skins/classic/settings.css +++ b/skins/classic/settings.css @@ -12,64 +12,53 @@ } #identities-table, -#subscription-table, #sections-table { width: 100%; table-layout: fixed; } -#subscription-table input -{ - font: inherit; -} - -#subscription-table tbody td, -#identities-table tbody td, -#sections-table tbody td -{ - cursor: default; - text-overflow: ellipsis; - -o-text-overflow: ellipsis; - height: 18px; -} - #identities-table tbody tr.readonly td { font-style: italic; } -#subscription-table tr.virtual td +#subscription-table li.selected a { - color: #666; + color: #FFF; + background-color: #CC3333; } -#subscription-table tr.root td +#subscription-table li.root { - font-size: 10%; + font-size: 5%; + line-height: 5px; height: 5px; + padding: 2px; } -#subscription-table tr.selected td -{ - color: #FFFFFF; - background-color: #CC3333; -} - -#subscription-table tr.droptarget td +#subscription-table li a.name { - background-color: #FFFFA6; + overflow: hidden; + text-overflow: ellipsis; + width: 100%; + display: block; + float: left; + padding: 0 0 0 5px; + height: 24px; + line-height: 24px; } -#subscription-table td.name +#subscription-table li input { - width: auto; + position: absolute; + right: 0; } -#subscription-table td.subscribed +html.chrome #subscription-table li input, +html.opera #subscription-table li input { - text-align: right; - padding-right: 12px; + margin-top: 6px; } #folder-box, diff --git a/skins/classic/templates/folders.html b/skins/classic/templates/folders.html index f00c23b22..66bec6243 100644 --- a/skins/classic/templates/folders.html +++ b/skins/classic/templates/folders.html @@ -21,8 +21,8 @@
    - +