Export 0.2.3
[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                         item.addClass('ui-swipe-item');
163                         coverTheme = defaultCoverTheme;
164                         itemHasThemeClass = item.parent().attr('class')
165                                         .match(/ui\-body\-[a-z]|ui\-bar\-[a-z]/);
166
167                         covers.each( function () {
168                                 var cover = $( this );
169
170                                 if ( itemHasThemeClass ) {
171                                         coverTheme = itemHasThemeClass[0];
172                                 }
173
174                                 cover.addClass('ui-swipe-item-cover');
175                                 cover.addClass( coverTheme );
176
177                                 if ( cover.has('.ui-swipe-item-cover-inner').length === 0 ) {
178                                         cover.wrapInner( $('<span/>').addClass('ui-swipe-item-cover-inner') );
179                                 }
180
181                                 if ( !( cover.data('animateRight') && cover.data('animateLeft') ) ) {
182                                         cover.data('animateRight', function () {
183                                                 self._animateCover( cover, 110 );
184                                         });
185
186                                         cover.data('animateLeft', function () {
187                                                 self._animateCover( cover, 0 );
188                                         });
189                                 }
190
191                                 // bind to synthetic events
192                                 item.bind( 'swipeleft', cover.data('animateLeft') );
193                                 cover.bind( 'swiperight', cover.data('animateRight') );
194                                 item.find( '.ui-btn' ).bind( 'vclick', cover.data('animateLeft') );
195                         } );
196
197                 },
198
199                 _cleanupDom: function () {
200                         var self = this,
201                                 defaultCoverTheme,
202                                 cover,
203                                 coverTheme = defaultCoverTheme,
204                                 item,
205                                 itemClass,
206                                 itemHasThemeClass,
207                                 text,
208                                 wrapper;
209
210                         defaultCoverTheme = 'ui-body-' + this.options.theme;
211
212                         this.element.removeClass('ui-swipe');
213
214                         // get the item covers
215                         cover = this.element.find(':jqmData(role="swipe-item-cover")');
216                         item = this.element.find(':jqmData(role="swipe-item")');
217
218                         item.removeClass('ui-swipe-item');
219                         cover.removeClass('ui-swipe-item-cover');
220
221                         itemClass = item.attr('class');
222                         itemHasThemeClass = itemClass &&
223                                 itemClass.match(/ui\-body\-[a-z]|ui\-bar\-[a-z]/);
224
225                         if ( itemHasThemeClass ) {
226                                 coverTheme = itemHasThemeClass[0];
227                         }
228
229                         cover.removeClass(coverTheme);
230
231                         // remove wrapper HTML
232                         wrapper = cover.find('.ui-swipe-item-cover-inner');
233                         wrapper.children().unwrap();
234                         text = wrapper.text();
235
236                         if ( text ) {
237                                 cover.append( text );
238                                 wrapper.remove();
239                         }
240
241                         // unbind swipe events
242                         if ( cover.data('animateRight') && cover.data('animateLeft') ) {
243                                 cover.unbind( 'swiperight', cover.data('animateRight') );
244                                 item.unbind( 'swipeleft', cover.data('animateLeft') );
245
246                                 // unbind clicks on buttons inside the item
247                                 item.find('.ui-btn').unbind( 'vclick', cover.data('animateLeft') );
248
249                                 cover.data( 'animateRight', null );
250                                 cover.data( 'animateLeft', null );
251                         }
252                 },
253
254                 // NB I tried to use CSS animations for this, but the performance
255                 // and appearance was terrible on Android 2.2 browser;
256                 // so I reverted to jQuery animations
257                 //
258                 // once the cover animation is done, the cover emits an
259                 // animationComplete event
260                 _animateCover: function ( cover, leftPercentage ) {
261                         var self = this,
262                                 animationOptions = {
263                                         easing: 'linear',
264                                         duration: 'fast',
265                                         queue: true,
266                                         complete: function () {
267                                                 cover.trigger('animationComplete');
268                                         }
269                                 };
270
271                         $( this.element.parent() )
272                                 .find(":jqmData(role='swipe')")
273                                 .each(
274                                         function () {
275                                                 if ( this !== self.element.get(0) &&
276                                                                 $( this ).swipe("opened") ) {
277                                                         $( this ).swipe("close");
278                                                 }
279                                         }
280                                 );
281
282                         if ( leftPercentage == 110 ) {
283                                 this._isopen = true;
284                         } else {
285                                 this._isopen = false;
286                         }
287
288                         cover.stop();
289                         cover.clearQueue();
290                         cover.trigger('animationStart');
291                         cover.animate( {left: leftPercentage + '%'}, animationOptions );
292                 },
293
294                 destroy: function () {
295                         this._cleanupDom();
296                 },
297
298                 open: function () {
299                         var self = this;
300
301                         $( self._covers ).each( function () {
302                                 var cover = $( this );
303                                 self._animateCover( cover, 110 );
304                         } );
305                 },
306
307                 opened: function () {
308                         return this._isopen;
309                 },
310
311                 close: function () {
312                         var self = this;
313
314                         $( self._covers ).each( function () {
315                                 var cover = $( this );
316                                 self._animateCover( cover, 0 );
317                         } );
318                 }
319
320         });
321
322         $( document ).bind("pagecreate", function ( e ) {
323                 $( e.target ).find(":jqmData(role='swipe')").swipe();
324         });
325
326 }( jQuery ));