Fixed bugs:
authorJose Reyero
Sun, 14 May 2006 18:13:50 +0000 (18:13 +0000)
committerJose Reyero
Sun, 14 May 2006 18:13:50 +0000 (18:13 +0000)
- http://drupal.org/node/62799
- http://drupal.org/node/62330
- http://drupal.org/node/62477
Reworked selection modes and rewriting
Improved edition/translation nodes

README.txt
i18n.inc
i18n.module
translation.module

index 8016367..9f2feb8 100644 (file)
@@ -2,7 +2,7 @@ README.txt
 ==========
 
 ********************************************************************
-  This is i18n package, cvs version , and works with Drupal HEAD
+This is i18n package, cvs version , and works with Drupal HEAD
 ********************************************************************
 WARNING: It is not 100% backwards compatible with the old i18n module [4.5.x] 
 WARNING: DO READ THE INSTALL FILE
@@ -12,42 +12,24 @@ This is not a single module anymore but a collection of modules providing comple
   translation --> module to add translation relationships
   
 ********************************************************************
-This module implements multilingual support as outlined in http://drupal.org/node/11051
-Some more info about this module will be available here: 
-    http://www.developmentseed.org/blog/internationalization
-       http://reyero.net/en/drupal/i18n
-
-It doesn't require anymore multiple language tables as previous versions
-
-This module provides support for multilingual Drupal sites:
+These modules provide support for multilingual Drupal sites:
     * Multilingual content, some basic translation interface, and links between translated versions
     * Translation of the user interface for registered and anonymous users (with locale)
     * Detection of the brower language
     * Keeps the language settings accross consecutive requests using URL rewriting.
-    * Provides a block for language selection and two theme functions: i18n_flags and i18n_links
-
-To have a language selector on your page, you can use the block provided or these theme functions:
-
- theme("i18n_flags") -> Adds just a row with the flags
- theme("i18n_links",$flags,$names,$delim1,$delim2) -> Check documentation in the code for different options
-
+    * Provides a block for language switching -i18n.module- and one for translations -translation.module-
 Multilingual content:
 =====================
 Multilingual content means providing content translated to different languages or language specific content, which is not the same as interface translation. Interface translation is done through Drupal's localization system. 
 This module supports:
   - Multilingual nodes
   - Multilingual taxonomy vocabularies and terms
-  - Basic translation management for nodes and terms
+  - Translations for nodes and terms
 
 When you navigate the site using multiple languages, the pages will just show terms and nodes for the chosen language plus the ones that haven't a definde language. 
 When editing a node, you must click on 'Preview' after changing language for the right vocabularies and terms to be shown.
 
-The multi language support is expected to work for all node types, and node listings in Drupal 4.6!!
-
-So far, I have not found incompatibilities with any other module. Please, let me know if you find any.
-
-And yes, flexinode works with multiple languages :-)
+The multi language support is expected to work for all node types, and node listings
 
 Taxonomy translation:
 ====================
@@ -57,20 +39,20 @@ You can create vocabularies and terms with or without language.
 - When editing nodes, if you change the language for a node, you have to click on 'Preview' to have the right vocabularies/terms for that language. Otherwise, the language/taxonomy data for that node could be inconsistent.
   
 About URL aliasing with language codes -requires path module
-====================================
+============================================================
 Incoming URL's are now translated following these steps:
 1. First, a translation is searched for path with language code: 'en/mypage'
 2. If not found, language code is removed, and path translation is searched again: 'mypage'
-Thus, you can define aliases with or without language codes in them
 
-The 'Front page: Language dependent' option means that when the request is for the front page '/', a language prefix will be added before doing the path translation, and then -> step 1 above
+Thus, you can define aliases with or without language codes in them.
+
 This language code will be taken from browser if enabled 'Browser language detection, or will be the default otherwise.
 
 To have aliases for a translated node/page, you have to define each of them. I.e.:
   en/mycustompath -> node/34 (which is suppossed to be the english version)
   es/mycustompath -> node/35 (which should be the spanish version)
 
-For outgoing URL's, the language code will be added authomatically.
+For outgoing URL's, the language code will be added automatically.
 
 About language dependent variables:
 ==================================
@@ -84,18 +66,18 @@ Language dependent tables are not needed anymore for multilingual content.
 This is kept for backwards compatibility, experimentation and may be some use in the future.
 * This can be used to have per-language data for modules not language-aware, like language statistics... you can experiment...
 
-Known problems, compatibility
-=============================
-- Taxonomy patch not compatible with taxonomy_access patch. See http://drupal.org/node/22834
+Known problems, compatibility issues
+====================================
+These modules should be compatible with all Drupal core modules.
 
 Sample sites, using this module - e-mail me to be listed here
 ==========================================================
   http://www.reyero.net
   http://www.para.ro
   http://www.ctac.ca
-  http://grasshopperarts.com/
-  http://funkycode.com/
-  http://www.newoceans.nl/
+  http://grasshopperarts.com
+  http://funkycode.com
+  http://www.newoceans.nl
 
 Additional Support
 =================
index 6345073..f1451e7 100644 (file)
--- a/i18n.inc
+++ b/i18n.inc
@@ -37,99 +37,58 @@ function i18n_url_rewrite($type, $path, $original){
  */
 function i18n_db_rewrite_sql($query, $primary_table, $primary_key){
   // Some exceptions for query rewrites
-  if(strstr(request_uri(),'cron.php')) return;
-
-  $alias = $primary_table;
-
-  switch ($alias) {
+  $mode = i18n_selection_mode();
+  // drupal_set_message("i18n_db_rewrite mode=$mode query=$query");
+  if($mode == 'off') return;
+  
+  switch ($primary_table) {
     case 'n':
-      $result = i18n_db_node_rewrite($query, $primary_table, $primary_key);
-      break;
+      // Node queries
+      return i18n_db_node_rewrite($query, $primary_table, $primary_key, $mode);
     case 't':
     case 'v':
-      $result = i18n_db_taxonomy_rewrite($query, $primary_table, $primary_key);
-      break;
+      // Taxonomy queries
+      return i18n_db_taxonomy_rewrite($query, $primary_table, $primary_key, $mode);
   }
-
-  return $result;
 }
 
-function i18n_db_node_rewrite($query, $primary_table, $primary_key){
-  $alias = $primary_table;
+function i18n_db_node_rewrite($query, $primary_table, $primary_key, $mode){
   // When loading specific nodes, language conditions shouldn't apply
   // TO-DO: Refine this regexp  
-  if (preg_match("/WHERE.*$alias.nid\s*=\s*(\d|%d)/", $query)) return;
-  //drupal_set_message($query);
-  $mode = i18n_selection_mode();
-  if($mode == 'off') return;
+  if (preg_match("/WHERE.*$primary_table.nid\s*=\s*(\d|%d)/", $query)) return;
   
-  $result['join'] = "LEFT JOIN {i18n_node} i18n ON $alias.nid = i18n.nid";
-  $alias = 'i18n';
-
-  switch($mode){
-    case 'simple':
-      $result['where'] = "$alias.language ='".i18n_get_lang()."' OR $alias.language IS NULL" ;
-      break;
-    case 'mixed':
-      $result['where'] = "$alias.language ='".i18n_get_lang()."' OR $alias.language ='".i18n_default_language()."' OR $alias.language IS NULL" ;
-      break;
-    case 'strict':
-      $result['where'] = "$alias.language ='".i18n_get_lang()."'" ;
-      break;
-    case 'default':
-      $result['where'] = "$alias.language ='".i18n_default_language()."' OR $alias.language IS NULL" ;
-      break;
-  }
+  $result['join'] = "LEFT JOIN {i18n_node} i18n ON $primary_table.nid = i18n.nid";
+  $result['where'] = i18n_db_rewrite_where('i18n', $mode);
   
   return $result;
 }
 
-function i18n_db_taxonomy_rewrite($query, $primary_table, $primary_key){
+function i18n_db_taxonomy_rewrite($query, $primary_table, $primary_key, $mode){
   // When loading specific terms, vocabs, language conditions shouldn't apply
   // TO-DO: Refine this regexp  
   if (preg_match("/WHERE.* $primary_table\.tid\s*(=\s*\d|IN)/", $query)) return;
   
-  // Decide language depending on what we are doing
-  $lang = i18n_get_lang(); // Default
-  switch(arg(0)) {
+  $result['where'] = i18n_db_rewrite_where($primary_table, $mode);
+  return $result;
+}
+
+function i18n_db_rewrite_where($alias, $mode){
+  switch($mode){
+    case 'simple':
+      return "$alias.language ='".i18n_get_lang()."' OR $alias.language =''" ;
+    case 'mixed':
+      return "$alias.language ='".i18n_get_lang()."' OR $alias.language ='".i18n_default_language()."' OR $alias.language =''" ;
+    case 'strict':
+      return "$alias.language ='".i18n_get_lang()."'" ;
     case 'node':
-           $edit = $_POST['edit'];
-           if( arg(1) == 'add'){
-             // Adding node
-             $lang = isset($edit['language']) ? $edit['language'] : i18n_get_lang();
-           } elseif( is_numeric(arg(1)) && arg(2) == 'edit') {
-             // Editing a node
-             if(is_array($edit)) {
-               $lang = isset($edit['language']) ? $edit['language'] : i18n_get_lang();
-             } else {
-               $lang = i18n_node_get_lang(arg(1), i18n_get_lang());
-             }
-           } else {
-             $lang = i18n_get_lang();
-           }
-           break;
     case 'translation':
-      $edit = $_POST['edit'];
-      $lang = isset($edit['language']) ? $edit['language'] : arg(3);
-      break;
-    case 'admin': 
-                 if(arg(1) == 'taxonomy') {
-                   // Taxonomy administration. Show all
-                   $lang = NULL;
-                 }
-    /*
-    case 'taxonomy':
-      if(arg(1) == 'term'){
-        $lang = NULL;
-      }
-      */
-  }
-  
-  if($lang) {
-    $alias = $primary_table;
-    $result['where'] = "$alias.language ='$lang' OR $alias.language = ''";
-    return $result;
-  }
+      return "$alias.language ='".i18n_selection_mode('params')."' OR $alias.language =''" ;
+    case 'default':
+      return "$alias.language ='".i18n_default_language()."' OR $alias.language =''" ;
+    case 'custom':
+      return str_replace('%alias',$alias, i18n_selection_mode('params'));
+  }  
 }
 
 /**
@@ -194,13 +153,23 @@ function i18n_form_alter($form_id, &$form) {
              // Correction for lang/node/nid aliases generated by path module
                                // if($form['#node']->path && $form['#node']->path == i18n_get_lang().'/node/'.$form['#node']->nid){
              if($form['#node']->path) {
-               $alias=drupal_lookup_path('alias', 'node/'.$form['#node']->nid);
+               $alias = drupal_lookup_path('alias', 'node/'.$form['#node']->nid);
                if($alias && $alias != 'node/'.$form['#node']->nid){
                  $form['#node']->path = $alias;
                } else {
                  unset($form['#node']->path);
                }
              }
+        // Some language values for node forms
+        // To-do: addapt for translations too
+        /*
+        if($language && $form['#node']->type == 'book') {
+          i18n_selection_mode('custom', "%alias.language ='$language' OR %alias.language IS NULL" );
+          $form['parent']['#options'] = book_toc($form['#node']->nid);
+          i18n_selection_mode('reset');
+        }
+        */
+
          }
     
   }    
@@ -286,18 +255,23 @@ function i18n_get_lang() {
 }
 
 /**
- * Produces i18n paths
+ * Produces i18n paths, with language prefix
  * If path is empty or site frontpage, path = 'lang'
- * Search for alias before adding language
+ * Check for frontpage and search for alias before adding language
  */
 function i18n_path($path, $lang) {
-  if (!$path || $path == variable_get('site_frontpage', 'node')) {
+  if (!$path || $path == i18n_frontpage($lang)) {
     return $lang;
-  } elseif($alias = drupal_lookup_path('alias', $path) ) {
-    return $lang.'/'.$alias;
-  } else {
-    return $lang.'/'.$path;
-  }
+  } elseif($alias = drupal_lookup_path('alias', $path)) {
+         if($prefix = i18n_get_lang_prefix($alias)) {
+      // This alias will be valid only if it has the same language
+           return ($prefix == $lang) ? $alias : $lang.'/'.$path;
+         } else { // Alias without language prefix
+           return $lang.'/'.$alias;
+         }
+  } else { // Alias for language path will be searched later
+    return $lang.'/'.$path;  
+  } 
 }
 
 function i18n_node_get_lang($nid, $default = '') {
@@ -327,7 +301,6 @@ function i18n_block($op = 'list', $delta = 0) {
     $blocks['subject'] = t('Languages');
     $blocks['content'] = theme('item_list', i18n_get_links($_GET['q']));
   }
-
   return $blocks;
 }
 
@@ -337,6 +310,9 @@ function i18n_block($op = 'list', $delta = 0) {
  * Returns an array of links for all languages, with or without names/flags
  */
 function i18n_get_links($path = '') {
+  if($path == i18n_frontpage()) {
+    $path = '';
+  }
   foreach(i18n_supported_languages() as $lang => $name){
     $links[$lang]= theme('i18n_link', $name, i18n_path($path, $lang), $lang);
   }
index 8488569..b553959 100644 (file)
@@ -24,11 +24,12 @@ function i18n_init(){
   $path = _i18n_get_original_path();
   $i18n_langpath = i18n_get_lang_prefix($path);
   $lang = _i18n_get_lang();
+  
+  // Init selection mode
+  i18n_selection_mode(variable_get('i18n_selection_mode', 'simple'));
   // Multi tables, for backwards compatibility and experimentation
-  global $db_prefix_i18n;
-  if (is_array($db_prefix_i18n)) {
-    _i18n_set_db_prefix($lang);
-  }
+  _i18n_set_db_prefix($lang);
+
   if ($path == '') { // Main page
     // Check for update or cron scripts to disable rewriting and redirection
     if(preg_match('|/(?!index\.php)\w+\.php|', request_uri())){
@@ -36,16 +37,16 @@ function i18n_init(){
     } elseif( variable_get('cache',0) && $lang != i18n_default_language() ) {
       // Redirect to main page in $lang
       _i18n_goto($lang);
-    } elseif (variable_get('i18n_frontpage',0)){
-      $_GET['q'] = i18n_frontpage();
+    } else {
+      $_GET['q'] = i18n_frontpage($lang);
     } 
   } elseif ($lang == $path) { // When path is only language code
-    $_GET['q'] =  variable_get('i18n_frontpage',0) ? i18n_frontpage() : variable_get('site_frontpage','node'); 
+    $_GET['q'] = i18n_frontpage($lang); 
   }
   elseif ($i18n_langpath) {
     //search alias with and without lang and remove lang.
     $_GET['q'] = i18n_get_normal_path($path);
-  } 
+  }
   // If not in bootstrap, include hooks
   if(!_i18n_is_bootstrap()){
     include drupal_get_path('module', 'i18n').'/i18n.inc';
@@ -77,6 +78,29 @@ function i18n_help($section = 'admin/help#i18n' ) {
 }
 
 /**
+ * Implementation of hook_menu().
+ * Modify rewriting conditions when viewing specific nodes
+ */
+function i18n_menu($may_cache) {
+  $items = array();
+  if (!$may_cache) {
+    if (arg(0) == 'node') {
+      if(isset($_POST['edit']['language']) && $_POST['edit']['language']) {
+        $language = $_POST['edit']['language'];
+      } elseif( is_numeric(arg(1)) && $node = node_load(arg(1)) ) {
+        // Node language when loading specific nodes
+        $language = $node->language;
+      }
+      if($language) i18n_selection_mode('node', db_escape_string($language));
+    } elseif(arg(0) == 'admin') {
+      // No restrictions for administration pages
+      i18n_selection_mode('off');
+    }
+  }
+
+  return $items;
+}
+/**
  * Implementation of hook_settings().
  * 
  * Some options have been removed from previous versions:
@@ -176,7 +200,7 @@ function i18n_default_language(){
 }
 
 /**
- * Get language from browser settings, but only if it is in the $i18n_languages array
+ * Get language from browser settings, but only if it is a valid language
  */
 function i18n_get_browser_lang() {
   $languages = i18n_supported_languages();
@@ -184,7 +208,7 @@ function i18n_get_browser_lang() {
   $accept=explode(',',array_shift($exploded_server));
   foreach ($accept as $lang) {
     $lang=substr($lang,0,2);
-    if ( !empty($lang) && array_key_exists($lang,$languages)) {
+    if ( !empty($lang) && array_key_exists($lang, $languages)) {
       return $lang;
     }
   }
@@ -194,7 +218,7 @@ function i18n_get_browser_lang() {
  * Get language code from path.
  *
  * @param $path
- * @param $trim true to remove language code from $path
+ * @param $trim = TRUE to remove language code from $path
  */
 function i18n_get_lang_prefix(&$path, $trim = FALSE) {
   $exploded_path = explode('/', $path);
@@ -210,10 +234,11 @@ function i18n_get_lang_prefix(&$path, $trim = FALSE) {
 
 /**
  * Language dependent front page
+ * This function will search for aliases like 'en/home', 'es/home'...
  */
-function i18n_frontpage() {
-  $path = _i18n_get_lang().'/'.variable_get('site_frontpage','node');
-  return i18n_get_normal_path($path);
+function i18n_frontpage($lang = NULL) {
+  $lang = $lang ? $lang : _i18n_get_lang();
+  return i18n_get_normal_path($lang.'/'.variable_get('site_frontpage','node'));
 }
 
 /**
@@ -221,23 +246,22 @@ function i18n_frontpage() {
  * Also removes language from path
  */
 function i18n_get_normal_path($path) {
-  // First, check alias with lang, then without
-  if(_i18n_is_bootstrap()){ 
-    // If in bootstrap, cache hit, only remove prefix
-    i18n_get_lang_prefix($path, TRUE);
-    return $path;
-  } if ($alias = drupal_lookup_path('source', $path)) {
+  $prefix = i18n_get_lang_prefix($path, TRUE);
+  if(!$prefix || _i18n_is_bootstrap()){
+    // If bootstrap, drupal_lookup_path is not defined
+    return $path; 
+  } // First, check alias with lang
+  elseif($alias = drupal_lookup_path('source', $prefix.'/'.$path)){
+    i18n_get_lang_prefix($alias, TRUE); // In case alias has language
+    return $alias;
+  } // Check alias without lang
+  elseif($alias = drupal_lookup_path('source', $path)){
+    i18n_get_lang_prefix($alias, TRUE);
     return $alias;
-  } elseif(i18n_get_lang_prefix($path, TRUE)){
-    if($alias = drupal_lookup_path('source', $path)){
-      i18n_get_lang_prefix($alias, TRUE);
-      return $alias;
-    } else {
-      return $path;
-    }
   } 
-  // We only get here when no alias is defined, with or without lang
-  return $path;
+  else {
+    return $path;
+  }
 }
 
 /**
@@ -252,14 +276,12 @@ function i18n_get_normal_path($path) {
 function _i18n_get_lang() {
   global $user, $i18n_langpath;
   static $i18n_lang;
-  
-  //see if the language is already set.
+  // Check whether the language is already set.
   if ($i18n_lang) {
     return $i18n_lang;
   }
-
+  // Language not set, find one
   $languages = i18n_supported_languages();
-   
   if ($i18n_langpath && array_key_exists($i18n_langpath,$languages)) {
     $i18n_lang = $i18n_langpath;
   }
@@ -332,6 +354,7 @@ function _i18n_goto($lang){
 
 /**
  * i18n_selection_mode
+ * 
  * Allows several modes for query rewriting and to change them programatically
  *     off = No language conditions inserted
  *     simple = Only current language and no language
@@ -339,16 +362,27 @@ function _i18n_goto($lang){
  *  strict = Only current language
  *  default = Only default language
  *  user = User defined, in the module's settings page
+ *  params = Gets the stored params
+ *  reset = Returns to previous
+ *  custom = add custom where clause, like "%alias.language = 'en'"
  */
-function i18n_selection_mode($mode=NULL){
-  static $current;
-  if($mode) {
-    $current = ($mode == 'user') ? variable_get('i18n_selection_mode', 'simple') : $mode;
-  } elseif($current) {
-    return $current;
+function i18n_selection_mode($mode= NULL, $params= NULL){
+  static $current_mode = 'simple';
+  static $current_value = '';
+  static $store = array();
+  
+  if(!$mode) {
+    return $current_mode;
+  } elseif($mode == 'params'){
+    return $current_value;
+  } elseif($mode == 'reset'){
+    list($current_mode, $current_value) = array_pop($store);
+    //drupal_set_message("i18n mode reset mode=$current_mode value=$current_value");
   } else {
-    return $current = variable_get('i18n_selection_mode', 'simple');
-  }
+    array_push($store, array($current_mode, $current_value));
+    $current_mode = $mode;
+    $current_value = $params;
+  } 
 }
 
 function _i18n_selection_mode(){
@@ -357,8 +391,7 @@ function _i18n_selection_mode(){
     'mixed' => t('Only current and default languages and no language'),
     'default' => t('Only default language and no language'),    
     'strict' => t('Only current language'),
-    'off' => t('All content. No language conditions apply'),
-    
+    'off' => t('All content. No language conditions apply'),    
   );
 }
 ?>
\ No newline at end of file
index f9d42aa..11f724c 100644 (file)
@@ -70,6 +70,10 @@ function translation_menu($may_cache) {
         'type' => MENU_LOCAL_TASK);
       
     }
+    // Change rewrite conditions when translating nodenode/add/type/translation/22/es
+    if( arg(0) == 'node' && arg(1) == 'add' && arg(3) == 'translation' && ($lang = arg(5)) && array_key_exists($lang, i18n_supported_languages()) ) {
+      i18n_selection_mode('translation', db_escape_string($lang));
+    }
   }
 
   return $items;
@@ -138,10 +142,9 @@ function translation_form_alter($form_id, &$form) {
       $language = arg(5);
       // Load the node to be translated and populate fields
       $trans = node_load($translation_nid);
-      translation_node_populate_fields($trans, $form, $node);      
       $form['i18n']['translation_nid'] = array('#type' => 'hidden', '#value' => $translation_nid);
       $form['i18n']['language']['#default_value'] = $language;
-
+      translation_node_populate_fields($trans, $form, $node);      
       if($trans->trid){
         $form['i18n']['trid'] = array('#type' => 'hidden', '#value' => $trans->trid);
       }
@@ -165,15 +168,33 @@ function translation_form_alter($form_id, &$form) {
   }    
 }
 
-function translation_node_populate_fields($source, &$form, &$node){
-    foreach(element_children($form) as $key) {
-      if($key != 'nid' && $key != 'vid' && isset($source->$key) && !isset($node->$key)) {
+function translation_node_populate_fields($source, &$form, &$node, $level = 0){
+  $fields = array();
+       foreach(element_children($form) as $key) {
+         if($key == 'nid' || $key == 'vid' || $key == 'i18n'){
+      continue;
+    } elseif(isset($source->$key) && !isset($node->$key)) {
+      if($level == 0 && $key == 'parent' && is_numeric($source->parent)) { // Translate book outline
+        $lang = $form['i18n']['language']['#default_value'];
+       $trans = translation_node_get_translations(array('nid' => $source->parent));
+        if(isset($trans[$lang])) {
+         $form['parent']['#default_value'] = $trans[$lang]->nid;
+        }
+      } else {
         $node->$key = $form[$key]['#default_value'] = $source->$key;
-        drupal_set_message("populated $key");
-      } elseif(!isset($form[$key]['#tree'])) {
-        translation_node_populate_fields($source, $form[$key], $node);
+        $fields[] = $key;
       }
+         } elseif(!isset($form[$key]['#tree'])) {
+           translation_node_populate_fields($source, $form[$key], $node, $level +1);
+         }
+       }
+  if($level = 0) {
+    if($source->type == 'book' && $source->parent){
+      
     }
+  }
+  // For debugging
+  // if($fields) drupal_set_message("Populated fields ($level): ". implode(', ', $fields));
 }
 /**
  * Multilingual Nodes support
@@ -245,7 +266,7 @@ function translation_node_form($node, $lang){
   // Disable i18n rewrite. Order by trid to show first nodes with no translation
   i18n_selection_mode('off');
   $result = pager_query(db_rewrite_sql("SELECT n.nid, n.title FROM {node} n INNER JOIN {i18n_node} i ON n.nid = i.nid WHERE i.language = '%s' ORDER BY i.trid"), 40, 0, NULL, $lang);
-  i18n_selection_mode('user');
+  i18n_selection_mode('reset');
   while($trnode = db_fetch_object($result)){
     $list[$trnode->nid] = l($trnode->title, "node/$trnode->nid") ;
   }
@@ -378,7 +399,7 @@ function translation_node_get_translations($params, $getall = TRUE) {
 
   i18n_selection_mode('off');
   $result = db_query(db_rewrite_sql($sql), $values);
-  i18n_selection_mode('user');
+  i18n_selection_mode('reset');
     
   $items = array();
   while ($node = db_fetch_object($result)) {