/* http://keith-wood.name/countdown.html
- Countdown for jQuery v1.5.7.
+ Countdown for jQuery v1.5.8.
Written by Keith Wood (kbwood{at}iinet.com.au) January 2008.
- Dual licensed under the GPL (http://dev.jquery.com/browser/trunk/jquery/GPL-LICENSE.txt) and
- MIT (http://dev.jquery.com/browser/trunk/jquery/MIT-LICENSE.txt) licenses.
+ Dual licensed under the GPL (http://dev.jquery.com/browser/trunk/jquery/GPL-LICENSE.txt) and
+ MIT (http://dev.jquery.com/browser/trunk/jquery/MIT-LICENSE.txt) licenses.
Please attribute the author if you use it. */
-/* Modified by Radek Czajka, Fundacja Nowoczesna Polska (radoslaw.czajka(at)nowoczesnapolska.org.pl) */
-
/* Display a countdown timer.
Attach it with options like:
$('div selector').countdown(
// The display texts for the counters if only one
labels1: ['Year', 'Month', 'Week', 'Day', 'Hour', 'Minute', 'Second'],
compactLabels: ['y', 'm', 'w', 'd'], // The compact texts for the counters
+ whichLabels: null, // Function to determine which labels to use
timeSeparator: ':', // Separator for time periods
- isRTL: false, // True for right-to-left languages, false for left-to-right
- which: function(n) {return n}
+ isRTL: false // True for right-to-left languages, false for left-to-right
};
this._defaults = {
until: null, // new Date(year, mth - 1, day, hr, min, sec) - date/time to count down to
// 'Y' years, 'O' months, 'W' weeks, 'D' days, 'H' hours, 'M' minutes, 'S' seconds
layout: '', // Build your own layout for the countdown
compact: false, // True to display in a compact format, false for an expanded one
+ significant: 0, // The number of periods with values to show, zero for all
description: '', // The description displayed for the countdown
expiryUrl: '', // A URL to load upon expiry, replacing the current page
expiryText: '', // Text to display upon expiry, replacing the countdown
$.extend(Countdown.prototype, {
/* Class name added to elements to indicate already configured with countdown. */
markerClassName: 'hasCountdown',
-
+
/* Shared timer for all countdowns. */
_timer: setInterval(function() { $.countdown._updateTargets(); }, 980),
/* List of currently active countdown targets. */
_timerTargets: [],
-
+
/* Override the default settings for all instances of the countdown widget.
@param options (object) the new settings to use as defaults */
setDefaults: function(options) {
var onTick = this._get(inst, 'onTick');
if (onTick) {
var periods = inst._hold != 'lap' ? inst._periods :
- this._calculatePeriods(inst, inst._show, new Date());
+ this._calculatePeriods(inst, inst._show, this._get(inst, 'significant'), new Date());
var tickInterval = this._get(inst, 'tickInterval');
if (tickInterval == 1 || this.periodsToSeconds(periods) % tickInterval == 0) {
onTick.apply(target, [periods]);
_resetExtraLabels: function(base, options) {
var changingLabels = false;
for (var n in options) {
- if (n.match(/[Ll]abels/)) {
+ if (n != 'whichLabels' && n.match(/[Ll]abels/)) {
changingLabels = true;
break;
}
}
}
},
-
+
/* Calculate interal settings for an instance.
@param target (element) the containing division
@param inst (object) the current settings for this instance */
inst[inst._since ? '_since' : '_until'] =
this._determineTime(sign + inst._periods[0] + 'y' +
sign + inst._periods[1] + 'o' + sign + inst._periods[2] + 'w' +
- sign + inst._periods[3] + 'd' + sign + inst._periods[4] + 'h' +
+ sign + inst._periods[3] + 'd' + sign + inst._periods[4] + 'h' +
sign + inst._periods[5] + 'm' + sign + inst._periods[6] + 's');
this._addTarget(target);
}
_getTimesCountdown: function(target) {
var inst = $.data(target, PROP_NAME);
return (!inst ? null : (!inst._hold ? inst._periods :
- this._calculatePeriods(inst, inst._show, new Date())));
+ this._calculatePeriods(inst, inst._show, this._get(inst, 'significant'), new Date())));
},
/* Get a setting value, defaulting if necessary.
case 'd': day += parseInt(matches[1], 10); break;
case 'w': day += parseInt(matches[1], 10) * 7; break;
case 'o':
- month += parseInt(matches[1], 10);
+ month += parseInt(matches[1], 10);
day = Math.min(day, $.countdown._getDaysInMonth(year, month));
break;
case 'y':
return 32 - new Date(year, month, 32).getDate();
},
+ /* Determine which set of labels should be used for an amount.
+ @param num (number) the amount to be displayed
+ @return (number) the set of labels to be used for this amount */
+ _normalLabels: function(num) {
+ return num;
+ },
+
/* Generate the HTML to display the countdown widget.
@param inst (object) the current settings for this instance
@return (string) the new HTML for the countdown display */
_generateHTML: function(inst) {
// Determine what to show
- inst._periods = periods = (inst._hold ? inst._periods :
- this._calculatePeriods(inst, inst._show, new Date()));
+ var significant = this._get(inst, 'significant');
+ inst._periods = (inst._hold ? inst._periods :
+ this._calculatePeriods(inst, inst._show, significant, new Date()));
// Show all 'asNeeded' after first non-zero value
var shownNonZero = false;
var showCount = 0;
+ var sigCount = significant;
var show = $.extend({}, inst._show);
- for (var period = 0; period < inst._show.length; period++) {
- shownNonZero |= (inst._show[period] == '?' && periods[period] > 0);
+ for (var period = Y; period <= S; period++) {
+ shownNonZero |= (inst._show[period] == '?' && inst._periods[period] > 0);
show[period] = (inst._show[period] == '?' && !shownNonZero ? null : inst._show[period]);
showCount += (show[period] ? 1 : 0);
+ sigCount -= (inst._periods[period] > 0 ? 1 : 0);
+ }
+ var showSignificant = [false, false, false, false, false, false, false];
+ for (var period = S; period >= Y; period--) { // Determine significant periods
+ if (inst._show[period]) {
+ if (inst._periods[period]) {
+ showSignificant[period] = true;
+ }
+ else {
+ showSignificant[period] = sigCount > 0;
+ sigCount--;
+ }
+ }
}
var compact = this._get(inst, 'compact');
var layout = this._get(inst, 'layout');
var labels = (compact ? this._get(inst, 'compactLabels') : this._get(inst, 'labels'));
+ var whichLabels = this._get(inst, 'whichLabels') || this._normalLabels;
var timeSeparator = this._get(inst, 'timeSeparator');
var description = this._get(inst, 'description') || '';
var showCompact = function(period) {
- var which = $.countdown._get(inst, 'which');
- if (which) {
- var labelsNum = $.countdown._get(inst, 'compactLabels' + which(periods[period]));
- }
- return (show[period] ? periods[period] +
+ var labelsNum = $.countdown._get(inst,
+ 'compactLabels' + whichLabels(inst._periods[period]));
+ return (show[period] ? inst._periods[period] +
(labelsNum ? labelsNum[period] : labels[period]) + ' ' : '');
};
var showFull = function(period) {
- var which = $.countdown._get(inst, 'which');
- if (which) {
- var labelsNum = $.countdown._get(inst, 'labels' + which(periods[period]));
- }
- return (show[period] ?
+ var labelsNum = $.countdown._get(inst, 'labels' + whichLabels(inst._periods[period]));
+ return ((!significant && show[period]) || (significant && showSignificant[period]) ?
'<span class="countdown_section"><span class="countdown_amount">' +
- periods[period] + '</span><br/>' +
+ inst._periods[period] + '</span><br/>' +
(labelsNum ? labelsNum[period] : labels[period]) + '</span>' : '');
};
- return (layout ? this._buildLayout(inst, show, layout, compact) :
+ return (layout ? this._buildLayout(inst, show, layout, compact, significant, showSignificant) :
((compact ? // Compact version
'<span class="countdown_row countdown_amount' +
- (inst._hold ? ' countdown_holding' : '') + '">' +
- showCompact(Y) + showCompact(O) + showCompact(W) + showCompact(D) +
- (show[H] ? this._minDigits(periods[H], 2) : '') +
+ (inst._hold ? ' countdown_holding' : '') + '">' +
+ showCompact(Y) + showCompact(O) + showCompact(W) + showCompact(D) +
+ (show[H] ? this._minDigits(inst._periods[H], 2) : '') +
(show[M] ? (show[H] ? timeSeparator : '') +
- this._minDigits(periods[M], 2) : '') +
+ this._minDigits(inst._periods[M], 2) : '') +
(show[S] ? (show[H] || show[M] ? timeSeparator : '') +
- this._minDigits(periods[S], 2) : '') :
+ this._minDigits(inst._periods[S], 2) : '') :
// Full version
- '<span class="countdown_row countdown_show' + showCount +
+ '<span class="countdown_row countdown_show' + (significant || showCount) +
(inst._hold ? ' countdown_holding' : '') + '">' +
showFull(Y) + showFull(O) + showFull(W) + showFull(D) +
showFull(H) + showFull(M) + showFull(S)) + '</span>' +
},
/* Construct a custom layout.
- @param inst (object) the current settings for this instance
- @param show (string[7]) flags indicating which periods are requested
- @param layout (string) the customised layout
- @param compact (boolean) true if using compact labels
+ @param inst (object) the current settings for this instance
+ @param show (string[7]) flags indicating which periods are requested
+ @param layout (string) the customised layout
+ @param compact (boolean) true if using compact labels
+ @param significant (number) the number of periods with values to show, zero for all
+ @param showSignificant (boolean[7]) other periods to show for significance
@return (string) the custom HTML */
- _buildLayout: function(inst, show, layout, compact) {
+ _buildLayout: function(inst, show, layout, compact, significant, showSignificant) {
var labels = this._get(inst, (compact ? 'compactLabels' : 'labels'));
+ var whichLabels = this._get(inst, 'whichLabels') || this._normalLabels;
var labelFor = function(index) {
return ($.countdown._get(inst,
- (compact ? 'compactLabels' : 'labels') + inst._periods[index]) ||
+ (compact ? 'compactLabels' : 'labels') + whichLabels(inst._periods[index])) ||
labels)[index];
};
var digit = function(value, position) {
s1000: digit(inst._periods[S], 1000)};
var html = layout;
// Replace period containers: {p<}...{p>}
- for (var i = 0; i < 7; i++) {
+ for (var i = Y; i <= S; i++) {
var period = 'yowdhms'.charAt(i);
var re = new RegExp('\\{' + period + '<\\}(.*)\\{' + period + '>\\}', 'g');
- html = html.replace(re, (show[i] ? '$1' : ''));
+ html = html.replace(re, ((!significant && show[i]) ||
+ (significant && showSignificant[i]) ? '$1' : ''));
}
// Replace period values: {pn}
$.each(subs, function(n, v) {
show[S] = (format.match('s') ? '?' : (format.match('S') ? '!' : null));
return show;
},
-
+
/* Calculate the requested periods between now and the target time.
- @param inst (object) the current settings for this instance
- @param show (string[7]) flags indicating which periods are requested/required
- @param now (Date) the current date and time
+ @param inst (object) the current settings for this instance
+ @param show (string[7]) flags indicating which periods are requested/required
+ @param significant (number) the number of periods with values to show, zero for all
+ @param now (Date) the current date and time
@return (number[7]) the current time periods (always positive)
by year, month, week, day, hour, minute, second */
- _calculatePeriods: function(inst, show, now) {
+ _calculatePeriods: function(inst, show, significant, now) {
// Find endpoints
inst._now = now;
inst._now.setMilliseconds(0);
periods[Y] = (show[Y] ? Math.floor(months / 12) : 0);
periods[O] = (show[O] ? months - periods[Y] * 12 : 0);
// Adjust for months difference and end of month if necessary
- var adjustDate = function(date, offset, last) {
- var wasLastDay = (date.getDate() == last);
- var lastDay = $.countdown._getDaysInMonth(date.getFullYear() + offset * periods[Y],
- date.getMonth() + offset * periods[O]);
- if (date.getDate() > lastDay) {
- date.setDate(lastDay);
- }
- date.setFullYear(date.getFullYear() + offset * periods[Y]);
- date.setMonth(date.getMonth() + offset * periods[O]);
- if (wasLastDay) {
- date.setDate(lastDay);
- }
- return date;
- };
- if (inst._since) {
- until = adjustDate(until, -1, lastUntil);
+ now = new Date(now.getTime());
+ var wasLastDay = (now.getDate() == lastNow);
+ var lastDay = $.countdown._getDaysInMonth(now.getFullYear() + periods[Y],
+ now.getMonth() + periods[O]);
+ if (now.getDate() > lastDay) {
+ now.setDate(lastDay);
}
- else {
- now = adjustDate(new Date(now.getTime()), +1, lastNow);
+ now.setFullYear(now.getFullYear() + periods[Y]);
+ now.setMonth(now.getMonth() + periods[O]);
+ if (wasLastDay) {
+ now.setDate(lastDay);
}
}
var diff = Math.floor((until.getTime() - now.getTime()) / 1000);
max *= multiplier[period];
}
}
+ if (significant) { // Zero out insignificant periods
+ for (var period = Y; period <= S; period++) {
+ if (significant && periods[period]) {
+ significant--;
+ }
+ else if (!significant) {
+ periods[period] = 0;
+ }
+ }
+ }
return periods;
}
});
/* Initialise the countdown functionality. */
$.countdown = new Countdown(); // singleton instance
-})(jQuery);
\ No newline at end of file
+})(jQuery);