0bbfacf37aac6028ceaf37135329bbebac0502b1
[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 list 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 list view on the screen where the list items can be swiped vertically to show a menu.
58         To add a swipe list widget to the application, use the following code:
59
60                 <ul data-role="swipe">
61                         <li>
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 list view methods.
74 */
75 /**
76         @property {String} data-role
77         Creates a swipe list using the HTML unordered list (&gt;ul&lt;) element.
78         The default value is swipe.
79
80         Creates a swipe list 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 swipelist-item-cover.
82 */
83 /**
84         @method open
85         uncover swipelist item
86 */
87 /**
88         @method close
89         cover swipelist item
90 */
91 /**
92         @method isOpen
93         return coveritem status( coverd or uncovred )
94 */
95 /**
96         @event animationstart
97         The swipe list can define a callback for the animationstart event, which is fired after a list item is swipe and the swipe animation is start:
98 */
99 /**
100         @event animationend
101         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:
102
103                 <ul data-role="swipelist">
104                 <li>
105                                 <div data-role="button" data-inline="true">OK</div>
106                                 <div data-role="button" data-inline="true">Cancel</div>
107                                 <div data-role="swipelist-item-cover" id="foo">
108                                 <p>This is a swipelist item cover.<br>
109                                                 This will be swiped out when swipe event comes.</p>
110                                 </div>
111                         </li>
112                 </ul>
113                 $("#foo").bind("animationend", function (ev)
114                 {
115                         Console.log("Swipelist cover's animation is complete.");
116                 });
117 */
118 (function ($) {
119
120         $.widget("tizen.swipe", $.mobile.widget, {
121                 options: {
122                         theme: null
123                 },
124
125                 _create: function () {
126                         // use the theme set on the element, set in options,
127                         // the parent theme, or 'c' (in that order of preference)
128                         var theme = this.element.jqmData('theme') ||
129                                 this.options.theme ||
130                                 this.element.parent().jqmData('theme') ||
131                                 's';
132
133                         this.options.theme = theme;
134                         this._isopen = false;
135                         this.refresh();
136                 },
137
138                 refresh: function () {
139                         this._cleanupDom();
140
141                         var self = this,
142                                 defaultCoverTheme,
143                                 covers,
144                                 coverTheme,
145                                 item,
146                                 itemHasThemeClass;
147
148                         defaultCoverTheme = 'ui-body-' + this.options.theme;
149
150                         // swipe is a listview
151                         if ( !this.element.parent().hasClass('ui-listview') ) {
152                                 this.element.parent().listview();
153                         }
154                         this.element.addClass('ui-swipe');
155
156                         // get the list item covers
157                         covers = this.element.find(':jqmData(role="swipe-item-cover")');
158                         item = this.element.find(':jqmData(role="swipe-item")');
159
160                         this._covers = covers;
161                         item.addClass('ui-swipe-item');
162                         coverTheme = defaultCoverTheme;
163                         itemHasThemeClass = item.parent().attr('class')
164                                         .match(/ui\-body\-[a-z]|ui\-bar\-[a-z]/);
165
166                         covers.each( function () {
167                                 var cover = $( this );
168
169                                 if ( itemHasThemeClass ) {
170                                         coverTheme = itemHasThemeClass[0];
171                                 }
172
173                                 cover.addClass('ui-swipe-item-cover');
174                                 cover.addClass( coverTheme );
175
176                                 if ( cover.has('.ui-swipe-item-cover-inner').length === 0 ) {
177                                         cover.wrapInner( $('<span/>').addClass('ui-swipe-item-cover-inner') );
178                                 }
179
180                                 if ( !( cover.data('animateRight') && cover.data('animateLeft') ) ) {
181                                         cover.data('animateRight', function () {
182                                                 self._animateCover( cover, 110 );
183                                         });
184
185                                         cover.data('animateLeft', function () {
186                                                 self._animateCover( cover, 0 );
187                                         });
188                                 }
189
190                                 // bind to synthetic events
191                                 item.bind( 'swipeleft', cover.data('animateLeft') );
192                                 cover.bind( 'swiperight', cover.data('animateRight') );
193                                 item.find( '.ui-btn' ).bind( 'vclick', cover.data('animateLeft') );
194                         } );
195
196                 },
197
198                 _cleanupDom: function () {
199                         var self = this,
200                                 defaultCoverTheme,
201                                 cover,
202                                 coverTheme = defaultCoverTheme,
203                                 item,
204                                 itemClass,
205                                 itemHasThemeClass,
206                                 text,
207                                 wrapper;
208
209                         defaultCoverTheme = 'ui-body-' + this.options.theme;
210
211                         this.element.removeClass('ui-swipe');
212
213                         // get the list item covers
214                         cover = this.element.find(':jqmData(role="swipe-item-cover")');
215                         item = this.element.find(':jqmData(role="swipe-item")');
216
217                         item.removeClass('ui-swipe-item');
218                         cover.removeClass('ui-swipe-item-cover');
219
220                         itemClass = item.attr('class');
221                         itemHasThemeClass = itemClass &&
222                                 itemClass.match(/ui\-body\-[a-z]|ui\-bar\-[a-z]/);
223
224                         if ( itemHasThemeClass ) {
225                                 coverTheme = itemHasThemeClass[0];
226                         }
227
228                         cover.removeClass(coverTheme);
229
230                         // remove wrapper HTML
231                         wrapper = cover.find('.ui-swipe-item-cover-inner');
232                         wrapper.children().unwrap();
233                         text = wrapper.text();
234
235                         if ( text ) {
236                                 cover.append( text );
237                                 wrapper.remove();
238                         }
239
240                         // unbind swipe events
241                         if ( cover.data('animateRight') && cover.data('animateLeft') ) {
242                                 cover.unbind( 'swiperight', cover.data('animateRight') );
243                                 item.unbind( 'swipeleft', cover.data('animateLeft') );
244
245                                 // unbind clicks on buttons inside the item
246                                 item.find('.ui-btn').unbind( 'vclick', cover.data('animateLeft') );
247
248                                 cover.data( 'animateRight', null );
249                                 cover.data( 'animateLeft', null );
250                         }
251                 },
252
253                 // NB I tried to use CSS animations for this, but the performance
254                 // and appearance was terrible on Android 2.2 browser;
255                 // so I reverted to jQuery animations
256                 //
257                 // once the cover animation is done, the cover emits an
258                 // animationComplete event
259                 _animateCover: function ( cover, leftPercentage ) {
260                         var self = this,
261                                 animationOptions = {
262                                         easing: 'linear',
263                                         duration: 'fast',
264                                         queue: true,
265                                         complete: function () {
266                                                 cover.trigger('animationComplete');
267                                         }
268                                 };
269
270                         $( this.element.parent() )
271                                 .find(":jqmData(role='swipe')")
272                                 .each(
273                                         function () {
274                                                 if ( this !== self.element.get(0) &&
275                                                                 $( this ).swipe("isOpen") ) {
276                                                         $( this ).swipe("close");
277                                                 }
278                                         }
279                                 );
280
281                         if ( leftPercentage == 110 ) {
282                                 this._isopen = true;
283                         } else {
284                                 this._isopen = false;
285                         }
286
287                         cover.stop();
288                         cover.clearQueue();
289                         cover.trigger('animationStart');
290                         cover.animate( {left: leftPercentage + '%'}, animationOptions );
291                 },
292
293                 destroy: function () {
294                         this._cleanupDom();
295                 },
296
297                 open: function () {
298                         var self = this;
299
300                         $( self._covers ).each( function () {
301                                 var cover = $( this );
302                                 self._animateCover( cover, 110 );
303                         } );
304                 },
305
306                 isOpen: function () {
307                         return this._isopen;
308                 },
309
310                 close: function () {
311                         var self = this;
312
313                         $( self._covers ).each( function () {
314                                 var cover = $( this );
315                                 self._animateCover( cover, 0 );
316                         } );
317                 }
318
319         });
320
321         $( document ).bind("pagecreate", function ( e ) {
322                 $( e.target ).find(":jqmData(role='swipe')").swipe();
323         });
324
325 }( jQuery ));