diff --git a/src/Orchard.Tests.Modules/Indexing/LuceneSearchBuilderTests.cs b/src/Orchard.Tests.Modules/Indexing/LuceneSearchBuilderTests.cs index 7259f6b30..bc9f61174 100644 --- a/src/Orchard.Tests.Modules/Indexing/LuceneSearchBuilderTests.cs +++ b/src/Orchard.Tests.Modules/Indexing/LuceneSearchBuilderTests.cs @@ -483,6 +483,22 @@ namespace Orchard.Tests.Modules.Indexing { Assert.That(SearchBuilder.Parse("body", "*@!woo*@!").Count(), Is.EqualTo(0)); } + [Test] + public void ShouldSearchFolderStructure() { + _provider.CreateIndex("default"); + _provider.Store("default", _provider.New(1).Add("media-path", "images").Store()); + _provider.Store("default", _provider.New(2).Add("media-path", "images/pets/puppies").Store()); + _provider.Store("default", _provider.New(3).Add("media-path", "images/pets/kitties").Store()); + + // Assert.That(SearchBuilder.WithField("media-path", "Pets").Mandatory().Count(), Is.EqualTo(0)); + Assert.That(SearchBuilder.WithField("media-path", "Images").Mandatory().Count(), Is.EqualTo(3)); + Assert.That(SearchBuilder.WithField("media-path", "Images").ExactMatch().Mandatory().Count(), Is.EqualTo(1)); + Assert.That(SearchBuilder.WithField("media-path", "Images/Pets").Mandatory().Count(), Is.EqualTo(2)); + Assert.That(SearchBuilder.WithField("media-path", "Images/Pets").ExactMatch().Mandatory().Count(), Is.EqualTo(0)); + Assert.That(SearchBuilder.WithField("media-path", "Images/Pets/Puppies").ExactMatch().Mandatory().Count(), Is.EqualTo(1)); + Assert.That(SearchBuilder.WithField("media-path", "Images/Pets/Puppies").Mandatory().Count(), Is.EqualTo(1)); + } + [Test] public void FieldsCanContainMultipleValue() { _provider.CreateIndex("default"); diff --git a/src/Orchard.Web/Modules/Lucene/Services/LuceneIndexProvider.cs b/src/Orchard.Web/Modules/Lucene/Services/LuceneIndexProvider.cs index f10e991a9..020b754ba 100644 --- a/src/Orchard.Web/Modules/Lucene/Services/LuceneIndexProvider.cs +++ b/src/Orchard.Web/Modules/Lucene/Services/LuceneIndexProvider.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.IO; using System.Linq; using Lucene.Models; @@ -23,7 +24,6 @@ namespace Lucene.Services { /// public class LuceneIndexProvider : IIndexProvider { private readonly IAppDataFolder _appDataFolder; - private readonly ShellSettings _shellSettings; public static readonly Version LuceneVersion = Version.LUCENE_29; private readonly Analyzer _analyzer ; private readonly string _basePath; @@ -31,11 +31,10 @@ namespace Lucene.Services { public LuceneIndexProvider(IAppDataFolder appDataFolder, ShellSettings shellSettings) { _appDataFolder = appDataFolder; - _shellSettings = shellSettings; _analyzer = CreateAnalyzer(); // TODO: (sebros) Find a common way to get where tenant's specific files should go. "Sites/Tenant" is hard coded in multiple places - _basePath = _appDataFolder.Combine("Sites", _shellSettings.Name, "Indexes"); + _basePath = _appDataFolder.Combine("Sites", shellSettings.Name, "Indexes"); Logger = NullLogger.Instance; @@ -152,13 +151,13 @@ namespace Lucene.Services { if (!documentIds.Any()) { return; } - + using(var writer = new IndexWriter(GetDirectory(indexName), _analyzer, false, IndexWriter.MaxFieldLength.UNLIMITED)) { var query = new BooleanQuery(); try { foreach (var id in documentIds) { - query.Add(new BooleanClause(new TermQuery(new Term("id", id.ToString())), Occur.SHOULD)); + query.Add(new BooleanClause(new TermQuery(new Term("id", id.ToString(CultureInfo.InvariantCulture))), Occur.SHOULD)); } writer.DeleteDocuments(query); diff --git a/src/Orchard.Web/Modules/Lucene/Services/LuceneSearchBuilder.cs b/src/Orchard.Web/Modules/Lucene/Services/LuceneSearchBuilder.cs index c5a5a2b3a..e6f3dd5b2 100644 --- a/src/Orchard.Web/Modules/Lucene/Services/LuceneSearchBuilder.cs +++ b/src/Orchard.Web/Modules/Lucene/Services/LuceneSearchBuilder.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; using Lucene.Models; +using Lucene.Net.Analysis; using Lucene.Net.Index; using Lucene.Net.Search; using Lucene.Net.Store; @@ -33,6 +34,7 @@ namespace Lucene.Services { private bool _exactMatch; private float _boost; private Query _query; + private readonly Analyzer _analyzer = LuceneIndexProvider.CreateAnalyzer(); public ILogger Logger { get; set; } @@ -68,10 +70,9 @@ namespace Lucene.Services { query = QueryParser.Escape(query); } - var analyzer = LuceneIndexProvider.CreateAnalyzer(); foreach (var defaultField in defaultFields) { CreatePendingClause(); - _query = new QueryParser(LuceneIndexProvider.LuceneVersion, defaultField, analyzer).Parse(query); + _query = new QueryParser(LuceneIndexProvider.LuceneVersion, defaultField, _analyzer).Parse(query); } return this; @@ -159,8 +160,6 @@ namespace Lucene.Services { _query = null; _boost = 0; _asFilter = false; - _sort = String.Empty; - _comparer = 0; } private void CreatePendingClause() { @@ -189,7 +188,7 @@ namespace Lucene.Services { _clauses.Add(new BooleanClause(_query, _occur)); } - _query = null; + InitPendingClause(); } public ISearchBuilder SortBy(string name) { diff --git a/src/Orchard.Web/Modules/Orchard.Localization/Handlers/LocalizationPartHandler.cs b/src/Orchard.Web/Modules/Orchard.Localization/Handlers/LocalizationPartHandler.cs index c6077e34f..32b87b863 100644 --- a/src/Orchard.Web/Modules/Orchard.Localization/Handlers/LocalizationPartHandler.cs +++ b/src/Orchard.Web/Modules/Orchard.Localization/Handlers/LocalizationPartHandler.cs @@ -25,8 +25,7 @@ namespace Orchard.Localization.Handlers { OnVersioning((context, part, versionedPart) => LazyLoadHandlers(versionedPart)); OnIndexed((context, localized) => context.DocumentIndex - .Add("culture", CultureInfo.GetCultureInfo(localized.Culture != null ? localized.Culture.Culture : _cultureManager.GetSiteCulture()).LCID) - .Store() + .Add("culture", CultureInfo.GetCultureInfo(localized.Culture != null ? localized.Culture.Culture : _cultureManager.GetSiteCulture()).LCID).Store() ); } diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Controllers/AdminController.cs b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Controllers/AdminController.cs index 2d7471f19..5405bb9c2 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Controllers/AdminController.cs +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Controllers/AdminController.cs @@ -48,13 +48,29 @@ namespace Orchard.MediaLibrary.Controllers { mediaTypes.Add(contentTypeDefinition.Name); } + // let other modules enhance the ui by providing custom navigation and actions + var explorer = Services.ContentManager.New("MediaLibraryExplorer"); + explorer.Weld(new MediaLibraryExplorerPart()); + + var explorerShape = Services.ContentManager.BuildDisplay(explorer); + var viewModel = new MediaManagerIndexViewModel { DialogMode = dialog, Folders = _mediaLibraryService.GetMediaFolders(null).Select(GetFolderHierarchy), FolderPath = folderPath, - MediaTypes = mediaTypes.ToArray() + MediaTypes = mediaTypes.ToArray(), + CustomActionsShapes = explorerShape.Actions, + CustomNavigationShapes = explorerShape.Navigation, }; + foreach (var shape in explorerShape.Actions.Items) { + shape.MediaManagerIndexViewModel = viewModel; + } + + foreach (var shape in explorerShape.Navigation.Items) { + shape.MediaManagerIndexViewModel = viewModel; + } + return View(viewModel); } diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Drivers/MediaLibraryExplorerPartDriver.cs b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Drivers/MediaLibraryExplorerPartDriver.cs new file mode 100644 index 000000000..e15f43e27 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Drivers/MediaLibraryExplorerPartDriver.cs @@ -0,0 +1,13 @@ +using Orchard.ContentManagement.Drivers; +using Orchard.MediaLibrary.Models; + +namespace Orchard.MediaLibrary.Drivers { + public class MediaLibraryExplorerPartDriver : ContentPartDriver { + protected override DriverResult Display(MediaLibraryExplorerPart part, string displayType, dynamic shapeHelper) { + return Combined( + ContentShape("Parts_MediaLibrary_Navigation", () => shapeHelper.Parts_MediaLibrary_Navigation()), + ContentShape("Parts_MediaLibrary_Actions", () => shapeHelper.Parts_MediaLibrary_Actions()) + ); + } + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Handlers/MediaPartHandler.cs b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Handlers/MediaPartHandler.cs index 926254ba8..32efbf696 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Handlers/MediaPartHandler.cs +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Handlers/MediaPartHandler.cs @@ -24,6 +24,41 @@ namespace Orchard.MediaLibrary.Handlers { part._publicUrl.Loader(x => _mediaLibraryService.GetMediaPublicUrl(part.FolderPath, part.FileName)); } }); + + OnIndexing((context, part) => + context.DocumentIndex + .Add("media-folderpath", Normalize(part.FolderPath)).Store() + .Add("media-filename", Normalize(part.FileName)).Store() + .Add("media-mimetype", Normalize(part.MimeType)).Store() + .Add("media-caption", part.Caption).Analyze() + .Add("media-alternatetext", part.AlternateText).Analyze() + ); + + OnIndexing((context, part) => + context.DocumentIndex + .Add("image-height", part.Height).Analyze().Store() + .Add("image-width", part.Width).Analyze().Store() + ); + + OnIndexing((context, part) => + context.DocumentIndex + .Add("document-length", part.Length).Analyze().Store() + ); + + OnIndexing((context, part) => + context.DocumentIndex + .Add("video-length", part.Length).Analyze().Store() + ); + + OnIndexing((context, part) => + context.DocumentIndex + .Add("audio-length", part.Length).Analyze().Store() + ); + + OnIndexing((context, part) => + context.DocumentIndex + .Add("oembed-source", part.Source).Analyze().Store() + ); } protected void RemoveMedia(MediaPart part) { @@ -32,5 +67,10 @@ namespace Orchard.MediaLibrary.Handlers { _storageProvider.DeleteFile(path); } } + + private string Normalize(string text) { + // when not indexed with Analyze() searches are case sensitive + return text.Replace("\\", "/").ToLowerInvariant(); + } } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Models/MediaLibraryExplorerPart.cs b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Models/MediaLibraryExplorerPart.cs new file mode 100644 index 000000000..0305aaf1b --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Models/MediaLibraryExplorerPart.cs @@ -0,0 +1,11 @@ +using Orchard.ContentManagement; + +namespace Orchard.MediaLibrary.Models { + /// + /// Provides an extension point to add custom shapes to the + /// Navigation and Actions zones of the Media Library explorer + /// + public class MediaLibraryExplorerPart : ContentPart { + + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Orchard.MediaLibrary.csproj b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Orchard.MediaLibrary.csproj index 8667294f2..6057b2307 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Orchard.MediaLibrary.csproj +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Orchard.MediaLibrary.csproj @@ -116,6 +116,7 @@ + @@ -146,6 +147,7 @@ + @@ -328,6 +330,12 @@ + + + + + + 10.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Placement.info b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Placement.info index 6184c750f..5e5e05e3b 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Placement.info +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Placement.info @@ -106,4 +106,11 @@ + + + + diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Scripts/media-library.js b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Scripts/media-library.js index 7aafe716a..f4ca95256 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Scripts/media-library.js +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Scripts/media-library.js @@ -1,4 +1,12 @@ -$(function () { +var enhanceViewModel = function(viewModel) { + // extension point for other modules to alter the view model +}; + +var baseViewModel = function() { + +}; + +$(function () { (function (settings) { function mediaPartViewModel(data) { var self = this; @@ -44,6 +52,10 @@ function mediaIndexViewModel() { var self = this; + // placeholder function called to retrieve content when scrolling + self.loadMediaItemsUrl = function (folderPath, skip, count, order, mediaType) { + }; + // values self.selection = ko.observableArray([]); self.focus = ko.observable(); @@ -54,21 +66,26 @@ self.orderMedia = ko.observableArray(['created']); self.mediaType = ko.observableArray([]); - self.getMediaItems = function(folderPath, max) { + self.getMediaItems = function (count, append) { + var folderPath = self.displayed() || ''; + if (self.pendingRequest()) { return; } - if (self.results().length > 0 && self.results().length >= self.mediaItemsCount) { - return; + if (append) { + if (self.results().length > 0 && self.results().length >= self.mediaItemsCount) { + return; + } + } else { + self.results([]); } self.pendingRequest(true); - var url = folderPath - ? settings.mediaItemsActionUrl + '?folderPath=' + encodeURIComponent(folderPath) + '&skip=' + self.results().length + '&count=' + max + '&order=' + self.orderMedia() + '&mediaType=' + self.mediaType() - : settings.recentMediaItemsActionUrl + '?skip=' + self.results().length + '&count=' + max + '&order=' + self.orderMedia() + '&mediaType=' + self.mediaType(); - + var url = self.loadMediaItemsUrl(folderPath, self.results().length, count, self.orderMedia(), self.mediaType()); + console.log(url); + $.ajax({ type: "GET", url: url, @@ -133,9 +150,13 @@ self.displayFolder = function(folderPath) { self.results([]); - - self.getMediaItems(folderPath, 20); self.displayed(folderPath); + + self.loadMediaItemsUrl = function (f, skip, count, order, mediaType) { + return settings.mediaItemsActionUrl + '?folderPath=' + encodeURIComponent(f) + '&skip=' + skip + '&count=' + count + '&order=' + order + '&mediaType=' + mediaType; + }; + + self.getMediaItems(20); }; self.selectFolder = function(folderPath) { @@ -146,46 +167,13 @@ self.selectRecent = function() { History.pushState({ action: 'selectRecent' }, '', '?recent'); + self.loadMediaItemsUrl = function (folderPath, skip, count, order, mediaType) { + return settings.recentMediaItemsActionUrl + '?skip=' + skip + '&count=' + count + '&order=' + order + '&mediaType=' + mediaType; + }; + self.results([]); self.displayed(null); - var max = 20; - - if (self.pendingRequest()) { - return; - } - - if (self.results().length > 0 && self.results().length >= self.mediaItemsCount) { - console.log('no more content, mediaItemsCount: ' + self.mediaItemsCount); - return; - } - - self.pendingRequest(true); - - var url = settings.recentMediaItemsActionUrl + '?skip=' + self.results().length + '&count=' + max + '&order=' + self.orderMedia() + '&mediaType=' + self.mediaType(); - - $.ajax({ - type: "GET", - url: url, - }).done(function(data) { - var mediaItems = data.mediaItems; - self.mediaItemsCount = data.mediaItemsCount; - for (var i = 0; i < mediaItems.length; i++) { - var item = new mediaPartViewModel(mediaItems[i]); - self.results.push(item); - - // pre-select result which are already part of the selection - var selection = self.selection(); - for (var j = 0; j < selection.length; j++) { - if (selection[j].data.id == item.data.id) { - viewModel.toggleSelect(item, true); - } - } - } - }).fail(function(data) { - console.error(data); - }).always(function() { - self.pendingRequest(false); - }); + self.getMediaItems(20); }; self.toggleSelect = function(searchResult, force) { @@ -216,12 +204,7 @@ self.scrolled = function(data, event) { var elem = event.target; if (elem.scrollTop > (elem.scrollHeight - elem.offsetHeight - 300)) { - if (self.displayed()) { - self.getMediaItems(self.displayed(), 20); - } else { - self.getMediaItems(null, 20); - } - + self.getMediaItems(20); } }; @@ -242,6 +225,9 @@ } var viewModel = new mediaIndexViewModel(); + + enhanceViewModel(viewModel); + ko.applyBindings(viewModel); if (settings.hasFolderPath) { diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/ViewModels/MediaManagerIndexViewModel.cs b/src/Orchard.Web/Modules/Orchard.MediaLibrary/ViewModels/MediaManagerIndexViewModel.cs index 24fa9be01..91028a16a 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaLibrary/ViewModels/MediaManagerIndexViewModel.cs +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/ViewModels/MediaManagerIndexViewModel.cs @@ -7,5 +7,7 @@ namespace Orchard.MediaLibrary.ViewModels { public string FolderPath { get; set; } public bool DialogMode { get; set; } public string[] MediaTypes { get; set; } + public dynamic CustomActionsShapes { get; set; } + public dynamic CustomNavigationShapes { get; set; } } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/Admin/Index.cshtml b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/Admin/Index.cshtml index d07c85d02..811274b7f 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/Admin/Index.cshtml +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/Admin/Index.cshtml @@ -20,31 +20,15 @@ @T("Import") @T("Create Folder") - - - - - - - -
- -
+ + @Display(Model.CustomActionsShapes)
    -
  • @T("Recent") + + @Display(Model.CustomNavigationShapes) +
    • @foreach (var folder in viewModel.Folders) { diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/Parts/MediaLibrary.Actions.cshtml b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/Parts/MediaLibrary.Actions.cshtml new file mode 100644 index 000000000..1104b08f3 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/Parts/MediaLibrary.Actions.cshtml @@ -0,0 +1,21 @@ +@using Orchard.MediaLibrary.ViewModels +@{ + MediaManagerIndexViewModel viewModel = Model.MediaManagerIndexViewModel; + +} + + + + + + diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/Parts/MediaLibrary.Navigation.cshtml b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/Parts/MediaLibrary.Navigation.cshtml new file mode 100644 index 000000000..499c6211a --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/Parts/MediaLibrary.Navigation.cshtml @@ -0,0 +1,6 @@ +@using Orchard.MediaLibrary.ViewModels +@{ + MediaManagerIndexViewModel viewModel = Model.MediaManagerIndexViewModel; + +} +
    • @T("Recent") diff --git a/src/Orchard.Web/Modules/Orchard.Search/Controllers/MediaController.cs b/src/Orchard.Web/Modules/Orchard.Search/Controllers/MediaController.cs new file mode 100644 index 000000000..e7e029c19 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Search/Controllers/MediaController.cs @@ -0,0 +1,68 @@ +using System; +using System.Linq; +using System.Web.Mvc; +using Orchard.ContentManagement; +using Orchard.Environment.Extensions; +using Orchard.Indexing; +using Orchard.MediaLibrary.Models; +using Orchard.MediaLibrary.ViewModels; +using Orchard.Themes; +using Orchard.UI.Admin; + +namespace Orchard.Search.Controllers { + [Admin] + [Themed(false)] + [OrchardFeature("Orchard.Search.MediaLibrary")] + public class MediaController : Controller { + private readonly IIndexProvider _indexProvider; + private readonly IContentManager _contentManager; + + public MediaController(IIndexProvider indexProvider, IContentManager contentManager) { + _indexProvider = indexProvider; + _contentManager = contentManager; + } + + public ActionResult MediaItems(string folderPath, int skip = 0, int count = 0, string order = "created", string mediaType = "", string search = "") { + var builder = _indexProvider.CreateSearchBuilder("Media"); + + if (!String.IsNullOrEmpty(search)) { + builder.WithField("title", search); + builder.WithField("author", search); + builder.WithField("media-caption", search); + builder.WithField("media-alternatetext", search); + builder.WithField("media-filename", search); + } + + if (!String.IsNullOrEmpty(mediaType)) { + builder.WithField("type", mediaType).Mandatory().AsFilter(); + } + + if (!String.IsNullOrEmpty(folderPath)) { + var path = folderPath.Replace("\\", "/"); + builder.WithField("media-folderpath", path.ToLowerInvariant()).AsFilter(); + } + + builder.SortBy(order); + + if (order == "title") { + builder.Ascending(); + } + + var mediaPartsCount = builder.Count(); + var contentItemIds = builder.Slice(skip, count).Search().Select(x => x.ContentItemId).ToArray(); + var mediaParts = _contentManager.GetMany(contentItemIds, VersionOptions.Published, QueryHints.Empty); + + var mediaItems = mediaParts.Select(x => new MediaManagerMediaItemViewModel { + MediaPart = x, + Shape = _contentManager.BuildDisplay(x, "Thumbnail") + }).ToList(); + + var viewModel = new MediaManagerMediaItemsViewModel { + MediaItems = mediaItems, + MediaItemsCount = mediaPartsCount + }; + + return View(viewModel); + } + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Search/Drivers/MediaLibraryExplorerPartDriver.cs b/src/Orchard.Web/Modules/Orchard.Search/Drivers/MediaLibraryExplorerPartDriver.cs new file mode 100644 index 000000000..2ef6cc6df --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Search/Drivers/MediaLibraryExplorerPartDriver.cs @@ -0,0 +1,15 @@ +using Orchard.ContentManagement.Drivers; +using Orchard.Environment.Extensions; +using Orchard.MediaLibrary.Models; + +namespace Orchard.Search.Drivers { + [OrchardFeature("Orchard.Search.MediaLibrary")] + public class MediaLibraryExplorerPartDriver : ContentPartDriver { + protected override DriverResult Display(MediaLibraryExplorerPart part, string displayType, dynamic shapeHelper) { + return Combined( + ContentShape("Parts_Search_MediaLibrary_Navigation", () => shapeHelper.Parts_Search_MediaLibrary_Navigation()), + ContentShape("Parts_Search_MediaLibrary_Actions", () => shapeHelper.Parts_Search_MediaLibrary_Actions()) + ); + } + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Search/Migrations.cs b/src/Orchard.Web/Modules/Orchard.Search/Migrations.cs index 682c4e197..941cc3e02 100644 --- a/src/Orchard.Web/Modules/Orchard.Search/Migrations.cs +++ b/src/Orchard.Web/Modules/Orchard.Search/Migrations.cs @@ -2,6 +2,8 @@ using Orchard.ContentManagement.MetaData; using Orchard.Data; using Orchard.Data.Migration; +using Orchard.Environment.Extensions; +using Orchard.Indexing; using Orchard.Search.Models; namespace Orchard.Search { @@ -45,4 +47,26 @@ namespace Orchard.Search { return 2; } } + + [OrchardFeature("Orchard.Search.MediaLibrary")] + public class MediaMigration : DataMigrationImpl { + private readonly IIndexManager _indexManager; + + public MediaMigration(IIndexManager indexManager) { + _indexManager = indexManager; + } + + public int Create() { + + _indexManager.GetSearchIndexProvider().CreateIndex("Media"); + + ContentDefinitionManager.AlterTypeDefinition("Image", cfg => cfg.WithSetting("TypeIndexing.Indexes", "Media")); + ContentDefinitionManager.AlterTypeDefinition("Video", cfg => cfg.WithSetting("TypeIndexing.Indexes", "Media")); + ContentDefinitionManager.AlterTypeDefinition("Document", cfg => cfg.WithSetting("TypeIndexing.Indexes", "Media")); + ContentDefinitionManager.AlterTypeDefinition("Audio", cfg => cfg.WithSetting("TypeIndexing.Indexes", "Media")); + ContentDefinitionManager.AlterTypeDefinition("OEmbed", cfg => cfg.WithSetting("TypeIndexing.Indexes", "Media")); + + return 1; + } + } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Search/Module.txt b/src/Orchard.Web/Modules/Orchard.Search/Module.txt index c067b79bc..eaf306260 100644 --- a/src/Orchard.Web/Modules/Orchard.Search/Module.txt +++ b/src/Orchard.Web/Modules/Orchard.Search/Module.txt @@ -22,3 +22,8 @@ Features: Description: Provides a search tab in Content Picker. Dependencies: Orchard.ContentPicker, Orchard.Search Category: Search + Orchard.Search.MediaLibrary: + Name: Media Library Search + Description: Provides search menu item in the Media Library explorer. + Dependencies: Orchard.MediaLibrary, Orchard.Search + Category: Search \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Search/Orchard.Search.csproj b/src/Orchard.Web/Modules/Orchard.Search/Orchard.Search.csproj index 36300156d..0f31f0b6f 100644 --- a/src/Orchard.Web/Modules/Orchard.Search/Orchard.Search.csproj +++ b/src/Orchard.Web/Modules/Orchard.Search/Orchard.Search.csproj @@ -62,6 +62,8 @@ + + @@ -86,6 +88,10 @@ {2D1D92BB-4555-4CBE-8D0E-63563D6CE4C6} Orchard.Framework + + {73a7688a-5bd3-4f7e-adfa-ce36c5a10e3b} + Orchard.MediaLibrary + @@ -126,6 +132,15 @@ + + + + + + + + + 10.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) diff --git a/src/Orchard.Web/Modules/Orchard.Search/Placement.info b/src/Orchard.Web/Modules/Orchard.Search/Placement.info index cbe277fdc..559f4bf95 100644 --- a/src/Orchard.Web/Modules/Orchard.Search/Placement.info +++ b/src/Orchard.Web/Modules/Orchard.Search/Placement.info @@ -1,4 +1,10 @@  + + + diff --git a/src/Orchard.Web/Modules/Orchard.Search/Views/Media/MediaItems.cshtml b/src/Orchard.Web/Modules/Orchard.Search/Views/Media/MediaItems.cshtml new file mode 100644 index 000000000..5263d9707 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Search/Views/Media/MediaItems.cshtml @@ -0,0 +1,24 @@ +@using Orchard.Utility.Extensions +@model Orchard.MediaLibrary.ViewModels.MediaManagerMediaItemsViewModel +@{ + Response.ContentType = "text/json"; + @Html.Raw(Newtonsoft.Json.JsonConvert.SerializeObject( + new { + mediaItemsCount = Model.MediaItemsCount, + mediaItems = Model.MediaItems.Select(x => new { + id = x.MediaPart.Id, + contentType = x.MediaPart.ContentItem.ContentType, + contentTypeClass = x.MediaPart.ContentItem.ContentType.HtmlClassify(), + title = x.MediaPart.Title, + alternateText = x.MediaPart.AlternateText, + caption = x.MediaPart.Caption, + resource = x.MediaPart.MediaUrl, + mimeType = x.MediaPart.MimeType, + mimeTypeClass = x.MediaPart.MimeType.HtmlClassify(), + thumbnail = Display(x.Shape).ToString(), + editLink = Url.ItemEditUrl(x.MediaPart) + }).ToArray() + })) +} + + \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Search/Views/Parts/Search.MediaLibrary.Actions.cshtml b/src/Orchard.Web/Modules/Orchard.Search/Views/Parts/Search.MediaLibrary.Actions.cshtml new file mode 100644 index 000000000..3fe4562e2 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Search/Views/Parts/Search.MediaLibrary.Actions.cshtml @@ -0,0 +1,27 @@ +Search
      + +@using (Script.Foot()) { + +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Search/Views/Parts/Search.MediaLibrary.Navigation.cshtml b/src/Orchard.Web/Modules/Orchard.Search/Views/Parts/Search.MediaLibrary.Navigation.cshtml new file mode 100644 index 000000000..db46df72c --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Search/Views/Parts/Search.MediaLibrary.Navigation.cshtml @@ -0,0 +1 @@ +
    • \ No newline at end of file diff --git a/src/Orchard.Web/Orchard.Web.csproj b/src/Orchard.Web/Orchard.Web.csproj index b4493b1bb..00f25ca2a 100644 --- a/src/Orchard.Web/Orchard.Web.csproj +++ b/src/Orchard.Web/Orchard.Web.csproj @@ -161,6 +161,7 @@ Web.config + Designer @@ -236,8 +237,7 @@ Other similar extension points exist, see Microsoft.Common.targets. --> - - + false @@ -246,14 +246,12 @@ @(RootBinFiles->'Modules\**\bin\%(Filename)%(Extension)');@(RootBinFiles->'Themes\**\%(Filename)%(Extension)');@(RootBinFiles->'Core\**\bin\%(Filename)%(Extension)');**\*.Debug.config;**\*.Release.config;**\obj\**;**\bin\*.xml;**\*.cs;**\*.csproj;Modules\**\Tests\**;Modules\**\Specs\**;Themes\bin\**;**\.hgignore;**\.hgtags;**\.hg\**;**\*.csproj.user;Properties\**\*;App_Data\Dependencies\*;App_Data\RecipeQueue\*;App_Data\Logs\*;App_Data\**\mappings.bin;App_Data\**\cache.dat;App_Data\**\hrestart.txt - - + -