You are here

nodehierarchy_widgets.module in Node Hierarchy 7.2

Alternative parent selector widgets for Node Hierarchy.

File

nodehierarchy_widgets/nodehierarchy_widgets.module
View source
<?php

/**
 * @file
 * Alternative parent selector widgets for Node Hierarchy.
 */

/**
 * Implements hook_menu().
 */
function nodehierarchy_widgets_menu() {
  $items = array();
  $items['nodehierarchy/autocomplete/parent'] = array(
    'title' => 'Autocomplete',
    'access arguments' => array(
      'access content',
    ),
    'page callback' => 'nodehierarchy_widgets_autocomplete_parent',
    'type' => MENU_CALLBACK,
  );
  return $items;
}

/**
 * Implements hook_nodehierarchy_get_parent_selector().
 */
function nodehierarchy_widgets_nodehierarchy_get_parent_selector($child_type, $pnid, $exclude = NULL) {
  if (variable_get('nodehierarchy_widgets_parent_selector', 'autocomplete') == 'autocomplete') {
    drupal_add_css(drupal_get_path('module', 'nodehierarchy_widgets') . '/nodehierarchy_widgets.css');
    $out = array(
      '#type' => 'textfield',
      '#autocomplete_path' => 'nodehierarchy/autocomplete/parent/' . $child_type . '/' . $exclude,
      '#child_type' => $child_type,
      '#exclude' => $exclude,
      '#description' => 'Enter the title of the parent node.',
      '#element_validate' => array(
        '_nodehierarchy_widgets_autocomplete_parent_validate',
      ),
      '#default_value' => _nodehierarchy_widgets_autocomplete_parent_value($pnid),
    );
    return array(
      $out,
    );
  }
}

/**
 * Page callback for autocomplete.
 */
function nodehierarchy_widgets_autocomplete_parent($child_type = NULL, $exclude = NULL, $string = NULL) {
  $nodes = array();
  $length = strlen($string);
  $options = _nodehierarchy_widgets_parent_autocomplete_options($child_type, $exclude, $string);
  foreach ($options as $key => $item) {
    $start = empty($string) ? FALSE : strpos(strtolower($item['title']), strtolower($string));
    if ($start !== FALSE) {
      $rendered = $item['title'];
      $rendered = substr_replace($rendered, '<u>', $start, 0);
      $rendered = substr_replace($rendered, '</u>', $start + $length + 3, 0);
      $trail = _nodehierarchy_widgets_autocomplete_parent_heirarchy_trail($item);
      if (count($trail) > 1) {
        $rendered .= ' <span class="nodehierarchy-autocomplete-trail">(' . implode(' &#9656; ', $trail) . ')</span>';
      }
      $nodes[$item['title'] . ' [nid:' . $item['nid'] . ']'] = $rendered;
    }
  }
  drupal_json_output($nodes);
}
function _nodehierarchy_widgets_autocomplete_parent_heirarchy_trail($item) {
  $out = array();
  $menu_links = _nodehierarchy_get_node_primary_ancestor_menu_links($item['nid']);
  $menu_links = (array) array_pop($menu_links);
  $out = array();
  foreach ($menu_links as $menu_link) {
    if ($menu_link) {
      $out[] = $menu_link['link_title'];
    }
  }
  return $out;
}

/**
 * Return a list of menu items that are valid possible parents for the given node.
 */
function _nodehierarchy_widgets_parent_autocomplete_options($child_type, $exclude = NULL, $string = NULL) {

  // Get all the possible parents.
  $types = nodehierarchy_get_allowed_parent_types();
  foreach ($types as $i => $type) {
    $types[$i] = "'{$type}'";
  }

  // Get the items with menu links.
  $items = $mlids = $tree = array();
  if ($types) {

    // TODO Please convert this statement to the D7 database API syntax.
    $result = db_query("SELECT n.nid, n.type as type, n.title as title, ml.*, IF(depth IS NULL, 1, depth) as depth, IF(ml.mlid IS NULL, CONCAT('nid:', n.nid), ml.mlid) as mlid, ml.mlid as linkid\n                           FROM {node} n\n                      LEFT JOIN {nodehierarchy_menu_links} nh_parent\n                             ON nh_parent.nid = n.nid\n                      LEFT JOIN {menu_links} ml\n                             ON ml.mlid = nh_parent.mlid\n                          WHERE (ml.module = 'nodehierarchy' OR ml.module IS NULL)\n                            AND n.type IN (" . implode(', ', $types) . ")\n                            AND LOWER(n.title) LIKE :title\n                          ORDER BY IF(p1 IS NULL, n.created, 0) ASC, p1 ASC, p2 ASC, p3 ASC, p4 ASC, p5 ASC, p6 ASC, p7 ASC, p8 ASC, p9 ASC", array(
      'title' => '%' . db_like(strtolower($string)) . '%',
    ), array(
      'fetch' => PDO::FETCH_ASSOC,
    ));
  }

  // Flatten tree to a list of options.
  $parent_types = nodehierarchy_get_allowed_parent_types($child_type);
  $out = nodehierarchy_tree_data($result, $exclude, $parent_types);
  return $out;
}

/**
 * Return a list of menu items that are valid possible parents for the given node.
 */
function _nodehierarchy_widgets_is_invalid_parent($parent_nid, $child_nid, $child_type) {
  $parent = node_load($parent_nid);

  // Check for a valid parent type.
  if (!$parent) {
    return t('The specified parent cannot be found');
  }

  // Check for a valid parent type.
  $types = nodehierarchy_get_allowed_parent_types($child_type);
  if (!in_array($parent->type, $types)) {
    return t('%title cannot be a parent of this node because %type is not an allowed parent node type.', array(
      '%title' => $parent->title,
      '%type' => node_type_get_name($parent->type),
    ));
  }

  // Check that the parent is not a child of itself
  if ($parent_nid == $child_nid) {
    return t('%title cannot be a parent of itself.', array(
      '%title' => $parent->title,
    ));
  }

  // Check that the parent is not a descendant of the given node.
  $ancestors = nodehierarchy_get_node_ancestor_nids($parent_nid);
  if (in_array($child_nid, $ancestors)) {
    return t('%title cannot be a parent of this node it is a descendant of the node.', array(
      '%title' => $parent->title,
    ));
  }
  return FALSE;
}

/**
 * Get the default display value for a node hierarchy autocomplete.
 */
function _nodehierarchy_widgets_autocomplete_parent_value($pnid) {
  if ($pnid && ($item = node_load($pnid))) {
    return $item->title . ' [nid:' . $item->nid . ']';
  }
}

/**
 * Validate a node hierarchy autocomplete in the format 'Tile [nid:xx]' or '[nid:xx]' or 'Title'.
 */
function _nodehierarchy_widgets_autocomplete_parent_validate($element, &$form_state) {
  $child_type = $element['#child_type'];
  $exclude = $element['#exclude'];
  $value = $element['#value'];
  $nid = NULL;
  if (!empty($value)) {
    preg_match('/^(?:\\s*|(.*) )?\\[\\s*nid\\s*:\\s*(\\d+)\\s*\\]$/', $value, $matches);
    if (!empty($matches)) {

      // Explicit [nid:n].
      list(, $title, $nid) = $matches;
      if (isset($form_state['values']['nid'])) {
        if ($err = _nodehierarchy_widgets_is_invalid_parent($nid, $form_state['values']['nid'], $form_state['values']['type'])) {
          form_error($element, $err);
        }
      }
    }
    else {

      // No explicit nid.
      $options = _nodehierarchy_widgets_parent_autocomplete_options($form_state['values']['type'], $form_state['values']['nid'], trim($value));
      if (empty($options)) {
        form_error($element, t('There are no available parents called \'%name\'', array(
          '%name' => $value,
        )));
      }
      else {
        $key = key($options);
        if ($err = _nodehierarchy_widgets_is_invalid_parent($options[$key]['nid'], $form_state['values']['nid'], $form_state['values']['type'])) {
          form_error($element, $err);
        }
        else {
          $nid = $key;
        }
      }
    }
  }
  form_set_value($element, $nid, $form_state);
}

Functions

Namesort descending Description
nodehierarchy_widgets_autocomplete_parent Page callback for autocomplete.
nodehierarchy_widgets_menu Implements hook_menu().
nodehierarchy_widgets_nodehierarchy_get_parent_selector Implements hook_nodehierarchy_get_parent_selector().
_nodehierarchy_widgets_autocomplete_parent_heirarchy_trail
_nodehierarchy_widgets_autocomplete_parent_validate Validate a node hierarchy autocomplete in the format 'Tile [nid:xx]' or '[nid:xx]' or 'Title'.
_nodehierarchy_widgets_autocomplete_parent_value Get the default display value for a node hierarchy autocomplete.
_nodehierarchy_widgets_is_invalid_parent Return a list of menu items that are valid possible parents for the given node.
_nodehierarchy_widgets_parent_autocomplete_options Return a list of menu items that are valid possible parents for the given node.