@@ -156,6 +156,20 @@ Tagify.prototype = {
156
156
return s ;
157
157
} ,
158
158
159
+ setStateSelection ( ) {
160
+ var selection = window . getSelection ( )
161
+
162
+ // save last selection place to be able to inject anything from outside to that specific place
163
+ var sel = {
164
+ anchorOffset : selection . anchorOffset ,
165
+ anchorNode : selection . anchorNode ,
166
+ range : selection . getRangeAt && selection . rangeCount && selection . getRangeAt ( 0 )
167
+ }
168
+
169
+ this . state . selection = sel
170
+ return sel
171
+ } ,
172
+
159
173
/**
160
174
* Get the caret position relative to the viewport
161
175
* https://stackoverflow.com/q/58985076/104380
@@ -364,7 +378,6 @@ Tagify.prototype = {
364
378
? document . createTextNode ( newNode )
365
379
: newNode
366
380
367
- tagElm . appendChild ( newNode )
368
381
tagElm . parentNode . insertBefore ( newNode , tagElm . nextSibling )
369
382
return newNode
370
383
} ,
@@ -533,7 +546,7 @@ Tagify.prototype = {
533
546
/**
534
547
* injects nodes/text at caret position, which is saved on the "state" when "blur" event gets triggered
535
548
* @param {Node } injectedNode [the node to inject at the caret position]
536
- * @param {Object } selection [optional selection Object. must have "anchorNode" & "anchorOffset"]
549
+ * @param {Object } selection [optional range Object. must have "anchorNode" & "anchorOffset"]
537
550
*/
538
551
injectAtCaret ( injectedNode , range ) {
539
552
range = range || this . state . selection . range
@@ -1175,19 +1188,60 @@ Tagify.prototype = {
1175
1188
1176
1189
/**
1177
1190
* Adds a mix-content tag
1178
- * @param {String/Array } tagsItems [A string (single or multiple values with a delimiter), or an Array of Objects or just Array of Strings]
1191
+ * @param {String/Array } tagData A string (single or multiple values with a delimiter), or an Array of Objects or just Array of Strings
1192
+ */
1193
+ addMixTags ( tagsData ) {
1194
+ if ( tagsData [ 0 ] . prefix || this . state . tag ) {
1195
+ this . prefixedTextToTag ( tagsData [ 0 ] )
1196
+ return
1197
+ }
1198
+
1199
+ if ( typeof tagsData == 'string' )
1200
+ tagsData = [ { value :tagsData } ]
1201
+
1202
+
1203
+ var selection = ! ! this . state . selection , // must be cast, not to use the reference which is changing
1204
+ frag = document . createDocumentFragment ( )
1205
+
1206
+ tagsData . forEach ( tagData => {
1207
+ var tagElm = this . createTagElem ( tagData )
1208
+ frag . appendChild ( tagElm )
1209
+ this . insertAfterTag ( tagElm )
1210
+ } )
1211
+
1212
+ // if "selection" exists, assumes intention of inecting the new tag at the last
1213
+ // saved location of the caret inside "this.DOM.input"
1214
+ if ( selection ) {
1215
+ this . injectAtCaret ( frag )
1216
+ }
1217
+ // else, create a range and inject the new tag as the last child of "this.DOM.input"
1218
+ else {
1219
+ this . DOM . input . focus ( )
1220
+ selection = this . setStateSelection ( )
1221
+ selection . range . setStart ( this . DOM . input , selection . range . endOffset )
1222
+ selection . range . setEnd ( this . DOM . input , selection . range . endOffset )
1223
+ this . DOM . input . appendChild ( frag )
1224
+
1225
+ this . updateValueByDOMTags ( ) // updates internal "this.value"
1226
+ this . update ( ) // updates original input/textarea
1227
+ }
1228
+ } ,
1229
+
1230
+ /**
1231
+ * Adds a tag which was activly typed by the user
1232
+ * @param {String/Array } tagsItem [A string (single or multiple values with a delimiter), or an Array of Objects or just Array of Strings]
1179
1233
*/
1180
- addMixTags ( tagsItems ) {
1234
+ prefixedTextToTag ( tagsItem ) {
1181
1235
var _s = this . settings ,
1182
1236
tagElm ,
1183
1237
createdFromDelimiters = this . state . tag . delimiters
1184
1238
1185
- _s . transformTag . call ( this , tagsItems [ 0 ] )
1239
+ _s . transformTag . call ( this , tagsItem )
1186
1240
1187
- tagsItems [ 0 ] . prefix = tagsItems [ 0 ] . prefix || this . state . tag ? this . state . tag . prefix : ( _s . pattern . source || _s . pattern ) [ 0 ] ;
1241
+ tagsItem . prefix = tagsItem . prefix || this . state . tag ? this . state . tag . prefix : ( _s . pattern . source || _s . pattern ) [ 0 ] ;
1188
1242
1189
1243
// TODO: should check if the tag is valid
1190
- tagElm = this . createTagElem ( tagsItems [ 0 ] )
1244
+ tagElm = this . createTagElem ( tagsItem )
1191
1245
1192
1246
// tries to replace a taged textNode with a tagElm, and if not able,
1193
1247
// insert the new tag to the END if "addTags" was called from outside
@@ -1197,7 +1251,7 @@ Tagify.prototype = {
1197
1251
1198
1252
setTimeout ( ( ) => tagElm . classList . add ( this . settings . classNames . tagNoAnimation ) , 300 )
1199
1253
1200
- this . value . push ( tagsItems [ 0 ] )
1254
+ this . value . push ( tagsItem )
1201
1255
this . update ( )
1202
1256
1203
1257
// fixes a firefox bug where if the last child of the input is a tag and not a text, the input cannot get focus (by Tab key)
@@ -1207,7 +1261,7 @@ Tagify.prototype = {
1207
1261
} , this . isFirefox ? 100 : 0 )
1208
1262
1209
1263
this . state . tag = null
1210
- this . trigger ( 'add' , extend ( { } , { tag :tagElm } , { data :tagsItems [ 0 ] } ) )
1264
+ this . trigger ( 'add' , extend ( { } , { tag :tagElm } , { data :tagsItem } ) )
1211
1265
1212
1266
return tagElm
1213
1267
} ,
0 commit comments