| // Copyright 2025 The Chromium Authors | 
 | // Use of this source code is governed by a BSD-style license that can be | 
 | // found in the LICENSE file. | 
 |  | 
 | import '//resources/cr_elements/cr_button/cr_button.js'; | 
 | import '//resources/cr_elements/cr_icon_button/cr_icon_button.js'; | 
 | import '//resources/cr_elements/icons.html.js'; | 
 | import '/strings.m.js'; | 
 |  | 
 | import {CrLitElement} from '//resources/lit/v3_0/lit.rollup.js'; | 
 | import {ColorChangeUpdater} from 'chrome://resources/cr_components/color_change_listener/colors_css_updater.js'; | 
 | import {loadTimeData} from 'chrome://resources/js/load_time_data.js'; | 
 |  | 
 | import {getCss} from './app.css.js'; | 
 | import {getHtml} from './app.html.js'; | 
 | import {BrowserProxyImpl} from './browser_proxy.js'; | 
 | import type {BrowserProxy} from './browser_proxy.js'; | 
 | import {MetricsRecorder} from './metrics_recorder.js'; | 
 |  | 
 | const RELOAD_BUTTON_TOOLTIP_RELOAD_WITH_MENU = | 
 |     'reloadButtonTooltipReloadWithMenu'; | 
 | const RELOAD_BUTTON_TOOLTIP_RELOAD = 'reloadButtonTooltipReload'; | 
 | const RELOAD_BUTTON_TOOLTIP_STOP = 'reloadButtonTooltipStop'; | 
 |  | 
 | const LONG_PRESS_TIMER_THRESHOLD_MS = 500; | 
 |  | 
 | export class ReloadButtonAppElement extends CrLitElement { | 
 |   private browserProxy_: BrowserProxy; | 
 |   private metricsRecorder_: MetricsRecorder; | 
 |  | 
 |   constructor() { | 
 |     super(); | 
 |     this.browserProxy_ = BrowserProxyImpl.getInstance(); | 
 |     this.metricsRecorder_ = new MetricsRecorder(this.browserProxy_); | 
 |     const callbackRouter = this.browserProxy_.callbackRouter; | 
 |     callbackRouter.setReloadButtonState.addListener( | 
 |         (isLoading: boolean, isMenuEnabled: boolean) => { | 
 |           this.metricsRecorder_.onChangeVisibleMode( | 
 |               MetricsRecorder.getVisibleMode(this.isLoading_), | 
 |               MetricsRecorder.getVisibleMode(isLoading)); | 
 |           this.isLoading_ = isLoading; | 
 |           this.isMenuEnabled_ = isMenuEnabled; | 
 |           this.tooltip_ = loadTimeData.getString( | 
 |               isLoading ? | 
 |                   RELOAD_BUTTON_TOOLTIP_STOP : | 
 |                   (isMenuEnabled ? RELOAD_BUTTON_TOOLTIP_RELOAD_WITH_MENU : | 
 |                                    RELOAD_BUTTON_TOOLTIP_RELOAD)); | 
 |         }); | 
 |     ColorChangeUpdater.forDocument().start(); | 
 |   } | 
 |  | 
 |   static get is() { | 
 |     return 'reload-button-app'; | 
 |   } | 
 |  | 
 |   static override get styles() { | 
 |     return getCss(); | 
 |   } | 
 |  | 
 |   override render() { | 
 |     return getHtml.bind(this)(); | 
 |   } | 
 |  | 
 |   static override get properties() { | 
 |     return { | 
 |       isLoading_: {state: true, type: Boolean}, | 
 |       tooltip_: {state: true, type: String}, | 
 |     }; | 
 |   } | 
 |  | 
 |   protected accessor isLoading_: boolean = false; | 
 |   protected accessor tooltip_: string = | 
 |       loadTimeData.getString(RELOAD_BUTTON_TOOLTIP_RELOAD); | 
 |   private isLongPressed_: boolean = false; | 
 |   private longPressTimer_: number = 0; | 
 |   private isMenuEnabled_: boolean = false; | 
 |  | 
 |   /** | 
 |    * Sets up event listeners and the PerformanceObserver when the element is | 
 |    * added to the DOM. | 
 |    */ | 
 |   override connectedCallback() { | 
 |     super.connectedCallback(); | 
 |  | 
 |     this.metricsRecorder_.startObserving(); | 
 |   } | 
 |  | 
 |   /** | 
 |    * Cleans up event listeners and the PerformanceObserver when the element is | 
 |    * removed from the DOM. | 
 |    */ | 
 |   override disconnectedCallback() { | 
 |     super.disconnectedCallback(); | 
 |  | 
 |     this.metricsRecorder_.stopObserving(); | 
 |   } | 
 |  | 
 |   protected onReloadButtonPointerDown_(e: MouseEvent) { | 
 |     if (e.button !== 0) { | 
 |       // The TypeScript code should only handle the left-click. | 
 |       return; | 
 |     } | 
 |  | 
 |     // Reset the long press tracker. | 
 |     this.isLongPressed_ = false; | 
 |     clearTimeout(this.longPressTimer_); | 
 |  | 
 |     if (this.isLoading_) { | 
 |       // No long press handler for the "stop loading" case. | 
 |       return; | 
 |     } | 
 |  | 
 |     this.longPressTimer_ = setTimeout(() => { | 
 |       // When the long press is triggered and handled, mark `isLongPressed_` | 
 |       // as true, so that it won't be treated as a normal click. | 
 |       this.isLongPressed_ = true; | 
 |       if (this.isMenuEnabled_) { | 
 |         BrowserProxyImpl.getInstance().handler.showContextMenu( | 
 |             e.offsetX, e.offsetY); | 
 |       } | 
 |     }, LONG_PRESS_TIMER_THRESHOLD_MS); | 
 |   } | 
 |  | 
 |   protected onReloadButtonPointerUp_(e: MouseEvent) { | 
 |     this.metricsRecorder_.onButtonPressedStart(e); | 
 |     if (this.isLongPressed_) { | 
 |       // If the long press is already handled, skip the rest. | 
 |       this.isLongPressed_ = false; | 
 |       return; | 
 |     } | 
 |     this.metricsRecorder_.onChangeVisibleMode( | 
 |         MetricsRecorder.getVisibleMode(this.isLoading_), | 
 |         MetricsRecorder.getVisibleMode(!this.isLoading_)); | 
 |  | 
 |     clearTimeout(this.longPressTimer_); | 
 |  | 
 |     if (this.isLoading_) { | 
 |       BrowserProxyImpl.getInstance().handler.stopReload(); | 
 |     } else { | 
 |       // If the shift or ctrl key is pressed, we should reload with cache | 
 |       // ignored. | 
 |       BrowserProxyImpl.getInstance().handler.reload(e.shiftKey || e.ctrlKey); | 
 |     } | 
 |     // Update the renderer in advance to avoid the delay. | 
 |     this.isLoading_ = !this.isLoading_; | 
 |   } | 
 | } | 
 |  | 
 | declare global { | 
 |   interface HTMLElementTagNameMap { | 
 |     'reload-button-app': ReloadButtonAppElement; | 
 |   } | 
 | } | 
 |  | 
 | customElements.define(ReloadButtonAppElement.is, ReloadButtonAppElement); |