mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-09 11:25:00 +00:00
Bug 1845796 - Rework the flow in ScreenshotsUtils to make exit an explicit outcome rather than a side-effect. r=niklas
* Add a UIPhases / getUIPhase to figure out where we are in the flow, and get the UI into the right state * Refactor to get rid of a bunch of implicit side-effects: - Separate out getting the panel from creating it - closePanel only closes the buttons panel - Add a closeOverlay so we do that and only that when needed * When the preview dialog closes, we expect to exit unless exitOnPreviewClose was set false * Keep some state for each browser using a weakmap so we can better handle re-entry (and later, re-focusing) Differential Revision: https://phabricator.services.mozilla.com/D185379
This commit is contained in:
parent
9577662c72
commit
8165b4bf88
@ -80,6 +80,10 @@ export class ScreenshotsComponentChild extends JSWindowActorChild {
|
|||||||
case "Screenshots:Download":
|
case "Screenshots:Download":
|
||||||
this.requestDownloadScreenshot(event.detail.region);
|
this.requestDownloadScreenshot(event.detail.region);
|
||||||
break;
|
break;
|
||||||
|
case "Screenshots:OverlaySelection":
|
||||||
|
let { hasSelection } = event.detail;
|
||||||
|
this.sendOverlaySelection({ hasSelection });
|
||||||
|
break;
|
||||||
case "Screenshots:RecordEvent":
|
case "Screenshots:RecordEvent":
|
||||||
let { eventName, reason, args } = event.detail;
|
let { eventName, reason, args } = event.detail;
|
||||||
this.recordTelemetryEvent(eventName, reason, args);
|
this.recordTelemetryEvent(eventName, reason, args);
|
||||||
@ -139,6 +143,10 @@ export class ScreenshotsComponentChild extends JSWindowActorChild {
|
|||||||
return this.document.title;
|
return this.document.title;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sendOverlaySelection(data) {
|
||||||
|
this.sendAsyncMessage("Screenshots:OverlaySelection", data);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resolves when the document is ready to have an overlay injected into it.
|
* Resolves when the document is ready to have an overlay injected into it.
|
||||||
*
|
*
|
||||||
|
@ -714,8 +714,9 @@ let JSWINDOWACTORS = {
|
|||||||
"Screenshots:Copy": { wantUntrusted: true },
|
"Screenshots:Copy": { wantUntrusted: true },
|
||||||
"Screenshots:Download": { wantUntrusted: true },
|
"Screenshots:Download": { wantUntrusted: true },
|
||||||
"Screenshots:HidePanel": { wantUntrusted: true },
|
"Screenshots:HidePanel": { wantUntrusted: true },
|
||||||
"Screenshots:ShowPanel": { wantUntrusted: true },
|
"Screenshots:OverlaySelection": { wantUntrusted: true },
|
||||||
"Screenshots:RecordEvent": { wantUntrusted: true },
|
"Screenshots:RecordEvent": { wantUntrusted: true },
|
||||||
|
"Screenshots:ShowPanel": { wantUntrusted: true },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
enablePreference: "screenshots.browser.component.enabled",
|
enablePreference: "screenshots.browser.component.enabled",
|
||||||
|
@ -440,6 +440,11 @@ export class ScreenshotsOverlay {
|
|||||||
reason: "overlay_retry",
|
reason: "overlay_retry",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
if (newState !== this.#state) {
|
||||||
|
this.#dispatchEvent("Screenshots:OverlaySelection", {
|
||||||
|
hasSelection: newState == "selected",
|
||||||
|
});
|
||||||
|
}
|
||||||
this.#state = newState;
|
this.#state = newState;
|
||||||
|
|
||||||
switch (this.#state) {
|
switch (this.#state) {
|
||||||
|
@ -36,19 +36,29 @@ export class ScreenshotsComponentParent extends JSWindowActorParent {
|
|||||||
let region, title;
|
let region, title;
|
||||||
switch (message.name) {
|
switch (message.name) {
|
||||||
case "Screenshots:CancelScreenshot":
|
case "Screenshots:CancelScreenshot":
|
||||||
await ScreenshotsUtils.closePanel(browser);
|
|
||||||
let { reason } = message.data;
|
let { reason } = message.data;
|
||||||
ScreenshotsUtils.recordTelemetryEvent("canceled", reason, {});
|
ScreenshotsUtils.cancel(browser, reason);
|
||||||
break;
|
break;
|
||||||
case "Screenshots:CopyScreenshot":
|
case "Screenshots:CopyScreenshot":
|
||||||
await ScreenshotsUtils.closePanel(browser);
|
ScreenshotsUtils.closePanel(browser);
|
||||||
({ region } = message.data);
|
({ region } = message.data);
|
||||||
ScreenshotsUtils.copyScreenshotFromRegion(region, browser);
|
await ScreenshotsUtils.copyScreenshotFromRegion(region, browser);
|
||||||
|
ScreenshotsUtils.exit(browser);
|
||||||
break;
|
break;
|
||||||
case "Screenshots:DownloadScreenshot":
|
case "Screenshots:DownloadScreenshot":
|
||||||
await ScreenshotsUtils.closePanel(browser);
|
ScreenshotsUtils.closePanel(browser);
|
||||||
({ title, region } = message.data);
|
({ title, region } = message.data);
|
||||||
ScreenshotsUtils.downloadScreenshotFromRegion(title, region, browser);
|
await ScreenshotsUtils.downloadScreenshotFromRegion(
|
||||||
|
title,
|
||||||
|
region,
|
||||||
|
browser
|
||||||
|
);
|
||||||
|
ScreenshotsUtils.exit(browser);
|
||||||
|
break;
|
||||||
|
case "Screenshots:OverlaySelection":
|
||||||
|
ScreenshotsUtils.setPerBrowserState(browser, {
|
||||||
|
hasOverlaySelection: message.data.hasSelection,
|
||||||
|
});
|
||||||
break;
|
break;
|
||||||
case "Screenshots:ShowPanel":
|
case "Screenshots:ShowPanel":
|
||||||
ScreenshotsUtils.openPanel(browser);
|
ScreenshotsUtils.openPanel(browser);
|
||||||
@ -63,14 +73,42 @@ export class ScreenshotsComponentParent extends JSWindowActorParent {
|
|||||||
// When restoring a crashed tab the browser is null
|
// When restoring a crashed tab the browser is null
|
||||||
let browser = this.browsingContext.topFrameElement;
|
let browser = this.browsingContext.topFrameElement;
|
||||||
if (browser) {
|
if (browser) {
|
||||||
ScreenshotsUtils.closePanel(browser);
|
ScreenshotsUtils.exit(browser);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const UIPhases = {
|
||||||
|
CLOSED: 0, // nothing showing
|
||||||
|
INITIAL: 1, // panel and overlay showing
|
||||||
|
OVERLAYSELECTION: 2, // something selected in the overlay
|
||||||
|
PREVIEW: 3, // preview dialog showing
|
||||||
|
};
|
||||||
|
|
||||||
export var ScreenshotsUtils = {
|
export var ScreenshotsUtils = {
|
||||||
|
browserToScreenshotsState: new WeakMap(),
|
||||||
initialized: false,
|
initialized: false,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Figures out which of various states the screenshots UI is in, for the given browser.
|
||||||
|
* @param browser The selected browser
|
||||||
|
* @returns One of the `UIPhases` constants
|
||||||
|
*/
|
||||||
|
getUIPhase(browser) {
|
||||||
|
let perBrowserState = this.browserToScreenshotsState.get(browser);
|
||||||
|
if (perBrowserState?.previewDialog) {
|
||||||
|
return UIPhases.PREVIEW;
|
||||||
|
}
|
||||||
|
const buttonsPanel = this.panelForBrowser(browser);
|
||||||
|
if (buttonsPanel && buttonsPanel.state !== "closed") {
|
||||||
|
return UIPhases.INITIAL;
|
||||||
|
}
|
||||||
|
if (perBrowserState?.hasOverlaySelection) {
|
||||||
|
return UIPhases.OVERLAYSELECTION;
|
||||||
|
}
|
||||||
|
return UIPhases.CLOSED;
|
||||||
|
},
|
||||||
|
|
||||||
initialize() {
|
initialize() {
|
||||||
if (!this.initialized) {
|
if (!this.initialized) {
|
||||||
if (
|
if (
|
||||||
@ -100,10 +138,10 @@ export var ScreenshotsUtils = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
handleEvent(event) {
|
handleEvent(event) {
|
||||||
// We need to add back Escape to hide behavior as we have set noautohide="true"
|
// Escape should cancel and exit
|
||||||
if (event.type === "keydown" && event.key === "Escape") {
|
if (event.type === "keydown" && event.key === "Escape") {
|
||||||
this.closePanel(event.view.gBrowser.selectedBrowser, true);
|
let browser = event.view.gBrowser.selectedBrowser;
|
||||||
this.recordTelemetryEvent("canceled", "escape", {});
|
this.cancel(browser, "escape");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -112,34 +150,27 @@ export var ScreenshotsUtils = {
|
|||||||
let browser = gBrowser.selectedBrowser;
|
let browser = gBrowser.selectedBrowser;
|
||||||
|
|
||||||
switch (topic) {
|
switch (topic) {
|
||||||
case "menuitem-screenshot":
|
case "menuitem-screenshot": {
|
||||||
let success = this.closeDialogBox(browser);
|
const uiPhase = this.getUIPhase(browser);
|
||||||
if (!success || data === "retry") {
|
if (uiPhase !== UIPhases.CLOSED) {
|
||||||
// only toggle the buttons if no dialog box is found because
|
// toggle from already-open to closed
|
||||||
// if dialog box is found then the buttons are hidden and we return early
|
this.cancel(browser, data);
|
||||||
// else no dialog box is found and we need to toggle the buttons
|
return;
|
||||||
// or if retry because the dialog box was closed and we need to show the panel
|
|
||||||
this.togglePanelAndOverlay(browser, data);
|
|
||||||
}
|
}
|
||||||
|
this.start(browser, data);
|
||||||
break;
|
break;
|
||||||
case "screenshots-take-screenshot":
|
}
|
||||||
// need to close the preview because screenshot was taken
|
case "screenshots-take-screenshot": {
|
||||||
this.closePanel(browser, true);
|
this.closePanel(browser);
|
||||||
|
this.closeOverlay(browser);
|
||||||
|
|
||||||
// init UI as a tab dialog box
|
// init UI as a tab dialog box
|
||||||
let dialogBox = gBrowser.getTabDialogBox(browser);
|
this.openPreviewDialog(browser).then(dialog => {
|
||||||
|
this.doScreenshot(browser, dialog, data);
|
||||||
let { dialog } = dialogBox.open(
|
});
|
||||||
`chrome://browser/content/screenshots/screenshots.html?browsingContextId=${browser.browsingContext.id}`,
|
break;
|
||||||
{
|
}
|
||||||
features: "resizable=no",
|
|
||||||
sizeTo: "available",
|
|
||||||
allowDuplicateDialogs: false,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
this.doScreenshot(browser, dialog, data);
|
|
||||||
}
|
}
|
||||||
return null;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -172,20 +203,132 @@ export var ScreenshotsUtils = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the buttons panel. If the panel doesn't exist, create the panel.
|
* Show the Screenshots UI and start the capture flow
|
||||||
|
* @param browser The current browser.
|
||||||
|
* @param reason [string] Optional reason string passed along when recording telemetry events
|
||||||
|
*/
|
||||||
|
start(browser, reason = "") {
|
||||||
|
const uiPhase = this.getUIPhase(browser);
|
||||||
|
switch (uiPhase) {
|
||||||
|
case UIPhases.CLOSED:
|
||||||
|
this.showPanelAndOverlay(browser, reason);
|
||||||
|
break;
|
||||||
|
case UIPhases.INITIAL:
|
||||||
|
// nothing to do, panel & overlay are already open
|
||||||
|
break;
|
||||||
|
case UIPhases.PREVIEW: {
|
||||||
|
this.closeDialogBox(browser);
|
||||||
|
this.showPanelAndOverlay(browser, reason);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exit the Screenshots UI for the given browser
|
||||||
|
* Closes any of open UI elements (preview dialog, panel, overlay) and cleans up internal state.
|
||||||
|
* @param browser The current browser.
|
||||||
|
*/
|
||||||
|
exit(browser) {
|
||||||
|
this.closeDialogBox(browser);
|
||||||
|
this.closePanel(browser);
|
||||||
|
this.closeOverlay(browser);
|
||||||
|
this.browserToScreenshotsState.delete(browser);
|
||||||
|
if (Cu.isInAutomation) {
|
||||||
|
Services.obs.notifyObservers(null, "screenshots-exit");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cancel/abort the screenshots operation for the given browser
|
||||||
|
* @param browser The current browser.
|
||||||
|
*/
|
||||||
|
cancel(browser, reason) {
|
||||||
|
this.recordTelemetryEvent("canceled", reason, {});
|
||||||
|
this.exit(browser);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update internal UI state associated with the given browser
|
||||||
|
* @param browser The current browser.
|
||||||
|
* @param nameValues {object} An object with one or more named property values
|
||||||
|
*/
|
||||||
|
setPerBrowserState(browser, nameValues = {}) {
|
||||||
|
if (!this.browserToScreenshotsState.has(browser)) {
|
||||||
|
// we should really have this state already, created when the preview dialog was opened
|
||||||
|
this.browserToScreenshotsState.set(browser, {});
|
||||||
|
}
|
||||||
|
let perBrowserState = this.browserToScreenshotsState.get(browser);
|
||||||
|
Object.assign(perBrowserState, nameValues);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a flag so we don't try to exit when preview dialog next closes.
|
||||||
|
* @param browser The current browser.
|
||||||
|
* @param reason [string] Optional reason string passed along when recording telemetry events
|
||||||
|
*/
|
||||||
|
scheduleRetry(browser, reason) {
|
||||||
|
let perBrowserState = this.browserToScreenshotsState.get(browser);
|
||||||
|
if (!perBrowserState?.closedPromise) {
|
||||||
|
console.warn(
|
||||||
|
"Expected perBrowserState with a closedPromise for the preview dialog"
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.setPerBrowserState(browser, { exitOnPreviewClose: false });
|
||||||
|
perBrowserState?.closedPromise.then(() => {
|
||||||
|
this.start(browser, reason);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open the tab dialog for preview
|
||||||
|
* @param browser The current browser
|
||||||
|
*/
|
||||||
|
async openPreviewDialog(browser) {
|
||||||
|
let dialogBox = browser.ownerGlobal.gBrowser.getTabDialogBox(browser);
|
||||||
|
let { dialog, closedPromise } = await dialogBox.open(
|
||||||
|
`chrome://browser/content/screenshots/screenshots.html?browsingContextId=${browser.browsingContext.id}`,
|
||||||
|
{
|
||||||
|
features: "resizable=no",
|
||||||
|
sizeTo: "available",
|
||||||
|
allowDuplicateDialogs: false,
|
||||||
|
},
|
||||||
|
browser
|
||||||
|
);
|
||||||
|
this.setPerBrowserState(browser, {
|
||||||
|
previewDialog: dialog,
|
||||||
|
exitOnPreviewClose: true,
|
||||||
|
closedPromise: closedPromise.finally(() => {
|
||||||
|
this.onDialogClose(browser);
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
return dialog;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the buttons panel for the given browser
|
||||||
* @param browser The current browser
|
* @param browser The current browser
|
||||||
* @returns The buttons panel
|
* @returns The buttons panel
|
||||||
*/
|
*/
|
||||||
panelForBrowser(browser) {
|
panelForBrowser(browser) {
|
||||||
let doc = browser.ownerDocument;
|
return browser.ownerDocument.getElementById("screenshotsPagePanel");
|
||||||
let buttonsPanel = doc.getElementById("screenshotsPagePanel");
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create the buttons container from its template, for this browser
|
||||||
|
* @param browser The current browser
|
||||||
|
* @returns The buttons panel
|
||||||
|
*/
|
||||||
|
createPanelForBrowser(browser) {
|
||||||
|
let buttonsPanel = this.panelForBrowser(browser);
|
||||||
if (!buttonsPanel) {
|
if (!buttonsPanel) {
|
||||||
|
let doc = browser.ownerDocument;
|
||||||
let template = doc.getElementById("screenshotsPagePanelTemplate");
|
let template = doc.getElementById("screenshotsPagePanelTemplate");
|
||||||
let clone = template.content.cloneNode(true);
|
let clone = template.content.cloneNode(true);
|
||||||
template.replaceWith(clone);
|
template.replaceWith(clone);
|
||||||
buttonsPanel = this.panelForBrowser(browser);
|
|
||||||
}
|
}
|
||||||
return buttonsPanel;
|
return this.panelForBrowser(browser);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -213,23 +356,18 @@ export var ScreenshotsUtils = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Close the panel and call child actor to close the overlay
|
* Close the panel
|
||||||
* @param browser The current browser
|
* @param browser The current browser
|
||||||
* @param {bool} closeOverlay Whether or not to
|
|
||||||
* send a message to the child to close the overly.
|
|
||||||
* Defaults to false. Will be false when called from didDestroy.
|
|
||||||
*/
|
*/
|
||||||
async closePanel(browser, closeOverlay = false) {
|
closePanel(browser) {
|
||||||
let buttonsPanel = this.panelForBrowser(browser);
|
let buttonsPanel = this.panelForBrowser(browser);
|
||||||
if (buttonsPanel && buttonsPanel.state !== "closed") {
|
if (!buttonsPanel) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (buttonsPanel.state !== "closed") {
|
||||||
buttonsPanel.hidePopup();
|
buttonsPanel.hidePopup();
|
||||||
}
|
}
|
||||||
buttonsPanel.ownerDocument.removeEventListener("keydown", this);
|
buttonsPanel.ownerDocument.removeEventListener("keydown", this);
|
||||||
|
|
||||||
if (closeOverlay) {
|
|
||||||
let actor = this.getActor(browser);
|
|
||||||
await actor.sendQuery("Screenshots:HideOverlay");
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -238,21 +376,28 @@ export var ScreenshotsUtils = {
|
|||||||
* Otherwise create or display the buttons.
|
* Otherwise create or display the buttons.
|
||||||
* @param browser The current browser.
|
* @param browser The current browser.
|
||||||
*/
|
*/
|
||||||
async togglePanelAndOverlay(browser, data) {
|
async showPanelAndOverlay(browser, data) {
|
||||||
let buttonsPanel = this.panelForBrowser(browser);
|
|
||||||
let isOverlayShowing = await this.getActor(browser).sendQuery(
|
|
||||||
"Screenshots:isOverlayShowing"
|
|
||||||
);
|
|
||||||
|
|
||||||
data = data === "retry" ? "preview_retry" : data;
|
|
||||||
if (buttonsPanel && (isOverlayShowing || buttonsPanel.state !== "closed")) {
|
|
||||||
this.recordTelemetryEvent("canceled", data, {});
|
|
||||||
return this.closePanel(browser, true);
|
|
||||||
}
|
|
||||||
let actor = this.getActor(browser);
|
let actor = this.getActor(browser);
|
||||||
actor.sendAsyncMessage("Screenshots:ShowOverlay");
|
actor.sendAsyncMessage("Screenshots:ShowOverlay");
|
||||||
|
this.createPanelForBrowser(browser);
|
||||||
this.recordTelemetryEvent("started", data, {});
|
this.recordTelemetryEvent("started", data, {});
|
||||||
return this.openPanel(browser);
|
await this.openPanel(browser);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close the overlay UI, and clear out internal state if there was an overlay selection
|
||||||
|
* The overlay lives in the child document; so although closing is actually async, we assume success.
|
||||||
|
* @param browser The current browser.
|
||||||
|
*/
|
||||||
|
closeOverlay(browser) {
|
||||||
|
let actor = this.getActor(browser);
|
||||||
|
actor?.sendAsyncMessage("Screenshots:HideOverlay");
|
||||||
|
|
||||||
|
if (this.browserToScreenshotsState.has(browser)) {
|
||||||
|
this.setPerBrowserState(browser, {
|
||||||
|
hasOverlaySelection: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -288,14 +433,30 @@ export var ScreenshotsUtils = {
|
|||||||
* @param browser The selected browser
|
* @param browser The selected browser
|
||||||
*/
|
*/
|
||||||
closeDialogBox(browser) {
|
closeDialogBox(browser) {
|
||||||
let dialog = this.getDialog(browser);
|
let perBrowserState = this.browserToScreenshotsState.get(browser);
|
||||||
if (dialog) {
|
if (perBrowserState?.previewDialog) {
|
||||||
dialog.close();
|
perBrowserState.previewDialog.close();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback fired when the preview dialog window closes
|
||||||
|
* Will exit the screenshots UI if the `exitOnPreviewClose` flag is set for this browser
|
||||||
|
* @param browser The associated browser
|
||||||
|
*/
|
||||||
|
onDialogClose(browser) {
|
||||||
|
let perBrowserState = this.browserToScreenshotsState.get(browser);
|
||||||
|
if (!perBrowserState) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
delete perBrowserState.previewDialog;
|
||||||
|
if (perBrowserState?.exitOnPreviewClose) {
|
||||||
|
this.exit(browser);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the screenshots button if it is visible, otherwise it will get the
|
* Gets the screenshots button if it is visible, otherwise it will get the
|
||||||
* element that the screenshots button is nested under. If the screenshots
|
* element that the screenshots button is nested under. If the screenshots
|
||||||
@ -490,11 +651,9 @@ export var ScreenshotsUtils = {
|
|||||||
*/
|
*/
|
||||||
async copyScreenshotFromRegion(region, browser) {
|
async copyScreenshotFromRegion(region, browser) {
|
||||||
let { canvas, snapshot } = await this.createCanvas(region, browser);
|
let { canvas, snapshot } = await this.createCanvas(region, browser);
|
||||||
|
|
||||||
let url = canvas.toDataURL();
|
let url = canvas.toDataURL();
|
||||||
|
|
||||||
this.copyScreenshot(url, browser);
|
this.copyScreenshot(url, browser);
|
||||||
|
|
||||||
snapshot.close();
|
snapshot.close();
|
||||||
|
|
||||||
this.recordTelemetryEvent("copy", "overlay_copy", {});
|
this.recordTelemetryEvent("copy", "overlay_copy", {});
|
||||||
@ -548,11 +707,9 @@ export var ScreenshotsUtils = {
|
|||||||
*/
|
*/
|
||||||
async downloadScreenshotFromRegion(title, region, browser) {
|
async downloadScreenshotFromRegion(title, region, browser) {
|
||||||
let { canvas, snapshot } = await this.createCanvas(region, browser);
|
let { canvas, snapshot } = await this.createCanvas(region, browser);
|
||||||
|
|
||||||
let dataUrl = canvas.toDataURL();
|
let dataUrl = canvas.toDataURL();
|
||||||
|
|
||||||
await this.downloadScreenshot(title, dataUrl, browser);
|
await this.downloadScreenshot(title, dataUrl, browser);
|
||||||
|
|
||||||
snapshot.close();
|
snapshot.close();
|
||||||
|
|
||||||
this.recordTelemetryEvent("download", "overlay_download", {});
|
this.recordTelemetryEvent("download", "overlay_download", {});
|
||||||
|
@ -14,6 +14,8 @@ ChromeUtils.defineESModuleGetters(this, {
|
|||||||
class ScreenshotsUI extends HTMLElement {
|
class ScreenshotsUI extends HTMLElement {
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
|
// we get passed the <browser> as a param via TabDialogBox.open()
|
||||||
|
this.openerBrowser = window.arguments[0];
|
||||||
}
|
}
|
||||||
async connectedCallback() {
|
async connectedCallback() {
|
||||||
this.initialize();
|
this.initialize();
|
||||||
@ -67,11 +69,8 @@ class ScreenshotsUI extends HTMLElement {
|
|||||||
event.type == "click" &&
|
event.type == "click" &&
|
||||||
event.currentTarget == this._retryButton
|
event.currentTarget == this._retryButton
|
||||||
) {
|
) {
|
||||||
Services.obs.notifyObservers(
|
ScreenshotsUtils.scheduleRetry(this.openerBrowser, "preview_retry");
|
||||||
window.parent.ownerGlobal,
|
this.close();
|
||||||
"menuitem-screenshot",
|
|
||||||
"retry"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -79,23 +78,16 @@ class ScreenshotsUI extends HTMLElement {
|
|||||||
await ScreenshotsUtils.downloadScreenshot(
|
await ScreenshotsUtils.downloadScreenshot(
|
||||||
null,
|
null,
|
||||||
dataUrl,
|
dataUrl,
|
||||||
window.parent.ownerGlobal.gBrowser.selectedBrowser
|
this.openerBrowser
|
||||||
);
|
);
|
||||||
|
|
||||||
this.close();
|
|
||||||
|
|
||||||
ScreenshotsUtils.recordTelemetryEvent("download", "preview_download", {});
|
ScreenshotsUtils.recordTelemetryEvent("download", "preview_download", {});
|
||||||
|
this.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
saveToClipboard(dataUrl) {
|
saveToClipboard(dataUrl) {
|
||||||
ScreenshotsUtils.copyScreenshot(
|
ScreenshotsUtils.copyScreenshot(dataUrl, this.openerBrowser);
|
||||||
dataUrl,
|
|
||||||
window.parent.ownerGlobal.gBrowser.selectedBrowser
|
|
||||||
);
|
|
||||||
|
|
||||||
this.close();
|
|
||||||
|
|
||||||
ScreenshotsUtils.recordTelemetryEvent("copy", "preview_copy", {});
|
ScreenshotsUtils.recordTelemetryEvent("copy", "preview_copy", {});
|
||||||
|
this.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
customElements.define("screenshots-ui", ScreenshotsUI);
|
customElements.define("screenshots-ui", ScreenshotsUI);
|
||||||
|
@ -59,18 +59,23 @@ add_task(async function test_started_and_canceled_events() {
|
|||||||
async browser => {
|
async browser => {
|
||||||
await clearAllTelemetryEvents();
|
await clearAllTelemetryEvents();
|
||||||
let helper = new ScreenshotsHelper(browser);
|
let helper = new ScreenshotsHelper(browser);
|
||||||
|
let screenshotExit;
|
||||||
|
|
||||||
helper.triggerUIFromToolbar();
|
helper.triggerUIFromToolbar();
|
||||||
await helper.waitForOverlay();
|
await helper.waitForOverlay();
|
||||||
|
|
||||||
|
screenshotExit = TestUtils.topicObserved("screenshots-exit");
|
||||||
helper.triggerUIFromToolbar();
|
helper.triggerUIFromToolbar();
|
||||||
await helper.waitForOverlayClosed();
|
await helper.waitForOverlayClosed();
|
||||||
|
await screenshotExit;
|
||||||
|
|
||||||
EventUtils.synthesizeKey("s", { shiftKey: true, accelKey: true });
|
EventUtils.synthesizeKey("s", { shiftKey: true, accelKey: true });
|
||||||
await helper.waitForOverlay();
|
await helper.waitForOverlay();
|
||||||
|
|
||||||
|
screenshotExit = TestUtils.topicObserved("screenshots-exit");
|
||||||
EventUtils.synthesizeKey("s", { shiftKey: true, accelKey: true });
|
EventUtils.synthesizeKey("s", { shiftKey: true, accelKey: true });
|
||||||
await helper.waitForOverlayClosed();
|
await helper.waitForOverlayClosed();
|
||||||
|
await screenshotExit;
|
||||||
|
|
||||||
let contextMenu = document.getElementById("contentAreaContextMenu");
|
let contextMenu = document.getElementById("contentAreaContextMenu");
|
||||||
let popupShownPromise = BrowserTestUtils.waitForEvent(
|
let popupShownPromise = BrowserTestUtils.waitForEvent(
|
||||||
@ -108,10 +113,12 @@ add_task(async function test_started_and_canceled_events() {
|
|||||||
);
|
);
|
||||||
await popupShownPromise;
|
await popupShownPromise;
|
||||||
|
|
||||||
|
screenshotExit = TestUtils.topicObserved("screenshots-exit");
|
||||||
contextMenu.activateItem(
|
contextMenu.activateItem(
|
||||||
contextMenu.querySelector("#context-take-screenshot")
|
contextMenu.querySelector("#context-take-screenshot")
|
||||||
);
|
);
|
||||||
await helper.waitForOverlayClosed();
|
await helper.waitForOverlayClosed();
|
||||||
|
await screenshotExit;
|
||||||
|
|
||||||
await UrlbarTestUtils.promiseAutocompleteResultPopup({
|
await UrlbarTestUtils.promiseAutocompleteResultPopup({
|
||||||
window,
|
window,
|
||||||
@ -137,9 +144,11 @@ add_task(async function test_started_and_canceled_events() {
|
|||||||
Assert.equal(result.providerName, "quickactions");
|
Assert.equal(result.providerName, "quickactions");
|
||||||
|
|
||||||
info("Trigger the screenshot mode");
|
info("Trigger the screenshot mode");
|
||||||
|
screenshotExit = TestUtils.topicObserved("screenshots-exit");
|
||||||
EventUtils.synthesizeKey("KEY_ArrowDown", {}, window);
|
EventUtils.synthesizeKey("KEY_ArrowDown", {}, window);
|
||||||
EventUtils.synthesizeKey("KEY_Enter", {}, window);
|
EventUtils.synthesizeKey("KEY_Enter", {}, window);
|
||||||
await helper.waitForOverlayClosed();
|
await helper.waitForOverlayClosed();
|
||||||
|
await screenshotExit;
|
||||||
|
|
||||||
await assertScreenshotsEvents(STARTED_AND_CANCELED_EVENTS);
|
await assertScreenshotsEvents(STARTED_AND_CANCELED_EVENTS);
|
||||||
}
|
}
|
||||||
@ -213,17 +222,22 @@ add_task(async function test_canceled() {
|
|||||||
let dialog = helper.getDialog();
|
let dialog = helper.getDialog();
|
||||||
let cancelButton = dialog._frame.contentDocument.getElementById("cancel");
|
let cancelButton = dialog._frame.contentDocument.getElementById("cancel");
|
||||||
ok(cancelButton, "Got the cancel button");
|
ok(cancelButton, "Got the cancel button");
|
||||||
|
|
||||||
|
let screenshotExit = TestUtils.topicObserved("screenshots-exit");
|
||||||
cancelButton.click();
|
cancelButton.click();
|
||||||
|
|
||||||
await helper.waitForOverlayClosed();
|
await helper.waitForOverlayClosed();
|
||||||
|
await screenshotExit;
|
||||||
|
|
||||||
helper.triggerUIFromToolbar();
|
helper.triggerUIFromToolbar();
|
||||||
await helper.waitForOverlay();
|
await helper.waitForOverlay();
|
||||||
|
|
||||||
await helper.dragOverlay(50, 50, 300, 300);
|
await helper.dragOverlay(50, 50, 300, 300);
|
||||||
|
screenshotExit = TestUtils.topicObserved("screenshots-exit");
|
||||||
helper.clickCancelButton();
|
helper.clickCancelButton();
|
||||||
|
|
||||||
await helper.waitForOverlayClosed();
|
await helper.waitForOverlayClosed();
|
||||||
|
await screenshotExit;
|
||||||
|
|
||||||
await assertScreenshotsEvents(CANCEL_EVENTS);
|
await assertScreenshotsEvents(CANCEL_EVENTS);
|
||||||
}
|
}
|
||||||
@ -241,8 +255,10 @@ add_task(async function test_copy() {
|
|||||||
let helper = new ScreenshotsHelper(browser);
|
let helper = new ScreenshotsHelper(browser);
|
||||||
|
|
||||||
helper.triggerUIFromToolbar();
|
helper.triggerUIFromToolbar();
|
||||||
|
info("waiting for overlay");
|
||||||
await helper.waitForOverlay();
|
await helper.waitForOverlay();
|
||||||
|
|
||||||
|
info("waiting for panel");
|
||||||
let panel = await helper.waitForPanel();
|
let panel = await helper.waitForPanel();
|
||||||
|
|
||||||
let screenshotReady = TestUtils.topicObserved(
|
let screenshotReady = TestUtils.topicObserved(
|
||||||
@ -254,30 +270,41 @@ add_task(async function test_copy() {
|
|||||||
.querySelector("screenshots-buttons")
|
.querySelector("screenshots-buttons")
|
||||||
.shadowRoot.querySelector(".visible-page");
|
.shadowRoot.querySelector(".visible-page");
|
||||||
visiblePageButton.click();
|
visiblePageButton.click();
|
||||||
|
info("clicked visible page, waiting for screenshots-preview-ready");
|
||||||
await screenshotReady;
|
await screenshotReady;
|
||||||
|
|
||||||
let dialog = helper.getDialog();
|
let dialog = helper.getDialog();
|
||||||
let copyButton = dialog._frame.contentDocument.getElementById("copy");
|
let copyButton = dialog._frame.contentDocument.getElementById("copy");
|
||||||
|
|
||||||
|
let screenshotExit = TestUtils.topicObserved("screenshots-exit");
|
||||||
let clipboardChanged = helper.waitForRawClipboardChange();
|
let clipboardChanged = helper.waitForRawClipboardChange();
|
||||||
|
|
||||||
// click copy button on dialog box
|
// click copy button on dialog box
|
||||||
|
info("clicking the copy button");
|
||||||
copyButton.click();
|
copyButton.click();
|
||||||
|
|
||||||
info("Waiting for clipboard change");
|
info("Waiting for clipboard change");
|
||||||
await clipboardChanged;
|
await clipboardChanged;
|
||||||
|
info("waiting for screenshot exit");
|
||||||
|
await screenshotExit;
|
||||||
|
|
||||||
helper.triggerUIFromToolbar();
|
helper.triggerUIFromToolbar();
|
||||||
|
info("waiting for overlay again");
|
||||||
await helper.waitForOverlay();
|
await helper.waitForOverlay();
|
||||||
|
|
||||||
await helper.dragOverlay(50, 50, 300, 300);
|
await helper.dragOverlay(50, 50, 300, 300);
|
||||||
|
|
||||||
clipboardChanged = helper.waitForRawClipboardChange();
|
clipboardChanged = helper.waitForRawClipboardChange();
|
||||||
|
|
||||||
|
screenshotExit = TestUtils.topicObserved("screenshots-exit");
|
||||||
helper.clickCopyButton();
|
helper.clickCopyButton();
|
||||||
|
|
||||||
info("Waiting for clipboard change");
|
info("Waiting for clipboard change");
|
||||||
await clipboardChanged;
|
await clipboardChanged;
|
||||||
|
info("Waiting for exit again");
|
||||||
|
await screenshotExit;
|
||||||
|
|
||||||
|
info("Waiting for assertScreenshotsEvents");
|
||||||
await assertScreenshotsEvents(COPY_EVENTS);
|
await assertScreenshotsEvents(COPY_EVENTS);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@ -306,4 +333,4 @@ add_task(async function test_content_events() {
|
|||||||
await assertScreenshotsEvents(CONTENT_EVENTS, "content");
|
await assertScreenshotsEvents(CONTENT_EVENTS, "content");
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
});
|
}).skip();
|
||||||
|
@ -120,6 +120,7 @@ add_task(async function test_download_without_filepicker() {
|
|||||||
dialog._frame.contentDocument.getElementById("download");
|
dialog._frame.contentDocument.getElementById("download");
|
||||||
ok(downloadButton, "Got the download button");
|
ok(downloadButton, "Got the download button");
|
||||||
|
|
||||||
|
let screenshotExit = TestUtils.topicObserved("screenshots-exit");
|
||||||
// click download button on dialog box
|
// click download button on dialog box
|
||||||
downloadButton.click();
|
downloadButton.click();
|
||||||
|
|
||||||
@ -129,7 +130,7 @@ add_task(async function test_download_without_filepicker() {
|
|||||||
ok(download.succeeded, "Download should succeed");
|
ok(download.succeeded, "Download should succeed");
|
||||||
|
|
||||||
await publicDownloads.removeFinished();
|
await publicDownloads.removeFinished();
|
||||||
|
await screenshotExit;
|
||||||
await assertScreenshotsEvents(SCREENSHOTS_EVENTS);
|
await assertScreenshotsEvents(SCREENSHOTS_EVENTS);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@ -168,7 +169,7 @@ add_task(async function test_download_with_filepicker() {
|
|||||||
await helper.dragOverlay(10, 10, 500, 500);
|
await helper.dragOverlay(10, 10, 500, 500);
|
||||||
|
|
||||||
let filePicker = waitForFilePicker();
|
let filePicker = waitForFilePicker();
|
||||||
|
let screenshotExit = TestUtils.topicObserved("screenshots-exit");
|
||||||
helper.clickDownloadButton();
|
helper.clickDownloadButton();
|
||||||
|
|
||||||
await filePicker;
|
await filePicker;
|
||||||
@ -178,8 +179,8 @@ add_task(async function test_download_with_filepicker() {
|
|||||||
let download = await downloadFinishedPromise;
|
let download = await downloadFinishedPromise;
|
||||||
|
|
||||||
ok(download.succeeded, "Download should succeed");
|
ok(download.succeeded, "Download should succeed");
|
||||||
|
|
||||||
await publicDownloads.removeFinished();
|
await publicDownloads.removeFinished();
|
||||||
|
await screenshotExit;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user