[ Index ]

PHP Cross Reference of Drupal 6 (gatewave)

title

Body

[close]

/sites/all/modules/link/ -> link.module (source)

   1  <?php
   2  // $Id: link.module,v 1.24.4.34 2010/06/14 18:14:11 jcfiala Exp $
   3  
   4  /**
   5   * @file
   6   * Defines simple link field types.
   7   */
   8  
   9  define('LINK_EXTERNAL', 'external');
  10  define('LINK_INTERNAL', 'internal');
  11  define('LINK_FRONT', 'front');
  12  define('LINK_EMAIL', 'email');
  13  define('LINK_NEWS', 'news');
  14  define('LINK_DOMAINS', 'aero|arpa|asia|biz|com|cat|coop|edu|gov|info|int|jobs|mil|museum|name|nato|net|org|pro|travel|mobi|local');
  15  // There are many other characters which are legal other than simply a-z - this includes them.
  16  // html_entity_decode() is buggy in php 4 - we'll put it back here for D7 when 5.x is assumed.
  17  /*define('LINK_ICHARS', (string) html_entity_decode(implode("", array(
  18      "&#x00E6;", // æ
  19      "&#x00C6;", // Æ
  20      "&#x00F8;", // ø
  21      "&#x00D8;", // Ø
  22      "&#x00E5;", // å
  23      "&#x00C5;", // Å
  24      "&#x00E4;", // ä
  25      "&#x00C4;", // Ä
  26      "&#x00F6;", // ö
  27      "&#x00D6;", // Ö
  28      "&#x00FC;", // ü
  29      "&#x00DC;", // Ü
  30    )), ENT_QUOTES, 'UTF-8'));*/
  31  
  32  define('LINK_TARGET_DEFAULT', 'default');
  33  define('LINK_TARGET_NEW_WINDOW', '_blank');
  34  define('LINK_TARGET_TOP', '_top');
  35  define('LINK_TARGET_USER', 'user');
  36  
  37  /**
  38   * Maximum URLs length.
  39   */
  40  define('LINK_URL_MAX_LENGTH', 2048);
  41  
  42  /**
  43   * Implementation of hook_field_info().
  44   */
  45  function link_field_info() {
  46    return array(
  47      'link' => array(
  48        'label' => t('Link'),
  49        'description' => t('Store a title, href, and attributes in the database to assemble a link.'),
  50      ),
  51    );
  52  }
  53  
  54  /**
  55   * Implementation of hook_field_settings().
  56   */
  57  function link_field_settings($op, $field) {
  58    switch ($op) {
  59      case 'form':
  60        $form = array(
  61          '#theme' => 'link_field_settings',
  62        );
  63  
  64        $form['validate_url'] = array(
  65          '#type' => 'checkbox',
  66          '#title' => t('Validate URL'),
  67          '#default_value' => isset($field['validate_url']) && ($field['validate_url'] !== '') ? $field['validate_url'] : TRUE,
  68          '#description' => t('If checked, the URL field will be verified as a valid URL during validation.'),
  69        );
  70  
  71        $form['url'] = array(
  72          '#type' => 'checkbox',
  73          '#title' => t('Optional URL'),
  74          '#default_value' => $field['url'],
  75          '#return_value' => 'optional',
  76          '#description' => t('If checked, the URL field is optional and submitting a title alone will be acceptable. If the URL is omitted, the title will be displayed as plain text.'),
  77        );
  78  
  79        $title_options = array(
  80          'optional' => t('Optional Title'),
  81          'required' => t('Required Title'),
  82          'value' => t('Static Title: '),
  83          'none' => t('No Title'),
  84        );
  85  
  86        $form['title'] = array(
  87          '#type' => 'radios',
  88          '#title' => t('Link Title'),
  89          '#default_value' => isset($field['title']) && ($field['title'] !== '') ? $field['title'] : 'optional',
  90          '#options' => $title_options,
  91          '#description' => t('If the link title is optional or required, a field will be displayed to the end user. If the link title is static, the link will always use the same title. If <a href="http://drupal.org/project/token">token module</a> is installed, the static title value may use any other node field as its value. Static and token-based titles may include most inline XHTML tags such as <em>strong</em>, <em>em</em>, <em>img</em>, <em>span</em>, etc.'),
  92        );
  93  
  94        $form['title_value'] = array(
  95          '#type' => 'textfield',
  96          '#default_value' => $field['title_value'],
  97          '#size' => '46',
  98        );
  99  
 100        // Add token module replacements if available
 101        if (module_exists('token')) {
 102          $form['tokens'] = array(
 103            '#type' => 'fieldset',
 104            '#collapsible' => TRUE,
 105            '#collapsed' => TRUE,
 106            '#title' => t('Placeholder tokens'),
 107            '#description' => t("The following placeholder tokens can be used in both paths and titles. When used in a path or title, they will be replaced with the appropriate values."),
 108          );
 109          $form['tokens']['help'] = array(
 110            '#value' => theme('token_help', 'node'),
 111          );
 112  
 113          $form['enable_tokens'] = array(
 114            '#type' => 'checkbox',
 115            '#title' => t('Allow user-entered tokens'),
 116            '#default_value' => isset($field['enable_tokens']) ? $field['enable_tokens'] : 1,
 117            '#description' => t('Checking will allow users to enter tokens in URLs and Titles on the node edit form. This does not affect the field settings on this page.'),
 118          );
 119        }
 120  
 121        $form['display'] = array(
 122          '#tree' => TRUE,
 123        );
 124        $form['display']['url_cutoff'] = array(
 125          '#type' => 'textfield',
 126          '#title' => t('URL Display Cutoff'),
 127          '#default_value' => isset($field['display']['url_cutoff']) ? $field['display']['url_cutoff'] : '80',
 128          '#description' => t('If the user does not include a title for this link, the URL will be used as the title. When should the link title be trimmed and finished with an elipsis (&hellip;)? Leave blank for no limit.'),
 129          '#maxlength' => 3,
 130          '#size' => 3,
 131        );
 132  
 133        $target_options = array(
 134          LINK_TARGET_DEFAULT => t('Default (no target attribute)'),
 135          LINK_TARGET_TOP => t('Open link in window root'),
 136          LINK_TARGET_NEW_WINDOW => t('Open link in new window'),
 137          LINK_TARGET_USER => t('Allow the user to choose'),
 138        );
 139        $form['attributes'] = array(
 140          '#tree' => TRUE,
 141        );
 142        $form['attributes']['target'] = array(
 143          '#type' => 'radios',
 144          '#title' => t('Link Target'),
 145          '#default_value' => empty($field['attributes']['target']) ? LINK_TARGET_DEFAULT : $field['attributes']['target'],
 146          '#options' => $target_options,
 147        );
 148        $form['attributes']['rel'] = array(
 149          '#type' => 'textfield',
 150          '#title' => t('Rel Attribute'),
 151          '#description' => t('When output, this link will have this rel attribute. The most common usage is <a href="http://en.wikipedia.org/wiki/Nofollow">rel=&quot;nofollow&quot;</a> which prevents some search engines from spidering entered links.'),
 152          '#default_value' => empty($field['attributes']['rel']) ? '' : $field['attributes']['rel'],
 153          '#field_prefix' => 'rel = "',
 154          '#field_suffix' => '"',
 155          '#size' => 20,
 156        );
 157        $form['attributes']['class'] = array(
 158          '#type' => 'textfield',
 159          '#title' => t('Additional CSS Class'),
 160          '#description' => t('When output, this link will have this class attribute. Multiple classes should be separated by spaces.'),
 161          '#default_value' => empty($field['attributes']['class']) ? '' : $field['attributes']['class'],
 162        );
 163        $form['attributes']['title'] = array(
 164          '#title' => t("Link 'title' Attribute"),
 165          '#type' => 'textfield',
 166          '#field_prefix' => 'title = "',
 167          '#field_suffix' => '"',
 168          '#description' => t('When output, links will use this "title" attribute (when different from the link text). Read <a href="http://www.w3.org/TR/WCAG10-HTML-TECHS/#links">WCAG 1.0 Guidelines</a> for links comformances. Tokens values will be evaluated.'),
 169          '#default_value' => empty($field['attributes']['title']) ? '' : $field['attributes']['title'],
 170        );
 171        return $form;
 172  
 173      case 'validate':
 174        if ($field['title'] == 'value' && empty($field['title_value'])) {
 175          form_set_error('title_value', t('A default title must be provided if the title is a static value'));
 176        }
 177        break;
 178  
 179      case 'save':
 180        return array('attributes', 'display', 'url', 'title', 'title_value', 'enable_tokens', 'validate_url');
 181  
 182      case 'database columns':
 183        return array(
 184          'url' => array('type' => 'varchar', 'length' => LINK_URL_MAX_LENGTH, 'not null' => FALSE, 'sortable' => TRUE),
 185          'title' => array('type' => 'varchar', 'length' => 255, 'not null' => FALSE, 'sortable' => TRUE),
 186          'attributes' => array('type' => 'text', 'size' => 'medium', 'not null' => FALSE),
 187        );
 188  
 189      case 'views data':
 190        module_load_include('inc', 'link', 'views/link.views');
 191        return link_views_content_field_data($field);
 192    }
 193  }
 194  
 195  /**
 196   * Theme the settings form for the link field.
 197   */
 198  function theme_link_field_settings($form) {
 199    $title_value = drupal_render($form['title_value']);
 200    $title_checkbox = drupal_render($form['title']['value']);
 201  
 202    // Set Static Title radio option to include the title_value textfield.
 203    $form['title']['value'] = array('#value' => '<div class="container-inline">'. $title_checkbox . $title_value .'</div>');
 204  
 205    // Reprint the title radio options with the included textfield.
 206    return drupal_render($form);
 207  }
 208  
 209  /**
 210   * Implementation of hook_content_is_empty().
 211   */
 212  function link_content_is_empty($item, $field) {
 213    if (empty($item['title']) && empty($item['url'])) {
 214      return TRUE;
 215    }
 216    return FALSE;
 217  }
 218  
 219  /**
 220   * Implementation of hook_field().
 221   */
 222  function link_field($op, &$node, $field, &$items, $teaser, $page) {
 223    switch ($op) {
 224      case 'load':
 225        return _link_load($field, $items);
 226  
 227      case 'validate':
 228        $optional_field_found = FALSE;
 229        if ($field['validate_url'] !== 0 || is_null($field['validate_url']) || !isset($field['validate_url'])) {
 230          foreach ($items as $delta => $value) {
 231            _link_validate($items[$delta], $delta, $field, $node, $optional_field_found);
 232          }
 233        }
 234  
 235        if ($field['url'] == 'optional' && $field['title'] == 'optional' && $field['required'] && !$optional_field_found) {
 236          form_set_error($field['field_name'] .'][0][title', t('At least one title or URL must be entered.'));
 237        }
 238        break;
 239  
 240      case 'presave':
 241        foreach ($items as $delta => $value) {
 242          _link_process($items[$delta], $delta, $field, $node);
 243        }
 244        break;
 245  
 246      case 'sanitize':
 247        foreach ($items as $delta => $value) {
 248          _link_sanitize($items[$delta], $delta, $field, $node);
 249        }
 250        break;
 251    }
 252  }
 253  
 254  /**
 255   * Implementation of hook_widget_info().
 256   */
 257  function link_widget_info() {
 258    return array(
 259      'link' => array(
 260        'label' => 'Link',
 261        'field types' => array('link'),
 262        'multiple values' => CONTENT_HANDLE_CORE,
 263      ),
 264    );
 265  }
 266  
 267  /**
 268   * Implementation of hook_widget().
 269   */
 270  function link_widget(&$form, &$form_state, $field, $items, $delta = 0) {
 271    $element = array(
 272      '#type' => $field['widget']['type'],
 273      '#default_value' => isset($items[$delta]) ? $items[$delta] : '',
 274      '#title' => $field['widget']['label'],
 275      '#weight' => $field['widget']['weight'],
 276      '#description' => $field['widget']['description'],
 277      '#required' => $field['required'],
 278      '#field' => $field,
 279    );
 280    return $element;
 281  }
 282  
 283  function _link_load($field, &$items) {
 284    foreach ($items as $delta => $item) {
 285      // Unserialize the attributes array.
 286      $items[$delta]['attributes'] = unserialize($item['attributes']);
 287    }
 288    return array($field['field_name'] => $items);
 289  }
 290  
 291  function _link_process(&$item, $delta = 0, $field, $node) {
 292    // Trim whitespace from URL.
 293    $item['url'] = trim($item['url']);
 294  
 295    // if no attributes are set then make sure $item['attributes'] is an empty array - this lets $field['attributes'] override it.
 296    if (empty($item['attributes'])) {
 297      $item['attributes'] = array(); 
 298    }
 299  
 300    // Serialize the attributes array.
 301    $item['attributes'] = serialize($item['attributes']);
 302  
 303    // Don't save an invalid default value (e.g. 'http://').
 304    if ((isset($field['widget']['default_value'][$delta]['url']) && $item['url'] == $field['widget']['default_value'][$delta]['url']) && is_object($node)) {
 305      if (!link_validate_url($item['url'])) {
 306        unset($item['url']);
 307      }
 308    }
 309  }
 310  
 311  function _link_validate(&$item, $delta, $field, $node, &$optional_field_found) {
 312    if ($item['url'] && !(isset($field['widget']['default_value'][$delta]['url']) && $item['url'] == $field['widget']['default_value'][$delta]['url'] && !$field['required'])) {
 313      // Validate the link.
 314      if (link_validate_url(trim($item['url'])) == FALSE) {
 315        form_set_error($field['field_name'] .']['. $delta .'][url', t('Not a valid URL.'));
 316      }
 317      // Require a title for the link if necessary.
 318      if ($field['title'] == 'required' && strlen(trim($item['title'])) == 0) {
 319        form_set_error($field['field_name'] .']['. $delta .'][title', t('Titles are required for all links.'));
 320      }
 321    }
 322    // Require a link if we have a title.
 323    if ($field['url'] !== 'optional' && strlen($item['title']) > 0 && strlen(trim($item['url'])) == 0) {
 324      form_set_error($field['field_name'] .']['. $delta .'][url', t('You cannot enter a title without a link url.'));
 325    }
 326    // In a totally bizzaro case, where URLs and titles are optional but the field is required, ensure there is at least one link.
 327    if ($field['url'] == 'optional' && $field['title'] == 'optional' && (strlen(trim($item['url'])) != 0 || strlen(trim($item['title'])) != 0)) {
 328      $optional_field_found = TRUE;
 329    }
 330  }
 331  
 332  /**
 333   * Cleanup user-entered values for a link field according to field settings.
 334   *
 335   * @param $item
 336   *   A single link item, usually containing url, title, and attributes.
 337   * @param $delta
 338   *   The delta value if this field is one of multiple fields.
 339   * @param $field
 340   *   The CCK field definition.
 341   * @param $node
 342   *   The node containing this link.
 343   */
 344  function _link_sanitize(&$item, $delta, &$field, &$node) {
 345    // Don't try to process empty links.
 346    if (empty($item['url']) && empty($item['title'])) {
 347      return;
 348    }
 349  
 350    // Replace URL tokens.
 351    if (module_exists('token') && $field['enable_tokens']) {
 352      // Load the node if necessary for nodes in views.
 353      $token_node = isset($node->nid) ? node_load($node->nid) : $node;
 354      $item['url'] = token_replace($item['url'], 'node', $token_node);
 355    }
 356  
 357    $type = link_validate_url($item['url']);
 358    // If we can't determine the type of url, and we've been told not to validate it,
 359    // then we assume it's a LINK_EXTERNAL type for later processing. #357604
 360    if ($type == FALSE && $field['validate_url'] === 0) {
 361      $type = LINK_EXTERNAL;
 362    }
 363    $url = link_cleanup_url($item['url']);
 364  
 365    // Separate out the anchor if any.
 366    if (strpos($url, '#') !== FALSE) {
 367      $item['fragment'] = substr($url, strpos($url, '#') + 1);
 368      $url = substr($url, 0, strpos($url, '#'));
 369    }
 370    // Separate out the query string if any.
 371    if (strpos($url, '?') !== FALSE) {
 372      $item['query'] = substr($url, strpos($url, '?') + 1);
 373      $url = substr($url, 0, strpos($url, '?'));
 374    }
 375    // Save the new URL without the anchor or query.
 376    if ($field['validate_url'] === 0) {
 377      $item['url'] = check_plain($url);
 378    }
 379    else {
 380      $item['url'] = $url;
 381    }
 382  
 383    // Create a shortened URL for display.
 384    $display_url = $type == LINK_EMAIL ? str_replace('mailto:', '', $url) : url($url, array('query' => isset($item['query']) ? $item['query'] : NULL, 'fragment' => isset($item['fragment']) ? $item['fragment'] : NULL, 'absolute' => TRUE));
 385    if ($field['display']['url_cutoff'] && strlen($display_url) > $field['display']['url_cutoff']) {
 386      $display_url = substr($display_url, 0, $field['display']['url_cutoff']) ."...";
 387    }
 388    $item['display_url'] = $display_url;
 389  
 390    // Use the title defined at the field level.
 391    if ($field['title'] == 'value' && strlen(trim($field['title_value']))) {
 392      $title = $field['title_value'];
 393    }
 394    // Use the title defined by the user at the widget level.
 395    else {
 396      $title = $item['title'];
 397    }
 398    // Replace tokens. - originally we only did it for value titles.
 399    if ($field['enable_tokens'] && module_exists('token')) {
 400      // Load the node if necessary for nodes in views.
 401      $token_node = isset($node->nid) ? node_load($node->nid) : $node;
 402      $title = filter_xss(token_replace($title, 'node', $token_node), array('b', 'br', 'code', 'em', 'i', 'img', 'span', 'strong', 'sub', 'sup', 'tt', 'u'));
 403      $item['html'] = TRUE;
 404    }
 405    elseif ($field['title'] == 'value') {
 406      $title = filter_xss($title, array('b', 'br', 'code', 'em', 'i', 'img', 'span', 'strong', 'sub', 'sup', 'tt', 'u'));
 407      $item['html'] = TRUE;
 408    }
 409    $item['display_title'] = empty($title) ? $item['display_url'] : $title;
 410  
 411    if (!isset($item['attributes'])) {
 412      $item['attributes'] = array();
 413    }
 414  
 415    // Unserialize attributtes array if it has not been unserialized yet.
 416    if (!is_array($item['attributes'])) {
 417      $item['attributes'] = (array)unserialize($item['attributes']);
 418    }
 419  
 420    // Add default attributes.  Make sure that $field['attributes'] is an array. #626932
 421    if (!is_array($field['attributes'])) {
 422      $field['attributes'] = array();
 423    }
 424    $field['attributes'] += _link_default_attributes();
 425  
 426    // Merge item attributes with attributes defined at the field level.
 427    $item['attributes'] += $field['attributes'];
 428  
 429    // If user is not allowed to choose target attribute, use default defined at
 430    // field level.
 431    if ($field['attributes']['target'] != LINK_TARGET_USER) {
 432      $item['attributes']['target'] = $field['attributes']['target'];
 433    }
 434  
 435    // Remove the target attribute if the default (no target) is selected.
 436    if (empty($item['attributes']) || $item['attributes']['target'] == LINK_TARGET_DEFAULT) {
 437      unset($item['attributes']['target']);
 438    }
 439  
 440    // Remove the rel=nofollow for internal links.
 441    if ($type != LINK_EXTERNAL && $type != LINK_NEWS && strpos($item['attributes']['rel'], 'nofollow') !== FALSE) {
 442      $item['attributes']['rel'] = str_replace('nofollow', '', $item['attributes']['rel']);
 443    }
 444    // Some old field data may have $element['#item']['attributes']['rel'] as an array, which will cause errors:
 445    if (is_array($element['#item']['attributes']['rel'])) {
 446      unset($element['#item']['attributes']['rel']);
 447    }
 448  
 449    // Handle "title" link attribute
 450    if ($field['enable_tokens'] && !empty($item['attributes']['title']) && module_exists('token')) {
 451      // Load the node (necessary for nodes in views).
 452      $token_node = isset($node->nid) ? node_load($node->nid) : $node;
 453      $item['attributes']['title'] = token_replace($item['attributes']['title'], 'node', $token_node);
 454    }
 455  
 456    // Remove title attribute if it's equal to link text.
 457    if ($item['attributes']['title'] == $item['display_title']) {
 458      unset($item['attributes']['title']);
 459    }
 460  
 461    // Remove empty attributes.
 462    $item['attributes'] = array_filter($item['attributes']);
 463  
 464    // Add the widget label.
 465    $item['label'] = $field['widget']['label'];
 466  }
 467  
 468  /**
 469   * Implementation of hook_theme().
 470   */
 471  function link_theme() {
 472    return array(
 473      'link_field_settings' => array(
 474        'arguments' => array('element' => NULL),
 475      ),
 476      'link_formatter_default' => array(
 477        'arguments' => array('element' => NULL),
 478      ),
 479      'link_formatter_plain' => array(
 480        'arguments' => array('element' => NULL),
 481      ),
 482      'link_formatter_title_plain' => array(
 483        'arguments' => array('element' => NULL),
 484      ),
 485      'link_formatter_url' => array(
 486        'arguments' => array('element' => NULL),
 487      ),
 488      'link_formatter_short' => array(
 489        'arguments' => array('element' => NULL),
 490      ),
 491      'link_formatter_label' => array(
 492        'arguments' => array('element' => NULL),
 493      ),
 494      'link_formatter_separate' => array(
 495        'arguments' => array('element' => NULL),
 496      ),
 497      'link' => array(
 498        'arguments' => array('element' => NULL),
 499      ),
 500    );
 501  }
 502  
 503  /**
 504   * FAPI theme for an individual text elements.
 505   */
 506  function theme_link($element) {
 507    drupal_add_css(drupal_get_path('module', 'link') .'/link.css');
 508  
 509    // Prefix single value link fields with the name of the field.
 510    if (empty($element['#field']['multiple'])) {
 511      if (isset($element['url']) && isset($element['title'])) {
 512        $element['url']['#title'] = $element['#title'] .' '. $element['url']['#title'];
 513        $element['title']['#title'] = $element['#title'] .' '. $element['title']['#title'];
 514      }
 515      elseif ($element['url']) {
 516        $element['url']['#title'] = $element['#title'];
 517      }
 518    }
 519  
 520    $output = '';
 521    $output .= '<div class="link-field-subrow clear-block">';
 522    if (isset($element['title'])) {
 523      $output .= '<div class="link-field-title link-field-column">'. theme('textfield', $element['title']) .'</div>';
 524    }
 525    $output .= '<div class="link-field-url'. (isset($element['title']) ? ' link-field-column' : '') .'">'. theme('textfield', $element['url']) .'</div>';
 526    $output .= '</div>';
 527    if (!empty($element['attributes']['target'])) {
 528      $output .= '<div class="link-attributes">'. theme('checkbox', $element['attributes']['target']) .'</div>';
 529    }
 530    return $output;
 531  }
 532  
 533  /**
 534   * Implementation of hook_elements().
 535   */
 536  function link_elements() {
 537    $elements = array();
 538    $elements['link'] =  array(
 539      '#input' => TRUE,
 540      '#process' => array('link_process'),
 541    );
 542    return $elements;
 543  }
 544  
 545  function _link_default_attributes() {
 546    return array(
 547      'title' => '',
 548      'target' => LINK_TARGET_DEFAULT,
 549      'class' => '',
 550      'rel' => '',
 551    );
 552  }
 553  
 554  /**
 555   * Process the link type element before displaying the field.
 556   *
 557   * Build the form element. When creating a form using FAPI #process,
 558   * note that $element['#value'] is already set.
 559   *
 560   * The $fields array is in $form['#field_info'][$element['#field_name']].
 561   */
 562  function link_process($element, $edit, $form_state, $form) {
 563     $field = $form['#field_info'][$element['#field_name']];
 564     $delta = $element['#delta'];
 565     $element['url'] = array(
 566       '#type' => 'textfield',
 567       '#maxlength' => LINK_URL_MAX_LENGTH,
 568       '#title' => t('URL'),
 569       '#description' => $element['#description'],
 570       '#required' => ($delta == 0 && $field['url'] !== 'optional') ? $element['#required'] : FALSE,
 571       '#default_value' => isset($element['#value']['url']) ? $element['#value']['url'] : NULL,
 572     );
 573     if ($field['title'] != 'none' && $field['title'] != 'value') {
 574       $element['title'] = array(
 575         '#type' => 'textfield',
 576         '#maxlength' => '255',
 577         '#title' => t('Title'),
 578         '#required' => ($delta == 0 && $field['title'] == 'required') ? $field['required'] : FALSE,
 579         '#default_value' => isset($element['#value']['title']) ? $element['#value']['title'] : NULL,
 580       );
 581     }
 582  
 583     // Initialize field attributes as an array if it is not an array yet.
 584     if (!is_array($field['attributes'])) {
 585       $field['attributes'] = array();
 586     }
 587     // Add default atrributes.
 588     $field['attributes'] += _link_default_attributes();
 589     $attributes = isset($element['#value']['attributes']) ? $element['#value']['attributes'] : $field['attributes'];
 590     if (!empty($field['attributes']['target']) && $field['attributes']['target'] == LINK_TARGET_USER) {
 591       $element['attributes']['target'] = array(
 592         '#type' => 'checkbox',
 593         '#title' => t('Open URL in a New Window'),
 594         '#return_value' => LINK_TARGET_NEW_WINDOW,
 595         '#default_value' => $attributes['target'],
 596       );
 597     }
 598     return $element;
 599  }
 600  
 601  /**
 602   * Implementation of hook_field_formatter_info().
 603   */
 604  function link_field_formatter_info() {
 605    return array(
 606      'default' => array(
 607        'label' => t('Title, as link (default)'),
 608        'field types' => array('link'),
 609        'multiple values' => CONTENT_HANDLE_CORE,
 610      ),
 611      'title_plain' => array(
 612        'label' => t('Title, as plain text'),
 613        'field types' => array('link'),
 614        'multiple values' => CONTENT_HANDLE_CORE,
 615      ),
 616      'url' => array(
 617        'label' => t('URL, as link'),
 618        'field types' => array('link'),
 619        'multiple values' => CONTENT_HANDLE_CORE,
 620      ),
 621      'plain' => array(
 622        'label' => t('URL, as plain text'),
 623        'field types' => array('link'),
 624        'multiple values' => CONTENT_HANDLE_CORE,
 625      ),
 626      'short' => array(
 627        'label' => t('Short, as link with title "Link"'),
 628        'field types' => array('link'),
 629        'multiple values' => CONTENT_HANDLE_CORE,
 630      ),
 631      'label' => array(
 632        'label' => t('Label, as link with label as title'),
 633        'field types' => array('link'),
 634        'multiple values' => CONTENT_HANDLE_CORE,
 635      ),
 636      'separate' => array(
 637        'label' => t('Separate title and URL'),
 638        'field types' => array('link'),
 639        'multiple values' => CONTENT_HANDLE_CORE,
 640      ),
 641    );
 642  }
 643  
 644  /**
 645   * Theme function for 'default' text field formatter.
 646   */
 647  function theme_link_formatter_default($element) {
 648    // Display a normal link if both title and URL are available.
 649    if (!empty($element['#item']['display_title']) && !empty($element['#item']['url'])) {
 650      return l($element['#item']['display_title'], $element['#item']['url'], $element['#item']);
 651    }
 652    // If only a title, display the title.
 653    elseif (!empty($element['#item']['display_title'])) {
 654      return check_plain($element['#item']['display_title']);
 655    }
 656  }
 657  
 658  /**
 659   * Theme function for 'plain' text field formatter.
 660   */
 661  function theme_link_formatter_plain($element) {
 662    return empty($element['#item']['url']) ? check_plain($element['#item']['title']) : url($element['#item']['url'], $element['#item']);
 663  }
 664  
 665  /**
 666   * Theme function for 'title_plain' text field formatter.
 667   */
 668  function theme_link_formatter_title_plain($element) {
 669    return empty($element['#item']['title']) ? '' : check_plain($element['#item']['title']);
 670  }
 671  
 672  /**
 673   * Theme function for 'url' text field formatter.
 674   */
 675  function theme_link_formatter_url($element) {
 676    return $element['#item']['url'] ? l($element['#item']['display_url'], $element['#item']['url'], $element['#item']) : '';
 677  }
 678  
 679  /**
 680   * Theme function for 'short' text field formatter.
 681   */
 682  function theme_link_formatter_short($element) {
 683    return $element['#item']['url'] ? l(t('Link'), $element['#item']['url'], $element['#item']) : '';
 684  }
 685  
 686  /**
 687   * Theme function for 'label' text field formatter.
 688   */
 689  function theme_link_formatter_label($element) {
 690    return $element['#item']['url'] ? l($element['#item']['label'], $element['#item']['url'], $element['#item']) : '';
 691  }
 692  
 693  /**
 694   * Theme function for 'separate' text field formatter.
 695   */
 696  function theme_link_formatter_separate($element) {
 697    $class = empty($element['#item']['attributes']['class']) ? '' : ' '. $element['#item']['attributes']['class'];
 698    unset($element['#item']['attributes']['class']);
 699    $title = empty($element['#item']['title']) ? '' : check_plain($element['#item']['title']);
 700  
 701    $output = '';
 702    $output .= '<div class="link-item '. $class .'">';
 703    if (!empty($title)) {
 704      $output .= '<div class="link-title">'. $title .'</div>';
 705    }
 706    $output .= '<div class="link-url">'. l($element['#item']['display_url'], $element['#item']['url'], $element['#item']) .'</div>';
 707    $output .= '</div>';
 708    return $output;
 709  }
 710  
 711  function link_token_list($type = 'all') {
 712    if ($type == 'field' || $type == 'all') {
 713      $tokens = array();
 714  
 715      $tokens['link']['url'] = t("Link URL");
 716      $tokens['link']['title'] = t("Link title");
 717      $tokens['link']['view'] = t("Formatted html link");
 718  
 719      return $tokens;
 720    }
 721  }
 722  
 723  function link_token_values($type, $object = NULL) {
 724    if ($type == 'field') {
 725      $item = $object[0];
 726  
 727      $tokens['url'] = $item['url'];
 728      $tokens['title'] = $item['title'];
 729      $tokens['view'] = isset($item['view']) ? $item['view'] : '';
 730  
 731      return $tokens;
 732    }
 733  }
 734  
 735  /**
 736   * Implementation of hook_views_api().
 737   */
 738  function link_views_api() {
 739    return array(
 740      'api' => 2,
 741      'path' => drupal_get_path('module', 'link') .'/views',
 742    );
 743  }
 744  
 745  /**
 746   * Forms a valid URL if possible from an entered address.
 747   * Trims whitespace and automatically adds an http:// to addresses without a protocol specified
 748   *
 749   * @param string $url
 750   * @param string $protocol The protocol to be prepended to the url if one is not specified
 751   */
 752  function link_cleanup_url($url, $protocol = "http") {
 753    $url = trim($url);
 754    $type = link_validate_url($url);
 755  
 756    if ($type == LINK_EXTERNAL) {
 757      // Check if there is no protocol specified.
 758      $protocol_match = preg_match("/^([a-z0-9][a-z0-9\.\-_]*:\/\/)/i", $url);
 759      if (empty($protocol_match)) {
 760        // But should there be? Add an automatic http:// if it starts with a domain name.
 761        $domain_match = preg_match('/^(([a-z0-9]([a-z0-9\-_]*\.)+)('. LINK_DOMAINS .'|[a-z]{2}))/i', $url);
 762        if (!empty($domain_match)) {
 763          $url = $protocol ."://". $url;
 764        }
 765      }
 766    }
 767  
 768    return $url;
 769  }
 770  
 771  /**
 772   * Wrapper around html_entity_decode to handle problems with PHP 4.
 773   *
 774   * See http://drupal.org/node/739650
 775   * See http://bugs.php.net/bug.php?id=25670
 776   *
 777   * We've taken this away from the beginning of file define() step, as this is
 778   * going to be slower for PHP4, and we don't want to run this on every page load,
 779   * just when we're doing a validate.
 780   */
 781  function _link_html_entity_decode($html_string, $quote_style = ENT_COMPAT, $charset) {
 782    if (defined('PHP_VERSION')) {
 783      $version = explode('.', PHP_VERSION);
 784      if ($version[0] == '5') {
 785        return html_entity_decode($html_string, $quote_style, $charset); // PHP 5, use default.
 786      }
 787    }
 788    else {
 789      $version = explode('.', PHP_VERSION);
 790      if ($version[0] == '5') {
 791        return html_entity_decode($html_string, $quote_style, $charset);
 792      }
 793    }
 794    // use suggested code from http://drupal.org/node/739650
 795    // replace numeric entities
 796    $string = preg_replace('~&#x([0-9a-f]+);~ei', "_link_code2utf(hexdec('\\1'))", $html_string);
 797    $string = preg_replace('~&#([0-9]+);~e', '_link_code2utf("\\1")', $string);
 798  
 799    // replace literal entities.
 800    $trans_tbl = get_html_translation_table(HTML_ENTITIES);
 801    $trans_tbl = array_flip($trans_tbl);
 802  
 803    return strtr($string, $trans_tbl);
 804  }
 805  
 806  /**
 807   * Returns the utf string corresponding to the unicode value.
 808   *
 809   * Needed for handling utf characters in PHP4.
 810   *
 811   * @see http://www.php.net/manual/en/function.html-entity-decode.php#75153
 812   */
 813  function _link_code2utf($num) {
 814    if ($num < 128) return chr($num);
 815    if ($num < 2048) return chr(($num >> 6) + 192) . chr(($num & 63) + 128);
 816    if ($num < 65536) return chr(($num >> 12) + 224) . chr((($num >> 6) & 63) + 128) . chr(($num & 63) + 128);
 817    if ($num < 2097152) return chr(($num >> 18) + 240) . chr((($num >> 12) & 63) + 128) . chr((($num >> 6) & 63) + 128) . chr(($num & 63) + 128);
 818    return '';
 819  }
 820  
 821  /**
 822   * A lenient verification for URLs. Accepts all URLs following RFC 1738 standard
 823   * for URL formation and all email addresses following the RFC 2368 standard for
 824   * mailto address formation.
 825   *
 826   * @param string $text
 827   * @return mixed Returns boolean FALSE if the URL is not valid. On success, returns an object with
 828   * the following attributes: protocol, hostname, ip, and port.
 829   */
 830  function link_validate_url($text) {
 831    $LINK_ICHARS_DOMAIN = (string) _link_html_entity_decode(implode("", array(
 832      "&#x00E6;", // æ
 833      "&#x00C6;", // Æ
 834      "&#x00F8;", // ø
 835      "&#x00D8;", // Ø
 836      "&#x00E5;", // å
 837      "&#x00C5;", // Å
 838      "&#x00E4;", // ä
 839      "&#x00C4;", // Ä
 840      "&#x00F6;", // ö
 841      "&#x00D6;", // Ö
 842      "&#x00FC;", // ü
 843      "&#x00DC;", // Ü
 844      "&#x00D1;", // Ñ
 845      "&#x00F1;", // ñ
 846    )), ENT_QUOTES, 'UTF-8');
 847    
 848    $LINK_ICHARS = $LINK_ICHARS_DOMAIN . (string) _link_html_entity_decode(implode("", array(
 849      "&#x00DF;", // ß
 850    )), ENT_QUOTES, 'UTF-8');
 851    $allowed_protocols = variable_get('filter_allowed_protocols', array('http', 'https', 'ftp', 'news', 'nntp', 'telnet', 'mailto', 'irc', 'ssh', 'sftp', 'webcal'));
 852  
 853    $protocol = '(('. implode("|", $allowed_protocols) .'):\/\/)';
 854    $authentication = '(([a-z0-9%' . $LINK_ICHARS . ']+(:[a-z0-9%'. $LINK_ICHARS . '!]*)?)?@)';
 855    $domain = '(([a-z0-9' . $LINK_ICHARS_DOMAIN . ']([a-z0-9'. $LINK_ICHARS_DOMAIN . '\-_\[\]])*)(\.(([a-z0-9' . $LINK_ICHARS_DOMAIN . '\-_\[\]])+\.)*('. LINK_DOMAINS .'|[a-z]{2}))?)';
 856    $ipv4 = '([0-9]{1,3}(\.[0-9]{1,3}){3})';
 857    $ipv6 = '([0-9a-fA-F]{1,4}(\:[0-9a-fA-F]{1,4}){7})';
 858    $port = '(:([0-9]{1,5}))';
 859  
 860    // Pattern specific to external links.
 861    $external_pattern = '/^'. $protocol .'?'. $authentication .'?('. $domain .'|'. $ipv4 .'|'. $ipv6 .' |localhost)'. $port .'?';
 862  
 863    // Pattern specific to internal links.
 864    $internal_pattern = "/^([a-z0-9". $LINK_ICHARS ."_\-+\[\]]+)";
 865    $internal_pattern_file = "/^([a-z0-9". $LINK_ICHARS ."_\-+\[\]\.]+)$/i";
 866  
 867    $directories = "(\/[a-z0-9". $LINK_ICHARS ."_\-\.~+%=&,$'!():;*@\[\]]*)*";
 868    // Yes, four backslashes == a single backslash.
 869    $query = "(\/?\?([?a-z0-9". $LINK_ICHARS ."+_|\-\.\/\\\\%=&,$'():;*@\[\]{} ]*))";
 870    $anchor = "(#[a-z0-9". $LINK_ICHARS ."_\-\.~+%=&,$'():;*@\[\]\/\?]*)";
 871  
 872    // The rest of the path for a standard URL.
 873    $end = $directories .'?'. $query .'?'. $anchor .'?'.'$/i';
 874    
 875    $message_id = '[^@].*@'. $domain;
 876    $newsgroup_name = '([0-9a-z+-]*\.)*[0-9a-z+-]*';
 877    $news_pattern = '/^news:('. $newsgroup_name .'|'. $message_id .')$/i';
 878  
 879    $user = '[a-zA-Z0-9'. $LINK_ICHARS .'_\-\.\+\^!#\$%&*+\/\=\?\`\|\{\}~\'\[\]]+';
 880    $email_pattern = '/^mailto:'. $user .'@'.'('. $domain .'|'. $ipv4 .'|'. $ipv6 .'|localhost)'. $query .'?$/';
 881  
 882    if (strpos($text, '<front>') === 0) {
 883      return LINK_FRONT;
 884    }
 885    if (in_array('mailto', $allowed_protocols) && preg_match($email_pattern, $text)) {
 886      return LINK_EMAIL;
 887    }
 888    if (in_array('news', $allowed_protocols) && preg_match($news_pattern, $text)) {
 889      return LINK_NEWS;
 890    }
 891    if (preg_match($internal_pattern . $end, $text)) {
 892      return LINK_INTERNAL;
 893    }
 894    if (preg_match($external_pattern . $end, $text)) {
 895      return LINK_EXTERNAL;
 896    }
 897    if (preg_match($internal_pattern_file, $text)) {
 898      return LINK_INTERNAL;
 899    }
 900  
 901    return FALSE;
 902  }


Generated: Thu Mar 24 11:18:33 2011 Cross-referenced by PHPXref 0.7