Project

General

Profile

Download (62.1 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/**
3
 * @file
4
 * Description theming functions.
5
 *
6
 * @copyright
7
 *   (C) 2007-2012 EDIT
8
 *   European Distributed Institute of Taxonomy
9
 *   http://www.e-taxonomy.eu
10
 *
11
 *   The contents of this module are subject to the Mozilla
12
 *   Public License Version 1.1.
13
 * @see http://www.mozilla.org/MPL/MPL-1.1.html
14
 */
15

    
16

    
17
/**
18
 * Theme function to alter the feature representation.
19
 *
20
 * It is highly qeutionalbe if this function should be completely removed.
21
 * If a feature needs a different representation this should be edited directly
22
 * in the cdm data but it shoud not be tweeked like this in the portal.
23
 *
24
 * Used in:
25
 *  - theme_cdm_feature_nodesTOC()
26
 *  - theme_cdm_feature_nodes()
27
 *  - theme_cdm_media_mime_application()
28
 *  - theme_cdm_media_mime_text()
29
 *
30
 * TODO delete this function? (a.kohlbecker feb 2013)
31
 *
32
 */
33
function theme_cdm_feature_name($variables) {
34
  $feature_name = $variables['feature_name'];
35
  return t($feature_name);
36
}
37

    
38
/**
39
 * Returns a set of feature blocks for a taxon profile from the $mergedFeatureNodes of a given $taxon.
40
 *
41
 * The taxon profile consists of drupal block elements, one for the description elements
42
 * of a specific feature. The structure is defined by specific FeatureTree.
43
 * The chosen FeatureTree is merged with the list of description elements prior to using this method.
44
 *
45
 * The merged nodes can be obtained by making use of the
46
 * function cdm_ws_descriptions_by_featuretree().
47
 *
48
 * @see cdm_ws_descriptions_by_featuretree()
49
 *
50
 * @param $mergedFeatureNodes
51
 *
52
 * @param $taxon
53
 *
54
 * @return array
55
 *  A Drupal render array containing feature blocks and the table of content
56
 *
57
 * @ingroup compose
58
 */
59
function compose_cdm_feature_nodes($mergedFeatureNodes, $taxon) {
60

    
61
  $block_list = array();
62

    
63
  RenderHints::pushToRenderStack('feature_nodes');
64

    
65
  $gallery_settings = getGallerySettings(CDM_DATAPORTAL_DESCRIPTION_GALLERY_NAME);
66

    
67
  // Create a drupal block for each feature
68
  foreach ($mergedFeatureNodes as $node) {
69

    
70
    if ((isset($node->descriptionElements['#type']) ||
71
        has_feature_node_description_elements($node)) && $node->feature->uuid != UUID_IMAGE) { // skip empty or supressed features
72

    
73
      $feature_name = cdm_term_representation($node->feature, 'Unnamed Feature');
74

    
75
      $block = feature_block($feature_name, $node->feature);
76
      $block->content = array();
77
      $block_content_is_empty = TRUE;
78
      $block_content_weight = 0;
79

    
80
      /*
81
       * Content/DISTRIBUTION.
82
       */
83

    
84
      if ($node->feature->uuid == UUID_DISTRIBUTION) {
85
        $block = compose_feature_block_distribution($taxon, $node->descriptionElements, $node->feature);
86
        $block_content_is_empty = FALSE;
87
      }
88
      /*
89
       * Content/COMMON_NAME.
90
       */
91
      else if ($node->feature->uuid == UUID_COMMON_NAME) {
92
        $common_names_render_array = compose_cdm_common_names($node->descriptionElements, $node->feature);
93
        $block->content[] = $common_names_render_array;
94
        $block_content_is_empty = FALSE;
95
      }
96

    
97
      else if ($node->feature->uuid == UUID_USE_RECORD) {
98
        $block_uses_content_html = theme('cdm_block_Uses', array('taxonUuid' => $taxon->uuid));
99
        $block->content[] = markup_to_render_array($block_uses_content_html);
100
        $block_content_is_empty = FALSE;
101
      }
102

    
103
      /*
104
       * Content/ALL OTHER FEATURES.
105
       */
106
      else {
107

    
108
        $media_list = array();
109
        $out_child_elements = '';
110

    
111
        if (isset($node->descriptionElements)) {
112
          $taxon_uuid = NULL;
113
          if(isset($taxon) ) {
114
            $taxon_uuid = $taxon->uuid;
115
          }
116
          $elements_render_array = compose_cdm_descriptionElements($node->descriptionElements, $node->feature, $taxon_uuid);
117
          $block_content_is_empty = empty($elements_render_array);
118
          $block->content[] = $elements_render_array;
119
        }
120

    
121
          // Content/ALL OTHER FEATURES/Subordinate Features
122
          // subordinate features are printed inline in one floating text,
123
          // it is expected hat subordinate features can "contain" TextData,
124
          // Qualitative- and Qualitative- DescriptioneElements
125
          if (isset($node->childNodes[0])) {
126

    
127
          // TODO support more than one level of children.
128
          // can this be solved by recursively calling this function?
129
          // @see http://dev.e-taxonomy.eu/trac/ticket/2393
130
          $text = '';
131
          foreach ($node->childNodes as $child) {
132

    
133
            if (isset($child->descriptionElements) && is_array($child->descriptionElements)) {
134
              foreach ($child->descriptionElements as $element) {
135

    
136
                //TODO it woud be better if we could use compose_cdm_descriptionElements() directly instead of the below stuff
137

    
138
                if (is_array($element->media)) {
139
                  // Append media of supordinate elements to list of main
140
                  // feature.
141
                  $media_list = array_merge($media_list, $element->media);
142
                }
143

    
144
                switch ($element->class) {
145
                  case 'TextData':
146
                    // FIXME use theme_cdm_descriptionElementTextData()
147
                    if(isset($element->multilanguageText_L10n->text)){
148
                      $out_child_elements = str_replace("\n", "<br/>", $element->multilanguageText_L10n->text);
149
                    }
150
                    $out_child_elements = str_replace($child->feature->titleCache, '<em>' . $child->feature->representation_L10n . '</em>', $out_child_elements);
151
                    break;
152
                  case 'CategoricalData':
153
                    $out_child_elements  = '<em>' . $child->feature->representation_L10n . '</em> '
154
                      . theme('cdm_descriptionElement_CategoricalData', array('element' => $element));
155
                    break;
156
                  case 'QuantitativeData':
157
                    $out_child_elements = '<em>' . $child->feature->representation_L10n . '</em> '
158
                      . theme('cdm_descriptionElement_QuantitativeData', array('element' => $element));
159

    
160
                }
161

    
162
              }
163
              $text .= " " . $out_child_elements;
164
              $out_child_elements = '';
165
            }
166
          }
167
          $block_content_is_empty = $block_content_is_empty && empty($text);
168
          $block->content[] = markup_to_render_array($text);
169
          $block_content_is_empty = $block_content_is_empty && empty($media_list);
170
          $block->content[] = compose_feature_media_gallery($node, $media_list, $gallery_settings);
171

    
172

    
173
          }
174
        /*
175
         * Footnotes for the feature block
176
         */
177
        $block->content[] = markup_to_render_array(theme('cdm_footnotes', array('footnoteListKey' => $node->feature->uuid)));
178
        $block->content[] = markup_to_render_array(theme('cdm_annotation_footnotes', array('footnoteListKey' => $node->feature->uuid)));
179
      } // END all other features
180

    
181
      if(!$block_content_is_empty){ // skip empty block content
182
        $block_list[] = $block;
183
        cdm_toc_list_add_item(cdm_term_representation($node->feature), $node->feature->uuid);
184
      } // END: skip empty block content
185
    } // END: skip empty or supressed features
186
  } // END: creating a block per feature
187

    
188
  drupal_alter('cdm_feature_node_blocks', $block_list, $taxon);
189

    
190
  RenderHints::popFromRenderStack();
191

    
192
  return _block_get_renderable_array($block_list);
193
}
194

    
195
  /**
196
   * @param $node
197
   * @param $media_list
198
   * @param $gallery_settings
199
   * @return array
200
   */
201
  function compose_feature_media_gallery($node, $media_list, $gallery_settings) {
202
    if (isset($node->descriptionElements)) {
203
      $media_list = array_merge($media_list, cdm_dataportal_media_from_descriptionElements($node->descriptionElements));
204
    }
205
    $captionElements = array('title', 'rights');
206
    $gallery = '';
207
    if (isset($gallery_settings['cdm_dataportal_media_maxextend']) && isset($gallery_settings['cdm_dataportal_media_cols'])) {
208
      $gallery = theme('cdm_media_gallerie', array(
209
        'mediaList' => $media_list,
210
        'galleryName' => CDM_DATAPORTAL_DESCRIPTION_GALLERY_NAME . '_' . $node->feature->uuid,
211
        'maxExtend' => $gallery_settings['cdm_dataportal_media_maxextend'],
212
        'cols' => $gallery_settings['cdm_dataportal_media_cols'],
213
        'captionElements' => $captionElements,
214
      ));
215
      return markup_to_render_array($gallery);
216
    }
217
    return markup_to_render_array($gallery);
218
  }
219

    
220
  /**
221
   * @param $taxon
222
   * @param $descriptionElements
223
   *   an associative array with two elements:
224
   *   - '#type': must be 'DTO'
225
   *   - 'DistributionInfoDTO': a CDM DistributionInfoDTO object as returned by the DistributionInfo web service
226
   * @param $feature
227
   *
228
   * @ingroup compose
229
   */
230
  function compose_feature_block_distribution($taxon, $descriptionElements, $feature) {
231
    $text_data_glue = '';
232
    $text_data_sortOutArray = FALSE;
233
    $text_data_enclosingTag = 'ul';
234
    $text_data_out_array = array();
235

    
236
    $distributionElements = NULL;
237
    $distribution_info_dto = NULL;
238
    $distribution_sortOutArray = FALSE;
239

    
240
    if (variable_get('distribution_sort', 'NO_SORT') != 'NO_SORT') {
241
      $distribution_glue = '';
242
      $distribution_enclosingTag = 'dl';
243
    } else {
244
      $distribution_glue = '';
245
      $distribution_enclosingTag = 'ul';
246
    }
247

    
248
    if (!isset($descriptionElements['#type']) || !$descriptionElements['#type'] == 'DTO') {
249
      // skip the DISTRIBUTION section if there is no DTO type element
250
      return array(); // FIXME is it ok to return an empty array?
251
    }
252

    
253
    $block = feature_block(
254
      cdm_term_representation($feature, 'Unnamed Feature'),
255
      $feature
256
    );
257

    
258
    // $$descriptionElements['TextData'] is added to to the feature node in merged_taxon_feature_tree()
259
    if (isset($descriptionElements['TextData'])) {
260
      // --- TextData
261
      foreach ($descriptionElements['TextData'] as $text_data_element) {
262
        $asListElement = FALSE;
263
        $text_data_render_array = compose_cdm_descriptionElementTextData($text_data_element, $asListElement, $text_data_element->feature->uuid);
264
        $repr = drupal_render($text_data_render_array);
265

    
266
        if (!array_search($repr, $text_data_out_array)) { // de-duplication !!
267
          $text_data_out_array[] = $repr;
268
          // TODO HINT: sorting in compose_cdm_feature_block_elements will
269
          // not work since this array contains html attributes with uuids
270
          // and what is about cases like the bibliography where
271
          // any content can be prefixed with some foot-note anchors?
272
          $text_data_sortOutArray = TRUE;
273
          $text_data_glue = '<br/> ';
274
          $text_data_enclosingTag = 'p';
275
        }
276
      }
277
    }
278

    
279

    
280
    if ($text_data_out_array && variable_get(DISTRIBUTION_TEXTDATA_DISPLAY_ON_TOP, 0)) {
281
      $block->content[] = compose_cdm_feature_block_elements(
282
        $text_data_out_array,
283
        $feature,
284
        $text_data_glue,
285
        $text_data_sortOutArray,
286
        $text_data_enclosingTag
287
      );
288
    }
289

    
290
    // --- Distribution map
291
    $distribution_map_query_parameters = NULL;
292
    if (isset($descriptionElements['DistributionInfoDTO'])) {
293
      $distribution_map_query_parameters = $descriptionElements['DistributionInfoDTO']->mapUriParams;
294
    }
295
    $map_render_element = compose_distribution_map($taxon, $distribution_map_query_parameters);
296
    $block->content[] = $map_render_element;
297

    
298
    // --- tree or list
299
    $dto_out_array = array();
300
    if (isset($descriptionElements['DistributionInfoDTO'])) {
301
      $distribution_info_dto = $descriptionElements['DistributionInfoDTO'];
302

    
303
      // --- tree
304
      if (is_object($distribution_info_dto->tree)) {
305
        $dto_out_array[] = theme('cdm_description_ordered_distributions', array('distribution_tree' => $distribution_info_dto->tree));
306
      }
307

    
308
      // --- sorted element list
309
      if (is_array($distribution_info_dto->elements) && count($distribution_info_dto->elements) > 0) {
310
        foreach ($distribution_info_dto->elements as $descriptionElement) {
311
          if (is_object($descriptionElement->area)) {
312
            $sortKey = $descriptionElement->area->representation_L10n;
313
            $distributionElements[$sortKey] = $descriptionElement;
314
          }
315
        }
316
        ksort($distributionElements);
317
        $distribution_element_render_array = compose_cdm_descriptionElement_Distribution($distributionElements);
318
        $dto_out_array[] = drupal_render($distribution_element_render_array);
319

    
320
      }
321
      //
322
      $block->content[] = compose_cdm_feature_block_elements(
323
        $dto_out_array,
324
        $feature,
325
        $distribution_glue,
326
        $distribution_sortOutArray,
327
        $distribution_enclosingTag
328
      );
329
    }
330

    
331
    // --- TextData at the bottom
332
    if ($text_data_out_array && !variable_get(DISTRIBUTION_TEXTDATA_DISPLAY_ON_TOP, 0)) {
333
      $block->content[] = compose_cdm_feature_block_elements(
334
        $text_data_out_array,
335
        $feature,
336
        $text_data_glue,
337
        $text_data_sortOutArray,
338
        $text_data_enclosingTag
339
      );
340
    }
341

    
342
    $block->content[] = markup_to_render_array(theme('cdm_footnotes', array('footnoteListKey' => UUID_DISTRIBUTION)));
343
    $block->content[] = markup_to_render_array(theme('cdm_annotation_footnotes', array('footnoteListKey' => UUID_DISTRIBUTION)));
344

    
345
    return $block;
346
  }
347

    
348

    
349
  /**
350
 * @todo Please document this function.
351
 * @see http://drupal.org/node/1354
352
 */
353
function theme_FeatureTree_hierarchy($variables) {
354

    
355
  $FeatureTreeUuid = $variables['FeatureTreeUuid'];
356
  if (!is_uuid($FeatureTreeUuid)) {
357
    return;
358
  }
359

    
360
  $out = '';
361
  $featureTree = cdm_ws_get(CDM_WS_FEATURETREE, array(
362
    $FeatureTreeUuid,
363
  ));
364

    
365
  if (isset($featureTree) && isset($featureTree->root)) {
366
    $out = '<ul class="' . $featureTree->class . '">';
367
    $out .= theme('FeatureTree_hierarchy_children', array('node' => $featureTree->root));
368
    $out .= '</ul>';
369
  }
370
  return $out;
371
}
372

    
373
/**
374
 * @todo Please document this function.
375
 * @see http://drupal.org/node/1354
376
 */
377
function theme_FeatureTree_hierarchy_children($variables) {
378

    
379
  $node = $variables['node'];
380
  $out = '';
381
  if (isset($node->childNodes)) {
382

    
383
    foreach ($node->childNodes as $childNode) {
384
      $out .= '<li>' . check_plain($childNode->feature->representation_L10n);
385
      if (isset($childNode->childNodes) && count($childNode->childNodes) > 0) {
386
        $out .= '<ul>' . theme('FeatureTree_hierarchy_children', array('node' => $childNode)) . '</ul>';
387
      }
388
      $out .= '</li>';
389
    }
390
  }
391
  return $out;
392
}
393

    
394
/**
395
 * Returns HTML for the texts in a description $elements.
396
 *
397
 * Joins the texts in $elements and encloses with a HTML tag.
398
 *
399
 * @param  $elements
400
 * @param  feature:
401
 *  The feature to which the elements given in $elements are belonging to.
402
 * @param  glue:
403
 *  Defaults to empty string.
404
 * @param $sort
405
 *   Boolean Whether to sort the $elements alphabetically, default is FALSE
406
 * @param  $enclosing_tag
407
 *
408
 * @ingroup compose
409
 */
410
function compose_cdm_feature_block_elements($elements, $feature, $glue = '', $sort = FALSE, $enclosing_tag = 'ul') {
411

    
412
  $feature_block_settings = get_feature_block_settings($feature->uuid);
413
  if($feature_block_settings['as_list']){
414
    $enclosing_tag = $feature_block_settings['as_list'];
415
  }
416

    
417
  $out = '<' . $enclosing_tag . ' class="feature-block-elements" id="' . $feature->representation_L10n . '">';
418

    
419
  if ($sort) {
420
    sort($elements);
421
  }
422

    
423
  //TODO it would be nice if any element would get "feature-block-element" as additional class attribute
424
  //     this will become possible once all $elemets are real Drupal render arrays
425
  $out .= join($glue, $elements) ;
426

    
427
  $out .= '</' . $enclosing_tag . '>';
428
  return markup_to_render_array($out);
429
}
430

    
431

    
432
/**
433
 * Theme function to render CDM DescriptionElements of the type CategoricalData.
434
 *
435
 * @param array $variables
436
 *   An associative array containing:
437
 *  - element: the CategoricalData element
438
 * @return a html representation of the given CategoricalData element
439
 *
440
 * @ingroup themeable
441
 */
442
function theme_cdm_descriptionElement_CategoricalData($variables) {
443
  $element = $variables['element'];
444

    
445
  $state_data_strings = array();
446
  if (isset($element->stateData)) {
447
    foreach ($element->stateData as $stateData) {
448

    
449
      $state  = NULL;
450

    
451
      if(isset($stateData->state)){
452
        $state = cdm_term_representation($stateData->state);
453
      }
454

    
455
      if (isset($stateData->modifyingText_L10n)) {
456
        $state = ' ' . $stateData->modifyingText_L10n;
457
      }
458

    
459
      $modifiers_strings = cdm_modifers_representations($stateData);
460

    
461
      $state_data_strings[] = $state . ($modifiers_strings ? ' ' . $modifiers_strings : '');
462

    
463
    }
464
  }
465

    
466
  $footnote_key_list_str = cdm_create_description_element_footnotes($element);
467

    
468
  $out = '<span class="' . html_class_attribute_ref($element) . '">' . implode(', ', $state_data_strings) . '</span>';
469
  return $out . $footnote_key_list_str;
470
}
471

    
472
/**
473
 * Theme function to render CDM DescriptionElements of the type QuantitativeData.
474
 *
475
 * @param array $variables
476
 *   An associative array containing:
477
 *  - element: the QuantitativeData element
478
 * @return a html representation of the given QuantitativeData element
479
 *
480
 * @ingroup themeable
481
 */
482
function theme_cdm_descriptionElement_QuantitativeData($variables) {
483
  /*
484
   * - statisticalValues
485
   *   - value
486
   *   - modifiers
487
   *   - type
488
   * - unit->representation_L10n
489
   * - modifyingText
490
   * - modifiers
491
   * - sources
492
   */
493
  $element = $variables['element'];
494

    
495
  $out = '';
496

    
497
  $type_representation = NULL;
498
  $modifiers_strings = array();
499

    
500

    
501
  if (isset($element->statisticalValues)) {
502
    $value_array = array();
503
    foreach ($element->statisticalValues as $val) {
504
      if (isset($val->value)) {
505
        $value_array[] = $val->value;
506
      }
507
    }
508

    
509
    $out .= implode($value_array, ', ');
510
  }
511

    
512
  if (isset($element->unit)) {
513
    $out .= ' '. cdm_term_representation($element->unit);
514
  }
515

    
516
  if (isset($element->statisticalValues->modifyingText_L10n)) {
517
    $out .=  ' ' . $element->statisticalValues->modifyingText_L10n;
518
  }
519
  $modifiers_strings = cdm_modifers_representations($element->statisticalValues);
520
  $out .= ($modifiers_strings ? ' ' . cdm_modifers_representations($element->statisticalValues) : '');
521

    
522
  $footnote_key_list_str = cdm_create_description_element_footnotes($element);
523

    
524
  return $out . $footnote_key_list_str;
525

    
526
}
527

    
528
/**
529
 * Theme function to render CDM DescriptionElements of the type IndividualsAssociations.
530
 *
531
 * @param array $variables
532
 *   An associative array containing:
533
 *  - element: the IndividualsAssociations element
534
 * @return html representation of the given IndividualsAssociations element
535
 *
536
 * @ingroup themeable
537
 */
538
function theme_cdm_descriptionElement_IndividualsAssociation($variables) {
539

    
540
  $element = $variables['element'];
541

    
542
  $out = '';
543

    
544
  $render_array = compose_cdm_specimenOrObservation($element->associatedSpecimenOrObservation);
545

    
546
  if (isset($element->description_L10n)) {
547
    $out .=  ' ' . $element->description_L10n;
548
  }
549

    
550
  $out .= drupal_render($render_array);
551

    
552
  $footnote_key_list_str = cdm_create_description_element_footnotes($element);
553

    
554
  return $out . $footnote_key_list_str;
555

    
556

    
557
}
558

    
559
/**
560
 * Theme function to render CDM DescriptionElements of the type TaxonInteraction.
561
 *
562
 * @param array $variables
563
 *   An associative array containing:
564
 *  - element: the TaxonInteraction element
565
 * @return html representation of the given TaxonInteraction element
566
 *
567
 * @ingroup themeable
568
 */
569
function theme_cdm_descriptionElement_TaxonInteraction($variables) {
570

    
571
  $element = $variables['element'];
572

    
573
  $out = '';
574

    
575
  if (isset($element->description_L10n)) {
576
    $out .=  ' ' . $element->description_L10n;
577
  }
578

    
579
  if(isset($element->taxon2)){
580
    $out = theme('cdm_taxonName',
581
        array(
582
            'taxonName' => $element->taxon2->name,
583
            'nameLink' => url(path_to_taxon($element->taxon2->uuid))
584
        )
585
      );
586
  }
587

    
588
  $footnote_key_list_str = cdm_create_description_element_footnotes($element);
589

    
590
  return $out . $footnote_key_list_str;
591

    
592

    
593
}
594

    
595
/**
596
 * Composes a drupal render array for CDM TextData description elements.
597
 *
598
 * @param $element
599
 *    The CDM TextData description element which contains the textual  information.
600
 * @param $asListElement
601
 *    A boolean which determines whether the citations should
602
 *     be rendered as a list or not.
603
 *    TODO remove and replace $asListElement by $feature_block_settings['as_list']
604
 *  @param $feature_uuid
605
 *
606
 * @return array
607
 *   A drupal render array with the following elements being used:
608
 *    - #tag: either 'div', 'li', ...
609
 *    ⁻ #attributes: class attributes
610
 *    - #value_prefix: (optionally) contains footnote anchors
611
 *    - #value: contains the textual content
612
 *    - #value_suffix: (optionally) contains footnote keys
613
 *
614
 * @ingroup compose
615
 */
616
function compose_cdm_descriptionElementTextData($element, $asListElement, $feature_uuid) {
617

    
618
  $footnote_list_key_suggestion = $feature_uuid;
619

    
620
  // FIXME $feature_block_settings should be passed as parameter!!!!!
621
  $feature_block_settings = get_feature_block_settings($feature_uuid);
622

    
623
  // FIXME remove this hack ---------------------------
624
  $default_theme = variable_get('theme_default', NULL);
625
  if($default_theme == 'garland_cichorieae' || $default_theme == 'cyprus'
626
    || $default_theme == 'flore_afrique_centrale' || $default_theme == 'flora_malesiana' || $default_theme == 'flore_gabon' ){
627
    $asListElement = $feature_block_settings['as_list'] == 'ul';
628
  }
629
  // --------------------------------------------------
630

    
631
  $render_array = array(
632
    '#type' => 'html_tag',
633
    '#tag' => $asListElement ? 'li' : 'span',
634
    '#attributes' => array(
635
      'class' => 'DescriptionElement DescriptionElement-' . $element->class . '
636
      ' .  html_class_attribute_ref($element)
637
    ),
638
    '#value' => '',
639
    '#value_suffix' => NULL
640
  );
641

    
642
  $element_text = '';
643
  if (isset($element->multilanguageText_L10n->text)) {
644
    // TODO replacement of \n by <br> should be configurable
645
    $element_text = str_replace("\n", "<br/>", $element->multilanguageText_L10n->text);
646
  }
647

    
648
  $annotations_and_sources = handle_annotations_and_sources($element, $feature_block_settings, $element_text, $footnote_list_key_suggestion);
649

    
650
  $names_used_in_source_markup = '';
651
  if (!empty($annotations_and_sources['names_used_in_source']) && empty($element_text)) {
652
    // $element_text ==  NULL  usually occurs only in the case of CITATIONS!!!
653
    $names_used_in_source_markup = join(', ', $annotations_and_sources['names_used_in_source']) . ': ';
654
  }
655

    
656
  $source_references_markup = '';
657
  if(!empty($annotations_and_sources['source_references'])){
658
    $source_references_markup = '<span class="sources">'. join(' ', $annotations_and_sources['source_references']) . '<span>';
659
  }
660

    
661
  $render_array['#value'] = $names_used_in_source_markup . $element_text . $source_references_markup;
662
  $render_array['#value-suffix'] = $annotations_and_sources['foot_note_keys'];
663

    
664
  return $render_array;
665
}
666

    
667
  /**
668
   * @param $element
669
   * @param $feature_block_settings
670
   * @param $element_text
671
   * @param $footnote_list_key_suggestion
672
   * @return array
673
   *   an associative array with the following elements:
674
   *   - foot_note_keys: all footnote keys as markup
675
   *   - source_references: an array of the source references citations
676
   *   - names used in source: an associative array of the names in source,
677
   *        the name in source string are de-duplicated
678
   *        !!!NOTE!!!!: this field will most probably be removed soon (TODO)
679
   *
680
   *
681
   */
682
  function handle_annotations_and_sources($element, $feature_block_settings, $element_text, $footnote_list_key_suggestion) {
683
    $annotations_and_sources = array(
684
      'foot_note_keys' => NULL,
685
      'source_references' => array(),
686
      'names_used_in_source' => array()
687
    );
688

    
689
    if ($feature_block_settings['sources_as_content']) {
690
      foreach ($element->sources as $source) {
691

    
692
        $referenceCitation = theme('cdm_OriginalSource',
693
          array(
694
            'source' => $source,
695
            'doLink' => $feature_block_settings['link_to_reference']
696
          )
697
        );
698

    
699
        if ($referenceCitation) {
700
          if (empty($element_text)) {
701
            $annotations_and_sources['source_references'][] = $referenceCitation;
702
          }
703
          else {
704
            $annotations_and_sources['source_references'][] = ' (' . $referenceCitation . ')';
705
          }
706
        }
707

    
708
        $name_in_source_render_array = compose_name_in_source(
709
          $source,
710
          $feature_block_settings['link_to_name_used_in_source']
711
        );
712

    
713
        if(!empty($name_in_source_render_array)){
714
          $annotations_and_sources['names_used_in_source'][$name_in_source_render_array['#_plaintext']] = drupal_render($name_in_source_render_array);
715
        }
716
      } // END of loop over sources
717

    
718
      // annotations footnotes separate.
719
      $annotations_and_sources['foot_note_keys'] = theme('cdm_annotations_as_footnotekeys',
720
        array(
721
          'cdmBase_list' => $element,
722
          'footnote_list_key' => $footnote_list_key_suggestion,
723
        )
724
      );
725

    
726
    } // END of references inline
727

    
728
    if (!$feature_block_settings['sources_as_content'] || $feature_block_settings['sources_as_content_to_bibliography']) {
729
      $annotations_and_sources['foot_note_keys'] = cdm_create_description_element_footnotes($element, ',', $footnote_list_key_suggestion);
730
    }
731

    
732
    return $annotations_and_sources;
733
  }
734

    
735
  /* compose nameInSource or originalNameString as markup
736
   *
737
   * @param $source
738
   * @param $do_link_to_name_used_in_source
739
   *
740
   * @return array
741
   *    A Drupal render array with an additional element, the render array is empty
742
   *    if the source had no name in source information
743
   *    - #_plaintext: contains the plaintext version of the name (custom element)
744
   *
745
   * @ingroup compose
746
   */
747
  function compose_name_in_source($source, $do_link_to_name_used_in_source) {
748

    
749
    $plaintext = NULL;
750
    $markup = NULL;
751
    $name_in_source_render_array = array();
752

    
753
    if (isset($source->nameUsedInSource->uuid) && isset($source->nameUsedInSource->titleCache)) {
754
      // it is a DescriptionElementSource !
755
      $plaintext = $source->nameUsedInSource->titleCache;
756
      $markup = theme('cdm_taxonName', array(
757
        'taxonName' => $source->nameUsedInSource
758
      ));
759
      if ($do_link_to_name_used_in_source) {
760
        $markup = l(
761
          $markup,
762
          path_to_name($source->nameUsedInSource->uuid),
763
          array(
764
            'attributes' => array(),
765
            'absolute' => TRUE,
766
            'html' => TRUE,
767
          ));
768
      }
769
    }
770
    else if (isset($source->originalNameString) && !empty($source->originalNameString)) {
771
      // the name used in source can not be expressed as valid taxon name,
772
      // so the editor has chosen to put the freetext name into ReferencedEntityBase.originalNameString
773
      // field
774
      // using the originalNameString as key to avoid duplicate entries
775
      $plaintext = $source->originalNameString;
776
      $markup = $source->originalNameString;
777
    }
778

    
779
    if ($plaintext) {
780
      $name_in_source_render_array = markup_to_render_array($markup);
781
      $name_in_source_render_array['#_plaintext'] = $plaintext;
782
    }
783

    
784
    return $name_in_source_render_array;
785
  }
786

    
787
  /**
788
 * Composes block of common names for the given DescriptionElements $elements which must be of the feature CommonName
789
 *
790
 * @parameter $elements
791
 *  an array of CDM DescriptionElements either of type CommonName or TextData
792
 * @parameter $feature
793
 *  the common feature of all $elements, must be CommonName
794
 *
795
 * @return
796
 *   A drupal render array
797
 *
798
 * @ingroup compose
799
 */
800
function compose_cdm_common_names($elements, $feature, $weight = FALSE) {
801

    
802
  $common_name_out = '';
803
  $common_name_feature_elements = array();
804
  $textData_commonNames = array();
805

    
806
  $footnote_key_suggestion = 'common-names-feature-block';
807

    
808
  $feature_block_settings = get_feature_block_settings(UUID_COMMON_NAME);
809

    
810
  $element_tag_name = cdm_feature_block_element_tag_name($feature_block_settings);
811

    
812
  if (is_array($elements)) {
813
    foreach ($elements as $element) {
814

    
815
      if ($element->class == 'CommonTaxonName') {
816

    
817
        // common name without a language or area, should not happen but is possible
818
        $language_area_key = '';
819
        if (isset($element->language->representation_L10n)) {
820
          $language_area_key .= '<b>' . $element->language->representation_L10n . '</b>';
821
        }
822
        if(isset($element->area->titleCache) && strlen($element->area->titleCache) > 0){
823
          $language_area_key .= ($language_area_key ? ' '  : '') . '(' . $element->area->titleCache . ')';
824
        }
825

    
826
        if(isset($common_names[$language_area_key][$element->name])) {
827
          // same name already exists for language and areae combination, se we merge the description elements
828
          cdm_merge_description_elements($common_names[$language_area_key][$element->name], $element);
829
        } else{
830
          // otherwise add as new entry
831
          $common_names[$language_area_key][$element->name] = $element;
832
        }
833

    
834
      }
835
      elseif ($element->class == 'TextData') {
836
        $textData_commonNames[] = $element;
837
      }
838
    }
839
  }
840
  // Handling common names.
841
  if (isset($common_names) && count($common_names) > 0) {
842
    // Sorting the array based on the key (language, + area if set).
843
    // Comment @WA there are common names without a language, so this sorting
844
    // can give strange results.
845
    ksort($common_names);
846

    
847
    // loop over set of elements per language area
848
    foreach ($common_names as $language_area_key => $elements) {
849
      ksort($elements); // sort names alphabetically
850
      $per_language_area_out = array();
851
      // loop over set of individual elements
852
      foreach ($elements as $element) {
853
        if ($element->name) {
854
          $annotations_and_sources = handle_annotations_and_sources($element, $feature_block_settings, $element->name, $footnote_key_suggestion);
855
          $source_references_markup = '';
856
          if(!empty($annotations_and_sources['source_references'])){
857
            $source_references_markup = ' ' . join(', ', $annotations_and_sources['source_references']);
858
          }
859
          $per_language_area_out[] = '<' . $element_tag_name. ' class="' . html_class_attribute_ref($element) . '">'
860
          . $element->name . $source_references_markup . $annotations_and_sources['foot_note_keys'] . '</' . $element_tag_name. '>';
861
        }
862
      } // End of loop over set of individual elements
863
      $common_name_feature_elements[] = ($language_area_key ? $language_area_key . ': ' : '' ) . join(', ', $per_language_area_out);
864
    } // End of loop over set of elements per language area
865

    
866

    
867
    $common_name_feature_elements_render_array = compose_cdm_feature_block_elements(
868
      $common_name_feature_elements,
869
      $feature,
870
      '; ',
871
      FALSE,
872
      $feature_block_settings['as_list']
873
      );
874
    $common_name_out .= $common_name_feature_elements_render_array['#markup'];
875

    
876
  }
877

    
878
  // Handling commons names as text data.
879
  $text_data_out = array();
880

    
881
  foreach ($textData_commonNames as $text_data_element) {
882
    /* footnotes are not handled correctly in theme_cdm_descriptionElementTextData,
883
       need to set 'common-names-feature-block' as $footnote_key_suggestion */
884
    RenderHints::setFootnoteListKey($footnote_key_suggestion);
885
    $text_data_render_array = compose_cdm_descriptionElementTextData($text_data_element, TRUE, $text_data_element->feature->uuid);
886
    $text_data_out[] = drupal_render($text_data_render_array);
887
  }
888

    
889
  $common_name_out_text_data = compose_cdm_feature_block_elements(
890
        $text_data_out,
891
        $feature
892
      );
893

    
894

    
895
  $footnotes = theme('cdm_footnotes', array('footnoteListKey' => $footnote_key_suggestion)); // FIXME is this needed at all?
896
  $footnotes .= theme('cdm_annotation_footnotes', array('footnoteListKey' => $footnote_key_suggestion));
897

    
898
  return  markup_to_render_array(
899
    '<div class="common_names_as_common_names">' . $common_name_out . '</div>'
900
    .'<div class="common_names_as_text_data">' . $common_name_out_text_data['#markup'] . '</div>'
901
    .$footnotes,
902
    $weight
903
  );
904
}
905

    
906
/**
907
 * Return HTML for a list of description elements.
908
 *
909
 * Usually these are of a specific feature type.
910
 *
911
 * @param $descriptionElements
912
 *   array of descriptionElements which belong to the same feature.
913
 *   These descriptions elements of a Description must be ordered by the chosen feature tree by
914
 *   calling the function _mergeFeatureTreeDescriptions().
915
 *   @see _mergeFeatureTreeDescriptions()
916
 *
917
 * @param  $feature_uuid
918
 *
919
 * @return
920
 *    A drupal render array for the $descriptionElements, may be an empty array if the textual content was empty.
921
 *    Footnote key or anchors are not considered to be textual content.
922
 *
923
 * @ingroup compose
924
 */
925
function compose_cdm_descriptionElements($descriptionElements, $feature) {
926

    
927
  $render_array = array();
928
  $elements_out_array = array();
929
  $distribution_tree = null;
930

    
931
  /*
932
   * $feature_block_has_content will be set true if at least one of the
933
   * $descriptionElements contains some text which makes up some content
934
   * for the feature block. Footnote keys are not considered
935
   * to be content in this sense.
936
   */
937
  $feature_block_has_content = false;
938

    
939
  /*
940
  $userDefined = mixed_variable_get(LAYOUT_SETTING_PREFIX . $feature_uuid, FEATURE_TREE_LAYOUT_DEFAULTS);
941
  if(variable_get('distribution_sort',
942
      'NO_SORT') != 'NO_SORT'){
943
      $glue = '';
944
      $enclosingTag = 'dl';
945
      $entryEnclosingTag = NULL;
946
  } else if($userDefined &&
947
      $userDefined['enabled']){
948
    $glue = $userDefined['glue'];
949
    $enclosingTag =  $userDefined['enclosingTag'];
950
    $entryEnclosingTag = $userDefined['entryEnclosingTag'];
951
  } else { // TODO remove once  LAYOUT_SETTING_PREFIX-{uuid} setting are configured to work for all portals(selenium test still missing!!!)
952
    $glue = ''; $enclosingTag = 'ul';
953
    $entryEnclosingTag = NULL ;
954
  }
955
  */
956

    
957
  RenderHints::pushToRenderStack('cdm_descriptionElements');
958

    
959
  if (is_array($descriptionElements)) {
960
    // --- normal description element arrays
961
    foreach ($descriptionElements as $descriptionElement) {
962

    
963
      // --- IMAGE_SOURCES --- //
964
      if ($descriptionElement->feature->uuid == UUID_IMAGE_SOURCES) {
965
        $image_sources[] = $descriptionElement;
966
      }
967
      // --- USE TEXTDATA --- //
968
      elseif ($descriptionElement->feature->uuid == UUID_USE) {
969
        // Do nothing to avoid rendering.
970
      } else {
971
        /* decide based on the description element class
972
         *
973
         * Features handled here:
974
         * all except DISTRIBUTION, COMMON_NAME, USES, IMAGES,
975
         *
976
         *
977
         * TODO provide api_hook as extension point for this?
978
         */
979
        $feature_block_settings = get_feature_block_settings($descriptionElement->feature->uuid);
980
        $asListElement  = $feature_block_settings['as_list'] == 'ul';
981
        switch ($descriptionElement->class) {
982
          case 'TextData':
983
              $text_data_render_array = compose_cdm_descriptionElementTextData($descriptionElement, $asListElement, $descriptionElement->feature->uuid);
984
              $feature_block_has_content = $feature_block_has_content || !empty($text_data_render_array['#value']);
985
              $elements_out_array[] = drupal_render($text_data_render_array);
986
            break;
987
          case 'CategoricalData':
988
            $feature_block_has_content = true;
989
            $elements_out_array[] = theme('cdm_descriptionElement_CategoricalData', array('element' => $descriptionElement));
990
            break;
991
          case 'QuantitativeData':
992
            $feature_block_has_content = true;
993
            $elements_out_array[] = theme('cdm_descriptionElement_QuantitativeData', array('element' => $descriptionElement));
994
            break;
995
          case 'IndividualsAssociation':
996
            $feature_block_has_content = true;
997
            $elements_out_array[] = theme('cdm_descriptionElement_IndividualsAssociation', array('element' => $descriptionElement));
998
            break;
999
          case 'TaxonInteraction':
1000
            $feature_block_has_content = true;
1001
            $elements_out_array[] = theme('cdm_descriptionElement_TaxonInteraction', array('element' => $descriptionElement));
1002
            break;
1003
          case 'Uses':
1004
          /* IGNORE Uses classes, these are handled completely in theme_cdm_UseDescription */
1005
          break;
1006
        default:
1007
          $feature_block_has_content = true;
1008
          $elements_out_array[] = '<li>No method for rendering unknown description class: ' . $descriptionElement->class . '</li>';
1009
      }
1010
    }
1011
    } // --- END loop over normal description element arrays
1012

    
1013
    // If feature = CITATION sort the list of sources.
1014
    // This is ONLY for FLORA MALESIANA and FLORE d'AFRIQUE CENTRALE.
1015
    if ($descriptionElement->feature->uuid == UUID_CITATION) {
1016
      sort($elements_out_array);
1017
    }
1018

    
1019
    if (isset($image_sources)) {
1020
      $elements_out_array[] = theme('cdm_description_element_image_source', array('image_sources' => $image_sources, 'asListElement' => TRUE));
1021
    }
1022
  } // END normal description element arrays
1023

    
1024
  if($feature_block_has_content){
1025
    $render_array = compose_cdm_feature_block_elements(
1026
      $elements_out_array,
1027
      $feature
1028
    );
1029
  }
1030

    
1031
  RenderHints::popFromRenderStack();
1032
  return $render_array;
1033
}
1034

    
1035
/**
1036
 * @todo Please document this function.
1037
 * @see http://drupal.org/node/1354
1038
 */
1039
function compare_image_sources($a, $b) {
1040
  if ($a->multilanguageText_L10n->text == $b->multilanguageText_L10n->text) {
1041
    return 0;
1042
  }
1043
  return ($a->multilanguageText_L10n->text < $b->multilanguageText_L10n->text) ? -1 : 1;
1044
}
1045

    
1046
/**
1047
 * @todo Please document this function.
1048
 * @see http://drupal.org/node/1354
1049
 */
1050
function theme_cdm_description_element_image_source($variables) {
1051
  $image_sources = $variables['image_sources'];
1052
  $asListElement = $variables['asListElement'];
1053
  $out = '';
1054
  $separator = ',';
1055
  RenderHints::pushToRenderStack('descriptionElementImageSource');
1056
  RenderHints::setFootnoteListKey(UUID_IMAGE_SOURCES);
1057

    
1058
  // Sorting the image sources.
1059
  usort($image_sources, "compare_image_sources");
1060
  // Generate the footnotes.
1061
  foreach ($image_sources as $image_source) {
1062
    $footNoteKeys = cdm_annotations_as_footnotekeys($image_source);
1063
    foreach ($image_source->sources as $source) {
1064
      if (_is_original_source_type($source)) {
1065
        $fn_key = FootnoteManager::addNewFootnote(original_source_footnote_list_key(), theme('cdm_OriginalSource', array(
1066
          'source' => $source,
1067
          'doLink' => FALSE,
1068
        )));
1069
        // Ensure uniqueness of the footnote keys.
1070
        cdm_add_footnote_to_array($footNoteKeys, $fn_key);
1071
      }
1072
    }
1073
    // Sort and render footnote keys.
1074
    $footnote_key_list_str = '';
1075
    asort($footNoteKeys);
1076
    foreach ($footNoteKeys as $footNoteKey) {
1077
      $footnote_key_list_str .= theme('cdm_footnote_key', array('footnoteKey' => $footNoteKey, 'separator' => ($footnote_key_list_str ? $separator : '')));
1078
    }
1079
    // Return value!
1080
    $out .= '<span class="descriptionElement descriptionElement-' . $image_source->uuid . '">' . $image_source->multilanguageText_L10n->text . $footnote_key_list_str . '; </span>';
1081
  }
1082

    
1083
  RenderHints::popFromRenderStack();
1084
  return $out;
1085
}
1086

    
1087
/**
1088
 * Composes the render array for a CDM Distribution element
1089
 *
1090
 * @param $descriptionElements
1091
 *   The CDM Distribution element
1092
 * @param $enclosingTag
1093
 *   The html tag to be use for the enclosing element
1094
 *
1095
 * @return array
1096
 *   A Drupal render array
1097
 *
1098
 * @ingroup compose
1099
 */
1100
function compose_cdm_descriptionElement_Distribution($descriptionElements, $enclosingTag = "span"){
1101

    
1102
  $out = '';
1103
  RenderHints::pushToRenderStack('descriptionElementDistribution');
1104
  RenderHints::setFootnoteListKey(UUID_DISTRIBUTION);
1105

    
1106
  $feature_block_settings = get_feature_block_settings(UUID_DISTRIBUTION);
1107

    
1108
  foreach ($descriptionElements as $descriptionElement) {
1109
    $annotations_and_sources = handle_annotations_and_sources(
1110
      $descriptionElement,
1111
      $feature_block_settings,
1112
      $descriptionElement->area->representation_L10n,
1113
      UUID_DISTRIBUTION
1114
    );
1115

    
1116

    
1117

    
1118
    $out .= '<' . $enclosingTag . ' class="descriptionElement descriptionElement-' . $descriptionElement->uuid . '">'
1119
        . $descriptionElement->area->representation_L10n;
1120
    if(!empty($annotations_and_sources['source_references'])){
1121
      $out .= ' ' . join(' ', $annotations_and_sources['source_references'] );
1122
    }
1123
    $out .= $annotations_and_sources['foot_note_keys']   . ' </' . $enclosingTag . '>';
1124
  }
1125

    
1126
  RenderHints::popFromRenderStack();
1127
  return markup_to_render_array($out);
1128
}
1129

    
1130

    
1131
/**
1132
 * Compare two different footnotes objects.
1133
 *
1134
 * The comparison is based on the footnote key. The one which is
1135
 * displayed as footnote number.
1136
 *
1137
 * @param mixed $a
1138
 *   Footnote object $a.
1139
 * @param mixed $b
1140
 *   Footnote object $b.
1141
 */
1142
function footnotes_key_compare($a, $b) {
1143
  $res = 0;
1144
  if (empty($a) || empty($b)) {
1145
    return $res;
1146
  }
1147
  if ($a->keyStr < $b->keyStr) {
1148
    $res = -1;
1149
  }
1150
  elseif ($a->keyStr > $b->keyStr) {
1151
    $res = 1;
1152
  }
1153
  return $res;
1154
}
1155

    
1156
/**
1157
 * @todo Please document this function.
1158
 * @see http://drupal.org/node/1354
1159
 */
1160
function theme_cdm_description_ordered_distributions($variables) {
1161

    
1162
  $distribution_tree = $variables['distribution_tree'];
1163

    
1164
  // Returning NULL if there are no description elements.
1165
  if ($distribution_tree == null) {
1166
    return NULL;
1167
  }
1168

    
1169
  // Initialization of some variables.
1170
  $out = '';
1171
  $separator = ',';
1172
  RenderHints::pushToRenderStack('descriptionElementDistribution');
1173
  RenderHints::setFootnoteListKey(UUID_DISTRIBUTION);
1174

    
1175
  $ordered_areas = $distribution_tree;
1176
  if (isset($ordered_areas->rootElement->children)) {
1177
    $ordered_areas = $ordered_areas->rootElement->children;
1178
  }
1179

    
1180
  // Printing the distributions.
1181
  if (is_array($ordered_areas) && count($ordered_areas) > 0) {
1182
    foreach ($ordered_areas as $element_level1) {
1183
      // Level1.
1184
      $out .= '<dt>' . $element_level1->nodeId->representation_L10n . ':</dt> ';
1185
      $out .= '<dd>';
1186

    
1187
      // Level3.
1188
      foreach ($element_level1->children as $element_level3) {
1189
        $text_l3 = $element_level3->nodeId->representation_L10n;
1190
        $fnKeysLevel3Str = '';
1191
        $fnKeysLevel3 = cdm_annotations_as_footnotekeys($element_level3->data);
1192
        if (isset($element_level3->data[0])) {
1193
          foreach ($element_level3->data as $description_level3){
1194
            foreach ($description_level3->sources as $source) {
1195
              if (_is_original_source_type($source)) {
1196
                $fn_key3 = FootnoteManager::addNewFootnote(
1197
                  original_source_footnote_list_key(),
1198
                  theme('cdm_OriginalSource', array('source' => $source, 'doLink' => FALSE)
1199
                ));
1200
                cdm_add_footnote_to_array($fnKeysLevel3, $fn_key3);
1201
              }
1202
            }
1203
          }
1204
        }
1205
        // Level4.
1206
        $l4_regions = array();
1207
        foreach ($element_level3->children as $element_level4) {
1208
          if (isset($element_level4->data[0])) {
1209
            $text_l4 = $element_level4->nodeId->representation_L10n;
1210
            $l4_regions[$element_level3->nodeId->representation_L10n] = array();
1211
            $fnKeysLevel4Str = '';
1212
            foreach($element_level4->data as $description_level4) {
1213
              $fnKeysLevel4 = cdm_annotations_as_footnotekeys($description_level4);
1214
              foreach ($description_level4->sources as $source) {
1215
                if (_is_original_source_type($source)) {
1216
                  $fn_key4 = FootnoteManager::addNewFootnote(
1217
                      original_source_footnote_list_key(),
1218
                      theme('cdm_OriginalSource', array('source' => $source, 'doLink' => FALSE)));
1219
                  cdm_add_footnote_to_array($fnKeysLevel4, $fn_key4);
1220
                }
1221
              }
1222
              usort($fnKeysLevel4, "footnotes_key_compare");
1223
              if(!isset( $l4_regions[$text_l4])){
1224
                $l4_regions[$text_l4] = $fnKeysLevel4;
1225
              } else {
1226
                $l4_regions[$text_l4] = array_merge($l4_regions[$text_l4], $fnKeysLevel4);
1227
              }
1228
            }
1229
          }
1230
        }// Level4.
1231
        // Managing level3 and level4 for generating the right output.
1232
        usort($fnKeysLevel3, "footnotes_key_compare");
1233
        foreach ($fnKeysLevel3 as $key3) {
1234
          foreach ($l4_regions as $key4 => $value4) {
1235
            cdm_add_footnote_to_array($l4_regions[$key4], $key3);
1236
          }
1237
        }
1238
        if ($element_level3->numberOfChildren == 1 && $text_l3 == $element_level3->children[0]->nodeId->representation_L10n) {
1239
          // var_dump($element_level3->children[0]->data->area->representation_L10n);
1240
          $fnStr = '';
1241
          $region = array_pop($l4_regions);
1242
          foreach ($region as $key) {
1243
            $fnStr .= theme('cdm_footnote_key', array('footnoteKey' => $key, 'separator' => ($fnStr ? $separator : '')));
1244
          }
1245
          $out .= "$text_l3 $fnStr; ";
1246
          // Removing whitespaces when &fnStr is empty.
1247
          if (substr($out, -3) == ' ; ') {
1248
            $out = substr($out, 0, -3) . '; ';
1249
          }
1250
        } else {
1251
          $fnKeysLevel3Str = '';
1252
          foreach ($fnKeysLevel3 as $key) {
1253
            $fnKeysLevel3Str .= theme('cdm_footnote_key', array('footnoteKey' => $key, 'separator' => ($fnKeysLevel3Str ? $separator : '')));
1254
          }
1255
          $text_l4_aux = '';
1256
          foreach ($l4_regions as $key => $value) {
1257
            $fnKeysLevel4Str = '';
1258
            if (is_array($l4_regions[$key])) {
1259
              foreach ($l4_regions[$key] as $fnkey) {
1260
                $fnKeysLevel4Str .= theme('cdm_footnote_key', array('footnoteKey' => $fnkey, 'separator' => ($fnKeysLevel4Str ? $separator : '')));
1261
              }
1262
            }
1263
            // if ($key != $text_l3 || sizeof($l4_regions > 1)){
1264
            if ($key != $text_l3) {
1265
              $text_l4_aux .= "$key $fnKeysLevel4Str, ";
1266
            }
1267
          }
1268
          $text_l4_aux = substr($text_l4_aux, 0, -2);
1269

    
1270
          if (strlen($text_l4_aux) > 0) {
1271
            $out .= "$text_l3 $fnKeysLevel3Str ($text_l4_aux); ";
1272
          }
1273
          else {
1274
            $out .= "$text_l3 $fnKeysLevel3Str; ";
1275
          }
1276
        }
1277
      }// Level3.
1278
      $out = substr($out, 0, -2);
1279
      $out .= '.</dd>';
1280
    }// Level1.
1281
  }
1282
  RenderHints::popFromRenderStack();
1283
  return $out;
1284
}
1285

    
1286
/**
1287
 * Returns a list of a specific type of IdentificationKeys.
1288
 *
1289
 * The list can be restricteded by a taxon.
1290
 *
1291
 * @param string $type
1292
 *   The simple name of the cdm class implementing the interface
1293
 *   IdentificationKey, valid values are:
1294
 *   PolytomousKey, MediaKey, MultiAccessKey.
1295
 * @param string $taxonUuid
1296
 *   If given this parameter restrict the listed keys to those which have
1297
 *   the taxon identified be this uuid in scope.
1298
 *
1299
 * @return array
1300
 *   List with identification keys.
1301
 */
1302
function _list_IdentificationKeys($type, $taxonUuid = NULL, $pageSize = NULL, $pageNumber = NULL) {
1303
  if (!$type) {
1304
    drupal_set_message(t('Type parameter is missing'), 'error');
1305
    return;
1306
  }
1307
  $cdm_ws_pasepath = NULL;
1308
  switch ($type) {
1309
    case "PolytomousKey":
1310
      $cdm_ws_pasepath = CDM_WS_POLYTOMOUSKEY;
1311
      break;
1312

    
1313
    case "MediaKey":
1314
      $cdm_ws_pasepath = CDM_WS_MEDIAKEY;
1315
      break;
1316

    
1317
    case "MultiAccessKey":
1318
      $cdm_ws_pasepath = CDM_WS_MULTIACCESSKEY;
1319
      break;
1320

    
1321
  }
1322

    
1323
  if (!$cdm_ws_pasepath) {
1324
    drupal_set_message(t('Type parameter is not valid: ') . $type, 'error');
1325
  }
1326

    
1327
  $queryParameters = '';
1328
  if (is_numeric($pageSize)) {
1329
    $queryParameters = "pageSize=" . $pageSize;
1330
  }
1331
  else {
1332
    $queryParameters = "pageSize=0";
1333
  }
1334

    
1335
  if (is_numeric($pageNumber)) {
1336
    $queryParameters = "pageNumber=" . $pageNumber;
1337
  }
1338
  else {
1339
    $queryParameters = "pageNumber=0";
1340
  }
1341
  $queryParameters = NULL;
1342
  if ($taxonUuid) {
1343
    $queryParameters = "findByTaxonomicScope=$taxonUuid";
1344
  }
1345
  $pager = cdm_ws_get($cdm_ws_pasepath, NULL, $queryParameters);
1346

    
1347
  if (!$pager || $pager->count == 0) {
1348
    return array();
1349
  }
1350
  return $pager->records;
1351
}
1352

    
1353
/**
1354
 * @todo Please document this function.
1355
 * @see http://drupal.org/node/1354
1356
 */
1357
function theme_cdm_IdentificationKey($variables) {
1358
  $out = '';
1359
  $identificationKey = $variables['identificationKey'];
1360
  $doLinkToKeyPage = $variables['doLinkToKeyPage'];
1361
  $showIdentificationKeyTitle = $variables['showIdentificationKeyTitle'];
1362
  $parentRenderPath = RenderHints::getRenderPath();
1363
  RenderHints::pushToRenderStack("IdentificationKey");
1364

    
1365
  if ($showIdentificationKeyTitle) {
1366
    if ($doLinkToKeyPage) {
1367
      $out = l($identificationKey->titleCache, path_to_key($identificationKey->class, $identificationKey->uuid));
1368
    }
1369
    else {
1370
      $out = $identificationKey->titleCache;
1371
    }
1372
  }
1373
  if (isset($identificationKey->sources) && is_array($identificationKey->sources)) {
1374
    // order and display sources.
1375
    $sources = oder_sources($identificationKey->sources, TRUE);
1376
    $out .= '<div class="sources">';
1377
    $out .=  implode('', $sources);
1378
    $out .= '</div>';
1379
  }
1380
  // Display annotations.
1381
  $out .= theme('cdm_annotations', array('annotations' => cdm_ws_getAnnotationsFor($identificationKey), 'enclosingTag' => 'div'));
1382
  RenderHints::popFromRenderStack();
1383
  return $out;
1384
}
1385

    
1386
/**
1387
 * @todo Please document this function.
1388
 * @see http://drupal.org/node/1354
1389
 */
1390
function theme_cdm_polytomousKey($variables) {
1391
  $polytomousKey = $variables['polytomousKey'];
1392

    
1393
  // TODO settings needed.
1394
  // @see http://en.wikipedia.org/wiki/Single_access_key#Presentation_styles
1395
  // @see http://dev.e-taxonomy.eu/trac/ticket/2152
1396
  $keyStyle = "linkedStyle";
1397

    
1398
  RenderHints::pushToRenderStack("polytomousKey");
1399
  // Key nodes in linked style.
1400
  $out = '<table class="polytomousKey polytomousKey_' . $keyStyle . '">';
1401
  $out .= theme('cdm_polytomousKey_' . $keyStyle . '_subgraph', array('polytomousKeyNode' => $polytomousKey->root));
1402
  $out .= '</table>';
1403
  RenderHints::popFromRenderStack();
1404
  return $out;
1405
}
1406

    
1407
/**
1408
 * @todo Please document this function.
1409
 * @see http://drupal.org/node/1354
1410
 */
1411
function theme_cdm_polytomousKey_linkedStyle_subgraph($variables) {
1412
  $polytomousKeyNode = $variables['polytomousKeyNode'];
1413
  static $statementCountCharacter = '\'';
1414
  $out = "";
1415

    
1416
  if (is_array($polytomousKeyNode->children)) {
1417
    $childIndex = 0;
1418

    
1419
    // Render edges of the current node.
1420
    foreach ($polytomousKeyNode->children as &$child) {
1421

    
1422
      if (!isset($child->statement) && isset($child->taxon->uuid)) {
1423
        // Skip node with empty statements (see below for explanation: "Special
1424
        // case").
1425
        // this skipping here happens always in the next deeper level of iteration
1426
        // the check below is node on the level above
1427
        continue;
1428
      }
1429

    
1430
      /*
1431
       * Special case: Child nodes with empty statements but taxa as leaf are to
1432
       * treated as if all those taxa where direct children of the source node.
1433
       */
1434
      $islinkToManyTaxa = !isset($child->children[0]->statement) && isset($child->children[0]->taxon->uuid);
1435
      $islinkToTaxon = isset($child->taxon->uuid);
1436
      $islinkToSubKey = isset($child->subkey->uuid);
1437
      $islinkToOtherNode = isset($child->otherNode);
1438
      // Either NULL or 0.
1439
      $islinkToNode = $child->nodeNumber && !$islinkToManyTaxa && !$islinkToOtherNode;
1440
      $hasQuestion = !empty($polytomousKeyNode->question->label_l10n);
1441
      $hasFeature = isset($polytomousKeyNode->feature);
1442

    
1443
      // $indentEdge = $hasQuestion && $childIndex > 0;
1444
      // Question.
1445
      if ($hasQuestion && $childIndex == 0) {
1446
        // Place question, as extra table row.
1447
        $out .= '<tr class="question new_section">';
1448
        $out .= '<td class="nodeNumber">' . uuid_anchor($polytomousKeyNode->uuid, $polytomousKeyNode->nodeNumber) . "</td>";
1449
        $out .= '<td class="question">' . $polytomousKeyNode->question->label_l10n . '</td>';
1450
        $out .= '</tr>';
1451
      }
1452

    
1453
      $out .= '<tr class="childCount_' . $childIndex . (!$hasQuestion && $childIndex == 0 ? ' new_section' : '') . '">';
1454

    
1455
      if ($hasQuestion) {
1456
        $out .= '<td class="nodeNumber"></td>';
1457
      }
1458
      else {
1459
        $out .= '<td class="nodeNumber">' . uuid_anchor($polytomousKeyNode->uuid, $polytomousKeyNode->nodeNumber . str_pad("", $childIndex, $statementCountCharacter)) . "</td>";
1460
      }
1461

    
1462
      $out .= '<td ' . RenderHints::getHtmlElementID($child) . '  class="edge' . ($hasQuestion ? ' edge-indent' : '') . '">';
1463

    
1464
      // Feature.
1465
      if ($hasFeature) {
1466
        $out .= $polytomousKeyNode->feature->representation_L10n . ": ";
1467
      }
1468

    
1469
      // Statement.
1470
      $out .= $child->statement->label_l10n;
1471

    
1472
      // --- Links to nodes taxa and subkeys.
1473
      $out .= '<div class="nodeLink">';
1474

    
1475
      // Link to a PolytomousKeyNode.
1476
      if ($islinkToNode) {
1477
        $out .= '<div class="nodeLinkToNode">';
1478
        if (isset($child->modifyingText)) {
1479
          $out .= theme('cdm_poytomousKeyNode_modifyingText', array('modifyingText' => $child->modifyingText));
1480
        }
1481
        $out .= l($child->nodeNumber, request_path(), array(
1482
          'attributes' => NULL,
1483
          'query' => NULL,
1484
          'fragment' => $child->uuid,
1485
        )) . '</div>';
1486
      }
1487

    
1488
      // Link to a PolytomousKeyNode.
1489
      if ($islinkToOtherNode) {
1490
        $out .= '<div class="nodeLinkToOtherNode">';
1491
        if (isset($child->modifyingText)) {
1492
          $out .= theme('cdm_poytomousKeyNode_modifyingText', array('modifyingText' => $child->modifyingText));
1493
        }
1494
        $out .= l($child->otherNode->nodeNumber, $_REQUEST["q"], array(
1495
          'attributes' => NULL,
1496
          'query' => NULL,
1497
          'fragment' => $child->otherNode->uuid,
1498
        )) . '</div>';
1499
      }
1500

    
1501
      // Link to one or many taxa.
1502
      if ($islinkToTaxon || $islinkToManyTaxa) {
1503

    
1504
        if ($islinkToManyTaxa) {
1505
          $taxonChildren = $child->children;
1506
        }
1507
        else {
1508
          $taxonChildren = array(
1509
            $child,
1510
          );
1511
        }
1512

    
1513
        foreach ($taxonChildren as $taxonChild) {
1514
          // TODO many taxa $child->children->taxon.
1515
          $out .= '<div class="nodeLinkToTaxon">';
1516
          if (isset($taxonChild->modifyingText)) {
1517
            $out .= theme('cdm_poytomousKeyNode_modifyingText', array('modifyingText' => $taxonChild->modifyingText));
1518
          }
1519
          $out .= theme("cdm_taxonName", array('taxonName' => $taxonChild->taxon->name, 'nameLink' => url(path_to_taxon($taxonChild->taxon->uuid))));
1520
          $out .= '</div>';
1521
        }
1522

    
1523
        // Link to a subkey.
1524
        if ($islinkToSubKey) {
1525
          $out .= '<div class="nodeLinkToSubkey">' . theme('cdm_IdentificationKey', array('identificationKey' => $child->subkey)) . '</div>';
1526
        }
1527
      }
1528

    
1529
      $out .= '</div>'; // End node link.
1530
      $out .= '</td>'; // End edge.
1531
      $out .= '</tr>';
1532

    
1533
      $childIndex++;
1534
    }
1535

    
1536
    // Recurse into child nodes.
1537
    foreach ($polytomousKeyNode->children as &$child) {
1538
      $out .= theme('cdm_polytomousKey_linkedStyle_subgraph', array('polytomousKeyNode' => $child));
1539
    }
1540
  }
1541

    
1542
  return $out;
1543
}
1544

    
1545
/**
1546
 * @todo Please document this function.
1547
 * @see http://drupal.org/node/1354
1548
 */
1549
function theme_cdm_poytomousKeyNode_modifyingText($variables) {
1550
  $out = '';
1551
  $modifyingText = $variables['modifyingText'];
1552
  if (is_object($modifyingText)) {
1553
    $i = 0;
1554
    foreach (get_object_vars($modifyingText) as $lang => $languageString) {
1555
      $out .= ($i++ > 0 ? ', ' : '') . '<span class="modifyingText">' . $languageString->text . '</span> ';
1556
    }
1557
  }
1558
  return $out;
1559
}
1560

    
1561
/**
1562
 * Returns HTML for a list of a specific type of IdentificationKeys.
1563
 *
1564
 * The list can be restricteded by a taxon.
1565
 *
1566
 * @param array $variables
1567
 *   An associative array containing:
1568
 *   - type: The simple name of the cdm class implementing the interface
1569
 *     IdentificationKey, valid values are:
1570
 *     PolytomousKey, MediaKey, MultiAccessKey
1571
 *   - taxonUuid: If given, this parameter restrict the listed keys to those
1572
 *     which have the taxon identified be this uuid in scope.
1573
 *
1574
 * @ingroup themeable
1575
 */
1576
function theme_cdm_list_IdentificationKeys($variables) {
1577
  $type = $variables['type'];
1578
  $taxonUuid = $variables['taxonUuid'];
1579
  $keyList = _list_IdentificationKeys($type, $taxonUuid);
1580
  if (!$keyList || count($keyList) == 0) {
1581
    return;
1582
  }
1583

    
1584
  RenderHints::pushToRenderStack('list_IdentificationKeys');
1585
  $out = '<ul>';
1586
  foreach ($keyList as $key) {
1587
    $out .= '<li>';
1588
    $out .= theme('cdm_IdentificationKey', array('identificationKey' => $key));
1589
    $out .= '</li>';
1590
  }
1591
  $out .= '</ul>';
1592
  $out .= theme("cdm_annotation_footnotes", array('footnoteListKey' => RenderHints::getRenderPath()));
1593
  RenderHints::popFromRenderStack();
1594

    
1595
  return $out;
1596
}
1597

    
1598
/**
1599
 * @todo Please document this function.
1600
 * @see http://drupal.org/node/1354
1601
 */
1602
function theme_cdm_block_IdentificationKeys($variables) {
1603
  $taxonUuid = $variables['taxonUuid'];
1604
  static $types = array(
1605
    "PolytomousKey" => "Polytomous",
1606
    "MediaKey" => "Media",
1607
    "MultiAccessKey" => "Multiaccess",
1608
  );
1609
  RenderHints::pushToRenderStack('block_IdentificationKeys');
1610
  $out = '';
1611
  foreach ($types as $type => $label) {
1612
    $keylist = theme('cdm_list_IdentificationKeys', array('type' => $type, 'taxonUuid' => $taxonUuid));
1613
    if (!$keylist) {
1614
      continue;
1615
    }
1616
    $out .= '<div class="' . $type . '">';
1617
    $out .= '<h3>' . t($label) . "</h3>";
1618
    $out .= $keylist;
1619
    $out .= '</div>';
1620
  }
1621
  RenderHints::popFromRenderStack();
1622
  return $out;
1623
}
1624

    
1625
/**
1626
 * This theming function formats the use description and use record list for
1627
 * these descriptions.
1628
 *
1629
 * @see http://drupal.org/node/1354
1630
 */
1631
function theme_cdm_UseDescription($variables) {
1632
  $descriptions = $variables['description'];
1633
  $taxonUuid = $variables['taxonUuid'];
1634
  $out = '<div id="content"><ul id="Description" class ="description">';
1635
  if ($descriptions == NULL) {
1636
    return;
1637
  }
1638
  $descriptionSynonyms = '';
1639
  $descriptionOut = '';
1640
  $synonymOut = '';
1641
  $currentTaxon = cdm_ws_get(CDM_WS_PORTAL_TAXON, $taxonUuid);
1642

    
1643
  foreach ($descriptions as $description) {
1644
    $useSummary = '';
1645
    foreach ($description->elements as $element) {
1646

    
1647
      if ($element->feature->uuid == UUID_USE && !(strlen($useSummary) > 0) && isset($element->multilanguageText_L10n)) {
1648
        $useSummary = $element->multilanguageText_L10n->text;
1649
      }
1650
    }
1651
    // uses will be ordered by source
1652
    foreach ($description->sources as $source) {
1653
      $is_about_current_taxon = FALSE;
1654
      $originalTaxonUsedInSource = NULL;
1655
      $originalTaxonPager = NULL;
1656
      if ($source->originalNameString) {
1657
        $request_params = array();
1658
        $request_params['query'] = $source->originalNameString;
1659
        $request_params['matchMode'] = "EXACT";
1660
        $originalTaxonPager = cdm_ws_get(CDM_WS_PORTAL_NAME_FINDBYNAME, NULL, queryString($request_params));
1661
        if ($originalTaxonPager->count > 0) {
1662
          $originalTaxonUsedInSource = $originalTaxonPager->records[0];
1663
        }
1664
        else {
1665
          $originalTaxonUsedInSource = $currentTaxon->name;
1666
        }
1667
      }
1668
      else {
1669
        $originalTaxonUsedInSource = $currentTaxon->name;
1670
      }
1671

    
1672
      $is_about_current_taxon = $currentTaxon->name->uuid == $originalTaxonUsedInSource->uuid;
1673

    
1674
      if (!$is_about_current_taxon) {
1675
        $descriptionOut .= '<li class="descriptionText DescriptionElement">';
1676
        $name_used_in_source_link_to_show_use = l($source->originalNameString, path_to_name($originalTaxonUsedInSource->uuid), array(
1677
          'absolute' => TRUE,
1678
          'html' => TRUE,
1679
        ));
1680
        $descriptionOut .= $name_used_in_source_link_to_show_use . ': ';
1681
        $descriptionOut .= $useSummary;
1682
        foreach ($description->sources as $source) {
1683
          $descriptionOut .= " (" . theme('cdm_OriginalSource', array('source' => $source, 'doLink' => TRUE)) . ")";
1684
        }
1685
        $hasUseRecords = FALSE;
1686
        $descriptionUseRecordOut = '<div id=useRecords><table><th>Use Category</th><th>Use Sub Category</th><th>Plant Part</th><th>Human Group</th><th>Ethnic Group</th><th>Country</th>';
1687
        foreach ($description->elements as $descriptionElement) {
1688
          if ($descriptionElement->feature->uuid == UUID_USE_RECORD) {
1689
            $hasUseRecords = TRUE;
1690
            // FIXME localization hardcoded to English
1691
            $useRecordTags = explode(';', $descriptionElement->modifyingText_l10n);
1692
            $descriptionUseRecordOut .= '<tr>';
1693
            $descriptionUseRecordOut .= '<td>' . $useRecordTags[0] . '</td>' . '<td>' . $useRecordTags[1] . '</td>' . '<td>' . $useRecordTags[3] . '</td>' . '<td>' . $useRecordTags[4] . '</td>' . '<td>' . $useRecordTags[5] . '</td>' . '<td>' . $useRecordTags[2] . '</td>';
1694
            $descriptionUseRecordOut .= '</tr>';
1695
          }
1696
        }
1697
        $descriptionUseRecordOut .= '</table></div>';
1698
        if ($hasUseRecords) {
1699
          $descriptionOut .= $descriptionUseRecordOut . '</li>';
1700
        }
1701
      }
1702
      else {
1703
        // TODO +/- duplicate of above, unify this code
1704
        $synonymOut .= '<li class="descriptionText DescriptionElement">';
1705
        $name_used_in_source_link_to_show_use = l($source->originalNameString, path_to_name($originalTaxonUsedInSource->uuid), array(
1706
          'absolute' => TRUE,
1707
          'html' => TRUE,
1708
        ));
1709

    
1710
        $synonymOut .= $name_used_in_source_link_to_show_use . ': ';
1711
        $synonymOut .= $useSummary;
1712
        foreach ($description->sources as $source) {
1713
          $synonymOut .= " (" . theme('cdm_OriginalSource', array('source' => $source, 'doLink' => TRUE)) . ")";
1714
        }
1715

    
1716
        $hasUseRecords = FALSE;
1717
        $useRecordTableOut = '<div id=useRecords><table><th>Use Category</th><th>Use Sub Category</th><th>Plant Part</th><th>Human Group</th><th>Ethnic Group</th><th>Country</th>';
1718
        foreach ($description->elements as $descriptionElement) {
1719
          if ($descriptionElement->feature->uuid == UUID_USE_RECORD) {
1720
            $hasUseRecords = TRUE;
1721
            $useRecordTags = explode(';', $descriptionElement->modifyingText_l10n);
1722
            $useRecordTableOut .= '<tr>';
1723
            $useRecordTableOut .= '<td>' . $useRecordTags[0] . '</td>' . '<td>' . $useRecordTags[1] . '</td>' . '<td>' . $useRecordTags[3] . '</td>' . '<td>' . $useRecordTags[4] . '</td>' . '<td>' . $useRecordTags[5] . '</td>' . '<td>' . $useRecordTags[2] . '</td>';
1724
            $useRecordTableOut .= '</tr>';
1725
          }
1726
        }
1727
        $useRecordTableOut .= '</table></div>';
1728
        if ($hasUseRecords) {
1729
          $synonymOut .= $useRecordTableOut . '</li>';
1730
        }
1731
      }
1732

    
1733
      // }
1734
    }
1735
  }
1736
  $out .= $descriptionOut . $synonymOut;
1737
  $out .= "</ul></div>";
1738
  return $out;
1739
}
1740

    
1741

    
1742
/**
1743
 * The theming function for a block of Uses Descriptions for a given taxon.
1744
 *
1745
 * The Uses block has been removed from the code but the according theme function
1746
 * is kept for compatibility reasons with existing code regarding palmweb.
1747
 *
1748
 */
1749
function theme_cdm_block_Uses($variables) {
1750
  $taxonUuid = $variables['taxonUuid'];
1751
  RenderHints::pushToRenderStack('block_Uses');
1752

    
1753
  if ($taxonUuid == NULL) {
1754
    return;
1755
  }
1756
  $out = '';
1757
  $markerTypes = array();
1758
  $markerTypes['markerTypes'] = UUID_MARKERTYPE_USE;
1759
  $useDescriptions = cdm_ws_get(CDM_WS_PORTAL_TAXON_DESCRIPTIONS, $taxonUuid, queryString($markerTypes));
1760
  if (!empty($useDescriptions)) {
1761
    // FIXME use theme_block instaed of hardcoding the block html here !!!!
1762
    $out .= '<div id="block-cdm_dataportal-feature-description" class="clear-block block block-cdm_dataportal-feature"><H2><a name="userecords"> </a> Uses </H2>';
1763
    $formatUseDescriptions = theme('cdm_UseDescription', array('description' => $useDescriptions, 'taxonUuid' => $taxonUuid));
1764

    
1765
    $out .= $formatUseDescriptions;
1766
    $out .= "</div>";
1767
  }
1768

    
1769
  return $out;
1770
}
(2-2/9)