Changeset 133565 in webkit


Ignore:
Timestamp:
Nov 5, 2012 11:18:12 PM (11 years ago)
Author:
keishi@webkit.org
Message:

Introduce Day class to calendar picker
https://bugs.webkit.org/show_bug.cgi?id=101194

Reviewed by Kent Tamura.

Introducing Day class so day, week, and month can all be abstracted. To
solve some of the complexity around which months to show, I made
CalendarPicker in charge of it. This also made YearMonthController and
DaysTable independent of each other.

No new tests. Covered by existing calendar-picker-*.html tests.

  • Resources/pagepopups/calendarPicker.js:

(createUTCDate): Allow negative month or date.
(parseDateString): Will return Day or Month depending on string format.
(Day): Represents a day.
(Day.parse): Parse yyyy-mm-dd.
(Day.createFromDate): Creates a Day that contains a datetime.
(Day.createFromToday): Creates Day for today. A method with the same name will be added to Week and Month in the future.
(Day.prototype.equals): Returns true if they are the same.
(Day.prototype.previous): Returns the previous day.
(Day.prototype.next): Returns the next day.
(Day.prototype.startDate): Returns the datetime that is the start of this day.
(Day.prototype.endDate): Returns the datetime that is the start of this day.
(Day.prototype.valueOf): Returns the milliseconds since epoch.
(Day.prototype.toString): Returns an ISO date string.
(Month): Fix bug in calculating month from value.
(Month.prototype.endDate): Use Day.Maximum.
(CalendarPicker): Added _currentMonth. yearMonthController and daysTable can be private members now.
(CalendarPicker.prototype._layout):
(CalendarPicker.prototype.handleToday): Use Day.createFromToday.
(CalendarPicker.prototype.shouldShowMonth): Returns true if the month should be shown.
(CalendarPicker.prototype.showMonth): Shows the given month. If the month is out of the range of months that should be shown, we clamp the month and show that.
(CalendarPicker.prototype.currentMonth): Returns the current month that is shown.
(YearMonthController): Removed _currentMonth.
(YearMonthController.prototype.attachTo):
(YearMonthController.prototype.setMonth):
(YearMonthController.prototype._handleYearMonthChange): Use CalendarPicker.showMonth
(YearMonthController.prototype.moveRelatively):
(DaysTable):
(CalendarPicker.prototype._stepMismatch): Made private.
(CalendarPicker.prototype._outOfRange): Made private.
(CalendarPicker.prototype.isValidDate): Take Day or Month instead of milliseconds since epoch.
(DaysTable.prototype._renderMonth):
(DaysTable.prototype.navigateToMonth): Shows a given month. Can use animation and leave the selection position as is.
(DaysTable.prototype.selectRange): Select a range.
(DaysTable.prototype._maybeSetPreviousMonth):
(DaysTable.prototype._maybeSetNextMonth):
(DaysTable.prototype._handleKey):
(CalendarPicker.prototype._handleBodyKeyDown):

Location:
trunk/Source/WebCore
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r133563 r133565  
     12012-11-05  Keishi Hattori  <keishi@webkit.org>
     2
     3        Introduce Day class to calendar picker
     4        https://bugs.webkit.org/show_bug.cgi?id=101194
     5
     6        Reviewed by Kent Tamura.
     7
     8        Introducing Day class so day, week, and month can all be abstracted. To
     9        solve some of the complexity around which months to show, I made
     10        CalendarPicker in charge of it. This also made YearMonthController and
     11        DaysTable independent of each other.
     12
     13        No new tests. Covered by existing calendar-picker-*.html tests.
     14
     15        * Resources/pagepopups/calendarPicker.js:
     16        (createUTCDate): Allow negative month or date.
     17        (parseDateString): Will return Day or Month depending on string format.
     18        (Day): Represents a day.
     19        (Day.parse): Parse yyyy-mm-dd.
     20        (Day.createFromDate): Creates a Day that contains a datetime.
     21        (Day.createFromToday): Creates Day for today. A method with the same name will be added to Week and Month in the future.
     22        (Day.prototype.equals): Returns true if they are the same.
     23        (Day.prototype.previous): Returns the previous day.
     24        (Day.prototype.next): Returns the next day.
     25        (Day.prototype.startDate): Returns the datetime that is the start of this day.
     26        (Day.prototype.endDate): Returns the datetime that is the start of this day.
     27        (Day.prototype.valueOf): Returns the milliseconds since epoch.
     28        (Day.prototype.toString): Returns an ISO date string.
     29        (Month): Fix bug in calculating month from value.
     30        (Month.prototype.endDate): Use Day.Maximum.
     31        (CalendarPicker): Added _currentMonth. yearMonthController and daysTable can be private members now.
     32        (CalendarPicker.prototype._layout):
     33        (CalendarPicker.prototype.handleToday): Use Day.createFromToday.
     34        (CalendarPicker.prototype.shouldShowMonth): Returns true if the month should be shown.
     35        (CalendarPicker.prototype.showMonth): Shows the given month. If the month is out of the range of months that should be shown, we clamp the month and show that.
     36        (CalendarPicker.prototype.currentMonth): Returns the current month that is shown.
     37        (YearMonthController): Removed _currentMonth.
     38        (YearMonthController.prototype.attachTo):
     39        (YearMonthController.prototype.setMonth):
     40        (YearMonthController.prototype._handleYearMonthChange): Use CalendarPicker.showMonth
     41        (YearMonthController.prototype.moveRelatively):
     42        (DaysTable):
     43        (CalendarPicker.prototype._stepMismatch): Made private.
     44        (CalendarPicker.prototype._outOfRange): Made private.
     45        (CalendarPicker.prototype.isValidDate): Take Day or Month instead of milliseconds since epoch.
     46        (DaysTable.prototype._renderMonth):
     47        (DaysTable.prototype.navigateToMonth): Shows a given month. Can use animation and leave the selection position as is.
     48        (DaysTable.prototype.selectRange): Select a range.
     49        (DaysTable.prototype._maybeSetPreviousMonth):
     50        (DaysTable.prototype._maybeSetNextMonth):
     51        (DaysTable.prototype._handleKey):
     52        (CalendarPicker.prototype._handleBodyKeyDown):
     53
    1542012-11-05  Kenichi Ishibashi  <bashi@chromium.org>
    255
  • trunk/Source/WebCore/Resources/pagepopups/calendarPicker.js

    r133434 r133565  
    176176
    177177function createUTCDate(year, month, date) {
    178     var newDate = new Date(Date.UTC(year, month, date));
    179     if (year < 100)
    180         newDate.setUTCFullYear(year);
     178    var newDate = new Date(0);
     179    newDate.setUTCFullYear(year);
     180    newDate.setUTCMonth(month);
     181    newDate.setUTCDate(date);
    181182    return newDate;
    182183};
    183184
    184185/**
    185  * @param {string=} opt_current
     186 * @param {string} dateString
     187 * @return {?Day|Month}
     188 */
     189function parseDateString(dateString) {
     190    var month = Month.parse(dateString);
     191    if (month)
     192        return month;
     193    return Day.parse(dateString);
     194}
     195
     196/**
     197 * @param {!number|Day} valueOrDayOrYear
     198 * @param {!number=} month
     199 * @param {!number=} date
     200 */
     201function Day(valueOrDayOrYear, month, date) {
     202    var dateObject;
     203    if (arguments.length == 3)
     204        dateObject = createUTCDate(valueOrDayOrYear, month, date);
     205    else if (valueOrDayOrYear instanceof Day)
     206        dateObject = createUTCDate(valueOrDayOrYear.year, valueOrDayOrYear.month, valueOrDayOrYear.date);
     207    else
     208        dateObject = new Date(valueOrDayOrYear);
     209    this.year = dateObject.getUTCFullYear();   
     210    this.month = dateObject.getUTCMonth();
     211    this.date = dateObject.getUTCDate();
     212};
     213
     214Day.ISOStringRegExp = /^(\d+)-(\d+)-(\d+)$/;
     215
     216// See WebCore/platform/DateComponents.h.
     217Day.Minimum = new Date(-62135596800000.0);
     218Day.Maximum = new Date(8640000000000000.0);
     219
     220/**
     221 * @param {!string} str
     222 * @return {?Month}
     223 */
     224Day.parse = function(str) {
     225    var match = Day.ISOStringRegExp.exec(str);
     226    if (!match)
     227        return null;
     228    var year = parseInt(match[1], 10);
     229    var month = parseInt(match[2], 10) - 1;
     230    var date = parseInt(match[3], 10);
     231    return new Day(year, month, date);
     232};
     233/**
     234 * @param {!Date} date
     235 * @return {!Month}
     236 */
     237Day.createFromDate = function(date) {
     238    return new Day(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate());
     239};
     240
     241Day.createFromToday = function() {
     242    var now = new Date();
     243    return new Day(now.getFullYear(), now.getMonth(), now.getDate());
     244}
     245
     246/**
     247 * @param {!Day} other
     248 * @return {!bool}
     249 */
     250Day.prototype.equals = function(other) {
     251    return this.year === other.year && this.month === other.month && this.date === other.date;
     252};
     253
     254/**
     255 * @return {!Day}
     256 */
     257Day.prototype.previous = function() {
     258    return new Day(this.year, this.month, this.date - 1);
     259};
     260
     261/**
     262 * @return {!Day}
     263 */
     264Day.prototype.next = function() {
     265    return new Day(this.year, this.month, this.date + 1);
     266};
     267
     268/**
    186269 * @return {!Date}
    187270 */
    188 function parseDateString(opt_current) {
    189     if (opt_current) {
    190         var result = opt_current.match(/(\d+)-(\d+)-(\d+)/);
    191         if (result)
    192             return createUTCDate(Number(result[1]), Number(result[2]) - 1, Number(result[3]));
    193     }
    194     var now = new Date();
    195     // Create UTC date with same numbers as local date.
    196     return createUTCDate(now.getFullYear(), now.getMonth(), now.getDate());
    197 }
    198 
    199 /**
    200  * @param {!number} year
    201  * @param {!number} month
    202  * @param {!number} day
     271Day.prototype.startDate = function() {
     272    return createUTCDate(this.year, this.month, this.date);
     273};
     274
     275/**
     276 * @return {!Date}
     277 */
     278Day.prototype.endDate = function() {
     279    return createUTCDate(this.year, this.month, this.date + 1);
     280};
     281
     282/**
     283 * @return {!number}
     284 */
     285Day.prototype.valueOf = function() {
     286    return this.startDate().getTime();
     287};
     288
     289/**
    203290 * @return {!string}
    204291 */
    205 function serializeDate(year, month, day) {
    206     var yearString = String(year);
     292Day.prototype.toString = function() {
     293    var yearString = String(this.year);
    207294    if (yearString.length < 4)
    208295        yearString = ("000" + yearString).substr(-4, 4);
    209     return yearString + "-" + ("0" + (month + 1)).substr(-2, 2) + "-" + ("0" + day).substr(-2, 2);
    210 }
     296    return yearString + "-" + ("0" + (this.month + 1)).substr(-2, 2) + "-" + ("0" + this.date).substr(-2, 2);
     297};
    211298
    212299/**
     
    222309        this.month = valueOrMonthOrYear.month;
    223310    } else {
    224         this.year = Math.floor(valueOrMonthOrYear / 12) + 1970;
    225         this.month = valueOrMonthOrYear % 12;
     311        this.year = 1970;
     312        this.month = valueOrMonthOrYear;
    226313    }
    227314    this.year = this.year + Math.floor(this.month / 12);
    228315    this.month = this.month < 0 ? this.month % 12 + 12 : this.month % 12;
    229     if (this.year < 0 || Month.Maximum < this) {
     316    if (this.year <= 0 || Month.Maximum < this) {
    230317        this.year = NaN;
    231318        this.month = NaN;
     
    293380Month.prototype.endDate = function() {
    294381    if (this.equals(Month.Maximum))
    295         return CalendarPicker.MaximumPossibleDate;
     382        return Day.Maximum.startDate();
    296383    return this.next().startDate();
    297384};
     
    419506    window.addEventListener("resize", this._handleWindowResizeBound, false);
    420507    // We assume this._config.min is a valid date.
    421     this.minimumDate = (typeof this._config.min !== "undefined") ? parseDateString(this._config.min) : CalendarPicker.MinimumPossibleDate;
     508    this._minimumValue = (typeof this._config.min !== "undefined") ? parseDateString(this._config.min).valueOf() : Day.Minimum.valueOf();
    422509    // We assume this._config.max is a valid date.
    423     this.maximumDate = (typeof this._config.max !== "undefined") ? parseDateString(this._config.max) : CalendarPicker.MaximumPossibleDate;
     510    this._maximumValue = (typeof this._config.max !== "undefined") ? parseDateString(this._config.max).valueOf() : Day.Maximum.valueOf();
    424511    this.step = (typeof this._config.step !== undefined) ? Number(this._config.step) : CalendarPicker.DefaultStepScaleFactor;
    425512    this.stepBase = (typeof this._config.stepBase !== "undefined") ? Number(this._config.stepBase) : CalendarPicker.DefaultStepBase;
    426     this.yearMonthController = new YearMonthController(this);
    427     this.daysTable = new DaysTable(this);
     513    this._minimumMonth = Month.createFromDate(new Date(this._minimumValue));
     514    this.maximumMonth = Month.createFromDate(new Date(this._maximumValue));
     515    this._currentMonth = new Month(NaN, NaN);
     516    this._yearMonthController = new YearMonthController(this);
     517    this._daysTable = new DaysTable(this);
    428518    this._hadKeyEvent = false;
    429519    this._layout();
    430     var initialDate = parseDateString(this._config.currentValue);
    431     if (initialDate < this.minimumDate)
    432         initialDate = this.minimumDate;
    433     else if (initialDate > this.maximumDate)
    434         initialDate = this.maximumDate;
    435     this.daysTable.selectDate(initialDate);
     520    var initialSelection = parseDateString(this._config.currentValue);
     521    if (!initialSelection)
     522        initialSelection = Day.createFromToday();
     523    if (initialSelection.valueOf() < this._minimumValue)
     524        initialSelection = new Day(this._minimumValue);
     525    else if (initialSelection.valueOf() > this._maximumValue)
     526        initialSelection = new Day(this._maximumValue);
     527    this.showMonth(Month.createFromDate(initialSelection.startDate()), false);
     528    this._daysTable.selectRange(initialSelection);
    436529    this.fixWindowSize();
    437530    this._handleBodyKeyDownBound = this._handleBodyKeyDown.bind(this);
     
    440533CalendarPicker.prototype = Object.create(Picker.prototype);
    441534
    442 // Hard limits of type=date. See WebCore/platform/DateComponents.h.
    443 CalendarPicker.MinimumPossibleDate = new Date(-62135596800000.0);
    444 CalendarPicker.MaximumPossibleDate = new Date(8640000000000000.0);
    445535// See WebCore/html/DateInputType.cpp.
    446536CalendarPicker.DefaultStepScaleFactor = 86400000;
     
    458548    if (this._config.isCalendarRTL)
    459549        this._element.classList.add("rtl");
    460     this.yearMonthController.attachTo(this._element);
    461     this.daysTable.attachTo(this._element);
     550    this._yearMonthController.attachTo(this._element);
     551    this._daysTable.attachTo(this._element);
    462552    this._layoutButtons();
    463553    // DaysTable will have focus but we don't want to show its focus ring until the first key event.
     
    466556
    467557CalendarPicker.prototype.handleToday = function() {
    468     var date = new Date();
    469     this.daysTable.selectDate(date);
    470     this.submitValue(serializeDate(date.getFullYear(), date.getMonth(), date.getDate()));
     558    var today = Day.createFromToday();
     559    this._daysTable.selectRange(today);
     560    this.submitValue(today.toString());
    471561};
    472562
     
    529619};
    530620
     621/**
     622 * @param {!Month} month
     623 * @return {!bool}
     624 */
     625CalendarPicker.prototype.shouldShowMonth = function(month) {
     626    return this._minimumMonth.valueOf() <= month.valueOf() && this.maximumMonth.valueOf() >= month.valueOf();
     627};
     628
     629/**
     630 * @param {!Month} month
     631 * @param {!bool=} animate
     632 * @param {!bool=} keepSelectionPosition
     633 */
     634CalendarPicker.prototype.showMonth = function(month, animate, keepSelectionPosition) {
     635    if (this._currentMonth.equals(month))
     636        return;
     637    else if (month.valueOf() < this._minimumMonth.valueOf())
     638        month = this._minimumMonth;
     639    else if (month.valueOf() > this.maximumMonth.valueOf())
     640        month = this.maximumMonth;
     641    this._yearMonthController.setMonth(month);
     642    this._daysTable.navigateToMonth(month, animate, keepSelectionPosition);
     643    this._currentMonth = month;
     644};
     645
     646/**
     647 * @return {!Month}
     648 */
     649CalendarPicker.prototype.currentMonth = function() {
     650    return this._currentMonth;
     651};
     652
    531653// ----------------------------------------------------------------
    532654
     
    537659function YearMonthController(picker) {
    538660    this.picker = picker;
    539     /**
    540      * @type {?Month}
    541      */
    542     this._currentMonth = null;
    543661}
    544662
     
    577695    element.appendChild(this._wall);
    578696
    579     var maximumYear = this.picker.maximumDate.getUTCFullYear();
    580     // Because the maximum possible year is September we should use the year before it.
    581     if (maximumYear === Month.Maximum.year)
    582         maximumYear--;
     697    var month = this.picker.maximumMonth;
    583698    var maxWidth = 0;
    584699    for (var m = 0; m < 12; ++m) {
    585         this._month.textContent = new Month(maximumYear, m).toLocaleString();
     700        this._month.textContent = month.toLocaleString();
    586701        maxWidth = Math.max(maxWidth, this._month.offsetWidth);
     702        month = month.previous();
    587703    }
    588704    if (getLanguage() == "ja" && ImperialEraLimit < maximumYear) {
     
    655771
    656772/**
    657  * @return {?Month}
    658  */
    659 YearMonthController.prototype.month = function() {
    660     return this._currentMonth;
    661 };
    662 
    663 /**
    664773 * @param {!Month} month
    665774 */
    666775YearMonthController.prototype.setMonth = function(month) {
    667     this._currentMonth = new Month(month);
    668     this._redraw();
    669 };
    670 
    671 YearMonthController.prototype._redraw = function() {
    672     var min = Month.createFromDate(this.picker.minimumDate).valueOf();
    673     var max = Month.createFromDate(this.picker.maximumDate).valueOf();
    674     var current = this._currentMonth.valueOf();
     776    var monthValue = month.valueOf();
    675777    if (this._left3)
    676         this._left3.disabled = current - 13 < min;
    677     this._left2.disabled = current - 2 < min;
    678     this._left1.disabled = current - 1 < min;
    679     this._right1.disabled = current + 1 > max;
    680     this._right2.disabled = current + 2 > max;
     778        this._left3.disabled = !this.picker.shouldShowMonth(new Month(monthValue - 13));
     779    this._left2.disabled = !this.picker.shouldShowMonth(new Month(monthValue - 2));
     780    this._left1.disabled = !this.picker.shouldShowMonth(new Month(monthValue - 1));
     781    this._right1.disabled = !this.picker.shouldShowMonth(new Month(monthValue + 1));
     782    this._right2.disabled = !this.picker.shouldShowMonth(new Month(monthValue + 2));
    681783    if (this._right3)
    682         this._right3.disabled = current + 13 > max;
    683     this._month.innerText = this._currentMonth.toLocaleString();
     784        this._left3.disabled = !this.picker.shouldShowMonth(new Month(monthValue + 13));
     785    this._month.innerText = month.toLocaleString();
    684786    while (this._monthPopupContents.hasChildNodes())
    685787        this._monthPopupContents.removeChild(this._monthPopupContents.firstChild);
    686788
    687     for (var m = current - 6; m <= current + 6; m++) {
    688         if (m < min || m > max)
     789    for (var m = monthValue - 6; m <= monthValue + 6; m++) {
     790        var month = new Month(m);
     791        if (!this.picker.shouldShowMonth(month))
    689792            continue;
    690         var month = new Month(m);
    691793        var option = createElement("div", ClassNames.MonthSelectorPopupEntry, month.toLocaleString());
    692794        option.dataset.value = month.toString();
    693795        this._monthPopupContents.appendChild(option);
    694         if (m == current)
     796        if (m == monthValue)
    695797            option.classList.add(ClassNames.SelectedMonthYear);
    696798    }
     
    811913    if (!selection)
    812914        return;
    813     this.picker.daysTable.navigateToMonthAndKeepSelectionPosition(Month.parse(selection.dataset.value));
     915    this.picker.showMonth(Month.parse(selection.dataset.value));
    814916};
    815917
     
    869971 */
    870972YearMonthController.prototype.moveRelatively = function(amount) {
    871     var min = Month.createFromDate(this.picker.minimumDate).valueOf();
    872     var max = Month.createFromDate(this.picker.maximumDate).valueOf();
    873     var current = this._currentMonth.valueOf();
    874     var updated = current;
    875     if (amount < 0)
    876         updated = current + amount >= min ? current + amount : min;
    877     else
    878         updated = current + amount <= max ? current + amount : max;
    879     if (updated == current)
    880         return;
    881     this.picker.daysTable.navigateToMonthAndKeepSelectionPosition(new Month(updated));
     973    var current = this.picker.currentMonth().valueOf();
     974    var updated = new Month(current + amount);
     975    this.picker.showMonth(updated, true, true);
    882976};
    883977
     
    890984function DaysTable(picker) {
    891985    this.picker = picker;
    892     /**
    893      * @type {?Month}
    894      */
    895     this._currentMonth = null;
    896986}
    897987
     
    9481038
    9491039/**
    950  * @param {!number} time date in millisecond.
     1040 * @param {!number} value
    9511041 * @return {!boolean}
    9521042 */
    953 CalendarPicker.prototype.stepMismatch = function(time) {
    954     return (time - this.stepBase) % this.step != 0;
    955 }
    956 
    957 /**
    958  * @param {!number} time date in millisecond.
     1043CalendarPicker.prototype._stepMismatch = function(value) {
     1044    return (value - this.stepBase) % this.step != 0;
     1045}
     1046
     1047/**
     1048 * @param {!number} value
    9591049 * @return {!boolean}
    9601050 */
    961 CalendarPicker.prototype.outOfRange = function(time) {
    962     return time < this.minimumDate.getTime() || time > this.maximumDate.getTime();
    963 }
    964 
    965 /**
    966  * @param {!number} time date in millisecond.
     1051CalendarPicker.prototype._outOfRange = function(value) {
     1052    return value < this._minimumValue || value > this._maximumValue;
     1053}
     1054
     1055/**
     1056 * @param {!Month|Day} range
    9671057 * @return {!boolean}
    9681058 */
    969 CalendarPicker.prototype.isValidDate = function(time) {
    970     return !this.outOfRange(time) && !this.stepMismatch(time);
    971 }
    972 
    973 /**
    974  * @param {!number} year
    975  * @param {!number} month
     1059CalendarPicker.prototype.isValidDate = function(range) {
     1060    var value = range.valueOf();
     1061    return !this._outOfRange(value) && !this._stepMismatch(value);
     1062}
     1063
     1064/**
     1065 * @param {!Month} month
    9761066 */
    9771067DaysTable.prototype._renderMonth = function(month) {
    978     this._currentMonth = new Month(month);
    979     var dayIterator = this._currentMonth.startDate();
     1068    var dayIterator = month.startDate();
    9801069    var monthStartDay = dayIterator.getUTCDay();
    9811070    var weekStartDay = global.params.weekStartDay || 0;
     
    9911080            element.innerText = localizeNumber(dayIterator.getUTCDate());
    9921081            element.className = ClassNames.Day;
    993             element.dataset.submitValue = serializeDate(iterMonth.year, iterMonth.month, dayIterator.getUTCDate());
     1082            element.dataset.submitValue = Day.createFromDate(dayIterator).toString();
    9941083            if (isNaN(time)) {
    9951084                element.innerText = "-";
    9961085                element.classList.add(ClassNames.Unavailable);
    997             } else if (this.picker.outOfRange(time))
     1086            } else if (!this.picker.isValidDate(Day.createFromDate(dayIterator)))
    9981087                element.classList.add(ClassNames.Unavailable);
    999             else if (this.picker.stepMismatch(time))
    1000                 element.classList.add(ClassNames.Unavailable);
    1001             else if (!iterMonth.equals(this._currentMonth)) {
     1088            else if (!iterMonth.equals(month)) {
    10021089                element.classList.add(ClassNames.Available);
    10031090                element.classList.add(ClassNames.NotThisMonth);
     
    10081095    }
    10091096
    1010     this.picker.today.disabled = !this.picker.isValidDate(parseDateString().getTime());
     1097    this.picker.today.disabled = !this.picker.isValidDate(Day.createFromToday().valueOf());
    10111098};
    10121099
    10131100/**
    10141101 * @param {!Month} month
    1015  */
    1016 DaysTable.prototype._navigateToMonth = function(month) {
    1017     this.picker.yearMonthController.setMonth(month);
    1018     this._renderMonth(month);
    1019 };
    1020 
    1021 /**
    1022  * @param {!Month} month
    1023  */
    1024 DaysTable.prototype._navigateToMonthWithAnimation = function(month) {
    1025     if (this._currentMonth) {
    1026         var delta = this._currentMonth.valueOf() - month.valueOf();
    1027         if (delta === 0)
    1028             return;
     1102 * @param {!bool} animate
     1103 * @param {!bool} keepSelectionPosition
     1104 */
     1105DaysTable.prototype.navigateToMonth = function(month, animate, keepSelectionPosition) {
     1106    var firstNodeInSelectedRange = this._firstNodeInSelectedRange();
     1107    if (animate) {
    10291108        var daysStyle = this._daysContainer.style;
    10301109        daysStyle.position = "relative";
    10311110        daysStyle.webkitTransition = "left 0.1s ease";
    1032         daysStyle.left = (delta > 0 ? "" : "-") + this._daysContainer.offsetWidth + "px";
    1033     }
    1034     this._navigateToMonth(month);
     1111        daysStyle.left = (this.picker.currentMonth().valueOf() > month.valueOf() ? "" : "-") + this._daysContainer.offsetWidth + "px";
     1112    }
     1113    this._renderMonth(month);
     1114    if (keepSelectionPosition && firstNodeInSelectedRange) {
     1115        var x = parseInt(firstNodeInSelectedRange.dataset.positionX, 10);
     1116        var y = parseInt(firstNodeInSelectedRange.dataset.positionY, 10);
     1117        this._selectRangeAtPosition(x, y);
     1118    }
    10351119};
    10361120
     
    10471131
    10481132/**
    1049  * @param {!Month} month
    1050  */
    1051 DaysTable.prototype.navigateToMonthAndKeepSelectionPosition = function(month) {
    1052     if (this._currentMonth.equals(month))
    1053         return;
    1054     var firstNodeInSelectedRange = this._firstNodeInSelectedRange();
    1055     this._navigateToMonthWithAnimation(month);
    1056     if (firstNodeInSelectedRange) {
    1057         var x = parseInt(firstNodeInSelectedRange.dataset.positionX, 10);
    1058         var y = parseInt(firstNodeInSelectedRange.dataset.positionY, 10);
    1059         this._selectRangeAtPosition(x, y);
    1060     }
    1061 };
    1062 
    1063 /**
    10641133 * @param {!Date} date
    10651134 */
    1066 DaysTable.prototype.selectDate = function(date) {
     1135DaysTable.prototype.selectRange = function(day) {
    10671136    this._deselect();
    1068     this._navigateToMonthWithAnimation(Month.createFromDate(date));
    1069     var dateString = serializeDate(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate());
     1137    this.picker.showMonth(Month.createFromDate(day.startDate()), true);
     1138    var dateString = day.toString();
    10701139    for (var w = 0; w < DaysTable._Weeks; w++) {
    10711140        for (var d = 0; d < 7; d++) {
     
    11141183 */
    11151184DaysTable.prototype._maybeSetPreviousMonth = function() {
    1116     var currentMonth = this.picker.yearMonthController.month();
    1117     if (this.picker.minimumDate >= currentMonth.startDate())
     1185    var previousMonth = this.picker.currentMonth().previous();
     1186    if (!this.picker.shouldShowMonth(previousMonth))
    11181187        return false;
    1119     this._navigateToMonthWithAnimation(currentMonth.previous());
     1188    this.picker.showMonth(previousMonth, true);
    11201189    return true;
    11211190};
     
    11251194 */
    11261195DaysTable.prototype._maybeSetNextMonth = function() {
    1127     var currentMonth = this.picker.yearMonthController.month();
    1128     if (this.picker.maximumDate < currentMonth.endDate())
     1196    var nextMonth = this.picker.currentMonth().next();
     1197    if (!this.picker.shouldShowMonth(nextMonth))
    11291198        return false;
    1130     this._navigateToMonthWithAnimation(currentMonth.next());
     1199    this.picker.showMonth(nextMonth, true);
    11311200    return true;
    11321201};
     
    12381307
    12391308    } else if (key == "U+0054") { // 't'
    1240         this.selectDate(new Date());
     1309        this.selectRange(Day.createFromToday());
    12411310        event.stopPropagation();
    12421311        event.preventDefault();
     
    12721341        }
    12731342    } else if (key == "U+004D") { // 'm'
    1274         this.yearMonthController.moveRelatively(event.shiftKey ? YearMonthController.PreviousMonth : YearMonthController.NextMonth);
     1343        this._yearMonthController.moveRelatively(event.shiftKey ? YearMonthController.PreviousMonth : YearMonthController.NextMonth);
    12751344    } else if (key == "U+0059") { // 'y'
    1276         this.yearMonthController.moveRelatively(event.shiftKey ? YearMonthController.PreviousYear : YearMonthController.NextYear);
     1345        this._yearMonthController.moveRelatively(event.shiftKey ? YearMonthController.PreviousYear : YearMonthController.NextYear);
    12771346    } else if (key == "U+0044") { // 'd'
    1278         this.yearMonthController.moveRelatively(event.shiftKey ? YearMonthController.PreviousTenYears : YearMonthController.NextTenYears);
     1347        this._yearMonthController.moveRelatively(event.shiftKey ? YearMonthController.PreviousTenYears : YearMonthController.NextTenYears);
    12791348    } else if (key == "U+001B") // ESC
    12801349        this.handleCancel();
Note: See TracChangeset for help on using the changeset viewer.