mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2025-10-15 19:54:57 +08:00
Initial work on configurable search widget.
This commit is contained in:
@@ -30,6 +30,7 @@ namespace Orchard.Search.Controllers {
|
||||
IContentManager contentManager,
|
||||
ISiteService siteService,
|
||||
IShapeFactory shapeFactory) {
|
||||
|
||||
Services = services;
|
||||
_searchService = searchService;
|
||||
_contentManager = contentManager;
|
||||
@@ -45,23 +46,24 @@ namespace Orchard.Search.Controllers {
|
||||
public ILogger Logger { get; set; }
|
||||
dynamic Shape { get; set; }
|
||||
|
||||
public ActionResult Index(PagerParameters pagerParameters, string q = "") {
|
||||
public ActionResult Index(PagerParameters pagerParameters, string searchIndex = null, string q = "") {
|
||||
var pager = new Pager(_siteService.GetSiteSettings(), pagerParameters);
|
||||
var searchSettingPart = Services.WorkContext.CurrentSite.As<SearchSettingsPart>();
|
||||
var index = !String.IsNullOrWhiteSpace(searchIndex) ? searchIndex.Trim() : searchSettingPart.SearchIndex;
|
||||
|
||||
if (String.IsNullOrEmpty(searchSettingPart.SearchIndex)) {
|
||||
Services.Notifier.Error(T("Please define a default search index"));
|
||||
if (String.IsNullOrEmpty(index)) {
|
||||
Services.Notifier.Error(T("Please define a default search index."));
|
||||
return HttpNotFound();
|
||||
}
|
||||
|
||||
IPageOfItems<ISearchHit> searchHits = new PageOfItems<ISearchHit>(new ISearchHit[] { });
|
||||
try {
|
||||
|
||||
searchHits = _searchService.Query(q, pager.Page, pager.PageSize,
|
||||
Services.WorkContext.CurrentSite.As<SearchSettingsPart>().FilterCulture,
|
||||
searchSettingPart.SearchIndex,
|
||||
searchSettingPart.GetSearchFields(),
|
||||
searchHit => searchHit);
|
||||
searchHits = _searchService.Query(
|
||||
q, pager.Page, pager.PageSize,
|
||||
Services.WorkContext.CurrentSite.As<SearchSettingsPart>().FilterCulture,
|
||||
index,
|
||||
searchSettingPart.GetSearchFields(index),
|
||||
searchHit => searchHit);
|
||||
} catch(Exception exception) {
|
||||
Logger.Error(T("Invalid search query: {0}", exception.Message).Text);
|
||||
Services.Notifier.Error(T("Invalid search query: {0}", exception.Message));
|
||||
|
@@ -1,19 +1,49 @@
|
||||
using Orchard.ContentManagement.Drivers;
|
||||
using System.Linq;
|
||||
using Orchard.ContentManagement;
|
||||
using Orchard.ContentManagement.Drivers;
|
||||
using Orchard.Indexing;
|
||||
using Orchard.Search.Models;
|
||||
using Orchard.Search.ViewModels;
|
||||
|
||||
namespace Orchard.Search.Drivers {
|
||||
public class SearchFormPartDriver : ContentPartDriver<SearchFormPart> {
|
||||
private readonly IIndexManager _indexManager;
|
||||
public SearchFormPartDriver(IIndexManager indexManager) {
|
||||
_indexManager = indexManager;
|
||||
}
|
||||
|
||||
protected override DriverResult Display(SearchFormPart part, string displayType, dynamic shapeHelper) {
|
||||
var model = new SearchViewModel();
|
||||
return ContentShape("Parts_Search_SearchForm",
|
||||
() => {
|
||||
var shape = shapeHelper.Parts_Search_SearchForm();
|
||||
shape.ContentPart = part;
|
||||
shape.ViewModel = model;
|
||||
return shape;
|
||||
});
|
||||
return ContentShape("Parts_Search_SearchForm", () => {
|
||||
var shape = shapeHelper.Parts_Search_SearchForm();
|
||||
shape.AvailableIndexes = _indexManager.GetSearchIndexProvider().List().ToList();
|
||||
shape.ContentPart = part;
|
||||
shape.ViewModel = model;
|
||||
return shape;
|
||||
});
|
||||
}
|
||||
|
||||
protected override DriverResult Editor(SearchFormPart part, dynamic shapeHelper) {
|
||||
return Editor(part, null, shapeHelper);
|
||||
}
|
||||
|
||||
protected override DriverResult Editor(SearchFormPart part, IUpdateModel updater, dynamic shapeHelper) {
|
||||
return ContentShape("Parts_Search_SearchForm_Edit", () => {
|
||||
var viewModel = new SearchFormViewModel {
|
||||
OverrideIndex = part.OverrideIndex,
|
||||
AvailableIndexes = _indexManager.GetSearchIndexProvider().List().ToList(),
|
||||
SelectedIndex = part.SelectedIndex
|
||||
};
|
||||
|
||||
if (updater != null) {
|
||||
if (updater.TryUpdateModel(viewModel, Prefix, null, new[] {"AvailableIndexes"})) {
|
||||
part.OverrideIndex = viewModel.OverrideIndex;
|
||||
part.SelectedIndex = viewModel.SelectedIndex;
|
||||
}
|
||||
}
|
||||
|
||||
return shapeHelper.EditorTemplate(TemplateName: "Parts/Search.SearchForm", Model: viewModel, Prefix: Prefix);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@@ -33,7 +33,11 @@ namespace Orchard.Search.Helpers {
|
||||
}
|
||||
|
||||
public static string[] GetSearchFields(this SearchSettingsPart part) {
|
||||
return part.SearchFields.ContainsKey(part.SearchIndex) ? part.SearchFields[part.SearchIndex] : new string[0];
|
||||
return GetSearchFields(part, part.SearchIndex);
|
||||
}
|
||||
|
||||
public static string[] GetSearchFields(this SearchSettingsPart part, string index) {
|
||||
return part.SearchFields.ContainsKey(index) ? part.SearchFields[index] : new string[0];
|
||||
}
|
||||
}
|
||||
}
|
@@ -5,5 +5,14 @@ namespace Orchard.Search.Models {
|
||||
/// Content part for the search form widget
|
||||
/// </summary>
|
||||
public class SearchFormPart : ContentPart {
|
||||
public bool OverrideIndex {
|
||||
get { return this.Retrieve(x => x.OverrideIndex); }
|
||||
set { this.Store(x => x.OverrideIndex, value); }
|
||||
}
|
||||
|
||||
public string SelectedIndex {
|
||||
get { return this.Retrieve(x => x.SelectedIndex); }
|
||||
set { this.Store(x => x.SelectedIndex, value); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -88,6 +88,7 @@
|
||||
<Compile Include="Services\SearchService.cs" />
|
||||
<Compile Include="Settings\ContentPickerFieldEditorEvents.cs" />
|
||||
<Compile Include="Settings\ContentPickerFieldSettings.cs" />
|
||||
<Compile Include="ViewModels\SearchFormViewModel.cs" />
|
||||
<Compile Include="ViewModels\SearchSettingsViewModel.cs" />
|
||||
<Compile Include="ViewModels\SearchResultViewModel.cs" />
|
||||
<Compile Include="ViewModels\SearchViewModel.cs" />
|
||||
@@ -95,9 +96,8 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\Orchard\Orchard.Framework.csproj">
|
||||
<Project>{2D1D92BB-4555-4CBE-8D0E-63563D6CE4C6}</Project>
|
||||
<Project>{2d1d92bb-4555-4cbe-8d0e-63563d6ce4c6}</Project>
|
||||
<Name>Orchard.Framework</Name>
|
||||
<Private>false</Private>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Orchard.MediaLibrary\Orchard.MediaLibrary.csproj">
|
||||
<Project>{73a7688a-5bd3-4f7e-adfa-ce36c5a10e3b}</Project>
|
||||
@@ -160,6 +160,9 @@
|
||||
<SubType>Designer</SubType>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="Views\EditorTemplates\Parts\Search.SearchForm.cshtml" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup>
|
||||
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
|
||||
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
||||
|
@@ -2,10 +2,11 @@
|
||||
<Place Parts_AdminSearch_SiteSettings="Content:1"/>
|
||||
<Place Parts_Search_SiteSettings="Content:1"/>
|
||||
<Place Parts_Search_SearchForm="Content:1"/>
|
||||
<Place Parts_Search_SearchForm_Edit="Content:1"/>
|
||||
|
||||
<Place
|
||||
Parts_Search_MediaLibrary_Actions="Actions:6"
|
||||
Parts_Search_MediaLibrary_Navigation="Navigation:1"
|
||||
<Place
|
||||
Parts_Search_MediaLibrary_Actions="Actions:6"
|
||||
Parts_Search_MediaLibrary_Navigation="Navigation:1"
|
||||
/>
|
||||
|
||||
|
||||
</Placement>
|
||||
|
@@ -3,7 +3,6 @@ using Orchard.UI.Resources;
|
||||
namespace Orchard.Search {
|
||||
public class ResourceManifest : IResourceManifestProvider {
|
||||
public void BuildManifests(ResourceManifestBuilder builder) {
|
||||
builder.Add().DefineStyle("SearchAdmin").SetUrl("orchard-search-admin.css"); // todo: this does not appear to be used anywhere
|
||||
builder.Add().DefineStyle("Search").SetUrl("orchard-search-search.css");
|
||||
}
|
||||
}
|
||||
|
@@ -13,22 +13,22 @@ namespace Orchard.Search {
|
||||
|
||||
public IEnumerable<RouteDescriptor> GetRoutes() {
|
||||
return new[] {
|
||||
new RouteDescriptor {
|
||||
Priority = 5,
|
||||
Route = new Route(
|
||||
"Search",
|
||||
new RouteValueDictionary {
|
||||
{"area", "Orchard.Search"},
|
||||
{"controller", "search"},
|
||||
{"action", "index"}
|
||||
},
|
||||
null,
|
||||
new RouteValueDictionary {
|
||||
{"area", "Orchard.Search"}
|
||||
},
|
||||
new MvcRouteHandler())
|
||||
}
|
||||
};
|
||||
new RouteDescriptor {
|
||||
Priority = 5,
|
||||
Route = new Route("Search/{searchIndex}",
|
||||
new RouteValueDictionary {
|
||||
{"area", "Orchard.Search"},
|
||||
{"controller", "Search"},
|
||||
{"action", "Index"},
|
||||
{"searchIndex", UrlParameter.Optional}
|
||||
},
|
||||
null,
|
||||
new RouteValueDictionary {
|
||||
{"area", "Orchard.Search"}
|
||||
},
|
||||
new MvcRouteHandler())
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,3 +1,4 @@
|
||||
#main button {
|
||||
display:block;
|
||||
.search-indexes > li {
|
||||
float: left;
|
||||
margin: 0 2em 2em 0;
|
||||
}
|
@@ -23,5 +23,4 @@ form.search input {
|
||||
/*Search widget styles. More syles could be added here to target specific zones.*/
|
||||
.widget-search-form {
|
||||
float:right;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,9 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Orchard.Search.ViewModels {
|
||||
public class SearchFormViewModel {
|
||||
public bool OverrideIndex { get; set; }
|
||||
public string SelectedIndex { get; set; }
|
||||
public IList<string> AvailableIndexes { get; set; }
|
||||
}
|
||||
}
|
@@ -0,0 +1,19 @@
|
||||
@model Orchard.Search.ViewModels.SearchFormViewModel
|
||||
@{
|
||||
Script.Require("ShapesBase");
|
||||
}
|
||||
@{
|
||||
var indexOptions = Model.AvailableIndexes.Select(x => new SelectListItem { Text = x, Value = x, Selected = x == Model.SelectedIndex });
|
||||
}
|
||||
<fieldset>
|
||||
<div class="form-group">
|
||||
@Html.CheckBoxFor(m => m.OverrideIndex)
|
||||
@Html.LabelFor(m => m.OverrideIndex, T("Override Search Index").Text, new { @class = "forcheckbox" })
|
||||
@Html.Hint(T("Check this if you want to specify a different index for this widget to search."))
|
||||
</div>
|
||||
<div class="form-group" data-controllerid="@Html.FieldIdFor(m => m.OverrideIndex)">
|
||||
@Html.LabelFor(m => m.SelectedIndex, T("Index"))
|
||||
@Html.DropDownListFor(m => m.SelectedIndex, indexOptions)
|
||||
@Html.Hint(T("The index to search."))
|
||||
</div>
|
||||
</fieldset>
|
@@ -1,50 +1,52 @@
|
||||
@using Orchard.Search.ViewModels
|
||||
@model SearchSettingsViewModel
|
||||
@{
|
||||
Script.Require("jQuery");
|
||||
Script.Include("orchard-search-settings.js");
|
||||
Style.Include("orchard-search-admin.css");
|
||||
}
|
||||
<fieldset>
|
||||
<legend>@T("Search")</legend>
|
||||
<div>
|
||||
<label>@T("Indexes")</label>
|
||||
|
||||
<div class="form-group">
|
||||
<label>@T("Default Index")</label>
|
||||
@if (Model.Entries != null && Model.Entries.Any()) {
|
||||
if (String.IsNullOrWhiteSpace(Model.SelectedIndex)) {
|
||||
Model.Entries.Insert(0, new IndexSettingsEntry { Index = "" });
|
||||
}
|
||||
|
||||
<select id="selectIndex" name="@Html.NameFor(m => m.SelectedIndex)">
|
||||
@foreach (var modelEntry in Model.Entries) {
|
||||
@Html.SelectOption(Model.SelectedIndex, modelEntry.Index, modelEntry.Index)
|
||||
}
|
||||
</select>
|
||||
<span class="hint">@T("Select which index to use in search queries.")</span>
|
||||
@Html.Hint(T("Select which index to use by default in search queries."))
|
||||
|
||||
<label>@T("Fields")</label>
|
||||
<ul class="search-fields" data-selected-index="@Model.SelectedIndex">
|
||||
@{var entryIndex = 0;}
|
||||
@foreach (var modelEntry in Model.Entries) {
|
||||
@Html.HiddenFor(m => m.Entries[entryIndex].Index)
|
||||
<li data-index="@modelEntry.Index">
|
||||
@if (modelEntry.Fields != null && modelEntry.Fields.Any()) {
|
||||
<ul class="search-indexes group">
|
||||
@{
|
||||
var indexes = Model.Entries.Select(x => x.Index);
|
||||
var entryIndex = 0;
|
||||
foreach (var index in indexes) {
|
||||
var fieldEntries = Model.Entries.Single(x => x.Index == index).Fields;
|
||||
var entryIndexClosure = entryIndex;
|
||||
@Html.HiddenFor(m => m.Entries[entryIndex].Index)
|
||||
<li>
|
||||
<h3>@index</h3>
|
||||
<ul>
|
||||
@{ var fieldIndex = 0;}
|
||||
@foreach (var fieldEntry in Model.Entries[entryIndex].Fields) {
|
||||
@{ var fieldIndex = 0; }
|
||||
@foreach (var fieldEntry in fieldEntries) {
|
||||
var fieldIndexClosure = fieldIndex;
|
||||
<li>
|
||||
@Html.EditorFor(m => m.Entries[entryIndex].Fields[fieldIndex].Selected)
|
||||
@Html.HiddenFor(m => m.Entries[entryIndex].Fields[fieldIndex].Field)
|
||||
<label class="forcheckbox" for="@Html.FieldIdFor(m => m.Entries[entryIndex].Fields[fieldIndex].Selected)">@Model.Entries[entryIndex].Fields[fieldIndex].Field</label>
|
||||
<label class="forcheckbox" for="@Html.FieldIdFor(m => m.Entries[entryIndexClosure].Fields[fieldIndexClosure].Selected)">@Model.Entries[entryIndex].Fields[fieldIndex].Field</label>
|
||||
</li>
|
||||
fieldIndex++;
|
||||
}
|
||||
</ul>
|
||||
}
|
||||
</li>
|
||||
</li>
|
||||
entryIndex++;
|
||||
}
|
||||
}
|
||||
</ul>
|
||||
<span class="hint">@T("Check any property which should be used for search queries.")</span>
|
||||
<span class="hint">@T("Check any field for each index which should be used for search queries.")</span>
|
||||
|
||||
}
|
||||
else {
|
||||
|
@@ -1,11 +1,20 @@
|
||||
@using Orchard.Search.ViewModels;
|
||||
|
||||
@using Orchard.ContentManagement
|
||||
@using Orchard.Search.Models
|
||||
@using Orchard.Search.ViewModels;
|
||||
@{
|
||||
Style.Require("Search");
|
||||
}
|
||||
@{
|
||||
var settings = WorkContext.CurrentSite.As<SearchSettingsPart>();
|
||||
var part = (SearchFormPart)Model.ContentPart;
|
||||
var index = part.OverrideIndex && part.SelectedIndex != settings.SearchIndex ? part.SelectedIndex : default(string);
|
||||
var routeValues = new RouteValueDictionary { { "area", "Orchard.Search" } };
|
||||
|
||||
|
||||
@using(Html.BeginForm("index", "search", new { area = "Orchard.Search" }, FormMethod.Get, new { @class = "search-form" })) {
|
||||
if (!String.IsNullOrEmpty(index)) {
|
||||
routeValues.Add("searchIndex", index);
|
||||
}
|
||||
}
|
||||
@using (Html.BeginForm("Index", "Search", routeValues, FormMethod.Get, new RouteValueDictionary { { "class", "search-form" } })) {
|
||||
<fieldset>
|
||||
@Html.TextBox("q", (SearchViewModel)Model.ViewModel.Query)
|
||||
@Html.Hidden("culture", WorkContext.CurrentCulture)
|
||||
|
Reference in New Issue
Block a user