summaryrefslogtreecommitdiff
path: root/program/js
diff options
context:
space:
mode:
Diffstat (limited to 'program/js')
-rw-r--r--program/js/app.js71
-rw-r--r--program/js/treelist.js226
2 files changed, 251 insertions, 46 deletions
diff --git a/program/js/app.js b/program/js/app.js
index 46d748062..97b8192b2 100644
--- a/program/js/app.js
+++ b/program/js/app.js
@@ -77,7 +77,7 @@ function rcube_webmail()
});
// unload fix
- $(window).bind('beforeunload', function() { rcmail.unload = true; });
+ $(window).bind('beforeunload', function() { ref.unload = true; });
// set environment variable(s)
this.set_env = function(p, value)
@@ -241,7 +241,7 @@ function rcube_webmail()
// load messages
this.command('list');
- $(this.gui_objects.qsearchbox).val(this.env.search_text).focusin(function() { rcmail.message_list.blur(); });
+ $(this.gui_objects.qsearchbox).val(this.env.search_text).focusin(function() { ref.message_list.blur(); });
}
this.set_button_titles();
@@ -479,7 +479,7 @@ function rcube_webmail()
case 'login':
var input_user = $('#rcmloginuser');
- input_user.bind('keyup', function(e){ return rcmail.login_user_keyup(e); });
+ input_user.bind('keyup', function(e){ return ref.login_user_keyup(e); });
if (input_user.val() == '')
input_user.focus();
@@ -499,8 +499,8 @@ function rcube_webmail()
// display 'loading' message on form submit, lock submit button
$('form').submit(function () {
$('input[type=submit]', this).prop('disabled', true);
- rcmail.clear_messages();
- rcmail.display_message('', 'loading');
+ ref.clear_messages();
+ ref.display_message('', 'loading');
});
this.enable_command('login', true);
@@ -1376,7 +1376,7 @@ function rcube_webmail()
if (this.is_framed())
parent.rcmail.reload(delay);
else if (delay)
- setTimeout(function(){ rcmail.reload(); }, delay);
+ setTimeout(function() { ref.reload(); }, delay);
else if (window.location)
location.href = this.env.comm_path + (this.env.action ? '&_action='+this.env.action : '');
};
@@ -2525,8 +2525,8 @@ function rcube_webmail()
$('#'+r.id+' .leaf:first')
.attr('id', 'rcmexpando' + r.id)
.attr('class', (r.obj.style.display != 'none' ? 'expanded' : 'collapsed'))
- .bind('mousedown', {uid:r.uid, p:this},
- function(e) { return e.data.p.expand_message_row(e, e.data.uid); });
+ .bind('mousedown', {uid: r.uid},
+ function(e) { return ref.expand_message_row(e, e.data.uid); });
r.unread_children = 0;
roots.push(r);
@@ -3633,8 +3633,8 @@ function rcube_webmail()
else if ((ed = this.env.spellcheck) && ed.state)
active = ed.state != 'ready' && ed.state != 'no_error_found';
- if (rcmail.buttons.spellcheck)
- $('#'+rcmail.buttons.spellcheck[0].id)[active ? 'addClass' : 'removeClass']('selected');
+ if (this.buttons.spellcheck)
+ $('#'+this.buttons.spellcheck[0].id)[active ? 'addClass' : 'removeClass']('selected');
return active;
};
@@ -3709,12 +3709,13 @@ function rcube_webmail()
this.auto_save_start = function()
{
- if (this.env.draft_autosave)
+ if (this.env.draft_autosave) {
this.draft_autosave_submit = false;
this.save_timer = setTimeout(function(){
ref.draft_autosave_submit = true; // set auto-saved flag (#1489789)
ref.command("savedraft");
}, this.env.draft_autosave * 1000);
+ }
// save compose form content to local storage every 5 seconds
if (!this.local_save_timer && window.localStorage) {
@@ -4065,17 +4066,17 @@ function rcube_webmail()
} else if (this.contentWindow) {
d = this.contentWindow.document;
}
- content = d.childNodes[0].innerHTML;
+ content = d.childNodes[1].innerHTML;
} catch (err) {}
- if (!content.match(/add2attachment/) && (!bw.opera || (rcmail.env.uploadframe && rcmail.env.uploadframe == e.data.ts))) {
+ if (!content.match(/add2attachment/) && (!bw.opera || (ref.env.uploadframe && ref.env.uploadframe == e.data.ts))) {
if (!content.match(/display_message/))
- rcmail.display_message(rcmail.get_label('fileuploaderror'), 'error');
- rcmail.remove_from_attachment_list(e.data.ts);
+ ref.display_message(ref.get_label('fileuploaderror'), 'error');
+ ref.remove_from_attachment_list(e.data.ts);
}
// Opera hack: handle double onload
if (bw.opera)
- rcmail.env.uploadframe = e.data.ts;
+ ref.env.uploadframe = e.data.ts;
});
// display upload indicator and cancel button
@@ -4160,7 +4161,7 @@ function rcube_webmail()
this.upload_progress_start = function(action, name)
{
- setTimeout(function() { rcmail.http_request(action, {_progress: name}); },
+ setTimeout(function() { ref.http_request(action, {_progress: name}); },
this.env.upload_progress_time * 1000);
};
@@ -4230,7 +4231,7 @@ function rcube_webmail()
};
// build URL params for search
- this.search_params = function(search, filter, smods)
+ this.search_params = function(search, filter)
{
var n, url = {}, mods_arr = [],
mods = this.env.search_mods,
@@ -4249,7 +4250,7 @@ function rcube_webmail()
if (search) {
url._q = search;
- if (!smods && mods && this.message_list)
+ if (mods && this.message_list)
mods = mods[mbox] || mods['*'];
if (mods) {
@@ -4299,7 +4300,7 @@ function rcube_webmail()
this.set_searchmods = function(mods)
{
- var mbox = rcmail.env.mailbox,
+ var mbox = this.env.mailbox,
scope = this.env.search_scope || 'base';
if (scope == 'all')
@@ -5139,7 +5140,7 @@ function rcube_webmail()
if (!this.name_input) {
this.enable_command('list', 'listgroup', false);
this.name_input = $('<input>').attr('type', 'text').val(this.env.contactgroups['G'+this.env.source+this.env.group].name);
- this.name_input.bind('keydown', function(e){ return rcmail.add_input_keydown(e); });
+ this.name_input.bind('keydown', function(e) { return ref.add_input_keydown(e); });
this.env.group_renaming = true;
var link, li = this.get_folder_li('G'+this.env.source+this.env.group,'',true);
@@ -5180,7 +5181,7 @@ function rcube_webmail()
if (!this.name_input) {
this.name_input = $('<input>').attr('type', 'text').data('tt', type);
- this.name_input.bind('keydown', function(e){ return rcmail.add_input_keydown(e); });
+ this.name_input.bind('keydown', function(e) { return ref.add_input_keydown(e); });
this.name_input_li = $('<li>').addClass(type).append(this.name_input);
var ul, li;
@@ -5283,7 +5284,7 @@ function rcube_webmail()
var key = 'G'+prop.source+prop.id,
link = $('<a>').attr('href', '#')
.attr('rel', prop.source+':'+prop.id)
- .click(function() { return rcmail.command('listgroup', prop, this); })
+ .click(function() { return ref.command('listgroup', prop, this); })
.html(prop.name);
this.env.contactfolders[key] = this.env.contactgroups[key] = prop;
@@ -5318,7 +5319,7 @@ function rcube_webmail()
newnode.id = newkey;
newnode.html = $('<a>').attr('href', '#')
.attr('rel', prop.source+':'+prop.newid)
- .click(function() { return rcmail.command('listgroup', newprop, this); })
+ .click(function() { return ref.command('listgroup', newprop, this); })
.html(prop.name);
}
// update displayed group name
@@ -5495,7 +5496,7 @@ function rcube_webmail()
{
if (form && form.elements._photo.value) {
this.async_upload_form(form, 'upload-photo', function(e) {
- rcmail.set_busy(false, null, rcmail.file_upload_id);
+ ref.set_busy(false, null, ref.file_upload_id);
});
// display upload indicator
@@ -5560,7 +5561,7 @@ function rcube_webmail()
var key = 'S'+id,
link = $('<a>').attr('href', '#')
.attr('rel', id)
- .click(function() { return rcmail.command('listsearch', id, this); })
+ .click(function() { return ref.command('listsearch', id, this); })
.html(name),
prop = { name:name, id:id };
@@ -6144,14 +6145,14 @@ function rcube_webmail()
elm._command = cmd;
elm._id = prop.id;
if (prop.sel) {
- elm.onmousedown = function(e){ return rcmail.button_sel(this._command, this._id); };
- elm.onmouseup = function(e){ return rcmail.button_out(this._command, this._id); };
+ elm.onmousedown = function(e) { return ref.button_sel(this._command, this._id); };
+ elm.onmouseup = function(e) { return ref.button_out(this._command, this._id); };
if (preload)
new Image().src = prop.sel;
}
if (prop.over) {
- elm.onmouseover = function(e){ return rcmail.button_over(this._command, this._id); };
- elm.onmouseout = function(e){ return rcmail.button_out(this._command, this._id); };
+ elm.onmouseover = function(e) { return ref.button_over(this._command, this._id); };
+ elm.onmouseout = function(e) { return ref.button_out(this._command, this._id); };
if (preload)
new Image().src = prop.over;
}
@@ -6682,7 +6683,7 @@ function rcube_webmail()
$(elem).removeClass('show-headers').addClass('hide-headers');
$(this.gui_objects.all_headers_row).show();
- elem.onclick = function() { rcmail.command('hide-headers', '', elem); };
+ elem.onclick = function() { ref.command('hide-headers', '', elem); };
// fetch headers only once
if (!this.gui_objects.all_headers_box.innerHTML) {
@@ -6700,7 +6701,7 @@ function rcube_webmail()
$(elem).removeClass('hide-headers').addClass('show-headers');
$(this.gui_objects.all_headers_row).hide();
- elem.onclick = function() { rcmail.command('show-headers', '', elem); };
+ elem.onclick = function() { ref.command('show-headers', '', elem); };
};
// create folder selector popup, position and display it
@@ -7705,7 +7706,7 @@ function rcube_webmail()
$(elem).parent().find('.mailtoprotohandler-status').html(status);
}
else {
- $(elem).click(function() { rcmail.register_protocol_handler(name); return false; });
+ $(elem).click(function() { ref.register_protocol_handler(name); return false; });
}
}
};
@@ -7744,8 +7745,8 @@ function rcube_webmail()
{
var img = new Image();
- img.onload = function() { rcmail.env.browser_capabilities.tif = 1; };
- img.onerror = function() { rcmail.env.browser_capabilities.tif = 0; };
+ img.onload = function() { ref.env.browser_capabilities.tif = 1; };
+ img.onerror = function() { ref.env.browser_capabilities.tif = 0; };
img.src = 'program/resources/blank.tif';
};
diff --git a/program/js/treelist.js b/program/js/treelist.js
index 353eb6be7..85d8aa928 100644
--- a/program/js/treelist.js
+++ b/program/js/treelist.js
@@ -44,6 +44,7 @@ function rcube_treelist_widget(node, p)
scroll_delay: 500,
scroll_step: 5,
scroll_speed: 20,
+ save_state: false,
check_droptarget: function(node){ return !node.virtual }
}, p || {});
@@ -52,6 +53,8 @@ function rcube_treelist_widget(node, p)
indexbyid = {},
selection = null,
drag_active = false,
+ search_active = false,
+ last_search = '',
box_coords = {},
item_coords = [],
autoexpand_timer,
@@ -59,6 +62,9 @@ function rcube_treelist_widget(node, p)
body_scroll_top = 0,
list_scroll_top = 0,
scroll_timer,
+ searchfield,
+ tree_state,
+ list_id = (container.attr('id') || p.id_prefix || '0'),
me = this;
@@ -77,6 +83,7 @@ function rcube_treelist_widget(node, p)
this.insert = insert;
this.remove = remove;
this.get_item = get_item;
+ this.get_node = get_node;
this.get_selection = get_selection;
/////// startup code (constructor)
@@ -105,6 +112,43 @@ function rcube_treelist_widget(node, p)
}
});
+ // activate search function
+ if (p.searchbox) {
+ searchfield = $(p.searchbox).on('keyup', function(e) {
+ var key = rcube_event.get_keycode(e),
+ mod = rcube_event.get_modifier(e);
+
+ switch (key) {
+ case 9: // tab
+ break;
+
+ case 13: // enter
+ search(this.value, true);
+ return rcube_event.cancel(e);
+
+ case 27: // escape
+ reset_search();
+ break;
+
+ case 38: // arrow up
+ case 37: // left
+ case 39: // right
+ case 40: // arrow down
+ return; // ignore arrow keys
+
+ default:
+ search(this.value, false);
+ break;
+ }
+ }).attr('autocomplete', 'off');
+
+ // find the reset button for this search field
+ searchfield.parent().find('a.reset').click(function(e) {
+ reset_search();
+ return false;
+ })
+ }
+
/////// private methods
@@ -126,6 +170,7 @@ function rcube_treelist_widget(node, p)
}
me.triggerEvent(node.collapsed ? 'collapse' : 'expand', node);
+ save_state(id, node.collapsed);
}
}
@@ -180,9 +225,17 @@ function rcube_treelist_widget(node, p)
/**
* Return the DOM element of the list item with the given ID
*/
- function get_item(id)
+ function get_node(id)
{
- return id2dom(id).get(0);
+ return indexbyid[id];
+ }
+
+ /**
+ * Return the DOM element of the list item with the given ID
+ */
+ function get_item(id, real)
+ {
+ return id2dom(id, real).get(0);
}
/**
@@ -191,13 +244,26 @@ function rcube_treelist_widget(node, p)
function insert(node, parent_id, sort)
{
var li, parent_li,
- parent_node = parent_id ? indexbyid[parent_id] : null;
+ parent_node = parent_id ? indexbyid[parent_id] : null
+ search_ = search_active;
+
+ // ignore, already exists
+ if (indexbyid[node.id]) {
+ return;
+ }
+
+ // apply saved state
+ state = get_state(node.id, node.collapsed);
+ if (state !== undefined) {
+ node.collapsed = state;
+ }
// insert as child of an existing node
if (parent_node) {
if (!parent_node.children)
parent_node.children = [];
+ search_active = false;
parent_node.children.push(node);
parent_li = id2dom(parent_id);
@@ -210,6 +276,21 @@ function rcube_treelist_widget(node, p)
// append new node to parent's child list
li = render_node(node, parent_li.children('ul').first());
}
+
+ // list is in search mode
+ if (search_) {
+ search_active = search_;
+
+ // add clone to current search results (top level)
+ if (!li.is(':visible')) {
+ $('<li>')
+ .attr('id', li.attr('id') + '--xsR')
+ .attr('class', li.attr('class'))
+ .addClass('searchresult__')
+ .append(li.children().first().clone(true, true))
+ .appendTo(container);
+ }
+ }
}
// insert at top level
else {
@@ -276,7 +357,7 @@ function rcube_treelist_widget(node, p)
if (sibling) {
li.insertAfter(sibling);
}
- else if (first.id != myid) {
+ else if (first && first.id != myid) {
li.insertBefore(first);
}
@@ -292,7 +373,7 @@ function rcube_treelist_widget(node, p)
var node, li;
if (node = indexbyid[id]) {
- li = id2dom(id);
+ li = id2dom(id, true);
li.remove();
node.deleted = true;
@@ -335,6 +416,80 @@ function rcube_treelist_widget(node, p)
drag_active = false;
container.html('');
+
+ reset_search();
+ }
+
+ /**
+ *
+ */
+ function search(q, enter)
+ {
+ q = String(q).toLowerCase();
+
+ if (!q.length)
+ return reset_search();
+ else if (q == last_search && !enter)
+ return 0;
+
+ var hits = [];
+ var search_tree = function(items) {
+ $.each(items, function(i, node) {
+ var li, sli;
+ if (!node.virtual && !node.deleted && String(node.text).toLowerCase().indexOf(q) >= 0 && hits.indexOf(node.id) < 0) {
+ li = id2dom(node.id);
+ sli = $('<li>')
+ .attr('id', li.attr('id') + '--xsR')
+ .attr('class', li.attr('class'))
+ .addClass('searchresult__')
+ .append(li.children().first().clone(true, true))
+ .appendTo(container);
+ hits.push(node.id);
+ }
+
+ if (node.children && node.children.length) {
+ search_tree(node.children);
+ }
+ });
+ };
+
+ // reset old search results
+ if (search_active) {
+ $(container).children('li.searchresult__').remove();
+ search_active = false;
+ }
+
+ // hide all list items
+ $(container).children('li').hide().removeClass('selected');
+
+ // search recursively in tree (to keep sorting order)
+ search_tree(data);
+ search_active = true;
+ last_search = q;
+
+ me.triggerEvent('search', { query: q, last: last_search, count: hits.length, ids: hits, execute: enter||false });
+
+ return hits.count;
+ }
+
+ /**
+ *
+ */
+ function reset_search()
+ {
+ if (searchfield)
+ searchfield.val('');
+
+ $(container).children('li.searchresult__').remove();
+ $(container).children('li').show();
+
+ search_active = false;
+
+ me.triggerEvent('search', { query: false, last: last_search });
+ last_search = '';
+
+ if (selection)
+ select(selection);
}
/**
@@ -378,6 +533,9 @@ function rcube_treelist_widget(node, p)
else if (typeof node.html == 'object')
li.append(node.html);
+ if (!node.text)
+ node.text = li.children().first().text();
+
if (node.virtual)
li.addClass('virtual');
if (node.id == selection)
@@ -406,12 +564,13 @@ function rcube_treelist_widget(node, p)
{
var result = [];
ul.children('li').each(function(i,e){
- var li = $(e), sublist = li.children('ul');
+ var state, li = $(e), sublist = li.children('ul');
var node = {
id: dom2id(li),
- classes: li.attr('class').split(' '),
+ classes: String(li.attr('class')).split(' '),
virtual: li.hasClass('virtual'),
html: li.children().first().get(0).outerHTML,
+ text: li.children().first().text(),
children: walk_list(sublist)
}
@@ -420,6 +579,16 @@ function rcube_treelist_widget(node, p)
}
if (node.children.length) {
node.collapsed = sublist.css('display') == 'none';
+
+ // apply saved state
+ state = get_state(node.id, node.collapsed);
+ if (state !== undefined) {
+ node.collapsed = state;
+ sublist[(state?'hide':'show')]();
+ }
+
+ if (!li.children('div.treetoggle').length)
+ $('<div class="treetoggle '+(node.collapsed ? 'collapsed' : 'expanded') + '">&nbsp;</div>').appendTo(li);
}
if (li.hasClass('selected')) {
selection = node.id;
@@ -450,17 +619,18 @@ function rcube_treelist_widget(node, p)
*/
function dom2id(li)
{
- var domid = li.attr('id').replace(new RegExp('^' + (p.id_prefix) || '%'), '');
+ var domid = li.attr('id').replace(new RegExp('^' + (p.id_prefix) || '%'), '').replace(/--xsR$/, '');
return p.id_decode ? p.id_decode(domid) : domid;
}
/**
* Get the <li> element for the given node ID
*/
- function id2dom(id)
+ function id2dom(id, real)
{
- var domid = p.id_encode ? p.id_encode(id) : id;
- return $('#' + p.id_prefix + domid);
+ var domid = p.id_encode ? p.id_encode(id) : id,
+ suffix = search_active && !real ? '--xsR' : '';
+ return $('#' + p.id_prefix + domid + suffix, container);
}
/**
@@ -476,6 +646,40 @@ function rcube_treelist_widget(node, p)
scroller.scrollTop(rel_offset + current_offset);
}
+ /**
+ * Save node collapse state to localStorage
+ */
+ function save_state(id, collapsed)
+ {
+ if (p.save_state && window.rcmail) {
+ var key = 'treelist-' + list_id;
+ if (!tree_state) {
+ tree_state = rcmail.local_storage_get_item(key, {});
+ }
+
+ if (tree_state[id] != collapsed) {
+ tree_state[id] = collapsed;
+ rcmail.local_storage_set_item(key, tree_state);
+ }
+ }
+ }
+
+ /**
+ * Read node collapse state from localStorage
+ */
+ function get_state(id)
+ {
+ if (p.save_state && window.rcmail) {
+ if (!tree_state) {
+ tree_state = rcmail.local_storage_get_item('treelist-' + list_id, {});
+ }
+ return tree_state[id];
+ }
+
+ return undefined;
+ }
+
+
///// drag & drop support
/**