6 var XUI_ScrollBox_useCSSP = !X_UA[ 'IE5' ],
\r
7 XUI_ScrollBox_current,
\r
8 XUI_ScrollBox_indicatorV,
\r
9 XUI_ScrollBox_indicatorH;
\r
11 function XUI_ScrollBox_start( scrollBox ){
\r
13 if( XUI_ScrollBox_current && XUI_ScrollBox_current !== scrollBox ){
\r
14 XUI_ScrollBox_indicatorV &&
\r
15 XUI_ScrollBox_current[ 'unlisten' ]( [ X_EVENT_CANCELED, XUI_Event.SCROLL_END ], XUI_ScrollBox_indicatorV, XUI_ScrollBox_indicatorHandleEvent );
\r
17 XUI_ScrollBox_indicatorH &&
\r
18 XUI_ScrollBox_current[ 'unlisten' ]( [ X_EVENT_CANCELED, XUI_Event.SCROLL_END ], XUI_ScrollBox_indicatorH, XUI_ScrollBox_indicatorHandleEvent );
\r
21 if( scrollBox && scrollBox.hasVScroll ){
\r
22 if( !XUI_ScrollBox_indicatorV ){
\r
23 XUI_ScrollBox_indicatorV = X_Doc_create( 'div' )[ 'className' ]( 'ScrollBox-IndicatorV' );
\r
25 if( scrollBox.xnode !== XUI_ScrollBox_indicatorV.parent ){
\r
26 console.log( '*** Scroll Indicator add ***' );
\r
27 scrollBox.xnode[ 'append' ]( XUI_ScrollBox_indicatorV );
\r
28 XUI_ScrollBox_indicatorV[ 'animate' ]({
\r
29 'from' : { opacity : 0 },
\r
30 'to' : { opacity : 0.5 },
\r
32 'easing' : 'circular',
\r
36 [ 'listen' ]( [ X_EVENT_CANCELED, XUI_Event.SCROLL_END ], XUI_ScrollBox_indicatorV, XUI_ScrollBox_indicatorHandleEvent );
\r
39 if( XUI_ScrollBox_indicatorV ){
\r
40 console.log( '*** Scroll Indicator remove ***' );
\r
41 XUI_ScrollBox_indicatorV[ 'remove' ]();
\r
44 if( scrollBox && scrollBox.hasHScroll ){
\r
45 if( !XUI_ScrollBox_indicatorH ){
\r
46 XUI_ScrollBox_indicatorH = X_Doc_create( 'div' )[ 'className' ]( 'ScrollBox-IndicatorH' );
\r
48 if( scrollBox.xnode !== XUI_ScrollBox_indicatorH.parent ){
\r
49 scrollBox.xnode[ 'append' ]( XUI_ScrollBox_indicatorH );
\r
50 XUI_ScrollBox_indicatorH[ 'animate' ]({
\r
51 'from' : { opacity : 0 },
\r
52 'to' : { opacity : 0.5 },
\r
54 'easing' : 'circular',
\r
58 [ 'listen' ]( [ X_EVENT_CANCELED, XUI_Event.SCROLL_END ], XUI_ScrollBox_indicatorH, XUI_ScrollBox_indicatorHandleEvent );
\r
61 if( XUI_ScrollBox_indicatorH ){
\r
62 XUI_ScrollBox_indicatorH[ 'remove' ]();
\r
65 XUI_ScrollBox_current = scrollBox;
\r
68 function XUI_ScrollBox_indicatorHandleEvent( e ){
\r
69 //if( !XUI_ScrollBox_useCSSP ) return;
\r
71 case X_EVENT_CANCELED :
\r
72 case XUI_Event.SCROLL_END :
\r
73 console.log( '-fadeout-' );
\r
75 'from' : { opacity : 0.5 },
\r
76 'to' : { opacity : 0 },
\r
78 'easing' : 'circular',
\r
86 var X_UI_ScrollBox_SUPPORT_ATTRS = {
\r
87 // スクロール開始するために必要な移動距離、縦か横、どちらか制限する場合、より重要
\r
88 directionLockThreshold : [ 10, XUI_Dirty.CLEAN, XUI_Attr_USER.UINODE, XUI_Attr_Type.LENGTH ],
\r
89 scrollXEnabled : [ true, XUI_Dirty.CLEAN, XUI_Attr_USER.UINODE, XUI_Attr_Type.BOOLEAN ],
\r
90 scrollYEnabled : [ true, XUI_Dirty.CLEAN, XUI_Attr_USER.UINODE, XUI_Attr_Type.BOOLEAN ],
\r
91 scrollEnabled : [ true, XUI_Dirty.CLEAN, XUI_Attr_USER.UINODE, XUI_Attr_Type.BOOLEAN ],
\r
92 bounceEnabled : [ true, XUI_Dirty.CLEAN, XUI_Attr_USER.UINODE, XUI_Attr_Type.BOOLEAN ],
\r
93 bounceTime : [ 300, XUI_Dirty.CLEAN, XUI_Attr_USER.UINODE, XUI_Attr_Type.TIME ],
\r
94 useWheel : [ true, XUI_Dirty.CLEAN, XUI_Attr_USER.UINODE, XUI_Attr_Type.BOOLEAN ],
\r
95 useKey : [ true, XUI_Dirty.CLEAN, XUI_Attr_USER.UINODE, XUI_Attr_Type.BOOLEAN ],
\r
96 hasScrollShadow : [ true, XUI_Dirty.CLEAN, XUI_Attr_USER.UINODE, XUI_Attr_Type.BOOLEAN ],
\r
97 scrollShadowColor : [ '#000', XUI_Dirty.CLEAN, XUI_Attr_USER.UINODE, XUI_Attr_Type.COLOR ]
\r
100 var XUI_ScrollBox = XUI_ChromeBox.inherits(
\r
104 layout : XUI_Layout_Canvas,
\r
106 directionLockThreshold : 10,
\r
107 scrollXEnabled : true,
\r
108 scrollYEnabled : true,
\r
109 scrollEnabled : true,
\r
110 bounceEnabled : true,
\r
111 momentumEnabled : true,
\r
115 hasScrollShadow : true,
\r
116 scrollShadowColor : '#000',
\r
122 directionLocked : '',
\r
125 isInTransition : false,
\r
127 hasHScroll : false,
\r
128 hasVScroll : false,
\r
132 requestFrameID : 0,
\r
138 scrollXMax : 0, // px
\r
139 scrollYMax : 0, // px
\r
140 scrollXRatio : 0, // この値は scroll 不要になっても保持される。 scroll 必要時に参照される
\r
144 absStartX : 0, // px
\r
145 absStartY : 0, // px
\r
150 directionX : 0, // -1, 0, 1
\r
151 directionY : 0, // -1, 0, 1
\r
153 lastScrollWidth : 0,
\r
154 lastScrollHeight : 0,
\r
158 _containerNode : null,
\r
159 xnodeSlider : null,
\r
161 Constructor : function( user, layout, args ){
\r
162 this[ 'Super' ]( user, layout, args );
\r
163 this._containerNode = X_Pair_get( this.containerNode );
\r
164 this.xnodeSlider = this._containerNode.xnode[ 'className' ]( 'ScrollSlider' )[ 'listen' ]( X_EVENT_ANIME_END, this, X_UI_ScrollBox_onAnimeEnd );
\r
165 this.xnode[ 'className' ]( 'ScrollBox' );
\r
168 creationComplete : function(){
\r
169 XUI_Box.prototype.creationComplete.apply( this, arguments );
\r
172 calculate : function(){
\r
173 this.lastScrollWidth = this._containerNode.boxWidth;
\r
174 this.lastScrollHeight = this._containerNode.boxHeight;
\r
175 this.lastBoxWidth = this.boxWidth;
\r
176 this.lastBoxHeight = this.boxHeight;
\r
178 XUI_Box.prototype.calculate.apply( this, arguments );
\r
180 // TODO root の layout_complete 後に。
\r
181 // TODO calculate 前に scroll の解放。
\r
184 this.lastScrollWidth !== this._containerNode.boxWidth ||
\r
185 this.lastScrollHeight !== this._containerNode.boxHeight ||
\r
186 this.lastBoxWidth !== this.boxWidth || this.lastBoxHeight !== this.boxHeight
\r
188 console.log( 'scroll - calc' );
\r
189 XUI_rootData[ 'listenOnce' ]( XUI_Event.LAYOUT_COMPLETE, this, X_UI_ScrollBox_onLayoutComplete );
\r
193 scrollTo : function( x, y, opt_time, opt_easing, opt_release ){
\r
194 //if( this.scrollX === x && this.scrollY === y ) return;
\r
196 opt_time = 0 <= opt_time ? opt_time : 0;
\r
197 opt_easing = opt_easing || 'circular';
\r
198 opt_release = 0 <= opt_release ? opt_release : 300;
\r
200 this.isInTransition = 0 < opt_time;
\r
202 X_UI_ScrollBox_translate( this, x, y, opt_time, opt_easing, opt_release );
\r
205 _remove : function(){
\r
206 XUI_AbstractUINode.prototype._remove.apply( this, arguments );
\r
208 if( this.scrolling ){
\r
210 this[ 'unlisten' ]( XUI_Event._POINTER_DOWN, X_UI_ScrollBox_onStart )
\r
211 [ 'unlisten' ]( XUI_Event.DRAG, X_UI_ScrollBox_onMove )
\r
212 [ 'unlisten' ]( XUI_Event.DRAG_END, X_UI_ScrollBox_onEnd );
\r
213 XUI_rootData[ 'unlisten' ]( XUI_Event.LAYOUT_BEFORE, this, X_UI_ScrollBox_onLayoutBefore );
\r
215 XUI_rootData[ 'unlisten' ]( XUI_Event.LAYOUT_COMPLETE, this, X_UI_ScrollBox_onLayoutComplete );
\r
216 this[ 'unlisten' ]( XUI_Event.SCROLL_END, XUI_rootData, XUI_rootData.calculate );
\r
218 XUI_ScrollBox_useCSSP ? this.xnodeSlider[ 'stop' ]() : this.xnode[ 'stop' ]();
\r
220 XUI_ScrollBox_current === this && XUI_ScrollBox_start( null );
\r
222 this.scrolling = false;
\r
229 function X_UI_ScrollBox_onLayoutBefore( e ){
\r
230 if( e[ 'cancelable' ] && this.isInTransition && X_NodeAnime_translateZ ){
\r
231 this[ 'listenOnce' ]( XUI_Event.SCROLL_END, XUI_rootData, XUI_rootData.calculate );
\r
232 return X_CALLBACK_PREVENT_DEFAULT;
\r
234 this.scrollXRatio = this.scrollX / this.scrollXMax;
\r
235 this.scrollYRatio = this.scrollY / this.scrollYMax;
\r
236 XUI_ScrollBox_useCSSP ? this.xnodeSlider[ 'stop' ]() : this.xnode[ 'stop' ]();
\r
237 this.isInTransition = false;
\r
238 return X_CALLBACK_NONE;
\r
241 function X_UI_ScrollBox_onLayoutComplete( e ){
\r
242 // scroll の停止、GPU の解除
\r
243 var font = this.fontSize = this.xnodeSlider[ 'call' ]( 'fontSize' );
\r
245 this.scrollXMax = ( this.boxWidth - this._containerNode.boxWidth ) * font | 0;
\r
246 this.scrollYMax = ( this.boxHeight - this._containerNode.boxHeight ) * font | 0;
\r
248 this.hasHScroll = this.scrollXEnabled && ( this.scrollXMax < -1 ); // < 0 だと
\r
249 this.hasVScroll = this.scrollYEnabled && ( this.scrollYMax < -1 );
\r
251 if( !this.hasHScroll ){
\r
252 this.scrollXMax = 0;
\r
255 if( !this.hasVScroll ){
\r
256 this.scrollYMax = 0;
\r
259 delete this.endTime;
\r
260 delete this.directionX;
\r
261 delete this.directionY;
\r
263 X_UI_ScrollBox_resetPosition( this, 0 );
\r
265 if( this.hasHScroll || this.hasVScroll ){
\r
267 if( this.scrolling ){
\r
268 X_UI_ScrollBox_translate( this, this.scrollXMax * this.scrollXRatio, this.scrollYMax * this.scrollYRatio, 100, '', 300 );
\r
271 this[ 'listen' ]( XUI_Event._POINTER_DOWN, X_UI_ScrollBox_onStart )
\r
272 [ 'listen' ]( XUI_Event.DRAG, X_UI_ScrollBox_onMove )
\r
273 [ 'listen' ]( XUI_Event.DRAG_END, X_UI_ScrollBox_onEnd );
\r
274 XUI_rootData[ 'listen' ]( XUI_Event.LAYOUT_BEFORE, this, X_UI_ScrollBox_onLayoutBefore );
\r
276 X_UI_ScrollBox_translate( this, this.scrollXMax * this.scrollXRatio, this.scrollYMax * this.scrollYRatio, 100, '', 300 );
\r
277 this.scrolling = true;
\r
281 if( this.scrolling ){
\r
283 this[ 'unlisten' ]( XUI_Event._POINTER_DOWN, X_UI_ScrollBox_onStart )
\r
284 [ 'unlisten' ]( XUI_Event.DRAG, X_UI_ScrollBox_onMove )
\r
285 [ 'unlisten' ]( XUI_Event.DRAG_END, X_UI_ScrollBox_onEnd );
\r
286 XUI_rootData[ 'unlisten' ]( XUI_Event.LAYOUT_BEFORE, this, X_UI_ScrollBox_onLayoutBefore );
\r
288 ( this.scrollX !== 0 || this.scrollY !== 0 ) && X_UI_ScrollBox_translate( this, 0, 0, 100, '', 300 );
\r
290 delete this.scrolling;
\r
291 delete this.scrollXRatio;
\r
292 delete this.scrollYRatio;
\r
296 // TODO use scrollLeft, scrollTop
\r
297 function X_UI_ScrollBox_translate( that, x, y, opt_time, opt_easing, opt_release ){
\r
298 var scrollBoxH = that.fontSize * that.boxHeight,
\r
299 scrollBoxW = that.fontSize * that.boxWidth,
\r
300 indicatorH, indicatorW;
\r
302 opt_time = 0 <= opt_time ? opt_time : 0;
\r
303 opt_easing = opt_easing === '' ? '' : opt_easing || 'circular';
\r
304 opt_release = 0 <= opt_release ? opt_release : 300;
\r
306 console.log( 'scr ' + y );
\r
308 if( !XUI_ScrollBox_useCSSP ){
\r
309 that.xnode[ 'animate' ]({
\r
311 scrollX : -that.scrollX,
\r
312 scrollY : -that.scrollY
\r
318 'duration' : opt_time,
\r
319 'easing' : opt_easing
\r
322 that.xnodeSlider[ 'animate' ]({
\r
331 'duration' : opt_time,
\r
332 'easing' : opt_easing,
\r
333 'lazyRelease' : opt_release
\r
337 if( X_UA[ 'IE' ] < 6 ){
\r
338 XUI_ScrollBox_indicatorV && XUI_ScrollBox_indicatorV[ 'css' ]( 'left', ( scrollBoxW - that.fontSize * 0.6 | 0 ) + 'px' );
\r
339 XUI_ScrollBox_indicatorH && XUI_ScrollBox_indicatorH[ 'css' ]( 'top' , ( scrollBoxH - that.fontSize * 0.6 | 0 ) + 'px' );
\r
342 if( that.hasVScroll && XUI_ScrollBox_indicatorV && XUI_ScrollBox_indicatorV.parent === that.xnode ){
\r
343 indicatorH = scrollBoxH * scrollBoxH / ( - that.scrollYMax + scrollBoxH );
\r
344 scrollBoxH -= indicatorH;
\r
346 XUI_ScrollBox_indicatorV
\r
348 height : ( indicatorH | 0 ) + 'px'
\r
352 y : scrollBoxH * that.scrollY / that.scrollYMax },
\r
354 y : scrollBoxH * y / that.scrollYMax,
\r
357 'duration' : opt_time,
\r
358 'easing' : opt_easing,
\r
359 'lazyRelease' : opt_release
\r
362 if( that.hasHScroll && XUI_ScrollBox_indicatorH && XUI_ScrollBox_indicatorH.parent === that.xnode ){
\r
363 indicatorW = scrollBoxW * scrollBoxW / ( - that.scrollXMax + scrollBoxW );
\r
364 scrollBoxW -= indicatorW;
\r
365 XUI_ScrollBox_indicatorH
\r
367 width : ( indicatorW | 0 ) + 'px'
\r
371 x : scrollBoxW * that.scrollX / that.scrollXMax },
\r
373 x : scrollBoxW * x / that.scrollXMax,
\r
376 'duration' : opt_time,
\r
377 'easing' : opt_easing,
\r
378 'lazyRelease' : opt_release
\r
383 that.scrollXEm = x / that.fontSize;
\r
385 that.scrollYEm = y / that.fontSize;
\r
388 function X_UI_ScrollBox_onStart( e ){
\r
389 var ret = X_CALLBACK_NONE;
\r
391 if( !this.scrollEnabled || ( this.initiated && e.pointerType !== this.initiated ) ){
\r
395 this.initiated = e.pointerType;
\r
396 this.moved = false;
\r
399 this.directionX = 0;
\r
400 this.directionY = 0;
\r
401 this.directionLocked = '';
\r
402 this.startTime = X_Timer_now();
\r
405 if( this.isInTransition ){
\r
406 this.isInTransition = false;
\r
407 //console.log( '-1-' );
\r
408 this[ 'dispatch' ]( XUI_Event.SCROLL_END );
\r
410 XUI_ScrollBox_useCSSP ? this.xnodeSlider[ 'stop' ]() : this.xnode[ 'stop' ]();
\r
413 this.startX = this.scrollX;
\r
414 this.startY = this.scrollY;
\r
415 this.absStartX = this.scrollX;
\r
416 this.absStartY = this.scrollY;
\r
417 this.pointX = e.pageX;
\r
418 this.pointY = e.pageY;
\r
420 console.log( 'scrollstart ' + e.pageY + e.target.className() );
\r
422 return ret | X_CALLBACK_PREVENT_DEFAULT;
\r
425 function X_UI_ScrollBox_onMove( e ){
\r
426 var ret = X_CALLBACK_NONE,
\r
427 deltaX, deltaY, timestamp,
\r
429 absDistX, absDistY;
\r
430 // 規定以上の move でスクロール開始
\r
432 //console.log( 'scrollmove ' + e.buttons + ' ' + e.button );
\r
434 if( !this.scrollEnabled || e.pointerType !== this.initiated ){
\r
439 if( !XUI_ScrollBox_useCSSP ? ( !this.xnode[ '_anime' ] || !this.xnode[ '_anime' ].phase ) : ( !this.xnodeSlider[ '_anime' ] || !this.xnodeSlider[ '_anime' ].phase ) ){
\r
440 //console.log( 'gpuレイヤーの用意 ' + e.pageY );
\r
441 //console.log( 'mov1 x:' + this.scrollX + ' y:' + this.scrollY );
\r
442 X_UI_ScrollBox_translate( this, this.scrollX, this.scrollY, 0, '', 300 );
\r
446 deltaX = e.pageX - this.pointX;
\r
447 deltaY = e.pageY - this.pointY;
\r
448 timestamp = X_Timer_now();
\r
450 this.pointX = e.pageX;
\r
451 this.pointY = e.pageY;
\r
453 this.distX += deltaX;
\r
454 this.distY += deltaY;
\r
455 absDistX = Math.abs(this.distX);
\r
456 absDistY = Math.abs(this.distY);
\r
458 // We need to move at least 10 pixels for the scrolling to initiate
\r
459 if( 300 < timestamp - this.endTime && ( absDistX < 10 && absDistY < 10 ) ){
\r
463 // If you are scrolling in one direction lock the other
\r
464 if( !this.directionLocked ){
\r
465 if( absDistX > absDistY + this.directionLockThreshold ){
\r
466 this.directionLocked = 'h'; // lock horizontally
\r
468 if( absDistY >= absDistX + this.directionLockThreshold ){
\r
469 this.directionLocked = 'v'; // lock vertically
\r
471 this.directionLocked = 'n'; // no lock
\r
475 if( this.directionLocked === 'h' ){
\r
478 if( this.directionLocked === 'v' ){
\r
482 deltaX = this.hasHScroll ? deltaX : 0;
\r
483 deltaY = this.hasVScroll ? deltaY : 0;
\r
486 this[ 'dispatch' ]( XUI_Event.SCROLL_BEFORE_MOVE );
\r
488 this.minusX = deltaX;
\r
489 this.minusY = deltaY;
\r
491 XUI_ScrollBox_start( this );
\r
493 this[ 'dispatch' ]( XUI_Event.SCROLL_MOVE );
\r
496 newX = this.scrollX + deltaX;// - this.minusX;
\r
497 newY = this.scrollY + deltaY;// - this.minusY;
\r
499 // Slow down if outside of the boundaries
\r
500 if( 0 < newX || newX < this.scrollXMax ){
\r
501 newX = this.bounceEnabled ? this.scrollX + ( deltaX ) / 3 : 0 < newX ? 0 : this.scrollXMax;
\r
504 if( 0 < newY || newY < this.scrollYMax ){
\r
505 //console.log( 'slow... ' + newY + ' ' + this.scrollYMax );
\r
506 newY = this.bounceEnabled ? this.scrollY + ( deltaY ) / 3 : 0 < newY ? 0 : this.scrollYMax;
\r
509 this.directionX = 0 < deltaX ? -1 : deltaX < 0 ? 1 : 0;
\r
510 this.directionY = 0 < deltaY ? -1 : deltaY < 0 ? 1 : 0;
\r
512 console.log( 'mov2 x:' + newX + ' y:' + newY );
\r
513 X_UI_ScrollBox_translate( this, newX, newY, 0, '', 300 );
\r
515 if( 300 < timestamp - this.startTime ){
\r
516 this.startTime = timestamp;
\r
517 this.startX = this.scrollX;
\r
518 this.startY = this.scrollY;
\r
521 return ret | X_CALLBACK_PREVENT_DEFAULT | X_CALLBACK_CAPTURE_POINTER;
\r
524 function X_UI_ScrollBox_onEnd( e ){
\r
525 var ret = X_CALLBACK_NONE,
\r
529 momentumX, momentumY,
\r
530 duration, distanceX, distanceY;
\r
532 //console.log( e.type + ' onend ' + XUI_Event.POINTER_OUT );
\r
534 if( !this.scrollEnabled || e.pointerType !== this.initiated ){
\r
535 //console.log( e.type + ' onend 1 ' + e.pointerType + ' ' + this.initiated );
\r
539 delete this.isInTransition;
\r
540 delete this.initiated;
\r
541 this.endTime = X_Timer_now();
\r
543 duration = this.endTime - this.startTime;
\r
544 newX = Math.round( this.scrollX );
\r
545 newY = Math.round( this.scrollY );
\r
546 distanceX = Math.abs(newX - this.startX);
\r
547 distanceY = Math.abs(newY - this.startY);
\r
549 // reset if we are outside of the boundaries
\r
550 if( X_UI_ScrollBox_resetPosition( this, this.bounceTime ) ){
\r
551 //console.log( e.type + ' onend 2 ' + XUI_Event.POINTER_OUT );
\r
552 return ret | X_CALLBACK_PREVENT_DEFAULT | X_CALLBACK_RELEASE_POINTER;
\r
555 // we scrolled less than 10 pixels
\r
557 this[ 'dispatch' ]( X_EVENT_CANCELED );
\r
558 //console.log( 'we scrolled less than 10 pixels ' + e.pageY );
\r
559 return ret | X_CALLBACK_PREVENT_DEFAULT | X_CALLBACK_RELEASE_POINTER;
\r
562 // start momentum animation if needed
\r
563 if( this.momentumEnabled && duration < 300 ){
\r
564 momentumX = this.hasHScroll ?
\r
565 X_UI_ScrollBox_momentum( this.scrollX, this.startX, duration, this.scrollXMax, this.bounceEnabled ? this.boxWidth * this.fontSize : 0, this.deceleration ) :
\r
566 { destination: newX, duration: 0 };
\r
567 momentumY = this.hasVScroll ?
\r
568 X_UI_ScrollBox_momentum( this.scrollY, this.startY, duration, this.scrollYMax, this.bounceEnabled ? this.boxHeight * this.fontSize : 0, this.deceleration ) :
\r
569 { destination: newY, duration: 0 };
\r
570 newX = momentumX.destination;
\r
571 newY = momentumY.destination;
\r
572 time = Math.max( momentumX.duration, momentumY.duration ) | 0;
\r
573 this.isInTransition = true;
\r
575 //console.log( '慣性無し' );
\r
578 if( newX != this.scrollX || newY != this.scrollY ){
\r
579 // change easing function when scroller goes out of the boundaries
\r
580 if( 0 < newX || newX < this.scrollXMax || 0 < newY || newY < this.scrollYMax ){
\r
581 easing = 'quadratic';
\r
584 //console.log( 'end2 x:' + newX + ' y:' + newY + '<-y:' + this.scrollY + ' t:' + time );
\r
585 this.scrollTo( newX, newY, time, easing, 1000 );
\r
587 //console.log( 'end1 x:' + newX + ' y:' + newY );
\r
588 this.scrollTo( newX, newY, 0, '', 1000 ); // ensures that the last position is rounded
\r
589 //console.log( '-3-' );
\r
590 this[ 'dispatch' ]( XUI_Event.SCROLL_END );
\r
593 return ret | X_CALLBACK_PREVENT_DEFAULT | X_CALLBACK_RELEASE_POINTER;
\r
596 function X_UI_ScrollBox_resetPosition( that, time ){
\r
597 var x = that.scrollX,
\r
602 if( !that.hasHScroll || 0 < that.scrollX ){
\r
605 if( that.scrollX < that.scrollXMax ){
\r
606 x = that.scrollXMax;
\r
609 if( !that.hasVScroll || 0 < that.scrollY ){
\r
612 if( that.scrollY < that.scrollYMax ){
\r
613 y = that.scrollYMax;
\r
616 if( x === that.scrollX && y === that.scrollY ){
\r
617 //console.log( 'no バウンド y:' + y + ' max:' + that.scrollYMax );
\r
621 //console.log( ' ===> resetPosition - バウンド!' );
\r
622 //console.log( ' x:' + x + ' y:' + y );
\r
623 that.scrollTo( x, y, time, that.bounceEasing, 1000 );
\r
628 function X_UI_ScrollBox_onAnimeEnd( e ){
\r
629 if( this.isInTransition && !X_UI_ScrollBox_resetPosition( this, this.bounceTime ) ){
\r
630 this.isInTransition = false;
\r
631 //console.log( '-2-' );
\r
632 this[ 'dispatch' ]( XUI_Event.SCROLL_END );
\r
634 //console.log(' -2.1- '+this.isInTransition );
\r
635 return X_CALLBACK_NONE;
\r
638 function X_UI_ScrollBox_momentum( current, start, time, lowerMargin, wrapperSize, deceleration ){
\r
639 var distance = current - start,
\r
640 speed = Math.abs( distance ) / time,
\r
644 deceleration = deceleration === undefined ? 0.0006 : deceleration;
\r
646 destination = current + ( speed * speed ) / ( 2 * deceleration ) * ( distance < 0 ? -1 : 1 );
\r
647 duration = speed / deceleration;
\r
649 if( destination < lowerMargin ){
\r
650 destination = wrapperSize ? lowerMargin - ( wrapperSize / 2.5 * ( speed / 8 ) ) : lowerMargin;
\r
651 distance = Math.abs( destination - current );
\r
652 duration = distance / speed;
\r
654 if ( destination > 0 ) {
\r
655 destination = wrapperSize ? wrapperSize / 2.5 * ( speed / 8 ) : 0;
\r
656 distance = Math.abs( current ) + destination;
\r
657 duration = distance / speed;
\r
661 destination : Math.round( destination ),
\r
662 duration : duration
\r
666 X.UI.ScrollBox = X.UI.ChromeBox.inherits(
\r
670 Constructor : function(){
\r
671 var supports, slider;
\r
673 if( XUI_ScrollBox.prototype.usableAttrs === XUI_ChromeBox.prototype.usableAttrs ){
\r
674 XUI_ScrollBox.prototype.usableAttrs = supports = XUI_Attr_createAttrDef( XUI_Attr_Support, X_UI_ScrollBox_SUPPORT_ATTRS );
\r
676 XUI_ScrollBox.prototype.attrClass = XUI_Attr_preset( XUI_Box.prototype.attrClass, supports, { width : '100%', height : '100%', bgColor : 0x111111 } );
\r
680 XUI_Layout_Vertical,
\r
682 name : 'ScrollBox-Scroller',
\r
683 role : 'container',
\r
690 l = arguments.length, i = 0, j = 1,
\r
693 for( ; i < l; ++i ){
\r
694 arg = arguments[ i ];
\r
695 if( arg[ 'instanceOf' ] && arg[ 'instanceOf' ]( XUI_LayoutBase ) ){
\r
698 if( arg[ 'instanceOf' ] && arg[ 'instanceOf' ]( X.UI.AbstractUINode ) ){
\r
701 if( X_Type_isObject( arg ) ){
\r
702 args[ ++j ] = attr = arg;
\r
703 slider = attr.scrollSlider;
\r
713 slider || X.UI.VBox.apply( 0, args )
\r
718 //attr && this.attr( attr );
\r
720 scrollX : function(){
\r
723 scrollY : function(){
\r
726 scrollWidth : function(){
\r
729 scrollHeight : function(){
\r
732 scrollTo : function( nodeOrX, y ){
\r