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