private static function _getCacheFileName($userID) { /* If timeout is not set, we're not caching */ $path = data_entry_helper::$cache_folder ? data_entry_helper::$cache_folder : data_entry_helper::relative_client_helper_path() . 'cache/'; if (!is_dir($path) || !is_writeable($path)) { return false; } return $path . 'cache_' . data_entry_helper::$website_id . '_CMS_User_List_' . $userID; }
private static function get_template_with_map($args, $readAuth, $extraParams, $paramDefaults) { $r = '<div id="outer-with-map" class="ui-helper-clearfix">'; $r .= '<div id="grid" class="left" style="width:65%">{paramsForm}{grid}</div>'; $r .= '<div id="map-and-record" class="right" style="width: 34%"><div id="summary-map">'; $options = iform_map_get_map_options($args, $readAuth); $olOptions = iform_map_get_ol_options($args); // This is used for drawing, so need an editlayer, but not used for input $options['editLayer'] = true; $options['editLayerInSwitcher'] = true; $options['clickForSpatialRef'] = false; $options['featureIdField'] = 'occurrence_id'; $r .= map_helper::map_panel($options, $olOptions); $reportMapOpts = array('dataSource' => !empty($args['mapping_report_name']) ? $args['mapping_report_name'] : $args['report_name'], 'mode' => 'report', 'readAuth' => $readAuth, 'autoParamsForm' => false, 'extraParams' => $extraParams, 'paramDefaults' => $paramDefaults, 'reportGroup' => 'verification', 'clickableLayersOutputMode' => 'report', 'rowId' => 'occurrence_id', 'sharing' => 'verification', 'ajax' => TRUE); if (!empty($args['mapping_report_name_lores'])) { $reportMapOpts['dataSourceLoRes'] = $args['mapping_report_name_lores']; } $r .= report_helper::report_map($reportMapOpts); $r .= '</div>'; global $user; if (function_exists('hostsite_get_user_field') && ($locationId = hostsite_get_user_field('location_expertise', false))) { iform_map_zoom_to_location($locationId, $readAuth); } $r .= '<div id="record-details-wrap" class="ui-widget ui-widget-content">'; $r .= self::instructions('grid on the left'); $r .= '<div id="record-details-content" style="display: none">'; $r .= '<div id="record-details-toolbar">'; $r .= '<div id="verify-buttons">'; $r .= '<div id="verify-buttons-inner">'; $r .= '<label>' . lang::get('Actions:') . '</label>'; $imgPath = empty(data_entry_helper::$images_path) ? data_entry_helper::relative_client_helper_path() . "../media/images/" : data_entry_helper::$images_path; $r .= '<button type="button" id="btn-verify" title="' . lang::get('Verify') . '"><img width="18" height="18" src="' . $imgPath . 'nuvola/ok-16px.png"/></button>'; $r .= '<button type="button" id="btn-edit-verify" title="' . lang::get('Edit determination then verify') . '"><img width="18" height="18" src="' . $imgPath . 'nuvola/package_editors-16px.png"/>' . '<img width="18" height="18" src="' . $imgPath . 'nuvola/ok-16px.png"/></button>'; $r .= '<button type="button" id="btn-reject" title="' . lang::get('Reject') . '"><img width="18" height="18" src="' . $imgPath . 'nuvola/cancel-16px.png"/></button>'; $r .= '<button type="button" id="btn-query" title="' . lang::get('Query') . '"><img width="18" height="18" src="' . $imgPath . 'nuvola/dubious-16px.png"/></button>'; $r .= '<div id="redet-dropdown-ctnr" style="display: none"><div id="redet-dropdown">'; $r .= data_entry_helper::species_autocomplete(array('fieldname' => 'redet', 'label' => lang::get('New determination'), 'labelClass' => 'auto', 'helpText' => lang::get('Enter a new determination for this record before verifying it. The previous determination will be stored with the record.'), 'cacheLookup' => true, 'extraParams' => $readAuth + array('taxon_list_id' => 1), 'speciesIncludeBothNames' => true, 'speciesIncludeTaxonGroup' => true)); $r .= '</div></div>'; $r .= '</div></div>'; $r .= '<label>Contact:</label>'; $r .= '<button type="button" id="btn-email-expert" class="default-button">' . lang::get('Another expert') . '</button>'; $r .= '<button type="button" id="btn-email-recorder" class="default-button">' . lang::get('Recorder') . '</button>'; $r .= '</div>'; $r .= '<div id="record-details-tabs">'; // note - there is a dependency in the JS that comments is the last tab and media the 2nd to last. $r .= data_entry_helper::tab_header(array('tabs' => array('#details-tab' => lang::get('Details'), '#experience-tab' => lang::get('Experience'), '#phenology-tab' => lang::get('Phenology'), '#media-tab' => lang::get('Media'), '#comments-tab' => lang::get('Comments')))); data_entry_helper::$javascript .= "indiciaData.detailsTabs = ['details','experience','phenology','media','comments'];\n"; data_entry_helper::enable_tabs(array('divId' => 'record-details-tabs')); $r .= '<div id="details-tab"></div>'; $r .= self::other_tab_html(); $r .= '</div></div></div></div></div>'; return $r; }
protected static function get_tab_content($auth, $args, $tab, $tabContent, $tabalias, &$attributes, &$hasControls) { // cols array used if we find | splitters $cols = array(); $defAttrOptions = array('extraParams' => $auth['read']); if (isset($args['attribute_termlist_language_filter']) && $args['attribute_termlist_language_filter']) { $defAttrOptions['language'] = iform_lang_iso_639_2($args['language']); } //create array of attribute field names to test against later $attribNames = array(); foreach ($attributes as $key => $attrib) { $attribNames[$key] = $attrib['id']; } $html = ''; // Now output the content of the tab. Use a for loop, not each, so we can treat several rows as one object for ($i = 0; $i < count($tabContent); $i++) { $component = trim($tabContent[$i]); if (preg_match('/\\A\\?[^�]*\\?\\z/', $component) === 1) { // Component surrounded by ? so represents a help text $helpText = substr($component, 1, -1); $html .= '<div class="page-notice ui-state-highlight ui-corner-all">' . lang::get($helpText) . "</div>"; } elseif (preg_match('/\\A\\[[^�]*\\]\\z/', $component) === 1) { // Component surrounded by [] so represents a control or control block // Anything following the component that starts with @ is an option to pass to the control $options = array(); while ($i < count($tabContent) - 1 && substr($tabContent[$i + 1], 0, 1) == '@' || trim($tabContent[$i]) === '') { $i++; // ignore empty lines if (trim($tabContent[$i]) !== '') { $option = explode('=', substr($tabContent[$i], 1), 2); if (!isset($option[1]) || $option[1] === 'false') { $options[$option[0]] = FALSE; } else { $options[$option[0]] = json_decode($option[1], TRUE); // if not json then need to use option value as it is if ($options[$option[0]] == '') { $options[$option[0]] = $option[1]; } } // urlParam is special as it loads the control's default value from $_GET if ($option[0] === 'urlParam' && isset($_GET[$option[1]])) { $options['default'] = $_GET[$option[1]]; } } } // if @permission specified as an option, then check that the user has access to this control if (!empty($options['permission']) && !user_access($options['permission'])) { continue; } $parts = explode('.', str_replace(array('[', ']'), '', $component)); $method = 'get_control_' . preg_replace('/[^a-zA-Z0-9]/', '', strtolower($component)); if (!empty($args['high_volume']) && $args['high_volume']) { // enable control level report caching when in high_volume mode $options['caching'] = empty($options['caching']) ? true : $options['caching']; $options['cachetimeout'] = empty($options['cachetimeout']) ? HIGH_VOLUME_CONTROL_CACHE_TIMEOUT : $options['cachetimeout']; } // allow user settings to override the control - see iform_user_ui_options.module if (isset(data_entry_helper::$data['structureControlOverrides']) && !empty(data_entry_helper::$data['structureControlOverrides'][$component])) { $options = array_merge($options, data_entry_helper::$data['structureControlOverrides'][$component]); } if (count($parts) === 1 && method_exists(self::$called_class, $method)) { //outputs a control for which a specific output function has been written. $html .= call_user_func(array(self::$called_class, $method), $auth, $args, $tabalias, $options); $hasControls = true; } elseif (count($parts) === 2) { require_once dirname($_SERVER['SCRIPT_FILENAME']) . '/' . data_entry_helper::relative_client_helper_path() . '/prebuilt_forms/extensions/' . $parts[0] . '.php'; if (method_exists('extension_' . $parts[0], $parts[1])) { //outputs a control for which a specific extension function has been written. $path = call_user_func(array(self::$called_class, 'getReloadPath')); //pass the classname of the form through to the extension control method to allow access to calling class functions and variables $args["calling_class"] = 'iform_' . self::$node->iform; $html .= call_user_func(array('extension_' . $parts[0], $parts[1]), $auth, $args, $tabalias, $options, $path, $attributes); $hasControls = true; // auto-add JavaScript for the extension if (file_exists(iform_client_helpers_path() . 'prebuilt_forms/extensions/' . $parts[0] . '.js')) { drupal_add_js(iform_client_helpers_path() . 'prebuilt_forms/extensions/' . $parts[0] . '.js', array('preprocess' => FALSE)); } if (file_exists(iform_client_helpers_path() . 'prebuilt_forms/extensions/' . $parts[0] . '.css')) { drupal_add_css(iform_client_helpers_path() . 'prebuilt_forms/extensions/' . $parts[0] . '.css', array('preprocess' => FALSE)); } } else { $html .= lang::get("The {$component} extension cannot be found."); } } elseif (($attribKey = array_search(substr($component, 1, -1), $attribNames)) !== false || preg_match('/^\\[[a-zA-Z]+:(?P<ctrlId>[0-9]+)\\]/', $component, $matches)) { // control is a smpAttr or other attr control. if (empty($options['extraParams'])) { $options['extraParams'] = array_merge($defAttrOptions['extraParams']); } else { $options['extraParams'] = array_merge($defAttrOptions['extraParams'], (array) $options['extraParams']); } //merge extraParams first so we don't loose authentication $options = array_merge($defAttrOptions, $options); foreach ($options as $key => &$value) { $value = apply_user_replacements($value); } if ($attribKey !== false) { // a smpAttr control $html .= data_entry_helper::outputAttribute($attributes[$attribKey], $options); $attributes[$attribKey]['handled'] = true; } else { // if the control name of form name:id, then we will call get_control_name passing the id as a parameter $method = 'get_control_' . preg_replace('/[^a-zA-Z]/', '', strtolower($component)); if (method_exists(self::$called_class, $method)) { $options['ctrlId'] = $matches['ctrlId']; $html .= call_user_func(array(self::$called_class, $method), $auth, $args, $tabalias, $options); } else { $html .= "Unsupported control {$component}<br/>"; } } $hasControls = true; } elseif ($component === '[*]') { // this outputs any custom attributes that remain for this tab. The custom attributes can be configured in the // settings text using something like @smpAttr:4|label=My label. The next bit of code parses these out into an // array used when building the html. // Alternatively, a setting like @option=value is applied to all the attributes. $attrSpecificOptions = array(); foreach ($options as $option => $value) { // split the id of the option into the control name and option name. $optionId = explode('|', $option); if (count($optionId) > 1) { // Found an option like @smpAttr:4|label=My label if (!isset($attrSpecificOptions[$optionId[0]])) { $attrSpecificOptions[$optionId[0]] = array(); } $attrSpecificOptions[$optionId[0]][$optionId[1]] = apply_user_replacements($value); } else { // Found an option like @option=value $defAttrOptions = array_merge($defAttrOptions, array($option => $value)); } } $attrHtml = get_attribute_html($attributes, $args, $defAttrOptions, $tab, $attrSpecificOptions); if (!empty($attrHtml)) { $hasControls = true; } $html .= $attrHtml; } else { $html .= "The form structure includes a control called {$component} which is not recognised.<br/>"; //ensure $hasControls is true so that the error message is shown $hasControls = true; } } elseif ($component === '|') { // column splitter. So, store the col html and start on the next column. $cols[] = $html; $html = ''; } else { // output anything else as is. This allow us to add html to the form structure. $html .= $component; } } if (count($cols) > 0) { $cols[] = $html; // a splitter in the structure so put the stuff so far in a 50% width left float div, and the stuff that follows in a 50% width right float div. global $indicia_templates; $html = str_replace(array('{col-1}', '{col-2}'), $cols, $indicia_templates['two-col-50']); if (count($cols) > 2) { unset($cols[1]); unset($cols[0]); $html .= '<div class="follow_on_block" style="clear:both;">' . implode('', $cols) . '</div>'; } else { $html .= '<div class="follow_on_block" style="clear:both;"></div>'; } // needed so any tab div is stretched around them } return $html; }
/** * Takes a file that has been uploaded to the client website upload folder, and moves it to the warehouse upload folder using the * data services. * * @param string $path Path to the file to upload, relative to the interim image path folder (normally the * client_helpers/upload folder. * @param boolean $persist_auth Allows the write nonce to be preserved after sending the file, useful when several files * are being uploaded. * @return string Error message, or true if successful. */ private static function send_file_to_warehouse($path, $persist_auth = false) { $interim_image_folder = isset(parent::$interim_image_folder) ? parent::$interim_image_folder : 'upload/'; $uploadpath = data_entry_helper::relative_client_helper_path() . $interim_image_folder; $serviceUrl = parent::$base_url . "/index.php/services/data/handle_media"; // This is used by the file box control which renames uploaded files using a guid system, so disable renaming on the server. $postargs = array('name_is_guid' => 'true'); // attach authentication details if (array_key_exists('auth_token', $_POST)) { $postargs['auth_token'] = $_POST['auth_token']; } if (array_key_exists('nonce', $_POST)) { $postargs['nonce'] = $_POST['nonce']; } if ($persist_auth) { $postargs['persist_auth'] = 'true'; } $file_to_upload = array('media_upload' => '@' . realpath($uploadpath . $path)); $response = data_entry_helper::http_post($serviceUrl, $file_to_upload + $postargs); $output = json_decode($response['output'], true); $r = true; // default is success if (is_array($output)) { //an array signals an error if (array_key_exists('error', $output)) { // return the most detailed bit of error information if (isset($output['errors']['media_upload'])) { $r = $output['errors']['media_upload']; } else { $r = $output['error']; } } } //remove local copy //unlink(realpath($uploadpath.$path)); watchdog('file exists', realpath($uploadpath . $path)); return $r; }
private static function get_notifications_html($auth, $sourceType, $website_id, $user_id, $options) { iform_load_helpers(array('report_helper')); $imgPath = empty(data_entry_helper::$images_path) ? data_entry_helper::relative_client_helper_path() . "../media/images/" : data_entry_helper::$images_path; $sendReply = $imgPath . "nuvola/mail_send-22px.png"; $cancelReply = $imgPath . "nuvola/mail_delete-22px.png"; //When the user wants to reply to a message, we have to add a new row report_helper::$javascript .= "\n indiciaData.reply_to_message = function(notification_id, occurrence_id) {\n if (!\$('#reply-row-'+occurrence_id).length) {\n rowHtml = '<tr id='+\"reply-row-\"+occurrence_id+'><td><label for=\"\">" . lang::get('Enter your reply below') . ":</label><textarea style=\"width: 95%\" id=\"reply-' +occurrence_id+'\"></textarea></td>';\n rowHtml += '<td class=\"actions\">';\n rowHtml += '<div><img class=\"action-button\" src=\"{$sendReply}\" onclick=\"reply('+occurrence_id+','+notification_id+',true);\" title=\"Send reply\">';\n rowHtml += '<img class=\"action-button\" src=\"{$cancelReply}\" onclick=\"reply('+occurrence_id+','+notification_id+',false);\" title=\"Cancel reply\">';\n rowHtml += '</div></td></tr>';\n \$(rowHtml).insertAfter('tr#row'+notification_id);\n \$('tr#row'+notification_id+' .action-button').hide();\n }\n };\n\n "; $urlParams = array('occurrence_id' => '{occurrence_id}'); if (!empty($_GET['group_id'])) { $urlParams['group_id'] = $_GET['group_id']; } $availableActions = array(array('caption' => lang::get('Edit this record'), 'class' => 'edit-notification', 'url' => '{rootFolder}{editing_form}', 'urlParams' => $urlParams, 'img' => $imgPath . 'nuvola/package_editors-22px.png', 'visibility_field' => 'editable_flag'), array('caption' => lang::get('View this record'), 'class' => 'view-notification', 'url' => '{rootFolder}{viewing_form}', 'urlParams' => $urlParams, 'img' => $imgPath . 'nuvola/find-22px.png', 'visibility_field' => 'viewable_flag'), array('caption' => lang::get('Mark as read'), 'javascript' => 'remove_message({notification_id});', 'img' => $imgPath . 'nuvola/kmail-22px.png')); //Only allow replying for 'user' messages. if (isset($options['allowReply']) && $options['allowReply'] === true) { $availableActions = array_merge($availableActions, array(array('caption' => lang::get('Reply to this message'), 'img' => $imgPath . 'nuvola/mail_reply-22px.png', 'visibility_field' => 'reply_flag', 'javascript' => "indiciaData.reply_to_message(" . '{notification_id}' . "," . '{occurrence_id}' . ");"))); } $extraParams = array('user_id' => $user_id, 'system_name' => 'indicia', 'orderby' => 'triggered_on', 'sortdir' => 'DESC', 'default_edit_page_path' => $options['default_edit_page_path'], 'view_record_page_path' => $options['view_record_page_path'], 'website_id' => $website_id); //Implode the source types so we can submit to the database in one text field. if (!empty($sourceType)) { $extraParams['source_types'] = "'" . implode("' ,'", $sourceType) . "'"; //If the user has supplied some config options for the different source types then we don't need the // source filter drop down. $extraParams['source_filter'] = 'all'; } //Only include notifications associated with a set of recording group ids if option is supplied. if (!empty($options['groupIds'])) { $extraParams['group_ids'] = $options['groupIds']; } $columns = array('data' => array('fieldname' => 'data', 'json' => true, 'template' => '<div class="type-{source_type}"><div class="status-{record_status}"></div></div><div class="note-type-{source_type}">{comment}</div>' . '<div class="comment-from helpText" style="margin-left: 34px; display: block;">from {username} on {triggered_date}</div>', 'display' => 'Message'), 'occurrence_id' => array('fieldname' => 'occurrence_id'), 'actions' => array('actions' => $availableActions), 'triggered_date' => array('fieldname' => 'triggered_date', 'visible' => false)); // allow columns config to override our default setup if (!empty($options['columns'])) { foreach ($options['columns'] as $column) { if (!empty($column['actions'])) { $columns['actions'] = $column; } elseif (!empty($column['fieldname'])) { $columns[$column['fieldname']] = $column; } } } $r = report_helper::report_grid(array('id' => 'notifications-' . $options['id'], 'readAuth' => $auth['read'], 'itemsPerPage' => 10, 'dataSource' => 'library/notifications/notifications_list_for_notifications_centre', 'rowId' => 'notification_id', 'ajax' => true, 'mode' => 'report', 'extraParams' => $extraParams, 'paramDefaults' => array('source_filter' => 'all'), 'paramsFormButtonCaption' => lang::get('Filter'), 'columns' => array_values($columns))); return $r; }
/** * Survey control that supports multiple surveys each with a date */ protected static function get_control_surveys($auth, $args, $tabalias, $options) { //Get the Delete icon for the Surveys Grid $imgPath = empty(data_entry_helper::$images_path) ? data_entry_helper::relative_client_helper_path() . "../media/images/" : data_entry_helper::$images_path; $deleteIcon = $imgPath . "delete.png"; //Pass the delete icon to javascript data_entry_helper::$javascript .= "indiciaData.deleteImagePath='" . $deleteIcon . "';\n"; if (!empty($_GET['parent_id'])) { $countUnitId = $_GET['parent_id']; } else { $countUnitId = $_GET['location_id']; } //Get the data for all surveys that are relevant $surveysData = data_entry_helper::get_population_data(array('table' => 'survey', 'extraParams' => $auth['read'], 'nocache' => true, 'sharing' => $sharing)); //If we are in edit mode, then collect the data relating to the previously selected surveys, the ID and Date are //held as JSON, so we need to decode it. if ($countUnitId) { $selectedSurveysData = data_entry_helper::get_population_data(array('table' => 'location_attribute_value', 'extraParams' => $auth['read'] + array('location_attribute_id' => $args['surveys_attribute_id'], 'location_id' => $countUnitId), 'nocache' => true, 'sharing' => $sharing)); if (!empty($selectedSurveysData)) { foreach ($selectedSurveysData as $idx => $theSurveyData) { $decodedSavedSurvey[$idx] = json_decode($theSurveyData['raw_value']); $decodedSavedSurveyIds[$idx] = $decodedSavedSurvey[$idx][0]; } } } //We need to populate the surveys drop-down but not include items that are already on the grid. $r = '<div id="surveys-control">'; $r .= '<h3>Surveys</h3>'; $r .= '<label>Surveys: </label><select id = "survey-select">'; $r .= '<option id="please-select-surveys-item">Please Select</option>'; if (!empty($surveysData)) { foreach ($surveysData as $surveyData) { if (empty($decodedSavedSurveyIds) || !in_array($surveyData['id'], $decodedSavedSurveyIds)) { $r .= '<option id="survey-select-' . $surveyData['id'] . '" value="' . $surveyData['id'] . '">' . $surveyData['title'] . '</option>'; } //Get the names of the survey items in the grid and save them in an array where the ids are the keys - for use in a minute if (!empty($decodedSavedSurveyIds)) { if (in_array($surveyData['id'], $decodedSavedSurveyIds)) { $surveyNameInGrid[$surveyData['id']]['title'] = $surveyData['title']; } } } } $r .= '</select><br>'; $r .= data_entry_helper::date_picker(array_merge(array('label' => lang::get('LANG_Location_Surveys_Date'), 'fieldname' => 'survey:date'), $options)); $r .= '</br>'; $r .= '<input type="button" id="select-surveys-add" value="Add" onclick="select_survey_and_date();"><br>'; $r .= '<table id="surveys-table" id="surveys-table" border="3">' . '<tr>' . '<th>Survey Id</th>' . '<th>Survey Name</th>' . '<th>Date</th>' . '<th>Remove</th>' . '<th style="display:none;">Existing Attribute Id</th>' . '<th style="display:none;" type="hidden">Deleted</th></tr>' . '<tr>' . '</tr>'; if ($countUnitId) { if (!empty($selectedSurveysData)) { foreach ($selectedSurveysData as $idx => $theSurveyData) { //Add a row to the grid of Selected Suveys and Dates for each existing survey that has been saved against the Count Unit //Note we use the Survey Id on the end of the various html ids. The fields that will be used in submission also have a //"name" otherwise they won't show in the submission $values variable $r .= "\r\n <tr id='" . "selected-survey-row-" . $decodedSavedSurvey[$idx][0] . "'>\r\n <td>\r\n <input style='border: none;' id='" . "selected-survey-id-" . $decodedSavedSurvey[$idx][0] . "' name='" . "selected-survey-id-" . $decodedSavedSurvey[$idx][0] . "' value='" . $decodedSavedSurvey[$idx][0] . "' readonly>\r\n </td>\r\n <td>\r\n <input style='border: none;' id='" . "selected-survey-name-" . $decodedSavedSurvey[$idx][0] . "' value='" . $surveyNameInGrid[$decodedSavedSurvey[$idx][0]]['title'] . "' readonly>\r\n </td>\r\n <td>\r\n <input id='" . "selected-survey-date-" . $decodedSavedSurvey[$idx][0] . "' name='" . "selected-survey-date-" . $decodedSavedSurvey[$idx][0] . "' value='" . $decodedSavedSurvey[$idx][1] . "'>\r\n </td>\r\n <td>\r\n <img class=\"action-button\" src=\"{$deleteIcon}\" onclick=\"remove_survey_selection(" . $decodedSavedSurvey[$idx][0] . ",'" . $surveyNameInGrid[$decodedSavedSurvey[$idx][0]]['title'] . "');\" title=\"Delete Survey Selection\">\r\n </td>\r\n <td style='display:none;'>\r\n <input id='" . "selected-survey-existing-" . $decodedSavedSurvey[$idx][0] . "' name='" . "selected-survey-existing-" . $decodedSavedSurvey[$idx][0] . "' value='" . $theSurveyData['id'] . "'>\r\n </td>\r\n <td style='display:none;'>\r\n <input id='" . "selected-survey-deleted-" . $decodedSavedSurvey[$idx][0] . "' name='" . "selected-survey-deleted-" . $decodedSavedSurvey[$idx][0] . "' value='false'>\r\n </td>\r\n </tr>"; } } } $r .= '</table>'; $r .= '</div>'; return $r; }
private static function get_notifications_html($auth, $sourceType, $website_id, $user_id, $options) { iform_load_helpers(array('report_helper')); global $auth; $readNonce = $auth['nonce']; $readAuthToken = $auth['auth_token']; $imgPath = empty(data_entry_helper::$images_path) ? data_entry_helper::relative_client_helper_path() . "../media/images/" : data_entry_helper::$images_path; $sendReply = $imgPath . "nuvola/mail_send-22px.png"; $cancelReply = $imgPath . "nuvola/mail_delete-22px.png"; //When the user wants to reply to a message, we have to add a new row report_helper::$javascript .= "\n indiciaData.reply_to_message = function(notification_id, occurrence_id) {\n if (!\$('#reply-row-'+occurrence_id).length) {\n rowHtml = '<tr id='+\"reply-row-\"+occurrence_id+'><td><label for=\"\">" . lang::get('Enter your reply below') . ":</label><textarea style=\"width: 95%\" id=\"reply-' +occurrence_id+'\"></textarea></td>';\n rowHtml += '<td class=\"actions\">';\n rowHtml += '<div><img class=\"action-button\" src=\"{$sendReply}\" onclick=\"reply('+occurrence_id+','+notification_id+',true);\" title=\"Send reply\">';\n rowHtml += '<img class=\"action-button\" src=\"{$cancelReply}\" onclick=\"reply('+occurrence_id+','+notification_id+',false);\" title=\"Cancel reply\">';\n rowHtml += '</div></td></tr>';\n \$(rowHtml).insertAfter('tr#row'+notification_id);\n \$('tr#row'+notification_id+' .action-button').hide();\n }\n };\n\n "; //Setup the javascript needed to support the remove notification button. self::setup_source_types_hidden_fields($options, $sourceType, $website_id, $auth); $auth = report_helper::get_read_auth(variable_get('indicia_website_id', ''), variable_get('indicia_password', '')); //Implode the source types so we can submit to the database in one text field. foreach ($sourceType as &$type) { $type = "'" . $type . "'"; } $sourceType = implode(',', $sourceType); $availableActions = array(array('caption' => lang::get('Edit this record'), 'class' => 'edit-notification', 'url' => '{rootFolder}{editing_form}', 'urlParams' => array('occurrence_id' => '{occurrence_id}'), 'img' => $imgPath . 'nuvola/package_editors-22px.png', 'visibility_field' => 'editable_flag'), array('caption' => lang::get('View this record'), 'class' => 'view-notification', 'url' => '{rootFolder}{viewing_form}', 'urlParams' => array('occurrence_id' => '{occurrence_id}'), 'img' => $imgPath . 'nuvola/find-22px.png', 'visibility_field' => 'viewable_flag'), array('caption' => lang::get('Mark as read'), 'javascript' => 'remove_message({notification_id});', 'img' => $imgPath . 'nuvola/kmail-22px.png')); //Only allow replying for 'user' messages. if ($options['allowReply'] === true) { $availableActions = array_merge($availableActions, array(array('caption' => lang::get('Reply to this message'), 'img' => $imgPath . 'nuvola/mail_reply-22px.png', 'javascript' => "indiciaData.reply_to_message(" . '{notification_id}' . "," . '{occurrence_id}' . ");"))); } return report_helper::report_grid(array('id' => 'notifications-' . $options['id'], 'readAuth' => $auth, 'itemsPerPage' => 10, 'dataSource' => 'library/notifications/notifications_list_for_notifications_centre', 'rowId' => 'notification_id', 'ajax' => true, 'mode' => 'report', 'extraParams' => array('user_id' => $user_id, 'system_name' => 'indicia', 'source_types' => $sourceType, 'orderby' => 'triggered_on', 'sortdir' => 'DESC', 'default_edit_page_path' => $options['default_edit_page_path'], 'view_record_page_path' => $options['view_record_page_path'], 'website_id' => $website_id), 'columns' => array(array('fieldname' => 'data', 'json' => true, 'template' => '<div class="type-{source_type}"><div class="status-{record_status}"></div></div><div class="note-type-{source_type}">{comment}</div>' . '<div class="comment-from helpText" style="margin-left: 34px; display: block;">from {username} on {triggered_date}</div>', 'display' => 'Message'), array('actions' => $availableActions), array('fieldname' => 'triggered_date', 'visible' => false)))); }
private static function get_comments($readAuth, $includeAddNew = true) { iform_load_helpers(array('data_entry_helper')); $comments = data_entry_helper::get_population_data(array('table' => 'sample_comment', 'extraParams' => $readAuth + array('sample_id' => $_GET['sample_id'], 'sortdir' => 'DESC', 'orderby' => 'updated_on'), 'nocache' => true, 'sharing' => 'verification')); $imgPath = empty(data_entry_helper::$images_path) ? data_entry_helper::relative_client_helper_path() . "../media/images/" : data_entry_helper::$images_path; $r = ''; if (count($comments) === 0) { $r .= '<p id="no-comments">' . lang::get('No comments have been made.') . '</p>'; } $r .= '<div id="comment-list">'; foreach ($comments as $comment) { $r .= '<div class="comment">'; $r .= '<div class="header">'; $r .= self::status_icons($comment['record_status'], $imgPath); if ($comment['query'] === 't') { $hint = lang::get('This is a query'); $r .= "<img width=\"12\" height=\"12\" src=\"{$imgPath}nuvola/dubious-16px.png\" title=\"{$hint}\" alt=\"{$hint}\"/>"; } $r .= '<strong>' . (empty($comment['person_name']) ? $comment['username'] : $comment['person_name']) . '</strong> '; $commentTime = strtotime($comment['updated_on']); // Output the comment time. Skip if in future (i.e. server/client date settings don't match) if ($commentTime < time()) { $r .= self::ago($commentTime); } $r .= '</div>'; $c = str_replace("\n", '<br/>', $comment['comment']); $r .= "<div>{$c}</div>"; $r .= '</div>'; } $r .= '</div>'; if ($includeAddNew) { $r .= '<form><fieldset><legend>' . lang::get('Add new comment') . '</legend>'; $r .= '<textarea id="comment-text"></textarea><br/>'; $r .= '<button type="button" class="default-button" onclick="saveComment(jQuery(\'#comment-text\').val());">' . lang::get('Save') . '</button>'; $r .= '</fieldset></form>'; } return $r; }
/** * 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. * @return HTML string */ public static function get_form($args, $node, $response) { $r = ""; data_entry_helper::add_resource('jquery_ui'); if (isset($args['advancedUI']) && $args['advancedUI']) { // TODO Sort out // data_entry_helper::$resource_list['jquery_ui_slider'] = // array('deps' => array('jquery_ui'), 'javascript' => array('/misc/ui/jquery.ui.slider.js')); // data_entry_helper::add_resource('jquery_ui_slider'); // drupal_add_js(drupal_get_path('module', 'jquery_update') .'/replace/ui/ui/jquery.ui.slider.js'); // drupal_add_js('/misc/ui/jquery.ui.slider.min.js'); drupal_add_js('/misc/ui/jquery.ui.slider.js'); // drupal_add_js('/misc/ui/jquery.ui.button.min.js'); } $readAuth = data_entry_helper::get_read_auth($args['website_id'], $args['password']); $now = new DateTime('now'); $year = isset($_REQUEST['year']) ? $_REQUEST['year'] : ($year = $now->format('Y')); iform_load_helpers(array('report_helper', 'map_helper')); $options = iform_report_get_report_options($args, $readAuth); $currentParamValues = array(); if (isset($options['extraParams'])) { foreach ($options['extraParams'] as $key => $value) { // trim data to ensure blank lines are not handled. $key = trim($key); $value = trim($value); // We have found a parameter, so put it in the request to the report service if (!empty($key)) { $currentParamValues[$key] = $value; } } } $extras = '&wantColumns=1&wantParameters=1&' . report_helper::array_to_query_string($currentParamValues, true); $canIDuser = false; // Report record should have location_id, sample_id, occurrence_id, sample_date, species ttl_id, attributes, geometry. created_by_id is optional // Event definition: Name|attribute_id|attribute_values // Loop through event definitions /* $events = array(array('type'=>'arrayVal', 'name'=>'Budburst', 'attr'=>'289', 'values'=>array(3904,3961,3905,3906,3962,3907)), array('type'=>'arrayVal', 'name'=>'Leaf', 'attr'=>'289', 'values'=>array(3906,3962,3907)), array('type'=>'arrayVal', 'name'=>'Flowering', 'attr'=>'291', 'values'=>array(3912,3913,3914,3916,3917,3918)), array('type'=>'presence', 'name'=>'Presence')); */ $events = str_replace("\r\n", "\n", $args['triggerEvents']); $events = str_replace("\r", "\n", $events); $events = explode("\n", trim($events)); foreach ($events as $idx => $event) { $events[$idx] = explode(':', $event); } $triggerEvents = array(); $SpeciesEventSelections = array(); $Species = array(); $r .= '<div id="errorMsg"></div>' . '<table class="ui-widget ui-widget-content ui-corner-all controls-table" id="controls-table">' . '<thead class="ui-widget-header">' . '<tr><th><label for="yearControl">' . lang::get("Year") . ' : </label><select id="yearControl" name="year">'; for ($i = $now->format('Y'); $i >= $args['first_year']; $i--) { $r .= '<option value="' . $i . '">' . $i . '</option>'; } $r .= '</select></th>' . '<th><label for="speciesControl">' . lang::get("Species") . ' : </label><select id="speciesControl"><option value="">' . lang::get("Please select species") . '</option></select></th>' . '<th><label for="eventControl">' . lang::get("Event") . ' : </label><select id="eventControl"><option value="">' . lang::get("Please select event") . '</option>'; foreach ($events as $index => $event) { $r .= '<option value="' . $index . '">' . $event[0] . '</option>'; $triggerEvents[] = '{"name":"' . $event[0] . '","type":"' . $event[1] . '"' . (count($event) > 2 ? ',"attr":' . $event[2] . ',"values":[' . $event[3] . ']' : '') . '}'; } $r .= "</select></th>\n"; if (isset($args['twinMaps']) && $args['twinMaps']) { $r .= '<th><label for="rhsCtrl">' . lang::get("Compare") . ' : </label><select id="rhsCtrl" name="rhsCtrl"><option value="">' . lang::get("Please select.") . '</option><option value="Test">' . lang::get("Test.") . "</option></select></th>\n"; } $r .= '</tr></thead></table>' . "\n"; $args['map_width'] = "auto"; $options = iform_map_get_map_options($args, $readAuth); $olOptions = iform_map_get_ol_options($args); $options['editLayer'] = false; $options['clickForSpatialRef'] = false; $options['scroll_wheel_zoom'] = false; $r .= '<div class="leftMap mapContainers leftMapOnly">' . map_helper::map_panel($options, $olOptions) . '</div>'; $options['divId'] = 'map2'; if (isset($args['twinMaps']) && $args['twinMaps']) { $r .= '<div class="rightMap mapContainers leftMapOnly">' . map_helper::map_panel($options, $olOptions) . '</div>'; } $r .= '<div class="ui-helper-clearfix"></div><div id="timeControls">' . (isset($args['advancedUI']) && $args['advancedUI'] ? '<div id="timeSlider"></div>' : '') . '<div id="toolbar">' . '<span id="dotControlLabel">' . lang::get('Dot Size') . ' :</span>' . (isset($args['advancedUI']) && $args['advancedUI'] ? '<div id="dotSlider"></div>' : '<select id="dotSelect"><option>2</option><option>3</option><option>4</option><option>5</option></select>') . '<button id="beginning">go to beginning</button><button id="playMap">play</button><button id="end">go to end</button>' . '<span id="dateControlLabel">' . lang::get("Date Currently displayed") . ' : ' . (isset($args['advancedUI']) && $args['advancedUI'] ? '<span id="displayDate" ></span>' : '<select id="timeSelect"><option value="">' . lang::get("Please select date") . '</option></select>') . '</span>' . '</div>'; $imgPath = empty(data_entry_helper::$images_path) ? data_entry_helper::relative_client_helper_path() . "../media/images/" : data_entry_helper::$images_path; data_entry_helper::$javascript .= "\ninitTreeMap2({\n advanced_UI: " . (isset($args['advancedUI']) && $args['advancedUI'] ? "true" : "false") . ",\n dotSize: " . $args['dotSize'] . ",\n lat: " . $args['map_centroid_lat'] . ",\n long: " . $args['map_centroid_long'] . ",\n zoom: " . $args['map_zoom'] . ",\n triggerEvents: [" . implode(',', $triggerEvents) . "],\n base_url: '" . data_entry_helper::$base_url . "',\n report_name: '" . $args['report_name'] . "',\n auth_token: '" . $readAuth['auth_token'] . "',\n nonce: '" . $readAuth['nonce'] . "',\n reportExtraParams: '" . $extras . "',\n indicia_user_id: " . (hostsite_get_user_field('indicia_user_id') ? hostsite_get_user_field('indicia_user_id') : 'false') . ",\n timeControlSelector: '" . (isset($args['advancedUI']) && $args['advancedUI'] ? '#timeSlider' : '#timeSelect') . "',\n dotControlSelector: '" . (isset($args['advancedUI']) && $args['advancedUI'] ? '#dotSlider' : '#dotSelect') . "',\n timerDelay: " . (int) 1000 / $args['frameRate'] . ",\n twinMaps: " . (isset($args['twinMaps']) && $args['twinMaps'] ? 'true' : 'false') . ",\n imgPath: '" . $imgPath . "'\n});\n"; $r .= '</div>'; return $r; }
private static function _getCacheFileName() { $cacheFolder = data_entry_helper::relative_client_helper_path() . (isset(data_entry_helper::$cache_folder) ? data_entry_helper::$cache_folder : 'cache/'); if (!is_dir($cacheFolder) || !is_writeable($cacheFolder)) { return false; } return $cacheFolder . 'cache_CMS_User_List'; }
/** * <p>Outputs a calendar based summary grid that loads the results of the summary builder module.</p> * <p>If you need 2 grids on one page, then you must define a different id in the options for each grid.</p> * <p>The grid operation has NOT been AJAXified. There is no download option.</p> * * @param array $options Options array with the following possibilities:<ul> * <li><b>id</b><br/> * Optional unique identifier for the grid's container div. This is required if there is more than * one grid on a single web page to allow separation of the page and sort $_GET parameters in the URLs * generated.</li> * <li><b>mode</b><br/> * Pass report for a report, or direct for an Indicia table or view. Default is report.</li> * <li><b>readAuth</b><br/> * Read authorisation tokens.</li> * <li><b>dataSource</b><br/> * Name of the report file or table/view. when used, any user_id must refer to the CMS user ID, not the Indicia * User.</li> * <li><b>view</b> * When loading from a view, specify list, gv or detail to determine which view variant is loaded. Default is list. * </li> * <li><b>extraParams</b><br/> * Array of additional key value pairs to attach to the request. This should include fixed values which cannot be changed by the * user and therefore are not needed in the parameters form. * </li> * <li><b>paramDefaults</b> * Optional associative array of parameter default values. Default values appear in the parameter form and can be overridden.</li> * <li><b>tableHeaders</b> * Defines which week column headers should be included: date, number or both * <li><b>weekstart</b> * Defines the first day of the week. There are 2 options.<br/>'. * weekday=<n> where <n> is a number between 1 (for Monday) and 7 (for Sunday). Default is 'weekday=7' * date=MMM-DD where MMM-DD is a month/day combination: e.g. choosing Apr-1 will start each week on the day of the week on which the 1st of April occurs.</li> * <li><b>weekOneContains</b> * Defines week one as the week which contains this date. Format should be MMM-DD, which is a month/day combination: e.g. choosing Apr-1 will define * week one as being the week containing the 1st of April. Defaults to the 1st of January.</li> * <li><b>weekNumberFilter</b> * Restrict displayed weeks to between 2 weeks defined by their week numbers. Colon separated. * Leaving an empty value means the end of the year. * Examples: "1:30" - Weeks one to thirty inclusive. * "4:" - Week four onwards. * ":5" - Upto and including week five.</li> * <li><b>rowGroupColumn</b> * The column in the report which is used as the label for the vertical axis on the grid.</li> * <li><b>rowGroupID</b> * The column in the report which is used as the id for the vertical axis on the grid.</li> * <li><b>countColumn</b> * OPTIONAL: The column in the report which contains the count for this occurrence. If omitted then the default * is to assume one occurrence = count of 1</li> * <li><b>includeChartItemSeries</b> * Defaults to true. Include a series for each item in the report output. * </li> * <li><b>includeChartTotalSeries</b> * Defaults to true. Include a series for the total of each item in the report output. * </li> * </ul> * @todo: Future Enhancements? Allow restriction to month. */ public static function report_calendar_summary2($options) { $r = ""; // I know that there are better ways to approach some of the date manipulation, but they are PHP 5.3+. // We support back to PHP 5.2 // TODO put following JS into a control JS file. $warnings = '<span style="display:none;">Starting report_calendar_summary2 : ' . date(DATE_ATOM) . '</span>' . "\n"; data_entry_helper::add_resource('jquery_ui'); $options = self::get_report_calendar_summary_options($options); // don't use all of these now, eg. extraParams: this is used later for raw data $extras = ''; $extraParams = $options['readAuth'] + array('year' => $options['year'], 'survey_id' => $options['survey_id']); // at the moment the summary_builder module indexes the user_id on the created_by_id field on the parent sample. // this effectively means that it assumes easy_login. // Also means we have to use the converted Indicia user_id, stored by options function above in the extraParams. $extraParams['user_id'] = !isset($options['extraParams']['user_id']) || $options['extraParams']['user_id'] == "" ? 'NULL' : $options['extraParams']['user_id']; if (isset($options['taxon_list_id']) && $options['taxon_list_id'] != "") { $extraParams['taxon_list_id'] = $options['taxon_list_id']; } if (isset($options['location_id']) && $options['location_id'] != "") { $extraParams['location_id'] = $options['location_id']; } else { if (isset($options['branch_location_list'])) { $extraParams['query'] = urlencode(json_encode(array('in' => array('location_id', $options['branch_location_list'])))); } else { $extraParams['location_id'] = 'NULL'; } } $records = data_entry_helper::get_population_data(array('table' => 'summary_occurrence', 'extraParams' => $extraParams)); if (isset($records['error'])) { return $records['error']; } data_entry_helper::$javascript .= "\r\nvar pageURI = \"" . $_SERVER['REQUEST_URI'] . "\";\r\nfunction rebuild_page_url(oldURL, overrideparam, overridevalue) {\r\n var parts = oldURL.split('?');\r\n var params = [];\r\n if(overridevalue!=='') params.push(overrideparam+'='+overridevalue);\r\n if(parts.length > 1) {\r\n var oldparams = parts[1].split('&');\r\n for(var i = 0; i < oldparams.length; i++){\r\n var bits = oldparams[i].split('=');\r\n if(bits[0] != overrideparam) params.push(oldparams[i]);\r\n }\r\n }\r\n return parts[0]+(params.length > 0 ? '?'+params.join('&') : '');\r\n};\r\nfunction update_controls(){\r\n \$('#year-control-previous').attr('href',rebuild_page_url(pageURI,'year'," . $options['year'] . "-1));\r\n \$('#year-control-next').attr('href',rebuild_page_url(pageURI,'year'," . $options['year'] . "+1));\r\n // user and location ids are dealt with in the main form. their change functions look a pageURI\r\n}\r\nupdate_controls();\r\n"; // ISO Date - Mon=1, Sun=7 // Week 1 = the week with date_from in if (!isset($options['weekstart']) || $options['weekstart'] == "") { $options['weekstart'] = "weekday=7"; // Default Sunday } if (!isset($options['weekNumberFilter']) || $options['weekNumberFilter'] == "") { $options['weekNumberFilter'] = ":"; } $weeknumberfilter = explode(':', $options['weekNumberFilter']); if (count($weeknumberfilter) != 2) { $warnings .= "Week number filter unrecognised {" . $options['weekNumberFilter'] . "} defaulting to all<br />"; $weeknumberfilter = array('', ''); } else { if ($weeknumberfilter[0] != '' && (intval($weeknumberfilter[0]) != $weeknumberfilter[0] || $weeknumberfilter[0] > 52)) { $warnings .= "Week number filter start unrecognised or out of range {" . $weeknumberfilter[0] . "} defaulting to year start<br />"; $weeknumberfilter[0] = ''; } if ($weeknumberfilter[1] != '' && (intval($weeknumberfilter[1]) != $weeknumberfilter[1] || $weeknumberfilter[1] < $weeknumberfilter[0] || $weeknumberfilter[1] > 52)) { $warnings .= "Week number filter end unrecognised or out of range {" . $weeknumberfilter[1] . "} defaulting to year end<br />"; $weeknumberfilter[1] = ''; } } $weekstart = explode('=', $options['weekstart']); if ($weekstart[0] == 'date') { $weekstart_date = date_create($options['year'] . "-" . $weekstart[1]); if (!$weekstart_date) { $warnings .= "Weekstart month-day combination unrecognised {" . $weekstart[1] . "} defaulting to weekday=7 - Sunday<br />"; $weekstart[1] = 7; } else { $weekstart[1] = $weekstart_date->format('N'); } } if (intval($weekstart[1]) != $weekstart[1] || $weekstart[1] < 1 || $weekstart[1] > 7) { $warnings .= "Weekstart unrecognised or out of range {" . $weekstart[1] . "} defaulting to 7 - Sunday<br />"; $weekstart[1] = 7; } if (isset($options['weekOneContains']) && $options['weekOneContains'] != "") { $weekOne_date = date_create($options['year'] . '-' . $options['weekOneContains']); if (!$weekOne_date) { $warnings .= "Week one month-day combination unrecognised {" . $options['weekOneContains'] . "} defaulting to Jan-01<br />"; $weekOne_date = date_create($options['year'] . '-Jan-01'); } } else { $weekOne_date = date_create($options['year'] . '-Jan-01'); } $weekOne_date_weekday = $weekOne_date->format('N'); if ($weekOne_date_weekday > $weekstart[1]) { // scan back to start of week $weekOne_date->modify('-' . ($weekOne_date_weekday - $weekstart[1]) . ' day'); } else { if ($weekOne_date_weekday < $weekstart[1]) { $weekOne_date->modify('-' . (7 + $weekOne_date_weekday - $weekstart[1]) . ' day'); } } $firstWeek_date = clone $weekOne_date; // date we start providing data for $weekOne_date_yearday = $weekOne_date->format('z'); // day within year note year_start_yearDay is by definition 0 $weekOne_date_weekday = $weekOne_date->format('N'); // day within week $minWeekNo = $weeknumberfilter[0] != '' ? $weeknumberfilter[0] : 1; $numWeeks = ceil($weekOne_date_yearday / 7); // number of weeks in year prior to $weekOne_date - 1st Jan gives zero, 2nd-8th Jan gives 1, etc if ($minWeekNo - 1 < -1 * $numWeeks) { $minWeekNo = -1 * $numWeeks + 1; } // have to allow for week zero if ($minWeekNo < 1) { $firstWeek_date->modify(($minWeekNo - 1) * 7 . ' days'); } else { if ($minWeekNo > 1) { $firstWeek_date->modify('+' . ($minWeekNo - 1) * 7 . ' days'); } } if ($weeknumberfilter[1] != '') { $maxWeekNo = $weeknumberfilter[1]; } else { $year_end = date_create($options['year'] . '-Dec-25'); // don't want to go beyond the end of year: this is 1st Jan minus 1 week: it is the start of the last full week $year_end_yearDay = $year_end->format('z'); // day within year $maxWeekNo = 1 + ceil(($year_end_yearDay - $weekOne_date_yearday) / 7); } $warnings .= '<span style="display:none;">Initial date processing complete : ' . date(DATE_ATOM) . '</span>' . "\n"; $tableNumberHeaderRow = ""; $tableDateHeaderRow = ""; $downloadNumberHeaderRow = ""; $downloadDateHeaderRow = ""; $chartNumberLabels = array(); $chartDateLabels = array(); $fullDates = array(); for ($i = $minWeekNo; $i <= $maxWeekNo; $i++) { $tableNumberHeaderRow .= '<th class="week">' . $i . '</th>'; $tableDateHeaderRow .= '<th class="week">' . $firstWeek_date->format('M') . '<br/>' . $firstWeek_date->format('d') . '</th>'; $downloadNumberHeaderRow .= ',' . $i; $downloadDateHeaderRow .= ',' . $firstWeek_date->format('d/m/Y'); $chartNumberLabels[] = "" . $i; $chartDateLabels[] = $firstWeek_date->format('M-d'); $fullDates[$i] = $firstWeek_date->format('d/m/Y'); $firstWeek_date->modify('+7 days'); } $summaryArray = array(); // this is used for the table output format $rawArray = array(); // this is used for the table output format // In order to apply the data combination and estmation processing, we assume that the the records are in taxon, location_id, sample_id order. $locationArray = array(); // this is for a single species at a time. $lastLocation = false; $seriesLabels = array(); $lastTaxonID = false; $lastSample = false; $locationSamples = array(); $weekList = array(); $sampleFieldList = !empty($options['sampleFields']) ? explode(',', $options['sampleFields']) : false; if (!$sampleFieldList || count($sampleFieldList) == 0) { $sampleFields = false; } else { $sampleFields = array(); foreach ($sampleFieldList as $sampleField) { $parts = explode(':', $sampleField); $field = array('caption' => $parts[0], 'field' => $parts[1], 'attr' => false); if (count($parts) == 3 && ($parts[1] = 'smpattr')) { $smpAttribute = data_entry_helper::get_population_data(array('table' => 'sample_attribute', 'extraParams' => $options['readAuth'] + array('view' => 'list', 'id' => $parts[2]))); if (count($smpAttribute) >= 1) { // may be assigned to more than one survey on this website. This is not relevant to info we want. $field['id'] = $parts[2]; $field['attr'] = $smpAttribute[0]; } } $sampleFields[] = $field; } } if ($options['location_list'] != 'all' && count($options['location_list']) == 0) { $options['location_list'] = 'none'; } foreach ($records as $recid => $record) { // If the taxon has changed $this_date = date_create(str_replace('/', '-', $record['date'])); // prevents day/month ordering issues $this_index = $this_date->format('z'); $this_weekday = $this_date->format('N'); if ($this_weekday > $weekstart[1]) { // scan back to start of week $this_date->modify('-' . ($this_weekday - $weekstart[1]) . ' day'); } else { if ($this_weekday < $weekstart[1]) { $this_date->modify('-' . (7 + $this_weekday - $weekstart[1]) . ' day'); } } // this_date now points to the start of the week. Next work out the week number. $this_yearday = $this_date->format('z'); $weekno = $record['period_number']; if (isset($weekList[$weekno])) { if (!in_array($record['location_name'], $weekList[$weekno])) { $weekList[$weekno][] = $record['location_name']; } } else { $weekList[$weekno] = array($record['location_name']); } } $warnings .= '<span style="display:none;">Records date pre-processing complete : ' . date(DATE_ATOM) . '</span>' . "\n"; $count = count($records); $warnings .= '<span style="display:none;">Number of records processed : ' . $count . ' : ' . date(DATE_ATOM) . '</span>' . "\n"; $summaryArray = array(); $sortData = array(); foreach ($records as $idex => $record) { $taxonID = $record['taxon_meaning_id']; // TODO ?? if (!empty($record['default_common_name'])) { $seriesLabels[$taxonID] = array('label' => $record['default_common_name']); } // TODO user to be able to choose from taxon or common if (empty($seriesLabels[$taxonID])) { $seriesLabels[$taxonID] = array('label' => $record['taxon']); } // various fall backs. if (empty($seriesLabels[$taxonID])) { $seriesLabels[$taxonID] = array('label' => '[' . $record['taxa_taxon_list_id'] . ']'); } if (!empty($record['preferred_taxon'])) { $seriesLabels[$taxonID]['preferred'] = $record['preferred_taxon']; } $weekno = $record['period_number']; $count = $record['count']; if (!isset($summaryArray[$taxonID])) { $summaryArray[$taxonID] = array(); } $sortData[$taxonID] = array($record['taxonomic_sort_order'], $taxonID); if ($weekno >= $minWeekNo && $weekno <= $maxWeekNo) { if (!isset($summaryArray[$taxonID][$weekno])) { $summaryArray[$taxonID][$weekno] = array('total' => null, 'estimate' => 0); } if ($count !== null) { $summaryArray[$taxonID][$weekno]['total'] = ($summaryArray[$taxonID][$weekno]['total'] == null ? 0 : $summaryArray[$taxonID][$weekno]['total']) + $count; } $summaryArray[$taxonID][$weekno]['estimate'] += $record['estimate']; } } usort($sortData, array('report_helper', 'report_calendar_summary_sort1')); $warnings .= '<span style="display:none;">Estimate processing finished : ' . date(DATE_ATOM) . '</span>' . "\n"; // will storedata in an array[Y][X] data_entry_helper::add_resource('jqplot'); switch ($options['chartType']) { case 'bar': self::add_resource('jqplot_bar'); $renderer = '$.jqplot.BarRenderer'; break; case 'pie': self::add_resource('jqplot_pie'); $renderer = '$.jqplot.PieRenderer'; break; default: // default is line $renderer = '$.jqplot.LineRenderer'; break; } self::add_resource('jqplot_category_axis_renderer'); $opts = array(); $opts[] = "seriesDefaults:{\n" . (isset($renderer) ? " renderer:{$renderer},\n" : '') . " rendererOptions:" . json_encode($options['rendererOptions']) . "}"; $warnings .= '<span style="display:none;">Controls complete : ' . date(DATE_ATOM) . '</span>' . "\n"; $seriesToDisplay = isset($options['outputSeries']) ? explode(',', $options['outputSeries']) : 'all'; $thClass = $options['thClass']; $summaryTab = '<div class="results-grid-wrapper-outer"><div class="results-grid-wrapper-inner"><table id="' . $options['tableID'] . '-summary" class="' . $options['tableClass'] . '"><thead class="' . $thClass . '">'; $estimateTab = '<div class="results-grid-wrapper-outer"><div class="results-grid-wrapper-inner"><table id="' . $options['tableID'] . '-estimate" class="' . $options['tableClass'] . '"><thead class="' . $thClass . '">'; $summaryDataDownloadGrid = ''; $estimateDataDownloadGrid = ''; $rawDataDownloadGrid = ''; $summaryTab .= '<tr><th class="freeze-first-col">' . lang::get('Week') . '</th>' . $tableNumberHeaderRow . '<th>Total</th></tr>' . '<tr><th class="freeze-first-col">' . lang::get('Date') . '</th>' . $tableDateHeaderRow . '<th></th></tr></thead><tbody>'; $estimateTab .= '<tr><th class="freeze-first-col">' . lang::get('Week') . '</th>' . $tableNumberHeaderRow . '<th>Total with<br/>estimates</th></tr>' . '<tr><th class="freeze-first-col">' . lang::get('Date') . '</th>' . $tableDateHeaderRow . '<th></th></tr></thead><tbody>'; $summaryDataDownloadGrid .= 'Week,' . $downloadNumberHeaderRow . ',Total' . "\n" . lang::get('Date') . ',' . $downloadDateHeaderRow . ",\n"; $estimateDataDownloadGrid .= 'Week,' . $downloadNumberHeaderRow . ',Estimates Total' . "\n" . lang::get('Date') . ',' . $downloadDateHeaderRow . ",\n"; $altRow = false; $grandTotal = 0; $totalRow = array(); $estimatesGrandTotal = 0; $totalEstimatesRow = array(); $seriesIDs = array(); $summarySeriesData = array(); $estimatesSeriesData = array(); $seriesOptions = array(); for ($i = $minWeekNo; $i <= $maxWeekNo; $i++) { $totalRow[$i] = 0; $totalEstimatesRow[$i] = 0; } foreach ($sortData as $sortedTaxon) { $seriesID = $sortedTaxon[1]; $summaryRow = $summaryArray[$seriesID]; $summaryValues = array(); $estimatesValues = array(); if (!empty($seriesLabels[$seriesID])) { $total = 0; // row total $estimatesTotal = 0; // row total $summaryTab .= '<tr class="datarow ' . ($altRow ? $options['altRowClass'] : '') . '"><td class="freeze-first-col"' . (isset($seriesLabels[$seriesID]['preferred']) ? ' title="' . $seriesLabels[$seriesID]['preferred'] . '"' : '') . '>' . $seriesLabels[$seriesID]['label'] . '</td>'; $estimateTab .= '<tr class="datarow ' . ($altRow ? $options['altRowClass'] : '') . '"><td class="freeze-first-col"' . (isset($seriesLabels[$seriesID]['preferred']) ? ' title="' . $seriesLabels[$seriesID]['preferred'] . '"' : '') . '>' . $seriesLabels[$seriesID]['label'] . '</td>'; $summaryDataDownloadGrid .= '"' . $seriesLabels[$seriesID]['label'] . '","' . (isset($seriesLabels[$seriesID]['preferred']) ? $seriesLabels[$seriesID]['preferred'] : '') . '"'; $estimateDataDownloadGrid .= '"' . $seriesLabels[$seriesID]['label'] . '","' . (isset($seriesLabels[$seriesID]['preferred']) ? $seriesLabels[$seriesID]['preferred'] : '') . '"'; for ($i = $minWeekNo; $i <= $maxWeekNo; $i++) { $summaryDataDownloadGrid .= ','; $estimateDataDownloadGrid .= ','; if (isset($summaryRow[$i])) { $summaryValue = $summaryRow[$i]['total']; $estimateValue = $summaryRow[$i]['estimate']; $class = $summaryValue !== null && $summaryValue === 0 ? 'forcedZero' : ''; $estimatesClass = $summaryValue === null || $summaryValue != $estimateValue ? 'highlight-estimates' : ''; if ($summaryValue !== null && $summaryValue === 0 && $estimateValue === 0) { $estimatesClass = 'forcedZero'; } $summaryDataDownloadGrid .= $summaryValue; $estimateDataDownloadGrid .= $estimateValue; $summaryTab .= '<td class="' . $class . '">' . ($summaryValue !== '' ? $summaryValue : '') . '</td>'; $estimateTab .= '<td class="' . $estimatesClass . '">' . $estimateValue . '</td>'; if ($summaryValue !== null && $summaryValue !== 0) { $total += $summaryValue; $totalRow[$i] += $summaryValue; // = $summaryTotalRow $grandTotal += $summaryValue; $summaryValues[] = $summaryValue; } else { $summaryValues[] = 0; } $estimatesValues[] = $estimateValue; $estimatesTotal += $estimateValue; $totalEstimatesRow[$i] += $estimateValue; // = $estimatesTotalRow $estimatesGrandTotal += $estimateValue; } else { $summaryTab .= '<td></td>'; $estimateTab .= '<td></td>'; $summaryValues[] = 0; $estimatesValues[] = 0; } } if ($options['includeChartItemSeries']) { $seriesIDs[] = $seriesID; $summarySeriesData[] = '[' . implode(',', $summaryValues) . ']'; $estimatesSeriesData[] = '[' . implode(',', $estimatesValues) . ']'; $seriesOptions[] = '{"show":' . ($seriesToDisplay == 'all' || in_array($seriesID, $seriesToDisplay) ? 'true' : 'false') . ',"label":"' . $seriesLabels[$seriesID]['label'] . '","showlabel":true}'; } $summaryTab .= '<td class="total-column">' . $total . '</td></tr>'; $summaryDataDownloadGrid .= ',' . $total . "\n"; $estimateTab .= '<td class="total-column estimates">' . $estimatesTotal . '</td></tr>'; $estimateDataDownloadGrid .= ',' . $estimatesTotal . "\n"; $altRow = !$altRow; } } if (isset($options['includeChartTotalSeries']) && $options['includeChartTotalSeries']) { // totals are put at the start array_unshift($seriesIDs, 0); // Total has ID 0 array_unshift($summarySeriesData, '[' . implode(',', $totalRow) . ']'); array_unshift($estimatesSeriesData, '[' . implode(',', $totalEstimatesRow) . ']'); array_unshift($seriesOptions, '{"show":' . ($seriesToDisplay == 'all' || in_array(0, $seriesToDisplay) ? 'true' : 'false') . ',"label":"' . lang::get('Total') . '","showlabel":true}'); } $opts[] = 'series:[' . implode(',', $seriesOptions) . ']'; $options['axesOptions']['xaxis']['renderer'] = '$.jqplot.CategoryAxisRenderer'; if (isset($options['chartLabels']) && $options['chartLabels'] == 'number') { $options['axesOptions']['xaxis']['ticks'] = $chartNumberLabels; } else { $options['axesOptions']['xaxis']['ticks'] = $chartDateLabels; } // We need to fudge the json so the renderer class is not a string $axesOpts = str_replace('"$.jqplot.CategoryAxisRenderer"', '$.jqplot.CategoryAxisRenderer', 'axes:' . json_encode($options['axesOptions'])); $opts[] = $axesOpts; $summaryTab .= "<tr class=\"totalrow\"><td class=\"freeze-first-col\">" . lang::get('Total (Summary)') . '</td>'; $estimateTab .= "<tr class=\"totalrow estimates\"><td class=\"freeze-first-col\">" . lang::get('Total inc Estimates') . '</td>'; $summaryDataDownloadGrid .= '"' . lang::get('Total (Summary)') . '",'; $estimateDataDownloadGrid .= '"' . lang::get('Total') . '",'; for ($i = $minWeekNo; $i <= $maxWeekNo; $i++) { $summaryTab .= '<td>' . $totalRow[$i] . '</td>'; $estimateTab .= '<td>' . $totalEstimatesRow[$i] . '</td>'; $estimateDataDownloadGrid .= ',' . $totalEstimatesRow[$i]; $summaryDataDownloadGrid .= ',' . $totalRow[$i]; } $summaryTab .= '<td class="total-column grand-total">' . $grandTotal . '</td></tr>'; $summaryDataDownloadGrid .= ',' . $grandTotal . "\n"; $estimateTab .= '<td class="total-column grand-total estimates">' . $estimatesGrandTotal . '</td></tr>'; $estimateDataDownloadGrid .= ',' . $estimatesGrandTotal . "\n"; $summaryTab .= "</tbody></table></div></div>\n"; $estimateTab .= "</tbody></table></div></div>\n"; data_entry_helper::$javascript .= "var seriesData = {ids: [" . implode(',', $seriesIDs) . "], summary: [" . implode(',', $summarySeriesData) . "], estimates: [" . implode(',', $estimatesSeriesData) . "]};\n"; data_entry_helper::$javascript .= "\r\nfunction replot(type){\r\n // there are problems with the coloring of series when added to a plot: easiest just to completely redraw.\r\n var max=0;\r\n \$('#" . $options['chartID'] . "-'+type).empty();\n" . (!isset($options['width']) || $options['width'] == '' ? " jQuery('#" . $options['chartID'] . "-'+type).width(jQuery('#" . $options['chartID'] . "-'+type).width());\n" : '') . " var opts = {" . implode(",\n", $opts) . "};\r\n // copy series from checkboxes.\r\n \$('#" . $options['chartID'] . "-'+type).parent().find('[name=" . $options['chartID'] . "-series]').each(function(idx, elem){\r\n opts.series[idx].show = (jQuery(elem).filter('[checked]').length > 0);\r\n });\r\n for(var i=0; i<seriesData[type].length; i++)\r\n if(opts.series[i].show)\r\n for(var j=0; j<seriesData[type][i].length; j++)\r\n max=(max>seriesData[type][i][j]?max:seriesData[type][i][j]);\r\n opts.axes.yaxis.max=max+1;\r\n opts.axes.yaxis.tickInterval = Math.floor(max/15); // number of ticks - too many takes too long to display\r\n if(!opts.axes.yaxis.tickInterval) opts.axes.yaxis.tickInterval=1;\r\n \$('.legend-colours').remove();\r\n if(\$('#" . $options['chartID'] . "-'+type).parent().find('[name=" . $options['chartID'] . "-series]').filter('[checked]').length == 0) return;\r\n var plot = \$.jqplot('" . $options['chartID'] . "-'+type, seriesData[type], opts);\r\n for(var i=0; i<plot.series.length; i++){\r\n \tif(plot.series[i].show==true) {\r\n\t var elem = \$('#" . $options['chartID'] . "-'+type).parent().find('[name=" . $options['chartID'] . "-series]').eq(i);\r\n \telem.after('<div class=\"legend-colours\"><div class=\"legend-colours-inner\" style=\"background:'+plot.series[i].color+';\"> </div></div>');\r\n\t}\r\n }\r\n};\r\nindiciaFns.bindTabsActivate(\$('#controls'), function(event, ui) {\r\n panel = typeof ui.newPanel==='undefined' ? ui.panel : ui.newPanel[0];\r\n if (panel.id==='summaryChart') { replot('summary'); }\r\n if (panel.id==='estimateChart') { replot('estimates'); }\r\n if (panel.id==='summaryData' || panel.id==='estimateData' || panel.id==='rawData') {\r\n \tvar max=0;\r\n \tvar extMax=0;\r\n \t\$('#'+panel.id+' .freeze-first-col').each(function(idx, elem){\r\n \t \$(elem).css('width',''); \r\n \t if(max < \$(elem).width()) max= \$(elem).width();\r\n \t if(extMax < \$(elem).outerWidth(true)) extMax= \$(elem).outerWidth(true);});\r\n \t\$('#'+panel.id+' .freeze-first-col').width(max+1);\r\n \t\$('#'+panel.id+' .results-grid-wrapper-inner').css('margin-left',extMax+1);\r\n \t\$('#'+panel.id+' table').hide();\r\n \t\$('#'+panel.id+' > div.results-grid-wrapper-outer').each(function(idx, elem){ \$(elem).css('width',''); \$(elem).width(\$(elem).width());});\r\n \t\$('#'+panel.id+' table').show();\r\n }\r\n});\r\n"; $summarySeriesPanel = ""; if (isset($options['disableableSeries']) && $options['disableableSeries'] && count($summaryArray) > (isset($options['includeChartTotalSeries']) && $options['includeChartTotalSeries'] ? 0 : 1) && isset($options['includeChartItemSeries']) && $options['includeChartItemSeries']) { $class = 'series-fieldset'; if (function_exists('hostsite_add_library') && (!defined('DRUPAL_CORE_COMPATIBILITY') || DRUPAL_CORE_COMPATIBILITY !== '7.x')) { hostsite_add_library('collapse'); $class .= ' collapsible collapsed'; } $summarySeriesPanel .= '<fieldset id="' . $options['chartID'] . '-series" class="' . $class . '"><legend>' . lang::get('Display Series') . "</legend><span>\n"; $summarySeriesPanel .= '<input type="button" class="disable-button" value="' . lang::get('Hide all ') . $options['rowGroupColumn'] . "\"/>\n"; $idx = 0; if (isset($options['includeChartTotalSeries']) && $options['includeChartTotalSeries']) { // use series ID = 0 for Total $summarySeriesPanel .= '<span class="chart-series-span"><input type="checkbox" checked="checked" id="' . $options['chartID'] . '-series-' . $idx . '" name="' . $options['chartID'] . '-series" value="' . $idx . '"/><label for="' . $options['chartID'] . '-series-' . $idx . '">' . lang::get('Total') . "</label></span>\n"; $idx++; data_entry_helper::$javascript .= "\njQuery('[name=" . $options['chartID'] . "-series]').filter('[value=0]')." . ($seriesToDisplay == 'all' || in_array(0, $seriesToDisplay) ? 'attr("checked","checked");' : 'removeAttr("checked");'); } foreach ($sortData as $sortedTaxon) { $seriesID = $sortedTaxon[1]; $summaryRow = $summaryArray[$seriesID]; $summarySeriesPanel .= '<span class="chart-series-span"><input type="checkbox" checked="checked" id="' . $options['chartID'] . '-series-' . $idx . '" name="' . $options['chartID'] . '-series" value="' . $seriesID . '"/><label for="' . $options['chartID'] . '-series-' . $idx . '"' . (isset($seriesLabels[$seriesID]['preferred']) ? ' title="' . $seriesLabels[$seriesID]['preferred'] . '"' : '') . '>' . $seriesLabels[$seriesID]['label'] . "</label></span>\n"; $idx++; data_entry_helper::$javascript .= "\njQuery('[name=" . $options['chartID'] . "-series]').filter('[value=" . $seriesID . "]')." . ($seriesToDisplay == 'all' || in_array($seriesID, $seriesToDisplay) ? 'attr("checked","checked");' : 'removeAttr("checked");'); } $summarySeriesPanel .= "</span></fieldset>\n"; // Known issue: jqplot considers the min and max of all series when drawing on the screen, even those which are not displayed // so replotting doesn't scale to the displayed series! // Note we are keeping the 2 charts in sync. data_entry_helper::$javascript .= "\r\njQuery('#summaryChart [name=" . $options['chartID'] . "-series]').change(function(){\r\n \$('#estimateChart [name=" . $options['chartID'] . "-series]').filter('[value='+\$(this).val()+']').attr('checked',\$(this).attr('checked'));\r\n replot('summary');\r\n});\r\njQuery('#estimateChart [name=" . $options['chartID'] . "-series]').change(function(){\r\n \$('#summaryChart [name=" . $options['chartID'] . "-series]').filter('[value='+\$(this).val()+']').attr('checked',\$(this).attr('checked'));\r\n replot('estimates');\r\n});\r\njQuery('#summaryChart .disable-button').click(function(){\r\n if(jQuery(this).is('.cleared')){ // button is to show all\r\n jQuery('[name=" . $options['chartID'] . "-series]').not('[value=0]').attr('checked','checked');\r\n jQuery('.disable-button').removeClass('cleared').val(\"" . lang::get('Hide all ') . $options['rowGroupColumn'] . "\");\r\n } else {\r\n jQuery('[name=" . $options['chartID'] . "-series]').not('[value=0]').removeAttr('checked');\r\n jQuery('.disable-button').addClass('cleared').val(\"" . lang::get('Show all ') . $options['rowGroupColumn'] . "\");\r\n }\r\n replot('summary');\r\n});\r\njQuery('#estimateChart .disable-button').click(function(){\r\n if(jQuery(this).is('.cleared')){ // button is to show all\r\n jQuery('[name=" . $options['chartID'] . "-series]').not('[value=0]').attr('checked','checked');\r\n jQuery('.disable-button').removeClass('cleared').val(\"" . lang::get('Hide all ') . $options['rowGroupColumn'] . "\");\r\n } else {\r\n jQuery('[name=" . $options['chartID'] . "-series]').not('[value=0]').removeAttr('checked');\r\n jQuery('.disable-button').addClass('cleared').val(\"" . lang::get('Show all ') . $options['rowGroupColumn'] . "\");\r\n }\r\n replot('estimates');\r\n});\r\n"; } $hasRawData = false; if (isset($options['location_id']) && $options['location_id'] != "") { // get the raw data for a single location. $options['extraParams']['orderby'] = 'date'; self::request_report($response, $options, $currentParamValues, false, ''); if (isset($response['error'])) { $rawTab = "ERROR RETURNED FROM request_report:<br />" . print_r($response, true); } else { if (isset($response['parameterRequest'])) { // We're not even going to bother with asking the user to populate a partially filled in report parameter set. $rawTab = '<p>Internal Error: Report request parameters not set up correctly.<br />' . print_r($response, true) . '<p>'; } else { // convert records to a date based array so it can be used when generating the grid. $altRow = false; $records = $response['records']; $rawTab = isset($options['linkMessage']) ? $options['linkMessage'] : ''; $rawDataDownloadGrid = lang::get('Date') . ','; $rawArray = array(); $sampleList = array(); $sampleDateList = array(); $smpIdx = 0; $hasRawData = count($records) > 0; if (!$hasRawData) { $rawTab .= '<p>' . lang::get('No raw data available for this period with these filter values.') . '</p>'; } else { $rawTab = '<div class="results-grid-wrapper-outer"><div class="results-grid-wrapper-inner"><table class="' . $options['tableClass'] . '"><thead class="' . $thClass . '"><tr><th class="freeze-first-col">' . lang::get('Date') . '</th>'; foreach ($records as $occurrence) { if (!in_array($occurrence['sample_id'], $sampleList)) { $sampleList[] = $occurrence['sample_id']; $sampleData = array('id' => $occurrence['sample_id'], 'date' => $occurrence['date'], 'location' => $occurrence['locaton_name']); $rawArray[$occurrence['sample_id']] = array(); if ($sampleFields) { foreach ($sampleFields as $sampleField) { if ($sampleField['attr'] === false) { $sampleData[$sampleField['caption']] = $occurrence[$sampleField['field']]; } else { if ($sampleField['attr']['data_type'] == 'L') { $sampleData[$sampleField['caption']] = $occurrence['attr_sample_term_' . $sampleField['id']]; } else { $sampleData[$sampleField['caption']] = $occurrence['attr_sample_' . $sampleField['id']]; } } } } $sampleDateList[] = $sampleData; } if ($occurrence['taxon_meaning_id'] !== null && $occurrence['taxon_meaning_id'] != '') { $count = isset($options['countColumn']) && $options['countColumn'] != '' ? isset($occurrence[$options['countColumn']]) ? $occurrence[$options['countColumn']] : 0 : 1; if (!isset($rawArray[$occurrence['sample_id']][$occurrence['taxon_meaning_id']])) { $rawArray[$occurrence['sample_id']][$occurrence['taxon_meaning_id']] = $count; } else { $rawArray[$occurrence['sample_id']][$occurrence['taxon_meaning_id']] += $count; } } } foreach ($sampleDateList as $sample) { $sample_date = date_create($sample['date']); $rawTab .= '<th>' . (isset($options['linkURL']) && $options['linkURL'] != '' ? '<a href="' . $options['linkURL'] . $sample['id'] . '" target="_blank" title="Link to data entry form for ' . $sample['location'] . ' on ' . $sample['date'] . ' (Sample ID ' . $sample['id'] . ')">' : '') . $sample_date->format('M') . '<br/>' . $sample_date->format('d') . (isset($options['linkURL']) && $options['linkURL'] != '' ? '</a>' : '') . '</th>'; $rawDataDownloadGrid .= ',' . $sample['date']; } $rawDataDownloadGrid .= "\n"; $rawTab .= '</tr></thead><tbody>'; if ($sampleFields) { foreach ($sampleFields as $sampleField) { // last-sample-datarow $rawTab .= '<tr class="sample-datarow ' . ($altRow ? $options['altRowClass'] : '') . '"><td class="freeze-first-col">' . $sampleField['caption'] . '</td>'; $rawDataDownloadGrid .= '"' . $sampleField['caption'] . '",'; foreach ($sampleDateList as $sample) { $rawTab .= '<td>' . ($sample[$sampleField['caption']] === null || $sample[$sampleField['caption']] == '' ? ' ' : $sample[$sampleField['caption']]) . '</td>'; $rawDataDownloadGrid .= ',' . $sample[$sampleField['caption']]; } $rawTab .= '</tr>'; $rawDataDownloadGrid .= "\n"; $altRow = !$altRow; } data_entry_helper::$javascript .= "var sampleDatarows = \$('#rawData .sample-datarow').length;\n\$('#rawData .sample-datarow').eq(sampleDatarows-1).addClass('last-sample-datarow');\n"; } foreach ($sortData as $sortedTaxon) { $seriesID = $sortedTaxon[1]; // this is the meaning id if (!empty($seriesLabels[$seriesID])) { $rawTab .= '<tr class="datarow ' . ($altRow ? $options['altRowClass'] : '') . '"><td class="freeze-first-col"' . (isset($seriesLabels[$seriesID]['preferred']) ? ' title="' . $seriesLabels[$seriesID]['preferred'] . '"' : '') . '>' . $seriesLabels[$seriesID]['label'] . '</td>'; $rawDataDownloadGrid .= '"' . $seriesLabels[$seriesID]['label'] . '","' . (isset($seriesLabels[$seriesID]['preferred']) ? $seriesLabels[$seriesID]['preferred'] : '') . '",'; foreach ($sampleList as $sampleID) { $rawTab .= '<td>' . (isset($rawArray[$sampleID][$seriesID]) ? $rawArray[$sampleID][$seriesID] : ' ') . '</td>'; $rawDataDownloadGrid .= ',' . (isset($rawArray[$sampleID][$seriesID]) ? $rawArray[$sampleID][$seriesID] : ''); } $rawTab .= '</tr>'; $rawDataDownloadGrid .= "\n"; $altRow = !$altRow; } } $rawTab .= '</tbody></table></div></div>'; } } } } else { $rawTab = "<p>Raw Data is only available when a location is specified.</p>"; } $hasData = count($summaryArray) > 0; $tabs = array('#summaryData' => lang::get('Summary Table')); if ($hasData) { $tabs = array_merge($tabs, array('#summaryChart' => lang::get('Summary Chart'), '#estimateData' => lang::get('Estimate Table'), '#estimateChart' => lang::get('Estimate Chart'))); } $tabs['#rawData'] = lang::get('Raw Data'); $downloadTab = ""; $timestamp = isset($options['includeReportTimeStamp']) && $options['includeReportTimeStamp'] ? '_' . date('YmdHis') : ''; unset($options['extraParams']['orderby']); // may have been set for raw data // No need for saved reports to be atomic events. Will be purged automatically. global $base_url; $cacheFolder = data_entry_helper::$cache_folder ? data_entry_helper::$cache_folder : data_entry_helper::relative_client_helper_path() . 'cache/'; if ($hasData && $options['includeSummaryGridDownload']) { $cacheFile = $options['downloadFilePrefix'] . 'summaryDataGrid' . $timestamp . '.csv'; $handle = fopen($cacheFolder . $cacheFile, 'wb'); fwrite($handle, $summaryDataDownloadGrid); fclose($handle); $downloadTab .= '<tr><td>' . lang::get('Download Summary Grid (CSV Format)') . ' : </td><td><a target="_blank" href="' . $base_url . '/' . drupal_get_path('module', 'iform') . '/client_helpers/cache/' . $cacheFile . '" download type="text/csv"><button type="button">' . lang::get('Download') . '</button></a></td></tr>' . "\n"; } if ($hasData && $options['includeEstimatesGridDownload']) { $cacheFile = $options['downloadFilePrefix'] . 'estimateDataGrid' . $timestamp . '.csv'; $handle = fopen($cacheFolder . $cacheFile, 'wb'); fwrite($handle, $estimateDataDownloadGrid); fclose($handle); $downloadTab .= '<tr><td>' . lang::get('Download Estimates Grid (CSV Format)') . ' : </td><td><a target="_blank" href="' . $base_url . '/' . drupal_get_path('module', 'iform') . '/client_helpers/cache/' . $cacheFile . '" download type="text/csv"><button type="button">' . lang::get('Download') . '</button></a></td></tr>' . "\n"; } if ($hasRawData && $options['includeRawGridDownload']) { $cacheFile = $options['downloadFilePrefix'] . 'rawDataGrid' . $timestamp . '.csv'; $handle = fopen($cacheFolder . $cacheFile, 'wb'); fwrite($handle, $rawDataDownloadGrid); fclose($handle); $downloadTab .= '<tr><td>' . lang::get('Download Raw Data Grid (CSV Format)') . ' : </td><td><a target="_blank" href="' . $base_url . '/' . drupal_get_path('module', 'iform') . '/client_helpers/cache/' . $cacheFile . '" download type="text/csv"><button type="button">' . lang::get('Download') . '</button></a></td></tr>' . "\n"; } if ($hasData && count($options['downloads']) > 0) { // format is assumed to be CSV global $indicia_templates; $indicia_templates['report_download_link'] = '<a target="_blank" href="{link}" download ><button type="button">' . lang::get('Download') . '</button></a>'; $downloadOptions = array('readAuth' => $options['readAuth'], 'extraParams' => array_merge($options['extraParams'], array('date_from' => $options['date_start'], 'date_to' => $options['date_end'])), 'itemsPerPage' => false); // there are problems dealing with location_list as an array if empty, so connvert if ($downloadOptions['extraParams']['location_list'] == "") { $downloadOptions['extraParams']['location_list'] = "(-1)"; } else { $downloadOptions['extraParams']['location_list'] = '(' . $downloadOptions['extraParams']['location_list'] . ')'; } foreach ($options['downloads'] as $download) { $downloadOptions['dataSource'] = $download['dataSource']; $downloadOptions['filename'] = $download['filename']; $downloadTab .= '<tr><td>' . $download['caption'] . ' : </td><td>' . report_helper::report_download_link($downloadOptions) . '</td></tr>'; } } if ($downloadTab != "") { $tabs['#dataDownloads'] = lang::get('Downloads'); } $r .= '<div id="controls">' . data_entry_helper::enable_tabs(array('divId' => 'controls')) . data_entry_helper::tab_header(array('tabs' => $tabs)) . ($hasData ? '<div id="summaryData">' . $summaryTab . '</div>' . '<div id="summaryChart"><div id="' . $options['chartID'] . '-summary" style="height:' . $options['height'] . 'px;' . (isset($options['width']) && $options['width'] != '' ? 'width:' . $options['width'] . 'px;' : '') . '"></div>' . $summarySeriesPanel . '</div>' . '<div id="estimateData">' . $estimateTab . '</div>' . '<div id="estimateChart"><div id="' . $options['chartID'] . '-estimates" style="height:' . $options['height'] . 'px;' . (isset($options['width']) && $options['width'] != '' ? 'width:' . $options['width'] . 'px;' : '') . '"></div>' . $summarySeriesPanel . '</div>' : '<div id="summaryData"><p>' . lang::get('No data available for this period with these filter values.') . '</p></div>') . '<div id="rawData">' . $rawTab . '</div>' . ($downloadTab != "" ? '<div id="dataDownloads"><table><tbody style="border:none;">' . $downloadTab . '</tbody></table></div>' : '') . '</div>'; $warnings .= '<span style="display:none;">Finish report_calendar_summary : ' . date(DATE_ATOM) . '</span>' . "\n"; return $warnings . $r; }