2 * jQuery Mobile Widget @VERSION
4 * This software is licensed under the MIT licence (as defined by the OSI at
5 * http://www.opensource.org/licenses/mit-license.php)
7 * ***************************************************************************
8 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd.
9 * Copyright (c) 2011 by Intel Corporation Ltd.
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:
18 * The above copyright notice and this permission notice shall be included in
19 * all copies or substantial portions of the Software.
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 * ***************************************************************************
30 * Authors: Elliot Smith <elliot.smith@intel.com>
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.
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.
45 // The closest element with class ui-scrollview-clip is used as the
46 // scrollview to be controlled.
48 // If a listview has no dividers or a single divider, the widget won't
51 (function ( $, undefined ) {
53 $.widget( "tizen.shortcutscroll", $.mobile.widget, {
55 initSelector: ":jqmData(shortcutscroll)"
58 _create: function () {
59 var $el = this.element,
62 page = $el.closest( ':jqmData(role="page")' ),
65 this.scrollview = $el.closest( '.ui-scrollview-clip' );
66 this.shortcutsContainer = $( '<div class="ui-shortcutscroll"/>' );
67 this.shortcutsList = $( '<ul></ul>' );
69 // popup for the hovering character
70 this.shortcutsContainer.append($( '<div class="ui-shortcutscroll-popup"></div>' ) );
71 $popup = this.shortcutsContainer.find( '.ui-shortcutscroll-popup' );
73 this.shortcutsContainer.append( this.shortcutsList );
74 this.scrollview.append( this.shortcutsContainer );
76 // find the bottom of the last item in the listview
77 this.lastListItem = $el.children().last();
79 // remove scrollbars from scrollview
80 this.scrollview.find( '.ui-scrollbar' ).hide();
82 jumpToDivider = function ( divider ) {
83 // get the vertical position of the divider (so we can scroll to it)
84 var dividerY = $( divider ).position().top,
85 // find the bottom of the last list item
86 bottomOffset = self.lastListItem.outerHeight( true ) + self.lastListItem.position().top,
87 scrollviewHeight = self.scrollview.height(),
89 // check that after the candidate scroll, the bottom of the
90 // last item will still be at the bottom of the scroll view
91 // and not some way up the page
92 maxScroll = bottomOffset - scrollviewHeight,
95 dividerY = ( dividerY > maxScroll ? maxScroll : dividerY );
97 // don't apply a negative scroll, as this means the
98 // divider should already be visible
99 dividerY = Math.max( dividerY, 0 );
102 self.scrollview.scrollview( 'scrollTo', 0, -dividerY );
104 dstOffset = self.scrollview.offset();
106 .text( $( divider ).text() )
107 .offset( { left : dstOffset.left + ( self.scrollview.width() - $popup.width() ) / 2,
108 top : dstOffset.top + ( self.scrollview.height() - $popup.height() ) / 2 } )
113 // bind mouse over so it moves the scroller to the divider
114 .bind( 'touchstart mousedown vmousedown touchmove vmousemove vmouseover ', function ( e ) {
115 // Get coords relative to the element
116 var coords = $.mobile.tizen.targetRelativeCoordsFromEvent( e ),
117 shortcutsListOffset = self.shortcutsList.offset();
119 // If the element is a list item, get coordinates relative to the shortcuts list
120 if ( e.target.tagName.toLowerCase() === "li" ) {
121 coords.x += $( e.target ).offset().left - shortcutsListOffset.left;
122 coords.y += $( e.target ).offset().top - shortcutsListOffset.top;
125 self.shortcutsList.find( 'li' ).each( function () {
126 var listItem = $( this );
128 .removeClass( "ui-shortcutscroll-hover" )
129 .removeClass( "ui-shortcutscroll-hover-up" )
130 .removeClass( "ui-shortcutscroll-hover-down" );
132 // Hit test each list item
133 self.shortcutsList.find( 'li' ).each( function () {
134 var listItem = $( this ),
135 l = listItem.offset().left - shortcutsListOffset.left,
136 t = listItem.offset().top - shortcutsListOffset.top,
137 r = l + Math.abs(listItem.outerWidth( true ) ),
138 b = t + Math.abs(listItem.outerHeight( true ) );
140 if ( coords.x >= l && coords.x <= r && coords.y >= t && coords.y <= b ) {
141 jumpToDivider( $( listItem.data( 'divider' ) ) );
142 $( listItem ).addClass( "ui-shortcutscroll-hover" );
143 if ( listItem.index() > 0 )
144 $( listItem ).siblings().eq( listItem.index() - 1 ).addClass( "ui-shortcutscroll-hover-up" );
145 $( listItem ).siblings().eq( listItem.index() ).addClass( "ui-shortcutscroll-hover-down" );
156 // bind mouseout of the shortcutscroll container to remove popup
157 .bind( 'touchend mouseup vmouseup vmouseout', function () {
161 if ( page && !( page.is( ':visible' ) ) ) {
162 page.bind( 'pageshow', function () { self.refresh(); } );
167 // refresh the list when dividers are filtered out
168 $el.bind( 'updatelayout', function () {
173 refresh: function () {
180 this.shortcutsList.find( 'li' ).remove();
182 // get all the dividers from the list and turn them into shortcuts
183 dividers = this.element.find( '.ui-li-divider' );
185 // get all the list items
186 listItems = this.element.find( 'li:not(.ui-li-divider)) ');
188 // only use visible dividers
189 dividers = dividers.filter( ':visible' );
190 listItems = listItems.filter( ':visible' );
192 if ( dividers.length < 2 ) {
193 this.shortcutsList.hide();
197 this.shortcutsList.show();
199 this.lastListItem = listItems.last();
201 dividers.each( function ( index, divider ) {
203 .append( $( '<li>' + $( divider ).text() + '</li>' )
204 .data( 'divider', divider ) );
207 // position the shortcut flush with the top of the first list divider
208 shortcutsTop = dividers.first().position().top;
209 this.shortcutsContainer.css( 'top', shortcutsTop );
211 // make the scrollview clip tall enough to show the whole of the shortcutslist
212 minClipHeight = shortcutsTop + this.shortcutsContainer.outerHeight() + 'px';
213 this.scrollview.css( 'min-height', minClipHeight );
217 $( document ).bind( "pagecreate create", function ( e ) {
218 $( $.tizen.shortcutscroll.prototype.options.initSelector, e.target )
219 .not( ":jqmData(role='none'), :jqmData(role='nojs')" )