Project

General

Profile

Download (97.1 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/**
3
 * @file
4
 * Module to provide a CDM Dataportal.
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
 * @author
16
 *   - Andreas Kohlbecker <a.kohlbecker@BGBM.org>
17
 *   - Wouter Addink <w.addink@eti.uva.nl> (migration from Drupal 5 to Drupal7)
18
 */
19

    
20
  module_load_include('php', 'cdm_dataportal', 'node_types');
21
  module_load_include('php', 'cdm_dataportal', 'settings');
22
  module_load_include('php', 'cdm_dataportal', 'help');
23
  module_load_include('php', 'cdm_dataportal', 'cdm_dataportal.search');
24

    
25
  module_load_include('inc', 'cdm_dataportal', 'includes/common');
26
  module_load_include('inc', 'cdm_dataportal', 'includes/name');
27
  module_load_include('inc', 'cdm_dataportal', 'includes/taxon');
28
  module_load_include('inc', 'cdm_dataportal', 'includes/references');
29
  module_load_include('inc', 'cdm_dataportal', 'includes/pages');
30
  module_load_include('inc', 'cdm_dataportal', 'includes/media');
31
  module_load_include('inc', 'cdm_dataportal', 'includes/maps');
32
  module_load_include('inc', 'cdm_dataportal', 'includes/occurrences');
33
  module_load_include('inc', 'cdm_dataportal', 'includes/descriptions');
34
  module_load_include('inc', 'cdm_dataportal', 'includes/pre-drupal8');
35

    
36
  module_load_include('inc', 'cdm_dataportal', 'theme/theme_registry');
37
  module_load_include('theme', 'cdm_dataportal', 'theme/cdm_dataportal.common');
38
  module_load_include('theme', 'cdm_dataportal', 'theme/cdm_dataportal.descriptions');
39
  module_load_include('theme', 'cdm_dataportal', 'theme/cdm_dataportal.media');
40
  module_load_include('theme', 'cdm_dataportal', 'theme/cdm_dataportal.occurrence');
41
  module_load_include('theme', 'cdm_dataportal', 'theme/cdm_dataportal.page');
42
  module_load_include('theme', 'cdm_dataportal', 'theme/cdm_dataportal.taxon');
43
  module_load_include('theme', 'cdm_dataportal', 'theme/cdm_dataportal.name');
44
  module_load_include('theme', 'cdm_dataportal', 'theme/cdm_dataportal.references');
45

    
46
  module_load_include('php', 'cdm_dataportal', 'classes/footnotemanager');
47
  module_load_include('php', 'cdm_dataportal', 'classes/footnote');
48
  module_load_include('php', 'cdm_dataportal', 'classes/footnotekey');
49
  module_load_include('php', 'cdm_dataportal', 'classes/renderhints');
50

    
51

    
52
  /* ============================ java script functions ============================= */
53

    
54

    
55
  /**
56
  * loads external java script files asynchronously.
57
  *
58
  * @param unknown_type $script_url
59
  */
60
  function drupal_add_js_async($script_url, $callback){
61

    
62
    drupal_add_js("
63
          jQuery(document).ready(function() {
64
            jQuery.ajax({
65
              url: '" . $script_url . "',
66
              dataType: 'script',
67
              cache: true, // otherwise will get fresh copy every page load
68
              success: function() {
69
                    " . $callback . "
70
              }
71
            });
72
          });"
73
    , 'inline');
74
  }
75

    
76
  /**
77
   */
78
  function drupal_add_js_rowToggle($tableId){
79

    
80
      drupal_add_js(drupal_get_path('module', 'cdm_dataportal') . '/js/table_modification.js');
81
      drupal_add_js('jQuery(document).ready(function(){
82
          addRowToggle("' . $tableId . '");
83
      });
84
      ', array('type' => 'inline'));
85
  }
86

    
87
  /**
88
   * @param unknown_type $link_element_selector
89
   * @param unknown_type $progress_element_selector
90
   */
91
  function _add_js_cdm_ws_progressbar($link_element_selector, $progress_element_selector){
92

    
93
    $callback = "jQuery('" . $link_element_selector . "').cdm_ws_progress('" . $progress_element_selector . "');";
94

    
95
    drupal_add_js_async(variable_get('cdm_webservice_url', '').'js/cdm_ws_progress.js', $callback);
96

    
97
    //   drupal_add_js("
98
    //   	  if (Drupal.jsEnabled) {
99
    //         $(document).ready(function() {
100
    //       		$('" . $link_element_selector . "').cdm_ws_progress('" . $progress_element_selector . "');
101
    //         });
102
    //       }", 'inline');
103
    }
104

    
105
  /**
106
   * @todo Please document this function.
107
   * @see http://drupal.org/node/1354
108
   */
109
  function _add_js_treeselector() {
110
    // drupal_add_js(drupal_get_path('module', 'cdm_dataportal').'/js/treeselector.js');
111
    drupal_add_js("
112
        jQuery(document).ready(function() {
113
           jQuery('#cdm-taxonomictree-selector-form #edit-val').change(function () {
114
                jQuery('#cdm-taxonomictree-selector-form').submit();
115
            });
116

    
117
        });
118
      ",
119
      array(
120
        'type' => 'inline',
121
        'scope' => 'footer'
122
      )
123
    );
124
  }
125

    
126
  function _add_js_resizable_element($selector, $y_axis_only) {
127

    
128
    _add_jquery_ui();
129
    $options = "";
130
    if($y_axis_only) {
131
      $options = "resize: function(event, ui) {
132
        ui.size.width = ui.originalSize.width;
133
        },
134
        handles: \"s\"";
135

    
136
    }
137
    drupal_add_js("
138
          jQuery(document).ready(function() {
139
             jQuery('" . $selector . "').resizable({". $options ."});
140
          });
141
        ",
142
      array(
143
        'type' => 'inline',
144
        'scope' => 'footer'
145
      )
146
    );
147
  }
148

    
149
  function _add_js_openlayers() {
150

    
151
    $openlayers = '/js/map/OpenLayers-2.13.1/OpenLayers.js';
152
    $proj4js = '/js/map/proj4js-1.1.0/proj4js-compressed.js';
153

    
154
    if(variable_get('cdm_js_devel_mode', FALSE)){
155
      // develooper mode libs
156
  //     $openlayers = '/js/map/OpenLayers-2.13.1/lib/OpenLayers.js';
157
      $openlayers = '/js/map/OpenLayers-2.13.1/OpenLayers.debug.js';
158
      $proj4js = '/js/map/proj4js-1.1.0/proj4js-combined.js';
159
    }
160

    
161
    drupal_add_js(drupal_get_path('module', 'cdm_dataportal') . $openlayers,
162
      array(
163
        'type' => 'file',
164
        'group' => JS_LIBRARY,
165
        'weight' => 0,
166
        'cache' => TRUE,
167
        'preprocess' => FALSE
168
      )
169
    );
170

    
171
    // see https://github.com/proj4js/proj4js
172
    // http://openlayers.org/dev/examples/using-proj4js.html
173
    drupal_add_js(drupal_get_path('module', 'cdm_dataportal') . $proj4js,
174
      array(
175
        'type' => 'file',
176
        'group' => JS_LIBRARY,
177
        'weight' => -1, // before open layers
178
        'cache' => TRUE,
179
      )
180
    );
181

    
182
    // configure the theme
183
    $openlayers_theme_path = drupal_get_path('module', 'cdm_dataportal') . '/js/map/OpenLayers-2.13.1/theme/default/';
184
    $openlayers_imp_path = drupal_get_path('module', 'cdm_dataportal') . '/js/map/img/dark/';
185
    drupal_add_js('OpenLayers.ImgPath="' . base_path() . $openlayers_imp_path . '";', array(
186
        'type' => 'inline',
187
        'group' => JS_LIBRARY,
188
        'weight' => 1, // after openlayers
189
        'cache' => TRUE,
190
        'preprocess' => FALSE
191
      ));
192

    
193
    drupal_add_css($openlayers_theme_path . 'style.tidy.css',
194
      array(
195
        'type' => 'file',
196
        'cache' => TRUE,
197
        'preprocess' => FALSE
198
      )
199
    );
200

    
201
  }
202

    
203
  /**
204
   * @todo Please document this function.
205
   * @see http://drupal.org/node/1354
206
   */
207
  function _add_js_thickbox() {
208
    // ---- jQuery thickbox:
209
    /*
210
    * bug: compat-1.0.js && thickbox.js line 237 .trigger("unload") -> event is
211
    * not triggered because of problems with compat-1.0.js' see INSTALL.txt
212
    */
213
    // drupal_add_js(drupal_get_path('module',
214
    // 'cdm_dataportal').'/js/jquery.imagetool.min.js');
215
    //
216
    // Add a setting for the path to cdm_dataportal module, used to find the path
217
    // for the loading animation image in thickbox.
218
    drupal_add_js(array(
219
    'cdm_dataportal' => array(
220
    'cdm_dataportal_path' => base_path() . drupal_get_path('module', 'cdm_dataportal'),
221
    )
222
    ),
223
    'setting'
224
        );
225
        drupal_add_js(drupal_get_path('module', 'cdm_dataportal') . '/js/thickbox/thickbox.js');
226
        drupal_add_css(drupal_get_path('module', 'cdm_dataportal') . '/js/thickbox/cdm_thickbox.css');
227
  }
228

    
229
  /**
230
   * @todo Please document this function.
231
   * @see http://drupal.org/node/1354
232
   */
233
  function _add_js_lightbox($galleryID) {
234
    /*
235
     * Important Notice: The jquery.lightbox-0.5.js has been modified in order to
236
     * allow using the "alt" attribute for captions instead of the "title"
237
     * attribute
238
     */
239
    $lightbox_base_path =  drupal_get_path('module', 'cdm_dataportal') . '/js/jquery-lightbox-0.5';
240
    $lightbox_image_path = base_path() . $lightbox_base_path . '/images/';
241
    drupal_add_js($lightbox_base_path . '/js/jquery.lightbox-0.5.js');
242
    drupal_add_css($lightbox_base_path . '/css/jquery.lightbox-0.5.css');
243
    drupal_add_js('jQuery(document).ready(function() {
244
        jQuery(\'#' . $galleryID . ' a.lightbox\').lightBox({
245
          fixedNavigation:  true,
246
          imageLoading:     \'' . $lightbox_image_path . 'lightbox-ico-loading.gif\',
247
          imageBtnPrev:     \'' . $lightbox_image_path . 'lightbox-btn-prev.gif\',
248
          imageBtnNext:     \'' . $lightbox_image_path . 'lightbox-btn-next.gif\',
249
          imageBtnClose:    \'' . $lightbox_image_path . 'lightbox-btn-close.gif\',
250
          imageBlank:       \'' . $lightbox_image_path . 'lightbox-blank.gif\',
251
          adjustToWindow: true
252
        });
253
      });
254
      ', array('type' => 'inline'));
255
  }
256

    
257
  /**
258
   * @todo Please document this function.
259
   * @see http://drupal.org/node/1354
260
   */
261
  function _add_js_footnotes() {
262
    _add_js_domEvent();
263
    drupal_add_js(drupal_get_path('module', 'cdm_dataportal') . '/js/footnotes.js');
264
  }
265

    
266
  /**
267
   * @todo Please document this function.
268
   * @see http://drupal.org/node/1354
269
   */
270
  function _add_js_ahah() {
271

    
272
    _add_js_domEvent(); // requires domEvent.js
273
    drupal_add_js(drupal_get_path('module', 'cdm_dataportal') . '/js/ahah-content.js');
274
  }
275

    
276
/**
277
 * @todo Please document this function.
278
 * @see http://drupal.org/node/1354
279
 */
280
function _add_js_taxonomic_children($jquery_selector) {
281

    
282
  global $base_url;
283

    
284

    
285
  drupal_add_js(drupal_get_path('module', 'cdm_dataportal') . '/js/jquery.cdm.taxonomic_children.js');
286
  
287
  drupal_add_js('jQuery(document).ready(function() {
288
        jQuery(\'' . $jquery_selector . '\').taxonomic_children({
289
          // hoverClass: "fa-rotate-90",
290
          // activeClass: "fa-rotate-90",
291
          classificationUuid: "' . get_current_classification_uuid() . '",
292
          taxonUuid: "' . get_current_taxon_uuid() . '",
293
          cdmWebappBaseUri: "' . variable_get('cdm_webservice_url', '') . '",
294
          proxyBaseUri: "' . $base_url . '",
295
          
296
        });
297
      });
298
      ', array('type' => 'inline'));
299
}
300

    
301
  /**
302
   * Adds the external javascript file for domEvent.js.
303
   *
304
   * @see drupal_add_js()
305
   */
306
  function _add_js_domEvent() {
307
    drupal_add_js(drupal_get_path('module', 'cdm_dataportal') . '/js/domEvent.js');
308
  }
309

    
310
  function _add_jquery_ui()
311
  {
312
    drupal_add_css(drupal_get_path('module',
313
        'cdm_dataportal') . '/js/jquery-ui-1.8.24/themes/base/jquery.ui.all.css');
314
    drupal_add_js(drupal_get_path('module',
315
        'cdm_dataportal') . '/js/jquery-ui-1.8.24/ui/jquery-ui.js',
316
      array(
317
        'type' => 'file',
318
        'weight' => JS_LIBRARY,
319
        'cache' => TRUE,
320
        'preprocess' => FALSE
321
      )
322
    );
323
  }
324

    
325
  function _add_js_ui_accordion(){
326
    _add_jquery_ui();
327
    drupal_add_js('jQuery(document).ready(function() {
328
        jQuery( "#accordion" ).accordion();
329
      });',
330
      array('type' => 'inline')
331
    );
332
  }
333

    
334

    
335
function _add_js_utis_client($jquery_selector){
336

    
337
  drupal_add_js(drupal_get_path('module',
338
      'cdm_dataportal') . '/js/utis-client/utis-client.js',
339
    array(
340
      'type' => 'file',
341
      'weight' => JS_LIBRARY,
342
      'cache' => TRUE,
343
      'preprocess' => FALSE
344
    )
345
  );
346

    
347
  drupal_add_js('jQuery(document).ready(function() {
348
        jQuery( "' . $jquery_selector . '" ).utis_client(
349
        {
350
          spinnerIcon: \'' . font_awesome_icon_markup('fa-sync', array('class' => array('fa-3x',  'fa-spin'), 'style' => array('opacity: 0.3;'))) . '\',
351
          externalLinkIcon: \'' . font_awesome_icon_markup('fa-external-link-alt') . '\'
352
        });
353
      });',
354
    array('type' => 'inline')
355
  );
356
}
357

    
358
function _add_js_universalviewer($jquery_selector, $manifest_uri){
359

    
360
  $universalviewer_path  = drupal_get_path('module',    'cdm_dataportal') . '/js/universalviewer';
361

    
362
  drupal_add_css($universalviewer_path . '/uv/uv.css');
363
  drupal_add_css($universalviewer_path . '/uv-fix.css');
364

    
365
  // offline.js is all of these dependencies concatenated (jQuery, CoreJS, and JSViews)
366
  drupal_add_js($universalviewer_path . '/uv/lib/offline.js',
367
      array(
368
      'type' => 'file',
369
      'group' => JS_LIBRARY,
370
      'cache' => TRUE,
371
      'preprocess' => FALSE
372
    )
373
  );
374
  drupal_add_js($universalviewer_path . '/uv/helpers.js',
375
    array(
376
      'type' => 'file',
377
      'group' => JS_LIBRARY,
378
      'cache' => TRUE,
379
      'preprocess' => FALSE
380
    )
381
  );
382
  // from UV 3.x documentation:
383
  // "root:
384
  // The path to the uv directory. Use a relative path e.g. root: '../../uv'
385
  // Don't start your path with a / otherwise requirejs will not append .js to
386
  // dependencies and they won't load."
387
  //
388
  // universalviewerPath will be used to build the root config variable.
389
  $folders_up = preg_replace('/[^\/]+/', '..', $_GET['q']);
390
  $folders_up = preg_replace('/\.\.$/', '', $folders_up);
391
  $config_file = 'uv-config.json';
392
  drupal_add_js('
393
      console.log(\'jQuery inline: \' + jQuery.fn.jquery);
394
      jQuery(window).on(\'uvLoaded\', function() {
395
        jQuery( "' . $jquery_selector . '" ).jqUniversalviewer(
396
        {
397
          root: \'' . $folders_up . $universalviewer_path . '/uv\',
398
          configUri: \'' . base_path() . $universalviewer_path . '/'. $config_file . '\',
399
          manifestUri: \'' . $manifest_uri . '\'
400
        }
401
        );
402
      });',
403
    array(
404
      'type' => 'inline',
405
      'scope' => 'footer',
406
      'group' => JS_DEFAULT,
407
      'weight' => 0,
408
    )
409
  );
410
  drupal_add_js($universalviewer_path . '/jq-universalviewer.js',
411
    array(
412
      'type' => 'file',
413
      'scope' => 'footer',
414
      'group' => JS_DEFAULT,
415
      'weight' => 10,
416
      'cache' => TRUE,
417
      'preprocess' => FALSE
418
    )
419
  );
420
  // ui.js must be last
421
  drupal_add_js($universalviewer_path . '/uv/uv.js',
422
    array(
423
      'type' => 'file',
424
      'scope' => 'footer',
425
      'group' => 300, // IMPORTANT!
426
      'cache' => TRUE,
427
      'preprocess' => FALSE
428
    )
429
  );
430
}
431

    
432
  /**
433
   * Provides the markup for an font awesome icon.
434
   *
435
   * The icons is created in default size without any extra features.
436
   *
437
   * The available icons are listed here http://fontawesome.io/cheatsheet/
438
   * fontawesome icons have much more features than implemented here in this function,
439
   * for spinning icons, fixed width icons, rotation, etc please checkout the
440
   * examples at http://fontawesome.io/examples/
441
   *
442
   * @parameter $icon_name
443
   *  The name of the icon which starts with 'fa-'
444
   *
445
   * @return String
446
   *    the markup for the icon in an <i> tag
447
   *
448
   */
449
  function font_awesome_icon_markup($icon_name = NULL, $attributes = array()){
450
    _add_font_awesome_font();
451

    
452

    
453
    if($icon_name){
454
      if(!isset($attributes['class'])){
455
        $attributes['class'] = array();
456
      }
457
      $attributes['class'][] = 'fa';
458
      $attributes['class'][] = $icon_name;
459

    
460
      return '<i ' . drupal_attributes($attributes) . '></i>';
461
    }
462

    
463
    return '';
464
  }
465

    
466
/**
467
 * @param string $glyph_name
468
 *   The name of the gloyph (e.g. 'icon-interal-link-alt-solid') for the foll list please
469
 *   refer to modules/cdm_dataportal/fonts/custom-icon-font
470
 * @param array $attributes
471
 * @return string
472
 */
473
  function custom_icon_font_markup($glyph_name = NULL, $attributes = array()){
474
    _add_font_custom_icon_font();
475

    
476

    
477
    if($glyph_name){
478
      if(!isset($attributes['class'])){
479
        $attributes['class'] = array();
480
      }
481
      $attributes['class'][] = $glyph_name;
482

    
483
      return '<i ' . drupal_attributes($attributes) . '></i>';
484
    }
485

    
486
    return '';
487
  }
488

    
489
/**
490
 * Adds the css  containing the font awesome icons to the html header.
491
 */
492
function _add_font_awesome_font()
493
{
494
  // $fa_font_version = 'font-awesome-4.6.3/css/font-awesome.min.css';
495
  $fa_font_version = 'fontawesome-free-5.9.0-web/css/all.css';
496
  $font_awesome_css_uri = base_path() . drupal_get_path('module', 'cdm_dataportal') . '/fonts/' . $fa_font_version;
497

    
498
  drupal_add_html_head_link(
499
    array(
500
      'href' => $font_awesome_css_uri,
501
      'rel' => 'stylesheet'
502
    )
503
  );
504
}
505

    
506
/**
507
 * Adds the css  containing the font awesome icons to the html header.
508
 */
509
function _add_font_custom_icon_font()
510
{
511

    
512
  $custom_icon_font_css_uri = base_path() . drupal_get_path('module', 'cdm_dataportal') . '/fonts/custom-icon-font/style.css';
513

    
514
  drupal_add_html_head_link(
515
    array(
516
      'href' => $custom_icon_font_css_uri,
517
      'rel' => 'stylesheet'
518
    )
519
  );
520
}
521

    
522
/* ====================== hook implementations ====================== */
523
  /**
524
   * Implements hook_permission().
525
   *
526
   * Valid permissions for this module.
527
   *
528
   * @return array
529
   *   An array of valid permissions for the cdm_dataportal module.
530
   */
531
  function cdm_dataportal_permission() {
532
    return array(
533
      'administer cdm_dataportal' => array(
534
        'title' => t('Administer CDM DataPortal settings'),
535
        'description' => t("Access the settings pages specific for the cdm_dataportal module"),
536
      ),
537
      'access cdm content' => array(
538
        'title' => t('Access CDM content'),
539
        'description' => t("Access content (taxa, names, specimens, etc.) served by the CDM web service."),
540
      ),
541
    );
542
  }
543

    
544
/**
545
 * Implements hook_menu().
546
 */
547
function cdm_dataportal_menu() {
548
  $items = array();
549

    
550
  // @see settings.php.
551
  cdm_dataportal_menu_admin($items);
552
  cdm_dataportal_menu_help($items);
553

    
554
  $items['cdm_dataportal/names'] = array(
555
    'page callback' => 'cdm_dataportal_view_names',
556
    'access arguments' => array('access cdm content'),
557
    'type' => MENU_CALLBACK,
558
  );
559

    
560
  // Optional callback arguments: page.
561
  $items['cdm_dataportal/taxon'] = array(
562
    'page callback' => 'cdm_dataportal_taxon_page_view',
563
    'access arguments' => array('access cdm content'),
564
    'type' => MENU_CALLBACK,
565
    // Expected callback arguments: uuid.
566
  );
567

    
568
  $items['cdm_dataportal/occurrence'] = array(
569
        'page callback' => 'cdm_dataportal_specimen_page_view',
570
        'access arguments' => array('access cdm content'),
571
        'type' => MENU_CALLBACK,
572
        // Expected callback arguments: uuid.
573
    );
574

    
575
  $items['cdm_dataportal/description'] = array(
576
        'page callback' => 'cdm_dataportal_description_page_view',
577
        'access arguments' => array('access cdm content'),
578
        'type' => MENU_CALLBACK,
579
        // Expected callback arguments: uuid.
580
    );
581

    
582
   $items['cdm_dataportal/specimen/accession_number'] = array(
583
        'page callback' => 'cdm_dataportal_specimen_by_accession_number_page_view',
584
        'access arguments' => array('access cdm content'),
585
        'type' => MENU_CALLBACK,
586
        // Expected callback arguments: accession number.
587
    );
588
  $items['cdm_dataportal/named_area'] = array(
589
    'page callback' => 'cdm_dataportal_named_area_page_view',
590
    'access arguments' => array('access cdm content'),
591
    'type' => MENU_CALLBACK,
592
    // Expected callback arguments: uuid.
593
  );
594

    
595
  $items['cdm_dataportal/name'] = array(
596
    'page callback' => 'cdm_dataportal_name_page_view',
597
      /*
598
    'page arguments' => array(
599
       'taxon_name_uuid',
600
       'taxon_to_hide_uuid',
601
       'synonym_uuid' => NULL
602
      ),
603
      */
604
    'access arguments' => array('access cdm content'),
605
    'type' => MENU_CALLBACK,
606
    // Expected callback arguments: uuid.
607
  );
608

    
609
  $items['cdm_dataportal/reference'] = array(
610
    'page callback' => 'cdm_dataportal_view_reference',
611
    'access arguments' => array('access cdm content'),
612
    'type' => MENU_CALLBACK,
613
    // Expected callback arguments: uuid.
614
  );
615

    
616
  $items['cdm_dataportal/reference/list'] = array(
617
    'page callback' => 'cdm_dataportal_view_reference_list',
618
    'access arguments' => array('access cdm content'),
619
    'type' => MENU_CALLBACK,
620
    // Expected callback arguments: uuid.
621
  );
622

    
623
  $items['cdm_dataportal/media'] = array(
624
    'page callback' => 'cdm_dataportal_view_media',
625
    'access arguments' => array('access cdm content'),
626
    'type' => MENU_CALLBACK,
627
    // Expected callback arguments:
628
    // uuid, mediarepresentation_uuid, part_uuid or part#.
629
  );
630

    
631
  $items['cdm_dataportal/polytomousKey'] = array(
632
    'page callback' => 'cdm_dataportal_view_polytomousKey',
633
    'access arguments' => array('access cdm content'),
634
    'type' => MENU_CALLBACK,
635
    // Expected callback arguments: polytomousKey->uuid.
636
  );
637

    
638
  $items['cdm_dataportal/search'] = array(
639
    'page callback' => 'cdm_dataportal_view_search_advanced',
640
    'access arguments' => array('access cdm content'),
641
    'type' => MENU_CALLBACK,
642
  );
643

    
644
  $items['cdm_dataportal/search/advanced'] = array(
645
    'title' => 'Advanced', // will be passed through t()
646
    'page callback' => 'cdm_dataportal_view_search_advanced',
647
    'access arguments' => array('access cdm content'),
648
    'type' => MENU_DEFAULT_LOCAL_TASK,
649
  );
650
  $items['cdm_dataportal/search/blast'] = array(
651
    'title' => 'Blast', // will be passed through t()
652
    'page callback' => 'cdm_dataportal_view_search_blast',
653
    'access arguments' => array('access cdm content'),
654
    'type' => MENU_LOCAL_TASK,
655
  );
656

    
657
  $items['cdm_dataportal/search/taxon_by_description'] = array(
658
    'title' => 'By content category', // will be passed through t()
659
    'page callback' => 'cdm_dataportal_view_search_taxon_by_description',
660
    'access arguments' => array('access cdm content'),
661
    'type' => MENU_LOCAL_TASK,
662
  );
663
  $items['cdm_dataportal/search/results/taxon'] = array(
664
    'page callback' => 'cdm_dataportal_view_search_results_taxon',
665
    'access arguments' => array('access cdm content'),
666
    'type' => MENU_CALLBACK,
667
  );
668

    
669

    
670
  $items['cdm_dataportal/search/results/specimen'] = array(
671
      'page callback' => 'cdm_dataportal_view_search_results_specimen',
672
      'access arguments' => array('access cdm content'),
673
      'type' => MENU_CALLBACK,
674
  );
675

    
676
  /*
677
   * MENU_CALLBACK at cdm_dataportal/registration-search is needed to make the
678
   * tabs in the subordinate paths work, accessing this 'page' will cause the
679
   * MENU_DEFAULT_LOCAL_TASK being displayed
680
   */
681
  $items['cdm_dataportal/registration-search'] = array(
682
    'title' => 'Search', // will be passed through t()
683
    'page callback' => 'cdm_dataportal_view_search_registrations_results',
684
    'page arguments' => array("filter"),
685
    'access arguments' => array('access cdm content'),
686
    'type' => MENU_CALLBACK,
687
  );
688
  /*
689
   * the MENU_DEFAULT_LOCAL_TASK creates a tab for the MENU_CALLBACK
690
   * defined at a higher level of the path (cdm_dataportal/registration-search)
691
   */
692
  $items['cdm_dataportal/registration-search/filter'] = array(
693
    'title' => 'Search', // will be passed through t()
694
    'page callback' => 'cdm_dataportal_view_search_registrations_results',
695
    'page arguments' => array("filter"),
696
    'access arguments' => array('access cdm content'),
697
    'type' => MENU_DEFAULT_LOCAL_TASK,
698
  );
699
  /*
700
   * the MENU_LOCAL_TASK creates another tab
701
   */
702
  $items['cdm_dataportal/registration-search/taxongraph'] = array(
703
    'title' => 'Taxon graph search', // will be passed through t()
704
    'page callback' => 'cdm_dataportal_view_search_registrations_results',
705
    'page arguments' => array("taxongraph"),
706
    'access arguments' => array('access cdm content'),
707
    'type' => MENU_LOCAL_TASK,
708
  );
709

    
710
  // Optional callback arguments: page.
711
  $items['cdm_dataportal/registration'] = array(
712
    'page callback' => 'cdm_dataportal_registration_page_view',
713
    'access arguments' => array('access cdm content'),
714
    'type' => MENU_CALLBACK,
715
    // Expected callback arguments: uuid.
716
  );
717

    
718
  /*
719
   $items['cdm/xml2json'] = array(
720
   'page callback' => 'cdm_view_xml2json',
721
   'access arguments' => array('access cdm content'),
722
   'type' => MENU_CALLBACK,
723
   );
724
   */
725

    
726
  // 'May not cache' in D5.
727
  $items['cdm_dataportal/name/%'] = array(
728
    // 'page callback' => 'cdm_dataportal_view_name',
729
    'page callback' => 'cdm_dataportal_name_page_view',
730
    'page arguments' => array(2, 3, 4, 5),
731
    'access arguments' => array('access cdm content'),
732
    'type' => MENU_CALLBACK,
733
  );
734

    
735
  // --- Local tasks for Taxon.
736
  // --- tabbed taxon page
737
  if (variable_get('cdm_dataportal_taxonpage_tabs', 1)) {
738
    $items['cdm_dataportal/taxon/%'] = array(
739
      'title' => cdm_taxonpage_tab_label('General'),
740
      'page callback' => 'cdm_dataportal_taxon_page_view',
741
      'access arguments' => array('access cdm content'),
742
      'type' => MENU_CALLBACK,
743
      'weight' => 1,
744
      'page arguments' => array(2, "description")
745
      , // Expected callback arguments: taxon_uuid.
746
    );
747

    
748
    $items['cdm_dataportal/taxon/%/all'] = array(
749
      'title' => cdm_taxonpage_tab_label('General'),
750
      'page callback' => 'cdm_dataportal_taxon_page_view',
751
      'access arguments' => array('access cdm content'),
752
      'type' => MENU_CALLBACK,
753
      'weight' => 2,
754
      'page arguments' => array(2, "all")
755
      , // Expected callback arguments: taxon_uuid.
756
    );
757

    
758
    $items['cdm_dataportal/taxon/%/description'] = array(
759
      'title' => cdm_taxonpage_tab_label('General'),
760
      'page callback' => 'cdm_dataportal_taxon_page_view',
761
      'access arguments' => array('access cdm content'),
762
      'type' => MENU_DEFAULT_LOCAL_TASK,
763
      'weight' => 2,
764
      'page arguments' => array(2, "description")
765
      , // Expected callback arguments: taxon_uuid.
766
    );
767

    
768
    $items['cdm_dataportal/taxon/%/synonymy'] = array(
769
      'title' => cdm_taxonpage_tab_label('Synonymy'),
770
      'page callback' => 'cdm_dataportal_taxon_page_view',
771
      'access arguments' => array('access cdm content'),
772
      'type' => MENU_LOCAL_TASK,
773
      'weight' => 4,
774
      'page arguments' => array(2, "synonymy", 4)
775
      , // Expected callback arguments: taxon_uuid and ...
776
    );
777
    $items['cdm_dataportal/taxon/%/images'] = array( // Images
778
      'title' => cdm_taxonpage_tab_label('Images'),
779
      'page callback' => 'cdm_dataportal_taxon_page_view',
780
      'access arguments' => array('access cdm content'),
781
      'type' => MENU_LOCAL_TASK,
782
      'weight' => 5,
783
      'page arguments' => array(2, "images")
784
      , // Expected callback arguments: taxon_uuid.
785
    );
786

    
787
    $items['cdm_dataportal/taxon/%/specimens'] = array( // Specimens
788
      'title' => cdm_taxonpage_tab_label('Specimens'),
789
      'page callback' => 'cdm_dataportal_taxon_page_view',
790
      'access arguments' => array('access cdm content'),
791
      'type' => MENU_LOCAL_TASK,
792
      'weight' => 6,
793
      'page arguments' => array(2, "specimens")
794
      , // Expected callback arguments: taxon_uuid.
795
    );
796

    
797
    $items['cdm_dataportal/taxon/%/keys'] = array( // Keys
798
      'title' => cdm_taxonpage_tab_label('Keys'),
799
      'page callback' => 'cdm_dataportal_taxon_page_view',
800
      'access arguments' => array('access cdm content'),
801
      'type' => MENU_LOCAL_TASK,
802
      'weight' => 6,
803
      'page arguments' => array(2, "keys")
804
      , // Expected callback arguments: taxon_uuid.
805
    );
806

    
807
    $items['cdm_dataportal/taxon/%/experts'] = array( // Experts
808
      'title' => cdm_taxonpage_tab_label('Experts'),
809
        'page callback' => 'cdm_dataportal_taxon_page_view',
810
        'access arguments' => array('access cdm content'),
811
        'type' => MENU_LOCAL_TASK,
812
        'weight' => 6,
813
        'page arguments' => array(2, "experts")
814
    , // Expected callback arguments: taxon_uuid.
815
    );
816

    
817
    $items['cdm_dataportal/taxon/autosuggest/%/%/%/'] = array(
818
        'page callback' => 'cdm_dataportal_taxon_autosuggest',
819
        'access arguments' => array('access cdm content'),
820
        'page arguments' => array(3,4,5),
821
        'type' => MENU_CALLBACK
822
    );
823
  }
824

    
825
  // --- refresh link for all cdmnode types
826
  foreach (cdm_get_nodetypes() as $type=>$name) {
827
    $items['cdm_dataportal/' . $name . '/%/refresh'] = array(
828
        'title' => 'Refresh',
829
        'page callback' => 'cdm_dataportal_refresh_node',
830
        'access arguments' => array('administer cdm_dataportal'),
831
        'type' => MENU_LOCAL_TASK,
832
        'weight' => 100,
833
        'page arguments' => array($name, 2)
834
    );
835
  }
836

    
837
  return $items;
838
}
839

    
840
/**
841
 * Implements hook_init().
842
 *
843
 */
844
function cdm_dataportal_init() {
845
  if (!path_is_admin(current_path())) {
846
    //FIXME To add CSS or JS that should be present on all pages, modules
847
    //      should not implement this hook, but declare these files in their .info file.
848
    drupal_add_css(drupal_get_path('module', 'cdm_dataportal') . '/cdm_dataportal.css');
849
    // drupal_add_css(drupal_get_path('module', 'cdm_dataportal').'/cdm_dataportal_print.css', 'print');
850
    drupal_add_css(drupal_get_path('module', 'cdm_dataportal') . '/cdm_dataportal_screen.css', array('type' => 'screen'));
851
  } else {
852
    drupal_add_css(drupal_get_path('module', 'cdm_dataportal') . '/cdm_dataportal_settings.css');
853
  }
854

    
855
  if(variable_get('cdm_debug_mode', FALSE)){
856
    $file = 'temporary://drupal_debug.txt';
857
    file_put_contents($file, 'CDM DEBUG LOG for ' . $_GET['q']. "\n"); // will overwrite the file
858
  }
859

    
860
  $bibliography_settings = get_bibliography_settings();
861
  $enclosing_tag = $bibliography_settings['enabled'] == 1 ? 'div' : 'span';
862
  FootnoteManager::registerFootnoteSet('BIBLIOGRAPHY', $enclosing_tag, $bibliography_settings['key_format']);
863
}
864

    
865
function cdm_dataportal_refresh_node($cdm_node_name, $uuid, $parameters = array()){
866

    
867
  $base_path = 'cdm_dataportal/' . $cdm_node_name . '/' . $uuid;
868

    
869
  if($cdm_node_name == 'taxon' && variable_get('cdm_dataportal_taxonpage_tabs', 1)){
870
    // force reloading of all and notify user about this special loading
871
    drupal_set_message(t('The level 2 cache has been cleared for all tabs of this taxon page at once, please click here to return to the tabbed page: ')
872
        . l('Back to tabbed taxon page', $base_path));
873
    $base_path .= '/all';
874
  } else {
875
    drupal_set_message(t('The level 2 cache has been cleared for this page'));
876
  }
877

    
878
  $parameters['cacheL2_refresh'] ='1';
879

    
880

    
881
  drupal_goto($base_path, array('query' => $parameters));
882
}
883

    
884
/**
885
 * Implements hook_requirements($phase)
886
 */
887
function cdm_dataportal_requirements($phase) {
888
    $requirements = array();
889
    if($phase == 'runtime'){
890

    
891
    }
892
    return $requirements;
893
}
894

    
895
/**
896
 * Implements hook_block_info().
897
 */
898
function cdm_dataportal_block_info() {
899

    
900
    // $block[0]["info"] = t("CDM DataPortal DevLinks");
901
    // $block[1]["info"] = t("CDM DataPortal Credits");
902
    $block["2"] = array(
903
        "info" => t("CDM - Search Taxa"),
904
        "cache" => DRUPAL_NO_CACHE
905
      );
906
    // $block[3]["info"] = t("CDM Filters");
907
    $block["4"]["info"] = t("CDM  - Dataportal Print");
908
    $block["keys"]["info"] = t("CDM - Identification keys");
909
    $block["fundedByEDIT"]["info"] = t('CDM - Powered by EDIT');
910
    $block["classification_breadcrumbs"] =  array(
911
        'info' => t('CDM - Classification breadcrumbs'),
912
        'cache' => DRUPAL_CACHE_PER_PAGE
913
      );
914
    $block["taxonomic_children"] =  array(
915
      'info' => t('CDM - Taxonomic children'),
916
      'cache' => DRUPAL_CACHE_PER_PAGE
917
    );
918
    $block["back_to_search_results"] =  array(
919
      'title' => '<none>',
920
      'info' => t('CDM - Back to search Results'),
921
      'cache' => DRUPAL_CACHE_PER_PAGE,
922
      'visibility' => BLOCK_VISIBILITY_LISTED,
923
      'pages' => "cdm_dataportal/taxon/*", // multiple page paths separated by "\n"!!!
924
    );
925
  $block['registrations_search_filter'] =  array(
926
    'title' => 'Filter registrations',
927
    'info' => t('CDM - Registrations search filter'),
928
    'cache' => DRUPAL_CACHE_PER_PAGE,
929
    'visibility' => BLOCK_VISIBILITY_NOTLISTED,
930
    'pages' => "cdm_dataportal/registration-search\ncdm_dataportal/registration-search/*", // multiple page paths separated by "\n"!!!
931
  );
932
  $block['registrations_search_taxongraph'] =  array(
933
    'title' => 'Taxonomic registration search',
934
    'info' => t('CDM - Registrations search by taxon graph'),
935
    'cache' => DRUPAL_CACHE_PER_PAGE,
936
    'visibility' => BLOCK_VISIBILITY_NOTLISTED,
937
    'pages' => "cdm_dataportal/registration-search\ncdm_dataportal/registration-search/*", // multiple page paths separated by "\n"!!!
938
  );
939
  $block['registrations_search'] =  array(
940
    'title' => 'Search',
941
    'info' => t('CDM - Registrations search combining filter and taxon graph search' ),
942
    'cache' => DRUPAL_CACHE_PER_PAGE,
943
    'visibility' => BLOCK_VISIBILITY_NOTLISTED,
944
    'pages' => "cdm_dataportal/registration-search\ncdm_dataportal/registration-search/*", // multiple page paths separated by "\n"!!!
945
  );
946
  $block['utis_search'] =  array(
947
    'title' => 'UTIS Search',
948
    'info' => t('Query the Unified Taxonomic Information Service (UTIS)' ),
949
    'cache' => DRUPAL_CACHE_PER_PAGE,
950
    'visibility' => BLOCK_VISIBILITY_NOTLISTED
951
  );
952
  return $block;
953
}
954

    
955
/**
956
 * Implements hook_block_view().
957
 */
958
function cdm_dataportal_block_view($delta) {
959
  // TODO Rename block deltas (e.g. '2') to readable strings.
960
  switch ($delta) {
961
    // case 'delta-1':
962
    // $block['subject'] = t('Credits');
963
    // $block['content'] = theme('cdm_credits');
964
    // return $block;
965
    case '2':
966
      $block['subject'] = t('Search taxa');
967
      $form = drupal_get_form('cdm_dataportal_search_taxon_form');
968
      $block['content'] = drupal_render($form);
969

    
970
      if (variable_get('cdm_dataportal_show_advanced_search', 1)) {
971
        $block['content'] .= '<div>' . l(t('Advanced Search'), 'cdm_dataportal/search') . '</div>';
972
      }
973
      if (variable_get(CDM_SEARCH_BLAST_ENABLED)){
974
          $block['content'] .= '<div>' . l(t('Blast Search'), 'cdm_dataportal/search/blast') . '</div>';
975
      }
976
      return $block;
977
    case '4':
978
      $block['subject'] = '';
979
      $block['content'] = theme('cdm_print_button');
980
      return $block;
981
    case "keys":
982
      $block['subject'] = t('Identification Keys');
983
      $block['content'] = theme('cdm_block_IdentificationKeys', array('taxonUuid' => NULL));
984
      return $block;
985
    case "fundedByEDIT":
986
      // t('Funded by EDIT');
987
      $text = '<none>';
988
      $block['subject'] = $text;
989
      $img_tag = '<img src="' . base_path() . drupal_get_path('module', 'cdm_dataportal') . '/images/powered_by_edit.png' . '" alt="' . $text . '"/>';
990
      $block['content'] = l($img_tag, "http://cybertaxonomy.org/", array(
991
        'attributes' => array("target" => "EDIT"),
992
        'absolute' => TRUE,
993
        'html' => TRUE,
994
      ));
995
      return $block;
996
    case 'classification_breadcrumbs':
997
      $taxon_uuid = get_current_taxon_uuid();
998
      $block['subject'] = '<none>';
999
      $block['content'] = compose_classification_breadcrumbs($taxon_uuid);
1000
      return $block;
1001
    case 'taxonomic_children':
1002
      $taxon_uuid = get_current_taxon_uuid();
1003
      $block['subject'] = '<none>';
1004
      $block['content'] = compose_taxonomic_children($taxon_uuid);
1005
      return $block;
1006
    case 'back_to_search_results':
1007
      $block['subject'] = '<none>';
1008
      if (isset($_SESSION['cdm']['search'])) {
1009
        $block['content'] = l(t('Back to search result'), "http://" . $_SERVER['SERVER_NAME'] . $_SESSION['cdm']['last_search']);
1010
      }
1011
      return $block;
1012
    case 'registrations_search_filter':
1013
      $block['subject'] = '<none>';
1014
      $block['content'] = drupal_get_form('cdm_dataportal_search_registration_filter_form'); // see cdm_dataportal_search_registration_filter_form($form, &$form_state)
1015
      return $block;
1016
    case 'registrations_search_taxongraph':
1017
      $block['subject'] = '<none>';
1018
      $block['content'] = drupal_get_form('cdm_dataportal_search_registration_taxongraph_form'); // see cdm_dataportal_search_registration_taxongraph_form($form, &$form_state)
1019
      return $block;
1020
    case 'registrations_search':
1021
      _add_js_ui_accordion();
1022
      _add_font_awesome_font();
1023
      $block['subject'] = '<none>';
1024
      $filter_form = drupal_get_form('cdm_dataportal_search_registration_filter_form');
1025
      $filter_form['#prefix'] = '<div>';
1026
      $filter_form['#suffix'] = '</div>';
1027
      $taxongraph_form = drupal_get_form('cdm_dataportal_search_registration_taxongraph_form');
1028
      $taxongraph_form['#prefix'] = '<div>';
1029
      $taxongraph_form['#suffix'] = '</div>';
1030
      $block['content'] = array(
1031
        'accordion' => array(
1032
          '#markup' => '',
1033
          '#prefix' => '<div id="accordion">',
1034
          '#suffix' => '</div>',
1035
          'content' => array(
1036
            array('#markup' => '<h3>Filter</h3>'),
1037
            $filter_form,
1038
            array('#markup' => '<h3>Taxon graph</h3>'),
1039
            $taxongraph_form,
1040
          )
1041
        )
1042
    );
1043
       return $block;
1044
    case 'utis_search':
1045
      _add_js_utis_client('.utis_client');
1046
      $block['subject'] = '<none>';
1047
      $block['content'] = '<div class="utis_client"></div>';
1048
      return $block;
1049
    default:
1050
      return null;
1051
  }
1052
}
1053

    
1054

    
1055
/**
1056
 * Provides the uuid of the taxon for pages with the path ./taxon/{taxon_uuid}
1057
 *
1058
 * @return string
1059
 *   the taxon uuid or NULL
1060
 */
1061
function get_current_taxon_uuid()
1062
{
1063
  static $taxon_uuid;
1064

    
1065
  if(!isset($taxon_uuid)){
1066
    if(isset($_REQUEST['currentTaxon']) && is_uuid($_REQUEST['currentTaxon'])) {
1067
      $taxon_uuid = $_REQUEST['currentTaxon'];
1068
    } else if (arg(1) == 'taxon' && is_uuid(arg(2))) {
1069
      $taxon_uuid = arg(2);
1070
    } else {
1071
      $taxon_uuid = null;
1072
    }
1073
  }
1074

    
1075
  return $taxon_uuid;
1076
}
1077

    
1078
/**
1079
 * Returns the currently classification tree in use.
1080
 *
1081
 * @return string
1082
 *   The uuid of the currently focused classification
1083
 */
1084
function get_current_classification_uuid() {
1085
  if (isset($_SESSION['cdm']['taxonomictree_uuid']) && is_uuid($_SESSION['cdm']['taxonomictree_uuid'])) {
1086
    return $_SESSION['cdm']['taxonomictree_uuid'];
1087
  }
1088
  else {
1089
    return variable_get(CDM_TAXONOMICTREE_UUID, FALSE);
1090
  }
1091
}
1092

    
1093
/*
1094
 function cdm_dataportal_session_clear($cdm_ws_uri_update = FALSE){
1095
 $_SESSION['cdm'] = NULL;
1096
 if(is_string($cdm_ws_uri_update)){
1097
 $_SESSION['cdm'] = array('ws_uri'=>$cdm_ws_uri_update);
1098
 }
1099
 }
1100

    
1101
 function cdm_dataportal_session_validate(){
1102
 if(!isset($_SESSION['cdm']['ws_uri'])){
1103
 $_SESSION['cdm'] = array('ws_uri'=>variable_get('cdm_webservice_url', FALSE));
1104
 } else if($_SESSION['cdm']['ws_uri'] != variable_get('cdm_webservice_url', FALSE)){
1105
 cdm_dataportal_session_clear(variable_get('cdm_webservice_url', FALSE));
1106
 }
1107
 }
1108
 */
1109

    
1110
/**
1111
 * creates a  selector form for taxonomic trees.
1112
 *
1113
 * @return array
1114
 *  a drupal form array
1115
 */
1116
function cdm_taxonomictree_selector() {
1117
  _add_js_treeselector();
1118

    
1119
  $form = drupal_get_form('cdm_taxonomictree_selector_form');
1120
  return $form;
1121
}
1122

    
1123
/**
1124
 * @todo Please document this function.
1125
 * @see http://drupal.org/node/1354
1126
 *
1127
 * @deprecated use compose_classification_selector instead
1128
 */
1129
function cdm_taxonomictree_selector_form($form, &$form_state) {
1130

    
1131
  $url = url('cdm_api/setvalue/session', array('query' => NULL));
1132
  $form['#action'] = $url;
1133

    
1134
  $form['var'] = array(
1135
    '#weight' => -3,
1136
    '#type' => 'hidden',
1137
    '#value' => '[cdm][taxonomictree_uuid]',
1138
  );
1139

    
1140
  $destination_array = drupal_get_destination();
1141
  $destination = $destination_array['destination'];
1142

    
1143
  $form['destination'] = array(
1144
    '#weight' => -3,
1145
    '#type' => 'hidden',
1146
    '#value' =>  $destination,
1147
  );
1148

    
1149
  $options = cdm_get_taxontrees_as_options();
1150
  $taxontree_includes = variable_get(CDM_TAXONTREE_INCLUDES, null);
1151
  if($taxontree_includes){
1152
    $filtered_options = array();
1153
    foreach($options as $uuid=>$label){
1154
      if(!empty($taxontree_includes[$uuid])){
1155
        $filtered_options[$uuid] = $label;
1156
      }
1157
    }
1158
    $options = $filtered_options;
1159
  }
1160

    
1161
  $form['val'] = array(
1162
    '#type' => 'select',
1163
    '#title' => t('Available classifications'),
1164
    '#default_value' => get_current_classification_uuid(),
1165
    '#options' => $options,
1166
    '#attributes' => array('class' => array('highlite-first-child')),
1167
  );
1168

    
1169
  return $form;
1170

    
1171
}
1172

    
1173
/**
1174
 *
1175
 * @ingroup compose
1176
 */
1177
function compose_classification_selector() {
1178

    
1179
  $destination_array = drupal_get_destination();
1180
  $destination = $destination_array['destination'];
1181

    
1182
  $options = cdm_get_taxontrees_as_options();
1183
  $items = array();
1184
  $taxontree_includes = variable_get(CDM_TAXONTREE_INCLUDES, null);
1185

    
1186
  $current_classification_uuid = get_current_classification_uuid();
1187

    
1188

    
1189
  foreach($options as $uuid=>$label){
1190
    if(!$taxontree_includes || !empty($taxontree_includes[$uuid])){
1191

    
1192
      $class_attributes = '';
1193
      if($current_classification_uuid == $uuid){
1194
        $class_attributes  = array('focused');
1195
      }
1196
      $items[] = array(
1197
        'data' => l($label,
1198
          'cdm_api/setvalue/session',
1199
          array(
1200
            'query' => array(
1201
              'destination' => $destination,
1202
              'val' => $uuid,
1203
              'var' => '[cdm][taxonomictree_uuid]'
1204
            ),
1205
          )
1206
        ),
1207
        'class' => $class_attributes
1208
      );
1209
    }
1210
  }
1211

    
1212
  $render_array = array(
1213
    '#theme' => 'item_list',
1214
    '#type' => 'ul',
1215
    '#items' => $items
1216
  );
1217

    
1218
  return $render_array;
1219
}
1220

    
1221

    
1222
/* UNREACHABLE since action of form directly links to view.
1223
 function cdm_dataportal_search_taxon_form_submit($form_id, $form_values) {
1224

    
1225
 $_SESSION['cdm']['search'] = $form_values;
1226
 //return '/cdm_dataportal/search/taxon/'.$form_values['queryString'].'/'.($form_values['vernacular']?'1':'0').'/'.$form_values['language'];
1227
 return '/cdm_dataportal/search/taxon/'.$form_values['queryString'].'/'.($form_values['onlyAccepted']?'1':'0');
1228
 //$paramstr = compose_url_prameterstr($form_values);
1229
 //return url('/cdm_dataportal/search/taxon/', array('query' => $paramstr));
1230
 }
1231
 */
1232
/* ====================== menu callback functions ====================== */
1233
/**
1234
 * @todo Please document this function.
1235
 * @see http://drupal.org/node/1354
1236
 */
1237
/*
1238
function cdm_dataportal_form_alter(&$form, &$form_state, $form_id) {
1239
  static $comment_node_disabled =  0;
1240
  static $comment_node_read_only =  1;
1241
  static $comment_node_read_write =  2;
1242

    
1243
  if ($form_id == 'node_type_form'
1244
   && isset($form['identity']['type'])
1245
   && array_key_exists($form['#node_type']->type, cdm_get_nodetypes())
1246
  ) {
1247
    $form['workflow']['comment'] = array(
1248
      '#type' => 'radios',
1249
      '#title' => t('Default comment setting'),
1250
      '#default_value' => variable_get('comment__' . $node->type . $form['#node_type']->type, $comment_node_disabled),
1251
      '#options' => array(t('Disabled'), t('Read only'), t('Read/Write')),
1252
      '#description' => t('Users with the <em>administer comments</em> permission will be able to override this setting.'),
1253
    );
1254
  }
1255
}
1256
*/
1257

    
1258
/**
1259
 * Displays a list of the known taxonomic names.
1260
 *
1261
 * When the list of taxonomic names is displayed, long lists are split up into
1262
 * multiple pages.
1263
 *
1264
 * TODO: Parameters are still preliminary.
1265
 *
1266
 * @param string $beginsWith
1267
 * @param string $page
1268
 *   Page number to diplay defaults to page 1.
1269
 * @param bool $onlyAccepted
1270
 */
1271
function cdm_dataportal_view_names($beginsWith = 'A', $page = 1, $onlyAccepted = FALSE) {
1272

    
1273
  $out = t('<h3>Sorry, the name list feature is not yet available in this version of the DataPortal software<h3>');
1274

    
1275
  /*
1276
  // FIXME the filter for accepted names will be a form element, thus this
1277
  // widget should be generated via form api preferably as block.
1278
  $out  = theme('cdm_dataportal_widget_filter_accepted', $onlyAccepted);
1279
  $out .= theme('cdm_dataportal_widget_names_list', $names, $page);
1280
  $out .= theme('cdm_listof_taxa', $taxonPager);
1281
  return $out;
1282
  */
1283
}
1284

    
1285
/**
1286
 * @todo Please document this function.
1287
 * @see http://drupal.org/node/1354
1288
 * @throws Exception
1289
 */
1290
function cdm_dataportal_view_reference($uuid, $arg2 = NULL) {
1291

    
1292
  cdm_check_valid_portal_page();
1293

    
1294
  return compose_cdm_reference_page($uuid);
1295
}
1296

    
1297
/**
1298
 * Creates a view on a all references contained in the portal.
1299
 *
1300
 * This function is used at the path cdm_dataportal/reference/list
1301
 */
1302
function cdm_dataportal_view_reference_list($pageNumber) {
1303
  $referencePager = cdm_ws_page(CDM_WS_REFERENCE, variable_get('cdm_dataportal_search_items_on_page', CDM_DATAPORTAL_SEARCH_ITEMS_ON_PAGE), $pageNumber);
1304
  cdm_reference_pager($referencePager, 'cdm_dataportal/reference/list/');
1305
}
1306

    
1307
/**
1308
 * @todo Please document this function.
1309
 * @see http://drupal.org/node/1354
1310
 */
1311
function cdm_dataportal_view_media($mediaUuid, $mediarepresentation_uuid = FALSE, $part = 0) {
1312

    
1313
  cdm_check_valid_portal_page();
1314

    
1315
  $media = cdm_ws_get(CDM_WS_PORTAL_MEDIA, $mediaUuid);
1316
  if (!$media) {
1317
    drupal_set_title(t('Media does not exist'), PASS_THROUGH);
1318
    return "";
1319
  }
1320
  return theme('cdm_media_page', array(
1321
    'media' => $media,
1322
    'mediarepresentation_uuid' => $mediarepresentation_uuid,
1323
    'partId' => $part,
1324
    ));
1325
}
1326

    
1327
/**
1328
 * @todo Please document this function.
1329
 * @see http://drupal.org/node/1354
1330
 */
1331
function _load_taxonBase(&$taxonBase) {
1332
  if (isset($taxonBase->uuid)) {
1333
    $taxonBase->name = cdm_ws_get(CDM_WS_TAXON, array($taxonBase->uuid, "name"));
1334
    $taxonBase->name->taggedName = cdm_ws_get(CDM_WS_NAME, array($taxonBase->name->uuid, "taggedName"));
1335
    $taxonBase->name->nomenclaturalReference = cdm_ws_get(CDM_WS_NAME, array($taxonBase->name->uuid, "nomenclaturalReference"));
1336
  }
1337
}
1338

    
1339
/**
1340
 * Loads the media associated to the given taxon from the cdm server.
1341
 * The aggregation settings regarding taxon relathionships and
1342
 * taxonnomic childen are taken into account.
1343
 *
1344
 * The media lists are cached in a static variable.
1345
 *
1346
 * @param Taxon $taxon
1347
 *   A CDM Taxon entity
1348
 *
1349
 * @return array
1350
 *   An array of CDM Media entities
1351
 *
1352
 */
1353
  function _load_media_for_taxon($taxon) {
1354

    
1355
  static $media = NULL;
1356

    
1357
  if(!isset($media)) {
1358
    $media = array();
1359
  }
1360
  if (!isset($media[$taxon->uuid])) {
1361

    
1362

    
1363
    $mediaQueryParameters = taxon_media_query_parameters();
1364

    
1365
    $ws_endpoint = NULL;
1366
    if ( $mediaQueryParameters['includeTaxonomicChildren']) {
1367
      $ws_endpoint = CDM_WS_PORTAL_TAXON_SUBTREE_MEDIA;
1368
    } else {
1369
      $ws_endpoint = CDM_WS_PORTAL_TAXON_MEDIA;
1370
    }
1371
    // this parameter is not yet used by the CDM_WS_PORTAL_TAXON_*MEDIA
1372
    // services
1373
    unset($mediaQueryParameters['includeTaxonomicChildren']);
1374

    
1375
    $media[$taxon->uuid] = cdm_ws_get($ws_endpoint,
1376
        array(
1377
            $taxon->uuid,
1378
        ),
1379
        queryString($mediaQueryParameters)
1380
       );
1381
  }
1382

    
1383
  return $media[$taxon->uuid];
1384
}
1385

    
1386
/**
1387
 *
1388
 * @param Taxon $taxon
1389
 *   A CDM Taxon entitiy
1390
 *
1391
 * @return array
1392
 *   An array of CDM SpecimenOrObservation entities
1393
 *
1394
function _load_occurences_for_taxon($taxon){
1395

    
1396
  static $occurences = NULL;
1397

    
1398
  if(!isset($occurences)) {
1399
    $occurences = array();
1400
  }
1401

    
1402
  if (!isset($occurences[$taxon->uuid])){
1403

    
1404
    $relationship_choice = variable_get(CDM_AGGREGATE_BY_TAXON_RELATIONSHIPS, unserialize(CDM_AGGREGATE_BY_TAXON_RELATIONSHIPS_DEFAULT));
1405
    $relationship_choice['direct'] = get_selection($relationship_choice['direct']);
1406
    $relationship_choice['invers'] = get_selection($relationship_choice['invers']);
1407

    
1408
    $by_associatedtaxon_query = http_build_query(array(
1409
        'relationshipsInvers' => implode(',', $relationship_choice['invers']),
1410
        'relationships' => implode(',', $relationship_choice['direct']),
1411
        'pageSize' => null // all hits in one page
1412
    )
1413
    );
1414

    
1415
    $pager = cdm_ws_get(CDM_WS_OCCURRENCE_BY_ASSOCIATEDTAXON,
1416
        null,
1417
        $by_associatedtaxon_query . '&taxonUuid=' . $taxon->uuid
1418
    );
1419

    
1420

    
1421
    if(isset($pager->records[0])){
1422
      $occurences[$taxon->uuid] =  $pager->records;
1423
    }
1424
  }
1425
  return $occurences[$taxon->uuid];
1426
}
1427
 */
1428

    
1429
/**
1430
 * Gets a Drupal variable, string or array and returns it.
1431
 *
1432
 * Similar to the variable_get() function of Drupal, except that this function
1433
 * is able to handle arrays correctly. This function is especially useful
1434
 * when dealing with collections of settings form elements (#tree = TRUE).
1435
 *
1436
 * @param string $variableKey
1437
 *   The Unique key of the Drupal variable in the Drupal variables table.
1438
 * @param string $defaultValueString
1439
 *   A string as for example derived from a CONSTANT.
1440
 *
1441
 * @return mixed
1442
 *   usually an array, depending on the nature of the variable.
1443
 *
1444
 * TODO compare with get_array_variable_merged() duplicate functions?
1445
 * @deprecated rather use get_array_variable_merged() since this function
1446
 * used an array as second parameter
1447
 */
1448
function mixed_variable_get($variableKey, $defaultValueString) {
1449
  $systemDefaults = unserialize($defaultValueString);
1450
  $storedSettings = variable_get($variableKey, array());
1451
  if (is_array($storedSettings)) {
1452
    // TODO better use drupal_array_merge_deep() ?
1453
    $settings = array_merge($systemDefaults, $storedSettings);
1454
  }
1455
  else {
1456
    $settings = $systemDefaults;
1457
  }
1458
  return $settings;
1459
}
1460

    
1461
/**
1462
 * Recursive function to convert an object into an array.
1463
 * also subordinate objects will be converted.
1464
 *
1465
 * @param object $object
1466
 *  the object to be converted
1467
 * @return array
1468
 *  The array
1469
 */
1470
function object_to_array($object) {
1471
  if(is_object($object) || is_array($object)) {
1472
    $array = (array)$object;
1473
    foreach ($array as $key=>$value){
1474
      $array[$key] = object_to_array($value);
1475
    }
1476
    return $array;
1477
  } else {
1478
    return $object;
1479
  }
1480
}
1481

    
1482
/**
1483
 * Searches the $collection for the cdm entitiy given as $element.
1484
 *
1485
 * The elements are compared by their UUID.
1486
 *
1487
 * @param $element
1488
 *  the CDM entitiy to search for
1489
 * @param $collection
1490
 *  the list of CDM entities to search in
1491
 *
1492
 * @return boolean TRUE if the $collection contains the $element, otheriwse FALSE
1493
 *
1494
 */
1495
function contains_cdm_entitiy($element, $collection) {
1496
  $result = FALSE;
1497
  foreach ($collection as $a) {
1498
    if ($a->uuid == $element->uuid) {
1499
      $result = TRUE;
1500
    }
1501
  }
1502
  return $result;
1503
}
1504

    
1505
/**
1506
 * Filters the array $entity_list of CDM entities by the list
1507
 * of $excludes. Any element contained in the $excludes will be removed
1508
 * from included int the returned list.
1509
 *
1510
 * If the $entity_list is not an array the $excludes will be returned.
1511
 */
1512
function filter_cdm_entity_list($entity_list, $excludes) {
1513
  if (is_array($entity_list)) {
1514
    $result = $entity_list;
1515
    if ($excludes) {
1516
      foreach ($excludes as $exclude) {
1517
        if (!contains_cdm_entitiy($exclude, $entity_list)) {
1518
          $result[] = $exclude;
1519
        }
1520
      }
1521
    }
1522
  }
1523
  else {
1524
    $result = $excludes;
1525
  }
1526
  return $result;
1527
}
1528

    
1529
/**
1530
 * Wraps the given $html string into a render array suitable for drupal_render()
1531
 *
1532
 * @param $html
1533
 *   the html string, see
1534
 *   http://api.drupal.org/api/drupal/developer!topics!forms_api_reference.html/7#markup
1535
 * @param $weight
1536
 *   A positive or negative number (integer or decimal).
1537
 *   see http://api.drupal.org/api/drupal/developer!topics!forms_api_reference.html/7#weightval
1538
 * @param $prefix
1539
 *   Optional markup for the '#prefix' element of the render array
1540
 * @param $suffix
1541
 *   Optional markup for the '#suffix' element of the render array
1542
 *
1543
 * @return array
1544
 *   A render array
1545
 *
1546
 */
1547
function markup_to_render_array($html, $weight = FALSE, $prefix = NULL, $suffix = NULL) {
1548
  $render_array = array(
1549
    '#markup' => $html
1550
      );
1551
  if (is_numeric($weight)) {
1552
    $render_array['#weight'] = $weight;
1553
  }
1554
  if($prefix){
1555
    $render_array['#prefix'] = $prefix;
1556
  }
1557
  if($suffix) {
1558
    $render_array['#suffix'] = $suffix;
1559
  }
1560
  return $render_array;
1561
}
1562

    
1563
/**
1564
 * Loads the subgraph of a given PolytomousKeyNode.
1565
 *
1566
 * Loads the subgraph of the given PolytomousKeyNode recursively from
1567
 * the CDM REST service.
1568
 *
1569
 * @param mixed $polytomousKeyNode
1570
 *   PolytomousKeyNode passed by reference.
1571
 *
1572
 * @return void
1573
 */
1574
function _load_polytomousKeySubGraph(&$polytomousKeyNode) {
1575

    
1576
  if (!$polytomousKeyNode) {
1577
    return;
1578
  }
1579
  if ($polytomousKeyNode->class != "PolytomousKeyNode") {
1580
    drupal_set_message('_load_polytomousKeySubGraph(): ' . t('invalid type given.'), 'error');
1581
    return;
1582
  }
1583
  if (!is_uuid($polytomousKeyNode->uuid)) {
1584
    drupal_set_message('_load_polytomousKeySubGraph(): ' . t('invalid type given.'), 'error');
1585
    return;
1586
  }
1587

    
1588
  $polytomousKeyNode = cdm_ws_get(CDM_WS_POLYTOMOUSKEY_NODE, $polytomousKeyNode->uuid);
1589

    
1590
  if (!$polytomousKeyNode) {
1591
    // drupal_set_message("_load_polytomousKeyChildNodes() : could not load polytomousKeyNode", "error");
1592
    return;
1593
  }
1594

    
1595
  // Load children.
1596
  foreach ($polytomousKeyNode->children as &$childNode) {
1597
    _load_polytomousKeySubGraph($childNode);
1598
  }
1599

    
1600
  // Load subkey.
1601
  $polytomousKeyNode->subkey = cdm_ws_get(CDM_WS_POLYTOMOUSKEY_NODE, array($polytomousKeyNode->uuid, "subkey"));
1602

    
1603
  // Load taxon.
1604
  $polytomousKeyNode->taxon = cdm_ws_get(CDM_WS_POLYTOMOUSKEY_NODE, array($polytomousKeyNode->uuid, "taxon"));
1605
  _load_taxonBase($polytomousKeyNode->taxon);
1606
  return;
1607
}
1608

    
1609
/**
1610
 * @todo Please document this function.
1611
 * @see http://drupal.org/node/1354
1612
 */
1613
function cdm_dataportal_view_polytomousKey($polytomousKeyUuid) {
1614

    
1615
  cdm_check_valid_portal_page();
1616

    
1617
  $polytomousKey = cdm_ws_get(CDM_WS_POLYTOMOUSKEY, $polytomousKeyUuid);
1618
  if (!$polytomousKey) {
1619
    drupal_set_title(t('Polytomous key does not exist'), PASS_THROUGH);
1620
    return "";
1621
  }
1622

    
1623
  $sourcePager = cdm_ws_get(CDM_WS_POLYTOMOUSKEY, array($polytomousKeyUuid, 'sources'));
1624
  if (is_array($sourcePager->records)) {
1625
    $polytomousKey->sources = $sourcePager->records;
1626
    // $polytomousKey->sources->citation = cdm_ws_get(CDM_WS_POLYTOMOUSKEY, array($polytomousKeyUuid, 'sources'));
1627
  }
1628

    
1629
  $annotationPager = cdm_ws_get(CDM_WS_POLYTOMOUSKEY, array($polytomousKeyUuid, 'annotations'));
1630
  if (is_array($annotationPager->records)) {
1631
    $polytomousKey->annotations = $annotationPager->records;
1632
  }
1633

    
1634
  _load_polytomousKeySubGraph($polytomousKey->root);
1635
  return theme('cdm_polytomousKey_page', array('polytomousKey' => $polytomousKey));
1636
}
1637

    
1638
/**
1639
 * Creates a taxon page view or a chapter of it.
1640
 *
1641
 * The taxon page gives detailed information on a taxon, it shows:
1642
 *  - Taxon name.
1643
 *  - Full list of synonyms homotypic synonyms on top, followed by the
1644
 *    heterotypic and finally followed by misapplied names.
1645
 *    The list is ordered historically.
1646
 *  - All description associated with the taxon.
1647
 *
1648
 * @param string $uuid
1649
 * @param string $chapter
1650
 *   Name of the part to display, valid values are:
1651
 *   'description', 'images', 'synonymy', 'specimens', 'all'.
1652
 *
1653
 * @return string
1654
 */
1655
function cdm_dataportal_taxon_page_view($uuid, $chapter = 'all') {
1656

    
1657
  cdm_check_valid_taxon_page($chapter);
1658
  cdm_dd("START OF TAXON PAGE [" . $chapter . "] " . $uuid . ' for ' . $_GET['q']);
1659

    
1660

    
1661
  // Display the page for the taxon defined by $uuid.
1662
  // set_last_taxon_page_tab(arg(3));
1663
  $taxonpage = cdm_dataportal_taxon_view($uuid, $chapter);
1664
  if (!empty($taxonpage)) {
1665
    cdm_dd("END OF TAXON PAGE [" . $chapter . "] " . $uuid);
1666
    return cdm_node_show(NODETYPE_TAXON, $uuid, $taxonpage->title, $taxonpage->content);
1667
  }
1668
  else {
1669
    cdm_dd("END OF TAXON PAGE [" . $chapter . "] " . $uuid . ' !!! PAGE IS EMPTY !!!');
1670
    return '';
1671
  }
1672
}
1673

    
1674
/**
1675
 * This function will generate the taxon page part ($chapter) and returns a taxonpage object
1676
 * which has two fields, one for the page title and one for the content. Later on in the
1677
 * process chain the value contained in these fields will be passed to the cdm_node_show()
1678
 * function as the function parameters $title and $content.
1679
 *
1680
 * @param string $uuid
1681
 *   the uuid of the taxon to show
1682
 * @param string $chapter
1683
 *   Name of the part to display, valid values are:
1684
 *   'description', 'images', 'synonymy', 'all'.
1685
 *
1686
 * @return object with the following fields:
1687
 *   - title : the title of the page
1688
 *   - content: the content of the page
1689
 *
1690
 * @throws Exception
1691
 *
1692
 */
1693
function cdm_dataportal_taxon_view($uuid, $chapter = 'all') {
1694
  // Taxon object.
1695
  $taxon = cdm_ws_get(CDM_WS_PORTAL_TAXON, $uuid);
1696
  if (empty($taxon)) {
1697
    drupal_set_title(t('Taxon does not exist'), PASS_THROUGH);
1698
    return null;
1699
  }
1700
  $taxonpage = new stdClass();
1701

    
1702
  $taxonpage->title = theme('cdm_taxon_page_title', array(
1703
    'taxon' => $taxon
1704
  ));
1705

    
1706
  // Check if the taxon id contained in the currently selected tree.
1707
  $taxon_in_current_classification = taxon_in_current_classification($uuid);
1708

    
1709
  if (!$taxon_in_current_classification) {
1710
    $classifications = get_classifications_for_taxon($taxon);
1711
    RenderHints::pushToRenderStack('not_in_current_classification');
1712
    $taxon_name_markup = render_taxon_or_name($taxon);
1713

    
1714
    if (count($classifications) == 0) {
1715
      drupal_set_message(t('This concept of the taxon !taxonname is not contained as an accepted taxon in the currently chosen classification.',
1716
        array(
1717
        '!taxonname' => $taxon_name_markup,
1718
        )
1719
      ), 'warning');
1720
    }
1721
    else {
1722
      $trees = '';
1723
      foreach ($classifications as $classification) {
1724
        if (isset($classification->titleCache)) {
1725
          $trees .= ($trees ? ', ' : '') . '<strong>' . $classification->titleCache . '</strong>';
1726
        }
1727
      }
1728

    
1729
      drupal_set_message(format_plural(count($trees),
1730
          'This concept of the taxon !taxonname is not contained as an accepted taxon in the currently chosen classification, but in this one: !trees',
1731
          'This concept of the taxon !taxonname is not contained as an accepted taxon in the currently chosen classification, but in one of these: !trees',
1732
          array('!taxonname' => $taxon_name_markup, '!trees' => $trees)
1733
        ) ,
1734
        'warning');
1735
    }
1736
    RenderHints::popFromRenderStack();
1737
  }
1738

    
1739
  // Render the taxon page.
1740
  $render_array = compose_cdm_taxon_page($taxon, $chapter);
1741
  $taxonpage->content = drupal_render($render_array);
1742

    
1743
  return $taxonpage;
1744
}
1745

    
1746

    
1747
function cdm_dataportal_specimen_by_accession_number_page_view($accession_number)
1748
{
1749
  cdm_check_valid_portal_page();
1750

    
1751
  $specimenpage = specimen_by_accession_number_view($accession_number);
1752

    
1753
  if (!empty($specimenpage)) {
1754
    return cdm_node_show_simulate($specimenpage->content);
1755
  }
1756
  else {
1757
    return '';
1758
  }
1759

    
1760

    
1761
}
1762

    
1763
/**
1764
 * Creates a specimen page view.
1765
 * @param string $uuid the UUID of the specimen
1766
 * @return array|string
1767
 */
1768
function cdm_dataportal_specimen_page_view($uuid) {
1769

    
1770
    cdm_check_valid_portal_page();
1771
    $specimenpage = cdm_dataportal_specimen_view($uuid);
1772
    if (!empty($specimenpage)) {
1773
        return cdm_node_show_simulate($specimenpage->content);
1774
    }
1775
    else {
1776
        return '';
1777
    }
1778
}
1779

    
1780

    
1781
/**
1782
 * Creates a specimen page view.
1783
 * @param string $uuid the UUID of the specimen
1784
 * @return object
1785
 *  The page object with the following fields:
1786
 *   - 'title': the page title
1787
 *   - 'content' : the page content rendered as markup
1788
 */
1789
function specimen_by_accession_number_view($accession_number = null) {
1790

    
1791
  $field_unit_dto = cdm_ws_get(CDM_WS_OCCURRENCE_ACCESSION_NUMBER, null, 'accessionNumber=' . $accession_number);
1792

    
1793
  // Display the page for the specimen defined by $uuid.
1794
  if (isset($field_unit_dto)){
1795
    $dto_array = array($field_unit_dto);
1796
    $specimen_array = specimen_render_array_items($dto_array);
1797
    $specimen_table = array(
1798
      '#theme' => 'table',
1799
      '#weight' => 2,
1800
      // prefix attributes and rows with '#' to let it pass toF the theme function,
1801
      // otherwise it is handled as child render array
1802
      '#attributes' => array('class' => 'specimens'),
1803
      '#rows' => array(),
1804
      '#prefix' => '<div id="specimens">',
1805
      '#suffix' => '</div>',
1806
    );
1807
    foreach($specimen_array as $value){
1808
      $renderArray = array(
1809
        '#theme' => 'item_list',
1810
        '#items' => array($value),
1811
        '#type' => 'ul');
1812
      $output = drupal_render($renderArray);
1813
      $specimen_table['#rows'][] = array(
1814
        // An array of table rows. Every row is an array of cells, or an associative array
1815
        'data' => array($output),
1816
        'class' =>  array(
1817
          'descriptionElement',
1818
          'descriptionElement_IndividualsAssociation'
1819
        ),
1820
      );
1821

    
1822

    
1823
    }
1824
    $specimenpage = new stdClass();
1825

    
1826
    $specimenpage->title = theme('theme_cdm_specimen_dto_page_title', array(
1827
      'specimen' => $field_unit_dto
1828
    ));
1829

    
1830
     $render_array['markup'] = $specimen_table;
1831
     $specimenpage->content = drupal_render($render_array);
1832
  }
1833

    
1834
  return $specimenpage;
1835
}
1836

    
1837

    
1838
/**
1839
 *
1840
 * Creates a specimen view.
1841
 * @param string $uuid the UUID of the specimen
1842
 * @return object
1843
 *    Page object with the fields
1844
 *    - title
1845
 *    - content
1846
 */
1847
function cdm_dataportal_specimen_view($uuid) {
1848
    //TODO: get the derivateDTO and don't call the webservice a second time in compose_cdm_specimen_page
1849
    $specimen = cdm_ws_get(CDM_WS_PORTAL_OCCURRENCE, $uuid);
1850
    if (empty($specimen)) {
1851
        drupal_set_title(t('Specimen does not exist'), PASS_THROUGH);
1852
        return FALSE;
1853
    }
1854
    $specimenpage = new stdClass();
1855

    
1856
    $specimenpage->title = specimen_page_title($specimen);
1857

    
1858
    // Render the specimen page.
1859
    $render_array = compose_cdm_specimen_page($specimen);
1860
    $specimenpage->content = drupal_render($render_array);
1861

    
1862
    return $specimenpage;
1863
}
1864

    
1865
/**
1866
 *
1867
 * Creates a description view.
1868
 *
1869
 * @param string $uuid the UUID of the description
1870
 * @param null $descriptive_dataset_uuid the uuid of the data set which defines
1871
 * the display of the description detail page
1872
 *
1873
 * @return object Page object with the fields
1874
 * Page object with the fields
1875
 * - title
1876
 * - content
1877
 */
1878
function cdm_dataportal_description_view($uuid, $descriptive_dataset_uuid = NULL) {
1879
    $description = cdm_ws_get(CDM_WS_PORTAL_DESCRIPTION, $uuid);
1880
    $description_page = new stdClass();
1881
    if (empty($description)) {
1882
      $description_page->title = t('Description does not exist');
1883
      drupal_set_title($description_page->title, PASS_THROUGH); // not necessary if correctly implemented as drupal node
1884
      $description_page->content = "";
1885

    
1886
    } else {
1887
      $description_page->title = $description->titleCache;
1888
      drupal_set_title($description_page->title); // not necessary if correctly implemented as drupal node
1889

    
1890
      // Render the description page.
1891
      $render_array = compose_description_table($description->uuid, $descriptive_dataset_uuid);
1892
      if($render_array['title']){
1893
        $page_title = strip_tags($render_array['title']['#markup']);
1894
        drupal_set_title($page_title);
1895
        unset($render_array['title']);
1896
      }
1897
      $description_page->content = drupal_render($render_array);
1898
    }
1899

    
1900
    return $description_page;
1901
}
1902

    
1903
function cdm_dataportal_description_page_view($uuid, $descriptive_dataset_uuid = NULL) {
1904

    
1905
  cdm_check_valid_portal_page();
1906
  $descriptionpage = cdm_dataportal_description_view($uuid, $descriptive_dataset_uuid);
1907
  if (!empty($descriptionpage)) {
1908
    return cdm_node_show_simulate($descriptionpage->content);
1909
  }
1910
  else {
1911
    return NULL;
1912
  }
1913
}
1914

    
1915
/**
1916
 *
1917
 * Creates a named area view.
1918
 * @param string $uuid the UUID of the specimen
1919
 *  * @return object
1920
 *   An object with two fields:
1921
 *     - title: the page title
1922
 *     - content: the page content
1923
 */
1924

    
1925
function cdm_dataportal_named_area_view($uuid) {
1926
  $named_area = cdm_ws_get(CDM_WS_PORTAL_TERM, $uuid);
1927
  if (empty($named_area) || $named_area->class !== 'NamedArea') {
1928
    drupal_set_title(t('Named area does not exist'), PASS_THROUGH);
1929
    return null;
1930
  }
1931
  $named_area_page = new stdClass();
1932

    
1933
  $named_area_page->title = $named_area->representation_L10n;
1934

    
1935
  // Render the specimen page.
1936
  $render_array = compose_cdm_named_area_page($uuid);
1937
  $named_area_page->content = drupal_render($render_array);
1938

    
1939
  return $named_area_page;
1940
}
1941

    
1942
function cdm_dataportal_named_area_page_view($uuid) {
1943

    
1944
  cdm_check_valid_portal_page();
1945

    
1946
  $named_area_page = cdm_dataportal_named_area_view($uuid);
1947
  if (!empty($named_area_page)) {
1948
    return cdm_node_show(NODETYPE_NAME, $uuid, $named_area_page->title, $named_area_page->content);
1949
  }
1950
  else {
1951
    return '';
1952
  }
1953

    
1954

    
1955
}
1956

    
1957
/**
1958
 * Returns a name page as a Drupal node ready to be renderized by Drupal.
1959
 *
1960
 * The node page shows the taxon name title and the list of taxon related
1961
 * with such taxon. Name on the tree already in use.
1962
 *
1963
 * @param string $taxon_name_uuid
1964
 *   The uuid of the CDM TaxonName to show a name page for
1965
 * @param string $taxon_to_hide_uuid
1966
 *   A taxon which should not be displayed in the taxon list
1967
 * @param $redirect_to_taxon
1968
 *   Automatically redirect to the related taxon if there is only one
1969
 *   accepted taxon for this name.
1970
 * @param string $highlite_synonym_uuid
1971
 *   Optinal parameter wich takes another taxon uuid, if given the
1972
 *   target taxon pages will show the syonymy tab where the taxon
1973
 *   refenrenced by the $highlite_synonym_uuid will be highlighted
1974
 *   in case it is found on this page.
1975
 *
1976
 * @return mixed
1977
 *   The formatted name page as node.
1978
 */
1979
function cdm_dataportal_name_page_view($taxon_name_uuid, $taxon_to_hide_uuid, $synonym_uuid = NULL, $redirect_to_taxon = false) {
1980

    
1981
  cdm_check_valid_portal_page();
1982

    
1983
  $taxonname_page = cdm_dataportal_name_view(
1984
    is_uuid($taxon_name_uuid) ? $taxon_name_uuid : null,
1985
    is_uuid($taxon_to_hide_uuid) ? $taxon_to_hide_uuid : null,
1986
    $redirect_to_taxon == 'redirect_to_taxon',
1987
    is_uuid($synonym_uuid) ? $synonym_uuid : null);
1988
  if (!empty($taxonname_page)) {
1989
    return cdm_node_show(NODETYPE_NAME, $taxon_name_uuid, $taxonname_page->title, $taxonname_page->content);
1990
  }
1991
  else {
1992
    return '';
1993
  }
1994
}
1995

    
1996
/**
1997
 * View function for a TaxonName page.
1998
 *
1999
 * The name page lists all taxa for which the name specified by the
2000
 * $taxon_name_uuid is being used. I case there is only one name the
2001
 * page automatically redirects ti the according taxon page. Otherwise
2002
 * the list of names is displayed.
2003
 *
2004
 * The parameter $taxon_to_hide_uuid allows to exclude a taxon from the
2005
 * list of taxa. This is useful for example when referencing from a taxon
2006
 * to the name page and the referring taxon should not be repeaded in the
2007
 * name page.
2008
 *
2009
 *
2010
 * @param string $taxon_name_uuid
2011
 *   The uuid of the CDM TaxonName to show a name page for
2012
 * @param string $taxon_to_hide_uuid
2013
 *   A taxon which should not be displayed in the taxon list
2014
 * @param $redirect_to_taxon
2015
 *   Automatically redirect to the related taxon if there is only one
2016
 *   accepted taxon for this name.
2017
 * @param string $highlite_synonym_uuid
2018
 *   Optional parameter which takes another taxon uuid, if given the
2019
 *   target taxon pages will show the synonymy tab where the taxon
2020
 *   referenced by the $highlite_synonym_uuid will be highlighted
2021
 *   in case it is found on this page.
2022
 *
2023
 * @return object|boolean
2024
 *   An object with two fields:
2025
 *     - title: the page title
2026
 *     - content: the page content
2027
 *   or FALSE
2028
 *
2029
 */
2030
function cdm_dataportal_name_view($taxon_name_uuid, $taxon_to_hide_uuid, $redirect_to_taxon, $highlite_synonym_uuid = NULL) {
2031
  // Getting the full taxonname object from the server.
2032
  $taxon_name = cdm_ws_get(CDM_WS_PORTAL_NAME, array($taxon_name_uuid));
2033
  if (!$taxon_name) {
2034
    drupal_set_title(t('Taxon name does not exist'), PASS_THROUGH);
2035
    return FALSE;
2036
  }
2037
  cdm_load_tagged_full_title($taxon_name);
2038
  // Searching for all the taxa connected with the taxon name on the tree
2039
  // in use.
2040
  $name = cdm_ws_get(CDM_WS_NAME, array($taxon_name_uuid));
2041
  $restrictions = array(new Restriction("name.titleCache","EXACT", array($name->titleCache), 'AND'));
2042
  $init_strategy = array(
2043
    "name.titleCache",
2044
    "name.nomenclaturalReference.authorship",
2045
    "name.nomenclaturalReference.inReference.authorship",
2046
    "name.nomenclaturalReference.inReference.inReference.authorship",
2047
    "name.nomenclaturalReference.inReference.inReference.inReference.authorship"
2048
  );
2049
  $taxa = cdm_ws_fetch_all_by_restriction("Taxon", $restrictions, $init_strategy);
2050

    
2051
  // Removing the name where we came from.
2052
  foreach ($taxa as $k => &$taxon) {
2053
    if ($taxon->uuid == $taxon_to_hide_uuid) {
2054
      unset($taxa[$k]);
2055
    }
2056
  }
2057
  // Show the taxa list or go to the singular taxon.
2058
  if (sizeof($taxa) == 1 && $redirect_to_taxon) {
2059
    // redirect to the taxon if there is only one.
2060
    $singleTaxon = array_pop($taxa);
2061
    if ($singleTaxon->class != "Taxon") {
2062
      // It is a Synonym -> look for the accepted.
2063
      $accepted_taxon = cdm_ws_get(CDM_WS_PORTAL_TAXON_ACCEPTED, array($singleTaxon->uuid), 'classificationFilter=' . get_current_classification_uuid());
2064
      if (!empty($highlite_synonym_uuid)) {
2065
        drupal_goto('cdm_dataportal/taxon/' . $accepted_taxon->uuid . '/synonymy', array('query' => array('highlite' => $highlite_synonym_uuid)));
2066
      }
2067
      else {
2068
        drupal_goto('cdm_dataportal/taxon/' . $accepted_taxon->uuid . '/synonymy', array('query' => array('highlite' => $singleTaxon->uuid)));
2069
      }
2070
    }
2071
    else {
2072
      // It is an accepted taxon.
2073
      if (!empty($highlite_synonym_uuid)) {
2074
        drupal_goto('cdm_dataportal/taxon/' . $singleTaxon->uuid . '/synonymy', array('query' => array('highlite' => $highlite_synonym_uuid)));
2075
      }
2076
      else {
2077
        drupal_goto('cdm_dataportal/taxon/' . $singleTaxon->uuid);
2078
      }
2079
    }
2080
  }
2081
  else {
2082
    // display the name page content
2083
    $taxon_name_page = new stdClass();
2084
    $taxon_name_page->title = theme('cdm_name_page_title', array('taxon_name' => $taxon_name));
2085
    $content = array();
2086

    
2087
    RenderHints::pushToRenderStack('name_page');
2088
    RenderHints::setFootnoteListKey('name_page');
2089
    $content['taxon_name'] = markup_to_render_array(render_taxon_or_name($taxon_name), null, '<div class="name-page-name">', '</div>');
2090

    
2091

    
2092
    // name relationships
2093
    $name_relations = cdm_ws_fetch_all(str_replace("$0", $taxon_name->uuid, CDM_WS_PORTAL_NAME_NAME_RELATIONS));
2094
    if(count($name_relations) > 0){
2095
      $content['name_relationships'] = compose_name_relationships_list($name_relations, $taxon_name->uuid, null);
2096
    }
2097

    
2098
    // type designations
2099
    $type_designations_render_array = compose_type_designations($taxon_name->uuid);
2100
    $content = array_merge($content, $type_designations_render_array);
2101
    // registrations
2102
    $registrationDTOs= cdm_ws_fetch_all(CDM_WS_REGISTRATION_DTO,  array('nameUuid' => $taxon_name_uuid));
2103
    if(isset($registrationDTOs) && count($registrationDTOs ) > 0 ){
2104
      $content['registrations'][] = markup_to_render_array('<h2>' . t("Registrations") . '</h2>') ;
2105
      foreach ($registrationDTOs as $regDTO){
2106
        $content['registrations'][] = compose_registration_dto_compact($regDTO);
2107
      }
2108
    }
2109

    
2110

    
2111
    // related taxa
2112
    $show_taxa_section = variable_get(CDM_NAME_PAGE_SECTION_TAXA, CDM_NAME_PAGE_SECTION_TAXA_DEFAULT);
2113
    if($show_taxa_section){
2114
      if ($taxa) {
2115
        $content['related_taxa_header'] = markup_to_render_array("<h2>Taxa for this name</h2>");
2116
        $content['related_taxa'] = compose_list_of_taxa($taxa);
2117
      }
2118
      else {
2119
        $content['related_taxa'] = markup_to_render_array('This name is not assigned to a taxon.', null, '<div class="no-taxon-message">', '</div>');
2120
      }
2121
    }
2122

    
2123
    $content['footnotes'] = markup_to_render_array(theme('cdm_footnotes', array('footnoteListKey' => RenderHints::getFootnoteListKey())));
2124

    
2125
    $taxon_name_page->content = $content;
2126
    RenderHints::popFromRenderStack();
2127
    RenderHints::clearFootnoteListKey();
2128
    return $taxon_name_page;
2129
  }
2130
}
2131

    
2132

    
2133
/**
2134
 * Returns a registration page as a Drupal node to be rendered by Drupal.
2135
 *
2136
 * @param string  $registration_identifier_encoded
2137
 *   The persistent identifier of the registration urlencoded.
2138
 * @return mixed
2139
 *   The formatted registration page as node.
2140
 */
2141
function cdm_dataportal_registration_page_view($registration_identifier_encoded) {
2142

    
2143
  cdm_check_valid_portal_page("/\/cdm_dataportal\/registration\/.*$/");
2144
  $registration_page = cdm_dataportal_registration_view($registration_identifier_encoded);
2145
  return cdm_node_show_simulate($registration_page);
2146
}
2147

    
2148
/**
2149
 * @param $registration_identifier_encoded
2150
 * @return array
2151
 *   The drupal render array for the registration view.
2152
 */
2153
function cdm_dataportal_registration_view($registration_identifier_encoded) {
2154

    
2155
  $registration_identifier = urldecode($registration_identifier_encoded);
2156

    
2157
  RenderHints::pushToRenderStack('registration_page');
2158
  RenderHints::setFootnoteListKey('registration_page');
2159

    
2160
  $render_array = array();
2161
  $registration_dto = cdm_ws_get(CDM_WS_REGISTRATION_DTO_BY_IDENTIFIER . $registration_identifier_encoded);
2162
  if($registration_dto){
2163

    
2164
    drupal_set_title(t('Registration Id:') . ' ' . $registration_identifier, PASS_THROUGH);
2165
    $render_array = compose_registration_dto_full($registration_dto, true);
2166

    
2167
  } else {
2168
    $status_text = cdm_ws_get(CDM_WS_REGISTRATION_STATUS_BY_IDENTIFIER, array($registration_identifier));
2169
    if(isset($status_text->String)) {
2170
      $status_text = strtolower($status_text->String);
2171
      if($status_text == 'preparation' || $status_text == 'curation'){
2172
        $status_text = 'in ' . $status_text;
2173
      }
2174
      drupal_set_title(t('Registration ' . $status_text), PASS_THROUGH);
2175
      //$status_message;
2176
      drupal_set_message("A registration with the identifier  " . $registration_identifier . " is " . $status_text, "status");
2177
    } else {
2178
      drupal_set_title(t('Registration not found'), PASS_THROUGH);
2179
      drupal_set_message("A registration with the identifier  " . $registration_identifier . " does not exist", "warning");
2180
    }
2181
  }
2182

    
2183
  $render_array = array(
2184
    '#prefix' => '<div id="registration">',
2185
    'registration' => $render_array,
2186
    '#suffix' => '</div>',
2187
  );
2188

    
2189
  RenderHints::popFromRenderStack();
2190
  RenderHints::clearFootnoteListKey();
2191

    
2192
  return $render_array ;
2193
}
2194

    
2195

    
2196
/**
2197
 * Creates a page with the advance search form.
2198
 *
2199
 * NOTE: The advance search form allows searching for taxa.
2200
 */
2201
function cdm_dataportal_view_search_advanced() {
2202
  drupal_set_title(t('Advanced search'), PASS_THROUGH);
2203
  return drupal_get_form('cdm_dataportal_search_taxon_form_advanced');
2204
}
2205

    
2206
/**
2207
 * Creates a page with the blast search form.
2208
 *
2209
 * NOTE: The advance search form allows searching for specimen in blast DB.
2210
 */
2211
function cdm_dataportal_view_search_blast() {
2212
    drupal_set_title(t('Blast search'), PASS_THROUGH);
2213
    return drupal_get_form('cdm_dataportal_search_blast_form');
2214
}
2215

    
2216
/**
2217
 * Creates a page with the search form for searching by taxon descriptions.
2218
 */
2219
function cdm_dataportal_view_search_taxon_by_description() {
2220
  drupal_set_title(t('Search by factual data'), PASS_THROUGH);
2221
  return drupal_get_form('cdm_dataportal_search_taxon_by_description_form');
2222
}
2223

    
2224
/**
2225
 * Executes the search and generates the result list of taxa.
2226
 */
2227
function cdm_dataportal_view_search_results_taxon() {
2228

    
2229
  $taxonPager = cdm_dataportal_search_taxon_execute();
2230

    
2231
  $showThumbnails = do_showThumbnails();
2232

    
2233
  $setSessionUri = url('cdm_api/setvalue/session', array(
2234
      'query' => array('var' => '[pageoption][searchtaxa][showThumbnails]', 'val' => ''),
2235
  ));
2236

    
2237
  drupal_add_js('jQuery(document).ready(function() {
2238

    
2239
      // init
2240
      if(' . $showThumbnails . ' == 1){
2241
          jQuery(\'.media_gallery\').show(20);
2242
      } else {
2243
          jQuery(\'.media_gallery\').hide(20);
2244
      }
2245

    
2246
      // add change handler
2247
      jQuery(\'#showThumbnails input.showThumbnails\').change(
2248
      function(event){
2249
        var state = 0;
2250
        if(jQuery(this).is(\':checked\')){
2251
          jQuery(\'.media_gallery\').show(20);
2252
          state = 1;
2253
        } else {
2254
          jQuery(\'.media_gallery\').hide(20);
2255
        }
2256
        // store state in session variable
2257
        var uri = \'' . $setSessionUri . '\' + state;
2258
        jQuery.get(uri);
2259
      });
2260
  });',
2261
  array('type' => "inline", 'scope' => JS_DEFAULT));
2262

    
2263
  drupal_set_title(t('Search results'), PASS_THROUGH);
2264

    
2265
  return theme('cdm_search_taxa_results', array(
2266
    'pager' => $taxonPager,
2267
    'path' => 'cdm_dataportal/search/results/taxon',
2268
    ));
2269
}
2270

    
2271
/**
2272
 * Executes the blast search and generates the result list of specimen.
2273
 */
2274
function cdm_dataportal_view_search_results_specimen() {
2275

    
2276
    $specimenPager = cdm_dataportal_search_blast_execute();
2277

    
2278
    return theme('cdm_search_specimen_results', array(
2279
        'pager' => $specimenPager,
2280
        'path' => 'cdm_dataportal/search/results/specimen',
2281
    ));
2282
}
2283

    
2284

    
2285
/**
2286
 * Executes the search for registrations and generates the result list..
2287
 */
2288
function cdm_dataportal_view_search_registrations_results($mode = 'filter') {
2289

    
2290
  switch($mode ){
2291
    case 'taxongraph':
2292
      $block = block_load('cdm_dataportal', 'registrations_search_taxongraph');
2293
      $registration_pager = cdm_dataportal_search_registrations_taxongraph_execute();
2294
      break;
2295
    case 'filter':
2296
    default:
2297
      $block = block_load('cdm_dataportal', 'registrations_search_filter');
2298
      $registration_pager = cdm_dataportal_search_registrations_filter_execute();
2299
  }
2300
  $block->title = null;
2301

    
2302
  drupal_set_title(t('Search registrations'), PASS_THROUGH);
2303

    
2304
  $render_array = _block_get_renderable_array(_block_render_blocks(array($block)));
2305
  $registrations_pager_array = compose_registrations_search_results($registration_pager);
2306
  $render_array = array_merge($render_array, $registrations_pager_array);
2307

    
2308
  return $render_array;
2309
}
2310

    
2311

    
2312
/**
2313
 * Provides the standard image which indicated a loading process
2314
 *
2315
 * @return string
2316
 *  The img html tag
2317
 */
2318
function loading_image_html() {
2319
  return '<img class="loading" src="' . base_path() . drupal_get_path('module', 'cdm_dataportal')
2320
    . '/images/loading_circle_grey_16.gif" style="display:none;">';
2321
}
2322

    
2323
/**
2324
 * Returns the state of the the showThumbnails flag set in the
2325
 * users session ($_SESSION['pageoption']['searchtaxa']['showThumbnails']).
2326
 *
2327
 * @return boolean
2328
 *    returns 1 if the flag is set
2329
 */
2330
function do_showThumbnails() {
2331
  static $showThumbnails = null;
2332

    
2333
  if($showThumbnails == null) {
2334
    $showThumbnails = 0;
2335
    if (!isset($_SESSION['pageoption']['searchtaxa']['showThumbnails'])) {
2336
      $showThumbnails = 0;
2337
      $search_gallery_settings = variable_get(CDM_DATAPORTAL_SEARCH_GALLERY_NAME, null);
2338
      $showThumbnails = is_array($search_gallery_settings)
2339
        && isset($search_gallery_settings['cdm_dataportal_show_taxon_thumbnails'])
2340
        && (
2341
            $search_gallery_settings['cdm_dataportal_show_taxon_thumbnails'] +
2342
            $search_gallery_settings['cdm_dataportal_show_synonym_thumbnails'] +
2343
            $search_gallery_settings['cdm_dataportal_show_thumbnail_captions'] > 0
2344
            )
2345
         ? 1 : 0;
2346

    
2347
       drupal_array_set_nested_value($_SESSION, array('pageoption', 'searchtaxa', 'showThumbnails'), $showThumbnails);
2348
    }
2349
    $showThumbnails = $_SESSION['pageoption']['searchtaxa']['showThumbnails'];
2350
    if (!is_numeric($showThumbnails)) {
2351
      $showThumbnails = 1;
2352
    }
2353
  }
2354

    
2355
  return $showThumbnails;
2356
}
2357

    
2358

    
2359

    
2360
/* ====================== other functions ====================== */
2361
/**
2362
 * Creates a URL to the taxon page specified by the $uuid parameter.
2363
 *
2364
 * The URL will be prepended with a path element to a specific taxon page tab.
2365
 *
2366
 * This tab is either taken from the CDM_DATAPORTAL_DEFAULT_TAXON_TAB which can
2367
 * be set globally in the administrative settings or individually in the user
2368
 * profile. If the CDM_DATAPORTAL_DEFAULT_TAXON_TAB value is set to LAST_VISITED_TAB
2369
 * the last portal will stay on this last tab.
2370
 *
2371
 * A third option is offerered by the $page_tab parameter which allows overwriting this
2372
 * internal mechanism by a specific value.
2373
 *
2374
 * @param string $uuid
2375
 *   The UUID of the taxon.
2376
 * @param string $page_tab
2377
 *   Overwriting the preset mechanism by defining specific value for the
2378
 *   taxon page tab.
2379
 * @return string
2380
 *   The created URL.
2381
 */
2382
function path_to_taxon($uuid, $page_tab = FALSE) {
2383

    
2384
  $tab = get_default_taxon_tab();
2385
  $values = unserialize(CDM_DATAPORTAL_DEFAULT_TAXON_TAB);
2386

    
2387
  if (!$uuid) {
2388
    return FALSE;
2389
  }
2390

    
2391
  if ($page_tab) {
2392
    $url = 'cdm_dataportal/taxon/' . $uuid . '/' . $page_tab;
2393
  }
2394
  elseif (!$tab || strtolower($tab) == 'general') {
2395
    $url = 'cdm_dataportal/taxon/' . $uuid;
2396
  }
2397
  elseif (get_last_taxon_page_tab() &&   $tab == $values[CDM_DATAPORTAL_LAST_VISITED_TAB_ARRAY_INDEX]) {
2398
    $url = 'cdm_dataportal/taxon/' . $uuid . '/' . get_last_taxon_page_tab();
2399
  }
2400
  else {
2401
    $url = 'cdm_dataportal/taxon/' . $uuid . '/' . strtolower($tab);
2402
  }
2403
  return $url;
2404
}
2405

    
2406
function path_to_description($uuid, $descriptive_dataset_uuid = NULL) {
2407

    
2408
    if (!$uuid) {
2409
        return FALSE;
2410
    }
2411
    else {
2412
      return 'cdm_dataportal/description/' . $uuid
2413
        . (is_uuid($descriptive_dataset_uuid) ? '/' . $descriptive_dataset_uuid : '');
2414
    }
2415
}
2416

    
2417
function path_to_specimen($uuid) {
2418

    
2419
    if (!$uuid) {
2420
        return FALSE;
2421
    }
2422
    else {
2423
        return 'cdm_dataportal/occurrence/' . $uuid;
2424
    }
2425
}
2426

    
2427
function path_to_specimen_by_accession_number($accession_number) {
2428

    
2429
    if (!$accession_number) {
2430
        return FALSE;
2431
    }
2432
    else {
2433
        return 'cdm_dataportal/specimen/accession_number/' . $accession_number;
2434
    }
2435
}
2436

    
2437
function path_to_named_area($uuid) {
2438

    
2439
  if (!$uuid) {
2440
    return FALSE;
2441
  }
2442
  else {
2443
    return 'cdm_dataportal/named_area/' . $uuid;
2444
  }
2445
}
2446

    
2447
/**
2448
 * Creates a URL to show a synonmy in the according taxon page.
2449
 *
2450
 * The URL will point to the synonymy tab of the taxon page of the accepted taxon given as parameter $acceptedUuid.
2451
 * The resulting URI will include query parameters to highlight the synonym, and to optionally display
2452
 * the accepted taxons name in aform like "Foo bar is accepted taxon for Ree doo". The URI will also
2453
 * include the sysnonym uuid as fragment in order to let the browser scroll to the according location
2454
 * in the page
2455
 *
2456
 * @param string $synonymUuid
2457
 *    The uuid of the synonym
2458
 * @param string $acceptedUuid
2459
 *    The uuid of the according accepted taxon
2460
 * @return string
2461
 *    The URL to show a synonmy in the according taxon page
2462
 */
2463
function uri_to_synonym($synonymUuid, $acceptedUuid) {
2464
  $acceptedPath = path_to_taxon($acceptedUuid, "synonymy");
2465
  return url($acceptedPath, array(
2466
      'query' => array(
2467
        // highlite the synony in the synonymy
2468
        'highlite' => $synonymUuid,
2469
        // the taxon page is refered from a synonym and the synonym can optionally be named in the page title
2470
        // see theme_taxon_page_title()
2471
        'acceptedFor' => $synonymUuid
2472
      ),
2473
      'fragment' => $synonymUuid
2474
  ));
2475

    
2476
}
2477

    
2478
/**
2479
 * Composes the drupal path to the key identified by the uuid.
2480
 *
2481
 * @param string $keyType
2482
 *    the key typer corresponds to the specific class of the CDM
2483
 *    IdentificationKey. Possible values are
2484
 *      -PolytomousKey
2485
 *      -MultimediaKey
2486
 *      - ...
2487
 * @param string $keyUuid
2488
 *   The UUID of the key
2489
 */
2490
function path_to_key($keyType, $keyUuid) {
2491
  if (!$keyUuid || !$keyType) {
2492
    return FALSE;
2493
  }
2494
  $keyType{0} = strtolower($keyType{0});
2495
  return "cdm_dataportal/" . $keyType . "/$keyUuid";
2496
}
2497

    
2498
/**
2499
 * Composes the drupal path to the reference identified by the uuid.
2500
 *
2501
 * @param $uuid string String representation of the registration entity uuid.
2502
 *
2503
 * @return string
2504
 *  The drupal path
2505
 *
2506
 */
2507
function path_to_reference($uuid) {
2508
  if (!$uuid) {
2509
    return FALSE;
2510
  }
2511
  return 'cdm_dataportal/reference/' . $uuid;
2512
}
2513

    
2514
/**
2515
 * Composes the drupal path to the reference identified by the uuid.
2516
 *
2517
 * @param string $identifier
2518
 *  The persistent identifier of the registration entity (Registration.identifier).
2519
 * @return string
2520
 *  The drupal path
2521
 */
2522
function path_to_registration($identifier) {
2523

    
2524
  if(variable_get(CDM_REGISTRATION_PRESISTENT_IDENTIFIER_AS_LINK)){
2525
    return $identifier;
2526
  } else {
2527
    return 'cdm_dataportal/registration/' . urlencode($identifier);
2528
  }
2529
}
2530

    
2531
/**
2532
 * Creates the path to a cdm_dataportal taxon name page.
2533
 *
2534
 * @param string $taxon_name_uuid
2535
 *   The uuid as string of the CDM TaxonName to show a name page for
2536
 * @param string $taxon_to_hide_uuid
2537
 *   The uuid as string of a taxon which should not be displayed in the taxon list
2538
 * @param string $highlited_synonym_uuid
2539
 *   Optional parameter which takes another taxon uuid, if given the
2540
 *   target taxon pages will show the synonymy tab where the taxon
2541
 *   referenced by the $highlite_synonym_uuid will be highlighted
2542
 *   in case it is found on this page.
2543
 * @param $redirect_to_taxon
2544
 *   If true, the name page will redirect to the related taxon if there is a single one
2545
 *   for this name only.
2546
 *
2547
 * @return string
2548
 *  URI path element as string
2549
 */
2550
function path_to_name($name_uuid, $taxon_to_hide_uuid = NULL, $highlited_synonym_uuid  = NULL, $redirect_to_taxon = false) {
2551
  $res = FALSE;
2552
  if ($name_uuid) {
2553
    $res = 'cdm_dataportal/name/' . $name_uuid .
2554
    '/' . (is_uuid($taxon_to_hide_uuid) ? $taxon_to_hide_uuid : "null") .
2555
    '/' . (is_uuid($highlited_synonym_uuid) ? $highlited_synonym_uuid : "null") .
2556
    '/' . ($redirect_to_taxon || variable_get(CDM_NAME_PAGE_AUTOREDIRECT, 0) ? "redirect_to_taxon" : "");
2557
  }
2558

    
2559
  return $res;
2560
}
2561

    
2562
/**
2563
 * Composes the drupal path to the media entity identified by the uuid.
2564
 *
2565
 * @param string $uuid
2566
 *  The persistent identifier of the entity entity
2567
 * @return string
2568
 *  The drupal path
2569
 */
2570
function path_to_media($uuid, $representaion_uuid = FALSE, $partId = FALSE) {
2571
  if (!$uuid) {
2572
    return FALSE;
2573
  }
2574
  $out = 'cdm_dataportal/media/' . $uuid;
2575
  if ($representaion_uuid) {
2576
    $out .= '/' . $representaion_uuid;
2577
    if (is_numeric($partId)) {
2578
      $out .= '/' . $partId;
2579
    }
2580
  }
2581
  return $out;
2582
}
2583

    
2584
/**
2585
 * Compares thisRank with thatRank.
2586
 *
2587
 * Returns a negative integer, zero, or a positive integer
2588
 * as the of thisRank is higher than, equal to, or lower than thatRank.
2589
 * e.g:
2590
 * <ul>
2591
 * <li>rank_compare({species_uuid}, {genus_uuid}) = -1</li>
2592
 * <li>rank_compare({genus_uuid}, {genus_uuid}) = 0</li>
2593
 * <li>rank_compare({genus_uuid}, {tribus_uuid}) = 1</li>
2594
 * </ul>
2595
 * <p>
2596
 * This compare logic of the underlying webservice is the
2597
 * <b>inverse logic</b> of the the one implemented in
2598
 * java.lang.Comparable#compareTo(java.lang.Object)
2599
 *
2600
 * @param $thisRankUuid
2601
 * @param $thatRankUuid
2602
 *
2603
 * @return int
2604
 *   A negative integer, zero, or a positive integer
2605
 *   as the thisRank is lower than, equal to, or higher than thatRank.
2606
 */
2607
function rank_compare($thisRankUuid, $thatRankUuid) {
2608
  $result = cdm_ws_get(CDM_WS_TERM_COMPARE, array($thisRankUuid, $thatRankUuid));
2609
  return $result->Integer;
2610
}
2611

    
2612
/**
2613
 * Creates a short version of a taxonname.
2614
 *
2615
 * The short name is created by using the taggedTitle field of
2616
 * TaxonNodeDTO instances.
2617
 * If the taggedTitle if empty the fullname will be returned.
2618
 *
2619
 * @param object $taxonNodeDTO
2620
 *   A TaxonNodeDTO object
2621
 *
2622
 * @return string
2623
 */
2624
function cdm_dataportal_shortname_of($taxonNodeDTO) {
2625

    
2626
  $nameStr = '';
2627

    
2628
  normalize_tagged_text($taxonNodeDTO->taggedTitle);
2629

    
2630
  // Get all tagged text tokens of the scientific name.
2631
  foreach ($taxonNodeDTO->taggedTitle as $tagtxt) {
2632
    if ($tagtxt->type == 'name' || $tagtxt->type == 'rank') {
2633
      $nameStr .= ($nameStr ? ' ' : '') . $tagtxt->text;
2634
    }
2635
  }
2636
  $nameStr = trim($nameStr);
2637

    
2638
  if ($nameStr) {
2639

    
2640
    // Do not return short names for these.
2641
    if ($taxonNodeDTO->unplaced || $taxonNodeDTO->excluded) {
2642
      return $nameStr;
2643
    }
2644

    
2645
    /*
2646
    1st capture group (^[a-zA-Z]): First letter of uninomial.
2647
    Second capture group ([\p{L}]+): remaining letters of uninomial ([\p{L} = an UTF-8 letter).
2648
    Third capture group (\s+[^(\x2E]+\s+.+$|\s+[a-zA-Z]+$): letters of name,
2649
    but only matching if no '(' or '.' in second word of name,        ( \x2E = '.')
2650
    OR only one specific epithet \s+[\p{L}\x22\x2D\xD7]+$             (\x22= '"', \x2D='-', \xD7='×' )
2651
    */
2652
    $pattern = '/(^[a-zA-Z])([\p{L}]+)(\s+[^(\x2E]+\s+.+$|\s+[\p{L}\x22\x2D\xD7]+$)/u';
2653
    if (preg_match($pattern, $nameStr, $matches, PREG_OFFSET_CAPTURE)) {
2654
      return $matches[1][0] . "." . $matches[3][0];
2655
    }
2656
    else {
2657
      return $nameStr;
2658
    }
2659
  }
2660
  else {
2661
    return $taxonNodeDTO->titleCache;
2662
  }
2663
}
2664

    
2665
/**
2666
 * Check if a taxon is accepted by the current taxonomic tree.
2667
 *
2668
 * @param mixed $taxon
2669
 *   The Taxon obkect to check.
2670
 *
2671
 * @return bool
2672
 *   Returns TRUE if $taxon is accepted, FALSE otherwise.
2673
 */
2674
function _cdm_dataportal_acceptedByCurrentView($taxon) {
2675

    
2676
  $defaultTreeUuid = get_current_classification_uuid();
2677

    
2678
  if (isset($taxon->taxonNodes)) {
2679
    $taxonNodes = $taxon->taxonNodes;
2680
  }
2681
  else {
2682
    $taxonNodes = cdm_ws_get(CDM_WS_PORTAL_TAXON_TAXONNODES, $taxon->uuid);
2683
  }
2684

    
2685
  if ($taxon->class == "Taxon" && isset($taxonNodes)) {
2686
    foreach ($taxonNodes as $node) {
2687
      if (isset($node->classification)){
2688
        if(is_object($node->classification)) {
2689
          if ($node->classification->uuid == $defaultTreeUuid) {
2690
            return TRUE;
2691
          }
2692
        }
2693
        else {
2694
          if ($node->classification == $defaultTreeUuid) {
2695
            return TRUE;
2696
          }
2697
        }
2698
      }
2699
    }
2700
  }
2701

    
2702
  return FALSE;
2703
}
2704

    
2705
/**
2706
 * Checks is the source has one of the given types.
2707
 *
2708
 * @param object $source
2709
 *   The original source entity
2710
 * @param array $types
2711
 *   An array of element of the OriginalSourceType enumeration
2712
 *   If not set the default will be used which is:
2713
 *    - Lineage
2714
 *    - PrimaryMediaSource
2715
 *    - PrimaryTaxonomicSource
2716
 *    - Unknown
2717
 *    - Other
2718
 * @return boolean
2719
 */
2720
  function _is_original_source_type($source, $types = null) {
2721
    // this is the default
2722
    // maybe this should also be put into the settings
2723
    static $default = array(
2724
      OriginalSourceType::Lineage,
2725
      OriginalSourceType::PrimaryMediaSource,
2726
      OriginalSourceType::PrimaryTaxonomicSource,
2727
      OriginalSourceType::Unknown,
2728
      OriginalSourceType::Other,
2729
      OriginalSourceType::Aggregation
2730
    );
2731

    
2732
    if(!$types){
2733
      $types = $default;
2734
    }
2735
    return isset($source->type) && in_array($source->type, $types);
2736
  }
2737

    
2738
/**
2739
 * Collects all the media from a list of description elements.
2740
 *
2741
 * @param array $descriptionElements
2742
 *   The description elements from which to collect the media.
2743
 *
2744
 * @return array
2745
 *   The output with all the collected media.
2746
 */
2747
function cdm_dataportal_media_from_descriptionElements($descriptionElements) {
2748

    
2749
  $outArrayOfMedia = array();
2750

    
2751
  // Avoiding a warning box in Drupal for Flora Malesiana.
2752
  if (isset($descriptionElements) && is_array($descriptionElements)) {
2753
    foreach ($descriptionElements as $descriptionElement) {
2754
      if (isset($descriptionElement->media) && is_array($descriptionElement->media)) {
2755
        foreach ($descriptionElement->media as $media) {
2756
          if (is_object($media)) {
2757
            $outArrayOfMedia[] = $media;
2758
          }
2759
        }
2760
      }
2761
    }
2762
  }
2763
  return $outArrayOfMedia;
2764
}
2765

    
2766
/**
2767
 * Fetches the list of visible annotations for each of the cdm entities and returns the footnote keys for them.
2768
 *
2769
 * The footnotes are passed to the FootnoteManager in order to store the annotations and to create the footnote keys.
2770
 *
2771
 * @see cdm_fetch_visible_annotations()
2772
 *
2773
 * @param array $cdm_entities
2774
 *   An array of CdmBase instances or a single instance.
2775
 * @param $footnote_list_key_suggestion string
2776
 *    optional parameter. If this parameter is left empty (null, 0, "") the footnote key will be determined be set to
2777
 *    RenderHints::getFootnoteListKey().'-annotations' otherwise the supplied key will be used.
2778
 *
2779
 * @return array of footnote keys
2780
 */
2781
function cdm_annotations_as_footnotekeys($cdm_entities, $footnote_list_key_suggestion = NULL) {
2782

    
2783
  $footNoteKeys = array();
2784

    
2785
  // Is argument cdmBase an array?
2786
  if (!is_array($cdm_entities)) {
2787
    $cdmBase_array = array();
2788
    $cdmBase_array[] = $cdm_entities;
2789
  }
2790
  else {
2791
    $cdmBase_array = $cdm_entities;
2792
  }
2793

    
2794
  // Getting the key for the footnotemanager.
2795
  if (isset($footnote_list_key_suggestion)) {
2796
    $footnote_list_key = $footnote_list_key_suggestion;
2797
  }
2798
  else {
2799
    $footnote_list_key = RenderHints::getFootnoteListKey() . '-annotations';
2800
  }
2801

    
2802
  // Adding the footnotes keys.
2803
  foreach ($cdmBase_array as $cdmBase_element) {
2804
    $annotations = cdm_fetch_visible_annotations($cdmBase_element);
2805
    if (is_array($annotations)) {
2806
      foreach ($annotations as $annotation) {
2807
        $footNoteKeys[] = FootnoteManager::addNewFootnote($footnote_list_key, $annotation->text);
2808
      }
2809
    }
2810
  }
2811

    
2812
  return $footNoteKeys;
2813
}
2814

    
2815

    
2816
/**
2817
 * Creates a CDM Dynabox.
2818
 *
2819
 * @param string $dynabox_id
2820
 *   a uninque name for tha dynabox, using a cdm entity uuid as id is good practice.
2821
 * @param string $label
2822
 *   The clickable text to show.
2823
 * @param string $content_url
2824
 *   The cdm REST service request url wich will deliver the content to be shown
2825
 *   once the dynabox toggles open.
2826
 * @param string $theme
2827
 *   The theme to be used for rendering the cdm REST service response with is
2828
 *   returned from the $content_url.
2829
 * @param string $link_alt_text
2830
 *   The value for the alt attribute of the dynabox link.
2831
 * @param array $enclosingtags
2832
 *   An array with two elements: $enclosingtags[0] will be used for the dynabox
2833
 *   element itself, $enclosingtags[1] is the tag to be used for the
2834
 *   dynabox_content (optional)
2835
 * @param array $attributes
2836
 * @param $content_element_selector
2837
 *   Optional jQuery selector which can be used to reference a dom element which should
2838
 *   be used as container for the content to be shown. The dynabox-<dynabox id>-content
2839
 *  element will be placed in this container.
2840
 *
2841
 * @param string $open_callback
2842
 *   optional javascript call back function to be triggered after toggling the box to
2843
 *   the open state.
2844
 * @param string $close_callback
2845
 *   optional javascript call back function to be triggered after toggling the box to
2846
 *   the closed state.
2847
 * @return string Returns HTML for a dynabox.
2848
 * Returns HTML for a dynabox.
2849
 */
2850
function cdm_dynabox($dynabox_id, $label, $content_url, $theme, $link_alt_text,
2851
                     $enclosingtags = array('li', 'ul'), $attributes = array(),
2852
                     $content_element_selector = null,
2853
                     $open_callback = 'function(){}', $close_callback = 'function(){}' ) {
2854
  $out = '';
2855

    
2856
  // check for plain class attribute string
2857
  $dynabox_id = preg_replace('/[^a-zA-Z0-9\-]/', '', $dynabox_id);
2858

    
2859
  if(!array_key_exists('class', $attributes)) {
2860
    $attributes['class'] = array();
2861
  }
2862
  $attributes['id'][] = 'dynabox-' . $dynabox_id;
2863
  $dynabox_attributes = drupal_attributes($attributes);
2864

    
2865

    
2866
  _add_js_domEvent(); // requires domEvent.js
2867
  drupal_add_js(drupal_get_path('module', 'cdm_dataportal') . '/js/cdm_dynabox.js');
2868
  drupal_add_js("
2869
  jQuery(document).ready(
2870
      function() {
2871
        dynabox('". $dynabox_id ."',
2872
          {
2873
            open_callback: " . $open_callback .",
2874
            close_callback: " . $close_callback .
2875
            ($content_element_selector ? ",\n content_container_selector: '" . $content_element_selector . "'" : "") . "
2876
          }
2877
        );
2878
      }
2879
   );",
2880
   array(
2881
    'type'=>'inline',
2882
    'scope'=>'footer'
2883
    )
2884
  );
2885

    
2886

    
2887
  $cdm_proxy_url = url('cdm_api/proxy/' . urlencode($content_url) . "/$theme");
2888
  $out .= '<!-- dynabox for ' . $content_url . ' -->';
2889
  $out .= '<' . $enclosingtags[0] . ' ' .  $dynabox_attributes. '><a href="' . $cdm_proxy_url . '" class="label" alt="' . t('@link-alt-text', array('@link-alt-text' => $link_alt_text)) . '">' . $label . '</a>';
2890
  $out .= '  <' . $enclosingtags[1] . ' id="dynabox-' . $dynabox_id . '-content">';
2891
  $out .= '    <' . $enclosingtags[0] . ' class="dynabox-content-inner">' . loading_image_html() . '</' . $enclosingtags[0] . '>';
2892
  $out .= '    </' . $enclosingtags[1] . '>';
2893
  $out .= '  </' . $enclosingtags[0] . '>';
2894
  $out .= '<!-- dynabox end -->';
2895
  return $out;
2896
}
2897

    
2898
/**
2899
 * Checks whether a feature has any description elements.
2900
 *
2901
 * @param mixed $featureNode
2902
 *   A feature node as produced by the function _mergeFeatureTreeDescriptions().
2903
 *
2904
 * @see _mergeFeatureTreeDescriptions()
2905
 *
2906
 * @return bool
2907
 *   Returns TRUE if the given $featureNode or any of its subordinate nodes
2908
 *   contains at least one non empty TextData or at least one DescriptionElement
2909
 *   of an other type. A TextData element holding a multilanguageText or a
2910
 *   source reference is considered to be not empty.
2911
 *
2912
 * @TODO this function may have become obsolete by the new method of detecting empty blocks,
2913
 *       see $block_content_is_not_empty in make_feature_block_list() and
2914
 *       $feature_block_has_content in compose_feature_block_items_generic
2915
 */
2916
function has_feature_node_description_elements($featureNode) {
2917

    
2918
  if (isset($featureNode->descriptionElements) && is_array($featureNode->descriptionElements) && count($featureNode->descriptionElements) > 0) {
2919
    if(!isset($featureNode->descriptionElements['#type'])){ // #type is used to identify e.g. DTO elements: '#type' => 'DTO'
2920
      foreach ($featureNode->descriptionElements as $descriptionElement) {
2921
        if ($descriptionElement->class != "TextData" || isset($descriptionElement->multilanguageText_L10n->text)
2922
          && $descriptionElement->multilanguageText_L10n->text != ''
2923
          || isset($descriptionElement->sources[0])
2924
          || isset($descriptionElement->media[0]) ) {
2925
          return TRUE;
2926
        }
2927
      }
2928
    }
2929
  }
2930
  else if (isset($featureNode->childNodes) && is_array($featureNode->childNodes)) {
2931
    foreach ($featureNode->childNodes as $child) {
2932
      if (has_feature_node_description_elements($child)) {
2933
        return TRUE;
2934
      }
2935
    }
2936
  }
2937
  return FALSE;
2938
}
2939

    
2940
/**
2941
 * Checks if the current page is a valid taxon portal page and responds with HTTP status 404 (not found) otherwise
2942
 *
2943
 * @param $chapter
2944
 *   The taxon page chapter or part
2945
 */
2946
function cdm_check_valid_taxon_page($chapter){
2947
  static $taxon_tabs = null;
2948

    
2949
  cdm_check_valid_portal_page();
2950

    
2951
  if($taxon_tabs == null){
2952
    $taxon_tabs = array('all', 'description');
2953
    foreach(get_taxon_tabs_list() as $tab){
2954
      $taxon_tabs[] = strtolower($tab);
2955
    }
2956
  }
2957

    
2958
  if(!in_array($chapter, $taxon_tabs)){
2959
    // oops this is not a valid chapter name
2960
    http_response_code(404); // 404 = Not Found
2961
  }
2962

    
2963
}
2964

    
2965
function check_js_devel_mode_disabled() {
2966
  if(variable_get('cdm_js_devel_mode', FALSE)) {
2967
    drupal_set_message(t('The !url1 is enabled.
2968
        WARNING: this is a performance penalty and must be turned off on production websites.', array(
2969
      '!url1' => l('java-script development mode', 'admin/config/cdm_dataportal/settings', array('fragment' => 'edit-cdm-js-devel-mode'))
2970
    )),
2971
      'warning'
2972
    );
2973
  }
2974
}
2975

    
2976
/**
2977
 * Checks if the current page is a valid portal page and responds with HTTP status 404 (not found) otherwise.
2978
 * The test applied by default it a check for the query parameter 'q' ending with a file suffix like '*.*'
2979
 *
2980
 * @param $preg_pattern
2981
 *   Optional regular expression pattern to be used in preg_match().
2982
 */
2983
function cdm_check_valid_portal_page($preg_pattern = null){
2984
  $ends_with_file_suffix_pattern = '/\/[^\.\/]*[\.][^\.\/]*$/';
2985
  if($preg_pattern === null){
2986
    $preg_pattern = $ends_with_file_suffix_pattern;
2987
  }
2988
  if(preg_match($preg_pattern, $_GET['q'])){
2989
    // oops this urls ends with a file_suffix and thus does not refer to a portal page
2990
    http_response_code(404); // 404 = Not Found
2991
    exit('HTTP 404');
2992
  }
2993
  check_js_devel_mode_disabled();
2994
}
2995

    
2996
/**
2997
 * Generates the diff of the texts and presents it in a HTML diff viewer.
2998
 *
2999
 * @param $text_a
3000
 * @param $text_b
3001
 * @return string
3002
 */
3003
function diff_viewer($text_a, $text_b) {
3004

    
3005
  static $diff_viewer_count = 0;
3006

    
3007
  $element_id = 'part_definitions_diff_' . $diff_viewer_count++;
3008

    
3009
  // http://code.stephenmorley.org/php/diff-implementation/
3010
  module_load_include('php', 'cdm_dataportal', 'lib/class.Diff');
3011
  drupal_add_css(drupal_get_path('module',
3012
      'cdm_dataportal') . '/css/diff.css');
3013
  _add_jquery_ui();
3014
  drupal_add_js(
3015
    'jQuery(document).ready( function(){
3016
        jQuery(\'#' . $element_id . '\').accordion({
3017
        collapsible: true,
3018
        active: false,
3019
        fillSpace: true,
3020
        }).children(\'div\').css({ \'height\': \'auto\' });
3021
        jQuery(\'#' . $element_id . ' table.diff\').prepend(\'<thead><tr><th>Default</th><th>User defined<th></th><tr></thead>\');
3022
     });'
3023
    , array(
3024
    'type' => 'inline',
3025
    'scope' => 'footer'
3026
  ));
3027

    
3028
  $diff = Diff::compare($text_a,
3029
    $text_b);
3030
  $diff_viewer_markup = '<div id="' . $element_id . '"><h3>View Diff</h3><div>'
3031
    . Diff::toTable($diff, '', '')
3032
    . '</div></div>';
3033
  return $diff_viewer_markup;
3034
}
3035

    
3036

    
(10-10/18)