3 * Copyright(c) 2006-2010 Sencha Inc.
5 * http://www.sencha.com/license
8 * @class Ext.layout.boxOverflow.Scroller
9 * @extends Ext.layout.boxOverflow.None
12 Ext.layout.boxOverflow.Scroller = Ext.extend(Ext.layout.boxOverflow.None, {
16 * True to animate the scrolling of items within the layout (defaults to true, ignored if enableScroll is false)
21 * @cfg scrollIncrement
23 * The number of pixels to scroll by on scroller click (defaults to 100)
30 * The number of pixels to increment on mouse wheel scrolling (defaults to <tt>3</tt>).
35 * @cfg scrollRepeatInterval
37 * Number of milliseconds between each scroll while a scroller button is held down (defaults to 400)
39 scrollRepeatInterval: 400,
44 * Number of seconds that each scroll animation lasts (defaults to 0.4)
51 * CSS class added to the beforeCt element. This is the element that holds any special items such as scrollers,
52 * which must always be present at the leftmost edge of the Container
54 beforeCls: 'x-strip-left',
59 * CSS class added to the afterCt element. This is the element that holds any special items such as scrollers,
60 * which must always be present at the rightmost edge of the Container
62 afterCls: 'x-strip-right',
67 * CSS class added to both scroller elements if enableScroll is used
69 scrollerCls: 'x-strip-scroller',
72 * @cfg beforeScrollerCls
74 * CSS class added to the left scroller element if enableScroll is used
76 beforeScrollerCls: 'x-strip-scroller-left',
79 * @cfg afterScrollerCls
81 * CSS class added to the right scroller element if enableScroll is used
83 afterScrollerCls: 'x-strip-scroller-right',
87 * Sets up an listener to scroll on the layout's innerCt mousewheel event
89 createWheelListener: function() {
90 this.layout.innerCt.on({
92 mousewheel: function(e) {
95 this.scrollBy(e.getWheelDelta() * this.wheelIncrement * -1, false);
102 * Most of the heavy lifting is done in the subclasses
104 handleOverflow: function(calculations, targetSize) {
105 this.createInnerElements();
106 this.showScrollers();
112 clearOverflow: function() {
113 this.hideScrollers();
118 * Shows the scroller elements in the beforeCt and afterCt. Creates the scrollers first if they are not already
121 showScrollers: function() {
122 this.createScrollers();
124 this.beforeScroller.show();
125 this.afterScroller.show();
127 this.updateScrollButtons();
132 * Hides the scroller elements in the beforeCt and afterCt
134 hideScrollers: function() {
135 if (this.beforeScroller != undefined) {
136 this.beforeScroller.hide();
137 this.afterScroller.hide();
143 * Creates the clickable scroller elements and places them into the beforeCt and afterCt
145 createScrollers: function() {
146 if (!this.beforeScroller && !this.afterScroller) {
147 var before = this.beforeCt.createChild({
148 cls: String.format("{0} {1} ", this.scrollerCls, this.beforeScrollerCls)
151 var after = this.afterCt.createChild({
152 cls: String.format("{0} {1}", this.scrollerCls, this.afterScrollerCls)
155 before.addClassOnOver(this.beforeScrollerCls + '-hover');
156 after.addClassOnOver(this.afterScrollerCls + '-hover');
158 before.setVisibilityMode(Ext.Element.DISPLAY);
159 after.setVisibilityMode(Ext.Element.DISPLAY);
161 this.beforeRepeater = new Ext.util.ClickRepeater(before, {
162 interval: this.scrollRepeatInterval,
163 handler : this.scrollLeft,
167 this.afterRepeater = new Ext.util.ClickRepeater(after, {
168 interval: this.scrollRepeatInterval,
169 handler : this.scrollRight,
174 * @property beforeScroller
176 * The left scroller element. Only created when needed.
178 this.beforeScroller = before;
181 * @property afterScroller
183 * The left scroller element. Only created when needed.
185 this.afterScroller = after;
192 destroy: function() {
193 Ext.destroy(this.beforeScroller, this.afterScroller, this.beforeRepeater, this.afterRepeater, this.beforeCt, this.afterCt);
198 * Scrolls left or right by the number of pixels specified
199 * @param {Number} delta Number of pixels to scroll to the right by. Use a negative number to scroll left
201 scrollBy: function(delta, animate) {
202 this.scrollTo(this.getScrollPosition() + delta, animate);
207 * Normalizes an item reference, string id or numerical index into a reference to the item
208 * @param {Ext.Component|String|Number} item The item reference, id or index
209 * @return {Ext.Component} The item
211 getItem: function(item) {
212 if (Ext.isString(item)) {
213 item = Ext.getCmp(item);
214 } else if (Ext.isNumber(item)) {
215 item = this.items[item];
223 * @return {Object} Object passed to scrollTo when scrolling
225 getScrollAnim: function() {
227 duration: this.scrollDuration,
228 callback: this.updateScrollButtons,
235 * Enables or disables each scroller button based on the current scroll position
237 updateScrollButtons: function() {
238 if (this.beforeScroller == undefined || this.afterScroller == undefined) {
242 var beforeMeth = this.atExtremeBefore() ? 'addClass' : 'removeClass',
243 afterMeth = this.atExtremeAfter() ? 'addClass' : 'removeClass',
244 beforeCls = this.beforeScrollerCls + '-disabled',
245 afterCls = this.afterScrollerCls + '-disabled';
247 this.beforeScroller[beforeMeth](beforeCls);
248 this.afterScroller[afterMeth](afterCls);
249 this.scrolling = false;
254 * Returns true if the innerCt scroll is already at its left-most point
255 * @return {Boolean} True if already at furthest left point
257 atExtremeBefore: function() {
258 return this.getScrollPosition() === 0;
263 * Scrolls to the left by the configured amount
265 scrollLeft: function(animate) {
266 this.scrollBy(-this.scrollIncrement, animate);
271 * Scrolls to the right by the configured amount
273 scrollRight: function(animate) {
274 this.scrollBy(this.scrollIncrement, animate);
278 * Scrolls to the given component.
279 * @param {String|Number|Ext.Component} item The item to scroll to. Can be a numerical index, component id
280 * or a reference to the component itself.
281 * @param {Boolean} animate True to animate the scrolling
283 scrollToItem: function(item, animate) {
284 item = this.getItem(item);
286 if (item != undefined) {
287 var visibility = this.getItemVisibility(item);
289 if (!visibility.fullyVisible) {
290 var box = item.getBox(true, true),
293 if (visibility.hiddenRight) {
294 newX -= (this.layout.innerCt.getWidth() - box.width);
297 this.scrollTo(newX, animate);
304 * For a given item in the container, return an object with information on whether the item is visible
305 * with the current innerCt scroll value.
306 * @param {Ext.Component} item The item
307 * @return {Object} Values for fullyVisible, hiddenLeft and hiddenRight
309 getItemVisibility: function(item) {
310 var box = this.getItem(item).getBox(true, true),
312 itemRight = box.x + box.width,
313 scrollLeft = this.getScrollPosition(),
314 scrollRight = this.layout.innerCt.getWidth() + scrollLeft;
317 hiddenLeft : itemLeft < scrollLeft,
318 hiddenRight : itemRight > scrollRight,
319 fullyVisible: itemLeft > scrollLeft && itemRight < scrollRight
324 Ext.layout.boxOverflow.scroller = Ext.layout.boxOverflow.Scroller;
328 * @class Ext.layout.boxOverflow.VerticalScroller
\r
329 * @extends Ext.layout.boxOverflow.Scroller
\r
332 Ext.layout.boxOverflow.VerticalScroller = Ext.extend(Ext.layout.boxOverflow.Scroller, {
336 handleOverflow: function(calculations, targetSize) {
337 Ext.layout.boxOverflow.VerticalScroller.superclass.handleOverflow.apply(this, arguments);
341 height: targetSize.height - (this.beforeCt.getHeight() + this.afterCt.getHeight()),
342 width : targetSize.width
349 * Creates the beforeCt and afterCt elements if they have not already been created
351 createInnerElements: function() {
352 var target = this.layout.innerCt;
354 //normal items will be rendered to the innerCt. beforeCt and afterCt allow for fixed positioning of
355 //special items such as scrollers or dropdown menu triggers
356 if (!this.beforeCt) {
357 this.beforeCt = target.insertSibling({cls: this.beforeCls}, 'before');
358 this.afterCt = target.insertSibling({cls: this.afterCls}, 'after');
360 this.createWheelListener();
366 * Scrolls to the given position. Performs bounds checking.
367 * @param {Number} position The position to scroll to. This is constrained.
368 * @param {Boolean} animate True to animate. If undefined, falls back to value of this.animateScroll
370 scrollTo: function(position, animate) {
371 var oldPosition = this.getScrollPosition(),
372 newPosition = position.constrain(0, this.getMaxScrollBottom());
374 if (newPosition != oldPosition && !this.scrolling) {
375 if (animate == undefined) {
376 animate = this.animateScroll;
379 this.layout.innerCt.scrollTo('top', newPosition, animate ? this.getScrollAnim() : false);
382 this.scrolling = true;
384 this.scrolling = false;
385 this.updateScrollButtons();
391 * Returns the current scroll position of the innerCt element
392 * @return {Number} The current scroll position
394 getScrollPosition: function(){
395 return parseInt(this.layout.innerCt.dom.scrollTop, 10) || 0;
400 * Returns the maximum value we can scrollTo
401 * @return {Number} The max scroll value
403 getMaxScrollBottom: function() {
404 return this.layout.innerCt.dom.scrollHeight - this.layout.innerCt.getHeight();
409 * Returns true if the innerCt scroll is already at its right-most point
410 * @return {Boolean} True if already at furthest right point
412 atExtremeAfter: function() {
413 return this.getScrollPosition() >= this.getMaxScrollBottom();
417 Ext.layout.boxOverflow.scroller.vbox = Ext.layout.boxOverflow.VerticalScroller;
421 * @class Ext.layout.boxOverflow.HorizontalScroller
422 * @extends Ext.layout.boxOverflow.Scroller
425 Ext.layout.boxOverflow.HorizontalScroller = Ext.extend(Ext.layout.boxOverflow.Scroller, {
426 handleOverflow: function(calculations, targetSize) {
427 Ext.layout.boxOverflow.HorizontalScroller.superclass.handleOverflow.apply(this, arguments);
431 height: targetSize.height,
432 width : targetSize.width - (this.beforeCt.getWidth() + this.afterCt.getWidth())
439 * Creates the beforeCt and afterCt elements if they have not already been created
441 createInnerElements: function() {
442 var target = this.layout.innerCt;
444 //normal items will be rendered to the innerCt. beforeCt and afterCt allow for fixed positioning of
445 //special items such as scrollers or dropdown menu triggers
446 if (!this.beforeCt) {
447 this.afterCt = target.insertSibling({cls: this.afterCls}, 'before');
448 this.beforeCt = target.insertSibling({cls: this.beforeCls}, 'before');
450 this.createWheelListener();
456 * Scrolls to the given position. Performs bounds checking.
457 * @param {Number} position The position to scroll to. This is constrained.
458 * @param {Boolean} animate True to animate. If undefined, falls back to value of this.animateScroll
460 scrollTo: function(position, animate) {
461 var oldPosition = this.getScrollPosition(),
462 newPosition = position.constrain(0, this.getMaxScrollRight());
464 if (newPosition != oldPosition && !this.scrolling) {
465 if (animate == undefined) {
466 animate = this.animateScroll;
469 this.layout.innerCt.scrollTo('left', newPosition, animate ? this.getScrollAnim() : false);
472 this.scrolling = true;
474 this.scrolling = false;
475 this.updateScrollButtons();
481 * Returns the current scroll position of the innerCt element
482 * @return {Number} The current scroll position
484 getScrollPosition: function(){
485 return parseInt(this.layout.innerCt.dom.scrollLeft, 10) || 0;
490 * Returns the maximum value we can scrollTo
491 * @return {Number} The max scroll value
493 getMaxScrollRight: function() {
494 return this.layout.innerCt.dom.scrollWidth - this.layout.innerCt.getWidth();
499 * Returns true if the innerCt scroll is already at its right-most point
500 * @return {Boolean} True if already at furthest right point
502 atExtremeAfter: function() {
503 return this.getScrollPosition() >= this.getMaxScrollRight();
507 Ext.layout.boxOverflow.scroller.hbox = Ext.layout.boxOverflow.HorizontalScroller;