From 683f0c5725a3d2990bb0fe7654ca1e3ef5813404 Mon Sep 17 00:00:00 2001 From: Shannon Date: Tue, 6 May 2014 14:44:24 +1000 Subject: [PATCH] Fixes: U4-4503 Tags datatype does not autocomplete --- src/Umbraco.Web.UI.Client/gruntFile.js | 2 +- src/Umbraco.Web.UI.Client/src/less/belle.less | 1 + .../src/less/typeahead.less | 65 +++++++++++++ .../propertyeditors/tags/tags.controller.js | 95 ++++++++++++------- .../src/views/propertyeditors/tags/tags.html | 1 + 5 files changed, 128 insertions(+), 36 deletions(-) create mode 100644 src/Umbraco.Web.UI.Client/src/less/typeahead.less diff --git a/src/Umbraco.Web.UI.Client/gruntFile.js b/src/Umbraco.Web.UI.Client/gruntFile.js index cb7850c274..d37f110fdb 100644 --- a/src/Umbraco.Web.UI.Client/gruntFile.js +++ b/src/Umbraco.Web.UI.Client/gruntFile.js @@ -34,7 +34,7 @@ module.exports = function (grunt) { var bower = require('bower'); var done = this.async(); - bower.commands.install(undefined, { offline: true }, { interactive: false, offline: true }) + bower.commands.install(undefined, { }, { interactive: false }) .on('log', function (data) { grunt.log.write(data.message + "\n"); }) diff --git a/src/Umbraco.Web.UI.Client/src/less/belle.less b/src/Umbraco.Web.UI.Client/src/less/belle.less index acb14f6a91..60caad7e82 100644 --- a/src/Umbraco.Web.UI.Client/src/less/belle.less +++ b/src/Umbraco.Web.UI.Client/src/less/belle.less @@ -82,4 +82,5 @@ //used for property editors @import "property-editors.less"; +@import "typeahead.less"; @import "hacks.less"; diff --git a/src/Umbraco.Web.UI.Client/src/less/typeahead.less b/src/Umbraco.Web.UI.Client/src/less/typeahead.less new file mode 100644 index 0000000000..f15da83ade --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/less/typeahead.less @@ -0,0 +1,65 @@ +.typeahead, +.tt-query, +.tt-hint { + z-index: auto !important; + margin-top:-4px !important; + width: 396px; + height: 30px; + padding: 8px 12px; + font-size: 24px; + line-height: 30px; + border: 2px solid @grayLight; + -webkit-border-radius: 2px !important; + -moz-border-radius: 2px !important; + border-radius: 2px !important; + outline: none; +} + +.typeahead { + background-color: #fff; +} + +.typeahead:focus { + /*border: 2px solid @blue;*/ +} + +.tt-query { + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); +} + +.tt-hint { + color: @grayLight !important; +} + +.tt-dropdown-menu { + width: 422px; + margin-top: 12px; + padding: 8px 0; + background-color: #fff; + border: 1px solid @grayLight; + border: 1px solid rgba(0, 0, 0, 0.2); + -webkit-border-radius: 8px; + -moz-border-radius: 8px; + border-radius: 8px; + -webkit-box-shadow: 0 5px 10px rgba(0,0,0,.2); + -moz-box-shadow: 0 5px 10px rgba(0,0,0,.2); + box-shadow: 0 5px 10px rgba(0,0,0,.2); +} + +.tt-suggestion { + padding: 3px 20px; + font-size: @baseFontSize; + line-height: @baseLineHeight; + cursor:pointer; +} + +.tt-suggestion.tt-cursor { + color: #fff; + background-color: @blue; +} + +.tt-suggestion p { + margin: 0; +} \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/tags/tags.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/tags/tags.controller.js index 186217e116..f510c954dc 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/tags/tags.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/tags/tags.controller.js @@ -1,31 +1,40 @@ angular.module("umbraco") .controller("Umbraco.PropertyEditors.TagsController", - function ($rootScope, $scope, $log, assetsService, umbRequestHelper) { - + function ($rootScope, $scope, $log, assetsService, umbRequestHelper, angularHelper, $timeout) { + //load current value $scope.currentTags = []; if ($scope.model.value) { $scope.currentTags = $scope.model.value.split(","); } + //Helper method to add a tag on enter or on typeahead select + function addTag(tagToAdd) { + if (tagToAdd.length > 0) { + if ($scope.currentTags.indexOf(tagToAdd) < 0) { + $scope.currentTags.push(tagToAdd); + } + } + } + $scope.addTag = function (e) { var code = e.keyCode || e.which; if (code == 13) { //Enter keycode - //this is required, otherwise the html form will attempt to submit. - e.preventDefault(); - - if ($scope.currentTags.indexOf($scope.tagToAdd) < 0) { - $scope.currentTags.push($scope.tagToAdd); + if ($('#tags-Tags').parent().find(".tt-dropdown-menu .tt-cursor").length === 0) { + //this is required, otherwise the html form will attempt to submit. + e.preventDefault(); + addTag($scope.tagToAdd); + $scope.tagToAdd = ""; } - $scope.tagToAdd = ""; + } }; $scope.removeTag = function (tag) { var i = $scope.currentTags.indexOf(tag); if (i >= 0) { - $scope.currentTags.splice(i, 1); + $scope.currentTags.splice(i, 1); } }; @@ -42,55 +51,71 @@ angular.module("umbraco") }; assetsService.loadJs("lib/typeahead/typeahead.bundle.min.js").then(function () { - + //configure the tags data source + //TODO: We'd like to be able to filter the shown list items to not show the tags that are currently + // selected but that is difficult, i've tried a number of things and also this link suggests we cannot do + // it currently without a lot of hacking: + // http://stackoverflow.com/questions/21044906/twitter-typeahead-js-remove-datum-upon-selection + + //helper method to format the data for bloodhound + function dataTransform(list) { + //transform the result to what bloodhound wants + return _.map(list, function (i) { + return { value: i.text }; + }); + } var tagsHound = new Bloodhound({ - datumTokenizer: Bloodhound.tokenizers.obj.whitespace("value"), + datumTokenizer: Bloodhound.tokenizers.obj.whitespace('value'), queryTokenizer: Bloodhound.tokenizers.whitespace, + dupDetector : function(remoteMatch, localMatch) { + return (remoteMatch["value"] == localMatch["value"]); + }, //pre-fetch the tags for this category prefetch: { url: umbRequestHelper.getApiUrl("tagsDataBaseUrl", "GetTags", [{ tagGroup: $scope.model.config.group }]), //TTL = 5 minutes ttl: 300000, - filter: function (list) { - return _.map(list, function (i) { - return { value: i.text }; - }); - } + filter: dataTransform }, - //dynamically get the tags for this category + //dynamically get the tags for this category (they may have changed on the server) remote: { url: umbRequestHelper.getApiUrl("tagsDataBaseUrl", "GetTags", [{ tagGroup: $scope.model.config.group }]), - filter: function (list) { - return _.map(list, function (i) { - return { value: i.text }; - }); - } + filter: dataTransform } }); tagsHound.initialize(); //configure the type ahead - - $('#tags-' + $scope.model.alias).typeahead( + $timeout(function() { + $('#tags-' + $scope.model.alias).typeahead( //use the default options null, { - //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: $scope.model.config.group, - // apparently thsi should be the same as the value above in the call to Bloodhound.tokenizers.obj.whitespace - // this isn't very clear in the docs but you can see that it's consistent with this statement here: - // http://twitter.github.io/typeahead.js/examples/ - displayKey: "value", - source: tagsHound.ttAdapter() + //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: $scope.model.config.group, + displayKey: "value", + source: tagsHound.ttAdapter(), + highlight: true, + hint: true + }).bind("typeahead:selected", function (obj, datum, name) { + + angularHelper.safeApply($scope, function () { + addTag(datum["value"]); + $scope.tagToAdd = ""; + }); + + }); + }); + + $scope.$on('$destroy', function () { + $('#tags-' + $scope.model.alias).typeahead('destroy'); + delete tagsHound; }); }); - //on destroy: - // $('.typeahead').typeahead('destroy'); - } ); \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/tags/tags.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/tags/tags.html index 378c48c722..e0c926b8b3 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/tags/tags.html +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/tags/tags.html @@ -4,6 +4,7 @@