| OLD | NEW |
| (Empty) |
| 1 <!-- | |
| 2 Copyright (c) 2014 The Polymer Project Authors. All rights reserved. | |
| 3 This code may only be used under the BSD style license found at http://polymer.g
ithub.io/LICENSE.txt | |
| 4 The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt | |
| 5 The complete set of contributors may be found at http://polymer.github.io/CONTRI
BUTORS.txt | |
| 6 Code distributed by Google as part of the polymer project is also | |
| 7 subject to an additional IP rights grant found at http://polymer.github.io/PATEN
TS.txt | |
| 8 --> | |
| 9 | |
| 10 <!-- | |
| 11 `paper-tabs` is a `core-selector` styled to look like tabs. Tabs make it easy to
| |
| 12 explore and switch between different views or functional aspects of an app, or | |
| 13 to browse categorized data sets. | |
| 14 | |
| 15 Use `selected` property to get or set the selected tab. | |
| 16 | |
| 17 Example: | |
| 18 | |
| 19 <paper-tabs selected="0"> | |
| 20 <paper-tab>TAB 1</paper-tab> | |
| 21 <paper-tab>TAB 2</paper-tab> | |
| 22 <paper-tab>TAB 3</paper-tab> | |
| 23 </paper-tabs> | |
| 24 | |
| 25 See <a href="#paper-tab">paper-tab</a> for more information about | |
| 26 `paper-tab`. | |
| 27 | |
| 28 A common usage for `paper-tabs` is to use it along with `core-pages` to switch | |
| 29 between different views. | |
| 30 | |
| 31 <paper-tabs selected="{{selected}}"> | |
| 32 <paper-tab>Tab 1</paper-tab> | |
| 33 <paper-tab>Tab 2</paper-tab> | |
| 34 <paper-tab>Tab 3</paper-tab> | |
| 35 </paper-tabs> | |
| 36 | |
| 37 <core-pages selected="{{selected}}"> | |
| 38 <div>Page 1</div> | |
| 39 <div>Page 2</div> | |
| 40 <div>Page 3</div> | |
| 41 </core-pages> | |
| 42 | |
| 43 `paper-tabs` adapt to mobile/narrow layout when there is a `core-narrow` class s
et | |
| 44 on itself or any of its ancestors. | |
| 45 | |
| 46 To use links in tabs, add `link` attribute to `paper-tabs` and put an `<a>` | |
| 47 element in `paper-tab`. | |
| 48 | |
| 49 Example: | |
| 50 | |
| 51 <paper-tabs selected="0" link> | |
| 52 <paper-tab> | |
| 53 <a href="#link1" horizontal center-center layout>TAB ONE</a> | |
| 54 </paper-tab> | |
| 55 <paper-tab> | |
| 56 <a href="#link2" horizontal center-center layout>TAB TWO</a> | |
| 57 </paper-tab> | |
| 58 <paper-tab> | |
| 59 <a href="#link3" horizontal center-center layout>TAB THREE</a> | |
| 60 </paper-tab> | |
| 61 </paper-tabs> | |
| 62 | |
| 63 Styling tabs: | |
| 64 | |
| 65 To change the sliding bar color: | |
| 66 | |
| 67 paper-tabs.pink::shadow #selectionBar { | |
| 68 background-color: #ff4081; | |
| 69 } | |
| 70 | |
| 71 To change the ink ripple color: | |
| 72 | |
| 73 paper-tabs.pink paper-tab::shadow #ink { | |
| 74 color: #ff4081; | |
| 75 } | |
| 76 | |
| 77 @group Paper Elements | |
| 78 @element paper-tabs | |
| 79 @extends core-selector | |
| 80 @homepage github.io | |
| 81 --> | |
| 82 | |
| 83 <link rel="import" href="../core-selector/core-selector.html"> | |
| 84 <link rel="import" href="../paper-icon-button/paper-icon-button.html"> | |
| 85 <link rel="import" href="../core-resizable/core-resizable.html"> | |
| 86 <link rel="import" href="paper-tab.html"> | |
| 87 | |
| 88 <polymer-element name="paper-tabs" extends="core-selector" attributes="noink nob
ar noslide scrollable hideScrollButton" role="tablist" horizontal center layout> | |
| 89 <template> | |
| 90 | |
| 91 <link rel="stylesheet" href="paper-tabs.css"> | |
| 92 | |
| 93 <div class="scroll-button" hidden?="{{!scrollable || hideScrollButton}}"> | |
| 94 <paper-icon-button icon="chevron-left" class="{{ {hidden: leftHidden} | toke
nList }}" on-down="{{holdLeft}}" on-up="{{releaseHold}}"></paper-icon-button> | |
| 95 </div> | |
| 96 | |
| 97 <div id="tabsContainer" class="{{ {scrollable: scrollable} | tokenList }}" fle
x on-scroll="{{scroll}}" on-trackstart="{{trackStart}}"> | |
| 98 | |
| 99 <div id="tabsContent" horizontal layout?="{{!scrollable}}"> | |
| 100 <shadow></shadow> | |
| 101 <div id="selectionBar" hidden?="{{nobar}}" on-transitionend="{{barTransiti
onEnd}}"></div> | |
| 102 </div> | |
| 103 | |
| 104 </div> | |
| 105 | |
| 106 <div class="scroll-button" hidden?="{{!scrollable || hideScrollButton}}"> | |
| 107 <paper-icon-button icon="chevron-right" class="{{ {hidden: rightHidden} | to
kenList }}" on-down="{{holdRight}}" on-up="{{releaseHold}}"></paper-icon-button> | |
| 108 </div> | |
| 109 | |
| 110 </template> | |
| 111 <script> | |
| 112 | |
| 113 Polymer(Polymer.mixin({ | |
| 114 | |
| 115 /** | |
| 116 * If true, ink ripple effect is disabled. | |
| 117 * | |
| 118 * @attribute noink | |
| 119 * @type boolean | |
| 120 * @default false | |
| 121 */ | |
| 122 noink: false, | |
| 123 | |
| 124 /** | |
| 125 * If true, the bottom bar to indicate the selected tab will not be shown. | |
| 126 * | |
| 127 * @attribute nobar | |
| 128 * @type boolean | |
| 129 * @default false | |
| 130 */ | |
| 131 nobar: false, | |
| 132 | |
| 133 /** | |
| 134 * If true, the slide effect for the bottom bar is disabled. | |
| 135 * | |
| 136 * @attribute noslide | |
| 137 * @type boolean | |
| 138 * @default false | |
| 139 */ | |
| 140 noslide: false, | |
| 141 | |
| 142 /** | |
| 143 * If true, tabs are scrollable and the tab width is based on the label widt
h. | |
| 144 * | |
| 145 * @attribute scrollable | |
| 146 * @type boolean | |
| 147 * @default false | |
| 148 */ | |
| 149 scrollable: false, | |
| 150 | |
| 151 /** | |
| 152 * If true, dragging on the tabs to scroll is disabled. | |
| 153 * | |
| 154 * @attribute disableDrag | |
| 155 * @type boolean | |
| 156 * @default false | |
| 157 */ | |
| 158 disableDrag: false, | |
| 159 | |
| 160 /** | |
| 161 * If true, scroll buttons (left/right arrow) will be hidden for scrollable
tabs. | |
| 162 * | |
| 163 * @attribute hideScrollButton | |
| 164 * @type boolean | |
| 165 * @default false | |
| 166 */ | |
| 167 hideScrollButton: false, | |
| 168 | |
| 169 eventDelegates: { | |
| 170 'core-resize': 'resizeHandler' | |
| 171 }, | |
| 172 | |
| 173 activateEvent: 'tap', | |
| 174 | |
| 175 step: 10, | |
| 176 | |
| 177 holdDelay: 10, | |
| 178 | |
| 179 ready: function() { | |
| 180 this.super(); | |
| 181 this._trackxHandler = this.trackx.bind(this); | |
| 182 Polymer.addEventListener(this.$.tabsContainer, 'trackx', this._trackxHandl
er); | |
| 183 this._tabsObserver = new MutationObserver(this.updateBar.bind(this)); | |
| 184 }, | |
| 185 | |
| 186 domReady: function() { | |
| 187 this.async('resizeHandler'); | |
| 188 this._tabsObserver.observe(this, {childList: true, subtree: true, characte
rData: true}); | |
| 189 }, | |
| 190 | |
| 191 attached: function() { | |
| 192 this.resizableAttachedHandler(); | |
| 193 }, | |
| 194 | |
| 195 detached: function() { | |
| 196 Polymer.removeEventListener(this.$.tabsContainer, 'trackx', this._trackxHa
ndler); | |
| 197 this._tabsObserver.disconnect(); | |
| 198 this.resizableDetachedHandler(); | |
| 199 }, | |
| 200 | |
| 201 trackStart: function(e) { | |
| 202 if (!this.scrollable || this.disableDrag) { | |
| 203 return; | |
| 204 } | |
| 205 var t = e.target; | |
| 206 if (t && t.cancelRipple) { | |
| 207 t.cancelRipple(); | |
| 208 } | |
| 209 this._startx = this.$.tabsContainer.scrollLeft; | |
| 210 e.preventTap(); | |
| 211 }, | |
| 212 | |
| 213 trackx: function(e) { | |
| 214 if (!this.scrollable || this.disableDrag) { | |
| 215 return; | |
| 216 } | |
| 217 this.$.tabsContainer.scrollLeft = this._startx - e.dx; | |
| 218 }, | |
| 219 | |
| 220 resizeHandler: function() { | |
| 221 this.scroll(); | |
| 222 this.updateBar(); | |
| 223 }, | |
| 224 | |
| 225 scroll: function() { | |
| 226 if (!this.scrollable) { | |
| 227 return; | |
| 228 } | |
| 229 var tc = this.$.tabsContainer; | |
| 230 var l = tc.scrollLeft; | |
| 231 this.leftHidden = l === 0; | |
| 232 this.rightHidden = l === (tc.scrollWidth - tc.clientWidth); | |
| 233 }, | |
| 234 | |
| 235 holdLeft: function() { | |
| 236 this.holdJob = setInterval(this.scrollToLeft.bind(this), this.holdDelay); | |
| 237 }, | |
| 238 | |
| 239 holdRight: function() { | |
| 240 this.holdJob = setInterval(this.scrollToRight.bind(this), this.holdDelay); | |
| 241 }, | |
| 242 | |
| 243 releaseHold: function() { | |
| 244 clearInterval(this.holdJob); | |
| 245 this.holdJob = null; | |
| 246 }, | |
| 247 | |
| 248 scrollToLeft: function() { | |
| 249 this.$.tabsContainer.scrollLeft -= this.step; | |
| 250 }, | |
| 251 | |
| 252 scrollToRight: function() { | |
| 253 this.$.tabsContainer.scrollLeft += this.step; | |
| 254 }, | |
| 255 | |
| 256 /** | |
| 257 * Invoke this to update the size and position of the bottom bar. Usually | |
| 258 * you only need to call this if the `paper-tabs` is initially hidden and | |
| 259 * later becomes visible. | |
| 260 * | |
| 261 * @method updateBar | |
| 262 */ | |
| 263 updateBar: function() { | |
| 264 this.async('selectedItemChanged'); | |
| 265 }, | |
| 266 | |
| 267 selectedItemChanged: function(old) { | |
| 268 var oldIndex = this.selectedIndex; | |
| 269 this.super(arguments); | |
| 270 var s = this.$.selectionBar.style; | |
| 271 | |
| 272 if (!this.selectedItem) { | |
| 273 s.width = 0; | |
| 274 s.left = 0; | |
| 275 return; | |
| 276 } | |
| 277 | |
| 278 var r = this.$.tabsContent.getBoundingClientRect(); | |
| 279 this._w = r.width; | |
| 280 this._l = r.left; | |
| 281 | |
| 282 r = this.selectedItem.getBoundingClientRect(); | |
| 283 this._sw = r.width; | |
| 284 this._sl = r.left; | |
| 285 this._sOffsetLeft = this._sl - this._l; | |
| 286 | |
| 287 if (this.noslide || old == null) { | |
| 288 this.positionBarForSelected(); | |
| 289 return; | |
| 290 } | |
| 291 | |
| 292 var oldRect = old.getBoundingClientRect(); | |
| 293 | |
| 294 var m = 5; | |
| 295 this.$.selectionBar.classList.add('expand'); | |
| 296 if (oldIndex < this.selectedIndex) { | |
| 297 s.width = this.calcPercent(this._sl + this._sw - oldRect.left) - m + '%'
; | |
| 298 this._transitionCounter = 1; | |
| 299 } else { | |
| 300 s.width = this.calcPercent(oldRect.left + oldRect.width - this._sl) - m
+ '%'; | |
| 301 s.left = this.calcPercent(this._sOffsetLeft) + m + '%'; | |
| 302 this._transitionCounter = 2; | |
| 303 } | |
| 304 if (this.scrollable) { | |
| 305 this.scrollToSelectedIfNeeded(); | |
| 306 } | |
| 307 }, | |
| 308 | |
| 309 scrollToSelectedIfNeeded: function() { | |
| 310 var scrollLeft = this.$.tabsContainer.scrollLeft; | |
| 311 // scroll to selected if needed | |
| 312 if (this._sOffsetLeft + this._sw < scrollLeft || | |
| 313 this._sOffsetLeft - scrollLeft > this.$.tabsContainer.offsetWidth) { | |
| 314 this.$.tabsContainer.scrollLeft = this._sOffsetLeft; | |
| 315 } | |
| 316 }, | |
| 317 | |
| 318 positionBarForSelected: function() { | |
| 319 var s = this.$.selectionBar.style; | |
| 320 s.width = this.calcPercent(this._sw) + '%'; | |
| 321 s.left = this.calcPercent(this._sOffsetLeft) + '%'; | |
| 322 }, | |
| 323 | |
| 324 calcPercent: function(w) { | |
| 325 return 100 * w / this._w; | |
| 326 }, | |
| 327 | |
| 328 barTransitionEnd: function(e) { | |
| 329 this._transitionCounter--; | |
| 330 var cl = this.$.selectionBar.classList; | |
| 331 if (cl.contains('expand') && !this._transitionCounter) { | |
| 332 cl.remove('expand'); | |
| 333 cl.add('contract'); | |
| 334 this.positionBarForSelected(); | |
| 335 } else if (cl.contains('contract')) { | |
| 336 cl.remove('contract'); | |
| 337 } | |
| 338 } | |
| 339 | |
| 340 }, Polymer.CoreResizable)); | |
| 341 | |
| 342 </script> | |
| 343 </polymer-element> | |
| OLD | NEW |