treelist.min.js 13.9 KB
/**
 * Roundcube Treelist Widget
 *
 * This file is part of the Roundcube Webmail client
 *
 * @licstart  The following is the entire license notice for the
 * JavaScript code in this file.
 *
 * Copyright (c) The Roundcube Dev Team
 *
 * The JavaScript code in this page is free software: you can
 * redistribute it and/or modify it under the terms of the GNU
 * General Public License (GNU GPL) as published by the Free Software
 * Foundation, either version 3 of the License, or (at your option)
 * any later version.  The code is distributed WITHOUT ANY WARRANTY;
 * without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE.  See the GNU GPL for more details.
 *
 * As additional permission under GNU GPL version 3 section 7, you
 * may distribute non-source (e.g., minimized or compacted) forms of
 * that code without the copy of the GNU GPL normally required by
 * section 4, provided you include this license notice and a URL
 * through which recipients can access the Corresponding Source.
 *
 * @licend  The above is the entire license notice
 * for the JavaScript code in this file.
 *
 * @author Thomas Bruederli <roundcube@gmail.com>
 * @requires jquery.js, common.js
 */
function rcube_treelist_widget(e,s){s=$.extend({id_prefix:"",autoexpand:1e3,selectable:!1,scroll_delay:500,scroll_step:5,scroll_speed:20,save_state:!1,keyboard:!0,tabexit:!0,parent_focus:!1,check_droptarget:function(e){return!e.virtual}},s||{});var d,c,l,t,o,u,r,i,n,f=$(e),a=s.data||[],p={},h=null,g=!1,v=!1,_="",m=!1,x={},b=[],y=0,T=0,w=f.attr("id")||s.id_prefix||"0",C=this;function E(e,t,r){var i,n,l;if(i=p[e]){if(i.collapsed=void 0===r||r,(l=F((n=i).id,!0)).attr("aria-expanded",n.collapsed?"false":"true"),l.children("ul").first()[n.collapsed?"hide":"show"](),l.children("div.treetoggle").removeClass("collapsed expanded").addClass(n.collapsed?"collapsed":"expanded"),C.triggerEvent("toggle",n),t&&i.children)for(var a=0;a<i.children.length;a++)E(i.children[a].id,t,r);C.triggerEvent(i.collapsed?"collapse":"expand",i),function(e,t){{var r;s.save_state&&window.rcmail&&(r="treelist-"+w,(o=o||rcmail.local_storage_get_item(r,{}))[e]!=t&&(o[e]=t,rcmail.local_storage_set_item(r,o)))}}(e,i.collapsed)}}function k(e,t){E(e,t,!1)}function L(e,t){var r;(r=p[e])&&E(e,t,!r.collapsed)}function A(e){var t;!1!==C.triggerEvent("beforeselect",p[e])&&(h&&(F(h,!0).removeClass("selected").removeAttr("aria-selected"),v&&F(h).removeClass("selected").removeAttr("aria-selected"),h=null),e&&((t=F(e,!0)).length&&(t.addClass("selected").attr("aria-selected","true"),h=e,v&&F(e).addClass("selected").attr("aria-selected","true"),I(t)),C.triggerEvent("select",p[e])))}function S(){return h}function R(e,t){return F(e,t).get(0)}function H(e,t){var r,i,n=e.get(0).id,l=e.children().first().text().toUpperCase();e.parent().children("li"+t).each(function(e,t){if(0==e&&(r=t),t.id!=n){if(!(t.id!=n&&l>=$(t).children().first().text().toUpperCase()))return!1;i=t}}),i?e.insertAfter(i):r&&r.id!=n&&e.insertBefore(r),N()}function N(){a=function l(e,a){var o=[];e.children("li").each(function(e,t){var r=$(t),i=r.children("ul"),n={id:j(r),classes:String(r.attr("class")).split(" "),virtual:r.hasClass("virtual"),level:a,html:r.children().first().get(0).outerHTML,text:r.children().first().text(),children:l(i,a+1)};i.length&&(n.childlistclass=i.attr("class")),n.children.length&&(void 0===n.collapsed&&(n.collapsed="none"==i.css("display")),void 0!==(t=U(n.id,n.collapsed))&&(n.collapsed=t,i[t?"hide":"show"]()),r.children("div.treetoggle").length||$('<div class="treetoggle '+(n.collapsed?"collapsed":"expanded")+'">&nbsp;</div>').appendTo(r),r.attr("aria-expanded",n.collapsed?"false":"true")),r.hasClass("selected")&&(r.attr("aria-selected","true"),h=n.id),r.data("id",n.id),r.attr("role","treeitem").attr("aria-level",n.level+1),n.virtual&&r.children("a").first().attr("tabindex","0"),o.push(n),p[n.id]=n});e.attr("role",0==a?"tree":"group");return o}(f,0)}function O(i,e){if(!(i=String(i).toLowerCase()).length)return P(),0;if(i!=_||e){function n(e){$.each(e,function(e,t){var r;if(!t.virtual&&!t.deleted&&0<=String(t.text).toLowerCase().indexOf(i)&&l.indexOf(t.id)<0){if((r=F(t.id)).data("filtered"))return;r=$("<li>").attr("id",r.attr("id")+"--xsR").attr("class",r.attr("class")).addClass("searchresult__").append(r.children(":not(div.treetoggle,ul)").clone(!0,!0)).appendTo(f),rcmail.triggerEvent("clonerow",{id:t.id,row:r.get(0)}),l.push(t.id)}t.children&&t.children.length&&n(t.children)})}var l=[];return v&&($(f).children("li.searchresult__").remove(),v=!1),$(f).children("li").hide().removeClass("selected"),n(a),v=!0,C.triggerEvent("search",{query:i,last:_,count:l.length,ids:l,execute:e||!1}),_=i,l.count}}function P(e){t&&t.val(""),$(f).children("li.searchresult__").remove(),$(f).children("li").filter(function(){return!$(this).data("filtered")}).show(),v=!1,C.triggerEvent("search",{query:!1,last:_}),_="",h&&!e&&A(h)}function Y(e,t,r){if(!e.deleted){var i=$("<li>").attr("id",s.id_prefix+(s.id_encode?s.id_encode(e.id):e.id)).attr("role","treeitem").addClass((e.classes||[]).join(" ")).data("id",e.id);if(r?(r.replaceWith(i),t&&i.appendTo(t)):i.appendTo(t),"string"==typeof e.html?i.html(e.html):"object"==typeof e.html&&i.append(e.html),e.text||(e.text=i.children().first().text()),e.virtual&&i.addClass("virtual"),e.id==h&&i.addClass("selected"),e.children&&e.children.length){i.attr("aria-expanded",e.collapsed?"false":"true"),$('<div class="treetoggle '+(e.collapsed?"collapsed":"expanded")+'">&nbsp;</div>').appendTo(i);var n=$("<ul>").appendTo(i).attr("class",e.childlistclass).attr("role","group");e.collapsed&&n.hide();for(var l=0;l<e.children.length;l++)e.children[l].level=e.level+1,Y(e.children[l],n)}return i}}function j(e){e=String(e.attr("id")).replace(new RegExp("^"+s.id_prefix||"%"),"").replace(/--xsR$/,"");return s.id_decode?s.id_decode(e):e}function F(e,t){e=s.id_encode?s.id_encode(e):e,t=v&&!t?"--xsR":"";return $("#"+s.id_prefix+e+t,f)}function I(e){var t=f.parent(),r=t.scrollTop(),i=e.offset().top-t.offset().top;(i<0||i+e.height()>t.height())&&t.scrollTop(i+r)}function U(e){if(s.save_state&&window.rcmail)return(o=o||rcmail.local_storage_get_item("treelist-"+w,{}))[e]}function q(e){if(e||!g){g=!0;var t,r,i,n=f.offset();for(i in y=bw.ie?0:window.pageYOffset,T=f.parent().scrollTop(),n.top+=T,x={x1:n.left,y1:n.top,x2:n.left+f.width(),y2:n.top+f.height()},b=[],p)(t=F(i).children().first().get(0))&&(r=t.offsetHeight)&&((n=$(t).offset()).top+=T,b[i]={x1:n.left,y1:n.top,x2:n.left+t.offsetWidth,y2:n.top+r,on:i==c});f.height()>f.parent().height()&&f.parent().on("mousemove.treelist",function(e){var t=0,e=rcube_event.get_mouse_pos(e);e.y-=f.parent().offset().top,e.y<25&&0<T?t=-1:e.y>f.parent().height()-25&&(t=1),g&&0!=t?l=l||setTimeout(function(){!function e(t){if(!g)return;var r=T;f.parent().get(0).scrollTop+=s.scroll_step*t;T=f.parent().scrollTop();l=null;T!=r&&(l=setTimeout(function(){e(t)},s.scroll_speed))}(t)},s.scroll_delay):l&&(window.clearTimeout(l),l=null)}).on("mouseleave.treelist",function(){l&&(window.clearTimeout(l),l=null)})}}function B(){f.parent().off(".treelist"),$("li.droptarget",f).removeClass("droptarget"),g&&(g=!1,l=null,d&&(clearTimeout(d),c=d=null))}function K(e,t){var r,i,n,l=bw.ie?-document.documentElement.scrollTop:y,a=f.parent().scrollTop(),o=null;if(e.top=e.y+a-l,e.x<x.x1||e.x>=x.x2||e.top<x.y1||e.top>=x.y2)return t&&$("li.droptarget",f).removeClass("droptarget"),o;for(r in b)i=b[r],e.x>=i.x1&&e.x<i.x2&&e.top>=i.y1&&e.top<i.y2?((n=p[r]).children&&n.children.length&&n.collapsed&&s.autoexpand&&c!=r?(d&&clearTimeout(d),c=r,d=setTimeout(function(){k(c),q(!0),c=null,u&&$.ui.ddmanager.prepareOffsets($.ui.ddmanager.current,null)},s.autoexpand)):d&&c!=r&&(clearTimeout(d),d=c=null),o=s.check_droptarget(n)?(t&&(F(r).addClass("droptarget"),i.on=!0),r):null):i.on&&(F(r).removeClass("droptarget"),i.on=!1);return o}function W(r){if(r=r||{},"string"==$.type(r))return"destroy"==r&&(u=null),$("li:not(.virtual)",f).droppable(r),this;n=r;var e=$.extend({greedy:!0,tolerance:"pointer",hoverClass:"droptarget",addClasses:!1},r);return e.activate=function(e,t){q(),u=t,r.activate&&r.activate(e,t)},e.deactivate=function(e,t){B(),u=null,r.deactivate&&r.deactivate(e,t)},e.over=function(e,t){K(rcube_event.get_mouse_pos(e),!1),r.over&&r.over(e,t)},$("li:not(.virtual)",f).droppable(e),this}function D(e){if(e=e||{},"string"==$.type(e))return"destroy"==e&&(r=null),$("li:not(.virtual)",f).draggable(e),this;i=e;e=$.extend({appendTo:"body",revert:"invalid",iframeFix:!0,addClasses:!1,cursorAt:{left:-20,top:5},create:function(e,t){r=t},helper:function(e){return $("<div>").attr("id","rcmdraglayer").text($(e.target).first().text().trim())}},e);return $("li:not(.virtual)",f).draggable(e),this}this.container=f,this.expand=k,this.collapse=E,this.expand_all=function(){$.each(p,function(e,t){0<t.children.length&&t.collapsed&&E(e,!1,!1)})},this.collapse_all=function(){$.each(p,function(e,t){0<t.children.length&&!t.collapsed&&E(e)})},this.select=A,this.render=function(){if(!1!==C.triggerEvent("renderBefore",a)){f.html("");for(var e=0;e<a.length;e++)a[e].level=0,Y(a[e],f);C.triggerEvent("renderAfter",f)}},this.reset=function(e,t){t||A("");a=[],g=!(p={}),e?(i&&(r&&D("destroy"),D(i)),n&&(u&&W("destroy"),W(n)),N()):f.html("");P(t)},this.drag_start=q,this.drag_end=B,this.intersects=K,this.droppable=W,this.draggable=D,this.is_draggable=function(){return!!r},this.update=function(e,t,r){var i,n,l,a,o=p[e];o&&(i=F(e),n=i.parent(),(t.id||t.html||t.children||t.classes||t.parent)&&(t.parent&&(l=p[t.parent])?(n.closest("li").length&&(a=p[j(n.closest("li"))])&&(a.children=$.grep(a.children,function(e,t){return e.id!=o.id})),n=F(t.parent).children("ul").first(),l.children||(l.children=[]),l.children.push(o)):void 0!==t.parent&&(n=f),$.extend(o,t),i=Y(o,n,i)),o.id!=e&&(delete p[e],p[o.id]=o),r&&H(i,"string"==typeof r?'[class~="'+r+'"]':""))},this.insert=function(e,t,r){var i,n=t?p[t]:null;search_=v,p[e.id]||(state=U(e.id,e.collapsed),void 0!==state&&(e.collapsed=state),n?(e.level=n.level+1,n.children?n.children=n.children.filter(function(e){return!e.deleted}):n.children=[],v=!1,n.children.push(e),i=F(t),i=1==n.children.length?(Y(n,null,i),F(e.id)):Y(e,i.children("ul").first()),search_&&(v=search_,i.is(":visible")||$("<li>").attr("id",i.attr("id")+"--xsR").attr("class",i.attr("class")).addClass("searchresult__").append(i.children().first().clone(!0,!0)).appendTo(f))):(e.level=0,a.push(e),i=Y(e,f)),"object"==typeof(p[e.id]=e).html&&(p[e.id].html=F(e.id,!0).children()),r&&H(i,"string"==typeof r?'[class~="'+r+'"]':""))},this.remove=function(e){var t,r,i;if(t=p[e])return r=F(e,!0),i=r.parent(),r.remove(),t.deleted=!0,delete p[e],v&&F(e,!1).remove(),i.children().length||(i.parent("li").find("div.treetoggle").remove(),i[0]!=f[0]&&i.remove()),!0;return!1},this.get_item=R,this.get_node=function(e){return p[e]},this.get_selection=S,this.in_selection=function(e){return h==e},this.get_next=function(){var e,t;if(h&&(e=F(h))){if((t=e.children("ul").children("li").first()).length)return j(t);if((t=e.next()).length)return j(t);for(;(e=e.parent("ul").parent("li"))&&e.length;)if((t=e.next()).length)return j(t)}},this.get_prev=function(){var e,t,r;if(h&&(e=F(h)))return t=e.prev(),(r=t.find("li").last()).length?j(r):t.length?j(t):(e=e.parent().parent()).length&&e.is("li")?j(e):void 0},this.get_single_selection=S,this.is_search=function(){return v},this.reset_search=P,f.length&&(s.data?function e(t){t.id&&(p[t.id]=t);for(var r=0;t.children&&r<t.children.length;r++)e(t.children[r])}({children:a}):N(),h&&I(F(h,!0)),f.attr("role","tree").on("focusin",function(e){m=!0}).on("focusout",function(e){m=!1}).on("click","div.treetoggle",function(e){L(j($(this).parent())),e.stopPropagation()}).on("click","li",function(e){if($(e.target).is("input"))return!0;var t=s.selectable?p[j($(this))]:null;t&&(t.virtual||A(t.id),e.stopPropagation())}).on("mousedown","a",function(e){var t=$(e.target),r=p[j(t.closest("li"))];if(r&&r.virtual&&!t.attr("href"))return e.preventDefault(),e.stopPropagation(),!1}),s.searchbox&&(t=$(s.searchbox).off("keyup.treelist").on("keyup.treelist",function(e){var t=rcube_event.get_keycode(e);rcube_event.get_modifier(e);switch(t){case 9:break;case 13:return O(this.value,!0),rcube_event.cancel(e);case 27:P();break;case 38:case 37:case 39:case 40:return;default:O(this.value,!1)}}).attr("autocomplete","off")).parent().find("a.reset").off("click.treelist").on("click.treelist",function(e){return P(),!1}),$(document.body).on("keydown",function(e){var t=e.target||{},r=rcube_event.get_keycode(e);if(!m||"INPUT"==t.nodeName&&38!=r&&40!=r||"TEXTAREA"==t.nodeName||"SELECT"==t.nodeName)return!0;switch(r){case 38:case 40:case 63232:case 63233:return(i=s.keyboard?f.find(":focus").closest("li"):[]).length&&function e(t,r,i){var n=r<0?"prev":"next",n=t[n]();0<r&&!i&&t.children("ul[role=group]:visible").length?t.children("ul").children("li").first().find("a").first().focus():r<0&&!i&&n.children("ul[role=group]:visible").length?n.children("ul").children("li").last().find("a").first().focus():n.length&&n.find("a").first().focus().length||(t=t.parent().closest("li[role=treeitem]")).length&&(r<0?t.find("a").first().focus():e(t,r,!0))}(i,mod=38==r||63232==r?-1:1),rcube_event.cancel(e);case 37:case 39:var i;return(i=f.find(":focus").closest("li")).length&&(n=j(i),(i=p[n])&&i.children.length&&i.collapsed!=(37==r)&&L(n,rcube_event.get_modifier(e)==SHIFT_KEY)),!1;case 9:var n;s.keyboard&&s.tabexit&&(n=rcube_event.get_modifier(e)==SHIFT_KEY?"first":"last",function(e){{var t,r;e.length&&(t=f.parent().get(0)||{scrollTop:0},r=t.scrollTop||t.scrollY,e.focus(),t.scrollTop=r)}}(f.find("li[role=treeitem]:has(a)")[n]().find("a:"+n)))}return!0}),s.parent_focus&&f.parent(":not(body)").click(function(e){return!!$(e.target).is("input")||void(!m&&h?$(R(h)).find(":focusable").first().focus():m||f.children("li").find(":focusable").first().focus())}))}rcube_treelist_widget.prototype.addEventListener=rcube_event_engine.prototype.addEventListener,rcube_treelist_widget.prototype.removeEventListener=rcube_event_engine.prototype.removeEventListener,rcube_treelist_widget.prototype.triggerEvent=rcube_event_engine.prototype.triggerEvent;