Simplify assigning new tags (#4159)
Added input field to the tag selector popup which can be used to search in existing tags or to create a new one (with Enter key)
This commit is contained in:
parent
9cd590aabb
commit
c9ee78fdd9
4 changed files with 138 additions and 19 deletions
|
@ -345,6 +345,9 @@ function update_tags(response)
|
||||||
{
|
{
|
||||||
var list = rcmail.message_list;
|
var list = rcmail.message_list;
|
||||||
|
|
||||||
|
// reset tag selector popup
|
||||||
|
tag_selector_reset();
|
||||||
|
|
||||||
// remove deleted tags
|
// remove deleted tags
|
||||||
remove_tags(response['delete']);
|
remove_tags(response['delete']);
|
||||||
|
|
||||||
|
@ -352,6 +355,9 @@ function update_tags(response)
|
||||||
$.each(response.add || [], function() {
|
$.each(response.add || [], function() {
|
||||||
rcmail.env.tags.push(this);
|
rcmail.env.tags.push(this);
|
||||||
add_tag_element($('#taglist'), this, list);
|
add_tag_element($('#taglist'), this, list);
|
||||||
|
if (response.mark) {
|
||||||
|
tag_add_callback(this);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// update existing tag
|
// update existing tag
|
||||||
|
@ -396,9 +402,6 @@ function update_tags(response)
|
||||||
message_list_select(list);
|
message_list_select(list);
|
||||||
}
|
}
|
||||||
|
|
||||||
// reset tag selector popup
|
|
||||||
tag_selector_element = null;
|
|
||||||
|
|
||||||
// @TODO: sort tags by name/prio
|
// @TODO: sort tags by name/prio
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -471,17 +474,43 @@ function tag_add(props, obj, event)
|
||||||
return tag_selector(event, function(props) { rcmail.command('tag-add', props); });
|
return tag_selector(event, function(props) { rcmail.command('tag-add', props); });
|
||||||
}
|
}
|
||||||
|
|
||||||
var postdata = rcmail.selection_post_data(),
|
var tag, postdata = rcmail.selection_post_data();
|
||||||
tag = this.tag_find(props),
|
|
||||||
frame_window = rcmail.get_frame_window(rcmail.env.contentframe);
|
// requested new tag?
|
||||||
|
if (props.name) {
|
||||||
|
postdata._tag = props.name;
|
||||||
|
// find the tag by name to be sure it exists or not
|
||||||
|
if (props = tag_find(props.name, 'name')) {
|
||||||
|
postdata._tag = props.uid;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
postdata._new = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
postdata._tag = props;
|
||||||
|
}
|
||||||
|
|
||||||
postdata._tag = props;
|
|
||||||
postdata._act = 'add';
|
postdata._act = 'add';
|
||||||
|
|
||||||
rcmail.http_post('plugin.kolab_tags', postdata, true);
|
rcmail.http_post('plugin.kolab_tags', postdata, true);
|
||||||
|
|
||||||
// add tags to message(s) without waiting to a response
|
// add tags to message(s) without waiting to a response
|
||||||
// in case of an error the list will be refreshed
|
// in case of an error the list will be refreshed
|
||||||
|
// this is possible if we use existing tag
|
||||||
|
if (!postdata._new && (tag = this.tag_find(props))) {
|
||||||
|
tag_add_callback(tag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// update messages list and message frame after tagging
|
||||||
|
function tag_add_callback(tag)
|
||||||
|
{
|
||||||
|
if (!tag)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var frame_window = rcmail.get_frame_window(rcmail.env.contentframe);
|
||||||
|
|
||||||
if (rcmail.message_list) {
|
if (rcmail.message_list) {
|
||||||
$.each(rcmail.message_list.get_selection(), function (i, uid) {
|
$.each(rcmail.message_list.get_selection(), function (i, uid) {
|
||||||
var row = rcmail.message_list.rows[uid];
|
var row = rcmail.message_list.rows[uid];
|
||||||
|
@ -508,6 +537,16 @@ function tag_remove(props, obj, event)
|
||||||
return tag_selector(event, function(props) { rcmail.command('tag-remove', props); });
|
return tag_selector(event, function(props) { rcmail.command('tag-remove', props); });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (props.name) {
|
||||||
|
// find the tag by name, make sure it exists
|
||||||
|
props = tag_find(props.name, 'name');
|
||||||
|
if (!props) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
props = props.uid;
|
||||||
|
}
|
||||||
|
|
||||||
var postdata = rcmail.selection_post_data(),
|
var postdata = rcmail.selection_post_data(),
|
||||||
tags = props != '*' ? [props] : $.map(rcmail.env.tags, function(tag) { return tag.uid; })
|
tags = props != '*' ? [props] : $.map(rcmail.env.tags, function(tag) { return tag.uid; })
|
||||||
win = window.parent && parent.rcmail && parent.remove_tags ? parent : window;
|
win = window.parent && parent.rcmail && parent.remove_tags ? parent : window;
|
||||||
|
@ -602,10 +641,14 @@ function message_tags(tags, merge)
|
||||||
}
|
}
|
||||||
|
|
||||||
// return tag info by tag uid
|
// return tag info by tag uid
|
||||||
function tag_find(uid)
|
function tag_find(search, key)
|
||||||
{
|
{
|
||||||
|
if (!key) {
|
||||||
|
key = 'uid';
|
||||||
|
}
|
||||||
|
|
||||||
for (var i in rcmail.env.tags)
|
for (var i in rcmail.env.tags)
|
||||||
if (rcmail.env.tags[i].uid == uid)
|
if (rcmail.env.tags[i][key] == search)
|
||||||
return rcmail.env.tags[i];
|
return rcmail.env.tags[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -663,6 +706,9 @@ function tag_selector(event, callback)
|
||||||
link.href = '#';
|
link.href = '#';
|
||||||
link.className = 'active';
|
link.className = 'active';
|
||||||
|
|
||||||
|
// add tag search/create input
|
||||||
|
rows.push(tag_selector_search_element(container));
|
||||||
|
|
||||||
// loop over tags list
|
// loop over tags list
|
||||||
$.each(rcmail.env.tags, function(i, tag) {
|
$.each(rcmail.env.tags, function(i, tag) {
|
||||||
var a = link.cloneNode(false), row = li.cloneNode(false);
|
var a = link.cloneNode(false), row = li.cloneNode(false);
|
||||||
|
@ -697,4 +743,48 @@ function tag_selector(event, callback)
|
||||||
container.data('callback', callback);
|
container.data('callback', callback);
|
||||||
|
|
||||||
rcmail.show_menu('tag-selector', true, event);
|
rcmail.show_menu('tag-selector', true, event);
|
||||||
|
|
||||||
|
// reset list and search input
|
||||||
|
$('li', container).show();
|
||||||
|
$('input', container).val('').focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove tag selector element (e.g. after adding/removing a tag)
|
||||||
|
function tag_selector_reset()
|
||||||
|
{
|
||||||
|
$(tag_selector_element).remove();
|
||||||
|
tag_selector_element = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function tag_selector_search_element(container)
|
||||||
|
{
|
||||||
|
var input = $('<input>').attr({'type': 'text', title: rcmail.gettext('kolab_tags.tagsearchnew')})
|
||||||
|
.keyup(function(e) {
|
||||||
|
if (this.value) {
|
||||||
|
// execute action on Enter
|
||||||
|
if (e.which == 13) {
|
||||||
|
container.data('callback')({name: this.value});
|
||||||
|
rcmail.hide_menu('tag-selector', e);
|
||||||
|
if ($('#markmessagemenu').is(':visible')) {
|
||||||
|
rcmail.hide_menu('markmessagemenu', e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// search tags
|
||||||
|
else {
|
||||||
|
var search = this.value.toUpperCase();
|
||||||
|
$('li:not(.search)', container).each(function() {
|
||||||
|
var tag_name = $(this).text().toUpperCase();
|
||||||
|
$(this)[tag_name.indexOf(search) >= 0 ? 'show' : 'hide']();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// reset search
|
||||||
|
$('li', container).show();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return $('<li class="search">').append(input)
|
||||||
|
// prevents from closing the menu on click in the input/row
|
||||||
|
.mouseup(function(e) { return false; });
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,7 +54,8 @@ class kolab_tags_engine
|
||||||
$this->plugin->include_script('kolab_tags.js');
|
$this->plugin->include_script('kolab_tags.js');
|
||||||
$this->rc->output->add_label('cancel', 'save');
|
$this->rc->output->add_label('cancel', 'save');
|
||||||
$this->plugin->add_label('tags', 'add', 'edit', 'delete', 'saving',
|
$this->plugin->add_label('tags', 'add', 'edit', 'delete', 'saving',
|
||||||
'nameempty', 'nameexists', 'colorinvalid', 'untag', 'tagname', 'tagcolor');
|
'nameempty', 'nameexists', 'colorinvalid', 'untag', 'tagname',
|
||||||
|
'tagcolor', 'tagsearchnew');
|
||||||
|
|
||||||
$this->rc->output->add_handlers(array(
|
$this->rc->output->add_handlers(array(
|
||||||
'plugin.taglist' => array($this, 'taglist'),
|
'plugin.taglist' => array($this, 'taglist'),
|
||||||
|
@ -199,8 +200,6 @@ class kolab_tags_engine
|
||||||
public function action_add()
|
public function action_add()
|
||||||
{
|
{
|
||||||
$tag = rcube_utils::get_input_value('_tag', rcube_utils::INPUT_POST);
|
$tag = rcube_utils::get_input_value('_tag', rcube_utils::INPUT_POST);
|
||||||
$filter = array(array('uid', '=', explode(',', $tag)));
|
|
||||||
$taglist = $this->backend->list_tags($filter);
|
|
||||||
$storage = $this->rc->get_storage();
|
$storage = $this->rc->get_storage();
|
||||||
$members = array();
|
$members = array();
|
||||||
|
|
||||||
|
@ -218,24 +217,45 @@ class kolab_tags_engine
|
||||||
$members = array_merge($members, $this->build_members($mbox, $msgs));
|
$members = array_merge($members, $this->build_members($mbox, $msgs));
|
||||||
}
|
}
|
||||||
|
|
||||||
// for every tag...
|
// create a new tag?
|
||||||
foreach ($taglist as $tag) {
|
if (!empty($_POST['_new'])) {
|
||||||
$tag['members'] = array_unique(array_merge((array) $tag['members'], $members));
|
$object = array(
|
||||||
|
'name' => $tag,
|
||||||
|
'members' => $members,
|
||||||
|
);
|
||||||
|
|
||||||
// update tag object
|
$object = $this->backend->create($object);
|
||||||
if (!$this->backend->update($tag)) {
|
$error = $object === false;
|
||||||
$error = true;
|
}
|
||||||
|
// use existing tags (by UID)
|
||||||
|
else {
|
||||||
|
$filter = array(array('uid', '=', explode(',', $tag)));
|
||||||
|
$taglist = $this->backend->list_tags($filter);
|
||||||
|
|
||||||
|
// for every tag...
|
||||||
|
foreach ($taglist as $tag) {
|
||||||
|
$tag['members'] = array_unique(array_merge((array) $tag['members'], $members));
|
||||||
|
|
||||||
|
// update tag object
|
||||||
|
if (!$this->backend->update($tag)) {
|
||||||
|
$error = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($error) {
|
if ($error) {
|
||||||
|
$this->rc->output->show_message($this->plugin->gettext('taggingerror'), 'error');
|
||||||
|
|
||||||
if ($_POST['_from'] != 'show') {
|
if ($_POST['_from'] != 'show') {
|
||||||
$this->rc->output->show_message($this->plugin->gettext('taggingerror'), 'error');
|
|
||||||
$this->rc->output->command('list_mailbox');
|
$this->rc->output->command('list_mailbox');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$this->rc->output->show_message($this->plugin->gettext('taggingsuccess'), 'confirmation');
|
$this->rc->output->show_message($this->plugin->gettext('taggingsuccess'), 'confirmation');
|
||||||
|
|
||||||
|
if (isset($object)) {
|
||||||
|
$this->rc->output->command('plugin.kolab_tags', array('mark' => 1, 'add' => array($this->parse_tag($object))));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@ $labels['edit'] = 'Edit';
|
||||||
$labels['delete'] = 'Delete';
|
$labels['delete'] = 'Delete';
|
||||||
$labels['tagname'] = 'Name';
|
$labels['tagname'] = 'Name';
|
||||||
$labels['tagcolor'] = 'Color';
|
$labels['tagcolor'] = 'Color';
|
||||||
|
$labels['tagsearchnew'] = 'Enter text to search or create a new tag';
|
||||||
$labels['nameempty'] = 'Tag name cannot be empty!';
|
$labels['nameempty'] = 'Tag name cannot be empty!';
|
||||||
$labels['nameexists'] = 'Tag with specified name already exists!';
|
$labels['nameexists'] = 'Tag with specified name already exists!';
|
||||||
$labels['colorinvalid'] = 'Invalid color specification!';
|
$labels['colorinvalid'] = 'Invalid color specification!';
|
||||||
|
|
|
@ -125,3 +125,11 @@ ul.toolbarmenu li span.icon.tagremoveall {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#tag-selector li.search {
|
||||||
|
padding: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#tag-selector li.search input {
|
||||||
|
width: 120px;
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue