diff options
Diffstat (limited to 'static/jquery.countdown.js')
-rw-r--r-- | static/jquery.countdown.js | 759 |
1 files changed, 0 insertions, 759 deletions
diff --git a/static/jquery.countdown.js b/static/jquery.countdown.js deleted file mode 100644 index 27e2f4a..0000000 --- a/static/jquery.countdown.js +++ /dev/null @@ -1,759 +0,0 @@ -/* http://keith-wood.name/countdown.html - 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. - Please attribute the author if you use it. */ - -/* Display a countdown timer. - Attach it with options like: - $('div selector').countdown( - {until: new Date(2009, 1 - 1, 1, 0, 0, 0), onExpiry: happyNewYear}); */ - -(function($) { // Hide scope, no $ conflict - -/* Countdown manager. */ -function Countdown() { - this.regional = []; // Available regional settings, indexed by language code - this.regional[''] = { // Default regional settings - // The display texts for the counters - labels: ['Years', 'Months', 'Weeks', 'Days', 'Hours', 'Minutes', 'Seconds'], - // 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 - }; - this._defaults = { - until: null, // new Date(year, mth - 1, day, hr, min, sec) - date/time to count down to - // or numeric for seconds offset, or string for unit offset(s): - // 'Y' years, 'O' months, 'W' weeks, 'D' days, 'H' hours, 'M' minutes, 'S' seconds - since: null, // new Date(year, mth - 1, day, hr, min, sec) - date/time to count up from - // or numeric for seconds offset, or string for unit offset(s): - // 'Y' years, 'O' months, 'W' weeks, 'D' days, 'H' hours, 'M' minutes, 'S' seconds - timezone: null, // The timezone (hours or minutes from GMT) for the target times, - // or null for client local - serverSync: null, // A function to retrieve the current server time for synchronisation - format: 'dHMS', // Format for display - upper case for always, lower case only if non-zero, - // '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 - alwaysExpire: false, // True to trigger onExpiry even if never counted down - onExpiry: null, // Callback when the countdown expires - - // receives no parameters and 'this' is the containing division - onTick: null, // Callback when the countdown is updated - - // receives int[7] being the breakdown by period (based on format) - // and 'this' is the containing division - tickInterval: 1 // Interval (seconds) between onTick callbacks - }; - $.extend(this._defaults, this.regional['']); - this._serverSyncs = []; -} - -var PROP_NAME = 'countdown'; - -var Y = 0; // Years -var O = 1; // Months -var W = 2; // Weeks -var D = 3; // Days -var H = 4; // Hours -var M = 5; // Minutes -var S = 6; // Seconds - -$.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) { - this._resetExtraLabels(this._defaults, options); - extendRemove(this._defaults, options || {}); - }, - - /* Convert a date/time to UTC. - @param tz (number) the hour or minute offset from GMT, e.g. +9, -360 - @param year (Date) the date/time in that timezone or - (number) the year in that timezone - @param month (number, optional) the month (0 - 11) (omit if year is a Date) - @param day (number, optional) the day (omit if year is a Date) - @param hours (number, optional) the hour (omit if year is a Date) - @param mins (number, optional) the minute (omit if year is a Date) - @param secs (number, optional) the second (omit if year is a Date) - @param ms (number, optional) the millisecond (omit if year is a Date) - @return (Date) the equivalent UTC date/time */ - UTCDate: function(tz, year, month, day, hours, mins, secs, ms) { - if (typeof year == 'object' && year.constructor == Date) { - ms = year.getMilliseconds(); - secs = year.getSeconds(); - mins = year.getMinutes(); - hours = year.getHours(); - day = year.getDate(); - month = year.getMonth(); - year = year.getFullYear(); - } - var d = new Date(); - d.setUTCFullYear(year); - d.setUTCDate(1); - d.setUTCMonth(month || 0); - d.setUTCDate(day || 1); - d.setUTCHours(hours || 0); - d.setUTCMinutes((mins || 0) - (Math.abs(tz) < 30 ? tz * 60 : tz)); - d.setUTCSeconds(secs || 0); - d.setUTCMilliseconds(ms || 0); - return d; - }, - - /* Convert a set of periods into seconds. - Averaged for months and years. - @param periods (number[7]) the periods per year/month/week/day/hour/minute/second - @return (number) the corresponding number of seconds */ - periodsToSeconds: function(periods) { - return periods[0] * 31557600 + periods[1] * 2629800 + periods[2] * 604800 + - periods[3] * 86400 + periods[4] * 3600 + periods[5] * 60 + periods[6]; - }, - - /* Retrieve one or more settings values. - @param name (string, optional) the name of the setting to retrieve - or 'all' for all instance settings or omit for all default settings - @return (any) the requested setting(s) */ - _settingsCountdown: function(target, name) { - if (!name) { - return $.countdown._defaults; - } - var inst = $.data(target, PROP_NAME); - return (name == 'all' ? inst.options : inst.options[name]); - }, - - /* Attach the countdown widget to a div. - @param target (element) the containing division - @param options (object) the initial settings for the countdown */ - _attachCountdown: function(target, options) { - var $target = $(target); - if ($target.hasClass(this.markerClassName)) { - return; - } - $target.addClass(this.markerClassName); - var inst = {options: $.extend({}, options), - _periods: [0, 0, 0, 0, 0, 0, 0]}; - $.data(target, PROP_NAME, inst); - this._changeCountdown(target); - }, - - /* Add a target to the list of active ones. - @param target (element) the countdown target */ - _addTarget: function(target) { - if (!this._hasTarget(target)) { - this._timerTargets.push(target); - } - }, - - /* See if a target is in the list of active ones. - @param target (element) the countdown target - @return (boolean) true if present, false if not */ - _hasTarget: function(target) { - return ($.inArray(target, this._timerTargets) > -1); - }, - - /* Remove a target from the list of active ones. - @param target (element) the countdown target */ - _removeTarget: function(target) { - this._timerTargets = $.map(this._timerTargets, - function(value) { return (value == target ? null : value); }); // delete entry - }, - - /* Update each active timer target. */ - _updateTargets: function() { - for (var i = this._timerTargets.length - 1; i >= 0; i--) { - this._updateCountdown(this._timerTargets[i]); - } - }, - - /* Redisplay the countdown with an updated display. - @param target (jQuery) the containing division - @param inst (object) the current settings for this instance */ - _updateCountdown: function(target, inst) { - var $target = $(target); - inst = inst || $.data(target, PROP_NAME); - if (!inst) { - return; - } - $target.html(this._generateHTML(inst)); - $target[(this._get(inst, 'isRTL') ? 'add' : 'remove') + 'Class']('countdown_rtl'); - var onTick = this._get(inst, 'onTick'); - if (onTick) { - var periods = inst._hold != 'lap' ? inst._periods : - 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]); - } - } - var expired = inst._hold != 'pause' && - (inst._since ? inst._now.getTime() < inst._since.getTime() : - inst._now.getTime() >= inst._until.getTime()); - if (expired && !inst._expiring) { - inst._expiring = true; - if (this._hasTarget(target) || this._get(inst, 'alwaysExpire')) { - this._removeTarget(target); - var onExpiry = this._get(inst, 'onExpiry'); - if (onExpiry) { - onExpiry.apply(target, []); - } - var expiryText = this._get(inst, 'expiryText'); - if (expiryText) { - var layout = this._get(inst, 'layout'); - inst.options.layout = expiryText; - this._updateCountdown(target, inst); - inst.options.layout = layout; - } - var expiryUrl = this._get(inst, 'expiryUrl'); - if (expiryUrl) { - window.location = expiryUrl; - } - } - inst._expiring = false; - } - else if (inst._hold == 'pause') { - this._removeTarget(target); - } - $.data(target, PROP_NAME, inst); - }, - - /* Reconfigure the settings for a countdown div. - @param target (element) the containing division - @param options (object) the new settings for the countdown or - (string) an individual property name - @param value (any) the individual property value - (omit if options is an object) */ - _changeCountdown: function(target, options, value) { - options = options || {}; - if (typeof options == 'string') { - var name = options; - options = {}; - options[name] = value; - } - var inst = $.data(target, PROP_NAME); - if (inst) { - this._resetExtraLabels(inst.options, options); - extendRemove(inst.options, options); - this._adjustSettings(target, inst); - $.data(target, PROP_NAME, inst); - var now = new Date(); - if ((inst._since && inst._since < now) || - (inst._until && inst._until > now)) { - this._addTarget(target); - } - this._updateCountdown(target, inst); - } - }, - - /* Reset any extra labelsn and compactLabelsn entries if changing labels. - @param base (object) the options to be updated - @param options (object) the new option values */ - _resetExtraLabels: function(base, options) { - var changingLabels = false; - for (var n in options) { - if (n != 'whichLabels' && n.match(/[Ll]abels/)) { - changingLabels = true; - break; - } - } - if (changingLabels) { - for (var n in base) { // Remove custom numbered labels - if (n.match(/[Ll]abels[0-9]/)) { - base[n] = null; - } - } - } - }, - - /* Calculate interal settings for an instance. - @param target (element) the containing division - @param inst (object) the current settings for this instance */ - _adjustSettings: function(target, inst) { - var now; - var serverSync = this._get(inst, 'serverSync'); - var serverOffset = 0; - var serverEntry = null; - for (var i = 0; i < this._serverSyncs.length; i++) { - if (this._serverSyncs[i][0] == serverSync) { - serverEntry = this._serverSyncs[i][1]; - break; - } - } - if (serverEntry != null) { - serverOffset = (serverSync ? serverEntry : 0); - now = new Date(); - } - else { - var serverResult = (serverSync ? serverSync.apply(target, []) : null); - now = new Date(); - serverOffset = (serverResult ? now.getTime() - serverResult.getTime() : 0); - this._serverSyncs.push([serverSync, serverOffset]); - } - var timezone = this._get(inst, 'timezone'); - timezone = (timezone == null ? -now.getTimezoneOffset() : timezone); - inst._since = this._get(inst, 'since'); - if (inst._since != null) { - inst._since = this.UTCDate(timezone, this._determineTime(inst._since, null)); - if (inst._since && serverOffset) { - inst._since.setMilliseconds(inst._since.getMilliseconds() + serverOffset); - } - } - inst._until = this.UTCDate(timezone, this._determineTime(this._get(inst, 'until'), now)); - if (serverOffset) { - inst._until.setMilliseconds(inst._until.getMilliseconds() + serverOffset); - } - inst._show = this._determineShow(inst); - }, - - /* Remove the countdown widget from a div. - @param target (element) the containing division */ - _destroyCountdown: function(target) { - var $target = $(target); - if (!$target.hasClass(this.markerClassName)) { - return; - } - this._removeTarget(target); - $target.removeClass(this.markerClassName).empty(); - $.removeData(target, PROP_NAME); - }, - - /* Pause a countdown widget at the current time. - Stop it running but remember and display the current time. - @param target (element) the containing division */ - _pauseCountdown: function(target) { - this._hold(target, 'pause'); - }, - - /* Pause a countdown widget at the current time. - Stop the display but keep the countdown running. - @param target (element) the containing division */ - _lapCountdown: function(target) { - this._hold(target, 'lap'); - }, - - /* Resume a paused countdown widget. - @param target (element) the containing division */ - _resumeCountdown: function(target) { - this._hold(target, null); - }, - - /* Pause or resume a countdown widget. - @param target (element) the containing division - @param hold (string) the new hold setting */ - _hold: function(target, hold) { - var inst = $.data(target, PROP_NAME); - if (inst) { - if (inst._hold == 'pause' && !hold) { - inst._periods = inst._savePeriods; - var sign = (inst._since ? '-' : '+'); - 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[5] + 'm' + sign + inst._periods[6] + 's'); - this._addTarget(target); - } - inst._hold = hold; - inst._savePeriods = (hold == 'pause' ? inst._periods : null); - $.data(target, PROP_NAME, inst); - this._updateCountdown(target, inst); - } - }, - - /* Return the current time periods. - @param target (element) the containing division - @return (number[7]) the current periods for the countdown */ - _getTimesCountdown: function(target) { - var inst = $.data(target, PROP_NAME); - return (!inst ? null : (!inst._hold ? inst._periods : - this._calculatePeriods(inst, inst._show, this._get(inst, 'significant'), new Date()))); - }, - - /* Get a setting value, defaulting if necessary. - @param inst (object) the current settings for this instance - @param name (string) the name of the required setting - @return (any) the setting's value or a default if not overridden */ - _get: function(inst, name) { - return (inst.options[name] != null ? - inst.options[name] : $.countdown._defaults[name]); - }, - - /* A time may be specified as an exact value or a relative one. - @param setting (string or number or Date) - the date/time value - as a relative or absolute value - @param defaultTime (Date) the date/time to use if no other is supplied - @return (Date) the corresponding date/time */ - _determineTime: function(setting, defaultTime) { - var offsetNumeric = function(offset) { // e.g. +300, -2 - var time = new Date(); - time.setTime(time.getTime() + offset * 1000); - return time; - }; - var offsetString = function(offset) { // e.g. '+2d', '-4w', '+3h +30m' - offset = offset.toLowerCase(); - var time = new Date(); - var year = time.getFullYear(); - var month = time.getMonth(); - var day = time.getDate(); - var hour = time.getHours(); - var minute = time.getMinutes(); - var second = time.getSeconds(); - var pattern = /([+-]?[0-9]+)\s*(s|m|h|d|w|o|y)?/g; - var matches = pattern.exec(offset); - while (matches) { - switch (matches[2] || 's') { - case 's': second += parseInt(matches[1], 10); break; - case 'm': minute += parseInt(matches[1], 10); break; - case 'h': hour += parseInt(matches[1], 10); break; - case 'd': day += parseInt(matches[1], 10); break; - case 'w': day += parseInt(matches[1], 10) * 7; break; - case 'o': - month += parseInt(matches[1], 10); - day = Math.min(day, $.countdown._getDaysInMonth(year, month)); - break; - case 'y': - year += parseInt(matches[1], 10); - day = Math.min(day, $.countdown._getDaysInMonth(year, month)); - break; - } - matches = pattern.exec(offset); - } - return new Date(year, month, day, hour, minute, second, 0); - }; - var time = (setting == null ? defaultTime : - (typeof setting == 'string' ? offsetString(setting) : - (typeof setting == 'number' ? offsetNumeric(setting) : setting))); - if (time) time.setMilliseconds(0); - return time; - }, - - /* Determine the number of days in a month. - @param year (number) the year - @param month (number) the month - @return (number) the days in that month */ - _getDaysInMonth: function(year, month) { - 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 - 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 = 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 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 labelsNum = $.countdown._get(inst, 'labels' + whichLabels(inst._periods[period])); - return ((!significant && show[period]) || (significant && showSignificant[period]) ? - '<span class="countdown_section"><span class="countdown_amount">' + - inst._periods[period] + '</span><br/>' + - (labelsNum ? labelsNum[period] : labels[period]) + '</span>' : ''); - }; - 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(inst._periods[H], 2) : '') + - (show[M] ? (show[H] ? timeSeparator : '') + - this._minDigits(inst._periods[M], 2) : '') + - (show[S] ? (show[H] || show[M] ? timeSeparator : '') + - this._minDigits(inst._periods[S], 2) : '') : - // Full version - '<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>' + - (description ? '<span class="countdown_row countdown_descr">' + description + '</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 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, 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') + whichLabels(inst._periods[index])) || - labels)[index]; - }; - var digit = function(value, position) { - return Math.floor(value / position) % 10; - }; - var subs = {desc: this._get(inst, 'description'), sep: this._get(inst, 'timeSeparator'), - yl: labelFor(Y), yn: inst._periods[Y], ynn: this._minDigits(inst._periods[Y], 2), - ynnn: this._minDigits(inst._periods[Y], 3), y1: digit(inst._periods[Y], 1), - y10: digit(inst._periods[Y], 10), y100: digit(inst._periods[Y], 100), - y1000: digit(inst._periods[Y], 1000), - ol: labelFor(O), on: inst._periods[O], onn: this._minDigits(inst._periods[O], 2), - onnn: this._minDigits(inst._periods[O], 3), o1: digit(inst._periods[O], 1), - o10: digit(inst._periods[O], 10), o100: digit(inst._periods[O], 100), - o1000: digit(inst._periods[O], 1000), - wl: labelFor(W), wn: inst._periods[W], wnn: this._minDigits(inst._periods[W], 2), - wnnn: this._minDigits(inst._periods[W], 3), w1: digit(inst._periods[W], 1), - w10: digit(inst._periods[W], 10), w100: digit(inst._periods[W], 100), - w1000: digit(inst._periods[W], 1000), - dl: labelFor(D), dn: inst._periods[D], dnn: this._minDigits(inst._periods[D], 2), - dnnn: this._minDigits(inst._periods[D], 3), d1: digit(inst._periods[D], 1), - d10: digit(inst._periods[D], 10), d100: digit(inst._periods[D], 100), - d1000: digit(inst._periods[D], 1000), - hl: labelFor(H), hn: inst._periods[H], hnn: this._minDigits(inst._periods[H], 2), - hnnn: this._minDigits(inst._periods[H], 3), h1: digit(inst._periods[H], 1), - h10: digit(inst._periods[H], 10), h100: digit(inst._periods[H], 100), - h1000: digit(inst._periods[H], 1000), - ml: labelFor(M), mn: inst._periods[M], mnn: this._minDigits(inst._periods[M], 2), - mnnn: this._minDigits(inst._periods[M], 3), m1: digit(inst._periods[M], 1), - m10: digit(inst._periods[M], 10), m100: digit(inst._periods[M], 100), - m1000: digit(inst._periods[M], 1000), - sl: labelFor(S), sn: inst._periods[S], snn: this._minDigits(inst._periods[S], 2), - snnn: this._minDigits(inst._periods[S], 3), s1: digit(inst._periods[S], 1), - s10: digit(inst._periods[S], 10), s100: digit(inst._periods[S], 100), - s1000: digit(inst._periods[S], 1000)}; - var html = layout; - // Replace period containers: {p<}...{p>} - for (var i = Y; i <= S; i++) { - var period = 'yowdhms'.charAt(i); - var re = new RegExp('\\{' + period + '<\\}(.*)\\{' + period + '>\\}', 'g'); - html = html.replace(re, ((!significant && show[i]) || - (significant && showSignificant[i]) ? '$1' : '')); - } - // Replace period values: {pn} - $.each(subs, function(n, v) { - var re = new RegExp('\\{' + n + '\\}', 'g'); - html = html.replace(re, v); - }); - return html; - }, - - /* Ensure a numeric value has at least n digits for display. - @param value (number) the value to display - @param len (number) the minimum length - @return (string) the display text */ - _minDigits: function(value, len) { - value = '' + value; - if (value.length >= len) { - return value; - } - value = '0000000000' + value; - return value.substr(value.length - len); - }, - - /* Translate the format into flags for each period. - @param inst (object) the current settings for this instance - @return (string[7]) flags indicating which periods are requested (?) or - required (!) by year, month, week, day, hour, minute, second */ - _determineShow: function(inst) { - var format = this._get(inst, 'format'); - var show = []; - show[Y] = (format.match('y') ? '?' : (format.match('Y') ? '!' : null)); - show[O] = (format.match('o') ? '?' : (format.match('O') ? '!' : null)); - show[W] = (format.match('w') ? '?' : (format.match('W') ? '!' : null)); - show[D] = (format.match('d') ? '?' : (format.match('D') ? '!' : null)); - show[H] = (format.match('h') ? '?' : (format.match('H') ? '!' : null)); - show[M] = (format.match('m') ? '?' : (format.match('M') ? '!' : null)); - 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 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, significant, now) { - // Find endpoints - inst._now = now; - inst._now.setMilliseconds(0); - var until = new Date(inst._now.getTime()); - if (inst._since) { - if (now.getTime() < inst._since.getTime()) { - inst._now = now = until; - } - else { - now = inst._since; - } - } - else { - until.setTime(inst._until.getTime()); - if (now.getTime() > inst._until.getTime()) { - inst._now = now = until; - } - } - // Calculate differences by period - var periods = [0, 0, 0, 0, 0, 0, 0]; - if (show[Y] || show[O]) { - // Treat end of months as the same - var lastNow = $.countdown._getDaysInMonth(now.getFullYear(), now.getMonth()); - var lastUntil = $.countdown._getDaysInMonth(until.getFullYear(), until.getMonth()); - var sameDay = (until.getDate() == now.getDate() || - (until.getDate() >= Math.min(lastNow, lastUntil) && - now.getDate() >= Math.min(lastNow, lastUntil))); - var getSecs = function(date) { - return (date.getHours() * 60 + date.getMinutes()) * 60 + date.getSeconds(); - }; - var months = Math.max(0, - (until.getFullYear() - now.getFullYear()) * 12 + until.getMonth() - now.getMonth() + - ((until.getDate() < now.getDate() && !sameDay) || - (sameDay && getSecs(until) < getSecs(now)) ? -1 : 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 - 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); - } - 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); - var extractPeriod = function(period, numSecs) { - periods[period] = (show[period] ? Math.floor(diff / numSecs) : 0); - diff -= periods[period] * numSecs; - }; - extractPeriod(W, 604800); - extractPeriod(D, 86400); - extractPeriod(H, 3600); - extractPeriod(M, 60); - extractPeriod(S, 1); - if (diff > 0 && !inst._since) { // Round up if left overs - var multiplier = [1, 12, 4.3482, 7, 24, 60, 60]; - var lastShown = S; - var max = 1; - for (var period = S; period >= Y; period--) { - if (show[period]) { - if (periods[lastShown] >= max) { - periods[lastShown] = 0; - diff = 1; - } - if (diff > 0) { - periods[period]++; - diff = 0; - lastShown = period; - max = 1; - } - } - 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; - } -}); - -/* jQuery extend now ignores nulls! - @param target (object) the object to update - @param props (object) the new settings - @return (object) the updated object */ -function extendRemove(target, props) { - $.extend(target, props); - for (var name in props) { - if (props[name] == null) { - target[name] = null; - } - } - return target; -} - -/* Process the countdown functionality for a jQuery selection. - @param command (string) the command to run (optional, default 'attach') - @param options (object) the new settings to use for these countdown instances - @return (jQuery) for chaining further calls */ -$.fn.countdown = function(options) { - var otherArgs = Array.prototype.slice.call(arguments, 1); - if (options == 'getTimes' || options == 'settings') { - return $.countdown['_' + options + 'Countdown']. - apply($.countdown, [this[0]].concat(otherArgs)); - } - return this.each(function() { - if (typeof options == 'string') { - $.countdown['_' + options + 'Countdown'].apply($.countdown, [this].concat(otherArgs)); - } - else { - $.countdown._attachCountdown(this, options); - } - }); -}; - -/* Initialise the countdown functionality. */ -$.countdown = new Countdown(); // singleton instance - -})(jQuery); |