You are here

atom_reference.module in Scald: Media Management made easy 7

Defines a new field type, allowing to directly reference Scald Atoms from a node.

File

modules/fields/atom_reference/atom_reference.module
View source
<?php

/**
 * @file
 *   Defines a new field type, allowing to directly reference Scald Atoms from
 *   a node.
 */

/**
 * Implements hook_library().
 */
function atom_reference_library() {
  $path = drupal_get_path('module', 'atom_reference');
  $libraries['library'] = array(
    'title' => 'Atom reference library',
    'website' => 'http://drupal.org/project/scald',
    'version' => '1.x',
    'js' => array(
      $path . '/atom_reference.js' => array(),
      drupal_get_path('module', 'ctools') . '/js/dropbutton.js' => array(),
    ),
    'css' => array(
      $path . '/atom_reference.css' => array(),
      drupal_get_path('module', 'ctools') . '/css/dropbutton.css' => array(),
      drupal_get_path('module', 'ctools') . '/css/button.css' => array(),
    ),
  );
  return $libraries;
}

/**
 * Implements hook_field_info().
 */
function atom_reference_field_info() {
  return array(
    'atom_reference' => array(
      'label' => t('Atom Reference'),
      'description' => t('This field stores the ID of a related atom as an integer value.'),
      'instance_settings' => array(
        'referencable_types' => array(),
      ),
      'default_widget' => 'atom_reference_textfield',
      'default_formatter' => 'title',
      'property_type' => 'scald_atom',
    ),
  );
}

/**
 * Implements hook_field_instance_settings_form().
 */
function atom_reference_field_instance_settings_form($field, $instance) {
  $options = array();
  foreach (scald_types() as $name => $type) {
    $options[$name] = $type->title;
  }
  $form = array();
  $form['referencable_types'] = array(
    '#type' => 'checkboxes',
    '#title' => t('Atom types that can be referenced'),
    '#multiple' => TRUE,
    '#options' => $options,
    '#default_value' => $instance['settings']['referencable_types'],
  );
  $allow_override = isset($instance['settings']['allow_override']) ? $instance['settings']['allow_override'] : FALSE;
  $form['allow_override'] = array(
    '#type' => 'checkbox',
    '#title' => t('Allow context override'),
    '#default_value' => $allow_override,
  );
  return $form;
}

/**
 * Implements hook_field_views_data().
 */
function atom_reference_field_views_data($field) {
  $data = field_views_field_default_views_data($field);
  $current_table = _field_sql_storage_tablename($field);
  $revision_table = _field_sql_storage_revision_tablename($field);
  $column = _field_sql_storage_columnname($field['field_name'], 'sid');

  // Relationship: add a relationship for related atom.
  $data[$current_table][$column]['relationship'] = array(
    'base' => 'scald_atoms',
    'field' => $column,
    'handler' => 'views_handler_relationship',
    'label' => $data[$current_table][$field['field_name']]['title'],
    'field_name' => $field['field_name'],
  );

  // Relationship: add a relationship for revisions.
  $data[$revision_table][$column]['relationship'] = array(
    'base' => 'scald_atoms',
    'field' => $column,
    'handler' => 'views_handler_relationship',
    'label' => t('Atom reference item revision from !field_name', array(
      '!field_name' => $field['field_name'],
    )),
    'field_name' => $field['field_name'],
  );
  return $data;
}

/**
 * Implements hook_field_validate().
 */
function atom_reference_field_validate($entity_type, $entity, $field, $instance, $langcode, $items, &$errors) {

  // Ensure that the types of the referenced atoms match the one of those
  // that were defined in the field configuration.
  $types = atom_reference_field_referenceable_types($instance);
  foreach ($items as $delta => $item) {
    if (empty($item['sid'])) {
      continue;
    }
    $atom = scald_fetch($item['sid']);
    if (!isset($types[$atom->type]) || empty($types[$atom->type])) {
      $errors[$field['field_name']][$langcode][$delta][] = array(
        'error' => 'atom_reference_bad_type',
        'message' => t("Atom %title is of type %type, which can't be referenced in field %field", array(
          '%title' => $atom->title,
          '%type' => $atom->type,
          '%field' => $instance['label'],
        )),
      );
    }
  }
}

/**
 * Implements hook_field_presave().
 */
function atom_reference_field_presave($entity_type, $entity, $field, $instance, $langcode, &$items) {
  foreach ($items as $delta => $item) {
    if (empty($item['sid'])) {
      continue;
    }
    $options = array();
    if (!empty($item['options'])) {
      $options = unserialize($item['options']);
    }
    foreach ($item as $name => $option) {
      if ($name == 'sid' || $name == 'options') {
        continue;
      }
      if (!empty($item[$name])) {
        $options[$name] = $option;
      }
      else {
        unset($options[$name]);
      }
    }
    $items[$delta]['options'] = serialize($options);
  }
}

/**
 * Implements hook_field_is_empty().
 */
function atom_reference_field_is_empty($item, $field) {
  return empty($item['sid']);
}

/**
 * Implements hook_field_formatter_info().
 */
function atom_reference_field_formatter_info() {

  // Expose all the Scald Contexts as formatters for the Atom Reference field.
  $formatters = array();
  $contexts = scald_contexts_public();
  foreach ($contexts as $name => $context) {
    $formatters[$name] = array(
      'label' => $context['title'],
      'field types' => array(
        'atom_reference',
      ),
      'settings' => array(
        'link' => 0,
        'override' => 0,
      ),
    );
  }
  return $formatters;
}

/**
 * Implements hook_field_formatter_settings_form().
 */
function atom_reference_field_formatter_settings_form($field, $instance, $view_mode, $form, &$form_state) {
  $display = $instance['display'][$view_mode];
  $settings = $display['settings'];
  $element = array();
  $element['link'] = array(
    '#title' => t('Link to content'),
    '#type' => 'select',
    '#default_value' => $settings['link'],
    '#options' => array(
      'no',
      'yes',
    ),
  );
  if (isset($instance['settings']['allow_override']) && $instance['settings']['allow_override']) {
    $element['override'] = array(
      '#title' => t('Allow context override'),
      '#type' => 'checkbox',
      '#default_value' => $settings['override'],
    );
  }
  return $element;
}

/**
 * Implements hook_field_formatter_settings_summary().
 */
function atom_reference_field_formatter_settings_summary($field, $instance, $view_mode) {
  $display = $instance['display'][$view_mode];
  $settings = $display['settings'];
  $link = empty($settings['link']) ? t('No') : t('Yes');
  $summary = t('Link to content: @choice', array(
    '@choice' => $link,
  ));
  return $summary;
}

/**
 * Implements hook_field_formatter_view.
 */
function atom_reference_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) {
  $render_context = $display['type'];
  $contexts = scald_contexts();
  $element = array();
  $uri = false;

  // Check if the formatter involves a link.
  if ($display['settings']['link']) {
    $uri = entity_uri($entity_type, $entity);
  }
  if (!empty($contexts[$render_context])) {
    foreach ($items as $delta => $item) {
      $options = array();
      if (!empty($item['options'])) {
        $options += unserialize($item['options']);
      }
      $context = $render_context;
      if (isset($display['settings']['override']) && $display['settings']['override'] && !empty($options['context']) && $options['context'] !== 'use_the_default') {
        $context = $options['context'];
      }
      $sid = $item['sid'];
      if ($uri) {
        $options['link'] = $uri['path'];
      }
      $element[$delta] = array(
        '#markup' => scald_render($sid, $context, drupal_json_encode($options)),
      );
    }
  }
  return $element;
}

/**
 * Implements hook_field_widget_info.
 */
function atom_reference_field_widget_info() {
  return array(
    'atom_reference_textfield' => array(
      'label' => t('Drop box'),
      'field types' => array(
        'atom_reference',
      ),
      'settings' => array(
        'context' => 'sdl_editor_representation',
      ),
    ),
  );
}

/**
 * Implements hook_field_widget_settings_form.
 */
function atom_reference_field_widget_settings_form($field, $instance) {
  $preview_context = isset($instance['widget']['settings']['context']) ? $instance['widget']['settings']['context'] : variable_get('dnd_context_default', 'sdl_editor_representation');
  $form['context'] = array(
    '#type' => 'select',
    '#title' => t('Preview context'),
    '#options' => array(),
    '#default_value' => $preview_context,
    '#description' => t('Scald preview context to be displayed in the edit form.'),
  );
  $contexts = scald_contexts_public();
  foreach ($contexts as $name => $context) {

    // TODO: Atom reference shouldn't need the context to be parsable, there's
    // nothing converting back and forth between the SAS and the rendered
    // representation.
    if (!empty($context['parseable'])) {
      $form['context']['#options'][$name] = $context['title'];
    }
  }
  return $form;
}

/**
 * Implements hook_field_widget_form.
 */
function atom_reference_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element) {
  $all = scald_types();
  $options = array();
  $types = atom_reference_field_referenceable_types($instance);
  foreach ($types as $name => $value) {
    if ($value && isset($all[$name])) {
      $options[$name] = $all[$name]->title;
    }
  }
  $help = format_plural(count($options), 'Allowed resource format: %types', 'Allowed resource formats: %types', array(
    '%types' => implode(', ', $options),
  ));
  $preview_context = $instance['widget']['settings']['context'];
  $element['#description'] .= ' ' . $help;
  $element['#type'] = 'textfield';
  $element['#attributes'] = array(
    'data-types' => implode(',', array_keys($options)),
    'data-dnd-context' => $preview_context,
  );
  $element['#default_value'] = isset($items[$delta]) ? $items[$delta]['sid'] : '';
  $element['#preview_context'] = $preview_context;
  $element['#process'][] = 'atom_reference_field_widget_form_process';
  $element['#attached'] = array(
    'library' => array(
      array(
        'atom_reference',
        'library',
      ),
    ),
  );
  $options = array();
  if (!empty($items[$delta]['options'])) {
    $options = unserialize($items[$delta]['options']);
  }
  $return = array(
    'sid' => $element,
  );
  if (isset($instance['settings']['allow_override']) && $instance['settings']['allow_override']) {
    $rendering_context = 'use_the_default';
    if (!empty($options['context'])) {
      $rendering_context = $options['context'];
    }
    $context_element = array(
      '#type' => 'select',
      '#title' => t('Representation context'),
      '#attributes' => array(
        'class' => array(
          'context-select',
        ),
      ),
      '#options' => array(),
      '#default_value' => $rendering_context,
      '#description' => t('Scald rendering context used in field display.'),
    );
    $context_element['#weight'] = 20;
    $contexts = scald_contexts_public();
    $context_element['#options']['use_the_default'] = t('Use the default');
    foreach ($contexts as $name => $context) {
      if ($name !== 'sdl_library_item') {
        $context_element['#options'][$name] = $context['title'];
      }
    }
    $return['context'] = $context_element;
  }
  return $return;
}

/**
 * Atom types that are allowed to be referenced in that field instance.
 */
function atom_reference_field_referenceable_types($instance) {
  $types = $instance['settings']['referencable_types'];
  $all = scald_types();

  // All types are allowed if no type is explicitely selected (default setting).
  if (!array_filter($types)) {
    $types = array_fill_keys(array_keys($all), '1');
  }
  return $types;
}

/**
 * Process the Atom Reference widget element.
 *
 * Add either the atom reference representation or the placeholder
 * on the fly, depending on the field being filled.
 */
function atom_reference_field_widget_form_process(&$element) {

  // Get the default value, rendering context and format the placeholder accordingly.
  $preview_context = variable_get('dnd_context_default', 'sdl_editor_representation');
  if (isset($element['#preview_context'])) {
    $preview_context = $element['#preview_context'];
  }
  $default = $element['#value'];
  if ($default) {
    $prefix = '<div class="atom_reference_drop_zone" data-rendering-context="' . $preview_context . '">' . scald_render($default, $preview_context) . '</div>';
  }
  else {
    $placeholder = t('Drop a resource from Scald media library here.');
    $prefix = '<div class="atom_reference_drop_zone" data-rendering-context="' . $preview_context . '"><em>' . $placeholder . '</em></div>';
  }
  $element['#field_prefix'] = $prefix;
  if (isset($element['#entity_type']) && module_exists('i18n_field')) {
    $instance = field_info_instance($element['#entity_type'], $element['#field_name'], $element['#bundle']);
    $translated_label = i18n_field_translate_property($instance, 'label');
    $element['#title'] = $translated_label;
  }
  return $element;
}

/**
 * Implements hook_field_widget_error.
 */
function atom_reference_field_widget_error($element, $error, $form, &$form_state) {
  $name = implode('][', $element['sid']['#array_parents']);
  form_set_error($name, $error['message']);
}

/**
 * Provide default field comparison options.
 */
function atom_reference_field_diff_default_options($field_type) {
  return array(
    'show_id' => 0,
    'show_type' => 1,
    'entity_title' => 'Atom',
  );
}

/**
 * Provide a form for setting the field comparison options.
 */
function atom_reference_field_diff_options_form($field_type, $settings) {
  $options_form = array();
  $options_form['show_id'] = array(
    '#type' => 'checkbox',
    '#title' => t('Show atom id'),
    '#default_value' => $settings['show_id'],
  );
  $options_form['show_type'] = array(
    '#type' => 'checkbox',
    '#title' => t('Show atom type'),
    '#default_value' => $settings['show_type'],
  );
  $options_form['entity_title'] = array(
    '#type' => 'textfield',
    '#title' => t('The title to use for the atom entity'),
    '#default_value' => $settings['entity_title'],
    '#description' => t('This can be useful if you call Atoms differently on your website, such as Resources.'),
  );
  return $options_form;
}

/**
 * Diff field callback for preloading the scald atom entities.
 */
function atom_reference_field_diff_view_prepare(&$old_items, &$new_items, $context) {
  $sids = array();
  foreach (array_merge_recursive($old_items, $new_items) as $info) {
    $sids[$info['sid']] = $info['sid'];
  }
  $atoms = scald_atom_load_multiple($sids);
  foreach ($old_items as $delta => $info) {
    $old_items[$delta]['atom'] = isset($atoms[$info['sid']]) ? $atoms[$info['sid']] : NULL;
  }
  foreach ($new_items as $delta => $info) {
    $new_items[$delta]['atom'] = isset($atoms[$info['sid']]) ? $atoms[$info['sid']] : NULL;
  }
}

/**
 * Diff field callback for parsing atom_reference field comparative values.
 */
function atom_reference_field_diff_view($items, $context) {
  $instance = $context['instance'];
  $settings = $context['settings'];
  $diff_items = array();
  foreach ($items as $delta => $item) {
    if (!isset($item['atom'])) {
      continue;
    }
    $diff_items[$delta] = $item['atom']->title;
    if ($settings['show_id'] || $settings['show_type']) {
      $diff_items[$delta] .= ' (';
    }
    if ($settings['show_type']) {
      $diff_items[$delta] .= t('!type', array(
        '!type' => ucfirst($item['atom']->type),
      ));
    }
    if ($settings['show_id']) {
      if ($settings['show_type']) {
        $diff_items[$delta] .= ', ';
      }
      $diff_items[$delta] .= t('@entity_name ID: !id', array(
        '@entity_name' => $settings['entity_title'],
        '!id' => $item['atom']->sid,
      ));
    }
    if ($settings['show_id'] || $settings['show_type']) {
      $diff_items[$delta] .= ')';
    }
  }
  return $diff_items;
}

Functions

Namesort descending Description
atom_reference_field_diff_default_options Provide default field comparison options.
atom_reference_field_diff_options_form Provide a form for setting the field comparison options.
atom_reference_field_diff_view Diff field callback for parsing atom_reference field comparative values.
atom_reference_field_diff_view_prepare Diff field callback for preloading the scald atom entities.
atom_reference_field_formatter_info Implements hook_field_formatter_info().
atom_reference_field_formatter_settings_form Implements hook_field_formatter_settings_form().
atom_reference_field_formatter_settings_summary Implements hook_field_formatter_settings_summary().
atom_reference_field_formatter_view Implements hook_field_formatter_view.
atom_reference_field_info Implements hook_field_info().
atom_reference_field_instance_settings_form Implements hook_field_instance_settings_form().
atom_reference_field_is_empty Implements hook_field_is_empty().
atom_reference_field_presave Implements hook_field_presave().
atom_reference_field_referenceable_types Atom types that are allowed to be referenced in that field instance.
atom_reference_field_validate Implements hook_field_validate().
atom_reference_field_views_data Implements hook_field_views_data().
atom_reference_field_widget_error Implements hook_field_widget_error.
atom_reference_field_widget_form Implements hook_field_widget_form.
atom_reference_field_widget_form_process Process the Atom Reference widget element.
atom_reference_field_widget_info Implements hook_field_widget_info.
atom_reference_field_widget_settings_form Implements hook_field_widget_settings_form.
atom_reference_library Implements hook_library().