diff options
Diffstat (limited to 'program/js')
-rw-r--r-- | program/js/app.js | 71 | ||||
-rw-r--r-- | program/js/treelist.js | 226 |
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') + '"> </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 /** |