Project

General

Profile

Download (34.7 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/**
3
 * @file
4
 * Name 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
 * Return HTML for the lectotype citation with the correct layout.
18
 *
19
 * This function prints the lectotype citation with the correct layout.
20
 * Lectotypes are renderized in the synonymy tab of a taxon if they exist.
21
 *
22
 * @param mixed $typeDesignation
23
 *   Object containing the lectotype citation to print.
24
 *
25
 * @return string
26
 *   Valid html string.
27
 */
28
function type_designation_citation_layout($typeDesignation, $footnote_separator = ',') {
29
  $res = '';
30
  $citation = $typeDesignation->citation;
31
  $pages = $typeDesignation->citationMicroReference;
32
  if(isset($typeDesignation->typeStatus->uuid) && isset($typeDesignation->typeStatus->representation_L10n)) {
33
    if ( $typeDesignation->typeStatus->uuid == UUID_NTD_ORIGINAL_DESIGNATION || $typeDesignation->typeStatus->uuid == UUID_NTD_MONOTYPY) {
34
      $res = ' (' . $typeDesignation->typeStatus->representation_L10n . ')';
35
      return $res;
36
    }
37
  }
38

    
39
  if ($citation) {
40
    // $type = $typeDesignation_citation->type;
41
    $year = isset($citation->datePublished->start) ? substr($citation->datePublished->start, 0, 4) : '';
42
    $author = isset($citation->authorTeam->titleCache) ? $citation->authorTeam->titleCache : '';
43
    $res .= ' (designated by ';
44
    $res .= $author;
45
    $res .= ($year ? ' ' . $year : '');
46
    $res .= ($pages ? ': ' . $pages : '');
47
    // $res .= ')';
48

    
49
    // footnotes should be rendered in the parent element so we
50
    // are relying on the FootnoteListKey set there
51
    $fkey_typeDesignation = FootnoteManager::addNewFootnote(RenderHints::getFootnoteListKey(), $typeDesignation->citation->titleCache);
52
    $res .= theme('cdm_footnote_key', array(
53
      'footnoteKey' => $fkey_typeDesignation,
54
      'separator' => $footnote_separator,
55
      'highlightable' => TRUE,
56
      'separator_off' => TRUE,
57
    )) . ')';
58
  }
59
  return $res;
60
}
61

    
62
/**
63
 * Searches the $collection for the cdm entitiy given as $element.
64
 *
65
 * The elements are compared by their UUID.
66
 *
67
 * @param $element
68
 *  the CDM entitiy to search for
69
 * @param $collection
70
 *  the list of CDM entities to search in
71
 *
72
 * @return boolean TRUE if the $collection contains the $element, otheriwse FALSE
73
 *
74
 * TODO move into module file
75
 */
76
function contains_cdm_entitiy($element, $collection) {
77
  $result = FALSE;
78
  foreach ($collection as $a) {
79
    if ($a->uuid == $element->uuid) {
80
      $result = TRUE;
81
    }
82
  }
83
  return $result;
84
}
85

    
86
/**
87
 * Fiters the array $entity_list of CDM entities by the list
88
 * of $excludes. Any element contained in the $excludes will be removed
89
 * from included int the retuned list.
90
 *
91
 * If the $entity_list is not an array the $excludes will be returned.
92
 */
93
function filter_cdm_entity_list($entity_list, $excludes) {
94
  if (is_array($entity_list)) {
95
    $result = $entity_list;
96
    if ($excludes) {
97
      foreach ($excludes as $exclude) {
98
        if (!contains_cdm_entitiy($exclude, $entity_list)) {
99
          $result[] = $exclude;
100
        }
101
      }
102
    }
103
  }
104
  else {
105
    $result = $excludes;
106
  }
107
  return $result;
108
}
109

    
110
/**
111
 * Renders and array of CDM TypeDesignations
112
 *
113
 * @param array $variables
114
 *   - typeDesignations: an array of cdm TypeDesignation entities to render
115
 */
116
function theme_cdm_typedesignations($variables) {
117
  $typeDesignations = $variables['typeDesignations'];
118

    
119
  // need to add element to render path since type designations
120
  // need other name render template
121
  RenderHints::pushToRenderStack('typedesignations');
122

    
123
  $out = '<ul class="typeDesignations">';
124
  $typeDesignation_footnotes = FALSE;
125
  $is_lectotype = FALSE;
126
  $specimenTypeDesignations = array();
127
  $separator = ',';
128
  foreach ($typeDesignations as $typeDesignation) {
129
    if ($typeDesignation->class == 'SpecimenTypeDesignation') {
130
      // SpecimenTypeDesignations should be ordered. Collect theme here only.
131
      $specimenTypeDesignations[] = $typeDesignation;
132
    }
133
    // It is a lectotype?
134
    else {
135
      if (isset($typeDesignation->typeStatus->uuid) && $typeDesignation->typeStatus->uuid == UUID_NTD_LECTOTYPE) {
136
        $is_lectotype = TRUE;
137
      }
138
      // It's a NameTypeDesignation.
139
      if ($typeDesignation->notDesignated) {
140
        $out .= '<li class="nameTypeDesignation"><span class="status">' . ($is_lectotype ? 'Lectotype' : 'Type') . '</span>: ' . t('not designated') . '</li>';
141
      }
142
      elseif ($typeDesignation->typeName) {
143
        $link_to_name_page = '?q=' . path_to_name($typeDesignation->typeName->uuid);
144
        $out .= '<li class="nameTypeDesignation"><span class="status">' . ($is_lectotype ? 'Lectotype' : 'Type') . '</span>';
145

    
146
        if ($typeDesignation->citation) {
147
          $out .= type_designation_citation_layout($typeDesignation, $separator);
148

    
149
        }
150
        $referenceUri = '';
151
        if (isset($typeDesignation->typeName->nomenclaturalReference)) {
152
          $referenceUri = url(path_to_reference($typeDesignation->typeName->nomenclaturalReference->uuid));
153
        }
154
        $out .= ': ' . theme('cdm_taxonName', array(
155
          'taxonName' => $typeDesignation->typeName,
156
          'nameLink' => $link_to_name_page,
157
          'refenceLink' => $referenceUri,
158
          'show_annotations' => TRUE,
159
          'is_type_designation' => TRUE,
160
          ));
161
      }
162
    }
163
  }
164

    
165
  if (!empty($specimenTypeDesignations)) {
166
    // Sorting might be different for dataportals so this has to be
167
    // parameterized.
168
    usort($specimenTypeDesignations, "compare_specimenTypeDesignationStatus");
169
    foreach ($specimenTypeDesignations as $std) {
170
      $typeReference = '';
171
      if (!empty($std->citation)) {
172
        $author_team = cdm_ws_get(CDM_WS_REFERENCE_AUTHORTEAM, $std->citation->uuid);
173
        $shortCitation = $author_team->titleCache;
174

    
175
        $shortCitation .= (strlen($shortCitation) > 0 ? ' ' : '') . partialToYear($std->citation->datePublished->start);
176
        $missingShortCitation = FALSE;
177
        if (strlen($shortCitation) == 0) {
178
          $shortCitation = theme('cdm_reference', array('reference' => $std->citation));
179
          $missingShortCitation = TRUE;
180
        }
181

    
182
        $typeReference .= '&nbsp;(' . t('designated by');
183
        $typeReference .= '&nbsp;<span class="typeReference ' . ($missingShortCitation ? '' : 'cluetip') . ' no-print" title="' . htmlspecialchars('|' . theme('cdm_reference', array('reference' => $std->citation)) . '|') . '">';
184
        $typeReference .= $shortCitation . '</span>';
185
        if (!empty($std->citationMicroReference)) {
186
          $typeReference .= ':' . $std->citationMicroReference;
187
        }
188
        $typeReference .= ')';
189

    
190
        // footnotes should be rendered in the parent element so we
191
        // are relying on the FootnoteListKey set there
192
        $_fkey2 = FootnoteManager::addNewFootnote(RenderHints::getFootnoteListKey(), $std->citation->titleCache);
193
        $typeReference .= theme('cdm_footnote_key', array(
194
          'footnoteKey' => $_fkey2,
195
          'separator' => $separator,
196
          'highlightable' => TRUE,
197
          'separator_off' => TRUE,
198
         ));
199
      }
200

    
201
      $derivedUnitFacadeInstance = null;
202

    
203
      $out .= '<li class="specimenTypeDesignation">';
204
      $out .= '<span class="status">'
205
        . ((isset($std->typeStatus->representation_L10n)) ? $std->typeStatus->representation_L10n : t('Type'))
206
        . $typeReference
207
        . '</span>: ';
208

    
209

    
210
      if (isset($std->typeSpecimen)) {
211
        $derivedUnitFacadeInstance = cdm_ws_get(CDM_WS_DERIVEDUNIT_FACADE, $std->typeSpecimen->uuid);
212
      }
213
      if ( isset($derivedUnitFacadeInstance ) ){
214
        $out .= $derivedUnitFacadeInstance->titleCache; // . ': ' . theme('cdm_specimen', array('specimenTypeDesignation' => $derivedUnitFacadeInstance));
215
      }
216

    
217
      // Footnotes for collection acronyms.
218
      // footnotes should be rendered in the parent element so we
219
      // are relying on the FootnoteListKey set there
220
      $_fkey = FootnoteManager::addNewFootnote(
221
          RenderHints::getFootnoteListKey(),
222
          (isset($derivedUnitFacadeInstance->collection->titleCache) ? $derivedUnitFacadeInstance->collection->titleCache : FALSE)
223
        );
224
      $out .= theme('cdm_footnote_key', array('footnoteKey' => $_fkey, 'separator' => $separator));
225
      $out .= '</li>';
226

    
227
    }
228
  }
229

    
230
  $out .= '</ul>';
231

    
232
  RenderHints::popFromRenderStack();
233

    
234
  return $out;
235
}
236

    
237
/**
238
 * FIXME this definitively has to be in another spot.
239
 * just didn't know where to put it right now.
240
 * Compares the status of two SpecimenTypeDesignations
241
 *
242
 * @param string $a
243
 *   A SpecimenTypeDesignations.
244
 * @param string $b
245
 *   SpecimenTypeDesignations.
246
 */
247
function compare_specimenTypeDesignationStatus($a, $b) {
248
  /*
249
  This is the desired sort order as of now: Holotype Isotype Lectotype
250
  Isolectotype Syntype.
251
  TODO Basically, what we are trying to do is, we define
252
  an ordered array of TypeDesignation-states and use the index of this array
253
  for comparison. This array has to be filled with the cdm- TypeDesignation
254
  states and the order should be parameterisable inside the dataportal.
255
  */
256
  // Make that static for now.
257
  $typeOrder = array(
258
    'Holotype',
259
    'Isotype',
260
    'Lectotype',
261
    'Isolectotype',
262
    'Syntype',
263
  );
264

    
265
  $aQuantifier = FALSE;
266
  $bQuantifier = FALSE;
267
  if (isset($a->typeStatus->label) && isset($b->typeStatus->label)) {
268
    $aQuantifier = array_search($a->typeStatus->label, $typeOrder);
269
    $bQuantifier = array_search($b->typeStatus->label, $typeOrder);
270
  }
271
  if ($aQuantifier == $bQuantifier) {
272
    // Sort alphabetically.
273
    return (isset($a->typeStatus->label) && isset($b->typeStatus->label) && $a->typeStatus->label < $b->typeStatus->label) ? -1 : 1;
274
  }
275
  return ($aQuantifier < $bQuantifier) ? -1 : 1;
276
}
277

    
278
/**
279
 * @todo Please document this function.
280
 * @see http://drupal.org/node/1354
281
 */
282
function theme_cdm_nameRelationships($variables) {
283
  $nameRelationships = $variables['nameRelationships'];
284
  $skipTypes = $variables['skipTypes'];
285
  if (!$nameRelationships) {
286
    return;
287
  }
288

    
289
  RenderHints::pushToRenderStack('nameRelationships');
290
  $footnoteListKey = 'nameRelationships';
291
  RenderHints::setFootnoteListKey($footnoteListKey);
292

    
293
  // Group by relationship type.
294
  $relationshipGroups = array();
295
  foreach ($nameRelationships as $nameRelationship) {
296
    if (!array_key_exists($nameRelationship->type->uuid, $relationshipGroups)) {
297
      $relationshipGroups[$nameRelationship->type->uuid] = array();
298
    }
299
    $relationshipGroups[$nameRelationship->type->uuid][] = $nameRelationship;
300
  }
301

    
302
  // Generate output.
303
  $out = '';
304
  $block = new stdclass(); // Empty object.
305
  foreach ($relationshipGroups as $group) {
306
    $type = $group[0]->type;
307

    
308
    if (is_array($skipTypes) && in_array($type->uuid, $skipTypes)) {
309
      continue;
310
    }
311

    
312
    $block->module = 'cdm_dataportal';
313
    $block->subject = t(ucfirst($type->inverseRepresentation_L10n));
314
    $block->delta = generalizeString(strtolower($type->inverseRepresentation_L10n));
315

    
316
    foreach ($group as $relationship) {
317
      $relatedNames[] = cdm_taggedtext2html($relationship->fromName->taggedName);
318
    }
319

    
320
    $block->content .= implode('; ', $relatedNames);
321
    $out .= theme('block', $block);
322
  }
323
  $out .= theme('cdm_footnotes', array('footnoteListKey' => $footnoteListKey, 'enclosingTag' => 'li'));
324

    
325
  RenderHints::popFromRenderStack();
326
  return $out;
327
}
328

    
329
/**
330
 * @todo Please document this function.
331
 * @see http://drupal.org/node/1354
332
 */
333
function theme_cdm_homotypicSynonymLine($variables) {
334
  $taxon = $variables['taxon'];
335
  $out = '';
336
  $out .= '<li class="synonym">' . cdm_related_taxon($taxon, UUID_HOMOTYPIC_SYNONYM_OF) . '</li>';
337

    
338
  return $out;
339
}
340

    
341
/**
342
 * @todo Please document this function.
343
 * @see http://drupal.org/node/1354
344
 */
345
function theme_cdm_heterotypicSynonymyGroup($variables) {
346
  $homotypicalGroup = $variables['homotypicalGroup'];
347
  RenderHints::pushToRenderStack('heterotypicSynonymyGroup');
348

    
349
  $out = '';
350
  $out = '<div class="heterotypic-synonymy-group"><ul class="heterotypicSynonymyGroup">';
351
  $footnoteListKey = (isset($homotypicalGroup[0]) ? $homotypicalGroup[0]->uuid : 'NULL');
352
  RenderHints::setFootnoteListKey($footnoteListKey);
353

    
354
  $is_first_entry = TRUE;
355
  $typeDesignations = NULL;
356
  foreach ($homotypicalGroup as $synonym) {
357
    if ($is_first_entry) {
358
      $is_first_entry = FALSE;
359
      $typeDesignations = cdm_ws_get(CDM_WS_PORTAL_NAME_TYPEDESIGNATIONS, $synonym->name->uuid);
360
      // Is first list entry.
361
      $out .= '<li class="firstentry synonym">' . cdm_related_taxon($synonym, UUID_HETEROTYPIC_SYNONYM_OF) . '</li>';
362
    }
363
    else {
364
      $out .= '<li class="synonym">' . cdm_related_taxon($synonym, UUID_HOMOTYPIC_SYNONYM_OF) . '</li>';
365
    }
366
  }
367

    
368
  if ($typeDesignations) {
369
    $out .= theme('cdm_typedesignations', array('typeDesignations' => $typeDesignations));
370
  }
371
  $out .= '</ul>';
372

    
373
  // ------- footnotes ------- //
374
  $out .= '<ul class="footnotes">';
375
  $out .= theme('cdm_annotation_footnotes', array('footnoteListKey' => RenderHints::getFootnoteListKey(), 'enclosingTag' => 'li'));
376
  $out .= theme('cdm_footnotes', array('footnoteListKey' => RenderHints::getFootnoteListKey(), 'enclosingTag' => 'li'));
377
  $out .= '</ul>';
378

    
379
  $out .= '</div>';
380

    
381
  RenderHints::popFromRenderStack();
382
  return $out;
383
}
384

    
385
/**
386
 * Renders the homotypic synonymy group for the accepted taxon in the synonymy.
387
 *
388
 * Foonotes of the accepted taxon will also be rendered here in the
389
 * homotypic synonymy group even if the synonymList or prependedSynonyms are
390
 * empty. Therefore  the homotypic group and accepted taxon share the  same
391
 * footnote key.
392
 *
393
 * @param $variables
394
 *   an associative array:
395
 *   - synonymList: the list of cdm Synonym entities
396
 *   - accepted_taxon_uuid: the uuid of the accepted taxon
397
 *   - prependedSynonyms: further synonyms which should be prepended
398
 *      before the actual list of synonyms
399
 */
400
function theme_cdm_homotypicSynonymyGroup($variables) {
401
  $synonymList = $variables['synonymList'];
402
  $accepted_taxon_uuid = $variables['accepted_taxon_uuid'];
403
  $prependedSynonyms = $variables['prependedSynonyms'];
404

    
405
  RenderHints::pushToRenderStack('homotypicSynonymyGroup');
406

    
407
  $homonym_typeDesignations = NULL;
408

    
409
// no new $footnoteListKey since homotypic group and accepted taxon should share the same key!
410
//   $footnoteListKey = isset($prependedSynonyms[0]) ? $prependedSynonyms[0]->uuid : (isset($synonymList[0]) ? $synonymList[0]->uuid : 'NULL');
411
//   // store the FootnoteListKey from the parent element which is the accepted taxon
412
//   $accepted_taxon_footnoteListKey = RenderHints::getFootnoteListKey();
413
//   // new FootnoteListKey for this homotypicSynonymyGroup
414
//   RenderHints::setFootnoteListKey($footnoteListKey);
415

    
416
  // TODO improve typeDesignations retrieval: wouldn't it be suffcient to retrieve all typeDesignations
417
  // only from the accepted taxon?
418
  $accepted_typeDesignations = cdm_ws_get(CDM_WS_PORTAL_TAXON_NAMETYPEDESIGNATIONS, $accepted_taxon_uuid);
419

    
420
  $out = '<div class="homotypic-synonymy-group">';
421

    
422
  if (isset ($accepted_typeDesignations) || is_array($prependedSynonyms) || is_array($synonymList)) {
423
  	$out .= '<ul class="homotypicSynonyms">';
424
	if (!empty($prependedSynonyms)) {
425
	  foreach ($prependedSynonyms as $taxon) {
426
	    $out .= '<li class="synonym">' . cdm_related_taxon($taxon, UUID_HOMOTYPIC_SYNONYM_OF) . '</li>';
427
	  }
428
	}
429

    
430
	$homonym_typeDesignations = NULL;
431
	if (isset($synonymList[0])) {
432
		foreach ($synonymList as $synonym) {
433
			$out .= '<li class="synonym">' . cdm_related_taxon($synonym, UUID_HOMOTYPIC_SYNONYM_OF) . '</li>';
434
		}
435
		$homonym_typeDesignations = cdm_ws_get(CDM_WS_PORTAL_NAME_TYPEDESIGNATIONS, $synonymList[0]->name->uuid);
436
	}
437

    
438
	// type designations
439
	if ($accepted_typeDesignations) {
440
	  $type_designations = filter_cdm_entity_list($homonym_typeDesignations, $accepted_typeDesignations);
441
	}
442
	else {
443
	  $type_designations = $homonym_typeDesignations;
444
	}
445
	if ($type_designations) {
446
	  $out .= theme('cdm_typedesignations', array('typeDesignations' => $type_designations));
447
	}
448

    
449
  }
450

    
451
  $out .= '</ul>';
452

    
453
  // ------- footnotes ------- //
454

    
455
  // all foonotes of the homotypic group and also of the accepted taxon are
456
  // rendered here, both should have the same footnote key
457
  $out .= '<ul class="footnotes">';
458
  $out .= theme('cdm_annotation_footnotes', array('footnoteListKey' => RenderHints::getFootnoteListKey(), 'enclosingTag' => 'li'));
459
  $out .= theme('cdm_footnotes', array('footnoteListKey' => RenderHints::getFootnoteListKey(), 'enclosingTag' => 'li'));
460
  $out .= '</ul>';
461

    
462
  $out .= '</div>';
463

    
464

    
465
  RenderHints::popFromRenderStack();
466
  return $out;
467
}
468

    
469
/**
470
 * Provides the name render template to be used within the page elements identified the the $renderPath.
471
 *
472
 * The render templates arrays contains one or more name render template to be used within the page elements identified the the
473
 * renderPath. The renderPath is the key of the subelements whereas the value is the name render template.
474
 * The following keys are curretly recogized:
475
 *
476
 *   - list_of_taxa:
477
 *   - acceptedFor:
478
 *   - taxon_page_synonymy
479
 *   - typedesignations
480
 *   - taxon_page_title
481
 *   - polytomousKey
482
 *   - na: name + authorship
483
 *   - nar:name + authorship + reference
484
 *   - #DEFAULT
485
 *
486
 * A single render template can be used for multiple render paths. In this case the according key of the render templates
487
 * array element should be the list of these render paths concatenated by ONLY a comma character without any whitespace.
488
 *
489
 * A render template is an associative array. The keys of this array are referring to the keys as defined in the part
490
 * definitions array.
491
 * @see get_partDefinition($taxonNameType) for more information
492
 *
493
 * The value of the render template element must be set to TRUE in order to let this part being rendered.
494
 * The namePart, nameAuthorPart and referencePart can also hold an associative array with a single
495
 * element: array('#uri' => TRUE). The value of the #uri element will be replaced by the according
496
 * links if the paramters $nameLink or $refenceLink are set.
497
 *
498
 * @param string $renderPath
499
 *   The render path can consist of multiple dot separated elements
500
 *   @see RenderHints::getRenderPath()
501
 * @param string $nameLink
502
 *   The link path ot URL to be used for name parts if a link is forseen in the template
503
 *   matching the given $renderPath.
504
 * @param string $referenceLink
505
 *   The link path ot URL to be used for nomencaltural reference parts if a link is forseen
506
 *   in the template matching the given $renderPath.
507
 * @return array
508
 *   An assciative array, the render template
509
 */
510
function get_nameRenderTemplate($renderPath, $nameLink = NULL, $refenceLink = NULL) {
511

    
512
  $template = NULL;
513

    
514
  static $default_render_templates = NULL;
515
  if (!isset($default_render_templates)) {
516
    $default_render_templates = unserialize(CDM_NAME_RENDER_TEMPLATES_DEFAULT);
517
  }
518

    
519
  // get the base element of the renderPath
520
  if (($separatorPos = strpos($renderPath, '.')) > 0) {
521
    $renderPath_base = substr($renderPath, 0, $separatorPos);
522
  } else {
523
    $renderPath_base = $renderPath;
524
  }
525

    
526
  // --- preliminar solution: using themes.
527
  $render_templates = theme('get_nameRenderTemplate', array());
528
  if (!isset($render_templates)) {
529
    // from the variables
530
    $render_templates = variable_get(CDM_NAME_RENDER_TEMPLATES, $default_render_templates);
531
  }
532

    
533
  // 1. try to find a template using the render path base element
534
  if(array_key_exists($renderPath_base, $render_templates)){
535
    $template = $render_templates[$renderPath_base];
536
  }
537

    
538
  // 2. Find best matching default RenderTemplate in theme
539
  // by stripping the dot separated render path element by element
540
  // is no matching template is found the DEFAULT will be used.
541
  while (!is_array($template) && strlen($renderPath) > 0) {
542

    
543
    foreach ($render_templates as $k => $t) {
544
      if (strpos(',' . $k . ',', $renderPath ) !== FALSE) {
545
        $template = $t;
546
        break;
547
      }
548
    }
549

    
550
    // shorten by one element
551
    $renderPath = substr($renderPath, 0, strrpos($renderPath, '.'));
552
    /*
553
    if(!is_array($template)){
554
      echo "<br/>->".$renderPath;
555
    }
556
    */
557
  }
558

    
559
  // 3. Otherwise get default RenderTemplate from theme.
560
  if (!is_array($template)) {
561
      $template = $render_templates['#DEFAULT'];
562
  }
563

    
564
  // --- set the link uris to the according template fields if they exist
565
  if ($nameLink && isset($template['nameAuthorPart']['#uri'])) {
566
    $template['nameAuthorPart']['#uri'] = $nameLink;
567
  }
568
  else {
569
    unset($template['nameAuthorPart']['#uri']);
570
  }
571

    
572
  if ($nameLink && isset($template['namePart']['#uri'])) {
573
    $template['namePart']['#uri'] = $nameLink;
574
  }
575
  else {
576
    unset($template['namePart']['#uri']);
577
  }
578

    
579
  if ($refenceLink && isset($template['referencePart']['#uri'])) {
580
    $template['referencePart']['#uri'] = $refenceLink;
581
  }
582
  else {
583
    unset($template['referencePart']['#uri']);
584
  }
585

    
586
  return $template;
587
}
588

    
589
/**
590
 * The part definitions define the specific parts of which a rendered taxon name plus additional information will consist.
591
 *
592
 * A full taxon name plus additional information can consist of the following elements:
593
 *
594
 *   - name: the taxon name inclugin rank nbut without author
595
 *   - authorTeam:  The authors of a reference, also used in taxon names
596
 *   - authors:  The authors of a reference, also used in taxon names
597
 *   - reference: the nomenclatural reference,
598
 *   - microreference:  Volume, page number etc.
599
 *   - status:  The nomenclatural status of a name
600
 *   - description: name descriptions like protologues etc ...
601
 *
602
 * These elements are combined in the part definitions array to from the specific parts to be rendered.
603
 * Usually the following parts are formed:
604
 *
605
 * The name "Lapsana communis L., Sp. Pl.: 811. 1753" shall be an example here:
606
 *  - namePart: the name and rank (in example: "Lapsana communis")
607
 *  - authorshipPart: the author (in example: "L.")
608
 *  - nameAuthorPart: the combination of name and author part (in example: "Lapsana communis L.").
609
 *     This is useful for zoological names where the authorshipPart belongs to the name and both should
610
 *     be combined when a link to the taxon is rendered.
611
 *  - referencePart: the nomencaltural reference (in example: "Sp. Pl. 1753")
612
 *  - microreferencePart: usually the page number (in example ": 811.")
613
 *  - statusPart: the nomenclatorical status
614
 *  - descriptionPart:
615
 *
616
 * Each set of parts is dedicated to render a specific TaxonName type, the type names are used as keys for the
617
 * specific parts part definitions:
618
 *
619
 *  - BotanicalName
620
 *  - ZoologicalName
621
 *  - #DEFAULT:  covers ViralNames and general NonViralNames
622
 *
623
 * An example:
624
 * @code
625
 * array(
626
 *    'ZoologicalName' => array(
627
 *        'namePart' => array('name' => TRUE),
628
 *        'referencePart' => array('authorTeam' => TRUE),
629
 *        'microreferencePart' => array('microreference' => TRUE),
630
 *        'statusPart' => array('status' => TRUE),
631
 *        'descriptionPart' => array('description' => TRUE),
632
 *    ),
633
 *    'BotanicalName' => array(
634
 *        'namePart' => array(
635
 *            'name' => TRUE,
636
 *            'authors' => TRUE,
637
 *        ),
638
 *        'referencePart' => array(
639
 *            'reference' => TRUE,
640
 *            'microreference' => TRUE,
641
 *        ),
642
 *        'statusPart' => array('status' => TRUE),
643
 *        'descriptionPart' => array('description' => TRUE),
644
 *    ),
645
 *  );
646
 * @endcode
647
 *
648
 * @todo document this function.
649
 */
650
function get_partDefinition($taxonNameType) {
651

    
652
  static $default_part_definitions = null;
653
  if (!isset($default_part_definitions)) {
654
    $default_part_definitions= unserialize(CDM_PART_DEFINITIONS_DEFAULT);
655
  }
656

    
657
  // Preliminar solution: using themes.
658
  // TODO remove this once all themes are using the newly introcuded part_definition settings
659
  $part_definitions = theme('get_partDefinition', array());
660

    
661
  // try to get get part definitions from variables
662
  if(!is_array($part_definitions)) {
663
    $part_definitions = variable_get(CDM_PART_DEFINITIONS, $default_part_definitions);
664
  }
665

    
666
  if (array_key_exists($taxonNameType, $part_definitions)) {
667
    return $part_definitions[$taxonNameType];
668
  } else {
669
    return $part_definitions['#DEFAULT']; // covers ViralNames and general NonViralNames
670
  }
671

    
672
}
673

    
674
/**
675
 * @param $variables
676
 *    - taxonName : cdm TaxonNameBase instance
677
 *    - nameLink: URI to the taxon, @see path_to_taxon()
678
 *    - refenceLink: URI to the reference, @see path_to_reference()
679
 *    - show_annotations: ...
680
 *    - is_type_designation: ...
681
 *    - skiptags: an array of tags to skip ....
682
 *
683
 * @todo Please document this function.
684
 * @see http://drupal.org/node/1354
685
 */
686
function theme_cdm_taxonName($variables) {
687

    
688
  $taxonName = $variables['taxonName'];
689
  $nameLink = $variables['nameLink'];
690
  $refenceLink = $variables['refenceLink'];
691
  $show_annotations = $variables['show_annotations'];
692
  $is_type_designation = $variables['is_type_designation'];
693
  $skiptags = $variables['skiptags'];
694

    
695
  $renderTemplate = get_nameRenderTemplate(RenderHints::getRenderPath(), $nameLink, $refenceLink);
696
  $partDefinition = get_partDefinition($taxonName->class);
697

    
698
  // Apply definitions to template.
699
  foreach ($renderTemplate as $part => $uri) {
700

    
701
    if (isset($partDefinition[$part])) {
702
      $renderTemplate[$part] = $partDefinition[$part];
703
    }
704
    if (is_array($uri) && isset($uri['#uri'])) {
705
      $renderTemplate[$part]['#uri'] = $uri['#uri'];
706
    }
707
  }
708

    
709
  normalize_TaggedName($taxonName->taggedName);
710

    
711
  $firstEntryIsValidNamePart = isset($taxonName->taggedName) && is_array($taxonName->taggedName) && isset($taxonName->taggedName[0]->text) && is_string($taxonName->taggedName[0]->text) && $taxonName->taggedName[0]->text != '' && isset($taxonName->taggedName[0]->type) && $taxonName->taggedName[0]->type == 'name';
712

    
713
  // Got to use second entry as first one, see ToDo comment below ...
714
  if ($firstEntryIsValidNamePart) {
715

    
716
    $taggedName = $taxonName->taggedName;
717
    $lastAuthorElementString = FALSE;
718
    $hasNamePart_with_Authors = isset($renderTemplate['namePart']) && isset($renderTemplate['namePart']['authors']);
719
    $hasNameAuthorPart_with_Authors = isset($renderTemplate['nameAuthorPart']) && isset($renderTemplate['nameAuthorPart']['authors']);
720

    
721
    if (!(($hasNamePart_with_Authors) || ($hasNameAuthorPart_with_Authors))) {
722
      // Find author and split off from name.
723
      // TODO expecting to find the author as the last element.
724
      /*
725
      if($taggedName[count($taggedName)- 1]->type == 'authors'){
726
        $authorTeam = $taggedName[count($taggedName)- 1]->text;
727
        unset($taggedName[count($taggedName)- 1]);
728
      }
729
      */
730

    
731
      // Remove all authors.
732
      $taggedNameNew = array();
733
      foreach ($taggedName as $element) {
734
        if ($element->type != 'authors') {
735
          $taggedNameNew[] = $element;
736
        }
737
        else {
738
          $lastAuthorElementString = $element->text;
739
        }
740
      }
741
      $taggedName = $taggedNameNew;
742
    }
743
    $name = '<span class="' . $taxonName->class . '">' . theme('cdm_taggedtext2html', array(
744
      'taggedtxt' => $taggedName,
745
      'tag' => 'span',
746
      'glue' => ' ',
747
      'skiptags' => $skiptags,
748
      )) . '</span>';
749
  }
750
  else {
751
    $name = '<span class="' . $taxonName->class . '_titleCache">' . $taxonName->titleCache . '</span>';
752
  }
753

    
754
  // Fill name into $renderTemplate.
755
  array_setr('name', $name, $renderTemplate);
756

    
757
  // Fill with authorTeam.
758
  /*
759
  if($authorTeam){
760
    $authorTeamHtml = ' <span class="authorTeam">'.$authorTeam.'</span>';
761
    array_setr('authorTeam', $authorTeamHtml, $renderTemplate);
762
  }
763
  */
764

    
765
  // Fill with reference.
766
  if (isset($renderTemplate['referencePart']) && !$is_type_designation) {
767

    
768
    // [Eckhard]:"Komma nach dem Taxonnamen ist grunsätzlich falsch,
769
    // Komma nach dem Autornamen ist überall dort falsch, wo ein "in" folgt."
770
    if (isset($renderTemplate['referencePart']['reference']) && isset($taxonName->nomenclaturalReference)) {
771
      $microreference = NULL;
772
      if (isset($renderTemplate['referencePart']['microreference'])&& isset($taxonName->nomenclaturalMicroReference)) {
773
        $microreference = $taxonName->nomenclaturalMicroReference;
774
      }
775
      $citation = cdm_ws_getNomenclaturalReference($taxonName->nomenclaturalReference->uuid, $microreference);
776

    
777
      // Find preceding element of the reference.
778
      $precedingKey = get_preceding_contentElementKey('reference', $renderTemplate);
779
      if (str_beginsWith($citation, ", in")) {
780
        $citation = substr($citation, 2);
781
        $separator = ' ';
782
      }
783
      elseif (!str_beginsWith($citation, "in") && $precedingKey == 'authors') {
784
        $separator = ', ';
785
      }
786
      else {
787
        $separator = ' ';
788
      }
789

    
790
      $referenceArray['#separator'] = $separator;
791
      $referenceArray['#html'] = '<span class="reference">' . $citation . '</span>';
792
      array_setr('reference', $referenceArray, $renderTemplate);
793
    }
794

    
795
    // If authors have been removed from the name part the last named authorteam
796
    // should be added to the reference citation, otherwise, keep the separator
797
    // out of the reference.
798
    if (isset($renderTemplate['referencePart']['authors']) && $lastAuthorElementString) {
799
      // If the nomenclaturalReference citation is not included in the
800
      // reference part but diplay of the microreference
801
      // is wanted, append the microreference to the authorTeam.
802
      if (!isset($renderTemplate['referencePart']['reference']) && isset($renderTemplate['referencePart']['microreference'])) {
803
        $separator = ": ";
804
        $citation = $taxonName->nomenclaturalMicroReference;
805
      }
806
      $referenceArray['#html'] = ' <span class="reference">' . $lastAuthorElementString . $separator . $citation . '</span>';
807
      array_setr('authors', $referenceArray, $renderTemplate);
808
    }
809
  }
810

    
811
  // Fill with status.
812
  $statusHtml = '';
813
  if (isset($taxonName->status) && is_array($taxonName->status)) {
814
    if (array_setr('status', TRUE, $renderTemplate)) {
815
      if (isset($taxonName->status[0])) {
816
        foreach ($taxonName->status as $status) {
817
          $statusHtml .= ', ' . $status->type->representation_L10n_abbreviatedLabel;
818
        }
819
      }
820
      array_setr('status', '<span class="nomenclatural_status">' . $statusHtml . '</span>', $renderTemplate);
821
    }
822
  }
823

    
824
  // Fill with protologues etc...
825
  $descriptionHtml = '';
826
  if (array_setr('description', TRUE, $renderTemplate)) {
827
    $descriptions = cdm_ws_get(CDM_WS_PORTAL_NAME_DESCRIPTIONS, $taxonName->uuid);
828
    foreach ($descriptions as $description) {
829
      if (!empty($description)) {
830
        foreach ($description->elements as $description_element) {
831
          $second_citation = '';
832
          if (isset($description_element->multilanguageText_L10n) && $description_element->multilanguageText_L10n->text) {
833
            $second_citation = '[& ' . $description_element->multilanguageText_L10n->text . '].';
834
          }
835
          $descriptionHtml .= $second_citation;
836
          $descriptionHtml .= theme("cdm_media", array(
837
              'descriptionElement' => $description_element,
838
              'mimeTypePreference' => array(
839
                  'application/pdf',
840
                  'image/png',
841
                  'image/jpeg',
842
                  'image/gif',
843
                  'text/html',
844
                )
845
              )
846
            );
847

    
848
        }
849
      }
850
    }
851
    array_setr('description', $descriptionHtml, $renderTemplate);
852
  }
853

    
854
  // Render.
855
  $out = '<span ref="/name/' . $taxonName->uuid . '">';
856

    
857
  foreach ($renderTemplate as $partName => $part) {
858
    $separator = '';
859
    $partHtml = '';
860
    $uri = FALSE;
861
    if (!is_array($part)) {
862
      continue;
863
    }
864
    if (isset($part['#uri']) && is_string($part['#uri'])) {
865
      $uri = $part['#uri'];
866
      unset($part['#uri']);
867
    }
868
    foreach ($part as $key => $content) {
869
      $html = '';
870
      if (is_array($content)) {
871
        $html = $content['#html'];
872
        $separator = $content['#separator'];
873
      }
874
      elseif (is_string($content)) {
875
        $html = $content;
876
      }
877
      $partHtml .= '<span class="' . $key . '">' . $html . '</span>';
878
    }
879
    if ($uri) {
880
      $out .= $separator . '<a href="' . $uri . '" class="' . $partName . '">' . $partHtml . '</a>';
881
    }
882
    else {
883
      $out .= $separator . $partHtml;
884
    }
885
  }
886
  $out .= '</span>';
887
  if ($show_annotations) {
888
    // $out .= theme('cdm_annotations_as_footnotekeys', $taxonName);
889
  }
890
  return $out;
891
}
892

    
893
/**
894
 * Recursively searches the array for the $key and sets the given value.
895
 *
896
 * @param mixed $key
897
 *   Key to search for.
898
 * @param mixed $value
899
 *   Value to set.
900
 * @param array $array
901
 *   Array to search in.
902
 *
903
 * @return bool
904
 *   True if the key has been found.
905
 */
906
function &array_setr($key, $value, array &$array) {
907
  $res = NULL;
908
  foreach ($array as $k => &$v) {
909
    if ($key == $k) {
910
      $v = $value;
911
      return $array;
912
    }
913
    elseif (is_array($v)) {
914
      $innerArray = array_setr($key, $value, $v);
915
      if ($innerArray) {
916
        return $array;
917
      }
918
    }
919
  }
920
  return $res;
921
}
922

    
923
/**
924
 * @todo Please document this function.
925
 * @see http://drupal.org/node/1354
926
 */
927
function &get_preceding_contentElement($contentElementKey, array &$renderTemplate) {
928
  $res = NULL;
929
  $precedingElement = NULL;
930
  foreach ($renderTemplate as &$part) {
931
    foreach ($part as $key => &$element) {
932
      if ($key == $contentElementKey) {
933
        return $precedingElement;
934
      }
935
      $precedingElement = $element;
936
    }
937
  }
938
  return $res;
939
}
940

    
941
/**
942
 * @todo Please document this function.
943
 * @see http://drupal.org/node/1354
944
 */
945
function &get_preceding_contentElementKey($contentElementKey, array &$renderTemplate) {
946
  $res = NULL;
947
  $precedingKey = NULL;
948
  foreach ($renderTemplate as &$part) {
949
    if (is_array($part)) {
950
      foreach ($part as $key => &$element) {
951
        if ($key == $contentElementKey) {
952
          return $precedingKey;
953
        }
954
        if (!str_beginsWith($key, '#')) {
955
          $precedingKey = $key;
956
        }
957
      }
958
    }
959
  }
960
  return $res;
961
}
962

    
963
/**
964
 * Returns HTML for a name in your theme, when implemented.
965
 *
966
 * This function returns currently nothing, but can be used to override
967
 * how names are rendered in your theme. See the code that is commented out
968
 * for an example usage. it is used in the function get_nameRenderTemplate.
969
 * See that function to find out how the create template is used.
970
 *
971
 * @see get_nameRenderTemplate()
972
 *
973
 * @deprecated define name render templates via the layout settings
974
 *
975
 * @ingroup: themeable
976
 */
977
function theme_get_nameRenderTemplate() {
978
  /*
979
  // Example usage:
980
//   $render_path = $variables['renderPath'];
981

    
982
  $templates = array(
983
    'taxon_page_title,polytomousKey' => array(
984
        'namePart' => array(
985
          '#uri' => TRUE
986
        )
987
      ),
988
    'taxon_page_synonymy,related_taxon' => array(
989
        'nameAuthorPart' => array(
990
          '#uri' => TRUE
991
        ),
992
        'referencePart' => TRUE,
993
        'statusPart' => TRUE,
994
        'descriptionPart' => TRUE
995
      ),
996
     'acceptedFor' => array(
997
        'nameAuthorPart' => array(
998
          '#uri' => TRUE
999
        ),
1000
        'referencePart' => TRUE
1001
      ),
1002
     'typedesignations,list_of_taxa' => array(
1003
        'nameAuthorPart' => array(
1004
           '#uri' => TRUE
1005
        ), 'referencePart' => TRUE
1006
      ),
1007
    '#DEFAULT'=> array(
1008
        'nameAuthorPart' => array(
1009
           '#uri' => TRUE
1010
        ), 'referencePart' => TRUE
1011
      )
1012
  );
1013
  return $templates;
1014
  */
1015

    
1016
}
(5-5/10)