1/** 2 * Amsify Suggestags 3 * https://github.com/amsify42/jquery.amsify.suggestags 4 */ 5 6var AmsifySuggestags; 7 8(function(factory) { 9 if(typeof module === 'object' && typeof module.exports === 'object') { 10 factory(require('jquery'), window, document); 11 } else { 12 factory(jQuery, window, document); 13 } 14} 15(function($, window, document, undefined) { 16 17 AmsifySuggestags = function(selector) { 18 this.selector = selector; 19 this.settings = { 20 type : 'bootstrap', 21 tagLimit : -1, 22 suggestions : [], 23 suggestMatch : {}, 24 suggestionsAction : {timeout: -1, minChars:2, minChange:-1, delay:100, type: 'GET'}, 25 defaultTagClass : '', 26 classes : [], 27 backgrounds : [], 28 colors : [], 29 whiteList : false, 30 afterAdd : {}, 31 afterRemove : {}, 32 //My changes 33 trimValue : false, 34 dashspaces : false, 35 lowercase : false, 36 selectOnHover : true, 37 triggerChange : false, 38 noSuggestionMsg : '', 39 showAllSuggestions: false, 40 keepLastOnHoverTag: true, 41 printValues : true, 42 checkSimilar : true, 43 delimiters : [], 44 showPlusAfter : 0 45 }; 46 this.method = undefined; 47 this.name = null; 48 this.defaultLabel = 'Type here'; 49 this.classes = { 50 sTagsArea : '.amsify-suggestags-area', 51 inputArea : '.amsify-suggestags-input-area', 52 inputAreaDef : '.amsify-suggestags-input-area-default', 53 focus : '.amsify-focus', 54 sTagsInput : '.amsify-suggestags-input', 55 listArea : '.amsify-suggestags-list', 56 list : '.amsify-list', 57 listItem : '.amsify-list-item', 58 itemPad : '.amsify-item-pad', 59 inputType : '.amsify-select-input', 60 tagItem : '.amsify-select-tag', 61 plusItem : '.amsify-plus-tag', 62 colBg : '.col-bg', 63 removeTag : '.amsify-remove-tag', 64 readyToRemove : '.ready-to-remove', 65 noSuggestion : '.amsify-no-suggestion', 66 showPlusBg : '.show-plus-bg' 67 }; 68 this.selectors = { 69 sTagsArea : null, 70 inputArea : null, 71 inputAreaDef : null, 72 sTagsInput : null, 73 listArea : null, 74 list : null, 75 listGroup : null, 76 listItem : null, 77 itemPad : null, 78 inputType : null, 79 plusTag : null 80 }; 81 this.isRequired = false; 82 this.ajaxActive = false; 83 this.tagNames = []; 84 this.delayTimer = 0; 85 this.blurTgItems= null; 86 }; 87 AmsifySuggestags.prototype = { 88 /** 89 * Merging default settings with custom 90 * @type {object} 91 */ 92 _settings : function(settings) { 93 this.settings = $.extend(true, {}, this.settings, settings); 94 }, 95 96 _setMethod : function(method) { 97 this.method = method; 98 }, 99 100 _init : function() { 101 if(this.checkMethod()) { 102 this.name = ($(this.selector).attr('name'))? $(this.selector).attr('name')+'_amsify': 'amsify_suggestags'; 103 this.createHTML(); 104 this.setEvents(); 105 $(this.selector).hide(); 106 this.setDefault(); 107 } 108 }, 109 110 createHTML : function() { 111 var HTML = '<div class="'+this.classes.sTagsArea.substring(1)+'"></div>'; 112 this.selectors.sTagsArea = $(HTML).insertAfter(this.selector); 113 var labelHTML = '<div class="'+this.classes.inputArea.substring(1)+'"></div>'; 114 this.selectors.inputArea = $(labelHTML).appendTo(this.selectors.sTagsArea); 115 this.defaultLabel = ($(this.selector).attr('placeholder') !== undefined)? $(this.selector).attr('placeholder'): this.defaultLabel; 116 var sTagsInput = '<input type="text" class="'+this.classes.sTagsInput.substring(1)+'" placeholder="'+this.defaultLabel+'">'; 117 this.selectors.sTagsInput = $(sTagsInput).appendTo(this.selectors.inputArea).attr('autocomplete', 'off'); 118 if($(this.selector).attr('required')) { 119 $(this.selector).removeAttr('required'); 120 this.isRequired = true; 121 this.updateIsRequired(); 122 } 123 var listArea = '<div class="'+this.classes.listArea.substring(1)+'"></div>'; 124 this.selectors.listArea = $(listArea).appendTo(this.selectors.sTagsArea); 125 $(this.selectors.listArea).width($(this.selectors.sTagsArea).width()-3); 126 var list = '<ul class="'+this.classes.list.substring(1)+'"></ul>'; 127 this.selectors.list = $(list).appendTo(this.selectors.listArea); 128 this.updateSuggestionList(); 129 this.fixCSS(); 130 }, 131 132 updateIsRequired : function() { 133 if(this.isRequired) { 134 if(this.tagNames.length){ 135 $(this.selectors.sTagsInput).removeAttr('required'); 136 } else { 137 $(this.selectors.sTagsInput).attr('required', 'required'); 138 } 139 } 140 }, 141 142 updateSuggestionList : function() { 143 $(this.selectors.list).html('');
144 $(this.createList()).appendTo(this.selectors.list); 145 }, 146 147 setEvents : function() { 148 var _self = this; 149 $(this.selectors.inputArea).attr('style', $(this.selector).attr('style')).addClass($(this.selector).attr('class')); 150 this.setTagEvents(); 151 if(window !== undefined) { 152 $(window).resize(function(){ 153 $(_self.selectors.listArea).width($(_self.selectors.sTagsArea).width()-3); 154 }); 155 } 156 this.setSuggestionsEvents(); 157 this.setRemoveEvent(); 158 }, 159 160 setTagEvents : function() { 161 var _self = this; 162 $(this.selectors.sTagsInput).focus(function(){ 163 /** 164 * Show all suggestions if setting set to true 165 */ 166 if(_self.settings.showAllSuggestions) { 167 _self.suggestWhiteList('', 0, true); 168 } 169 $(this).closest(_self.classes.inputArea).addClass(_self.classes.focus.substring(1)); 170 if(_self.settings.type == 'materialize') { 171 $(this).css({ 172 'border-bottom': 'none', 173 '-webkit-box-shadow': 'none', 174 'box-shadow': 'none', 175 }); 176 } 177 _self.checkPlusAfter(); 178 }); 179 $(this.selectors.sTagsInput).blur(function(){ 180 $(this).closest(_self.classes.inputArea).removeClass(_self.classes.focus.substring(1)); 181 if(!$(this).val()) { 182 $(_self.selectors.listArea).hide(); 183 } 184 _self.checkPlusAfter(true); 185 }); 186 $(this.selectors.sTagsInput).keyup(function(e){ 187 var keycode = (e.keyCode ? e.keyCode : e.which); 188 var key = ''; 189 if(e.key) { 190 key = e.key; 191 } else { 192 if(keycode == '13') { 193 key = 'Enter'; 194 } else if(keycode == '188') { 195 key = ','; 196 } 197 } 198 /** 199 * Mobile browser fix 200 */ 201 if(keycode == 229 && key == 'Unidentified' && /android|webos|iphone|ipad|ipod|blackberry|iemobile|opera mini/i.test(navigator.userAgent.toLowerCase()) && $(this).val()[$(this).val().length - 1] == ',') 202 { 203 key = ','; 204 } 205 var isDelimiter = ($.inArray(key, _self.settings.delimiters) !== -1)? true: false; 206 if(key == 'Enter' || key == ',' || isDelimiter) { 207 var value = $.trim($(this).val().replace(/,/g , '')); 208 if(isDelimiter) { 209 $.each(_self.settings.delimiters, function(dkey, delimiter) { 210 value = $.trim(value.replace(delimiter, '')); 211 }); 212 } 213 $(this).val(''); 214 _self.addTag(_self.getValue(value)); 215 if(_self.settings.showAllSuggestions) { 216 _self.suggestWhiteList('', 0, true); 217 } 218 } else if(keycode == '8' && !$(this).val()) { 219 var removeClass = _self.classes.readyToRemove.substring(1); 220 if($(this).hasClass(removeClass)) { 221 $item = $(this).closest(_self.classes.inputArea).find(_self.classes.tagItem+':last'); 222 _self.removeTagByItem($item, false); 223 } else { 224 $(this).addClass(removeClass); 225 } 226 $(_self.selectors.listArea).hide(); 227 if(_self.settings.showAllSuggestions) { 228 _self.suggestWhiteList('', 0, true); 229 } 230 } else if((_self.settings.suggestions.length || _self.isSuggestAction()) && ($(this).val() || _self.settings.showAllSuggestions)) { 231 $(this).removeClass(_self.classes.readyToRemove.substring(1)); 232 _self.processWhiteList(keycode, $(this).val()); 233 } 234 }); 235 $(this.selectors.sTagsInput).keypress(function(e){ 236 var keycode = (e.keyCode ? e.keyCode : e.which); 237 if(keycode == 13) { 238 return false; 239 } 240 }); 241 $(this.selectors.sTagsArea).click(function(){ 242 $(_self.selectors.sTagsInput).focus(); 243 }); 244 }, 245 246 setSuggestionsEvents : function() { 247 var _self = this; 248 if(this.settings.selectOnHover) { 249 $(this.selectors.listArea).find(this.classes.listItem).hover(function(){ 250 $(_self.selectors.listArea).find(_self.classes.listItem).removeClass('active'); 251 $(this).addClass('active'); 252 $(_self.selectors.sTagsInput).val($(this).text()); 253 }, function() { 254 $(this).removeClass('active'); 255 if(!_self.settings.keepLastOnHoverTag) { 256 $(_self.selectors.sTagsInput).val(''); 257 } 258 }); 259 } 260 $(this.selectors.listArea).find(this.classes.listItem).click(function(){ 261 _self.addTag($(this).data('val')); 262 $(_self.selectors.sTagsInput).val('').focus(); 263 }); 264 }, 265 266 isSuggestAction : function() { 267 return (this.settings.suggestionsAction && this.settings.suggestionsAction.url); 268 }, 269 270 getTag : function(value) { 271 if(this.settings.suggestions.length) { 272 var tag = value; 273 $.each(this.settings.suggestions, function(key, item){ 274 if(typeof item === 'object' && item.value == value) { 275 tag = item.tag 276 return false;
277 } 278 else if(item == value) { 279 return false; 280 } 281 }); 282 return tag; 283 } 284 return value; 285 }, 286 287 getValue : function(tag) { 288 if(this.settings.suggestions.length) { 289 var value = tag; 290 var lower = tag.toString().toLowerCase(); 291 $.each(this.settings.suggestions, function(key, item){ 292 if(typeof item === 'object' && item.tag.toString().toLowerCase() == lower) { 293 value = item.value 294 return false; 295 } 296 else if(item.toString().toLowerCase() == lower) { 297 return false; 298 } 299 }); 300 return value; 301 } 302 return tag; 303 }, 304 305 processAjaxSuggestion : function(value, keycode) { 306 var _self = this; 307 var actionURL = this.getActionURL(this.settings.suggestionsAction.url); 308 var params = {existingTags: this.tagNames, existing: this.settings.suggestions, term: value}; 309 var ajaxConfig = (this.settings.suggestionsAction.callbacks)? this.settings.suggestionsAction.callbacks: {}; 310 var ajaxFormParams = { 311 url : actionURL, 312 }; 313 if(this.settings.suggestionsAction.type == 'GET') { 314 ajaxFormParams.url = ajaxFormParams.url+'?'+$.param(params); 315 } else { 316 ajaxFormParams.type = this.settings.suggestionsAction.type; 317 ajaxFormParams.data = params; 318 } 319 if(this.settings.suggestionsAction.timeout !== -1) { 320 ajaxFormParams['timeout'] = this.settings.suggestionsAction.timeout*1000; 321 } 322 if(this.settings.suggestionsAction.beforeSend !== undefined && typeof this.settings.suggestionsAction.beforeSend == "function") { 323 ajaxFormParams['beforeSend'] = this.settings.suggestionsAction.beforeSend; 324 } 325 ajaxFormParams['success'] = function(data) { 326 if(data && data.suggestions) { 327 _self.settings.suggestions = $.merge(_self.settings.suggestions, data.suggestions); 328 _self.settings.suggestions = _self.unique(_self.settings.suggestions); 329 _self.updateSuggestionList(); 330 _self.setSuggestionsEvents(); 331 _self.suggestWhiteList(value, keycode); 332 } 333 if(_self.settings.suggestionsAction.success !== undefined && typeof _self.settings.suggestionsAction.success == "function") { 334 _self.settings.suggestionsAction.success(data); 335 } 336 }; 337 if(this.settings.suggestionsAction.error !== undefined && typeof this.settings.suggestionsAction.error == "function") { 338 ajaxFormParams['error'] = this.settings.suggestionsAction.error; 339 } 340 ajaxFormParams['complete'] = function(data) { 341 if(_self.settings.suggestionsAction.complete !== undefined && typeof _self.settings.suggestionsAction.complete == "function") { 342 _self.settings.suggestionsAction.complete(data); 343 } 344 _self.ajaxActive = false; 345 }; 346 347 if(this.settings.suggestionsAction.dataType !== undefined && this.settings.suggestionsAction.dataType !== null) { 348 ajaxFormParams['dataType'] = this.settings.suggestionsAction.dataType; 349 } 350 351 $.ajax(ajaxFormParams); 352 }, 353 354 processWhiteList : function(keycode, value) { 355 if(keycode == '40' || keycode == '38') { 356 var type = (keycode == '40')? 'down': 'up'; 357 this.upDownSuggestion(value, type); 358 } else { 359 clearTimeout(this.delayTimer); 360 var _self = this; 361 this.delayTimer = setTimeout(function() { 362 if(_self.isSuggestAction() && !_self.ajaxActive) { 363 var minChars = _self.settings.suggestionsAction.minChars; 364 var minChange = _self.settings.suggestionsAction.minChange; 365 var lastSearch= _self.selectors.sTagsInput.attr('last-search'); 366 if(value.length >= minChars && (minChange === -1 || !lastSearch || _self.similarity(lastSearch, value)*100 <= minChange)) { 367 _self.selectors.sTagsInput.attr('last-search', value); 368 _self.ajaxActive = true; 369 _self.processAjaxSuggestion(value, keycode); 370 } 371 } else { 372 _self.suggestWhiteList(value, keycode); 373 } 374 }, this.settings.suggestionsAction.delay); 375 } 376 }, 377 378 upDownSuggestion : function(value, type) { 379 var _self = this; 380 var isActive = false; 381 $(this.selectors.listArea).find(this.classes.listItem+':visible').each(function(){ 382 if($(this).hasClass('active')) { 383 $(this).removeClass('active'); 384 if(type == 'up') { 385 $item = $(this).prevAll(_self.classes.listItem+':visible:first'); 386 } else { 387 $item = $(this).nextAll(_self.classes.listItem+':visible:first'); 388 } 389 if($item.length) { 390 isActive = true; 391 $item.addClass('active'); 392 $(_self.selectors.sTagsInput).val($item.text()); 393 } 394 return false;
395 } 396 }); 397 if(!isActive) { 398 var childItem = (type == 'down')? 'first': 'last'; 399 $item = $(this.selectors.listArea).find(this.classes.listItem+':visible:'+childItem); 400 if($item.length) { 401 $item.addClass('active'); 402 $(_self.selectors.sTagsInput).val($item.text()); 403 } 404 } 405 }, 406 407 suggestWhiteList : function(value, keycode, showAll) { 408 var _self = this; 409 var found = false; 410 var all = (showAll)? true: false; 411 var lower = value.toString().toLowerCase(); 412 $(this.selectors.listArea).find(_self.classes.noSuggestion).hide(); 413 var $list = $(this.selectors.listArea).find(this.classes.list); 414 $list.find(this.classes.listItem).each(function(){ 415 var dataVal = $(this).data('val'); 416 if($.isNumeric(dataVal)) { 417 dataVal = (value.toString().indexOf('.') == -1)? parseInt(dataVal): parseFloat(dataVal); 418 } 419 420 /** 421 * Suggest item matching result 422 */ 423 var suggestItemResult = 0; 424 if(_self.settings.suggestMatch && typeof _self.settings.suggestMatch == "function") { 425 suggestItemResult = _self.settings.suggestMatch($(this).text(), value); 426 } else { 427 suggestItemResult = ~$(this).text().toString().toLowerCase().indexOf(lower); 428 } 429 430 if((all || suggestItemResult) && $.inArray(dataVal, _self.tagNames) === -1) { 431 $(this).attr('data-show', 1); 432 found = true; 433 } else { 434 $(this).removeAttr('data-show'); 435 } 436 $(this).hide(); 437 }); 438 if(found) { 439 /** 440 * Sorting the suggestions 441 */ 442 $dataShow = $list.find(this.classes.listItem+'[data-show]'); 443 if(lower) { 444 $dataShow.sort(function(a, b) { 445 return value.localeCompare($(a).text().toString()); 446 }).appendTo($list); 447 } else { 448 $dataShow.sort(function(a, b) { 449 return $(a).text().toString().localeCompare($(b).text().toString()); 450 }).appendTo($list); 451 } 452 $dataShow.each(function(){ 453 $(this).show(); 454 }); 455 456 /** 457 * If only one item left in whitelist suggestions 458 */ 459 $item = $(this.selectors.listArea).find(this.classes.listItem+':visible'); 460 if($item.length == 1 && keycode != '8') { 461 if((this.settings.whiteList && this.isSimilarText(value.toLowerCase(), $item.text().toLowerCase(), 40)) || this.isSimilarText(value.toLowerCase(), $item.text().toLowerCase(), 60)) { 462 $item.addClass('active'); 463 $(this.selectors.sTagsInput).val($item.text()); 464 } 465 } else { 466 $item.removeClass('active'); 467 } 468 469 $(this.selectors.listArea).show(); 470 471 } else { 472 if(value && _self.settings.noSuggestionMsg) { 473 $(this.selectors.listArea).find(_self.classes.listItem).hide(); 474 $(this.selectors.listArea).find(_self.classes.noSuggestion).show(); 475 } else { 476 $(this.selectors.listArea).hide(); 477 } 478 } 479 }, 480 481 setDefault : function() { 482 var _self = this; 483 var items = $(this.selector).val().split(','); 484 if(items.length) { 485 $.each(items, function(index, item){ 486 _self.addTag($.trim(item)); 487 }); 488 } 489 }, 490 491 setRemoveEvent: function() { 492 var _self = this; 493 $(this.selectors.inputArea).find(this.classes.removeTag).click(function(e){ 494 e.stopImmediatePropagation(); 495 $tagItem = $(this).closest(_self.classes.tagItem); 496 _self.removeTagByItem($tagItem, false); 497 }); 498 }, 499 500 createList : function() { 501 var _self = this; 502 var listHTML = ''; 503 $.each(this.settings.suggestions, function(index, item){ 504 var value = ''; 505 var tag = ''; 506 if(typeof item === 'object') { 507 value = item.value 508 tag = item.tag 509 } else { 510 value = item; 511 tag = item; 512 } 513 listHTML += '<li class="'+_self.classes.listItem.substring(1)+'" data-val="'+value+'">'+tag+'</li>'; 514 }); 515 if(_self.settings.noSuggestionMsg) { 516 listHTML += '<li class="'+_self.classes.noSuggestion.substring(1)+'">'+_self.settings.noSuggestionMsg+'</li>'; 517 } 518 return listHTML; 519 }, 520 521 addTag : function(value, animate=true) { 522 if(!value) { 523 return; 524 } 525 // Trim value 526 if (typeof value === "string" && this.settings.trimValue) { 527 value = $.trim(value); 528 } 529 530 // lowercase and dash 531 if (typeof value === "string" && this.settings.lowercase && this.settings.dashspaces) { 532 value = value.replace(/\s+/g, '-').toLowerCase(); 533 } 534 else if (typeof value === "string" && this.settings.lowercase){ 535 value = value.toLowerCase(); 536 } 537 else if (typeof value === "string" && this.settings.dashspaces){ 538 value = value.replace(/\s+/g, '-'); 539 } 540 541 var html = '<span class="'+this.classes.tagItem.substring(1)+'" data-val="'+value+'">'+this.getTag(value)+' '+this.setIcon()+'</span>'; 542 $item = $(html).insertBefore($(this.selectors.sTagsInput)); 543 if(this.settings.defaultTagClass) { 544 $item.addClass(this.settings.defaultTagClass); 545 } 546 if(this.settings.tagLimit != -1 && this.settings.tagLimit > 0 && this.tagNames.length >= this.settings.tagLimit) { 547 this.animateRemove($item, animate); 548 if(animate) { 549 this.flashItem(value); 550 } 551 return false;
552 } 553 var itemKey = this.getItemKey(value); 554 if(this.settings.whiteList && itemKey === -1) { 555 this.animateRemove($item, animate); 556 if(animate) { 557 this.flashItem(value, itemKey); 558 } 559 return false; 560 } 561 if(this.isPresent(value)) { 562 this.animateRemove($item, animate); 563 if(animate) { 564 this.flashItem(value, itemKey); 565 } 566 } else { 567 this.customStylings($item, itemKey); 568 var dataVal = value; 569 if($.isNumeric(dataVal)) { 570 dataVal = (value.toString().indexOf('.') == -1)? parseInt(dataVal): parseFloat(dataVal); 571 } 572 this.tagNames.push(dataVal); 573 this.setRemoveEvent(); 574 this.setInputValue(); 575 if(this.settings.afterAdd && typeof this.settings.afterAdd == "function") { 576 this.settings.afterAdd(value); 577 } 578 } 579 $(this.selector).trigger('suggestags.add', [value]); 580 $(this.selector).trigger('suggestags.change'); 581 if(this.settings.triggerChange) { 582 $(this.selector).trigger('change'); 583 } 584 $(this.selectors.listArea).find(this.classes.listItem).removeClass('active'); 585 $(this.selectors.listArea).hide(); 586 $(this.selectors.sTagsInput).removeClass(this.classes.readyToRemove.substring(1)); 587 this.checkPlusAfter(); 588 }, 589 590 getItemKey : function(value) { 591 var itemKey = -1 592 var _self = this; 593 if(this.settings.suggestions.length) { 594 var lower = value.toString().toLowerCase(); 595 $.each(this.settings.suggestions, function(key, item){ 596 if(typeof item === 'object') { 597 if(item.value.toString().toLowerCase() == lower) { 598 itemKey = key; 599 if(item.class !== undefined && _self.settings.classes[key] === undefined) { 600 _self.settings.classes[key] = item.class; 601 } 602 if(item.background !== undefined && _self.settings.backgrounds[key] === undefined) { 603 _self.settings.backgrounds[key] = item.background; 604 } 605 if(item.color !== undefined && _self.settings.colors[key] === undefined) { 606 _self.settings.colors[key] = item.color; 607 } 608 return false; 609 } 610 } else if(item.toString().toLowerCase() == lower) { 611 itemKey = key; 612 return false; 613 } 614 }); 615 } 616 return itemKey; 617 }, 618 619 isPresent : function(value) { 620 var present = false; 621 $.each(this.tagNames, function(index, tag){ 622 if(value.toString().toLowerCase() == tag.toString().toLowerCase()) { 623 present = true; 624 return false; 625 } 626 }); 627 return present; 628 }, 629 630 customStylings : function(item, key) { 631 var isCustom = false; 632 if(this.settings.classes[key]) { 633 isCustom = true; 634 $(item).addClass(this.settings.classes[key]); 635 } 636 if(this.settings.backgrounds[key]) { 637 isCustom = true; 638 $(item).css('background', this.settings.backgrounds[key]); 639 } 640 if(this.settings.colors[key]) { 641 isCustom = true; 642 $(item).css('color', this.settings.colors[key]); 643 } 644 if(!isCustom) { 645 $(item).addClass(this.classes.colBg.substring(1)); 646 } 647 }, 648 649 removeTag: function(value, animate=true) { 650 var _self = this; 651 $findTags = $(this.selectors.inputArea).find('[data-val="'+value+'"]'); 652 if($findTags.length) { 653 $findTags.each(function(){ 654 _self.removeTagByItem(this, animate); 655 }); 656 } 657 }, 658 659 removeTagByItem : function(item, animate) { 660 this.tagNames.splice($(item).index(), 1); 661 this.animateRemove(item, animate); 662 this.setInputValue(); 663 $(this.selector).trigger('suggestags.remove', [$(item).attr('data-val')]); 664 $(this.selector).trigger('suggestags.change'); 665 if(this.settings.triggerChange) { 666 $(this.selector).trigger('change'); 667 } 668 if(this.settings.afterRemove && typeof this.settings.afterRemove == "function") { 669 this.settings.afterRemove($(item).attr('data-val')); 670 } 671 $(this.selectors.sTagsInput).removeClass(this.classes.readyToRemove.substring(1)); 672 this.checkPlusAfter(); 673 }, 674 675 animateRemove : function(item, animate) { 676 $(item).addClass('disabled'); 677 if(animate) { 678 setTimeout(function(){ 679 $(item).slideUp(); 680 setTimeout(function(){ 681 $(item).remove(); 682 }, 500); 683 }, 500); 684 } else { 685 $(item).remove(); 686 } 687 }, 688 689 flashItem : function(value, itemKey) { 690 $tagItem = ''; 691 value = value.toString().toLowerCase(); 692 $(this.selectors.sTagsArea).find(this.classes.tagItem).each(function(){ 693 var tagName = $.trim($(this).attr('data-val')); 694 if(value == tagName.toString().toLowerCase()) { 695 $tagItem = $(this); 696 return false;
697 } 698 }); 699 if($tagItem) { 700 background = (this.settings.backgrounds[itemKey] !== undefined)? this.settings.backgrounds[itemKey]: null; 701 if(background !== null) { 702 $tagItem.css('background', ''); 703 } 704 $tagItem.addClass('flash'); 705 setTimeout(function(){ 706 $tagItem.removeClass('flash'); 707 if(background !== null) { 708 $tagItem.css('background', background); 709 } 710 }, 1500, $tagItem); 711 } 712 }, 713 714 setIcon : function() { 715 var removeClass = this.classes.removeTag.substring(1); 716 if(this.settings.type == 'bootstrap') { 717 return '<span class="fa fa-times '+removeClass+'"></span>'; 718 } else if(this.settings.type == 'materialize') { 719 return '<i class="material-icons right '+removeClass+'">clear</i>'; 720 } else { 721 return '<b class="'+removeClass+'">✖</b>'; 722 } 723 }, 724 725 setInputValue: function() { 726 this.updateIsRequired(); 727 $(this.selector).val(this.tagNames.join(',')); 728 if(this.settings.printValues) { 729 this.printValues(); 730 } 731 }, 732 733 fixCSS : function() { 734 if(this.settings.type == 'amsify') { 735 $(this.selectors.inputArea).addClass(this.classes.inputAreaDef.substring(1)).css({'padding': '5px 5px'}); 736 } else if(this.settings.type == 'materialize') { 737 $(this.selectors.inputArea).addClass(this.classes.inputAreaDef.substring(1)).css({'height': 'auto', 'padding': '5px 5px'}); 738 $(this.selectors.sTagsInput).css({'margin': '0', 'height': 'auto'}); 739 } 740 }, 741 742 printValues : function() { 743 console.info(this.tagNames, $(this.selector).val()); 744 }, 745 746 checkMethod : function() { 747 $findTags = $(this.selector).next(this.classes.sTagsArea); 748 if($findTags.length) { 749 $findTags.remove(); 750 } 751 $(this.selector).show(); 752 if(typeof this.method !== undefined && this.method == 'destroy') { 753 return false; 754 } else { 755 return true; 756 } 757 }, 758 759 refresh : function() { 760 this._setMethod('refresh'); 761 this._init(); 762 }, 763 764 destroy : function() { 765 this._setMethod('destroy'); 766 this._init(); 767 }, 768 769 getActionURL : function(urlString) { 770 var URL = ''; 771 if(window !== undefined) { 772 URL = window.location.protocol+'//'+window.location.host; 773 } 774 if(this.isAbsoluteURL(urlString)) { 775 URL = urlString; 776 } else { 777 URL += '/'+urlString.replace(/^\/|\/$/g, ''); 778 } 779 return URL; 780 }, 781 782 isAbsoluteURL : function(urlString) { 783 var regexURL = new RegExp('^(?:[a-z]+:)?//', 'i'); 784 return (regexURL.test(urlString))? true: false; 785 }, 786 787 unique: function(list) { 788 var result = []; 789 var _self = this; 790 $.each(list, function(i, e) { 791 if(typeof e === 'object') { 792 if(!_self.objectInArray(e, result)) { 793 result.push(e); 794 } 795 } else { 796 if($.inArray(e, result) == -1) { 797 result.push(e); 798 } 799 } 800 }); 801 return result; 802 }, 803 804 objectInArray : function(element, result) { 805 if(result.length) { 806 var present = false; 807 $.each(result, function(i, e) { 808 if(typeof e === 'object') { 809 if(e.value == element.value) { 810 present = true; 811 return false; 812 } 813 } else { 814 if(e == element.value) { 815 present = true; 816 return false; 817 } 818 } 819 }); 820 return present; 821 } else { 822 return false; 823 } 824 }, 825 826 isSimilarText: function(str1, str2, perc) { 827 if(!this.settings.checkSimilar) { 828 return false; 829 } 830 var percent = this.similarity(str1, str2); 831 return (percent*100 >= perc)? true: false; 832 }, 833 834 similarity: function(s1, s2) { 835 var longer = s1; 836 var shorter = s2; 837 if(s1.length < s2.length) { 838 longer = s2; 839 shorter = s1; 840 } 841 var longerLength = longer.length; 842 if(longerLength == 0) { 843 return 1.0; 844 } 845 return (longerLength - this.editDistance(longer, shorter))/parseFloat(longerLength); 846 }, 847 848 editDistance: function(s1, s2) { 849 s1 = s1.toLowerCase(); 850 s2 = s2.toLowerCase(); 851 var costs = new Array(); 852 for(var i = 0; i <= s1.length; i++) { 853 var lastValue = i; 854 for(var j = 0; j <= s2.length; j++) { 855 if(i == 0) { 856 costs[j] = j; 857 } else { 858 if(j > 0) { 859 var newValue = costs[j-1]; 860 if(s1.charAt(i-1) != s2.charAt(j-1)) { 861 newValue = Math.min(Math.min(newValue, lastValue), costs[j]) + 1; 862 } 863 costs[j-1] = lastValue;
864 lastValue = newValue; 865 } 866 } 867 } 868 if(i > 0) 869 costs[s2.length] = lastValue; 870 } 871 return costs[s2.length]; 872 }, 873 874 checkPlusAfter : function(fromBlur) { 875 if(this.settings.showPlusAfter > 0) { 876 if(this.tagNames.length > this.settings.showPlusAfter) { 877 var _self = this; 878 var plusNumber = this.tagNames.length - this.settings.showPlusAfter; 879 if(!this.selectors.plusTag) { 880 var html = '<span class="'+this.classes.plusItem.substring(1)+'"></span>'; 881 this.selectors.plusTag = $(html).appendTo(this.selectors.inputArea); 882 $(this.selectors.plusTag).addClass(this.classes.showPlusBg.substring(1)); 883 /** 884 * Show input after focus on input area 885 */ 886 $(this.selectors.inputArea).click(function(){ 887 $(_self.selectors.sTagsInput).show(); 888 }); 889 } 890 $(this.selectors.plusTag).text('+ '+plusNumber); 891 $tagItems = $(this.selectors.inputArea).find(this.classes.tagItem); 892 $tagItems.show(); 893 if($(this.selectors.inputArea).hasClass(this.classes.focus.substring(1))){ 894 $(this.selectors.plusTag).hide(); 895 } else { 896 if(fromBlur && !this.blurTgItems) { 897 this.blurTgItems = $tagItems; 898 setTimeout(function(){ 899 if(_self.blurTgItems) { 900 _self.blurTgItems.slice(_self.settings.showPlusAfter).hide(); 901 } 902 }, 200); 903 } else { 904 this.blurTgItems = null; 905 $tagItems.slice(this.settings.showPlusAfter).hide(); 906 } 907 $(this.selectors.sTagsInput).hide(); 908 $(this.selectors.plusTag).show(); 909 } 910 } else if(this.selectors.plusTag) { 911 $(this.selectors.inputArea).find(this.classes.tagItem).show(); 912 $(this.selectors.plusTag).hide(); 913 } 914 } 915 } 916 }; 917 918 $.fn.amsifySuggestags = function(options, method) { 919 return this.each(function() { 920 var amsifySuggestags = new AmsifySuggestags(this); 921 amsifySuggestags._settings(options); 922 amsifySuggestags._setMethod(method); 923 amsifySuggestags._init(); 924 }); 925 }; 926}));
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.