? jquery.timers.js
Index: clock.js
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/clock/clock.js,v
retrieving revision 1.11
diff -u -p -r1.11 clock.js
--- clock.js	21 Mar 2010 20:52:32 -0000	1.11
+++ clock.js	3 May 2010 17:22:13 -0000
@@ -1,416 +1,454 @@
 // $Id: clock.js,v 1.11 2010/03/21 20:52:32 tstoeckler Exp $
 (function ($) {
 
-/*
- * Gets the date format and time zone related parameters from PHP and formats the date according
- * to the php date formatters. Visit http://php.net/date for more information. Using jQuery Timers (http://plugins.jquery.com/project/timers) the
- * date is recalculated every second to make the clock dynamic.
+/**
+ * Gets the date format and time zone related parameters from PHP and formats
+ * the date according to the PHP date formatters. Visit http://php.net/date for
+ * more information. Using jQuery Timers
+ * (http://plugins.jquery.com/project/timers) the date is recalculated every
+ * second to make the clock dynamic.
  */
 Drupal.behaviors.clockDisplay = {
   attach: function (context, settings) {
 
-    // Whether or not to update the clock continuously
-    var clockUpdate = Drupal.settings['0'];
-    // Gets a PHP timestamp, which counts the seconds since the begin of the UNIX-era.
-    var clockTimestampString = settings['1'];
-    // The time zone offset in seconds.
-    var clockTimezoneOffsetSeconds = settings['2'];
-    // The name of the timezone, e.g. 'Europe/London'.
-    var clockTimezoneName = settings['3'];
-    // Daylight Savings Time information. '1' for yes, '0' for no.
-    var clockDaylightSavingsTime = settings['4'];
-    // The name of the offset, e.g. 'GMT'.
-    var clockOffsetName = settings['5'];
-    // A PHP date format string.
-    var clockDateFormat = settings['6'];
-
-    // Calculate the timestamp with the time zone offset and turn it into milliseconds.
-    // JavaScript's time handling is based on milliseconds, while PHP's is based on seconds.
-    // TODO: Either remove the '-3600'-hack that currently makes this work, or figure out why it is needed.
-    var clockTimestamp = (parseInt(clockTimestampString) - 3600 + parseInt(clockTimezoneOffsetSeconds)) * 1000;
-
-    // Calculate whether it is a leap year or not. Years that are multiples of 4 are leap years,
-    // while multiples of 100 are not, but multiples of 400 are. That way 1600, 2000, 2004, 2008 were leap years, while 1700, 1800, 1900 were not.
-    var clockDate = new Date(clockTimestamp);
-    var year = clockDate.getFullYear();
-    if (((year % 4) == 0) && ((year % 100) != 0) || ((year % 400) == 0)) {
-      var leapYear = '1';
-    }
-    else {
-      var leapYear = '0';
-    }
-
-    // Create an array containing month names and lengths.
-    // While contexts are in Core for the t() and format_plural() functions, they are not implememted for the JavaScript equivalent Drupal.t();
-    // See http://drupal.org/node/488496 for more information.
-    var months = new Array();
-    months[1] = new Object();
-    months[1]['longName'] = Drupal.t('January');
-    months[1]['shortName'] = Drupal.t('Jan');
-    months[1]['days'] = 31;
-    months[2] = new Object();
-    months[2]['longName'] = Drupal.t('February');
-    months[2]['shortName'] = Drupal.t('Feb');
-    months[2]['days'] = ((leapYear == 1) ? 29 : 28);
-    months[3] = new Object();
-    months[3]['longName'] = Drupal.t('March');
-    months[3]['shortName'] = Drupal.t('Mar');
-    months[3]['days'] = 31;
-    months[4] = new Object();
-    months[4]['longName'] = Drupal.t('April');
-    months[4]['shortName'] = Drupal.t('Apr');
-    months[4]['days'] = 30;
-    months[5] = new Object();
-    months[5]['longName'] = Drupal.t('May');
-    months[5]['shortName'] = Drupal.t('May');
-    months[5]['days'] = 31;
-    months[6] = new Object();
-    months[6]['longName'] = Drupal.t('June');
-    months[6]['shortName'] = Drupal.t('Jun');
-    months[6]['days'] = 30;
-    months[7] = new Object();
-    months[7]['longName'] = Drupal.t('July');
-    months[7]['shortName'] = Drupal.t('Jul');
-    months[7]['days'] = 31;
-    months[8] = new Object();
-    months[8]['longName'] = Drupal.t('August');
-    months[8]['shortName'] = Drupal.t('Aug');
-    months[8]['days'] = 31;
-    months[9] = new Object();
-    months[9]['longName'] = Drupal.t('September');
-    months[9]['shortName'] = Drupal.t('Sep');
-    months[9]['days'] = 30;
-    months[10] = new Object();
-    months[10]['longName'] = Drupal.t('October');
-    months[10]['shortName'] = Drupal.t('Oct');
-    months[10]['days'] = 31;
-    months[11] = new Object();
-    months[11]['longName'] = Drupal.t('November');
-    months[11]['shortName'] = Drupal.t('Nov');
-    months[11]['days'] = 30;
-    months[12] = new Object();
-    months[12]['longName'] = Drupal.t('December');
-    months[12]['shortName'] = Drupal.t('Dec');
-    months[12]['days'] = 31;
-
-    // Create an array containing weekday names.
-    var weekdays = new Array();
-    weekdays[0] = new Object();
-    weekdays[0]['longName'] = Drupal.t('Sunday');
-    weekdays[0]['shortName'] = Drupal.t('Sun');
-    weekdays[1] = new Object();
-    weekdays[1]['longName'] = Drupal.t('Monday');
-    weekdays[1]['shortName'] = Drupal.t('Mon');
-    weekdays[2] = new Object();
-    weekdays[2]['longName'] = Drupal.t('Tuesday');
-    weekdays[2]['shortName'] = Drupal.t('Tue');
-    weekdays[3] = new Object();
-    weekdays[3]['longName'] = Drupal.t('Wednesday');
-    weekdays[3]['shortName'] = Drupal.t('Wed');
-    weekdays[4] = new Object();
-    weekdays[4]['longName'] = Drupal.t('Thursday');
-    weekdays[4]['shortName'] = Drupal.t('Thu');
-    weekdays[5] = new Object();
-    weekdays[5]['longName'] = Drupal.t('Friday');
-    weekdays[5]['shortName'] = Drupal.t('Fri');
-    weekdays[6] = new Object();
-    weekdays[6]['longName'] = Drupal.t('Saturday');
-    weekdays[6]['shortName'] = Drupal.t('Sat');
-
-
-    // Initialize the clock variable for later use.
-    var clock = '';
-
-    // Format a given date format string into a proper date string.
-    function formatDate(date, timestamp, dateFormat, timezoneOffsetSeconds, timezoneName, daylightSavingsTime, offsetName) {
-      // Initialize the 'formattedDate' variable for later use.
-      var formattedDate = '';
-
-      // Prepare variables for the format conversion.
-
-      // Year-related.
-      var year = date.getFullYear();
-      var yearShort = year % 100;
-
-      // Month-related.
-      var month = date.getMonth();
-      // JavaScript starts counting the months with 0 instead of 1.
-      month++;
-      var monthLeadingZero = ((month < 10) ? '0' + month : month);
-      var monthLongName = months[month]['longName'];
-      var monthShortName = months[month]['shortName'];
-
-      var day = date.getDate();
-      var dayLeadingZero = ((day < 10) ? '0' + day : day);
-      switch (day) {
-        case 1:
-          var dayOfMonthAppend = Drupal.t('st');
-          break;
-        case 2:
-          var dayOfMonthAppend = Drupal.t('nd');
-          break;
-        case 3:
-          var dayOfMonthAppend = Drupal.t('rd');
-          break;
-        default:
-          var dayOfMonthAppend = Drupal.t('th');
-          break;
-      }
-      // To calculate the days of the year, iterate through all passed months and then add the current days of the month.
-      var daysOfYear = 0;
-      for (var m = 1; m < month; m++) {
-        daysOfYear += months[m]['days'];
-      }
-      daysOfYear += day;
-
-      // Week-related.
-      var weekday = date.getDay();
-      if (weekday == 0) {
-        var weekNumber = Math.floor((daysOfYear - 7) / 7) + 1;
-      }
-      else {
-        var weekNumber = Math.floor((daysOfYear - weekday) / 7) + 1;
-      }
-      var weekNumberLeadingZero = ((weekNumber < 10) ? '0' + weekNumber : weekNumber);
-      var weekdayLongName = weekdays[weekday]['longName'];
-      var weekdayShortName = weekdays[weekday]['shortName'];
-
-      // Offset-related.
-      if (timezoneOffsetSeconds < 0) {
-        var offsetPrefix = '-';
-        var offsetHours = Math.floor(parseInt(timezoneOffsetSeconds.substr(1)) / 3600);
-        var offsetHoursLeadingZero = ((offsetHours < 10) ? '0' + offsetHours : offsetHours);
-        var offsetMinutes = (parseInt(timezoneOffsetSeconds.substr(1)) / 60) % 60;
-        var offsetMinutesLeadingZero = ((offsetMinutes < 10) ? '0' + offsetMinutes : offsetMinutes);
-      }
-      else {
-        var offsetPrefix = '+';
-        var offsetHours = Math.floor(timezoneOffsetSeconds) / 3600;
-        var offsetHoursLeadingZero = ((offsetHours < 10) ? '0' + offsetHours : offsetHours);
-        var offsetMinutes = (timezoneOffsetSeconds / 60) % 60;
-        var offsetMinutesLeadingZero = ((offsetMinutes < 10) ? '0' + offsetMinutes : offsetMinutes);
-      }
-
-      // Hour-related.
-      var hours = date.getHours();
-      var hoursLeadingZero = ((hours < 10) ? '0' + hours : hours);
-      if (hours == 0) {
-        var hoursTwelve = (hours + 12);
-      }
-      else if (hours > 12) {
-        var hoursTwelve = (hours - 12);
-      }
-      else {
-        var hoursTwelve = hours;
-      }
-      var hoursTwelveLeadingZero = ((hoursTwelve < 10) ? '0' + hoursTwelve : hoursTwelve);
-
-      // Minute-related.
-      var minutes = date.getMinutes();
-      var minutesLeadingZero = ((minutes < 10) ? '0' + minutes : minutes);
-
-      // Second-related.
-      var seconds = date.getSeconds();
-      var secondsLeadingZero = ((seconds < 10) ? '0' + seconds : seconds);
-      var beats = Math.floor(((hours * 3600) + (minutes * 60) + seconds - parseInt(timezoneOffsetSeconds) + 3600) / 86400 * 1000);
-      if (beats < 10) {
-        var beatsLeadingZero = ((beats < 10) ? '00' + beats : beats);
-      }
-      else if (beats < 100) {
-        var beatsLeadingZero = ((beats < 100) ? '0' + beats : beats);
-      }
-      else {
-        var beatsLeadingZero = beats;
-      }
-
-      // Turn the date format string into an array so each character has its own key.
-      var dateFormatParts = dateFormat.length;
-      var dateFormatArray = dateFormat.split('');
-
-      // Perform the date format conversion for a character.
-      for (i=0; i < dateFormatParts; i++) {
-        switch (dateFormatArray[i]) {
-          // If the escape character '\' is used, simply return the following character.
-          case '\\':
-            formattedDate += dateFormatArray[++i];
-            break;
-          // 'am' or 'pm' depending on the time of day.
-          case 'a':
-            formattedDate += ((hours >= 12) ? Drupal.t('pm') : Drupal.t('am'));
-            break;
-          // 'AM' or 'PM' depending on the time of day.
-          case 'A':
-            formattedDate += ((hours >= 12) ? Drupal.t('PM') : Drupal.t('AM'));
-            break;
-          // Swatch-Internet-Time.
-          case 'B':
-            formattedDate += beatsLeadingZero;
-            break;
-          // ISO-8601 date.
-          case 'c':
-            formattedDate += year + '-' + monthLeadingZero + '-' + dayLeadingZero + 'T' + hoursLeadingZero + ':' + minutesLeadingZero + ':' + secondsLeadingZero + offsetPrefix + offsetHoursLeadingZero + ':' + offsetMinutesLeadingZero;
-            break;
-          // Day of month with leading zero, '01' - '31'.
-          case 'd':
-            formattedDate += dayLeadingZero;
-            break;
-          // Short name of weekday, e.g. 'Sun'.
-          case 'D':
-            formattedDate += weekdayShortName;
-            break;
-          // Time zone name, e.g. 'Europe/London';
-          case 'e':
-            formattedDate += timezoneName;
-            break;
-          // Name of month, e.g. 'January'.
-          case 'F':
-            formattedDate += monthLongName;
-            break;
-          // Hours in 12-hour format, '1' - '12'.
-          case 'g':
-            formattedDate += hoursTwelve;
-            break;
-          // Hours in 24-hour format, '0' - '23'.
-          case 'G':
-            formattedDate += hours;
-            break;
-          // Hours in 12-hour format with leading zero, '01' - '12'.
-          case 'h':
-            formattedDate += hoursTwelveLeadingZero;
-            break;
-          // Hours in 24-hour format with leading zero, '00' - '23'.
-          case 'H':
-            formattedDate += hoursLeadingZero;
-            break;
-          // Minutes with leading zero, '00' - '59'.
-          case 'i':
-            formattedDate += minutesLeadingZero;
-            break;
-          // Daylight Savings Time, '1' or '0'
-          case 'I':
-            formattedDate += daylightSavingsTime;
-            break;
-          // Day of month, '1' - '31'
-          case 'j':
-            formattedDate += day;
-            break;
-          // Name of weekday, e.g. 'Sunday'.
-          case 'l':
-            formattedDate += weekdayLongName;
-            break;
-          // Leap year, '1' or '0'.
-          case 'L':
-            formattedDate += leapYear;
-            break;
-          // Number of month with leading zero, '01' - '12'
-          case 'm':
-            formattedDate += monthLeadingZero;
-            break;
-          // Short name of month, e.g. 'Jan'.
-          case 'M':
-            formattedDate += monthShortName;
-            break;
-          // Number of month, '1' - '12'.
-          case 'n':
-            formattedDate += month;
-            break;
-          // Time zone offset, e.g. '+1030'
-          case 'O':
-            formattedDate += offsetPrefix + offsetHoursLeadingZero + offsetMinutesLeadingZero;
-            break;
-          // Time zone offset, e.g. '+10:30'.
-          case 'P':
-            formattedDate += offsetPrefix + offsetHoursLeadingZero + ':' + offsetMinutesLeadingZero;
-            break;
-          // RFC-2822 date.
-          case 'r':
-            formattedDate += weekdayShortName + ', ' + dayLeadingZero + ' ' + monthShortName + ' ' + year + ' ' + hoursLeadingZero + ':' + minutesLeadingZero + ':' + secondsLeadingZero + ' ' + offsetPrefix + offsetHoursLeadingZero + offsetMinutesLeadingZero;
-            break;
-          // Seconds with leading zero.
-          case 's':
-            formattedDate += secondsLeadingZero;
-            break;
-          // Appendage for the day of month, e.g. 'st' if the day is '1'.
-          case 'S':
-            formattedDate += dayOfMonthAppend;
-            break;
-          // Total days of month, '28' - '31'.
-          case 't':
-            formattedDate += months[month]['days'];
-            break;
-          // Name of offset, e.g. 'GMT'.
-          case 'T':
-            formattedDate += offsetName;
-            break;
-          // Seconds since the begin of the UNIX-era.
-          // We have to divide by 1000 to get seconds, not milliseconds.
-          case 'U':
-            formattedDate += timestamp / 1000;
-            break;
-          // Number of weekday, '0' for Sunday, ..., '6' for Saturday.
-          case 'w':
-            formattedDate += weekday;
-            break;
-          // Week number with leading zero, '01' - '52'.
-          case 'W':
-            formattedDate += weekNumberLeadingZero;
-            break;
-          // Year, e.g. '2001'.
-          case 'Y':
-            formattedDate += year;
-            break;
-          // Short year, e.g. '01'.
-          case 'y':
-            formattedDate += yearShort;
-            break;
-          // Days of the year, '0' - '365'.
-          // Since PHP starts counting the days of the year at '0', we need subtract one.
-          case 'z':
-            formattedDate += daysOfYear - 1;
-            break;
-          // Time zone offset in seconds.
-          case 'Z':
-            formattedDate += timezoneOffsetSeconds;
-            break;
-          // If the character is not a date formatter, just add it to the output.
-          default:
-            formattedDate += dateFormatArray[i];
-            break;
-        }
-      }
-      return formattedDate;
-    }
-
-    if (clockUpdate == '1') {
+  // Gets the correct variables from PHP.
+  // Creates a JavaScript date object, from a specially formatted date string.
+  var date = new Date(Drupal.settings['time']);
+  // A PHP date format string.
+  var dateFormat = Drupal.settings['date_format'];
+  // The name of the timezone, e.g. 'Europe/London'.
+  var timezoneName = Drupal.settings['timezone_name'];
+  // If time zone is set to 'Local' overwrite the date.
+  if (timezoneName == 'Local') {
+    var date = new Date();
+  }
+  // The name of the offset, e.g. 'GMT'.
+  var offsetName = Drupal.settings['offset_name'];
+  // The time zone offset in seconds.
+  var offsetSeconds = Drupal.settings['offset_seconds'];
+  // Daylight Savings Time information. '1' for yes, '0' for no.
+  var daylightSavingsTime = Drupal.settings['daylight_savings_time'];
+  // Whether or not to update the clock continuously
+  var update = Drupal.settings['js'];
+
+  // Create an array containing month names.
+  var monthNames = new Array();
+  monthNames[1] = new Object();
+  monthNames[1]['long'] = Drupal.t('January');
+  monthNames[1]['short'] = Drupal.t('Jan');
+  monthNames[2] = new Object();
+  monthNames[2]['long'] = Drupal.t('February');
+  monthNames[2]['short'] = Drupal.t('Feb');
+  monthNames[3] = new Object();
+  monthNames[3]['long'] = Drupal.t('March');
+  monthNames[3]['short'] = Drupal.t('Mar');
+  monthNames[4] = new Object();
+  monthNames[4]['long'] = Drupal.t('April');
+  monthNames[4]['short'] = Drupal.t('Apr');
+  monthNames[5] = new Object();
+  monthNames[5]['long'] = Drupal.t('May');
+  // Use context if http://drupal.org/node/488496 gets in.
+  monthNames[5]['short'] = Drupal.t('May');
+  monthNames[6] = new Object();
+  monthNames[6]['long'] = Drupal.t('June');
+  monthNames[6]['short'] = Drupal.t('Jun');
+  monthNames[7] = new Object();
+  monthNames[7]['long'] = Drupal.t('July');
+  monthNames[7]['short'] = Drupal.t('Jul');
+  monthNames[8] = new Object();
+  monthNames[8]['long'] = Drupal.t('August');
+  monthNames[8]['short'] = Drupal.t('Aug');
+  monthNames[9] = new Object();
+  monthNames[9]['long'] = Drupal.t('September');
+  monthNames[9]['short'] = Drupal.t('Sep');
+  monthNames[10] = new Object();
+  monthNames[10]['long'] = Drupal.t('October');
+  monthNames[10]['short'] = Drupal.t('Oct');
+  monthNames[11] = new Object();
+  monthNames[11]['long'] = Drupal.t('November');
+  monthNames[11]['short'] = Drupal.t('Nov');
+  monthNames[12] = new Object();
+  monthNames[12]['long'] = Drupal.t('December');
+  monthNames[12]['short'] = Drupal.t('Dec');
+
+  // Create an array containing weekday names.
+  var weekdayNames = new Array();
+  weekdayNames[0] = new Object();
+  weekdayNames[0]['long'] = Drupal.t('Sunday');
+  weekdayNames[0]['short'] = Drupal.t('Sun');
+  weekdayNames[1] = new Object();
+  weekdayNames[1]['long'] = Drupal.t('Monday');
+  weekdayNames[1]['short'] = Drupal.t('Mon');
+  weekdayNames[2] = new Object();
+  weekdayNames[2]['long'] = Drupal.t('Tuesday');
+  weekdayNames[2]['short'] = Drupal.t('Tue');
+  weekdayNames[3] = new Object();
+  weekdayNames[3]['long'] = Drupal.t('Wednesday');
+  weekdayNames[3]['short'] = Drupal.t('Wed');
+  weekdayNames[4] = new Object();
+  weekdayNames[4]['long'] = Drupal.t('Thursday');
+  weekdayNames[4]['short'] = Drupal.t('Thu');
+  weekdayNames[5] = new Object();
+  weekdayNames[5]['long'] = Drupal.t('Friday');
+  weekdayNames[5]['short'] = Drupal.t('Fri');
+  weekdayNames[6] = new Object();
+  weekdayNames[6]['long'] = Drupal.t('Saturday');
+  weekdayNames[6]['short'] = Drupal.t('Sat');
+
+  // Prepare the timezone array.
+  var timezone = new Array();
+  timezone['name'] = timezoneName;
+  timezone['offsetSeconds'] = offsetSeconds;
+  timezone['daylightSavingsTime'] = daylightSavingsTime;
+  timezone['offsetName'] = offsetName;
+
+  // Format the clock.
+  clock = formatDate(date, dateFormat, timezone, monthNames, weekdayNames);
+  $('div.clock').html(clock);
+
+  if (update == '1') {
+
+    // Recalculate the date every second. '.everyTime' is provided by jQuery Timers.
+    $(document).everyTime(1000, function() {
+
+      // Add 1 second to the time.
+      var clockTimestamp = date.getTime();
+      clockTimestamp = clockTimestamp + 1000;
+      date = new Date(clockTimestamp);
 
       // Format the clock.
-      if (clockTimezoneName == 'Local') {
-        var clockDate = new Date();
-      }
-      else {
-        var clockDate = new Date(clockTimestamp);
-      }
-      clock = formatDate(clockDate, clockTimestamp, clockDateFormat, clockTimezoneOffsetSeconds, clockTimezoneName, clockDaylightSavingsTime, clockOffsetName);
+      clock = formatDate(date, dateFormat, timezone, monthNames, weekdayNames);
       $('div.clock').html(clock);
+    }, 0);
+
+  }
+}
 
-      // Recalculate the date every second. '.everyTime' is provided by jQuery Timers.
-      $(document).everyTime(1000, function() {
-        // Add 1 second to the timestamp.
-        clockTimestamp = clockTimestamp + 1000;
-        // Format the timestamp into the given format.
-        if (clockTimezoneName == 'Local') {
-          clockDate = new Date();
-        }
-        else {
-          clockDate = new Date(clockTimestamp);
-        }
-        clock = formatDate(clockDate, clockTimestamp, clockDateFormat, clockTimezoneOffsetSeconds, clockTimezoneName, clockDaylightSavingsTime, clockOffsetName);
-        $('div.clock').html(clock);
-      }, 0);
+})(jQuery);
+
+/**
+ * Formats a date into a PHP date string.
+ *
+ * @param date
+ *   A date object.
+ * @param dateFormat
+ *   A string. See http://php.net/date for possible values.
+ * @param timezone
+ *   An associative array containing timezone information. It should consist of
+ *   following keys:
+ *   - timezoneName: The name of the timezone, e.g. 'Europe/London'.
+ *   - offsetSeconds: The timezone offset in seconds.
+ *   - offsetName: The name of the offset, e.g. 'UTC'.
+ *   - daylightSavingsTime: Whether or not the time is in daylight savings time.
+ *     '1' if yes, '0' if not.
+ * @param monthNames
+ *   An array of month names keyed by the numbers 1-12. Each value should in turn
+ *   be an array keyed 'long' and 'short' for the long respective the short
+ *   month names.
+ * @param weekdayNames
+ *   An array of weekday names keyed by the numbers 0 (for Sunday) - 6 (for
+ *   Saturday). Each value should in turn be an array keyed by 'long' and
+ *   'short' for the long respective the short weekday names.
+ *
+ * @return
+ *   A formatted date string.
+ */
+function formatDate(date, dateFormat, timezone, monthNames, weekdayNames) {
+  var timezoneName = timezone['name'];
+  var offsetSeconds = timezone['offsetSeconds'];
+  var offsetName = timezone['offsetName'];
+  var daylightSavingsTime = timezone['daylightSavingsTime'];
+
+  // Initialize the 'formattedDate' variable for later use.
+  var formattedDate = '';
+
+  // Prepare variables for the format conversion.
+
+  // Year-related.
+  var year = date.getFullYear();
+  var yearShort = year % 100;
+  // Calculate whether it is a leap year or not. Years that are multiples of 4
+  // are leap years, while multiples of 100 are not, but multiples of 400 are.
+  var year = date.getFullYear();
+  if (((year % 4) == 0) && ((year % 100) != 0) || ((year % 400) == 0)) {
+    var leapYear = '1';
+  }
+  else {
+    var leapYear = '0';
+  }
 
-    }
+  // Month-related.
+  var month = date.getMonth();
+  // JavaScript starts counting the months with 0 instead of 1.
+  month++;
+  var monthLeadingZero = ((month < 10) ? '0' + month : month);
+  var monthLongName = monthNames[month]['long'];
+  var monthShortName = monthNames[month]['short'];
+  var day = date.getDate();
+  var dayLeadingZero = ((day < 10) ? '0' + day : day);
+  switch (day) {
+    case 1:
+      var dayOfMonthAppend = Drupal.t('st');
+      break;
+    case 2:
+      var dayOfMonthAppend = Drupal.t('nd');
+      break;
+    case 3:
+      var dayOfMonthAppend = Drupal.t('rd');
+      break;
+    default:
+      var dayOfMonthAppend = Drupal.t('th');
+      break;
+  }
+  // Create an array containing month names and lengths.
+  var months = new Array();
+  months[1] = 31;
+  months[2] = ((leapYear == 1) ? 29 : 28);
+  months[3] = 31;
+  months[4] = 30;
+  months[5] = 31;
+  months[6] = 30;
+  months[7] = 31;
+  months[8] = 31;
+  months[9] = 30;
+  months[10] = 31;
+  months[11] = 30;
+  months[12] = 31;
+  // To calculate the days of the year, iterate through all passed months and then add the current days of the month.
+  var daysOfYear = 0;
+  for (var m = 1; m < month; m++) {
+    daysOfYear += months[m];
+  }
+  daysOfYear += day;
 
+  // Week-related.
+  var weekday = date.getDay();
+  if (weekday == 0) {
+    var weekNumber = Math.floor((daysOfYear - 7) / 7) + 1;
+  }
+  else {
+    var weekNumber = Math.floor((daysOfYear - weekday) / 7) + 1;
   }
+  var weekNumberLeadingZero = ((weekNumber < 10) ? '0' + weekNumber : weekNumber);
+  var weekdayLongName = weekdayNames[weekday]['long'];
+  var weekdayShortName = weekdayNames[weekday]['short'];
+
+  // Offset-related.
+  if (offsetSeconds < 0) {
+    var offsetPrefix = '-';
+    var offsetHours = Math.floor(parseInt(offsetSeconds.substr(1)) / 3600);
+    var offsetHoursLeadingZero = ((offsetHours < 10) ? '0' + offsetHours : offsetHours);
+    var offsetMinutes = (parseInt(offsetSeconds.substr(1)) / 60) % 60;
+    var offsetMinutesLeadingZero = ((offsetMinutes < 10) ? '0' + offsetMinutes : offsetMinutes);
+  }
+  else {
+    var offsetPrefix = '+';
+    var offsetHours = Math.floor(offsetSeconds) / 3600;
+    var offsetHoursLeadingZero = ((offsetHours < 10) ? '0' + offsetHours : offsetHours);
+    var offsetMinutes = (offsetSeconds / 60) % 60;
+    var offsetMinutesLeadingZero = ((offsetMinutes < 10) ? '0' + offsetMinutes : offsetMinutes);
+  }
+
+  // Hour-related.
+  var hours = date.getHours();
+  var hoursLeadingZero = ((hours < 10) ? '0' + hours : hours);
+  if (hours == 0) {
+    var hoursTwelve = (hours + 12);
+  }
+  else if (hours > 12) {
+    var hoursTwelve = (hours - 12);
+  }
+  else {
+    var hoursTwelve = hours;
+  }
+  var hoursTwelveLeadingZero = ((hoursTwelve < 10) ? '0' + hoursTwelve : hoursTwelve);
+
+  // Minute-related.
+  var minutes = date.getMinutes();
+  var minutesLeadingZero = ((minutes < 10) ? '0' + minutes : minutes);
+
+  // Second-related.
+  var seconds = date.getSeconds();
+  var secondsLeadingZero = ((seconds < 10) ? '0' + seconds : seconds);
+  var beats = Math.floor(((hours * 3600) + (minutes * 60) + seconds - parseInt(offsetSeconds) + 3600) / 86400 * 1000);
+  if (beats < 10) {
+    var beatsLeadingZero = ((beats < 10) ? '00' + beats : beats);
+  }
+  else if (beats < 100) {
+    var beatsLeadingZero = ((beats < 100) ? '0' + beats : beats);
+  }
+  else {
+    var beatsLeadingZero = beats;
+  }
+  var timestamp = date.getTime();
+
+  // Turn the date format string into an array so each character has its own key.
+  var dateFormat = dateFormat.split('');
+
+  // Perform the date format conversion for a character.
+  for (i=0; i < dateFormat.length; i++) {
+    switch (dateFormat[i]) {
+      // If the escape character '\' is used, simply return the following character.
+      case '\\':
+        formattedDate += dateFormat[++i];
+        break;
+      // 'am' or 'pm' depending on the time of day.
+      case 'a':
+        formattedDate += ((hours >= 12) ? Drupal.t('pm') : Drupal.t('am'));
+        break;
+      // 'AM' or 'PM' depending on the time of day.
+      case 'A':
+        formattedDate += ((hours >= 12) ? Drupal.t('PM') : Drupal.t('AM'));
+        break;
+      // Swatch-Internet-Time.
+      case 'B':
+        formattedDate += beatsLeadingZero;
+        break;
+      // ISO-8601 date.
+      case 'c':
+        formattedDate += year + '-' + monthLeadingZero + '-' + dayLeadingZero + 'T' + hoursLeadingZero + ':' + minutesLeadingZero + ':' + secondsLeadingZero + offsetPrefix + offsetHoursLeadingZero + ':' + offsetMinutesLeadingZero;
+        break;
+      // Day of month with leading zero, '01' - '31'.
+      case 'd':
+        formattedDate += dayLeadingZero;
+        break;
+      // Short name of weekday, e.g. 'Sun'.
+      case 'D':
+        formattedDate += weekdayShortName;
+        break;
+      // Time zone name, e.g. 'Europe/London';
+      case 'e':
+        formattedDate += timezoneName;
+        break;
+      // Name of month, e.g. 'January'.
+      case 'F':
+        formattedDate += monthLongName;
+        break;
+      // Hours in 12-hour format, '1' - '12'.
+      case 'g':
+        formattedDate += hoursTwelve;
+        break;
+      // Hours in 24-hour format, '0' - '23'.
+      case 'G':
+        formattedDate += hours;
+        break;
+      // Hours in 12-hour format with leading zero, '01' - '12'.
+      case 'h':
+        formattedDate += hoursTwelveLeadingZero;
+        break;
+      // Hours in 24-hour format with leading zero, '00' - '23'.
+      case 'H':
+        formattedDate += hoursLeadingZero;
+        break;
+      // Minutes with leading zero, '00' - '59'.
+      case 'i':
+        formattedDate += minutesLeadingZero;
+        break;
+      // Daylight Savings Time, '1' or '0'
+      case 'I':
+        formattedDate += daylightSavingsTime;
+        break;
+      // Day of month, '1' - '31'
+      case 'j':
+        formattedDate += day;
+        break;
+      // Name of weekday, e.g. 'Sunday'.
+      case 'l':
+        formattedDate += weekdayLongName;
+        break;
+      // Leap year, '1' or '0'.
+      case 'L':
+        formattedDate += leapYear;
+        break;
+      // Number of month with leading zero, '01' - '12'
+      case 'm':
+        formattedDate += monthLeadingZero;
+        break;
+      // Short name of month, e.g. 'Jan'.
+      case 'M':
+        formattedDate += monthShortName;
+        break;
+      // Number of month, '1' - '12'.
+      case 'n':
+        formattedDate += month;
+        break;
+      // ISO-8601 weekday number, '1' - '7'.
+      case 'N':
+        formattedDate += weekday + 1;
+        break;
+      // ISO-8601 year number.
+      // This has a different value from 'Y' in certain constellations at the
+      // beginning or end of a year, but this is not implemented here.
+      case 'o':
+        formattedDate += year;
+        break;
+      // Time zone offset, e.g. '+1030'
+      case 'O':
+        formattedDate += offsetPrefix + offsetHoursLeadingZero + offsetMinutesLeadingZero;
+        break;
+      // Time zone offset, e.g. '+10:30'.
+      case 'P':
+        formattedDate += offsetPrefix + offsetHoursLeadingZero + ':' + offsetMinutesLeadingZero;
+        break;
+      // RFC-2822 date.
+      case 'r':
+        formattedDate += weekdayShortName + ', ' + dayLeadingZero + ' ' + monthShortName + ' ' + year + ' ' + hoursLeadingZero + ':' + minutesLeadingZero + ':' + secondsLeadingZero + ' ' + offsetPrefix + offsetHoursLeadingZero + offsetMinutesLeadingZero;
+        break;
+      // Seconds with leading zero.
+      case 's':
+        formattedDate += secondsLeadingZero;
+        break;
+      // Appendage for the day of month, e.g. 'st' if the day is '1'.
+      case 'S':
+        formattedDate += dayOfMonthAppend;
+        break;
+      // Total days of month, '28' - '31'.
+      case 't':
+        formattedDate += months[month];
+        break;
+      // Name of offset, e.g. 'GMT'.
+      case 'T':
+        formattedDate += offsetName;
+        break;
+      // Milliseconds since the begin of the UNIX-era.
+      case 'u':
+        formattedDate += timestamp;
+        break;
+      // Seconds since the begin of the UNIX-era.
+      case 'U':
+        formattedDate += timestamp / 1000;
+        break;
+      // Number of weekday, '0' for Sunday, ..., '6' for Saturday.
+      case 'w':
+        formattedDate += weekday;
+        break;
+      // ISO-8601 week number, '01' - '52'.
+      case 'W':
+        formattedDate += weekNumberLeadingZero;
+        break;
+      // Year, e.g. '2001'.
+      case 'Y':
+        formattedDate += year;
+        break;
+      // Short year, e.g. '01'.
+      case 'y':
+        formattedDate += yearShort;
+        break;
+      // Days of the year, '0' - '365'.
+      // Since PHP starts counting the days of the year at '0', we need subtract one.
+      case 'z':
+        formattedDate += daysOfYear - 1;
+        break;
+      // Time zone offset in seconds.
+      case 'Z':
+        formattedDate += offsetSeconds;
+        break;
+      // If the character is not a date formatter, just add it to the output.
+      default:
+        formattedDate += dateFormat[i];
+        break;
+    }
+  }
+  return formattedDate;
 }
 
-})(jQuery);
Index: clock.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/clock/clock.module,v
retrieving revision 1.12
diff -u -p -r1.12 clock.module
--- clock.module	22 Mar 2010 17:18:12 -0000	1.12
+++ clock.module	3 May 2010 17:22:13 -0000
@@ -1,8 +1,54 @@
 <?php
 // $Id: clock.module,v 1.12 2010/03/22 17:18:12 tstoeckler Exp $
-
-/*
- * Implement hook_block_info()
+
+/**
+* Implements hook_help().
+*/
+function clock_help($path, $arg) {
+  switch ($path) {
+    case 'admin/help#clock':
+      $output = '';
+      $output .= '<h3>' . t('About') . '</h3>';
+      $output .= '<p>' . t('Clock module allows the display of a clock on your site.') . '</p>';
+      $output .= '<h3>' . t('Uses') . '</h3>';
+      $output .= '<dl>';
+      $output .= '<dt>' . t('Administering the clock') . '</dt>';
+      $output .= '<dd>' . t('Since the clock is a block, it can be administered via its <a href="@clock-settings">block settings page</a> which is accessible from the <a href="@block-admin">block administration page</a>. In addition to the usual block configuration options there are a number of options.', array('@clock-settings' => '/admin/build/block/configure/clock/clock', '@block-admin' => '/admin/build/block')) . '</dd>';
+      $output .= '<dl>';
+      $output .= '<dt>' . t('Time zone') . '</dt>';
+      $output .= '<dd>' . t('The time zone of the clock.') . '</dd>';
+      $output .= '<dl>';
+      $output .= '<dt>' . t('Site time zone') . '</dt>';
+      $output .= '<dd>' . t('The time zone that has been set on the <a href="@date-admin">date and time settings page</a>.', array('@date-admin' => '/admin/settings/date-time')) . '</dd>';
+      $output .= '<dt>' . t('User time zone') . '</dt>';
+      $output .= '<dd>' . t('This option will only show up, if user-configurable time zones are enabled. The time zone the user has selected.') . '</dd>';
+      $output .= '<dt>' . t('Local time zone') . '</dt>';
+      $output .= '<dd>' . t('The local time zone on the computer of the visiting user (anonymous and authenticated). Since JavaScript is used to calculate this time, it falls back to the site time zone if the visitor has JavaScript disabled.');
+      $output .= '<dt>' . t('Custom time zone') . '</dt>';
+      $output .= '<dd>' . t('A custom time zone that can be selected in the select box below the radio buttons.') . '</dd>';
+      $output .= '</dl>';
+      $output .= '<dt>' . t('Date format') . '</dt>';
+      $output .= '<dd>' . t('The date format that the clock is to be displayed in.') . '</dd>';
+      $output .= '<dl>';
+      $output .= '<dt>' . t('Short date format') . '</dt>';
+      $output .= '<dd>' . t('The short date format that has been set on the <a href="@format-admin">date format configuration page</a>. The expected output (not necessarily in the correct timezone) is shown in parentheses.', array('@format-admin' => '/admin/settings/date-time/formats')). '</dd>';
+      $output .= '<dt>' . t('Medium date format') . '</dt>';
+      $output .= '<dd>' . t('The medium date format that has been set on the <a href="@format-admin">date format configuration page</a>. The expected output (not necessarily in the correct timezone) is shown in parentheses.', array('@format-admin' => '/admin/settings/date-time/formats')). '</dd>';
+      $output .= '<dt>' . t('Long date format') . '</dt>';
+      $output .= '<dd>' . t('The long date format that has been set on the <a href="@format-admin">date format configuration page</a>. The expected output (not necessarily in the correct timezone) is shown in parentheses.', array('@format-admin' => '/admin/settings/date-time/formats')). '</dd>';
+      $output .= '<dt>' . t('Custom date format') . '</dt>';
+      $output .= '<dd>' . t('This options will only show up, if there are <a href="@custom-formats">custom date formats</a>. A custom date format can be selected in the select box below the radio buttons.', array('@custom-formats' => '/admin/settings/date-time/formats/custom')) . '</dd>';
+      $output .= '</dl>';
+      $output .= '<dt>' . t('JavaScript updating') . '</dt>';
+      $output .= '<dd>' . t('Whether or not the clock should be updated continuously via JavaScript. This is especially useful if seconds are displayed. It only works if the visitor has JavaScript enabled.') . '</dd>';
+      $output .= '</dl>';
+      $output .= '</dl>';
+      return $output;
+  }
+}
+
+/**
+ * Implements hook_block_info().
  */
 function clock_block_info() {
   $blocks['clock'] = array(
@@ -13,15 +59,22 @@ function clock_block_info() {
   return $blocks;
 }
 
-/*
+/**
  * Implement hook_block_configure().
  */
 function clock_block_configure($delta = '') {
-  if ($delta == 'clock') {
+  if ($delta == 'clock') {
+
+    // Time zone options.
     $form['timezone'] = array(
       '#type' => 'radios',
       '#title' => t('Time zone settings'),
-      '#weight' => 1,
+      '#weight' => 1,
+      '#options' => array(
+        '1' => t('Site time zone'),
+        '3' => t('Local time zone'),
+        '4' => t('Custom time zone'),
+      ),
       '#default_value' => variable_get('clock_timezone_type', '1'),
     );
     // In case of user-configurable timezones show it as an option.
@@ -33,33 +86,25 @@ function clock_block_configure($delta = 
         '4' => t('Custom time zone'),
       );
     }
-    else {
-      $form['timezone']['#options'] = array(
-        '1' => t('Site time zone'),
-        '3' => t('Local time zone'),
-        '4' => t('Custom time zone'),
-      );
-    }
     $form['custom_timezone'] = array(
       '#type' => 'select',
       '#multiple' => FALSE,
       '#weight' => 2,
       '#default_value' => variable_get('clock_custom_timezone', 'UTC'),
       '#options' => date_timezone_names(),
-      // Hide the select list if "Custom time zone" is not selected.
-      // This does not seem to be working currently.
+      // Show the select list only if "Custom time zone" is selected.
       '#states' => array(
-        'invisible' => array(
-          'input[id="edit-timezone-4"]' => array('checked' => FALSE),
+        'visible' => array(
+          ':input[name="timezone"]' => array('value' => '4'),
         ),
       ),
     );
 
+    // Date format options.
     // Format the current time with each date type to display them in the form.
     $date_types = array();
     foreach(system_get_date_types() as $date_type => $info) {
-      $date_format = _clock_get_date_format($date_type);
-      $date_types[$date_type] = $info['title'] . ' (' . date_format_date(date_now(_clock_get_timezone()), $type = 'custom', $format = $date_format) . ')';
+      $date_types[$date_type] = $info['title'] . ' (' . date_format_date(date_now(_clock_get_timezone()), 'custom', clock_get_date_format($date_type)) . ')';
     }
     $form['date_format'] = array(
       '#type' => 'radios',
@@ -69,6 +114,7 @@ function clock_block_configure($delta = 
       '#options' => $date_types,
     );
 
+    // JavaScript options.
     $form['js'] = array(
       '#type' => 'checkbox',
       '#title' => t('Use JavaScript to continuously update the clock'),
@@ -80,8 +126,8 @@ function clock_block_configure($delta = 
   }
 }
 
-/*
- * Implement hook_block_save().
+/**
+ * Implements hook_block_save().
  */
 function clock_block_save($delta = '', $edit = array()) {
   if ($delta == 'clock') {
@@ -95,29 +141,32 @@ function clock_block_save($delta = '', $
   }
 }
 
-/*
- * Implement hook_block_view().
+/**
+ * Implements hook_block_view().
  */
 function clock_block_view($delta = '') {
   if ($delta == 'clock') {
     $block = array();
     $block['subject'] = 'Clock';
-    $block['content'] = theme_clock(variable_get('clock_timezone_type', '1'), _clock_get_timezone(), _clock_get_date_format(), variable_get('clock_js', '1'));
+    $block['content'] = theme_clock(clock_get_timezone(), clock_get_date_format(), variable_get('clock_js', '1'));
     return $block;
   }
 }
 
-/*
- * Get the correct timezone to display.
+/**
+ * Gets the correct timezone to display.
  *
- * @return The name of the timezone, NULL if the user's time zone is to be used or 'Local' is the user's local time is to be used.
+ * @return
+ *   The name of the timezone, NULL if the user's time zone is to be used or
+ *   'Local' is the user's local time is to be used.
  */
-function _clock_get_timezone() {
+function clock_get_timezone() {
   $clock_timezone_type = variable_get('clock_timezone_type', '1');
   switch ($clock_timezone_type) {
     // Site time zone
     case '1':
-    // If time zone is set to 'Local' and the user has JS disabled, show the site time zone.
+    // If time zone is set to 'Local' and the user has JS disabled, show the
+    // site time zone.
     case '3':
       $clock_timezone = variable_get('date_default_timezone_name', 'UTC');
       break;
@@ -133,34 +182,38 @@ function _clock_get_timezone() {
   return $clock_timezone;
 }
 
-/*
- * Get the correct date format.
+/**
+ * Gets the correct date format.
  *
- * @param $type (Optional) Specify the date format for a specific format type.
- *   If omitted, returns the date format for the format type used for the clock block.
+ * @param $type
+ *   (optional) The format type.
+ *
+ * @return
+ *   If $type was specified, the date format of the specified format type. If
+ *   $type is omitted, the date format of the format type used for the clock.
  */
-function _clock_get_date_format($type = FALSE) {
+function clock_get_date_format($type = FALSE) {
   if (!$type) {
     $type = variable_get('clock_date_format_type', 'long');
   }
   $date_format = variable_get('date_format_' . $type, '');
+  // If the date format has not been specifically set, load the default.
   if (!$date_format) {
     $date_format = array_shift(array_keys(system_get_date_formats($type)));
   }
   return $date_format;
 }
 
-/*
+/**
  * Implements hook_theme.
  */
 function clock_theme() {
   return array(
     'clock' => array(
-      'variables' => array(
-        'clock_timezone_type' => '1',
-        'clock_timezone' => 'UTC',
-        'clock_date_format' => 'short',
-        'clock_js' => '1',
+      'variables' => array(
+        'timezone' => 'UTC',
+        'date_format' => 'short',
+        'js' => '1',
       ),
     ),
   );
@@ -169,49 +222,41 @@ function clock_theme() {
 /*
  * Provide a default implementation of theme_clock().
  */
-function theme_clock($clock_timezone_type = '1', $clock_timezone = 'UTC', $clock_date_format = 'g:i a', $clock_js = '1') {
-  $output = '';
+function theme_clock($timezone, $date_format, $js) {
 
-  if ($clock_js == '1' || $clock_timezone_type == '3') {
-    // Create a timestamp.
-    $clock_timestamp = date_format_date(date_now($timezone = $clock_timezone), $type = 'custom', $format = 'U');
-
-    // Get the time zone offset in seconds.
-    $clock_timezone_offset_seconds = date_format_date(date_now($timezone = $clock_timezone), $type = 'custom', $format = 'Z');
-
-    // Get the name of the time zone, e.g. 'Europe/London'. 'Local' if the user's local time is to be displayed.
-    if ($clock_timezone_type == '3') {
-      $clock_timezone_name = 'Local';
-    }
-    else {
-      $clock_timezone_name = date_format_date(date_make_date($date = 'now', $timezone = $clock_timezone), $type = 'custom', $format = 'e');
-    }
+  if ($js == '1' || $timezone == 'Local') {
 
-    // Get Daylight Savings Time information. '1' for yes, '0' for no.
-    $clock_daylight_savings_time = date_format_date(date_now($timezone = $clock_timezone), $type = 'custom', $format = 'I');
+    // Load the jQuery Timers library and clock.js
+    drupal_add_js(libraries_get_path('jquerytimers') . '/jquery.timers.js');
+    drupal_add_js(drupal_get_path('module', 'clock') . '/clock.js');
 
+    // Create variables that are needed for the JavaScript time calculation.
+    // Create a time string.
+    $time = date_format_date(date_now($timezone), $type = 'custom', $format = 'F j, Y H:i:s');
+    // Get the time zone offset in seconds.
+    $offset_seconds = date_format_date(date_now($timezone), $type = 'custom', $format = 'Z');
+    // Get Daylight Savings Time information. '1' for yes, '0' for no.
+    $daylight_savings_time = date_format_date(date_now($timezone), $type = 'custom', $format = 'I');
     // Get the name of the offset, e.g. 'GMT'.
-    $clock_offset_name = date_format_date(date_now($timezone = $clock_timezone), $type = 'custom', $format = 'T');
+    $offset_name = date_format_date(date_now($timezone), $type = 'custom', $format = 'T');
 
-    // Pass the variables to JavaScript.
+    // Pass the variables to JavaScript.
     drupal_add_js(array(
-      '0' => $clock_js,
-      '1' => $clock_timestamp,
-      '2' => $clock_timezone_offset_seconds,
-      '3' => $clock_timezone_name,
-      '4' => $clock_daylight_savings_time,
-      '5' => $clock_offset_name,
-      '6' => $clock_date_format,
-    ), 'setting');
+      'time' => $time,
+      'date_format' => $date_format,
+      'timezone_name' => $timezone,
+      'offset_name' => $offset_name,
+      'offset_seconds' => $offset_seconds,
+      'daylight_savings_time' => $daylight_savings_time,
+      'js' => $js,
+    ), 'setting'); 
 
-    drupal_add_js(libraries_get_path('jquerytimers') . '/jquery.timers.js');
-    drupal_add_js(drupal_get_path('module', 'clock') . '/clock.js');
   }
 
   // Create a date object with the correct timezone and format it with the correct date format.
-  $clock_formatted = date_format_date(date_make_date($date = 'now', $timezone = $clock_timezone), $type = 'custom', $format = $clock_date_format);
+  $clock = date_format_date(date_now($timezone), 'custom', $date_format);
 
-  $output .= '<div class="clock">' . $clock_formatted . '</div>';
+  $output = '<div class="clock">' . $clock . '</div>';
 
   return $output;
 }
