Tizen 2.1 base
[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) 2011 by Intel Corporation Ltd.
9  *
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:
16  *
17  * The above copyright notice and this permission notice shall be included in
18  * all copies or substantial portions of the Software.
19  *
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  * ***************************************************************************
28  *
29  * Authors: Elliot Smith <elliot.smith@intel.com>
30  */
31
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.
39 //
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.
43 //
44 // The closest element with class ui-scrollview-clip is used as the
45 // scrollview to be controlled.
46 //
47 // If a listview has no dividers or a single divider, the widget won't
48 // display.
49
50 (function( $, undefined ) {
51
52 $.widget( "tizen.shortcutscroll", $.mobile.widget, {
53     options: {
54         initSelector: ":jqmData(shortcutscroll)"
55     },
56
57     _create: function () {
58         var $el = this.element,
59             self = this,
60             $popup,
61             page = $el.closest(':jqmData(role="page")');
62
63         this.scrollview = $el.closest('.ui-scrollview-clip');
64         this.shortcutsContainer = $('<div class="ui-shortcutscroll"/>');
65         this.shortcutsList = $('<ul></ul>');
66
67         // popup for the hovering character
68         this.shortcutsContainer.append($('<div class="ui-shortcutscroll-popup"></div>'));
69         $popup = this.shortcutsContainer.find('.ui-shortcutscroll-popup');
70
71         this.shortcutsContainer.append(this.shortcutsList);
72         this.scrollview.append(this.shortcutsContainer);
73
74         // find the bottom of the last item in the listview
75         this.lastListItem = $el.children().last();
76
77         // remove scrollbars from scrollview
78         this.scrollview.find('.ui-scrollbar').hide();
79
80         var jumpToDivider = function(divider) {
81             // get the vertical position of the divider (so we can
82             // scroll to it)
83             var dividerY = $(divider).position().top;
84
85             // find the bottom of the last list item
86             var bottomOffset = self.lastListItem.outerHeight(true) +
87                                self.lastListItem.position().top;
88
89             var scrollviewHeight = self.scrollview.height();
90
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);
96
97             // don't apply a negative scroll, as this means the
98             // divider should already be visible
99             dividerY = Math.max(dividerY, 0);
100
101             // apply the scroll
102             self.scrollview.scrollview('scrollTo', 0, -dividerY);
103
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})
108                   .show();
109         };
110
111         this.shortcutsList
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();
117
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;
122             }
123
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));
131
132                 if (coords.x >= l && coords.x <= r && coords.y >= t && coords.y <= b) {
133                     jumpToDivider($(listItem.data('divider')));
134                     return false;
135                 }
136                 return true;
137             });
138
139             e.preventDefault();
140             e.stopPropagation();
141         })
142         // bind mouseout of the shortcutscroll container to remove popup
143         .bind('touchend mouseup vmouseup vmouseout', function () {
144             $popup.hide();
145         });
146
147         if (page && !(page.is(':visible'))) {
148             page.bind('pageshow', function () { self.refresh(); });
149         }
150         else {
151             this.refresh();
152         }
153
154         // refresh the list when dividers are filtered out
155         $el.bind('updatelayout', function () {
156             self.refresh();
157         });
158     },
159
160     refresh: function () {
161         var self = this,
162             shortcutsTop,
163             minClipHeight;
164
165         this.shortcutsList.find('li').remove();
166
167         // get all the dividers from the list and turn them into
168         // shortcuts
169         var dividers = this.element.find('.ui-li-divider');
170
171         // get all the list items
172         var listItems = this.element.find('li:not(.ui-li-divider))');
173
174         // only use visible dividers
175         dividers = dividers.filter(':visible');
176         listItems = listItems.filter(':visible');
177
178         if (dividers.length < 2) {
179             this.shortcutsList.hide();
180             return;
181         }
182
183         this.shortcutsList.show();
184
185         this.lastListItem = listItems.last();
186
187         dividers.each(function (index, divider) {
188             self.shortcutsList.append($('<li>' + $(divider).text() + '</li>')
189                               .data('divider', divider));
190         });
191
192         // position the shortcut flush with the top of the first
193         // list divider
194         shortcutsTop = dividers.first().position().top;
195         this.shortcutsContainer.css('top', shortcutsTop);
196
197         // make the scrollview clip tall enough to show the whole of
198         // the shortcutslist
199         minClipHeight = shortcutsTop + this.shortcutsContainer.outerHeight() + 'px';
200         this.scrollview.css('min-height', minClipHeight);
201     }
202 });
203
204 $(document).bind( "pagecreate create", function (e) {
205     $($.tizen.shortcutscroll.prototype.options.initSelector, e.target)
206     .not(":jqmData(role='none'), :jqmData(role='nojs')")
207     .shortcutscroll();
208 });
209
210 })( jQuery );