Add an exponential backoff to rechecking the app list doodle.
[chromium-blink-merge.git] / third_party / polymer / components-chromium / paper-tabs / paper-tabs-extracted.js
blob6567715dc38a52f7d0dca7c634be9e047d93a045
3   Polymer('paper-tabs',Polymer.mixin({
4     
5     /**
6      * If true, ink ripple effect is disabled.
7      *
8      * @attribute noink
9      * @type boolean
10      * @default false
11      */
12     noink: false,
13     
14     /**
15      * If true, the bottom bar to indicate the selected tab will not be shown.
16      *
17      * @attribute nobar
18      * @type boolean
19      * @default false
20      */
21     nobar: false,
22     
23     /**
24      * If true, the slide effect for the bottom bar is disabled.
25      *
26      * @attribute noslide
27      * @type boolean
28      * @default false
29      */
30     noslide: false,
31     
32     /**
33      * If true, tabs are scrollable and the tab width is based on the label width.
34      *
35      * @attribute scrollable
36      * @type boolean
37      * @default false
38      */
39     scrollable: false,
40     
41     /**
42      * If true, dragging on the tabs to scroll is disabled.
43      *
44      * @attribute disableDrag
45      * @type boolean
46      * @default false
47      */
48     disableDrag: false,
49     
50     /**
51      * If true, scroll buttons (left/right arrow) will be hidden for scrollable tabs.
52      *
53      * @attribute hideScrollButton
54      * @type boolean
55      * @default false
56      */
57     hideScrollButton: false,
59     eventDelegates: {
60       'core-resize': 'resizeHandler'
61     },
62     
63     activateEvent: 'tap',
64     
65     step: 10,
66     
67     holdDelay: 10,
68     
69     ready: function() {
70       this.super();
71       this._trackxHandler = this.trackx.bind(this);
72       Polymer.addEventListener(this.$.tabsContainer, 'trackx', this._trackxHandler);
73       this._tabsObserver = new MutationObserver(this.updateBar.bind(this));
74     },
75     
76     domReady: function() {
77       this.async('resizeHandler');
78       this._tabsObserver.observe(this, {childList: true, subtree: true, characterData: true});
79     },
81     attached: function() {
82       this.resizableAttachedHandler();
83     },
84     
85     detached: function() {
86       Polymer.removeEventListener(this.$.tabsContainer, 'trackx', this._trackxHandler);
87       this._tabsObserver.disconnect();
88       this.resizableDetachedHandler();
89     },
90     
91     trackStart: function(e) {
92       if (!this.scrollable || this.disableDrag) {
93         return;
94       }
95       var t = e.target;
96       if (t && t.cancelRipple) {
97         t.cancelRipple();
98       }
99       this._startx = this.$.tabsContainer.scrollLeft;
100       e.preventTap();
101     },
102     
103     trackx: function(e) {
104       if (!this.scrollable || this.disableDrag) {
105         return;
106       }
107       this.$.tabsContainer.scrollLeft = this._startx - e.dx;
108     },
109     
110     resizeHandler: function() {
111       this.scroll();
112       this.updateBar();
113     },
114     
115     scroll: function() {
116       if (!this.scrollable) {
117         return;
118       }
119       var tc = this.$.tabsContainer;
120       var l = tc.scrollLeft;
121       this.leftHidden = l === 0;
122       this.rightHidden = l === (tc.scrollWidth - tc.clientWidth);
123     },
124     
125     holdLeft: function() {
126       this.holdJob = setInterval(this.scrollToLeft.bind(this), this.holdDelay);
127     },
128     
129     holdRight: function() {
130       this.holdJob = setInterval(this.scrollToRight.bind(this), this.holdDelay);
131     },
132     
133     releaseHold: function() {
134       clearInterval(this.holdJob);
135       this.holdJob = null;
136     },
137     
138     scrollToLeft: function() {
139       this.$.tabsContainer.scrollLeft -= this.step;
140     },
141     
142     scrollToRight: function() {
143       this.$.tabsContainer.scrollLeft += this.step;
144     },
145     
146     /**
147      * Invoke this to update the size and position of the bottom bar.  Usually
148      * you only need to call this if the `paper-tabs` is initially hidden and
149      * later becomes visible.
150      *
151      * @method updateBar
152      */
153     updateBar: function() {
154       this.async('selectedItemChanged');
155     },
156     
157     selectedItemChanged: function(old) {
158       var oldIndex = this.selectedIndex;
159       this.super(arguments);
160       var s = this.$.selectionBar.style;
161       
162       if (!this.selectedItem) {
163         s.width = 0;
164         s.left = 0;
165         return;
166       } 
167       
168       var r = this.$.tabsContent.getBoundingClientRect();
169       this._w = r.width;
170       this._l = r.left;
171       
172       r = this.selectedItem.getBoundingClientRect();
173       this._sw = r.width;
174       this._sl = r.left;
175       this._sOffsetLeft = this._sl - this._l; 
176       
177       if (this.noslide || old == null) {
178         this.positionBarForSelected();
179         return;
180       }
181       
182       var oldRect = old.getBoundingClientRect();
183       
184       var m = 5;
185       this.$.selectionBar.classList.add('expand');
186       if (oldIndex < this.selectedIndex) {
187         s.width = this.calcPercent(this._sl + this._sw - oldRect.left) - m + '%';
188         this._transitionCounter = 1;
189       } else {
190         s.width = this.calcPercent(oldRect.left + oldRect.width - this._sl) - m + '%';
191         s.left = this.calcPercent(this._sOffsetLeft) + m + '%';
192         this._transitionCounter = 2;
193       }
194       if (this.scrollable) {
195         this.scrollToSelectedIfNeeded();
196       }
197     },
198     
199     scrollToSelectedIfNeeded: function() {
200       var scrollLeft = this.$.tabsContainer.scrollLeft;
201       // scroll to selected if needed
202       if (this._sOffsetLeft + this._sw < scrollLeft || 
203           this._sOffsetLeft - scrollLeft > this.$.tabsContainer.offsetWidth) {
204         this.$.tabsContainer.scrollLeft = this._sOffsetLeft;
205       }
206     },
207     
208     positionBarForSelected: function() {
209       var s = this.$.selectionBar.style;
210       s.width = this.calcPercent(this._sw) + '%';
211       s.left = this.calcPercent(this._sOffsetLeft) + '%';
212     },
213     
214     calcPercent: function(w) {
215       return 100 * w / this._w;
216     },
217     
218     barTransitionEnd: function(e) {
219       this._transitionCounter--;
220       var cl = this.$.selectionBar.classList;
221       if (cl.contains('expand') && !this._transitionCounter) {
222         cl.remove('expand');
223         cl.add('contract');
224         this.positionBarForSelected();
225       } else if (cl.contains('contract')) {
226         cl.remove('contract');
227       }
228     }
229     
230   }, Polymer.CoreResizable));
231