5252 * promise is returned, the tag will not be removed.
5353 * @param {expression= } [onTagRemoved=NA] Expression to evaluate upon removing an existing tag. The removed tag is available as $tag.
5454 * @param {expression= } [onTagClicked=NA] Expression to evaluate upon clicking an existing tag. The clicked tag is available as $tag.
55+ * @param {boolean= } [allowDblclickToEdit=false] Flag indicating that allow double click to edit current tag.
56+ * @param {string= } [inputSplitPattern=null] Regular expression that split edit input tags.
5557 */
5658export default function TagsInputDirective ( $timeout , $document , $window , $q , tagsInputConfig , tiUtil , tiConstants ) {
5759 'ngInject' ;
5860
5961 function TagList ( options , events , onTagAdding , onTagRemoving ) {
6062 let self = { } ;
6163
62- let getTagText = tag => tiUtil . safeToString ( tag [ options . displayProperty ] ) ;
64+ let getTagText = tag => tiUtil . safeToString ( tag [ options . displayProperty ] ) ;
6365 let setTagText = ( tag , text ) => {
6466 tag [ options . displayProperty ] = text ;
6567 } ;
6668
6769 let canAddTag = tag => {
6870 let tagText = getTagText ( tag ) ;
6971 let valid = tagText &&
70- tagText . length >= options . minLength &&
71- tagText . length <= options . maxLength &&
72- options . allowedTagsPattern . test ( tagText ) &&
73- ! tiUtil . findInObjectArray ( self . items , tag , options . keyProperty || options . displayProperty ) ;
72+ tagText . length >= options . minLength &&
73+ tagText . length <= options . maxLength &&
74+ options . allowedTagsPattern . test ( tagText ) &&
75+ ! tiUtil . findInObjectArray ( self . items , tag , options . keyProperty || options . displayProperty ) ;
7476
7577 return $q . when ( valid && onTagAdding ( { $tag : tag } ) ) . then ( tiUtil . promisifyValue ) ;
7678 } ;
@@ -85,6 +87,10 @@ export default function TagsInputDirective($timeout, $document, $window, $q, tag
8587 return self . add ( tag ) ;
8688 } ;
8789
90+ self . addTextArr = textArr => {
91+ textArr . forEach ( text => self . addText ( text ) ) ;
92+ }
93+
8894 self . add = tag => {
8995 let tagText = getTagText ( tag ) ;
9096
@@ -95,7 +101,7 @@ export default function TagsInputDirective($timeout, $document, $window, $q, tag
95101 setTagText ( tag , tagText ) ;
96102
97103 return canAddTag ( tag )
98- . then ( ( ) => {
104+ . then ( ( ) => {
99105 self . items . push ( tag ) ;
100106 events . trigger ( 'tag-added' , { $tag : tag } ) ;
101107 } )
@@ -201,6 +207,8 @@ export default function TagsInputDirective($timeout, $document, $window, $q, tag
201207 allowLeftoverText : [ Boolean , false ] ,
202208 addFromAutocompleteOnly : [ Boolean , false ] ,
203209 spellcheck : [ Boolean , true ] ,
210+ allowDblclickToEdit : [ Boolean , false ] ,
211+ inputSplitPattern : [ RegExp , null ] ,
204212 useStrings : [ Boolean , false ]
205213 } ) ;
206214
@@ -209,22 +217,22 @@ export default function TagsInputDirective($timeout, $document, $window, $q, tag
209217 tiUtil . handleUndefinedResult ( $scope . onTagRemoving , true ) ) ;
210218
211219 this . registerAutocomplete = ( ) => ( {
212- addTag : function ( tag ) {
220+ addTag : function ( tag ) {
213221 return $scope . tagList . add ( tag ) ;
214222 } ,
215- getTags : function ( ) {
223+ getTags : function ( ) {
216224 return $scope . tagList . items ;
217225 } ,
218- getCurrentTagText : function ( ) {
226+ getCurrentTagText : function ( ) {
219227 return $scope . newTag . text ( ) ;
220228 } ,
221- getOptions : function ( ) {
229+ getOptions : function ( ) {
222230 return $scope . options ;
223231 } ,
224- getTemplateScope : function ( ) {
232+ getTemplateScope : function ( ) {
225233 return $scope . templateScope ;
226234 } ,
227- on : function ( name , handler ) {
235+ on : function ( name , handler ) {
228236 $scope . events . on ( name , handler , true ) ;
229237 return this ;
230238 }
@@ -263,6 +271,20 @@ export default function TagsInputDirective($timeout, $document, $window, $q, tag
263271
264272 ngModelCtrl . $isEmpty = value => ! value || ! value . length ;
265273
274+ scope . isEditing = false ;
275+
276+ scope . editingTag = {
277+ text ( value ) {
278+ if ( angular . isDefined ( value ) ) {
279+ scope . editingText = value ;
280+ events . trigger ( 'edit-input-change' , value ) ;
281+ } else {
282+ return scope . editingText || '' ;
283+ }
284+ } ,
285+ invalid : null
286+ } ;
287+
266288 scope . newTag = {
267289 text ( value ) {
268290 if ( angular . isDefined ( value ) ) {
@@ -281,8 +303,8 @@ export default function TagsInputDirective($timeout, $document, $window, $q, tag
281303 scope . getTagClass = ( tag , index ) => {
282304 let selected = tag === tagList . selected ;
283305 return [
284- scope . tagClass ( { $tag : tag , $index : index , $selected : selected } ) ,
285- { selected : selected }
306+ scope . tagClass ( { $tag : tag , $index : index , $selected : selected } ) ,
307+ { selected : selected }
286308 ] ;
287309 } ;
288310
@@ -337,6 +359,9 @@ export default function TagsInputDirective($timeout, $document, $window, $q, tag
337359 }
338360 } ) ;
339361 } ,
362+ editBlur ( $event , tag ) {
363+ events . trigger ( 'edit-input-blur' , tag ) ;
364+ } ,
340365 paste ( $event ) {
341366 $event . getTextData = ( ) => {
342367 let clipboardData = $event . clipboardData || ( $event . originalEvent && $event . originalEvent . clipboardData ) ;
@@ -356,6 +381,9 @@ export default function TagsInputDirective($timeout, $document, $window, $q, tag
356381 tag : {
357382 click ( tag ) {
358383 events . trigger ( 'tag-clicked' , { $tag : tag } ) ;
384+ } ,
385+ dblclick ( tag ) {
386+ events . trigger ( 'tag-dblclicked' , tag ) ;
359387 }
360388 }
361389 } ;
@@ -365,6 +393,13 @@ export default function TagsInputDirective($timeout, $document, $window, $q, tag
365393 . on ( 'invalid-tag' , scope . onInvalidTag )
366394 . on ( 'tag-removed' , scope . onTagRemoved )
367395 . on ( 'tag-clicked' , scope . onTagClicked )
396+ . on ( 'tag-dblclicked' , ( tag ) => {
397+ if ( options . allowDblclickToEdit ) {
398+ scope . editingTag . text ( tag . text ) ;
399+ tag . editable = true ;
400+ scope . isEditing = true ;
401+ }
402+ } )
368403 . on ( 'tag-added' , ( ) => {
369404 scope . newTag . text ( '' ) ;
370405 } )
@@ -394,11 +429,26 @@ export default function TagsInputDirective($timeout, $document, $window, $q, tag
394429 } )
395430 . on ( 'input-blur' , ( ) => {
396431 if ( options . addOnBlur && ! options . addFromAutocompleteOnly ) {
397- tagList . addText ( scope . newTag . text ( ) ) ;
432+ let tags = scope . newTag . text ( ) . split ( options . inputSplitPattern ) ;
433+ tagList . addTextArr ( tags ) ;
398434 }
399435 element . triggerHandler ( 'blur' ) ;
400436 setElementValidity ( ) ;
401437 } )
438+ . on ( 'edit-input-blur' , tag => {
439+ let editingText = scope . editingTag . text ( ) ;
440+ let tags = editingText . split ( options . inputSplitPattern ) ;
441+ let firstTagText = tags . shift ( ) ;
442+ tag . text = firstTagText ;
443+ tagList . addTextArr ( tags ) ;
444+ tag . editable = false ;
445+ scope . isEditing = false ;
446+ focusInput ( ) ;
447+ } )
448+ . on ( 'edit-input-change' , ( ) => {
449+ tagList . clearSelection ( ) ;
450+ scope . editingTag . invalid = null ;
451+ } )
402452 . on ( 'input-keydown' , event => {
403453 let key = event . keyCode ;
404454
@@ -414,12 +464,17 @@ export default function TagsInputDirective($timeout, $document, $window, $q, tag
414464
415465 let shouldAdd = ! options . addFromAutocompleteOnly && addKeys [ key ] ;
416466 let shouldRemove = ( key === tiConstants . KEYS . backspace || key === tiConstants . KEYS . delete ) && tagList . selected ;
417- let shouldEditLastTag = key === tiConstants . KEYS . backspace && scope . newTag . text ( ) . length === 0 && options . enableEditingLastTag ;
467+ let shouldEditLastTag = key === tiConstants . KEYS . backspace && scope . newTag . text ( ) . length === 0 && options . enableEditingLastTag && ! scope . isEditing ;
418468 let shouldSelect = ( key === tiConstants . KEYS . backspace || key === tiConstants . KEYS . left || key === tiConstants . KEYS . right ) &&
419469 scope . newTag . text ( ) . length === 0 && ! options . enableEditingLastTag ;
420470
421471 if ( shouldAdd ) {
422- tagList . addText ( scope . newTag . text ( ) ) ;
472+ if ( scope . isEditing ) {
473+ element . find ( 'input' ) [ 0 ] . blur ( ) ;
474+ return ;
475+ }
476+ let tags = scope . newTag . text ( ) . split ( options . inputSplitPattern ) ;
477+ tagList . addTextArr ( tags ) ;
423478 }
424479 else if ( shouldEditLastTag ) {
425480 tagList . selectPrior ( ) ;
@@ -451,13 +506,12 @@ export default function TagsInputDirective($timeout, $document, $window, $q, tag
451506 let tags = data . split ( options . pasteSplitPattern ) ;
452507
453508 if ( tags . length > 1 ) {
454- tags . forEach ( tag => {
455- tagList . addText ( tag ) ;
456- } ) ;
509+ tagList . addTextArr ( tags ) ;
457510 event . preventDefault ( ) ;
458511 }
459512 }
460513 } ) ;
461514 }
462515 } ;
463516}
517+
0 commit comments