blob: 110997b0e45a06ce4b684078f74c272e1594b1ed [file] [log] [blame]
Copybara botbe50d492023-11-30 00:16:42 +01001/**
2 * @license
3 * Copyright 2015 Google Inc. All Rights Reserved.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18(function() {
19 'use strict';
20
21 /**
22 * Class constructor for Tabs MDL component.
23 * Implements MDL component design pattern defined at:
24 * https://github.com/jasonmayes/mdl-component-design-pattern
25 *
26 * @constructor
27 * @param {Element} element The element that will be upgraded.
28 */
29 var MaterialTabs = function MaterialTabs(element) {
30 // Stores the HTML element.
31 this.element_ = element;
32
33 // Initialize instance.
34 this.init();
35 };
36 window['MaterialTabs'] = MaterialTabs;
37
38 /**
39 * Store constants in one place so they can be updated easily.
40 *
41 * @enum {string}
42 * @private
43 */
44 MaterialTabs.prototype.Constant_ = {
45 // None at the moment.
46 };
47
48 /**
49 * Store strings for class names defined by this component that are used in
50 * JavaScript. This allows us to simply change it in one place should we
51 * decide to modify at a later date.
52 *
53 * @enum {string}
54 * @private
55 */
56 MaterialTabs.prototype.CssClasses_ = {
57 TAB_CLASS: 'mdl-tabs__tab',
58 PANEL_CLASS: 'mdl-tabs__panel',
59 ACTIVE_CLASS: 'is-active',
60 UPGRADED_CLASS: 'is-upgraded',
61
62 MDL_JS_RIPPLE_EFFECT: 'mdl-js-ripple-effect',
63 MDL_RIPPLE_CONTAINER: 'mdl-tabs__ripple-container',
64 MDL_RIPPLE: 'mdl-ripple',
65 MDL_JS_RIPPLE_EFFECT_IGNORE_EVENTS: 'mdl-js-ripple-effect--ignore-events'
66 };
67
68 /**
69 * Handle clicks to a tabs component
70 *
71 * @private
72 */
73 MaterialTabs.prototype.initTabs_ = function() {
74 if (this.element_.classList.contains(this.CssClasses_.MDL_JS_RIPPLE_EFFECT)) {
75 this.element_.classList.add(
76 this.CssClasses_.MDL_JS_RIPPLE_EFFECT_IGNORE_EVENTS);
77 }
78
79 // Select element tabs, document panels
80 this.tabs_ = this.element_.querySelectorAll('.' + this.CssClasses_.TAB_CLASS);
81 this.panels_ =
82 this.element_.querySelectorAll('.' + this.CssClasses_.PANEL_CLASS);
83
84 // Create new tabs for each tab element
85 for (var i = 0; i < this.tabs_.length; i++) {
86 new MaterialTab(this.tabs_[i], this);
87 }
88
89 this.element_.classList.add(this.CssClasses_.UPGRADED_CLASS);
90 };
91
92 /**
93 * Reset tab state, dropping active classes
94 *
95 * @private
96 */
97 MaterialTabs.prototype.resetTabState_ = function() {
98 for (var k = 0; k < this.tabs_.length; k++) {
99 this.tabs_[k].classList.remove(this.CssClasses_.ACTIVE_CLASS);
100 }
101 };
102
103 /**
104 * Reset panel state, droping active classes
105 *
106 * @private
107 */
108 MaterialTabs.prototype.resetPanelState_ = function() {
109 for (var j = 0; j < this.panels_.length; j++) {
110 this.panels_[j].classList.remove(this.CssClasses_.ACTIVE_CLASS);
111 }
112 };
113
114 /**
115 * Initialize element.
116 */
117 MaterialTabs.prototype.init = function() {
118 if (this.element_) {
119 this.initTabs_();
120 }
121 };
122
123 /**
124 * Constructor for an individual tab.
125 *
126 * @constructor
127 * @param {Element} tab The HTML element for the tab.
128 * @param {MaterialTabs} ctx The MaterialTabs object that owns the tab.
129 */
130 function MaterialTab(tab, ctx) {
131 if (tab) {
132 if (ctx.element_.classList.contains(ctx.CssClasses_.MDL_JS_RIPPLE_EFFECT)) {
133 var rippleContainer = document.createElement('span');
134 rippleContainer.classList.add(ctx.CssClasses_.MDL_RIPPLE_CONTAINER);
135 rippleContainer.classList.add(ctx.CssClasses_.MDL_JS_RIPPLE_EFFECT);
136 var ripple = document.createElement('span');
137 ripple.classList.add(ctx.CssClasses_.MDL_RIPPLE);
138 rippleContainer.appendChild(ripple);
139 tab.appendChild(rippleContainer);
140 }
141
142 tab.addEventListener('click', function(e) {
143 if (tab.getAttribute('href').charAt(0) === '#') {
144 e.preventDefault();
145 var href = tab.href.split('#')[1];
146 var panel = ctx.element_.querySelector('#' + href);
147 ctx.resetTabState_();
148 ctx.resetPanelState_();
149 tab.classList.add(ctx.CssClasses_.ACTIVE_CLASS);
150 panel.classList.add(ctx.CssClasses_.ACTIVE_CLASS);
151 }
152 });
153
154 }
155 }
156
157 // The component registers itself. It can assume componentHandler is available
158 // in the global scope.
159 componentHandler.register({
160 constructor: MaterialTabs,
161 classAsString: 'MaterialTabs',
162 cssClass: 'mdl-js-tabs'
163 });
164})();