1 //>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);
2 //>>description: Shows listview swapping its contents automatically
3 //>>label: Virtual listview
4 //>>group: Tizen:Widgets
6 define( [ '../jquery.mobile.tizen.core', '../jquery.mobile.tizen.scrollview' ], function ( ) {
7 //>>excludeEnd("jqmBuildExclude");
9 /* ***************************************************************************
10 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd.
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:
19 * The above copyright notice and this permission notice shall be included in
20 * all copies or substantial portions of the Software.
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 * ***************************************************************************
31 * Author: Wongi Lee <wongi11.lee@samsung.com>
32 * Youmin Ha <youmin.ha@samsung.com>
36 * Virtual List Widget for unlimited data.
37 * To support more then 1,000 items, special list widget developed.
38 * Fast initialize and light DOM tree.
39 * DB connection and works like DB cursor.
43 * data-role: virtuallistview
44 * data-template : jQuery.template ID that populate into virtual list
45 * data-row : Optional. Set number of <li> elements that are used for data handling.
47 * ID : <UL> element that has "data-role=virtuallist" must have ID attribute.
52 * itemData: function ( idx ) { return json_obj; },
53 * numItemData: number or function () { return number; },
54 * cacheItemData: function ( minIdx, maxIdx ) {}
56 * : Create a virtuallist widget. At this moment, _create method is called.
57 * args : A collection of options
58 * itemData: A function that returns JSON object for given index. Mandatory.
59 * numItemData: Total number of itemData. Mandatory.
60 * cacheItemData: Virtuallist will ask itemData between minIdx and maxIdx.
61 * Developers can implement this function for preparing data.
66 * touchstart : Temporary preventDefault applied on touchstart event to avoid broken screen.
70 * <script id="tmp-3-2-7" type="text/x-jquery-tmpl">
71 * <li class="ui-li-3-2-7">
72 * <span class="ui-li-text-main">${NAME}</span>
73 * <img src="00_winset_icon_favorite_on.png" class="ui-li-icon-sub">
74 * <span class="ui-li-text-sub">${ACTIVE}</span>
75 * <span class="ui-li-text-sub2">${FROM}</span>
79 * <ul id="virtuallist-normal_3_2_7_ul" data-role="virtuallistview" data-template="tmp-3-2-7" data-dbtable="JSON_DATA" data-row="100">
86 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.
88 The virtual list widget is used to display a list of unlimited data elements on the screen for better performance. This widget provides easy access to databases to retrieve and display data. Virtual lists are based on the jQuery.template plugin as described in the jQuery documentation for jQuery.template plugin.
90 To add a virtual list widget to the application, use the following code:
92 <script id="tmp-3-2-7" type="text/x-jquery-tmpl">
93 <li class="ui-li-3-2-7">
94 <span class="ui-li-text-main">${NAME}</span>
95 <img src="00_winset_icon_favorite_on.png" class="ui-li-icon-sub"/>
96 <span class="ui-li-text-sub">${ACTIVE}</span>
97 <span class="ui-li-text-sub2">${FROM}</span>
100 <ul id="vlist" data-role="virtuallistview" data-template="tmp-3-2-7" data-dbtable="JSON_DATA" data-row="100"></ul>
103 @property {String} data-role
104 Creates the virtual list view. The value must be set to virtuallistview.
105 Only the >ul< element, which a id attribute defined, supports this option. Also, the vlLoadSuccess class attribute must be defined in the >ul< element to ensure that loading data from the database is complete.
108 @property {String} data-template
109 Defines the jQuery.template element ID.
110 The jQuery.template must be defined. The template style can use rem units to support scalability.
113 @property {Number} data-row
114 Defines the number of virtual list child elements.
115 The minimum value is 20 and the default value is 100. As the value gets higher, the loading time increases while the system performance improves. So you need to pick a value that provides the best performance without excessive loading time.
119 @param {function} itemData(index)
120 : function itemData(index) returns the JSON object matched with the given index. The index value is between 0 and numItemData-1.
121 @param {Number} numItemData
122 : number numItemData or function numItemData() defines or returns a static number of items.
123 @param {function} cacheItemData(minIndex, maxIndex)
124 : function cacheItemData(minIndex, maxIndex) prepares the JSON data. This method is called before calling the itemData() method with index values between minIndex and maxIndex.
127 (function ( $, undefined ) {
129 /* Code for Virtual List Demo */
130 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 */
131 _NO_SCROLL = 0, /* ENUM */
132 _SCROLL_DOWN = 1, /* ENUM */
133 _SCROLL_UP = -1; /* ENUM */
135 $.widget( "tizen.virtuallistview", $.mobile.widget, {
141 splitIcon: "arrow-r",
144 id: "", /* Virtual list UL elemet's ID */
145 childSelector: " li", /* To support swipe list */
148 dbkey: false, /* Data's unique Key */
152 initSelector: ":jqmData(role='virtuallistview')"
155 _stylerMouseUp: function () {
156 $( this ).addClass( "ui-btn-up-s" );
157 $( this ).removeClass( "ui-btn-down-s" );
160 _stylerMouseDown: function () {
161 $( this ).addClass( "ui-btn-down-s" );
162 $( this ).removeClass( "ui-btn-up-s" );
165 _stylerMouseOver: function () {
166 $( this ).toggleClass( "ui-btn-hover-s" );
169 _stylerMouseOut: function () {
170 $( this ).toggleClass( "ui-btn-hover-s" );
171 $( this ).addClass( "ui-btn-up-s" );
172 $( this ).removeClass( "ui-btn-down-s" );
176 // this virtuallistview object
177 // @param[in] template template name(string)
178 _pushData: function ( template ) {
179 var o = this.options,
181 myTemplate = $( "#" + template ), // Get template object
182 // NOTE: o.row = # of rows handled at once. Default value is 100.
183 lastIndex = ( o.row > this._numItemData ? this._numItemData : o.row ), // last index of handled data
186 for ( i = 0; i < lastIndex; i++ ) {
187 htmlData = myTemplate.tmpl( this._itemData( i ) ); // Make rows with template,
188 $( o.id ).append( $( htmlData ).attr( 'id', o.itemIDPrefix + i ) ); // and append it to the vlist object
191 // After pushing data re-style virtuallist widget
192 $( o.id ).trigger( "create" );
195 // Set children <li> elements' position
197 // this: virtuallist element
198 // event: virtuallistview.options
199 // TODO: Why this arg name is 'event'? Not resonable.
200 // (this function is not called with event element as args!)
201 _reposition: function ( event ) {
212 if ( $( o.id + o.childSelector ).size() > 0 ) { // $("#vlistid li")
213 // first child's top position
214 // NOTE: the first element may not be '0'!!!
215 t._title_h = $( o.id + o.childSelector + ':first' ).position().top;
216 // first child's outer height (TODO: reuse selected items)
217 t._line_h = $( o.id + o.childSelector + ':first' ).outerHeight();
219 // container(vlist element)'s innerwidth
220 t._container_w = $( o.id ).innerWidth();
222 // get sum of container's left/right padding
223 padding = parseInt( $( o.id + o.childSelector ).css( "padding-left" ), 10 )
224 + parseInt( $( o.id + o.childSelector ).css( "padding-right" ), 10 );
226 // Add CSS to all <li> elements
227 // * absolute position
229 // * mouse up/down/over/out styles
230 $( o.id + ">" + o.childSelector )
231 .addClass( "position_absolute" )
232 .addClass( "ui-btn-up-s" )
233 .bind( "mouseup", t._stylerMouseUp )
234 .bind( "mousedown", t._stylerMouseDown )
235 .bind( "mouseover", t._stylerMouseOver )
236 .bind( "mouseout", t._stylerMouseOut );
239 // Set absolute top/left position of each <li>
240 $( o.id + ">" + o.childSelector ).each( function ( index ) {
241 margin = parseInt( $( this ).css( "margin-left" ), 10 )
242 + parseInt( $( this ).css( "margin-right" ), 10 );
244 $( this ).css( "top", t._title_h + t._line_h * index + 'px' )
245 .css( "width", t._container_w - padding - margin );
248 // Set Max Listview Height
249 $( o.id ).height( t._numItemData * t._line_h );
252 _resize: function ( event ) {
264 t._container_w = $( o.id ).innerWidth();
266 padding = parseInt( $( o.id + o.childSelector ).css( "padding-left" ), 10 )
267 + parseInt( $( o.id + o.childSelector ).css( "padding-right" ), 10 );
269 $( o.id + o.childSelector ).each( function (index) {
270 margin = parseInt( $( this ).css( "margin-left" ), 10 )
271 + parseInt( $( this ).css( "margin-right" ), 10 );
272 $( this ).css( "width", t._container_w - padding - margin );
276 // New scrollmove function supporting scrollTo
277 _scrollmove: function ( ev ) {
278 var t = ev.data, // vlist (JQM object)
279 o = t.options, // options
280 prevTopBufLen = t._num_top_items, // Previous(remembered) top buf length
287 viewTop: function ( ) {
288 var sv = $( o.id ).parentsUntil( ".ui-page" ).find( ".ui-scrollview-view" ),
289 svTrans = sv.css( "-webkit-transform" ),
290 svTransVal = "0,0,0,0,0,0";
292 svTransVal = svTrans.replace( /matrix\s*\((.*)\)/, "$1" ); // matrix(a,c,b,d,tx,ty)
294 return - parseInt( svTransVal.split(',')[5], 10 );
298 viewTop: function ( ) {
299 return $( window ).scrollTop( ); // TODO: - _line_h?
302 // Get current view top position
303 function viewTop ( ) {
304 return o.scrollview ? _scrollView.viewTop() : _normalScroll.viewTop();
306 // log function for debug
307 function log ( msg ) {
310 console.log( ">>virtualllist: " + msg );
314 // Timer interval function
315 // @param[in] vl virtuallist object (JQM object)
316 function timerMove ( vl, undefined ) {
317 var cy, // current y position
318 cti, // current top idx
319 cbi, // current bottom idx
320 oti = vl._first_index, // old top idx
321 obi = vl._last_index, // old botton idx
322 dti, // delta of top idx
324 toIdx, // index range to be moved
325 delta, // moveItem delta
326 rowLen = vl.options.row, // max. # of items handled at once
327 bufSize, // top/bottom buffer size. unit: # of items
330 // subroutine: Move itemContents in i2 into i1
331 function moveItemContents( vl, i1, i2 ) {
332 // TODO: Find a efficient way to replace data!
333 // Assumption: i1 and i2 has same children.
334 var NODETYPE = { ELEMENT_NODE: 1, TEXT_NODE: 3 },
335 c1, // child item 1 (old)
336 c2, // child item 2 (new)
341 $( i1 ).find( ".ui-li-text-main", ".ui-li-text-sub", ".ui-li-text-sub2", "ui-btn-text" ).each( function ( index ) {
343 newText = $( i2 ).find( ".ui-li-text-main", ".ui-li-text-sub", "ui-btn-text" ).eq( index ).text();
345 $( c1 ).contents().filter( function () {
346 return ( this.nodeType == NODETYPE.TEXT_NODE );
347 } ).get( 0 ).data = newText;
350 $( i1 ).find( "img" ).each( function ( imgIdx ) {
352 newImg = $( i2 ).find( "img" ).eq( imgIdx ).attr( "src" );
354 $( c1 ).attr( "src", newImg );
357 $( i1 ).removeData( ); // Clear old data
360 // subroutine: Move item
361 function moveItem( vl, fromIdx, toIdx ) {
362 var itemData, // data from itemData()
363 item, // item element
364 newItem, // new item element
367 log( ">> move item: " + fromIdx + " --> " + toIdx );
370 item = $( '#' + vl.options.itemIDPrefix + fromIdx ); // TODO: refactor ID generation!
371 if ( ! item || ! item.length ) {
376 tmpl = $( "#" + vl.options.template );
378 newItem = tmpl.tmpl( vl._itemData( toIdx ) );
380 // TODO: Consider touch block while moving?
382 // Move item contents
383 moveItemContents( vl, item, newItem );
385 // clean up temporary item
389 // Move position, and set id
390 item.css( 'top', toIdx * vl._line_h )
391 .attr( 'id' , vl.options.itemIDPrefix + toIdx ); // TODO: refactor ID generation!
393 // TODO: Apply jqmdata? check following old code;
394 // $( oldItem ).removeData( ); // Clear old data
395 // if (key) { $( oldItem ).data( key, $( newItem ).data( key ) ); }
401 // Get current view position
404 // Calculate bufSize: rowLen / 3
405 // NOTE: Assumption: total row length = visible items * 3 (upper+visible+lower)
406 bufSize = Math.ceil( rowLen / 3 );
408 // Calculate current top/bottom index (to be applied)
409 // top index = current position / line height
410 cti = Math.floor( cy / vl._line_h ) - bufSize; // TODO: consider buffer!
411 cbi = cti + rowLen - 1;
413 if ( cti < 0 ) { // Top boundary check
416 } else if ( cbi > ( vl._numItemData - 1 ) ) { // Bottom boundary check
417 cti -= ( cbi - ( vl._numItemData - 1 ) );
418 cbi = ( vl._numItemData - 1 );
423 log( "cy=" + cy + ", oti=" + oti + ", obi=" + obi + ", cti=" + cti + ", cbi=" + cbi + ", dti=" + dti );
425 // switch: dti = 0 --> timer stop condition: delta=0 or scrollstop event comes. END.
427 // Check timer runtime
428 vl.timerStillCount += 1;
429 if ( vl.timerStillCount < 12 ) { // check count ( TODO: test and adjust )
430 log("dti=0 " + vl.timerStillCount + " times");
431 vl.timerMoveID = setTimeout( timerMove, timerInterval, vl ); // run once more
435 log("dti=0 " + vl.timerStillCount + " times. End timer.");
436 vl.timerStillCount = 0;
438 if ( vl.timerMoveID ) {
439 clearTimeout( vl.timerMoveID );
440 vl.timerMoveID = null;
443 // switch: dti >= # of max elements --> total replace.
444 vl.timerStillCount = 0; // Reset still counter
446 if ( Math.abs( dti ) >= rowLen ) {
450 log( ">>> WHOLE CHANGE! delta=" + delta );
452 // switch: dti < # of max elements --> move t2b or b2t until new top/bottom idx is covered
455 toIdx = oti + dti - 1;
458 fromIdx = obi + dti + 1; // dti < 0
462 log( ">>> partial change. delta=" + delta );
466 for ( i = fromIdx; i <= toIdx; i++ ) {
467 moveItem( vl, i, i + delta ); // Change data and position
470 // Store current top/bottom idx into vl
471 vl._first_index = cti;
472 vl._last_index = cbi;
474 // Register timer to check again
475 vl.timerMoveID = setTimeout( timerMove, timerInterval, vl );
477 return; // End of function
480 // ==== function start ====
482 t.timerStillCount = 0; // Count do-nothing time. For behavior tuning.
484 // If a timer function is alive, clear it
485 if ( t.timerMoveID ) {
486 clearTimeout( t.timerMoveID );
487 t.timerMoveID = null;
493 _recreate: function ( newArray ) {
499 t._numItemData = newArray.length;
500 t._direction = _NO_SCROLL;
502 t._last_index = o.row - 1;
504 t._pushData( o.template );
506 if (o.childSelector == " ul" ) {
507 $( o.id + " ul" ).swipelist();
510 $( o.id ).virtuallistview();
517 // Init virtuallistview
518 // this virtuallistview object
519 _initList: function () {
523 /* After AJAX loading success */
525 // Put initial <li> elements
526 t._pushData( o.template );
528 // find a parent page, and run _reposition() at 'pageshow' event
529 // TODO: Consider replace parentsUntil().parent() to parent('.ui-page') ???
530 $( o.id ).parentsUntil( ".ui-page" ).parent().one( "pageshow", function () {
531 setTimeout( function () {
536 // Bind _scrollmove() at 'scrollstart.virtuallist' event
537 $( document ).bind( "scrollstart.virtuallist scrollstop.vrituallist", t, t._scrollmove );
539 // Bind _resize() at 'resize.virtuallist'
540 $( window ).bind( "resize.virtuallist", t._resize );
542 // when ul is a childselector, assume that this is also a swipelist,
543 // and run swipelist constructor
544 if ( o.childSelector == " ul" ) {
545 $( o.id + " ul" ).swipelist();
551 create: function () {
552 var o = this.options;
554 /* external API for AJAX callback */
555 this._create.apply( this, arguments );
557 // TODO: remove this line? _initList() calls reposition...
558 this._reposition( o );
561 _create: function ( args ) {
562 // Extend instance variables
564 _itemData : function ( idx ) { return null; },
566 _cacheItemData : function ( minIdx, maxIdx ) { },
570 _direction : _NO_SCROLL,
573 _num_top_items : 0 // By scroll move, number of hidden elements.
580 shortcutsContainer = $('<div class="ui-virtuallist"/>'),
581 shortcutsList = $('<ul></ul>'),
582 dividers = $el.find(':jqmData(role="virtuallistview" )'),
584 shortcutscroll = this,
589 // Add CSS classes to $el (=virtuallistview)
590 $el.addClass( function ( i, orig ) {
591 return orig + " ui-listview ui-virtual-list-container" + ( t.options.inset ? " ui-listview-inset ui-corner-all ui-shadow " : "" );
594 // keep the vlist's ID
595 o.itemIDPrefix = $el.attr( "id" ) + '_';
596 o.id = "#" + $el.attr( "id" );
598 // when page hides, empty all child elements
599 $( o.id ).bind( "pagehide", function ( e ) {
603 // Find if scrollview is used
604 if ( $( ".ui-scrollview-clip" ).size() > 0 ) {
607 o.scrollview = false;
610 // Calculate page buffer size
611 if ( $el.data( "row" ) ) {
612 o.row = $el.data( "row" );
614 if ( o.row < t._minimum_row ) {
615 o.row = t._minimum_row;
618 o.page_buf = parseInt( ( o.row / 2 ), 10 );
623 if ( args.itemData && typeof args.itemData == 'function' ) {
624 t._itemData = args.itemData;
628 if ( args.numItemData ) {
629 if ( typeof args.numItemData == 'function' ) {
630 t._numItemData = args.numItemData( );
631 } else if ( typeof args.numItemData == 'number' ) {
632 t._numItemData = args.numItemData;
639 } else { // No option is given
640 // Legacy support: dbtable
641 console.warn( "WARNING: The data interface of virtuallist is changed. \nOld data interface(data-dbtable) is still supported, but will be removed in next version. \nPlease fix your code soon!" );
643 /* After DB Load complete, Init Vritual list */
644 if ( $( o.id ).hasClass( "vlLoadSuccess" ) ) {
645 dbtable_name = $el.jqmData('dbtable');
646 dbtable = window[ dbtable_name ];
654 t._itemData = function ( idx ) {
655 return dbtable[ idx ];
657 t._numItemData = dbtable.length;
659 return; // Do nothing
664 if ( $el.data( "template" ) ) {
665 o.template = $el.data( "template" );
667 /* to support swipe list, <li> or <ul> can be main node of virtual list. */
668 if ( $el.data( "swipelist" ) == true ) {
669 o.childSelector = " ul";
671 o.childSelector = " li";
675 // Set data's unique key
676 // NOTE: Unnecessary?
677 if ( $el.data( "dbkey" ) ) {
678 o.dbkey = $el.data( "dbkey" );
681 t._first_index = 0; // initial top idx of <li> element.
682 t._last_index = o.row - 1; // initial bottom idx of <li> element.
683 t._initList(); // NOTE: Called at here only!
686 destroy : function () {
687 var o = this.options;
689 $( document ).unbind( "scrollstop" );
691 $( window ).unbind( "resize.virtuallist" );
695 if ( this.timerMoveID ) {
696 clearTimeout( this.timerMoveID );
697 this.timerMoveID = null;
701 _itemApply: function ( $list, item ) {
702 var $countli = item.find( ".ui-li-count" );
704 if ( $countli.length ) {
705 item.addClass( "ui-li-has-count" );
708 $countli.addClass( "ui-btn-up-" + ( $list.jqmData( "counttheme" ) || this.options.countTheme ) + " ui-btn-corner-all" );
710 // TODO class has to be defined in markup
711 item.find( "h1, h2, h3, h4, h5, h6" ).addClass( "ui-li-heading" ).end()
712 .find( "p, dl" ).addClass( "ui-li-desc" ).end()
713 .find( ">img:eq(0), .ui-link-inherit>img:eq(0)" ).addClass( "ui-li-thumb" ).each( function () {
714 item.addClass( $( this ).is( ".ui-li-icon" ) ? "ui-li-has-icon" : "ui-li-has-thumb" );
716 .find( ".ui-li-aside" ).each(function () {
717 var $this = $( this );
718 $this.prependTo( $this.parent() ); //shift aside to front for css float
722 _removeCorners: function ( li, which ) {
723 var top = "ui-corner-top ui-corner-tr ui-corner-tl",
724 bot = "ui-corner-bottom ui-corner-br ui-corner-bl";
726 li = li.add( li.find( ".ui-btn-inner, .ui-li-link-alt, .ui-li-thumb" ) );
728 if ( which === "top" ) {
729 li.removeClass( top );
730 } else if ( which === "bottom" ) {
731 li.removeClass( bot );
733 li.removeClass( top + " " + bot );
737 _refreshCorners: function ( create ) {
743 if ( this.options.inset ) {
744 $li = this.element.children( "li" );
745 // at create time the li are not visible yet so we need to rely on .ui-screen-hidden
746 $visibleli = create ? $li.not( ".ui-screen-hidden" ) : $li.filter( ":visible" );
748 this._removeCorners( $li );
750 // Select the first visible li element
751 $topli = $visibleli.first()
752 .addClass( "ui-corner-top" );
754 $topli.add( $topli.find( ".ui-btn-inner" ) )
755 .find( ".ui-li-link-alt" )
756 .addClass( "ui-corner-tr" )
758 .find( ".ui-li-thumb" )
759 .not( ".ui-li-icon" )
760 .addClass( "ui-corner-tl" );
762 // Select the last visible li element
763 $bottomli = $visibleli.last()
764 .addClass( "ui-corner-bottom" );
766 $bottomli.add( $bottomli.find( ".ui-btn-inner" ) )
767 .find( ".ui-li-link-alt" )
768 .addClass( "ui-corner-br" )
770 .find( ".ui-li-thumb" )
771 .not( ".ui-li-icon" )
772 .addClass( "ui-corner-bl" );
776 // this virtuallistview object
777 refresh: function ( create ) {
778 this.parentPage = this.element.closest( ".ui-page" );
779 // Make sub page, and move the virtuallist into it...
780 // NOTE: check this subroutine.
781 this._createSubPages();
783 var o = this.options,
784 $list = this.element,
786 dividertheme = $list.jqmData( "dividertheme" ) || o.dividerTheme,
787 listsplittheme = $list.jqmData( "splittheme" ),
788 listspliticon = $list.jqmData( "spliticon" ),
789 li = $list.children( "li" ),
790 counter = $.support.cssPseudoElement || !$.nodeName( $list[ 0 ], "ol" ) ? 0 : 1,
805 $list.find( ".ui-li-dec" ).remove();
808 for ( pos = 0, numli = li.length; pos < numli; pos++ ) {
812 // If we're creating the element, we update it regardless
813 if ( create || !item.hasClass( "ui-li" ) ) {
814 itemTheme = item.jqmData( "theme" ) || o.theme;
815 a = item.children( "a" );
818 icon = item.jqmData( "icon" );
825 /* icon: a.length > 1 || icon === false ? false : icon || "arrow-r",*/
826 icon: false, /* Remove unnecessary arrow icon */
830 if ( ( icon != false ) && ( a.length == 1 ) ) {
831 item.addClass( "ui-li-has-arrow" );
834 a.first().addClass( "ui-link-inherit" );
836 if ( a.length > 1 ) {
837 itemClass += " ui-li-has-alt";
840 splittheme = listsplittheme || last.jqmData( "theme" ) || o.splitTheme;
843 .attr( "title", last.getEncodedText() )
844 .addClass( "ui-li-link-alt" )
853 .find( ".ui-btn-inner" )
855 $( "<span />" ).buttonMarkup({
860 icon: listspliticon || last.jqmData( "icon" ) || o.splitIcon
864 } else if ( item.jqmData( "role" ) === "list-divider" ) {
866 itemClass += " ui-li-divider ui-btn ui-bar-" + dividertheme;
867 item.attr( "role", "heading" );
869 //reset counter when a divider heading is encountered
875 itemClass += " ui-li-static ui-body-" + itemTheme;
879 if ( counter && itemClass.indexOf( "ui-li-divider" ) < 0 ) {
880 countParent = item.is( ".ui-li-static:first" ) ? item : item.find( ".ui-link-inherit" );
882 countParent.addClass( "ui-li-jsnumbering" )
883 .prepend( "<span class='ui-li-dec'>" + (counter++) + ". </span>" );
886 item.add( item.children( ".ui-btn-inner" ) ).addClass( itemClass );
888 self._itemApply( $list, item );
891 this._refreshCorners( create );
894 //create a string for ID/subpage url creation
895 _idStringEscape: function ( str ) {
896 return str.replace(/\W/g , "-");
900 // this virtuallistview object
901 _createSubPages: function () {
902 var parentList = this.element,
903 parentPage = parentList.closest( ".ui-page" ),
904 parentUrl = parentPage.jqmData( "url" ),
905 parentId = parentUrl || parentPage[ 0 ][ $.expando ],
906 parentListId = parentList.attr( "id" ),
908 dns = "data-" + $.mobile.ns,
910 persistentFooterID = parentPage.find( ":jqmData(role='footer')" ).jqmData( "id" ),
914 if ( typeof listCountPerPage[ parentId ] === "undefined" ) {
915 listCountPerPage[ parentId ] = -1;
918 parentListId = parentListId || ++listCountPerPage[ parentId ];
920 $( parentList.find( "li>ul, li>ol" ).toArray().reverse() ).each(function ( i ) {
923 listId = list.attr( "id" ) || parentListId + "-" + i,
924 parent = list.parent(),
926 title = nodeEls.first().getEncodedText(),//url limits to first 30 chars of text
927 id = ( parentUrl || "" ) + "&" + $.mobile.subPageUrlKey + "=" + listId,
928 theme = list.jqmData( "theme" ) || o.theme,
929 countTheme = list.jqmData( "counttheme" ) || parentList.jqmData( "counttheme" ) || o.countTheme,
933 nodeEls = $( list.prevAll().toArray().reverse() );
934 nodeEls = nodeEls.length ? nodeEls : $( "<span>" + $.trim( parent.contents()[ 0 ].nodeValue ) + "</span>" );
936 //define hasSubPages for use in later removal
939 newPage = list.detach()
940 .wrap( "<div " + dns + "role='page' " + dns + "url='" + id + "' " + dns + "theme='" + theme + "' " + dns + "count-theme='" + countTheme + "'><div " + dns + "role='content'></div></div>" )
942 .before( "<div " + dns + "role='header' " + dns + "theme='" + o.headerTheme + "'><div class='ui-title'>" + title + "</div></div>" )
943 .after( persistentFooterID ? $( "<div " + dns + "role='footer' " + dns + "id='" + persistentFooterID + "'>" ) : "" )
945 .appendTo( $.mobile.pageContainer );
949 anchor = parent.find('a:first');
951 if ( !anchor.length ) {
952 anchor = $( "<a/>" ).html( nodeEls || title ).prependTo( parent.empty() );
955 anchor.attr( "href", "#" + id );
957 }).virtuallistview();
959 // on pagehide, remove any nested pages along with the parent page, as long as they aren't active
960 // and aren't embedded
962 parentPage.is( ":jqmData(external-page='true')" ) &&
963 parentPage.data( "page" ).options.domCache === false ) {
965 newRemove = function ( e, ui ) {
966 var nextPage = ui.nextPage, npURL;
969 npURL = nextPage.jqmData( "url" );
970 if ( npURL.indexOf( parentUrl + "&" + $.mobile.subPageUrlKey ) !== 0 ) {
971 self.childPages().remove();
977 // unbind the original page remove and replace with our specialized version
979 .unbind( "pagehide.remove" )
980 .bind( "pagehide.remove", newRemove );
984 // TODO sort out a better way to track sub pages of the virtuallistview this is brittle
985 childPages: function () {
986 var parentUrl = this.parentPage.jqmData( "url" );
988 return $( ":jqmData(url^='" + parentUrl + "&" + $.mobile.subPageUrlKey + "')" );
992 //auto self-init widgets
993 $( document ).bind( "pagecreate create", function ( e ) {
994 $( $.tizen.virtuallistview.prototype.options.initSelector, e.target ).virtuallistview();
999 //>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);
1001 //>>excludeEnd("jqmBuildExclude");