You are here

references_dialog.module in References dialog 7

This the main module file.

File

references_dialog.module
View source
<?php

/**
 * @file
 * This the main module file.
 */

/**
 * Implements hook_menu().
 */
function references_dialog_menu() {

  // This redirect callback is used when adding and editing content in
  // the overlay. When content is created or edited, we are directed here,
  // so we can act properly on entities.
  $entity_id = 2;
  $entity_type = 3;
  $items['references-dialog/redirect/%/%'] = array(
    'page callback' => 'references_dialog_redirect_page',
    'page arguments' => array(
      $entity_id,
      $entity_type,
    ),
    'access callback' => 'references_dialog_redirect_access',
    'access arguments' => array(
      $entity_id,
      $entity_type,
    ),
  );
  return $items;
}

/**
 * Implements hook_theme().
 */
function references_dialog_theme() {
  return array(
    'references_dialog_page' => array(
      'render element' => 'page',
      'template' => 'references-dialog-page',
    ),
    'references_dialog_links' => array(
      'variables' => array(
        'links' => NULL,
      ),
    ),
  );
}

/**
 * Implements hook_element_info().
 */
function references_dialog_element_info() {
  $types['references_dialog'] = array(
    '#input' => FALSE,
    '#after_build' => array(
      'references_dialog_build_element',
    ),
    '#attached' => references_dialog_attached(),
  );
  return $types;
}

/**
 * Get everything that needs to be attached in order for the links to work.
 */
function references_dialog_attached() {
  $module_patch = drupal_get_path('module', 'references_dialog');
  return array(
    'js' => array(
      $module_patch . '/js/references-dialog.js',
    ),
    'css' => array(
      $module_patch . '/css/references-dialog-admin.css',
    ),
    'library' => array(
      array(
        'system',
        'ui.dialog',
      ),
    ),
  );
}

/**
 * Implements hook_element_info_alter().
 */
function references_dialog_element_info_alter(&$info) {

  // Add #after_builds to widgets that needs them.
  foreach (references_dialog_widgets() as $widget) {

    // If this element type is specified as a type that a widget should be
    // attached to, go ahead and make it so.
    if (isset($info[$widget['element_type']]) && (!isset($info[$widget['element_type']]['#after_build']) || !in_array('references_dialog_process_widget', $info[$widget['element_type']]['#after_build']))) {
      $info[$widget['element_type']]['#after_build'][] = 'references_dialog_process_widget';
    }
  }
}

/**
 * Implements hook_admin_paths().
 */
function references_dialog_admin_paths() {

  // We only activate admin theme if we use the admin theme
  // when editing nodes.
  if (variable_get('node_admin_theme', FALSE)) {
    return array(
      'references-dialog/search/*' => TRUE,
    );
  }
}

/**
 * Get search views attached to a particular field instance.
 *
 * @param array $instance
 *   A field instance.
 *
 * @return array
 */
function references_dialog_field_get_search_views(array $instance) {
  $attachable = _references_dialog_get_attachable_name_by_instance($instance);
  return references_dialog_get_search_views($attachable);
}

/**
 * Provides attachable name by the field instance.
 *
 * @param array $instance
 *   Instance data.
 *
 * @return string
 *   Attachable has name format "entity_type:field_name:bundle".
 */
function _references_dialog_get_attachable_name_by_instance(array $instance) {
  return implode(':', array(
    $instance['entity_type'],
    $instance['field_name'],
    $instance['bundle'],
  ));
}

/**
 * Get all search views that are available for a particular attachable.
 *
 * @param string $attachable
 *   The name of the attachable to look for.
 *
 * @return array
 */
function references_dialog_get_search_views($attachable) {
  $search_views =& drupal_static(__FUNCTION__, array());
  if (!isset($search_views[$attachable])) {
    $search_views[$attachable] = array();

    // Get all views that has a references_dialog display.
    $results = references_dialog_get_applicable_views();
    foreach ($results as $view_name => $result) {
      foreach ($result as $display_name => $result_displays) {
        foreach ($result_displays['attachables'] as $name => $view_attachable) {
          if ($attachable == $view_attachable) {
            $search_views[$attachable][$view_name] = $result_displays;
          }
        }
      }
    }
  }
  return $search_views[$attachable];
}
function references_dialog_get_applicable_views() {
  $references_dialog_views =& drupal_static(__FUNCTION__, FALSE);
  if (!$references_dialog_views) {
    $references_dialog_views = cache_get('references_dialog_views');
    $references_dialog_views = !empty($references_dialog_views) ? $references_dialog_views->data : FALSE;
  }
  if (!empty($references_dialog_views)) {
    return $references_dialog_views;
  }
  $references_dialog_views = array();

  // Get all references_dialog_views that has a references_dialog display.
  $results = views_get_applicable_views('references_dialog display');
  foreach ($results as $result) {
    list($view, $display) = $result;
    if (is_object($view)) {
      $references_dialog_views[$view->name][$display] = array(
        'display' => $display,
        'title' => isset($view->display[$view->current_display]->display_options['title']) ? $view->display[$view->current_display]->display_options['title'] : t('Search'),
        'attachables' => $view->display_handler
          ->get_option('attach'),
      );
    }
  }
  cache_set('references_dialog_views', $references_dialog_views);
  return $references_dialog_views;
}

/**
 * Implements hook_widget_info_alter().
 */
function references_dialog_field_widget_info_alter(array &$info) {

  // Adds settings that we need to declare to widgets we are extending.
  foreach (references_dialog_widgets() as $widget_name => $widget_info) {
    if (isset($info[$widget_name]['settings'])) {
      foreach (array_keys($widget_info['operations']) as $operation) {
        $info[$widget_name]['settings']['references_dialog_' . $operation] = 0;

        // Add search view setting if we have search.
        if ($operation == 'search') {
          $info[$widget_name]['settings']['references_dialog_search_view'] = '';
        }
      }
    }
  }
}

/**
 * Get instances appropriate for a search view on a particular entity type.
 *
 * @param string $entity_type
 *   Name of the entity type.
 *
 * @return array
 *   An array of appropriate instances.
 */
function references_dialog_get_search_view_attachables($entity_type = NULL) {
  $attachables = module_invoke_all('references_dialog_search_attachables');

  // @todo Add an alter here.
  if (isset($entity_type)) {
    return $attachables[$entity_type];
  }
  else {
    return $attachables;
  }
}

/**
 * Get an attachable by name.
 *
 * @param $entity_type
 *   The type of entity the attacable is attached to.
 * @param $name
 *   The name of the attachable.
 */
function references_dialog_get_attachable($entity_type, $name) {
  $attachables = module_invoke_all('references_dialog_search_attachables');
  return $attachables[$entity_type][$name];
}

/**
 * Implements hook_references_dialog_search_attachables().
 */
function references_dialog_references_dialog_search_attachables() {
  $fields = field_info_fields();
  $dialog_widgets = references_dialog_widgets();
  $applicable_instances = array();
  foreach ($fields as $field_name => $field) {
    foreach ($field['bundles'] as $entity_type => $bundles) {
      foreach ($bundles as $bundle_name) {
        $instance = field_info_instance($entity_type, $field_name, $bundle_name);
        $widget_type = $instance['widget']['type'];
        if (in_array($widget_type, array_keys($dialog_widgets)) && $instance['widget']['settings']['references_dialog_search']) {

          // If the entity type is specified, in the declaration, add it here.
          $dialog_widget = $dialog_widgets[$widget_type];
          if (isset($dialog_widget['entity_type'])) {
            $attachable_type = $dialog_widget['entity_type'];
          }
          elseif (isset($dialog_widgets[$instance['widget']['type']]['type_callback'])) {
            $attachable_type = $dialog_widget['type_callback']($instance, $field);
          }
          if (isset($attachable_type)) {
            $attachable_name = _references_dialog_get_attachable_name_by_instance($instance);
            $applicable_instances[$attachable_type][$attachable_name] = array(
              'label' => $instance['bundle'] . ': ' . $instance['label'],
              'query' => 'references_dialog_field_attachable_query',
              'widget' => $dialog_widget,
            );
          }
        }
      }
    }
  }
  return $applicable_instances;
}

/**
 * This query is used by field referneces dialog attachables.
 *
 * @param \stdClass $view
 *   The view to work with.
 */
function references_dialog_field_attachable_query($view) {
  list($entity_type, $field_name, $bundle_name) = explode(':', $view->references_dialog['attachable']['name']);
  $instance = field_info_instance($entity_type, $field_name, $bundle_name);
  $field_info = field_info_field($field_name);
  $dialog_widget = references_dialog_widget_load($instance['widget']['type']);
  if (isset($dialog_widget['views_query']) && function_exists($dialog_widget['views_query'])) {
    $dialog_widget['views_query']($view, $instance, $field_info);
  }
}

/**
 * Return an array of supported widgets.
 */
function references_dialog_widgets() {
  $widgets =& drupal_static(__FUNCTION__);
  if ($widgets === NULL) {
    $widgets = module_invoke_all('references_dialog_widgets');
    drupal_alter('references_dialog_widgets', $widgets);
  }
  return $widgets;
}

/**
 * Load a particular widget.
 *
 * @param string $widget
 *   The name of the widget.
 *
 * @return array
 *   The widget definition.
 */
function references_dialog_widget_load($widget) {
  $widgets = references_dialog_widgets();
  return $widgets[$widget];
}

/**
 * Implements hook_form_alter().
 */
function references_dialog_form_field_ui_field_edit_form_alter(&$form, $form_state) {
  $widgets = references_dialog_widgets();
  if (array_key_exists($form['instance']['widget']['type']['#value'], $widgets)) {
    $field = $form['#field'];
    $instance = field_info_instance($form['instance']['entity_type']['#value'], $form['instance']['field_name']['#value'], $form['instance']['bundle']['#value']);
    if (isset($form['instance']['widget']['settings'])) {
      $form['instance']['widget']['settings'] += references_dialog_settings_form($field, $instance);
    }
    else {
      $form['instance']['widget']['settings'] = references_dialog_settings_form($field, $instance);
    }
  }
}

/**
 * A widget settings form for our references dialog fields.
 */
function references_dialog_settings_form($field, $instance) {
  $widget = $instance['widget'];
  $defaults = field_info_widget_settings($widget['type']);
  $settings = array_merge($defaults, $widget['settings']);
  $dialog_widget = references_dialog_widget_load($widget['type']);

  // Add our own additions.
  foreach ($dialog_widget['operations'] as $operation => $dialog_settings) {
    $form['references_dialog_' . $operation] = array(
      '#type' => 'checkbox',
      '#title' => check_plain($dialog_settings['title']),
      '#default_value' => isset($settings['references_dialog_' . $operation]) ? $settings['references_dialog_' . $operation] : FALSE,
    );
  }
  return $form;
}

/**
 * Menu access checker for references_dialog
 */
function references_dialog_search_access($entity_type, $field_name, $bundle_name) {

  // @todo make an access check.
  return TRUE;
}

/**
 * Add our references dialog fields to the existing element
 */
function references_dialog_process_widget(&$element) {
  if (!isset($element['#entity_type'])) {
    return $element;
  }
  $field = field_info_field($element['#field_name']);
  $instance = field_info_instance($element['#entity_type'], $element['#field_name'], $element['#bundle']);
  $widget_settings = $instance['widget']['settings'];
  $widget_type = $instance['widget']['type'];
  $widgets = references_dialog_widgets();

  // Bail if we don't have anything to do here.
  if (!in_array($widget_type, array_keys($widgets))) {
    return $element;
  }
  $dialog_widget = references_dialog_widget_load($widget_type);

  // Attach javascript and CSS needed.
  $attached = references_dialog_attached();
  $element['#attached']['js'][] = $attached['js'][0];
  $element['#attached']['js'][] = references_dialog_js_settings($element['#id'], array(
    'format' => $dialog_widget['format'],
  ));
  $element['#attached']['css'][] = $attached['css'][0];
  $element['#attached']['library'][] = $attached['library'][0];
  $dialog_links = array();
  foreach ($dialog_widget['operations'] as $operation => $settings) {
    if (isset($widget_settings['references_dialog_' . $operation]) && $widget_settings['references_dialog_' . $operation]) {
      $links = $settings['function']($element, $widget_settings, $field, $instance);
      foreach ($links as $link) {
        $link['attributes']['class'][] = $operation . '-dialog';
        $dialog_links[] = references_dialog_link($link);
      }
    }
  }
  if (count($dialog_links)) {

    // We add a div directly into the markup here since we really need it in order
    // to make sure the javascript works.
    $element['#suffix'] = reference_dialog_links_themed($element['#id'], $dialog_links);
  }
  return $element;
}
function references_dialog_build_element($element) {
  $dialog_links = array();
  $element['#attached']['js'][] = references_dialog_js_settings($element['#id'], array(
    'format' => $element['#format'],
    'target' => $element['#target'],
  ));
  if (isset($element['#operations'])) {
    foreach ($element['#operations'] as $operation => $link) {
      $link['attributes']['class'][] = $operation . '-dialog';
      $dialog_links[] = references_dialog_link($link);
    }
  }
  if (isset($element['#attachable'])) {
    $dialog_links = array_merge($dialog_links, references_dialog_get_views_search_links($element['#attachable']));
  }
  if (count($dialog_links)) {

    // We add a div directly into the markup here since we really need it in order
    // to make sure the javascript works.
    $element['#suffix'] = reference_dialog_links_themed($element['#id'], $dialog_links);
  }
  return $element;
}

/**
 * Provides themed dialog links.
 *
 * @param $id
 *   Identifier.
 * @param array $dialog_links
 *   Links.
 *
 * @return string
 *   Themed links
 */
function reference_dialog_links_themed($id, $dialog_links) {
  $links = theme('references_dialog_links', array(
    'links' => $dialog_links,
  ));
  return "<div class='dialog-links {$id}'>{$links}</div>";
}

/**
 * Attach necessary info to a link definition.
 */
function references_dialog_link($link) {
  if (!isset($link['attributes']['class']) || !in_array('references-dialog-activate', $link['attributes']['class'])) {
    $link['attributes']['class'][] = 'references-dialog-activate';
  }
  return $link;
}

/**
 * Javascript settings for the dialog.
 *
 * @param $id
 *   Identifier.
 * @param array $settings
 *   Settings to add.
 *
 * @return array
 *   Prepared settings array.
 */
function references_dialog_js_settings($id, array $settings) {
  if (isset($settings['callback_path'])) {
    $settings['callback_path'] = url($settings['callback_path']);
  }
  return array(
    'data' => array(
      'ReferencesDialog' => array(
        'fields' => array(
          $id => $settings,
        ),
      ),
    ),
    'type' => 'setting',
  );
}

/**
 * Process variables for references_dialog_page.
 */
function template_process_references_dialog_page(&$variables) {

  // Generate messages last in order to capture as many as possible for the
  // current page.
  if (!isset($variables['messages'])) {
    $variables['messages'] = $variables['page']['#show_messages'] ? theme('status_messages') : '';
  }
}

/**
 * Implements hook_entity_insert().
 */
function references_dialog_entity_insert($entity, $entity_type) {

  // If we are in a dialog, we want to make sure that we redirect to the
  // the close dialog page, so that the dialog may be closed.
  if (references_dialog_in_dialog() && references_dialog_close_on_submit()) {
    references_dialog_close_on_redirect($entity, $entity_type);
  }
}

/**
 * Implements hook_entity_update().
 */
function references_dialog_entity_update($entity, $entity_type) {
  if (references_dialog_in_dialog() && references_dialog_close_on_submit()) {
    references_dialog_close_on_redirect($entity, $entity_type);
  }
}

/**
 * Sets our destination parameter so that the dialog will close itself after
 * redirect is completed.
 */
function references_dialog_close_on_redirect($entity, $entity_type) {
  $entity_info = entity_get_info($entity_type);

  // We use $_GET['destination'] since that overrides anything that happens
  // in the form. It is a hack, but it is very effective, since we don't have
  // to be worried about getting overrun by other form submit handlers.
  $_GET['destination'] = 'references-dialog/redirect/' . $entity->{$entity_info['entity keys']['id']} . '/' . $entity_type . '?references-dialog-close=1&render=references-dialog';
}

/**
 * Implements hook_init().
 */
function references_dialog_init() {
  if (references_dialog_in_dialog()) {
    if (module_exists('admin_menu')) {
      module_invoke('admin_menu', 'suppress');
    }
    drupal_add_css(drupal_get_path('module', 'references_dialog') . '/css/references-dialog-search.css');
  }
}

/**
 * Menu callback for fetching a search view.
 *
 * @param $view_name a view to use.
 * @param $display_name the display name.
 * @param $instance_info information aboutythe current display in a packed form.
 */
function references_dialog_search_view($view_name, $display_name, $attachable) {
  $args = func_get_args();
  $args = array_slice($args, 3);
  $view = views_get_view($view_name);

  // Find the entity that matches our base table.
  $entities = entity_get_info();
  foreach ($entities as $entity_type => $entity_info) {
    if ($entity_info['base table'] == $view->base_table) {
      break;
    }
  }

  // Add some nice data about our field that the display handler can use.
  $view->references_dialog = array(
    'attachable' => references_dialog_get_attachable($entity_type, $attachable) + array(
      'name' => $attachable,
    ),
  );
  return $view
    ->execute_display($display_name, $args);
}

/**
 * Implements hook_hook_info().
 */
function references_dialog_hook_info() {
  $hooks['references_dialog_widgets'] = array(
    'group' => 'dialog_widgets',
  );
  return $hooks;
}
function references_dialog_get_field_search_links($element, $widget_settings, $field, $instance) {

  // We pack the necessary information for getting a field instance together in the
  // url, so that we can retrieve the field instance and attach it to the view
  // later on.
  $attachable = _references_dialog_get_attachable_name_by_instance($instance);
  return references_dialog_get_views_search_links($attachable);
}

/**
 * Get all views search links for an instance.
 * This function should be used by references dialog widgets that uses
 * views for it's search functionality.
 * @param type $instance
 */
function references_dialog_get_views_search_links($attachable) {
  $applicable_views = references_dialog_get_search_views($attachable);
  $links = array();
  foreach ($applicable_views as $view_name => $view) {
    $links[] = references_dialog_link(array(
      'title' => $view['title'],
      'href' => 'references-dialog/search/' . $view_name . '/' . $view['display'] . '/' . $attachable,
    ));
  }
  return $links;
}

/**
 * Implements hook_page_alter().
 */
function references_dialog_page_alter(&$page) {
  if (references_dialog_in_dialog()) {
    unset($page['page_top']);
    unset($page['page_bottom']);
    $page['#theme'] = 'references_dialog_page';
  }
}

/**
 * Check if we are in a references dialog.
 * @return boolean if we are in a dialog.
 */
function references_dialog_in_dialog() {
  return isset($_GET['render']) && $_GET['render'] == 'references-dialog' || strstr(current_path(), 'references-dialog/search') !== FALSE;
}

/**
 * Check if we should close the dialog upon submition.
 */
function references_dialog_close_on_submit() {
  return !isset($_GET['closeonsubmit']) || $_GET['closeonsubmit'];
}

/**
 * Implements of hook_views_api().
 */
function references_dialog_views_api() {
  return array(
    'api' => 3,
    'path' => drupal_get_path('module', 'references_dialog') . '/views',
  );
}

/**
 * Implements of hook_views_plugins().
 */
function references_dialog_views_plugins() {
  return array(
    'display' => array(
      'references_dialog' => array(
        'title' => t('Reference dialog Search'),
        'admin' => t('References'),
        'theme' => 'views_view',
        'help' => t('A view that can be used when referencing content.'),
        'handler' => 'references_dialog_plugin_display',
        'use ajax' => TRUE,
        'use pager' => TRUE,
        'uses hook menu' => TRUE,
        'help topic' => 'references-dialog',
        'references_dialog display' => TRUE,
        'path' => drupal_get_path('module', 'references_dialog') . '/views',
      ),
    ),
  );
}
function references_dialog_redirect_access() {

  // @todo It is not really a security issue, but we should probably check
  // that you can create the content you just created (silly), to access
  // this page.
  return TRUE;
}

/**
 * Page callback for our redirect page.
 */
function references_dialog_redirect_page($entity_id, $entity_type) {

  // Get some information about the entity we are dealing with.
  $entity = entity_load($entity_type, array(
    $entity_id,
  ));
  $entity = reset($entity);
  $entity_info = entity_get_info($entity_type);
  $entity_id = $entity->{$entity_info['entity keys']['id']};
  $entity_title = entity_label($entity_type, $entity);

  // Add appropriate javascript that will be used by the parent page to
  // fill in the required data.
  if (isset($entity_id) && references_dialog_in_dialog() && isset($_GET['references-dialog-close'])) {
    drupal_add_js(drupal_get_path('module', 'references_dialog') . '/js/references-dialog-child.js');
    drupal_add_js(array(
      'ReferencesDialog' => array(
        'entity_id' => $entity_id,
        'title' => $entity_title,
        'entity_type' => $entity_type,
      ),
    ), 'setting');
  }
  return '';
}

/**
 * Implements hook_references_dialog_entity_admin_paths().
 */
function references_dialog_references_dialog_entity_admin_paths() {

  // We define the add and edit page callbacks for core entities here.
  $admin_paths = array(
    'node' => array(
      'add' => 'node/add/[bundle-sanitized]',
      'edit' => 'node/[entity_id]/edit',
    ),
    'taxonomy_term' => array(
      'edit' => 'taxonomy/term/[entity_id]/edit',
      'add' => 'admin/structure/taxonomy/[bundle]/add',
    ),
    // Dealing with taxonomy vocabularies like this is kind of silly,
    // and accessing them is a bit harder since their admin page is accessible
    // through their machine name, so we leave it at just adding them for now.
    'taxonomy_vocabulary' => array(
      'add' => 'admin/structure/taxonomy/add',
    ),
    'comment' => array(
      'edit' => 'comment/[entity_id]/edit',
    ),
    'user' => array(
      'add' => 'admin/people/create',
      'edit' => 'user/[entity_id]/edit',
    ),
  );

  // The media module adds an edit callback for media as well.
  // Note: this will probably not work until file_entity provides an access
  // API, see http://drupal.org/node/1227706
  if (module_exists('media')) {
    $admin_paths['file'] = array(
      'edit' => 'media/[entity_id]/edit',
    );
  }

  // Bean provides add and edit paths for custom entities.
  if (module_exists('bean')) {
    $admin_paths['bean'] = array(
      'add' => 'block/add/[bundle-sanitized]',
      'edit' => 'block/[entity_id]/edit',
    );
  }
  return $admin_paths;
}

/**
 * Get the admin path (edit/add) page for a particular entity.
 *
 * @param string $entity_type the entity type
 * @param string $op Which operation to perform. Either "edit" or "add".
 * @param string $bundle The bundle to use.
 * @param mixed $entity The entity to edit. This is only used with the "edit" operation.
 *
 * @return string The path where the entity can be edited or created.
 */
function references_dialog_get_admin_path($entity_type, $op, $bundle = NULL, $entity = NULL) {

  // Let's cache the paths.
  $paths =& drupal_static(__FUNCTION__, NULL);
  if (!isset($paths)) {
    $paths = module_invoke_all('references_dialog_entity_admin_paths');
  }
  if (isset($paths[$entity_type]) && isset($paths[$entity_type][$op])) {
    $path = $paths[$entity_type][$op];

    // Create a wrapper, so we can deal with this in a sane way.
    $wrapper = entity_metadata_wrapper($entity_type, $entity);

    // Replace [entity_id] with the entity id.
    if (isset($entity)) {
      $path = str_replace('[entity_id]', $wrapper
        ->getIdentifier(), $path);
    }
    if (!$bundle) {
      $bundle = $wrapper
        ->getBundle();
    }
    if ($bundle) {
      $path = str_replace('[bundle]', $bundle, $path);

      // Some entities (like node) provide a sort of sanitized version.
      // This makes sure we support this.
      $bundle = strtr($bundle, array(
        '_' => '-',
      ));
      $path = str_replace('[bundle-sanitized]', $bundle, $path);
    }
    return $path;
  }
  return FALSE;
}

/**
 * Theme function for theming the links for opening the references dialog.
 */
function theme_references_dialog_links($variables) {
  return theme('links', array(
    'links' => $variables['links'],
    'attributes' => array(
      'class' => array(
        'references-dialog-links',
      ),
    ),
  ));
}

/**
 * Implements hook_field_widget_info().
 */
function references_dialog_field_widget_info() {
  return array(
    'references_dialog_term_reference' => array(
      'label' => t('Autocomplete term widget for References Dialog'),
      'field types' => array(
        'taxonomy_term_reference',
      ),
      'settings' => array(
        'size' => 60,
        'autocomplete_path' => 'taxonomy/autocomplete',
        'autocomplete_match' => 'starts_with',
      ),
    ),
  );
}

/**
 * Implements hook_field_widget_settings_form().
 */
function references_dialog_field_widget_settings_form($field, $instance) {
  $widget = $instance['widget'];
  $defaults = field_info_widget_settings($widget['type']);
  $settings = array_merge($defaults, $widget['settings']);
  $form = array();
  if ($widget['type'] == 'references_dialog_term_reference') {
    $form['autocomplete_match'] = [
      '#type' => 'select',
      '#title' => t('Autocomplete matching'),
      '#default_value' => $settings['autocomplete_match'],
      '#options' => [
        'starts_with' => t('Starts with'),
        'contains' => t('Contains'),
      ],
      '#description' => t('Select the method used to collect autocomplete suggestions. Note that <em>Contains</em> can cause performance issues on sites with thousands of nodes.'),
    ];
    $form['size'] = [
      '#type' => 'textfield',
      '#title' => t('Size of textfield'),
      '#default_value' => $settings['size'],
      '#element_validate' => [
        '_element_validate_integer_positive',
      ],
      '#required' => TRUE,
    ];
  }
  return $form;
}

/**
 * Implements hook_field_widget_form().
 */
function references_dialog_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element) {
  switch ($instance['widget']['type']) {
    case 'references_dialog_term_reference':
      if (isset($items[$delta]['tid'])) {
        $term = taxonomy_term_load($items[$delta]['tid']);
        $value = $term->name;
      }
      else {
        $value = NULL;
      }
      $element += array(
        '#type' => 'textfield',
        '#default_value' => $value,
        '#autocomplete_path' => $instance['widget']['settings']['autocomplete_path'] . '/' . $field['field_name'],
        '#size' => $instance['widget']['settings']['size'],
        '#maxlength' => NULL,
        '#element_validate' => array(
          'references_dialog_term_reference_autocomplete_validate',
        ),
      );
      break;
  }
  return array(
    'tid' => $element,
  );
}

/**
 * Form element validate handler for taxonomy term autocomplete element.
 */
function references_dialog_term_reference_autocomplete_validate($element, &$form_state) {

  // Autocomplete widgets do not send their tids in the form, so we must detect
  // them here and process them independently.
  $value = NULL;
  if ($element['#value']) {
    $term = FALSE;
    $field = field_widget_field($element, $form_state);
    $instance = field_widget_instance($element, $form_state);

    // Check whether we have an explicit "[tid:n]" input.
    preg_match('/^(?:\\s*|(.*) )?\\[\\s*tid\\s*:\\s*(\\d+)\\s*\\]$/', $element['#value'], $matches);
    if (!empty($matches)) {

      // Explicit tid.
      list(, $term_name, $tid) = $matches;
      if (!empty($term_name)) {
        $term = taxonomy_term_load($tid);
      }
    }
    else {

      // Collect candidate vocabularies.
      $vocabularies = array();
      foreach ($field['settings']['allowed_values'] as $tree) {
        if ($vocabulary = taxonomy_vocabulary_machine_name_load($tree['vocabulary'])) {
          $vocabularies[$vocabulary->vid] = $vocabulary;
        }
      }
      if ($possibilities = taxonomy_term_load_multiple(array(), array(
        'name' => trim($element['#value']),
        'vid' => array_keys($vocabularies),
      ))) {
        $term = array_pop($possibilities);
      }
    }
    if ($term) {
      $value = $term->tid;
    }
    else {
      form_error($element, t('%name: found no valid post for this value.', array(
        '%name' => $instance['label'],
      )));
    }
  }
  form_set_value($element, $value, $form_state);
}

Functions

Namesort descending Description
references_dialog_admin_paths Implements hook_admin_paths().
references_dialog_attached Get everything that needs to be attached in order for the links to work.
references_dialog_build_element
references_dialog_close_on_redirect Sets our destination parameter so that the dialog will close itself after redirect is completed.
references_dialog_close_on_submit Check if we should close the dialog upon submition.
references_dialog_element_info Implements hook_element_info().
references_dialog_element_info_alter Implements hook_element_info_alter().
references_dialog_entity_insert Implements hook_entity_insert().
references_dialog_entity_update Implements hook_entity_update().
references_dialog_field_attachable_query This query is used by field referneces dialog attachables.
references_dialog_field_get_search_views Get search views attached to a particular field instance.
references_dialog_field_widget_form Implements hook_field_widget_form().
references_dialog_field_widget_info Implements hook_field_widget_info().
references_dialog_field_widget_info_alter Implements hook_widget_info_alter().
references_dialog_field_widget_settings_form Implements hook_field_widget_settings_form().
references_dialog_form_field_ui_field_edit_form_alter Implements hook_form_alter().
references_dialog_get_admin_path Get the admin path (edit/add) page for a particular entity.
references_dialog_get_applicable_views
references_dialog_get_attachable Get an attachable by name.
references_dialog_get_field_search_links
references_dialog_get_search_views Get all search views that are available for a particular attachable.
references_dialog_get_search_view_attachables Get instances appropriate for a search view on a particular entity type.
references_dialog_get_views_search_links Get all views search links for an instance. This function should be used by references dialog widgets that uses views for it's search functionality.
references_dialog_hook_info Implements hook_hook_info().
references_dialog_init Implements hook_init().
references_dialog_in_dialog Check if we are in a references dialog.
references_dialog_js_settings Javascript settings for the dialog.
references_dialog_link Attach necessary info to a link definition.
references_dialog_menu Implements hook_menu().
references_dialog_page_alter Implements hook_page_alter().
references_dialog_process_widget Add our references dialog fields to the existing element
references_dialog_redirect_access
references_dialog_redirect_page Page callback for our redirect page.
references_dialog_references_dialog_entity_admin_paths Implements hook_references_dialog_entity_admin_paths().
references_dialog_references_dialog_search_attachables Implements hook_references_dialog_search_attachables().
references_dialog_search_access Menu access checker for references_dialog
references_dialog_search_view Menu callback for fetching a search view.
references_dialog_settings_form A widget settings form for our references dialog fields.
references_dialog_term_reference_autocomplete_validate Form element validate handler for taxonomy term autocomplete element.
references_dialog_theme Implements hook_theme().
references_dialog_views_api Implements of hook_views_api().
references_dialog_views_plugins Implements of hook_views_plugins().
references_dialog_widgets Return an array of supported widgets.
references_dialog_widget_load Load a particular widget.
reference_dialog_links_themed Provides themed dialog links.
template_process_references_dialog_page Process variables for references_dialog_page.
theme_references_dialog_links Theme function for theming the links for opening the references dialog.
_references_dialog_get_attachable_name_by_instance Provides attachable name by the field instance.