diff --git a/salsa_advocacy/salsa_advocacy.module b/salsa_advocacy/salsa_advocacy.module
index 31b05ce..0c7033c 100644
--- a/salsa_advocacy/salsa_advocacy.module
+++ b/salsa_advocacy/salsa_advocacy.module
@@ -181,6 +181,21 @@ function salsa_advocacy_petition_form($form, &$form_state, $action) {
   }
   $action_content_detail = entity_load('salsa_action_content_detail', FALSE, array('action_content_KEY' => $action_content->action_content_KEY));
   $action_content_detail = reset($action_content_detail);
+
+  // Check if progress bar is enabled.
+  if (!empty($action->Signature_Goal) && $action->Signatures != 'Do not show signatures') {
+    // Add the progress bar.
+    salsa_entity_add_progress_bar(
+      $form_state,
+      salsa_advocacy_get_supporter_actions_total($action),
+      $action->Signature_Goal,
+      $form
+    );
+
+    // Set weight in order to display on top of supporter fieldset.
+    $form['progress']['#weight'] = -200;
+  }
+
   if ($action_content_detail->Recommended_Content) {
     // @todo For some reason petition content are highlighted on public page,
     // so I added the prefix and suffix, but it can be removed if there is no need.
@@ -344,6 +359,9 @@ function salsa_advocacy_petition_form_submit($form, &$form_state) {
   // Create a new one or update existing supporter.
   salsa_entity_supporter_fieldset_submit($form, $form_state);
 
+  // Clear the cached count of supporter actions on this action.
+  cache_clear_all('salsa_advocacy_supporter_action_count:' . $form_state['salsa_object']->action_KEY, 'cache');
+
   // Save comments, if any.
   if (!empty($form_state['values']['Comment'])) {
     $supporter_action_comment = new SalsaEntity(array(), 'salsa_supporter_action_comment');
@@ -409,6 +427,7 @@ function salsa_advocacy_petition_form_submit($form, &$form_state) {
  * Salsa targeted action form callback.
  */
 function salsa_advocacy_targeted_form($form, &$form_state, $action) {
+  $form_state['salsa_object'] = $action;
   $action_content = reset(entity_load('salsa_action_content', FALSE, array('action_KEY' => $action->action_KEY)));
   $action_content_detail = reset(entity_load('salsa_action_content_detail', FALSE, array('action_content_KEY' => $action_content->key)));
   $action_target = reset(entity_load('salsa_action_target', FALSE, array('action_KEY' => $action->action_KEY)));
@@ -504,6 +523,17 @@ function salsa_advocacy_targeted_form($form, &$form_state, $action) {
       }
     }
 
+    // Check if progress bar is enabled.
+    $field_key = variable_get('salsa_advocacy_targeted_goal_field');
+    if (!empty($action->{$field_key})) {
+      salsa_entity_add_progress_bar(
+        $form_state,
+        salsa_advocacy_get_supporter_actions_total($action),
+        $action->{$field_key},
+        $form
+      );
+    }
+
     // Action content fieldset.
     $form['action_content'] = array(
       '#type' => 'fieldset',
@@ -566,9 +596,6 @@ function salsa_advocacy_targeted_form($form, &$form_state, $action) {
     // Add hidden fields.
     salsa_advocacy_targeted_form_hidden_fields($form, $form_state);
 
-    // Submit this form directly to salsa page.
-    $form['#action'] = variable_get('salsa_api_url') . '/o/' . $action->organization_KEY . '/action/wrapperProcessAction2.jsp';
-
     // Submit button.
     $form['submit'] = array(
       '#type' => 'submit',
@@ -586,6 +613,39 @@ function salsa_advocacy_targeted_form($form, &$form_state, $action) {
 }
 
 /**
+ * Submit handler for the single target action form.
+ *
+ * Necessary to clear the cache for the supporter actions count and for the
+ * mollom captcha validation.
+ */
+function salsa_advocacy_targeted_form_submit($form, &$form_state) {
+  $action = $form_state['salsa_object'];
+  // Clear the cached count of supporter actions on this action.
+  cache_clear_all('salsa_advocacy_supporter_action_count:' . $action->action_KEY, 'cache');
+
+  // Eventually submit the data to the salsa page.
+  $salsa_url = variable_get('salsa_api_url') . '/o/' . $action->organization_KEY . '/action/wrapperProcessAction2.jsp';
+  // Get data from raw request body instead of using http_build_query() as
+  // fields with same names get missing that way.
+  $options = array(
+    'method' => 'POST',
+    'data' => file_get_contents('php://input'),
+    'headers' => array(
+      'Content-Type' => 'application/x-www-form-urlencoded',
+    ),
+  );
+  drupal_http_request($salsa_url, $options);
+
+  // Redirect the the configured uri or the frontpage otherwise.
+  if (!empty($action->redirect_path)) {
+    $form_state['redirect'] = $action->redirect_path;
+  }
+  else {
+    $form_state['redirect'] = '<front>';
+  }
+}
+
+/**
  * Hidden fields for targeted actions form.
  */
 function salsa_advocacy_targeted_form_hidden_fields(&$form, $form_state) {
@@ -1044,6 +1104,27 @@ function salsa_advocacy_fetch_action_targets($action_key) {
  *   A form array set for theming by theme_salsa_advocacy_settings_form()
  */
 function salsa_advocacy_settings_form($form, &$form_state) {
+  // Custom fields used as goal for progress bars on action forms.
+  $custom_fields = salsa_entity_custom_fields('action');
+  if (!empty($custom_fields)) {
+    $form['progress'] = array(
+      '#type' => 'fieldset',
+      '#title' => t('Progress bar'),
+    );
+
+    foreach ($custom_fields as $field_name => $field) {
+      $options[$field_name] = $field['label'];
+    }
+    $form['progress']['salsa_advocacy_targeted_goal_field'] = array(
+      '#type' => 'select',
+      '#title' => t('Salsa Advocacy Goal Field'),
+      '#description' => t('Salsa custom field that contains the submission goal for actions.'),
+      '#options' => $options,
+      '#default_value' => variable_get('salsa_advocacy_targeted_goal_field'),
+      '#empty_option' => t('- None -'),
+    );
+  }
+
   $form['items']['#tree'] = TRUE;
 
   // Fetch custom fields.
@@ -1152,19 +1233,49 @@ function theme_salsa_advocacy_settings_form($variables) {
  * Submit handler for advocacy settings form.
  */
 function salsa_advocacy_settings_form_submit($form, &$form_state) {
-  $custom_fields_settings = array();
-  foreach ($form_state['values']['items'] as $item) {
-    $custom_fields_settings[$item['name']] = array(
-      'weight' => $item['weight'],
-      'fixed_value' => $item['fixed'],
-      'default_value' => $item['default_value'],
-      'default_value_callback' => '',
-      'enabled' => $item['enabled'] ? TRUE : FALSE,
-    );
+  if (isset($form_state['values']['items'])) {
+    $custom_fields_settings = array();
+    foreach ($form_state['values']['items'] as $item) {
+      $custom_fields_settings[$item['name']] = array(
+        'weight' => $item['weight'],
+        'fixed_value' => $item['fixed'],
+        'default_value' => $item['default_value'],
+        'default_value_callback' => '',
+        'enabled' => $item['enabled'] ? TRUE : FALSE,
+      );
+    }
+    variable_set('salsa_advocacy_custom_fields', $custom_fields_settings);
   }
-  variable_set('salsa_advocacy_custom_fields', $custom_fields_settings);
+
+  // Set the field for the barometer goal targeted actions.
+  variable_set('salsa_advocacy_targeted_goal_field', $form_state['values']['salsa_advocacy_targeted_goal_field']);
+
   cache_clear_all('salsa_advocacy_mapping', 'cache');
   cache_clear_all('salsa_advocacy_filters', 'cache');
   cache_clear_all('salsa_advocacy_custom_fields', 'cache');
   drupal_set_message(t('Settings have been saved.'));
 }
+
+/**
+ * Retrieves the supporter action objects related to a given action.
+ *
+ * Caches the data that is fetched from Salsa if the count isn't cached yet,
+ * otherwise cached data is returned.
+ *
+ * @param object $action
+ *   The Salsa entity of type action.
+ *
+ * @return int
+ *   The amount ob supporter actions for the given action.
+ */
+function salsa_advocacy_get_supporter_actions_total($action) {
+  $cache = cache_get('salsa_advocacy_supporter_action_count:' . $action->action_KEY);
+  if (!$cache) {
+    $salsa_api = salsa_api();
+    $count = $salsa_api->getCount('supporter_action', array('action_KEY' => $action->action_KEY));
+    cache_set('salsa_advocacy_supporter_action_count:' . $action->action_KEY, $count);
+    return $count;
+  }
+
+  return $cache->data;
+}
diff --git a/salsa_donate_page/includes/salsa_donate_page.css b/salsa_donate_page/includes/salsa_donate_page.css
deleted file mode 100644
index 7ebcf7a..0000000
--- a/salsa_donate_page/includes/salsa_donate_page.css
+++ /dev/null
@@ -1,35 +0,0 @@
-/**
- * @file
- * CSS style definitions for salsa donate page module.
- */
-
-.donate-page-barometer-progress {
-  background-color: #598EDE;
-  position: absolute;
-  height: 22px;
-}
-
-.donate-page-barometer {
-  background-color: #C3C3C3;
-  border: 1px solid #000;
-  width: 30%;
-  position: relative;
-  height: 22px;
-}
-
-.donate-page-donation-goal {
-  font-weight: bold;
-  margin-bottom: 10px;
-}
-
-.donate-page-barometer-label {
-  position: absolute;
-  height: 20px;
-  z-index: 1;
-  font-weight: bold;
-  padding: 2px 0px 2px 6px;
-}
-
-.donate-page-barometer-wrapper {
-  margin-bottom: 1em;
-}
\ No newline at end of file
diff --git a/salsa_donate_page/salsa_donate_page.module b/salsa_donate_page/salsa_donate_page.module
index 7e07ad4..c15f422 100644
--- a/salsa_donate_page/salsa_donate_page.module
+++ b/salsa_donate_page/salsa_donate_page.module
@@ -45,13 +45,6 @@ function salsa_donate_page_menu() {
  */
 function salsa_donate_page_theme() {
   return array(
-    'salsa_donate_page_progress_bar' => array(
-      'variables' => array(
-        'goal' => NULL,
-        'value' => NULL,
-        'total' => NULL,
-      ),
-    ),
     'salsa_donate_page_donors_list' => array(
       'variables' => array(
         'row_values' => array(),
@@ -85,6 +78,21 @@ function salsa_donate_page_mollom_form_info($form_id) {
 }
 
 /**
+ * Implements hook_salsa_entity_progress_bar_labels_alter().
+ *
+ * Add currencies to the amounts and change the labels of the donation progress
+ * bar.
+ */
+function salsa_donate_page_salsa_entity_progress_bar_labels_alter(&$labels, $form_id) {
+  if ($form_id == 'salsa_donate_page_form') {
+    $labels['goal'] = salsa_entity_get_amount($labels['goal'], TRUE);
+    $labels['total'] = salsa_entity_get_amount($labels['total'], TRUE);
+    $labels['goal_label'] = t('Donation goal:');
+    $labels['total_label'] = t('Donated:');
+  }
+}
+
+/**
  * Donate Page form.
  *
  * @todo State / Province should be dynamic.
@@ -110,11 +118,6 @@ function salsa_donate_page_form($form, &$form_state, $donate_page, $view_mode) {
         'data' => drupal_get_path('module', 'salsa_entity') . '/salsa_donate_page/js/salsa_donate_page.behaviors.js',
       ),
     ),
-    'css' => array(
-      array(
-        'data' => drupal_get_path('module', 'salsa_donate_page') . '/includes/salsa_donate_page.css'
-      ),
-    ),
   );
 
   // Add default required fields for a donation.
@@ -210,9 +213,15 @@ function salsa_donate_page_form($form, &$form_state, $donate_page, $view_mode) {
     '#title' => t('Donation Amount'),
   );
 
-  $form['Donation']['progress'] = array(
-    '#markup' => salsa_donate_page_get_barometer($donate_page),
-  );
+  $field_key = variable_get('salsa_donations_goal_field');
+  if (!empty($donate_page->{$field_key})) {
+    salsa_entity_add_progress_bar(
+      $form_state,
+      salsa_donate_page_total_donation_amount($donate_page->donate_page_KEY),
+      $donate_page->{$field_key},
+      $form
+    );
+  }
 
   if (variable_get('salsa_donations_donors_list_row_count', 0)) {
     $form['Donation']['donors_list'] = salsa_donate_page_get_donors_list($donate_page);
@@ -1014,20 +1023,6 @@ function salsa_donate_page_get_latest_donations($donate_page_key, $limit) {
 }
 
 /**
- * Theme function for the donation barometer.
- */
-function theme_salsa_donate_page_progress_bar($vars) {
-  $output =  '<div class="donate-page-barometer-wrapper">';
-  $output .=   '<div class="donate-page-donation-goal">' . t('Donation goal:') . '&nbsp;' . $vars['goal'] . '</div>';
-  $output .=   '<div class="donate-page-barometer">';
-  $output .=     '<span class="donate-page-barometer-label">' . t('Donated:') . '&nbsp;' . $vars['total'] . '</span>';
-  $output .=     '<div class="donate-page-barometer-progress" style="width:' . min($vars['value'], 100) . '%;"></div>';
-  $output .=   '</div>';
-  $output .= '</div>';
-  return $output;
-}
-
-/**
  * Theme function for the donors list.
  */
 function theme_salsa_donate_page_donors_list($vars) {
@@ -1064,31 +1059,6 @@ function theme_salsa_donate_page_donors_list($vars) {
 }
 
 /**
- * Wrapper function to get the markup of the barometer.
- *
- * @param object $donate_page
- *   The salsa donation object.
- *
- * @return string
- *   The markup of the barometer.
- */
-function salsa_donate_page_get_barometer($donate_page) {
-  $field_name = variable_get('salsa_donations_goal_field');
-  // Return an empty string if the goal isn't set.
-  if (empty($donate_page->{$field_name})) {
-    return '';
-  }
-  $total = salsa_donate_page_total_donation_amount($donate_page->donate_page_KEY);
-  $goal = $donate_page->{$field_name};
-  $value = (($total / $goal) < 1) ? ($total / $goal) : 1;
-  return theme('salsa_donate_page_progress_bar', array(
-    'goal' => salsa_entity_get_amount($goal, TRUE),
-    'value' => min(round($value * 100), 100),
-    'total' => salsa_entity_get_amount(salsa_donate_page_total_donation_amount($donate_page->donate_page_KEY), TRUE),
-  ));
-}
-
-/**
  * Wrapper that prints the markup for the donors list.
  *
  * @param object $donate_page
diff --git a/salsa_entity.api.php b/salsa_entity.api.php
index bbec6ae..dbeb17e 100644
--- a/salsa_entity.api.php
+++ b/salsa_entity.api.php
@@ -145,3 +145,20 @@ function hook_salsa_query_TAG_alter(array &$conditions, EntityFieldQuery $query)
   // Define a different order field, prepend - for descending order.
   $conditions['#order'] = array('-field_name_2');
 }
+
+/**
+ * Alter the labels that are displayed within the progress bar.
+ *
+ * @param int $goal
+ *   The number representing the total width of the progress bar.
+ * @param int $form_id
+ *   The form id (form function name) of the form that adds the progress bar.
+ */
+function hook_salsa_entity_progress_bar_labels_alter(&$labels, $form_id) {
+  if ($form_id == 'salsa_donate_page_form') {
+    $labels['goal'] = salsa_entity_get_amount($labels['goal'], TRUE);
+    $labels['total'] = salsa_entity_get_amount($labels['total'], TRUE);
+    $labels['goal_label'] = t('Donation goal:');
+    $labels['total_label'] = t('Donated:');
+  }
+}
diff --git a/salsa_entity.module b/salsa_entity.module
index 8f39734..6b3b905 100644
--- a/salsa_entity.module
+++ b/salsa_entity.module
@@ -51,6 +51,13 @@ function salsa_entity_menu() {
     'access callback' => TRUE,
     'type' => MENU_CALLBACK,
   );
+  $items['admin/config/services/salsa/common'] = array(
+    'title' => 'Common',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('salsa_entity_system_settings_form'),
+    'access arguments' => array('administer salsa'),
+    'type' => MENU_LOCAL_TASK,
+  );
   return $items;
 }
 
@@ -66,7 +73,39 @@ function salsa_entity_theme() {
         'title' => NULL,
       ),
     ),
+    'salsa_entity_progress_bar' => array(
+      'variables' => array(
+        'goal' => NULL,
+        'value' => NULL,
+        'total' => NULL,
+        'goal_label' => NULL,
+        'total_label' => NULL,
+        'barometer_type' => NULL,
+        'entity_id' => NULL,
+      ),
+    ),
+  );
+}
+
+/**
+ * Implements hook_library().
+ */
+function salsa_entity_library() {
+  // Library with required JS and CSS for the progress bar.
+  $libraries['progress_bar'] = array(
+    'title' => 'Salsa entity progress bar library',
+    'version' => '1.0',
+    'js' => array(
+      drupal_get_path('module', 'salsa_entity') . '/theme/salsa_entity.js' => array(),
+    ),
+    'css' => array(
+      drupal_get_path('module', 'salsa_entity') . '/theme/salsa_progress_bar.css' => array(
+        'type' => 'file',
+        'media' => 'screen',
+      ),
+    ),
   );
+  return $libraries;
 }
 
 /**
@@ -95,7 +134,68 @@ function salsa_entity_form_salsa_api_system_settings_alter(&$form, &$form_state)
       'salsa_entity_submit_clear_describe_cache',
     ),
   );
-  return $form;
+}
+
+/**
+ * General system settings for salsa entity.
+ */
+function salsa_entity_system_settings_form($form, &$form_state) {
+  $form['progress_bar_settings'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Progress bar settings'),
+    '#collapsible' => TRUE,
+    '#collapsed' => FALSE,
+  );
+
+  $form['progress_bar_settings']['salsa_entity_progress_bar_animation'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Progress bar animation'),
+    '#description' => t('If enabled, progress bars on donate pages, single target and petition action forms will get animated with a load effect on page load.'),
+    '#default_value' => variable_get('salsa_entity_progress_bar_animation', FALSE),
+  );
+
+  $form['progress_bar_settings']['salsa_entity_progress_bar_animation_speed'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Animation speed'),
+    '#description' => t('Enter an amount of milliseconds. Each step of the animation will take the entered amount of time.'),
+    '#default_value' => variable_get('salsa_entity_progress_bar_animation_speed', 25),
+    '#states' => array(
+      'visible' => array(
+        ':input[name="salsa_entity_progress_bar_animation"]' => array('checked' => TRUE),
+      ),
+    ),
+  );
+
+  $query = new EntityFieldQuery();
+  $types = variable_get('salsa_entity_progress_bar_entity_types', array(
+    'salsa_donate_page',
+    'salsa_action',
+  ));
+  $options = array();
+  foreach ($types as $type) {
+    $query->entityCondition('entity_type', $type);
+    $result = $query->execute();
+    foreach ($result[$type] as $salsa_entity) {
+      $options[$salsa_entity->key] = $salsa_entity->Reference_Name;
+    }
+  }
+
+  $form['progress_bar_settings']['salsa_entity_progress_bar_animation_style_percent'] = array(
+    '#type' => 'select',
+    '#multiple' => TRUE,
+    '#size' => 10,
+    '#options' => $options,
+    '#title' => t('Animation label as percentage'),
+    '#description' => t('Select the entities that will count up the label in percent steps. Entities that are not selected will count up the progress value as absolute amount.'),
+    '#default_value' => variable_get('salsa_entity_progress_bar_animation_style_percent', 25),
+    '#states' => array(
+      'visible' => array(
+        ':input[name="salsa_entity_progress_bar_animation"]' => array('checked' => TRUE),
+      ),
+    ),
+  );
+
+  return system_settings_form($form);
 }
 
 /**
@@ -825,6 +925,91 @@ function salsa_entity_filter_info() {
 }
 
 /**
+ * Creates the markup of the barometer.
+ *
+ * Also attaches the corresponding CSS and JS library to the form and gives
+ * other modules a chance to alter the labels that will be printed.
+ *
+ * @param array $form_state
+ *   The form state of the requesting form which also contains the salsa entity
+ *   object among other useful stuff.
+ * @param int $total
+ *   Counted amount for the current progress.
+ * @param int $goal
+ *   The goal amount that equals 100% progress.
+ * @param array $container
+ *   The container which the progress bar will get attached to, passed by
+ *   reference.
+ *
+ * @return string
+ *   The markup for the barometer.
+ */
+function salsa_entity_add_progress_bar($form_state, $total, $goal, &$container) {
+  // Don't allow rendering of progress bar without values that make sense.
+  if (!$total && !$goal) {
+    return '';
+  }
+
+  // Calculate the percentage of the total for the styling of the progress bar.
+  $value = (($total / $goal) < 1) ? ($total / $goal) : 1;
+  $form_id = $form_state['build_info']['form_id'];
+  $entity_id = $form_state['build_info']['args'][0]->key;
+
+  // Give other modules a chance to alter the labels.
+  $labels = array(
+    'goal' => $goal,
+    'total' =>  $total,
+    'goal_label' => t('Goal', array(), array('context' => $form_id)),
+    'total_label' => t('Total', array(), array('context' => $form_id)),
+  );
+  drupal_alter('salsa_entity_progress_bar_labels', $labels, $form_id);
+
+  if (variable_get('salsa_entity_progress_bar_animation', FALSE)) {
+    // Add the progress bar css, js and jq library to the requesting form.
+    $container['#attached']['library'][] = array('salsa_entity', 'progress_bar');
+    // Add settings that will be used by the JS that adds the load effect to the
+    // progress bar.
+    $percent_styles = variable_get('salsa_entity_progress_bar_animation_style_percent', array());
+    $js_settings = array(
+      'entity_id' => $entity_id,
+      'total_label' => $labels['total_label'],
+      'total' => (int) $total,
+      'goal' =>  (int) $goal,
+      'total_string' => variable_get('salsa_entity_progress_bar_total_string', '@total_label @total'),
+      'total_args' => variable_get('salsa_entity_progress_bar_total_replacements', array(
+        '@total_label' => $labels['total_label'],
+        '@total' => $labels['total'],
+      )),
+      'animation_speed' => variable_get('salsa_entity_progress_bar_animation_speed', 25),
+      'percent_label' => in_array($entity_id, $percent_styles),
+    );
+    $container['#attached']['js'][] = array(
+      'data' => array('salsaEntityProgressBar' => array($js_settings)),
+      'type' => 'setting',
+    );
+  }
+  else {
+    // Animation is disabled, add only CSS to the form.
+    $container['#attached']['css'] = array(
+      drupal_get_path('module', 'salsa_entity') . '/theme/salsa_progress_bar.css'
+    );
+  }
+
+  // Theme the progress bar with the collected values and add it to the form.
+  $container['progress'] = array(
+    '#markup' => theme('salsa_entity_progress_bar', array(
+      'goal' => $labels['goal'],
+      'goal_label' => $labels['goal_label'],
+      'total' => $labels['total'],
+      'total_label' => $labels['total_label'],
+      'value' => min(round($value * 100), 100),
+      'barometer_type' => $form_id,
+      'entity_id' => $entity_id,
+    )),
+  );
+}
+
+/**
  * Filter process callback to render an entity.
  */
 function _salsa_entity_filter_entity_view($text, $filter, $format, $langcode, $cache, $cache_id) {
@@ -853,3 +1038,17 @@ function _salsa_entity_filter_replace_callback($matches) {
     }
   }
 }
+
+/**
+ * Theme function for the progress barometer.
+ */
+function theme_salsa_entity_progress_bar($vars) {
+  $output =  '<div class="salsa-barometer-wrapper salsa-entity-' . $vars['entity_id'] . '">';
+  $output .=   '<div class="salsa-barometer-goal">' . $vars['goal_label'] . '&nbsp;' . $vars['goal'] . '</div>';
+  $output .=   '<div class="salsa-barometer">';
+  $output .=     '<span class="salsa-barometer-label">' . $vars['total_label'] . '&nbsp;' . $vars['total'] . '</span>';
+  $output .=     '<div class="salsa-barometer-progress" style="width:' . min($vars['value'], 100) . '%;"></div>';
+  $output .=   '</div>';
+  $output .= '</div>';
+  return $output;
+}
diff --git a/salsa_my_donate_page/salsa_my_donate_page.module b/salsa_my_donate_page/salsa_my_donate_page.module
index a124b15..e5142e1 100644
--- a/salsa_my_donate_page/salsa_my_donate_page.module
+++ b/salsa_my_donate_page/salsa_my_donate_page.module
@@ -617,7 +617,7 @@ function salsa_my_donate_page_form($form, &$form_state, $supporter_my_donate_pag
   );
 
   $form['progress']['progressbar'] = array(
-    '#theme' => 'salsa_donate_page_progress_bar',
+    '#theme' => 'salsa_entity_progress_bar',
     '#goal' => salsa_entity_get_amount($total, TRUE),
     '#total' => salsa_entity_get_amount($current, TRUE),
     '#value' => $percent,
diff --git a/theme/salsa_entity.js b/theme/salsa_entity.js
new file mode 100644
index 0000000..8339de5
--- /dev/null
+++ b/theme/salsa_entity.js
@@ -0,0 +1,77 @@
+/**
+ * @file
+ * JS Behaviors for the salsa entity progress bar.
+ */
+
+(function($) {
+  Drupal.behaviors.salsaEntityProgressBar = {
+    attach: function(context, settings) {
+
+      var progress_conf = Drupal.settings.salsaEntityProgressBar;
+      var stack = [];
+
+      // Progress bar might be disabled and settings unavailable.
+      if (progress_conf !== undefined) {
+        for (var i = 0; i < progress_conf.length; i++) {
+          var config = progress_conf[i];
+          var $wrapper = $('.salsa-entity-' + config.entity_id);
+
+          // Get the data for each progress bar and push it on the stack.
+          stack[i] = {
+            config: progress_conf[i],
+            $wrapper: $wrapper,
+            $progress_bar:  $wrapper.find('.salsa-barometer'),
+            $label: $wrapper.find('.salsa-barometer-label'),
+            $progress_indicator: $wrapper.find('.salsa-barometer-progress'),
+            // Ensure the animation won't take too long.
+            step: config.percent_label ? 1 : config.goal/100,
+            complete: false,
+            value: 0
+          };
+        }
+
+        // Start the animation.
+        setTimeout(progress, progress_conf[0].animation_speed);
+
+        /**
+         * Increases value and width of the progress bar.
+         *
+         * Calls itself after some timeout until the maximum value is reached.
+         */
+        function progress() {
+          var all_complete = true;
+          for (var i = 0; i < progress_conf.length; i++) {
+            // The total is either a percent amount of the goal or the passed
+            // total if label is counted up in absolute parts.
+            var total =  stack[i].config.percent_label ? parseInt(stack[i].config.total/stack[i].config.goal * 100) : stack[i].config.total;
+            if (!stack[i].complete) {
+              // Increase the value for 1% point and store it on the stack.
+              stack[i].value += stack[i].step;
+              // Also increase the width of the progress bar.
+              stack[i].$progress_indicator.css('width', Math.min(100, parseInt(stack[i].value/stack[i].step)) + '%');
+              // Don't print fractals, only integers. If percent label is set
+              // for the entity add the % sign to the label.
+              var label = stack[i].config.percent_label ? parseInt(stack[i].value) + '%' : parseInt(stack[i].value);
+              stack[i].$label.text(label);
+              all_complete = false;
+            }
+
+            // Loop until the total is reached or the value exceeds 100%.
+            if (!stack[i].complete && (stack[i].value >= total || parseInt(stack[i].value/stack[i].step) >= 100)) {
+              // Display label that was set on the server.
+              stack[i].$label.text(Drupal.t(stack[i].config.total_string, stack[i].config.total_args));
+              // Mark current progress bar as done.
+              stack[i].complete = true;
+            }
+          }
+
+          if (!all_complete) {
+            // Loop.
+            setTimeout(progress, stack[0].config.animation_speed);
+          }
+        }
+      }
+
+    }
+  }
+}(jQuery));
diff --git a/theme/salsa_progress_bar.css b/theme/salsa_progress_bar.css
new file mode 100644
index 0000000..b85cbad
--- /dev/null
+++ b/theme/salsa_progress_bar.css
@@ -0,0 +1,41 @@
+/**
+ * @file
+ * CSS style definitions for salsa barometer/progress bar.
+ */
+
+.salsa-barometer-progress {
+  background-color: #598EDE;
+  position: absolute;
+  height: 22px;
+  -webkit-border-radius: 15px;
+  -moz-border-radius: 15px;
+  border-radius: 15px;
+}
+
+.salsa-barometer {
+  background-color: #C3C3C3;
+  border: 1px solid #000;
+  width: 30%;
+  position: relative;
+  height: 22px;
+  -webkit-border-radius: 15px;
+  -moz-border-radius: 15px;
+  border-radius: 15px;
+}
+
+.salsa-donation-goal {
+  font-weight: bold;
+  margin-bottom: 10px;
+}
+
+.salsa-barometer-label {
+  position: absolute;
+  height: 20px;
+  z-index: 1;
+  font-weight: bold;
+  padding: 0px 0px 2px 10px;
+}
+
+.salsa-barometer-wrapper {
+  margin-bottom: 1em;
+}
