mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2026-02-09 09:16:41 +08:00
#20542 Collapsible media library tree in admin.
Dynamically loading MediaLibrary directory tree using ajax and knockout templates
This commit is contained in:
committed by
Sebastien Ros
parent
ba09ba8053
commit
5d2a31ffc0
@@ -48,7 +48,6 @@ namespace Orchard.MediaLibrary.Controllers {
|
|||||||
|
|
||||||
var viewModel = new MediaManagerIndexViewModel {
|
var viewModel = new MediaManagerIndexViewModel {
|
||||||
DialogMode = dialog,
|
DialogMode = dialog,
|
||||||
Folders = _mediaLibraryService.GetMediaFolders(null).Select(GetFolderHierarchy),
|
|
||||||
FolderPath = folderPath,
|
FolderPath = folderPath,
|
||||||
MediaTypes = _mediaLibraryService.GetMediaTypes(),
|
MediaTypes = _mediaLibraryService.GetMediaTypes(),
|
||||||
CustomActionsShapes = explorerShape.Actions,
|
CustomActionsShapes = explorerShape.Actions,
|
||||||
@@ -99,6 +98,20 @@ namespace Orchard.MediaLibrary.Controllers {
|
|||||||
return View(viewModel);
|
return View(viewModel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Themed(false)]
|
||||||
|
public ActionResult ChildFolders(string folderPath = null) {
|
||||||
|
if (!Services.Authorizer.Authorize(Permissions.ManageMediaContent, T("Cannot get child folder listing")))
|
||||||
|
return new HttpUnauthorizedResult();
|
||||||
|
|
||||||
|
var childFolders = _mediaLibraryService.GetMediaFolders(folderPath);
|
||||||
|
|
||||||
|
var viewModel = new MediaManagerChildFoldersViewModel {
|
||||||
|
Children = childFolders
|
||||||
|
};
|
||||||
|
|
||||||
|
return View(viewModel);
|
||||||
|
}
|
||||||
|
|
||||||
[Themed(false)]
|
[Themed(false)]
|
||||||
public ActionResult RecentMediaItems(int skip = 0, int count = 0, string order = "created", string mediaType = "") {
|
public ActionResult RecentMediaItems(int skip = 0, int count = 0, string order = "created", string mediaType = "") {
|
||||||
var mediaParts = _mediaLibraryService.GetMediaContentItems(skip, count, order, mediaType, VersionOptions.Latest);
|
var mediaParts = _mediaLibraryService.GetMediaContentItems(skip, count, order, mediaType, VersionOptions.Latest);
|
||||||
|
|||||||
@@ -172,6 +172,7 @@
|
|||||||
<Compile Include="Settings\MediaLibraryPickerFieldEditorEvents.cs" />
|
<Compile Include="Settings\MediaLibraryPickerFieldEditorEvents.cs" />
|
||||||
<Compile Include="Settings\MediaLibraryPickerFieldSettings.cs" />
|
<Compile Include="Settings\MediaLibraryPickerFieldSettings.cs" />
|
||||||
<Compile Include="Tokens\FieldTokens.cs" />
|
<Compile Include="Tokens\FieldTokens.cs" />
|
||||||
|
<Compile Include="ViewModels\MediaManagerChildFoldersViewModel.cs" />
|
||||||
<Compile Include="ViewModels\ImportMediaViewModel.cs" />
|
<Compile Include="ViewModels\ImportMediaViewModel.cs" />
|
||||||
<Compile Include="ViewModels\MediaLibraryPickerFieldViewModel.cs" />
|
<Compile Include="ViewModels\MediaLibraryPickerFieldViewModel.cs" />
|
||||||
<Compile Include="ViewModels\MediaManagerMediaItemsViewModel.cs" />
|
<Compile Include="ViewModels\MediaManagerMediaItemsViewModel.cs" />
|
||||||
@@ -184,9 +185,6 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Content Include="Views\Admin\Index.cshtml" />
|
<Content Include="Views\Admin\Index.cshtml" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
|
||||||
<Content Include="Views\Admin\MediaManagerFolder.cshtml" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Content Include="Views\Media.cshtml" />
|
<Content Include="Views\Media.cshtml" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
@@ -345,6 +343,9 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Content Include="Views\Fields\MediaLibraryPicker.Summary.cshtml" />
|
<Content Include="Views\Fields\MediaLibraryPicker.Summary.cshtml" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Content Include="Views\Admin\ChildFolders.cshtml" />
|
||||||
|
</ItemGroup>
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
|
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
|
||||||
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
||||||
|
|||||||
@@ -81,6 +81,28 @@ $(function () {
|
|||||||
self.orderMedia = ko.observableArray(['created']);
|
self.orderMedia = ko.observableArray(['created']);
|
||||||
self.mediaType = ko.observableArray([]);
|
self.mediaType = ko.observableArray([]);
|
||||||
|
|
||||||
|
self.mediaFolders = ko.observableArray([]);
|
||||||
|
|
||||||
|
(function () {
|
||||||
|
var getChildFolderListUrl = function (f) {
|
||||||
|
return settings.childFolderListingActionUrl + '?folderPath=' + encodeURIComponent(f);
|
||||||
|
};
|
||||||
|
var url = getChildFolderListUrl(settings.folderPath);
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
type: "GET",
|
||||||
|
url: url,
|
||||||
|
cache: false
|
||||||
|
}).done(function (data) {
|
||||||
|
var childFolders = data.childFolders;
|
||||||
|
for (var x = 0; x < childFolders.length; x++) {
|
||||||
|
self.mediaFolders.push(new mediaFolderViewModel(childFolders[x]));
|
||||||
|
}
|
||||||
|
}).fail(function (data) {
|
||||||
|
console.error(data);
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
|
||||||
self.getMediaItems = function (count, append) {
|
self.getMediaItems = function (count, append) {
|
||||||
var folderPath = self.displayed() || '';
|
var folderPath = self.displayed() || '';
|
||||||
|
|
||||||
@@ -164,7 +186,6 @@ $(function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
self.displayFolder = function(folderPath) {
|
self.displayFolder = function(folderPath) {
|
||||||
|
|
||||||
self.results([]);
|
self.results([]);
|
||||||
self.displayed(folderPath);
|
self.displayed(folderPath);
|
||||||
|
|
||||||
@@ -175,7 +196,7 @@ $(function () {
|
|||||||
self.getMediaItems(pageCount);
|
self.getMediaItems(pageCount);
|
||||||
};
|
};
|
||||||
|
|
||||||
self.selectFolder = function(folderPath) {
|
self.selectFolder = function (folderPath) {
|
||||||
History.pushState({ action: 'displayFolder', folderPath: folderPath }, '', '?folderPath=' + folderPath);
|
History.pushState({ action: 'displayFolder', folderPath: folderPath }, '', '?folderPath=' + folderPath);
|
||||||
self.displayFolder(folderPath);
|
self.displayFolder(folderPath);
|
||||||
};
|
};
|
||||||
@@ -242,6 +263,73 @@ $(function () {
|
|||||||
|
|
||||||
var viewModel = new mediaIndexViewModel();
|
var viewModel = new mediaIndexViewModel();
|
||||||
|
|
||||||
|
function mediaFolderViewModel(data) {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
self.mediaIndexViewModel = viewModel;
|
||||||
|
|
||||||
|
self.folderPath = ko.observable(data.folderPath);
|
||||||
|
|
||||||
|
self.name = ko.observable(data.name);
|
||||||
|
|
||||||
|
self.childFolders = ko.observableArray([]);
|
||||||
|
|
||||||
|
self.childFoldersFetchStatus = 0; //0 = unfetched, 1 = fetching, 2 = fetched
|
||||||
|
|
||||||
|
self.isExpanded = ko.observable(false);
|
||||||
|
self.isVisible = ko.observable(true);
|
||||||
|
|
||||||
|
self.isSelected = ko.computed(function() {
|
||||||
|
return (self.mediaIndexViewModel.displayed() == self.folderPath());
|
||||||
|
});
|
||||||
|
|
||||||
|
self.folderClicked = function () {
|
||||||
|
self.mediaIndexViewModel.selectFolder(self.folderPath());
|
||||||
|
|
||||||
|
var childFolders = self.childFolders();
|
||||||
|
|
||||||
|
if (self.isExpanded()) {
|
||||||
|
for (var x = 0; x < childFolders.length; x++) {
|
||||||
|
childFolders[x].isVisible(false);
|
||||||
|
}
|
||||||
|
self.isExpanded(false);
|
||||||
|
} else {
|
||||||
|
if (self.childFoldersFetchStatus !== 0) {
|
||||||
|
for (var x = 0; x < childFolders.length; x++) {
|
||||||
|
childFolders[x].isVisible(true);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.childFoldersFetchStatus = 1;
|
||||||
|
var getChildFolderListUrl = function (f) {
|
||||||
|
return settings.childFolderListingActionUrl + '?folderPath=' + encodeURIComponent(f);
|
||||||
|
};
|
||||||
|
var url = getChildFolderListUrl(self.folderPath());
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
type: "GET",
|
||||||
|
url: url,
|
||||||
|
cache: false
|
||||||
|
}).done(function (data) {
|
||||||
|
var newChildFolders = data.childFolders;
|
||||||
|
for (var y = 0; y < newChildFolders.length; y++) {
|
||||||
|
var newChildFolder = new mediaFolderViewModel(newChildFolders[y]);
|
||||||
|
newChildFolder.isVisible(true);
|
||||||
|
self.childFolders.push(newChildFolder);
|
||||||
|
}
|
||||||
|
self.childFoldersFetchStatus = 2;
|
||||||
|
}).fail(function (data) {
|
||||||
|
console.error(data);
|
||||||
|
self.childFoldersFetchStatus = 0;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
self.isExpanded(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
enhanceViewModel(viewModel);
|
enhanceViewModel(viewModel);
|
||||||
|
|
||||||
ko.applyBindings(viewModel);
|
ko.applyBindings(viewModel);
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using Orchard.MediaLibrary.Models;
|
||||||
|
|
||||||
|
namespace Orchard.MediaLibrary.ViewModels {
|
||||||
|
public class MediaManagerChildFoldersViewModel {
|
||||||
|
public IEnumerable<MediaFolder> Children { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,7 +4,6 @@ using Orchard.MediaLibrary.Models;
|
|||||||
|
|
||||||
namespace Orchard.MediaLibrary.ViewModels {
|
namespace Orchard.MediaLibrary.ViewModels {
|
||||||
public class MediaManagerIndexViewModel {
|
public class MediaManagerIndexViewModel {
|
||||||
public IEnumerable<FolderHierarchy> Folders { get; set; }
|
|
||||||
public string FolderPath { get; set; }
|
public string FolderPath { get; set; }
|
||||||
public bool DialogMode { get; set; }
|
public bool DialogMode { get; set; }
|
||||||
public IEnumerable<ContentTypeDefinition> MediaTypes { get; set; }
|
public IEnumerable<ContentTypeDefinition> MediaTypes { get; set; }
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
@using Orchard.Utility.Extensions
|
||||||
|
@model Orchard.MediaLibrary.ViewModels.MediaManagerChildFoldersViewModel
|
||||||
|
@{
|
||||||
|
Response.ContentType = "text/json";
|
||||||
|
@Html.Raw(Newtonsoft.Json.JsonConvert.SerializeObject(
|
||||||
|
new {
|
||||||
|
childFolders = Model.Children.Select(x => new {
|
||||||
|
folderPath = x.MediaPath,
|
||||||
|
name = x.Name,
|
||||||
|
lastUpdated = x.LastUpdated
|
||||||
|
}).ToArray()
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -30,12 +30,7 @@
|
|||||||
@Display(Model.CustomNavigationShapes)
|
@Display(Model.CustomNavigationShapes)
|
||||||
|
|
||||||
<li id="media-library-main-navigation-tree">
|
<li id="media-library-main-navigation-tree">
|
||||||
<ul>
|
<ul data-bind="template: { name: 'media-folder-template', foreach: mediaFolders }">
|
||||||
@foreach (var folder in viewModel.Folders) {
|
|
||||||
<li>
|
|
||||||
@Display.Partial(TemplateName: "MediaManagerFolder", Model: folder)
|
|
||||||
</li>
|
|
||||||
}
|
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
@@ -95,6 +90,7 @@ var mediaLibrarySettings = {
|
|||||||
mediaItemActionUrl: '@HttpUtility.JavaScriptStringEncode(Url.Action("MediaItem", "Admin"))',
|
mediaItemActionUrl: '@HttpUtility.JavaScriptStringEncode(Url.Action("MediaItem", "Admin"))',
|
||||||
mediaItemsActionUrl: '@HttpUtility.JavaScriptStringEncode(Url.Action("MediaItems", "Admin"))',
|
mediaItemsActionUrl: '@HttpUtility.JavaScriptStringEncode(Url.Action("MediaItems", "Admin"))',
|
||||||
recentMediaItemsActionUrl: '@HttpUtility.JavaScriptStringEncode(Url.Action("RecentMediaItems", "Admin"))',
|
recentMediaItemsActionUrl: '@HttpUtility.JavaScriptStringEncode(Url.Action("RecentMediaItems", "Admin"))',
|
||||||
|
childFolderListingActionUrl: '@HttpUtility.JavaScriptStringEncode(Url.Action("ChildFolders", "Admin"))',
|
||||||
importActionUrl: '@HttpUtility.JavaScriptStringEncode(Url.Action("Import", "Admin"))',
|
importActionUrl: '@HttpUtility.JavaScriptStringEncode(Url.Action("Import", "Admin"))',
|
||||||
moveActionUrl: '@Url.Action("Move", "Folder", new {area = "Orchard.MediaLibrary"})',
|
moveActionUrl: '@Url.Action("Move", "Folder", new {area = "Orchard.MediaLibrary"})',
|
||||||
deleteActionUrl: '@Url.Action("Delete", "Admin", new {area = "Orchard.MediaLibrary"})',
|
deleteActionUrl: '@Url.Action("Delete", "Admin", new {area = "Orchard.MediaLibrary"})',
|
||||||
@@ -106,4 +102,15 @@ var mediaLibrarySettings = {
|
|||||||
};
|
};
|
||||||
//]]>
|
//]]>
|
||||||
</script>
|
</script>
|
||||||
|
<script type="text/html" id="media-folder-template">
|
||||||
|
<li data-bind="visible: isVisible()">
|
||||||
|
<div class="media-library-folder">
|
||||||
|
<div class="media-library-folder-title" data-bind="click: folderClicked, css: { selected: isSelected() }">
|
||||||
|
<a data-bind="disable: $root.pendingRequest" href="#" class="media-library-navigation-folder-link"><i data-bind="css: {'icon-folder-open-alt': isExpanded(), 'icon-folder-close-alt': !isExpanded()}"></i><span data-bind="text: name"></span></a>
|
||||||
|
</div>
|
||||||
|
<ul data-bind="template: { name: 'media-folder-template', foreach: childFolders }, visible: childFolders().length > 0">
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</script>
|
||||||
}
|
}
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
@model Orchard.MediaLibrary.Models.FolderHierarchy
|
|
||||||
|
|
||||||
<div class="media-library-folder">
|
|
||||||
<div class="media-library-folder-title" data-bind="click: function(data, event) { selectFolder('@HttpUtility.JavaScriptStringEncode(Model.Root.MediaPath)'); }, css: { selected: displayed() == $element.getAttribute('data-media-path') }" data-media-path="@Model.Root.MediaPath" >
|
|
||||||
<a data-bind="disable: $root.pendingRequest" href="#" class="media-library-navigation-folder-link" data-mediapath="@Model.Root.MediaPath"><i class="icon-folder-close-alt"></i>@Model.Root.Name</a>
|
|
||||||
</div>
|
|
||||||
@if (Model.Children.Any()) {
|
|
||||||
<ul>
|
|
||||||
@foreach (var folder in Model.Children) {
|
|
||||||
<li>
|
|
||||||
@Display.Partial(TemplateName: "MediaManagerFolder", Model: folder)
|
|
||||||
</li>
|
|
||||||
}
|
|
||||||
</ul>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
Reference in New Issue
Block a user