188 lines
5.3 KiB
JavaScript
188 lines
5.3 KiB
JavaScript
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||
|
|
||
|
"use strict";
|
||
|
|
||
|
const Cc = Components.classes;
|
||
|
const Ci = Components.interfaces;
|
||
|
const Cu = Components.utils;
|
||
|
|
||
|
const DEBUG = false;
|
||
|
function debug(aStr) {
|
||
|
if (DEBUG) {
|
||
|
dump("-*- DateTimePickerHelper: " + aStr + "\n");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
this.EXPORTED_SYMBOLS = [
|
||
|
"DateTimePickerHelper"
|
||
|
];
|
||
|
|
||
|
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||
|
Cu.import("resource://gre/modules/Services.jsm");
|
||
|
Cu.import("resource://gre/modules/Task.jsm");
|
||
|
|
||
|
/*
|
||
|
* DateTimePickerHelper receives message from content side (input box) and
|
||
|
* is reposible for opening, closing and updating the picker. Similary,
|
||
|
* DateTimePickerHelper listens for picker's events and notifies the content
|
||
|
* side (input box) about them.
|
||
|
*/
|
||
|
this.DateTimePickerHelper = {
|
||
|
picker: null,
|
||
|
weakBrowser: null,
|
||
|
|
||
|
MESSAGES: [
|
||
|
"FormDateTime:OpenPicker",
|
||
|
"FormDateTime:ClosePicker",
|
||
|
"FormDateTime:UpdatePicker"
|
||
|
],
|
||
|
|
||
|
init: function() {
|
||
|
for (let msg of this.MESSAGES) {
|
||
|
Services.mm.addMessageListener(msg, this);
|
||
|
}
|
||
|
},
|
||
|
|
||
|
uninit: function() {
|
||
|
for (let msg of this.MESSAGES) {
|
||
|
Services.mm.removeMessageListener(msg, this);
|
||
|
}
|
||
|
},
|
||
|
|
||
|
// nsIMessageListener
|
||
|
receiveMessage: function(aMessage) {
|
||
|
debug("receiveMessage: " + aMessage.name);
|
||
|
switch (aMessage.name) {
|
||
|
case "FormDateTime:OpenPicker": {
|
||
|
this.showPicker(aMessage.target, aMessage.data);
|
||
|
break;
|
||
|
}
|
||
|
case "FormDateTime:ClosePicker": {
|
||
|
if (!this.picker) {
|
||
|
return;
|
||
|
}
|
||
|
this.picker.closePicker();
|
||
|
this.close();
|
||
|
break;
|
||
|
}
|
||
|
case "FormDateTime:UpdatePicker": {
|
||
|
if (!this.picker) {
|
||
|
return;
|
||
|
}
|
||
|
this.picker.setPopupValue(aMessage.data);
|
||
|
break;
|
||
|
}
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
},
|
||
|
|
||
|
// nsIDOMEventListener
|
||
|
handleEvent: function(aEvent) {
|
||
|
debug("handleEvent: " + aEvent.type);
|
||
|
switch (aEvent.type) {
|
||
|
case "DateTimePickerValueChanged": {
|
||
|
this.updateInputBoxValue(aEvent);
|
||
|
break;
|
||
|
}
|
||
|
case "popuphidden": {
|
||
|
let browser = this.weakBrowser ? this.weakBrowser.get() : null;
|
||
|
if (browser) {
|
||
|
browser.messageManager.sendAsyncMessage("FormDateTime:PickerClosed");
|
||
|
}
|
||
|
this.picker.closePicker();
|
||
|
this.close();
|
||
|
break;
|
||
|
}
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
},
|
||
|
|
||
|
// Called when picker value has changed, notify input box about it.
|
||
|
updateInputBoxValue: function(aEvent) {
|
||
|
let browser = this.weakBrowser ? this.weakBrowser.get() : null;
|
||
|
if (browser) {
|
||
|
browser.messageManager.sendAsyncMessage(
|
||
|
"FormDateTime:PickerValueChanged", aEvent.detail);
|
||
|
}
|
||
|
},
|
||
|
|
||
|
// Get picker from browser and show it anchored to the input box.
|
||
|
showPicker: Task.async(function* (aBrowser, aData) {
|
||
|
let rect = aData.rect;
|
||
|
let dir = aData.dir;
|
||
|
let type = aData.type;
|
||
|
let detail = aData.detail;
|
||
|
|
||
|
this._anchor = aBrowser.ownerGlobal.gBrowser.popupAnchor;
|
||
|
this._anchor.left = rect.left;
|
||
|
this._anchor.top = rect.top;
|
||
|
this._anchor.width = rect.width;
|
||
|
this._anchor.height = rect.height;
|
||
|
this._anchor.hidden = false;
|
||
|
|
||
|
debug("Opening picker with details: " + JSON.stringify(detail));
|
||
|
|
||
|
let window = aBrowser.ownerDocument.defaultView;
|
||
|
let tabbrowser = window.gBrowser;
|
||
|
if (Services.focus.activeWindow != window ||
|
||
|
tabbrowser.selectedBrowser != aBrowser) {
|
||
|
// We were sent a message from a window or tab that went into the
|
||
|
// background, so we'll ignore it for now.
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
this.weakBrowser = Cu.getWeakReference(aBrowser);
|
||
|
this.picker = aBrowser.dateTimePicker;
|
||
|
if (!this.picker) {
|
||
|
debug("aBrowser.dateTimePicker not found, exiting now.");
|
||
|
return;
|
||
|
}
|
||
|
// The datetimepopup binding is only attached when it is needed.
|
||
|
// Check if openPicker method is present to determine if binding has
|
||
|
// been attached. If not, attach the binding first before calling it.
|
||
|
if (!this.picker.openPicker) {
|
||
|
let bindingPromise = new Promise(resolve => {
|
||
|
this.picker.addEventListener("DateTimePickerBindingReady",
|
||
|
resolve, {once: true});
|
||
|
});
|
||
|
this.picker.setAttribute("active", true);
|
||
|
yield bindingPromise;
|
||
|
}
|
||
|
// The arrow panel needs an anchor to work. The popupAnchor (this._anchor)
|
||
|
// is a transparent div that the arrow can point to.
|
||
|
this.picker.openPicker(type, this._anchor, detail);
|
||
|
|
||
|
this.addPickerListeners();
|
||
|
}),
|
||
|
|
||
|
// Picker is closed, do some cleanup.
|
||
|
close: function() {
|
||
|
this.removePickerListeners();
|
||
|
this.picker = null;
|
||
|
this.weakBrowser = null;
|
||
|
this._anchor.hidden = true;
|
||
|
},
|
||
|
|
||
|
// Listen to picker's event.
|
||
|
addPickerListeners: function() {
|
||
|
if (!this.picker) {
|
||
|
return;
|
||
|
}
|
||
|
this.picker.addEventListener("popuphidden", this);
|
||
|
this.picker.addEventListener("DateTimePickerValueChanged", this);
|
||
|
},
|
||
|
|
||
|
// Stop listening to picker's event.
|
||
|
removePickerListeners: function() {
|
||
|
if (!this.picker) {
|
||
|
return;
|
||
|
}
|
||
|
this.picker.removeEventListener("popuphidden", this);
|
||
|
this.picker.removeEventListener("DateTimePickerValueChanged", this);
|
||
|
},
|
||
|
};
|