Changeset 133722 in webkit


Ignore:
Timestamp:
Nov 6, 2012 10:29:43 PM (11 years ago)
Author:
keishi@webkit.org
Message:

Implement month picking to calendar picker
https://bugs.webkit.org/show_bug.cgi?id=101333

Reviewed by Kent Tamura.

.:

  • ManualTests/forms/calendar-picker.html: Added test for month picker.

Source/WebCore:

This adds month picker mode to CalendarPicker.

No new tests. Tests will be added later when this feature is enabled in DRT.

  • Resources/pagepopups/calendarPicker.css:

(.month-mode .day): Remove rounded corners when in month mode.

  • Resources/pagepopups/calendarPicker.js:

(Month.createFromToday): Creates month containing today.
(CalendarPicker): Set this.selectionConstructor to Day or Month depending on the mode. Create DayTables or MonthPickerDaysTable depending on the mode.
(CalendarPicker.prototype.handleToday):
(CalendarPicker.prototype._layoutButtons):
(DaysTable.prototype._renderMonth): Set element.dataset.monthValue for all date nodes.
(DaysTable.prototype._markRangeAsSelected): Marks all day nodes in range as selected.
(DaysTable.prototype.selectRange): Selects a day.
(DaysTable.prototype.selectRangeAndShowEntireRange): Same as selectRange.
(DaysTable.prototype._selectRangeContainingNode):
(DaysTable.prototype._rangeForNode): Returns Day for node.
(DaysTable.prototype.startDate): Start datetime of visible date range. This value is inclusive.
(DaysTable.prototype.endDate): End datetime of visible date range. This value is exclusive.
(DaysTable.prototype._handleKey):
(MonthPickerDaysTable):
(MonthPickerDaysTable.prototype._markRangeAsSelected): Marks all day nodes in range as selected.
(MonthPickerDaysTable.prototype.selectRange): Selects month. If month is not visible, navigates to that month.
(MonthPickerDaysTable.prototype.selectRangeAndShowEntireRange): Selects month. Navigates to the month.
(MonthPickerDaysTable.prototype._rangeForNode): Returns Month for node.
(MonthPickerDaysTable.prototype._handleKey): Arrow keys simply move the selection forwards or backwards.

Location:
trunk
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/ChangeLog

    r133678 r133722  
     12012-11-06  Keishi Hattori  <keishi@webkit.org>
     2
     3        Implement month picking to calendar picker
     4        https://bugs.webkit.org/show_bug.cgi?id=101333
     5
     6        Reviewed by Kent Tamura.
     7
     8        * ManualTests/forms/calendar-picker.html: Added test for month picker.
     9
    1102012-11-06  Laszlo Gombos  <l.gombos@samsung.com>
    211
  • trunk/ManualTests/forms/calendar-picker.html

    r130888 r133722  
    2828 <option>Arabic with datalist</option>
    2929 <option>Arabic with long datalist</option>
     30 <option>Month</option>
    3031</select>
    3132
     
    239240    suggestionHighlightTextColor: "#ffffff"
    240241};
     242var monthArguments = {
     243    locale: 'en-US',
     244    monthLabels : ['January', 'February', 'March', 'April', 'May', 'June',
     245    'July', 'August', 'September', 'October', 'November', 'December'],
     246    dayLabels : ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
     247    todayLabel : 'This Month',
     248    clearLabel : 'Clear',
     249    cancelLabel : 'Cancel',
     250    weekStartDay : 0,
     251    step : "1",
     252    stepBase: "0",
     253    currentValue : '2000-01',
     254    max : '2099-03',
     255    mode: "month"
     256};
    241257
    242258function openCalendar(args) {
     
    311327        openCalendar(arabicLongDatalistArguments);
    312328        break;
     329    case 7:
     330        openCalendar(monthArguments);
     331        break;
    313332    }
    314333}
  • trunk/Source/WebCore/ChangeLog

    r133720 r133722  
     12012-11-06  Keishi Hattori  <keishi@webkit.org>
     2
     3        Implement month picking to calendar picker
     4        https://bugs.webkit.org/show_bug.cgi?id=101333
     5
     6        Reviewed by Kent Tamura.
     7
     8        This adds month picker mode to CalendarPicker.
     9
     10        No new tests. Tests will be added later when this feature is enabled in DRT.
     11
     12        * Resources/pagepopups/calendarPicker.css:
     13        (.month-mode .day): Remove rounded corners when in month mode.
     14        * Resources/pagepopups/calendarPicker.js:
     15        (Month.createFromToday): Creates month containing today.
     16        (CalendarPicker): Set this.selectionConstructor to Day or Month depending on the mode. Create DayTables or MonthPickerDaysTable depending on the mode.
     17        (CalendarPicker.prototype.handleToday):
     18        (CalendarPicker.prototype._layoutButtons):
     19        (DaysTable.prototype._renderMonth): Set element.dataset.monthValue for all date nodes.
     20        (DaysTable.prototype._markRangeAsSelected): Marks all day nodes in range as selected.
     21        (DaysTable.prototype.selectRange): Selects a day.
     22        (DaysTable.prototype.selectRangeAndShowEntireRange): Same as selectRange.
     23        (DaysTable.prototype._selectRangeContainingNode):
     24        (DaysTable.prototype._rangeForNode): Returns Day for node.
     25        (DaysTable.prototype.startDate): Start datetime of visible date range. This value is inclusive.
     26        (DaysTable.prototype.endDate): End datetime of visible date range. This value is exclusive.
     27        (DaysTable.prototype._handleKey):
     28        (MonthPickerDaysTable):
     29        (MonthPickerDaysTable.prototype._markRangeAsSelected): Marks all day nodes in range as selected.
     30        (MonthPickerDaysTable.prototype.selectRange): Selects month. If month is not visible, navigates to that month.
     31        (MonthPickerDaysTable.prototype.selectRangeAndShowEntireRange): Selects month. Navigates to the month.
     32        (MonthPickerDaysTable.prototype._rangeForNode): Returns Month for node.
     33        (MonthPickerDaysTable.prototype._handleKey): Arrow keys simply move the selection forwards or backwards.
     34
    1352012-11-06  Dan Beam  <dbeam@chromium.org>
    236
  • trunk/Source/WebCore/Resources/pagepopups/calendarPicker.css

    r132028 r133722  
    225225    -webkit-transition: none;
    226226}
     227
     228.month-mode .day {
     229    -webkit-transition: none;
     230    border-radius: 0;
     231    border: 1px solid transparent;
     232}
  • trunk/Source/WebCore/Resources/pagepopups/calendarPicker.js

    r133565 r133722  
    4747    DaysArea: "days-area",
    4848    DaysAreaContainer: "days-area-container",
     49    MonthMode: "month-mode",
    4950    MonthSelector: "month-selector",
    5051    MonthSelectorBox: "month-selector-box",
     
    215216
    216217// See WebCore/platform/DateComponents.h.
    217 Day.Minimum = new Date(-62135596800000.0);
    218 Day.Maximum = new Date(8640000000000000.0);
     218Day.Minimum = new Day(-62135596800000.0);
     219Day.Maximum = new Day(8640000000000000.0);
    219220
    220221/**
     
    231232    return new Day(year, month, date);
    232233};
     234
    233235/**
    234236 * @param {!Date} date
     
    239241};
    240242
     243/**
     244 * @return {!Month}
     245 */
    241246Day.createFromToday = function() {
    242247    var now = new Date();
    243248    return new Day(now.getFullYear(), now.getMonth(), now.getDate());
    244 }
     249};
    245250
    246251/**
     
    323328
    324329// See WebCore/platform/DateComponents.h.
     330Month.Minimum = new Month(1, 0);
    325331Month.Maximum = new Month(275760, 8);
    326332
     
    344350Month.createFromDate = function(date) {
    345351    return new Month(date.getUTCFullYear(), date.getUTCMonth());
     352};
     353
     354/**
     355 * @return {!Month}
     356 */
     357Month.createFromToday = function() {
     358    var now = new Date();
     359    return new Month(now.getFullYear(), now.getMonth());
    346360};
    347361
     
    501515function CalendarPicker(element, config) {
    502516    Picker.call(this, element, config);
     517    if (this._config.mode === "month") {
     518        this.selectionConstructor = Month;
     519        this._daysTable = new MonthPickerDaysTable(this);
     520        this._element.classList.add(ClassNames.MonthMode);
     521    } else {
     522        this.selectionConstructor = Day;
     523        this._daysTable = new DaysTable(this);
     524    }
    503525    this._element.classList.add("calendar-picker");
    504526    this._element.classList.add("preparing");
    505527    this._handleWindowResizeBound = this._handleWindowResize.bind(this);
    506528    window.addEventListener("resize", this._handleWindowResizeBound, false);
    507     // We assume this._config.min is a valid date.
    508     this._minimumValue = (typeof this._config.min !== "undefined") ? parseDateString(this._config.min).valueOf() : Day.Minimum.valueOf();
    509     // We assume this._config.max is a valid date.
    510     this._maximumValue = (typeof this._config.max !== "undefined") ? parseDateString(this._config.max).valueOf() : Day.Maximum.valueOf();
     529    // We assume this._config.min/max are valid dates or months.
     530    var minimum = (typeof this._config.min !== "undefined") ? parseDateString(this._config.min) : this.selectionConstructor.Minimum;
     531    var maximum = (typeof this._config.max !== "undefined") ? parseDateString(this._config.max) : this.selectionConstructor.Maximum;
     532    this._minimumValue = minimum.valueOf();
     533    this._maximumValue = maximum.valueOf();
    511534    this.step = (typeof this._config.step !== undefined) ? Number(this._config.step) : CalendarPicker.DefaultStepScaleFactor;
    512535    this.stepBase = (typeof this._config.stepBase !== "undefined") ? Number(this._config.stepBase) : CalendarPicker.DefaultStepBase;
    513     this._minimumMonth = Month.createFromDate(new Date(this._minimumValue));
    514     this.maximumMonth = Month.createFromDate(new Date(this._maximumValue));
     536    this._minimumMonth = Month.createFromDate(minimum.startDate());
     537    this.maximumMonth = Month.createFromDate(maximum.startDate());
    515538    this._currentMonth = new Month(NaN, NaN);
    516539    this._yearMonthController = new YearMonthController(this);
    517     this._daysTable = new DaysTable(this);
    518540    this._hadKeyEvent = false;
    519541    this._layout();
    520542    var initialSelection = parseDateString(this._config.currentValue);
    521543    if (!initialSelection)
    522         initialSelection = Day.createFromToday();
     544        initialSelection = this.selectionConstructor.createFromToday();
    523545    if (initialSelection.valueOf() < this._minimumValue)
    524         initialSelection = new Day(this._minimumValue);
     546        initialSelection = new this.selectionConstructor(this._minimumValue);
    525547    else if (initialSelection.valueOf() > this._maximumValue)
    526         initialSelection = new Day(this._maximumValue);
     548        initialSelection = new this.selectionConstructor(this._maximumValue);
    527549    this.showMonth(Month.createFromDate(initialSelection.startDate()), false);
    528     this._daysTable.selectRange(initialSelection);
     550    this._daysTable.selectRangeAndShowEntireRange(initialSelection);
    529551    this.fixWindowSize();
    530552    this._handleBodyKeyDownBound = this._handleBodyKeyDown.bind(this);
     
    556578
    557579CalendarPicker.prototype.handleToday = function() {
    558     var today = Day.createFromToday();
    559     this._daysTable.selectRange(today);
     580    var today = this.selectionConstructor.createFromToday();
     581    this._daysTable.selectRangeAndShowEntireRange(today);
    560582    this.submitValue(today.toString());
    561583};
     
    602624    var container = createElement("div", ClassNames.TodayClearArea);
    603625    this.today = createElement("input", ClassNames.TodayButton);
     626    this.today.disabled = !this.isValidDate(this.selectionConstructor.createFromToday());
    604627    this.today.type = "button";
    605628    this.today.value = this._config.todayLabel;
     
    10811104            element.className = ClassNames.Day;
    10821105            element.dataset.submitValue = Day.createFromDate(dayIterator).toString();
     1106            element.dataset.monthValue = iterMonth.toString();
    10831107            if (isNaN(time)) {
    10841108                element.innerText = "-";
    10851109                element.classList.add(ClassNames.Unavailable);
    1086             } else if (!this.picker.isValidDate(Day.createFromDate(dayIterator)))
     1110            } else if (!this.picker.isValidDate(this._rangeForNode(element)))
    10871111                element.classList.add(ClassNames.Unavailable);
    10881112            else if (!iterMonth.equals(month)) {
     
    10941118        }
    10951119    }
    1096 
    1097     this.picker.today.disabled = !this.picker.isValidDate(Day.createFromToday().valueOf());
    10981120};
    10991121
     
    11311153
    11321154/**
    1133  * @param {!Date} date
    1134  */
    1135 DaysTable.prototype.selectRange = function(day) {
    1136     this._deselect();
    1137     this.picker.showMonth(Month.createFromDate(day.startDate()), true);
     1155 * @param {!Day} day
     1156 */
     1157DaysTable.prototype._markRangeAsSelected = function(day) {
    11381158    var dateString = day.toString();
    11391159    for (var w = 0; w < DaysTable._Weeks; w++) {
     
    11481168
    11491169/**
     1170 * @param {!Day} day
     1171 */
     1172DaysTable.prototype.selectRange = function(day) {
     1173    this._deselect();
     1174    if (this.startDate() > day.startDate() || this.endDate() < day.endDate())
     1175        this.picker.showMonth(Month.createFromDate(day.startDate()), false);
     1176    this._markRangeAsSelected(day);
     1177};
     1178
     1179/**
     1180 * @param {!Day} day
     1181 */
     1182DaysTable.prototype.selectRangeAndShowEntireRange = function(day) {
     1183    this.selectRange(day);
     1184};
     1185
     1186/**
    11501187 * @param {!Element} dayNode
    11511188 */
    11521189DaysTable.prototype._selectRangeContainingNode = function(dayNode) {
    1153     this._deselect();
    1154     if (!dayNode || !dayNode.classList.contains(ClassNames.Day) || !dayNode.classList.contains(ClassNames.Available))
     1190    var range = this._rangeForNode(dayNode);
     1191    if (!range)
    11551192        return;
    1156     // FIXME: Select date, week or month depending on the config.
    1157     dayNode.classList.add(ClassNames.Selected);
     1193    this.selectRange(range);
     1194};
     1195
     1196/**
     1197 * @param {!Element} dayNode
     1198 * @return {?Day}
     1199 */
     1200DaysTable.prototype._rangeForNode = function(dayNode) {
     1201    if (!dayNode)
     1202        return null;
     1203    return Day.parse(dayNode.dataset.submitValue);
     1204};
     1205
     1206/**
     1207 * @return {!Date}
     1208 */
     1209DaysTable.prototype.startDate = function() {
     1210    return Day.parse(this._days[0][0].dataset.submitValue).startDate();
     1211};
     1212
     1213/**
     1214 * @return {!Date}
     1215 */
     1216DaysTable.prototype.endDate = function() {
     1217    return Day.parse(this._days[DaysTable._Weeks - 1][7 - 1].dataset.submitValue).endDate();
    11581218};
    11591219
     
    13071367
    13081368    } else if (key == "U+0054") { // 't'
    1309         this.selectRange(Day.createFromToday());
     1369        this.selectRangeAndShowEntireRange(Day.createFromToday());
    13101370        event.stopPropagation();
    13111371        event.preventDefault();
     
    13221382    event.stopPropagation();
    13231383    event.preventDefault();
     1384};
     1385
     1386/**
     1387 * @constructor
     1388 * @param{!CalendarPicker} picker
     1389 */
     1390function MonthPickerDaysTable(picker) {
     1391    DaysTable.call(this, picker);
     1392}
     1393MonthPickerDaysTable.prototype = Object.create(DaysTable.prototype);
     1394
     1395/**
     1396 * @param {!Month} month
     1397 */
     1398MonthPickerDaysTable.prototype._markRangeAsSelected = function(month) {
     1399    var monthString = month.toString();
     1400    for (var w = 0; w < DaysTable._Weeks; w++) {
     1401        for (var d = 0; d < 7; d++) {
     1402            if (this._days[w][d].dataset.monthValue == monthString) {
     1403                this._days[w][d].classList.add(ClassNames.Selected);
     1404            }
     1405        }
     1406    }
     1407};
     1408
     1409/**
     1410 * @param {!Month} month
     1411 */
     1412MonthPickerDaysTable.prototype.selectRange = function(month) {
     1413    this._deselect();
     1414    if (this.startDate() >= month.endDate() || this.endDate() <= month.startDate())
     1415        this.picker.showMonth(month, true);
     1416    this._markRangeAsSelected(month);
     1417};
     1418
     1419/**
     1420 * @param {!Month} month
     1421 */
     1422MonthPickerDaysTable.prototype.selectRangeAndShowEntireRange = function(month) {
     1423    this._deselect();
     1424    this.picker.showMonth(month, true);
     1425    this._markRangeAsSelected(month);
     1426};
     1427
     1428/**
     1429 * @param {!Element} dayNode
     1430 * @return {?Month}
     1431 */
     1432MonthPickerDaysTable.prototype._rangeForNode = function(dayNode) {
     1433    if (!dayNode)
     1434        return null;
     1435    return Month.parse(dayNode.dataset.monthValue);
     1436};
     1437
     1438/**
     1439 * @param {Event} event
     1440 */
     1441MonthPickerDaysTable.prototype._handleKey = function(event) {
     1442    this.picker.maybeUpdateFocusStyle();
     1443    var key = event.keyIdentifier;
     1444    var eventHandled = false;
     1445    var currentMonth = this.picker.currentMonth();
     1446    var firstNodeInSelectedRange = this._firstNodeInSelectedRange();
     1447    if (!firstNodeInSelectedRange
     1448        && (key == "Right" || key == "Left" || key == "Up" || key == "Down" || key == "PageUp" || key == "PageDown")) {
     1449        this.selectRange(currentMonth);
     1450        event.stopPropagation();
     1451        event.preventDefault();
     1452        return;
     1453    }
     1454    var selectedMonth = this._rangeForNode(firstNodeInSelectedRange);
     1455    if (key == (global.params.isCalendarRTL ? "Right" : "Left") || key == "Up" || key == "PageUp") {
     1456        if (selectedMonth.valueOf() > currentMonth.valueOf())
     1457            this.selectRangeAndShowEntireRange(currentMonth);
     1458        else
     1459            this.selectRangeAndShowEntireRange(currentMonth.previous());
     1460        eventHandled = true;
     1461    } else if (key == (global.params.isCalendarRTL ? "Left" : "Right") || key == "Down" || key == "PageDown") {
     1462        if (selectedMonth.valueOf() < currentMonth.valueOf())
     1463            this.selectRangeAndShowEntireRange(currentMonth);
     1464        else
     1465            this.selectRangeAndShowEntireRange(currentMonth.next());
     1466        eventHandled = true;
     1467    } else if (this._hasSelection() && key == "Enter") {
     1468        if (currentSelection) {
     1469            this.picker.submitValue(currentSelection.toString());
     1470            eventHandled = true;
     1471        }
     1472    } else if (key == "U+0054") { // 't'
     1473        this.selectRangeAndShowEntireRange(Month.createFromToday());
     1474        eventHandled = true;
     1475    }
     1476    if (eventHandled) {
     1477        event.stopPropagation();
     1478        event.preventDefault();
     1479    }
    13241480};
    13251481
Note: See TracChangeset for help on using the changeset viewer.