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