From 8adb69de5454fad4e4506b3819b7a1bf72511123 Mon Sep 17 00:00:00 2001 From: Jeff Date: Fri, 21 Aug 2015 16:22:49 +0100 Subject: [PATCH 1/2] Loading terms via a service for autocomplete enabled taxonomy field. It also maintains the order the terms are selected. Issue #4409. --- .../Controllers/TagsController.cs | 60 +++++++++ .../Drivers/TaxonomyFieldDriver.cs | 8 +- .../Orchard.Taxonomies.csproj | 5 + .../Scripts/admin-taxonomy-tags.js | 114 ++++-------------- .../Services/ITaxonomyService.cs | 1 + .../Services/TaxonomyService.cs | 6 + .../Styles/admin-taxonomy-tags.css | 4 + .../ViewModels/TaxonomyFieldViewModel.cs | 3 + .../Fields/TaxonomyField.Autocomplete.cshtml | 72 +++++------ 9 files changed, 146 insertions(+), 127 deletions(-) create mode 100644 src/Orchard.Web/Modules/Orchard.Taxonomies/Controllers/TagsController.cs diff --git a/src/Orchard.Web/Modules/Orchard.Taxonomies/Controllers/TagsController.cs b/src/Orchard.Web/Modules/Orchard.Taxonomies/Controllers/TagsController.cs new file mode 100644 index 000000000..3b99517d3 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Taxonomies/Controllers/TagsController.cs @@ -0,0 +1,60 @@ +using System.Collections.Generic; +using System.Globalization; +using System.Web.Http; +using Orchard.ContentManagement; +using Orchard.Core.Title.Models; +using Orchard.Localization; +using Orchard.Logging; +using Orchard.Taxonomies.Helpers; +using Orchard.Taxonomies.Models; +using Orchard.Taxonomies.Services; +using System.Linq; + +namespace Orchard.Taxonomies.Controllers { + public class TagsController : ApiController { + private readonly ITaxonomyService _taxonomyService; + private readonly IContentManager _contentManager; + public Localizer T { get; set; } + protected ILogger Logger { get; set; } + + public TagsController( + ITaxonomyService taxonomyService, + IContentManager contentManager) { + _taxonomyService = taxonomyService; + T = NullLocalizer.Instance; + _contentManager = contentManager; + Logger = NullLogger.Instance; + } + + public IEnumerable Get(int taxonomyId, bool leavesOnly, string query) { + if (string.IsNullOrEmpty(query)) return new List(); + var allTerms = leavesOnly + ? _taxonomyService.GetTerms(taxonomyId).ToList() + : new List(); + var matchingTerms = _contentManager.Query() + .Where(t => t.TaxonomyId == taxonomyId) + .Join() + .Where(r => r.Title.Contains(query)) + .List() + .Select(t => CreateTagDto(t, leavesOnly, allTerms)) + .OrderBy(t => t.label) + .ToList(); + return matchingTerms; + } + + private static TagDto CreateTagDto(TermPart term, bool leavesOnly, IEnumerable terms) { + return new TagDto { + value = term.Id, + label = term.Name, + disabled = !term.Selectable || (leavesOnly && terms.Any(t => t.Path.Contains(term.Path + term.Id))), + levels = term.GetLevels() + }; + } + } + public class TagDto { + public string label { get; set; } + public int value { get; set; } + public int levels { get; set; } + public bool disabled { get; set; } + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Taxonomies/Drivers/TaxonomyFieldDriver.cs b/src/Orchard.Web/Modules/Orchard.Taxonomies/Drivers/TaxonomyFieldDriver.cs index 0d97d0ae3..eed4d476c 100644 --- a/src/Orchard.Web/Modules/Orchard.Taxonomies/Drivers/TaxonomyFieldDriver.cs +++ b/src/Orchard.Web/Modules/Orchard.Taxonomies/Drivers/TaxonomyFieldDriver.cs @@ -60,7 +60,7 @@ namespace Orchard.Taxonomies.Drivers { var settings = field.PartFieldDefinition.Settings.GetModel(); var appliedTerms = GetAppliedTerms(part, field, VersionOptions.Latest).ToDictionary(t => t.Id, t => t); var taxonomy = _taxonomyService.GetTaxonomyByName(settings.Taxonomy); - var terms = taxonomy != null + var terms = taxonomy != null && !settings.Autocomplete ? _taxonomyService.GetTerms(taxonomy.Id).Where(t => !string.IsNullOrWhiteSpace(t.Name)).Select(t => t.CreateTermEntry()).ToList() : new List(0); @@ -70,9 +70,11 @@ namespace Orchard.Taxonomies.Drivers { DisplayName = field.DisplayName, Name = field.Name, Terms = terms, + SelectedTerms = appliedTerms.Select(t => t.Value), Settings = settings, - SingleTermId = terms.Where(t => t.IsChecked).Select(t => t.Id).FirstOrDefault(), - TaxonomyId = taxonomy != null ? taxonomy.Id : 0 + SingleTermId = appliedTerms.Select(t => t.Key).FirstOrDefault(), + TaxonomyId = taxonomy != null ? taxonomy.Id : 0, + HasTerms = taxonomy != null && _taxonomyService.GetTermsCount(taxonomy.Id) > 0 }; var templateName = settings.Autocomplete ? "Fields/TaxonomyField.Autocomplete" : "Fields/TaxonomyField"; diff --git a/src/Orchard.Web/Modules/Orchard.Taxonomies/Orchard.Taxonomies.csproj b/src/Orchard.Web/Modules/Orchard.Taxonomies/Orchard.Taxonomies.csproj index 28d48a98d..d7249ff13 100644 --- a/src/Orchard.Web/Modules/Orchard.Taxonomies/Orchard.Taxonomies.csproj +++ b/src/Orchard.Web/Modules/Orchard.Taxonomies/Orchard.Taxonomies.csproj @@ -59,6 +59,10 @@ + + False + ..\..\..\..\lib\aspnetwebapi\System.Web.Http.dll + False ..\..\..\..\lib\aspnetmvc\System.Web.Mvc.dll @@ -72,6 +76,7 @@ + diff --git a/src/Orchard.Web/Modules/Orchard.Taxonomies/Scripts/admin-taxonomy-tags.js b/src/Orchard.Web/Modules/Orchard.Taxonomies/Scripts/admin-taxonomy-tags.js index 26518b153..95033e84b 100644 --- a/src/Orchard.Web/Modules/Orchard.Taxonomies/Scripts/admin-taxonomy-tags.js +++ b/src/Orchard.Web/Modules/Orchard.Taxonomies/Scripts/admin-taxonomy-tags.js @@ -2,49 +2,24 @@ /* Helper functions **********************************************************************/ - var addTag = function ($plugin, label) { - $plugin.tagit("add", label); - }; - - var removeTag = function ($plugin, label) { - var tags = $plugin.tagit("tags"); - var index = findTagIndexByLabel(tags, label); - - if (index == -1) - return; - - tags.splice(index, 1); - $plugin.tagit("fill", tags); - }; - - var findTagIndexByLabel = function (tags, label) { - for (var i = 0; i < tags.length; i++) { - var tag = tags[i]; - - if (tag.label == label) { - return i; - } - } - return -1; - }; - var createTermCheckbox = function ($wrapper, tag) { var $ul = $("ul.terms", $wrapper); var singleChoice = $(".terms-editor", $wrapper).data("singlechoice"); var namePrefix = $wrapper.data("name-prefix"); var idPrefix = $wrapper.data("id-prefix"); var nextIndex = $("li", $ul).length; + var id = isNaN(tag.value) ? -nextIndex : tag.value; var checkboxId = idPrefix + "_Terms_" + nextIndex + "__IsChecked"; var checkboxName = namePrefix + ".Terms[" + nextIndex + "].IsChecked"; var radioName = namePrefix + ".SingleTermId"; - var checkboxHtml = ""; - var radioHtml = ""; + var checkboxHtml = ""; + var radioHtml = ""; var inputHtml = singleChoice ? radioHtml : checkboxHtml; var $li = $("
  • " + inputHtml + - "" + - "" + - "" + + "" + + "" + + "" + "
  • ").hide(); if (singleChoice) { @@ -68,67 +43,20 @@ var $tagIt = $("ul.tagit", $wrapper); var singleChoice = $(".terms-editor", $wrapper).data("singlechoice"); var $terms = $("ul.terms", $wrapper); - var $termCheckbox = $("input[data-term-identity='" + tag.label.toLowerCase() + "']", $terms).filter(function () { - return $(this).siblings("input[value='" + tag.value + "']").length; - }); - - if ($termCheckbox.is(":disabled")) { - removeTag($tagIt, tagLabelOrValue); - return; - } - - if ($termCheckbox.length == 0 && action == "added") { - createTermCheckbox($wrapper, tag.label, this); - } - - $termCheckbox.prop("checked", action == "added"); if (singleChoice && action == "added") { - $tagIt.tagit("fill", [tag.label]); + $tagIt.tagit("fill", tag); } - if (singleChoice) { - if (action == "added") { - var $option = $("select.term-picker", $wrapper).find("option[data-term-identity='" + tag.label.toLowerCase() + "']"); - $option.remove(); - } else { - $("select.term-picker", $wrapper).append(""); - } - } + $terms.empty(); + + $($tagIt.tagit("tags")).each(function (index, tag) { + createTermCheckbox($wrapper, tag, this); + }); $(".no-terms", $wrapper).hide(); }; - $("fieldset.taxonomy-wrapper .expando").on("change", "input[data-term]:enabled", function(e) { - var $checkbox = $(this); - var term = $checkbox.data("term"); - var $wrapper = $checkbox.parents("fieldset.taxonomy-wrapper:first"); - var $tagIt = $("ul.tagit", $wrapper); - var isChecked = $checkbox.is(":checked"); - - isChecked ? addTag($tagIt, term) : removeTag($tagIt, term); - }); - - $("select.term-picker").change(function (e) { - var $select = $(this); - var $firstOption = $("option:first", $select); - - if ($firstOption.is(":selected")) - return; - - var $selecedOption = $("option:selected", $select); - var $wrapper = $select.parents("fieldset.taxonomy-wrapper:first"); - var $tagIt = $("ul.tagit", $wrapper); - var term = $selecedOption.text(); - var singleChoice = $(".terms-editor", $wrapper).data("singlechoice"); - - addTag($tagIt, term); - $select.val(""); - - if (!singleChoice) - $selecedOption.remove(); - }); - var renderAutocompleteItem = function (ul, item) { var label = item.label; @@ -148,20 +76,28 @@ /* Initialization **********************************************************************/ $(".terms-editor").each(function () { - var allTerms = $(this).data("all-terms"); var selectedTerms = $(this).data("selected-terms"); var $tagit = $("> ul", this).tagit({ - tagSource: allTerms, + tagSource: function (request, response) { + var termsEditor = $(this.element).parents(".terms-editor"); + $.getJSON("/api/taxonomies/tags", { taxonomyId: termsEditor.data("taxonomy-id"), leavesOnly: termsEditor.data("leaves-only"), query: request.term }, function (data, status, xhr) { + response(data); + }); + }, initialTags: selectedTerms, triggerKeys: ['enter', 'tab'], // default is ['enter', 'space', 'comma', 'tab'] but we remove comma and space to allow them in the terms allowNewTags: $(this).data("allow-new-terms"), tagsChanged: onTagsChanged, caseSensitive: false, - minLength: 0 - }).data("uiTagit"); + minLength: 0, + sortable: true + }).data("ui-tagit"); - $tagit.input.autocomplete().data("uiAutocomplete")._renderItem = renderAutocompleteItem; + $tagit.input.autocomplete().data("ui-autocomplete")._renderItem = renderAutocompleteItem; + $tagit.input.autocomplete().on("autocompletefocus", function (event, ui) { + event.preventDefault(); + }); }); diff --git a/src/Orchard.Web/Modules/Orchard.Taxonomies/Services/ITaxonomyService.cs b/src/Orchard.Web/Modules/Orchard.Taxonomies/Services/ITaxonomyService.cs index ab31ba19b..fd3cd01a7 100644 --- a/src/Orchard.Web/Modules/Orchard.Taxonomies/Services/ITaxonomyService.cs +++ b/src/Orchard.Web/Modules/Orchard.Taxonomies/Services/ITaxonomyService.cs @@ -41,6 +41,7 @@ namespace Orchard.Taxonomies.Services { IEnumerable GetTerms(int taxonomyId); + int GetTermsCount(int taxonomyId); TermPart GetTerm(int id); TermPart GetTermByName(int taxonomyId, string name); void DeleteTerm(TermPart termPart); diff --git a/src/Orchard.Web/Modules/Orchard.Taxonomies/Services/TaxonomyService.cs b/src/Orchard.Web/Modules/Orchard.Taxonomies/Services/TaxonomyService.cs index a6d6b14d0..296f41a2b 100644 --- a/src/Orchard.Web/Modules/Orchard.Taxonomies/Services/TaxonomyService.cs +++ b/src/Orchard.Web/Modules/Orchard.Taxonomies/Services/TaxonomyService.cs @@ -185,6 +185,12 @@ namespace Orchard.Taxonomies.Services { return TermPart.Sort(result); } + public int GetTermsCount(int taxonomyId) { + return _contentManager.Query() + .Where(x => x.TaxonomyId == taxonomyId) + .Count(); + } + public TermPart GetTerm(int id) { return _contentManager .Query() diff --git a/src/Orchard.Web/Modules/Orchard.Taxonomies/Styles/admin-taxonomy-tags.css b/src/Orchard.Web/Modules/Orchard.Taxonomies/Styles/admin-taxonomy-tags.css index 48db0b876..115a4fffd 100644 --- a/src/Orchard.Web/Modules/Orchard.Taxonomies/Styles/admin-taxonomy-tags.css +++ b/src/Orchard.Web/Modules/Orchard.Taxonomies/Styles/admin-taxonomy-tags.css @@ -2,6 +2,10 @@ opacity: 0.3; } +.ui-autocomplete .ui-menu-item { + float: none; +} + .ui-autocomplete .ui-menu-item a { font-size: 0.8em; } diff --git a/src/Orchard.Web/Modules/Orchard.Taxonomies/ViewModels/TaxonomyFieldViewModel.cs b/src/Orchard.Web/Modules/Orchard.Taxonomies/ViewModels/TaxonomyFieldViewModel.cs index 1eccb5eda..948227fe7 100644 --- a/src/Orchard.Web/Modules/Orchard.Taxonomies/ViewModels/TaxonomyFieldViewModel.cs +++ b/src/Orchard.Web/Modules/Orchard.Taxonomies/ViewModels/TaxonomyFieldViewModel.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using Orchard.Taxonomies.Models; using Orchard.Taxonomies.Settings; namespace Orchard.Taxonomies.ViewModels { @@ -8,6 +9,8 @@ namespace Orchard.Taxonomies.ViewModels { public string DisplayName { get; set; } public TaxonomyFieldSettings Settings { get; set; } public IList Terms { get; set; } + public IEnumerable SelectedTerms { get; set; } public int SingleTermId { get; set; } + public bool HasTerms { get; set; } } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Taxonomies/Views/EditorTemplates/Fields/TaxonomyField.Autocomplete.cshtml b/src/Orchard.Web/Modules/Orchard.Taxonomies/Views/EditorTemplates/Fields/TaxonomyField.Autocomplete.cshtml index a63b09cc2..11f5e0f1b 100644 --- a/src/Orchard.Web/Modules/Orchard.Taxonomies/Views/EditorTemplates/Fields/TaxonomyField.Autocomplete.cshtml +++ b/src/Orchard.Web/Modules/Orchard.Taxonomies/Views/EditorTemplates/Fields/TaxonomyField.Autocomplete.cshtml @@ -1,5 +1,6 @@ @model TaxonomyFieldViewModel @using Orchard.Taxonomies.Helpers; +@using Orchard.Taxonomies.Models @using Orchard.Utility.Extensions; @using Orchard.Taxonomies.ViewModels; @@ -18,60 +19,61 @@ Script.Include("~/Themes/TheAdmin/scripts/admin.js").AtFoot(); Script.Include("admin-taxonomy-expando.js").AtFoot(); - var termIndex = 0; } @functions { - bool IsTermDisabled(TermEntry term) { + bool IsTermDisabled(TermPart term) { return !term.Selectable || (Model.Settings.LeavesOnly && Model.Terms.Any(t => t.Path.Contains(term.Path + term.Id))); } } @{ - var allTerms = Newtonsoft.Json.JsonConvert.SerializeObject(Model.Terms.Select(x => new { label = x.Name, value = x.Id, levels = x.GetLevels(), disabled = IsTermDisabled(x) })); - var selectedTerms = Newtonsoft.Json.JsonConvert.SerializeObject(Model.Terms.Where(x => x.IsChecked).Select(x => new { label = x.Name, value = x.Id, levels = 0, disabled = true })); + var termIndex = 0; + var checkedTerms = Model.SelectedTerms.ToList(); + var selectedTerms = Newtonsoft.Json.JsonConvert.SerializeObject(checkedTerms.Select(x => new { label = x.Name, value = x.Id, levels = 0, disabled = true })); + }
    @if (Model.Settings.Autocomplete) { -
    -
      - @if (Model.Settings.SingleChoice) { -
      @T("Enter a single term. Hit tab or enter to apply the term.") @if (!Model.Settings.AllowCustomTerms) { @T("This taxonomy does not allow you to create new terms.") }
      - } - else { -
      @T("Enter multiple terms. Hit tab, enter or , to add multiple terms.") @if (!Model.Settings.AllowCustomTerms) { @T("This taxonomy does not allow you to create new terms.") }
      - } -
      +
      +
        + @if (Model.Settings.SingleChoice) { +
        @T("Enter a single term. Hit tab or enter to apply the term.") @if (!Model.Settings.AllowCustomTerms) { @T("This taxonomy does not allow you to create new terms.") }
        + } + else { +
        @T("Enter multiple terms. Hit tab, enter or , to add multiple terms.") @if (!Model.Settings.AllowCustomTerms) { @T("This taxonomy does not allow you to create new terms.") }
        + } +
        } @if (!String.IsNullOrWhiteSpace(Model.Settings.Hint)) { - @Model.Settings.Hint + @Model.Settings.Hint }
          - @foreach (var entry in Model.Terms) { - var ti = termIndex; -
        • - @{ - var disabled = IsTermDisabled(entry); - if (Model.Settings.SingleChoice) { - disabled="disabled" } type="radio" value="@Model.Terms[ti].Id" @if (entry.Id == Model.SingleTermId) { checked="checked" } name="@Html.FieldNameFor(m => m.SingleTermId)" id="@Html.FieldIdFor(m => m.Terms[ti].IsChecked)" data-term="@entry.Name" data-term-identity="@entry.Name.ToLower()" /> + @foreach (var entry in checkedTerms) { + var ti = termIndex; +
        • + @{ + var disabled = IsTermDisabled(entry); + if (Model.Settings.SingleChoice) { + disabled="disabled" } type="radio" value="@entry.Id" @if (entry.Id == Model.SingleTermId){ checked="checked" } name="@Html.FieldNameFor(m => m.SingleTermId)" id="@Html.FieldIdFor(m => m.Terms[ti].IsChecked)" data-term="@entry.Name" data-term-identity="@entry.Name.ToLower()" /> + } + else { + disabled="disabled" } type="checkbox" value="true" checked="checked" name="@Html.FieldNameFor(m => m.Terms[ti].IsChecked)" id="@Html.FieldIdFor(m => m.Terms[ti].IsChecked)" data-term="@entry.Name" data-term-identity="@entry.Name.ToLower()" /> + } } - else { - disabled="disabled" } type="checkbox" value="true" @if (entry.IsChecked) { checked="checked" } name="@Html.FieldNameFor(m => m.Terms[ti].IsChecked)" id="@Html.FieldIdFor(m => m.Terms[ti].IsChecked)" data-term="@entry.Name" data-term-identity="@entry.Name.ToLower()" /> - } - } - - @Html.HiddenFor(m => m.Terms[ti].Id) -
        • - termIndex++; - } + + + + termIndex++; + }
        - @if (!Model.Terms.Any() && AuthorizedFor(Orchard.Taxonomies.Permissions.CreateTerm)) { -
        - @T("There are no terms defined for {0} yet.", Model.DisplayName) - @T("Create some terms") -
        + @if (!Model.HasTerms && AuthorizedFor(Orchard.Taxonomies.Permissions.CreateTerm)) { +
        + @T("There are no terms defined for {0} yet.", Model.DisplayName.CamelFriendly()) + @T("Create some terms") +
        } @Html.HiddenFor(m => m.TaxonomyId)
        From c81fc702516981087766706d1f3f3282c27f6e26 Mon Sep 17 00:00:00 2001 From: Jeff Date: Mon, 28 Sep 2015 15:52:43 +0100 Subject: [PATCH 2/2] Added admin check and moved tag class to separate file with serialization attributes for lowercasing property names. --- .../Controllers/TagsController.cs | 39 ++++++++++--------- .../Orchard.Taxonomies.csproj | 4 ++ .../Orchard.Taxonomies/ViewModels/Tag.cs | 17 ++++++++ 3 files changed, 42 insertions(+), 18 deletions(-) create mode 100644 src/Orchard.Web/Modules/Orchard.Taxonomies/ViewModels/Tag.cs diff --git a/src/Orchard.Web/Modules/Orchard.Taxonomies/Controllers/TagsController.cs b/src/Orchard.Web/Modules/Orchard.Taxonomies/Controllers/TagsController.cs index 3b99517d3..bc1d929f3 100644 --- a/src/Orchard.Web/Modules/Orchard.Taxonomies/Controllers/TagsController.cs +++ b/src/Orchard.Web/Modules/Orchard.Taxonomies/Controllers/TagsController.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Globalization; using System.Web.Http; using Orchard.ContentManagement; @@ -9,25 +10,33 @@ using Orchard.Taxonomies.Helpers; using Orchard.Taxonomies.Models; using Orchard.Taxonomies.Services; using System.Linq; +using Orchard.Security; +using Orchard.Taxonomies.ViewModels; namespace Orchard.Taxonomies.Controllers { public class TagsController : ApiController { private readonly ITaxonomyService _taxonomyService; private readonly IContentManager _contentManager; + private readonly IAuthorizer _authorizer; public Localizer T { get; set; } protected ILogger Logger { get; set; } public TagsController( ITaxonomyService taxonomyService, - IContentManager contentManager) { + IContentManager contentManager, + IAuthorizer authorizer) { _taxonomyService = taxonomyService; T = NullLocalizer.Instance; _contentManager = contentManager; + _authorizer = authorizer; Logger = NullLogger.Instance; } - public IEnumerable Get(int taxonomyId, bool leavesOnly, string query) { - if (string.IsNullOrEmpty(query)) return new List(); + public IEnumerable Get(int taxonomyId, bool leavesOnly, string query) { + if (!_authorizer.Authorize(StandardPermissions.AccessAdminPanel)) { + throw new UnauthorizedAccessException("Can't access the admin"); + } + if (string.IsNullOrEmpty(query)) return new List(); var allTerms = leavesOnly ? _taxonomyService.GetTerms(taxonomyId).ToList() : new List(); @@ -36,25 +45,19 @@ namespace Orchard.Taxonomies.Controllers { .Join() .Where(r => r.Title.Contains(query)) .List() - .Select(t => CreateTagDto(t, leavesOnly, allTerms)) - .OrderBy(t => t.label) + .Select(t => BuildTag(t, leavesOnly, allTerms)) + .OrderBy(t => t.Label) .ToList(); return matchingTerms; } - private static TagDto CreateTagDto(TermPart term, bool leavesOnly, IEnumerable terms) { - return new TagDto { - value = term.Id, - label = term.Name, - disabled = !term.Selectable || (leavesOnly && terms.Any(t => t.Path.Contains(term.Path + term.Id))), - levels = term.GetLevels() + private static Tag BuildTag(TermPart term, bool leavesOnly, IEnumerable terms) { + return new Tag { + Value = term.Id, + Label = term.Name, + Disabled = !term.Selectable || (leavesOnly && terms.Any(t => t.Path.Contains(term.Path + term.Id))), + Levels = term.GetLevels() }; } } - public class TagDto { - public string label { get; set; } - public int value { get; set; } - public int levels { get; set; } - public bool disabled { get; set; } - } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Taxonomies/Orchard.Taxonomies.csproj b/src/Orchard.Web/Modules/Orchard.Taxonomies/Orchard.Taxonomies.csproj index d7249ff13..b3725af1a 100644 --- a/src/Orchard.Web/Modules/Orchard.Taxonomies/Orchard.Taxonomies.csproj +++ b/src/Orchard.Web/Modules/Orchard.Taxonomies/Orchard.Taxonomies.csproj @@ -50,6 +50,9 @@ + + ..\..\..\..\lib\newtonsoft.json\Newtonsoft.Json.dll + 3.5 @@ -76,6 +79,7 @@ + diff --git a/src/Orchard.Web/Modules/Orchard.Taxonomies/ViewModels/Tag.cs b/src/Orchard.Web/Modules/Orchard.Taxonomies/ViewModels/Tag.cs new file mode 100644 index 000000000..e379d0653 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Taxonomies/ViewModels/Tag.cs @@ -0,0 +1,17 @@ +using Newtonsoft.Json; + +namespace Orchard.Taxonomies.ViewModels { + public class Tag { + [JsonProperty("label")] + public string Label { get; set; } + + [JsonProperty("value")] + public int Value { get; set; } + + [JsonProperty("levels")] + public int Levels { get; set; } + + [JsonProperty("disabled")] + public bool Disabled { get; set; } + } +} \ No newline at end of file