Project

General

Profile

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

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

    
8
/*
9
 * Definition of privacy levels
10
 */
11
define('PRIVACY_CONTACT_PRIVATE', 'ContactPrivate');
12
define('PRIVACY_PRIVATE', 'Private');
13
define('PRIVACY_PUBLIC', 'Public');
14

    
15
/**
16
 * Implementation of hook_perm()
17
 *
18
 * Valid permissions for this module
19
 * @return array An array of valid permissions for the expertsdb_phone module
20
 */
21
function expertsdb_phone_perm() {
22
	return array(
23
    	'view private expertsdb_phone fields',
24
	//TODO which else permission are required?
25
	);
26
}
27

    
28
/**
29
 * Implementation of hook_help().
30
 *
31
 * @param unknown_type $section
32
 * @return unknown
33
 */
34
function expertsdb_phone_help($section) {
35
	switch ($section) {
36
		case 'admin/modules#description':
37
			return t('Defines a text field type for multiple phone numbers in international notation. Data will be integrated as serialized array into the according content type database. <em>Note: Requires content.module.</em>');
38
	}
39
}
40

    
41
/**
42
 * Implementation of hook_menu().
43
 */
44
function expertsdb_phone_menu($may_cache) {
45
	$items = array();
46
	if ($may_cache) {
47
		$items[] = array(
48
      'path' => 'expertsdb_phone/widget/js',
49
      'callback' => 'expertsdb_phone_widget_js',
50
      'access' => user_access('access content'),
51
      'type' => MENU_CALLBACK,
52
		);
53
	}
54
	return $items;
55
}
56

    
57
/**
58
 * Implementation of hook_field_info().
59
 */
60
function expertsdb_phone_field_info() {
61
	return array(
62
    'expertsdb_phone' => array('label' => 'Expertsdb Phone Numbers'),
63
	);
64
}
65

    
66
/**
67
 * Implementation of hook_field_settings().
68
 */
69
function expertsdb_phone_field_settings($op, $field) {
70
	switch ($op) {
71
		case 'form':
72
			$form = array();
73

    
74
			$title_options = array(
75
        'optional' => t('Optional Title'),
76
        'required' => t('Required Title'),
77
        'value' => t('Static Title: '),
78
        'none' => t('No Title'),
79
			);
80

    
81
			$form['title'] = array(
82
        '#type' => 'radios',
83
        '#title' => t('Link Title'),
84
        '#default_value' => isset($field['title']) ? $field['title'] : 'optional',
85
        '#options' => $title_options,
86
        '#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.'),
87
			);
88

    
89
			$form['title_value'] = array(
90
        '#type' => 'textfield',
91
        '#default_value' => $field['title_value'],
92
        '#size' => '46',
93
			);
94

    
95
			// disable multiple and
96
			$form['multiple'] = array('#type' => 'hidden','#value' => '0');
97

    
98
			return $form;
99

    
100
		case 'validate':
101
			if ($field['title'] == 'value' && empty($field['title_value'])) {
102
				form_set_error('title_value', t('A default title must be provided if the title is a static value'));
103
			}
104
			break;
105

    
106
		case 'save':
107
			return array('title', 'title_value');
108

    
109
		case 'database columns':
110
			$columns = array(
111
        'expertsdb_phone' => array('type' => 'mediumtext', 'not null' => FALSE),
112
			);
113
			return $columns;
114

    
115
		case 'filters':
116
			return;
117

    
118
		case 'arguments':
119
			return;
120

    
121
		case 'callbacks'://pairs up with cck_fullname_field::view
122
			return array(
123
        'view' => CONTENT_CALLBACK_CUSTOM,
124
			);
125

    
126
	}
127
}
128

    
129
/**
130
 * Implemantation of hook_field()
131
 *
132
 * @param unknown_type $op
133
 * @param unknown_type $node
134
 * @param unknown_type $field
135
 * @param unknown_type $items
136
 * @param unknown_type $teaser
137
 * @param unknown_type $page
138
 * @return unknown
139
 */
140
function expertsdb_phone_field($op, &$node, $field, &$items, $teaser, $page) {
141
	switch ($op) {
142

    
143
		case 'view':
144
			$context = $teaser ? 'teaser' : 'full';
145
			$formatter = isset($field['display_settings'][$context]['format']) ? $field['display_settings'][$context]['format'] : 'default';
146
			$items = content_format($field, $items, $formatter, $node);
147
			if(!empty($items) && is_array($items) && count($items) > 0){
148
				return theme('expertsdb_phone_container', $node, $field, $items, $teaser, $page);
149
			}
150
			return;
151
	}
152
}
153

    
154
/**
155
 * Implementation of hook_widget_info().
156
 */
157
function expertsdb_phone_widget_info() {
158
	return array(
159
    'expertsdb_phone' => array(
160
      'label' => 'Text Fields for Phone Numbers with Optional Title',
161
      'field types' => array('expertsdb_phone'),
162
	),
163
	);
164
}
165

    
166
/**
167
 * Implementation of hook_widget().
168
 */
169
function expertsdb_phone_widget($op, &$node, $field, &$node_field) {
170
	switch ($op) {
171
		case 'prepare form values':
172
			// unserialize and prepare data
173
			_expertsdb_phone_widget_prepare($node_field);
174

    
175
			// get posted values in both node edit and profile edit mode
176
			if ($_POST[$field['field_name']] || $_POST[$field['type_name'].'_node_form'][$field['field_name']]) {
177
				$node_field = ($_POST['form_id'] == 'user_edit') ?  $_POST[$field['type_name'].'_node_form'][$field['field_name']] : $_POST[$field['field_name']];
178
				unset($node_field['count'], $node_field['more-url'], $node_field['more']);
179
			}
180
			return;
181

    
182
		case 'form':
183
			$form = array();
184
			$form[$field['field_name']] = array(
185
        '#tree' => TRUE,
186
        '#theme' => 'expertsdb_phone_widget_form',
187
        '#type' => 'fieldset',
188
        '#collapsible' => TRUE,
189
        '#collapsed' => FALSE,
190
        '#title' => t($field['widget']['label']),
191
        '#description' => t($field['widget']['description']) . '<br />If you need to add an extension number of a PABX without direct in-dialling, please use the abbreviation for "extension" (ext.).<br />
192
        <strong>Format:</strong> +[Country calling code] [Area code] [Phone number] ext. [Extension number]<br />
193
        <strong>Example:</strong> +22 30 xxx xxxxx<br />
194
        <strong>Example with extension:</strong> +22 30 xxx xxxxx ext. 123',
195
			);
196

    
197
			drupal_add_js(drupal_get_path('module', 'expertsdb_phone') .'/expertsdb_phone.js');
198

    
199
			$delta = 0;
200
			// Render phone number fields for all the entered values
201
			foreach ($node_field as $data) {
202
				if (is_array($data) && $data['phone']) {
203
					_expertsdb_phone_widget_form($form[$field['field_name']][$delta], $field, $data, $delta);
204
					$delta++;
205
				}
206
			}
207
			// Render one additional new phone field
208
			_expertsdb_phone_widget_form($form[$field['field_name']][$delta], $field, array(), $delta);
209

    
210
			// Create a wrapper for additional fields
211
			$form[$field['field_name']]['wrapper'] = array(
212
          '#type' => 'markup',
213
          '#value' => '<div id="' . str_replace('_', '-', $field['field_name']) . '-wrapper" class="clear-block"></div>',
214
			);
215

    
216
			// Add 'More' Javascript Callback
217
			$form[$field['field_name']]['more-url'] = array(
218
          '#type' => 'hidden',
219
          '#value' => url('expertsdb_phone/widget/js/' . $field['type_name'] . '/' . $field['field_name'], NULL, NULL, TRUE),
220
          '#attributes' => array('class' => 'more-phone-numbers'),
221
          '#id' => str_replace('_', '-', $field['field_name']) . '-more-url',
222
			);
223

    
224
			// Add Current Field Count
225
			$form[$field['field_name']]['count'] = array(
226
          '#type' => 'hidden',
227
          '#value' => $delta,
228
          '#id' => str_replace('_', '-', $field['field_name']) . '-count',
229
			);
230

    
231
			// Add More Button
232
			$form[$field['field_name']]['more'] = array(
233
        '#name' => 'more',
234
        '#id' => str_replace('_', '-', $field['field_name']) . '-more',
235
        '#weight' => 10,
236
				'#type' => 'views_imagebutton',
237
				'#title' => t('More Phone Numbers'),
238
    		'#image' => drupal_get_path('module','expertsdb_email') . '/images/button_add_element.png',  // provide the path to your image here
239
    		'#default_value' => t('More emails'), // original value of button text
240
			);
241

    
242
			if (isset($tokens_form)) {
243
				$form[$field['field_name']]['tokens'] = $tokens_form;
244
			}
245

    
246
			return $form;
247

    
248
		case 'validate':
249
			_expertsdb_phone_cleanup($node_field);
250
			_expertsdb_phone_widget_process($node_field);
251

    
252
			foreach($node_field as $delta => $value) {
253
				if ($value['phone'] && !(isset($field['widget']['default_value'][$delta]['phone']) && $value['phone'] == $field['widget']['default_value'][$delta]['phone'] && !$field['required'])) {
254
					// Validate the phone number, well basically
255
					// pattern validates, if phone number starts with a plus, some digits and a space
256
					if (preg_match('@^\+[0-9]+ @',$value['phone']) == FALSE) {
257
						form_set_error($field['field_name'] .']['. $delta. '][phone', t('Please use international notation for phone numbers. You can find examples in the field description.'));
258
					}
259
					if (preg_match('@\(|\)@',$value['phone']) == TRUE) {
260
						form_set_error($field['field_name'] .']['. $delta. '][phone', t('Please avoid brackets in phone numbers as these parts of the number are normally unneeded when placing an international call. You can find examples in the field description.'));
261
					}
262
					if ($field['title'] == 'required' && strlen(trim($value['title'])) == 0) {
263
						form_set_error($field['field_name'] .']['. $delta. '][title', t('Titles are required for all phone numbers.'));
264
					}
265
				}
266
				// Require a link if we have a title
267
				if (strlen($value['title']) > 0 && strlen(trim($value['phone'])) == 0) {
268
					form_set_error($field['field_name'] .']['. $delta. '][phone', t('You cannot enter a title without a phone number.'));
269
				}
270

    
271
			}
272
			return;
273

    
274
		case 'process form values':
275
			// run a cleanup cycle
276
			if(!strstr($node_field[0]['expertsdb_phone'],':{')){
277
				_expertsdb_phone_cleanup($node_field);
278
			}
279
			// apply some basic formatting
280
			_expertsdb_phone_widget_process($node_field);
281
			return;
282

    
283
		case 'submit':
284
			// do not save empty values
285
			_expertsdb_phone_cleanup($node_field);
286
			// apply some basic formatting
287
			_expertsdb_phone_widget_process($node_field);
288
			// serialize data
289
			_expertsdb_phone_serialize($node_field);
290
			return;
291
	}
292
}
293

    
294
/**
295
 * AHAH generation of additional form fields
296
 *
297
 * @param unknown_type $type_name
298
 * @param unknown_type $field_name
299
 */
300
function expertsdb_phone_widget_js($type_name, $field_name) {
301
	$field = content_fields($field_name, $type_name);
302
	$type = content_types($type_name);
303
	// get the correct delta and field_name depending on being in node_form or user_edit
304
	// $delta = ($_POST['form_id'] == 'user_edit') ? $_POST[$type['type'].'_node_form'][$field_name]['count']: $_POST[$field_name]['count'];
305
	$delta = $_POST[$field_name]['count'];
306
	$form = array();
307

    
308
	_expertsdb_phone_widget_form($form, $field, $node_field, $delta);
309

    
310
	// Assign parents matching the original form
311
	foreach (element_children($form) as $key) {
312
		$form[$key]['#parents'] = array($field_name, $delta, $key);
313
	}
314

    
315
	// Add names, ids, and other form properties
316
	foreach (module_implements('form_alter') as $module) {
317
		$function = $module .'_form_alter';
318
		$function('expertsdb_phone_widget_js', $form);
319
	}
320
	$form = form_builder('expertsdb_phone_widget_js', $form);
321

    
322
	// if form is rendered as part of the user profile page, we need to alter name and id of newly generated form elements
323
	/*	if($_POST['form_id'] == 'user_edit'){
324
	foreach (element_children($form) as $key) {
325
	$element_name = explode('[',$form[$key]['#name']);
326
	array_walk($element_name,'_expertsdb_phone_widget_alter_elements');
327
	$form[$key]['#name'] = $type['type'] . '_node_form' . '[' . implode('][',$element_name).']';
328
	}
329
	}*/
330

    
331
	$output = drupal_render($form);
332

    
333
	print drupal_to_js(array('status' => TRUE, 'data' => $output));
334
	exit;
335
}
336

    
337

    
338
/**
339
 * Helper function renders the expertsdb_phone widget only for multiple values.
340
 *
341
 * @param unknown_type $form_item
342
 * @param unknown_type $field
343
 * @param unknown_type $node_field
344
 * @param unknown_type $delta
345
 */
346
function _expertsdb_phone_widget_form(&$form_item, $field, $node_field, $delta = 0) {
347

    
348
	$form_item = array(
349
    '#tree' => TRUE,
350
    '#theme' => 'expertsdb_phone_widget_form_row',
351
	);
352

    
353
	$default_phone_number = "";
354
	if (isset($field['widget']['default_value'][$delta]['phone'])) {
355
		$default_phone_number = $field['widget']['default_value'][$delta]['phone'];
356
	}
357

    
358
	$form_item['phone'] = array(
359
    '#type' => 'textfield',
360
    '#maxlength' => '255',
361
    '#title' => $delta === 0 ? t('Phone Number') : NULL,
362
    '#default_value' => ($node_field['phone']) ? $node_field['phone'] : $default_phone_number,
363
    '#required' => ($delta === 0) ? $field['required'] : FALSE,
364
	);
365
	if ($field['title'] == 'optional' || $field['title'] == 'required') {
366
		$default_title = "";
367
		if (isset($field['widget']['default_value'][$delta]['title'])) {
368
			$default_title = $field['widget']['default_value'][$delta]['title'];
369
		}
370
		$form_item['title'] = array(
371
      '#type' => 'textfield',
372
      '#maxlength' => '255',
373
      '#title' => $delta === 0 ? t('Title') : NULL,
374
      '#default_value' => ($node_field['title']) ? $node_field['title'] : $default_title,
375
      '#required' => ($delta === 0 && $field['title'] == 'required') ? $field['required'] : FALSE,
376
		);
377
	}
378
}
379

    
380
function _expertsdb_phone_widget_prepare(&$node_field) {
381
	// only prepare, if data is actually serialized
382
	if(strstr($node_field[0]['expertsdb_phone'],':{')){
383
		$node_field[0] = unserialize($node_field[0]['expertsdb_phone']);
384
		if(count($node_field) > 0){
385
			// return content of first array element
386
			$node_field = $node_field[0];
387
		}
388
	}
389
}
390

    
391
function _expertsdb_phone_serialize(&$node_field){
392
	$node_field = array(array('expertsdb_phone' => serialize($node_field)));
393
}
394

    
395
/**
396
 * Function to remove unwanted elements from the node_field array
397
 *
398
 * @param array $node_field
399
 */
400
function _expertsdb_phone_cleanup(&$node_field){
401

    
402
	$save_field = array();
403
	$registered_phone_numbers =array();
404
	// Remove the JS helper fields
405
	unset($node_field['count'], $node_field['more-url'], $node_field['more']);
406
	foreach ($node_field as $delta => $value) {
407
		if (!empty($value['phone']) || $delta == 0) {
408
			// skip duplicates phone numbers
409
			if(in_array($value['phone'], $registered_phone_numbers)){
410
				continue;
411
			}
412
			// register phone numbers to avoid duplicates
413
			array_push($registered_phone_numbers, $value['phone']);
414

    
415
			if (!empty($value['phone']) || $delta == 0) {
416
				$save_field[] = $node_field[$delta];
417
			}
418
		}
419
	}
420
	$node_field = $save_field;
421
}
422

    
423
function _expertsdb_phone_widget_process(&$node_field) {
424
	foreach($node_field as $delta => $value) {
425
		if (is_numeric($delta)) {
426
			// Trim whitespace from phone number
427
			// remove unwanted characters
428
			// and apply *some* formatting
429
			$parts = explode('ext.',strtolower($node_field[$delta]['phone']));
430
			$pat = array('@[^0-9 \(\)\+]@', // only allow +, digits, space, round brackets (yes, we leave them in for validation)
431
									 '@ +?@'); // remove multiple spaces
432
			$rep = array(' ',
433
									 ' ');
434
			foreach($parts as $key => $value){
435
				$parts[$key] = check_plain(trim(preg_replace($pat, $rep, $value)));
436
			}
437

    
438
			$node_field[$delta]['phone'] = (count($parts) > 1) ? implode(" ext. ",$parts) : $parts[0];
439
			$node_field[$delta]['title'] = check_plain(trim($node_field[$delta]['title']));
440
		}
441
	}
442
}
443

    
444
function _expertsdb_phone_validate_phone($phone = FALSE){
445
	if(!$phone) return;
446

    
447
}
448

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

    
453

    
454
/**
455
 * Theme the display of the entire set of phone numbers
456
 */
457
function theme_expertsdb_phone_widget_form($element) {
458
	// pull in the stylesheet
459
	drupal_add_css(drupal_get_path('module', 'expertsdb_phone') .'/expertsdb_phone_form.css');
460
	$output = drupal_render($element);
461

    
462
	return $output;
463
}
464

    
465
/**
466
 * Theme the display of a single form row
467
 */
468
function theme_expertsdb_phone_widget_form_row($element) {
469

    
470
	$output = '';
471
	$output .= '<div class="expertsdb-phone-number-field-row clear-block"><div class="expertsdb-phone-number-field-subrow clear-block">';
472
	if ($element['title']) {
473
		$output .= '<div class="expertsdb-phone-number-field-title expertsdb-title-field-column">' . drupal_render($element['title']) . '</div>';
474
	}
475
	$output .= '<div class="expertsdb-phone-number-field-url' . ($element['title'] ? ' expertsdb-phone-number-field-column' : '') . '">' . drupal_render($element['phone']) . '</div>';
476
	$output .= '</div>';
477
	$output .= drupal_render($element);
478
	$output .= '</div>';
479
	return $output;
480
}
481

    
482
/**
483
 * Theme to display a complete container with all phone numbers in view mode
484
 *
485
 * @param unknown_type $node
486
 * @param unknown_type $field
487
 * @param unknown_type $items
488
 * @param unknown_type $teaser
489
 * @param unknown_type $page
490
 * @return unknown
491
 */
492
function theme_expertsdb_phone_container($node, $field, $items, $teaser, $page){
493
	// pull in the stylesheet
494
	drupal_add_css(drupal_get_path('module', 'expertsdb_phone') .'/expertsdb_phone_view.css');
495
	$output = '';
496
	$output .= '<div class="expertsdb-phone-numbers-container">';
497
	$output .= theme('field', $node, $field, $items, $teaser, $page);
498
	$output .= '</div>';
499
	return $output;
500
}
501

    
502
/**
503
 * Implementation of hook_field_formatter_info().
504
 */
505
function expertsdb_phone_field_formatter_info() {
506
	return array(
507
    'default' => array(
508
      'label' => t('Default'),
509
      'field types' => array('expertsdb_phone'),
510
	),
511
	);
512
}
513

    
514
/**
515
 * Implementation of hook_field_formatter().
516
 */
517
function expertsdb_phone_field_formatter($field, $item, $formatter, $node) {
518
	// item comes in either as serialized or unserialized value
519
	if (empty($item[0]['expertsdb_phone']) && empty($item[0]['phone'])) {
520
		return '';
521
	}
522
	if(strstr($item[0]['expertsdb_phone'],':{')){
523
		$items = unserialize($item[0]['expertsdb_phone']);
524
	}else{
525
		unset($item['count'], $item['more-url'], $item['more']);
526
		$items = $item;
527
	}
528
	// check, if we do have any phone number
529
	$phone_number_present = FALSE;
530
	foreach ($items as $delta => $item){
531
		if(!empty($item['phone'])){
532
			$phone_number_present = TRUE;
533
		}
534
	}
535
	if (!$phone_number_present) return;
536

    
537
	/*
538
	 * React on privacy settings
539
	 */
540
	if($node->field_privacy){
541
		global $user;
542
		$term = taxonomy_get_term($node->field_privacy[0]['tid']);
543
		switch($term->name){
544

    
545
			case PRIVACY_CONTACT_PRIVATE:
546
			case PRIVACY_PRIVATE:
547
				// show information only to roles with access and node author
548
				if($user->uid != $node->uid && !user_access('view private expertsdb_phone fields',$user)){
549
					return;
550
				}
551
				break;
552

    
553
			case PRIVACY_PUBLIC:
554
				// allow everybody to view aliases as configured in the field formatter (display field)
555
				break;
556

    
557
		}
558
	}
559

    
560
	foreach ($items as $delta => $item) {
561

    
562
		switch ($formatter) {
563
			default:
564
				$items[$delta]['view'] = '<div class="item-label label-column">' . $item['title'] . '</div><div class="phone-number">' . $item['phone'] . '</div>';
565
		}
566
	}
567

    
568
	return $items;
569
}
(36-36/47)