tizen beta release
[platform/framework/web/web-ui-fw.git] / src / widgets / swipelist / js / jquery.mobile.tizen.swipelist.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: Kalyan Kondapally <kalyan.kondapally@intel.com>,
30  *          Elliot Smith <elliot.smith@intel.com>
31  */
32
33 // Widget which turns a list into a "swipe list":
34 // i.e. each list item has a sliding "cover" which can be swiped
35 // to the right (to reveal buttons underneath) or left (to
36 // cover the buttons again). Clicking on a button under a swipelist
37 // also moves the cover back to the left.
38 //
39 // To create a swipelist, you need markup like this:
40 //
41 // <pre>
42 // &lt;ul data-role="swipelist"&gt;<br/>
43 //     &lt;li&gt;<br/>
44 //         &lt;div class="ui-grid-b"&gt;<br/>
45 //             &lt;div class="ui-block-a"&gt;<br/>
46 //                 &lt;a href="#" data-role="button" data-theme="a"&gt;Twitter&lt;/a&gt;<br/>
47 //             &lt;/div&gt;<br/>
48 //             &lt;div class="ui-block-b"&gt;<br/>
49 //                 &lt;a href="#" data-role="button" data-theme="b"&gt;FaceBook&lt;/a&gt;<br/>
50 //             &lt;/div&gt;<br/>
51 //             &lt;div class="ui-block-c"&gt;<br/>
52 //                 &lt;a href="#" data-role="button" data-theme="c"&gt;Google+&lt;/a&gt;<br/>
53 //             &lt;/div&gt;<br/>
54 //         &lt;/div&gt;<br/>
55 //         &lt;div data-role="swipelist-item-cover"&gt;Nigel&lt;/div&gt;<br/>
56 //     &lt;/li&gt;<br/>
57 //     ...<br/>
58 // &lt;/ul&gt;
59 // </pre>
60 //
61 // In this case, the cover is over a grid of buttons;
62 // but it is should also be possible to use other types of markup under the
63 // list items.
64 //
65 // Note the use of a separate div, parented by the li element, marked
66 // up with data-role="swipelist-item-cover". This div will usually
67 // contain text. If you want other elements in your swipelist covers,
68 // you may need to style them yourself. Because the covers aren't
69 // technically list items, you may need to do some work to make them
70 // look right.
71 //
72 // WARNING: This doesn't work well inside a scrollview widget, as
73 // the touch events currently interfere with each other badly (e.g.
74 // a swipe will work but cause a scroll as well).
75 //
76 // Theme: default is to use the theme on the target element,
77 // theme passed in options, parent theme, or 'c' if none of the above.
78 // If list items are themed individually, the cover will pick up the
79 // theme of the list item which is its parent.
80 //
81 // Events:
82 //
83 //   animationComplete: Triggered by a cover when it finishes sliding
84 //                      (to either the right or left).
85 (function ($) {
86
87 $.widget("tizen.swipelist", $.mobile.widget, {
88     options: {
89         theme: null
90     },
91
92     _create: function () {
93         // use the theme set on the element, set in options,
94         // the parent theme, or 'c' (in that order of preference)
95         var theme = this.element.jqmData('theme') ||
96                     this.options.theme ||
97                     this.element.parent().jqmData('theme') ||
98                     'c';
99
100         this.options.theme = theme;
101
102         this.refresh();
103     },
104
105     refresh: function () {
106         this._cleanupDom();
107
108         var self = this,
109             defaultCoverTheme,
110             covers;
111
112         defaultCoverTheme = 'ui-body-' + this.options.theme;
113
114         // swipelist is a listview
115         if (!this.element.hasClass('ui-listview')) {
116             this.element.listview();
117         }
118
119         this.element.addClass('ui-swipelist');
120
121         // get the list item covers
122         covers = this.element.find(':jqmData(role="swipelist-item-cover")');
123
124         covers.each(function () {
125             var cover = $(this);
126             var coverTheme = defaultCoverTheme;
127
128             // get the parent li element and add classes
129             var item = cover.closest('li');
130
131             // add swipelist CSS classes
132             item.addClass('ui-swipelist-item');
133
134             cover.addClass('ui-swipelist-item-cover');
135
136             // set swatch on cover: if the nearest list item has
137             // a swatch set on it, that will be used; otherwise, use
138             // the swatch set for the swipelist
139             var itemHasThemeClass = item.attr('class')
140                                         .match(/ui\-body\-[a-z]|ui\-bar\-[a-z]/);
141
142             if (itemHasThemeClass) {
143                 coverTheme = itemHasThemeClass[0];
144             }
145
146             cover.addClass(coverTheme);
147
148             // wrap inner HTML (so it can potentially be styled)
149             if (cover.has('.ui-swipelist-item-cover-inner').length === 0) {
150                 cover.wrapInner($('<span/>').addClass('ui-swipelist-item-cover-inner'));
151             }
152
153             // bind to swipe events on the cover and the item
154             if (!(cover.data('animateRight') && cover.data('animateLeft'))) {
155                 cover.data('animateRight', function () {
156                     self._animateCover(cover, 100);
157                 });
158
159                 cover.data('animateLeft', function () {
160                     self._animateCover(cover, 0);
161                 });
162             }
163
164             // bind to synthetic events
165             item.bind('swipeleft', cover.data('animateLeft'));
166             cover.bind('swiperight', cover.data('animateRight'));
167
168             // any clicks on buttons inside the item also trigger
169             // the cover to slide back to the left
170             item.find('.ui-btn').bind('vclick', cover.data('animateLeft'));
171         });
172     },
173
174     _cleanupDom: function () {
175         var self = this,
176             defaultCoverTheme,
177             covers;
178
179         defaultCoverTheme = 'ui-body-' + this.options.theme;
180
181         this.element.removeClass('ui-swipelist');
182
183         // get the list item covers
184         covers = this.element.find(':jqmData(role="swipelist-item-cover")');
185
186         covers.each(function () {
187             var cover = $(this);
188             var coverTheme = defaultCoverTheme;
189             var text, wrapper;
190
191             // get the parent li element and add classes
192             var item = cover.closest('li');
193
194             // remove swipelist CSS classes
195             item.removeClass('ui-swipelist-item');
196             cover.removeClass('ui-swipelist-item-cover');
197
198             // remove swatch from cover: if the nearest list item has
199             // a swatch set on it, that will be used; otherwise, use
200             // the swatch set for the swipelist
201             var itemClass = item.attr('class');
202             var itemHasThemeClass = itemClass &&
203                                     itemClass.match(/ui\-body\-[a-z]|ui\-bar\-[a-z]/);
204
205             if (itemHasThemeClass) {
206                 coverTheme = itemHasThemeClass[0];
207             }
208
209             cover.removeClass(coverTheme);
210
211             // remove wrapper HTML
212             wrapper = cover.find('.ui-swipelist-item-cover-inner');
213
214             wrapper.children().unwrap();
215
216             text = wrapper.text()
217
218             if (text) {
219               cover.append(text);
220               wrapper.remove();
221             }
222
223             // unbind swipe events
224             if (cover.data('animateRight') && cover.data('animateLeft')) {
225                 cover.unbind('swiperight', cover.data('animateRight'));
226                 item.unbind('swipeleft', cover.data('animateLeft'));
227
228                 // unbind clicks on buttons inside the item
229                 item.find('.ui-btn').unbind('vclick', cover.data('animateLeft'));
230
231                 cover.data('animateRight', null);
232                 cover.data('animateLeft', null);
233             }
234         });
235     },
236
237     // NB I tried to use CSS animations for this, but the performance
238     // and appearance was terrible on Android 2.2 browser;
239     // so I reverted to jQuery animations
240     //
241     // once the cover animation is done, the cover emits an
242     // animationComplete event
243     _animateCover: function (cover, leftPercentage) {
244         var animationOptions = {
245           easing: 'linear',
246           duration: 'fast',
247           queue: true,
248           complete: function () {
249               cover.trigger('animationComplete');
250           }
251         };
252
253         cover.stop();
254         cover.clearQueue();
255         cover.animate({left: '' + leftPercentage + '%'}, animationOptions);
256     },
257
258     destroy: function () {
259       this._cleanupDom();
260     }
261
262 });
263
264 $(document).bind("pagecreate", function (e) {
265     $(e.target).find(":jqmData(role='swipelist')").swipelist();
266 });
267
268 })(jQuery);