• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5/**
6 * Controller and View for switching between tabs.
7 *
8 * The View part of TabSwitcherView displays the contents of the currently
9 * selected tab (only one tab can be active at a time).
10 *
11 * The controller part of TabSwitcherView hooks up a dropdown menu (i.e. HTML
12 * SELECT) to control switching between tabs.
13 */
14var TabSwitcherView = (function() {
15  'use strict';
16
17  // We inherit from View.
18  var superClass = View;
19
20  /**
21   * @constructor
22   *
23   * @param {DOMSelectNode} dropdownMenu The menu for switching between tabs.
24   *                        The TabSwitcherView will attach an onchange event to
25   *                        the dropdown menu, and control the selected index.
26   * @param {?Function} opt_onTabSwitched Optional callback to run when the
27   *                    active tab changes. Called as
28   *                    opt_onTabSwitched(oldTabId, newTabId).
29   */
30  function TabSwitcherView(dropdownMenu, opt_onTabSwitched) {
31    assertFirstConstructorCall(TabSwitcherView);
32
33    this.tabIdToView_ = {};
34    this.activeTabId_ = null;
35
36    this.dropdownMenu_ = dropdownMenu;
37    this.dropdownMenu_.onchange = this.onMenuSelectionChanged_.bind(this);
38
39    this.onTabSwitched_ = opt_onTabSwitched;
40
41    superClass.call(this);
42  }
43
44  TabSwitcherView.prototype = {
45    // Inherit the superclass's methods.
46    __proto__: superClass.prototype,
47
48    // ---------------------------------------------
49    // Override methods in View
50    // ---------------------------------------------
51
52    setGeometry: function(left, top, width, height) {
53      superClass.prototype.setGeometry.call(this, left, top, width, height);
54
55      // Position each of the tabs content areas.
56      for (var tabId in this.tabIdToView_) {
57        var view = this.tabIdToView_[tabId];
58        view.setGeometry(left, top, width, height);
59      }
60    },
61
62    show: function(isVisible) {
63      superClass.prototype.show.call(this, isVisible);
64      var activeView = this.getActiveTabView();
65      if (activeView)
66        activeView.show(isVisible);
67    },
68
69    // ---------------------------------------------
70
71    /**
72     * Adds a new tab (initially hidden).
73     *
74     * @param {string} tabId The ID to refer to the tab by.
75     * @param {!View} view The tab's actual contents.
76     * @param {string} name The name for the menu item that selects the tab.
77     */
78    addTab: function(tabId, view, name) {
79      if (!tabId) {
80        throw Error('Must specify a non-false tabId');
81      }
82
83      this.tabIdToView_[tabId] = view;
84
85      // Tab content views start off hidden.
86      view.show(false);
87
88      // Add it to the dropdown menu.
89      var menuItem = addNode(this.dropdownMenu_, 'option');
90      menuItem.value = tabId;
91      menuItem.textContent = name;
92    },
93
94    showMenuItem: function(tabId, isVisible) {
95      var wasActive = this.activeTabId_ == tabId;
96
97      // Hide the menuitem from the list. Note it needs to be 'disabled' to
98      // prevent it being selectable from keyboard.
99      var menuitem = this.getMenuItemNode_(tabId);
100      setNodeDisplay(menuitem, isVisible);
101      menuitem.disabled = !isVisible;
102
103      if (wasActive && !isVisible) {
104        // If the active tab is being hidden in the dropdown menu, then
105        // switch to the first tab which is still visible.
106        for (var i = 0; i < this.dropdownMenu_.options.length; ++i) {
107          var option = this.dropdownMenu_.options[i];
108          if (option.style.display != 'none') {
109            this.switchToTab(option.value);
110            break;
111          }
112        }
113      }
114    },
115
116    getAllTabViews: function() {
117      return this.tabIdToView_;
118    },
119
120    getTabView: function(tabId) {
121      return this.tabIdToView_[tabId];
122    },
123
124    getActiveTabView: function() {
125      return this.tabIdToView_[this.activeTabId_];
126    },
127
128    getActiveTabId: function() {
129      return this.activeTabId_;
130    },
131
132    /**
133     * Changes the currently active tab to |tabId|. This has several effects:
134     *   (1) Replace the tab contents view with that of the new tab.
135     *   (2) Update the dropdown menu's current selection.
136     *   (3) Invoke the optional onTabSwitched callback.
137     */
138    switchToTab: function(tabId) {
139      var newView = this.getTabView(tabId);
140
141      if (!newView) {
142        throw Error('Invalid tabId');
143      }
144
145      var oldTabId = this.activeTabId_;
146      this.activeTabId_ = tabId;
147
148      this.dropdownMenu_.value = tabId;
149
150      // Hide the previously visible tab contents.
151      if (oldTabId)
152        this.getTabView(oldTabId).show(false);
153
154      newView.show(this.isVisible());
155
156      if (this.onTabSwitched_)
157        this.onTabSwitched_(oldTabId, tabId);
158    },
159
160    getMenuItemNode_: function(tabId) {
161      for (var i = 0; i < this.dropdownMenu_.options.length; ++i) {
162        var option = this.dropdownMenu_.options[i];
163        if (option.value == tabId) {
164          return option;
165        }
166      }
167      return null;
168    },
169
170    onMenuSelectionChanged_: function(event) {
171      var tabId = this.dropdownMenu_.value;
172      this.switchToTab(tabId);
173    },
174  };
175
176  return TabSwitcherView;
177})();
178