Index: weather.module
===================================================================
--- weather.module (revision 9)
+++ weather.module (working copy)
@@ -56,7 +56,10 @@
* Implementation of hook_perm().
*/
function weather_perm() {
- return array('administer custom weather block');
+ return array(
+ 'administer custom weather block',
+ 'view weather'
+ );
}
@@ -147,6 +150,19 @@
'callback' => 'weather_get_places_xml',
'access' => user_access('administer custom weather block'),
'type' => MENU_CALLBACK,
+ );
+ $items[] = array(
+ 'path' => 'weather',
+ 'title' => t('Weather'),
+ 'callback' => 'weather_get_weather',
+ 'access' => user_access('view weather'),
+ 'type' => MENU_CALLBACK,
+ );
+ $items[] = array(
+ 'path' => 'weather/autocomplete',
+ 'title' => t('Weather AJAX Autocomplete'),
+ 'callback' => 'weather_location_ajax',
+ 'access' => user_access('view weather'),
);
}
@@ -404,6 +420,33 @@
$content .= '';
}
return $content;
+}
+
+/**
+ * Custom theme function for the table of potential search results when a user
+ * searches for a weather location but there is more than one result.
+ *
+ * @param array $data An array of arrays containing table data.
+ */
+function theme_weather_disambiguation($data) {
+ $output = "
";
+ $output .= t('Your search returned more than one result:');
+ $output .= "
";
+
+ $output .= "\n";
+
+ foreach ($data as $datum) {
+ $output .= "- \n";
+ $output .= l(
+ $datum['title'],
+ 'weather/' . $datum['icao']
+ );
+ $output .= "
\n";
+ }
+
+ $output .= "
\n";
+
+ return $output;
}
@@ -1562,4 +1605,224 @@
}
return $metar_raw;
+}
+
+/**
+ * Gets the weather for the specified location, whether it is a place name or
+ * an ICAO code. For example, waether/bristol will display the weather for
+ * bristol.
+ *
+ * @param string $arg The argument passed in the URL that specifies the
+ * location for which to get the weather.
+ */
+function weather_get_weather($arg = NULL) {
+ if ($arg) {
+ // We don't know whether the argument is a location, an ICAO code or
+ // a load of gibberish, so figure this out first.
+ if (strlen($arg) < 3) {
+ // Argument is not at least 3 characters, so don't bother to
+ // search.
+ drupal_set_message(
+ 'Please enter at least 3 characters when searching for weather.',
+ 'error'
+ );
+ drupal_goto('weather');
+ }
+ if (strlen($arg) > 64) {
+ // Argument is too long. I mean, come on! 64 characters?
+ drupal_set_message(
+ 'Please enter less than 64 characters when searching for weather.',
+ 'error'
+ );
+ drupal_goto('weather');
+ }
+
+ $arg = urldecode($arg);
+
+ // Try for an exact match on the ICAO code.
+ $result = db_query_range(
+ "SELECT icao, country, name FROM {weather_icao} " .
+ "WHERE icao = '%s'",
+ $arg,
+ 0, 1
+ );
+
+ $exact_match = NULL;
+ $row_total = 1;
+
+ while ($row = db_fetch_object($result)) {
+ $exact_match = $row;
+ }
+
+ if (!$exact_match) {
+ // Perform the database search to get close matches.
+ $result = db_query_range(
+ "SELECT icao, country, name FROM {weather_icao} " .
+ "WHERE LOWER(icao) LIKE LOWER('%%%s%%') " .
+ "OR LOWER(country) LIKE LOWER('%%%s%%') " .
+ "OR LOWER(name) LIKE LOWER('%%%s%%')",
+ $arg,
+ $arg,
+ $arg,
+ 0, 10
+ );
+
+ $row_total = db_num_rows($result);
+ }
+
+ if ($exact_match || $row_total == 1) {
+ // There is one match, so we can show the weather for this match.
+ $icao = '';
+ $real_name = '';
+
+ if ($exact_match) {
+ $icao = $exact_match->icao;
+ $real_name = $exact_match->name;
+ }
+ else {
+ $row = db_fetch_object($result);
+ $icao = $row->icao;
+ $real_name = $row->name;
+ }
+
+ // Create a config specially for this weather display.
+ $config['icao'] = strtoupper($icao);
+ $config['real_name'] = $real_name;
+ $config['units'] = array(
+ 'temperature' => 'celsius',
+ 'windspeed' => 'mph',
+ 'pressure' => 'hpa',
+ 'visibility' => 'miles',
+ );
+ $config['settings'] = array(
+ 'show_unconverted_metar' => FALSE,
+ 'show_abbreviated_directions' => FALSE,
+ 'show_directions_degree' => FALSE,
+ 'show_sunrise_sunset' => TRUE,
+ 'show_compact_block' => FALSE,
+ 'full_mode' => TRUE,
+ );
+ $config['weight'] = 0;
+
+ return theme('weather', $config, weather_get_metar($icao)) . drupal_get_form('weather_selection_form');
+ }
+ else if ($row_total == 0) {
+ drupal_set_message('Your weather search returned no results.');
+ drupal_goto('weather');
+ }
+ else {
+ // More than one row. We'll have to show a disambiguation page
+ // where the user can choose some results.
+ $disambig = array();
+
+ // Put each result into a custom array to pass to a custom
+ // theme function.
+ while ($row = db_fetch_object($result)) {
+ $disambig[] = array(
+ 'icao' => strtolower($row->icao),
+ 'title' => check_plain(
+ sprintf(
+ '%s, %s (%s)',
+ $row->name,
+ $row->country,
+ $row->icao
+ )
+ ),
+ );
+ }
+ return theme('weather_disambiguation', $disambig) . drupal_get_form('weather_selection_form');
+ }
+ }
+ else {
+ // There is no argument, so the user has nagivated to /weather instead
+ // of /weather/foo.
+ return drupal_get_form('weather_selection_form');
+ }
+}
+
+/**
+ * Display a form for the user to choose a weather location or search for
+ * him/herself.
+ *
+ */
+function weather_selection_form() {
+ $form = array();
+
+ $form['search'] = array(
+ '#type' => 'textfield',
+ '#title' => 'Search',
+ '#description' => 'Start typing a location or ICAO code to find weather.',
+ '#autocomplete_path' => 'weather/autocomplete',
+ );
+
+ $form['submit'] = array(
+ '#type' => 'submit',
+ '#value' => 'Search',
+ );
+
+ return $form;
+}
+
+function weather_selection_form_validate($form_id, $form_values) {
+ $search = $form_values['search'];
+
+ if (strlen($search) < 3) {
+ form_set_error(
+ 'search',
+ t('Please enter at least 3 characters when searching for weather.')
+ );
+ }
+ else if (strlen($search) > 64) {
+ form_set_error(
+ 'search',
+ t('Please enter less than 64 characters when searching for weather.')
+ );
+ }
}
+
+/**
+ * Submit handler for the weather_selection_form() form.
+ *
+ */
+function weather_selection_form_submit($form, $form_values) {
+ // Just redirect the user to the weather URL with the search term stuffed
+ // on the end of it. We've been through validation but make sure the
+ // search contains no dodgy characters here.
+ return 'weather/' . check_plain(urlencode($form_values['search']));
+}
+
+/**
+ * Given a partial string, search for a location or ICAO code matching that
+ * string. Provides AJAX auto-complete for forms.
+ *
+ * @param string $input The partial text to search for.
+ */
+function weather_location_ajax($input) {
+ $matches = array();
+
+ // In this query we search on ICAO, country AND name of place.
+ $result = db_query_range(
+ "SELECT icao, country, name FROM {weather_icao} " .
+ "WHERE LOWER(icao) LIKE LOWER('%%%s%%') " .
+ "OR LOWER(country) LIKE LOWER('%%%s%%') " .
+ "OR LOWER(name) LIKE LOWER('%%%s%%')",
+ $input,
+ $input,
+ $input,
+ 0, 10
+ );
+
+ while($match = db_fetch_object($result)) {
+ $matches[strtolower($match->icao)] = check_plain(
+ sprintf(
+ "%s, %s (%s)",
+ $match->name,
+ $match->country,
+ $match->icao
+ )
+ );
+ }
+
+ print drupal_to_js($matches);
+ exit();
+}
\ No newline at end of file