/[drupal]/contributions/modules/cck/nodereference.module
ViewVC logotype

Contents of /contributions/modules/cck/nodereference.module

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.121 - (show annotations) (download) (as text)
Tue Mar 25 13:12:41 2008 UTC (20 months ago) by karens
Branch: MAIN
Changes since 1.120: +7 -14 lines
File MIME type: text/x-php
Re-name fields to use Views 1 naming like field_text_value instead of field_text to make updates easier, and alter content.views_convert.inc to match.

Add default filters for all fields, and update fields to switch from string or numeric filters to 'in' operators if there are lists of allowed values.

Add helper function to return Views table name to make it easier to change the tablename in the future, like if we find a way to avoid the need to alias each field as its own table.
1 <?php
2 // $Id: nodereference.module,v 1.120 2008/03/24 01:59:03 yched Exp $
3
4 /**
5 * @file
6 * Defines a field type for referencing one node from another.
7 */
8
9 /**
10 * Implementation of hook_menu().
11 */
12 function nodereference_menu() {
13 $items = array();
14 $items['nodereference/autocomplete'] = array(
15 'title' => t('Nodereference autocomplete'),
16 'page callback' => 'nodereference_autocomplete',
17 'access arguments' => array('access content'),
18 'type' => MENU_CALLBACK
19 );
20 return $items;
21 }
22
23 /**
24 * Implementation of hook_theme().
25 */
26 function nodereference_theme() {
27 return array(
28 'nodereference_item_simple' => array(
29 'arguments' => array('item' => NULL),
30 ),
31 'nodereference_item_advanced' => array(
32 'arguments' => array('item' => NULL, 'view' => NULL),
33 ),
34 'nodereference_select' => array(
35 'arguments' => array('element' => NULL),
36 ),
37 'nodereference_autocomplete' => array(
38 'arguments' => array('element' => NULL),
39 ),
40 'nodereference_formatter_default' => array(
41 'arguments' => array('element'),
42 ),
43 'nodereference_formatter_full' => array(
44 'arguments' => array('element'),
45 'function' => 'theme_nodereference_formatter_full_teaser',
46 ),
47 'nodereference_formatter_teaser' => array(
48 'arguments' => array('element'),
49 'function' => 'theme_nodereference_formatter_full_teaser',
50 ),
51 );
52 }
53
54 /**
55 * Implementation of hook_field_info().
56 *
57 * Here we indicate that the content module will use its default
58 * handling for the view of this field.
59 *
60 * Callbacks can be omitted if default handing is used.
61 * They're included here just so this module can be used
62 * as an example for custom modules that might do things
63 * differently.
64 */
65 function nodereference_field_info() {
66 return array(
67 'nodereference' => array(
68 'label' => t('Node Reference'),
69 'description' => t('Store the id of a related node as an integer value.'),
70 'callbacks' => array(
71 'tables' => CONTENT_CALLBACK_DEFAULT,
72 'arguments' => CONTENT_CALLBACK_DEFAULT,
73 ),
74 ),
75 );
76 }
77
78 /**
79 * Implementation of hook_field_settings().
80 */
81 function nodereference_field_settings($op, $field) {
82 switch ($op) {
83 case 'form':
84 $form = array();
85 $form['referenceable_types'] = array(
86 '#type' => 'checkboxes',
87 '#title' => t('Content types that can be referenced'),
88 '#multiple' => TRUE,
89 '#default_value' => is_array($field['referenceable_types']) ? $field['referenceable_types'] : array(),
90 '#options' => node_get_types('names'),
91 );
92 if (module_exists('views')) {
93 $views = array('--' => '--');
94 $all_views = views_get_all_views();
95 foreach ($all_views as $view) {
96 $views[t('Existing Views')][$view->name] = $view->name;
97 }
98
99 if (count($views) > 1) {
100 $form['advanced'] = array(
101 '#type' => 'fieldset',
102 '#title' => t('Advanced - Nodes that can be referenced (View)'),
103 '#collapsible' => TRUE,
104 '#collapsed' => !isset($field['advanced_view']) || $field['advanced_view'] == '--',
105 );
106 $form['advanced']['advanced_view'] = array(
107 '#type' => 'select',
108 '#title' => t('View'),
109 '#options' => $views,
110 '#default_value' => isset($field['advanced_view']) ? $field['advanced_view'] : '--',
111 '#description' => t('Choose the "Views module" view that selects the nodes that can be referenced.<br>Note :<ul><li>This will discard the "Content types" settings above. Use the view\'s "filters" section instead.</li><li>Use the view\'s "fields" section to display additional informations about candidate nodes on node creation/edition form.</li><li>Use the view\'s "sort criteria" section to determine the order in which candidate nodes will be displayed.</li></ul>'),
112 );
113 $form['advanced']['advanced_view_args'] = array(
114 '#type' => 'textfield',
115 '#title' => t('View arguments'),
116 '#default_value' => isset($field['advanced_view_args']) ? $field['advanced_view_args'] : '',
117 '#required' => FALSE,
118 '#description' => t('Provide a comma separated list of arguments to pass to the view.'),
119 );
120 }
121 }
122 return $form;
123
124 case 'save':
125 $settings = array('referenceable_types');
126 if (module_exists('views')) {
127 $settings[] = 'advanced_view';
128 $settings[] = 'advanced_view_args';
129 }
130 return $settings;
131
132 case 'database columns':
133 $columns = array(
134 'nid' => array('type' => 'int', 'unsigned' => TRUE, 'not null' => FALSE),
135 );
136 return $columns;
137
138 case 'views data':
139 $data = content_views_field_views_data($field);
140 $db_info = content_database_info($field);
141 $table_alias = content_views_tablename($field);
142
143 // Swap the filter handler to the 'in' operator.
144 $data[$table_alias][$field['field_name'] .'_nid']['filter']['handler'] = 'views_handler_filter_in_operator_content';
145
146 // Add a relationship for related node.
147 $data[$table_alias][$field['field_name'] .'_nid']['relationship'] = array(
148 'base' => 'node',
149 'field' => $db_info['columns']['nid']['column'],
150 'handler' => 'views_handler_relationship',
151 );
152 return $data;
153 }
154 }
155
156 /**
157 * Implementation of hook_field().
158 */
159 function nodereference_field($op, &$node, $field, &$items, $teaser, $page) {
160 switch ($op) {
161 case 'validate':
162 $refs = _nodereference_potential_references($field, TRUE);
163 foreach ($items as $delta => $item) {
164 if (is_array($item) && !empty($item['error_field'])) {
165 $error_field = $item['error_field'];
166 unset($item['error_field']);
167 if (!empty($item['nid'])) {
168 if (!in_array($item['nid'], array_keys($refs))) {
169 form_set_error($error_field, t('%name : This post can\'t be referenced.', array('%name' => t($field['widget']['label']))));
170 }
171 }
172 }
173 }
174 return $items;
175 }
176 }
177
178 /**
179 * Implementation of hook_content_is_empty().
180 */
181 function nodereference_content_is_empty($item, $field) {
182 if (empty($item['nid'])) {
183 return TRUE;
184 }
185 return FALSE;
186 }
187
188 /**
189 * Implementation of hook_field_formatter_info().
190 */
191 function nodereference_field_formatter_info() {
192 return array(
193 'default' => array(
194 'label' => t('Title (link)'),
195 'field types' => array('nodereference'),
196 'multiple values' => CONTENT_HANDLE_CORE,
197 ),
198 'plain' => array(
199 'label' => t('Title (no link)'),
200 'field types' => array('nodereference'),
201 'multiple values' => CONTENT_HANDLE_CORE,
202 ),
203 'full' => array(
204 'label' => t('Full node'),
205 'field types' => array('nodereference'),
206 'multiple values' => CONTENT_HANDLE_CORE,
207 ),
208 'teaser' => array(
209 'label' => t('Teaser'),
210 'field types' => array('nodereference'),
211 'multiple values' => CONTENT_HANDLE_CORE,
212 ),
213 );
214 }
215
216 /**
217 * Theme function for 'default' nodereference field formatter.
218 */
219 function theme_nodereference_formatter_default($element) {
220 $output = '';
221 if (!empty($element['#item']['nid']) && is_numeric($element['#item']['nid']) && ($title = _nodereference_titles($element['#item']['nid']))) {
222 $output = l($title, 'node/'. $element['#item']['nid']);
223 }
224 return $output;
225 }
226
227 /**
228 * Theme function for 'plain' nodereference field formatter.
229 */
230 function theme_nodereference_formatter_plain($element) {
231 $output = '';
232 if (!empty($element['#item']['nid']) && is_numeric($element['#item']['nid']) && ($title = _nodereference_titles($element['#item']['nid']))) {
233 $output = check_plain($title);
234 }
235 return $output;
236 }
237
238 /**
239 * Proxy theme function for 'full' and 'teaser' nodereference field formatters.
240 */
241 function theme_nodereference_formatter_full_teaser($element) {
242 static $recursion_queue = array();
243 $output = '';
244 if (!empty($element['#item']['nid']) && is_numeric($element['#item']['nid'])) {
245 // If no 'referencing node' is set, we are starting a new 'reference thread'
246 if (!isset($node->referencing_node)) {
247 $recursion_queue = array();
248 }
249 $recursion_queue[] = $node->nid;
250 if (in_array($element['#item']['nid'], $recursion_queue)) {
251 // Prevent infinite recursion caused by reference cycles :
252 // if the node has already been rendered earlier in this 'thread',
253 // we fall back to 'default' (node title) formatter.
254 return theme('nodereference_formatter_default', $element);
255 }
256 if ($referenced_node = node_load($element['#item']['nid'])) {
257 $referenced_node->referencing_node = $node;
258 $referenced_node->referencing_field = $field;
259 _nodereference_titles($element['#item']['nid'], $referenced_node->title);
260 $output = node_view($referenced_node, $element['#formatter'] == 'teaser');
261 }
262 }
263 return $output;
264 }
265
266 /**
267 * Helper function for formatters.
268 *
269 * Store node titles collected in the curent request.
270 */
271 function _nodereference_titles($nid, $known_title = NULL) {
272 static $titles = array();
273 if (!isset($titles[$nid])) {
274 $title = $known_title ? $known_title : db_result(db_query("SELECT title FROM {node} WHERE nid=%d", $nid));
275 $titles[$nid] = $title ? $title : '';
276 }
277 return $titles[$nid];
278 }
279
280 /**
281 * Implementation of hook_widget_info().
282 *
283 * We need custom handling of multiple values for the nodereference_select
284 * widget because we need to combine them into a options list rather
285 * than display multiple elements.
286 *
287 * We will use the content module's default handling for default value.
288 *
289 * Callbacks can be omitted if default handing is used.
290 * They're included here just so this module can be used
291 * as an example for custom modules that might do things
292 * differently.
293 */
294 function nodereference_widget_info() {
295 return array(
296 'nodereference_select' => array(
297 'label' => t('Select List'),
298 'field types' => array('nodereference'),
299 'multiple values' => CONTENT_HANDLE_MODULE,
300 'callbacks' => array(
301 'default value' => CONTENT_CALLBACK_DEFAULT,
302 ),
303 ),
304 'nodereference_autocomplete' => array(
305 'label' => t('Autocomplete Text Field'),
306 'field types' => array('nodereference'),
307 'multiple values' => CONTENT_HANDLE_CORE,
308 'callbacks' => array(
309 'default value' => CONTENT_CALLBACK_DEFAULT,
310 ),
311 ),
312 );
313 }
314
315 /**
316 * Implementation of FAPI hook_elements().
317 *
318 * Any FAPI callbacks needed for individual widgets can be declared here,
319 * and the element will be passed to those callbacks for processing.
320 *
321 * Drupal will automatically theme the element using a theme with
322 * the same name as the hook_elements key.
323 *
324 * Autocomplete_path is not used by text_widget but other widgets can use it
325 * (see nodereference and userreference).
326 */
327 function nodereference_elements() {
328 return array(
329 'nodereference_select' => array(
330 '#input' => TRUE,
331 '#columns' => array('uid'), '#delta' => 0,
332 '#process' => array('nodereference_select_process'),
333 ),
334 'nodereference_autocomplete' => array(
335 '#input' => TRUE,
336 '#columns' => array('name'), '#delta' => 0,
337 '#process' => array('nodereference_autocomplete_process'),
338 '#autocomplete_path' => FALSE,
339 ),
340 );
341 }
342
343 /**
344 * Implementation of hook_widget().
345 *
346 * Attach a single form element to the form. It will be built out and
347 * validated in the callback(s) listed in hook_elements. We build it
348 * out in the callbacks rather than here in hook_widget so it can be
349 * plugged into any module that can provide it with valid
350 * $field information.
351 *
352 * Content module will set the weight, field name and delta values
353 * for each form element. This is a change from earlier CCK versions
354 * where the widget managed its own multiple values.
355 *
356 * If there are multiple values for this field, the content module will
357 * call this function as many times as needed.
358 *
359 * @param $form
360 * the entire form array, $form['#node'] holds node information
361 * @param $form_state
362 * the form_state, $form_state['values'][$field['field_name']]
363 * holds the field's form values.
364 * @param $field
365 * the field array
366 * @param $items
367 * array of default values for this field
368 * @param $delta
369 * the order of this item in the array of subelements (0, 1, 2, etc)
370 *
371 * @return
372 * the form item for a single element for this field
373 */
374 function nodereference_widget(&$form, &$form_state, $field, $items, $delta = 0) {
375 switch ($field['widget']['type']) {
376 case 'nodereference_select':
377 $element = array(
378 '#type' => 'nodereference_select',
379 '#default_value' => $items,
380 );
381 break;
382
383 case 'nodereference_autocomplete':
384 $element = array(
385 '#type' => 'nodereference_autocomplete',
386 '#default_value' => isset($items[$delta]) ? $items[$delta] : NULL,
387 '#value_callback' => 'nodereference_autocomplete_value',
388 );
389 break;
390 }
391 return $element;
392 }
393
394 /**
395 * Value for a nodereference autocomplete element.
396 *
397 * Substitute in the node title for the node nid.
398 */
399 function nodereference_autocomplete_value($element, $edit = FALSE) {
400 $field_key = $element['#columns'][0];
401 if (!empty($element['#default_value'][$field_key])) {
402 $nid = $element['#default_value'][$field_key];
403 $value = db_result(db_query(db_rewrite_sql('SELECT n.title FROM {node} n WHERE n.nid = %d'), $nid));
404 $value .= ' [nid:'. $nid .']';
405 return array($field_key => $value);
406 }
407 return array($field_key => NULL);
408 }
409
410 /**
411 * Process an individual element.
412 *
413 * Build the form element. When creating a form using FAPI #process,
414 * note that $element['#value'] is already set.
415 *
416 * The $fields array is in $form['#field_info'][$element['#field_name']].
417 */
418 function nodereference_select_process($element, $edit, $form_state, $form) {
419 // The nodereference_select widget doesn't need to create its own
420 // element, it can wrap around the optionwidgets_select element.
421 // Add a validation step where the value can be unwrapped.
422 $field_key = $element['#columns'][0];
423 $element[$field_key] = array(
424 '#type' => 'optionwidgets_select',
425 '#default_value' => isset($element['#value']) ? $element['#value'] : '',
426 '#element_validate' => array('optionwidgets_validate', 'nodereference_select_validate'),
427
428 // The following values were set by the content module and need
429 // to be passed down to the nested element.
430 '#field_name' => $element['#field_name'],
431 '#delta' => $element['#delta'],
432 '#columns' => $element['#columns'],
433 '#title' => $element['#title'],
434 '#required' => $element['#required'],
435 '#description' => $element['#description'],
436 );
437 return $element;
438 }
439
440 /**
441 * Process an individual element.
442 *
443 * Build the form element. When creating a form using FAPI #process,
444 * note that $element['#value'] is already set.
445 *
446 */
447 function nodereference_autocomplete_process($element, $edit, $form_state, $form) {
448 // The nodereference autocomplete widget doesn't need to create its own
449 // element, it can wrap around the text_textfield element and add an autocomplete
450 // path and some extra processing to it.
451 // Add a validation step where the value can be unwrapped.
452 $field_key = $element['#columns'][0];
453
454 $element[$field_key] = array(
455 '#type' => 'text_textfield',
456 '#default_value' => isset($element['#value']) ? $element['#value'] : '',
457 '#autocomplete_path' => 'nodereference/autocomplete/'. $element['#field_name'],
458 '#element_validate' => array('nodereference_autocomplete_validate'),
459
460 // The following values were set by the content module and need
461 // to be passed down to the nested element.
462 '#field_name' => $element['#field_name'],
463 '#delta' => $element['#delta'],
464 '#columns' => $element['#columns'],
465 '#title' => $element['#title'],
466 '#required' => $element['#required'],
467 '#description' => $element['#description'],
468 );
469 return $element;
470 }
471
472 /**
473 * Validate an select element.
474 *
475 * Remove the wrapper layer and set the right element's value.
476 */
477 function nodereference_select_validate($element, &$form_state) {
478 $field_key = $element['#columns'][0];
479 array_pop($element['#parents']);
480 form_set_value($element, $form_state['values'][$element['#field_name']][$field_key], $form_state);
481 }
482
483 /**
484 * Validate an autocomplete element.
485 *
486 * Remove the wrapper layer and set the right element's value.
487 */
488 function nodereference_autocomplete_validate($element, &$form_state) {
489 $field_name = $element['#field_name'];
490 $field = content_fields($field_name);
491 $field_key = $element['#columns'][0];
492 $delta = $element['#delta'];
493 $value = $element['#value'][$field_key];
494 $nid = NULL;
495 if (!empty($value)) {
496 preg_match('/^(?:\s*|(.*) )?\[\s*nid\s*:\s*(\d+)\s*\]$/', $value, $matches);
497 if (!empty($matches)) {
498 // explicit nid
499 list(, $title, $nid) = $matches;
500 if (!empty($title) && ($n = node_load($nid)) && $title != $n->title) {
501 form_set_error($element[$field_key], t('%name : Title mismatch. Please check your selection.'), array('%name' => t($element[$field_key]['#title'])));
502 }
503 }
504 else {
505 // no explicit nid
506 // TODO :
507 // the best thing would be to present the user with an additional form,
508 // allowing the user to choose between valid candidates with the same title
509 // ATM, we pick the first matching candidate...
510 $nids = _nodereference_potential_references($field, FALSE, $value, TRUE);
511 $nid = (!empty($nids)) ? array_shift(array_keys($nids)) : 0;
512 }
513 }
514 form_set_value($element, $nid, $form_state);
515 return $element;
516 }
517
518 /**
519 * Implementation of hook_allowed_values().
520 */
521 function nodereference_allowed_values($field) {
522 $options = _nodereference_potential_references($field, TRUE);
523 foreach ($options as $key => $value) {
524 $options[$key] = _nodereference_item($field, $value);
525 }
526 if (!$field['required']) {
527 $options = array(0 => '<'. t('none') .'>') + $options;
528 }
529 return $options;
530 }
531
532 /**
533 * Fetch an array of all candidate referenced nodes,
534 * for use in presenting the selection form to the user.
535 */
536 function _nodereference_potential_references($field, $return_full_nodes = FALSE, $string = '', $exact_string = false) {
537 // TODO Once filtering by title is working, get rid of "empty($string)" constraint to use this with autocomplete.
538 if (empty($string) && module_exists('views') && isset($field['advanced_view']) && $field['advanced_view'] != '--' && ($view = views_get_view($field['advanced_view']))) {
539 // advanced field : referenceable nodes defined by a view
540 // let views.module build the query
541
542 $view->init();
543
544 // TODO is this the right way to do this?
545 // make sure the fields get included in the query
546 $view->set_display('page');
547 $view->display['page']->style_plugin = 'list';
548
549 // arguments for the view
550 if (isset($field['advanced_view_args'])) {
551 // TODO: Support Tokens using token.module ?
552 $view_args = array();
553 $view_args = array_map('trim', explode(',', $field['advanced_view_args']));
554 $view->set_arguments($view_args);
555 }
556
557 // TODO Filtering by title is not yet working in Views 2, can't do this yet??
558 //if (isset($string)) {
559 // views_view_add_filter($view, 'node', 'title', $exact_string ? '=' : 'contains', $string, null);
560 //}
561
562 // we do need title field, so add it if not present (unlikely, but...)
563 //$has_title = array_reduce($view->field, create_function('$a, $b', 'return ($b["field"] == "title") || $a;'), false);
564 //if (!$has_title) {
565 // views_view_add_field($view, 'node', 'title', '');
566 //}
567 //views_load_cache();
568 //views_sanitize_view($view);
569
570 // make sure the query is not cached
571 $view->is_cacheable = FALSE;
572
573 $view->execute();
574 $options = array();
575 foreach ($view->result as $row) {
576 foreach ($view->field as $field) {
577 if (!empty($field['handler']) && is_object($field['handler'])) {
578 $options[$row->nid][] = theme('views_view_field', $view, $field, $row);
579 }
580 }
581 }
582 return $options;
583 }
584 else {
585 // standard field : referenceable nodes defined by content types
586 // build the appropriate query
587 $related_types = array();
588 $args = array();
589
590 if (is_array($field['referenceable_types'])) {
591 foreach ($field['referenceable_types'] as $related_type) {
592 if ($related_type) {
593 $related_types[] = " n.type = '%s'";
594 $args[] = $related_type;
595 }
596 }
597 }
598
599 $related_clause = implode(' OR ', $related_types);
600
601 if (!count($related_types)) {
602 return array();
603 }
604
605 if (isset($string)) {
606 $string_clause = $exact_string ? " AND n.title = '%s'" : " AND n.title LIKE '%%%s%'";
607 $related_clause = "(". $related_clause .")". $string_clause;
608 $args[] = $string;
609 }
610
611 $result = db_query(db_rewrite_sql("SELECT n.nid, n.title AS node_title, n.type AS node_type FROM {node} n WHERE ". $related_clause ." ORDER BY n.title, n.type"), $args);
612 }
613
614 $rows = array();
615
616 while ($node = db_fetch_object($result)) {
617 if ($return_full_nodes) {
618 $rows[$node->nid] = $node;
619 }
620 else {
621 $rows[$node->nid] = $node->node_title;
622 }
623 }
624
625 return $rows;
626 }
627
628 /**
629 * Retrieve a pipe delimited string of autocomplete suggestions
630 */
631 function nodereference_autocomplete($field_name, $string = '') {
632 $fields = content_fields();
633 $field = $fields[$field_name];
634 $matches = array();
635
636 foreach (_nodereference_potential_references($field, TRUE, $string) as $row) {
637 $matches[$row->node_title .' [nid:'. $row->nid .']'] = _nodereference_item($field, $row, TRUE);
638 }
639 drupal_json($matches);
640 }
641
642 function _nodereference_item($field, $item, $html = FALSE) {
643 if (module_exists('views') && isset($field['advanced_view']) && $field['advanced_view'] != '--' && ($view = views_get_view($field['advanced_view']))) {
644 $field_names = array();
645 foreach ($view->field as $name => $viewfield) {
646 $field_names[] = $name;
647 }
648 $output = theme('nodereference_item_advanced', $item, $field_names, $view);
649 if (!$html) {
650 // Views theming runs check_plain (htmlentities) on the values.
651 // We reverse that with html_entity_decode.
652 $output = html_entity_decode(strip_tags($output), ENT_QUOTES);
653 }
654 }
655 else {
656 $output = theme('nodereference_item_simple', $item);
657 $output = $html ? check_plain($output) : $output;
658 }
659 return $output;
660 }
661
662 function theme_nodereference_item_advanced($item, $field_names, $view) {
663 $item_fields = array();
664 foreach ($item as $delta => $value) {
665 // remove link tags (ex : for node titles)
666 $value = preg_replace('/<a[^>]*>(.*)<\/a>/iU', '$1', $value);
667 if (!empty($value)) {
668 $item_fields[] = "<span class='view-field view-data-$field_names[$delta]'>$value</span>";;
669 }
670 }
671 $output = implode(' - ', $item_fields);
672 $output = "<span class='view-item view-item-$view->name'>$output</span>";
673 return $output;
674 }
675
676 function theme_nodereference_item_simple($item) {
677 return $item->node_title;
678 }
679
680 /**
681 * Provide a list of users to filter on.
682 */
683 function _nodereference_filter_handler($op, $filterinfo) {
684 $options = array(0 => t('<empty>'));
685 $options = $options + _nodereference_potential_references($filterinfo['extra']['field']);
686 return $options;
687 }
688
689 /**
690 * FAPI theme for an individual elements.
691 *
692 * The textfield or select is already rendered by the
693 * textfield or select themes and the html output
694 * lives in $element['#children']. Override this theme to
695 * make custom changes to the output.
696 *
697 * $element['#field_name'] contains the field name
698 * $element['#delta] is the position of this element in the group
699 */
700 function theme_nodereference_select($element) {
701 return $element['#children'];
702 }
703
704 function theme_nodereference_autocomplete($element) {
705 return $element['#children'];
706 }

  ViewVC Help
Powered by ViewVC 1.1.2