Project

General

Profile

Download (97.9 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/symbols');
26
  module_load_include('inc', 'cdm_dataportal', 'includes/common');
27
  module_load_include('inc', 'cdm_dataportal', 'includes/footnotes');
28
  module_load_include('inc', 'cdm_dataportal', 'includes/agent');
29
  module_load_include('inc', 'cdm_dataportal', 'includes/name');
30
  module_load_include('inc', 'cdm_dataportal', 'includes/taxon');
31
  module_load_include('inc', 'cdm_dataportal', 'includes/taxon-node');
32
  module_load_include('inc', 'cdm_dataportal', 'includes/references');
33
  module_load_include('inc', 'cdm_dataportal', 'includes/pages');
34
  module_load_include('inc', 'cdm_dataportal', 'includes/media');
35
  module_load_include('inc', 'cdm_dataportal', 'includes/maps');
36
  module_load_include('inc', 'cdm_dataportal', 'includes/occurrences');
37
  module_load_include('inc', 'cdm_dataportal', 'includes/occurrences_new'); // tmp file, shoud be merged later with occurrences.inc
38
  module_load_include('inc', 'cdm_dataportal', 'includes/descriptions');
39
  module_load_include('inc', 'cdm_dataportal', 'includes/pre-drupal8');
40

    
41
  module_load_include('inc', 'cdm_dataportal', 'theme/theme_registry');
42
  module_load_include('theme', 'cdm_dataportal', 'theme/cdm_dataportal.common');
43
  module_load_include('theme', 'cdm_dataportal', 'theme/cdm_dataportal.descriptions');
44
  module_load_include('theme', 'cdm_dataportal', 'theme/cdm_dataportal.media');
45
  module_load_include('theme', 'cdm_dataportal', 'theme/cdm_dataportal.page');
46
  module_load_include('theme', 'cdm_dataportal', 'theme/cdm_dataportal.taxon');
47
  module_load_include('theme', 'cdm_dataportal', 'theme/cdm_dataportal.name');
48
  module_load_include('theme', 'cdm_dataportal', 'theme/cdm_dataportal.references');
49

    
50
  module_load_include('php', 'cdm_dataportal', 'classes/footnotemanager');
51
  module_load_include('php', 'cdm_dataportal', 'classes/footnote');
52
  module_load_include('php', 'cdm_dataportal', 'classes/footnotekey');
53
  module_load_include('php', 'cdm_dataportal', 'classes/renderhints');
54

    
55

    
56
  /* ============================ java script functions ============================= */
57

    
58

    
59
  /**
60
  * loads external java script files asynchronously.
61
  *
62
  * @param unknown_type $script_url
63
  */
64
  function drupal_add_js_async($script_url, $callback){
65

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

    
80
  /**
81
   */
82
  function drupal_add_js_rowToggle($tableId){
83

    
84
      drupal_add_js(drupal_get_path('module', 'cdm_dataportal') . '/js/table_modification.js');
85
      drupal_add_js('jQuery(document).ready(function(){
86
          addRowToggle("' . $tableId . '");
87
      });
88
      ', array('type' => 'inline'));
89
  }
90

    
91
  /**
92
   * @param unknown_type $link_element_selector
93
   * @param unknown_type $progress_element_selector
94
   */
95
  function _add_js_cdm_ws_progressbar($link_element_selector, $progress_element_selector){
96

    
97
    $callback = "jQuery('" . $link_element_selector . "').cdm_ws_progress('" . $progress_element_selector . "');";
98

    
99
    drupal_add_js_async(variable_get('cdm_webservice_url', '').'js/cdm_ws_progress.js', $callback);
100

    
101
    //   drupal_add_js("
102
    //   	  if (Drupal.jsEnabled) {
103
    //         $(document).ready(function() {
104
    //       		$('" . $link_element_selector . "').cdm_ws_progress('" . $progress_element_selector . "');
105
    //         });
106
    //       }", 'inline');
107
    }
108

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

    
121
        });
122
      ",
123
      array(
124
        'type' => 'inline',
125
        'scope' => 'footer'
126
      )
127
    );
128
  }
129

    
130
  function _add_js_resizable_element($selector, $y_axis_only) {
131

    
132
    _add_jquery_ui();
133
    $options = "";
134
    if($y_axis_only) {
135
      $options = "resize: function(event, ui) {
136
        ui.size.width = ui.originalSize.width;
137
        },
138
        handles: \"s\"";
139

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

    
153
  function _add_js_openlayers() {
154

    
155
    $openlayers = '/js/map/OpenLayers-2.13.1/OpenLayers.js';
156
    $proj4js = '/js/map/proj4js-1.1.0/proj4js-compressed.js';
157

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

    
165
    drupal_add_js(drupal_get_path('module', 'cdm_dataportal') . $openlayers,
166
      array(
167
        'type' => 'file',
168
        'group' => JS_LIBRARY,
169
        'weight' => 0,
170
        'cache' => TRUE,
171
        'preprocess' => FALSE
172
      )
173
    );
174

    
175

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

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

    
198
    drupal_add_css($openlayers_theme_path . 'style.tidy.css',
199
      array(
200
        'type' => 'file',
201
        'cache' => TRUE,
202
        'preprocess' => FALSE
203
      )
204
    );
205

    
206
  }
207

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

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

    
262
  /**
263
   * @todo Please document this function.
264
   * @see http://drupal.org/node/1354
265
   */
266
  function _add_js_footnotes() {
267
    _add_js_domEvent();
268
    drupal_add_js(drupal_get_path('module', 'cdm_dataportal') . '/js/footnotes.js');
269
  }
270

    
271
  /**
272
   * @todo Please document this function.
273
   * @see http://drupal.org/node/1354
274
   */
275
  function _add_js_ahah() {
276

    
277
    _add_js_domEvent(); // requires domEvent.js
278
    drupal_add_js(drupal_get_path('module', 'cdm_dataportal') . '/js/ahah-content.js');
279
  }
280

    
281
/**
282
 * @todo Please document this function.
283
 * @see http://drupal.org/node/1354
284
 */
285
function _add_js_taxonomic_children($jquery_selector) {
286

    
287
  global $base_url;
288

    
289

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

    
306
  /**
307
   * Adds the external javascript file for domEvent.js.
308
   *
309
   * @see drupal_add_js()
310
   */
311
  function _add_js_domEvent() {
312
    drupal_add_js(drupal_get_path('module', 'cdm_dataportal') . '/js/domEvent.js');
313
  }
314

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

    
330
function _add_js_ui_accordion(){
331
  _add_jquery_ui();
332
  drupal_add_js('jQuery(document).ready(function() {
333
      jQuery( "#accordion" ).accordion();
334
    });',
335
    array('type' => 'inline')
336
  );
337
}
338

    
339

    
340
function _add_js_utis_client($jquery_selector){
341

    
342
  drupal_add_js(drupal_get_path('module',
343
      'cdm_dataportal') . '/js/utis-client/utis-client.js',
344
    array(
345
      'type' => 'file',
346
      'weight' => JS_LIBRARY,
347
      'cache' => TRUE,
348
      'preprocess' => FALSE
349
    )
350
  );
351

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

    
363
function _add_js_universalviewer($jquery_selector, $manifest_uri){
364

    
365
  $universalviewer_path  = drupal_get_path('module',    'cdm_dataportal') . '/js/universalviewer';
366

    
367
  drupal_add_css($universalviewer_path . '/uv/uv.css');
368
  drupal_add_css($universalviewer_path . '/uv-fix.css');
369

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

    
443
function _add_js_derivation_tree($jquery_selector){
444
  drupal_add_js(drupal_get_path('module','cdm_dataportal') . '/js/derivation-tree.js');
445
  drupal_add_js('jQuery(document).ready(function() {
446
      jQuery( "' . $jquery_selector . '" ).derivationTree();
447
    });',
448
    array('type' => 'inline')
449
  );
450
}
451

    
452
  /**
453
   * Provides the markup for an font awesome icon.
454
   *
455
   * The icons is created in default size without any extra features.
456
   *
457
   * The available icons are listed here http://fontawesome.io/cheatsheet/
458
   * fontawesome icons have much more features than implemented here in this function,
459
   * for spinning icons, fixed width icons, rotation, etc please checkout the
460
   * examples at http://fontawesome.io/examples/
461
   *
462
   * @parameter $icon_name
463
   *  The name of the icon which starts with 'fa-'
464
   *
465
   * @return String
466
   *    the markup for the icon in an <i> tag
467
   *
468
   */
469
  function font_awesome_icon_markup($icon_name = NULL, $attributes = array()){
470
    _add_font_awesome_font();
471

    
472
    if($icon_name){
473
      if(!isset($attributes['class'])){
474
        $attributes['class'] = array();
475
      }
476
      $attributes['class'][] = 'fa';
477
      $attributes['class'][] = $icon_name;
478

    
479
      return '<i ' . drupal_attributes($attributes) . '></i>';
480
    }
481

    
482
    return '';
483
  }
484

    
485
/**
486
 * see https://fontawesome.com/how-to-use/on-the-web/styling/stacking-icons
487
 * @param array $fa_icons_markup
488
 *  Array of font awesome icon markup preferably created by font_awesome_icon_markup()
489
 *
490
 * @return string
491
 *  The markup
492
 */
493
function font_awesome_icon_stack($fa_icons_markup, $attributes = array(), $no_resize = TRUE){
494

    
495

    
496
    if(!isset($attributes['class'])){
497
      $attributes['class'] = array();
498
    }
499
    if($no_resize){
500
      $attributes['class'][] = 'fa-stack-no-resize';
501
    } else {
502
      $attributes['class'][] = 'fa-stack';
503
    }
504

    
505
    return '<span ' . drupal_attributes($attributes) . '>' . join('', $fa_icons_markup) . '</span>';
506
}
507

    
508
/**
509
 * @param string $glyph_name
510
 *   The name of the gloyph (e.g. 'icon-interal-link-alt-solid') for the foll list please
511
 *   refer to modules/cdm_dataportal/fonts/custom-icon-font
512
 * @param array $attributes
513
 * @return string
514
 */
515
  function custom_icon_font_markup($glyph_name = NULL, $attributes = array()){
516
    _add_font_custom_icon_font();
517

    
518

    
519
    if($glyph_name){
520
      if(!isset($attributes['class'])){
521
        $attributes['class'] = array();
522
      }
523
      $attributes['class'][] = $glyph_name;
524

    
525
      return '<i ' . drupal_attributes($attributes) . '></i>';
526
    }
527

    
528
    return '';
529
  }
530

    
531
/**
532
 * Adds the css  containing the font awesome icons to the html header.
533
 */
534
function _add_font_awesome_font()
535
{
536
  // $fa_font_version = 'font-awesome-4.6.3/css/font-awesome.min.css';
537
  $fa_font_version = 'fontawesome-free-5.9.0-web/css/all.css';
538
  $font_awesome_css_uri = base_path() . drupal_get_path('module', 'cdm_dataportal') . '/fonts/' . $fa_font_version;
539

    
540
  drupal_add_html_head_link(
541
    array(
542
      'href' => $font_awesome_css_uri,
543
      'rel' => 'stylesheet'
544
    )
545
  );
546
}
547

    
548
/**
549
 * Adds the css  containing the font awesome icons to the html header.
550
 */
551
function _add_font_custom_icon_font()
552
{
553

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

    
556
  drupal_add_html_head_link(
557
    array(
558
      'href' => $custom_icon_font_css_uri,
559
      'rel' => 'stylesheet'
560
    )
561
  );
562
}
563

    
564
/* ====================== hook implementations ====================== */
565
  /**
566
   * Implements hook_permission().
567
   *
568
   * Valid permissions for this module.
569
   *
570
   * @return array
571
   *   An array of valid permissions for the cdm_dataportal module.
572
   */
573
  function cdm_dataportal_permission() {
574
    return array(
575
      'administer cdm_dataportal' => array(
576
        'title' => t('Administer CDM DataPortal settings'),
577
        'description' => t("Access the settings pages specific for the cdm_dataportal module"),
578
      ),
579
      'access cdm content' => array(
580
        'title' => t('Access CDM content'),
581
        'description' => t("Access content (taxa, names, specimens, etc.) served by the CDM web service."),
582
      ),
583
    );
584
  }
585

    
586
/**
587
 * Implements hook_menu().
588
 */
589
function cdm_dataportal_menu() {
590
  $items = array();
591

    
592
  // @see settings.php.
593
  cdm_dataportal_menu_admin($items);
594
  cdm_dataportal_menu_help($items);
595

    
596
  $items['cdm_dataportal/names'] = array(
597
    'page callback' => 'cdm_dataportal_view_names',
598
    'access arguments' => array('access cdm content'),
599
    'type' => MENU_CALLBACK,
600
  );
601

    
602
  // Optional callback arguments: page.
603
  $items['cdm_dataportal/taxon'] = array(
604
    'page callback' => 'cdm_dataportal_taxon_page_view',
605
    'access arguments' => array('access cdm content'),
606
    'type' => MENU_CALLBACK,
607
    // Expected callback arguments: uuid.
608
  );
609

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

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

    
624
   $items['cdm_dataportal/specimen/accession_number'] = array(
625
        'page callback' => 'cdm_dataportal_specimen_by_accession_number_page_view',
626
        'access arguments' => array('access cdm content'),
627
        'type' => MENU_CALLBACK,
628
        // Expected callback arguments: accession number.
629
    );
630
  $items['cdm_dataportal/named_area'] = array(
631
    'page callback' => 'cdm_dataportal_named_area_page_view',
632
    'access arguments' => array('access cdm content'),
633
    'type' => MENU_CALLBACK,
634
    // Expected callback arguments: uuid.
635
  );
636

    
637
  $items['cdm_dataportal/name'] = array(
638
    'page callback' => 'cdm_dataportal_name_page_view',
639
      /*
640
    'page arguments' => array(
641
       'taxon_name_uuid',
642
       'taxon_to_hide_uuid',
643
       'synonym_uuid' => NULL
644
      ),
645
      */
646
    'access arguments' => array('access cdm content'),
647
    'type' => MENU_CALLBACK,
648
    // Expected callback arguments: uuid.
649
  );
650

    
651
  $items['cdm_dataportal/reference'] = array(
652
    'page callback' => 'cdm_dataportal_view_reference',
653
    'access arguments' => array('access cdm content'),
654
    'type' => MENU_CALLBACK,
655
    // Expected callback arguments: uuid.
656
  );
657

    
658
  $items['cdm_dataportal/reference/list'] = array(
659
    'page callback' => 'cdm_dataportal_view_reference_list',
660
    'access arguments' => array('access cdm content'),
661
    'type' => MENU_CALLBACK,
662
    // Expected callback arguments: uuid.
663
  );
664

    
665
  $items['cdm_dataportal/media'] = array(
666
    'page callback' => 'cdm_dataportal_view_media',
667
    'access arguments' => array('access cdm content'),
668
    'type' => MENU_CALLBACK,
669
    // Expected callback arguments:
670
    // uuid, mediarepresentation_uuid, part_uuid or part#.
671
  );
672

    
673
  $items['cdm_dataportal/polytomousKey'] = array(
674
    'page callback' => 'cdm_dataportal_view_polytomousKey',
675
    'access arguments' => array('access cdm content'),
676
    'type' => MENU_CALLBACK,
677
    // Expected callback arguments: polytomousKey->uuid.
678
  );
679

    
680
  $items['cdm_dataportal/search'] = array(
681
    'page callback' => 'cdm_dataportal_view_search_advanced',
682
    'access arguments' => array('access cdm content'),
683
    'type' => MENU_CALLBACK,
684
  );
685

    
686
  // Optional callback arguments: page.
687
  $items['cdm_dataportal/registration'] = array(
688
    'page callback' => 'cdm_dataportal_registration_page_view',
689
    'access arguments' => array('access cdm content'),
690
    'type' => MENU_CALLBACK,
691
    // Expected callback arguments: uuid.
692
  );
693

    
694
  // ------------ SEARCH -----------
695
  $items['cdm_dataportal/search/advanced'] = array(
696
    'title' => 'Advanced', // will be passed through t()
697
    'page callback' => 'cdm_dataportal_view_search_advanced',
698
    'access arguments' => array('access cdm content'),
699
    'type' => MENU_DEFAULT_LOCAL_TASK,
700
  );
701
  $items['cdm_dataportal/search/blast'] = array(
702
    'title' => 'Blast', // will be passed through t()
703
    'page callback' => 'cdm_dataportal_view_search_blast',
704
    'access arguments' => array('access cdm content'),
705
    'type' => MENU_LOCAL_TASK,
706
  );
707

    
708
  $items['cdm_dataportal/search/taxon_by_description'] = array(
709
    'title' => 'By content category', // will be passed through t()
710
    'page callback' => 'cdm_dataportal_view_search_taxon_by_description',
711
    'access arguments' => array('access cdm content'),
712
    'type' => MENU_LOCAL_TASK,
713
  );
714
  $items['cdm_dataportal/search/results/taxon'] = array(
715
    'page callback' => 'cdm_dataportal_view_search_results_taxon',
716
    'access arguments' => array('access cdm content'),
717
    'type' => MENU_CALLBACK,
718
  );
719

    
720
  $items['cdm_dataportal/search/results/specimen'] = array(
721
      'page callback' => 'cdm_dataportal_view_search_results_specimen',
722
      'access arguments' => array('access cdm content'),
723
      'type' => MENU_CALLBACK,
724
  );
725

    
726
  /*
727
   * MENU_CALLBACK at cdm_dataportal/registration-search is needed to make the
728
   * tabs in the subordinate paths work, accessing this 'page' will cause the
729
   * MENU_DEFAULT_LOCAL_TASK being displayed
730
   */
731
  $items['cdm_dataportal/registration-search'] = array(
732
    'title' => 'Search', // will be passed through t()
733
    'page callback' => 'cdm_dataportal_view_search_registrations_results',
734
    'page arguments' => array("filter"),
735
    'access arguments' => array('access cdm content'),
736
    'type' => MENU_CALLBACK,
737
  );
738
  /*
739
   * the MENU_DEFAULT_LOCAL_TASK creates a tab for the MENU_CALLBACK
740
   * defined at a higher level of the path (cdm_dataportal/registration-search)
741
   */
742
  $items['cdm_dataportal/registration-search/filter'] = array(
743
    'title' => 'Search', // will be passed through t()
744
    'page callback' => 'cdm_dataportal_view_search_registrations_results',
745
    'page arguments' => array("filter"),
746
    'access arguments' => array('access cdm content'),
747
    'type' => MENU_DEFAULT_LOCAL_TASK,
748
  );
749
  /*
750
   * the MENU_LOCAL_TASK creates another tab
751
   */
752
  $items['cdm_dataportal/registration-search/taxongraph'] = array(
753
    'title' => 'Taxon graph search', // will be passed through t()
754
    'page callback' => 'cdm_dataportal_view_search_registrations_results',
755
    'page arguments' => array("taxongraph"),
756
    'access arguments' => array('access cdm content'),
757
    'type' => MENU_LOCAL_TASK,
758
  );
759

    
760
  // Optional callback arguments: page.
761
  $items['cdm_dataportal/search/agent'] = array(
762
    'page callback' => 'cdm_dataportal_view_search_agent',
763
    'access arguments' => array('access cdm content'),
764
    'type' => MENU_CALLBACK,
765
    // Expected callback arguments: uuid.
766
  );
767

    
768
  // ------------ menu items with variable path elements -----------
769

    
770
  // 'May not cache' in D5.
771
  $items['cdm_dataportal/name/%'] = array(
772
    // 'page callback' => 'cdm_dataportal_view_name',
773
    'page callback' => 'cdm_dataportal_name_page_view',
774
    'page arguments' => array(2, 3, 4, 5),
775
    'access arguments' => array('access cdm content'),
776
    'type' => MENU_CALLBACK,
777
  );
778

    
779
  // --- Local tasks for Taxon.
780
  // --- tabbed taxon page
781
  if (variable_get('cdm_dataportal_taxonpage_tabs', 1)) {
782
    $items['cdm_dataportal/taxon/%'] = array(
783
      'title' => cdm_taxonpage_tab_label('General'),
784
      'page callback' => 'cdm_dataportal_taxon_page_view',
785
      'access arguments' => array('access cdm content'),
786
      'type' => MENU_CALLBACK,
787
      'weight' => 1,
788
      'page arguments' => array(2, "description")
789
      , // Expected callback arguments: taxon_uuid.
790
    );
791

    
792
    $items['cdm_dataportal/taxon/%/all'] = array(
793
      'title' => cdm_taxonpage_tab_label('General'),
794
      'page callback' => 'cdm_dataportal_taxon_page_view',
795
      'access arguments' => array('access cdm content'),
796
      'type' => MENU_CALLBACK,
797
      'weight' => 2,
798
      'page arguments' => array(2, "all")
799
      , // Expected callback arguments: taxon_uuid.
800
    );
801

    
802
    $items['cdm_dataportal/taxon/%/description'] = array(
803
      'title' => cdm_taxonpage_tab_label('General'),
804
      'page callback' => 'cdm_dataportal_taxon_page_view',
805
      'access arguments' => array('access cdm content'),
806
      'type' => MENU_DEFAULT_LOCAL_TASK,
807
      'weight' => 2,
808
      'page arguments' => array(2, "description")
809
      , // Expected callback arguments: taxon_uuid.
810
    );
811

    
812
    $items['cdm_dataportal/taxon/%/synonymy'] = array(
813
      'title' => cdm_taxonpage_tab_label('Synonymy'),
814
      'page callback' => 'cdm_dataportal_taxon_page_view',
815
      'access arguments' => array('access cdm content'),
816
      'type' => MENU_LOCAL_TASK,
817
      'weight' => 4,
818
      'page arguments' => array(2, "synonymy", 4)
819
      , // Expected callback arguments: taxon_uuid and ...
820
    );
821
    $items['cdm_dataportal/taxon/%/images'] = array( // Images
822
      'title' => cdm_taxonpage_tab_label('Images'),
823
      'page callback' => 'cdm_dataportal_taxon_page_view',
824
      'access arguments' => array('access cdm content'),
825
      'type' => MENU_LOCAL_TASK,
826
      'weight' => 5,
827
      'page arguments' => array(2, "images")
828
      , // Expected callback arguments: taxon_uuid.
829
    );
830

    
831
    $items['cdm_dataportal/taxon/%/specimens'] = array( // Specimens
832
      'title' => cdm_taxonpage_tab_label('Specimens'),
833
      'page callback' => 'cdm_dataportal_taxon_page_view',
834
      'access arguments' => array('access cdm content'),
835
      'type' => MENU_LOCAL_TASK,
836
      'weight' => 6,
837
      'page arguments' => array(2, "specimens")
838
      , // Expected callback arguments: taxon_uuid.
839
    );
840

    
841
    $items['cdm_dataportal/taxon/%/keys'] = array( // Keys
842
      'title' => cdm_taxonpage_tab_label('Keys'),
843
      'page callback' => 'cdm_dataportal_taxon_page_view',
844
      'access arguments' => array('access cdm content'),
845
      'type' => MENU_LOCAL_TASK,
846
      'weight' => 6,
847
      'page arguments' => array(2, "keys")
848
      , // Expected callback arguments: taxon_uuid.
849
    );
850

    
851
    $items['cdm_dataportal/taxon/%/experts'] = array( // Experts
852
      'title' => cdm_taxonpage_tab_label('Experts'),
853
        'page callback' => 'cdm_dataportal_taxon_page_view',
854
        'access arguments' => array('access cdm content'),
855
        'type' => MENU_LOCAL_TASK,
856
        'weight' => 6,
857
        'page arguments' => array(2, "experts")
858
    , // Expected callback arguments: taxon_uuid.
859
    );
860

    
861
    $items['cdm_dataportal/taxon/autosuggest/%/%/%/'] = array(
862
        'page callback' => 'cdm_dataportal_taxon_autosuggest',
863
        'access arguments' => array('access cdm content'),
864
        'page arguments' => array(3,4,5),
865
        'type' => MENU_CALLBACK
866
    );
867
  }
868

    
869
  // --- refresh link for all cdmnode types
870
  foreach (cdm_get_nodetypes() as $type=>$name) {
871
    $items['cdm_dataportal/' . $name . '/%/refresh'] = array(
872
        'title' => 'Refresh',
873
        'page callback' => 'cdm_dataportal_refresh_node',
874
        'access arguments' => array('administer cdm_dataportal'),
875
        'type' => MENU_LOCAL_TASK,
876
        'weight' => 100,
877
        'page arguments' => array($name, 2)
878
    );
879
  }
880

    
881
  return $items;
882
}
883

    
884
/**
885
 * Implements hook_init().
886
 *
887
 */
888
function cdm_dataportal_init() {
889
  if (!path_is_admin(current_path())) {
890
    //FIXME To add CSS or JS that should be present on all pages, modules
891
    //      should not implement this hook, but declare these files in their .info file.
892
    drupal_add_css(drupal_get_path('module', 'cdm_dataportal') . '/cdm_dataportal.css');
893
    // drupal_add_css(drupal_get_path('module', 'cdm_dataportal').'/cdm_dataportal_print.css', 'print');
894
    drupal_add_css(drupal_get_path('module', 'cdm_dataportal') . '/cdm_dataportal_screen.css', array('type' => 'screen'));
895
  } else {
896
    drupal_add_css(drupal_get_path('module', 'cdm_dataportal') . '/cdm_dataportal_settings.css');
897
  }
898

    
899
  if(variable_get('cdm_debug_mode', FALSE)){
900
    $file = 'temporary://drupal_debug.txt';
901
    file_put_contents($file, 'CDM DEBUG LOG for ' . $_GET['q']. "\n"); // will overwrite the file
902
  }
903

    
904
  $bibliography_settings = get_bibliography_settings();
905
  $enclosing_tag = $bibliography_settings['enabled'] == 1 ? 'div' : 'span';
906
  FootnoteManager::registerFootnoteSet('BIBLIOGRAPHY', $enclosing_tag, $bibliography_settings['key_format']);
907
}
908

    
909
function cdm_dataportal_refresh_node($cdm_node_name, $uuid, $parameters = array()){
910

    
911
  $base_path = 'cdm_dataportal/' . $cdm_node_name . '/' . $uuid;
912

    
913
  if($cdm_node_name == 'taxon' && variable_get('cdm_dataportal_taxonpage_tabs', 1)){
914
    // force reloading of all and notify user about this special loading
915
    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: ')
916
        . l('Back to tabbed taxon page', $base_path));
917
    $base_path .= '/all';
918
  } else {
919
    drupal_set_message(t('The level 2 cache has been cleared for this page'));
920
  }
921

    
922
  $parameters['cacheL2_refresh'] ='1';
923

    
924

    
925
  drupal_goto($base_path, array('query' => $parameters));
926
}
927

    
928
/**
929
 * Implements hook_requirements($phase)
930
 */
931
function cdm_dataportal_requirements($phase) {
932
    $requirements = array();
933
    if($phase == 'runtime'){
934

    
935
    }
936
    return $requirements;
937
}
938

    
939
/**
940
 * Implements hook_block_info().
941
 */
942
function cdm_dataportal_block_info() {
943

    
944
    // $block[0]["info"] = t("CDM DataPortal DevLinks");
945
    // $block[1]["info"] = t("CDM DataPortal Credits");
946
    $block["2"] = array(
947
        "info" => t("CDM - Search Taxa"),
948
        "cache" => DRUPAL_NO_CACHE
949
      );
950
    // $block[3]["info"] = t("CDM Filters");
951
    $block["4"]["info"] = t("CDM  - Dataportal Print");
952
    $block["keys"]["info"] = t("CDM - Identification keys");
953
    $block["fundedByEDIT"]["info"] = t('CDM - Powered by EDIT');
954
    $block["classification_breadcrumbs"] =  array(
955
        'info' => t('CDM - Classification breadcrumbs'),
956
        'cache' => DRUPAL_CACHE_PER_PAGE
957
      );
958
    $block["taxonomic_children"] =  array(
959
      'info' => t('CDM - Taxonomic children'),
960
      'cache' => DRUPAL_CACHE_PER_PAGE
961
    );
962
    $block["back_to_search_results"] =  array(
963
      'title' => '<none>',
964
      'info' => t('CDM - Back to search Results'),
965
      'cache' => DRUPAL_CACHE_PER_PAGE,
966
      'visibility' => BLOCK_VISIBILITY_LISTED,
967
      'pages' => "cdm_dataportal/taxon/*", // multiple page paths separated by "\n"!!!
968
    );
969
  $block['registrations_search_filter'] =  array(
970
    'title' => 'Filter registrations',
971
    'info' => t('CDM - Registrations search filter'),
972
    'cache' => DRUPAL_CACHE_PER_PAGE,
973
    'visibility' => BLOCK_VISIBILITY_NOTLISTED,
974
    'pages' => "cdm_dataportal/registration-search\ncdm_dataportal/registration-search/*", // multiple page paths separated by "\n"!!!
975
  );
976
  $block['registrations_search_taxongraph'] =  array(
977
    'title' => 'Taxonomic registration search',
978
    'info' => t('CDM - Registrations search by taxon graph'),
979
    'cache' => DRUPAL_CACHE_PER_PAGE,
980
    'visibility' => BLOCK_VISIBILITY_NOTLISTED,
981
    'pages' => "cdm_dataportal/registration-search\ncdm_dataportal/registration-search/*", // multiple page paths separated by "\n"!!!
982
  );
983
  $block['registrations_search'] =  array(
984
    'title' => 'Search',
985
    'info' => t('CDM - Registrations search combining filter and taxon graph search' ),
986
    'cache' => DRUPAL_CACHE_PER_PAGE,
987
    'visibility' => BLOCK_VISIBILITY_NOTLISTED,
988
    'pages' => "cdm_dataportal/registration-search\ncdm_dataportal/registration-search/*", // multiple page paths separated by "\n"!!!
989
  );
990
  $block['utis_search'] =  array(
991
    'title' => 'UTIS Search',
992
    'info' => t('Query the Unified Taxonomic Information Service (UTIS)' ),
993
    'cache' => DRUPAL_CACHE_PER_PAGE,
994
    'visibility' => BLOCK_VISIBILITY_NOTLISTED
995
  );
996
  return $block;
997
}
998

    
999
/**
1000
 * Implements hook_block_view().
1001
 */
1002
function cdm_dataportal_block_view($delta) {
1003
  // TODO Rename block deltas (e.g. '2') to readable strings.
1004
  switch ($delta) {
1005
    // case 'delta-1':
1006
    // $block['subject'] = t('Credits');
1007
    // $block['content'] = theme('cdm_credits');
1008
    // return $block;
1009
    case '2':
1010
      $block['subject'] = t('Search taxa');
1011
      $form = drupal_get_form('cdm_dataportal_search_taxon_form');
1012
      $block['content'] = drupal_render($form);
1013

    
1014
      if (variable_get('cdm_dataportal_show_advanced_search', 1)) {
1015
        $block['content'] .= '<div>' . l(t('Advanced Search'), 'cdm_dataportal/search') . '</div>';
1016
      }
1017
      if (variable_get(CDM_SEARCH_BLAST_ENABLED)){
1018
          $block['content'] .= '<div>' . l(t('Blast Search'), 'cdm_dataportal/search/blast') . '</div>';
1019
      }
1020
      return $block;
1021
    case '4':
1022
      $block['subject'] = '';
1023
      $block['content'] = theme('cdm_print_button');
1024
      return $block;
1025
    case "keys":
1026
      $block['subject'] = t('Identification Keys');
1027
      $block['content'] = theme('cdm_block_IdentificationKeys', array('taxonUuid' => NULL));
1028
      return $block;
1029
    case "fundedByEDIT":
1030
      // t('Funded by EDIT');
1031
      $text = '<none>';
1032
      $block['subject'] = $text;
1033
      $img_tag = '<img src="' . base_path() . drupal_get_path('module', 'cdm_dataportal') . '/images/powered_by_edit.png' . '" alt="' . $text . '"/>';
1034
      $block['content'] = l($img_tag, "http://cybertaxonomy.org/", array(
1035
        'attributes' => array("target" => "EDIT"),
1036
        'absolute' => TRUE,
1037
        'html' => TRUE,
1038
      ));
1039
      return $block;
1040
    case 'classification_breadcrumbs':
1041
      $taxon_uuid = get_current_taxon_uuid();
1042
      $block['subject'] = '<none>';
1043
      $block['content'] = compose_classification_breadcrumbs($taxon_uuid);
1044
      return $block;
1045
    case 'taxonomic_children':
1046
      $taxon_uuid = get_current_taxon_uuid();
1047
      $block['subject'] = '<none>';
1048
      $block['content'] = compose_taxonomic_children($taxon_uuid);
1049
      return $block;
1050
    case 'back_to_search_results':
1051
      $block['subject'] = '<none>';
1052
      if (isset($_SESSION['cdm']['search'])) {
1053
        $block['content'] = l(t('Back to search result'), "http://" . $_SERVER['SERVER_NAME'] . $_SESSION['cdm']['last_search']);
1054
      }
1055
      return $block;
1056
    case 'registrations_search_filter':
1057
      $block['subject'] = '<none>';
1058
      $block['content'] = drupal_get_form('cdm_dataportal_search_registration_filter_form'); // see cdm_dataportal_search_registration_filter_form($form, &$form_state)
1059
      return $block;
1060
    case 'registrations_search_taxongraph':
1061
      $block['subject'] = '<none>';
1062
      $block['content'] = drupal_get_form('cdm_dataportal_search_registration_taxongraph_form'); // see cdm_dataportal_search_registration_taxongraph_form($form, &$form_state)
1063
      return $block;
1064
    case 'registrations_search':
1065
      _add_js_ui_accordion();
1066
      _add_font_awesome_font();
1067
      $block['subject'] = '<none>';
1068
      $filter_form = drupal_get_form('cdm_dataportal_search_registration_filter_form');
1069
      $filter_form['#prefix'] = '<div>';
1070
      $filter_form['#suffix'] = '</div>';
1071
      $taxongraph_form = drupal_get_form('cdm_dataportal_search_registration_taxongraph_form');
1072
      $taxongraph_form['#prefix'] = '<div>';
1073
      $taxongraph_form['#suffix'] = '</div>';
1074
      $block['content'] = array(
1075
        'accordion' => array(
1076
          '#markup' => '',
1077
          '#prefix' => '<div id="accordion">',
1078
          '#suffix' => '</div>',
1079
          'content' => array(
1080
            array('#markup' => '<h3>Filter</h3>'),
1081
            $filter_form,
1082
            array('#markup' => '<h3>Taxon graph</h3>'),
1083
            $taxongraph_form,
1084
          )
1085
        )
1086
    );
1087
       return $block;
1088
    case 'utis_search':
1089
      _add_js_utis_client('.utis_client');
1090
      $block['subject'] = '<none>';
1091
      $block['content'] = '<div class="utis_client"></div>';
1092
      return $block;
1093
    default:
1094
      return null;
1095
  }
1096
}
1097

    
1098

    
1099
/**
1100
 * Provides the uuid of the taxon for pages with the path ./taxon/{taxon_uuid}
1101
 *
1102
 * @return string
1103
 *   the taxon uuid or NULL
1104
 */
1105
function get_current_taxon_uuid()
1106
{
1107
  static $taxon_uuid;
1108

    
1109
  if(!isset($taxon_uuid)){
1110
    if(isset($_REQUEST['currentTaxon']) && is_uuid($_REQUEST['currentTaxon'])) {
1111
      $taxon_uuid = $_REQUEST['currentTaxon'];
1112
    } else if (arg(1) == 'taxon' && is_uuid(arg(2))) {
1113
      $taxon_uuid = arg(2);
1114
    } else {
1115
      $taxon_uuid = null;
1116
    }
1117
  }
1118
  return $taxon_uuid;
1119
}
1120

    
1121
/**
1122
 * Provides the uuid of the name for pages with the path ./name/{name_uuid}
1123
 *
1124
 * @return string
1125
 *   the name uuid or NULL
1126
 */
1127
function get_current_name_uuid()
1128
{
1129
  static $name_uuid;
1130
  if(!isset($name_uuid)){
1131
    if(arg(1) == 'name' && is_uuid(arg(2))) {
1132
      $name_uuid = arg(2);
1133
    } else {
1134
      $name_uuid = null;
1135
    }
1136
  }
1137
  return $name_uuid;
1138
}
1139

    
1140
/**
1141
 * Returns the currently classification tree in use.
1142
 *
1143
 * @return string
1144
 *   The uuid of the currently focused classification
1145
 */
1146
function get_current_classification_uuid() {
1147
  if (isset($_SESSION['cdm']['taxonomictree_uuid']) && is_uuid($_SESSION['cdm']['taxonomictree_uuid'])) {
1148
    return $_SESSION['cdm']['taxonomictree_uuid'];
1149
  }
1150
  else {
1151
    return variable_get(CDM_TAXONOMICTREE_UUID, FALSE);
1152
  }
1153
}
1154

    
1155
/*
1156
 function cdm_dataportal_session_clear($cdm_ws_uri_update = FALSE){
1157
 $_SESSION['cdm'] = NULL;
1158
 if(is_string($cdm_ws_uri_update)){
1159
 $_SESSION['cdm'] = array('ws_uri'=>$cdm_ws_uri_update);
1160
 }
1161
 }
1162

    
1163
 function cdm_dataportal_session_validate(){
1164
 if(!isset($_SESSION['cdm']['ws_uri'])){
1165
 $_SESSION['cdm'] = array('ws_uri'=>variable_get('cdm_webservice_url', FALSE));
1166
 } else if($_SESSION['cdm']['ws_uri'] != variable_get('cdm_webservice_url', FALSE)){
1167
 cdm_dataportal_session_clear(variable_get('cdm_webservice_url', FALSE));
1168
 }
1169
 }
1170
 */
1171

    
1172
/**
1173
 * creates a  selector form for taxonomic trees.
1174
 *
1175
 * @return array
1176
 *  a drupal form array
1177
 */
1178
function cdm_taxonomictree_selector() {
1179
  _add_js_treeselector();
1180

    
1181
  $form = drupal_get_form('cdm_taxonomictree_selector_form');
1182
  return $form;
1183
}
1184

    
1185
/**
1186
 * @todo Please document this function.
1187
 * @see http://drupal.org/node/1354
1188
 *
1189
 * used by cdm_taxonomictree_selector()
1190
 *
1191
 * @deprecated use compose_classification_selector instead
1192
 */
1193
function cdm_taxonomictree_selector_form($form, &$form_state) {
1194

    
1195
  $url = url('cdm_api/setvalue/session', array('query' => NULL));
1196
  $form['#action'] = $url;
1197

    
1198
  $form['var'] = array(
1199
    '#weight' => -3,
1200
    '#type' => 'hidden',
1201
    '#value' => '[cdm][taxonomictree_uuid]',
1202
  );
1203

    
1204
  $destination_array = drupal_get_destination();
1205
  $destination = $destination_array['destination'];
1206

    
1207
  $form['destination'] = array(
1208
    '#weight' => -3,
1209
    '#type' => 'hidden',
1210
    '#value' =>  $destination,
1211
  );
1212
  $options = cdm_get_taxontrees_as_options(
1213
    FALSE,
1214
    variable_get(CDM_TAXONTREE_INCLUDES, [])
1215
  );
1216
  $form['val'] = array(
1217
    '#type' => 'select',
1218
    '#title' => t('Available classifications'),
1219
    '#default_value' => get_current_classification_uuid(),
1220
    '#options' => $options,
1221
    '#attributes' => array('class' => array('highlite-first-child')),
1222
  );
1223

    
1224
  return $form;
1225

    
1226
}
1227

    
1228
/**
1229
 *
1230
 * @ingroup compose
1231
 */
1232
function compose_classification_selector() {
1233

    
1234
  $destination_array = drupal_get_destination();
1235
  $destination = $destination_array['destination'];
1236

    
1237
  $options = cdm_get_taxontrees_as_options(
1238
    FALSE,
1239
    variable_get(CDM_TAXONTREE_INCLUDES, [])
1240
  );
1241
  $items = array();
1242

    
1243
  $current_classification_uuid = get_current_classification_uuid();
1244

    
1245

    
1246
  foreach($options as $uuid=>$label){
1247
    $class_attributes = '';
1248
    if($current_classification_uuid == $uuid){
1249
      $class_attributes  = array('focused');
1250
    }
1251
    $items[] = array(
1252
      'data' => l($label,
1253
        'cdm_api/setvalue/session',
1254
        array(
1255
          'query' => array(
1256
            'destination' => $destination,
1257
            'val' => $uuid,
1258
            'var' => '[cdm][taxonomictree_uuid]'
1259
          ),
1260
        )
1261
      ),
1262
      'class' => $class_attributes
1263
    );
1264
  }
1265

    
1266
  $render_array = array(
1267
    '#theme' => 'item_list',
1268
    '#type' => 'ul',
1269
    '#items' => $items
1270
  );
1271

    
1272
  return $render_array;
1273
}
1274

    
1275

    
1276
/* ====================== menu callback functions ====================== */
1277
/**
1278
 * @todo Please document this function.
1279
 * @see http://drupal.org/node/1354
1280
 */
1281
/*
1282
function cdm_dataportal_form_alter(&$form, &$form_state, $form_id) {
1283
  static $comment_node_disabled =  0;
1284
  static $comment_node_read_only =  1;
1285
  static $comment_node_read_write =  2;
1286

    
1287
  if ($form_id == 'node_type_form'
1288
   && isset($form['identity']['type'])
1289
   && array_key_exists($form['#node_type']->type, cdm_get_nodetypes())
1290
  ) {
1291
    $form['workflow']['comment'] = array(
1292
      '#type' => 'radios',
1293
      '#title' => t('Default comment setting'),
1294
      '#default_value' => variable_get('comment__' . $node->type . $form['#node_type']->type, $comment_node_disabled),
1295
      '#options' => array(t('Disabled'), t('Read only'), t('Read/Write')),
1296
      '#description' => t('Users with the <em>administer comments</em> permission will be able to override this setting.'),
1297
    );
1298
  }
1299
}
1300
*/
1301

    
1302
/**
1303
 * Displays a list of the known taxonomic names.
1304
 *
1305
 * When the list of taxonomic names is displayed, long lists are split up into
1306
 * multiple pages.
1307
 *
1308
 * TODO: Parameters are still preliminary.
1309
 *
1310
 * @param string $beginsWith
1311
 * @param string $page
1312
 *   Page number to diplay defaults to page 1.
1313
 * @param bool $onlyAccepted
1314
 */
1315
function cdm_dataportal_view_names($beginsWith = 'A', $page = 1, $onlyAccepted = FALSE) {
1316

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

    
1319
  /*
1320
  // FIXME the filter for accepted names will be a form element, thus this
1321
  // widget should be generated via form api preferably as block.
1322
  $out  = theme('cdm_dataportal_widget_filter_accepted', $onlyAccepted);
1323
  $out .= theme('cdm_dataportal_widget_names_list', $names, $page);
1324
  $out .= theme('cdm_listof_taxa', $taxonPager);
1325
  return $out;
1326
  */
1327
}
1328

    
1329
/**
1330
 * @todo Please document this function.
1331
 * @see http://drupal.org/node/1354
1332
 * @throws Exception
1333
 */
1334
function cdm_dataportal_view_reference($uuid, $arg2 = NULL) {
1335

    
1336
  cdm_check_valid_portal_page();
1337

    
1338
  return compose_cdm_reference_page($uuid);
1339
}
1340

    
1341
/**
1342
 * Creates a view on a all references contained in the portal.
1343
 *
1344
 * This function is used at the path cdm_dataportal/reference/list
1345
 */
1346
function cdm_dataportal_view_reference_list($pageNumber) {
1347
  $referencePager = cdm_ws_page(CDM_WS_REFERENCE, variable_get(CDM_SEARCH_RESULT_PAGE_SIZE, CDM_SEARCH_RESULT_PAGE_SIZE_DEFAULT), $pageNumber);
1348
  cdm_reference_pager($referencePager, 'cdm_dataportal/reference/list/');
1349
}
1350

    
1351
/**
1352
 * @todo Please document this function.
1353
 * @see http://drupal.org/node/1354
1354
 */
1355
function cdm_dataportal_view_media($mediaUuid, $mediarepresentation_uuid = FALSE, $part = 0) {
1356

    
1357
  cdm_check_valid_portal_page();
1358

    
1359
  $media = cdm_ws_get(CDM_WS_PORTAL_MEDIA, $mediaUuid);
1360
  if (!$media) {
1361
    drupal_set_title(t('Media does not exist'), PASS_THROUGH);
1362
    return "";
1363
  }
1364
  return theme('cdm_media_page', array(
1365
    'media' => $media,
1366
    'mediarepresentation_uuid' => $mediarepresentation_uuid,
1367
    'partId' => $part,
1368
    ));
1369
}
1370

    
1371
/**
1372
 * Loads the media associated to the given taxon from the cdm server.
1373
 * The aggregation settings regarding taxon relathionships and
1374
 * taxonnomic childen are taken into account.
1375
 *
1376
 * The media lists are cached in a static variable.
1377
 *
1378
 * @param Taxon $taxon
1379
 *   A CDM Taxon entity
1380
 *
1381
 * @return array
1382
 *   An array of CDM Media entities
1383
 *
1384
 */
1385
  function _load_media_for_taxon($taxon) {
1386

    
1387
  static $media = NULL;
1388

    
1389
  if(!isset($media)) {
1390
    $media = array();
1391
  }
1392
  if (!isset($media[$taxon->uuid])) {
1393

    
1394

    
1395
    $mediaQueryParameters = taxon_media_query_parameters();
1396

    
1397
    $ws_endpoint = NULL;
1398
    if ( $mediaQueryParameters['includeTaxonomicChildren']) {
1399
      $ws_endpoint = CDM_WS_PORTAL_TAXON_SUBTREE_MEDIA;
1400
    } else {
1401
      $ws_endpoint = CDM_WS_PORTAL_TAXON_MEDIA;
1402
    }
1403
    // this parameter is not yet used by the CDM_WS_PORTAL_TAXON_*MEDIA
1404
    // services
1405
    unset($mediaQueryParameters['includeTaxonomicChildren']);
1406

    
1407
    $media[$taxon->uuid] = cdm_ws_get($ws_endpoint,
1408
        array(
1409
            $taxon->uuid,
1410
        ),
1411
        queryString($mediaQueryParameters)
1412
       );
1413
  }
1414

    
1415
  return $media[$taxon->uuid];
1416
}
1417

    
1418
/**
1419
 *
1420
 * @param Taxon $taxon
1421
 *   A CDM Taxon entitiy
1422
 *
1423
 * @return array
1424
 *   An array of CDM SpecimenOrObservation entities
1425
 *
1426
function _load_occurences_for_taxon($taxon){
1427

    
1428
  static $occurences = NULL;
1429

    
1430
  if(!isset($occurences)) {
1431
    $occurences = array();
1432
  }
1433

    
1434
  if (!isset($occurences[$taxon->uuid])){
1435

    
1436
    $relationship_choice = variable_get(CDM_AGGREGATE_BY_TAXON_RELATIONSHIPS, unserialize(CDM_AGGREGATE_BY_TAXON_RELATIONSHIPS_DEFAULT));
1437
    $relationship_choice['direct'] = get_selection($relationship_choice['direct']);
1438
    $relationship_choice['invers'] = get_selection($relationship_choice['invers']);
1439

    
1440
    $by_associatedtaxon_query = http_build_query(array(
1441
        'relationshipsInvers' => implode(',', $relationship_choice['invers']),
1442
        'relationships' => implode(',', $relationship_choice['direct']),
1443
        'pageSize' => null // all hits in one page
1444
    )
1445
    );
1446

    
1447
    $pager = cdm_ws_get(CDM_WS_OCCURRENCE_BY_ASSOCIATEDTAXON,
1448
        null,
1449
        $by_associatedtaxon_query . '&taxonUuid=' . $taxon->uuid
1450
    );
1451

    
1452

    
1453
    if(isset($pager->records[0])){
1454
      $occurences[$taxon->uuid] =  $pager->records;
1455
    }
1456
  }
1457
  return $occurences[$taxon->uuid];
1458
}
1459
 */
1460

    
1461
/**
1462
 * Gets a Drupal variable, string or array and returns it.
1463
 *
1464
 * Similar to the variable_get() function of Drupal, except that this function
1465
 * is able to handle arrays correctly. This function is especially useful
1466
 * when dealing with collections of settings form elements (#tree = TRUE).
1467
 *
1468
 * @param string $variableKey
1469
 *   The Unique key of the Drupal variable in the Drupal variables table.
1470
 * @param string $defaultValueString
1471
 *   A string as for example derived from a CONSTANT.
1472
 *
1473
 * @return mixed
1474
 *   usually an array, depending on the nature of the variable.
1475
 *
1476
 * TODO compare with get_array_variable_merged() duplicate functions?
1477
 * @deprecated rather use get_array_variable_merged() since this function
1478
 * used an array as second parameter
1479
 */
1480
function mixed_variable_get($variableKey, $defaultValueString) {
1481
  $systemDefaults = unserialize($defaultValueString);
1482
  $storedSettings = variable_get($variableKey, array());
1483
  if (is_array($storedSettings)) {
1484
    // TODO better use drupal_array_merge_deep() ?
1485
    $settings = array_merge($systemDefaults, $storedSettings);
1486
  }
1487
  else {
1488
    $settings = $systemDefaults;
1489
  }
1490
  return $settings;
1491
}
1492

    
1493
/**
1494
 * Recursive function to convert an object into an array.
1495
 * also subordinate objects will be converted.
1496
 *
1497
 * @param object $object
1498
 *  the object to be converted
1499
 * @return array
1500
 *  The array
1501
 */
1502
function object_to_array($object) {
1503
  if(is_object($object) || is_array($object)) {
1504
    $array = (array)$object;
1505
    foreach ($array as $key=>$value){
1506
      $array[$key] = object_to_array($value);
1507
    }
1508
    return $array;
1509
  } else {
1510
    return $object;
1511
  }
1512
}
1513

    
1514
/**
1515
 * Searches the $collection for the cdm entitiy given as $element.
1516
 *
1517
 * The elements are compared by their UUID.
1518
 *
1519
 * @param $element
1520
 *  the CDM entitiy to search for
1521
 * @param $collection
1522
 *  the list of CDM entities to search in
1523
 *
1524
 * @return boolean TRUE if the $collection contains the $element, otheriwse FALSE
1525
 *
1526
 */
1527
function contains_cdm_entitiy($element, $collection) {
1528
  $result = FALSE;
1529
  foreach ($collection as $a) {
1530
    if ($a->uuid == $element->uuid) {
1531
      $result = TRUE;
1532
    }
1533
  }
1534
  return $result;
1535
}
1536

    
1537
/**
1538
 * Filters the array $entity_list of CDM entities by the list
1539
 * of $excludes. Any element contained in the $excludes will be removed
1540
 * from included int the returned list.
1541
 *
1542
 * If the $entity_list is not an array the $excludes will be returned.
1543
 */
1544
function filter_cdm_entity_list($entity_list, $excludes) {
1545
  if (is_array($entity_list)) {
1546
    $result = $entity_list;
1547
    if ($excludes) {
1548
      foreach ($excludes as $exclude) {
1549
        if (!contains_cdm_entitiy($exclude, $entity_list)) {
1550
          $result[] = $exclude;
1551
        }
1552
      }
1553
    }
1554
  }
1555
  else {
1556
    $result = $excludes;
1557
  }
1558
  return $result;
1559
}
1560

    
1561
/**
1562
 * Wraps the given $html string into a render array suitable for drupal_render()
1563
 *
1564
 * @param $html
1565
 *   the html string, see
1566
 *   http://api.drupal.org/api/drupal/developer!topics!forms_api_reference.html/7#markup
1567
 * @param $weight
1568
 *   A positive or negative number (integer or decimal).
1569
 *   see http://api.drupal.org/api/drupal/developer!topics!forms_api_reference.html/7#weightval
1570
 * @param $prefix
1571
 *   Optional markup for the '#prefix' element of the render array
1572
 * @param $suffix
1573
 *   Optional markup for the '#suffix' element of the render array
1574
 *
1575
 * @return array
1576
 *   A render array
1577
 *
1578
 */
1579
function markup_to_render_array($html, $weight = FALSE, $prefix = NULL, $suffix = NULL) {
1580
  $render_array = array(
1581
    '#markup' => $html
1582
      );
1583
  if (is_numeric($weight)) {
1584
    $render_array['#weight'] = $weight;
1585
  }
1586
  if($prefix){
1587
    $render_array['#prefix'] = $prefix;
1588
  }
1589
  if($suffix) {
1590
    $render_array['#suffix'] = $suffix;
1591
  }
1592
  return $render_array;
1593
}
1594

    
1595
/**
1596
 * Loads the subgraph of a given PolytomousKeyNode.
1597
 *
1598
 * Loads the subgraph of the given PolytomousKeyNode recursively from
1599
 * the CDM REST service.
1600
 *
1601
 * @param mixed $polytomousKeyNode
1602
 *   PolytomousKeyNode passed by reference.
1603
 *
1604
 * @return void
1605
 */
1606
function _load_polytomousKeySubGraph(&$polytomousKeyNode) {
1607

    
1608
  if (!$polytomousKeyNode) {
1609
    return;
1610
  }
1611
  if ($polytomousKeyNode->class != "PolytomousKeyNode") {
1612
    drupal_set_message('_load_polytomousKeySubGraph(): ' . t('invalid type given.'), 'error');
1613
    return;
1614
  }
1615
  if (!is_uuid($polytomousKeyNode->uuid)) {
1616
    drupal_set_message('_load_polytomousKeySubGraph(): ' . t('invalid type given.'), 'error');
1617
    return;
1618
  }
1619

    
1620
  $polytomousKeyNode = cdm_ws_get(CDM_WS_PORTAL_POLYTOMOUSKEY_NODE, $polytomousKeyNode->uuid);
1621

    
1622
  if (!$polytomousKeyNode) {
1623
    // drupal_set_message("_load_polytomousKeyChildNodes() : could not load polytomousKeyNode", "error");
1624
    return;
1625
  }
1626

    
1627
  // Load children.
1628
  foreach ($polytomousKeyNode->children as &$childNode) {
1629
    _load_polytomousKeySubGraph($childNode);
1630
  }
1631
  return;
1632
}
1633

    
1634
/**
1635
 * @todo Please document this function.
1636
 * @see http://drupal.org/node/1354
1637
 */
1638
function cdm_dataportal_view_polytomousKey($polytomousKeyUuid) {
1639

    
1640
  cdm_check_valid_portal_page();
1641

    
1642
  $polytomousKey = cdm_ws_get(CDM_WS_POLYTOMOUSKEY, $polytomousKeyUuid);
1643
  if (!$polytomousKey) {
1644
    drupal_set_title(t('Polytomous key does not exist'), PASS_THROUGH);
1645
    return "";
1646
  }
1647

    
1648
  $sourcePager = cdm_ws_get(CDM_WS_POLYTOMOUSKEY, array($polytomousKeyUuid, 'sources'));
1649
  if (is_array($sourcePager->records)) {
1650
    $polytomousKey->sources = $sourcePager->records;
1651
    // $polytomousKey->sources->citation = cdm_ws_get(CDM_WS_POLYTOMOUSKEY, array($polytomousKeyUuid, 'sources'));
1652
  }
1653

    
1654
  $annotationPager = cdm_ws_get(CDM_WS_POLYTOMOUSKEY, array($polytomousKeyUuid, 'annotations'));
1655
  if (is_array($annotationPager->records)) {
1656
    $polytomousKey->annotations = $annotationPager->records;
1657
  }
1658

    
1659
  _load_polytomousKeySubGraph($polytomousKey->root);
1660
  return theme('cdm_polytomousKey_page', array('polytomousKey' => $polytomousKey));
1661
}
1662

    
1663
/**
1664
 * Creates a taxon page view or a chapter of it.
1665
 *
1666
 * The taxon page gives detailed information on a taxon, it shows:
1667
 *  - Taxon name.
1668
 *  - Full list of synonyms homotypic synonyms on top, followed by the
1669
 *    heterotypic and finally followed by misapplied names.
1670
 *    The list is ordered historically.
1671
 *  - All description associated with the taxon.
1672
 *
1673
 * @param string $uuid
1674
 * @param string $chapter
1675
 *   Name of the part to display, valid values are:
1676
 *   'description', 'images', 'synonymy', 'specimens', 'all'.
1677
 *
1678
 * @return string
1679
 */
1680
function cdm_dataportal_taxon_page_view($uuid, $chapter = 'all') {
1681

    
1682
  cdm_check_valid_taxon_page($chapter);
1683
  cdm_dd("START OF TAXON PAGE [" . $chapter . "] " . $uuid . ' for ' . $_GET['q']);
1684

    
1685

    
1686
  // Display the page for the taxon defined by $uuid.
1687
  // set_last_taxon_page_tab(arg(3));
1688
  $taxonpage = cdm_dataportal_taxon_view($uuid, $chapter);
1689
  if (!empty($taxonpage)) {
1690
    cdm_dd("END OF TAXON PAGE [" . $chapter . "] " . $uuid);
1691
    return cdm_node_show(NODETYPE_TAXON, $uuid, $taxonpage->title, $taxonpage->content);
1692
  }
1693
  else {
1694
    cdm_dd("END OF TAXON PAGE [" . $chapter . "] " . $uuid . ' !!! PAGE IS EMPTY !!!');
1695
    return '';
1696
  }
1697
}
1698

    
1699
/**
1700
 * This function will generate the taxon page part ($chapter) and returns a taxonpage object
1701
 * which has two fields, one for the page title and one for the content. Later on in the
1702
 * process chain the value contained in these fields will be passed to the cdm_node_show()
1703
 * function as the function parameters $title and $content.
1704
 *
1705
 * @param string $uuid
1706
 *   the uuid of the taxon to show
1707
 * @param string $chapter
1708
 *   Name of the part to display, valid values are:
1709
 *   'description', 'images', 'synonymy', 'all'.
1710
 *
1711
 * @return object with the following fields:
1712
 *   - title : the title of the page
1713
 *   - content: the content of the page
1714
 *
1715
 * @throws Exception
1716
 *
1717
 */
1718
function cdm_dataportal_taxon_view($uuid, $chapter = 'all') {
1719
  // Taxon object.
1720
  $taxon = cdm_ws_get(CDM_WS_PORTAL_TAXON, $uuid);
1721
  if (empty($taxon)) {
1722
    drupal_set_title(t('Taxon does not exist'), PASS_THROUGH);
1723
    return null;
1724
  }
1725
  $taxonpage = new stdClass();
1726

    
1727
  $taxonpage->title = theme('cdm_taxon_page_title', array(
1728
    'taxon' => $taxon
1729
  ));
1730

    
1731
  // Check if the taxon id contained in the currently selected tree.
1732
  $taxon_in_current_classification = taxon_in_current_classification($uuid);
1733

    
1734
  if (!$taxon_in_current_classification) {
1735
    $classifications = get_classifications_for_taxon($taxon);
1736
    RenderHints::pushToRenderStack('not_in_current_classification');
1737
    RenderHints::setFootnoteListKey('not_in_current_classification');
1738
    FootnoteManager::blockFootnotesFor('not_in_current_classification');
1739
    $taxon_name_markup = render_taxon_or_name($taxon);
1740
    FootnoteManager::unblockFootnotesFor('not_in_current_classification');
1741
    RenderHints::clearFootnoteListKey();
1742

    
1743
    if (count($classifications) == 0) {
1744
      drupal_set_message(t('This concept of the taxon !taxonname is not contained as an accepted taxon in the currently chosen classification.',
1745
        array(
1746
        '!taxonname' => $taxon_name_markup,
1747
        )
1748
      ), 'warning');
1749
    }
1750
    else {
1751
      $trees = [];
1752
      foreach ($classifications as $classification) {
1753
        if (isset($classification->titleCache)) {
1754
          $trees[] = '<strong>' . $classification->titleCache . '</strong>';
1755
        }
1756
      }
1757

    
1758
      drupal_set_message(format_plural(count($trees),
1759
          'This concept of the taxon !taxonname is not contained as an accepted taxon in the currently chosen classification, but in this one: !trees',
1760
          'This concept of the taxon !taxonname is not contained as an accepted taxon in the currently chosen classification, but in one of these: !trees',
1761
          array('!taxonname' => $taxon_name_markup, '!trees' => join(', ', $trees))
1762
        ) ,
1763
        'warning');
1764
    }
1765
    RenderHints::popFromRenderStack();
1766
  }
1767

    
1768
  // Render the taxon page.
1769
  $render_array = compose_cdm_taxon_page($taxon, $chapter);
1770
  $taxonpage->content = drupal_render($render_array);
1771

    
1772
  return $taxonpage;
1773
}
1774

    
1775

    
1776
function cdm_dataportal_specimen_by_accession_number_page_view($accession_number)
1777
{
1778
  cdm_check_valid_portal_page();
1779

    
1780
  $specimenpage = specimen_by_accession_number_view($accession_number);
1781

    
1782
  if (!empty($specimenpage)) {
1783
    return cdm_node_show_simulate($specimenpage->content);
1784
  }
1785
  else {
1786
    return '';
1787
  }
1788

    
1789

    
1790
}
1791

    
1792
/**
1793
 * Creates a specimen page view.
1794
 * @param string $uuid the UUID of the specimen
1795
 * @return array|string
1796
 */
1797
function cdm_dataportal_specimen_page_view($uuid) {
1798

    
1799
    cdm_check_valid_portal_page();
1800
    $specimenpage = cdm_dataportal_specimen_view($uuid);
1801
    if (!empty($specimenpage)) {
1802
        return cdm_node_show_simulate($specimenpage->content);
1803
    }
1804
    else {
1805
        return '';
1806
    }
1807
}
1808

    
1809

    
1810
/**
1811
 * Creates a specimen page view.
1812
 * @param string $uuid the UUID of the specimen
1813
 * @return object
1814
 *  The page object with the following fields:
1815
 *   - 'title': the page title
1816
 *   - 'content' : the page content rendered as markup
1817
 */
1818
function specimen_by_accession_number_view($accession_number = null) {
1819

    
1820
  $field_unit_dto = cdm_ws_get(CDM_WS_OCCURRENCE_ACCESSION_NUMBER, null, 'accessionNumber=' . $accession_number);
1821

    
1822
  // Display the page for the specimen defined by $uuid.
1823
  if (isset($field_unit_dto)){
1824
    $dto_array = array($field_unit_dto);
1825
    $specimen_array = specimen_render_array_items($dto_array);
1826
    $specimen_table = array(
1827
      '#theme' => 'table',
1828
      '#weight' => 2,
1829
      // prefix attributes and rows with '#' to let it pass toF the theme function,
1830
      // otherwise it is handled as child render array
1831
      '#attributes' => array('class' => 'specimens'),
1832
      '#rows' => array(),
1833
      '#prefix' => '<div id="specimens">',
1834
      '#suffix' => '</div>',
1835
    );
1836
    foreach($specimen_array as $value){
1837
      $renderArray = array(
1838
        '#theme' => 'item_list',
1839
        '#items' => array($value),
1840
        '#type' => 'ul');
1841
      $output = drupal_render($renderArray);
1842
      $specimen_table['#rows'][] = array(
1843
        // An array of table rows. Every row is an array of cells, or an associative array
1844
        'data' => array($output),
1845
        'class' =>  array(
1846
          'descriptionElement',
1847
          'descriptionElement_IndividualsAssociation'
1848
        ),
1849
      );
1850

    
1851

    
1852
    }
1853
    $specimenpage = new stdClass();
1854

    
1855
    $specimenpage->title = render_cdm_specimen_dto_page_title($field_unit_dto);
1856

    
1857
     $render_array['markup'] = $specimen_table;
1858
     $specimenpage->content = drupal_render($render_array);
1859
  }
1860

    
1861
  return $specimenpage;
1862
}
1863

    
1864

    
1865
/**
1866
 *
1867
 * Creates a specimen view.
1868
 * @param string $uuid the UUID of the specimen
1869
 * @return object
1870
 *    Page object with the fields
1871
 *    - title
1872
 *    - content
1873
 */
1874
function cdm_dataportal_specimen_view($uuid) {
1875

    
1876
    $sob_dto = cdm_ws_get(CDM_WS_PORTAL_OCCURRENCE_AS_DTO, $uuid);
1877
    if (empty($sob_dto)) {
1878
        drupal_set_title(t('Specimen does not exist'), PASS_THROUGH);
1879
        return FALSE;
1880
    }
1881
    $specimenpage = new stdClass();
1882
    $specimenpage->title = render_specimen_page_title($sob_dto);
1883

    
1884
    // Render the specimen page.
1885
    $render_array = compose_cdm_specimen_page($sob_dto);
1886
    $specimenpage->content = drupal_render($render_array);
1887

    
1888
    return $specimenpage;
1889
}
1890

    
1891
/**
1892
 *
1893
 * Creates a description view.
1894
 *
1895
 * @param string $uuid the UUID of the description
1896
 * @param null $descriptive_dataset_uuid the uuid of the data set which defines
1897
 * the display of the description detail page
1898
 *
1899
 * @return object Page object with the fields
1900
 * Page object with the fields
1901
 * - title
1902
 * - content
1903
 */
1904
function cdm_dataportal_description_view($uuid, $descriptive_dataset_uuid = NULL) {
1905
    $description = cdm_ws_get(CDM_WS_PORTAL_DESCRIPTION, $uuid);
1906
    $description_page = new stdClass();
1907
    if (empty($description)) {
1908
      $description_page->title = t('Description does not exist');
1909
      drupal_set_title($description_page->title, PASS_THROUGH); // not necessary if correctly implemented as drupal node
1910
      $description_page->content = "";
1911

    
1912
    } else {
1913
      $description_page->title = $description->titleCache;
1914
      drupal_set_title($description_page->title); // not necessary if correctly implemented as drupal node
1915

    
1916
      // Render the description page.
1917
      $render_array = compose_description_table($description->uuid, $descriptive_dataset_uuid);
1918
      if($render_array['title']){
1919
        $page_title = strip_tags($render_array['title']['#markup']);
1920
        drupal_set_title($page_title);
1921
        unset($render_array['title']);
1922
      }
1923
      $description_page->content = drupal_render($render_array);
1924
    }
1925

    
1926
    return $description_page;
1927
}
1928

    
1929
function cdm_dataportal_description_page_view($uuid, $descriptive_dataset_uuid = NULL) {
1930

    
1931
  cdm_check_valid_portal_page();
1932
  $descriptionpage = cdm_dataportal_description_view($uuid, $descriptive_dataset_uuid);
1933
  if (!empty($descriptionpage)) {
1934
    return cdm_node_show_simulate($descriptionpage->content);
1935
  }
1936
  else {
1937
    return NULL;
1938
  }
1939
}
1940

    
1941
/**
1942
 *
1943
 * Creates a named area view.
1944
 * @param string $uuid the UUID of the specimen
1945
 *  * @return object
1946
 *   An object with two fields:
1947
 *     - title: the page title
1948
 *     - content: the page content
1949
 */
1950

    
1951
function cdm_dataportal_named_area_view($uuid) {
1952
  $named_area = cdm_ws_get(CDM_WS_PORTAL_TERM, $uuid);
1953
  if (empty($named_area) || $named_area->class !== 'NamedArea') {
1954
    drupal_set_title(t('Named area does not exist'), PASS_THROUGH);
1955
    return null;
1956
  }
1957
  $named_area_page = new stdClass();
1958

    
1959
  $named_area_page->title = $named_area->representation_L10n;
1960

    
1961
  // Render the specimen page.
1962
  $render_array = compose_cdm_named_area_page($uuid);
1963
  $named_area_page->content = drupal_render($render_array);
1964

    
1965
  return $named_area_page;
1966
}
1967

    
1968
function cdm_dataportal_named_area_page_view($uuid) {
1969

    
1970
  cdm_check_valid_portal_page();
1971

    
1972
  $named_area_page = cdm_dataportal_named_area_view($uuid);
1973
  if (!empty($named_area_page)) {
1974
    return cdm_node_show(NODETYPE_NAME, $uuid, $named_area_page->title, $named_area_page->content);
1975
  }
1976
  else {
1977
    return '';
1978
  }
1979

    
1980

    
1981
}
1982

    
1983
/**
1984
 * Returns a name page as a Drupal node ready to be renderized by Drupal.
1985
 *
1986
 * The node page shows the taxon name title and the list of taxon related
1987
 * with such taxon. Name on the tree already in use.
1988
 *
1989
 * @param string $taxon_name_uuid
1990
 *   The uuid of the CDM TaxonName to show a name page for
1991
 * @param string $taxon_to_hide_uuid
1992
 *   A taxon which should not be displayed in the taxon list
1993
 * @param $redirect_to_taxon
1994
 *   Automatically redirect to the related taxon if there is only one
1995
 *   accepted taxon for this name.
1996
 * @param string $highlite_synonym_uuid
1997
 *   Optinal parameter wich takes another taxon uuid, if given the
1998
 *   target taxon pages will show the syonymy tab where the taxon
1999
 *   refenrenced by the $highlite_synonym_uuid will be highlighted
2000
 *   in case it is found on this page.
2001
 *
2002
 * @return mixed
2003
 *   The formatted name page as node.
2004
 */
2005
function cdm_dataportal_name_page_view($taxon_name_uuid, $taxon_to_hide_uuid, $synonym_uuid = NULL, $redirect_to_taxon = false) {
2006

    
2007
  cdm_check_valid_portal_page();
2008

    
2009
  $taxonname_page = cdm_dataportal_name_view(
2010
    is_uuid($taxon_name_uuid) ? $taxon_name_uuid : null,
2011
    is_uuid($taxon_to_hide_uuid) ? $taxon_to_hide_uuid : null,
2012
    $redirect_to_taxon == 'redirect_to_taxon',
2013
    is_uuid($synonym_uuid) ? $synonym_uuid : null);
2014
  if (!empty($taxonname_page)) {
2015
    return cdm_node_show(NODETYPE_NAME, $taxon_name_uuid, $taxonname_page->title, $taxonname_page->content);
2016
  }
2017
  else {
2018
    return '';
2019
  }
2020
}
2021

    
2022
/**
2023
 * View function for a TaxonName page.
2024
 *
2025
 * The name page lists all taxa for which the name specified by the
2026
 * $taxon_name_uuid is being used. I case there is only one name the
2027
 * page automatically redirects ti the according taxon page. Otherwise
2028
 * the list of names is displayed.
2029
 *
2030
 * The parameter $taxon_to_hide_uuid allows to exclude a taxon from the
2031
 * list of taxa. This is useful for example when referencing from a taxon
2032
 * to the name page and the referring taxon should not be repeaded in the
2033
 * name page.
2034
 *
2035
 *
2036
 * @param string $taxon_name_uuid
2037
 *   The uuid of the CDM TaxonName to show a name page for
2038
 * @param string $taxon_to_hide_uuid
2039
 *   A taxon which should not be displayed in the taxon list
2040
 * @param $redirect_to_taxon
2041
 *   Automatically redirect to the related taxon if there is only one
2042
 *   accepted taxon for this name.
2043
 * @param string $highlite_synonym_uuid
2044
 *   Optional parameter which takes another taxon uuid, if given the
2045
 *   target taxon pages will show the synonymy tab where the taxon
2046
 *   referenced by the $highlite_synonym_uuid will be highlighted
2047
 *   in case it is found on this page.
2048
 *
2049
 * @return object|boolean
2050
 *   An object with two fields:
2051
 *     - title: the page title
2052
 *     - content: the page content
2053
 *   or FALSE
2054
 *
2055
 */
2056
function cdm_dataportal_name_view($taxon_name_uuid, $taxon_to_hide_uuid, $redirect_to_taxon, $highlite_synonym_uuid = NULL) {
2057
  // Getting the full taxonname object from the server.
2058
  $taxon_name = cdm_ws_get(CDM_WS_PORTAL_NAME, array($taxon_name_uuid));
2059
  if (!$taxon_name) {
2060
    drupal_set_title(t('Taxon name does not exist'), PASS_THROUGH);
2061
    return FALSE;
2062
  }
2063
  cdm_load_tagged_full_title($taxon_name);
2064
  // Searching for all the taxa connected with the taxon name on the tree
2065
  // in use.
2066
  $name = cdm_ws_get(CDM_WS_NAME, array($taxon_name_uuid));
2067
  $restrictions = array(new Restriction("name.titleCache","EXACT", array($name->titleCache), 'AND'));
2068
  $init_strategy = array(
2069
    "name.titleCache",
2070
    "name.nomenclaturalReference.authorship",
2071
    "name.nomenclaturalReference.inReference.authorship",
2072
    "name.nomenclaturalReference.inReference.inReference.authorship",
2073
    "name.nomenclaturalReference.inReference.inReference.inReference.authorship"
2074
  );
2075
  $taxa = cdm_ws_fetch_all_by_restriction("Taxon", NULL, $restrictions, $init_strategy);
2076

    
2077
  // Removing the name where we came from.
2078
  foreach ($taxa as $k => &$taxon) {
2079
    if ($taxon->uuid == $taxon_to_hide_uuid) {
2080
      unset($taxa[$k]);
2081
    }
2082
  }
2083
  // Show the taxa list or go to the singular taxon.
2084
  if (sizeof($taxa) == 1 && $redirect_to_taxon) {
2085
    // redirect to the taxon if there is only one.
2086
    $singleTaxon = array_pop($taxa);
2087
    if ($singleTaxon->class != "Taxon") {
2088
      // It is a Synonym -> look for the accepted.
2089
      $accepted_taxon = cdm_ws_get(CDM_WS_PORTAL_TAXON_ACCEPTED, array($singleTaxon->uuid), 'classificationFilter=' . get_current_classification_uuid());
2090
      if (!empty($highlite_synonym_uuid)) {
2091
        drupal_goto('cdm_dataportal/taxon/' . $accepted_taxon->uuid . '/synonymy', array('query' => array('highlite' => $highlite_synonym_uuid)));
2092
      }
2093
      else {
2094
        drupal_goto('cdm_dataportal/taxon/' . $accepted_taxon->uuid . '/synonymy', array('query' => array('highlite' => $singleTaxon->uuid)));
2095
      }
2096
    }
2097
    else {
2098
      // It is an accepted taxon.
2099
      if (!empty($highlite_synonym_uuid)) {
2100
        drupal_goto('cdm_dataportal/taxon/' . $singleTaxon->uuid . '/synonymy', array('query' => array('highlite' => $highlite_synonym_uuid)));
2101
      }
2102
      else {
2103
        drupal_goto('cdm_dataportal/taxon/' . $singleTaxon->uuid);
2104
      }
2105
    }
2106
  }
2107
  else {
2108
    // display the name page content
2109
    $taxon_name_page = new stdClass();
2110
    $taxon_name_page->title = theme('cdm_name_page_title', array('taxon_name' => $taxon_name));
2111
    $content = array();
2112

    
2113
    RenderHints::pushToRenderStack('name_page');
2114
    RenderHints::setFootnoteListKey('name_page');
2115
    $content['taxon_name'] = markup_to_render_array(render_taxon_or_name($taxon_name), null, '<div class="name-page-name">', '</div>');
2116

    
2117

    
2118
    // name relationships
2119
    $name_relations = cdm_ws_fetch_all(str_replace("$0", $taxon_name->uuid, CDM_WS_PORTAL_NAME_NAME_RELATIONS));
2120
    if(count($name_relations) > 0){
2121
      $content['name_relationships'] = compose_name_relationships_list($name_relations, $taxon_name->uuid, null);
2122
    }
2123

    
2124
    // type designations
2125
    $type_designations_render_array = compose_type_designations($taxon_name->uuid);
2126
    $content = array_merge($content, $type_designations_render_array);
2127
    // registrations
2128
    $registrationDTOs= cdm_ws_fetch_all(CDM_WS_REGISTRATION_DTO,  array('nameUuid' => $taxon_name_uuid));
2129
    if(isset($registrationDTOs) && count($registrationDTOs ) > 0 ){
2130
      $content['registrations'][] = markup_to_render_array('<h2>' . t("Registrations") . '</h2>') ;
2131
      foreach ($registrationDTOs as $regDTO){
2132
        $content['registrations'][] = compose_registration_dto_compact($regDTO);
2133
      }
2134
    }
2135

    
2136

    
2137
    // related taxa
2138
    $show_taxa_section = variable_get(CDM_NAME_PAGE_SECTION_TAXA, CDM_NAME_PAGE_SECTION_TAXA_DEFAULT);
2139
    if($show_taxa_section){
2140
      if ($taxa) {
2141
        $content['related_taxa_header'] = markup_to_render_array("<h2>" . count($taxa) > 1 ? t("Taxa for this name") :  t("Taxon for this name") . "</h2>");
2142
        $content['related_taxa'] = compose_list_of_taxa($taxa);
2143
      }
2144
      else {
2145
        $content['related_taxa'] = markup_to_render_array('This name is not assigned to any taxon.', null, '<div class="no-taxon-message">', '</div>');
2146
      }
2147
    }
2148

    
2149
    $content['footnotes'] = markup_to_render_array(render_footnotes());
2150

    
2151
    $taxon_name_page->content = $content;
2152
    RenderHints::popFromRenderStack();
2153
    RenderHints::clearFootnoteListKey();
2154
    return $taxon_name_page;
2155
  }
2156
}
2157

    
2158

    
2159
/**
2160
 * Returns a registration page as a Drupal node to be rendered by Drupal.
2161
 *
2162
 * @param string  $registration_identifie
2163
 *   The persistent identifier of the registration urlencoded.
2164
 * @return mixed
2165
 *   The formatted registration page as node.
2166
 */
2167
function cdm_dataportal_registration_page_view() {
2168

    
2169
  cdm_check_valid_portal_page("/\/cdm_dataportal\/registration/");
2170
  $registration_identifier = $_REQUEST['identifier'];
2171
  $registration_page = cdm_dataportal_registration_view($registration_identifier);
2172
  return cdm_node_show_simulate($registration_page);
2173
}
2174

    
2175
/**
2176
 * @param $registration_identifier
2177
 * @return array
2178
 *   The drupal render array for the registration view.
2179
 */
2180
function cdm_dataportal_registration_view($registration_identifier) {
2181

    
2182
  RenderHints::pushToRenderStack('registration_page');
2183
  RenderHints::setFootnoteListKey('registration_page');
2184

    
2185
  $render_array = array();
2186
  $registration_dto = cdm_ws_get(CDM_WS_REGISTRATION_DTO, null, 'identifier=' . $registration_identifier);
2187
  if($registration_dto){
2188

    
2189
    drupal_set_title(t('Registration Id:') . ' ' . $registration_identifier, PASS_THROUGH);
2190
    $render_array = compose_registration_dto_full($registration_dto, true);
2191

    
2192
  } else {
2193
    $status_text = cdm_ws_get(CDM_WS_REGISTRATION_STATUS, null, 'identifier=' . $registration_identifier);
2194
    if(isset($status_text->String)) {
2195
      $status_text = strtolower($status_text->String);
2196
      if($status_text == 'preparation' || $status_text == 'curation'){
2197
        $status_text = 'in ' . $status_text;
2198
      }
2199
      drupal_set_title(t('Registration ' . $status_text), PASS_THROUGH);
2200
      //$status_message;
2201
      drupal_set_message("A registration with the identifier  " . $registration_identifier . " is " . $status_text, "status");
2202
    } else {
2203
      drupal_set_title(t('Registration not found'), PASS_THROUGH);
2204
      drupal_set_message("A registration with the identifier  " . $registration_identifier . " does not exist", "warning");
2205
    }
2206
  }
2207

    
2208
  $render_array = array(
2209
    '#prefix' => '<div id="registration">',
2210
    'registration' => $render_array,
2211
    '#suffix' => '</div>',
2212
  );
2213

    
2214
  RenderHints::popFromRenderStack();
2215
  RenderHints::clearFootnoteListKey();
2216

    
2217
  return $render_array ;
2218
}
2219

    
2220

    
2221
/**
2222
 * Creates a page with the advance search form.
2223
 *
2224
 * NOTE: The advance search form allows searching for taxa.
2225
 */
2226
function cdm_dataportal_view_search_advanced() {
2227
  drupal_set_title(t('Advanced search'), PASS_THROUGH);
2228
  return drupal_get_form('cdm_dataportal_search_taxon_form_advanced');
2229
}
2230

    
2231
/**
2232
 * Creates a page with the blast search form.
2233
 *
2234
 * NOTE: The advance search form allows searching for specimen in blast DB.
2235
 */
2236
function cdm_dataportal_view_search_blast() {
2237
    drupal_set_title(t('Blast search'), PASS_THROUGH);
2238
    return drupal_get_form('cdm_dataportal_search_blast_form');
2239
}
2240

    
2241
/**
2242
 * Creates a page with the search form for searching by taxon descriptions.
2243
 */
2244
function cdm_dataportal_view_search_taxon_by_description() {
2245
  drupal_set_title(t('Search by factual data'), PASS_THROUGH);
2246
  return drupal_get_form('cdm_dataportal_search_taxon_by_description_form');
2247
}
2248

    
2249
/**
2250
 * Executes the search and generates the result list of taxa.
2251
 */
2252
function cdm_dataportal_view_search_results_taxon() {
2253

    
2254
  $taxonPager = cdm_dataportal_search_taxon_execute();
2255

    
2256
  $showThumbnails = do_showThumbnails();
2257

    
2258
  $setSessionUri = url('cdm_api/setvalue/session', array(
2259
      'query' => array('var' => '[pageoption][searchtaxa][showThumbnails]', 'val' => ''),
2260
  ));
2261

    
2262
  drupal_add_js('jQuery(document).ready(function() {
2263

    
2264
      // init
2265
      if(' . $showThumbnails . ' == 1){
2266
          jQuery(\'.media_gallery\').show(20);
2267
      } else {
2268
          jQuery(\'.media_gallery\').hide(20);
2269
      }
2270

    
2271
      // add change handler
2272
      jQuery(\'#showThumbnails input.showThumbnails\').change(
2273
      function(event){
2274
        var state = 0;
2275
        if(jQuery(this).is(\':checked\')){
2276
          jQuery(\'.media_gallery\').show(20);
2277
          state = 1;
2278
        } else {
2279
          jQuery(\'.media_gallery\').hide(20);
2280
        }
2281
        // store state in session variable
2282
        var uri = \'' . $setSessionUri . '\' + state;
2283
        jQuery.get(uri);
2284
      });
2285
  });',
2286
  array('type' => "inline", 'scope' => JS_DEFAULT));
2287

    
2288
  drupal_set_title(t('Search results'), PASS_THROUGH);
2289

    
2290
  return theme('cdm_search_taxa_results', array(
2291
    'pager' => $taxonPager,
2292
    'path' => 'cdm_dataportal/search/results/taxon',
2293
    ));
2294
}
2295

    
2296
/**
2297
 * Executes the blast search and generates the result list of specimen.
2298
 */
2299
function cdm_dataportal_view_search_results_specimen() {
2300

    
2301
    $specimenPager = cdm_dataportal_search_blast_execute();
2302

    
2303
    return theme('cdm_search_specimen_results', array(
2304
        'pager' => $specimenPager,
2305
        'path' => 'cdm_dataportal/search/results/specimen',
2306
    ));
2307
}
2308

    
2309

    
2310
/**
2311
 * Executes the search for registrations and generates the result list..
2312
 */
2313
function cdm_dataportal_view_search_registrations_results($mode = 'filter') {
2314

    
2315
  switch($mode ){
2316
    case 'taxongraph':
2317
      $block = block_load('cdm_dataportal', 'registrations_search_taxongraph');
2318
      $registration_pager = cdm_dataportal_search_registrations_taxongraph_execute();
2319
      break;
2320
    case 'filter':
2321
    default:
2322
      $block = block_load('cdm_dataportal', 'registrations_search_filter');
2323
      $registration_pager = cdm_dataportal_search_registrations_filter_execute();
2324
  }
2325
  $block->title = null;
2326

    
2327
  drupal_set_title(t('Search registrations'), PASS_THROUGH);
2328

    
2329
  $render_array = _block_get_renderable_array(_block_render_blocks(array($block)));
2330
  $registrations_pager_array = compose_search_results($registration_pager, new RegistrationDTOComposeHandler());
2331
  $render_array = array_merge($render_array, $registrations_pager_array);
2332

    
2333
  return $render_array;
2334
}
2335

    
2336
/**
2337
 * Executes the search for registrations and generates the result list..
2338
 */
2339
function cdm_dataportal_view_search_agent() {
2340

    
2341
  $render_array = [];
2342
  $title = isset($_REQUEST['class']) && $_REQUEST['class'] ? $_REQUEST['class'] : 'Persons & Teams';
2343
  drupal_set_title(t($title), PASS_THROUGH);
2344
  // TODO $block = block_load('cdm_dataportal', 'search_agent_filter');
2345
  // $block->title = null;
2346
  // $render_array = _block_get_renderable_array(_block_render_blocks(array($block)));
2347
  $pager = cdm_dataportal_search_agent_execute();
2348
  $pager_render_array = compose_search_results($pager, new AgentComposeHandler());
2349
  $render_array = array_merge($render_array, $pager_render_array);
2350
  return $render_array;
2351
}
2352

    
2353

    
2354
/**
2355
 * Provides the standard image which indicated a loading process
2356
 *
2357
 * @return string
2358
 *  The img html tag
2359
 */
2360
function loading_image_html() {
2361
  return '<img class="loading" src="' . base_path() . drupal_get_path('module', 'cdm_dataportal')
2362
    . '/images/loading_circle_grey_16.gif" style="display:none;">';
2363
}
2364

    
2365
/**
2366
 * Returns the state of the the showThumbnails flag set in the
2367
 * users session ($_SESSION['pageoption']['searchtaxa']['showThumbnails']).
2368
 *
2369
 * @return boolean
2370
 *    returns 1 if the flag is set
2371
 */
2372
function do_showThumbnails() {
2373
  static $showThumbnails = null;
2374

    
2375
  if($showThumbnails == null) {
2376
    $showThumbnails = 0;
2377
    if (!isset($_SESSION['pageoption']['searchtaxa']['showThumbnails'])) {
2378
      $showThumbnails = 0;
2379
      $search_gallery_settings = variable_get(CDM_DATAPORTAL_SEARCH_GALLERY_NAME, null);
2380
      $showThumbnails = is_array($search_gallery_settings)
2381
        && isset($search_gallery_settings['cdm_dataportal_show_taxon_thumbnails'])
2382
        && (
2383
            $search_gallery_settings['cdm_dataportal_show_taxon_thumbnails'] +
2384
            $search_gallery_settings['cdm_dataportal_show_synonym_thumbnails'] +
2385
            $search_gallery_settings['cdm_dataportal_show_thumbnail_captions'] > 0
2386
            )
2387
         ? 1 : 0;
2388

    
2389
       drupal_array_set_nested_value($_SESSION, array('pageoption', 'searchtaxa', 'showThumbnails'), $showThumbnails);
2390
    }
2391
    $showThumbnails = $_SESSION['pageoption']['searchtaxa']['showThumbnails'];
2392
    if (!is_numeric($showThumbnails)) {
2393
      $showThumbnails = 1;
2394
    }
2395
  }
2396

    
2397
  return $showThumbnails;
2398
}
2399

    
2400

    
2401

    
2402
/* ====================== other functions ====================== */
2403
/**
2404
 * Creates a URL to the taxon page specified by the $uuid parameter.
2405
 *
2406
 * The URL will be prepended with a path element to a specific taxon page tab.
2407
 *
2408
 * This tab is either taken from the CDM_DATAPORTAL_DEFAULT_TAXON_TAB which can
2409
 * be set globally in the administrative settings or individually in the user
2410
 * profile. If the CDM_DATAPORTAL_DEFAULT_TAXON_TAB value is set to LAST_VISITED_TAB
2411
 * the last portal will stay on this last tab.
2412
 *
2413
 * A third option is offerered by the $page_tab parameter which allows overwriting this
2414
 * internal mechanism by a specific value.
2415
 *
2416
 * @param string $uuid
2417
 *   The UUID of the taxon.
2418
 * @param string $page_tab
2419
 *   Overwriting the preset mechanism by defining specific value for the
2420
 *   taxon page tab.
2421
 * @return string
2422
 *   The created URL.
2423
 */
2424
function path_to_taxon($uuid, $page_tab = FALSE) {
2425

    
2426
  $tab = get_default_taxon_tab();
2427
  $values = unserialize(CDM_DATAPORTAL_DEFAULT_TAXON_TAB);
2428

    
2429
  if (!$uuid) {
2430
    return FALSE;
2431
  }
2432

    
2433
  if ($page_tab) {
2434
    $url = 'cdm_dataportal/taxon/' . $uuid . '/' . $page_tab;
2435
  }
2436
  elseif (!$tab || strtolower($tab) == 'general') {
2437
    $url = 'cdm_dataportal/taxon/' . $uuid;
2438
  }
2439
  elseif (get_last_taxon_page_tab() &&   $tab == $values[CDM_DATAPORTAL_LAST_VISITED_TAB_ARRAY_INDEX]) {
2440
    $url = 'cdm_dataportal/taxon/' . $uuid . '/' . get_last_taxon_page_tab();
2441
  }
2442
  else {
2443
    $url = 'cdm_dataportal/taxon/' . $uuid . '/' . strtolower($tab);
2444
  }
2445
  return $url;
2446
}
2447

    
2448
function path_to_description($uuid, $descriptive_dataset_uuid = NULL) {
2449

    
2450
    if (!$uuid) {
2451
        return FALSE;
2452
    }
2453
    else {
2454
      return 'cdm_dataportal/description/' . $uuid
2455
        . (is_uuid($descriptive_dataset_uuid) ? '/' . $descriptive_dataset_uuid : '');
2456
    }
2457
}
2458

    
2459
function path_to_specimen($uuid) {
2460

    
2461
    if (!$uuid) {
2462
        return FALSE;
2463
    }
2464
    else {
2465
        return 'cdm_dataportal/occurrence/' . $uuid;
2466
    }
2467
}
2468

    
2469
function path_to_specimen_by_accession_number($accession_number) {
2470

    
2471
    if (!$accession_number) {
2472
        return FALSE;
2473
    }
2474
    else {
2475
        return 'cdm_dataportal/specimen/accession_number/' . $accession_number;
2476
    }
2477
}
2478

    
2479
function path_to_named_area($uuid) {
2480

    
2481
  if (!$uuid) {
2482
    return FALSE;
2483
  }
2484
  else {
2485
    return 'cdm_dataportal/named_area/' . $uuid;
2486
  }
2487
}
2488

    
2489
/**
2490
 * @param $uuid
2491
 *
2492
 * @return string
2493
 */
2494
function path_to_collection($uuid) {
2495
  if (!$uuid) {
2496
    return '';
2497
  }
2498
  else {
2499
    return 'cdm_dataportal/collection/' . $uuid;
2500
  }
2501
}
2502

    
2503
/**
2504
 * Creates a URL to show a synonmy in the according taxon page.
2505
 *
2506
 * The URL will point to the synonymy tab of the taxon page of the accepted taxon given as parameter $acceptedUuid.
2507
 * The resulting URI will include query parameters to highlight the synonym, and to optionally display
2508
 * the accepted taxons name in aform like "Foo bar is accepted taxon for Ree doo". The URI will also
2509
 * include the sysnonym uuid as fragment in order to let the browser scroll to the according location
2510
 * in the page
2511
 *
2512
 * @param string $synonymUuid
2513
 *    The uuid of the synonym
2514
 * @param string $acceptedUuid
2515
 *    The uuid of the according accepted taxon
2516
 * @return string
2517
 *    The URL to show a synonmy in the according taxon page
2518
 */
2519
function uri_to_synonym($synonymUuid, $acceptedUuid) {
2520
  $acceptedPath = path_to_taxon($acceptedUuid, "synonymy");
2521
  return url($acceptedPath, array(
2522
      'query' => array(
2523
        // highlite the synony in the synonymy
2524
        'highlite' => $synonymUuid,
2525
        // the taxon page is refered from a synonym and the synonym can optionally be named in the page title
2526
        // see theme_taxon_page_title()
2527
        'acceptedFor' => $synonymUuid
2528
      ),
2529
      'fragment' => $synonymUuid
2530
  ));
2531

    
2532
}
2533

    
2534
/**
2535
 * Composes the drupal path to the key identified by the uuid.
2536
 *
2537
 * @param string $keyType
2538
 *    the key typer corresponds to the specific class of the CDM
2539
 *    IdentificationKey. Possible values are
2540
 *      -PolytomousKey
2541
 *      -MultimediaKey
2542
 *      - ...
2543
 * @param string $keyUuid
2544
 *   The UUID of the key
2545
 */
2546
function path_to_key($keyType, $keyUuid) {
2547
  if (!$keyUuid || !$keyType) {
2548
    return FALSE;
2549
  }
2550
  $keyType[0] = strtolower($keyType[0]);
2551
  return "cdm_dataportal/" . $keyType . "/$keyUuid";
2552
}
2553

    
2554
/**
2555
 * Composes the drupal path to the reference identified by the uuid.
2556
 *
2557
 * @param $uuid string String representation of the registration entity uuid.
2558
 *
2559
 * @return string
2560
 *  The drupal path
2561
 *
2562
 */
2563
function path_to_reference($uuid) {
2564
  if (!$uuid) {
2565
    return FALSE;
2566
  }
2567
  return 'cdm_dataportal/reference/' . $uuid;
2568
}
2569

    
2570
/**
2571
 * @param string $registration_identifier
2572
 *  The persistent identifier of the registration entity (Registration.identifier).
2573
 *
2574
 * @return string
2575
 *  the markup for a HTML link
2576
 */
2577
function render_link_to_registration($registration_identifier) {
2578

    
2579
  if(variable_get(CDM_REGISTRATION_PRESISTENT_IDENTIFIER_AS_LINK)){
2580
    $path = $registration_identifier;
2581
    $query = [];
2582
  } else {
2583
    $path = 'cdm_dataportal/registration';
2584
    $query = ['identifier' => $registration_identifier];
2585
  }
2586
  return l($registration_identifier, $path, array('attributes' => array('class' => array('identifier')), 'query' => $query));
2587
}
2588

    
2589

    
2590
/**
2591
 * Creates the path to a cdm_dataportal taxon name page.
2592
 *
2593
 * @param string $taxon_name_uuid
2594
 *   The uuid as string of the CDM TaxonName to show a name page for
2595
 * @param string $taxon_to_hide_uuid
2596
 *   The uuid as string of a taxon which should not be displayed in the taxon list
2597
 * @param string $highlited_synonym_uuid
2598
 *   Optional parameter which takes another taxon uuid, if given the
2599
 *   target taxon pages will show the synonymy tab where the taxon
2600
 *   referenced by the $highlite_synonym_uuid will be highlighted
2601
 *   in case it is found on this page.
2602
 * @param $redirect_to_taxon
2603
 *   If true, the name page will redirect to the related taxon if there is a single one
2604
 *   for this name only.
2605
 *
2606
 * @return string
2607
 *  URI path element as string
2608
 */
2609
function path_to_name($name_uuid, $taxon_to_hide_uuid = NULL, $highlited_synonym_uuid  = NULL, $redirect_to_taxon = false) {
2610
  $res = FALSE;
2611
  if ($name_uuid) {
2612
    $res = 'cdm_dataportal/name/' . $name_uuid .
2613
    '/' . (is_uuid($taxon_to_hide_uuid) ? $taxon_to_hide_uuid : "null") .
2614
    '/' . (is_uuid($highlited_synonym_uuid) ? $highlited_synonym_uuid : "null") .
2615
    '/' . ($redirect_to_taxon || variable_get(CDM_NAME_PAGE_AUTOREDIRECT, 0) ? "redirect_to_taxon" : "");
2616
  }
2617

    
2618
  return $res;
2619
}
2620

    
2621
/**
2622
 * Composes the drupal path to the media entity identified by the uuid.
2623
 *
2624
 * @param string $uuid
2625
 *  The persistent identifier of the entity entity
2626
 * @return string
2627
 *  The drupal path
2628
 */
2629
function path_to_media($uuid, $representaion_uuid = FALSE, $partId = FALSE) {
2630
  if (!$uuid) {
2631
    return FALSE;
2632
  }
2633
  $out = 'cdm_dataportal/media/' . $uuid;
2634
  if ($representaion_uuid) {
2635
    $out .= '/' . $representaion_uuid;
2636
    if (is_numeric($partId)) {
2637
      $out .= '/' . $partId;
2638
    }
2639
  }
2640
  return $out;
2641
}
2642

    
2643
/**
2644
 * Compares thisRank with thatRank.
2645
 *
2646
 * Returns a negative integer, zero, or a positive integer
2647
 * as the of thisRank is higher than, equal to, or lower than thatRank.
2648
 * e.g:
2649
 * <ul>
2650
 * <li>rank_compare({species_uuid}, {genus_uuid}) = -1</li>
2651
 * <li>rank_compare({genus_uuid}, {genus_uuid}) = 0</li>
2652
 * <li>rank_compare({genus_uuid}, {tribus_uuid}) = 1</li>
2653
 * </ul>
2654
 * <p>
2655
 * This compare logic of the underlying webservice is the
2656
 * <b>inverse logic</b> of the the one implemented in
2657
 * java.lang.Comparable#compareTo(java.lang.Object)
2658
 *
2659
 * @param $thisRankUuid
2660
 * @param $thatRankUuid
2661
 *
2662
 * @return int
2663
 *   A negative integer, zero, or a positive integer
2664
 *   as the thisRank is lower than, equal to, or higher than thatRank.
2665
 */
2666
function rank_compare($thisRankUuid, $thatRankUuid) {
2667
  $result = cdm_ws_get(CDM_WS_TERM_COMPARE, array($thisRankUuid, $thatRankUuid));
2668
  return $result->Integer;
2669
}
2670

    
2671
/**
2672
 * Creates a short version of a taxonname.
2673
 *
2674
 * The short name is created by using the taggedTitle field of
2675
 * TaxonNodeDTO instances.
2676
 * If the taggedTitle if empty the fullname will be returned.
2677
 *
2678
 * @param object $taxonNodeDTO
2679
 *   A TaxonNodeDTO object
2680
 *
2681
 * @return string
2682
 */
2683
function cdm_dataportal_shortname_of($taxonNodeDTO) {
2684

    
2685
  $nameStr = '';
2686

    
2687
  normalize_tagged_text($taxonNodeDTO->taggedTitle);
2688

    
2689
  // Get all tagged text tokens of the scientific name.
2690
  foreach ($taxonNodeDTO->taggedTitle as $tagtxt) {
2691
    if ($tagtxt->type == 'name' || $tagtxt->type == 'rank') {
2692
      $nameStr .= ($nameStr ? ' ' : '') . $tagtxt->text;
2693
    }
2694
  }
2695
  $nameStr = trim($nameStr);
2696

    
2697
  if ($nameStr) {
2698
    if(isset($taxonNodeDTO->status->symbol)){
2699
      $nameStr = $taxonNodeDTO->status->symbol . ' ' . $nameStr;
2700
    }
2701
    // Do not return short names for these.
2702
    if ($taxonNodeDTO->unplaced || $taxonNodeDTO->excluded) {
2703
      return $nameStr;
2704
    }
2705

    
2706
    /*
2707
    1st capture group (^[a-zA-Z]): First letter of uninomial.
2708
    Second capture group ([\p{L}]+): remaining letters of uninomial ([\p{L} = an UTF-8 letter).
2709
    Third capture group (\s+[^(\x2E]+\s+.+$|\s+[a-zA-Z]+$): letters of name,
2710
    but only matching if no '(' or '.' in second word of name,        ( \x2E = '.')
2711
    OR only one specific epithet \s+[\p{L}\x22\x2D\xD7]+$             (\x22= '"', \x2D='-', \xD7='×' )
2712
    */
2713
    $pattern = '/(^[a-zA-Z])([\p{L}]+)(\s+[^(\x2E]+\s+.+$|\s+[\p{L}\x22\x2D\xD7]+$)/u';
2714
    if (preg_match($pattern, $nameStr, $matches, PREG_OFFSET_CAPTURE)) {
2715
      return $matches[1][0] . "." . $matches[3][0];
2716
    }
2717
    else {
2718
      return $nameStr;
2719
    }
2720
  }
2721
  else {
2722
    return $taxonNodeDTO->titleCache;
2723
  }
2724
}
2725

    
2726
/**
2727
 * Check if a taxon is accepted by the current taxonomic tree.
2728
 *
2729
 * @param mixed $taxon
2730
 *   The Taxon obkect to check.
2731
 *
2732
 * @return bool
2733
 *   Returns TRUE if $taxon is accepted, FALSE otherwise.
2734
 */
2735
function _cdm_dataportal_acceptedByCurrentView($taxon) {
2736

    
2737
  $default_classification_uuid = get_current_classification_uuid();
2738

    
2739
  if (isset($taxon->taxonNodes)) {
2740
    $taxon_nodes = $taxon->taxonNodes;
2741
  }
2742
  else {
2743
    $taxon_nodes = cdm_ws_get(CDM_WS_PORTAL_TAXON_TAXONNODES, $taxon->uuid);
2744
  }
2745

    
2746
  if ($taxon->class == "Taxon" && isset($taxon_nodes)) {
2747
    foreach ($taxon_nodes as $node) {
2748
      if($node->class == 'TaxonNodeDto' && isset($node->classificationUUID)){
2749
        // case of TaxonNodeDto
2750
        return $node->classificationUUID == $default_classification_uuid;
2751
      } else if($node->class == 'TaxonNode' && isset($node->classification->uuid)) {
2752
         return $node->classification->uuid == $default_classification_uuid;
2753
      }
2754
    }
2755
  }
2756
  return FALSE;
2757
}
2758

    
2759
/**
2760
 * Checks is the source has one of the given types.
2761
 *
2762
 * @param object $source
2763
 *   The original source entity
2764
 * @param array $types
2765
 *   An array of element of the OriginalSourceType enumeration
2766
 *   If not set the default will be used which is:
2767
 *    - Lineage
2768
 *    - PrimaryMediaSource
2769
 *    - PrimaryTaxonomicSource
2770
 *    - Unknown
2771
 *    - Other
2772
 * @return boolean
2773
 */
2774
  function _is_original_source_type($source, $types = null) {
2775
    // this is the default
2776
    // maybe this should also be put into the settings
2777
    static $default = array(
2778
      OriginalSourceType::Lineage,
2779
      OriginalSourceType::PrimaryMediaSource,
2780
      OriginalSourceType::PrimaryTaxonomicSource,
2781
      OriginalSourceType::Unknown,
2782
      OriginalSourceType::Other,
2783
      OriginalSourceType::Aggregation
2784
    );
2785

    
2786
    if(!$types){
2787
      $types = $default;
2788
    }
2789
    return isset($source->type) && in_array($source->type, $types);
2790
  }
2791

    
2792
/**
2793
 * Collects all the media from a list of description elements.
2794
 *
2795
 * @param array $descriptionElements
2796
 *   The description elements from which to collect the media.
2797
 *
2798
 * @return array
2799
 *   The output with all the collected media.
2800
 */
2801
function cdm_dataportal_media_from_descriptionElements($descriptionElements) {
2802

    
2803
  $outArrayOfMedia = array();
2804

    
2805
  // Avoiding a warning box in Drupal for Flora Malesiana.
2806
  if (isset($descriptionElements) && is_array($descriptionElements)) {
2807
    foreach ($descriptionElements as $descriptionElement) {
2808
      if (isset($descriptionElement->media) && is_array($descriptionElement->media)) {
2809
        foreach ($descriptionElement->media as $media) {
2810
          if (is_object($media)) {
2811
            $outArrayOfMedia[] = $media;
2812
          }
2813
        }
2814
      }
2815
    }
2816
  }
2817
  return $outArrayOfMedia;
2818
}
2819

    
2820

    
2821

    
2822

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

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

    
2866
  if(!array_key_exists('class', $attributes)) {
2867
    $attributes['class'] = ["dynabox"];
2868
  } else {
2869
    $attributes['class'] = array_merge($attributes['class'], ["dynabox"]);
2870
  }
2871
  $attributes['id'][] = 'dynabox-' . $dynabox_id;
2872
  $dynabox_attributes = drupal_attributes($attributes);
2873

    
2874

    
2875
  _add_js_domEvent(); // requires domEvent.js
2876
  drupal_add_js(drupal_get_path('module', 'cdm_dataportal') . '/js/cdm_dynabox.js');
2877
  drupal_add_js("
2878
  jQuery(document).ready(
2879
      function() {
2880
        dynabox('". $dynabox_id ."',
2881
          {
2882
            open_callback: " . $open_callback .",
2883
            close_callback: " . $close_callback .
2884
            ($content_element_selector ? ",\n content_container_selector: '" . $content_element_selector . "'" : "") . "
2885
          }
2886
        );
2887
      }
2888
   );",
2889
   array(
2890
    'type'=>'inline',
2891
    'scope'=>'footer'
2892
    )
2893
  );
2894

    
2895

    
2896
  $cdm_proxy_url = url('cdm_api/proxy/' . urlencode($content_url) . "/$theme");
2897
  $out .= '<!-- dynabox for ' . $content_url . ' -->';
2898
  $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>';
2899
  $out .= '  <' . $enclosingtags[1] . ' id="dynabox-' . $dynabox_id . '-content">';
2900
  $out .= '    <' . $enclosingtags[0] . ' class="dynabox-content-inner">' . loading_image_html() . '</' . $enclosingtags[0] . '>';
2901
  $out .= '    </' . $enclosingtags[1] . '>';
2902
  $out .= '  </' . $enclosingtags[0] . '>';
2903
  $out .= '<!-- dynabox end -->';
2904
  return $out;
2905
}
2906

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

    
2927
  if (isset($featureNode->descriptionElements) && is_array($featureNode->descriptionElements) && count($featureNode->descriptionElements) > 0) {
2928
    if(!isset($featureNode->descriptionElements['#type'])){ // #type is used to identify e.g. DTO elements: '#type' => 'DTO'
2929
      foreach ($featureNode->descriptionElements as $descriptionElement) {
2930
        if ($descriptionElement->class != "TextData" || isset($descriptionElement->multilanguageText_L10n->text)
2931
          && $descriptionElement->multilanguageText_L10n->text != ''
2932
          || isset($descriptionElement->sources[0])
2933
          || isset($descriptionElement->media[0]) ) {
2934
          return TRUE;
2935
        }
2936
      }
2937
    }
2938
  }
2939
  else if (isset($featureNode->childNodes) && is_array($featureNode->childNodes)) {
2940
    foreach ($featureNode->childNodes as $child) {
2941
      if (has_feature_node_description_elements($child)) {
2942
        return TRUE;
2943
      }
2944
    }
2945
  }
2946
  return FALSE;
2947
}
2948

    
2949
/**
2950
 * Checks if the current page is a valid taxon portal page and responds with HTTP status 404 (not found) otherwise
2951
 *
2952
 * @param $chapter
2953
 *   The taxon page chapter or part
2954
 */
2955
function cdm_check_valid_taxon_page($chapter){
2956
  static $taxon_tabs = null;
2957

    
2958
  cdm_check_valid_portal_page();
2959

    
2960
  if($taxon_tabs == null){
2961
    $taxon_tabs = array('all', 'description');
2962
    foreach(get_taxon_tabs_list() as $tab){
2963
      $taxon_tabs[] = strtolower($tab);
2964
    }
2965
  }
2966

    
2967
  if(!in_array($chapter, $taxon_tabs)){
2968
    // oops this is not a valid chapter name
2969
    http_response_code(404); // 404 = Not Found
2970
  }
2971

    
2972
}
2973

    
2974
function check_js_devel_mode_disabled() {
2975
  if(variable_get('cdm_js_devel_mode', FALSE)) {
2976
    drupal_set_message(t('The !url1 is enabled.
2977
        WARNING: this is a performance penalty and must be turned off on production websites.', array(
2978
      '!url1' => l('java-script development mode', 'admin/config/cdm_dataportal/settings', array('fragment' => 'edit-cdm-js-devel-mode'))
2979
    )),
2980
      'warning'
2981
    );
2982
  }
2983
}
2984

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

    
3005
/**
3006
 * Generates the diff of the texts and presents it in a HTML diff viewer.
3007
 *
3008
 * @param $text_a
3009
 * @param $text_b
3010
 * @return string
3011
 */
3012
function diff_viewer($text_a, $text_b) {
3013

    
3014
  static $diff_viewer_count = 0;
3015

    
3016
  $element_id = 'part_definitions_diff_' . $diff_viewer_count++;
3017

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

    
3037
  $diff = Diff::compare($text_a,
3038
    $text_b);
3039
  $diff_viewer_markup = '<div id="' . $element_id . '"><h3>View Diff</h3><div>'
3040
    . Diff::toTable($diff, '', '')
3041
    . '</div></div>';
3042
  return $diff_viewer_markup;
3043
}
3044

    
3045
/**
3046
 * ====== EXPERIMENTAL only used by Euro+Med ===============
3047
 */
3048

    
3049

    
3050
/**
3051
 * See
3052
 *  - https://dev.e-taxonomy.eu/redmine/issues/9233
3053
 *  - https://www.drupal.org/project/feedback_simple
3054
 *  - https://www.drupal.org/node/1299158
3055
 * Implements hook_preprocess_feedback_simple().
3056
 *
3057
 * TODO: move into separate module
3058
 */
3059
function cdm_dataportal_preprocess_feedback_simple(&$variables) {
3060
  // Add modal_forms classes.
3061
  $variables['class'][] = 'ctools-use-modal';
3062
  // Uncomment either small, medium or large.
3063
  $variables['class'][] = 'ctools-modal-modal-popup-small';
3064
  // $variables['class'][] = 'ctools-modal-modal-popup-medium';
3065
  // $variables['class'][] = 'ctools-modal-modal-popup-large';
3066
}
3067

    
3068

    
(10-10/19)