galaxy-commits
Threads by month
- ----- 2026 -----
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- 15302 discussions
galaxy-dist commit b1ec8342053f: Adding NGS simulation tool
by commits-noreply@bitbucket.org 20 Nov '10
by commits-noreply@bitbucket.org 20 Nov '10
20 Nov '10
# HG changeset patch -- Bitbucket.org
# Project galaxy-dist
# URL http://bitbucket.org/galaxy/galaxy-dist/overview
# User Kelly Vincent <kpvincent(a)bx.psu.edu>
# Date 1288806772 14400
# Node ID b1ec8342053f3cdcd0a081ff28f077a76bd188cc
# Parent 9d68027b01096e2b32101234878d11946c03d08c
Adding NGS simulation tool
--- /dev/null
+++ b/tool-data/ngs_sim_fasta.loc.sample
@@ -0,0 +1,20 @@
+#This is a sample file distributed with Galaxy that enables the NGS simulation
+#tool to use some FASTA files. You will need to make sure that these FASTA files
+#are in place and then create the ngs_sim.loc file similar to this one (store it
+#in this directory) that points to the locations of those files. The ngs_sim.loc
+#file has this format (white space characters are TAB characters):
+#
+#<unique_build_id><dbkey><display_name><file_base_path>
+#
+#So, for example, if you had hg18chrM.fa in
+#/data/path/hg18/seq/,
+#then the ngs_sim.loc entry would look like this:
+#
+#hg18chrM hg18 hg18chrM /data/path/hg18/seq/hg18chrM.fa
+#
+#Your ngs_sim.loc file should include an entry per line for each FASTA file you
+#have stored.
+#
+#hg18chrM hg18 hg18chrM /data/path/hg18/seq/hg18chrM.fa
+#phiX174 phiX phiX174 /data/path/genome/phiX/seq/phiX.fa
+#pUC18 pUC18 pUC18 /data/path/genome/pUC18/seq/pUC18.fa
Binary file test-data/ngs_simulation_out3.png has changed
--- /dev/null
+++ b/tools/ngs_simulation/ngs_simulation.xml
@@ -0,0 +1,217 @@
+<tool id="ngs_simulation" name="Simulate" version="1.0.0">
+<!--<tool id="ngs_simulation" name="Simulate" force_history_refresh="True" version="1.0.0">-->
+ <description>Illumina runs</description>
+ <command interpreter="python">
+ ngs_simulation.py
+ #if $in_type.input_type == "built-in"
+ --input="${ filter( lambda x: str( x[0] ) == str( $in_type.genome ), $__app__.tool_data_tables[ 'ngs_sim_fasta' ].get_fields() )[0][-1] }"
+ --genome=$genome
+ #else
+ --input=$in_type.input1
+ #end if
+ --read_len=$read_len
+ --avg_coverage=$avg_coverage
+ --error_rate=$error_rate
+ --num_sims=$num_sims
+ --polymorphism=$polymorphism
+ --detection_thresh=$detection_thresh
+ --output_png=$output_png
+ --summary_out=$summary_out
+ --output_summary=$output_summary
+ --new_file_path=$__new_file_path__
+ </command>
+<!-- If want to include all simulation results file
+ sim_results=$sim_results
+ output=$output.id
+-->
+ <inputs>
+ <conditional name="in_type">
+ <param name="input_type" type="select" label="Use a built-in FASTA file or one from the history?">
+ <option value="built-in">Built-in</option>
+ <option value="history">History file</option>
+ </param>
+ <when value="built-in">
+ <param name="genome" type="select" label="Select a built-in genome" help="if your genome of interest is not listed - contact Galaxy team">
+ <options from_data_table="ngs_sim_fasta" />
+ </param>
+ </when>
+ <when value="history">
+ <param name="input1" type="data" format="fasta" label="Input genome (FASTA format)" />
+ </when>
+ </conditional>
+ <param name="read_len" type="integer" value="76" label="Read length" />
+ <param name="avg_coverage" type="integer" value="200" label="Average coverage" />
+ <param name="error_rate" type="float" value="0.001" label="Error rate or quality score" help="Quality score if integer 1 or greater; error rate if between 0 and 1" />
+ <param name="num_sims" type="integer" value="100" label="The number of simulations to run" />
+ <param name="polymorphism" type="select" multiple="true" label="Frequency/ies for minor allele">
+ <option value="0.001">0.001</option>
+ <option value="0.002">0.002</option>
+ <option value="0.003">0.003</option>
+ <option value="0.004">0.004</option>
+ <option value="0.005">0.005</option>
+ <option value="0.006">0.006</option>
+ <option value="0.007">0.007</option>
+ <option value="0.008">0.008</option>
+ <option value="0.009">0.009</option>
+ <option value="0.01">0.01</option>
+ <option value="0.02">0.02</option>
+ <option value="0.03">0.03</option>
+ <option value="0.04">0.04</option>
+ <option value="0.05">0.05</option>
+ <option value="0.06">0.06</option>
+ <option value="0.07">0.07</option>
+ <option value="0.08">0.08</option>
+ <option value="0.09">0.09</option>
+ <option value="0.1">0.1</option>
+ <option value="0.2">0.2</option>
+ <option value="0.3">0.3</option>
+ <option value="0.4">0.4</option>
+ <option value="0.5">0.5</option>
+ <option value="0.6">0.6</option>
+ <option value="0.7">0.7</option>
+ <option value="0.8">0.8</option>
+ <option value="0.9">0.9</option>
+ <option value="1.0">1.0</option>
+ </param>
+ <param name="detection_thresh" type="select" multiple="true" label="Detection thresholds">
+ <option value="0.001">0.001</option>
+ <option value="0.002">0.002</option>
+ <option value="0.003">0.003</option>
+ <option value="0.004">0.004</option>
+ <option value="0.005">0.005</option>
+ <option value="0.006">0.006</option>
+ <option value="0.007">0.007</option>
+ <option value="0.008">0.008</option>
+ <option value="0.009">0.009</option>
+ <option value="0.01">0.01</option>
+ <option value="0.02">0.02</option>
+ <option value="0.03">0.03</option>
+ <option value="0.04">0.04</option>
+ <option value="0.05">0.05</option>
+ <option value="0.06">0.06</option>
+ <option value="0.07">0.07</option>
+ <option value="0.08">0.08</option>
+ <option value="0.09">0.09</option>
+ <option value="0.1">0.1</option>
+ <option value="0.2">0.2</option>
+ <option value="0.3">0.3</option>
+ <option value="0.4">0.4</option>
+ <option value="0.5">0.5</option>
+ <option value="0.6">0.6</option>
+ <option value="0.7">0.7</option>
+ <option value="0.8">0.8</option>
+ <option value="0.9">0.9</option>
+ <option value="1.0">1.0</option>
+ </param>
+ <param name="summary_out" type="boolean" truevalue="true" falsevalue="false" checked="true" label="Include a (text) summary file for all the simulations" />
+<!-- <param name="sim_results" type="boolean" truevalue="true" falsevalue="false" checked="false" label="Output all tabular simulation results" help="Number of polymorphisms times number of detection thresholds"/>
+-->
+ </inputs>
+ <outputs>
+ <data format="png" name="output_png" />
+ <data format="tabular" name="output_summary">
+ <filter>summary_out == True</filter>
+ </data>
+<!--
+ <data format="tabular" name="output">
+ <filter>sim_files_out</filter>
+ </data>
+-->
+ </outputs>
+ <tests>
+ <!--
+ Tests cannot be run because of the non-deterministic element of the simulation.
+ But if you run the following "tests" manually in the browser and check against
+ the output files, they should be very similar to the listed output files.
+ -->
+ <!--
+ <test>
+ <param name="input_type" value="history" />
+ <param name="input1" value="ngs_simulation_in1.fasta" ftype="fasta" />
+ <param name="read_len" value="76" />
+ <param name="avg_coverage" value="200" />
+ <param name="error_rate" value="0.001" />
+ <param name="num_sims" value="25" />
+ <param name="polymorphism" value="0.02,0.04,0.1" />
+ <param name="detection_thresh" value="0.01,0.02" />
+ <param name="summary_out" value="true" />
+ <output name="output_png" file="ngs_simulation_out1.png" />
+ <output name="output_summary" file="ngs_simulation_out2.tabular" />
+ </test>
+ <test>
+ <param name="input_type" value="built-in" />
+ <param name="genome" value="pUC18" />
+ <param name="read_len" value="50" />
+ <param name="avg_coverage" value="150" />
+ <param name="error_rate" value="0.005" />
+ <param name="num_sims" value="25" />
+ <param name="polymorphism" value="0.001,0.005" />
+ <param name="detection_thresh" value="0.001,0.002" />
+ <param name="summary_out" value="false" />
+ <output name="output_png" file="ngs_simulation_out3.png" />
+ </test>
+ -->
+ </tests>
+ <help>
+
+**What it does**
+
+This tool simulates an Illumina run and provides plots of false positives and false negatives. It allows for a range of simulation parameters to be set. Note that this simulation sets only one (randomly chosen) position in the genome as polymorphic, according to the value specified. Superimposed on this are "sequencing errors", which are uniformly (and randomly) distributed. Polymorphisms are assigned using the detection threshold, so if the detection threshold is set to the same as the minor allele frequency, the expected false negative rate is 50%.
+
+**Parameter list**
+
+These are the parameters that should be set for the simulation::
+
+ Read length (which is the same for all reads)
+ Average Coverage
+ Frequency for Minor Allele
+ Sequencing Error Rate
+ Detection Threshold
+ Number of Simulations
+
+You also should choose to use either a built-in genome or supply your own FASTA file.
+
+**Output**
+
+There are one or two. The first is a png that contains two different plots and is always generated. The second is optional and is a text file with some summary information about the simulations that were run. Below are some example outputs for a 10-simulation run on phiX with the default settings::
+
+ Read length 76
+ Average coverage 200
+ Error rate/quality score 0.001
+ Number of simulations 100
+ Frequencies for minor allele 0.002
+ 0.004
+ Detection thresholds 0.003
+ 0.005
+ 0.007
+ Include summary file Yes
+
+Plot output (png):
+
+.. image:: ../static/images/ngs_simulation.png
+
+Summary output (txt)::
+
+ FP FN GENOMESIZE.5386 fprate hetcol errcol
+ Min. : 71.0 Min. :0.0 Mode:logical Min. :0.01318 Min. :0.004 Min. :0.007
+ 1st Qu.:86.0 1st Qu.:1.0 NA's:10 1st Qu.:0.01597 1st Qu.:0.004 1st Qu.:0.007
+ Median :92.5 Median :1.0 NA Median :0.01717 Median :0.004 Median :0.007
+ Mean :93.6 Mean :0.9 NA Mean :0.01738 Mean :0.004 Mean :0.007
+ 3rd Qu.:100.8 3rd Qu.:1.0 NA 3rd Qu.:0.01871 3rd Qu.:0.004 3rd Qu.:0.007
+ Max. :123.0 Max. :1.0 NA Max. :0.02284 Max. :0.004 Max. :0.007
+
+ False Positive Rate Summary
+ 0.003 0.005 0.007
+ 0.001 0.17711 0.10854 0.01673
+ 0.009 0.18049 0.10791 0.01738
+
+ False Negative Rate Summary
+ 0.003 0.005 0.007
+ 0.001 1.0 0.8 1.0
+ 0.009 0.4 0.7 0.9
+
+
+ </help>
+</tool>
+
+
Binary file test-data/ngs_simulation_out1.png has changed
--- a/tool_conf.xml.sample
+++ b/tool_conf.xml.sample
@@ -312,6 +312,9 @@
<tool file="genetrack/genetrack_indexer.xml" /><tool file="genetrack/genetrack_peak_prediction.xml" /></section>
+ <section name="NGS: Simulation" id="ngs-simulation">
+ <tool file="ngs_simulation/ngs_simulation.xml" />
+ </section><section name="SNP/WGA: Data; Filters" id="rgdat"><label text="Data: Import and upload" id="rgimport" /><tool file="data_source/upload.xml"/>
--- /dev/null
+++ b/test-data/ngs_simulation_in1.fasta
@@ -0,0 +1,41 @@
+>gi|209210|gb|L09136.1|SYNPUC18CV pUC18c cloning vector (beta-galactosidase mRNA on complementary strand)
+TCGCGCGTTTCGGTGATGACGGTGAAAACCTCTGACACATGCAGCTCCCGGAGACGGTCACAGCTTGTCT
+GTAAGCGGATGCCGGGAGCAGACAAGCCCGTCAGGGCGCGTCAGCGGGTGTTGGCGGGTGTCGGGGCTGG
+CTTAACTATGCGGCATCAGAGCAGATTGTACTGAGAGTGCACCATATGCGGTGTGAAATACCGCACAGAT
+GCGTAAGGAGAAAATACCGCATCAGGCGCCATTCGCCATTCAGGCTGCGCAACTGTTGGGAAGGGCGATC
+GGTGCGGGCCTCTTCGCTATTACGCCAGCTGGCGAAAGGGGGATGTGCTGCAAGGCGATTAAGTTGGGTA
+ACGCCAGGGTTTTCCCAGTCACGACGTTGTAAAACGACGGCCAGTGCCAAGCTTGCATGCCTGCAGGTCG
+ACTCTAGAGGATCCCCGGGTACCGAGCTCGAATTCGTAATCATGGTCATAGCTGTTTCCTGTGTGAAATT
+GTTATCCGCTCACAATTCCACACAACATACGAGCCGGAAGCATAAAGTGTAAAGCCTGGGGTGCCTAATG
+AGTGAGCTAACTCACATTAATTGCGTTGCGCTCACTGCCCGCTTTCCAGTCGGGAAACCTGTCGTGCCAG
+CTGCATTAATGAATCGGCCAACGCGCGGGGAGAGGCGGTTTGCGTATTGGGCGCTCTTCCGCTTCCTCGC
+TCACTGACTCGCTGCGCTCGGTCGTTCGGCTGCGGCGAGCGGTATCAGCTCACTCAAAGGCGGTAATACG
+GTTATCCACAGAATCAGGGGATAACGCAGGAAAGAACATGTGAGCAAAAGGCCAGCAAAAGGCCAGGAAC
+CGTAAAAAGGCCGCGTTGCTGGCGTTTTTCCATAGGCTCCGCCCCCCTGACGAGCATCACAAAAATCGAC
+GCTCAAGTCAGAGGTGGCGAAACCCGACAGGACTATAAAGATACCAGGCGTTTCCCCCTGGAAGCTCCCT
+CGTGCGCTCTCCTGTTCCGACCCTGCCGCTTACCGGATACCTGTCCGCCTTTCTCCCTTCGGGAAGCGTG
+GCGCTTTCTCATAGCTCACGCTGTAGGTATCTCAGTTCGGTGTAGGTCGTTCGCTCCAAGCTGGGCTGTG
+TGCACGAACCCCCCGTTCAGCCCGACCGCTGCGCCTTATCCGGTAACTATCGTCTTGAGTCCAACCCGGT
+AAGACACGACTTATCGCCACTGGCAGCAGCCACTGGTAACAGGATTAGCAGAGCGAGGTATGTAGGCGGT
+GCTACAGAGTTCTTGAAGTGGTGGCCTAACTACGGCTACACTAGAAGGACAGTATTTGGTATCTGCGCTC
+TGCTGAAGCCAGTTACCTTCGGAAAAAGAGTTGGTAGCTCTTGATCCGGCAAACAAACCACCGCTGGTAG
+CGGTGGTTTTTTTGTTTGCAAGCAGCAGATTACGCGCAGAAAAAAAGGATCTCAAGAAGATCCTTTGATC
+TTTTCTACGGGGTCTGACGCTCAGTGGAACGAAAACTCACGTTAAGGGATTTTGGTCATGAGATTATCAA
+AAAGGATCTTCACCTAGATCCTTTTAAATTAAAAATGAAGTTTTAAATCAATCTAAAGTATATATGAGTA
+AACTTGGTCTGACAGTTACCAATGCTTAATCAGTGAGGCACCTATCTCAGCGATCTGTCTATTTCGTTCA
+TCCATAGTTGCCTGACTCCCCGTCGTGTAGATAACTACGATACGGGAGGGCTTACCATCTGGCCCCAGTG
+CTGCAATGATACCGCGAGACCCACGCTCACCGGCTCCAGATTTATCAGCAATAAACCAGCCAGCCGGAAG
+GGCCGAGCGCAGAAGTGGTCCTGCAACTTTATCCGCCTCCATCCAGTCTATTAATTGTTGCCGGGAAGCT
+AGAGTAAGTAGTTCGCCAGTTAATAGTTTGCGCAACGTTGTTGCCATTGCTACAGGCATCGTGGTGTCAC
+GCTCGTCGTTTGGTATGGCTTCATTCAGCTCCGGTTCCCAACGATCAAGGCGAGTTACATGATCCCCCAT
+GTTGTGCAAAAAAGCGGTTAGCTCCTTCGGTCCTCCGATCGTTGTCAGAAGTAAGTTGGCCGCAGTGTTA
+TCACTCATGGTTATGGCAGCACTGCATAATTCTCTTACTGTCATGCCATCCGTAAGATGCTTTTCTGTGA
+CTGGTGAGTACTCAACCAAGTCATTCTGAGAATAGTGTATGCGGCGACCGAGTTGCTCTTGCCCGGCGTC
+AATACGGGATAATACCGCGCCACATAGCAGAACTTTAAAAGTGCTCATCATTGGAAAACGTTCTTCGGGG
+CGAAAACTCTCAAGGATCTTACCGCTGTTGAGATCCAGTTCGATGTAACCCACTCGTGCACCCAACTGAT
+CTTCAGCATCTTTTACTTTCACCAGCGTTTCTGGGTGAGCAAAAACAGGAAGGCAAAATGCCGCAAAAAA
+GGGAATAAGGGCGACACGGAAATGTTGAATACTCATACTCTTCCTTTTTCAATATTATTGAAGCATTTAT
+CAGGGTTATTGTCTCATGAGCGGATACATATTTGAATGTATTTAGAAAAATAAACAAATAGGGGTTCCGC
+GCACATTTCCCCGAAAAGTGCCACCTGACGTCTAAGAAACCATTATTATCATGACATTAACCTATAAAAA
+TAGGCGTATCACGAGGCCCTTTCGTC
+
--- a/tool_data_table_conf.xml.sample
+++ b/tool_data_table_conf.xml.sample
@@ -1,22 +1,27 @@
<tables>
- <!-- Locations of MAF files that have been indexed with bx-python -->
- <table name="indexed_maf_files">
- <columns>name, value, dbkey, species</columns>
- <file path="tool-data/maf_index.loc" />
+ <!-- Locations of indexes in the BFAST mapper format -->
+ <table name="bfast_indexes" comment_char="#">
+ <columns>value, dbkey, formats, name, path</columns>
+ <file path="tool-data/bfast_indexes.loc" />
+ </table>
+ <!-- Locations of indexes in the Bowtie mapper format -->
+ <table name="bowtie_indexes">
+ <columns>name, value</columns>
+ <file path="tool-data/bowtie_indices.loc" /></table><!-- Locations of indexes in the BWA mapper format --><table name="bwa_indexes"><columns>name, value</columns><file path="tool-data/bwa_index.loc" /></table>
- <!-- Locations of indexes in the Bowtie mapper format -->
- <table name="bowtie_indexes">
- <columns>name, value</columns>
- <file path="tool-data/bowtie_indices.loc" />
+ <!-- Locations of MAF files that have been indexed with bx-python -->
+ <table name="indexed_maf_files">
+ <columns>name, value, dbkey, species</columns>
+ <file path="tool-data/maf_index.loc" /></table>
- <!-- Locations of indexes in the BFAST mapper format -->
- <table name="bfast_indexes" comment_char="#">
- <columns>value, dbkey, formats, name, path</columns>
- <file path="tool-data/bfast_indexes.loc" />
+ <!-- Locations of fasta files appropriate for NGS simulation -->
+ <table name="ngs_sim_fasta" comment_char="#">
+ <columns>value, dbkey, name, path</columns>
+ <file path="tool-data/ngs_sim_fasta.loc" /></table></tables>
--- /dev/null
+++ b/tools/ngs_simulation/ngs_simulation.py
@@ -0,0 +1,280 @@
+#!/usr/bin/env python
+
+"""
+Runs Ben's simulation.
+
+usage: %prog [options]
+ -i, --input=i: Input genome (FASTA format)
+ -g, --genome=g: If built-in, the genome being used
+ -l, --read_len=l: Read length
+ -c, --avg_coverage=c: Average coverage
+ -e, --error_rate=e: Error rate (0-1)
+ -n, --num_sims=n: Number of simulations to run
+ -p, --polymorphism=p: Frequency/ies for minor allele (comma-separate list of 0-1)
+ -d, --detection_thresh=d: Detection thresholds (comma-separate list of 0-1)
+ -p, --output_png=p: Plot output
+ -s, --summary_out=s: Whether or not to output a file with summary of all simulations
+ -m, --output_summary=m: File name for output summary of all simulations
+ -f, --new_file_path=f: Directory for summary output files
+
+"""
+# removed output of all simulation results on request (not working)
+# -r, --sim_results=r: Output all tabular simulation results (number of polymorphisms times number of detection thresholds)
+# -o, --output=o: Base name for summary output for each run
+
+from rpy import *
+import os
+import random, sys, tempfile
+from galaxy import eggs
+import pkg_resources; pkg_resources.require( "bx-python" )
+from bx.cookbook import doc_optparse
+
+def stop_err( msg ):
+ sys.stderr.write( '%s\n' % msg )
+ sys.exit()
+
+def __main__():
+ #Parse Command Line
+ options, args = doc_optparse.parse( __doc__ )
+ # validate parameters
+ error = ''
+ try:
+ read_len = int( options.read_len )
+ if read_len <= 0:
+ raise Exception, ' greater than 0'
+ except TypeError, e:
+ error = ': %s' % str( e )
+ if error:
+ stop_err( 'Make sure your number of reads is an integer value%s' % error )
+ error = ''
+ try:
+ avg_coverage = int( options.avg_coverage )
+ if avg_coverage <= 0:
+ raise Exception, ' greater than 0'
+ except Exception, e:
+ error = ': %s' % str( e )
+ if error:
+ stop_err( 'Make sure your average coverage is an integer value%s' % error )
+ error = ''
+ try:
+ error_rate = float( options.error_rate )
+ if error_rate >= 1.0:
+ error_rate = 10 ** ( -error_rate / 10.0 )
+ elif error_rate < 0:
+ raise Exception, ' between 0 and 1'
+ except Exception, e:
+ error = ': %s' % str( e )
+ if error:
+ stop_err( 'Make sure the error rate is a decimal value%s or the quality score is at least 1' % error )
+ try:
+ num_sims = int( options.num_sims )
+ except TypeError, e:
+ stop_err( 'Make sure the number of simulations is an integer value: %s' % str( e ) )
+ if len( options.polymorphism ) > 0:
+ polymorphisms = [ float( p ) for p in options.polymorphism.split( ',' ) ]
+ else:
+ stop_err( 'Select at least one polymorphism value to use' )
+ if len( options.detection_thresh ) > 0:
+ detection_threshes = [ float( dt ) for dt in options.detection_thresh.split( ',' ) ]
+ else:
+ stop_err( 'Select at least one detection threshold to use' )
+
+ # mutation dictionaries
+ hp_dict = { 'A':'G', 'G':'A', 'C':'T', 'T':'C', 'N':'N' } # heteroplasmy dictionary
+ mt_dict = { 'A':'C', 'C':'A', 'G':'T', 'T':'G', 'N':'N'} # misread dictionary
+
+ # read fasta file to seq string
+ all_lines = open( options.input, 'rb' ).readlines()
+ seq = ''
+ for line in all_lines:
+ line = line.rstrip()
+ if line.startswith('>'):
+ pass
+ else:
+ seq += line.upper()
+ seq_len = len( seq )
+
+ # output file name template
+# removed output of all simulation results on request (not working)
+# if options.sim_results == "true":
+# out_name_template = os.path.join( options.new_file_path, 'primary_output%s_' + options.output + '_visible_tabular' )
+# else:
+# out_name_template = tempfile.NamedTemporaryFile().name + '_%s'
+ out_name_template = tempfile.NamedTemporaryFile().name + '_%s'
+ print 'out_name_template:', out_name_template
+
+ # set up output files
+ outputs = {}
+ i = 1
+ for p in polymorphisms:
+ outputs[ p ] = {}
+ for d in detection_threshes:
+ outputs[ p ][ d ] = out_name_template % i
+ i += 1
+
+ # run sims
+ for polymorphism in polymorphisms:
+ for detection_thresh in detection_threshes:
+ output = open( outputs[ polymorphism ][ detection_thresh ], 'wb' )
+ output.write( 'FP\tFN\tGENOMESIZE=%s\n' % seq_len )
+ sim_count = 0
+ while sim_count < num_sims:
+ # randomly pick heteroplasmic base index
+ hbase = random.choice( range( 0, seq_len ) )
+ #hbase = seq_len/2#random.randrange( 0, seq_len )
+ # create 2D quasispecies list
+ qspec = map( lambda x: [], [0] * seq_len )
+ # simulate read indices and assign to quasispecies
+ i = 0
+ while i < ( avg_coverage * ( seq_len / read_len ) ): # number of reads (approximates coverage)
+ start = random.choice( range( 0, seq_len ) )
+ #start = seq_len/2#random.randrange( 0, seq_len ) # assign read start
+ if random.random() < 0.5: # positive sense read
+ end = start + read_len # assign read end
+ if end > seq_len: # overshooting origin
+ read = range( start, seq_len ) + range( 0, ( end - seq_len ) )
+ else: # regular read
+ read = range( start, end )
+ else: # negative sense read
+ end = start - read_len # assign read end
+ if end < -1: # overshooting origin
+ read = range( start, -1, -1) + range( ( seq_len - 1 ), ( seq_len + end ), -1 )
+ else: # regular read
+ read = range( start, end, -1 )
+ # assign read to quasispecies list by index
+ for j in read:
+ if j == hbase and random.random() < polymorphism: # heteroplasmic base is variant with p = het
+ ref = hp_dict[ seq[ j ] ]
+ else: # ref is the verbatim reference nucleotide (all positions)
+ ref = seq[ j ]
+ if random.random() < error_rate: # base in read is misread with p = err
+ qspec[ j ].append( mt_dict[ ref ] )
+ else: # otherwise we carry ref through to the end
+ qspec[ j ].append(ref)
+ # last but not least
+ i += 1
+ bases, fpos, fneg = {}, 0, 0 # last two will be outputted to summary file later
+ for i, nuc in enumerate( seq ):
+ cov = len( qspec[ i ] )
+ bases[ 'A' ] = qspec[ i ].count( 'A' )
+ bases[ 'C' ] = qspec[ i ].count( 'C' )
+ bases[ 'G' ] = qspec[ i ].count( 'G' )
+ bases[ 'T' ] = qspec[ i ].count( 'T' )
+ # calculate max NON-REF deviation
+ del bases[ nuc ]
+ maxdev = float( max( bases.values() ) ) / cov
+ # deal with non-het sites
+ if i != hbase:
+ if maxdev >= detection_thresh: # greater than detection threshold = false positive
+ fpos += 1
+ # deal with het sites
+ if i == hbase:
+ hnuc = hp_dict[ nuc ] # let's recover het variant
+ if ( float( bases[ hnuc ] ) / cov ) < detection_thresh: # less than detection threshold = false negative
+ fneg += 1
+ del bases[ hnuc ] # ignore het variant
+ maxdev = float( max( bases.values() ) ) / cov # check other non-ref bases at het site
+ if maxdev >= detection_thresh: # greater than detection threshold = false positive (possible)
+ fpos += 1
+ # output error sums and genome size to summary file
+ output.write( '%d\t%d\n' % ( fpos, fneg ) )
+ sim_count += 1
+ # close output up
+ output.close()
+
+ # Parameters (heteroplasmy, error threshold, colours)
+ r( '''
+ het=c(%s)
+ err=c(%s)
+ grade = (0:32)/32
+ hues = rev(gray(grade))
+ ''' % ( ','.join( [ str( p ) for p in polymorphisms ] ), ','.join( [ str( d ) for d in detection_threshes ] ) ) )
+
+ # Suppress warnings
+ r( 'options(warn=-1)' )
+
+ # Create allsum (for FP) and allneg (for FN) objects
+ r( 'allsum <- data.frame()' )
+ for polymorphism in polymorphisms:
+ for detection_thresh in detection_threshes:
+ output = outputs[ polymorphism ][ detection_thresh ]
+ cmd = '''
+ ngsum = read.delim('%s', header=T)
+ ngsum$fprate <- ngsum$FP/%s
+ ngsum$hetcol <- %s
+ ngsum$errcol <- %s
+ allsum <- rbind(allsum, ngsum)
+ ''' % ( output, seq_len, polymorphism, detection_thresh )
+ r( cmd )
+
+ if os.path.getsize( output ) == 0:
+ for p in outputs.keys():
+ for d in outputs[ p ].keys():
+ sys.stderr.write(outputs[ p ][ d ] + ' '+str( os.path.getsize( outputs[ p ][ d ] ) )+'\n')
+
+ if options.summary_out == "true":
+ r( 'write.table(summary(ngsum), file="%s", quote=FALSE, sep="\t", row.names=FALSE)' % options.output_summary )
+
+ # Summary objects (these could be printed)
+ r( '''
+ tr_pos <- tapply(allsum$fprate,list(allsum$hetcol,allsum$errcol), mean)
+ tr_neg <- tapply(allsum$FN,list(allsum$hetcol,allsum$errcol), mean)
+ cat('\nFalse Positive Rate Summary\n\t', file='%s', append=T, sep='\t')
+ write.table(format(tr_pos, digits=4), file='%s', append=T, quote=F, sep='\t')
+ cat('\nFalse Negative Rate Summary\n\t', file='%s', append=T, sep='\t')
+ write.table(format(tr_neg, digits=4), file='%s', append=T, quote=F, sep='\t')
+ ''' % tuple( [ options.output_summary ] * 4 ) )
+
+ # Setup graphs
+ #pdf(paste(prefix,'_jointgraph.pdf',sep=''), 15, 10)
+ r( '''
+ png('%s', width=800, height=500, units='px', res=250)
+ layout(matrix(data=c(1,2,1,3,1,4), nrow=2, ncol=3), widths=c(4,6,2), heights=c(1,10,10))
+ ''' % options.output_png )
+
+ # Main title
+ genome = ''
+ if options.genome:
+ genome = '%s: ' % options.genome
+ r( '''
+ par(mar=c(0,0,0,0))
+ plot(1, type='n', axes=F, xlab='', ylab='')
+ text(1,1,paste('%sVariation in False Positives and Negatives (', %s, ' simulations, coverage ', %s,')', sep=''), font=2, family='sans', cex=0.7)
+ ''' % ( genome, options.num_sims, options.avg_coverage ) )
+
+ # False positive boxplot
+ r( '''
+ par(mar=c(5,4,2,2), las=1, cex=0.35)
+ boxplot(allsum$fprate ~ allsum$errcol, horizontal=T, ylim=rev(range(allsum$fprate)), cex.axis=0.85)
+ title(main='False Positives', xlab='false positive rate', ylab='')
+ ''' )
+
+ # False negative heatmap (note zlim command!)
+ num_polys = len( polymorphisms )
+ num_dets = len( detection_threshes )
+ r( '''
+ par(mar=c(5,4,2,1), las=1, cex=0.35)
+ image(1:%s, 1:%s, tr_neg, zlim=c(0,1), col=hues, xlab='', ylab='', axes=F, border=1)
+ axis(1, at=1:%s, labels=rownames(tr_neg), lwd=1, cex.axis=0.85, axs='i')
+ axis(2, at=1:%s, labels=colnames(tr_neg), lwd=1, cex.axis=0.85)
+ title(main='False Negatives', xlab='minor allele frequency', ylab='detection threshold')
+ ''' % ( num_polys, num_dets, num_polys, num_dets ) )
+
+ # Scale alongside
+ r( '''
+ par(mar=c(2,2,2,3), las=1)
+ image(1, grade, matrix(grade, ncol=length(grade), nrow=1), col=hues, xlab='', ylab='', xaxt='n', las=1, cex.axis=0.85)
+ title(main='Key', cex=0.35)
+ mtext('false negative rate', side=1, cex=0.35)
+ ''' )
+
+ # Close graphics
+ r( '''
+ layout(1)
+ dev.off()
+ ''' )
+
+ # Tidy up
+# r( 'rm(folder,prefix,sim,cov,het,err,grade,hues,i,j,ngsum)' )
+
+if __name__ == "__main__" : __main__()
--- /dev/null
+++ b/test-data/ngs_simulation_out2.tabular
@@ -0,0 +1,19 @@
+ FP FN GENOMESIZE.2686 fprate hetcol errcol
+Min. :0.00 Min. :0 Mode:logical Min. :0.000e+00 Min. :0.1 Min. :0.02
+1st Qu.:0.00 1st Qu.:0 NA's:25 1st Qu.:0.000e+00 1st Qu.:0.1 1st Qu.:0.02
+Median :0.00 Median :0 NA Median :0.000e+00 Median :0.1 Median :0.02
+Mean :0.04 Mean :0 NA Mean :1.489e-05 Mean :0.1 Mean :0.02
+3rd Qu.:0.00 3rd Qu.:0 NA 3rd Qu.:0.000e+00 3rd Qu.:0.1 3rd Qu.:0.02
+Max. :1.00 Max. :0 NA Max. :3.723e-04 Max. :0.1 Max. :0.02
+
+False Positive Rate Summary
+ 0.01 0.02
+0.02 9.710e-03 4.468e-05
+0.04 9.680e-03 1.489e-05
+0.1 9.695e-03 1.489e-05
+
+False Negative Rate Summary
+ 0.01 0.02
+0.02 0.16 0.52
+0.04 0.00 0.04
+0.1 0.00 0.00
1
0
galaxy-dist commit cdf8d61425cc: Fix typo when running a workflow that contains an updated tool.
by commits-noreply@bitbucket.org 20 Nov '10
by commits-noreply@bitbucket.org 20 Nov '10
20 Nov '10
# HG changeset patch -- Bitbucket.org
# Project galaxy-dist
# URL http://bitbucket.org/galaxy/galaxy-dist/overview
# User Daniel Blankenberg <dan(a)bx.psu.edu>
# Date 1288898016 14400
# Node ID cdf8d61425cce011f98b1f24bd9fe19dc59b10ab
# Parent bc690ccf23396e1c7e29e8ee801996ac3e3d3409
Fix typo when running a workflow that contains an updated tool.
--- a/templates/workflow/run.mako
+++ b/templates/workflow/run.mako
@@ -123,7 +123,7 @@ from galaxy.jobs.actions.post import Act
%if has_upgrade_messages:
<div class="warningmessage">
- Problems were encourered when loading this workflow, likely due to tool
+ Problems were encountered when loading this workflow, likely due to tool
version changes. Missing parameter values have been replaced with default.
Please review the parameter values below.
</div>
1
0
galaxy-dist commit 16bd91a54888: Must be logged in to use api keys. Fix small typo in error messages
by commits-noreply@bitbucket.org 20 Nov '10
by commits-noreply@bitbucket.org 20 Nov '10
20 Nov '10
# HG changeset patch -- Bitbucket.org
# Project galaxy-dist
# URL http://bitbucket.org/galaxy/galaxy-dist/overview
# User Kanwei Li <kanwei(a)gmail.com>
# Date 1288813870 14400
# Node ID 16bd91a548887fb0be24b981c2d66fb7ef7b1922
# Parent cf8bef68e8befb8b6631578b71ff69f701fc0d4d
Must be logged in to use api keys. Fix small typo in error messages
--- a/lib/galaxy/web/controllers/user.py
+++ b/lib/galaxy/web/controllers/user.py
@@ -984,6 +984,7 @@ class User( BaseController, UsesFormDefi
message=message,
lines_skipped=lines_skipped )
@web.expose
+ @web.require_login()
def api_keys( self, trans, **kwd ):
params = util.Params( kwd )
message = util.restore_text( params.get( 'message', '' ) )
--- a/lib/galaxy/web/framework/__init__.py
+++ b/lib/galaxy/web/framework/__init__.py
@@ -84,7 +84,7 @@ def require_login( verb="perform this ac
return func( self, trans, *args, **kwargs )
else:
return trans.show_error_message(
- 'You must be <a target="_top" href="%s">logged in</a> to %s</div>.'
+ 'You must be <a target="_top" href="%s">logged in</a> to %s.'
% ( url_for( controller='user', action='login', webapp=webapp ), verb ), use_panels=use_panels )
return decorator
return argcatcher
1
0
galaxy-dist commit f372ea5a6014: Fix interpreter for the FASTX Barcode Splitter.
by commits-noreply@bitbucket.org 20 Nov '10
by commits-noreply@bitbucket.org 20 Nov '10
20 Nov '10
# HG changeset patch -- Bitbucket.org
# Project galaxy-dist
# URL http://bitbucket.org/galaxy/galaxy-dist/overview
# User Nate Coraor <nate(a)bx.psu.edu>
# Date 1288902351 14400
# Node ID f372ea5a601443a9b9cd1d3f7e04ddc24db5b57a
# Parent cdf8d61425cce011f98b1f24bd9fe19dc59b10ab
Fix interpreter for the FASTX Barcode Splitter.
--- a/tools/fastx_toolkit/fastx_barcode_splitter.xml
+++ b/tools/fastx_toolkit/fastx_barcode_splitter.xml
@@ -1,7 +1,7 @@
<tool id="cshl_fastx_barcode_splitter" name="Barcode Splitter"><description></description><requirements><requirement type="package">fastx_toolkit</requirement></requirements>
- <command interpreter="sh">fastx_barcode_splitter_galaxy_wrapper.sh $BARCODE $input "$input.name" "$output.files_path" --mismatches $mismatches --partial $partial $EOL > $output </command>
+ <command interpreter="bash">fastx_barcode_splitter_galaxy_wrapper.sh $BARCODE $input "$input.name" "$output.files_path" --mismatches $mismatches --partial $partial $EOL > $output </command><inputs><param format="txt" name="BARCODE" type="data" label="Barcodes to use" />
1
0
galaxy-dist commit cf8bef68e8be: Correction to docstring for Tool.build_param_dict() -- from peter@maubp.freeserve.co.uk
by commits-noreply@bitbucket.org 20 Nov '10
by commits-noreply@bitbucket.org 20 Nov '10
20 Nov '10
# HG changeset patch -- Bitbucket.org
# Project galaxy-dist
# URL http://bitbucket.org/galaxy/galaxy-dist/overview
# User jeremy goecks <jeremy.goecks(a)emory.edu>
# Date 1288810958 14400
# Node ID cf8bef68e8befb8b6631578b71ff69f701fc0d4d
# Parent b1ec8342053f3cdcd0a081ff28f077a76bd188cc
Correction to docstring for Tool.build_param_dict() -- from peter(a)maubp.freeserve.co.uk
--- a/lib/galaxy/tools/__init__.py
+++ b/lib/galaxy/tools/__init__.py
@@ -1333,7 +1333,7 @@ class Tool:
line. Each value is wrapped in a `InputValueWrapper`, which allows
all the attributes of the value to be used in the template, *but*
when the __str__ method is called it actually calls the
- `to_param_dict_value` method of the associated input.
+ `to_param_dict_string` method of the associated input.
"""
param_dict = dict()
# All parameters go into the param_dict
1
0
galaxy-dist commit 6838e10e5912: Fix for TextToolParameter.get_html_field when provided value is an empty string but default value specified in tool is non-empty string. Fixes issue with rerun button where if a user had input an empty string, the form displayed when rerun would have the default value from the tool and not the actual previously specified value.
by commits-noreply@bitbucket.org 20 Nov '10
by commits-noreply@bitbucket.org 20 Nov '10
20 Nov '10
# HG changeset patch -- Bitbucket.org
# Project galaxy-dist
# URL http://bitbucket.org/galaxy/galaxy-dist/overview
# User Daniel Blankenberg <dan(a)bx.psu.edu>
# Date 1288818754 14400
# Node ID 6838e10e5912cec46060bda189841edba305ac1d
# Parent 16bd91a548887fb0be24b981c2d66fb7ef7b1922
Fix for TextToolParameter.get_html_field when provided value is an empty string but default value specified in tool is non-empty string. Fixes issue with rerun button where if a user had input an empty string, the form displayed when rerun would have the default value from the tool and not the actual previously specified value.
--- a/lib/galaxy/tools/parameters/basic.py
+++ b/lib/galaxy/tools/parameters/basic.py
@@ -165,10 +165,11 @@ class TextToolParameter( ToolParameter )
self.value = elem.get( 'value' )
self.area = string_as_bool( elem.get( 'area', False ) )
def get_html_field( self, trans=None, value=None, other_values={} ):
+ if value is None: value = self.value
if self.area:
- return form_builder.TextArea( self.name, self.size, value or self.value )
+ return form_builder.TextArea( self.name, self.size, value )
else:
- return form_builder.TextField( self.name, self.size, value or self.value )
+ return form_builder.TextField( self.name, self.size, value )
def get_initial_value( self, trans, context ):
return self.value
1
0
20 Nov '10
# 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(a)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(a)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
1
0
galaxy-dist commit e000a6800e1c: trackster: Fix summary_tree data provider to reflect bottom level not being indexed anymore.
by commits-noreply@bitbucket.org 20 Nov '10
by commits-noreply@bitbucket.org 20 Nov '10
20 Nov '10
# HG changeset patch -- Bitbucket.org
# Project galaxy-dist
# URL http://bitbucket.org/galaxy/galaxy-dist/overview
# User Kanwei Li <kanwei(a)gmail.com>
# Date 1288748135 14400
# Node ID e000a6800e1cbfa15a190bb2aff90a5956882a43
# Parent 56948309109207f932a113e464409432c7a38df7
trackster: Fix summary_tree data provider to reflect bottom level not being indexed anymore.
- Fix a bug causing no display modes to appear.
- Update "Visualize in Trackster" init code in root/history.mako
Fix small typo in root/tool_menu.mako
--- a/templates/root/tool_menu.mako
+++ b/templates/root/tool_menu.mako
@@ -32,7 +32,7 @@
<div class="toolTitleNoSection">
%endif
<% encoded_id = key.lstrip( 'workflow_' ) %>
- <a id="link-${workflow.id}" href="${ h.url_for( controller='workflow', action='run', id=encoded_id, check_user=False )}" target="_parent"}">${_(workflow.name)}</a>
+ <a id="link-${workflow.id}" href="${ h.url_for( controller='workflow', action='run', id=encoded_id, check_user=False )}" target="_parent">${_(workflow.name)}</a></div></%def>
--- a/static/scripts/trackster.js
+++ b/static/scripts/trackster.js
@@ -677,7 +677,7 @@ var TiledTrack = function() {
track.draw();
};
var mode_mapping = {};
- for (var i, len = track.display_modes.length; i < len; i++) {
+ for (var i = 0, len = track.display_modes.length; i < len; i++) {
var mode = track.display_modes[i];
mode_mapping[mode] = function(mode) {
return function() { change_mode(mode); };
--- a/lib/galaxy/visualization/tracks/data_providers.py
+++ b/lib/galaxy/visualization/tracks/data_providers.py
@@ -102,14 +102,14 @@ class SummaryTreeDataProvider( TracksDat
level = ceil( log( resolution, st.block_size ) ) - 1
level = int(max( level, 0 ))
- if level <= 0:
+ if level <= 1:
return None
stats = st.chrom_stats[chrom]
results = st.query(chrom, int(start), int(end), level)
if results == "detail":
return None
- elif results == "draw" or level <= 1:
+ elif results == "draw":
return "no_detail"
else:
return results, stats[level]["max"], stats[level]["avg"], stats[level]["delta"]
--- a/templates/root/history.mako
+++ b/templates/root/history.mako
@@ -157,29 +157,33 @@ TERMINAL_STATES = ${ h.to_json_string(TE
// Trackster links
function init_trackster_links() {
- $("a.trackster").live( "click", function() {
- var link = $(this),
- hid = link.attr("id").split("_")[1]; // visualize_{id}
-
+ // Add to trackster browser functionality
+ $(".trackster-add").live("click", function() {
+ var dataset = this,
+ dataset_jquery = $(this);
$.ajax({
- url: "${h.url_for( controller='tracks', action='list_tracks' )}",
- data: {'hid': hid},
- error: function() { alert( "Visualization error" ); },
- success: function(html) {
- show_modal("Add Track — Select Dataset(s)", html, {
- "New Browser": function() {
- hide_modal();
+ url: dataset_jquery.attr("data-url"),
+ dataType: "html",
+ error: function() { alert( "Could not add this dataset to browser." ); },
+ success: function(table_html) {
+ var parent = window.parent;
+ parent.show_modal("Add to Browser:", table_html, {
+ "Cancel": function() {
+ parent.hide_modal();
},
- "Insert": function() {
- hide_modal();
+ "Insert into selected": function() {
+ $(parent.document).find('input[name=id]:checked').each(function() {
+ var vis_id = $(this).val();
+ parent.location = dataset_jquery.attr("action-url") + "&id=" + vis_id;
+ });
},
- "Cancel": function() {
- hide_modal();
+ "Insert into new browser": function() {
+ parent.location = dataset_jquery.attr("new-url");
}
});
}
});
- });
+ });
}
init_trackster_links();
--- a/static/scripts/packed/trackster.js
+++ b/static/scripts/packed/trackster.js
@@ -1,1 +1,1 @@
-var DENSITY=200,FEATURE_LEVELS=10,MAX_FEATURE_DEPTH=50,CONNECTOR_COLOR="#ccc",DATA_ERROR="There was an error in indexing this dataset.",DATA_NOCONVERTER="A converter for this dataset is not installed. Please check your datatypes_conf.xml file.",DATA_NONE="No data for this chrom/contig.",DATA_PENDING="Currently indexing... please wait",DATA_LOADING="Loading data...",FILTERABLE_CLASS="filterable",CACHED_TILES_FEATURE=10,CACHED_TILES_LINE=5,CACHED_DATA=5,DUMMY_CANVAS=document.createElement("canvas"),RIGHT_STRAND,LEFT_STRAND;if(window.G_vmlCanvasManager){G_vmlCanvasManager.initElement(DUMMY_CANVAS)}CONTEXT=DUMMY_CANVAS.getContext("2d");PX_PER_CHAR=CONTEXT.measureText("A").width;var right_img=new Image();right_img.src=image_path+"/visualization/strand_right.png";right_img.onload=function(){RIGHT_STRAND=CONTEXT.createPattern(right_img,"repeat")};var left_img=new Image();left_img.src=image_path+"/visualization/strand_left.png";left_img.onload=function(){LEFT_STRAND=CONTEXT.createPa
ttern(left_img,"repeat")};var right_img_inv=new Image();right_img_inv.src=image_path+"/visualization/strand_right_inv.png";right_img_inv.onload=function(){RIGHT_STRAND_INV=CONTEXT.createPattern(right_img_inv,"repeat")};var left_img_inv=new Image();left_img_inv.src=image_path+"/visualization/strand_left_inv.png";left_img_inv.onload=function(){LEFT_STRAND_INV=CONTEXT.createPattern(left_img_inv,"repeat")};function round_1000(a){return Math.round(a*1000)/1000}var Cache=function(a){this.num_elements=a;this.clear()};$.extend(Cache.prototype,{get:function(b){var a=this.key_ary.indexOf(b);if(a!=-1){this.key_ary.splice(a,1);this.key_ary.push(b)}return this.obj_cache[b]},set:function(b,c){if(!this.obj_cache[b]){if(this.key_ary.length>=this.num_elements){var a=this.key_ary.shift();delete this.obj_cache[a]}this.key_ary.push(b)}this.obj_cache[b]=c;return c},clear:function(){this.obj_cache={};this.key_ary=[]}});var View=function(a,d,c,b){this.container=a;this.vis_id=c;this.dbkey=b;this.ti
tle=d;this.tracks=[];this.label_tracks=[];this.max_low=0;this.max_high=0;this.num_tracks=0;this.track_id_counter=0;this.zoom_factor=3;this.min_separation=30;this.has_changes=false;this.init();this.reset()};$.extend(View.prototype,{init:function(){var c=this.container,a=this;this.top_labeltrack=$("<div/>").addClass("top-labeltrack").appendTo(c);this.content_div=$("<div/>").addClass("content").css("position","relative").appendTo(c);this.viewport_container=$("<div/>").addClass("viewport-container").addClass("viewport-container").appendTo(this.content_div);this.intro_div=$("<div/>").addClass("intro").text("Select a chrom from the dropdown below").hide();this.nav_container=$("<div/>").addClass("nav-container").appendTo(c);this.nav_labeltrack=$("<div/>").addClass("nav-labeltrack").appendTo(this.nav_container);this.nav=$("<div/>").addClass("nav").appendTo(this.nav_container);this.overview=$("<div/>").addClass("overview").appendTo(this.nav);this.overview_viewport=$("<div/>").addClas
s("overview-viewport").appendTo(this.overview);this.overview_close=$("<a href='javascript:void(0);'>Close Overview</a>").addClass("overview-close").hide().appendTo(this.overview_viewport);this.overview_highlight=$("<div />").addClass("overview-highlight").hide().appendTo(this.overview_viewport);this.overview_box_background=$("<div/>").addClass("overview-boxback").appendTo(this.overview_viewport);this.overview_box=$("<div/>").addClass("overview-box").appendTo(this.overview_viewport);this.default_overview_height=this.overview_box.height();this.nav_controls=$("<div/>").addClass("nav-controls").appendTo(this.nav);this.chrom_form=$("<form/>").attr("action",function(){}).appendTo(this.nav_controls);this.chrom_select=$("<select/>").attr({name:"chrom"}).css("width","15em").addClass("no-autocomplete").append("<option value=''>Loading</option>").appendTo(this.chrom_form);var b=function(d){if(d.type==="focusout"||(d.keyCode||d.which)===13||(d.keyCode||d.which)===27){if((d.keyCode||d.wh
ich)!==27){a.go_to($(this).val())}$(this).hide();a.location_span.show();a.chrom_select.show();return false}};this.nav_input=$("<input/>").addClass("nav-input").hide().bind("keypress focusout",b).appendTo(this.chrom_form);this.location_span=$("<span/>").addClass("location").appendTo(this.chrom_form);this.location_span.bind("click",function(){a.location_span.hide();a.chrom_select.hide();a.nav_input.css("display","inline-block");a.nav_input.select();a.nav_input.focus()});if(this.vis_id!==undefined){this.hidden_input=$("<input/>").attr("type","hidden").val(this.vis_id).appendTo(this.chrom_form)}this.zo_link=$("<a/>").click(function(){a.zoom_out();a.redraw()}).html('<img src="'+image_path+'/fugue/magnifier-zoom-out.png" />').appendTo(this.chrom_form);this.zi_link=$("<a/>").click(function(){a.zoom_in();a.redraw()}).html('<img src="'+image_path+'/fugue/magnifier-zoom.png" />').appendTo(this.chrom_form);$.ajax({url:chrom_url,data:(this.vis_id!==undefined?{vis_id:this.vis_id}:{dbkey:
this.dbkey}),dataType:"json",success:function(e){if(e.reference){a.add_label_track(new ReferenceTrack(a))}a.chrom_data=e.chrom_info;var h='<option value="">Select Chrom/Contig</option>';for(var g=0,d=a.chrom_data.length;g<d;g++){var f=a.chrom_data[g].chrom;h+='<option value="'+f+'">'+f+"</option>"}a.chrom_select.html(h);a.intro_div.show();a.chrom_select.bind("change",function(){a.change_chrom(a.chrom_select.val())})},error:function(){alert("Could not load chroms for this dbkey:",a.dbkey)}});this.content_div.bind("dblclick",function(d){a.zoom_in(d.pageX,this.viewport_container)});this.overview_box.bind("dragstart",function(d){this.current_x=d.offsetX}).bind("drag",function(d){var g=d.offsetX-this.current_x;this.current_x=d.offsetX;var f=Math.round(g/a.viewport_container.width()*(a.max_high-a.max_low));a.move_delta(-f)});this.overview_close.bind("click",function(){for(var e=0,d=a.tracks.length;e<d;e++){a.tracks[e].is_overview=false}$(this).siblings().filter("canvas").remove();
$(this).parent().css("height",a.overview_box.height());a.overview_highlight.hide();$(this).hide()});this.viewport_container.bind("dragstart",function(d){this.original_low=a.low;this.current_height=d.clientY;this.current_x=d.offsetX;this.enable_pan=(d.clientX<a.viewport_container.width()-16)?true:false}).bind("drag",function(g){if(!this.enable_pan||this.in_reordering){return}var d=$(this);var i=g.offsetX-this.current_x;var f=d.scrollTop()-(g.clientY-this.current_height);d.scrollTop(f);this.current_height=g.clientY;this.current_x=g.offsetX;var h=Math.round(i/a.viewport_container.width()*(a.high-a.low));a.move_delta(h)});this.top_labeltrack.bind("dragstart",function(d){this.drag_origin_x=d.clientX;this.drag_origin_pos=d.clientX/a.viewport_container.width()*(a.high-a.low)+a.low;this.drag_div=$("<div />").css({height:a.content_div.height()+30,top:"0px",position:"absolute","background-color":"#cfc",border:"1px solid #6a6",opacity:0.5,"z-index":1000}).appendTo($(this))}).bind("drag
",function(i){var f=Math.min(i.clientX,this.drag_origin_x)-a.container.offset().left,d=Math.max(i.clientX,this.drag_origin_x)-a.container.offset().left,h=(a.high-a.low),g=a.viewport_container.width();a.update_location(Math.round(f/g*h)+a.low,Math.round(d/g*h)+a.low);this.drag_div.css({left:f+"px",width:(d-f)+"px"})}).bind("dragend",function(j){var f=Math.min(j.clientX,this.drag_origin_x),d=Math.max(j.clientX,this.drag_origin_x),h=(a.high-a.low),g=a.viewport_container.width(),i=a.low;a.low=Math.round(f/g*h)+i;a.high=Math.round(d/g*h)+i;this.drag_div.remove();a.redraw()});this.add_label_track(new LabelTrack(this,this.top_labeltrack));this.add_label_track(new LabelTrack(this,this.nav_labeltrack));$(window).bind("resize",function(){a.resize_window()});$(document).bind("redraw",function(){a.redraw()});this.reset();$(window).trigger("resize")},update_location:function(a,b){this.location_span.text(commatize(a)+" - "+commatize(b));this.nav_input.val(this.chrom+":"+commatize(a)+"-"+c
ommatize(b))},change_chrom:function(e,b,g){var d=this;var f=$.grep(d.chrom_data,function(j,k){return j.chrom===e})[0];if(f===undefined){return}if(e!==d.chrom){d.chrom=e;if(!d.chrom){d.intro_div.show()}else{d.intro_div.hide()}d.chrom_select.val(d.chrom);d.max_high=f.len;d.reset();d.redraw(true);for(var h=0,a=d.tracks.length;h<a;h++){var c=d.tracks[h];if(c.init){c.init()}}}if(b!==undefined&&g!==undefined){d.low=Math.max(b,0);d.high=Math.min(g,d.max_high)}d.reset_overview();d.redraw()},go_to:function(f){var j=this,a,d,b=f.split(":"),h=b[0],i=b[1];if(i!==undefined){try{var g=i.split("-");a=parseInt(g[0].replace(/,/g,""),10);d=parseInt(g[1].replace(/,/g,""),10)}catch(c){return false}}j.change_chrom(h,a,d)},move_delta:function(c){var a=this;var b=a.high-a.low;if(a.low-c<a.max_low){a.low=a.max_low;a.high=a.max_low+b}else{if(a.high-c>a.max_high){a.high=a.max_high;a.low=a.max_high-b}else{a.high-=c;a.low-=c}}a.redraw()},add_track:function(a){a.view=this;a.track_id=this.track_id_counte
r;this.tracks.push(a);if(a.init){a.init()}a.container_div.attr("id","track_"+a.track_id);this.track_id_counter+=1;this.num_tracks+=1},add_label_track:function(a){a.view=this;this.label_tracks.push(a)},remove_track:function(a){this.has_changes=true;a.container_div.fadeOut("slow",function(){$(this).remove()});delete this.tracks[this.tracks.indexOf(a)];this.num_tracks-=1},reset:function(){this.low=this.max_low;this.high=this.max_high;this.viewport_container.find(".yaxislabel").remove()},redraw:function(h){var g=this.high-this.low,f=this.low,b=this.high;if(f<this.max_low){f=this.max_low}if(b>this.max_high){b=this.max_high}if(this.high!==0&&g<this.min_separation){b=f+this.min_separation}this.low=Math.floor(f);this.high=Math.ceil(b);this.resolution=Math.pow(10,Math.ceil(Math.log((this.high-this.low)/200)/Math.LN10));this.zoom_res=Math.pow(FEATURE_LEVELS,Math.max(0,Math.ceil(Math.log(this.resolution,FEATURE_LEVELS)/Math.log(FEATURE_LEVELS))));var a=(this.low/(this.max_high-this.max
_low)*this.overview_viewport.width())||0;var e=((this.high-this.low)/(this.max_high-this.max_low)*this.overview_viewport.width())||0;var j=13;this.overview_box.css({left:a,width:Math.max(j,e)}).show();if(e<j){this.overview_box.css("left",a-(j-e)/2)}if(this.overview_highlight){this.overview_highlight.css({left:a,width:e})}this.update_location(this.low,this.high);if(!h){for(var c=0,d=this.tracks.length;c<d;c++){if(this.tracks[c]&&this.tracks[c].enabled){this.tracks[c].draw()}}for(c=0,d=this.label_tracks.length;c<d;c++){this.label_tracks[c].draw()}}},zoom_in:function(b,c){if(this.max_high===0||this.high-this.low<this.min_separation){return}var d=this.high-this.low,e=d/2+this.low,a=(d/this.zoom_factor)/2;if(b){e=b/this.viewport_container.width()*(this.high-this.low)+this.low}this.low=Math.round(e-a);this.high=Math.round(e+a);this.redraw()},zoom_out:function(){if(this.max_high===0){return}var b=this.high-this.low,c=b/2+this.low,a=(b*this.zoom_factor)/2;this.low=Math.round(c-a);th
is.high=Math.round(c+a);this.redraw()},resize_window:function(){this.viewport_container.height(this.container.height()-this.nav_container.height()-45);this.nav_container.width(this.container.width());this.redraw()},reset_overview:function(){this.overview_viewport.find("canvas").remove();this.overview_viewport.height(this.default_overview_height);this.overview_box.height(this.default_overview_height);this.overview_close.hide();this.overview_highlight.hide()}});var Filter=function(b,a,c){this.name=b;this.index=a;this.value=c};var NumberFilter=function(b,a){this.name=b;this.index=a;this.low=-Number.MAX_VALUE;this.high=Number.MAX_VALUE;this.slider_min=Number.MAX_VALUE;this.slider_max=-Number.MAX_VALUE;this.slider=null;this.slider_label=null};$.extend(NumberFilter.prototype,{applies_to:function(a){if(a.length>this.index){return true}return false},keep:function(a){if(!this.applies_to(a)){return true}return(a[this.index]>=this.low&&a[this.index]<=this.high)},update_attrs:function(b
){var a=false;if(!this.applies_to(b)){return a}if(b[this.index]<this.slider_min){this.slider_min=b[this.index];a=true}if(b[this.index]>this.slider_max){this.slider_max=b[this.index];a=false}return a},update_ui_elt:function(){var b=this.slider.slider("option","min"),a=this.slider.slider("option","max");if(this.slider_min<b||this.slider_max>a){this.slider.slider("option","min",this.slider_min);this.slider.slider("option","max",this.slider_max);this.slider.slider("option","values",[this.slider_min,this.slider_max])}}});var get_filters=function(a){var g=[];for(var d=0;d<a.length;d++){var f=a[d];var c=f.name,e=f.type,b=f.index;if(e=="int"||e=="float"){g[d]=new NumberFilter(c,b)}else{g[d]=new Filter(c,b,e)}}return g};var Track=function(b,a,d,c){this.name=b;this.view=a;this.parent_element=d;this.filters=(c!==undefined?get_filters(c):[]);this.init_global()};$.extend(Track.prototype,{init_global:function(){this.container_div=$("<div />").addClass("track").css("position","relative");i
f(!this.hidden){this.header_div=$("<div class='track-header' />").appendTo(this.container_div);if(this.view.editor){this.drag_div=$("<div class='draghandle' />").appendTo(this.header_div)}this.name_div=$("<div class='menubutton popup' />").appendTo(this.header_div);this.name_div.text(this.name);this.name_div.attr("id",this.name.replace(/\s+/g,"-").replace(/[^a-zA-Z0-9\-]/g,"").toLowerCase())}this.filtering_div=$("<div class='track-filters'>").appendTo(this.container_div);this.filtering_div.hide();this.filtering_div.bind("drag",function(i){i.stopPropagation()});var b=$("<table class='filters'>").appendTo(this.filtering_div);var c=this;for(var e=0;e<this.filters.length;e++){var a=this.filters[e];var f=$("<tr>").appendTo(b);var g=$("<th class='filter-info'>").appendTo(f);var j=$("<span class='name'>").appendTo(g);j.text(a.name+" ");var d=$("<span class='values'>").appendTo(g);var h=$("<td>").appendTo(f);a.control_element=$("<div id='"+a.name+"-filter-control' style='width: 200
px; position: relative'>").appendTo(h);a.control_element.slider({range:true,min:Number.MAX_VALUE,max:-Number.MIN_VALUE,values:[0,0],slide:function(k,l){var i=l.values;d.text("["+i[0]+"-"+i[1]+"]");a.low=i[0];a.high=i[1];c.draw(true)},change:function(i,k){a.control_element.slider("option","slide").call(a.control_element,i,k)}});a.slider=a.control_element;a.slider_label=d}this.content_div=$("<div class='track-content'>").appendTo(this.container_div);this.parent_element.append(this.container_div)},init_each:function(c,b){var a=this;a.enabled=false;a.data_queue={};a.tile_cache.clear();a.data_cache.clear();a.initial_canvas=undefined;a.content_div.css("height","auto");if(!a.content_div.text()){a.content_div.text(DATA_LOADING)}a.container_div.removeClass("nodata error pending");if(a.view.chrom){$.getJSON(data_url,c,function(d){if(!d||d==="error"||d.kind==="error"){a.container_div.addClass("error");a.content_div.text(DATA_ERROR);if(d.message){var f=a.view.tracks.indexOf(a);var e=$("
<a href='javascript:void(0);'></a>").attr("id",f+"_error");e.text("Click to view error");$("#"+f+"_error").live("click",function(){show_modal("Trackster Error","<pre>"+d.message+"</pre>",{Close:hide_modal})});a.content_div.append(e)}}else{if(d==="no converter"){a.container_div.addClass("error");a.content_div.text(DATA_NOCONVERTER)}else{if(d.data!==undefined&&(d.data===null||d.data.length===0)){a.container_div.addClass("nodata");a.content_div.text(DATA_NONE)}else{if(d==="pending"){a.container_div.addClass("pending");a.content_div.text(DATA_PENDING);setTimeout(function(){a.init()},5000)}else{a.content_div.text("");a.content_div.css("height",a.height_px+"px");a.enabled=true;b(d);a.draw()}}}}})}else{a.container_div.addClass("nodata");a.content_div.text(DATA_NONE)}}});var TiledTrack=function(){var b=this,j=b.view;if(b.hidden){return}if(b.display_modes!==undefined){if(b.mode_div===undefined){b.mode_div=$("<div class='right-float menubutton popup' />").appendTo(b.header_div);var e=
b.display_modes[0];b.mode=e;b.mode_div.text(e);var c=function(i){b.mode_div.text(i);b.mode=i;b.tile_cache.clear();b.draw()};var a={};for(var f,h=b.display_modes.length;f<h;f++){var g=b.display_modes[f];a[g]=function(i){return function(){c(i)}}(g)}make_popupmenu(b.mode_div,a)}else{b.mode_div.hide()}}var d={};d["Set as overview"]=function(){j.overview_viewport.find("canvas").remove();b.is_overview=true;b.set_overview();for(var i in j.tracks){if(j.tracks[i]!==b){j.tracks[i].is_overview=false}}};d["Edit configuration"]=function(){var l=function(){hide_modal();$(window).unbind("keypress.check_enter_esc")},i=function(){b.update_options(b.track_id);hide_modal();$(window).unbind("keypress.check_enter_esc")},k=function(m){if((m.keyCode||m.which)===27){l()}else{if((m.keyCode||m.which)===13){i()}}};$(window).bind("keypress.check_enter_esc",k);show_modal("Configure Track",b.gen_options(b.track_id),{Cancel:l,OK:i})};if(b.filters.length>0){d["Show filters"]=function(){var i;if(!b.filterin
g_div.is(":visible")){i="Hide filters";b.filters_visible=true}else{i="Show filters";b.filters_visible=false}$("#"+b.name_div.attr("id")+"-menu").find("li").eq(2).text(i);b.filtering_div.toggle()}}d.Remove=function(){j.remove_track(b);if(j.num_tracks===0){$("#no-tracks").show()}};b.popup_menu=make_popupmenu(b.name_div,d);show_hide_popupmenu_options(b.popup_menu,"(Show|Hide) filters",false)};$.extend(TiledTrack.prototype,Track.prototype,{draw:function(a){var k=this.view.low,g=this.view.high,h=g-k,f=this.view.resolution;var n=$("<div style='position: relative;'></div>"),o=this.content_div.width()/h;this.content_div.append(n);this.max_height=0;var b=Math.floor(k/f/DENSITY);var j={};while((b*DENSITY*f)<g){var l=this.content_div.width()+"_"+o+"_"+b;var e=this.tile_cache.get(l);if(!a&&e){var i=b*DENSITY*f;var d=(i-k)*o;if(this.left_offset){d-=this.left_offset}e.css({left:d});this.show_tile(e,n)}else{this.delayed_draw(this,l,k,g,b,f,n,o,j)}b+=1}var c=this;var m=setInterval(function(
){if(obj_length(j)===0){if(c.content_div.children().length>1){c.content_div.children(":first").remove()}for(var p=0;p<c.filters.length;p++){c.filters[p].update_ui_elt()}clearInterval(m)}},50)},delayed_draw:function(c,h,g,e,b,d,i,j,f){var a=setTimeout(function(){if(g<=c.view.high&&e>=c.view.low){var k=c.draw_tile(d,b,i,j);if(k){if(!c.initial_canvas&&!window.G_vmlCanvasManager){c.initial_canvas=$(k).clone();var n=k.get(0).getContext("2d");var l=c.initial_canvas.get(0).getContext("2d");var m=n.getImageData(0,0,n.canvas.width,n.canvas.height);l.putImageData(m,0,0);c.set_overview()}c.tile_cache.set(h,k);c.show_tile(k,i)}}delete f[a]},50);f[a]=true},show_tile:function(a,c){var b=this;c.append(a);b.max_height=Math.max(b.max_height,a.height());b.content_div.css("height",b.max_height+"px");if(a.hasClass(FILTERABLE_CLASS)){show_hide_popupmenu_options(b.popup_menu,"(Show|Hide) filters");if(b.filters_visible){b.filtering_div.show()}}else{show_hide_popupmenu_options(b.popup_menu,"(Show|H
ide) filters",false);b.filtering_div.hide()}},set_overview:function(){var a=this.view;if(this.initial_canvas&&this.is_overview){a.overview_close.show();a.overview_viewport.append(this.initial_canvas);a.overview_highlight.show().height(this.initial_canvas.height());a.overview_viewport.height(this.initial_canvas.height()+a.overview_box.height())}$(window).trigger("resize")}});var LabelTrack=function(a,b){this.track_type="LabelTrack";this.hidden=true;Track.call(this,null,a,b);this.container_div.addClass("label-track")};$.extend(LabelTrack.prototype,Track.prototype,{draw:function(){var c=this.view,d=c.high-c.low,g=Math.floor(Math.pow(10,Math.floor(Math.log(d)/Math.log(10)))),a=Math.floor(c.low/g)*g,e=this.content_div.width(),b=$("<div style='position: relative; height: 1.3em;'></div>");while(a<c.high){var f=(a-c.low)/d*e;b.append($("<div class='label'>"+commatize(a)+"</div>").css({position:"absolute",left:f-1}));a+=g}this.content_div.children(":first").remove();this.content_div.
append(b)}});var ReferenceTrack=function(a){this.track_type="ReferenceTrack";this.hidden=true;Track.call(this,null,a,a.top_labeltrack);TiledTrack.call(this);this.left_offset=200;this.height_px=12;this.container_div.addClass("reference-track");this.data_queue={};this.data_cache=new Cache(CACHED_DATA);this.tile_cache=new Cache(CACHED_TILES_LINE)};$.extend(ReferenceTrack.prototype,TiledTrack.prototype,{get_data:function(d,b){var c=this,a=b*DENSITY*d,f=(b+1)*DENSITY*d,e=d+"_"+b;if(!c.data_queue[e]){c.data_queue[e]=true;$.ajax({url:reference_url,dataType:"json",data:{chrom:this.view.chrom,low:a,high:f,dbkey:this.view.dbkey},success:function(g){c.data_cache.set(e,g);delete c.data_queue[e];c.draw()},error:function(h,g,i){console.log(h,g,i)}})}},draw_tile:function(f,b,k,o){var g=b*DENSITY*f,d=DENSITY*f,j=f+"_"+b;var e=document.createElement("canvas");if(window.G_vmlCanvasManager){G_vmlCanvasManager.initElement(e)}e=$(e);var n=e.get(0).getContext("2d");if(o>PX_PER_CHAR){if(this.data_
cache.get(j)===undefined){this.get_data(f,b);return}var m=this.data_cache.get(j);if(m===null){this.content_div.css("height","0px");return}e.get(0).width=Math.ceil(d*o+this.left_offset);e.get(0).height=this.height_px;e.css({position:"absolute",top:0,left:(g-this.view.low)*o-this.left_offset});for(var h=0,l=m.length;h<l;h++){var a=Math.round(h*o),i=Math.round(o/2);n.fillText(m[h],a+this.left_offset+i,10)}k.append(e);return e}this.content_div.css("height","0px")}});var LineTrack=function(d,b,a,c){this.track_type="LineTrack";this.display_modes=["Histogram","Line","Filled","Intensity"];this.mode="Histogram";Track.call(this,d,b,b.viewport_container);TiledTrack.call(this);this.height_px=80;this.dataset_id=a;this.data_cache=new Cache(CACHED_DATA);this.tile_cache=new Cache(CACHED_TILES_LINE);this.prefs={color:"black",min_value:undefined,max_value:undefined,mode:this.mode}};$.extend(LineTrack.prototype,TiledTrack.prototype,{init:function(){var a=this,b=a.view.tracks.indexOf(a);a.verti
cal_range=undefined;this.init_each({stats:true,chrom:a.view.chrom,low:null,high:null,dataset_id:a.dataset_id},function(c){a.container_div.addClass("line-track");var e=c.data;if(isNaN(parseFloat(a.prefs.min_value))||isNaN(parseFloat(a.prefs.max_value))){a.prefs.min_value=e.min;a.prefs.max_value=e.max;$("#track_"+b+"_minval").val(a.prefs.min_value);$("#track_"+b+"_maxval").val(a.prefs.max_value)}a.vertical_range=a.prefs.max_value-a.prefs.min_value;a.total_frequency=e.total_frequency;a.container_div.find(".yaxislabel").remove();var f=$("<div />").addClass("yaxislabel").attr("id","linetrack_"+b+"_minval").text(round_1000(a.prefs.min_value));var d=$("<div />").addClass("yaxislabel").attr("id","linetrack_"+b+"_maxval").text(round_1000(a.prefs.max_value));d.css({position:"absolute",top:"22px",left:"10px"});d.prependTo(a.container_div);f.css({position:"absolute",top:a.height_px+11+"px",left:"10px"});f.prependTo(a.container_div)})},get_data:function(d,b){var c=this,a=b*DENSITY*d,f=(b
+1)*DENSITY*d,e=d+"_"+b;if(!c.data_queue[e]){c.data_queue[e]=true;$.ajax({url:data_url,dataType:"json",data:{chrom:this.view.chrom,low:a,high:f,dataset_id:this.dataset_id,resolution:this.view.resolution},success:function(g){var h=g.data;c.data_cache.set(e,h);delete c.data_queue[e];c.draw()},error:function(h,g,i){console.log(h,g,i)}})}},draw_tile:function(o,r,c,e){if(this.vertical_range===undefined){return}var s=r*DENSITY*o,a=DENSITY*o,w=o+"_"+r;var b=document.createElement("canvas");if(window.G_vmlCanvasManager){G_vmlCanvasManager.initElement(b)}b=$(b);if(this.data_cache.get(w)===undefined){this.get_data(o,r);return}var v=this.data_cache.get(w);if(!v){return}b.css({position:"absolute",top:0,left:(s-this.view.low)*e});b.get(0).width=Math.ceil(a*e);b.get(0).height=this.height_px;var n=b.get(0).getContext("2d"),j=false,k=this.prefs.min_value,g=this.prefs.max_value,m=this.vertical_range,t=this.total_frequency,d=this.height_px,l=this.mode;n.beginPath();n.fillStyle=this.prefs.colo
r;var u,h,f;if(v.length>1){f=Math.ceil((v[1][0]-v[0][0])*e)}else{f=10}for(var p=0,q=v.length;p<q;p++){u=Math.round((v[p][0]-s)*e);h=v[p][1];if(h===null){if(j&&l==="Filled"){n.lineTo(u,d)}j=false;continue}if(h<k){h=k}else{if(h>g){h=g}}if(l==="Histogram"){h=Math.round(d-(h-k)/m*d);n.fillRect(u,h,f,d-h)}else{if(l==="Intensity"){h=255-Math.floor((h-k)/m*255);n.fillStyle="rgb("+h+","+h+","+h+")";n.fillRect(u,0,f,d)}else{h=Math.round(d-(h-k)/m*d);if(j){n.lineTo(u,h)}else{j=true;if(l==="Filled"){n.moveTo(u,d);n.lineTo(u,h)}else{n.moveTo(u,h)}}}}}if(l==="Filled"){if(j){n.lineTo(u,d)}n.fill()}else{n.stroke()}c.append(b);return b},gen_options:function(m){var a=$("<div />").addClass("form-row");var e="track_"+m+"_color",b=$("<label />").attr("for",e).text("Color:"),c=$("<input />").attr("id",e).attr("name",e).val(this.prefs.color),h="track_"+m+"_minval",l=$("<label></label>").attr("for",h).text("Min value:"),d=(this.prefs.min_value===undefined?"":this.prefs.min_value),k=$("<input></inp
ut>").attr("id",h).val(d),j="track_"+m+"_maxval",g=$("<label></label>").attr("for",j).text("Max value:"),i=(this.prefs.max_value===undefined?"":this.prefs.max_value),f=$("<input></input>").attr("id",j).val(i);return a.append(l).append(k).append(g).append(f).append(b).append(c)},update_options:function(d){var a=$("#track_"+d+"_minval").val(),c=$("#track_"+d+"_maxval").val(),b=$("#track_"+d+"_color").val();if(a!==this.prefs.min_value||c!==this.prefs.max_value||b!==this.prefs.color){this.prefs.min_value=parseFloat(a);this.prefs.max_value=parseFloat(c);this.prefs.color=b;this.vertical_range=this.prefs.max_value-this.prefs.min_value;$("#linetrack_"+d+"_minval").text(this.prefs.min_value);$("#linetrack_"+d+"_maxval").text(this.prefs.max_value);this.tile_cache.clear();this.draw()}}});var FeatureTrack=function(d,b,a,e,c){this.track_type="FeatureTrack";this.display_modes=["Auto","Dense","Squish","Pack"];Track.call(this,d,b,b.viewport_container,e);TiledTrack.call(this);this.height_px=
0;this.container_div.addClass("feature-track");this.dataset_id=a;this.zo_slots={};this.show_labels_scale=0.001;this.showing_details=false;this.vertical_detail_px=10;this.vertical_nodetail_px=2;this.summary_draw_height=30;this.default_font="9px Monaco, Lucida Console, monospace";this.inc_slots={};this.data_queue={};this.s_e_by_tile={};this.tile_cache=new Cache(CACHED_TILES_FEATURE);this.data_cache=new Cache(20);this.left_offset=200;this.prefs={block_color:"#444",label_color:"black",show_counts:true}};$.extend(FeatureTrack.prototype,TiledTrack.prototype,{init:function(){var a=this,b="initial";this.init_each({low:a.view.max_low,high:a.view.max_high,dataset_id:a.dataset_id,chrom:a.view.chrom,resolution:this.view.resolution,mode:a.mode},function(c){a.mode_div.show();a.data_cache.set(b,c);a.draw()})},get_data:function(a,d){var b=this,c=a+"_"+d;if(!b.data_queue[c]){b.data_queue[c]=true;$.getJSON(data_url,{chrom:b.view.chrom,low:a,high:d,dataset_id:b.dataset_id,resolution:this.view.
resolution,mode:this.mode},function(e){b.data_cache.set(c,e);delete b.data_queue[c];b.draw()})}},incremental_slots:function(a,g,b,q){if(!this.inc_slots[a]){this.inc_slots[a]={};this.inc_slots[a].w_scale=a;this.inc_slots[a].mode=q;this.s_e_by_tile[a]={}}var m=this.inc_slots[a].w_scale,y=[],h=0,n=this.view.max_low;var A=[];if(this.inc_slots[a].mode!==q){delete this.inc_slots[a];this.inc_slots[a]={mode:q,w_scale:m};delete this.s_e_by_tile[a];this.s_e_by_tile[a]={}}for(var v=0,w=g.length;v<w;v++){var f=g[v],l=f[0];if(this.inc_slots[a][l]!==undefined){h=Math.max(h,this.inc_slots[a][l]);A.push(this.inc_slots[a][l])}else{y.push(v)}}for(var v=0,w=y.length;v<w;v++){var f=g[y[v]],l=f[0],r=f[1],c=f[2],p=f[3],d=Math.floor((r-n)*m),e=Math.ceil((c-n)*m);if(p!==undefined&&!b){var s=CONTEXT.measureText(p).width;if(d-s<0){e+=s}else{d-=s}}var u=0;while(u<=MAX_FEATURE_DEPTH){var o=true;if(this.s_e_by_tile[a][u]!==undefined){for(var t=0,z=this.s_e_by_tile[a][u].length;t<z;t++){var x=this.s_e_by
_tile[a][u][t];if(e>x[0]&&d<x[1]){o=false;break}}}if(o){if(this.s_e_by_tile[a][u]===undefined){this.s_e_by_tile[a][u]=[]}this.s_e_by_tile[a][u].push([d,e]);this.inc_slots[a][l]=u;h=Math.max(h,u);break}u++}}return h},rect_or_text:function(r,l,t,b,q,f,i,e){r.textAlign="center";var k=0,p=Math.round(l/2);for(var m=0,s=i.length;m<s;m++){var j=i[m],d="MIDNSHP"[j[0]],n=j[1];if(d==="H"||d==="S"){k-=n}var g=q+k,w=Math.floor(Math.max(0,(g-t)*l)),h=Math.floor(Math.max(0,(g+n-t)*l));switch(d){case"S":case"H":case"M":var o=f.slice(k,n);if((this.mode==="Pack"||this.mode==="Auto")&&f!==undefined&&l>PX_PER_CHAR){r.fillStyle=this.prefs.block_color;r.fillRect(w+this.left_offset,e+1,h-w,9);r.fillStyle=CONNECTOR_COLOR;for(var u=0,a=o.length;u<a;u++){if(g+u>=t&&g+u<=b){var v=Math.floor(Math.max(0,(g+u-t)*l));r.fillText(o[u],v+this.left_offset+p,e+9)}}}else{r.fillStyle=this.prefs.block_color;r.fillRect(w+this.left_offset,e+4,h-w,3)}break;case"N":r.fillStyle=CONNECTOR_COLOR;r.fillRect(w+this.left_
offset,e+5,h-w,1);break;case"D":r.fillStyle="red";r.fillRect(w+this.left_offset,e+4,h-w,3);break;case"P":case"I":break}k+=n}},draw_tile:function(ag,o,s,av){var N=o*DENSITY*ag,al=(o+1)*DENSITY*ag,M=al-N;var an=(!this.initial_canvas?"initial":N+"_"+al);var I=this.data_cache.get(an);var e;if(I===undefined||(this.mode!=="Auto"&&I.dataset_type==="summary_tree")){this.data_queue[[N,al]]=true;this.get_data(N,al);return}var a=Math.ceil(M*av),ai=this.prefs.label_color,l=this.prefs.block_color,r=this.mode,z=25,ae=(r==="Squish")||(r==="Dense")&&(r!=="Pack")||(r==="Auto"&&(I.extra_info==="no_detail")),W=this.left_offset,au,D,aw;var q=document.createElement("canvas");if(window.G_vmlCanvasManager){G_vmlCanvasManager.initElement(q)}q=$(q);if(I.dataset_type==="summary_tree"){D=this.summary_draw_height}else{if(r==="Dense"){D=z;aw=10}else{aw=(ae?this.vertical_nodetail_px:this.vertical_detail_px);var A=(av<0.0001?1/this.view.zoom_res:av);D=this.incremental_slots(A,I.data,ae,r)*aw+z;au=this.inc
_slots[A]}}q.css({position:"absolute",top:0,left:(N-this.view.low)*av-W});q.get(0).width=a+W;q.get(0).height=D;s.parent().css("height",Math.max(this.height_px,D)+"px");var J=q.get(0).getContext("2d");J.fillStyle=l;J.font=this.default_font;J.textAlign="right";this.container_div.find(".yaxislabel").remove();if(I.dataset_type=="summary_tree"){var Y=I.data,L=I.max,b=Math.ceil(I.delta*av);var p=$("<div />").addClass("yaxislabel").text(L);p.css({position:"absolute",top:"22px",left:"10px"});p.prependTo(this.container_div);for(var ap=0,H=Y.length;ap<H;ap++){var aa=Math.floor((Y[ap][0]-N)*av);var Z=Y[ap][1];if(!Z){continue}var am=Z/L*this.summary_draw_height;J.fillStyle="black";J.fillRect(aa+W,this.summary_draw_height-am,b,am);if(this.prefs.show_counts&&J.measureText(Z).width<b){J.fillStyle="#bbb";J.textAlign="center";J.fillText(Z,aa+W+(b/2),this.summary_draw_height-5)}}e="Summary";s.append(q);return q}if(I.message){q.css({border:"solid red","border-width":"2px 2px 2px 0px"});J.fillS
tyle="red";J.textAlign="left";J.fillText(I.message,100+W,aw)}var ad=false;if(I.data){ad=true;for(var ar=0;ar<this.filters.length;ar++){if(!this.filters[ar].applies_to(I.data[0])){ad=false}}}if(ad){q.addClass(FILTERABLE_CLASS)}var at=I.data;var ao=0;for(var ap=0,H=at.length;ap<H;ap++){var S=at[ap],R=S[0],aq=S[1],ac=S[2],O=S[3];if(au[R]===undefined){continue}var ab=false;var U;for(var ar=0;ar<this.filters.length;ar++){U=this.filters[ar];U.update_attrs(S);if(!U.keep(S)){ab=true;break}}if(ab){continue}if(aq<=al&&ac>=N){var af=Math.floor(Math.max(0,(aq-N)*av)),K=Math.ceil(Math.min(a,Math.max(0,(ac-N)*av))),X=(r==="Dense"?1:(1+au[R]))*aw;var G,aj,P=null,ax=null;if(I.dataset_type==="bai"){var v=S[4];J.fillStyle=l;if(S[5] instanceof Array){var E=Math.floor(Math.max(0,(S[5][0]-N)*av)),Q=Math.ceil(Math.min(a,Math.max(0,(S[5][1]-N)*av))),C=Math.floor(Math.max(0,(S[6][0]-N)*av)),w=Math.ceil(Math.min(a,Math.max(0,(S[6][1]-N)*av)));if(S[5][1]>=N&&S[5][0]<=al){this.rect_or_text(J,av,N,al,S
[5][0],S[5][2],v,X)}if(S[6][1]>=N&&S[6][0]<=al){this.rect_or_text(J,av,N,al,S[6][0],S[6][2],v,X)}if(C>Q){J.fillStyle=CONNECTOR_COLOR;J.fillRect(Q+W,X+5,C-Q,1)}}else{J.fillStyle=l;this.rect_or_text(J,av,N,al,aq,O,v,X)}if(r!=="Dense"&&!ae&&aq>N){J.fillStyle=this.prefs.label_color;if(o===0&&af-J.measureText(O).width<0){J.textAlign="left";J.fillText(R,K+2+W,X+8)}else{J.textAlign="right";J.fillText(R,af-2+W,X+8)}J.fillStyle=l}}else{if(I.dataset_type==="interval_index"){if(ae){J.fillStyle=l;J.fillRect(af+W,X+5,K-af,1)}else{var F=S[4],V=S[5],ah=S[6],h=S[7];if(V&&ah){P=Math.floor(Math.max(0,(V-N)*av));ax=Math.ceil(Math.min(a,Math.max(0,(ah-N)*av)))}if(r!=="Dense"&&O!==undefined&&aq>N){J.fillStyle=ai;if(o===0&&af-J.measureText(O).width<0){J.textAlign="left";J.fillText(O,K+2+W,X+8)}else{J.textAlign="right";J.fillText(O,af-2+W,X+8)}J.fillStyle=l}if(h){if(F){if(F=="+"){J.fillStyle=RIGHT_STRAND}else{if(F=="-"){J.fillStyle=LEFT_STRAND}}J.fillRect(af+W,X,K-af,10);J.fillStyle=l}for(var an=0
,g=h.length;an<g;an++){var u=h[an],d=Math.floor(Math.max(0,(u[0]-N)*av)),T=Math.ceil(Math.min(a,Math.max((u[1]-N)*av)));if(d>T){continue}G=5;aj=3;J.fillRect(d+W,X+aj,T-d,G);if(P!==undefined&&!(d>ax||T<P)){G=9;aj=1;var ak=Math.max(d,P),B=Math.min(T,ax);J.fillRect(ak+W,X+aj,B-ak,G)}}}else{G=9;aj=1;J.fillRect(af+W,X+aj,K-af,G);if(S.strand){if(S.strand=="+"){J.fillStyle=RIGHT_STRAND_INV}else{if(S.strand=="-"){J.fillStyle=LEFT_STRAND_INV}}J.fillRect(af+W,X,K-af,10);J.fillStyle=l}}}}else{if(I.dataset_type==="vcf"){if(ae){J.fillStyle=l;J.fillRect(af+W,X+5,K-af,1)}else{var t=S[4],n=S[5],c=S[6];G=9;aj=1;J.fillRect(af+W,X,K-af,G);if(r!=="Dense"&&O!==undefined&&aq>N){J.fillStyle=ai;if(o===0&&af-J.measureText(O).width<0){J.textAlign="left";J.fillText(O,K+2+W,X+8)}else{J.textAlign="right";J.fillText(O,af-2+W,X+8)}J.fillStyle=l}var m=t+" / "+n;if(aq>N&&J.measureText(m).width<(K-af)){J.fillStyle="white";J.textAlign="center";J.fillText(m,W+af+(K-af)/2,X+8);J.fillStyle=l}}}}}ao++}}return q},
gen_options:function(i){var a=$("<div />").addClass("form-row");var e="track_"+i+"_block_color",k=$("<label />").attr("for",e).text("Block color:"),l=$("<input />").attr("id",e).attr("name",e).val(this.prefs.block_color),j="track_"+i+"_label_color",g=$("<label />").attr("for",j).text("Text color:"),h=$("<input />").attr("id",j).attr("name",j).val(this.prefs.label_color),f="track_"+i+"_show_count",c=$("<label />").attr("for",f).text("Show summary counts"),b=$('<input type="checkbox" style="float:left;"></input>').attr("id",f).attr("name",f).attr("checked",this.prefs.show_counts),d=$("<div />").append(b).append(c);return a.append(k).append(l).append(g).append(h).append(d)},update_options:function(d){var b=$("#track_"+d+"_block_color").val(),c=$("#track_"+d+"_label_color").val(),a=$("#track_"+d+"_show_count").attr("checked");if(b!==this.prefs.block_color||c!==this.prefs.label_color||a!==this.prefs.show_counts){this.prefs.block_color=b;this.prefs.label_color=c;this.prefs.show_co
unts=a;this.tile_cache.clear();this.draw()}}});var ReadTrack=function(d,b,a,e,c){FeatureTrack.call(this,d,b,a,e,c);this.track_type="ReadTrack";this.vertical_detail_px=10;this.vertical_nodetail_px=5};$.extend(ReadTrack.prototype,TiledTrack.prototype,FeatureTrack.prototype,{});
+var DENSITY=200,FEATURE_LEVELS=10,MAX_FEATURE_DEPTH=50,CONNECTOR_COLOR="#ccc",DATA_ERROR="There was an error in indexing this dataset.",DATA_NOCONVERTER="A converter for this dataset is not installed. Please check your datatypes_conf.xml file.",DATA_NONE="No data for this chrom/contig.",DATA_PENDING="Currently indexing... please wait",DATA_LOADING="Loading data...",FILTERABLE_CLASS="filterable",CACHED_TILES_FEATURE=10,CACHED_TILES_LINE=5,CACHED_DATA=5,DUMMY_CANVAS=document.createElement("canvas"),RIGHT_STRAND,LEFT_STRAND;if(window.G_vmlCanvasManager){G_vmlCanvasManager.initElement(DUMMY_CANVAS)}CONTEXT=DUMMY_CANVAS.getContext("2d");PX_PER_CHAR=CONTEXT.measureText("A").width;var right_img=new Image();right_img.src=image_path+"/visualization/strand_right.png";right_img.onload=function(){RIGHT_STRAND=CONTEXT.createPattern(right_img,"repeat")};var left_img=new Image();left_img.src=image_path+"/visualization/strand_left.png";left_img.onload=function(){LEFT_STRAND=CONTEXT.createPa
ttern(left_img,"repeat")};var right_img_inv=new Image();right_img_inv.src=image_path+"/visualization/strand_right_inv.png";right_img_inv.onload=function(){RIGHT_STRAND_INV=CONTEXT.createPattern(right_img_inv,"repeat")};var left_img_inv=new Image();left_img_inv.src=image_path+"/visualization/strand_left_inv.png";left_img_inv.onload=function(){LEFT_STRAND_INV=CONTEXT.createPattern(left_img_inv,"repeat")};function round_1000(a){return Math.round(a*1000)/1000}var Cache=function(a){this.num_elements=a;this.clear()};$.extend(Cache.prototype,{get:function(b){var a=this.key_ary.indexOf(b);if(a!=-1){this.key_ary.splice(a,1);this.key_ary.push(b)}return this.obj_cache[b]},set:function(b,c){if(!this.obj_cache[b]){if(this.key_ary.length>=this.num_elements){var a=this.key_ary.shift();delete this.obj_cache[a]}this.key_ary.push(b)}this.obj_cache[b]=c;return c},clear:function(){this.obj_cache={};this.key_ary=[]}});var View=function(a,d,c,b){this.container=a;this.vis_id=c;this.dbkey=b;this.ti
tle=d;this.tracks=[];this.label_tracks=[];this.max_low=0;this.max_high=0;this.num_tracks=0;this.track_id_counter=0;this.zoom_factor=3;this.min_separation=30;this.has_changes=false;this.init();this.reset()};$.extend(View.prototype,{init:function(){var c=this.container,a=this;this.top_labeltrack=$("<div/>").addClass("top-labeltrack").appendTo(c);this.content_div=$("<div/>").addClass("content").css("position","relative").appendTo(c);this.viewport_container=$("<div/>").addClass("viewport-container").addClass("viewport-container").appendTo(this.content_div);this.intro_div=$("<div/>").addClass("intro").text("Select a chrom from the dropdown below").hide();this.nav_container=$("<div/>").addClass("nav-container").appendTo(c);this.nav_labeltrack=$("<div/>").addClass("nav-labeltrack").appendTo(this.nav_container);this.nav=$("<div/>").addClass("nav").appendTo(this.nav_container);this.overview=$("<div/>").addClass("overview").appendTo(this.nav);this.overview_viewport=$("<div/>").addClas
s("overview-viewport").appendTo(this.overview);this.overview_close=$("<a href='javascript:void(0);'>Close Overview</a>").addClass("overview-close").hide().appendTo(this.overview_viewport);this.overview_highlight=$("<div />").addClass("overview-highlight").hide().appendTo(this.overview_viewport);this.overview_box_background=$("<div/>").addClass("overview-boxback").appendTo(this.overview_viewport);this.overview_box=$("<div/>").addClass("overview-box").appendTo(this.overview_viewport);this.default_overview_height=this.overview_box.height();this.nav_controls=$("<div/>").addClass("nav-controls").appendTo(this.nav);this.chrom_form=$("<form/>").attr("action",function(){}).appendTo(this.nav_controls);this.chrom_select=$("<select/>").attr({name:"chrom"}).css("width","15em").addClass("no-autocomplete").append("<option value=''>Loading</option>").appendTo(this.chrom_form);var b=function(d){if(d.type==="focusout"||(d.keyCode||d.which)===13||(d.keyCode||d.which)===27){if((d.keyCode||d.wh
ich)!==27){a.go_to($(this).val())}$(this).hide();a.location_span.show();a.chrom_select.show();return false}};this.nav_input=$("<input/>").addClass("nav-input").hide().bind("keypress focusout",b).appendTo(this.chrom_form);this.location_span=$("<span/>").addClass("location").appendTo(this.chrom_form);this.location_span.bind("click",function(){a.location_span.hide();a.chrom_select.hide();a.nav_input.css("display","inline-block");a.nav_input.select();a.nav_input.focus()});if(this.vis_id!==undefined){this.hidden_input=$("<input/>").attr("type","hidden").val(this.vis_id).appendTo(this.chrom_form)}this.zo_link=$("<a/>").click(function(){a.zoom_out();a.redraw()}).html('<img src="'+image_path+'/fugue/magnifier-zoom-out.png" />').appendTo(this.chrom_form);this.zi_link=$("<a/>").click(function(){a.zoom_in();a.redraw()}).html('<img src="'+image_path+'/fugue/magnifier-zoom.png" />').appendTo(this.chrom_form);$.ajax({url:chrom_url,data:(this.vis_id!==undefined?{vis_id:this.vis_id}:{dbkey:
this.dbkey}),dataType:"json",success:function(e){if(e.reference){a.add_label_track(new ReferenceTrack(a))}a.chrom_data=e.chrom_info;var h='<option value="">Select Chrom/Contig</option>';for(var g=0,d=a.chrom_data.length;g<d;g++){var f=a.chrom_data[g].chrom;h+='<option value="'+f+'">'+f+"</option>"}a.chrom_select.html(h);a.intro_div.show();a.chrom_select.bind("change",function(){a.change_chrom(a.chrom_select.val())})},error:function(){alert("Could not load chroms for this dbkey:",a.dbkey)}});this.content_div.bind("dblclick",function(d){a.zoom_in(d.pageX,this.viewport_container)});this.overview_box.bind("dragstart",function(d){this.current_x=d.offsetX}).bind("drag",function(d){var g=d.offsetX-this.current_x;this.current_x=d.offsetX;var f=Math.round(g/a.viewport_container.width()*(a.max_high-a.max_low));a.move_delta(-f)});this.overview_close.bind("click",function(){for(var e=0,d=a.tracks.length;e<d;e++){a.tracks[e].is_overview=false}$(this).siblings().filter("canvas").remove();
$(this).parent().css("height",a.overview_box.height());a.overview_highlight.hide();$(this).hide()});this.viewport_container.bind("dragstart",function(d){this.original_low=a.low;this.current_height=d.clientY;this.current_x=d.offsetX;this.enable_pan=(d.clientX<a.viewport_container.width()-16)?true:false}).bind("drag",function(g){if(!this.enable_pan||this.in_reordering){return}var d=$(this);var i=g.offsetX-this.current_x;var f=d.scrollTop()-(g.clientY-this.current_height);d.scrollTop(f);this.current_height=g.clientY;this.current_x=g.offsetX;var h=Math.round(i/a.viewport_container.width()*(a.high-a.low));a.move_delta(h)});this.top_labeltrack.bind("dragstart",function(d){this.drag_origin_x=d.clientX;this.drag_origin_pos=d.clientX/a.viewport_container.width()*(a.high-a.low)+a.low;this.drag_div=$("<div />").css({height:a.content_div.height()+30,top:"0px",position:"absolute","background-color":"#cfc",border:"1px solid #6a6",opacity:0.5,"z-index":1000}).appendTo($(this))}).bind("drag
",function(i){var f=Math.min(i.clientX,this.drag_origin_x)-a.container.offset().left,d=Math.max(i.clientX,this.drag_origin_x)-a.container.offset().left,h=(a.high-a.low),g=a.viewport_container.width();a.update_location(Math.round(f/g*h)+a.low,Math.round(d/g*h)+a.low);this.drag_div.css({left:f+"px",width:(d-f)+"px"})}).bind("dragend",function(j){var f=Math.min(j.clientX,this.drag_origin_x),d=Math.max(j.clientX,this.drag_origin_x),h=(a.high-a.low),g=a.viewport_container.width(),i=a.low;a.low=Math.round(f/g*h)+i;a.high=Math.round(d/g*h)+i;this.drag_div.remove();a.redraw()});this.add_label_track(new LabelTrack(this,this.top_labeltrack));this.add_label_track(new LabelTrack(this,this.nav_labeltrack));$(window).bind("resize",function(){a.resize_window()});$(document).bind("redraw",function(){a.redraw()});this.reset();$(window).trigger("resize")},update_location:function(a,b){this.location_span.text(commatize(a)+" - "+commatize(b));this.nav_input.val(this.chrom+":"+commatize(a)+"-"+c
ommatize(b))},change_chrom:function(e,b,g){var d=this;var f=$.grep(d.chrom_data,function(j,k){return j.chrom===e})[0];if(f===undefined){return}if(e!==d.chrom){d.chrom=e;if(!d.chrom){d.intro_div.show()}else{d.intro_div.hide()}d.chrom_select.val(d.chrom);d.max_high=f.len;d.reset();d.redraw(true);for(var h=0,a=d.tracks.length;h<a;h++){var c=d.tracks[h];if(c.init){c.init()}}}if(b!==undefined&&g!==undefined){d.low=Math.max(b,0);d.high=Math.min(g,d.max_high)}d.reset_overview();d.redraw()},go_to:function(f){var j=this,a,d,b=f.split(":"),h=b[0],i=b[1];if(i!==undefined){try{var g=i.split("-");a=parseInt(g[0].replace(/,/g,""),10);d=parseInt(g[1].replace(/,/g,""),10)}catch(c){return false}}j.change_chrom(h,a,d)},move_delta:function(c){var a=this;var b=a.high-a.low;if(a.low-c<a.max_low){a.low=a.max_low;a.high=a.max_low+b}else{if(a.high-c>a.max_high){a.high=a.max_high;a.low=a.max_high-b}else{a.high-=c;a.low-=c}}a.redraw()},add_track:function(a){a.view=this;a.track_id=this.track_id_counte
r;this.tracks.push(a);if(a.init){a.init()}a.container_div.attr("id","track_"+a.track_id);this.track_id_counter+=1;this.num_tracks+=1},add_label_track:function(a){a.view=this;this.label_tracks.push(a)},remove_track:function(a){this.has_changes=true;a.container_div.fadeOut("slow",function(){$(this).remove()});delete this.tracks[this.tracks.indexOf(a)];this.num_tracks-=1},reset:function(){this.low=this.max_low;this.high=this.max_high;this.viewport_container.find(".yaxislabel").remove()},redraw:function(h){var g=this.high-this.low,f=this.low,b=this.high;if(f<this.max_low){f=this.max_low}if(b>this.max_high){b=this.max_high}if(this.high!==0&&g<this.min_separation){b=f+this.min_separation}this.low=Math.floor(f);this.high=Math.ceil(b);this.resolution=Math.pow(10,Math.ceil(Math.log((this.high-this.low)/200)/Math.LN10));this.zoom_res=Math.pow(FEATURE_LEVELS,Math.max(0,Math.ceil(Math.log(this.resolution,FEATURE_LEVELS)/Math.log(FEATURE_LEVELS))));var a=(this.low/(this.max_high-this.max
_low)*this.overview_viewport.width())||0;var e=((this.high-this.low)/(this.max_high-this.max_low)*this.overview_viewport.width())||0;var j=13;this.overview_box.css({left:a,width:Math.max(j,e)}).show();if(e<j){this.overview_box.css("left",a-(j-e)/2)}if(this.overview_highlight){this.overview_highlight.css({left:a,width:e})}this.update_location(this.low,this.high);if(!h){for(var c=0,d=this.tracks.length;c<d;c++){if(this.tracks[c]&&this.tracks[c].enabled){this.tracks[c].draw()}}for(c=0,d=this.label_tracks.length;c<d;c++){this.label_tracks[c].draw()}}},zoom_in:function(b,c){if(this.max_high===0||this.high-this.low<this.min_separation){return}var d=this.high-this.low,e=d/2+this.low,a=(d/this.zoom_factor)/2;if(b){e=b/this.viewport_container.width()*(this.high-this.low)+this.low}this.low=Math.round(e-a);this.high=Math.round(e+a);this.redraw()},zoom_out:function(){if(this.max_high===0){return}var b=this.high-this.low,c=b/2+this.low,a=(b*this.zoom_factor)/2;this.low=Math.round(c-a);th
is.high=Math.round(c+a);this.redraw()},resize_window:function(){this.viewport_container.height(this.container.height()-this.nav_container.height()-45);this.nav_container.width(this.container.width());this.redraw()},reset_overview:function(){this.overview_viewport.find("canvas").remove();this.overview_viewport.height(this.default_overview_height);this.overview_box.height(this.default_overview_height);this.overview_close.hide();this.overview_highlight.hide()}});var Filter=function(b,a,c){this.name=b;this.index=a;this.value=c};var NumberFilter=function(b,a){this.name=b;this.index=a;this.low=-Number.MAX_VALUE;this.high=Number.MAX_VALUE;this.slider_min=Number.MAX_VALUE;this.slider_max=-Number.MAX_VALUE;this.slider=null;this.slider_label=null};$.extend(NumberFilter.prototype,{applies_to:function(a){if(a.length>this.index){return true}return false},keep:function(a){if(!this.applies_to(a)){return true}return(a[this.index]>=this.low&&a[this.index]<=this.high)},update_attrs:function(b
){var a=false;if(!this.applies_to(b)){return a}if(b[this.index]<this.slider_min){this.slider_min=b[this.index];a=true}if(b[this.index]>this.slider_max){this.slider_max=b[this.index];a=false}return a},update_ui_elt:function(){var b=this.slider.slider("option","min"),a=this.slider.slider("option","max");if(this.slider_min<b||this.slider_max>a){this.slider.slider("option","min",this.slider_min);this.slider.slider("option","max",this.slider_max);this.slider.slider("option","values",[this.slider_min,this.slider_max])}}});var get_filters=function(a){var g=[];for(var d=0;d<a.length;d++){var f=a[d];var c=f.name,e=f.type,b=f.index;if(e=="int"||e=="float"){g[d]=new NumberFilter(c,b)}else{g[d]=new Filter(c,b,e)}}return g};var Track=function(b,a,d,c){this.name=b;this.view=a;this.parent_element=d;this.filters=(c!==undefined?get_filters(c):[]);this.init_global()};$.extend(Track.prototype,{init_global:function(){this.container_div=$("<div />").addClass("track").css("position","relative");i
f(!this.hidden){this.header_div=$("<div class='track-header' />").appendTo(this.container_div);if(this.view.editor){this.drag_div=$("<div class='draghandle' />").appendTo(this.header_div)}this.name_div=$("<div class='menubutton popup' />").appendTo(this.header_div);this.name_div.text(this.name);this.name_div.attr("id",this.name.replace(/\s+/g,"-").replace(/[^a-zA-Z0-9\-]/g,"").toLowerCase())}this.filtering_div=$("<div class='track-filters'>").appendTo(this.container_div);this.filtering_div.hide();this.filtering_div.bind("drag",function(i){i.stopPropagation()});var b=$("<table class='filters'>").appendTo(this.filtering_div);var c=this;for(var e=0;e<this.filters.length;e++){var a=this.filters[e];var f=$("<tr>").appendTo(b);var g=$("<th class='filter-info'>").appendTo(f);var j=$("<span class='name'>").appendTo(g);j.text(a.name+" ");var d=$("<span class='values'>").appendTo(g);var h=$("<td>").appendTo(f);a.control_element=$("<div id='"+a.name+"-filter-control' style='width: 200
px; position: relative'>").appendTo(h);a.control_element.slider({range:true,min:Number.MAX_VALUE,max:-Number.MIN_VALUE,values:[0,0],slide:function(k,l){var i=l.values;d.text("["+i[0]+"-"+i[1]+"]");a.low=i[0];a.high=i[1];c.draw(true)},change:function(i,k){a.control_element.slider("option","slide").call(a.control_element,i,k)}});a.slider=a.control_element;a.slider_label=d}this.content_div=$("<div class='track-content'>").appendTo(this.container_div);this.parent_element.append(this.container_div)},init_each:function(c,b){var a=this;a.enabled=false;a.data_queue={};a.tile_cache.clear();a.data_cache.clear();a.initial_canvas=undefined;a.content_div.css("height","auto");if(!a.content_div.text()){a.content_div.text(DATA_LOADING)}a.container_div.removeClass("nodata error pending");if(a.view.chrom){$.getJSON(data_url,c,function(d){if(!d||d==="error"||d.kind==="error"){a.container_div.addClass("error");a.content_div.text(DATA_ERROR);if(d.message){var f=a.view.tracks.indexOf(a);var e=$("
<a href='javascript:void(0);'></a>").attr("id",f+"_error");e.text("Click to view error");$("#"+f+"_error").live("click",function(){show_modal("Trackster Error","<pre>"+d.message+"</pre>",{Close:hide_modal})});a.content_div.append(e)}}else{if(d==="no converter"){a.container_div.addClass("error");a.content_div.text(DATA_NOCONVERTER)}else{if(d.data!==undefined&&(d.data===null||d.data.length===0)){a.container_div.addClass("nodata");a.content_div.text(DATA_NONE)}else{if(d==="pending"){a.container_div.addClass("pending");a.content_div.text(DATA_PENDING);setTimeout(function(){a.init()},5000)}else{a.content_div.text("");a.content_div.css("height",a.height_px+"px");a.enabled=true;b(d);a.draw()}}}}})}else{a.container_div.addClass("nodata");a.content_div.text(DATA_NONE)}}});var TiledTrack=function(){var b=this,j=b.view;if(b.hidden){return}if(b.display_modes!==undefined){if(b.mode_div===undefined){b.mode_div=$("<div class='right-float menubutton popup' />").appendTo(b.header_div);var e=
b.display_modes[0];b.mode=e;b.mode_div.text(e);var c=function(i){b.mode_div.text(i);b.mode=i;b.tile_cache.clear();b.draw()};var a={};for(var f=0,h=b.display_modes.length;f<h;f++){var g=b.display_modes[f];a[g]=function(i){return function(){c(i)}}(g)}make_popupmenu(b.mode_div,a)}else{b.mode_div.hide()}}var d={};d["Set as overview"]=function(){j.overview_viewport.find("canvas").remove();b.is_overview=true;b.set_overview();for(var i in j.tracks){if(j.tracks[i]!==b){j.tracks[i].is_overview=false}}};d["Edit configuration"]=function(){var l=function(){hide_modal();$(window).unbind("keypress.check_enter_esc")},i=function(){b.update_options(b.track_id);hide_modal();$(window).unbind("keypress.check_enter_esc")},k=function(m){if((m.keyCode||m.which)===27){l()}else{if((m.keyCode||m.which)===13){i()}}};$(window).bind("keypress.check_enter_esc",k);show_modal("Configure Track",b.gen_options(b.track_id),{Cancel:l,OK:i})};if(b.filters.length>0){d["Show filters"]=function(){var i;if(!b.filter
ing_div.is(":visible")){i="Hide filters";b.filters_visible=true}else{i="Show filters";b.filters_visible=false}$("#"+b.name_div.attr("id")+"-menu").find("li").eq(2).text(i);b.filtering_div.toggle()}}d.Remove=function(){j.remove_track(b);if(j.num_tracks===0){$("#no-tracks").show()}};b.popup_menu=make_popupmenu(b.name_div,d);show_hide_popupmenu_options(b.popup_menu,"(Show|Hide) filters",false)};$.extend(TiledTrack.prototype,Track.prototype,{draw:function(a){var k=this.view.low,g=this.view.high,h=g-k,f=this.view.resolution;var n=$("<div style='position: relative;'></div>"),o=this.content_div.width()/h;this.content_div.append(n);this.max_height=0;var b=Math.floor(k/f/DENSITY);var j={};while((b*DENSITY*f)<g){var l=this.content_div.width()+"_"+o+"_"+b;var e=this.tile_cache.get(l);if(!a&&e){var i=b*DENSITY*f;var d=(i-k)*o;if(this.left_offset){d-=this.left_offset}e.css({left:d});this.show_tile(e,n)}else{this.delayed_draw(this,l,k,g,b,f,n,o,j)}b+=1}var c=this;var m=setInterval(functio
n(){if(obj_length(j)===0){if(c.content_div.children().length>1){c.content_div.children(":first").remove()}for(var p=0;p<c.filters.length;p++){c.filters[p].update_ui_elt()}clearInterval(m)}},50)},delayed_draw:function(c,h,g,e,b,d,i,j,f){var a=setTimeout(function(){if(g<=c.view.high&&e>=c.view.low){var k=c.draw_tile(d,b,i,j);if(k){if(!c.initial_canvas&&!window.G_vmlCanvasManager){c.initial_canvas=$(k).clone();var n=k.get(0).getContext("2d");var l=c.initial_canvas.get(0).getContext("2d");var m=n.getImageData(0,0,n.canvas.width,n.canvas.height);l.putImageData(m,0,0);c.set_overview()}c.tile_cache.set(h,k);c.show_tile(k,i)}}delete f[a]},50);f[a]=true},show_tile:function(a,c){var b=this;c.append(a);b.max_height=Math.max(b.max_height,a.height());b.content_div.css("height",b.max_height+"px");if(a.hasClass(FILTERABLE_CLASS)){show_hide_popupmenu_options(b.popup_menu,"(Show|Hide) filters");if(b.filters_visible){b.filtering_div.show()}}else{show_hide_popupmenu_options(b.popup_menu,"(Show
|Hide) filters",false);b.filtering_div.hide()}},set_overview:function(){var a=this.view;if(this.initial_canvas&&this.is_overview){a.overview_close.show();a.overview_viewport.append(this.initial_canvas);a.overview_highlight.show().height(this.initial_canvas.height());a.overview_viewport.height(this.initial_canvas.height()+a.overview_box.height())}$(window).trigger("resize")}});var LabelTrack=function(a,b){this.track_type="LabelTrack";this.hidden=true;Track.call(this,null,a,b);this.container_div.addClass("label-track")};$.extend(LabelTrack.prototype,Track.prototype,{draw:function(){var c=this.view,d=c.high-c.low,g=Math.floor(Math.pow(10,Math.floor(Math.log(d)/Math.log(10)))),a=Math.floor(c.low/g)*g,e=this.content_div.width(),b=$("<div style='position: relative; height: 1.3em;'></div>");while(a<c.high){var f=(a-c.low)/d*e;b.append($("<div class='label'>"+commatize(a)+"</div>").css({position:"absolute",left:f-1}));a+=g}this.content_div.children(":first").remove();this.content_di
v.append(b)}});var ReferenceTrack=function(a){this.track_type="ReferenceTrack";this.hidden=true;Track.call(this,null,a,a.top_labeltrack);TiledTrack.call(this);this.left_offset=200;this.height_px=12;this.container_div.addClass("reference-track");this.data_queue={};this.data_cache=new Cache(CACHED_DATA);this.tile_cache=new Cache(CACHED_TILES_LINE)};$.extend(ReferenceTrack.prototype,TiledTrack.prototype,{get_data:function(d,b){var c=this,a=b*DENSITY*d,f=(b+1)*DENSITY*d,e=d+"_"+b;if(!c.data_queue[e]){c.data_queue[e]=true;$.ajax({url:reference_url,dataType:"json",data:{chrom:this.view.chrom,low:a,high:f,dbkey:this.view.dbkey},success:function(g){c.data_cache.set(e,g);delete c.data_queue[e];c.draw()},error:function(h,g,i){console.log(h,g,i)}})}},draw_tile:function(f,b,k,o){var g=b*DENSITY*f,d=DENSITY*f,j=f+"_"+b;var e=document.createElement("canvas");if(window.G_vmlCanvasManager){G_vmlCanvasManager.initElement(e)}e=$(e);var n=e.get(0).getContext("2d");if(o>PX_PER_CHAR){if(this.dat
a_cache.get(j)===undefined){this.get_data(f,b);return}var m=this.data_cache.get(j);if(m===null){this.content_div.css("height","0px");return}e.get(0).width=Math.ceil(d*o+this.left_offset);e.get(0).height=this.height_px;e.css({position:"absolute",top:0,left:(g-this.view.low)*o-this.left_offset});for(var h=0,l=m.length;h<l;h++){var a=Math.round(h*o),i=Math.round(o/2);n.fillText(m[h],a+this.left_offset+i,10)}k.append(e);return e}this.content_div.css("height","0px")}});var LineTrack=function(d,b,a,c){this.track_type="LineTrack";this.display_modes=["Histogram","Line","Filled","Intensity"];this.mode="Histogram";Track.call(this,d,b,b.viewport_container);TiledTrack.call(this);this.height_px=80;this.dataset_id=a;this.data_cache=new Cache(CACHED_DATA);this.tile_cache=new Cache(CACHED_TILES_LINE);this.prefs={color:"black",min_value:undefined,max_value:undefined,mode:this.mode}};$.extend(LineTrack.prototype,TiledTrack.prototype,{init:function(){var a=this,b=a.view.tracks.indexOf(a);a.ver
tical_range=undefined;this.init_each({stats:true,chrom:a.view.chrom,low:null,high:null,dataset_id:a.dataset_id},function(c){a.container_div.addClass("line-track");var e=c.data;if(isNaN(parseFloat(a.prefs.min_value))||isNaN(parseFloat(a.prefs.max_value))){a.prefs.min_value=e.min;a.prefs.max_value=e.max;$("#track_"+b+"_minval").val(a.prefs.min_value);$("#track_"+b+"_maxval").val(a.prefs.max_value)}a.vertical_range=a.prefs.max_value-a.prefs.min_value;a.total_frequency=e.total_frequency;a.container_div.find(".yaxislabel").remove();var f=$("<div />").addClass("yaxislabel").attr("id","linetrack_"+b+"_minval").text(round_1000(a.prefs.min_value));var d=$("<div />").addClass("yaxislabel").attr("id","linetrack_"+b+"_maxval").text(round_1000(a.prefs.max_value));d.css({position:"absolute",top:"22px",left:"10px"});d.prependTo(a.container_div);f.css({position:"absolute",top:a.height_px+11+"px",left:"10px"});f.prependTo(a.container_div)})},get_data:function(d,b){var c=this,a=b*DENSITY*d,f=
(b+1)*DENSITY*d,e=d+"_"+b;if(!c.data_queue[e]){c.data_queue[e]=true;$.ajax({url:data_url,dataType:"json",data:{chrom:this.view.chrom,low:a,high:f,dataset_id:this.dataset_id,resolution:this.view.resolution},success:function(g){var h=g.data;c.data_cache.set(e,h);delete c.data_queue[e];c.draw()},error:function(h,g,i){console.log(h,g,i)}})}},draw_tile:function(o,r,c,e){if(this.vertical_range===undefined){return}var s=r*DENSITY*o,a=DENSITY*o,w=o+"_"+r;var b=document.createElement("canvas");if(window.G_vmlCanvasManager){G_vmlCanvasManager.initElement(b)}b=$(b);if(this.data_cache.get(w)===undefined){this.get_data(o,r);return}var v=this.data_cache.get(w);if(!v){return}b.css({position:"absolute",top:0,left:(s-this.view.low)*e});b.get(0).width=Math.ceil(a*e);b.get(0).height=this.height_px;var n=b.get(0).getContext("2d"),j=false,k=this.prefs.min_value,g=this.prefs.max_value,m=this.vertical_range,t=this.total_frequency,d=this.height_px,l=this.mode;n.beginPath();n.fillStyle=this.prefs.co
lor;var u,h,f;if(v.length>1){f=Math.ceil((v[1][0]-v[0][0])*e)}else{f=10}for(var p=0,q=v.length;p<q;p++){u=Math.round((v[p][0]-s)*e);h=v[p][1];if(h===null){if(j&&l==="Filled"){n.lineTo(u,d)}j=false;continue}if(h<k){h=k}else{if(h>g){h=g}}if(l==="Histogram"){h=Math.round(d-(h-k)/m*d);n.fillRect(u,h,f,d-h)}else{if(l==="Intensity"){h=255-Math.floor((h-k)/m*255);n.fillStyle="rgb("+h+","+h+","+h+")";n.fillRect(u,0,f,d)}else{h=Math.round(d-(h-k)/m*d);if(j){n.lineTo(u,h)}else{j=true;if(l==="Filled"){n.moveTo(u,d);n.lineTo(u,h)}else{n.moveTo(u,h)}}}}}if(l==="Filled"){if(j){n.lineTo(u,d)}n.fill()}else{n.stroke()}c.append(b);return b},gen_options:function(m){var a=$("<div />").addClass("form-row");var e="track_"+m+"_color",b=$("<label />").attr("for",e).text("Color:"),c=$("<input />").attr("id",e).attr("name",e).val(this.prefs.color),h="track_"+m+"_minval",l=$("<label></label>").attr("for",h).text("Min value:"),d=(this.prefs.min_value===undefined?"":this.prefs.min_value),k=$("<input></i
nput>").attr("id",h).val(d),j="track_"+m+"_maxval",g=$("<label></label>").attr("for",j).text("Max value:"),i=(this.prefs.max_value===undefined?"":this.prefs.max_value),f=$("<input></input>").attr("id",j).val(i);return a.append(l).append(k).append(g).append(f).append(b).append(c)},update_options:function(d){var a=$("#track_"+d+"_minval").val(),c=$("#track_"+d+"_maxval").val(),b=$("#track_"+d+"_color").val();if(a!==this.prefs.min_value||c!==this.prefs.max_value||b!==this.prefs.color){this.prefs.min_value=parseFloat(a);this.prefs.max_value=parseFloat(c);this.prefs.color=b;this.vertical_range=this.prefs.max_value-this.prefs.min_value;$("#linetrack_"+d+"_minval").text(this.prefs.min_value);$("#linetrack_"+d+"_maxval").text(this.prefs.max_value);this.tile_cache.clear();this.draw()}}});var FeatureTrack=function(d,b,a,e,c){this.track_type="FeatureTrack";this.display_modes=["Auto","Dense","Squish","Pack"];Track.call(this,d,b,b.viewport_container,e);TiledTrack.call(this);this.height_p
x=0;this.container_div.addClass("feature-track");this.dataset_id=a;this.zo_slots={};this.show_labels_scale=0.001;this.showing_details=false;this.vertical_detail_px=10;this.vertical_nodetail_px=2;this.summary_draw_height=30;this.default_font="9px Monaco, Lucida Console, monospace";this.inc_slots={};this.data_queue={};this.s_e_by_tile={};this.tile_cache=new Cache(CACHED_TILES_FEATURE);this.data_cache=new Cache(20);this.left_offset=200;this.prefs={block_color:"#444",label_color:"black",show_counts:true}};$.extend(FeatureTrack.prototype,TiledTrack.prototype,{init:function(){var a=this,b="initial";this.init_each({low:a.view.max_low,high:a.view.max_high,dataset_id:a.dataset_id,chrom:a.view.chrom,resolution:this.view.resolution,mode:a.mode},function(c){a.mode_div.show();a.data_cache.set(b,c);a.draw()})},get_data:function(a,d){var b=this,c=a+"_"+d;if(!b.data_queue[c]){b.data_queue[c]=true;$.getJSON(data_url,{chrom:b.view.chrom,low:a,high:d,dataset_id:b.dataset_id,resolution:this.vie
w.resolution,mode:this.mode},function(e){b.data_cache.set(c,e);delete b.data_queue[c];b.draw()})}},incremental_slots:function(a,g,b,q){if(!this.inc_slots[a]){this.inc_slots[a]={};this.inc_slots[a].w_scale=a;this.inc_slots[a].mode=q;this.s_e_by_tile[a]={}}var m=this.inc_slots[a].w_scale,y=[],h=0,n=this.view.max_low;var A=[];if(this.inc_slots[a].mode!==q){delete this.inc_slots[a];this.inc_slots[a]={mode:q,w_scale:m};delete this.s_e_by_tile[a];this.s_e_by_tile[a]={}}for(var v=0,w=g.length;v<w;v++){var f=g[v],l=f[0];if(this.inc_slots[a][l]!==undefined){h=Math.max(h,this.inc_slots[a][l]);A.push(this.inc_slots[a][l])}else{y.push(v)}}for(var v=0,w=y.length;v<w;v++){var f=g[y[v]],l=f[0],r=f[1],c=f[2],p=f[3],d=Math.floor((r-n)*m),e=Math.ceil((c-n)*m);if(p!==undefined&&!b){var s=CONTEXT.measureText(p).width;if(d-s<0){e+=s}else{d-=s}}var u=0;while(u<=MAX_FEATURE_DEPTH){var o=true;if(this.s_e_by_tile[a][u]!==undefined){for(var t=0,z=this.s_e_by_tile[a][u].length;t<z;t++){var x=this.s_e_
by_tile[a][u][t];if(e>x[0]&&d<x[1]){o=false;break}}}if(o){if(this.s_e_by_tile[a][u]===undefined){this.s_e_by_tile[a][u]=[]}this.s_e_by_tile[a][u].push([d,e]);this.inc_slots[a][l]=u;h=Math.max(h,u);break}u++}}return h},rect_or_text:function(r,l,t,b,q,f,i,e){r.textAlign="center";var k=0,p=Math.round(l/2);for(var m=0,s=i.length;m<s;m++){var j=i[m],d="MIDNSHP"[j[0]],n=j[1];if(d==="H"||d==="S"){k-=n}var g=q+k,w=Math.floor(Math.max(0,(g-t)*l)),h=Math.floor(Math.max(0,(g+n-t)*l));switch(d){case"S":case"H":case"M":var o=f.slice(k,n);if((this.mode==="Pack"||this.mode==="Auto")&&f!==undefined&&l>PX_PER_CHAR){r.fillStyle=this.prefs.block_color;r.fillRect(w+this.left_offset,e+1,h-w,9);r.fillStyle=CONNECTOR_COLOR;for(var u=0,a=o.length;u<a;u++){if(g+u>=t&&g+u<=b){var v=Math.floor(Math.max(0,(g+u-t)*l));r.fillText(o[u],v+this.left_offset+p,e+9)}}}else{r.fillStyle=this.prefs.block_color;r.fillRect(w+this.left_offset,e+4,h-w,3)}break;case"N":r.fillStyle=CONNECTOR_COLOR;r.fillRect(w+this.lef
t_offset,e+5,h-w,1);break;case"D":r.fillStyle="red";r.fillRect(w+this.left_offset,e+4,h-w,3);break;case"P":case"I":break}k+=n}},draw_tile:function(ag,o,s,av){var N=o*DENSITY*ag,al=(o+1)*DENSITY*ag,M=al-N;var an=(!this.initial_canvas?"initial":N+"_"+al);var I=this.data_cache.get(an);var e;if(I===undefined||(this.mode!=="Auto"&&I.dataset_type==="summary_tree")){this.data_queue[[N,al]]=true;this.get_data(N,al);return}var a=Math.ceil(M*av),ai=this.prefs.label_color,l=this.prefs.block_color,r=this.mode,z=25,ae=(r==="Squish")||(r==="Dense")&&(r!=="Pack")||(r==="Auto"&&(I.extra_info==="no_detail")),W=this.left_offset,au,D,aw;var q=document.createElement("canvas");if(window.G_vmlCanvasManager){G_vmlCanvasManager.initElement(q)}q=$(q);if(I.dataset_type==="summary_tree"){D=this.summary_draw_height}else{if(r==="Dense"){D=z;aw=10}else{aw=(ae?this.vertical_nodetail_px:this.vertical_detail_px);var A=(av<0.0001?1/this.view.zoom_res:av);D=this.incremental_slots(A,I.data,ae,r)*aw+z;au=this.i
nc_slots[A]}}q.css({position:"absolute",top:0,left:(N-this.view.low)*av-W});q.get(0).width=a+W;q.get(0).height=D;s.parent().css("height",Math.max(this.height_px,D)+"px");var J=q.get(0).getContext("2d");J.fillStyle=l;J.font=this.default_font;J.textAlign="right";this.container_div.find(".yaxislabel").remove();if(I.dataset_type=="summary_tree"){var Y=I.data,L=I.max,b=Math.ceil(I.delta*av);var p=$("<div />").addClass("yaxislabel").text(L);p.css({position:"absolute",top:"22px",left:"10px"});p.prependTo(this.container_div);for(var ap=0,H=Y.length;ap<H;ap++){var aa=Math.floor((Y[ap][0]-N)*av);var Z=Y[ap][1];if(!Z){continue}var am=Z/L*this.summary_draw_height;J.fillStyle="black";J.fillRect(aa+W,this.summary_draw_height-am,b,am);if(this.prefs.show_counts&&J.measureText(Z).width<b){J.fillStyle="#bbb";J.textAlign="center";J.fillText(Z,aa+W+(b/2),this.summary_draw_height-5)}}e="Summary";s.append(q);return q}if(I.message){q.css({border:"solid red","border-width":"2px 2px 2px 0px"});J.fil
lStyle="red";J.textAlign="left";J.fillText(I.message,100+W,aw)}var ad=false;if(I.data){ad=true;for(var ar=0;ar<this.filters.length;ar++){if(!this.filters[ar].applies_to(I.data[0])){ad=false}}}if(ad){q.addClass(FILTERABLE_CLASS)}var at=I.data;var ao=0;for(var ap=0,H=at.length;ap<H;ap++){var S=at[ap],R=S[0],aq=S[1],ac=S[2],O=S[3];if(au[R]===undefined){continue}var ab=false;var U;for(var ar=0;ar<this.filters.length;ar++){U=this.filters[ar];U.update_attrs(S);if(!U.keep(S)){ab=true;break}}if(ab){continue}if(aq<=al&&ac>=N){var af=Math.floor(Math.max(0,(aq-N)*av)),K=Math.ceil(Math.min(a,Math.max(0,(ac-N)*av))),X=(r==="Dense"?1:(1+au[R]))*aw;var G,aj,P=null,ax=null;if(I.dataset_type==="bai"){var v=S[4];J.fillStyle=l;if(S[5] instanceof Array){var E=Math.floor(Math.max(0,(S[5][0]-N)*av)),Q=Math.ceil(Math.min(a,Math.max(0,(S[5][1]-N)*av))),C=Math.floor(Math.max(0,(S[6][0]-N)*av)),w=Math.ceil(Math.min(a,Math.max(0,(S[6][1]-N)*av)));if(S[5][1]>=N&&S[5][0]<=al){this.rect_or_text(J,av,N,al
,S[5][0],S[5][2],v,X)}if(S[6][1]>=N&&S[6][0]<=al){this.rect_or_text(J,av,N,al,S[6][0],S[6][2],v,X)}if(C>Q){J.fillStyle=CONNECTOR_COLOR;J.fillRect(Q+W,X+5,C-Q,1)}}else{J.fillStyle=l;this.rect_or_text(J,av,N,al,aq,O,v,X)}if(r!=="Dense"&&!ae&&aq>N){J.fillStyle=this.prefs.label_color;if(o===0&&af-J.measureText(O).width<0){J.textAlign="left";J.fillText(R,K+2+W,X+8)}else{J.textAlign="right";J.fillText(R,af-2+W,X+8)}J.fillStyle=l}}else{if(I.dataset_type==="interval_index"){if(ae){J.fillStyle=l;J.fillRect(af+W,X+5,K-af,1)}else{var F=S[4],V=S[5],ah=S[6],h=S[7];if(V&&ah){P=Math.floor(Math.max(0,(V-N)*av));ax=Math.ceil(Math.min(a,Math.max(0,(ah-N)*av)))}if(r!=="Dense"&&O!==undefined&&aq>N){J.fillStyle=ai;if(o===0&&af-J.measureText(O).width<0){J.textAlign="left";J.fillText(O,K+2+W,X+8)}else{J.textAlign="right";J.fillText(O,af-2+W,X+8)}J.fillStyle=l}if(h){if(F){if(F=="+"){J.fillStyle=RIGHT_STRAND}else{if(F=="-"){J.fillStyle=LEFT_STRAND}}J.fillRect(af+W,X,K-af,10);J.fillStyle=l}for(var an
=0,g=h.length;an<g;an++){var u=h[an],d=Math.floor(Math.max(0,(u[0]-N)*av)),T=Math.ceil(Math.min(a,Math.max((u[1]-N)*av)));if(d>T){continue}G=5;aj=3;J.fillRect(d+W,X+aj,T-d,G);if(P!==undefined&&!(d>ax||T<P)){G=9;aj=1;var ak=Math.max(d,P),B=Math.min(T,ax);J.fillRect(ak+W,X+aj,B-ak,G)}}}else{G=9;aj=1;J.fillRect(af+W,X+aj,K-af,G);if(S.strand){if(S.strand=="+"){J.fillStyle=RIGHT_STRAND_INV}else{if(S.strand=="-"){J.fillStyle=LEFT_STRAND_INV}}J.fillRect(af+W,X,K-af,10);J.fillStyle=l}}}}else{if(I.dataset_type==="vcf"){if(ae){J.fillStyle=l;J.fillRect(af+W,X+5,K-af,1)}else{var t=S[4],n=S[5],c=S[6];G=9;aj=1;J.fillRect(af+W,X,K-af,G);if(r!=="Dense"&&O!==undefined&&aq>N){J.fillStyle=ai;if(o===0&&af-J.measureText(O).width<0){J.textAlign="left";J.fillText(O,K+2+W,X+8)}else{J.textAlign="right";J.fillText(O,af-2+W,X+8)}J.fillStyle=l}var m=t+" / "+n;if(aq>N&&J.measureText(m).width<(K-af)){J.fillStyle="white";J.textAlign="center";J.fillText(m,W+af+(K-af)/2,X+8);J.fillStyle=l}}}}}ao++}}return q
},gen_options:function(i){var a=$("<div />").addClass("form-row");var e="track_"+i+"_block_color",k=$("<label />").attr("for",e).text("Block color:"),l=$("<input />").attr("id",e).attr("name",e).val(this.prefs.block_color),j="track_"+i+"_label_color",g=$("<label />").attr("for",j).text("Text color:"),h=$("<input />").attr("id",j).attr("name",j).val(this.prefs.label_color),f="track_"+i+"_show_count",c=$("<label />").attr("for",f).text("Show summary counts"),b=$('<input type="checkbox" style="float:left;"></input>').attr("id",f).attr("name",f).attr("checked",this.prefs.show_counts),d=$("<div />").append(b).append(c);return a.append(k).append(l).append(g).append(h).append(d)},update_options:function(d){var b=$("#track_"+d+"_block_color").val(),c=$("#track_"+d+"_label_color").val(),a=$("#track_"+d+"_show_count").attr("checked");if(b!==this.prefs.block_color||c!==this.prefs.label_color||a!==this.prefs.show_counts){this.prefs.block_color=b;this.prefs.label_color=c;this.prefs.show_
counts=a;this.tile_cache.clear();this.draw()}}});var ReadTrack=function(d,b,a,e,c){FeatureTrack.call(this,d,b,a,e,c);this.track_type="ReadTrack";this.vertical_detail_px=10;this.vertical_nodetail_px=5};$.extend(ReadTrack.prototype,TiledTrack.prototype,FeatureTrack.prototype,{});
1
0
galaxy-dist commit 569483091092: Keep the sample's bar code incormation when editn the sample row in the non-admin user view.
by commits-noreply@bitbucket.org 20 Nov '10
by commits-noreply@bitbucket.org 20 Nov '10
20 Nov '10
# HG changeset patch -- Bitbucket.org
# Project galaxy-dist
# URL http://bitbucket.org/galaxy/galaxy-dist/overview
# User Greg Von Kuster <greg(a)bx.psu.edu>
# Date 1288731289 14400
# Node ID 56948309109207f932a113e464409432c7a38df7
# Parent 27c152bb441a0136720dbbc0c7cb293e581b8f5f
Keep the sample's bar code incormation when editn the sample row in the non-admin user view.
--- a/templates/requests/common/common.mako
+++ b/templates/requests/common/common.mako
@@ -153,6 +153,7 @@
<input type="text" name="sample_${current_sample_index}_barcode" value="${current_sample['barcode']}" size="10"/>
%else:
${current_sample['barcode']}
+ <input type="hidden" name="sample_${current_sample_index}_barcode" value="${current_sample['barcode']}"/>
%endif
</td>
%endif
@@ -261,7 +262,7 @@
%elif sample:
<tr><td>${current_sample_name}</td>
- %if is_submitted or is_complete:
+ %if display_bar_code:
<td>${current_sample_barcode}</td>
%endif
%if is_unsubmitted:
1
0
galaxy-dist commit 27c152bb441a: More sample tracking bug fixes - tweaked permissions on displaying buttons, and fixed exceptions thrown when ddata transfer congid file is incorrect.
by commits-noreply@bitbucket.org 20 Nov '10
by commits-noreply@bitbucket.org 20 Nov '10
20 Nov '10
# HG changeset patch -- Bitbucket.org
# Project galaxy-dist
# URL http://bitbucket.org/galaxy/galaxy-dist/overview
# User Greg Von Kuster <greg(a)bx.psu.edu>
# Date 1288730067 14400
# Node ID 27c152bb441a0136720dbbc0c7cb293e581b8f5f
# Parent 6497a8cfd12e477e9c92dd183c4abb81d469ba51
More sample tracking bug fixes - tweaked permissions on displaying buttons, and fixed exceptions thrown when ddata transfer congid file is incorrect.
--- a/lib/galaxy/web/controllers/requests_admin.py
+++ b/lib/galaxy/web/controllers/requests_admin.py
@@ -541,7 +541,7 @@ class RequestsAdmin( BaseController, Use
return sample.request.name + '_' + sample.name + '_' + name
if opt == options.EXPERIMENT_NAME:
return sample.request.name + '_' + name
- def __setup_datatx_user( self, trans, library, folder ):
+ def __setup_datatx_user( self, trans, sample ):
"""
Sets up the datatx user:
- Checks if the user exists, if not creates them.
@@ -550,9 +550,25 @@ class RequestsAdmin( BaseController, Use
"""
# Retrieve the upload user login information from the config file
config = ConfigParser.ConfigParser()
- config.read( 'transfer_datasets.ini' )
- email = config.get( "data_transfer_user_login_info", "email" )
- password = config.get( "data_transfer_user_login_info", "password" )
+ ok = True
+ try:
+ config.read( 'transfer_datasets.ini' )
+ except Exception, e:
+ message = "Error attempting to read config file named 'transfer_datasets.ini'. Make sure this file is correct."
+ ok = False
+ try:
+ email = config.get( "data_transfer_user_login_info", "email" )
+ password = config.get( "data_transfer_user_login_info", "password" )
+ except Exception, e:
+ message = "The 'data_transfer_user_login_info' section is missing from the 'transfer_datasets.ini'. Make sure this file is correct."
+ ok = False
+ if not ok:
+ status = 'error'
+ return trans.response.send_redirect( web.url_for( controller='requests_admin',
+ action='manage_datasets',
+ sample_id=trans.security.encode_id( sample.id ),
+ status=status,
+ message=message ) )
# check if the user already exists
datatx_user = trans.sa_session.query( trans.model.User ) \
.filter( trans.model.User.table.c.email==email ) \
@@ -570,14 +586,14 @@ class RequestsAdmin( BaseController, Use
datatx_user_private_role = trans.app.security_agent.get_private_user_role( datatx_user )
# Make sure this user has LIBRARY_ADD permissions on the target library and folder.
# If not, give them permission.
- if not trans.app.security_agent.can_add_library_item( datatx_user_roles, library ):
+ if not trans.app.security_agent.can_add_library_item( datatx_user_roles, sample.library ):
lp = trans.model.LibraryPermissions( trans.app.security_agent.permitted_actions.LIBRARY_ADD.action,
- library,
+ sample.library,
datatx_user_private_role )
trans.sa_session.add( lp )
- if not trans.app.security_agent.can_add_library_item( datatx_user_roles, folder ):
+ if not trans.app.security_agent.can_add_library_item( datatx_user_roles, sample.folder ):
lfp = trans.model.LibraryFolderPermissions( trans.app.security_agent.permitted_actions.LIBRARY_ADD.action,
- folder,
+ sample.folder,
datatx_user_private_role )
trans.sa_session.add( lfp )
trans.sa_session.flush()
@@ -646,7 +662,7 @@ class RequestsAdmin( BaseController, Use
message=message) )
def __start_datatx( self, trans, sample, selected_sample_datasets ):
- datatx_user = self.__setup_datatx_user( trans, sample.library, sample.folder )
+ datatx_user = self.__setup_datatx_user( trans, sample )
# Validate sequencer information
datatx_info = sample.request.type.datatx_info
if not datatx_info['host'] or not datatx_info['username'] or not datatx_info['password']:
@@ -660,7 +676,7 @@ class RequestsAdmin( BaseController, Use
action='manage_datasets',
sample_id=trans.security.encode_id( sample.id ),
status=status,
- message=message) )
+ message=message ) )
@web.expose
def update_sample_dataset_status(self, trans, cntrller, sample_dataset_ids, new_status, error_msg=None ):
# check if the new status is a valid transfer status
--- a/templates/requests/common/common.mako
+++ b/templates/requests/common/common.mako
@@ -120,20 +120,25 @@
if sample:
trans.sa_session.refresh( sample.request )
is_complete = sample.request.is_complete
+ is_rejected = request.is_rejected
is_submitted = sample.request.is_submitted
is_unsubmitted = sample.request.is_unsubmitted
+ display_checkboxes = editing_samples and ( is_complete or is_rejected or is_submitted )
+ display_bar_code = request.samples and ( is_complete or is_rejected or is_submitted )
+ display_datasets = request.samples and ( is_complete or is_rejected or is_submitted )
else:
is_complete = False
is_submitted = False
is_unsubmitted = False
+ display_checkboxes = False
%><%
- if is_submitted and editing_samples and trans.security.encode_id( sample.id ) in encoded_selected_sample_ids:
+ if display_checkboxes and trans.security.encode_id( sample.id ) in encoded_selected_sample_ids:
checked_str = "checked"
else:
checked_str = ""
%>
- %if is_submitted and editing_samples:
+ %if display_checkboxes:
<td><input type="checkbox" name=select_sample_${sample.id} id="sample_checkbox" value="true" ${checked_str}/><input type="hidden" name=select_sample_${sample.id} id="sample_checkbox" value="true"/></td>
%endif
<td valign="top">
@@ -142,12 +147,14 @@
<i>${' (required)' }</i></div></td>
- %if sample and is_submitted or is_complete:
- %if is_admin:
- <td valign="top"><input type="text" name="sample_${current_sample_index}_barcode" value="${current_sample['barcode']}" size="10"/></td>
- %else:
- ${current_sample['barcode']}
- %endif
+ %if display_bar_code:
+ <td valign="top">
+ %if is_admin:
+ <input type="text" name="sample_${current_sample_index}_barcode" value="${current_sample['barcode']}" size="10"/>
+ %else:
+ ${current_sample['barcode']}
+ %endif
+ </td>
%endif
%if sample:
%if is_unsubmitted:
@@ -160,7 +167,7 @@
%endif
<td valign="top">${current_sample['library_select_field'].get_html()}</td><td valign="top">${current_sample['folder_select_field'].get_html()}</td>
- %if is_submitted or is_complete:
+ %if display_datasets:
<%
if sample:
label = str( len( sample.datasets ) )
@@ -182,11 +189,15 @@
trans.sa_session.refresh( request )
is_admin = cntrller == 'requests_admin' and trans.user_is_admin()
is_complete = request.is_complete
+ is_rejected = request.is_rejected
is_submitted = request.is_submitted
is_unsubmitted = request.is_unsubmitted
can_add_samples = request.is_unsubmitted
can_delete_samples = request.samples and not is_complete
can_edit_samples = request.samples and ( is_admin or not is_complete )
+ display_checkboxes = editing_samples and ( is_complete or is_rejected or is_submitted )
+ display_bar_code = request.samples and ( is_complete or is_rejected or is_submitted )
+ display_datasets = request.samples and ( is_complete or is_rejected or is_submitted )
%>
${grid_header}
%if render_buttons and ( can_add_samples or can_edit_samples ):
@@ -202,22 +213,22 @@
<table class="grid"><thead><tr>
- %if is_submitted and editing_samples:
+ %if display_checkboxes:
<th><input type="checkbox" id="checkAll" name=select_all_samples_checkbox value="true" onclick='checkAllFields(1);'/><input type="hidden" name=select_all_samples_checkbox value="true"/></th>
%endif
<th>Name</th>
- %if is_submitted or is_complete:
+ %if display_bar_code:
<th>Barcode</th>
%endif
<th>State</th><th>Data Library</th><th>Folder</th>
- %if is_submitted or is_complete:
+ %if display_datasets:
<th>Datasets Selected</th><th>Datasets Transferred</th>
%endif
<th>
- %if editing_samples:
+ %if can_delete_samples:
Delete
%endif
</th>
@@ -245,7 +256,7 @@
except:
sample = None
%>
- %if not is_complete and editing_samples:
+ %if editing_samples:
<tr>${render_editable_sample_row( is_admin, sample, current_sample_index, current_sample, encoded_selected_sample_ids )}</tr>
%elif sample:
<tr>
1
0