xref: /aosp_15_r20/external/perfetto/infra/perfetto.dev/src/assets/script.js (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
1*6dbdd20aSAndroid Build Coastguard Worker// Copyright (C) 2020 The Android Open Source Project
2*6dbdd20aSAndroid Build Coastguard Worker//
3*6dbdd20aSAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License");
4*6dbdd20aSAndroid Build Coastguard Worker// you may not use this file except in compliance with the License.
5*6dbdd20aSAndroid Build Coastguard Worker// You may obtain a copy of the License at
6*6dbdd20aSAndroid Build Coastguard Worker//
7*6dbdd20aSAndroid Build Coastguard Worker//      http://www.apache.org/licenses/LICENSE-2.0
8*6dbdd20aSAndroid Build Coastguard Worker//
9*6dbdd20aSAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software
10*6dbdd20aSAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS,
11*6dbdd20aSAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*6dbdd20aSAndroid Build Coastguard Worker// See the License for the specific language governing permissions and
13*6dbdd20aSAndroid Build Coastguard Worker// limitations under the License.
14*6dbdd20aSAndroid Build Coastguard Worker
15*6dbdd20aSAndroid Build Coastguard Worker'use strict';
16*6dbdd20aSAndroid Build Coastguard Worker
17*6dbdd20aSAndroid Build Coastguard Workerlet tocAnchors = [];
18*6dbdd20aSAndroid Build Coastguard Workerlet lastMouseOffY = 0;
19*6dbdd20aSAndroid Build Coastguard Workerlet onloadFired = false;
20*6dbdd20aSAndroid Build Coastguard Workerconst postLoadActions = [];
21*6dbdd20aSAndroid Build Coastguard Workerlet tocEventHandlersInstalled = false;
22*6dbdd20aSAndroid Build Coastguard Workerlet resizeObserver = undefined;
23*6dbdd20aSAndroid Build Coastguard Worker
24*6dbdd20aSAndroid Build Coastguard Workerfunction doAfterLoadEvent(action) {
25*6dbdd20aSAndroid Build Coastguard Worker  if (onloadFired) {
26*6dbdd20aSAndroid Build Coastguard Worker    return action();
27*6dbdd20aSAndroid Build Coastguard Worker  }
28*6dbdd20aSAndroid Build Coastguard Worker  postLoadActions.push(action);
29*6dbdd20aSAndroid Build Coastguard Worker}
30*6dbdd20aSAndroid Build Coastguard Worker
31*6dbdd20aSAndroid Build Coastguard Workerfunction setupSandwichMenu() {
32*6dbdd20aSAndroid Build Coastguard Worker  const header = document.querySelector('.site-header');
33*6dbdd20aSAndroid Build Coastguard Worker  const docsNav = document.querySelector('.nav');
34*6dbdd20aSAndroid Build Coastguard Worker  const menu = header.querySelector('.menu');
35*6dbdd20aSAndroid Build Coastguard Worker  menu.addEventListener('click', (e) => {
36*6dbdd20aSAndroid Build Coastguard Worker    e.preventDefault();
37*6dbdd20aSAndroid Build Coastguard Worker
38*6dbdd20aSAndroid Build Coastguard Worker    // If we are displaying any /docs, toggle the navbar instead (the TOC).
39*6dbdd20aSAndroid Build Coastguard Worker    if (docsNav) {
40*6dbdd20aSAndroid Build Coastguard Worker      // |after_first_click| is to avoid spurious transitions on page load.
41*6dbdd20aSAndroid Build Coastguard Worker      docsNav.classList.add('after_first_click');
42*6dbdd20aSAndroid Build Coastguard Worker      updateNav();
43*6dbdd20aSAndroid Build Coastguard Worker      setTimeout(() => docsNav.classList.toggle('expanded'), 0);
44*6dbdd20aSAndroid Build Coastguard Worker    } else {
45*6dbdd20aSAndroid Build Coastguard Worker      header.classList.toggle('expanded');
46*6dbdd20aSAndroid Build Coastguard Worker    }
47*6dbdd20aSAndroid Build Coastguard Worker  });
48*6dbdd20aSAndroid Build Coastguard Worker}
49*6dbdd20aSAndroid Build Coastguard Worker
50*6dbdd20aSAndroid Build Coastguard Worker// (Re-)Generates the Table Of Contents for docs (the right-hand-side one).
51*6dbdd20aSAndroid Build Coastguard Workerfunction updateTOC() {
52*6dbdd20aSAndroid Build Coastguard Worker  const tocContainer = document.querySelector('.docs .toc');
53*6dbdd20aSAndroid Build Coastguard Worker  if (!tocContainer)
54*6dbdd20aSAndroid Build Coastguard Worker    return;
55*6dbdd20aSAndroid Build Coastguard Worker  const toc = document.createElement('ul');
56*6dbdd20aSAndroid Build Coastguard Worker  const anchors = document.querySelectorAll('.doc a.anchor');
57*6dbdd20aSAndroid Build Coastguard Worker  tocAnchors = [];
58*6dbdd20aSAndroid Build Coastguard Worker  for (const anchor of anchors) {
59*6dbdd20aSAndroid Build Coastguard Worker    const li = document.createElement('li');
60*6dbdd20aSAndroid Build Coastguard Worker    const link = document.createElement('a');
61*6dbdd20aSAndroid Build Coastguard Worker    link.innerText = anchor.parentElement.innerText;
62*6dbdd20aSAndroid Build Coastguard Worker    link.href = anchor.href;
63*6dbdd20aSAndroid Build Coastguard Worker    link.onclick = () => {
64*6dbdd20aSAndroid Build Coastguard Worker      onScroll(link)
65*6dbdd20aSAndroid Build Coastguard Worker    };
66*6dbdd20aSAndroid Build Coastguard Worker    li.appendChild(link);
67*6dbdd20aSAndroid Build Coastguard Worker    if (anchor.parentElement.tagName === 'H3')
68*6dbdd20aSAndroid Build Coastguard Worker      li.style.paddingLeft = '10px';
69*6dbdd20aSAndroid Build Coastguard Worker    toc.appendChild(li);
70*6dbdd20aSAndroid Build Coastguard Worker    doAfterLoadEvent(() => {
71*6dbdd20aSAndroid Build Coastguard Worker      tocAnchors.push(
72*6dbdd20aSAndroid Build Coastguard Worker        { top: anchor.offsetTop + anchor.offsetHeight / 2, obj: link });
73*6dbdd20aSAndroid Build Coastguard Worker    });
74*6dbdd20aSAndroid Build Coastguard Worker  }
75*6dbdd20aSAndroid Build Coastguard Worker  tocContainer.innerHTML = '';
76*6dbdd20aSAndroid Build Coastguard Worker  tocContainer.appendChild(toc);
77*6dbdd20aSAndroid Build Coastguard Worker
78*6dbdd20aSAndroid Build Coastguard Worker  // Add event handlers on the first call (can be called more than once to
79*6dbdd20aSAndroid Build Coastguard Worker  // recompute anchors on resize).
80*6dbdd20aSAndroid Build Coastguard Worker  if (tocEventHandlersInstalled)
81*6dbdd20aSAndroid Build Coastguard Worker    return;
82*6dbdd20aSAndroid Build Coastguard Worker  tocEventHandlersInstalled = true;
83*6dbdd20aSAndroid Build Coastguard Worker  const doc = document.querySelector('.doc');
84*6dbdd20aSAndroid Build Coastguard Worker  const passive = { passive: true };
85*6dbdd20aSAndroid Build Coastguard Worker  if (doc) {
86*6dbdd20aSAndroid Build Coastguard Worker    const offY = doc.offsetTop;
87*6dbdd20aSAndroid Build Coastguard Worker    doc.addEventListener('mousemove', (e) => onMouseMove(offY, e), passive);
88*6dbdd20aSAndroid Build Coastguard Worker    doc.addEventListener('mouseleave', () => {
89*6dbdd20aSAndroid Build Coastguard Worker      lastMouseOffY = 0;
90*6dbdd20aSAndroid Build Coastguard Worker    }, passive);
91*6dbdd20aSAndroid Build Coastguard Worker  }
92*6dbdd20aSAndroid Build Coastguard Worker  window.addEventListener('scroll', () => onScroll(), passive);
93*6dbdd20aSAndroid Build Coastguard Worker  resizeObserver = new ResizeObserver(() => requestAnimationFrame(() => {
94*6dbdd20aSAndroid Build Coastguard Worker    updateNav();
95*6dbdd20aSAndroid Build Coastguard Worker    updateTOC();
96*6dbdd20aSAndroid Build Coastguard Worker  }));
97*6dbdd20aSAndroid Build Coastguard Worker  resizeObserver.observe(doc);
98*6dbdd20aSAndroid Build Coastguard Worker}
99*6dbdd20aSAndroid Build Coastguard Worker
100*6dbdd20aSAndroid Build Coastguard Worker// Highlights the current TOC anchor depending on the scroll offset.
101*6dbdd20aSAndroid Build Coastguard Workerfunction onMouseMove(offY, e) {
102*6dbdd20aSAndroid Build Coastguard Worker  lastMouseOffY = e.clientY - offY;
103*6dbdd20aSAndroid Build Coastguard Worker  onScroll();
104*6dbdd20aSAndroid Build Coastguard Worker}
105*6dbdd20aSAndroid Build Coastguard Worker
106*6dbdd20aSAndroid Build Coastguard Workerfunction onScroll(forceHighlight) {
107*6dbdd20aSAndroid Build Coastguard Worker  const y = document.documentElement.scrollTop + lastMouseOffY;
108*6dbdd20aSAndroid Build Coastguard Worker  let highEl = undefined;
109*6dbdd20aSAndroid Build Coastguard Worker  for (const x of tocAnchors) {
110*6dbdd20aSAndroid Build Coastguard Worker    if (y < x.top)
111*6dbdd20aSAndroid Build Coastguard Worker      continue;
112*6dbdd20aSAndroid Build Coastguard Worker    highEl = x.obj;
113*6dbdd20aSAndroid Build Coastguard Worker  }
114*6dbdd20aSAndroid Build Coastguard Worker  for (const link of document.querySelectorAll('.docs .toc a')) {
115*6dbdd20aSAndroid Build Coastguard Worker    if ((!forceHighlight && link === highEl) || (forceHighlight === link)) {
116*6dbdd20aSAndroid Build Coastguard Worker      link.classList.add('highlighted');
117*6dbdd20aSAndroid Build Coastguard Worker    } else {
118*6dbdd20aSAndroid Build Coastguard Worker      link.classList.remove('highlighted');
119*6dbdd20aSAndroid Build Coastguard Worker    }
120*6dbdd20aSAndroid Build Coastguard Worker  }
121*6dbdd20aSAndroid Build Coastguard Worker}
122*6dbdd20aSAndroid Build Coastguard Worker
123*6dbdd20aSAndroid Build Coastguard Worker// This function needs to be idempotent as it is called more than once (on every
124*6dbdd20aSAndroid Build Coastguard Worker// resize).
125*6dbdd20aSAndroid Build Coastguard Workerfunction updateNav() {
126*6dbdd20aSAndroid Build Coastguard Worker  const curDoc = document.querySelector('.doc');
127*6dbdd20aSAndroid Build Coastguard Worker  let curFileName = '';
128*6dbdd20aSAndroid Build Coastguard Worker  if (curDoc)
129*6dbdd20aSAndroid Build Coastguard Worker    curFileName = curDoc.dataset['mdFile'];
130*6dbdd20aSAndroid Build Coastguard Worker
131*6dbdd20aSAndroid Build Coastguard Worker  // First identify all the top-level nav entries (Quickstart, Data Sources,
132*6dbdd20aSAndroid Build Coastguard Worker  // ...) and make them compressible.
133*6dbdd20aSAndroid Build Coastguard Worker  const toplevelSections = document.querySelectorAll('.docs .nav > ul > li');
134*6dbdd20aSAndroid Build Coastguard Worker  const toplevelLinks = [];
135*6dbdd20aSAndroid Build Coastguard Worker  for (const sec of toplevelSections) {
136*6dbdd20aSAndroid Build Coastguard Worker    const childMenu = sec.querySelector('ul');
137*6dbdd20aSAndroid Build Coastguard Worker    if (!childMenu) {
138*6dbdd20aSAndroid Build Coastguard Worker      // Don't make it compressible if it has no children (e.g. the very
139*6dbdd20aSAndroid Build Coastguard Worker      // first 'Introduction' link).
140*6dbdd20aSAndroid Build Coastguard Worker      continue;
141*6dbdd20aSAndroid Build Coastguard Worker    }
142*6dbdd20aSAndroid Build Coastguard Worker
143*6dbdd20aSAndroid Build Coastguard Worker    // Don't make it compressible if the entry has an actual link (e.g. the very
144*6dbdd20aSAndroid Build Coastguard Worker    // first 'Introduction' link), because otherwise it become ambiguous whether
145*6dbdd20aSAndroid Build Coastguard Worker    // the link should toggle or open the link.
146*6dbdd20aSAndroid Build Coastguard Worker    const link = sec.querySelector('a');
147*6dbdd20aSAndroid Build Coastguard Worker    if (!link || !link.href.endsWith('#'))
148*6dbdd20aSAndroid Build Coastguard Worker      continue;
149*6dbdd20aSAndroid Build Coastguard Worker
150*6dbdd20aSAndroid Build Coastguard Worker    sec.classList.add('compressible');
151*6dbdd20aSAndroid Build Coastguard Worker
152*6dbdd20aSAndroid Build Coastguard Worker    // Remember the compressed status as long as the page is opened, so clicking
153*6dbdd20aSAndroid Build Coastguard Worker    // through links keeps the sidebar in a consistent visual state.
154*6dbdd20aSAndroid Build Coastguard Worker    const memoKey = `docs.nav.compressed[${link.innerHTML}]`;
155*6dbdd20aSAndroid Build Coastguard Worker
156*6dbdd20aSAndroid Build Coastguard Worker    if (sessionStorage.getItem(memoKey) === '1') {
157*6dbdd20aSAndroid Build Coastguard Worker      sec.classList.add('compressed');
158*6dbdd20aSAndroid Build Coastguard Worker    }
159*6dbdd20aSAndroid Build Coastguard Worker    doAfterLoadEvent(() => {
160*6dbdd20aSAndroid Build Coastguard Worker      childMenu.style.maxHeight = `${childMenu.scrollHeight + 40}px`;
161*6dbdd20aSAndroid Build Coastguard Worker    });
162*6dbdd20aSAndroid Build Coastguard Worker
163*6dbdd20aSAndroid Build Coastguard Worker    toplevelLinks.push(link);
164*6dbdd20aSAndroid Build Coastguard Worker    link.onclick = (evt) => {
165*6dbdd20aSAndroid Build Coastguard Worker      evt.preventDefault();
166*6dbdd20aSAndroid Build Coastguard Worker      sec.classList.toggle('compressed');
167*6dbdd20aSAndroid Build Coastguard Worker      if (sec.classList.contains('compressed')) {
168*6dbdd20aSAndroid Build Coastguard Worker        sessionStorage.setItem(memoKey, '1');
169*6dbdd20aSAndroid Build Coastguard Worker      } else {
170*6dbdd20aSAndroid Build Coastguard Worker        sessionStorage.removeItem(memoKey);
171*6dbdd20aSAndroid Build Coastguard Worker      }
172*6dbdd20aSAndroid Build Coastguard Worker    };
173*6dbdd20aSAndroid Build Coastguard Worker  }
174*6dbdd20aSAndroid Build Coastguard Worker
175*6dbdd20aSAndroid Build Coastguard Worker  const exps = document.querySelectorAll('.docs .nav ul a');
176*6dbdd20aSAndroid Build Coastguard Worker  let found = false;
177*6dbdd20aSAndroid Build Coastguard Worker  for (const x of exps) {
178*6dbdd20aSAndroid Build Coastguard Worker    // If the url of the entry matches the url of the page, mark the item as
179*6dbdd20aSAndroid Build Coastguard Worker    // highlighted and expand all its parents.
180*6dbdd20aSAndroid Build Coastguard Worker    if (!x.href)
181*6dbdd20aSAndroid Build Coastguard Worker      continue;
182*6dbdd20aSAndroid Build Coastguard Worker    const url = new URL(x.href);
183*6dbdd20aSAndroid Build Coastguard Worker    if (x.href.endsWith('#')) {
184*6dbdd20aSAndroid Build Coastguard Worker      // This is a non-leaf link to a menu.
185*6dbdd20aSAndroid Build Coastguard Worker      if (toplevelLinks.indexOf(x) < 0) {
186*6dbdd20aSAndroid Build Coastguard Worker        x.removeAttribute('href');
187*6dbdd20aSAndroid Build Coastguard Worker      }
188*6dbdd20aSAndroid Build Coastguard Worker    } else if (url.pathname === curFileName && !found) {
189*6dbdd20aSAndroid Build Coastguard Worker      x.classList.add('selected');
190*6dbdd20aSAndroid Build Coastguard Worker      doAfterLoadEvent(() => x.scrollIntoViewIfNeeded());
191*6dbdd20aSAndroid Build Coastguard Worker      found = true;  // Highlight only the first occurrence.
192*6dbdd20aSAndroid Build Coastguard Worker    }
193*6dbdd20aSAndroid Build Coastguard Worker  }
194*6dbdd20aSAndroid Build Coastguard Worker}
195*6dbdd20aSAndroid Build Coastguard Worker
196*6dbdd20aSAndroid Build Coastguard Worker// If the page contains a ```mermaid ``` block, lazily loads the plugin and
197*6dbdd20aSAndroid Build Coastguard Worker// renders.
198*6dbdd20aSAndroid Build Coastguard Workerfunction initMermaid() {
199*6dbdd20aSAndroid Build Coastguard Worker  const graphs = document.querySelectorAll('.mermaid');
200*6dbdd20aSAndroid Build Coastguard Worker
201*6dbdd20aSAndroid Build Coastguard Worker  // Skip if there are no mermaid graphs to render.
202*6dbdd20aSAndroid Build Coastguard Worker  if (!graphs.length)
203*6dbdd20aSAndroid Build Coastguard Worker    return;
204*6dbdd20aSAndroid Build Coastguard Worker
205*6dbdd20aSAndroid Build Coastguard Worker  const script = document.createElement('script');
206*6dbdd20aSAndroid Build Coastguard Worker  script.type = 'text/javascript';
207*6dbdd20aSAndroid Build Coastguard Worker  script.src = '/assets/mermaid.min.js';
208*6dbdd20aSAndroid Build Coastguard Worker  const themeCSS = `
209*6dbdd20aSAndroid Build Coastguard Worker  .cluster rect { fill: #FCFCFC; stroke: #ddd }
210*6dbdd20aSAndroid Build Coastguard Worker  .node rect { fill: #DCEDC8; stroke: #8BC34A}
211*6dbdd20aSAndroid Build Coastguard Worker  .edgeLabel:not(:empty) {
212*6dbdd20aSAndroid Build Coastguard Worker      border-radius: 6px;
213*6dbdd20aSAndroid Build Coastguard Worker      font-size: 0.9em;
214*6dbdd20aSAndroid Build Coastguard Worker      padding: 4px;
215*6dbdd20aSAndroid Build Coastguard Worker      background: #F5F5F5;
216*6dbdd20aSAndroid Build Coastguard Worker      border: 1px solid #DDDDDD;
217*6dbdd20aSAndroid Build Coastguard Worker      color: #666;
218*6dbdd20aSAndroid Build Coastguard Worker  }
219*6dbdd20aSAndroid Build Coastguard Worker  `;
220*6dbdd20aSAndroid Build Coastguard Worker  script.addEventListener('load', () => {
221*6dbdd20aSAndroid Build Coastguard Worker    mermaid.initialize({
222*6dbdd20aSAndroid Build Coastguard Worker      startOnLoad: false,
223*6dbdd20aSAndroid Build Coastguard Worker      themeCSS: themeCSS,
224*6dbdd20aSAndroid Build Coastguard Worker      securityLevel: 'loose',  // To allow #in-page-links
225*6dbdd20aSAndroid Build Coastguard Worker    });
226*6dbdd20aSAndroid Build Coastguard Worker    for (const graph of graphs) {
227*6dbdd20aSAndroid Build Coastguard Worker      requestAnimationFrame(() => {
228*6dbdd20aSAndroid Build Coastguard Worker        mermaid.init(undefined, graph);
229*6dbdd20aSAndroid Build Coastguard Worker        graph.classList.add('rendered');
230*6dbdd20aSAndroid Build Coastguard Worker      });
231*6dbdd20aSAndroid Build Coastguard Worker    }
232*6dbdd20aSAndroid Build Coastguard Worker  })
233*6dbdd20aSAndroid Build Coastguard Worker  document.body.appendChild(script);
234*6dbdd20aSAndroid Build Coastguard Worker}
235*6dbdd20aSAndroid Build Coastguard Worker
236*6dbdd20aSAndroid Build Coastguard Workerfunction setupSearch() {
237*6dbdd20aSAndroid Build Coastguard Worker  const URL =
238*6dbdd20aSAndroid Build Coastguard Worker    'https://www.googleapis.com/customsearch/v1?key=AIzaSyBTD2XJkQkkuvDn76LSftsgWOkdBz9Gfwo&cx=007128963598137843411:8suis14kcmy&q='
239*6dbdd20aSAndroid Build Coastguard Worker  const searchContainer = document.getElementById('search');
240*6dbdd20aSAndroid Build Coastguard Worker  const searchBox = document.getElementById('search-box');
241*6dbdd20aSAndroid Build Coastguard Worker  const searchRes = document.getElementById('search-res')
242*6dbdd20aSAndroid Build Coastguard Worker  if (!searchBox || !searchRes) return;
243*6dbdd20aSAndroid Build Coastguard Worker
244*6dbdd20aSAndroid Build Coastguard Worker  document.body.addEventListener('keydown', (e) => {
245*6dbdd20aSAndroid Build Coastguard Worker    if (e.key === '/' && e.target.tagName.toLowerCase() === 'body') {
246*6dbdd20aSAndroid Build Coastguard Worker      searchBox.setSelectionRange(0, -1);
247*6dbdd20aSAndroid Build Coastguard Worker      searchBox.focus();
248*6dbdd20aSAndroid Build Coastguard Worker      e.preventDefault();
249*6dbdd20aSAndroid Build Coastguard Worker    } else if (e.key === 'Escape' && searchContainer.contains(e.target)) {
250*6dbdd20aSAndroid Build Coastguard Worker      searchBox.blur();
251*6dbdd20aSAndroid Build Coastguard Worker
252*6dbdd20aSAndroid Build Coastguard Worker      // Handle the case of clicking Tab and moving down to results.
253*6dbdd20aSAndroid Build Coastguard Worker      e.target.blur();
254*6dbdd20aSAndroid Build Coastguard Worker    }
255*6dbdd20aSAndroid Build Coastguard Worker  });
256*6dbdd20aSAndroid Build Coastguard Worker
257*6dbdd20aSAndroid Build Coastguard Worker  let timerId = -1;
258*6dbdd20aSAndroid Build Coastguard Worker  let lastSearchId = 0;
259*6dbdd20aSAndroid Build Coastguard Worker
260*6dbdd20aSAndroid Build Coastguard Worker  const doSearch = async () => {
261*6dbdd20aSAndroid Build Coastguard Worker    timerId = -1;
262*6dbdd20aSAndroid Build Coastguard Worker    searchRes.style.width = `${searchBox.offsetWidth}px`;
263*6dbdd20aSAndroid Build Coastguard Worker
264*6dbdd20aSAndroid Build Coastguard Worker    // `searchId` handles the case of two subsequent requests racing. This is to
265*6dbdd20aSAndroid Build Coastguard Worker    // prevent older results, delivered in reverse order, to replace newer ones.
266*6dbdd20aSAndroid Build Coastguard Worker    const searchId = ++lastSearchId;
267*6dbdd20aSAndroid Build Coastguard Worker    const f = await fetch(URL + encodeURIComponent(searchBox.value));
268*6dbdd20aSAndroid Build Coastguard Worker    const jsonRes = await f.json();
269*6dbdd20aSAndroid Build Coastguard Worker    const results = jsonRes['items'];
270*6dbdd20aSAndroid Build Coastguard Worker    searchRes.innerHTML = '';
271*6dbdd20aSAndroid Build Coastguard Worker    if (results === undefined || searchId != lastSearchId) {
272*6dbdd20aSAndroid Build Coastguard Worker      return;
273*6dbdd20aSAndroid Build Coastguard Worker    }
274*6dbdd20aSAndroid Build Coastguard Worker    for (const res of results) {
275*6dbdd20aSAndroid Build Coastguard Worker      const link = document.createElement('a');
276*6dbdd20aSAndroid Build Coastguard Worker      link.href = res.link;
277*6dbdd20aSAndroid Build Coastguard Worker      const title = document.createElement('div');
278*6dbdd20aSAndroid Build Coastguard Worker      title.className = 'sr-title';
279*6dbdd20aSAndroid Build Coastguard Worker      title.innerText = res.title.replace(' - Perfetto Tracing Docs', '');
280*6dbdd20aSAndroid Build Coastguard Worker      link.appendChild(title);
281*6dbdd20aSAndroid Build Coastguard Worker
282*6dbdd20aSAndroid Build Coastguard Worker      const snippet = document.createElement('div');
283*6dbdd20aSAndroid Build Coastguard Worker      snippet.className = 'sr-snippet';
284*6dbdd20aSAndroid Build Coastguard Worker      snippet.innerText = res.snippet;
285*6dbdd20aSAndroid Build Coastguard Worker      link.appendChild(snippet);
286*6dbdd20aSAndroid Build Coastguard Worker
287*6dbdd20aSAndroid Build Coastguard Worker      const div = document.createElement('div');
288*6dbdd20aSAndroid Build Coastguard Worker      div.appendChild(link);
289*6dbdd20aSAndroid Build Coastguard Worker      searchRes.appendChild(div);
290*6dbdd20aSAndroid Build Coastguard Worker    }
291*6dbdd20aSAndroid Build Coastguard Worker  };
292*6dbdd20aSAndroid Build Coastguard Worker
293*6dbdd20aSAndroid Build Coastguard Worker  searchBox.addEventListener('keyup', () => {
294*6dbdd20aSAndroid Build Coastguard Worker    if (timerId >= 0) return;
295*6dbdd20aSAndroid Build Coastguard Worker    timerId = setTimeout(doSearch, 200);
296*6dbdd20aSAndroid Build Coastguard Worker  });
297*6dbdd20aSAndroid Build Coastguard Worker}
298*6dbdd20aSAndroid Build Coastguard Worker
299*6dbdd20aSAndroid Build Coastguard Workerwindow.addEventListener('DOMContentLoaded', () => {
300*6dbdd20aSAndroid Build Coastguard Worker  updateNav();
301*6dbdd20aSAndroid Build Coastguard Worker  updateTOC();
302*6dbdd20aSAndroid Build Coastguard Worker});
303*6dbdd20aSAndroid Build Coastguard Worker
304*6dbdd20aSAndroid Build Coastguard Workerwindow.addEventListener('load', () => {
305*6dbdd20aSAndroid Build Coastguard Worker  setupSandwichMenu();
306*6dbdd20aSAndroid Build Coastguard Worker  initMermaid();
307*6dbdd20aSAndroid Build Coastguard Worker
308*6dbdd20aSAndroid Build Coastguard Worker  // Don't smooth-scroll on pages that are too long (e.g. reference pages).
309*6dbdd20aSAndroid Build Coastguard Worker  if (document.body.scrollHeight < 10000) {
310*6dbdd20aSAndroid Build Coastguard Worker    document.documentElement.style.scrollBehavior = 'smooth';
311*6dbdd20aSAndroid Build Coastguard Worker  } else {
312*6dbdd20aSAndroid Build Coastguard Worker    document.documentElement.style.scrollBehavior = 'initial';
313*6dbdd20aSAndroid Build Coastguard Worker  }
314*6dbdd20aSAndroid Build Coastguard Worker
315*6dbdd20aSAndroid Build Coastguard Worker  onloadFired = true;
316*6dbdd20aSAndroid Build Coastguard Worker  while (postLoadActions.length > 0) {
317*6dbdd20aSAndroid Build Coastguard Worker    postLoadActions.shift()();
318*6dbdd20aSAndroid Build Coastguard Worker  }
319*6dbdd20aSAndroid Build Coastguard Worker
320*6dbdd20aSAndroid Build Coastguard Worker  updateTOC();
321*6dbdd20aSAndroid Build Coastguard Worker  setupSearch();
322*6dbdd20aSAndroid Build Coastguard Worker
323*6dbdd20aSAndroid Build Coastguard Worker  // Enable animations only after the load event. This is to prevent glitches
324*6dbdd20aSAndroid Build Coastguard Worker  // when switching pages.
325*6dbdd20aSAndroid Build Coastguard Worker  document.documentElement.style.setProperty('--anim-enabled', '1')
326*6dbdd20aSAndroid Build Coastguard Worker});
327*6dbdd20aSAndroid Build Coastguard Worker
328*6dbdd20aSAndroid Build Coastguard Worker// Handles redirects from the old docs.perfetto.dev.
329*6dbdd20aSAndroid Build Coastguard Workerconst legacyRedirectMap = {
330*6dbdd20aSAndroid Build Coastguard Worker  '#/contributing': '/docs/contributing/getting-started#community',
331*6dbdd20aSAndroid Build Coastguard Worker  '#/build-instructions': '/docs/contributing/build-instructions',
332*6dbdd20aSAndroid Build Coastguard Worker  '#/testing': '/docs/contributing/testing',
333*6dbdd20aSAndroid Build Coastguard Worker  '#/app-instrumentation': '/docs/instrumentation/tracing-sdk',
334*6dbdd20aSAndroid Build Coastguard Worker  '#/recording-traces': '/docs/instrumentation/tracing-sdk#recording',
335*6dbdd20aSAndroid Build Coastguard Worker  '#/running': '/docs/quickstart/android-tracing',
336*6dbdd20aSAndroid Build Coastguard Worker  '#/long-traces': '/docs/concepts/config#long-traces',
337*6dbdd20aSAndroid Build Coastguard Worker  '#/detached-mode': '/docs/concepts/detached-mode',
338*6dbdd20aSAndroid Build Coastguard Worker  '#/heapprofd': '/docs/data-sources/native-heap-profiler',
339*6dbdd20aSAndroid Build Coastguard Worker  '#/java-hprof': '/docs/data-sources/java-heap-profiler',
340*6dbdd20aSAndroid Build Coastguard Worker  '#/trace-processor': '/docs/analysis/trace-processor',
341*6dbdd20aSAndroid Build Coastguard Worker  '#/analysis': '/docs/analysis/trace-processor#annotations',
342*6dbdd20aSAndroid Build Coastguard Worker  '#/metrics': '/docs/analysis/metrics',
343*6dbdd20aSAndroid Build Coastguard Worker  '#/traceconv': '/docs/quickstart/traceconv',
344*6dbdd20aSAndroid Build Coastguard Worker  '#/clock-sync': '/docs/concepts/clock-sync',
345*6dbdd20aSAndroid Build Coastguard Worker  '#/architecture': '/docs/concepts/service-model',
346*6dbdd20aSAndroid Build Coastguard Worker};
347*6dbdd20aSAndroid Build Coastguard Worker
348*6dbdd20aSAndroid Build Coastguard Workerconst fragment = location.hash.split('?')[0].replace('.md', '');
349*6dbdd20aSAndroid Build Coastguard Workerif (fragment in legacyRedirectMap) {
350*6dbdd20aSAndroid Build Coastguard Worker  location.replace(legacyRedirectMap[fragment]);
351*6dbdd20aSAndroid Build Coastguard Worker}
352*6dbdd20aSAndroid Build Coastguard Worker
353*6dbdd20aSAndroid Build Coastguard Worker// Pages which have been been removed/renamed/moved and need to be redirected
354*6dbdd20aSAndroid Build Coastguard Worker// to their new home.
355*6dbdd20aSAndroid Build Coastguard Workerconst redirectMap = {
356*6dbdd20aSAndroid Build Coastguard Worker  // stdlib docs is not a perfect replacement but is good enough until we write
357*6dbdd20aSAndroid Build Coastguard Worker  // a proper, Android specific query codelab page.
358*6dbdd20aSAndroid Build Coastguard Worker  // TODO(lalitm): switch to that page when it's ready.
359*6dbdd20aSAndroid Build Coastguard Worker  '/docs/analysis/common-queries': '/docs/analysis/stdlib-docs',
360*6dbdd20aSAndroid Build Coastguard Worker};
361*6dbdd20aSAndroid Build Coastguard Worker
362*6dbdd20aSAndroid Build Coastguard Workerif (location.pathname in redirectMap) {
363*6dbdd20aSAndroid Build Coastguard Worker  location.replace(redirectMap[location.pathname]);
364*6dbdd20aSAndroid Build Coastguard Worker}
365