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