Export 0.1.63
[platform/framework/web/web-ui-fw.git] / src / widgets / shortcutscroll / js / jquery.mobile.tizen.shortcutscroll.js
1 /*
2  * jQuery Mobile Widget @VERSION
3  *
4  * This software is licensed under the MIT licence (as defined by the OSI at
5  * http://www.opensource.org/licenses/mit-license.php)
6  *
7  * ***************************************************************************
8  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd.
9  * Copyright (c) 2011 by Intel Corporation Ltd.
10  *
11  * Permission is hereby granted, free of charge, to any person obtaining a
12  * copy of this software and associated documentation files (the "Software"),
13  * to deal in the Software without restriction, including without limitation
14  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15  * and/or sell copies of the Software, and to permit persons to whom the
16  * Software is furnished to do so, subject to the following conditions:
17  *
18  * The above copyright notice and this permission notice shall be included in
19  * all copies or substantial portions of the Software.
20  *
21  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27  * DEALINGS IN THE SOFTWARE.
28  * ***************************************************************************
29  *
30  * Authors: Elliot Smith <elliot.smith@intel.com>
31  */
32
33 // shortcutscroll is a scrollview controller, which binds
34 // a scrollview to a a list of short cuts; the shortcuts are built
35 // from the text on dividers in the list. Clicking on a shortcut
36 // instantaneously jumps the scrollview to the selected list divider;
37 // mouse movements on the shortcut column move the scrollview to the
38 // list divider matching the text currently under the touch; a popup
39 // with the text currently under the touch is also displayed.
40 //
41 // To apply, add the attribute data-shortcutscroll="true" to a listview
42 // (a <ul> or <ol> element inside a page). Alternatively, call
43 // shortcutscroll() on an element.
44 //
45 // The closest element with class ui-scrollview-clip is used as the
46 // scrollview to be controlled.
47 //
48 // If a listview has no dividers or a single divider, the widget won't
49 // display.
50
51 /**
52         @class ShortcutScroll
53         The shortcut scroll widget shows a shortcut list that is bound to its parent scroll bar and respective list view. This widget is displayed as a text pop-up representing shortcuts to different list dividers in the list view. If you select a shortcut text from the shortcut scroll, the parent list view is moved to the location representing the selected shortcut.
54
55         To add a shortcut scroll widget to the application, use the following code:
56
57                 <div class="content" data-role="content" data-scroll="y">
58                         <ul id="contacts" data-role="listview" data-shortcutscroll="true">
59                                 <li>Anton</li>
60                         </ul>
61                 </div>
62
63         For the shortcut scroll widget to be visible, the parent list view must have multiple list dividers.
64 */
65
66 /**
67         @property {Boolean}  data-shortcutscroll
68         When set to true, creates a shortcut scroll using the HTML unordered list (&lt;ul&gt;) element.
69 */
70 /**
71         @method shortcutscroll
72         The shortcut scroll is created for the closest list view with the ui-scrollview-clip class.
73 */
74 (function ( $, undefined ) {
75
76         $.widget( "tizen.shortcutscroll", $.mobile.widget, {
77                 options: {
78                         initSelector: ":jqmData(shortcutscroll)"
79                 },
80
81                 _create: function () {
82                         var $el = this.element,
83                                 self = this,
84                                 $popup,
85                                 page = $el.closest( ':jqmData(role="page")' ),
86                                 jumpToDivider;
87
88                         this.scrollview = $el.closest( '.ui-scrollview-clip' );
89                         this.shortcutsContainer = $( '<div class="ui-shortcutscroll"/>' );
90                         this.shortcutsList = $( '<ul></ul>' );
91
92                         // popup for the hovering character
93                         this.shortcutsContainer.append($( '<div class="ui-shortcutscroll-popup"></div>' ) );
94                         $popup = this.shortcutsContainer.find( '.ui-shortcutscroll-popup' );
95
96                         this.shortcutsContainer.append( this.shortcutsList );
97                         this.scrollview.append( this.shortcutsContainer );
98
99                         // find the bottom of the last item in the listview
100                         this.lastListItem = $el.children().last();
101
102                         // remove scrollbars from scrollview
103                         this.scrollview.find( '.ui-scrollbar' ).hide();
104
105                         jumpToDivider = function ( divider ) {
106                                 // get the vertical position of the divider (so we can scroll to it)
107                                 var dividerY = $( divider ).position().top,
108                                         // find the bottom of the last list item
109                                         bottomOffset = self.lastListItem.outerHeight( true ) + self.lastListItem.position().top,
110                                         scrollviewHeight = self.scrollview.height(),
111
112                                 // check that after the candidate scroll, the bottom of the
113                                 // last item will still be at the bottom of the scroll view
114                                 // and not some way up the page
115                                         maxScroll = bottomOffset - scrollviewHeight,
116                                         dstOffset;
117
118                                 dividerY = ( dividerY > maxScroll ? maxScroll : dividerY );
119
120                                 // don't apply a negative scroll, as this means the
121                                 // divider should already be visible
122                                 dividerY = Math.max( dividerY, 0 );
123
124                                 // apply the scroll
125                                 self.scrollview.scrollview( 'scrollTo', 0, -dividerY );
126
127                                 dstOffset = self.scrollview.offset();
128                                 $popup
129                                         .text( $( divider ).text() )
130                                         .offset( { left : dstOffset.left + ( self.scrollview.width()  - $popup.width() ) / 2,
131                                                                 top  : dstOffset.top  + ( self.scrollview.height() - $popup.height() ) / 2 } )
132                                         .show();
133                         };
134
135                         this.shortcutsList
136                         // bind mouse over so it moves the scroller to the divider
137                                 .bind( 'touchstart mousedown vmousedown touchmove vmousemove vmouseover ', function ( e ) {
138                                         // Get coords relative to the element
139                                         var coords = $.mobile.tizen.targetRelativeCoordsFromEvent( e ),
140                                                 shortcutsListOffset = self.shortcutsList.offset();
141
142                                         // If the element is a list item, get coordinates relative to the shortcuts list
143                                         if ( e.target.tagName.toLowerCase() === "li" ) {
144                                                 coords.x += $( e.target ).offset().left - shortcutsListOffset.left;
145                                                 coords.y += $( e.target ).offset().top  - shortcutsListOffset.top;
146                                         }
147
148                                         self.shortcutsList.find( 'li' ).each( function () {
149                                                 var listItem = $( this );
150                                                 $( listItem )
151                                                         .removeClass( "ui-shortcutscroll-hover" )
152                                                         .removeClass( "ui-shortcutscroll-hover-up" )
153                                                         .removeClass( "ui-shortcutscroll-hover-down" );
154                                         });
155                                         // Hit test each list item
156                                         self.shortcutsList.find( 'li' ).each( function () {
157                                                 var listItem = $( this ),
158                                                         l = listItem.offset().left - shortcutsListOffset.left,
159                                                         t = listItem.offset().top  - shortcutsListOffset.top,
160                                                         r = l + Math.abs(listItem.outerWidth( true ) ),
161                                                         b = t + Math.abs(listItem.outerHeight( true ) );
162
163                                                 if ( coords.x >= l && coords.x <= r && coords.y >= t && coords.y <= b ) {
164                                                         jumpToDivider( $( listItem.data( 'divider' ) ) );
165                                                         $( listItem ).addClass( "ui-shortcutscroll-hover" );
166                                                         if ( listItem.index() > 0 )
167                                                                 $( listItem ).siblings().eq( listItem.index() - 1 ).addClass( "ui-shortcutscroll-hover-up" );
168                                                         $( listItem ).siblings().eq( listItem.index() ).addClass( "ui-shortcutscroll-hover-down" );
169                                                         return false;
170                                                 }
171                                                 return true;
172                                         } );
173
174
175
176                                         e.preventDefault();
177                                         e.stopPropagation();
178                                 } )
179                                 // bind mouseout of the shortcutscroll container to remove popup
180                                 .bind( 'touchend mouseup vmouseup vmouseout', function () {
181                                         $popup.hide();
182                                 } );
183
184                         if ( page && !( page.is( ':visible' ) ) ) {
185                                 page.bind( 'pageshow', function () { self.refresh(); } );
186                         } else {
187                                 this.refresh();
188                         }
189
190                         // refresh the list when dividers are filtered out
191                         $el.bind( 'updatelayout', function () {
192                                 self.refresh();
193                         } );
194                 },
195
196                 refresh: function () {
197                         var self = this,
198                                 shortcutsTop,
199                                 minClipHeight,
200                                 dividers,
201                                 listItems;
202
203                         this.shortcutsList.find( 'li' ).remove();
204
205                         // get all the dividers from the list and turn them into shortcuts
206                         dividers = this.element.find( '.ui-li-divider' );
207
208                         // get all the list items
209                         listItems = this.element.find( 'li:not(.ui-li-divider)) ');
210
211                         // only use visible dividers
212                         dividers = dividers.filter( ':visible' );
213                         listItems = listItems.filter( ':visible' );
214
215                         if ( dividers.length < 2 ) {
216                                 this.shortcutsList.hide();
217                                 return;
218                         }
219
220                         this.shortcutsList.show();
221
222                         this.lastListItem = listItems.last();
223
224                         dividers.each( function ( index, divider ) {
225                                 self.shortcutsList
226                                         .append( $( '<li>' + $( divider ).text() + '</li>' )
227                                                 .data( 'divider', divider ) );
228                         } );
229
230                         // position the shortcut flush with the top of the first list divider
231                         shortcutsTop = dividers.first().position().top;
232                         this.shortcutsContainer.css( 'top', shortcutsTop );
233
234                         // make the scrollview clip tall enough to show the whole of the shortcutslist
235                         minClipHeight = shortcutsTop + this.shortcutsContainer.outerHeight() + 'px';
236                         this.scrollview.css( 'min-height', minClipHeight );
237                 }
238         } );
239
240         $( document ).bind( "pagecreate create", function ( e ) {
241                 $( $.tizen.shortcutscroll.prototype.options.initSelector, e.target )
242                         .not( ":jqmData(role='none'), :jqmData(role='nojs')" )
243                         .shortcutscroll();
244         } );
245
246 } ( jQuery ) );