/* +-----------------------------------------------------------------------+ | Roundcube Treelist widget | | | | This file is part of the Roundcube Webmail client | | Copyright (C) 2013, The Roundcube Dev Team | | | | Licensed under the GNU General Public License version 3 or | | any later version with exceptions for skins & plugins. | | See the README file for a full license statement. | | | +-----------------------------------------------------------------------+ | Authors: Thomas Bruederli | +-----------------------------------------------------------------------+ | Requires: common.js | +-----------------------------------------------------------------------+ */ /** * Roundcube Treelist widget class * @contructor */ function rcube_treelist_widget(node, p) { // apply some defaults to p p = $.extend({ id_prefix: '', autoexpand: 1000, selectable: false, check_droptarget: function(node){ return !node.virtual } }, p || {}); var container = $(node); var data = p.data || []; var indexbyid = {}; var selection = null; var drag_active = false; var box_coords = {}; var item_coords = []; var autoexpand_timer; var autoexpand_item; var body_scroll_top = 0; var list_scroll_top = 0; var me = this; /////// export public members and methods this.container = container; this.expand = expand; this.collapse = collapse; this.select = select; this.render = render; this.drag_start = drag_start; this.drag_end = drag_end; this.intersects = intersects; /////// startup code (constructor) // abort if node not found if (!container.length) return; if (p.data) { index_data({ children:data }); } // load data from DOM else { data = walk_list(container); // console.log(data); } // register click handlers on list container.on('click', 'div.treetoggle', function(e){ toggle(dom2id($(this).parent())); }); container.on('click', 'li', function(e){ var node = p.selectable ? indexbyid[dom2id($(this))] : null; if (node && !node.virtual) { select(node.id); e.stopPropagation(); } }); /////// private methods /** * Collaps a the node with the given ID */ function collapse(id, recursive, set) { var node; if (node = indexbyid[id]) { node.collapsed = typeof set == 'undefined' || set; update_dom(node); // Work around a bug in IE6 and IE7, see #1485309 if (window.bw && (bw.ie6 || bw.ie7) && node.collapsed) { id2dom(node.id).next().children('ul:visible').hide().show(); } if (recursive && node.children) { for (var i=0; i < node.children.length; i++) { collapse(node.children[i].id, recursive, set); } } me.triggerEvent(node.collapsed ? 'collapse' : 'expand', node); } } /** * Expand a the node with the given ID */ function expand(id, recursive) { collapse(id, recursive, false); } /** * Toggle collapsed state of a list node */ function toggle(id, recursive) { var node; if (node = indexbyid[id]) { collapse(id, recursive, !node.collapsed); } } /** * Select a tree node by it's ID */ function select(id) { if (selection) { id2dom(selection).removeClass('selected'); selection = null; } var li = id2dom(id); if (li.length) { li.addClass('selected'); selection = id; // TODO: expand all parent nodes if collapsed scroll_to_node(li); } me.triggerEvent('select', indexbyid[id]); } /** * Getter for the currently selected node ID */ function get_selection() { return selection; } /** * Return the DOM element of the list item with the given ID */ function get_item(id) { return id2dom(id).get(0); } /** * Apply the 'collapsed' status of the data node to the corresponding DOM element(s) */ function update_dom(node) { var li = id2dom(node.id); li.children('ul').first()[(node.collapsed ? 'hide' : 'show')](); li.children('div.treetoggle').removeClass('collapsed expanded').addClass(node.collapsed ? 'collapsed' : 'expanded'); me.triggerEvent('toggle', node); } /** * Render the tree list from the internal data structure */ function render() { if (me.triggerEvent('renderBefore', data) === false) return; // remove all child nodes container.html(''); // render child nodes for (var i=0; i < data.length; i++) { render_node(data[i], container); } me.triggerEvent('renderAfter', container); } /** * Render a specific node into the DOM list */ function render_node(node, parent) { var li = $('
  • ' + node.html + '
  • ') .attr('id', p.id_prefix + node.id) .addClass((node.classes || []).join(' ')) .appendTo(parent); if (node.virtual) li.addClass('virtual'); if (node.id == selection) li.addClass('selected'); // add child list and toggle icon if (node.children && node.children.length) { $('
     
    ').appendTo(li); var ul = $('