tizen beta release
[platform/framework/web/web-ui-fw.git] / src / widgets / virtuallist / js / jquery.mobile.tizen.virtuallistview.js
1 /*\r
2  *      Author: Wongi Lee <wongi11.lee@samsung.com>\r
3 */\r
4 \r
5 /**\r
6  * Virtual List Widget for unlimited data.\r
7  * To support more then 1,000 items, special list widget developed. \r
8  * Fast initialize and light DOM tree.\r
9  * DB connection and works like DB cursor.     \r
10  * \r
11  * HTML Attributes:\r
12  *\r
13  *              data-role:      virtuallistview\r
14  *              data-template : jQuery.template ID that populate into virtual list \r
15  *              data-dbtable : DB Table name. It used as window[DB NAME]. Loaded data should be converted as window object.\r
16  *              data-dbkey : Unique key of DB Table. To sync each element on virtual list with DB table. \r
17  *              \r
18  *              ID : <UL> element that has "data-role=virtuallist" must have ID attribute.\r
19  *              Class : <UL> element that has "data-role=virtuallist" should have "vlLoadSuccess" class to guaranty DB loading is completed. \r
20  *\r
21  *\r
22  * APIs:\r
23  *\r
24  *              create ( void )\r
25  *                      : API to call _create method. API for AJAX or DB loading callback.\r
26  *\r
27  *              recreate ( Array )\r
28  *                      : Update virtual list with new data array. For example, update with search result. \r
29  *\r
30  * Events:\r
31  *\r
32  *              touchstart : Temporary preventDefault applied on touchstart event to avoid broken screen.\r
33  *\r
34  * Examples:\r
35  * \r
36  *              <script id="tmp-3-2-7" type="text/x-jquery-tmpl">\r
37  *                      <li class="ui-li-3-2-7">\r
38  *                              <span class="ui-li-text-main">${NAME}</span>\r
39  *                              <img src="00_winset_icon_favorite_on.png" class="ui-li-icon-sub">\r
40  *                              <span class="ui-li-text-sub">${ACTIVE}</span>\r
41  *                              <span class="ui-li-text-sub2">${FROM}</span>\r
42  *                      </li>\r
43  *              </script>\r
44  *\r
45  *              <ul id="virtuallist-normal_3_2_7_ul" data-role="virtuallistview" data-template="tmp-3-2-7" data-dbtable="JSON_DATA">\r
46  *              </ul>\r
47  *\r
48  */\r
49 \r
50 \r
51 (function( $, undefined ) {\r
52 \r
53 //Keeps track of the number of lists per page UID\r
54 //This allows support for multiple nested list in the same page\r
55 //https://github.com/jquery/jquery-mobile/issues/1617\r
56 var listCountPerPage = {};\r
57 \r
58 /* Code for Virtual List Demo */\r
59 var     INIT_LIST_NUM = 100;\r
60 var     PAGE_BUF = (INIT_LIST_NUM/2);\r
61 var     TOTAL_ITEMS = 0;\r
62 var LINE_H = 0;\r
63 var TITLE_H = 0;        \r
64 var CONTAINER_W = 0;\r
65 \r
66 /* ENUM */\r
67 var     NO_SCROLL = 0;  \r
68 var     SCROLL_DOWN = 1;\r
69 var     SCROLL_UP = -1;\r
70 \r
71 var i =0;\r
72 var direction = NO_SCROLL;\r
73 var first_index = 0;                            //first id of <li> element.\r
74 var last_index = INIT_LIST_NUM -1;      //last id of <li> element.\r
75 \r
76 var num_top_items = 0;                          //By scroll move, number of hidden elements.\r
77 \r
78 $.widget( "tizen.virtuallistview", $.mobile.widget, {\r
79         options: {\r
80                 theme: "s",\r
81                 countTheme: "c",\r
82                 headerTheme: "b",\r
83                 dividerTheme: "b",\r
84                 splitIcon: "arrow-r",\r
85                 splitTheme: "b",\r
86                 inset: false,\r
87                 id:     "",                                     /* Virtual list UL elemet's ID */\r
88                 childSelector: " li",   /* To support swipe list */\r
89                 dbtable: "",\r
90                 template : "",\r
91                 dbkey: false,                   /* Data's unique Key */\r
92                 scrollview: false,\r
93                 initSelector: ":jqmData(role='virtuallistview')"\r
94         },\r
95 \r
96         _stylerMouseUp: function()\r
97         {\r
98                 $( this ).addClass( "ui-btn-up-s" );\r
99                 $( this ).removeClass( "ui-btn-down-s" );\r
100         },\r
101 \r
102         _stylerMouseDown: function()\r
103         {\r
104                 $( this ).addClass( "ui-btn-down-s" );\r
105                 $( this ).removeClass( "ui-btn-up-s" );\r
106         },\r
107         \r
108         _stylerMouseOver: function()\r
109         {\r
110                 $( this ).toggleClass( "ui-btn-hover-s" );              \r
111         },\r
112         \r
113         _stylerMouseOut: function()\r
114         {\r
115                 $( this ).toggleClass( "ui-btn-hover-s" );\r
116         },\r
117 \r
118         _pushData: function ( template, data ) {\r
119                 var o = this.options;\r
120                 \r
121                 var dataTable = data;\r
122                 \r
123                 var myTemplate = $( "#" + template );\r
124                 \r
125                 var lastIndex = ( INIT_LIST_NUM > data.length ? data.length : INIT_LIST_NUM ); \r
126                 \r
127                 for ( i = 0; i < lastIndex; i++ ) \r
128                 {\r
129                         var htmlData = myTemplate.tmpl( dataTable[i] );\r
130                         $( o.id ).append( $(htmlData).attr( 'id', 'li_'+i ) );\r
131                 }\r
132                 \r
133                 /* After push data, re-style virtuallist widget */\r
134                 $( o.id ).trigger( "create" );\r
135         }, \r
136 \r
137         _reposition: function( event ) {\r
138                 var o;\r
139                 \r
140                 if ( event.data ) {\r
141                         o = event.data;\r
142                 }\r
143                 else {\r
144                         o = event;\r
145                 }\r
146                 \r
147                 var t = this;\r
148                 \r
149                 if ($(o.id + o.childSelector).size() > 0){\r
150                         TITLE_H = $( o.id + o.childSelector + ':first' ).position().top;\r
151                         LINE_H = $( o.id + o.childSelector + ':first' ).outerHeight();\r
152                         \r
153                         CONTAINER_W = $( o.id ).innerWidth();\r
154                         \r
155                         var padding = parseInt( $( o.id + o.childSelector ).css( "padding-left" )) + parseInt( $(o.id + o.childSelector).css( "padding-right" ) );\r
156                         \r
157                         /* Add style */\r
158                         $( o.id + ">" + o.childSelector ).addClass( "position_absolute" ).addClass( "ui-btn-up-s" )\r
159                                                                                                 .bind( "mouseup", t._stylerMouseUp )\r
160                                                                                                 .bind( "mousedown", t._stylerMouseDown )                \r
161                                                                                                 .bind( "mouseover", t._stylerMouseOver )\r
162                                                                                                 .bind( "mouseout", t._stylerMouseOut );\r
163                 }\r
164 \r
165                 $( o.id + ">" + o.childSelector ).each( function( index ) {\r
166                         $( this ).css( "top", TITLE_H + LINE_H*index + 'px' )\r
167                         .css( "width", CONTAINER_W - padding );\r
168                 });\r
169 \r
170                 /* Set Max List Height */\r
171                 $( o.id ).height( TOTAL_ITEMS * LINE_H );\r
172         },\r
173         \r
174         _resize: function( event ) {\r
175                 var o;\r
176                 \r
177                 if ( event.data ) {\r
178                         o = event.data;\r
179                 }\r
180                 else {\r
181                         o = event;\r
182                 }\r
183                 \r
184                 var t = this;           \r
185                 \r
186                 CONTAINER_W = $( o.id ).innerWidth();\r
187                 \r
188                 var padding = parseInt( $( o.id + o.childSelector ).css( "padding-left" )) + parseInt( $( o.id + o.childSelector ).css( "padding-right" ) );\r
189                 \r
190                 $( o.id + o.childSelector ).each( function(index){\r
191                         $( this ).css( "width", CONTAINER_W - padding );\r
192                 });\r
193         },\r
194         \r
195         _scrollmove: function( event ) {\r
196                 var velocity = 0;\r
197                 var o = event.data;\r
198                 var dataList = window[o.dbtable];\r
199                 \r
200                 /* Text & image src replace function */\r
201                 var _replace= function( oldItem, newItem, key ) {\r
202                         $( oldItem ).find( ".ui-li-text-main",".ui-li-text-sub","ui-btn-text" ).each( function( index ) {\r
203                                 var oldObj = $( this );\r
204                                 var newText = $( newItem ).find( ".ui-li-text-main",".ui-li-text-sub","ui-btn-text" ).eq( index ).text();\r
205                                 \r
206                     $( oldObj).contents().filter( function(){ \r
207                         return( this.nodeType == 3 );\r
208                     } ).get( 0 ).data = newText;\r
209                         });\r
210                         \r
211                         $( oldItem ).find( "img" ).each( function( imgIndex ) {\r
212                                 var oldObj = $( this );\r
213 \r
214                                 var newImg = $( newItem ).find( "img" ).eq( imgIndex ).attr( "src" );\r
215                                 \r
216                                 $( oldObj ).attr( "src", newImg );\r
217                         });\r
218                         \r
219                         if (key) {\r
220                                 $( oldItem ).data(key, $( newItem ).data(key));\r
221                         }\r
222             };\r
223                 \r
224                 //Move older item to bottom\r
225                 var _moveTopBottom= function( v_firstIndex, v_lastIndex, num, key ) {\r
226                         if (v_firstIndex < 0) {\r
227                                 return;\r
228                         }\r
229                         \r
230                         for (i=0; i<num; i++)\r
231                         {\r
232                                 if (v_lastIndex + i > TOTAL_ITEMS)\r
233                                         break;\r
234                                 \r
235                                 var cur_item = $('#li_' + (v_firstIndex + i));\r
236                                 \r
237                                 if (cur_item) {\r
238                                         /* Make New <LI> element from template. */\r
239                                         var myTemplate = $( "#" + o.template );\r
240                                         var htmlData = myTemplate.tmpl( dataList[ v_lastIndex + i ] );\r
241                                         \r
242                                         /* Copy all data to current item. */\r
243                                         _replace( cur_item, htmlData, key );\r
244                                         \r
245                                         /* Set New Position */\r
246                                         ( cur_item ).css( 'top', TITLE_H + LINE_H*( v_lastIndex + 1 + i ) ).attr( 'id', 'li_' +( v_lastIndex + 1+ i ) );\r
247                                 }\r
248                                 else {\r
249                                         break;\r
250                                 }\r
251                         }\r
252                 };\r
253 \r
254                 // Move older item to bottom\r
255                 var _moveBottomTop= function( v_firstIndex, v_lastIndex, num, key ) {\r
256                         if ( v_firstIndex < 0 ) {\r
257                                 return;\r
258                         }\r
259                         \r
260                         for ( i=0; i<num; i++ )\r
261                         {\r
262                                 var cur_item = $( '#li_' + ( v_lastIndex - i ) );\r
263 \r
264                                 if ( cur_item ) {\r
265                                         if ( v_firstIndex-1-i < 0 ) {\r
266                                                 break;  \r
267                                         }\r
268                                 \r
269                                         /* Make New <LI> element from template. */\r
270                                         var myTemplate = $( "#" + o.template );\r
271                                         var htmlData = myTemplate.tmpl( dataList[ v_firstIndex - 1 - i ] );\r
272                                         \r
273                                         /* Copy all data to current item. */\r
274                                         _replace( cur_item, htmlData, key );\r
275 \r
276                                         /* Set New Position */\r
277                                         $( cur_item ).css( 'top', TITLE_H + LINE_H * ( v_firstIndex - 1 - i )).attr( 'id', 'li_' +( v_firstIndex - 1 - i ));\r
278                                 }\r
279                                 else {\r
280                                         break;\r
281                                 }\r
282                         }\r
283                 };\r
284                 \r
285                 /* Matrix to Array function written by Blender@stackoverflow.nnikishi@emich.edu*/\r
286                 var matrixToArray = function( matrix ) {\r
287                     var contents = matrix.substr( 7 );\r
288                     contents = contents.substr( 0, contents.length - 1 );\r
289 \r
290                     return contents.split( ', ' );\r
291                 };              \r
292                 \r
293                 // Get scroll direction and velocity\r
294                 /* with Scroll view */\r
295                 if ( o.scrollview ) {\r
296                         var $el = $( o.id ).parentsUntil( ".ui-page" ).find( ".ui-scrollview-view" );\r
297                         var transformValue = matrixToArray( $el.css( "-webkit-transform" ) );\r
298                         \r
299                         var curWindowTop = Math.abs( transformValue[ 5 ] );     /* Y vector */\r
300                 }\r
301         else {\r
302                 var curWindowTop = $( window ).scrollTop() - LINE_H;\r
303         }\r
304                 \r
305                 var cur_num_top_itmes = $( o.id + o.childSelector ).filter( function(){\r
306                                                                         return (parseInt($( this ).css( "top" )) < curWindowTop);\r
307                                                                 } ).size(); \r
308                 \r
309                 if ( num_top_items < cur_num_top_itmes ) {\r
310                         direction = SCROLL_DOWN;\r
311                         velocity = cur_num_top_itmes - num_top_items;\r
312                         num_top_items = cur_num_top_itmes;\r
313                 }\r
314                 else if ( num_top_items > cur_num_top_itmes ) {\r
315                         direction = SCROLL_UP;\r
316                         velocity = num_top_items - cur_num_top_itmes;\r
317                         num_top_items = cur_num_top_itmes;\r
318                 }\r
319 \r
320                 // Move items\r
321                 if( direction == SCROLL_DOWN )\r
322                 {\r
323                         if ( cur_num_top_itmes > PAGE_BUF ) {\r
324                                 if ( last_index + velocity > TOTAL_ITEMS ) {\r
325                                         velocity = TOTAL_ITEMS - last_index -1;\r
326                                 }\r
327                                 \r
328                                 /* Prevent scroll touch event while DOM access */\r
329                                 $(document).bind( "touchstart.virtuallist", function(event) {\r
330                                           event.preventDefault();\r
331                                 });                             \r
332                                 \r
333                                 _moveTopBottom( first_index, last_index, velocity, o.dbkey );\r
334                                 \r
335                                 first_index += velocity;\r
336                                 last_index += velocity;\r
337                                 num_top_items -= velocity;\r
338                                 \r
339                                 /* Unset prevent touch event */\r
340                                 $( document ).unbind( "touchstart.virtuallist" );\r
341                         }\r
342                 }\r
343                 else if( direction == SCROLL_UP ) {\r
344                         if ( cur_num_top_itmes <= PAGE_BUF ) {\r
345                                 if ( first_index < velocity ) {\r
346                                         velocity = first_index;\r
347                                 }\r
348 \r
349                                 /* Prevent scroll touch event while DOM access */\r
350                                 $( document ).bind( "touchstart.virtuallist", function( event ) {\r
351                                           event.preventDefault();\r
352                                 });             \r
353                                 \r
354                                 _moveBottomTop( first_index, last_index, velocity, o.dbkey );\r
355                                 \r
356                                 first_index -= velocity;\r
357                                 last_index -= velocity;\r
358                                 num_top_items += velocity;\r
359                                 \r
360                                 /* Unset prevent touch event */\r
361                                 $( document ).unbind( "touchstart.virtuallist" );                               \r
362                         }\r
363                         \r
364                         if ( first_index < PAGE_BUF ) {\r
365                                 num_top_items = first_index;\r
366                         }\r
367                 }\r
368         },\r
369         \r
370         recreate: function( newArray ){\r
371                 var t = this;\r
372                 var o = this.options;\r
373                 \r
374                 $( o.id ).empty();\r
375                 \r
376                 TOTAL_ITEMS = newArray.length;\r
377                 direction = NO_SCROLL;\r
378                 first_index = 0;\r
379                 last_index = INIT_LIST_NUM -1;          \r
380                 \r
381                 t._pushData( ( o.template ), newArray );\r
382                 \r
383                 if (o.childSelector == " ul" ) {\r
384                         $( o.id + " ul" ).swipelist();  \r
385                 }\r
386                 \r
387                 $( o.id ).virtuallistview();\r
388                 \r
389                 t._reposition( o );\r
390                 \r
391                 t.refresh( true );\r
392         },\r
393 \r
394         _initList: function() {\r
395                 var t = this;\r
396                 var o = this.options;\r
397                 \r
398                 /* After AJAX loading success */\r
399                 o.dbtable = t.element.data( "dbtable" );\r
400                 \r
401                 TOTAL_ITEMS = $(window[o.dbtable]).size();\r
402                 \r
403                 /* Make Gen list by template */\r
404                 t._pushData((o.template), window[o.dbtable]);\r
405         \r
406                 $( o.id ).parentsUntil( ".ui-page" ).parent().one( "pageshow", o, t._reposition);\r
407 \r
408                 /* Scrollview */\r
409                 $( document ).bind( "scrollstop.virtuallist", t.options, t._scrollmove );\r
410                 \r
411                 $( window ).bind( "resize.virtuallist", t._resize );\r
412 \r
413                 if ( o.childSelector == " ul" ) {\r
414                         $( o.id + " ul" ).swipelist();\r
415                 }\r
416             \r
417                 t.refresh( true );\r
418         },\r
419         \r
420         create: function() {\r
421                 var o = this.options;\r
422 \r
423                 /* external API for AJAX callback */\r
424                 this._create( "create" );\r
425                 \r
426                 this._reposition( o );\r
427         },\r
428         \r
429         _create: function( event ) {\r
430                 var t = this;\r
431                 var o = this.options; \r
432                 \r
433                 // create listview markup\r
434                 t.element.addClass( function( i, orig ) {\r
435                         return orig + " ui-listview ui-virtual-list-container" + ( t.options.inset ? " ui-listview-inset ui-corner-all ui-shadow " : "" );\r
436                 });\r
437 \r
438                 var $el = this.element,\r
439                 shortcutsContainer = $('<div class="ui-virtuallist"/>'),\r
440                 shortcutsList = $('<ul></ul>'),\r
441                 dividers = $el.find(':jqmData(role="virtuallistview" )'),\r
442                 lastListItem = null,\r
443                 shortcutscroll = this;\r
444                 \r
445                 o.id = "#" + $el.attr( "id" );\r
446         \r
447                 $( o.id ).bind( "pagehide", function( e ){\r
448                         $( o.id ).empty();\r
449                 });\r
450             \r
451                 /* Scroll view */\r
452                 ( $( ".ui-scrollview-clip" ).size()>0 ) ? o.scrollview = true : o.scrollview = false;\r
453 \r
454                 /* After DB Load complete, Init Vritual list */\r
455                 if ($( o.id ).hasClass( "vlLoadSuccess" )) {\r
456                         $( o.id ).empty();              \r
457                 \r
458                         if ($el.data( "template" )) {\r
459                                 o.template = $el.data( "template" );\r
460                                 \r
461                         /* to support swipe list, <li> or <ul> can be main node of virtual list. */\r
462                         if ( $el.data( "swipelist" ) == true ) {\r
463                                 o.childSelector = " ul";\r
464                         }\r
465                         else {\r
466                                 o.shildSelector = " li";\r
467                         }\r
468                 }\r
469                         \r
470                 /* Set data's unique key */\r
471                 if ( $el.data( "dbkey" ) ) {\r
472                         o.datakey = $el.data( "dbkey" );\r
473                 }\r
474 \r
475                 t._initList();\r
476             }\r
477         },\r
478         \r
479         destroy : function(){\r
480                 var o = this.options;\r
481                 \r
482                 $( document ).unbind( "scrollstop" );\r
483                 \r
484                 $( window ).unbind( "resize.virtuallist" );\r
485                 \r
486                 $( o.id ).empty();\r
487         },\r
488         \r
489         _itemApply: function( $list, item ) {\r
490                 var $countli = item.find( ".ui-li-count" );\r
491                 \r
492                 if ( $countli.length ) {\r
493                         item.addClass( "ui-li-has-count" );\r
494                 }\r
495                 \r
496                 $countli.addClass( "ui-btn-up-" + ( $list.jqmData( "counttheme" ) || this.options.countTheme ) + " ui-btn-corner-all" );\r
497 \r
498                 // TODO class has to be defined in markup\r
499                 item.find( "h1, h2, h3, h4, h5, h6" ).addClass( "ui-li-heading" ).end()\r
500                         .find( "p, dl" ).addClass( "ui-li-desc" ).end()\r
501                         .find( ">img:eq(0), .ui-link-inherit>img:eq(0)" ).addClass( "ui-li-thumb" ).each( function() {\r
502                                 item.addClass( $( this ).is( ".ui-li-icon" ) ? "ui-li-has-icon" : "ui-li-has-thumb" );\r
503                         }).end()\r
504                         .find( ".ui-li-aside" ).each(function() {\r
505                                 var $this = $( this );\r
506                                 $this.prependTo( $this.parent() ); //shift aside to front for css float\r
507                         } );\r
508         },\r
509 \r
510         _removeCorners: function( li, which ) {\r
511                 var top = "ui-corner-top ui-corner-tr ui-corner-tl",\r
512                         bot = "ui-corner-bottom ui-corner-br ui-corner-bl";\r
513 \r
514                 li = li.add( li.find( ".ui-btn-inner, .ui-li-link-alt, .ui-li-thumb" ) );\r
515 \r
516                 if ( which === "top" ) {\r
517                         li.removeClass( top );\r
518                 } else if ( which === "bottom" ) {\r
519                         li.removeClass( bot );\r
520                 } else {\r
521                         li.removeClass( top + " " + bot );\r
522                 }\r
523         },\r
524 \r
525         _refreshCorners: function( create ) {\r
526                 var $li,\r
527                         $visibleli,\r
528                         $topli,\r
529                         $bottomli;\r
530 \r
531                 if ( this.options.inset ) {\r
532                         $li = this.element.children( "li" );\r
533                         // at create time the li are not visible yet so we need to rely on .ui-screen-hidden\r
534                         $visibleli = create?$li.not( ".ui-screen-hidden" ):$li.filter( ":visible" );\r
535 \r
536                         this._removeCorners( $li );\r
537 \r
538                         // Select the first visible li element\r
539                         $topli = $visibleli.first()\r
540                                 .addClass( "ui-corner-top" );\r
541 \r
542                         $topli.add( $topli.find( ".ui-btn-inner" ) )\r
543                                 .find( ".ui-li-link-alt" )\r
544                                         .addClass( "ui-corner-tr" )\r
545                                 .end()\r
546                                 .find( ".ui-li-thumb" )\r
547                                         .not( ".ui-li-icon" )\r
548                                         .addClass( "ui-corner-tl" );\r
549 \r
550                         // Select the last visible li element\r
551                         $bottomli = $visibleli.last()\r
552                                 .addClass( "ui-corner-bottom" );\r
553 \r
554                         $bottomli.add( $bottomli.find( ".ui-btn-inner" ) )\r
555                                 .find( ".ui-li-link-alt" )\r
556                                         .addClass( "ui-corner-br" )\r
557                                 .end()\r
558                                 .find( ".ui-li-thumb" )\r
559                                         .not( ".ui-li-icon" )\r
560                                         .addClass( "ui-corner-bl" );\r
561                 }\r
562         },\r
563 \r
564         refresh: function( create ) {\r
565                 this.parentPage = this.element.closest( ".ui-page" );\r
566                 this._createSubPages();\r
567 \r
568                 var o = this.options,\r
569                         $list = this.element,\r
570                         self = this,\r
571                         dividertheme = $list.jqmData( "dividertheme" ) || o.dividerTheme,\r
572                         listsplittheme = $list.jqmData( "splittheme" ),\r
573                         listspliticon = $list.jqmData( "spliticon" ),\r
574                         li = $list.children( "li" ),\r
575                         counter = $.support.cssPseudoElement || !$.nodeName( $list[ 0 ], "ol" ) ? 0 : 1,\r
576                         item, itemClass, itemTheme,\r
577                         a, last, splittheme, countParent, icon;\r
578 \r
579                 if ( counter ) {\r
580                         $list.find( ".ui-li-dec" ).remove();\r
581                 }\r
582 \r
583                 for ( var pos = 0, numli = li.length; pos < numli; pos++ ) {\r
584                         item = li.eq( pos );\r
585                         itemClass = "ui-li";\r
586 \r
587                         // If we're creating the element, we update it regardless\r
588                         if ( create || !item.hasClass( "ui-li" ) ) {\r
589                                 itemTheme = item.jqmData( "theme" ) || o.theme;\r
590                                 a = item.children( "a" );\r
591 \r
592                                 if ( a.length ) {\r
593                                         icon = item.jqmData( "icon" );\r
594 \r
595                                         item.buttonMarkup({\r
596                                                 wrapperEls: "div",\r
597                                                 shadow: false,\r
598                                                 corners: false,\r
599                                                 iconpos: "right",\r
600                                                 /* icon: a.length > 1 || icon === false ? false : icon || "arrow-r",*/\r
601                                                 icon: false,    /* Remove unnecessary arrow icon */\r
602                                                 theme: itemTheme\r
603                                         });\r
604 \r
605                                         if ( ( icon != false ) && ( a.length == 1 ) ) {\r
606                                                 item.addClass( "ui-li-has-arrow" );\r
607                                         }\r
608 \r
609                                         a.first().addClass( "ui-link-inherit" );\r
610 \r
611                                         if ( a.length > 1 ) {\r
612                                                 itemClass += " ui-li-has-alt";\r
613 \r
614                                                 last = a.last();\r
615                                                 splittheme = listsplittheme || last.jqmData( "theme" ) || o.splitTheme;\r
616 \r
617                                                 last.appendTo(item)\r
618                                                         .attr( "title", last.getEncodedText() )\r
619                                                         .addClass( "ui-li-link-alt" )\r
620                                                         .empty()\r
621                                                         .buttonMarkup({\r
622                                                                 shadow: false,\r
623                                                                 corners: false,\r
624                                                                 theme: itemTheme,\r
625                                                                 icon: false,\r
626                                                                 iconpos: false\r
627                                                         })\r
628                                                         .find( ".ui-btn-inner" )\r
629                                                                 .append(\r
630                                                                         $( "<span />" ).buttonMarkup({\r
631                                                                                 shadow: true,\r
632                                                                                 corners: true,\r
633                                                                                 theme: splittheme,\r
634                                                                                 iconpos: "notext",\r
635                                                                                 icon: listspliticon || last.jqmData( "icon" ) || o.splitIcon\r
636                                                                         })\r
637                                                                 );\r
638                                         }\r
639                                 } else if ( item.jqmData( "role" ) === "list-divider" ) {\r
640 \r
641                                         itemClass += " ui-li-divider ui-btn ui-bar-" + dividertheme;\r
642                                         item.attr( "role", "heading" );\r
643 \r
644                                         //reset counter when a divider heading is encountered\r
645                                         if ( counter ) {\r
646                                                 counter = 1;\r
647                                         }\r
648 \r
649                                 } else {\r
650                                         itemClass += " ui-li-static ui-body-" + itemTheme;\r
651                                 }\r
652                         }\r
653 \r
654                         if ( counter && itemClass.indexOf( "ui-li-divider" ) < 0 ) {\r
655                                 countParent = item.is( ".ui-li-static:first" ) ? item : item.find( ".ui-link-inherit" );\r
656 \r
657                                 countParent.addClass( "ui-li-jsnumbering" )\r
658                                         .prepend( "<span class='ui-li-dec'>" + (counter++) + ". </span>" );\r
659                         }\r
660 \r
661                         item.add( item.children( ".ui-btn-inner" ) ).addClass( itemClass );\r
662 \r
663                         self._itemApply( $list, item );\r
664                 }\r
665 \r
666                 this._refreshCorners( create );\r
667         },\r
668 \r
669         //create a string for ID/subpage url creation\r
670         _idStringEscape: function( str ) {\r
671                 return str.replace(/[^a-zA-Z0-9]/g, '-');\r
672         },\r
673 \r
674         _createSubPages: function() {\r
675                 var parentList = this.element,\r
676                         parentPage = parentList.closest( ".ui-page" ),\r
677                         parentUrl = parentPage.jqmData( "url" ),\r
678                         parentId = parentUrl || parentPage[ 0 ][ $.expando ],\r
679                         parentListId = parentList.attr( "id" ),\r
680                         o = this.options,\r
681                         dns = "data-" + $.mobile.ns,\r
682                         self = this,\r
683                         persistentFooterID = parentPage.find( ":jqmData(role='footer')" ).jqmData( "id" ),\r
684                         hasSubPages;\r
685 \r
686                 if ( typeof listCountPerPage[ parentId ] === "undefined" ) {\r
687                         listCountPerPage[ parentId ] = -1;\r
688                 }\r
689 \r
690                 parentListId = parentListId || ++listCountPerPage[ parentId ];\r
691 \r
692                 $( parentList.find( "li>ul, li>ol" ).toArray().reverse() ).each(function( i ) {\r
693                         var self = this,\r
694                                 list = $( this ),\r
695                                 listId = list.attr( "id" ) || parentListId + "-" + i,\r
696                                 parent = list.parent(),\r
697                                 nodeEls = $( list.prevAll().toArray().reverse() ),\r
698                                 nodeEls = nodeEls.length ? nodeEls : $( "<span>" + $.trim(parent.contents()[ 0 ].nodeValue) + "</span>" ),\r
699                                 title = nodeEls.first().getEncodedText(),//url limits to first 30 chars of text\r
700                                 id = ( parentUrl || "" ) + "&" + $.mobile.subPageUrlKey + "=" + listId,\r
701                                 theme = list.jqmData( "theme" ) || o.theme,\r
702                                 countTheme = list.jqmData( "counttheme" ) || parentList.jqmData( "counttheme" ) || o.countTheme,\r
703                                 newPage, anchor;\r
704 \r
705                         //define hasSubPages for use in later removal\r
706                         hasSubPages = true;\r
707 \r
708                         newPage = list.detach()\r
709                                                 .wrap( "<div " + dns + "role='page' " + dns + "url='" + id + "' " + dns + "theme='" + theme + "' " + dns + "count-theme='" + countTheme + "'><div " + dns + "role='content'></div></div>" )\r
710                                                 .parent()\r
711                                                         .before( "<div " + dns + "role='header' " + dns + "theme='" + o.headerTheme + "'><div class='ui-title'>" + title + "</div></div>" )\r
712                                                         .after( persistentFooterID ? $( "<div " + dns + "role='footer' " + dns + "id='"+ persistentFooterID +"'>" ) : "" )\r
713                                                         .parent()\r
714                                                                 .appendTo( $.mobile.pageContainer );\r
715 \r
716                         newPage.page();\r
717 \r
718                         anchor = parent.find('a:first');\r
719 \r
720                         if ( !anchor.length ) {\r
721                                 anchor = $( "<a/>" ).html( nodeEls || title ).prependTo( parent.empty() );\r
722                         }\r
723 \r
724                         anchor.attr( "href", "#" + id );\r
725 \r
726                 }).virtuallistview();\r
727 \r
728                 // on pagehide, remove any nested pages along with the parent page, as long as they aren't active\r
729                 // and aren't embedded\r
730                 if( hasSubPages &&\r
731                         parentPage.is( ":jqmData(external-page='true')" ) &&\r
732                         parentPage.data( "page" ).options.domCache === false ) {\r
733 \r
734                         var newRemove = function( e, ui ){\r
735                                 var nextPage = ui.nextPage, npURL;\r
736 \r
737                                 if( ui.nextPage ){\r
738                                         npURL = nextPage.jqmData( "url" );\r
739                                         if( npURL.indexOf( parentUrl + "&" + $.mobile.subPageUrlKey ) !== 0 ){\r
740                                                 self.childPages().remove();\r
741                                                 parentPage.remove();\r
742                                         }\r
743                                 }\r
744                         };\r
745 \r
746                         // unbind the original page remove and replace with our specialized version\r
747                         parentPage\r
748                                 .unbind( "pagehide.remove" )\r
749                                 .bind( "pagehide.remove", newRemove);\r
750                 }\r
751         },\r
752 \r
753         // TODO sort out a better way to track sub pages of the virtuallistview this is brittle\r
754         childPages: function(){\r
755                 var parentUrl = this.parentPage.jqmData( "url" );\r
756 \r
757                 return $( ":jqmData(url^='"+  parentUrl + "&" + $.mobile.subPageUrlKey +"')" );\r
758         }\r
759 });\r
760 \r
761 //auto self-init widgets\r
762 $( document ).bind( "pagecreate create", function( e ){\r
763         $( $.tizen.virtuallistview.prototype.options.initSelector, e.target ).virtuallistview();\r
764 });\r
765 \r
766 })( jQuery );\r