screenshots-preview.mjs (7579B)
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/. */ 4 5 import { html } from "chrome://global/content/vendor/lit.all.mjs"; 6 import { MozLitElement } from "chrome://global/content/lit-utils.mjs"; 7 // eslint-disable-next-line import/no-unassigned-import 8 import "chrome://global/content/elements/moz-button.mjs"; 9 10 const lazy = {}; 11 12 ChromeUtils.defineLazyGetter(lazy, "screenshotsLocalization", () => { 13 return new Localization(["browser/screenshots.ftl"], true); 14 }); 15 16 ChromeUtils.defineESModuleGetters(lazy, { 17 AppConstants: "resource://gre/modules/AppConstants.sys.mjs", 18 ScreenshotsUtils: "resource:///modules/ScreenshotsUtils.sys.mjs", 19 ShortcutUtils: "resource://gre/modules/ShortcutUtils.sys.mjs", 20 }); 21 22 class ScreenshotsPreview extends MozLitElement { 23 static queries = { 24 retryButtonEl: "#retry", 25 cancelButtonEl: "#cancel", 26 copyButtonEl: "#copy", 27 downloadButtonEl: "#download", 28 previewImg: "#preview-image", 29 buttons: { all: "moz-button" }, 30 }; 31 32 constructor() { 33 super(); 34 // we get passed the <browser> as a param via TabDialogBox.open() 35 this.openerBrowser = window.arguments[0]; 36 37 let [downloadKey, copyKey] = 38 lazy.screenshotsLocalization.formatMessagesSync([ 39 { id: "screenshots-component-download-key" }, 40 { id: "screenshots-component-copy-key" }, 41 ]); 42 43 this.downloadKey = downloadKey.value; 44 this.copyKey = copyKey.value; 45 } 46 47 connectedCallback() { 48 super.connectedCallback(); 49 50 window.addEventListener("keydown", this, true); 51 52 this.updateL10nAttributes(); 53 } 54 55 async updateL10nAttributes() { 56 let accelString = lazy.ShortcutUtils.getModifierString("accel"); 57 let copyShorcut = accelString + this.copyKey; 58 let downloadShortcut = accelString + this.downloadKey; 59 60 await this.updateComplete; 61 62 document.l10n.setAttributes( 63 this.copyButtonEl, 64 "screenshots-component-copy-button-2", 65 { shortcut: copyShorcut } 66 ); 67 68 document.l10n.setAttributes( 69 this.downloadButtonEl, 70 "screenshots-component-download-button-2", 71 { shortcut: downloadShortcut } 72 ); 73 } 74 75 close() { 76 window.removeEventListener("keydown", this, true); 77 window.close(); 78 } 79 80 handleEvent(event) { 81 switch (event.type) { 82 case "click": 83 this.handleClick(event); 84 break; 85 case "keydown": 86 this.handleKeydown(event); 87 break; 88 } 89 } 90 91 handleClick(event) { 92 switch (event.target.id) { 93 case "retry": 94 lazy.ScreenshotsUtils.scheduleRetry(this.openerBrowser, "PreviewRetry"); 95 this.close(); 96 break; 97 case "cancel": 98 this.close(); 99 lazy.ScreenshotsUtils.recordTelemetryEvent("canceledPreviewCancel"); 100 break; 101 case "copy": 102 this.saveToClipboard(); 103 break; 104 case "download": 105 this.saveToFile(); 106 break; 107 } 108 } 109 110 handleKeydown(event) { 111 switch (event.key) { 112 case this.copyKey.toLowerCase(): 113 if (this.getAccelKey(event)) { 114 event.preventDefault(); 115 event.stopPropagation(); 116 this.saveToClipboard(); 117 } 118 break; 119 case this.downloadKey.toLowerCase(): 120 if (this.getAccelKey(event)) { 121 event.preventDefault(); 122 event.stopPropagation(); 123 this.saveToFile(); 124 } 125 break; 126 } 127 } 128 129 /** 130 * If the image is complete and the height is greater than 0, we can resolve. 131 * Otherwise wait for a load event on the image and resolve then. 132 * 133 * @returns {Promise<string>} Resolves that resolves to the preview image src 134 * once the image is loaded. 135 */ 136 async imageLoadedPromise() { 137 await this.updateComplete; 138 if (this.previewImg.complete && this.previewImg.height > 0) { 139 return Promise.resolve(this.previewImg.src); 140 } 141 142 return new Promise(resolve => { 143 function onImageLoaded(event) { 144 resolve(event.target.src); 145 } 146 this.previewImg.addEventListener("load", onImageLoaded, { once: true }); 147 }); 148 } 149 150 getAccelKey(event) { 151 if (lazy.AppConstants.platform === "macosx") { 152 return event.metaKey; 153 } 154 return event.ctrlKey; 155 } 156 157 /** 158 * Enable all the buttons. This will only happen when the download button is 159 * clicked and the file picker is closed without saving the image. 160 */ 161 enableButtons() { 162 this.buttons.forEach(button => (button.disabled = false)); 163 } 164 165 /** 166 * Disable all the buttons so they can't be clicked multiple times before 167 * successfully copying or downloading the image. 168 */ 169 disableButtons() { 170 this.buttons.forEach(button => (button.disabled = true)); 171 } 172 173 async saveToFile() { 174 // Disable buttons so they can't by clicked again while waiting for the 175 // image to load. 176 this.disableButtons(); 177 178 // Wait for the image to be loaded before we save it 179 let imageSrc = await this.imageLoadedPromise(); 180 let downloadSucceeded = await lazy.ScreenshotsUtils.downloadScreenshot( 181 null, 182 imageSrc, 183 this.openerBrowser, 184 "PreviewDownload" 185 ); 186 187 if (downloadSucceeded) { 188 this.close(); 189 } else { 190 this.enableButtons(); 191 } 192 } 193 194 async saveToClipboard() { 195 // Disable buttons so they can't by clicked again while waiting for the 196 // image to load 197 this.disableButtons(); 198 199 // Wait for the image to be loaded before we copy it 200 let imageSrc = await this.imageLoadedPromise(); 201 await lazy.ScreenshotsUtils.copyScreenshotFromBlobURL( 202 imageSrc, 203 this.openerBrowser, 204 "PreviewCopy" 205 ); 206 this.close(); 207 } 208 209 /** 210 * Set the focus to the most recent saved method. 211 * This will default to the download button. 212 * 213 * @param {string} buttonToFocus 214 */ 215 focusButton(buttonToFocus) { 216 if (buttonToFocus === "copy") { 217 this.copyButtonEl.focus({ focusVisible: true }); 218 } else { 219 this.downloadButtonEl.focus({ focusVisible: true }); 220 } 221 } 222 223 render() { 224 return html` 225 <link 226 rel="stylesheet" 227 href="chrome://browser/content/screenshots/screenshots-preview.css" 228 /> 229 <div class="image-view"> 230 <div class="preview-buttons"> 231 <moz-button 232 id="retry" 233 data-l10n-id="screenshots-component-retry-button" 234 iconSrc="chrome://global/skin/icons/reload.svg" 235 @click=${this.handleClick} 236 ></moz-button> 237 <moz-button 238 id="cancel" 239 data-l10n-id="screenshots-component-cancel-button" 240 iconSrc="chrome://global/skin/icons/close.svg" 241 @click=${this.handleClick} 242 ></moz-button> 243 <moz-button 244 id="copy" 245 data-l10n-id="screenshots-component-copy-button-2" 246 data-l10n-args='{ "shortcut": "" }' 247 iconSrc="chrome://global/skin/icons/edit-copy.svg" 248 @click=${this.handleClick} 249 ></moz-button> 250 <moz-button 251 id="download" 252 type="primary" 253 data-l10n-id="screenshots-component-download-button-2" 254 data-l10n-args='{ "shortcut": "" }' 255 iconSrc="chrome://browser/skin/downloads/downloads.svg" 256 @click=${this.handleClick} 257 ></moz-button> 258 </div> 259 <div id="preview-image-container"> 260 <img id="preview-image" /> 261 </div> 262 </div> 263 `; 264 } 265 } 266 267 customElements.define("screenshots-preview", ScreenshotsPreview);