123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792 |
- (function ($, undefined) {
- var ms = $.mobiscroll,
- datetime = ms.datetime,
- date = new Date(),
- defaults = {
- startYear: date.getFullYear() - 100,
- endYear: date.getFullYear() + 1,
- separator: ' ',
- // Localization
- dateFormat: 'mm/dd/yy',
- dateOrder: 'mmddy',
- timeWheels: 'hhiiA',
- timeFormat: 'hh:ii A',
- dayText: 'Day',
- monthText: 'Month',
- yearText: 'Year',
- hourText: 'Hours',
- minuteText: 'Minutes',
- ampmText: ' ',
- secText: 'Seconds',
- nowText: 'Now'
- },
- /**
- * @class Mobiscroll.datetime
- * @extends Mobiscroll
- * Mobiscroll Datetime component
- */
- preset = function (inst) {
- var that = $(this),
- html5def = {},
- format;
- // Force format for html5 date inputs (experimental)
- if (that.is('input')) {
- switch (that.attr('type')) {
- case 'date':
- format = 'yy-mm-dd';
- break;
- case 'datetime':
- format = 'yy-mm-ddTHH:ii:ssZ';
- break;
- case 'datetime-local':
- format = 'yy-mm-ddTHH:ii:ss';
- break;
- case 'month':
- format = 'yy-mm';
- html5def.dateOrder = 'mmyy';
- break;
- case 'time':
- format = 'HH:ii:ss';
- break;
- }
- // Check for min/max attributes
- var min = that.attr('min'),
- max = that.attr('max');
- if (min) {
- html5def.minDate = datetime.parseDate(format, min);
- }
- if (max) {
- html5def.maxDate = datetime.parseDate(format, max);
- }
- }
- // Set year-month-day order
- var i,
- k,
- keys,
- values,
- wg,
- start,
- end,
- hasTime,
- mins,
- maxs,
- orig = $.extend({}, inst.settings),
- s = $.extend(inst.settings, ms.datetime.defaults, defaults, html5def, orig),
- offset = 0,
- validValues = [],
- wheels = [],
- ord = [],
- o = {},
- innerValues = {},
- f = { y: getYear, m: getMonth, d: getDay, h: getHour, i: getMinute, s: getSecond, u: getMillisecond, a: getAmPm },
- invalid = s.invalid,
- valid = s.valid,
- p = s.preset,
- dord = s.dateOrder,
- tord = s.timeWheels,
- regen = dord.match(/D/),
- ampm = tord.match(/a/i),
- hampm = tord.match(/h/),
- hformat = p == 'datetime' ? s.dateFormat + s.separator + s.timeFormat : p == 'time' ? s.timeFormat : s.dateFormat,
- defd = new Date(),
- steps = s.steps || {},
- stepH = steps.hour || s.stepHour || 1,
- stepM = steps.minute || s.stepMinute || 1,
- stepS = steps.second || s.stepSecond || 1,
- zeroBased = steps.zeroBased,
- mind = s.minDate || new Date(s.startYear, 0, 1),
- maxd = s.maxDate || new Date(s.endYear, 11, 31, 23, 59, 59),
- minH = zeroBased ? 0 : mind.getHours() % stepH,
- minM = zeroBased ? 0 : mind.getMinutes() % stepM,
- minS = zeroBased ? 0 : mind.getSeconds() % stepS,
- maxH = getMax(stepH, minH, (hampm ? 11 : 23)),
- maxM = getMax(stepM, minM, 59),
- maxS = getMax(stepM, minM, 59);
- format = format || hformat;
- if (p.match(/date/i)) {
- // Determine the order of year, month, day wheels
- $.each(['y', 'm', 'd'], function (j, v) {
- i = dord.search(new RegExp(v, 'i'));
- if (i > -1) {
- ord.push({ o: i, v: v });
- }
- });
- ord.sort(function (a, b) { return a.o > b.o ? 1 : -1; });
- $.each(ord, function (i, v) {
- o[v.v] = i;
- });
- wg = [];
- for (k = 0; k < 3; k++) {
- if (k == o.y) {
- offset++;
- values = [];
- keys = [];
- start = s.getYear(mind);
- end = s.getYear(maxd);
- for (i = start; i <= end; i++) {
- keys.push(i);
- values.push((dord.match(/yy/i) ? i : (i + '').substr(2, 2)) + (s.yearSuffix || ''));
- }
- addWheel(wg, keys, values, s.yearText);
- } else if (k == o.m) {
- offset++;
- values = [];
- keys = [];
- for (i = 0; i < 12; i++) {
- var str = dord.replace(/[dy]/gi, '').replace(/mm/, (i < 9 ? '0' + (i + 1) : i + 1) + (s.monthSuffix || '')).replace(/m/, i + 1 + (s.monthSuffix || ''));
- keys.push(i);
- values.push(str.match(/MM/) ? str.replace(/MM/, '<span class="dw-mon">' + s.monthNames[i] + '</span>') : str.replace(/M/, '<span class="dw-mon">' + s.monthNamesShort[i] + '</span>'));
- }
- addWheel(wg, keys, values, s.monthText);
- } else if (k == o.d) {
- offset++;
- values = [];
- keys = [];
- for (i = 1; i < 32; i++) {
- keys.push(i);
- values.push((dord.match(/dd/i) && i < 10 ? '0' + i : i) + (s.daySuffix || ''));
- }
- addWheel(wg, keys, values, s.dayText);
- }
- }
- wheels.push(wg);
- }
- if (p.match(/time/i)) {
- hasTime = true;
- // Determine the order of hours, minutes, seconds wheels
- ord = [];
- $.each(['h', 'i', 's', 'a'], function (i, v) {
- i = tord.search(new RegExp(v, 'i'));
- if (i > -1) {
- ord.push({ o: i, v: v });
- }
- });
- ord.sort(function (a, b) {
- return a.o > b.o ? 1 : -1;
- });
- $.each(ord, function (i, v) {
- o[v.v] = offset + i;
- });
- wg = [];
- for (k = offset; k < offset + 4; k++) {
- if (k == o.h) {
- offset++;
- values = [];
- keys = [];
- for (i = minH; i < (hampm ? 12 : 24); i += stepH) {
- keys.push(i);
- values.push(hampm && i === 0 ? 12 : tord.match(/hh/i) && i < 10 ? '0' + i : i);
- }
- addWheel(wg, keys, values, s.hourText);
- } else if (k == o.i) {
- offset++;
- values = [];
- keys = [];
- for (i = minM; i < 60; i += stepM) {
- keys.push(i);
- values.push(tord.match(/ii/) && i < 10 ? '0' + i : i);
- }
- addWheel(wg, keys, values, s.minuteText);
- } else if (k == o.s) {
- offset++;
- values = [];
- keys = [];
- for (i = minS; i < 60; i += stepS) {
- keys.push(i);
- values.push(tord.match(/ss/) && i < 10 ? '0' + i : i);
- }
- addWheel(wg, keys, values, s.secText);
- } else if (k == o.a) {
- offset++;
- var upper = tord.match(/A/);
- addWheel(wg, [0, 1], upper ? [s.amText.toUpperCase(), s.pmText.toUpperCase()] : [s.amText, s.pmText], s.ampmText);
- }
- }
- wheels.push(wg);
- }
- function get(d, i, def) {
- if (o[i] !== undefined) {
- return +d[o[i]];
- }
- if (innerValues[i] !== undefined) {
- return innerValues[i];
- }
- if (def !== undefined) {
- return def;
- }
- return f[i](defd);
- }
- function addWheel(wg, k, v, lbl) {
- wg.push({
- values: v,
- keys: k,
- label: lbl
- });
- }
- function step(v, st, min, max) {
- return Math.min(max, Math.floor(v / st) * st + min);
- }
- function getYear(d) {
- return s.getYear(d);
- }
- function getMonth(d) {
- return s.getMonth(d);
- }
- function getDay(d) {
- return s.getDay(d);
- }
- function getHour(d) {
- var hour = d.getHours();
- hour = hampm && hour >= 12 ? hour - 12 : hour;
- return step(hour, stepH, minH, maxH);
- }
- function getMinute(d) {
- return step(d.getMinutes(), stepM, minM, maxM);
- }
- function getSecond(d) {
- return step(d.getSeconds(), stepS, minS, maxS);
- }
- function getMillisecond(d) {
- return d.getMilliseconds();
- }
- function getAmPm(d) {
- return ampm && d.getHours() > 11 ? 1 : 0;
- }
- function getDate(d) {
- if (d === null) {
- return d;
- }
- var year = get(d, 'y'),
- month = get(d, 'm'),
- day = Math.min(get(d, 'd', 1), s.getMaxDayOfMonth(year, month)),
- hour = get(d, 'h', 0);
- return s.getDate(year, month, day, get(d, 'a', 0) ? hour + 12 : hour, get(d, 'i', 0), get(d, 's', 0), get(d, 'u', 0));
- }
- function getMax(step, min, max) {
- return Math.floor((max - min) / step) * step + min;
- }
- function getClosestValidDate(d, dir) {
- var next,
- prev,
- nextValid = false,
- prevValid = false,
- up = 0,
- down = 0;
- // Normalize min and max dates for comparing later (set default values where there are no values from wheels)
- mind = getDate(getArray(mind));
- maxd = getDate(getArray(maxd));
- if (isValid(d)) {
- return d;
- }
- if (d < mind) {
- d = mind;
- }
- if (d > maxd) {
- d = maxd;
- }
- next = d;
- prev = d;
- if (dir !== 2) {
- nextValid = isValid(next);
- while (!nextValid && next < maxd) {
- next = new Date(next.getTime() + 1000 * 60 * 60 * 24);
- nextValid = isValid(next);
- up++;
- }
- }
- if (dir !== 1) {
- prevValid = isValid(prev);
- while (!prevValid && prev > mind) {
- prev = new Date(prev.getTime() - 1000 * 60 * 60 * 24);
- prevValid = isValid(prev);
- down++;
- }
- }
- if (dir === 1 && nextValid) {
- return next;
- }
- if (dir === 2 && prevValid) {
- return prev;
- }
- return down <= up && prevValid ? prev : next;
- }
- function isValid(d) {
- if (d < mind) {
- return false;
- }
- if (d > maxd) {
- return false;
- }
- if (isInObj(d, valid)) {
- return true;
- }
- if (isInObj(d, invalid)) {
- return false;
- }
- return true;
- }
- function isInObj(d, obj) {
- var curr,
- j,
- v;
- if (obj) {
- for (j = 0; j < obj.length; j++) {
- curr = obj[j];
- v = curr + '';
- if (!curr.start) {
- if (curr.getTime) { // Exact date
- if (d.getFullYear() == curr.getFullYear() && d.getMonth() == curr.getMonth() && d.getDate() == curr.getDate()) {
- return true;
- }
- } else if (!v.match(/w/i)) { // Day of month
- v = v.split('/');
- if (v[1]) {
- if ((v[0] - 1) == d.getMonth() && v[1] == d.getDate()) {
- return true;
- }
- } else if (v[0] == d.getDate()) {
- return true;
- }
- } else { // Day of week
- v = +v.replace('w', '');
- if (v == d.getDay()) {
- return true;
- }
- }
- }
- }
- }
- return false;
- }
- function validateDates(obj, y, m, first, maxdays, idx, val) {
- var j, d, v;
- if (obj) {
- for (j = 0; j < obj.length; j++) {
- d = obj[j];
- v = d + '';
- if (!d.start) {
- if (d.getTime) { // Exact date
- if (s.getYear(d) == y && s.getMonth(d) == m) {
- idx[s.getDay(d) - 1] = val;
- }
- } else if (!v.match(/w/i)) { // Day of month
- v = v.split('/');
- if (v[1]) {
- if (v[0] - 1 == m) {
- idx[v[1] - 1] = val;
- }
- } else {
- idx[v[0] - 1] = val;
- }
- } else { // Day of week
- v = +v.replace('w', '');
- for (k = v - first; k < maxdays; k += 7) {
- if (k >= 0) {
- idx[k] = val;
- }
- }
- }
- }
- }
- }
- }
- function validateTimes(vobj, i, v, temp, y, m, d, target, valid) {
- var dd, ss, str, parts1, parts2, prop1, prop2, v1, v2, j, i1, i2, add, remove, all, hours1, hours2, hours3,
- spec = {},
- steps = { h: stepH, i: stepM, s: stepS, a: 1 },
- day = s.getDate(y, m, d),
- w = ['a', 'h', 'i', 's'];
- if (vobj) {
- $.each(vobj, function (i, obj) {
- if (obj.start) {
- obj.apply = false;
- dd = obj.d;
- ss = dd + '';
- str = ss.split('/');
- if (dd && ((dd.getTime && y == s.getYear(dd) && m == s.getMonth(dd) && d == s.getDay(dd)) || // Exact date
- (!ss.match(/w/i) && ((str[1] && d == str[1] && m == str[0] - 1) || (!str[1] && d == str[0]))) || // Day of month
- (ss.match(/w/i) && day.getDay() == +ss.replace('w', '')) // Day of week
- )) {
- obj.apply = true;
- spec[day] = true; // Prevent applying generic rule on day, if specific exists
- }
- }
- });
- $.each(vobj, function (x, obj) {
- add = 0;
- remove = 0;
- i1 = 0;
- i2 = undefined;
- prop1 = true;
- prop2 = true;
- all = false;
- if (obj.start && (obj.apply || (!obj.d && !spec[day]))) {
- // Define time parts
- parts1 = obj.start.split(':');
- parts2 = obj.end.split(':');
- for (j = 0; j < 3; j++) {
- if (parts1[j] === undefined) {
- parts1[j] = 0;
- }
- if (parts2[j] === undefined) {
- parts2[j] = 59;
- }
- parts1[j] = +parts1[j];
- parts2[j] = +parts2[j];
- }
- parts1.unshift(parts1[0] > 11 ? 1 : 0);
- parts2.unshift(parts2[0] > 11 ? 1 : 0);
- if (hampm) {
- if (parts1[1] >= 12) {
- parts1[1] = parts1[1] - 12;
- }
- if (parts2[1] >= 12) {
- parts2[1] = parts2[1] - 12;
- }
- }
- // Look behind
- for (j = 0; j < i; j++) {
- if (validValues[j] !== undefined) {
- v1 = step(parts1[j], steps[w[j]], mins[w[j]], maxs[w[j]]);
- v2 = step(parts2[j], steps[w[j]], mins[w[j]], maxs[w[j]]);
- hours1 = 0;
- hours2 = 0;
- hours3 = 0;
- if (hampm && j == 1) {
- hours1 = parts1[0] ? 12 : 0;
- hours2 = parts2[0] ? 12 : 0;
- hours3 = validValues[0] ? 12 : 0;
- }
- if (!prop1) {
- v1 = 0;
- }
- if (!prop2) {
- v2 = maxs[w[j]];
- }
- if ((prop1 || prop2) && (v1 + hours1 < validValues[j] + hours3 && validValues[j] + hours3 < v2 + hours2)) {
- all = true;
- }
- if (validValues[j] != v1) {
- prop1 = false;
- }
- if (validValues[j] != v2) {
- prop2 = false;
- }
- }
- }
- // Look ahead
- if (!valid) {
- for (j = i + 1; j < 4; j++) {
- if (parts1[j] > 0) {
- add = steps[v];
- }
- if (parts2[j] < maxs[w[j]]) {
- remove = steps[v];
- }
- }
- }
-
- if (!all) {
- // Calculate min and max values
- v1 = step(parts1[i], steps[v], mins[v], maxs[v]) + add;
- v2 = step(parts2[i], steps[v], mins[v], maxs[v]) - remove;
- if (prop1) {
- i1 = getValidIndex(target, v1, maxs[v], 0);
- }
- if (prop2) {
- i2 = getValidIndex(target, v2, maxs[v], 1);
- }
- }
- // Disable values
- if (prop1 || prop2 || all) {
- if (valid) {
- $('.dw-li', target).slice(i1, i2).addClass('dw-v');
- } else {
- $('.dw-li', target).slice(i1, i2).removeClass('dw-v');
- }
- }
-
- }
- });
- }
- }
- function getIndex(t, v) {
- return $('.dw-li', t).index($('.dw-li[data-val="' + v + '"]', t));
- }
- function getValidIndex(t, v, max, add) {
- if (v < 0) {
- return 0;
- }
- if (v > max) {
- return $('.dw-li', t).length;
- }
- return getIndex(t, v) + add;
- }
- function getArray(d, fillInner) {
- var ret = [];
- if (d === null || d === undefined) {
- return d;
- }
- $.each(['y', 'm', 'd', 'a', 'h', 'i', 's', 'u'], function (x, i) {
- if (o[i] !== undefined) {
- ret[o[i]] = f[i](d);
- }
- if (fillInner) {
- innerValues[i] = f[i](d);
- }
- });
- return ret;
- }
- function convertRanges(arr) {
- var i, v, start,
- ret = [];
- if (arr) {
- for (i = 0; i < arr.length; i++) {
- v = arr[i];
- if (v.start && v.start.getTime) {
- start = new Date(v.start);
- while (start <= v.end) {
- ret.push(new Date(start.getFullYear(), start.getMonth(), start.getDate()));
- start.setDate(start.getDate() + 1);
- }
- } else {
- ret.push(v);
- }
- }
- return ret;
- }
- return arr;
- }
- // Extended methods
- // ---
- inst.getVal = function (temp) {
- return inst._hasValue || temp ? getDate(inst.getArrayVal(temp)) : null;
- };
- /**
- * Sets the selected date
- *
- * @param {Date} d Date to select.
- * @param {Boolean} [fill=false] Also set the value of the associated input element. Default is true.
- * @param {Number} [time=0] Animation time to scroll to the selected date.
- * @param {Boolean} [temp=false] Set temporary value only.
- * @param {Boolean} [change=fill] Trigger change on input element.
- */
- inst.setDate = function (d, fill, time, temp, change) {
- inst.setArrayVal(getArray(d), fill, change, temp, time);
- };
- /**
- * Returns the selected date.
- *
- * @param {Boolean} [temp=false] If true, return the currently shown date on the picker, otherwise the last selected one.
- * @return {Date}
- */
- inst.getDate = inst.getVal;
- // ---
- // Initializations
- // ---
- inst.format = hformat;
- inst.order = o;
- inst.handlers.now = function () { inst.setDate(new Date(), false, 0.3, true, true); };
- inst.buttons.now = { text: s.nowText, handler: 'now' };
- invalid = convertRanges(invalid);
- valid = convertRanges(valid);
- mins = { y: mind.getFullYear(), m: 0, d: 1, h: minH, i: minM, s: minS, a: 0 };
- maxs = { y: maxd.getFullYear(), m: 11, d: 31, h: maxH, i: maxM, s: maxS, a: 1 };
- // ---
- return {
- wheels: wheels,
- headerText: s.headerText ? function () {
- return datetime.formatDate(hformat, getDate(inst.getArrayVal(true)), s);
- } : false,
- formatValue: function (d) {
- return datetime.formatDate(format, getDate(d), s);
- },
- parseValue: function (val) {
- if (!val) {
- innerValues = {};
- }
- return getArray(val ? datetime.parseDate(format, val, s) : (s.defaultValue || new Date()), !!val && !!val.getTime);
- },
- validate: function (dw, i, time, dir) {
- var validated = getClosestValidDate(getDate(inst.getArrayVal(true)), dir),
- temp = getArray(validated),
- y = get(temp, 'y'),
- m = get(temp, 'm'),
- minprop = true,
- maxprop = true;
- $.each(['y', 'm', 'd', 'a', 'h', 'i', 's'], function (x, i) {
- if (o[i] !== undefined) {
- var min = mins[i],
- max = maxs[i],
- maxdays = 31,
- val = get(temp, i),
- t = $('.dw-ul', dw).eq(o[i]);
- if (i == 'd') {
- maxdays = s.getMaxDayOfMonth(y, m);
- max = maxdays;
- if (regen) {
- $('.dw-li', t).each(function () {
- var that = $(this),
- d = that.data('val'),
- w = s.getDate(y, m, d).getDay(),
- str = dord.replace(/[my]/gi, '').replace(/dd/, (d < 10 ? '0' + d : d) + (s.daySuffix || '')).replace(/d/, d + (s.daySuffix || ''));
- $('.dw-i', that).html(str.match(/DD/) ? str.replace(/DD/, '<span class="dw-day">' + s.dayNames[w] + '</span>') : str.replace(/D/, '<span class="dw-day">' + s.dayNamesShort[w] + '</span>'));
- });
- }
- }
- if (minprop && mind) {
- min = f[i](mind);
- }
- if (maxprop && maxd) {
- max = f[i](maxd);
- }
- if (i != 'y') {
- var i1 = getIndex(t, min),
- i2 = getIndex(t, max);
- $('.dw-li', t).removeClass('dw-v').slice(i1, i2 + 1).addClass('dw-v');
- if (i == 'd') { // Hide days not in month
- $('.dw-li', t).removeClass('dw-h').slice(maxdays).addClass('dw-h');
- }
- }
- if (val < min) {
- val = min;
- }
- if (val > max) {
- val = max;
- }
- if (minprop) {
- minprop = val == min;
- }
- if (maxprop) {
- maxprop = val == max;
- }
- // Disable some days
- if (i == 'd') {
- var first = s.getDate(y, m, 1).getDay(),
- idx = {};
- // Set invalid indexes
- validateDates(invalid, y, m, first, maxdays, idx, 1);
- // Delete indexes which are valid
- validateDates(valid, y, m, first, maxdays, idx, 0);
- $.each(idx, function (i, v) {
- if (v) {
- $('.dw-li', t).eq(i).removeClass('dw-v');
- }
- });
- }
- }
- });
- // Invalid times
- if (hasTime) {
- $.each(['a', 'h', 'i', 's'], function (i, v) {
- var val = get(temp, v),
- d = get(temp, 'd'),
- t = $('.dw-ul', dw).eq(o[v]);
- if (o[v] !== undefined) {
- validateTimes(invalid, i, v, temp, y, m, d, t, 0);
- validateTimes(valid, i, v, temp, y, m, d, t, 1);
- // Get valid value
- validValues[i] = +inst.getValidCell(val, t, dir).val;
- }
- });
- }
- inst._tempWheelArray = temp;
- }
- };
- };
- $.each(['date', 'time', 'datetime'], function (i, v) {
- ms.presets.scroller[v] = preset;
- });
- })(jQuery);
|