1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 var EXPORTED_SYMBOLS = ["DateTimePickerPanel"];
9 const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
11 var DateTimePickerPanel = class {
12 constructor(element) {
13 this.element = element;
15 this.TIME_PICKER_WIDTH = "12em";
16 this.TIME_PICKER_HEIGHT = "21em";
17 this.DATE_PICKER_WIDTH = "23.1em";
18 this.DATE_PICKER_HEIGHT = "20.7em";
21 get dateTimePopupFrame() {
22 let frame = this.element.querySelector("#dateTimePopupFrame");
24 frame = this.element.ownerDocument.createXULElement("iframe");
25 frame.id = "dateTimePopupFrame";
26 this.element.appendChild(frame);
31 openPicker(type, anchor, detail) {
33 this.pickerState = {};
34 // TODO: Resize picker according to content zoom level
35 this.element.style.fontSize = "10px";
39 this.dateTimePopupFrame.addEventListener("load", this, true);
40 this.dateTimePopupFrame.setAttribute(
42 "chrome://global/content/timepicker.xhtml"
44 this.dateTimePopupFrame.style.width = this.TIME_PICKER_WIDTH;
45 this.dateTimePopupFrame.style.height = this.TIME_PICKER_HEIGHT;
50 this.dateTimePopupFrame.addEventListener("load", this, true);
51 this.dateTimePopupFrame.setAttribute(
53 "chrome://global/content/datepicker.xhtml"
55 this.dateTimePopupFrame.style.width = this.DATE_PICKER_WIDTH;
56 this.dateTimePopupFrame.style.height = this.DATE_PICKER_HEIGHT;
60 this.element.hidden = false;
61 this.element.openPopup(anchor, "after_start", 0, 0);
65 this.setInputBoxValue(true);
66 this.pickerState = {};
67 this.type = undefined;
68 this.dateTimePopupFrame.removeEventListener("load", this, true);
69 this.dateTimePopupFrame.contentDocument.removeEventListener(
73 this.dateTimePopupFrame.setAttribute("src", "");
74 this.element.hidden = true;
80 this.postMessageToPicker({
81 name: "PickerSetValue",
87 const { year, month, day } = data.value;
88 this.postMessageToPicker({
89 name: "PickerSetValue",
92 // Month value from input box starts from 1 instead of 0
93 month: month == undefined ? undefined : month - 1,
103 // TODO: When bug 1376616 lands, replace this.setGregorian with
104 // mozIntl.Locale for setting calendar to Gregorian
105 let locale = this.setGregorian(Services.locale.webExposedLocales[0]);
107 // Workaround for bug 1418061, while we wait for resolution of
108 // http://bugs.icu-project.org/trac/ticket/13592: drop the PT region code,
109 // because it results in "abbreviated" day names that are too long;
110 // the region-less "pt" locale has shorter forms that are better here.
111 locale = locale.replace(/^pt-PT/i, "pt");
113 const dir = Services.intl.getLocaleInfo(locale).direction;
117 const { hour, minute } = detail.value;
118 const format = detail.format || "12";
120 this.postMessageToPicker({
135 const { year, month, day } = detail.value;
136 const { firstDayOfWeek, weekends } = this.getCalendarInfo(locale);
137 const monthStrings = this.getDisplayNames(
140 "dates/gregorian/months/january",
141 "dates/gregorian/months/february",
142 "dates/gregorian/months/march",
143 "dates/gregorian/months/april",
144 "dates/gregorian/months/may",
145 "dates/gregorian/months/june",
146 "dates/gregorian/months/july",
147 "dates/gregorian/months/august",
148 "dates/gregorian/months/september",
149 "dates/gregorian/months/october",
150 "dates/gregorian/months/november",
151 "dates/gregorian/months/december",
155 const weekdayStrings = this.getDisplayNames(
158 "dates/gregorian/weekdays/sunday",
159 "dates/gregorian/weekdays/monday",
160 "dates/gregorian/weekdays/tuesday",
161 "dates/gregorian/weekdays/wednesday",
162 "dates/gregorian/weekdays/thursday",
163 "dates/gregorian/weekdays/friday",
164 "dates/gregorian/weekdays/saturday",
169 this.postMessageToPicker({
173 // Month value from input box starts from 1 instead of 0
174 month: month == undefined ? undefined : month - 1,
185 stepBase: detail.stepBase,
194 * @param {Boolean} passAllValues: Pass spinner values regardless if they've been set/changed or not
196 setInputBoxValue(passAllValues) {
205 } = this.pickerState;
206 const isAnyValueSet = isHourSet || isMinuteSet || isDayPeriodSet;
207 if (passAllValues && isAnyValueSet) {
208 this.sendPickerValueChanged({ hour, minute });
210 this.sendPickerValueChanged({
211 hour: isHourSet || isDayPeriodSet ? hour : undefined,
212 minute: isMinuteSet ? minute : undefined,
218 this.sendPickerValueChanged(this.pickerState);
224 sendPickerValueChanged(value) {
227 this.element.dispatchEvent(
228 new CustomEvent("DateTimePickerValueChanged", {
231 minute: value.minute,
238 this.element.dispatchEvent(
239 new CustomEvent("DateTimePickerValueChanged", {
242 // Month value from input box starts from 1 instead of 0
243 month: value.month == undefined ? undefined : value.month + 1,
253 getCalendarInfo(locale) {
254 const calendarInfo = Services.intl.getCalendarInfo(locale);
256 // Day of week from calendarInfo starts from 1 as Sunday to 7 as Saturday,
257 // so they need to be mapped to JavaScript convention with 0 as Sunday
259 let firstDayOfWeek = calendarInfo.firstDayOfWeek - 1,
260 weekendStart = calendarInfo.weekendStart - 1,
261 weekendEnd = calendarInfo.weekendEnd - 1;
265 // Make sure weekendEnd is greater than weekendStart
266 if (weekendEnd < weekendStart) {
270 // We get the weekends by incrementing weekendStart up to weekendEnd.
271 // If the start and end is the same day, then weekends only has one day.
272 for (let day = weekendStart; day <= weekendEnd; day++) {
273 weekends.push(day % 7);
282 getDisplayNames(locale, keys, style) {
283 const displayNames = Services.intl.getDisplayNames(locale, { keys, style });
284 return keys.map(key => displayNames.values[key]);
287 setGregorian(locale) {
288 if (locale.match(/u-ca-/)) {
289 return locale.replace(/u-ca-[^-]+/, "u-ca-gregory");
291 return locale + "-u-ca-gregory";
294 handleEvent(aEvent) {
295 switch (aEvent.type) {
297 this.initPicker(this.detail);
298 this.dateTimePopupFrame.contentWindow.addEventListener("message", this);
302 this.handleMessage(aEvent);
308 handleMessage(aEvent) {
310 !this.dateTimePopupFrame.contentDocument.nodePrincipal.isSystemPrincipal
315 switch (aEvent.data.name) {
316 case "PickerPopupChanged": {
317 this.pickerState = aEvent.data.detail;
318 this.setInputBoxValue();
322 this.element.hidePopup();
329 postMessageToPicker(data) {
331 this.dateTimePopupFrame.contentDocument.nodePrincipal.isSystemPrincipal
333 this.dateTimePopupFrame.contentWindow.postMessage(data, "*");