Merge - potentially bad merges in a place or two

--HG--
branch : composition
This commit is contained in:
Louis DeJardin
2010-10-12 17:43:49 -07:00
60 changed files with 863 additions and 471 deletions

View File

@@ -17,8 +17,10 @@ using Orchard.DisplayManagement;
using Orchard.DisplayManagement.Descriptors;
using Orchard.DisplayManagement.Implementation;
using Orchard.Environment;
using Orchard.Environment.Extensions;
using Orchard.Security;
using Orchard.Tests.Modules;
using Orchard.Tests.Stubs;
using Orchard.UI.Notify;
namespace Orchard.Core.Tests.Body {
@@ -41,6 +43,7 @@ namespace Orchard.Core.Tests.Body {
builder.RegisterType<DefaultContentQuery>().As<IContentQuery>();
builder.RegisterType<BodyPartHandler>().As<IContentHandler>();
builder.RegisterType<StubExtensionManager>().As<IExtensionManager>();
}
[Test]

View File

@@ -20,12 +20,14 @@ using Orchard.Core.Scheduling.Services;
using Orchard.DisplayManagement;
using Orchard.DisplayManagement.Descriptors;
using Orchard.DisplayManagement.Implementation;
using Orchard.Environment.Extensions;
using Orchard.Localization;
using Orchard.Security;
using Orchard.Tasks.Scheduling;
using Orchard.Tests.Modules;
using Orchard.Core.Common.ViewModels;
using System.Web.Mvc;
using Orchard.Tests.Stubs;
namespace Orchard.Core.Tests.Common.Providers {
[TestFixture]
@@ -46,6 +48,7 @@ namespace Orchard.Core.Tests.Common.Providers {
builder.RegisterType<DefaultShapeTableManager>().As<IShapeTableManager>();
builder.RegisterType<DefaultShapeFactory>().As<IShapeFactory>();
builder.RegisterType<ShapeHelperFactory>().As<IShapeHelperFactory>();
builder.RegisterType<StubExtensionManager>().As<IExtensionManager>();
_authn = new Mock<IAuthenticationService>();
_authz = new Mock<IAuthorizationService>();
@@ -81,7 +84,7 @@ namespace Orchard.Core.Tests.Common.Providers {
}
class TestUser : ContentPart, IUser {
public int Id { get { return 6655321; } }
public new int Id { get { return 6655321; } }
public string UserName {get { return "x"; }}
public string Email { get { return "y"; } }
}

View File

@@ -20,6 +20,7 @@ using Orchard.DisplayManagement;
using Orchard.DisplayManagement.Descriptors;
using Orchard.DisplayManagement.Implementation;
using Orchard.Environment;
using Orchard.Environment.Extensions;
using Orchard.Security;
using Orchard.Tests.Modules;
using System.Web.Mvc;
@@ -56,6 +57,8 @@ namespace Orchard.Core.Tests.Routable.Services {
builder.RegisterType<DefaultContentQuery>().As<IContentQuery>();
builder.RegisterInstance(new UrlHelper(new RequestContext(new StubHttpContext("~/"), new RouteData()))).As<UrlHelper>();
builder.RegisterType<RoutePartHandler>().As<IContentHandler>();
builder.RegisterType<StubExtensionManager>().As<IExtensionManager>();
}
private IRoutableService _routableService;

View File

@@ -12,9 +12,11 @@ using Orchard.Data;
using Orchard.DisplayManagement;
using Orchard.DisplayManagement.Descriptors;
using Orchard.DisplayManagement.Implementation;
using Orchard.Environment.Extensions;
using Orchard.Tasks;
using Orchard.Tasks.Scheduling;
using Orchard.Tests.Modules;
using Orchard.Tests.Stubs;
namespace Orchard.Core.Tests.Scheduling {
[TestFixture]
@@ -40,6 +42,8 @@ namespace Orchard.Core.Tests.Scheduling {
builder.RegisterType<ScheduledTaskExecutor>().As<IBackgroundTask>().Named("ScheduledTaskExecutor", typeof(IBackgroundTask));
builder.RegisterInstance(_handler).As<IScheduledTaskHandler>();
builder.RegisterType<StubExtensionManager>().As<IExtensionManager>();
}
protected override IEnumerable<Type> DatabaseTypes {

View File

@@ -13,8 +13,10 @@ using Orchard.Data;
using Orchard.DisplayManagement;
using Orchard.DisplayManagement.Descriptors;
using Orchard.DisplayManagement.Implementation;
using Orchard.Environment.Extensions;
using Orchard.Tasks.Scheduling;
using Orchard.Tests.Modules;
using Orchard.Tests.Stubs;
namespace Orchard.Core.Tests.Scheduling {
[TestFixture]
@@ -43,6 +45,8 @@ namespace Orchard.Core.Tests.Scheduling {
builder.RegisterInstance(new Mock<IContentDefinitionManager>().Object);
builder.RegisterType<ScheduledTaskManager>().As<IScheduledTaskManager>();
builder.RegisterType<StubExtensionManager>().As<IExtensionManager>();
}
protected override IEnumerable<Type> DatabaseTypes {

View File

@@ -68,6 +68,7 @@ namespace Orchard.Tests.Modules.Themes.Services {
var context = new DynamicProxyContext();
var builder = new ContainerBuilder();
builder.RegisterModule(new SettingsModule());
builder.RegisterType<StubWorkContextAccessor>().As<IWorkContextAccessor>();
builder.RegisterType<ThemeService>().EnableDynamicProxy(context).As<IThemeService>();
builder.RegisterType<SettingsModuleInterceptor>().As<ISettingsModuleInterceptor>();
builder.RegisterType<SiteService>().As<ISiteService>();
@@ -85,7 +86,7 @@ namespace Orchard.Tests.Modules.Themes.Services {
builder.RegisterType<ThemeSiteSettingsPartHandler>().As<IContentHandler>();
builder.RegisterType<ModuleService>().As<IModuleService>();
builder.RegisterType<OrchardServices>().As<IOrchardServices>();
builder.RegisterType<StubShellDescriptorManager>().As<IShellDescriptorManager>();
builder.RegisterType<StubShellDescriptorManager>().As<IShellDescriptorManager>().InstancePerLifetimeScope();
builder.RegisterType<TransactionManager>().As<ITransactionManager>();
builder.RegisterType<Notifier>().As<INotifier>();
builder.RegisterType<StubAuthorizer>().As<IAuthorizer>();
@@ -135,6 +136,34 @@ namespace Orchard.Tests.Modules.Themes.Services {
Assert.That(siteTheme.ThemeName, Is.EqualTo("ThemeOne"));
}
[Test]
public void CanEnableAndDisableThemes() {
_themeService.EnableTheme("ThemeOne");
Assert.IsTrue(_themeService.GetThemeByName("ThemeOne").Enabled);
Assert.IsTrue(_container.Resolve<IShellDescriptorManager>().GetShellDescriptor().Features.Any(sf => sf.Name == "ThemeOne"));
_themeService.DisableTheme("ThemeOne");
Assert.IsFalse(_themeService.GetThemeByName("ThemeOne").Enabled);
Assert.IsFalse(_container.Resolve<IShellDescriptorManager>().GetShellDescriptor().Features.Any(sf => sf.Name == "ThemeOne"));
}
[Test]
public void ActivatingThemeEnablesIt() {
_themeService.SetSiteTheme("ThemeOne");
Assert.IsTrue(_themeService.GetThemeByName("ThemeOne").Enabled);
Assert.IsTrue(_container.Resolve<IShellDescriptorManager>().GetShellDescriptor().Features.Any(sf => sf.Name == "ThemeOne"));
}
[Test]
public void ActivatingThemeDoesNotDisableOldTheme() {
_themeService.SetSiteTheme("ThemeOne");
_themeService.SetSiteTheme("ThemeTwo");
Assert.IsTrue(_themeService.GetThemeByName("ThemeOne").Enabled);
Assert.IsTrue(_themeService.GetThemeByName("ThemeTwo").Enabled);
Assert.IsTrue(_container.Resolve<IShellDescriptorManager>().GetShellDescriptor().Features.Any(sf => sf.Name == "ThemeOne"));
Assert.IsTrue(_container.Resolve<IShellDescriptorManager>().GetShellDescriptor().Features.Any(sf => sf.Name == "ThemeTwo"));
}
#region Stubs
public class TestSessionLocator : ISessionLocator {

View File

@@ -20,11 +20,13 @@ using Orchard.Environment;
using Orchard.ContentManagement;
using Orchard.ContentManagement.Handlers;
using Orchard.ContentManagement.Records;
using Orchard.Environment.Extensions;
using Orchard.Localization;
using Orchard.Messaging.Events;
using Orchard.Messaging.Services;
using Orchard.Security;
using Orchard.Security.Permissions;
using Orchard.Tests.Stubs;
using Orchard.UI.Notify;
using Orchard.Users.Controllers;
using Orchard.Users.Handlers;
@@ -57,6 +59,7 @@ namespace Orchard.Tests.Modules.Users.Controllers {
builder.RegisterType<DefaultShapeTableManager>().As<IShapeTableManager>();
builder.RegisterType<DefaultShapeFactory>().As<IShapeFactory>();
builder.RegisterType<ShapeHelperFactory>().As<IShapeHelperFactory>();
builder.RegisterType<StubExtensionManager>().As<IExtensionManager>();
builder.RegisterInstance(new Mock<INotifier>().Object);
_authorizer = new Mock<IAuthorizer>();
builder.RegisterInstance(_authorizer.Object);

View File

@@ -17,9 +17,11 @@ using Orchard.ContentManagement.Records;
using Orchard.DisplayManagement;
using Orchard.DisplayManagement.Descriptors;
using Orchard.DisplayManagement.Implementation;
using Orchard.Environment.Extensions;
using Orchard.Messaging.Events;
using Orchard.Messaging.Services;
using Orchard.Security;
using Orchard.Tests.Stubs;
using Orchard.Users.Handlers;
using Orchard.Users.Models;
using Orchard.Users.Services;
@@ -80,6 +82,7 @@ namespace Orchard.Tests.Modules.Users.Services {
builder.RegisterType<DefaultShapeTableManager>().As<IShapeTableManager>();
builder.RegisterType<DefaultShapeFactory>().As<IShapeFactory>();
builder.RegisterType<ShapeHelperFactory>().As<IShapeHelperFactory>();
builder.RegisterType<StubExtensionManager>().As<IExtensionManager>();
_session = _sessionFactory.OpenSession();
builder.RegisterInstance(new TestSessionLocator(_session)).As<ISessionLocator>();
_container = builder.Build();

View File

@@ -15,7 +15,9 @@ using Orchard.DisplayManagement;
using Orchard.DisplayManagement.Descriptors;
using Orchard.DisplayManagement.Implementation;
using Orchard.Environment;
using Orchard.Environment.Extensions;
using Orchard.Security;
using Orchard.Tests.Stubs;
using Orchard.Themes;
using Orchard.Themes.Models;
using Orchard.UI.Notify;
@@ -72,7 +74,7 @@ namespace Orchard.Tests.Modules.Widgets.Services {
builder.RegisterType<DefaultShapeFactory>().As<IShapeFactory>();
builder.RegisterType<ShapeHelperFactory>().As<IShapeHelperFactory>();
builder.RegisterType<WidgetsService>().As<IWidgetsService>();
builder.RegisterType<StubExtensionManager>().As<IExtensionManager>();
Theme theme1 = new Theme { Zones = ThemeZoneName1 };
Theme theme2 = new Theme { Zones = ThemeZoneName2 };
Mock<IThemeService> themeServiceMock = new Mock<IThemeService>();

View File

@@ -10,9 +10,11 @@ using Orchard.ContentManagement.Handlers;
using Orchard.ContentManagement.Records;
using Orchard.DisplayManagement;
using Orchard.DisplayManagement.Descriptors;
using Orchard.Environment.Extensions;
using Orchard.Tests.ContentManagement.Records;
using Orchard.Tests.ContentManagement.Models;
using Orchard.DisplayManagement.Implementation;
using Orchard.Tests.Stubs;
namespace Orchard.Tests.ContentManagement {
[TestFixture]
@@ -64,6 +66,8 @@ namespace Orchard.Tests.ContentManagement {
builder.RegisterGeneric(typeof(Repository<>)).As(typeof(IRepository<>));
builder.RegisterType<StubExtensionManager>().As<IExtensionManager>();
_session = _sessionFactory.OpenSession();
builder.RegisterInstance(new DefaultContentManagerTests.TestSessionLocator(_session)).As<ISessionLocator>();

View File

@@ -12,12 +12,14 @@ using Orchard.Data;
using Orchard.ContentManagement;
using Orchard.ContentManagement.Handlers;
using Orchard.ContentManagement.Records;
using Orchard.Environment.Extensions;
using Orchard.Tests.ContentManagement.Records;
using Orchard.Tests.ContentManagement.Models;
using Orchard.DisplayManagement.Descriptors;
using Orchard.DisplayManagement.Implementation;
using Orchard.DisplayManagement;
using System.Collections.Generic;
using Orchard.Tests.Stubs;
namespace Orchard.Tests.ContentManagement {
[TestFixture]
@@ -72,6 +74,8 @@ namespace Orchard.Tests.ContentManagement {
builder.RegisterType<DefaultShapeFactory>().As<IShapeFactory>();
builder.RegisterType<ShapeHelperFactory>().As<IShapeHelperFactory>();
builder.RegisterType<StubExtensionManager>().As<IExtensionManager>();
builder.RegisterGeneric(typeof(Repository<>)).As(typeof(IRepository<>));
_session = _sessionFactory.OpenSession();

View File

@@ -46,6 +46,7 @@ namespace Orchard.Tests.DisplayManagement {
}
public class Theme : ITheme {
public bool Enabled { get; set; }
public string ThemeName { get; set; }
public string DisplayName { get; set; }
public string Description { get; set; }

View File

@@ -1,9 +1,12 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Autofac;
using NUnit.Framework;
using Orchard.DisplayManagement.Descriptors;
using Orchard.DisplayManagement.Implementation;
using Orchard.Environment.Extensions;
using Orchard.Environment.Extensions.Models;
namespace Orchard.Tests.DisplayManagement.Descriptors {
@@ -12,12 +15,50 @@ namespace Orchard.Tests.DisplayManagement.Descriptors {
protected override void Register(Autofac.ContainerBuilder builder) {
builder.RegisterType<DefaultShapeTableManager>().As<IShapeTableManager>();
var features = new [] {
new FeatureDescriptor {
Name = "Theme1",
Extension = new ExtensionDescriptor {
Name = "Theme1",
ExtensionType = "Theme"
}
},
new FeatureDescriptor {
Name = "DerivedTheme",
Extension = new ExtensionDescriptor {
Name = "DerivedTheme",
ExtensionType = "Theme",
BaseTheme = "BaseTheme"
}
},
new FeatureDescriptor {
Name = "BaseTheme",
Extension = new ExtensionDescriptor {
Name = "BaseTheme",
ExtensionType = "Theme"
}
}
};
builder.RegisterInstance<IExtensionManager>(new TestExtensionManager(features));
TestShapeProvider.FeatureShapes = new Dictionary<Feature, IEnumerable<string>> {
{ TestFeature(), new [] {"Hello"} },
{ Feature(features[0]), new [] {"Theme1Shape"} },
{ Feature(features[1]), new [] {"DerivedShape", "OverriddenShape"} },
{ Feature(features[2]), new [] {"BaseShape", "OverriddenShape"} }
};
builder.RegisterType<TestShapeProvider>().As<IShapeTableProvider>()
.WithMetadata("Feature", TestFeature())
.As<TestShapeProvider>()
.InstancePerLifetimeScope();
}
static Feature Feature(FeatureDescriptor descriptor) {
return new Feature {
Descriptor = descriptor
};
}
static Feature TestFeature() {
return new Feature {
Descriptor = new FeatureDescriptor {
@@ -31,12 +72,45 @@ namespace Orchard.Tests.DisplayManagement.Descriptors {
};
}
public class TestExtensionManager : IExtensionManager {
private readonly IEnumerable<FeatureDescriptor> _availableFeautures;
public TestExtensionManager(IEnumerable<FeatureDescriptor> availableFeautures) {
_availableFeautures = availableFeautures;
}
public IEnumerable<ExtensionDescriptor> AvailableExtensions() {
throw new NotSupportedException();
}
public IEnumerable<FeatureDescriptor> AvailableFeatures() {
return _availableFeautures;
}
public IEnumerable<Feature> LoadFeatures(IEnumerable<FeatureDescriptor> featureDescriptors) {
throw new NotSupportedException();
}
public void InstallExtension(string extensionType, HttpPostedFileBase extensionBundle) {
throw new NotSupportedException();
}
public void UninstallExtension(string extensionType, string extensionName) {
throw new NotSupportedException();
}
}
public class TestShapeProvider : IShapeTableProvider {
public static IDictionary<Feature, IEnumerable<string>> FeatureShapes;
public Action<ShapeTableBuilder> Discover = x => { };
void IShapeTableProvider.Discover(ShapeTableBuilder builder) {
builder.Describe("Hello");
foreach (var pair in FeatureShapes) {
foreach (var shape in pair.Value) {
builder.Describe(shape).From(pair.Key).BoundAs(pair.Key.Descriptor.Name, null);
}
}
Discover(builder);
}
}
@@ -64,7 +138,7 @@ namespace Orchard.Tests.DisplayManagement.Descriptors {
Action<ShapeDisplayedContext> cb4 = x => { };
_container.Resolve<TestShapeProvider>().Discover =
builder => builder.Describe("Foo")
builder => builder.Describe("Foo").From(TestFeature())
.OnCreating(cb1)
.OnCreated(cb2)
.OnDisplaying(cb3)
@@ -79,7 +153,6 @@ namespace Orchard.Tests.DisplayManagement.Descriptors {
Assert.That(foo.Displaying.Single(), Is.SameAs(cb3));
Assert.That(foo.Displayed.Single(), Is.SameAs(cb4));
}
[Test]
public void DefaultPlacementIsReturnedByDefault() {
var manager = _container.Resolve<IShapeTableManager>();
@@ -141,5 +214,36 @@ namespace Orchard.Tests.DisplayManagement.Descriptors {
Assert.That(result5, Is.EqualTo(""));
Assert.That(result6, Is.EqualTo("Header:5"));
}
[Test]
public void OnlyShapesFromTheGivenThemeAreProvided() {
_container.Resolve<TestShapeProvider>();
var manager = _container.Resolve<IShapeTableManager>();
var table = manager.GetShapeTable("Theme1");
Assert.IsTrue(table.Descriptors.ContainsKey("Theme1Shape"));
Assert.IsFalse(table.Descriptors.ContainsKey("DerivedShape"));
Assert.IsFalse(table.Descriptors.ContainsKey("BaseShape"));
}
[Test]
public void ShapesFromTheBaseThemeAreProvided() {
_container.Resolve<TestShapeProvider>();
var manager = _container.Resolve<IShapeTableManager>();
var table = manager.GetShapeTable("DerivedTheme");
Assert.IsFalse(table.Descriptors.ContainsKey("Theme1Shape"));
Assert.IsTrue(table.Descriptors.ContainsKey("DerivedShape"));
Assert.IsTrue(table.Descriptors.ContainsKey("BaseShape"));
}
[Test]
public void DerivedThemesCanOverrideBaseThemeShapeBindings() {
_container.Resolve<TestShapeProvider>();
var manager = _container.Resolve<IShapeTableManager>();
var table = manager.GetShapeTable("DerivedTheme");
Assert.IsTrue(table.Bindings.ContainsKey("OverriddenShape"));
Assert.AreEqual("DerivedTheme", table.Descriptors["OverriddenShape"].BindingSource);
}
}
}

View File

@@ -8,6 +8,8 @@ using Orchard.DisplayManagement;
using Orchard.DisplayManagement.Descriptors;
using Orchard.DisplayManagement.Implementation;
using Orchard.DisplayManagement.Shapes;
using Orchard.Environment.Extensions;
using Orchard.Tests.Stubs;
namespace Orchard.Tests.DisplayManagement {
[TestFixture]
@@ -20,6 +22,7 @@ namespace Orchard.Tests.DisplayManagement {
builder.RegisterType<DefaultShapeFactory>().As<IShapeFactory>();
builder.RegisterType<DefaultShapeTableManager>().As<IShapeTableManager>();
builder.RegisterType<ShapeHelperFactory>().As<IShapeHelperFactory>();
builder.RegisterType<StubExtensionManager>().As<IExtensionManager>();
_container = builder.Build();
}

View File

@@ -8,6 +8,8 @@ using Orchard.DisplayManagement;
using Orchard.DisplayManagement.Descriptors;
using Orchard.DisplayManagement.Implementation;
using Orchard.DisplayManagement.Shapes;
using Orchard.Environment.Extensions;
using Orchard.Tests.Stubs;
namespace Orchard.Tests.DisplayManagement {
[TestFixture]
@@ -20,6 +22,7 @@ namespace Orchard.Tests.DisplayManagement {
builder.RegisterType<ShapeHelperFactory>().As<IShapeHelperFactory>();
builder.RegisterType<DefaultShapeFactory>().As<IShapeFactory>();
builder.RegisterType<DefaultShapeTableManager>().As<IShapeTableManager>();
builder.RegisterType<StubExtensionManager>().As<IExtensionManager>();
_container = builder.Build();
}

View File

@@ -246,6 +246,8 @@
<Compile Include="Mvc\Routes\UrlPrefixTests.cs" />
<Compile Include="Records\BigRecord.cs" />
<Compile Include="Scripting\ScriptingTests.cs" />
<Compile Include="Stubs\StubWorkContextAccessor.cs" />
<Compile Include="Stubs\StubExtensionManager.cs" />
<Compile Include="Stubs\StubReportsCoordinator.cs" />
<Compile Include="Stubs\StubVirtualPathProvider.cs" />
<Compile Include="Stubs\StubFileSystem.cs" />

View File

@@ -0,0 +1,29 @@
using System;
using System.Collections.Generic;
using System.Web;
using Orchard.Environment.Extensions;
using Orchard.Environment.Extensions.Models;
namespace Orchard.Tests.Stubs {
public class StubExtensionManager : IExtensionManager {
public IEnumerable<ExtensionDescriptor> AvailableExtensions() {
throw new NotSupportedException();
}
public IEnumerable<FeatureDescriptor> AvailableFeatures() {
throw new NotSupportedException();
}
public IEnumerable<Feature> LoadFeatures(IEnumerable<FeatureDescriptor> featureDescriptors) {
throw new NotSupportedException();
}
public void InstallExtension(string extensionType, HttpPostedFileBase extensionBundle) {
throw new NotSupportedException();
}
public void UninstallExtension(string extensionType, string extensionName) {
throw new NotSupportedException();
}
}
}

View File

@@ -0,0 +1,22 @@
using System;
using System.Web;
namespace Orchard.Tests.Stubs {
public class StubWorkContextAccessor : IWorkContextAccessor {
public WorkContext GetContext(HttpContextBase httpContext) {
throw new NotSupportedException();
}
public IWorkContextScope CreateWorkContextScope(HttpContextBase httpContext) {
throw new NotSupportedException();
}
public WorkContext GetContext() {
return null;
}
public IWorkContextScope CreateWorkContextScope() {
throw new NotSupportedException();
}
}
}

View File

@@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
@@ -10,7 +9,6 @@ using System.Web.Mvc.Html;
using Orchard.DisplayManagement;
using Orchard.DisplayManagement.Descriptors;
using Orchard.DisplayManagement.Implementation;
using Orchard.DisplayManagement.Shapes;
using Orchard.Settings;
using Orchard.UI;
using Orchard.UI.Resources;
@@ -158,57 +156,6 @@ namespace Orchard.Core.Shapes {
return ordering.Select(ordered => ordered.item).ToList();
}
private class FlatPositionComparer : IComparer<string> {
public int Compare(string x, string y) {
if (x == y)
return 0;
// "" == "5"
x = string.IsNullOrWhiteSpace(x) ? "5" : x.TrimStart(':'); // ':' is _sometimes_ used as a partition identifier
y = string.IsNullOrWhiteSpace(y) ? "5" : y.TrimStart(':');
var xParts = x.Split(new[] { '.' }, StringSplitOptions.RemoveEmptyEntries);
var yParts = y.Split(new[] { '.' }, StringSplitOptions.RemoveEmptyEntries);
for (var i = 0; i < xParts.Count(); i++) {
if (yParts.Length < i - 1) // x is further defined meaning it comes after y (e.g. x == 1.2.3 and y == 1.2)
return 1;
int xPos;
int yPos;
xParts[i] = normalizeKnownPartitions(xParts[i]);
yParts[i] = normalizeKnownPartitions(yParts[i]);
var xIsInt = int.TryParse(xParts[i], out xPos);
var yIsInt = int.TryParse(yParts[i], out yPos);
if (!xIsInt && !yIsInt)
return string.Compare(x, y, StringComparison.OrdinalIgnoreCase);
if (!xIsInt || (yIsInt && xPos > yPos)) // non-int after int or greater x pos than y pos (which is an int)
return 1;
if (!yIsInt || xPos < yPos)
return -1;
}
if (xParts.Length < yParts.Length) // all things being equal y might be further defined than x (e.g. x == 1.2 and y == 1.2.3)
return -1;
return 0;
}
private static string normalizeKnownPartitions(string partition) {
if (partition.Length < 5) // known partitions are long
return partition;
if (string.Compare(partition, "before", StringComparison.OrdinalIgnoreCase) == 0)
return "-9999";
if (string.Compare(partition, "after", StringComparison.OrdinalIgnoreCase) == 0)
return "9999";
return partition;
}
}
#endregion
[Shape]

View File

@@ -1,17 +1,22 @@
@{
// odd formatting in this file is to cause more attractive results in the output.
var items = (IEnumerable<dynamic>)Enumerable.Cast<dynamic>(Model);
// odd formatting in this file is to cause more attractive results in the output.
var items = (IEnumerable<dynamic>)Enumerable.Cast<dynamic>(Model);
}
@{
if (string.IsNullOrWhiteSpace((string)Model.Text)) {
if (!HasText(Model.Text)) {
@DisplayChildren(Model)
} else {
<li><a href="@Model.Href">@Model.Text</a>
@if (items.Any()) {
if (Model.Href.TrimEnd('/').ToUpperInvariant() == Request.Path.TrimEnd('/').ToUpperInvariant()) {
Model.Classes.Add("current");
}
var tag = Tag(Model, "li");
@tag.StartElement
<a href="@Model.Href">@Model.Text</a>
if (items.Any()) {
<ul>
@DisplayChildren(Model)
</ul>
}
</li>
@tag.EndElement
}
}

View File

@@ -0,0 +1,62 @@
using System.Collections.Generic;
using System.Linq;
using Orchard.Blogs.Models;
using Orchard.Blogs.Services;
using Orchard.ContentManagement;
using Orchard.ContentManagement.Drivers;
using Orchard.Core.Common.Models;
using Orchard.Core.ContentsLocation.Models;
namespace Orchard.Blogs.Drivers {
public class RecentBlogPostsPartDriver : ContentPartDriver<RecentBlogPostsPart> {
private readonly IBlogService _blogService;
private readonly IContentManager _contentManager;
public RecentBlogPostsPartDriver(IBlogService blogService, IContentManager contentManager) {
_blogService = blogService;
_contentManager = contentManager;
}
protected override DriverResult Display(RecentBlogPostsPart part, string displayType, dynamic shapeHelper) {
IEnumerable<BlogPostPart> blogPosts = null;
BlogPart blog = null;
if (!string.IsNullOrWhiteSpace(part.ForBlog))
blog = _blogService.Get(part.ForBlog);
if (blog != null) {
blogPosts = _contentManager.Query(VersionOptions.Published, "BlogPost")
.Join<CommonPartRecord>().Where(cr => cr.Container == blog.Record.ContentItemRecord)
.OrderByDescending(cr => cr.CreatedUtc)
.Slice(0, part.Count)
.Select(ci => ci.As<BlogPostPart>());
}
else {
var blogs = _blogService.Get().ToList();
blogPosts = _contentManager.Query(VersionOptions.Published, "BlogPost")
.Join<CommonPartRecord>()
.OrderByDescending(cr => cr.CreatedUtc)
.Slice(0, part.Count)
.Select(ci => ci.As<BlogPostPart>());
}
var list = shapeHelper.List();
list.AddRange(blogPosts.Select(bp => _contentManager.BuildDisplay(bp, "Summary.BlogPost")));
var blogPostList = shapeHelper.Parts_Blogs_BlogPost_List(ContentPart: part, BlogPosts: list);
blogPostList.Metadata.Type = "Parts_Blogs_BlogPost.List";
return ContentShape(blogPostList).Location("Primary");
}
protected override DriverResult Editor(RecentBlogPostsPart part, dynamic shapeHelper) {
var location = part.GetLocation("Editor", "Primary", "5");
return ContentPartTemplate(part, "Parts/Blogs.RecentBlogPosts").Location(location);
}
protected override DriverResult Editor(RecentBlogPostsPart part, IUpdateModel updater, dynamic shapeHelper) {
updater.TryUpdateModel(part, Prefix, null, null);
return Editor(part, shapeHelper);
}
}
}

View File

@@ -0,0 +1,13 @@
using JetBrains.Annotations;
using Orchard.Blogs.Models;
using Orchard.ContentManagement.Handlers;
using Orchard.Data;
namespace Orchard.Blogs.Handlers {
[UsedImplicitly]
public class RecentBlogPostsPartHandler : ContentHandler {
public RecentBlogPostsPartHandler(IRepository<RecentBlogPostsPartRecord> repository) {
Filters.Add(StorageFilter.For(repository));
}
}
}

View File

@@ -55,5 +55,22 @@ namespace Orchard.Blogs {
}));
return 3;
}
public int UpdateFrom3() {
SchemaBuilder.CreateTable("RecentBlogPostsPartRecord", table => table
.ContentPartRecord()
.Column<string>("BlogSlug")
.Column<int>("Count")
);
ContentDefinitionManager.AlterTypeDefinition("RecentBlogPosts",
cfg => cfg
.WithPart("RecentBlogPostsPart")
.WithPart("CommonPart")
.WithPart("WidgetPart")
.WithSetting("Stereotype", "Widget")
);
return 4;
}
}
}

View File

@@ -0,0 +1,17 @@
using System.ComponentModel.DataAnnotations;
using Orchard.ContentManagement;
namespace Orchard.Blogs.Models {
public class RecentBlogPostsPart : ContentPart<RecentBlogPostsPartRecord> {
public string ForBlog {
get { return Record.BlogSlug; }
set { Record.BlogSlug = value; }
}
[Required]
public int Count {
get { return Record.Count; }
set { Record.Count = value; }
}
}
}

View File

@@ -0,0 +1,8 @@
using Orchard.ContentManagement.Records;
namespace Orchard.Blogs.Models {
public class RecentBlogPostsPartRecord : ContentPartRecord {
public virtual string BlogSlug { get; set; }
public virtual int Count { get; set; }
}
}

View File

@@ -67,6 +67,10 @@
</ItemGroup>
<ItemGroup>
<Compile Include="AdminMenu.cs" />
<Compile Include="Drivers\RecentBlogPostsPartDriver.cs" />
<Compile Include="Handlers\RecentBlogPostsPartHandler.cs" />
<Compile Include="Models\RecentBlogPostsPart.cs" />
<Compile Include="Models\RecentBlogPostsPartRecord.cs" />
<Compile Include="ResourceManifest.cs" />
<Compile Include="Commands\BlogCommands.cs" />
<Compile Include="Controllers\BlogAdminController.cs" />
@@ -183,6 +187,7 @@
</ItemGroup>
<ItemGroup>
<None Include="App_Data\Localization\fr-FR\orchard.module.po" />
<None Include="Views\EditorTemplates\Parts\Blogs.RecentBlogPosts.cshtml" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets" />

View File

@@ -0,0 +1,11 @@
@model Orchard.Blogs.Models.RecentBlogPostsPart
<fieldset>
<div>
@Html.LabelFor(m => m.ForBlog)
@Html.TextBoxFor(m => m.ForBlog)
</div>
<div>
@Html.LabelFor(m => m.Count)
@Html.TextBoxFor(m => m.Count)
</div>
</fieldset>

View File

@@ -85,7 +85,7 @@ namespace Orchard.Modules.Controllers {
if (!Services.Authorizer.Authorize(Permissions.ManageFeatures, T("Not allowed to manage features")))
return new HttpUnauthorizedResult();
var features = _moduleService.GetAvailableFeatures().ToList();
var features = _moduleService.GetAvailableFeatures().Where(f => !f.Descriptor.Extension.ExtensionType.Equals("Theme", StringComparison.OrdinalIgnoreCase)).ToList();
var featuresThatNeedUpdate = _dataMigrationManager.GetFeaturesThatNeedUpdate();
return View(new FeaturesViewModel { Features = features, FeaturesThatNeedUpdate = featuresThatNeedUpdate });

View File

@@ -1,13 +1,23 @@
using Orchard.Localization;
using Orchard.Environment.Configuration;
using Orchard.Localization;
using Orchard.UI.Navigation;
namespace Orchard.MultiTenancy {
public class AdminMenu : INavigationProvider {
private readonly ShellSettings _shellSettings;
public AdminMenu(ShellSettings shellSettings) {
_shellSettings = shellSettings;
}
public Localizer T { get; set; }
public string MenuName { get { return "admin"; } }
public void GetNavigation(NavigationBuilder builder) {
if ( _shellSettings.Name != "Default" )
return;
builder.Add(T("Tenants"), "22",
menu => menu
.Add(T("Manage Tenants"), "1.0", item => item.Action("Index", "Admin", new { area = "Orchard.MultiTenancy" }).Permission(Permissions.ManageTenants))

View File

@@ -32,6 +32,10 @@ namespace Orchard.MultiTenancy.Controllers {
public ActionResult Add() {
if (!Services.Authorizer.Authorize(Permissions.ManageTenants, T("Cannot create tenant")))
return new HttpUnauthorizedResult();
if ( !EnsureDefaultTenant() )
return new HttpUnauthorizedResult();
return View(new TenantAddViewModel());
}
@@ -40,7 +44,10 @@ namespace Orchard.MultiTenancy.Controllers {
try {
if (!Services.Authorizer.Authorize(Permissions.ManageTenants, T("Couldn't create tenant")))
return new HttpUnauthorizedResult();
if ( !EnsureDefaultTenant() )
return new HttpUnauthorizedResult();
_tenantService.CreateTenant(
new ShellSettings {
Name = viewModel.Name,
@@ -64,6 +71,9 @@ namespace Orchard.MultiTenancy.Controllers {
if (!Services.Authorizer.Authorize(Permissions.ManageTenants, T("Cannot edit tenant")))
return new HttpUnauthorizedResult();
if ( !EnsureDefaultTenant() )
return new HttpUnauthorizedResult();
var tenant = _tenantService.GetTenants().FirstOrDefault(ss => ss.Name == name);
if (tenant == null)
return new NotFoundResult();
@@ -85,6 +95,9 @@ namespace Orchard.MultiTenancy.Controllers {
if (!Services.Authorizer.Authorize(Permissions.ManageTenants, T("Couldn't edit tenant")))
return new HttpUnauthorizedResult();
if ( !EnsureDefaultTenant() )
return new HttpUnauthorizedResult();
var tenant = _tenantService.GetTenants().FirstOrDefault(ss => ss.Name == viewModel.Name);
if (tenant == null)
return new NotFoundResult();
@@ -113,6 +126,9 @@ namespace Orchard.MultiTenancy.Controllers {
if (!Services.Authorizer.Authorize(Permissions.ManageTenants, T("Couldn't disable tenant")))
return new HttpUnauthorizedResult();
if ( !EnsureDefaultTenant() )
return new HttpUnauthorizedResult();
var tenant = _tenantService.GetTenants().FirstOrDefault(ss => ss.Name == name);
if (tenant != null && tenant.Name != _thisShellSettings.Name) {
@@ -120,7 +136,7 @@ namespace Orchard.MultiTenancy.Controllers {
_tenantService.UpdateTenant(tenant);
}
return RedirectToAction("index");
return RedirectToAction("Index");
}
[HttpPost]
@@ -128,6 +144,9 @@ namespace Orchard.MultiTenancy.Controllers {
if (!Services.Authorizer.Authorize(Permissions.ManageTenants, T("Couldn't enable tenant")))
return new HttpUnauthorizedResult();
if ( !EnsureDefaultTenant() )
return new HttpUnauthorizedResult();
var tenant = _tenantService.GetTenants().FirstOrDefault(ss => ss.Name == name);
if (tenant != null && tenant.Name != _thisShellSettings.Name) {
@@ -135,7 +154,11 @@ namespace Orchard.MultiTenancy.Controllers {
_tenantService.UpdateTenant(tenant);
}
return RedirectToAction("index");
return RedirectToAction("Index");
}
private bool EnsureDefaultTenant() {
return _thisShellSettings.Name == "Default";
}
}
}

View File

@@ -215,16 +215,6 @@ namespace Orchard.Setup.Services {
contentDefinitionManager.AlterPartDefinition("BodyPart", cfg => cfg
.WithSetting("BodyPartSettings.FlavorDefault", BodyPartSettings.FlavorDefaultDefault));
// create home page as a CMS page
//var page = contentManager.Create("Page", VersionOptions.Draft);
//page.As<BodyPart>().Text = "<p>Welcome to Orchard!</p><p>Congratulations, you've successfully set-up your Orchard site.</p><p>This is the home page of your new site. We've taken the liberty to write here about a few things you could look at next in order to get familiar with the application. Once you feel confident you don't need this anymore, just click <a href=\"Admin/Pages/Edit/3\">Edit</a> to go into edit mode and replace this with whatever you want on your home page to make it your own.</p><p>One thing you could do (but you don't have to) is go into <a href=\"Admin/Settings\">Manage Settings</a> (follow the <a href=\"Admin\">Admin</a> link and then look for it under \"Settings\" in the menu on the left) and check that everything is configured the way you want.</p><p>You probably want to make the site your own. One of the ways you can do that is by clicking <a href=\"Admin/Themes\">Manage Themes</a> in the admin menu. A theme is a packaged look and feel that affects the whole site.</p><p>Next, you can start playing with the content types that we installed. For example, go ahead and click <a href=\"Admin/Pages/Create\">Add New Page</a> in the admin menu and create an \"about\" page. Then, add it to the navigation menu by going to <a href=\"Admin/Navigation\">Manage Menu</a>. You can also click <a href=\"Admin/Blogs/Create\">Add New Blog</a> and start posting by clicking \"Add New Post\".</p><p>Finally, Orchard has been designed to be extended. It comes with a few built-in modules such as pages and blogs or themes. You can install new themes by going to <a href=\"Admin/Themes\">Manage Themes</a> and clicking <a href=\"Admin/Themes/Install\">Install a new Theme</a>. Like for themes, modules are created by other users of Orchard just like you so if you feel up to it, please <a href=\"http://www.orchardproject.net/\">consider participating</a>.</p><p>--The Orchard Crew</p>";
//page.As<RoutePart>().Slug = "home";
//page.As<RoutePart>().Path = "home";
//page.As<RoutePart>().Title = T("Home").ToString();
//page.As<CommonPart>().Owner = user;
//contentManager.Publish(page);
//siteSettings.Record.HomePage = "RoutableHomePageProvider;" + page.Id;
//scratch that
// add a layer for the homepage
var layer = contentManager.Create("Layer");
@@ -237,15 +227,17 @@ namespace Orchard.Setup.Services {
htmlWidget.As<WidgetPart>().LayerPart = layer.As<LayerPart>();
htmlWidget.As<WidgetPart>().Title = T("Welcome to Orchard!").Text;
htmlWidget.As<WidgetPart>().Zone = "Content";
htmlWidget.As<WidgetPart>().Position = "5";
htmlWidget.As<BodyPart>().Text = "<p>Welcome to Orchard!</p><p>Congratulations, you've successfully set-up your Orchard site.</p><p>This is the home page of your new site. We've taken the liberty to write here about a few things you could look at next in order to get familiar with the application. Once you feel confident you don't need this anymore, just click <a href=\"Admin/Pages/Edit/3\">Edit</a> to go into edit mode and replace this with whatever you want on your home page to make it your own.</p><p>One thing you could do (but you don't have to) is go into <a href=\"Admin/Settings\">Manage Settings</a> (follow the <a href=\"Admin\">Admin</a> link and then look for it under \"Settings\" in the menu on the left) and check that everything is configured the way you want.</p><p>You probably want to make the site your own. One of the ways you can do that is by clicking <a href=\"Admin/Themes\">Manage Themes</a> in the admin menu. A theme is a packaged look and feel that affects the whole site.</p><p>Next, you can start playing with the content types that we installed. For example, go ahead and click <a href=\"Admin/Pages/Create\">Add New Page</a> in the admin menu and create an \"about\" page. Then, add it to the navigation menu by going to <a href=\"Admin/Navigation\">Manage Menu</a>. You can also click <a href=\"Admin/Blogs/Create\">Add New Blog</a> and start posting by clicking \"Add New Post\".</p><p>Finally, Orchard has been designed to be extended. It comes with a few built-in modules such as pages and blogs or themes. You can install new themes by going to <a href=\"Admin/Themes\">Manage Themes</a> and clicking <a href=\"Admin/Themes/Install\">Install a new Theme</a>. Like for themes, modules are created by other users of Orchard just like you so if you feel up to it, please <a href=\"http://www.orchardproject.net/\">consider participating</a>.</p><p>--The Orchard Crew</p>";
contentManager.Publish(htmlWidget);
// create the home page as a WidgetPage
var page = contentManager.Create("WidgetPage", VersionOptions.Draft);
page.As<RoutePart>().Title = T("Home").ToString();
page.As<CommonPart>().Owner = user;
contentManager.Publish(page);
siteSettings.Record.HomePage = "RoutableHomePageProvider;" + page.Id;
// add a menu item for the shiny new home page
var menuItem = contentManager.Create("MenuItem");
menuItem.As<MenuPart>().MenuPosition = "1";

View File

@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Web;
using System.Web.Routing;
using Autofac;
using JetBrains.Annotations;
using Orchard.Commands;
using Orchard.Commands.Builtin;
using Orchard.ContentManagement;
@@ -91,6 +92,7 @@ namespace Orchard.Setup {
}
[UsedImplicitly]
class SafeModeText : IText {
public LocalizedString Get(string textHint, params object[] args) {
if (args == null || args.Length == 0) {
@@ -100,9 +102,11 @@ namespace Orchard.Setup {
}
}
[UsedImplicitly]
class SafeModeThemeService : IThemeService {
class SafeModeTheme : ITheme {
public ContentItem ContentItem { get; set; }
public bool Enabled { get; set; }
public string ThemeName { get; set; }
public string DisplayName { get; set; }
public string Description { get; set; }
@@ -115,6 +119,7 @@ namespace Orchard.Setup {
}
private readonly SafeModeTheme _theme = new SafeModeTheme {
Enabled = true,
ThemeName = "SafeMode",
DisplayName = "SafeMode",
};
@@ -126,8 +131,11 @@ namespace Orchard.Setup {
public IEnumerable<ITheme> GetInstalledThemes() { return new[] { _theme }; }
public void InstallTheme(HttpPostedFileBase file) { }
public void UninstallTheme(string themeName) { }
public void EnableTheme(string themeName) { }
public void DisableTheme(string themeName) { }
}
[UsedImplicitly]
class SafeModeSiteWorkContextProvider : IWorkContextStateProvider {
public T Get<T>(string name) {
if (name == "CurrentSite")
@@ -136,6 +144,7 @@ namespace Orchard.Setup {
}
}
[UsedImplicitly]
class SafeModeSiteService : ISiteService {
public ISite GetSiteSettings() {
var siteType = new ContentTypeDefinitionBuilder().Named("Site").Build();

View File

@@ -2,8 +2,11 @@
using System.Reflection;
using System.Web;
using System.Web.Mvc;
using Orchard.Data.Migration;
using Orchard.DisplayManagement;
using Orchard.Localization;
using Orchard.Mvc.Results;
using Orchard.Reports.Services;
using Orchard.Security;
using Orchard.Themes.Preview;
using Orchard.Themes.ViewModels;
@@ -14,8 +17,12 @@ namespace Orchard.Themes.Controllers {
public class AdminController : Controller {
private readonly IThemeService _themeService;
private readonly IPreviewTheme _previewTheme;
private readonly IDataMigrationManager _dataMigrationManager;
private readonly IReportsCoordinator _reportsCoordinator;
public AdminController(
IDataMigrationManager dataMigraitonManager,
IReportsCoordinator reportsCoordinator,
IOrchardServices services,
IThemeService themeService,
IPreviewTheme previewTheme,
@@ -23,6 +30,8 @@ namespace Orchard.Themes.Controllers {
INotifier notifier,
IShapeHelperFactory shapeHelperFactory) {
Services = services;
_dataMigrationManager = dataMigraitonManager;
_reportsCoordinator = reportsCoordinator;
_themeService = themeService;
_previewTheme = previewTheme;
T = NullLocalizer.Instance;
@@ -36,7 +45,8 @@ namespace Orchard.Themes.Controllers {
try {
var themes = _themeService.GetInstalledThemes();
var currentTheme = _themeService.GetSiteTheme();
var model = new ThemesIndexViewModel { CurrentTheme = currentTheme, Themes = themes };
var featuresThatNeedUpdate = _dataMigrationManager.GetFeaturesThatNeedUpdate();
var model = new ThemesIndexViewModel { CurrentTheme = currentTheme, Themes = themes, FeaturesThatNeedUpdate = featuresThatNeedUpdate };
return View(model);
}
catch (Exception exception) {
@@ -66,12 +76,11 @@ namespace Orchard.Themes.Controllers {
return new HttpUnauthorizedResult();
_previewTheme.SetPreviewTheme(null);
_themeService.SetSiteTheme(themeName);
return RedirectToAction("Index");
}
catch (Exception exception) {
Services.Notifier.Error(T("Previewing theme failed: " + exception.Message));
return RedirectToAction("Index");
}
return RedirectToAction("Index");
}
[HttpPost, ActionName("Preview"), FormValueRequired("submit.Cancel")]
@@ -80,12 +89,37 @@ namespace Orchard.Themes.Controllers {
if (!Services.Authorizer.Authorize(Permissions.ApplyTheme, T("Couldn't preview the current theme")))
return new HttpUnauthorizedResult();
_previewTheme.SetPreviewTheme(null);
return RedirectToAction("Index");
}
catch (Exception exception) {
Services.Notifier.Error(T("Previewing theme failed: " + exception.Message));
return RedirectToAction("Index");
}
return RedirectToAction("Index");
}
[HttpPost]
public ActionResult Enable(string themeName) {
try {
if (!Services.Authorizer.Authorize(Permissions.ApplyTheme, T("Couldn't enable the theme")))
return new HttpUnauthorizedResult();
_themeService.EnableTheme(themeName);
}
catch (Exception exception) {
Services.Notifier.Error(T("Enabling theme failed: " + exception.Message));
}
return RedirectToAction("Index");
}
[HttpPost]
public ActionResult Disable(string themeName) {
try {
if (!Services.Authorizer.Authorize(Permissions.ApplyTheme, T("Couldn't disable the current theme")))
return new HttpUnauthorizedResult();
_themeService.DisableTheme(themeName);
}
catch (Exception exception) {
Services.Notifier.Error(T("Disabling theme failed: " + exception.Message));
}
return RedirectToAction("Index");
}
[HttpPost]
@@ -94,12 +128,11 @@ namespace Orchard.Themes.Controllers {
if (!Services.Authorizer.Authorize(Permissions.ApplyTheme, T("Couldn't set the current theme")))
return new HttpUnauthorizedResult();
_themeService.SetSiteTheme(themeName);
return RedirectToAction("Index");
}
catch (Exception exception) {
Services.Notifier.Error(T("Activating theme failed: " + exception.Message));
return RedirectToAction("Index");
}
return RedirectToAction("Index");
}
public ActionResult Install() {
@@ -137,6 +170,26 @@ namespace Orchard.Themes.Controllers {
}
}
[HttpPost]
public ActionResult Update(string themeName) {
if (!Services.Authorizer.Authorize(Permissions.ManageThemes, T("Couldn't update theme")))
return new HttpUnauthorizedResult();
if (string.IsNullOrEmpty(themeName))
return new NotFoundResult();
try {
_reportsCoordinator.Register("Data Migration", "Upgrade " + themeName, "Orchard installation");
_dataMigrationManager.Update(themeName);
Services.Notifier.Information(T("The theme {0} was updated succesfuly", themeName));
}
catch (Exception ex) {
Services.Notifier.Error(T("An error occured while updating the theme {0}: {1}", themeName, ex.Message));
}
return RedirectToAction("Index");
}
class FormValueRequiredAttribute : ActionMethodSelectorAttribute {
private readonly string _submitButtonName;

View File

@@ -1,5 +1,6 @@
namespace Orchard.Themes.Models {
public class Theme : ITheme {
public bool Enabled { get; set; }
public string ThemeName { get; set; }
public string DisplayName { get; set; }
public string Description { get; set; }

View File

@@ -4,6 +4,7 @@ using System.Linq;
using System.Web;
using System.Web.Routing;
using JetBrains.Annotations;
using Orchard.Environment.Descriptor;
using Orchard.Environment.Extensions;
using Orchard.Environment.Extensions.Models;
using Orchard.Localization;
@@ -19,13 +20,16 @@ namespace Orchard.Themes.Services {
private readonly IExtensionManager _extensionManager;
private readonly IEnumerable<IThemeSelector> _themeSelectors;
private readonly IModuleService _moduleService;
private IWorkContextAccessor _workContextAccessor;
private readonly IWorkContextAccessor _workContextAccessor;
private readonly IShellDescriptorManager _shellDescriptorManager;
public ThemeService(
IShellDescriptorManager shellDescriptorManager,
IExtensionManager extensionManager,
IEnumerable<IThemeSelector> themeSelectors,
IModuleService moduleService,
IWorkContextAccessor workContextAccessor) {
_shellDescriptorManager = shellDescriptorManager;
_extensionManager = extensionManager;
_themeSelectors = themeSelectors;
_moduleService = moduleService;
@@ -49,26 +53,17 @@ namespace Orchard.Themes.Services {
}
public void SetSiteTheme(string themeName) {
if (string.IsNullOrWhiteSpace(themeName))
return;
if (DoEnableTheme(themeName)) {
CurrentSite.As<ThemeSiteSettingsPart>().Record.CurrentThemeName = themeName;
}
}
//todo: (heskew) need messages given in addition to all of these early returns so something meaningful can be presented to the user
var themeToSet = GetThemeByName(themeName);
if (themeToSet == null)
return;
public void EnableTheme(string themeName) {
DoEnableTheme(themeName);
}
// ensure all base themes down the line are present and accounted for
//todo: (heskew) dito on the need of a meaningful message
if (!AllBaseThemesAreInstalled(themeToSet.BaseTheme))
return;
// disable all theme features
DisableThemeFeatures(CurrentSite.As<ThemeSiteSettingsPart>().CurrentThemeName);
// enable all theme features
EnableThemeFeatures(themeToSet.ThemeName);
CurrentSite.As<ThemeSiteSettingsPart>().Record.CurrentThemeName = themeToSet.ThemeName;
public void DisableTheme(string themeName) {
DisableThemeFeatures(themeName);
}
private bool AllBaseThemesAreInstalled(string baseThemeName) {
@@ -93,12 +88,15 @@ namespace Orchard.Themes.Services {
while (themeName != null) {
if (themes.Contains(themeName))
throw new InvalidOperationException(T("The theme \"{0}\" is already in the stack of themes that need features disabled.", themeName).Text);
var theme = GetThemeByName(themeName);
if (theme == null)
break;
themes.Enqueue(themeName);
var theme = GetThemeByName(themeName);
themeName = !string.IsNullOrWhiteSpace(theme.BaseTheme)
? theme.BaseTheme
: null;
}
while (themes.Count > 0)
@@ -119,7 +117,26 @@ namespace Orchard.Themes.Services {
}
while (themes.Count > 0)
_moduleService.DisableFeatures(new[] {themes.Pop()});
_moduleService.EnableFeatures(new[] {themes.Pop()});
}
private bool DoEnableTheme(string themeName) {
if (string.IsNullOrWhiteSpace(themeName))
return false;
//todo: (heskew) need messages given in addition to all of these early returns so something meaningful can be presented to the user
var themeToEnable = GetThemeByName(themeName);
if (themeToEnable == null)
return false;
// ensure all base themes down the line are present and accounted for
//todo: (heskew) dito on the need of a meaningful message
if (!AllBaseThemesAreInstalled(themeToEnable.BaseTheme))
return false;
// enable all theme features
EnableThemeFeatures(themeToEnable.ThemeName);
return true;
}
public ITheme GetRequestTheme(RequestContext requestContext) {
@@ -188,6 +205,10 @@ namespace Orchard.Themes.Services {
return localized;
}
private bool IsThemeEnabled(ExtensionDescriptor descriptor) {
return _shellDescriptorManager.GetShellDescriptor().Features.Any(sf => sf.Name == descriptor.Name);
}
private ITheme CreateTheme(ExtensionDescriptor descriptor) {
var localizer = LocalizationUtilities.Resolve(_workContextAccessor.GetContext(), String.Concat(descriptor.Location, "/", descriptor.Name, "/Theme.txt"));
@@ -202,6 +223,7 @@ namespace Orchard.Themes.Services {
Tags = TryLocalize("Tags", descriptor.Tags, localizer) ?? "",
Zones = descriptor.Zones ?? "",
BaseTheme = descriptor.BaseTheme ?? "",
Enabled = IsThemeEnabled(descriptor)
};
}
}

View File

@@ -4,5 +4,6 @@ namespace Orchard.Themes.ViewModels {
public class ThemesIndexViewModel {
public ITheme CurrentTheme { get; set; }
public IEnumerable<ITheme> Themes { get; set; }
public IEnumerable<string> FeaturesThatNeedUpdate { get; set; }
}
}

View File

@@ -29,9 +29,13 @@
<div>
<h3>@theme.DisplayName</h3>
@Html.Image(Href(Html.ThemePath(theme, "/Theme.png")), Html.Encode(theme.DisplayName), null)
@using (Html.BeginFormAntiForgeryPost(Url.Action(theme.Enabled ? "Disable" : "Enable"), FormMethod.Post, new { @class = "inline" })) {
@Html.Hidden("themeName", theme.ThemeName)
<button type="submit" title="@T(theme.Enabled ? "Disable" : "Enable")">@T(theme.Enabled ? "Disable" : "Enable")</button>
}
@using (Html.BeginFormAntiForgeryPost(Url.Action("Activate"), FormMethod.Post, new { @class = "inline" })) {
@Html.Hidden("themeName", theme.ThemeName)
<button type="submit" title="@T("Activate")">@T("Activate")</button>
<button type="submit" title="@T("Activate")">@T("Set Current")</button>
}
@using (Html.BeginFormAntiForgeryPost(Url.Action("Preview"), FormMethod.Post, new { @class = "inline" })) {
@Html.Hidden("themeName", theme.ThemeName)
@@ -43,6 +47,12 @@
@theme.Description<br />
@theme.HomePage
</p>
@if(Model.FeaturesThatNeedUpdate.Contains(theme.ThemeName)){
using (Html.BeginFormAntiForgeryPost(Url.Action("Update"), FormMethod.Post, new { @class = "inline link" })) {
@Html.Hidden("themeName", theme.ThemeName)
<button type="submit" class="update">@T("Update")</button> <br/>
}
}
@using (Html.BeginFormAntiForgeryPost(Url.Action("Uninstall"), FormMethod.Post, new { @class = "inline link" })) {
@Html.Hidden("themeName", theme.ThemeName)
<button type="submit" class="uninstall" title="@T("Uninstall")">@T("Uninstall")</button>

View File

@@ -3,10 +3,6 @@ using Orchard.Security;
namespace Orchard.Users.Models {
public sealed class UserPart : ContentPart<UserPartRecord>, IUser {
public int Id {
get { return ContentItem.Id; }
}
public string UserName {
get { return Record.UserName; }
set { Record.UserName = value; }

View File

@@ -101,6 +101,7 @@ namespace Orchard.Widgets {
);
ContentDefinitionManager.AlterTypeDefinition("WidgetPage",
cfg => cfg
.WithPart("CommonPart")
.WithPart("RoutePart")
.WithPart("WidgetBagPart")
.Creatable()

View File

@@ -1,4 +1,4 @@
@model WidgetsIndexViewModel;
@model WidgetsIndexViewModel
@using Orchard.Widgets.Models;
@using Orchard.Widgets.ViewModels;
@{ Style.Require("WidgetsAdmin"); }
@@ -48,7 +48,7 @@
<li>
<div class="widgets-zone">@zone</div>
<ul>
@foreach (WidgetPart widget in Model.CurrentLayerWidgets.Where(widgetPart => widgetPart.Zone == zone).OrderBy(widgetPart => widgetPart.Position)) {
@foreach (WidgetPart widget in Model.CurrentLayerWidgets.Where(widgetPart => widgetPart.Zone == zone).OrderBy(widgetPart => widgetPart.Position, new Orchard.UI.FlatPositionComparer())) {
<li class="widgets-zoneWidget">
@if (widget.Position != "1") {
<input type="image" name="submit.MoveUp.@widget.Id" src="@Url.Content("~/modules/orchard.widgets/Content/Admin/images/moveup.gif")" alt="Move up" value="@widget.Id" />

View File

@@ -141,11 +141,10 @@
<Content Include="Themes\TheThemeMachine\Theme.png" />
<Content Include="Themes\TheThemeMachine\Theme.txt" />
<None Include="Themes\Classic\App_Data\Localization\fr-FR\orchard.theme.po" />
<None Include="Themes\TheThemeMachine\Views\Layout-homePage.cshtml" />
<None Include="Themes\TheThemeMachine\Views\AsideThird.cshtml" />
<None Include="Themes\TheThemeMachine\Views\Recent.cshtml">
<SubType>Designer</SubType>
</None>
<None Include="Themes\TheThemeMachine\Views\Layout-Blog.cshtml" />
<None Include="Themes\TheThemeMachine\Views\Featured.cshtml">
<SubType>Designer</SubType>
</None>

View File

@@ -78,7 +78,7 @@ body {
font-size: 62.5%;
color: #333;
background: #fff;
font-family: Segoe UI,Trebuchet,Arial,Sans-Serif;
font-family: Tahoma, "Helvetica Neue", Arial, Helvetica, sans-serif;
}
a {}
@@ -88,10 +88,10 @@ a:visited{}
/* Headings */
h1,h2,h3,h4,h5,h6 { font-weight: normal; }
h1,h2,h3,h4,h5,h6 { font-weight: normal; margin:.6em 0;}
h1 { font-size: 3em;}
h2 { font-size: 1.3em; }
h1 { font-size: 2em; }
h2 { font-size: 1.4em; }
h3 { font-size: 1.2em; }
h4 { font-size: 1.1em; }
h5 { font-size: 1em; }
@@ -102,9 +102,16 @@ h4 img, h5 img, h6 img {
margin: 0;
}
p, .meta {
/* TODO: We wrap all widgets with consistent html so we get predictable font sizing */
p, footer, .meta {
font-size:1.3em;
line-height:2em;
line-height:1.8em;
}
p {
margin-bottom: 1em;
}
/* Structure
@@ -115,40 +122,23 @@ p, .meta {
}
#layout-header {
border:1px solid #ff0000;
background: #53a4ca;
padding: 12px 0;
margin-bottom:12px;
}
#branding a {
color:#fff;
text-decoration:none;
padding:48px 12px;
padding:0 12px;
}
#layout-wrapper {
border:1px solid #CCC;
}
/* Sidebar off - Content Zone 960 */
#content {
/*clear:both;
padding:12px;*/
}
/*One Sidebar on */
.has-sidebar #content {
background-color:#e8e8e8;
width: 600px;
/*padding:12px 6px 6px 12px;*/
float:left;
/*clear:both;*/
}
.has-sidebar .sidebar {
background-color:#f6f6f6;
width: 360px;
float:right;
#layout-footer {
border-top: 1px solid #999;
margin-top:12px;
}
/*Two Sidebars on */
@@ -166,17 +156,12 @@ p, .meta {
float:left;
}
#sitemap {
clear:both;
}
/* Navigation */
#navigation {
width: 960px;
margin: 4px auto;
margin: 12px auto;
display:block;
border-bottom: 1px solid #999;
}
@@ -188,13 +173,13 @@ nav ul {
nav ul li
{
border:1px solid #999;
background:#e7e7e7;
background:#f6f6f6;
display:block;
float:left;
margin:0 2px -1px 0;
}
nav ul li.on {
nav ul li.current {
border-bottom: 1px solid #fff;
background:#fff;
}
@@ -203,80 +188,159 @@ nav ul a {
padding:0 18px;
display:block;
float:left;
color: #333;
font-size:1.4em;
text-decoration:none;
line-height:24px;
}
#footer {}
/* Main
***************************************************************/
#content, .aside, .about {
padding:6px;
}
/* One Sidebar on */
.has-sidebar #content {
width: 588px;
float:left;
}
.has-sidebar .aside.first {
width: 348px;
float:right;
}
/* Sidebar on the left */
.has-sidebar-left #content {
width: 588px;
float:right;
}
.has-sidebar-left .aside.second {
width: 348px;
float:left;
}
/* Two Sidebars on */
.has-sidebars #content {
width: 588px;
}
.has-sidebars .aside.first, .has-sidebars .aside.second {
width: 168px;
}
.has-sidebars .aside.first, .has-sidebars .aside.second, .has-sidebars #content {
float:left;
}
/* Secondary
***************************************************************/
/* Forms
***************************************************************/
label { font-weight: normal; display:block; }
label.forcheckbox { margin:0 0 0 .4em; display:inline; }
fieldset { padding:0em; margin: 0 0 0em 0; border: 0px solid #ccc; }
legend { font-weight: 600; font-size:1.2em; }
input[type=text],
input.text, input.title,
textarea, select {
background-color:#fff;
border:1px solid #bbb;
}
input[type=text]:focus,
input.text:focus, input.title:focus,
textarea:focus, select:focus {
border-color:#a5cc7a;
background-color: #fbfff7;
input[type="text"], #CommentText, #password, #confirmPassword {
border:1px solid #999;
display: block;
padding:6px;
width:50%;
}
input[type=text],
input.text, input.title,
textarea, select {
margin:0.5em 0;
form.search {
margin-bottom:2em;
}
input.text,
input.title { width: 300px; padding:5px; }
input.title { font-size:1.5em; }
textarea { padding:5px; }
input[type=checkbox], input[type=radio],
input.checkbox, input.radio {
position:relative; top:.25em;
.search input[type=text] {
display:inline;
width:17em;
}
/* TODO: Causes form rendering issues with theme preview, had to add line-height: normal */
form.inline { line-height: normal; }
form.inline p { margin-bottom:0; }
fieldset div {margin:1.6em 0 0 0}
legend {
font-size: 1.4em;
border:none;
}
label {
font-size: 1.3em;
margin:0 0 .3em 0;
}
/*- Login Control -*/
input[type="checkbox"] {
margin:.2em 0 1.2em 0;
}
.login-form { border: solid 1px #e2e2e2; padding: 20px; font-size: 1.2em; font-weight: normal; }
.login-form div { padding: 5px 0px 5px 0px; }
.login-form input[type=submit] { margin: 5px 0px 5px 0px; }
.validation-summary-errors { padding: 20px 20px 0px 20px; border: solid 1px #fff54f; background-color: #fffcca; margin-bottom: 20px; }
input[type="submit"], input[type="button"], button, .button, .button:link, .button:visited {
color:#333;
background:#F5F5F5;
background: -webkit-gradient(linear, left top, left bottom, from(#F5F5F5), to(#cbcbcb));
background:-moz-linear-gradient(top , #F5F5F5, #cbcbcb);
border:1px solid #999;
cursor:pointer;
margin:.2em 0 2em 0;
padding:.3em 1.8em;
text-align:center;
}
input[type="submit"]:hover, input[type="button"]:hover,
input[type="submit"]:active, input[type="button"]:active,
input[type="submit"]:focus, input[type="button"]:focus,
button:hover, .button:hover,
button:active, .button:active,
button:focus, .button:focus {
text-decoration:none;
background: #ffac40;
background: -webkit-gradient(linear, left top, left bottom, from(#ffac40), to(#f06015));
background: -moz-linear-gradient(top, #ffac40, #f9760d);
background: -webkit-gradient(linear, left top, left bottom, from(#e1e1e1), to(#ebebeb));
background:-moz-linear-gradient(top , #e1e1e1, #ebebeb);
}
.edit-form { display: none; }
.static_text_div { border: dashed 1px #CCCCCC; display:block; color: inherit; }
.static_text_div:hover { border: dashed 1px red; color: inherit; }
/* Misc
***************************************************************/
/* For testing purposes */
.zone {
/*padding:6px;*/
#comments {
font-weight:600;
margin:1.2em 0 1.2em 1.2em;
}
ul.comments, form.comment {
margin:1.2em 0 1.2em 1.2em;
}
div.comment span {
font-size:1.3em;
}
ul.comments li div.text {
margin:.6em 0;
}
.user-display {
display:inline;
}
.aside.third {
border-top:1px solid #999999;
clear:both;
}
.aside.third div > div {
float:left;
width:304px;
padding:12px 6px 0 6px;
}
/* Featured Zone - switch to an image */

View File

@@ -4,4 +4,4 @@ Description: It's a *really* good theme, yo.
Version: 0.1
Tags: Awesome
Website: http://orchardproject.net
Zones: Header, Navigation, Messages, Featured, Recent, Footer
Zones: Header, Navigation, Messages, AsideFirst, AsideSecond, AsideThird, Content, Footer

View File

@@ -0,0 +1,14 @@
<div>
<h1>First Leader Aside</h1>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur a nibh ut tortor dapibus vestibulum. Aliquam vel sem nibh. Suspendisse vel condimentum tellus.</p>
</div>
<div>
<h1>Second Leader Aside</h1>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur a nibh ut tortor dapibus vestibulum. Aliquam vel sem nibh. Suspendisse vel condimentum tellus.</p>
</div>
<div>
<h1>Third Leader Aside</h1>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur a nibh ut tortor dapibus vestibulum. Aliquam vel sem nibh. Suspendisse vel condimentum tellus.</p>
</div>

View File

@@ -1,15 +0,0 @@
<!-- zone: featured -->
<div class="featuredimage">Image</div>
<article class="featured-blogpost">
<header>
<!-- // example // -->
@if(HasText(Model.Title)) {
<h1>@Model.Title</h1>
}
else {
<h1>@Model.insertMessage</h1>
}
</header>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed ultrices vehicula nibh quis varius. Donec tincidunt, purus at tincidunt elementum, justo nisi rhoncus metus, quis bibendum lorem nunc at dolor. Sed scelerisque aliquet leo sed semper. Donec accumsan, nibh at consectetur rhoncus, odio justo imperdiet risus, quis pretium tortor dolor vel dolor.</p>
</article>
<!-- /zone: featured -->

View File

@@ -1,79 +0,0 @@
@{
Style.Include("site.css");
// cool stuff goes up here
var homeUrl = Href("~/");
// Zone is an alias for Display
Func<dynamic, dynamic> Zone = x => Display(x);
if (Model.Sidebar != null) {
Html.AddPageClassNames(new[]{"icanhassidebar"});
}
}
<div id="layout-wrapper">
<header id="layout-header">
@* needs to be the page title, not page (head) title... *@
<h1><a href="@homeUrl">@WorkContext.CurrentSite.SiteName</a></h1>
@if(Model.Header != null) {
<div id="header">
@Zone(Model.Header)
</div>
}
@if(Model.Navigation != null) {
<div id="navigation">
@Zone(Model.Navigation)
</div>
}
</header>
@if(Model.Messages != null) {
<div id="messages">
@Zone(Model.Messages)
</div>
}
@* This code would inject text into the Featured zone.
@{WorkContext.Layout.Featured.Add("just some text in featured");}
*@
@{
WorkContext.Layout.Featured.Add(New.Featured(insertMessage:"This is a featured blog post."));
}
@if(Model.Featured != null) {
<div id="featured" class="group">
@Zone(Model.Featured)
</div>
}
@* the model content for the page is in the Content zone @ the default position (nothing, zero, zilch) *@
@if(Model.Content == null) {
<div id="content">
@Zone(Model.Content)
</div>
}
else {
<div id="content">
Let's take over the home page
</div>
}
@if(Model.Sidebar != null) {
<aside class="sidebar">
@Zone(Model.Sidebar)
</aside>
}
@if(Model.Footer != null) {
<footer>
@Zone(Model.Footer)
</footer>
}
else {
<footer id="sitemap">
Powered by Orchard @Display.User()
</footer>
}
</div>

View File

@@ -1,87 +0,0 @@
@{
Style.Include("site.css");
// cool stuff goes up here
var homeUrl = Href("~/");
// Zone is an alias for Display
Func<dynamic, dynamic> Zone = x => Display(x);
if (Model.Sidebar != null) {
Html.AddPageClassNames(new[]{"has-sidebar"});
}
}
<div id="layout-wrapper">
<header id="layout-header">
@* needs to be the page title, not page (head) title... *@
<h1><a href="@homeUrl">@WorkContext.CurrentSite.SiteName</a></h1>
@if(Model.Header != null) {
<div id="header">
@Zone(Model.Header)
</div>
}
@if(Model.Navigation != null) {
<div id="navigation">
@Zone(Model.Navigation)
</div>
}
</header>
@if(Model.Messages != null) {
<div id="messages">
@Zone(Model.Messages)
</div>
}
@* This code would inject text into the Featured zone.
@{WorkContext.Layout.Featured.Add("just some text in featured");}
*@
@{
WorkContext.Layout.Featured.Add(New.Featured(insertMessage:"This is a featured blog post."));
}
@if(Model.Featured != null) {
<div class="group">
@Zone(Model.Featured)
</div>
}
@{
WorkContext.Layout.Recent.Add(New.Recent());
}
@if(Model.Featured != null) {
<div class="zone-featured zone group">
@Zone(Model.Recent)
</div>
}
@* the model content for the page is in the Content zone @ the default position (nothing, zero, zilch) *@
@if(Model.Content != null) {
<div id="content" class="group">
@Zone(Model.Content)
</div>
}
else {
<div id="content" class="group">
Let's take over the home page
</div>
}
@if(Model.Sidebar != null) {
<aside class="sidebar">
@Zone(Model.Sidebar)
</aside>
}
@if(Model.Footer != null) {
<footer>
@Zone(Model.Footer)
</footer>
}
else {
<footer id="sitemap">
Powered by Orchard @Display.User()
</footer>
}
</div>

View File

@@ -1,4 +1,5 @@
@{
Style.Include("site.css");
// cool stuff goes up here
@@ -7,15 +8,18 @@
// Zone is an alias for Display
Func<dynamic, dynamic> Zone = x => Display(x);
//Use the two lines below to test the sidebar zones.
//WorkContext.Layout.AsideFirst.Add("This test text will render in Sidebar1.");
//WorkContext.Layout.AsideSecond.Add("This test text will render in Sidebar2.");
if (Model.Sidebar != null && Model.Sidebar2 == null) {
//Add classes to the wrapper div to toggle zones on and off
if (Model.AsideFirst != null && Model.AsideSecond == null) {
Model.Classes.Add("has-sidebar");
}
else if (Model.Sidebar == null && Model.Sidebar2 != null) {
else if (Model.AsideFirst == null && Model.AsideSecond != null) {
Model.Classes.Add("has-sidebar-left");
}
else if (Model.Sidebar != null && Model.Sidebar2 != null) {
else if (Model.AsideFirst != null && Model.AsideSecond != null) {
Model.Classes.Add("has-sidebars");
}
else {
@@ -63,31 +67,9 @@
</div>
}
@* This code would inject text into the Featured zone.
@{WorkContext.Layout.Featured.Add("just some text in featured");}
*@
@{
WorkContext.Layout.Featured.Add(New.Featured(insertMessage:"This is a featured blog post."));
}
@if(Model.Featured != null) {
<div class="zone-featured group">
@Zone(Model.Featured)
</div>
}
@{
WorkContext.Layout.Recent.Add(New.Recent());
}
@if(Model.Featured != null) {
<div class="group">
@Zone(Model.Recent)
</div>
}
@if(Model.Sidebar2 != null) {
<aside class="sidebar secondary">
@Zone(Model.Sidebar2)
@if(Model.AsideSecond != null) {
<aside class="aside second">
@Zone(Model.AsideSecond)
</aside>
}
@@ -97,27 +79,34 @@
@Zone(Model.Content)
</div>
}
@if(Model.Sidebar != null) {
<aside class="sidebar primary">
@Zone(Model.Sidebar)
@if(Model.AsideFirst != null) {
<aside class="aside first">
@Zone(Model.AsideFirst)
</aside>
@* Create a zone and only show it on the home page. *@
@if (Request.Path == "/OrchardLocal") {
WorkContext.Layout.AsideThird.Add(New.AsideThird());
}
@if(Model.AsideThird != null) {
<aside class="aside third group">
@Zone(Model.AsideThird)
</aside>
}
</div>
@{
WorkContext.Layout.Footer.Add(@Display.User());
}
@if(Model.Footer != null) {
<footer id="layout-footer" class="group">
@Zone(Model.Footer)
</footer>
}
else {
<footer id="layout-footer">
Powered by Orchard @Display.User()
<footer id="layout-footer" class="group">
Powered by Orchard &#169; The Theme Machine 2010. @Display.User()
</footer>
}

View File

@@ -1,17 +1,22 @@
@{
// odd formatting in this file is to cause more attractive results in the output.
var items = (IEnumerable<dynamic>)Enumerable.Cast<dynamic>(Model);
// odd formatting in this file is to cause more attractive results in the output.
var items = (IEnumerable<dynamic>)Enumerable.Cast<dynamic>(Model);
}
@{
if (!HasText(Model.Text)) {
@DisplayChildren(Model)
} else {
<li><a href="@Model.Href">@Model.Text</a>
@if (items.Any()) {
if (Model.Href.TrimEnd('/').ToUpperInvariant() == Request.Path.TrimEnd('/').ToUpperInvariant()) {
Model.Classes.Add("current");
}
var tag = Tag(Model, "li");
@tag.StartElement
<a href="@Model.Href">@Model.Text</a>
if (items.Any()) {
<ul>
@DisplayChildren(Model)
</ul>
}
</li>
@tag.EndElement
}
}

View File

@@ -1,22 +0,0 @@
<!-- zone: recent -->
<section class="posts-recent">
<ul>
<li class="first">
<article>
<header>
<h1>Another recent post title</h1>
</header>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent magna ante, accumsan at blandit et, posuere imperdiet sapien. Praesent condimentum laoreet justo non semper. Cras molestie fermentum turpis, in ornare eros mollis non. Sed a ligula sit amet mauris ultrices hendrerit ac vitae quam. Integer sit amet lorem vitae velit accumsan suscipit. Nulla mi nulla, congue eget euismod eget, ultrices in mauris. Mauris leo turpis, malesuada mattis feugiat ut, convallis in neque. Maecenas iaculis consequat interdum. Sed fermentum dolor quis ante interdum in sollicitudin lorem sollicitudin. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.</p>
</article>
</li>
<li class="last">
<article>
<header>
<h1>Another recent post title</h1>
</header>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent magna ante, accumsan at blandit et, posuere imperdiet sapien. Praesent condimentum laoreet justo non semper. Cras molestie fermentum turpis, in ornare eros mollis non. Sed a ligula sit amet mauris ultrices hendrerit ac vitae quam. Integer sit amet lorem vitae velit accumsan suscipit. Nulla mi nulla, congue eget euismod eget, ultrices in mauris. Mauris leo turpis, malesuada mattis feugiat ut, convallis in neque. Maecenas iaculis consequat interdum. Sed fermentum dolor quis ante interdum in sollicitudin lorem sollicitudin. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.</p>
</article>
</li>
</ul>
</section>
<!-- /zone: recent -->

View File

@@ -1,6 +1,4 @@
using Orchard.UI;
namespace Orchard.ContentManagement {
namespace Orchard.ContentManagement {
public interface IContent {
ContentItem ContentItem { get; }

View File

@@ -3,7 +3,9 @@ using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using Autofac.Features.Metadata;
using Orchard.Environment.Extensions;
using Orchard.Environment.Extensions.Models;
using Orchard.Utility;
namespace Orchard.DisplayManagement.Descriptors {
@@ -13,8 +15,12 @@ namespace Orchard.DisplayManagement.Descriptors {
public class DefaultShapeTableManager : IShapeTableManager {
private readonly IEnumerable<Meta<IShapeTableProvider, IFeatureMetadata>> _bindingStrategies;
private readonly IExtensionManager _extensionManager;
public DefaultShapeTableManager(IEnumerable<Meta<IShapeTableProvider, IFeatureMetadata>> bindingStrategies) {
public DefaultShapeTableManager(
IEnumerable<Meta<IShapeTableProvider, IFeatureMetadata>> bindingStrategies,
IExtensionManager extensionManager) {
_extensionManager = extensionManager;
_bindingStrategies = bindingStrategies;
}
@@ -30,7 +36,8 @@ namespace Orchard.DisplayManagement.Descriptors {
}
var alterations = builderFactory.BuildAlterations()
.Where(alteration => IsModuleOrRequestedTheme(alteration, themeName));
.Where(alteration => IsModuleOrRequestedTheme(alteration, themeName))
.OrderByDependencies(AlterationHasDependency);
var descriptors = alterations.GroupBy(alteration => alteration.ShapeType, StringComparer.OrdinalIgnoreCase)
.Select(group => group.Aggregate(
@@ -47,8 +54,11 @@ namespace Orchard.DisplayManagement.Descriptors {
});
}
private static bool AlterationHasDependency(ShapeAlteration item, ShapeAlteration subject) {
return ExtensionManager.HasDependency(item.Feature.Descriptor, subject.Feature.Descriptor);
}
static bool IsModuleOrRequestedTheme(ShapeAlteration alteration, string themeName) {
private bool IsModuleOrRequestedTheme(ShapeAlteration alteration, string themeName) {
if (alteration == null ||
alteration.Feature == null ||
alteration.Feature.Descriptor == null ||
@@ -57,10 +67,36 @@ namespace Orchard.DisplayManagement.Descriptors {
}
var extensionType = alteration.Feature.Descriptor.Extension.ExtensionType;
var featureName = alteration.Feature.Descriptor.Name;
return extensionType == "Module" ||
(extensionType == "Theme" && featureName == themeName);
if (extensionType == "Module") {
return true;
}
if (extensionType == "Theme") {
// alterations from themes must be from the given theme or a base theme
var featureName = alteration.Feature.Descriptor.Name;
return featureName == themeName || IsBaseTheme(featureName, themeName);
}
return false;
}
private bool IsBaseTheme(string featureName, string themeName) {
// determine if the given feature is a base theme of the given theme
var availableFeatures = _extensionManager.AvailableFeatures();
var themeFeature = availableFeatures.SingleOrDefault(fd => fd.Name == themeName);
while(themeFeature != null) {
var baseTheme = themeFeature.Extension.BaseTheme;
if (String.IsNullOrEmpty(baseTheme)) {
return false;
}
if (featureName == baseTheme) {
return true;
}
themeFeature = availableFeatures.SingleOrDefault(fd => fd.Name == baseTheme);
}
return false;
}
class ShapeTableBuilderFactory {

View File

@@ -38,7 +38,7 @@ namespace Orchard.DisplayManagement.Descriptors.ShapeTemplateStrategy {
var harvesterInfos = _harvesters.Select(harvester => new { harvester, subPaths = harvester.SubPaths() });
var availableFeatures = _extensionManager.AvailableFeatures();
var activeFeatures = availableFeatures.Where(fd => FeatureIsTheme(fd) || FeatureIsEnabled(fd));
var activeFeatures = availableFeatures.Where(FeatureIsEnabled);
var activeExtensions = Once(activeFeatures);
var hits = activeExtensions.SelectMany(extensionDescriptor => {
@@ -81,12 +81,9 @@ namespace Orchard.DisplayManagement.Descriptors.ShapeTemplateStrategy {
}
}
private bool FeatureIsTheme(FeatureDescriptor fd) {
return fd.Extension.ExtensionType == "Theme";
}
private bool FeatureIsEnabled(FeatureDescriptor fd) {
return _shellDescriptor.Features.Any(sf => sf.Name == fd.Name);
return (fd.Extension.ExtensionType == "Theme" && (fd.Name == "TheAdmin" || fd.Name == "SafeMode")) ||
_shellDescriptor.Features.Any(sf => sf.Name == fd.Name);
}
private IHtmlString Render(ShapeDescriptor shapeDescriptor, DisplayContext displayContext, HarvestShapeInfo harvestShapeInfo, HarvestShapeHit harvestShapeHit) {

View File

@@ -48,17 +48,23 @@ namespace Orchard.Environment.Extensions {
/// <param name="item"></param>
/// <param name="subject"></param>
/// <returns></returns>
static bool HasDependency(FeatureDescriptor item, FeatureDescriptor subject) {
// Themes implicitly depend on modules to ensure build and override ordering
if (item.Extension.ExtensionType == "Theme" && subject.Extension.ExtensionType == "Module")
return true;
internal static bool HasDependency(FeatureDescriptor item, FeatureDescriptor subject) {
if (item.Extension.ExtensionType == "Theme") {
// Themes implicitly depend on modules to ensure build and override ordering
if (subject.Extension.ExtensionType == "Module") {
return true;
}
if (subject.Extension.ExtensionType == "Theme") {
// theme depends on another if it is its base theme
return item.Extension.BaseTheme == subject.Name;
}
}
// Return based on explicit dependencies
return item.Dependencies != null &&
item.Dependencies.Any(x => StringComparer.OrdinalIgnoreCase.Equals(x, subject.Name));
}
private IEnumerable<ExtensionEntry> LoadedExtensions() {
foreach ( var descriptor in AvailableExtensions() ) {
ExtensionEntry entry = null;

View File

@@ -50,11 +50,9 @@ namespace Orchard.Environment.Extensions.Loaders {
}
protected override ExtensionEntry LoadWorker(ExtensionDescriptor descriptor) {
var assembly = Assembly.Load("Orchard.Themes");
return new ExtensionEntry {
Descriptor = descriptor,
Assembly = assembly,
Assembly = GetType().Assembly,
ExportedTypes = new Type[0]
};
}

View File

@@ -184,6 +184,7 @@
<Compile Include="Security\CurrentUserWorkContext.cs" />
<Compile Include="Settings\CurrentSiteWorkContext.cs" />
<Compile Include="Settings\ResourceDebugMode.cs" />
<Compile Include="UI\FlatPositionComparer.cs" />
<Compile Include="UI\Resources\IResourceManifestProvider.cs" />
<Compile Include="UI\Resources\ResourceManifestBuilder.cs" />
<Compile Include="UI\Widgets\IRuleManager.cs" />

View File

@@ -3,6 +3,7 @@
/// Interface provided by the "themes" model.
/// </summary>
public interface ITheme {
bool Enabled { get; set; }
string ThemeName { get; set; }
string DisplayName { get; set; }
string Description { get; set; }

View File

@@ -10,6 +10,9 @@ namespace Orchard.Themes {
void SetSiteTheme(string themeName);
ITheme GetRequestTheme(RequestContext requestContext);
void EnableTheme(string themeName);
void DisableTheme(string themeName);
IEnumerable<ITheme> GetInstalledThemes();
void InstallTheme(HttpPostedFileBase file);
void UninstallTheme(string themeName);

View File

@@ -0,0 +1,56 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace Orchard.UI {
public class FlatPositionComparer : IComparer<string> {
public int Compare(string x, string y) {
if (x == y)
return 0;
// "" == "5"
x = string.IsNullOrWhiteSpace(x) ? "5" : x.TrimStart(':'); // ':' is _sometimes_ used as a partition identifier
y = string.IsNullOrWhiteSpace(y) ? "5" : y.TrimStart(':');
var xParts = x.Split(new[] { '.' }, StringSplitOptions.RemoveEmptyEntries);
var yParts = y.Split(new[] { '.' }, StringSplitOptions.RemoveEmptyEntries);
for (var i = 0; i < xParts.Count(); i++) {
if (yParts.Length < i - 1) // x is further defined meaning it comes after y (e.g. x == 1.2.3 and y == 1.2)
return 1;
int xPos;
int yPos;
xParts[i] = NormalizeKnownPartitions(xParts[i]);
yParts[i] = NormalizeKnownPartitions(yParts[i]);
var xIsInt = int.TryParse(xParts[i], out xPos);
var yIsInt = int.TryParse(yParts[i], out yPos);
if (!xIsInt && !yIsInt)
return string.Compare(x, y, StringComparison.OrdinalIgnoreCase);
if (!xIsInt || (yIsInt && xPos > yPos)) // non-int after int or greater x pos than y pos (which is an int)
return 1;
if (!yIsInt || xPos < yPos)
return -1;
}
if (xParts.Length < yParts.Length) // all things being equal y might be further defined than x (e.g. x == 1.2 and y == 1.2.3)
return -1;
return 0;
}
private static string NormalizeKnownPartitions(string partition) {
if (partition.Length < 5) // known partitions are long
return partition;
if (string.Compare(partition, "before", StringComparison.OrdinalIgnoreCase) == 0)
return "-9999";
if (string.Compare(partition, "after", StringComparison.OrdinalIgnoreCase) == 0)
return "9999";
return partition;
}
}
}