? DELETE
? MISC-FIELD-CHANGES-REAPPLY.patch
? Makefile
? article.macro
? d6-50-nodes.sql.gz
? d7-50-nodes-new.sql.gz
? d7-50-nodes.sql.gz
? head.kpf
? patches
? test.php
? modules/field/field.bulk.update.inc
? scripts/OLD-generate-autoload.pl
? scripts/generate-autoload.pl
? sites/all/cck
? sites/all/modules/admin_menu
? sites/all/modules/color
? sites/all/modules/combofield
? sites/all/modules/devel
? sites/all/modules/macro
? sites/all/modules/pbs
? sites/all/modules/pipedream
? sites/all/modules/taint
? sites/default/files
? sites/default/private
? sites/default/settings.php
Index: modules/field/modules/text/text.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/field/modules/text/text.module,v
retrieving revision 1.61
diff -u -F '^[fc]' -r1.61 text.module
--- modules/field/modules/text/text.module	17 Aug 2010 18:25:31 -0000	1.61
+++ modules/field/modules/text/text.module	19 Aug 2010 15:16:33 -0000
@@ -649,3 +649,20 @@ function text_field_prepare_translation(
     }
   }
 }
+
+/**
+ * Implements hook_filter_format_delete().
+ *
+ * When a text format is deleted, the Filter API remembers the old
+ * format's replacement format and uses the replacement when asked to
+ * render text in the old format. Thus, all we really need to do here
+ * is invalidate the field data cache. We could try to be more clever
+ * and only invalid selected cache elements, but input formats are not
+ * deleted that often.
+ *
+ * @todo: Update all text field data items to refer to the new format
+ * directly.
+ */
+function text_filter_format_delete($format, $fallback) {
+  field_cache_clear();
+}
Index: modules/filter/filter.api.php
===================================================================
RCS file: /cvs/drupal/drupal/modules/filter/filter.api.php,v
retrieving revision 1.20
diff -u -F '^[fc]' -r1.20 filter.api.php
--- modules/filter/filter.api.php	26 Jun 2010 01:55:29 -0000	1.20
+++ modules/filter/filter.api.php	19 Aug 2010 15:16:33 -0000
@@ -237,8 +237,12 @@ function hook_filter_format_update($form
  *
  * All modules storing references to text formats have to implement this hook.
  *
- * When a text format is deleted, all content that previously had that format
- * assigned needs to be switched to the passed fallback format.
+ * When a text format is deleted, all content that previously had that
+ * format assigned should to be switched to the passed fallback
+ * format. Alternatively, modules can temporarily rely on the Filter
+ * API to handle deleted formats, but they should still make a best
+ * effort to update their text format references eventually. See
+ * filter_format_delete() for more information.
  *
  * @param $format
  *   The format object of the format being deleted.
Index: modules/filter/filter.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/filter/filter.module,v
retrieving revision 1.338
diff -u -F '^[fc]' -r1.338 filter.module
--- modules/filter/filter.module	17 Aug 2010 13:50:52 -0000	1.338
+++ modules/filter/filter.module	19 Aug 2010 15:16:33 -0000
@@ -148,6 +148,57 @@ function _filter_delete_format_access($f
   return user_access('administer filters') && ($format->format != filter_fallback_format());
 }
 
+ /**
+ * Set the fallback format for a deleted format.
+ *
+ * @param $format_id
+ *   A format that is deleted.
+ * @param $fallback_id
+ *   The fallback format for $format_id.
+ */
+function _filter_set_fallback_format($format_id, $fallback_id) {
+  $deleted = variable_get('filter_deleted_formats', array());
+  // Add the new entry.
+  $deleted[$format_id] = $fallback_id;
+  // Update any previously deleted format whose fallback is $format_id
+  // to fall back to $fallback_id.
+  foreach ($deleted as $k => $v) {
+    if ($v == $format_id) {
+      $deleted[$k] = $fallback_id;
+    }
+  }
+  variable_set('filter_deleted_formats', $deleted);
+}
+
+/**
+ * Get a format's fallback format if it has been deleted.
+ *
+ * @param $format_id
+ *   A format that is deleted.
+ * @return
+ *   The fallback format for $format_id if $format_id has been
+ *   deleted, or $format_id if it has not been deleted.
+ */
+function _filter_get_fallback_format($format_id) {
+  $deleted = variable_get('filter_deleted_formats', array());
+  // Handle a chain of deleted formats.
+  while (isset($deleted[$format_id])) {
+    $format_id = $deleted[$format_id];
+  }
+  return $format_id;
+}
+
+/**
+ * Retrieve the mapping of deleted formats to their fallback format.
+ *
+ * @return
+ *   An associative array mapping deleted format id to fallback format
+ *   id.
+ */
+function filter_get_fallback_formats() {
+  return variable_get('filter_deleted_formats', array());
+}
+
 /**
  * Load a text format object from the database.
  *
@@ -258,6 +309,20 @@ function filter_format_save(&$format) {
 /**
  * Delete a text format.
  *
+ * Modules that manage data associated with a text format should
+ * update their data to refer to the fallback text format by
+ * implementing hook_filter_format_delete(). However, in some cases
+ * this is not possible to do immediately. Therefore, the Filter API
+ * maintains a history of all deleted formats and their corresponding
+ * fallback formats. When the Filter API is asked to operate on a
+ * deleted format, it instead uses the corresponding fallback format.
+ *
+ * The history of deleted formats is available from
+ * filter_get_fallback_formats().
+ *
+ * @todo: This method of handling deleted formats may not be
+ * ideal. See http://drupal.org/node/556022 for a lengthy discussion.
+ *
  * @param $format
  *   The text format object to be deleted.
  * @param $fallback_id
@@ -273,11 +338,16 @@ function filter_format_delete($format, $
     ->condition('format', $format->format)
     ->execute();
 
-  // Allow modules to react on text format deletion.
+  // Determine the fallback format.
   if (empty($fallback_id)) {
     $fallback_id = filter_fallback_format();
   }
   $fallback = filter_format_load($fallback_id);
+
+  // Update the deleted-formats fallback list.
+  _filter_set_fallback_format($format->format, $fallback->format);
+
+  // Allow modules to react on text format deletion.
   module_invoke_all('filter_format_delete', $format, $fallback);
 
   filter_formats_reset();
@@ -618,7 +688,9 @@ function _filter_format_is_cacheable($fo
  *
  * @return
  *   An array of filter objects associated to the given text format, keyed by
- *   filter name.
+ *   filter name. If $format_id has been deleted, the returned array
+ *   is the filter objects for $format_id's fallback format, which are
+ *   the same filters that check_markup() will apply for $format_id.
  */
 function filter_list_format($format_id) {
   $filters = &drupal_static(__FUNCTION__, array());
@@ -631,6 +703,10 @@ function filter_list_format($format_id) 
     }
   }
 
+  // If we're being asked about a format that was previously
+  // deleted, use its fallback format instead.
+  $format_id = _filter_get_fallback_format($format_id);
+
   if (!isset($filters[$format_id])) {
     $format_filters = array();
     foreach ($filters['all'][$format_id] as $name => $filter) {
@@ -681,6 +757,9 @@ function check_markup($text, $format_id 
   if (empty($format_id)) {
     $format_id = filter_fallback_format();
   }
+  // If we're being asked to use a format that was previously
+  // deleted, load its fallback format instead.
+  $format_id = _filter_get_fallback_format($format_id);
   $format = filter_format_load($format_id);
 
   // Check for a cached version of this piece of text.
@@ -819,6 +898,8 @@ function filter_process_format($element)
   if (empty($element['#format'])) {
     $element['#format'] = filter_default_format($user);
   }
+  // If the format has been deleted, use its fallback format.
+  $element['#format'] = _filter_get_fallback_format($element['#format']);
   $element['format']['format'] = array(
     '#type' => 'select',
     '#title' => t('Text format'),
Index: modules/filter/filter.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/filter/filter.test,v
retrieving revision 1.71
diff -u -F '^[fc]' -r1.71 filter.test
--- modules/filter/filter.test	5 Aug 2010 23:53:38 -0000	1.71
+++ modules/filter/filter.test	19 Aug 2010 15:16:33 -0000
@@ -68,6 +68,45 @@ class FilterCRUDTestCase extends DrupalW
   }
 
   /**
+   * Test that when a text format is deleted, calls to check_markup()
+   * using a deleted format use the correct fallback format.
+   */
+  function testTextFormatDeleteFallback() {
+    module_load_include('inc', 'node', 'node.pages');
+
+    $filtered_html_format = db_query_range('SELECT * FROM {filter_format} WHERE name = :name', 0, 1, array(':name' => 'Filtered HTML'))->fetchObject();
+    $full_html_format = db_query_range('SELECT * FROM {filter_format} WHERE name = :name', 0, 1, array(':name' => 'Full HTML'))->fetchObject();
+
+    // Create a node using Full HTML
+    $html_text = '<div>looks different under Full HTML, Filtered HTML, and default fallback format</div>';
+    $settings['type'] = 'article';
+    $settings['uid'] = 1;
+    $settings['body'][LANGUAGE_NONE][0]['value'] = $html_text;
+    $settings['body'][LANGUAGE_NONE][0]['format'] = $full_html_format->format;
+    $node = $this->drupalCreateNode($settings);
+
+    // Verify Full HTML is used.
+    $this->content = drupal_render(node_view($node));
+    $this->assertRaw($html_text, 'Full HTML renders full html');
+    $form = drupal_get_form($node->type . '_node_form', $node);
+    $this->assertEqual($form['body'][LANGUAGE_NONE][0]['#format'], $full_html_format->format, 'Form offers Full HTML as default');
+
+    // Delete Full HTML, replacing it with Filtered HTML.
+    filter_format_delete($full_html_format, $filtered_html_format->format);
+    $this->content = drupal_render(node_view($node));
+    $this->assertRaw(strip_tags($html_text), 'Fallback to Filtered HTML works');
+    $form = drupal_get_form($node->type . '_node_form', $node);
+    $this->assertEqual($form['body'][LANGUAGE_NONE][0]['#format'], $filtered_html_format->format, 'Form offers Filtered HTML as default');
+
+    // Delete Filtered HTML, verify default format is used.
+    filter_format_delete($filtered_html_format);
+    $this->content = drupal_render(node_view($node));
+    $this->assertRaw(check_plain($html_text), 'Fallback to default format works');
+    $form = drupal_get_form($node->type . '_node_form', $node);
+    $this->assertEqual($form['body'][LANGUAGE_NONE][0]['#format'], filter_fallback_format(), 'Form offers fallback format as default');
+  }
+
+  /**
    * Verify that a text format is properly stored.
    */
   function verifyTextFormat($format) {
