11a1ad0127d189f098a5d26e05dabe5e376d28ae
[platform/framework/web/web-ui-fw.git] / src / js / widgets / jquery.mobile.tizen.extendablelist.js
1 //>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);
2 //>>description: Listview which can be extended more and more
3 //>>label: Extendable list
4 //>>group: Tizen:Widgets
5
6 define( [ '../jquery.mobile.tizen.scrollview' ], function ( ) {
7 //>>excludeEnd("jqmBuildExclude");
8
9 /****************************************************************************
10  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd.
11  *
12  * Permission is hereby granted, free of charge, to any person obtaining a
13  * copy of this software and associated documentation files (the "Software"),
14  * to deal in the Software without restriction, including without limitation
15  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16  * and/or sell copies of the Software, and to permit persons to whom the
17  * Software is furnished to do so, subject to the following conditions:
18  *
19  * The above copyright notice and this permission notice shall be included in
20  * all copies or substantial portions of the Software.
21  *
22  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28  * DEALINGS IN THE SOFTWARE.
29  * ***************************************************************************
30  *
31  *      Author: Wongi Lee <wongi11.lee@samsung.com>
32 */
33
34 /**
35  *      Extendable List Widget for unlimited data.
36  *      To support more then 1,000 items, special list widget developed.
37  *      Fast initialize and append some element into the DOM tree repeatedly.
38  *      DB connection and works like DB cursor.
39  *
40  * HTML Attributes:
41  *
42  *              data-role:      extendablelist
43  *              data-template : jQuery.template ID that populate into extendable list. A button : a <DIV> element with "data-role : button" should be included on data-template.
44  *              data-dbtable : DB Table name. It used as window[DB NAME]. Loaded data should be converted as window object.
45  *              data-extenditems : Number of elements to extend at once.
46  *              
47  *              ID : <UL> element that has "data-role=extendablelist" must have ID attribute.
48  *              Class : <UL> element that has "data-role=extendablelist" should have "vlLoadSuccess" class to guaranty DB loading is completed.
49  *              tmp_load_more : Template ID for "load more" message and button.
50  *
51  *
52  *APIs:
53  *              create ( {
54  *                              itemData: function ( idx ) { return json_obj; },
55  *                              numItemData: number or function () { return number; },
56  *                              cacheItemData: function ( minIdx, maxIdx ) {}
57  *                              } )
58  *                      : Create a extendable list widget. At this moment, _create method is called.
59  *                      args : A collection of options
60  *                              itemData: A function that returns JSON object for given index. Mandatory.
61  *                              numItemData: Total number of itemData. Mandatory.
62  *                              cacheItemData: Extendable list will ask itemData between minIdx and maxIdx.
63  *                                  Developers can implement this function for preparing data.
64  *                                  Optional.
65  *
66  *Examples:
67  *
68  *              <script id="tmp-3-1-1" type="text/x-jquery-tmpl">
69  *                      <li class="ui-li-3-1-1"><span class="ui-li-text-main">${NAME}</span></li>
70  *              </script>
71  *
72  *              <script id="tmp_load_more" type="text/x-jquery-tmpl"> 
73  *                      <li class="ui-li-3-1-1" style="text-align:center; margin:0 auto">
74  *                              <div data-role="button">Load ${NUM_MORE_ITEMS} more items</div>
75  *                      </li>
76  *              </script>
77  *      
78  *              <ul id = "extendable_list_main" data-role="extendablelist" data-extenditems="50" data-template="tmp-3-1-1">
79  *              </ul>
80  *
81  */
82
83 /**
84         @class Extendablelist
85         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.
86         The extendable list widget is used to display a list of unlimited data elements on the screen for better performance. The list is extended if you click the button at the bottom of the list to load more data elements. Extendable lists are based on the jQuery.template plugin as described in the jQuery documentation for jQuery.template plugin.<br/>
87         To add a extendable list widget to the application, use the following code:
88
89                         <script id="tmp-3-1-1" type="text/x-jquery-tmpl">
90                                 <li class="ui-li-3-1-1"><span class="ui-li-text-main">${NAME}</span></li>
91                         </script>
92                         <script id="tmp_load_more" type="text/x-jquery-tmpl">
93                                 <li class="ui-li-3-1-1" style="text-align:center; margin:0 auto">
94                                 <div data-role="button">Load ${NUM_MORE_ITEMS} more items</div>
95                                 </li>
96                         </script>
97                         <ul id="extendable_list_main" data-role="extendablelist" data-extenditems="50" data-template="tmp-3-1-1">
98                         </ul>
99 */
100 /**
101         @property {String} data-role
102         Creates the extendable list view. The value must be set to extendablelist. Only the &lt;ul&gt; element, which a id attribute defined, supports this option. Also, the elLoadSuccess class attribute must be defined in the &lt;ul&gt; element to ensure that loading data from the database is complete.
103 */
104 /**
105         @property {String} data-template
106         Specifies the jQuery.template element ID. The jQuery.template must be defined. The template style can use rem units to support scalability. For using the button at the bottom of the list to load more data elements, there must be list view template with the button. The attribute ID must be tmp_load_more.
107 */
108 /**
109         @property {Integer} data-extenditems
110         Defines the number of data elements to be extended at a time.
111 */
112 ( function ( $, undefined ) {
113
114         //Keeps track of the number of lists per page UID
115         //This allows support for multiple nested list in the same page
116         //https://github.com/jquery/jquery-mobile/issues/1617
117         var listCountPerPage = {};
118
119         $.widget( "tizen.extendablelist", $.mobile.widget, {
120                 options: {
121                         theme: "s",
122                         countTheme: "c",
123                         headerTheme: "b",
124                         dividerTheme: "b",
125                         splitIcon: "arrow-r",
126                         splitTheme: "b",
127                         inset: false,
128                         id:     "",                                             /* Extendable list UL elemet's ID */
129                         extenditems: 50,                        /* Number of append items */
130                         childSelector: " li",           /* To support swipe list */
131                         dbtable: "",
132                         template : "",                          /* Template for each list item */
133                         loadmore : "tmp_load_more",     /* Template for "Load more" message */
134                         scrollview: false,
135                         initSelector: ":jqmData(role='extendablelist')"
136                 },
137
138                 _stylerMouseUp: function () {
139                         $( this ).addClass( "ui-btn-up-s" );
140                         $( this ).removeClass( "ui-btn-down-s" );
141                 },
142
143                 _stylerMouseDown: function () {
144                         $( this ).addClass( "ui-btn-down-s" );
145                         $( this ).removeClass( "ui-btn-up-s" );
146                 },
147
148                 _stylerMouseOver: function () {
149                         $( this ).toggleClass( "ui-btn-hover-s" );
150                 },
151
152                 _stylerMouseOut: function () {
153                         $( this ).toggleClass( "ui-btn-hover-s" );
154                         $( this ).addClass( "ui-btn-up-s" );
155                         $( this ).removeClass( "ui-btn-down-s" );
156                 },
157
158                 _pushData: function ( template ) {
159                         var o = this.options,
160                                 t = this,
161                                 i = 0,
162                                 myTemplate = $( "#" + template ),
163                                 loadMoreItems = ( o.extenditems > t._numItemData - t._lastIndex ? t._numItemData - t.lastIndex : o.extenditems ),
164                                 htmlData;
165
166                         for (i = 0; i < loadMoreItems; i++ ) {
167                                 htmlData = myTemplate.tmpl( t._itemData( i ) );
168                                 $( o.id ).append( $( htmlData ).attr( 'id', 'li_' + i ) );
169
170                                 /* Add style */
171                                 $( o.id + ">" + o.childSelector )
172                                         .addClass( "ui-btn-up-s" )
173                                         .bind( "mouseup", t._stylerMouseUp )
174                                         .bind( "mousedown", t._stylerMouseDown )
175                                         .bind( "mouseover", t._stylerMouseOver )
176                                         .bind( "mouseout", t._stylerMouseOut );
177
178                                 t._lastIndex += 1;
179                         }
180
181                         /* After push data, re-style extendable list widget */
182                         $( o.id ).trigger( "create" );
183                 },
184
185                 _loadmore: function ( event ) {
186                         var t = event.data,     // <li> element
187                                 o = t.options,
188                                 i = 0,
189                                 myTemplate = $( "#" + o.template ),
190                                 loadMoreItems = ( o.extenditems > t._numItemData - t._lastIndex ? t._numItemData - t._lastIndex : o.extenditems ),
191                                 htmlData,
192                                 more_items_to_load,
193                                 num_next_load_items;
194
195                         /* Remove load more message */
196                         $( "#load_more_message" ).remove();
197
198                         /* Append More Items */
199                         for ( i = 0; i < loadMoreItems; i++ ) {
200                                 htmlData = myTemplate.tmpl( t._itemData( t._lastIndex ) );
201                                 $( o.id ).append( $( htmlData ).attr( 'id', 'li_' + t._lastIndex ) );
202                                 t._lastIndex += 1;
203                         }
204
205                         /* Append "Load more" message on the last of list */
206                         if ( t._numItemData > t._lastIndex ) {
207                                 myTemplate = $( "#" + o.loadmore );
208                                 more_items_to_load = t._numItemData - t._lastIndex;
209                                 num_next_load_items = ( o.extenditems <= more_items_to_load ) ? o.extenditems : more_items_to_load;
210                                 htmlData = myTemplate.tmpl( { NUM_MORE_ITEMS : num_next_load_items } );
211
212                                 $( o.id ).append( $( htmlData ).attr( 'id', "load_more_message" ) );
213                         }
214
215                         $( o.id ).trigger( "create" );
216                         $( o.id ).extendablelist( "refresh" );
217                 },
218
219                 recreate: function ( newArray ) {
220                         this._create( {
221                                 itemData: function ( idx ) { return newArray[ idx ]; },
222                                 numItemData: newArray.length
223                         } );
224                 },
225
226                 _initList: function (args ) {
227                         var t = this,
228                                 o = this.options,
229                                 myTemplate,
230                                 more_items_to_load,
231                                 num_next_load_items,
232                                 htmlData;
233
234                         /* Make Gen list by template */
235                         if ( t._lastIndex <= 0 ) {
236                                 t._pushData( o.template );
237
238                                 /* Append "Load more" message on the last of list */
239                                 if ( t._numItemData > t._lastIndex ) {
240                                         myTemplate = $( "#" + o.loadmore );
241                                         more_items_to_load = t._numItemData - t._lastIndex;
242                                         num_next_load_items = ( o.extenditems <= more_items_to_load) ? o.extenditems : more_items_to_load;
243                                         htmlData = myTemplate.tmpl( { NUM_MORE_ITEMS : num_next_load_items } );
244
245                                         $( o.id ).append( $( htmlData ).attr( 'id', "load_more_message" ) );
246
247                                         $( "#load_more_message" ).live( "click", t, t._loadmore );
248                                 } else {
249                                         /* No more items to load */
250                                         $( "#load_more_message" ).die();
251                                         $( "#load_more_message" ).remove();
252                                 }
253                         }
254
255                         if ( o.childSelector == " ul" ) {
256                                 $( o.id + " ul" ).swipelist();
257                         }
258
259                         $( o.id ).trigger( "create" );
260
261                         t.refresh( true );
262                 },
263
264                 create: function () {
265                         var o = this.options;
266
267                         /* external API for AJAX callback */
268                         this._create.apply( this, arguments );
269                 },
270
271                 _create: function ( args ) {
272                         var t = this,
273                                 o = this.options,
274                                 $el = this.element,
275                                 dbtable_name;
276
277
278                         t.destroy();
279
280                         $.extend(this, {
281                                 _itemData: function ( idx ) { return null; },
282                                 _numItemData: 0,
283                                 _cacheItemData: function ( minIdx, maxIdx ) { },
284                                 _lastIndex: 0
285                         });
286
287
288                         // create listview markup
289                         t.element.addClass( function ( i, orig ) {
290                                 return orig + " ui-listview ui-extendable-list-container" + ( t.options.inset ? " ui-listview-inset ui-corner-all ui-shadow " : "" );
291                         });
292
293                         o.id = "#" + $el.attr( "id" );
294
295                         if ( $el.data( "extenditems" ) ) {
296                                 o.extenditems = parseInt( $el.data( "extenditems" ), 10 );
297                         }
298
299                         $( o.id ).bind( "pagehide", function (e) {
300                                 $( o.id ).empty();
301                         });
302
303                         /* Scroll view */
304                         if ( $( ".ui-scrollview-clip" ).size() > 0) {
305                                 o.scrollview = true;
306                         } else {
307                                 o.scrollview = false;
308                         }
309
310                         if ( args ) {
311                                 if ( !t._loadData( args ) ) {
312                                         return;
313                                 }
314                         } else {
315                                 // Legacy support: dbtable
316                                 console.warn("WARNING: The data interface of extendable list is changed. \nOld data interface(data-dbtable) is still supported, but will be removed in next version. \nPlease fix your code soon!");
317
318                                 if ( $( o.id ).hasClass( "elLoadSuccess" ) ) {
319                                         dbtable_name = $el.jqmData('dbtable');
320                                         o.dbtable = window[ dbtable_name ];
321                                         if ( !(o.dbtable) ) {
322                                                 o.dbtable = { };
323                                         }
324                                         t._itemData = function ( idx ) {
325                                                 return o.dbtable[ idx ];
326                                         };
327                                         t._numItemData = o.dbtable.length;
328
329                                 } else {
330                                         console.warn("No elLoadSuccess class");
331                                         return;
332                                 }
333                         }
334
335                         if ( $el.data( "template" ) ) {
336                                 o.template = $el.data( "template" );
337
338                                 /* to support swipe list, <li> or <ul> can be main node of extendable list. */
339                                 if ( $el.data( "swipelist" ) == true ) {
340                                         o.childSelector = " ul";
341                                 } else {
342                                         o.shildSelector = " li";
343                                 }
344                         }
345                         t._initList( args );
346                 },
347
348                 _loadData : function ( args ) {
349                         var self = this;
350
351                         if ( args.itemData && typeof args.itemData == 'function'  ) {
352                                 self._itemData = args.itemData;
353                         } else {
354                                 return false;
355                         }
356                         if ( args.numItemData ) {
357                                 if ( typeof args.numItemData == 'function' ) {
358                                         self._numItemData = args.numItemData( );
359                                 } else if ( typeof args.numItemData == 'number' ) {
360                                         self._numItemData = args.numItemData;
361                                 } else {
362                                         return false;
363                                 }
364                         } else {
365                                 return false;
366                         }
367                         return true;
368                 },
369
370
371                 destroy : function () {
372                         var o = this.options,
373                                 eOTAL_ITEMS = 0,
374                                 last_index = 0;
375
376                         $( o.id ).empty();
377
378                         $( "#load_more_message" ).die();
379                 },
380
381                 _itemApply: function ( $list, item ) {
382                         var $countli = item.find( ".ui-li-count" );
383
384                         if ( $countli.length ) {
385                                 item.addClass( "ui-li-has-count" );
386                         }
387
388                         $countli.addClass( "ui-btn-up-" + ( $list.jqmData( "counttheme" ) || this.options.countTheme ) + " ui-btn-corner-all" );
389
390                         // TODO class has to be defined in markup
391                         item.find( "h1, h2, h3, h4, h5, h6" ).addClass( "ui-li-heading" ).end()
392                                 .find( "p, dl" ).addClass( "ui-li-desc" ).end()
393                                 .find( ">img:eq(0), .ui-link-inherit>img:eq(0)" ).addClass( "ui-li-thumb" ).each(function () {
394                                         item.addClass( $( this ).is( ".ui-li-icon" ) ? "ui-li-has-icon" : "ui-li-has-thumb" );
395                                 }).end()
396                                 .find( ".ui-li-aside" ).each(function () {
397                                         var $this = $( this );
398                                         $this.prependTo( $this.parent() ); //shift aside to front for css float
399                                 });
400                 },
401
402                 _removeCorners: function ( li, which ) {
403                         var top = "ui-corner-top ui-corner-tr ui-corner-tl",
404                                 bot = "ui-corner-bottom ui-corner-br ui-corner-bl";
405
406                         li = li.add( li.find( ".ui-btn-inner, .ui-li-link-alt, .ui-li-thumb" ) );
407
408                         if ( which === "top" ) {
409                                 li.removeClass( top );
410                         } else if ( which === "bottom" ) {
411                                 li.removeClass( bot );
412                         } else {
413                                 li.removeClass( top + " " + bot );
414                         }
415                 },
416
417                 _refreshCorners: function ( create ) {
418                         var $li,
419                                 $visibleli,
420                                 $topli,
421                                 $bottomli;
422
423                         if ( this.options.inset ) {
424                                 $li = this.element.children( "li" );
425                                 // at create time the li are not visible yet so we need to rely on .ui-screen-hidden
426                                 $visibleli = create ? $li.not( ".ui-screen-hidden" ) : $li.filter( ":visible" );
427
428                                 this._removeCorners( $li );
429
430                                 // Select the first visible li element
431                                 $topli = $visibleli.first()
432                                         .addClass( "ui-corner-top" );
433
434                                 $topli.add( $topli.find( ".ui-btn-inner" ) )
435                                         .find( ".ui-li-link-alt" )
436                                                 .addClass( "ui-corner-tr" )
437                                         .end()
438                                         .find( ".ui-li-thumb" )
439                                                 .not( ".ui-li-icon" )
440                                                 .addClass( "ui-corner-tl" );
441
442                                 // Select the last visible li element
443                                 $bottomli = $visibleli.last()
444                                         .addClass( "ui-corner-bottom" );
445
446                                 $bottomli.add( $bottomli.find( ".ui-btn-inner" ) )
447                                         .find( ".ui-li-link-alt" )
448                                                 .addClass( "ui-corner-br" )
449                                         .end()
450                                         .find( ".ui-li-thumb" )
451                                                 .not( ".ui-li-icon" )
452                                                 .addClass( "ui-corner-bl" );
453                         }
454                 },
455
456                 refresh: function ( create ) {
457                         this.parentPage = this.element.closest( ".ui-page" );
458                         this._createSubPages();
459
460                         var o = this.options,
461                                 $list = this.element,
462                                 self = this,
463                                 dividertheme = $list.jqmData( "dividertheme" ) || o.dividerTheme,
464                                 listsplittheme = $list.jqmData( "splittheme" ),
465                                 listspliticon = $list.jqmData( "spliticon" ),
466                                 li = $list.children( "li" ),
467                                 counter = $.support.cssPseudoElement || !$.nodeName( $list[ 0 ], "ol" ) ? 0 : 1,
468                                 item,
469                                 itemClass,
470                                 itemTheme,
471                                 a,
472                                 last,
473                                 splittheme,
474                                 countParent,
475                                 icon,
476                                 pos,
477                                 numli;
478
479                         if ( counter ) {
480                                 $list.find( ".ui-li-dec" ).remove();
481                         }
482
483                         for ( pos = 0, numli = li.length; pos < numli; pos++ ) {
484                                 item = li.eq( pos );
485                                 itemClass = "ui-li";
486
487                                 // If we're creating the element, we update it regardless
488                                 if ( create || !item.hasClass( "ui-li" ) ) {
489                                         itemTheme = item.jqmData( "theme" ) || o.theme;
490                                         a = item.children( "a" );
491
492                                         if ( a.length ) {
493                                                 icon = item.jqmData( "icon" );
494
495                                                 item.buttonMarkup({
496                                                         wrapperEls: "div",
497                                                         shadow: false,
498                                                         corners: false,
499                                                         iconpos: "right",
500                                                         /* icon: a.length > 1 || icon === false ? false : icon || "arrow-r",*/
501                                                         icon: false,    /* Remove unnecessary arrow icon */
502                                                         theme: itemTheme
503                                                 });
504
505                                                 if ( ( icon != false ) && ( a.length == 1 ) ) {
506                                                         item.addClass( "ui-li-has-arrow" );
507                                                 }
508
509                                                 a.first().addClass( "ui-link-inherit" );
510
511                                                 if ( a.length > 1 ) {
512                                                         itemClass += " ui-li-has-alt";
513
514                                                         last = a.last();
515                                                         splittheme = listsplittheme || last.jqmData( "theme" ) || o.splitTheme;
516
517                                                         last.appendTo(item)
518                                                                 .attr( "title", last.getEncodedText() )
519                                                                 .addClass( "ui-li-link-alt" )
520                                                                 .empty()
521                                                                 .buttonMarkup({
522                                                                         shadow: false,
523                                                                         corners: false,
524                                                                         theme: itemTheme,
525                                                                         icon: false,
526                                                                         iconpos: false
527                                                                 })
528                                                                 .find( ".ui-btn-inner" )
529                                                                 .append(
530                                                                         $( "<span />" ).buttonMarkup( {
531                                                                                 shadow : true,
532                                                                                 corners : true,
533                                                                                 theme : splittheme,
534                                                                                 iconpos : "notext",
535                                                                                 icon : listspliticon || last.jqmData( "icon" ) || o.splitIcon
536                                                                         })
537                                                                 );
538                                                 }
539                                         } else if ( item.jqmData( "role" ) === "list-divider" ) {
540
541                                                 itemClass += " ui-li-divider ui-btn ui-bar-" + dividertheme;
542                                                 item.attr( "role", "heading" );
543
544                                                 //reset counter when a divider heading is encountered
545                                                 if ( counter ) {
546                                                         counter = 1;
547                                                 }
548
549                                         } else {
550                                                 itemClass += " ui-li-static ui-body-" + itemTheme;
551                                         }
552                                 }
553
554                                 if ( counter && itemClass.indexOf( "ui-li-divider" ) < 0 ) {
555                                         countParent = item.is( ".ui-li-static:first" ) ? item : item.find( ".ui-link-inherit" );
556
557                                         countParent.addClass( "ui-li-jsnumbering" )
558                                                 .prepend( "<span class='ui-li-dec'>" + (counter++) + ". </span>" );
559                                 }
560
561                                 item.add( item.children( ".ui-btn-inner" ) ).addClass( itemClass );
562
563                                 self._itemApply( $list, item );
564                         }
565
566                         this._refreshCorners( create );
567                 },
568
569                 //create a string for ID/subpage url creation
570                 _idStringEscape: function ( str ) {
571                         return str.replace(/\W/g , "-");
572
573                 },
574
575                 _createSubPages: function () {
576                         var parentList = this.element,
577                                 parentPage = parentList.closest( ".ui-page" ),
578                                 parentUrl = parentPage.jqmData( "url" ),
579                                 parentId = parentUrl || parentPage[ 0 ][ $.expando ],
580                                 parentListId = parentList.attr( "id" ),
581                                 o = this.options,
582                                 dns = "data-" + $.mobile.ns,
583                                 self = this,
584                                 persistentFooterID = parentPage.find( ":jqmData(role='footer')" ).jqmData( "id" ),
585                                 hasSubPages,
586                                 newRemove;
587
588                         if ( typeof listCountPerPage[ parentId ] === "undefined" ) {
589                                 listCountPerPage[ parentId ] = -1;
590                         }
591
592                         parentListId = parentListId || ++listCountPerPage[ parentId ];
593
594                         $( parentList.find( "li>ul, li>ol" ).toArray().reverse() ).each(function ( i ) {
595                                 var self = this,
596                                         list = $( this ),
597                                         listId = list.attr( "id" ) || parentListId + "-" + i,
598                                         parent = list.parent(),
599                                         nodeEls,
600                                         title = nodeEls.first().getEncodedText(),//url limits to first 30 chars of text
601                                         id = ( parentUrl || "" ) + "&" + $.mobile.subPageUrlKey + "=" + listId,
602                                         theme = list.jqmData( "theme" ) || o.theme,
603                                         countTheme = list.jqmData( "counttheme" ) || parentList.jqmData( "counttheme" ) || o.countTheme,
604                                         newPage,
605                                         anchor;
606
607                                 nodeEls = $( list.prevAll().toArray().reverse() );
608                                 nodeEls = nodeEls.length ? nodeEls : $( "<span>" + $.trim(parent.contents()[ 0 ].nodeValue) + "</span>" );
609
610                                 //define hasSubPages for use in later removal
611                                 hasSubPages = true;
612
613                                 newPage = list.detach()
614                                                         .wrap( "<div " + dns + "role='page' " + dns + "url='" + id + "' " + dns + "theme='" + theme + "' " + dns + "count-theme='" + countTheme + "'><div " + dns + "role='content'></div></div>" )
615                                                         .parent()
616                                                                 .before( "<div " + dns + "role='header' " + dns + "theme='" + o.headerTheme + "'><div class='ui-title'>" + title + "</div></div>" )
617                                                                 .after( persistentFooterID ? $( "<div " + dns + "role='footer' " + dns + "id='" + persistentFooterID + "'>" ) : "" )
618                                                                 .parent()
619                                                                         .appendTo( $.mobile.pageContainer );
620
621                                 newPage.page();
622
623                                 anchor = parent.find('a:first');
624
625                                 if ( !anchor.length ) {
626                                         anchor = $( "<a/>" ).html( nodeEls || title ).prependTo( parent.empty() );
627                                 }
628
629                                 anchor.attr( "href", "#" + id );
630
631                         }).extendablelist();
632
633                         // on pagehide, remove any nested pages along with the parent page, as long as they aren't active
634                         // and aren't embedded
635                         if ( hasSubPages &&
636                                         parentPage.is( ":jqmData(external-page='true')" ) &&
637                                         parentPage.data( "page" ).options.domCache === false ) {
638
639                                 newRemove = function ( e, ui ) {
640                                         var nextPage = ui.nextPage, npURL;
641
642                                         if ( ui.nextPage ) {
643                                                 npURL = nextPage.jqmData( "url" );
644                                                 if ( npURL.indexOf( parentUrl + "&" + $.mobile.subPageUrlKey ) !== 0 ) {
645                                                         self.childPages().remove();
646                                                         parentPage.remove();
647                                                 }
648                                         }
649                                 };
650
651                                 // unbind the original page remove and replace with our specialized version
652                                 parentPage
653                                         .unbind( "pagehide.remove" )
654                                         .bind( "pagehide.remove", newRemove);
655                         }
656                 },
657
658                 // TODO sort out a better way to track sub pages of the extendable listview this is brittle
659                 childPages: function () {
660                         var parentUrl = this.parentPage.jqmData( "url" );
661
662                         return $( ":jqmData(url^='" +  parentUrl + "&" + $.mobile.subPageUrlKey + "')" );
663                 }
664         });
665
666         //auto self-init widgets
667         $( document ).bind( "pagecreate create", function ( e ) {
668                 $( $.tizen.extendablelist.prototype.options.initSelector, e.target ).extendablelist();
669         });
670
671 }( jQuery ));
672
673 //>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);
674 } );
675 //>>excludeEnd("jqmBuildExclude");