Issue #1073106 by scottrouse: Fixed 'Input Format' should be 'Text Format'.
[project/wysiwyg.git] / wysiwyg.module
index 46b5b0c..31f3228 100644 (file)
@@ -1,12 +1,48 @@
 <?php
-// $Id$
 
 /**
  * @file
- * Integrate client-side editors with Drupal.
+ * Integrates client-side editors with Drupal.
  */
 
 /**
+ * Implements hook_entity_info().
+ */
+function wysiwyg_entity_info() {
+  $types['wysiwyg_profile'] = array(
+    'label' => t('Wysiwyg profile'),
+    'base table' => 'wysiwyg',
+    'controller class' => 'WysiwygProfileController',
+    'fieldable' => FALSE,
+    // When loading all entities, DrupalDefaultEntityController::load() ignores
+    // its static cache. Therefore, wysiwyg_profile_load_all() implements a
+    // custom static cache.
+    'static cache' => FALSE,
+    'entity keys' => array(
+      'id' => 'format',
+    ),
+  );
+  return $types;
+}
+
+/**
+ * Controller class for Wysiwyg profiles.
+ */
+class WysiwygProfileController extends DrupalDefaultEntityController {
+  /**
+   * Overrides DrupalDefaultEntityController::attachLoad().
+   */
+  function attachLoad(&$queried_entities, $revision_id = FALSE) {
+    // Unserialize the profile settings.
+    foreach ($queried_entities as $key => $record) {
+      $queried_entities[$key]->settings = unserialize($record->settings);
+    }
+    // Call the default attachLoad() method.
+    parent::attachLoad($queried_entities, $revision_id);
+  }
+}
+
+/**
  * Implementation of hook_menu().
  */
 function wysiwyg_menu() {
@@ -81,7 +117,7 @@ function wysiwyg_theme() {
 function wysiwyg_help($path, $arg) {
   switch ($path) {
     case 'admin/config/content/wysiwyg':
-      $output = '<p>' . t('A Wysiwyg profile is associated with an input format. A Wysiwyg profile defines which client-side editor is loaded with a particular input format, what buttons or themes are enabled for the editor, how the editor is displayed, and a few other editor-specific functions.') . '</p>';
+      $output = '<p>' . t('A Wysiwyg profile is associated with a text format. A Wysiwyg profile defines which client-side editor is loaded with a particular text format, what buttons or themes are enabled for the editor, how the editor is displayed, and a few other editor-specific functions.') . '</p>';
       return $output;
   }
 }
@@ -110,8 +146,14 @@ function wysiwyg_element_info_alter(&$types) {
  */
 function wysiwyg_pre_render_text_format($element) {
   // filter_process_format() copies properties to the expanded 'value' child
-  // element.
-  if (!isset($element['format'])) {
+  // element. Skip this text format widget, if it contains no 'format' or when
+  // the current user does not have access to edit the value.
+  if (!isset($element['format']) || !empty($element['value']['#disabled'])) {
+    return $element;
+  }
+  // Allow modules to programmatically enforce no client-side editor by setting
+  // the #wysiwyg property to FALSE.
+  if (isset($element['#wysiwyg']) && !$element['#wysiwyg']) {
     return $element;
   }
 
@@ -136,10 +178,12 @@ function wysiwyg_pre_render_text_format($element) {
   foreach ($format_field['format']['#options'] as $format_id => $format_name) {
     $format = 'format' . $format_id;
     // Initialize default settings, defaulting to 'none' editor.
-    $settings[$format]['editor'] = 'none';
-    $settings[$format]['status'] = 1;
-    $settings[$format]['toggle'] = 1;
-    $settings[$format]['resizable'] = $resizable;
+    $settings[$format] = array(
+      'editor' => 'none',
+      'status' => 1,
+      'toggle' => 1,
+      'resizable' => $resizable,
+    );
 
     // Fetch the profile associated to this text format.
     $profile = wysiwyg_get_profile($format_id);
@@ -161,15 +205,23 @@ function wysiwyg_pre_render_text_format($element) {
   }
   // Use a hidden element for a single text format.
   if (!$format_field['format']['#access']) {
-    $format_field['guidelines']['format'] = array(
+    $format_field['wysiwyg'] = array(
       '#type' => 'hidden',
       '#name' => $format_field['format']['#name'],
-      '#id' => $format_field['format']['#id'],
       '#value' => $format_id,
-      '#attributes' => array('class' => array('wysiwyg')),
+      '#attributes' => array(
+        'id' => $format_field['format']['#id'],
+        'class' => array('wysiwyg'),
+      ),
     );
-    $format_field['guidelines']['format']['#attached']['js'][] = array(
-      'data' => array('wysiwyg' => array('triggers' => array($format_field['format']['#id'] => $settings))),
+    $format_field['wysiwyg']['#attached']['js'][] = array(
+      'data' => array(
+        'wysiwyg' => array(
+          'triggers' => array(
+            $format_field['format']['#id'] => $settings,
+          ),
+        ),
+      ),
       'type' => 'setting',
     );
   }
@@ -177,7 +229,13 @@ function wysiwyg_pre_render_text_format($element) {
   else {
     $format_field['format']['#attributes']['class'][] = 'wysiwyg';
     $format_field['format']['#attached']['js'][] = array(
-      'data' => array('wysiwyg' => array('triggers' => array($format_field['format']['#id'] => $settings))),
+      'data' => array(
+        'wysiwyg' => array(
+          'triggers' => array(
+            $format_field['format']['#id'] => $settings,
+          ),
+        ),
+      ),
       'type' => 'setting',
     );
   }
@@ -307,7 +365,7 @@ function wysiwyg_load_editor($profile) {
     $path = drupal_get_path('module', 'wysiwyg');
     // Initialize our namespaces in the *header* to do not force editor
     // integration scripts to check and define Drupal.wysiwyg on its own.
-    drupal_add_js($path . '/wysiwyg.init.js', array('weight' => JS_LIBRARY));
+    drupal_add_js($path . '/wysiwyg.init.js', array('group' => JS_LIBRARY));
 
     // The 'none' editor is a special editor implementation, allowing us to
     // attach and detach regular Drupal behaviors just like any other editor.
@@ -560,7 +618,7 @@ function wysiwyg_get_css() {
 
   $files = array();
   foreach (drupal_add_css() as $filepath => $info) {
-    if ($info['weight'] >= CSS_THEME && $info['media'] != 'print') {
+    if ($info['group'] >= CSS_THEME && $info['media'] != 'print') {
       if (file_exists($filepath)) {
         $files[] = base_path() . $filepath;
       }
@@ -570,38 +628,34 @@ function wysiwyg_get_css() {
 }
 
 /**
- * Load profile for a given input format.
+ * Loads a profile for a given text format.
+ *
+ * Since there are commonly not many text formats, and each text format-enabled
+ * form element will possibly have to load every single profile, all existing
+ * profiles are loaded and cached once to reduce the amount of database queries.
  */
 function wysiwyg_profile_load($format) {
-  static $profiles;
-
-  if ($cached = cache_get('wysiwyg_profiles')) {
-    $profiles = $cached->data;
-  }
-  else {
-    $result = db_query('SELECT format, editor, settings FROM {wysiwyg}');
-    foreach ($result as $profile) {
-      $profile->settings = unserialize($profile->settings);
-      $profiles[$profile->format] = $profile;
-    }
-    cache_set('wysiwyg_profiles', $profiles);
-  }
-
+  $profiles = wysiwyg_profile_load_all();
   return (isset($profiles[$format]) ? $profiles[$format] : FALSE);
 }
 
 /**
- * Load all profiles.
+ * Loads all profiles.
  */
 function wysiwyg_profile_load_all() {
-  static $profiles;
+  // entity_load(..., FALSE) does not re-use its own static cache upon
+  // repetitive calls, so a custom static cache is required.
+  // @see wysiwyg_entity_info()
+  $profiles = &drupal_static(__FUNCTION__);
 
   if (!isset($profiles)) {
-    $profiles = array();
-    $result = db_query('SELECT format, editor, settings FROM {wysiwyg}');
-    foreach ($result as $profile) {
-      $profile->settings = unserialize($profile->settings);
-      $profiles[$profile->format] = $profile;
+    // Additional database cache to support alternative caches like memcache.
+    if ($cached = cache_get('wysiwyg_profiles')) {
+      $profiles = $cached->data;
+    }
+    else {
+      $profiles = entity_load('wysiwyg_profile', FALSE);
+      cache_set('wysiwyg_profiles', $profiles);
     }
   }
 
@@ -609,46 +663,105 @@ function wysiwyg_profile_load_all() {
 }
 
 /**
- * Implementation of hook_user().
- */
-function wysiwyg_user($type, &$edit, &$user, $category = NULL) {
-  if ($type == 'form' && $category == 'account') {
-    // @todo http://drupal.org/node/322433
-    $profile = new stdClass;
-    if (isset($profile->settings['user_choose']) && $profile->settings['user_choose']) {
-      $form['wysiwyg'] = array(
-        '#type' => 'fieldset',
-        '#title' => t('Wysiwyg Editor settings'),
-        '#weight' => 10,
-        '#collapsible' => TRUE,
-        '#collapsed' => TRUE,
-      );
-      $form['wysiwyg']['wysiwyg_status'] = array(
-        '#type' => 'checkbox',
-        '#title' => t('Enable editor by default'),
-        '#default_value' => isset($user->wysiwyg_status) ? $user->wysiwyg_status : (isset($profile->settings['default']) ? $profile->settings['default'] : FALSE),
-        '#return_value' => 1,
-        '#description' => t('If enabled, rich-text editing is enabled by default in textarea fields.'),
-      );
-      return array('wysiwyg' => $form);
+ * Deletes a profile from the database.
+ */
+function wysiwyg_profile_delete($format) {
+  db_delete('wysiwyg')
+    ->condition('format', $format)
+    ->execute();
+}
+
+/**
+ * Clear all Wysiwyg profile caches.
+ */
+function wysiwyg_profile_cache_clear() {
+  entity_get_controller('wysiwyg_profile')->resetCache();
+  drupal_static_reset('wysiwyg_profile_load_all');
+  cache_clear_all('wysiwyg_profiles', 'cache');
+}
+
+/**
+ * Implements hook_form_FORM_ID_alter().
+ */
+function wysiwyg_form_user_profile_form_alter(&$form, &$form_state, $form_id) {
+  $account = $form['#user'];
+  $user_formats = filter_formats($account);
+  $options = array();
+  $options_default = array();
+  foreach (wysiwyg_profile_load_all() as $format => $profile) {
+    // Only show profiles that have user_choose enabled.
+    if (!empty($profile->settings['user_choose']) && isset($user_formats[$format])) {
+      $options[$format] = check_plain($user_formats[$format]->name);
+      if (wysiwyg_user_get_status($profile, $account)) {
+        $options_default[] = $format;
+      }
     }
   }
-  elseif ($type == 'validate' && isset($edit['wysiwyg_status'])) {
-    return array('wysiwyg_status' => $edit['wysiwyg_status']);
+  if (!empty($options)) {
+    $form['wysiwyg']['wysiwyg_status'] = array(
+      '#type' => 'checkboxes',
+      '#title' => t('Text formats enabled for rich-text editing'),
+      '#options' => $options,
+      '#default_value' => $options_default,
+    );
   }
 }
 
-function wysiwyg_user_get_status($profile) {
+/**
+ * Implements hook_user_insert().
+ *
+ * Wysiwyg's user preferences are normally not exposed on the user registration
+ * form, but in case they are manually altered in, we invoke
+ * wysiwyg_user_update() accordingly.
+ */
+function wysiwyg_user_insert(&$edit, $account, $category) {
+  wysiwyg_user_update($edit, $account, $category);
+}
+
+/**
+ * Implements hook_user_update().
+ */
+function wysiwyg_user_update(&$edit, $account, $category) {
+  if (isset($edit['wysiwyg_status'])) {
+    db_delete('wysiwyg_user')
+      ->condition('uid', $account->uid)
+      ->execute();
+    $query = db_insert('wysiwyg_user')
+      ->fields(array('uid', 'format', 'status'));
+    foreach ($edit['wysiwyg_status'] as $format => $status) {
+      $query->values(array(
+        'uid' => $account->uid,
+        'format' => $format,
+        'status' => (int) (bool) $status,
+      ));
+    }
+    $query->execute();
+  }
+}
+
+function wysiwyg_user_get_status($profile, $account = NULL) {
   global $user;
 
-  if (!empty($profile->settings['user_choose']) && isset($user->wysiwyg_status)) {
-    $status = $user->wysiwyg_status;
+  if (!isset($account)) {
+    $account = $user;
+  }
+
+  // Default wysiwyg editor status information is only required on forms, so we
+  // do not pre-emptively load and attach this information on every user_load().
+  if (!isset($account->wysiwyg_status)) {
+    $account->wysiwyg_status = db_query("SELECT format, status FROM {wysiwyg_user} WHERE uid = :uid", array(
+      ':uid' => $account->uid,
+    ))->fetchAllKeyed();
+  }
+
+  if (!empty($profile->settings['user_choose']) && isset($account->wysiwyg_status[$profile->format])) {
+    $status = $account->wysiwyg_status[$profile->format];
   }
   else {
     $status = isset($profile->settings['default']) ? $profile->settings['default'] : TRUE;
   }
 
-  return $status;
+  return (bool) $status;
 }
 
 /**
@@ -964,4 +1077,3 @@ function _wysiwyg_process_include($module, $identifier, $path, $hook) {
 /**
  * @} End of "defgroup wysiwyg_api".
  */
-