Index: feedapi_mapper.admin.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/feedapi_mapper/Attic/feedapi_mapper.admin.inc,v
retrieving revision 1.1.2.1
diff -u -p -r1.1.2.1 feedapi_mapper.admin.inc
--- feedapi_mapper.admin.inc	4 Aug 2009 20:03:52 -0000	1.1.2.1
+++ feedapi_mapper.admin.inc	6 Aug 2009 15:22:38 -0000
@@ -96,6 +110,43 @@ function feedapi_mapper_delete_form_subm
 }
 
 /**
+ * Reverts the mapping to the version that lies in the .inc file.
+ */
+function feedapi_mapper_revert($form_state, $param) {
+  $form = array();
+  $key = base64_decode($encoded_key);
+  if (is_string($param)) {
+    $node = new stdClass();
+    $node->type = str_replace('-', '_', $param);
+    $path = 'admin/content/node-type/'. $param .'/map';
+  }
+  else {
+    $node = $param;
+    $path = "node/{$node->nid}/map";
+  }
+
+  $form['#node'] = $node;
+  $form['#redirect'] = $path;
+  $form['#source'] = $key;
+
+  return confirm_form($form,
+    t('Revert this mapping?'),
+    $path,
+    t('Are you sure you would like to revert the mapping to the exported one? The changes that you made in this mapping will be lost.'),
+    t('Revert'), t('Cancel')
+  );
+}
+
+/**
+ * Submission callback for feedapi_mapper_revert.
+ */
+
+function feedapi_mapper_revert_submit($form, &$form_state) {
+  $param = isset($form['#node']->nid) && _feedapi_mapper_is_overridden($form['#node']->nid) ? $form['#node']->nid : $form['#node']->type;
+  feedapi_mapper_delete_mapping($param);
+}
+
+/**
  * Form callback confirmation form for fall back to default.
  */
 function feedapi_mapper_default_form($form_state, $feed_node) {
@@ -203,9 +254,23 @@ function feedapi_mapper_form($form_state
     $override = t('This mapping is the standard content-type mapping. Any changes will affect all content-types.') .' '. l(t('Override.'), 'node/'. $feed_node->nid .'/map/override');
     $form['#override'] = FALSE;
   }
+
+  if ($mapping['export_type'] === EXPORT_IN_DATABASE) {
+    $revert = t('The mapping comes from the database.');
+  }
+  if ($mapping['export_type'] === EXPORT_IN_CODE) {
+    $revert = t('The mapping comes from exported code.');
+  }
+  if ($mapping['export_type'] === (EXPORT_IN_CODE | EXPORT_IN_DATABASE)) {
+    $revert = t('The mapping comes from the database which overwrites the exported code.') . l(t('Revert to the exported mapping.'), 'node/'. $feed_node->nid .'/map/revert');
+  }
+
   $form['override'] = array(
     '#value' => $override,
   );
+  $form['revert'] = array(
+    '#value' => '<br />'. $revert,
+  );
 
   // Create a placeholder for mapping form elements. This will be populated in
   // theme_feedapi_mapper_form().
@@ -308,3 +370,21 @@ function feedapi_mapper_form_submit($for
   $param = ($form['#node']->nid && $form['#override']) ? $form['#node']->nid : $form['#node']->type;
   feedapi_mapper_add_mapping($param, $form_state['values']['source'], $form_state['values']['target'], $form_state['values']['unique']);
 }
+
+/**
+ * Callback function for hook_menu().
+ */
+function feedapi_mapper_export_page($form_state, $param) {
+  $param = is_object($param) ? $param->nid : $param;
+  ctools_include('export');
+  $mapping = array();
+  $type = is_string($node) ? $node : $node->nid;
+  $mapping = ctools_export_object('feedapi_mapper', array_pop(ctools_export_load_object('feedapi_mapper', 'conditions', array('param' => $param))));
+  $form['show'] = array(
+    '#title' => t('PHP code'),
+    '#type' => 'textarea',
+    '#default_value' => $mapping,
+    '#description' => t('To import the mapping to another site you should put the code above into a hook_feedapi_mapper_default() implementation.'),
+  );
+  return $form;
+}
Index: feedapi_mapper.info
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/feedapi_mapper/feedapi_mapper.info,v
retrieving revision 1.2.2.1
diff -u -p -r1.2.2.1 feedapi_mapper.info
--- feedapi_mapper.info	15 Jul 2009 17:48:00 -0000	1.2.2.1
+++ feedapi_mapper.info	6 Aug 2009 15:22:38 -0000
@@ -2,5 +2,6 @@
 name = FeedAPI Mapper
 description = "Maps feed item elements to node fields."
 dependencies[] = feedapi
+dependencies[] = ctools
 package = FeedAPI Add On
 core = 6.x
\ No newline at end of file
Index: feedapi_mapper.install
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/feedapi_mapper/feedapi_mapper.install,v
retrieving revision 1.2.2.1
diff -u -p -r1.2.2.1 feedapi_mapper.install
--- feedapi_mapper.install	15 Jul 2009 17:48:00 -0000	1.2.2.1
+++ feedapi_mapper.install	6 Aug 2009 15:22:38 -0000
@@ -7,11 +7,22 @@
 function feedapi_mapper_schema() {
   $schema['feedapi_mapper'] = array(
     'description' => 'Stores data for the feedapi mapper',
+    'export' => array(
+      'key' => 'param',
+      'identifier' => 'feedapi_mapper',
+      'default hook' => 'feedapi_mapper_default',  // Function hook name.
+      'api' => array(
+        'owner' => 'feedapi_mapper',
+        'api' => 'feedapi_mapper_default',  // Base name for api include files.
+        'minimum_version' => 1,
+        'current_version' => 1,
+      ),
+    ),
     'fields' => array(
-      'nid' => array(
-        'description' => 'The primary identifier for the feed.',
-        'type' => 'int',
-        'unsigned' => TRUE,
+      'param' => array(
+        'description' => 'The identifier of the mapping. Can be a nid or a content-type name.',
+        'type' => 'varchar',
+	'length' => 32,
         'not null' => TRUE),
       'mapping' => array(
         'type' => 'text',
@@ -25,7 +36,7 @@ function feedapi_mapper_schema() {
         'not null' => TRUE,
         'serialize' => TRUE),
       ),
-    'primary key' => array('nid'),
+    'primary key' => array('param'),
   );
   return $schema;
 }
@@ -67,3 +78,19 @@ function feedapi_mapper_update_6201() {
   db_change_field($ret, 'feedapi_mapper', 'mapping', 'mapping', $spec);
   return $ret;
 }
+
+/**
+ * Changes nid field to param to be able to unify per-type and per-node storage of the mappings.
+ */
+function feedapi_mapper_update_6202() {
+  $ret = array();
+  db_change_field($ret, 'feedapi_mapper', 'nid', 'param',
+    array(
+      'description' => 'The identifier of the mapping. Can be a nid or a content-type name.',
+      'type' => 'varchar',
+      'length' => 32,
+      'not null' => TRUE
+    )
+  );
+  return $ret;
+}
Index: feedapi_mapper.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/feedapi_mapper/feedapi_mapper.module,v
retrieving revision 1.2.2.14
diff -u -p -r1.2.2.14 feedapi_mapper.module
--- feedapi_mapper.module	4 Aug 2009 20:03:52 -0000	1.2.2.14
+++ feedapi_mapper.module	6 Aug 2009 15:22:38 -0000
@@ -36,6 +36,34 @@ function feedapi_mapper_menu() {
     'access arguments' => array(1),
     'file' => 'feedapi_mapper.admin.inc',
   );
+  $items['node/%node/map/export'] = array(
+    'title' => 'Export',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('feedapi_mapper_export_page', 1),
+    'type' => MENU_LOCAL_TASK,
+    'access callback' => 'feedapi_mapper_access_mapper',
+    'access arguments' => array(1),
+    'weight' => 2,
+    'file' => 'feedapi_mapper.admin.inc',
+  );
+  $items['node/%node/map/map'] = array(
+    'title' => 'Map',
+    'page callback' => 'feedapi_mapper_page',
+    'page arguments' => array(1),
+    'type' => MENU_DEFAULT_LOCAL_TASK,
+    'access callback' => 'feedapi_mapper_access_mapper',
+    'access arguments' => array(1),
+    'file' => 'feedapi_mapper.admin.inc',
+  );
+  $items['node/%node/map/revert'] = array(
+    'title' => 'Export',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('feedapi_mapper_revert', 1),
+    'access callback' => 'feedapi_mapper_access_mapper',
+    'access arguments' => array(1),
+    'weight' => 2,
+    'file' => 'feedapi_mapper.admin.inc',
+  );
   $items['node/%node/map/default'] = array(
     'title' => 'Default',
     'page callback' => 'drupal_get_form',
@@ -66,6 +94,16 @@ function feedapi_mapper_menu() {
       'access arguments' => array(3),
       'file' => 'feedapi_mapper.admin.inc',
       );
+    $items['admin/content/node-type/'. $type_url_str .'/map/map'] = array(
+      'title' => 'Map',
+      'page callback' => 'feedapi_mapper_page',
+      'page arguments' => array(3),
+      'load arguments' => array(3),
+      'type' => MENU_DEFAULT_LOCAL_TASK,
+      'access callback' => 'feedapi_mapper_access_mapper',
+      'access arguments' => array(3),
+      'file' => 'feedapi_mapper.admin.inc',
+    );
     $items['admin/content/node-type/'. $type_url_str .'/map/delete/%'] = array(
       'title' => 'Delete',
       'page callback' => 'drupal_get_form',
@@ -76,6 +114,16 @@ function feedapi_mapper_menu() {
       'access arguments' => array(3),
       'file' => 'feedapi_mapper.admin.inc',
     );
+    $items['admin/content/node-type/'. $type_url_str .'/map/export'] = array(
+      'title' => 'Export',
+      'page callback' => 'drupal_get_form',
+      'page arguments' => array('feedapi_mapper_export_page', 3),
+      'type' => MENU_LOCAL_TASK,
+      'access callback' => 'feedapi_mapper_access_mapper',
+      'access arguments' => array(3),
+      'weight' => 2,
+      'file' => 'feedapi_mapper.admin.inc',
+    );
   }
   return $items;
 }
@@ -231,30 +279,21 @@ function feedapi_mapper_get_element($pat
  * A boolean value that specifies whether the given $source should be unique.
  */
 function feedapi_mapper_add_mapping($param, $source, $target, $unique) {
-  if (is_numeric($param)) {
-    $map = db_fetch_array(db_query('SELECT mapping, unique_elements, nid FROM {feedapi_mapper} WHERE nid = %d', $param));
-    if (is_array($map)) {
-      $map['mapping'] = unserialize($map['mapping']);
-      $map['unique_elements'] = unserialize($map['unique_elements']);
-      $map['mapping'][$source] = $target;
-      $map['unique_elements'][$source] = $unique;
-      drupal_write_record('feedapi_mapper', $map, 'nid');
-    }
-    else {
-      $map = array(
-        'nid' => $param,
-        'mapping' => array($source => $target),
-        'unique_elements' => array($source => $unique),
-      );
-      drupal_write_record('feedapi_mapper', $map);
-    }
-  }
-  else if (is_string($param)) {
-    $variable = 'feedapi_mapper_mapping_'. $param;
-    $map = variable_get($variable, array());
-    $map['mapping'][$source] = $target;
-    $map['unique'][$source] = $unique;
-    variable_set($variable, $map);
+	$map = db_fetch_array(db_query("SELECT mapping, unique_elements, param FROM {feedapi_mapper} WHERE param = '%s'", $param));
+	if (is_array($map)) {
+		$map['mapping'] = unserialize($map['mapping']);
+		$map['unique_elements'] = unserialize($map['unique_elements']);
+		$map['mapping'][$source] = $target;
+		$map['unique_elements'][$source] = $unique;
+		drupal_write_record('feedapi_mapper', $map, 'param');
+	}
+	else {
+    $map = array(
+      'param' => $param,
+      'mapping' => array($source => $target),
+      'unique_elements' => array($source => $unique),
+    );
+    drupal_write_record('feedapi_mapper', $map);
   }
 }
 
@@ -267,14 +306,9 @@ function feedapi_mapper_add_mapping($par
  *   Mapping object like returned from feedapi_mapper_load_mapping();
  */
 function feedapi_mapper_save_mapping($param, $mapping) {
-  if (is_numeric($param)) {
-    feedapi_mapper_delete_mapping($param);
-    $mapping['nid'] = $param;
-    drupal_write_record('feedapi_mapper', $mapping);
-  }
-  else {
-    variable_set('feedapi_mapper_mapping_'. $param, $mapping);
-  }
+  feedapi_mapper_delete_mapping($param);
+  $mapping['param'] = $param;
+  drupal_write_record('feedapi_mapper', $mapping);
 }
 
 /**
@@ -282,29 +316,15 @@ function feedapi_mapper_save_mapping($pa
  */
 function feedapi_mapper_delete_mapping($param, $source = NULL) {
   if ($source === NULL) {
-    if (is_numeric($param)) {
-      db_query('DELETE FROM {feedapi_mapper} WHERE nid = %d', $param);
-    }
-    else {
-      $map = variable_del('feedapi_mapper_mapping_'. $param);
-    }
+    db_query("DELETE FROM {feedapi_mapper} WHERE param = '%s'", $param);
   }
   else {
-    if (is_numeric($param)) {
-      if ($map = db_fetch_array(db_query('SELECT nid, mapping, unique_elements FROM {feedapi_mapper} WHERE nid = %d', $param))) {
-        $map['mapping'] = unserialize($map['mapping']);
-        $map['unique_elements'] = unserialize($map['unique_elements']);
-        unset($map['mapping'][$source]);
-        unset($map['unique_elements'][$source]);
-        drupal_write_record('feedapi_mapper', $map, 'nid');
-      }
-    }
-    else if (is_string($param)) {
-      $variable = 'feedapi_mapper_mapping_'. $param;
-      $map = variable_get($variable, array());
+    if ($map = db_fetch_array(db_query("SELECT mapping, unique_elements, param FROM {feedapi_mapper} WHERE param = '%s'", $param))) {
+      $map['mapping'] = unserialize($map['mapping']);
+      $map['unique_elements'] = unserialize($map['unique_elements']);
       unset($map['mapping'][$source]);
-      unset($map['unique'][$source]);
-      variable_set($variable, $map);
+      unset($map['unique_elements'][$source]);
+      drupal_write_record('feedapi_mapper', $map, 'param');
     }
   }
 }
@@ -335,30 +355,26 @@ function feedapi_mapper_get_item_node_ty
  *   mapping. FALSE if no mapping is available for the given $feed_node.
  */
 function feedapi_mapper_load_mapping($feed_node) {
-  if ($mapping = _feedapi_mapper_load_mapping($feed_node->nid)) {
-    return $mapping;
+  if (isset($feed_node->nid)) {
+    if ($mapping = _feedapi_mapper_load_mapping($feed_node->nid)) {
+      return $mapping;
+    }
   }
-  return variable_get('feedapi_mapper_mapping_'. $feed_node->type, FALSE);
+  return _feedapi_mapper_load_mapping($feed_node->type);
 }
 
 /**
- * Retrieve mapping for a given feed node nid.
+ * Retrieve mapping for a given param.
  * 
  * Use feedapi_mapper_load_mapping() to retrieve per content_type mapping
  * or per node type mapping automatically depending on availability.
  */
-function _feedapi_mapper_load_mapping($nid) {
-  static $mappings;
-  if (isset($mappings[$nid])) {
-    return $mappings[$nid];
-  }
-  if ($mapping = db_fetch_array(db_query('SELECT mapping, unique_elements FROM {feedapi_mapper} WHERE nid = %d', $nid))) {
+function _feedapi_mapper_load_mapping($param) {
+  ctools_include('export');
+  if ($mapping = ctools_export_load_object('feedapi_mapper', 'conditions', array('param' => $param))) {
+    $mapping = (array) array_pop($mapping);
     if (!empty($mapping['mapping'])) {
-      $mappings[$nid] = array(
-        'mapping' => unserialize($mapping['mapping']),
-        'unique' => unserialize($mapping['unique_elements']),
-      );
-      return $mappings[$nid];
+      return $mapping;
     }
   }
   return FALSE;
@@ -387,11 +403,12 @@ function _feedapi_mapper_is_overridden($
 function _feedapi_mapper_load_mappers() {
   static $loaded = FALSE;
   if (!$loaded) {
-    // Load all feedapi mapper implementations from ./mappers
-    $path = drupal_get_path('module', 'feedapi_mapper') .'/mappers';
-    $files = drupal_system_listing('.*\.inc$', $path, 'name', 0);
+    // Load all feedapi mapper implementations from all the modules' ./mappers
+    $files = drupal_system_listing('.*\.inc$', 'modules', 'name');
     foreach ($files as $file) {
-      require_once("./$file->filename");
+      if (strstr($file->filename, '/mappers/')) {
+	      require_once("./$file->filename");
+      }
     }
     // Rebuild cache.
     module_implements('', FALSE, TRUE);
