374 lines
14 KiB
PHP
374 lines
14 KiB
PHP
<?php
|
|
/**
|
|
* Portal block for displaying weather information obtained via
|
|
* Horde_Service_Weather.
|
|
*
|
|
* Copyright 2011-2017 Horde LLC (http://www.horde.org/)
|
|
*
|
|
* @author Michael J Rubinsky <mrubinsk@horde.org>
|
|
* @license http://www.horde.org/licenses/bsd BSD
|
|
* @package Horde
|
|
*/
|
|
|
|
/**
|
|
* Horde_Block_Weather
|
|
*
|
|
* @author Michael J Rubinsky <mrubinsk@horde.org>
|
|
* @package Horde
|
|
*/
|
|
class Horde_Block_Weather extends Horde_Core_Block
|
|
{
|
|
/**
|
|
*/
|
|
public $updateable = true;
|
|
|
|
protected $_refreshParams;
|
|
|
|
public $autoUpdateMethod = 'refreshContent';
|
|
|
|
/**
|
|
* @var Horde_Service_Weather_Base
|
|
*/
|
|
protected $_weather;
|
|
|
|
/**
|
|
*/
|
|
public function __construct($app, $params = array())
|
|
{
|
|
global $injector;
|
|
|
|
parent::__construct($app, $params);
|
|
try {
|
|
$this->_weather = $injector->getInstance('Horde_Weather');
|
|
} catch (Horde_Exception $e) {
|
|
$this->enabled = false;
|
|
}
|
|
$this->_name = _("Weather");
|
|
}
|
|
|
|
/**
|
|
* Handle user initiated block refresh. Set a private member to avoid
|
|
* BC issues with having to add a parameter to the _content method.
|
|
*
|
|
* @param Horde_Variables $vars
|
|
*
|
|
* @return string
|
|
*/
|
|
public function refreshContent($vars = null)
|
|
{
|
|
if (empty($vars) || empty($vars->location)) {
|
|
$this->_refreshParams = Horde_Variables::getDefaultVariables();
|
|
$this->_refreshParams->set('location', $this->_params['location']);
|
|
} else {
|
|
$this->_refreshParams = $vars;
|
|
}
|
|
|
|
return $this->_content();
|
|
}
|
|
|
|
/**
|
|
*/
|
|
protected function _title()
|
|
{
|
|
return _("Weather");
|
|
}
|
|
|
|
/**
|
|
*/
|
|
protected function _params()
|
|
{
|
|
$lengths = $this->_weather->getSupportedForecastLengths();
|
|
return array(
|
|
'location' => array(
|
|
'type' => 'text',
|
|
'name' => _("Location"),
|
|
'default' => 'Boston,MA'
|
|
),
|
|
'units' => array(
|
|
'type' => 'enum',
|
|
'name' => _("Units"),
|
|
'default' => 'standard',
|
|
'values' => array(
|
|
Horde_Service_Weather::UNITS_STANDARD => _("English"),
|
|
Horde_Service_Weather::UNITS_METRIC => _("Metric")
|
|
)
|
|
),
|
|
'days' => array(
|
|
'type' => 'enum',
|
|
'name' => _("Forecast Days (note that the returned forecast returns both day and night; a large number here could result in a wide block)"),
|
|
'default' => 3,
|
|
'values' => $lengths
|
|
),
|
|
'detailedForecast' => array(
|
|
'type' => 'checkbox',
|
|
'name' => _("Display detailed forecast"),
|
|
'default' => 0
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
*/
|
|
protected function _content()
|
|
{
|
|
// Set the requested units.
|
|
$this->_weather->units = $this->_params['units'];
|
|
|
|
if (!empty($this->_refreshParams) && !empty($this->_refreshParams->location)) {
|
|
$location = $this->_refreshParams->location;
|
|
$html = '';
|
|
$instance = '';
|
|
} else {
|
|
$instance = hash('md5', mt_rand());
|
|
$GLOBALS['injector']
|
|
->getInstance('Horde_Core_Factory_Imple')
|
|
->create(
|
|
'WeatherLocationAutoCompleter',
|
|
array(
|
|
'id' => 'location' . $instance,
|
|
'instance' => $instance
|
|
)
|
|
);
|
|
|
|
$html = '<div class="horde-content"><input id="location' . $instance . '" name="location' . $instance . '"> <input type="button" id="button' . $instance . '" class="horde-default" value="'
|
|
. _("Change Location") . '" /><span style="display:none;" id="location' . $instance . '_loading_img">'
|
|
. Horde_Themes_Image::tag('loading.gif') . '</span></div>';
|
|
$location = $this->_params['location'];
|
|
}
|
|
|
|
// Test location
|
|
try {
|
|
$location = $this->_weather->searchLocations($location);
|
|
} catch (Horde_Service_Weather_Exception $e) {
|
|
return $e->getMessage();
|
|
}
|
|
|
|
$html .= '<div id="weathercontent' . $instance . '">';
|
|
|
|
if (is_array($location)) {
|
|
// Several locations returned due to imprecise location parameter.
|
|
$html = sprintf(_("Several locations possible with the parameter: %s"), $this->_params['location'])
|
|
. '<br />';
|
|
foreach ($location as $real_location) {
|
|
$html .= '<li>' . $real_location->city . ', ' . $real_location->state . '(' . $real_location->code . ")</li>\n";
|
|
}
|
|
$html .= '</ul>';
|
|
return $html;
|
|
}
|
|
try {
|
|
$forecast = $this->_weather->getForecast($location->code, $this->_params['days']);
|
|
$station = $this->_weather->getStation();
|
|
$current = $this->_weather->getCurrentConditions($location->code);
|
|
} catch (Horde_Service_Weather_Exception $e) {
|
|
return $e->getMessage();
|
|
}
|
|
|
|
// Units to display as
|
|
$units = $this->_weather->getUnits($this->_weather->units);
|
|
|
|
// Location and local time.
|
|
$html .= '<div class="control">'
|
|
. '<strong>' . $station->name . '</strong>';
|
|
if ($current->time->timestamp()) {
|
|
$html .= ' ' . sprintf(_("Local time: %s %s (UTC %s)"), $current->time->strftime($GLOBALS['prefs']->getValue('date_format')), $current->time->strftime($GLOBALS['prefs']->getValue('time_format')), $station->getOffset());
|
|
}
|
|
$html .= '</div>';
|
|
|
|
$html .= '<div class="horde-content">';
|
|
// Sunrise/sunset.
|
|
if ($station->sunrise) {
|
|
$html .= '<strong>' . _("Sunrise") . ': </strong>'
|
|
. Horde_Themes_Image::tag('block/sunrise/sunrise.png', array('alt' => _("Sunrise")))
|
|
. sprintf("%s %s", $station->sunrise->strftime($GLOBALS['prefs']->getValue('date_format')), $station->sunrise->strftime($GLOBALS['prefs']->getValue('time_format')));
|
|
$html .= ' <strong>' . _("Sunset") . ': </strong>'
|
|
. Horde_Themes_Image::tag('block/sunrise/sunset.png', array('alt' => _("Sunset")))
|
|
. sprintf("%s %s", $station->sunset->strftime($GLOBALS['prefs']->getValue('date_format')), $station->sunset->strftime($GLOBALS['prefs']->getValue('time_format')));
|
|
$html .= '<br />';
|
|
}
|
|
|
|
// Temperature.
|
|
$html .= '<strong>' . _("Temperature") . ': </strong>' .
|
|
$current->temp . '°' . Horde_String::upper($units['temp']);
|
|
|
|
// Dew point.
|
|
if (is_numeric($current->dewpoint)) {
|
|
$html .= ' <strong>' . _("Dew point") . ': </strong>' .
|
|
round($current->dewpoint) . '°' . Horde_String::upper($units['temp']);
|
|
}
|
|
|
|
// Feels like temperature.
|
|
// @TODO: Need to parse if wind chill/heat index etc..
|
|
// $html .= ' <strong>' . _("Feels like: ") . '</strong>' .
|
|
// round($this->_weather['feltTemperature']) . '°' . Horde_String::upper($units['temp']);
|
|
|
|
// Pressure and trend.
|
|
if ($current->pressure) {
|
|
$html .= '<br /><strong>' . _("Pressure") . ': </strong>';
|
|
$trend = $current->pressure_trend;
|
|
if (empty($trend)) {
|
|
$html .= sprintf('%d %s',
|
|
round($current->pressure), $units['pres']);
|
|
} else {
|
|
$html .= sprintf(_("%d %s and %s"),
|
|
round($current->pressure), $units['pres'],
|
|
_($trend));
|
|
}
|
|
}
|
|
if ($current->wind_direction) {
|
|
// Wind.
|
|
$html .= '<br /><strong>' . _("Wind") . ': </strong>';
|
|
$html .= sprintf(
|
|
_("From the %s (%s °) at %s %s"),
|
|
$current->wind_direction,
|
|
$current->wind_degrees,
|
|
$current->wind_speed,
|
|
$units['wind']);
|
|
if ($current->wind_gust > 0) {
|
|
$html .= ', ' . _("gusting") . ' ' . $current->wind_gust . ' ' . $units['wind'];
|
|
}
|
|
}
|
|
|
|
// Humidity.
|
|
if ($current->humidity) {
|
|
$html .= '<br /><strong>' . _("Humidity") . ': </strong>' . $current->humidity;
|
|
}
|
|
|
|
if ($current->visibility) {
|
|
// Visibility.
|
|
$html .= ' <strong>' . _("Visibility") . ': </strong>'
|
|
. round($current->visibility) . ' ' . $units['vis'];
|
|
}
|
|
|
|
// Current condition.
|
|
$condition = $current->condition;
|
|
$html .= '<br /><strong>' . _("Current condition") . ': </strong>'
|
|
. Horde_Themes_Image::tag('weather/32x32/' . $current->icon)
|
|
. ' ' . $condition
|
|
. '</div>';
|
|
|
|
// Forecast
|
|
if ($this->_params['days'] > 0) {
|
|
$html .= '<div class="control"><strong>' .
|
|
sprintf(_("%d-day forecast"), $this->_params['days']) .
|
|
'</strong></div>';
|
|
|
|
$futureDays = 0;
|
|
$html .= '<table class="horde-block-weather">';
|
|
|
|
// Headers.
|
|
$html .= '<tr>';
|
|
$html .= '<th>' . _("Day") . '</th><th>' .
|
|
sprintf(_("Temperature%s(%sHi%s/%sLo%s)"),
|
|
'<br />',
|
|
'<span style="color:red">', '</span>',
|
|
'<span style="color:blue">', '</span>') .
|
|
'</th><th>' . _("Condition") . '</th>';
|
|
|
|
if (isset($this->_params['detailedForecast'])) {
|
|
if (in_array(Horde_Service_Weather::FORECAST_FIELD_PRECIPITATION, $forecast->fields)) {
|
|
$html .= '<th>' . sprintf(_("Precipitation%schance"), '<br />') . '</th>';
|
|
}
|
|
|
|
if (in_array(Horde_Service_Weather::FORECAST_FIELD_HUMIDITY, $forecast->fields)) {
|
|
$html .= '<th>' . _("Humidity") . '</th>';
|
|
}
|
|
|
|
if (in_array(Horde_Service_Weather::FORECAST_FIELD_WIND, $forecast->fields)) {
|
|
$html .= '<th>' . _("Wind") . '</th>';
|
|
}
|
|
}
|
|
|
|
$html .= '</tr>';
|
|
$which = -1;
|
|
foreach ($forecast as $day) {
|
|
$which++;
|
|
if ($which > $this->_params['days']) {
|
|
break;
|
|
}
|
|
$html .= '<tr class="rowEven">';
|
|
|
|
// Day name.
|
|
$html .= '<td><strong>';
|
|
|
|
if ($which == 0) {
|
|
$html .= _("Today");
|
|
} elseif ($which == 1) {
|
|
$html .= _("Tomorrow");
|
|
} else {
|
|
$html .= strftime('%A', mktime(0, 0, 0, date('m'), date('d') + $futureDays, date('Y')));
|
|
}
|
|
$html .= '</strong><br />' .
|
|
strftime('%b %d', mktime(0, 0, 0, date('m'), date('d') + $futureDays, date('Y'))) .
|
|
'</td>';
|
|
|
|
// Forecast condition.
|
|
$condition = $day->conditions;
|
|
|
|
// Temperature.
|
|
$html .= '<td>'
|
|
. '<span style="color:red">' . $day->high . '°'
|
|
. Horde_String::upper($units['temp']) . '</span>/'
|
|
. '<span style="color:blue">' . $day->low . '°'
|
|
. Horde_String::upper($units['temp']) . '</span></td>';
|
|
|
|
// Condition.
|
|
$html .= '<td>'
|
|
. Horde_Themes_Image::tag('weather/32x32/' . $day->icon)
|
|
. '<br />' . $condition . '</td>';
|
|
|
|
if (isset($this->_params['detailedForecast'])) {
|
|
if (in_array(Horde_Service_Weather::FORECAST_FIELD_PRECIPITATION, $forecast->fields)) {
|
|
$html .= '<td>'
|
|
. ($day->precipitation_percent >= 0 ? $day->precipitation_percent . '%' : _("N/A")) . '</td>';
|
|
}
|
|
if (in_array(Horde_Service_Weather::FORECAST_FIELD_HUMIDITY, $forecast->fields)) {
|
|
$html .= '<td>'
|
|
. ($day->humidity ? $day->humidity . '%': _("N/A")) . '</td>';
|
|
}
|
|
if (in_array(Horde_Service_Weather::FORECAST_FIELD_WIND, $forecast->fields)) {
|
|
// Winds.
|
|
if ($day->wind_direction) {
|
|
$html .= '<td>' . ' '
|
|
. sprintf(_("From the %s at %s %s"),
|
|
$day->wind_direction,
|
|
$day->wind_speed,
|
|
$units['wind']);
|
|
if ($day->wind_gust && $day->wind_gust > $day->wind_speed) {
|
|
$html .= ', ' . _("gusting") . ' '
|
|
. $day->wind_gust . ' ' . $units['wind'];
|
|
}
|
|
$html .= '</td>';
|
|
} else {
|
|
$html .= '<td>' . _("N/A") . '</td>';
|
|
}
|
|
}
|
|
}
|
|
$html .= '</tr>';
|
|
$futureDays++;
|
|
}
|
|
$html .= '</table>';
|
|
}
|
|
|
|
if ($this->_weather->logo) {
|
|
$html .= '<div class="rightAlign">'
|
|
. _("Weather data provided by") . ' '
|
|
. Horde::link(
|
|
Horde::externalUrl($this->_weather->link),
|
|
$this->_weather->title, '', '_blank', '', $this->_weather->title)
|
|
. Horde_Themes_Image::tag($this->_weather->logo)
|
|
. '</a></div>';
|
|
} else {
|
|
$html .= '<div class="rightAlign">'
|
|
. _("Weather data provided by") . ' '
|
|
. Horde::link(
|
|
Horde::externalUrl($this->_weather->link),
|
|
$this->_weather->title, '', '_blank', '', $this->_weather->title)
|
|
. '<em>' . $this->_weather->title . '</em>'
|
|
. '</a></div>';
|
|
}
|
|
|
|
return $html . '</div>';
|
|
}
|
|
|
|
}
|