Project

General

Profile

Download (33.4 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2

    
3
/**
4
 * @file
5
 * Defines simple expertsdb_link field types.
6
 */
7

    
8
define('LINK_EXTERNAL', 'external');
9
define('LINK_INTERNAL', 'internal');
10
define('LINK_FRONT', 'front');
11
define('LINK_EMAIL', 'email');
12
define('LINK_DOMAINS', 'aero|arpa|biz|com|cat|coop|edu|gov|info|int|jobs|mil|museum|name|nato|net|org|pro|travel|mobi');
13

    
14
/*
15
 * Definition of privacy levels
16
 */
17
define('PRIVACY_CONTACT_PRIVATE', 'ContactPrivate');
18
define('PRIVACY_PRIVATE', 'Private');
19
define('PRIVACY_PUBLIC', 'Public');
20

    
21
/**
22
 * Implementation of hook_perm()
23
 *
24
 * Valid permissions for this module
25
 * @return array An array of valid permissions for the portfolio module
26
 */
27
function expertsdb_link_perm() {
28
	return array(
29
    	'view private expertsdb_link fields',
30
	//TODO which else permission are required?
31
	);
32
}
33

    
34
/**
35
 * Implementation of hook_help().
36
 *
37
 * @param unknown_type $section
38
 * @return unknown
39
 */
40
function expertsdb_link_help($section) {
41
	switch ($section) {
42
		case 'admin/modules#description':
43
			return t('Defines a field type for links with optional title. Data will be integrated as serialized array into the according content type database. <em>Note: Requires content.module.</em>');
44
	}
45
}
46

    
47
/**
48
 * Implementation of hook_menu().
49
 */
50
function expertsdb_link_menu($may_cache) {
51
	$items = array();
52
	if ($may_cache) {
53
		$items[] = array(
54
      'path' => 'expertsdb_link/widget/js',
55
      'callback' => 'expertsdb_link_widget_js',
56
      'access' => user_access('access content'),
57
      'type' => MENU_CALLBACK,
58
		);
59
	}
60
	return $items;
61
}
62

    
63
/**
64
 * Implementation of hook_field_info().
65
 */
66
function expertsdb_link_field_info() {
67
	return array(
68
    'expertsdb_link' => array('label' => 'Expertsdb Link'),
69
	);
70
}
71

    
72
/**
73
 * Implementation of hook_field_settings().
74
 */
75
function expertsdb_link_field_settings($op, $field) {
76
	switch ($op) {
77
		case 'form':
78
			$form = array(
79
        '#theme' => 'expertsdb_link_field_settings',
80
			);
81

    
82
			$title_options = array(
83
        'optional' => t('Optional Title'),
84
        'required' => t('Required Title'),
85
        'value' => t('Static Title: '),
86
        'none' => t('No Title'),
87
			);
88

    
89
			$form['title'] = array(
90
        '#type' => 'radios',
91
        '#title' => t('Link Title'),
92
        '#default_value' => isset($field['title']) ? $field['title'] : 'optional',
93
        '#options' => $title_options,
94
        '#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.'),
95
			);
96

    
97
			$form['title_value'] = array(
98
        '#type' => 'textfield',
99
        '#default_value' => $field['title_value'],
100
        '#size' => '46',
101
			);
102

    
103
			// Add token module replacements if available
104
			if (module_exists('token')) {
105
				$form['tokens'] = array(
106
          '#type' => 'fieldset',
107
          '#collapsible' => TRUE,
108
          '#collapsed' => TRUE,
109
          '#title' => t('Placeholder tokens'),
110
          '#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."),
111
				);
112
				$form['tokens']['help'] = array(
113
          '#value' => theme('token_help', 'node'),
114
				);
115

    
116
				$form['enable_tokens'] = array(
117
          '#type' => 'checkbox',
118
          '#title' => t('Allow tokens'),
119
          '#default_value' => isset($field['enable_tokens']) ? $field['enable_tokens'] : 1,
120
          '#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.'),
121
				);
122
			}
123

    
124
			$form['display'] = array(
125
        '#tree' => true,
126
			);
127
			$form['display']['url_cutoff'] = array(
128
        '#type' => 'textfield',
129
        '#title' => t('URL Display Cutoff'),
130
        '#default_value' => $field['display']['url_cutoff'] ? $field['display']['url_cutoff'] : '80',
131
        '#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.'),
132
        '#maxlength' => 3,
133
        '#size' => 3,
134
			);
135

    
136
			$target_options = array(
137
        'default' => t('Default (no target attribute)'),
138
        '_top' => t('Open link in window root'),
139
        '_blank' => t('Open link in new window'),
140
        'user' => t('Allow the user to choose'),
141
			);
142
			$form['attributes'] = array(
143
        '#tree' => true,
144
			);
145
			$form['attributes']['target'] = array(
146
        '#type' => 'radios',
147
        '#title' => t('Link Target'),
148
        '#default_value' => $field['attributes']['target'] ? $field['attributes']['target'] : 'default',
149
        '#options' => $target_options,
150
			);
151
			$form['attributes']['rel'] = array(
152
        '#type' => 'textfield',
153
        '#title' => t('Rel Attribute'),
154
        '#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.'),
155
        '#default_value' => $field['attributes']['rel'] ? $field['attributes']['rel'] : '',
156
			);
157
			$form['attributes']['class'] = array(
158
        '#type' => 'textfield',
159
        '#title' => t('Additional CSS Class'),
160
        '#description' => t('When output, this link will have have this class attribute. Multiple classes should be seperated by spaces.'),
161
        '#default_value' => isset($field['attributes']['class']) ? $field['attributes']['class'] : '',
162
			);
163

    
164
			// disable multiple and
165
			$form['multiple'] = array('#type' => 'hidden','#value' => '0');
166

    
167
			return $form;
168

    
169
		case 'validate':
170
			if ($field['title'] == 'value' && empty($field['title_value'])) {
171
				form_set_error('title_value', t('A default title must be provided if the title is a static value'));
172
			}
173
			break;
174

    
175
		case 'save':
176
			return array('attributes', 'display', 'title', 'title_value', 'enable_tokens');
177

    
178
		case 'database columns':
179
			$columns = array(
180
        'expertsdb_link' => array('type' => 'mediumtext', 'not null' => FALSE),
181
			);
182
			return $columns;
183

    
184
		case 'filters':
185
			/*			return array(
186
			 'default' => array(
187
			 'name' => t('URL'),
188
			 'operator' => 'views_handler_operator_like',
189
			 'handler' => 'views_handler_operator_like',
190
			 ),
191
			 'title' => array(
192
			 'name' => t('Title'),
193
			 'operator' => 'views_handler_operator_like',
194
			 'handler' => 'views_handler_operator_like',
195
			 ),
196
			 'protocol' => array(
197
			 'name' => t('Protocol'),
198
			 'list' => drupal_map_assoc(variable_get('filter_allowed_protocols', array('http', 'https', 'ftp', 'news', 'nntp', 'telnet', 'mailto', 'irc', 'ssh', 'sftp', 'webcal'))),
199
			 'operator' => 'views_handler_operator_or',
200
			 'handler' => 'expertsdb_link_views_protocol_filter_handler',
201
			 ),
202
			 );*/
203
			return;
204

    
205
		case 'arguments':
206
			/*      return array(
207
			 'content: '. $field['field_name'] .'_url' => array(
208
			 'name' => t('Link URL') .': '. t($field['widget']['label']) .' ('. $field['field_name'] .')',
209
			 'handler' => 'expertsdb_link_views_argument_handler',
210
			 ),
211
			 'content: '. $field['field_name'] .'_title' => array(
212
			 'name' => t('Link Title') .': '. t($field['widget']['label']) .' ('. $field['field_name'] .')',
213
			 'handler' => 'expertsdb_link_views_argument_handler',
214
			 ),
215
			 'content: '. $field['field_name'] .'_target' => array(
216
			 'name' => t('Link Target') .': '. t($field['widget']['label']) .' ('. $field['field_name'] .')',
217
			 'handler' => 'expertsdb_link_views_argument_handler',
218

    
219
			 ),
220
			 );*/
221
			return;
222

    
223
		case 'callbacks'://pairs up with cck_fullname_field::view
224
			return array(
225
        'view' => CONTENT_CALLBACK_CUSTOM,
226
			);
227

    
228
	}
229
}
230

    
231
/**
232
 * Implemantation of hook_field()
233
 *
234
 * @param unknown_type $op
235
 * @param unknown_type $node
236
 * @param unknown_type $field
237
 * @param unknown_type $items
238
 * @param unknown_type $teaser
239
 * @param unknown_type $page
240
 * @return unknown
241
 */
242
function expertsdb_link_field($op, &$node, $field, &$items, $teaser, $page) {
243
	switch ($op) {
244

    
245
		case 'view':
246
			$context = $teaser ? 'teaser' : 'full';
247
			$formatter = isset($field['display_settings'][$context]['format']) ? $field['display_settings'][$context]['format'] : 'default';
248
			$items = content_format($field, $items, $formatter, $node);
249
			if(!empty($items) && is_array($items) && count($items) > 0){
250
				return theme('expertsdb_link_container', $node, $field, $items, $teaser, $page);
251
			}
252
			return;
253
	}
254
}
255

    
256
/**
257
 * Implementation of hook_widget_info().
258
 */
259
function expertsdb_link_widget_info() {
260
	return array(
261
    'expertsdb_link' => array(
262
      'label' => 'Text Fields for Title and URL',
263
      'field types' => array('expertsdb_link'),
264
	),
265
	);
266
}
267

    
268
/**
269
 * Implementation of hook_widget().
270
 */
271
function expertsdb_link_widget($op, &$node, $field, &$node_field) {
272
	switch ($op) {
273
		case 'prepare form values':
274
			// unserialize and prepare data
275
			_expertsdb_link_widget_prepare($node_field);
276

    
277
			// get posted values in both node edit and profile edit mode
278
			if ($_POST[$field['field_name']] || $_POST[$field['type_name'].'_node_form'][$field['field_name']]) {
279
				$node_field = ($_POST['form_id'] == 'user_edit') ?  $_POST[$field['type_name'].'_node_form'][$field['field_name']] : $_POST[$field['field_name']];
280
				unset($node_field['count'], $node_field['more-url'], $node_field['more']);
281
			}
282
			break;
283

    
284
		case 'form':
285
			$form = array();
286
			$form[$field['field_name']] = array(
287
        '#tree' => TRUE,
288
        '#theme' => 'expertsdb_link_widget_form',
289
        '#type' => 'fieldset',
290
        '#collapsible' => TRUE,
291
        '#collapsed' => FALSE,
292
        '#title' => t($field['widget']['label']),
293
        '#description' => t($field['widget']['description']),
294
			);
295

    
296
			// Add token module replacements if available
297
			if (module_exists('token') && $field['enable_tokens']) {
298
				$tokens_form = array(
299
          '#type' => 'fieldset',
300
          '#collapsible' => TRUE,
301
          '#collapsed' => TRUE,
302
          '#title' => t('Placeholder tokens'),
303
          '#description' => t("The following placeholder tokens can be used in both titles and URLs. When used in a URL or title, they will be replaced with the appropriate values."),
304
          '#weight' => 2,
305
				);
306
				$tokens_form['help'] = array(
307
          '#value' => theme('token_help', 'node'),
308
				);
309
			}
310

    
311
			drupal_add_js(drupal_get_path('module', 'expertsdb_link') .'/expertsdb_link.js');
312

    
313
			$delta = 0;
314
			// Render link fields for all the entered values
315
			foreach ($node_field as $data) {
316
				if (is_array($data) && $data['url']) {
317
					_expertsdb_link_widget_form($form[$field['field_name']][$delta], $field, $data, $delta);
318
					$delta++;
319
				}
320
			}
321
			// Render one additional new link fields
322
			_expertsdb_link_widget_form($form[$field['field_name']][$delta], $field, array(), $delta);
323

    
324
			// Create a wrapper for additional fields
325
			$form[$field['field_name']]['wrapper'] = array(
326
          '#type' => 'markup',
327
          '#value' => '<div id="' . str_replace('_', '-', $field['field_name']) . '-wrapper" class="clear-block"></div>',
328
			);
329

    
330
			// Add 'More' Javascript Callback
331
			$form[$field['field_name']]['more-url'] = array(
332
          '#type' => 'hidden',
333
          '#value' => url('expertsdb_link/widget/js/' . $field['type_name'] . '/' . $field['field_name'], NULL, NULL, TRUE),
334
          '#attributes' => array('class' => 'more-links'),
335
          '#id' => str_replace('_', '-', $field['field_name']) . '-more-url',
336
			);
337

    
338
			// Add Current Field Count
339
			$form[$field['field_name']]['count'] = array(
340
          '#type' => 'hidden',
341
          '#value' => $delta,
342
          '#id' => str_replace('_', '-', $field['field_name']) . '-count',
343
			);
344

    
345
			// Add More Button
346
			$form[$field['field_name']]['more'] = array(
347
        '#name' => 'more',
348
        '#id' => str_replace('_', '-', $field['field_name']) . '-more',
349
        '#weight' => 10,
350
				'#type' => 'views_imagebutton',
351
				'#title' => t('More Links'),
352
    		'#image' => drupal_get_path('module','expertsdb_email') . '/images/button_add_element.png',  // provide the path to your image here
353
    		'#default_value' => t('More emails'), // original value of button text
354
			);
355

    
356
			if (isset($tokens_form)) {
357
				$form[$field['field_name']]['tokens'] = $tokens_form;
358
			}
359

    
360
			return $form;
361

    
362
		case 'validate':
363
			_expertsdb_link_cleanup($node_field);
364

    
365
			foreach($node_field as $delta => $value) {
366
				if ($value['url'] && !(isset($field['widget']['default_value'][$delta]['url']) && $value['url'] == $field['widget']['default_value'][$delta]['url'] && !$field['required'])) {
367
					// Validate the link
368
					if (expertsdb_link_validate_url(trim($value['url'])) == FALSE) {
369
						form_set_error($field['field_name'] .']['. $delta. '][url', t('Not a valid URL.'));
370
					}
371
					// Require a title for the link if necessary
372
					elseif ($field['title'] == 'required' && strlen(trim($value['title'])) == 0) {
373
						form_set_error($field['field_name'] .']['. $delta. '][title', t('Titles are required for all links.'));
374
					}
375
				}
376
				// Require a link if we have a title
377
				elseif (strlen($value['title']) > 0 && strlen(trim($value['url'])) == 0) {
378
					form_set_error($field['field_name'] .']['. $delta. '][url', t('You cannot enter a title without a link.'));
379
				}
380
			}
381
			return;
382

    
383
		case 'process form values':
384
			// run a cleanup cycle
385
			if(!strstr($node_field[0]['expertsdb_link'],':{')){
386
				_expertsdb_link_cleanup($node_field);
387
			}
388
			// apply some checks and trims
389
			_expertsdb_link_widget_process($node_field);
390
			return;
391

    
392
		case 'submit':
393
			// do not save empty values and bring preferred email to the top
394
			_expertsdb_link_cleanup($node_field);
395
			// apply some checks and trims
396
			_expertsdb_link_widget_process($node_field);
397
			// serialize data
398
			_expertsdb_link_serialize($node_field);
399
			return;
400
	}
401
}
402

    
403
/**
404
 * AHAH generation of additional form fields
405
 *
406
 * @param unknown_type $type_name
407
 * @param unknown_type $field_name
408
 */
409
function expertsdb_link_widget_js($type_name, $field_name) {
410
	$field = content_fields($field_name, $type_name);
411
	$type = content_types($type_name);
412
	// get the correct delta and field_name depending on being in node_form or user_edit
413
	// $delta = ($_POST['form_id'] == 'user_edit') ? $_POST[$type['type'].'_node_form'][$field_name]['count']: $_POST[$field_name]['count'];
414
	$delta = $_POST[$field_name]['count'];
415
	$form = array();
416

    
417
	$node_field = array();
418

    
419
	_expertsdb_link_widget_form($form, $field, $node_field, $delta);
420

    
421
	// Assign parents matching the original form
422
	foreach (element_children($form) as $key) {
423
		$form[$key]['#parents'] = array($field_name, $delta, $key);
424
	}
425

    
426
	// Add names, ids, and other form properties
427
	foreach (module_implements('form_alter') as $module) {
428
		$function = $module .'_form_alter';
429
		$function('expertsdb_link_widget_js', $form);
430
	}
431
	$form = form_builder('expertsdb_link_widget_js', $form);
432

    
433
	// if form is rendered as part of the user profile page, we need to alter name and id of newly generated form elements
434
/*	if($_POST['form_id'] == 'user_edit'){
435
		foreach (element_children($form) as $key) {
436
			$element_name = explode('[',$form[$key]['#name']);
437
			array_walk($element_name,'_expertsdb_link_widget_alter_elements');
438
			$form[$key]['#name'] = $type['type'] . '_node_form' . '[' . implode('][',$element_name).']';
439
		}
440
	}*/
441

    
442
	$output = drupal_render($form);
443

    
444
	print drupal_to_js(array('status' => TRUE, 'data' => $output));
445
	exit;
446
}
447

    
448
function _expertsdb_link_widget_alter_elements(&$element){
449
	$element = preg_replace('@\]@', '', $element);
450
}
451

    
452
/**
453
 * Helper function renders the expertsdb_email widget only for multiple values.
454
 *
455
 * @param unknown_type $form_item
456
 * @param unknown_type $field
457
 * @param unknown_type $node_field
458
 * @param unknown_type $delta
459
 */
460
function _expertsdb_link_widget_form(&$form_item, $field, $node_field, $delta = 0) {
461

    
462
	$form_item = array(
463
    '#tree' => TRUE,
464
    '#theme' => 'expertsdb_link_widget_form_row',
465
	);
466

    
467
	$default_url = "";
468
	if (isset($field['widget']['default_value'][$delta]['url'])) {
469
		$default_url = $field['widget']['default_value'][$delta]['url'];
470
	}
471

    
472
	$form_item['url'] = array(
473
    '#type' => 'textfield',
474
    '#maxlength' => '255',
475
    '#title' => $delta === 0 ? t('URL') : NULL,
476
    '#default_value' => ($node_field['url']) ? $node_field['url'] : $default_url,
477
    '#required' => ($delta === 0) ? $field['required'] : FALSE,
478
	);
479
	if ($field['title'] == 'optional' || $field['title'] == 'required') {
480
		$default_title = "";
481
		if (isset($field['widget']['default_value'][$delta]['title'])) {
482
			$default_title = $field['widget']['default_value'][$delta]['title'];
483
		}
484
		$form_item['title'] = array(
485
      '#type' => 'textfield',
486
      '#maxlength' => '255',
487
      '#title' => $delta === 0 ? t('Title') : NULL,
488
      '#default_value' => ($node_field['title']) ? $node_field['title'] : $default_title,
489
      '#required' => ($delta === 0 && $field['title'] == 'required') ? $field['required'] : FALSE,
490
		);
491
	}
492
	if ($field['attributes']['target'] == 'user') {
493
		$form_item['attributes']['target'] = array(
494
      '#type' => 'checkbox',
495
      '#title' => t('Open URL in a New Window'),
496
      '#default_value' => $node_field['attributes']['target'],
497
      '#return_value' => "_blank",
498
		);
499
	}
500
}
501

    
502
function _expertsdb_link_widget_prepare(&$node_field) {
503
	// only prepare, if data is actually serialized
504
	if(strstr($node_field[0]['expertsdb_link'],':{')){
505
		$node_field[0] = unserialize($node_field[0]['expertsdb_link']);
506
		if(count($node_field) > 0){
507
			// return content of first array element
508
			$node_field = $node_field[0];
509
		}
510
	}
511
}
512

    
513
function _expertsdb_link_serialize(&$node_field){
514
	$node_field = array(array('expertsdb_link' => serialize($node_field)));
515
}
516

    
517
/**
518
 * Function to remove unwanted elements from the node_field array
519
 *
520
 * @param array $node_field
521
 */
522
function _expertsdb_link_cleanup(&$node_field){
523
	$save_field = array();
524
	$registered_urls =array();
525
	// Remove the JS helper fields
526
	unset($node_field['count'], $node_field['more-url'], $node_field['more']);
527
	foreach ($node_field as $delta => $value) {
528
		if (!empty($value['url']) || $delta == 0) {
529
			// skip duplicates emails
530
			if(in_array($value['url'], $registered_urls)){
531
				continue;
532
			}
533
			// register email to avoid duplicates
534
			array_push($registered_urls, $value['url']);
535

    
536
			if (!empty($value['url']) || $delta == 0) {
537
				$save_field[] = $node_field[$delta];
538
			}
539
		}
540
	}
541
	$node_field = $save_field;
542
}
543

    
544
function _expertsdb_link_widget_process(&$node_field) {
545
	foreach($node_field as $delta => $value) {
546
		if (is_numeric($delta)) {
547
			// Remove the target attribute if not selected
548
			if (!$node_field[$delta]['attributes']['target'] || $node_field[$delta]['attributes']['target'] == "default") {
549
				unset($node_field[$delta]['attributes']['target']);
550
			}
551
			// Trim whitespace and remove code
552
			$node_field[$delta]['url'] = check_url(trim($node_field[$delta]['url']));
553
			$node_field[$delta]['title'] = check_plain(trim($node_field[$delta]['title']));
554

    
555
			//don't save an invalid default value (e.g. 'http://')
556
			if ((isset($field['widget']['default_value'][$delta]['url']) && $node_field[$delta]['url'] == $field['widget']['default_value'][$delta]['url']) && is_object($node)) {
557
				if (!expertsdb_link_validate_url($node_field[$delta]['url'])) {
558
					unset($node_field[$delta]['url']);
559
				}
560
			}
561
		}
562
	}
563
}
564

    
565

    
566
/**
567
 * Theme the display of the entire link set
568
 */
569
function theme_expertsdb_link_widget_form($element) {
570
	// pull in the stylesheet
571
	drupal_add_css(drupal_get_path('module', 'expertsdb_link') .'/expertsdb_link_form.css');
572
	$output = drupal_render($element);
573

    
574
	return $output;
575
}
576

    
577
/**
578
 * Theme the display of a single form row
579
 */
580
function theme_expertsdb_link_widget_form_row($element) {
581
	$output = '';
582
	$output .= '<div class="expertsdb-link-field-row clear-block"><div class="expertsdb-link-field-subrow clear-block">';
583
	if ($element['title']) {
584
		$output .= '<div class="expertsdb-link-field-title expertsdb-title-field-column">' . drupal_render($element['title']) . '</div>';
585
	}
586
	$output .= '<div class="expertsdb-link-field-url' . ($element['title'] ? ' expertsdb-link-field-column' : '') . '">' . drupal_render($element['url']) . '</div>';
587
	$output .= '</div>';
588
	if ($element['attributes']) {
589
		$output .= '<div class="expertsdb-link-attributes">' . drupal_render($element['attributes']) . '</div>';
590
	}
591
	$output .= drupal_render($element);
592
	$output .= '</div>';
593
	return $output;
594
}
595

    
596
/**
597
 * Theme the settings form for the expertsdb_link field.
598
 */
599
function theme_expertsdb_link_field_settings($form) {
600
	$title_value = drupal_render($form['title_value']);
601
	$title_checkbox = drupal_render($form['title']['value']);
602

    
603
	// Set Static Title radio option to include the title_value textfield
604
	$form['title']['value'] = array('#value' => '<div class="container-inline">'. $title_checkbox . $title_value .'</div>');
605

    
606
	// Reprint the title radio options with the included textfield
607
	return drupal_render($form);
608
}
609

    
610
/**
611
 * Theme to display a complete container with all links in view mode
612
 *
613
 * @param unknown_type $node
614
 * @param unknown_type $field
615
 * @param unknown_type $items
616
 * @param unknown_type $teaser
617
 * @param unknown_type $page
618
 * @return unknown
619
 */
620
function theme_expertsdb_link_container($node, $field, $items, $teaser, $page){
621
	// pull in the stylesheet
622
	drupal_add_css(drupal_get_path('module', 'expertsdb_link') .'/expertsdb_link_view.css');
623
	$output = '';
624
	$output .= '<div class="expertsdb-link-container">';
625
	$output .= theme('field', $node, $field, $items, $teaser, $page);
626
	$output .= '</div>';
627
	return $output;
628
}
629

    
630
/**
631
 * Implementation of hook_field_formatter_info().
632
 */
633
function expertsdb_link_field_formatter_info() {
634
	return array(
635
    'default' => array(
636
      'label' => t('Default, as link with title'),
637
      'field types' => array('expertsdb_link'),
638
	),
639
    'plain' => array(
640
      'label' => t('Plain, as the text URL'),
641
      'field types' => array('expertsdb_link'),
642
	),
643
    'short' => array(
644
      'label' => t('Short, as link with title "Link"'),
645
      'field types' => array('expertsdb_link'),
646
	),
647
    'title as prefix' => array(
648
      'label' => t('Title as prefix, as Title: Link'),
649
      'field types' => array('expertsdb_link'),
650
	),
651
    'label' => array(
652
      'label' => t('Label, as link with label as title'),
653
      'field types' => array('expertsdb_link'),
654
	),
655
	);
656
}
657

    
658
/**
659
 * Implementation of hook_field_formatter().
660
 */
661
function expertsdb_link_field_formatter($field, $item, $formatter, $node) {
662
	// item comes in either as serialized or unserialized value
663
	if (empty($item[0]['expertsdb_link']) && empty($item[0]['url'])) {
664
		return '';
665
	}
666
	if(strstr($item[0]['expertsdb_link'],':{')){
667
		$items = unserialize($item[0]['expertsdb_link']);
668
	}else{
669
		unset($item['count'], $item['more-url'], $item['more']);
670
		$items = $item;
671
	}
672

    
673
	// check, if we do have any urls
674
	$urls_present = FALSE;
675
	foreach ($items as $delta => $item){
676
		if(!empty($item['url'])){
677
			$urls_present = TRUE;
678
		}
679
	}
680
	if (!$urls_present) return;
681

    
682
	/*
683
	 * React on privacy settings
684
	 */
685

    
686
	if($node->field_privacy){
687
		global $user;
688
		$term = taxonomy_get_term($node->field_privacy[0]['tid']);
689
		switch($term->name){
690

    
691
			case PRIVACY_CONTACT_PRIVATE:
692
			case PRIVACY_PRIVATE:
693
				// show information only to roles with access and node author
694
				if($user->uid != $node->uid && !user_access('view private expertsdb_link fields',$user)){
695
					return;
696
				}
697
				break;
698

    
699
			case PRIVACY_PUBLIC:
700
				// allow everybody to view aliases as configured in the field formatter (display field)
701
				break;
702

    
703
		}
704
	}
705

    
706
	foreach ($items as $delta => $item) {
707
		if ($formatter == 'plain') {
708
			return check_plain($item['url']);
709
		}
710

    
711
		$attributes = array();
712
		$item['attributes'] = $item['attributes'];
713
		// Add attributes defined at the widget level
714
		if (is_array($item['attributes'])) {
715
			foreach($item['attributes'] as $attribute => $attbvalue) {
716
				if (isset($item['attributes'][$attribute]) && $field['attributes'][$attribute] == 'user') {
717
					$attributes[$attribute] = $attbvalue;
718
				}
719
			}
720
		}
721
		// Add attributes defined at the field level
722
		if (is_array($field['attributes'])) {
723
			foreach($field['attributes'] as $attribute => $attbvalue) {
724
				if (!empty($attbvalue) && $attbvalue != 'default' && $attbvalue != 'user') {
725
					$attributes[$attribute] = $attbvalue;
726
				}
727
			}
728
		}
729

    
730
		// Replace URL tokens
731
		if (module_exists('token') && $field['enable_tokens']) {
732
			$item['url'] = token_replace($item['url'], 'node', $node);
733
		}
734

    
735
		$type = expertsdb_link_validate_url($item['url']);
736
		$url = expertsdb_link_cleanup_url($item['url']);
737

    
738
		// Seperate out the anchor if any
739
		if (strpos($url, '#') !== FALSE) {
740
			$fragment = substr($url, strpos($url, '#') + 1);
741
			$url = substr($url, 0, strpos($url, '#'));
742
		}
743
		// Seperate out the query string if any
744
		if (strpos($url, '?') !== FALSE) {
745
			$query = substr($url, strpos($url, '?') + 1);
746
			$url = substr($url, 0, strpos($url, '?'));
747
		}
748

    
749
		// Give the link the title 'Link'
750
		if ($formatter == 'short') {
751
			$items[$delta]['view'] = l(t('Link'), $url, $attributes, $query, $fragment);
752
		}
753
		// Build the link using the widget label
754
		elseif ($formatter == 'label') {
755
			$items[$delta]['view'] = l(t($field['widget']['label']), $url, $attributes, $query, $fragment);
756
		}
757
		// Build the link as Title: URL
758
		elseif ($formatter == 'title as prefix') {
759
			$display_url = $type == LINK_EMAIL ? str_replace('mailto:', '', $url) : url($url, $query, $fragment, TRUE);
760
			if ($field['display']['url_cutoff'] && strlen($display_url) > $field['display']['url_cutoff']) {
761
				$display_url = substr($display_url, 0, $field['display']['url_cutoff']) . "...";
762
			}
763
			// Use the title defined at the field level
764
			if ($field['title'] == 'value' && strlen(trim($field['title_value']))) {
765
				$title = $field['title_value'];
766
			}
767
			// Use the title defined by the user at the widget level
768
			else {
769
				$title = ($item['title']) ? $item['title'] : '&nbsp;' ;
770
			}
771
			// Replace tokens
772
			if (module_exists('token') && ($field['title'] == 'value' || $field['enable_tokens'])) {
773
				$title = token_replace($title, 'node', $node);
774
			}
775
			$items[$delta]['view'] = '<div class="item-label label-column">' . $title . '</div> ' . l($display_url, $url, $attributes, $query, $fragment);
776
		}
777
		// Build the link with a title
778
		elseif (strlen(trim($item['title'])) || ($field['title'] == 'value' && strlen(trim($field['title_value'])))) {
779
			// Use the title defined at the field level
780
			if ($field['title'] == 'value' && strlen(trim($field['title_value']))) {
781
				$title = $field['title_value'];
782
			}
783
			// Use the title defined by the user at the widget level
784
			else {
785
				$title = $item['title'];
786
			}
787
			// Replace tokens
788
			if (module_exists('token') && ($field['title'] == 'value' || $field['enable_tokens'])) {
789
				$title = token_replace($title, 'node', $node);
790
			}
791
			$items[$delta]['view'] = l($title, $url, $attributes, $query, $fragment);
792
		}
793

    
794
		// Build the link with the URL or email address as the title (max 80 characters)
795
		else {
796
			$display_url = $type == LINK_EMAIL ? str_replace('mailto:', '', $url) : url($url, $query, $fragment, TRUE);
797
			if ($field['display']['url_cutoff'] && strlen($display_url) > $field['display']['url_cutoff']) {
798
				$display_url = substr($display_url, 0, $field['display']['url_cutoff']) . "...";
799
			}
800
			$items[$delta]['view'] = l($display_url, $url, $attributes, $query, $fragment);
801
		}
802
	}
803
	return $items;
804
}
805

    
806
/**
807
 * Views module argument handler for expertsdb_link fields
808
 */
809
function expertsdb_link_views_argument_handler($op, &$query, $argtype, $arg = '') {
810
	if ($op == 'filter') {
811
		$field_name = substr($argtype['type'], 9, strrpos($argtype['type'], '_') - 9);
812
		$column = substr($argtype['type'], strrpos($argtype['type'], '_') + 1);
813
	}
814
	else {
815
		$field_name = substr($argtype, 9, strrpos($argtype, '_') - 9);
816
		$column = substr($argtype, strrpos($argtype, '_') + 1);
817
	}
818

    
819
	// Right now the only attribute we support in views in 'target', but
820
	// other attributes of the href tag could be added later
821
	if ($column == 'target') {
822
		$attribute = $column;
823
		$column = 'attributes';
824
	}
825

    
826
	$field = content_fields($field_name);
827
	$db_info = content_database_info($field);
828
	$main_column = $db_info['columns'][$column];
829

    
830
	// The table name used here is the Views alias for the table, not the actual
831
	// table name.
832
	$table = 'node_data_'. $field['field_name'];
833

    
834
	switch ($op) {
835
		case 'summary':
836
			$query->ensure_table($table);
837
			$query->add_field($main_column['column'], $table);
838
			return array('field' => $table .'.'. $main_column['column']);
839
			break;
840

    
841
		case 'filter':
842
			$query->ensure_table($table);
843
			if ($column == 'attributes') {
844
				// Because attributes are stored serialized, our only option is to also
845
				// serialize the data we're searching for and use LIKE to find similar data
846
				$query->add_where($table .'.'. $main_column['column'] ." LIKE '%%%s%'", serialize($attribute) . serialize($arg));
847
			}
848
			else {
849
				$query->add_where($table .'.'. $main_column['column'] ." = '%s'", $arg);
850
			}
851
			break;
852

    
853
		case 'expertsdb_link':
854
			$item = array();
855
			foreach ($db_info['columns'] as $column => $attributes) {
856
				$view_column_name = $attributes['column'];
857
				$item[$column] = $query->$view_column_name;
858
			}
859

    
860
			return l(content_format($field, $item, 'plain'), $arg .'/'. $query->$main_column['column'], array(), NULL, NULL, FALSE, TRUE);
861

    
862
		case 'sort':
863
			break;
864

    
865
		case 'title':
866
			$item = array(key($db_info['columns']) => $query);
867
			return content_format($field, $item);
868
			break;
869
	}
870
}
871

    
872
/**
873
 * Views modules filter handler for link protocol filtering
874
 */
875
function expertsdb_link_views_protocol_filter_handler($op, $filter, $filterinfo, &$query) {
876
	global $db_type;
877

    
878
	$protocols = $filter['value'];
879
	$field = $filterinfo['field'];
880
	// $table is not the real table name but the views alias
881
	$table = 'node_data_'. $filterinfo['content_field']['field_name'];
882

    
883
	foreach ($protocols as $protocol) {
884
		// Simple case, the URL begins with the specified protocol
885
		$condition = $table .'.'. $field .' LIKE \''. $protocol .'%\'';
886

    
887
		// More complex case, no protocol specified but is automatically cleaned up
888
		// by expertsdb_link_cleanup_url(). RegEx is required for this search operation.
889
		if ($protocol == 'http') {
890
			if ($db_type == 'pgsql') {
891
				// PostGreSQL code has NOT been tested. Please report any problems to the link issue queue.
892
				// pgSQL requires all slashes to be double escaped in regular expressions.
893
				// See http://www.postgresql.org/docs/8.1/static/functions-matching.html#FUNCTIONS-POSIX-REGEXP
894
				$condition .= ' OR '. $table .'.'. $field .' ~* \''. '^(([a-z0-9]([a-z0-9\\-_]*\\.)+)('. LINK_DOMAINS .'|[a-z][a-z]))' .'\'';
895
			}
896
			else {
897
				// mySQL requires backslashes to be double (triple?) escaped within character classes.
898
				// See http://dev.mysql.com/doc/refman/5.0/en/string-comparison-functions.html#operator_regexp
899
				$condition .= ' OR '. $table .'.'. $field .' REGEXP \''. '^(([a-z0-9]([a-z0-9\\\-_]*\.)+)('. LINK_DOMAINS .'|[a-z][a-z]))' .'\'';
900
			}
901
		}
902

    
903
		$where_conditions[] = $condition;
904
	}
905

    
906
	$query->ensure_table($table);
907
	$query->add_where(implode(' '. $filter['operator'] .' ', $where_conditions));
908
}
909

    
910
/**
911
 * Forms a valid URL if possible from an entered address.
912
 * Trims whitespace and automatically adds an http:// to addresses without a protocol specified
913
 *
914
 * @param string $url
915
 * @param string $protocol The protocol to be prepended to the url if one is not specified
916
 */
917
function expertsdb_link_cleanup_url($url, $protocol = "http") {
918
	$url = trim($url);
919
	$type = expertsdb_link_validate_url($url);
920

    
921
	if ($type == LINK_EXTERNAL) {
922
		// Check if there is no protocol specified
923
		$protocol_match = preg_match("/^([a-z0-9][a-z0-9\.\-_]*:\/\/)/i",$url);
924
		if (empty($protocol_match)) {
925
			// But should there be? Add an automatic http:// if it starts with a domain name
926
			$domain_match = preg_match('/^(([a-z0-9]([a-z0-9\-_]*\.)+)('. LINK_DOMAINS .'|[a-z]{2}))/i',$url);
927
			if (!empty($domain_match)) {
928
				$url = $protocol."://".$url;
929
			}
930
		}
931
	}
932

    
933
	return $url;
934
}
935

    
936
/**
937
 * A lenient verification for URLs. Accepts all URLs following RFC 1738 standard
938
 * for URL formation and all email addresses following the RFC 2368 standard for
939
 * mailto address formation.
940
 *
941
 * @param string $text
942
 * @return mixed Returns boolean FALSE if the URL is not valid. On success, returns an object with
943
 * the following attributes: protocol, hostname, ip, and port.
944
 */
945
function expertsdb_link_validate_url($text) {
946

    
947
	$allowed_protocols = variable_get('filter_allowed_protocols', array('http', 'https', 'ftp', 'news', 'nntp', 'telnet', 'mailto', 'irc', 'ssh', 'sftp', 'webcal'));
948

    
949
	$protocol = '((' . implode("|", $allowed_protocols) . '):\/\/)';
950
	$authentication = '([a-z0-9]+(:[a-z0-9]+)?@)';
951
	$domain = '(([a-z0-9]([a-z0-9\-_\[\]]*\.)+)('. LINK_DOMAINS .'|[a-z]{2}))';
952
	$ipv4 = '([0-9]{1,3}(\.[0-9]{1,3}){3})';
953
	$ipv6 = '([0-9a-fA-F]{1,4}(\:[0-9a-fA-F]{1,4}){7})';
954
	$port = '(:([0-9]{1,5}))';
955

    
956
	// Pattern specific to eternal links
957
	$external_pattern = '/^' . $protocol . '?'. $authentication . '?' . '(' . $domain . '|' . $ipv4 . '|' . $ipv6 . ' |localhost)' . $port . '?';
958

    
959
	// Pattern specific to internal links
960
	$internal_pattern = "/^([a-z0-9_\-+\[\]]+)";
961

    
962
	$directories = "(\/[a-z0-9_\-\.~+%=&,$'():;*@\[\]]*)*";
963
	$query = "(\/?[?a-z0-9+_\-\.\/%=&,$'():;*@\[\]]*)";
964
	$anchor = "(#[a-z0-9_\-\.~+%=&,$'():;*@\[\]]*)";
965

    
966
	// the rest of the path for a standard URL
967
	$end = $directories . '?' . $query . '?' .  $anchor . '?' . '$/i';
968

    
969
	$user = '[a-zA-Z0-9_\-\.\+\^!#\$%&*+\/\=\?\`\|\{\}~\'\[\]]+';
970
	$email_pattern = '/^mailto:' . $user . '@' . '(' . $domain . '|' . $ipv4 .'|'. $ipv6 . '|localhost)' . $query . '$/';
971

    
972
	if (preg_match($external_pattern . $end, $text)) {
973
		return LINK_EXTERNAL;
974
	}
975
	elseif (preg_match($internal_pattern . $end, $text)) {
976
		return LINK_INTERNAL;
977
	}
978
	elseif (in_array('mailto', $allowed_protocols) && preg_match($email_pattern, $text)) {
979
		return LINK_EMAIL;
980
	}
981
	elseif (strpos($text, '<front>') === 0) {
982
		return LINK_FRONT;
983
	}
984
	return FALSE;
985
}
(31-31/47)