| // Copyright 2017 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| import 'chrome://resources/js/jstemplate_compiled.js'; |
| |
| import {assert} from 'chrome://resources/js/assert_ts.js'; |
| import {addWebUiListener} from 'chrome://resources/js/cr.js'; |
| |
| let instance: TrafficLogTag|null = null; |
| |
| export interface ProtocolEvent { |
| time: string; |
| } |
| |
| class TrafficLogTag { |
| container: HTMLElement|null = null; |
| protocolEvents: ProtocolEvent[] = []; |
| knownEventTimestamps: Set<string> = new Set(); |
| |
| /** |
| * Helper to determine if the window is scrolled to its bottom limit. |
| * @return true if the container is scrolled to the bottom |
| */ |
| private isScrolledToBottom_(): boolean { |
| return (window.innerHeight + window.scrollY) >= document.body.offsetHeight; |
| } |
| |
| /** |
| * Helper to scroll the window to its bottom. |
| */ |
| private scrollToBottom_() { |
| window.scrollTo(0, document.body.scrollHeight); |
| } |
| |
| /** |
| * Callback for incoming protocol events. |
| * @param details The protocol event. |
| */ |
| private onReceivedProtocolEvent_(details: ProtocolEvent) { |
| if (this.knownEventTimestamps.has(details.time)) { |
| return; |
| } |
| |
| this.knownEventTimestamps.add(details.time); |
| this.protocolEvents.push(details); |
| |
| const shouldScrollDown = this.isScrolledToBottom_(); |
| |
| assert(this.container); |
| jstProcess( |
| new JsEvalContext({events: this.protocolEvents}), this.container); |
| |
| if (shouldScrollDown) { |
| this.scrollToBottom_(); |
| } |
| } |
| |
| /** |
| * Toggles the given traffic event entry div's "expanded" state. |
| * @param e the click event that triggered the toggle. |
| */ |
| private expandListener_(e: Event) { |
| if ((e.target as HTMLElement).classList.contains('proto')) { |
| // We ignore proto clicks to keep it copyable. |
| return; |
| } |
| let trafficEventDiv = e.target as HTMLElement; |
| // Click might be on div's child. |
| if (trafficEventDiv.nodeName !== 'DIV' && trafficEventDiv.parentNode) { |
| trafficEventDiv = trafficEventDiv.parentNode as HTMLElement; |
| } |
| trafficEventDiv.classList.toggle('traffic-event-entry-expanded-fullscreen'); |
| } |
| |
| /** |
| * Attaches a listener to the given traffic event entry div. |
| */ |
| addExpandListener(element: HTMLElement) { |
| element.addEventListener('click', this.expandListener_, false); |
| } |
| |
| onLoad() { |
| const container = document.querySelector<HTMLElement>( |
| '#traffic-event-fullscreen-container'); |
| assert(container); |
| this.container = container; |
| |
| addWebUiListener( |
| 'onProtocolEvent', this.onReceivedProtocolEvent_.bind(this)); |
| |
| // Make the prototype jscontent element disappear. |
| jstProcess(new JsEvalContext({}), this.container); |
| } |
| |
| static getInstance(): TrafficLogTag { |
| return instance || (instance = new TrafficLogTag()); |
| } |
| } |
| |
| // For JS eval. |
| Object.assign(window, {TrafficLogTag}); |
| |
| document.addEventListener('DOMContentLoaded', () => { |
| TrafficLogTag.getInstance().onLoad(); |
| }); |