Parent Directory
|
Revision Log
|
Revision Graph
Merge changes from DRUPAL-6--5-6 to DRUPAL-6--5-7
| 1 | <?php |
| 2 | /* $Id: weather.module,v 1.208 2009/09/03 20:31:09 toddy Exp $ |
| 3 | * |
| 4 | * Copyright © 2006-2009 Tobias Quathamer <t.quathamer@gmx.net> |
| 5 | * |
| 6 | * This file is part of the Drupal Weather module. |
| 7 | * |
| 8 | * It was inspired by the Weather module which was written in 2004 by |
| 9 | * Gerard Ryan <gerardryan@canada.com>. |
| 10 | * |
| 11 | * Weather is free software; you can redistribute it and/or modify |
| 12 | * it under the terms of the GNU General Public License as published by |
| 13 | * the Free Software Foundation; either version 2 of the License, or |
| 14 | * (at your option) any later version. |
| 15 | * |
| 16 | * Weather is distributed in the hope that it will be useful, |
| 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 19 | * GNU General Public License for more details. |
| 20 | * |
| 21 | * You should have received a copy of the GNU General Public License |
| 22 | * along with Weather; if not, write to the Free Software |
| 23 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
| 24 | */ |
| 25 | |
| 26 | |
| 27 | |
| 28 | /** |
| 29 | * @file |
| 30 | * Display <acronym title="METeorological Aerodrome Report">METAR</acronym> |
| 31 | * weather data from anywhere in the world |
| 32 | * |
| 33 | * The module is compatible with Drupal 6.x |
| 34 | * |
| 35 | * @author Tobias Quathamer |
| 36 | */ |
| 37 | |
| 38 | |
| 39 | |
| 40 | // Define the start of block deltas for system-wide blocks |
| 41 | define('SYSTEM_BLOCK_DELTA_START', 3); |
| 42 | |
| 43 | // Include the parser for METAR data |
| 44 | require_once drupal_get_path('module', 'weather') .'/weather_parser.inc'; |
| 45 | |
| 46 | |
| 47 | |
| 48 | /********************************************************************* |
| 49 | * General Drupal hooks for registering the module |
| 50 | ********************************************************************/ |
| 51 | |
| 52 | |
| 53 | |
| 54 | /** |
| 55 | * Implementation of hook_perm(). |
| 56 | */ |
| 57 | function weather_perm() { |
| 58 | return array( |
| 59 | 'administer custom weather block', |
| 60 | 'access weather pages' |
| 61 | ); |
| 62 | } |
| 63 | |
| 64 | |
| 65 | |
| 66 | /** |
| 67 | * Implementation of hook_menu(). |
| 68 | */ |
| 69 | function weather_menu() { |
| 70 | $items['admin/settings/weather'] = array( |
| 71 | 'title' => 'Weather', |
| 72 | 'description' => 'Configure system-wide weather blocks and the default configuration for new locations.', |
| 73 | 'page callback' => 'weather_admin_main_page', |
| 74 | 'access arguments' => array('administer site configuration'), |
| 75 | 'type' => MENU_NORMAL_ITEM, |
| 76 | ); |
| 77 | $items['admin/settings/weather/edit/%/%'] = array( |
| 78 | 'title' => 'Edit location', |
| 79 | 'description' => 'Configure a system-wide weather block.', |
| 80 | 'page callback' => 'weather_custom_block', |
| 81 | 'page arguments' => array(4, 5), |
| 82 | 'access arguments' => array('administer site configuration'), |
| 83 | 'type' => MENU_CALLBACK, |
| 84 | ); |
| 85 | $items['admin/settings/weather/delete/%/%'] = array( |
| 86 | 'title' => 'Delete location', |
| 87 | 'description' => 'Delete a location from a system-wide weather block.', |
| 88 | 'page callback' => 'drupal_get_form', |
| 89 | 'page arguments' => array('weather_custom_block_delete_confirm', 4, 5), |
| 90 | 'access arguments' => array('administer site configuration'), |
| 91 | 'type' => MENU_CALLBACK, |
| 92 | ); |
| 93 | $items['admin/settings/weather/default'] = array( |
| 94 | 'title' => 'Default configuration', |
| 95 | 'description' => 'Setup the default configuration for new locations.', |
| 96 | 'page callback' => 'weather_custom_block', |
| 97 | 'page arguments' => array('0'), |
| 98 | 'access arguments' => array('administer site configuration'), |
| 99 | 'type' => MENU_CALLBACK, |
| 100 | ); |
| 101 | $items['user/%/weather'] = array( |
| 102 | 'title' => 'My weather', |
| 103 | 'description' => 'Configure your custom weather block.', |
| 104 | 'page callback' => 'weather_user_main_page', |
| 105 | 'page arguments' => array(1), |
| 106 | 'access callback' => 'weather_custom_block_access', |
| 107 | 'access arguments' => array(1), |
| 108 | 'type' => MENU_LOCAL_TASK, |
| 109 | ); |
| 110 | $items['user/%/weather/edit/%'] = array( |
| 111 | 'title' => 'Edit location', |
| 112 | 'description' => 'Configure your custom weather block.', |
| 113 | 'page callback' => 'weather_custom_block', |
| 114 | 'page arguments' => array(1, 4), |
| 115 | 'access callback' => 'weather_custom_block_access', |
| 116 | 'access arguments' => array(1), |
| 117 | 'type' => MENU_CALLBACK, |
| 118 | ); |
| 119 | $items['user/%/weather/delete/%'] = array( |
| 120 | 'title' => 'Delete location', |
| 121 | 'description' => 'Delete a location from your custom weather block.', |
| 122 | 'page callback' => 'drupal_get_form', |
| 123 | 'page arguments' => array('weather_custom_block_delete_confirm', |
| 124 | 1, 4), |
| 125 | 'access callback' => 'weather_custom_block_access', |
| 126 | 'access arguments' => array(1), |
| 127 | 'type' => MENU_CALLBACK, |
| 128 | ); |
| 129 | $items['weather/js'] = array( |
| 130 | 'page callback' => 'weather_js', |
| 131 | 'access arguments' => array('access content'), |
| 132 | 'type' => MENU_CALLBACK, |
| 133 | ); |
| 134 | $items['weather'] = array( |
| 135 | 'title' => 'Weather', |
| 136 | 'description' => 'Search for locations and display their current weather.', |
| 137 | 'page callback' => 'weather_search_location', |
| 138 | 'access arguments' => array('access weather pages'), |
| 139 | 'type' => MENU_NORMAL_ITEM, |
| 140 | ); |
| 141 | $items['weather/autocomplete'] = array( |
| 142 | 'page callback' => 'weather_search_autocomplete', |
| 143 | 'access arguments' => array('access weather pages'), |
| 144 | 'type' => MENU_CALLBACK, |
| 145 | ); |
| 146 | return $items; |
| 147 | } |
| 148 | |
| 149 | |
| 150 | |
| 151 | /** |
| 152 | * Implementation of hook_help(). |
| 153 | */ |
| 154 | function weather_help($path, $arg) { |
| 155 | $output = ''; |
| 156 | |
| 157 | switch ($path) { |
| 158 | case 'admin/settings/weather': |
| 159 | $output .= '<p>'; |
| 160 | $output .= t('You can add, edit, and delete locations from system-wide weather blocks. Moreover, you can specify default values for newly created locations.'); |
| 161 | $output .= '</p>'; |
| 162 | break; |
| 163 | case 'user/%/weather': |
| 164 | $output = '<p>'; |
| 165 | $output .= t('You can add, edit, and delete locations from your custom weather block.'); |
| 166 | $output .= "\n"; |
| 167 | $output .= t('Please note that the block will not be shown until you configure at least one location.'); |
| 168 | $output .= '</p>'; |
| 169 | break; |
| 170 | } |
| 171 | |
| 172 | return $output; |
| 173 | } |
| 174 | |
| 175 | |
| 176 | |
| 177 | /********************************************************************* |
| 178 | * General Drupal hooks for maintenance tasks |
| 179 | ********************************************************************/ |
| 180 | |
| 181 | |
| 182 | |
| 183 | /** |
| 184 | * Implementation of hook_cron(). |
| 185 | * |
| 186 | * If the site uses caching for anonymous users, the cached weather |
| 187 | * blocks are not updated until the page cache is flushed. |
| 188 | * We rely on cron to perform necessary updates (and flushing the cache) |
| 189 | * for anonymous users. In order to not clear the cache for user-defined |
| 190 | * weather blocks (which are not shown to anonymous users), we only |
| 191 | * check for system weather blocks. |
| 192 | */ |
| 193 | function weather_cron() { |
| 194 | if (variable_get('weather_use_cron', FALSE)) { |
| 195 | $sql = "SELECT * FROM {weather_metar} LEFT JOIN {weather_config} |
| 196 | ON {weather_metar}.icao={weather_config}.icao |
| 197 | WHERE {weather_config}.uid < 0 ORDER BY next_update_on ASC"; |
| 198 | $result = db_query($sql); |
| 199 | $row = db_fetch_array($result); |
| 200 | if (isset($row['next_update_on'])) { |
| 201 | if ($row['next_update_on'] <= time()) { |
| 202 | cache_clear_all(); |
| 203 | } |
| 204 | } |
| 205 | } |
| 206 | } |
| 207 | |
| 208 | |
| 209 | |
| 210 | /********************************************************************* |
| 211 | * Drupal hooks for the block content |
| 212 | ********************************************************************/ |
| 213 | |
| 214 | |
| 215 | |
| 216 | /** |
| 217 | * Generate HTML for the weather block |
| 218 | * @param op operation from the URL |
| 219 | * @param delta offset |
| 220 | * @returns block HTML |
| 221 | */ |
| 222 | function weather_block($op='list', $delta=0) { |
| 223 | global $user; |
| 224 | |
| 225 | if ($op == 'list') { |
| 226 | $block[0]['info'] = t('Weather: custom user'); |
| 227 | $block[1]['info'] = t('Weather: location of nodes (requires Location or Node Map module)'); |
| 228 | $current_blocks = _weather_get_blocks_in_use(); |
| 229 | if (!empty($current_blocks)) { |
| 230 | foreach ($current_blocks as $block_id) { |
| 231 | // $block_id is at least 1, so make sure the delta is at least 2 |
| 232 | $block[SYSTEM_BLOCK_DELTA_START + $block_id - 1]['info'] = |
| 233 | t('Weather: system-wide !number', array('!number' => $block_id)); |
| 234 | } |
| 235 | } |
| 236 | return $block; |
| 237 | } |
| 238 | else if ($op == 'view') { |
| 239 | if ($delta == 0 and weather_custom_block_access()) { |
| 240 | // Show the user's custom weather block, if there is already |
| 241 | // a location configured. Otherwise, do not show the block. |
| 242 | $configs_in_use = _weather_get_configs_in_use($user->uid); |
| 243 | if (count($configs_in_use) == 0) { |
| 244 | return; |
| 245 | } |
| 246 | $block['subject'] = t('Current weather'); |
| 247 | $block['content'] = ''; |
| 248 | foreach ($configs_in_use as $index) { |
| 249 | $config = _weather_get_config($user->uid, $index['cid']); |
| 250 | $metar = weather_get_metar($config['icao']); |
| 251 | $block['content'] .= theme('weather_theming', $config, $metar); |
| 252 | } |
| 253 | return $block; |
| 254 | } |
| 255 | else if ($delta == 1 and user_access('access content')) { |
| 256 | // show the node location weather block |
| 257 | if (arg(0) == 'node' and is_numeric(arg(1))) { |
| 258 | $node = node_load(arg(1)); |
| 259 | $block['content'] = ''; |
| 260 | // This checks the location module |
| 261 | if (isset($node->locations)) { |
| 262 | // Iterate through all available locations and check |
| 263 | // for lat/long information. If there is no information, |
| 264 | // the location module return 0.0/0.0 instead of NULL values |
| 265 | foreach ($node->locations as $location) { |
| 266 | if (($location['latitude'] != 0) or ($location['longitude'] != 0)) { |
| 267 | $nearest_station = weather_get_icao_from_lat_lon( |
| 268 | $location['latitude'], $location['longitude']); |
| 269 | $config = _weather_get_config(0, 1); |
| 270 | $config = array_merge($config, $nearest_station); |
| 271 | $config['real_name'] = $config['name']; |
| 272 | $metar = weather_get_metar($config['icao']); |
| 273 | $block['content'] .= theme('weather_theming', $config, $metar); |
| 274 | } |
| 275 | } |
| 276 | } |
| 277 | if (isset($node->nodemap_latitude_field) |
| 278 | and isset($node->nodemap_longitude_field) |
| 279 | and ($node->nodemap_latitude_field != 0 or $node->nodemap_longitude_field != 0)) { |
| 280 | $nearest_station = weather_get_icao_from_lat_lon( |
| 281 | $node->nodemap_latitude_field, $node->nodemap_longitude_field); |
| 282 | $config = _weather_get_config(0, 1); |
| 283 | $config = array_merge($config, $nearest_station); |
| 284 | $config['real_name'] = $config['name']; |
| 285 | $metar = weather_get_metar($config['icao']); |
| 286 | $block['content'] .= theme('weather_theming', $config, $metar); |
| 287 | } |
| 288 | // Do not show block if no lat/long information has been found |
| 289 | if ($block['content'] != '') { |
| 290 | $block['subject'] = t('Current weather nearby'); |
| 291 | return $block; |
| 292 | } |
| 293 | } |
| 294 | } |
| 295 | else if ($delta >= SYSTEM_BLOCK_DELTA_START and user_access('access content')) { |
| 296 | // show a system-wide weather block |
| 297 | $system_block_id = SYSTEM_BLOCK_DELTA_START - $delta - 1; |
| 298 | $block['subject'] = t('Current weather'); |
| 299 | $block['content'] = ''; |
| 300 | $configs_in_use = _weather_get_configs_in_use($system_block_id); |
| 301 | if (count($configs_in_use) == 0) { |
| 302 | $configs_in_use[] = array('cid' => 1); |
| 303 | } |
| 304 | foreach ($configs_in_use as $index) { |
| 305 | $config = _weather_get_config($system_block_id, $index['cid']); |
| 306 | $metar = weather_get_metar($config['icao']); |
| 307 | $block['content'] .= theme('weather_theming', $config, $metar); |
| 308 | } |
| 309 | return $block; |
| 310 | } |
| 311 | } |
| 312 | } |
| 313 | |
| 314 | |
| 315 | |
| 316 | /** |
| 317 | * Check whether the user has access to their own custom weather block |
| 318 | */ |
| 319 | function weather_custom_block_access($uid=NULL) { |
| 320 | global $user; |
| 321 | // If $uid is not set, just check for the access permission |
| 322 | if (is_null($uid) || $user->uid == $uid) { |
| 323 | return user_access('administer custom weather block'); |
| 324 | } |
| 325 | return FALSE; |
| 326 | } |
| 327 | |
| 328 | |
| 329 | |
| 330 | /** |
| 331 | * Implementation of hook_theme(). |
| 332 | */ |
| 333 | function weather_theme() { |
| 334 | return array( |
| 335 | // Custom theme function for preprocessing variables |
| 336 | 'weather_theming' => array( |
| 337 | 'arguments' => array('config' => NULL, 'metar' => NULL), |
| 338 | ), |
| 339 | // Default block layout |
| 340 | 'weather' => array( |
| 341 | 'template' => 'weather', |
| 342 | 'arguments' => array('weather' => NULL), |
| 343 | ), |
| 344 | // Compact block layout |
| 345 | 'weather_compact' => array( |
| 346 | 'template' => 'weather_compact', |
| 347 | 'arguments' => array('weather' => NULL), |
| 348 | ), |
| 349 | ); |
| 350 | } |
| 351 | |
| 352 | |
| 353 | |
| 354 | /** |
| 355 | * Custom theme function for preprocessing the weather block output |
| 356 | */ |
| 357 | function theme_weather_theming($config, $metar) { |
| 358 | // Set up variables which might be needed in the templates |
| 359 | $weather['real_name'] = check_plain($config['real_name']); |
| 360 | $weather['condition'] = _weather_format_condition($metar); |
| 361 | $weather['image'] = _weather_get_image($metar); |
| 362 | if (isset($metar['temperature']) and $config['units']['temperature'] != 'dont-display') { |
| 363 | $weather = array_merge($weather, _weather_format_temperature( |
| 364 | $metar['temperature'], $metar['wind'], $config['units'], $config['settings'] |
| 365 | )); |
| 366 | } |
| 367 | if (isset($metar['wind']) and $config['units']['windspeed'] != 'dont-display') { |
| 368 | $weather['wind'] = _weather_format_wind($metar['wind'], $config['units'], |
| 369 | $config['settings']); |
| 370 | } |
| 371 | if (isset($metar['pressure']) and $config['units']['pressure'] != 'dont-display') { |
| 372 | $weather['pressure'] = _weather_format_pressure($metar['pressure'], $config['units']); |
| 373 | } |
| 374 | if (isset($metar['temperature']) and isset($metar['dewpoint']) |
| 375 | and $config['units']['humidity'] != 'dont-display') { |
| 376 | $weather['rel_humidity'] = _weather_format_relative_humidity($metar['temperature'], $metar['dewpoint']); |
| 377 | } |
| 378 | if (isset($metar['visibility']['kilometers']) and $config['units']['visibility'] != 'dont-display') { |
| 379 | $weather['visibility'] = _weather_format_visibility($metar['visibility'], $config['units']); |
| 380 | } |
| 381 | if ($config['settings']['show_sunrise_sunset']) { |
| 382 | // Check if there is a sunrise or sunset |
| 383 | if ($metar['daytime']['no_sunrise']) { |
| 384 | $weather['sunrise'] = t('No sunrise today'); |
| 385 | } |
| 386 | else if ($metar['daytime']['no_sunset']) { |
| 387 | $weather['sunset'] = t('No sunset today'); |
| 388 | } |
| 389 | else { |
| 390 | // Set up timezone with a sensible default value |
| 391 | $timezone = $config['settings']['sunrise_sunset_timezone']; |
| 392 | // If the timezone is numeric, just use that value |
| 393 | if (!is_numeric($timezone)) { |
| 394 | if ($timezone == 'drupal') { |
| 395 | // Use Drupal's default timezone or user's timezone |
| 396 | $timezone = NULL; |
| 397 | } |
| 398 | else { |
| 399 | // Fall back to using GMT |
| 400 | $timezone = 0; |
| 401 | } |
| 402 | } |
| 403 | // Try to extract a time format from the system wide date format |
| 404 | $date_format_short = variable_get('date_format_short', 'm/d/Y - H:i'); |
| 405 | preg_match("/[GgHh].*?i(.*?[Aa])?/", $date_format_short, $matches); |
| 406 | if (isset($matches[0])) { |
| 407 | $format = $matches[0]; |
| 408 | } |
| 409 | else { |
| 410 | $format = 'G:i'; |
| 411 | } |
| 412 | // If the selected timezone is "drupal", just show the time. |
| 413 | // Otherwise, we append either "GMT" or the current GMT offset. |
| 414 | if (is_null($timezone)) { |
| 415 | // This is Drupal's default timezone, so do nothing. |
| 416 | } |
| 417 | else if ($timezone == 0) { |
| 418 | // This is GMT |
| 419 | $format .= ' T'; |
| 420 | } |
| 421 | else { |
| 422 | // Append the GMT offset |
| 423 | $format .= ' O'; |
| 424 | } |
| 425 | $text = format_date($metar['daytime']['sunrise_on'], 'custom', $format, $timezone); |
| 426 | $weather['sunrise'] = t('Sunrise: !sunrise', array('!sunrise' => $text)); |
| 427 | $text = format_date($metar['daytime']['sunset_on'], 'custom', $format, $timezone); |
| 428 | $weather['sunset'] = t('Sunset: !sunset', array('!sunset' => $text)); |
| 429 | } |
| 430 | } |
| 431 | if (isset($metar['#raw']) and $config['settings']['show_unconverted_metar']) { |
| 432 | $weather['metar'] = $metar['#raw']; |
| 433 | } |
| 434 | // If this is displayed as location block, show information about |
| 435 | // which METAR station has been used for weather data |
| 436 | if (isset($config['distance'])) { |
| 437 | $weather['location'] = _weather_format_closest_station($config['distance'], |
| 438 | $config['units'], $config['settings']); |
| 439 | } |
| 440 | if (isset($metar['reported_on'])) { |
| 441 | $weather['reported_on'] = format_date($metar['reported_on']); |
| 442 | } |
| 443 | |
| 444 | // Use compact block, if desired |
| 445 | if ($config['settings']['show_compact_block']) { |
| 446 | return theme('weather_compact', $weather); |
| 447 | } |
| 448 | else { |
| 449 | return theme('weather', $weather); |
| 450 | } |
| 451 | } |
| 452 | |
| 453 | |
| 454 | |
| 455 | function _weather_get_image($metar) { |
| 456 | // is there any data available? |
| 457 | if (!isset($metar['condition_text'])) { |
| 458 | $name = 'nodata'; |
| 459 | } |
| 460 | else { |
| 461 | // handle special case: NSC, we just use few for the display |
| 462 | if ($metar['condition_text'] == 'no-significant-clouds') { |
| 463 | $metar['condition_text'] = 'few'; |
| 464 | } |
| 465 | // calculate the sunrise and sunset times for day/night images |
| 466 | $name = $metar['daytime']['condition'] .'-'. $metar['condition_text']; |
| 467 | |
| 468 | // Use fog image, if needed |
| 469 | if (isset($metar['phenomena']['#mist']) |
| 470 | or isset($metar['phenomena']['fog']) |
| 471 | or isset($metar['phenomena']['#smoke'])) { |
| 472 | $name .= '-fog'; |
| 473 | } |
| 474 | |
| 475 | // handle rain images |
| 476 | if (isset($metar['phenomena']['rain'])) { |
| 477 | $rain = $metar['phenomena']['rain']; |
| 478 | } |
| 479 | else if (isset($metar['phenomena']['drizzle'])) { |
| 480 | $rain = $metar['phenomena']['drizzle']; |
| 481 | } |
| 482 | // handle snow images |
| 483 | else if (isset($metar['phenomena']['snow'])) { |
| 484 | $snow = $metar['phenomena']['snow']; |
| 485 | } |
| 486 | if (isset($rain)) { |
| 487 | if (isset($rain['#light'])) { |
| 488 | $name .= '-light-rain'; |
| 489 | } |
| 490 | else if (isset($rain['#heavy'])) { |
| 491 | $name .= '-heavy-rain'; |
| 492 | } |
| 493 | else { |
| 494 | $name .= '-moderate-rain'; |
| 495 | } |
| 496 | } |
| 497 | if (isset($snow)) { |
| 498 | if (isset($snow['#light'])) { |
| 499 | $name .= '-light-snow'; |
| 500 | } |
| 501 | else if (isset($snow['#heavy'])) { |
| 502 | $name .= '-heavy-snow'; |
| 503 | } |
| 504 | else { |
| 505 | $name .= '-moderate-snow'; |
| 506 | } |
| 507 | } |
| 508 | } |
| 509 | |
| 510 | // set up final return array |
| 511 | $image['filename'] = base_path() . drupal_get_path('module', 'weather') .'/images/'. $name .'.png'; |
| 512 | $size = getimagesize(drupal_get_path('module', 'weather') .'/images/'. $name .'.png'); |
| 513 | $image['size'] = $size[3]; |
| 514 | return $image; |
| 515 | } |
| 516 | |
| 517 | |
| 518 | |
| 519 | /********************************************************************* |
| 520 | * Internal functions for custom weather blocks |
| 521 | ********************************************************************/ |
| 522 | |
| 523 | |
| 524 | |
| 525 | /** |
| 526 | * Show an overview of configured locations |
| 527 | */ |
| 528 | function weather_user_main_page($uid) { |
| 529 | $header = array( |
| 530 | t('Real name'), |
| 531 | t('Weight'), |
| 532 | array('data' => t('Operations'), 'colspan' => 2), |
| 533 | ); |
| 534 | |
| 535 | $path = 'user/'. $uid .'/weather/'; |
| 536 | $rows = array(); |
| 537 | $sql = "SELECT * FROM {weather_config} |
| 538 | WHERE uid=%d ORDER BY weight ASC, real_name ASC"; |
| 539 | $result = db_query($sql, $uid); |
| 540 | while ($row = db_fetch_array($result)) { |
| 541 | $rows[] = array( |
| 542 | $row['real_name'], |
| 543 | $row['weight'], |
| 544 | l(t('edit'), $path .'edit/'. $row['cid']), |
| 545 | l(t('delete'), $path .'delete/'. $row['cid']), |
| 546 | ); |
| 547 | } |
| 548 | |
| 549 | if (count($rows) == 0) { |
| 550 | $rows[] = array( |
| 551 | array( |
| 552 | 'data' => '<em>'. t('There are currently no locations.') .'</em>', |
| 553 | 'colspan' => 4 |
| 554 | ) |
| 555 | ); |
| 556 | } |
| 557 | |
| 558 | $output = theme('table', $header, $rows); |
| 559 | if (isset($form['pager']['#value'])) { |
| 560 | $output .= drupal_render($form['pager']); |
| 561 | } |
| 562 | |
| 563 | $free_cid = _weather_get_free_config($uid); |
| 564 | $output .= '<p>'. l(t('Create new location'), |
| 565 | $path .'edit/'. $free_cid) .'</p>'; |
| 566 | |
| 567 | return $output; |
| 568 | } |
| 569 | |
| 570 | |
| 571 | |
| 572 | /** |
| 573 | * Show an overview of configured locations and the default location |
| 574 | */ |
| 575 | function weather_admin_main_page() { |
| 576 | $output = ''; |
| 577 | $blocks = _weather_get_blocks_in_use(); |
| 578 | $path = 'admin/settings/weather/'; |
| 579 | |
| 580 | if (!empty($blocks)) { |
| 581 | foreach ($blocks as $block_id) { |
| 582 | $header = array( |
| 583 | t('System-wide block !number', array('!number' => $block_id)), |
| 584 | t('Weight'), |
| 585 | array('data' => t('Operations'), 'colspan' => 2), |
| 586 | ); |
| 587 | |
| 588 | $rows = array(); |
| 589 | $sql = "SELECT * FROM {weather_config} |
| 590 | WHERE uid=%d ORDER BY weight ASC, real_name ASC"; |
| 591 | $result = db_query($sql, -$block_id); |
| 592 | while ($row = db_fetch_array($result)) { |
| 593 | $rows[] = array( |
| 594 | $row['real_name'], |
| 595 | $row['weight'], |
| 596 | l(t('edit'), $path .'edit/'. -$block_id .'/'. $row['cid']), |
| 597 | l(t('delete'), $path .'delete/'. -$block_id .'/'. $row['cid']), |
| 598 | ); |
| 599 | } |
| 600 | |
| 601 | $output .= theme('table', $header, $rows); |
| 602 | if (isset($form['pager']['#value'])) { |
| 603 | $output .= drupal_render($form['pager']); |
| 604 | } |
| 605 | |
| 606 | $free_cid = _weather_get_free_config(-$block_id); |
| 607 | $output .= '<p>'. l(t('Create new location in block !number', |
| 608 | array('!number' => $block_id)), |
| 609 | $path .'edit/'. -$block_id .'/'. $free_cid) .'</p>'; |
| 610 | } |
| 611 | } |
| 612 | |
| 613 | // Allow creation of another system-wide block |
| 614 | $free_block_id = _weather_get_free_block_id(); |
| 615 | $output .= '<p>'. l(t('Create new system-wide block'), |
| 616 | $path .'edit/'. $free_block_id .'/1') .'</p>'; |
| 617 | |
| 618 | // Add the default location |
| 619 | $output .= '<p>'. l(t('Configure the default location'), |
| 620 | $path .'default') .'</p>'; |
| 621 | $output .= drupal_get_form('weather_main_page_form'); |
| 622 | return $output; |
| 623 | } |
| 624 | |
| 625 | |
| 626 | |
| 627 | /** |
| 628 | * Construct a form for general settings of the Weather module |
| 629 | */ |
| 630 | function weather_main_page_form() { |
| 631 | $form['use_cron'] = array( |
| 632 | '#type' => 'checkbox', |
| 633 | '#title' => t('Use cron to clear the cache once per hour'), |
| 634 | '#description' => t('If you use Drupal\'s cache, the system weather blocks will not be updated for anonymous users unless the cache is cleared. This happens e.g. when new nodes are created. If you want the system weather blocks to be updated when new weather data is available, you can clear the cache once per hour. Please note that this might slow down your site.'), |
| 635 | '#default_value' => variable_get('weather_use_cron', FALSE), |
| 636 | ); |
| 637 | $form['submit'] = array( |
| 638 | '#type' => 'submit', |
| 639 | '#value' => t('Save configuration'), |
| 640 | ); |
| 641 | |
| 642 | return $form; |
| 643 | } |
| 644 | |
| 645 | |
| 646 | |
| 647 | /** |
| 648 | * Handle the submission for general settings of the Weather module |
| 649 | */ |
| 650 | function weather_main_page_form_submit($form, &$form_state) { |
| 651 | variable_set('weather_use_cron', $form_state['values']['use_cron']); |
| 652 | drupal_set_message(t('The configuration has been saved.')); |
| 653 | } |
| 654 | |
| 655 | |
| 656 | |
| 657 | /** |
| 658 | * Show a configuration page for a custom weather block |
| 659 | */ |
| 660 | function weather_custom_block($uid, $cid=0) { |
| 661 | // Include a nice Javascript which makes the settings easier |
| 662 | drupal_add_js(drupal_get_path('module', 'weather') .'/helper.js'); |
| 663 | |
| 664 | // if there's no configuration id provided, we get the first in use or 1 |
| 665 | if ($cid == 0) { |
| 666 | $cid = _weather_get_first_valid_config($uid); |
| 667 | } |
| 668 | |
| 669 | // if the provided config id is not currently used, we want the lowest |
| 670 | // free configuration id. This avoid cases like 56271 for config ids |
| 671 | $config_in_use = _weather_get_configs_in_use($uid); |
| 672 | $cid_found = FALSE; |
| 673 | foreach ($config_in_use as $index) { |
| 674 | if ($index['cid'] == $cid) { |
| 675 | $cid_found = TRUE; |
| 676 | break; |
| 677 | } |
| 678 | } |
| 679 | if (!$cid_found) { |
| 680 | $cid = _weather_get_free_config($uid); |
| 681 | } |
| 682 | // get the previously determined configuration |
| 683 | $config = _weather_get_config($uid, $cid); |
| 684 | |
| 685 | $config['country'] = weather_get_country_from_icao($config['icao']); |
| 686 | $config['countries'] = weather_get_countries(); |
| 687 | $config['places'] = weather_get_places($config['country']); |
| 688 | |
| 689 | $output = drupal_get_form('weather_custom_block_form', $uid, $cid, $config); |
| 690 | |
| 691 | return $output; |
| 692 | } |
| 693 | |
| 694 | |
| 695 | |
| 696 | /** |
| 697 | * Return a new place selection box based on the country selection |
| 698 | */ |
| 699 | function weather_js() { |
| 700 | // Get the current selected country for the new places |
| 701 | $form_state = array('values' => $_POST); |
| 702 | $new_places = weather_get_places($form_state['values']['country']); |
| 703 | |
| 704 | // Get form from cache and store modified place selection |
| 705 | $form = form_get_cache($_POST['form_build_id'], $form_state); |
| 706 | $form['place'] = array( |
| 707 | '#type' => 'select', |
| 708 | '#title' => t('Place'), |
| 709 | '#description' => t('Select a place in that country for the weather display.'), |
| 710 | '#options' => $new_places, |
| 711 | ); |
| 712 | form_set_cache($_POST['form_build_id'], $form, $form_state); |
| 713 | $form += array( |
| 714 | '#post' => $_POST, |
| 715 | '#programmed' => FALSE, |
| 716 | ); |
| 717 | |
| 718 | // Rebuild the form. |
| 719 | $form_state = array('submitted' => FALSE); |
| 720 | $form = form_builder('weather_custom_block_form', $form, $form_state); |
| 721 | |
| 722 | // Render the new output. |
| 723 | $output = theme('status_messages') . drupal_render($form['place']); |
| 724 | |
| 725 | // Don't call drupal_json(). ahah.js uses an iframe and |
| 726 | // the header output by drupal_json() causes problems in some browsers. |
| 727 | print drupal_to_js(array('status' => TRUE, 'data' => $output)); |
| 728 | exit; |
| 729 | } |
| 730 | |
| 731 | |
| 732 | |
| 733 | /** |
| 734 | * Construct the configuration form for a weather block |
| 735 | */ |
| 736 | function weather_custom_block_form($dummy, $uid, $cid, $config) { |
| 737 | // set up a selection box with all countries |
| 738 | $form['country'] = array( |
| 739 | '#type' => 'select', |
| 740 | '#title' => t('Country'), |
| 741 | '#description' => t('Select a country to narrow down your search.'), |
| 742 | '#default_value' => $config['country'], |
| 743 | '#options' => drupal_map_assoc($config['countries']), |
| 744 | '#ahah' => array( |
| 745 | 'path' => 'weather/js', |
| 746 | 'wrapper' => 'edit-place-wrapper', |
| 747 | ), |
| 748 | ); |
| 749 | // set up a selection box with all place names of the selected country |
| 750 | $form['place'] = array( |
| 751 | '#type' => 'select', |
| 752 | '#title' => t('Place'), |
| 753 | '#description' => t('Select a place in that country for the weather display.'), |
| 754 | '#default_value' => $config['icao'], |
| 755 | '#options' => $config['places'], |
| 756 | ); |
| 757 | $form['icao'] = array( |
| 758 | '#type' => 'textfield', |
| 759 | '#title' => t('ICAO code'), |
| 760 | '#default_value' => $config['icao'], |
| 761 | '#description' => t('Enter the 4-letter ICAO code of the weather station. If you first need to look up the code, you can use !url_1 or !url_2. Please note that not all stations listed at those URLs are providing weather data and thus may not be supported by this module.', |
| 762 | array( |
| 763 | '!url_1' => l('airlinecodes.co.uk', 'http://www.airlinecodes.co.uk/aptcodesearch.asp'), |
| 764 | '!url_2' => l('notams.jcs.mil', 'https://www.notams.jcs.mil/common/icao/index.html') |
| 765 | ) |
| 766 | ), |
| 767 | '#required' => true, |
| 768 | '#size' => '5', |
| 769 | ); |
| 770 | $form['real_name'] = array( |
| 771 | '#type' => 'textfield', |
| 772 | '#title' => t('Real name for the selected place'), |
| 773 | '#default_value' => $config['real_name'], |
| 774 | '#description' => t('You may enter another name for the place selected above.'), |
| 775 | '#required' => true, |
| 776 | '#size' => '30' |
| 777 | ); |
| 778 | $form['units'] = array( |
| 779 | '#type' => 'fieldset', |
| 780 | '#title' => t('Display units'), |
| 781 | '#description' => t('You can specify which units should be used for displaying the data.'), |
| 782 | '#collapsible' => TRUE, |
| 783 | '#collapsed' => FALSE, |
| 784 | '#tree' => TRUE, |
| 785 | ); |
| 786 | $form['units']['temperature'] = array( |
| 787 | '#type' => 'select', |
| 788 | '#title' => t('Temperature'), |
| 789 | '#default_value' => $config['units']['temperature'], |
| 790 | '#options' => array('celsius' => t('Celsius'), 'fahrenheit' => t('Fahrenheit'), |
| 791 | 'celsiusfahrenheit' => t('Celsius / Fahrenheit'), |
| 792 | 'fahrenheitcelsius' => t('Fahrenheit / Celsius'), |
| 793 | 'dont-display' => t('Don\'t display')), |
| 794 | ); |
| 795 | $form['units']['windspeed'] = array( |
| 796 | '#type' => 'select', |
| 797 | '#title' => t('Wind speed'), |
| 798 | '#default_value' => $config['units']['windspeed'], |
| 799 | '#options' => array('kmh' => t('km/h'), 'mph' => t('mph'), 'knots' => t('Knots'), |
| 800 | 'mps' => t('meter/s'), 'beaufort' => t('Beaufort'), |
| 801 | 'dont-display' => t('Don\'t display')), |
| 802 | ); |
| 803 | $form['units']['pressure'] = array( |
| 804 | '#type' => 'select', |
| 805 | '#title' => t('Pressure'), |
| 806 | '#default_value' => $config['units']['pressure'], |
| 807 | '#options' => array('hpa' => t('hPa'), 'kpa' => t('kPa'), 'inhg' => t('inHg'), 'mmhg' => t('mmHg'), |
| 808 | 'dont-display' => t('Don\'t display')), |
| 809 | ); |
| 810 | $form['units']['humidity'] = array( |
| 811 | '#type' => 'select', |
| 812 | '#title' => t('Rel. Humidity'), |
| 813 | '#default_value' => $config['units']['humidity'], |
| 814 | '#options' => array('display' => t('Display'), 'dont-display' => t('Don\'t display')), |
| 815 | ); |
| 816 | $form['units']['visibility'] = array( |
| 817 | '#type' => 'select', |
| 818 | '#title' => t('Visibility'), |
| 819 | '#default_value' => $config['units']['visibility'], |
| 820 | '#options' => array('kilometers' => t('kilometers'), 'miles' => t('UK miles'), |
| 821 | 'dont-display' => t('Don\'t display')), |
| 822 | ); |
| 823 | $form['settings'] = array( |
| 824 | '#type' => 'fieldset', |
| 825 | '#title' => t('Display settings'), |
| 826 | '#description' => t('You can customize the display of the block.'), |
| 827 | '#collapsible' => TRUE, |
| 828 | '#collapsed' => TRUE, |
| 829 | '#tree' => TRUE, |
| 830 | ); |
| 831 | $form['settings']['show_windchill'] = array( |
| 832 | '#type' => 'checkbox', |
| 833 | '#title' => t('Show windchill temperature'), |
| 834 | '#default_value' => $config['settings']['show_windchill'], |
| 835 | '#description' => t('Calculates the temperature resulting from windchill. This is how the temperature <q>feels like</q>.'), |
| 836 | ); |
| 837 | $form['settings']['show_unconverted_metar'] = array( |
| 838 | '#type' => 'checkbox', |
| 839 | '#title' => t('Show unconverted METAR data'), |
| 840 | '#default_value' => $config['settings']['show_unconverted_metar'], |
| 841 | '#description' => t('Displays the original data of the METAR report.'), |
| 842 | ); |
| 843 | $form['settings']['show_abbreviated_directions'] = array( |
| 844 | '#type' => 'checkbox', |
| 845 | '#title' => t('Show abbreviated wind directions'), |
| 846 | '#default_value' => $config['settings']['show_abbreviated_directions'], |
| 847 | '#description' => t('Displays abbreviated wind directions like N, SE, or W instead of North, Southeast, or West.'), |
| 848 | ); |
| 849 | $form['settings']['show_directions_degree'] = array( |
| 850 | '#type' => 'checkbox', |
| 851 | '#title' => t('Show degrees of wind directions'), |
| 852 | '#default_value' => $config['settings']['show_directions_degree'], |
| 853 | '#description' => t('Displays the degrees of wind directions, e.g. North (20°).'), |
| 854 | ); |
| 855 | $form['settings']['show_sunrise_sunset'] = array( |
| 856 | '#type' => 'checkbox', |
| 857 | '#title' => t('Show time of sunrise and sunset'), |
| 858 | '#default_value' => $config['settings']['show_sunrise_sunset'], |
| 859 | '#description' => t('Displays the time of sunrise and sunset.'), |
| 860 | ); |
| 861 | // Construct timezones |
| 862 | $timezones = array('gmt' => t('GMT'), 'drupal' => t('Drupal')); |
| 863 | $system_timezones = _system_zonelist(); |
| 864 | foreach ($system_timezones as $seconds_offset => $date) { |
| 865 | $timezones[$seconds_offset] = sprintf("%+03d:%02d", |
| 866 | $seconds_offset / 3600, |
| 867 | abs($seconds_offset % 3600) / 60); |
| 868 | } |
| 869 | $form['settings']['sunrise_sunset_timezone'] = array( |
| 870 | '#type' => 'select', |
| 871 | '#title' => t('Timezone for sunrise and sunset'), |
| 872 | '#default_value' => $config['settings']['sunrise_sunset_timezone'], |
| 873 | '#description' => t('Choose either Greenwich Mean Time (GMT), Drupal\'s standard timezone as set in the configuration, or a custom timezone.'), |
| 874 | '#options' => $timezones, |
| 875 | ); |
| 876 | $form['settings']['show_compact_block'] = array( |
| 877 | '#type' => 'checkbox', |
| 878 | '#title' => t('Show compact block'), |
| 879 | '#default_value' => $config['settings']['show_compact_block'], |
| 880 | '#description' => t('Displays only the name, condition, and temperature of the weather station.'), |
| 881 | ); |
| 882 | $form['weight'] = array( |
| 883 | '#type' => 'weight', |
| 884 | '#title' => t('Weight'), |
| 885 | '#default_value' => $config['weight'], |
| 886 | '#description' => t('Optional. In the block, the heavier locations will sink and the lighter locations will be positioned nearer the top. Locations with equal weights are sorted alphabetically.'), |
| 887 | ); |
| 888 | $form['uid'] = array( |
| 889 | '#type' => 'value', |
| 890 | '#value' => $uid, |
| 891 | ); |
| 892 | $form['cid'] = array( |
| 893 | '#type' => 'value', |
| 894 | '#value' => $cid, |
| 895 | ); |
| 896 | $form['submit'] = array( |
| 897 | '#type' => 'submit', |
| 898 | '#value' => t('Save configuration'), |
| 899 | ); |
| 900 | |
| 901 | return $form; |
| 902 | } |
| 903 | |
| 904 | |
| 905 | |
| 906 | /** |
| 907 | * Check the submission of the custom weather block |
| 908 | */ |
| 909 | function weather_custom_block_form_validate($form, &$form_state) { |
| 910 | if (weather_get_country_from_icao($form_state['values']['icao']) == '') { |
| 911 | form_set_error('icao', t('The ICAO code is not supported by this module.')); |
| 912 | } |
| 913 | } |
| 914 | |
| 915 | |
| 916 | |
| 917 | /** |
| 918 | * Handle the submission of the custom weather block |
| 919 | */ |
| 920 | function weather_custom_block_form_submit($form, &$form_state) { |
| 921 | // delete the previous entry |
| 922 | $sql = "DELETE FROM {weather_config} WHERE uid=%d AND cid=%d"; |
| 923 | db_query($sql, $form_state['values']['uid'], $form_state['values']['cid']); |
| 924 | |
| 925 | // insert the new configuration values into the DB |
| 926 | $sql = "INSERT INTO {weather_config} |
| 927 | (uid, cid, icao, real_name, units, settings, weight) |
| 928 | VALUES(%d, %d, '%s', '%s', '%s', '%s', %d)"; |
| 929 | db_query($sql, |
| 930 | $form_state['values']['uid'], |
| 931 | $form_state['values']['cid'], |
| 932 | strtoupper($form_state['values']['icao']), |
| 933 | $form_state['values']['real_name'], |
| 934 | serialize($form_state['values']['units']), |
| 935 | serialize($form_state['values']['settings']), |
| 936 | $form_state['values']['weight'] |
| 937 | ); |
| 938 | |
| 939 | if ($form_state['values']['uid'] == 0) { |
| 940 | drupal_set_message(t('The default configuration has been saved.')); |
| 941 | } |
| 942 | else { |
| 943 | drupal_set_message(t('The location has been saved.')); |
| 944 | } |
| 945 | |
| 946 | if ($form_state['values']['uid'] <= 0) { |
| 947 | // go back to the administration of the system weather block, |
| 948 | // if this is the default configuration or a system-wide block |
| 949 | $form_state['redirect'] = 'admin/settings/weather'; |
| 950 | /** TODO |
| 951 | * Rehashing is not needed on every submission, only if the block |
| 952 | * is newly created. On the other hand, this happens only |
| 953 | * rarely and surely is not a performance bottleneck. |
| 954 | */ |
| 955 | _block_rehash(); |
| 956 | } |
| 957 | else { |
| 958 | $form_state['redirect'] = 'user/'. $form_state['values']['uid'] .'/weather'; |
| 959 | } |
| 960 | } |
| 961 | |
| 962 | |
| 963 | |
| 964 | /** |
| 965 | * Confirmation page before deleting a location |
| 966 | */ |
| 967 | function weather_custom_block_delete_confirm($form, $uid, $cid) { |
| 968 | if ($uid < 0) { |
| 969 | $abort_path = 'admin/settings/weather'; |
| 970 | } |
| 971 | else { |
| 972 | $abort_path = 'user/'. $uid .'/weather'; |
| 973 | } |
| 974 | |
| 975 | $sql = "SELECT * FROM {weather_config} WHERE uid=%d and cid=%d"; |
| 976 | $result = db_query($sql, $uid, $cid); |
| 977 | $row = db_fetch_array($result); |
| 978 | |
| 979 | $form = array(); |
| 980 | $form['uid'] = array('#type' => 'hidden', '#value' => $uid); |
| 981 | $form['cid'] = array('#type' => 'hidden', '#value' => $cid); |
| 982 | return confirm_form($form, |
| 983 | t('Are you sure you want to delete the location %name?', |
| 984 | array('%name' => $row['real_name'])), |
| 985 | $abort_path, |
| 986 | t('This action cannot be undone.'), |
| 987 | t('Delete'), |
| 988 | t('Cancel') |
| 989 | ); |
| 990 | } |
| 991 | |
| 992 | |
| 993 | |
| 994 | /** |
| 995 | * Handle the deletion of a location |
| 996 | */ |
| 997 | function weather_custom_block_delete_confirm_submit($form, &$form_state) { |
| 998 | // delete the entry |
| 999 | $sql = "DELETE FROM {weather_config} WHERE uid=%d AND cid=%d"; |
| 1000 | db_query($sql, $form_state['values']['uid'], $form_state['values']['cid']); |
| 1001 | |
| 1002 | drupal_set_message(t('The location has been deleted.')); |
| 1003 | |
| 1004 | if ($form_state['values']['uid'] < 0) { |
| 1005 | // go back to the administration of system-wide weather blocks |
| 1006 | $form_state['redirect'] = 'admin/settings/weather'; |
| 1007 | /** TODO |
| 1008 | * Rehashing is not needed on every submission, only if the block |
| 1009 | * is totally empty. On the other hand, this happens only |
| 1010 | * rarely and surely is not a performance bottleneck. |
| 1011 | */ |
| 1012 | _block_rehash(); |
| 1013 | } |
| 1014 | else { |
| 1015 | $form_state['redirect'] = 'user/'. $form_state['values']['uid'] .'/weather'; |
| 1016 | } |
| 1017 | } |
| 1018 | |
| 1019 | |
| 1020 | |
| 1021 | /** |
| 1022 | * Searches for the specified location, whether it is a place name or |
| 1023 | * an ICAO code. For example, weather/fuhlsbüttel will display the weather |
| 1024 | * for Hamburg-Fuhlsbüttel. |
| 1025 | * |
| 1026 | * @param string The argument passed in the URL that specifies the |
| 1027 | * location which should be searched for. |
| 1028 | */ |
| 1029 | function weather_search_location($search = NULL) { |
| 1030 | if ($search == NULL) { |
| 1031 | // The user did not enter a search string in the URL, so just |
| 1032 | // display the search form. |
| 1033 | return drupal_get_form('weather_search_form'); |
| 1034 | } |
| 1035 | else { |
| 1036 | $search = urldecode($search); |
| 1037 | // Do some sanity checks first |
| 1038 | if ((strlen($search) < 3) || (strlen($search) > 64)) { |
| 1039 | drupal_set_message(t('The string to search for must be between 3 and 64 characters.'), 'error'); |
| 1040 | drupal_goto('weather'); |
| 1041 | } |
| 1042 | |
| 1043 | // Try to match the ICAO code |
| 1044 | if (strlen($search) == 4) { |
| 1045 | $sql = "SELECT icao, country, name FROM {weather_icao} WHERE icao = '%s'"; |
| 1046 | $result = db_query($sql, strtoupper($search)); |
| 1047 | if ($location = db_fetch_object($result)) { |
| 1048 | // Use the default configuration for display |
| 1049 | $config = _weather_get_config(0, 0); |
| 1050 | $config['icao'] = $location->icao; |
| 1051 | $config['real_name'] = $location->name; |
| 1052 | $metar = weather_get_metar($location->icao); |
| 1053 | $output = theme('weather_theming', $config, $metar); |
| 1054 | $output .= drupal_get_form('weather_search_form'); |
| 1055 | return $output; |
| 1056 | } |
| 1057 | } |
| 1058 | |
| 1059 | // Try to match on icao, name, or country |
| 1060 | $locations = array(); |
| 1061 | $sql = "SELECT icao, country, name FROM {weather_icao} |
| 1062 | WHERE icao LIKE UPPER('%%%s%%') |
| 1063 | OR UPPER(country) LIKE UPPER('%%%s%%') |
| 1064 | OR UPPER(name) LIKE UPPER('%%%s%%') |
| 1065 | ORDER BY name ASC"; |
| 1066 | $result = db_query($sql, $search, $search, $search); |
| 1067 | while ($location = db_fetch_object($result)) { |
| 1068 | $locations[] = $location; |
| 1069 | } |
| 1070 | |
| 1071 | // If there are no results, notify user |
| 1072 | if (empty($locations)) { |
| 1073 | drupal_set_message(t('Your search did not return any results.'), 'error'); |
| 1074 | drupal_goto('weather'); |
| 1075 | } |
| 1076 | else { |
| 1077 | if (count($locations) == 1) { |
| 1078 | $location = $locations[0]; |
| 1079 | // There's only one search result, so show the weather directly |
| 1080 | // using the default configuration for display |
| 1081 | $config = _weather_get_config(0, 0); |
| 1082 | $config['icao'] = $location->icao; |
| 1083 | $config['real_name'] = $location->name; |
| 1084 | $metar = weather_get_metar($location->icao); |
| 1085 | $output = theme('weather_theming', $config, $metar); |
| 1086 | $output .= drupal_get_form('weather_search_form'); |
| 1087 | return $output; |
| 1088 | } |
| 1089 | else { |
| 1090 | // There is more than one result, so show all of them |
| 1091 | // to let the user decide |
| 1092 | $links = array(); |
| 1093 | foreach ($locations as $location) { |
| 1094 | $links[] = l($location->name, 'weather/' . $location->icao); |
| 1095 | } |
| 1096 | $title = t('Search results for <q>@search</q>', array('@search' => $search)); |
| 1097 | $output = theme('item_list', $links, $title); |
| 1098 | $output .= drupal_get_form('weather_search_form'); |
| 1099 | return $output; |
| 1100 | } |
| 1101 | } |
| 1102 | } |
| 1103 | } |
| 1104 | |
| 1105 | |
| 1106 | |
| 1107 | /** |
| 1108 | * Display a form for the user to search for weather locations. |
| 1109 | */ |
| 1110 | function weather_search_form() { |
| 1111 | $form = array(); |
| 1112 | $form['search'] = array( |
| 1113 | '#type' => 'textfield', |
| 1114 | '#title' => t('Search for a location'), |
| 1115 | '#description' => t('Type in an ICAO code, a name, or a country to search for weather conditions at that location.'), |
| 1116 | '#autocomplete_path' => 'weather/autocomplete', |
| 1117 | ); |
| 1118 | $form['submit'] = array( |
| 1119 | '#type' => 'submit', |
| 1120 | '#value' => t('Search'), |
| 1121 | ); |
| 1122 | return $form; |
| 1123 | } |
| 1124 | |
| 1125 | |
| 1126 | |
| 1127 | /** |
| 1128 | * Validate the input from the weather search form |
| 1129 | */ |
| 1130 | function weather_search_form_validate($form, &$form_state) { |
| 1131 | if ((strlen($form_state['values']['search']) < 3) |
| 1132 | || (strlen($form_state['values']['search']) > 64)) { |
| 1133 | form_set_error('search', t('The string to search for must be between 3 and 64 characters.')); |
| 1134 | } |
| 1135 | } |
| 1136 | |
| 1137 | |
| 1138 | |
| 1139 | /** |
| 1140 | * Submission handler for the weather search form. |
| 1141 | * |
| 1142 | * Just redirect the user to the weather URL with the search term stuffed |
| 1143 | * on the end of it. We've been through validation but make sure the |
| 1144 | * search contains no dodgy characters here. |
| 1145 | */ |
| 1146 | function weather_search_form_submit($form, &$form_state) { |
| 1147 | drupal_goto('weather/' . urlencode($form_state['values']['search'])); |
| 1148 | } |
| 1149 | |
| 1150 | |
| 1151 | |
| 1152 | /** |
| 1153 | * Given a partial string, search for a location or ICAO code matching that |
| 1154 | * string. |
| 1155 | * |
| 1156 | * @param string $input The partial text to search for. |
| 1157 | */ |