diff --git a/js/jquery.cuteTime.js b/js/jquery.cuteTime.js
index dbd514e..2b40c07 100644
--- a/js/jquery.cuteTime.js
+++ b/js/jquery.cuteTime.js
@@ -1,702 +1,696 @@
-/******************************************************************************************************
-
- jQuery.cuteTime
-
- Author Jeremy Horn
- Version 1.1.3
- Date: 4/6/2010
-
- Copyright (c) 2009 Jeremy Horn- jeremydhorn(at)gmail(dot)c0m | http://tpgblog.com
- Dual licensed under MIT and GPL.
-
- DESCRIPTION
-
- It's CuteTime!
-
- CuteTime is a customizable jQuery plugin that automatically converts timestamps to
- formats much cuter. Also has the ability to dynamically re-update and/or
- automatically update timestamps on a controlled interval.
-
- If used by Selector, replaces the text of the provided object with a cuteTime.
- If used as a function, returns a string containing a cuteTime version of the provided
- timestamp.
-
- BY DEFAULT
- automatic updating is disabled and the following CuteTimes can be displayed...
-
- the future!
- just now
- a few seconds ago
- a minute ago
- x minutes ago
- an hour ago
- x hours ago
- yesterday
- x days ago
- last month
- x months ago
- last year
- x years ago
-
- IMPLEMENTATION
-
- $('.timestamp').cuteTime();
- $('.timestamp').cuteTime({ / * OPTIONS * / });
-
- cutetime_object = $('.timestamp').cuteTime();
- cutetime_object.update_cuteness();
-
- $.cuteTime('2009/10/12 22:11:19');
- $.cuteTime({ / * OPTIONS * / }, '2009/10/12 22:11:19');
-
- COMPATIBILITY
-
- Tested in FF3.5, IE7
- With jQuery 1.3.2
-
- METHODS
-
- When initialized the cuteTime variable either updates or assigns the TS_ATTR
- attribute to the provided objects. Method implementation supports chaining and
- returns jQuery object.
-
- e.g.
-
2009 10 12 22:11:19
-
- If the cutetime attribute already exists within the provided object, then the
- text within the object is ignored in the cutification process. If the cutetime attribute
- does not exist or an invalid one is provided, then a valid cutetime attribute is assigned
- to the object.
-
- If the cutetime attribute is missing, then it is calculated from the text of the
- provided object.
-
- If neither cutetime attibute nor valid object text exist then the timestamp is assumed
- to by 'now'.
-
- stop_cuteness()
- stops all automatic updates of refresh enabled timestamps
-
- start_cuteness()
- starts the automatic updating of timestamps
- REMINDER: make sure refresh is set to > 0
-
- update_cuteness()
- updates timestamps of the provided objects
-
- FUNCTIONS
-
- cuteTime()
-
- CUSTOMIZATION
-
- cuteTime(OPTIONS)
- e.g. $('.ts2').cuteTime({ refresh: 60000 });
-
- refresh: time in milliseconds before next refresh of page data; -1 == no refresh
- time_ranges: array of bound_structures definining the cute descriptions associated with
- time ranges
-
- bound_structures consist of the following variables
- bound: lower inclusive bound, or starting point, for using the 'cuteness' string
- for describing the current timestamp
-
- the exclusive upper bound is defined by the next bound definition in the
- time_ranges array
-
- cuteness: string to use in place of the current timestamp
-
- the special keyword %CT% can be used within the cutetime string to
- override the prepending of the calculated difference, when called for
-
- e.g. "it was %CT% hours ago"
-
- unit_size: the divisor to apply to the calculated time difference; if unit_size > 0
- then a number value is prepended to the cuteness string as calculated by
- time_difference / unit_size
- e.g. 4 hours ago
-
- if unit_size = 0, then no number is pre-pended to the cuteness string
- e.g. an hour ago
-
- EXAMPLE OPTIONS =
- { refresh: -1,
- time_ranges: [
- {bound: NEG_INF,
- cuteness: 'the future!', unit_size: 0},
- {bound: 0,
- cuteness: 'just now', unit_size: 0},
- {bound: 60 * 1000,
- cuteness: 'a minute ago', unit_size: 0},
- {bound: 60 * 1000 * 2,
- cuteness: ' minutes ago', unit_size: 60 * 1000},
- {bound: 60 * 1000 * 60,
- cuteness: 'an hour ago', unit_size: 0},
- {bound: 60 * 1000 * 60 * 2,
- cuteness: ' hours ago', unit_size: 60 * 1000 * 60},
- {bound: POS_INF,
- cuteness: 'a blinkle ago', unit_size: 0}
- ]
- };
-
-
- VALID TIMESTAMP FORMAT EXAMPLES
-
- 2009-10-15 14:06:23 *doesn't work in IE
- Thu Oct 15 2009 22:11:19 GMT-0400 (Eastern Daylight Time
- Oct 15 2009 22:11:19
- 2009 10 12 22:11:19 * only works in FF
- 10 15 2009 22:11:19 * only works in FF
-
- ALL ISO8601 Date/Time Formats Also Supported
- 2009-11-24T19:20:30+01:00
- 2009-11
- 2009-11-24T13:15:30Z
- ...etc...
-
- * if the TIMESTAMP can be recognized by the JavaScript Date() Object then it is VALID
- (i.e. if it can be parsed by Date.parse())
- ** IE date parsing is VERY DIFFERENT (and more limiting) than FF :-( [not cute!]
-
- MORE
-
- For more usage and examples, go to:
- http://tpgblog.com/cutetime/
-
-******************************************************************************************************/
-
-(function($) {
- // CONSTANTS
- var NEG_INF = Number.NEGATIVE_INFINITY;
- var POS_INF = Number.POSITIVE_INFINITY;
- var TS_ATTR = 'data-timestamp';
-
- /**********************************************************************************
-
- FUNCTION
- cuteTime
-
- DESCRIPTION
- cuteTime method constructor
-
- allows for customization of refreh rate the time difference ranges and
- cute descriptions
-
- e.g. $(something).cuteTime();
-
- **********************************************************************************/
- $.fn.cuteTime = function(options) {
- var right_now = new Date().getTime();
- var other_time;
- var curr_this;
-
- // check for new & valid options
- if ((typeof options == 'object') || (options == undefined)) {
- // then update the settings [destructive]
- $.fn.cuteTime.c_settings = $.extend({}, $.fn.cuteTime.settings, options);
- $.fn.cuteTime.the_selected = this;
-
- // process all provided objects
- this.each(function() {
- // element-specific code here
- curr_this = $(this);
- other_time = get_time_value(curr_this);
- curr_this.html(get_cuteness(right_now - other_time));
- });
-
- // check for and conditionally launch the automatic refreshing of timestamps
- $.fn.cuteTime.start_cuteness();
- }
-
- return this;
- };
-
- /**********************************************************************************
-
- FUNCTION
- cuteTime
-
- DESCRIPTION
- cuteTime function
-
- accepts a string representation of a timestamp as its parameter and
- returns a string version of its equivalent cutetime
-
- e.g. $.cuteTime('2009 10 12 22:11:19');
-
- or
-
- e.g. $.cuteTime(SETTINGS, '2009 10 12 22:11:19');
-
- can be customized by directly accessing the settings:
- $.fn.cuteTime.settings = ...
-
- **********************************************************************************/
- $.cuteTime = function(options, val) {
- var right_now = new Date().getTime();
- var other_time;
- var curr_this;
- var ts_string = null;
-
- if (typeof options == 'object') {
- $.fn.cuteTime.c_settings = $.extend({}, $.fn.cuteTime.settings, options);
- }
-
- if (typeof options == 'string') {
- ts_string = options;
- } else if (typeof val == 'string') {
- ts_string = val;
- }
-
- if (ts_string != null) {
- // then we will be returning a cutetime string and doing nothing else
- other_time = date_value(ts_string);
- if (!isNaN(other_time)) {
- return get_cuteness(right_now - other_time);
- } else {
- // on failure return error message
- return 'INVALID_DATETIME_FORMAT';
- }
- }
-
- return this;
- };
-
-
- /**********************************************************************************
-
- FUNCTION
- cuteTime.settings
-
- DESCRIPTION
- data stucture containing the refresh rate and time range specifications
- for the cuteTimes
-
- can be directly accessed by '$.fn.cuteTime.settings = ... ;'
-
- **********************************************************************************/
- $.fn.cuteTime.settings = {
- refresh: -1, // time in milliseconds before next refresh of page data; -1 == no refresh
- time_ranges: [
- {bound: NEG_INF, // IMPORANT: bounds MUST be in ascending order, from negative infinity to positive infinity
- cuteness: 'the future!', unit_size: 0},
- {bound: 0,
- cuteness: 'just now', unit_size: 0},
- {bound: 20 * 1000,
- cuteness: 'a few seconds ago', unit_size: 0},
- {bound: 60 * 1000,
- cuteness: 'a minute ago', unit_size: 0},
- {bound: 60 * 1000 * 2,
- cuteness: ' minutes ago', unit_size: 60 * 1000},
- {bound: 60 * 1000 * 60,
- cuteness: 'an hour ago', unit_size: 0},
- {bound: 60 * 1000 * 60 * 2,
- cuteness: ' hours ago', unit_size: 60 * 1000 * 60},
- {bound: 60 * 1000 * 60 * 24,
- cuteness: 'yesterday', unit_size: 0},
- {bound: 60 * 1000 * 60 * 24 * 2,
- cuteness: ' days ago', unit_size: 60 * 1000 * 60 * 24},
- {bound: 60 * 1000 * 60 * 24 * 30,
- cuteness: 'last month', unit_size: 0},
- {bound: 60 * 1000 * 60 * 24 * 30 * 2,
- cuteness: ' months ago', unit_size: 60 * 1000 * 60 * 24 * 30},
- {bound: 60 * 1000 * 60 * 24 * 30 * 12,
- cuteness: 'last year', unit_size: 0},
- {bound: 60 * 1000 * 60 * 24 * 30 * 12 * 2,
- cuteness: ' years ago', unit_size: 60 * 1000 * 60 * 24 * 30 * 12},
- {bound: POS_INF,
- cuteness: 'a blinkle ago', unit_size: 0}
- ]
- };
-
-
- /**********************************************************************************
-
- FUNCTION
- cuteTime.start_cuteness
-
- DESCRIPTION
- activates the recurring process to update the objects' timestamps
-
- IMPORTANT: make sure refresh has been set to > 0
-
- TODO
- allow for the specifying of a new refresh rate when this function is called
-
- **********************************************************************************/
- $.fn.cuteTime.start_cuteness = function() {
- var refresh_rate = $.fn.cuteTime.c_settings.refresh;
-
- if ($.fn.cuteTime.process_tracker == null) {
- if (refresh_rate > 0) {
- $.fn.cuteTime.process_tracker = setInterval( "$.fn.cuteTime.update_cuteness()", refresh_rate );
- }
- } else {
- // ignore this call; auto-refresh is already running!!
- }
- return this;
- };
-
-
- /**********************************************************************************
-
- FUNCTION
- cuteTime.update_cuteness
-
- DESCRIPTION
- updates the objects' timestamps
-
- **********************************************************************************/
- $.fn.cuteTime.update_cuteness = function() {
- var right_now = new Date().getTime();
- var curr_this;
- var other_time;
-
- $.fn.cuteTime.the_selected.each(function() {
- curr_this = $(this);
- other_time = get_time_value(curr_this);
- curr_this.html(get_cuteness(right_now - other_time));
- });
- }
-
-
- /**********************************************************************************
-
- FUNCTION
- cuteTime.stop_cuteness
-
- DESCRIPTION
- deactivates the recurring process that updates the objects' timestamps
-
- **********************************************************************************/
- $.fn.cuteTime.stop_cuteness = function() {
- if ($.fn.cuteTime.process_tracker != null) {
- clearInterval($.fn.cuteTime.process_tracker);
- $.fn.cuteTime.process_tracker = null;
- } else {
- // ignore this call; there is nothing to stop!!
- }
-
- return this;
- };
-
-
- //////////////////////////////////////////////////////////////////////////////////
-
- // private functions and settings
-
- /**********************************************************************************
-
- FUNCTION
- get_cuteness
-
- DESCRIPTION
- based on passed in time_difference (in milliseconds) returns a string
- of the associated cuteness
-
- if a number should be insterted into the string (unit_size not empty)
- THEN
- if %CT% exists within the cuteness STRING
- THEN replace it with the calculated number
- ELSE prepend the calculated number to the front of the string
- (mostly for backwards compatibility)
-
- ON ERROR returns time in 'pookies'
-
- **********************************************************************************/
- function get_cuteness(time_difference) {
- var time_ranges = $.fn.cuteTime.c_settings.time_ranges;
- var pre_calculated_time, calculated_time;
- var cute_time = '';
-
- jQuery.each(time_ranges, function(i, timespan) {
- if (i < time_ranges.length-1) {
- if (( time_difference >= timespan['bound']) &&
- ( time_difference < time_ranges[i+1]['bound'])) {
- if (timespan['unit_size'] > 0) {
- calculated_time = Math.floor(time_difference / timespan['unit_size']);
- } else {
- calculated_time = '';
- }
-
- // allow for inline replacement
- pre_calculated_time = timespan['cuteness'].replace(/%CT%/, calculated_time);
-
- if (pre_calculated_time == timespan['cuteness']) {
- // nothing was replaced
- // prepend the value
- cute_time = calculated_time + timespan['cuteness'];
-
- } else {
- // inline replacement occurred
- cute_time = pre_calculated_time;
- }
-
- return false;
- }
- } else {
- return false;
- }
- });
-
- // something is wrong with the time
- if (cute_time == '') {
- cute_time = '2 pookies ago'; // IMPORTANT: ALWAYS BE CUTE!!!
- }
-
- return cute_time;
- }
-
-
- /**********************************************************************************
-
- FUNCTION
- date_value
-
- DESCRIPTION
- returns the date in time measured since 1970 (see definition of Date.valueOf)
-
- if not ISO 8601 date format compliant, performs minimal date correction
- to expand the range of VALID date formats
-
- **********************************************************************************/
- function date_value(the_date) {
-
- var the_value;
-
- if ((new_date = toISO8601(the_date)) != null) {
- the_value = new_date.valueOf();
- } else {
-
- the_value = (new Date(the_date)).valueOf();
-
- if (isNaN(the_value)) {
- // then the date must be the alternate db styled format
- the_value = new Date(the_date.replace(/-/g, " "));
- }
- }
- return the_value;
- }
-
-
- /**********************************************************************************
-
- FUNCTION
- toISO8601
-
- DESCRIPTION
- converts an ISO8601 formatted timestamp to the JavaScript Date() Object
- if the provided string is not in ISO8601 format, then null is returned
-
- ** Note to people who copy this function: If you like it, if you use it,
- please provide credit to Jeremy Horn, The Product Guy @ http://tpgblog.com
- and the jQuery CuteTime Plugin @ http://tpgblog.com/cutetime; Thanks. :-)
-
- ISO8601
- http://www.w3.org/TR/NOTE-datetime
-
- Year:
- YYYY (eg 1997)
- Year and month:
- YYYY-MM (eg 1997-07)
- Complete date:
- YYYY-MM-DD (eg 1997-07-16)
- Complete date plus hours and minutes:
- YYYY-MM-DDThh:mmTZD (eg 1997-07-16T19:20+01:00)
- Complete date plus hours, minutes and seconds:
- YYYY-MM-DDThh:mm:ssTZD (eg 1997-07-16T19:20:30+01:00)
- Complete date plus hours, minutes, seconds and a decimal fraction of a second
- YYYY-MM-DDThh:mm:ss.sTZD (eg 1997-07-16T19:20:30.45+01:00)
-
- Formatted REGEXP used within...
-
- /^(\d{4})(
- (-(\d{2})
- (-(\d{2})
- (T(\d{2}):(\d{2})
- (:(\d{2})
- (.(\d+))?
- )?
- (Z|(
- ([+-])((\d{2}):(\d{2}))
- ))
- )?
- )?
- )?
- )$/
-
- NOTE
- String.match() returns:
- in FireFox, void(0)
- in Internet Explorer, "" <-- empty string
- ... for unmatched elements within the array
-
- **********************************************************************************/
- function toISO8601(the_date){
-
- var iso_date = the_date.match(/^(\d{4})((-(\d{2})(-(\d{2})(T(\d{2}):(\d{2})(:(\d{2})(.(\d+))?)?(Z|(([+-])((\d{2}):(\d{2})))))?)?)?)$/);
-
- if (iso_date != null) {
- var new_date = new Date();
- var TZ_hour_offset = 0;
- var TZ_minute_offset = 0;
-
- new_date.setUTCFullYear(iso_date[1]);
- if (!isEmpty(iso_date[4])) {
- new_date.setUTCMonth(iso_date[4] - 1);
- if (!isEmpty(iso_date[6])) {
- new_date.setUTCDate(iso_date[6]);
-
- // check TZ first
- if (!isEmpty(iso_date[16])) {
- TZ_hour_offset = iso_date[18];
- TZ_minute_offset = iso_date[19];
-
- if (iso_date[16] == '-') { // is the time offset negative ?
- TZ_hour_offset *= -1;
- TZ_minute_offset *= -1;
- } // otherwise: timeoffset is positive & do nothing
- }
-
- if (!isEmpty(iso_date[8])) {
- new_date.setUTCHours(iso_date[8] - TZ_hour_offset);
- new_date.setUTCMinutes(iso_date[9] - TZ_minute_offset)
- if (!isEmpty(iso_date[11])) {
- new_date.setUTCSeconds(iso_date[11]);
- if (!isEmpty(iso_date[13])) {
- new_date.setUTCMilliseconds(iso_date[13]*1000);
- }
- }
- }
-
- }
- }
-
- return new_date;
- } else {
- return null;
- }
- }
-
-
- /**********************************************************************************
-
- FUNCTION
- isEmpty
-
- DESCRIPTION
- determines whether or not the passed in string is EMPTY
-
- EMPTY = null OR "" {EMPTY STRING}
-
- **********************************************************************************/
- function isEmpty( inputStr ) {
- if ( null == inputStr || "" == inputStr ) {
- return true;
- }
-
- return false;
- }
-
- /**********************************************************************************
-
- FUNCTION
- get_time_value
-
- DESCRIPTION
- get the time value specified either in the text or the cuteime attribute
- of the object and update the cutetime attribute whether initially present
- or not
-
- If the cutetime attribute already exists within the provided object,
- then the text within the object is ignored in the cutification
- process. If the cutetime attribute does not exist or an invalid one
- is provided, then a valid cutetime attribute is assigned to the object.
-
- If the cutetime attribute is missing, then it is calculated from the text
- of the provided object.
-
- If neither cutetime attibute nor valid object text exist then the
- timestamp is assumed to by 'now'.
-
- **********************************************************************************/
- function get_time_value(obj) {
- var time_value = Number.NaN;
-
- var time_string = get_cutetime_attr(obj); // returns string or NULL
- if (time_string != null) {
- time_value = date_value(time_string);
- }
-
- if (isNaN(time_value)) {
- time_string = get_object_text(obj);
- if (time_string != null) {
- time_value = date_value(time_string);
- }
- }
-
- // if nothing valid available then set time to RIGHT NOW
- if (isNaN(time_value)) {
- time_string = new Date().toString();
- time_value = date_value(time_string);
- }
-
- // update cutetime attribute and return the time_value
- set_cutetime_attr(time_string, obj);
- return time_value;
- }
-
-
- /**********************************************************************************
-
- FUNCTION
- get_cutetime_attr
-
- DESCRIPTION
- returns the found value of the cutetime attribute of the specified object
- or NULL
-
- **********************************************************************************/
- function get_cutetime_attr(obj) {
- var return_value = obj.attr(TS_ATTR);
-
- if (return_value != undefined) {
- return return_value;
- } else {
- return null;
- }
- }
-
-
- /**********************************************************************************
-
- FUNCTION
- set_cutetime_attr
-
- DESCRIPTION
- sets / updates the cutetime attribute of the object
-
- the cuteime attribute is set to be STARTING point against which all
- future updates are measured against
-
- **********************************************************************************/
- function set_cutetime_attr(attr, obj) {
- // assume valid attr(ibute) value
- obj.attr(TS_ATTR, attr);
- }
-
-
- /**********************************************************************************
-
- FUNCTION
- get_object_text
-
- DESCRIPTION
- returns the text associated with the specified object (if any)
-
- **********************************************************************************/
- function get_object_text(obj) {
- return obj.text();
- }
-
-})(jQuery);
+/******************************************************************************************************
+
+ jQuery.cuteTime
+
+ Author Jeremy Horn
+ Version 1.1.3
+ Date: 4/6/2010
+
+ Copyright (c) 2009 Jeremy Horn- jeremydhorn(at)gmail(dot)c0m | http://tpgblog.com
+ Dual licensed under MIT and GPL.
+
+ DESCRIPTION
+
+ It's CuteTime!
+
+ CuteTime is a customizable jQuery plugin that automatically converts timestamps to
+ formats much cuter. Also has the ability to dynamically re-update and/or
+ automatically update timestamps on a controlled interval.
+
+ If used by Selector, replaces the text of the provided object with a cuteTime.
+ If used as a function, returns a string containing a cuteTime version of the provided
+ timestamp.
+
+ BY DEFAULT
+ automatic updating is disabled and the following CuteTimes can be displayed...
+
+ the future!
+ just now
+ a few seconds ago
+ a minute ago
+ x minutes ago
+ an hour ago
+ x hours ago
+ yesterday
+ x days ago
+ last month
+ x months ago
+ last year
+ x years ago
+
+ IMPLEMENTATION
+
+ $('.timestamp').cuteTime();
+ $('.timestamp').cuteTime({ / * OPTIONS * / });
+
+ cutetime_object = $('.timestamp').cuteTime();
+ cutetime_object.update_cuteness();
+
+ $.cuteTime('2009/10/12 22:11:19');
+ $.cuteTime({ / * OPTIONS * / }, '2009/10/12 22:11:19');
+
+ COMPATIBILITY
+
+ Tested in FF3.5, IE7
+ With jQuery 1.3.2
+
+ METHODS
+
+ When initialized the cuteTime variable either updates or assigns the TS_ATTR
+ attribute to the provided objects. Method implementation supports chaining and
+ returns jQuery object.
+
+ e.g.
+ 2009 10 12 22:11:19
+
+ If the cutetime attribute already exists within the provided object, then the
+ text within the object is ignored in the cutification process. If the cutetime attribute
+ does not exist or an invalid one is provided, then a valid cutetime attribute is assigned
+ to the object.
+
+ If the cutetime attribute is missing, then it is calculated from the text of the
+ provided object.
+
+ If neither cutetime attibute nor valid object text exist then the timestamp is assumed
+ to by 'now'.
+
+ stop_cuteness()
+ stops all automatic updates of refresh enabled timestamps
+
+ start_cuteness()
+ starts the automatic updating of timestamps
+ REMINDER: make sure refresh is set to > 0
+
+ update_cuteness()
+ updates timestamps of the provided objects
+
+ FUNCTIONS
+
+ cuteTime()
+
+ CUSTOMIZATION
+
+ cuteTime(OPTIONS)
+ e.g. $('.ts2').cuteTime({ refresh: 60000 });
+
+ refresh: time in milliseconds before next refresh of page data; -1 == no refresh
+ time_ranges: array of bound_structures definining the cute descriptions associated with
+ time ranges
+
+ bound_structures consist of the following variables
+ bound: lower inclusive bound, or starting point, for using the 'cuteness' string
+ for describing the current timestamp
+
+ the exclusive upper bound is defined by the next bound definition in the
+ time_ranges array
+
+ cuteness: string to use in place of the current timestamp
+
+ the special keyword %CT% can be used within the cutetime string to
+ override the prepending of the calculated difference, when called for
+
+ e.g. "it was %CT% hours ago"
+
+ unit_size: the divisor to apply to the calculated time difference; if unit_size > 0
+ then a number value is prepended to the cuteness string as calculated by
+ time_difference / unit_size
+ e.g. 4 hours ago
+
+ if unit_size = 0, then no number is pre-pended to the cuteness string
+ e.g. an hour ago
+
+ EXAMPLE OPTIONS =
+ { refresh: -1,
+ time_ranges: [
+ {bound: NEG_INF,
+ cuteness: 'the future!', unit_size: 0},
+ {bound: 0,
+ cuteness: 'just now', unit_size: 0},
+ {bound: 60 * 1000,
+ cuteness: 'a minute ago', unit_size: 0},
+ {bound: 60 * 1000 * 2,
+ cuteness: ' minutes ago', unit_size: 60 * 1000},
+ {bound: 60 * 1000 * 60,
+ cuteness: 'an hour ago', unit_size: 0},
+ {bound: 60 * 1000 * 60 * 2,
+ cuteness: ' hours ago', unit_size: 60 * 1000 * 60},
+ {bound: POS_INF,
+ cuteness: 'a blinkle ago', unit_size: 0}
+ ]
+ };
+
+
+ VALID TIMESTAMP FORMAT EXAMPLES
+
+ 2009-10-15 14:06:23 *doesn't work in IE
+ Thu Oct 15 2009 22:11:19 GMT-0400 (Eastern Daylight Time
+ Oct 15 2009 22:11:19
+ 2009 10 12 22:11:19 * only works in FF
+ 10 15 2009 22:11:19 * only works in FF
+
+ ALL ISO8601 Date/Time Formats Also Supported
+ 2009-11-24T19:20:30+01:00
+ 2009-11
+ 2009-11-24T13:15:30Z
+ ...etc...
+
+ * if the TIMESTAMP can be recognized by the JavaScript Date() Object then it is VALID
+ (i.e. if it can be parsed by Date.parse())
+ ** IE date parsing is VERY DIFFERENT (and more limiting) than FF :-( [not cute!]
+
+ MORE
+
+ For more usage and examples, go to:
+ http://tpgblog.com/cutetime/
+
+******************************************************************************************************/
+
+(function($) {
+ // CONSTANTS
+ var NEG_INF = Number.NEGATIVE_INFINITY;
+ var POS_INF = Number.POSITIVE_INFINITY;
+ var TS_ATTR = 'data-timestamp';
+
+ /**********************************************************************************
+
+ FUNCTION
+ cuteTime
+
+ DESCRIPTION
+ cuteTime method constructor
+
+ allows for customization of refreh rate the time difference ranges and
+ cute descriptions
+
+ e.g. $(something).cuteTime();
+
+ **********************************************************************************/
+ $.fn.cuteTime = function(options) {
+ var right_now = new Date().getTime();
+ var other_time;
+ var curr_this;
+
+ // check for new & valid options
+ if ((typeof options == 'object') || (options === undefined)) {
+ // then update the settings [destructive]
+ $.fn.cuteTime.c_settings = $.extend({}, $.fn.cuteTime.settings, options);
+ $.fn.cuteTime.the_selected = this;
+
+ // process all provided objects
+ this.each(function() {
+ // element-specific code here
+ curr_this = $(this);
+ other_time = get_time_value(curr_this);
+ curr_this.html(get_cuteness(right_now - other_time));
+ });
+
+ // check for and conditionally launch the automatic refreshing of timestamps
+ $.fn.cuteTime.start_cuteness();
+ }
+
+ return this;
+ };
+
+ /**********************************************************************************
+
+ FUNCTION
+ cuteTime
+
+ DESCRIPTION
+ cuteTime function
+
+ accepts a string representation of a timestamp as its parameter and
+ returns a string version of its equivalent cutetime
+
+ e.g. $.cuteTime('2009 10 12 22:11:19');
+
+ or
+
+ e.g. $.cuteTime(SETTINGS, '2009 10 12 22:11:19');
+
+ can be customized by directly accessing the settings:
+ $.fn.cuteTime.settings = ...
+
+ **********************************************************************************/
+ $.cuteTime = function(options, val) {
+ var right_now = new Date().getTime();
+ var other_time;
+ var ts_string = null;
+
+ if (typeof options == 'object') {
+ $.fn.cuteTime.c_settings = $.extend({}, $.fn.cuteTime.settings, options);
+ }
+
+ if (typeof options == 'string') {
+ ts_string = options;
+ } else if (typeof val == 'string') {
+ ts_string = val;
+ }
+
+ if (ts_string !== null) {
+ // then we will be returning a cutetime string and doing nothing else
+ other_time = date_value(ts_string);
+ if (!isNaN(other_time)) {
+ return get_cuteness(right_now - other_time);
+ } else {
+ // on failure return error message
+ return 'INVALID_DATETIME_FORMAT';
+ }
+ }
+
+ return this;
+ };
+
+
+ /**********************************************************************************
+
+ FUNCTION
+ cuteTime.settings
+
+ DESCRIPTION
+ data stucture containing the refresh rate and time range specifications
+ for the cuteTimes
+
+ can be directly accessed by '$.fn.cuteTime.settings = ... ;'
+
+ **********************************************************************************/
+ $.fn.cuteTime.settings = {
+ refresh: -1, // time in milliseconds before next refresh of page data; -1 == no refresh
+ time_ranges: [
+ {bound: NEG_INF, // IMPORANT: bounds MUST be in ascending order, from negative infinity to positive infinity
+ cuteness: 'the future!', unit_size: 0},
+ {bound: 0,
+ cuteness: 'just now', unit_size: 0},
+ {bound: 20 * 1000,
+ cuteness: 'a few seconds ago', unit_size: 0},
+ {bound: 60 * 1000,
+ cuteness: 'a minute ago', unit_size: 0},
+ {bound: 60 * 1000 * 2,
+ cuteness: ' minutes ago', unit_size: 60 * 1000},
+ {bound: 60 * 1000 * 60,
+ cuteness: 'an hour ago', unit_size: 0},
+ {bound: 60 * 1000 * 60 * 2,
+ cuteness: ' hours ago', unit_size: 60 * 1000 * 60},
+ {bound: 60 * 1000 * 60 * 24,
+ cuteness: 'yesterday', unit_size: 0},
+ {bound: 60 * 1000 * 60 * 24 * 2,
+ cuteness: ' days ago', unit_size: 60 * 1000 * 60 * 24},
+ {bound: 60 * 1000 * 60 * 24 * 30,
+ cuteness: 'last month', unit_size: 0},
+ {bound: 60 * 1000 * 60 * 24 * 30 * 2,
+ cuteness: ' months ago', unit_size: 60 * 1000 * 60 * 24 * 30},
+ {bound: 60 * 1000 * 60 * 24 * 30 * 12,
+ cuteness: 'last year', unit_size: 0},
+ {bound: 60 * 1000 * 60 * 24 * 30 * 12 * 2,
+ cuteness: ' years ago', unit_size: 60 * 1000 * 60 * 24 * 30 * 12},
+ {bound: POS_INF,
+ cuteness: 'a blinkle ago', unit_size: 0}
+ ]
+ };
+
+
+ /**********************************************************************************
+
+ FUNCTION
+ cuteTime.start_cuteness
+
+ DESCRIPTION
+ Activates or updates repeatedly processing the objects' timestamps.
+
+ The minimum refresh rate is one second. Nobody needs more than that.
+
+ **********************************************************************************/
+ $.fn.cuteTime.start_cuteness = function(opt_refresh) {
+ var refresh_rate = $.fn.cuteTime.c_settings.refresh;
+ if (opt_refresh !== undefined)
+ refresh_rate = opt_refresh;
+
+ if (refresh_rate < 1000)
+ refresh_rate = 1000;
+
+ clearInterval($.fn.cuteTime.process_tracker);
+ $.fn.cuteTime.process_tracker = setInterval(
+ $.proxy($.fn.cuteTime.update_cuteness, this),
+ refresh_rate);
+ return this;
+ };
+
+
+ /**********************************************************************************
+
+ FUNCTION
+ cuteTime.update_cuteness
+
+ DESCRIPTION
+ updates the objects' timestamps
+
+ **********************************************************************************/
+ $.fn.cuteTime.update_cuteness = function() {
+ var right_now = new Date().getTime();
+ var curr_this;
+ var other_time;
+
+ $.fn.cuteTime.the_selected.each(function() {
+ curr_this = $(this);
+ other_time = get_time_value(curr_this);
+ curr_this.html(get_cuteness(right_now - other_time));
+ });
+ };
+
+
+ /**********************************************************************************
+
+ FUNCTION
+ cuteTime.stop_cuteness
+
+ DESCRIPTION
+ deactivates the recurring process that updates the objects' timestamps
+
+ **********************************************************************************/
+ $.fn.cuteTime.stop_cuteness = function() {
+ clearInterval($.fn.cuteTime.process_tracker);
+ $.fn.cuteTime.process_tracker = null;
+
+ return this;
+ };
+
+
+ //////////////////////////////////////////////////////////////////////////////////
+
+ // private functions and settings
+
+ /**********************************************************************************
+
+ FUNCTION
+ get_cuteness
+
+ DESCRIPTION
+ based on passed in time_difference (in milliseconds) returns a string
+ of the associated cuteness
+
+ if a number should be insterted into the string (unit_size not empty)
+ THEN
+ if %CT% exists within the cuteness STRING
+ THEN replace it with the calculated number
+ ELSE prepend the calculated number to the front of the string
+ (mostly for backwards compatibility)
+
+ ON ERROR returns time in 'pookies'
+
+ **********************************************************************************/
+ function get_cuteness(time_difference) {
+ var time_ranges = $.fn.cuteTime.c_settings.time_ranges;
+ var pre_calculated_time, calculated_time;
+ var cute_time = '';
+
+ jQuery.each(time_ranges, function(i, timespan) {
+ if (i < time_ranges.length-1) {
+ if (( time_difference >= timespan.bound) &&
+ ( time_difference < time_ranges[i+1].bound)) {
+ if (timespan.unit_size > 0) {
+ calculated_time = Math.floor(time_difference / timespan.unit_size);
+ } else {
+ calculated_time = '';
+ }
+
+ // allow for inline replacement
+ pre_calculated_time = timespan.cuteness.replace(/%CT%/, calculated_time);
+
+ if (pre_calculated_time == timespan.cuteness) {
+ // nothing was replaced
+ // prepend the value
+ cute_time = calculated_time + timespan.cuteness;
+
+ } else {
+ // inline replacement occurred
+ cute_time = pre_calculated_time;
+ }
+
+ return false;
+ }
+ } else {
+ return false;
+ }
+ });
+
+ // something is wrong with the time
+ if (cute_time === '') {
+ cute_time = '2 pookies ago'; // IMPORTANT: ALWAYS BE CUTE!!!
+ }
+
+ return cute_time;
+ }
+
+
+ /**********************************************************************************
+
+ FUNCTION
+ date_value
+
+ DESCRIPTION
+ returns the date in time measured since 1970 (see definition of Date.valueOf)
+
+ if not ISO 8601 date format compliant, performs minimal date correction
+ to expand the range of VALID date formats
+
+ **********************************************************************************/
+ function date_value(the_date) {
+
+ var the_value;
+ var new_date = toISO8601(the_date);
+ if (new_date !== null) {
+ the_value = new_date.valueOf();
+ } else {
+
+ the_value = (new Date(the_date)).valueOf();
+
+ if (isNaN(the_value)) {
+ // then the date must be the alternate db styled format
+ the_value = new Date(the_date.replace(/-/g, " "));
+ }
+ }
+ return the_value;
+ }
+
+
+ /**********************************************************************************
+
+ FUNCTION
+ toISO8601
+
+ DESCRIPTION
+ converts an ISO8601 formatted timestamp to the JavaScript Date() Object
+ if the provided string is not in ISO8601 format, then null is returned
+
+ ** Note to people who copy this function: If you like it, if you use it,
+ please provide credit to Jeremy Horn, The Product Guy @ http://tpgblog.com
+ and the jQuery CuteTime Plugin @ http://tpgblog.com/cutetime; Thanks. :-)
+
+ ISO8601
+ http://www.w3.org/TR/NOTE-datetime
+
+ Year:
+ YYYY (eg 1997)
+ Year and month:
+ YYYY-MM (eg 1997-07)
+ Complete date:
+ YYYY-MM-DD (eg 1997-07-16)
+ Complete date plus hours and minutes:
+ YYYY-MM-DDThh:mmTZD (eg 1997-07-16T19:20+01:00)
+ Complete date plus hours, minutes and seconds:
+ YYYY-MM-DDThh:mm:ssTZD (eg 1997-07-16T19:20:30+01:00)
+ Complete date plus hours, minutes, seconds and a decimal fraction of a second
+ YYYY-MM-DDThh:mm:ss.sTZD (eg 1997-07-16T19:20:30.45+01:00)
+
+ Formatted REGEXP used within...
+
+ /^(\d{4})(
+ (-(\d{2})
+ (-(\d{2})
+ (T(\d{2}):(\d{2})
+ (:(\d{2})
+ (.(\d+))?
+ )?
+ (Z|(
+ ([+-])((\d{2}):(\d{2}))
+ ))
+ )?
+ )?
+ )?
+ )$/
+
+ NOTE
+ String.match() returns:
+ in FireFox, void(0)
+ in Internet Explorer, "" <-- empty string
+ ... for unmatched elements within the array
+
+ **********************************************************************************/
+ function toISO8601(the_date){
+
+ var iso_date = the_date.match(/^(\d{4})((-(\d{2})(-(\d{2})(T(\d{2}):(\d{2})(:(\d{2})(.(\d+))?)?(Z|(([+-])((\d{2}):(\d{2})))))?)?)?)$/);
+
+ if (iso_date !== null) {
+ var new_date = new Date();
+ var TZ_hour_offset = 0;
+ var TZ_minute_offset = 0;
+
+ new_date.setUTCFullYear(iso_date[1]);
+ if (!isEmpty(iso_date[4])) {
+ new_date.setUTCMonth(iso_date[4] - 1);
+ if (!isEmpty(iso_date[6])) {
+ new_date.setUTCDate(iso_date[6]);
+
+ // check TZ first
+ if (!isEmpty(iso_date[16])) {
+ TZ_hour_offset = iso_date[18];
+ TZ_minute_offset = iso_date[19];
+
+ if (iso_date[16] == '-') { // is the time offset negative ?
+ TZ_hour_offset *= -1;
+ TZ_minute_offset *= -1;
+ } // otherwise: timeoffset is positive & do nothing
+ }
+
+ if (!isEmpty(iso_date[8])) {
+ new_date.setUTCHours(iso_date[8] - TZ_hour_offset);
+ new_date.setUTCMinutes(iso_date[9] - TZ_minute_offset);
+ if (!isEmpty(iso_date[11])) {
+ new_date.setUTCSeconds(iso_date[11]);
+ if (!isEmpty(iso_date[13])) {
+ new_date.setUTCMilliseconds(iso_date[13]*1000);
+ }
+ }
+ }
+
+ }
+ }
+
+ return new_date;
+ } else {
+ return null;
+ }
+ }
+
+
+ /**********************************************************************************
+
+ FUNCTION
+ isEmpty
+
+ DESCRIPTION
+ determines whether or not the passed in string is EMPTY
+
+ EMPTY = null OR "" {EMPTY STRING}
+
+ **********************************************************************************/
+ function isEmpty( inputStr ) {
+ if ( null === inputStr || '' === inputStr ) {
+ return true;
+ }
+
+ return false;
+ }
+
+ /**********************************************************************************
+
+ FUNCTION
+ get_time_value
+
+ DESCRIPTION
+ get the time value specified either in the text or the cuteime attribute
+ of the object and update the cutetime attribute whether initially present
+ or not
+
+ If the cutetime attribute already exists within the provided object,
+ then the text within the object is ignored in the cutification
+ process. If the cutetime attribute does not exist or an invalid one
+ is provided, then a valid cutetime attribute is assigned to the object.
+
+ If the cutetime attribute is missing, then it is calculated from the text
+ of the provided object.
+
+ If neither cutetime attibute nor valid object text exist then the
+ timestamp is assumed to by 'now'.
+
+ **********************************************************************************/
+ function get_time_value(obj) {
+ var time_value = Number.NaN;
+
+ var time_string = get_cutetime_attr(obj); // returns string or NULL
+ if (time_string !== null) {
+ time_value = date_value(time_string);
+ }
+
+ if (isNaN(time_value)) {
+ time_string = get_object_text(obj);
+ if (time_string !== null) {
+ time_value = date_value(time_string);
+ }
+ }
+
+ // if nothing valid available then set time to RIGHT NOW
+ if (isNaN(time_value)) {
+ time_string = new Date().toString();
+ time_value = date_value(time_string);
+ }
+
+ // update cutetime attribute and return the time_value
+ set_cutetime_attr(time_string, obj);
+ return time_value;
+ }
+
+
+ /**********************************************************************************
+
+ FUNCTION
+ get_cutetime_attr
+
+ DESCRIPTION
+ returns the found value of the cutetime attribute of the specified object
+ or NULL
+
+ **********************************************************************************/
+ function get_cutetime_attr(obj) {
+ var return_value = obj.attr(TS_ATTR);
+
+ if (return_value !== undefined) {
+ return return_value;
+ } else {
+ return null;
+ }
+ }
+
+
+ /**********************************************************************************
+
+ FUNCTION
+ set_cutetime_attr
+
+ DESCRIPTION
+ sets / updates the cutetime attribute of the object
+
+ the cuteime attribute is set to be STARTING point against which all
+ future updates are measured against
+
+ **********************************************************************************/
+ function set_cutetime_attr(attr, obj) {
+ // assume valid attr(ibute) value
+ obj.attr(TS_ATTR, attr);
+ }
+
+
+ /**********************************************************************************
+
+ FUNCTION
+ get_object_text
+
+ DESCRIPTION
+ returns the text associated with the specified object (if any)
+
+ **********************************************************************************/
+ function get_object_text(obj) {
+ return obj.text();
+ }
+
+})(jQuery);