소스 검색

Merge branch 'advancedoptions' into advancedoptions

Bradford Condon 6 년 전
부모
커밋
2d0a764277

+ 4 - 0
.gitignore

@@ -0,0 +1,4 @@
+
+# Ignore an internal CViTjs installation.
+# Assumes it's been cloned in the js directory
+js/*

+ 127 - 42
api/blast_ui.api.inc

@@ -48,23 +48,8 @@ function get_blast_database($identifiers) {
 function get_blast_database_options($type) {
   global $user;
 
-  // Use the Entity API to get a list of BLAST Nodes to load
-  // We use this function in order respect node access control so that
-  // administrators can use this module in combination with a node access module
-  // of their choice to limit access to specific BLAST databases.
-  $query = new EntityFieldQuery();
-  $query->entityCondition('entity_type', 'node')
-    // Restrict to BLASTDB nodes.
-    ->entityCondition('bundle', 'blastdb')
-    // Restrict to Published nodes.
-    ->propertyCondition('status', 1)
-    // Restrict to nodes the current user has permission to view.
-    ->addTag('node_access');
-  $entities = $query->execute();
-
-
   // Get all BlastDB nodes
-  $nodes  = node_load_multiple(array_keys($entities['node']));
+  $nodes = get_blast_database_nodes();
 
   // Support obsolete database type n/p
   $obs_type = '';
@@ -90,6 +75,32 @@ function get_blast_database_options($type) {
   return $options;
 }
 
+/**
+ * Returns all blast database nodes.
+ *
+ * @return
+ *   An array of nodes.
+ */
+function get_blast_database_nodes() {
+  // Use the Entity API to get a list of BLAST Nodes to load
+  // We use this function in order respect node access control so that
+  // administrators can use this module in combination with a node access module
+  // of their choice to limit access to specific BLAST databases.
+  $query = new EntityFieldQuery();
+  $query->entityCondition('entity_type', 'node')
+    // Restrict to BLASTDB nodes.
+    ->entityCondition('bundle', 'blastdb')
+    // Restrict to Published nodes.
+    ->propertyCondition('status', 1)
+    // Restrict to nodes the current user has permission to view.
+    ->addTag('node_access');
+  $entities = $query->execute();
+
+  // Get all BlastDB nodes
+  return node_load_multiple(array_keys($entities['node']));
+}
+
+
 /**
  * Retrieve all the information for a blast job in a standardized node-like format.
  *
@@ -101,6 +112,11 @@ function get_blast_database_options($type) {
 function get_BLAST_job($job_id) {
 
   $blastjob = db_query('SELECT * FROM blastjob WHERE job_id=:id', array(':id' => $job_id))->fetchObject();
+
+  if (!$blastjob) {
+    return false;
+  }
+
   $tripal_job = tripal_get_job($job_id);
 
   $job = new stdClass();
@@ -329,8 +345,8 @@ function run_BLAST_tripal_job($program, $query, $database, $output_filestub, $op
  */
 function validate_fasta_sequence($type, $sequence) {
   //Includes IUPAC codes.
-  $fastaSeqRegEx = ($type == 'nucleotide') 
-                   ? '/^[ATCGNUKMBVSWDYRHatcgnukmbvswdyrh\s\n\r]*$/' 
+  $fastaSeqRegEx = ($type == 'nucleotide')
+                   ? '/^[ATCGNUKMBVSWDYRHatcgnukmbvswdyrh\[\/\]\s\n\r]*$/'
                    : '/^[ABCDEFGHIKLMNPQRSTUVWYZXabcdefghiklmnpqrstuvwyzx\*\-\s\n\r]*$/';
   $defRegEx      = '/^>.*(\\n|\\r)(.*)$/sm';
   if (preg_match($defRegEx, $sequence, $matches)) {
@@ -341,7 +357,7 @@ function validate_fasta_sequence($type, $sequence) {
   else if ($sequence != '' && preg_match($defRegEx, $sequence)) {
     return true;
   }
-  
+
   return false;
 }
 
@@ -404,23 +420,21 @@ function get_recent_blast_jobs($programs = array()) {
       $add = TRUE;
 
       $job_id = blast_ui_reveal_secret($job_secret);
-      $job = get_BLAST_job($job_id);
+      if ($job = get_BLAST_job($job_id)) {
 
-      // @TODO: Check that the results are still available.
-      // This is meant to replace the arbitrary only show jobs executed less than 48 hrs ago.
+        // @TODO: Check that the results are still available.
+        // This is meant to replace the arbitrary only show jobs executed less than 48 hrs ago.
 
-      // Remove jobs from the list that are not of the correct program.
-      if ($filter_jobs AND !in_array($job->program, $programs)) {
-        $add = FALSE;
-      }
+        // Remove jobs from the list that are not of the correct program.
+        if ($filter_jobs AND !in_array($job->program, $programs)) {
+          $add = FALSE;
+        }
 
-      if ($add) {
-
-        $job->query_summary = format_query_headers($job->files->query);
-
-        $jobs[] = $job;
+        if ($add) {
+          $job->query_summary = format_query_headers($job->files->query);
+          $jobs[] = $job;
+        }
       }
-
     }
 
     return $jobs;
@@ -745,7 +759,7 @@ function convert_tsv2gff3($blast_tsv,$blast_gff){
   $last_s = NULL;
   $hsp = NULL;
   $HitResult=array();
-  
+
   while(!feof($tsv)) {
     $line = fgets($tsv);
     $line = rtrim($line);
@@ -780,9 +794,9 @@ function convert_tsv2gff3($blast_tsv,$blast_gff){
     $qs = $parts[6];
     $qe = $parts[7];
     $e = $parts[10];
-     
 
-    // if this is a new hit print the last and 
+
+    // if this is a new hit print the last and
     // empty the $HitResult array and
     // reset hsp counter
     if ($last_s != NULL and $s != $last_s ) {
@@ -790,10 +804,10 @@ function convert_tsv2gff3($blast_tsv,$blast_gff){
       $HitResult = array();
       $hsp=0;
     }
-  
+
     // every line is a new hsp
     $hsp++;
-  
+
     // determine query strand to use in match_part line, no need to store, just print
     $q_strand = '+';
     if ($qs > $qe) {
@@ -808,12 +822,12 @@ function convert_tsv2gff3($blast_tsv,$blast_gff){
        list($start,$end) = array($se,$ss);
        $HitResult["$s,$q"]['strand']='-';
      }
-  
+
     // store smallest start
      if (!array_key_exists('SS',$HitResult["$s,$q"]) or $ss < $HitResult["$s,$q"]['SS']) {
        $HitResult["$s,$q"]['SS'] = $ss;
      }
-    
+
     // store largest end
      if (!array_key_exists('SE',$HitResult["$s,$q"]) or $se > $HitResult["$s,$q"]['SE']) {
        $HitResult["$s,$q"]['SE'] = $se;
@@ -822,8 +836,8 @@ function convert_tsv2gff3($blast_tsv,$blast_gff){
      // store best evalue
      if (!array_key_exists('E',$HitResult["$s,$q"]) or $e < $HitResult["$s,$q"]['E']) {
        $HitResult["$s,$q"]['E'] = $e;
-     }   
-    
+     }
+
      // generate the match_part line for each hsp
      $HitResult["$s,$q"]['HSPs'][] = join("\t", array($s, "BLASTRESULT" , "match_part" , $start , $end , $e , $HitResult["$s,$q"]['strand'] , '.' , "ID=$s.$q.$hsp;Parent=$s.$q;Target=$q $qs $qe $q_strand"));
      $last_s = $s;
@@ -847,7 +861,6 @@ function convert_tsv2gff3($blast_tsv,$blast_gff){
  *
  *
  */
-
 function printGFF_parent_children ($gff,$blast_feature_array){
   foreach ($blast_feature_array as $sq => $value ) {
     list ($s,$q) = preg_split('/,/' , $sq);
@@ -858,3 +871,75 @@ function printGFF_parent_children ($gff,$blast_feature_array){
     fwrite($gff,$child);
   }
 }
+
+/**
+ * Get text from cvitjs conf file, if possible.
+ *
+ * @param $genome_target
+ *   The section of the config to return. Should consist of "data."+[blastdb name].
+ *
+ * @return
+ *   A string containing the entire contents of the cvitjs configuration file. FALSE otherwise.
+ */
+function blast_ui_get_cvit_conf_text($genome_target = FALSE) {
+
+  // Retrieve the full path and filename of the conf.
+  $cvit_conf = blast_ui_get_cvit_conf();
+  if ($cvit_conf) {
+
+    // Retrieve the contents of the file.
+    $contents = file_get_contents($cvit_conf);
+
+    // If no genome target was provided then return the full file.
+    if ($contents && $genome_target == FALSE) {
+      return $contents;
+    }
+
+    // If a genome target was provided, then only return that section.
+    if ($genome_target) {
+      $section = array();
+      $in_section = FALSE;
+
+      // For each line of the configuration file...
+      $section_header = '['.$genome_target.']';
+      $lines = preg_split('/\r\n|\n|\r/', trim($contents));
+      foreach($lines as $l) {
+
+        // Are we in the section for this genome target?
+        if (trim($l) == $section_header) {
+          $in_section = TRUE; }
+
+        // Id so and we haven't fallen out of it through an empty line,
+        // then add it to saved section for returning.
+        if ($in_section) {
+          if (trim($l) == '') { break; }
+          $section[] = trim($l);
+        }
+      }
+
+      // If we found the section, then return it ;-).
+      if (!empty($section)) {
+        return implode("\n", $section);
+      }
+    }
+  }
+
+  return false;
+}
+
+
+/**
+ * Get path to cvitjs conf file.
+ *
+ * @return
+ *  The path to the CViTjs codebase.
+ */
+function blast_ui_get_cvit_conf($cvitjs_location = NULL) {
+  if (!$cvitjs_location) {
+    $cvitjs_location = libraries_get_path('cvitjs') . DIRECTORY_SEPARATOR;
+  }
+
+  $cvit_conf_path = $cvitjs_location . 'cvit.conf';
+
+  return $cvit_conf_path;
+}

+ 2 - 0
blast_ui.info

@@ -4,3 +4,5 @@ configure = admin/tripal/extension/tripal_blast/blast_ui
 project = tripal_blast
 package = Tripal Extensions
 core = 7.x
+
+dependencies[] = libraries

+ 54 - 4
blast_ui.install

@@ -17,6 +17,34 @@ function blast_ui_install() {
    tripal_create_files_dir('tripal_blast');
 }
 
+/**
+ * Implements hook_uninstall().
+ */
+function blast_ui_uninstall() {
+  // Remove all nodes of type blastdb
+  
+  $query = new EntityFieldQuery();
+  $query->entityCondition('entity_type', 'node')
+    // Restrict to BLASTDB nodes.
+    ->entityCondition('bundle', 'blastdb')
+    // Restrict to Published nodes.
+    ->propertyCondition('status', 1)
+    // Restrict to nodes the current user has permission to view.
+    ->addTag('node_access');
+  $entities = $query->execute();
+
+  // Get all BlastDB nodes and delete them
+  $nodes = node_load_multiple(array_keys($entities['node']));
+  foreach ($nodes as $node) {
+    print "Delete node " . $node->title . "\n";
+    $nrs = node_revision_list($node);
+    foreach ($nrs as $nr) {
+      node_revision_delete($nr->vid);
+    }
+    node_delete($node->nid);
+  }
+}
+
 /**
  * Implements hook_schema().
  * Create the blastdb database table for storing addditional info related to blastdb nodes.
@@ -24,9 +52,8 @@ function blast_ui_install() {
  * NOTE: This hook is called via Drupal magic during the installation process and no longer
  * needs to be called explicitly in hook_install().
  */
-function blast_ui_schema(){
-
-  // A table ot keep extra information related to blastdb nodes.
+function blast_ui_schema() {
+  // A table to keep extra information related to blastdb nodes.
   $schema['blastdb'] = array(
     'description' => t('The base table for blastdb node'),
     'fields' => array(
@@ -69,6 +96,12 @@ function blast_ui_schema(){
         'not null' => true,
         'default' => 'link'
       ),
+      'cvitjs_enabled' => array(
+        'description' => t('Indicate if CViTjs should be used to display hits on a whole genome'),
+        'type' => 'int',
+        'not null' => false,
+        'default' => 0
+      ),
     ),
     
     'indexes' => array(
@@ -247,4 +280,21 @@ function blast_ui_update_7103() {
   // First create the tables.
   db_create_table('blastjob', $schema['blastjob']);
   
-}
+}
+
+
+/**
+ * Add fields to blastp table for CViTjs support.
+ */
+function blast_ui_update_7104() {
+  db_add_field(
+    'blastdb',
+    'cvitjs_enabled',
+    array(
+      'description' => t('Indicate if CViTjs should be used to display hits on a whole genome'),
+      'type' => 'int',
+      'not null' => false,
+      'default' => 0
+    )
+  );
+}

+ 20 - 4
blast_ui.module

@@ -168,14 +168,14 @@ function blast_ui_theme() {
     'variables' => array('hsps' => NULL),
     'path' => "$path/theme",
   );
-  
+
   // Lists the recent blast jobs for a given user/session.
   $items['blast_recent_jobs'] = array(
     'template' => 'blast_recent_jobs',
     'variables' => array('programs' => NULL),
     'path' => "$path/theme",
   );
-  
+
   // Module Help
   $items['blast_help'] = array(
     'template' => 'blast_help',
@@ -210,6 +210,22 @@ function blast_ui_help($path, $arg) {
   }
 }
 
+/**
+ * Implements hook_libraries_info().
+ */
+function blast_ui_libraries_info() {
+
+  // Tell the libraries API about CViTjs
+  $libraries['cvitjs'] = array(
+    'name' => 'CViTjs',
+    'vendor url' => 'https://github.com/awilkey/cvitjs',
+    'version' => '0.0.1',
+    'download url' => 'https://github.com/awilkey/cvitjs/archive/master.zip',
+  );
+
+  return $libraries;
+}
+
 /**
  * Facilitate presenting the result of the blast search
  *
@@ -259,11 +275,11 @@ function show_blast_output($job_string) {
  * Enable web services API
  *
  * @param $owner
- *   
+ *
  * @param $api
  *
  * @return $result
- *  
+ *
  */
 function blast_ui_ctools_plugin_api($owner, $api) {
   if ($owner == 'services' && $api == 'services') {

+ 143 - 3
includes/blast_ui.admin.inc

@@ -31,7 +31,7 @@ function blast_ui_admin_form($form, $form_state) {
 
    $form['general']['eVal']= array(
     '#type' => 'textfield',
-    '#title' => t('Default e-Value (Expected Threshold)'),
+    '#title' => t('Default e-value (Expected Threshold)'),
     '#description' => t('Expected number of chance matches in a random model. This number should be give in a decimal format.'),
      '#default_value' => variable_get('eVal', 0.001),
     //'#default_value' => variable_get('blast_threads', 1),
@@ -151,6 +151,87 @@ KRSLEEGLKTTGEGLDWGVLFGFGPGLTIETVVLRSVAI';
     '#default_value' => variable_get('blast_ui_max_results_displayed', 500)
   );
 
+  // CVITJS
+  $cvitjs_enabled = variable_get('blast_ui_cvitjs_enabled', FALSE);
+  $description = 'The JavaScript program CViTjs enables users to see BLAST hits on an '
+               . 'entire genome assembly. See the help tab for information on how to '
+               . 'download and set up CViTjs.';
+
+  $form['cvitjs'] = array(
+    '#type' => 'fieldset',
+    '#collapsible' => true,
+    '#collapsed' => !$cvitjs_enabled,
+    '#title' => 'Enable and configure genome visualization',
+    '#description' => $description,
+  );
+
+  $absolute_cvitjs_data_path = DRUPAL_ROOT . '/sites/all/libraries/cvitjs/data';
+  $description = '<div class ="messages warning">CViTjs is only applicable for genome BLAST targets. After it is '
+               . 'enabled here, CViTjs will need to be enabled for each applicable BLAST '
+              . 'target node.</div>'
+              . '<div class="messages status"><strong>CViTjs Data Location: '.$absolute_cvitjs_data_path.'</strong>'
+              . '<br />The GFF3 and Genome Target-specific CViTjs configuration files should be located '
+              . 'at the above system path. Feel free to organize this directory further. '
+              . 'See the "Help" tab for more information.</div>';
+  $form['cvitjs']['explanation'] = array(
+    '#markup' => t($description),
+  );
+
+
+  $form['cvitjs']['cvitjs_enabled'] = array(
+    '#type' => 'checkbox',
+    '#title' => 'Enable CViTjs',
+    '#description' => 'When checked, CViTjs will be enabled.',
+    '#default_value' => $cvitjs_enabled,
+  );
+
+  // Get CViTjs confuration text, if possible.
+  if (!$default_value = blast_ui_get_cvit_conf_text()) {
+    $default_value = 'Unable to get CViTjs configuration information. '
+                   . 'You will need to enable CViTjs and set and save the '
+                   . 'path to CViTjs before you can edit the CViTjs configuration text.';
+    $disabled = true;
+  }
+  else {
+    $disabled = false;
+  }
+
+  $description = 'This is the contents of the file that defines data directories and '
+               . 'backbone GFF files for each genome assembly target. It is named '
+               . 'cvit.conf and is in the root directory for the CViTjs javascript code. '
+               . 'This is NOT the config file that is used to build the display for each '
+               . 'individual genome. See the help tab for more information about '
+               . 'configuration files.';
+  $form['cvitjs']['cvitjs_config'] = array(
+    '#type' => 'textarea',
+    '#title' => 'CViTjs configuration (empty until CViTjs path is saved)',
+    '#description' => $description,
+    '#default_value' => $default_value,
+    '#rows' => 10,
+    '#disabled' => $disabled,
+  );
+
+//eksc:
+  // WARNING
+  $description = 'This permits display of a temporary warning message at the top of the
+                  BLAST input form. Text can include HTML tags. Remember to remove the
+                  message when it is no longer relevant.';
+  $form['warning'] = array(
+    '#type' => 'fieldset',
+    '#collapsible' => true,
+    '#collapsed' => true,
+    '#title' => 'Show warning text',
+    '#description' => $description,
+  );
+    $form['warning']['warning_text'] = array(
+    '#type' => 'textarea',
+    '#title' => 'Text to be displayed',
+    '#description' => $description,
+    '#default_value' => variable_get('blast_ui_warning_text', ''),
+    '#rows' => 10,
+  );
+
+
   // SUBMIT
   $form['submit'] = array(
     '#type' => 'submit',
@@ -176,6 +257,46 @@ function blast_ui_admin_form_validate($form, &$form_state) {
     }
   }
 
+  // Check path to CViTjs executable and make sure cvit.conf is writable
+  if ($form_state['values']['cvitjs_enabled']) {
+    $cvit_path = blast_ui_get_cvit_conf();
+    if (!$cvit_path || !file_exists($cvit_path)) {
+      $msg = "The CViTjs configuration file, cvit.conf, does not exist at the path given ("
+           . $form_state['values']['cvitjs_location']
+           . "). Please check your path. "
+           . "If you have not yet downloaded CViTjs, see the help tab for more information.";
+      form_set_error('cvitjs_location', t($msg));
+    }
+
+    if (!is_writable($cvit_path)) {
+      $msg = "The file $cvit_path is not writable by this page. "
+           . "Please enable write access for apache then try saving these settings again.";
+      form_set_error('cvitjs_location', t($msg));
+    }
+  }
+
+  // Empty contents of cvitjs_config textarea if it is disabled
+  if ($form['cvitjs']['cvitjs_config']['#disabled']) {
+    $form_state['values']['cvitjs_config'] = '';
+  }
+
+  // Check CViTjs configuration text
+  if ($form_state['values']['cvitjs_config']
+        && !preg_match('/\[general\]\s*\ndata_default =.*/m',
+                       $form_state['values']['cvitjs_config'])) {
+    $msg = "The CViTjs configuration text looks incorrect. "
+         . "It should contain a [general] section. "
+         . "See the help tab for more information.";
+    form_set_error('cvitjs_config', t($msg));
+  }
+  if ($form_state['values']['cvitjs_config']
+        && !preg_match('/\[.*\]\s*\nconf = .*\ndefaultData =.*/m',
+                       $form_state['values']['cvitjs_config'])) {
+    $msg = "The CViTjs configuration text looks incorrect. "
+         . "It should contain one section for each genome target. "
+         . "See the help tab for more information.";
+    form_set_error('cvitjs_config', t($msg));
+  }
 }
 
 /**
@@ -196,7 +317,26 @@ function blast_ui_admin_form_submit($form, $form_state) {
   // Example sequence
   variable_set('blast_ui_nucleotide_example_sequence', $form_state['values']['nucleotide_example']);
   variable_set('blast_ui_protein_example_sequence', $form_state['values']['protein_example']);
-  
-/**: added by safetybrake*/
+
+  // Protect against large result sets
   variable_set('blast_ui_max_results_displayed', $form_state['values']['max_results_displayed']);
+
+  // Whole genome visualization - CViTjs
+  variable_set('blast_ui_cvitjs_enabled', $form_state['values']['cvitjs_enabled']);
+  if ($form_state['values']['cvitjs_enabled'] && $form_state['values']['cvitjs_config']) {
+    // Need absolute path to conf file to write
+    $cvit_conf_path = getcwd() . DIRECTORY_SEPARATOR
+                    . blast_ui_get_cvit_conf($form_state['values']['cvitjs_location']);
+    if ($fh = fopen($cvit_conf_path, 'w')) {
+      fwrite($fh, $form_state['values']['cvitjs_config']);
+      fclose($fh);
+    }
+    else {
+      drupal_set_message("Unable to open CViTjs conf file for writing: <pre>" . print_r(error_get_last(),true) . "</pre>");
+    }
+  }
+
+//eksc:
+  // Warning text
+  variable_set('blast_ui_warning_text', $form_state['values']['warning_text']);
 }

+ 0 - 3
includes/blast_ui.form_advanced_options.inc

@@ -643,8 +643,6 @@ function _get_default_values($options, $program) {
     ? $options['evalue'] : variable_get('eVal', 0.001);
   $word_size = (isset($options['word_size']))
     ? $options['word_size'] : 11;
-//  $qRange = (isset($options['culling_limit']))
-//    ? $options['culling_limit'] : variable_get('qRange', 0);
 
   // match/mismatch
   $matchmiss = 0;
@@ -717,7 +715,6 @@ function _get_default_values($options, $program) {
     'evalue' => $evalue,
     'matchmiss' => $matchmiss,
     'gap' => $gap,
-   // 'qRange' => $qRange,
     'matrix' => $matrix,
   );
 }//_get_default_values

+ 12 - 3
includes/blast_ui.form_per_program.inc

@@ -15,6 +15,15 @@
  */
 function blast_ui_per_blast_program_form($form, $form_state) {
 
+  // Add a warning, if need be (to be used for temporary messages like down-for-maintanence)
+  if ($warning = variable_get('blast_ui_warning_text', '')) {
+    $form['warning'] = array(
+      '#markup' => t($warning),
+      '#prefix' => '<div class="messages warning">',
+      '#suffix' => '</div>',
+    );
+  }
+
   // CSS support to the form
   $form['#attached']['css'] = array(
     drupal_get_path('module', 'blast_ui') . '/theme/css/form.css',
@@ -444,9 +453,9 @@ function blast_ui_per_blast_program_form_submit($form, &$form_state) {
       drupal_set_message(t('Unable to generate a BLAST database from your uploaded FASTA '
                           .'sequence. Please check that your file is a valid FASTA file '
                           .'and that if your sequence headers include pipes (i.e.: | ) '
-                          .' they adhere to ') 
-                          .l('NCBI standards.', 
-                             'http://www.ncbi.nlm.nih.gov/books/NBK21097/table/A632/?report=objectonly', 
+                          .' they adhere to ')
+                          .l('NCBI standards.',
+                             'http://www.ncbi.nlm.nih.gov/books/NBK21097/table/A632/?report=objectonly',
                              array('attributes' => array('target' => '_blank'))
                           ),
         'error'

+ 19 - 2
includes/blast_ui.linkouts.inc

@@ -152,10 +152,27 @@ function tripal_blast_generate_linkout_link($url_prefix, $hit, $info, $options =
 
   if (isset($hit->{'linkout_id'})) {
     $hit_url = $url_prefix . $hit->{'linkout_id'};
+    
+    // Split out the CGI params, if any
+    $params = array();
+    if (!$paramstr=strstr($hit_url, '?')) {
+      $url_prefix = $hit_url;
+    }
+    else {
+      $url_parts = preg_split("/\?/", $hit_url);
+      $url_prefix = $url_parts[0];
+      $param_list = preg_split("/\&/", $url_parts[1]);
+
+      foreach ($param_list as $param) {
+        $param_parts = preg_split("/=/", $param, 2);
+        $params[$param_parts[0]] = $param_parts[1];
+      }
+    }//URL contains CGI parameters
+    
     return l(
       $hit->{'linkout_id'},
-      $hit_url,
-      array('attributes' => array('target' => '_blank'))
+      $url_prefix,
+      array('attributes' => array('target' => '_blank'), 'query' => $params)
     );
   }
   else {

+ 80 - 20
includes/blast_ui.node.inc

@@ -67,7 +67,7 @@ function blastdb_form($node, &$form_state) {
   $form = array();
 
   $form['#validate'] = array('blastdb_form_validate');
-  
+
   $form['#attached']['css'] = array(
     drupal_get_path('module', 'blast_ui') . '/theme/css/form.css',
   );
@@ -106,7 +106,7 @@ function blastdb_form($node, &$form_state) {
   $form['dbxref'] = array(
     '#type' => 'fieldset',
     '#title' => 'Link-outs',
-    '#description' => 'These settings will be used to <em>transform the hit name into a 
+    '#description' => 'These settings will be used to <em>transform the hit name into a
       link to additional information</em>.',
     '#prefix' => '<div id="link-outs">',
     '#suffix' => '</div>',
@@ -122,16 +122,13 @@ function blastdb_form($node, &$form_state) {
   $form['dbxref']['dbxref_linkout_type'] = array(
     '#type' => 'radios',
     '#title' => 'Link-out Type',
-    '#description' => 'This determines how the URL to be linked to is formed. <strong>Make 
-      sure the database chosen supports this type of link</strong> (ie: the database 
+    '#description' => 'This determines how the URL to be linked to is formed. <strong>Make
+      sure the database chosen supports this type of link</strong> (ie: the database
       should point to a GBrowse instance if you choose GBrowse here).',
     '#options' => $options,
     '#default_value' => $linkout_type,
-    '#ajax' => array(
-      'callback' => 'ajax_blast_ui_node_linkout_custom_callback',
-      'wrapper' => 'link-outs',
-    )
   );
+
   // Add information about each format to the description.
   if ($linkout_type) {
     $form['dbxref']['dbxref_linkout_type']['#description'] .= '
@@ -232,7 +229,43 @@ function blastdb_form($node, &$form_state) {
       '#default_value' => (isset($node->linkout->db_id->db_id)) ? $node->linkout->db_id->db_id : 0
     );
   }
-    
+
+  // CViTjs settings, if enabled
+  if (variable_get('blast_ui_cvitjs_enabled', false)) {
+    $form['cvitjs'] = array(
+      '#type' => 'fieldset',
+      '#title' => 'Whole Genome Visualization',
+      '#description' => 'Settings for the display of BLAST hits on an entire genome assembly using CViTjs.',
+      '#prefix' => '<div id="cvitjs-settings">',
+      '#suffix' => '</div>',
+    );
+
+    $form['cvitjs']['cvitjs_enabled'] = array(
+      '#type' => 'checkbox',
+      '#title' => t('Show BLAST hits on the genome in the results page.'),
+      '#description' => t('Uses CViTjs to display BLAST hits on the entire genome'),
+      '#default_value' => (isset($node->cvitjs_enabled)) ? $node->cvitjs_enabled : false,
+    );
+    $cvitjs_msg_class = 'blastdb-extra-info';
+    $cvitjs_msg = 'Target Genome Configuration should be under <strong>[data.'.$node->db_name.']</strong> in the main cvit.conf.';
+
+    $conf_section = blast_ui_get_cvit_conf_text('data.'.$node->db_name);
+    if (!$conf_section) {
+      $cvitjs_msg_class .= ' messages warning';
+      $cvitjs_msg .= '<br /><br />There is no section for this genome target defined in the CViTjs
+        configuration file. <strong>No genome visualization will be shown until you define a
+        configuration section, "[data.'.$form_state['values']['db_name'].']", at '
+        .l('Admin > Tripal > Extensions > Tripal BLAST > BLAST UI', 'admin/tripal/extension/tripal_blast')
+        .'</strong>.';
+    }
+    else {
+      $cvitjs_msg .= '<br /><br /><strong>Current Configuration:</strong><pre>'.$conf_section.'</pre>';
+    }
+
+    $form['cvitjs']['cvitjs_enabled']['#description'] .= '<div class="'.$cvitjs_msg_class.'">'.$cvitjs_msg.'</p>';
+
+  }
+
   return $form;
 }
 
@@ -267,6 +300,19 @@ function blastdb_form_validate($form, $form_state) {
       );
     }
   }
+
+  // Check that there is a cvitjs section for the current
+  if ($form_state['values']['cvitjs_enabled']) {
+    $conf_section = blast_ui_get_cvit_conf_text('data.'.$form_state['values']['db_name']);
+    if (!$conf_section) {
+      drupal_set_message('There is no section for this genome target defined in the CViTjs
+        configuration file. <strong>No genome visualization will be shown until you define a
+        configuration section, "[data.'.$form_state['values']['db_name'].']", at '
+        .l('Admin > Tripal > Extensions > Tripal BLAST > BLAST UI', 'admin/tripal/extension/tripal_blast')
+        .'</strong>.',
+      'warning');
+    }
+  }
 }
 
 /**
@@ -284,7 +330,7 @@ function blastdb_insert($node) {
       $regex = $node->dbxref_id_type;
     }
   }
-  
+
   $db_id = 0;
   if (isset($node->db_id)) {
     $db_id = $node->db_id;
@@ -293,7 +339,11 @@ function blastdb_insert($node) {
   if (!$node->dbxref_linkout_type) {
     $node->dbxref_linkout_type = 'none';
   }
-  
+
+  if (!isset($node->cvitjs_enabled)) {
+    $node->cvitjs_enabled = 0;
+  }
+
   // Actually insert the record.
   db_insert('blastdb')->fields(array(
     'nid'                 => $node->nid,
@@ -303,6 +353,7 @@ function blastdb_insert($node) {
     'dbxref_id_regex'     => $regex,
     'dbxref_db_id'        => $db_id,
     'dbxref_linkout_type' => $node->dbxref_linkout_type,
+    'cvitjs_enabled'      => $node->cvitjs_enabled,
   ))->execute();
 }
 
@@ -331,16 +382,20 @@ function blastdb_update($node) {
       $regex = $node->dbxref_id_type;
     }
   }
-  
+
   $db_id = 0;
   if (isset($node->db_id)) {
     $db_id = $node->db_id;
   }
 
+  if (!$node->cvitjs_enabled) {
+    $node->cvitjs_enabled = 0;
+  }
+
   if (!$node->dbxref_linkout_type) {
     $node->dbxref_linkout_type = 'none';
   }
-  
+
   // Update the record.
   db_update('blastdb')->fields(array(
     'name'                => $node->db_name,
@@ -349,6 +404,7 @@ function blastdb_update($node) {
     'dbxref_id_regex'     => $regex,
     'dbxref_db_id'        => $db_id,
     'dbxref_linkout_type' => $node->dbxref_linkout_type,
+    'cvitjs_enabled'      => $node->cvitjs_enabled,
   ))->condition('nid', $node->nid)->execute();
 }
 
@@ -375,9 +431,9 @@ function blastdb_delete($node) {
 function blastdb_load($nodes) {
 
   $sql = "
-    SELECT nid, name, path, dbtype, dbxref_id_regex, dbxref_db_id, 
-           dbxref_linkout_type
-    FROM {blastdb} 
+    SELECT nid, name, path, dbtype, dbxref_id_regex, dbxref_db_id,
+           dbxref_linkout_type, cvitjs_enabled
+    FROM {blastdb}
     WHERE nid IN (:nids)";
   $result = db_query($sql, array(':nids' => array_keys($nodes)));
 
@@ -389,6 +445,9 @@ function blastdb_load($nodes) {
     $nodes[$record->nid]->title = $record->name;
     $nodes[$record->nid]->db_dbtype = $record->dbtype;
 
+    // CViTjs status
+    $nodes[$record->nid]->cvitjs_enabled  = $record->cvitjs_enabled;
+
     // Determine the type of link-out chosen.
     $types = module_invoke_all('blast_linkout_info');
     $type = NULL;
@@ -399,7 +458,7 @@ function blastdb_load($nodes) {
       tripal_report_error(
         'blast_ui',
         TRIPAL_ERROR,
-        'Unable to find details on the type of link-out choosen (%type). Have you defined hook_blast_linkout_info()? Make sure to clear the cache once you do so.',       
+        'Unable to find details on the type of link-out choosen (%type). Have you defined hook_blast_linkout_info()? Make sure to clear the cache once you do so.',
         array('%type' => $record->dbxref_linkout_type)
       );
     }
@@ -419,7 +478,7 @@ function blastdb_load($nodes) {
       }
     }
 
-    // finally add information related to link-outs to the node.
+    // Add information related to link-outs to the node.
     if ($add_linkout) {
       $nodes[$record->nid]->linkout = new stdClass();
 
@@ -440,7 +499,7 @@ function blastdb_load($nodes) {
       }
 
       // If the link-out type requires a db then provide one.
-      if ($type['require_db']) {
+      if (isset($type['require_db'])) {
         $nodes[$record->nid]->linkout->db_id = tripal_get_db(array('db_id' => $record->dbxref_db_id));
       }
       else {
@@ -452,7 +511,7 @@ function blastdb_load($nodes) {
       // Support complex link-outs.
       $nodes[$record->nid]->linkout->type = $record->dbxref_linkout_type;
       $nodes[$record->nid]->linkout->url_function = $type['process function'];
-   
+
     }
     // If there is no linkout then provide some defaults.
     else {
@@ -475,3 +534,4 @@ function blastdb_load($nodes) {
 function ajax_blast_ui_node_linkout_custom_callback($form, $form_state) {
   return $form['dbxref'];
 }
+

+ 109 - 33
theme/blast_help.tpl.php

@@ -17,6 +17,7 @@
 
 <p>
   <a href="#setup">Setup</a> | <a href="#function">Functionality</a>
+  | <a href="#protection">Large jobs | <a href="#genomeview">Genome visualization</a>
 </p>
 
 <a name="setup"></a>
@@ -24,32 +25,32 @@
 <h3><b>Setup Instructions</b></h3>
 <ol>
   <li>
-    Install NCBI BLAST+ on your server (Tested with 2.2.26+). There is a 
-    <a href="https://launchpad.net/ubuntu/+source/ncbi-blast+">package available 
-    for Ubuntu</a> to ease installation. Optionally you can set the path to your 
+    Install NCBI BLAST+ on your server (Tested with 2.2.26+). There is a
+    <a href="https://launchpad.net/ubuntu/+source/ncbi-blast+">package available
+    for Ubuntu</a> to ease installation. Optionally you can set the path to your
     BLAST executable <a href="<?php print url('admin/tripal/extension/tripal_blast/blast_ui');?>">
     in the settings</a>.
   </li>
   <li>
-    Optionally, create Tripal External Database References to allow you to link 
-    the records in your BLAST database to further information. To do this simply 
-    go to <a href="<?php print url('admin/tripal/chado/tripal_db/add'); ?>" target="_blank">Tripal> 
-    Chado Modules > Databases > Add DB</a> and make sure to fill in the Database 
-    prefix which will be concatenated with the record IDs in your BLAST database 
-    to determine the link-out to additional information. Note that a regular 
-    expression can be used when creating the BLAST database to indicate what the 
+    Optionally, create Tripal External Database References to allow you to link
+    the records in your BLAST database to further information. To do this simply
+    go to <a href="<?php print url('admin/tripal/chado/tripal_db/add'); ?>" target="_blank">Tripal>
+    Chado Modules > Databases > Add DB</a> and make sure to fill in the Database
+    prefix which will be concatenated with the record IDs in your BLAST database
+    to determine the link-out to additional information. Note that a regular
+    expression can be used when creating the BLAST database to indicate what the
     ID is.
   </li>
   <li>
-    <a href="<?php print url('node/add/blastdb');?>">Create "Blast Database" 
-    nodes</a> for each dataset you want to make available for your users to BLAST 
-    against. BLAST databases should first be created using the command-line 
-    <code>makeblastdb</code> program with the <code>-parse_seqids</code> flag.  
+    <a href="<?php print url('node/add/blastdb');?>">Create "BLAST Database"
+    nodes</a> for each dataset you want to make available for your users to BLAST
+    against. BLAST databases should first be created using the command-line
+    <code>makeblastdb</code> program with the <code>-parse_seqids</code> flag.
   </li>
   <li>
-    It's recommended that you also install the <a href="http://drupal.org/project/tripal_daemon">Tripal Job Daemon</a> 
-    to manage BLAST jobs and ensure they are run soon after being submitted by the 
-    user. Without this additional module, administrators will have to execute the 
+    It's recommended that you also install the <a href="http://drupal.org/project/tripal_daemon">Tripal Job Daemon</a>
+    to manage BLAST jobs and ensure they are run soon after being submitted by the
+    user. Without this additional module, administrators will have to execute the
     tripal jobs either manually or through use of cron jobs.
   </li>
 </ol>
@@ -58,50 +59,125 @@
 &mdash;
 <h3><b>Highlighted Functionality</b></h3>
 <ul>
-  <li>Supports <a href="<?php print url('blast/nucleotide/nucleotide');?>">blastn</a>, 
-    <a href="<?php print url('blast/nucleotide/protein');?>">blastx</a>, 
-    <a href="<?php print url('blast/protein/protein');?>">blastp</a> and 
+  <li>Supports <a href="<?php print url('blast/nucleotide/nucleotide');?>">blastn</a>,
+    <a href="<?php print url('blast/nucleotide/protein');?>">blastx</a>,
+    <a href="<?php print url('blast/protein/protein');?>">blastp</a> and
     <a href="<?php print url('blast/protein/nucleotide');?>">tblastx</a> with separate forms depending upon the database/query type.
   </li>
   <li>
-    Simple interface allowing users to paste or upload a query sequence and then 
-    select from available databases. Additionally, a FASTA file can be uploaded 
+    Simple interface allowing users to paste or upload a query sequence and then
+    select from available databases. Additionally, a FASTA file can be uploaded
     for use as a database to BLAST against (this functionality can be disabled).
   </li>
   <li>
-    Tabular Results listing with alignment information and multiple download 
+    Tabular Results listing with alignment information and multiple download
     formats (HTML, TSV, XML) available.
   </li>
   <li>
-    Completely integrated with <a href="<?php print url('admin/tripal/tripal_jobs');?>">Tripal Jobs</a> 
-    providing administrators with a way to track BLAST jobs and ensuring long 
+    Completely integrated with <a href="<?php print url('admin/tripal/tripal_jobs');?>">Tripal Jobs</a>
+    providing administrators with a way to track BLAST jobs and ensuring long
     running BLASTs will not cause page time-outs
   </li>
   <li>
-    BLAST databases are made available to the module by 
-    <a href="<?php print url('node/add/blastdb');?>">creating Drupal Pages</a> 
-    describing them. This allows administrators to 
+    BLAST databases are made available to the module by
+    <a href="<?php print url('node/add/blastdb');?>">creating Drupal Pages</a>
+    describing them. This allows administrators to
     <a href="<?php print url('admin/structure/types/manage/blastdb/fields');?>">use the Drupal Field API to add any information they want to these pages</a>.
   </li>
   <li>
-    BLAST database records can be linked to an external source with more 
+    BLAST database records can be linked to an external source with more
     information (ie: NCBI) per BLAST database.
   </li>
 </ul>
 
+<a name="protection"</a></a>
+&mdash;
 <h3><b>Protection Against Large Jobs</b></h3>
-Depending on the size and nature of your target databases, you may wish to constrain use 
+Depending on the size and nature of your target databases, you may wish to constrain use
 of this module.
 <ol>
   <li>Limit the number of results displayed via admin page. The recommended number is 500.</li>
   <li>
-    Limit the maximum upload file size in php settings. This is less useful because some 
+    Limit the maximum upload file size in php settings. This is less useful because some
     very large queries may be manageable, and others not.
   </li>
   <li>
-    Repeat-mask your targets, or provide repeat-masked versions. Note that some 
-    researchers may be looking for repeats, so this may limit the usefulness of the BLAST 
+    Repeat-mask your targets, or provide repeat-masked versions. Note that some
+    researchers may be looking for repeats, so this may limit the usefulness of the BLAST
     service.
   </li>
 </ol>
 
+<a name="genomeview"></a>
+&mdash;
+<h3><b>Whole Genome Visualization</b></h3>
+This module can be configured to use
+<a href="https://github.com/LegumeFederation/cvitjs">CViTjs</a> to display BLAST hits on
+a genome image.
+
+<h4>CViTjs Setup</h4>
+<ol>
+  <li>
+    <a href="https://github.com/LegumeFederation/cvitjs">Download CViTjs</a> and copy
+    the code to your webserver. It needs to be placed in <code>[your drupal root]/sites/all/libraries</code>. To download, execute
+    the git command inside the <code>libraries/</code> directory:<br>
+    <code>git clone https://github.com/LegumeFederation/cvitjs.git</code>
+  </li>
+  <li>
+    CViTjs will have a config file in its root directory named cvit.conf. This file
+    provides information for whole genome visualization for each genome BLAST target.
+    <b>Make sure the config file can be edited by your web server.</b>
+  </li>
+  <li>
+    Enable CViTjs from the BLAST module administration page.
+  </li>
+  <li>
+    Edit the configuration file to define each genome target. These will look like:
+    <pre>
+[data.Cajanus cajan - genome]
+conf = data/cajca/cajca.conf
+defaultData = data/cajca/cajca.gff</pre>
+    Where:<br>
+    <ul>
+      <li>the section name, "data.Cajanus cajan - genome", consists of "data." followed
+          by the name of the BLAST target node,</li>
+      <li>the file "cajca.conf" is a cvit configuration file which describes how to draw the
+          chromosomes and BLAST hits on the <i>Cajanus cajan</i> genome,</li>
+      <li>and the file "cajca.gff" is a GFF3 file that describes the <i>Cajanus cajan</i>
+          chromosomes.</li>
+    </ul>
+    At the top of the configuration file there must be a [general] section that defines
+    the default data set. For example:
+    <pre>
+[general]
+data_default = data.Cajanus cajan - genome</pre>
+  </li>
+  <li>
+    Edit the nodes for each genome target (nodes of type "BLAST Database") and enable whole
+    genome visualization. Remember that the names listed in the CViTjs config file must
+    match the BLAST node name. In the example above, the BLAST database node for the
+    <i>Cajanus cajan</i> genome assembly is named "Cajanus cajan - genome"
+  </li>
+</ol>
+
+<h4>Notes</h4>
+<ul>
+<li>The .conf file for each genome can be modified to suit your needs and tastes. See the
+  sample configuration file, <code>data/test1/test1.conf</code>, and the CViTjs
+  <a href="https://github.com/LegumeFederation/cvitjs#using-cvitjs">documentation</a>.</li>
+<li>Each blast target CViTjs configuration file must define how to visualize blast hits or you will not see them.
+  <pre>[blast]
+feature = BLASTRESULT:match_part
+glyph   = position
+shape = rect
+color   = #FF00FF
+width = 5</pre></li>
+<li>You will have to put the target-specific conf and gff files (e.g. cajca.conf and
+  cjca.gff) on your web server, in the directory, <code>sites/all/libraries/cvitjs/data</code>. You may
+  choose to group files for each genome into subdirectories, for example,
+  <code>sites/all/libraries/cvitjs/data/cajca</code>.</li>
+<li>It is important to make sure that cvit.conf points to the correct data directory and the
+  correct .gff and .conf files for the genome in question. For more information about how to
+  create the .gff file, see the
+  <a href="https://github.com/LegumeFederation/cvitjs#how-to">documentation</a>.</li>
+</ul>

+ 22 - 12
theme/blast_report.tpl.php

@@ -62,7 +62,6 @@ $no_hits = TRUE;
 
 <div class="blast-report">
 
-  <div class="blast-job-info">
     <!-- Provide Information to the user about their blast job -->
     <div class="blast-job-info">
       <div class="blast-download-info"><strong>Download</strong>:
@@ -72,13 +71,13 @@ $no_hits = TRUE;
         <a href="<?php print '../../' . $blast_job->files->result->gff; ?>">GFF3</a>
       </div>
       <br />
-      <div class="blast-query-info"><strong>Query Information</strong>: 
+      <div class="blast-query-info"><strong>Query Information</strong>:
         <?php print $blast_job->files->query;?></div>
-      <div class="blast-target-info"><strong>Search Target</strong>: 
+      <div class="blast-target-info"><strong>Search Target</strong>:
         <?php print $blast_job->blastdb->db_name;?></div>
-      <div class="blast-date-info"><strong>Submission Date</strong>: 
+      <div class="blast-date-info"><strong>Submission Date</strong>:
         <?php print format_date($blast_job->date_submitted, 'medium');?></div>
-      <div class="blast-cmd-info"><strong>BLAST Command executed</strong>: 
+      <div class="blast-cmd-info"><strong>BLAST Command executed</strong>:
         <?php print $blast_job->blast_cmd;?></div>
       <br />
       <div class="num-results">
@@ -86,12 +85,19 @@ $no_hits = TRUE;
       </div>
     </div>
 
-    <br />
-    <div class="num-results">
-      <strong>Number of Results</strong>: <?php print $num_results; ?>
-    </div>
+    <?php
+      if ($show_cvit_diagram) {
+    ?>
+      <!-- CViTjs image of BLAST hits, if enabled -->
+      <div class="cvitjs">
+        <div id="title-div"><h2>Whole Genome Visualization of BLAST hits</h2></div>
+        <div id="cvit-div"></div>
+      </div>
+
+    <?php
+      }
+    ?>
 
-  </div>
   <br />
 
   <div class="report-table">
@@ -104,6 +110,8 @@ $no_hits = TRUE;
     if ($xml) {
     ?>
 
+    <h2>Resulting BLAST hits</h2>
+
     <p>The following table summarizes the results of your BLAST.
     Click on a <em>triangle </em> on the left to see the alignment and a visualization of the hit,
     and click the <em>target name </em> to get more information about the target hit.</p>
@@ -149,8 +157,8 @@ $no_hits = TRUE;
               // If the id is of the form gnl|BL_ORD_ID|### then the parseids flag
               // to makeblastdb did a really poor job. In thhis case we want to use
               // the def to provide the original FASTA header.
-              // @todo Deepak changed this to use just the hit_def; inquire as to why.
               $hit_name = (preg_match('/BL_ORD_ID/', $hit->{'Hit_id'})) ? $hit->{'Hit_def'} : $hit->{'Hit_id'};
+
               // Used for the hit visualization to ensure the name isn't truncated.
               $hit_name_short = (preg_match('/^([^\s]+)/', $hit_name, $matches)) ? $matches[1] : $hit_name;
 
@@ -212,7 +220,7 @@ $no_hits = TRUE;
                               ';';
                 $Hsp_bit_score .=   $hsp_xml->{'Hsp_bit-score'} .';';
               }
-              
+
               // Finally record the range.
               // @todo figure out why we arbitrarily subtract 50,000 here...
               // @more removing the 50,000 and using track start/end appears to cause no change...
@@ -251,6 +259,7 @@ $no_hits = TRUE;
                 // First extract the linkout text using the regex provided through
                 // the Tripal blast database node.
                 if (preg_match($linkout_regex, $hit_name, $linkout_match)) {
+
                   $hit->{'linkout_id'} = $linkout_match[1];
                   $hit->{'hit_name'} = $hit_name;
 
@@ -266,6 +275,7 @@ $no_hits = TRUE;
                       'e-value'    => $evalue,
                       'HSPs'       => $HSPs,
                       'Target'     => $blast_job->blastdb->db_name,
+                      'RegEx'      => $linkout_regex,
                     )
                   );
                 }

+ 29 - 2
theme/blast_ui.theme.inc

@@ -30,6 +30,33 @@ function blast_ui_preprocess_show_blast_report(&$vars) {
       $vars['blast_job']->blast_cmd .= ' -' . $key. ' ' . $value ;
   }
 
+  // CViTjs
+  $vars['show_cvit_diagram'] = FALSE;
+  if (variable_get('blast_ui_cvitjs_enabled', false)
+    && isset($vars['blast_job']->blastdb->cvitjs_enabled)
+    && $vars['blast_job']->blastdb->cvitjs_enabled == '1') {
+
+    // Set a clean var so we don't have to do this long check again ;-).
+    $vars['show_cvit_diagram'] = TRUE;
+
+    // Add the CSS/JS.
+    $cvitjs_lib_path = libraries_get_path('cvitjs') . DIRECTORY_SEPARATOR;
+    drupal_add_css($cvitjs_lib_path . 'js/lib/bootstrap_embed/css/bootstrap.min.css',array('preprocess'=>FALSE));
+    drupal_add_css($cvitjs_lib_path . 'js/lib/hopscotch/css/hopscotch.min.css',array('preprocess'=>FALSE));
+    drupal_add_css($cvitjs_lib_path . 'css/cvit.css',array('preprocess'=> FALSE));
+    drupal_add_js($cvitjs_lib_path . 'js/lib/require/require.js',array('group'=>'JS_LIBRARY','type'=>'file'));
+    drupal_add_js($cvitjs_lib_path . 'js/lib/require/blast_ui-config.js',array('group'=>'JS_THEME'));
+
+    // Add the JS settings.
+    global $base_url;
+    drupal_add_js(array('blast_ui'=> array(
+            'dataset' => $vars['blast_job']->blastdb->db_name,
+            'gff' => $base_url . '/' . $vars['blast_job']->files->result->gff
+      )),
+      'setting'
+    );
+  }
+
   // Determine the URL of the blast form.
   $vars['blast_form_url'] = 'blast/nucleotide/nucleotide';
   switch($vars['blast_job']->program) {
@@ -129,7 +156,7 @@ function blast_ui_reveal_secret($secret) {
   // Check that the job_id exists if it is an integer.
   if (is_numeric($job_id)) {
 
-    $exists = db_query('SELECT job_id FROM {tripal_jobs} WHERE job_id=:id', 
+    $exists = db_query('SELECT job_id FROM {tripal_jobs} WHERE job_id=:id',
                        array(':id' => $job_id))->fetchField();
     if (!$exists) {
       tripal_report_error(
@@ -148,7 +175,7 @@ function blast_ui_reveal_secret($secret) {
 
     $job_id = base64_decode($secret);
     if (is_numeric($job_id)) {
-      $exists = db_query('SELECT job_id FROM {tripal_jobs} WHERE job_id=:id', 
+      $exists = db_query('SELECT job_id FROM {tripal_jobs} WHERE job_id=:id',
                          array(':id' => $job_id))->fetchField();
       if (!$exists) {
         tripal_report_error(

+ 23 - 0
theme/css/blast_report.css

@@ -68,3 +68,26 @@ table#blast_report div.alignment-row{
 table#blast_report div.alignment-subrow{
   padding-bottom: 15px;
 }
+
+/* CViTjs support */
+.blast-top:after {
+   clear: both;
+   display: table;
+   content: "";
+}
+.blast-job-info {
+  float: left;
+  margin-bottom: 25px;
+}
+.cvitjs {
+  float: left;
+  margin-top: 10px;
+  margin-bottom: 25px;
+}
+.cvitjs #cvit-div{
+  padding: 5px 0 0 0;
+}
+.report-table {
+  clear: both;
+  position: static;
+}

+ 2 - 2
theme/css/form.css

@@ -2,10 +2,10 @@ div.center {
   margin-left: auto;
   margin-right: auto;
   width:70%
-} 
+}
 
 .blastdb-extra-info {
   padding: 10px;
   border: 1px solid #be7;
   background-color: #f8fff0;
-}
+}

+ 23 - 0
theme/node--blastdb.tpl.php

@@ -105,8 +105,31 @@
       <tr><th>RegEx</th><td><?php print $node->linkout->regex; ?></td></tr>
       <tr><th>Link-out Type</th><td><?php print $node->linkout->type; ?></td></tr>
 <?php } ?>
+      <tr><th>Whole Genome Viewer</th><td><?php print ($node->cvitjs_enabled) ? 'Enabled' : 'Disabled'; ?></td></tr>
     </table>
 
+
+    <?php
+      if ($node->cvitjs_enabled) {
+
+        print '<h3>Whole Genome Viewer</h3>';
+
+        $conf_section = blast_ui_get_cvit_conf_text('data.'.$node->db_name);
+
+        if (!$conf_section) {
+
+          print '<div class="messages warning">There is no section for this genome target defined in the CViTjs
+            configuration file. <strong>No genome visualization will be shown until you define a
+            configuration section, "[data.'.$form_state['values']['db_name'].']", at '
+            .l('Admin > Tripal > Extensions > Tripal BLAST > BLAST UI', 'admin/tripal/extension/tripal_blast')
+            .'</strong>.</div>';
+        }
+        else {
+          print '<h4>Configuration</h4>'
+            . '<pre>'.$conf_section.'</pre>';
+        }
+    }
+    ?>
     <?php
       // Add in any remaining content
       print render($content);