Export 0.2.3
[platform/framework/web/web-ui-fw.git] / src / widgets / handler / js / jquery.tizen.scrollview.handler.js
1 /* ***************************************************************************
2  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20  * DEALINGS IN THE SOFTWARE.
21  * ***************************************************************************
22  *
23  * Authors: Wonseop Kim ( wonseop.kim@samsung.com )
24 */
25
26 /**
27  * "Handler" is a widget helping a user to scroll a window or panel.
28  * It is different from the scrollview feature in that the handler has a fixed size
29  * and disappears when a scroll size is smaller than a parent window's size.
30  * If the handler widget is activated, a scroll bar on the screen will be deactivated.
31  * The handler widget supports scrolling up and down and indicates the position of the scrolled window.
32  *
33  * HTML Attributes:
34  *
35  *              data-handler : This attribute is indicating that whether enable.
36  *                                              If you want to use, you will set 'true'.
37  *              data-handler-theme : Set the widget theme ( optional )
38  *
39  * APIs:
40  *
41  *              enableHandler ( boolean )
42  *                      : Get or set the use of handler widget.
43  *                      If the value is "true", it will be run handler widget.
44  *                      If the value is "false", it will be not run handler widget.
45  *                      If no value is specified, will act as a getter.
46  *
47  * Events:
48  *
49  * Examples:
50  *
51  *              <div data-role="content" data-scroll="y" data-handler="true">
52  *                      <ul data-role="listview">
53  *                              <li data-role="list-divider">A</li>
54  *                              <li><a href="#">Adam Kinkaid</a></li>
55  *                                      ...
56  *                      </ul>
57  *              </div>
58  */
59
60 /**
61         @class handler
62         The handler widget enables the user to vertically scroll through a page or panel using a fixed-size handle. The widget indicates the position of the scrolled window, and only appears on the screen if the parent page or panel's scroll size is larger than the screen size. <br/> To add a handler widget to the application, use the following code:
63
64                 <div data-role="content" data-scroll="y" data-handler="true">
65                         <ul data-role="listview">
66                                 <li data-role="list-divider">A</li>
67                                 <li><a href="#">Adam Kinkaid</a></li>
68                                         ...
69                         </ul>
70                 </div>
71         
72         You can use the enableHandler method with the handler widget to get (if no value is defined) or set the handler usage status. If the [enable] value is true, the handler is enabled; otherwise the handler is not used.
73
74                 $("#.selector").scrollview("enableHandler", [enable]);
75 */
76 /**
77         @property {Boolean} data-handler
78         Enables the handler widget. The value must be set to true.
79 */
80 /**
81         @property {String} data-handler-theme
82         Sets the handler widget theme.
83 */
84 ( function ( $, document, undefined ) {
85         // The options of handler in scrollview
86         $.tizen.scrollview.prototype.options.handler = false;
87         $.tizen.scrollview.prototype.options.handlerTheme = "s";
88
89         var originSetOption = $.tizen.scrollview.prototype._setOption,
90                 createHandler = function ( target ) {
91                         var $view = target,
92                                 prefix = "<div class=\"ui-handler ui-handler-direction-",
93                                 suffix = "\"><div class=\"ui-handler-track\"><div class=\"ui-handler-thumb\"></div></div></div>",
94                                 scrollview = $view.data( "scrollview" ),
95                                 options = scrollview.options,
96                                 direction = options.direction,
97                                 parentTheme = $.mobile.getInheritedTheme( scrollview, "s" ),
98                                 theme = options.theme || parentTheme,
99                                 isHorizontal = ( scrollview.options.direction === "x" ),
100                                 _$view = scrollview._$view,
101                                 _$clip = scrollview._$clip,
102                                 handler = null,
103                                 handlerThumb = null,
104                                 viewLength = 0,
105                                 clipLength = 0,
106                                 handlerHeight = 0,
107                                 handlerMargin = 0,
108                                 trackLength = 0,
109                                 isTouchable = $.support.touch,
110                                 dragStartEvt = ( isTouchable ? "touchstart" : "mousedown" ) + ".handler",
111                                 dragMoveEvt = ( isTouchable ? "touchmove" : "mousemove" ) + ".handler",
112                                 dragStopEvt = ( isTouchable ? "touchend" : "mouseup" ) + ".handler",
113                                 calculateLength = function () {
114                                         clipLength = ( isHorizontal ? _$clip.width() : _$clip.height() );
115                                         viewLength = ( isHorizontal ? _$view.outerWidth( true ) : _$view.outerHeight( true ) ) - clipLength;
116                                         trackLength = clipLength - handlerHeight - handlerMargin * 2;
117                                 },
118                                 setHanderPostion = function ( scrollPos ) {
119                                         var handlerPos = Math.round( ( isHorizontal ? scrollPos.x : scrollPos.y ) / viewLength * trackLength );
120                                         handlerThumb.css( isHorizontal ? "left" : "top", handlerPos );
121                                 };
122
123                         if ( $view.find( ".ui-handler-thumb" ).length !== 0 || typeof direction !== "string" ) {
124                                 return;
125                         }
126
127                         $view.addClass( " ui-handler-" + theme ).append( [ prefix, direction, suffix ].join( "" ) );
128                         handler = $view.find( ".ui-handler" );
129                         handlerThumb = $view.find( ".ui-handler-thumb" ).hide();
130                         handlerHeight = ( isHorizontal ? handlerThumb.width() : handlerThumb.height() );
131                         handlerMargin = ( isHorizontal ? parseInt( handler.css( "right" ), 10 ) : parseInt( handler.css( "bottom" ), 10 ) );
132
133                         $.extend( $view, {
134                                 moveData : null
135                         });
136
137                         // handler drag
138                         handlerThumb.bind( dragStartEvt, {
139                                 e : handlerThumb
140                         }, function ( event ) {
141                                 scrollview._stopMScroll();
142
143                                 var target = event.data.e,
144                                         t = ( isTouchable ? event.originalEvent.targetTouches[0] : event );
145
146                                 target.css( "opacity", 1.0 );
147
148                                 $view.moveData = {
149                                         target : target,
150                                         X : parseInt( target.css( 'left' ), 10 ) || 0,
151                                         Y : parseInt( target.css( 'top' ), 10 ) || 0,
152                                         pX : t.pageX,
153                                         pY : t.pageY
154                                 };
155                                 calculateLength();
156
157                                 _$view.trigger( "scrollstart" );
158                                 event.preventDefault();
159                                 event.stopPropagation();
160
161                                 $( document ).bind( dragMoveEvt, function ( event ) {
162                                         var moveData = $view.moveData,
163                                                 handlePos = 0,
164                                                 scrollPos = 0,
165                                                 t = ( isTouchable ? event.originalEvent.targetTouches[0] : event );
166
167                                         handlePos = ( isHorizontal ? moveData.X + t.pageX - moveData.pX : moveData.Y + t.pageY - moveData.pY );
168
169                                         if ( handlePos < 0 ) {
170                                                 handlePos = 0;
171                                         }
172
173                                         if ( handlePos > trackLength ) {
174                                                 handlePos = trackLength;
175                                         }
176                                         scrollPos = - Math.round( handlePos / trackLength * viewLength );
177
178                                         $view.attr( "display", "none" );
179                                         if ( isHorizontal ) {
180                                                 scrollview._setScrollPosition( scrollPos, 0 );
181                                                 moveData.target.css( {
182                                                         left : handlePos
183                                                 });
184                                         } else {
185                                                 scrollview._setScrollPosition( 0, scrollPos );
186                                                 moveData.target.css( {
187                                                         top : handlePos
188                                                 });
189                                         }
190                                         $view.attr( "display", "inline" );
191
192                                         event.preventDefault();
193                                         event.stopPropagation();
194                                 }).bind( dragStopEvt, function ( event ) {
195                                         $( document ).unbind( dragMoveEvt ).unbind( dragStopEvt );
196
197                                         $view.moveData = null;
198                                         _$view.trigger( "scrollstop" );
199
200                                         event.preventDefault();
201                                 });
202                         });
203
204                         $( document ).bind( dragMoveEvt, function ( event ) {
205                                 var isVisible = false,
206                                         vclass = "ui-scrollbar-visible";
207
208                                 if ( scrollview._$vScrollBar ) {
209                                         isVisible = scrollview._$vScrollBar.hasClass( vclass );
210                                 } else if ( scrollview._$hScrollBar ) {
211                                         isVisible = scrollview._$hScrollBar.hasClass( vclass );
212                                 }
213
214                                 if ( isVisible || $view.moveData !== null ) {
215                                         if ( handlerThumb.hasClass( "ui-handler-visible" ) ) {
216                                                 _$view.trigger( "scrollupdate" );
217                                         } else {
218                                                 _$view.trigger( "scrollstop" );
219                                         }
220                                 }
221                         }).bind( dragStopEvt, function ( event ) {
222                                 if ( handlerThumb.hasClass( "ui-handler-visible" ) ) {
223                                         _$view.trigger( "scrollstop" );
224                                 }
225                         });
226
227                         $view.bind( "scrollstart", function ( event ) {
228                                 if ( !scrollview.enableHandler() ) {
229                                         return;
230                                 }
231                                 calculateLength();
232
233                                 if ( clipLength > viewLength || trackLength < ( handlerHeight * 4 / 3 ) ) {
234                                         return;
235                                 }
236
237                                 handlerThumb.addClass( "ui-handler-visible" )
238                                                         .stop( true, true )
239                                                         .fadeIn( 'fast' );
240
241                                 event.preventDefault();
242                                 event.stopPropagation();
243                         }).bind( "scrollupdate", function ( event, data ) {
244                                 if ( !scrollview.enableHandler() || clipLength > viewLength || trackLength < ( handlerHeight * 4 / 3 ) ) {
245                                         return;
246                                 }
247
248                                 setHanderPostion( scrollview.getScrollPosition() );
249
250                                 event.preventDefault();
251                                 event.stopPropagation();
252                         }).bind( "scrollstop", function ( event ) {
253                                 if ( !scrollview.enableHandler() || clipLength > viewLength ) {
254                                         return;
255                                 }
256
257                                 if ( scrollview._handlerTimer ) {
258                                         clearTimeout( scrollview._handlerTimer );
259                                         scrollview._handlerTimer = 0;
260                                 }
261                                 scrollview._handlerTimer = setTimeout( function () {
262                                         if ( scrollview._timerID === 0 && $view.moveData === null ) {
263                                                 handlerThumb.removeClass( "ui-handler-visible" )
264                                                                         .stop( true, true )
265                                                                         .css( "opacity", 1.0 )
266                                                                         .fadeOut( 'fast' );
267                                                 scrollview._handlerTimer = 0;
268                                         }
269                                 }, 1000 );
270
271                                 event.preventDefault();
272                         }).bind( "mousewheel", function ( event ) {
273                                 handlerThumb.removeClass( "ui-handler-visible" ).hide();
274                                 setHanderPostion( scrollview.getScrollPosition() );
275                         });
276                 };
277
278         $.extend( $.tizen.scrollview.prototype, {
279                 enableHandler: function ( enabled ) {
280                         if ( typeof enabled === 'undefined' ) {
281                                 return this.options.handler;
282                         }
283
284                         this.options.handler = !!enabled;
285
286                         var view = this.element;
287                         if ( this.options.handler ) {
288                                 if ( view.find( ".ui-handler" ).length === 0 ) {
289                                         createHandler( view );
290                                 }
291
292                                 view.find( ".ui-scrollbar" ).hide();
293                                 view.find( ".ui-handler" ).show();
294                         } else {
295                                 view.find( ".ui-handler" ).hide();
296                                 view.find( ".ui-scrollbar" ).show();
297                         }
298                 },
299
300                 _setHandlerTheme: function ( handlerTheme ) {
301                         if ( !handlerTheme ) {
302                                 return;
303                         }
304
305                         var oldClass = "ui-handler-" + this.options.handlerTheme,
306                                 newClass = "ui-handler-" + handlerTheme;
307
308                         this.element.removeClass( oldClass ).addClass( newClass );
309                         this.options.handlerTheme = handlerTheme;
310                 },
311
312                 _setOption: function ( key, value ) {
313                         switch ( key ) {
314                         case "handler":
315                                 this.enableHandler( value );
316                                 break;
317                         case "handlerTheme":
318                                 this._setHandlerTheme( value );
319                                 break;
320                         default:
321                                 originSetOption.call( this, key, value );
322                         }
323                 },
324
325                 _handlerTimer : 0
326         });
327
328         $( document ).delegate( ":jqmData(scroll)", "scrollviewcreate", function () {
329                 var widget = $( this );
330                 if ( widget.attr( "data-" + $.mobile.ns + "scroll" ) === "none"
331                                 || widget.jqmData( "handler" ) !== true ) {
332                         return;
333                 }
334                 widget.scrollview( "enableHandler", "true" );
335         });
336 } ( jQuery, document ) );