зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1828477 - Support input type=date in non-tabbrowser windows. r=Gijs,geckoview-reviewers,ohall
Differential Revision: https://phabricator.services.mozilla.com/D175771
This commit is contained in:
Родитель
d4b63553f2
Коммит
1d61a94f1b
|
@ -136,21 +136,6 @@
|
|||
noautofocus="true"
|
||||
hidden="true" />
|
||||
|
||||
<html:template id="dateTimePickerTemplate">
|
||||
<!-- for date/time picker. consumeoutsideclicks is set to never, so that
|
||||
clicks on the anchored input box are never consumed. -->
|
||||
<panel id="DateTimePickerPanel"
|
||||
type="arrow"
|
||||
orient="vertical"
|
||||
ignorekeys="true"
|
||||
norolluponanchor="true"
|
||||
noautofocus="true"
|
||||
consumeoutsideclicks="never"
|
||||
level="parent"
|
||||
tabspecific="true">
|
||||
</panel>
|
||||
</html:template>
|
||||
|
||||
<html:template id="printPreviewStackTemplate">
|
||||
<stack class="previewStack" rendering="true" flex="1" previewtype="primary">
|
||||
<vbox class="previewRendering" flex="1">
|
||||
|
|
|
@ -172,8 +172,6 @@
|
|||
|
||||
arrowKeysShouldWrap: AppConstants == "macosx",
|
||||
|
||||
_dateTimePicker: null,
|
||||
|
||||
_previewMode: false,
|
||||
|
||||
_lastFindValue: "",
|
||||
|
@ -806,16 +804,6 @@
|
|||
}
|
||||
},
|
||||
|
||||
_getAndMaybeCreateDateTimePickerPanel() {
|
||||
if (!this._dateTimePicker) {
|
||||
let wrapper = document.getElementById("dateTimePickerTemplate");
|
||||
wrapper.replaceWith(wrapper.content);
|
||||
this._dateTimePicker = document.getElementById("DateTimePickerPanel");
|
||||
}
|
||||
|
||||
return this._dateTimePicker;
|
||||
},
|
||||
|
||||
syncThrobberAnimations(aTab) {
|
||||
aTab.ownerGlobal.promiseDocumentFlushed(() => {
|
||||
if (!aTab.container) {
|
||||
|
|
|
@ -723,7 +723,7 @@ partial interface Window {
|
|||
[NewObject, Func="nsGlobalWindowInner::IsPrivilegedChromeWindow"]
|
||||
Promise<any> promiseDocumentFlushed(PromiseDocumentFlushedCallback callback);
|
||||
|
||||
[ChromeOnly]
|
||||
[Func="IsChromeOrUAWidget"]
|
||||
readonly attribute boolean isChromeWindow;
|
||||
|
||||
[ChromeOnly]
|
||||
|
|
|
@ -226,23 +226,28 @@ class PromptFactory {
|
|||
}
|
||||
|
||||
_handleDateTime(aElement) {
|
||||
const prompt = new lazy.GeckoViewPrompter(aElement.ownerGlobal);
|
||||
const win = aElement.ownerGlobal;
|
||||
const prompt = new lazy.GeckoViewPrompter(win);
|
||||
|
||||
const chromeEventHandler = aElement.ownerGlobal.docShell.chromeEventHandler;
|
||||
const dismissPrompt = () => prompt.dismiss();
|
||||
// Some controls don't have UA widget (bug 888320)
|
||||
if (
|
||||
["month", "week"].includes(aElement.type) &&
|
||||
!aElement.openOrClosedShadowRoot
|
||||
) {
|
||||
aElement.addEventListener("blur", dismissPrompt, {
|
||||
mozSystemGroup: true,
|
||||
});
|
||||
} else {
|
||||
chromeEventHandler.addEventListener(
|
||||
"MozCloseDateTimePicker",
|
||||
dismissPrompt
|
||||
);
|
||||
{
|
||||
const dateTimeBoxElement = aElement.dateTimeBoxElement;
|
||||
if (["month", "week"].includes(aElement.type) && !dateTimeBoxElement) {
|
||||
aElement.addEventListener("blur", dismissPrompt, {
|
||||
mozSystemGroup: true,
|
||||
});
|
||||
} else {
|
||||
chromeEventHandler.addEventListener(
|
||||
"MozCloseDateTimePicker",
|
||||
dismissPrompt
|
||||
);
|
||||
|
||||
dateTimeBoxElement.dispatchEvent(
|
||||
new win.CustomEvent("MozSetDateTimePickerState", { detail: true })
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
prompt.asyncShowPrompt(
|
||||
|
@ -256,10 +261,8 @@ class PromptFactory {
|
|||
},
|
||||
result => {
|
||||
// Some controls don't have UA widget (bug 888320)
|
||||
if (
|
||||
["month", "week"].includes(aElement.type) &&
|
||||
!aElement.openOrClosedShadowRoot
|
||||
) {
|
||||
const dateTimeBoxElement = aElement.dateTimeBoxElement;
|
||||
if (["month", "week"].includes(aElement.type) && !dateTimeBoxElement) {
|
||||
aElement.removeEventListener("blur", dismissPrompt, {
|
||||
mozSystemGroup: true,
|
||||
});
|
||||
|
@ -268,6 +271,9 @@ class PromptFactory {
|
|||
"MozCloseDateTimePicker",
|
||||
dismissPrompt
|
||||
);
|
||||
dateTimeBoxElement.dispatchEvent(
|
||||
new win.CustomEvent("MozSetDateTimePickerState", { detail: false })
|
||||
);
|
||||
}
|
||||
|
||||
// OK: result
|
||||
|
|
|
@ -1412,6 +1412,87 @@ export var BrowserTestUtils = {
|
|||
return menulist.menupopup;
|
||||
},
|
||||
|
||||
/**
|
||||
* Waits for the datetime picker popup to be shown.
|
||||
*
|
||||
* @param {Window} win
|
||||
* A window to expect the popup in.
|
||||
*
|
||||
* @return {Promise}
|
||||
* Resolves when the popup has been fully opened. The resolution value
|
||||
* is the select popup.
|
||||
*/
|
||||
async waitForDateTimePickerPanelShown(win) {
|
||||
let getPanel = () => win.document.getElementById("DateTimePickerPanel");
|
||||
let panel = getPanel();
|
||||
let ensureReady = async () => {
|
||||
let frame = panel.querySelector("#dateTimePopupFrame");
|
||||
let isValidUrl = () => {
|
||||
return (
|
||||
frame.browsingContext?.currentURI?.spec ==
|
||||
"chrome://global/content/datepicker.xhtml" ||
|
||||
frame.browsingContext?.currentURI?.spec ==
|
||||
"chrome://global/content/timepicker.xhtml"
|
||||
);
|
||||
};
|
||||
|
||||
// Ensure it's loaded.
|
||||
if (!isValidUrl() || frame.contentDocument.readyState != "complete") {
|
||||
await new Promise(resolve => {
|
||||
frame.addEventListener(
|
||||
"load",
|
||||
function listener() {
|
||||
if (isValidUrl()) {
|
||||
frame.removeEventListener("load", listener, { capture: true });
|
||||
resolve();
|
||||
}
|
||||
},
|
||||
{ capture: true }
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
// Ensure it's ready.
|
||||
if (!frame.contentWindow.PICKER_READY) {
|
||||
await new Promise(resolve => {
|
||||
frame.contentDocument.addEventListener("PickerReady", resolve, {
|
||||
once: true,
|
||||
});
|
||||
});
|
||||
}
|
||||
// And that l10n mutations are flushed.
|
||||
// FIXME(bug 1828721): We should ideally localize everything before
|
||||
// showing the panel.
|
||||
if (frame.contentDocument.hasPendingL10nMutations) {
|
||||
await new Promise(resolve => {
|
||||
frame.contentDocument.addEventListener(
|
||||
"L10nMutationsFinished",
|
||||
resolve,
|
||||
{
|
||||
once: true,
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
if (!panel) {
|
||||
await this.waitForMutationCondition(
|
||||
win.document,
|
||||
{ childList: true, subtree: true },
|
||||
getPanel
|
||||
);
|
||||
panel = getPanel();
|
||||
if (panel.state == "open") {
|
||||
await ensureReady();
|
||||
return panel;
|
||||
}
|
||||
}
|
||||
await this.waitForEvent(panel, "popupshown");
|
||||
await ensureReady();
|
||||
return panel;
|
||||
},
|
||||
|
||||
/**
|
||||
* Adds a content event listener on the given browser
|
||||
* element. Similar to waitForContentEvent, but the listener will
|
||||
|
|
|
@ -33,14 +33,12 @@ export class DateTimePickerChild extends JSWindowActorChild {
|
|||
return;
|
||||
}
|
||||
|
||||
if (this._inputElement.openOrClosedShadowRoot) {
|
||||
// dateTimeBoxElement is within UA Widget Shadow DOM.
|
||||
// An event dispatch to it can't be accessed by document.
|
||||
let win = this._inputElement.ownerGlobal;
|
||||
dateTimeBoxElement.dispatchEvent(
|
||||
new win.CustomEvent("MozSetDateTimePickerState", { detail: false })
|
||||
);
|
||||
}
|
||||
// dateTimeBoxElement is within UA Widget Shadow DOM.
|
||||
// An event dispatch to it can't be accessed by document.
|
||||
let win = this._inputElement.ownerGlobal;
|
||||
dateTimeBoxElement.dispatchEvent(
|
||||
new win.CustomEvent("MozSetDateTimePickerState", { detail: false })
|
||||
);
|
||||
|
||||
this._inputElement = null;
|
||||
}
|
||||
|
@ -148,20 +146,16 @@ export class DateTimePickerChild extends JSWindowActorChild {
|
|||
|
||||
let dateTimeBoxElement = this._inputElement.dateTimeBoxElement;
|
||||
if (!dateTimeBoxElement) {
|
||||
throw new Error(
|
||||
"How do we get this event without a UA Widget or XBL binding?"
|
||||
);
|
||||
throw new Error("How do we get this event without a UA Widget?");
|
||||
}
|
||||
|
||||
if (this._inputElement.openOrClosedShadowRoot) {
|
||||
// dateTimeBoxElement is within UA Widget Shadow DOM.
|
||||
// An event dispatch to it can't be accessed by document, because
|
||||
// the event is not composed.
|
||||
let win = this._inputElement.ownerGlobal;
|
||||
dateTimeBoxElement.dispatchEvent(
|
||||
new win.CustomEvent("MozSetDateTimePickerState", { detail: true })
|
||||
);
|
||||
}
|
||||
// dateTimeBoxElement is within UA Widget Shadow DOM.
|
||||
// An event dispatch to it can't be accessed by document, because
|
||||
// the event is not composed.
|
||||
let win = this._inputElement.ownerGlobal;
|
||||
dateTimeBoxElement.dispatchEvent(
|
||||
new win.CustomEvent("MozSetDateTimePickerState", { detail: true })
|
||||
);
|
||||
|
||||
this.addListeners(this._inputElement);
|
||||
|
||||
|
|
|
@ -25,16 +25,13 @@ export class DateTimePickerParent extends JSWindowActorParent {
|
|||
debug("receiveMessage: " + aMessage.name);
|
||||
switch (aMessage.name) {
|
||||
case "FormDateTime:OpenPicker": {
|
||||
let topBrowsingContext = this.manager.browsingContext.top;
|
||||
let browser = topBrowsingContext.embedderElement;
|
||||
this.showPicker(browser, aMessage.data);
|
||||
this.showPicker(aMessage.data);
|
||||
break;
|
||||
}
|
||||
case "FormDateTime:ClosePicker": {
|
||||
if (!this._picker) {
|
||||
return;
|
||||
}
|
||||
this._picker.closePicker();
|
||||
this.close();
|
||||
break;
|
||||
}
|
||||
|
@ -63,7 +60,6 @@ export class DateTimePickerParent extends JSWindowActorParent {
|
|||
}
|
||||
case "popuphidden": {
|
||||
this.sendAsyncMessage("FormDateTime:PickerClosed", {});
|
||||
this._picker.closePicker();
|
||||
this.close();
|
||||
break;
|
||||
}
|
||||
|
@ -73,45 +69,62 @@ export class DateTimePickerParent extends JSWindowActorParent {
|
|||
}
|
||||
|
||||
// Get picker from browser and show it anchored to the input box.
|
||||
showPicker(aBrowser, aData) {
|
||||
showPicker(aData) {
|
||||
let rect = aData.rect;
|
||||
let type = aData.type;
|
||||
let detail = aData.detail;
|
||||
|
||||
debug("Opening picker with details: " + JSON.stringify(detail));
|
||||
|
||||
let window = aBrowser.ownerGlobal;
|
||||
let tabbrowser = window.gBrowser;
|
||||
if (!tabbrowser) {
|
||||
// TODO(bug 1828477): Support non-<tabbrowser> windows
|
||||
debug("no tabbrowser, exiting now.");
|
||||
let topBC = this.browsingContext.top;
|
||||
let window = topBC.topChromeWindow;
|
||||
if (Services.focus.activeWindow != window) {
|
||||
debug("Not in the active window");
|
||||
return;
|
||||
}
|
||||
|
||||
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;
|
||||
{
|
||||
let browser = topBC.embedderElement;
|
||||
if (
|
||||
browser &&
|
||||
browser.ownerGlobal.gBrowser &&
|
||||
browser.ownerGlobal.gBrowser.selectedBrowser != browser
|
||||
) {
|
||||
debug("In background tab");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let panel = tabbrowser._getAndMaybeCreateDateTimePickerPanel();
|
||||
this.oldFocus = window.document.activeElement;
|
||||
let doc = window.document;
|
||||
let panel = doc.getElementById("DateTimePickerPanel");
|
||||
if (!panel) {
|
||||
panel = doc.createXULElement("panel");
|
||||
panel.id = "DateTimePickerPanel";
|
||||
panel.setAttribute("type", "arrow");
|
||||
panel.setAttribute("orient", "vertical");
|
||||
panel.setAttribute("ignorekeys", "true");
|
||||
panel.setAttribute("noautofocus", "true");
|
||||
// This ensures that clicks on the anchored input box are never consumed.
|
||||
panel.setAttribute("consumeoutsideclicks", "never");
|
||||
panel.setAttribute("level", "parent");
|
||||
panel.setAttribute("tabspecific", "true");
|
||||
let container =
|
||||
doc.getElementById("mainPopupSet") ||
|
||||
doc.querySelector("popupset") ||
|
||||
doc.documentElement.appendChild(doc.createXULElement("popupset"));
|
||||
container.appendChild(panel);
|
||||
}
|
||||
this._oldFocus = doc.activeElement;
|
||||
this._picker = new lazy.DateTimePickerPanel(panel);
|
||||
this._picker.openPicker(type, rect, detail);
|
||||
|
||||
this.addPickerListeners();
|
||||
}
|
||||
|
||||
// Picker is closed, do some cleanup.
|
||||
// Close the picker and do some cleanup.
|
||||
close() {
|
||||
if (this.oldFocus) {
|
||||
// Restore focus to where it was before the picker opened.
|
||||
this.oldFocus.focus();
|
||||
this.oldFocus = null;
|
||||
}
|
||||
this._picker.closePicker();
|
||||
// Restore focus to where it was before the picker opened.
|
||||
this._oldFocus?.focus();
|
||||
this._oldFocus = null;
|
||||
this.removePickerListeners();
|
||||
this._picker = null;
|
||||
}
|
||||
|
|
|
@ -61,6 +61,7 @@ skip-if =
|
|||
os == "linux" && fission && socketprocess_networking && !debug # high frequency intermittent, Bug 1673140
|
||||
[browser_datetime_showPicker.js]
|
||||
# do not skip
|
||||
[browser_datetime_toplevel.js]
|
||||
[browser_spinner.js]
|
||||
skip-if =
|
||||
tsan # Frequently times out on TSan
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* https://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
add_task(async function() {
|
||||
let input = document.createElement("input");
|
||||
input.type = "date";
|
||||
registerCleanupFunction(() => input.remove());
|
||||
document.body.appendChild(input);
|
||||
|
||||
let shown = BrowserTestUtils.waitForDateTimePickerPanelShown(window);
|
||||
|
||||
const shadowRoot = SpecialPowers.wrap(input).openOrClosedShadowRoot;
|
||||
|
||||
EventUtils.synthesizeMouseAtCenter(
|
||||
shadowRoot.getElementById("calendar-button"),
|
||||
{}
|
||||
);
|
||||
|
||||
let popup = await shown;
|
||||
ok(!!popup, "Should've shown the popup");
|
||||
|
||||
let hidden = BrowserTestUtils.waitForPopupEvent(popup, "hidden");
|
||||
popup.hidePopup();
|
||||
|
||||
await hidden;
|
||||
popup.remove();
|
||||
});
|
|
@ -9,8 +9,7 @@
|
|||
*/
|
||||
class DateTimeTestHelper {
|
||||
constructor() {
|
||||
this.panel = gBrowser._getAndMaybeCreateDateTimePickerPanel();
|
||||
this.panel.setAttribute("animate", false);
|
||||
this.panel = null;
|
||||
this.tab = null;
|
||||
this.frame = null;
|
||||
}
|
||||
|
@ -40,6 +39,8 @@ class DateTimeTestHelper {
|
|||
await SpecialPowers.contentTransformsReceived(content);
|
||||
});
|
||||
|
||||
let shown = this.waitForPickerReady();
|
||||
|
||||
if (openMethod === "click") {
|
||||
await SpecialPowers.spawn(bc, [], () => {
|
||||
const input = content.document.querySelector("input");
|
||||
|
@ -52,8 +53,8 @@ class DateTimeTestHelper {
|
|||
content.document.querySelector("input").showPicker();
|
||||
});
|
||||
}
|
||||
this.panel = await shown;
|
||||
this.frame = this.panel.querySelector("#dateTimePopupFrame");
|
||||
await this.waitForPickerReady();
|
||||
}
|
||||
|
||||
promisePickerClosed() {
|
||||
|
@ -79,35 +80,8 @@ class DateTimeTestHelper {
|
|||
);
|
||||
}
|
||||
|
||||
async waitForPickerReady() {
|
||||
let readyPromise;
|
||||
let loadPromise = new Promise(resolve => {
|
||||
let listener = () => {
|
||||
if (
|
||||
this.frame.browsingContext.currentURI.spec !=
|
||||
"chrome://global/content/datepicker.xhtml" &&
|
||||
this.frame.browsingContext.currentURI.spec !=
|
||||
"chrome://global/content/timepicker.xhtml"
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.frame.removeEventListener("load", listener, { capture: true });
|
||||
// Add the PickerReady event listener directly inside the load event
|
||||
// listener to avoid missing the event.
|
||||
readyPromise = BrowserTestUtils.waitForEvent(
|
||||
this.frame.contentDocument,
|
||||
"PickerReady"
|
||||
);
|
||||
resolve();
|
||||
};
|
||||
|
||||
this.frame.addEventListener("load", listener, { capture: true });
|
||||
});
|
||||
|
||||
await loadPromise;
|
||||
// Wait for picker elements to be ready
|
||||
await readyPromise;
|
||||
waitForPickerReady() {
|
||||
return BrowserTestUtils.waitForDateTimePickerPanelShown(window);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -156,9 +130,8 @@ class DateTimeTestHelper {
|
|||
* Clean up after tests. Remove the frame to prevent leak.
|
||||
*/
|
||||
cleanup() {
|
||||
this.frame.remove();
|
||||
this.frame?.remove();
|
||||
this.frame = null;
|
||||
this.panel.removeAttribute("animate");
|
||||
this.panel = null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,6 +41,8 @@ function DatePicker(context) {
|
|||
this._createComponents();
|
||||
this._update();
|
||||
this.components.calendar.focusDay();
|
||||
// TODO(bug 1828721): This is a bit sad.
|
||||
window.PICKER_READY = true;
|
||||
document.dispatchEvent(new CustomEvent("PickerReady"));
|
||||
},
|
||||
|
||||
|
|
|
@ -611,19 +611,34 @@ this.DateTimeBoxWidget = class {
|
|||
" target: " +
|
||||
aEvent.target +
|
||||
" rt: " +
|
||||
aEvent.relatedTarget
|
||||
aEvent.relatedTarget +
|
||||
" open: " +
|
||||
this.mIsPickerOpen
|
||||
);
|
||||
|
||||
let target = aEvent.originalTarget;
|
||||
target.setAttribute("typeBuffer", "");
|
||||
this.setInputValueFromFields();
|
||||
// No need to set and unset the focus state if the focus is staying within
|
||||
// our input. Same about closing the picker.
|
||||
if (aEvent.relatedTarget != this.mInputElement) {
|
||||
this.mInputElement.setFocusState(false);
|
||||
if (this.mIsPickerOpen) {
|
||||
this.closeDateTimePicker();
|
||||
}
|
||||
// No need to set and unset the focus state (or closing the picker) if the
|
||||
// focus is staying within our input.
|
||||
if (aEvent.relatedTarget == this.mInputElement) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If we're in chrome and the focus moves to a separate document
|
||||
// (relatedTarget is null) we also don't want to close it, since it
|
||||
// could've moved to the datetime popup itself.
|
||||
if (
|
||||
!aEvent.relatedTarget &&
|
||||
this.window.isChromeWindow &&
|
||||
this.window == this.window.top
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.mInputElement.setFocusState(false);
|
||||
if (this.mIsPickerOpen) {
|
||||
this.closeDateTimePicker();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -35,6 +35,8 @@ function TimePicker(context) {
|
|||
this._setDefaultState();
|
||||
this._createComponents();
|
||||
this._setComponentStates();
|
||||
// TODO(bug 1828721): This is a bit sad.
|
||||
window.PICKER_READY = true;
|
||||
document.dispatchEvent(new CustomEvent("PickerReady"));
|
||||
},
|
||||
|
||||
|
|
|
@ -236,23 +236,6 @@ let JSWINDOWACTORS = {
|
|||
enablePreference: "cookiebanners.bannerClicking.enabled",
|
||||
},
|
||||
|
||||
DateTimePicker: {
|
||||
parent: {
|
||||
esModuleURI: "resource://gre/actors/DateTimePickerParent.sys.mjs",
|
||||
},
|
||||
|
||||
child: {
|
||||
esModuleURI: "resource://gre/actors/DateTimePickerChild.sys.mjs",
|
||||
events: {
|
||||
MozOpenDateTimePicker: {},
|
||||
MozUpdateDateTimePicker: {},
|
||||
MozCloseDateTimePicker: {},
|
||||
},
|
||||
},
|
||||
|
||||
allFrames: true,
|
||||
},
|
||||
|
||||
ExtFind: {
|
||||
child: {
|
||||
esModuleURI: "resource://gre/actors/ExtFindChild.sys.mjs",
|
||||
|
@ -524,6 +507,7 @@ let JSWINDOWACTORS = {
|
|||
},
|
||||
},
|
||||
|
||||
includeChrome: true,
|
||||
allFrames: true,
|
||||
},
|
||||
|
||||
|
@ -582,9 +566,7 @@ if (AppConstants.platform != "android") {
|
|||
allFrames: true,
|
||||
};
|
||||
|
||||
/**
|
||||
* Note that GeckoView has another implementation in mobile/android/actors.
|
||||
*/
|
||||
// Note that GeckoView has another implementation in mobile/android/actors.
|
||||
JSWINDOWACTORS.Select = {
|
||||
parent: {
|
||||
esModuleURI: "resource://gre/actors/SelectParent.sys.mjs",
|
||||
|
@ -602,6 +584,25 @@ if (AppConstants.platform != "android") {
|
|||
includeChrome: true,
|
||||
allFrames: true,
|
||||
};
|
||||
|
||||
// Note that GeckoView handles MozOpenDateTimePicker in GeckoViewPrompt.
|
||||
JSWINDOWACTORS.DateTimePicker = {
|
||||
parent: {
|
||||
esModuleURI: "resource://gre/actors/DateTimePickerParent.sys.mjs",
|
||||
},
|
||||
|
||||
child: {
|
||||
esModuleURI: "resource://gre/actors/DateTimePickerChild.sys.mjs",
|
||||
events: {
|
||||
MozOpenDateTimePicker: {},
|
||||
MozUpdateDateTimePicker: {},
|
||||
MozCloseDateTimePicker: {},
|
||||
},
|
||||
},
|
||||
|
||||
includeChrome: true,
|
||||
allFrames: true,
|
||||
};
|
||||
}
|
||||
|
||||
export var ActorManagerParent = {
|
||||
|
|
Загрузка…
Ссылка в новой задаче