Export 0.1.63
[platform/framework/web/web-ui-fw.git] / src / widgets / multibuttonentry / js / jquery.mobile.tizen.multibuttonentry.js
1 /* ***************************************************************************
2  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20  * DEALINGS IN THE SOFTWARE.
21  * ***************************************************************************
22  *
23  *      Author: Kangsik Kim <kangsik81.kim@samsung.com>
24  *                              Minkyeong Kim <minkyeong.kim@samsung.com>
25 */
26
27 /**
28  *      The MultiButtonEntry widget changes a text item to a button. It can be comprised of a number of button widgets. 
29  *      When a user types text and the text gets a specific event to change from a text to a button, 
30  *      the input text is changed to a MultiButtonEntry widget.
31  *      A user can add the MultiButtonEntry widget to a contact list, email list, or another list.
32  *      The typical use of this widget is composing a number of contacts or phone numbers in a specific area of the screen.
33  *
34  *      HTML Attributes:
35  *
36  *              data-list-id : Represents the page id.
37  *                              The page contains data for the user, for example, an address book.
38  *                              If the value is null, anchor button doesn't work. (Default : null)
39  *              data-label:     Provide a label for a user-guide. (Default : 'To : ')
40  *              data-description : This attribute is managing message format.
41  *                              This message is displayed when widget status was changed to 'focusout'. (Default : '+ {0}')
42  *
43  *      APIs:
44  *
45  *              inputtext (  [string]  )
46  *                      : If argument is not exist, will get a string from inputbox.
47  *                      If argument is exist, will set a string to inputbox.
48  *              select (  [number]  )
49  *                      : If no argument exists, gets a string of the selected block.
50  *                      If any button isn't selected on a multibuttonentry widget, this method returns "null" value.
51  *                      When a user call this method with an argument which is a number type,
52  *                      this method selects the button which is matched with the argument.
53  *              add ( text, [number] )
54  *                      :  If second argument does not exist, will insert to a new button at last position.
55  *                      Insert a new button at indexed position. The position is decided by the second argument.
56  *                      "index of position" means that the position of inserting a new button is decided by the second argument on "add" method.
57  *                      For example, if a user call the method like this "add("Tizen", 2)",
58  *                      new button labed "Tizen" will be inserted on the third position.
59  *              remove ( [number] )
60  *                      : If no argument exists, all buttons are removed.
61  *                      Remove a button at indexed position.
62  *                      The position is decided by the second argument. (index: index of button)
63  *              length ( void )
64  *                      : Get a number of buttons.
65  *              foucsIn ( void )
66  *                      : This method change a status to 'focusin'.
67  *                      This status is able to manage a widget.
68  *              focusOut ( void )
69  *                      : Changes the focus status to 'focus out'.
70  *                      The status is not able to manage a widget.
71  *                      All buttons that contained in the widget are removed and
72  *                      summarized message is displayed.
73  *              destroy ( void )
74  *                      : Remove all of the new DOM elements for the current widget that you created.
75  *
76  *      Events:
77  *
78  *              create : Occur when create MultiButtonEntry widget.
79  *              select : Occur when a button is selected.
80  *              add : Occur when new button is inserted.
81  *              remove : Occur when a button is removed.
82  *
83  *      Examples:
84  *
85  *              <div data-role="multibuttonentry" data-label="To : " data-list-id:"#addressbook" data-description="+ {0}">
86  *              </div>
87  *
88  */
89
90
91 /**
92         @class MultiButtonEntry
93         The multi-button entry widget enables the user to enter text and convert it to a button. Each button that is created from entered text as a result of a change event forms a multi-button entry widget. This widget is useful in composing an e-mail or SMS message to a group of addresses, each of which is a clickable item for more actions, such as copying, editing, or removing the address.
94
95         To add a multi-button entry widget to the application, use the following code:
96
97                 <div data-role="multibuttonentry" data-label="To:" data-theme="#addressbook" data-list-id="pageId">
98                 </div>
99 */
100
101 /**
102         @property {String}  data-label
103         Sets a label as a guide for the user.
104         For example, while composing an e-mail message, the 'To: ' label is a guide for the user to enter e-mail addresses.
105 */
106
107 /**
108         @property {String} data-decription
109         Manages the message format.
110         The message is displayed when the widget status changes to focus out
111  */
112 /**
113         @property {String} data-list-id
114         Sets the ID of the page to which the button links.
115 */
116 /**
117         @event create
118         The create event is fired when the multi-button view widget is created:
119
120                 <div data-role="multibuttonentry" data-label="To:" data-theme="#addressbook">
121                 </div>
122                 // Option 01
123                 $(".selector").multibuttonentry
124                 ({
125                         create: function(event, ui)
126                         {
127                                 // Handle the create event
128                         }
129                 });
130                 // Option 02
131                 $(".selector").bind("create", function(event, ui)
132                 {
133                         // Handle the create event
134                 });
135 **/
136 /**
137         @event select
138         The select event is fired when a multi-button view widget button is selected:
139
140                 <div data-role="multibuttonentry" data-label="To:" data-theme="#addressbook">
141                 </div>
142                 // Option 01
143                 $(".selector").multibuttonentry
144                 ({
145                         select: function(event, ui)
146                         {
147                         // Handle the select event
148                         }
149                 });
150                 // Option 02
151                 $(".selector").bind("multibuttonentryselect", function(event, ui)
152                 {
153                         // Handle the select event
154                 });     
155 */
156 /**
157         @event add
158         The add event is fired when a multi-button view widget button is created:
159
160                 <div data-role="multibuttonentry" data-label="To:" data-theme="#addressbook">
161                 </div>
162                 // Option 01
163                 $(".selector").multibuttonentry
164                 ({
165                         add: function(event, ui)
166                         {
167                                 // Handle the add event
168                         }
169                 });
170                 // Option 02
171                 $(".selector").bind("multibuttonentryadd", function(event, ui)
172                 {
173                 // Handle the add event
174                 });
175 */
176 /**
177         @event remove
178         The remove event is fired when a multi-button view widget button is removed:
179
180                 <div data-role="multibuttonentry" data-label="To:" data-theme="#addressbook">
181                 </div>
182                 // Option 01
183                 $(".selector").multibuttonentry
184                 ({
185                         remove: function(event, ui)
186                         {
187                         // Handle the remove event
188                         }
189                 });
190                 // Option 02
191                 $(".selector").bind("multibuttonentryremove", function(event, ui)
192                 {
193                         // Handle the remove event
194                 });
195 */
196 /**
197         @method destroy
198         The destroy method is used to remove in the current widget all the new DOM elements that you have created.
199         
200                 <div data-role="multibuttonentry" data-label="To:" data-theme="#addressbook">
201                 </div>
202                 $(".selector").multibuttonentry("destroy");
203         
204         @since Tizen2.0
205 */
206 /**
207         @method inputText
208         The inputText method is used to manage the widget input box text. If no parameter is set, the method gets the input box text. If a parameter is set, the parameter text is set in the input box.
209         
210                 <div data-role="multibuttonentry" data-label="To:" data-theme="#addressbook">
211                 </div>
212                 $(".selector").multibuttonentry("inputText", [text]);
213 */
214 /**
215         @method select
216         The select method is used to select a multi-button entry widget button based on its index value. If no index value is defined, the method returns the string of the selected block. If there are no buttons present in the widget, the method returns null.
217
218                 <div data-role="multibuttonentry" data-label="To:" data-theme="#addressbook">
219                 </div>
220                 $(".selector").multibuttonentry("select", [index]);
221 */
222 /**
223         @method add
224         The add method is used to add a new multi-button entry widget button with the specified label text at the specified index position. If the index parameter is not defined, the widget button is added at the bottom of the list. For example, the $(".selector").multibuttonentry("add", "Tizen", 2) method call creates a new widget button labeled 'Tizen' at the third position in the widget.
225
226                 <div data-role="multibuttonentry" data-label="To:" data-theme="#addressbook">
227                 </div>
228                 $(".selector").multibuttonentry("add", [text], [index]);
229 */
230 /**
231         @method remove
232         The remove method is used to remove a multi-button entry widget button at the specified index position. If the parameter is not defined, all the widget buttons are removed.
233
234                 <div data-role="multibuttonentry" data-label="To:" data-theme="#addressbook">
235                 </div>
236                 $(".selector").multibuttonentry("remove", [index]);
237 */
238 /**
239         @method length
240         The length method is used to retrieve the number of buttons in the multi-button entry widget:
241                 <div data-role="multibuttonentry" data-label="To:" data-theme="#addressbook">
242                 </div>
243                 $(".selector").multibuttonentry("length");
244 */
245 /**
246         @method focusIn
247         The focusIn method is used to set the focus status to "focus in". This focus state enables the user to add or remove buttons in the multi-button entry widget.
248
249                 <div data-role="multibuttonentry" data-label="To:" data-theme="#addressbook">
250                 </div>
251                 $(".selector").multibuttonentry("focusIn");
252 */
253 /**
254         @method focusOut
255         The focusOut method is used to set the focus status to "focus out". In this focus state, the user cannot manage the buttons in the widget, all the buttons are removed, and a message is displayed.
256
257                 <div data-role="multibuttonentry" data-label="To:" data-theme="#addressbook">
258                 </div>
259                 $(".selector").multibuttonentry("focusOut");
260 */
261 ( function ( $, window, document, undefined ) {
262         $.widget( "tizen.multibuttonentry", $.mobile.widget, {
263                 _focusStatus : null,
264                 _items : null,
265                 _viewWidth : 0,
266                 _reservedWidth : 0,
267                 _currentWidth : 0,
268                 _fontSize : 0,
269                 _anchorWidth : 0,
270                 _labelWidth : 0,
271                 _marginWidth : 0,
272                 options : {
273                         label : "To : ",
274                         listId : null,
275                         description : "+ {0}"
276                 },
277
278                 _create : function () {
279                         var self = this,
280                                 $view = this.element,
281                                 role = $view.jqmData( "role" ),
282                                 option = this.options,
283                                 className = "ui-multibuttonentry-link",
284                                 inputbox = $( document.createElement( "input" ) ),
285                                 labeltag = $( document.createElement( "label" ) ),
286                                 moreBlock = $( document.createElement( "a" ) );
287
288                         $view.hide().empty().addClass( "ui-" + role );
289
290                         // create a label tag.
291                         $( labeltag ).text( option.label ).addClass( "ui-multibuttonentry-label" );
292                         $view.append( labeltag );
293
294                         // create a input tag
295                         $( inputbox ).text( option.label ).addClass( "ui-multibuttonentry-input" );
296                         $view.append( inputbox );
297
298                         // create a anchor tag.
299                         if ( option.listId === null || $.trim( option.listId ).length < 1 || $( option.listId ).length === 0 ) {
300                                 className += "-dim";
301                         }
302                         $( moreBlock ).attr( "href", $.trim( option.listId ) ).attr( "data-role", "button" ).attr( "data-inline", "true" ).attr( "data-icon", "plus" ).attr( "data-style", "circle" ).addClass( "ui-multibuttonentry-link-base" ).addClass( className );
303
304                         // append default htmlelements to main widget.
305                         $view.append( moreBlock );
306
307                         // bind a event
308                         this._bindEvents();
309                         self._focusStatus = "init";
310                         // display widget
311                         $view.show();
312                         $view.attr( "tabindex", -1 ).focusin( function ( e ) {
313                                 self.focusIn();
314                         });
315
316                         // assign global variables
317                         self._viewWidth = $view.innerWidth();
318                         self._reservedWidth += self._calcBlockWidth( moreBlock );
319                         self._reservedWidth += self._calcBlockWidth( labeltag );
320                         self._fontSize = parseInt( $( moreBlock ).css( "font-size" ), 10 );
321                         self._currentWidth = self._reservedWidth;
322                 },
323
324                 // bind events
325                 _bindEvents : function () {
326                         var self = this,
327                                 $view = self.element,
328                                 option = self.options,
329                                 inputbox = $view.find( ".ui-multibuttonentry-input" ),
330                                 moreBlock = $view.find( ".ui-multibuttonentry-link-base" ),
331                                 isSeparator = false;
332
333                         // delegate a event to HTMLDivElement(each block).
334                         $view.delegate( "div", "vclick", function ( event ) {
335                                 if ( $( this ).hasClass( "ui-multibuttonentry-sblock" ) ) {
336                                         // If block is selected, it will be removed.
337                                         self._removeTextBlock();
338                                 }
339
340                                 var lockBlock = $view.find( "div.ui-multibuttonentry-sblock" );
341                                 if ( typeof lockBlock !== "undefined" ) {
342                                         lockBlock.removeClass( "ui-multibuttonentry-sblock" ).addClass( "ui-multibuttonentry-block" );
343                                 }
344                                 $( this ).removeClass( "ui-multibuttonentry-block" ).addClass( "ui-multibuttonentry-sblock" );
345                                 self._trigger( "select" );
346                         });
347
348                         inputbox.bind( "keyup", function ( event ) {
349                                 // 8  : backspace
350                                 // 13 : Enter
351                                 // 186 : semi-colon
352                                 // 188 : comma
353                                 var keyValue = event.keyCode,
354                                         valueString = $( inputbox ).val(),
355                                         valueStrings = [],
356                                         index;
357
358                                 if ( keyValue === 8 ) {
359                                         if ( valueString.length === 0 ) {
360                                                 self._validateTargetBlock();
361                                         }
362                                 } else if ( keyValue === 13 || keyValue === 186 || keyValue === 188 ) {
363                                         if ( valueString.length !== 0 ) {
364                                                 // split content by separators(',', ';')
365                                                 valueStrings = valueString.split ( /[,;]/ );
366                                                 for ( index = 0; index < valueStrings.length; index++ ) {
367                                                         if ( valueStrings[index].length !== 0 && valueStrings[index].replace( /\s/g, "" ).length !== 0 ) {
368                                                                 self._addTextBlock( valueStrings[index] );
369                                                         }
370                                                 }
371                                         }
372                                         inputbox.val( "" );
373                                         isSeparator = true;
374                                 } else {
375                                         self._unlockTextBlock();
376                                 }
377
378                                 return !isSeparator;
379                         });
380
381                         moreBlock.click( function () {
382                                 if ( $( moreBlock ).hasClass( "ui-multibuttonentry-link-dim" ) ) {
383                                         return;
384                                 }
385
386                                 $( inputbox ).hide();
387
388                                 $.mobile.changePage( option.listId, {
389                                         transition: "slide",
390                                         reverse: false,
391                                         changeHash: false
392                                 });
393                         });
394
395                         $( document ).bind( "pagechange.mbe", function ( event ) {
396                                 if ( $view.innerWidth() === 0 ) {
397                                         return ;
398                                 }
399                                 var inputBox = $view.find( ".ui-multibuttonentry-input" );
400                                 if ( self._labelWidth === 0 ) {
401                                         self._labelWidth = $view.find( ".ui-multibuttonentry-label" ).outerWidth( true );
402                                         self._anchorWidth = $view.find( ".ui-multibuttonentry-link-base" ).outerWidth( true );
403                                         self._marginWidth = parseInt( ( $( inputBox ).css( "margin-left" ) ), 10 );
404                                         self._marginWidth += parseInt( ( $( inputBox ).css( "margin-right" ) ), 10 );
405                                         self._viewWidth = $view.innerWidth();
406                                 }
407                                 self._modifyInputBoxWidth();
408                                 $( inputbox ).show();
409                         });
410
411                         $view.bind( "click", function ( event ) {
412                                 if ( self._focusStatus === "focusOut" ) {
413                                         self.focusIn();
414                                 }
415                         });
416                 },
417
418                 // create a textbutton and append this button to parent layer.
419                 // @param arg1 : string
420                 // @param arg2 : index
421                 _addTextBlock : function ( messages, blockIndex ) {
422                         if ( arguments.length === 0 ) {
423                                 return;
424                         }
425
426                         if ( !messages ) {
427                                 return ;
428                         }
429
430                         var self = this,
431                                 $view = self.element,
432                                 content = messages,
433                                 index = blockIndex,
434                                 blocks = null,
435                                 textBlock = null;
436
437                         if ( self._viewWidth === 0 ) {
438                                 self._viewWidth = $view.innerWidth();
439                         }
440
441                         // Create a new text HTMLDivElement.
442                         textBlock = $( document.createElement( 'div' ) );
443
444                         textBlock.text( content ).addClass( "ui-multibuttonentry-block" );
445                         textBlock.css( {'visibility': 'hidden'} );
446
447                         blocks = $view.find( "div" );
448                         if ( index !== null && index <= blocks.length ) {
449                                 $( blocks[index] ).before( textBlock );
450                         } else {
451                                 $view.find( ".ui-multibuttonentry-input" ).before( textBlock );
452                         }
453
454                         textBlock = self._ellipsisTextBlock( textBlock );
455                         textBlock.css( {'visibility': 'visible'} );
456
457                         self._currentWidth += self._calcBlockWidth( textBlock );
458                         self._modifyInputBoxWidth();
459                         self._trigger( "add" );
460                 },
461
462                 _removeTextBlock : function () {
463                         var self = this,
464                                 $view = this.element,
465                                 lockBlock = $view.find( "div.ui-multibuttonentry-sblock" );
466
467                         if ( lockBlock !== null && lockBlock.length > 0 ) {
468                                 self._currentWidth -= self._calcBlockWidth( lockBlock );
469                                 lockBlock.remove();
470                                 self._modifyInputBoxWidth();
471                                 this._trigger( "remove" );
472                         } else {
473                                 $view.find( "div:last" ).removeClass( "ui-multibuttonentry-block" ).addClass( "ui-multibuttonentry-sblock" );
474                         }
475                 },
476
477                 _calcBlockWidth : function ( block ) {
478                         return $( block ).outerWidth( true );
479                 },
480
481                 _unlockTextBlock : function () {
482                         var $view = this.element,
483                                 lockBlock = $view.find( "div.ui-multibuttonentry-sblock" );
484                         if ( !lockBlock ) {
485                                 lockBlock.removeClass( "ui-multibuttonentry-sblock" ).addClass( "ui-multibuttonentry-block" );
486                         }
487                 },
488
489                 // call when remove text block by backspace key.
490                 _validateTargetBlock : function () {
491                         var self = this,
492                                 $view = self.element,
493                                 lastBlock = $view.find( "div:last" ),
494                                 tmpBlock = null;
495
496                         if ( lastBlock.hasClass( "ui-multibuttonentry-sblock" ) ) {
497                                 self._removeTextBlock();
498                         } else {
499                                 tmpBlock = $view.find( "div.ui-multibuttonentry-sblock" );
500                                 tmpBlock.removeClass( "ui-multibuttonentry-sblock" ).addClass( "ui-multibuttonentry-block" );
501                                 lastBlock.removeClass( "ui-multibuttonentry-block" ).addClass( "ui-multibuttonentry-sblock" );
502                         }
503                 },
504
505                 _ellipsisTextBlock : function ( textBlock ) {
506                         var self = this,
507                                 $view = self.element,
508                                 maxWidth = $view.innerWidth() - ( self._labelWidth + self._anchorWidth ) * 2;
509
510                         if ( self._calcBlockWidth( textBlock ) > maxWidth ) {
511                                 $( textBlock ).width( maxWidth - self._marginWidth );
512                         }
513
514                         return textBlock;
515                 },
516
517                 _modifyInputBoxWidth : function () {
518                         var self = this,
519                                 $view = self.element,
520                                 margin = self._marginWidth,
521                                 labelWidth = self._labelWidth,
522                                 anchorWidth = self._anchorWidth,
523                                 inputBoxWidth = self._viewWidth - labelWidth,
524                                 blocks = $view.find( "div" ),
525                                 blockWidth = 0,
526                                 index = 0,
527                                 inputBoxMargin = 10,
528                                 inputBox = $view.find( ".ui-multibuttonentry-input" );
529
530                         if ( $view.width() === 0 ) {
531                                 return;
532                         }
533
534                         for ( index = 0; index < blocks.length; index += 1 ) {
535                                 blockWidth = self._calcBlockWidth( blocks[index] );
536
537                                 if ( blockWidth >= inputBoxWidth + anchorWidth ) {
538                                         if ( blockWidth >= inputBoxWidth ) {
539                                                 inputBoxWidth = self._viewWidth - blockWidth;
540                                         } else {
541                                                 inputBoxWidth = self._viewWidth;
542                                         }
543                                 } else {
544                                         if ( blockWidth >= inputBoxWidth ) {
545                                                 inputBoxWidth = self._viewWidth - blockWidth;
546                                         } else {
547                                                 inputBoxWidth -= blockWidth;
548                                         }
549                                 }
550                         }
551
552                         inputBoxWidth -= margin;
553                         if ( inputBoxWidth < anchorWidth * 2 ) {
554                                 inputBoxWidth = self._viewWidth - margin;
555                         }
556                         $( inputBox ).width( inputBoxWidth - anchorWidth - inputBoxMargin );
557                 },
558
559                 _stringFormat : function ( expression ) {
560                         var pattern = null,
561                                 message = expression,
562                                 i = 0;
563                         for ( i = 1; i < arguments.length; i += 1 ) {
564                                 pattern = "{" + ( i - 1 ) + "}";
565                                 message = message.replace( pattern, arguments[i] );
566                         }
567                         return message;
568                 },
569
570                 _resizeBlocks : function () {
571                         var self = this,
572                                 $view = self.element,
573                                 blocks = $view.find( "div" ),
574                                 index = 0;
575
576                         for ( index = 0 ; index < blocks.length ; index += 1 ) {
577                                 $( blocks[index] ).css( "width", "auto" );
578                                 blocks[index] = self._ellipsisTextBlock( blocks[index] );
579                         }
580                 },
581
582                 //---------------------------------------------------- //
583                 //                                      Public Method   //
584                 //----------------------------------------------------//
585                 //
586                 // Focus In Event
587                 //
588                 focusIn : function () {
589                         if ( this._focusStatus === "focusIn" ) {
590                                 return;
591                         }
592
593                         var $view = this.element;
594
595                         $view.find( "label" ).show();
596                         $view.find( ".ui-multibuttonentry-desclabel" ).remove();
597                         $view.find( "div.ui-multibuttonentry-sblock" ).removeClass( "ui-multibuttonentry-sblock" ).addClass( "ui-multibuttonentry-block" );
598                         $view.find( "div" ).show();
599                         $view.find( ".ui-multibuttonentry-input" ).show();
600                         $view.find( "a" ).show();
601
602                         // change focus state.
603                         this._modifyInputBoxWidth();
604                         this._focusStatus = "focusIn";
605                         $view.removeClass( "ui-multibuttonentry-focusout" ).addClass( "ui-multibuttonentry-focusin" );
606                 },
607
608                 focusOut : function () {
609                         if ( this._focusStatus === "focusOut" ) {
610                                 return;
611                         }
612
613                         var self = this,
614                                 $view = self.element,
615                                 tempBlock = null,
616                                 statement = "",
617                                 index = 0,
618                                 lastIndex = 10,
619                                 label = $view.find( "label" ),
620                                 more = $view.find( "span" ),
621                                 blocks = $view.find( "div" ),
622                                 currentWidth = $view.outerWidth( true ) - more.outerWidth( true ) - label.outerWidth( true ),
623                                 blockWidth = 0;
624
625                         $view.find( ".ui-multibuttonentry-input" ).hide();
626                         $view.find( "a" ).hide();
627                         blocks.hide();
628
629                         currentWidth = currentWidth - self._reservedWidth;
630
631                         for ( index = 0; index < blocks.length; index++ ) {
632                                 blockWidth = $( blocks[index] ).outerWidth( true );
633                                 if ( currentWidth - blockWidth <= 0 ) {
634                                         lastIndex = index - 1;
635                                         break;
636                                 }
637
638                                 $( blocks[index] ).show();
639                                 currentWidth -= blockWidth;
640                         }
641
642                         if ( lastIndex !== blocks.length ) {
643                                 statement = self._stringFormat( self.options.description, blocks.length - lastIndex - 1 );
644                                 tempBlock = $( document.createElement( 'label' ) );
645                                 tempBlock.text( statement );
646                                 tempBlock.addClass( "ui-multibuttonentry-desclabel" ).addClass( "ui-multibuttonentry-desclabel" );
647                                 $( blocks[lastIndex] ).after( tempBlock );
648                         }
649
650                         // update focus state
651                         this._focusStatus = "focusOut";
652                         $view.removeClass( "ui-multibuttonentry-focusin" ).addClass( "ui-multibuttonentry-focusout" );
653                 },
654
655                 inputText : function ( message ) {
656                         var $view = this.element;
657
658                         if ( arguments.length === 0 ) {
659                                 return $view.find( ".ui-multibuttonentry-input" ).val();
660                         }
661                         $view.find( ".ui-multibuttonentry-input" ).val( message );
662                         return message;
663                 },
664
665                 select : function ( index ) {
666                         var $view = this.element,
667                                 lockBlock = null,
668                                 blocks = null;
669
670                         if ( this._focusStatus === "focusOut" ) {
671                                 return;
672                         }
673
674                         if ( arguments.length === 0 ) {
675                                 // return a selected block.
676                                 lockBlock = $view.find( "div.ui-multibuttonentry-sblock" );
677                                 if ( lockBlock ) {
678                                         return lockBlock.text();
679                                 }
680                                 return null;
681                         }
682                         // 1. unlock all blocks.
683                         this._unlockTextBlock();
684                         // 2. select pointed block.
685                         blocks = $view.find( "div" );
686                         if ( blocks.length > index ) {
687                                 $( blocks[index] ).removeClass( "ui-multibuttonentry-block" ).addClass( "ui-multibuttonentry-sblock" );
688                                 this._trigger( "select" );
689                         }
690                         return null;
691                 },
692
693                 add : function ( message, position ) {
694                         if ( this._focusStatus === "focusOut" ) {
695                                 return;
696                         }
697
698                         this._addTextBlock( message, position );
699                 },
700
701                 remove : function ( position ) {
702                         var self = this,
703                                 $view = this.element,
704                                 blocks = $view.find( "div" ),
705                                 index = 0;
706                         if ( this._focusStatus === "focusOut" ) {
707                                 return;
708                         }
709
710                         if ( arguments.length === 0 ) {
711                                 blocks.remove();
712                                 this._trigger( "clear" );
713                         } else if ( typeof position == "number" ) {
714                                 // remove selected button
715                                 index = ( ( position < blocks.length ) ? position : ( blocks.length - 1 ) );
716                                 $( blocks[index] ).remove();
717                                 this._trigger( "remove" );
718                         }
719                         self._modifyInputBoxWidth();
720                 },
721
722                 length : function () {
723                         return this.element.find( "div" ).length;
724                 },
725
726                 refresh : function () {
727                         var self = this,
728                                 $view = this.element;
729
730                         self._viewWidth = $view.innerWidth();
731                         self._resizeBlocks();
732                         self._modifyInputBoxWidth();
733                 },
734
735                 destroy : function () {
736                         var $view = this.element;
737
738                         $view.find( "label" ).remove();
739                         $view.find( "div" ).undelegate( "vclick" ).remove();
740                         $view.find( "a" ).remove();
741                         $view.find( ".ui-multibuttonentry-input" ).unbind( "keyup" ).remove();
742
743                         this._trigger( "destroy" );
744                 }
745         });
746
747         $( document ).bind( "pagecreate create", function () {
748                 $( ":jqmData(role='multibuttonentry')" ).multibuttonentry();
749         });
750
751         $( window ).bind( "resize", function () {
752                 $( ":jqmData(role='multibuttonentry')" ).multibuttonentry( "refresh" );
753         });
754 } ( jQuery, window, document ) );