[TemporaryStorage] add files required for SDK build
[samples/web/TemporaryStorage.git] / tizen-web-ui-fw / latest / js / src / widgets / jquery.mobile.tizen.virtuallistview.js
1
2 /* ***************************************************************************
3  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd.
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in
13  * all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21  * DEALINGS IN THE SOFTWARE.
22  * ***************************************************************************
23  *
24  *      Author: Wongi Lee <wongi11.lee@samsung.com>
25  *              Youmin Ha <youmin.ha@samsung.com>
26  */
27
28 /**
29  * Virtual List Widget for unlimited data.
30  * To support more then 1,000 items, special list widget developed. 
31  * Fast initialize and light DOM tree.
32  * DB connection and works like DB cursor.
33  * 
34  * HTML Attributes:
35  *
36  *              data-role:      virtuallistview
37  *              data-template : jQuery.template ID that populate into virtual list 
38  *              data-row : Optional. Set number of <li> elements that are used for data handling. 
39  *              
40  *              ID : <UL> element that has "data-role=virtuallist" must have ID attribute.
41  *
42  * * APIs:
43  *
44  *              create ( {
45  *                              itemData: function ( idx ) { return json_obj; },
46  *                              numItemData: number or function () { return number; },
47  *                              cacheItemData: function ( minIdx, maxIdx ) {}
48  *                              } )
49  *                      : Create a virtuallist widget. At this moment, _create method is called.
50  *                      args : A collection of options
51  *                              itemData: A function that returns JSON object for given index. Mandatory.
52  *                              numItemData: Total number of itemData. Mandatory.
53  *                              cacheItemData: Virtuallist will ask itemData between minIdx and maxIdx.
54  *                                             Developers can implement this function for preparing data.
55  *                                             Optional.
56  *
57  * Events:
58  *
59  *              touchstart : Temporary preventDefault applied on touchstart event to avoid broken screen.
60  *
61  * Examples:
62  *
63  *              <script id="tmp-3-2-7" type="text/x-jquery-tmpl">
64  *                      <li class="ui-li-3-2-7">
65  *                              <span class="ui-li-text-main">${NAME}</span>
66  *                              <img src="00_winset_icon_favorite_on.png" class="ui-li-icon-sub">
67  *                              <span class="ui-li-text-sub">${ACTIVE}</span>
68  *                              <span class="ui-li-text-sub2">${FROM}</span>
69  *                      </li>
70  *              </script>
71  *
72  *              <ul id="virtuallist-normal_3_2_7_ul" data-role="virtuallistview" data-template="tmp-3-2-7" data-dbtable="JSON_DATA" data-row="100">
73  *              </ul>
74  *
75  */
76
77 /**
78         @class VirtualList
79         In the Web environment, it is challenging to display a large amount of data in a list, such as displaying a contact list of over 1000 list items. It takes time to display the entire list in HTML and the DOM manipulation is complex.
80
81         The virtual list widget is used to display a list of unlimited data elements on the screen for better performance. This widget provides easy access to databases to retrieve and display data. Virtual lists are based on the jQuery.template plugin as described in the jQuery documentation for jQuery.template plugin.
82
83         To add a virtual list widget to the application, use the following code:
84
85                 <script id="tmp-3-2-7" type="text/x-jquery-tmpl">
86                         <li class="ui-li-3-2-7">
87                                 <span class="ui-li-text-main">${NAME}</span>
88                                 <img src="00_winset_icon_favorite_on.png" class="ui-li-icon-sub"/>
89                                 <span class="ui-li-text-sub">${ACTIVE}</span>
90                                 <span class="ui-li-text-sub2">${FROM}</span>
91                         </li>
92                 </script>
93                 <ul id="vlist" data-role="virtuallistview" data-template="tmp-3-2-7" data-dbtable="JSON_DATA" data-row="100"></ul>
94 */
95 /**
96         @property {String} data-role
97         Creates the virtual list view. The value must be set to virtuallistview.
98         Only the &gt;ul&lt; element, which a id attribute defined, supports this option. Also, the vlLoadSuccess class attribute must be defined in the &gt;ul&lt; element to ensure that loading data from the database is complete.
99 */
100 /**
101         @property {String} data-template
102         Defines the jQuery.template element ID.
103         The jQuery.template must be defined. The template style can use rem units to support scalability.
104 */
105 /**
106         @property {Number} data-row
107         Defines the number of virtual list child elements.
108         The minimum value is 20 and the default value is 100. As the value gets higher, the loading time increases while the system performance improves. So you need to pick a value that provides the best performance without excessive loading time.
109 */
110 /**
111         @method create
112         @param {function} itemData(index)
113         : function itemData(index) returns the JSON object matched with the given index. The index value is between 0 and numItemData-1.
114         @param {Number} numItemData
115         : number numItemData or function numItemData() defines or returns a static number of items.
116         @param {function} cacheItemData(minIndex, maxIndex)
117         : function cacheItemData(minIndex, maxIndex) prepares the JSON data. This method is called before calling the itemData() method with index values between minIndex and maxIndex.
118 */
119
120 (function ( $, undefined ) {
121
122         /* Code for Virtual List Demo */
123         var listCountPerPage = {},      /* Keeps track of the number of lists per page UID. This allows support for multiple nested list in the same page. https://github.com/jquery/jquery-mobile/issues/1617 */
124                 _NO_SCROLL = 0,                                 /* ENUM */
125                 _SCROLL_DOWN = 1,                               /* ENUM */
126                 _SCROLL_UP = -1;                                        /* ENUM */
127
128         $.widget( "tizen.virtuallistview", $.mobile.widget, {
129                 options: {
130                         theme: "s",
131                         countTheme: "s",
132                         headerTheme: "s",
133                         dividerTheme: "s",
134                         splitIcon: "arrow-r",
135                         splitTheme: "s",
136                         inset: false,
137                         id:     "",                                     /* Virtual list UL elemet's ID */
138                         childSelector: " li",   /* To support swipe list */
139                         dbtable: "",
140                         template : "",
141                         dbkey: false,                   /* Data's unique Key */
142                         scrollview: false,
143                         row: 100,
144                         page_buf: 30,
145                         initSelector: ":jqmData(role='virtuallistview')"
146                 },
147
148                 _stylerMouseUp: function () {
149                         $( this ).addClass( "ui-btn-up-s" );
150                         $( this ).removeClass( "ui-btn-down-s" );
151                 },
152
153                 _stylerMouseDown: function () {
154                         $( this ).addClass( "ui-btn-down-s" );
155                         $( this ).removeClass( "ui-btn-up-s" );
156                 },
157
158                 _stylerMouseOver: function () {
159                         $( this ).toggleClass( "ui-btn-hover-s" );
160                 },
161
162                 _stylerMouseOut: function () {
163                         $( this ).toggleClass( "ui-btn-hover-s" );
164                         $( this ).addClass( "ui-btn-up-s" );
165                         $( this ).removeClass( "ui-btn-down-s" );
166                 },
167
168                 // ?
169                 // this         virtuallistview object
170                 // @param[in]   template        template name(string)
171                 _pushData: function ( template ) {
172                         var o = this.options,
173                                 i,
174                                 myTemplate = $( "#" + template ),       // Get template object
175                                 // NOTE: o.row = # of rows handled at once. Default value is 100.
176                                 lastIndex = ( o.row > this._numItemData ? this._numItemData : o.row ),  // last index of handled data
177                                 htmlData;
178
179                         for ( i = 0; i < lastIndex; i++ ) {
180                                 htmlData = myTemplate.tmpl( this._itemData( i ) );      // Make rows with template,
181                                 $( o.id ).append( $( htmlData ).attr( 'id', o.itemIDPrefix + i ) );     // and append it to the vlist object
182                         }
183
184                         // After pushing data re-style virtuallist widget
185                         $( o.id ).trigger( "create" );
186                 },
187
188                 // Set children <li> elements' position
189                 //
190                 // this: virtuallist element
191                 // event: virtuallistview.options
192                 //              TODO: Why this arg name is 'event'? Not resonable.
193                 //              (this function is not called with event element as args!)
194                 _reposition: function ( event ) {
195                         var o,
196                                 t = this,
197                                 padding,
198                                 margin;
199
200                         if ( event.data ) {
201                                 o = event.data;
202                         } else {
203                                 o = event;
204                         }
205                         if ( $( o.id + o.childSelector ).size() > 0 ) { // $("#vlistid li")
206                                 // first child's top position
207                                 // NOTE: the first element may not be '0'!!!
208                                 t._title_h = $( o.id + o.childSelector + ':first' ).position().top;
209                                 // first child's outer height (TODO: reuse selected items)
210                                 t._line_h = $( o.id + o.childSelector + ':first' ).outerHeight();
211
212                                 // container(vlist element)'s innerwidth
213                                 t._container_w = $( o.id ).innerWidth();
214
215                                 // get sum of container's left/right padding
216                                 padding = parseInt( $( o.id + o.childSelector ).css( "padding-left" ), 10 )
217                                         + parseInt( $( o.id + o.childSelector ).css( "padding-right" ), 10 );
218
219                                 // Add CSS to all <li> elements
220                                 //      * absolute position
221                                 //      * btn-up
222                                 //      * mouse up/down/over/out styles
223                                 $( o.id + ">" + o.childSelector )
224                                         .addClass( "position_absolute" )
225                                         .addClass( "ui-btn-up-s" )
226                                         .bind( "mouseup", t._stylerMouseUp )
227                                         .bind( "mousedown", t._stylerMouseDown )
228                                         .bind( "mouseover", t._stylerMouseOver )
229                                         .bind( "mouseout", t._stylerMouseOut );
230                         }
231
232                         // Set absolute top/left position of each <li>
233                         $( o.id + ">" + o.childSelector ).each( function ( index ) {
234                                 margin = parseInt( $( this ).css( "margin-left" ), 10 )
235                                         + parseInt( $( this ).css( "margin-right" ), 10 );
236
237                                 $( this ).css( "top", t._title_h + t._line_h * index + 'px' )
238                                         .css( "width", t._container_w - padding - margin );
239                         } );
240
241                         // Set Max Listview Height
242                         $( o.id ).height( t._numItemData * t._line_h );
243                 },
244
245                 // Resize each listitem's width
246                 _resize: function ( event ) {
247                         var o,  // 'ul'
248                                 t = this,
249                                 li,
250                                 padding,
251                                 margin;
252
253                         if ( event.data ) {
254                                 o = event.data;
255                         } else {
256                                 o = event;
257                         }
258                         li = $( o ).children( o.childSelector )
259
260                         t._container_w = $( o ).width();
261
262                         padding = parseInt( li.css( "padding-left" ), 10 )
263                                 + parseInt( li.css( "padding-right" ), 10 );
264
265                         li.each( function ( index, obj ) {
266                                 margin = parseInt( $( this ).css( "margin-left" ), 10 )
267                                         + parseInt( $( this ).css( "margin-right" ), 10 );
268                                 $( this ).css( "width", t._container_w - padding - margin );
269                         } );
270                 },
271
272                 // New scrollmove function supporting scrollTo
273                 _scrollmove: function ( ev ) {
274                         var t = ev.data,        // vlist (JQM object)
275                                 o = t.options,  // options
276                                 prevTopBufLen = t._num_top_items,       // Previous(remembered) top buf length
277                                 timerInterval = 100,
278                                 i,
279                                 _scrollView,
280                                 _normalScroll;
281
282                         _scrollView = {
283                                 viewTop: function ( ) {
284                                         var sv = $( o.id ).parentsUntil( ".ui-page" ).find( ".ui-scrollview-view" ),
285                                                 svTrans = sv.css( "-webkit-transform" ),
286                                                 svTransVal = "0,0,0,0,0,0";
287                                         if ( svTrans ) {
288                                                 svTransVal = svTrans.replace( /matrix\s*\((.*)\)/, "$1" );      // matrix(a,c,b,d,tx,ty)
289                                         }
290                                         return - parseInt( svTransVal.split(',')[5], 10 );
291                                 }
292                         };
293                         _normalScroll = {
294                                 viewTop: function ( ) {
295                                         return $( window ).scrollTop( );        // TODO: - _line_h?
296                                 }
297                         };
298                         // Get current view top position
299                         function viewTop ( ) {
300                                 return o.scrollview ? _scrollView.viewTop() : _normalScroll.viewTop();
301                         }
302                         // log function for debug
303                         function log ( msg ) {
304                                 var debug = false;
305                                 if ( debug ) {
306                                         console.log( ">>virtualllist: " + msg );
307                                 }
308                         }
309
310                         // Timer interval function
311                         // @param[in]   vl      virtuallist object (JQM object)
312                         function timerMove ( vl, undefined ) {
313                                 var cy,                         // current y position
314                                         cti,            // current top idx
315                                         cbi,            // current bottom idx
316                                         oti = vl._first_index,  // old top idx
317                                         obi = vl._last_index,   // old botton idx
318                                         dti,                    // delta of top idx
319                                         fromIdx,
320                                         toIdx,  // index range to be moved
321                                         delta,                  // moveItem delta
322                                         rowLen = vl.options.row,        // max. # of items handled at once
323                                         bufSize,                // top/bottom buffer size. unit: # of items
324                                         i;
325
326                                 // subroutine: Move itemContents in i2 into i1
327                                 function moveItemContents( vl, i1, i2 ) {
328                                         // TODO: Find a efficient way to replace data!
329                                         // Assumption: i1 and i2 has same children.
330                                         var NODETYPE = { ELEMENT_NODE: 1, TEXT_NODE: 3 },
331                                                 c1,     // child item 1 (old)
332                                                 c2,     // child item 2 (new)
333                                                 newText,
334                                                 newImg,
335                                                 i;
336
337                                         $( i1 ).find( ".ui-li-text-main", ".ui-li-text-sub", ".ui-li-text-sub2", "ui-btn-text" ).each( function ( index ) {
338                                                 c1 = $( this );
339                                                 newText = $( i2 ).find( ".ui-li-text-main", ".ui-li-text-sub", "ui-btn-text" ).eq( index ).text();
340
341                                                 $( c1 ).contents().filter( function () {
342                                                         return ( this.nodeType == NODETYPE.TEXT_NODE );
343                                                 } ).get( 0 ).data = newText;
344                                         } );
345
346                                         $( i1 ).find( "img" ).each( function ( imgIdx ) {
347                                                 var c1 = $( this );
348                                                 newImg = $( i2 ).find( "img" ).eq( imgIdx ).attr( "src" );
349
350                                                 $( c1 ).attr( "src", newImg );
351                                         } );
352
353                                         $( i1 ).removeData( );  // Clear old data
354                                 }
355
356                                 // subroutine: Move item
357                                 function moveItem( vl, fromIdx, toIdx ) {
358                                         var itemData,   // data from itemData()
359                                                 item,           // item element
360                                                 newItem,        // new item element
361                                                 tmpl;           // template
362
363                                         log( ">> move item: " + fromIdx + " --> " + toIdx );
364
365                                         // Find current item
366                                         item = $( '#' + vl.options.itemIDPrefix + fromIdx );    // TODO: refactor ID generation!
367                                         if ( ! item || ! item.length ) {
368                                                 return false;
369                                         }
370
371                                         // Get new item
372                                         tmpl = $( "#" + vl.options.template );
373                                         if ( tmpl ) {
374                                                 newItem = tmpl.tmpl( vl._itemData( toIdx ) );
375
376                                                 // TODO: Consider touch block while moving?
377
378                                                 // Move item contents
379                                                 moveItemContents( vl, item, newItem );
380
381                                                 // clean up temporary item
382                                                 newItem.remove();
383                                         }
384
385                                         // Move position, and set id
386                                         item.css( 'top', toIdx * vl._line_h )
387                                                 .attr( 'id' , vl.options.itemIDPrefix + toIdx );        // TODO: refactor ID generation!
388
389                                         // TODO: Apply jqmdata? check following old code;
390                                         // $( oldItem ).removeData( );  // Clear old data
391                                         // if (key) { $( oldItem ).data( key, $( newItem ).data( key ) ); }
392
393                                         return true;
394                                 }
395
396
397                                 // Get current view position
398                                 cy = viewTop();
399
400                                 // Calculate bufSize: rowLen / 3
401                                 // NOTE: Assumption: total row length = visible items * 3 (upper+visible+lower)
402                                 bufSize = Math.ceil( rowLen / 3 );
403
404                                 // Calculate current top/bottom index (to be applied)
405                                 // top index = current position / line height
406                                 cti = Math.floor( cy / vl._line_h ) - bufSize;  // TODO: consider buffer!
407                                 cbi = cti + rowLen - 1;
408
409                                 if ( cti < 0 ) {                // Top boundary check
410                                         cbi += ( - cti );
411                                         cti = 0;
412                                 } else if ( cbi > ( vl._numItemData - 1 ) ) {           // Bottom boundary check
413                                         cti -= ( cbi - ( vl._numItemData - 1 ) );
414                                         cbi = ( vl._numItemData - 1 );
415                                 }
416
417                                 // Calculate dti
418                                 dti = cti - oti;
419                                 log( "cy=" + cy + ", oti=" + oti + ", obi=" + obi + ", cti=" + cti + ", cbi=" + cbi + ", dti=" + dti );
420
421                                 // switch: dti = 0 --> timer stop condition: delta=0 or scrollstop event comes. END.
422                                 if ( 0 == dti ) {
423                                         // Check timer runtime
424                                         vl.timerStillCount += 1;
425                                         if ( vl.timerStillCount < 12 ) {        // check count ( TODO: test and adjust )
426                                                 log("dti=0 " + vl.timerStillCount + " times");
427                                                 vl.timerMoveID = setTimeout( timerMove, timerInterval, vl );    // run once more
428                                                 return;
429                                         }
430
431                                         log("dti=0 " + vl.timerStillCount + " times. End timer.");
432                                         vl.timerStillCount = 0;
433                                         // Stop timer
434                                         if ( vl.timerMoveID ) {
435                                                 clearTimeout( vl.timerMoveID );
436                                                 vl.timerMoveID = null;
437                                         }
438                                 } else {
439                                         // switch: dti >= # of max elements --> total replace.
440                                         vl.timerStillCount = 0;         // Reset still counter
441
442                                         if ( Math.abs( dti ) >= rowLen ) {
443                                                 fromIdx = oti;
444                                                 toIdx = obi;
445                                                 delta = dti;
446                                                 log( ">>> WHOLE CHANGE! delta=" + delta );
447                                         } else {
448                                                 // switch: dti < # of max elements --> move t2b or b2t until new top/bottom idx is covered
449                                                 if ( dti > 0 ) {
450                                                         fromIdx = oti;
451                                                         toIdx = oti + dti - 1;
452                                                         delta = rowLen;
453                                                 } else {
454                                                         fromIdx = obi + dti + 1;        // dti < 0
455                                                         toIdx = obi;
456                                                         delta = -rowLen;
457                                                 }
458                                                 log( ">>> partial change. delta=" + delta );
459                                         }
460
461                                         // Move items
462                                         for ( i = fromIdx; i <= toIdx; i++ ) {
463                                                 moveItem( vl, i, i + delta );           // Change data and position
464                                         }
465
466                                         // Store current top/bottom idx into vl
467                                         vl._first_index = cti;
468                                         vl._last_index = cbi;
469
470                                         // Register timer to check again
471                                         vl.timerMoveID = setTimeout( timerMove, timerInterval, vl );
472                                 }
473                                 return; // End of function
474                         }
475
476                         // ==== function start ====
477
478                         t.timerStillCount = 0;  // Count do-nothing time.       For behavior tuning.
479
480                         // If a timer function is alive, clear it
481                         if ( t.timerMoveID ) {
482                                 clearTimeout( t.timerMoveID );
483                                 t.timerMoveID = null;
484                         }
485                         // run TimerMove()
486                         timerMove( t );
487                 },
488
489                 _recreate: function ( newArray ) {
490                         var t = this,
491                                 o = this.options;
492
493                         $( o.id ).empty();
494
495                         t._numItemData = newArray.length;
496                         t._direction = _NO_SCROLL;
497                         t._first_index = 0;
498                         t._last_index = o.row - 1;
499
500                         t._pushData( o.template );
501
502                         if (o.childSelector == " ul" ) {
503                                 $( o.id + " ul" ).swipelist();
504                         }
505
506                         $( o.id ).virtuallistview();
507
508                         t.refresh( true );
509
510                         t._reposition( o );
511                 },
512
513                 // Init virtuallistview
514                 // this         virtuallistview object
515                 _initList: function () {
516                         var t = this,
517                                 o = this.options;
518
519                         /* After AJAX loading success */
520
521                         // Put initial <li> elements
522                         t._pushData( o.template );
523
524                         // find a parent page, and run _reposition() at 'pageshow' event
525                         // TODO: Consider replace parentsUntil().parent() to parent('.ui-page') ???
526                         $( o.id ).parentsUntil( ".ui-page" ).parent().one( "pageshow", function () {
527                                 setTimeout( function () {
528                                         t._reposition( o );
529                                 }, 0);
530                         });
531
532                         // Bind _scrollmove() at 'scrollstart.virtuallist' event
533                         $( document ).bind( "scrollstart.virtuallist scrollstop.vrituallist", t, t._scrollmove );
534
535                         // Bind _resize()
536                         $( window ).on( "throttledresize", $( o.id ), t._resize );
537
538                         // when ul is a childselector, assume that this is also a swipelist,
539                         // and run swipelist constructor
540                         if ( o.childSelector == " ul" ) {
541                                 $( o.id + " ul" ).swipelist();
542                         }
543
544                         t.refresh( true );
545                 },
546
547                 create: function () {
548                         var o = this.options;
549
550                         /* external API for AJAX callback */
551                         this._create.apply( this, arguments );
552
553                         // TODO: remove this line? _initList() calls reposition...
554                         this._reposition( o );
555                 },
556
557                 _create: function ( args ) {
558                         // Extend instance variables
559                         $.extend( this, {
560                                 _itemData : function ( idx ) { return null; },
561                                 _numItemData : 0,
562                                 _cacheItemData : function ( minIdx, maxIdx ) { },
563                                 _title_h : 0,
564                                 _container_w : 0,
565                                 _minimum_row : 100,
566                                 _direction : _NO_SCROLL,
567                                 _first_index : 0,
568                                 _last_index : 0,
569                                 _num_top_items : 0      // By scroll move, number of hidden elements.
570                         } );
571
572                         // local variables
573                         var t = this,
574                                 o = this.options,
575                                 $el = this.element,
576                                 shortcutsContainer = $('<div class="ui-virtuallist"/>'),
577                                 shortcutsList = $('<ul></ul>'),
578                                 dividers = $el.find(':jqmData(role="virtuallistview" )'),
579                                 lastListItem = null,
580                                 shortcutscroll = this,
581                                 dbtable_name,
582                                 dbtable;
583
584
585                         // Add CSS classes to $el (=virtuallistview)
586                         $el.addClass( function ( i, orig ) {
587                                 return orig + " ui-listview ui-virtual-list-container" + ( t.options.inset ? " ui-listview-inset ui-corner-all ui-shadow " : "" );
588                         });
589
590                         // keep the vlist's ID
591                         o.itemIDPrefix = $el.attr( "id" ) + '_';
592                         o.id = "#" + $el.attr( "id" );
593
594                         // when page hides, empty all child elements
595                         $( o.id ).bind( "pagehide", function ( e ) {
596                                 $( o.id ).empty();
597                         });
598
599                         // Find if scrollview is used
600                         if ( $( ".ui-scrollview-clip" ).size() > 0 ) {
601                                 o.scrollview = true;
602                         } else {
603                                 o.scrollview = false;
604                         }
605
606                         // Calculate page buffer size
607                         if ( $el.data( "row" ) ) {
608                                 o.row = $el.data( "row" );
609
610                                 if ( o.row < t._minimum_row ) {
611                                         o.row = t._minimum_row;
612                                 }
613
614                                 o.page_buf = parseInt( ( o.row / 2 ), 10 );
615                         }
616
617                         // Get arguments
618                         if ( args ) {
619                                 if ( args.itemData && typeof args.itemData == 'function'  ) {
620                                         t._itemData = args.itemData;
621                                 } else {
622                                         return;
623                                 }
624                                 if ( args.numItemData ) {
625                                         if ( typeof args.numItemData == 'function' ) {
626                                                 t._numItemData = args.numItemData( );
627                                         } else if ( typeof args.numItemData == 'number' ) {
628                                                 t._numItemData = args.numItemData;
629                                         } else {
630                                                 return;
631                                         }
632                                 } else {
633                                         return;
634                                 }
635                         } else {        // No option is given
636                                 // Legacy support: dbtable
637                                 console.warn( "WARNING: The data interface of virtuallist is changed. \nOld data interface(data-dbtable) is still supported, but will be removed in next version. \nPlease fix your code soon!" );
638
639                                 /* After DB Load complete, Init Vritual list */
640                                 if ( $( o.id ).hasClass( "vlLoadSuccess" ) ) {
641                                         dbtable_name = $el.jqmData('dbtable');
642                                         dbtable = window[ dbtable_name ];
643
644                                         $( o.id ).empty();
645
646                                         if ( !dbtable ) {
647                                                 dbtable = { };
648                                         }
649
650                                         t._itemData = function ( idx ) {
651                                                 return dbtable[ idx ];
652                                         };
653                                         t._numItemData = dbtable.length;
654                                 } else {
655                                         return; // Do nothing
656                                 }
657                         }
658
659                         // Get template data
660                         if ( $el.data( "template" ) ) {
661                                 o.template = $el.data( "template" );
662
663                                 /* to support swipe list, <li> or <ul> can be main node of virtual list. */
664                                 if ( $el.data( "swipelist" ) == true ) {
665                                         o.childSelector = " ul";
666                                 } else {
667                                         o.childSelector = " li";
668                                 }
669                         }
670
671                         // Set data's unique key
672                         // NOTE: Unnecessary?
673                         if ( $el.data( "dbkey" ) ) {
674                                 o.dbkey = $el.data( "dbkey" );
675                         }
676
677                         t._first_index = 0;                     // initial top idx of <li> element.
678                         t._last_index = o.row - 1;              // initial bottom idx of <li> element.
679                         t._initList();  // NOTE: Called at here only!
680                 },
681
682                 destroy : function () {
683                         var o = this.options;
684
685                         $( document ).unbind( "scrollstop" );
686
687                         $( window ).off( "throttledresize", this._resize );
688
689                         $( o.id ).empty();
690
691                         if ( this.timerMoveID ) {
692                                 clearTimeout( this.timerMoveID );
693                                 this.timerMoveID = null;
694                         }
695                 },
696
697                 _itemApply: function ( $list, item ) {
698                         var $countli = item.find( ".ui-li-count" );
699
700                         if ( $countli.length ) {
701                                 item.addClass( "ui-li-has-count" );
702                         }
703
704                         $countli.addClass( "ui-btn-up-" + ( $list.jqmData( "counttheme" ) || this.options.countTheme ) + " ui-btn-corner-all" );
705
706                         // TODO class has to be defined in markup
707                         item.find( "h1, h2, h3, h4, h5, h6" ).addClass( "ui-li-heading" ).end()
708                                 .find( "p, dl" ).addClass( "ui-li-desc" ).end()
709                                 .find( ">img:eq(0), .ui-link-inherit>img:eq(0)" ).addClass( "ui-li-thumb" ).each( function () {
710                                         item.addClass( $( this ).is( ".ui-li-icon" ) ? "ui-li-has-icon" : "ui-li-has-thumb" );
711                                 }).end()
712                                 .find( ".ui-li-aside" ).each(function () {
713                                         var $this = $( this );
714                                         $this.prependTo( $this.parent() ); //shift aside to front for css float
715                                 } );
716                 },
717
718                 _removeCorners: function ( li, which ) {
719                         var top = "ui-corner-top ui-corner-tr ui-corner-tl",
720                                 bot = "ui-corner-bottom ui-corner-br ui-corner-bl";
721
722                         li = li.add( li.find( ".ui-btn-inner, .ui-li-link-alt, .ui-li-thumb" ) );
723
724                         if ( which === "top" ) {
725                                 li.removeClass( top );
726                         } else if ( which === "bottom" ) {
727                                 li.removeClass( bot );
728                         } else {
729                                 li.removeClass( top + " " + bot );
730                         }
731                 },
732
733                 _refreshCorners: function ( create ) {
734                         var $li,
735                                 $visibleli,
736                                 $topli,
737                                 $bottomli;
738
739                         if ( this.options.inset ) {
740                                 $li = this.element.children( "li" );
741                                 // at create time the li are not visible yet so we need to rely on .ui-screen-hidden
742                                 $visibleli = create ? $li.not( ".ui-screen-hidden" ) : $li.filter( ":visible" );
743
744                                 this._removeCorners( $li );
745
746                                 // Select the first visible li element
747                                 $topli = $visibleli.first()
748                                         .addClass( "ui-corner-top" );
749
750                                 $topli.add( $topli.find( ".ui-btn-inner" ) )
751                                         .find( ".ui-li-link-alt" )
752                                                 .addClass( "ui-corner-tr" )
753                                         .end()
754                                         .find( ".ui-li-thumb" )
755                                                 .not( ".ui-li-icon" )
756                                                 .addClass( "ui-corner-tl" );
757
758                                 // Select the last visible li element
759                                 $bottomli = $visibleli.last()
760                                         .addClass( "ui-corner-bottom" );
761
762                                 $bottomli.add( $bottomli.find( ".ui-btn-inner" ) )
763                                         .find( ".ui-li-link-alt" )
764                                                 .addClass( "ui-corner-br" )
765                                         .end()
766                                         .find( ".ui-li-thumb" )
767                                                 .not( ".ui-li-icon" )
768                                                 .addClass( "ui-corner-bl" );
769                         }
770                 },
771
772                 // this         virtuallistview object
773                 refresh: function ( create ) {
774                         this.parentPage = this.element.closest( ".ui-page" );
775                         // Make sub page, and move the virtuallist into it...
776                         // NOTE: check this subroutine.
777                         this._createSubPages();
778
779                         var o = this.options,
780                                 $list = this.element,
781                                 self = this,
782                                 dividertheme = $list.jqmData( "dividertheme" ) || o.dividerTheme,
783                                 listsplittheme = $list.jqmData( "splittheme" ),
784                                 listspliticon = $list.jqmData( "spliticon" ),
785                                 li = $list.children( "li" ),
786                                 counter = $.support.cssPseudoElement || !$.nodeName( $list[ 0 ], "ol" ) ? 0 : 1,
787                                 item,
788                                 itemClass,
789                                 temTheme,
790                                 a,
791                                 last,
792                                 splittheme,
793                                 countParent,
794                                 icon,
795                                 pos,
796                                 numli,
797                                 itemTheme;
798
799                         // TODO: ?
800                         if ( counter ) {
801                                 $list.find( ".ui-li-dec" ).remove();
802                         }
803
804                         for ( pos = 0, numli = li.length; pos < numli; pos++ ) {
805                                 item = li.eq( pos );
806                                 itemClass = "ui-li";
807
808                                 // If we're creating the element, we update it regardless
809                                 if ( create || !item.hasClass( "ui-li" ) ) {
810                                         itemTheme = item.jqmData( "theme" ) || o.theme;
811                                         a = item.children( "a" );
812
813                                         if ( a.length ) {
814                                                 icon = item.jqmData( "icon" );
815
816                                                 item.buttonMarkup({
817                                                         wrapperEls: "div",
818                                                         shadow: false,
819                                                         corners: false,
820                                                         iconpos: "right",
821                                                         /* icon: a.length > 1 || icon === false ? false : icon || "arrow-r",*/
822                                                         icon: false,    /* Remove unnecessary arrow icon */
823                                                         theme: itemTheme
824                                                 });
825
826                                                 if ( ( icon != false ) && ( a.length == 1 ) ) {
827                                                         item.addClass( "ui-li-has-arrow" );
828                                                 }
829
830                                                 a.first().addClass( "ui-link-inherit" );
831
832                                                 if ( a.length > 1 ) {
833                                                         itemClass += " ui-li-has-alt";
834
835                                                         last = a.last();
836                                                         splittheme = listsplittheme || last.jqmData( "theme" ) || o.splitTheme;
837
838                                                         last.appendTo(item)
839                                                                 .attr( "title", last.getEncodedText() )
840                                                                 .addClass( "ui-li-link-alt" )
841                                                                 .empty()
842                                                                 .buttonMarkup({
843                                                                         shadow: false,
844                                                                         corners: false,
845                                                                         theme: itemTheme,
846                                                                         icon: false,
847                                                                         iconpos: false
848                                                                 })
849                                                                 .find( ".ui-btn-inner" )
850                                                                 .append(
851                                                                         $( "<span />" ).buttonMarkup({
852                                                                                 shadow: true,
853                                                                                 corners: true,
854                                                                                 theme: splittheme,
855                                                                                 iconpos: "notext",
856                                                                                 icon: listspliticon || last.jqmData( "icon" ) || o.splitIcon
857                                                                         })
858                                                                 );
859                                                 }
860                                         } else if ( item.jqmData( "role" ) === "list-divider" ) {
861
862                                                 itemClass += " ui-li-divider ui-btn ui-bar-" + dividertheme;
863                                                 item.attr( "role", "heading" );
864
865                                                 //reset counter when a divider heading is encountered
866                                                 if ( counter ) {
867                                                         counter = 1;
868                                                 }
869
870                                         } else {
871                                                 itemClass += " ui-li-static ui-body-" + itemTheme;
872                                         }
873                                 }
874
875                                 if ( counter && itemClass.indexOf( "ui-li-divider" ) < 0 ) {
876                                         countParent = item.is( ".ui-li-static:first" ) ? item : item.find( ".ui-link-inherit" );
877
878                                         countParent.addClass( "ui-li-jsnumbering" )
879                                                 .prepend( "<span class='ui-li-dec'>" + (counter++) + ". </span>" );
880                                 }
881
882                                 item.add( item.children( ".ui-btn-inner" ) ).addClass( itemClass );
883
884                                 self._itemApply( $list, item );
885                         }
886
887                         this._refreshCorners( create );
888                 },
889
890                 //create a string for ID/subpage url creation
891                 _idStringEscape: function ( str ) {
892                         return str.replace(/\W/g , "-");
893                 },
894
895                 // ?
896                 // this         virtuallistview object
897                 _createSubPages: function () {
898                         var parentList = this.element,
899                                 parentPage = parentList.closest( ".ui-page" ),
900                                 parentUrl = parentPage.jqmData( "url" ),
901                                 parentId = parentUrl || parentPage[ 0 ][ $.expando ],
902                                 parentListId = parentList.attr( "id" ),
903                                 o = this.options,
904                                 dns = "data-" + $.mobile.ns,
905                                 self = this,
906                                 persistentFooterID = parentPage.find( ":jqmData(role='footer')" ).jqmData( "id" ),
907                                 hasSubPages,
908                                 newRemove;
909
910                         if ( typeof listCountPerPage[ parentId ] === "undefined" ) {
911                                 listCountPerPage[ parentId ] = -1;
912                         }
913
914                         parentListId = parentListId || ++listCountPerPage[ parentId ];
915
916                         $( parentList.find( "li>ul, li>ol" ).toArray().reverse() ).each(function ( i ) {
917                                 var self = this,
918                                         list = $( this ),
919                                         listId = list.attr( "id" ) || parentListId + "-" + i,
920                                         parent = list.parent(),
921                                         nodeEls,
922                                         title = nodeEls.first().getEncodedText(),//url limits to first 30 chars of text
923                                         id = ( parentUrl || "" ) + "&" + $.mobile.subPageUrlKey + "=" + listId,
924                                         theme = list.jqmData( "theme" ) || o.theme,
925                                         countTheme = list.jqmData( "counttheme" ) || parentList.jqmData( "counttheme" ) || o.countTheme,
926                                         newPage,
927                                         anchor;
928
929                                 nodeEls = $( list.prevAll().toArray().reverse() );
930                                 nodeEls = nodeEls.length ? nodeEls : $( "<span>" + $.trim( parent.contents()[ 0 ].nodeValue ) + "</span>" );
931
932                                 //define hasSubPages for use in later removal
933                                 hasSubPages = true;
934
935                                 newPage = list.detach()
936                                                         .wrap( "<div " + dns + "role='page' " + dns + "url='" + id + "' " + dns + "theme='" + theme + "' " + dns + "count-theme='" + countTheme + "'><div " + dns + "role='content'></div></div>" )
937                                                         .parent()
938                                                                 .before( "<div " + dns + "role='header' " + dns + "theme='" + o.headerTheme + "'><div class='ui-title'>" + title + "</div></div>" )
939                                                                 .after( persistentFooterID ? $( "<div " + dns + "role='footer' " + dns + "id='" + persistentFooterID + "'>" ) : "" )
940                                                                 .parent()
941                                                                 .appendTo( $.mobile.pageContainer );
942
943                                 newPage.page();
944
945                                 anchor = parent.find('a:first');
946
947                                 if ( !anchor.length ) {
948                                         anchor = $( "<a/>" ).html( nodeEls || title ).prependTo( parent.empty() );
949                                 }
950
951                                 anchor.attr( "href", "#" + id );
952
953                         }).virtuallistview();
954
955                         // on pagehide, remove any nested pages along with the parent page, as long as they aren't active
956                         // and aren't embedded
957                         if ( hasSubPages &&
958                                                 parentPage.is( ":jqmData(external-page='true')" ) &&
959                                                 parentPage.data( "page" ).options.domCache === false ) {
960
961                                 newRemove = function ( e, ui ) {
962                                         var nextPage = ui.nextPage, npURL;
963
964                                         if ( ui.nextPage ) {
965                                                 npURL = nextPage.jqmData( "url" );
966                                                 if ( npURL.indexOf( parentUrl + "&" + $.mobile.subPageUrlKey ) !== 0 ) {
967                                                         self.childPages().remove();
968                                                         parentPage.remove();
969                                                 }
970                                         }
971                                 };
972
973                                 // unbind the original page remove and replace with our specialized version
974                                 parentPage
975                                         .unbind( "pagehide.remove" )
976                                         .bind( "pagehide.remove", newRemove );
977                         }
978                 },
979
980                 // TODO sort out a better way to track sub pages of the virtuallistview this is brittle
981                 childPages: function () {
982                         var parentUrl = this.parentPage.jqmData( "url" );
983
984                         return $( ":jqmData(url^='" +  parentUrl + "&" + $.mobile.subPageUrlKey + "')" );
985                 }
986         });
987
988         //auto self-init widgets
989         $( document ).bind( "pagecreate create", function ( e ) {
990                 $( $.tizen.virtuallistview.prototype.options.initSelector, e.target ).virtuallistview();
991         });
992
993 } ( jQuery ) );
994