From e5074859edbfd0b07a12cec8139406f080cfeac3 Mon Sep 17 00:00:00 2001
From: jessebeach <jessebeach@748566.no-reply.drupal.org>
Date: Sun, 7 Aug 2011 22:32:07 -0400
Subject: [PATCH] Issue #1183250 by jessebeach: Introduced theme_time to theme.inc

Signed-off-by: Jesse Beach <splendidnoise@gmail.com>
---
 includes/common.inc                 |    3 +
 includes/theme.inc                  |  114 +++++++++++++++++++++++++++++++++++
 modules/simpletest/tests/theme.test |   83 +++++++++++++++++++++++++
 3 files changed, 200 insertions(+), 0 deletions(-)

diff --git a/includes/common.inc b/includes/common.inc
index 5f7cdb8..9b57db2 100644
--- a/includes/common.inc
+++ b/includes/common.inc
@@ -6438,6 +6438,9 @@ function drupal_common_theme() {
       'render element' => 'elements',
       'template' => 'region',
     ),
+    'time' => array(
+      'variables' => array('text' => NULL, 'attributes' => array(), 'path' => NULL),
+    ),
     'status_messages' => array(
       'variables' => array('display' => NULL),
     ),
diff --git a/includes/theme.inc b/includes/theme.inc
index bea87c0..ffb15c2 100644
--- a/includes/theme.inc
+++ b/includes/theme.inc
@@ -1447,6 +1447,34 @@ function theme_disable($theme_list) {
  */
 
 /**
+ * Returns HTML for a date / time.
+ *
+ * @param $variables
+ *   An associative array containing:
+ *   - text: (optional) The text to display in the <time> element. This will
+ *     default to a formatted date of the datetime attribute value.
+ *   - attributes: (optional) Attributes for the time element. @see
+ *     http://www.w3.org/TR/html5/text-level-semantics.html#the-time-element
+ *   - path: (optional) A string that contains a URL or URL fragment to pass to
+ *     the l() function to render the time element text as a link.
+ *
+ * @see template_preprocess_time
+ */
+function theme_time($variables) {
+  $output = '<time' . drupal_attributes($variables['attributes']) . '>';
+  // Wrap the human readable label in a link if a path is provided.
+  if (!empty($variables['path'])) {
+    $output .= l($variables['text'], $variables['path']);
+  }
+  else {
+    $output .= $variables['text'];
+  }
+  $output .= '</time>';
+
+  return $output;
+}
+
+/**
  * Returns HTML for status and/or error messages, grouped by type.
  *
  * An invisible heading identifies the messages for assistive technology.
@@ -2563,6 +2591,92 @@ function theme_get_suggestions($args, $base, $delimiter = '__') {
 }
 
 /**
+ * Process variables for theme_time().
+ *
+ * The offset value is used to calculate a time interval from the timestamp.
+ * The labels are used to indicate if the interval represents how long in the
+ * past the timestamp event occurred or when in the future the timestamp event
+ * will occur. If the offset and the timestamp are equivalent, the label
+ * indicates that the timestamp has happened now.
+ *
+ * @param $variables
+ *   An associative array containing:
+ *   - gmdate_format: The format for the Unix style timestamp passed
+ *     to the gmdate() function. Defaults to 'Y-m-d\TH:i:s\Z'. We use gmdate()
+ *     with Z for the UTC value so that the datestamp remains constant
+ *     regardless of the time on the server that requested it.
+ *     @see http://www.php.net/manual/en/function.gmdate.php
+ *   - timestamp: the original value of the datetime attribute. This can be used
+ *     to change the output format of the datetime attribute or the time element
+ *     text. 
+ *   - offset: A Unix style time from or until the datetime
+ *     attribute value. Providing an offset will cause the time element text
+ *     to be rendered as an interval e.g. 2 months, 3 days ago. To get an
+ *     interval from today, set the offset property to REQUEST_TIME.
+ *   - labels: An associative array containing the following optional
+ *     properties.
+ *     - past: The label for an interval time that occurred in the past.
+ *     - future: The label for an interval time that occurs in the future.
+ *   - granularity: The granularity of the interval time, passed to
+ *     format_interval().
+ *   - langcode: The langcode of the interval time, passed to
+ *     format_interval().
+ *   - format_options: The options passed to format_date().
+ */
+function template_preprocess_time(&$variables) {
+  // Get the datetime attribute. If none exists, assume REQUEST_TIME;
+  if (empty($variables['attributes']['datetime'])) {
+    $variables['attributes']['datetime'] = REQUEST_TIME;
+  }
+  // Save the datetime attribute to a variable so that modules can reformat
+  // the datetime attribute value in subsequent process functions.
+  $variables['timestamp'] = $variables['attributes']['datetime'];
+  // Set the datetime attribute date format.
+  if (empty($variables['gmdate_format'])) {
+    $variables['gmdate_format'] = 'Y-m-d\TH:i:s\Z';
+  }
+  // Format the datetime attribute with gmdate().
+  $variables['attributes']['datetime'] = gmdate($variables['gmdate_format'], $variables['timestamp']);
+  // If an offset time is provided, print the <time> element text as an interval
+  // between the timestamp time and the offset time.
+  if (empty($variables['text']) && isset($variables['offset'])) {
+    // Prepare the interval labels.
+    $past_label = (!empty($variables['labels']['past'])) ? $variables['labels']['past'] : t('ago');
+    $future_label = (!empty($variables['labels']['future'])) ? $variables['labels']['future'] : t('to go');
+    $granularity = (!empty($variables['granularity'])) ? $variables['granularity'] : 2;
+    $langcode = (!empty($variables['langcode'])) ? $variables['langcode'] : NULL;
+    // Calculate the time interval.
+    $interval = $variables['timestamp'] - $variables['offset'];
+    // Determine if the date is in the past or the future and
+    // adjust the human readable label according to the interval value.
+    switch ($interval) {
+      case ($interval > 0):
+        $variables['text'] = t(format_interval(abs($interval), $granularity, $langcode) . ' ' . $future_label);
+        break;
+
+      case ($interval <= 0):
+        $variables['text'] = t(format_interval(abs($interval), $granularity, $langcode). ' ' . $past_label);
+        break;
+    }
+  }
+  // If no text for the <time> element was provided, print a formatted version
+  // of the datetime attribute.
+  if (empty($variables['text'])) {
+    // Set defaults for the format_date() function.
+    if (!isset($variables['format_options'])) {
+      $variables['format_options'] = array();
+    }
+    $variables['format_options'] += array(
+      'type' => '',
+      'format' => '',
+      'timezone' => NULL,
+      'langcode' => NULL,
+    );
+    $variables['text'] = format_date($variables['timestamp'], $variables['format_options']['type'], $variables['format_options']['format'], $variables['format_options']['timezone'], $variables['format_options']['langcode']);
+  }
+}
+
+/**
  * The variables array generated here is a mirror of template_preprocess_page().
  * This preprocessor will run its course when theme_maintenance_page() is
  * invoked.
diff --git a/modules/simpletest/tests/theme.test b/modules/simpletest/tests/theme.test
index 7c68989..4d24534 100644
--- a/modules/simpletest/tests/theme.test
+++ b/modules/simpletest/tests/theme.test
@@ -451,3 +451,86 @@ class ThemeHtmlTag extends DrupalUnitTestCase {
     $this->assertEqual('<title>title test</title>'."\n", theme_html_tag($tag), t('Test title tag generation.'));
   }
 }
+
+/**
+ * Unit tests for theme_time().
+ */
+class ThemeTime extends DrupalUnitTestCase {
+  public static function getInfo() {
+    return array(
+      'name' => "Theme HTML time tag",
+      'description' => 'Tests the theme_time() theme function.',
+      'group' => 'Theme',
+    );
+  }
+
+  /**
+   * Test function theme_time().
+   */
+  function testThemeTime() {
+    // Test the server's timezone
+    $timestamp = 280281600;
+    $variables = array(
+      'attributes' => array(
+        'datetime' => $timestamp  
+      ),
+    );
+    // format_date is called because the display of the timestamp will depend
+    // on the timezone of the server that runs this function.
+    $date = format_date($timestamp);
+    $this->assertEqual('<time datetime="1978-11-19T00:00:00Z">' . $date . '</time>', theme('time', $variables), 'Test a basic invocation of theme_time with just a timestamp.');
+
+    // Test a specific timezone - Europe/Brussels
+    $timestamp = 280281600;
+    $variables = array(
+      'attributes' => array(
+        'datetime' => $timestamp,
+      ),
+      'format_options' => array(
+        'timezone' => 'Europe/Brussels',
+      ),
+    );
+    $this->assertEqual('<time datetime="1978-11-19T00:00:00Z">Sun, 11/19/1978 - 01:00</time>', theme('time', $variables), 'Test theme_time with a timestamp and the timezone Europe/Brussels.');
+
+    // Test the text rendered as an interval in the past.
+    $timestamp = 280281600;
+    $offset = 1227052800;
+    $variables = array(
+      'attributes' => array(
+        'datetime' => $timestamp,
+      ),
+      'offset' => $offset,
+      'labels' => array(
+        'past' => 'in the past',
+      ),
+    );
+    $this->assertEqual('<time datetime="1978-11-19T00:00:00Z">30 years 1 week in the past</time>', theme('time', $variables), 'Test theme_time with an offset time of 30 years in the past.');
+
+    // Test the text rendered as an interval in the future.
+    $timestamp = 1227052800;
+    $offset = 280281600;
+    $variables = array(
+      'attributes' => array(
+        'datetime' => $timestamp,
+      ),
+      'offset' => $offset,
+      'labels' => array(
+        'future' => 'in the future',
+      ),
+    );
+    $this->assertEqual('<time datetime="2008-11-19T00:00:00Z">30 years 1 week in the future</time>', theme('time', $variables), 'Test theme_time with an offset time of 30 years in the future.');
+
+    // Test wrapping the time text in a link.
+    $timestamp = 280281600;
+    $variables = array(
+      'attributes' => array(
+        'datetime' => $timestamp,
+      ),
+      'format_options' => array(
+        'timezone' => 'Europe/Brussels',
+      ),
+      'path' => 'http://buytaert.net/',
+    );
+    $this->assertEqual('<time datetime="1978-11-19T00:00:00Z"><a href="http://buytaert.net/">Sun, 11/19/1978 - 01:00</a></time>', theme('time', $variables), 'Test theme_time with a timestamp, the timezone Europe/Brussels and a link.');
+  }
+}
-- 
1.7.3.4

