Add new folder navigation to address book (#3046).
This patches/overwrites default functions from Roundcube core. Be careful when updating those!
This commit is contained in:
parent
22d3e7553b
commit
32164e30bf
8 changed files with 404 additions and 35 deletions
|
@ -87,6 +87,91 @@ if (window.rcmail) {
|
|||
}
|
||||
});
|
||||
}
|
||||
|
||||
// append search form for address books
|
||||
if (rcmail.gui_objects.folderlist) {
|
||||
var container = $(rcmail.gui_objects.folderlist);
|
||||
$('<div class="listsearchbox" style="display:none">' +
|
||||
'<div class="searchbox" role="search" aria-labelledby="aria-labelfoldersearchform" aria-controls="' + rcmail.gui_objects.folderlist.id + '">' +
|
||||
'<h3 id="aria-label-labelfoldersearchform" class="voice">' + rcmail.gettext('foldersearchform', 'kolab_addressbook') + '" /></h3>' +
|
||||
'<label for="addressbooksearch" class="voice">' + rcmail.gettext('searchterms', 'kolab_addressbook') + '</label>' +
|
||||
'<input type="text" name="q" id="addressbooksearch" placeholder="' + rcmail.gettext('findaddressbooks', 'kolab_addressbook') + '" />' +
|
||||
'<a class="iconbutton searchicon"></a>' +
|
||||
'<a href="#reset" onclick="return rcmail.command(\'reset-listsearch\',null,this,event)" id="directorylistsearch-reset" class="iconbutton reset" title="' + rcmail.gettext('resetsearch') + '">' +
|
||||
rcmail.gettext('resetsearch') + '</a>' +
|
||||
'</div>' +
|
||||
'</div>')
|
||||
.insertBefore(container.parent());
|
||||
|
||||
$('<a href="#search" class="iconbutton search" title="' + rcmail.gettext('findaddressbooks', 'kolab_addressbook') + '" tabindex="0">' +
|
||||
rcmail.gettext('findaddressbooks', 'kolab_addressbook') + '</a>')
|
||||
.appendTo('#directorylistbox h2.boxtitle')
|
||||
.click(function(e){
|
||||
var box = $('#directorylistbox .listsearchbox'),
|
||||
dir = box.is(':visible') ? -1 : 1;
|
||||
|
||||
box.slideToggle({
|
||||
duration: 160,
|
||||
progress: function(animation, progress) {
|
||||
if (dir < 0) progress = 1 - progress;
|
||||
$('#directorylistbox .scroller').css('top', (34 + 34 * progress) + 'px');
|
||||
},
|
||||
complete: function() {
|
||||
box.toggleClass('expanded');
|
||||
if (box.is(':visible')) {
|
||||
box.find('input[type=text]').focus();
|
||||
}
|
||||
else {
|
||||
$('#directorylistsearch-reset').click();
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
// remove event handlers set by the regular treelist widget
|
||||
rcmail.treelist.container.off('click mousedown focusin focusout');
|
||||
|
||||
// re-initialize folderlist widget
|
||||
// copy form app.js with additional parameters
|
||||
var widget_class = window.kolab_folderlist || rcube_treelist_widget;
|
||||
rcmail.treelist = new widget_class(rcmail.gui_objects.folderlist, {
|
||||
selectable: true,
|
||||
id_prefix: 'rcmli',
|
||||
id_encode: rcmail.html_identifier_encode,
|
||||
id_decode: rcmail.html_identifier_decode,
|
||||
searchbox: '#addressbooksearch',
|
||||
search_action: 'plugin.book-search',
|
||||
search_sources: [ 'folders', 'users' ],
|
||||
search_title: rcmail.gettext('listsearchresults','kolab_addressbook'),
|
||||
check_droptarget: function(node) { return !node.virtual && rcmail.check_droptarget(node.id) }
|
||||
});
|
||||
|
||||
rcmail.treelist
|
||||
.addEventListener('collapse', function(node) { rcmail.folder_collapsed(node) })
|
||||
.addEventListener('expand', function(node) { rcmail.folder_collapsed(node) })
|
||||
.addEventListener('select', function(node) { rcmail.triggerEvent('selectfolder', { folder:node.id, prefix:'rcmli' }) })
|
||||
.addEventListener('subscribe', function(node) {
|
||||
var source;
|
||||
if ((source = rcmail.env.address_sources[node.id])) {
|
||||
source.subscribed = node.subscribed || false;
|
||||
rcmail.http_post('plugin.book-subscribe', { _source:node.id, _permanent:source.subscribed?1:0 });
|
||||
}
|
||||
})
|
||||
.addEventListener('insert-item', function(data) {
|
||||
// register new address source
|
||||
rcmail.env.address_sources[data.id] = rcmail.env.contactfolders[data.id] = data.data;
|
||||
if (data.data.subscribed)
|
||||
rcmail.http_post('plugin.book-subscribe', { _source:data.id, _permanent:1 });
|
||||
// TODO: load groups and add them to the list
|
||||
})
|
||||
.addEventListener('search-complete', function(data) {
|
||||
if (data.length)
|
||||
rcmail.display_message(rcmail.gettext('nraddressbooksfound','kolab_addressbook').replace('$nr', data.length), 'voice');
|
||||
else
|
||||
rcmail.display_message(rcmail.gettext('noaddressbooksfound','kolab_addressbook'), 'info');
|
||||
});
|
||||
}
|
||||
});
|
||||
rcmail.addEventListener('listupdate', function() {
|
||||
rcmail.set_book_actions();
|
||||
|
|
|
@ -66,6 +66,8 @@ class kolab_addressbook extends rcube_plugin
|
|||
// Plugin actions
|
||||
$this->register_action('plugin.book', array($this, 'book_actions'));
|
||||
$this->register_action('plugin.book-save', array($this, 'book_save'));
|
||||
$this->register_action('plugin.book-search', array($this, 'book_search'));
|
||||
$this->register_action('plugin.book-subscribe', array($this, 'book_subscribe'));
|
||||
|
||||
// Load UI elements
|
||||
if ($this->api->output->type == 'html') {
|
||||
|
@ -133,19 +135,34 @@ class kolab_addressbook extends rcube_plugin
|
|||
*/
|
||||
protected function abook_prop($id, $abook)
|
||||
{
|
||||
return array(
|
||||
'id' => $id,
|
||||
'name' => $abook->get_name(),
|
||||
'listname' => $abook->get_foldername(),
|
||||
'readonly' => $abook->readonly,
|
||||
'editable' => $abook->editable,
|
||||
'groups' => $abook->groups,
|
||||
'undelete' => $abook->undelete && $this->rc->config->get('undo_timeout'),
|
||||
'realname' => rcube_charset::convert($abook->get_realname(), 'UTF7-IMAP'), // IMAP folder name
|
||||
'group' => $abook->get_namespace(),
|
||||
'carddavurl' => $abook->get_carddav_url(),
|
||||
'kolab' => true,
|
||||
);
|
||||
if ($abook->virtual) {
|
||||
return array(
|
||||
'id' => $id,
|
||||
'name' => $abook->get_name(),
|
||||
'listname' => $abook->get_foldername(),
|
||||
'group' => $abook instanceof kolab_storage_folder_user ? 'user' : $abook->get_namespace(),
|
||||
'readonly' => true,
|
||||
'editable' => false,
|
||||
'kolab' => true,
|
||||
'virtual' => true,
|
||||
);
|
||||
}
|
||||
else {
|
||||
return array(
|
||||
'id' => $id,
|
||||
'name' => $abook->get_name(),
|
||||
'listname' => $abook->get_foldername(),
|
||||
'readonly' => $abook->readonly,
|
||||
'editable' => $abook->editable,
|
||||
'groups' => $abook->groups,
|
||||
'undelete' => $abook->undelete && $this->rc->config->get('undo_timeout'),
|
||||
'realname' => rcube_charset::convert($abook->get_realname(), 'UTF7-IMAP'), // IMAP folder name
|
||||
'group' => $abook->get_namespace(),
|
||||
'subscribed' => $abook->is_subscribed(),
|
||||
'carddavurl' => $abook->get_carddav_url(),
|
||||
'kolab' => true,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -167,7 +184,8 @@ class kolab_addressbook extends rcube_plugin
|
|||
kolab_storage::folder_hierarchy($this->folders, $tree);
|
||||
$out .= $this->folder_tree_html($tree, $sources, $jsdata);
|
||||
|
||||
$this->rc->output->set_env('contactgroups', $jsdata);
|
||||
$this->rc->output->set_env('contactgroups', array_filter($jsdata, function($src){ return $src['type'] == 'group'; }));
|
||||
$this->rc->output->set_env('address_sources', array_filter($jsdata, function($src){ return $src['type'] != 'group'; }));
|
||||
|
||||
$args['content'] = html::tag('ul', $args, $out, html::$common_attrib);
|
||||
return $args;
|
||||
|
@ -185,16 +203,11 @@ class kolab_addressbook extends rcube_plugin
|
|||
$is_collapsed = strpos($this->rc->config->get('collapsed_abooks',''), '&'.rawurlencode($id).'&') !== false;
|
||||
|
||||
if ($folder->virtual) {
|
||||
$source = array(
|
||||
'id' => $folder->id,
|
||||
'name' => $folder->get_name(),
|
||||
'listname' => $folder->get_foldername(),
|
||||
'group' => $folder->get_namespace(),
|
||||
'readonly' => true,
|
||||
'editable' => false,
|
||||
'kolab' => true,
|
||||
'virtual' => true,
|
||||
);
|
||||
$source = $this->abook_prop($folder->id, $folder);
|
||||
}
|
||||
else if (empty($source)) {
|
||||
$this->sources[$id] = new rcube_kolab_contacts($folder->name);
|
||||
$source = $this->abook_prop($id, $this->sources[$id]);
|
||||
}
|
||||
|
||||
$content = $this->addressbook_list_item($id, $source, $jsdata);
|
||||
|
@ -219,11 +232,15 @@ class kolab_addressbook extends rcube_plugin
|
|||
/**
|
||||
*
|
||||
*/
|
||||
protected function addressbook_list_item($id, $source, &$jsdata, $checkbox = false)
|
||||
protected function addressbook_list_item($id, $source, &$jsdata, $search_mode = false)
|
||||
{
|
||||
$folder = $this->folders[$id];
|
||||
$current = rcube_utils::get_input_value('_source', rcube_utils::INPUT_GPC);
|
||||
|
||||
if (!$source['virtual']) {
|
||||
$jsdata[$id] = $source;
|
||||
}
|
||||
|
||||
// set class name(s)
|
||||
$classes = array($source['group'] ?: '000', 'addressbook');
|
||||
if ($current === $id)
|
||||
|
@ -236,19 +253,48 @@ class kolab_addressbook extends rcube_plugin
|
|||
$classes[] = $source['class_name'];
|
||||
|
||||
$name = !empty($source['listname']) ? $source['listname'] : (!empty($source['name']) ? $source['name'] : $id);
|
||||
$label_id = 'kabt:' . $id;
|
||||
$inner = ($source['virtual'] ?
|
||||
html::a(array('tabindex' => '0'), $name) :
|
||||
html::a(array(
|
||||
'href' => $this->rc->url(array('_source' => $id)),
|
||||
'rel' => $source['id'],
|
||||
'id' => $label_id,
|
||||
'onclick' => "return " . rcmail_output::JS_OBJECT_NAME.".command('list','" . rcube::JQ($id) . "',this)",
|
||||
), $name)
|
||||
);
|
||||
|
||||
if (isset($source['subscribed'])) {
|
||||
$inner .= html::span(array(
|
||||
'class' => 'subscribed',
|
||||
'title' => $this->gettext('foldersubscribe'),
|
||||
'role' => 'checkbox',
|
||||
'aria-checked' => $source['subscribed'] ? 'true' : 'false',
|
||||
), '');
|
||||
}
|
||||
|
||||
// don't wrap in <li> but add a checkbox for search results listing
|
||||
if ($search_mode) {
|
||||
$jsdata[$id]['group'] = join(' ', $classes);
|
||||
|
||||
if (!$source['virtual']) {
|
||||
$inner .= html::tag('input', array(
|
||||
'type' => 'checkbox',
|
||||
'name' => '_source[]',
|
||||
'value' => $id,
|
||||
'checked' => $prop['active'],
|
||||
'aria-labelledby' => $label_id,
|
||||
));
|
||||
}
|
||||
return html::div(null, $inner);
|
||||
}
|
||||
|
||||
$out .= html::tag('li', array(
|
||||
'id' => 'rcmli' . rcube_utils::html_identifier($id, true),
|
||||
'class' => join(' ', $classes),
|
||||
'noclose' => true,
|
||||
),
|
||||
($source['virtual'] ?
|
||||
html::a(array('tabindex' => '0'), $name) :
|
||||
html::a(array(
|
||||
'href' => $this->rc->url(array('_source' => $id)),
|
||||
'rel' => $source['id'],
|
||||
'onclick' => "return " . rcmail_output::JS_OBJECT_NAME.".command('list','" . rcube::JQ($id) . "',this)",
|
||||
), $name)
|
||||
)
|
||||
html::div($source['subscribed'] ? 'subscribed' : null, $inner)
|
||||
);
|
||||
|
||||
$groupdata = array('out' => '', 'jsdata' => $jsdata, 'source' => $id);
|
||||
|
@ -596,6 +642,119 @@ class kolab_addressbook extends rcube_plugin
|
|||
$this->ui->book_edit();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function book_search()
|
||||
{
|
||||
$results = array();
|
||||
$query = rcube_utils::get_input_value('q', RCUBE_INPUT_GPC);
|
||||
$source = rcube_utils::get_input_value('source', RCUBE_INPUT_GPC);
|
||||
|
||||
kolab_storage::$encode_ids = true;
|
||||
$search_more_results = false;
|
||||
$this->sources = array();
|
||||
$this->folders = array();
|
||||
|
||||
// find unsubscribed IMAP folders that have "event" type
|
||||
if ($source == 'folders') {
|
||||
foreach ((array)kolab_storage::search_folders('contact', $query, array('other')) as $folder) {
|
||||
$this->folders[$folder->id] = $folder;
|
||||
$this->sources[$folder->id] = new rcube_kolab_contacts($folder->name);
|
||||
}
|
||||
}
|
||||
// search other user's namespace via LDAP
|
||||
else if ($source == 'users') {
|
||||
$limit = $this->rc->config->get('autocomplete_max', 15) * 2; // we have slightly more space, so display twice the number
|
||||
foreach (kolab_storage::search_users($query, 0, array(), $limit * 10) as $user) {
|
||||
$folders = array();
|
||||
// search for contact folders shared by this user
|
||||
foreach (kolab_storage::list_user_folders($user, 'contact', false) as $foldername) {
|
||||
$folders[] = new kolab_storage_folder($foldername, 'contact');
|
||||
}
|
||||
|
||||
if (count($folders)) {
|
||||
$userfolder = new kolab_storage_folder_user($user['kolabtargetfolder'], '', $user);
|
||||
$this->folders[$userfolder->id] = $userfolder;
|
||||
$this->sources[$userfolder->id] = $userfolder;
|
||||
|
||||
foreach ($folders as $folder) {
|
||||
$this->folders[$folder->id] = $folder;
|
||||
$this->sources[$folder->id] = new rcube_kolab_contacts($folder->name);;
|
||||
$count++;
|
||||
}
|
||||
}
|
||||
|
||||
if ($count >= $limit) {
|
||||
$search_more_results = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$delim = $this->rc->get_storage()->get_hierarchy_delimiter();
|
||||
|
||||
// build results list
|
||||
foreach ($this->sources as $id => $source) {
|
||||
$folder = $this->folders[$id];
|
||||
$imap_path = explode($delim, $folder->name);
|
||||
|
||||
// find parent
|
||||
do {
|
||||
array_pop($imap_path);
|
||||
$parent_id = kolab_storage::folder_id(join($delim, $imap_path));
|
||||
}
|
||||
while (count($imap_path) > 1 && !$this->folders[$parent_id]);
|
||||
|
||||
// restore "real" parent ID
|
||||
if ($parent_id && !$this->folders[$parent_id]) {
|
||||
$parent_id = kolab_storage::folder_id($folder->get_parent());
|
||||
}
|
||||
|
||||
$prop = $this->abook_prop($id, $source);
|
||||
$prop['parent'] = $parent_id;
|
||||
unset($prop['group']);
|
||||
|
||||
$html = $this->addressbook_list_item($id, $prop, $jsdata, true);
|
||||
$prop += (array)$jsdata[$id];
|
||||
$prop['html'] = $html;
|
||||
|
||||
$results[] = $prop;
|
||||
}
|
||||
|
||||
// report more results available
|
||||
if ($search_more_results) {
|
||||
$this->rc->output->show_message('autocompletemore', 'info');
|
||||
}
|
||||
|
||||
$this->rc->output->command('multi_thread_http_response', $results, rcube_utils::get_input_value('_reqid', RCUBE_INPUT_GPC));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function book_subscribe()
|
||||
{
|
||||
$success = false;
|
||||
$id = rcube_utils::get_input_value('_source', RCUBE_INPUT_GPC);
|
||||
|
||||
if ($id && ($folder = kolab_storage::get_folder(kolab_storage::id_decode($id)))) {
|
||||
if (isset($_POST['_permanent']))
|
||||
$success |= $folder->subscribe(intval($_POST['_permanent']));
|
||||
if (isset($_POST['_active']))
|
||||
$success |= $folder->activate(intval($_POST['_active']));
|
||||
}
|
||||
|
||||
if ($success) {
|
||||
$this->rc->output->show_message('successfullysaved', 'confirmation');
|
||||
}
|
||||
else {
|
||||
$this->rc->output->show_message($this->gettext('errorsaving'), 'error');
|
||||
}
|
||||
|
||||
$this->rc->output->send();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handler for address book delete action (AJAX)
|
||||
|
|
|
@ -54,6 +54,11 @@ class kolab_addressbook_ui
|
|||
// Include stylesheet (for directorylist)
|
||||
$this->plugin->include_stylesheet($this->plugin->local_skin_path().'/kolab_addressbook.css');
|
||||
|
||||
// include kolab folderlist widget if available
|
||||
if (is_readable($this->plugin->api->dir . 'libkolab/js/folderlist.js')) {
|
||||
$this->plugin->api->include_script('libkolab/js/folderlist.js');
|
||||
}
|
||||
|
||||
// Add actions on address books
|
||||
$options = array('book-create', 'book-edit', 'book-delete');
|
||||
$idx = 0;
|
||||
|
@ -91,7 +96,14 @@ class kolab_addressbook_ui
|
|||
'kolab_addressbook.carddavurldescription',
|
||||
'kolab_addressbook.bookedit',
|
||||
'kolab_addressbook.bookdelete',
|
||||
'kolab_addressbook.bookshowurl');
|
||||
'kolab_addressbook.bookshowurl',
|
||||
'kolab_addressbook.findaddressbooks',
|
||||
'kolab_addressbook.searchterms',
|
||||
'kolab_addressbook.foldersearchform',
|
||||
'kolab_addressbook.listsearchresults',
|
||||
'kolab_addressbook.nraddressbooksfound',
|
||||
'kolab_addressbook.noaddressbooksfound',
|
||||
'resetsearch');
|
||||
}
|
||||
// book create/edit form
|
||||
else {
|
||||
|
|
|
@ -198,6 +198,16 @@ class rcube_kolab_contacts extends rcube_addressbook
|
|||
return $this->storagefolder->get_parent();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check subscription status of this folder
|
||||
*
|
||||
* @return boolean True if subscribed, false if not
|
||||
*/
|
||||
public function is_subscribed()
|
||||
{
|
||||
return kolab_storage::folder_is_subscribed($this->imap_folder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compose an URL for CardDAV access to this address book (if configured)
|
||||
*/
|
||||
|
|
|
@ -34,6 +34,14 @@ $labels['globalfirst'] = 'Global address book(s) first';
|
|||
$labels['personalonly'] = 'Personal address book(s) only';
|
||||
$labels['globalonly'] = 'Global address book(s) only';
|
||||
|
||||
$labels['findaddressbooks'] = 'Find address books';
|
||||
$labels['searchterms'] = 'Search terms';
|
||||
$labels['listsearchresults'] = 'Additional address books';
|
||||
$labels['foldersearchform'] = 'Address book search form';
|
||||
$labels['foldersubscribe'] = 'List permanently';
|
||||
$labels['nraddressbooksfound'] = '$nr address books found';
|
||||
$labels['noaddressbooksfound'] = 'No address books found';
|
||||
|
||||
$messages['bookdeleteconfirm'] = 'Do you really want to delete the selected address book and all contacts in it?';
|
||||
$messages['bookdeleting'] = 'Deleting address book...';
|
||||
$messages['booksaving'] = 'Saving address book...';
|
||||
|
|
|
@ -1,6 +1,19 @@
|
|||
#directorylistbox ul.treelist li.virtual {
|
||||
background-image: none !important;
|
||||
}
|
||||
|
||||
#directorylistbox ul.treelist li.virtual > div a {
|
||||
color: #aaa;
|
||||
background-image: none;
|
||||
}
|
||||
|
||||
#directorylistbox ul.treelist li.virtual > .treetoggle {
|
||||
top: -2px !important;
|
||||
}
|
||||
|
||||
/*
|
||||
#directorylist li.addressbook.readonly
|
||||
{
|
||||
/* don't use 'background' to not reset background color */
|
||||
background-image: url(kolab_folders.png);
|
||||
background-position: 5px 0px;
|
||||
background-repeat: no-repeat;
|
||||
|
@ -33,3 +46,4 @@
|
|||
background-position: 5px -36px;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
*/
|
Binary file not shown.
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 1.3 KiB |
|
@ -1,4 +1,79 @@
|
|||
|
||||
#directorylistbox .listsearchbox + .scroller {
|
||||
top: 34px;
|
||||
}
|
||||
|
||||
#directorylistbox .listsearchbox.expanded + .scroller {
|
||||
top: 68px;
|
||||
}
|
||||
|
||||
#directorylistbox .boxtitle a.iconbutton.search {
|
||||
position: absolute;
|
||||
top: 8px;
|
||||
right: 8px;
|
||||
width: 16px;
|
||||
cursor: pointer;
|
||||
background-position: -2px -317px;
|
||||
}
|
||||
|
||||
#directorylistbox ul.treelist li.virtual {
|
||||
background-image: none !important;
|
||||
}
|
||||
|
||||
#directorylistbox ul.treelist li.virtual > div a {
|
||||
color: #aaa;
|
||||
background-image: none;
|
||||
height: 16px;
|
||||
padding-top: 3px;
|
||||
padding-bottom: 3px;
|
||||
}
|
||||
|
||||
#directorylistbox ul.treelist li.virtual > .treetoggle {
|
||||
top: 6px !important;
|
||||
}
|
||||
|
||||
#directorylistbox ul.treelist li input {
|
||||
position: absolute;
|
||||
top: 4px;
|
||||
left: 10px;
|
||||
}
|
||||
|
||||
#directorylistbox ul.treelist ul li input {
|
||||
left: 36px;
|
||||
}
|
||||
|
||||
#directorylist li input {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#directorylistbox ul.treelist div span.subscribed {
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
top: 4px;
|
||||
right: 5px;
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
padding: 0;
|
||||
background: url(folder_icons.png) -100px 0 no-repeat;
|
||||
overflow: hidden;
|
||||
text-indent: -5000px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#directorylistbox ul.treelist div > span.subscribed:focus,
|
||||
#directorylistbox ul.treelist div:hover > span.subscribed {
|
||||
background-position: 2px -160px;
|
||||
}
|
||||
|
||||
#directorylistbox ul.treelist div.subscribed span.subscribed {
|
||||
background-position: -16px -160px;
|
||||
}
|
||||
|
||||
#directorylistbox ul.treelist div span.subscribed:focus {
|
||||
border-radius: 3px;
|
||||
outline: 2px solid rgba(30,150,192, 0.5);
|
||||
}
|
||||
|
||||
#directorylist li.addressbook.readonly,
|
||||
#directorylist li.addressbook.shared,
|
||||
#directorylist li.addressbook.other {
|
||||
|
@ -15,6 +90,7 @@
|
|||
background-position: 98% -52px;
|
||||
}
|
||||
|
||||
#directorylist li.addressbook.personal.readonly,
|
||||
#directorylist li.addressbook.other.readonly {
|
||||
background-position: 98% -77px;
|
||||
}
|
||||
|
@ -27,6 +103,11 @@
|
|||
background-position: 98% -130px;
|
||||
}
|
||||
|
||||
#directorylist li.addressbook.virtual.user {
|
||||
background-image: url(folder_icons.png) !important;
|
||||
background-position: 98% -52px;
|
||||
}
|
||||
|
||||
#directorylist li.addressbook.readonly a,
|
||||
#directorylist li.addressbook.shared a,
|
||||
#directorylist li.addressbook.other a {
|
||||
|
|
Loading…
Add table
Reference in a new issue