Index: flag.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/flag/Attic/flag.module,v
retrieving revision 1.11.2.72.2.11
diff -u -r1.11.2.72.2.11 flag.module
--- flag.module	18 Sep 2009 22:30:28 -0000	1.11.2.72.2.11
+++ flag.module	28 Sep 2009 01:15:53 -0000
@@ -57,6 +57,25 @@
     'access arguments' => array('administer flags'),
     'file' => 'includes/flag.admin.inc',
     'type' => MENU_LOCAL_TASK,
+    'weight' => 1,
+  );
+  $items['admin/build/flags/import'] = array(
+    'title' => 'Import',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('flag_import_form'),
+    'access arguments' => array('administer flags'),
+    'type' => MENU_LOCAL_TASK,
+    'file' => 'includes/flag.export.inc',
+    'weight' => 2,
+  );
+  $items['admin/build/flags/export'] = array(
+    'title' => 'Export',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('flag_export_form'),
+    'access arguments' => array('administer flags'),
+    'type' => MENU_LOCAL_TASK,
+    'file' => 'includes/flag.export.inc',
+    'weight' => 3,
   );
   $items['flag'] = array(
     'title' => 'Flag',
@@ -101,6 +120,19 @@
 }
 
 /**
+ * Implementation of hook_features_api().
+ */
+function flag_features_api() {
+  return array(
+    'flag' => array(
+      'feature_source' => TRUE,
+      'default_hook' => 'flag_default_flags',
+      'file' => drupal_get_path('module', 'flag') . '/includes/flag.features.inc',
+    ),
+  );
+}
+
+/**
  * Implementation of hook_perm().
  */
 function flag_perm() {
@@ -934,6 +966,7 @@
       }
     }
   }
+  return FALSE;
 }
 
 /**
@@ -1169,7 +1202,7 @@
     $flag_names = _flag_get_flag_names();
     $result = db_query("SELECT * FROM {flag_content} WHERE content_type = '%s' AND content_id = %d ORDER BY timestamp DESC", $content_type, $content_id);
     while ($flag_content = db_fetch_object($result)) {
-      // Build a list of flaggings for all flags by user. 
+      // Build a list of flaggings for all flags by user.
       $content_flags[$content_type][$content_id]['users'][$flag_content->uid][$flag_names[$flag_content->fid]] = $flag_content;
       // Build a list of flaggings for each individual flag.
       $content_flags[$content_type][$content_id]['flags'][$flag_names[$flag_content->fid]][$flag_content->uid] = $flag_content;
Index: flag.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/flag/Attic/flag.inc,v
retrieving revision 1.1.2.30.2.7
diff -u -r1.1.2.30.2.7 flag.inc
--- flag.inc	27 Sep 2009 22:59:00 -0000	1.1.2.30.2.7
+++ flag.inc	28 Sep 2009 01:15:53 -0000
@@ -761,9 +761,11 @@
   function save() {
     if (isset($this->fid)) {
       $this->update();
+      $this->is_new = FALSE;
     }
     else {
       $this->insert();
+      $this->is_new = TRUE;
     }
   }
 
Index: includes/flag.admin.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/flag/includes/Attic/flag.admin.inc,v
retrieving revision 1.1.4.2.2.5
diff -u -r1.1.4.2.2.5 flag.admin.inc
--- includes/flag.admin.inc	27 Sep 2009 22:59:01 -0000	1.1.4.2.2.5
+++ includes/flag.admin.inc	28 Sep 2009 01:15:53 -0000
@@ -24,8 +24,9 @@
   // Build out the list of normal, database flags.
   foreach ($flags as $flag) {
     $ops = theme('links', array(
-      'flags_edit' =>  array('title' => t('edit'), 'href' => "admin/build/flags/edit/". $flag->name),
-      'flags_delete' =>  array('title' => t('delete'), 'href' => "admin/build/flags/delete/". $flag->name),
+      'flags_edit' =>  array('title' => t('edit'), 'href' => 'admin/build/flags/edit/' . $flag->name),
+      'flags_delete' =>  array('title' => t('delete'), 'href' => 'admin/build/flags/delete/' . $flag->name),
+      'flags_export' =>  array('title' => t('export'), 'href' => 'admin/build/flags/export/' . $flag->name),
     ));
 
     $roles = array_flip(array_intersect(array_flip(user_roles()), $flag->roles));
@@ -52,7 +53,7 @@
   foreach ($default_flags as $name => $flag) {
     if (!isset($flags[$name])) {
       $ops = theme('links', array(
-        'flags_enable' =>  array('title' => t('enable'), 'href' => "admin/build/flags/edit/". $flag->name),
+        'flags_enable' =>  array('title' => t('enable'), 'href' => 'admin/build/flags/edit/' . $flag->name),
       ));
 
       $roles = array_flip(array_intersect(array_flip(user_roles()), $flag->roles));
Index: includes/flag.export.inc
===================================================================
RCS file: includes/flag.export.inc
diff -N includes/flag.export.inc
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ includes/flag.export.inc	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,190 @@
+<?php
+// $Id$
+
+/**
+ * @file
+ * Import/Export functionality provided by Flag module.
+ */
+
+/**
+ * Export a flag to code.
+ *
+ * @param $flags
+ *   An array of flag objects.
+ * @param $module
+ *   Optional. The name of the module that will be created if exporting to use
+ *   in hook_flag_default_flags().
+ */
+function flag_export_flags($flags = array(), $module = '') {
+  $output = array();
+  $output = '$flags = array();'. "\n";
+  foreach ($flags as $flag) {
+    $new_flag = (array) $flag;
+
+    if (!empty($module)) {
+      // Even though Flag adds the module name itself later, we add the module
+      // name here for reference by other modules (such as Features).
+      $new_flag['module'] = $module;
+      // Lock the flag name, as is normally desired by modules using
+      // hook_flag_default_flags(), and needed by Features.
+      $new_flag['locked'] = array('name');
+    }
+    // Allow other modules to change the exported flag.
+    drupal_alter('flag_export', $new_flag);
+
+    // Remove the flag ID.
+    unset($new_flag['fid']);
+
+    $output .= '// Exported flag: "'. check_plain($flag->get_title()) . '"' . ".\n";
+    $output .= '$flags[] = ' . var_export($new_flag, TRUE) . ";\n";
+  }
+  $output .= 'return $flags;';
+  return $output;
+}
+
+/**
+ * Form to import a flag.
+ */
+function flag_import_form() {
+  $form = array();
+
+  $form['import'] = array(
+    '#title' => t('Flag import code'),
+    '#type' => 'textarea',
+    '#default_value' => '',
+    '#rows' => 15,
+    '#required' => TRUE,
+    '#description' => t('Paste the code from a <a href="@export-url">flag export</a> here to import it into you site. Flags imported with the same name will update existing flags. Flags with a new name will be created.', array('@export-url' => url('admin/build/flags/export'))),
+  );
+  $form['submit'] = array(
+    '#value' => t('Import'),
+    '#type' => 'submit',
+  );
+
+  return $form;
+}
+
+/**
+ * Validate handler; Import a flag.
+ */
+function flag_import_form_validate($form, &$form_state) {
+  $flags = array();
+  ob_start();
+  eval($form_state['values']['import']);
+  ob_end_clean();
+
+  if (!isset($flags) || !is_array($flags)) {
+    form_set_error('import', t('A valid list of flags could be found in the import code.'));
+    return;
+  }
+
+  // Create the flag object.
+  foreach ($flags as $config) {
+    $new_flag = flag_flag::factory_by_array($config);
+
+    // Give new flags with the same name a matching FID, which tells Flag to
+    // update the existing flag, rather than creating a new one.
+    if ($existing_flag = flag_get_flag($new_flag->name)) {
+      $new_flag->fid = $existing_flag->fid;
+    }
+
+    if ($errors = $new_flag->validate()) {
+      $message = t('The import of the %flag flag failed because the following errors were encountered during the import:', array('%flag' => $new_flag->name));
+      $message_errors = array();
+      foreach ($errors as $field => $field_errors) {
+        foreach ($field_errors as $error) {
+          $message_errors[] = $error['message'];
+        }
+      }
+      form_set_error('import', $message . theme('item_list', $message_errors));
+    }
+    else {
+      // Save the new flag for the submit handler.
+      $form_state['flags'][] = $new_flag;
+    }
+  }
+}
+
+/**
+ * Submit handler; Import a flag.
+ */
+function flag_import_form_submit($form, &$form_state) {
+  module_load_include('inc', 'flag', 'includes/flag.admin');
+
+  foreach ($form_state['flags'] as $flag) {
+    $flag->save();
+    if (!empty($flag->status)) {
+      $flag->enable();
+    }
+    if ($flag->is_new) {
+      drupal_set_message(t('Flag @name has been imported.', array('@name' => $flag->name)));
+    }
+    else {
+      drupal_set_message(t('Flag @name has been updated.', array('@name' => $flag->name)));
+    }
+  }
+  _flag_clear_cache();
+
+  $form_state['redirect'] = 'admin/build/flags';
+}
+
+/**
+ * Export a flag and display it in a form.
+ */
+function flag_export_form(&$form_state, $flag_name = NULL) {
+  $form = array();
+
+  // Convert a flag name (if any) to the list of export flags.
+  if ($flag = flag_get_flag($flag_name)) {
+    $flags = array($flag);
+  }
+
+  // Display a list of flags to export.
+  if (!isset($flags)) {
+    if (isset($form_state['values']['flags'])) {
+      $flags = array();
+      foreach ($form_state['values']['flags'] as $flag_name) {
+        if ($flag_name && $flag = flag_get_flag($flag_name)) {
+          $flags[] = $flag;
+        }
+      }
+    }
+    else {
+      $form['flags'] = array(
+        '#type' => 'checkboxes',
+        '#title' => t('Flags to export'),
+        '#options' => drupal_map_assoc(array_keys(flag_get_flags())),
+        '#description' => t('Exporting your flags is useful for moving flags from one site to another, or when including your flag definitions in a module.'),
+      );
+      $form['submit'] = array(
+        '#type' => 'submit',
+        '#value' => t('Export'),
+      );
+    }
+  }
+
+  if (isset($flags)) {
+    $code = flag_export_flags($flags);
+
+    // Link to the Features page if module is present, otherwise link to the
+    // Drupal project page.
+    $features_link = module_exists('features') ? url('admin/build/features') : url('http://drupal.org/project/features');
+
+    $form['export'] = array(
+      '#type' => 'textarea',
+      '#title' => t('Flag exports'),
+      '#description' => t('Use the exported code to later <a href="@import-flag">import</a> it. Exports can be included in modules using <a href="http://drupal.org/node/305086#default-flags">hook_flag_default_flags()</a> or using the <a href="@features-url">Features</a> module.', array('@import-flag' => url('admin/build/flags/import'), '@features-url' => $features_link)),
+      '#value' => $code,
+      '#rows' => 15,
+    );
+  }
+
+  return $form;
+}
+
+/**
+ * Submit handler; Rebuild the export form after the list of flags has been set.
+ */
+function flag_export_form_submit($form, &$form_state) {
+  $form_state['rebuild'] = TRUE;
+}
Index: includes/flag.features.inc
===================================================================
RCS file: includes/flag.features.inc
diff -N includes/flag.features.inc
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ includes/flag.features.inc	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,97 @@
+<?php
+// $Id$
+
+/**
+ * @file
+ * Features integration for Flag module.
+ */
+
+/**
+ * Implementation of hook_features_export().
+ */
+function flag_features_export($data, &$export, $module_name = '') {
+  $pipe = array();
+
+  // Add flag module as a dependency.
+  $export['dependencies']['features'] = 'flag';
+
+  // Ensure the modules that provide the flag are included as dependencies.
+  $modules = flag_features_providing_module();
+  foreach ($data as $key => $flag) {
+    // Get the module that provided the flag definition.
+    $flag = flag_get_flag($flag);
+    $module = $modules[$flag->content_type];
+    $export['dependencies'][$module] = $module;
+    $export['features']['flag'][$flag->name] = $flag->name;
+
+    // Add the content types related to the flag.
+    if (!empty($flag->types)) {
+      foreach ($flag->types as $type) {
+        // Add a pipe for dependencies.
+        $pipe[$flag->content_type][] = $type;
+      }
+    }
+  }
+
+  return $pipe;
+}
+
+/**
+ * Implementation of hook_features_export_options().
+ */
+function flag_features_export_options() {
+  $options = array();
+  // Get all flags.
+  foreach (flag_get_flags() as $name => $flag) {
+    $options[$name] = ucfirst(check_plain($flag->content_type)) .': '. check_plain($flag->title);
+  }
+  return $options;
+}
+
+/**
+ * Implementation of hook_features_export_render().
+ */
+function flag_features_export_render($module = 'foo', $data, $features_export) {
+  $code = flag_export_flags($data, $features_export['name']);
+  return array('flag_default_flags' => $code);
+}
+
+/**
+ * Implementation of hook_features_revert().
+ *
+ * @param $module
+ *   The name of module for which to revert content.
+ */
+function flag_features_revert($module = NULL) {
+  // Get default flags from features.
+  if (module_hook($module, 'flag_default_flags')) {
+    module_load_include('inc', 'flag', '/includes/flag.admin');
+    $default_flags = module_invoke($module, 'flag_default_flags');
+
+    // Delete flags that are defined in code.
+    foreach ($default_flags as $default_flag) {
+      $current_flag = flag_get_flag($default_flag['name']);
+      $current_flag->delete();
+    }
+    _flag_clear_cache();
+  }
+  else {
+    drupal_set_message(t('Could not load default flag.'), 'error');
+    return FALSE;
+  }
+  return TRUE;
+}
+
+/**
+ * Helper function; Retrieve the providing modules defining the flags.
+ */
+function flag_features_providing_module() {
+  $modules = array();
+  $hook = 'flag_definitions';
+  foreach (module_implements($hook) as $module) {
+    foreach (module_invoke($module, $hook) as $key => $value) {
+      $modules[$key] = $module;
+    }
+  }
+  return $modules;
+}
