UNPKG

12.9 kBJavaScriptView Raw
1/**
2 * @license
3 * Copyright 2017 Google Inc.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to deal
7 * in the Software without restriction, including without limitation the rights
8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 * copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 * THE SOFTWARE.
22 */
23import * as tslib_1 from "tslib";
24import { MDCFoundation } from '@material/base/foundation';
25import { cssClasses, strings } from './constants';
26var INTERACTION_EVENTS = ['touchstart', 'mousedown', 'focus'];
27var MDCTabBarScrollerFoundation = /** @class */ (function (_super) {
28 tslib_1.__extends(MDCTabBarScrollerFoundation, _super);
29 function MDCTabBarScrollerFoundation(adapter) {
30 var _this = _super.call(this, tslib_1.__assign({}, MDCTabBarScrollerFoundation.defaultAdapter, adapter)) || this;
31 _this.pointerDownRecognized_ = false;
32 _this.currentTranslateOffset_ = 0;
33 _this.focusedTarget_ = null;
34 _this.layoutFrame_ = 0;
35 _this.scrollFrameScrollLeft_ = 0;
36 _this.forwardIndicatorClickHandler_ = function (evt) { return _this.scrollForward(evt); };
37 _this.backIndicatorClickHandler_ = function (evt) { return _this.scrollBack(evt); };
38 _this.resizeHandler_ = function () { return _this.layout(); };
39 _this.interactionHandler_ = function (evt) {
40 if (evt.type === 'touchstart' || evt.type === 'mousedown') {
41 _this.pointerDownRecognized_ = true;
42 }
43 _this.handlePossibleTabKeyboardFocus_(evt);
44 if (evt.type === 'focus') {
45 _this.pointerDownRecognized_ = false;
46 }
47 };
48 return _this;
49 }
50 Object.defineProperty(MDCTabBarScrollerFoundation, "cssClasses", {
51 get: function () {
52 return cssClasses;
53 },
54 enumerable: true,
55 configurable: true
56 });
57 Object.defineProperty(MDCTabBarScrollerFoundation, "strings", {
58 get: function () {
59 return strings;
60 },
61 enumerable: true,
62 configurable: true
63 });
64 Object.defineProperty(MDCTabBarScrollerFoundation, "defaultAdapter", {
65 get: function () {
66 // tslint:disable:object-literal-sort-keys Methods should be in the same order as the adapter interface.
67 return {
68 addClass: function () { return undefined; },
69 removeClass: function () { return undefined; },
70 eventTargetHasClass: function () { return false; },
71 addClassToForwardIndicator: function () { return undefined; },
72 removeClassFromForwardIndicator: function () { return undefined; },
73 addClassToBackIndicator: function () { return undefined; },
74 removeClassFromBackIndicator: function () { return undefined; },
75 isRTL: function () { return false; },
76 registerBackIndicatorClickHandler: function () { return undefined; },
77 deregisterBackIndicatorClickHandler: function () { return undefined; },
78 registerForwardIndicatorClickHandler: function () { return undefined; },
79 deregisterForwardIndicatorClickHandler: function () { return undefined; },
80 registerCapturedInteractionHandler: function () { return undefined; },
81 deregisterCapturedInteractionHandler: function () { return undefined; },
82 registerWindowResizeHandler: function () { return undefined; },
83 deregisterWindowResizeHandler: function () { return undefined; },
84 getNumberOfTabs: function () { return 0; },
85 getComputedWidthForTabAtIndex: function () { return 0; },
86 getComputedLeftForTabAtIndex: function () { return 0; },
87 getOffsetWidthForScrollFrame: function () { return 0; },
88 getScrollLeftForScrollFrame: function () { return 0; },
89 setScrollLeftForScrollFrame: function () { return undefined; },
90 getOffsetWidthForTabBar: function () { return 0; },
91 setTransformStyleForTabBar: function () { return undefined; },
92 getOffsetLeftForEventTarget: function () { return 0; },
93 getOffsetWidthForEventTarget: function () { return 0; },
94 };
95 // tslint:enable:object-literal-sort-keys
96 },
97 enumerable: true,
98 configurable: true
99 });
100 MDCTabBarScrollerFoundation.prototype.init = function () {
101 var _this = this;
102 this.adapter_.registerBackIndicatorClickHandler(this.backIndicatorClickHandler_);
103 this.adapter_.registerForwardIndicatorClickHandler(this.forwardIndicatorClickHandler_);
104 this.adapter_.registerWindowResizeHandler(this.resizeHandler_);
105 INTERACTION_EVENTS.forEach(function (evtType) {
106 _this.adapter_.registerCapturedInteractionHandler(evtType, _this.interactionHandler_);
107 });
108 this.layout();
109 };
110 MDCTabBarScrollerFoundation.prototype.destroy = function () {
111 var _this = this;
112 this.adapter_.deregisterBackIndicatorClickHandler(this.backIndicatorClickHandler_);
113 this.adapter_.deregisterForwardIndicatorClickHandler(this.forwardIndicatorClickHandler_);
114 this.adapter_.deregisterWindowResizeHandler(this.resizeHandler_);
115 INTERACTION_EVENTS.forEach(function (evtType) {
116 _this.adapter_.deregisterCapturedInteractionHandler(evtType, _this.interactionHandler_);
117 });
118 };
119 MDCTabBarScrollerFoundation.prototype.scrollBack = function (evt) {
120 if (evt) {
121 evt.preventDefault();
122 }
123 var tabWidthAccumulator = 0;
124 var scrollTargetIndex = 0;
125 for (var i = this.adapter_.getNumberOfTabs() - 1; i > 0; i--) {
126 var tabOffsetLeft = this.adapter_.getComputedLeftForTabAtIndex(i);
127 var tabBarWidthLessTabOffsetLeft = this.adapter_.getOffsetWidthForTabBar() - tabOffsetLeft;
128 var tabIsNotOccluded = tabOffsetLeft > this.currentTranslateOffset_;
129 if (this.isRTL_()) {
130 tabIsNotOccluded = tabBarWidthLessTabOffsetLeft > this.currentTranslateOffset_;
131 }
132 if (tabIsNotOccluded) {
133 continue;
134 }
135 tabWidthAccumulator += this.adapter_.getComputedWidthForTabAtIndex(i);
136 var scrollTargetDetermined = tabWidthAccumulator > this.adapter_.getOffsetWidthForScrollFrame();
137 if (scrollTargetDetermined) {
138 scrollTargetIndex = this.isRTL_() ? i + 1 : i;
139 break;
140 }
141 }
142 this.scrollToTabAtIndex(scrollTargetIndex);
143 };
144 MDCTabBarScrollerFoundation.prototype.scrollForward = function (evt) {
145 if (evt) {
146 evt.preventDefault();
147 }
148 var scrollFrameOffsetWidth = this.adapter_.getOffsetWidthForScrollFrame() + this.currentTranslateOffset_;
149 var scrollTargetIndex = 0;
150 for (var i = 0; i < this.adapter_.getNumberOfTabs(); i++) {
151 var tabOffsetLeftAndWidth = this.adapter_.getComputedLeftForTabAtIndex(i) + this.adapter_.getComputedWidthForTabAtIndex(i);
152 var scrollTargetDetermined = tabOffsetLeftAndWidth > scrollFrameOffsetWidth;
153 if (this.isRTL_()) {
154 var frameOffsetAndTabWidth = scrollFrameOffsetWidth - this.adapter_.getComputedWidthForTabAtIndex(i);
155 var tabRightOffset = this.adapter_.getOffsetWidthForTabBar() - tabOffsetLeftAndWidth;
156 scrollTargetDetermined = tabRightOffset > frameOffsetAndTabWidth;
157 }
158 if (scrollTargetDetermined) {
159 scrollTargetIndex = i;
160 break;
161 }
162 }
163 this.scrollToTabAtIndex(scrollTargetIndex);
164 };
165 MDCTabBarScrollerFoundation.prototype.layout = function () {
166 var _this = this;
167 cancelAnimationFrame(this.layoutFrame_);
168 this.scrollFrameScrollLeft_ = this.adapter_.getScrollLeftForScrollFrame();
169 this.layoutFrame_ = requestAnimationFrame(function () { return _this.layout_(); });
170 };
171 MDCTabBarScrollerFoundation.prototype.scrollToTabAtIndex = function (index) {
172 var _this = this;
173 var scrollTargetOffsetLeft = this.adapter_.getComputedLeftForTabAtIndex(index);
174 var scrollTargetOffsetWidth = this.adapter_.getComputedWidthForTabAtIndex(index);
175 this.currentTranslateOffset_ =
176 this.normalizeForRTL_(scrollTargetOffsetLeft, scrollTargetOffsetWidth);
177 requestAnimationFrame(function () { return _this.shiftFrame_(); });
178 };
179 MDCTabBarScrollerFoundation.prototype.layout_ = function () {
180 var frameWidth = this.adapter_.getOffsetWidthForScrollFrame();
181 var isOverflowing = this.adapter_.getOffsetWidthForTabBar() > frameWidth;
182 if (!isOverflowing) {
183 this.currentTranslateOffset_ = 0;
184 }
185 this.shiftFrame_();
186 this.updateIndicatorEnabledStates_();
187 };
188 MDCTabBarScrollerFoundation.prototype.shiftFrame_ = function () {
189 var shiftAmount = this.isRTL_() ?
190 this.currentTranslateOffset_ : -this.currentTranslateOffset_;
191 this.adapter_.setTransformStyleForTabBar("translateX(" + shiftAmount + "px)");
192 this.updateIndicatorEnabledStates_();
193 };
194 MDCTabBarScrollerFoundation.prototype.handlePossibleTabKeyboardFocus_ = function (evt) {
195 var target = evt.target;
196 if (!this.adapter_.eventTargetHasClass(target, cssClasses.TAB) || this.pointerDownRecognized_) {
197 return;
198 }
199 var resetAmt = this.isRTL_() ? this.scrollFrameScrollLeft_ : 0;
200 this.adapter_.setScrollLeftForScrollFrame(resetAmt);
201 this.focusedTarget_ = target;
202 var scrollFrameWidth = this.adapter_.getOffsetWidthForScrollFrame();
203 var tabBarWidth = this.adapter_.getOffsetWidthForTabBar();
204 var leftEdge = this.adapter_.getOffsetLeftForEventTarget(this.focusedTarget_);
205 var rightEdge = leftEdge + this.adapter_.getOffsetWidthForEventTarget(this.focusedTarget_);
206 var shouldScrollBack = rightEdge <= this.currentTranslateOffset_;
207 var shouldScrollForward = rightEdge > this.currentTranslateOffset_ + scrollFrameWidth;
208 if (this.isRTL_()) {
209 var normalizedLeftOffset = tabBarWidth - leftEdge;
210 shouldScrollBack = leftEdge >= tabBarWidth - this.currentTranslateOffset_;
211 shouldScrollForward = normalizedLeftOffset > scrollFrameWidth + this.currentTranslateOffset_;
212 }
213 if (shouldScrollForward) {
214 this.scrollForward();
215 }
216 else if (shouldScrollBack) {
217 this.scrollBack();
218 }
219 this.pointerDownRecognized_ = false;
220 };
221 MDCTabBarScrollerFoundation.prototype.updateIndicatorEnabledStates_ = function () {
222 var INDICATOR_ENABLED = cssClasses.INDICATOR_ENABLED;
223 if (this.currentTranslateOffset_ === 0) {
224 this.adapter_.removeClassFromBackIndicator(INDICATOR_ENABLED);
225 }
226 else {
227 this.adapter_.addClassToBackIndicator(INDICATOR_ENABLED);
228 }
229 var remainingTabBarWidth = this.adapter_.getOffsetWidthForTabBar() - this.currentTranslateOffset_;
230 if (remainingTabBarWidth > this.adapter_.getOffsetWidthForScrollFrame()) {
231 this.adapter_.addClassToForwardIndicator(INDICATOR_ENABLED);
232 }
233 else {
234 this.adapter_.removeClassFromForwardIndicator(INDICATOR_ENABLED);
235 }
236 };
237 MDCTabBarScrollerFoundation.prototype.normalizeForRTL_ = function (left, width) {
238 return this.isRTL_() ? this.adapter_.getOffsetWidthForTabBar() - (left + width) : left;
239 };
240 MDCTabBarScrollerFoundation.prototype.isRTL_ = function () {
241 return this.adapter_.isRTL();
242 };
243 return MDCTabBarScrollerFoundation;
244}(MDCFoundation));
245export { MDCTabBarScrollerFoundation };
246// tslint:disable-next-line:no-default-export Needed for backward compatibility with MDC Web v0.44.0 and earlier.
247export default MDCTabBarScrollerFoundation;
248//# sourceMappingURL=foundation.js.map
\No newline at end of file