From f7af22c7801afcc248b004c84d0f1fb45e1a1632 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Tue, 17 Feb 2015 11:54:04 +0100 Subject: Add possibility to print contact information (of a single contact) --- CHANGELOG | 1 + program/js/app.js | 46 +++++++--- program/localization/en_US/labels.inc | 1 + program/steps/addressbook/func.inc | 75 ++++++++++------ program/steps/addressbook/print.inc | 138 ++++++++++++++++++++++++++++++ program/steps/addressbook/show.inc | 15 ++-- skins/classic/addressbook.css | 10 +++ skins/classic/print.css | 64 ++++++++++++++ skins/classic/templates/addressbook.html | 1 + skins/classic/templates/contactprint.html | 20 +++++ skins/larry/print.css | 63 ++++++++++++++ skins/larry/templates/addressbook.html | 1 + skins/larry/templates/contactprint.html | 20 +++++ 13 files changed, 412 insertions(+), 43 deletions(-) create mode 100644 program/steps/addressbook/print.inc create mode 100644 skins/classic/templates/contactprint.html create mode 100644 skins/larry/templates/contactprint.html diff --git a/CHANGELOG b/CHANGELOG index 1b98ed2a2..ec400f2ad 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,7 @@ CHANGELOG Roundcube Webmail =========================== +- Add possibility to print contact information (of a single contact) - Fix refreshing of drafts list when sending a message which was saved in meantime (#1490238) RELEASE 1.1.0 diff --git a/program/js/app.js b/program/js/app.js index 227ba3275..e818955bd 100644 --- a/program/js/app.js +++ b/program/js/app.js @@ -326,10 +326,7 @@ function rcube_webmail() this.enable_command('download', 'print', true); // show printing dialog else if (this.env.action == 'print' && this.env.uid) { - if (bw.safari) - setTimeout('window.print()', 10); - else - window.print(); + this.print_dialog(); } // get unread count for each mailbox @@ -440,6 +437,9 @@ function rcube_webmail() if (this.env.action == 'add' || this.env.action == 'edit' || this.env.action == 'search') this.init_contact_form(); } + else if (this.env.action == 'print') { + this.print_dialog(); + } break; @@ -1176,7 +1176,15 @@ function rcube_webmail() break; case 'print': - if (this.env.action == 'get') { + if (this.task == 'addressbook') { + if (uid = this.contact_list.get_single_selection()) { + url = '&_action=print&_cid=' + uid; + if (this.env.source) + url += '&_source=' + urlencode(this.env.source); + this.open_window(this.env.comm_path + url, true, true); + } + } + else if (this.env.action == 'get') { this.gui_objects.messagepartframe.contentWindow.print(); } else if (uid = this.get_single_uid()) { @@ -4721,6 +4729,7 @@ function rcube_webmail() clearTimeout(this.preview_timer); var n, id, sid, contact, writable = false, + selected = list.selection.length, source = this.env.source ? this.env.address_sources[this.env.source] : null; // we don't have dblclick handler here, so use 200 instead of this.dblclick_time @@ -4729,7 +4738,7 @@ function rcube_webmail() else if (this.env.contentframe) this.show_contentframe(false); - if (list.selection.length) { + if (selected) { list.draggable = false; // no source = search result, we'll need to detect if any of @@ -4764,11 +4773,12 @@ function rcube_webmail() // if a group is currently selected, and there is at least one contact selected // thend we can enable the group-remove-selected command - this.enable_command('group-remove-selected', this.env.group && list.selection.length > 0 && writable); - this.enable_command('compose', this.env.group || list.selection.length > 0); - this.enable_command('export-selected', 'copy', list.selection.length > 0); + this.enable_command('group-remove-selected', this.env.group && selected && writable); + this.enable_command('compose', this.env.group || selected); + this.enable_command('print', selected == 1); + this.enable_command('export-selected', 'copy', selected > 0); this.enable_command('edit', id && writable); - this.enable_command('delete', 'move', list.selection.length > 0 && writable); + this.enable_command('delete', 'move', selected && writable); return false; }; @@ -4881,8 +4891,8 @@ function rcube_webmail() this.contact_list.data = {}; this.contact_list.clear(true); this.show_contentframe(false); - this.enable_command('delete', 'move', 'copy', false); - this.enable_command('compose', this.env.group ? true : false); + this.enable_command('delete', 'move', 'copy', 'print', false); + this.enable_command('compose', this.env.group); }; this.set_group_prop = function(prop) @@ -4922,7 +4932,7 @@ function rcube_webmail() this.contact_list.clear_selection(); this.enable_command('compose', rec && rec.email); - this.enable_command('export-selected', rec && rec._type != 'group'); + this.enable_command('export-selected', 'print', rec && rec._type != 'group'); } else if (framed) return false; @@ -7365,7 +7375,7 @@ function rcube_webmail() this.enable_command('compose', (uid && this.contact_list.rows[uid])); this.enable_command('delete', 'edit', writable); this.enable_command('export', (this.contact_list && this.contact_list.rowcount > 0)); - this.enable_command('export-selected', false); + this.enable_command('export-selected', 'print', false); } case 'move': @@ -8198,6 +8208,14 @@ function rcube_webmail() return false; } }; + + this.print_dialog = function() + { + if (bw.safari) + setTimeout('window.print()', 10); + else + window.print(); + }; } // end object rcube_webmail diff --git a/program/localization/en_US/labels.inc b/program/localization/en_US/labels.inc index 63b6616fe..fac52ba1e 100644 --- a/program/localization/en_US/labels.inc +++ b/program/localization/en_US/labels.inc @@ -343,6 +343,7 @@ $labels['searchresult'] = 'Search result'; $labels['advsearch'] = 'Advanced Search'; $labels['advanced'] = 'Advanced'; $labels['other'] = 'Other'; +$labels['printcontact'] = 'Print contact'; $labels['typehome'] = 'Home'; $labels['typework'] = 'Work'; diff --git a/program/steps/addressbook/func.inc b/program/steps/addressbook/func.inc index c40b517dc..594c2a695 100644 --- a/program/steps/addressbook/func.inc +++ b/program/steps/addressbook/func.inc @@ -518,12 +518,13 @@ function rcmail_contact_form($form, $record, $attrib = null) $plugin = $RCMAIL->plugins->exec_hook('contact_form', array( 'form' => $form, 'record' => $record)); - $form = $plugin['form']; - $record = $plugin['record']; - $edit_mode = $RCMAIL->action != 'show'; + $form = $plugin['form']; + $record = $plugin['record']; + $edit_mode = $RCMAIL->action != 'show' && $RCMAIL->action != 'print'; $del_button = $attrib['deleteicon'] ? html::img(array('src' => $RCMAIL->output->get_skin_file($attrib['deleteicon']), 'alt' => $RCMAIL->gettext('delete'))) : $RCMAIL->gettext('delete'); + $out = ''; + unset($attrib['deleteicon']); - $out = ''; // get default coltypes $coltypes = $GLOBALS['CONTACT_COLTYPES']; @@ -544,8 +545,9 @@ function rcmail_contact_form($form, $record, $attrib = null) foreach ($form as $section => $fieldset) { // skip empty sections - if (empty($fieldset['content'])) + if (empty($fieldset['content'])) { continue; + } $select_add = new html_select(array('class' => 'addfieldmenu', 'rel' => $section)); $select_add->add($RCMAIL->gettext('addfield'), ''); @@ -555,18 +557,20 @@ function rcmail_contact_form($form, $record, $attrib = null) $content = ''; // unset display name if it is composed from name parts - if ($record['name'] == rcube_addressbook::compose_display_name(array('name' => '') + (array)$record)) - unset($record['name']); + if ($record['name'] == rcube_addressbook::compose_display_name(array('name' => '') + (array)$record)) { + unset($record['name']); + } // group fields $field_blocks = array( - 'names' => array('prefix','firstname','middlename','surname','suffix'), - 'displayname' => array('name'), - 'nickname' => array('nickname'), + 'names' => array('prefix','firstname','middlename','surname','suffix'), + 'displayname' => array('name'), + 'nickname' => array('nickname'), 'organization' => array('organization'), - 'department' => array('department'), - 'jobtitle' => array('jobtitle'), + 'department' => array('department'), + 'jobtitle' => array('jobtitle'), ); + foreach ($field_blocks as $blockname => $colnames) { $fields = ''; foreach ($colnames as $col) { @@ -574,11 +578,16 @@ function rcmail_contact_form($form, $record, $attrib = null) if (!$coltypes[$col]) continue; + // skip cols not listed in the form definition + if (is_array($fieldset['content']) && !in_array($col, array_keys($fieldset['content']))) { + continue; + } + // only string values are expected here if (is_array($record[$col])) $record[$col] = join(' ', $record[$col]); - if ($RCMAIL->action == 'show') { + if (!$edit_mode) { if (!empty($record[$col])) $fields .= html::span('namefield ' . $col, rcube::Q($record[$col])) . " "; } @@ -611,11 +620,15 @@ function rcmail_contact_form($form, $record, $attrib = null) $fullkey = $col.':'.$subtype; // skip cols unknown to the backend - if (!$coltypes[$field]) + if (!$coltypes[$field] && empty($colprop['value'])) { continue; + } // merge colprop with global coltype configuration - $colprop += $coltypes[$field]; + if ($coltypes[$field]) { + $colprop += $coltypes[$field]; + } + $label = isset($colprop['label']) ? $colprop['label'] : $RCMAIL->gettext($col); // prepare subtype selector in edit mode @@ -624,8 +637,9 @@ function rcmail_contact_form($form, $record, $attrib = null) $select_subtype = new html_select(array('name' => '_subtype_'.$col.'[]', 'class' => 'contactselectsubtype', 'title' => $colprop['label'] . ' ' . $RCMAIL->gettext('type'))); $select_subtype->add($subtype_names, $colprop['subtypes']); } - else + else { $select_subtype = null; + } if (!empty($colprop['value'])) { $values = (array)$colprop['value']; @@ -729,12 +743,21 @@ function rcmail_contact_form($form, $record, $attrib = null) // display row with label if ($label) { + if ($RCMAIL->action == 'print') { + $_label = rcube::Q($colprop['label'] . ($label != $colprop['label'] ? ' (' . $label . ')' : '')); + } + else { + $_label = $select_subtype ? $select_subtype->show($subtype) : html::label($colprop['id'], rcube::Q($label)); + } + $rows .= html::div('row', - html::div('contactfieldlabel label', $select_subtype ? $select_subtype->show($subtype) : html::label($colprop['id'], rcube::Q($label))) . + html::div('contactfieldlabel label', $_label) . html::div('contactfieldcontent '.$colprop['type'], $val)); } - else // row without label + // row without label + else { $rows .= html::div('row', html::div('contactfield', $val)); + } } // add option to the add-field menu @@ -745,9 +768,13 @@ function rcmail_contact_form($form, $record, $attrib = null) // wrap rows in fieldgroup container if ($rows) { - $content .= html::tag('fieldset', array('class' => 'contactfieldgroup ' . ($colprop['subtypes'] ? 'contactfieldgroupmulti ' : '') . 'contactcontroller' . $col, 'style' => ($rows ? null : 'display:none')), - ($colprop['subtypes'] ? html::tag('legend', null, rcube::Q($colprop['label'])) : ' ') . - $rows); + $c_class = 'contactfieldgroup ' . ($colprop['subtypes'] ? 'contactfieldgroupmulti ' : '') . 'contactcontroller' . $col; + $with_label = $colprop['subtypes'] && $RCMAIL->action != 'print'; + $content .= html::tag( + 'fieldset', + array('class' => $c_class, 'style' => ($rows ? null : 'display:none')), + ($with_label ? html::tag('legend', null, rcube::Q($colprop['label'])) : ' ') . $rows + ); } } @@ -769,9 +796,9 @@ function rcmail_contact_form($form, $record, $attrib = null) } if ($edit_mode) { - $RCMAIL->output->set_env('coltypes', $coltypes + $coltype_labels); - $RCMAIL->output->set_env('delbutton', $del_button); - $RCMAIL->output->add_label('delete'); + $RCMAIL->output->set_env('coltypes', $coltypes + $coltype_labels); + $RCMAIL->output->set_env('delbutton', $del_button); + $RCMAIL->output->add_label('delete'); } return $out; diff --git a/program/steps/addressbook/print.inc b/program/steps/addressbook/print.inc new file mode 100644 index 000000000..c9460d44f --- /dev/null +++ b/program/steps/addressbook/print.inc @@ -0,0 +1,138 @@ + | + | Author: Aleksander Machniak | + +-----------------------------------------------------------------------+ +*/ + +// Get contact ID and source ID from request +$cids = rcmail_get_cids(); +$source = key($cids); +$cid = $cids ? array_shift($cids[$source]) : null; + +// Initialize addressbook source +$CONTACTS = rcmail_contact_source($source, true); +$SOURCE_ID = $source; + +// read contact record +if ($cid && $CONTACTS) { + $record = $CONTACTS->get_record($cid, true); +} + +$OUTPUT->add_handlers(array( + 'contacthead' => 'rcmail_contact_head', + 'contactdetails' => 'rcmail_contact_details', + 'contactphoto' => 'rcmail_contact_photo', +)); + +$OUTPUT->send('contactprint'); + + + +function rcmail_contact_head($attrib) +{ + global $CONTACTS, $RCMAIL; + + // check if we have a valid result + if (!(($result = $CONTACTS->get_result()) && ($record = $result->first()))) { + $RCMAIL->output->show_message('contactnotfound', 'error'); + return false; + } + + $form = array( + 'head' => array( // section 'head' is magic! + 'name' => $RCMAIL->gettext('contactnameandorg'), + 'content' => array( + 'prefix' => array(), + 'name' => array(), + 'firstname' => array(), + 'middlename' => array(), + 'surname' => array(), + 'suffix' => array(), + ), + ), + ); + + unset($attrib['name']); + return rcmail_contact_form($form, $record, $attrib); +} + + +function rcmail_contact_details($attrib) +{ + global $CONTACTS, $RCMAIL, $CONTACT_COLTYPES; + + // check if we have a valid result + if (!(($result = $CONTACTS->get_result()) && ($record = $result->first()))) { + return false; + } + + $i_size = !empty($attrib['size']) ? $attrib['size'] : 40; + + $form = array( + 'contact' => array( + 'name' => $RCMAIL->gettext('properties'), + 'content' => array( + 'organization' => array(), + 'department' => array(), + 'jobtitle' => array(), + 'email' => array(), + 'phone' => array(), + 'address' => array(), + 'website' => array(), + 'im' => array(), + 'groups' => array('value' => 'sdfsdfs', 'label' => $RCMAIL->gettext('groups')), + ), + ), + 'personal' => array( + 'name' => $RCMAIL->gettext('personalinfo'), + 'content' => array( + 'nickname' => array(), + 'gender' => array(), + 'maidenname' => array(), + 'birthday' => array(), + 'anniversary' => array(), + 'manager' => array(), + 'assistant' => array(), + 'spouse' => array(), + ), + ), + ); + + if (isset($CONTACT_COLTYPES['notes'])) { + $form['notes'] = array( + 'name' => $RCMAIL->gettext('notes'), + 'content' => array( + 'notes' => array('type' => 'textarea', 'label' => false), + ), + ); + } + + if ($CONTACTS->groups) { + $groups = $CONTACTS->get_record_groups($record['ID']); + if (!empty($groups)) { + $form['contact']['content']['groups'] = array( + 'value' => rcube::Q(implode(', ', $groups)), + 'label' => $RCMAIL->gettext('groups') + ); + } + } + + return rcmail_contact_form($form, $record); +} diff --git a/program/steps/addressbook/show.inc b/program/steps/addressbook/show.inc index 5835ce7e5..d1bc8594d 100644 --- a/program/steps/addressbook/show.inc +++ b/program/steps/addressbook/show.inc @@ -66,11 +66,16 @@ function rcmail_contact_head($attrib) 'head' => array( // section 'head' is magic! 'name' => $RCMAIL->gettext('contactnameandorg'), 'content' => array( - 'prefix' => array('type' => 'text'), - 'firstname' => array('type' => 'text'), - 'middlename' => array('type' => 'text'), - 'surname' => array('type' => 'text'), - 'suffix' => array('type' => 'text'), + 'prefix' => array('type' => 'text'), + 'firstname' => array('type' => 'text'), + 'middlename' => array('type' => 'text'), + 'surname' => array('type' => 'text'), + 'suffix' => array('type' => 'text'), + 'name' => array('type' => 'text'), + 'nickname' => array('type' => 'text'), + 'organization' => array('type' => 'text'), + 'department' => array('type' => 'text'), + 'jobtitle' => array('type' => 'text'), ), ), ); diff --git a/skins/classic/addressbook.css b/skins/classic/addressbook.css index 90438aa70..b54f057c8 100644 --- a/skins/classic/addressbook.css +++ b/skins/classic/addressbook.css @@ -43,6 +43,16 @@ background-position: -32px -32px; } +#abooktoolbar a.print { + background: url(images/mail_toolbar.png) 0 0 no-repeat transparent; + background-position: -256px 0; +} + +#abooktoolbar a.printSel { + background: url(images/mail_toolbar.png) 0 0 no-repeat transparent; + background-position: -256px -32px; +} + #abooktoolbar a.delete { background-position: -64px 0; } diff --git a/skins/classic/print.css b/skins/classic/print.css index 349b224cb..4d7fb246e 100644 --- a/skins/classic/print.css +++ b/skins/classic/print.css @@ -159,3 +159,67 @@ p.image-attachment .attachment-links { display: none; } + +/* contact print */ +#contact-details fieldset { + color: #666; + border: 1px solid #999; + margin-top: 5px; +} + +#contact-details fieldset.contactfieldgroup { + border: 0; + padding: 0; + margin: 0; +} + +#contact-details div.row { + padding: 2px 0; +} + +#contact-details .contactfieldlabel { + display: inline-block; + vertical-align: top; + width: 150px; + overflow: hidden; + text-overflow: ellipsis; +} + +#contact-details .contactfieldcontent { + display: inline-block; + vertical-align: top; + font-weight: bold; +} + +#contact-details #contactphoto { + float: left; + margin: 5px 15px 5px 3px; + width: 112px; + border: 0; + padding: 0; +} + +#contact-details #contactpic { + width: 112px; + background: white; +} + +#contact-details #contactpic img { + max-width: 112px; + visibility: inherit; +} + +#contact-details #contacthead { + border: 0; + margin: 0 16em 0 0; + padding: 0; +} + +#contact-details #contacthead > legend { + display: none; +} + +#contact-details #contacthead .names span.namefield { + font-size: 140%; + font-weight: bold; +} diff --git a/skins/classic/templates/addressbook.html b/skins/classic/templates/addressbook.html index 0af5e4317..6fb8bf599 100644 --- a/skins/classic/templates/addressbook.html +++ b/skins/classic/templates/addressbook.html @@ -21,6 +21,7 @@
+   diff --git a/skins/classic/templates/contactprint.html b/skins/classic/templates/contactprint.html new file mode 100644 index 000000000..81794f5a1 --- /dev/null +++ b/skins/classic/templates/contactprint.html @@ -0,0 +1,20 @@ + + + +<roundcube:object name="pagetitle" /> + + + + + +