mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2026-01-19 17:51:45 +08:00
Including Orchard.Autoroute
--HG-- branch : 1.x
This commit is contained in:
@@ -0,0 +1,18 @@
|
||||
using Orchard.Commands;
|
||||
using Orchard.Autoroute.Services;
|
||||
|
||||
namespace Orchard.Autoroute.Commands {
|
||||
public class AutorouteCommands : DefaultOrchardCommandHandler {
|
||||
private readonly IAutorouteService _autorouteService;
|
||||
|
||||
public AutorouteCommands(IAutorouteService autorouteService) {
|
||||
_autorouteService = autorouteService;
|
||||
}
|
||||
|
||||
[CommandHelp("autoroute create <content-type> <name> <pattern> <description> <isDefault>\r\n\t" + "Adds a new autoroute pattern to a specific content type")]
|
||||
[CommandName("autoroute create")]
|
||||
public void CreatePattern(string contentType, string name, string pattern, string description, bool isDefault) {
|
||||
_autorouteService.CreatePattern(contentType, name, pattern, description, isDefault);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Orchard.Alias;
|
||||
using Orchard.Autoroute.Models;
|
||||
using Orchard.Autoroute.Services;
|
||||
using Orchard.ContentManagement;
|
||||
using Orchard.ContentManagement.Drivers;
|
||||
using Orchard.Autoroute.ViewModels;
|
||||
using Orchard.Autoroute.Settings;
|
||||
using Orchard.Localization;
|
||||
using Orchard.Security;
|
||||
using Orchard.UI.Notify;
|
||||
using Orchard.Utility.Extensions;
|
||||
|
||||
namespace Orchard.Autoroute.Drivers {
|
||||
public class AutoroutePartDriver : ContentPartDriver<AutoroutePart> {
|
||||
private readonly IAliasService _aliasService;
|
||||
private readonly IContentManager _contentManager;
|
||||
private readonly IAutorouteService _autorouteService;
|
||||
private readonly IAuthorizer _authorizer;
|
||||
private readonly INotifier _notifier;
|
||||
|
||||
public AutoroutePartDriver(
|
||||
IAliasService aliasService,
|
||||
IContentManager contentManager,
|
||||
IAutorouteService autorouteService,
|
||||
IAuthorizer authorizer,
|
||||
INotifier notifier) {
|
||||
_aliasService = aliasService;
|
||||
_contentManager = contentManager;
|
||||
_autorouteService = autorouteService;
|
||||
_authorizer = authorizer;
|
||||
_notifier = notifier;
|
||||
|
||||
T = NullLocalizer.Instance;
|
||||
}
|
||||
|
||||
public Localizer T { get; set; }
|
||||
|
||||
protected override string Prefix { get { return "Autoroute"; }}
|
||||
|
||||
protected override DriverResult Editor(AutoroutePart part, dynamic shapeHelper) {
|
||||
return Editor(part, null, shapeHelper);
|
||||
}
|
||||
|
||||
protected override DriverResult Editor(AutoroutePart part, IUpdateModel updater, dynamic shapeHelper) {
|
||||
|
||||
var settings = part.TypePartDefinition.Settings.GetModel<AutorouteSettings>();
|
||||
|
||||
// if the content type has no pattern for autoroute, then use a default one
|
||||
if(!settings.Patterns.Any()) {
|
||||
settings.AllowCustomPattern = true;
|
||||
settings.AutomaticAdjustmentOnEdit = false;
|
||||
settings.DefaultPatternIndex = 0;
|
||||
settings.Patterns = new List<RoutePattern> {new RoutePattern {Name = "Title", Description = "my-title", Pattern = "{Content.Slug}"}};
|
||||
|
||||
_notifier.Warning(T("No route patterns are currently defined for this Content Type. If you don't set one in the settings, a default one will be used."));
|
||||
}
|
||||
|
||||
var viewModel = new AutoroutePartEditViewModel {
|
||||
CurrentUrl = part.DisplayAlias,
|
||||
Settings = settings
|
||||
};
|
||||
|
||||
// retrieve home page
|
||||
var homepage = _aliasService.Get(string.Empty);
|
||||
var displayRouteValues = _contentManager.GetItemMetadata(part).DisplayRouteValues;
|
||||
|
||||
if(homepage.Match(displayRouteValues)) {
|
||||
viewModel.PromoteToHomePage = true;
|
||||
}
|
||||
|
||||
if (settings.PerItemConfiguration) {
|
||||
// if enabled, the list of all available patterns is displayed, and the user can
|
||||
// select which one to use
|
||||
|
||||
// todo: later
|
||||
}
|
||||
|
||||
var previous = part.DisplayAlias;
|
||||
if (updater != null && updater.TryUpdateModel(viewModel, Prefix, null, null)) {
|
||||
|
||||
// remove any trailing slash in the permalink
|
||||
while(!string.IsNullOrEmpty(viewModel.CurrentUrl) && viewModel.CurrentUrl.StartsWith("/")) {
|
||||
viewModel.CurrentUrl = viewModel.CurrentUrl.Substring(1);
|
||||
}
|
||||
|
||||
part.DisplayAlias = viewModel.CurrentUrl;
|
||||
|
||||
// reset the alias if we need to force regeneration, and the user didn't provide a custom one
|
||||
if(settings.AutomaticAdjustmentOnEdit && previous == part.DisplayAlias) {
|
||||
part.DisplayAlias = string.Empty;
|
||||
}
|
||||
|
||||
if (!_autorouteService.IsPathValid(part.DisplayAlias)) {
|
||||
var path = (part.DisplayAlias ?? String.Empty);
|
||||
if (path.StartsWith(".") || path.EndsWith("."))
|
||||
updater.AddModelError("CurrentUrl", T("The \".\" can't be used at either end of the permalink."));
|
||||
else
|
||||
updater.AddModelError("CurrentUrl", T("Please do not use any of the following characters in your permalink: \":\", \"?\", \"#\", \"[\", \"]\", \"@\", \"!\", \"$\", \"&\", \"'\", \"(\", \")\", \"*\", \"+\", \",\", \";\", \"=\", \", \"<\", \">\", \"\\\". No spaces are allowed (please use dashes or underscores instead)."));
|
||||
}
|
||||
|
||||
// if CurrentUrl is set, the handler won't try to create an alias for it
|
||||
// but instead keep the value
|
||||
|
||||
// if home page is requested, use "/" to have the handler create a homepage alias
|
||||
if(_authorizer.Authorize(Permissions.SetHomePage) && viewModel.PromoteToHomePage) {
|
||||
part.DisplayAlias = "/";
|
||||
}
|
||||
}
|
||||
|
||||
return ContentShape("Parts_Autoroute_Edit",
|
||||
() => shapeHelper.EditorTemplate(TemplateName: "Parts.Autoroute.Edit", Model: viewModel, Prefix: Prefix));
|
||||
}
|
||||
|
||||
protected override void Importing(AutoroutePart part, ContentManagement.Handlers.ImportContentContext context) {
|
||||
var displayAlias = context.Attribute(part.PartDefinition.Name, "Alias");
|
||||
if (displayAlias != null) {
|
||||
part.DisplayAlias = displayAlias;
|
||||
}
|
||||
|
||||
var customPattern = context.Attribute(part.PartDefinition.Name, "CustomPattern");
|
||||
if (customPattern != null) {
|
||||
part.CustomPattern = customPattern;
|
||||
}
|
||||
|
||||
var useCustomPattern = context.Attribute(part.PartDefinition.Name, "UseCustomPattern");
|
||||
if (useCustomPattern != null) {
|
||||
part.UseCustomPattern = bool.Parse(useCustomPattern);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Exporting(AutoroutePart part, ContentManagement.Handlers.ExportContentContext context) {
|
||||
context.Element(part.PartDefinition.Name).SetAttributeValue("Alias", String.IsNullOrEmpty(part.Record.DisplayAlias) ? "/" : part.Record.DisplayAlias);
|
||||
context.Element(part.PartDefinition.Name).SetAttributeValue("CustomPattern", part.Record.CustomPattern);
|
||||
context.Element(part.PartDefinition.Name).SetAttributeValue("UseCustomPattern", part.Record.UseCustomPattern);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
using System;
|
||||
using Orchard.ContentManagement;
|
||||
using Orchard.ContentManagement.Handlers;
|
||||
using Orchard.Autoroute.Models;
|
||||
using Orchard.Data;
|
||||
using Orchard.Autoroute.Services;
|
||||
using Orchard.Localization;
|
||||
using Orchard.UI.Notify;
|
||||
|
||||
namespace Orchard.Autoroute.Handlers {
|
||||
public class AutoroutePartHandler : ContentHandler {
|
||||
|
||||
private readonly Lazy<IAutorouteService> _autorouteService;
|
||||
private readonly IOrchardServices _orchardServices;
|
||||
|
||||
public Localizer T { get; set; }
|
||||
|
||||
public AutoroutePartHandler(
|
||||
IRepository<AutoroutePartRecord> autoroutePartRepository,
|
||||
Lazy<IAutorouteService> autorouteService,
|
||||
IOrchardServices orchardServices) {
|
||||
|
||||
Filters.Add(StorageFilter.For(autoroutePartRepository));
|
||||
_autorouteService = autorouteService;
|
||||
_orchardServices = orchardServices;
|
||||
|
||||
OnUpdated<AutoroutePart>((ctx, part) => CreateAlias(part));
|
||||
|
||||
OnCreated<AutoroutePart>((ctx, part) => {
|
||||
// non-draftable items
|
||||
if (part.ContentItem.VersionRecord == null) {
|
||||
PublishAlias(part);
|
||||
}
|
||||
});
|
||||
|
||||
// OnVersioned<AutoroutePart>((ctx, part1, part2) => CreateAlias(part1));
|
||||
|
||||
OnPublished<AutoroutePart>((ctx, part) => PublishAlias(part));
|
||||
|
||||
// Remove alias if removed or unpublished
|
||||
OnRemoved<AutoroutePart>((ctx, part) => RemoveAlias(part));
|
||||
OnUnpublished<AutoroutePart>((ctx, part) => RemoveAlias(part));
|
||||
|
||||
// Register alias as identity
|
||||
OnGetContentItemMetadata<AutoroutePart>((ctx, part) => {
|
||||
if (part.DisplayAlias != null)
|
||||
ctx.Metadata.Identity.Add("alias", part.DisplayAlias);
|
||||
});
|
||||
}
|
||||
|
||||
private void CreateAlias(AutoroutePart part) {
|
||||
ProcessAlias(part);
|
||||
}
|
||||
|
||||
private void PublishAlias(AutoroutePart part) {
|
||||
ProcessAlias(part);
|
||||
|
||||
// should it become the home page ?
|
||||
if (part.DisplayAlias == "/") {
|
||||
part.DisplayAlias = String.Empty;
|
||||
|
||||
// regenerate the alias for the previous home page
|
||||
var currentHomePages = _orchardServices.ContentManager.Query<AutoroutePart, AutoroutePartRecord>().Where(x => x.DisplayAlias == "").List();
|
||||
foreach (var current in currentHomePages) {
|
||||
if (current != null) {
|
||||
current.CustomPattern = String.Empty; // force the regeneration
|
||||
current.DisplayAlias = _autorouteService.Value.GenerateAlias(current);
|
||||
}
|
||||
_autorouteService.Value.PublishAlias(current);
|
||||
}
|
||||
}
|
||||
|
||||
_autorouteService.Value.PublishAlias(part);
|
||||
}
|
||||
|
||||
private void ProcessAlias(AutoroutePart part) {
|
||||
// generate an alias if one as not already been entered
|
||||
if (String.IsNullOrWhiteSpace(part.DisplayAlias)) {
|
||||
part.DisplayAlias = _autorouteService.Value.GenerateAlias(part);
|
||||
}
|
||||
|
||||
// should it become the home page ?
|
||||
if (part.DisplayAlias != "/") {
|
||||
var previous = part.Path;
|
||||
if (!_autorouteService.Value.ProcessPath(part))
|
||||
_orchardServices.Notifier.Warning(T("Permalinks in conflict. \"{0}\" is already set for a previously created {2} so now it has the slug \"{1}\"",
|
||||
previous, part.Path, part.ContentItem.ContentType));
|
||||
}
|
||||
}
|
||||
|
||||
void RemoveAlias(AutoroutePart part) {
|
||||
_autorouteService.Value.RemoveAliases(part);
|
||||
}
|
||||
}
|
||||
}
|
||||
20
src/Orchard.Web/Modules/Orchard.Autoroute/Migrations.cs
Normal file
20
src/Orchard.Web/Modules/Orchard.Autoroute/Migrations.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using Orchard.ContentManagement.MetaData;
|
||||
using Orchard.Core.Contents.Extensions;
|
||||
using Orchard.Data.Migration;
|
||||
|
||||
namespace Orchard.Autoroute {
|
||||
public class Migrations : DataMigrationImpl {
|
||||
public int Create() {
|
||||
SchemaBuilder.CreateTable("AutoroutePartRecord",
|
||||
table => table
|
||||
.ContentPartVersionRecord()
|
||||
.Column<string>("CustomPattern", c => c.WithLength(2048))
|
||||
.Column<bool>("UseCustomPattern", c=> c.WithDefault(false))
|
||||
.Column<string>("DisplayAlias", c => c.WithLength(2048)));
|
||||
|
||||
ContentDefinitionManager.AlterPartDefinition("AutoroutePart", part => part.Attachable());
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
using Orchard.ContentManagement;
|
||||
using Orchard.ContentManagement.Aspects;
|
||||
|
||||
namespace Orchard.Autoroute.Models {
|
||||
public class AutoroutePart : ContentPart<AutoroutePartRecord>, IAliasAspect {
|
||||
|
||||
public string CustomPattern {
|
||||
get { return Record.CustomPattern; }
|
||||
set { Record.CustomPattern = value; }
|
||||
}
|
||||
|
||||
public bool UseCustomPattern {
|
||||
get { return Record.UseCustomPattern; }
|
||||
set { Record.UseCustomPattern = value; }
|
||||
}
|
||||
|
||||
public string DisplayAlias {
|
||||
get { return Record.DisplayAlias; }
|
||||
set { Record.DisplayAlias = value; }
|
||||
}
|
||||
|
||||
public string Path {
|
||||
get { return DisplayAlias; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
using Orchard.ContentManagement.Records;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Orchard.Autoroute.Models {
|
||||
public class AutoroutePartRecord : ContentPartVersionRecord {
|
||||
|
||||
public virtual bool UseCustomPattern { get; set; }
|
||||
|
||||
[StringLength(2048)]
|
||||
public virtual string CustomPattern { get; set; }
|
||||
|
||||
[StringLength(2048)]
|
||||
public virtual string DisplayAlias { get; set; }
|
||||
}
|
||||
}
|
||||
13
src/Orchard.Web/Modules/Orchard.Autoroute/Module.txt
Normal file
13
src/Orchard.Web/Modules/Orchard.Autoroute/Module.txt
Normal file
@@ -0,0 +1,13 @@
|
||||
Name: Autoroute
|
||||
AntiForgery: enabled
|
||||
Author: The Orchard Team
|
||||
Website: http://orchardproject.net
|
||||
Version: 1.5
|
||||
OrchardVersion: 1.3
|
||||
Description: Description for the module
|
||||
Features:
|
||||
Orchard.Autoroute:
|
||||
Name: Autoroute
|
||||
Description: Enables the Autoroute part for tokenized routing
|
||||
Dependencies: Orchard.Alias, Orchard.Tokens
|
||||
Category: Content
|
||||
@@ -0,0 +1,175 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProductVersion>9.0.30729</ProductVersion>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<ProjectGuid>{66FCCD76-2761-47E3-8D11-B45D0001DDAA}</ProjectGuid>
|
||||
<ProjectTypeGuids>{349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}</ProjectTypeGuids>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>Orchard.Autoroute</RootNamespace>
|
||||
<AssemblyName>Orchard.Autoroute</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
|
||||
<MvcBuildViews>false</MvcBuildViews>
|
||||
<FileUpgradeFlags>
|
||||
</FileUpgradeFlags>
|
||||
<OldToolsVersion>4.0</OldToolsVersion>
|
||||
<UpgradeBackupLocation>
|
||||
</UpgradeBackupLocation>
|
||||
<TargetFrameworkProfile />
|
||||
<UseIISExpress>false</UseIISExpress>
|
||||
<IISExpressSSLPort />
|
||||
<IISExpressAnonymousAuthentication />
|
||||
<IISExpressWindowsAuthentication />
|
||||
<IISExpressUseClassicPipelineMode />
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.ComponentModel.DataAnnotations">
|
||||
<RequiredTargetFramework>3.5</RequiredTargetFramework>
|
||||
</Reference>
|
||||
<Reference Include="System.Web.DynamicData" />
|
||||
<Reference Include="System.Web.Extensions" />
|
||||
<Reference Include="System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\..\..\..\lib\aspnetmvc\System.Web.Mvc.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Web" />
|
||||
<Reference Include="System.Web.Abstractions" />
|
||||
<Reference Include="System.Web.Routing" />
|
||||
<Reference Include="System.Xml" />
|
||||
<Reference Include="System.Configuration" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="Recipes\autorouteblogs.recipe.xml" />
|
||||
<Content Include="Recipes\autoroutepages.recipe.xml" />
|
||||
<Content Include="Recipes\autoroutelists.recipe.xml" />
|
||||
<Content Include="Styles\orchard-autoroute-settings.css" />
|
||||
<Content Include="Web.config" />
|
||||
<Content Include="Scripts\Web.config" />
|
||||
<Content Include="Styles\Web.config" />
|
||||
<Compile Include="Permissions.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Content Include="Module.txt" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\Orchard\Orchard.Framework.csproj">
|
||||
<Project>{2D1D92BB-4555-4CBE-8D0E-63563D6CE4C6}</Project>
|
||||
<Name>Orchard.Framework</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\Core\Orchard.Core.csproj">
|
||||
<Project>{9916839C-39FC-4CEB-A5AF-89CA7E87119F}</Project>
|
||||
<Name>Orchard.Core</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Orchard.Alias\Orchard.Alias.csproj">
|
||||
<Project>{475B6C45-B27C-438B-8966-908B9D6D1077}</Project>
|
||||
<Name>Orchard.Alias</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Orchard.Tokens\Orchard.Tokens.csproj">
|
||||
<Project>{6F759635-13D7-4E94-BCC9-80445D63F117}</Project>
|
||||
<Name>Orchard.Tokens</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Commands\AutorouteCommands.cs" />
|
||||
<Compile Include="ResourceManifest.cs" />
|
||||
<Compile Include="Services\IRouteEvents.cs" />
|
||||
<Compile Include="Settings\AutorouteSettingsEvents.cs" />
|
||||
<Compile Include="Settings\RoutePattern.cs" />
|
||||
<Compile Include="Drivers\AutoroutePartDriver.cs" />
|
||||
<Compile Include="Handlers\AutoroutePartHandler.cs" />
|
||||
<Compile Include="Services\ISlugService.cs" />
|
||||
<Compile Include="Migrations.cs" />
|
||||
<Compile Include="Providers\SlugTokens.cs" />
|
||||
<Compile Include="Services\AutorouteService.cs" />
|
||||
<Compile Include="Services\IAutorouteService.cs" />
|
||||
<Compile Include="Models\AutoroutePart.cs" />
|
||||
<Compile Include="Models\AutoroutePartRecord.cs" />
|
||||
<Compile Include="Services\DefaultSlugService.cs" />
|
||||
<Compile Include="Services\ISlugEventHandler.cs" />
|
||||
<Compile Include="Settings\AutorouteSettings.cs" />
|
||||
<Compile Include="ViewModels\AutoroutePartEditViewModel.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="Controllers\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="Placement.info">
|
||||
<SubType>Designer</SubType>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="Views\DefinitionTemplates\AutorouteSettings.cshtml" />
|
||||
<Content Include="Views\EditorTemplates\Parts.Autoroute.Edit.cshtml" />
|
||||
<Content Include="Views\Web.config" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup>
|
||||
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
|
||||
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||
<Import Project="$(VSToolsPath)\WebApplications\Microsoft.WebApplication.targets" Condition="'$(VSToolsPath)' != ''" />
|
||||
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets" Condition="false" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target> -->
|
||||
<Target Name="AfterBuild" DependsOnTargets="AfterBuildCompiler">
|
||||
<PropertyGroup>
|
||||
<AreasManifestDir>$(ProjectDir)\..\Manifests</AreasManifestDir>
|
||||
</PropertyGroup>
|
||||
<!-- If this is an area child project, uncomment the following line:
|
||||
<CreateAreaManifest AreaName="$(AssemblyName)" AreaType="Child" AreaPath="$(ProjectDir)" ManifestPath="$(AreasManifestDir)" ContentFiles="@(Content)" />
|
||||
-->
|
||||
<!-- If this is an area parent project, uncomment the following lines:
|
||||
<CreateAreaManifest AreaName="$(AssemblyName)" AreaType="Parent" AreaPath="$(ProjectDir)" ManifestPath="$(AreasManifestDir)" ContentFiles="@(Content)" />
|
||||
<CopyAreaManifests ManifestPath="$(AreasManifestDir)" CrossCopy="false" RenameViews="true" />
|
||||
-->
|
||||
</Target>
|
||||
<Target Name="AfterBuildCompiler" Condition="'$(MvcBuildViews)'=='true'">
|
||||
<AspNetCompiler VirtualPath="temp" PhysicalPath="$(ProjectDir)\..\$(ProjectName)" />
|
||||
</Target>
|
||||
<ProjectExtensions>
|
||||
<VisualStudio>
|
||||
<FlavorProperties GUID="{349c5851-65df-11da-9384-00065b846f21}">
|
||||
<WebProjectProperties>
|
||||
<UseIIS>False</UseIIS>
|
||||
<AutoAssignPort>True</AutoAssignPort>
|
||||
<DevelopmentServerPort>28871</DevelopmentServerPort>
|
||||
<DevelopmentServerVPath>/</DevelopmentServerVPath>
|
||||
<IISUrl>
|
||||
</IISUrl>
|
||||
<NTLMAuthentication>False</NTLMAuthentication>
|
||||
<UseCustomServer>True</UseCustomServer>
|
||||
<CustomServerUrl>http://orchard.codeplex.com</CustomServerUrl>
|
||||
<SaveServerSettingsInUserFile>False</SaveServerSettingsInUserFile>
|
||||
</WebProjectProperties>
|
||||
</FlavorProperties>
|
||||
</VisualStudio>
|
||||
</ProjectExtensions>
|
||||
</Project>
|
||||
31
src/Orchard.Web/Modules/Orchard.Autoroute/Permissions.cs
Normal file
31
src/Orchard.Web/Modules/Orchard.Autoroute/Permissions.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
using System.Collections.Generic;
|
||||
using Orchard.Environment.Extensions.Models;
|
||||
using Orchard.Security.Permissions;
|
||||
|
||||
namespace Orchard.Autoroute {
|
||||
public class Permissions : IPermissionProvider {
|
||||
public static readonly Permission SetHomePage = new Permission { Description = "Set Home Page", Name = "SetHomePage" };
|
||||
|
||||
public virtual Feature Feature { get; set; }
|
||||
|
||||
public IEnumerable<Permission> GetPermissions() {
|
||||
return new[] {
|
||||
SetHomePage
|
||||
};
|
||||
}
|
||||
|
||||
public IEnumerable<PermissionStereotype> GetDefaultStereotypes() {
|
||||
return new[] {
|
||||
new PermissionStereotype {
|
||||
Name = "Administrator",
|
||||
Permissions = new[] {SetHomePage}
|
||||
},
|
||||
new PermissionStereotype {
|
||||
Name = "Editor",
|
||||
Permissions = new[] {SetHomePage}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
3
src/Orchard.Web/Modules/Orchard.Autoroute/Placement.info
Normal file
3
src/Orchard.Web/Modules/Orchard.Autoroute/Placement.info
Normal file
@@ -0,0 +1,3 @@
|
||||
<Placement>
|
||||
<Place Parts_Autoroute_Edit="Content:before.51"/>
|
||||
</Placement>
|
||||
@@ -0,0 +1,35 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("Orchard.Autoroute")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyProduct("Orchard")]
|
||||
[assembly: AssemblyCopyright("Copyright <20> Outercurve Foundation 2009")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("149d93d0-2d4b-4fcb-9461-9de3c553eced")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Revision and Build Numbers
|
||||
// by using the '*' as shown below:
|
||||
[assembly: AssemblyVersion("1.5")]
|
||||
[assembly: AssemblyFileVersion("1.5")]
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
using System;
|
||||
using Orchard.Autoroute.Services;
|
||||
using Orchard.Tokens;
|
||||
using Orchard.Localization;
|
||||
using Orchard.ContentManagement;
|
||||
using Orchard.ContentManagement.MetaData.Models;
|
||||
using Orchard.Autoroute.Models;
|
||||
using Orchard.Core.Common.Models;
|
||||
|
||||
namespace Orchard.Autoroute.Providers {
|
||||
public class SlugTokens : ITokenProvider {
|
||||
private readonly ISlugService _slugService;
|
||||
|
||||
public SlugTokens(ISlugService slugService) {
|
||||
T = NullLocalizer.Instance;
|
||||
_slugService = slugService;
|
||||
}
|
||||
|
||||
public Localizer T { get; set; }
|
||||
|
||||
public void Describe(DescribeContext context) {
|
||||
context.For("Content")
|
||||
// /my-item
|
||||
.Token("Slug", T("Slug"), T("A slugified version of the item title appropriate for content Urls"))
|
||||
// /path/to/my-item
|
||||
.Token("Path", T("Path"), T("The full path of an item as already generated by Autoroute"))
|
||||
// /path/to/parent-item/
|
||||
.Token("ParentPath", T("Parent Path"), T("The parent item's path and slug with an appended forward slash if non-empty"));
|
||||
|
||||
context.For("TypeDefinition")
|
||||
// /blog-post
|
||||
.Token("Slug", T("Slug"), T("Slugified version of content type display name."));
|
||||
|
||||
context.For("Text")
|
||||
.Token("Slug", T("Slug"), T("Slugify the text"));
|
||||
}
|
||||
|
||||
public void Evaluate(EvaluateContext context) {
|
||||
context.For<IContent>("Content")
|
||||
// {Content.Slug}
|
||||
.Token("Slug", (content => content == null ? String.Empty : _slugService.Slugify(content)))
|
||||
.Token("Path", (content => {
|
||||
var autoroute = content.As<AutoroutePart>();
|
||||
if (autoroute == null) {
|
||||
return String.Empty;
|
||||
}
|
||||
return autoroute.DisplayAlias;
|
||||
}))
|
||||
// {Content.ParentPath}
|
||||
.Token("ParentPath", (content => {
|
||||
var common = content.As<CommonPart>();
|
||||
if (common == null || common.Container == null) {
|
||||
return String.Empty;
|
||||
}
|
||||
var ar = common.Container.As<AutoroutePart>();
|
||||
if (ar == null) {
|
||||
return String.Empty;
|
||||
}
|
||||
if (String.IsNullOrEmpty(ar.DisplayAlias))
|
||||
return String.Empty;
|
||||
return ar.DisplayAlias + "/";
|
||||
}));
|
||||
|
||||
context.For<ContentTypeDefinition>("TypeDefinition")
|
||||
// {Content.ContentType.Slug}
|
||||
.Token("Slug", (ctd => _slugService.Slugify(ctd.DisplayName)));
|
||||
|
||||
context.For<String>("Text")
|
||||
.Token("Slug", text => _slugService.Slugify(text));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?xml version="1.0"?>
|
||||
<Orchard>
|
||||
<Recipe>
|
||||
<Name>AutorouteBlogs</Name>
|
||||
<Description>Adds Autoroute functionality to an existing blog</Description>
|
||||
<Author>The Orchard Team</Author>
|
||||
<WebSite>http://orchardproject.net</WebSite>
|
||||
<Tags>blog, autoroute</Tags>
|
||||
<Version>1.0</Version>
|
||||
</Recipe>
|
||||
|
||||
<Feature enable="Orchard.Blogs" />
|
||||
|
||||
<Metadata>
|
||||
<Types>
|
||||
<Blog>
|
||||
<AutoroutePart />
|
||||
</Blog>
|
||||
<BlogPost>
|
||||
<AutoroutePart />
|
||||
</BlogPost>
|
||||
</Types>
|
||||
</Metadata>
|
||||
|
||||
<Migration features="*" />
|
||||
|
||||
<Command>
|
||||
autoroute create "Blog" "Title" "{Content.Slug}" "http://website.com/my-blog" true
|
||||
autoroute create "BlogPost" "Date and Title" "{Content.Date.Format:yyyy}/{Content.Date.Format:MM}/{Content.Date.Format:dd}/{Content.Slug}" "http://website.com/2011/05/12/a-blog-post" true
|
||||
</Command>
|
||||
</Orchard>
|
||||
@@ -0,0 +1,27 @@
|
||||
<?xml version="1.0"?>
|
||||
<Orchard>
|
||||
<Recipe>
|
||||
<Name>AutorouteLists</Name>
|
||||
<Description>Adds Autoroute functionality to an existing blog</Description>
|
||||
<Author>The Orchard Team</Author>
|
||||
<WebSite>http://orchardproject.net</WebSite>
|
||||
<Tags>container, autoroute</Tags>
|
||||
<Version>1.0</Version>
|
||||
</Recipe>
|
||||
|
||||
<Feature enable="Orchard.Pages" />
|
||||
|
||||
<Metadata>
|
||||
<Types>
|
||||
<List>
|
||||
<AutoroutePart />
|
||||
</List>
|
||||
</Types>
|
||||
</Metadata>
|
||||
|
||||
<Migration features="*" />
|
||||
|
||||
<Command>
|
||||
autoroute create "List" "Title" "{Content.Slug}" "http://website.com/events" true
|
||||
</Command>
|
||||
</Orchard>
|
||||
@@ -0,0 +1,27 @@
|
||||
<?xml version="1.0"?>
|
||||
<Orchard>
|
||||
<Recipe>
|
||||
<Name>AutoroutePages</Name>
|
||||
<Description>Adds Autoroute functionality to an existing blog</Description>
|
||||
<Author>The Orchard Team</Author>
|
||||
<WebSite>http://orchardproject.net</WebSite>
|
||||
<Tags>page, autoroute</Tags>
|
||||
<Version>1.0</Version>
|
||||
</Recipe>
|
||||
|
||||
<Feature enable="Orchard.Pages" />
|
||||
|
||||
<Metadata>
|
||||
<Types>
|
||||
<Page>
|
||||
<AutoroutePart />
|
||||
</Page>
|
||||
</Types>
|
||||
</Metadata>
|
||||
|
||||
<Migration features="*" />
|
||||
|
||||
<Command>
|
||||
autoroute create "Page" "Title" "{Content.Slug}" "http://website.com/about-us" false
|
||||
</Command>
|
||||
</Orchard>
|
||||
@@ -0,0 +1,10 @@
|
||||
using Orchard.UI.Resources;
|
||||
|
||||
namespace Orchard.Autoroute {
|
||||
public class ResourceManifest : IResourceManifestProvider {
|
||||
public void BuildManifests(ResourceManifestBuilder builder) {
|
||||
var manifest = builder.Add();
|
||||
manifest.DefineStyle("AutorouteSettings").SetUrl("orchard-autoroute-settings.css");
|
||||
}
|
||||
}
|
||||
}
|
||||
21
src/Orchard.Web/Modules/Orchard.Autoroute/Scripts/Web.config
Normal file
21
src/Orchard.Web/Modules/Orchard.Autoroute/Scripts/Web.config
Normal file
@@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration>
|
||||
<appSettings>
|
||||
<add key="webpages:Enabled" value="false" />
|
||||
</appSettings>
|
||||
<system.web>
|
||||
<httpHandlers>
|
||||
<!-- iis6 - for any request in this location, return via managed static file handler -->
|
||||
<add path="*" verb="*" type="System.Web.StaticFileHandler" />
|
||||
</httpHandlers>
|
||||
</system.web>
|
||||
<system.webServer>
|
||||
<handlers accessPolicy="Script,Read">
|
||||
<!--
|
||||
iis7 - for any request to a file exists on disk, return it via native http module.
|
||||
accessPolicy 'Script' is to allow for a managed 404 page.
|
||||
-->
|
||||
<add name="StaticFile" path="*" verb="*" modules="StaticFileModule" preCondition="integratedMode" resourceType="File" requireAccess="Read" />
|
||||
</handlers>
|
||||
</system.webServer>
|
||||
</configuration>
|
||||
@@ -0,0 +1,192 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using Orchard.Alias;
|
||||
using Orchard.Autoroute.Models;
|
||||
using Orchard.Autoroute.Settings;
|
||||
using Orchard.ContentManagement;
|
||||
using Orchard.ContentManagement.MetaData;
|
||||
using Orchard.ContentManagement.MetaData.Models;
|
||||
using Orchard.Localization;
|
||||
using Orchard.Logging;
|
||||
using Orchard.Tokens;
|
||||
|
||||
namespace Orchard.Autoroute.Services {
|
||||
public class AutorouteService : IAutorouteService {
|
||||
|
||||
private readonly IAliasService _aliasService;
|
||||
private readonly ITokenizer _tokenizer;
|
||||
private readonly IContentDefinitionManager _contentDefinitionManager;
|
||||
private readonly IContentManager _contentManager;
|
||||
private readonly IRouteEvents _routeEvents;
|
||||
private const string AliasSource = "Autoroute:View";
|
||||
|
||||
public AutorouteService(
|
||||
IAliasService aliasService,
|
||||
ITokenizer tokenizer,
|
||||
IContentDefinitionManager contentDefinitionManager,
|
||||
IContentManager contentManager,
|
||||
IRouteEvents routeEvents) {
|
||||
_aliasService = aliasService;
|
||||
_tokenizer = tokenizer;
|
||||
_contentDefinitionManager = contentDefinitionManager;
|
||||
_contentManager = contentManager;
|
||||
_routeEvents = routeEvents;
|
||||
|
||||
Logger = NullLogger.Instance;
|
||||
T = NullLocalizer.Instance;
|
||||
}
|
||||
|
||||
public ILogger Logger { get; set; }
|
||||
public Localizer T { get; set; }
|
||||
|
||||
public string GenerateAlias(AutoroutePart part) {
|
||||
|
||||
if (part == null) {
|
||||
throw new ArgumentNullException("part");
|
||||
}
|
||||
|
||||
string pattern = GetDefaultPattern(part.ContentItem.ContentType).Pattern;
|
||||
|
||||
// String.Empty forces pattern based generation. "/" forces homepage
|
||||
if(part.UseCustomPattern
|
||||
&& (!String.IsNullOrWhiteSpace(part.CustomPattern) || String.Equals(part.CustomPattern, "/"))) {
|
||||
pattern = part.CustomPattern;
|
||||
}
|
||||
|
||||
// Convert the pattern and route values via tokens
|
||||
var path = _tokenizer.Replace(pattern, BuildTokenContext(part.ContentItem), new ReplaceOptions { Encoding = ReplaceOptions.NoEncode });
|
||||
|
||||
// removing trailing slashes in case the container is empty, and tokens are base on it (e.g. home page)
|
||||
while(path.StartsWith("/")) {
|
||||
path = path.Substring(1);
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
public void PublishAlias(AutoroutePart part) {
|
||||
var displayRouteValues = _contentManager.GetItemMetadata(part).DisplayRouteValues;
|
||||
|
||||
_aliasService.Replace(part.DisplayAlias, displayRouteValues, AliasSource);
|
||||
|
||||
_routeEvents.Routed(part, part.DisplayAlias);
|
||||
}
|
||||
|
||||
private IDictionary<string, object> BuildTokenContext(IContent item) {
|
||||
return new Dictionary<string, object> { { "Content", item } };
|
||||
}
|
||||
|
||||
public void CreatePattern(string contentType, string name, string pattern, string description, bool makeDefault) {
|
||||
var contentDefinition = _contentDefinitionManager.GetTypeDefinition(contentType);
|
||||
|
||||
if (contentDefinition == null) {
|
||||
throw new OrchardException(T("Unknown content type: {0}", contentType));
|
||||
}
|
||||
|
||||
var settings = contentDefinition.Settings.GetModel<AutorouteSettings>();
|
||||
|
||||
var routePattern = new RoutePattern {
|
||||
Description = description,
|
||||
Name = name,
|
||||
Pattern = pattern
|
||||
};
|
||||
|
||||
var patterns = settings.Patterns;
|
||||
patterns.Add(routePattern);
|
||||
settings.Patterns = patterns;
|
||||
|
||||
// define which pattern is the default
|
||||
if (makeDefault || settings.Patterns.Count == 1) {
|
||||
settings.DefaultPatternIndex = settings.Patterns.IndexOf(routePattern);
|
||||
}
|
||||
|
||||
_contentDefinitionManager.AlterTypeDefinition(contentType, builder => builder.WithPart("AutoroutePart", settings.Build));
|
||||
}
|
||||
|
||||
public IEnumerable<RoutePattern> GetPatterns(string contentType) {
|
||||
var settings = GetTypePartSettings(contentType).GetModel<AutorouteSettings>();
|
||||
return settings.Patterns;
|
||||
}
|
||||
|
||||
public RoutePattern GetDefaultPattern(string contentType) {
|
||||
var settings = GetTypePartSettings(contentType).GetModel<AutorouteSettings>();
|
||||
|
||||
// return a default pattern if none is defined
|
||||
if(settings.DefaultPatternIndex < settings.Patterns.Count) {
|
||||
return settings.Patterns.ElementAt(settings.DefaultPatternIndex);
|
||||
}
|
||||
|
||||
return new RoutePattern {Name = "Title", Description = "my-title", Pattern = "{Content.Slug}"};
|
||||
}
|
||||
|
||||
public void RemoveAliases(AutoroutePart part) {
|
||||
_aliasService.Delete(part.Path, AliasSource);
|
||||
}
|
||||
|
||||
private SettingsDictionary GetTypePartSettings(string contentType) {
|
||||
var contentDefinition = _contentDefinitionManager.GetTypeDefinition(contentType);
|
||||
|
||||
if (contentDefinition == null) {
|
||||
throw new OrchardException(T("Unknown content type: {0}", contentType));
|
||||
}
|
||||
|
||||
return contentDefinition.Parts.First(x => x.PartDefinition.Name == "AutoroutePart").Settings;
|
||||
}
|
||||
|
||||
public string GenerateUniqueSlug(AutoroutePart part, IEnumerable<string> existingPaths) {
|
||||
if (existingPaths == null || !existingPaths.Contains(part.Path))
|
||||
return part.Path;
|
||||
|
||||
int? version = existingPaths.Select(s => GetSlugVersion(part.Path, s)).OrderBy(i => i).LastOrDefault();
|
||||
|
||||
return version != null
|
||||
? string.Format("{0}-{1}", part.Path, version)
|
||||
: part.Path;
|
||||
}
|
||||
|
||||
private static int? GetSlugVersion(string path, string potentialConflictingPath) {
|
||||
int v;
|
||||
string[] slugParts = potentialConflictingPath.Split(new[] { path }, StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
if (slugParts.Length == 0)
|
||||
return 2;
|
||||
|
||||
return int.TryParse(slugParts[0].TrimStart('-'), out v)
|
||||
? (int?)++v
|
||||
: null;
|
||||
}
|
||||
|
||||
public IEnumerable<AutoroutePart> GetSimilarPaths(string path) {
|
||||
return
|
||||
_contentManager.Query<AutoroutePart, AutoroutePartRecord>()
|
||||
.Where(part => part.DisplayAlias != null && part.DisplayAlias.StartsWith(path))
|
||||
.List();
|
||||
}
|
||||
|
||||
public bool IsPathValid(string slug) {
|
||||
return String.IsNullOrWhiteSpace(slug) || Regex.IsMatch(slug, @"^[^:?#\[\]@!$&'()*+,;=\s\""\<\>\\]+$") && !(slug.StartsWith(".") || slug.EndsWith("."));
|
||||
}
|
||||
|
||||
public bool ProcessPath(AutoroutePart part) {
|
||||
|
||||
var pathsLikeThis = GetSimilarPaths(part.Path).ToArray();
|
||||
|
||||
// Don't include *this* part in the list
|
||||
// of slugs to consider for conflict detection
|
||||
pathsLikeThis = pathsLikeThis.Where(p => p.ContentItem.Id != part.ContentItem.Id).ToArray();
|
||||
|
||||
if (pathsLikeThis.Any()) {
|
||||
var originalPath = part.Path;
|
||||
var newPath = GenerateUniqueSlug(part, pathsLikeThis.Select(p => p.Path));
|
||||
part.DisplayAlias = newPath;
|
||||
|
||||
if (originalPath != newPath)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
using Orchard.ContentManagement;
|
||||
using System.Text.RegularExpressions;
|
||||
using Orchard.Utility.Extensions;
|
||||
|
||||
namespace Orchard.Autoroute.Services {
|
||||
|
||||
public class DefaultSlugService : ISlugService {
|
||||
|
||||
private readonly ISlugEventHandler _slugEventHandler;
|
||||
|
||||
public DefaultSlugService(
|
||||
ISlugEventHandler slugEventHander
|
||||
) {
|
||||
_slugEventHandler = slugEventHander;
|
||||
}
|
||||
|
||||
public string Slugify(IContent content) {
|
||||
var metadata = content.ContentItem.ContentManager.GetItemMetadata(content);
|
||||
if (metadata == null) return null;
|
||||
var title = metadata.DisplayText.Trim();
|
||||
return Slugify(new FillSlugContext(content,title));
|
||||
}
|
||||
|
||||
private string Slugify(FillSlugContext slugContext) {
|
||||
_slugEventHandler.FillingSlugFromTitle(slugContext);
|
||||
|
||||
if (!slugContext.Adjusted) {
|
||||
|
||||
var disallowed = new Regex(@"[/:?#\[\]@!$&'()*+,;=\s\""\<\>\\]+");
|
||||
|
||||
slugContext.Slug = disallowed.Replace(slugContext.Title, "-").Trim('-','.');
|
||||
|
||||
if (slugContext.Slug.Length > 1000)
|
||||
slugContext.Slug = slugContext.Slug.Substring(0, 1000).Trim('-', '.');
|
||||
|
||||
slugContext.Slug = StringExtensions.RemoveDiacritics(slugContext.Slug.ToLower());
|
||||
}
|
||||
|
||||
_slugEventHandler.FilledSlugFromTitle(slugContext);
|
||||
|
||||
return slugContext.Slug;
|
||||
}
|
||||
|
||||
public string Slugify(string text) {
|
||||
return Slugify(new FillSlugContext(null, text));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
using System.Collections.Generic;
|
||||
using Orchard.Autoroute.Models;
|
||||
using Orchard.Autoroute.Settings;
|
||||
|
||||
namespace Orchard.Autoroute.Services {
|
||||
|
||||
/// <summary>
|
||||
/// Provides main services for Autoroute module
|
||||
/// </summary>
|
||||
public interface IAutorouteService : IDependency {
|
||||
|
||||
string GenerateAlias(AutoroutePart part);
|
||||
void PublishAlias(AutoroutePart part);
|
||||
|
||||
void RemoveAliases(AutoroutePart part);
|
||||
|
||||
void CreatePattern(string contentType, string name, string pattern, string description, bool makeDefault);
|
||||
RoutePattern GetDefaultPattern(string contentType);
|
||||
IEnumerable<RoutePattern> GetPatterns(string contentType);
|
||||
bool ProcessPath(AutoroutePart part);
|
||||
bool IsPathValid(string slug);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
using System;
|
||||
using Orchard.ContentManagement;
|
||||
using Orchard.Events;
|
||||
|
||||
namespace Orchard.Autoroute.Services {
|
||||
public interface IRouteEvents : IEventHandler {
|
||||
void Routed(IContent content, String path);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
using Orchard.Events;
|
||||
using Orchard.ContentManagement;
|
||||
|
||||
namespace Orchard.Autoroute.Services {
|
||||
public interface ISlugEventHandler : IEventHandler {
|
||||
void FillingSlugFromTitle(FillSlugContext context);
|
||||
void FilledSlugFromTitle(FillSlugContext context);
|
||||
}
|
||||
|
||||
public class FillSlugContext {
|
||||
public FillSlugContext(IContent content, string title) {
|
||||
Content = content;
|
||||
Title = title;
|
||||
}
|
||||
public IContent Content { get; set; }
|
||||
public string Title { get; set; }
|
||||
public string Slug { get; set; }
|
||||
public bool Adjusted { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace Orchard.Autoroute.Services {
|
||||
public interface ISlugService : IDependency {
|
||||
string Slugify(ContentManagement.IContent content);
|
||||
string Slugify(string text);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Web.Script.Serialization;
|
||||
using Orchard.ContentManagement.MetaData.Builders;
|
||||
|
||||
namespace Orchard.Autoroute.Settings {
|
||||
|
||||
/// <summary>
|
||||
/// Settings when attaching part to a content item
|
||||
/// </summary>
|
||||
public class AutorouteSettings {
|
||||
|
||||
private List<RoutePattern> _patterns;
|
||||
|
||||
public AutorouteSettings() {
|
||||
PerItemConfiguration = false;
|
||||
AllowCustomPattern = true;
|
||||
AutomaticAdjustmentOnEdit = false;
|
||||
PatternDefinitions = "[]";
|
||||
}
|
||||
|
||||
public bool PerItemConfiguration { get; set; }
|
||||
public bool AllowCustomPattern { get; set; }
|
||||
public bool AutomaticAdjustmentOnEdit { get; set; }
|
||||
public int DefaultPatternIndex { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A serialized Json array of <see cref="RoutePattern"/> objects
|
||||
/// </summary>
|
||||
public string PatternDefinitions { get; set; }
|
||||
|
||||
public List<RoutePattern> Patterns {
|
||||
get {
|
||||
if (_patterns == null) {
|
||||
_patterns = new JavaScriptSerializer().Deserialize<RoutePattern[]>(PatternDefinitions).ToList();
|
||||
}
|
||||
|
||||
return _patterns;
|
||||
}
|
||||
|
||||
set {
|
||||
_patterns = value;
|
||||
PatternDefinitions = new JavaScriptSerializer().Serialize(_patterns.ToArray());
|
||||
}
|
||||
}
|
||||
|
||||
public void Build(ContentTypePartDefinitionBuilder builder) {
|
||||
builder.WithSetting("AutorouteSettings.PerItemConfiguration", PerItemConfiguration.ToString(CultureInfo.InvariantCulture));
|
||||
builder.WithSetting("AutorouteSettings.AllowCustomPattern", AllowCustomPattern.ToString(CultureInfo.InvariantCulture));
|
||||
builder.WithSetting("AutorouteSettings.AutomaticAdjustmentOnEdit", AutomaticAdjustmentOnEdit.ToString(CultureInfo.InvariantCulture));
|
||||
builder.WithSetting("AutorouteSettings.PatternDefinitions", PatternDefinitions);
|
||||
builder.WithSetting("AutorouteSettings.DefaultPatternIndex", DefaultPatternIndex.ToString(CultureInfo.InvariantCulture));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Orchard.ContentManagement;
|
||||
using Orchard.ContentManagement.MetaData;
|
||||
using Orchard.ContentManagement.MetaData.Builders;
|
||||
using Orchard.ContentManagement.MetaData.Models;
|
||||
using Orchard.ContentManagement.ViewModels;
|
||||
using Orchard.Localization;
|
||||
using Orchard.UI.Notify;
|
||||
|
||||
namespace Orchard.Autoroute.Settings {
|
||||
public class AutorouteSettingsHooks : ContentDefinitionEditorEventsBase {
|
||||
private readonly INotifier _notifier;
|
||||
|
||||
public AutorouteSettingsHooks(INotifier notifier) {
|
||||
_notifier = notifier;
|
||||
}
|
||||
|
||||
public Localizer T { get; set; }
|
||||
|
||||
public override IEnumerable<TemplateViewModel> TypePartEditor(ContentTypePartDefinition definition) {
|
||||
if (definition.PartDefinition.Name != "AutoroutePart")
|
||||
yield break;
|
||||
|
||||
var settings = definition.Settings.GetModel<AutorouteSettings>();
|
||||
|
||||
// add an empty pattern for the editor
|
||||
settings.Patterns.Add(new RoutePattern());
|
||||
|
||||
yield return DefinitionTemplate(settings);
|
||||
}
|
||||
|
||||
public override IEnumerable<TemplateViewModel> TypePartEditorUpdate(ContentTypePartDefinitionBuilder builder, IUpdateModel updateModel) {
|
||||
if (builder.Name != "AutoroutePart")
|
||||
yield break;
|
||||
|
||||
var settings = new AutorouteSettings {
|
||||
Patterns = new List<RoutePattern>()
|
||||
};
|
||||
|
||||
if (updateModel.TryUpdateModel(settings, "AutorouteSettings", null, null)) {
|
||||
|
||||
var defaultPattern = settings.Patterns[settings.DefaultPatternIndex];
|
||||
// remove empty patterns
|
||||
var patterns = settings.Patterns;
|
||||
patterns.RemoveAll(p => String.IsNullOrWhiteSpace(p.Name) && String.IsNullOrWhiteSpace(p.Pattern) && String.IsNullOrWhiteSpace(p.Description));
|
||||
|
||||
if (patterns.Count == 0) {
|
||||
patterns.Add(new RoutePattern {
|
||||
Name = "Title",
|
||||
Description = "my-title",
|
||||
Pattern = "{Content.Slug}"
|
||||
});
|
||||
|
||||
_notifier.Warning(T("A default pattern has been added to AutoroutePart"));
|
||||
}
|
||||
|
||||
settings.Patterns = patterns;
|
||||
// search for the pattern which was marked as default, and update its index
|
||||
settings.DefaultPatternIndex = patterns.IndexOf(defaultPattern);
|
||||
|
||||
// if a wrong pattern was selected and there is at least one pattern, default to first
|
||||
if (settings.DefaultPatternIndex == -1 && settings.Patterns.Any()) {
|
||||
settings.DefaultPatternIndex = 0;
|
||||
}
|
||||
|
||||
// update the settings builder
|
||||
settings.Build(builder);
|
||||
}
|
||||
|
||||
yield return DefinitionTemplate(settings);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
namespace Orchard.Autoroute.Settings {
|
||||
|
||||
/// <summary>
|
||||
/// Models the patterns you can choose from
|
||||
/// </summary>
|
||||
public class RoutePattern {
|
||||
public string Name { get; set; }
|
||||
public string Pattern { get; set; }
|
||||
public string Description { get; set; }
|
||||
}
|
||||
}
|
||||
12
src/Orchard.Web/Modules/Orchard.Autoroute/Specs/App.config
Normal file
12
src/Orchard.Web/Modules/Orchard.Autoroute/Specs/App.config
Normal file
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<configuration>
|
||||
<configSections>
|
||||
<section name="specFlow" type="TechTalk.SpecFlow.Configuration.ConfigurationSectionHandler, TechTalk.SpecFlow" />
|
||||
</configSections>
|
||||
<specFlow>
|
||||
<unitTestProvider name="NUnit" />
|
||||
<stepAssemblies>
|
||||
<stepAssembly assembly="Orchard.Specs" />
|
||||
</stepAssemblies>
|
||||
</specFlow>
|
||||
</configuration>
|
||||
@@ -0,0 +1,27 @@
|
||||
Feature: Autoroutes
|
||||
In order to add content to my site
|
||||
As an author
|
||||
I want to create, publish and edit routes
|
||||
|
||||
Scenario: I can create and publish a new Page with international characters in its route
|
||||
Given I have installed Orchard
|
||||
When I go to "admin/contents/create/page"
|
||||
And I fill in
|
||||
| name | value |
|
||||
| Title.Title | Χελλο |
|
||||
And I hit "Publish Now"
|
||||
And I go to "Χελλο"
|
||||
Then I should see "<h1[^>]*>.*?Χελλο.*?</h1>"
|
||||
|
||||
Scenario: I can create and publish a new Home Page
|
||||
Given I have installed Orchard
|
||||
When I go to "admin/contents/create/page"
|
||||
And I fill in
|
||||
| name | value |
|
||||
| Title.Title | Foo |
|
||||
| Autoroute.PromoteToHomePage | True |
|
||||
And I hit "Publish Now"
|
||||
And I go to "/"
|
||||
Then I should see "<h1[^>]*>.*?Foo.*?</h1>"
|
||||
When I go to "/welcome-to-orchard"
|
||||
Then I should see "<h1[^>]*>.*?Welcome.*?</h1>"
|
||||
137
src/Orchard.Web/Modules/Orchard.Autoroute/Specs/Autoroute.feature.cs
generated
Normal file
137
src/Orchard.Web/Modules/Orchard.Autoroute/Specs/Autoroute.feature.cs
generated
Normal file
@@ -0,0 +1,137 @@
|
||||
// ------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by SpecFlow (http://www.specflow.org/).
|
||||
// SpecFlow Version:1.9.0.77
|
||||
// SpecFlow Generator Version:1.9.0.0
|
||||
// Runtime Version:4.0.30319.17929
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
// ------------------------------------------------------------------------------
|
||||
#region Designer generated code
|
||||
#pragma warning disable
|
||||
namespace Orchard.Autoroute.Specs
|
||||
{
|
||||
using TechTalk.SpecFlow;
|
||||
|
||||
|
||||
[System.CodeDom.Compiler.GeneratedCodeAttribute("TechTalk.SpecFlow", "1.9.0.77")]
|
||||
[System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
[NUnit.Framework.TestFixtureAttribute()]
|
||||
[NUnit.Framework.DescriptionAttribute("Autoroutes")]
|
||||
public partial class AutoroutesFeature
|
||||
{
|
||||
|
||||
private static TechTalk.SpecFlow.ITestRunner testRunner;
|
||||
|
||||
#line 1 "Autoroute.feature"
|
||||
#line hidden
|
||||
|
||||
[NUnit.Framework.TestFixtureSetUpAttribute()]
|
||||
public virtual void FeatureSetup()
|
||||
{
|
||||
testRunner = TechTalk.SpecFlow.TestRunnerManager.GetTestRunner();
|
||||
TechTalk.SpecFlow.FeatureInfo featureInfo = new TechTalk.SpecFlow.FeatureInfo(new System.Globalization.CultureInfo("en-US"), "Autoroutes", " In order to add content to my site\r\n As an author\r\n I want to create, publish" +
|
||||
" and edit routes", ProgrammingLanguage.CSharp, ((string[])(null)));
|
||||
testRunner.OnFeatureStart(featureInfo);
|
||||
}
|
||||
|
||||
[NUnit.Framework.TestFixtureTearDownAttribute()]
|
||||
public virtual void FeatureTearDown()
|
||||
{
|
||||
testRunner.OnFeatureEnd();
|
||||
testRunner = null;
|
||||
}
|
||||
|
||||
[NUnit.Framework.SetUpAttribute()]
|
||||
public virtual void TestInitialize()
|
||||
{
|
||||
}
|
||||
|
||||
[NUnit.Framework.TearDownAttribute()]
|
||||
public virtual void ScenarioTearDown()
|
||||
{
|
||||
testRunner.OnScenarioEnd();
|
||||
}
|
||||
|
||||
public virtual void ScenarioSetup(TechTalk.SpecFlow.ScenarioInfo scenarioInfo)
|
||||
{
|
||||
testRunner.OnScenarioStart(scenarioInfo);
|
||||
}
|
||||
|
||||
public virtual void ScenarioCleanup()
|
||||
{
|
||||
testRunner.CollectScenarioErrors();
|
||||
}
|
||||
|
||||
[NUnit.Framework.TestAttribute()]
|
||||
[NUnit.Framework.DescriptionAttribute("I can create and publish a new Page with international characters in its route")]
|
||||
public virtual void ICanCreateAndPublishANewPageWithInternationalCharactersInItsRoute()
|
||||
{
|
||||
TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("I can create and publish a new Page with international characters in its route", ((string[])(null)));
|
||||
#line 6
|
||||
this.ScenarioSetup(scenarioInfo);
|
||||
#line 7
|
||||
testRunner.Given("I have installed Orchard", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Given ");
|
||||
#line 8
|
||||
testRunner.When("I go to \"admin/contents/create/page\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When ");
|
||||
#line hidden
|
||||
TechTalk.SpecFlow.Table table1 = new TechTalk.SpecFlow.Table(new string[] {
|
||||
"name",
|
||||
"value"});
|
||||
table1.AddRow(new string[] {
|
||||
"Title.Title",
|
||||
"Χελλο"});
|
||||
#line 9
|
||||
testRunner.And("I fill in", ((string)(null)), table1, "And ");
|
||||
#line 12
|
||||
testRunner.And("I hit \"Publish Now\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 13
|
||||
testRunner.And("I go to \"Χελλο\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 14
|
||||
testRunner.Then("I should see \"<h1[^>]*>.*?Χελλο.*?</h1>\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then ");
|
||||
#line hidden
|
||||
this.ScenarioCleanup();
|
||||
}
|
||||
|
||||
[NUnit.Framework.TestAttribute()]
|
||||
[NUnit.Framework.DescriptionAttribute("I can create and publish a new Home Page")]
|
||||
public virtual void ICanCreateAndPublishANewHomePage()
|
||||
{
|
||||
TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("I can create and publish a new Home Page", ((string[])(null)));
|
||||
#line 16
|
||||
this.ScenarioSetup(scenarioInfo);
|
||||
#line 17
|
||||
testRunner.Given("I have installed Orchard", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Given ");
|
||||
#line 18
|
||||
testRunner.When("I go to \"admin/contents/create/page\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When ");
|
||||
#line hidden
|
||||
TechTalk.SpecFlow.Table table2 = new TechTalk.SpecFlow.Table(new string[] {
|
||||
"name",
|
||||
"value"});
|
||||
table2.AddRow(new string[] {
|
||||
"Title.Title",
|
||||
"Foo"});
|
||||
table2.AddRow(new string[] {
|
||||
"Autoroute.PromoteToHomePage",
|
||||
"True"});
|
||||
#line 19
|
||||
testRunner.And("I fill in", ((string)(null)), table2, "And ");
|
||||
#line 23
|
||||
testRunner.And("I hit \"Publish Now\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 24
|
||||
testRunner.And("I go to \"/\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 25
|
||||
testRunner.Then("I should see \"<h1[^>]*>.*?Foo.*?</h1>\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then ");
|
||||
#line 26
|
||||
testRunner.When("I go to \"/welcome-to-orchard\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When ");
|
||||
#line 27
|
||||
testRunner.Then("I should see \"<h1[^>]*>.*?Welcome.*?</h1>\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then ");
|
||||
#line hidden
|
||||
this.ScenarioCleanup();
|
||||
}
|
||||
}
|
||||
}
|
||||
#pragma warning restore
|
||||
#endregion
|
||||
@@ -0,0 +1,77 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProductVersion>8.0.30703</ProductVersion>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<ProjectGuid>{AC4402A1-61C4-4229-B840-FB1777DAE10C}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>Orchard.Autoroute.Specs</RootNamespace>
|
||||
<AssemblyName>Orchard.Autoroute.Specs</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="nunit.framework">
|
||||
<HintPath>..\..\..\..\..\lib\nunit\nunit.framework.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Xml" />
|
||||
<Reference Include="TechTalk.SpecFlow">
|
||||
<HintPath>..\..\..\..\..\lib\specflow\TechTalk.SpecFlow.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Autoroute.feature.cs">
|
||||
<AutoGen>True</AutoGen>
|
||||
<DesignTime>True</DesignTime>
|
||||
<DependentUpon>Autoroute.feature</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\..\Orchard.Specs\Orchard.Specs.csproj">
|
||||
<Project>{7354DF37-934B-46CF-A13C-455D5F5F5413}</Project>
|
||||
<Name>Orchard.Specs</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="App.config" />
|
||||
<None Include="Autoroute.feature">
|
||||
<Generator>SpecFlowSingleFileGenerator</Generator>
|
||||
<LastGenOutput>Autoroute.feature.cs</LastGenOutput>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
||||
@@ -0,0 +1,33 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("Orchard.Autoroute.Specs")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("Microsoft")]
|
||||
[assembly: AssemblyProduct("Orchard")]
|
||||
[assembly: AssemblyCopyright("Outercurve Foundation 2011")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
21
src/Orchard.Web/Modules/Orchard.Autoroute/Styles/Web.config
Normal file
21
src/Orchard.Web/Modules/Orchard.Autoroute/Styles/Web.config
Normal file
@@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration>
|
||||
<appSettings>
|
||||
<add key="webpages:Enabled" value="false" />
|
||||
</appSettings>
|
||||
<system.web>
|
||||
<httpHandlers>
|
||||
<!-- iis6 - for any request in this location, return via managed static file handler -->
|
||||
<add path="*" verb="*" type="System.Web.StaticFileHandler" />
|
||||
</httpHandlers>
|
||||
</system.web>
|
||||
<system.webServer>
|
||||
<handlers accessPolicy="Script,Read">
|
||||
<!--
|
||||
iis7 - for any request to a file exists on disk, return it via native http module.
|
||||
accessPolicy 'Script' is to allow for a managed 404 page.
|
||||
-->
|
||||
<add name="StaticFile" path="*" verb="*" modules="StaticFileModule" preCondition="integratedMode" resourceType="File" requireAccess="Read" />
|
||||
</handlers>
|
||||
</system.webServer>
|
||||
</configuration>
|
||||
@@ -0,0 +1,23 @@
|
||||
.autoroute-settings-default {
|
||||
width: 5%;
|
||||
}
|
||||
.autoroute-settings-name {
|
||||
width: 20%
|
||||
}
|
||||
|
||||
.autoroute-settings-pat {
|
||||
width: 30%
|
||||
}
|
||||
|
||||
.autoroute-settings-desc {
|
||||
width: 40%
|
||||
}
|
||||
|
||||
.autoroute-settings-actions {
|
||||
width: 10%;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.autoroute-settings-patterns tr td input {
|
||||
width: 100%;
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
using Orchard.Autoroute.Settings;
|
||||
|
||||
namespace Orchard.Autoroute.ViewModels {
|
||||
|
||||
public class AutoroutePartEditViewModel {
|
||||
public AutorouteSettings Settings { get; set; }
|
||||
public bool PromoteToHomePage { get; set; }
|
||||
public string CurrentUrl { get; set; }
|
||||
public string CustomPattern { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
@model Orchard.Autoroute.Settings.AutorouteSettings
|
||||
@using Orchard.Utility.Extensions;
|
||||
|
||||
@{
|
||||
Style.Require("AutorouteSettings");
|
||||
}
|
||||
@*<fieldset>
|
||||
<div>
|
||||
@Html.CheckBoxFor(m => m.PerItemConfiguration)
|
||||
<label class="forcheckbox" for="@Html.FieldIdFor(m => m.PerItemConfiguration)">@T("Per item configuration")</label>
|
||||
<span class="hint">@T("Allow the user to change the pattern on each item")</span>
|
||||
</div>
|
||||
</fieldset>
|
||||
*@<fieldset>
|
||||
<div>
|
||||
@Html.CheckBoxFor(m => m.AllowCustomPattern)
|
||||
<label class="forcheckbox" for="@Html.FieldIdFor(m => m.AllowCustomPattern)">@T("Allow custom patterns")</label>
|
||||
<span class="hint">@T("Allow the user to change the pattern on each item")</span>
|
||||
</div>
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<div>
|
||||
@Html.CheckBoxFor(m => m.AutomaticAdjustmentOnEdit)
|
||||
<label class="forcheckbox" for="@Html.FieldIdFor(m => m.AutomaticAdjustmentOnEdit)">@T("Automatically regenerate when editing content")</label>
|
||||
<span class="hint">@T("This option will cause the Url to automatically be regenerated when you edit existing content and publish it again, otherwise it will always keep the old route, or you have to perform bulk update in the Autoroute admin.")</span>
|
||||
</div>
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<label>@T("Patterns:")</label>
|
||||
<table class="items autoroute-settings-patterns">
|
||||
<tr>
|
||||
<th class="autoroute-settings-default">@T("Default")</th>
|
||||
<th class="autoroute-settings-name">@T("Name")<span class="hint">@T("Name of the pattern")</span></th>
|
||||
<th class="autoroute-settings-pat">@T("Pattern")<span class="hint">@T("The definition of the pattern")</span></th>
|
||||
<th class="autoroute-settings-desc">@T("Description")<span class="hint">@T("The description of the pattern, displayed in the editor")</span></th>
|
||||
<th class="autoroute-settings-actions"> </th>
|
||||
</tr>
|
||||
|
||||
@for (int index = 0; index < Model.Patterns.Count; index++) {
|
||||
<tr>
|
||||
<td>@Html.RadioButtonFor(m => m.DefaultPatternIndex, index, new { @class = "radio" })</td>
|
||||
<td>@Html.TextBoxFor(m => m.Patterns[index].Name, new { @class = "text-box"})</td>
|
||||
<td>@Html.TextBoxFor(m => m.Patterns[index].Pattern, new { @class = "tokenized text-box" })</td>
|
||||
<td>@Html.TextBoxFor(m => m.Patterns[index].Description, new { @class = "text-box" })</td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
}
|
||||
|
||||
<tr>
|
||||
</tr>
|
||||
</table>
|
||||
</fieldset>
|
||||
|
||||
@Display.TokenHint()
|
||||
@@ -0,0 +1,38 @@
|
||||
@model Orchard.Autoroute.ViewModels.AutoroutePartEditViewModel
|
||||
@using Orchard.Autoroute
|
||||
@using Orchard.Utility.Extensions;
|
||||
|
||||
@if(Model.Settings.DefaultPatternIndex == -1) {
|
||||
<div class="message message-Error">@T("The current Content Type does not have a default Autoroute Pattern. Please edit the settings first.")</div>
|
||||
return;
|
||||
}
|
||||
|
||||
@{
|
||||
var defaultPattern = Model.Settings.Patterns[Model.Settings.DefaultPatternIndex];
|
||||
}
|
||||
|
||||
<fieldset class="permalink">
|
||||
<label>@T("Permalink")</label>
|
||||
@if (Model.Settings.AllowCustomPattern) {
|
||||
<span>@ViewContext.RequestContext.HttpContext.Request.ToApplicationRootUrlString()/</span>
|
||||
<span>@Html.TextBoxFor(m => m.CurrentUrl, new { @class = "text" })</span>
|
||||
}
|
||||
else {
|
||||
<span>@ViewContext.RequestContext.HttpContext.Request.ToApplicationRootUrlString()/</span>
|
||||
<span>@Model.CurrentUrl</span>
|
||||
}
|
||||
|
||||
<span class="hint">@T("Leave empty to use the default permalink pattern ({0}: {1})", defaultPattern.Name, defaultPattern.Description)</span>
|
||||
|
||||
</fieldset>
|
||||
|
||||
<fieldset>
|
||||
@if (AuthorizedFor(Permissions.SetHomePage) && !Model.PromoteToHomePage) {
|
||||
<span class="checkbox-and-label">
|
||||
@Html.EditorFor(m => m.PromoteToHomePage)
|
||||
<label for="@Html.FieldIdFor(m => m.PromoteToHomePage)" class="forcheckbox">@T("Set as home page")</label>
|
||||
</span>
|
||||
<span class="hint">@T("Check to promote this content as the home page")</span>
|
||||
}
|
||||
|
||||
</fieldset>
|
||||
41
src/Orchard.Web/Modules/Orchard.Autoroute/Views/Web.config
Normal file
41
src/Orchard.Web/Modules/Orchard.Autoroute/Views/Web.config
Normal file
@@ -0,0 +1,41 @@
|
||||
<?xml version="1.0"?>
|
||||
<configuration>
|
||||
<appSettings>
|
||||
<add key="webpages:Enabled" value="false" />
|
||||
</appSettings>
|
||||
<system.web>
|
||||
<httpHandlers>
|
||||
</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=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL"
|
||||
pageBaseType="System.Web.Mvc.ViewPage, System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL"
|
||||
userControlBaseType="System.Web.Mvc.ViewUserControl, System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<controls>
|
||||
<add assembly="System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL" namespace="System.Web.Mvc" tagPrefix="mvc" />
|
||||
</controls>
|
||||
</pages>
|
||||
</system.web>
|
||||
|
||||
<system.webServer>
|
||||
<validation validateIntegratedModeConfiguration="false"/>
|
||||
<handlers>
|
||||
</handlers>
|
||||
</system.webServer>
|
||||
<runtime>
|
||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" />
|
||||
<bindingRedirect oldVersion="2.0.0.0" newVersion="3.0.0.0" />
|
||||
</dependentAssembly>
|
||||
</assemblyBinding>
|
||||
</runtime>
|
||||
</configuration>
|
||||
40
src/Orchard.Web/Modules/Orchard.Autoroute/Web.config
Normal file
40
src/Orchard.Web/Modules/Orchard.Autoroute/Web.config
Normal file
@@ -0,0 +1,40 @@
|
||||
<?xml version="1.0"?>
|
||||
<configuration>
|
||||
|
||||
<configSections>
|
||||
<sectionGroup name="system.web.webPages.razor" type="System.Web.WebPages.Razor.Configuration.RazorWebSectionGroup, System.Web.WebPages.Razor, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
|
||||
<remove name="host" />
|
||||
<remove name="pages" />
|
||||
<section name="host" type="System.Web.WebPages.Razor.Configuration.HostSection, System.Web.WebPages.Razor, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" />
|
||||
<section name="pages" type="System.Web.WebPages.Razor.Configuration.RazorPagesSection, System.Web.WebPages.Razor, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" />
|
||||
</sectionGroup>
|
||||
</configSections>
|
||||
|
||||
<system.web.webPages.razor>
|
||||
<host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
|
||||
<pages pageBaseType="Orchard.Mvc.ViewEngines.Razor.WebViewPage">
|
||||
<namespaces>
|
||||
<add namespace="System.Web.Mvc" />
|
||||
<add namespace="System.Web.Mvc.Ajax" />
|
||||
<add namespace="System.Web.Mvc.Html" />
|
||||
<add namespace="System.Web.Routing" />
|
||||
<add namespace="System.Linq"/>
|
||||
<add namespace="System.Collections.Generic"/>
|
||||
<add namespace="Orchard.Mvc.Html"/>
|
||||
</namespaces>
|
||||
</pages>
|
||||
</system.web.webPages.razor>
|
||||
|
||||
<system.web>
|
||||
<compilation targetFramework="4.0">
|
||||
<assemblies>
|
||||
<add assembly="System.Web.Abstractions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
|
||||
<add assembly="System.Web.Routing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
|
||||
<add assembly="System.Data.Linq, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
|
||||
<add assembly="System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
|
||||
<add assembly="System.Web.WebPages, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
|
||||
</assemblies>
|
||||
</compilation>
|
||||
</system.web>
|
||||
|
||||
</configuration>
|
||||
Reference in New Issue
Block a user