rents defaultIconURL: { type: String, reflect: true }, defaultLabel: { type: String, reflect: true }, defaultPath: { type: String, reflect: true }, supportBaseLink: { type: String }, embeddedFxBackupOptIn: { type: Boolean, reflect: true, attribute: "embedded-fx-backup-opt-in", }, hideFilePathChooser: { type: Boolean, reflect: true, attribute: "hide-file-path-chooser", }, hideSecondaryButton: { type: Boolean, reflect: true, attribute: "hide-secondary-button", }, backupIsEncrypted: { type: Boolean, reflect: true, attribute: "backup-is-encrypted", }, filePathLabelL10nId: { type: String, reflect: true, attribute: "file-path-label-l10n-id", }, turnOnBackupHeaderL10nId: { type: String, reflect: true, attribute: "turn-on-backup-header-l10n-id", }, createPasswordLabelL10nId: { type: String, reflect: true, attribute: "create-password-label-l10n-id", }, turnOnBackupConfirmBtnL10nId: { type: String, reflect: true, attribute: "turn-on-backup-confirm-btn-l10n-id", }, turnOnBackupCancelBtnL10nId: { type: String, reflect: true, attribute: "turn-on-backup-cancel-btn-l10n-id", }, // internal state _newIconURL: { type: String, state: true }, _newLabel: { type: String, state: true }, _newPath: { type: String, state: true }, _showPasswordOptions: { type: Boolean, reflect: true, state: true }, _passwordsMatch: { type: Boolean, state: true }, _inputPassValue: { type: String, state: true }, // managed by BackupUIChild enableBackupErrorCode: { type: Number }, }; static get queries() { return { cancelButtonEl: "#backup-turn-on-scheduled-cancel-button", confirmButtonEl: "#backup-turn-on-scheduled-confirm-button", filePathButtonEl: "#backup-location-filepicker-button", filePathInputCustomEl: "#backup-location-filepicker-input-custom", filePathInputDefaultEl: "#backup-location-filepicker-input-default", passwordOptionsCheckboxEl: "#sensitive-data-checkbox-input", passwordOptionsExpandedEl: "#passwords", errorEl: "#enable-backup-encryption-error", }; } constructor() { super(); this.backupServiceState = {}; this.defaultIconURL = ""; this.defaultLabel = ""; this.defaultPath = ""; this._newIconURL = ""; this._newLabel = ""; this._newPath = ""; this._showPasswordOptions = false; this._passwordsMatch = false; this.enableBackupErrorCode = 0; this.disableSubmit = false; } connectedCallback() { super.connectedCallback(); this.dispatchEvent( new CustomEvent("BackupUI:InitWidget", { bubbles: true }) ); // listen to events from BackupUIChild this.addEventListener("BackupUI:SelectNewFilepickerPath", this); // listen to events from this.addEventListener("ValidPasswordsDetected", this); this.addEventListener("InvalidPasswordsDetected", this); // listens to keydown events this.addEventListener("keydown", this); } handleEvent(event) { if (event.type == "BackupUI:SelectNewFilepickerPath") { let { path, filename, iconURL } = event.detail; this._newPath = path; this._newLabel = filename; this._newIconURL = iconURL; if (this.embeddedFxBackupOptIn) { // Let's set a persistent path this.dispatchEvent( new CustomEvent("BackupUI:SetEmbeddedComponentPersistentData", { bubbles: true, detail: { path, label: filename, iconURL, }, }) ); } } else if (event.type == "ValidPasswordsDetected") { let { password } = event.detail; this._passwordsMatch = true; this._inputPassValue = password; } else if (event.type == "InvalidPasswordsDetected") { this._passwordsMatch = false; this._inputPassValue = ""; } else if (event.type == "keydown") { if ( event.key === "Enter" && (event.originalTarget.id == "backup-location-filepicker-input-default" || event.originalTarget.id == "backup-location-filepicker-input-custom") ) { event.preventDefault(); } } } async handleChooseLocation() { this.dispatchEvent( new CustomEvent("BackupUI:ShowFilepicker", { bubbles: true, detail: { win: window.browsingContext, }, }) ); } close() { this.dispatchEvent( new CustomEvent("dialogCancel", { bubbles: true, composed: true, }) ); } handleConfirm() { let detail = { parentDirPath: this._newPath || this.defaultPath, }; if (this._showPasswordOptions && this._passwordsMatch) { detail.password = this._inputPassValue; } if (this.embeddedFxBackupOptIn && this.backupIsEncrypted) { if (!detail.password) { // We're in the embedded component and we haven't set a password yet // when one is expected, let's not do a confirm action yet! this.dispatchEvent( new CustomEvent("SpotlightOnboardingAdvanceScreens", { bubbles: true, }) ); return; } // The persistent data will take precedence over the default path detail.parentDirPath = this.backupServiceState?.embeddedComponentPersistentData?.path || detail.parentDirPath; } this.dispatchEvent( new CustomEvent("BackupUI:EnableScheduledBackups", { bubbles: true, detail, }) ); } handleTogglePasswordOptions() { this._showPasswordOptions = this.passwordOptionsCheckboxEl?.checked; this._passwordsMatch = false; } updated(changedProperties) { super.updated?.(changedProperties); if (changedProperties.has("hideFilePathChooser")) { // If hideFilePathChooser is true, show password options this._showPasswordOptions = !!this.hideFilePathChooser; // Uncheck the checkbox if it exists if (this.passwordOptionsCheckboxEl) { this.passwordOptionsCheckboxEl.checked = this._showPasswordOptions; } } } reset() { this._showPasswordOptions = false; this.passwordOptionsCheckboxEl.checked = false; this._passwordsMatch = false; this._inputPassValue = ""; this.enableBackupErrorCode = 0; this.disableSubmit = false; // we don't want to reset the path when embedded in the spotlight if (!this.embeddedFxBackupOptIn) { this._newPath = ""; this._newIconURL = ""; this._newLabel = ""; } if (this.passwordOptionsExpandedEl) { /** @type {import("./password-validation-inputs.mjs").default} */ const passwordElement = this.passwordOptionsExpandedEl; passwordElement.reset(); } if ( this.embeddedFxBackupOptIn && this.backupServiceState?.embeddedComponentPersistentData ) { this.dispatchEvent( new CustomEvent("BackupUI:FlushEmbeddedComponentPersistentData", { bubbles: true, }) ); } } defaultFilePathInputTemplate() { let filename = this.defaultLabel; let iconURL = this.defaultIconURL || this.#placeholderIconURL; const hasFilename = !!filename; const l10nArgs = hasFilename ? JSON.stringify({ recommendedFolder: filename }) : null; return html` `; } /** * Note: We also consider the embeddedComponentPersistentData since we might be in the * Spotlight where we need this persistent data between screens. This state property should * not be set if we are not in the Spotlight. */ customFilePathInputTemplate() { let filename = this._newLabel || this.backupServiceState?.embeddedComponentPersistentData?.label; let iconURL = this._newIconURL || this.backupServiceState?.embeddedComponentPersistentData?.iconURL || this.#placeholderIconURL; return html` `; } errorTemplate() { return html` `; } allOptionsTemplate() { return html`
${!this._newPath && !this.backupServiceState?.embeddedComponentPersistentData?.path ? this.defaultFilePathInputTemplate() : this.customFilePathInputTemplate()}
${this._showPasswordOptions ? this.passwordsTemplate() : null}
`; } passwordsTemplate() { return html` `; } contentTemplate() { const hasEmbeddedPersistentData = this.embeddedFxBackupOptIn && this.backupServiceState?.embeddedComponentPersistentData?.path; // All the situations where we want to disable submit: // - passwords don't match // - there's no destination folder // - other unknown errors if ( (this._showPasswordOptions && !this._passwordsMatch) || (!this._newPath && !this.defaultLabel && !hasEmbeddedPersistentData) || this.enableBackupErrorCode != ERRORS.NONE ) { this.disableSubmit = true; } else { this.disableSubmit = false; } return html`

${this.allOptionsTemplate()} ${this.enableBackupErrorCode ? this.errorTemplate() : null}
`; } render() { return html` ${this.contentTemplate()} `; } } customElements.define("turn-on-scheduled-backups", TurnOnScheduledBackups); PK