/**
  * Outputs a map with an overlay of regions, showing a count for each. Default is to count records, but can
  * be configured to count taxa.
  *
  * @param array $auth Authorisation tokens.
  * @param array $args Form arguments (the settings on the form edit tab).
  * @param string $tabalias The alias of the tab this is being loaded onto.
  * @param array $options The options passed to this control using @option=value settings in the form structure.
  * Options supported are those which can be passed to the report_helper::report_map method. In addition
  * set @output=species to configure the report to show a species counts map.   
  * @param string $path The page reload path, in case it is required for the building of links.
  * @return string HTML to insert into the page for the location map. JavaScript is added to the variables in helper_base.
  *
  * @link http://www.biodiverseit.co.uk/indicia/dev/docs/classes/report_helper.html#method_report_map API docs for report_helper::report_map
  */
 public static function count_by_location_map($auth, $args, $tabalias, $options, $path)
 {
     iform_load_helpers(array('map_helper', 'report_helper'));
     require_once iform_client_helpers_path() . 'prebuilt_forms/includes/map.php';
     $mapOptions = iform_map_get_map_options($args, $auth['read']);
     $olOptions = iform_map_get_ol_options($args);
     $mapOptions['clickForSpatialRef'] = false;
     $r = map_helper::map_panel($mapOptions, $olOptions);
     if (!empty($options['output']) && $options['output'] === 'species') {
         $type = 'species';
     } else {
         $type = 'occurrence';
     }
     $reportOptions = array_merge(iform_report_get_report_options($args, $auth['read']), array('dataSource' => "library/locations/{$type}_counts_mappable_for_event", 'featureDoubleOutlineColour' => '#f7f7f7', 'rowId' => 'id'), $options);
     $r .= report_helper::report_map($reportOptions);
     return $r;
 }
 /**
  * Outputs a map with an overlay of regions, showing a count for each. Default is to count records, but can
  * be configured to count taxa.
  *
  * @param array $auth Authorisation tokens.
  * @param array $args Form arguments (the settings on the form edit tab).
  * @param string $tabalias The alias of the tab this is being loaded onto.
  * @param array $options The options passed to this control using @option=value settings in the form structure.
  * Options supported are those which can be passed to the report_helper::report_map method. In addition
  * set @output=species to configure the report to show a species counts map and set @title=... to 
  * include a heading in the output.   
  * @param string $path The page reload path, in case it is required for the building of links.
  * @return string HTML to insert into the page for the location map. JavaScript is added to the variables in helper_base.
  *
  * @link http://www.biodiverseit.co.uk/indicia/dev/docs/classes/report_helper.html#method_report_map API docs for report_helper::report_map
  */
 public static function count_by_location_map($auth, $args, $tabalias, $options, $path)
 {
     iform_load_helpers(array('map_helper', 'report_helper'));
     require_once iform_client_helpers_path() . 'prebuilt_forms/includes/map.php';
     $mapOptions = iform_map_get_map_options($args, $auth['read']);
     $olOptions = iform_map_get_ol_options($args);
     $mapOptions['clickForSpatialRef'] = false;
     if ($args['interface'] !== 'one_page') {
         $mapOptions['tabDiv'] = $tabalias;
     }
     $r = self::output_title($options);
     $r .= map_helper::map_panel($mapOptions, $olOptions);
     if (!empty($options['output']) && $options['output'] === 'species') {
         $type = 'species';
     } else {
         $type = 'occurrence';
     }
     $subtype = empty($options['linked']) || $options['linked'] === false ? '' : '_linked';
     $reportOptions = array_merge(iform_report_get_report_options($args, $auth['read']), array('dataSource' => "library/locations/filterable_{$type}_counts_mappable{$subtype}", 'featureDoubleOutlineColour' => '#f7f7f7', 'rowId' => 'id', 'caching' => true, 'cachePerUser' => false), $options);
     $r .= report_helper::report_map($reportOptions);
     return $r;
 }
 /**
  * Performs the download.
  * @global array $indicia_templates
  * @param type $args
  * @param type $node
  */
 private static function do_data_services_download($args, $node)
 {
     iform_load_helpers(array('report_helper'));
     $format = $_POST['format'];
     $isCustom = preg_match('/^custom-(\\d+)$/', $_POST['format'], $matches);
     if ($isCustom) {
         $customFormats = json_decode($args['custom_formats'], true);
         $customFormat = $customFormats[$matches[1]];
         $report = $customFormat['report'];
         // strip unnecessary .xml from end of report name if provided
         $report = preg_replace('/\\.xml$/', '', $report);
         $format = $customFormat['format'];
         $additionalParamText = $customFormat['params'];
     } else {
         $report = $args["report_{$format}"];
         $additionalParamText = $args["report_params_{$format}"];
     }
     $params = self::build_params($args);
     $params = array_merge($params, get_options_array_with_user_data($additionalParamText));
     $conn = iform_get_connection_details($node);
     global $indicia_templates;
     // let's just get the URL, not the whole anchor element
     $indicia_templates['report_download_link'] = '{link}';
     $limit = $args['limit'] == 0 ? '' : $args['limit'];
     // unlimited or limited
     $sharing = substr($_POST['download-type'], 0, 1);
     $url = report_helper::report_download_link(array('readAuth' => data_entry_helper::$js_read_tokens, 'dataSource' => $report, 'extraParams' => $params, 'format' => $format, 'sharing' => self::expand_sharing_mode($sharing), 'itemsPerPage' => $limit));
     if ($args['reverse_proxy'] == true) {
         // Rewrite the url to pass through proxy.php
         $relative_proxy_path = iform_client_helpers_path() . 'proxy.php?url=' . report_helper::$base_url;
         global $base_url;
         $proxy_path = $base_url . substr($relative_proxy_path, 1);
         // remove report_helper::$base_url from $url
         $url = substr($url, strlen(report_helper::$base_url));
         // add $proxy_path to $url
         $url = $proxy_path . $url;
     }
     header("Location: {$url}");
 }
 public static function call_page_from_map($auth, $args, $tabalias, $options, $path)
 {
     data_entry_helper::$javascript .= "indiciaData.linkToPage='" . url($options['link']) . (variable_get('clean_url', 0) ? '?' : '&') . $options['linkPageParam'] . '=' . "';";
     drupal_add_js(iform_client_helpers_path() . 'prebuilt_forms/extensions/shorewatch_extensions.js');
 }
 /**
  * Return the generated form output.
  * @param array $args List of parameter values passed through to the form depending on how the form has been configured.
  * This array always contains a value for language.
  * @param object $node The Drupal node object.
  * @param array $response When this form is reloading after saving a submission, contains the response from the service call.
  * Note this does not apply when redirecting (in this case the details of the saved object are in the $_GET data).
  * @return Form HTML.
  * @todo: Implement this method 
  */
 public static function get_form($args, $node, $response = null)
 {
     global $user;
     // use the js from the main form, until there is a deviation.
     drupal_add_js(iform_client_helpers_path() . "prebuilt_forms/js/sectioned_transects_edit_transect.js");
     drupal_add_css(iform_client_helpers_path() . "prebuilt_forms/css/sectioned_transects_edit_transect.css");
     $checks = self::check_prerequisites();
     $args = self::getArgDefaults($args);
     if ($checks !== true) {
         return $checks;
     }
     iform_load_helpers(array('map_helper'));
     data_entry_helper::add_resource('jquery_form');
     self::$ajaxFormUrl = iform_ajaxproxy_url($node, 'location');
     self::$ajaxFormSampleUrl = iform_ajaxproxy_url($node, 'sample');
     $auth = data_entry_helper::get_read_write_auth($args['website_id'], $args['password']);
     $settings = array('mainLocationType' => helper_base::get_termlist_terms($auth, 'indicia:location_types', array(empty($args['main_type_term_1']) ? 'Transect' : $args['main_type_term_1'])), 'sectionLocationType' => helper_base::get_termlist_terms($auth, 'indicia:location_types', array(empty($args['section_type_term']) ? 'Section' : $args['section_type_term'])), 'locationId' => isset($_GET['id']) ? $_GET['id'] : null, 'canEditBody' => true, 'canEditSections' => true, 'canAllocBranch' => $args['managerPermission'] == "" || user_access($args['managerPermission']), 'canAllocUser' => $args['managerPermission'] == "" || user_access($args['managerPermission']));
     // WARNING!!!! we are making the assumption that the attributes are defined to be the same for all the location_types.
     $settings['attributes'] = data_entry_helper::getAttributes(array('id' => $settings['locationId'], 'valuetable' => 'location_attribute_value', 'attrtable' => 'location_attribute', 'key' => 'location_id', 'fieldprefix' => 'locAttr', 'extraParams' => $auth['read'], 'survey_id' => $args['survey_id'], 'location_type_id' => $settings['mainLocationType'][0]['id'], 'multiValue' => true));
     $settings['section_attributes'] = data_entry_helper::getAttributes(array('valuetable' => 'location_attribute_value', 'attrtable' => 'location_attribute', 'key' => 'location_id', 'fieldprefix' => 'locAttr', 'extraParams' => $auth['read'], 'survey_id' => $args['survey_id'], 'location_type_id' => $settings['sectionLocationType'][0]['id'], 'multiValue' => true));
     if ($args['allow_user_assignment']) {
         if (false == ($settings['cmsUserAttr'] = extract_cms_user_attr($settings['attributes']))) {
             return 'This form is designed to be used with the CMS User ID attribute setup for locations in the survey, or the "Allow users to be assigned to transects" option unticked.';
         }
         // keep a copy of the cms user ID attribute so we can use it later.
         self::$cmsUserAttrId = $settings['cmsUserAttr']['attributeId'];
     }
     // need to check if branch allocation is active.
     if ($args['branch_assignment_permission'] != '') {
         if (false == ($settings['branchCmsUserAttr'] = self::extract_attr($settings['attributes'], "Branch CMS User ID"))) {
             return '<br />This form is designed to be used with either<br />1) the Branch CMS User ID attribute setup for locations in the survey, or<br />2) the "Permission name for Branch Manager" option left blank.<br />';
         }
         // keep a copy of the branch cms user ID attribute so we can use it later.
         self::$branchCmsUserAttrId = $settings['branchCmsUserAttr']['attributeId'];
     } else {
         self::$branchCmsUserAttrId = false;
     }
     data_entry_helper::$javascript .= "indiciaData.sections = {};\n";
     $settings['sections'] = array();
     $settings['numSectionsAttr'] = "";
     $settings['maxSectionCount'] = $args['maxSectionCount'];
     $settings['autocalcSectionLengthAttrId'] = empty($args['autocalc_section_length_attr_id']) ? 0 : $args['autocalc_section_length_attr_id'];
     $settings['defaultSectionGridRef'] = empty($args['default_section_grid_ref']) ? 'parent' : $args['default_section_grid_ref'];
     if ($settings['locationId']) {
         $fixedSectionNumber = false;
         data_entry_helper::load_existing_record($auth['read'], 'location', $settings['locationId']);
         $settings['walks'] = data_entry_helper::get_population_data(array('table' => 'sample', 'extraParams' => $auth['read'] + array('view' => 'detail', 'location_id' => $settings['locationId'], 'deleted' => 'f'), 'nocache' => true));
         // Work out permissions for this user: note that canAllocBranch setting effectively shows if a manager.
         if (!$settings['canAllocBranch']) {
             // Check whether I am a normal user and it is allocated to me, and also if I am a branch manager and it is allocated to me.
             $settings['canEditBody'] = false;
             $settings['canEditSections'] = false;
             if ($args['allow_user_assignment'] && count($settings['walks']) == 0 && isset($settings['cmsUserAttr']['default']) && !empty($settings['cmsUserAttr']['default'])) {
                 foreach ($settings['cmsUserAttr']['default'] as $value) {
                     // multi value
                     if ($value['default'] == $user->uid) {
                         // comparing string against int so no triple equals
                         $settings['canEditBody'] = true;
                         $settings['canEditSections'] = true;
                         break;
                     }
                 }
             }
             // If a Branch Manager and not a main manager, then can't edit the number of sections
             if ($args['branch_assignment_permission'] != '' && user_access($args['branch_assignment_permission']) && isset($settings['branchCmsUserAttr']['default']) && !empty($settings['branchCmsUserAttr']['default'])) {
                 foreach ($settings['branchCmsUserAttr']['default'] as $value) {
                     // now multi value
                     if ($value['default'] == $user->uid) {
                         // comparing string against int so no triple equals
                         $settings['canEditBody'] = true;
                         $settings['canAllocUser'] = true;
                         break;
                     }
                 }
             }
             // but if the location type is a fixed number type, then canEditSections is always false
             for ($i = 1; $i < 4; $i++) {
                 if (!empty($args['main_type_term_' . $i])) {
                     $type = helper_base::get_termlist_terms($auth, 'indicia:location_types', array($args['main_type_term_' . $i]));
                     if (data_entry_helper::$entity_to_load['location:location_type_id'] == $type[0]['id'] && (!isset($args['can_change_section_number_' . $i]) || !$args['can_change_section_number_' . $i])) {
                         $settings['canEditSections'] = false;
                         $fixedSectionNumber = $args['section_number_' . $i];
                     }
                 }
             }
         }
         // for an admin user the defaults apply, which will be can do everything.
         // find the number of sections attribute.
         foreach ($settings['attributes'] as $attr) {
             if ($attr['caption'] === 'No. of sections') {
                 $settings['numSectionsAttr'] = $attr['fieldname'];
                 if ($fixedSectionNumber) {
                     for ($i = 1; $i <= $fixedSectionNumber; $i++) {
                         $settings['sections']["S{$i}"] = null;
                     }
                     data_entry_helper::$javascript .= "\$('#" . str_replace(':', '\\\\:', $attr['id']) . "').val({$fixedSectionNumber}).attr('readonly','readonly').css('color','graytext');\n";
                 } else {
                     for ($i = 1; $i <= $attr['displayValue']; $i++) {
                         $settings['sections']["S{$i}"] = null;
                     }
                     $existingSectionCount = empty($attr['displayValue']) ? 1 : $attr['displayValue'];
                     data_entry_helper::$javascript .= "\$('#" . str_replace(':', '\\\\:', $attr['id']) . "').attr('min',{$existingSectionCount}).attr('max'," . $args['maxSectionCount'] . ");\n";
                     if (!$settings['canEditSections']) {
                         data_entry_helper::$javascript .= "\$('#" . str_replace(':', '\\\\:', $attr['id']) . "').attr('readonly','readonly').css('color','graytext');\n";
                     }
                 }
             }
         }
         $sections = data_entry_helper::get_population_data(array('table' => 'location', 'extraParams' => $auth['read'] + array('view' => 'detail', 'parent_id' => $settings['locationId'], 'deleted' => 'f', 'orderby' => 'id'), 'nocache' => true));
         foreach ($sections as $section) {
             $code = $section['code'];
             if (in_array($section['centroid_sref_system'], array('osgb', 'osie'))) {
                 $section['centroid_sref_system'] = strtoupper($section['centroid_sref_system']);
             }
             data_entry_helper::$javascript .= "indiciaData.sections.{$code} = {'geom':'" . $section['boundary_geom'] . "','id':'" . $section['id'] . "','sref':'" . $section['centroid_sref'] . "','system':'" . $section['centroid_sref_system'] . "'};\n";
             $settings['sections'][$code] = $section;
         }
     } else {
         // not an existing site therefore no walks. On initial save, no section data is created.
         foreach ($settings['attributes'] as $attr) {
             if ($attr['caption'] === 'No. of sections') {
                 $settings['numSectionsAttr'] = $attr['fieldname'];
                 data_entry_helper::$javascript .= "\$('#" . str_replace(':', '\\\\:', $attr['id']) . "').attr('min',1).attr('max'," . $args['maxSectionCount'] . ");\n";
             }
         }
         $settings['walks'] = array();
     }
     if ($settings['numSectionsAttr'] === '') {
         for ($i = 1; $i <= $settings['maxSectionCount']; $i++) {
             $settings['sections']["S{$i}"] = null;
         }
     }
     $r = '<div id="controls">';
     $headerOptions = array('tabs' => array('#site-details' => lang::get('Site Details')));
     if ($settings['locationId']) {
         $headerOptions['tabs']['#your-route'] = lang::get('Your Route');
         if (count($settings['section_attributes']) > 0) {
             $headerOptions['tabs']['#section-details'] = lang::get('Section Details');
         }
     }
     if (count($headerOptions['tabs'])) {
         $r .= data_entry_helper::tab_header($headerOptions);
         data_entry_helper::enable_tabs(array('divId' => 'controls', 'style' => 'Tabs', 'progressBar' => isset($args['tabProgress']) && $args['tabProgress'] == true));
     }
     $r .= self::get_site_tab($auth, $args, $settings);
     if ($settings['locationId']) {
         $r .= self::get_your_route_tab($auth, $args, $settings);
         if (count($settings['section_attributes']) > 0) {
             $r .= self::get_section_details_tab($auth, $args, $settings);
         }
     }
     $r .= '</div>';
     // controls
     data_entry_helper::enable_validation('input-form');
     if (function_exists('drupal_set_breadcrumb')) {
         $breadcrumb = array();
         $breadcrumb[] = l(lang::get('Home'), '<front>');
         $breadcrumb[] = l(lang::get('Sites'), $args['sites_list_path']);
         if ($settings['locationId']) {
             $breadcrumb[] = data_entry_helper::$entity_to_load['location:name'];
         } else {
             $breadcrumb[] = lang::get('New Site');
         }
         drupal_set_breadcrumb($breadcrumb);
     }
     // Inform JS where to post data to for AJAX form saving
     data_entry_helper::$javascript .= 'indiciaData.ajaxFormPostUrl="' . self::$ajaxFormUrl . "\";\n";
     data_entry_helper::$javascript .= 'indiciaData.ajaxFormPostSampleUrl="' . self::$ajaxFormSampleUrl . "\";\n";
     data_entry_helper::$javascript .= 'indiciaData.website_id="' . $args['website_id'] . "\";\n";
     data_entry_helper::$javascript .= "indiciaData.indiciaSvc = '" . data_entry_helper::$base_url . "';\n";
     data_entry_helper::$javascript .= "indiciaData.readAuth = {nonce: '" . $auth['read']['nonce'] . "', auth_token: '" . $auth['read']['auth_token'] . "'};\n";
     data_entry_helper::$javascript .= "indiciaData.currentSection = '';\n";
     data_entry_helper::$javascript .= "indiciaData.sectionTypeId = '" . $settings['sectionLocationType'][0]['id'] . "';\n";
     data_entry_helper::$javascript .= "indiciaData.sectionDeleteConfirm = \"" . lang::get('Are you sure you wish to delete section') . "\";\n";
     data_entry_helper::$javascript .= "indiciaData.sectionInsertConfirm = \"" . lang::get('Are you sure you wish to insert a new section after section') . "\";\n";
     data_entry_helper::$javascript .= "indiciaData.sectionChangeConfirm = \"" . lang::get('Do you wish to save the currently unsaved changes you have made to the Section Details?') . "\";\n";
     data_entry_helper::$javascript .= "indiciaData.numSectionsAttrName = \"" . $settings['numSectionsAttr'] . "\";\n";
     data_entry_helper::$javascript .= "indiciaData.maxSectionCount = \"" . $settings['maxSectionCount'] . "\";\n";
     data_entry_helper::$javascript .= "indiciaData.autocalcSectionLengthAttrId = " . $settings['autocalcSectionLengthAttrId'] . ";\n";
     data_entry_helper::$javascript .= "indiciaData.defaultSectionGridRef = '" . $settings['defaultSectionGridRef'] . "';\n";
     if ($settings['locationId']) {
         data_entry_helper::$javascript .= "selectSection('S1', true);\n";
     }
     return $r;
 }
Exemple #6
0
 protected static function get_tab_content($auth, $args, $tab, $tabContent, $tabalias, &$attributes, &$hasControls)
 {
     // cols array used if we find | splitters
     $cols = array();
     $defAttrOptions = array('extraParams' => $auth['read']);
     if (isset($args['attribute_termlist_language_filter']) && $args['attribute_termlist_language_filter']) {
         $defAttrOptions['language'] = iform_lang_iso_639_2($args['language']);
     }
     //create array of attribute field names to test against later
     $attribNames = array();
     foreach ($attributes as $key => $attrib) {
         $attribNames[$key] = $attrib['id'];
     }
     $html = '';
     // Now output the content of the tab. Use a for loop, not each, so we can treat several rows as one object
     for ($i = 0; $i < count($tabContent); $i++) {
         $component = trim($tabContent[$i]);
         if (preg_match('/\\A\\?[^�]*\\?\\z/', $component) === 1) {
             // Component surrounded by ? so represents a help text
             $helpText = substr($component, 1, -1);
             $html .= '<div class="page-notice ui-state-highlight ui-corner-all">' . lang::get($helpText) . "</div>";
         } elseif (preg_match('/\\A\\[[^�]*\\]\\z/', $component) === 1) {
             // Component surrounded by [] so represents a control or control block
             // Anything following the component that starts with @ is an option to pass to the control
             $options = array();
             while ($i < count($tabContent) - 1 && substr($tabContent[$i + 1], 0, 1) == '@' || trim($tabContent[$i]) === '') {
                 $i++;
                 // ignore empty lines
                 if (trim($tabContent[$i]) !== '') {
                     $option = explode('=', substr($tabContent[$i], 1), 2);
                     if (!isset($option[1]) || $option[1] === 'false') {
                         $options[$option[0]] = FALSE;
                     } else {
                         $options[$option[0]] = json_decode($option[1], TRUE);
                         // if not json then need to use option value as it is
                         if ($options[$option[0]] == '') {
                             $options[$option[0]] = $option[1];
                         }
                     }
                     // urlParam is special as it loads the control's default value from $_GET
                     if ($option[0] === 'urlParam' && isset($_GET[$option[1]])) {
                         $options['default'] = $_GET[$option[1]];
                     }
                 }
             }
             // if @permission specified as an option, then check that the user has access to this control
             if (!empty($options['permission']) && !user_access($options['permission'])) {
                 continue;
             }
             $parts = explode('.', str_replace(array('[', ']'), '', $component));
             $method = 'get_control_' . preg_replace('/[^a-zA-Z0-9]/', '', strtolower($component));
             if (!empty($args['high_volume']) && $args['high_volume']) {
                 // enable control level report caching when in high_volume mode
                 $options['caching'] = empty($options['caching']) ? true : $options['caching'];
                 $options['cachetimeout'] = empty($options['cachetimeout']) ? HIGH_VOLUME_CONTROL_CACHE_TIMEOUT : $options['cachetimeout'];
             }
             // allow user settings to override the control - see iform_user_ui_options.module
             if (isset(data_entry_helper::$data['structureControlOverrides']) && !empty(data_entry_helper::$data['structureControlOverrides'][$component])) {
                 $options = array_merge($options, data_entry_helper::$data['structureControlOverrides'][$component]);
             }
             if (count($parts) === 1 && method_exists(self::$called_class, $method)) {
                 //outputs a control for which a specific output function has been written.
                 $html .= call_user_func(array(self::$called_class, $method), $auth, $args, $tabalias, $options);
                 $hasControls = true;
             } elseif (count($parts) === 2) {
                 require_once dirname($_SERVER['SCRIPT_FILENAME']) . '/' . data_entry_helper::relative_client_helper_path() . '/prebuilt_forms/extensions/' . $parts[0] . '.php';
                 if (method_exists('extension_' . $parts[0], $parts[1])) {
                     //outputs a control for which a specific extension function has been written.
                     $path = call_user_func(array(self::$called_class, 'getReloadPath'));
                     //pass the classname of the form through to the extension control method to allow access to calling class functions and variables
                     $args["calling_class"] = 'iform_' . self::$node->iform;
                     $html .= call_user_func(array('extension_' . $parts[0], $parts[1]), $auth, $args, $tabalias, $options, $path, $attributes);
                     $hasControls = true;
                     // auto-add JavaScript for the extension
                     if (file_exists(iform_client_helpers_path() . 'prebuilt_forms/extensions/' . $parts[0] . '.js')) {
                         drupal_add_js(iform_client_helpers_path() . 'prebuilt_forms/extensions/' . $parts[0] . '.js', array('preprocess' => FALSE));
                     }
                     if (file_exists(iform_client_helpers_path() . 'prebuilt_forms/extensions/' . $parts[0] . '.css')) {
                         drupal_add_css(iform_client_helpers_path() . 'prebuilt_forms/extensions/' . $parts[0] . '.css', array('preprocess' => FALSE));
                     }
                 } else {
                     $html .= lang::get("The {$component} extension cannot be found.");
                 }
             } elseif (($attribKey = array_search(substr($component, 1, -1), $attribNames)) !== false || preg_match('/^\\[[a-zA-Z]+:(?P<ctrlId>[0-9]+)\\]/', $component, $matches)) {
                 // control is a smpAttr or other attr control.
                 if (empty($options['extraParams'])) {
                     $options['extraParams'] = array_merge($defAttrOptions['extraParams']);
                 } else {
                     $options['extraParams'] = array_merge($defAttrOptions['extraParams'], (array) $options['extraParams']);
                 }
                 //merge extraParams first so we don't loose authentication
                 $options = array_merge($defAttrOptions, $options);
                 foreach ($options as $key => &$value) {
                     $value = apply_user_replacements($value);
                 }
                 if ($attribKey !== false) {
                     // a smpAttr control
                     $html .= data_entry_helper::outputAttribute($attributes[$attribKey], $options);
                     $attributes[$attribKey]['handled'] = true;
                 } else {
                     // if the control name of form name:id, then we will call get_control_name passing the id as a parameter
                     $method = 'get_control_' . preg_replace('/[^a-zA-Z]/', '', strtolower($component));
                     if (method_exists(self::$called_class, $method)) {
                         $options['ctrlId'] = $matches['ctrlId'];
                         $html .= call_user_func(array(self::$called_class, $method), $auth, $args, $tabalias, $options);
                     } else {
                         $html .= "Unsupported control {$component}<br/>";
                     }
                 }
                 $hasControls = true;
             } elseif ($component === '[*]') {
                 // this outputs any custom attributes that remain for this tab. The custom attributes can be configured in the
                 // settings text using something like @smpAttr:4|label=My label. The next bit of code parses these out into an
                 // array used when building the html.
                 // Alternatively, a setting like @option=value is applied to all the attributes.
                 $attrSpecificOptions = array();
                 foreach ($options as $option => $value) {
                     // split the id of the option into the control name and option name.
                     $optionId = explode('|', $option);
                     if (count($optionId) > 1) {
                         // Found an option like @smpAttr:4|label=My label
                         if (!isset($attrSpecificOptions[$optionId[0]])) {
                             $attrSpecificOptions[$optionId[0]] = array();
                         }
                         $attrSpecificOptions[$optionId[0]][$optionId[1]] = apply_user_replacements($value);
                     } else {
                         // Found an option like @option=value
                         $defAttrOptions = array_merge($defAttrOptions, array($option => $value));
                     }
                 }
                 $attrHtml = get_attribute_html($attributes, $args, $defAttrOptions, $tab, $attrSpecificOptions);
                 if (!empty($attrHtml)) {
                     $hasControls = true;
                 }
                 $html .= $attrHtml;
             } else {
                 $html .= "The form structure includes a control called {$component} which is not recognised.<br/>";
                 //ensure $hasControls is true so that the error message is shown
                 $hasControls = true;
             }
         } elseif ($component === '|') {
             // column splitter. So, store the col html and start on the next column.
             $cols[] = $html;
             $html = '';
         } else {
             // output anything else as is. This allow us to add html to the form structure.
             $html .= $component;
         }
     }
     if (count($cols) > 0) {
         $cols[] = $html;
         // a splitter in the structure so put the stuff so far in a 50% width left float div, and the stuff that follows in a 50% width right float div.
         global $indicia_templates;
         $html = str_replace(array('{col-1}', '{col-2}'), $cols, $indicia_templates['two-col-50']);
         if (count($cols) > 2) {
             unset($cols[1]);
             unset($cols[0]);
             $html .= '<div class="follow_on_block" style="clear:both;">' . implode('', $cols) . '</div>';
         } else {
             $html .= '<div class="follow_on_block" style="clear:both;"></div>';
         }
         // needed so any tab div is stretched around them
     }
     return $html;
 }
 /**
  * Hierarchy map control, which can be added to user interface form configurations using [site_hierarchy_navigator.map].
  *
  * Display a map with polygons loaded onto it of a particular location type. When the user clicks on one, reloads the map layer
  * to show the intersecting polygons from the next location type. Continues down the locations hierarchy in a supplied sequence of 
  * location types (e.g. you might set the location type sequence to Country, County, Parish, Site). 
  *
  * Supply an option @layerLocationTypes with a comma separated array of the location types ID to load in top down order.
  */
 public function map($auth, $args, $tabalias, $options, $path)
 {
     global $base_root;
     //Setup the path to the cudi information sheets.
     //Include the parameter on the end of the path, but leave off the parameter values
     //as these will change for each path used.
     iform_load_helpers(array('map_helper', 'report_helper'));
     $informationSheetLinkParts = explode('|', $options['informationSheetLink']);
     $path = $base_root . base_path() . (variable_get('clean_url', 0) ? '' : '?q=') . $informationSheetLinkParts[0] . (variable_get('clean_url', 0) ? '?' : '&') . $informationSheetLinkParts[1] . '=';
     map_helper::$javascript .= "indiciaData.informationSheetLink='" . $path . "';\n";
     if (empty($options['layerLocationTypes'])) {
         return '<p>Please provide a @layerLocationTypes option for the [site_hierarchy_navigator.map] map control on the edit tab</p>';
     }
     $msg = self::check_format($options, 'layerLocationTypes', 'location_type_id (from the termlists term table)', '/^([0-9]*,\\s*)*[0-9]*\\s*$/');
     if ($msg !== true) {
         return $msg;
     }
     //This option is optional, so don't need to check if it isn't present
     $msg = self::check_format($options, 'showCountUnitsForLayers', 'location_type_id (from the termlists term table)', '/^([0-9]*,\\s*)*[0-9]*\\s*$/');
     if ($msg !== true) {
         return $msg;
     }
     drupal_add_js(iform_client_helpers_path() . 'prebuilt_forms/extensions/site_hierarchy_navigator.js');
     //The location types are supplied by the user in a comma seperated list.
     //The first number is used as the initial location type to display.
     //The second number is used after the user clicks the first time on a feature and so on
     $layerLocationTypes = explode(',', $options['layerLocationTypes']);
     //Comma seperated list of location types which signify which layers should also display the Count Unit location type.
     //This should be a subset of $layerLocationTypes.
     $showCountUnitsForLayers = explode(',', $options['showCountUnitsForLayers']);
     $locationTypesWithSymbols = explode(',', $options['locationTypesWithSymbols']);
     //Annotation location types as defined on edit tab
     $annotationTypeIds = explode(',', $options['annotationTypeIds']);
     $mapOptions = iform_map_get_map_options($args, $auth);
     $olOptions = iform_map_get_ol_options($args);
     $mapOptions['readAuth'] = $mapOptions['readAuth']['read'];
     $mapOptions['clickForSpatialRef'] = false;
     //When user clicks on map, run specified Javascript function
     $mapOptions['clickableLayersOutputMode'] = 'customFunction';
     $mapOptions['customClickFn'] = 'move_to_new_layer';
     $mapOptions['clickableLayersOutputDiv'] = '';
     //Tell the system which layers we to be clickable.
     $mapOptions['clickableLayers'] = array('indiciaData.reportlayer');
     $r .= map_helper::map_panel($mapOptions, $olOptions);
     map_helper::$javascript .= "indiciaData.layerLocationTypes=" . json_encode($layerLocationTypes) . ";\n";
     $reportOptions = array('dataSource' => 'reports_for_prebuilt_forms/CUDI/get_layer_list_names', 'readAuth' => $auth['read'], 'mode' => 'report', 'extraParams' => array('layer_ids' => $options['layerLocationTypes']));
     //Return a list of location type names for the location type id layers list
     //provided by the user in the form structure.
     $locationTypeNamesDirty = data_entry_helper::get_report_data($reportOptions);
     //The data returned by the database is not a simple array of names, so convert the data and put into correct order
     foreach ($layerLocationTypes as $originalLayerIndex => $layerLocationTypeFromOriginalList) {
         foreach ($locationTypeNamesDirty as $locationTypeNamesData) {
             if ($locationTypeNamesData['id'] === $layerLocationTypeFromOriginalList) {
                 $locationTypeNamesClean[$originalLayerIndex] = $locationTypeNamesData['name'];
             }
         }
     }
     //Send the array of names to javascript
     map_helper::$javascript .= "indiciaData.layerLocationTypesNames=" . json_encode($locationTypeNamesClean) . ";\n";
     //Send the user supplied options for layers to display count units to Javascript
     map_helper::$javascript .= "indiciaData.showCountUnitsForLayers=" . json_encode($showCountUnitsForLayers) . ";\n";
     map_helper::$javascript .= "indiciaData.countUnitBoundaryTypeId=" . $options['countUnitBoundaryTypeId'] . ";\n";
     map_helper::$javascript .= "indiciaData.annotationTypeIds=" . json_encode($annotationTypeIds) . ";\n";
     map_helper::$javascript .= "indiciaData.deactivateSiteAttributeId=" . $options['deactivateSiteAttributeId'] . ";\n";
     //Get translatable label for top-level breadcrub item.
     map_helper::$javascript .= "indiciaData.allSitesLabel='" . lang::get('All Sites') . "';\n";
     $reportOptions = array('linkOnly' => 'true', 'dataSource' => 'reports_for_prebuilt_forms/cudi/get_boundaries_and_locations_for_cudi_map', 'readAuth' => $auth['read']);
     //Get the report options such as the Preset Parameters on the Edit Tab
     $reportOptions = array_merge(iform_report_get_report_options($args, $readAuth), $reportOptions);
     //Run the report that shows the locations (features) to the user when the map loads the first time.
     map_helper::$javascript .= "indiciaData.layerReportRequest='" . report_helper::get_report_data($reportOptions) . "';\n";
     //Options for the report that is used to draw the map breadcrumb
     $reportOptions = array('linkOnly' => 'true', 'dataSource' => 'reports_for_prebuilt_forms/CUDI/get_map_hierarchy_for_current_position', 'readAuth' => $auth['read']);
     //Get the report options such as the Preset Parameters on the Edit Tab
     $reportOptions = array_merge(iform_report_get_report_options($args, $readAuth), $reportOptions);
     //Run the report that builds the map breadcrumb.
     map_helper::$javascript .= "indiciaData.breadcrumbReportRequest='" . report_helper::get_report_data($reportOptions) . "';\n";
     return $r;
 }
 /**
  * Returns the client helper folder path, relative to the root folder.
  */
 public static function client_helper_path()
 {
     // allow integration modules to control path handling, e.g. Drupal).
     if (function_exists('iform_client_helpers_path')) {
         return iform_client_helpers_path();
     } else {
         $fullpath = str_replace('\\', '/', realpath(__FILE__));
         $root = $_SERVER['DOCUMENT_ROOT'] . self::getRootFolder();
         $root = str_replace('\\', '/', $root);
         $client_helper_path = dirname(str_replace($root, '', $fullpath)) . '/';
         return $client_helper_path;
     }
 }
 private static function initialise($auth, $args, $tabalias, $options, $path)
 {
     if (!self::$initialised) {
         $indicia_user_id = hostsite_get_user_field('indicia_user_id');
         if ($indicia_user_id) {
             iform_load_helpers(array('report_helper'));
             report_helper::$javascript .= "indiciaData.website_id = " . variable_get('indicia_website_id', '') . ";\n";
             report_helper::$javascript .= "indiciaData.user_id = " . $indicia_user_id . ";\n";
             //The proxy url used when interacting with the notifications table in the database.
             report_helper::$javascript .= "indiciaData.notification_proxy_url = '" . iform_ajaxproxy_url(null, 'notification') . "';\n";
             //The proxy url used when interacting with the occurrence comment table in the database.
             report_helper::$javascript .= "indiciaData.occurrence_comment_proxy_url = '" . iform_ajaxproxy_url(null, 'occ-comment') . "';\n";
             // The url used for direct access to data services.
             if (!empty(data_entry_helper::$warehouse_proxy)) {
                 self::$dataServicesUrl = data_entry_helper::$warehouse_proxy . "index.php/services/data";
             } else {
                 self::$dataServicesUrl = data_entry_helper::$base_url . "index.php/services/data";
             }
             report_helper::$javascript .= "indiciaData.data_services_url = '" . self::$dataServicesUrl . "';\n";
             // include the JavaScript file
             $jsPath = iform_client_helpers_path() . 'prebuilt_forms/extensions/notifications_centre.js';
             drupal_add_js($jsPath);
             //If the user clicks the Remove Notifications submit button, then a hidden field
             //called remove-notifications is set. We can check for this when the
             //page reloads and then call the remove notifications code.
             if (!empty($_POST['remove-notifications']) && $_POST['remove-notifications'] == 1) {
                 self::build_notifications_removal_submission($_POST, $auth);
             }
         }
         self::$initialised = true;
     }
 }
 private static function _build_sites_report($args, $readAuth, $output, $type, $mySites)
 {
     $r = self::filter_toolbar(array('my_records', 'year', 'taxon_group_list'), $readAuth);
     $reportNameSuffix = $mySites ? '_my_sites' : '_indexed_sites';
     $extraParams = $mySites ? array('person_site_attr_id' => $args['my_sites_psn_attr_id']) : array('location_type_ids' => $args['main_location_layer_type_id']);
     if (!empty($args['min_rank_sort_order_for_species'])) {
         $extraParams['min_taxon_rank_sort_order'] = $args['min_rank_sort_order_for_species'];
     }
     $reportPerUser = $mySites || !empty($_GET['my_records']);
     $reportOptions = array('readAuth' => $readAuth, 'dataSource' => "library/locations/filterable_{$type}_counts_mappable{$reportNameSuffix}", 'extraParams' => $extraParams, 'caching' => true, 'cachePerUser' => $reportPerUser, 'cachetimeout' => $reportPerUser ? self::FAST_CACHE_REFRESH : self::SLOW_CACHE_REFRESH);
     self::check_filters($reportOptions);
     if ($output === 'map') {
         require_once iform_client_helpers_path() . 'prebuilt_forms/includes/map.php';
         $reportOptions += array('valueOutput' => array('fillColor' => array('from' => '#0000ff', 'to' => '#ff0000', 'valueField' => 'value', 'minValue' => '{minvalue}', 'maxValue' => '{maxvalue}'), 'fillOpacity' => array('from' => 0.25, 'to' => 0.6, 'valueField' => 'value', 'minValue' => '{minvalue}', 'maxValue' => '{maxvalue}')));
         // This looks better when the sites are not contiguous (unlike the full indexed sites layer)
         if ($mySites) {
             $reportOptions['featureDoubleOutlineColour'] = '#f7f7f7';
         }
         $mapOptions = iform_map_get_map_options($args, $readAuth);
         $olOptions = iform_map_get_ol_options($args);
         $mapOptions['clickForSpatialRef'] = false;
         $r .= map_helper::map_panel($mapOptions, $olOptions);
         $r .= report_helper::report_map($reportOptions);
     } else {
         $reportOptions += array('downloadLink' => true, 'columns' => array(array('fieldname' => 'site_label', 'visible' => false)));
         $r .= report_helper::report_grid($reportOptions);
     }
     return $r;
 }
 public static function draw_map_plot($auth, $args, $tabalias, $options, $path)
 {
     drupal_add_js(iform_client_helpers_path() . 'prebuilt_forms/extensions/splash_extensions.js');
     if (empty($options['squareSizes'])) {
         drupal_set_message('Please fill in the @squareSizes option for the draw_map_plot control');
         return '';
     }
     iform_load_helpers(array('map_helper'));
     //Array to hold the plot width and length for Splash
     map_helper::$javascript .= "indiciaData.plotWidthLength='';\n";
     //Some Splash plot types use the polygon tool to draw the plot as any shape, specify the plot types and pass to Javascript.
     if (!empty($options['freeDrawPlotTypeNames'])) {
         map_helper::$javascript .= "indiciaData.freeDrawPlotTypeNames=" . json_encode(explode(',', $options['freeDrawPlotTypeNames'])) . ";";
     }
     //The user provides the square sizes associated with the various plot types as a comma seperated option list.
     $squareSizesOptionsSplit = explode(',', $options['squareSizes']);
     //Each option consists of the following formats
     //<plot type id>|<square side lengh> or <plot type id>|<rectangle width>|<rectangle length> or <plot type id>|0 (for drawPolygon plots)
     //So these options need splitting into an array for use
     foreach ($squareSizesOptionsSplit as $squareSizeOption) {
         $squareSizeSingleOptionSplit = explode('|', $squareSizeOption);
         //The user can supply the options for the plot in two formats, like this,
         //<location_type_id>|<number>,<location_type_id>|<number>...
         //Or like this,
         //<location_type_id>|<number>|<number>,<location_type_id>|<number>|<number>...
         //In code, both formats are treated the same way, if the second number is missing, the use the first number twice
         if (empty($squareSizeSingleOptionSplit[2])) {
             $squareSizesArray[$squareSizeSingleOptionSplit[0]] = array($squareSizeSingleOptionSplit[1], $squareSizeSingleOptionSplit[1]);
         } else {
             $squareSizesArray[$squareSizeSingleOptionSplit[0]] = array($squareSizeSingleOptionSplit[1], $squareSizeSingleOptionSplit[2]);
         }
     }
     //Javascript needs to know the square sizes for each location type (note that squares can actually be rectangles if required now, however code still refers to
     //squares as this was a late enhancement)
     $squareSizesForJavascript = json_encode($squareSizesArray);
     map_helper::$javascript .= "indiciaData.squareSizes={$squareSizesForJavascript};\n";
     if (!empty($options['pssMode'])) {
         //In NPMS/PSS, the size of the plot types used to be shown on screen, this is no longer the case, however the basic code of how this works remains intact
         //in case the client changes their minds. These attributes simply get hidden on screen now, but we could revert to displaying them if needed.
         map_helper::$javascript .= "indiciaData.plotWidthAttrId='" . $options['plotWidthAttrId'] . "';\n";
         map_helper::$javascript .= "indiciaData.plotLengthAttrId='" . $options['plotLengthAttrId'] . "';\n";
         //When use linear (free draw) plots, we have two extra boxes to fill if for the start and end grid references
         //of the plot which are not otherwise saved because it is free draw.
         //Applies to both "normal" and enhanced modes.
         if (!empty($options['linearGridRef1']) && !empty($options['linearGridRef2'])) {
             map_helper::$javascript .= "indiciaData.linearGridRef1='" . $options['linearGridRef1'] . "';\n";
             map_helper::$javascript .= "indiciaData.linearGridRef2='" . $options['linearGridRef2'] . "';\n";
         }
         map_helper::$javascript .= "indiciaData.pssMode=true;\n";
     }
     map_helper::$javascript .= "indiciaData.noSizeWarning='Please select plot type from the drop-down.';\n";
     //In edit mode, we need to manually load the plot geom
     map_helper::$javascript .= "\$('#imp-boundary-geom').val(\$('#imp-geom').val());\n";
     //On NPMS/PSS system there is a checkbox for enhanced mode (when this isn't selected, plots are not configurable and default to a 3 x 3 square.
     //Note that on splash there is no enhanced mode so plots are fully configurable.
     if (!empty($options['enhancedModeCheckboxAttrId'])) {
         map_helper::$javascript .= "indiciaData.enhancedModeCheckboxAttrId=" . $options['enhancedModeCheckboxAttrId'] . ";\n";
     }
     //On PSS/NPMS non-enhanced mode the user can define some attributes that should be hidden from view.
     //Comma separated list.
     if (!empty($options['hideLocationAttrsInSimpleMode'])) {
         map_helper::$javascript .= "indiciaData.hideLocationAttrsInSimpleMode='" . $options['hideLocationAttrsInSimpleMode'] . "';\n";
     }
     //If enhanced mode is toggled, then clear the map and also run the code as if the plot type has changed.
     //This allows the plot drawing to be reset for a new mode.
     map_helper::$javascript .= "  \n    \$('#locAttr\\\\:'+indiciaData.enhancedModeCheckboxAttrId).change(function() {  \n      clear_map_features();\n      plot_type_dropdown_change();\n    });";
     //If you change the location type then clear the features already on the map
     //If no location type is selected, then don't provide the plot drawing code with plot size details, this way it automatically warns the user
     map_helper::$javascript .= " \n    \$('#location\\\\:location_type_id').change(function() {\n      clear_map_features();\n      if (\$(this).val()) {\n        plot_type_dropdown_change();\n      } else {\n        indiciaData.plotWidthLength='';\n        \$('#locAttr\\\\:'+indiciaData.plotWidthAttrId).val('');\n        \$('#locAttr\\\\:'+indiciaData.plotLengthAttrId).val('');\n      }\n    });\n    //Don't use \$(document).ready as that fires before the indiciaData.mapdiv is setup\n    \$(window).load(function() {\n      //NPMS/PSS used to use on-screen attributes to define the plot size, they changed their minds on this so that\n      //users can no longer see the values to change on screen, however I have left the engine for this intact in case they want to go\n      //back, so simply hide the on-screen attributes.\n      \$('[id^=\"container-locAttr\\\\:'+indiciaData.plotWidthAttrId+'\"]').hide();\n      \$('[id^=\"container-locAttr\\\\:'+indiciaData.plotLengthAttrId+'\"]').hide();\n      plot_type_dropdown_change();\n      if (!\$('#location\\\\:location_type_id').val()) {\n        indiciaData.plotWidthLength='';\n        \$('#locAttr\\\\:'+indiciaData.plotWidthAttrId).val('');\n        \$('#locAttr\\\\:'+indiciaData.plotLengthAttrId).val('');\n      }\n      //As requested by client, stop return submitting form when spatial reference field is focussed\n      document.getElementById('imp-sref').addEventListener('keypress', function(event) {\n        if (event.keyCode == 13) {\n          event.preventDefault();\n        }\n      })\n    });\n";
     //Do not allow submission if there is no plot set
     data_entry_helper::$javascript .= '
 $("#save-button").click(function() { 
   if (!$("#imp-boundary-geom").val()) {
     alert("Please select a plot type and then select a plot position on the map before continuing. If you are using a Linear plot in Enhanced Mode, you will also need to make sure the plot is manually drawn onto the map."); 
     return false; 
   } else { 
     $("#entry_form").submit(); 
   }
 });';
 }