/framework/source/class/qx/ui/control/DateChooser.js
JavaScript | 771 lines | 453 code | 140 blank | 178 comment | 90 complexity | c2c2ff9e05f6a86db37c603a7a6c2bea MD5 | raw file
Possible License(s): CC-BY-SA-3.0, LGPL-3.0, MIT
- /* ************************************************************************
- qooxdoo - the new era of web development
- http://qooxdoo.org
- Copyright:
- 2006 STZ-IDA, Germany, http://www.stz-ida.de
- License:
- MIT: https://opensource.org/licenses/MIT
- See the LICENSE file in the project's top-level directory for details.
- Authors:
- * Til Schneider (til132)
- * Martin Wittemann (martinwittemann)
- ************************************************************************ */
- /**
- * A *date chooser* is a small calendar including a navigation bar to switch the shown
- * month. It includes a column for the calendar week and shows one month. Selecting
- * a date is as easy as tapping on it.
- *
- * To be conform with all form widgets, the {@link qx.ui.form.IForm} interface
- * is implemented.
- *
- * The following example creates and adds a date chooser to the root element.
- * A listener alerts the user if a new date is selected.
- *
- * <pre class='javascript'>
- * var chooser = new qx.ui.control.DateChooser();
- * this.getRoot().add(chooser, { left : 20, top: 20});
- *
- * chooser.addListener("changeValue", function(e) {
- * alert(e.getData());
- * });
- * </pre>
- *
- * Additionally to a selection event an execute event is available which is
- * fired by doubletap or tapping the space / enter key. With this event you
- * can for example save the selection and close the date chooser.
- *
- * @childControl navigation-bar {qx.ui.container.Composite} container for the navigation bar controls
- * @childControl last-year-button-tooltip {qx.ui.tooltip.ToolTip} tooltip for the last year button
- * @childControl last-year-button {qx.ui.form.Button} button to jump to the last year
- * @childControl last-month-button-tooltip {qx.ui.tooltip.ToolTip} tooltip for the last month button
- * @childControl last-month-button {qx.ui.form.Button} button to jump to the last month
- * @childControl next-month-button-tooltip {qx.ui.tooltip.ToolTip} tooltip for the next month button
- * @childControl next-month-button {qx.ui.form.Button} button to jump to the next month
- * @childControl next-year-button-tooltip {qx.ui.tooltip.ToolTip} tooltip for the next year button
- * @childControl next-year-button {qx.ui.form.Button} button to jump to the next year
- * @childControl month-year-label {qx.ui.basic.Label} shows the current month and year
- * @childControl week {qx.ui.basic.Label} week label (used multiple times)
- * @childControl weekday {qx.ui.basic.Label} weekday label (used multiple times)
- * @childControl day {qx.ui.basic.Label} day label (used multiple times)
- * @childControl date-pane {qx.ui.container.Composite} the pane used to position the week, weekday and day labels
- *
- */
- qx.Class.define("qx.ui.control.DateChooser",
- {
- extend : qx.ui.core.Widget,
- include : [
- qx.ui.core.MExecutable,
- qx.ui.form.MForm
- ],
- implement : [
- qx.ui.form.IExecutable,
- qx.ui.form.IForm,
- qx.ui.form.IDateForm
- ],
- /*
- *****************************************************************************
- CONSTRUCTOR
- *****************************************************************************
- */
- /**
- * @param date {Date ? null} The initial date to show. If <code>null</code>
- * the current day (today) is shown.
- */
- construct : function(date)
- {
- this.base(arguments);
- // set the layout
- var layout = new qx.ui.layout.VBox();
- this._setLayout(layout);
- // create the child controls
- this._createChildControl("navigation-bar");
- this._createChildControl("date-pane");
- // Support for key events
- this.addListener("keypress", this._onKeyPress);
- // initialize format - moved from statics{} to constructor due to [BUG #7149]
- var DateChooser = qx.ui.control.DateChooser;
- if (!DateChooser.MONTH_YEAR_FORMAT) {
- DateChooser.MONTH_YEAR_FORMAT = qx.locale.Date.getDateTimeFormat("yyyyMMMM", "MMMM yyyy");
- }
- // Show the right date
- var shownDate = (date != null) ? date : new Date();
- this.showMonth(shownDate.getMonth(), shownDate.getFullYear());
- // listen for locale changes
- if (qx.core.Environment.get("qx.dynlocale")) {
- qx.locale.Manager.getInstance().addListener("changeLocale", this._updateDatePane, this);
- }
- // register pointer up and down handler
- this.addListener("pointerdown", this._onPointerUpDown, this);
- this.addListener("pointerup", this._onPointerUpDown, this);
- },
- /*
- *****************************************************************************
- STATICS
- *****************************************************************************
- */
- statics :
- {
- /**
- * @type {string} The format for the date year label at the top center.
- */
- MONTH_YEAR_FORMAT : null,
- /**
- * @type {string} The format for the weekday labels (the headers of the date table).
- */
- WEEKDAY_FORMAT : "EE",
- /**
- * @type {string} The format for the week numbers (the labels of the left column).
- */
- WEEK_FORMAT : "ww"
- },
- /*
- *****************************************************************************
- PROPERTIES
- *****************************************************************************
- */
- properties :
- {
- // overridden
- appearance :
- {
- refine : true,
- init : "datechooser"
- },
- // overridden
- width :
- {
- refine : true,
- init : 200
- },
- // overridden
- height :
- {
- refine : true,
- init : 150
- },
- /** The currently shown month. 0 = january, 1 = february, and so on. */
- shownMonth :
- {
- check : "Integer",
- init : null,
- nullable : true,
- event : "changeShownMonth"
- },
- /** The currently shown year. */
- shownYear :
- {
- check : "Integer",
- init : null,
- nullable : true,
- event : "changeShownYear"
- },
- /** The date value of the widget. */
- value :
- {
- check : "Date",
- init : null,
- nullable : true,
- event : "changeValue",
- apply : "_applyValue"
- }
- },
- /*
- *****************************************************************************
- MEMBERS
- *****************************************************************************
- */
- members :
- {
- __weekdayLabelArr : null,
- __dayLabelArr : null,
- __weekLabelArr : null,
- // overridden
- /**
- * @lint ignoreReferenceField(_forwardStates)
- */
- _forwardStates :
- {
- invalid : true
- },
- /*
- ---------------------------------------------------------------------------
- WIDGET INTERNALS
- ---------------------------------------------------------------------------
- */
- // overridden
- _createChildControlImpl : function(id, hash)
- {
- var control;
- switch(id)
- {
- // NAVIGATION BAR STUFF
- case "navigation-bar":
- control = new qx.ui.container.Composite(new qx.ui.layout.HBox());
- // Add the navigation bar elements
- control.add(this.getChildControl("last-year-button"));
- control.add(this.getChildControl("last-month-button"));
- control.add(this.getChildControl("month-year-label"), {flex: 1});
- control.add(this.getChildControl("next-month-button"));
- control.add(this.getChildControl("next-year-button"));
- this._add(control);
- break;
- case "last-year-button-tooltip":
- control = new qx.ui.tooltip.ToolTip(this.tr("Last year"));
- break;
- case "last-year-button":
- control = new qx.ui.toolbar.Button();
- control.addState("lastYear");
- control.setFocusable(false);
- control.setToolTip(this.getChildControl("last-year-button-tooltip"));
- control.addListener("tap", this._onNavButtonTap, this);
- break;
- case "last-month-button-tooltip":
- control = new qx.ui.tooltip.ToolTip(this.tr("Last month"));
- break;
- case "last-month-button":
- control = new qx.ui.toolbar.Button();
- control.addState("lastMonth");
- control.setFocusable(false);
- control.setToolTip(this.getChildControl("last-month-button-tooltip"));
- control.addListener("tap", this._onNavButtonTap, this);
- break;
- case "next-month-button-tooltip":
- control = new qx.ui.tooltip.ToolTip(this.tr("Next month"));
- break;
- case "next-month-button":
- control = new qx.ui.toolbar.Button();
- control.addState("nextMonth");
- control.setFocusable(false);
- control.setToolTip(this.getChildControl("next-month-button-tooltip"));
- control.addListener("tap", this._onNavButtonTap, this);
- break;
- case "next-year-button-tooltip":
- control = new qx.ui.tooltip.ToolTip(this.tr("Next year"));
- break;
- case "next-year-button":
- control = new qx.ui.toolbar.Button();
- control.addState("nextYear");
- control.setFocusable(false);
- control.setToolTip(this.getChildControl("next-year-button-tooltip"));
- control.addListener("tap", this._onNavButtonTap, this);
- break;
- case "month-year-label":
- control = new qx.ui.basic.Label();
- control.setAllowGrowX(true);
- control.setAnonymous(true);
- break;
- case "week":
- control = new qx.ui.basic.Label();
- control.setAllowGrowX(true);
- control.setAllowGrowY(true);
- control.setSelectable(false);
- control.setAnonymous(true);
- control.setCursor("default");
- break;
- case "weekday":
- control = new qx.ui.basic.Label();
- control.setAllowGrowX(true);
- control.setAllowGrowY(true);
- control.setSelectable(false);
- control.setAnonymous(true);
- control.setCursor("default");
- break;
- case "day":
- control = new qx.ui.basic.Label();
- control.setAllowGrowX(true);
- control.setAllowGrowY(true);
- control.setCursor("default");
- control.addListener("pointerdown", this._onDayTap, this);
- control.addListener("dbltap", this._onDayDblTap, this);
- break;
- case "date-pane":
- var controlLayout = new qx.ui.layout.Grid();
- control = new qx.ui.container.Composite(controlLayout);
- for (var i = 0; i < 8; i++) {
- controlLayout.setColumnFlex(i, 1);
- }
- for (var i = 0; i < 7; i++) {
- controlLayout.setRowFlex(i, 1);
- }
- // Create the weekdays
- // Add an empty label as spacer for the week numbers
- var label = this.getChildControl("week#0");
- label.addState("header");
- control.add(label, {column: 0, row: 0});
- this.__weekdayLabelArr = [];
- for (var i=0; i<7; i++)
- {
- label = this.getChildControl("weekday#" + i);
- control.add(label, {column: i + 1, row: 0});
- this.__weekdayLabelArr.push(label);
- }
- // Add the days
- this.__dayLabelArr = [];
- this.__weekLabelArr = [];
- for (var y = 0; y < 6; y++)
- {
- // Add the week label
- var label = this.getChildControl("week#" + (y+1));
- control.add(label, {column: 0, row: y + 1});
- this.__weekLabelArr.push(label);
- // Add the day labels
- for (var x = 0; x < 7; x++)
- {
- var label = this.getChildControl("day#" + ((y*7)+x));
- control.add(label, {column:x + 1, row:y + 1});
- this.__dayLabelArr.push(label);
- }
- }
- this._add(control);
- break;
- }
- return control || this.base(arguments, id);
- },
- // apply methods
- _applyValue : function(value, old)
- {
- if ((value != null) && (this.getShownMonth() != value.getMonth() || this.getShownYear() != value.getFullYear()))
- {
- // The new date is in another month -> Show that month
- this.showMonth(value.getMonth(), value.getFullYear());
- }
- else
- {
- // The new date is in the current month -> Just change the states
- var newDay = (value == null) ? -1 : value.getDate();
- for (var i=0; i<6*7; i++)
- {
- var dayLabel = this.__dayLabelArr[i];
- if (dayLabel.hasState("otherMonth"))
- {
- if (dayLabel.hasState("selected")) {
- dayLabel.removeState("selected");
- }
- }
- else
- {
- var day = parseInt(dayLabel.getValue(), 10);
- if (day == newDay) {
- dayLabel.addState("selected");
- } else if (dayLabel.hasState("selected")) {
- dayLabel.removeState("selected");
- }
- }
- }
- }
- },
- /*
- ---------------------------------------------------------------------------
- EVENT HANDLER
- ---------------------------------------------------------------------------
- */
- /**
- * Handler which stops the propagation of the tap event if
- * the navigation bar or calendar headers will be tapped.
- *
- * @param e {qx.event.type.Pointer} The pointer up / down event
- */
- _onPointerUpDown : function(e) {
- var target = e.getTarget();
- if (target == this.getChildControl("navigation-bar") ||
- target == this.getChildControl("date-pane")) {
- e.stopPropagation();
- return;
- }
- },
- /**
- * Event handler. Called when a navigation button has been tapped.
- *
- * @param evt {qx.event.type.Data} The data event.
- */
- _onNavButtonTap : function(evt)
- {
- var year = this.getShownYear();
- var month = this.getShownMonth();
- switch(evt.getCurrentTarget())
- {
- case this.getChildControl("last-year-button"):
- year--;
- break;
- case this.getChildControl("last-month-button"):
- month--;
- if (month < 0)
- {
- month = 11;
- year--;
- }
- break;
- case this.getChildControl("next-month-button"):
- month++;
- if (month >= 12)
- {
- month = 0;
- year++;
- }
- break;
- case this.getChildControl("next-year-button"):
- year++;
- break;
- }
- this.showMonth(month, year);
- },
- /**
- * Event handler. Called when a day has been tapped.
- *
- * @param evt {qx.event.type.Data} The event.
- */
- _onDayTap : function(evt)
- {
- var time = evt.getCurrentTarget().dateTime;
- this.setValue(new Date(time));
- },
- /**
- * Event handler. Called when a day has been double-tapped.
- */
- _onDayDblTap : function() {
- this.execute();
- },
- /**
- * Event handler. Called when a key was pressed.
- *
- * @param evt {qx.event.type.Data} The event.
- */
- _onKeyPress : function(evt)
- {
- var dayIncrement = null;
- var monthIncrement = null;
- var yearIncrement = null;
- if (evt.getModifiers() == 0)
- {
- switch(evt.getKeyIdentifier())
- {
- case "Left":
- dayIncrement = -1;
- break;
- case "Right":
- dayIncrement = 1;
- break;
- case "Up":
- dayIncrement = -7;
- break;
- case "Down":
- dayIncrement = 7;
- break;
- case "PageUp":
- monthIncrement = -1;
- break;
- case "PageDown":
- monthIncrement = 1;
- break;
- case "Escape":
- if (this.getValue() != null)
- {
- this.setValue(null);
- return;
- }
- break;
- case "Enter":
- case "Space":
- if (this.getValue() != null) {
- this.execute();
- }
- return;
- }
- }
- else if (evt.isShiftPressed())
- {
- switch(evt.getKeyIdentifier())
- {
- case "PageUp":
- yearIncrement = -1;
- break;
- case "PageDown":
- yearIncrement = 1;
- break;
- }
- }
- if (dayIncrement != null || monthIncrement != null || yearIncrement != null)
- {
- var date = this.getValue();
- if (date != null) {
- date = new Date(date.getTime());
- }
- if (date == null) {
- date = new Date();
- }
- else
- {
- if (dayIncrement != null){date.setDate(date.getDate() + dayIncrement);}
- if (monthIncrement != null){date.setMonth(date.getMonth() + monthIncrement);}
- if (yearIncrement != null){date.setFullYear(date.getFullYear() + yearIncrement);}
- }
- this.setValue(date);
- }
- },
- /**
- * Shows a certain month.
- *
- * @param month {Integer ? null} the month to show (0 = january). If not set
- * the month will remain the same.
- * @param year {Integer ? null} the year to show. If not set the year will
- * remain the same.
- */
- showMonth : function(month, year)
- {
- if ((month != null && month != this.getShownMonth()) || (year != null && year != this.getShownYear()))
- {
- if (month != null) {
- this.setShownMonth(month);
- }
- if (year != null) {
- this.setShownYear(year);
- }
- this._updateDatePane();
- }
- },
- /**
- * Event handler. Used to handle the key events.
- *
- * @param e {qx.event.type.Data} The event.
- */
- handleKeyPress : function(e) {
- this._onKeyPress(e);
- },
- /**
- * Updates the date pane.
- */
- _updateDatePane : function()
- {
- var DateChooser = qx.ui.control.DateChooser;
- var today = new Date();
- var todayYear = today.getFullYear();
- var todayMonth = today.getMonth();
- var todayDayOfMonth = today.getDate();
- var selDate = this.getValue();
- var selYear = (selDate == null) ? -1 : selDate.getFullYear();
- var selMonth = (selDate == null) ? -1 : selDate.getMonth();
- var selDayOfMonth = (selDate == null) ? -1 : selDate.getDate();
- var shownMonth = this.getShownMonth();
- var shownYear = this.getShownYear();
- var startOfWeek = qx.locale.Date.getWeekStart();
- // Create a help date that points to the first of the current month
- var helpDate = new Date(this.getShownYear(), this.getShownMonth(), 1);
- var monthYearFormat = new qx.util.format.DateFormat(DateChooser.MONTH_YEAR_FORMAT);
- this.getChildControl("month-year-label").setValue(monthYearFormat.format(helpDate));
- // Show the day names
- var firstDayOfWeek = helpDate.getDay();
- var firstSundayInMonth = 1 + ((7 - firstDayOfWeek) % 7);
- var weekDayFormat = new qx.util.format.DateFormat(DateChooser.WEEKDAY_FORMAT);
- for (var i=0; i<7; i++)
- {
- var day = (i + startOfWeek) % 7;
- var dayLabel = this.__weekdayLabelArr[i];
- helpDate.setDate(firstSundayInMonth + day);
- dayLabel.setValue(weekDayFormat.format(helpDate));
- if (qx.locale.Date.isWeekend(day)) {
- dayLabel.addState("weekend");
- } else {
- dayLabel.removeState("weekend");
- }
- }
- // Show the days
- helpDate = new Date(shownYear, shownMonth, 1, 12, 0, 0);
- var nrDaysOfLastMonth = (7 + firstDayOfWeek - startOfWeek) % 7;
- helpDate.setDate(helpDate.getDate() - nrDaysOfLastMonth);
- var weekFormat = new qx.util.format.DateFormat(DateChooser.WEEK_FORMAT);
- for (var week=0; week<6; week++)
- {
- this.__weekLabelArr[week].setValue(weekFormat.format(helpDate));
- for (var i=0; i<7; i++)
- {
- var dayLabel = this.__dayLabelArr[week * 7 + i];
- var year = helpDate.getFullYear();
- var month = helpDate.getMonth();
- var dayOfMonth = helpDate.getDate();
- var isSelectedDate = (selYear == year && selMonth == month && selDayOfMonth == dayOfMonth);
- if (isSelectedDate) {
- dayLabel.addState("selected");
- } else {
- dayLabel.removeState("selected");
- }
- if (month != shownMonth) {
- dayLabel.addState("otherMonth");
- } else {
- dayLabel.removeState("otherMonth");
- }
- var isToday = (year == todayYear && month == todayMonth && dayOfMonth == todayDayOfMonth);
- if (isToday) {
- dayLabel.addState("today");
- } else {
- dayLabel.removeState("today");
- }
- dayLabel.setValue("" + dayOfMonth);
- dayLabel.dateTime = helpDate.getTime();
- // Go to the next day
- helpDate.setDate(helpDate.getDate() + 1);
- }
- }
- monthYearFormat.dispose();
- weekDayFormat.dispose();
- weekFormat.dispose();
- }
- },
- /*
- *****************************************************************************
- DESTRUCTOR
- *****************************************************************************
- */
- destruct : function()
- {
- if (qx.core.Environment.get("qx.dynlocale")) {
- qx.locale.Manager.getInstance().removeListener("changeLocale", this._updateDatePane, this);
- }
- this.__weekdayLabelArr = this.__dayLabelArr = this.__weekLabelArr = null;
- }
- });