Merge branch 'master' into tizen_2.1
[platform/framework/web/web-ui-fw.git] / src / js / widgets / jquery.mobile.tizen.fastscroll.js
1 //>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);
2 //>>description: Shows list index and scroll to the index directly
3 //>>label: Fastscroll
4 //>>group: Tizen:Widgets
5
6 define( [ '../jquery.mobile.tizen.scrollview' ], function ( ) {
7 //>>excludeEnd("jqmBuildExclude");
8
9 /*
10  * jQuery Mobile Widget @VERSION
11  *
12  * This software is licensed under the MIT licence (as defined by the OSI at
13  * http://www.opensource.org/licenses/mit-license.php)
14  *
15  * ***************************************************************************
16  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd.
17  * Copyright (c) 2011 by Intel Corporation Ltd.
18  *
19  * Permission is hereby granted, free of charge, to any person obtaining a
20  * copy of this software and associated documentation files (the "Software"),
21  * to deal in the Software without restriction, including without limitation
22  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
23  * and/or sell copies of the Software, and to permit persons to whom the
24  * Software is furnished to do so, subject to the following conditions:
25  *
26  * The above copyright notice and this permission notice shall be included in
27  * all copies or substantial portions of the Software.
28  *
29  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
30  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
31  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
32  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
33  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
34  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
35  * DEALINGS IN THE SOFTWARE.
36  * ***************************************************************************
37  *
38  * Authors: Elliot Smith <elliot.smith@intel.com>
39  *               Yonghwi Park <yonghwi0324.park@samsung.com>
40  */
41
42 // fastscroll is a scrollview controller, which binds
43 // a scrollview to a a list of short cuts; the shortcuts are built
44 // from the text on dividers in the list. Clicking on a shortcut
45 // instantaneously jumps the scrollview to the selected list divider;
46 // mouse movements on the shortcut column move the scrollview to the
47 // list divider matching the text currently under the touch; a popup
48 // with the text currently under the touch is also displayed.
49 //
50 // To apply, add the attribute data-fastscroll="true" to a listview
51 // (a <ul> or <ol> element inside a page). Alternatively, call
52 // fastscroll() on an element.
53 //
54 // The closest element with class ui-scrollview-clip is used as the
55 // scrollview to be controlled.
56 //
57 // If a listview has no dividers or a single divider, the widget won't
58 // display.
59
60 /**
61         @class fastscroll
62         The shortcut scroll widget shows a shortcut list that is bound to its parent scroll bar and respective list view. This widget is displayed as a text pop-up representing shortcuts to different list dividers in the list view. If you select a shortcut text from the shortcut scroll, the parent list view is moved to the location representing the selected shortcut.
63
64         To add a shortcut scroll widget to the application, use the following code:
65
66                 <div class="content" data-role="content" data-scroll="y">
67                         <ul id="contacts" data-role="listview" data-fastscroll="true">
68                                 <li>Anton</li>
69                         </ul>
70                 </div>
71
72         For the shortcut scroll widget to be visible, the parent list view must have multiple list dividers.
73 */
74
75 /**
76         @property {Boolean}  data-fastscroll
77         When set to true, creates a shortcut scroll using the HTML unordered list (&lt;ul&gt;) element.
78 */
79 /**
80         @method fastscroll
81         The shortcut scroll is created for the closest list view with the ui-scrollview-clip class.
82 */
83 /**
84         @method indexString
85         The indexString method is used to get (if no value is defined) or set the string to present the index.
86
87                 <div class="content" data-role="content" data-scroll="y">
88                         ul id="contacts" data-role="listview" data-fastscroll="true">
89                                 <li data-role="list-divider">A</li>
90                                 <li>Anton</li>
91                         </ul>
92                 </div>
93
94                 $(".selector").fastscroll( "indexString" [, indexAlphabet] );
95 */
96 (function ( $, undefined ) {
97
98         $.widget( "tizen.fastscroll", $.mobile.widget, {
99                 options: {
100                         initSelector: ":jqmData(fastscroll)"
101                 },
102
103                 _primaryLanguage: null,
104                 _secondLanguage: null,
105                 _dividerMap: {},
106                 _defaultTime: 500,
107                 _defaultDuration: 500,
108                 _timer: null,
109                 _isFadeOut: false,
110
111                 _create: function () {
112                         var $el = this.element,
113                                 self = this,
114                                 $popup,
115                                 page = $el.closest( ':jqmData(role="page")' ),
116                                 jumpToDivider;
117
118                         this.scrollview = $el.closest( '.ui-scrollview-clip' );
119                         this.shortcutsContainer = $( '<div class="ui-fastscroll" aria-label="Fast scroll bar, double tap to fast scroll mode" tabindex="0"/>' );
120                         this.shortcutsList = $( '<ul aria-hidden="true"></ul>' );
121
122                         // popup for the hovering character
123                         this.scrollview.append($( '<div class="ui-fastscroll-popup"></div>' ) );
124                         $popup = this.scrollview.find( '.ui-fastscroll-popup' );
125
126                         this.shortcutsContainer.append( this.shortcutsList );
127                         this.scrollview.append( this.shortcutsContainer );
128
129                         // find the bottom of the last item in the listview
130                         this.lastListItem = $el.children().last();
131
132                         // remove scrollbars from scrollview
133                         this.scrollview.find( '.ui-scrollbar' ).hide();
134
135                         this.jumpToDivider = function ( divider ) {
136                                 // get the vertical position of the divider (so we can scroll to it)
137                                 var dividerY = $( divider ).position().top,
138                                         // find the bottom of the last list item
139                                         bottomOffset = self.lastListItem.outerHeight( true ) + self.lastListItem.position().top,
140                                         scrollviewHeight = self.scrollview.height(),
141
142                                 // check that after the candidate scroll, the bottom of the
143                                 // last item will still be at the bottom of the scroll view
144                                 // and not some way up the page
145                                         maxScroll = bottomOffset - scrollviewHeight,
146                                         dstOffset;
147
148                                 dividerY = ( dividerY > maxScroll ? maxScroll : dividerY );
149
150                                 // don't apply a negative scroll, as this means the
151                                 // divider should already be visible
152                                 dividerY = Math.max( dividerY, 0 );
153
154                                 // apply the scroll
155                                 self.scrollview.scrollview( 'scrollTo', 0, -dividerY );
156
157                                 dstOffset = self.scrollview.offset();
158                         };
159
160                         this.shortcutsList
161                         // bind mouse over so it moves the scroller to the divider
162                                 .bind( 'touchstart mousedown vmousedown touchmove vmousemove vmouseover', function ( e ) {
163                                         // Get coords relative to the element
164                                         var coords = $.mobile.tizen.targetRelativeCoordsFromEvent( e ),
165                                                 shortcutsListOffset = self.shortcutsList.offset();
166
167                                         if ( self._isFadeOut === true ) {
168                                                 return;
169                                         }
170
171                                         // If the element is a list item, get coordinates relative to the shortcuts list
172                                         if ( e.target.tagName.toLowerCase() === "li" ) {
173                                                 coords.x += $( e.target ).offset().left - shortcutsListOffset.left;
174                                                 coords.y += $( e.target ).offset().top  - shortcutsListOffset.top;
175                                         }
176
177                                         if ( e.target.tagName.toLowerCase() === "span" ) {
178                                                 coords.x += $( e.target ).parent().offset().left - shortcutsListOffset.left;
179                                                 coords.y += $( e.target ).parent().offset().top  - shortcutsListOffset.top;
180                                         }
181
182                                         self.shortcutsList.find( 'li' ).each( function () {
183                                                 var listItem = $( this );
184                                                 $( listItem )
185                                                         .removeClass( "ui-fastscroll-hover" )
186                                                         .removeClass( "ui-fastscroll-hover-up" )
187                                                         .removeClass( "ui-fastscroll-hover-down" );
188                                         });
189                                         // Hit test each list item
190                                         self.shortcutsList.find( 'li' ).each( function () {
191                                                 var listItem = $( this ),
192                                                         l = listItem.offset().left - shortcutsListOffset.left,
193                                                         t = listItem.offset().top  - shortcutsListOffset.top,
194                                                         r = l + Math.abs(listItem.outerWidth( true ) ),
195                                                         b = t + Math.abs(listItem.outerHeight( true ) ),
196                                                         unit,
197                                                         baseTop,
198                                                         baseBottom,
199                                                         omitSet,
200                                                         i;
201
202                                                 if ( coords.x >= l && coords.x <= r && coords.y >= t && coords.y <= b ) {
203                                                         if ( listItem.text() !== "." ) {
204                                                                 self._hitItem( listItem );
205                                                         } else {
206                                                                 omitSet = listItem.data( "omitSet" );
207                                                                 unit = ( b - t ) / omitSet.length;
208                                                                 for ( i = 0; i < omitSet.length; i++ ) {
209                                                                         baseTop = t + ( i * unit );
210                                                                         baseBottom = baseTop + unit;
211                                                                         if ( coords.y >= baseTop && coords.y <= baseBottom ) {
212                                                                                 self._hitOmitItem( listItem, omitSet.charAt( i ) );
213                                                                         }
214                                                                 }
215                                                         }
216                                                         return false;
217                                                 }
218                                                 return true;
219                                         } );
220
221                                         self._setTimer( false );
222
223                                         e.preventDefault();
224                                         e.stopPropagation();
225                                 } )
226                                 // bind mouseout of the fastscroll container to remove popup
227                                 .bind( 'touchend mouseup vmouseup vmouseout', function () {
228                                         $popup.hide();
229                                         $( ".ui-fastscroll-hover" ).removeClass( "ui-fastscroll-hover" );
230                                         $( ".ui-fastscroll-hover-first-item" ).removeClass( "ui-fastscroll-hover-first-item" );
231                                         $( ".ui-fastscroll-hover-up" ).removeClass( "ui-fastscroll-hover-up" );
232                                         $( ".ui-fastscroll-hover-down" ).removeClass( "ui-fastscroll-hover-down" );
233                                         self._setTimer( true );
234                                 } );
235
236                         if ( page && !( page.is( ':visible' ) ) ) {
237                                 page.bind( 'pageshow', function () { self.refresh(); } );
238                         } else {
239                                 self.refresh();
240                         }
241
242                         // refresh the list when dividers are filtered out
243                         $el.bind( 'updatelayout', function () {
244                                 self.refresh();
245                         } );
246
247                         $( window ).unbind( ".fastscroll" ).bind( "resize.fastscroll", function ( e ) {
248                                 self.refresh();
249                         } );
250
251                         self.scrollview.bind( "scrollstart", function ( e ) {
252                                 self._setTimer( false );
253                         }).bind( "scrollstop", function ( e ) {
254                                 self._setTimer( true );
255                         });
256                 },
257
258                 _hitOmitItem: function ( listItem, text ) {
259                         var self = this,
260                                 $popup = self.scrollview.find( '.ui-fastscroll-popup' ),
261                                 divider = self._dividerMap[ text ];
262
263                         if ( typeof divider !== "undefined" ) {
264                                 self.jumpToDivider( $( divider ) );
265                         }
266
267                         $popup.text( text )
268                                 .css( { marginLeft: -( $popup.width() / 2 ),
269                                         marginTop: -( $popup.height() / 2 ),
270                                         padding: $popup.css( "paddingTop" ) } )
271                                 .width( $popup.height() )
272                                 .show();
273
274                         $( listItem ).addClass( "ui-fastscroll-hover" );
275                         if ( listItem.index() === 0 ) {
276                                 $( listItem ).addClass( "ui-fastscroll-hover-first-item" );
277                         }
278                         if ( listItem.index() > 0 ) {
279                                 $( listItem ).siblings().eq( listItem.index() - 1 ).addClass( "ui-fastscroll-hover-up" );
280                         }
281                         $( listItem ).siblings().eq( listItem.index() ).addClass( "ui-fastscroll-hover-down" );
282                 },
283
284                 _hitItem: function ( listItem  ) {
285                         var self = this,
286                                 $popup = self.scrollview.find( '.ui-fastscroll-popup' ),
287                                 text = listItem.text(),
288                                 divider;
289
290                         if ( text === "#" ) {
291                                 divider = self._dividerMap.number;
292                         } else {
293                                 divider = self._dividerMap[ text ];
294                         }
295
296                         if ( typeof divider !== "undefined" ) {
297                                 self.jumpToDivider( $( divider ) );
298                         }
299
300                         $popup.text( text )
301                                 .css( { marginLeft: -( $popup.width() / 2 ),
302                                         marginTop: -( $popup.height() / 2 ),
303                                         padding: $popup.css( "paddingTop" ) } )
304                                 .width( $popup.height() )
305                                 .show();
306
307                         $( listItem ).addClass( "ui-fastscroll-hover" );
308                         if ( listItem.index() === 0 ) {
309                                 $( listItem ).addClass( "ui-fastscroll-hover-first-item" );
310                         }
311                         if ( listItem.index() > 0 ) {
312                                 $( listItem ).siblings().eq( listItem.index() - 1 ).addClass( "ui-fastscroll-hover-up" );
313                         }
314                         $( listItem ).siblings().eq( listItem.index() ).addClass( "ui-fastscroll-hover-down" );
315                 },
316
317                 _focusItem: function ( listItem ) {
318                         var self = this,
319                                 $popup = self.scrollview.find( '.ui-fastscroll-popup' );
320
321                         listItem.focusin( function ( e ) {
322                                 self.shortcutsList.attr( "aria-hidden", false );
323                                 self._hitItem( listItem );
324                                 self._setTimer( false );
325                         }).focusout( function ( e ) {
326                                 self.shortcutsList.attr( "aria-hidden", true );
327                                 $popup.hide();
328                                 $( ".ui-fastscroll-hover" ).removeClass( "ui-fastscroll-hover" );
329                                 $( ".ui-fastscroll-hover-first-item" ).removeClass( "ui-fastscroll-hover-first-item" );
330                                 $( ".ui-fastscroll-hover-up" ).removeClass( "ui-fastscroll-hover-up" );
331                                 $( ".ui-fastscroll-hover-down" ).removeClass( "ui-fastscroll-hover-down" );
332                                 self._setTimer( true );
333                         });
334                 },
335
336                 _contentHeight: function () {
337                         var self = this,
338                                 $content = $( '.ui-scrollview-clip' ),
339                                 header = null,
340                                 footer = null,
341                                 paddingValue = 0,
342                                 clipSize = $( window ).height();
343
344                         if ( $content.hasClass( "ui-content" ) ) {
345                                 paddingValue = parseInt( $content.css( "padding-top" ), 10 );
346                                 clipSize = clipSize - ( paddingValue || 0 );
347                                 paddingValue = parseInt( $content.css( "padding-bottom" ), 10 );
348                                 clipSize = clipSize - ( paddingValue || 0 );
349                                 header = $content.siblings( ".ui-header:visible" );
350                                 footer = $content.siblings( ".ui-footer:visible" );
351
352                                 if ( header ) {
353                                         if ( header.outerHeight( true ) === null ) {
354                                                 clipSize = clipSize - ( $( ".ui-header" ).outerHeight() || 0 );
355                                         } else {
356                                                 clipSize = clipSize - header.outerHeight( true );
357                                         }
358                                 }
359                                 if ( footer ) {
360                                         clipSize = clipSize - footer.outerHeight( true );
361                                 }
362                         } else {
363                                 clipSize = $content.height();
364                         }
365                         return clipSize;
366                 },
367
368                 _omit: function ( numOfItems, maxNumOfItems ) {
369                         var maxGroupNum = parseInt( ( maxNumOfItems - 1 ) / 2, 10 ),
370                                 numOfExtraItems = numOfItems - maxNumOfItems,
371                                 groupPos = [],
372                                 omitInfo = [],
373                                 groupPosLength,
374                                 group,
375                                 size,
376                                 i;
377
378                         if ( ( maxNumOfItems < 3 ) || ( numOfItems <= maxNumOfItems ) ) {
379                                 return;
380                         }
381
382                         if ( numOfExtraItems >= maxGroupNum ) {
383                                 size = 2;
384                                 group = 1;
385                                 groupPosLength = maxGroupNum;
386                         } else {
387                                 size = maxNumOfItems / ( numOfExtraItems + 1 );
388                                 group = size;
389                                 groupPosLength = numOfExtraItems;
390                         }
391
392                         for ( i = 0; i < groupPosLength; i++ ) {
393                                 groupPos.push( parseInt( group, 10 ) );
394                                 group += size;
395                         }
396
397                         for ( i = 0; i < maxNumOfItems; i++ ) {
398                                 omitInfo.push( 1 );
399                         }
400
401                         for ( i = 0; i < numOfExtraItems; i++ ) {
402                                 omitInfo[ groupPos[ i % maxGroupNum ] ]++;
403                         }
404
405                         return omitInfo;
406                 },
407
408                 _createDividerMap: function () {
409                         var self = this,
410                                 primaryCharacterSet = self._primaryLanguage ? self._primaryLanguage.replace( /,/g, "" ) : null,
411                                 secondCharacterSet = self._secondLanguage ? self._secondLanguage.replace( /,/g, "" ) : null,
412                                 numberSet = "0123456789",
413                                 dividers = self.element.find( '.ui-li-divider' ),
414                                 map = {},
415                                 matchToDivider,
416                                 makeCharacterSet,
417                                 indexChar,
418                                 i;
419
420                         matchToDivider = function ( index, divider ) {
421                                 if ( $( divider ).text() === indexChar ) {
422                                         map[ indexChar ] = divider;
423                                 }
424                         };
425
426                         makeCharacterSet = function ( index, divider ) {
427                                 primaryCharacterSet += $( divider ).text();
428                         };
429
430                         if ( primaryCharacterSet === null ) {
431                                 primaryCharacterSet = "";
432                                 dividers.each( makeCharacterSet );
433                         }
434
435                         for ( i = 0; i < primaryCharacterSet.length; i++ ) {
436                                 indexChar = primaryCharacterSet.charAt( i );
437                                 dividers.each( matchToDivider );
438                         }
439
440                         if ( secondCharacterSet !== null ) {
441                                 for ( i = 0; i < secondCharacterSet.length; i++ ) {
442                                         indexChar = secondCharacterSet.charAt( i );
443                                         dividers.each( matchToDivider );
444                                 }
445                         }
446
447                         dividers.each( function ( index, divider ) {
448                                 if (  numberSet.search( $( divider ).text() ) !== -1  ) {
449                                         map.number = divider;
450                                         return false;
451                                 }
452                         });
453
454                         self._dividerMap = map;
455                 },
456
457                 _setTimer: function ( start ) {
458                         var self = this;
459
460                         if ( start === true ) {
461                                 self._timer = setTimeout( function () {
462                                         self._isFadeOut = true;
463                                         self.shortcutsContainer.fadeOut( self._defaultDuration, function () {
464                                                 self._isFadeOut = false;
465                                         });
466                                 }, self._defaultTime );
467                         } else {
468                                 if ( self._timer !== null ) {
469                                         clearTimeout( self._timer );
470                                 }
471                                 self.shortcutsContainer.show();
472                         }
473                 },
474
475                 indexString: function ( indexAlphabet ) {
476                         var self = this,
477                                 characterSet = [];
478
479                         if ( typeof indexAlphabet === "undefined" ) {
480                                 return self._primaryLanguage + ":" + self._secondLanguage;
481                         }
482
483                         characterSet = indexAlphabet.split( ":" );
484                         self._primaryLanguage = characterSet[ 0 ];
485                         if ( characterSet.length === 2 ) {
486                                 self._secondLanguage = characterSet[ 1 ];
487                         }
488                 },
489
490                 refresh: function () {
491                         var self = this,
492                                 primaryCharacterSet = self._primaryLanguage ? self._primaryLanguage.replace( /,/g, "" ) : null,
493                                 secondCharacterSet = self._secondLanguage ? self._secondLanguage.replace( /,/g, "" ) : null,
494                                 contentHeight = self._contentHeight(),
495                                 shapItem = $( '<li tabindex="0" aria-label="double to move Number list"><span aria-hidden="true">#</span><span aria-label="Number"/></li>' ),
496                                 omitIndex = 0,
497                                 makeCharacterSet,
498                                 makeOmitSet,
499                                 itemHandler,
500                                 containerHeight,
501                                 shortcutsItems,
502                                 shortcutItem,
503                                 shortcutsTop,
504                                 minClipHeight,
505                                 maxNumOfItems,
506                                 numOfItems,
507                                 minHeight,
508                                 padding,
509                                 omitInfo,
510                                 dividers,
511                                 listItems,
512                                 emptySize,
513                                 correction,
514                                 indexChar,
515                                 lastIndex,
516                                 seconds,
517                                 height,
518                                 size,
519                                 i;
520
521                         makeCharacterSet = function ( index, divider ) {
522                                 primaryCharacterSet += $( divider ).text();
523                         };
524
525                         makeOmitSet = function ( index, length ) {
526                                 var count,
527                                         omitSet = "";
528
529                                 for ( count = 0; count < length; count++ ) {
530                                         omitSet += primaryCharacterSet[ index + count ];
531                                 }
532
533                                 return omitSet;
534                         };
535
536                         itemHandler = function ( e ) {
537                                 var text = $( this ).text(),
538                                         matchDivider = self._dividerMap[ text ];
539
540                                 if ( typeof matchDivider !== "undefined" ) {
541                                         $( matchDivider ).next().focus();
542                                 }
543                         };
544
545                         self._createDividerMap();
546
547                         self.shortcutsList.find( 'li' ).remove();
548
549                         // get all the dividers from the list and turn them into shortcuts
550                         dividers = self.element.find( '.ui-li-divider' );
551
552                         // get all the list items
553                         listItems = self.element.find('li').not('.ui-li-divider');
554
555                         // only use visible dividers
556                         dividers = dividers.filter( ':visible' );
557                         listItems = listItems.filter( ':visible' );
558
559                         if ( dividers.length < 2 ) {
560                                 self.shortcutsList.hide();
561                                 return;
562                         }
563
564                         self.shortcutsList.show();
565                         self.lastListItem = listItems.last();
566                         self.shortcutsList.append( shapItem );
567                         self._focusItem( shapItem );
568
569                         if ( primaryCharacterSet === null ) {
570                                 primaryCharacterSet = "";
571                                 dividers.each( makeCharacterSet );
572                         }
573
574                         padding = parseInt( shapItem.css( "padding" ), 10 );
575                         minHeight = shapItem.height() + ( padding * 2 );
576                         maxNumOfItems = parseInt( ( contentHeight / minHeight ) - 1, 10 );
577                         numOfItems = primaryCharacterSet.length;
578
579                         maxNumOfItems = secondCharacterSet ? maxNumOfItems - 2 : maxNumOfItems;
580
581                         if ( maxNumOfItems < 3 ) {
582                                 shapItem.remove();
583                                 return;
584                         }
585
586                         omitInfo = self._omit( numOfItems, maxNumOfItems );
587
588                         for ( i = 0; i < primaryCharacterSet.length; i++ ) {
589                                 indexChar = primaryCharacterSet.charAt( i );
590                                 shortcutItem = $( '<li tabindex="0" aria-label="double to move ' + indexChar + ' list">' + indexChar + '</li>' );
591
592                                 self._focusItem( shortcutItem );
593
594                                 if ( typeof omitInfo !== "undefined" && omitInfo[ omitIndex ] > 1 ) {
595                                         shortcutItem = $( '<li>.</li>' );
596                                         shortcutItem.data( "omitSet",  makeOmitSet( i, omitInfo[ omitIndex ] ) );
597                                         i += omitInfo[ omitIndex ] - 1;
598                                 } else {
599                                         shortcutItem.bind( 'vclick', itemHandler );
600                                 }
601
602                                 shapItem.before( shortcutItem );
603                                 omitIndex++;
604                         }
605
606                         if ( secondCharacterSet !== null ) {
607                                 lastIndex = secondCharacterSet.length - 1;
608                                 seconds = [];
609
610                                 seconds.push( secondCharacterSet.charAt( 0 ) );
611                                 seconds.push( secondCharacterSet.charAt( lastIndex ) );
612
613                                 for ( i = 0; i < seconds.length; i++ ) {
614                                         indexChar = seconds[ i ];
615                                         shortcutItem = $( '<li tabindex="0" aria-label="double to move ' + indexChar + ' list">' + indexChar + '</li>' );
616
617                                         self._focusItem( shortcutItem );
618                                         shortcutItem.bind( 'vclick', itemHandler );
619                                         shapItem.before( shortcutItem );
620                                 }
621                         }
622
623                         containerHeight = self.shortcutsContainer.outerHeight();
624                         emptySize = contentHeight - containerHeight;
625                         shortcutsItems = self.shortcutsList.children();
626                         size = parseInt( emptySize / shortcutsItems.length, 10 );
627                         correction = emptySize - ( shortcutsItems.length * size );
628
629                         if ( emptySize > 0 ) {
630                                 shortcutsItems.each( function ( index, item ) {
631                                         height = $( item ).height() + size;
632                                         if ( correction !== 0 ) {
633                                                 height += 1;
634                                                 correction -= 1;
635                                         }
636                                         $( item ).css( {
637                                                 height: height,
638                                                 lineHeight: height + "px"
639                                         } );
640                                 } );
641                         }
642
643                         // position the shortcut flush with the top of the first list divider
644                         shortcutsTop = dividers.first().position().top;
645                         self.shortcutsContainer.css( 'top', shortcutsTop );
646
647                         // make the scrollview clip tall enough to show the whole of the shortcutslist
648                         minClipHeight = shortcutsTop + self.shortcutsContainer.outerHeight() + 'px';
649                         self.scrollview.css( 'min-height', minClipHeight );
650
651                         self._setTimer( false );
652                         self._setTimer( true );
653                 }
654         } );
655
656         $( document ).bind( "pagecreate create", function ( e ) {
657                 $( $.tizen.fastscroll.prototype.options.initSelector, e.target )
658                         .not( ":jqmData(role='none'), :jqmData(role='nojs')" )
659                         .fastscroll();
660         } );
661
662 } ( jQuery ) );
663
664 //>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);
665 } );
666 //>>excludeEnd("jqmBuildExclude");