mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2026-02-09 09:16:41 +08:00
#18182: Implementing Autocompleted on Tags
Work Item: 18182 --HG-- branch : 1.x
This commit is contained in:
@@ -63,5 +63,12 @@ namespace Orchard.Tags.Controllers {
|
|||||||
|
|
||||||
return View(viewModel);
|
return View(viewModel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public JsonResult FetchSimilarTags(string snippet) {
|
||||||
|
return Json(
|
||||||
|
_tagService.GetTagsByNameSnippet(snippet).Select(tag => tag.TagName).ToList(),
|
||||||
|
JsonRequestBehavior.AllowGet
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ Features:
|
|||||||
Orchard.Tags:
|
Orchard.Tags:
|
||||||
Name: Tags
|
Name: Tags
|
||||||
Description: The tags module is providing basic tagging for arbitrary content types.
|
Description: The tags module is providing basic tagging for arbitrary content types.
|
||||||
Dependencies: Settings
|
Dependencies: Settings, Orchard.jQuery
|
||||||
Category: Navigation
|
Category: Navigation
|
||||||
Orchard.Tags.Projections:
|
Orchard.Tags.Projections:
|
||||||
Name: Tags Projections
|
Name: Tags Projections
|
||||||
|
|||||||
@@ -82,6 +82,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Content Include="Module.txt" />
|
<Content Include="Module.txt" />
|
||||||
|
<Content Include="Scripts\orchard-tags-autocomplete.js" />
|
||||||
<Content Include="Styles\images\menu.tags.png" />
|
<Content Include="Styles\images\menu.tags.png" />
|
||||||
<Content Include="Styles\menu.tags-admin.css" />
|
<Content Include="Styles\menu.tags-admin.css" />
|
||||||
<Content Include="Styles\orchard-tags-admin.css" />
|
<Content Include="Styles\orchard-tags-admin.css" />
|
||||||
@@ -117,6 +118,9 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Content Include="web.config" />
|
<Content Include="web.config" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Content Include="Scripts\Web.config" />
|
||||||
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||||
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets" />
|
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets" />
|
||||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||||
|
|||||||
@@ -3,7 +3,11 @@ using Orchard.UI.Resources;
|
|||||||
namespace Orchard.Tags {
|
namespace Orchard.Tags {
|
||||||
public class ResourceManifest : IResourceManifestProvider {
|
public class ResourceManifest : IResourceManifestProvider {
|
||||||
public void BuildManifests(ResourceManifestBuilder builder) {
|
public void BuildManifests(ResourceManifestBuilder builder) {
|
||||||
builder.Add().DefineStyle("TagsAdmin").SetUrl("orchard-tags-admin.css");
|
var manifest = builder.Add();
|
||||||
|
|
||||||
|
manifest.DefineScript("TagsAutocomplete").SetUrl("orchard-tags-autocomplete.js").SetDependencies("jQueryUI_Autocomplete");
|
||||||
|
|
||||||
|
manifest.DefineStyle("TagsAdmin").SetUrl("orchard-tags-admin.css");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<configuration>
|
||||||
|
<appSettings>
|
||||||
|
<add key="webpages:Enabled" value="false" />
|
||||||
|
</appSettings>
|
||||||
|
<system.web>
|
||||||
|
<httpHandlers>
|
||||||
|
<!-- iis6 - for any request in this location, return via managed static file handler -->
|
||||||
|
<add path="*" verb="*" type="System.Web.StaticFileHandler" />
|
||||||
|
</httpHandlers>
|
||||||
|
</system.web>
|
||||||
|
<system.webServer>
|
||||||
|
<handlers accessPolicy="Script,Read">
|
||||||
|
<!--
|
||||||
|
iis7 - for any request to a file exists on disk, return it via native http module.
|
||||||
|
accessPolicy 'Script' is to allow for a managed 404 page.
|
||||||
|
-->
|
||||||
|
<add name="StaticFile" path="*" verb="*" modules="StaticFileModule" preCondition="integratedMode" resourceType="File" requireAccess="Read" />
|
||||||
|
</handlers>
|
||||||
|
</system.webServer>
|
||||||
|
</configuration>
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
(function ($) {
|
||||||
|
$.extend({
|
||||||
|
tagsAutocomplete: {
|
||||||
|
minSnippetLength: 3,
|
||||||
|
|
||||||
|
autocomplete: function (textboxId, fetchUrl, minSnippetLength) {
|
||||||
|
if (minSnippetLength != null) this.minSnippetLength = minSnippetLength;
|
||||||
|
|
||||||
|
function split(val) {
|
||||||
|
return val.split(/,\s*/);
|
||||||
|
}
|
||||||
|
function extractLast(snippet) {
|
||||||
|
return split(snippet).pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
var that = this;
|
||||||
|
var textBox = $('#' + textboxId);
|
||||||
|
|
||||||
|
textBox.bind('keydown', function (event) {
|
||||||
|
// don't navigate away from the field on tab when selecting an item
|
||||||
|
if (event.keyCode === $.ui.keyCode.TAB && $(this).data('autocomplete').menu.active) {
|
||||||
|
event.preventDefault();
|
||||||
|
}
|
||||||
|
}).autocomplete({
|
||||||
|
source: function (request, response) {
|
||||||
|
$.getJSON(fetchUrl, {
|
||||||
|
snippet: extractLast(request.term)
|
||||||
|
}, response);
|
||||||
|
},
|
||||||
|
appendTo: textBox.parent(),
|
||||||
|
search: function () {
|
||||||
|
// custom minLength
|
||||||
|
var snippet = extractLast(this.value);
|
||||||
|
if (snippet.length < that.minSnippetLength) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
focus: function () {
|
||||||
|
// prevent value inserted on focus
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
select: function (event, ui) {
|
||||||
|
var snippets = split(this.value);
|
||||||
|
// remove the current input
|
||||||
|
snippets.pop();
|
||||||
|
// add the selected item
|
||||||
|
snippets.push(ui.item.value);
|
||||||
|
// add placeholder to get the comma-and-space at the end
|
||||||
|
snippets.push('');
|
||||||
|
this.value = snippets.join(', ');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})(jQuery);
|
||||||
@@ -5,6 +5,14 @@ using Orchard.Tags.Models;
|
|||||||
namespace Orchard.Tags.Services {
|
namespace Orchard.Tags.Services {
|
||||||
public interface ITagService : IDependency {
|
public interface ITagService : IDependency {
|
||||||
IEnumerable<TagRecord> GetTags();
|
IEnumerable<TagRecord> GetTags();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns tags whose name start with snippet
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="snippet">The starting snippet</param>
|
||||||
|
/// <param name="maxCount">Maximum number of tags returned</param>
|
||||||
|
/// <returns>Tags found</returns>
|
||||||
|
IEnumerable<TagRecord> GetTagsByNameSnippet(string snippet, int maxCount = 10);
|
||||||
TagRecord GetTag(int tagId);
|
TagRecord GetTag(int tagId);
|
||||||
TagRecord GetTagByName(string tagName);
|
TagRecord GetTagByName(string tagName);
|
||||||
IEnumerable<IContent> GetTaggedContentItems(int tagId);
|
IEnumerable<IContent> GetTaggedContentItems(int tagId);
|
||||||
|
|||||||
@@ -41,6 +41,11 @@ namespace Orchard.Tags.Services {
|
|||||||
return _tagRepository.Table.ToList();
|
return _tagRepository.Table.ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IEnumerable<TagRecord> GetTagsByNameSnippet(string snippet, int maxCount = 10) {
|
||||||
|
if (String.IsNullOrEmpty(snippet)) return null; // Otherwise would return the whole dataset
|
||||||
|
return _tagRepository.Fetch(tag => tag.TagName.StartsWith(snippet)).Take(maxCount);
|
||||||
|
}
|
||||||
|
|
||||||
public TagRecord GetTag(int tagId) {
|
public TagRecord GetTag(int tagId) {
|
||||||
return _tagRepository.Get(x => x.Id == tagId);
|
return _tagRepository.Get(x => x.Id == tagId);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,23 @@
|
|||||||
@model Orchard.Tags.ViewModels.EditTagsViewModel
|
@model Orchard.Tags.ViewModels.EditTagsViewModel
|
||||||
|
|
||||||
|
@{
|
||||||
|
Style.Require("jQueryUI_Orchard");
|
||||||
|
Script.Require("TagsAutocomplete");
|
||||||
|
}
|
||||||
|
|
||||||
<fieldset>
|
<fieldset>
|
||||||
@Html.LabelFor(m => m.Tags, T("Tags"))
|
@Html.LabelFor(m => m.Tags, T("Tags"))
|
||||||
@Html.TextBoxFor(m => m.Tags, new { @class = "large text" })
|
@Html.TextBoxFor(m => m.Tags, new { @class = "large text" })
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
|
@using (Script.Foot()) {
|
||||||
|
<script type="text/javascript">
|
||||||
|
//<![CDATA[
|
||||||
|
$(function () {
|
||||||
|
$.tagsAutocomplete.autocomplete(
|
||||||
|
'@Html.FieldIdFor(m => m.Tags)',
|
||||||
|
'@Url.Action("FetchSimilarTags", new { Controller = "Home", Area = "Orchard.Tags" })', 1);
|
||||||
|
});
|
||||||
|
//]]>
|
||||||
|
</script>
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user