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) 2011 by Intel Corporation Ltd.
10 * Permission is hereby granted, free of charge, to any person obtaining a
11 * copy of this software and associated documentation files (the "Software"),
12 * to deal in the Software without restriction, including without limitation
13 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14 * and/or sell copies of the Software, and to permit persons to whom the
15 * Software is furnished to do so, subject to the following conditions:
17 * The above copyright notice and this permission notice shall be included in
18 * all copies or substantial portions of the Software.
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 * DEALINGS IN THE SOFTWARE.
27 * ***************************************************************************
29 * Authors: Elliot Smith <elliot.smith@intel.com>
32 // shortcutscroll is a scrollview controller, which binds
33 // a scrollview to a a list of short cuts; the shortcuts are built
34 // from the text on dividers in the list. Clicking on a shortcut
35 // instantaneously jumps the scrollview to the selected list divider;
36 // mouse movements on the shortcut column move the scrollview to the
37 // list divider matching the text currently under the touch; a popup
38 // with the text currently under the touch is also displayed.
40 // To apply, add the attribute data-shortcutscroll="true" to a listview
41 // (a <ul> or <ol> element inside a page). Alternatively, call
42 // shortcutscroll() on an element.
44 // The closest element with class ui-scrollview-clip is used as the
45 // scrollview to be controlled.
47 // If a listview has no dividers or a single divider, the widget won't
50 (function( $, undefined ) {
52 $.widget( "tizen.shortcutscroll", $.mobile.widget, {
54 initSelector: ":jqmData(shortcutscroll)"
57 _create: function () {
58 var $el = this.element,
61 page = $el.closest(':jqmData(role="page")');
63 this.scrollview = $el.closest('.ui-scrollview-clip');
64 this.shortcutsContainer = $('<div class="ui-shortcutscroll"/>');
65 this.shortcutsList = $('<ul></ul>');
67 // popup for the hovering character
68 this.shortcutsContainer.append($('<div class="ui-shortcutscroll-popup"></div>'));
69 $popup = this.shortcutsContainer.find('.ui-shortcutscroll-popup');
71 this.shortcutsContainer.append(this.shortcutsList);
72 this.scrollview.append(this.shortcutsContainer);
74 // find the bottom of the last item in the listview
75 this.lastListItem = $el.children().last();
77 // remove scrollbars from scrollview
78 this.scrollview.find('.ui-scrollbar').hide();
80 var jumpToDivider = function(divider) {
81 // get the vertical position of the divider (so we can
83 var dividerY = $(divider).position().top;
85 // find the bottom of the last list item
86 var bottomOffset = self.lastListItem.outerHeight(true) +
87 self.lastListItem.position().top;
89 var scrollviewHeight = self.scrollview.height();
91 // check that after the candidate scroll, the bottom of the
92 // last item will still be at the bottom of the scroll view
93 // and not some way up the page
94 var 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 var dstOffset = self.scrollview.offset();
105 $popup.text($(divider).text())
106 .offset({left : dstOffset.left + (self.scrollview.width() - $popup.width()) / 2,
107 top : dstOffset.top + (self.scrollview.height() - $popup.height()) / 2})
112 // bind mouse over so it moves the scroller to the divider
113 .bind('touchstart mousedown vmousedown touchmove vmousemove vmouseover', function (e) {
114 // Get coords relative to the element
115 var coords = $.mobile.tizen.targetRelativeCoordsFromEvent(e);
116 var shortcutsListOffset = self.shortcutsList.offset();
118 // If the element is a list item, get coordinates relative to the shortcuts list
119 if (e.target.tagName.toLowerCase() === "li") {
120 coords.x += $(e.target).offset().left - shortcutsListOffset.left;
121 coords.y += $(e.target).offset().top - shortcutsListOffset.top;
124 // Hit test each list item
125 self.shortcutsList.find('li').each(function() {
126 var listItem = $(this),
127 l = listItem.offset().left - shortcutsListOffset.left,
128 t = listItem.offset().top - shortcutsListOffset.top,
129 r = l + Math.abs(listItem.outerWidth(true)),
130 b = t + Math.abs(listItem.outerHeight(true));
132 if (coords.x >= l && coords.x <= r && coords.y >= t && coords.y <= b) {
133 jumpToDivider($(listItem.data('divider')));
142 // bind mouseout of the shortcutscroll container to remove popup
143 .bind('touchend mouseup vmouseup vmouseout', function () {
147 if (page && !(page.is(':visible'))) {
148 page.bind('pageshow', function () { self.refresh(); });
154 // refresh the list when dividers are filtered out
155 $el.bind('updatelayout', function () {
160 refresh: function () {
165 this.shortcutsList.find('li').remove();
167 // get all the dividers from the list and turn them into
169 var dividers = this.element.find('.ui-li-divider');
171 // get all the list items
172 var listItems = this.element.find('li:not(.ui-li-divider))');
174 // only use visible dividers
175 dividers = dividers.filter(':visible');
176 listItems = listItems.filter(':visible');
178 if (dividers.length < 2) {
179 this.shortcutsList.hide();
183 this.shortcutsList.show();
185 this.lastListItem = listItems.last();
187 dividers.each(function (index, divider) {
188 self.shortcutsList.append($('<li>' + $(divider).text() + '</li>')
189 .data('divider', divider));
192 // position the shortcut flush with the top of the first
194 shortcutsTop = dividers.first().position().top;
195 this.shortcutsContainer.css('top', shortcutsTop);
197 // make the scrollview clip tall enough to show the whole of
199 minClipHeight = shortcutsTop + this.shortcutsContainer.outerHeight() + 'px';
200 this.scrollview.css('min-height', minClipHeight);
204 $(document).bind( "pagecreate create", function (e) {
205 $($.tizen.shortcutscroll.prototype.options.initSelector, e.target)
206 .not(":jqmData(role='none'), :jqmData(role='nojs')")