FilePickerHandler.sys.mjs (3055B)
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 const FILE_PICKER_HANDLER_CID = Services.uuid.generateUUID(); 6 const FILE_PICKER_CONTRACT_ID = "@mozilla.org/filepicker;1"; 7 8 /** 9 * The FilePickerHandler can override the default component factory for the file 10 * picker to prevent showing file pickers if needed. 11 */ 12 class FilePickerHandlerClass { 13 #callers; 14 #originalFilePickerCID; 15 #registrar; 16 #registeredFactory; 17 18 constructor() { 19 this.#registeredFactory = null; 20 21 this.#registrar = Components.manager.QueryInterface( 22 Ci.nsIComponentRegistrar 23 ); 24 this.#originalFilePickerCID = this.#registrar.contractIDToCID( 25 FILE_PICKER_CONTRACT_ID 26 ); 27 28 // Set to keep track of all callers which requested to handle file pickers. 29 this.#callers = new Set(); 30 } 31 32 /** 33 * Stop requesting to dismiss all file pickers on behalf of the provided 34 * caller. 35 * Note that file pickers will only be displayed again once all callers 36 * called allowFilePickers. 37 * 38 * @param {object} caller 39 * A reference to identify the caller which requested to dismiss pickers. 40 */ 41 allowFilePickers(caller) { 42 if (!this.#callers.has(caller)) { 43 return; 44 } 45 46 this.#callers.delete(caller); 47 48 if (this.#callers.size || !this.#registeredFactory) { 49 return; 50 } 51 52 // Unregister our proxy factory. 53 this.#registrar.unregisterFactory( 54 FILE_PICKER_HANDLER_CID, 55 this.#registeredFactory 56 ); 57 this.#registeredFactory = null; 58 59 // Restore the original factory. 60 this.#registrar.registerFactory( 61 this.#originalFilePickerCID, 62 "", 63 FILE_PICKER_CONTRACT_ID, 64 null 65 ); 66 } 67 68 /** 69 * Request to dismiss all file picker dialogs by registering a custom file 70 * picker factory instead of the default one. 71 * 72 * @param {object} caller 73 * A reference to identify the caller which requested to dismiss pickers. 74 */ 75 dismissFilePickers(caller) { 76 this.#callers.add(caller); 77 78 if (this.#registeredFactory) { 79 return; 80 } 81 82 this.#registeredFactory = { 83 createInstance(iid) { 84 const filePickerProxy = { 85 init() {}, 86 open: openCallback => { 87 openCallback.done(Ci.nsIFilePicker.returnCancel); 88 }, 89 displayDirectory: null, 90 file: null, 91 QueryInterface: ChromeUtils.generateQI(["nsIFilePicker"]), 92 }; 93 return filePickerProxy.QueryInterface(iid); 94 }, 95 QueryInterface: ChromeUtils.generateQI(["nsIFactory"]), 96 }; 97 98 this.#registrar.registerFactory( 99 FILE_PICKER_HANDLER_CID, 100 "WebDriver FilePicker handler", 101 FILE_PICKER_CONTRACT_ID, 102 this.#registeredFactory 103 ); 104 } 105 } 106 107 // Expose a singleton shared by all WebDriver sessions. 108 // The FilePickerHandler factory should only be registered once at most. 109 export const FilePickerHandler = new FilePickerHandlerClass();