diff --git a/classes/DailyImageWidget.php b/classes/DailyImageWidget.php index 72611db..5d18bdb 100644 --- a/classes/DailyImageWidget.php +++ b/classes/DailyImageWidget.php @@ -1,11 +1,18 @@ default_display_options = array( 'title', - 'image', - 'styles' + 'image' ); $this->_cache_time = 86400; @@ -14,13 +21,11 @@ class DailyImageWidget { $this->has_simplexml = class_exists('SimpleXMLElement'); - $this->_valid_column_names = array('title', 'caption', 'date', 'image_url', 'gallery_url', 'credits'); + $this->_valid_column_names = array('title', 'date', 'image_url', 'gallery_url', 'credits'); $this->_valid_options = array( "image" => __("Daily Image", "hubblesite-daily-image-widget"), "title" => __("Image Title", "hubblesite-daily-image-widget"), - "caption" => __("Image Caption", "hubblesite-daily-image-widget"), - "credits" => __("Credits", "hubblesite-daily-image-widget"), - "styles" => __("HubbleSite Styles", "hubblesite-daily-image-widget"), + "credits" => __("Credits", "hubblesite-daily-image-widget") ); add_action('init', array($this, "_init")); @@ -34,6 +39,9 @@ class DailyImageWidget { } } + /** + * WordPress init hook. + */ function _init() { register_sidebar_widget(__("HubbleSite Daily Image", "hubblesite-daily-image-widget"), array($this, "render")); register_widget_control(__("HubbleSite Daily Image", "hubblesite-daily-image-widget"), array($this, "render_ui")); @@ -42,6 +50,9 @@ class DailyImageWidget { $this->get_display_options(); } + /** + * Display a warning if the connection failed. + */ function _connection_warning() { echo "
"; _e("HubbleSite Daily Image Widget was unable to retrieve new data from HubbleSite.", "hubblesite-daily-image-widget"); @@ -49,6 +60,10 @@ class DailyImageWidget { echo "
"; } + /** + * Wrapper around a remote data call for unit testing purposes. + * @return string The data from the remote source. + */ function _get_from_data_source() { if (extension_loaded('curl')) { $ch = curl_init($this->data_source); @@ -61,6 +76,12 @@ class DailyImageWidget { } } + /** + * Load the remote data into the object. + * This will try to pull from cache and, if necessary, retrieve and parse the XML from the + * remote server. If any of this fails, returns false. + * @return boolean True if data could be loaded, false otherwise. + */ function _load_data() { if (($result = $this->_get_cached_data()) === false) { if (($xml_text = $this->_get_from_data_source()) !== false) { @@ -75,6 +96,9 @@ class DailyImageWidget { } } + /** + * Handle updating the widget options. + */ function handle_post() { if (isset($_POST['hubblesite']['_wpnonce'])) { if (wp_verify_nonce($_POST['hubblesite']['_wpnonce'], 'hubble')) { @@ -111,47 +135,41 @@ class DailyImageWidget { /** * Render the widget. + * @param array $args The theme's widget layout arguments. */ - function render() { + function render($args) { if (!empty($this->data) && is_array($this->data)) { + extract($args); $options = $this->get_display_options(); - echo '
'; - echo '

HubbleSite Daily Image

'; - + echo $before_widget; + echo $before_title; + echo "HubbleSite Daily Image"; + echo $after_title; if (in_array("image", $options)) { echo ''; - echo '' . $this->data['title'] . ''; + echo '' . $this->data['title'] . ''; echo ''; } if (in_array("title", $options)) { echo ''; - echo $this->data['title']; + echo $this->_fix_widows($this->data['title']); echo ''; } - if (in_array("caption", $options)) { - echo '
'; - echo $this->data['caption']; - echo '
'; - } - if (in_array("credits", $options)) { echo '
'; - echo $this->data['credits']; + echo $this->_fix_widows($this->data['credits']); echo '
'; } - echo '
'; - - if (in_array("styles", $options)) { - echo ""; - } + echo $after_widget; } } + /** + * Render the widget admin UI. + */ function render_ui() { echo ""; echo "

"; @@ -169,6 +187,9 @@ class DailyImageWidget { /** * Parse a string of XML from the HubbleSite Daily Gallery Image feed. + * This will try to use SimpleXML if vailable. If not, will fall back on Expat. + * @param string $xml_text The text to parse. + * @return array|boolean The retrieved data, or false on failure. */ function parse_xml($xml_text) { if ($this->has_simplexml) { @@ -216,10 +237,16 @@ class DailyImageWidget { return $this->data; } + /** + * Expat start element handler. + */ function _start_element_handler($parser, $name, $attributes) { $this->_character_data = ""; } + /** + * Expat end element handler. + */ function _end_element_handler($parser, $name) { $name = strtolower($name); if (in_array($name, $this->_valid_column_names)) { @@ -229,32 +256,44 @@ class DailyImageWidget { $this->_character_data = ""; } + /** + * Expat character data handler. + */ function _character_data_handler($parser, $data) { $this->_character_data .= $data; } + /** + * Retrieve the cached data from WP Options. + * @return array|boolean The cached data or false upon failure. + */ function _get_cached_data() { - $result = get_option('hubblesite-daily-image-cache'); - - if (is_string($result)) { - if (($data = @unserialize($result)) !== false) { - list($timestamp, $cached_data) = $data; + if (($result = get_option('hubblesite-daily-image-cache')) !== false) { + list($timestamp, $cached_data) = $result; + + if (($timestamp + $this->_cache_time) > time()) { + $is_valid = true; + foreach ($this->_valid_column_names as $field) { + if (!isset($cached_data[$field])) { $is_valid = false; break; } + } - if (($timestamp + $this->_cache_time) > time()) { - $is_valid = true; - foreach ($this->_valid_column_names as $field) { - if (!isset($cached_data[$field])) { $is_valid = false; break; } - } - - if ($is_valid) { - $this->data = $cached_data; - return $cached_data; - } + if ($is_valid) { + $this->data = $cached_data; + return $cached_data; } } } return false; } + + /** + * Try to ensure that no words in a paragraph or link are widowed. + * @param string $text The text to process. + * @return string The processed text. + */ + function _fix_widows($text) { + return preg_replace("#([^\ ]+)\ ([^\ \>]+)($|

|)#", '\1 \2\3', $text); + } } function the_hubblesite_daily_image_widget() { @@ -262,4 +301,4 @@ function the_hubblesite_daily_image_widget() { $diw->render(); } -?> \ No newline at end of file +?> diff --git a/hubblesite-styles.css b/hubblesite-styles.css index ba7bca7..0f9afdd 100644 --- a/hubblesite-styles.css +++ b/hubblesite-styles.css @@ -1,17 +1,21 @@ div#hubblesite-daily-image { text-align: center; - border: 1px solid #67201D; - background-color: #F0EEDD; + border: 1px solid #6B7595; + background-color: #191D28; padding: 10px; } +div#hubblesite-daily-image a { + color: #D1D184 +} + div#hubblesite-daily-image a:hover { color: #00d2d3 } div#hubblesite-daily-image img { margin: 5px 0; - border: 1px solid #67201D; + border: 1px solid #6B7595; } div#hubblesite-daily-image a:hover img { @@ -22,7 +26,11 @@ p#hubblesite-daily-image-header { text-align: center; font-size: 12px; font-weight: bold; - color: #666; + color: #9FA6BA; margin: 0; padding: 0; +} + +div#hubblesite-daily-image-credits { + color: #CCCCCC } \ No newline at end of file diff --git a/test/DailyImageWidgetTest.php b/test/DailyImageWidgetTest.php index b182e13..bba3ed8 100644 --- a/test/DailyImageWidgetTest.php +++ b/test/DailyImageWidgetTest.php @@ -15,7 +15,6 @@ class DailyImageWidgetTest extends PHPUnit_Framework_TestCase { $this->sample_data = array( 'title' => 'title', - 'caption' => 'caption', 'date' => '12345', 'image_url' => 'image_url', 'gallery_url' => 'gallery_url', @@ -60,33 +59,21 @@ class DailyImageWidgetTest extends PHPUnit_Framework_TestCase { array( "image", array( - '//div[@id="hubblesite-daily-image"]' => true, - '//div/a[@href="gallery_url" and @title="title"]' => true, - '//div/a/img[@src="image_url" and @alt="title"]' => true, + '//div[@id="hubblesite-daily-image"]' => false, + '//a[@href="gallery_url" and @title="title"]' => true, + '//a/img[@src="image_url" and @alt="title"]' => true, ) ), array( "title", array( - '//div/a[@href="gallery_url" and @id="hubblesite-daily-image-title"]' => "title" - ) - ), - array( - "styles", - array( - '//style[@type="text/css"]' => true - ) - ), - array( - "caption", - array( - '//div/div[@id="hubblesite-daily-image-caption"]' => 'caption' + '//a[@href="gallery_url" and @id="hubblesite-daily-image-title"]' => "title" ) ), array( "credits", array( - '//div/div[@id="hubblesite-daily-image-credits"]' => 'credits' + '//div[@id="hubblesite-daily-image-credits"]' => 'credits' ) ) ); @@ -99,7 +86,12 @@ class DailyImageWidgetTest extends PHPUnit_Framework_TestCase { update_option('hubblesite-daily-image-options', $option_string); ob_start(); - $this->diw->render(); + $this->diw->render(array( + 'before_widget' => "", + 'after_widget' => "", + 'before_title' => "", + 'after_title' => "" + )); $result = ob_get_clean(); $this->assertTrue(!empty($result)); @@ -112,8 +104,8 @@ class DailyImageWidgetTest extends PHPUnit_Framework_TestCase { function providerTestGetDisplayOptions() { return array( - array("", array("title", "image", "styles")), - array("meow", array("title", "image", "styles")), + array("", array("title", "image")), + array("meow", array("title", "image")), array("title", array("title")), array("title,image", array("title", "image")), array("title,meow", array("title")) @@ -262,52 +254,71 @@ class DailyImageWidgetTest extends PHPUnit_Framework_TestCase { } } - function testGetCachedData() { - $test_time = time() + 86500; - update_option('hubblesite-daily-image-cache', serialize(array($test_time, $this->sample_data))); - $this->assertEquals($this->sample_data, $this->diw->_get_cached_data()); - - $test_time = time() - 86500; - update_option('hubblesite-daily-image-cache', serialize(array($test_time, $this->sample_data))); - $this->assertEquals(false, $this->diw->_get_cached_data()); - - update_option('hubblesite-daily-image-cache', null); - $this->assertEquals(false, $this->diw->_get_cached_data()); + function providerTestGetCachedData() { + return array( + array(time() + 86500, true), + array(time() - 86500, false), + array(null, false) + ); } - function testLoadData() { - $diw = $this->getMock('DailyImageWidget', array('_get_from_data_source', '_get_cached_data', 'parse_xml')); - $diw->expects($this->once())->method('_get_cached_data')->will($this->returnValue(false)); - $diw->expects($this->once())->method('_get_from_data_source')->will($this->returnValue(false)); - _reset_wp(); + /** + * @dataProvider providerTestGetCachedData + */ + function testGetCachedData($test_time, $has_sample_data) { + if (!is_null($test_time)) { + update_option('hubblesite-daily-image-cache', array($test_time, $this->sample_data)); + } else { + update_option('hubblesite-daily-image-cache', null); + } - $this->assertFalse($diw->_load_data()); - $this->assertFalse(is_array(get_option('hubblesite-daily-image-cache'))); - + $this->assertEquals($has_sample_data ? $this->sample_data : false, $this->diw->_get_cached_data()); + } + + function providerTestLoadData() { + return array( + array(true, null, null, true), + array(false, false, null, false), + array(false, true, false, false), + array(false, true, true, true) + ); + } + + /** + * @dataProvider providerTestLoadData + */ + function testLoadData($get_cached_data, $get_from_data_source, $parse_xml_result, $expected_return) { $diw = $this->getMock('DailyImageWidget', array('_get_from_data_source', '_get_cached_data', 'parse_xml')); - $diw->expects($this->once())->method('_get_cached_data')->will($this->returnValue(true)); - _reset_wp(); - $this->assertTrue($diw->_load_data()); - $this->assertFalse(is_array(get_option('hubblesite-daily-image-cache'))); - - $diw = $this->getMock('DailyImageWidget', array('_get_from_data_source', '_get_cached_data', 'parse_xml')); - $diw->expects($this->once())->method('_get_cached_data')->will($this->returnValue(false)); - $diw->expects($this->once())->method('_get_from_data_source')->will($this->returnValue(true)); - $diw->expects($this->once())->method('parse_xml')->will($this->returnValue(false)); - _reset_wp(); + $diw->expects($this->once())->method('_get_cached_data')->will($this->returnValue($get_cached_data)); + if ($get_cached_data == false) { + $diw->expects($this->once())->method('_get_from_data_source')->will($this->returnValue($get_from_data_source)); + if ($get_from_data_source) { + $diw->expects($this->once())->method('parse_xml')->will($this->returnValue($parse_xml_result)); + } + } - $this->assertFalse($diw->_load_data()); - $this->assertFalse(is_array(get_option('hubblesite-daily-image-cache'))); - - $diw = $this->getMock('DailyImageWidget', array('_get_from_data_source', '_get_cached_data', 'parse_xml')); - $diw->expects($this->once())->method('_get_cached_data')->will($this->returnValue(false)); - $diw->expects($this->once())->method('_get_from_data_source')->will($this->returnValue(true)); - $diw->expects($this->once())->method('parse_xml')->will($this->returnValue(true)); - _reset_wp(); + $this->assertEquals($expected_return, $diw->_load_data()); - $this->assertTrue($diw->_load_data()); - $this->assertTrue(is_array(get_option('hubblesite-daily-image-cache'))); + $this->assertEquals($parse_xml_result, is_array(get_option('hubblesite-daily-image-cache'))); + } + + + function providerTestWidowProtection() { + return array( + array("this is fixed", "this is fixed"), + array("

this is fixed

" ,"

this is fixed

"), + array("this is fixed", "this is fixed"), + array("word", "word"), + array("

this is fixed

Also fixed

", '

this is fixed

Also fixed

') + ); + } + + /** + * @dataProvider providerTestWidowProtection + */ + function testWidowProtection($source, $result) { + $this->assertEquals($result, $this->diw->_fix_widows($source)); } }