Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / third_party / polymer / v1_0 / components-chromium / paper-tabs / paper-tabs-extracted.js
blobaaf1b8f6cb191f217272f243cd50c86a115f46d9
3   Polymer({
5     is: 'paper-tabs',
7     behaviors: [
8       Polymer.IronResizableBehavior,
9       Polymer.IronMenubarBehavior
10     ],
12     properties: {
14       /**
15        * If true, ink ripple effect is disabled.
16        */
17       noink: {
18         type: Boolean,
19         value: false
20       },
22       /**
23        * If true, the bottom bar to indicate the selected tab will not be shown.
24        */
25       noBar: {
26         type: Boolean,
27         value: false
28       },
30       /**
31        * If true, the slide effect for the bottom bar is disabled.
32        */
33       noSlide: {
34         type: Boolean,
35         value: false
36       },
38       /**
39        * If true, tabs are scrollable and the tab width is based on the label width.
40        */
41       scrollable: {
42         type: Boolean,
43         value: false
44       },
46       /**
47        * If true, dragging on the tabs to scroll is disabled.
48        */
49       disableDrag: {
50         type: Boolean,
51         value: false
52       },
54       /**
55        * If true, scroll buttons (left/right arrow) will be hidden for scrollable tabs.
56        */
57       hideScrollButtons: {
58         type: Boolean,
59         value: false
60       },
62       /**
63        * If true, the tabs are aligned to bottom (the selection bar appears at the top).
64        */
65       alignBottom: {
66         type: Boolean,
67         value: false
68       },
70       /**
71        * Gets or sets the selected element. The default is to use the index of the item.
72        */
73       selected: {
74         type: String,
75         notify: true
76       },
78       selectable: {
79         type: String,
80         value: 'paper-tab'
81       },
83       _step: {
84         type: Number,
85         value: 10
86       },
88       _holdDelay: {
89         type: Number,
90         value: 1
91       },
93       _leftHidden: {
94         type: Boolean,
95         value: false
96       },
98       _rightHidden: {
99         type: Boolean,
100         value: false
101       },
103       _previousTab: {
104         type: Object
105       }
106     },
108     hostAttributes: {
109       role: 'tablist'
110     },
112     listeners: {
113       'iron-resize': '_onResize',
114       'iron-select': '_onIronSelect',
115       'iron-deselect': '_onIronDeselect'
116     },
118     _computeScrollButtonClass: function(hideThisButton, scrollable, hideScrollButtons) {
119       if (!scrollable || hideScrollButtons) {
120         return 'hidden';
121       }
123       if (hideThisButton) {
124         return 'not-visible';
125       }
127       return '';
128     },
130     _computeTabsContentClass: function(scrollable) {
131       return scrollable ? 'scrollable' : 'horizontal layout';
132     },
134     _computeSelectionBarClass: function(noBar, alignBottom) {
135       if (noBar) {
136         return 'hidden';
137       } else if (alignBottom) {
138         return 'align-bottom';
139       }
140     },
142     // TODO(cdata): Add `track` response back in when gesture lands.
144     _onResize: function() {
145       this.debounce('_onResize', function() {
146         this._scroll();
147         this._tabChanged(this.selectedItem);
148       }, 10);
149     },
151     _onIronSelect: function(event) {
152       this._tabChanged(event.detail.item, this._previousTab);
153       this._previousTab = event.detail.item;
154       this.cancelDebouncer('tab-changed');
155     },
157     _onIronDeselect: function(event) {
158       this.debounce('tab-changed', function() {
159         this._tabChanged(null, this._previousTab);
160       // See polymer/polymer#1305
161       }, 1);
162     },
164     get _tabContainerScrollSize () {
165       return Math.max(
166         0,
167         this.$.tabsContainer.scrollWidth -
168           this.$.tabsContainer.offsetWidth
169       );
170     },
172     _scroll: function() {
173       var scrollLeft;
175       if (!this.scrollable) {
176         return;
177       }
179       scrollLeft = this.$.tabsContainer.scrollLeft;
181       this._leftHidden = scrollLeft === 0;
182       this._rightHidden = scrollLeft === this._tabContainerScrollSize;
183     },
185     _onLeftScrollButtonDown: function() {
186       this._holdJob = setInterval(this._scrollToLeft.bind(this), this._holdDelay);
187     },
189     _onRightScrollButtonDown: function() {
190       this._holdJob = setInterval(this._scrollToRight.bind(this), this._holdDelay);
191     },
193     _onScrollButtonUp: function() {
194       clearInterval(this._holdJob);
195       this._holdJob = null;
196     },
198     _scrollToLeft: function() {
199       this.$.tabsContainer.scrollLeft -= this._step;
200     },
202     _scrollToRight: function() {
203       this.$.tabsContainer.scrollLeft += this._step;
204     },
206     _tabChanged: function(tab, old) {
207       if (!tab) {
208         this._positionBar(0, 0);
209         return;
210       }
212       var r = this.$.tabsContent.getBoundingClientRect();
213       var w = r.width;
214       var tabRect = tab.getBoundingClientRect();
215       var tabOffsetLeft = tabRect.left - r.left;
217       this._pos = {
218         width: this._calcPercent(tabRect.width, w),
219         left: this._calcPercent(tabOffsetLeft, w)
220       };
222       if (this.noSlide || old == null) {
223         // position bar directly without animation
224         this._positionBar(this._pos.width, this._pos.left);
225         return;
226       }
228       var oldRect = old.getBoundingClientRect();
229       var oldIndex = this.items.indexOf(old);
230       var index = this.items.indexOf(tab);
231       var m = 5;
233       // bar animation: expand
234       this.$.selectionBar.classList.add('expand');
236       if (oldIndex < index) {
237         this._positionBar(this._calcPercent(tabRect.left + tabRect.width - oldRect.left, w) - m,
238             this._left);
239       } else {
240         this._positionBar(this._calcPercent(oldRect.left + oldRect.width - tabRect.left, w) - m,
241             this._calcPercent(tabOffsetLeft, w) + m);
242       }
244       if (this.scrollable) {
245         this._scrollToSelectedIfNeeded(tabRect.width, tabOffsetLeft);
246       }
247     },
249     _scrollToSelectedIfNeeded: function(tabWidth, tabOffsetLeft) {
250       var l = tabOffsetLeft - this.$.tabsContainer.scrollLeft;
251       if (l < 0) {
252         this.$.tabsContainer.scrollLeft += l;
253       } else {
254         l += (tabWidth - this.$.tabsContainer.offsetWidth);
255         if (l > 0) {
256           this.$.tabsContainer.scrollLeft += l;
257         }
258       }
259     },
261     _calcPercent: function(w, w0) {
262       return 100 * w / w0;
263     },
265     _positionBar: function(width, left) {
266       width = width || 0;
267       left = left || 0;
269       this._width = width;
270       this._left = left;
271       this.transform(
272           'translate3d(' + left + '%, 0, 0) scaleX(' + (width / 100) + ')',
273           this.$.selectionBar);
274     },
276     _onBarTransitionEnd: function(e) {
277       var cl = this.$.selectionBar.classList;
278       // bar animation: expand -> contract
279       if (cl.contains('expand')) {
280         cl.remove('expand');
281         cl.add('contract');
282         this._positionBar(this._pos.width, this._pos.left);
283       // bar animation done
284       } else if (cl.contains('contract')) {
285         cl.remove('contract');
286       }
287     }
289   });