diff --git a/jquery.countdown.css b/css/jquery.countdown.css similarity index 100% rename from jquery.countdown.css rename to css/jquery.countdown.css diff --git a/countdownGlowing.gif b/img/countdownGlowing.gif similarity index 100% rename from countdownGlowing.gif rename to img/countdownGlowing.gif diff --git a/countdownLED.png b/img/countdownLED.png similarity index 100% rename from countdownLED.png rename to img/countdownLED.png diff --git a/jquery.countdown.js b/jquery.countdown.js deleted file mode 100644 index 57a302b..0000000 --- a/jquery.countdown.js +++ /dev/null @@ -1,857 +0,0 @@ -/* http://keith-wood.name/countdown.html - Countdown for jQuery v2.0.0. - Written by Keith Wood (kbwood{at}iinet.com.au) January 2008. - Available under the MIT (https://github.com/jquery/jquery/blob/master/MIT-LICENSE.txt) license. - Please attribute the author if you use it. */ - -(function($) { // Hide scope, no $ conflict - - var pluginName = '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 - - /** Create the countdown plugin. -
Sets an element to show the time remaining until a given instant.
-Expects HTML like:
-<div></div>-
Provide inline configuration like:
-<div data-countdown="name: 'value'"></div>- @module Countdown - @augments JQPlugin - @example $(selector).countdown({until: +300}) */ - $.JQPlugin.createPlugin({ - - /** The name of the plugin. */ - name: pluginName, - - /** Countdown expiry callback. - Triggered when the countdown expires. - @callback expiryCallback */ - - /** Countdown server synchronisation callback. - Triggered when the countdown is initialised. - @callback serverSyncCallback - @return {Date} The current date/time on the server as expressed in the local timezone. */ - - /** Countdown tick callback. - Triggered on every
tickInterval
ticks of the countdown.
- @callback tickCallback
- @param periods {number[]} The breakdown by period (years, months, weeks, days,
- hours, minutes, seconds) of the time remaining/passed. */
-
- /** Countdown which labels callback.
- Triggered when the countdown is being display to determine which set of labels
- (labels
, labels1
, ...) are to be used for the current period value.
- @callback whichLabelsCallback
- @param num {number} The current period value.
- @return {number} The suffix for the label set to use. */
-
- /** Default settings for the plugin.
- @property until {Date|number|string} The date/time to count down to, or number of seconds
- offset from now, or string of amounts and units for offset(s) from now:
- 'Y' years, 'O' months, 'W' weeks, 'D' days, 'H' hours, 'M' minutes, 'S' seconds.
- @example until: new Date(2013, 12-1, 25, 13, 30)
- until: +300
- until: '+1O -2D'
- @property [since] {Date|number|string} The date/time to count up from, or
- number of seconds offset from now, or string for unit offset(s):
- 'Y' years, 'O' months, 'W' weeks, 'D' days, 'H' hours, 'M' minutes, 'S' seconds.
- @example since: new Date(2013, 1-1, 1)
- since: -300
- since: '-1O +2D'
- @property [timezone=null] {number} The timezone (hours or minutes from GMT) for the target times,
- or null for client local timezone.
- @example timezone: +10
- timezone: -60
- @property [serverSync=null] {serverSyncCallback} A function to retrieve the current server time
- for synchronisation.
- @property [format='dHMS'] {string} The 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.
- @property [layout=''] {string} Build your own layout for the countdown.
- @example layout: '{d<}{dn} {dl}{d>} {hnn}:{mnn}:{snn}'
- @property [compact=false] {boolean} True to display in a compact format, false for an expanded one.
- @property [padZeroes=false] {boolean} True to add leading zeroes
- @property [significant=0] {number} The number of periods with non-zero values to show, zero for all.
- @property [description=''] {string} The description displayed for the countdown.
- @property [expiryUrl=''] {string} A URL to load upon expiry, replacing the current page.
- @property [expiryText=''] {string} Text to display upon expiry, replacing the countdown. This may be HTML.
- @property [alwaysExpire=false] {boolean} True to trigger onExpiry
even if target time has passed.
- @property [onExpiry=null] {expiryCallback} Callback when the countdown expires -
- receives no parameters and this
is the containing division.
- @example onExpiry: function() {
- ...
- }
- @property [onTick=null] {tickCallback} Callback when the countdown is updated -
- receives number[7]
being the breakdown by period
- (years, months, weeks, days, hours, minutes, seconds - based on
- format
) and this
is the containing division.
- @example onTick: function(periods) {
- var secs = $.countdown.periodsToSeconds(periods);
- if (secs < 300) { // Last five minutes
- ...
- }
- }
- @property [tickInterval=1] {number} The interval (seconds) between onTick
callbacks. */
- defaultOptions: {
- until: null,
- since: null,
- timezone: null,
- serverSync: null,
- format: 'dHMS',
- layout: '',
- compact: false,
- padZeroes: false,
- significant: 0,
- description: '',
- expiryUrl: '',
- expiryText: '',
- alwaysExpire: false,
- onExpiry: null,
- onTick: null,
- tickInterval: 1
- },
-
- /** Localisations for the plugin.
- Entries are objects indexed by the language code ('' being the default US/English).
- Each object has the following attributes.
- @property [labels=['Years','Months','Weeks','Days','Hours','Minutes','Seconds']] {string[]}
- The display texts for the counter periods.
- @property [labels1=['Year','Month','Week','Day','Hour','Minute','Second']] {string[]}
- The display texts for the counter periods if they have a value of 1.
- Add other labelsn
attributes as necessary to
- cater for other numeric idiosyncrasies of the localisation.
- @property [compactLabels=['y','m','w','d']] {string[]} The compact texts for the counter periods.
- @property [whichLabels=null] {whichLabelsCallback} A function to determine which
- labelsn
to use.
- @example whichLabels: function(num) {
- return (num > 1 ? 0 : 1);
- }
- @property [digits=['0','1',...,'9']] {number[]} The digits to display (0-9).
- @property [timeSeparator=':'] {string} Separator for time periods in the compact layout.
- @property [isRTL=false] {boolean} True for right-to-left languages, false for left-to-right. */
- regionalOptions: { // Available regional settings, indexed by language/country code
- '': { // Default regional settings - English/US
- labels: ['Years', 'Months', 'Weeks', 'Days', 'Hours', 'Minutes', 'Seconds'],
- labels1: ['Year', 'Month', 'Week', 'Day', 'Hour', 'Minute', 'Second'],
- compactLabels: ['y', 'm', 'w', 'd'],
- whichLabels: null,
- digits: ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'],
- timeSeparator: ':',
- isRTL: false
- }
- },
-
- /** Names of getter methods - those that can't be chained. */
- _getters: ['getTimes'],
-
- /* Class name for the right-to-left marker. */
- _rtlClass: pluginName + '-rtl',
- /* Class name for the countdown section marker. */
- _sectionClass: pluginName + '-section',
- /* Class name for the period amount marker. */
- _amountClass: pluginName + '-amount',
- /* Class name for the period name marker. */
- _periodClass: pluginName + '-period',
- /* Class name for the countdown row marker. */
- _rowClass: pluginName + '-row',
- /* Class name for the holding countdown marker. */
- _holdingClass: pluginName + '-holding',
- /* Class name for the showing countdown marker. */
- _showClass: pluginName + '-show',
- /* Class name for the description marker. */
- _descrClass: pluginName + '-descr',
-
- /* List of currently active countdown elements. */
- _timerElems: [],
-
- /** Additional setup for the countdown.
- Apply default localisations.
- Create the timer. */
- _init: function() {
- var self = this;
- this._super();
- this._serverSyncs = [];
- var now = (typeof Date.now == 'function' ? Date.now :
- function() { return new Date().getTime(); });
- var perfAvail = (window.performance && typeof window.performance.now == 'function');
- // Shared timer for all countdowns
- function timerCallBack(timestamp) {
- var drawStart = (timestamp < 1e12 ? // New HTML5 high resolution timer
- (perfAvail ? (performance.now() + performance.timing.navigationStart) : now()) :
- // Integer milliseconds since unix epoch
- timestamp || now());
- if (drawStart - animationStartTime >= 1000) {
- self._updateElems();
- animationStartTime = drawStart;
- }
- requestAnimationFrame(timerCallBack);
- }
- var requestAnimationFrame = window.requestAnimationFrame ||
- window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame ||
- window.oRequestAnimationFrame || window.msRequestAnimationFrame || null;
- // This is when we expect a fall-back to setInterval as it's much more fluid
- var animationStartTime = 0;
- if (!requestAnimationFrame || $.noRequestAnimationFrame) {
- $.noRequestAnimationFrame = null;
- setInterval(function() { self._updateElems(); }, 980); // Fall back to good old setInterval
- }
- else {
- animationStartTime = window.animationStartTime ||
- window.webkitAnimationStartTime || window.mozAnimationStartTime ||
- window.oAnimationStartTime || window.msAnimationStartTime || now();
- requestAnimationFrame(timerCallBack);
- }
- },
-
- /** Convert a date/time to UTC.
- @param tz {number} The hour or minute offset from GMT, e.g. +9, -360.
- @param year {Date|number} the date/time in that timezone or the year in that timezone.
- @param [month] {number} The month (0 - 11) (omit if year
is a Date
).
- @param [day] {number} The day (omit if year
is a Date
).
- @param [hours] {number} The hour (omit if year
is a Date
).
- @param [mins] {number} The minute (omit if year
is a Date
).
- @param [secs] {number} The second (omit if year
is a Date
).
- @param [ms] {number} The millisecond (omit if year
is a Date
).
- @return {Date} The equivalent UTC date/time.
- @example $.countdown.UTCDate(+10, 2013, 12-1, 25, 12, 0)
- $.countdown.UTCDate(-7, new Date(2013, 12-1, 25, 12, 0)) */
- 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[]} The periods per year/month/week/day/hour/minute/second.
- @return {number} The corresponding number of seconds.
- @example var secs = $.countdown.periodsToSeconds(periods) */
- periodsToSeconds: function(periods) {
- return periods[0] * 31557600 + periods[1] * 2629800 + periods[2] * 604800 +
- periods[3] * 86400 + periods[4] * 3600 + periods[5] * 60 + periods[6];
- },
-
- _instSettings: function(elem, options) {
- return {_periods: [0, 0, 0, 0, 0, 0, 0]};
- },
-
- /** Add an element to the list of active ones.
- @private
- @param elem {Element} The countdown element. */
- _addElem: function(elem) {
- if (!this._hasElem(elem)) {
- this._timerElems.push(elem);
- }
- },
-
- /** See if an element is in the list of active ones.
- @private
- @param elem {Element} The countdown element.
- @return {boolean} True if present, false if not. */
- _hasElem: function(elem) {
- return ($.inArray(elem, this._timerElems) > -1);
- },
-
- /** Remove an element from the list of active ones.
- @private
- @param elem {Element} The countdown element. */
- _removeElem: function(elem) {
- this._timerElems = $.map(this._timerElems,
- function(value) { return (value == elem ? null : value); }); // delete entry
- },
-
- /** Update each active timer element.
- @private */
- _updateElems: function() {
- for (var i = this._timerElems.length - 1; i >= 0; i--) {
- this._updateCountdown(this._timerElems[i]);
- }
- },
-
- _optionsChanged: function(elem, inst, options) {
- if (options.layout) {
- options.layout = options.layout.replace(/</g, '<').replace(/>/g, '>');
- }
- this._resetExtraLabels(inst.options, options);
- var timezoneChanged = (inst.options.timezone != options.timezone);
- $.extend(inst.options, options);
- this._adjustSettings(elem, inst,
- options.until != null || options.since != null || timezoneChanged);
- var now = new Date();
- if ((inst._since && inst._since < now) || (inst._until && inst._until > now)) {
- this._addElem(elem[0]);
- }
- this._updateCountdown(elem, inst);
- },
-
- /** Redisplay the countdown with an updated display.
- @private
- @param elem {Element|jQuery} The containing division.
- @param inst {object} The current settings for this instance. */
- _updateCountdown: function(elem, inst) {
- elem = elem.jquery ? elem : $(elem);
- inst = inst || elem.data(this.name);
- if (!inst) {
- return;
- }
- elem.html(this._generateHTML(inst)).toggleClass(this._rtlClass, inst.options.isRTL);
- if ($.isFunction(inst.options.onTick)) {
- var periods = inst._hold != 'lap' ? inst._periods :
- this._calculatePeriods(inst, inst._show, inst.options.significant, new Date());
- if (inst.options.tickInterval == 1 ||
- this.periodsToSeconds(periods) % inst.options.tickInterval == 0) {
- inst.options.onTick.apply(elem[0], [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._hasElem(elem[0]) || inst.options.alwaysExpire) {
- this._removeElem(elem[0]);
- if ($.isFunction(inst.options.onExpiry)) {
- inst.options.onExpiry.apply(elem[0], []);
- }
- if (inst.options.expiryText) {
- var layout = inst.options.layout;
- inst.options.layout = inst.options.expiryText;
- this._updateCountdown(elem[0], inst);
- inst.options.layout = layout;
- }
- if (inst.options.expiryUrl) {
- window.location = inst.options.expiryUrl;
- }
- }
- inst._expiring = false;
- }
- else if (inst._hold == 'pause') {
- this._removeElem(elem[0]);
- }
- },
-
- /** Reset any extra labelsn and compactLabelsn entries if changing labels.
- @private
- @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[02-9]|compactLabels1/)) {
- base[n] = null;
- }
- }
- }
- },
-
- /** Calculate internal settings for an instance.
- @private
- @param elem {jQuery} The containing division.
- @param inst {object} The current settings for this instance.
- @param recalc {boolean} True if until or since are set. */
- _adjustSettings: function(elem, inst, recalc) {
- var now;
- var serverOffset = 0;
- var serverEntry = null;
- for (var i = 0; i < this._serverSyncs.length; i++) {
- if (this._serverSyncs[i][0] == inst.options.serverSync) {
- serverEntry = this._serverSyncs[i][1];
- break;
- }
- }
- if (serverEntry != null) {
- serverOffset = (inst.options.serverSync ? serverEntry : 0);
- now = new Date();
- }
- else {
- var serverResult = ($.isFunction(inst.options.serverSync) ?
- inst.options.serverSync.apply(elem[0], []) : null);
- now = new Date();
- serverOffset = (serverResult ? now.getTime() - serverResult.getTime() : 0);
- this._serverSyncs.push([inst.options.serverSync, serverOffset]);
- }
- var timezone = inst.options.timezone;
- timezone = (timezone == null ? -now.getTimezoneOffset() : timezone);
- if (recalc || (!recalc && inst._until == null && inst._since == null)) {
- inst._since = inst.options.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(inst.options.until, now));
- if (serverOffset) {
- inst._until.setMilliseconds(inst._until.getMilliseconds() + serverOffset);
- }
- }
- inst._show = this._determineShow(inst);
- },
-
- /** Remove the countdown widget from a div.
- @param elem {jQuery} The containing division.
- @param inst {object} The current instance object. */
- _preDestroy: function(elem, inst) {
- this._removeElem(elem[0]);
- elem.empty();
- },
-
- /** Pause a countdown widget at the current time.
- Stop it running but remember and display the current time.
- @param elem {Element} The containing division.
- @example $(selector).countdown('pause') */
- pause: function(elem) {
- this._hold(elem, 'pause');
- },
-
- /** Pause a countdown widget at the current time.
- Stop the display but keep the countdown running.
- @param elem {Element} The containing division.
- @example $(selector).countdown('lap') */
- lap: function(elem) {
- this._hold(elem, 'lap');
- },
-
- /** Resume a paused countdown widget.
- @param elem {Element} The containing division.
- @example $(selector).countdown('resume') */
- resume: function(elem) {
- this._hold(elem, null);
- },
-
- /** Toggle a paused countdown widget.
- @param elem {Element} The containing division.
- @example $(selector).countdown('toggle') */
- toggle: function(elem) {
- var inst = $.data(elem, this.name) || {};
- this[!inst._hold ? 'pause' : 'resume'](elem);
- },
-
- /** Toggle a lapped countdown widget.
- @param elem {Element} The containing division.
- @example $(selector).countdown('toggleLap') */
- toggleLap: function(elem) {
- var inst = $.data(elem, this.name) || {};
- this[!inst._hold ? 'lap' : 'resume'](elem);
- },
-
- /** Pause or resume a countdown widget.
- @private
- @param elem {Element} The containing division.
- @param hold {string} The new hold setting. */
- _hold: function(elem, hold) {
- var inst = $.data(elem, this.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._addElem(elem);
- }
- inst._hold = hold;
- inst._savePeriods = (hold == 'pause' ? inst._periods : null);
- $.data(elem, this.name, inst);
- this._updateCountdown(elem, inst);
- }
- },
-
- /** Return the current time periods.
- @param elem {Element} The containing division.
- @return {number[]} The current periods for the countdown.
- @example var periods = $(selector).countdown('getTimes') */
- getTimes: function(elem) {
- var inst = $.data(elem, this.name);
- return (!inst ? null : (inst._hold == 'pause' ? inst._savePeriods : (!inst._hold ? inst._periods :
- this._calculatePeriods(inst, inst._show, inst.options.significant, new Date()))));
- },
-
- /** A time may be specified as an exact value or a relative one.
- @private
- @param setting {string|number|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 self = this;
- 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, self._getDaysInMonth(year, month));
- break;
- case 'y':
- year += parseInt(matches[1], 10);
- day = Math.min(day, self._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.
- @private
- @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();
- },
-
- /** Default implementation to determine which set of labels should be used for an amount.
- Use the labels
attribute with the same numeric suffix (if it exists).
- @private
- @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.
- @private
- @param inst {object} The current settings for this instance.
- @return {string} The new HTML for the countdown display. */
- _generateHTML: function(inst) {
- var self = this;
- // Determine what to show
- inst._periods = (inst._hold ? inst._periods :
- this._calculatePeriods(inst, inst._show, inst.options.significant, new Date()));
- // Show all 'asNeeded' after first non-zero value
- var shownNonZero = false;
- var showCount = 0;
- var sigCount = inst.options.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 labels = (inst.options.compact ? inst.options.compactLabels : inst.options.labels);
- var whichLabels = inst.options.whichLabels || this._normalLabels;
- var showCompact = function(period) {
- var labelsNum = inst.options['compactLabels' + whichLabels(inst._periods[period])];
- return (show[period] ? self._translateDigits(inst, inst._periods[period]) +
- (labelsNum ? labelsNum[period] : labels[period]) + ' ' : '');
- };
- var minDigits = (inst.options.padZeroes ? 2 : 1);
- var showFull = function(period) {
- var labelsNum = inst.options['labels' + whichLabels(inst._periods[period])];
- return ((!inst.options.significant && show[period]) ||
- (inst.options.significant && showSignificant[period]) ?
- '' +
- '' +
- self._minDigits(inst, inst._periods[period], minDigits) + '' +
- '' +
- (labelsNum ? labelsNum[period] : labels[period]) + '' : '');
- };
- return (inst.options.layout ? this._buildLayout(inst, show, inst.options.layout,
- inst.options.compact, inst.options.significant, showSignificant) :
- ((inst.options.compact ? // Compact version
- '' +
- showCompact(Y) + showCompact(O) + showCompact(W) + showCompact(D) +
- (show[H] ? this._minDigits(inst, inst._periods[H], 2) : '') +
- (show[M] ? (show[H] ? inst.options.timeSeparator : '') +
- this._minDigits(inst, inst._periods[M], 2) : '') +
- (show[S] ? (show[H] || show[M] ? inst.options.timeSeparator : '') +
- this._minDigits(inst, inst._periods[S], 2) : '') :
- // Full version
- '' +
- inst.options.description + '' : '')));
- },
-
- /** Construct a custom layout.
- @private
- @param inst {object} The current settings for this instance.
- @param show {boolean[]} 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[]} Other periods to show for significance.
- @return {string} The custom HTML. */
- _buildLayout: function(inst, show, layout, compact, significant, showSignificant) {
- var labels = inst.options[compact ? 'compactLabels' : 'labels'];
- var whichLabels = inst.options.whichLabels || this._normalLabels;
- var labelFor = function(index) {
- return (inst.options[(compact ? 'compactLabels' : 'labels') +
- whichLabels(inst._periods[index])] || labels)[index];
- };
- var digit = function(value, position) {
- return inst.options.digits[Math.floor(value / position) % 10];
- };
- var subs = {desc: inst.options.description, sep: inst.options.timeSeparator,
- yl: labelFor(Y), yn: this._minDigits(inst, inst._periods[Y], 1),
- ynn: this._minDigits(inst, inst._periods[Y], 2),
- ynnn: this._minDigits(inst, 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: this._minDigits(inst, inst._periods[O], 1),
- onn: this._minDigits(inst, inst._periods[O], 2),
- onnn: this._minDigits(inst, 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: this._minDigits(inst, inst._periods[W], 1),
- wnn: this._minDigits(inst, inst._periods[W], 2),
- wnnn: this._minDigits(inst, 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: this._minDigits(inst, inst._periods[D], 1),
- dnn: this._minDigits(inst, inst._periods[D], 2),
- dnnn: this._minDigits(inst, 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: this._minDigits(inst, inst._periods[H], 1),
- hnn: this._minDigits(inst, inst._periods[H], 2),
- hnnn: this._minDigits(inst, 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: this._minDigits(inst, inst._periods[M], 1),
- mnn: this._minDigits(inst, inst._periods[M], 2),
- mnnn: this._minDigits(inst, 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: this._minDigits(inst, inst._periods[S], 1),
- snn: this._minDigits(inst, inst._periods[S], 2),
- snnn: this._minDigits(inst, 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 + '<\\}([\\s\\S]*)\\{' + 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.
- @private
- @param inst {object} The current settings for this instance.
- @param value {number} The value to display.
- @param len {number} The minimum length.
- @return {string} The display text. */
- _minDigits: function(inst, value, len) {
- value = '' + value;
- if (value.length >= len) {
- return this._translateDigits(inst, value);
- }
- value = '0000000000' + value;
- return this._translateDigits(inst, value.substr(value.length - len));
- },
-
- /** Translate digits into other representations.
- @private
- @param inst {object} The current settings for this instance.
- @param value {string} The text to translate.
- @return {string} The translated text. */
- _translateDigits: function(inst, value) {
- return ('' + value).replace(/[0-9]/g, function(digit) {
- return inst.options.digits[digit];
- });
- },
-
- /** Translate the format into flags for each period.
- @private
- @param inst {object} The current settings for this instance.
- @return {string[]} Flags indicating which periods are requested (?) or
- required (!) by year, month, week, day, hour, minute, second. */
- _determineShow: function(inst) {
- var format = inst.options.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.
- @private
- @param inst {object} The current settings for this instance.
- @param show {string[]} 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[]} 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 = this._getDaysInMonth(now.getFullYear(), now.getMonth());
- var lastUntil = this._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 = this._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);
diff --git a/js/jquery.countdown.js b/js/jquery.countdown.js
new file mode 100644
index 0000000..9a224ee
--- /dev/null
+++ b/js/jquery.countdown.js
@@ -0,0 +1,852 @@
+/* http://keith-wood.name/countdown.html
+ Countdown for jQuery v2.0.0.
+ Written by Keith Wood (kbwood{at}iinet.com.au) January 2008.
+ Available under the MIT (https://github.com/jquery/jquery/blob/master/MIT-LICENSE.txt) license.
+ Please attribute the author if you use it. */
+
+(function($) { // Hide scope, no $ conflict
+
+ var pluginName = '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
+
+ /** Create the countdown plugin.
+ Sets an element to show the time remaining until a given instant.
+Expects HTML like:
+<div></div>+
Provide inline configuration like:
+<div data-countdown="name: 'value'"></div>+ @module Countdown + @augments JQPlugin + @example $(selector).countdown({until: +300}) */ + $.JQPlugin.createPlugin({ + + /** The name of the plugin. */ + name: pluginName, + + /** Countdown expiry callback. + Triggered when the countdown expires. + @callback expiryCallback */ + + /** Countdown server synchronisation callback. + Triggered when the countdown is initialised. + @callback serverSyncCallback + @return {Date} The current date/time on the server as expressed in the local timezone. */ + + /** Countdown tick callback. + Triggered on every
tickInterval
ticks of the countdown.
+ @callback tickCallback
+ @param periods {number[]} The breakdown by period (years, months, weeks, days,
+ hours, minutes, seconds) of the time remaining/passed. */
+
+ /** Countdown which labels callback.
+ Triggered when the countdown is being display to determine which set of labels
+ (labels
, labels1
, ...) are to be used for the current period value.
+ @callback whichLabelsCallback
+ @param num {number} The current period value.
+ @return {number} The suffix for the label set to use. */
+
+ /** Default settings for the plugin.
+ @property until {Date|number|string} The date/time to count down to, or number of seconds
+ offset from now, or string of amounts and units for offset(s) from now:
+ 'Y' years, 'O' months, 'W' weeks, 'D' days, 'H' hours, 'M' minutes, 'S' seconds.
+ @example until: new Date(2013, 12-1, 25, 13, 30)
+ until: +300
+ until: '+1O -2D'
+ @property [since] {Date|number|string} The date/time to count up from, or
+ number of seconds offset from now, or string for unit offset(s):
+ 'Y' years, 'O' months, 'W' weeks, 'D' days, 'H' hours, 'M' minutes, 'S' seconds.
+ @example since: new Date(2013, 1-1, 1)
+ since: -300
+ since: '-1O +2D'
+ @property [timezone=null] {number} The timezone (hours or minutes from GMT) for the target times,
+ or null for client local timezone.
+ @example timezone: +10
+ timezone: -60
+ @property [serverSync=null] {serverSyncCallback} A function to retrieve the current server time
+ for synchronisation.
+ @property [format='dHMS'] {string} The 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.
+ @property [layout=''] {string} Build your own layout for the countdown.
+ @example layout: '{d<}{dn} {dl}{d>} {hnn}:{mnn}:{snn}'
+ @property [compact=false] {boolean} True to display in a compact format, false for an expanded one.
+ @property [padZeroes=false] {boolean} True to add leading zeroes
+ @property [significant=0] {number} The number of periods with non-zero values to show, zero for all.
+ @property [description=''] {string} The description displayed for the countdown.
+ @property [expiryUrl=''] {string} A URL to load upon expiry, replacing the current page.
+ @property [expiryText=''] {string} Text to display upon expiry, replacing the countdown. This may be HTML.
+ @property [alwaysExpire=false] {boolean} True to trigger onExpiry
even if target time has passed.
+ @property [onExpiry=null] {expiryCallback} Callback when the countdown expires -
+ receives no parameters and this
is the containing division.
+ @example onExpiry: function() {
+ ...
+ }
+ @property [onTick=null] {tickCallback} Callback when the countdown is updated -
+ receives number[7]
being the breakdown by period
+ (years, months, weeks, days, hours, minutes, seconds - based on
+ format
) and this
is the containing division.
+ @example onTick: function(periods) {
+ var secs = $.countdown.periodsToSeconds(periods);
+ if (secs < 300) { // Last five minutes
+ ...
+ }
+ }
+ @property [tickInterval=1] {number} The interval (seconds) between onTick
callbacks. */
+ defaultOptions: {
+ until: null,
+ since: null,
+ timezone: null,
+ serverSync: null,
+ format: 'dHMS',
+ layout: '',
+ compact: false,
+ padZeroes: false,
+ significant: 0,
+ description: '',
+ expiryUrl: '',
+ expiryText: '',
+ alwaysExpire: false,
+ onExpiry: null,
+ onTick: null,
+ tickInterval: 1
+ },
+
+ /** Localisations for the plugin.
+ Entries are objects indexed by the language code ('' being the default US/English).
+ Each object has the following attributes.
+ @property [labels=['Years','Months','Weeks','Days','Hours','Minutes','Seconds']] {string[]}
+ The display texts for the counter periods.
+ @property [labels1=['Year','Month','Week','Day','Hour','Minute','Second']] {string[]}
+ The display texts for the counter periods if they have a value of 1.
+ Add other labelsn
attributes as necessary to
+ cater for other numeric idiosyncrasies of the localisation.
+ @property [compactLabels=['y','m','w','d']] {string[]} The compact texts for the counter periods.
+ @property [whichLabels=null] {whichLabelsCallback} A function to determine which
+ labelsn
to use.
+ @example whichLabels: function(num) {
+ return (num > 1 ? 0 : 1);
+ }
+ @property [digits=['0','1',...,'9']] {number[]} The digits to display (0-9).
+ @property [timeSeparator=':'] {string} Separator for time periods in the compact layout.
+ @property [isRTL=false] {boolean} True for right-to-left languages, false for left-to-right. */
+ regionalOptions: { // Available regional settings, indexed by language/country code
+ '': { // Default regional settings - English/US
+ labels: ['Years', 'Months', 'Weeks', 'Days', 'Hours', 'Minutes', 'Seconds'],
+ labels1: ['Year', 'Month', 'Week', 'Day', 'Hour', 'Minute', 'Second'],
+ compactLabels: ['y', 'm', 'w', 'd'],
+ whichLabels: null,
+ digits: ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'],
+ timeSeparator: ':',
+ isRTL: false
+ }
+ },
+
+ /** Names of getter methods - those that can't be chained. */
+ _getters: ['getTimes'],
+
+ /* Class name for the right-to-left marker. */
+ _rtlClass: pluginName + '-rtl',
+ /* Class name for the countdown section marker. */
+ _sectionClass: pluginName + '-section',
+ /* Class name for the period amount marker. */
+ _amountClass: pluginName + '-amount',
+ /* Class name for the period name marker. */
+ _periodClass: pluginName + '-period',
+ /* Class name for the countdown row marker. */
+ _rowClass: pluginName + '-row',
+ /* Class name for the holding countdown marker. */
+ _holdingClass: pluginName + '-holding',
+ /* Class name for the showing countdown marker. */
+ _showClass: pluginName + '-show',
+ /* Class name for the description marker. */
+ _descrClass: pluginName + '-descr',
+
+ /* List of currently active countdown elements. */
+ _timerElems: [],
+
+ /** Additional setup for the countdown.
+ Apply default localisations.
+ Create the timer. */
+ _init: function() {
+ var self = this;
+ this._super();
+ this._serverSyncs = [];
+ var now = (typeof Date.now == 'function' ? Date.now :
+ function() { return new Date().getTime(); });
+ var perfAvail = (window.performance && typeof window.performance.now == 'function');
+ // Shared timer for all countdowns
+ function timerCallBack(timestamp) {
+ var drawStart = (timestamp < 1e12 ? // New HTML5 high resolution timer
+ (perfAvail ? (performance.now() + performance.timing.navigationStart) : now()) :
+ // Integer milliseconds since unix epoch
+ timestamp || now());
+ if (drawStart - animationStartTime >= 1000) {
+ self._updateElems();
+ animationStartTime = drawStart;
+ }
+ requestAnimationFrame(timerCallBack);
+ }
+ var requestAnimationFrame = window.requestAnimationFrame ||
+ window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame ||
+ window.oRequestAnimationFrame || window.msRequestAnimationFrame || null;
+ // This is when we expect a fall-back to setInterval as it's much more fluid
+ var animationStartTime = 0;
+ if (!requestAnimationFrame || $.noRequestAnimationFrame) {
+ $.noRequestAnimationFrame = null;
+ setInterval(function() { self._updateElems(); }, 980); // Fall back to good old setInterval
+ } else {
+ animationStartTime = window.animationStartTime ||
+ window.webkitAnimationStartTime || window.mozAnimationStartTime ||
+ window.oAnimationStartTime || window.msAnimationStartTime || now();
+ requestAnimationFrame(timerCallBack);
+ }
+ },
+
+ /** Convert a date/time to UTC.
+ @param tz {number} The hour or minute offset from GMT, e.g. +9, -360.
+ @param year {Date|number} the date/time in that timezone or the year in that timezone.
+ @param [month] {number} The month (0 - 11) (omit if year
is a Date
).
+ @param [day] {number} The day (omit if year
is a Date
).
+ @param [hours] {number} The hour (omit if year
is a Date
).
+ @param [mins] {number} The minute (omit if year
is a Date
).
+ @param [secs] {number} The second (omit if year
is a Date
).
+ @param [ms] {number} The millisecond (omit if year
is a Date
).
+ @return {Date} The equivalent UTC date/time.
+ @example $.countdown.UTCDate(+10, 2013, 12-1, 25, 12, 0)
+ $.countdown.UTCDate(-7, new Date(2013, 12-1, 25, 12, 0)) */
+ 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[]} The periods per year/month/week/day/hour/minute/second.
+ @return {number} The corresponding number of seconds.
+ @example var secs = $.countdown.periodsToSeconds(periods) */
+ periodsToSeconds: function(periods) {
+ return periods[0] * 31557600 + periods[1] * 2629800 + periods[2] * 604800 +
+ periods[3] * 86400 + periods[4] * 3600 + periods[5] * 60 + periods[6];
+ },
+
+ _instSettings: function(elem, options) {
+ return {_periods: [0, 0, 0, 0, 0, 0, 0]};
+ },
+
+ /** Add an element to the list of active ones.
+ @private
+ @param elem {Element} The countdown element. */
+ _addElem: function(elem) {
+ if (!this._hasElem(elem)) {
+ this._timerElems.push(elem);
+ }
+ },
+
+ /** See if an element is in the list of active ones.
+ @private
+ @param elem {Element} The countdown element.
+ @return {boolean} True if present, false if not. */
+ _hasElem: function(elem) {
+ return ($.inArray(elem, this._timerElems) > -1);
+ },
+
+ /** Remove an element from the list of active ones.
+ @private
+ @param elem {Element} The countdown element. */
+ _removeElem: function(elem) {
+ this._timerElems = $.map(this._timerElems,
+ function(value) { return (value == elem ? null : value); }); // delete entry
+ },
+
+ /** Update each active timer element.
+ @private */
+ _updateElems: function() {
+ for (var i = this._timerElems.length - 1; i >= 0; i--) {
+ this._updateCountdown(this._timerElems[i]);
+ }
+ },
+
+ _optionsChanged: function(elem, inst, options) {
+ if (options.layout) {
+ options.layout = options.layout.replace(/</g, '<').replace(/>/g, '>');
+ }
+ this._resetExtraLabels(inst.options, options);
+ var timezoneChanged = (inst.options.timezone != options.timezone);
+ $.extend(inst.options, options);
+ this._adjustSettings(elem, inst,
+ options.until != null || options.since != null || timezoneChanged);
+ var now = new Date();
+ if ((inst._since && inst._since < now) || (inst._until && inst._until > now)) {
+ this._addElem(elem[0]);
+ }
+ this._updateCountdown(elem, inst);
+ },
+
+ /** Redisplay the countdown with an updated display.
+ @private
+ @param elem {Element|jQuery} The containing division.
+ @param inst {object} The current settings for this instance. */
+ _updateCountdown: function(elem, inst) {
+ elem = elem.jquery ? elem : $(elem);
+ inst = inst || elem.data(this.name);
+ if (!inst) {
+ return;
+ }
+ elem.html(this._generateHTML(inst)).toggleClass(this._rtlClass, inst.options.isRTL);
+ if ($.isFunction(inst.options.onTick)) {
+ var periods = inst._hold != 'lap' ? inst._periods :
+ this._calculatePeriods(inst, inst._show, inst.options.significant, new Date());
+ if (inst.options.tickInterval == 1 ||
+ this.periodsToSeconds(periods) % inst.options.tickInterval == 0) {
+ inst.options.onTick.apply(elem[0], [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._hasElem(elem[0]) || inst.options.alwaysExpire) {
+ this._removeElem(elem[0]);
+ if ($.isFunction(inst.options.onExpiry)) {
+ inst.options.onExpiry.apply(elem[0], []);
+ }
+ if (inst.options.expiryText) {
+ var layout = inst.options.layout;
+ inst.options.layout = inst.options.expiryText;
+ this._updateCountdown(elem[0], inst);
+ inst.options.layout = layout;
+ }
+ if (inst.options.expiryUrl) {
+ window.location = inst.options.expiryUrl;
+ }
+ }
+ inst._expiring = false;
+ }else if (inst._hold == 'pause') {
+ this._removeElem(elem[0]);
+ }
+ },
+
+ /** Reset any extra labelsn and compactLabelsn entries if changing labels.
+ @private
+ @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[02-9]|compactLabels1/)) {
+ base[n] = null;
+ }
+ }
+ }
+ },
+
+ /** Calculate internal settings for an instance.
+ @private
+ @param elem {jQuery} The containing division.
+ @param inst {object} The current settings for this instance.
+ @param recalc {boolean} True if until or since are set. */
+ _adjustSettings: function(elem, inst, recalc) {
+ var now;
+ var serverOffset = 0;
+ var serverEntry = null;
+ for (var i = 0; i < this._serverSyncs.length; i++) {
+ if (this._serverSyncs[i][0] == inst.options.serverSync) {
+ serverEntry = this._serverSyncs[i][1];
+ break;
+ }
+ }
+ if (serverEntry != null) {
+ serverOffset = (inst.options.serverSync ? serverEntry : 0);
+ now = new Date();
+ }
+ else {
+ var serverResult = ($.isFunction(inst.options.serverSync) ?
+ inst.options.serverSync.apply(elem[0], []) : null);
+ now = new Date();
+ serverOffset = (serverResult ? now.getTime() - serverResult.getTime() : 0);
+ this._serverSyncs.push([inst.options.serverSync, serverOffset]);
+ }
+ var timezone = inst.options.timezone;
+ timezone = (timezone == null ? -now.getTimezoneOffset() : timezone);
+ if (recalc || (!recalc && inst._until == null && inst._since == null)) {
+ inst._since = inst.options.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(inst.options.until, now));
+ if (serverOffset) {
+ inst._until.setMilliseconds(inst._until.getMilliseconds() + serverOffset);
+ }
+ }
+ inst._show = this._determineShow(inst);
+ },
+
+ /** Remove the countdown widget from a div.
+ @param elem {jQuery} The containing division.
+ @param inst {object} The current instance object. */
+ _preDestroy: function(elem, inst) {
+ this._removeElem(elem[0]);
+ elem.empty();
+ },
+
+ /** Pause a countdown widget at the current time.
+ Stop it running but remember and display the current time.
+ @param elem {Element} The containing division.
+ @example $(selector).countdown('pause') */
+ pause: function(elem) {
+ this._hold(elem, 'pause');
+ },
+
+ /** Pause a countdown widget at the current time.
+ Stop the display but keep the countdown running.
+ @param elem {Element} The containing division.
+ @example $(selector).countdown('lap') */
+ lap: function(elem) {
+ this._hold(elem, 'lap');
+ },
+
+ /** Resume a paused countdown widget.
+ @param elem {Element} The containing division.
+ @example $(selector).countdown('resume') */
+ resume: function(elem) {
+ this._hold(elem, null);
+ },
+
+ /** Toggle a paused countdown widget.
+ @param elem {Element} The containing division.
+ @example $(selector).countdown('toggle') */
+ toggle: function(elem) {
+ var inst = $.data(elem, this.name) || {};
+ this[!inst._hold ? 'pause' : 'resume'](elem);
+ },
+
+ /** Toggle a lapped countdown widget.
+ @param elem {Element} The containing division.
+ @example $(selector).countdown('toggleLap') */
+ toggleLap: function(elem) {
+ var inst = $.data(elem, this.name) || {};
+ this[!inst._hold ? 'lap' : 'resume'](elem);
+ },
+
+ /** Pause or resume a countdown widget.
+ @private
+ @param elem {Element} The containing division.
+ @param hold {string} The new hold setting. */
+ _hold: function(elem, hold) {
+ var inst = $.data(elem, this.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._addElem(elem);
+ }
+ inst._hold = hold;
+ inst._savePeriods = (hold == 'pause' ? inst._periods : null);
+ $.data(elem, this.name, inst);
+ this._updateCountdown(elem, inst);
+ }
+ },
+
+ /** Return the current time periods.
+ @param elem {Element} The containing division.
+ @return {number[]} The current periods for the countdown.
+ @example var periods = $(selector).countdown('getTimes') */
+ getTimes: function(elem) {
+ var inst = $.data(elem, this.name);
+ return (!inst ? null : (inst._hold == 'pause' ? inst._savePeriods : (!inst._hold ? inst._periods :
+ this._calculatePeriods(inst, inst._show, inst.options.significant, new Date()))));
+ },
+
+ /** A time may be specified as an exact value or a relative one.
+ @private
+ @param setting {string|number|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 self = this;
+ 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, self._getDaysInMonth(year, month));
+ break;
+ case 'y':
+ year += parseInt(matches[1], 10);
+ day = Math.min(day, self._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.
+ @private
+ @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();
+ },
+
+ /** Default implementation to determine which set of labels should be used for an amount.
+ Use the labels
attribute with the same numeric suffix (if it exists).
+ @private
+ @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.
+ @private
+ @param inst {object} The current settings for this instance.
+ @return {string} The new HTML for the countdown display. */
+ _generateHTML: function(inst) {
+ var self = this;
+ // Determine what to show
+ inst._periods = (inst._hold ? inst._periods :
+ this._calculatePeriods(inst, inst._show, inst.options.significant, new Date()));
+ // Show all 'asNeeded' after first non-zero value
+ var shownNonZero = false;
+ var showCount = 0;
+ var sigCount = inst.options.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 labels = (inst.options.compact ? inst.options.compactLabels : inst.options.labels);
+ var whichLabels = inst.options.whichLabels || this._normalLabels;
+ var showCompact = function(period) {
+ var labelsNum = inst.options['compactLabels' + whichLabels(inst._periods[period])];
+ return (show[period] ? self._translateDigits(inst, inst._periods[period]) +
+ (labelsNum ? labelsNum[period] : labels[period]) + ' ' : '');
+ };
+ var minDigits = (inst.options.padZeroes ? 2 : 1);
+ var showFull = function(period) {
+ var labelsNum = inst.options['labels' + whichLabels(inst._periods[period])];
+ return ((!inst.options.significant && show[period]) ||
+ (inst.options.significant && showSignificant[period]) ?
+ '' +
+ '' +
+ self._minDigits(inst, inst._periods[period], minDigits) + '' +
+ '' +
+ (labelsNum ? labelsNum[period] : labels[period]) + '' : '');
+ };
+ return (inst.options.layout ? this._buildLayout(inst, show, inst.options.layout,
+ inst.options.compact, inst.options.significant, showSignificant) :
+ ((inst.options.compact ? // Compact version
+ '' +
+ showCompact(Y) + showCompact(O) + showCompact(W) + showCompact(D) +
+ (show[H] ? this._minDigits(inst, inst._periods[H], 2) : '') +
+ (show[M] ? (show[H] ? inst.options.timeSeparator : '') +
+ this._minDigits(inst, inst._periods[M], 2) : '') +
+ (show[S] ? (show[H] || show[M] ? inst.options.timeSeparator : '') +
+ this._minDigits(inst, inst._periods[S], 2) : '') :
+ // Full version
+ '' +
+ inst.options.description + '' : '')));
+ },
+
+ /** Construct a custom layout.
+ @private
+ @param inst {object} The current settings for this instance.
+ @param show {boolean[]} 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[]} Other periods to show for significance.
+ @return {string} The custom HTML. */
+ _buildLayout: function(inst, show, layout, compact, significant, showSignificant) {
+ var labels = inst.options[compact ? 'compactLabels' : 'labels'];
+ var whichLabels = inst.options.whichLabels || this._normalLabels;
+ var labelFor = function(index) {
+ return (inst.options[(compact ? 'compactLabels' : 'labels') +
+ whichLabels(inst._periods[index])] || labels)[index];
+ };
+ var digit = function(value, position) {
+ return inst.options.digits[Math.floor(value / position) % 10];
+ };
+ var subs = {desc: inst.options.description, sep: inst.options.timeSeparator,
+ yl: labelFor(Y), yn: this._minDigits(inst, inst._periods[Y], 1),
+ ynn: this._minDigits(inst, inst._periods[Y], 2),
+ ynnn: this._minDigits(inst, 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: this._minDigits(inst, inst._periods[O], 1),
+ onn: this._minDigits(inst, inst._periods[O], 2),
+ onnn: this._minDigits(inst, 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: this._minDigits(inst, inst._periods[W], 1),
+ wnn: this._minDigits(inst, inst._periods[W], 2),
+ wnnn: this._minDigits(inst, 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: this._minDigits(inst, inst._periods[D], 1),
+ dnn: this._minDigits(inst, inst._periods[D], 2),
+ dnnn: this._minDigits(inst, 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: this._minDigits(inst, inst._periods[H], 1),
+ hnn: this._minDigits(inst, inst._periods[H], 2),
+ hnnn: this._minDigits(inst, 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: this._minDigits(inst, inst._periods[M], 1),
+ mnn: this._minDigits(inst, inst._periods[M], 2),
+ mnnn: this._minDigits(inst, 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: this._minDigits(inst, inst._periods[S], 1),
+ snn: this._minDigits(inst, inst._periods[S], 2),
+ snnn: this._minDigits(inst, 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 + '<\\}([\\s\\S]*)\\{' + 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.
+ @private
+ @param inst {object} The current settings for this instance.
+ @param value {number} The value to display.
+ @param len {number} The minimum length.
+ @return {string} The display text. */
+ _minDigits: function(inst, value, len) {
+ value = '' + value;
+ if (value.length >= len) {
+ return this._translateDigits(inst, value);
+ }
+ value = '0000000000' + value;
+ return this._translateDigits(inst, value.substr(value.length - len));
+ },
+
+ /** Translate digits into other representations.
+ @private
+ @param inst {object} The current settings for this instance.
+ @param value {string} The text to translate.
+ @return {string} The translated text. */
+ _translateDigits: function(inst, value) {
+ return ('' + value).replace(/[0-9]/g, function(digit) {
+ return inst.options.digits[digit];
+ });
+ },
+
+ /** Translate the format into flags for each period.
+ @private
+ @param inst {object} The current settings for this instance.
+ @return {string[]} Flags indicating which periods are requested (?) or
+ required (!) by year, month, week, day, hour, minute, second. */
+ _determineShow: function(inst) {
+ var format = inst.options.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.
+ @private
+ @param inst {object} The current settings for this instance.
+ @param show {string[]} 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[]} 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 = this._getDaysInMonth(now.getFullYear(), now.getMonth());
+ var lastUntil = this._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 = this._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);
diff --git a/jquery.countdown.min.js b/js/jquery.countdown.min.js
similarity index 100%
rename from jquery.countdown.min.js
rename to js/jquery.countdown.min.js
diff --git a/jquery.plugin.js b/js/jquery.plugin.js
similarity index 100%
rename from jquery.plugin.js
rename to js/jquery.plugin.js
diff --git a/jquery.plugin.min.js b/js/jquery.plugin.min.js
similarity index 100%
rename from jquery.plugin.min.js
rename to js/jquery.plugin.min.js
diff --git a/jquery.countdown-ar.js b/js/localisations/ar.js
similarity index 100%
rename from jquery.countdown-ar.js
rename to js/localisations/ar.js
diff --git a/jquery.countdown-bg.js b/js/localisations/bg.js
similarity index 100%
rename from jquery.countdown-bg.js
rename to js/localisations/bg.js
diff --git a/jquery.countdown-bn.js b/js/localisations/bn.js
similarity index 100%
rename from jquery.countdown-bn.js
rename to js/localisations/bn.js
diff --git a/jquery.countdown-bs.js b/js/localisations/bs.js
similarity index 100%
rename from jquery.countdown-bs.js
rename to js/localisations/bs.js
diff --git a/jquery.countdown-ca.js b/js/localisations/ca.js
similarity index 100%
rename from jquery.countdown-ca.js
rename to js/localisations/ca.js
diff --git a/jquery.countdown-cs.js b/js/localisations/cs.js
similarity index 100%
rename from jquery.countdown-cs.js
rename to js/localisations/cs.js
diff --git a/jquery.countdown-cy.js b/js/localisations/cy.js
similarity index 100%
rename from jquery.countdown-cy.js
rename to js/localisations/cy.js
diff --git a/jquery.countdown-da.js b/js/localisations/da.js
similarity index 100%
rename from jquery.countdown-da.js
rename to js/localisations/da.js
diff --git a/jquery.countdown-de.js b/js/localisations/de.js
similarity index 100%
rename from jquery.countdown-de.js
rename to js/localisations/de.js
diff --git a/jquery.countdown-el.js b/js/localisations/el.js
similarity index 100%
rename from jquery.countdown-el.js
rename to js/localisations/el.js
diff --git a/jquery.countdown-es.js b/js/localisations/es.js
similarity index 100%
rename from jquery.countdown-es.js
rename to js/localisations/es.js
diff --git a/jquery.countdown-et.js b/js/localisations/et.js
similarity index 100%
rename from jquery.countdown-et.js
rename to js/localisations/et.js
diff --git a/jquery.countdown-fa.js b/js/localisations/fa.js
similarity index 100%
rename from jquery.countdown-fa.js
rename to js/localisations/fa.js
diff --git a/jquery.countdown-fi.js b/js/localisations/fi.js
similarity index 100%
rename from jquery.countdown-fi.js
rename to js/localisations/fi.js
diff --git a/jquery.countdown-fr.js b/js/localisations/fr.js
similarity index 100%
rename from jquery.countdown-fr.js
rename to js/localisations/fr.js
diff --git a/jquery.countdown-gl.js b/js/localisations/gl.js
similarity index 100%
rename from jquery.countdown-gl.js
rename to js/localisations/gl.js
diff --git a/jquery.countdown-gu.js b/js/localisations/gu.js
similarity index 100%
rename from jquery.countdown-gu.js
rename to js/localisations/gu.js
diff --git a/jquery.countdown-he.js b/js/localisations/he.js
similarity index 100%
rename from jquery.countdown-he.js
rename to js/localisations/he.js
diff --git a/jquery.countdown-hr.js b/js/localisations/hr.js
similarity index 100%
rename from jquery.countdown-hr.js
rename to js/localisations/hr.js
diff --git a/jquery.countdown-hu.js b/js/localisations/hu.js
similarity index 100%
rename from jquery.countdown-hu.js
rename to js/localisations/hu.js
diff --git a/jquery.countdown-hy.js b/js/localisations/hy.js
similarity index 100%
rename from jquery.countdown-hy.js
rename to js/localisations/hy.js
diff --git a/jquery.countdown-id.js b/js/localisations/id.js
similarity index 100%
rename from jquery.countdown-id.js
rename to js/localisations/id.js
diff --git a/jquery.countdown-it.js b/js/localisations/it.js
similarity index 100%
rename from jquery.countdown-it.js
rename to js/localisations/it.js
diff --git a/jquery.countdown-ja.js b/js/localisations/ja.js
similarity index 100%
rename from jquery.countdown-ja.js
rename to js/localisations/ja.js
diff --git a/jquery.countdown-kn.js b/js/localisations/kn.js
similarity index 100%
rename from jquery.countdown-kn.js
rename to js/localisations/kn.js
diff --git a/jquery.countdown-ko.js b/js/localisations/ko.js
similarity index 100%
rename from jquery.countdown-ko.js
rename to js/localisations/ko.js
diff --git a/jquery.countdown-lt.js b/js/localisations/lt.js
similarity index 100%
rename from jquery.countdown-lt.js
rename to js/localisations/lt.js
diff --git a/jquery.countdown-lv.js b/js/localisations/lv.js
similarity index 100%
rename from jquery.countdown-lv.js
rename to js/localisations/lv.js
diff --git a/jquery.countdown-ml.js b/js/localisations/ml.js
similarity index 100%
rename from jquery.countdown-ml.js
rename to js/localisations/ml.js
diff --git a/jquery.countdown-ms.js b/js/localisations/ms.js
similarity index 100%
rename from jquery.countdown-ms.js
rename to js/localisations/ms.js
diff --git a/jquery.countdown-my.js b/js/localisations/my.js
similarity index 100%
rename from jquery.countdown-my.js
rename to js/localisations/my.js
diff --git a/jquery.countdown-nb.js b/js/localisations/nb.js
similarity index 100%
rename from jquery.countdown-nb.js
rename to js/localisations/nb.js
diff --git a/jquery.countdown-nl.js b/js/localisations/nl.js
similarity index 100%
rename from jquery.countdown-nl.js
rename to js/localisations/nl.js
diff --git a/jquery.countdown-pl.js b/js/localisations/pl.js
similarity index 100%
rename from jquery.countdown-pl.js
rename to js/localisations/pl.js
diff --git a/jquery.countdown-pt-BR.js b/js/localisations/pt-BR.js
similarity index 100%
rename from jquery.countdown-pt-BR.js
rename to js/localisations/pt-BR.js
diff --git a/jquery.countdown-ro.js b/js/localisations/ro.js
similarity index 100%
rename from jquery.countdown-ro.js
rename to js/localisations/ro.js
diff --git a/jquery.countdown-ru.js b/js/localisations/ru.js
similarity index 100%
rename from jquery.countdown-ru.js
rename to js/localisations/ru.js
diff --git a/jquery.countdown-sk.js b/js/localisations/sk.js
similarity index 100%
rename from jquery.countdown-sk.js
rename to js/localisations/sk.js
diff --git a/jquery.countdown-sl.js b/js/localisations/sl.js
similarity index 100%
rename from jquery.countdown-sl.js
rename to js/localisations/sl.js
diff --git a/jquery.countdown-sq.js b/js/localisations/sq.js
similarity index 100%
rename from jquery.countdown-sq.js
rename to js/localisations/sq.js
diff --git a/jquery.countdown-sr-SR.js b/js/localisations/sr-SR.js
similarity index 100%
rename from jquery.countdown-sr-SR.js
rename to js/localisations/sr-SR.js
diff --git a/jquery.countdown-sr.js b/js/localisations/sr.js
similarity index 100%
rename from jquery.countdown-sr.js
rename to js/localisations/sr.js
diff --git a/jquery.countdown-sv.js b/js/localisations/sv.js
similarity index 100%
rename from jquery.countdown-sv.js
rename to js/localisations/sv.js
diff --git a/jquery.countdown-th.js b/js/localisations/th.js
similarity index 100%
rename from jquery.countdown-th.js
rename to js/localisations/th.js
diff --git a/jquery.countdown-tr.js b/js/localisations/tr.js
similarity index 100%
rename from jquery.countdown-tr.js
rename to js/localisations/tr.js
diff --git a/jquery.countdown-uk.js b/js/localisations/uk.js
similarity index 100%
rename from jquery.countdown-uk.js
rename to js/localisations/uk.js
diff --git a/jquery.countdown-ur.js b/js/localisations/ur.js
similarity index 100%
rename from jquery.countdown-ur.js
rename to js/localisations/ur.js
diff --git a/jquery.countdown-uz.js b/js/localisations/uz.js
similarity index 100%
rename from jquery.countdown-uz.js
rename to js/localisations/uz.js
diff --git a/jquery.countdown-vi.js b/js/localisations/vi.js
similarity index 100%
rename from jquery.countdown-vi.js
rename to js/localisations/vi.js
diff --git a/jquery.countdown-zh-CN.js b/js/localisations/zh-CN.js
similarity index 100%
rename from jquery.countdown-zh-CN.js
rename to js/localisations/zh-CN.js
diff --git a/jquery.countdown-zh-TW.js b/js/localisations/zh-TW.js
similarity index 100%
rename from jquery.countdown-zh-TW.js
rename to js/localisations/zh-TW.js
' +
+ (inst.options.description ? ' ' +
- (inst.options.description ? '