--HG--
branch : dev
This commit is contained in:
Renaud Paquay
2010-06-09 19:00:48 -07:00
276 changed files with 2821 additions and 1036 deletions

View File

@@ -15,3 +15,4 @@ glob:src/Orchard.Azure.suo
glob:src/Orchard.5.0.ReSharper
glob:log.xml
glob:profiling
glob:*.csproj.orig

View File

@@ -63,6 +63,18 @@ Website: http://fluentnhibernate.org/
Copyright: Copyright (c) 2008-2009 James Gregory and contributors
License: New BSD
FluentPath
-----
Website: http://fluentpath.codeplex.com/
Copyright: Copyright (c) 2010 Bertrand Le Roy
License: MS-PL
Html Agility Pack
-----
Website: http://htmlagilitypack.codeplex.com/
Copyright: Copyright (c) 2003-20010 Simon Mourier
License: MS-PL
IESI Collections
-----
Website: http://www.codeproject.com/KB/recipes/sets.aspx
@@ -93,6 +105,12 @@ Log4Net
Website: http://logging.apache.org/log4net/index.html
Copyright: Copyright (c) 2007 Apache Software Foundation
License: Apache Software Foundation License 2.0
Lucene.net
-----
Website: http://incubator.apache.org/projects/lucene.net.html
Copyright: Copyright (c) 2009 Apache Software Foundation
License: Apache Software Foundation License 2.0
Moq
-----
@@ -125,6 +143,12 @@ Website: http://www.icsharpcode.net/OpenSource/SharpZipLib/Default.aspx
Copyright: Copyright (c) 2000-2009 IC#Code
License: Modified GPL: http://www.icsharpcode.net/OpenSource/SharpZipLib/Default.aspx
SpecFlow
-----
Website: http://www.specflow.org/
Copyright: Copyright (c) 2009 TechTalk
License: New BSD
SQLite
-----
Website: http://www.sqlite.org
@@ -137,6 +161,12 @@ WebSite: http://tinymce.moxiecode.com/
Copyright: Copyright (c) 2003-2009 Moxiecode Systems AB
License: LGPL 2.1
WCat
-----
WebSite: http://www.iis.net/community/default.aspx?tabid=34&i=1466&g=6
Copyright: Copyright (c) 2007 Microsoft
License: "Free"
Yamlnet
-----
Website: http://code.google.com/p/yamlnet/

View File

@@ -6,6 +6,7 @@ using JetBrains.Annotations;
using Moq;
using NUnit.Framework;
using Orchard.ContentManagement.Aspects;
using Orchard.ContentManagement.MetaData;
using Orchard.Core.Common;
using Orchard.Core.Common.Handlers;
using Orchard.Core.Common.Models;
@@ -25,6 +26,7 @@ namespace Orchard.Core.Tests.Common.Providers {
private Mock<IAuthenticationService> _authn;
private Mock<IAuthorizationService> _authz;
private Mock<IMembershipService> _membership;
private Mock<IContentDefinitionManager> _contentDefinitionManager;
public override void Register(ContainerBuilder builder) {
builder.RegisterType<DefaultContentManager>().As<IContentManager>();
@@ -35,11 +37,12 @@ namespace Orchard.Core.Tests.Common.Providers {
_authn = new Mock<IAuthenticationService>();
_authz = new Mock<IAuthorizationService>();
_membership = new Mock<IMembershipService>();
_contentDefinitionManager = new Mock<IContentDefinitionManager>();
builder.RegisterInstance(_authn.Object);
builder.RegisterInstance(_authz.Object);
builder.RegisterInstance(_membership.Object);
builder.RegisterInstance(_contentDefinitionManager.Object);
}
protected override IEnumerable<Type> DatabaseTypes {

View File

@@ -2,10 +2,12 @@
using System.Collections.Generic;
using Autofac;
using JetBrains.Annotations;
using Moq;
using NUnit.Framework;
using Orchard.ContentManagement;
using Orchard.ContentManagement.Drivers;
using Orchard.ContentManagement.Handlers;
using Orchard.ContentManagement.MetaData;
using Orchard.ContentManagement.Records;
using Orchard.Core.Common.Models;
using Orchard.Core.Common.Services;
@@ -27,6 +29,7 @@ namespace Orchard.Core.Tests.Common.Services {
public override void Register(ContainerBuilder builder) {
builder.RegisterType<DefaultContentManager>().As<IContentManager>();
builder.RegisterType<DefaultContentManagerSession>().As<IContentManagerSession>();
builder.RegisterInstance(new Mock<IContentDefinitionManager>().Object);
builder.RegisterType<ThingHandler>().As<IContentHandler>();
builder.RegisterType<StuffHandler>().As<IContentHandler>();

View File

@@ -9,6 +9,8 @@ using Moq;
using NUnit.Framework;
using Orchard.ContentManagement;
using Orchard.ContentManagement.Handlers;
using Orchard.ContentManagement.MetaData.Builders;
using Orchard.ContentManagement.MetaData.Models;
using Orchard.Core.Common.Models;
using Orchard.Core.Feeds;
using Orchard.Core.Feeds.Controllers;
@@ -145,7 +147,7 @@ namespace Orchard.Core.Tests.Feeds.Controllers {
[Test]
public void CorePartValuesAreExtracted() {
var clock = new StubClock();
var hello = new ContentItemBuilder("hello")
var hello = new ContentItemBuilder(new ContentTypeDefinitionBuilder().Named("hello").Build())
.Weld<CommonAspect>()
.Weld<RoutableAspect>()
.Weld<BodyAspect>()

View File

@@ -216,5 +216,38 @@ namespace Orchard.Tests.Indexing {
_provider.Store("default", _provider.New(1).Add("body", null));
Assert.That(_provider.IsEmpty("default"), Is.False);
}
[Test]
public void IsDirtyShouldBeFalseForNewDocuments() {
IIndexDocument doc = _provider.New(1);
Assert.That(doc.IsDirty, Is.False);
}
[Test]
public void IsDirtyShouldBeTrueWhenIndexIsModified() {
IIndexDocument doc;
doc = _provider.New(1);
doc.Add("foo", "value");
Assert.That(doc.IsDirty, Is.True);
doc = _provider.New(1);
doc.Add("foo", false);
Assert.That(doc.IsDirty, Is.True);
doc = _provider.New(1);
doc.Add("foo", (float)1.0);
Assert.That(doc.IsDirty, Is.True);
doc = _provider.New(1);
doc.Add("foo", 1);
Assert.That(doc.IsDirty, Is.True);
doc = _provider.New(1);
doc.Add("foo", DateTime.Now);
Assert.That(doc.IsDirty, Is.True);
}
}
}

View File

@@ -177,5 +177,19 @@ namespace Orchard.Tests.Indexing {
Assert.That(date[0].GetDateTime("date") < date[1].GetDateTime("date"), Is.True);
Assert.That(date[1].GetDateTime("date") < date[2].GetDateTime("date"), Is.True);
}
[Test]
public void ShouldEscapeSpecialChars() {
_provider.CreateIndex("default");
_provider.Store("default", _provider.New(1).Add("body", "Orchard has been developped in C#"));
_provider.Store("default", _provider.New(2).Add("body", "Windows has been developped in C++"));
var cs = _searchBuilder.WithField("body", "C#").Search().ToList();
Assert.That(cs.Count(), Is.EqualTo(2));
var cpp = _searchBuilder.WithField("body", "C++").Search().ToList();
Assert.That(cpp.Count(), Is.EqualTo(2));
}
}
}

View File

@@ -4,6 +4,7 @@ using Autofac;
using Moq;
using NUnit.Framework;
using Orchard.ContentManagement;
using Orchard.ContentManagement.MetaData;
using Orchard.ContentManagement.Records;
using Orchard.Core.Scheduling.Models;
using Orchard.Core.Scheduling.Services;
@@ -29,6 +30,7 @@ namespace Orchard.Core.Tests.Scheduling {
builder.RegisterInstance(new Mock<IOrchardServices>().Object);
builder.RegisterType<DefaultContentManager>().As<IContentManager>();
builder.RegisterType<DefaultContentManagerSession>().As<IContentManagerSession>();
builder.RegisterInstance(new Mock<IContentDefinitionManager>().Object);
builder.RegisterType<ScheduledTaskExecutor>().As<IBackgroundTask>().Named("ScheduledTaskExecutor", typeof(IBackgroundTask));
builder.RegisterInstance(_handler).As<IScheduledTaskHandler>();

View File

@@ -5,6 +5,7 @@ using Autofac;
using Moq;
using NUnit.Framework;
using Orchard.ContentManagement;
using Orchard.ContentManagement.MetaData;
using Orchard.ContentManagement.Records;
using Orchard.Core.Scheduling.Models;
using Orchard.Core.Scheduling.Services;
@@ -33,6 +34,7 @@ namespace Orchard.Core.Tests.Scheduling {
builder.RegisterInstance(_mockServices.Object);
builder.RegisterType<DefaultContentManager>().As<IContentManager>();
builder.RegisterType<DefaultContentManagerSession>().As<IContentManagerSession>();
builder.RegisterInstance(new Mock<IContentDefinitionManager>().Object);
builder.RegisterType<ScheduledTaskManager>().As<IScheduledTaskManager>();
}

View File

@@ -7,15 +7,9 @@ Scenario: Installed modules are listed
Given I have installed Orchard
When I go to "admin/modules"
Then I should see "<h1>Installed Modules</h1>"
And I should see "<h3>Themes</h3>"
And I should see "<h2>Themes"
And the status should be 200 OK
Scenario: Edit module shows its features
Given I have installed Orchard
When I go to "admin/modules/Edit/Orchard.Themes"
Then I should see "<h1>Edit Module: Themes</h1>"
And the status should be 200 OK
Scenario: Features of installed modules are listed
Given I have installed Orchard
When I go to "admin/modules/features"

View File

@@ -7,7 +7,7 @@ Scenario: Default site is listed
Given I have installed Orchard
And I have installed "Orchard.MultiTenancy"
When I go to "Admin/MultiTenancy"
Then I should see "List of Site's Tenants"
Then I should see "List of Site&#39;s Tenants"
And I should see "<span class="tenantName">Default</span>"
And the status should be 200 OK

View File

@@ -1,7 +1,9 @@
using System.Linq;
using Autofac;
using Moq;
using NHibernate;
using NUnit.Framework;
using Orchard.ContentManagement.MetaData;
using Orchard.Data;
using Orchard.ContentManagement;
using Orchard.ContentManagement.Handlers;
@@ -44,6 +46,7 @@ namespace Orchard.Tests.ContentManagement {
builder.RegisterModule(new ContentModule());
builder.RegisterType<DefaultContentManager>().As<IContentManager>().SingleInstance();
builder.RegisterType<DefaultContentManagerSession>().As<IContentManagerSession>();
builder.RegisterInstance(new Mock<IContentDefinitionManager>().Object);
builder.RegisterType<AlphaHandler>().As<IContentHandler>();
builder.RegisterType<BetaHandler>().As<IContentHandler>();

View File

@@ -2,8 +2,11 @@
using System.Diagnostics;
using System.Linq;
using Autofac;
using Moq;
using NHibernate;
using NUnit.Framework;
using Orchard.ContentManagement.MetaData;
using Orchard.ContentManagement.MetaData.Builders;
using Orchard.Data;
using Orchard.ContentManagement;
using Orchard.ContentManagement.Handlers;
@@ -18,6 +21,7 @@ namespace Orchard.Tests.ContentManagement {
private IContentManager _manager;
private ISessionFactory _sessionFactory;
private ISession _session;
private Mock<IContentDefinitionManager> _contentDefinitionManager;
[TestFixtureSetUp]
public void InitFixture() {
@@ -39,10 +43,12 @@ namespace Orchard.Tests.ContentManagement {
[SetUp]
public void Init() {
_contentDefinitionManager = new Mock<IContentDefinitionManager>();
var builder = new ContainerBuilder();
//builder.RegisterModule(new ImplicitCollectionSupportModule());
builder.RegisterType<DefaultContentManager>().As<IContentManager>();
builder.RegisterType<DefaultContentManagerSession>().As<IContentManagerSession>();
builder.RegisterInstance(_contentDefinitionManager.Object);
builder.RegisterType<AlphaHandler>().As<IContentHandler>();
builder.RegisterType<BetaHandler>().As<IContentHandler>();
@@ -459,6 +465,40 @@ namespace Orchard.Tests.ContentManagement {
Assert.That(gammas[3].Version, Is.EqualTo(4));
}
[Test]
public void EmptyTypeDefinitionShouldBeCreatedIfNotAlreadyDefined() {
var contentItem = _manager.New("no-such-type");
Assert.That(contentItem.ContentType, Is.EqualTo("no-such-type"));
Assert.That(contentItem.TypeDefinition, Is.Not.Null);
Assert.That(contentItem.TypeDefinition.Name, Is.EqualTo("no-such-type"));
Assert.That(contentItem.TypeDefinition.Settings.Count(), Is.EqualTo(0));
Assert.That(contentItem.TypeDefinition.Parts.Count(), Is.EqualTo(0));
}
[Test]
public void ExistingTypeAndPartDefinitionShouldBeUsed() {
var alphaType = new ContentTypeDefinitionBuilder()
.Named("alpha")
.WithSetting("x", "1")
.WithPart("foo")
.WithPart("Flavored", part => part.WithSetting("spin", "clockwise"))
.Build();
_contentDefinitionManager
.Setup(x => x.GetTypeDefinition("alpha"))
.Returns(alphaType);
var contentItem = _manager.New("alpha");
Assert.That(contentItem.ContentType, Is.EqualTo("alpha"));
Assert.That(contentItem.TypeDefinition, Is.Not.Null);
Assert.That(contentItem.TypeDefinition, Is.SameAs(alphaType));
var flavored = contentItem.As<Flavored>();
Assert.That(flavored, Is.Not.Null);
Assert.That(flavored.TypePartDefinition, Is.Not.Null);
Assert.That(flavored.TypePartDefinition.Settings["spin"], Is.EqualTo("clockwise"));
}
}
}

View File

@@ -1,6 +1,7 @@
using NUnit.Framework;
using Orchard.ContentManagement;
using Orchard.ContentManagement.Handlers;
using Orchard.ContentManagement.MetaData.Builders;
namespace Orchard.Tests.ContentManagement.Handlers {
@@ -22,7 +23,7 @@ namespace Orchard.Tests.ContentManagement.Handlers {
public void PartShouldBeAddedBasedOnSimplePredicate() {
var modelDriver = new TestModelHandler();
var builder = new ContentItemBuilder("testing");
var builder = new ContentItemBuilder(new ContentTypeDefinitionBuilder().Named("testing").Build());
((IContentHandler)modelDriver).Activating(new ActivatingContentContext { Builder = builder, ContentType = "testing" });
var model = builder.Build();
Assert.That(model.Is<TestModelPart>(), Is.True);

View File

@@ -5,6 +5,7 @@ using System.Text;
using NUnit.Framework;
using Orchard.ContentManagement;
using Orchard.ContentManagement.Handlers;
using Orchard.ContentManagement.MetaData.Builders;
using Orchard.Tests.ContentManagement.Models;
namespace Orchard.Tests.ContentManagement.Handlers {
@@ -12,21 +13,21 @@ namespace Orchard.Tests.ContentManagement.Handlers {
public class ModelBuilderTests {
[Test]
public void BuilderShouldReturnWorkingModelWithTypeAndId() {
var builder = new ContentItemBuilder("foo");
var builder = new ContentItemBuilder(new ContentTypeDefinitionBuilder().Named("foo").Build());
var model = builder.Build();
Assert.That(model.ContentType, Is.EqualTo("foo"));
}
[Test]
public void IdShouldDefaultToZero() {
var builder = new ContentItemBuilder("foo");
var builder = new ContentItemBuilder(new ContentTypeDefinitionBuilder().Named("foo").Build());
var model = builder.Build();
Assert.That(model.Id, Is.EqualTo(0));
}
[Test]
public void WeldShouldAddPartToModel() {
var builder = new ContentItemBuilder("foo");
var builder = new ContentItemBuilder(new ContentTypeDefinitionBuilder().Named("foo").Build());
builder.Weld<Alpha>();
var model = builder.Build();

View File

@@ -0,0 +1,52 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using NUnit.Framework;
using Orchard.ContentManagement.MetaData;
using Orchard.ContentManagement.MetaData.Builders;
using Orchard.ContentManagement.MetaData.Services;
namespace Orchard.Tests.ContentManagement.MetaData.Services {
[TestFixture]
public class ContentDefinitionReaderTests {
private IContentDefinitionReader _reader;
[SetUp]
public void Init() {
_reader = new ContentDefinitionReader(new SettingsFormatter());
}
[Test]
public void ReadingElementSetsName() {
var builder = new ContentTypeDefinitionBuilder();
_reader.Merge(new XElement("foo"), builder);
var type = builder.Build();
Assert.That(type.Name, Is.EqualTo("foo"));
}
[Test]
public void AttributesAreAppliedAsSettings() {
var builder = new ContentTypeDefinitionBuilder();
_reader.Merge(new XElement("foo", new XAttribute("x", "1")), builder);
var type = builder.Build();
Assert.That(type.Settings["x"], Is.EqualTo("1"));
}
[Test]
public void ChildElementsAreAddedAsPartsWithSettings() {
var builder = new ContentTypeDefinitionBuilder();
_reader.Merge(new XElement("foo", new XElement("bar", new XAttribute("y", "2"))), builder);
var type = builder.Build();
Assert.That(type.Parts.Single().PartDefinition.Name, Is.EqualTo("bar"));
Assert.That(type.Parts.Single().Settings["y"], Is.EqualTo("2"));
}
[Test, Ignore("Parts can be removed by name")]
public void PartsCanBeRemovedByNameWhenImporting() {
Assert.Fail();
}
}
}

View File

@@ -0,0 +1,55 @@
using System.Linq;
using System.Xml;
using System.Xml.Linq;
using NUnit.Framework;
using Orchard.ContentManagement.MetaData.Builders;
using Orchard.ContentManagement.MetaData.Services;
namespace Orchard.Tests.ContentManagement.MetaData.Services {
[TestFixture]
public class ContentDefinitionWriterTests {
private ContentDefinitionWriter _writer;
[SetUp]
public void Init() {
_writer = new ContentDefinitionWriter(new SettingsFormatter());
}
[Test]
public void CreatesElementWithEncodedContentTypeName() {
var alphaInfoset = _writer.Export(new ContentTypeDefinitionBuilder().Named("alpha").Build());
var betaInfoset = _writer.Export(new ContentTypeDefinitionBuilder().Named(":beta").Build());
var gammaInfoset = _writer.Export(new ContentTypeDefinitionBuilder().Named(" g a m m a ").Build());
var deltaInfoset = _writer.Export(new ContentTypeDefinitionBuilder().Named("del\r\nta").Build());
Assert.That(XmlConvert.DecodeName(alphaInfoset.Name.LocalName), Is.EqualTo("alpha"));
Assert.That(XmlConvert.DecodeName(betaInfoset.Name.LocalName), Is.EqualTo(":beta"));
Assert.That(XmlConvert.DecodeName(gammaInfoset.Name.LocalName), Is.EqualTo(" g a m m a "));
Assert.That(XmlConvert.DecodeName(deltaInfoset.Name.LocalName), Is.EqualTo("del\r\nta"));
}
[Test]
public void ChildElementsArePartNames() {
var alphaInfoset = _writer.Export(new ContentTypeDefinitionBuilder().Named("alpha").WithPart(":beta").WithPart("del\r\nta").Build());
Assert.That(XmlConvert.DecodeName(alphaInfoset.Name.LocalName), Is.EqualTo("alpha"));
Assert.That(alphaInfoset.Elements().Count(), Is.EqualTo(2));
Assert.That(alphaInfoset.Elements().Select(elt => elt.Name.LocalName), Has.Some.EqualTo(XmlConvert.EncodeLocalName(":beta")));
Assert.That(alphaInfoset.Elements().Select(elt => elt.Name.LocalName), Has.Some.EqualTo(XmlConvert.EncodeLocalName("del\r\nta")));
}
[Test]
public void TypeAndTypePartSettingsAreAttributes() {
var alpha = new ContentTypeDefinitionBuilder()
.Named("alpha")
.WithSetting("x", "1")
.WithPart("beta", part => part.WithSetting(" y ", "2"))
.Build();
var alphaInfoset = _writer.Export(alpha);
Assert.That(alphaInfoset.Attributes("x").Single().Value, Is.EqualTo("1"));
Assert.That(alphaInfoset.Elements("beta").Attributes(XmlConvert.EncodeLocalName(" y ")).Single().Value, Is.EqualTo("2"));
}
}
}

View File

@@ -154,6 +154,8 @@
<Compile Include="ContentManagement\Handlers\ContentHandlerTests.cs" />
<Compile Include="ContentManagement\Handlers\ModelBuilderTests.cs" />
<Compile Include="ContentManagement\MetaData\Builders\ContentTypeDefinitionBuilderTests.cs" />
<Compile Include="ContentManagement\MetaData\Services\ContentDefinitionReaderTests.cs" />
<Compile Include="ContentManagement\MetaData\Services\ContentDefinitionWriterTests.cs" />
<Compile Include="ContentManagement\Models\Alpha.cs" />
<Compile Include="ContentManagement\Models\AlphaHandler.cs" />
<Compile Include="ContentManagement\Models\Beta.cs" />

View File

@@ -1811,7 +1811,7 @@ msgstr "Changer le mot de passe"
#: ~/Modules/Orchard.Users/Views/Account/ChangePassword.ascx
#| msgid : "Use the form below to change your password."
msgid "Use the form below to change your password."
msgstr "Veuillez utiliser le forumulaire ci-dessous pour changer votre mot de passe."
msgstr "Veuillez utiliser le formulaire ci-dessous pour changer votre mot de passe."
#: ~/Modules/Orchard.Users/Views/Account/ChangePassword.ascx
#| msgid : "New passwords are required to be a minimum of {0} characters in length."

View File

@@ -1,7 +1,8 @@
using Orchard.ContentManagement;
using Orchard.ContentManagement.Aspects;
namespace Orchard.Core.Common.Models {
public class RoutableAspect : ContentPart<RoutableRecord> {
public class RoutableAspect : ContentPart<RoutableRecord>, IRoutableAspect {
public string ContentItemBasePath { get; set; }
public string Title {
@@ -14,4 +15,4 @@ namespace Orchard.Core.Common.Models {
set { Record.Slug = value; }
}
}
}
}

View File

@@ -1,4 +1,5 @@
using System.ComponentModel.DataAnnotations;
using System;
using System.ComponentModel.DataAnnotations;
using Orchard.ContentManagement.Records;
namespace Orchard.Core.Common.Models {
@@ -7,5 +8,8 @@ namespace Orchard.Core.Common.Models {
public virtual string Title { get; set; }
public virtual string Slug { get; set; }
[StringLength(2048)]
public virtual string Path { get; set; }
}
}
}

View File

@@ -1,7 +1,7 @@
<%@ Control Language="C#" Inherits="Orchard.Mvc.ViewUserControl<BodyEditorViewModel>" %>
<%@ Import Namespace="Orchard.Core.Common.ViewModels" %>
<fieldset>
<label><%=_Encoded("Body")%></label>
<label><%: T("Body")%></label>
<%=Html.Partial("EditorTemplates/" + Model.TextEditorTemplate, Model) %>
<%=Html.ValidationMessageFor(m => m.Text) %>
<%: Html.ValidationMessageFor(m => m.Text) %>
</fieldset>

View File

@@ -1,7 +1,7 @@
<%@ Control Language="C#" Inherits="Orchard.Mvc.ViewUserControl<OwnerEditorViewModel>" %>
<%@ Import Namespace="Orchard.Core.Common.ViewModels"%>
<fieldset>
<%=Html.LabelFor(m=>m.Owner) %>
<%=Html.EditorFor(m=>m.Owner) %>
<%=Html.ValidationMessageFor(m=>m.Owner) %>
<%: Html.LabelFor(m=>m.Owner) %>
<%: Html.EditorFor(m=>m.Owner) %>
<%: Html.ValidationMessageFor(m=>m.Owner) %>
</fieldset>

View File

@@ -6,12 +6,12 @@
<%@ Import Namespace="Orchard.Core.Common.ViewModels"%>
<% Html.RegisterFootScript("jquery.slugify.js"); %>
<fieldset>
<%=Html.LabelFor(m => m.Title) %>
<%=Html.TextBoxFor(m => m.Title, new { @class = "large text" }) %>
<%: Html.LabelFor(m => m.Title) %>
<%: Html.TextBoxFor(m => m.Title, new { @class = "large text" }) %>
</fieldset>
<fieldset class="permalink">
<label class="sub" for="Slug"><%=_Encoded("Permalink")%><br /><span><%=Html.Encode(Request.ToRootUrlString())%>/<%=Html.Encode(Model.RoutableAspect.ContentItemBasePath) %></span></label>
<span><%=Html.TextBoxFor(m => m.Slug, new { @class = "text" })%></span>
<label class="sub" for="Slug"><%: T("Permalink")%><br /><span><%: Request.ToRootUrlString() %>/<%: Model.RoutableAspect.ContentItemBasePath %></span></label>
<span><%: Html.TextBoxFor(m => m.Slug, new { @class = "text" })%></span>
</fieldset>
<% using (this.Capture("end-of-page-scripts")) { %>
<script type="text/javascript">
@@ -24,7 +24,8 @@
url:"<%=Url.Slugify() %>",
contentType:"<%=Model.RoutableAspect.ContentItem.ContentType %>",
id:"<%=Model.RoutableAspect.ContentItem.Id %>"<%
var container = Model.RoutableAspect.ContentItem.As<ICommonAspect>().Container;
var commonAspect = Model.RoutableAspect.ContentItem.As<ICommonAspect>();
var container = commonAspect != null ? commonAspect.Container : null;
if (container != null) { %>,
containerId:<%=container.ContentItem.Id %><%
} %>

View File

@@ -0,0 +1,19 @@
using Orchard.Localization;
using Orchard.Security;
using Orchard.UI.Navigation;
namespace Orchard.Core.Contents {
public class AdminMenu : INavigationProvider {
public Localizer T { get; set; }
public string MenuName { get { return "admin"; } }
public void GetNavigation(NavigationBuilder builder) {
builder.Add(T("Content"), "1",
menu => {
menu.Add(T("Create"), "1.1", item => item.Action("Create", "Admin", new { area = "Contents" }));
menu.Add(T("List"), "1.2", item => item.Action("List", "Admin", new { area = "Contents" }));
menu.Add(T("Types"), "1.3", item => item.Action("Types", "Admin", new { area = "Contents" }));
});
}
}
}

View File

@@ -0,0 +1,166 @@
using System;
using System.Linq;
using System.Web.Mvc;
using System.Web.Routing;
using Orchard.ContentManagement;
using Orchard.ContentManagement.MetaData;
using Orchard.ContentManagement.Records;
using Orchard.Core.Contents.ViewModels;
using Orchard.Data;
using Orchard.Localization;
using Orchard.Logging;
using Orchard.Mvc.ViewModels;
using Orchard.UI.Notify;
namespace Orchard.Core.Contents.Controllers {
[ValidateInput(false)]
public class AdminController : Controller, IUpdateModel {
private readonly INotifier _notifier;
private readonly IContentDefinitionManager _contentDefinitionManager;
private readonly IContentManager _contentManager;
private readonly ITransactionManager _transactionManager;
public AdminController(
INotifier notifier,
IContentDefinitionManager contentDefinitionManager,
IContentManager contentManager,
ITransactionManager transactionManager) {
_notifier = notifier;
_contentDefinitionManager = contentDefinitionManager;
_contentManager = contentManager;
_transactionManager = transactionManager;
T = NullLocalizer.Instance;
Logger = NullLogger.Instance;
}
public Localizer T { get; set; }
public ILogger Logger { get; set; }
public ActionResult Index() {
return Types();
}
public ActionResult Types() {
return View("Types", new ContentTypeListViewModel {
Types = _contentDefinitionManager.ListTypeDefinitions()
});
}
public ActionResult List(ListContentViewModel model) {
const int pageSize = 20;
var skip = (Math.Max(model.Page ?? 0, 1) - 1) * pageSize;
var query = _contentManager.Query(VersionOptions.Latest);
if (!string.IsNullOrEmpty(model.Id)) {
query = query.ForType(model.Id);
}
var contentItems = query.Slice(skip, pageSize);
model.Entries = contentItems.Select(BuildEntry).ToList();
return View("List", model);
}
private ListContentViewModel.Entry BuildEntry(ContentItem contentItem) {
var entry = new ListContentViewModel.Entry {
ContentItem = contentItem,
ContentItemMetadata = _contentManager.GetItemMetadata(contentItem),
ViewModel = _contentManager.BuildDisplayModel(contentItem, "List"),
};
if (string.IsNullOrEmpty(entry.ContentItemMetadata.DisplayText)) {
entry.ContentItemMetadata.DisplayText = string.Format("[{0}#{1}]", contentItem.ContentType, contentItem.Id);
}
if (entry.ContentItemMetadata.EditorRouteValues == null) {
entry.ContentItemMetadata.EditorRouteValues = new RouteValueDictionary {
{"Area", "Contents"},
{"Controller", "Admin"},
{"Action", "Edit"},
{"Id", contentItem.Id}
};
}
return entry;
}
ActionResult CreatableTypeList() {
var model = new ContentTypeListViewModel {
Types = _contentDefinitionManager.ListTypeDefinitions()
};
return View("CreatableTypeList", model);
}
public ActionResult Create(string id) {
if (string.IsNullOrEmpty(id))
return CreatableTypeList();
var contentItem = _contentManager.New(id);
var model = new CreateItemViewModel {
Id = id,
Content = _contentManager.BuildEditorModel(contentItem)
};
PrepareEditorViewModel(model.Content);
return View("Create", model);
}
[HttpPost]
public ActionResult Create(CreateItemViewModel model) {
var contentItem = _contentManager.New(model.Id);
model.Content = _contentManager.UpdateEditorModel(contentItem, this);
if (ModelState.IsValid) {
_contentManager.Create(contentItem, VersionOptions.Draft);
model.Content = _contentManager.UpdateEditorModel(contentItem, this);
}
if (ModelState.IsValid) {
_contentManager.Publish(contentItem);
}
if (!ModelState.IsValid) {
_transactionManager.Cancel();
PrepareEditorViewModel(model.Content);
return View("Create", model);
}
_notifier.Information(T("Created content item"));
return RedirectToAction("Edit", new RouteValueDictionary { { "Id", contentItem.Id } });
}
public ActionResult Edit(int id) {
var contentItem = _contentManager.Get(id, VersionOptions.Latest);
var model = new EditItemViewModel {
Id = id,
Content = _contentManager.BuildEditorModel(contentItem)
};
PrepareEditorViewModel(model.Content);
return View("Edit", model);
}
[HttpPost]
public ActionResult Edit(EditItemViewModel model) {
var contentItem = _contentManager.Get(model.Id, VersionOptions.DraftRequired);
model.Content = _contentManager.UpdateEditorModel(contentItem, this);
if (!ModelState.IsValid) {
_transactionManager.Cancel();
PrepareEditorViewModel(model.Content);
return View("Edit", model);
}
_contentManager.Publish(contentItem);
return RedirectToAction("Edit", new RouteValueDictionary { { "Id", contentItem.Id } });
}
private void PrepareEditorViewModel(ContentItemViewModel itemViewModel) {
if (string.IsNullOrEmpty(itemViewModel.TemplateName)) {
itemViewModel.TemplateName = "Items/Contents.Item";
}
}
bool IUpdateModel.TryUpdateModel<TModel>(TModel model, string prefix, string[] includeProperties, string[] excludeProperties) {
return TryUpdateModel(model, prefix, includeProperties, excludeProperties);
}
void IUpdateModel.AddModelError(string key, LocalizedString errorMessage) {
ModelState.AddModelError(key, errorMessage.ToString());
}
}
}

View File

@@ -0,0 +1,49 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Orchard.ContentManagement;
using Orchard.Core.Contents.ViewModels;
using Orchard.Mvc.ViewModels;
namespace Orchard.Core.Contents.Controllers {
public class ItemController : Controller {
private readonly IContentManager _contentManager;
public ItemController(IContentManager contentManager) {
_contentManager = contentManager;
}
public ActionResult Display(int id) {
var contentItem = _contentManager.Get(id, VersionOptions.Published);
var model = new DisplayItemViewModel {
Content = _contentManager.BuildDisplayModel(contentItem, "Detail")
};
PrepareDisplayViewModel(model.Content);
return View("Display", model);
}
public ActionResult Preview(int id, int? version) {
var versionOptions = VersionOptions.Latest;
if (version != null) {
versionOptions = VersionOptions.Number((int)version);
}
var contentItem = _contentManager.Get(id, versionOptions);
var model = new DisplayItemViewModel {
Content = _contentManager.BuildDisplayModel(contentItem, "Detail")
};
PrepareDisplayViewModel(model.Content);
return View("Preview", model);
}
private static void PrepareDisplayViewModel(ContentItemViewModel itemViewModel) {
if (string.IsNullOrEmpty(itemViewModel.TemplateName)) {
itemViewModel.TemplateName = "Items/Contents.Item";
}
}
}
}

View File

@@ -0,0 +1,29 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Routing;
using Orchard.ContentManagement.Handlers;
namespace Orchard.Core.Contents.Handlers {
public class ContentsModuleHandler : ContentHandlerBase {
public override void GetContentItemMetadata(GetContentItemMetadataContext context) {
if (context.Metadata.EditorRouteValues == null) {
context.Metadata.EditorRouteValues = new RouteValueDictionary {
{"Area", "Contents"},
{"Controller", "Admin"},
{"Action", "Edit"},
{"Id", context.ContentItem.Id}
};
}
if (context.Metadata.DisplayRouteValues == null) {
context.Metadata.DisplayRouteValues = new RouteValueDictionary {
{"Area", "Contents"},
{"Controller", "Item"},
{"Action", "Display"},
{"Id", context.ContentItem.Id}
};
}
}
}
}

View File

@@ -0,0 +1,11 @@
Name: Contents
antiforgery: enabled
author: The Orchard Team
website: http://orchardproject.net
version: 0.1
orchardversion: 0.1.2010.0312
description: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas consectetur consequat risus, vel blandit arcu tincidunt eget. Nam rutrum nulla vestibulum dolor dapibus sagittis. Vivamus convallis faucibus accumsan. Suspendisse sapien enim, cursus at dignissim a, sollicitudin sit amet est. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Donec sed urna magna, in luctus nulla. Pellentesque erat ipsum, convallis sed molestie tempus, mattis vel leo metus.
features:
Contents:
Description: Default controllers for some content types.
Category: Core

View File

@@ -0,0 +1,10 @@
using System;
using System.Collections.Generic;
using Orchard.ContentManagement.MetaData.Models;
using Orchard.Mvc.ViewModels;
namespace Orchard.Core.Contents.ViewModels {
public class ContentTypeListViewModel : BaseViewModel {
public IEnumerable<ContentTypeDefinition> Types { get; set; }
}
}

View File

@@ -0,0 +1,8 @@
using Orchard.Mvc.ViewModels;
namespace Orchard.Core.Contents.ViewModels {
public class CreateItemViewModel : BaseViewModel {
public string Id { get; set; }
public ContentItemViewModel Content { get; set; }
}
}

View File

@@ -0,0 +1,11 @@
using Orchard.Mvc.ViewModels;
namespace Orchard.Core.Contents.ViewModels {
public class EditItemViewModel : BaseViewModel {
public int Id { get; set; }
public ContentItemViewModel Content { get; set; }
}
public class DisplayItemViewModel : BaseViewModel {
public ContentItemViewModel Content { get; set; }
}
}

View File

@@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using Orchard.ContentManagement;
using Orchard.Mvc.ViewModels;
namespace Orchard.Core.Contents.ViewModels {
public class ListContentViewModel : BaseViewModel {
public string Id { get; set; }
public int? Page { get; set; }
public IList<Entry> Entries { get; set; }
public class Entry {
public ContentItem ContentItem { get; set; }
public ContentItemMetadata ContentItemMetadata { get; set; }
public ContentItemViewModel ViewModel { get; set; }
}
}
}

View File

@@ -0,0 +1,12 @@
<%@ Page Language="C#" Inherits="Orchard.Mvc.ViewPage<ContentTypeListViewModel>" %>
<%@ Import Namespace="Orchard.Core.Contents.ViewModels" %>
<% Html.AddTitleParts(T("Create Content").ToString()); %>
<p>
Create content</p>
<ul>
<% foreach (var t in Model.Types) {%>
<li>
<%:Html.ActionLink(t.Name, "Create", new RouteValueDictionary{{"Area","Contents"},{"Id",t.Name}}) %></li>
<%} %>
</ul>

View File

@@ -0,0 +1,8 @@
<%@ Page Language="C#" Inherits="Orchard.Mvc.ViewPage<CreateItemViewModel>" %>
<%@ Import Namespace="Orchard.Core.Contents.ViewModels" %>
<% Html.AddTitleParts(T("Create Content").ToString()); %>
<% using (Html.BeginFormAntiForgeryPost()) { %>
<%:Html.ValidationSummary() %>
<%:Html.EditorForItem(m=>m.Content) %>
<%} %>

View File

@@ -0,0 +1,8 @@
<%@ Page Language="C#" Inherits="Orchard.Mvc.ViewPage<EditItemViewModel>" %>
<%@ Import Namespace="Orchard.Core.Contents.ViewModels" %>
<% Html.AddTitleParts(T("Edit Content").ToString()); %>
<% using (Html.BeginFormAntiForgeryPost()) { %>
<%:Html.ValidationSummary() %>
<%:Html.EditorForItem(m=>m.Content) %>
<%} %>

View File

@@ -0,0 +1,33 @@
<%@ Page Language="C#" Inherits="Orchard.Mvc.ViewPage<ListContentViewModel>" %>
<%@ Import Namespace="Orchard.Core.Contents.ViewModels" %>
<% Html.AddTitleParts(T("Browse Contents").ToString()); %>
<p>
Browse Contents</p>
<table>
<% foreach (var t in Model.Entries) {%>
<tr>
<td>
<%:t.ContentItem.Id %>.
</td>
<td>
<%:t.ContentItem.ContentType %>
</td>
<td>
ver #<%:t.ContentItem.Version %>
</td>
<td>
<%if (t.ContentItemMetadata.DisplayRouteValues != null) {%>
<%:Html.ActionLink(t.ContentItemMetadata.DisplayText, t.ContentItemMetadata.DisplayRouteValues["Action"].ToString(), t.ContentItemMetadata.DisplayRouteValues)%>
<%}%>
</td>
<td>
<%if (t.ContentItemMetadata.EditorRouteValues != null) {%>
<%:Html.ActionLink("edit", t.ContentItemMetadata.EditorRouteValues["Action"].ToString(), t.ContentItemMetadata.EditorRouteValues)%>
<%}%>
</td>
</tr>
<%} %>
</table>
<p>
<%:Html.ActionLink("Create new item", "Create", "Admin", new RouteValueDictionary{{"Area","Contents"},{"Id",Model.Id}}, new Dictionary<string, object>()) %></p>

View File

@@ -0,0 +1,24 @@
<%@ Page Language="C#" Inherits="Orchard.Mvc.ViewPage<ContentTypeListViewModel>" %>
<%@ Import Namespace="Orchard.Core.Contents.ViewModels" %>
<% Html.AddTitleParts(T("Create Content").ToString()); %>
<p>
Create content</p>
<table>
<% foreach (var t in Model.Types) {%>
<tr>
<td>
<%:t.Name %>
</td>
<td>
<%:Html.ActionLink(T("List Items").ToString(), "List", "Admin", new RouteValueDictionary{{"Area","Contents"},{"Id",t.Name}}, new Dictionary<string, object>()) %>
</td>
<td>
<%:Html.ActionLink(T("Create Item").ToString(), "Create", "Admin", new RouteValueDictionary{{"Area","Contents"},{"Id",t.Name}}, new Dictionary<string, object>()) %>
</td>
<td>
<%:Html.ActionLink(T("Edit Type").ToString(), "ContentTypeList", "Admin", new RouteValueDictionary{{"Area","Orchard.MetaData"},{"Id",t.Name}}, new Dictionary<string, object>()) %>
</td>
</tr>
<%} %>
</table>

View File

@@ -0,0 +1,11 @@
<%@ Control Language="C#" Inherits="Orchard.Mvc.ViewUserControl<ContentItemViewModel>" %>
<%@ Import Namespace="Orchard.Mvc.ViewModels" %>
<%@ Import Namespace="Orchard.ContentManagement.Aspects" %>
<%@ Import Namespace="Orchard.ContentManagement" %>
<%var routable = Model.Item.As<IRoutableAspect>();
if (routable != null && !string.IsNullOrEmpty(routable.Title)) {%>
<h1>
<%:routable.Title%></h1>
<%} %>
<% Html.Zone("primary", ":manage :metadata");
Html.ZonesAny(); %>

View File

@@ -0,0 +1,14 @@
<%@ Control Language="C#" Inherits="Orchard.Mvc.ViewUserControl<ContentItemViewModel>" %>
<%@ Import Namespace="Orchard.Mvc.ViewModels"%>
<div class="sections">
<div class="primary"><%
Html.Zone("primary");
Html.ZonesExcept("secondary"); %>
</div>
<div class="secondary">
<% Html.Zone("secondary");%>
<fieldset>
<input class="button primaryAction" type="submit" name="submit.Save" value="<%=_Encoded("Save") %>"/>
</fieldset>
</div>
</div>

View File

@@ -0,0 +1,5 @@
<%@ Page Language="C#" Inherits="Orchard.Mvc.ViewPage<Orchard.Core.Contents.ViewModels.DisplayItemViewModel>" %>
<div class="preview">
<%=Html.DisplayForItem(m=>m.Content) %>
</div>

View File

@@ -0,0 +1,3 @@
<%@ Page Language="C#" Inherits="Orchard.Mvc.ViewPage<Orchard.Core.Contents.ViewModels.DisplayItemViewModel>" %>
<%=Html.DisplayForItem(m=>m.Content) %>

View File

@@ -0,0 +1,34 @@
<?xml version="1.0"?>
<configuration>
<system.web>
<httpHandlers>
<add path="*" verb="*"
type="System.Web.HttpNotFoundHandler"/>
</httpHandlers>
<!--
Enabling request validation in view pages would cause validation to occur
after the input has already been processed by the controller. By default
MVC performs request validation before a controller processes the input.
To change this behavior apply the ValidateInputAttribute to a
controller or action.
-->
<pages
validateRequest="false"
pageParserFilterType="System.Web.Mvc.ViewTypeParserFilter, System.Web.Mvc, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
pageBaseType="System.Web.Mvc.ViewPage, System.Web.Mvc, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
userControlBaseType="System.Web.Mvc.ViewUserControl, System.Web.Mvc, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
<controls>
<add assembly="System.Web.Mvc, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" namespace="System.Web.Mvc" tagPrefix="mvc" />
</controls>
</pages>
</system.web>
<system.webServer>
<validation validateIntegratedModeConfiguration="false"/>
<handlers>
<remove name="BlockViewHandler"/>
<add name="BlockViewHandler" path="*" verb="*" preCondition="integratedMode" type="System.Web.HttpNotFoundHandler"/>
</handlers>
</system.webServer>
</configuration>

View File

@@ -1,6 +1,6 @@
<%@ Control Language="C#" Inherits="Orchard.Mvc.ViewUserControl<AdminViewModel>" %>
<%@ Import Namespace="Orchard.Mvc.ViewModels"%>
<h1><%=Html.TitleForPage(T("Welcome to Orchard").ToString())%></h1>
<p><%=_Encoded("This is the place where you can manage your web site, its appearance and its contents. Please take a moment to explore the different menu items on the left of the screen to familiarize yourself with the features of the application. For example, try to change the theme through the “Manage Themes” menu entry. You can also create new pages and manage existing ones through the “Manage Pages” menu entry or create blogs through “Manage Blogs”.") %></p>
<p><%=_Encoded("Have fun!") %><br /><%=_Encoded("The Orchard Team") %></p>
<h1><%: Html.TitleForPage(T("Welcome to Orchard").ToString())%></h1>
<p><%: T("This is the place where you can manage your web site, its appearance and its contents. Please take a moment to explore the different menu items on the left of the screen to familiarize yourself with the features of the application. For example, try to change the theme through the “Manage Themes” menu entry. You can also create new pages and manage existing ones through the “Manage Pages” menu entry or create blogs through “Manage Blogs”.") %></p>
<p><%: T("Have fun!") %><br /><%: T("The Orchard Team") %></p>

View File

@@ -5,17 +5,24 @@ using Orchard.Commands;
using Orchard.ContentManagement;
using Orchard.Indexing;
using Orchard.Security;
using Orchard.Tasks.Indexing;
namespace Orchard.Core.Indexing.Commands {
public class IndexingCommands : DefaultOrchardCommandHandler {
private readonly IEnumerable<IIndexNotifierHandler> _indexNotifierHandlers;
private readonly IIndexManager _indexManager;
private readonly IIndexingTaskManager _indexingTaskManager;
private readonly IContentManager _contentManager;
private const string SearchIndexName = "Search";
public IndexingCommands(
IEnumerable<IIndexNotifierHandler> indexNotifierHandlers,
IIndexManager indexManager) {
IIndexManager indexManager,
IIndexingTaskManager indexingTaskManager,
IContentManager contentManager) {
_indexNotifierHandlers = indexNotifierHandlers;
_indexingTaskManager = indexingTaskManager;
_contentManager = contentManager;
_indexManager = indexManager;
}
@@ -25,6 +32,9 @@ namespace Orchard.Core.Indexing.Commands {
[OrchardSwitch]
public string Query { get; set; }
[OrchardSwitch]
public string ContentItemId { get; set; }
[CommandName("index update")]
[CommandHelp("index update [/IndexName:<index name>]\r\n\t" + "Updates the index with the specified <index name>, or the search index if not specified")]
[OrchardSwitches("IndexName")]
@@ -97,5 +107,36 @@ namespace Orchard.Core.Indexing.Commands {
Context.Output.WriteLine("Number of indexed documents: {0}", _indexManager.GetSearchIndexProvider().NumDocs(indexName));
return "";
}
[CommandName("index refresh")]
[CommandHelp("index refresh /ContenItem:<content item id> \r\n\t" + "Refreshes the index for the specifed <content item id>")]
[OrchardSwitches("ContentItem")]
public string Refresh() {
int contenItemId;
if ( !int.TryParse(ContentItemId, out contenItemId) ) {
return "Invalid content item id. Not an integer.";
}
var contentItem = _contentManager.Get(contenItemId);
_indexingTaskManager.CreateUpdateIndexTask(contentItem);
return "Content Item marked for reindexing";
}
[CommandName("index delete")]
[CommandHelp("index delete /ContenItem:<content item id>\r\n\t" + "Deletes the specifed <content item id> from the index")]
[OrchardSwitches("ContentItem")]
public string Delete() {
int contenItemId;
if(!int.TryParse(ContentItemId, out contenItemId)) {
return "Invalid content item id. Not an integer.";
}
var contentItem = _contentManager.Get(contenItemId);
_indexingTaskManager.CreateDeleteIndexTask(contentItem);
return "Content Item marked for deletion";
}
}
}

View File

@@ -12,13 +12,17 @@ namespace Orchard.Core.Indexing.Lucene {
public List<AbstractField> Fields { get; private set; }
private AbstractField _previousField;
public int Id { get; private set; }
public DefaultIndexDocument(int documentId) {
Fields = new List<AbstractField>();
SetContentItemId(documentId);
IsDirty = false;
}
public bool IsDirty { get; private set; }
public IIndexDocument Add(string name, string value) {
return Add(name, value, false);
}
@@ -35,36 +39,42 @@ namespace Orchard.Core.Indexing.Lucene {
}
_previousField = new Field(name, value, Field.Store.YES, Field.Index.ANALYZED);
IsDirty = true;
return this;
}
public IIndexDocument Add(string name, DateTime value) {
AppendPreviousField();
_previousField = new Field(name, DateTools.DateToString(value, DateTools.Resolution.SECOND), Field.Store.YES, Field.Index.NOT_ANALYZED);
IsDirty = true;
return this;
}
public IIndexDocument Add(string name, int value) {
AppendPreviousField();
_previousField = new NumericField(name, Field.Store.YES, true).SetIntValue(value);
IsDirty = true;
return this;
}
public IIndexDocument Add(string name, bool value) {
AppendPreviousField();
_previousField = new Field(name, value.ToString().ToLower(), Field.Store.YES, Field.Index.NOT_ANALYZED);
IsDirty = true;
return this;
}
public IIndexDocument Add(string name, float value) {
AppendPreviousField();
_previousField = new NumericField(name, Field.Store.YES, true).SetFloatValue(value);
IsDirty = true;
return this;
}
public IIndexDocument Add(string name, object value) {
AppendPreviousField();
_previousField = new Field(name, value.ToString(), Field.Store.NO, Field.Index.NOT_ANALYZED);
IsDirty = true;
return this;
}

View File

@@ -23,7 +23,7 @@ namespace Orchard.Core.Indexing.Lucene {
private readonly IAppDataFolder _appDataFolder;
private readonly ShellSettings _shellSettings;
public static readonly Version LuceneVersion = Version.LUCENE_29;
private readonly Analyzer _analyzer = new StandardAnalyzer(LuceneVersion);
private readonly Analyzer _analyzer ;
private readonly string _basePath;
public static readonly DateTime DefaultMinDateTime = new DateTime(1980, 1, 1);
public static readonly string Settings = "Settings";
@@ -34,6 +34,7 @@ namespace Orchard.Core.Indexing.Lucene {
public DefaultIndexProvider(IAppDataFolder appDataFolder, ShellSettings shellSettings) {
_appDataFolder = appDataFolder;
_shellSettings = shellSettings;
_analyzer = CreateAnalyzer();
// TODO: (sebros) Find a common way to get where tenant's specific files should go. "Sites/Tenant" is hard coded in multiple places
_basePath = Path.Combine("Sites", _shellSettings.Name, "Indexes");
@@ -44,6 +45,11 @@ namespace Orchard.Core.Indexing.Lucene {
EnsureDirectoryExists();
}
public static Analyzer CreateAnalyzer() {
// StandardAnalyzer does lower-case and stop-word filtering. It also removes punctuation
return new StandardAnalyzer(LuceneVersion);
}
private void EnsureDirectoryExists() {
var directory = new DirectoryInfo(_appDataFolder.MapPath(_basePath));
if(!directory.Exists) {

View File

@@ -2,12 +2,15 @@
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using Lucene.Net.Analysis;
using Lucene.Net.Analysis.Tokenattributes;
using Lucene.Net.Index;
using Lucene.Net.Search;
using Lucene.Net.Store;
using Orchard.Logging;
using Lucene.Net.Documents;
using Orchard.Indexing;
using Lucene.Net.QueryParsers;
namespace Orchard.Core.Indexing.Lucene {
public class DefaultSearchBuilder : ISearchBuilder {
@@ -23,6 +26,9 @@ namespace Orchard.Core.Indexing.Lucene {
private readonly Dictionary<string, DateTime> _after;
private string _sort;
private bool _sortDescending;
private string _parse;
private readonly Analyzer _analyzer;
private string _defaultField;
public ILogger Logger { get; set; }
@@ -37,9 +43,21 @@ namespace Orchard.Core.Indexing.Lucene {
_fields = new Dictionary<string, Query[]>();
_sort = String.Empty;
_sortDescending = true;
_parse = String.Empty;
_analyzer = DefaultIndexProvider.CreateAnalyzer();
}
public ISearchBuilder Parse(string query) {
public ISearchBuilder Parse(string defaultField, string query) {
if ( String.IsNullOrWhiteSpace(defaultField) ) {
throw new ArgumentException("Default field can't be empty");
}
if ( String.IsNullOrWhiteSpace(query) ) {
throw new ArgumentException("Query can't be empty");
}
_defaultField = defaultField;
_parse = query;
return this;
}
@@ -49,8 +67,17 @@ namespace Orchard.Core.Indexing.Lucene {
public ISearchBuilder WithField(string field, string value, bool wildcardSearch) {
_fields[field] = value.Split(' ')
var tokens = new List<string>();
using(var sr = new System.IO.StringReader(value)) {
var stream = _analyzer.TokenStream(field, sr);
while(stream.IncrementToken()) {
tokens.Add(((TermAttribute)stream.GetAttribute(typeof(TermAttribute))).Term());
}
}
_fields[field] = tokens
.Where(k => !String.IsNullOrWhiteSpace(k))
.Select(QueryParser.Escape)
.Select(k => wildcardSearch ? (Query)new PrefixQuery(new Term(field, k)) : new TermQuery(new Term(k)))
.ToArray();
@@ -93,6 +120,10 @@ namespace Orchard.Core.Indexing.Lucene {
}
private Query CreateQuery() {
if(!String.IsNullOrWhiteSpace(_parse)) {
return new QueryParser(DefaultIndexProvider.LuceneVersion, _defaultField, DefaultIndexProvider.CreateAnalyzer()).Parse(_parse);
}
var query = new BooleanQuery();
if ( _fields.Keys.Count > 0 ) { // apply specific filters if defined
@@ -124,7 +155,16 @@ namespace Orchard.Core.Indexing.Lucene {
public IEnumerable<ISearchHit> Search() {
var query = CreateQuery();
var searcher = new IndexSearcher(_directory, true);
IndexSearcher searcher;
try {
searcher = new IndexSearcher(_directory, true);
}
catch {
// index might not exist if it has been rebuilt
Logger.Information("Attempt to read a none existing index");
return Enumerable.Empty<ISearchHit>();
}
try {
var sort = String.IsNullOrEmpty(_sort)
@@ -157,8 +197,17 @@ namespace Orchard.Core.Indexing.Lucene {
public int Count() {
var query = CreateQuery();
IndexSearcher searcher;
try {
searcher = new IndexSearcher(_directory, true);
}
catch {
// index might not exist if it has been rebuilt
Logger.Information("Attempt to read a none existing index");
return 0;
}
var searcher = new IndexSearcher(_directory, true);
try {
var hits = searcher.Search(query, Int16.MaxValue);
Logger.Information("Search results: {0}", hits.scoreDocs.Length);

View File

@@ -91,10 +91,12 @@ namespace Orchard.Core.Indexing.Services {
handler.Indexing(context);
}
updateIndexDocuments.Add(context.IndexDocument);
if ( context.IndexDocument.IsDirty ) {
updateIndexDocuments.Add(context.IndexDocument);
foreach (var handler in _handlers) {
handler.Indexed(context);
foreach ( var handler in _handlers ) {
handler.Indexed(context);
}
}
}
catch (Exception ex) {
@@ -111,10 +113,11 @@ namespace Orchard.Core.Indexing.Services {
_indexProvider.SetLastIndexUtc(SearchIndexName, _clock.UtcNow);
// retrieve not yet processed tasks
var taskRecords = _repository.Fetch(x => x.CreatedUtc >= lastIndexing)
var taskRecords = _repository.Fetch(x => x.CreatedUtc > lastIndexing)
.ToArray();
if (taskRecords.Length == 0)
// nothing to do ?
if (taskRecords.Length + updateIndexDocuments.Count == 0)
return;
Logger.Information("Processing {0} indexing tasks", taskRecords.Length);
@@ -146,11 +149,14 @@ namespace Orchard.Core.Indexing.Services {
handler.Indexing(context);
}
updateIndexDocuments.Add(context.IndexDocument);
foreach (var handler in _handlers) {
handler.Indexed(context);
if ( context.IndexDocument.IsDirty ) {
updateIndexDocuments.Add(context.IndexDocument);
foreach (var handler in _handlers) {
handler.Indexed(context);
}
}
}
catch (Exception ex) {
Logger.Warning(ex, "Unable to process indexing task #{0}", taskRecord.Id);

View File

@@ -0,0 +1,9 @@
using JetBrains.Annotations;
using Orchard.ContentManagement.Drivers;
using Orchard.Core.Localization.Models;
namespace Orchard.Core.Localization.Drivers {
[UsedImplicitly]
public class LocalizedDriver : ContentPartDriver<Localized> {
}
}

View File

@@ -0,0 +1,48 @@
using JetBrains.Annotations;
using Orchard.Core.Localization.Models;
using Orchard.Data;
using Orchard.Localization;
using Orchard.ContentManagement;
using Orchard.ContentManagement.Handlers;
using Orchard.Localization.Services;
using Orchard.Settings;
namespace Orchard.Core.Localization.Handlers {
[UsedImplicitly]
public class LocalizedHandler : ContentHandler {
private readonly ICultureManager _cultureManager;
private readonly IContentManager _contentManager;
public LocalizedHandler(IRepository<LocalizedRecord> localizedRepository, ICultureManager cultureManager, IContentManager contentManager) {
_cultureManager = cultureManager;
_contentManager = contentManager;
T = NullLocalizer.Instance;
Filters.Add(StorageFilter.For(localizedRepository));
OnActivated<Localized>(InitializePart);
OnLoaded<Localized>(LazyLoadHandlers);
OnIndexed<Localized>((context, localized) => context.IndexDocument.Add("culture", localized.Culture != null ? localized.Culture.Culture : _cultureManager.GetSiteCulture()).Store(false).Analyze(false));
}
public Localizer T { get; set; }
void LazyLoadHandlers(LoadContentContext context, Localized localized) {
localized.CultureField.Loader(ctx => _cultureManager.GetCultureById(localized.Record.CultureId));
localized.MasterContentItemField.Loader(ctx => _contentManager.Get(localized.Record.MasterContentItemId));
}
void InitializePart(ActivatedContentContext context, Localized localized) {
localized.CultureField.Setter(cultureRecord => {
localized.Record.CultureId = cultureRecord.Id;
return cultureRecord;
});
localized.MasterContentItemField.Setter(masterContentItem => {
localized.Record.MasterContentItemId = masterContentItem.ContentItem.Id;
return masterContentItem;
});
}
}
}

View File

@@ -0,0 +1,33 @@
using System.Web.Mvc;
using Orchard.ContentManagement;
using Orchard.ContentManagement.Utilities;
using Orchard.Localization.Records;
namespace Orchard.Core.Localization.Models {
public sealed class Localized : ContentPart<LocalizedRecord> {
private readonly LazyField<CultureRecord> _culture = new LazyField<CultureRecord>();
private readonly LazyField<IContent> _masterContentItem = new LazyField<IContent>();
public LazyField<CultureRecord> CultureField { get { return _culture; } }
public LazyField<IContent> MasterContentItemField { get { return _masterContentItem; } }
[HiddenInput(DisplayValue = false)]
public int Id { get { return ContentItem.Id; } }
public CultureRecord Culture {
get { return _culture.Value; }
set { _culture.Value = value; }
}
public IContent MasterContentItem {
get { return _masterContentItem.Value; }
set { _masterContentItem.Value = value; }
}
public bool HasTranslationGroup {
get {
return Record.MasterContentItemId != 0;
}
}
}
}

View File

@@ -0,0 +1,8 @@
using Orchard.ContentManagement.Records;
namespace Orchard.Core.Localization.Models {
public class LocalizedRecord : ContentPartRecord {
public virtual int CultureId { get; set; }
public virtual int MasterContentItemId { get; set; }
}
}

View File

@@ -0,0 +1,11 @@
name: Localization
antiforgery: enabled
author: The Orchard Team
website: http://orchardproject.net
version: 0.1
orchardversion: 0.1.2010.0312
description: Support for localizing content items for cultures.
features:
Localization:
Description: Localize content items.
Category: Core

View File

@@ -2,7 +2,7 @@
<%@ Import Namespace="Orchard.ContentManagement"%>
<%@ Import Namespace="Orchard.Core.Navigation.Models"%>
<%@ Import Namespace="Orchard.Core.Navigation.ViewModels"%>
<h1><%=Html.TitleForPage(T("Manage Main Menu").ToString())%></h1><%
<h1><%: Html.TitleForPage(T("Manage Main Menu").ToString())%></h1><%
using (Html.BeginFormAntiForgeryPost()) { %>
<table class="items">
<colgroup>
@@ -13,9 +13,9 @@ using (Html.BeginFormAntiForgeryPost()) { %>
</colgroup>
<thead>
<tr>
<td scope="col"><%=_Encoded("Text") %></td>
<td scope="col"><%=_Encoded("Position") %></td>
<td scope="col"><%=_Encoded("Url") %></td>
<td scope="col"><%: T("Text") %></td>
<td scope="col"><%: T("Position") %></td>
<td scope="col"><%: T("Url") %></td>
<td scope="col"></td>
</tr>
</thead>
@@ -27,18 +27,18 @@ using (Html.BeginFormAntiForgeryPost()) { %>
<td><input type="text" class="text-box" name="<%=Html.NameOf(m => m.MenuItemEntries[i].MenuItem.Text) %>" value="<%=menuPartEntry.MenuItem.Text %>" /></td>
<td><input type="text" class="text-box" name="<%=Html.NameOf(m => m.MenuItemEntries[i].MenuItem.Position) %>" value="<%=menuPartEntry.MenuItem.Position %>" /></td>
<td><% if (!menuPartEntry.IsMenuItem) { %><input type="text" class="text-box disabled" disabled="disabled" value="<%=menuPartEntry.MenuItem.Url %>" /><% } else { %><input type="text" class="text-box" name="<%=Html.NameOf(m => m.MenuItemEntries[i].MenuItem.Url) %>" value="<%=menuPartEntry.MenuItem.Url %>" /><% } %></td>
<td><input type="hidden" name="<%=Html.NameOf(m => m.MenuItemEntries[i].MenuItemId) %>" value="<%=menuPartEntry.MenuItemId %>" /><a href="<%=Html.AntiForgeryTokenGetUrl(Url.Action("Delete", new {id = menuPartEntry.MenuItemId})) %>" class="remove"><%=_Encoded("Remove") %></a></td>
<td><input type="hidden" name="<%=Html.NameOf(m => m.MenuItemEntries[i].MenuItemId) %>" value="<%=menuPartEntry.MenuItemId %>" /><a href="<%=Html.AntiForgeryTokenGetUrl(Url.Action("Delete", new {id = menuPartEntry.MenuItemId})) %>" class="remove"><%: T("Remove") %></a></td>
</tr><%
++menuPartEntryIndex;
} %>
</tbody>
</table>
<fieldset class="actions"><button type="submit" class="button primaryAction"><%=_Encoded("Update All") %></button></fieldset><%
<fieldset class="actions"><button type="submit" class="button primaryAction"><%: T("Update All") %></button></fieldset><%
}
%>
<h2><%=_Encoded("Add New Item") %></h2><%
using (Html.BeginFormAntiForgeryPost("/admin/navigation/create", FormMethod.Post)) { %>
<h2><%: T("Add New Item") %></h2><%
using (Html.BeginFormAntiForgeryPost(Url.Action("create"), FormMethod.Post)) { %>
<table class="menu items">
<colgroup>
<col id="AddText" />
@@ -49,18 +49,18 @@ using (Html.BeginFormAntiForgeryPost("/admin/navigation/create", FormMethod.Post
<tbody>
<tr>
<td>
<label for="MenuText"><%=_Encoded("Text") %></label>
<%=Html.EditorFor(nmvm => nmvm.NewMenuItem.MenuItem.Item.As<MenuPart>().MenuText) %>
<label for="MenuText"><%: T("Text") %></label>
<%: Html.EditorFor(nmvm => nmvm.NewMenuItem.MenuItem.Item.As<MenuPart>().MenuText) %>
</td>
<td>
<label for="MenuPosition"><%=_Encoded("Position")%></label>
<%=Html.EditorFor(nmvm => nmvm.NewMenuItem.MenuItem.Item.As<MenuPart>().MenuPosition) %>
<label for="MenuPosition"><%: T("Position")%></label>
<%: Html.EditorFor(nmvm => nmvm.NewMenuItem.MenuItem.Item.As<MenuPart>().MenuPosition) %>
</td>
<td>
<label for="Url"><%=_Encoded("Url")%></label>
<%=Html.EditorFor(nmvm => nmvm.NewMenuItem.MenuItem.Item.As<Orchard.Core.Navigation.Models.MenuItem>().Url)%>
<label for="Url"><%: T("Url")%></label>
<%: Html.EditorFor(nmvm => nmvm.NewMenuItem.MenuItem.Item.As<Orchard.Core.Navigation.Models.MenuItem>().Url)%>
</td>
<td><button class="add" type="submit"><%=_Encoded("Add") %></button></td>
<td><button class="add" type="submit"><%: T("Add") %></button></td>
</tr>
</tbody>
</table><%

View File

@@ -2,10 +2,10 @@
<%@ Import Namespace="Orchard.Core.Navigation.Models"%>
<%@ Import Namespace="Orchard.Core.Navigation.ViewModels"%>
<fieldset>
<%=Html.EditorFor(m => m.OnMainMenu) %>
<label for="OnMainMenu" class="forcheckbox"><%=_Encoded("Show on main menu") %></label>
<%: Html.EditorFor(m => m.OnMainMenu) %>
<label for="OnMainMenu" class="forcheckbox"><%: T("Show on main menu") %></label>
<div data-controllerid="OnMainMenu" class="">
<label for="MenuText"><%=_Encoded("Menu text") %></label>
<%=Html.TextBoxFor(m => m.MenuText, new { @class = "large text" })%>
<label for="MenuText"><%: T("Menu text") %></label>
<%: Html.TextBoxFor(m => m.MenuText, new { @class = "large text" })%>
</div>
</fieldset>

View File

@@ -47,6 +47,7 @@
<Reference Include="System.ComponentModel.DataAnnotations">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Data" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="System.Web.ApplicationServices" />
<Reference Include="System.Web.DynamicData" />
@@ -68,6 +69,14 @@
<Compile Include="Common\Drivers\RoutableDriver.cs" />
<Compile Include="Common\Controllers\RoutableController.cs" />
<Compile Include="Common\Handlers\RoutableAspectHandler.cs" />
<Compile Include="Contents\Controllers\ItemController.cs" />
<Compile Include="Contents\Handlers\ContentsModuleHandler.cs" />
<Compile Include="Localization\Drivers\LocalizedDriver.cs" />
<Compile Include="Routable\Controllers\ItemController.cs" />
<Compile Include="Routable\Drivers\RoutableDriver.cs" />
<Compile Include="Routable\Handlers\RoutableHandler.cs" />
<Compile Include="Routable\IRoutablePathConstraint.cs" />
<Compile Include="Routable\Models\IsRoutable.cs" />
<Compile Include="Common\Permissions.cs" />
<Compile Include="Common\Models\CommonVersionRecord.cs" />
<Compile Include="Common\Routes.cs" />
@@ -86,6 +95,12 @@
<Compile Include="Common\ViewModels\BodyEditorViewModel.cs" />
<Compile Include="Common\ViewModels\RoutableEditorViewModel.cs" />
<Compile Include="Common\ViewModels\OwnerEditorViewModel.cs" />
<Compile Include="Contents\AdminMenu.cs" />
<Compile Include="Contents\Controllers\AdminController.cs" />
<Compile Include="Contents\ViewModels\CreateItemViewModel.cs" />
<Compile Include="Contents\ViewModels\ContentTypeListViewModel.cs" />
<Compile Include="Contents\ViewModels\EditItemViewModel.cs" />
<Compile Include="Contents\ViewModels\ListContentViewModel.cs" />
<Compile Include="Dashboard\AdminMenu.cs" />
<Compile Include="Dashboard\Controllers\AdminController.cs" />
<Compile Include="Dashboard\Routes.cs" />
@@ -119,6 +134,9 @@
<Compile Include="Indexing\Services\CreateIndexingTaskHandler.cs" />
<Compile Include="Indexing\Services\IndexingTaskExecutor.cs" />
<Compile Include="Indexing\Services\IndexingTaskManager.cs" />
<Compile Include="Localization\Handlers\LocalizedHandler.cs" />
<Compile Include="Localization\Models\Localized.cs" />
<Compile Include="Localization\Models\LocalizedRecord.cs" />
<Compile Include="Navigation\AdminMenu.cs" />
<Compile Include="Navigation\Controllers\AdminController.cs" />
<Compile Include="Navigation\Models\MenuItem.cs" />
@@ -136,12 +154,17 @@
<Compile Include="Navigation\ViewModels\MenuItemEntry.cs" />
<Compile Include="Navigation\ViewModels\NavigationManagementViewModel.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Routable\Routes.cs" />
<Compile Include="Routable\Services\RoutablePathConstraint.cs" />
<Compile Include="Routable\Services\RoutablePathConstraintUpdator.cs" />
<Compile Include="Routable\ViewModels\RoutableDisplayViewModel.cs" />
<Compile Include="Scheduling\Models\ScheduledTaskRecord.cs" />
<Compile Include="Scheduling\Services\PublishingTaskHandler.cs" />
<Compile Include="Scheduling\Services\PublishingTaskManager.cs" />
<Compile Include="Scheduling\Services\ScheduledTaskManager.cs" />
<Compile Include="Scheduling\Services\ScheduledTaskExecutor.cs" />
<Compile Include="Scheduling\Models\Task.cs" />
<Compile Include="Settings\ViewModels\SiteCulturesViewModel.cs" />
<Compile Include="Settings\Drivers\SiteSettingsDriver.cs" />
<Compile Include="Settings\Metadata\ContentDefinitionManager.cs" />
<Compile Include="Settings\Metadata\Records\ContentFieldDefinitionRecord.cs" />
@@ -179,9 +202,26 @@
</ItemGroup>
<ItemGroup>
<Content Include="Common\Module.txt" />
<Content Include="Contents\Module.txt" />
<Content Include="Contents\Views\Admin\Types.aspx" />
<Content Include="Contents\Views\Admin\List.aspx" />
<Content Include="Contents\Views\Admin\Edit.aspx" />
<Content Include="Contents\Views\Admin\CreatableTypeList.aspx" />
<Content Include="Contents\Views\Admin\Create.aspx" />
<Content Include="Contents\Views\DisplayTemplates\Items\Contents.Item.ascx" />
<Content Include="Contents\Views\EditorTemplates\Items\Contents.Item.ascx" />
<Content Include="Contents\Views\Item\Preview.aspx" />
<Content Include="Contents\Views\Item\Display.aspx" />
<Content Include="Indexing\Module.txt" />
<Content Include="Localization\Module.txt" />
<Content Include="Routable\Module.txt" />
<Content Include="Routable\Views\Item\Display.aspx" />
<Content Include="Settings\Module.txt" />
<Content Include="Settings\Styles\admin.css" />
<Content Include="Settings\Views\Admin\Index.ascx" />
<Content Include="Settings\Views\Admin\Culture.ascx" />
<Content Include="Settings\Views\DisplayTemplates\CurrentCulture.ascx" />
<Content Include="Settings\Views\DisplayTemplates\RemovableCulture.ascx" />
<Content Include="Web.config" />
<Content Include="XmlRpc\Module.txt" />
<Content Include="XmlRpc\Views\Home\Index.aspx" />
@@ -231,6 +271,8 @@
<ItemGroup>
<None Include="App_Data\Localization\en-US\orchard.core.po" />
<None Include="App_Data\Localization\fr-FR\orchard.core.po" />
<Content Include="Contents\Views\Web.config" />
<Content Include="Routable\Views\Web.config" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets" />

View File

@@ -0,0 +1,51 @@
using System;
using System.Linq;
using System.Web.Mvc;
using Orchard.ContentManagement;
using Orchard.ContentManagement.Aspects;
using Orchard.Core.Common.Models;
using Orchard.Core.Routable.Models;
using Orchard.Core.Routable.ViewModels;
using Orchard.Mvc.ViewModels;
namespace Orchard.Core.Routable.Controllers {
[ValidateInput(false)]
public class ItemController : Controller {
private readonly IContentManager _contentManager;
private readonly IRoutablePathConstraint _routablePathConstraint;
public ItemController(IContentManager contentManager, IRoutablePathConstraint routablePathConstraint) {
_contentManager = contentManager;
_routablePathConstraint = routablePathConstraint;
}
public ActionResult Display(string path) {
var matchedPath = _routablePathConstraint.FindPath(path);
if (string.IsNullOrEmpty(matchedPath)) {
throw new ApplicationException("404 - should not have passed path constraint");
}
var hits = _contentManager
.Query<IsRoutable, RoutableRecord>(VersionOptions.Published)
.Where(r => r.Path == matchedPath)
.Slice(0, 2);
if (hits.Count() == 0) {
throw new ApplicationException("404 - should not have passed path constraint");
}
if (hits.Count() != 1) {
throw new ApplicationException("Ambiguous content");
}
var model = new RoutableDisplayViewModel {
Routable = _contentManager.BuildDisplayModel<IRoutableAspect>(hits.Single(), "Detail")
};
PrepareDisplayViewModel(model.Routable);
return View("Display", model);
}
private void PrepareDisplayViewModel(ContentItemViewModel<IRoutableAspect> itemViewModel) {
if (string.IsNullOrEmpty(itemViewModel.TemplateName)) {
itemViewModel.TemplateName = "Items/Contents.Item";
}
}
}
}

View File

@@ -0,0 +1,61 @@
using JetBrains.Annotations;
using Orchard.ContentManagement;
using Orchard.ContentManagement.Drivers;
using Orchard.Core.Common.Models;
using Orchard.Core.Common.ViewModels;
using Orchard.Core.Common.Services;
using Orchard.Core.Routable.Models;
using Orchard.Localization;
using Orchard.UI.Notify;
namespace Orchard.Core.Routable.Drivers {
public class RoutableDriver : ContentPartDriver<IsRoutable> {
protected override DriverResult Editor(IsRoutable part, IUpdateModel updater) {
part.Record.Title = "Routable #" + part.ContentItem.Id;
part.Record.Slug = "routable" + part.ContentItem.Id;
part.Record.Path = "routable" + part.ContentItem.Id;
return base.Editor(part, updater);
}
//private const string TemplateName = "Parts/Common.Routable";
//private readonly IOrchardServices _services;
//private readonly IRoutableService _routableService;
//public Localizer T { get; set; }
//protected override string Prefix {
// get { return "Routable"; }
//}
//public Routable(IOrchardServices services, IRoutableService routableService)
//{
// _services = services;
// _routableService = routableService;
// T = NullLocalizer.Instance;
//}
//protected override DriverResult Editor(RoutableAspect part) {
// var model = new RoutableEditorViewModel { Prefix = Prefix, RoutableAspect = part };
// return ContentPartTemplate(model, TemplateName, Prefix).Location("primary", "before.5");
//}
//protected override DriverResult Editor(RoutableAspect part, IUpdateModel updater) {
// var model = new RoutableEditorViewModel { Prefix = Prefix, RoutableAspect = part };
// updater.TryUpdateModel(model, Prefix, null, null);
// if (!_routableService.IsSlugValid(part.Slug)){
// updater.AddModelError("Routable.Slug", T("Please do not use any of the following characters in your slugs: \"/\", \":\", \"?\", \"#\", \"[\", \"]\", \"@\", \"!\", \"$\", \"&\", \"'\", \"(\", \")\", \"*\", \"+\", \",\", \";\", \"=\". No spaces are allowed (please use dashes or underscores instead).").ToString());
// }
// string originalSlug = part.Slug;
// if(!_routableService.ProcessSlug(part)) {
// _services.Notifier.Warning(T("Slugs in conflict. \"{0}\" is already set for a previously created {2} so now it has the slug \"{1}\"",
// originalSlug, part.Slug, part.ContentItem.ContentType));
// }
// return ContentPartTemplate(model, TemplateName, Prefix).Location("primary", "before.5");
//}
}
}

View File

@@ -0,0 +1,20 @@
using System.Web.Routing;
using Orchard.ContentManagement;
using Orchard.ContentManagement.Handlers;
using Orchard.Core.Routable.Models;
namespace Orchard.Core.Routable.Handlers {
public class RoutableHandler : ContentHandlerBase {
public override void GetContentItemMetadata(GetContentItemMetadataContext context) {
var routable = context.ContentItem.As<IsRoutable>();
if (routable != null) {
context.Metadata.DisplayRouteValues = new RouteValueDictionary {
{"Area", "Routable"},
{"Controller", "Item"},
{"Action", "Display"},
{"Path", context.ContentItem.As<IsRoutable>().Record.Path}
};
}
}
}
}

View File

@@ -0,0 +1,11 @@
using System.Collections.Generic;
using System.Web.Routing;
namespace Orchard.Core.Routable {
public interface IRoutablePathConstraint : IRouteConstraint, ISingletonDependency {
void SetPaths(IEnumerable<string> paths);
string FindPath(string path);
void AddPath(string path);
void RemovePath(string path);
}
}

View File

@@ -0,0 +1,18 @@
using Orchard.ContentManagement;
using Orchard.ContentManagement.Aspects;
using Orchard.Core.Common.Models;
namespace Orchard.Core.Routable.Models {
public class IsRoutable : ContentPart<RoutableRecord>, IRoutableAspect {
public string Title {
get { return Record.Title; }
set { Record.Title = value; }
}
public string Slug {
get { return Record.Slug; }
set { Record.Slug = value; }
}
}
}

View File

@@ -0,0 +1,11 @@
Name: Routable
antiforgery: enabled
author: The Orchard Team
website: http://orchardproject.net
version: 0.1
orchardversion: 0.1.2010.0312
description: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas consectetur consequat risus, vel blandit arcu tincidunt eget. Nam rutrum nulla vestibulum dolor dapibus sagittis. Vivamus convallis faucibus accumsan. Suspendisse sapien enim, cursus at dignissim a, sollicitudin sit amet est. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Donec sed urna magna, in luctus nulla. Pellentesque erat ipsum, convallis sed molestie tempus, mattis vel leo metus.
features:
Routable:
Description: Routable content part.
Category: Core2

View File

@@ -0,0 +1,42 @@
using System.Collections.Generic;
using System.Web.Mvc;
using System.Web.Routing;
using Orchard.Mvc.Routes;
namespace Orchard.Core.Routable {
public class Routes : IRouteProvider {
private readonly IRoutablePathConstraint _routablePathConstraint;
public Routes(IRoutablePathConstraint routablePathConstraint) {
_routablePathConstraint = routablePathConstraint;
}
public void GetRoutes(ICollection<RouteDescriptor> routes) {
foreach (var routeDescriptor in GetRoutes())
routes.Add(routeDescriptor);
}
public IEnumerable<RouteDescriptor> GetRoutes() {
return new[] {
new RouteDescriptor {
Priority = 10,
Route = new Route(
"{*path}",
new RouteValueDictionary {
{"area", "Routable"},
{"controller", "Item"},
{"action", "Display"}
},
new RouteValueDictionary {
{"path", _routablePathConstraint}
},
new RouteValueDictionary {
{"area", "Routable"}
},
new MvcRouteHandler())
}
};
}
}
}

View File

@@ -0,0 +1,68 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Routing;
using JetBrains.Annotations;
using Orchard.Logging;
namespace Orchard.Core.Routable.Services {
[UsedImplicitly]
public class RoutablePathConstraint : IRoutablePathConstraint {
/// <summary>
/// Singleton object, per Orchard Shell instance. We need to protect concurrent access to the dictionary.
/// </summary>
private readonly object _syncLock = new object();
private IDictionary<string, string> _paths = new Dictionary<string, string>();
public RoutablePathConstraint() {
Logger = NullLogger.Instance;
}
public ILogger Logger { get; set; }
public void SetPaths(IEnumerable<string> paths) {
// Make a copy to avoid performing potential lazy computation inside the lock
var slugsArray = paths.ToArray();
lock (_syncLock) {
_paths = slugsArray.Distinct(StringComparer.OrdinalIgnoreCase).ToDictionary(value => value, StringComparer.OrdinalIgnoreCase);
}
}
public string FindPath(string path) {
lock (_syncLock) {
string actual;
return _paths.TryGetValue(path, out actual) ? actual : path;
}
}
public void AddPath(string path) {
lock (_syncLock) {
_paths[path] = path;
}
}
public void RemovePath(string path) {
lock (_syncLock) {
_paths.Remove(path);
}
}
public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection) {
if (routeDirection == RouteDirection.UrlGeneration)
return true;
object value;
if (values.TryGetValue(parameterName, out value)) {
var parameterValue = Convert.ToString(value);
lock (_syncLock) {
return _paths.ContainsKey(parameterValue);
}
}
return false;
}
}
}

View File

@@ -0,0 +1,36 @@
using System.Linq;
using JetBrains.Annotations;
using Orchard.Core.Common.Models;
using Orchard.Data;
using Orchard.Environment;
using Orchard.Tasks;
namespace Orchard.Core.Routable.Services {
[UsedImplicitly]
public class RoutablePathConstraintUpdator : IOrchardShellEvents, IBackgroundTask {
private readonly IRoutablePathConstraint _pageSlugConstraint;
private readonly IRepository<RoutableRecord> _repository;
public RoutablePathConstraintUpdator(IRoutablePathConstraint pageSlugConstraint, IRepository<RoutableRecord> repository) {
_pageSlugConstraint = pageSlugConstraint;
_repository = repository;
}
void IOrchardShellEvents.Activated() {
Refresh();
}
void IOrchardShellEvents.Terminating() {
}
void IBackgroundTask.Sweep() {
Refresh();
}
private void Refresh() {
var slugs = _repository.Fetch(r => r.ContentItemVersionRecord.Published && r.Path != "" && r.Path != null).Select(r => r.Path);
_pageSlugConstraint.SetPaths(slugs);
}
}
}

View File

@@ -0,0 +1,8 @@
using Orchard.ContentManagement.Aspects;
using Orchard.Mvc.ViewModels;
namespace Orchard.Core.Routable.ViewModels {
public class RoutableDisplayViewModel : BaseViewModel {
public ContentItemViewModel<IRoutableAspect> Routable {get;set;}
}
}

View File

@@ -0,0 +1,3 @@
<%@ Page Language="C#" Inherits="Orchard.Mvc.ViewPage<Orchard.Core.Routable.ViewModels.RoutableDisplayViewModel>" %>
<% Html.AddTitleParts(Model.Routable.Item.Title); %>
<%=Html.DisplayForItem(m=>m.Routable) %>

View File

@@ -0,0 +1,34 @@
<?xml version="1.0"?>
<configuration>
<system.web>
<httpHandlers>
<add path="*" verb="*"
type="System.Web.HttpNotFoundHandler"/>
</httpHandlers>
<!--
Enabling request validation in view pages would cause validation to occur
after the input has already been processed by the controller. By default
MVC performs request validation before a controller processes the input.
To change this behavior apply the ValidateInputAttribute to a
controller or action.
-->
<pages
validateRequest="false"
pageParserFilterType="System.Web.Mvc.ViewTypeParserFilter, System.Web.Mvc, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
pageBaseType="System.Web.Mvc.ViewPage, System.Web.Mvc, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
userControlBaseType="System.Web.Mvc.ViewUserControl, System.Web.Mvc, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
<controls>
<add assembly="System.Web.Mvc, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" namespace="System.Web.Mvc" tagPrefix="mvc" />
</controls>
</pages>
</system.web>
<system.webServer>
<validation validateIntegratedModeConfiguration="false"/>
<handlers>
<remove name="BlockViewHandler"/>
<add name="BlockViewHandler" path="*" verb="*" preCondition="integratedMode" type="System.Web.HttpNotFoundHandler"/>
</handlers>
</system.webServer>
</configuration>

View File

@@ -1,8 +1,11 @@
using System.Web.Mvc;
using System.Globalization;
using System.Linq;
using System.Web.Mvc;
using Orchard.Core.Settings.Models;
using Orchard.Core.Settings.ViewModels;
using Orchard.Localization;
using Orchard.ContentManagement;
using Orchard.Localization.Services;
using Orchard.Settings;
using Orchard.UI.Notify;
@@ -10,10 +13,12 @@ namespace Orchard.Core.Settings.Controllers {
[ValidateInput(false)]
public class AdminController : Controller, IUpdateModel {
private readonly ISiteService _siteService;
private readonly ICultureManager _cultureManager;
public IOrchardServices Services { get; private set; }
public AdminController(ISiteService siteService, IOrchardServices services) {
public AdminController(ISiteService siteService, IOrchardServices services, ICultureManager cultureManager) {
_siteService = siteService;
_cultureManager = cultureManager;
Services = services;
T = NullLocalizer.Instance;
}
@@ -25,7 +30,8 @@ namespace Orchard.Core.Settings.Controllers {
return new HttpUnauthorizedResult();
var model = new SettingsIndexViewModel {
Site = _siteService.GetSiteSettings().As<SiteSettings>()
Site = _siteService.GetSiteSettings().As<SiteSettings>(),
SiteCultures = _cultureManager.ListCultures()
};
model.ViewModel = Services.ContentManager.BuildEditorModel(model.Site);
return View(model);
@@ -47,6 +53,39 @@ namespace Orchard.Core.Settings.Controllers {
return RedirectToAction("Index");
}
public ActionResult Culture() {
//todo: class and/or method attributes for our auth?
if (!Services.Authorizer.Authorize(Permissions.ManageSettings, T("Not authorized to manage settings")))
return new HttpUnauthorizedResult();
var viewModel = new SiteCulturesViewModel {
CurrentCulture = CultureInfo.CurrentCulture.Name,
SiteCultures = _cultureManager.ListCultures(),
};
viewModel.AvailableSystemCultures = CultureInfo.GetCultures(CultureTypes.SpecificCultures)
.Select(ci => ci.Name)
.Where(s => !viewModel.SiteCultures.Contains(s));
return View(viewModel);
}
[HttpPost]
public ActionResult AddCulture(string cultureName) {
if (!Services.Authorizer.Authorize(Permissions.ManageSettings, T("Not authorized to manage settings")))
return new HttpUnauthorizedResult();
_cultureManager.AddCulture(cultureName);
return RedirectToAction("Culture");
}
[HttpPost]
public ActionResult DeleteCulture(string cultureName) {
if (!Services.Authorizer.Authorize(Permissions.ManageSettings, T("Not authorized to manage settings")))
return new HttpUnauthorizedResult();
_cultureManager.DeleteCulture(cultureName);
return RedirectToAction("Culture");
}
bool IUpdateModel.TryUpdateModel<TModel>(TModel model, string prefix, string[] includeProperties, string[] excludeProperties) {
return TryUpdateModel(model, prefix, includeProperties, excludeProperties);

View File

@@ -0,0 +1,18 @@
.site-cultures {
font-size:1.2em;
overflow:auto;
}
.site-cultures li {
clear:left;
float:left;
overflow:auto;
padding:1px 6px;
margin:0 0 0 1em;
}
.site-cultures li:hover {
background:#EAEAEA;
}
.site-cultures div {
float:left;
width:6em;
}

View File

@@ -1,4 +1,5 @@
using System.Web.Mvc;
using System.Collections.Generic;
using System.Web.Mvc;
using Orchard.ContentManagement;
using Orchard.Mvc.ViewModels;
using Orchard.Core.Settings.Models;
@@ -6,6 +7,7 @@ using Orchard.Core.Settings.Models;
namespace Orchard.Core.Settings.ViewModels {
public class SettingsIndexViewModel : BaseViewModel {
public SiteSettings Site { get; set; }
public IEnumerable<string> SiteCultures { get; set; }
public ContentItemViewModel ViewModel { get; set; }
@@ -20,12 +22,16 @@ namespace Orchard.Core.Settings.ViewModels {
set { Site.As<SiteSettings>().Record.PageTitleSeparator = value; }
}
public string SiteName
{
public string SiteName {
get { return Site.As<SiteSettings>().Record.SiteName; }
set { Site.As<SiteSettings>().Record.SiteName = value; }
}
public string SiteCulture {
get { return Site.As<SiteSettings>().Record.SiteCulture; }
set { Site.As<SiteSettings>().Record.SiteCulture = value; }
}
public string SuperUser {
get { return Site.As<SiteSettings>().Record.SuperUser; }
set { Site.As<SiteSettings>().Record.SuperUser = value; }

View File

@@ -0,0 +1,10 @@
using System.Collections.Generic;
using Orchard.Mvc.ViewModels;
namespace Orchard.Core.Settings.ViewModels {
public class SiteCulturesViewModel : BaseViewModel {
public string CurrentCulture { get; set; }
public IEnumerable<string> SiteCultures { get; set; }
public IEnumerable<string> AvailableSystemCultures { get; set; }
}
}

View File

@@ -0,0 +1,17 @@
<%@ Control Language="C#" Inherits="Orchard.Mvc.ViewUserControl<SiteCulturesViewModel>" %>
<%@ Import Namespace="Orchard.Core.Settings.ViewModels" %><%
Html.RegisterStyle("admin.css"); %>
<h1><%:Html.TitleForPage(T("Manage Settings").ToString()) %></h1>
<h2><%:T("Cultures this site supports") %></h2>
<%=Html.UnorderedList(
Model.SiteCultures.OrderBy(s => s),
(s, i) => Html.DisplayFor(scvm => s, s == Model.CurrentCulture ? "CurrentCulture" : "RemovableCulture", "").ToString(),
"site-cultures", "culture", "odd")%>
<% using (Html.BeginFormAntiForgeryPost("AddCulture")) { %>
<%:Html.ValidationSummary() %>
<fieldset>
<legend><%:T("Add a culture...") %></legend>
<%:Html.DropDownList("CultureName", new SelectList(Model.AvailableSystemCultures.OrderBy(s => s), Model.CurrentCulture)) %>
<button class="primaryAction" type="submit"><%:T("Add") %></button>
</fieldset>
<% } %>

View File

@@ -1,29 +1,35 @@
<%@ Control Language="C#" Inherits="Orchard.Mvc.ViewUserControl<SettingsIndexViewModel>" %>
<%@ Import Namespace="Orchard.Core.Settings.ViewModels"%>
<h1><%=Html.TitleForPage(T("Manage Settings").ToString())%></h1>
<%using (Html.BeginFormAntiForgeryPost()) { %>
<%= Html.ValidationSummary() %>
<%@ Import Namespace="Orchard.Core.Settings.ViewModels" %>
<h1><%:Html.TitleForPage(T("Manage Settings").ToString()) %></h1>
<% using (Html.BeginFormAntiForgeryPost()) { %>
<%:Html.ValidationSummary() %>
<fieldset>
<legend><%=_Encoded("Global Settings")%></legend>
<legend><%:T("Global Settings") %></legend>
<div>
<label for="SiteName"><%=_Encoded("Site name") %></label>
<%=Html.EditorFor(m => m.SiteName)%>
<%=Html.ValidationMessage("SiteName", "*") %>
<label for="SiteName"><%:T("Site name") %></label>
<%:Html.EditorFor(m => m.SiteName) %>
<%:Html.ValidationMessage("SiteName", "*") %>
</div>
<div>
<label for="PageTitleSeparator"><%=_Encoded("Page title separator") %></label>
<%=Html.EditorFor(x => x.PageTitleSeparator)%>
<%=Html.ValidationMessage("PageTitleSeparator", "*")%>
<label for="SiteCulture"><%:T("Default Site Culture") %></label>
<%:Html.DropDownList("SiteCulture", new SelectList(Model.SiteCultures, Model.SiteCulture)) %>
<%:Html.ValidationMessage("SiteCulture", "*") %>
<%:Html.ActionLink(T("Add or remove supported cultures for the site.").ToString(), "Culture") %>
</div>
<div>
<label for="SuperUser"><%=_Encoded("Super user") %></label>
<%=Html.EditorFor(x=>x.SuperUser) %>
<%=Html.ValidationMessage("SuperUser", "*") %>
<label for="PageTitleSeparator"><%:T("Page title separator") %></label>
<%:Html.EditorFor(x => x.PageTitleSeparator) %>
<%:Html.ValidationMessage("PageTitleSeparator", "*") %>
</div>
<div>
<label for="SuperUser"><%:T("Super user") %></label>
<%:Html.EditorFor(x=>x.SuperUser) %>
<%:Html.ValidationMessage("SuperUser", "*") %>
</div>
</fieldset>
<%= Html.EditorForItem(Model.ViewModel) %>
<%:Html.EditorForItem(Model.ViewModel) %>
<fieldset>
<%=Html.EditorFor(s => s.Id) %>
<input class="button primaryAction" type="submit" value="<%=_Encoded("Save") %>" />
<%:Html.EditorFor(s => s.Id) %>
<input class="button primaryAction" type="submit" value="<%:T("Save") %>" />
</fieldset>
<% } %>

View File

@@ -0,0 +1,2 @@
<%@ Control Language="C#" Inherits="Orchard.Mvc.ViewUserControl<string>" %>
<strong><%:Model %></strong>

View File

@@ -0,0 +1,6 @@
<%@ Control Language="C#" Inherits="Orchard.Mvc.ViewUserControl<string>" %>
<div><%:Model %></div>
<% using (Html.BeginFormAntiForgeryPost(Url.Action("DeleteCulture", "Admin", new { area = "Settings" }), FormMethod.Post, new {@class = "inline link"})) { %>
<%=Html.Hidden("cultureName", Model, new { id = "" }) %>
<button type="submit" title="<%:T("Delete") %>">x</button>
<% } %>

View File

@@ -1,12 +1,12 @@
<%@ Control Language="C#" Inherits="Orchard.Mvc.ViewUserControl<WidgetEditViewModel>" %>
<%@ Import Namespace="Futures.Widgets.ViewModels" %>
<%@ Import Namespace="Orchard.Mvc.Html" %>
<h1><%=Html.TitleForPage(T("Edit Widget").ToString()) %></h1>
<h1><%: Html.TitleForPage(T("Edit Widget").ToString()) %></h1>
<% using (Html.BeginFormAntiForgeryPost()) { %>
<%= Html.ValidationSummary() %>
<%= Html.EditorForItem(m => m.Widget) %>
<%: Html.ValidationSummary() %>
<%: Html.EditorForItem(m => m.Widget) %>
<fieldset>
<%= Html.HiddenFor(m => m.ReturnUrl) %>
<%: Html.HiddenFor(m => m.ReturnUrl) %>
<input class="button primaryAction" type="submit" name="submit.Save" value="Save"/>
</fieldset>
<%} %>

View File

@@ -5,7 +5,7 @@
<% Html.RegisterStyle("archives.css"); %>
<% Html.RegisterFootScript("archives.js"); %>
<div class="archives">
<h3><%=_Encoded("Archives") %></h3><%
<h3><%: T("Archives") %></h3><%
if (Model.Archives.Count() > 0) {
if (Model.Archives.Count() > 20) { %>
<ul class="years"><%
@@ -33,6 +33,6 @@
}
}
else { %>
<div class="message info"><%=_Encoded("None found")%></div><%
<div class="message info"><%: T("None found")%></div><%
} %>
</div>

View File

@@ -4,5 +4,5 @@
<%=Html.UnorderedList(Model.Blogs, (b, i) => Html.DisplayForItem(b).ToHtmlString(), "blogs contentItems") %><%
}
else { %>
<p><%=_Encoded("No blogs found.") %></p><%
<p><%: T("No blogs found.") %></p><%
} %>

View File

@@ -1,12 +1,12 @@
<%@ Control Language="C#" Inherits="Orchard.Mvc.ViewUserControl<CreateBlogViewModel>" %>
<%@ Import Namespace="Orchard.Blogs.ViewModels"%>
<h1><%=Html.TitleForPage(T("Add Blog").ToString()) %></h1>
<h1><%: Html.TitleForPage(T("Add Blog").ToString()) %></h1>
<% using (Html.BeginFormAntiForgeryPost()) { %>
<%=Html.ValidationSummary() %>
<%=Html.EditorForItem(vm => vm.Blog) %>
<%: Html.ValidationSummary() %>
<%: Html.EditorForItem(vm => vm.Blog) %>
<fieldset>
<%=Html.EditorFor(m => m.PromoteToHomePage) %>
<label for="PromoteToHomePage" class="forcheckbox"><%=_Encoded("Set as home page") %></label>
<%: Html.EditorFor(m => m.PromoteToHomePage) %>
<label for="PromoteToHomePage" class="forcheckbox"><%: T("Set as home page") %></label>
</fieldset>
<fieldset><input class="button primaryAction" type="submit" value="<%=_Encoded("Add") %>" /></fieldset><%
<fieldset><input class="button primaryAction" type="submit" value="<%: T("Add") %>" /></fieldset><%
} %>

View File

@@ -1,12 +1,12 @@
<%@ Control Language="C#" Inherits="Orchard.Mvc.ViewUserControl<BlogEditViewModel>" %>
<%@ Import Namespace="Orchard.Blogs.ViewModels"%>
<h1><%=Html.TitleForPage(T("Edit Blog").ToString()) %></h1>
<h1><%: Html.TitleForPage(T("Edit Blog").ToString()) %></h1>
<% using (Html.BeginFormAntiForgeryPost()) { %>
<%=Html.ValidationSummary() %>
<%=Html.EditorForItem(m => m.Blog) %>
<%: Html.ValidationSummary() %>
<%: Html.EditorForItem(m => m.Blog) %>
<fieldset>
<%=Html.EditorFor(m => m.PromoteToHomePage) %>
<label for="PromoteToHomePage" class="forcheckbox"><%=_Encoded("Set as home page") %></label>
<%: Html.EditorFor(m => m.PromoteToHomePage) %>
<label for="PromoteToHomePage" class="forcheckbox"><%: T("Set as home page") %></label>
</fieldset>
<fieldset><input class="button primaryAction" type="submit" value="<%=_Encoded("Save") %>" /></fieldset><%
<fieldset><input class="button primaryAction" type="submit" value="<%: T("Save") %>" /></fieldset><%
} %>

View File

@@ -1,10 +1,10 @@
<%@ Control Language="C#" Inherits="Orchard.Mvc.ViewUserControl<AdminBlogsViewModel>" %>
<%@ Import Namespace="Orchard.Blogs.Extensions"%>
<%@ Import Namespace="Orchard.Blogs.ViewModels"%>
<h1><%=Html.TitleForPage(T("Manage Blogs").ToString()) %></h1>
<%-- todo: Add helper text here when ready. <p><%=_Encoded("Possible text about setting up and managing a blog goes here.") %></p> --%><%
<h1><%: Html.TitleForPage(T("Manage Blogs").ToString()) %></h1>
<%-- todo: Add helper text here when ready. <p><%: T("Possible text about setting up and managing a blog goes here.") %></p> --%><%
if (Model.Entries.Count() > 0) { %>
<div class="actions"><a class="add button primaryAction" href="<%=Url.BlogCreate() %>"><%=_Encoded("New Blog") %></a></div>
<div class="actions"><a class="add button primaryAction" href="<%=Url.BlogCreate() %>"><%: T("New Blog") %></a></div>
<%=Html.UnorderedList(Model.Entries, (entry, i) => {
// Add blog post count rendering into "meta" zone
entry.ContentItemViewModel.Zones.AddAction("meta", html => {

View File

@@ -1,7 +1,7 @@
<%@ Control Language="C#" Inherits="Orchard.Mvc.ViewUserControl<BlogPostArchiveViewModel>" %>
<%@ Import Namespace="Orchard.Blogs.Extensions"%>
<%@ Import Namespace="Orchard.Blogs.ViewModels"%>
<h1 class="page-title"><%=Html.TitleForPage(T("Archives").ToString(), Model.ArchiveData.Year.ToString(), Model.ArchiveData.Month > 0 ? new DateTime(Model.ArchiveData.Year, Model.ArchiveData.Month, 1).ToString("MMMM") : null, Model.ArchiveData.Day > 0 ? Model.ArchiveData.Day.ToString() : null)%></h1>
<h1 class="page-title"><%: Html.TitleForPage(T("Archives").ToString(), Model.ArchiveData.Year.ToString(), Model.ArchiveData.Month > 0 ? new DateTime(Model.ArchiveData.Year, Model.ArchiveData.Month, 1).ToString("MMMM") : null, Model.ArchiveData.Day > 0 ? Model.ArchiveData.Day.ToString() : null)%></h1>
<div class="archive-trail">
<%=T("Archives").ToString()

View File

@@ -1,7 +1,7 @@
<%@ Control Language="C#" Inherits="Orchard.Mvc.ViewUserControl<CreateBlogPostViewModel>" %>
<%@ Import Namespace="Orchard.Blogs.ViewModels"%>
<h1><%=Html.TitleForPage(T("Add Post").ToString()) %></h1>
<h1><%: Html.TitleForPage(T("Add Post").ToString()) %></h1>
<% using (Html.BeginFormAntiForgeryPost()) { %>
<%=Html.ValidationSummary() %>
<%=Html.EditorForItem(m => m.BlogPost) %><%
<%: Html.ValidationSummary() %>
<%: Html.EditorForItem(m => m.BlogPost) %><%
} %>

View File

@@ -1,7 +1,7 @@
<%@ Control Language="C#" Inherits="Orchard.Mvc.ViewUserControl<BlogPostEditViewModel>" %>
<%@ Import Namespace="Orchard.Blogs.ViewModels"%>
<h1><%=Html.TitleForPage(T("Edit Post").ToString()) %></h1>
<h1><%: Html.TitleForPage(T("Edit Post").ToString()) %></h1>
<% using (Html.BeginFormAntiForgeryPost()) { %>
<%=Html.ValidationSummary() %>
<%=Html.EditorForItem(m => m.BlogPost) %><%
<%: Html.ValidationSummary() %>
<%: Html.EditorForItem(m => m.BlogPost) %><%
} %>

View File

@@ -2,20 +2,22 @@
<%@ Import Namespace="Orchard.Mvc.ViewModels"%>
<%@ Import Namespace="Orchard.Blogs.Extensions"%>
<%@ Import Namespace="Orchard.Blogs.Models"%>
<h1><a href="<%=Url.BlogForAdmin(Model.Item.Slug) %>"><%=Html.TitleForPage(Model.Item.Name) %></a></h1>
<h1><a href="<%=Url.BlogForAdmin(Model.Item.Slug) %>"><%: Html.TitleForPage(Model.Item.Name) %></a>
</h1>
<% Html.Zone("manage"); %><%--
<form>
<div class="actions bulk">
<fieldset>
<label for="filterResults"><%=_Encoded("Filter:")%></label>
<label for="filterResults"><%: T("Filter:")%></label>
<select id="filterResults" name="">
<option value="">All Posts</option>
<option value="">Published Posts</option>
</select>
<input class="button" type="submit" name="submit.Filter" value="<%=_Encoded("Apply") %>"/>
<input class="button" type="submit" name="submit.Filter" value="<%: T("Apply") %>"/>
</fieldset>
</div>
</form>--%>
<div class="actions"><a href="<%=Url.BlogPostCreate(Model.Item) %>" class="add button primaryAction"><%=_Encoded("New Post")%></a></div>
<div class="actions"><a href="<%=Url.BlogPostCreate(Model.Item) %>" class="add button primaryAction"><%: T("New Post")%></a></div>
<% Html.Zone("primary");
Html.ZonesAny(); %>

View File

@@ -3,5 +3,5 @@
<%@ Import Namespace="Orchard.Blogs.Extensions"%>
<%@ Import Namespace="Orchard.Blogs.Models"%>
<h2><%=Html.Link(Html.Encode(Model.Item.Name), Url.Blog(Model.Item.Slug)) %></h2>
<% if (!string.IsNullOrEmpty(Model.Item.Description)) { %><p><%=Html.Encode(Model.Item.Description) %></p><% } %>
<div class="blog metadata"><%=_Encoded("{0} post{1}", Model.Item.PostCount, Model.Item.PostCount == 1 ? "" : "s")%> | <%Html.Zone("meta");%></div>
<% if (!string.IsNullOrEmpty(Model.Item.Description)) { %><p><%: Model.Item.Description %></p><% } %>
<div class="blog metadata"><%: T("{0} post{1}", Model.Item.PostCount, Model.Item.PostCount == 1 ? "" : "s")%> | <%Html.Zone("meta");%></div>

View File

@@ -4,20 +4,20 @@
<%@ Import Namespace="Orchard.Blogs.Models"%>
<div class="summary">
<div class="related">
<a href="<%=Url.Blog(Model.Item.Slug) %>" title="<%=_Encoded("View") %>"><%=_Encoded("View") %></a><%=_Encoded(" | ")%>
<a href="<%=Url.BlogForAdmin(Model.Item.Slug) %>" title="<%=_Encoded("Edit Posts") %>"><%=_Encoded("Edit Posts")%></a><%=_Encoded(" | ")%>
<a href="<%=Url.BlogPostCreate(Model.Item) %>" title="<%=_Encoded("New Post") %>"><%=_Encoded("New Post") %></a><%=_Encoded(" | ")%>
<a href="<%=Url.BlogEdit(Model.Item.Slug) %>" title="<%=_Encoded("Settings") %>"><%=_Encoded("Settings") %></a><%=_Encoded(" | ")%>
<a href="<%=Url.Blog(Model.Item.Slug) %>" title="<%: T("View") %>"><%: T("View") %></a><%: T(" | ")%>
<a href="<%=Url.BlogForAdmin(Model.Item.Slug) %>" title="<%: T("Edit Posts") %>"><%: T("Edit Posts")%></a><%: T(" | ")%>
<a href="<%=Url.BlogPostCreate(Model.Item) %>" title="<%: T("New Post") %>"><%: T("New Post") %></a><%: T(" | ")%>
<a href="<%=Url.BlogEdit(Model.Item.Slug) %>" title="<%: T("Settings") %>"><%: T("Settings") %></a><%: T(" | ")%>
<%-- todo: (heskew) this is waaaaa too verbose. need template helpers for all ibuttons --%>
<% using (Html.BeginFormAntiForgeryPost(Url.BlogDelete(Model.Item.Slug), FormMethod.Post, new { @class = "inline link" })) { %>
<button type="submit" title="<%=_Encoded("Remove") %>"><%=_Encoded("Remove") %></button><%
<button type="submit" class="linkButton" title="<%: T("Remove") %>"><%: T("Remove") %></button><%
} %>
</div>
<div class="properties">
<h3><%=Html.Link(Html.Encode(Model.Item.Name), Url.BlogForAdmin(Model.Item.Slug)) %></h3>
<p><% Html.Zone("meta");%></p>
<%--<p>[list of authors] [modify blog access]</p>--%>
<p><%=Html.Encode(Model.Item.Description) %></p>
<p><%: Model.Item.Description %></p>
</div>
<div style="clear:both;"></div>
</div>

View File

@@ -3,7 +3,7 @@
<%@ Import Namespace="Orchard.Blogs.Extensions"%>
<%@ Import Namespace="Orchard.Mvc.ViewModels"%>
<%@ Import Namespace="Orchard.Blogs.Models"%>
<h1><%=Html.TitleForPage(Model.Item.Name) %></h1>
<h1><%: Html.TitleForPage(Model.Item.Name) %></h1>
<% Html.RegisterLink(new LinkEntry { Rel = "wlwmanifest", Type = "application/wlwmanifest+xml", Href = Url.BlogLiveWriterManifest(Model.Item.Slug) });%>
<% Html.RegisterLink(new LinkEntry { Rel = "EditURI", Type = "application/rsd+xml", Title = "RSD", Href = Url.BlogRsd(Model.Item.Slug) });%>
<% Html.Zone("primary", ":manage :metadata");

View File

@@ -11,48 +11,48 @@
<ul>
<li><%
if (Model.Item.HasPublished) { %>
<img class="icon" src="<%=ResolveUrl("~/Modules/Orchard.Blogs/Content/Admin/images/online.gif") %>" alt="<%=_Encoded("Online") %>" title="<%=_Encoded("The page is currently online") %>" /><%=_Encoded(" Published")%><%
<img class="icon" src="<%=ResolveUrl("~/Modules/Orchard.Blogs/Content/Admin/images/online.gif") %>" alt="<%: T("Online") %>" title="<%: T("The page is currently online") %>" /><%: T(" Published")%><%
}
else { %>
<img class="icon" src="<%=ResolveUrl("~/Modules/Orchard.Blogs/Content/Admin/images/offline.gif") %>" alt="<%=_Encoded("Offline") %>" title="<%=_Encoded("The page is currently offline") %>" /><%=_Encoded(" Not Published")%><%
<img class="icon" src="<%=ResolveUrl("~/Modules/Orchard.Blogs/Content/Admin/images/offline.gif") %>" alt="<%: T("Offline") %>" title="<%: T("The page is currently offline") %>" /><%: T(" Not Published")%><%
} %>&nbsp;&#124;&nbsp;
</li>
<li><%
if (Model.Item.HasDraft) { %>
<img class="icon" src="<%=ResolveUrl("~/Modules/Orchard.Blogs/Content/Admin/images/draft.gif") %>" alt="<%=_Encoded("Draft") %>" title="<%=_Encoded("The post has a draft") %>" /><%=Html.PublishedState(Model.Item)%><%
<img class="icon" src="<%=ResolveUrl("~/Modules/Orchard.Blogs/Content/Admin/images/draft.gif") %>" alt="<%: T("Draft") %>" title="<%: T("The post has a draft") %>" /><%=Html.PublishedState(Model.Item)%><%
}
else { %>
<%=_Encoded("No draft")%><%
<%: T("No draft")%><%
} %>&nbsp;&#124;&nbsp;
</li>
<li><%
if (Model.Item.ScheduledPublishUtc.HasValue && Model.Item.ScheduledPublishUtc.Value > DateTime.UtcNow) { %>
<img class="icon" src="<%=ResolveUrl("~/Modules/Orchard.Blogs/Content/Admin/images/scheduled.gif") %>" alt="<%=_Encoded("Scheduled") %>" title="<%=_Encoded("The post is scheduled for publishing") %>" /><%=_Encoded("Scheduled")%>
<img class="icon" src="<%=ResolveUrl("~/Modules/Orchard.Blogs/Content/Admin/images/scheduled.gif") %>" alt="<%: T("Scheduled") %>" title="<%: T("The post is scheduled for publishing") %>" /><%: T("Scheduled")%>
<%=Html.DateTime(Model.Item.ScheduledPublishUtc.Value, "M/d/yyyy h:mm tt")%><%
}
else if (Model.Item.IsPublished) { %>
<%=_Encoded("Published: ") + Html.DateTimeRelative(Model.Item.As<ICommonAspect>().VersionPublishedUtc.Value)%><%
<%: T("Published: ") + Html.DateTimeRelative(Model.Item.As<ICommonAspect>().VersionPublishedUtc.Value)%><%
}
else { %>
<%=_Encoded("Last modified: ") + Html.DateTimeRelative(Model.Item.As<ICommonAspect>().ModifiedUtc.Value) %><%
<%: T("Last modified: ") + Html.DateTimeRelative(Model.Item.As<ICommonAspect>().ModifiedUtc.Value) %><%
} %>&nbsp;&#124;&nbsp;
</li>
<li><%=_Encoded("By {0}", Model.Item.Creator.UserName)%></li>
<li><%: T("By {0}", Model.Item.Creator.UserName)%></li>
</ul>
</div>
<div class="related"><%
if (Model.Item.HasPublished){ %>
<a href="<%=Url.BlogPost(Model.Item) %>" title="<%=_Encoded("View Post")%>"><%=_Encoded("View")%></a><%=_Encoded(" | ")%><%
<a href="<%=Url.BlogPost(Model.Item) %>" title="<%: T("View Post")%>"><%: T("View")%></a><%: T(" | ")%><%
if (Model.Item.HasDraft) { %>
<a href="<%=Html.AntiForgeryTokenGetUrl(Url.BlogPostPublish(Model.Item)) %>" title="<%=_Encoded("Publish Draft")%>"><%=_Encoded("Publish Draft")%></a><%=_Encoded(" | ")%><%
<a href="<%=Html.AntiForgeryTokenGetUrl(Url.BlogPostPublish(Model.Item)) %>" title="<%: T("Publish Draft")%>"><%: T("Publish Draft")%></a><%: T(" | ")%><%
} %>
<a href="<%=Html.AntiForgeryTokenGetUrl(Url.BlogPostUnpublish(Model.Item)) %>" title="<%=_Encoded("Unpublish Post")%>"><%=_Encoded("Unpublish")%></a><%=_Encoded(" | ")%><%
<a href="<%=Html.AntiForgeryTokenGetUrl(Url.BlogPostUnpublish(Model.Item)) %>" title="<%: T("Unpublish Post")%>"><%: T("Unpublish")%></a><%: T(" | ")%><%
}
else { %>
<a href="<%=Html.AntiForgeryTokenGetUrl(Url.BlogPostPublish(Model.Item)) %>" title="<%=_Encoded("Publish Post")%>"><%=_Encoded("Publish")%></a><%=_Encoded(" | ")%><%
<a href="<%=Html.AntiForgeryTokenGetUrl(Url.BlogPostPublish(Model.Item)) %>" title="<%: T("Publish Post")%>"><%: T("Publish")%></a><%: T(" | ")%><%
} %>
<a href="<%=Url.BlogPostEdit(Model.Item) %>" title="<%=_Encoded("Edit Post")%>"><%=_Encoded("Edit")%></a><%=_Encoded(" | ")%>
<a href="<%=Html.AntiForgeryTokenGetUrl(Url.BlogPostDelete(Model.Item)) %>" title="<%=_Encoded("Remove Post")%>"><%=_Encoded("Remove")%></a>
<a href="<%=Url.BlogPostEdit(Model.Item) %>" title="<%: T("Edit Post")%>"><%: T("Edit")%></a><%: T(" | ")%>
<a href="<%=Html.AntiForgeryTokenGetUrl(Url.BlogPostDelete(Model.Item)) %>" title="<%: T("Remove Post")%>"><%: T("Remove")%></a>
<br /><%Html.Zone("meta");%>
</div>
<div style="clear:both;"></div>

View File

@@ -1,6 +1,6 @@
<%@ Control Language="C#" Inherits="Orchard.Mvc.ViewUserControl<ContentItemViewModel<BlogPost>>" %>
<%@ Import Namespace="Orchard.Mvc.ViewModels"%>
<%@ Import Namespace="Orchard.Blogs.Models"%>
<h1><%=Html.TitleForPage(Model.Item.Title)%></h1>
<h1><%: Html.TitleForPage(Model.Item.Title)%></h1>
<% Html.Zone("primary", ":manage :metadata");
Html.ZonesAny(); %>

View File

@@ -1,5 +1,5 @@
<%@ Control Language="C#" Inherits="Orchard.Mvc.ViewUserControl<Blog>" %>
<%@ Import Namespace="Orchard.Blogs.Models"%>
<div class="blogdescription">
<p><%=Html.Encode(Model.Description) %></p>
<p><%: Model.Description %></p>
</div>

View File

@@ -5,6 +5,6 @@
Html.RegisterStyle("admin.css");
if (AuthorizedFor(Permissions.ManageBlogs)) { %>
<div class="folderProperties">
<p><a href="<%=Url.BlogEdit(Model.Slug) %>" class="edit"><%=_Encoded("Edit") %></a></p>
<p><a href="<%=Url.BlogEdit(Model.Slug) %>" class="edit"><%: T("Edit") %></a></p>
</div><%
} %>

View File

@@ -2,4 +2,4 @@
<%@ Import Namespace="Orchard.Mvc.ViewModels"%>
<%@ Import Namespace="Orchard.Blogs.Models"%>
<%=Html.UnorderedList(Model, (bp, i) => Html.DisplayForItem(bp).ToHtmlString(), "blogPosts contentItems") %>
<% if (Model.Count() < 1) { %><div class="info message"><%=_Encoded("There are no posts for this blog.") %></div><% } %>
<% if (Model.Count() < 1) { %><div class="info message"><%: T("There are no posts for this blog.") %></div><% } %>

View File

@@ -2,5 +2,5 @@
<%@ Import Namespace="Orchard.Blogs.Extensions"%>
<%@ Import Namespace="Orchard.Blogs.Models"%><%
if (Model.Creator != null) {
%><span class="posted"><%=_Encoded("Posted by {0} {1}", Model.Creator.UserName, Html.PublishedWhen(Model)) %> | </span><%
%><span class="posted"><%: T("Posted by {0} {1}", Model.Creator.UserName, Html.PublishedWhen(Model)) %> | </span><%
} %>

View File

@@ -3,6 +3,6 @@
<%@ Import Namespace="Orchard.Blogs.Models"%>
<div class="metadata"><%
if (Model.Creator != null) {
%><div class="posted"><%=_Encoded("Posted by {0} {1}", Model.Creator.UserName, Html.PublishedWhen(Model)) %></div><%
%><div class="posted"><%: T("Posted by {0} {1}", Model.Creator.UserName, Html.PublishedWhen(Model)) %></div><%
} %>
</div>

View File

@@ -10,7 +10,7 @@
<div class="secondary">
<% Html.Zone("secondary");%>
<fieldset>
<input class="button primaryAction" type="submit" name="submit.Save" value="<%=_Encoded("Save") %>"/><%
<input class="button primaryAction" type="submit" name="submit.Save" value="<%: T("Save") %>"/><%
//TODO: (erikpo) In the future, remove the HasPublished check so the user can delete the content item from here if the choose to
if (Model.Item.HasDraft && Model.Item.HasPublished) { %>
<%=Html.AntiForgeryTokenValueOrchardLink(T("Discard Draft").ToString(), Url.Action("DiscardDraft", new {Area = "Orchard.Blogs", Controller = "BlogPostAdmin", id = Model.Item.Id}), new {@class = "button"})%><%

View File

@@ -1,6 +1,6 @@
<%@ Control Language="C#" Inherits="Orchard.Mvc.ViewUserControl<Blog>" %>
<%@ Import Namespace="Orchard.Blogs.Models"%>
<fieldset>
<%=Html.LabelFor(m => m.Description) %>
<%=Html.TextAreaFor(m => m.Description, 5, 60, null) %>
<%: Html.LabelFor(m => m.Description) %>
<%: Html.TextAreaFor(m => m.Description, 5, 60, null) %>
</fieldset>

View File

@@ -9,24 +9,24 @@
<% Html.RegisterFootScript("jquery.utils.js"); %>
<% Html.RegisterFootScript("ui.timepickr.js"); %>
<fieldset>
<legend><%=_Encoded("Publish Settings")%></legend>
<legend><%: T("Publish Settings")%></legend>
<div>
<%=Html.RadioButton("Command", "SaveDraft", Model.ContentItem.VersionRecord == null || !Model.ContentItem.VersionRecord.Published, new { id = "Command_SaveDraft" }) %>
<label class="forcheckbox" for="Command_SaveDraft"><%=_Encoded("Save Draft")%></label>
<%: Html.RadioButton("Command", "SaveDraft", Model.ContentItem.VersionRecord == null || !Model.ContentItem.VersionRecord.Published, new { id = "Command_SaveDraft" }) %>
<label class="forcheckbox" for="Command_SaveDraft"><%: T("Save Draft")%></label>
</div>
<div>
<%=Html.RadioButton("Command", "PublishNow", Model.ContentItem.VersionRecord != null && Model.ContentItem.VersionRecord.Published, new { id = "Command_PublishNow" })%>
<label class="forcheckbox" for="Command_PublishNow"><%=_Encoded("Publish Now")%></label>
<%: Html.RadioButton("Command", "PublishNow", Model.ContentItem.VersionRecord != null && Model.ContentItem.VersionRecord.Published, new { id = "Command_PublishNow" })%>
<label class="forcheckbox" for="Command_PublishNow"><%: T("Publish Now")%></label>
</div>
<div>
<%=Html.RadioButton("Command", "PublishLater", Model.ScheduledPublishUtc != null, new { id = "Command_PublishLater" }) %>
<label class="forcheckbox" for="Command_PublishLater"><%=_Encoded("Publish Later")%></label>
<%: Html.RadioButton("Command", "PublishLater", Model.ScheduledPublishUtc != null, new { id = "Command_PublishLater" }) %>
<label class="forcheckbox" for="Command_PublishLater"><%: T("Publish Later")%></label>
</div>
<div>
<label class="forpicker" for="ScheduledPublishUtcDate"><%=_Encoded("Date")%></label>
<%=Html.EditorFor(m => m.ScheduledPublishUtcDate)%>
<label class="forpicker" for="ScheduledPublishUtcTime"><%=_Encoded("Time")%></label>
<%=Html.EditorFor(m => m.ScheduledPublishUtcTime)%>
<label class="forpicker" for="ScheduledPublishUtcDate"><%: T("Date")%></label>
<%: Html.EditorFor(m => m.ScheduledPublishUtcDate)%>
<label class="forpicker" for="ScheduledPublishUtcTime"><%: T("Time")%></label>
<%: Html.EditorFor(m => m.ScheduledPublishUtcTime)%>
</div>
</fieldset>
<script type="text/javascript">$(function() {

Some files were not shown because too many files have changed in this diff Show More