Index: l10n_community/export.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/l10n_server/l10n_community/Attic/export.inc,v
retrieving revision 1.1.2.15.2.24
diff -u -p -r1.1.2.15.2.24 export.inc
--- l10n_community/export.inc	25 Jan 2010 20:43:32 -0000	1.1.2.15.2.24
+++ l10n_community/export.inc	15 Feb 2010 09:24:06 -0000
@@ -44,31 +44,42 @@ function l10n_community_export_page($uri
  */
 function l10n_community_export_form(&$form_state, $uri = NULL, $langcode = NULL) {
 
-  $hide_projects = FALSE;
-  if (!isset($uri)) {
-    $uri = !empty($form_state['values']['project']) ? $form_state['values']['project'] : (!empty($_GET['project']) ? $_GET['project'] : NULL);
-  }
-  else {
-    // When project was preset from URL, disable the selector.
-    $hide_projects = TRUE;
-  }
-
+  // When project was preset from path, disable the selector. 
+  $hide_projects = isset($uri);
+  
+  // Set initial form state, so we can consistently use that.
   $projects = l10n_community_get_projects();
+  if (empty($form_state['values'])) {
+    $form_state['values'] = array(
+      'project' => isset($projects[$uri]) ? $projects[$uri]->title : (isset($_GET['project']) && isset($projects[$_GET['project']]) ? $projects[$_GET['project']]->title : ''),
+      'release' => isset($_GET['release']) ? isset($_GET['release']) : 'all',
+    );
+  }
+  
+  $form = array();
   $form['data'] = array(
     '#type' => 'fieldset',
     '#title' => t('Source data'),
   );
   if ($hide_projects) {
+    // This only happens if we have a project to export via $uri.
+    // In this case, $uri is already verified via the menu system.
     $form['data']['project'] = array(
       '#type' => 'value',
-      // Value of $uri already verified in menu path handler.
-      '#value' => $projects[$uri]->title,
+      '#value' => $form_state['values']['project'],
     );
   }
   else {
     $form['data']['project'] = array(
       '#title' => t('Project'),
       '#required' => TRUE,
+      '#default_value' => $form_state['values']['project'],
+      '#ahah' => array(
+        // 'event' missing, Drupal will apply the per-#type defaults.
+        'path' => 'translate/releases-ahah',
+        'wrapper' => 'l10n-server-releases',
+        'effect' => 'fade',
+      ),
     );
     if (($count = count($projects)) <= 30) {
       // Radio box widget for as much as 5 projects, select widget for 5-30 projects.
@@ -88,23 +99,29 @@ function l10n_community_export_form(&$fo
     }
   }
 
-  if (isset($projects[$uri])) {
-    // Set this project as default value if identified.
-    $form['data']['project']['#default_value'] = $projects[$uri]->title;
-
-    $releases = l10n_community_get_releases($uri);
-    $release_options = array('all' => t('All releases merged'));
+  $release_options = array('all' => t('All releases merged'));
+  if (!empty($form_state['values']['project'])) {
+    $selected_project = $projects[l10n_community_project_uri_by_title($form_state['values']['project'])];
+    $releases = l10n_community_get_releases($selected_project->uri);
     foreach ($releases as $rid => $this_release) {
       $release_options[$rid] = t('@release only', array('@release' => $this_release->title));
     }
-    $form['data']['release'] = array(
-      '#title' => t('Release'),
-      '#type' => count($release_options) <= 3 ? 'radios' : 'select',
-      '#options' => $release_options,
-      '#default_value' => isset($_GET['release']) && isset($releases[$_GET['release']]) ? $_GET['release'] : 'all',
-    );
   }
-  if (isset($langcode) && isset($form['data']['release'])) {
+  if (!isset($release_options[$form_state['values']['release']])) {
+    $form_state['values']['release'] = 'all';
+  }
+  $form['data']['release'] = array(
+    '#title' => t('Release'),
+    '#required' => TRUE,
+    '#type' => 'select',
+    '#options' => $release_options,
+    '#default_value' => $form_state['values']['release'],
+    // Wrapper used to replace release options via AHAH.
+    '#prefix' => '<div id="l10n-server-releases">',
+    '#suffix' => '</div>',
+  );
+
+  if (isset($langcode)) {
     $form['langcode'] = array(
       '#type' => 'value',
       '#value' => $langcode,
@@ -137,7 +154,7 @@ function l10n_community_export_form(&$fo
   }
   $form['submit'] = array(
     '#type' => 'submit',
-    '#value' => isset($form['data']['release']) ? t('Export') : t('Choose project'),
+    '#value' => t('Export'),
   );
   return $form;
 }
Index: l10n_community/l10n_community.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/l10n_server/l10n_community/Attic/l10n_community.module,v
retrieving revision 1.1.2.23.2.66.2.2
diff -u -p -r1.1.2.23.2.66.2.2 l10n_community.module
--- l10n_community/l10n_community.module	26 Jan 2010 15:33:44 -0000	1.1.2.23.2.66.2.2
+++ l10n_community/l10n_community.module	15 Feb 2010 09:24:07 -0000
@@ -202,6 +202,14 @@ function l10n_community_menu() {
     'access arguments' => array('access localization community'),
     'type' => MENU_CALLBACK
   );
+  // Serve a list of releases for a given project.
+  $items['translate/releases-ahah'] = array(
+    'title' => 'AHAH release picker callback',
+    'page callback' => 'l10n_community_ahah_releases',
+    'access arguments' => array('access localization community'),
+    'type' => MENU_CALLBACK
+  );
+  
 
   // AJAX callbacks for easy translation management. These are expected to be
   // used only onsite (not as remote API endpoints), so they have no versioning.
@@ -1577,3 +1585,49 @@ function l10n_community_add_url_modifier
   }
   drupal_add_js(array('l10nServerURLs' => $replacements), 'setting');
 }
+
+// = AHAH callbacks ============================================================
+
+/**
+ * AHAH callback to serve an updated list of releases on project changes.
+ *
+ * This callback is used on the filter forms for translation pages and the
+ * export form, so need to accommodate for small differences of the two.
+ */
+function l10n_community_ahah_releases() {
+  // AHAH copy-paste from http://drupal.org/node/331941
+  $form_state = array('storage' => NULL, 'submitted' => FALSE, 'rebuild' => TRUE);
+  $form_build_id = $_POST['form_build_id'];
+  $form = form_get_cache($form_build_id, $form_state);
+  $args = $form['#parameters'];
+  $form_id = array_shift($args);
+  // AHAH copy-paste cut.
+
+  // Include the right file based on the form being used.
+  $file = ($form_id == 'l10n_community_export_form') ? 'export.inc' : 'translate.inc';
+  include_once drupal_get_path('module', 'l10n_community') .'/'. $file;
+
+  // AHAH copy-paste from http://drupal.org/node/331941 continued
+  $form_state['post'] = $form['#post'] = $_POST;
+  $form['#programmed'] = $form['#redirect'] = FALSE;
+  drupal_process_form($form_id, $form, $form_state);
+  $form = drupal_rebuild_form($form_id, $form_state, $args, $form_build_id);
+  // End of AHAH copy paste.
+
+  // Pick and render our changed element for output.
+  $changed_element = ($form_id == 'l10n_community_export_form') ? $form['data']['release'] : $form['release'];
+  // Prevent duplicate wrappers.
+  unset($changed_element['#prefix'], $changed_element['#suffix']); 
+
+  if ($form_id == 'l10n_community_filter_form') {
+    // Prevent duplicate titles (due to how we render the elements).
+    unset($changed_element['#title']);
+  }
+  
+  drupal_json(
+    array(
+      'status' => TRUE,
+      'data'   => theme('status_messages') . drupal_render($changed_element),
+    )
+  );
+}
Index: l10n_community/translate.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/l10n_server/l10n_community/Attic/translate.inc,v
retrieving revision 1.1.2.7.2.31.2.4
diff -u -p -r1.1.2.7.2.31.2.4 translate.inc
--- l10n_community/translate.inc	8 Feb 2010 16:15:01 -0000	1.1.2.7.2.31.2.4
+++ l10n_community/translate.inc	15 Feb 2010 09:24:07 -0000
@@ -30,9 +30,32 @@ function l10n_community_filter_form(&$fo
     L10N_STATUS_HAS_SUGGESTION => t('Has suggestion'),
   );
 
+  // This form can be submitted multiple times to support AHAH flows.
+  // So we set an initial default value set for the form values, if there
+  // was none submitted already. Otherwise, the submitted values will take
+  // on being the defaults.
+  if (empty($form_state['values'])) {
+    $form_state['values'] = array(
+      'project' => isset($filters['project']) ? $filters['project']->title : '',
+      'release' => isset($filters['release']) ? $filters['release']        : 'all',
+      'context' => isset($filters['context']) ? $filters['context']        : '',
+      'status'  => isset($filters['status'])  ? $filters['status']         : L10N_STATUS_ALL,
+      'author'  => isset($filters['author'])  ? $filters['author']->name   : '',
+      'search'  => isset($filters['search'])  ? $filters['search']         : '',
+      'limit'   => isset($filters['limit'])   ? $filters['limit']          : 10,
+    );
+  }
+  
+  $form = array();
   $form['project'] = array(
     '#title' => t('Project'),
-    '#default_value' => isset($filters['project']) ? $filters['project']->title : '',
+    '#default_value' => $form_state['values']['project'],
+    '#ahah' => array(
+      // 'event' missing, Drupal will apply the per-#type defaults.
+      'path' => 'translate/releases-ahah',
+      'wrapper' => 'l10n-server-releases',
+      'effect' => 'fade',
+    ),
   );
   if (($count = count($projects)) <= 30) {
     // Select widget for 1-30 projects.
@@ -52,26 +75,35 @@ function l10n_community_filter_form(&$fo
     );
   }
 
-  if (isset($filters['project'])) {
-    $releases = l10n_community_get_releases($filters['project']->uri);
-    $release_options = array('all' => t('All'));
+  // Always add releases option, so we can update it when 
+  // needed as the project changes with AHAH.
+  $release_options = array('all' => t('All'));
+  if (!empty($form_state['values']['project'])) {
+    $selected_project = $projects[l10n_community_project_uri_by_title($form_state['values']['project'])];
+    $releases = l10n_community_get_releases($selected_project->uri);
     foreach ($releases as $rid => $release) {
       $release_options[$rid] = $release->title;
     }
-    $form['release'] = array(
-      '#title' => t('Release'),
-      '#type' => 'select',
-      '#options' => $release_options,
-      '#default_value' => isset($filters['release']) ? $filters['release'] : 'all',
-    );
   }
+  if (!isset($release_options[$form_state['values']['release']])) {
+    $form_state['values']['release'] = 'all';
+  }
+  $form['release'] = array(
+    '#title' => t('Release'),
+    '#type' => 'select',
+    '#options' => $release_options,
+    '#default_value' => $form_state['values']['release'],
+    // Wrapper used to replace release options via AHAH.
+    '#prefix' => '<div id="l10n-server-releases">',
+    '#suffix' => '</div>',
+  );
 
   if (count($contexts = l10n_community_get_contexts()) > 1) {
     $form['context'] = array(
      '#title' => t('Context'),
       '#type' => 'select',
       '#options' => array('all' => t('All')) + $contexts,
-      '#default_value' => $filters['context'],
+      '#default_value' => $form_state['values']['context'],
     );
   }
 
@@ -82,13 +114,13 @@ function l10n_community_filter_form(&$fo
   $form['status']['translation'] = array(
     '#type' => 'select',
     '#options' => $translation_options,
-    '#default_value' => $filters['status'] & (L10N_STATUS_TRANSLATED | L10N_STATUS_UNTRANSLATED),
+    '#default_value' => $form_state['values']['status'] & (L10N_STATUS_TRANSLATED | L10N_STATUS_UNTRANSLATED),
   );
   if (!$limited) {
     $form['status']['suggestion'] = array(
       '#type' => 'select',
       '#options' => $suggestion_options,
-      '#default_value' => $filters['status'] & (L10N_STATUS_HAS_SUGGESTION | L10N_STATUS_NO_SUGGESTION),
+      '#default_value' => $form_state['values']['status'] & (L10N_STATUS_HAS_SUGGESTION | L10N_STATUS_NO_SUGGESTION),
     );
   }
 
@@ -97,23 +129,22 @@ function l10n_community_filter_form(&$fo
     '#title' => t('Submitted by'),
     '#maxlength' => 60,
     '#autocomplete_path' => 'user/autocomplete',
-    '#default_value' => isset($filters['author']) ? $filters['author']->name : '',
+    '#default_value' => $form_state['values']['author'],
     '#size' => 15,
   );
 
   $form['search'] = array(
     '#title' => t('Contains'),
     '#type' => 'textfield',
-    '#default_value' => $filters['search'],
+    '#default_value' => $form_state['values']['search'],
     '#size' => 20,
   );
 
   $form['limit'] = array(
     '#type' => 'select',
     '#title' => t('Limit'),
-    '#default_value' => isset($filters['limit']) ? $filters['limit'] : 10,
     '#options' => drupal_map_assoc(array(5, 10, 20, 30)),
-    '#default_value' => $filters['limit'],
+    '#default_value' => $form_state['values']['limit'],
   );
 
   $form['submit'] = array(
