| Commit | Line | Data |
|---|---|---|
| f695ec1c NH |
1 | <?php |
| 2 | // $Id$ | |
| 3 | ||
| 4 | /** | |
| 5 | * @file | |
| 6 | * Defines simple link field types. | |
| 7 | */ | |
| 8 | ||
| 8509ca14 NH |
9 | define('LINK_EXTERNAL', 'external'); |
| 10 | define('LINK_INTERNAL', 'internal'); | |
| 11 | define('LINK_FRONT', 'front'); | |
| 12 | define('LINK_EMAIL', 'email'); | |
| 23727726 R |
13 | 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'); |
| 14 | ||
| 15 | define('LINK_TARGET_DEFAULT', 'default'); | |
| 16 | define('LINK_TARGET_NEW_WINDOW', '_blank'); | |
| 17 | define('LINK_TARGET_TOP', '_top'); | |
| 18 | define('LINK_TARGET_USER', 'user'); | |
| 8509ca14 NH |
19 | |
| 20 | /** | |
| 3c962bfd JF |
21 | * Maximum URLs length. |
| 22 | */ | |
| 23 | define('LINK_URL_MAX_LENGTH', 2048); | |
| 24 | ||
| 25 | /** | |
| 26 | * Implements hook_field_info(). | |
| f695ec1c NH |
27 | */ |
| 28 | function link_field_info() { | |
| 29 | return array( | |
| 3c962bfd | 30 | 'link_field' => array( |
| 23727726 R |
31 | 'label' => t('Link'), |
| 32 | 'description' => t('Store a title, href, and attributes in the database to assemble a link.'), | |
| ebddcdaa R |
33 | 'settings' => array( |
| 34 | 'target' => LINK_TARGET_DEFAULT, | |
| 35 | 'class' => '', | |
| 36 | 'rel' => '', | |
| 37 | ), | |
| 3c962bfd JF |
38 | 'default_widget' => 'link_field', |
| 39 | 'default_formatter' => 'default', | |
| 23727726 | 40 | ), |
| f695ec1c NH |
41 | ); |
| 42 | } | |
| 43 | ||
| 44 | /** | |
| 3c962bfd | 45 | * Implements hook_field_schema(). |
| ebddcdaa R |
46 | */ |
| 47 | function link_field_schema($field) { | |
| 48 | return array( | |
| 49 | 'columns' => array( | |
| 50 | 'url' => array( | |
| 51 | 'type' => 'varchar', | |
| 3c962bfd | 52 | 'length' => LINK_URL_MAX_LENGTH, |
| ebddcdaa R |
53 | 'not null' => FALSE, |
| 54 | 'sortable' => TRUE | |
| 55 | ), | |
| 56 | 'title' => array( | |
| 57 | 'type' => 'varchar', | |
| 58 | 'length' => 255, | |
| 59 | 'not null' => FALSE, | |
| 60 | 'sortable' => TRUE | |
| 61 | ), | |
| 62 | 'attributes' => array( | |
| 63 | 'type' => 'text', | |
| 64 | 'size' => 'medium', | |
| 65 | 'not null' => FALSE | |
| 66 | ), | |
| 67 | ), | |
| 68 | ); | |
| 69 | } | |
| 70 | ||
| 71 | /** | |
| 3c962bfd JF |
72 | * Implements hook_field_settings_form(). |
| 73 | */ | |
| 74 | function link_field_settings_form($field, $instance, $has_data) { | |
| 75 | $form = array( | |
| 76 | '#element_validate' => array('link_field_settings_form_validate'), | |
| 77 | /* '#theme' => 'link_field_settings', */ | |
| 78 | ); | |
| 50761cbd | 79 | |
| 3c962bfd JF |
80 | $form['url'] = array( |
| 81 | '#type' => 'checkbox', | |
| 82 | '#title' => t('Optional URL'), | |
| 83 | '#default_value' => isset($field['settings']['url']) ? $field['settings']['url'] : '', | |
| 84 | '#return_value' => 'optional', | |
| 85 | '#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.'), | |
| 86 | ); | |
| 50761cbd | 87 | |
| 3c962bfd JF |
88 | $title_options = array( |
| 89 | 'optional' => t('Optional Title'), | |
| 90 | 'required' => t('Required Title'), | |
| 91 | 'value' => t('Static Title'), | |
| 92 | 'none' => t('No Title'), | |
| 93 | ); | |
| 50761cbd | 94 | |
| 3c962bfd JF |
95 | $form['title'] = array( |
| 96 | '#type' => 'radios', | |
| 97 | '#title' => t('Link Title'), | |
| 98 | '#default_value' => isset($field['settings']['title']) ? $field['settings']['title'] : 'optional', | |
| 99 | '#options' => $title_options, | |
| 100 | '#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.'), | |
| 101 | ); | |
| 50761cbd | 102 | |
| 3c962bfd JF |
103 | $form['title_value'] = array( |
| 104 | '#type' => 'textfield', | |
| 105 | '#title' => t('Static title'), | |
| 106 | '#default_value' => isset($field['settings']['title_value']) ? $field['settings']['title_value'] : '', | |
| 107 | /* '#size' => '46', */ | |
| 108 | '#description' => t('This title will always be used if “Static Title” is selected above.'), | |
| 109 | ); | |
| 50761cbd | 110 | |
| 3c962bfd JF |
111 | // Add token module replacements if available |
| 112 | if (module_exists('token')) { | |
| 113 | $form['tokens'] = array( | |
| 114 | '#type' => 'fieldset', | |
| 115 | '#collapsible' => TRUE, | |
| 116 | '#collapsed' => TRUE, | |
| 117 | '#title' => t('Placeholder tokens'), | |
| 118 | '#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."), | |
| 119 | ); | |
| 120 | $form['tokens']['help'] = array( | |
| 121 | '#value' => theme('token_help', 'node'), | |
| 122 | ); | |
| 50761cbd | 123 | |
| 3c962bfd JF |
124 | $form['enable_tokens'] = array( |
| 125 | '#type' => 'checkbox', | |
| 126 | '#title' => t('Allow user-entered tokens'), | |
| 127 | '#default_value' => isset($field['settings']['enable_tokens']) ? $field['settings']['enable_tokens'] : 1, | |
| 128 | '#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.'), | |
| 129 | ); | |
| 130 | } | |
| 50761cbd | 131 | |
| 3c962bfd JF |
132 | $form['display'] = array( |
| 133 | '#tree' => TRUE, | |
| 134 | ); | |
| 135 | $form['display']['url_cutoff'] = array( | |
| 136 | '#type' => 'textfield', | |
| 137 | '#title' => t('URL Display Cutoff'), | |
| 138 | '#default_value' => isset($field['settings']['display']['url_cutoff']) ? $field['settings']['display']['url_cutoff'] : '80', | |
| 139 | '#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 (…)? Leave blank for no limit.'), | |
| 140 | '#maxlength' => 3, | |
| 141 | '#size' => 3, | |
| 142 | ); | |
| 50761cbd | 143 | |
| 3c962bfd JF |
144 | $target_options = array( |
| 145 | LINK_TARGET_DEFAULT => t('Default (no target attribute)'), | |
| 146 | LINK_TARGET_TOP => t('Open link in window root'), | |
| 147 | LINK_TARGET_NEW_WINDOW => t('Open link in new window'), | |
| 148 | LINK_TARGET_USER => t('Allow the user to choose'), | |
| 149 | ); | |
| 150 | $form['attributes'] = array( | |
| 151 | '#tree' => TRUE, | |
| 152 | ); | |
| 153 | $form['attributes']['target'] = array( | |
| 154 | '#type' => 'radios', | |
| 155 | '#title' => t('Link Target'), | |
| 156 | '#default_value' => empty($field['settings']['attributes']['target']) ? LINK_TARGET_DEFAULT : $field['settings']['attributes']['target'], | |
| 157 | '#options' => $target_options, | |
| 158 | ); | |
| 159 | $form['attributes']['rel'] = array( | |
| 160 | '#type' => 'textfield', | |
| 161 | '#title' => t('Rel Attribute'), | |
| 162 | '#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="nofollow"</a> which prevents some search engines from spidering entered links.'), | |
| 163 | '#default_value' => empty($field['settings']['attributes']['rel']) ? '' : $field['settings']['attributes']['rel'], | |
| 164 | '#field_prefix' => 'rel = "', | |
| 165 | '#field_suffix' => '"', | |
| 166 | '#size' => 20, | |
| 167 | ); | |
| 168 | $form['attributes']['class'] = array( | |
| 169 | '#type' => 'textfield', | |
| 170 | '#title' => t('Additional CSS Class'), | |
| 171 | '#description' => t('When output, this link will have have this class attribute. Multiple classes should be separated by spaces.'), | |
| 172 | '#default_value' => empty($field['settings']['attributes']['class']) ? '' : $field['settings']['attributes']['class'], | |
| 173 | ); | |
| 174 | return $form; | |
| 175 | } | |
| 176 | ||
| 177 | /** | |
| 178 | * Validate the field settings form. | |
| 179 | */ | |
| 180 | function link_field_settings_form_validate($element, &$form_state, $complete_form) { | |
| 181 | if ($form_state['values']['field']['settings']['title'] === 'value' && empty($form_state['values']['field']['settings']['title_value'])) { | |
| 182 | form_set_error('title_value', t('A default title must be provided if the title is a static value.')); | |
| 183 | } | |
| 184 | } | |
| 185 | ||
| 186 | /** | |
| f695ec1c NH |
187 | * Implementation of hook_field_settings(). |
| 188 | */ | |
| 189 | function link_field_settings($op, $field) { | |
| 190 | switch ($op) { | |
| 191 | case 'form': | |
| 8509ca14 NH |
192 | $form = array( |
| 193 | '#theme' => 'link_field_settings', | |
| 194 | ); | |
| f35cf48f | 195 | |
| 8509ca14 NH |
196 | $form['url'] = array( |
| 197 | '#type' => 'checkbox', | |
| 198 | '#title' => t('Optional URL'), | |
| 199 | '#default_value' => $field['url'], | |
| 200 | '#return_value' => 'optional', | |
| 23727726 | 201 | '#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.'), |
| 8509ca14 NH |
202 | ); |
| 203 | ||
| 204 | $title_options = array( | |
| 500b2140 NH |
205 | 'optional' => t('Optional Title'), |
| 206 | 'required' => t('Required Title'), | |
| 8509ca14 | 207 | 'value' => t('Static Title: '), |
| 500b2140 NH |
208 | 'none' => t('No Title'), |
| 209 | ); | |
| f35cf48f | 210 | |
| 500b2140 NH |
211 | $form['title'] = array( |
| 212 | '#type' => 'radios', | |
| 213 | '#title' => t('Link Title'), | |
| 214 | '#default_value' => isset($field['title']) ? $field['title'] : 'optional', | |
| 8509ca14 | 215 | '#options' => $title_options, |
| 23727726 | 216 | '#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.'), |
| 8509ca14 | 217 | ); |
| f35cf48f | 218 | |
| 8509ca14 NH |
219 | $form['title_value'] = array( |
| 220 | '#type' => 'textfield', | |
| 221 | '#default_value' => $field['title_value'], | |
| 222 | '#size' => '46', | |
| 223 | ); | |
| f35cf48f | 224 | |
| 8509ca14 NH |
225 | // Add token module replacements if available |
| 226 | if (module_exists('token')) { | |
| 227 | $form['tokens'] = array( | |
| 228 | '#type' => 'fieldset', | |
| 229 | '#collapsible' => TRUE, | |
| 230 | '#collapsed' => TRUE, | |
| 231 | '#title' => t('Placeholder tokens'), | |
| 232 | '#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."), | |
| 233 | ); | |
| 234 | $form['tokens']['help'] = array( | |
| 235 | '#value' => theme('token_help', 'node'), | |
| 236 | ); | |
| f35cf48f | 237 | |
| 8509ca14 NH |
238 | $form['enable_tokens'] = array( |
| 239 | '#type' => 'checkbox', | |
| 23727726 R |
240 | '#title' => t('Allow user-entered tokens'), |
| 241 | '#default_value' => isset($field['enable_tokens']) ? $field['enable_tokens'] : 1, | |
| 8509ca14 NH |
242 | '#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.'), |
| 243 | ); | |
| 244 | } | |
| f35cf48f | 245 | |
| 8509ca14 | 246 | $form['display'] = array( |
| 23727726 | 247 | '#tree' => TRUE, |
| 8509ca14 NH |
248 | ); |
| 249 | $form['display']['url_cutoff'] = array( | |
| 250 | '#type' => 'textfield', | |
| 251 | '#title' => t('URL Display Cutoff'), | |
| 252 | '#default_value' => isset($field['display']['url_cutoff']) ? $field['display']['url_cutoff'] : '80', | |
| 253 | '#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 (…)? Leave blank for no limit.'), | |
| 254 | '#maxlength' => 3, | |
| 255 | '#size' => 3, | |
| 500b2140 | 256 | ); |
| f35cf48f | 257 | |
| 8509ca14 | 258 | $target_options = array( |
| 23727726 R |
259 | LINK_TARGET_DEFAULT => t('Default (no target attribute)'), |
| 260 | LINK_TARGET_TOP => t('Open link in window root'), | |
| 261 | LINK_TARGET_NEW_WINDOW => t('Open link in new window'), | |
| 262 | LINK_TARGET_USER => t('Allow the user to choose'), | |
| f695ec1c | 263 | ); |
| 8509ca14 | 264 | $form['attributes'] = array( |
| 23727726 | 265 | '#tree' => TRUE, |
| f695ec1c NH |
266 | ); |
| 267 | $form['attributes']['target'] = array( | |
| 268 | '#type' => 'radios', | |
| 269 | '#title' => t('Link Target'), | |
| 23727726 | 270 | '#default_value' => empty($field['attributes']['target']) ? LINK_TARGET_DEFAULT : $field['attributes']['target'], |
| 8509ca14 | 271 | '#options' => $target_options, |
| f695ec1c | 272 | ); |
| 8f5f8b4f | 273 | $form['attributes']['rel'] = array( |
| 8509ca14 NH |
274 | '#type' => 'textfield', |
| 275 | '#title' => t('Rel Attribute'), | |
| 276 | '#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="nofollow"</a> which prevents some search engines from spidering entered links.'), | |
| 23727726 R |
277 | '#default_value' => empty($field['attributes']['rel']) ? '' : $field['attributes']['rel'], |
| 278 | '#field_prefix' => 'rel = "', | |
| 279 | '#field_suffix' => '"', | |
| 280 | '#size' => 20, | |
| 8509ca14 NH |
281 | ); |
| 282 | $form['attributes']['class'] = array( | |
| 283 | '#type' => 'textfield', | |
| 284 | '#title' => t('Additional CSS Class'), | |
| 23727726 R |
285 | '#description' => t('When output, this link will have have this class attribute. Multiple classes should be separated by spaces.'), |
| 286 | '#default_value' => empty($field['attributes']['class']) ? '' : $field['attributes']['class'], | |
| 8f5f8b4f | 287 | ); |
| f695ec1c NH |
288 | return $form; |
| 289 | ||
| 8509ca14 NH |
290 | case 'validate': |
| 291 | if ($field['title'] == 'value' && empty($field['title_value'])) { | |
| 292 | form_set_error('title_value', t('A default title must be provided if the title is a static value')); | |
| 293 | } | |
| 294 | break; | |
| 295 | ||
| f695ec1c | 296 | case 'save': |
| 8509ca14 | 297 | return array('attributes', 'display', 'url', 'title', 'title_value', 'enable_tokens'); |
| d31c2959 NH |
298 | |
| 299 | case 'database columns': | |
| 300 | return array( | |
| 23727726 R |
301 | 'url' => array('type' => 'varchar', 'length' => 255, 'not null' => FALSE, 'sortable' => TRUE), |
| 302 | 'title' => array('type' => 'varchar', 'length' => 255, 'not null' => FALSE, 'sortable' => TRUE), | |
| f35cf48f | 303 | 'attributes' => array('type' => 'text', 'size' => 'medium', 'not null' => FALSE), |
| 8509ca14 | 304 | ); |
| d31c2959 | 305 | |
| 23727726 R |
306 | case 'views data': |
| 307 | module_load_include('inc', 'link', 'views/link.views'); | |
| 308 | return link_views_content_field_data($field); | |
| f695ec1c NH |
309 | } |
| 310 | } | |
| 311 | ||
| 312 | /** | |
| 8509ca14 NH |
313 | * Theme the settings form for the link field. |
| 314 | */ | |
| 3c962bfd | 315 | /* |
| 8509ca14 NH |
316 | function theme_link_field_settings($form) { |
| 317 | $title_value = drupal_render($form['title_value']); | |
| 318 | $title_checkbox = drupal_render($form['title']['value']); | |
| f35cf48f | 319 | |
| 8509ca14 NH |
320 | // Set Static Title radio option to include the title_value textfield. |
| 321 | $form['title']['value'] = array('#value' => '<div class="container-inline">'. $title_checkbox . $title_value .'</div>'); | |
| f35cf48f | 322 | |
| 8509ca14 NH |
323 | // Reprint the title radio options with the included textfield. |
| 324 | return drupal_render($form); | |
| 325 | } | |
| 326 | ||
| 327 | /** | |
| ebddcdaa | 328 | * Implement hook_field_is_empty(). |
| f35cf48f | 329 | */ |
| ebddcdaa | 330 | function link_field_is_empty($item, $field) { |
| 3c962bfd JF |
331 | return empty($item['title']) && empty($item['url']); |
| 332 | } | |
| 333 | ||
| 334 | function link_field_load($entity_type, $entities, $field, $instances, $langcode, &$items, $age) { | |
| 335 | foreach ($entities as $id => $entity) { | |
| 336 | foreach ($items[$id] as $delta => $item) { | |
| 50761cbd | 337 | $items[$id][$delta]['attributes'] = _link_load($field, $item); |
| 3c962bfd | 338 | } |
| f35cf48f | 339 | } |
| f35cf48f NH |
340 | } |
| 341 | ||
| 342 | /** | |
| 3c962bfd | 343 | * Implements hook_field_validate(). |
| f695ec1c | 344 | */ |
| 3c962bfd JF |
345 | function link_field_validate($entity_type, $entity, $field, $instance, $langcode, $items, &$errors) { |
| 346 | $optional_field_found = FALSE; | |
| 347 | foreach ($items as $delta => $value) { | |
| 50761cbd | 348 | _link_validate($items[$delta], $delta, $field, $entity, $instance, $optional_field_found); |
| 3c962bfd JF |
349 | } |
| 350 | } | |
| f35cf48f | 351 | |
| 3c962bfd JF |
352 | /** |
| 353 | * Implements hook_field_presave(). | |
| 354 | */ | |
| 355 | function link_field_presave($entity_type, $entity, $field, $instance, $langcode, &$items) { | |
| 356 | foreach ($items as $delta => $value) { | |
| 50761cbd | 357 | _link_sanitize($items[$delta], $delta, $field, $entity); |
| 3c962bfd | 358 | _link_process($items[$delta], $delta, $field, $entity); |
| f695ec1c NH |
359 | } |
| 360 | } | |
| 361 | ||
| 362 | /** | |
| 3c962bfd | 363 | * Implements hook_field_widget_info(). |
| f695ec1c | 364 | */ |
| 3c962bfd | 365 | function link_field_widget_info() { |
| f695ec1c | 366 | return array( |
| 3c962bfd | 367 | 'link_field' => array( |
| 23727726 | 368 | 'label' => 'Link', |
| 3c962bfd JF |
369 | 'field types' => array('link_field'), |
| 370 | 'multiple values' => FIELD_BEHAVIOR_DEFAULT, | |
| f695ec1c NH |
371 | ), |
| 372 | ); | |
| 373 | } | |
| 374 | ||
| 375 | /** | |
| 3c962bfd | 376 | * Implements hook_field_widget_form(). |
| f695ec1c | 377 | */ |
| 3c962bfd JF |
378 | function link_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element) { |
| 379 | $element += array( | |
| 380 | '#type' => $instance['widget']['type'], | |
| f35cf48f | 381 | '#default_value' => isset($items[$delta]) ? $items[$delta] : '', |
| 0a10b9ca | 382 | ); |
| f35cf48f | 383 | return $element; |
| 0a10b9ca NH |
384 | } |
| 385 | ||
| 3c962bfd JF |
386 | /** |
| 387 | * Implements hook_field_formatter_view(). | |
| 388 | */ | |
| 389 | /*function link_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) { | |
| 390 | $element = array(); | |
| 391 | if ($display['type'] === 'link_default') { | |
| 392 | foreach ($items as $delta => $item) { | |
| 393 | $element[$delta] = array( | |
| 394 | '#markup' => theme('link_field', $item), | |
| 395 | ); | |
| 396 | } | |
| 23727726 | 397 | } |
| 3c962bfd JF |
398 | return $element; |
| 399 | }*/ | |
| 400 | ||
| 401 | function _link_load($field, &$item) { | |
| 50761cbd | 402 | return $item['attributes'] = isset($item['attributes']) ? unserialize($item['attributes']) : $field['settings']['attributes']; |
| 8509ca14 NH |
403 | } |
| 404 | ||
| 3c962bfd | 405 | function _link_process(&$item, $delta = 0, $field, $entity) { |
| 8509ca14 | 406 | // Trim whitespace from URL. |
| f35cf48f | 407 | $item['url'] = trim($item['url']); |
| 23727726 R |
408 | |
| 409 | // if no attributes are set then make sure $item['attributes'] is an empty array - this lets $field['attributes'] override it. | |
| 410 | if (empty($item['attributes'])) { | |
| ebddcdaa | 411 | $item['attributes'] = array(); |
| 23727726 R |
412 | } |
| 413 | ||
| 8509ca14 | 414 | // Serialize the attributes array. |
| f35cf48f NH |
415 | $item['attributes'] = serialize($item['attributes']); |
| 416 | ||
| 417 | // Don't save an invalid default value (e.g. 'http://'). | |
| e5534e6b JF |
418 | if ((isset($field['widget']['default_value'][$delta]['url']) && $item['url'] == $field['widget']['default_value'][$delta]['url']) |
| 419 | && is_object($node)) { | |
| f35cf48f NH |
420 | if (!link_validate_url($item['url'])) { |
| 421 | unset($item['url']); | |
| 8509ca14 NH |
422 | } |
| 423 | } | |
| 424 | } | |
| 425 | ||
| 50761cbd | 426 | function _link_validate(&$item, $delta, $field, $node, $instance, &$optional_field_found) { |
| 3c962bfd | 427 | if ($item['url'] && !(isset($field['widget']['default_value'][$delta]['url']) && $item['url'] === $field['widget']['default_value'][$delta]['url'] && !$item['required'])) { |
| f35cf48f NH |
428 | // Validate the link. |
| 429 | if (link_validate_url(trim($item['url'])) == FALSE) { | |
| 23727726 | 430 | form_set_error($field['field_name'] .']['. $delta .'][url', t('Not a valid URL.')); |
| f35cf48f NH |
431 | } |
| 432 | // Require a title for the link if necessary. | |
| 3c962bfd | 433 | if ($field['settings']['title'] == 'required' && strlen(trim($item['title'])) == 0) { |
| 23727726 | 434 | form_set_error($field['field_name'] .']['. $delta .'][title', t('Titles are required for all links.')); |
| f35cf48f | 435 | } |
| 8509ca14 | 436 | } |
| f35cf48f | 437 | // Require a link if we have a title. |
| 50761cbd | 438 | if ($field['settings']['url'] !== 'optional' && strlen(isset($item['title']) ? $item['title'] : NULL) > 0 && strlen(trim($item['url'])) == 0) { |
| 23727726 | 439 | form_set_error($field['field_name'] .']['. $delta .'][url', t('You cannot enter a title without a link url.')); |
| f35cf48f NH |
440 | } |
| 441 | // In a totally bizzaro case, where URLs and titles are optional but the field is required, ensure there is at least one link. | |
| 3c962bfd | 442 | if ($field['settings']['url'] === 'optional' && $field['settings']['title'] === 'optional' && (strlen(trim($item['url'])) !== 0 || strlen(trim($item['title'])) !== 0)) { |
| f35cf48f | 443 | $optional_field_found = TRUE; |
| 8509ca14 | 444 | } |
| 50761cbd JF |
445 | // Require entire field |
| 446 | if ($field['settings']['url'] === 'optional' | |
| 447 | && $field['settings']['title'] === 'optional' | |
| 448 | && $instance['required'] == 1 && !$optional_field_found && isset($instance['id'])) { | |
| 449 | form_set_error($instance['field_name'] .'][0][title', | |
| 450 | t('At least one title or URL must be entered.')); | |
| 451 | } | |
| 8509ca14 NH |
452 | } |
| 453 | ||
| 454 | /** | |
| f35cf48f | 455 | * Cleanup user-entered values for a link field according to field settings. |
| 23727726 | 456 | * |
| f35cf48f NH |
457 | * @param $item |
| 458 | * A single link item, usually containing url, title, and attributes. | |
| 459 | * @param $delta | |
| 460 | * The delta value if this field is one of multiple fields. | |
| 461 | * @param $field | |
| 462 | * The CCK field definition. | |
| 463 | * @param $node | |
| 464 | * The node containing this link. | |
| 8509ca14 | 465 | */ |
| f35cf48f | 466 | function _link_sanitize(&$item, $delta, &$field, &$node) { |
| 23727726 R |
467 | // Don't try to process empty links. |
| 468 | if (empty($item['url']) && empty($item['title'])) { | |
| 469 | return; | |
| 470 | } | |
| 471 | ||
| f35cf48f NH |
472 | // Replace URL tokens. |
| 473 | if (module_exists('token') && $field['enable_tokens']) { | |
| 23727726 R |
474 | // Load the node if necessary for nodes in views. |
| 475 | $token_node = isset($node->nid) ? node_load($node->nid) : $node; | |
| 476 | $item['url'] = token_replace($item['url'], 'node', $token_node); | |
| f35cf48f NH |
477 | } |
| 478 | ||
| 479 | $type = link_validate_url($item['url']); | |
| 480 | $url = link_cleanup_url($item['url']); | |
| 481 | ||
| 23727726 | 482 | // Separate out the anchor if any. |
| f35cf48f NH |
483 | if (strpos($url, '#') !== FALSE) { |
| 484 | $item['fragment'] = substr($url, strpos($url, '#') + 1); | |
| 485 | $url = substr($url, 0, strpos($url, '#')); | |
| 8509ca14 | 486 | } |
| 23727726 | 487 | // Separate out the query string if any. |
| f35cf48f | 488 | if (strpos($url, '?') !== FALSE) { |
| e5534e6b JF |
489 | $query = substr($url, strpos($url, '?') + 1); |
| 490 | parse_str($query, $query_array); | |
| 491 | $item['query'] = $query_array; | |
| f35cf48f NH |
492 | $url = substr($url, 0, strpos($url, '?')); |
| 493 | } | |
| f35cf48f NH |
494 | |
| 495 | // Create a shortened URL for display. | |
| 23727726 | 496 | $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)); |
| 50761cbd JF |
497 | if ($field['settings']['display']['url_cutoff'] && strlen($display_url) > $field['settings']['display']['url_cutoff']) { |
| 498 | $display_url = substr($display_url, 0, $field['settings']['display']['url_cutoff']) ."..."; | |
| f35cf48f NH |
499 | } |
| 500 | $item['display_url'] = $display_url; | |
| 501 | ||
| 502 | // Use the title defined at the field level. | |
| 50761cbd | 503 | if ($field['settings']['title'] == 'value' && strlen(trim($field['settings']['title_value']))) { |
| e5534e6b | 504 | $title = $field['settings']['title_value']; |
| f35cf48f NH |
505 | } |
| 506 | // Use the title defined by the user at the widget level. | |
| e5534e6b | 507 | else if (isset($item['title'])) { |
| f35cf48f NH |
508 | $title = $item['title']; |
| 509 | } | |
| e5534e6b | 510 | |
| f35cf48f NH |
511 | // Replace tokens. |
| 512 | if (module_exists('token') && ($field['title'] == 'value' || $field['enable_tokens'])) { | |
| 23727726 R |
513 | // Load the node if necessary for nodes in views. |
| 514 | $token_node = isset($node->nid) ? node_load($node->nid) : $node; | |
| 515 | $title = filter_xss(token_replace($title, 'node', $token_node), array('b', 'br', 'code', 'em', 'i', 'img', 'span', 'strong', 'sub', 'sup', 'tt', 'u')); | |
| 516 | $item['html'] = TRUE; | |
| f35cf48f | 517 | } |
| e5534e6b | 518 | $item['title'] = empty($title) ? $item['display_url'] : $title; |
| f35cf48f | 519 | |
| 23727726 R |
520 | if (!isset($item['attributes'])) { |
| 521 | $item['attributes'] = array(); | |
| 522 | } | |
| 523 | ||
| 524 | // Unserialize attributtes array if it has not been unserialized yet. | |
| 525 | if (!is_array($item['attributes'])) { | |
| 526 | $item['attributes'] = (array)unserialize($item['attributes']); | |
| 527 | } | |
| 528 | ||
| 529 | // Add default attributes. | |
| 50761cbd | 530 | $field['settings']['attributes'] += _link_default_attributes(); |
| 23727726 R |
531 | |
| 532 | // Merge item attributes with attributes defined at the field level. | |
| 50761cbd | 533 | $item['attributes'] += $field['settings']['attributes']; |
| 23727726 R |
534 | |
| 535 | // If user is not allowed to choose target attribute, use default defined at | |
| 536 | // field level. | |
| 50761cbd JF |
537 | if ($field['settings']['attributes']['target'] != LINK_TARGET_USER) { |
| 538 | $item['attributes']['target'] = $field['settings']['attributes']['target']; | |
| 23727726 R |
539 | } |
| 540 | ||
| 541 | // Remove the target attribute if the default (no target) is selected. | |
| 542 | if (empty($item['attributes']) || $item['attributes']['target'] == LINK_TARGET_DEFAULT) { | |
| 543 | unset($item['attributes']['target']); | |
| 544 | } | |
| 545 | ||
| 546 | // Remove the rel=nofollow for internal links. | |
| 547 | if ($type != LINK_EXTERNAL && strpos($item['attributes']['rel'], 'nofollow') !== FALSE) { | |
| 548 | $item['attributes']['rel'] = str_replace('nofollow', '', $item['attributes']); | |
| 8509ca14 | 549 | } |
| 23727726 R |
550 | |
| 551 | // Remove empty attributes. | |
| 552 | $item['attributes'] = array_filter($item['attributes']); | |
| f35cf48f | 553 | |
| 50761cbd | 554 | // Sets title to trimmed url if one exists |
| e5534e6b | 555 | // @TODO: Do we need this? It seems not. |
| 50761cbd JF |
556 | if(!empty($item['display_url']) && empty($item['title'])) { |
| 557 | $item['title'] = $item['display_url']; | |
| 558 | } | |
| 559 | elseif(!isset($item['title'])) { | |
| 560 | $item['title'] = $item['url']; | |
| 561 | } | |
| e5534e6b | 562 | |
| 8509ca14 NH |
563 | } |
| 564 | ||
| 565 | /** | |
| 3c962bfd | 566 | * Implements hook_theme(). |
| 8509ca14 | 567 | */ |
| f35cf48f NH |
568 | function link_theme() { |
| 569 | return array( | |
| 3c962bfd JF |
570 | /*'link_field_settings' => array( |
| 571 | 'variables' => array('element' => NULL), | |
| 572 | ),*/ | |
| f35cf48f | 573 | 'link_formatter_default' => array( |
| 3c962bfd | 574 | 'variables' => array('element' => NULL), |
| f35cf48f NH |
575 | ), |
| 576 | 'link_formatter_plain' => array( | |
| 3c962bfd | 577 | 'variables' => array('element' => NULL), |
| f35cf48f | 578 | ), |
| 23727726 | 579 | 'link_formatter_url' => array( |
| 3c962bfd | 580 | 'variables' => array('element' => NULL), |
| 23727726 | 581 | ), |
| f35cf48f | 582 | 'link_formatter_short' => array( |
| 3c962bfd | 583 | 'variables' => array('element' => NULL), |
| f35cf48f NH |
584 | ), |
| 585 | 'link_formatter_label' => array( | |
| 3c962bfd | 586 | 'variables' => array('element' => NULL), |
| f35cf48f | 587 | ), |
| 23727726 | 588 | 'link_formatter_separate' => array( |
| 3c962bfd | 589 | 'variables' => array('element' => NULL), |
| 23727726 | 590 | ), |
| 3c962bfd | 591 | 'link_field' => array( |
| 93b7f6b4 | 592 | 'render element' => 'element', |
| f35cf48f NH |
593 | ), |
| 594 | ); | |
| 595 | } | |
| 596 | ||
| 597 | /** | |
| 598 | * FAPI theme for an individual text elements. | |
| f35cf48f | 599 | */ |
| 93b7f6b4 | 600 | function theme_link_field($vars) { |
| f35cf48f NH |
601 | drupal_add_css(drupal_get_path('module', 'link') .'/link.css'); |
| 602 | ||
| 93b7f6b4 | 603 | $element = $vars['element']; |
| 23727726 R |
604 | // Prefix single value link fields with the name of the field. |
| 605 | if (empty($element['#field']['multiple'])) { | |
| 93b7f6b4 JF |
606 | if (isset($element['url']) && !isset($element['title'])) { |
| 607 | unset($element['url']['#title']); | |
| 23727726 | 608 | } |
| f35cf48f NH |
609 | } |
| 610 | ||
| 8509ca14 | 611 | $output = ''; |
| 93b7f6b4 | 612 | $output .= '<div class="link-field-subrow clearfix">'; |
| 23727726 | 613 | if (isset($element['title'])) { |
| 93b7f6b4 | 614 | $output .= '<div class="link-field-title link-field-column">'. drupal_render($element['title']) .'</div>'; |
| 8509ca14 | 615 | } |
| 93b7f6b4 | 616 | $output .= '<div class="link-field-url'. (isset($element['title']) ? ' link-field-column' : '') .'">'. drupal_render($element['url']) .'</div>'; |
| 8509ca14 | 617 | $output .= '</div>'; |
| 23727726 | 618 | if (!empty($element['attributes']['target'])) { |
| 93b7f6b4 | 619 | $output .= '<div class="link-attributes">'. drupal_render($element['attributes']['target']) .'</div>'; |
| 8509ca14 | 620 | } |
| 8509ca14 | 621 | return $output; |
| f9252715 NH |
622 | } |
| 623 | ||
| 23727726 | 624 | /** |
| 3c962bfd | 625 | * Implements hook_element_info(). |
| f35cf48f | 626 | */ |
| 3c962bfd | 627 | function link_element_info() { |
| f35cf48f | 628 | $elements = array(); |
| 3c962bfd | 629 | $elements['link_field'] = array( |
| f35cf48f | 630 | '#input' => TRUE, |
| 3c962bfd | 631 | '#process' => array('link_field_process'), |
| 93b7f6b4 JF |
632 | '#theme' => 'link_field', |
| 633 | '#theme_wrappers' => array('form_element'), | |
| f35cf48f NH |
634 | ); |
| 635 | return $elements; | |
| 636 | } | |
| 637 | ||
| 23727726 R |
638 | function _link_default_attributes() { |
| 639 | return array( | |
| 640 | 'target' => LINK_TARGET_DEFAULT, | |
| 641 | 'class' => '', | |
| 642 | 'rel' => '', | |
| 643 | ); | |
| 644 | } | |
| 645 | ||
| f35cf48f NH |
646 | /** |
| 647 | * Process the link type element before displaying the field. | |
| 648 | * | |
| 649 | * Build the form element. When creating a form using FAPI #process, | |
| 650 | * note that $element['#value'] is already set. | |
| 651 | * | |
| 652 | * The $fields array is in $form['#field_info'][$element['#field_name']]. | |
| 653 | */ | |
| 3c962bfd JF |
654 | function link_field_process($element, $form_state, $form) { |
| 655 | $settings = &$form_state['field'][$element['#field_name']][$element['#language']]['field']['settings']; | |
| 656 | $element['url'] = array( | |
| 657 | '#type' => 'textfield', | |
| 658 | '#maxlength' => LINK_URL_MAX_LENGTH, | |
| 659 | '#title' => t('URL'), | |
| 3c962bfd JF |
660 | '#required' => ($element['#delta'] == 0 && $settings['url'] !== 'optional') ? $element['#required'] : FALSE, |
| 661 | '#default_value' => isset($element['#value']['url']) ? $element['#value']['url'] : NULL, | |
| 662 | ); | |
| 663 | if ($settings['title'] !== 'none' && $settings['title'] !== 'value') { | |
| 664 | $element['title'] = array( | |
| 665 | '#type' => 'textfield', | |
| 666 | '#maxlength' => '255', | |
| 667 | '#title' => t('Title'), | |
| 50761cbd | 668 | '#required' => ($settings['title'] == 'required' && !empty($element['#value']['url'])) ? TRUE : FALSE, |
| 3c962bfd JF |
669 | '#default_value' => isset($element['#value']['title']) ? $element['#value']['title'] : NULL, |
| 670 | ); | |
| 671 | } | |
| 672 | ||
| 673 | // Initialize field attributes as an array if it is not an array yet. | |
| 674 | if (!is_array($settings['attributes'])) { | |
| 675 | $settings['attributes'] = array(); | |
| 676 | } | |
| 677 | // Add default atrributes. | |
| 678 | $settings['attributes'] += _link_default_attributes(); | |
| 679 | $attributes = isset($element['#value']['attributes']) ? $element['#value']['attributes'] : $settings['attributes']; | |
| 680 | if (!empty($settings['attributes']['target']) && $settings['attributes']['target'] == LINK_TARGET_USER) { | |
| 681 | $element['attributes']['target'] = array( | |
| 682 | '#type' => 'checkbox', | |
| 683 | '#title' => t('Open URL in a New Window'), | |
| 684 | '#return_value' => LINK_TARGET_NEW_WINDOW, | |
| 50761cbd | 685 | '#default_value' => isset($attributes['target']) ? $attributes['target'] : FALSE, |
| 3c962bfd JF |
686 | ); |
| 687 | } | |
| 688 | return $element; | |
| f35cf48f NH |
689 | } |
| 690 | ||
| 0a10b9ca | 691 | /** |
| d31c2959 NH |
692 | * Implementation of hook_field_formatter_info(). |
| 693 | */ | |
| 694 | function link_field_formatter_info() { | |
| 695 | return array( | |
| 696 | 'default' => array( | |
| 23727726 | 697 | 'label' => t('Title, as link (default)'), |
| 3c962bfd JF |
698 | 'field types' => array('link_field'), |
| 699 | 'multiple values' => FIELD_BEHAVIOR_DEFAULT, | |
| 23727726 R |
700 | ), |
| 701 | 'url' => array( | |
| 702 | 'label' => t('URL, as link'), | |
| 3c962bfd JF |
703 | 'field types' => array('link_field'), |
| 704 | 'multiple values' => FIELD_BEHAVIOR_DEFAULT, | |
| d31c2959 NH |
705 | ), |
| 706 | 'plain' => array( | |
| 23727726 | 707 | 'label' => t('URL, as plain text'), |
| 3c962bfd JF |
708 | 'field types' => array('link_field'), |
| 709 | 'multiple values' => FIELD_BEHAVIOR_DEFAULT, | |
| 8509ca14 NH |
710 | ), |
| 711 | 'short' => array( | |
| 712 | 'label' => t('Short, as link with title "Link"'), | |
| 3c962bfd JF |
713 | 'field types' => array('link_field'), |
| 714 | 'multiple values' => FIELD_BEHAVIOR_DEFAULT, | |
| 8509ca14 NH |
715 | ), |
| 716 | 'label' => array( | |
| 717 | 'label' => t('Label, as link with label as title'), | |
| 3c962bfd JF |
718 | 'field types' => array('link_field'), |
| 719 | 'multiple values' => FIELD_BEHAVIOR_DEFAULT, | |
| d31c2959 | 720 | ), |
| 23727726 R |
721 | 'separate' => array( |
| 722 | 'label' => t('Separate title and URL'), | |
| 3c962bfd JF |
723 | 'field types' => array('link_field'), |
| 724 | 'multiple values' => FIELD_BEHAVIOR_DEFAULT, | |
| 23727726 | 725 | ), |
| d31c2959 NH |
726 | ); |
| 727 | } | |
| 728 | ||
| 3c962bfd JF |
729 | function link_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) { |
| 730 | $elements = array(); | |
| 731 | foreach ($items as $delta => $item) { | |
| 732 | $elements[$delta] = array( | |
| 50761cbd | 733 | '#markup' => theme('link_formatter_'. $display['type'], array('element' => $item, 'field' => $instance)), |
| 3c962bfd JF |
734 | ); |
| 735 | } | |
| 736 | return $elements; | |
| 737 | } | |
| 738 | ||
| d31c2959 | 739 | /** |
| f35cf48f | 740 | * Theme function for 'default' text field formatter. |
| f695ec1c | 741 | */ |
| f35cf48f | 742 | function theme_link_formatter_default($element) { |
| 50761cbd | 743 | //drupal_set_message('<pre>'. print_r($element['element'], TRUE) .'</pre>'); |
| f35cf48f | 744 | // Display a normal link if both title and URL are available. |
| 50761cbd JF |
745 | if (!empty($element['element']['title']) && !empty($element['element']['url'])) { |
| 746 | return l($element['element']['title'], $element['element']['url'], array('attributes' => $element['element']['attributes'])); | |
| f695ec1c | 747 | } |
| f35cf48f | 748 | // If only a title, display the title. |
| 50761cbd JF |
749 | elseif (!empty($element['element']['title'])) { |
| 750 | return check_plain($element['element']['title']); | |
| 751 | } | |
| 752 | elseif (!empty($element['element']['url'])) { | |
| 753 | return l($element['element']['title'], $element['element']['url'], array('attributes' => $element['element']['attributes'])); | |
| 8509ca14 | 754 | } |
| f35cf48f | 755 | } |
| 8509ca14 | 756 | |
| f35cf48f NH |
757 | /** |
| 758 | * Theme function for 'plain' text field formatter. | |
| 759 | */ | |
| 760 | function theme_link_formatter_plain($element) { | |
| 50761cbd | 761 | return empty($element['element']['url']) ? check_plain($element['element']['title']) : url($element['element']['url'], array('attributes' => $element['element']['attributes'])); |
| 23727726 R |
762 | } |
| 763 | ||
| 764 | /** | |
| 765 | * Theme function for 'url' text field formatter. | |
| 766 | */ | |
| 3c962bfd | 767 | /* |
| 23727726 | 768 | function theme_link_formatter_url($element) { |
| 50761cbd | 769 | return $element['element']['url'] ? l($element['element']['display_url'], $element['element']['url'], array('attributes' => $element['element']['attributes']) : ''; |
| f35cf48f | 770 | } |
| 3c962bfd | 771 | */ |
| 8509ca14 | 772 | |
| f35cf48f NH |
773 | /** |
| 774 | * Theme function for 'short' text field formatter. | |
| 775 | */ | |
| 776 | function theme_link_formatter_short($element) { | |
| 50761cbd | 777 | return $element['element']['url'] ? l(t('Link'), $element['element']['url'], array('attributes' => $element['element']['attributes'])) : ''; |
| f695ec1c NH |
778 | } |
| 779 | ||
| 780 | /** | |
| 23727726 | 781 | * Theme function for 'label' text field formatter. |
| f35cf48f NH |
782 | */ |
| 783 | function theme_link_formatter_label($element) { | |
| 50761cbd | 784 | return $element['element']['url'] ? l($element['field']['label'], $element['element']['url'], array('attributes' => $element['element']['attributes'])) : ''; |
| f35cf48f | 785 | } |
| 23727726 | 786 | |
| f35cf48f | 787 | /** |
| 23727726 | 788 | * Theme function for 'separate' text field formatter. |
| 8509ca14 | 789 | */ |
| 50761cbd | 790 | |
| 23727726 | 791 | function theme_link_formatter_separate($element) { |
| 50761cbd JF |
792 | $class = empty($element['element']['attributes']['class']) ? '' : ' '. $element['element']['attributes']['class']; |
| 793 | unset($element['element']['attributes']['class']); | |
| 794 | $title = empty($element['element']['title']) ? '' : check_plain($element['element']['title']); | |
| f35cf48f | 795 | |
| 23727726 R |
796 | $output = ''; |
| 797 | $output .= '<div class="link-item '. $class .'">'; | |
| 798 | if (!empty($title)) { | |
| 799 | $output .= '<div class="link-title">'. $title .'</div>'; | |
| 8509ca14 | 800 | } |
| 50761cbd | 801 | $output .= '<div class="link-url">'. l($element['element']['url'], $element['element']['url'], array('attributes' => $element['element']['attributes'])) .'</div>'; |
| 23727726 R |
802 | $output .= '</div>'; |
| 803 | return $output; | |
| 804 | } | |
| 50761cbd | 805 | |
| f35cf48f | 806 | |
| 23727726 | 807 | function link_token_list($type = 'all') { |
| 3c962bfd | 808 | if ($type === 'field' || $type === 'all') { |
| 23727726 | 809 | $tokens = array(); |
| f35cf48f | 810 | |
| 23727726 R |
811 | $tokens['link']['url'] = t("Link URL"); |
| 812 | $tokens['link']['title'] = t("Link title"); | |
| 813 | $tokens['link']['view'] = t("Formatted html link"); | |
| 8509ca14 | 814 | |
| 23727726 R |
815 | return $tokens; |
| 816 | } | |
| 817 | } | |
| 8509ca14 | 818 | |
| 23727726 | 819 | function link_token_values($type, $object = NULL) { |
| 3c962bfd | 820 | if ($type === 'field') { |
| 23727726 | 821 | $item = $object[0]; |
| 8509ca14 | 822 | |
| 23727726 R |
823 | $tokens['url'] = $item['url']; |
| 824 | $tokens['title'] = $item['title']; | |
| 825 | $tokens['view'] = isset($item['view']) ? $item['view'] : ''; | |
| 8509ca14 | 826 | |
| 23727726 | 827 | return $tokens; |
| 8509ca14 NH |
828 | } |
| 829 | } | |
| 830 | ||
| 831 | /** | |
| 3c962bfd | 832 | * Implements hook_views_api(). |
| 8509ca14 | 833 | */ |
| 23727726 R |
834 | function link_views_api() { |
| 835 | return array( | |
| 836 | 'api' => 2, | |
| 837 | 'path' => drupal_get_path('module', 'link') .'/views', | |
| 838 | ); | |
| 8509ca14 NH |
839 | } |
| 840 | ||
| 841 | /** | |
| f9252715 NH |
842 | * Forms a valid URL if possible from an entered address. |
| 843 | * Trims whitespace and automatically adds an http:// to addresses without a protocol specified | |
| 844 | * | |
| 1051a8ba NH |
845 | * @param string $url |
| 846 | * @param string $protocol The protocol to be prepended to the url if one is not specified | |
| f9252715 | 847 | */ |
| 8509ca14 | 848 | function link_cleanup_url($url, $protocol = "http") { |
| f9252715 | 849 | $url = trim($url); |
| 8509ca14 | 850 | $type = link_validate_url($url); |
| f35cf48f | 851 | |
| 3c962bfd | 852 | if ($type === LINK_EXTERNAL) { |
| 8509ca14 | 853 | // Check if there is no protocol specified. |
| 23727726 | 854 | $protocol_match = preg_match("/^([a-z0-9][a-z0-9\.\-_]*:\/\/)/i", $url); |
| 8509ca14 NH |
855 | if (empty($protocol_match)) { |
| 856 | // But should there be? Add an automatic http:// if it starts with a domain name. | |
| 23727726 | 857 | $domain_match = preg_match('/^(([a-z0-9]([a-z0-9\-_]*\.)+)('. LINK_DOMAINS .'|[a-z]{2}))/i', $url); |
| 8509ca14 | 858 | if (!empty($domain_match)) { |
| 23727726 | 859 | $url = $protocol ."://". $url; |
| 8509ca14 | 860 | } |
| f9252715 NH |
861 | } |
| 862 | } | |
| f35cf48f | 863 | |
| 8509ca14 | 864 | return $url; |
| f9252715 NH |
865 | } |
| 866 | ||
| 867 | /** | |
| 8509ca14 NH |
868 | * A lenient verification for URLs. Accepts all URLs following RFC 1738 standard |
| 869 | * for URL formation and all email addresses following the RFC 2368 standard for | |
| 870 | * mailto address formation. | |
| f9252715 NH |
871 | * |
| 872 | * @param string $text | |
| 873 | * @return mixed Returns boolean FALSE if the URL is not valid. On success, returns an object with | |
| 874 | * the following attributes: protocol, hostname, ip, and port. | |
| 875 | */ | |
| 8509ca14 | 876 | function link_validate_url($text) { |
| f35cf48f | 877 | |
| 8509ca14 | 878 | $allowed_protocols = variable_get('filter_allowed_protocols', array('http', 'https', 'ftp', 'news', 'nntp', 'telnet', 'mailto', 'irc', 'ssh', 'sftp', 'webcal')); |
| f35cf48f | 879 | |
| 23727726 | 880 | $protocol = '(('. implode("|", $allowed_protocols) .'):\/\/)'; |
| 8509ca14 | 881 | $authentication = '([a-z0-9]+(:[a-z0-9]+)?@)'; |
| 23727726 R |
882 | $domain = '(([a-z0-9]([a-z0-9\-_\[\]])*)(\.(([a-z0-9\-_\[\]])+\.)*('. LINK_DOMAINS .'|[a-z]{2}))?)'; |
| 883 | $ipv4 = '([0-9]{1,3}(\.[0-9]{1,3}){3})'; | |
| 884 | $ipv6 = '([0-9a-fA-F]{1,4}(\:[0-9a-fA-F]{1,4}){7})'; | |
| 8509ca14 | 885 | $port = '(:([0-9]{1,5}))'; |
| f35cf48f | 886 | |
| 8509ca14 | 887 | // Pattern specific to eternal links. |
| 23727726 | 888 | $external_pattern = '/^'. $protocol .'?'. $authentication .'?('. $domain .'|'. $ipv4 .'|'. $ipv6 .' |localhost)'. $port .'?'; |
| 8509ca14 NH |
889 | |
| 890 | // Pattern specific to internal links. | |
| 891 | $internal_pattern = "/^([a-z0-9_\-+\[\]]+)"; | |
| 892 | ||
| 23727726 R |
893 | $directories = "(\/[a-z0-9_\-\.~+%=&,$'!():;*@\[\]]*)*"; |
| 894 | // Yes, four backslashes == a single backslash. | |
| 895 | $query = "(\/?\?([?a-z0-9+_|\-\.\/\\\\%=&,$'():;*@\[\]]*))"; | |
| 8509ca14 NH |
896 | $anchor = "(#[a-z0-9_\-\.~+%=&,$'():;*@\[\]]*)"; |
| 897 | ||
| 898 | // The rest of the path for a standard URL. | |
| 23727726 | 899 | $end = $directories .'?'. $query .'?'. $anchor .'?'.'$/i'; |
| 8509ca14 NH |
900 | |
| 901 | $user = '[a-zA-Z0-9_\-\.\+\^!#\$%&*+\/\=\?\`\|\{\}~\'\[\]]+'; | |
| 23727726 | 902 | $email_pattern = '/^mailto:'. $user .'@'.'('. $domain .'|'. $ipv4 .'|'. $ipv6 .'|localhost)'. $query .'?$/'; |
| 8509ca14 | 903 | |
| 23727726 R |
904 | if (strpos($text, '<front>') === 0) { |
| 905 | return LINK_FRONT; | |
| 8509ca14 | 906 | } |
| 23727726 | 907 | if (in_array('mailto', $allowed_protocols) && preg_match($email_pattern, $text)) { |
| 8509ca14 NH |
908 | return LINK_EMAIL; |
| 909 | } | |
| 23727726 R |
910 | if (preg_match($internal_pattern . $end, $text)) { |
| 911 | return LINK_INTERNAL; | |
| 912 | } | |
| 913 | if (preg_match($external_pattern . $end, $text)) { | |
| 914 | return LINK_EXTERNAL; | |
| f695ec1c | 915 | } |
| 23727726 | 916 | |
| 8509ca14 | 917 | return FALSE; |
| 6f21634b | 918 | } |