mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2025-10-14 10:54:50 +08:00
Implementing shim and cache for theme awareness
Configured arrays of view engines cached for use in appropriate contexts Adding current theme as dedicated property on work context Current theme assigned by selecters, if null, as result begins executing Distinction is made between deep and shallow view path locations --HG-- branch : theming
This commit is contained in:
@@ -24,6 +24,7 @@ using Orchard.Mvc.ModelBinders;
|
||||
using Orchard.Mvc.Routes;
|
||||
using Orchard.Mvc.ViewEngines;
|
||||
using Orchard.Mvc.ViewEngines.Razor;
|
||||
using Orchard.Mvc.ViewEngines.ThemeAwareness;
|
||||
using Orchard.Mvc.ViewEngines.WebForms;
|
||||
using Orchard.Settings;
|
||||
using Orchard.Setup.Commands;
|
||||
@@ -44,7 +45,7 @@ namespace Orchard.Setup {
|
||||
builder.RegisterType<ModelBinderPublisher>().As<IModelBinderPublisher>().InstancePerLifetimeScope();
|
||||
builder.RegisterType<WebFormViewEngineProvider>().As<IViewEngineProvider>().InstancePerLifetimeScope();
|
||||
builder.RegisterType<RazorViewEngineProvider>().As<IViewEngineProvider>().InstancePerLifetimeScope();
|
||||
builder.RegisterType<ViewEngineFilter>().As<IFilterProvider>().InstancePerLifetimeScope();
|
||||
builder.RegisterType<CurrentThemeFilter>().As<IFilterProvider>().InstancePerLifetimeScope();
|
||||
builder.RegisterType<ThemeFilter>().As<IFilterProvider>().InstancePerLifetimeScope();
|
||||
builder.RegisterType<PageTitleBuilder>().As<IPageTitleBuilder>().InstancePerLifetimeScope();
|
||||
builder.RegisterType<ZoneManager>().As<IZoneManager>().InstancePerLifetimeScope();
|
||||
@@ -69,7 +70,11 @@ namespace Orchard.Setup {
|
||||
builder.RegisterType<DefaultDisplayManager>().As<IDisplayManager>();
|
||||
builder.RegisterType<DefaultShapeFactory>().As<IShapeFactory>();
|
||||
builder.RegisterType<ShapeHelperFactory>().As<IShapeHelperFactory>();
|
||||
builder.RegisterType<DefaultShapeTableManager>().As<IShapeTableManager>();
|
||||
builder.RegisterType<DefaultShapeTableManager>().As<IShapeTableManager>();
|
||||
|
||||
builder.RegisterType<ThemeAwareViewEngine>().As<IThemeAwareViewEngine>();
|
||||
builder.RegisterType<ConfiguredEnginesCache>().As<IConfiguredEnginesCache>();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@@ -58,9 +58,6 @@ namespace Orchard.Environment {
|
||||
|
||||
void IOrchardHost.Initialize() {
|
||||
Logger.Information("Initializing");
|
||||
ViewEngines.Engines.Insert(0, LayoutViewEngine.CreateShim());
|
||||
|
||||
|
||||
BuildCurrent();
|
||||
}
|
||||
|
||||
|
@@ -23,6 +23,7 @@ using Orchard.FileSystems.VirtualPath;
|
||||
using Orchard.FileSystems.WebSite;
|
||||
using Orchard.Logging;
|
||||
using Orchard.Mvc;
|
||||
using Orchard.Mvc.ViewEngines.ThemeAwareness;
|
||||
using Orchard.Services;
|
||||
|
||||
namespace Orchard.Environment {
|
||||
@@ -117,6 +118,8 @@ namespace Orchard.Environment {
|
||||
}
|
||||
|
||||
ControllerBuilder.Current.SetControllerFactory(new OrchardControllerFactory());
|
||||
ViewEngines.Engines.Clear();
|
||||
ViewEngines.Engines.Add(new ThemeArareViewEngineShim());
|
||||
|
||||
var hostContainer = new DefaultOrchardHostContainer(container);
|
||||
//MvcServiceLocator.SetCurrent(hostContainer);
|
||||
|
@@ -10,8 +10,13 @@ namespace Orchard.Mvc.ViewEngines {
|
||||
public IEnumerable<string> VirtualPaths { get; set; }
|
||||
}
|
||||
|
||||
public interface IViewEngineProvider : IDependency {
|
||||
public interface IViewEngineProvider : ISingletonDependency {
|
||||
IViewEngine CreateThemeViewEngine(CreateThemeViewEngineParams parameters);
|
||||
IViewEngine CreateModulesViewEngine(CreateModulesViewEngineParams parameters);
|
||||
|
||||
/// <summary>
|
||||
/// Produce a view engine configured to resolve only fully qualified {viewName} parameters
|
||||
/// </summary>
|
||||
IViewEngine CreateBareViewEngine();
|
||||
}
|
||||
}
|
||||
|
@@ -91,6 +91,17 @@ namespace Orchard.Mvc.ViewEngines.Razor {
|
||||
return viewEngine;
|
||||
}
|
||||
|
||||
public IViewEngine CreateBareViewEngine() {
|
||||
return new CshtmlViewEngine {
|
||||
MasterLocationFormats = DisabledFormats,
|
||||
ViewLocationFormats = DisabledFormats,
|
||||
PartialViewLocationFormats = DisabledFormats,
|
||||
AreaMasterLocationFormats = DisabledFormats,
|
||||
AreaViewLocationFormats = DisabledFormats,
|
||||
AreaPartialViewLocationFormats = DisabledFormats,
|
||||
};
|
||||
}
|
||||
|
||||
public IEnumerable<string> DetectTemplateFileNames(string virtualPath) {
|
||||
var fileNames = _virtualPathProvider.ListFiles(virtualPath).Select(Path.GetFileName);
|
||||
foreach (var fileName in fileNames) {
|
||||
|
@@ -0,0 +1,33 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Web.Mvc;
|
||||
|
||||
namespace Orchard.Mvc.ViewEngines.ThemeAwareness {
|
||||
public interface IConfiguredEnginesCache : ISingletonDependency {
|
||||
IViewEngine BindBareEngines(Func<IViewEngine> factory);
|
||||
IViewEngine BindShallowEngines(string themeName, Func<IViewEngine> factory);
|
||||
IViewEngine BindDeepEngines(string themeName, Func<IViewEngine> factory);
|
||||
}
|
||||
|
||||
public class ConfiguredEnginesCache : IConfiguredEnginesCache {
|
||||
IViewEngine _bare = null;
|
||||
readonly ConcurrentDictionary<string, IViewEngine> _shallow = new ConcurrentDictionary<string, IViewEngine>();
|
||||
readonly ConcurrentDictionary<string, IViewEngine> _deep = new ConcurrentDictionary<string, IViewEngine>();
|
||||
|
||||
public ConfiguredEnginesCache() {
|
||||
_shallow = new ConcurrentDictionary<string, IViewEngine>();
|
||||
}
|
||||
|
||||
public IViewEngine BindBareEngines(Func<IViewEngine> factory) {
|
||||
return _bare ?? (_bare = factory());
|
||||
}
|
||||
|
||||
public IViewEngine BindShallowEngines(string themeName, Func<IViewEngine> factory) {
|
||||
return _shallow.GetOrAdd(themeName, key => factory());
|
||||
}
|
||||
|
||||
public IViewEngine BindDeepEngines(string themeName, Func<IViewEngine> factory) {
|
||||
return _deep.GetOrAdd(themeName, key => factory());
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,35 +1,27 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Web.Mvc;
|
||||
using Orchard.Environment.Extensions;
|
||||
using Orchard.Logging;
|
||||
using Orchard.Mvc.Filters;
|
||||
using Orchard.Themes;
|
||||
|
||||
namespace Orchard.Mvc.ViewEngines {
|
||||
namespace Orchard.Mvc.ViewEngines.ThemeAwareness {
|
||||
|
||||
public class ViewEngineFilter : FilterProvider, IResultFilter {
|
||||
private readonly ViewEngineCollection _viewEngines;
|
||||
public class CurrentThemeFilter : FilterProvider, IResultFilter {
|
||||
private readonly IThemeService _themeService;
|
||||
private readonly IExtensionManager _extensionManager;
|
||||
private readonly IEnumerable<IViewEngineProvider> _viewEngineProviders;
|
||||
private readonly WorkContext _workContext;
|
||||
|
||||
public ViewEngineFilter(
|
||||
ViewEngineCollection viewEngines,
|
||||
IThemeService themeService,
|
||||
IExtensionManager extensionManager,
|
||||
IEnumerable<IViewEngineProvider> viewEngineProviders) {
|
||||
_viewEngines = viewEngines;
|
||||
public CurrentThemeFilter(IThemeService themeService, WorkContext workContext) {
|
||||
_themeService = themeService;
|
||||
_extensionManager = extensionManager;
|
||||
_viewEngineProviders = viewEngineProviders;
|
||||
_workContext = workContext;
|
||||
Logger = NullLogger.Instance;
|
||||
}
|
||||
|
||||
public ILogger Logger { get; set; }
|
||||
|
||||
public void OnResultExecuting(ResultExecutingContext filterContext) {
|
||||
if (_workContext.CurrentTheme == null) {
|
||||
_workContext.CurrentTheme = _themeService.GetRequestTheme(filterContext.RequestContext);
|
||||
}
|
||||
#if REFACTORING
|
||||
var viewResultBase = filterContext.Result as ViewResultBase;
|
||||
if (viewResultBase == null) {
|
||||
return;
|
||||
@@ -70,14 +62,7 @@ namespace Orchard.Mvc.ViewEngines {
|
||||
|
||||
viewResultBase.ViewEngineCollection = new ViewEngineCollection(_viewEngines.ToList());
|
||||
viewResultBase.ViewEngineCollection.Insert(0, layoutViewEngine);
|
||||
}
|
||||
|
||||
static bool ViewEngineIsForwarded(IViewEngine x) {
|
||||
// default view engine, and layout view engine, are not forwarded to
|
||||
// be used for resolving partials
|
||||
return
|
||||
x.GetType().Assembly != typeof(LayoutViewEngine).Assembly &&
|
||||
x.GetType() != typeof(WebFormViewEngine);
|
||||
#endif
|
||||
}
|
||||
|
||||
public void OnResultExecuted(ResultExecutedContext filterContext) {
|
@@ -0,0 +1,87 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web.Mvc;
|
||||
using Orchard.Environment.Descriptor.Models;
|
||||
using Orchard.Environment.Extensions;
|
||||
using Orchard.Themes;
|
||||
|
||||
namespace Orchard.Mvc.ViewEngines.ThemeAwareness {
|
||||
public interface IThemeAwareViewEngine : IDependency, IViewEngine {
|
||||
}
|
||||
|
||||
public class ThemeAwareViewEngine : IThemeAwareViewEngine {
|
||||
private readonly WorkContext _workContext;
|
||||
private readonly IEnumerable<IViewEngineProvider> _viewEngineProviders;
|
||||
private readonly IConfiguredEnginesCache _configuredEnginesCache;
|
||||
private readonly IExtensionManager _extensionManager;
|
||||
private readonly ShellDescriptor _shellDescriptor;
|
||||
private readonly IViewEngine _nullEngines = new ViewEngineCollectionWrapper(Enumerable.Empty<IViewEngine>());
|
||||
|
||||
public ThemeAwareViewEngine(
|
||||
WorkContext workContext,
|
||||
IEnumerable<IViewEngineProvider> viewEngineProviders,
|
||||
IConfiguredEnginesCache configuredEnginesCache,
|
||||
IExtensionManager extensionManager,
|
||||
ShellDescriptor shellDescriptor) {
|
||||
_workContext = workContext;
|
||||
_viewEngineProviders = viewEngineProviders;
|
||||
_configuredEnginesCache = configuredEnginesCache;
|
||||
_extensionManager = extensionManager;
|
||||
_shellDescriptor = shellDescriptor;
|
||||
}
|
||||
|
||||
public ViewEngineResult FindPartialView(ControllerContext controllerContext, string partialViewName, bool useCache) {
|
||||
IViewEngine engines = _nullEngines;
|
||||
|
||||
if (partialViewName.StartsWith("/") || partialViewName.StartsWith("~")) {
|
||||
engines = BareEngines();
|
||||
}
|
||||
else if (_workContext.CurrentTheme != null) {
|
||||
if (controllerContext is ViewContext) {
|
||||
engines = ShallowEngines(_workContext.CurrentTheme);
|
||||
}
|
||||
else {
|
||||
engines = DeepEngines(_workContext.CurrentTheme);
|
||||
}
|
||||
}
|
||||
|
||||
return engines.FindPartialView(controllerContext, partialViewName, useCache);
|
||||
}
|
||||
|
||||
private IViewEngine BareEngines() {
|
||||
return _configuredEnginesCache.BindBareEngines(() => new ViewEngineCollectionWrapper(_viewEngineProviders.Select(vep => vep.CreateBareViewEngine())));
|
||||
}
|
||||
|
||||
private IViewEngine ShallowEngines(ITheme theme) {
|
||||
//return _configuredEnginesCache.BindShallowEngines(theme.ThemeName, () => new ViewEngineCollectionWrapper(_viewEngineProviders.Select(vep => vep.CreateBareViewEngine())));
|
||||
return DeepEngines(theme);
|
||||
}
|
||||
|
||||
private IViewEngine DeepEngines(ITheme theme) {
|
||||
return _configuredEnginesCache.BindDeepEngines(theme.ThemeName, () => {
|
||||
var engines = Enumerable.Empty<IViewEngine>();
|
||||
var themeLocation = _extensionManager.GetThemeLocation(theme);
|
||||
|
||||
var themeParams = new CreateThemeViewEngineParams { VirtualPath = themeLocation };
|
||||
engines = engines.Concat(_viewEngineProviders.Select(vep => vep.CreateThemeViewEngine(themeParams)));
|
||||
|
||||
var activeFeatures = _extensionManager.AvailableFeatures().Where(fd => _shellDescriptor.Features.Any(sdf => sdf.Name == fd.Name));
|
||||
var activeModuleLocations = activeFeatures.Select(fd => fd.Extension.Location + "/" + fd.Extension.Name).Distinct();
|
||||
var moduleParams = new CreateModulesViewEngineParams { VirtualPaths = activeModuleLocations };
|
||||
engines = engines.Concat(_viewEngineProviders.Select(vep => vep.CreateModulesViewEngine(moduleParams)));
|
||||
|
||||
return new ViewEngineCollectionWrapper(engines);
|
||||
});
|
||||
}
|
||||
|
||||
public ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache) {
|
||||
return FindPartialView(controllerContext, viewName, useCache);
|
||||
}
|
||||
|
||||
public void ReleaseView(ControllerContext controllerContext, IView view) {
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,47 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Web.Mvc;
|
||||
using Orchard.Environment;
|
||||
|
||||
namespace Orchard.Mvc.ViewEngines.ThemeAwareness {
|
||||
public class ThemeArareViewEngineShim : IViewEngine, IShim {
|
||||
public ThemeArareViewEngineShim() {
|
||||
OrchardHostContainerRegistry.RegisterShim(this);
|
||||
}
|
||||
|
||||
public IOrchardHostContainer HostContainer { get; set; }
|
||||
|
||||
public ViewEngineResult FindPartialView(ControllerContext controllerContext, string partialViewName, bool useCache) {
|
||||
return Forward(
|
||||
controllerContext,
|
||||
dve => dve.FindPartialView(controllerContext, partialViewName, useCache),
|
||||
EmptyViewEngineResult);
|
||||
}
|
||||
|
||||
public ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache) {
|
||||
return Forward(
|
||||
controllerContext,
|
||||
dve => dve.FindView(controllerContext, viewName, masterName, useCache),
|
||||
EmptyViewEngineResult);
|
||||
}
|
||||
|
||||
public void ReleaseView(ControllerContext controllerContext, IView view) {
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
static TResult Forward<TResult>(ControllerContext controllerContext, Func<IThemeAwareViewEngine, TResult> forwardAction, Func<TResult> defaultAction) {
|
||||
var workContext = controllerContext.GetWorkContext();
|
||||
if (workContext != null) {
|
||||
var displayViewEngine = workContext.Resolve<IThemeAwareViewEngine>();
|
||||
if (displayViewEngine != null) {
|
||||
return forwardAction(displayViewEngine);
|
||||
}
|
||||
}
|
||||
return defaultAction();
|
||||
}
|
||||
|
||||
static ViewEngineResult EmptyViewEngineResult() {
|
||||
return new ViewEngineResult(Enumerable.Empty<string>());
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,42 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web.Mvc;
|
||||
|
||||
namespace Orchard.Mvc.ViewEngines.ThemeAwareness {
|
||||
public class ViewEngineCollectionWrapper : IViewEngine {
|
||||
private readonly IEnumerable<IViewEngine> _engines;
|
||||
|
||||
public ViewEngineCollectionWrapper(IEnumerable<IViewEngine> engines) {
|
||||
_engines = engines.ToArray();
|
||||
}
|
||||
|
||||
public ViewEngineResult FindPartialView(ControllerContext controllerContext, string partialViewName, bool useCache) {
|
||||
var searchedLocations = Enumerable.Empty<string>();
|
||||
foreach (var engine in _engines) {
|
||||
var result = engine.FindPartialView(controllerContext, partialViewName, useCache);
|
||||
if (result.View != null)
|
||||
return result;
|
||||
if (!useCache)
|
||||
searchedLocations = searchedLocations.Concat(result.SearchedLocations);
|
||||
}
|
||||
return new ViewEngineResult(searchedLocations.Distinct());
|
||||
}
|
||||
|
||||
public ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache) {
|
||||
var searchedLocations = Enumerable.Empty<string>();
|
||||
foreach (var engine in _engines) {
|
||||
var result = engine.FindView(controllerContext, viewName, masterName, useCache);
|
||||
if (result.View != null)
|
||||
return result;
|
||||
if (!useCache)
|
||||
searchedLocations = searchedLocations.Concat(result.SearchedLocations);
|
||||
}
|
||||
return new ViewEngineResult(searchedLocations.Distinct());
|
||||
}
|
||||
|
||||
public void ReleaseView(ControllerContext controllerContext, IView view) {
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,4 +1,5 @@
|
||||
using System.Linq;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Web.Mvc;
|
||||
using Orchard.Logging;
|
||||
|
||||
@@ -85,5 +86,17 @@ namespace Orchard.Mvc.ViewEngines.WebForms {
|
||||
|
||||
return viewEngine;
|
||||
}
|
||||
|
||||
|
||||
public IViewEngine CreateBareViewEngine() {
|
||||
return new WebFormViewEngineForAspNet4 {
|
||||
MasterLocationFormats = DisabledFormats,
|
||||
ViewLocationFormats = DisabledFormats,
|
||||
PartialViewLocationFormats = DisabledFormats,
|
||||
AreaMasterLocationFormats = DisabledFormats,
|
||||
AreaViewLocationFormats = DisabledFormats,
|
||||
AreaPartialViewLocationFormats = DisabledFormats,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -139,6 +139,10 @@
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Mvc\ViewEngines\ThemeAwareness\ConfiguredEnginesCache.cs" />
|
||||
<Compile Include="Mvc\ViewEngines\ThemeAwareness\ThemeAwareViewEngine.cs" />
|
||||
<Compile Include="Mvc\ViewEngines\ThemeAwareness\ThemeAwareViewEngineShim.cs" />
|
||||
<Compile Include="Mvc\ViewEngines\ThemeAwareness\ViewEngineCollectionWrapper.cs" />
|
||||
<Compile Include="Mvc\ViewModels\BaseViewModel.cs" />
|
||||
<Compile Include="Caching\Signals.cs" />
|
||||
<Compile Include="Collections\IPageOfItems.cs" />
|
||||
@@ -716,7 +720,7 @@
|
||||
<Compile Include="Mvc\ViewEngines\LayoutView.cs" />
|
||||
<Compile Include="Mvc\ViewEngines\LayoutViewEngine.cs" />
|
||||
<Compile Include="Mvc\ViewEngines\LayoutViewContext.cs" />
|
||||
<Compile Include="Mvc\ViewEngines\ViewEngineFilter.cs" />
|
||||
<Compile Include="Mvc\ViewEngines\ThemeAwareness\CurrentTheme.cs" />
|
||||
<Compile Include="Mvc\ViewEngines\WebForms\WebFormViewEngineProvider.cs" />
|
||||
<Compile Include="UI\Admin\AdminThemeSelector.cs" />
|
||||
<Compile Include="UI\Navigation\INavigationManager.cs" />
|
||||
|
@@ -3,6 +3,7 @@ using System.Web;
|
||||
using Autofac;
|
||||
using Orchard.Security;
|
||||
using Orchard.Settings;
|
||||
using Orchard.Themes;
|
||||
using Orchard.UI;
|
||||
|
||||
namespace Orchard {
|
||||
@@ -20,6 +21,8 @@ namespace Orchard {
|
||||
get { return State<IUser>(); }
|
||||
}
|
||||
|
||||
public ITheme CurrentTheme { get; set; }
|
||||
|
||||
public abstract T Resolve<T>();
|
||||
public abstract T State<T>();
|
||||
}
|
||||
|
Reference in New Issue
Block a user