File: tab_switcher_view.js

package info (click to toggle)
chromium 138.0.7204.157-1
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 6,071,864 kB
  • sloc: cpp: 34,936,859; ansic: 7,176,967; javascript: 4,110,704; python: 1,419,953; asm: 946,768; xml: 739,967; pascal: 187,324; sh: 89,623; perl: 88,663; objc: 79,944; sql: 50,304; cs: 41,786; fortran: 24,137; makefile: 21,806; php: 13,980; tcl: 13,166; yacc: 8,925; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (163 lines) | stat: -rw-r--r-- 4,626 bytes parent folder | download | duplicates (6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import {$} from 'chrome://resources/js/util.js';

import {addNode, addNodeWithText, setNodeDisplay, setNodePosition} from './util.js';
import {View} from './view.js';

const TAB_LIST_ID = 'tab-list';

/** @type {?TabSwitcherView} */
let instance = null;

/**
 * Controller and View for switching between tabs.
 *
 * The View part of TabSwitcherView displays the contents of the currently
 * selected tab (only one tab can be active at a time).
 *
 * The controller part of TabSwitcherView hooks up a dropdown menu (i.e. HTML
 * SELECT) to control switching between tabs.
 */
export class TabSwitcherView extends View {
  constructor() {
    super();

    this.tabIdToView_ = {};
    this.tabIdToLink_ = {};
    // Map from tab id to the views link visiblity.
    this.tabIdsLinkVisibility_ = new Map();
    this.activeTabId_ = null;
    this.onTabSwitched_ = null;

    // The ideal width of the tab list.  If width is reduced below this, the
    // tab list will be shrunk, but it will be returned to this width once it
    // can be.
    this.tabListWidth_ = $(TAB_LIST_ID).offsetWidth;
  }

  /**
   * @param {!Function} onTabSwitched Callback to run when the
   *                    active tab changes. Called as
   *                    onTabSwitched(oldTabId, newTabId).
   */
  setOnTabSwitched(onTabSwitched) {
    this.onTabSwitched_ = onTabSwitched;
  }

  // ---------------------------------------------
  // Override methods in View
  // ---------------------------------------------

  setGeometry(left, top, width, height) {
    super.setGeometry(this, left, top, width, height);

    const tabListNode = $(TAB_LIST_ID);

    // Set position of the tab list.  Can't use DivView because DivView sets
    // a fixed width at creation time, and need to set the width of the tab
    // list only after its been populated.
    let tabListWidth = this.tabListWidth_;
    if (tabListWidth > width) {
      tabListWidth = width;
    }
    tabListNode.style.position = 'absolute';
    setNodePosition(tabListNode, left, top, tabListWidth, height);

    // Position each of the tab's content areas.
    for (const tabId in this.tabIdToView_) {
      const view = this.tabIdToView_[tabId];
      view.setGeometry(left + tabListWidth, top, width - tabListWidth, height);
    }
  }

  show(isVisible) {
    super.show(isVisible);
    const activeView = this.getActiveTabView();
    if (activeView) {
      activeView.show(isVisible);
    }
  }

  // ---------------------------------------------

  /**
   * Adds a new tab (initially hidden).  To ensure correct tab list sizing,
   * may only be called before first layout.
   *
   * @param {string} tabId The ID to refer to the tab by.
   * @param {!View} view The tab's actual contents.
   * @param {string} name The name for the menu item that selects the tab.
   */
  addTab(tabId, view, name, hash) {
    if (!tabId) {
      throw Error('Must specify a non-false tabId');
    }

    this.tabIdToView_[tabId] = view;
    this.tabIdsLinkVisibility_.set(tabId, true);

    const node = addNodeWithText($(TAB_LIST_ID), 'a', name);
    node.href = hash;
    this.tabIdToLink_[tabId] = node;
    addNode($(TAB_LIST_ID), 'br');

    // Tab content views start off hidden.
    view.show(false);

    this.tabListWidth_ = $(TAB_LIST_ID).offsetWidth;
  }

  getAllTabViews() {
    return this.tabIdToView_;
  }

  getTabView(tabId) {
    return this.tabIdToView_[tabId];
  }

  getActiveTabView() {
    return this.tabIdToView_[this.activeTabId_];
  }

  getActiveTabId() {
    return this.activeTabId_;
  }

  /**
   * Changes the currently active tab to |tabId|. This has several effects:
   *   (1) Replace the tab contents view with that of the new tab.
   *   (2) Update the dropdown menu's current selection.
   *   (3) Invoke the optional onTabSwitched callback.
   */
  switchToTab(tabId) {
    const newView = this.getTabView(tabId);

    if (!newView) {
      throw Error('Invalid tabId');
    }

    const oldTabId = this.activeTabId_;
    this.activeTabId_ = tabId;

    if (oldTabId) {
      this.tabIdToLink_[oldTabId].classList.remove('selected');
      // Hide the previously visible tab contents.
      this.getTabView(oldTabId).show(false);
    }

    this.tabIdToLink_[tabId].classList.add('selected');

    newView.show(this.isVisible());

    if (this.onTabSwitched_) {
      this.onTabSwitched_(oldTabId, tabId);
    }
  }

  static getInstance() {
    return instance || (instance = new TabSwitcherView());
  }
}