/**
  * 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.
  */
 public static function get_form($args, $node, $response = null)
 {
     if (empty($_GET['token'])) {
         return self::fail_message("You've arrived at a page intended for accepting invitations to a recording " . "group but without the correct information allowing you to join a group", $args);
     }
     $auth = data_entry_helper::get_read_write_auth($args['website_id'], $args['password']);
     $invite = data_entry_helper::get_population_data(array('table' => 'group_invitation', 'extraParams' => $auth['read'] + array('token' => $_GET['token']), 'nocache' => true));
     if (empty($invite)) {
         return self::fail_message("You've followed a link to accept an invite to a recording group but unfortunately " . "the invite is no longer valid.", $args);
     }
     $invite = $invite[0];
     if ($_POST && !empty($_POST['accept'])) {
         return self::accept($args, $invite, $auth);
     } elseif ($_POST && !empty($_POST['reject'])) {
         return self::reject($args, $invite, $auth);
     } elseif ($_POST && !empty($_POST['maybe'])) {
         return self::maybe($args, $invite, $auth);
     }
     global $user;
     if ($user->uid) {
         return self::logged_in_page($invite, $auth);
     } else {
         return self::logged_out_page($invite, $auth);
     }
 }
Пример #2
0
 /**
  * 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.
  */
 public static function get_form($args, $node, $response = null)
 {
     $reloadPath = self::get_reload_path();
     $auth = data_entry_helper::get_read_write_auth($args['website_id'], $args['password']);
     $r = "<form method=\"post\" id=\"entry_form\" action=\"{$reloadPath}\">\n";
     $r .= $auth['write'];
     data_entry_helper::$entity_to_load = array();
     if (!empty($_GET['termlists_term_id'])) {
         data_entry_helper::load_existing_record($auth['read'], 'termlists_term', $_GET['termlists_term_id']);
         // map fields to their appropriate supermodels
         data_entry_helper::$entity_to_load['term:term'] = data_entry_helper::$entity_to_load['termlists_term:term'];
         data_entry_helper::$entity_to_load['term:id'] = data_entry_helper::$entity_to_load['termlists_term:term_id'];
         data_entry_helper::$entity_to_load['meaning:id'] = data_entry_helper::$entity_to_load['termlists_term:meaning_id'];
         if (function_exists('hostsite_set_page_title')) {
             hostsite_set_page_title(lang::get('Edit {1}', data_entry_helper::$entity_to_load['term:term']));
         }
     }
     $r .= data_entry_helper::hidden_text(array('fieldname' => 'website_id', 'default' => $args['website_id']));
     $r .= data_entry_helper::hidden_text(array('fieldname' => 'termlists_term:id'));
     $r .= data_entry_helper::hidden_text(array('fieldname' => 'termlists_term:termlist_id', 'default' => $args['termlist_id']));
     $r .= data_entry_helper::hidden_text(array('fieldname' => 'termlists_term:preferred', 'default' => 't'));
     $r .= data_entry_helper::hidden_text(array('fieldname' => 'term:id'));
     $r .= data_entry_helper::hidden_text(array('fieldname' => 'term:language_id', 'default' => $args['language_id']));
     $r .= data_entry_helper::hidden_text(array('fieldname' => 'meaning:id'));
     // request automatic JS validation
     data_entry_helper::enable_validation('entry_form');
     $r .= data_entry_helper::text_input(array('label' => lang::get('Term'), 'fieldname' => 'term:term', 'helpText' => lang::get('Please provide the term'), 'validation' => array('required'), 'class' => 'control-width-5'));
     $r .= "<input type=\"submit\" name=\"form-submit\" id=\"delete\" value=\"Delete\" />\n";
     $r .= "<input type=\"submit\" name=\"form-submit\" value=\"Save\" />\n";
     $r .= '<form>';
     self::set_breadcrumb($args);
     return $r;
 }
Пример #3
0
 /**
  * Return the Indicia form code
  * @param array $args Input parameters.
  * @param array $node Drupal node object
  * @param array $response Response from Indicia services after posting a verification.
  * @return HTML string
  */
 public static function get_form($args, $node, $response)
 {
     $auth = data_entry_helper::get_read_write_auth($args['website_id'], $args['password']);
     global $user;
     $r = '';
     $presetList = explode("\n", $args['param_presets']);
     $presets = array();
     foreach ($presetList as $param) {
         $tokens = explode('=', $param);
         if (count($tokens) == 2) {
             $presets[$tokens[0]] = $tokens[1];
         } else {
             $r .= '<div class="page-notice ui-widget ui-widget-content ui-corner-all ui-state-error">' . 'Some of the preset parameters defined for this page are not of the form param=value.</div>';
         }
     }
     $reportOptions = array('id' => 'report-grid', 'class' => '', 'thClass' => '', 'dataSource' => $args['report_name'], 'mode' => 'report', 'readAuth' => $auth['read'], 'columns' => array(), 'itemsPerPage' => 20, 'autoParamsForm' => $args['auto_params_form'], 'extraParams' => $presets);
     // Add a download link
     $r .= '<a href="' . data_entry_helper::get_report_data(array_merge($reportOptions, array('linkOnly' => true))) . '&mode=csv">Download this report</a>';
     // now the grid
     $r .= data_entry_helper::report_grid($reportOptions);
     // Set up a page refresh for dynamic update of the report at set intervals
     if ($args['refresh_timer'] !== 0 && is_numeric($args['refresh_timer'])) {
         // is_int prevents injection
         if (isset($args['load_on_refresh']) && !empty($args['load_on_refresh'])) {
             data_entry_helper::$javascript .= "setTimeout('window.location=\"" . $args['load_on_refresh'] . "\";', " . $args['refresh_timer'] . "*1000 );\n";
         } else {
             data_entry_helper::$javascript .= "setTimeout('window.location.reload( false );', " . $args['refresh_timer'] . "*1000 );\n";
         }
     }
     return $r;
 }
Пример #4
0
 /**
  * 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 $errors 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.
  */
 public static function get_form($args, $node, $errors = null)
 {
     $r = '';
     $auth = data_entry_helper::get_read_write_auth($args['website_id'], $args['password']);
     // variables to tracks which parts of the plots grid are not completed, so we can display a correct message
     $someGridRefsMissing = false;
     $someHabitatsMissing = false;
     $someSqTypesMissing = false;
     data_entry_helper::$validation_mode = array('colour', 'hint', 'message');
     if (isset($_GET['sample_id'])) {
         data_entry_helper::load_existing_record($auth['read'], 'sample', $_GET['sample_id']);
         if (isset(data_entry_helper::$entity_to_load['sample:date']) && preg_match('/^(\\d{4})/', data_entry_helper::$entity_to_load['sample:date'])) {
             // Date has 4 digit year first (ISO style) - convert date to expected output format
             // @todo The date format should be a global configurable option. It should also be applied to reloading of custom date attributes.
             $d = new DateTime(data_entry_helper::$entity_to_load['sample:date']);
             data_entry_helper::$entity_to_load['sample:date'] = $d->format('d/m/Y');
         }
         $topSampleAttrs = self::load_top_sample_attrs($auth, $args, $_GET['sample_id']);
     } else {
         $topSampleAttrs = self::load_top_sample_attrs($auth, $args);
     }
     global $indicia_templates;
     $indicia_templates['starredSuffix'] = "*<br/>\n";
     $indicia_templates['validation_message'] = "<span class=\"ui-state-error-text\">{error}</span>\n";
     data_entry_helper::enable_validation('entry-form');
     $r .= '<form method="post" action="" id="entry-form">';
     $r .= '<div id="tabs">';
     data_entry_helper::enable_tabs(array('divId' => 'tabs', 'navButtons' => true));
     $r .= data_entry_helper::tab_header(array('tabs' => array('#your-square' => 'Find Place', '#your-plots' => 'Your Plots', '#species_1' => 'Species Page 1', '#species_2' => 'Species Page 2', '#species_3' => 'Species Page 3', '#species_other' => 'Other Species')));
     $r .= '<div id="your-square">';
     $r .= self::get_hiddens($args, $auth);
     $r .= self::tab_your_square($args, $auth['read'], $topSampleAttrs);
     $r .= '</div>';
     // your-square
     $r .= '<div id="your-plots">';
     $r .= self::tab_your_plots($args, $auth['read']);
     $r .= '</div>';
     // your-plots
     $r .= '<div id="species_1">';
     $r .= self::tab_species($args, $auth, 0, 34);
     $r .= '</div>';
     // species-1
     $r .= '<div id="species_2">';
     $r .= self::tab_species($args, $auth, 34, 34);
     $r .= '</div>';
     // species-2
     $r .= '<div id="species_3">';
     $r .= self::tab_species($args, $auth, 68, 34);
     $r .= '</div>';
     // species-3
     $r .= '<div id="species_other">';
     $r .= self::tab_other_species($args, $auth);
     $r .= '</div>';
     // species-3
     $r .= '</div>';
     // tabs
     $r .= '</form>';
     return $r;
 }
Пример #5
0
 /**
  * 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.
  */
 public static function get_form($args, $node, $response = null)
 {
     if (!hostsite_get_user_field('indicia_user_id')) {
         return 'Please ensure that you\'ve filled in your surname on your user profile before creating or editing groups.';
     }
     iform_load_helpers(array('report_helper', 'map_helper'));
     $args = array_merge(array('include_code' => false, 'include_dates' => false, 'include_report_filter' => true, 'include_private_records' => false, 'include_administrators' => false, 'include_members' => false, 'filter_types' => '{"":"what,where,when","Advanced":"source,quality"}'), $args);
     $args['filter_types'] = json_decode($args['filter_types'], true);
     $reloadPath = self::getReloadPath();
     data_entry_helper::$website_id = $args['website_id'];
     $auth = data_entry_helper::get_read_write_auth($args['website_id'], $args['password']);
     if (!empty($_GET['group_id'])) {
         self::loadExistingGroup($_GET['group_id'], $auth, $args);
     } else {
         if (!empty($args['parent_group_relationship_type']) && empty($_GET['from_group_id'])) {
             return 'This form should be called with a from_group_id parameter to define the parent when creating a new group';
         }
     }
     $r = "<form method=\"post\" id=\"entry_form\" action=\"{$reloadPath}\">\n";
     $r .= $auth['write'] . "<input type=\"hidden\" id=\"website_id\" name=\"website_id\" value=\"" . $args['website_id'] . "\" />\n";
     $r .= data_entry_helper::hidden_text(array('fieldname' => 'group:id'));
     if (!empty($args['group_type'])) {
         $r .= '<input type="hidden" name="group:group_type_id" value="' . $args['group_type'] . '"/>';
         $response = data_entry_helper::get_population_data(array('table' => 'termlists_term', 'extraParams' => $auth['read'] + array('id' => $args['group_type'])));
         self::$groupType = strtolower($response[0]['term']);
     }
     if (!empty(data_entry_helper::$entity_to_load['group:title']) && function_exists('drupal_set_title')) {
         drupal_set_title(lang::get('Edit {1}', data_entry_helper::$entity_to_load['group:title']));
     }
     $r .= data_entry_helper::text_input(array('label' => lang::get('{1} name', ucfirst(self::$groupType)), 'fieldname' => 'group:title', 'validation' => array('required'), 'class' => 'control-width-5', 'helpText' => lang::get('The full title of the {1}', self::$groupType)));
     if ($args['include_code']) {
         $r .= data_entry_helper::text_input(array('label' => lang::get('Code'), 'fieldname' => 'group:code', 'class' => 'control-width-4', 'helpText' => lang::get('A code or abbreviation identifying the {1}', self::$groupType)));
     }
     if (empty($args['group_type'])) {
         $r .= data_entry_helper::select(array('label' => lang::get('Group type'), 'fieldname' => 'group:group_type_id', 'required' => true, 'table' => 'termlists_term', 'valueField' => 'id', 'captionField' => 'term', 'extraParams' => $auth['read'] + array('termlist_external_key' => 'indicia:group_types'), 'class' => 'control-width-4'));
     }
     $r .= self::joinMethodsControl($args);
     $r .= data_entry_helper::textarea(array('label' => ucfirst(lang::get('{1} description', self::$groupType)), 'fieldname' => 'group:description', 'helpText' => lang::get('Description and notes about the {1}.', self::$groupType)));
     $r .= self::dateControls($args);
     if ($args['include_private_records']) {
         $r .= data_entry_helper::checkbox(array('label' => lang::get('Records are private'), 'fieldname' => 'group:private_records', 'helpText' => lang::get('Tick this box if you want to withold the release of the records from this {1} until a ' . 'later point in time, e.g. when a project is completed.', self::$groupType)));
     }
     $r .= self::memberControls($args, $auth);
     $r .= self::reportFilterBlock($args, $auth, $hiddenPopupDivs);
     // auto-insert the creator as an admin of the new group, unless the admins are manually specified
     if (!$args['include_administrators'] && empty($_GET['group_id'])) {
         $r .= '<input type="hidden" name="groups_user:admin_user_id[]" value="' . hostsite_get_user_field('indicia_user_id') . '"/>';
     }
     $r .= '<input type="hidden" name="groups_user:administrator" value="t"/>';
     $r .= '<input type="submit" class="indicia-button" id="save-button" value="' . (empty(data_entry_helper::$entity_to_load['group:id']) ? lang::get('Create {1}', self::$groupType) : lang::get('Update {1} settings', self::$groupType)) . "\" />\n";
     $r .= '</form>';
     $r .= $hiddenPopupDivs;
     data_entry_helper::enable_validation('entry_form');
     // JavaScript to grab the filter definition and store in the form for posting when the form is submitted
     data_entry_helper::$javascript .= "\n\$('#entry_form').submit(function() {\n  \$('#filter-title-val').val('" . lang::get('Filter for user group') . " ' + \$('#group\\\\:title').val());\n  \$('#filter-def-val').val(JSON.stringify(indiciaData.filter.def));\n});\n";
     return $r;
 }
 /**
  * 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)
 {
     require_once drupal_get_path('module', 'iform') . '/client_helpers/map_helper.php';
     $auth = data_entry_helper::get_read_write_auth($args['website_id'], $args['password']);
     $settings = array('locationTypes' => helper_base::get_termlist_terms($auth, 'indicia:location_types', array('Transect Section')), 'locationId' => isset($_GET['section_id']) ? $_GET['section_id'] : null, 'parentId' => isset($_GET['transect_id']) ? $_GET['transect_id'] : null);
     if ($settings['parentId']) {
         $parent = data_entry_helper::get_population_data(array('table' => 'location', 'extraParams' => $auth['read'] + array('view' => 'detail', 'id' => $settings['parentId'], 'deleted' => 'f'), 'nocache' => true));
         $settings['parent'] = $parent[0];
     } else {
         return 'This form must be called with a parent transect_id parameter.';
     }
     $settings['sections'] = data_entry_helper::get_population_data(array('table' => 'location', 'extraParams' => $auth['read'] + array('view' => 'detail', 'parent_id' => $settings['parentId'], 'deleted' => 'f'), 'nocache' => true));
     if ($settings['locationId']) {
         data_entry_helper::load_existing_record($auth['read'], 'location', $settings['locationId']);
     } else {
         data_entry_helper::$entity_to_load['location:code'] = 'S' . (count($settings['sections']) + 1);
     }
     $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['locationTypes'][0]['id']));
     if (data_entry_helper::$entity_to_load['location:code']) {
         $r = '<form method="post" id="input-form">';
     }
     $r .= $auth['write'];
     $r .= '<div id="controls">';
     $customAttributeTabs = array_merge(array('Section' => array('[*]')), get_attribute_tabs($settings['attributes']));
     if (count($customAttributeTabs) > 1) {
         $headerOptions = array('tabs' => array());
         foreach ($customAttributeTabs as $tab => $content) {
             $alias = preg_replace('/[^a-zA-Z0-9]/', '', strtolower($tab));
             $headerOptions['tabs']['#' . $alias] = lang::get($tab);
         }
         $r .= data_entry_helper::tab_header($headerOptions);
         data_entry_helper::enable_tabs(array('divId' => 'controls', 'style' => $args['interface'], 'progressBar' => isset($args['tabProgress']) && $args['tabProgress'] == true));
     }
     foreach ($customAttributeTabs as $tab => $content) {
         if ($tab == 'Section') {
             $r .= self::get_section_tab($auth, $args, $settings);
         } else {
             $alias = preg_replace('/[^a-zA-Z0-9]/', '', strtolower($tab));
             $r .= "\n<div id=\"{$alias}\">\n";
             $r .= get_attribute_html($settings['attributes'], $args, array('extraParams' => $auth['read']), $tab);
             $r .= "</div>\n";
         }
     }
     $r .= '</div>';
     // controls
     $r .= '</form>';
     data_entry_helper::link_default_stylesheet();
     if (function_exists('drupal_set_breadcrumb')) {
         $breadcrumb = array();
         $breadcrumb[] = l('Home', '<front>');
         $breadcrumb[] = l('Sites', $args['sites_list_path']);
         $breadcrumb[] = l($settings['parent']['name'], $args['transect_edit_path'], array('query' => array('id' => $settings['parentId'])));
         $breadcrumb[] = $settings['locationId'] ? data_entry_helper::$entity_to_load['location:name'] : lang::get('new section');
         drupal_set_breadcrumb($breadcrumb);
     }
     return $r;
 }
Пример #7
0
 /**
  * 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.
  */
 public static function get_form($args, $node, $response = null)
 {
     if (!($user_id = hostsite_get_user_field('indicia_user_id'))) {
         return self::abort('Please ensure that you\'ve filled in your surname on your user profile before joining a group.', $args);
     }
     if (empty($_GET['group_id'])) {
         return self::abort('This form must be called with a group_id in the URL parameters.', $args);
     }
     $r = '';
     $auth = data_entry_helper::get_read_write_auth($args['website_id'], $args['password']);
     $group = data_entry_helper::get_population_data(array('table' => 'group', 'extraParams' => $auth['read'] + array('id' => $_GET['group_id']), 'nocache' => true));
     if (count($group) !== 1) {
         return self::abort('The group you\'ve requested membership of does not exist.', $args);
     }
     iform_load_helpers(array('submission_builder'));
     $group = $group[0];
     // Check for an existing group user record
     $existing = data_entry_helper::get_population_data(array('table' => 'groups_user', 'extraParams' => $auth['read'] + array('group_id' => $_GET['group_id'], 'user_id' => $user_id), 'nocache' => true));
     if (count($existing)) {
         if ($existing[0]['pending'] === 'true') {
             // if a previous request was made and unapproved when the group was request only, but the group is now public, we can approve their existing
             // groups_user record.
             if ($group['joining_method'] === 'P') {
                 $data = array('groups_user:id' => $existing[0]['id'], 'groups_user:pending' => 'f');
                 $wrap = submission_builder::wrap($data, 'groups_user');
                 $r = data_entry_helper::forward_post_to('groups_user', $wrap, $auth['write_tokens']);
                 return self::success($auth, $group, $args);
             } else {
                 return self::abort("You've already got a membership request for {$group['title']} pending approval.", $args);
             }
         } else {
             return self::abort("You're already a member of {$group['title']}.", $args);
         }
     } else {
         $data = array('groups_user:group_id' => $group['id'], 'groups_user:user_id' => $user_id);
         // request only, so make the groups_user record pending approval
         if ($group['joining_method'] === 'R') {
             $data['groups_user:pending'] = 't';
         }
         $wrap = submission_builder::wrap($data, 'groups_user');
         $r = data_entry_helper::forward_post_to('groups_user', $wrap, $auth['write_tokens']);
         if (!isset($r['success'])) {
             return self::abort('An error occurred whilst trying to update your group membership.', $args);
         } elseif ($group['joining_method'] === 'R') {
             return self::abort("Your request to join {$group['title']} is now awaiting approval.", $args);
         } else {
             return self::success($auth, $group, $args);
         }
     }
     return $r;
 }
Пример #8
0
 /**
  * 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.
  */
 public static function get_form($args, $node, $response = null)
 {
     if (empty($_GET['group_id'])) {
         return 'This page needs a group_id URL parameter.';
     }
     global $base_url;
     global $user;
     iform_load_helpers(array('data_entry_helper'));
     data_entry_helper::$javascript .= "indiciaData.nodeId=" . $node->nid . ";\n";
     data_entry_helper::$javascript .= "indiciaData.baseUrl='" . $base_url . "';\n";
     data_entry_helper::$javascript .= "indiciaData.currentUsername='******';\n";
     //Translations for the comment that goes into occurrence_comments when a record is verified or rejected.
     data_entry_helper::$javascript .= 'indiciaData.verifiedTranslation = "' . lang::get('Verified') . "\";\n";
     data_entry_helper::$javascript .= 'indiciaData.rejectedTranslation = "' . lang::get('Rejected') . "\";\n";
     self::$auth = data_entry_helper::get_read_write_auth($args['website_id'], $args['password']);
     group_authorise_form($args, self::$auth['read']);
     $group = data_entry_helper::get_population_data(array('table' => 'group', 'extraParams' => self::$auth['read'] + array('id' => $_GET['group_id'], 'view' => 'detail')));
     $group = $group[0];
     hostsite_set_page_title("{$group['title']}: {$node->title}");
     $def = json_decode($group['filter_definition'], true);
     $defstring = '';
     // reconstruct this as a string to feed into dynamic report explorer
     foreach ($def as $key => $value) {
         if ($key) {
             $value = is_array($value) ? json_encode($value) : $value;
             $defstring .= "{$key}={$value}\n";
             if ($key === 'indexed_location_id' || $key === 'indexed_location_list' || $key === 'location_id' || $key === 'location_list') {
                 $args['location_boundary_id'] = $value;
             } elseif (($key === 'taxon_group_id' || $key === 'taxon_group_list') && strpos($value, ',') === FALSE) {
                 // if the report is locked to a single taxon group, then we don't need taxonomy columns.
                 $args['skipped_report_columns'] = array('taxon_group', 'taxonomy');
             }
         }
     }
     if (empty($_GET['implicit'])) {
         // no need for a group user filter
         $args['param_presets'] = implode("\n", array($args['param_presets'], $defstring));
     } else {
         // filter to group users - either implicitly, or only if they explicitly submitted to the group
         $prefix = $_GET['implicit'] === 'true' || $_GET['implicit'] === 't' ? 'implicit_' : '';
         // add the group parameters to the preset parameters passed to all reports on this page
         $args['param_presets'] = implode("\n", array($args['param_presets'], $defstring, "{$prefix}group_id=" . $_GET['group_id']));
     }
     $args['param_presets'] .= "\n";
     if (!empty($args['hide_standard_param_filter'])) {
         data_entry_helper::$javascript .= "\$('#standard-params').hide();\n";
     }
     return parent::get_form($args, $node);
 }
Пример #9
0
 /**
  * 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.
  */
 public static function get_form($args, $node, $response = null)
 {
     if (!($user_id = hostsite_get_user_field('indicia_user_id'))) {
         return self::abort('Please ensure that you\'ve filled in your surname on your user profile before leaving a group.', $args);
     }
     if (empty($_GET['group_id'])) {
         return self::abort('This form must be called with a group_id in the URL parameters.', $args);
     }
     $r = '';
     $auth = data_entry_helper::get_read_write_auth($args['website_id'], $args['password']);
     $group = data_entry_helper::get_population_data(array('table' => 'group', 'extraParams' => $auth['read'] + array('id' => $_GET['group_id']), 'nocache' => true));
     if (count($group) !== 1) {
         return self::abort('The group you\'ve requested membership of does not exist.', $args);
     }
     iform_load_helpers(array('submission_builder'));
     $group = $group[0];
     // Check for an existing group user record
     $existing = data_entry_helper::get_population_data(array('table' => 'groups_user', 'extraParams' => $auth['read'] + array('group_id' => $_GET['group_id'], 'user_id' => $user_id), 'nocache' => true));
     if (count($existing) !== 1) {
         return self::abort('You are not a member of this group.', $args);
     }
     if (!empty($_POST['response']) && $_POST['response'] === lang::get('Cancel')) {
         drupal_goto($args['groups_page_path']);
     } elseif (!empty($_POST['response']) && $_POST['response'] === lang::get('Confirm')) {
         $data = array('groups_user:id' => $existing[0]['id'], 'groups_user:group_id' => $group['id'], 'groups_user:user_id' => $user_id, 'deleted' => 't');
         $wrap = submission_builder::wrap($data, 'groups_user');
         $response = data_entry_helper::forward_post_to('groups_user', $wrap, $auth['write_tokens']);
         if (isset($response['success'])) {
             hostsite_show_message("You are no longer participating in {$group['title']}!");
             drupal_goto($args['groups_page_path']);
         } else {
             return self::abort('An error occurred whilst trying to update your group membership.');
         }
     } else {
         // First access of the form. Let's get confirmation
         $reload = data_entry_helper::get_reload_link_parts();
         $reloadpath = $reload['path'] . '?' . data_entry_helper::array_to_query_string($reload['params']);
         $r = '<form action="' . $reloadpath . '" method="POST"><fieldset>';
         $r .= '<legend>' . lang::get('Confirmation') . '</legend>';
         $r .= '<input type="hidden" name="leave" value="1" />';
         $r .= '<p>' . lang::get('Are you sure you want to stop participating in {1}?', $group['title']) . '</p>';
         $r .= '<input type="submit" value="' . lang::get('Confirm') . '" name="response" />';
         $r .= '<input type="submit" value="' . lang::get('Cancel') . '" name="response" />';
         $r .= '</fieldset></form>';
     }
     return $r;
 }
Пример #10
0
 /**
  * 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.
  */
 public static function get_form($args, $node, $response = null)
 {
     global $indicia_templates;
     iform_load_helpers(array('map_helper', 'report_helper'));
     // apply defaults
     $args = array_merge(array(), $args);
     $reloadPath = self::getReloadPath();
     data_entry_helper::$website_id = $args['website_id'];
     $auth = data_entry_helper::get_read_write_auth($args['website_id'], $args['password']);
     if (!empty($_GET['user_trust_id'])) {
         self::loadExistingUserTrust($_GET['user_trust_id'], $auth, $args);
     }
     $r = "<form method=\"post\" id=\"entry_form\" action=\"{$reloadPath}\">\n";
     $r .= $auth['write'] . "<input type=\"hidden\" id=\"website_id\" name=\"website_id\" value=\"" . $args['website_id'] . "\" />\n";
     $r .= data_entry_helper::hidden_text(array('fieldname' => 'user_trust:id'));
     $r .= data_entry_helper::autocomplete(array('label' => lang::get('Recorder to trust'), 'fieldname' => 'user_trust:user_id', 'table' => 'user', 'valueField' => 'id', 'captionField' => 'person_name', 'extraParams' => $auth['read'] + array('view' => 'detail'), 'class' => 'control-width-4'));
     $col1 = '<p>Define the combination of survey, taxon group and/or location that this recorder is trusted for below.</p>';
     $col1 .= '<fieldset><legend>' . lang::get('Trust settings') . '</legend>';
     $col1 .= data_entry_helper::autocomplete(array('label' => lang::get('Trust records in this survey'), 'fieldname' => 'user_trust:survey_id', 'table' => 'survey', 'valueField' => 'id', 'captionField' => 'title', 'blankText' => '<' . lang::get('any') . '>', 'extraParams' => $auth['read'] + array('sharing' => 'verification'), 'class' => 'control-width-4'));
     $col1 .= data_entry_helper::autocomplete(array('label' => lang::get('Trust records in this taxon group'), 'fieldname' => 'user_trust:taxon_group_id', 'table' => 'taxon_group', 'valueField' => 'id', 'captionField' => 'title', 'blankText' => '<' . lang::get('any') . '>', 'extraParams' => $auth['read'], 'class' => 'control-width-4'));
     $col1 .= data_entry_helper::autocomplete(array('label' => lang::get('Trust records in this location'), 'fieldname' => 'user_trust:location_id', 'table' => 'location', 'valueField' => 'id', 'captionField' => 'name', 'blankText' => '<' . lang::get('any') . '>', 'extraParams' => $auth['read'] + array('location_type_id' => variable_get('indicia_profile_location_type_id', '')), 'class' => 'control-width-4'));
     $col2 = '<p>' . lang::get('Review this recorder\'s experience in the tabs below') . '</p>';
     $col2 .= '<div id="summary-tabs">';
     $col2 .= data_entry_helper::tab_header(array('tabs' => array('#tab-surveys' => lang::get('Surveys'), '#tab-taxon-groups' => lang::get('Taxon groups'), '#tab-locations' => lang::get('Locations'))));
     data_entry_helper::enable_tabs(array('divId' => 'summary-tabs'));
     $col2 .= '<div id="tab-surveys">';
     $col2 .= report_helper::report_grid(array('id' => 'surveys-summary', 'readAuth' => $auth['read'], 'dataSource' => 'library/surveys/filterable_surveys_verification_breakdown', 'ajax' => TRUE, 'autoloadAjax' => FALSE, 'extraParams' => array('my_records' => 1)));
     $col2 .= '</div>';
     $col2 .= '<div id="tab-taxon-groups">';
     $col2 .= report_helper::report_grid(array('id' => 'taxon-groups-summary', 'readAuth' => $auth['read'], 'dataSource' => 'library/taxon_groups/filterable_taxon_groups_verification_breakdown', 'ajax' => TRUE, 'autoloadAjax' => FALSE, 'extraParams' => array('my_records' => 1)));
     $col2 .= '</div>';
     $col2 .= '<div id="tab-locations">';
     $col2 .= report_helper::report_grid(array('id' => 'locations-summary', 'readAuth' => $auth['read'], 'dataSource' => 'library/locations/filterable_locations_verification_breakdown', 'ajax' => TRUE, 'autoloadAjax' => FALSE, 'extraParams' => array('my_records' => 1, 'location_type_id' => variable_get('indicia_profile_location_type_id', ''))));
     $col2 .= '</div>';
     $col2 .= '</div>';
     $r .= str_replace(array('{col-1}', '{col-2}'), array($col1, $col2), $indicia_templates['two-col-50']);
     $r .= '</fieldset>';
     $r .= '<input type="submit" class="indicia-button" id="save-button" value="' . (empty(data_entry_helper::$entity_to_load['user_trust_id:id']) ? lang::get('Grant trust') : lang::get('Update trust settings')) . "\" />\n";
     if (!empty($_GET['user_trust_id'])) {
         $r .= '<input type="submit" class="indicia-button" id="delete-button" name="delete-button" value="' . lang::get('Revoke this trust') . "\" />\n";
         data_entry_helper::$javascript .= "\$('#delete-button').click(function(e) {\n        if (!confirm(\"Are you sure you want to revoke this trust?\")) {\n          e.preventDefault();\n          return false;\n        }\n      });\n";
     }
     $r .= '</form>';
     data_entry_helper::enable_validation('entry_form');
     return $r;
 }
 /**
  * Return the generated form output.
  * @return Form HTML.
  */
 public static function get_form($args)
 {
     if (empty($_GET['occurrence_id'])) {
         return 'This form requires an occurrence_id parameter in the URL.';
     }
     $r = "<form method=\"post\">\n";
     // Get authorisation tokens to update and read from the Warehouse.
     $auth = data_entry_helper::get_read_write_auth($args['website_id'], $args['password']);
     data_entry_helper::load_existing_record($auth['read'], 'occurrence', $_GET['occurrence_id']);
     data_entry_helper::load_existing_record($auth['read'], 'sample', data_entry_helper::$entity_to_load['occurrence:sample_id']);
     $r .= $auth['write'];
     $r .= "<input type=\"hidden\" id=\"website_id\" name=\"website_id\" value=\"" . $args['website_id'] . "\" />\n";
     $r .= "<input type=\"hidden\" id=\"occurrence:id\" name=\"occurrence:id\" value=\"" . $_GET['occurrence_id'] . "\" />\n";
     $r .= "<input type=\"hidden\" id=\"occurrence:sample_id\" name=\"occurrence:sample_id\" value=\"" . data_entry_helper::$entity_to_load['sample:id'] . "\" />\n";
     $r .= "<div id=\"controls\">\n";
     $r .= "<table>\n";
     $r .= "<tr><td><strong>Date</strong></td><td>" . data_entry_helper::$entity_to_load['sample:date'] . "</td></tr>\n";
     $r .= "<tr><td><strong>Spatial Reference</strong></td><td>" . data_entry_helper::$entity_to_load['sample:entered_sref'] . "</td></tr>\n";
     $siteLabels = array();
     if (!empty(data_entry_helper::$entity_to_load['sample:location'])) {
         $siteLabels[] = data_entry_helper::$entity_to_load['sample:location'];
     }
     if (!empty(data_entry_helper::$entity_to_load['sample:location_name'])) {
         $siteLabels[] = data_entry_helper::$entity_to_load['sample:location_name'];
     }
     $r .= "<tr><td><strong>Site</strong></td><td>" . implode(' | ', $siteLabels) . "</td></tr>\n";
     $smpAttrs = data_entry_helper::getAttributes(array('id' => data_entry_helper::$entity_to_load['sample:id'], 'valuetable' => 'sample_attribute_value', 'attrtable' => 'sample_attribute', 'key' => 'sample_id', 'extraParams' => $auth['read'], 'survey_id' => data_entry_helper::$entity_to_load['occurrence:survey_id']));
     $occAttrs = data_entry_helper::getAttributes(array('id' => $_GET['occurrence_id'], 'valuetable' => 'occurrence_attribute_value', 'attrtable' => 'occurrence_attribute', 'key' => 'occurrence_id', 'extraParams' => $auth['read'], 'survey_id' => data_entry_helper::$entity_to_load['occurrence:survey_id']));
     $attributes = array_merge($smpAttrs, $occAttrs);
     foreach ($attributes as $attr) {
         $r .= "<tr><td><strong>" . $attr['caption'] . "</strong></td><td>" . $attr['displayValue'] . "</td></tr>\n";
     }
     $extraParams = $auth['read'] + array('taxon_list_id' => $args['list_id']);
     if ($args['preferred']) {
         $extraParams += array('preferred' => 't');
     }
     $species_list_args = array('itemTemplate' => 'select_species', 'fieldname' => 'occurrence:taxa_taxon_list_id', 'table' => 'taxa_taxon_list', 'captionField' => 'taxon', 'valueField' => 'id', 'columns' => 2, 'extraParams' => $extraParams);
     // Dynamically generate the species selection control required.
     $r .= '<tr/><td><strong>Species</strong></td><td>' . call_user_func(array('data_entry_helper', $args['species_ctrl']), $species_list_args) . "</td></tr>\n";
     $r .= "</table>\n";
     $r .= "</div>\n";
     $r .= "<input type=\"submit\" class=\"ui-state-default ui-corner-all\" value=\"Save\" />\n";
     $r .= "</form>";
     return $r;
 }
Пример #12
0
 public function setup()
 {
     $this->auth = data_entry_helper::get_read_write_auth(1, 'password');
     // make the tokens re-usable
     $this->auth['write_tokens']['persist_auth'] = true;
     // set up a tiny bit of data. First pick a termlists_term_id to use which is never going to be a valid location type,
     // so we can filter for just our test location.
     $this->db = new Database();
     $qry = $this->db->select('id')->from('list_termlists_terms')->where(array('termlist_external_key' => 'indicia:dafor', 'term' => 'Frequent'))->get()->result_array(false);
     $this->locationTypeId = $qry[0]['id'];
     $loc = ORM::Factory('location');
     $loc->name = 'UnitTest';
     $loc->centroid_sref = 'SU01';
     $loc->centroid_sref_system = 'OSGB';
     $loc->location_type_id = $this->locationTypeId;
     $loc->set_metadata();
     $loc->save();
     $this->locationId = $loc->id;
     $locattr = ORM::Factory('location_attribute');
     $locattr->caption = 'UnitTest';
     $locattr->data_type = 'T';
     $locattr->public = 'f';
     $locattr->set_metadata();
     $locattr->save();
     $this->locationAttributeId = $locattr->id;
     $locwebsite = ORM::Factory('location_attributes_website');
     $locwebsite->website_id = 1;
     $locwebsite->location_attribute_id = $this->locationAttributeId;
     $locwebsite->set_metadata();
     $locwebsite->save();
     $this->locationAttrWebsiteId = $locwebsite->id;
     $locattr = ORM::Factory('location_attribute');
     $locattr->caption = 'UnitTestInt';
     $locattr->data_type = 'I';
     $locattr->public = 'f';
     $locattr->set_metadata();
     $locattr->save();
     $this->locationAttributeId2 = $locattr->id;
     $locwebsite = ORM::Factory('location_attributes_website');
     $locwebsite->website_id = 1;
     $locwebsite->location_attribute_id = $this->locationAttributeId2;
     $locwebsite->set_metadata();
     $locwebsite->save();
     $this->locationAttrWebsiteId2 = $locwebsite->id;
 }
Пример #13
0
 /**
  * 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.
  */
 public static function get_form($args, $node, $response = null)
 {
     $reloadPath = self::getReloadPath();
     data_entry_helper::$website_id = $args['website_id'];
     $auth = data_entry_helper::get_read_write_auth($args['website_id'], $args['password']);
     $group = self::loadGroup($auth);
     if (!empty($_POST['invitee_emails'])) {
         self::sendInvites($args, $auth);
     }
     $r = "<form method=\"post\" id=\"entry_form\" action=\"{$reloadPath}\">\n";
     $r .= data_entry_helper::textarea(array('label' => lang::get('Send invites to'), 'helpText' => 'Enter email addresses for the people you want to invite, one per line', 'fieldname' => 'invitee_emails', 'validation' => array('required')));
     $r .= data_entry_helper::textarea(array('label' => lang::get('Invitation message'), 'helpText' => 'What message would you like to send to your invitees?', 'fieldname' => 'invite_message', 'validation' => array('required'), 'default' => 'Would you like to join the ' . $group['title'] . '?'));
     $r .= '<button type="submit" class="indicia-button" id="save-button">' . lang::get('Send Invites') . "</button>\n";
     $r .= '<button type="button" class="indicia-button" id="not-now-button" ' . 'onclick="window.location.href=\'' . url($args['redirect_on_success']) . '\'">' . lang::get('Not Now') . "</button>\n";
     $r .= '</form>';
     data_entry_helper::enable_validation('entry_form');
     return $r;
 }
Пример #14
0
 public function setup()
 {
     $this->auth = data_entry_helper::get_read_write_auth(1, 'password');
     $token = $this->auth['read']['auth_token'];
     $nonce = $this->auth['read']['nonce'];
     $this->request = data_entry_helper::$base_url . "index.php/services/data_cleaner/verify?auth_token={$token}&nonce={$nonce}";
     $this->db = new Database();
     $qry = $this->db->query('select id from taxon_groups limit 1')->result_array(false);
     $taxon_group_id = $qry[0]['id'];
     $species = array('taxon:taxon' => 'test species', 'taxon:language_id' => 2, 'taxon:taxon_group_id' => $taxon_group_id, 'taxon:external_key' => 'TESTKEY', 'taxa_taxon_list:taxon_list_id' => 1, 'taxa_taxon_list:preferred' => 't');
     $this->ttl = ORM::Factory('taxa_taxon_list');
     $this->ttl->set_submission_data($species, false);
     if (!$this->ttl->submit()) {
         echo kohana::debug($this->ttl->getAllErrors());
         throw new exception('Failed to create species');
     }
     $cache = Cache::instance();
     $cache->delete('data-cleaner-rules');
 }
Пример #15
0
 /**
  * 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)
 {
     if (empty($_GET['group_id'])) {
         return 'This page needs a group_id URL parameter.';
     }
     self::$auth = data_entry_helper::get_read_write_auth($args['website_id'], $args['password']);
     $group = data_entry_helper::get_population_data(array('table' => 'group', 'extraParams' => self::$auth['read'] + array('id' => $_GET['group_id'])));
     $group = $group[0];
     hostsite_set_page_title($group['title']);
     $filter = data_entry_helper::get_population_data(array('table' => 'filter', 'extraParams' => self::$auth['read'] + array('id' => $group['filter_id'])));
     $filter = $filter[0];
     $def = json_decode($filter['definition'], true);
     $defstring = '';
     // reconstruct this as a string to feed into dynamic report explorer
     foreach ($def as $key => $value) {
         if ($key) {
             $defstring .= "{$key}={$value}\n";
         }
     }
     // add the group parameters to the preset parameters passed to all reports on this page
     $args['param_presets'] = implode("\n", array($args['param_presets'], $defstring, "group_id=" . $_GET['group_id']));
     return parent::get_form($args, $node);
 }
Пример #16
0
 /**
  * Clears moderation notifications for a moderator automatically on visiting the page, so then they
  * will get notified about new incoming records.
  */
 public static function clear_moderation_task_notifications($auth, $args, $tabalias, $options, $path)
 {
     //Using 'submission_list' and 'entries' allows us to specify several top-level submissions to the system
     //i.e. we need to be able to submit several notifications.
     $submission['submission_list']['entries'] = array();
     $submission['id'] = 'notification';
     $notifications = data_entry_helper::get_population_data(array('table' => 'notification', 'extraParams' => $auth['read'] + array('acknowledged' => 'f', 'user_id' => hostsite_get_user_field('indicia_user_id'), 'source_type' => 'PT'), 'nocache' => true));
     if (count($notifications) > 0) {
         $auth = data_entry_helper::get_read_write_auth(variable_get('indicia_website_id', 0), variable_get('indicia_password', ''));
         //Setup the structure we need to submit.
         foreach ($notifications as $notification) {
             $data['id'] = 'notification';
             $data['fields']['id']['value'] = $notification['id'];
             $data['fields']['acknowledged']['value'] = 't';
             $submission['submission_list']['entries'][] = $data;
         }
         //Submit the stucture for processing
         $response = data_entry_helper::forward_post_to('save', $submission, $auth['write_tokens']);
         if (!is_array($response) || !array_key_exists('success', $response)) {
             drupal_set_message(print_r($response, true));
         }
     }
     return '';
 }
Пример #17
0
 /**
  * Ajax method to proxy requests for bulk verification on to the warehouse, attaching write auth
  * as it goes.
  */
 public static function ajax_bulk_verify($website_id, $password)
 {
     iform_load_helpers(array('data_entry_helper'));
     $auth = data_entry_helper::get_read_write_auth($website_id, $password);
     $url = data_entry_helper::$base_url . "index.php/services/data_utils/bulk_verify";
     $params = array_merge($_POST, $auth['write_tokens']);
     $response = data_entry_helper::http_post($url, $params);
     echo $response['output'];
 }
Пример #18
0
   /**
    * Return the generated form output.
    * @return Form HTML.
    */
   public static function get_form($args, $node)
   {
       define("MODE_GRID", 0);
       define("MODE_NEW_SAMPLE", 1);
       define("MODE_EXISTING", 2);
       self::parse_defaults($args);
       self::getArgDefaults($args);
       global $user;
       $logged_in = $user->uid > 0;
       self::$node = $node;
       // Get authorisation tokens to update and read from the Warehouse.
       $auth = data_entry_helper::get_read_write_auth($args['website_id'], $args['password']);
       $svcUrl = data_entry_helper::$base_url . '/index.php/services';
       self::$auth = $auth;
       $mode = isset($args['no_grid']) && $args['no_grid'] ? MODE_NEW_SAMPLE : MODE_GRID;
       // default mode when no grid set to false - display grid of existing data
       // mode MODE_EXISTING: display existing sample
       $loadedSampleId = null;
       $loadedOccurrenceId = null;
       if ($_POST) {
           if (!array_key_exists('website_id', $_POST)) {
               // non Indicia POST, in this case must be the location allocations. add check to ensure we don't corrept the data by accident
               if (function_exists('iform_loctools_checkaccess') && iform_loctools_checkaccess($node, 'admin') && array_key_exists('mnhnld1', $_POST)) {
                   iform_loctools_deletelocations($node);
                   foreach ($_POST as $key => $value) {
                       $parts = explode(':', $key);
                       iform_loctools_insertlocation($node, $parts[2], $parts[1]);
                   }
               }
           } else {
               if (!is_null(data_entry_helper::$entity_to_load)) {
                   $mode = MODE_EXISTING;
                   // errors with new sample, entity populated with post, so display this data.
               }
           }
           // else valid save, so go back to gridview: default mode 0
       }
       if (array_key_exists('sample_id', $_GET) && $_GET['sample_id'] != '{sample_id}') {
           $mode = MODE_EXISTING;
           $loadedSampleId = $_GET['sample_id'];
       }
       if (array_key_exists('occurrence_id', $_GET) && $_GET['occurrence_id'] != '{occurrence_id}') {
           $mode = MODE_EXISTING;
           $loadedOccurrenceId = $_GET['occurrence_id'];
           self::$occurrenceIds = array($loadedOccurrenceId);
       }
       if ($mode != MODE_EXISTING && array_key_exists('newSample', $_GET)) {
           $mode = MODE_NEW_SAMPLE;
           data_entry_helper::$entity_to_load = array();
       }
       // else default to mode MODE_GRID or MODE_NEW_SAMPLE depending on no_grid parameter
       self::$mode = $mode;
       // default mode  MODE_GRID : display grid of the samples to add a new one
       // or edit an existing one.
       if ($mode == MODE_GRID) {
           $r = '';
           $attributes = data_entry_helper::getAttributes(array('valuetable' => 'sample_attribute_value', 'attrtable' => 'sample_attribute', 'key' => 'sample_id', 'fieldprefix' => 'smpAttr', 'extraParams' => $auth['read'], 'survey_id' => $args['survey_id']), false);
           $tabs = array('#sampleList' => lang::get('LANG_Main_Samples_Tab'));
           if ($args['includeLocTools'] && function_exists('iform_loctools_checkaccess') && iform_loctools_checkaccess($node, 'admin')) {
               $tabs['#setLocations'] = lang::get('LANG_Allocate_Locations');
           }
           if (method_exists(get_called_class(), 'getExtraGridModeTabs')) {
               $extraTabs = call_user_func(array(get_called_class(), 'getExtraGridModeTabs'), false, $auth['read'], $args, $attributes);
               if (is_array($extraTabs)) {
                   $tabs = $tabs + $extraTabs;
               }
           }
           if (count($tabs) > 1) {
               $r .= "<div id=\"controls\">" . data_entry_helper::enable_tabs(array('divId' => 'controls', 'active' => '#sampleList')) . "<div id=\"temp\"></div>";
               $r .= data_entry_helper::tab_header(array('tabs' => $tabs));
           }
           $r .= "<div id=\"sampleList\">" . call_user_func(array(get_called_class(), 'getSampleListGrid'), $args, $node, $auth, $attributes) . "</div>";
           if ($args['includeLocTools'] && function_exists('iform_loctools_checkaccess') && iform_loctools_checkaccess($node, 'admin')) {
               $r .= '
 <div id="setLocations">
   <form method="post">
     <input type="hidden" id="mnhnld1" name="mnhnld1" value="mnhnld1" /><table border="1"><tr><td></td>';
               $url = $svcUrl . '/data/location?mode=json&view=detail&auth_token=' . $auth['read']['auth_token'] . "&nonce=" . $auth['read']["nonce"] . "&parent_id=NULL&orderby=name";
               $session = curl_init($url);
               curl_setopt($session, CURLOPT_RETURNTRANSFER, true);
               $entities = json_decode(curl_exec($session), true);
               $userlist = iform_loctools_listusers($node);
               foreach ($userlist as $uid => $a_user) {
                   $r .= '<td>' . $a_user->name . '</td>';
               }
               $r .= "</tr>";
               if (!empty($entities)) {
                   foreach ($entities as $entity) {
                       if (!$entity["parent_id"]) {
                           // only assign parent locations.
                           $r .= "<tr><td>" . $entity["name"] . "</td>";
                           $defaultuserids = iform_loctools_getusers($node, $entity["id"]);
                           foreach ($userlist as $uid => $a_user) {
                               $r .= '<td><input type="checkbox" name="location:' . $entity["id"] . ':' . $uid . (in_array($uid, $defaultuserids) ? '" checked="checked"' : '"') . '></td>';
                           }
                           $r .= "</tr>";
                       }
                   }
               }
               $r .= "</table>\n      <input type=\"submit\" class=\"ui-state-default ui-corner-all\" value=\"" . lang::get('LANG_Save_Location_Allocations') . "\" />\n    </form>\n  </div>";
           }
           if (method_exists(get_called_class(), 'getExtraGridModeTabs')) {
               $r .= call_user_func(array(get_called_class(), 'getExtraGridModeTabs'), true, $auth['read'], $args, $attributes);
           }
           if (count($tabs) > 1) {
               // close tabs div if present
               $r .= "</div>";
           }
           return $r;
       }
       if ($mode == MODE_EXISTING && is_null(data_entry_helper::$entity_to_load)) {
           // only load if not in error situation
           data_entry_helper::$entity_to_load = array();
           // Displaying an existing sample. If we know the occurrence ID, and don't know the sample ID or are displaying just one occurrence
           // rather than a grid of occurrences then we must load the occurrence data to get the sample id.
           if ($loadedOccurrenceId && (!$loadedSampleId || !self::getGridMode($args))) {
               data_entry_helper::load_existing_record($auth['read'], 'occurrence', $loadedOccurrenceId);
               // Get the sample ID for the occurrence. This overwrites it if supply in GET but did not match the occurrence's sample
               $loadedSampleId = data_entry_helper::$entity_to_load['occurrence:sample_id'];
               if (self::getGridMode($args)) {
                   // in grid mode, we only needed to load the occurrence to find out the sample id.
                   data_entry_helper::$entity_to_load = array();
               }
           }
           if ($loadedSampleId) {
               data_entry_helper::load_existing_record($auth['read'], 'sample', $loadedSampleId);
           }
       }
       // attributes must be fetched after the entity to load is filled in - this is because the id gets filled in then!
       $attrOpts = array('id' => data_entry_helper::$entity_to_load['sample:id'], 'valuetable' => 'sample_attribute_value', 'attrtable' => 'sample_attribute', 'key' => 'sample_id', 'fieldprefix' => 'smpAttr', 'extraParams' => $auth['read'], 'survey_id' => $args['survey_id']);
       // select only the custom attributes that are for this sample method or all sample methods, if this
       // form is for a specific sample method.
       if (!empty($args['sample_method_id'])) {
           $attrOpts['sample_method_id'] = $args['sample_method_id'];
       }
       $attributes = data_entry_helper::getAttributes($attrOpts, false);
       //// Make sure the form action points back to this page
       $reload = data_entry_helper::get_reload_link_parts();
       unset($reload['params']['sample_id']);
       unset($reload['params']['occurrence_id']);
       unset($reload['params']['newSample']);
       $reloadPath = $reload['path'];
       if (count($reload['params'])) {
           $reloadPath .= '?' . http_build_query($reload['params']);
       }
       $r = "<form method=\"post\" id=\"entry_form\" action=\"{$reloadPath}\">\n";
       // Get authorisation tokens to update the Warehouse, plus any other hidden data.
       $hiddens = $auth['write'] . "<input type=\"hidden\" id=\"website_id\" name=\"website_id\" value=\"" . $args['website_id'] . "\" />\n" . "<input type=\"hidden\" id=\"survey_id\" name=\"survey_id\" value=\"" . $args['survey_id'] . "\" />\n";
       if (!empty($args['sample_method_id'])) {
           $hiddens .= '<input type="hidden" name="sample:sample_method_id" value="' . $args['sample_method_id'] . '"/>';
       }
       if (isset(data_entry_helper::$entity_to_load['sample:id'])) {
           $hiddens .= "<input type=\"hidden\" id=\"sample:id\" name=\"sample:id\" value=\"" . data_entry_helper::$entity_to_load['sample:id'] . "\" />\n";
       }
       if (isset(data_entry_helper::$entity_to_load['occurrence:id'])) {
           $hiddens .= "<input type=\"hidden\" id=\"occurrence:id\" name=\"occurrence:id\" value=\"" . data_entry_helper::$entity_to_load['occurrence:id'] . "\" />\n";
       }
       // Check if Record Status is included as a control. If not, then add it as a hidden.
       $arr = explode("\r\n", $args['structure']);
       if (!in_array('[record status]', $arr)) {
           $value = isset($args['defaults']['occurrence:record_status']) ? $args['defaults']['occurrence:record_status'] : 'C';
           $hiddens .= "<input type=\"hidden\" id=\"occurrence:record_status\" name=\"occurrence:record_status\" value=\"{$value}\" />\n";
       }
       // request automatic JS validation
       if (!isset($args['clientSideValidation']) || $args['clientSideValidation']) {
           data_entry_helper::enable_validation('entry_form');
       }
       // If logged in, output some hidden data about the user
       if (isset($args['copyFromProfile']) && $args['copyFromProfile'] == true) {
           self::profile_load_all_profile($user);
       }
       foreach ($attributes as &$attribute) {
           $attrPropName = 'profile_' . strtolower(str_replace(' ', '_', $attribute['caption']));
           if (isset($args['copyFromProfile']) && $args['copyFromProfile'] == true && isset($user->{$attrPropName})) {
               if ($args['nameShow'] == true) {
                   $attribute['default'] = $user->{$attrPropName};
               } else {
                   // profile attributes are not displayed as the user is logged in
                   $attribute['handled'] = true;
                   $attribute['value'] = $user->{$attrPropName};
               }
           } elseif (strcasecmp($attribute['caption'], 'cms user id') == 0) {
               if ($logged_in) {
                   $attribute['value'] = $user->uid;
               }
               $attribute['handled'] = true;
               // user id attribute is never displayed
           } elseif (strcasecmp($attribute['caption'], 'cms username') == 0) {
               if ($logged_in) {
                   $attribute['value'] = $user->name;
               }
               $attribute['handled'] = true;
               // username attribute is never displayed
           } elseif (strcasecmp($attribute['caption'], 'email') == 0) {
               if ($logged_in) {
                   if ($args['emailShow'] != true) {
                       // email attribute is not displayed
                       $attribute['value'] = $user->mail;
                       $attribute['handled'] = true;
                   } else {
                       $attribute['default'] = $user->mail;
                   }
               }
           } elseif ((strcasecmp($attribute['caption'], 'first name') == 0 || strcasecmp($attribute['caption'], 'last name') == 0 || strcasecmp($attribute['caption'], 'surname') == 0) && $logged_in) {
               if ($args['nameShow'] != true) {
                   // name attributes are not displayed because we have the users login
                   $attribute['handled'] = true;
               }
           }
           // If we have a value for one of the user login attributes then we need to output this value. BUT, for existing data
           // we must not overwrite the user who created the record.
           if (isset($attribute['value']) && $mode != MODE_EXISTING) {
               $hiddens .= '<input type="hidden" name="' . $attribute['fieldname'] . '" value="' . $attribute['value'] . '" />' . "\n";
           }
       }
       $customAttributeTabs = get_attribute_tabs($attributes);
       $tabs = self::get_all_tabs($args['structure'], $customAttributeTabs);
       $r .= "<div id=\"controls\">\n";
       // Build a list of the tabs that actually have content
       $tabHtml = self::get_tab_html($tabs, $auth, $args, $attributes, $hiddens);
       // Output the dynamic tab headers
       if ($args['interface'] != 'one_page') {
           $headerOptions = array('tabs' => array());
           foreach ($tabHtml as $tab => $tabContent) {
               $alias = preg_replace('/[^a-zA-Z0-9]/', '', strtolower($tab));
               $tabtitle = lang::get("LANG_Tab_{$alias}");
               if ($tabtitle == "LANG_Tab_{$alias}") {
                   // if no translation provided, we'll just use the standard heading
                   $tabtitle = $tab;
               }
               $headerOptions['tabs']['#' . $alias] = $tabtitle;
           }
           $r .= data_entry_helper::tab_header($headerOptions);
           data_entry_helper::enable_tabs(array('divId' => 'controls', 'style' => $args['interface'], 'progressBar' => isset($args['tabProgress']) && $args['tabProgress'] == true));
       }
       // Output the dynamic tab content
       $pageIdx = 0;
       foreach ($tabHtml as $tab => $tabContent) {
           // get a machine readable alias for the heading
           $tabalias = preg_replace('/[^a-zA-Z0-9]/', '', strtolower($tab));
           $r .= '<div id="' . $tabalias . '">' . "\n";
           // For wizard include the tab title as a header.
           if ($args['interface'] == 'wizard') {
               $r .= '<h1>' . $headerOptions['tabs']['#' . $tabalias] . '</h1>';
           }
           $r .= $tabContent;
           // Add any buttons required at the bottom of the tab
           if ($args['interface'] == 'wizard') {
               $r .= data_entry_helper::wizard_buttons(array('divId' => 'controls', 'page' => $pageIdx === 0 ? 'first' : ($pageIdx == count($tabHtml) - 1 ? 'last' : 'middle')));
           } elseif ($pageIdx == count($tabHtml) - 1 && !($args['interface'] == 'tabs' && $args['save_button_below_all_pages'])) {
               // last part of a non wizard interface must insert a save button, unless it is tabbed interface with save button beneath all pages
               $r .= "<input type=\"submit\" class=\"ui-state-default ui-corner-all\" id=\"save-button\" value=\"" . lang::get('LANG_Save') . "\" />\n";
           }
           $pageIdx++;
           $r .= "</div>\n";
       }
       $r .= "</div>\n";
       if ($args['interface'] == 'tabs' && $args['save_button_below_all_pages']) {
           $r .= "<input type=\"submit\" class=\"ui-state-default ui-corner-all\" id=\"save-button\" value=\"" . lang::get('LANG_Save') . "\" />\n";
       }
       if (!empty(data_entry_helper::$validation_errors)) {
           $r .= data_entry_helper::dump_remaining_errors();
       }
       $r .= "</form>";
       $r .= self::link_species_popups($args);
       return $r;
   }
Пример #19
0
    /**
     * Return the Indicia form code
     * @param array $args Input parameters.
     * @param array $node Drupal node object
     * @param array $response Response from Indicia services after posting a verification.
     * @return HTML string
     */
    public static function get_form($args, $node, $response)
    {
        global $user;
        $auth = data_entry_helper::get_read_write_auth($args['website_id'], $args['password']);
        $r = '';
        if ($_POST) {
            // dump out any errors that occurred on verification
            if (data_entry_helper::$validation_errors) {
                $r .= '<div class="page-notice ui-state-highlight ui-corner-all"><p>' . implode('</p></p>', array_values(data_entry_helper::$validation_errors)) . '</p></div>';
            } else {
                if (isset($_POST['email'])) {
                    // Send email. Depends upon settings in php.ini being correct
                    $success = mail($_POST['email_to'], $_POST['email_subject'], wordwrap($_POST['email_body'], 70), 'From: ' . $user->mail . PHP_EOL . 'Return-Path: ' . $user->mail);
                } else {
                    if (isset($_POST['occurrence:record_status']) && isset($response['success']) && $args['emails_enabled']) {
                        // Provide a send email form to allow the user to send a verification email
                        if ($_POST['occurrence:record_status'] == 'V') {
                            $action = 'verified';
                        } elseif ($_POST['occurrence:record_status'] == 'R') {
                            $action = 'rejected';
                        } else {
                            $action = '';
                        }
                        if ($action) {
                            $occ = data_entry_helper::get_population_data(array('table' => 'occurrence', 'extraParams' => $auth['read'] + array('id' => $response['outer_id'], 'view' => 'detail')));
                            $occ = $occ[0];
                            $email_attr = data_entry_helper::get_population_data(array('table' => 'sample_attribute_value', 'extraParams' => $auth['read'] + array('caption' => 'Email', 'sample_id' => $occ['sample_id'])));
                            $verified_taxa_taxon_list_id = $_POST['occAttr:' . $args['occ_attr_id']];
                            if ($action == 'verified' && $verified_taxa_taxon_list_id != $occ['taxa_taxon_list_id']) {
                                $action = 'misidentified';
                                $verified_taxon = data_entry_helper::get_population_data(array('table' => 'taxa_taxon_list', 'extraParams' => $auth['read'] + array('id' => $verified_taxa_taxon_list_id)));
                                $occ = array_merge($occ, array('verified_taxon' => $verified_taxon[0]['taxon']));
                            }
                            $subject = self::get_email_component('subject', $action, $occ, $args);
                            $body = self::get_email_component('body', $action, $occ, $args);
                            if (!empty($email_attr[0]['value'])) {
                                $r .= '
<form id="email" action="" method="post">
<fieldset>
<legend>Send a notification email to the recorder.</legend>
<label>To: <input type="text" name="email_to" size="80" value="' . $email_attr[0]['value'] . '"></label><br />
<label>Subject: <input type="text" name="email_subject" size="80" value="' . $subject . '"></label><br />
<label>Body: <textarea name="email_body" rows="5" cols="80">' . $body . '</textarea></label><br />
<input type="hidden" name="email" value="1">
<input type="button" value="Send Email" onclick="
    $(\'form#email\').attr(\'action\', submit_to());
    $(\'form#email\').submit();
">
</fieldset>
</form>
';
                            } else {
                                $r .= '<div class="page-notice ui-state-highlight ui-corner-all">The record has been ' . $action . '. The recorder did not leave an email address so cannot be notified.</div>';
                            }
                        }
                    }
                }
            }
        }
        //extract fixed parameters for report grid.
        $params = explode(",", $args['fixed_params']);
        foreach ($params as $param) {
            $keyvals = explode("=", $param);
            $key = trim($keyvals[0]);
            $val = trim($keyvals[1]);
            $extraParams[$key] = $val;
        }
        $columns = array(array('display' => 'Actions', 'actions' => array(array('caption' => 'Verify', 'javascript' => 'indicia_verify({occurrence_id}, true, ' . $user->uid . '); return false;'), array('caption' => 'Reject', 'javascript' => 'indicia_verify({occurrence_id}, false, ' . $user->uid . '); return false;'))));
        //create a list of species to choose from with a hidden field indicating which to preselect
        //with javascript
        $taxon_list = data_entry_helper::get_population_data(array('table' => 'taxa_taxon_list', 'extraParams' => $auth['read'] + array('taxon_list_id' => $args['taxon_list_id'], 'orderby' => 'taxon_id')));
        $species = '<select id="species-{occurrence_id}">';
        foreach ($taxon_list as $taxon) {
            $species .= '<option value="' . $taxon['id'] . '">' . $taxon['taxon'] . '</opton>';
        }
        $species .= '</select>';
        $species .= '<input type="hidden" value="{taxa_taxon_list_id}" />';
        $columns = array_merge($columns, array(array('display' => 'Taxon', 'template' => $species)));
        $r .= data_entry_helper::report_grid(array('id' => 'verification-grid', 'dataSource' => $args['report_name'], 'mode' => 'report', 'readAuth' => $auth['read'], 'columns' => $columns, 'itemsPerPage' => 10, 'autoParamsForm' => $args['auto_params_form'], 'extraParams' => $extraParams, 'callback' => 'indicia_verification_2_species_init'));
        $r .= '
<form id="verify" method="post" action="">
  ' . $auth['write'] . '
  <input type="hidden" id="occurrence:id" name="occurrence:id" value="" />
  <input type="hidden" id="occurrence:record_status" name="occurrence:record_status" value="" />
  <input type="hidden" id="website_id" name="website_id" value="' . $args['website_id'] . '" />
  <input type="hidden" id="occurrence:verified_by_id" name="occurrence:verified_by_id" value="" />
  <input type="hidden" id="occAttr:' . $args['occ_attr_id'] . '" name="occAttr:' . $args['occ_attr_id'] . '" value="" />
</form>
';
        drupal_add_js('
var verifiers_mapping = "' . $args['verifiers_mapping'] . '";
var url = ' . json_encode(data_entry_helper::get_reload_link_parts()) . ';
var verified_species = "occAttr:' . $args['occ_attr_id'] . '";', 'inline');
        return $r;
    }
 public static function get_occurrences_form($args, $node, $response)
 {
     global $user;
     if (!module_exists('iform_ajaxproxy')) {
         return 'This form must be used in Drupal with the Indicia AJAX Proxy module enabled.';
     }
     drupal_add_js('misc/tableheader.js');
     // for sticky heading
     data_entry_helper::add_resource('jquery_form');
     $auth = data_entry_helper::get_read_write_auth($args['website_id'], $args['password']);
     // did the parent sample previously exist? Default is no.
     $existing = false;
     $url = explode('?', $args['my_obs_page'], 2);
     $params = NULL;
     $fragment = NULL;
     // fragment is always at the end.
     if (count($url) > 1) {
         $params = explode('#', $url[1], 2);
         if (count($params) > 1) {
             $fragment = $params[1];
         }
         $params = $params[0];
     } else {
         $url = explode('#', $url[0], 2);
         if (count($url) > 1) {
             $fragment = $url[1];
         }
     }
     $args['my_obs_page'] = url($url[0], array('query' => $params, 'fragment' => $fragment, 'absolute' => TRUE));
     if (isset($_POST['sample:id'])) {
         // have just posted an edit to the existing sample
         $sampleId = $_POST['sample:id'];
         $existing = true;
         data_entry_helper::load_existing_record($auth['read'], 'sample', $sampleId);
     } else {
         if (isset($response['outer_id'])) {
             // have just posted a new sample.
             $sampleId = $response['outer_id'];
         } else {
             $sampleId = $_GET['sample_id'];
             $existing = true;
         }
     }
     $sample = data_entry_helper::get_population_data(array('table' => 'sample', 'extraParams' => $auth['read'] + array('view' => 'detail', 'id' => $sampleId, 'deleted' => 'f')));
     $sample = $sample[0];
     $date = $sample['date_start'];
     if (!function_exists('module_exists') || !module_exists('easy_login')) {
         // work out the CMS User sample ID.
         $sampleMethods = helper_base::get_termlist_terms($auth, 'indicia:sample_methods', array('Field Observation'));
         $attributes = data_entry_helper::getAttributes(array('valuetable' => 'sample_attribute_value', 'attrtable' => 'sample_attribute', 'key' => 'sample_id', 'fieldprefix' => 'smpAttr', 'extraParams' => $auth['read'], 'survey_id' => $args['survey_id'], 'sample_method_id' => $sampleMethods[0]['id']));
         if (false == ($cmsUserAttr = extract_cms_user_attr($attributes))) {
             return 'Easy Login not active: This form is designed to be used with the CMS User ID attribute setup for samples in the survey.';
         }
     }
     $allTaxonMeaningIdsAtSample = array();
     if ($existing) {
         // Only need to load the occurrences for a pre-existing sample
         $o = data_entry_helper::get_population_data(array('report' => 'reports_for_prebuilt_forms/UKBMS/ukbms_occurrences_list_for_sample', 'extraParams' => $auth['read'] + array('view' => 'detail', 'sample_id' => $sampleId, 'survey_id' => $args['survey_id'], 'date_from' => '', 'date_to' => '', 'taxon_group_id' => '', 'smpattrs' => '', 'occattrs' => $args['occurrence_attribute_ids']), 'nocache' => true));
         // build an array keyed for easy lookup
         $occurrences = array();
         $attrs = explode(',', $args['occurrence_attribute_ids']);
         if (!isset($o['error'])) {
             foreach ($o as $occurrence) {
                 if (!in_array($occurrence['taxon_meaning_id'], $allTaxonMeaningIdsAtSample)) {
                     $allTaxonMeaningIdsAtSample[] = $occurrence['taxon_meaning_id'];
                 }
                 $occurrences[$occurrence['taxon_meaning_id']] = array('ttl_id' => $occurrence['taxa_taxon_list_id'], 'ttl_id' => $occurrence['taxa_taxon_list_id'], 'preferred_ttl_id' => $occurrence['preferred_ttl_id'], 'o_id' => $occurrence['occurrence_id'], 'processed' => false);
                 foreach ($attrs as $attr) {
                     $occurrences[$occurrence['taxon_meaning_id']]['value_' . $attr] = $occurrence['attr_occurrence_' . $attr];
                     $occurrences[$occurrence['taxon_meaning_id']]['a_id_' . $attr] = $occurrence['attr_id_occurrence_' . $attr];
                 }
             }
         }
         // store it in data for JS to read when populating the grid
         data_entry_helper::$javascript .= "indiciaData.existingOccurrences = " . json_encode($occurrences) . ";\n";
     } else {
         data_entry_helper::$javascript .= "indiciaData.existingOccurrences = {};\n";
     }
     $occ_attributes = data_entry_helper::getAttributes(array('valuetable' => 'occurrence_attribute_value', 'attrtable' => 'occurrence_attribute', 'key' => 'occurrence_id', 'fieldprefix' => 'occAttr', 'extraParams' => $auth['read'], 'survey_id' => $args['survey_id'], 'multiValue' => false));
     data_entry_helper::$javascript .= "indiciaData.occurrence_totals = [];\n";
     data_entry_helper::$javascript .= "indiciaData.occurrence_attribute = [];\n";
     data_entry_helper::$javascript .= "indiciaData.occurrence_attribute_ctrl = [];\n";
     $defAttrOptions = array('extraParams' => $auth['read'] + array('orderby' => 'id'), 'suffixTemplate' => 'nosuffix');
     $occ_attributes_captions = array();
     foreach (explode(',', $args['occurrence_attribute_ids']) as $idx => $attr) {
         $occ_attributes_captions[$idx] = $occ_attributes[$attr]['caption'];
         unset($occ_attributes[$attr]['caption']);
         $ctrl = data_entry_helper::outputAttribute($occ_attributes[$attr], $defAttrOptions);
         data_entry_helper::$javascript .= "indiciaData.occurrence_totals[" . $idx . "] = [];\n";
         data_entry_helper::$javascript .= "indiciaData.occurrence_attribute[" . $idx . "] = {$attr};\n";
         data_entry_helper::$javascript .= "indiciaData.occurrence_attribute_ctrl[" . $idx . "] = jQuery('" . str_replace("\n", "", $ctrl) . "');\n";
     }
     //    $r = "<h2>".$location[0]['name']." on ".$date."</h2>\n";
     $r = '<div id="tabs">';
     $tabs = array('#grid1' => t($args['species_tab_1']));
     // tab 1 is required.
     if (isset($args['taxon_list_id_2']) && $args['taxon_list_id_2'] != '') {
         $tabs['#grid2'] = t(isset($args['species_tab_2']) && $args['species_tab_2'] != '' ? $args['species_tab_2'] : 'Species Tab 2');
     }
     if (isset($args['taxon_list_id_3']) && $args['taxon_list_id_3'] != '') {
         $tabs['#grid3'] = t(isset($args['species_tab_3']) && $args['species_tab_3'] != '' ? $args['species_tab_3'] : 'Species Tab 3');
     }
     if (isset($args['taxon_list_id_4']) && $args['taxon_list_id_4'] != '') {
         $tabs['#grid4'] = t(isset($args['species_tab_4']) && $args['species_tab_4'] != '' ? $args['species_tab_4'] : 'Species Tab 4');
     }
     $tabs['#notes'] = lang::get('Notes');
     $r .= data_entry_helper::tab_header(array('tabs' => $tabs));
     data_entry_helper::enable_tabs(array('divId' => 'tabs', 'style' => 'Tabs'));
     // will assume that first table is based on abundance count, so do totals
     $r .= '<div id="grid1"><table id="observation-input1" class="ui-widget species-grid"><thead class="table-header"><tr><th class="ui-widget-header"></th>';
     foreach (explode(',', $args['occurrence_attribute_ids']) as $idx => $attr) {
         $r .= '<th class="ui-widget-header col-' . ($idx + 1) . '">' . $occ_attributes_captions[$idx] . '</th>';
     }
     $r .= '<th class="ui-widget-header">' . lang::get('Total') . '</th></tr></thead>';
     $r .= '<tbody class="ui-widget-content occs-body"></tbody><tfoot><tr><td>Total</td>';
     foreach (explode(',', $args['occurrence_attribute_ids']) as $idx => $attr) {
         $r .= '<td class="col-' . ($idx + 1) . ' ' . ($idx % 5 == 0 ? 'first' : '') . ' col-total"></td>';
     }
     $r .= '<td class="ui-state-disabled first"></td></tr></tfoot></table><br /><a href="' . $args['my_obs_page'] . '" class="button">' . lang::get('Finish') . '</a></div>';
     $extraParams = array_merge($auth['read'], array('taxon_list_id' => $args['taxon_list_id_1'], 'preferred' => 't', 'allow_data_entry' => 't', 'view' => 'cache', 'orderby' => 'taxonomic_sort_order'));
     if (!empty($args['taxon_filter_field_1']) && !empty($args['taxon_filter_1'])) {
         $extraParams[$args['taxon_filter_field_1']] = helper_base::explode_lines($args['taxon_filter_1']);
     }
     $taxa = data_entry_helper::get_population_data(array('table' => 'taxa_taxon_list', 'extraParams' => $extraParams));
     data_entry_helper::$javascript .= "indiciaData.speciesList1List = [";
     $first = true;
     foreach ($taxa as $taxon) {
         data_entry_helper::$javascript .= ($first ? "\n" : ",\n") . "{'id':" . $taxon['id'] . ",'taxon_meaning_id':" . $taxon['taxon_meaning_id'] . ",'preferred_language_iso':'" . $taxon["preferred_language_iso"] . "','default_common_name':'" . str_replace("'", "\\'", $taxon["default_common_name"]) . "'}";
         $first = false;
     }
     data_entry_helper::$javascript .= "];\n";
     data_entry_helper::$javascript .= "indiciaData.allTaxonMeaningIdsAtSample = [" . implode(',', $allTaxonMeaningIdsAtSample) . "];\n";
     if (isset($args['taxon_list_id_2']) && $args['taxon_list_id_2'] != '') {
         $r .= '<div id="grid2"><p id="grid2-loading">' . lang::get('Loading - Please Wait') . '</p><table id="observation-input2" class="ui-widget species-grid"><thead class="table-header"><tr><th class="ui-widget-header"></th>';
         foreach (explode(',', $args['occurrence_attribute_ids']) as $idx => $attr) {
             $r .= '<th class="ui-widget-header col-' . ($idx + 1) . '">' . $occ_attributes_captions[$idx] . '</th>';
         }
         $r .= '<th class="ui-widget-header">' . lang::get('Total') . '</th></tr></thead><tbody class="ui-widget-content occs-body"></tbody><tfoot><tr><td>Total</td>';
         foreach (explode(',', $args['occurrence_attribute_ids']) as $idx => $attr) {
             $r .= '<td class="col-' . ($idx + 1) . ' ' . ($idx % 5 == 0 ? 'first' : '') . ' col-total"></td>';
         }
         $r .= '<td class="ui-state-disabled first"></td></tr></tfoot></table><br /><a href="' . $args['my_obs_page'] . '" class="button">' . lang::get('Finish') . '</a></div>';
     }
     if (isset($args['taxon_list_id_3']) && $args['taxon_list_id_3'] != '') {
         $r .= '<div id="grid3"><p id="grid3-loading">' . lang::get('Loading - Please Wait') . '</p><table id="observation-input3" class="ui-widget species-grid"><thead class="table-header"><tr><th class="ui-widget-header"></th>';
         foreach (explode(',', $args['occurrence_attribute_ids']) as $idx => $attr) {
             $r .= '<th class="ui-widget-header col-' . ($idx + 1) . '">' . $occ_attributes_captions[$idx] . '</th>';
         }
         $r .= '<th class="ui-widget-header">' . lang::get('Total') . '</th></tr></thead><tbody class="ui-widget-content occs-body"></tbody><tfoot><tr><td>Total</td>';
         foreach (explode(',', $args['occurrence_attribute_ids']) as $idx => $attr) {
             $r .= '<td class="col-' . ($idx + 1) . ' ' . ($idx % 5 == 0 ? 'first' : '') . ' col-total"></td>';
         }
         $r .= '<td class="ui-state-disabled first"></td></tr></tfoot></table><br /><a href="' . $args['my_obs_page'] . '" class="button">' . lang::get('Finish') . '</a></div>';
     }
     if (isset($args['taxon_list_id_4']) && $args['taxon_list_id_4'] != '') {
         $r .= '<div id="grid4"><p id="grid4-loading">' . lang::get('Loading - Please Wait') . '</p><table id="observation-input4" class="ui-widget species-grid"><thead class="table-header"><tr><th class="ui-widget-header"></th>';
         foreach (explode(',', $args['occurrence_attribute_ids']) as $idx => $attr) {
             $r .= '<th class="ui-widget-header col-' . ($idx + 1) . '">' . $occ_attributes_captions[$idx] . '</th>';
         }
         $r .= '<th class="ui-widget-header">' . lang::get('Total') . '</th></tr></thead><tbody class="ui-widget-content occs-body"></tbody><tfoot><tr><td>Total</td>';
         foreach (explode(',', $args['occurrence_attribute_ids']) as $idx => $attr) {
             $r .= '<td class="col-' . ($idx + 1) . ' ' . ($idx % 5 == 0 ? 'first' : '') . ' col-total"></td>';
         }
         $r .= '<td class="ui-state-disabled first"></td></tr></tfoot></table>';
         $r .= '<label for="taxonLookupControl4" class="auto-width">' . lang::get('Add species to list') . ':</label> <input id="taxonLookupControl4" name="taxonLookupControl4" >';
         $r .= '<br /><a href="' . $args['my_obs_page'] . '" class="button">' . lang::get('Finish') . '</a></div>';
     }
     // for the comment form, we want to ensure that if there is a timeout error that it reloads the
     // data as stored in the DB.
     $reload = data_entry_helper::get_reload_link_parts();
     $reload['params']['sample_id'] = $parentSampleId;
     unset($reload['params']['new']);
     $reloadPath = $reload['path'];
     if (count($reload['params'])) {
         // decode params prior to encoding to prevent double encoding.
         foreach ($reload['params'] as $key => $param) {
             $reload['params'][$key] = urldecode($param);
         }
         $reloadPath .= '?' . http_build_query($reload['params']);
     }
     // fragment is always at the end. discard this.
     $reloadPath = explode('#', $reloadPath, 2);
     $reloadPath = $reloadPath[0];
     $r .= "<div id=\"notes\"><form method=\"post\" id=\"notes_form\" action=\"" . $reloadPath . "#notes\">\n";
     $r .= $auth['write'];
     $r .= '<input type="hidden" name="sample:id" value="' . $sampleId . '" />' . '<input type="hidden" name="website_id" value="' . $args['website_id'] . '"/>' . '<input type="hidden" name="survey_id" value="' . $args['survey_id'] . '"/>' . '<input type="hidden" name="page" value="notes"/>';
     $r .= '<p class="page-notice ui-state-highlight ui-corner-all">' . lang::get('When using this page, please remember that the data is not saved to the database as you go (which is the case for the previous tabs). In order to save the data entered in this page you must click on the Submit button at the bottom of the page.') . '</p>';
     $r .= data_entry_helper::textarea(array('fieldname' => 'sample:comment', 'label' => lang::get('Notes'), 'helpText' => "Use this space to input comments about this week's walk."));
     $r .= '<input type="submit" value="' . lang::get('Submit') . '" id="save-button"/></form>';
     $r .= '<br /><a href="' . $args['my_walks_page'] . '" class="button">' . lang::get('Finish') . '</a></div></div>';
     // enable validation on the comments form in order to include the simplified ajax queuing for the autocomplete.
     data_entry_helper::enable_validation('notes_form');
     // A stub form for AJAX posting when we need to create an occurrence
     $r .= '<form style="display: none" id="occ-form" method="post" action="' . iform_ajaxproxy_url($node, 'occurrence') . '">';
     $r .= '<input name="website_id" value="' . $args['website_id'] . '"/>';
     $r .= '<input name="occurrence:id" id="occid" />';
     $r .= '<input name="occurrence:taxa_taxon_list_id" id="ttlid" />';
     $r .= '<input name="occurrence:sample_id" value="' . $sampleId . '"/>';
     $r .= '<input name="occAttr:" id="occattr"/>';
     $r .= '<input name="transaction_id" id="transaction_id"/>';
     $r .= '<input name="user_id" value="' . hostsite_get_user_field('user_id', 1) . '"/>';
     $r .= '</form>';
     // tell the Javascript where to get species from.
     data_entry_helper::add_resource('jquery_ui');
     data_entry_helper::add_resource('json');
     data_entry_helper::add_resource('autocomplete');
     data_entry_helper::$javascript .= "indiciaData.speciesList1 = " . $args['taxon_list_id_1'] . ";\n";
     if (!empty($args['taxon_filter_field_1']) && !empty($args['taxon_filter_1'])) {
         data_entry_helper::$javascript .= "indiciaData.speciesList1FilterField = '" . $args['taxon_filter_field_1'] . "';\n";
         $filterLines = helper_base::explode_lines($args['taxon_filter_1']);
         data_entry_helper::$javascript .= "indiciaData.speciesList1FilterValues = '" . json_encode($filterLines) . "';\n";
     }
     data_entry_helper::$javascript .= "indiciaData.speciesList2 = " . (isset($args['taxon_list_id_2']) && $args['taxon_list_id_2'] != "" ? $args['taxon_list_id_2'] : "-1") . ";\n";
     if (!empty($args['taxon_filter_field_2']) && !empty($args['taxon_filter_2'])) {
         data_entry_helper::$javascript .= "indiciaData.speciesList2FilterField = '" . $args['taxon_filter_field_2'] . "';\n";
         $filterLines = helper_base::explode_lines($args['taxon_filter_2']);
         data_entry_helper::$javascript .= "indiciaData.speciesList2FilterValues = " . json_encode($filterLines) . ";\n";
     }
     data_entry_helper::$javascript .= "indiciaData.speciesList3 = " . (isset($args['taxon_list_id_3']) && $args['taxon_list_id_3'] != "" ? $args['taxon_list_id_3'] : "-1") . ";\n";
     if (!empty($args['taxon_filter_field_3']) && !empty($args['taxon_filter_3'])) {
         data_entry_helper::$javascript .= "indiciaData.speciesList3FilterField = '" . $args['taxon_filter_field_3'] . "';\n";
         $filterLines = helper_base::explode_lines($args['taxon_filter_3']);
         data_entry_helper::$javascript .= "indiciaData.speciesList3FilterValues = " . json_encode($filterLines) . ";\n";
     }
     data_entry_helper::$javascript .= "indiciaData.speciesList4 = " . (isset($args['taxon_list_id_4']) && $args['taxon_list_id_4'] != "" ? $args['taxon_list_id_4'] : "-1") . ";\n";
     if (!empty($args['taxon_filter_field_4']) && !empty($args['taxon_filter_4'])) {
         data_entry_helper::$javascript .= "indiciaData.speciesList4FilterField = '" . $args['taxon_filter_field_4'] . "';\n";
         $filterLines = helper_base::explode_lines($args['taxon_filter_4']);
         data_entry_helper::$javascript .= "indiciaData.speciesList4FilterValues = " . json_encode($filterLines) . ";\n";
     }
     // allow js to do AJAX by passing in the information it needs to post forms
     data_entry_helper::$javascript .= "bindSpeciesAutocomplete(\"taxonLookupControl4\",\"table#observation-input4\",\"" . data_entry_helper::$base_url . "index.php/services/data\", indiciaData.speciesList4,\n  indiciaData.speciesList4FilterField, indiciaData.speciesList4FilterValues, {\"auth_token\" : \"" . $auth['read']['auth_token'] . "\", \"nonce\" : \"" . $auth['read']['nonce'] . "\"},\n  \"" . lang::get('LANG_Duplicate_Taxon') . "\", 25, 4);\n\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.sample = " . $sampleId . ";\n";
     if (function_exists('module_exists') && module_exists('easy_login')) {
         data_entry_helper::$javascript .= "indiciaData.easyLogin = true;\n";
         $userId = hostsite_get_user_field('indicia_user_id');
         if (!empty($userId)) {
             data_entry_helper::$javascript .= "indiciaData.UserID = " . $userId . ";\n";
         } else {
             return '<p>Easy Login active but could not identify user</p>';
         }
         // something is wrong
     } else {
         data_entry_helper::$javascript .= "indiciaData.easyLogin = false;\n";
         data_entry_helper::$javascript .= "indiciaData.CMSUserAttrID = " . $cmsUserAttr['attributeId'] . ";\n";
         data_entry_helper::$javascript .= "indiciaData.CMSUserID = " . $user->uid . ";\n";
     }
     // Do an AJAX population of the grid rows.
     data_entry_helper::$javascript .= "loadSpeciesList();\njQuery('#tabs').bind('tabsshow', function(event, ui) {\n    var target = ui.panel;\n    // first get rid of any previous tables\n    jQuery('table.sticky-header').remove();\n    jQuery('table.sticky-enabled thead.tableHeader-processed').removeClass('tableHeader-processed');\n    jQuery('table.sticky-enabled.tableheader-processed').removeClass('tableheader-processed');\n    jQuery('table.species-grid.sticky-enabled').removeClass('sticky-enabled');\n    var table = jQuery('#'+target.id+' table.species-grid');\n    if(table.length > 0) {\n        table.addClass('sticky-enabled');\n        if(typeof Drupal.behaviors.tableHeader == 'object') // Drupal 7\n          Drupal.behaviors.tableHeader.attach(table.parent());\n        else // Drupal6 : it is a function\n          Drupal.behaviors.tableHeader(target);\n    }\n    // remove any hanging autocomplete select list.\n    jQuery('.ac_results').hide();\n});";
     return $r;
 }
Пример #21
0
   /**
    * Return the generated form output.
    * @return Form HTML.
    */
   public static function get_form($args, $node)
   {
       define("MODE_GRID", 0);
       define("MODE_NEW_SAMPLE", 1);
       define("MODE_EXISTING", 2);
       self::parse_defaults($args);
       self::getArgDefaults($args);
       global $user;
       $logged_in = $user->uid > 0;
       $r = '';
       // Get authorisation tokens to update and read from the Warehouse.
       $auth = data_entry_helper::get_read_write_auth($args['website_id'], $args['password']);
       $svcUrl = data_entry_helper::$base_url . '/index.php/services';
       self::$auth = $auth;
       $mode = isset($args['no_grid']) && $args['no_grid'] ? MODE_NEW_SAMPLE : MODE_GRID;
       // default mode when no grid set to false - display grid of existing data
       // mode MODE_EXISTING: display existing sample
       $loadedSampleId = null;
       $loadedOccurrenceId = null;
       if ($_POST) {
           if (!array_key_exists('website_id', $_POST)) {
               // non Indicia POST, in this case must be the location allocations. add check to ensure we don't corrept the data by accident
               if (iform_loctools_checkaccess($node, 'admin') && array_key_exists('mnhnld1', $_POST)) {
                   iform_loctools_deletelocations($node);
                   foreach ($_POST as $key => $value) {
                       $parts = explode(':', $key);
                       iform_loctools_insertlocation($node, $parts[2], $parts[1]);
                   }
               }
           } else {
               if (!is_null(data_entry_helper::$entity_to_load)) {
                   $mode = MODE_EXISTING;
                   // errors with new sample, entity populated with post, so display this data.
               }
           }
           // else valid save, so go back to gridview: default mode 0
       }
       if (array_key_exists('sample_id', $_GET)) {
           $mode = MODE_EXISTING;
           $loadedSampleId = $_GET['sample_id'];
       }
       if (array_key_exists('occurrence_id', $_GET)) {
           $mode = MODE_EXISTING;
           $loadedOccurrenceId = $_GET['occurrence_id'];
       }
       if ($mode != MODE_EXISTING && array_key_exists('newSample', $_GET)) {
           $mode = MODE_NEW_SAMPLE;
           data_entry_helper::$entity_to_load = array();
       }
       // else default to mode MODE_GRID or MODE_NEW_SAMPLE depending on no_grid parameter
       self::$mode = $mode;
       // default mode  MODE_GRID : display grid of the samples to add a new one
       // or edit an existing one.
       if ($mode == MODE_GRID) {
           $attributes = data_entry_helper::getAttributes(array('valuetable' => 'sample_attribute_value', 'attrtable' => 'sample_attribute', 'key' => 'sample_id', 'fieldprefix' => 'smpAttr', 'extraParams' => $auth['read'], 'survey_id' => $args['survey_id']));
           $tabs = array('#sampleList' => lang::get('LANG_Main_Samples_Tab'));
           if ($args['includeLocTools'] && iform_loctools_checkaccess($node, 'admin')) {
               $tabs['#setLocations'] = lang::get('LANG_Allocate_Locations');
           }
           if (count($tabs) > 1) {
               $r .= "<div id=\"controls\">" . data_entry_helper::enable_tabs(array('divId' => 'controls', 'active' => '#sampleList')) . "<div id=\"temp\"></div>";
               $r .= data_entry_helper::tab_header(array('tabs' => $tabs));
           }
           $r .= "<div id=\"sampleList\">" . self::getSampleListGrid($args, $node, $auth, $attributes) . "</div>";
           if ($args['includeLocTools'] && iform_loctools_checkaccess($node, 'admin')) {
               $r .= '
 <div id="setLocations">
   <form method="post">
     <input type="hidden" id="mnhnld1" name="mnhnld1" value="mnhnld1" /><table border="1"><tr><td></td>';
               $url = $svcUrl . '/data/location?mode=json&view=detail&auth_token=' . $auth['read']['auth_token'] . "&nonce=" . $auth['read']["nonce"] . "&parent_id=NULL&orderby=name";
               $session = curl_init($url);
               curl_setopt($session, CURLOPT_RETURNTRANSFER, true);
               $entities = json_decode(curl_exec($session), true);
               $userlist = iform_loctools_listusers($node);
               foreach ($userlist as $uid => $a_user) {
                   $r .= '<td>' . $a_user->name . '</td>';
               }
               $r .= "</tr>";
               if (!empty($entities)) {
                   foreach ($entities as $entity) {
                       if (!$entity["parent_id"]) {
                           // only assign parent locations.
                           $r .= "<tr><td>" . $entity["name"] . "</td>";
                           $defaultuserids = iform_loctools_getusers($node, $entity["id"]);
                           foreach ($userlist as $uid => $a_user) {
                               $r .= '<td><input type="checkbox" name="location:' . $entity["id"] . ':' . $uid . (in_array($uid, $defaultuserids) ? '" checked="checked"' : '"') . '></td>';
                           }
                           $r .= "</tr>";
                       }
                   }
               }
               $r .= "</table>\n      <input type=\"submit\" class=\"ui-state-default ui-corner-all\" value=\"" . lang::get('LANG_Save_Location_Allocations') . "\" />\n    </form>\n  </div>";
           }
           if (count($tabs) > 1) {
               // close tabs div if present
               $r .= "</div>";
           }
           return $r;
       }
       if ($mode == MODE_EXISTING) {
           data_entry_helper::$entity_to_load = array();
           // Displaying an existing sample. If we know the occurrence ID, and don't know the sample ID or are displaying just one occurrence
           // rather than a grid of occurrences then we must load the occurrence data.
           if ($loadedOccurrenceId && (!$loadedSampleId || !self::getGridMode($args))) {
               // The URL has provided us with an occurrence ID, but we need to know the sample ID as well.
               $url = $svcUrl . "/data/occurrence/{$loadedOccurrenceId}";
               $url .= "?mode=json&view=detail&auth_token=" . $auth['read']['auth_token'] . "&nonce=" . $auth['read']["nonce"];
               $session = curl_init($url);
               curl_setopt($session, CURLOPT_RETURNTRANSFER, true);
               $entity = json_decode(curl_exec($session), true);
               // Get the sample ID for the occurrence. This overwrites it if supply in GET but did not match the occurrence's sample
               $loadedSampleId = $entity[0]['sample_id'];
               if (!self::getGridMode($args)) {
                   // populate the entity to load with the single occurrence's data
                   foreach ($entity[0] as $key => $value) {
                       data_entry_helper::$entity_to_load['occurrence:' . $key] = $value;
                   }
               }
           }
           if ($loadedSampleId) {
               $url = $svcUrl . '/data/sample/' . $loadedSampleId;
               $url .= "?mode=json&view=detail&auth_token=" . $auth['read']['auth_token'] . "&nonce=" . $auth['read']["nonce"];
               $session = curl_init($url);
               curl_setopt($session, CURLOPT_RETURNTRANSFER, true);
               $entity = json_decode(curl_exec($session), true);
               // Build a list of the sample data.
               foreach ($entity[0] as $key => $value) {
                   data_entry_helper::$entity_to_load['sample:' . $key] = $value;
               }
               data_entry_helper::$entity_to_load['sample:geom'] = '';
               // value received from db is not WKT, which is assumed by all the code.
               data_entry_helper::$entity_to_load['sample:date'] = data_entry_helper::$entity_to_load['sample:date_start'];
               // bit of a bodge to get around vague dates.
           }
       }
       // atributes must be fetched after the entity to load is filled in - this is because the id gets filled in then!
       $attributes = data_entry_helper::getAttributes(array('id' => data_entry_helper::$entity_to_load['sample:id'], 'valuetable' => 'sample_attribute_value', 'attrtable' => 'sample_attribute', 'key' => 'sample_id', 'fieldprefix' => 'smpAttr', 'extraParams' => $auth['read'], 'survey_id' => $args['survey_id']));
       // Make sure the form action points back to this page
       $reload = data_entry_helper::get_reload_link_parts();
       $reloadPath = $reload['path'];
       $r = "<form method=\"post\" id=\"entry_form\" action=\"{$reloadPath}\">\n";
       // Get authorisation tokens to update the Warehouse, plus any other hidden data.
       $hiddens = $auth['write'] . "<input type=\"hidden\" id=\"website_id\" name=\"website_id\" value=\"" . $args['website_id'] . "\" />\n" . "<input type=\"hidden\" id=\"survey_id\" name=\"survey_id\" value=\"" . $args['survey_id'] . "\" />\n";
       if (isset(data_entry_helper::$entity_to_load['sample:id'])) {
           $hiddens .= "<input type=\"hidden\" id=\"sample:id\" name=\"sample:id\" value=\"" . data_entry_helper::$entity_to_load['sample:id'] . "\" />\n";
       }
       if (isset(data_entry_helper::$entity_to_load['occurrence:id'])) {
           $hiddens .= "<input type=\"hidden\" id=\"occurrence:id\" name=\"occurrence:id\" value=\"" . data_entry_helper::$entity_to_load['occurrence:id'] . "\" />\n";
       }
       // Check if Record Status is included as a control. If not, then add it as a hidden.
       $arr = explode("\r\n", $args['structure']);
       if (!in_array('[record status]', $arr)) {
           $value = isset($args['defaults']['occurrence:record_status']) ? $args['defaults']['occurrence:record_status'] : 'C';
           $hiddens .= "<input type=\"hidden\" id=\"occurrence:record_status\" name=\"occurrence:record_status\" value=\"{$value}\" />\n";
       }
       // request automatic JS validation
       if (!isset($args['clientSideValidation']) || $args['clientSideValidation']) {
           data_entry_helper::enable_validation('entry_form');
       }
       // If logged in, output some hidden data about the user
       foreach ($attributes as &$attribute) {
           if (strcasecmp($attribute['caption'], 'cms user id') == 0) {
               if ($logged_in) {
                   $attribute['value'] = $user->uid;
               }
               $attribute['handled'] = true;
               // user id attribute is never displayed
           } elseif (strcasecmp($attribute['caption'], 'cms username') == 0) {
               if ($logged_in) {
                   $attribute['value'] = $user->name;
               }
               $attribute['handled'] = true;
               // username attribute is never displayed
           } elseif (strcasecmp($attribute['caption'], 'email') == 0) {
               if ($logged_in) {
                   if ($args['emailShow'] != true) {
                       // email attribute is not displayed
                       $attribute['value'] = $user->mail;
                       $attribute['handled'] = true;
                   } else {
                       $attribute['default'] = $user->mail;
                   }
               }
           } elseif ((strcasecmp($attribute['caption'], 'first name') == 0 || strcasecmp($attribute['caption'], 'last name') == 0 || strcasecmp($attribute['caption'], 'surname') == 0) && $logged_in) {
               if ($args['nameShow'] != true) {
                   // name attributes are not displayed
                   $attribute['handled'] = true;
               }
           }
           if (isset($attribute['value'])) {
               $hiddens .= '<input type="hidden" name="' . $attribute['fieldname'] . '" value="' . $attribute['value'] . '" />' . "\n";
           }
       }
       $customAttributeTabs = self::get_attribute_tabs($attributes);
       $tabs = self::get_all_tabs($args['structure'], $customAttributeTabs);
       $r .= "<div id=\"controls\">\n";
       // Build a list of the tabs that actually have content
       $tabHtml = self::get_tab_html($tabs, $auth, $args, $attributes, $hiddens);
       // Output the dynamic tab headers
       if ($args['interface'] != 'one_page') {
           $headerOptions = array('tabs' => array());
           foreach ($tabHtml as $tab => $tabContent) {
               $alias = preg_replace('/[^a-zA-Z0-9]/', '', strtolower($tab));
               $tabtitle = lang::get("LANG_Tab_{$alias}");
               if ($tabtitle == "LANG_Tab_{$alias}") {
                   // if no translation provided, we'll just use the standard heading
                   $tabtitle = $tab;
               }
               $headerOptions['tabs']['#' . $alias] = $tabtitle;
           }
           $r .= data_entry_helper::tab_header($headerOptions);
           data_entry_helper::enable_tabs(array('divId' => 'controls', 'style' => $args['interface'], 'progressBar' => isset($args['tabProgress']) && $args['tabProgress'] == true));
       }
       // Output the dynamic tab content
       $pageIdx = 0;
       foreach ($tabHtml as $tab => $tabContent) {
           // get a machine readable alias for the heading
           $tabalias = preg_replace('/[^a-zA-Z0-9]/', '', strtolower($tab));
           $r .= '<div id="' . $tabalias . '">' . "\n";
           // For wizard include the tab title as a header.
           if ($args['interface'] == 'wizard') {
               $r .= '<h1>' . $headerOptions['tabs']['#' . $tabalias] . '</h1>';
           }
           $r .= $tabContent;
           // Add any buttons required at the bottom of the tab
           if ($args['interface'] == 'wizard') {
               $r .= data_entry_helper::wizard_buttons(array('divId' => 'controls', 'page' => $pageIdx === 0 ? 'first' : ($pageIdx == count($tabs) - 1 ? 'last' : 'middle')));
           } elseif ($pageIdx == count($tabs) - 1 && !($args['interface'] == 'tabs' && $args['save_button_below_all_pages'])) {
               // last part of a non wizard interface must insert a save button, unless it is tabbed interface with save button beneath all pages
               $r .= "<input type=\"submit\" class=\"ui-state-default ui-corner-all\" value=\"" . lang::get('LANG_Save') . "\" />\n";
           }
           $pageIdx++;
           $r .= "</div>\n";
       }
       $r .= "</div>\n";
       if ($args['interface'] == 'tabs' && $args['save_button_below_all_pages']) {
           $r .= "<input type=\"submit\" class=\"ui-state-default ui-corner-all\" value=\"" . lang::get('LANG_Save') . "\" />\n";
       }
       if (!empty(data_entry_helper::$validation_errors)) {
           $r .= data_entry_helper::dump_remaining_errors();
       }
       $r .= "</form>";
       // may need to keep following code for location change functionality
       // @todo Why is this not in the data entry helper, and is it really needed?
       if (self::$want_location_layer) {
           data_entry_helper::$onload_javascript .= "\n    \nlocationChange = function(obj){\n  locationLayer.destroyFeatures();\n  if(obj.value != ''){\n    jQuery.getJSON(\"" . $svcUrl . "\" + \"/data/location/\"+obj.value +\n      \"?mode=json&view=detail&auth_token=" . $auth['read']['auth_token'] . "&nonce=" . $auth['read']["nonce"] . "\" +\n      \"&callback=?\", function(data) {\n        if (data.length>0) {\n          var parser = new OpenLayers.Format.WKT();\n          for (var i=0;i<data.length;i++) {\n            if(data[i].centroid_geom){\n              feature = parser.read(data[i].centroid_geom);\n              centre = feature.geometry.getCentroid();\n              centrefeature = new OpenLayers.Feature.Vector(centre, {}, {label: data[i].name});\n              locationLayer.addFeatures([feature, centrefeature]); \n            }\n            if (data[i].boundary_geom){\n              feature = parser.read(data[i].boundary_geom);\n              feature.style = {strokeColor: \"Blue\",\n                  strokeWidth: 2,\n                  label: (data[i].centroid_geom ? \"\" : data[i].name)};\n                  locationLayer.addFeatures([feature]);\n            }\n          }\n          var extent=locationLayer.getDataExtent();\n          if (extent!==null) {\n            locationLayer.map.zoomToExtent(extent);\n          }\n        }\n\t\t  }\n    );\n  }\n};\njQuery('#imp-location').unbind('change');\njQuery('#imp-location').change(function(){\n\tlocationChange(this);\n});\n\nvar updatePlaceTabHandler = function(event, ui) { \n  if (ui.panel.id=='place') {\n    // upload location & sref initial values into map.\n    jQuery('#imp-location').change();\n    jQuery('#imp-sref').change();\n    jQuery('#controls').unbind('tabsshow', updatePlaceTabHandler);\n  }\n}\njQuery('#controls').bind('tabsshow', updatePlaceTabHandler);\n\n";
       }
       $r .= self::link_species_popups($args);
       return $r;
   }
   /**
    * Return the generated form output.
    * @return Form HTML.
    */
   public static function get_form($args, $node)
   {
       define("MODE_GRID", 0);
       define("MODE_NEW_SAMPLE", 1);
       define("MODE_EXISTING", 2);
       self::parse_defaults($args);
       self::getArgDefaults($args);
       self::$node = $node;
       // if we use locks, we want them to be distinct for each drupal user
       if (function_exists('profile_load_profile')) {
           // check we are in drupal
           global $user;
           data_entry_helper::$javascript .= "if (indicia && indicia.locks && indicia.locks.setUser) {\n        indicia.locks.setUser ('" . $user->uid . "');\n      }\n";
       }
       // hard-wire some 'dynamic' options to simplify the form. Todo: take out the dynamic code for these
       $args['subjectAccordion'] = false;
       $args['emailShow'] = false;
       $args['nameShow'] = false;
       $args['copyFromProfile'] = false;
       $args['multiple_subject_observation_mode'] = 'single';
       $args['extra_list_id'] = '';
       $args['occurrence_comment'] = false;
       $args['col_widths'] = '';
       $args['includeLocTools'] = false;
       $args['loctoolsLocTypeID'] = 0;
       $args['subject_observation_confidential'] = false;
       $args['observation_images'] = false;
       // Get authorisation tokens to update and read from the Warehouse.
       $auth = data_entry_helper::get_read_write_auth($args['website_id'], $args['password']);
       $svcUrl = self::warehouseUrl() . 'index.php/services';
       self::$auth = $auth;
       drupal_add_js(iform_media_folder_path() . 'js/jquery.form.js', 'module');
       $mode = isset($args['no_grid']) && $args['no_grid'] ? MODE_NEW_SAMPLE : MODE_GRID;
       // default mode when no grid set to false - display grid of existing data
       // mode MODE_EXISTING: display existing sample
       $loadedSampleId = null;
       $loadedSubjectObservationId = null;
       if ($_POST) {
           if (!array_key_exists('website_id', $_POST)) {
               // non Indicia POST, in this case must be the location allocations. add check to ensure we don't corrept the data by accident
               if (function_exists('iform_loctools_checkaccess') && iform_loctools_checkaccess($node, 'admin') && array_key_exists('mnhnld1', $_POST)) {
                   iform_loctools_deletelocations($node);
                   foreach ($_POST as $key => $value) {
                       $parts = explode(':', $key);
                       iform_loctools_insertlocation($node, $parts[2], $parts[1]);
                   }
               }
           } else {
               if (!is_null(data_entry_helper::$entity_to_load)) {
                   $mode = MODE_EXISTING;
                   // errors with new sample, entity populated with post, so display this data.
               }
           }
           // else valid save, so go back to gridview: default mode 0
       }
       if (array_key_exists('sample_id', $_GET) && $_GET['sample_id'] != '{sample_id}') {
           $mode = MODE_EXISTING;
           $loadedSampleId = $_GET['sample_id'];
       }
       if (array_key_exists('subject_observation_id', $_GET) && $_GET['subject_observation_id'] != '{subject_observation_id}') {
           $mode = MODE_EXISTING;
           // single subject_observation case
           $loadedSubjectObservationId = $_GET['subject_observation_id'];
           self::$subjectObservationIds = array($loadedSubjectObservationId);
       }
       if ($mode != MODE_EXISTING && array_key_exists('newSample', $_GET)) {
           $mode = MODE_NEW_SAMPLE;
           data_entry_helper::$entity_to_load = array();
       }
       // else default to mode MODE_GRID or MODE_NEW_SAMPLE depending on no_grid parameter
       self::$mode = $mode;
       // default mode  MODE_GRID : display grid of the samples to add a new one
       // or edit an existing one.
       if ($mode == MODE_GRID) {
           $r = '';
           // debug section
           if (!empty($args['debug_info']) && $args['debug_info']) {
               $r .= '<input type="button" value="Debug info" onclick="$(\'#debug-info-div\').slideToggle();" /><br />' . '<div id="debug-info-div" style="display: none;">';
               $r .= '<p>$_GET is:<br /><pre>' . print_r($_GET, true) . '</pre></p>';
               $r .= '<p>$_POST is:<br /><pre>' . print_r($_POST, true) . '</pre></p>';
               $r .= '<p>Entity to load is:<br /><pre>' . print_r(data_entry_helper::$entity_to_load, true) . '</pre></p>';
               $r .= '<p>Submission was:<br /><pre>' . print_r(self::$submission, true) . '</pre></p>';
               $r .= '<input type="button" value="Hide debug info" onclick="$(\'#debug-info-div\').slideToggle();" />';
               $r .= '</div>';
           }
           if (method_exists(get_called_class(), 'getHeaderHTML')) {
               $r .= call_user_func(array(get_called_class(), 'getHeaderHTML'), true, $args);
           }
           $attributes = data_entry_helper::getAttributes(array('valuetable' => 'sample_attribute_value', 'attrtable' => 'sample_attribute', 'key' => 'sample_id', 'fieldprefix' => 'smpAttr', 'extraParams' => $auth['read'], 'survey_id' => $args['survey_id']), false);
           $tabs = array('#sampleList' => lang::get('LANG_Main_Samples_Tab'));
           if ($args['includeLocTools'] && function_exists('iform_loctools_checkaccess') && iform_loctools_checkaccess($node, 'admin')) {
               $tabs['#setLocations'] = lang::get('LANG_Allocate_Locations');
           }
           if (method_exists(get_called_class(), 'getExtraGridModeTabs')) {
               $extraTabs = call_user_func(array(get_called_class(), 'getExtraGridModeTabs'), false, $auth['read'], $args, $attributes);
               if (is_array($extraTabs)) {
                   $tabs = $tabs + $extraTabs;
               }
           }
           if (count($tabs) > 1) {
               $r .= "<div id=\"controls\">" . data_entry_helper::enable_tabs(array('divId' => 'controls', 'active' => '#sampleList')) . "<div id=\"temp\"></div>";
               $r .= data_entry_helper::tab_header(array('tabs' => $tabs));
           }
           $r .= "<div id=\"sampleList\">" . call_user_func(array(get_called_class(), 'getSampleListGrid'), $args, $node, $auth, $attributes) . "</div>";
           if ($args['includeLocTools'] && function_exists('iform_loctools_checkaccess') && iform_loctools_checkaccess($node, 'admin')) {
               $r .= '
 <div id="setLocations">
   <form method="post">
     <input type="hidden" id="mnhnld1" name="mnhnld1" value="mnhnld1" /><table border="1"><tr><td></td>';
               $url = $svcUrl . '/data/location?mode=json&view=detail&auth_token=' . $auth['read']['auth_token'] . "&nonce=" . $auth['read']["nonce"] . "&parent_id=NULL&orderby=name" . (isset($args['loctoolsLocTypeID']) && $args['loctoolsLocTypeID'] != '' ? '&location_type_id=' . $args['loctoolsLocTypeID'] : '');
               $session = curl_init($url);
               curl_setopt($session, CURLOPT_RETURNTRANSFER, true);
               $entities = json_decode(curl_exec($session), true);
               $userlist = iform_loctools_listusers($node);
               foreach ($userlist as $uid => $a_user) {
                   $r .= '<td>' . $a_user->name . '</td>';
               }
               $r .= "</tr>";
               if (!empty($entities)) {
                   foreach ($entities as $entity) {
                       if (!$entity["parent_id"]) {
                           // only assign parent locations.
                           $r .= "<tr><td>" . $entity["name"] . "</td>";
                           $defaultuserids = iform_loctools_getusers($node, $entity["id"]);
                           foreach ($userlist as $uid => $a_user) {
                               $r .= '<td><input type="checkbox" name="location:' . $entity["id"] . ':' . $uid . (in_array($uid, $defaultuserids) ? '" checked="checked"' : '"') . '></td>';
                           }
                           $r .= "</tr>";
                       }
                   }
               }
               $r .= "</table>\n      <input type=\"submit\" class=\"ui-state-default ui-corner-all\" value=\"" . lang::get('LANG_Save_Location_Allocations') . "\" />\n    </form>\n  </div>";
           }
           if (method_exists(get_called_class(), 'getExtraGridModeTabs')) {
               $r .= call_user_func(array(get_called_class(), 'getExtraGridModeTabs'), true, $auth['read'], $args, $attributes);
           }
           if (count($tabs) > 1) {
               // close tabs div if present
               $r .= "</div>";
           }
           if (method_exists(get_called_class(), 'getTrailerHTML')) {
               $r .= call_user_func(array(get_called_class(), 'getTrailerHTML'), true, $args);
           }
           return $r;
       }
       // from this point on, we are MODE_EXISTING or MODE_NEW_SAMPLE
       if ($mode == MODE_EXISTING && is_null(data_entry_helper::$entity_to_load)) {
           // only load if not in error situation
           // Displaying an existing sample. If we know the subject_observation ID, and don't know the sample ID
           // then we must get the sample id from the subject_observation data.
           if ($loadedSubjectObservationId && !$loadedSampleId) {
               data_entry_helper::load_existing_record($auth['read'], 'subject_observation', $loadedSubjectObservationId);
               $loadedSampleId = data_entry_helper::$entity_to_load['subject_observation:sample_id'];
           }
           data_entry_helper::$entity_to_load = self::reload_form_data($loadedSampleId, $args, $auth);
       }
       // get the sample attributes
       $attrOpts = array('id' => data_entry_helper::$entity_to_load['sample:id'], 'valuetable' => 'sample_attribute_value', 'attrtable' => 'sample_attribute', 'key' => 'sample_id', 'fieldprefix' => 'smpAttr', 'extraParams' => $auth['read'], 'survey_id' => $args['survey_id']);
       // select only the custom attributes that are for this sample method or all sample methods, if this
       // form is for a specific sample method.
       if (!empty($args['sample_method_id'])) {
           $attrOpts['sample_method_id'] = $args['sample_method_id'];
       }
       $attributes = data_entry_helper::getAttributes($attrOpts, false);
       // Check if Recorder details is included as a control.
       // If so, remove the recorder attributes from the $attributes array so not output anywhere else.
       $arr = helper_base::explode_lines($args['structure']);
       if (in_array('[recorder details]', $arr)) {
           $attrCount = count($attributes);
           for ($i = 0; $i < $attrCount; $i++) {
               if (strcasecmp($attributes[$i]['caption'], 'first name') === 0 || strcasecmp($attributes[$i]['caption'], 'last name') === 0 || strcasecmp($attributes[$i]['caption'], 'email') === 0) {
                   unset($attributes[$i]);
               }
           }
       }
       //// Make sure the form action points back to this page
       $reload = data_entry_helper::get_reload_link_parts();
       unset($reload['params']['sample_id']);
       unset($reload['params']['subject_observation_id']);
       unset($reload['params']['newSample']);
       $reloadPath = $reload['path'];
       // don't url-encode the drupal path id using dirty url
       $pathParam = function_exists('variable_get') && variable_get('clean_url', 0) == '0' ? 'q' : '';
       if (count($reload['params'])) {
           if ($pathParam === 'q' && array_key_exists('q', $reload['params'])) {
               $reloadPath .= '?q=' . $reload['params']['q'];
               unset($reload['params']['q']);
               if (count($reload['params'])) {
                   $reloadPath .= '&' . http_build_query($reload['params']);
               }
           } else {
               $reloadPath .= '?' . http_build_query($reload['params']);
           }
       }
       $r = "<form method=\"post\" id=\"entry_form\" action=\"{$reloadPath}\">\n";
       // debug section
       if (!empty($args['debug_info']) && $args['debug_info']) {
           $r .= '<input type="button" value="Debug info" onclick="$(\'#debug-info-div\').slideToggle();" /><br />' . '<div id="debug-info-div" style="display: none;">';
           $r .= '<p>$_GET is:<br /><pre>' . print_r($_GET, true) . '</pre></p>';
           $r .= '<p>$_POST is:<br /><pre>' . print_r($_POST, true) . '</pre></p>';
           $r .= '<p>Entity to load is:<br /><pre>' . print_r(data_entry_helper::$entity_to_load, true) . '</pre></p>';
           $r .= '<p>Submission was:<br /><pre>' . print_r(self::$submission, true) . '</pre></p>';
           $r .= '<input type="button" value="Hide debug info" onclick="$(\'#debug-info-div\').slideToggle();" />';
           $r .= '</div>';
       }
       // reset button
       $r .= '<input type="button" class="ui-state-default ui-corner-all" value="' . lang::get('Abandon Form and Reload') . '" ' . 'onclick="window.location.href=\'' . url('node/' . $node->nid, array('query' => 'newSample')) . '\'">';
       // clear all padlocks button
       $r .= ' <input type="button" class="ui-state-default ui-corner-all" value="' . lang::get('Clear All Padlocks') . '" ' . 'onclick="if (indicia && indicia.locks) indicia.locks.unlockRegion(\'body\');">';
       // Get authorisation tokens to update the Warehouse, plus any other hidden data.
       $hiddens = $auth['write'] . "<input type=\"hidden\" id=\"read_auth_token\" name=\"read_auth_token\" value=\"" . $auth['read']['auth_token'] . "\" />\n" . "<input type=\"hidden\" id=\"read_nonce\" name=\"read_nonce\" value=\"" . $auth['read']['nonce'] . "\" />\n" . "<input type=\"hidden\" id=\"website_id\" name=\"website_id\" value=\"" . $args['website_id'] . "\" />\n" . "<input type=\"hidden\" id=\"survey_id\" name=\"survey_id\" value=\"" . $args['survey_id'] . "\" />\n";
       if (!empty($args['sample_method_id'])) {
           $hiddens .= '<input type="hidden" name="sample:sample_method_id" value="' . $args['sample_method_id'] . '"/>';
       }
       if (isset(data_entry_helper::$entity_to_load['sample:id'])) {
           $hiddens .= "<input type=\"hidden\" id=\"sample:id\" name=\"sample:id\" value=\"" . data_entry_helper::$entity_to_load['sample:id'] . "\" />\n";
       }
       // request automatic JS validation
       if (!isset($args['clientSideValidation']) || $args['clientSideValidation']) {
           data_entry_helper::enable_validation('entry_form');
           // override the default invalidHandler to activate the first accordion panels which has an error
           global $indicia_templates;
           $indicia_templates['invalid_handler_javascript'] = "function(form, validator) {\n          var tabselected=false;\n          var accordion\$=jQuery('.ui-accordion');\n          jQuery.each(validator.errorMap, function(ctrlId, error) {\n            // select the tab containing the first error control\n            var ctrl = jQuery('[name=' + ctrlId.replace(/:/g, '\\\\:').replace(/\\[/g, '\\\\[').replace(/]/g, '\\\\]') + ']');\n            if (!tabselected && typeof(tabs)!=='undefined') {\n              tabs.tabs('select',ctrl.filter('input,select').parents('.ui-tabs-panel')[0].id);\n              tabselected = true;\n            }\n            ctrl.parents('fieldset').removeClass('collapsed');\n            ctrl.parents('.fieldset-wrapper').show();\n            // for each accordion, activate the first panel which has an error\n            ctrl.parents('.ui-accordion-content').each(function (n) {\n              var acc\$ = \$(this).closest('.ui-accordion');\n              var accId = acc\$[0].id.replace(/:/g, '\\\\:').replace(/\\[/g, '\\\\[').replace(/]/g, '\\\\]');\n              if (accordion\$.is('#'+accId)) {\n                var header\$ = \$(this).prev('h3');\n                var accHeaderId = header\$.attr('id').replace(/:/g, '\\\\:').replace(/\\[/g, '\\\\[').replace(/]/g, '\\\\]');\n                acc\$.accordion('activate', '#'+accHeaderId);\n                accordion\$ = accordion\$.not('#'+accId);\n              }\n            });\n          });\n        }";
           // By default, validate doesn't validate any ':hidden' fields,
           // but we need to validate hidden with display: none; fields in accordions
           data_entry_helper::$javascript .= "jQuery.validator.setDefaults({ \n        ignore: \"input[type='hidden']\"\n      });\n";
       }
       if (method_exists(get_called_class(), 'getHeaderHTML')) {
           $r .= call_user_func(array(get_called_class(), 'getHeaderHTML'), true, $args);
       }
       if ($mode == MODE_EXISTING && ($loadedSampleId || $loadedSubjectObservationId)) {
           $existing = true;
       } else {
           $existing = false;
       }
       $hiddens .= get_user_profile_hidden_inputs($attributes, $args, $existing, $auth['read']);
       $customAttributeTabs = get_attribute_tabs($attributes);
       // remove added comment controls unless editing an existing sample
       if ($mode !== MODE_EXISTING || helper_base::$form_mode === 'ERRORS') {
           $controls = helper_base::explode_lines($args['structure']);
           $new_controls = array();
           foreach ($controls as $control) {
               if ($control !== '[show added sample comments]' && $control !== '[add sample comment]') {
                   $new_controls[] = $control;
               }
           }
           $args['structure'] = implode("\r\n", $new_controls);
       }
       $tabs = self::get_all_tabs($args['structure'], $customAttributeTabs);
       $r .= "<div id=\"controls\">\n";
       // Build a list of the tabs that actually have content
       $tabHtml = self::get_tab_html($tabs, $auth, $args, $attributes, $hiddens);
       // Output the dynamic tab headers
       if ($args['interface'] != 'one_page') {
           $headerOptions = array('tabs' => array());
           foreach ($tabHtml as $tab => $tabContent) {
               $alias = preg_replace('/[^a-zA-Z0-9]/', '', strtolower($tab));
               $tabtitle = lang::get("LANG_Tab_{$alias}");
               if ($tabtitle == "LANG_Tab_{$alias}") {
                   // if no translation provided, we'll just use the standard heading
                   $tabtitle = $tab;
               }
               $headerOptions['tabs']['#' . $alias] = $tabtitle;
           }
           $r .= data_entry_helper::tab_header($headerOptions);
           data_entry_helper::enable_tabs(array('divId' => 'controls', 'style' => $args['interface'], 'progressBar' => isset($args['tabProgress']) && $args['tabProgress'] == true));
       }
       // Output the dynamic tab content
       $pageIdx = 0;
       foreach ($tabHtml as $tab => $tabContent) {
           // get a machine readable alias for the heading
           $tabalias = preg_replace('/[^a-zA-Z0-9]/', '', strtolower($tab));
           $r .= '<div id="' . $tabalias . '">' . "\n";
           // For wizard include the tab title as a header.
           if ($args['interface'] == 'wizard') {
               $r .= '<h1>' . $headerOptions['tabs']['#' . $tabalias] . '</h1>';
           }
           $r .= $tabContent;
           // Add any buttons required at the bottom of the tab
           if ($args['interface'] == 'wizard') {
               $r .= data_entry_helper::wizard_buttons(array('divId' => 'controls', 'page' => $pageIdx === 0 ? 'first' : ($pageIdx == count($tabHtml) - 1 ? 'last' : 'middle')));
           } elseif ($pageIdx == count($tabHtml) - 1 && !($args['interface'] == 'tabs' && $args['save_button_below_all_pages'])) {
               // last part of a non wizard interface must insert a save button, unless it is tabbed interface with save button beneath all pages
               $r .= "<input type=\"submit\" class=\"ui-state-default ui-corner-all\" id=\"save-button\" value=\"" . lang::get('LANG_Save') . "\" />\n";
           }
           $pageIdx++;
           $r .= "</div>\n";
       }
       $r .= "</div>\n";
       if ($args['interface'] == 'tabs' && $args['save_button_below_all_pages']) {
           $r .= "<input type=\"submit\" class=\"ui-state-default ui-corner-all\" id=\"save-button\" value=\"" . lang::get('LANG_Save') . "\" />\n";
       }
       if (!empty(data_entry_helper::$validation_errors)) {
           $r .= data_entry_helper::dump_remaining_errors();
       }
       $r .= "</form>";
       if (method_exists(get_called_class(), 'getTrailerHTML')) {
           $r .= call_user_func(array(get_called_class(), 'getTrailerHTML'), true, $args);
       }
       return $r;
   }
 /**
  * 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;
     $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']);
     $typeTerms = array(empty($args['transect_type_term']) ? 'Transect' : $args['transect_type_term'], empty($args['section_type_term']) ? 'Section' : $args['section_type_term']);
     $settings = array('locationTypes' => helper_base::get_termlist_terms($auth, 'indicia:location_types', $typeTerms), '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']));
     $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['locationTypes'][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['locationTypes'][1]['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'];
     }
     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']) {
         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;
                     }
                 }
             }
         }
         // 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'];
                 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'];
             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 ($args['always_show_section_details'] || 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 ($args['always_show_section_details'] || 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['locationTypes'][1]['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;
 }
 /**
  * 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.
  */
 public static function get_form($args, $node, $response = null)
 {
     $form = '<form action="#" method="POST" id="entry_form">';
     if ($_POST) {
         $auth = data_entry_helper::get_read_write_auth($args['website_id'], $args['password']);
         self::subscribe($args, $auth);
     } else {
         // don't bother with write auth for initial form load, as read auth is cached and faster
         $auth = array('read' => data_entry_helper::get_read_auth($args['website_id'], $args['password']));
     }
     if (!empty($_GET['id'])) {
         data_entry_helper::load_existing_record($auth['read'], 'species_alert', $_GET['id']);
         // enforce permissions
         if (data_entry_helper::$entity_to_load['species_alert:user_id'] != hostsite_get_user_field('indicia_user_id')) {
             return lang::get('You cannot modify a species alert subscription created by someone else');
         }
         $form .= data_entry_helper::hidden_text(array('fieldname' => 'species_alert:id', 'default' => $_GET['id']));
     }
     // if not logged in, then ask for details to register against
     global $user;
     if (!hostsite_get_user_field('id') || !isset($user) || empty($user->mail) || !hostsite_get_user_field('last_name')) {
         $form .= "<fieldset><legend>" . lang::get('Your details') . ":</legend>\n";
         $default = empty($_POST['first_name']) ? hostsite_get_user_field('first_name', '') : $_POST['first_name'];
         $form .= data_entry_helper::text_input(array('label' => lang::get('First name'), 'fieldname' => 'first_name', 'validation' => array('required'), 'default' => $default, 'class' => 'control-width-4'));
         $default = empty($_POST['surname']) ? hostsite_get_user_field('last_name', '') : $_POST['surname'];
         $form .= data_entry_helper::text_input(array('label' => lang::get('Last name'), 'fieldname' => 'surname', 'validation' => array('required'), 'default' => $default, 'class' => 'control-width-4'));
         $default = empty($_POST['email']) ? empty($user->mail) ? '' : $user->mail : $_POST['email'];
         $form .= data_entry_helper::text_input(array('label' => lang::get('Email'), 'fieldname' => 'email', 'validation' => array('required', 'email'), 'default' => $default, 'class' => 'control-width-4'));
         $form .= "</fieldset>\n";
     } else {
         $form .= data_entry_helper::hidden_text(array('fieldname' => 'first_name', 'default' => hostsite_get_user_field('first_name')));
         $form .= data_entry_helper::hidden_text(array('fieldname' => 'surname', 'default' => hostsite_get_user_field('last_name')));
         $form .= data_entry_helper::hidden_text(array('fieldname' => 'email', 'default' => $user->mail));
         $form .= data_entry_helper::hidden_text(array('fieldname' => 'user_id', 'default' => hostsite_get_user_field('indicia_user_id')));
     }
     $form .= "<fieldset><legend>" . lang::get('Alert criteria') . ":</legend>\n";
     // Output the species selection control
     // Default after saving with a validation failure can be pulled direct from the post, but
     // when reloading we don't need a default taxa taxon list ID since we already know the meaning
     // ID or external key.
     $default = empty($_POST['taxa_taxon_list_id']) ? '' : $_POST['taxa_taxon_list_id'];
     if (empty($_POST['taxa_taxon_list_id:taxon'])) {
         $defaultCaption = empty(data_entry_helper::$entity_to_load['species_alert:preferred_taxon']) ? '' : data_entry_helper::$entity_to_load['species_alert:preferred_taxon'];
     } else {
         $defaultCaption = $_POST['taxa_taxon_list_id:taxon'];
     }
     $form .= data_entry_helper::species_autocomplete(array('label' => lang::get('Alert species'), 'helpText' => lang::get('Select the species you are interested in receiving alerts in ' . 'relation to if you want to receive alerts on a single species.'), 'fieldname' => 'taxa_taxon_list_id', 'cacheLookup' => true, 'extraParams' => $auth['read'] + array('taxon_list_id' => $args['list_id']), 'class' => 'control-width-4', 'default' => $default, 'defaultCaption' => $defaultCaption));
     if (empty($default)) {
         // Unless we've searched for the species name then posted (and failed), then the
         // default will be empty. We might therefore be reloading existing data which has
         // a meaning ID or external key.
         if (!empty(data_entry_helper::$entity_to_load['species_alert:external_key'])) {
             $form .= data_entry_helper::hidden_text(array('fieldname' => 'species_alert:external_key', 'default' => data_entry_helper::$entity_to_load['species_alert:external_key']));
         } elseif (!empty(data_entry_helper::$entity_to_load['species_alert:taxon_meaning_id'])) {
             $form .= data_entry_helper::hidden_text(array('fieldname' => 'species_alert:taxon_meaning_id', 'default' => data_entry_helper::$entity_to_load['species_alert:taxon_meaning_id']));
         }
     }
     if (!empty($args['full_lists'])) {
         $form .= data_entry_helper::select(array('label' => lang::get('Select full species lists'), 'helpText' => lang::get('If you want to restrict the alerts to records of any ' . 'species within a species list, then select the list here.'), 'fieldname' => 'species_alert:taxon_list_id', 'blankText' => lang::get('<Select a species list>'), 'table' => 'taxon_list', 'valueField' => 'id', 'captionField' => 'title', 'extraParams' => $auth['read'] + array('id' => $args['full_lists'], 'orderby' => 'title'), 'class' => 'control-width-4'));
     }
     $form .= data_entry_helper::location_select(array('label' => lang::get('Select location'), 'helpText' => lang::get('If you want to restrict the alerts to records within a certain boundary, select it here.'), 'fieldname' => 'species_alert:location_id', 'id' => 'imp-location', 'blankText' => lang::get('<Select boundary>'), 'extraParams' => $auth['read'] + array('location_type_id' => $args['location_type_id'], 'orderby' => 'name'), 'class' => 'control-width-4'));
     $form .= data_entry_helper::checkbox(array('label' => lang::get('Alert on initial entry'), 'helpText' => lang::get('Tick this box if you want to receive a notification when the record is first input into the system.'), 'fieldname' => 'species_alert:alert_on_entry'));
     $form .= data_entry_helper::checkbox(array('label' => lang::get('Alert on verification as correct'), 'helpText' => lang::get('Tick this box if you want to receive a notification when the record has been verified as correct.'), 'fieldname' => 'species_alert:alert_on_verify'));
     $form .= "</fieldset>\n";
     $form .= '<input type="Submit" value="Subscribe" />';
     $form .= '</form>';
     data_entry_helper::enable_validation('entry_form');
     iform_load_helpers(array('map_helper'));
     $mapOptions = iform_map_get_map_options($args, $auth['read']);
     $map = map_helper::map_panel($mapOptions);
     global $indicia_templates;
     return str_replace(array('{col-1}', '{col-2}'), array($form, $map), $indicia_templates['two-col-50']);
 }
   /**
    * Return the generated form output.
    * @return Form HTML.
    */
   public static function get_form($args, $node, $response = null)
   {
       global $user;
       global $custom_terms;
       $logged_in = $user->uid > 0;
       $r = '';
       // Get authorisation tokens to update and read from the Warehouse.
       $auth = data_entry_helper::get_read_write_auth($args['website_id'], $args['password']);
       $readAuth = $auth['read'];
       $svcUrl = data_entry_helper::$base_url . '/index.php/services';
       drupal_add_js(drupal_get_path('module', 'iform') . '/media/js/jquery.form.js', 'module');
       data_entry_helper::link_default_stylesheet();
       data_entry_helper::add_resource('jquery_ui');
       $language = iform_lang_iso_639_2($args['language']);
       if ($args['language'] != 'en') {
           data_entry_helper::add_resource('jquery_ui_' . $args['language']);
       }
       // If not logged in: Display an information message.
       // This form should only be called in POST mode when setting the location allocation.
       //  All other posting is now done via AJAX.
       // When invoked by GET there are the following modes:
       // No additional arguments: mode 0.
       // Additional argument - new : mode 1.
       // Additional argument - sample_id=<id> : mode 2.
       // Additional argument - occurrence_id=<id> : mode 3.
       // Additional arguments - merge_sample_id1=<id>&merge_sample_id2=<id> : mode 2.1
       $mode = 0;
       // default mode : output survey selector
       // mode 1: output the main Data Entry page: occurrence list or add/edit occurrence tabs hidden. "Survey" tab active
       // mode 2: output the main Data Entry page, display existing sample. Active tab determined by iform params. No occurence details filled in.
       // mode 2.1: sample 2 has all its occurrences merged into sample 1. sample 2 is then flagged as deleted. sample 1 is then viewed as in normal mode 2.
       // mode 3: output the main Data Entry page, display existing occurrence. "Edit Occurrence" tab active. Occurence details filled in.
       $surveyReadOnly = false;
       // On top of this, things can be flagged as readonly. RO mode 2+4 means no Add Occurrence tab.
       if (!$logged_in) {
           return lang::get('LANG_not_logged_in');
       }
       $parentSample = array();
       $parentLoadID = null;
       $childSample = array();
       $childLoadID = null;
       $thisOccID = -1;
       // IDs have to be >0, so this is outside the valid range
       // Load up attribute details
       $sample_walk_direction_id = self::getAttrID($auth, $args, 'sample', self::ATTR_WALK);
       $sample_reliability_id = self::getAttrID($auth, $args, 'sample', self::ATTR_RELIABILITY);
       $sample_visit_number_id = self::getAttrID($auth, $args, 'sample', self::ATTR_VISIT);
       $sample_wind_id = self::getAttrID($auth, $args, 'sample', self::ATTR_WIND);
       $sample_precipitation_id = self::getAttrID($auth, $args, 'sample', self::ATTR_RAIN);
       $sample_temperature_id = self::getAttrID($auth, $args, 'sample', self::ATTR_TEMP);
       $sample_cloud_id = self::getAttrID($auth, $args, 'sample', self::ATTR_CLOUD);
       $sample_start_time_id = self::getAttrID($auth, $args, 'sample', self::ATTR_START_TIME);
       $sample_end_time_id = self::getAttrID($auth, $args, 'sample', self::ATTR_END_TIME);
       $sample_closure_id = self::getAttrID($auth, $args, 'sample', self::ATTR_CLOSED);
       $uid_attr_id = self::getAttrID($auth, $args, 'sample', self::ATTR_UID);
       $email_attr_id = self::getAttrID($auth, $args, 'sample', self::ATTR_EMAIL);
       $username_attr_id = self::getAttrID($auth, $args, 'sample', self::ATTR_USERNAME);
       $occurrence_confidence_id = self::getAttrID($auth, $args, 'occurrence', self::ATTR_CONFIDENCE);
       $occurrence_count_id = self::getAttrID($auth, $args, 'occurrence', self::ATTR_COUNT);
       $occurrence_approximation_id = self::getAttrID($auth, $args, 'occurrence', self::ATTR_APPROXIMATION);
       $occurrence_territorial_id = self::getAttrID($auth, $args, 'occurrence', self::ATTR_TERRITORIAL);
       $occurrence_atlas_code_id = self::getAttrID($auth, $args, 'occurrence', self::ATTR_ATLAS_CODE);
       $occurrence_overflying_id = self::getAttrID($auth, $args, 'occurrence', self::ATTR_OVERFLYING);
       if (!$sample_closure_id) {
           return '<p>This form must be used with a survey which has the "' . self::ATTR_CLOSED . '" sample attribute allocated to it. Survey_id = ' . $args['survey_id'];
       }
       if (!$uid_attr_id) {
           return '<p>This form must be used with a survey which has the "' . self::ATTR_UID . '" sample attribute allocated to it. Survey_id = ' . $args['survey_id'];
       }
       if (!$email_attr_id) {
           return '<p>This form must be used with a survey which has the "' . self::ATTR_EMAIL . '" sample attribute allocated to it. Survey_id = ' . $args['survey_id'];
       }
       if (!$username_attr_id) {
           return '<p>This form must be used with a survey which has the "' . self::ATTR_USERNAME . '" sample attribute allocated to it. Survey_id = ' . $args['survey_id'];
       }
       if (!$sample_walk_direction_id) {
           return '<p>This form must be used with a survey which has the "' . self::ATTR_WALK . '" sample attribute allocated to it. Survey_id = ' . $args['survey_id'];
       }
       if (!$sample_visit_number_id) {
           return '<p>This form must be used with a survey which has the "' . self::ATTR_VISIT . '" sample attribute allocated to it. Survey_id = ' . $args['survey_id'];
       }
       if (!$occurrence_count_id) {
           return '<p>This form must be used with a survey which has the "' . self::ATTR_COUNT . '" occurrence attribute allocated to it. Survey_id = ' . $args['survey_id'];
       }
       if (!$occurrence_territorial_id) {
           return '<p>This form must be used with a survey which has the "' . self::ATTR_TERRITORIAL . '" occurrence attribute allocated to it. Survey_id = ' . $args['survey_id'];
       }
       if (!$occurrence_atlas_code_id) {
           return '<p>This form must be used with a survey which has the "' . self::ATTR_ATLAS_CODE . '" occurrence attribute allocated to it. Survey_id = ' . $args['survey_id'];
       }
       if ($_POST) {
           if (!array_key_exists('website_id', $_POST)) {
               // non Indicia POST, in this case must be the location allocations. add check to ensure we don't corrept the data by accident
               if (iform_loctools_checkaccess($node, 'admin') && array_key_exists('mnhnlbtw', $_POST)) {
                   iform_loctools_deletelocations($node);
                   foreach ($_POST as $key => $value) {
                       $parts = explode(':', $key);
                       if ($parts[0] == 'location' && $value) {
                           iform_loctools_insertlocation($node, $value, $parts[1]);
                       }
                   }
               }
           }
       } else {
           if (array_key_exists('merge_sample_id1', $_GET) && array_key_exists('merge_sample_id2', $_GET) && user_access($args['edit_permission'])) {
               $mode = 2;
               // first check can access the 2 samples given
               $parentLoadID = $_GET['merge_sample_id1'];
               $url = $svcUrl . '/data/sample/' . $parentLoadID . "?mode=json&view=detail&auth_token=" . $readAuth['auth_token'] . "&nonce=" . $readAuth["nonce"];
               $session = curl_init($url);
               curl_setopt($session, CURLOPT_RETURNTRANSFER, true);
               $entity = json_decode(curl_exec($session), true);
               if (count($entity) == 0 || $entity[0]["parent_id"]) {
                   return '<p>' . lang::get('LANG_No_Access_To_Sample') . ' ' . $parentLoadID . '</p>';
               }
               // The check for id2 is slightly different: there is the possiblity that someone will F5/refresh their browser, after the transfer and delete have taken place.
               // In this case we carry on, but do not do the transfer and delete.
               $url = $svcUrl . '/data/sample/' . $_GET['merge_sample_id2'] . "?mode=json&view=detail&auth_token=" . $readAuth['auth_token'] . "&nonce=" . $readAuth["nonce"];
               $session = curl_init($url);
               curl_setopt($session, CURLOPT_RETURNTRANSFER, true);
               $entity = json_decode(curl_exec($session), true);
               if (count($entity) > 0 && !$entity[0]["parent_id"]) {
                   // now get child samples and point to new parent.
                   $url = $svcUrl . '/data/sample?mode=json&view=detail&auth_token=' . $readAuth['auth_token'] . "&nonce=" . $readAuth["nonce"] . '&parent_id=' . $_GET['merge_sample_id2'];
                   $session = curl_init($url);
                   curl_setopt($session, CURLOPT_RETURNTRANSFER, true);
                   $entities = json_decode(curl_exec($session), true);
                   if (count($entities) > 0) {
                       foreach ($entities as $entity) {
                           $Model = data_entry_helper::wrap(array('id' => $entity['id'], 'parent_id' => $_GET['merge_sample_id1']), 'sample');
                           $request = data_entry_helper::$base_url . "/index.php/services/data/save";
                           $postargs = 'submission=' . json_encode($Model) . '&auth_token=' . $auth['write_tokens']['auth_token'] . '&nonce=' . $auth['write_tokens']['nonce'] . '&persist_auth=true';
                           $postresponse = data_entry_helper::http_post($request, $postargs, false);
                           // the response array will always feature an output, which is the actual response or error message. if it is not json format, assume error text, and json encode that.
                           $response = $postresponse['output'];
                           if (!json_decode($response, true)) {
                               return "<p>" . lang::get('LANG_Error_When_Moving_Sample') . ": id " . $entity['id'] . " : " . $response;
                           }
                       }
                   }
                   // finally delete the no longer used sample
                   $Model = data_entry_helper::wrap(array('id' => $_GET['merge_sample_id2'], 'deleted' => 'true'), 'sample');
                   $request = data_entry_helper::$base_url . "/index.php/services/data/save";
                   $postargs = 'submission=' . json_encode($Model) . '&auth_token=' . $auth['write_tokens']['auth_token'] . '&nonce=' . $auth['write_tokens']['nonce'] . '&persist_auth=true';
                   $postresponse = data_entry_helper::http_post($request, $postargs, false);
                   // the response array will always feature an output, which is the actual response or error message. if it is not json format, assume error text, and json encode that.
                   $response = $postresponse['output'];
                   if (!json_decode($response, true)) {
                       return "<p>" . lang::get('LANG_Error_When_Deleting_Sample') . ": id " . $entity['id'] . " : " . $response;
                   }
               }
           } else {
               if (array_key_exists('sample_id', $_GET)) {
                   $mode = 2;
                   $parentLoadID = $_GET['sample_id'];
               } else {
                   if (array_key_exists('occurrence_id', $_GET)) {
                       $mode = 3;
                       $childLoadID = $_GET['occurrence_id'];
                       $thisOccID = $childLoadID;
                   } else {
                       if (array_key_exists('new', $_GET)) {
                           $mode = 1;
                       }
                   }
               }
           }
           // else default to mode 0
       }
       // define language strings so they can be used for validation translation.
       data_entry_helper::$javascript .= "var translations = [\n";
       foreach ($custom_terms as $key => $value) {
           if (substr($key, 0, 4) != "LANG") {
               data_entry_helper::$javascript .= "  {key: \"" . $key . "\", translated: \"" . $value . "\"},\n";
           }
       }
       data_entry_helper::$javascript .= "];\n";
       // define layers for all maps.
       // each argument is a comma separated list eg:
       // "Name:Lux Outline,URL:http://localhost/geoserver/wms,LAYERS:indicia:nation2,SRS:EPSG:2169,FORMAT:image/png,minScale:0,maxScale:1000000,units:m";
       $optionsArray_Location = array();
       $options = explode(',', $args['locationLayer']);
       foreach ($options as $option) {
           $parts = explode(':', $option);
           $optionName = $parts[0];
           unset($parts[0]);
           $optionsArray_Location[$optionName] = implode(':', $parts);
       }
       // Work out list of locations this user can see.
       $locations = iform_loctools_listlocations($node);
       if ($locations != 'all') {
           data_entry_helper::$javascript .= "var locationList = [" . implode(',', $locations) . "];\n";
       }
       drupal_add_js(drupal_get_path('module', 'iform') . '/media/js/hasharray.js', 'module');
       drupal_add_js(drupal_get_path('module', 'iform') . '/media/js/jquery.datagrid.js', 'module');
       if (method_exists(get_called_class(), 'getHeaderHTML')) {
           $r .= call_user_func(array(get_called_class(), 'getHeaderHTML'), $args);
       }
       // Work out list of locations this user can see.
       // $locations = iform_loctools_listlocations($node);
       ///////////////////////////////////////////////////////////////////
       // default mode 0 : display a page with tabs for survey selector,
       // locations allocator and reports (last two require permissions)
       ///////////////////////////////////////////////////////////////////
       if ($mode == 0) {
           // If the user has permissions, add tabs so can choose to see
           // locations allocator
           $tabs = array('#surveyList' => lang::get('LANG_Surveys'));
           if (iform_loctools_checkaccess($node, 'admin')) {
               $tabs['#setLocations'] = lang::get('LANG_Allocate_Locations');
           }
           if (iform_loctools_checkaccess($node, 'superuser')) {
               $tabs['#downloads'] = lang::get('LANG_Download');
           }
           if (count($tabs) > 1) {
               $r .= "<div id=\"controls\">" . data_entry_helper::enable_tabs(array('divId' => 'controls', 'active' => '#surveyList')) . "<div id=\"temp\"></div>";
               $r .= data_entry_helper::tab_header(array('tabs' => $tabs));
           }
           if ($locations == 'all') {
               $useloclist = 'NO';
               $loclist = '-1';
           } else {
               // an empty list will cause an sql error, lids must be > 0, so push a -1 to prevent the error.
               if (empty($locations)) {
                   $locations[] = -1;
               }
               $useloclist = 'YES';
               $loclist = implode(',', $locations);
           }
           // Create the Survey list datagrid for this user.
           drupal_add_js("jQuery(document).ready(function(){\n  \$('div#smp_grid').indiciaDataGrid('rpt:reports_for_prebuilt_forms/MNHNL/mnhnl_btw_list_samples', {\n    indiciaSvc: '" . $svcUrl . "',\n    dataColumns: ['location_name', 'date', 'num_visit', 'num_occurrences', 'num_taxa'],\n    reportColumnTitles: {location_name : '" . lang::get('LANG_Transect') . "', date : '" . lang::get('LANG_Date') . "', num_visit : '" . lang::get('LANG_Visit_No') . "', num_occurrences : '" . lang::get('LANG_Num_Occurrences') . "', num_taxa : '" . lang::get('LANG_Num_Species') . "'},\n    actionColumns: {" . lang::get('LANG_Show') . " : \"" . url('node/' . $node->nid, array('query' => 'sample_id=£id£')) . "\"},\n    auth : { nonce : '" . $readAuth['nonce'] . "', auth_token : '" . $readAuth['auth_token'] . "'},\n    parameters : { survey_id : '" . $args['survey_id'] . "', visit_attr_id : '" . $sample_visit_number_id . "', closed_attr_id : '" . $sample_closure_id . "', use_location_list : '" . $useloclist . "', locations : '" . $loclist . "'},\n    itemsPerPage : 12,\n    condCss : {field : 'closed', value : '0', css: 'mnhnl-btw-highlight'},\n    cssOdd : ''\n  });\n});\n      ", 'inline');
           data_entry_helper::$javascript .= "\n// Create Layers.\nvar locationListLayer;\nmapInitialisationHooks.push(function (div) {\n      \"use strict\";";
           if ($locations == 'all' || $loclist != '-1') {
               data_entry_helper::$javascript .= "\n  var WMSoptions = {SERVICE: 'WMS', VERSION: '1.1.0', STYLES: '',\n        SRS: div.map.projection.proj.srsCode, /* Now takes it from map */\n        FORMAT: '" . $optionsArray_Location['FORMAT'] . "',\n        TRANSPARENT: 'true', ";
               if ($locations != 'all') {
                   // when given a restricted feature list we have to use the feature id to filter in order to not go over 2000 char limit on the URL
                   // Can only generate the feature id if we access a table directly, not through a view. Go direct to the locations table.
                   // don't need to worry about parent_id in this case as we know exactly which features we want.
                   // need to use btw_transects view for unrestricted so we can filter by parent_id=NULL.
                   $locFeatures = array();
                   foreach ($locations as $location) {
                       $locFeatures[] = "locations." . $location;
                   }
                   data_entry_helper::$javascript .= "\n        LAYERS: 'indicia:locations',\n        FEATUREID: '" . implode(',', $locFeatures) . "'";
               } else {
                   data_entry_helper::$javascript .= " LAYERS: '" . $optionsArray_Location['LAYERS'] . "', CQL_FILTER: 'website_id=" . $args['website_id'] . "'";
               }
               data_entry_helper::$javascript .= "\n  };\n  locationListLayer = new OpenLayers.Layer.WMS('" . $optionsArray_Location['Name'] . "',\n        '" . (function_exists(iform_proxy_url) ? iform_proxy_url($optionsArray_Location['URL']) : $optionsArray_Location['URL']) . "',\n        WMSoptions, {\n        minScale: " . $optionsArray_Location['minScale'] . ",\n        maxScale: " . $optionsArray_Location['maxScale'] . ",\n        units: '" . $optionsArray_Location['units'] . "',\n        isBaseLayer: false,\n        singleTile: true\n  });\n  div.map.addLayer(locationListLayer);\n});\n";
           }
           $r .= '
 <div id="surveyList" class="mnhnl-btw-datapanel"><div id="smp_grid"></div>
   <form><input type="button" value="' . lang::get('LANG_Add_Survey') . '" onclick="window.location.href=\'' . url('node/' . $node->nid, array('query' => 'new')) . '\'"></form></div>';
           // Add the locations allocator if user has admin rights.
           if (iform_loctools_checkaccess($node, 'admin')) {
               $r .= '
 <div id="setLocations" class="mnhnl-btw-datapanel">
   <form method="post">
     <input type="hidden" id="mnhnlbtw" name="mnhnlbtw" value="mnhnlbtw" />';
               $url = $svcUrl . '/data/location?mode=json&view=detail&auth_token=' . $readAuth['auth_token'] . "&nonce=" . $readAuth["nonce"] . "&parent_id=NULL&orderby=name&columns=id,name,parent_id";
               $session = curl_init($url);
               curl_setopt($session, CURLOPT_RETURNTRANSFER, true);
               $entities = json_decode(curl_exec($session), true);
               $userlist = iform_loctools_listusers($node);
               if (!empty($entities)) {
                   foreach ($entities as $entity) {
                       if (!$entity["parent_id"]) {
                           // only assign parent locations.
                           $r .= "\n<label for=\"location:" . $entity["id"] . "\">" . $entity["name"] . ":</label><select id=\"location:" . $entity["id"] . "\" name=\"location:" . $entity["id"] . "\"><option value=\"\" >&lt;" . lang::get('LANG_Not_Allocated') . "&gt;</option>";
                           $defaultuserid = iform_loctools_getuser($node, $entity["id"]);
                           foreach ($userlist as $uid => $a_user) {
                               $r .= "<option value=\"" . $uid . "\" " . ($uid == $defaultuserid ? 'selected="selected" ' : '') . ">" . $a_user->name . "</option>";
                           }
                           $r .= "</select>";
                       }
                   }
               }
               $r .= "\n      <input type=\"submit\" class=\"ui-state-default ui-corner-all\" value=\"" . lang::get('Save Location Allocations') . "\" />\n    </form>\n  </div>";
           }
           // Add the downloader if user has manager (superuser) rights.
           if (iform_loctools_checkaccess($node, 'superuser')) {
               $r .= '
 <div id="downloads" class="mnhnl-btw-datapanel">
   <form method="post" action="' . data_entry_helper::$base_url . '/index.php/services/report/requestReport?report=reports_for_prebuilt_forms/MNHNL/mnhnl_btw_transect_direction_report.xml&reportSource=local&auth_token=' . $readAuth['auth_token'] . '&nonce=' . $readAuth['nonce'] . '&mode=csv">
     <p>' . lang::get('LANG_Direction_Report') . '</p>
     <input type="hidden" name="params" value=\'{"survey_id":' . $args['survey_id'] . ', "direction_attr_id":' . $sample_walk_direction_id . ', "closed_attr_id":' . $sample_closure_id . '}\' />
     <input type="submit" class="ui-state-default ui-corner-all" value="' . lang::get('LANG_Direction_Report_Button') . '">
   </form>
   <form method="post" action="' . data_entry_helper::$base_url . '/index.php/services/report/requestReport?report=reports_for_prebuilt_forms/MNHNL/mnhnl_btw_verified_data_report.xml&reportSource=local&auth_token=' . $readAuth['auth_token'] . '&nonce=' . $readAuth['nonce'] . '&mode=csv">
     <p>' . lang::get('LANG_Verified_Data_Report') . '</p>
     <input type="hidden" name="params" value=\'{"survey_id":' . $args['survey_id'] . '}\' />
     <input type="submit" class="ui-state-default ui-corner-all" value="' . lang::get('LANG_Verified_Data_Report_Button') . '">
   </form>
   <form method="post" action="' . data_entry_helper::$base_url . '/index.php/services/report/requestReport?report=reports_for_prebuilt_forms/MNHNL/mnhnl_btw_download_report_2.xml&reportSource=local&auth_token=' . $readAuth['auth_token'] . '&nonce=' . $readAuth['nonce'] . '&mode=csv">
     <p>' . lang::get('LANG_Initial_Download') . '</p>
     <input type="hidden" name="params" value=\'{"survey_id":' . $args['survey_id'] . ', "closed_attr_id":' . $sample_closure_id . ', "download": "INITIAL", "quality": "!R", "occattrs": "' . $occurrence_confidence_id . ',' . $occurrence_count_id . ',' . $occurrence_approximation_id . ',' . $occurrence_territorial_id . ',' . $occurrence_atlas_code_id . ',' . $occurrence_overflying_id . '", "smpattrs" : "' . $sample_walk_direction_id . ',' . $sample_reliability_id . ',' . $sample_visit_number_id . ',' . $sample_wind_id . ',' . $sample_precipitation_id . ',' . $sample_temperature_id . ',' . $sample_cloud_id . ',' . $sample_start_time_id . ',' . $sample_end_time_id . ',' . $sample_closure_id . ',' . $uid_attr_id . ',' . $email_attr_id . ',' . $username_attr_id . '"}\' />
     <input type="submit" class="ui-state-default ui-corner-all" value="' . lang::get('LANG_Initial_Download_Button') . '">
   </form>
   <form method="post" action="' . data_entry_helper::$base_url . '/index.php/services/report/requestReport?report=reports_for_prebuilt_forms/MNHNL/mnhnl_btw_download_report_2.xml&reportSource=local&auth_token=' . $readAuth['auth_token'] . '&nonce=' . $readAuth['nonce'] . '&mode=csv">
     <p>' . lang::get('LANG_Confirm_Download') . '</p>
     <input type="hidden" name="params" value=\'{"survey_id":' . $args['survey_id'] . ', "closed_attr_id":' . $sample_closure_id . ', "download": "CONFIRM", "quality": "V", "occattrs": "' . $occurrence_confidence_id . ',' . $occurrence_count_id . ',' . $occurrence_approximation_id . ',' . $occurrence_territorial_id . ',' . $occurrence_atlas_code_id . ',' . $occurrence_overflying_id . '", "smpattrs" : "' . $sample_walk_direction_id . ',' . $sample_reliability_id . ',' . $sample_visit_number_id . ',' . $sample_wind_id . ',' . $sample_precipitation_id . ',' . $sample_temperature_id . ',' . $sample_cloud_id . ',' . $sample_start_time_id . ',' . $sample_end_time_id . ',' . $sample_closure_id . ',' . $uid_attr_id . ',' . $email_attr_id . ',' . $username_attr_id . '"}\' />
     <input type="submit" class="ui-state-default ui-corner-all" value="' . lang::get('LANG_Confirm_Download_Button') . '">
   </form>
   <form method="post" action="' . data_entry_helper::$base_url . '/index.php/services/report/requestReport?report=reports_for_prebuilt_forms/MNHNL/mnhnl_btw_download_report_2.xml&reportSource=local&auth_token=' . $readAuth['auth_token'] . '&nonce=' . $readAuth['nonce'] . '&mode=csv">
     <p>' . lang::get('LANG_Final_Download') . '</p>
     <input type="hidden" name="params" value=\'{"survey_id":' . $args['survey_id'] . ', "closed_attr_id":' . $sample_closure_id . ', "download": "FINAL", "quality": "V", "occattrs": "' . $occurrence_confidence_id . ',' . $occurrence_count_id . ',' . $occurrence_approximation_id . ',' . $occurrence_territorial_id . ',' . $occurrence_atlas_code_id . ',' . $occurrence_overflying_id . '", "smpattrs" : "' . $sample_walk_direction_id . ',' . $sample_reliability_id . ',' . $sample_visit_number_id . ',' . $sample_wind_id . ',' . $sample_precipitation_id . ',' . $sample_temperature_id . ',' . $sample_cloud_id . ',' . $sample_start_time_id . ',' . $sample_end_time_id . ',' . $sample_closure_id . ',' . $uid_attr_id . ',' . $email_attr_id . ',' . $username_attr_id . '"}\' />
     <input type="submit" class="ui-state-default ui-corner-all" value="' . lang::get('LANG_Final_Download_Button') . '">
   </form>
   <form method="post" action="' . data_entry_helper::$base_url . '/index.php/services/report/requestReport?report=reports_for_prebuilt_forms/MNHNL/mnhnl_btw_download_report_2.xml&reportSource=local&auth_token=' . $readAuth['auth_token'] . '&nonce=' . $readAuth['nonce'] . '&mode=csv">
     <p>' . lang::get('LANG_Complete_Final_Download') . '</p>
     <input type="hidden" name="params" value=\'{"survey_id":' . $args['survey_id'] . ', "closed_attr_id":' . $sample_closure_id . ', "download": "OFF", "quality": "NA", "occattrs": "' . $occurrence_confidence_id . ',' . $occurrence_count_id . ',' . $occurrence_approximation_id . ',' . $occurrence_territorial_id . ',' . $occurrence_atlas_code_id . ',' . $occurrence_overflying_id . '", "smpattrs" : "' . $sample_walk_direction_id . ',' . $sample_reliability_id . ',' . $sample_visit_number_id . ',' . $sample_wind_id . ',' . $sample_precipitation_id . ',' . $sample_temperature_id . ',' . $sample_cloud_id . ',' . $sample_start_time_id . ',' . $sample_end_time_id . ',' . $sample_closure_id . ',' . $uid_attr_id . ',' . $email_attr_id . ',' . $username_attr_id . '"}\' />
     <input type="submit" class="ui-state-default ui-corner-all" value="' . lang::get('LANG_Complete_Final_Download_Button') . '">
   </form>
 </div>';
           }
           // Create Map
           $options = iform_map_get_map_options($args, $readAuth);
           $olOptions = iform_map_get_ol_options($args);
           //      if($locations == 'all' || $loclist != '-1')
           //        $options['layers'] = array('locationListLayer');
           $options['searchLayer'] = 'false';
           $options['editLayer'] = 'false';
           $options['initialFeatureWkt'] = null;
           $options['proxy'] = '';
           $options['scroll_wheel_zoom'] = false;
           $options['width'] = 'auto';
           // TBD remove from arglist
           $r .= "<div class=\"mnhnl-btw-mappanel\">\n" . data_entry_helper::map_panel($options, $olOptions) . "</div>\n";
           data_entry_helper::$javascript .= "\n\$('#controls').bind('tabsshow', function(event, ui) {\n  var y = \$('.mnhnl-btw-datapanel:visible').outerHeight(true) + \$('.mnhnl-btw-datapanel:visible').position().top;\n  if(y < \$('.mnhnl-btw-mappanel').outerHeight(true)+ \$('.mnhnl-btw-mappanel').position().top){\n    y = \$('.mnhnl-btw-mappanel').outerHeight(true)+ \$('.mnhnl-btw-mappanel').position().top;\n  }\n  \$('#controls').height(y - \$('#controls').position().top);\n});\n";
           if (count($tabs) > 1) {
               // close tabs div if present
               $r .= "</div>";
           }
           if (method_exists(get_called_class(), 'getTrailerHTML')) {
               $r .= call_user_func(array(get_called_class(), 'getTrailerHTML'), $args);
           }
           return $r;
       }
       ///////////////////////////////////////////////////////////////////
       // At this point there are 3 modes:
       // Adding a new survey
       // editing/showing an existing survey
       // editing/showing an existing occurrence
       // First load the occurrence (and its position sample) if provided
       // Then load the parent sample if provided, or derived from occurrence.
       // $occReadOnly is set if the occurrence has been downloaded. Not even an admin user can modify it in this case.
       data_entry_helper::$javascript .= "\n// Create Layers.\nvar locationLayer, occListLayer, control;\nmapInitialisationHooks.push(function (div) {\n  \"use strict\";\n  // Create vector layers: one to display the location onto, and another for the occurrence list\n  // the default edit layer is used for the occurrences themselves\n  var locStyleMap = new OpenLayers.StyleMap({\n      'default': new OpenLayers.Style({\n        fillColor: 'Green',\n        strokeColor: 'Black',\n        fillOpacity: 0.2,\n        strokeWidth: 1\n  })});\n  locationLayer = new OpenLayers.Layer.Vector('" . lang::get("LANG_Location_Layer") . "', {styleMap: locStyleMap});\n  var occStyleMap = new OpenLayers.StyleMap({\n      'default': new OpenLayers.Style({\n        pointRadius: 3,\n        fillColor: 'Red',\n        fillOpacity: 0.3,\n        strokeColor: 'Red',\n        strokeWidth: 1\n  })});\n  occListLayer = new OpenLayers.Layer.Vector(\"" . lang::get("LANG_Occurrence_List_Layer") . "\", {styleMap: occStyleMap});\n  div.map.addLayer(locationLayer);\n  div.map.addLayer(occListLayer);\n  var control = new OpenLayers.Control.SelectFeature(occListLayer);\n  occListLayer.map.addControl(control);\n  function onPopupClose(evt) {\n    // 'this' is the popup.\n    control.unselect(this.feature);\n  }\n  function onFeatureSelect(evt) {\n    feature = evt.feature;\n    popup = new OpenLayers.Popup.FramedCloud(\"featurePopup\",\n               feature.geometry.getBounds().getCenterLonLat(),\n                             new OpenLayers.Size(100,100),\n                             feature.attributes.taxon + \" (\" + feature.attributes.count + \")\",\n                             null, true, onPopupClose);\n    feature.popup = popup;\n    popup.feature = feature;\n    feature.layer.map.addPopup(popup);\n  }\n  function onFeatureUnselect(evt) {\n    feature = evt.feature;\n    if (feature.popup) {\n        popup.feature = null;\n        feature.layer.map.removePopup(feature.popup);\n        feature.popup.destroy();\n        feature.popup = null;\n    }\n  }\n  occListLayer.events.on({\n    'featureselected': onFeatureSelect,\n    'featureunselected': onFeatureUnselect\n  });\n  control.activate();\n});\n";
       $occReadOnly = false;
       $childSample = array();
       if ($childLoadID) {
           // load the occurrence and its associated sample (which holds the position)
           $url = $svcUrl . '/data/occurrence/' . $childLoadID;
           $url .= "?mode=json&view=detail&auth_token=" . $readAuth['auth_token'] . "&nonce=" . $readAuth["nonce"];
           $session = curl_init($url);
           curl_setopt($session, CURLOPT_RETURNTRANSFER, true);
           $entity = json_decode(curl_exec($session), true);
           if (count($entity) == 0) {
               return '<p>' . lang::get('LANG_No_Access_To_Occurrence') . '</p>';
           }
           foreach ($entity[0] as $key => $value) {
               $childSample['occurrence:' . $key] = $value;
           }
           if ($entity[0]['downloaded_flag'] == 'F') {
               // Final download complete, now readonly
               $occReadOnly = true;
           }
           $url = $svcUrl . '/data/sample/' . $childSample['occurrence:sample_id'];
           $url .= "?mode=json&view=detail&auth_token=" . $readAuth['auth_token'] . "&nonce=" . $readAuth["nonce"];
           $session = curl_init($url);
           curl_setopt($session, CURLOPT_RETURNTRANSFER, true);
           $entity = json_decode(curl_exec($session), true);
           if (count($entity) == 0) {
               return '<p>' . lang::get('LANG_No_Access_To_Occurrence') . '</p>';
           }
           foreach ($entity[0] as $key => $value) {
               $childSample['sample:' . $key] = $value;
           }
           $childSample['sample:geom'] = '';
           // value received from db is not WKT, which is assumed by all the code.
           $childSample['taxon'] = $childSample['occurrence:taxon'];
           $parentLoadID = $childSample['sample:parent_id'];
       }
       $parentSample = array();
       if ($parentLoadID) {
           // load the container master sample
           $url = $svcUrl . '/data/sample/' . $parentLoadID;
           $url .= "?mode=json&view=detail&auth_token=" . $readAuth['auth_token'] . "&nonce=" . $readAuth["nonce"];
           $session = curl_init($url);
           curl_setopt($session, CURLOPT_RETURNTRANSFER, true);
           $entity = json_decode(curl_exec($session), true);
           if (count($entity) == 0) {
               return '<p>' . lang::get('LANG_No_Access_To_Sample') . '</p>';
           }
           foreach ($entity[0] as $key => $value) {
               $parentSample['sample:' . $key] = $value;
           }
           if (is_array($locations) && !in_array($entity[0]["location_id"], $locations)) {
               return '<p>' . lang::get('LANG_No_Access_To_Location') . '</p>';
           }
           if ($entity[0]["parent_id"]) {
               return '<p>' . lang::get('LANG_No_Access_To_Sample') . '</p>';
           }
           $parentSample['sample:date'] = $parentSample['sample:date_start'];
           // bit of a bodge
           $childSample['sample:date'] = $parentSample['sample:date'];
           // enforce a match between child and parent sample dates
           // default values for attributes from DB are picked up automatically.
       }
       data_entry_helper::$entity_to_load = $parentSample;
       $attributes = data_entry_helper::getAttributes(array('id' => data_entry_helper::$entity_to_load['sample:id'], 'valuetable' => 'sample_attribute_value', 'attrtable' => 'sample_attribute', 'key' => 'sample_id', 'fieldprefix' => 'smpAttr', 'extraParams' => $readAuth));
       $closedFieldName = $attributes[$sample_closure_id]['fieldname'];
       $closedFieldValue = data_entry_helper::check_default_value($closedFieldName, array_key_exists('default', $attributes[$sample_closure_id]) ? $attributes[$sample_closure_id]['default'] : '0');
       // default is not closed
       if ($closedFieldValue == '') {
           $closedFieldValue = '0';
       }
       if ($closedFieldValue == '1' && !user_access($args['edit_permission'])) {
           // sample has been closed, no admin perms. Everything now set to read only.
           $surveyReadOnly = true;
           $disabledText = "disabled=\"disabled\"";
           $defAttrOptions = array('extraParams' => $readAuth, 'disabled' => $disabledText);
       } else {
           // sample editable. Admin users can modify closed samples.
           $disabledText = "";
           $defAttrOptions = array('extraParams' => $readAuth);
       }
       // with the AJAX code, we deal with the validation semi manually: Form name is meant be invalid as we only want code included.
       data_entry_helper::enable_validation(null);
       $r .= "<div id=\"controls\">\n";
       $activeTab = 'survey';
       // mode 1 = new Sample, display sample.
       if ($mode == 2) {
           // have specified a sample ID
           if ($args["on_edit_survey_nav"] == "survey") {
               $activeTab = 'survey';
           } else {
               if ($surveyReadOnly || $args["on_edit_survey_nav"] == "list") {
                   $activeTab = 'occurrenceList';
               } else {
                   $activeTab = 'occurrence';
               }
           }
           if ($surveyReadOnly) {
               data_entry_helper::$javascript .= "jQuery('#occ-form').hide();";
           }
       } else {
           if ($mode == 3) {
               // have specified an occurrence ID
               $activeTab = 'occurrence';
           }
       }
       // Set Up form tabs.
       $r .= data_entry_helper::enable_tabs(array('divId' => 'controls', 'active' => $activeTab));
       $r .= "<div id=\"temp\"></div>";
       $r .= data_entry_helper::tab_header(array('tabs' => array('#survey' => lang::get('LANG_Survey'), '#occurrence' => lang::get($surveyReadOnly || $occReadOnly ? 'LANG_Show_Occurrence' : (isset($childSample['sample:id']) ? 'LANG_Edit_Occurrence' : 'LANG_Add_Occurrence')), '#occurrenceList' => lang::get('LANG_Occurrence_List'))));
       // Set up main Survey Form.
       $r .= "<div id=\"survey\" class=\"mnhnl-btw-datapanel\">\n  <p id=\"read-only-survey\"><strong>" . lang::get('LANG_Read_Only_Survey') . "</strong></p>";
       if (user_access($args['edit_permission']) && array_key_exists('sample:id', data_entry_helper::$entity_to_load)) {
           // check for other surveys of same date/transect: only if admin user.
           $url = $svcUrl . '/data/sample?mode=json&view=detail&auth_token=' . $readAuth['auth_token'] . "&nonce=" . $readAuth["nonce"] . "&date_start=" . $parentSample['sample:date_start'] . "&location_id=" . $parentSample['sample:location_id'];
           $session = curl_init($url);
           curl_setopt($session, CURLOPT_RETURNTRANSFER, true);
           $entity = json_decode(curl_exec($session), true);
           if (count($entity) > 1) {
               // ignore ourselves!
               $r .= "<div id=\"mergeSurveys\"><p><strong>" . lang::get('LANG_Found_Mergable_Surveys') . "</strong></p>";
               foreach ($entity as $survey) {
                   if ($survey['id'] != $parentSample['sample:id']) {
                       $r .= "<form action=\"" . url('node/' . $node->nid, array()) . "\" method=\"get\"><input type=\"submit\" value=\"" . lang::get('LANG_Merge_With_ID') . " " . $survey['id'] . "\"><input type=\"hidden\" name=\"merge_sample_id1\" value=\"" . $parentSample['sample:id'] . "\" /><input type=\"hidden\" name=\"merge_sample_id2\" value=\"" . $survey['id'] . "\" /></form>";
                   }
               }
               $r .= "</div>";
           }
       }
       $r .= "<form id=\"SurveyForm\" action=\"" . iform_ajaxproxy_url($node, 'sample') . "\" method=\"post\">\n    <input type=\"hidden\" id=\"website_id\" name=\"website_id\" value=\"" . $args['website_id'] . "\" />\n    <input type=\"hidden\" id=\"sample:survey_id\" name=\"sample:survey_id\" value=\"" . $args['survey_id'] . "\" />";
       if (array_key_exists('sample:id', data_entry_helper::$entity_to_load)) {
           $r .= "<input type=\"hidden\" id=\"sample:id\" name=\"sample:id\" value=\"" . data_entry_helper::$entity_to_load['sample:id'] . "\" />\n";
       } else {
           $r .= "<input type=\"hidden\" id=\"sample:id\" name=\"sample:id\" value=\"\" disabled=\"disabled\" />\n";
           // GvB 19/Nov/2012 : change to user detail defaults
           // logic is now much simpler, and they are only included/created if the sample is new.
           $fieldName = $attributes[$uid_attr_id]['fieldname'];
           $fieldValue = data_entry_helper::check_default_value($fieldName, $user->uid);
           $r .= "<input type=\"hidden\" name=\"" . $fieldName . "\" value=\"" . $fieldValue . "\" />\n";
           $fieldName = $attributes[$email_attr_id]['fieldname'];
           $fieldValue = data_entry_helper::check_default_value($fieldName, $user->mail);
           $r .= "<input type=\"hidden\" name=\"" . $fieldName . "\" value=\"" . $fieldValue . "\" />\n";
           $fieldName = $attributes[$username_attr_id]['fieldname'];
           $fieldValue = data_entry_helper::check_default_value($fieldName, $user->name);
           $r .= "<input type=\"hidden\" name=\"" . $fieldName . "\" value=\"" . $fieldValue . "\" />\n";
       }
       $defAttrOptions['validation'] = array('required');
       if ($locations == 'all') {
           $locOptions = array_merge(array('label' => lang::get('LANG_Transect')), $defAttrOptions);
           $locOptions['extraParams'] = array_merge(array('parent_id' => 'NULL', 'view' => 'detail', 'orderby' => 'name'), $locOptions['extraParams']);
           $r .= data_entry_helper::location_select($locOptions);
       } else {
           // can't use location select due to location filtering.
           $r .= "<label for=\"imp-location\">" . lang::get('LANG_Transect') . ":</label>\n<select id=\"imp-location\" name=\"sample:location_id\" " . $disabled_text . " class=\" \"  >";
           $url = $svcUrl . '/data/location?mode=json&view=detail&parent_id=NULL&orderby=name&auth_token=' . $readAuth['auth_token'] . '&nonce=' . $readAuth["nonce"];
           $session = curl_init($url);
           curl_setopt($session, CURLOPT_RETURNTRANSFER, true);
           $entities = json_decode(curl_exec($session), true);
           if (!empty($entities)) {
               foreach ($entities as $entity) {
                   if (in_array($entity["id"], $locations)) {
                       if ($entity["id"] == data_entry_helper::$entity_to_load['sample:location_id']) {
                           $selected = 'selected="selected"';
                       } else {
                           $selected = '';
                       }
                       $r .= "<option value=\"" . $entity["id"] . "\" " . $selected . ">" . $entity["name"] . "</option>";
                   }
               }
           }
           $r .= "</select><span class=\"deh-required\">*</span><br />";
       }
       $languageFilteredAttrOptions = $defAttrOptions + array('language' => iform_lang_iso_639_2($args['language']));
       $r .= data_entry_helper::outputAttribute($attributes[$sample_walk_direction_id], $languageFilteredAttrOptions) . ($sample_reliability_id ? data_entry_helper::outputAttribute($attributes[$sample_reliability_id], $languageFilteredAttrOptions) : "<span style=\"display: none;\">Sample attribute '" . self::ATTR_RELIABILITY . "' not assigned to this survey</span>") . data_entry_helper::outputAttribute($attributes[$sample_visit_number_id], array_merge($languageFilteredAttrOptions, array('default' => 1, 'noBlankText' => true)));
       if (isset(data_entry_helper::$entity_to_load['sample:date']) && preg_match('/^(\\d{4})/', data_entry_helper::$entity_to_load['sample:date'])) {
           // Date has 4 digit year first (ISO style) - convert date to expected output format
           $d = new DateTime(data_entry_helper::$entity_to_load['sample:date']);
           data_entry_helper::$entity_to_load['sample:date'] = $d->format('d/m/Y');
       }
       if ($args['language'] != 'en') {
           data_entry_helper::add_resource('jquery_ui_' . $args['language']);
       }
       // this will autoload the jquery_ui resource. The date_picker does not have access to the args.
       if ($surveyReadOnly) {
           $r .= data_entry_helper::text_input(array_merge($defAttrOptions, array('label' => lang::get('LANG_Date'), 'fieldname' => 'sample:date', 'disabled' => $disabledText)));
       } else {
           $r .= data_entry_helper::date_picker(array('label' => lang::get('LANG_Date'), 'fieldname' => 'sample:date', 'class' => 'vague-date-picker'));
       }
       $r .= ($sample_wind_id ? data_entry_helper::outputAttribute($attributes[$sample_wind_id], $languageFilteredAttrOptions) : "<span style=\"display: none;\">Sample attribute '" . self::ATTR_WIND . "' not assigned to this survey</span>") . ($sample_precipitation_id ? data_entry_helper::outputAttribute($attributes[$sample_precipitation_id], $languageFilteredAttrOptions) : "<span style=\"display: none;\">Sample attribute '" . self::ATTR_RAIN . "' not assigned to this survey</span>") . ($sample_temperature_id ? data_entry_helper::outputAttribute($attributes[$sample_temperature_id], array_merge($defAttrOptions, array('suffixTemplate' => 'nosuffix'))) . "<span class=\"attr-trailer\"> &deg;C</span><br />" : "<span style=\"display: none;\">Sample attribute '" . self::ATTR_TEMP . "' not assigned to this survey</span>") . ($sample_cloud_id ? data_entry_helper::outputAttribute($attributes[$sample_cloud_id], $defAttrOptions) : "<span style=\"display: none;\">Sample attribute '" . self::ATTR_CLOUD . "' not assigned to this survey</span>") . ($sample_start_time_id ? data_entry_helper::outputAttribute($attributes[$sample_start_time_id], array_merge($defAttrOptions, array('suffixTemplate' => 'nosuffix'))) . "<span class=\"attr-trailer\"> hh:mm</span><br />" : "<span style=\"display: none;\">Sample attribute '" . self::ATTR_START_TIME . "' not assigned to this survey</span>") . ($sample_end_time_id ? data_entry_helper::outputAttribute($attributes[$sample_end_time_id], array_merge($defAttrOptions, array('suffixTemplate' => 'nosuffix'))) . "<span class=\"attr-trailer\"> hh:mm</span><br />" : "<span style=\"display: none;\">Sample attribute '" . self::ATTR_END_TIME . "' not assigned to this survey</span>");
       data_entry_helper::$javascript .= "\njQuery('.attr-trailer').prev('br').remove();\n";
       unset($defAttrOptions['suffixTemplate']);
       unset($defAttrOptions['validation']);
       if (user_access($args['edit_permission'])) {
           //  users with admin permissions can override the closing of the
           // sample by unchecking the checkbox.
           // Because this is attached to the sample, we have to include the sample required fields in the
           // the post. This means they can't be disabled, so we enable all fields in this case.
           // Normal users can only set this to closed, and they do this using a button/hidden field.
           $r .= data_entry_helper::outputAttribute($attributes[$sample_closure_id], $defAttrOptions);
           // In addition admin users can delete a survey/sample.
           $r .= data_entry_helper::checkbox(array('label' => lang::get('Deleted'), 'fieldname' => 'sample:deleted', 'id' => 'main-sample-deleted'));
       } else {
           // hidden closed
           $r .= "<input type=\"hidden\" id=\"main-sample-closed\" name=\"" . $closedFieldName . "\" value=\"" . $closedFieldValue . "\" />\n";
       }
       data_entry_helper::$javascript .= "\n\$.validator.messages.required = \"" . lang::get('validation_required') . "\";\n\$.validator.defaults.onsubmit = false; // override default - so that we handle all submission validation.\n";
       if (!$surveyReadOnly) {
           // NB that we don't even include the buttons when readonly.
           data_entry_helper::$javascript .= "\njQuery('#read-only-survey').hide();\njQuery('#ro-sur-occ-warn').hide();\n";
           $r .= "<input type=button id=\"close1\" class=\"ui-state-default ui-corner-all \" value=\"" . lang::get('LANG_Save_Survey_Details') . "\";\n        onclick=\"var result = \$('#SurveyForm input').valid();\n          var result2 = \$('#SurveyForm select').valid();\n          if (!result || !result2) {\n              return;\n            }\n            jQuery('#close1').addClass('loading-button');\n            jQuery('#SurveyForm').submit();\">\n";
           if (!user_access($args['edit_permission'])) {
               if ($mode == 1) {
                   data_entry_helper::$javascript .= "jQuery('#close2').hide();\n";
               }
               $r .= "<input type=button id=\"close2\" class=\"ui-state-default ui-corner-all \" value=\"" . lang::get('LANG_Save_Survey_And_Close') . "\"\n        onclick=\"if(confirm('" . lang::get('LANG_Close_Survey_Confirm') . "')){\n          var result = \$('#SurveyForm input').valid();\n          var result2 = \$('#SurveyForm select').valid();\n          if (!result || !result2) {\n              return;\n            }\n            jQuery('#main-sample-closed').val('1');\n            jQuery('#close2').addClass('loading-button');\n            jQuery('#SurveyForm').submit();\n          };\">\n";
           }
       }
       $r .= "</form></div>\n";
       data_entry_helper::$javascript .= "\nalertIndiciaError = function(data){\n\tvar errorString = \"" . lang::get('LANG_Indicia_Warehouse_Error') . "\";\n\tif(data.error){\terrorString = errorString + ' : ' + data.error;\t}\n\tif(data.errors){\n\t\tfor (var i in data.errors){\n\t\t\terrorString = errorString + ' : ' + data.errors[i];\n\t\t}\n\t}\n\talert(errorString);\n\t// the most likely cause is authentication failure - eg the read authentication has timed out.\n\t// prevent further use of the form:\n\t\$('.loading-panel').remove();\n\t\$('.loading-hide').removeClass('loading-hide');\n};\nerrorPos = null;\nclearErrors = function(formSel) {\n\tjQuery(formSel).find('.inline-error').remove();\n\terrorPos = null;\n};\nmyScrollTo = function(selector){\n\tjQuery(selector).filter(':visible').each(function(){\n\t\tif(errorPos == null || jQuery(this).offset().top < errorPos){\n\t\t\terrorPos = jQuery(this).offset().top;\n\t\t\twindow.scroll(0,errorPos);\n\t\t}\n\t});\n};\nmyScrollToError = function(){\n\tjQuery('.inline-error,.error').filter(':visible').prev().each(function(){\n\t\tif(errorPos == null || jQuery(this).offset().top < errorPos){\n\t\t\terrorPos = jQuery(this).offset().top;\n\t\t\twindow.scroll(0,errorPos);\n\t\t}\n\t});\n};\njQuery('#SurveyForm').ajaxForm({\n\tasync: false,\n\tdataType:  'json',\n    beforeSubmit:   function(data, obj, options){\n    \tvar valid = true;\n    \tclearErrors('form#SurveyForm');\n    \tif (!jQuery('form#SurveyForm > input').valid()) {\n\t\t\tmyScrollToError();\n  \t\t\tjQuery('.loading-button').removeClass('loading-button');\n\t\t\treturn false;\n  \t\t};\n  \t\tSurveyFormRetVal = true;\n  \t\tif(jQuery('#main-sample-deleted:checked').length == 0){ // only do check if not deleting\n          jQuery.ajax({ // now check if there are any other samples with this combination of date and location\n            type: 'GET',\n            url: \"" . $svcUrl . "/data/sample?mode=json&view=detail\" +\n                \"&nonce=" . $readAuth['nonce'] . "&auth_token=" . $readAuth['auth_token'] . "\" +\n                \"&orderby=id&callback=?&location_id=\"+jQuery('#imp-location').val()+\"&date_start=\"+jQuery('#SurveyForm [name=sample\\:date]').val(),\n            data: {},\n            success: function(detData) {\n              for(i=0, j=0; i< detData.length; i++){\n                if(detData[i].id != jQuery('#SurveyForm [name=sample\\:id]').val()) j++;\n              }\n              if(j) {\n              \tSurveyFormRetVal = confirm(\"" . lang::get('LANG_Survey_Already_Exists') . "\");\n              }\n            },\n            dataType: 'json',\n            async: false\n          });\n        }\n\t\treturn SurveyFormRetVal;\n\t},\n    success:   function(data){\n       // this will leave all the fields populated.\n       \tif(data.success == 'multiple records' && data.outer_table == 'sample'){\n          jQuery('#occ-form').show();\n          jQuery('#na-occ-warn,#mergeSurveys').hide();";
       if (!user_access($args['edit_permission'])) {
           // don't need to worry about record_status value for non admins as they can't modify when closed.
           data_entry_helper::$javascript .= "\n          if(jQuery('#main-sample-closed').val() == '1'){\n            jQuery('#read-only-survey,#ro-sur-occ-warn').show();\n            jQuery('#close1,#close2,#occ-form').hide(); //can't enter any more occurrences\n            jQuery('#SurveyForm').children().attr('disabled','disabled');\n          };\n";
       } else {
           data_entry_helper::$javascript .= "\n          jQuery('#occurrence\\\\:record_status').val(jQuery('#smpAttr\\\\:" . $attributes[$sample_closure_id]['attributeId'] . ":checked').length > 0 ? 'C' : 'I');\n          if(jQuery('#main-sample-deleted:checked').length > 0){\n            jQuery('#return-to-main').click();\n            return;\n          };\n";
       }
       data_entry_helper::$javascript .= "// If sample_id filled in -> we have a previously saved collection, so possibly have subsamples.\nif(jQuery('#SurveyForm > input[name=sample\\:id]').val() != ''){\n    // Put up warning dialogue that we are checking the subsamples: include a progress bar: set to zero%.\n    var dialog = \$('<span id=\"subsample-progress-span\"><p>'+\"" . lang::get('Please wait whilst some data integrity checks are carried out.') . "\"+'</p><div id=\"subsample-progress\"></div></span>').dialog({ title: \"" . lang::get('Checks') . "\", zIndex: 4000 });\n    jQuery('#subsample-progress').progressbar({value: 0});\n    jQuery.ajax({ // get all subsamples/occurrences to check if the dates match\n            type: 'GET',\n            url: \"" . $svcUrl . "/report/requestReport?report=library/occurrences/occurrences_list_for_parent_sample.xml&reportSource=local&mode=json&nonce=" . $readAuth['nonce'] . "&auth_token=" . $readAuth['auth_token'] . "\" +\n                \"&callback=?&sample_id=\"+data.outer_id+\"&survey_id=&date_from=&date_to=&taxon_group_id=&smpattrs=&occattrs=\",\n            data: {},\n            success: function(subData) {\n              jQuery('#subsample-progress').data('max',subData.length+1);\n              var mainDate = \$.datepicker.formatDate('yy-mm-dd', jQuery('#SurveyForm > input[name=sample\\:date]').datepicker(\"getDate\"));\n              for(i=0; i< subData.length; i++){ // loop through all subsamples\n                jQuery('#subsample-progress').progressbar('option','value',(i+1)*100/jQuery('#subsample-progress').data('max'));\n                var values = {};\n                var url = '';\n                // Check if date on subsamples matches supersample date: if not set up a post array for the sample, with correct date.\n                if(subData[i].date_start != mainDate){\n                  values['sample:id']=subData[i].sample_id;\n                  values['sample:date']=mainDate;\n                  url=\"" . iform_ajaxproxy_url($node, 'sample') . "\";\n                }\n";
       // Send AJAX request to set occurrence to 'C' if closed : use sync
       if (!user_access($args['edit_permission'])) {
           data_entry_helper::$javascript .= "                if(jQuery('#main-sample-closed').val() == '1'){\n";
       } else {
           data_entry_helper::$javascript .= "                if(jQuery('#smpAttr\\\\:" . $attributes[$sample_closure_id]['attributeId'] . ":checked').length > 0){\n";
       }
       // If records are already verified, they are left verified, as if the records themselves are saved
       // they will flagged as no longer verified: But have to force a re verification if date is changed.
       data_entry_helper::$javascript .= "\n                  if(subData[i].record_status == 'I' || typeof values['sample:id'] != 'undefined'){\n                    values['occurrence:id']=subData[i].occurrence_id;\n                    values['occurrence:record_status']='C';\n                    url=(url == '' ? \"" . iform_ajaxproxy_url($node, 'occurrence') . "\" : \"" . iform_ajaxproxy_url($node, 'smp-occ') . "\");\n                  }\n                } else { // any occurrences on unclosed collections must be flagged as 'I' - reopening unverifies.\n                  if(subData[i].record_status != 'I'){\n                    values['occurrence:id']=subData[i].occurrence_id;\n                    values['occurrence:record_status']='I';\n                    url=(url == '' ? \"" . iform_ajaxproxy_url($node, 'occurrence') . "\" : \"" . iform_ajaxproxy_url($node, 'smp-occ') . "\");\n                  }\n                }\n                if(url!=''){\n                  values['website_id']=" . $args['website_id'] . ";\n                  jQuery.ajax({ type: 'POST', url: url, data: values, dataType: 'json', async: false});\n                }\n              }\n            },\n            dataType: 'json',\n            async: false\n    });\n    dialog.dialog('close');\n    dialog.dialog('destroy');\n    jQuery('#subsample-progress-span').remove();\n}\n\n\t\t\twindow.scroll(0,0);\n            jQuery('#SurveyForm > input[name=sample\\:id]').removeAttr('disabled').val(data.outer_id);\n            jQuery('#occ-form > input[name=sample\\:parent_id]').val(data.outer_id);\n            jQuery('#occ-form > input[name=sample\\:date]').val(jQuery('#SurveyForm > input[name=sample\\:date]').val());\n            loadAttributes('sample_attribute_value', 'sample_attribute_id', 'sample_id', data.outer_id, 'smpAttr');\n            switch(\"" . $args["on_save_survey_nav"] . "\"){\n\t\t\t\tcase \"list\":\n\t\t\t\t\tvar a = \$('ul.ui-tabs-nav a')[2];\n\t\t\t\t\t\$(a).click();\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"survey\":\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:";
       if (!user_access($args['edit_permission'])) {
           data_entry_helper::$javascript .= "\n\t\t\t\t\tif(jQuery('#main-sample-closed').val() == 0){\n\t\t\t\t\t\tvar a = \$('ul.ui-tabs-nav a')[1];\n\t\t\t\t\t\t\$(a).click();\n\t\t\t\t\t};";
       } else {
           data_entry_helper::$javascript .= "\n\t\t\t\t\tvar a = \$('ul.ui-tabs-nav a')[1];\n\t\t\t\t\t\$(a).click();";
       }
       data_entry_helper::$javascript .= "\n\t\t\t\t\tbreak;\n\t\t\t}\n        } else {\n\t\t\tif(data.error){\n\t\t\t\tvar lastIndex = data.error.lastIndexOf('Validation error');\n    \t\t\tif (lastIndex != -1 && lastIndex  == (data.error.length - 16)){\n\t\t\t\t\tif(data.errors){\n\t\t\t\t\t\t// TODO translation\n\t\t\t\t\t\tfor (i in data.errors){\n\t\t\t\t\t\t\tvar label = \$('<p/>').addClass('inline-error').html(data.errors[i]);\n\t\t\t\t\t\t\tlabel.insertAfter('[name='+i+']');\n\t\t\t\t\t\t}\n\t\t\t\t\t\tmyScrollToError();\n\t\t\t\t\t\treturn;\n  \t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\talertIndiciaError(data);\n        }\n\t},\n    complete: function (){\n  \t\tjQuery('.loading-button').removeClass('loading-button');\n  \t}\n});\n// In this case, all the samples attributes are on the survey tab, and all the occurrence attributes are on the occurrence tab. No need to worry about getting the correct form.\nloadAttributes = function(attributeTable, attributeKey, key, keyValue, prefix){\n    jQuery.ajax({\n        type: \"GET\",\n        url: \"" . $svcUrl . "/data/\" + attributeTable + \"?mode=json&view=list\" +\n        \t\"&reset_timeout=true&nonce=" . $readAuth['nonce'] . "&auth_token=" . $readAuth['auth_token'] . "\" +\n   \t\t\t\"&\" + key + \"=\" + keyValue + \"&callback=?\",\n        data: {},\n        success: (function(attrPrefix, attrKey) {\n          var retVal = function(attrdata) {\n            if(!(attrdata instanceof Array)){\n              alertIndiciaError(attrdata);\n            } else if (attrdata.length>0) {\n              for (var i=0;i<attrdata.length;i++){\n                // in all cases if the attribute already has the <prefix>:<X>:<Y> format name we leave. Other wise we update <prefix>:<X> to <prefix>:<X>:<Y>\n                // We leave all values unchanged.\n                // need to be careful about Cloud: this is a drop down, but it is not language specific: the termlist is\n                // always in english, so the iso won't match.\n                if (attrdata[i].id){\n                  if (attrdata[i].iso == null || attrdata[i].iso == '') // no iso - not a look up.\n                    jQuery('[name='+attrPrefix+'\\:'+attrdata[i][attrKey]+']').attr('name', attrPrefix+':'+attrdata[i][attrKey]+':'+attrdata[i].id);\n                  else {\n                    if (attrdata[i].iso == '" . $language . "') // this is our actual language so OK\n                      jQuery('[name='+attrPrefix+'\\:'+attrdata[i][attrKey]+']').attr('name', attrPrefix+':'+attrdata[i][attrKey]+':'+attrdata[i].id);\n                    else {// not our language: look up all the other attrs, and if we don't find one of this id for our language, use this one.\n                      var found = false;\n                      for (var j=0;j<attrdata.length;j++)\n                        found = found || (i!=j && attrdata[i][attrKey] == attrdata[j][attrKey] && attrdata[j].iso == '" . $language . "');\n                      if(!found)\n                        jQuery('[name='+attrPrefix+'\\:'+attrdata[i][attrKey]+']').attr('name', attrPrefix+':'+attrdata[i][attrKey]+':'+attrdata[i].id);\n                    }\n                  }\n                }\n              }\n            }};\n          return retVal;\n          })(prefix, attributeKey),\n\t\tdataType: 'json',\n\t    async: false\n\t});\n}";
       // Set up Occurrence List tab: don't include when creating a new sample as it will have no occurrences
       // Grid populated at a later point
       $r .= "<div id=\"occurrenceList\" class=\"mnhnl-btw-datapanel\"><div id=\"occ_grid\"></div>\n  <form method=\"post\" action=\"" . data_entry_helper::$base_url . "/index.php/services/report/requestReport?report=reports_for_prebuilt_forms/MNHNL/mnhnl_btw_occurrences_report.xml&reportSource=local&auth_token=" . $readAuth['auth_token'] . "&nonce=" . $readAuth['nonce'] . "&mode=csv\">\n    <input type=\"hidden\" id=\"params\" name=\"params\" value='{\"survey_id\":" . $args['survey_id'] . ", \"sample_id\":" . data_entry_helper::$entity_to_load['sample:id'] . "}' />\n    <input type=\"submit\" class=\"ui-state-default ui-corner-all\" value=\"" . lang::get('LANG_Download_Occurrences') . "\">\n  </form></div>";
       if ($occReadOnly) {
           // NB that we don't even include the buttons when readonly.
           data_entry_helper::$javascript .= "\njQuery('#ro-occ-occ-warn').show();\njQuery('#ro-sur-occ-warn').hide();\n";
       } else {
           data_entry_helper::$javascript .= "\njQuery('#ro-occ-occ-warn').hide();\n";
       }
       if ($mode == 1) {
           data_entry_helper::$javascript .= "jQuery('#occ-form').hide();";
       } else {
           data_entry_helper::$javascript .= "jQuery('#na-occ-warn').hide();";
       }
       // Set up Occurrence tab: don't allow entry of a new occurrence until after top level sample is saved.
       data_entry_helper::$entity_to_load = $childSample;
       $attributes = data_entry_helper::getAttributes(array('id' => data_entry_helper::$entity_to_load['occurrence:id'], 'valuetable' => 'occurrence_attribute_value', 'attrtable' => 'occurrence_attribute', 'key' => 'occurrence_id', 'fieldprefix' => 'occAttr', 'extraParams' => $readAuth));
       $extraParams = $readAuth + array('taxon_list_id' => $args['list_id'], 'view' => 'detail', 'query' => urlencode(json_encode(array('in' => array('language_iso', array('lat', iform_lang_iso_639_2($args['language'])))))));
       if ($occReadOnly) {
           // if the occurrence has been downloaded, no one can modify it.
           $disabledText = "disabled=\"disabled\"";
           $defAttrOptions['disabled'] = $disabledText;
       }
       $species_ctrl_args = array('label' => lang::get('LANG_Species'), 'fieldname' => 'occurrence:taxa_taxon_list_id', 'table' => 'taxa_taxon_list', 'captionField' => 'taxon', 'valueField' => 'id', 'columns' => 2, 'extraParams' => $extraParams, 'disabled' => $disabledText, 'defaultCaption' => data_entry_helper::$entity_to_load['occurrence:taxon']);
       $r .= "  <div id=\"occurrence\" class=\"mnhnl-btw-datapanel\">\n    <p id=\"ro-occ-occ-warn\"><strong>" . lang::get('LANG_Read_Only_Occurrence') . "</strong></p>\n    <p id=\"ro-sur-occ-warn\"><strong>" . lang::get('LANG_Read_Only_Survey') . "</strong></p>\n    <p id=\"na-occ-warn\"><strong>" . lang::get('LANG_Page_Not_Available') . "</strong></p>\n    <form method=\"post\" id=\"occ-form\" action=\"" . iform_ajaxproxy_url($node, 'smp-occ') . "\" >\n    <input type=\"hidden\" id=\"website_id\" name=\"website_id\" value=\"" . $args['website_id'] . "\" />\n    <input type=\"hidden\" id=\"sample:survey_id\" name=\"sample:survey_id\" value=\"" . $args['survey_id'] . "\" />\n    <input type=\"hidden\" id=\"sample:parent_id\" name=\"sample:parent_id\" value=\"" . $parentSample['sample:id'] . "\" />\n    <input type=\"hidden\" id=\"sample:date\" name=\"sample:date\" value=\"" . data_entry_helper::$entity_to_load['sample:date'] . "\" />\n    <input type=\"hidden\" id=\"sample:id\" name=\"sample:id\" value=\"" . data_entry_helper::$entity_to_load['sample:id'] . "\" />\n    <input type=\"hidden\" id=\"occurrence:id\" name=\"occurrence:id\" value=\"" . data_entry_helper::$entity_to_load['occurrence:id'] . "\" />\n    <input type=\"hidden\" id=\"occurrence:record_status\" name=\"occurrence:record_status\" value=\"" . ($closedFieldValue == '0' ? 'I' : 'C') . "\" />\n    <input type=\"hidden\" id=\"occurrence:downloaded_flag\" name=\"occurrence:downloaded_flag\" value=\"N\" />\n    " . data_entry_helper::autocomplete($species_ctrl_args) . "\n    " . ($occurrence_confidence_id ? data_entry_helper::outputAttribute($attributes[$occurrence_confidence_id], array_merge($languageFilteredAttrOptions, array('noBlankText' => ''))) : "<span style=\"display: none;\">Occurrence attribute '" . self::ATTR_CONFIDENCE . "' not assigned to this survey</span>") . "\n    " . data_entry_helper::sref_and_system(array('label' => lang::get('LANG_Spatial_ref'), 'systems' => array('2169' => 'Luref (Gauss Luxembourg)'))) . "\n    <p>" . lang::get('LANG_Click_on_map') . "</p>\n    " . data_entry_helper::outputAttribute($attributes[$occurrence_count_id], array_merge($defAttrOptions, array('default' => 1))) . "\n    " . ($occurrence_approximation_id ? data_entry_helper::outputAttribute($attributes[$occurrence_approximation_id], $defAttrOptions) : "<span style=\"display: none;\">Occurrence attribute '" . self::ATTR_APPROXIMATION . "' not assigned to this survey</span>") . "\n    " . data_entry_helper::outputAttribute($attributes[$occurrence_territorial_id], array_merge($defAttrOptions, array('default' => 1, 'id' => 'occ-territorial'))) . "\n    " . data_entry_helper::outputAttribute($attributes[$occurrence_atlas_code_id], $languageFilteredAttrOptions) . "\n    " . ($occurrence_overflying_id ? data_entry_helper::outputAttribute($attributes[$occurrence_overflying_id], $defAttrOptions) : "<span style=\"display: none;\">Occurrence attribute '" . self::ATTR_OVERFLYING . "' not assigned to this survey</span>") . "\n    " . data_entry_helper::textarea(array('label' => lang::get('LANG_Comment'), 'fieldname' => 'occurrence:comment', 'disabled' => $disabledText));
       if (!$surveyReadOnly && !$occReadOnly) {
           if ($mode == 3) {
               $r .= data_entry_helper::checkbox(array('label' => lang::get('Delete'), 'fieldname' => 'sample:deleted', 'id' => 'occ-sample-deleted'));
           }
           $r .= "<input type=\"submit\" id=\"occ-submit\" class=\"ui-state-default ui-corner-all\" value=\"" . lang::get('LANG_Save_Occurrence_Details') . "\" />";
       }
       $r .= "  </form>\n";
       data_entry_helper::$javascript .= "\n// because of ID tracking it is easier to rebuild entire list etc.\nretriggerGrid = function(){\n  \$('div#occ_grid').empty();\n  occListLayer.destroyFeatures();\n  activateAddList = 1;\n  thisOccID = -1;\n  \$('div#occ_grid').indiciaDataGrid('rpt:reports_for_prebuilt_forms/MNHNL/mnhnl_btw_list_occurrences', {\n    indiciaSvc: '" . $svcUrl . "',\n    dataColumns: ['taxon', 'territorial', 'count'],\n    reportColumnTitles: {taxon : '" . lang::get('LANG_Species') . "', territorial : '" . lang::get('LANG_Territorial') . "', count : '" . lang::get('LANG_Count') . "'},\n    actionColumns: {'" . lang::get('LANG_Show') . "' : \"" . url('node/' . $node->nid, array('query' => 'occurrence_id=£id£')) . "\",\n            '" . lang::get('LANG_Highlight') . "' : \"script:highlight(£id£);\"},\n    auth : { nonce : '" . $readAuth['nonce'] . "', auth_token : '" . $readAuth['auth_token'] . "'},\n    parameters : { survey_id : '" . $args['survey_id'] . "',\n            parent_id : jQuery('#SurveyForm [name=sample\\:id]').val(),\n            territorial_attr_id : '" . $occurrence_territorial_id . "',\n            count_attr_id : '" . $occurrence_count_id . "'},\n    itemsPerPage : 12,\n    callback : addListFeature ,\n    cssOdd : ''\n  });\n}\n\njQuery('#occ-form').ajaxForm({\n\tasync: false,\n\tdataType:  'json',\n    beforeSubmit:   function(data, obj, options){\n    \tvar valid = true;\n    \tclearErrors('form#occ-form');\n    \tif (!jQuery('form#occ-form > input').valid()) { valid = false; }\n    \tif (!jQuery('form#occ-form > select').valid()) { valid = false; }\n    \tif(!valid) {\n\t\t\tmyScrollToError();\n\t\t\treturn false;\n\t\t};\n\t\tjQuery('#occ-submit').addClass('loading-button');\n\t\treturn true;\n\t},\n    success:   function(data){\n       // this will leave all the fields populated.\n       \tif(data.success == 'multiple records' && data.outer_table == 'sample'){\n\t\t\twindow.scroll(0,0);\n\t\t\t// cant use reset form, as returns it to original values: if this was called with occurrence_id =<x> then it would repopulate with original occurrence's values\n\t\t\t// website_id, survey_id, record_status, downloaded_flag, sample:entered_sref_system are constants and are left alone. parent_id, date are only set referring to parent sample.\n\t\t\tjQuery('form#occ-form').find('[name^=occAttr\\:]').each(function(){\n\t\t\t\tvar name = jQuery(this).attr('name').split(':');\n\t\t\t\tjQuery(this).attr('name', name[0]+':'+name[1]);\n\t\t\t});\n\t\t\tjQuery('form#occ-form').find('[name=occurrence\\:id],[name=sample\\:id]').val('').attr('disabled', 'disabled');\n\t\t\tjQuery('form#occ-form').find('[name=occurrence\\:taxa_taxon_list_id],[name=occurrence\\:taxa_taxon_list_id\\:taxon],[name=sample\\:entered_sref],[name=sample\\:geom],[name=occurrence\\:comment]').val('');\n\t\t\tjQuery('form#occ-form').find('[name=occAttr\\:" . $occurrence_confidence_id . "]').find('option').removeAttr('selected');\n\t\t\tjQuery('form#occ-form').find('[name=occAttr\\:" . $occurrence_count_id . "]').val('1');\n\t\t\tjQuery('form#occ-form').find('input[name=occAttr\\:" . $occurrence_approximation_id . "],input[name=occAttr\\:" . $occurrence_overflying_id . "]').removeAttr('checked','checked');\n\t\t\tjQuery('form#occ-form').find('#occ-territorial').attr('checked','checked');\n\t\t\tjQuery('label[for=occ-sample-deleted]').remove(); // sample deleted only applicable when editing an existing occurrence. After saving reverts to Add Occurreence: no delete. Remove label then actual checkbox\n\t\t\tjQuery('form#occ-form').find('[name=sample\\:deleted]').remove(); // This removes both parts of the checkbox.\n\t\t\tsetAtlasStatus();\n\t\t\tretriggerGrid();\n\t\t\tlocationLayer.map.editLayer.destroyFeatures();\n\t\t\tvar a = \$('ul.ui-tabs-nav a')[1];\n\t\t\t\$(a).empty().html('<span>" . lang::get('LANG_Add_Occurrence') . "</span>');\n\t\t\tswitch(\"" . $args["on_save_occurrence_nav"] . "\"){\n\t\t\t\tcase \"list\":\n\t\t\t\t\ta = \$('ul.ui-tabs-nav a')[2];\n\t\t\t\t\t\$(a).click();\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"survey\":\n\t\t\t\t\ta = \$('ul.ui-tabs-nav a')[0];\n\t\t\t\t\t\$(a).click();\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tbreak;\n\t\t\t}\n        } else {\n\t\t\tif(data.error){\n\t\t\t\tvar lastIndex = data.error.lastIndexOf('Validation error');\n    \t\t\tif (lastIndex != -1 && lastIndex  == (data.error.length - 16)){\n\t\t\t\t\tif(data.errors){\n\t\t\t\t\t\t// TODO translation\n\t\t\t\t\t\tfor (i in data.errors){\n\t\t\t\t\t\t\tvar label = \$('<p/>').addClass('inline-error').html(data.errors[i]);\n\t\t\t\t\t\t\tlabel.insertAfter('[name='+i+']');\n\t\t\t\t\t\t}\n\t\t\t\t\t\tmyScrollToError();\n\t\t\t\t\t\treturn;\n  \t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\talertIndiciaError(data);\n        }\n\t},\n    complete: function (){\n  \t\tjQuery('.loading-button').removeClass('loading-button');\n  \t}\n});\nsetAtlasStatus = function() {\n  if (jQuery(\"#occ-territorial:checked\").length == 0) {\n      jQuery(\"select[name=occAttr\\:" . $occurrence_atlas_code_id . "],select[name^=occAttr\\:" . $occurrence_atlas_code_id . "\\:]\").val('');\n  } else {\n      if(jQuery(\"select[name=occAttr\\:" . $occurrence_atlas_code_id . "],select[name^=occAttr\\:" . $occurrence_atlas_code_id . "\\:]\").val() == '') {\n        // Find the BB02 option (depends on the language what val it has)\n        var bb02;\n        jQuery.each(jQuery(\"select[name=occAttr\\:" . $occurrence_atlas_code_id . "],select[name^=occAttr\\:" . $occurrence_atlas_code_id . "\\:]\").find('option'), function(index, option) {\n          if (option.text.substr(0,4)=='BB02') {\n            bb02 = option.value;\n            return; // just from the each loop\n          }\n        });\n        jQuery(\"select[name=occAttr\\:" . $occurrence_atlas_code_id . "],select[name^=occAttr\\:" . $occurrence_atlas_code_id . "\\:]\").val(bb02);\n      }\n  }\n};\njQuery(\"#occ-territorial\").change(setAtlasStatus);\nif(\$.browser.msie) {\n    jQuery(\"#occ-territorial\").click(function() {\n        \$(this).change();\n    });\n}\n\n";
       if ($mode != 3) {
           data_entry_helper::$javascript .= "setAtlasStatus();\n";
       }
       // reset the atlas when not looking at a old occurrence.
       $r .= '</div>';
       // add map panel.
       $options = iform_map_get_map_options($args, $readAuth);
       $olOptions = iform_map_get_ol_options($args);
       // $options['layers'] = array('locationLayer', 'occListLayer');
       $options['searchLayer'] = 'false';
       $options['initialFeatureWkt'] = null;
       $options['proxy'] = '';
       $options['scroll_wheel_zoom'] = false;
       $options['width'] = 'auto';
       // TBD remove from arglist
       $r .= "<div class=\"mnhnl-btw-mappanel\">\n";
       $r .= data_entry_helper::map_panel($options, $olOptions);
       // for timing reasons, all the following has to be done after the map is loaded.
       // 1) feature selector for occurrence list must have the map present to attach the control
       // 2) location placer must have the location layer populated and the map present in
       //    order to zoom the map into the location.
       // 3) occurrence list feature adder must have map present in order to zoom into any
       //    current selection.
       data_entry_helper::$onload_javascript .= "\n\n\nlocationChange = function(obj){\n  locationLayer.destroyFeatures();\n  if(obj.value != ''){\n    jQuery.getJSON(\"" . $svcUrl . "\" + \"/data/location/\"+obj.value +\n      \"?mode=json&view=detail&auth_token=" . $readAuth['auth_token'] . "&nonce=" . $readAuth["nonce"] . "\" +\n      \"&callback=?\", function(data) {\n            if (data.length>0) {\n              var parser = new OpenLayers.Format.WKT();\n              for (var i=0;i<data.length;i++)\n        {\n          if(data[i].centroid_geom){\n            " . self::readBoundaryJs('data[i].centroid_geom', $args['map_projection']) . "\n            feature.style = {label: data[i].name,\n\t\t\t\t\t\t     strokeColor: \"Green\",\n                             strokeWidth: 2,\n                             fillOpacity: 0};\n            centre = feature.geometry.getCentroid();\n            centrefeature = new OpenLayers.Feature.Vector(centre, {}, {label: data[i].name});\n            locationLayer.addFeatures([feature, centrefeature]);\n          }\n          if(data[i].boundary_geom){\n            " . self::readBoundaryJs('data[i].boundary_geom', $args['map_projection']) . "\n            feature.style = {strokeColor: \"Blue\", strokeWidth: 2};\n            locationLayer.addFeatures([feature]);\n          }\n          locationLayer.map.zoomToExtent(locationLayer.getDataExtent());\n        }\n      }\n    });\n     jQuery.getJSON(\"" . $svcUrl . "\" + \"/data/location\" +\n      \"?mode=json&view=detail&auth_token=" . $readAuth['auth_token'] . "&nonce=" . $readAuth["nonce"] . "&callback=?&parent_id=\"+obj.value, function(data) {\n            if (data.length>0) {\n              var parser = new OpenLayers.Format.WKT();\n              for (var i=0;i<data.length;i++)\n        {\n          if(data[i].centroid_geom){\n            " . self::readBoundaryJs('data[i].centroid_geom', $args['map_projection']) . "\n            locationLayer.addFeatures([feature]);\n          }\n          if(data[i].boundary_geom){\n            " . self::readBoundaryJs('data[i].boundary_geom', $args['map_projection']) . "\n            feature.style = {label: data[i].name,\n              labelAlign: \"cb\",\n              strokeColor: \"Blue\",\n                        strokeWidth: 2};\n            locationLayer.addFeatures([feature]);\n           }\n         }\n      }\n        });\n  }\n};\n// upload location initial value into map.\njQuery('#imp-location').each(function(){\n  locationChange(this);\n});\njQuery('#imp-location').unbind('change');\njQuery('#imp-location').change(function(){\n  locationChange(this);\n});\nvar selected = \$('#controls').tabs('option', 'selected');\n\n// Only leave the click control activated for edit/add occurrence tab.\nif(selected != 1){\n    locationLayer.map.editLayer.clickControl.deactivate();\n}\n\$('#controls').bind('tabsshow', function(event, ui) {\n        if(ui.index == 1)\n        {\n         locationLayer.map.editLayer.clickControl.activate();\n        }\n        else\n        {\n         locationLayer.map.editLayer.clickControl.deactivate();\n        }\n    }\n);\nactivateAddList = 1;\nthisOccID = " . $thisOccID . ";\naddListFeature = function(div, r, record, count) {\n  if(activateAddList == 0)\n    return;\n  if(r == count)\n    activateAddList = 0;\n    var parser = new OpenLayers.Format.WKT();\n    " . self::readBoundaryJs('record.geom', $args['map_projection']) . "\n    if(record.id != thisOccID || 1==" . ($surveyReadOnly ? 1 : 0) . " || 1==" . ($occReadOnly ? 1 : 0) . "){\n      feature.attributes.id = record.id;\n      feature.attributes.taxon = record.taxon;\n      feature.attributes.count = record.count;\n      occListLayer.addFeatures([feature]);\n      if(record.id == " . $thisOccID . "){\n        var bounds=feature.geometry.getBounds();\n        locationLayer.map.setCenter(bounds.getCenterLonLat());\n      }\n    } else {\n      locationLayer.map.editLayer.destroyFeatures();\n      locationLayer.map.editLayer.addFeatures([feature]);\n      var bounds=feature.geometry.getBounds()\n      var centre=bounds.getCenterLonLat();\n      locationLayer.map.setCenter(centre);\n    }\n};\nhighlight = function(id){\n  if(id == " . $thisOccID . "){\n    if(occListLayer.map.editLayer.features.length > 0){\n      var bounds=occListLayer.map.editLayer.features[0].geometry.getBounds()\n      var centre=bounds.getCenterLonLat();\n      occListLayer.map.setCenter(centre);\n      return;\n    }\n  }\n  for(var i = 0; i < occListLayer.features.length; i++){\n    if(occListLayer.features[i].attributes.id == id){\n      control.unselectAll();\n      var bounds=occListLayer.features[i].geometry.getBounds()\n      var centre=bounds.getCenterLonLat();\n      occListLayer.map.setCenter(centre);\n      control.select(occListLayer.features[i]);\n      return;\n    }\n  }\n}\n";
       if ($mode != 1) {
           data_entry_helper::$onload_javascript .= "\n\$('div#occ_grid').indiciaDataGrid('rpt:reports_for_prebuilt_forms/MNHNL/mnhnl_btw_list_occurrences', {\n    indiciaSvc: '" . $svcUrl . "',\n    dataColumns: ['taxon', 'territorial', 'count'],\n    reportColumnTitles: {taxon : '" . lang::get('LANG_Species') . "', territorial : '" . lang::get('LANG_Territorial') . "', count : '" . lang::get('LANG_Count') . "'},\n    actionColumns: {'" . lang::get('LANG_Show') . "' : \"" . url('node/' . $node->nid, array('query' => 'occurrence_id=£id£')) . "\",\n            '" . lang::get('LANG_Highlight') . "' : \"script:highlight(£id£);\"},\n    auth : { nonce : '" . $readAuth['nonce'] . "', auth_token : '" . $readAuth['auth_token'] . "'},\n    parameters : { survey_id : '" . $args['survey_id'] . "',\n            parent_id : '" . $parentSample['sample:id'] . "',\n            territorial_attr_id : '" . $occurrence_territorial_id . "',\n            count_attr_id : '" . $occurrence_count_id . "'},\n    itemsPerPage : 12,\n    callback : addListFeature ,\n    cssOdd : ''\n  });\n\n// activateAddList = 0;\n\n";
       }
       $r .= "</div><div><form><input id=\"return-to-main\" type=\"button\" value=\"" . lang::get('LANG_Return') . "\" onclick=\"window.location.href='" . url('node/' . $node->nid, array('query' => 'Main')) . "'\"></form></div></div>\n";
       if (method_exists(get_called_class(), 'getTrailerHTML')) {
           $r .= call_user_func(array(get_called_class(), 'getTrailerHTML'), $args);
       }
       return $r;
   }
 public static function get_occurrences_form($args, $node, $response)
 {
     if (!module_exists('iform_ajaxproxy')) {
         return 'This form must be used in Drupal with the Indicia AJAX Proxy module enabled.';
     }
     data_entry_helper::add_resource('jquery_form');
     $auth = data_entry_helper::get_read_write_auth($args['website_id'], $args['password']);
     // did the parent sample previously exist? Default is no.
     $existing = false;
     if (isset($_POST['sample:id'])) {
         // have just posted an edit to the existing parent sample, so can use it to get the parent location id.
         $parentSampleId = $_POST['sample:id'];
         $parentLocId = $_POST['sample:location_id'];
         $date = $_POST['sample:date'];
         $existing = true;
     } else {
         if (isset($response['outer_id'])) {
             // have just posted a new parent sample, so can use it to get the parent location id.
             $parentSampleId = $response['outer_id'];
         } else {
             $parentSampleId = $_GET['sample_id'];
             $existing = true;
         }
         $sample = data_entry_helper::get_population_data(array('table' => 'sample', 'extraParams' => $auth['read'] + array('view' => 'detail', 'id' => $parentSampleId, 'deleted' => 'f')));
         $sample = $sample[0];
         $parentLocId = $sample['location_id'];
         $date = $sample['date_start'];
     }
     // find any attributes that apply to transect section samples.
     $sampleMethods = helper_base::get_termlist_terms($auth, 'indicia:sample_methods', array('Transect Section'));
     $attributes = data_entry_helper::getAttributes(array('id' => $sampleId, 'valuetable' => 'sample_attribute_value', 'attrtable' => 'sample_attribute', 'key' => 'sample_id', 'fieldprefix' => 'smpAttr', 'extraParams' => $auth['read'], 'survey_id' => $args['survey_id'], 'sample_method_id' => $sampleMethods[0]['id'], 'multiValue' => false));
     if ($existing) {
         // as the parent sample exists, we need to load the sub-samples and occurrences
         $subSamples = data_entry_helper::get_population_data(array('report' => 'library/samples/samples_list_for_parent_sample', 'extraParams' => $auth['read'] + array('sample_id' => $parentSampleId, 'date_from' => '', 'date_to' => '', 'sample_method_id' => '', 'smpattrs' => implode(',', array_keys($attributes))), 'nocache' => true));
         // transcribe the response array into a couple of forms that are useful elsewhere - one for outputting JSON so the JS knows about
         // the samples, and another for lookup of sample data by code later.
         $subSampleJson = array();
         $subSamplesByCode = array();
         foreach ($subSamples as $subSample) {
             $subSampleJson[] = '"' . $subSample['code'] . '": ' . $subSample['sample_id'];
             $subSamplesByCode[$subSample['code']] = $subSample;
         }
         data_entry_helper::$javascript .= "indiciaData.samples = { " . implode(', ', $subSampleJson) . "};\n";
         $o = data_entry_helper::get_population_data(array('report' => 'library/occurrences/occurrences_list_for_parent_sample', 'extraParams' => $auth['read'] + array('view' => 'detail', 'sample_id' => $parentSampleId, 'survey_id' => '', 'date_from' => '', 'date_to' => '', 'taxon_group_id' => '', 'smpattrs' => '', 'occattrs' => $args['occurrence_attribute_id']), 'nocache' => true));
         // build an array keyed for easy lookup
         $occurrences = array();
         foreach ($o as $occurrence) {
             $occurrences[$occurrence['sample_id'] . ':' . $occurrence['taxa_taxon_list_id']] = array('value' => $occurrence['attr_occurrence_' . $args['occurrence_attribute_id']], 'o_id' => $occurrence['occurrence_id'], 'a_id' => $occurrence['attr_id_occurrence_' . $args['occurrence_attribute_id']]);
         }
         // store it in data for JS to read when populating the grid
         data_entry_helper::$javascript .= "indiciaData.existingOccurrences = " . json_encode($occurrences) . ";\n";
     } else {
         data_entry_helper::$javascript .= "indiciaData.samples = {};\n";
         data_entry_helper::$javascript .= "indiciaData.existingOccurrences = {};\n";
     }
     $sections = data_entry_helper::get_population_data(array('table' => 'location', 'extraParams' => $auth['read'] + array('view' => 'detail', 'parent_id' => $parentLocId, 'deleted' => 'f', 'orderby' => 'code')));
     $r = "<form method=\"post\"><div id=\"tabs\">\n";
     $r .= '<input type="hidden" name="sample:id" value="' . $parentSampleId . '" />';
     $r .= '<input type="hidden" name="website_id" value="' . $args['website_id'] . '"/>';
     $r .= '<input type="hidden" name="survey_id" value="' . $args['survey_id'] . '"/>';
     $r .= '<input type="hidden" name="page" value="grid"/>';
     $r .= data_entry_helper::tab_header(array('tabs' => array('#grid' => lang::get('Enter Transect Data'), '#notes' => lang::get('Notes'))));
     data_entry_helper::enable_tabs(array('divId' => 'tabs', 'style' => $args['interface']));
     $r .= "<div id=\"grid\">\n";
     $r .= '<table id="transect-input" class="ui-widget"><thead>';
     $r .= '<tr><th class="ui-widget-header">' . lang::get('Sections') . '</th>';
     foreach ($sections as $section) {
         $r .= '<th class="ui-widget-header">' . $section['code'] . '</th>';
     }
     $r .= '</tr></thead>';
     $r .= '<tbody class="ui-widget-content">';
     // output rows at the top for any transect section level sample attributes
     $rowClass = '';
     foreach ($attributes as $attr) {
         $r .= '<tr ' . $rowClass . '><td>' . $attr['caption'] . '</td>';
         $rowClass = $rowClass == '' ? 'class="alt-row"' : '';
         unset($attr['caption']);
         foreach ($sections as $section) {
             // output a cell with the attribute - tag it with a class & id to make it easy to find from JS.
             $attrOpts = array('class' => 'smp-input smpAttr-' . $section['code'], 'id' => $attr['fieldname'] . ':' . $section['code'], 'extraParams' => $auth['read']);
             // if there is an existing value, set it and also ensure the attribute name reflects the attribute value id.
             if (isset($subSamplesByCode[$section['code']])) {
                 $attrOpts['fieldname'] = $attr['fieldname'] . ':' . $subSamplesByCode[$section['code']]['attr_id_sample_' . $attr['attributeId']];
                 $attr['default'] = $subSamplesByCode[$section['code']]['attr_sample_' . $attr['attributeId']];
             } else {
                 $attr['default'] = isset($_POST[$attr['fieldname']]) ? $_POST[$attr['fieldname']] : '';
             }
             $r .= '<td>' . data_entry_helper::outputAttribute($attr, $attrOpts) . '</td>';
         }
         $r .= '</tr>';
     }
     $r .= '</tbody>';
     $r .= '<tbody class="ui-widget-content" id="occs-body"></tbody>';
     $r .= '</table>';
     $r .= '</div>';
     $r .= "<div id=\"notes\">\n";
     $r .= data_entry_helper::textarea(array('fieldname' => 'sample:comment', 'label' => lang::get('Notes'), 'helpText' => "Use this space to input comments about this week's walk."));
     $r .= '<input type="submit" value="' . lang::get('Save') . '"/>';
     $r .= '</div></div></form>';
     // A stub form for AJAX posting when we need to create an occurrence
     $r .= '<form style="display: none" id="occ-form" method="post" action="' . iform_ajaxproxy_url($node, 'occurrence') . '">';
     $r .= '<input name="website_id" value="' . $args['website_id'] . '"/>';
     $r .= '<input name="occurrence:id" id="occid" />';
     $r .= '<input name="occurrence:taxa_taxon_list_id" id="ttlid" />';
     $r .= '<input name="occurrence:sample_id" id="occ_sampleid"/>';
     $r .= '<input name="occAttr:' . $args['occurrence_attribute_id'] . '" id="occattr"/>';
     $r .= '<input name="transaction_id" id="transaction_id"/>';
     $r .= '</form>';
     // A stub form for AJAX posting when we need to create a sample
     $r .= '<form style="display: none" id="smp-form" method="post" action="' . iform_ajaxproxy_url($node, 'sample') . '">';
     $r .= '<input name="website_id" value="' . $args['website_id'] . '"/>';
     $r .= '<input name="sample:id" id="smpid" />';
     $r .= '<input name="sample:parent_id" value="' . $parentSampleId . '" />';
     $r .= '<input name="sample:survey_id" value="' . $args['survey_id'] . '" />';
     $r .= '<input name="sample:sample_method_id" value="' . $sampleMethods[0]['id'] . '" />';
     $r .= '<input name="sample:entered_sref" id="smpsref" />';
     $r .= '<input name="sample:entered_sref_system" id="smpsref_system" />';
     $r .= '<input name="sample:location_id" id="smploc" />';
     $r .= '<input name="sample:date" value="' . $date . '" />';
     // include a stub input for each transect section sample attribute
     foreach ($attributes as $attr) {
         $r .= '<input id="' . $attr['fieldname'] . '" />';
     }
     $r .= '</form>';
     // tell the Javascript where to get species from.
     // @todo handle diff species lists.
     data_entry_helper::$javascript .= "indiciaData.initSpeciesList = " . $args['taxon_list_id'] . ";\n";
     // allow js to do AJAX by passing in the information it needs to post forms
     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.transect = " . $parentLocId . ";\n";
     data_entry_helper::$javascript .= "indiciaData.parentSample = " . $parentSampleId . ";\n";
     data_entry_helper::$javascript .= "indiciaData.sections = " . json_encode($sections) . ";\n";
     data_entry_helper::$javascript .= "indiciaData.occAttrId = " . $args['occurrence_attribute_id'] . ";\n";
     // Do an AJAX population of the grid rows.
     data_entry_helper::$javascript .= "loadSpeciesList();\n";
     data_entry_helper::add_resource('jquery_ui');
     return $r;
 }
Пример #27
0
    /**
     * Return the Indicia form code.
     * Expects there to be a sample attribute with caption 'Email' containing the email
     * address.
     * @param array $args Input parameters.
     * @param array $node Drupal node object
     * @param array $response Response from Indicia services after posting a verification.
     * @return HTML string
     */
    public static function get_form($args, $node, $response)
    {
        global $user, $indicia_templates;
        // put each param control in a div, which makes it easier to layout with CSS
        $indicia_templates['prefix'] = '<div id="container-{fieldname}" class="param-container">';
        $indicia_templates['suffix'] = '</div>';
        $indicia_user_id = self::get_indicia_user_id($args);
        $auth = data_entry_helper::get_read_write_auth($args['website_id'], $args['password']);
        $r = '';
        if ($_POST) {
            // dump out any errors that occurred on verification
            if (data_entry_helper::$validation_errors) {
                $r .= '<div class="page-notice ui-state-highlight ui-corner-all"><p>' . implode('</p></p>', array_values(data_entry_helper::$validation_errors)) . '</p></div>';
            } else {
                if (isset($_POST['email']) && !isset($response['error'])) {
                    // To send HTML mail, the Content-type header must be set
                    $headers = 'MIME-Version: 1.0' . "\r\n";
                    $headers .= 'Content-type: text/html; charset=iso-8859-1' . "\r\n";
                    $headers .= 'From: ' . $user->mail . PHP_EOL . "\r\n";
                    $headers .= 'Return-Path: ' . $user->mail . "\r\n";
                    if (isset($_POST['photoHTML'])) {
                        $emailBody = str_replace('[photo]', '<br/>' . $_POST['photoHTML'], $_POST['email_content']);
                    } else {
                        $emailBody = $_POST['email_content'];
                    }
                    $emailBody = str_replace("\n", "<br/>", $emailBody);
                    // Send email. Depends upon settings in php.ini being correct
                    $success = mail($_POST['email_to'], $_POST['email_subject'], wordwrap($emailBody, 70), $headers);
                    if ($success) {
                        $r .= '<div class="page-notice ui-state-highlight ui-corner-all"><p>An email was sent to ' . $_POST['email_to'] . '.</p></div>';
                    } else {
                        $r .= '<div class="page-notice ui-widget-content ui-corner-all ui-state-highlight left">The webserver is not correctly configured to send emails. Please send the following email manually: <br/>' . '<div id="manual-email"><span>To:</span><div>' . $_POST['email_to'] . '</div>' . '<span>Subject:</span><div>' . $_POST['email_subject'] . '</div>' . '<span>Content:</span><div>' . $emailBody . '</div>' . '</div></div><div style="clear: both">';
                    }
                } else {
                    if (isset($_POST['occurrence:record_status']) && isset($response['success']) && $args['emails_enabled']) {
                        $r .= self::get_notification_email_form($args, $response, $auth);
                    }
                }
            }
            if (isset($_POST['action']) && $_POST['action'] == 'send_to_verifier' && $args['log_send_to_verifier']) {
                $comment = str_replace(array('%email%', '%date%', '%user%'), array($_POST['email_to'], date('jS F Y'), $user->name), $args['log_send_to_verifier_comment']);
            } elseif (isset($_POST['action']) && ($_POST['action'] = 'general_comment')) {
                $comment = $_POST['comment'];
            }
            // If there is a comment to save, add it to the occurrence comments
            if (isset($comment)) {
                // get our own write tokens for this submission, as the main ones are used in the JavaScript form.
                $loggingAuth = data_entry_helper::get_read_write_auth($args['website_id'], $args['password']);
                $sub = data_entry_helper::wrap(array('comment' => $comment, 'occurrence_id' => $_POST['occurrence:id'], 'created_by_id' => $indicia_user_id), 'occurrence_comment');
                $logResponse = data_entry_helper::forward_post_to('occurrence_comment', $sub, $loggingAuth['write_tokens']);
                if (!array_key_exists('success', $logResponse)) {
                    $r .= data_entry_helper::dump_errors($response, false);
                }
            }
        }
        //extract fixed parameters for report grid.
        $params = explode(",", $args['fixed_params']);
        foreach ($params as $param) {
            $keyvals = explode("=", $param);
            $key = trim($keyvals[0]);
            $val = trim($keyvals[1]);
            $extraParams[$key] = $val;
        }
        // plus defaults which are not fixed
        $params = explode("\n", $args['param_defaults']);
        foreach ($params as $param) {
            $keyvals = explode("=", $param);
            $key = trim($keyvals[0]);
            $val = trim($keyvals[1]);
            $paramDefaults[$key] = $val;
        }
        $actions = array();
        if ($args['send_for_verification']) {
            // store authorisation details as a global in js, since some of the JavaScript needs to be able to access Indicia data
            data_entry_helper::$javascript .= 'auth=' . json_encode($auth) . ';';
            $actions[] = array('caption' => str_replace(' ', '&nbsp;', lang::get('Send to verifier')), 'class' => 'send_for_verification_btn', 'javascript' => 'indicia_send_to_verifier(\'{taxon}\', {occurrence_id}, ' . $user->uid . ', ' . $args['website_id'] . '); return false;');
            $r .= self::get_send_for_verification_form();
        }
        $actions[] = array('caption' => str_replace(' ', '&nbsp;', lang::get('Verify')), 'javascript' => 'indicia_verify(\'{taxon}\', {occurrence_id}, true, ' . $user->uid . '); return false;');
        $actions[] = array('caption' => str_replace(' ', '&nbsp;', lang::get('Reject')), 'javascript' => 'indicia_verify(\'{taxon}\', {occurrence_id}, false, ' . $user->uid . '); return false;');
        $actions[] = array('caption' => str_replace(' ', '&nbsp;', lang::get('Comments')), 'javascript' => 'indicia_comments(\'{taxon}\', {occurrence_id}, ' . $user->uid . ', \'' . $auth['read']['nonce'] . '\', \'' . $auth['read']['auth_token'] . '\'); return false;');
        if (isset($args['path_to_record_details_page']) && $args['path_to_record_details_page']) {
            $actions[] = array('caption' => str_replace(' ', '&nbsp;', lang::get('View details')), 'url' => '{rootFolder}' . $args['path_to_record_details_page'], 'urlParams' => array('occurrence_id' => '{occurrence_id}'));
        }
        // default columns behaviour is to just include anything returned by the report plus add an actions column
        $columns = array(array('display' => 'Actions', 'actions' => $actions));
        // this can be overridden
        if (isset($args['columns_config']) && !empty($args['columns_config'])) {
            $columns = array_merge(json_decode($args['columns_config'], true), $columns);
        }
        $r .= data_entry_helper::report_grid(array('id' => 'verification-grid', 'dataSource' => $args['report_name'], 'mode' => 'report', 'readAuth' => $auth['read'], 'columns' => $columns, 'rowId' => 'occurrence_id', 'itemsPerPage' => 10, 'autoParamsForm' => $args['auto_params_form'], 'extraParams' => $extraParams, 'paramDefaults' => $paramDefaults));
        // Put in a blank form, which lets JavaScript set the values and post the data.
        $r .= '
<form id="verify" method="post" action="">
  ' . $auth['write'] . '
  <input type="hidden" id="occurrence:id" name="occurrence:id" value="" />
  <input type="hidden" id="occurrence:record_status" name="occurrence:record_status" value="" />
  <input type="hidden" id="occurrence_comment:comment" name="occurrence_comment:comment" value="" />
  <input type="hidden" name="occurrence_comment:created_by_id" value="' . $indicia_user_id . '" />
  <input type="hidden" id="website_id" name="website_id" value="' . $args['website_id'] . '" />
  <input type="hidden" id="occurrence:verified_by_id" name="occurrence:verified_by_id" value="" />
</form>
';
        drupal_add_js('
var indicia_user_id = ' . $indicia_user_id . ';
var url = ' . json_encode(data_entry_helper::get_reload_link_parts()) . ';
var svc = "' . data_entry_helper::$base_url . 'index.php/services/data/";
var email_subject_send_to_verifier = "' . $args['email_subject_send_to_verifier'] . '";
var email_body_send_to_verifier = "' . str_replace(array("\r", "\n"), array('', '\\n'), $args['email_body_send_to_verifier']) . '";
', 'inline');
        /*.';
        
        ');*/
        return $r;
    }
Пример #28
0
 /**
  * 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.
  */
 public static function get_form($args, $node, $response = null)
 {
     if (!hostsite_get_user_field('indicia_user_id')) {
         return 'Please ensure that you\'ve filled in your surname on your user profile before creating or editing groups.';
     }
     self::createBreadcrumb($args);
     iform_load_helpers(array('report_helper', 'map_helper'));
     $args = array_merge(array('include_code' => false, 'include_dates' => false, 'include_logo_controls' => true, 'include_sensitivity_controls' => true, 'include_report_filter' => true, 'include_linked_pages' => true, 'include_private_records' => false, 'include_administrators' => false, 'include_members' => false, 'filter_types' => '{"":"what,where,when","Advanced":"source,quality"}', 'indexed_location_type_ids' => '', 'other_location_type_ids' => '', 'data_inclusion_mode' => 'choose'), $args);
     $args['filter_types'] = json_decode($args['filter_types'], true);
     $reloadPath = self::getReloadPath();
     data_entry_helper::$website_id = $args['website_id'];
     $auth = data_entry_helper::get_read_write_auth($args['website_id'], $args['password']);
     if (!empty($_GET['group_id'])) {
         self::loadExistingGroup($_GET['group_id'], $auth, $args);
     }
     // maintain compatibility with form settings from before group type became multiselect.
     if (empty($args['group_type'])) {
         $args['group_type'] = array();
     } elseif (!is_array($args['group_type'])) {
         $args['group_type'] = array($args['group_type']);
     }
     if (count($args['group_type']) === 1) {
         $response = data_entry_helper::get_population_data(array('table' => 'termlists_term', 'extraParams' => $auth['read'] + array('id' => $args['group_type'][0])));
         self::$groupType = strtolower($response[0]['term']);
     }
     self::$groupType = lang::get(self::$groupType);
     $r = "<form method=\"post\" id=\"entry_form\" action=\"{$reloadPath}\" enctype=\"multipart/form-data\">\n";
     $r .= '<fieldset><legend>' . lang::get('Fill in details of your {1} below', self::$groupType) . '</legend>';
     $r .= $auth['write'] . "<input type=\"hidden\" id=\"website_id\" name=\"website_id\" value=\"" . $args['website_id'] . "\" />\n";
     $r .= data_entry_helper::hidden_text(array('fieldname' => 'group:id'));
     // if a fixed choice of group type, can use a hidden input to put the value in the form.
     if (count($args['group_type']) === 1) {
         $r .= '<input type="hidden" name="group:group_type_id" value="' . $args['group_type'][0] . '"/>';
     }
     if (!empty(data_entry_helper::$entity_to_load['group:title'])) {
         hostsite_set_page_title(lang::get('Edit {1}', data_entry_helper::$entity_to_load['group:title']));
     }
     $r .= data_entry_helper::text_input(array('label' => lang::get('{1} name', ucfirst(self::$groupType)), 'fieldname' => 'group:title', 'validation' => array('required'), 'class' => 'control-width-6', 'helpText' => lang::get('Provide the full title of the {1}', self::$groupType)));
     if ($args['include_code']) {
         $r .= data_entry_helper::text_input(array('label' => lang::get('Code'), 'fieldname' => 'group:code', 'class' => 'control-width-4', 'helpText' => lang::get('Provide a code or abbreviation identifying the {1}', self::$groupType)));
     }
     $r .= data_entry_helper::textarea(array('label' => ucfirst(lang::get('{1} description', self::$groupType)), 'fieldname' => 'group:description', 'helpText' => lang::get('LANG_Description_Field_Instruct', self::$groupType), 'class' => 'control-width-6'));
     // If adding a new group which should have a parent group of some type or other, but no parent
     // group is specified in the from_group_id parameter, then let the user pick a group to link as the parent.
     if (empty($_GET['group_id']) && !empty($args['parent_group_type']) && !empty($args['parent_group_relationship_type']) && empty($_REQUEST['from_group_id'])) {
         // There should be a parent group, but none provided, so allow the user to pick one.
         $r .= data_entry_helper::select(array('label' => ucfirst(lang::get('{1} parent', self::$groupType)), 'fieldname' => 'from_group_id', 'table' => 'groups_user', 'captionField' => 'title', 'valueFields' => 'group_id', 'extraParams' => $auth['read'] + array('group_type_id' => $args['parent_group_type'], 'user_id' => hostsite_get_user_field('indicia_user_id'), 'view' => 'detail'), 'validation' => array('required'), 'blankText' => lang::get('<please select>')));
     }
     if (count($args['group_type']) !== 1) {
         $params = array('termlist_external_key' => 'indicia:group_types', 'orderby' => 'sortorder,term');
         if (!empty($args['group_type'])) {
             $params['query'] = json_encode(array('in' => array('id' => array_values($args['group_type']))));
         }
         $r .= data_entry_helper::select(array('label' => ucfirst(lang::get('{1} type', self::$groupType)), 'fieldname' => 'group:group_type_id', 'validation' => array('required'), 'table' => 'termlists_term', 'valueField' => 'id', 'captionField' => 'term', 'extraParams' => $auth['read'] + $params, 'class' => 'control-width-4', 'blankText' => lang::get('<please select>'), 'helpText' => lang::get('What sort of {1} is it?', self::$groupType)));
     }
     $r .= self::groupLogoControl($args);
     $r .= self::joinMethodsControl($args);
     if ($args['include_sensitivity_controls']) {
         $r .= data_entry_helper::checkbox(array('label' => lang::get('Show records at full precision'), 'fieldname' => 'group:view_full_precision', 'helpText' => lang::get('Any sensitive records added to the system are normally shown blurred to a lower grid reference precision. If this box ' . 'is checked, then group members can see sensitive records explicitly posted for the {1} at full precision.', self::$groupType)));
     }
     $r .= self::dateControls($args);
     if ($args['include_private_records']) {
         $r .= data_entry_helper::checkbox(array('label' => lang::get('Records are private'), 'fieldname' => 'group:private_records', 'helpText' => lang::get('Tick this box if you want to withold the release of the records from this {1} until a ' . 'later point in time, e.g. when a project is completed.', self::$groupType)));
         // If an existing group with private records, then we might need to display a message warning the user about releasing the records.
         // Initially hidden, we use JS to display it when appropriate.
         if (!empty(data_entry_helper::$entity_to_load['group:id']) && data_entry_helper::$entity_to_load['group:private_records'] === 't') {
             $r .= '<p class="warning" style="display: none" id="release-warning">' . lang::get('You are about to release the records belonging to this group. Do not proceed unless you intend to do this!') . '</p>';
         }
     }
     $r .= self::memberControls($args, $auth);
     $r .= '</fieldset>';
     $r .= self::reportFilterBlock($args, $auth, $hiddenPopupDivs);
     $r .= self::inclusionMethodControl($args);
     $r .= self::formsBlock($args, $auth, $node);
     // auto-insert the creator as an admin of the new group, unless the admins are manually specified
     if (!$args['include_administrators'] && empty($_GET['group_id'])) {
         $r .= '<input type="hidden" name="groups_user:admin_user_id[]" value="' . hostsite_get_user_field('indicia_user_id') . '"/>';
     }
     $r .= '<input type="hidden" name="groups_user:administrator" value="t"/>';
     $r .= '<input type="submit" class="indicia-button" id="save-button" value="' . (empty(data_entry_helper::$entity_to_load['group:id']) ? lang::get('Create {1}', self::$groupType) : lang::get('Update {1} settings', self::$groupType)) . "\" />\n";
     $r .= '</form>';
     $r .= $hiddenPopupDivs;
     data_entry_helper::enable_validation('entry_form');
     // JavaScript to grab the filter definition and store in the form for posting when the form is submitted
     data_entry_helper::$javascript .= "\r\n\$('#entry_form').submit(function() {\r\n  \$('#filter-title-val').val('" . lang::get('Filter for user group') . " ' + \$('#group\\\\:title').val() + ' ' + new Date().getTime());\r\n  \$('#filter-def-val').val(JSON.stringify(indiciaData.filter.def));\r\n});\n";
     // for existing groups, prevent removal of yourself as a member. Someone else will have to do this for you so we don't orphan groups.
     if (!empty(data_entry_helper::$entity_to_load['group:id'])) {
         data_entry_helper::$javascript .= "\$('#groups_user\\\\:admin_user_id\\\\:sublist input[value=" . hostsite_get_user_field('indicia_user_id') . "]').closest('li').children('span').remove();\n";
     }
     return $r;
 }
 /**
  * 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 integer $nid The Drupal node object's ID.
  * @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.
  */
 public static function get_form($args, $nid, $response = null)
 {
     global $user;
     //    if (!function_exists('module_exists') || !module_exists('iform_ajaxproxy'))
     //      return 'This form must be used in Drupal with the Indicia AJAX Proxy module enabled.';
     if (!function_exists('module_exists') || !module_exists('easy_login')) {
         return 'FATAL INTERNAL CONFIGURATION ERROR: This form must be used in Drupal with the Easy Login module enabled.';
     }
     if (!function_exists('module_exists') || !module_exists('species_packages')) {
         return 'FATAL INTERNAL CONFIGURATION ERROR: This form must be used in Drupal with the custom species_packages module enabled.';
     }
     // assuming easy login
     $userId = hostsite_get_user_field('indicia_user_id');
     if (empty($userId)) {
         return '<p>FATAL ERROR: Could not identify user.</p>';
     }
     // something is wrong
     $r = isset($response['error']) ? data_entry_helper::dump_errors($response) : '';
     iform_load_helpers(array('map_helper', 'report_helper'));
     $auth = data_entry_helper::get_read_write_auth($args['website_id'], $args['password']);
     self::$sampleId = null;
     self::$occurrenceId = false;
     if (isset(data_entry_helper::$entity_to_load['sample:id']) && data_entry_helper::$entity_to_load['sample:id'] != "") {
         // have just posted a (failed) edit to an existing parent sample.
         self::$sampleId = data_entry_helper::$entity_to_load['sample:id'];
     } else {
         if (isset(data_entry_helper::$entity_to_load['sample:survey_id']) && data_entry_helper::$entity_to_load['sample:survey_id'] != "") {
             // have just posted a (failed) edit to a new parent sample.
             self::$sampleId = null;
         } else {
             if (isset($response['outer_id'])) {
                 // have just successfully posted either a new parent sample, or an update to an existing one.
                 self::$sampleId = $response['outer_id'];
                 data_entry_helper::load_existing_record($auth['read'], 'sample', self::$sampleId, 'detail', false, true);
                 if (!isset($_POST['force_page_reload'])) {
                     return self::get_success_page($args, $auth, $response['outer_id']);
                 }
                 drupal_set_message(lang::get('The Transect you have just saved specified the Species Package to be used. The Transect has been reloaded below, and the Species tab now contains the Species Grid for the Species Package, which will allow you to enter the species data.'));
             } else {
                 if (isset($_GET['sample_id']) && intval($_GET['sample_id']) == $_GET['sample_id']) {
                     self::$sampleId = $_GET['sample_id'];
                     data_entry_helper::load_existing_record($auth['read'], 'sample', self::$sampleId, 'detail', false, true);
                 } else {
                     self::$sampleId = null;
                 }
             }
         }
     }
     if (isset($_GET['occurrence_id']) && intval($_GET['occurrence_id']) == $_GET['occurrence_id']) {
         self::$occurrenceId = $_GET['occurrence_id'];
         if (self::$sampleId == null) {
             // fill in the sample_id from the occurrence if don't already have it
             $occurrence = data_entry_helper::get_population_data(array('table' => 'occurrence', 'extraParams' => $auth['read'] + array('view' => 'detail', 'id' => self::$occurrenceId)));
             // this throws an error exception if any error.
             // this gives
             if (count($occurrence) == 1) {
                 $subsample = data_entry_helper::get_population_data(array('table' => 'sample', 'extraParams' => $auth['read'] + array('view' => 'detail', 'id' => $occurrence[0]['sample_id'])));
                 if (count($subsample) == 1) {
                     self::$sampleId = $subsample[0]['parent_id'];
                     data_entry_helper::load_existing_record($auth['read'], 'sample', self::$sampleId, 'detail', false, true);
                 }
             }
         }
     }
     if (isset(data_entry_helper::$entity_to_load['sample:survey_id']) && data_entry_helper::$entity_to_load['sample:survey_id'] != $args['survey_id']) {
         drupal_set_message(t('The data entry form you have selected to use is configured for a particular survey:') . ' ID ' . $args['survey_id'] . ' ' . t('The sample you have chosen to view is not assigned to this survey.'), 'error');
         drupal_goto('<front>');
     }
     if (isset(data_entry_helper::$entity_to_load['sample:parent_id']) && data_entry_helper::$entity_to_load['sample:parent_id'] != '' && data_entry_helper::$entity_to_load['sample:parent_id'] !== null) {
         drupal_set_message(t('An attempt has been made to access a non top level sample.'));
         drupal_goto('<front>');
     }
     $survey = data_entry_helper::get_population_data(array('table' => 'survey', 'extraParams' => $auth['read'] + array('view' => 'detail', 'id' => $args['survey_id'], 'website_id' => $args['website_id'])));
     if (count($survey) != 1) {
         return "FATAL INTERNAL CONFIGURATION ERROR: Supplied form survey_id value (" . $args['survey_id'] . ") is not valid survey for this website (" . $args['website_id'] . ").<br/>";
     }
     $surveyTitle = $survey[0]['title'];
     if (self::$sampleId == null) {
         $packages = species_packages_get_packages($user->uid, $args['survey_id']);
         if ($packages === false || is_array($packages) && count($packages) == 0) {
             drupal_set_message(t('You have not yet selected a species package that is compatible with survey') . ' : &quot;' . $surveyTitle . '&quot;', 'error');
             drupal_set_message(str_replace('#link#', '<a href="' . url('user/' . $user->uid . '/edit') . '">' . t('this link') . '</a>', t('You can set the species package on your user account page, which can be accessed using #link#. If you have already selected a species package, and wish to add another or wish to change your selection, please contact your Hub Manager.')));
             drupal_goto('<front>');
         }
         self::$readOnly = false;
     } else {
         self::$readOnly = !isset($response['error']) && data_entry_helper::$entity_to_load['sample:created_by_id'] != hostsite_get_user_field('indicia_user_id') && (empty($args['edit_permission']) || !hostsite_user_has_permission($args['edit_permission']));
     }
     if (self::$readOnly) {
         drupal_set_message(t('In order to save changes to existing records, you must either be the creator of the entry, or have been given the appropriate permission.'));
     }
     // In readonly mode, the forms are replaced by divs and there are no save buttons.
     //    $r .= '<span style="display:none;">'.print_r($packages,true).'</span>';
     //	$r .= '<span style="display:none;">'.print_r(array($user->uid, $args, $packageAttr), true).'</span>' .
     $attributes = data_entry_helper::getAttributes(array('id' => self::$sampleId, 'valuetable' => 'sample_attribute_value', 'attrtable' => 'sample_attribute', 'key' => 'sample_id', 'fieldprefix' => 'smpAttr', 'extraParams' => $auth['read'], 'survey_id' => $args['survey_id'], 'sample_method_id' => $args['transect_level_sample_method_id']));
     $packageAttr = self::extract_package_attr($attributes, true);
     if (!$packageAttr) {
         return "FATAL INTERNAL CONFIGURATION ERROR: This form must be used with a survey which has a &#x22;Species Package&#x22; sample attribute defined for it (integer, required on parent).<br/>";
     }
     self::_remove_options($args);
     $r .= (self::$readOnly ? '<div id="data_entry_form">' : '<form method="post" id="data_entry_form">' . $auth['write']) . '<input type="hidden" name="website_id" value="' . $args['website_id'] . '"/>' . (isset(data_entry_helper::$entity_to_load['sample:id']) ? '<input type="hidden" name="sample:id" value="' . data_entry_helper::$entity_to_load['sample:id'] . '"/>' : '') . '<input type="hidden" name="sample:survey_id" value="' . $args['survey_id'] . '"/>' . '<input type="hidden" name="sample:sample_method_id" value="' . $args['transect_level_sample_method_id'] . '" />';
     if (isset(data_entry_helper::$entity_to_load['sample:id'])) {
         $r .= "<h2>" . data_entry_helper::$entity_to_load['sample:location_name'] . " on " . data_entry_helper::$entity_to_load['sample:date'] . (self::$readOnly ? ' ' . lang::get('READ ONLY') : '') . "</h2>\n";
     }
     $r .= "<div id=\"tabs\">\n";
     $tabs = array();
     $smpTab = self::get_sample_tab($args, $nid, $auth, $attributes, $packageAttr);
     $mediaTab = self::get_media_tab($args, $nid, $auth);
     $occTab = self::get_occurrences_tab($args, $nid, $auth, $packageAttr);
     // Note this messes with the templates, so done last just in case
     $tabs['#sample'] = t($args['sample_tab_label']);
     if ($occTab != "") {
         $tabs['#occurrences'] = t($args['occurrence_tab_label']);
     }
     if ($mediaTab != "") {
         $tabs['#media'] = t($args['media_tab_label']);
     }
     $r .= data_entry_helper::tab_header(array('tabs' => $tabs));
     data_entry_helper::enable_tabs(array('divId' => 'tabs', 'style' => 'Tabs', 'active' => $occTab != "" && (self::$occurrenceId || self::$sampleId) ? 'occurrences' : 'sample'));
     $r .= $smpTab . $occTab . $mediaTab . '</div>' . (self::$readOnly ? '</div>' : '</form>');
     if (!self::$readOnly) {
         // custom version of enable validation code
         data_entry_helper::$validated_form_id = 'data_entry_form';
         data_entry_helper::$javascript .= "indiciaData.validatedFormId = '" . data_entry_helper::$validated_form_id . "';\n";
         // prevent double submission of the form
         data_entry_helper::$javascript .= "\$('#data_entry_form').submit(function(e) {\r\n  if (typeof \$('#data_entry_form').valid === 'undefined' || \$('#data_entry_form').valid()) {\r\n    if (typeof indiciaData.formSubmitted==='undefined' || !indiciaData.formSubmitted) {\r\n      \$('<p>" . lang::get('Please wait whilst the data is saved.') . "</p>').dialog({ title: '" . lang::get('Saving Data') . "', buttons: { '" . lang::get('OK') . "' : function() { \$( this ).dialog('close'); } } });\r\n      indiciaData.formSubmitted=true;\r\n    } else {\r\n      e.preventDefault();\r\n      return false;\r\n    }\r\n  }\r\n});\n";
         data_entry_helper::add_resource('validation');
     }
     return $r;
 }
Пример #30
0
 /**
  * Return the generated form output.
  * @return Form HTML.
  */
 public static function get_form($args, $node)
 {
     self::parse_defaults($args);
     self::getArgDefaults($args);
     global $user;
     $logged_in = $user->uid > 0;
     $r = '';
     // Get authorisation tokens to update and read from the Warehouse.
     $auth = data_entry_helper::get_read_write_auth($args['website_id'], $args['password']);
     $svcUrl = data_entry_helper::$base_url . '/index.php/services';
     $mode = 0;
     // default mode : display grid of existing data
     // mode 1: display new sample
     // mode 2: display existing sample
     $loadID = null;
     if ($_POST) {
         if (!is_null(data_entry_helper::$entity_to_load)) {
             $mode = 2;
             // errors with new sample, entity populated with post, so display this data.
         }
         // else valid save, so go back to gridview: default mode 0
     } elseif (array_key_exists('sample_id', $_GET)) {
         $mode = 2;
         $loadID = $_GET['sample_id'];
     } else {
         if (array_key_exists('newSample', $_GET)) {
             $mode = 1;
             data_entry_helper::$entity_to_load = array();
         }
     }
     // else default to mode 0
     $attributes = data_entry_helper::getAttributes(array('id' => data_entry_helper::$entity_to_load['sample:id'], 'valuetable' => 'sample_attribute_value', 'attrtable' => 'sample_attribute', 'key' => 'sample_id', 'fieldprefix' => 'smpAttr', 'extraParams' => $auth['read'], 'survey_id' => $args['survey_id']));
     ///////////////////////////////////////////////////////////////////
     // default mode 0 : display grid of the samples to add a new one
     // or edit an existing one.
     ///////////////////////////////////////////////////////////////////
     if ($mode == 0) {
         return self::getSampleListGrid($args, $node, $auth, $attributes);
     }
     ///////////////////////////////////////////////////////////////////
     data_entry_helper::$javascript .= "\n// Create vector layers: one to display the location onto, and another for the occurrence list\n// the default edit layer is used for the occurrences themselves\nlocStyleMap = new OpenLayers.StyleMap({\n                \"default\": new OpenLayers.Style({\n                    fillColor: \"Green\",\n                    strokeColor: \"Black\",\n                    fillOpacity: 0.3,\n                    strokeWidth: 1\n                  })\n  });\nlocationLayer = new OpenLayers.Layer.Vector(\"" . lang::get("LANG_Location_Layer") . "\",\n                                    {styleMap: locStyleMap});\n";
     if ($loadID) {
         $url = $svcUrl . '/data/sample/' . $loadID;
         $url .= "?mode=json&view=detail&auth_token=" . $auth['read']['auth_token'] . "&nonce=" . $auth['read']["nonce"];
         $session = curl_init($url);
         curl_setopt($session, CURLOPT_RETURNTRANSFER, true);
         $entity = json_decode(curl_exec($session), true);
         // Build a list of the sample data.
         data_entry_helper::$entity_to_load = array();
         foreach ($entity[0] as $key => $value) {
             data_entry_helper::$entity_to_load['sample:' . $key] = $value;
         }
         data_entry_helper::$entity_to_load['sample:geom'] = '';
         // value received from db is not WKT, which is assumed by all the code.
         data_entry_helper::$entity_to_load['sample:date'] = data_entry_helper::$entity_to_load['sample:date_start'];
         // bit of a bodge to get around vague dates.
     }
     $defAttrOptions = array('extraParams' => $auth['read']);
     //    $r .= "<h1>MODE = ".$mode."</h1>";
     //    $r .= "<h2>readOnly = ".$readOnly."</h2>";
     $r = "<form method=\"post\" id=\"entry_form\">\n";
     // Get authorisation tokens to update the Warehouse, plus any other hidden data.
     $hiddens = $auth['write'] . "<input type=\"hidden\" id=\"website_id\" name=\"website_id\" value=\"" . $args['website_id'] . "\" />\n" . "<input type=\"hidden\" id=\"sample:survey_id\" name=\"sample:survey_id\" value=\"" . $args['survey_id'] . "\" />\n";
     if (array_key_exists('sample:id', data_entry_helper::$entity_to_load)) {
         $hiddens .= "<input type=\"hidden\" id=\"sample:id\" name=\"sample:id\" value=\"" . data_entry_helper::$entity_to_load['sample:id'] . "\" />\n";
     }
     if (array_key_exists('occurrence:id', data_entry_helper::$entity_to_load)) {
         $hiddens .= "<input type=\"hidden\" id=\"occurrence:id\" name=\"occurrence:id\" value=\"" . data_entry_helper::$entity_to_load['occurrence:id'] . "\" />\n";
     }
     // Check if Record Status is included as a control. If not, then add it as a hidden.
     $arr = explode("\r\n", $args['structure']);
     if (!in_array('[record status]', $arr)) {
         $value = isset($args['defaults']['occurrence:record_status']) ? $args['defaults']['occurrence:record_status'] : 'C';
         $hiddens .= "<input type=\"hidden\" id=\"occurrence:record_status\" name=\"occurrence:record_status\" value=\"{$value}\" />\n";
     }
     // request automatic JS validation
     data_entry_helper::enable_validation('entry_form');
     $attributes = data_entry_helper::getAttributes(array('id' => data_entry_helper::$entity_to_load['sample:id'], 'valuetable' => 'sample_attribute_value', 'attrtable' => 'sample_attribute', 'key' => 'sample_id', 'fieldprefix' => 'smpAttr', 'extraParams' => $auth['read'], 'survey_id' => $args['survey_id']));
     // If logged in, output some hidden data about the user
     foreach ($attributes as &$attribute) {
         if (strcasecmp($attribute['caption'], 'cms user id') == 0) {
             if ($logged_in) {
                 $attribute['value'] = $user->uid;
             }
             $attribute['handled'] = true;
             // user id attribute is never displayed
         } elseif (strcasecmp($attribute['caption'], 'cms username') == 0) {
             if ($logged_in) {
                 $attribute['value'] = $user->name;
             }
             $attribute['handled'] = true;
             // username attribute is never displayed
         } elseif (strcasecmp($attribute['caption'], 'email') == 0) {
             if ($logged_in) {
                 $attribute['value'] = $user->mail;
                 $attribute['handled'] = true;
                 // email attribute is displayed unless logged in
             }
         } elseif ((strcasecmp($attribute['caption'], 'first name') == 0 || strcasecmp($attribute['caption'], 'last name') == 0 || strcasecmp($attribute['caption'], 'surname') == 0) && $logged_in) {
             $attribute['handled'] = true;
         }
         // name attributes are displayed unless logged in
         if (isset($attribute['value'])) {
             $hiddens .= '<input type="hidden" name="' . $attribute['fieldname'] . '" value="' . $attribute['value'] . '" />' . "\n";
         }
     }
     $customAttributeTabs = self::get_attribute_tabs($attributes);
     $tabs = self::get_all_tabs($args['structure'], $customAttributeTabs);
     $r .= "<div id=\"controls\">\n";
     // Output the dynamic tab headers
     if ($args['interface'] != 'one_page') {
         $r .= "<ul>\n";
         foreach ($tabs as $tab => $tabContent) {
             $alias = preg_replace('/[^a-zA-Z0-9]/', '', strtolower($tab));
             $tabtitle = lang::get("LANG_Tab_{$alias}");
             if ($tabtitle == "LANG_Tab_{$alias}") {
                 // if no translation provided, we'll just use the standard heading
                 $tabtitle = $tab;
             }
             $r .= '  <li><a href="#' . $alias . '"><span>' . $tabtitle . "</span></a></li>\n";
         }
         $r .= "</ul>\n";
         data_entry_helper::enable_tabs(array('divId' => 'controls', 'style' => $args['interface']));
     }
     // Output the dynamic tab content
     $pageIdx = 0;
     foreach ($tabs as $tab => $tabContent) {
         // get a machine readable alias for the heading
         $tabalias = preg_replace('/[^a-zA-Z0-9]/', '', strtolower($tab));
         $r .= '<div id="' . $tabalias . '">' . "\n";
         if ($pageIdx == 0) {
             // output the hidden inputs on the first tab
             $r .= $hiddens;
         }
         // 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 = $tabContent[$i];
             if (preg_match('/\\A\\?[^¬]*\\?\\z/', trim($component)) === 1) {
                 // Component surrounded by ? so represents a help text
                 $helpText = substr(trim($component), 1, -1);
                 $r .= '<p class="page-notice ui-state-highlight ui-corner-all">' . lang::get($helpText) . "</p>";
             } elseif (preg_match('/\\A\\[[^¬]*\\]\\z/', trim($component)) === 1) {
                 // Component surrounded by [] so represents a control
                 $method = 'get_control_' . preg_replace('/[^a-zA-Z0-9]/', '', strtolower($component));
                 // 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) == '@') {
                     $i++;
                     $option = explode('=', substr($tabContent[$i], 1));
                     $options[$option[0]] = $option[1];
                 }
                 if (method_exists('iform_mnhnl_dynamic_1', $method)) {
                     $r .= self::$method($auth, $args, $tabalias, $options);
                 } elseif (trim($component) === '[*]') {
                     $r .= self::get_attribute_html($attributes, $defAttrOptions, $tab);
                 } else {
                     $r .= "The form structure includes a control called {$component} which is not recognised.<br/>";
                 }
             }
         }
         // Add any buttons required at the bottom of the tab
         if ($args['interface'] == 'wizard') {
             $r .= data_entry_helper::wizard_buttons(array('divId' => 'controls', 'page' => $pageIdx === 0 ? 'first' : ($pageIdx == count($tabs) - 1 ? 'last' : 'middle')));
         } elseif ($pageIdx == count($tabs) - 1 && !($args['interface'] == 'tabs' && $args['save_button_below_all_pages'])) {
             // last part of a non wizard interface must insert a save button, unless it is tabbed interface with save button beneath all pages
             $r .= "<input type=\"submit\" class=\"ui-state-default ui-corner-all\" value=\"" . lang::get('LANG_Save') . "\" />\n";
         }
         $pageIdx++;
         $r .= "</div>\n";
     }
     $r .= "</div>\n";
     if ($args['interface'] == 'tabs' && $args['save_button_below_all_pages']) {
         $r .= "<input type=\"submit\" class=\"ui-state-default ui-corner-all\" value=\"" . lang::get('LANG_Save') . "\" />\n";
     }
     if (!empty(data_entry_helper::$validation_errors)) {
         $r .= data_entry_helper::dump_remaining_errors();
     }
     $r .= "</form>";
     // may need to keep following code for location change functionality
     data_entry_helper::$onload_javascript .= "\n    \nlocationChange = function(obj){\n\tlocationLayer.destroyFeatures();\n\tif(obj.value != ''){\n\t\tjQuery.getJSON(\"" . $svcUrl . "\" + \"/data/location/\"+obj.value +\n\t\t\t\"?mode=json&view=detail&auth_token=" . $auth['read']['auth_token'] . "&nonce=" . $auth['read']["nonce"] . "\" +\n\t\t\t\"&callback=?\", function(data) {\n        if (data.length>0) {\n          var parser = new OpenLayers.Format.WKT();\n          for (var i=0;i<data.length;i++) {\n            if(data[i].centroid_geom){\n              feature = parser.read(data[i].centroid_geom);\n              centre = feature.geometry.getCentroid();\n              centrefeature = new OpenLayers.Feature.Vector(centre, {}, {label: data[i].name});\n              locationLayer.addFeatures([feature, centrefeature]); \n            }\n            if (data[i].boundary_geom){\n              feature = parser.read(data[i].boundary_geom);\n              feature.style = {strokeColor: \"Blue\",\n                  strokeWidth: 2,\n                  label: (data[i].centroid_geom ? \"\" : data[i].name)};\n                  locationLayer.addFeatures([feature]);\n            }\n          }\n          var extent=locationLayer.getDataExtent();\n          if (extent!==null) {\n            locationLayer.map.zoomToExtent(extent);\n          }\n        }\n\t\t  }\n    );\n  }\n};\njQuery('#imp-location').unbind('change');\njQuery('#imp-location').change(function(){\n\tlocationChange(this);\n});\n\nvar updatePlaceTabHandler = function(event, ui) { \n  if (ui.panel.id=='place') {\n    // upload location & sref initial values into map.\n    jQuery('#imp-location').change();\n    jQuery('#imp-sref').change();\n    jQuery('#controls').unbind('tabsshow', updatePlaceTabHandler);\n  }\n}\njQuery('#controls').bind('tabsshow', updatePlaceTabHandler);\n\n";
     return $r;
 }