galaxy-dist commit 49f0e8441a4d: sample tracking
# HG changeset patch -- Bitbucket.org # Project galaxy-dist # URL http://bitbucket.org/galaxy/galaxy-dist/overview # User rc # Date 1288760547 14400 # Node ID 49f0e8441a4da6b1ec03250448ab84854f07aa77 # Parent 37477f7d10e7407186bd189fdec9e114e4b8f3d2 sample tracking - new file browser for selecting datasets in the sequencer --- a/templates/admin/requests/get_data.mako +++ b/templates/admin/requests/get_data.mako @@ -1,71 +1,71 @@ <%inherit file="/base.mako"/><%namespace file="/message.mako" import="render_msg" /> +${h.js( "ui.core", "jquery.cookie" )} +<link href='/static/june_2007_style/blue/dynatree_skin/ui.dynatree.css' rel='stylesheet' type='text/css'> +${h.js( "jquery.dynatree" )} <script type="text/javascript"> - $(document).ready(function(){ - //hide the all of the element with class msg_body - $(".msg_body").hide(); - //toggle the component with class msg_body - $(".msg_head").click(function(){ - $(this).next(".msg_body").slideToggle(450); - }); + $(function(){ + $("#tree").ajaxComplete(function(event, XMLHttpRequest, ajaxOptions) { + _log("debug", "ajaxComplete: %o", this); // dom element listening + }); + // --- Initialize sample trees + $("#tree").dynatree({ + title: "${request.type.datatx_info['data_dir']}", + rootVisible: true, + minExpandLevel: 0, // 1: root node is not collapsible + persist: false, + checkbox: true, + selectMode: 3, + onPostInit: function(isReloading, isError) { +// alert("reloading: "+isReloading+", error:"+isError); + logMsg("onPostInit(%o, %o) - %o", isReloading, isError, this); + // Re-fire onActivate, so the text is updated + this.reactivate(); + }, + fx: { height: "toggle", duration: 200 }, + // initAjax is hard to fake, so we pass the children as object array: + initAjax: {url: "${h.url_for( controller='requests_admin', action='open_folder' )}", + dataType: "json", + data: { id: "${request.id}", key: "${request.type.datatx_info['data_dir']}" }, + }, + onLazyRead: function(dtnode){ + dtnode.appendAjax({ + url: "${h.url_for( controller='requests_admin', action='open_folder' )}", + dataType: "json", + data: { id: "${request.id}", key: dtnode.data.key }, + }); + }, + onSelect: function(select, dtnode) { + // Display list of selected nodes + var selNodes = dtnode.tree.getSelectedNodes(); + // convert to title/key array + var selKeys = $.map(selNodes, function(node){ + return node.data.key; + }); + document.get_data.selected_files.value = selKeys.join(",") + }, + onActivate: function(dtnode) { + var cell = $("#file_details"); + var selected_value = dtnode.data.key + if(selected_value.charAt(selected_value.length-1) != '/') { + // Make ajax call + $.ajax( { + type: "POST", + url: "${h.url_for( controller='requests_admin', action='get_file_details' )}", + dataType: "json", + data: { id: "${request.id}", folder_path: dtnode.data.key }, + success : function ( data ) { + cell.html( '<label>'+data+'</label>' ) + } + }); + } else { + cell.html( '' ) + } + }, + }); }); - function display_file_details(request_id, folder_path) - { - var w = document.get_data.files_list.selectedIndex; - var selected_value = document.get_data.files_list.options[w].value; - var cell = $("#file_details"); - if(selected_value.charAt(selected_value.length-1) != '/') - { - // Make ajax call - $.ajax( { - type: "POST", - url: "${h.url_for( controller='requests_admin', action='get_file_details' )}", - dataType: "json", - data: { id: request_id, folder_path: document.get_data.folder_path.value + selected_value }, - success : function ( data ) { - cell.html( '<label>'+data+'</label>' ) - } - }); - } - else - { - cell.html( '' ) - } - } - - function open_folder1( request_id, folder_path ) - { - var w = document.get_data.files_list.selectedIndex; - var selected_value = document.get_data.files_list.options[w].value; - var cell = $("#file_details"); - if(selected_value.charAt(selected_value.length-1) == '/') - { - document.get_data.folder_path.value = document.get_data.folder_path.value+selected_value - // Make ajax call - $.ajax( { - type: "POST", - url: "${h.url_for( controller='requests_admin', action='open_folder' )}", - dataType: "json", - data: { id: request_id, folder_path: document.get_data.folder_path.value }, - success : function ( data ) { - document.get_data.files_list.options.length = 0 - for(i=0; i<data.length; i++) - { - var newOpt = new Option(data[i], data[i]); - document.get_data.files_list.options[i] = newOpt; - } - //cell.html( '<label>'+data+'</label>' ) - - } - }); - } - else - { - cell.html( '' ) - } - } </script><br/> @@ -92,18 +92,16 @@ <div class="toolParamHelp" style="clear: both;"> Select the sample with which you want to associate the datasets </div> - <br/> - <label>Folder path on the sequencer:</label> - <input type="text" name="folder_path" value="${folder_path}" size="100"/> - <input type="submit" name="browse_button" value="List contents"/> - <input type="submit" name="folder_up" value="Up"/></div> - <div class="form-row"> - <select name="files_list" id="files_list" style="max-width: 60%; width: 98%; height: 150px; font-size: 100%;" ondblclick="open_folder1(${request.id}, '${folder_path}')" onChange="display_file_details(${request.id}, '${folder_path}')" multiple> - %for index, f in enumerate( files ): - <option value="${f}">${f}</option> - %endfor - </select> + <div class="form-row" > + <label>Select dataset files in the sequencer:</label> + <div id="tree" > + Loading... + </div> + <input id="selected_files" name="selected_files" type="hidden" size=40"/> + <div class="toolParamHelp" style="clear: both;"> + To select a folder, select all the individual files in that folder. + </div></div><div class="form-row"><div id="file_details" class="toolParamHelp" style="clear: both;background-color:#FAFAFA;"></div> Binary file static/june_2007_style/blue/dynatree_skin/rbUnchecked_hover.gif has changed Binary file static/june_2007_style/blue/dynatree_skin/cbChecked.gif has changed Binary file static/june_2007_style/blue/dynatree_skin/ltError.gif has changed Binary file static/june_2007_style/blue/dynatree_skin/cbIntermediate.gif has changed --- a/lib/galaxy/web/controllers/requests_admin.py +++ b/lib/galaxy/web/controllers/requests_admin.py @@ -316,7 +316,6 @@ class RequestsAdmin( BaseController, Use dict( controller='requests_admin', action='get_data', request_id=request_id, - folder_path=sample.request.type.datatx_info[ 'data_dir' ], sample_id=sample_id ) ), grids.GridAction( "Browse target data library", dict( controller='library_common', @@ -383,67 +382,61 @@ class RequestsAdmin( BaseController, Use request = trans.sa_session.query( trans.model.Request ).get( trans.security.decode_id( request_id ) ) except: return invalid_id_redirect( trans, 'requests_admin', request_id ) - selected_files = util.listify( params.get( 'files_list', [] ) ) - folder_path = util.restore_text( params.get( 'folder_path', request.type.datatx_info[ 'data_dir' ] ) ) + selected_files = util.restore_text( params.get( 'selected_files', '' ) ) + if len( selected_files ): + selected_files = selected_files.split(',') + else: + selected_files = [] selected_sample_id = kwd.get( 'sample_id', 'none' ) sample_id_select_field = self.__build_sample_id_select_field( trans, request, selected_sample_id ) # The __get_files() method redirects here with a status of 'error' and a message if there # was a problem retrieving the files. - if folder_path and status != 'error': - folder_path = self.__check_path( folder_path ) - if params.get( 'folder_up', False ): - if folder_path[-1] == os.sep: - folder_path = os.path.dirname( folder_path[:-1] ) - folder_path = self.__check_path( folder_path ) - elif params.get( 'open_folder', False ): - if len(selected_files) == 1: - folder_path = os.path.join(folder_path, selected_files[0]) - folder_path = self.__check_path( folder_path ) - elif params.get( 'select_show_datasets_button', False ) or params.get( 'select_more_button', False ): - # get the sample these datasets are associated with - try: - sample = trans.sa_session.query( trans.model.Sample ).get( trans.security.decode_id( selected_sample_id ) ) - except: - return invalid_id_redirect( trans, 'requests_admin', selected_sample_id ) - if sample in sample.request.samples_without_library_destinations: - # Display an error if a sample has been selected that - # has not yet been associated with a destination library. - status = 'error' - message = 'Select a sample with associated data library and folder before selecting the datasets.' - return trans.response.send_redirect( web.url_for( controller='requests_admin', - action='get_data', - request_id=request_id, - folder_path=folder_path, - status=status, - message=message ) ) - # Save the sample datasets - sample_dataset_file_names = self.__save_sample_datasets( trans, sample, selected_files, folder_path ) - if sample_dataset_file_names: - message = 'Datasets (%s) have been selected for sample (%s)' % \ - ( str( sample_dataset_file_names )[1:-1].replace( "'", "" ), sample.name ) - if params.get( 'select_show_datasets_button', False ): - return trans.response.send_redirect( web.url_for( controller='requests_admin', - action='manage_datasets', - request_id=request_id, - sample_id=selected_sample_id, - message=message, - status=status ) ) - else: # 'select_more_button' was clicked - return trans.response.send_redirect( web.url_for( controller='requests_admin', - action='get_data', - request_id=request_id, - folder_path=folder_path, - sample_id=sample.id, - message=message, - status=status ) ) - # Get the filenames from the remote host - files = self.__get_files( trans, request, folder_path ) + if params.get( 'select_show_datasets_button', False ) or params.get( 'select_more_button', False ): + # get the sample these datasets are associated with + try: + sample = trans.sa_session.query( trans.model.Sample ).get( trans.security.decode_id( selected_sample_id ) ) + except: + message = 'Select a sample before selecting its associated datasets.' + return trans.fill_template( '/admin/requests/get_data.mako', + cntrller='requests_admin', + request=request, + sample_id_select_field=sample_id_select_field, + status='error', + message=message ) + if sample in sample.request.samples_without_library_destinations: + # Display an error if a sample has been selected that + # has not yet been associated with a destination library. + status = 'error' + message = 'Select a sample with associated data library and folder before selecting the datasets.' + return trans.response.send_redirect( web.url_for( controller='requests_admin', + action='get_data', + request_id=request_id, + sample_id=sample.id, + status=status, + message=message ) ) + # Save the sample datasets + sample_dataset_file_names = self.__save_sample_datasets( trans, sample, selected_files ) + if sample_dataset_file_names: + message = 'Datasets (%s) have been selected for sample (%s)' % \ + ( str( sample_dataset_file_names )[1:-1].replace( "'", "" ), sample.name ) + if params.get( 'select_show_datasets_button', False ): + return trans.response.send_redirect( web.url_for( controller='requests_admin', + action='manage_datasets', + request_id=request_id, + sample_id=selected_sample_id, + message=message, + status=status ) ) + else: # 'select_more_button' was clicked + return trans.response.send_redirect( web.url_for( controller='requests_admin', + action='get_data', + request_id=request_id, + sample_id=sample.id, + message=message, + status=status ) ) return trans.fill_template( '/admin/requests/get_data.mako', cntrller='requests_admin', request=request, sample_id_select_field=sample_id_select_field, - files=files, - folder_path=folder_path, status=status, message=message ) @web.json @@ -464,15 +457,27 @@ class RequestsAdmin( BaseController, Use timeout=10 ) return unicode( output.replace( '\n', '<br/>' ) ) @web.json - def open_folder( self, trans, id, folder_path ): - def print_ticks( d ): - # pexpect timeout method - pass + def open_folder( self, trans, id, key ): # Avoid caching trans.response.headers['Pragma'] = 'no-cache' trans.response.headers['Expires'] = '0' request = trans.sa_session.query( trans.model.Request ).get( int( id ) ) - return self.__get_files( trans, request, folder_path ) + folder_path = key + files_list = self.__get_files( trans, request, folder_path ) + folder_contents = [] + for filename in files_list: + is_folder = False + if filename[-1] == os.sep: + is_folder = True + full_path = os.path.join(folder_path, filename) + node = {"title": filename, + "isFolder": is_folder, + "isLazy": is_folder, + "tooltip": full_path, + "key": full_path + } + folder_contents.append(node) + return folder_contents def __get_files( self, trans, request, folder_path ): # Retrieves the filenames to be transferred from the remote host. ok = True @@ -496,7 +501,6 @@ class RequestsAdmin( BaseController, Use return trans.response.send_redirect( web.url_for( controller='requests_admin', action='get_data', request_id=trans.security.encode_id( request.id ), - folder_path=folder_path, status=status, message=message ) ) def __check_path( self, a_path ): @@ -504,20 +508,13 @@ class RequestsAdmin( BaseController, Use if a_path and not a_path.endswith( os.sep ): a_path += os.sep return a_path - def __save_sample_datasets( self, trans, sample, selected_files, folder_path ): + def __save_sample_datasets( self, trans, sample, selected_files ): sample_dataset_file_names = [] if selected_files: - for f in selected_files: - filepath = os.path.join( folder_path, f ) - if f[-1] == os.sep: - # FIXME: The selected item is a folder so transfer all the folder contents - request_id = trans.security.ecnode_id( sample.request.id ) - return trans.response.send_redirect( web.url_for( controller='requests_admin', - action='get_data', - request_id=request_id, - folder_path=folder_path, - open_folder=True ) ) - else: + for filepath in selected_files: + # FIXME: handle folder selection + # ignore folders for now + if filepath[-1] != os.sep: name = self.__dataset_name( sample, filepath.split( '/' )[-1] ) sample_dataset = trans.model.SampleDataset( sample=sample, file_path=filepath, Binary file static/june_2007_style/blue/dynatree_skin/ltP_nes.gif has changed Binary file static/june_2007_style/blue/dynatree_skin/ltFld.gif has changed Binary file static/june_2007_style/blue/dynatree_skin/rbIntermediate.gif has changed --- /dev/null +++ b/static/scripts/packed/ui.core.js @@ -0,0 +1,1 @@ +jQuery.ui||(function(c){var i=c.fn.remove,d=c.browser.mozilla&&(parseFloat(c.browser.version)<1.9);c.ui={version:"1.7.1",plugin:{add:function(k,l,n){var m=c.ui[k].prototype;for(var j in n){m.plugins[j]=m.plugins[j]||[];m.plugins[j].push([l,n[j]])}},call:function(j,l,k){var n=j.plugins[l];if(!n||!j.element[0].parentNode){return}for(var m=0;m<n.length;m++){if(j.options[n[m][0]]){n[m][1].apply(j.element,k)}}}},contains:function(k,j){return document.compareDocumentPosition?k.compareDocumentPosition(j)&16:k!==j&&k.contains(j)},hasScroll:function(m,k){if(c(m).css("overflow")=="hidden"){return false}var j=(k&&k=="left")?"scrollLeft":"scrollTop",l=false;if(m[j]>0){return true}m[j]=1;l=(m[j]>0);m[j]=0;return l},isOverAxis:function(k,j,l){return(k>j)&&(k<(j+l))},isOver:function(o,k,n,m,j,l){return c.ui.isOverAxis(o,n,j)&&c.ui.isOverAxis(k,m,l)},keyCode:{BACKSPACE:8,CAPS_LOCK:20,COMMA:188,CONTROL:17,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,INSERT:45,LEFT:37,NUMPAD_ADD:107,NU MPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106,NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SHIFT:16,SPACE:32,TAB:9,UP:38}};if(d){var f=c.attr,e=c.fn.removeAttr,h="http://www.w3.org/2005/07/aaa",a=/^aria-/,b=/^wairole:/;c.attr=function(k,j,l){var m=l!==undefined;return(j=="role"?(m?f.call(this,k,j,"wairole:"+l):(f.apply(this,arguments)||"").replace(b,"")):(a.test(j)?(m?k.setAttributeNS(h,j.replace(a,"aaa:"),l):f.call(this,k,j.replace(a,"aaa:"))):f.apply(this,arguments)))};c.fn.removeAttr=function(j){return(a.test(j)?this.each(function(){this.removeAttributeNS(h,j.replace(a,""))}):e.call(this,j))}}c.fn.extend({remove:function(){c("*",this).add(this).each(function(){c(this).triggerHandler("remove")});return i.apply(this,arguments)},enableSelection:function(){return this.attr("unselectable","off").css("MozUserSelect","").unbind("selectstart.ui")},disableSelection:function(){return this.attr("unselectable","on").css("MozUserSelect","no ne").bind("selectstart.ui",function(){return false})},scrollParent:function(){var j;if((c.browser.msie&&(/(static|relative)/).test(this.css("position")))||(/absolute/).test(this.css("position"))){j=this.parents().filter(function(){return(/(relative|absolute|fixed)/).test(c.curCSS(this,"position",1))&&(/(auto|scroll)/).test(c.curCSS(this,"overflow",1)+c.curCSS(this,"overflow-y",1)+c.curCSS(this,"overflow-x",1))}).eq(0)}else{j=this.parents().filter(function(){return(/(auto|scroll)/).test(c.curCSS(this,"overflow",1)+c.curCSS(this,"overflow-y",1)+c.curCSS(this,"overflow-x",1))}).eq(0)}return(/fixed/).test(this.css("position"))||!j.length?c(document):j}});c.extend(c.expr[":"],{data:function(l,k,j){return !!c.data(l,j[3])},focusable:function(k){var l=k.nodeName.toLowerCase(),j=c.attr(k,"tabindex");return(/input|select|textarea|button|object/.test(l)?!k.disabled:"a"==l||"area"==l?k.href||!isNaN(j):!isNaN(j))&&!c(k)["area"==l?"parents":"closest"](":hidden").length},tabbable:function (k){var j=c.attr(k,"tabindex");return(isNaN(j)||j>=0)&&c(k).is(":focusable")}});function g(m,n,o,l){function k(q){var p=c[m][n][q]||[];return(typeof p=="string"?p.split(/,?\s+/):p)}var j=k("getter");if(l.length==1&&typeof l[0]=="string"){j=j.concat(k("getterSetter"))}return(c.inArray(o,j)!=-1)}c.widget=function(k,j){var l=k.split(".")[0];k=k.split(".")[1];c.fn[k]=function(p){var n=(typeof p=="string"),o=Array.prototype.slice.call(arguments,1);if(n&&p.substring(0,1)=="_"){return this}if(n&&g(l,k,p,o)){var m=c.data(this[0],k);return(m?m[p].apply(m,o):undefined)}return this.each(function(){var q=c.data(this,k);(!q&&!n&&c.data(this,k,new c[l][k](this,p))._init());(q&&n&&c.isFunction(q[p])&&q[p].apply(q,o))})};c[l]=c[l]||{};c[l][k]=function(o,n){var m=this;this.namespace=l;this.widgetName=k;this.widgetEventPrefix=c[l][k].eventPrefix||k;this.widgetBaseClass=l+"-"+k;this.options=c.extend({},c.widget.defaults,c[l][k].defaults,c.metadata&&c.metadata.get(o)[k],n);this.element=c(o).bin d("setData."+k,function(q,p,r){if(q.target==o){return m._setData(p,r)}}).bind("getData."+k,function(q,p){if(q.target==o){return m._getData(p)}}).bind("remove",function(){return m.destroy()})};c[l][k].prototype=c.extend({},c.widget.prototype,j);c[l][k].getterSetter="option"};c.widget.prototype={_init:function(){},destroy:function(){this.element.removeData(this.widgetName).removeClass(this.widgetBaseClass+"-disabled "+this.namespace+"-state-disabled").removeAttr("aria-disabled")},option:function(l,m){var k=l,j=this;if(typeof l=="string"){if(m===undefined){return this._getData(l)}k={};k[l]=m}c.each(k,function(n,o){j._setData(n,o)})},_getData:function(j){return this.options[j]},_setData:function(j,k){this.options[j]=k;if(j=="disabled"){this.element[k?"addClass":"removeClass"](this.widgetBaseClass+"-disabled "+this.namespace+"-state-disabled").attr("aria-disabled",k)}},enable:function(){this._setData("disabled",false)},disable:function(){this._setData("disabled",true)},_trigger:f unction(l,m,n){var p=this.options[l],j=(l==this.widgetEventPrefix?l:this.widgetEventPrefix+l);m=c.Event(m);m.type=j;if(m.originalEvent){for(var k=c.event.props.length,o;k;){o=c.event.props[--k];m[o]=m.originalEvent[o]}}this.element.trigger(m,n);return !(c.isFunction(p)&&p.call(this.element[0],m,n)===false||m.isDefaultPrevented())}};c.widget.defaults={disabled:false};c.ui.mouse={_mouseInit:function(){var j=this;this.element.bind("mousedown."+this.widgetName,function(k){return j._mouseDown(k)}).bind("click."+this.widgetName,function(k){if(j._preventClickEvent){j._preventClickEvent=false;k.stopImmediatePropagation();return false}});if(c.browser.msie){this._mouseUnselectable=this.element.attr("unselectable");this.element.attr("unselectable","on")}this.started=false},_mouseDestroy:function(){this.element.unbind("."+this.widgetName);(c.browser.msie&&this.element.attr("unselectable",this._mouseUnselectable))},_mouseDown:function(l){l.originalEvent=l.originalEvent||{};if(l.originalE vent.mouseHandled){return}(this._mouseStarted&&this._mouseUp(l));this._mouseDownEvent=l;var k=this,m=(l.which==1),j=(typeof this.options.cancel=="string"?c(l.target).parents().add(l.target).filter(this.options.cancel).length:false);if(!m||j||!this._mouseCapture(l)){return true}this.mouseDelayMet=!this.options.delay;if(!this.mouseDelayMet){this._mouseDelayTimer=setTimeout(function(){k.mouseDelayMet=true},this.options.delay)}if(this._mouseDistanceMet(l)&&this._mouseDelayMet(l)){this._mouseStarted=(this._mouseStart(l)!==false);if(!this._mouseStarted){l.preventDefault();return true}}this._mouseMoveDelegate=function(n){return k._mouseMove(n)};this._mouseUpDelegate=function(n){return k._mouseUp(n)};c(document).bind("mousemove."+this.widgetName,this._mouseMoveDelegate).bind("mouseup."+this.widgetName,this._mouseUpDelegate);(c.browser.safari||l.preventDefault());l.originalEvent.mouseHandled=true;return true},_mouseMove:function(j){if(c.browser.msie&&!j.button){return this._mouseUp(j )}if(this._mouseStarted){this._mouseDrag(j);return j.preventDefault()}if(this._mouseDistanceMet(j)&&this._mouseDelayMet(j)){this._mouseStarted=(this._mouseStart(this._mouseDownEvent,j)!==false);(this._mouseStarted?this._mouseDrag(j):this._mouseUp(j))}return !this._mouseStarted},_mouseUp:function(j){c(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate);if(this._mouseStarted){this._mouseStarted=false;this._preventClickEvent=(j.target==this._mouseDownEvent.target);this._mouseStop(j)}return false},_mouseDistanceMet:function(j){return(Math.max(Math.abs(this._mouseDownEvent.pageX-j.pageX),Math.abs(this._mouseDownEvent.pageY-j.pageY))>=this.options.distance)},_mouseDelayMet:function(j){return this.mouseDelayMet},_mouseStart:function(j){},_mouseDrag:function(j){},_mouseStop:function(j){},_mouseCapture:function(j){return true}};c.ui.mouse.defaults={cancel:null,distance:1,delay:0}})(jQuery); Binary file static/june_2007_style/blue/dynatree_skin/ltP_ne.gif has changed Binary file static/june_2007_style/blue/dynatree_skin/cbIntermediate_hover.gif has changed Binary file static/june_2007_style/blue/dynatree_skin/ltDoc.gif has changed Binary file static/june_2007_style/blue/dynatree_skin/rbUnchecked.gif has changed Binary file static/june_2007_style/blue/dynatree_skin/ltWait.gif has changed Binary file static/june_2007_style/blue/dynatree_skin/cbChecked_hover.gif has changed Binary file static/june_2007_style/blue/dynatree_skin/customDoc1.gif has changed --- /dev/null +++ b/static/scripts/ui.core.js @@ -0,0 +1,519 @@ +/* + * jQuery UI 1.7.1 + * + * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI + */ +;jQuery.ui || (function($) { + +var _remove = $.fn.remove, + isFF2 = $.browser.mozilla && (parseFloat($.browser.version) < 1.9); + +//Helper functions and ui object +$.ui = { + version: "1.7.1", + + // $.ui.plugin is deprecated. Use the proxy pattern instead. + plugin: { + add: function(module, option, set) { + var proto = $.ui[module].prototype; + for(var i in set) { + proto.plugins[i] = proto.plugins[i] || []; + proto.plugins[i].push([option, set[i]]); + } + }, + call: function(instance, name, args) { + var set = instance.plugins[name]; + if(!set || !instance.element[0].parentNode) { return; } + + for (var i = 0; i < set.length; i++) { + if (instance.options[set[i][0]]) { + set[i][1].apply(instance.element, args); + } + } + } + }, + + contains: function(a, b) { + return document.compareDocumentPosition + ? a.compareDocumentPosition(b) & 16 + : a !== b && a.contains(b); + }, + + hasScroll: function(el, a) { + + //If overflow is hidden, the element might have extra content, but the user wants to hide it + if ($(el).css('overflow') == 'hidden') { return false; } + + var scroll = (a && a == 'left') ? 'scrollLeft' : 'scrollTop', + has = false; + + if (el[scroll] > 0) { return true; } + + // TODO: determine which cases actually cause this to happen + // if the element doesn't have the scroll set, see if it's possible to + // set the scroll + el[scroll] = 1; + has = (el[scroll] > 0); + el[scroll] = 0; + return has; + }, + + isOverAxis: function(x, reference, size) { + //Determines when x coordinate is over "b" element axis + return (x > reference) && (x < (reference + size)); + }, + + isOver: function(y, x, top, left, height, width) { + //Determines when x, y coordinates is over "b" element + return $.ui.isOverAxis(y, top, height) && $.ui.isOverAxis(x, left, width); + }, + + keyCode: { + BACKSPACE: 8, + CAPS_LOCK: 20, + COMMA: 188, + CONTROL: 17, + DELETE: 46, + DOWN: 40, + END: 35, + ENTER: 13, + ESCAPE: 27, + HOME: 36, + INSERT: 45, + LEFT: 37, + NUMPAD_ADD: 107, + NUMPAD_DECIMAL: 110, + NUMPAD_DIVIDE: 111, + NUMPAD_ENTER: 108, + NUMPAD_MULTIPLY: 106, + NUMPAD_SUBTRACT: 109, + PAGE_DOWN: 34, + PAGE_UP: 33, + PERIOD: 190, + RIGHT: 39, + SHIFT: 16, + SPACE: 32, + TAB: 9, + UP: 38 + } +}; + +// WAI-ARIA normalization +if (isFF2) { + var attr = $.attr, + removeAttr = $.fn.removeAttr, + ariaNS = "http://www.w3.org/2005/07/aaa", + ariaState = /^aria-/, + ariaRole = /^wairole:/; + + $.attr = function(elem, name, value) { + var set = value !== undefined; + + return (name == 'role' + ? (set + ? attr.call(this, elem, name, "wairole:" + value) + : (attr.apply(this, arguments) || "").replace(ariaRole, "")) + : (ariaState.test(name) + ? (set + ? elem.setAttributeNS(ariaNS, + name.replace(ariaState, "aaa:"), value) + : attr.call(this, elem, name.replace(ariaState, "aaa:"))) + : attr.apply(this, arguments))); + }; + + $.fn.removeAttr = function(name) { + return (ariaState.test(name) + ? this.each(function() { + this.removeAttributeNS(ariaNS, name.replace(ariaState, "")); + }) : removeAttr.call(this, name)); + }; +} + +//jQuery plugins +$.fn.extend({ + remove: function() { + // Safari has a native remove event which actually removes DOM elements, + // so we have to use triggerHandler instead of trigger (#3037). + $("*", this).add(this).each(function() { + $(this).triggerHandler("remove"); + }); + return _remove.apply(this, arguments ); + }, + + enableSelection: function() { + return this + .attr('unselectable', 'off') + .css('MozUserSelect', '') + .unbind('selectstart.ui'); + }, + + disableSelection: function() { + return this + .attr('unselectable', 'on') + .css('MozUserSelect', 'none') + .bind('selectstart.ui', function() { return false; }); + }, + + scrollParent: function() { + var scrollParent; + if(($.browser.msie && (/(static|relative)/).test(this.css('position'))) || (/absolute/).test(this.css('position'))) { + scrollParent = this.parents().filter(function() { + return (/(relative|absolute|fixed)/).test($.curCSS(this,'position',1)) && (/(auto|scroll)/).test($.curCSS(this,'overflow',1)+$.curCSS(this,'overflow-y',1)+$.curCSS(this,'overflow-x',1)); + }).eq(0); + } else { + scrollParent = this.parents().filter(function() { + return (/(auto|scroll)/).test($.curCSS(this,'overflow',1)+$.curCSS(this,'overflow-y',1)+$.curCSS(this,'overflow-x',1)); + }).eq(0); + } + + return (/fixed/).test(this.css('position')) || !scrollParent.length ? $(document) : scrollParent; + } +}); + + +//Additional selectors +$.extend($.expr[':'], { + data: function(elem, i, match) { + return !!$.data(elem, match[3]); + }, + + focusable: function(element) { + var nodeName = element.nodeName.toLowerCase(), + tabIndex = $.attr(element, 'tabindex'); + return (/input|select|textarea|button|object/.test(nodeName) + ? !element.disabled + : 'a' == nodeName || 'area' == nodeName + ? element.href || !isNaN(tabIndex) + : !isNaN(tabIndex)) + // the element and all of its ancestors must be visible + // the browser may report that the area is hidden + && !$(element)['area' == nodeName ? 'parents' : 'closest'](':hidden').length; + }, + + tabbable: function(element) { + var tabIndex = $.attr(element, 'tabindex'); + return (isNaN(tabIndex) || tabIndex >= 0) && $(element).is(':focusable'); + } +}); + + +// $.widget is a factory to create jQuery plugins +// taking some boilerplate code out of the plugin code +function getter(namespace, plugin, method, args) { + function getMethods(type) { + var methods = $[namespace][plugin][type] || []; + return (typeof methods == 'string' ? methods.split(/,?\s+/) : methods); + } + + var methods = getMethods('getter'); + if (args.length == 1 && typeof args[0] == 'string') { + methods = methods.concat(getMethods('getterSetter')); + } + return ($.inArray(method, methods) != -1); +} + +$.widget = function(name, prototype) { + var namespace = name.split(".")[0]; + name = name.split(".")[1]; + + // create plugin method + $.fn[name] = function(options) { + var isMethodCall = (typeof options == 'string'), + args = Array.prototype.slice.call(arguments, 1); + + // prevent calls to internal methods + if (isMethodCall && options.substring(0, 1) == '_') { + return this; + } + + // handle getter methods + if (isMethodCall && getter(namespace, name, options, args)) { + var instance = $.data(this[0], name); + return (instance ? instance[options].apply(instance, args) + : undefined); + } + + // handle initialization and non-getter methods + return this.each(function() { + var instance = $.data(this, name); + + // constructor + (!instance && !isMethodCall && + $.data(this, name, new $[namespace][name](this, options))._init()); + + // method call + (instance && isMethodCall && $.isFunction(instance[options]) && + instance[options].apply(instance, args)); + }); + }; + + // create widget constructor + $[namespace] = $[namespace] || {}; + $[namespace][name] = function(element, options) { + var self = this; + + this.namespace = namespace; + this.widgetName = name; + this.widgetEventPrefix = $[namespace][name].eventPrefix || name; + this.widgetBaseClass = namespace + '-' + name; + + this.options = $.extend({}, + $.widget.defaults, + $[namespace][name].defaults, + $.metadata && $.metadata.get(element)[name], + options); + + this.element = $(element) + .bind('setData.' + name, function(event, key, value) { + if (event.target == element) { + return self._setData(key, value); + } + }) + .bind('getData.' + name, function(event, key) { + if (event.target == element) { + return self._getData(key); + } + }) + .bind('remove', function() { + return self.destroy(); + }); + }; + + // add widget prototype + $[namespace][name].prototype = $.extend({}, $.widget.prototype, prototype); + + // TODO: merge getter and getterSetter properties from widget prototype + // and plugin prototype + $[namespace][name].getterSetter = 'option'; +}; + +$.widget.prototype = { + _init: function() {}, + destroy: function() { + this.element.removeData(this.widgetName) + .removeClass(this.widgetBaseClass + '-disabled' + ' ' + this.namespace + '-state-disabled') + .removeAttr('aria-disabled'); + }, + + option: function(key, value) { + var options = key, + self = this; + + if (typeof key == "string") { + if (value === undefined) { + return this._getData(key); + } + options = {}; + options[key] = value; + } + + $.each(options, function(key, value) { + self._setData(key, value); + }); + }, + _getData: function(key) { + return this.options[key]; + }, + _setData: function(key, value) { + this.options[key] = value; + + if (key == 'disabled') { + this.element + [value ? 'addClass' : 'removeClass']( + this.widgetBaseClass + '-disabled' + ' ' + + this.namespace + '-state-disabled') + .attr("aria-disabled", value); + } + }, + + enable: function() { + this._setData('disabled', false); + }, + disable: function() { + this._setData('disabled', true); + }, + + _trigger: function(type, event, data) { + var callback = this.options[type], + eventName = (type == this.widgetEventPrefix + ? type : this.widgetEventPrefix + type); + + event = $.Event(event); + event.type = eventName; + + // copy original event properties over to the new event + // this would happen if we could call $.event.fix instead of $.Event + // but we don't have a way to force an event to be fixed multiple times + if (event.originalEvent) { + for (var i = $.event.props.length, prop; i;) { + prop = $.event.props[--i]; + event[prop] = event.originalEvent[prop]; + } + } + + this.element.trigger(event, data); + + return !($.isFunction(callback) && callback.call(this.element[0], event, data) === false + || event.isDefaultPrevented()); + } +}; + +$.widget.defaults = { + disabled: false +}; + + +/** Mouse Interaction Plugin **/ + +$.ui.mouse = { + _mouseInit: function() { + var self = this; + + this.element + .bind('mousedown.'+this.widgetName, function(event) { + return self._mouseDown(event); + }) + .bind('click.'+this.widgetName, function(event) { + if(self._preventClickEvent) { + self._preventClickEvent = false; + event.stopImmediatePropagation(); + return false; + } + }); + + // Prevent text selection in IE + if ($.browser.msie) { + this._mouseUnselectable = this.element.attr('unselectable'); + this.element.attr('unselectable', 'on'); + } + + this.started = false; + }, + + // TODO: make sure destroying one instance of mouse doesn't mess with + // other instances of mouse + _mouseDestroy: function() { + this.element.unbind('.'+this.widgetName); + + // Restore text selection in IE + ($.browser.msie + && this.element.attr('unselectable', this._mouseUnselectable)); + }, + + _mouseDown: function(event) { + // don't let more than one widget handle mouseStart + // TODO: figure out why we have to use originalEvent + event.originalEvent = event.originalEvent || {}; + if (event.originalEvent.mouseHandled) { return; } + + // we may have missed mouseup (out of window) + (this._mouseStarted && this._mouseUp(event)); + + this._mouseDownEvent = event; + + var self = this, + btnIsLeft = (event.which == 1), + elIsCancel = (typeof this.options.cancel == "string" ? $(event.target).parents().add(event.target).filter(this.options.cancel).length : false); + if (!btnIsLeft || elIsCancel || !this._mouseCapture(event)) { + return true; + } + + this.mouseDelayMet = !this.options.delay; + if (!this.mouseDelayMet) { + this._mouseDelayTimer = setTimeout(function() { + self.mouseDelayMet = true; + }, this.options.delay); + } + + if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) { + this._mouseStarted = (this._mouseStart(event) !== false); + if (!this._mouseStarted) { + event.preventDefault(); + return true; + } + } + + // these delegates are required to keep context + this._mouseMoveDelegate = function(event) { + return self._mouseMove(event); + }; + this._mouseUpDelegate = function(event) { + return self._mouseUp(event); + }; + $(document) + .bind('mousemove.'+this.widgetName, this._mouseMoveDelegate) + .bind('mouseup.'+this.widgetName, this._mouseUpDelegate); + + // preventDefault() is used to prevent the selection of text here - + // however, in Safari, this causes select boxes not to be selectable + // anymore, so this fix is needed + ($.browser.safari || event.preventDefault()); + + event.originalEvent.mouseHandled = true; + return true; + }, + + _mouseMove: function(event) { + // IE mouseup check - mouseup happened when mouse was out of window + if ($.browser.msie && !event.button) { + return this._mouseUp(event); + } + + if (this._mouseStarted) { + this._mouseDrag(event); + return event.preventDefault(); + } + + if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) { + this._mouseStarted = + (this._mouseStart(this._mouseDownEvent, event) !== false); + (this._mouseStarted ? this._mouseDrag(event) : this._mouseUp(event)); + } + + return !this._mouseStarted; + }, + + _mouseUp: function(event) { + $(document) + .unbind('mousemove.'+this.widgetName, this._mouseMoveDelegate) + .unbind('mouseup.'+this.widgetName, this._mouseUpDelegate); + + if (this._mouseStarted) { + this._mouseStarted = false; + this._preventClickEvent = (event.target == this._mouseDownEvent.target); + this._mouseStop(event); + } + + return false; + }, + + _mouseDistanceMet: function(event) { + return (Math.max( + Math.abs(this._mouseDownEvent.pageX - event.pageX), + Math.abs(this._mouseDownEvent.pageY - event.pageY) + ) >= this.options.distance + ); + }, + + _mouseDelayMet: function(event) { + return this.mouseDelayMet; + }, + + // These are placeholder methods, to be overriden by extending plugin + _mouseStart: function(event) {}, + _mouseDrag: function(event) {}, + _mouseStop: function(event) {}, + _mouseCapture: function(event) { return true; } +}; + +$.ui.mouse.defaults = { + cancel: null, + distance: 1, + delay: 0 +}; + +})(jQuery); --- /dev/null +++ b/static/scripts/jquery.cookie.js @@ -0,0 +1,97 @@ +/** + * Cookie plugin + * + * Copyright (c) 2006 Klaus Hartl (stilbuero.de) + * Dual licensed under the MIT and GPL licenses: + * http://www.opensource.org/licenses/mit-license.php + * http://www.gnu.org/licenses/gpl.html + * + */ + +/** + * Create a cookie with the given name and value and other optional parameters. + * + * @example $.cookie('the_cookie', 'the_value'); + * @desc Set the value of a cookie. + * @example $.cookie('the_cookie', 'the_value', { expires: 7, path: '/', domain: 'jquery.com', secure: true }); + * @desc Create a cookie with all available options. + * @example $.cookie('the_cookie', 'the_value'); + * @desc Create a session cookie. + * @example $.cookie('the_cookie', null); + * @desc Delete a cookie by passing null as value. Keep in mind that you have to use the same path and domain + * used when the cookie was set. + * + * @param String name The name of the cookie. + * @param String value The value of the cookie. + * @param Object options An object literal containing key/value pairs to provide optional cookie attributes. + * @option Number|Date expires Either an integer specifying the expiration date from now on in days or a Date object. + * If a negative value is specified (e.g. a date in the past), the cookie will be deleted. + * If set to null or omitted, the cookie will be a session cookie and will not be retained + * when the the browser exits. + * @option String path The value of the path atribute of the cookie (default: path of page that created the cookie). + * @option String domain The value of the domain attribute of the cookie (default: domain of page that created the cookie). + * @option Boolean secure If true, the secure attribute of the cookie will be set and the cookie transmission will + * require a secure protocol (like HTTPS). + * @type undefined + * + * @name $.cookie + * @cat Plugins/Cookie + * @author Klaus Hartl/klaus.hartl@stilbuero.de + */ + +/** + * Get the value of a cookie with the given name. + * + * @example $.cookie('the_cookie'); + * @desc Get the value of a cookie. + * + * @param String name The name of the cookie. + * @return The value of the cookie. + * @type String + * + * @name $.cookie + * @cat Plugins/Cookie + * @author Klaus Hartl/klaus.hartl@stilbuero.de + */ +jQuery.cookie = function(name, value, options) { + if (typeof value != 'undefined') { // name and value given, set cookie + options = options || {}; + if (value === null) { + value = ''; + options = $.extend({}, options); // clone object since it's unexpected behavior if the expired property were changed + options.expires = -1; + } + var expires = ''; + if (options.expires && (typeof options.expires == 'number' || options.expires.toUTCString)) { + var date; + if (typeof options.expires == 'number') { + date = new Date(); + date.setTime(date.getTime() + (options.expires * 24 * 60 * 60 * 1000)); + } else { + date = options.expires; + } + expires = '; expires=' + date.toUTCString(); // use expires attribute, max-age is not supported by IE + } + // NOTE Needed to parenthesize options.path and options.domain + // in the following expressions, otherwise they evaluate to undefined + // in the packed version for some reason... + var path = options.path ? '; path=' + (options.path) : ''; + var domain = options.domain ? '; domain=' + (options.domain) : ''; + var secure = options.secure ? '; secure' : ''; + document.cookie = [name, '=', encodeURIComponent(value), expires, path, domain, secure].join(''); + } else { // only name given, get cookie + var cookieValue = null; + if (document.cookie && document.cookie != '') { + var cookies = document.cookie.split(';'); + for (var i = 0; i < cookies.length; i++) { + var cookie = jQuery.trim(cookies[i]); + // Does this cookie string begin with the name we want? + if (cookie.substring(0, name.length + 1) == (name + '=')) { + cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); + break; + } + } + } + return cookieValue; + } +}; Binary file static/june_2007_style/blue/dynatree_skin/ltM_ne.gif has changed Binary file static/june_2007_style/blue/dynatree_skin/ltD_nes.gif has changed Binary file static/june_2007_style/blue/dynatree_skin/ltFld_o.gif has changed Binary file static/june_2007_style/blue/dynatree_skin/ltM_nes.gif has changed --- /dev/null +++ b/static/scripts/packed/jquery.dynatree.js @@ -0,0 +1,1 @@ +var _canLog=true;function _log(g,f){if(!_canLog){return}var b=Array.prototype.slice.apply(arguments,[1]);var c=new Date();var a=c.getHours()+":"+c.getMinutes()+":"+c.getSeconds()+"."+c.getMilliseconds();b[0]=a+" - "+b[0];try{switch(g){case"info":window.console.info.apply(window.console,b);break;case"warn":window.console.warn.apply(window.console,b);break;default:window.console.log.apply(window.console,b)}}catch(d){if(!window.console){_canLog=false}}}function logMsg(a){Array.prototype.unshift.apply(arguments,["debug"]);_log.apply(this,arguments)}var getDynaTreePersistData=undefined;var DTNodeStatus_Error=-1;var DTNodeStatus_Loading=1;var DTNodeStatus_Ok=0;(function($){var Class={create:function(){return function(){this.initialize.apply(this,arguments)}}};var DynaTreeNode=Class.create();DynaTreeNode.prototype={initialize:function(parent,tree,data){this.parent=parent;this.tree=tree;if(typeof data=="string"){data={title:data}}if(data.key==undefined){data.key="_"+tree._nodeCount+ +}this.data=$.extend({},$.ui.dynatree.nodedatadefaults,data);this.div=null;this.span=null;this.childList=null;this.isLoading=false;this.hasSubSel=false},toString:function(){return"dtnode<"+this.data.key+">: '"+this.data.title+"'"},toDict:function(recursive,callback){var dict=$.extend({},this.data);dict.activate=(this.tree.activeNode===this);dict.focus=(this.tree.focusNode===this);dict.expand=this.bExpanded;dict.select=this.bSelected;if(callback){callback(dict)}if(recursive&&this.childList){dict.children=[];for(var i=0;i<this.childList.length;i++){dict.children.push(this.childList[i].toDict(true,callback))}}else{delete dict.children}return dict},_getInnerHtml:function(){var opts=this.tree.options;var cache=this.tree.cache;var rootParent=opts.rootVisible?null:this.tree.tnRoot;var bHideFirstExpander=(opts.rootVisible&&opts.minExpandLevel>0)||opts.minExpandLevel>1;var bHideFirstConnector=opts.rootVisible||opts.minExpandLevel>0;var res="";var p=this.parent;while(p){if(bHideFirstC onnector&&p==rootParent){break}res=(p.isLastSibling()?cache.tagEmpty:cache.tagVline)+res;p=p.parent}if(bHideFirstExpander&&this.parent==rootParent){}else{if(this.childList||this.data.isLazy){res+=cache.tagExpander}else{res+=cache.tagConnector}}if(opts.checkbox&&this.data.hideCheckbox!=true&&!this.data.isStatusNode){res+=cache.tagCheckbox}if(this.data.icon){res+="<img src='"+opts.imagePath+this.data.icon+"' alt='' />"}else{if(this.data.icon==false){}else{res+=cache.tagNodeIcon}}var tooltip=(this.data&&typeof this.data.tooltip=="string")?" title='"+this.data.tooltip+"'":"";res+="<a href='#' class='"+opts.classNames.title+"'"+tooltip+">"+this.data.title+"</a>";return res},_fixOrder:function(){var cl=this.childList;if(!cl){return}var childDiv=this.div.firstChild.nextSibling;for(var i=0;i<cl.length-1;i++){var childNode1=cl[i];var childNode2=childDiv.firstChild.dtnode;if(childNode1!==childNode2){this.tree.logDebug("_fixOrder: mismatch at index "+i+": "+childNode1+" != "+childNode2 );this.div.insertBefore(childNode1.div,childNode2.div)}else{childDiv=childDiv.nextSibling}}},render:function(bDeep,bHidden){var opts=this.tree.options;var cn=opts.classNames;var isLastSib=this.isLastSibling();if(!this.div){this.span=document.createElement("span");this.span.dtnode=this;if(this.data.key){this.span.id=this.tree.options.idPrefix+this.data.key}this.div=document.createElement("div");this.div.appendChild(this.span);if(this.parent){this.parent.div.appendChild(this.div)}if(this.parent==null&&!this.tree.options.rootVisible){this.span.style.display="none"}}this.span.innerHTML=this._getInnerHtml();this.div.style.display=(this.parent==null||this.parent.bExpanded?"":"none");var cnList=[];cnList.push((this.data.isFolder)?cn.folder:cn.document);if(this.bExpanded){cnList.push(cn.expanded)}if(this.childList!=null){cnList.push(cn.hasChildren)}if(this.data.isLazy&&this.childList==null){cnList.push(cn.lazy)}if(isLastSib){cnList.push(cn.lastsib)}if(this.bSelected){cnList.push(cn. selected)}if(this.hasSubSel){cnList.push(cn.partsel)}if(this.tree.activeNode===this){cnList.push(cn.active)}if(this.data.addClass){cnList.push(this.data.addClass)}cnList.push(cn.combinedExpanderPrefix+(this.bExpanded?"e":"c")+(this.data.isLazy&&this.childList==null?"d":"")+(isLastSib?"l":""));cnList.push(cn.combinedIconPrefix+(this.bExpanded?"e":"c")+(this.data.isFolder?"f":""));this.span.className=cnList.join(" ");if(bDeep&&this.childList&&(bHidden||this.bExpanded)){for(var i=0;i<this.childList.length;i++){this.childList[i].render(bDeep,bHidden)}this._fixOrder()}},hasChildren:function(){return this.childList!=null},isLastSibling:function(){var p=this.parent;if(!p){return true}return p.childList[p.childList.length-1]===this},prevSibling:function(){if(!this.parent){return null}var ac=this.parent.childList;for(var i=1;i<ac.length;i++){if(ac[i]===this){return ac[i-1]}}return null},nextSibling:function(){if(!this.parent){return null}var ac=this.parent.childList;for(var i=0;i<ac. length-1;i++){if(ac[i]===this){return ac[i+1]}}return null},_setStatusNode:function(data){var firstChild=(this.childList?this.childList[0]:null);if(!data){if(firstChild){this.div.removeChild(firstChild.div);if(this.childList.length==1){this.childList=null}else{this.childList.shift()}}}else{if(firstChild){data.isStatusNode=true;firstChild.data=data;firstChild.render(false,false)}else{data.isStatusNode=true;firstChild=this.addChild(data)}}},setLazyNodeStatus:function(lts,opts){var tooltip=(opts&&opts.tooltip)?opts.tooltip:null;var info=(opts&&opts.info)?" ("+opts.info+")":"";switch(lts){case DTNodeStatus_Ok:this._setStatusNode(null);this.isLoading=false;this.render(false,false);if(this.tree.options.autoFocus){if(this===this.tree.tnRoot&&!this.tree.options.rootVisible&&this.childList){this.childList[0].focus()}else{this.focus()}}break;case DTNodeStatus_Loading:this.isLoading=true;this._setStatusNode({title:this.tree.options.strings.loading+info,tooltip:tooltip,addClass:this.tre e.options.classNames.nodeWait});break;case DTNodeStatus_Error:this.isLoading=false;this._setStatusNode({title:this.tree.options.strings.loadError+info,tooltip:tooltip,addClass:this.tree.options.classNames.nodeError});break;default:throw"Bad LazyNodeStatus: '"+lts+"'."}},_parentList:function(includeRoot,includeSelf){var l=[];var dtn=includeSelf?this:this.parent;while(dtn){if(includeRoot||dtn.parent){l.unshift(dtn)}dtn=dtn.parent}return l},getLevel:function(){var level=0;var dtn=this.parent;while(dtn){level++;dtn=dtn.parent}return level},_getTypeForOuterNodeEvent:function(event){var cns=this.tree.options.classNames;var target=event.target;if(target.className.indexOf(cns.folder)<0&&target.className.indexOf(cns.document)<0){return null}var eventX=event.pageX-target.offsetLeft;var eventY=event.pageY-target.offsetTop;for(var i=0;i<target.childNodes.length;i++){var cn=target.childNodes[i];var x=cn.offsetLeft-target.offsetLeft;var y=cn.offsetTop-target.offsetTop;var nx=cn.clientWidt h,ny=cn.clientHeight;if(eventX>=x&&eventX<=(x+nx)&&eventY>=y&&eventY<=(y+ny)){if(cn.className==cns.title){return"title"}else{if(cn.className==cns.expander){return"expander"}else{if(cn.className==cns.checkbox){return"checkbox"}else{if(cn.className==cns.nodeIcon){return"icon"}}}}}}return"prefix"},getEventTargetType:function(event){var tcn=event&&event.target?event.target.className:"";var cns=this.tree.options.classNames;if(tcn==cns.title){return"title"}else{if(tcn==cns.expander){return"expander"}else{if(tcn==cns.checkbox){return"checkbox"}else{if(tcn==cns.nodeIcon){return"icon"}else{if(tcn==cns.empty||tcn==cns.vline||tcn==cns.connector){return"prefix"}else{if(tcn.indexOf(cns.folder)>=0||tcn.indexOf(cns.document)>=0){return this._getTypeForOuterNodeEvent(event)}}}}}}return null},isVisible:function(){var parents=this._parentList(true,false);for(var i=0;i<parents.length;i++){if(!parents[i].bExpanded){return false}}return true},makeVisible:function(){var parents=this._parentList(t rue,false);for(var i=0;i<parents.length;i++){parents[i]._expand(true)}},focus:function(){this.makeVisible();try{$(this.span).find(">a").focus()}catch(e){}},_activate:function(flag,fireEvents){this.tree.logDebug("dtnode._activate(%o, fireEvents=%o) - %o",flag,fireEvents,this);var opts=this.tree.options;if(this.data.isStatusNode){return}if(fireEvents&&opts.onQueryActivate&&opts.onQueryActivate.call(this.span,flag,this)==false){return}if(flag){if(this.tree.activeNode){if(this.tree.activeNode===this){return}this.tree.activeNode.deactivate()}if(opts.activeVisible){this.makeVisible()}this.tree.activeNode=this;if(opts.persist){$.cookie(opts.cookieId+"-active",this.data.key,opts.cookie)}this.tree.persistence.activeKey=this.data.key;$(this.span).addClass(opts.classNames.active);if(fireEvents&&opts.onActivate){opts.onActivate.call(this.span,this)}}else{if(this.tree.activeNode===this){var opts=this.tree.options;if(opts.onQueryActivate&&opts.onQueryActivate.call(this.span,false,this)==f alse){return}$(this.span).removeClass(opts.classNames.active);if(opts.persist){$.cookie(opts.cookieId+"-active","",opts.cookie)}this.tree.persistence.activeKey=null;this.tree.activeNode=null;if(fireEvents&&opts.onDeactivate){opts.onDeactivate.call(this.span,this)}}}},activate:function(){this._activate(true,true)},deactivate:function(){this._activate(false,true)},isActive:function(){return(this.tree.activeNode===this)},_userActivate:function(){var activate=true;var expand=false;if(this.data.isFolder){switch(this.tree.options.clickFolderMode){case 2:activate=false;expand=true;break;case 3:activate=expand=true;break}}if(this.parent==null&&this.tree.options.minExpandLevel>0){expand=false}if(expand){this.toggleExpand();this.focus()}if(activate){this.activate()}},_setSubSel:function(hasSubSel){if(hasSubSel){this.hasSubSel=true;$(this.span).addClass(this.tree.options.classNames.partsel)}else{this.hasSubSel=false;$(this.span).removeClass(this.tree.options.classNames.partsel)}},_fixS electionState:function(){if(this.bSelected){this.visit(function(dtnode){dtnode.parent._setSubSel(true);dtnode._select(true,false,false)});var p=this.parent;while(p){p._setSubSel(true);var allChildsSelected=true;for(var i=0;i<p.childList.length;i++){var n=p.childList[i];if(!n.bSelected&&!n.data.isStatusNode){allChildsSelected=false;break}}if(allChildsSelected){p._select(true,false,false)}p=p.parent}}else{this._setSubSel(false);this.visit(function(dtnode){dtnode._setSubSel(false);dtnode._select(false,false,false)});var p=this.parent;while(p){p._select(false,false,false);var isPartSel=false;for(var i=0;i<p.childList.length;i++){if(p.childList[i].bSelected||p.childList[i].hasSubSel){isPartSel=true;break}}p._setSubSel(isPartSel);p=p.parent}}},_select:function(sel,fireEvents,deep){var opts=this.tree.options;if(this.data.isStatusNode){return}if(this.bSelected==sel){return}if(fireEvents&&opts.onQuerySelect&&opts.onQuerySelect.call(this.span,sel,this)==false){return}if(opts.selectMod e==1&&sel){this.tree.visit(function(dtnode){if(dtnode.bSelected){dtnode._select(false,false,false);return false}})}this.bSelected=sel;if(sel){if(opts.persist){this.tree.persistence.addSelect(this.data.key)}$(this.span).addClass(opts.classNames.selected);if(deep&&opts.selectMode==3){this._fixSelectionState()}if(fireEvents&&opts.onSelect){opts.onSelect.call(this.span,true,this)}}else{if(opts.persist){this.tree.persistence.clearSelect(this.data.key)}$(this.span).removeClass(opts.classNames.selected);if(deep&&opts.selectMode==3){this._fixSelectionState()}if(fireEvents&&opts.onSelect){opts.onSelect.call(this.span,false,this)}}},select:function(sel){if(this.data.unselectable){return this.bSelected}return this._select(sel!=false,true,true)},toggleSelect:function(){return this.select(!this.bSelected)},isSelected:function(){return this.bSelected},_loadContent:function(){try{var opts=this.tree.options;this.tree.logDebug("_loadContent: start - %o",this);this.setLazyNodeStatus(DTNodeSta tus_Loading);if(true==opts.onLazyRead.call(this.span,this)){this.setLazyNodeStatus(DTNodeStatus_Ok);this.tree.logDebug("_loadContent: succeeded - %o",this)}}catch(e){this.setLazyNodeStatus(DTNodeStatus_Error);this.tree.logWarning("_loadContent: failed - %o",e)}},_expand:function(bExpand){if(this.bExpanded==bExpand){return}var opts=this.tree.options;if(!bExpand&&this.getLevel()<opts.minExpandLevel){this.tree.logDebug("dtnode._expand(%o) forced expand - %o",bExpand,this);return}if(opts.onQueryExpand&&opts.onQueryExpand.call(this.span,bExpand,this)==false){return}this.bExpanded=bExpand;if(opts.persist){if(bExpand){this.tree.persistence.addExpand(this.data.key)}else{this.tree.persistence.clearExpand(this.data.key)}}this.render(false);if(this.bExpanded&&this.parent&&opts.autoCollapse){var parents=this._parentList(false,true);for(var i=0;i<parents.length;i++){parents[i].collapseSiblings()}}if(opts.activeVisible&&this.tree.activeNode&&!this.tree.activeNode.isVisible()){this.tree.ac tiveNode.deactivate()}if(bExpand&&this.data.isLazy&&this.childList==null&&!this.isLoading){this._loadContent();return}var fxDuration=opts.fx?(opts.fx.duration||200):0;if(this.childList){for(var i=0;i<this.childList.length;i++){var $child=$(this.childList[i].div);if(fxDuration){if(bExpand!=$child.is(":visible")){$child.animate(opts.fx,fxDuration)}}else{if(bExpand){$child.show()}else{$child.hide()}}}}if(opts.onExpand){opts.onExpand.call(this.span,bExpand,this)}},expand:function(flag){if(!this.childList&&!this.data.isLazy&&flag){return}if(this.parent==null&&this.tree.options.minExpandLevel>0&&!flag){return}this._expand(flag)},toggleExpand:function(){this.expand(!this.bExpanded)},collapseSiblings:function(){if(this.parent==null){return}var ac=this.parent.childList;for(var i=0;i<ac.length;i++){if(ac[i]!==this&&ac[i].bExpanded){ac[i]._expand(false)}}},onClick:function(event){var targetType=this.getEventTargetType(event);if(targetType=="expander"){this.toggleExpand();this.focus()}e lse{if(targetType=="checkbox"){this.toggleSelect();this.focus()}else{this._userActivate();this.span.getElementsByTagName("a")[0].focus()}}return false},onDblClick:function(event){},onKeydown:function(event){var handled=true;switch(event.which){case 107:case 187:if(!this.bExpanded){this.toggleExpand()}break;case 109:case 189:if(this.bExpanded){this.toggleExpand()}break;case 32:this._userActivate();break;case 8:if(this.parent){this.parent.focus()}break;case 37:if(this.bExpanded){this.toggleExpand();this.focus()}else{if(this.parent&&(this.tree.options.rootVisible||this.parent.parent)){this.parent.focus()}}break;case 39:if(!this.bExpanded&&(this.childList||this.data.isLazy)){this.toggleExpand();this.focus()}else{if(this.childList){this.childList[0].focus()}}break;case 38:var sib=this.prevSibling();while(sib&&sib.bExpanded&&sib.childList){sib=sib.childList[sib.childList.length-1]}if(!sib&&this.parent&&(this.tree.options.rootVisible||this.parent.parent)){sib=this.parent}if(sib){si b.focus()}break;case 40:var sib;if(this.bExpanded&&this.childList){sib=this.childList[0]}else{var parents=this._parentList(false,true);for(var i=parents.length-1;i>=0;i--){sib=parents[i].nextSibling();if(sib){break}}}if(sib){sib.focus()}break;default:handled=false}return !handled},onKeypress:function(event){},onFocus:function(event){var opts=this.tree.options;if(event.type=="blur"||event.type=="focusout"){if(opts.onBlur){opts.onBlur.call(this.span,this)}if(this.tree.tnFocused){$(this.tree.tnFocused.span).removeClass(opts.classNames.focused)}this.tree.tnFocused=null;if(opts.persist){$.cookie(opts.cookieId+"-focus","",opts.cookie)}}else{if(event.type=="focus"||event.type=="focusin"){if(this.tree.tnFocused&&this.tree.tnFocused!==this){this.tree.logDebug("dtnode.onFocus: out of sync: curFocus: %o",this.tree.tnFocused);$(this.tree.tnFocused.span).removeClass(opts.classNames.focused)}this.tree.tnFocused=this;if(opts.onFocus){opts.onFocus.call(this.span,this)}$(this.tree.tnFocused. span).addClass(opts.classNames.focused);if(opts.persist){$.cookie(opts.cookieId+"-focus",this.data.key,opts.cookie)}}}},visit:function(fn,data,includeSelf){var n=0;if(includeSelf==true){if(fn(this,data)==false){return 1}n++}if(this.childList){for(var i=0;i<this.childList.length;i++){n+=this.childList[i].visit(fn,data,true)}}return n},remove:function(){if(this===this.tree.root){return false}return this.parent.removeChild(this)},removeChild:function(tn){var ac=this.childList;if(ac.length==1){if(tn!==ac[0]){throw"removeChild: invalid child"}return this.removeChildren()}if(tn===this.tree.activeNode){tn.deactivate()}if(this.tree.options.persist){if(tn.bSelected){this.tree.persistence.clearSelect(tn.data.key)}if(tn.bExpanded){this.tree.persistence.clearExpand(tn.data.key)}}tn.removeChildren(true);this.div.removeChild(tn.div);for(var i=0;i<ac.length;i++){if(ac[i]===tn){this.childList.splice(i,1);delete tn;break}}},removeChildren:function(isRecursiveCall,retainPersistence){var tree= this.tree;var ac=this.childList;if(ac){for(var i=0;i<ac.length;i++){var tn=ac[i];if(tn===tree.activeNode&&!retainPersistence){tn.deactivate()}if(this.tree.options.persist&&!retainPersistence){if(tn.bSelected){this.tree.persistence.clearSelect(tn.data.key)}if(tn.bExpanded){this.tree.persistence.clearExpand(tn.data.key)}}tn.removeChildren(true,retainPersistence);this.div.removeChild(tn.div);delete tn}this.childList=null}if(!isRecursiveCall){this.isLoading=false;this.render(false,false)}},reload:function(force){if(this.parent==null){return this.tree.reload()}if(!this.data.isLazy){throw"node.reload() requires lazy nodes."}if(this.bExpanded){this.expand(false);this.removeChildren();this.expand(true)}else{this.removeChildren();if(force){this._loadContent()}}},_addChildNode:function(dtnode,beforeNode){var tree=this.tree;var opts=tree.options;var pers=tree.persistence;dtnode.parent=this;if(this.childList==null){this.childList=[]}else{if(!beforeNode){$(this.childList[this.childList.l ength-1].span).removeClass(opts.classNames.lastsib)}}if(beforeNode){var iBefore=$.inArray(beforeNode,this.childList);if(iBefore<0){throw"<beforeNode> must be a child of <this>"}this.childList.splice(iBefore,0,dtnode)}else{this.childList.push(dtnode)}var isInitializing=tree.isInitializing();if(opts.persist&&pers.cookiesFound&&isInitializing){if(pers.activeKey==dtnode.data.key){tree.activeNode=dtnode}if(pers.focusedKey==dtnode.data.key){tree.focusNode=dtnode}dtnode.bExpanded=($.inArray(dtnode.data.key,pers.expandedKeyList)>=0);dtnode.bSelected=($.inArray(dtnode.data.key,pers.selectedKeyList)>=0)}else{if(dtnode.data.activate){tree.activeNode=dtnode;if(opts.persist){pers.activeKey=dtnode.data.key}}if(dtnode.data.focus){tree.focusNode=dtnode;if(opts.persist){pers.focusedKey=dtnode.data.key}}dtnode.bExpanded=(dtnode.data.expand==true);if(dtnode.bExpanded&&opts.persist){pers.addExpand(dtnode.data.key)}dtnode.bSelected=(dtnode.data.select==true);if(dtnode.bSelected&&opts.persist){pe rs.addSelect(dtnode.data.key)}}if(opts.minExpandLevel>=dtnode.getLevel()){this.bExpanded=true}if(dtnode.bSelected&&opts.selectMode==3){var p=this;while(p){if(!p.hasSubSel){p._setSubSel(true)}p=p.parent}}if(tree.bEnableUpdate){this.render(true,true)}return dtnode},addChild:function(obj,beforeNode){if(!obj||obj.length==0){return}if(obj instanceof DynaTreeNode){return this._addChildNode(obj,beforeNode)}if(!obj.length){obj=[obj]}var prevFlag=this.tree.enableUpdate(false);var tnFirst=null;for(var i=0;i<obj.length;i++){var data=obj[i];var dtnode=this._addChildNode(new DynaTreeNode(this,this.tree,data),beforeNode);if(!tnFirst){tnFirst=dtnode}if(data.children){dtnode.addChild(data.children,null)}}this.tree.enableUpdate(prevFlag);return tnFirst},append:function(obj){this.tree.logWarning("node.append() is deprecated (use node.addChild() instead).");return this.addChild(obj,null)},appendAjax:function(ajaxOptions){this.removeChildren(false,true);this.setLazyNodeStatus(DTNodeStatus_Loadi ng);var self=this;var orgSuccess=ajaxOptions.success;var orgError=ajaxOptions.error;var options=$.extend({},this.tree.options.ajaxDefaults,ajaxOptions,{success:function(data,textStatus){var prevPhase=self.tree.phase;self.tree.phase="init";self.addChild(data,null);self.tree.phase="postInit";self.setLazyNodeStatus(DTNodeStatus_Ok);if(orgSuccess){orgSuccess.call(options,self)}self.tree.phase=prevPhase},error:function(XMLHttpRequest,textStatus,errorThrown){self.tree.logWarning("appendAjax failed:",textStatus,":\n",XMLHttpRequest,"\n",errorThrown);self.setLazyNodeStatus(DTNodeStatus_Error,{info:textStatus,tooltip:""+errorThrown});if(orgError){orgError.call(options,self,XMLHttpRequest,textStatus,errorThrown)}}});$.ajax(options)},lastentry:undefined};var DynaTreeStatus=Class.create();DynaTreeStatus._getTreePersistData=function(cookieId,cookieOpts){var ts=new DynaTreeStatus(cookieId,cookieOpts);ts.read();return ts.toDict()};getDynaTreePersistData=DynaTreeStatus._getTreePersistData;D ynaTreeStatus.prototype={initialize:function(cookieId,cookieOpts){this._log("DynaTreeStatus: initialize");if(cookieId===undefined){cookieId=$.ui.dynatree.defaults.cookieId}cookieOpts=$.extend({},$.ui.dynatree.defaults.cookie,cookieOpts);this.cookieId=cookieId;this.cookieOpts=cookieOpts;this.cookiesFound=undefined;this.activeKey=null;this.focusedKey=null;this.expandedKeyList=null;this.selectedKeyList=null},_log:function(msg){Array.prototype.unshift.apply(arguments,["debug"]);_log.apply(this,arguments)},read:function(){this._log("DynaTreeStatus: read");this.cookiesFound=false;var cookie=$.cookie(this.cookieId+"-active");this.activeKey=(cookie==null)?"":cookie;if(cookie!=null){this.cookiesFound=true}cookie=$.cookie(this.cookieId+"-focus");this.focusedKey=(cookie==null)?"":cookie;if(cookie!=null){this.cookiesFound=true}cookie=$.cookie(this.cookieId+"-expand");this.expandedKeyList=(cookie==null)?[]:cookie.split(",");if(cookie!=null){this.cookiesFound=true}cookie=$.cookie(this.coo kieId+"-select");this.selectedKeyList=(cookie==null)?[]:cookie.split(",");if(cookie!=null){this.cookiesFound=true}},write:function(){this._log("DynaTreeStatus: write");$.cookie(this.cookieId+"-active",(this.activeKey==null)?"":this.activeKey,this.cookieOpts);$.cookie(this.cookieId+"-focus",(this.focusedKey==null)?"":this.focusedKey,this.cookieOpts);$.cookie(this.cookieId+"-expand",(this.expandedKeyList==null)?"":this.expandedKeyList.join(","),this.cookieOpts);$.cookie(this.cookieId+"-select",(this.selectedKeyList==null)?"":this.selectedKeyList.join(","),this.cookieOpts)},addExpand:function(key){this._log("addExpand(%o)",key);if($.inArray(key,this.expandedKeyList)<0){this.expandedKeyList.push(key);$.cookie(this.cookieId+"-expand",this.expandedKeyList.join(","),this.cookieOpts)}},clearExpand:function(key){this._log("clearExpand(%o)",key);var idx=$.inArray(key,this.expandedKeyList);if(idx>=0){this.expandedKeyList.splice(idx,1);$.cookie(this.cookieId+"-expand",this.expandedKeyLi st.join(","),this.cookieOpts)}},addSelect:function(key){this._log("addSelect(%o)",key);if($.inArray(key,this.selectedKeyList)<0){this.selectedKeyList.push(key);$.cookie(this.cookieId+"-select",this.selectedKeyList.join(","),this.cookieOpts)}},clearSelect:function(key){this._log("clearSelect(%o)",key);var idx=$.inArray(key,this.selectedKeyList);if(idx>=0){this.selectedKeyList.splice(idx,1);$.cookie(this.cookieId+"-select",this.selectedKeyList.join(","),this.cookieOpts)}},isReloading:function(){return this.cookiesFound==true},toDict:function(){return{cookiesFound:this.cookiesFound,activeKey:this.activeKey,focusedKey:this.activeKey,expandedKeyList:this.expandedKeyList,selectedKeyList:this.selectedKeyList}},lastentry:undefined};var DynaTree=Class.create();DynaTree.version="$Version: 0.5.4$";DynaTree.prototype={initialize:function($widget){this.phase="init";this.$widget=$widget;this.options=$widget.options;this.$tree=$widget.element;this.divTree=this.$tree.get(0)},_load:function( ){var $widget=this.$widget;var opts=this.options;this.bEnableUpdate=true;this._nodeCount=1;this.activeNode=null;this.focusNode=null;if(opts.classNames!==$.ui.dynatree.defaults.classNames){opts.classNames=$.extend({},$.ui.dynatree.defaults.classNames,opts.classNames)}if(!opts.imagePath){$("script").each(function(){if(this.src.search(_rexDtLibName)>=0){if(this.src.indexOf("/")>=0){opts.imagePath=this.src.slice(0,this.src.lastIndexOf("/"))+"/skin/"}else{opts.imagePath="skin/"}return false}})}this.persistence=new DynaTreeStatus(opts.cookieId,opts.cookie);if(opts.persist){if(!$.cookie){_log("warn","Please include jquery.cookie.js to use persistence.")}this.persistence.read()}this.logDebug("DynaTree.persistence: %o",this.persistence.toDict());this.cache={tagEmpty:"<span class='"+opts.classNames.empty+"'></span>",tagVline:"<span class='"+opts.classNames.vline+"'></span>",tagExpander:"<span class='"+opts.classNames.expander+"'></span>",tagConnector:"<span class='"+opts.classNames.co nnector+"'></span>",tagNodeIcon:"<span class='"+opts.classNames.nodeIcon+"'></span>",tagCheckbox:"<span class='"+opts.classNames.checkbox+"'></span>",lastentry:undefined};if(opts.children||(opts.initAjax&&opts.initAjax.url)||opts.initId){$(this.divTree).empty()}else{if(this.divRoot){$(this.divRoot).remove()}}this.tnRoot=new DynaTreeNode(null,this,{title:opts.title,key:"root"});this.tnRoot.data.isFolder=true;this.tnRoot.render(false,false);this.divRoot=this.tnRoot.div;this.divRoot.className=opts.classNames.container;this.divTree.appendChild(this.divRoot);var root=this.tnRoot;var isReloading=(opts.persist&&this.persistence.isReloading());var isLazy=false;var prevFlag=this.enableUpdate(false);this.logDebug("Dynatree._load(): read tree structure...");if(opts.children){root.addChild(opts.children)}else{if(opts.initAjax&&opts.initAjax.url){isLazy=true;root.data.isLazy=true;this._reloadAjax()}else{if(opts.initId){this._createFromTag(root,$("#"+opts.initId))}else{var $ul=this.$tree. find(">ul").hide();this._createFromTag(root,$ul);$ul.remove()}}}this._checkConsistency();this.logDebug("Dynatree._load(): render nodes...");this.enableUpdate(prevFlag);this.logDebug("Dynatree._load(): bind events...");this.$widget.bind();this.logDebug("Dynatree._load(): postInit...");this.phase="postInit";if(opts.persist){this.persistence.write()}if(this.focusNode&&this.focusNode.isVisible()){this.logDebug("Focus on init: %o",this.focusNode);this.focusNode.focus()}if(!isLazy&&opts.onPostInit){opts.onPostInit.call(this,isReloading,false)}this.phase="idle"},_reloadAjax:function(){var opts=this.options;if(!opts.initAjax||!opts.initAjax.url){throw"tree.reload() requires 'initAjax' mode."}var pers=this.persistence;var ajaxOpts=$.extend({},opts.initAjax);if(ajaxOpts.addActiveKey){ajaxOpts.data.activeKey=pers.activeKey}if(ajaxOpts.addFocusedKey){ajaxOpts.data.focusedKey=pers.focusedKey}if(ajaxOpts.addExpandedKeyList){ajaxOpts.data.expandedKeyList=pers.expandedKeyList.join(",")}if(a jaxOpts.addSelectedKeyList){ajaxOpts.data.selectedKeyList=pers.selectedKeyList.join(",")}if(opts.onPostInit){if(ajaxOpts.success){this.logWarning("initAjax: success callback is ignored when onPostInit was specified.")}if(ajaxOpts.error){this.logWarning("initAjax: error callback is ignored when onPostInit was specified.")}var isReloading=pers.isReloading();ajaxOpts.success=function(dtnode){opts.onPostInit.call(dtnode.tree,isReloading,false)};ajaxOpts.error=function(dtnode){opts.onPostInit.call(dtnode.tree,isReloading,true)}}this.logDebug("Dynatree._init(): send Ajax request...");this.tnRoot.appendAjax(ajaxOpts)},toString:function(){return"DynaTree '"+this.options.title+"'"},toDict:function(){return this.tnRoot.toDict(true)},getPersistData:function(){return this.persistence.toDict()},logDebug:function(msg){if(this.options.debugLevel>=2){Array.prototype.unshift.apply(arguments,["debug"]);_log.apply(this,arguments)}},logInfo:function(msg){if(this.options.debugLevel>=1){Array.pro totype.unshift.apply(arguments,["info"]);_log.apply(this,arguments)}},logWarning:function(msg){Array.prototype.unshift.apply(arguments,["warn"]);_log.apply(this,arguments)},isInitializing:function(){return(this.phase=="init"||this.phase=="postInit")},isReloading:function(){return(this.phase=="init"||this.phase=="postInit")&&this.options.persist&&this.persistence.cookiesFound},isUserEvent:function(){return(this.phase=="userEvent")},redraw:function(){this.logDebug("dynatree.redraw()...");this.tnRoot.render(true,true);this.logDebug("dynatree.redraw() done.")},reloadAjax:function(){this.logWarning("tree.reloadAjax() is deprecated since v0.5.2 (use reload() instead).")},reload:function(){this._load()},getRoot:function(){return this.tnRoot},getNodeByKey:function(key){var el=document.getElementById(this.options.idPrefix+key);return(el&&el.dtnode)?el.dtnode:null},getActiveNode:function(){return this.activeNode},reactivate:function(setFocus){var node=this.activeNode;if(node){this.act iveNode=null;node.activate();if(setFocus){node.focus()}}},getSelectedNodes:function(stopOnParents){var nodeList=[];this.tnRoot.visit(function(dtnode){if(dtnode.bSelected){nodeList.push(dtnode);if(stopOnParents==true){return false}}});return nodeList},activateKey:function(key){var dtnode=(key===null)?null:this.getNodeByKey(key);if(!dtnode){if(this.activeNode){this.activeNode.deactivate()}this.activeNode=null;return null}dtnode.focus();dtnode.activate();return dtnode},selectKey:function(key,select){var dtnode=this.getNodeByKey(key);if(!dtnode){return null}dtnode.select(select);return dtnode},enableUpdate:function(bEnable){if(this.bEnableUpdate==bEnable){return bEnable}this.bEnableUpdate=bEnable;if(bEnable){this.redraw()}return !bEnable},visit:function(fn,data,includeRoot){return this.tnRoot.visit(fn,data,includeRoot)},_createFromTag:function(parentTreeNode,$ulParent){var self=this;$ulParent.find(">li").each(function(){var $li=$(this);var $liSpan=$li.find(">span:first");var tit le;if($liSpan.length){title=$liSpan.html()}else{title=$li.html();var iPos=title.search(/<ul/i);if(iPos>=0){title=$.trim(title.substring(0,iPos))}else{title=$.trim(title)}}var data={title:title,isFolder:$li.hasClass("folder"),isLazy:$li.hasClass("lazy"),expand:$li.hasClass("expanded"),select:$li.hasClass("selected"),activate:$li.hasClass("active"),focus:$li.hasClass("focused")};if($li.attr("title")){data.tooltip=$li.attr("title")}if($li.attr("id")){data.key=$li.attr("id")}if($li.attr("data")){var dataAttr=$.trim($li.attr("data"));if(dataAttr){if(dataAttr.charAt(0)!="{"){dataAttr="{"+dataAttr+"}"}try{$.extend(data,eval("("+dataAttr+")"))}catch(e){throw ("Error parsing node data: "+e+"\ndata:\n'"+dataAttr+"'")}}}childNode=parentTreeNode.addChild(data);var $ul=$li.find(">ul:first");if($ul.length){self._createFromTag(childNode,$ul)}})},_checkConsistency:function(){},lastentry:undefined};$.widget("ui.dynatree",{init:function(){_log("warn","ui.dynatree.init() was called; you should upgrade to ui.core.js v1.6 or higher.");return this._init()},_init:function(){if(parseFloat($.ui.version)<1.8){_log("info","ui.dynatree._init() was called; consider upgrading to jquery.ui.core.js v1.8 or higher.");return this._create()}_log("debug","ui.dynatree._init() was called; no current default functionality.")},_create:function(){if(parseFloat($.ui.version)>=1.8){this.options=$.extend(true,{},$[this.namespace][this.widgetName].defaults,this.options)}logMsg("Dynatree._create(): version='%s', debugLevel=%o.",DynaTree.version,this.options.debugLevel);var opts=this.options;this.options.event+=".dynatree";var divTree=this.element.get(0);this.tree=new DynaTree(this);this.tree._load();this.tree.logDebug("Dynatree._create(): done.")},bind:function(){var $this=this.element;var o=this.options;this.unbind();function __getNodeFromElement(el){var iMax=5;while(el&&iMax--){if(el.dtnode){return el.dtnode}el=el.parentNode}return null}var eventNames="click.dynatree dblclick.dynatree";i f(o.keyboard){eventNames+=" keypress.dynatree keydown.dynatree"}$this.bind(eventNames,function(event){var dtnode=__getNodeFromElement(event.target);if(!dtnode){return true}var prevPhase=dtnode.tree.phase;dtnode.tree.phase="userEvent";try{dtnode.tree.logDebug("bind(%o): dtnode: %o",event,dtnode);switch(event.type){case"click":return(o.onClick&&o.onClick(dtnode,event)===false)?false:dtnode.onClick(event);case"dblclick":return(o.onDblClick&&o.onDblClick(dtnode,event)===false)?false:dtnode.onDblClick(event);case"keydown":return(o.onKeydown&&o.onKeydown(dtnode,event)===false)?false:dtnode.onKeydown(event);case"keypress":return(o.onKeypress&&o.onKeypress(dtnode,event)===false)?false:dtnode.onKeypress(event)}}catch(e){var _=null}finally{dtnode.tree.phase=prevPhase}});function __focusHandler(event){event=arguments[0]=$.event.fix(event||window.event);var dtnode=__getNodeFromElement(event.target);return dtnode?dtnode.onFocus(event):false}var div=this.tree.divTree;if(div.addEventListen er){div.addEventListener("focus",__focusHandler,true);div.addEventListener("blur",__focusHandler,true)}else{div.onfocusin=div.onfocusout=__focusHandler}},unbind:function(){this.element.unbind(".dynatree")},enable:function(){this.bind();$.widget.prototype.enable.apply(this,arguments)},disable:function(){this.unbind();$.widget.prototype.disable.apply(this,arguments)},getTree:function(){return this.tree},getRoot:function(){return this.tree.getRoot()},getActiveNode:function(){return this.tree.getActiveNode()},getSelectedNodes:function(){return this.tree.getSelectedNodes()},lastentry:undefined});$.ui.dynatree.getter="getTree getRoot getActiveNode getSelectedNodes";$.ui.dynatree.defaults={title:"Dynatree root",rootVisible:false,minExpandLevel:1,imagePath:null,children:null,initId:null,initAjax:null,autoFocus:true,keyboard:true,persist:false,autoCollapse:false,clickFolderMode:3,activeVisible:true,checkbox:false,selectMode:2,fx:null,onClick:null,onDblClick:null,onKeydown:null,onKeyp ress:null,onFocus:null,onBlur:null,onQueryActivate:null,onQuerySelect:null,onQueryExpand:null,onPostInit:null,onActivate:null,onDeactivate:null,onSelect:null,onExpand:null,onLazyRead:null,ajaxDefaults:{cache:false,dataType:"json"},strings:{loading:"Loading…",loadError:"Load error!"},idPrefix:"ui-dynatree-id-",cookieId:"dynatree",cookie:{expires:null},classNames:{container:"ui-dynatree-container",folder:"ui-dynatree-folder",document:"ui-dynatree-document",empty:"ui-dynatree-empty",vline:"ui-dynatree-vline",expander:"ui-dynatree-expander",connector:"ui-dynatree-connector",checkbox:"ui-dynatree-checkbox",nodeIcon:"ui-dynatree-icon",title:"ui-dynatree-title",nodeError:"ui-dynatree-statusnode-error",nodeWait:"ui-dynatree-statusnode-wait",hidden:"ui-dynatree-hidden",combinedExpanderPrefix:"ui-dynatree-exp-",combinedIconPrefix:"ui-dynatree-ico-",hasChildren:"ui-dynatree-has-children",active:"ui-dynatree-active",selected:"ui-dynatree-selected",expanded:"ui-dynatree-expanded",l azy:"ui-dynatree-lazy",focused:"ui-dynatree-focused",partsel:"ui-dynatree-partsel",lastsib:"ui-dynatree-lastsib"},debugLevel:1,lastentry:undefined};$.ui.dynatree.nodedatadefaults={title:null,key:null,isFolder:false,isLazy:false,tooltip:null,icon:null,addClass:null,activate:false,focus:false,expand:false,select:false,hideCheckbox:false,unselectable:false,children:null,lastentry:undefined}})(jQuery);var _rexDtLibName=/.*dynatree[^/]*\.js$/i; Binary file static/june_2007_style/blue/dynatree_skin/rbChecked.gif has changed --- /dev/null +++ b/static/scripts/jquery.dynatree.js @@ -0,0 +1,2034 @@ +/************************************************************************* + jquery.dynatree.js + Dynamic tree view control, with support for lazy loading of branches. + + Copyright (c) 2008-2010, Martin Wendt (http://wwWendt.de) + Dual licensed under the MIT or GPL Version 2 licenses. + http://code.google.com/p/dynatree/wiki/LicenseInfo + + A current version and some documentation is available at + http://dynatree.googlecode.com/ + + $Version: 0.5.4$ + $Revision: 329, 2010-05-05 08:04:39$ + + @depends: jquery.js + @depends: ui.core.js + @depends: jquery.cookie.js +*************************************************************************/ + + +/************************************************************************* + * Debug functions + */ + +var _canLog = true; + +function _log(mode, msg) { + /** + * Usage: logMsg("%o was toggled", this); + */ + if( !_canLog ) + return; + // Remove first argument + var args = Array.prototype.slice.apply(arguments, [1]); + // Prepend timestamp + var dt = new Date(); + var tag = dt.getHours()+":"+dt.getMinutes()+":"+dt.getSeconds()+"."+dt.getMilliseconds(); + args[0] = tag + " - " + args[0]; + + try { + switch( mode ) { + case "info": + window.console.info.apply(window.console, args); + break; + case "warn": + window.console.warn.apply(window.console, args); + break; + default: + window.console.log.apply(window.console, args); + } + } catch(e) { + if( !window.console ) + _canLog = false; // Permanently disable, when logging is not supported by the browser + } +} + +function logMsg(msg) { + Array.prototype.unshift.apply(arguments, ["debug"]); + _log.apply(this, arguments); +} + + +// Forward declaration +var getDynaTreePersistData = undefined; + + + +/************************************************************************* + * Constants + */ +var DTNodeStatus_Error = -1; +var DTNodeStatus_Loading = 1; +var DTNodeStatus_Ok = 0; + + +// Start of local namespace +;(function($) { + +/************************************************************************* + * Common tool functions. + */ + +var Class = { + create: function() { + return function() { + this.initialize.apply(this, arguments); + } + } +} + +/************************************************************************* + * Class DynaTreeNode + */ +var DynaTreeNode = Class.create(); + +DynaTreeNode.prototype = { + initialize: function(parent, tree, data) { + /** + * @constructor + */ + this.parent = parent; + this.tree = tree; + if ( typeof data == "string" ) + data = { title: data }; + if( data.key == undefined ) + data.key = "_" + tree._nodeCount++; + this.data = $.extend({}, $.ui.dynatree.nodedatadefaults, data); + this.div = null; // not yet created + this.span = null; // not yet created + this.childList = null; // no subnodes yet +// this.isRead = false; // Lazy content not yet read + this.isLoading = false; // Lazy content is being loaded + this.hasSubSel = false; + }, + + toString: function() { + return "dtnode<" + this.data.key + ">: '" + this.data.title + "'"; + }, + + toDict: function(recursive, callback) { + var dict = $.extend({}, this.data); + dict.activate = ( this.tree.activeNode === this ); + dict.focus = ( this.tree.focusNode === this ); + dict.expand = this.bExpanded; + dict.select = this.bSelected; + if( callback ) + callback(dict); + if( recursive && this.childList ) { + dict.children = []; + for(var i=0; i<this.childList.length; i++ ) + dict.children.push(this.childList[i].toDict(true, callback)); + } else { + delete dict.children; + } + return dict; + }, + + _getInnerHtml: function() { + var opts = this.tree.options; + var cache = this.tree.cache; + // parent connectors + var rootParent = opts.rootVisible ? null : this.tree.tnRoot; + var bHideFirstExpander = (opts.rootVisible && opts.minExpandLevel>0) || opts.minExpandLevel>1; + var bHideFirstConnector = opts.rootVisible || opts.minExpandLevel>0; + + var res = ""; + var p = this.parent; + while( p ) { + // Suppress first connector column, if visible top level is always expanded + if ( bHideFirstConnector && p==rootParent ) + break; + res = ( p.isLastSibling() ? cache.tagEmpty : cache.tagVline) + res; + p = p.parent; + } + + // connector (expanded, expandable or simple) + if( bHideFirstExpander && this.parent==rootParent ) { + // skip connector + } else if ( this.childList || this.data.isLazy ) { + res += cache.tagExpander; + } else { + res += cache.tagConnector; + } + + // Checkbox mode + if( opts.checkbox && this.data.hideCheckbox!=true && !this.data.isStatusNode ) { + res += cache.tagCheckbox; + } + + // folder or doctype icon + if ( this.data.icon ) { + res += "<img src='" + opts.imagePath + this.data.icon + "' alt='' />"; + } else if ( this.data.icon == false ) { + // icon == false means 'no icon' + } else { + // icon == null means 'default icon' + res += cache.tagNodeIcon; + } + + // node name + var tooltip = ( this.data && typeof this.data.tooltip == "string" ) ? " title='" + this.data.tooltip + "'" : ""; + res += "<a href='#' class='" + opts.classNames.title + "'" + tooltip + ">" + this.data.title + "</a>"; + return res; + }, + + _fixOrder: function() { + /** + * Make sure, that <div> order matches childList order. + */ + var cl = this.childList; + if( !cl ) + return; + var childDiv = this.div.firstChild.nextSibling; + for(var i=0; i<cl.length-1; i++) { + var childNode1 = cl[i]; + var childNode2 = childDiv.firstChild.dtnode; + if( childNode1 !== childNode2 ) { + this.tree.logDebug("_fixOrder: mismatch at index " + i + ": " + childNode1 + " != " + childNode2); + this.div.insertBefore(childNode1.div, childNode2.div); + } else { + childDiv = childDiv.nextSibling; + } + } + }, + + render: function(bDeep, bHidden) { + /** + * Create HTML markup for this node. + * + * <div> // This div contains the node's span and list of child div's. + * <span id='key'>S S S A</span> // Span contains graphic spans and title <a> tag + * <div>child1</div> + * <div>child2</div> + * </div> + */ +// this.tree.logDebug("%o.render()", this); + var opts = this.tree.options; + var cn = opts.classNames; + var isLastSib = this.isLastSibling(); + // --- + if( ! this.div ) { + this.span = document.createElement("span"); + this.span.dtnode = this; + if( this.data.key ) + this.span.id = this.tree.options.idPrefix + this.data.key; + this.div = document.createElement("div"); + this.div.appendChild(this.span); + + if ( this.parent ) { + this.parent.div.appendChild(this.div); + } + + if( this.parent==null && !this.tree.options.rootVisible ) + this.span.style.display = "none"; + } + // set node connector images, links and text + this.span.innerHTML = this._getInnerHtml(); + + // hide this node, if parent is collapsed + this.div.style.display = ( this.parent==null || this.parent.bExpanded ? "" : "none"); + + // Set classes for current status + var cnList = []; + cnList.push( ( this.data.isFolder ) ? cn.folder : cn.document ); + if( this.bExpanded ) + cnList.push(cn.expanded); + if( this.childList != null ) + cnList.push(cn.hasChildren); + if( this.data.isLazy && this.childList==null ) + cnList.push(cn.lazy); + if( isLastSib ) + cnList.push(cn.lastsib); + if( this.bSelected ) + cnList.push(cn.selected); + if( this.hasSubSel ) + cnList.push(cn.partsel); + if( this.tree.activeNode === this ) + cnList.push(cn.active); + if( this.data.addClass ) + cnList.push(this.data.addClass); + // IE6 doesn't correctly evaluate multiple class names, + // so we create combined class names that can be used in the CSS + cnList.push(cn.combinedExpanderPrefix + + (this.bExpanded ? "e" : "c") + + (this.data.isLazy && this.childList==null ? "d" : "") + + (isLastSib ? "l" : "") + ); + cnList.push(cn.combinedIconPrefix + + (this.bExpanded ? "e" : "c") + + (this.data.isFolder ? "f" : "") + ); + this.span.className = cnList.join(" "); + + if( bDeep && this.childList && (bHidden || this.bExpanded) ) { + for(var i=0; i<this.childList.length; i++) { + this.childList[i].render(bDeep, bHidden) + } + this._fixOrder(); + } + }, + + hasChildren: function() { + return this.childList != null; + }, + + isLastSibling: function() { + var p = this.parent; + if ( !p ) return true; + return p.childList[p.childList.length-1] === this; + }, + + prevSibling: function() { + if( !this.parent ) return null; + var ac = this.parent.childList; + for(var i=1; i<ac.length; i++) // start with 1, so prev(first) = null + if( ac[i] === this ) + return ac[i-1]; + return null; + }, + + nextSibling: function() { + if( !this.parent ) return null; + var ac = this.parent.childList; + for(var i=0; i<ac.length-1; i++) // up to length-2, so next(last) = null + if( ac[i] === this ) + return ac[i+1]; + return null; + }, + + _setStatusNode: function(data) { + // Create, modify or remove the status child node (pass 'null', to remove it). + var firstChild = ( this.childList ? this.childList[0] : null ); + if( !data ) { + if ( firstChild ) { + this.div.removeChild(firstChild.div); + if( this.childList.length == 1 ) + this.childList = null; + else + this.childList.shift(); + } + } else if ( firstChild ) { + data.isStatusNode = true; + firstChild.data = data; + firstChild.render(false, false); + } else { + data.isStatusNode = true; + firstChild = this.addChild(data); + } + }, + + setLazyNodeStatus: function(lts, opts) { + var tooltip = (opts && opts.tooltip) ? opts.tooltip : null; + var info = (opts && opts.info) ? " (" + opts.info + ")" : ""; + switch( lts ) { + case DTNodeStatus_Ok: + this._setStatusNode(null); +// this.isRead = true; + this.isLoading = false; + this.render(false, false); + if( this.tree.options.autoFocus ) { + if( this === this.tree.tnRoot && !this.tree.options.rootVisible && this.childList ) { + // special case: using ajaxInit + this.childList[0].focus(); + } else { + this.focus(); + } + } + break; + case DTNodeStatus_Loading: + this.isLoading = true; + this._setStatusNode({ + title: this.tree.options.strings.loading + info, + tooltip: tooltip, + addClass: this.tree.options.classNames.nodeWait + }); + break; + case DTNodeStatus_Error: + this.isLoading = false; + this._setStatusNode({ + title: this.tree.options.strings.loadError + info, + tooltip: tooltip, + addClass: this.tree.options.classNames.nodeError + }); + break; + default: + throw "Bad LazyNodeStatus: '" + lts + "'."; + } + }, + + _parentList: function(includeRoot, includeSelf) { + var l = []; + var dtn = includeSelf ? this : this.parent; + while( dtn ) { + if( includeRoot || dtn.parent ) + l.unshift(dtn); + dtn = dtn.parent; + }; + return l; + }, + + getLevel: function() { + var level = 0; + var dtn = this.parent; + while( dtn ) { + level++; + dtn = dtn.parent; + }; + return level; + }, + + _getTypeForOuterNodeEvent: function(event) { + /** Return the inner node span (title, checkbox or expander) if + * event.target points to the outer span. + * This function should fix issue #93: + * FF2 ignores empty spans, when generating events (returning the parent instead). + */ + var cns = this.tree.options.classNames; + var target = event.target; + // Only process clicks on an outer node span (probably due to a FF2 event handling bug) + if( target.className.indexOf(cns.folder)<0 + && target.className.indexOf(cns.document)<0 ) { + return null + } + // Event coordinates, relative to outer node span: + var eventX = event.pageX - target.offsetLeft; + var eventY = event.pageY - target.offsetTop; + + for(var i=0; i<target.childNodes.length; i++) { + var cn = target.childNodes[i]; + var x = cn.offsetLeft - target.offsetLeft; + var y = cn.offsetTop - target.offsetTop; + var nx = cn.clientWidth, ny = cn.clientHeight; +// alert (cn.className + ": " + x + ", " + y + ", s:" + nx + ", " + ny); + if( eventX>=x && eventX<=(x+nx) && eventY>=y && eventY<=(y+ny) ) { +// alert("HIT "+ cn.className); + if( cn.className==cns.title ) + return "title"; + else if( cn.className==cns.expander ) + return "expander"; + else if( cn.className==cns.checkbox ) + return "checkbox"; + else if( cn.className==cns.nodeIcon ) + return "icon"; + } + } + return "prefix"; + }, + + getEventTargetType: function(event) { + // Return the part of a node, that a click event occured on. + // Note: there is no check, if the was fired on TIHS node. + var tcn = event && event.target ? event.target.className : ""; + var cns = this.tree.options.classNames; + + if( tcn == cns.title ) + return "title"; + else if( tcn==cns.expander ) + return "expander"; + else if( tcn==cns.checkbox ) + return "checkbox"; + else if( tcn==cns.nodeIcon ) + return "icon"; + else if( tcn==cns.empty || tcn==cns.vline || tcn==cns.connector ) + return "prefix"; + else if( tcn.indexOf(cns.folder)>=0 || tcn.indexOf(cns.document)>=0 ) + // FIX issue #93 + return this._getTypeForOuterNodeEvent(event); + return null; + }, + + isVisible: function() { + // Return true, if all parents are expanded. + var parents = this._parentList(true, false); + for(var i=0; i<parents.length; i++) + if( ! parents[i].bExpanded ) return false; + return true; + }, + + makeVisible: function() { + // Make sure, all parents are expanded + var parents = this._parentList(true, false); + for(var i=0; i<parents.length; i++) + parents[i]._expand(true); + }, + + focus: function() { + // TODO: check, if we already have focus +// this.tree.logDebug("dtnode.focus(): %o", this); + this.makeVisible(); + try { + $(this.span).find(">a").focus(); + } catch(e) { } + }, + + _activate: function(flag, fireEvents) { + // (De)Activate - but not focus - this node. + this.tree.logDebug("dtnode._activate(%o, fireEvents=%o) - %o", flag, fireEvents, this); + var opts = this.tree.options; + if( this.data.isStatusNode ) + return; + if ( fireEvents && opts.onQueryActivate && opts.onQueryActivate.call(this.span, flag, this) == false ) + return; // Callback returned false + + if( flag ) { + // Activate + if( this.tree.activeNode ) { + if( this.tree.activeNode === this ) + return; + this.tree.activeNode.deactivate(); + } + if( opts.activeVisible ) + this.makeVisible(); + this.tree.activeNode = this; + if( opts.persist ) + $.cookie(opts.cookieId+"-active", this.data.key, opts.cookie); + this.tree.persistence.activeKey = this.data.key; + $(this.span).addClass(opts.classNames.active); + if ( fireEvents && opts.onActivate ) // Pass element as 'this' (jQuery convention) + opts.onActivate.call(this.span, this); + } else { + // Deactivate + if( this.tree.activeNode === this ) { + var opts = this.tree.options; + if ( opts.onQueryActivate && opts.onQueryActivate.call(this.span, false, this) == false ) + return; // Callback returned false + $(this.span).removeClass(opts.classNames.active); + if( opts.persist ) { + // Note: we don't pass null, but ''. So the cookie is not deleted. + // If we pass null, we also have to pass a COPY of opts, because $cookie will override opts.expires (issue 84) + $.cookie(opts.cookieId+"-active", "", opts.cookie); + } + this.tree.persistence.activeKey = null; + this.tree.activeNode = null; + if ( fireEvents && opts.onDeactivate ) + opts.onDeactivate.call(this.span, this); + } + } + }, + + activate: function() { + // Select - but not focus - this node. +// this.tree.logDebug("dtnode.activate(): %o", this); + this._activate(true, true); + }, + + deactivate: function() { +// this.tree.logDebug("dtnode.deactivate(): %o", this); + this._activate(false, true); + }, + + isActive: function() { + return (this.tree.activeNode === this); + }, + + _userActivate: function() { + // Handle user click / [space] / [enter], according to clickFolderMode. + var activate = true; + var expand = false; + if ( this.data.isFolder ) { + switch( this.tree.options.clickFolderMode ) { + case 2: + activate = false; + expand = true; + break; + case 3: + activate = expand = true; + break; + } + } + if( this.parent == null && this.tree.options.minExpandLevel>0 ) { + expand = false; + } + if( expand ) { + this.toggleExpand(); + this.focus(); + } + if( activate ) { + this.activate(); + } + }, + + _setSubSel: function(hasSubSel) { + if( hasSubSel ) { + this.hasSubSel = true; + $(this.span).addClass(this.tree.options.classNames.partsel); + } else { + this.hasSubSel = false; + $(this.span).removeClass(this.tree.options.classNames.partsel); + } + }, + + _fixSelectionState: function() { + // fix selection status, for multi-hier mode +// this.tree.logDebug("_fixSelectionState(%o) - %o", this.bSelected, this); + if( this.bSelected ) { + // Select all children + this.visit(function(dtnode){ + dtnode.parent._setSubSel(true); + dtnode._select(true, false, false); + }); + // Select parents, if all children are selected + var p = this.parent; + while( p ) { + p._setSubSel(true); + var allChildsSelected = true; + for(var i=0; i<p.childList.length; i++) { + var n = p.childList[i]; + if( !n.bSelected && !n.data.isStatusNode ) { + allChildsSelected = false; + break; + } + } + if( allChildsSelected ) + p._select(true, false, false); + p = p.parent; + } + } else { + // Deselect all children + this._setSubSel(false); + this.visit(function(dtnode){ + dtnode._setSubSel(false); + dtnode._select(false, false, false); + }); + // Deselect parents, and recalc hasSubSel + var p = this.parent; + while( p ) { + p._select(false, false, false); + var isPartSel = false; + for(var i=0; i<p.childList.length; i++) { + if( p.childList[i].bSelected || p.childList[i].hasSubSel ) { + isPartSel = true; + break; + } + } + p._setSubSel(isPartSel); + p = p.parent; + } + } + }, + + _select: function(sel, fireEvents, deep) { + // Select - but not focus - this node. +// this.tree.logDebug("dtnode._select(%o) - %o", sel, this); + var opts = this.tree.options; + if( this.data.isStatusNode ) + return; + // + if( this.bSelected == sel ) { +// this.tree.logDebug("dtnode._select(%o) IGNORED - %o", sel, this); + return; + } + // Allow event listener to abort selection + if ( fireEvents && opts.onQuerySelect && opts.onQuerySelect.call(this.span, sel, this) == false ) + return; // Callback returned false + + // Force single-selection + if( opts.selectMode==1 && sel ) { + this.tree.visit(function(dtnode){ + if( dtnode.bSelected ) { + // Deselect; assuming that in selectMode:1 there's max. one other selected node + dtnode._select(false, false, false); + return false; + } + }); + } + + this.bSelected = sel; +// this.tree._changeNodeList("select", this, sel); + + if( sel ) { + if( opts.persist ) + this.tree.persistence.addSelect(this.data.key); + + $(this.span).addClass(opts.classNames.selected); + + if( deep && opts.selectMode==3 ) + this._fixSelectionState(); + + if ( fireEvents && opts.onSelect ) + opts.onSelect.call(this.span, true, this); + + } else { + if( opts.persist ) + this.tree.persistence.clearSelect(this.data.key); + + $(this.span).removeClass(opts.classNames.selected); + + if( deep && opts.selectMode==3 ) + this._fixSelectionState(); + + if ( fireEvents && opts.onSelect ) + opts.onSelect.call(this.span, false, this); + } + }, + + select: function(sel) { + // Select - but not focus - this node. +// this.tree.logDebug("dtnode.select(%o) - %o", sel, this); + if( this.data.unselectable ) + return this.bSelected; + return this._select(sel!=false, true, true); + }, + + toggleSelect: function() { +// this.tree.logDebug("dtnode.toggleSelect() - %o", this); + return this.select(!this.bSelected); + }, + + isSelected: function() { + return this.bSelected; + }, + + _loadContent: function() { + try { + var opts = this.tree.options; + this.tree.logDebug("_loadContent: start - %o", this); + this.setLazyNodeStatus(DTNodeStatus_Loading); + if( true == opts.onLazyRead.call(this.span, this) ) { + // If function returns 'true', we assume that the loading is done: + this.setLazyNodeStatus(DTNodeStatus_Ok); + // Otherwise (i.e. if the loading was started as an asynchronous process) + // the onLazyRead(dtnode) handler is expected to call dtnode.setLazyNodeStatus(DTNodeStatus_Ok/_Error) when done. + this.tree.logDebug("_loadContent: succeeded - %o", this); + } + } catch(e) { +// alert(e); + this.setLazyNodeStatus(DTNodeStatus_Error); + this.tree.logWarning("_loadContent: failed - %o", e); + } + }, + + _expand: function(bExpand) { +// this.tree.logDebug("dtnode._expand(%o) - %o", bExpand, this); + if( this.bExpanded == bExpand ) { +// this.tree.logDebug("dtnode._expand(%o) IGNORED - %o", bExpand, this); + return; + } + var opts = this.tree.options; + if( !bExpand && this.getLevel()<opts.minExpandLevel ) { + this.tree.logDebug("dtnode._expand(%o) forced expand - %o", bExpand, this); + return; + } + if ( opts.onQueryExpand && opts.onQueryExpand.call(this.span, bExpand, this) == false ) + return; // Callback returned false + this.bExpanded = bExpand; + + // Persist expand state + if( opts.persist ) { + if( bExpand ) + this.tree.persistence.addExpand(this.data.key); + else + this.tree.persistence.clearExpand(this.data.key); + } + + this.render(false); + + // Auto-collapse mode: collapse all siblings + if( this.bExpanded && this.parent && opts.autoCollapse ) { + var parents = this._parentList(false, true); + for(var i=0; i<parents.length; i++) + parents[i].collapseSiblings(); + } + + // If the currently active node is now hidden, deactivate it + if( opts.activeVisible && this.tree.activeNode && ! this.tree.activeNode.isVisible() ) { + this.tree.activeNode.deactivate(); + } + // Expanding a lazy node: set 'loading...' and call callback + if( bExpand && this.data.isLazy && this.childList==null && !this.isLoading ) { + this._loadContent(); + return; + } +// this.tree.logDebug("_expand: start div toggle - %o", this); + + var fxDuration = opts.fx ? (opts.fx.duration || 200) : 0; + if( this.childList ) { + for(var i=0; i<this.childList.length; i++ ) { + var $child = $(this.childList[i].div); + if( fxDuration ) { + // This is a toggle, so only do it, if not already rendered (in)visible (issue 98) + if( bExpand != $child.is(':visible') ) + $child.animate(opts.fx, fxDuration); + } else { + if( bExpand ) + $child.show(); + else + $child.hide(); // TODO: this seems to be slow, when called the first time for an element + } + } + } + +/* issue 109: using selector filter is really SLOW. + // issue 98: only toggle, if render hasn't set visibility already: + var filter = ">DIV" + (bExpand ? ":hidden" : ":visible"); + + if( opts.fx ) { + var duration = opts.fx.duration || 200; +// $(">DIV", this.div).animate(opts.fx, duration); + $(filter, this.div).animate(opts.fx, duration); + } else { + $(filter, this.div).toggle(); +// var $d = $(">DIV", this.div); +// this.tree.logDebug("_expand: got div, start toggle - %o", this); +// $d.toggle(); + } +//*/ +// this.tree.logDebug("_expand: end div toggle - %o", this); + + if ( opts.onExpand ) + opts.onExpand.call(this.span, bExpand, this); + }, + + expand: function(flag) { + if( !this.childList && !this.data.isLazy && flag ) + return; // Prevent expanding empty nodes + if( this.parent == null && this.tree.options.minExpandLevel>0 && !flag ) + return; // Prevent collapsing the root + this._expand(flag); + }, + + toggleExpand: function() { + this.expand(!this.bExpanded); + }, + + collapseSiblings: function() { + if( this.parent == null ) + return; + var ac = this.parent.childList; + for (var i=0; i<ac.length; i++) { + if ( ac[i] !== this && ac[i].bExpanded ) + ac[i]._expand(false); + } + }, + + onClick: function(event) { +// this.tree.logDebug("dtnode.onClick(" + event.type + "): dtnode:" + this + ", button:" + event.button + ", which: " + event.which); + var targetType = this.getEventTargetType(event); + if( targetType == "expander" ) { + // Clicking the expander icon always expands/collapses + this.toggleExpand(); + this.focus(); // issue 95 + } else if( targetType == "checkbox" ) { + // Clicking the checkbox always (de)selects + this.toggleSelect(); + this.focus(); // issue 95 + } else { + this._userActivate(); + // Chrome and Safari don't focus the a-tag on click + this.span.getElementsByTagName("a")[0].focus(); + } + // Make sure that clicks stop, otherwise <a href='#'> jumps to the top + return false; + }, + + onDblClick: function(event) { +// this.tree.logDebug("dtnode.onDblClick(" + event.type + "): dtnode:" + this + ", button:" + event.button + ", which: " + event.which); + }, + + onKeydown: function(event) { +// this.tree.logDebug("dtnode.onKeydown(" + event.type + "): dtnode:" + this + ", charCode:" + event.charCode + ", keyCode: " + event.keyCode + ", which: " + event.which); + var handled = true; +// alert("keyDown" + event.which); + + switch( event.which ) { + // charCodes: +// case 43: // '+' + case 107: // '+' + case 187: // '+' @ Chrome, Safari + if( !this.bExpanded ) this.toggleExpand(); + break; +// case 45: // '-' + case 109: // '-' + case 189: // '+' @ Chrome, Safari + if( this.bExpanded ) this.toggleExpand(); + break; + //~ case 42: // '*' + //~ break; + //~ case 47: // '/' + //~ break; + // case 13: // <enter> + // <enter> on a focused <a> tag seems to generate a click-event. + // this._userActivate(); + // break; + case 32: // <space> + this._userActivate(); + break; + case 8: // <backspace> + if( this.parent ) + this.parent.focus(); + break; + case 37: // <left> + if( this.bExpanded ) { + this.toggleExpand(); + this.focus(); + } else if( this.parent && (this.tree.options.rootVisible || this.parent.parent) ) { + this.parent.focus(); + } + break; + case 39: // <right> + if( !this.bExpanded && (this.childList || this.data.isLazy) ) { + this.toggleExpand(); + this.focus(); + } else if( this.childList ) { + this.childList[0].focus(); + } + break; + case 38: // <up> + var sib = this.prevSibling(); + while( sib && sib.bExpanded && sib.childList ) + sib = sib.childList[sib.childList.length-1]; + if( !sib && this.parent && (this.tree.options.rootVisible || this.parent.parent) ) + sib = this.parent; + if( sib ) sib.focus(); + break; + case 40: // <down> + var sib; + if( this.bExpanded && this.childList ) { + sib = this.childList[0]; + } else { + var parents = this._parentList(false, true); + for(var i=parents.length-1; i>=0; i--) { + sib = parents[i].nextSibling(); + if( sib ) break; + } + } + if( sib ) sib.focus(); + break; + default: + handled = false; + } + // Return false, if handled, to prevent default processing + return !handled; + }, + + onKeypress: function(event) { + // onKeypress is only hooked to allow user callbacks. + // We don't process it, because IE and Safari don't fire keypress for cursor keys. +// this.tree.logDebug("dtnode.onKeypress(" + event.type + "): dtnode:" + this + ", charCode:" + event.charCode + ", keyCode: " + event.keyCode + ", which: " + event.which); + }, + + onFocus: function(event) { + // Handles blur and focus events. +// this.tree.logDebug("dtnode.onFocus(%o): %o", event, this); + var opts = this.tree.options; + if ( event.type=="blur" || event.type=="focusout" ) { + if ( opts.onBlur ) // Pass element as 'this' (jQuery convention) + opts.onBlur.call(this.span, this); + if( this.tree.tnFocused ) + $(this.tree.tnFocused.span).removeClass(opts.classNames.focused); + this.tree.tnFocused = null; + if( opts.persist ) + $.cookie(opts.cookieId+"-focus", "", opts.cookie); + } else if ( event.type=="focus" || event.type=="focusin") { + // Fix: sometimes the blur event is not generated + if( this.tree.tnFocused && this.tree.tnFocused !== this ) { + this.tree.logDebug("dtnode.onFocus: out of sync: curFocus: %o", this.tree.tnFocused); + $(this.tree.tnFocused.span).removeClass(opts.classNames.focused); + } + this.tree.tnFocused = this; + if ( opts.onFocus ) // Pass element as 'this' (jQuery convention) + opts.onFocus.call(this.span, this); + $(this.tree.tnFocused.span).addClass(opts.classNames.focused); + if( opts.persist ) + $.cookie(opts.cookieId+"-focus", this.data.key, opts.cookie); + } + // TODO: return anything? +// return false; + }, + + visit: function(fn, data, includeSelf) { + // Call fn(dtnode, data) for all child nodes. Stop iteration, if fn() returns false. + var n = 0; + if( includeSelf == true ) { + if( fn(this, data) == false ) + return 1; + n++; + } + if ( this.childList ) + for (var i=0; i<this.childList.length; i++) + n += this.childList[i].visit(fn, data, true); + return n; + }, + + remove: function() { + // Remove this node +// this.tree.logDebug ("%o.remove()", this); + if ( this === this.tree.root ) + return false; + return this.parent.removeChild(this); + }, + + removeChild: function(tn) { + // Remove tn from list of direct children. + var ac = this.childList; + if( ac.length == 1 ) { + if( tn !== ac[0] ) + throw "removeChild: invalid child"; + return this.removeChildren(); + } + if( tn === this.tree.activeNode ) + tn.deactivate(); + if( this.tree.options.persist ) { + if( tn.bSelected ) + this.tree.persistence.clearSelect(tn.data.key); + if ( tn.bExpanded ) + this.tree.persistence.clearExpand(tn.data.key); + } + tn.removeChildren(true); + this.div.removeChild(tn.div); + for(var i=0; i<ac.length; i++) { + if( ac[i] === tn ) { + this.childList.splice(i, 1); + delete tn; + break; + } + } + }, + + removeChildren: function(isRecursiveCall, retainPersistence) { + // Remove all child nodes (more efficiently than recursive remove()) +// this.tree.logDebug ("%o.removeChildren(%o)", this, isRecursiveCall); + var tree = this.tree; + var ac = this.childList; + if( ac ) { + for(var i=0; i<ac.length; i++) { + var tn=ac[i]; +// this.tree.logDebug ("del %o", tn); + if ( tn === tree.activeNode && !retainPersistence ) + tn.deactivate(); + if( this.tree.options.persist && !retainPersistence ) { + if( tn.bSelected ) + this.tree.persistence.clearSelect(tn.data.key); + if ( tn.bExpanded ) + this.tree.persistence.clearExpand(tn.data.key); + } + tn.removeChildren(true, retainPersistence); + this.div.removeChild(tn.div); + delete tn; + } + this.childList = null; + } + if( ! isRecursiveCall ) { +// this._expand(false); +// this.isRead = false; + this.isLoading = false; + this.render(false, false); + } + }, + + reload: function(force) { + // Discard lazy content (and reload, if node was expanded). + if( this.parent == null ) + return this.tree.reload(); + + if( ! this.data.isLazy ) + throw "node.reload() requires lazy nodes."; + if( this.bExpanded ) { + this.expand(false); + this.removeChildren(); + this.expand(true); + } else { + this.removeChildren(); + if( force ) + this._loadContent(); + } + }, + + _addChildNode: function(dtnode, beforeNode) { + /** + * Internal function to add one single DynatreeNode as a child. + * + */ + var tree = this.tree; + var opts = tree.options; + var pers = tree.persistence; + +// tree.logDebug("%o._addChildNode(%o)", this, dtnode); + + // --- Update and fix dtnode attributes if necessary + dtnode.parent = this; +// if( beforeNode && (beforeNode.parent !== this || beforeNode === dtnode ) ) +// throw "<beforeNode> must be another child of <this>"; + + // --- Add dtnode as a child + if ( this.childList==null ) { + this.childList = []; + } else if( ! beforeNode ) { + // Fix 'lastsib' + $(this.childList[this.childList.length-1].span).removeClass(opts.classNames.lastsib); + } + if( beforeNode ) { + var iBefore = $.inArray(beforeNode, this.childList); + if( iBefore < 0 ) + throw "<beforeNode> must be a child of <this>"; + this.childList.splice(iBefore, 0, dtnode); +// alert(this.childList); + } else { + // Append node + this.childList.push(dtnode); + } + + // --- Handle persistence + // Initial status is read from cookies, if persistence is active and + // cookies are already present. + // Otherwise the status is read from the data attributes and then persisted. + var isInitializing = tree.isInitializing(); + if( opts.persist && pers.cookiesFound && isInitializing ) { + // Init status from cookies +// tree.logDebug("init from cookie, pa=%o, dk=%o", pers.activeKey, dtnode.data.key); + if( pers.activeKey == dtnode.data.key ) + tree.activeNode = dtnode; + if( pers.focusedKey == dtnode.data.key ) + tree.focusNode = dtnode; + dtnode.bExpanded = ($.inArray(dtnode.data.key, pers.expandedKeyList) >= 0); + dtnode.bSelected = ($.inArray(dtnode.data.key, pers.selectedKeyList) >= 0); +// tree.logDebug(" key=%o, bSelected=%o", dtnode.data.key, dtnode.bSelected); + } else { + // Init status from data (Note: we write the cookies after the init phase) +// tree.logDebug("init from data"); + if( dtnode.data.activate ) { + tree.activeNode = dtnode; + if( opts.persist ) + pers.activeKey = dtnode.data.key; + } + if( dtnode.data.focus ) { + tree.focusNode = dtnode; + if( opts.persist ) + pers.focusedKey = dtnode.data.key; + } + dtnode.bExpanded = ( dtnode.data.expand == true ); // Collapsed by default + if( dtnode.bExpanded && opts.persist ) + pers.addExpand(dtnode.data.key); + dtnode.bSelected = ( dtnode.data.select == true ); // Deselected by default +/* + Doesn't work, cause pers.selectedKeyList may be null + if( dtnode.bSelected && opts.selectMode==1 + && pers.selectedKeyList && pers.selectedKeyList.length>0 ) { + tree.logWarning("Ignored multi-selection in single-mode for %o", dtnode); + dtnode.bSelected = false; // Fixing bad input data (multi selection for mode:1) + } +*/ + if( dtnode.bSelected && opts.persist ) + pers.addSelect(dtnode.data.key); + } + + // Always expand, if it's below minExpandLevel +// tree.logDebug ("%o._addChildNode(%o), l=%o", this, dtnode, dtnode.getLevel()); + if ( opts.minExpandLevel >= dtnode.getLevel() ) { +// tree.logDebug ("Force expand for %o", dtnode); + this.bExpanded = true; + } + + // In multi-hier mode, update the parents selection state + // issue #82: only if not initializing, because the children may not exist yet +// if( !dtnode.data.isStatusNode && opts.selectMode==3 && !isInitializing ) +// dtnode._fixSelectionState(); + + // In multi-hier mode, update the parents selection state + if( dtnode.bSelected && opts.selectMode==3 ) { + var p = this; + while( p ) { + if( !p.hasSubSel ) + p._setSubSel(true); + p = p.parent; + } + } + // render this node and the new child + if ( tree.bEnableUpdate ) + this.render(true, true); + + return dtnode; + }, + + addChild: function(obj, beforeNode) { + /** + * Add a node object as child. + * + * This should be the only place, where a DynaTreeNode is constructed! + * (Except for the root node creation in the tree constructor) + * + * @param obj A JS object (may be recursive) or an array of those. + * @param {DynaTreeNode} beforeNode (optional) sibling node. + * + * Data format: array of node objects, with optional 'children' attributes. + * [ + * { title: "t1", isFolder: true, ... } + * { title: "t2", isFolder: true, ..., + * children: [ + * {title: "t2.1", ..}, + * {..} + * ] + * } + * ] + * A simple object is also accepted instead of an array. + * + */ +// this.tree.logDebug("%o.addChild(%o, %o)", this, obj, beforeNode); + if( !obj || obj.length==0 ) // Passed null or undefined or empty array + return; + if( obj instanceof DynaTreeNode ) + return this._addChildNode(obj, beforeNode); + if( !obj.length ) // Passed a single data object + obj = [ obj ]; + + var prevFlag = this.tree.enableUpdate(false); + + var tnFirst = null; + for (var i=0; i<obj.length; i++) { + var data = obj[i]; + var dtnode = this._addChildNode(new DynaTreeNode(this, this.tree, data), beforeNode); + if( !tnFirst ) tnFirst = dtnode; + // Add child nodes recursively + if( data.children ) + dtnode.addChild(data.children, null); + } + this.tree.enableUpdate(prevFlag); + return tnFirst; + }, + + append: function(obj) { + this.tree.logWarning("node.append() is deprecated (use node.addChild() instead)."); + return this.addChild(obj, null); + }, + + appendAjax: function(ajaxOptions) { + this.removeChildren(false, true); + this.setLazyNodeStatus(DTNodeStatus_Loading); + // Ajax option inheritance: $.ajaxSetup < $.ui.dynatree.defaults.ajaxDefaults < tree.options.ajaxDefaults < ajaxOptions + var self = this; + var orgSuccess = ajaxOptions.success; + var orgError = ajaxOptions.error; + var options = $.extend({}, this.tree.options.ajaxDefaults, ajaxOptions, { +/* + complete: function(req, textStatus){ + alert("ajax complete"); + }, + timeout: 5000, // 5 sec +*/ + success: function(data, textStatus){ + // <this> is the request options +// self.tree.logDebug("appendAjax().success"); + var prevPhase = self.tree.phase; + self.tree.phase = "init"; +// self.append(data); + self.addChild(data, null); + self.tree.phase = "postInit"; + self.setLazyNodeStatus(DTNodeStatus_Ok); + if( orgSuccess ) + orgSuccess.call(options, self); + self.tree.phase = prevPhase; + }, + error: function(XMLHttpRequest, textStatus, errorThrown){ + // <this> is the request options +// self.tree.logWarning("appendAjax failed: %o:\n%o\n%o", textStatus, XMLHttpRequest, errorThrown); + self.tree.logWarning("appendAjax failed:", textStatus, ":\n", XMLHttpRequest, "\n", errorThrown); + self.setLazyNodeStatus(DTNodeStatus_Error, {info: textStatus, tooltip: ""+errorThrown}); + if( orgError ) + orgError.call(options, self, XMLHttpRequest, textStatus, errorThrown); + } + }); + $.ajax(options); + }, + // --- end of class + lastentry: undefined +} + +/************************************************************************* + * class DynaTreeStatus + */ + +var DynaTreeStatus = Class.create(); + + +DynaTreeStatus._getTreePersistData = function(cookieId, cookieOpts) { + // Static member: Return persistence information from cookies + var ts = new DynaTreeStatus(cookieId, cookieOpts); + ts.read(); + return ts.toDict(); +} +// Make available in global scope +getDynaTreePersistData = DynaTreeStatus._getTreePersistData; + + +DynaTreeStatus.prototype = { + // Constructor + initialize: function(cookieId, cookieOpts) { + this._log("DynaTreeStatus: initialize"); + if( cookieId === undefined ) + cookieId = $.ui.dynatree.defaults.cookieId; + cookieOpts = $.extend({}, $.ui.dynatree.defaults.cookie, cookieOpts); + + this.cookieId = cookieId; + this.cookieOpts = cookieOpts; + this.cookiesFound = undefined; + this.activeKey = null; + this.focusedKey = null; + this.expandedKeyList = null; + this.selectedKeyList = null; + }, + // member functions + _log: function(msg) { + // this.logDebug("_changeNodeList(%o): nodeList:%o, idx:%o", mode, nodeList, idx); + Array.prototype.unshift.apply(arguments, ["debug"]); + _log.apply(this, arguments); + }, + read: function() { + this._log("DynaTreeStatus: read"); + // Read or init cookies. + this.cookiesFound = false; + + var cookie = $.cookie(this.cookieId + "-active"); + this.activeKey = ( cookie == null ) ? "" : cookie; + if( cookie != null ) this.cookiesFound = true; + + cookie = $.cookie(this.cookieId + "-focus"); + this.focusedKey = ( cookie == null ) ? "" : cookie; + if( cookie != null ) this.cookiesFound = true; + + cookie = $.cookie(this.cookieId + "-expand"); + this.expandedKeyList = ( cookie == null ) ? [] : cookie.split(","); + if( cookie != null ) this.cookiesFound = true; + + cookie = $.cookie(this.cookieId + "-select"); + this.selectedKeyList = ( cookie == null ) ? [] : cookie.split(","); + if( cookie != null ) this.cookiesFound = true; + }, + write: function() { + this._log("DynaTreeStatus: write"); + $.cookie(this.cookieId + "-active", ( this.activeKey == null ) ? "" : this.activeKey, this.cookieOpts); + $.cookie(this.cookieId + "-focus", ( this.focusedKey == null ) ? "" : this.focusedKey, this.cookieOpts); + $.cookie(this.cookieId + "-expand", ( this.expandedKeyList == null ) ? "" : this.expandedKeyList.join(","), this.cookieOpts); + $.cookie(this.cookieId + "-select", ( this.selectedKeyList == null ) ? "" : this.selectedKeyList.join(","), this.cookieOpts); + }, + addExpand: function(key) { + this._log("addExpand(%o)", key); + if( $.inArray(key, this.expandedKeyList) < 0 ) { + this.expandedKeyList.push(key); + $.cookie(this.cookieId + "-expand", this.expandedKeyList.join(","), this.cookieOpts); + } + }, + clearExpand: function(key) { + this._log("clearExpand(%o)", key); + var idx = $.inArray(key, this.expandedKeyList); + if( idx >= 0 ) { + this.expandedKeyList.splice(idx, 1); + $.cookie(this.cookieId + "-expand", this.expandedKeyList.join(","), this.cookieOpts); + } + }, + addSelect: function(key) { + this._log("addSelect(%o)", key); + if( $.inArray(key, this.selectedKeyList) < 0 ) { + this.selectedKeyList.push(key); + $.cookie(this.cookieId + "-select", this.selectedKeyList.join(","), this.cookieOpts); + } + }, + clearSelect: function(key) { + this._log("clearSelect(%o)", key); + var idx = $.inArray(key, this.selectedKeyList); + if( idx >= 0 ) { + this.selectedKeyList.splice(idx, 1); + $.cookie(this.cookieId + "-select", this.selectedKeyList.join(","), this.cookieOpts); + } + }, + isReloading: function() { + return this.cookiesFound == true; + }, + toDict: function() { + return { + cookiesFound: this.cookiesFound, + activeKey: this.activeKey, + focusedKey: this.activeKey, + expandedKeyList: this.expandedKeyList, + selectedKeyList: this.selectedKeyList + }; + }, + // --- end of class + lastentry: undefined +}; + + +/************************************************************************* + * class DynaTree + */ + +var DynaTree = Class.create(); + +// --- Static members ---------------------------------------------------------- + +DynaTree.version = "$Version: 0.5.4$"; +/* +DynaTree._initTree = function() { +}; + +DynaTree._bind = function() { +}; +*/ +//--- Class members ------------------------------------------------------------ + +DynaTree.prototype = { + // Constructor +// initialize: function(divContainer, options) { + initialize: function($widget) { + // instance members + this.phase = "init"; + this.$widget = $widget; + this.options = $widget.options; + this.$tree = $widget.element; + // find container element + this.divTree = this.$tree.get(0); + }, + + // member functions + + _load: function() { + var $widget = this.$widget; + var opts = this.options; + this.bEnableUpdate = true; + this._nodeCount = 1; + this.activeNode = null; + this.focusNode = null; + + // If a 'options.classNames' dictionary was passed, still use defaults + // for undefined classes: + if( opts.classNames !== $.ui.dynatree.defaults.classNames ) { + opts.classNames = $.extend({}, $.ui.dynatree.defaults.classNames, opts.classNames); + } + // Guess skin path, if not specified + if(!opts.imagePath) { + $("script").each( function () { + // Eclipse syntax parser breaks on this expression, so put it at the bottom: + if( this.src.search(_rexDtLibName) >= 0 ) { + if( this.src.indexOf("/")>=0 ) // issue #47 + opts.imagePath = this.src.slice(0, this.src.lastIndexOf("/")) + "/skin/"; + else + opts.imagePath = "skin/"; +// logMsg("Guessing imagePath from '%s': '%s'", this.src, opts.imagePath); + return false; // first match + } + }); + } + + this.persistence = new DynaTreeStatus(opts.cookieId, opts.cookie); + if( opts.persist ) { + if( !$.cookie ) + _log("warn", "Please include jquery.cookie.js to use persistence."); + this.persistence.read(); + } + this.logDebug("DynaTree.persistence: %o", this.persistence.toDict()); + + // Cached tag strings + this.cache = { + tagEmpty: "<span class='" + opts.classNames.empty + "'></span>", + tagVline: "<span class='" + opts.classNames.vline + "'></span>", + tagExpander: "<span class='" + opts.classNames.expander + "'></span>", + tagConnector: "<span class='" + opts.classNames.connector + "'></span>", + tagNodeIcon: "<span class='" + opts.classNames.nodeIcon + "'></span>", + tagCheckbox: "<span class='" + opts.classNames.checkbox + "'></span>", + lastentry: undefined + }; + + // Clear container, in case it contained some 'waiting' or 'error' text + // for clients that don't support JS. + // We don't do this however, if we try to load from an embedded UL element. + if( opts.children || (opts.initAjax && opts.initAjax.url) || opts.initId ) + $(this.divTree).empty(); + else if( this.divRoot ) + $(this.divRoot).remove(); + + // create the root element + this.tnRoot = new DynaTreeNode(null, this, {title: opts.title, key: "root"}); + this.tnRoot.data.isFolder = true; + this.tnRoot.render(false, false); + this.divRoot = this.tnRoot.div; + this.divRoot.className = opts.classNames.container; + // add root to container + // TODO: this should be delayed until all children have been created for performance reasons + this.divTree.appendChild(this.divRoot); + + var root = this.tnRoot; + var isReloading = ( opts.persist && this.persistence.isReloading() ); + var isLazy = false; + var prevFlag = this.enableUpdate(false); + + this.logDebug("Dynatree._load(): read tree structure..."); + + // Init tree structure + if( opts.children ) { + // Read structure from node array + root.addChild(opts.children); + + } else if( opts.initAjax && opts.initAjax.url ) { + // Init tree from AJAX request + isLazy = true; + root.data.isLazy = true; + this._reloadAjax(); + + } else if( opts.initId ) { + // Init tree from another UL element + this._createFromTag(root, $("#"+opts.initId)); + + } else { + // Init tree from the first UL element inside the container <div> + var $ul = this.$tree.find(">ul").hide(); + this._createFromTag(root, $ul); + $ul.remove(); + } + + this._checkConsistency(); + // Render html markup + this.logDebug("Dynatree._load(): render nodes..."); + this.enableUpdate(prevFlag); + + // bind event handlers + this.logDebug("Dynatree._load(): bind events..."); + this.$widget.bind(); + + // --- Post-load processing + this.logDebug("Dynatree._load(): postInit..."); + this.phase = "postInit"; + + // In persist mode, make sure that cookies are written, even if they are empty + if( opts.persist ) { + this.persistence.write(); + } + + // Set focus, if possible (this will also fire an event and write a cookie) + if( this.focusNode && this.focusNode.isVisible() ) { + this.logDebug("Focus on init: %o", this.focusNode); + this.focusNode.focus(); + } + + if( !isLazy && opts.onPostInit ) { + opts.onPostInit.call(this, isReloading, false); + } + + this.phase = "idle"; + }, + + _reloadAjax: function() { + // Reload + var opts = this.options; + if( ! opts.initAjax || ! opts.initAjax.url ) + throw "tree.reload() requires 'initAjax' mode."; + var pers = this.persistence; + var ajaxOpts = $.extend({}, opts.initAjax); + // Append cookie info to the request +// this.logDebug("reloadAjax: key=%o, an.key:%o", pers.activeKey, this.activeNode?this.activeNode.data.key:"?"); + if( ajaxOpts.addActiveKey ) + ajaxOpts.data.activeKey = pers.activeKey; + if( ajaxOpts.addFocusedKey ) + ajaxOpts.data.focusedKey = pers.focusedKey; + if( ajaxOpts.addExpandedKeyList ) + ajaxOpts.data.expandedKeyList = pers.expandedKeyList.join(","); + if( ajaxOpts.addSelectedKeyList ) + ajaxOpts.data.selectedKeyList = pers.selectedKeyList.join(","); + + // Set up onPostInit callback to be called when Ajax returns + if( opts.onPostInit ) { + if( ajaxOpts.success ) + this.logWarning("initAjax: success callback is ignored when onPostInit was specified."); + if( ajaxOpts.error ) + this.logWarning("initAjax: error callback is ignored when onPostInit was specified."); + var isReloading = pers.isReloading(); + ajaxOpts["success"] = function(dtnode) { opts.onPostInit.call(dtnode.tree, isReloading, false); }; + ajaxOpts["error"] = function(dtnode) { opts.onPostInit.call(dtnode.tree, isReloading, true); }; + } + this.logDebug("Dynatree._init(): send Ajax request..."); + this.tnRoot.appendAjax(ajaxOpts); + }, + + toString: function() { + return "DynaTree '" + this.options.title + "'"; + }, + + toDict: function() { + return this.tnRoot.toDict(true); + }, + + getPersistData: function() { + return this.persistence.toDict(); + }, + + logDebug: function(msg) { + if( this.options.debugLevel >= 2 ) { + Array.prototype.unshift.apply(arguments, ["debug"]); + _log.apply(this, arguments); + } + }, + + logInfo: function(msg) { + if( this.options.debugLevel >= 1 ) { + Array.prototype.unshift.apply(arguments, ["info"]); + _log.apply(this, arguments); + } + }, + + logWarning: function(msg) { + Array.prototype.unshift.apply(arguments, ["warn"]); + _log.apply(this, arguments); + }, + + isInitializing: function() { + return ( this.phase=="init" || this.phase=="postInit" ); + }, + isReloading: function() { + return ( this.phase=="init" || this.phase=="postInit" ) && this.options.persist && this.persistence.cookiesFound; + }, + isUserEvent: function() { + return ( this.phase=="userEvent" ); + }, + + redraw: function() { + this.logDebug("dynatree.redraw()..."); + this.tnRoot.render(true, true); + this.logDebug("dynatree.redraw() done."); + }, + + reloadAjax: function() { + this.logWarning("tree.reloadAjax() is deprecated since v0.5.2 (use reload() instead)."); + }, + + reload: function() { + this._load(); + }, + + getRoot: function() { + return this.tnRoot; + }, + + getNodeByKey: function(key) { + // $("#...") has problems, if the key contains '.', so we use getElementById() +// return $("#" + this.options.idPrefix + key).attr("dtnode"); + var el = document.getElementById(this.options.idPrefix + key); + return ( el && el.dtnode ) ? el.dtnode : null; + }, + + getActiveNode: function() { + return this.activeNode; + }, + + reactivate: function(setFocus) { + // Re-fire onQueryActivate and onActivate events. + var node = this.activeNode; +// this.logDebug("reactivate %o", node); + if( node ) { + this.activeNode = null; // Force re-activating + node.activate(); + if( setFocus ) + node.focus(); + } + }, + + getSelectedNodes: function(stopOnParents) { + var nodeList = []; + this.tnRoot.visit(function(dtnode){ + if( dtnode.bSelected ) { + nodeList.push(dtnode); + if( stopOnParents == true ) + return false; // stop processing this branch + } + }); + return nodeList; + }, + + activateKey: function(key) { + var dtnode = (key === null) ? null : this.getNodeByKey(key); + if( !dtnode ) { + if( this.activeNode ) + this.activeNode.deactivate(); + this.activeNode = null; + return null; + } + dtnode.focus(); + dtnode.activate(); + return dtnode; + }, + + selectKey: function(key, select) { + var dtnode = this.getNodeByKey(key); + if( !dtnode ) + return null; + dtnode.select(select); + return dtnode; + }, + + enableUpdate: function(bEnable) { + if ( this.bEnableUpdate==bEnable ) + return bEnable; + this.bEnableUpdate = bEnable; + if ( bEnable ) + this.redraw(); + return !bEnable; // return previous value + }, + + visit: function(fn, data, includeRoot) { + return this.tnRoot.visit(fn, data, includeRoot); + }, + + _createFromTag: function(parentTreeNode, $ulParent) { + // Convert a <UL>...</UL> list into children of the parent tree node. + var self = this; +/* +TODO: better? + this.$lis = $("li:has(a[href])", this.element); + this.$tabs = this.$lis.map(function() { return $("a", this)[0]; }); + */ + $ulParent.find(">li").each(function() { + var $li = $(this); + var $liSpan = $li.find(">span:first"); + var title; + if( $liSpan.length ) { + // If a <li><span> tag is specified, use it literally. + title = $liSpan.html(); + } else { + // If only a <li> tag is specified, use the trimmed string up to the next child <ul> tag. + title = $li.html(); + var iPos = title.search(/<ul/i); + if( iPos>=0 ) + title = $.trim(title.substring(0, iPos)); + else + title = $.trim(title); +// self.logDebug("%o", title); + } + // Parse node options from ID, title and class attributes + var data = { + title: title, + isFolder: $li.hasClass("folder"), + isLazy: $li.hasClass("lazy"), + expand: $li.hasClass("expanded"), + select: $li.hasClass("selected"), + activate: $li.hasClass("active"), + focus: $li.hasClass("focused") + }; + if( $li.attr("title") ) + data.tooltip = $li.attr("title"); + if( $li.attr("id") ) + data.key = $li.attr("id"); + // If a data attribute is present, evaluate as a JavaScript object + if( $li.attr("data") ) { + var dataAttr = $.trim($li.attr("data")); + if( dataAttr ) { + if( dataAttr.charAt(0) != "{" ) + dataAttr = "{" + dataAttr + "}" + try { + $.extend(data, eval("(" + dataAttr + ")")); + } catch(e) { + throw ("Error parsing node data: " + e + "\ndata:\n'" + dataAttr + "'"); + } + } + } + childNode = parentTreeNode.addChild(data); + // Recursive reading of child nodes, if LI tag contains an UL tag + var $ul = $li.find(">ul:first"); + if( $ul.length ) { + self._createFromTag(childNode, $ul); // must use 'self', because 'this' is the each() context + } + }); + }, + + _checkConsistency: function() { +// this.logDebug("tree._checkConsistency() NOT IMPLEMENTED - %o", this); + }, + + // --- end of class + lastentry: undefined +}; + +/************************************************************************* + * widget $(..).dynatree + */ + +$.widget("ui.dynatree", { + init: function() { + // ui.core 1.6 renamed init() to _init(): this stub assures backward compatibility + _log("warn", "ui.dynatree.init() was called; you should upgrade to ui.core.js v1.6 or higher."); + return this._init(); + }, + + _init: function() { + if( parseFloat($.ui.version) < 1.8 ) { + // jquery.ui.core 1.8 renamed _init() to _create(): this stub assures backward compatibility + _log("info", "ui.dynatree._init() was called; consider upgrading to jquery.ui.core.js v1.8 or higher."); + return this._create(); + } + // jquery.ui.core 1.8 still uses _init() to perform "default functionality" + _log("debug", "ui.dynatree._init() was called; no current default functionality."); + }, + + _create: function() { + if( parseFloat($.ui.version) >= 1.8 ) { + this.options = $.extend(true, {}, $[this.namespace][this.widgetName].defaults, this.options); + } + logMsg("Dynatree._create(): version='%s', debugLevel=%o.", DynaTree.version, this.options.debugLevel); + var opts = this.options; + // The widget framework supplies this.element and this.options. + this.options.event += ".dynatree"; // namespace event + + var divTree = this.element.get(0); +/* // Clear container, in case it contained some 'waiting' or 'error' text + // for clients that don't support JS + if( opts.children || (opts.initAjax && opts.initAjax.url) || opts.initId ) + $(divTree).empty(); +*/ + // Create the DynaTree object + this.tree = new DynaTree(this); + this.tree._load(); + this.tree.logDebug("Dynatree._create(): done."); + }, + + bind: function() { + var $this = this.element; + var o = this.options; + + // Prevent duplicate binding + this.unbind(); + + // Tool function to get dtnode from the event target: + function __getNodeFromElement(el) { + var iMax = 5; + while( el && iMax-- ) { + if( el.dtnode ) return el.dtnode; + el = el.parentNode; + }; + return null; + } + + var eventNames = "click.dynatree dblclick.dynatree"; + if( o.keyboard ) // Note: leading ' '! + eventNames += " keypress.dynatree keydown.dynatree"; + $this.bind(eventNames, function(event){ + var dtnode = __getNodeFromElement(event.target); + if( !dtnode ) + return true; // Allow bubbling of other events + var prevPhase = dtnode.tree.phase; + dtnode.tree.phase = "userEvent"; + try { + dtnode.tree.logDebug("bind(%o): dtnode: %o", event, dtnode); + + switch(event.type) { + case "click": + return ( o.onClick && o.onClick(dtnode, event)===false ) ? false : dtnode.onClick(event); + case "dblclick": + return ( o.onDblClick && o.onDblClick(dtnode, event)===false ) ? false : dtnode.onDblClick(event); + case "keydown": + return ( o.onKeydown && o.onKeydown(dtnode, event)===false ) ? false : dtnode.onKeydown(event); + case "keypress": + return ( o.onKeypress && o.onKeypress(dtnode, event)===false ) ? false : dtnode.onKeypress(event); + }; + } catch(e) { + var _ = null; // issue 117 +// dtnode.tree.logError("bind(%o): dtnode: %o", event, dtnode); + } finally { + dtnode.tree.phase = prevPhase; + } + }); + + // focus/blur don't bubble, i.e. are not delegated to parent <div> tags, + // so we use the addEventListener capturing phase. + // See http://www.howtocreate.co.uk/tutorials/javascript/domevents + function __focusHandler(event) { + // Handles blur and focus. + // Fix event for IE: + event = arguments[0] = $.event.fix( event || window.event ); + var dtnode = __getNodeFromElement(event.target); + return dtnode ? dtnode.onFocus(event) : false; + } + var div = this.tree.divTree; + if( div.addEventListener ) { + div.addEventListener("focus", __focusHandler, true); + div.addEventListener("blur", __focusHandler, true); + } else { + div.onfocusin = div.onfocusout = __focusHandler; + } + // EVENTS + // disable click if event is configured to something else +// if (!(/^click/).test(o.event)) +// this.$tabs.bind("click.tabs", function() { return false; }); + + }, + + unbind: function() { + this.element.unbind(".dynatree"); + }, + +/* TODO: we could handle option changes during runtime here (maybe to re-render, ...) + setData: function(key, value) { + this.tree.logDebug("dynatree.setData('" + key + "', '" + value + "')"); + }, +*/ + enable: function() { + this.bind(); + // Call default disable(): remove -disabled from css: + $.widget.prototype.enable.apply(this, arguments); + }, + + disable: function() { + this.unbind(); + // Call default disable(): add -disabled to css: + $.widget.prototype.disable.apply(this, arguments); + }, + + // --- getter methods (i.e. NOT returning a reference to $) + getTree: function() { + return this.tree; + }, + + getRoot: function() { + return this.tree.getRoot(); + }, + + getActiveNode: function() { + return this.tree.getActiveNode(); + }, + + getSelectedNodes: function() { + return this.tree.getSelectedNodes(); + }, + + // ------------------------------------------------------------------------ + lastentry: undefined +}); + + +// The following methods return a value (thus breaking the jQuery call chain): + +$.ui.dynatree.getter = "getTree getRoot getActiveNode getSelectedNodes"; + + +// Plugin default options: + +$.ui.dynatree.defaults = { + title: "Dynatree root", // Name of the root node. + rootVisible: false, // Set to true, to make the root node visible. + minExpandLevel: 1, // 1: root node is not collapsible + imagePath: null, // Path to a folder containing icons. Defaults to 'skin/' subdirectory. + children: null, // Init tree structure from this object array. + initId: null, // Init tree structure from a <ul> element with this ID. + initAjax: null, // Ajax options used to initialize the tree strucuture. + autoFocus: true, // Set focus to first child, when expanding or lazy-loading. + keyboard: true, // Support keyboard navigation. + persist: false, // Persist expand-status to a cookie + autoCollapse: false, // Automatically collapse all siblings, when a node is expanded. + clickFolderMode: 3, // 1:activate, 2:expand, 3:activate and expand + activeVisible: true, // Make sure, active nodes are visible (expanded). + checkbox: false, // Show checkboxes. + selectMode: 2, // 1:single, 2:multi, 3:multi-hier + fx: null, // Animations, e.g. null or { height: "toggle", duration: 200 } + + // Low level event handlers: onEvent(dtnode, event): return false, to stop default processing + onClick: null, // null: generate focus, expand, activate, select events. + onDblClick: null, // (No default actions.) + onKeydown: null, // null: generate keyboard navigation (focus, expand, activate). + onKeypress: null, // (No default actions.) + onFocus: null, // null: set focus to node. + onBlur: null, // null: remove focus from node. + + // Pre-event handlers onQueryEvent(flag, dtnode): return false, to stop processing + onQueryActivate: null, // Callback(flag, dtnode) before a node is (de)activated. + onQuerySelect: null, // Callback(flag, dtnode) before a node is (de)selected. + onQueryExpand: null, // Callback(flag, dtnode) before a node is expanded/collpsed. + + // High level event handlers + onPostInit: null, // Callback(isReloading, isError) when tree was (re)loaded. + onActivate: null, // Callback(dtnode) when a node is activated. + onDeactivate: null, // Callback(dtnode) when a node is deactivated. + onSelect: null, // Callback(flag, dtnode) when a node is (de)selected. + onExpand: null, // Callback(dtnode) when a node is expanded/collapsed. + onLazyRead: null, // Callback(dtnode) when a lazy node is expanded for the first time. + + ajaxDefaults: { // Used by initAjax option + cache: false, // false: Append random '_' argument to the request url to prevent caching. + dataType: "json" // Expect json format and pass json object to callbacks. + }, + strings: { + loading: "Loading…", + loadError: "Load error!" + }, + idPrefix: "ui-dynatree-id-", // Used to generate node id's like <span id="ui-dynatree-id-<key>">. +// cookieId: "ui-dynatree-cookie", // Choose a more unique name, to allow multiple trees. + cookieId: "dynatree", // Choose a more unique name, to allow multiple trees. + cookie: { + expires: null //7, // Days or Date; null: session cookie +// path: "/", // Defaults to current page +// domain: "jquery.com", +// secure: true + }, + // Class names used, when rendering the HTML markup. + // Note: if only single entries are passed for options.classNames, all other + // values are still set to default. + classNames: { + container: "ui-dynatree-container", + folder: "ui-dynatree-folder", + document: "ui-dynatree-document", + + empty: "ui-dynatree-empty", + vline: "ui-dynatree-vline", + expander: "ui-dynatree-expander", + connector: "ui-dynatree-connector", + checkbox: "ui-dynatree-checkbox", + nodeIcon: "ui-dynatree-icon", + title: "ui-dynatree-title", + + nodeError: "ui-dynatree-statusnode-error", + nodeWait: "ui-dynatree-statusnode-wait", + hidden: "ui-dynatree-hidden", + combinedExpanderPrefix: "ui-dynatree-exp-", + combinedIconPrefix: "ui-dynatree-ico-", +// disabled: "ui-dynatree-disabled", + hasChildren: "ui-dynatree-has-children", + active: "ui-dynatree-active", + selected: "ui-dynatree-selected", + expanded: "ui-dynatree-expanded", + lazy: "ui-dynatree-lazy", + focused: "ui-dynatree-focused", + partsel: "ui-dynatree-partsel", + lastsib: "ui-dynatree-lastsib" + }, + debugLevel: 1, + + // ------------------------------------------------------------------------ + lastentry: undefined +}; + +/** + * Reserved data attributes for a tree node. + */ +$.ui.dynatree.nodedatadefaults = { + title: null, // (required) Displayed name of the node (html is allowed here) + key: null, // May be used with activate(), select(), find(), ... + isFolder: false, // Use a folder icon. Also the node is expandable but not selectable. + isLazy: false, // Call onLazyRead(), when the node is expanded for the first time to allow for delayed creation of children. + tooltip: null, // Show this popup text. + icon: null, // Use a custom image (filename relative to tree.options.imagePath). 'null' for default icon, 'false' for no icon. + addClass: null, // Class name added to the node's span tag. + activate: false, // Initial active status. + focus: false, // Initial focused status. + expand: false, // Initial expanded status. + select: false, // Initial selected status. + hideCheckbox: false, // Suppress checkbox display for this node. + unselectable: false, // Prevent selection. +// disabled: false, + // The following attributes are only valid if passed to some functions: + children: null, // Array of child nodes. + // NOTE: we can also add custom attributes here. + // This may then also be used in the onActivate(), onSelect() or onLazyTree() callbacks. + // ------------------------------------------------------------------------ + lastentry: undefined +}; + +// --------------------------------------------------------------------------- +})(jQuery); + +// Eclipse syntax parser breaks on this expression, so we put it at the bottom. +var _rexDtLibName = /.*dynatree[^/]*\.js$/i; Binary file static/june_2007_style/blue/dynatree_skin/customFolder1.gif has changed --- /dev/null +++ b/static/june_2007_style/blue/dynatree_skin/ui.dynatree.css @@ -0,0 +1,295 @@ +/******************************************************************************* + * Tree container + */ +div.ui-dynatree-container +{ + font-family: tahoma, arial, helvetica; + font-size: 10pt; /* font size should not be too big */ + white-space: nowrap; + padding: 3px; + + background-color: white; + border: none; +} + +/* Style, when control is disabled */ +.ui-dynatree-disabled div.ui-dynatree-container +{ + opacity: 0.5; +/* filter: alpha(opacity=50); /* Yields a css warning */ + background-color: silver; +} + + +/******************************************************************************* + * Vertical line image + */ +div.ui-dynatree-container img +{ + width: 16px; + height: 16px; + margin-left: 3px; + vertical-align: top; + border-style: none; +} + +/******************************************************************************* + * Common icon definitions + */ +span.ui-dynatree-empty, +span.ui-dynatree-vline, +span.ui-dynatree-connector, +span.ui-dynatree-expander, +span.ui-dynatree-icon, +span.ui-dynatree-checkbox, +span.ui-dynatree-radio +{ + width: 16px; + height: 16px; + display: -moz-inline-box; /* @ FF 1+2 */ + display: inline-block; /* Required to make a span sizeable */ + vertical-align: top; + background-repeat: no-repeat; + background-position: left; +} + +/******************************************************************************* + * Lines and connectors + */ +span.ui-dynatree-empty +{ +} +span.ui-dynatree-vline +{ + background-image: url("ltL_ns.gif"); +} +span.ui-dynatree-connector +{ + background-image: url("ltL_nes.gif"); +} +.ui-dynatree-lastsib span.ui-dynatree-connector +{ + background-image: url("ltL_ne.gif"); +} + +/******************************************************************************* + * Expander icon + * Note: IE6 doesn't correctly evaluate multiples class names, + * so we create combined class names that can be used in the CSS. + * + * Prefix: ui-dynatree-exp- + * 1st character: 'e': expanded, 'c': collapsed + * 2nd character (optional): 'd': lazy (Delayed) + * 3rd character (optional): 'l': Last sibling + */ + +span.ui-dynatree-expander +{ + background-image: url("ltP_nes.gif"); + cursor: pointer; +} +.ui-dynatree-exp-cl span.ui-dynatree-expander /* Collapsed, not delayed, last sibling */ +{ + background-image: url("ltP_ne.gif"); +} +.ui-dynatree-exp-cd span.ui-dynatree-expander /* Collapsed, delayed, not last sibling */ +{ + background-image: url("ltD_nes.gif"); +} +.ui-dynatree-exp-cdl span.ui-dynatree-expander /* Collapsed, delayed, last sibling */ +{ + background-image: url("ltD_ne.gif"); +} +.ui-dynatree-exp-e span.ui-dynatree-expander, /* Expanded, not delayed, not last sibling */ +.ui-dynatree-exp-ed span.ui-dynatree-expander /* Expanded, delayed, not last sibling */ +{ + background-image: url("ltM_nes.gif"); +} +.ui-dynatree-exp-el span.ui-dynatree-expander, /* Expanded, not delayed, last sibling */ +.ui-dynatree-exp-edl span.ui-dynatree-expander /* Expanded, delayed, last sibling */ +{ + background-image: url("ltM_ne.gif"); +} + + +/******************************************************************************* + * Checkbox icon + */ +span.ui-dynatree-checkbox +{ + margin-left: 3px; + background-image: url("cbUnchecked.gif"); +} +span.ui-dynatree-checkbox:hover +{ + background-image: url("cbUnchecked_hover.gif"); +} + +.ui-dynatree-partsel span.ui-dynatree-checkbox +{ + background-image: url("cbIntermediate.gif"); +} +.ui-dynatree-partsel span.ui-dynatree-checkbox:hover +{ + background-image: url("cbIntermediate_hover.gif"); +} + +.ui-dynatree-selected span.ui-dynatree-checkbox +{ + background-image: url("cbChecked.gif"); +} +.ui-dynatree-selected span.ui-dynatree-checkbox:hover +{ + background-image: url("cbChecked_hover.gif"); +} + +/******************************************************************************* + * Radiobutton icon + * This is a customization, that may be activated by overriding the 'checkbox' + * class name as 'ui-dynatree-radio' in the tree options. + */ +span.ui-dynatree-radio +{ + margin-left: 3px; + background-image: url("rbUnchecked.gif"); +} +span.ui-dynatree-radio:hover +{ + background-image: url("rbUnchecked_hover.gif"); +} + +.ui-dynatree-partsel span.ui-dynatree-radio +{ + background-image: url("rbIntermediate.gif"); +} +.ui-dynatree-partsel span.ui-dynatree-radio:hover +{ + background-image: url("rbIntermediate_hover.gif"); +} + +.ui-dynatree-selected span.ui-dynatree-radio +{ + background-image: url("rbChecked.gif"); +} +.ui-dynatree-selected span.ui-dynatree-radio:hover +{ + background-image: url("rbChecked_hover.gif"); +} + +/******************************************************************************* + * Node type icon + * Note: IE6 doesn't correctly evaluate multiples class names, + * so we create combined class names that can be used in the CSS. + * + * Prefix: ui-dynatree-ico- + * 1st character: 'e': expanded, 'c': collapsed + * 2nd character (optional): 'f': folder + */ + +span.ui-dynatree-icon /* Default icon */ +{ + margin-left: 3px; + background-image: url("ltDoc.gif"); +} + +.ui-dynatree-ico-cf span.ui-dynatree-icon /* Collapsed Folder */ +{ + background-image: url("ltFld.gif"); +} + +.ui-dynatree-ico-ef span.ui-dynatree-icon /* Expanded Folder */ +{ + background-image: url("ltFld_o.gif"); +} + +/* Status node icons */ + +.ui-dynatree-statusnode-wait span.ui-dynatree-icon +{ + background-image: url("ltWait.gif"); +} + +.ui-dynatree-statusnode-error span.ui-dynatree-icon +{ + background-image: url("ltError.gif"); +} + +/******************************************************************************* + * Node titles + */ + + /* @Chrome: fix broken hit area of node titles (issue 133) */ +span.ui-dynatree-document, +span.ui-dynatree-folder +{ + display: -moz-inline-box; /* @ FF 1+2 */ + display: inline-block; /* Required to make a span sizeable */ +} + +/* Remove blue color and underline from title links */ +div.ui-dynatree-container a +/*, div.ui-dynatree-container a:visited*/ +{ + color: black; /* inherit doesn't work on IE */ + text-decoration: none; + vertical-align: top; + margin: 0px; + margin-left: 3px; +/* outline: 0; /* @ Firefox, prevent dotted border after click */ +} + +div.ui-dynatree-container a:hover +{ + text-decoration: underline; +} + +span.ui-dynatree-document a, +span.ui-dynatree-folder a +{ + display: inline-block; /* Better alignment, when title contains <br> */ +/* vertical-align: top;*/ + padding-left: 3px; + padding-right: 3px; /* Otherwise italic font will be outside bounds */ + /* line-height: 16px; /* should be the same as img height, in case 16 px */ +} +span.ui-dynatree-folder a +{ + font-weight: normal; +} + +div.ui-dynatree-container a:focus, +span.ui-dynatree-focused a:link /* @IE */ +{ + background-color: #EFEBDE; /* gray */ +} + + +span.ui-dynatree-has-children a +{ +} + +span.ui-dynatree-expanded a +{ +} + +span.ui-dynatree-selected a +{ + color: black; + font-style: italic; +} + +span.ui-dynatree-active a +{ + background-color: #3169C6 !important; + color: white !important; /* @ IE6 */ +} + +/******************************************************************************* + * Custom node classes (sample) + */ + +span.custom1 a +{ + background-color: maroon; + color: yellow; +} --- /dev/null +++ b/static/scripts/packed/jquery.cookie.js @@ -0,0 +1,1 @@ +jQuery.cookie=function(b,j,m){if(typeof j!="undefined"){m=m||{};if(j===null){j="";m=$.extend({},m);m.expires=-1}var e="";if(m.expires&&(typeof m.expires=="number"||m.expires.toUTCString)){var f;if(typeof m.expires=="number"){f=new Date();f.setTime(f.getTime()+(m.expires*24*60*60*1000))}else{f=m.expires}e="; expires="+f.toUTCString()}var l=m.path?"; path="+(m.path):"";var g=m.domain?"; domain="+(m.domain):"";var a=m.secure?"; secure":"";document.cookie=[b,"=",encodeURIComponent(j),e,l,g,a].join("")}else{var d=null;if(document.cookie&&document.cookie!=""){var k=document.cookie.split(";");for(var h=0;h<k.length;h++){var c=jQuery.trim(k[h]);if(c.substring(0,b.length+1)==(b+"=")){d=decodeURIComponent(c.substring(b.length+1));break}}}return d}}; Binary file static/june_2007_style/blue/dynatree_skin/ltL_nes.gif has changed Binary file static/june_2007_style/blue/dynatree_skin/ltL_ns.gif has changed Binary file static/june_2007_style/blue/dynatree_skin/ltL_ne.gif has changed Binary file static/june_2007_style/blue/dynatree_skin/ltD_ne.gif has changed Binary file static/june_2007_style/blue/dynatree_skin/rbIntermediate_hover.gif has changed Binary file static/june_2007_style/blue/dynatree_skin/cbUnchecked.gif has changed Binary file static/june_2007_style/blue/dynatree_skin/cbUnchecked_hover.gif has changed Binary file static/june_2007_style/blue/dynatree_skin/ltL_.gif has changed Binary file static/june_2007_style/blue/dynatree_skin/rbChecked_hover.gif has changed
participants (1)
-
commits-noreply@bitbucket.org