From 7614ba42df7b1ef33575e58bbfc068ad50149619 Mon Sep 17 00:00:00 2001 From: Shannon Date: Fri, 1 Feb 2019 13:32:17 +1100 Subject: [PATCH] Fixes the tag editor and tag suggestions --- .../tags/umbtagseditor.directive.js | 85 +++++++------------ .../Editors/BackOfficeServerVariables.cs | 2 +- .../PropertyEditors/TagsDataController.cs | 24 +++++- 3 files changed, 56 insertions(+), 55 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/tags/umbtagseditor.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/tags/umbtagseditor.directive.js index 4d10625d23..edf54ca034 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/tags/umbtagseditor.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/tags/umbtagseditor.directive.js @@ -24,10 +24,10 @@ function umbTagsEditorController($rootScope, assetsService, umbRequestHelper, angularHelper, $timeout, $element) { - var vm = this; + let vm = this; - var typeahead; - var tagsHound; + let typeahead; + let tagsHound; vm.$onInit = onInit; vm.$onChanges = onChanges; @@ -53,50 +53,51 @@ vm.isLoading = false; //ensure that the models are formatted correctly - configureViewModel(true); + configureViewModel(); // Set the visible prompt to -1 to ensure it will not be visible vm.promptIsVisible = "-1"; tagsHound = new Bloodhound({ - datumTokenizer: Bloodhound.tokenizers.obj.whitespace('value'), + initialize: false, + identify: function (obj) { return obj.id; }, + datumTokenizer: Bloodhound.tokenizers.obj.whitespace('text'), queryTokenizer: Bloodhound.tokenizers.whitespace, //pre-fetch the tags for this category prefetch: { url: umbRequestHelper.getApiUrl("tagsDataBaseUrl", "GetTags", { tagGroup: vm.config.group, culture: vm.culture }), //TTL = 5 minutes - ttl: 300000, - transform: dataTransform + ttl: 300000 }, //dynamically get the tags for this category (they may have changed on the server) remote: { - url: umbRequestHelper.getApiUrl("tagsDataBaseUrl", "GetTags", { tagGroup: vm.config.group, culture: vm.culture }), - transform: dataTransform + url: umbRequestHelper.getApiUrl("tagsDataBaseUrl", "GetTags", { tagGroup: vm.config.group, culture: vm.culture, query: "%QUERY" }), + wildcard: "%QUERY" } }); - tagsHound.initialize(true); - - //configure the type ahead - $timeout(function () { + tagsHound.initialize().then(function() { + //configure the type ahead + var sources = { //see: https://github.com/twitter/typeahead.js/blob/master/doc/jquery_typeahead.md#options - // name = the data set name, we'll make this the tag group name - name: vm.config.group, - display: "value", + // name = the data set name, we'll make this the tag group name + culture + name: vm.config.group + (vm.culture ? vm.culture : ""), + display: "text", //source: tagsHound - source: function (query, cb) { + source: function (query, syncCallback, asyncCallback) { tagsHound.search(query, function(suggestions) { - cb(removeCurrentTagsFromSuggestions(suggestions)); + syncCallback(removeCurrentTagsFromSuggestions(suggestions)); + }, function(suggestions) { + asyncCallback(removeCurrentTagsFromSuggestions(suggestions)); }); } }; var opts = { - //This causes some strangeness as it duplicates the textbox, best leave off for now. - hint: false, + hint: true, highlight: true, cacheKey: new Date(), // Force a cache refresh each time the control is initialized minLength: 1 @@ -105,22 +106,25 @@ typeahead = $element.find('.tags-' + vm.htmlId).typeahead(opts, sources) .bind("typeahead:selected", function (obj, datum, name) { angularHelper.safeApply($rootScope, function () { - addTagInternal(datum["value"]); + addTagInternal(datum["text"]); vm.tagToAdd = ""; // clear the typed text typeahead.typeahead('val', ''); }); }).bind("typeahead:autocompleted", function (obj, datum, name) { angularHelper.safeApply($rootScope, function () { - addTagInternal(datum["value"]); + addTagInternal(datum["text"]); vm.tagToAdd = ""; + // clear the typed text + typeahead.typeahead('val', ''); }); }).bind("typeahead:opened", function (obj) { }); - }); + }); + }); } @@ -150,15 +154,13 @@ $element.find('.tags-' + vm.htmlId).typeahead('destroy'); } - function configureViewModel(isInitLoad) { + function configureViewModel() { if (vm.value) { if (angular.isString(vm.value) && vm.value.length > 0) { if (vm.config.storageType === "Json") { //json storage vm.viewModel = JSON.parse(vm.value); - if (!isInitLoad) { - updateModelValue(vm.viewModel); - } + updateModelValue(vm.viewModel); } else { //csv storage @@ -172,9 +174,7 @@ return self.indexOf(v) === i; }); - if (!isInitLoad) { - updateModelValue(vm.viewModel); - } + updateModelValue(vm.viewModel); } } @@ -186,14 +186,7 @@ function updateModelValue(val) { - //need to format the underlying model value for persistence based on the storage type - if (vm.config.storageType === "Json") { - val = val ? val : []; - } - else { - //then it is csv and we need to format it like that - val = val ? val.join() : ""; - } + val = val ? val : []; vm.onValueChanged({ value: val }); @@ -267,23 +260,11 @@ function hidePrompt() { vm.promptIsVisible = "-1"; } - - //helper method to format the data for bloodhound - function dataTransform(list) { - //transform the result to what bloodhound wants - var tagList = _.map(list, function (i) { - return { value: i.text }; - }); - // remove current tags from the list - return $.grep(tagList, function (tag) { - return ($.inArray(tag.value, vm.viewModel) === -1); - }); - } - + // helper method to remove current tags function removeCurrentTagsFromSuggestions(suggestions) { return $.grep(suggestions, function (suggestion) { - return ($.inArray(suggestion.value, vm.viewModel) === -1); + return ($.inArray(suggestion.text, vm.viewModel) === -1); }); } diff --git a/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs b/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs index 83bb152e0a..954491eab9 100644 --- a/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs +++ b/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs @@ -259,7 +259,7 @@ namespace Umbraco.Web.Editors }, { "tagsDataBaseUrl", _urlHelper.GetUmbracoApiServiceBaseUrl( - controller => controller.GetTags("", "")) + controller => controller.GetTags("", "", null)) }, { "examineMgmtBaseUrl", _urlHelper.GetUmbracoApiServiceBaseUrl( diff --git a/src/Umbraco.Web/PropertyEditors/TagsDataController.cs b/src/Umbraco.Web/PropertyEditors/TagsDataController.cs index 15c39bf994..7d699077c3 100644 --- a/src/Umbraco.Web/PropertyEditors/TagsDataController.cs +++ b/src/Umbraco.Web/PropertyEditors/TagsDataController.cs @@ -1,4 +1,6 @@ using System.Collections.Generic; +using System.Linq; +using Umbraco.Core; using Umbraco.Web.Models; using Umbraco.Web.Mvc; using Umbraco.Web.WebApi; @@ -15,10 +17,28 @@ namespace Umbraco.Web.PropertyEditors [PluginController("UmbracoApi")] public class TagsDataController : UmbracoAuthorizedApiController { - public IEnumerable GetTags(string tagGroup, string culture) + /// + /// Returns all tags matching tagGroup, culture and an optional query + /// + /// + /// + /// + /// + public IEnumerable GetTags(string tagGroup, string culture, string query = null) { if (culture == string.Empty) culture = null; - return Umbraco.TagQuery.GetAllTags(tagGroup, culture); + + var result = Umbraco.TagQuery.GetAllTags(tagGroup, culture); + + + if (!query.IsNullOrWhiteSpace()) + { + //TODO: add the query to TagQuery + the tag service, this is ugly but all we can do for now. + //currently we are post filtering this :( but works for now + result = result.Where(x => x.Text.InvariantContains(query)); + } + + return result.OrderBy(x => x.Text); } } }