diff --git a/build/ng-tags-input.js b/build/ng-tags-input.js index e9d93ac8..efb52c7a 100644 --- a/build/ng-tags-input.js +++ b/build/ng-tags-input.js @@ -337,6 +337,12 @@ tagsInput.directive('autoComplete', ["$document","$timeout","$sce","tagsInputCon return self; } + function encodeHTML(value) { + return value.replace(/&/g, '&') + .replace(//g, '>'); + } + return { restrict: 'E', require: '?^tagsInput', @@ -344,7 +350,7 @@ tagsInput.directive('autoComplete', ["$document","$timeout","$sce","tagsInputCon templateUrl: 'ngTagsInput/auto-complete.html', link: function(scope, element, attrs, tagsInputCtrl) { var hotkeys = [KEYS.enter, KEYS.tab, KEYS.escape, KEYS.up, KEYS.down], - suggestionList, tagsInput, highlight; + suggestionList, tagsInput, markdown; tagsInputConfig.load(scope, attrs, { debounceDelay: { type: Number, defaultValue: 100 }, @@ -357,13 +363,13 @@ tagsInput.directive('autoComplete', ["$document","$timeout","$sce","tagsInputCon suggestionList = new SuggestionList(scope.source, scope.options); if (scope.options.highlightMatchedText) { - highlight = function(item, text) { + markdown = function(item, text) { var expression = new RegExp(text, 'gi'); - return item.replace(expression, '$&'); + return item.replace(expression, '**$&**'); }; } else { - highlight = function(item) { + markdown = function(item) { return item; }; } @@ -384,7 +390,10 @@ tagsInput.directive('autoComplete', ["$document","$timeout","$sce","tagsInputCon }; scope.highlight = function(item) { - return $sce.trustAsHtml(highlight(item, suggestionList.query)); + item = markdown(item, suggestionList.query); + item = encodeHTML(item); + item = item.replace(/\*\*(.+?)\*\*/g, '$1'); + return $sce.trustAsHtml(item); }; tagsInput diff --git a/build/ng-tags-input.min.zip b/build/ng-tags-input.min.zip index efb9a46c..70809573 100644 Binary files a/build/ng-tags-input.min.zip and b/build/ng-tags-input.min.zip differ diff --git a/build/ng-tags-input.zip b/build/ng-tags-input.zip index 975ba99e..b0f12fdb 100644 Binary files a/build/ng-tags-input.zip and b/build/ng-tags-input.zip differ diff --git a/src/auto-complete.js b/src/auto-complete.js index 07c6f311..5bdda480 100644 --- a/src/auto-complete.js +++ b/src/auto-complete.js @@ -89,6 +89,12 @@ tagsInput.directive('autoComplete', function($document, $timeout, $sce, tagsInpu return self; } + function encodeHTML(value) { + return value.replace(/&/g, '&') + .replace(//g, '>'); + } + return { restrict: 'E', require: '?^tagsInput', @@ -96,7 +102,7 @@ tagsInput.directive('autoComplete', function($document, $timeout, $sce, tagsInpu templateUrl: 'ngTagsInput/auto-complete.html', link: function(scope, element, attrs, tagsInputCtrl) { var hotkeys = [KEYS.enter, KEYS.tab, KEYS.escape, KEYS.up, KEYS.down], - suggestionList, tagsInput, highlight; + suggestionList, tagsInput, markdown; tagsInputConfig.load(scope, attrs, { debounceDelay: { type: Number, defaultValue: 100 }, @@ -109,13 +115,13 @@ tagsInput.directive('autoComplete', function($document, $timeout, $sce, tagsInpu suggestionList = new SuggestionList(scope.source, scope.options); if (scope.options.highlightMatchedText) { - highlight = function(item, text) { + markdown = function(item, text) { var expression = new RegExp(text, 'gi'); - return item.replace(expression, '$&'); + return item.replace(expression, '**$&**'); }; } else { - highlight = function(item) { + markdown = function(item) { return item; }; } @@ -136,7 +142,10 @@ tagsInput.directive('autoComplete', function($document, $timeout, $sce, tagsInpu }; scope.highlight = function(item) { - return $sce.trustAsHtml(highlight(item, suggestionList.query)); + item = markdown(item, suggestionList.query); + item = encodeHTML(item); + item = item.replace(/\*\*(.+?)\*\*/g, '$1'); + return $sce.trustAsHtml(item); }; tagsInput diff --git a/test/auto-complete.spec.js b/test/auto-complete.spec.js index 54f9595d..63fd03f4 100644 --- a/test/auto-complete.spec.js +++ b/test/auto-complete.spec.js @@ -683,6 +683,30 @@ describe('autocomplete-directive', function() { expect(getSuggestionText(3)).toBe('aba'); expect(getSuggestionText(4)).toBe('bab'); }); + + it('encodes HTML characters in suggestions list', function() { + // Act + loadSuggestions(['', 'Item <2>', 'Item &3']); + + // Assert + expect(getSuggestionText(0)).toBe('<Item 1>'); + expect(getSuggestionText(1)).toBe('Item <2>'); + expect(getSuggestionText(2)).toBe('Item &3'); + }); + + it('highlights encoded HTML characters in suggestions list', function() { + // Arrange + compile('highlight-matched-text="true"', 'min-length="1"'); + + // Act + loadSuggestions(['', 'Item <2>', 'Item &3'], '>'); + + // Assert + expect(getSuggestionText(0)).toBe('<Item 1>'); + expect(getSuggestionText(1)).toBe('Item <2>'); + expect(getSuggestionText(2)).toBe('Item &3'); + }); + }); describe('max-results-to-show option', function() { diff --git a/test/test-page.html b/test/test-page.html index 5850cd44..d14e79a5 100644 --- a/test/test-page.html +++ b/test/test-page.html @@ -10,7 +10,8 @@ + add-on-blur="true" + allowed-tags-pattern="^[a-zA-Z0-9\s<>@\.]+$"> ', 'Superman', 'Flash', 'Iron Man', 'Hulk', 'Wolverine', "Green Lantern", "Green Arrow", "Spiderman"]); return deferred.promise; }; });