changeset 0:548f63d8a41b

Blam, simple MEE cck field type.
author David Eads <eads@chicagotech.org>
date Tue, 10 Mar 2009 13:44:50 -0500
parents
children 814c6ce77297
files mee.info mee.install mee.module
diffstat 3 files changed, 365 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mee.info	Tue Mar 10 13:44:50 2009 -0500
@@ -0,0 +1,8 @@
+; $Id$
+name = Multimedia Editorial Element
+package = CCK
+description = A configurable CCK content type that provides a textarea and drag and drop media library.
+dependencies[] = content
+dependencies[] = dnd
+core = 6.x
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mee.install	Tue Mar 10 13:44:50 2009 -0500
@@ -0,0 +1,27 @@
+<?php
+// $Id;
+
+/**
+ * @file
+ * Implementation of hook_install().
+ */
+ function mee_install() {
+   drupal_load('module', 'content');
+   content_notify('install', 'mee');
+ }
+
+/**
+ * Implementation of hook_uninstall().
+ */
+ function mee_uninstall() {
+   drupal_load('module', 'content');
+   content_notify('uninstall', 'mee');
+ }
+
+/**
+ * Implementation of hook_disable().
+ */
+ function mee_disable() {
+   drupal_load('module', 'content');
+   content_notify('disable', 'mee');
+ }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mee.module	Tue Mar 10 13:44:50 2009 -0500
@@ -0,0 +1,330 @@
+<?php
+// $Id;
+/**
+ * @file
+ * Defines a special textarea, with drag and drop media driven by Scald and 
+ * dnd.module when rich text editing is enabled on the textarea via the 
+ * WYSIWYG API. 
+ */
+
+/**
+ * Implementation of hook_theme().
+ */
+function mee_theme() {
+  $theme = array(
+    'mee_textarea' => array(
+      'arguments' => array('element' => NULL),
+    ),
+    'mee_formatter_default' => array(
+      'arguments' => array('element' => NULL),
+    ),
+  );
+  // @TODO enable!
+  //foreach (scald_contexts() as $context) {
+  //  $theme['mee_formatter_'. $context] = array(
+  //    'arguments' => array('element' => NULL),
+  //    'function' => 'theme_mee_context_formatter',
+  //  );
+  //}
+  return $theme;
+}
+
+/**
+ * Implementation of hook_field_info().
+ */
+function mee_field_info() {
+  return array(
+    'multimedia_editorial_element' => array(
+      'label' => t('Multimedia Editorial Element (MEE)'),
+      'description' => t('MEE combines Scald, WYSIWYG, and DnD to create a multimedia enabled text field.'),
+    ),
+  );
+}
+
+/**
+ * Implementation of hook_field_settings().
+ */
+function mee_field_settings($op, $field) {
+  switch ($op) {
+    case 'form':
+      $form = array();
+      $options = array(0 => t('Plain text'), 1 => t('Filtered text (user selects input format)'));
+      $form['mee_processing'] = array(
+        '#type' => 'radios',
+        '#title' => t('Text processing'),
+        '#default_value' => is_numeric($field['mee_processing']) ? $field['mee_processing'] : 1,
+        '#options' => $options,
+        '#description' => t('Filtered text, with a WYSIWYG editor defined on one or more input formats, is strongly recommended.'),
+      );
+      // @TODO Ask Drupal about available libraries
+      $form['mee_dnd_callback_url'] = array(
+        '#type' => 'textfield',
+        '#title' => t('Library callback URL'),
+        '#default_value' => url($field['mee_dnd_callback_url']) ? $field['mee_dnd_callback_url'] : '',
+        '#description' => t('The absolute URL or relative path of a callback URL that provides proper JSON to the drag and drop library.'),
+      );
+      return $form;
+
+    case 'save':
+      return array('mee_processing', 'mee_dnd_callback_url');
+
+    case 'database columns':
+      $columns['value'] = array('type' => 'text', 'size' => 'big', 'not null' => FALSE, 'sortable' => TRUE);
+      $columns['dnd_callback_url'] = array('type' => 'text', 'size' => 'small', 'not null' => FALSE);
+      if (!empty($field['mee_processing'])) {
+        $columns['format'] = array('type' => 'int', 'unsigned' => TRUE, 'not null' => FALSE);
+      }
+      return $columns;
+
+    case 'views data':
+      return content_views_field_views_data($field);
+  }
+}
+
+/**
+ * Implementation of hook_field().
+ */
+function mee_field($op, &$node, $field, &$items, $teaser, $page) {
+  switch ($op) {
+    case 'sanitize':
+      foreach ($items as $delta => $item) {
+        if (!empty($field['mee_processing'])) {
+          $check = is_null($node) || (isset($node->build_mode) && $node->build_mode == NODE_BUILD_PREVIEW);
+          $text = isset($item['value']) ? check_markup($item['value'], $item['format'], $check) : '';
+        }
+        else {
+          $text = check_plain($item['value']);
+        }
+        $items[$delta]['safe'] = $text;
+      }
+  }
+}
+
+/**
+ * Implementation of hook_content_is_empty().
+ */
+function mee_content_is_empty($item, $field) {
+  if (empty($item['value']) && (string)$item['value'] !== '0') {
+    return TRUE;
+  }
+  return FALSE;
+}
+
+/**
+ * Implementation of hook_field_formatter_info().
+ */
+function mee_field_formatter_info() {
+  $formatters = array(
+    'default' => array(
+      'label' => t('Filtered text'),
+      'field types' => array('multimedia_editorial_element'),
+      'multiple values' => CONTENT_HANDLE_CORE,
+    ),
+    'plain' => array(
+      'label' => t('Plain text'),
+      'field types' => array('multimedia_editorial_element'),
+      'multiple values' => CONTENT_HANDLE_CORE,
+    ),
+  );
+  //@TODO generate context processor based field formatters
+  //foreach (scald_contexts() as $context) {
+  //  $formatters[$context] = array(
+  //    'label' => t('Scald context processor: @context', array('@context' => $context),
+  //    'field types' => 'mee',
+  //  );
+  //}
+  return $formatters; 
+}
+
+function theme_mee_formatter_default($element) {
+  return $element['#item']['safe'];
+}
+
+/**
+ * Theme function for 'plain' text field formatter.
+ */
+function theme_mee_formatter_plain($element) {
+  return strip_tags($element['#item']['safe']);
+}
+
+function theme_mee_context_formatter($element) {
+  return 'foo';
+}
+
+/**
+ * Implementation of hook_widget_info().
+ */
+function mee_widget_info() {
+  return array(
+    'mee_textarea' => array(
+      'label' => t('MEE Textarea'),
+      'field types' => array('multimedia_editorial_element'),
+      'multiple values' => CONTENT_HANDLE_CORE,
+    ),
+  );
+}
+
+/**
+ * Implementation of FAPI hook_elements().
+ *
+ * Any FAPI callbacks needed for individual widgets can be declared here,
+ * and the element will be passed to those callbacks for processing.
+ *
+ * Drupal will automatically theme the element using a theme with
+ * the same name as the hook_elements key.
+ */
+function mee_elements() {
+  return array(
+    'mee_textarea' => array(
+      '#input' => TRUE,
+      '#columns' => array('value', 'format'), '#delta' => 0,
+      '#process' => array('mee_textarea_process', 'dnd_process_textarea'),
+      '#filter_value' => FILTER_FORMAT_DEFAULT,
+    ),
+  );
+}
+
+/**
+ * Implementation of hook_widget_settings().
+ */
+function mee_widget_settings($op, $widget) {
+  switch ($op) {
+    case 'form':
+      $form = array();
+      $rows = (isset($widget['rows']) && is_numeric($widget['rows'])) ? $widget['rows'] : 5;
+      $size = (isset($widget['size']) && is_numeric($widget['size'])) ? $widget['size'] : 60;
+      $form['rows'] = array(
+        '#type' => 'textfield',
+        '#title' => t('Rows'),
+        '#default_value' => $rows,
+        '#element_validate' => array('_mee_widget_settings_row_validate'),
+        '#required' => TRUE,
+      );
+      $form['size'] = array('#type' => 'hidden', '#value' => $size);
+      return $form;
+
+    case 'save':
+      return array('rows', 'size');
+  }
+}
+
+function _mee_widget_settings_row_validate($element, &$form_state) {
+  $value = $form_state['values']['rows'];
+  if (!is_numeric($value) || intval($value) != $value || $value <= 0) {
+    form_error($element, t('"Rows" must be a positive integer.'));
+  }
+}
+
+function _mee_widget_settings_size_validate($element, &$form_state) {
+  $value = $form_state['values']['size'];
+  if (!is_numeric($value) || intval($value) != $value || $value <= 0) {
+    form_error($element, t('"Size" must be a positive integer.'));
+  }
+}
+
+/**
+ * Implementation of hook_widget().
+ *
+ * Attach a single form element to the form. It will be built out and
+ * validated in the callback(s) listed in hook_elements. We build it
+ * out in the callbacks rather than here in hook_widget so it can be
+ * plugged into any module that can provide it with valid
+ * $field information.
+ *
+ * Content module will set the weight, field name and delta values
+ * for each form element. This is a change from earlier CCK versions
+ * where the widget managed its own multiple values.
+ *
+ * If there are multiple values for this field, the content module will
+ * call this function as many times as needed.
+ *
+ * @param $form
+ *   the entire form array, $form['#node'] holds node information
+ * @param $form_state
+ *   the form_state, $form_state['values'][$field['field_name']]
+ *   holds the field's form values.
+ * @param $field
+ *   the field array
+ * @param $items
+ *   array of default values for this field
+ * @param $delta
+ *   the order of this item in the array of subelements (0, 1, 2, etc)
+ *
+ * @return
+ *   the form item for a single element for this field
+ */
+function mee_widget(&$form, &$form_state, $field, $items, $delta = 0) {
+  $element = array(
+    '#type' => $field['widget']['type'],
+    '#default_value' => isset($items[$delta]) ? $items[$delta] : '',
+  );
+  return $element;
+}
+
+/**
+ * Process an individual element.
+ *
+ * Build the form element. When creating a form using FAPI #process,
+ * note that $element['#value'] is already set.
+ *
+ * The $fields array is in $form['#field_info'][$element['#field_name']].
+ */
+function mee_textarea_process($element, $edit, $form_state, $form) {
+  drupal_add_css(drupal_get_path('module', 'mee') .'/css/mee.css');
+
+  $field = $form['#field_info'][$element['#field_name']];
+  $field_key   = $element['#columns'][0];
+  $element[$field_key] = array(
+    '#type' => 'textarea',
+    '#default_value' => isset($element['#value'][$field_key]) ? $element['#value'][$field_key] : NULL,
+    '#rows' => !empty($field['widget']['rows']) ? $field['widget']['rows'] : 10,
+    '#weight' => 0,
+    // The following values were set by the content module and need
+    // to be passed down to the nested element.
+    '#title' => $element['#title'],
+    '#description' => $element['#description'],
+    '#required' => $element['#required'],
+    '#field_name' => $element['#field_name'],
+    '#type_name' => $element['#type_name'],
+    '#delta' => $element['#delta'],
+    '#columns' => $element['#columns'],
+    '#prefix' => '<div class="mee-wrap-editor-library">',
+    '#suffix' => '</div>',
+    '#dnd-enabled' => TRUE,
+    '#dnd-settings' => array(
+      'drop_selector' => '#'. $element['#id'] .' .drop',
+      'url' => $field['mee_dnd_callback_url'],
+    ),
+  );
+
+  if (!empty($field['mee_processing'])) {
+    $filter_key  = (count($element['#columns']) == 2) ? $element['#columns'][1] : 'format';
+    $format = isset($element['#value'][$filter_key]) ? $element['#value'][$filter_key] : FILTER_FORMAT_DEFAULT;
+    $parents = array_merge($element['#parents'] , array($filter_key));
+    $element[$filter_key] = filter_form($format, 1, $parents);
+  }
+
+  // Used so that hook_field('validate') knows where to flag an error.
+  $element['_error_element'] = array(
+    '#type' => 'value',
+    '#value' => implode('][', array_merge($element['#parents'], array($field_key))),
+  );
+
+
+  return $element;
+}
+
+/**
+ * FAPI theme for an individual text elements.
+ *
+ * The textfield or textarea is already rendered by the
+ * textfield or textarea themes and the html output
+ * lives in $element['#children']. Override this theme to
+ * make custom changes to the output.
+ *
+ * $element['#field_name'] contains the field name
+ * $element['#delta]  is the position of this element in the group
+ */
+function theme_mee_textarea($element) {
+  return $element['#children'];
+}