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