Merge with 1.x

This commit is contained in:
Sebastien Ros 2012-07-07 15:21:52 -07:00
commit 1b5f9b2a16
325 changed files with 5127 additions and 2673 deletions

6
.hgsub
View File

@ -6,4 +6,8 @@ src/Orchard.Web/Modules/Orchard.TaskLease = https://hg.codeplex.com/orchardtaskl
src/orchard.web/modules/Orchard.Fields = https://hg.codeplex.com/orchardfields
src/Orchard.Web/Modules/Orchard.Autoroute = https://hg.codeplex.com/orchardautoroute
src/orchard.web/Modules/Orchard.Alias = https://hg.codeplex.com/orchardalias
src/orchard.web/Modules/Orchard.Projections = https://hg.codeplex.com/orchardprojections
src/orchard.web/Modules/Orchard.Projections = https://hg.codeplex.com/orchardprojections
src/Orchard.Web/Modules/Orchard.AntiSpam = https://hg.codeplex.com/orchardantispam
src/Orchard.Web/Modules/Orchard.CustomForms = https://hg.codeplex.com/orchardcustomforms
src/Orchard.Web/Modules/Orchard.ContentPermissions = https://hg.codeplex.com/orchardcontentperm
src/Orchard.Web/Modules/Orchard.ContentPicker = https://hg.codeplex.com/orchardcontentpicker

View File

@ -1,8 +1,12 @@
bf20391f8fe1ba5d67cadc0643d79ad9fe892d4e src/Orchard.Web/Modules/Orchard.Autoroute
e7fc05ff6137ed5459d198b2bea9a5804818b0bd src/Orchard.Web/Modules/Orchard.Forms
681acdfadd946098a10a4a22f6904e8c482c122f src/Orchard.Web/Modules/Orchard.Rules
c47525e90819321d37962a11313006a4ccfc8362 src/Orchard.Web/Modules/Orchard.AntiSpam
03306c0dad118c03c4ee21ce274a5f9c5855aec3 src/Orchard.Web/Modules/Orchard.Autoroute
a8cd78f4730747bf592935aaa605874938a9c89f src/Orchard.Web/Modules/Orchard.ContentPermissions
4a97d09dc6a31a083643c4b7468c307413a43f44 src/Orchard.Web/Modules/Orchard.ContentPicker
3ad1bdc80b8374433d98469e8740bc48ef114be2 src/Orchard.Web/Modules/Orchard.CustomForms
b639cb33d2ba038de6048350400b664399608996 src/Orchard.Web/Modules/Orchard.Forms
b748de63e3cf8debfc3eba77f26089705147047d src/Orchard.Web/Modules/Orchard.Rules
419399ef2e37122a000e6cc8674148d3183d7032 src/Orchard.Web/Modules/Orchard.TaskLease
aca1f5aeb5dd426bc80c6142afc7f2717fc6d5a1 src/Orchard.Web/Modules/Orchard.Tokens
4ed51e0e76c2aacc2de90ce9984fd00cfdfae2ce src/orchard.web/Modules/Orchard.Alias
f5353e9e0f678d396735df6eb6ca3c7f30a09660 src/orchard.web/Modules/Orchard.Projections
4d125be1a6b35451214768cd8e46b6e7e2b08174 src/orchard.web/modules/Orchard.Fields
63dda71453ebbfd0e165662a0d56c9c0a7a3d3d4 src/Orchard.Web/Modules/Orchard.Tokens
a47761330447df38f714bc17797b8895721a6974 src/orchard.web/Modules/Orchard.Alias
a2ed939103036405c0d446d6562bd365752ca9d3 src/orchard.web/Modules/Orchard.Projections
c1f7fa43511eb21314eb0fda82f74bd07769d508 src/orchard.web/modules/Orchard.Fields

View File

@ -16,7 +16,7 @@
</PropertyGroup>
<Import Project="$(LibFolder)\msbuild\MSBuild.Community.Tasks.Targets"/>
<Import Project="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v10.0\Windows Azure Tools\1.6\Microsoft.WindowsAzure.targets" />
<Import Project="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v10.0\Windows Azure Tools\1.7\Microsoft.WindowsAzure.targets" />
<!-- Coordinating Targets -->

View File

@ -277,7 +277,6 @@
$(StageFolder)\**\Modules\Orchard.CodeGeneration\**;
$(StageFolder)\**\Modules\Orchard.DesignerTools\**;
$(StageFolder)\**\Modules\Orchard.Email\**;
$(StageFolder)\**\Modules\Orchard.Experimental\**;
$(StageFolder)\**\Modules\Orchard.ImportExport\**;
$(StageFolder)\**\Modules\Orchard.Indexing\**;
$(StageFolder)\**\Modules\Orchard.Lists\**;
@ -311,6 +310,7 @@
$(MSBuildProjectDirectory)\**\*.suo;
$(MSBuildProjectDirectory)\**\*.user;
$(MSBuildProjectDirectory)\**\*.patch;
$(MSBuildProjectDirectory)\**\*.hgignore;
$(MSBuildProjectDirectory)\**\*.hg*\**\*;
$(LibFolder)\nunit\addins\**\*;
" />
@ -383,7 +383,6 @@
<Exec Command="&quot;$(GalleryFolder)\bin\Orchard.exe&quot; package create Orchard.CodeGeneration &quot;$(GalleryArtifactFolder)&quot;" WorkingDirectory="$(GalleryFolder)"/>
<Exec Command="&quot;$(GalleryFolder)\bin\Orchard.exe&quot; package create Orchard.DesignerTools &quot;$(GalleryArtifactFolder)&quot;" WorkingDirectory="$(GalleryFolder)"/>
<Exec Command="&quot;$(GalleryFolder)\bin\Orchard.exe&quot; package create Orchard.Email &quot;$(GalleryArtifactFolder)&quot;" WorkingDirectory="$(GalleryFolder)"/>
<Exec Command="&quot;$(GalleryFolder)\bin\Orchard.exe&quot; package create Orchard.Experimental &quot;$(GalleryArtifactFolder)&quot;" WorkingDirectory="$(GalleryFolder)"/>
<Exec Command="&quot;$(GalleryFolder)\bin\Orchard.exe&quot; package create Orchard.ImportExport &quot;$(GalleryArtifactFolder)&quot;" WorkingDirectory="$(GalleryFolder)"/>
<Exec Command="&quot;$(GalleryFolder)\bin\Orchard.exe&quot; package create Orchard.Indexing &quot;$(GalleryArtifactFolder)&quot;" WorkingDirectory="$(GalleryFolder)"/>
<Exec Command="&quot;$(GalleryFolder)\bin\Orchard.exe&quot; package create Orchard.Lists &quot;$(GalleryArtifactFolder)&quot;" WorkingDirectory="$(GalleryFolder)"/>

View File

@ -1,7 +1,7 @@
<?xml version="1.0"?>
<configuration>
<appSettings>
<add key="AzureSDK" value="C:\Program Files\Windows Azure SDK\v1.6\"/>
<add key="AzureSDK" value="C:\Program Files\Microsoft SDKs\Windows Azure\"/>
</appSettings>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>

View File

@ -17,8 +17,7 @@ namespace Orchard.Azure.Tests {
if ( count == 0 ) {
var start = new ProcessStartInfo {
Arguments = "/devstore:start",
FileName =
Path.Combine(ConfigurationManager.AppSettings["AzureSDK"], @"C:\Program Files\Windows Azure Emulator\emulator\csrun.exe")
FileName = Path.Combine(ConfigurationManager.AppSettings["AzureSDK"], @"emulator\csrun.exe")
};
_dsService = new Process { StartInfo = start };

View File

@ -53,9 +53,9 @@
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.WindowsAzure.Diagnostics, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL" />
<Reference Include="Microsoft.WindowsAzure.ServiceRuntime, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL" />
<Reference Include="Microsoft.WindowsAzure.StorageClient, Version=1.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL" />
<Reference Include="Microsoft.WindowsAzure.Diagnostics, Version=1.7.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL" />
<Reference Include="Microsoft.WindowsAzure.ServiceRuntime, Version=1.7.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL" />
<Reference Include="Microsoft.WindowsAzure.StorageClient, Version=1.7.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL" />
<Reference Include="Moq, Version=4.0.812.4, Culture=neutral, PublicKeyToken=69f491c39445e920, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\lib\moq\Moq.dll</HintPath>
@ -96,7 +96,9 @@
</ProjectReference>
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
<None Include="App.config">
<SubType>Designer</SubType>
</None>
</ItemGroup>
<ItemGroup>
<BootstrapperPackage Include="Microsoft.Net.Client.3.5">

View File

@ -298,26 +298,37 @@ namespace Orchard.Azure {
return "application/unknown";
}
string applicationHost = System.Environment.ExpandEnvironmentVariables(@"%windir%\system32\inetsrv\config\applicationHost.config");
if (File.Exists(applicationHost)) {
var xdoc = XDocument.Load(applicationHost);
var mimeMap = xdoc.XPathSelectElements("//staticContent/mimeMap[@fileExtension='" + extension + "']").FirstOrDefault();
if(mimeMap != null) {
var mimeType = mimeMap.Attribute("mimeType");
if(mimeType != null) {
return mimeType.Value;
try {
string applicationHost = System.Environment.ExpandEnvironmentVariables(@"%windir%\system32\inetsrv\config\applicationHost.config");
string webConfig = System.Web.Configuration.WebConfigurationManager.OpenWebConfiguration("/").FilePath;
// search for custom mime types in web.config and applicationhost.config
foreach (var configFile in new[] {webConfig, applicationHost}) {
if (File.Exists(configFile)) {
var xdoc = XDocument.Load(configFile);
var mimeMap = xdoc.XPathSelectElements("//staticContent/mimeMap[@fileExtension='" + extension + "']").FirstOrDefault();
if (mimeMap != null) {
var mimeType = mimeMap.Attribute("mimeType");
if (mimeType != null) {
return mimeType.Value;
}
}
}
}
}
// search into the registry
RegistryKey regKey = Registry.ClassesRoot.OpenSubKey(extension.ToLower());
if (regKey != null) {
var contentType = regKey.GetValue("Content Type");
if (contentType != null) {
return contentType.ToString();
// search into the registry
RegistryKey regKey = Registry.ClassesRoot.OpenSubKey(extension.ToLower());
if (regKey != null) {
var contentType = regKey.GetValue("Content Type");
if (contentType != null) {
return contentType.ToString();
}
}
}
catch {
// if an exception occured return application/unknown
return "application/unknown";
}
return "application/unknown";
}

View File

@ -4,7 +4,7 @@
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>1.6</ProductVersion>
<ProductVersion>1.7</ProductVersion>
<ProjectGuid>{03c5327d-4e8e-45a7-acd1-e18e7caa3c4a}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
@ -12,6 +12,7 @@
<AssemblyName>Orchard.Azure.CloudService</AssemblyName>
<StartDevelopmentStorage>True</StartDevelopmentStorage>
<Name>OrchardCloudService</Name>
<UseIISExpressByDefault>False</UseIISExpressByDefault>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@ -47,7 +48,7 @@
<!-- Import the target files for this project template -->
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
<CloudExtensionsDir Condition=" '$(CloudExtensionsDir)' == '' ">$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v$(VisualStudioVersion)\Windows Azure Tools\1.6\</CloudExtensionsDir>
<CloudExtensionsDir Condition=" '$(CloudExtensionsDir)' == '' ">$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v$(VisualStudioVersion)\Windows Azure Tools\1.7\</CloudExtensionsDir>
</PropertyGroup>
<Import Project="$(CloudExtensionsDir)Microsoft.WindowsAzure.targets" />
</Project>

View File

@ -1,5 +1,5 @@
<?xml version="1.0"?>
<ServiceConfiguration serviceName="OrchardCloudService" osFamily="1" osVersion="*" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceConfiguration">
<?xml version="1.0" encoding="utf-8"?>
<ServiceConfiguration serviceName="OrchardCloudService" osFamily="1" osVersion="*" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceConfiguration" schemaVersion="2012-05.1.7">
<Role name="Orchard.Azure.Web">
<Instances count="1" />
<ConfigurationSettings>

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<ServiceDefinition name="OrchardCloudService" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition">
<ServiceDefinition name="OrchardCloudService" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition" schemaVersion="2012-05.1.7">
<WebRole name="Orchard.Azure.Web">
<Sites>
<Site name="Web">

View File

@ -55,15 +55,10 @@
<HintPath>..\..\..\lib\aspnetmvc\Microsoft.Web.Infrastructure.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Microsoft.WindowsAzure.Diagnostics, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<Private>True</Private>
</Reference>
<Reference Include="Microsoft.WindowsAzure.ServiceRuntime, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<Private>False</Private>
</Reference>
<Reference Include="Microsoft.WindowsAzure.StorageClient, Version=1.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<Private>True</Private>
</Reference>
<Reference Include="Microsoft.WindowsAzure.Configuration, Version=1.7.0.0, Culture=neutral, processorArchitecture=MSIL" />
<Reference Include="Microsoft.WindowsAzure.Diagnostics, Version=1.7.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL" />
<Reference Include="Microsoft.WindowsAzure.ServiceRuntime, Version=1.7.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL" />
<Reference Include="Microsoft.WindowsAzure.StorageClient, Version=1.7.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL" />
<Reference Include="NHibernate.ByteCode.Castle">
<HintPath>..\..\..\lib\fluentnhibernate\NHibernate.ByteCode.Castle.dll</HintPath>
<Private>True</Private>
@ -81,11 +76,8 @@
<Reference Include="System.Data.DataSetExtensions">
<Private>False</Private>
</Reference>
<Reference Include="System.Data.SqlServerCe, Version=4.0.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\lib\sqlce\System.Data.SqlServerCe.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System.Data.Services.Client" />
<Reference Include="System.Data.SqlServerCe, Version=3.5.1.0, PublicKeyToken=89845dcd8080cc91" />
<Reference Include="System.Web.ApplicationServices">
<Private>False</Private>
</Reference>
@ -231,11 +223,6 @@
<Name>Orchard.Email</Name>
<Private>True</Private>
</ProjectReference>
<ProjectReference Include="..\..\Orchard.Web\Modules\Orchard.Experimental\Orchard.Experimental.csproj">
<Project>{AB3C207C-0126-4143-8D62-1119DF80D366}</Project>
<Name>Orchard.Experimental</Name>
<Private>True</Private>
</ProjectReference>
<ProjectReference Include="..\..\Orchard.Web\Modules\Orchard.Fields\Orchard.Fields.csproj">
<Project>{3787DDE5-E5C8-4841-BDA7-DCB325388064}</Project>
<Name>Orchard.Fields</Name>

View File

@ -40,12 +40,9 @@
<system.diagnostics>
<trace>
<listeners>
<add type="Microsoft.WindowsAzure.Diagnostics.DiagnosticMonitorTraceListener,
Microsoft.WindowsAzure.Diagnostics,
Version=1.0.0.0,
Culture=neutral,
PublicKeyToken=31bf3856ad364e35"
name="AzureDiagnostics">
<add type="Microsoft.WindowsAzure.Diagnostics.DiagnosticMonitorTraceListener, Microsoft.WindowsAzure.Diagnostics, Version=1.7.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
name="AzureDiagnostics">
<filter type="" />
</add>
</listeners>
</trace>

View File

@ -57,12 +57,11 @@
<HintPath>..\..\lib\fluentnhibernate\log4net.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Microsoft.WindowsAzure.Diagnostics, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL" />
<Reference Include="Microsoft.WindowsAzure.ServiceRuntime, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL" />
<Reference Include="Microsoft.WindowsAzure.StorageClient, Version=1.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<Private>True</Private>
</Reference>
<Reference Include="Microsoft.WindowsAzure.Diagnostics, Version=1.7.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL" />
<Reference Include="Microsoft.WindowsAzure.ServiceRuntime, Version=1.7.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL" />
<Reference Include="Microsoft.WindowsAzure.StorageClient, Version=1.7.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL" />
<Reference Include="System" />
<Reference Include="System.configuration" />
<Reference Include="System.Core">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>

View File

@ -49,8 +49,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lucene", "..\Orchard.Web\Mo
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Orchard.Packaging", "..\Orchard.Web\Modules\Orchard.Packaging\Orchard.Packaging.csproj", "{DFD137A2-DDB5-4D22-BE0D-FA9AD4C8B059}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Orchard.Experimental", "..\Orchard.Web\Modules\Orchard.Experimental\Orchard.Experimental.csproj", "{AB3C207C-0126-4143-8D62-1119DF80D366}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Orchard.CodeGeneration", "..\Orchard.Web\Modules\Orchard.CodeGeneration\Orchard.CodeGeneration.csproj", "{C0C45321-B51D-4D8D-9B7B-AA4C2E0B2962}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Orchard.ArchiveLater", "..\Orchard.Web\Modules\Orchard.ArchiveLater\Orchard.ArchiveLater.csproj", "{1C981BB3-26F7-494C-9005-CC27A5144233}"
@ -107,6 +105,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Orchard.Projections", "..\O
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UpgradeTo14", "..\Orchard.Web\Modules\UpgradeTo14\UpgradeTo14.csproj", "{8A9FDB57-342D-49C2-BAFC-D885AAE5CC7C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Orchard.AntiSpam", "..\Orchard.Web\Modules\Orchard.AntiSpam\Orchard.AntiSpam.csproj", "{91BC2E7F-DA04-421C-98EF-76D37CEC130C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Orchard.ContentPermissions", "..\Orchard.Web\Modules\Orchard.ContentPermissions\Orchard.ContentPermissions.csproj", "{E826F796-8CE3-4B5B-8423-5AA5F81D2FC3}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Orchard.CustomForms", "..\Orchard.Web\Modules\Orchard.CustomForms\Orchard.CustomForms.csproj", "{2CF067CA-064B-43C6-8B88-5E3B99A65F1D}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -201,10 +205,6 @@ Global
{DFD137A2-DDB5-4D22-BE0D-FA9AD4C8B059}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DFD137A2-DDB5-4D22-BE0D-FA9AD4C8B059}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DFD137A2-DDB5-4D22-BE0D-FA9AD4C8B059}.Release|Any CPU.Build.0 = Release|Any CPU
{AB3C207C-0126-4143-8D62-1119DF80D366}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{AB3C207C-0126-4143-8D62-1119DF80D366}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AB3C207C-0126-4143-8D62-1119DF80D366}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AB3C207C-0126-4143-8D62-1119DF80D366}.Release|Any CPU.Build.0 = Release|Any CPU
{C0C45321-B51D-4D8D-9B7B-AA4C2E0B2962}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C0C45321-B51D-4D8D-9B7B-AA4C2E0B2962}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C0C45321-B51D-4D8D-9B7B-AA4C2E0B2962}.Release|Any CPU.ActiveCfg = Release|Any CPU
@ -313,6 +313,18 @@ Global
{8A9FDB57-342D-49C2-BAFC-D885AAE5CC7C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8A9FDB57-342D-49C2-BAFC-D885AAE5CC7C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8A9FDB57-342D-49C2-BAFC-D885AAE5CC7C}.Release|Any CPU.Build.0 = Release|Any CPU
{91BC2E7F-DA04-421C-98EF-76D37CEC130C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{91BC2E7F-DA04-421C-98EF-76D37CEC130C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{91BC2E7F-DA04-421C-98EF-76D37CEC130C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{91BC2E7F-DA04-421C-98EF-76D37CEC130C}.Release|Any CPU.Build.0 = Release|Any CPU
{E826F796-8CE3-4B5B-8423-5AA5F81D2FC3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E826F796-8CE3-4B5B-8423-5AA5F81D2FC3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E826F796-8CE3-4B5B-8423-5AA5F81D2FC3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E826F796-8CE3-4B5B-8423-5AA5F81D2FC3}.Release|Any CPU.Build.0 = Release|Any CPU
{2CF067CA-064B-43C6-8B88-5E3B99A65F1D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2CF067CA-064B-43C6-8B88-5E3B99A65F1D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2CF067CA-064B-43C6-8B88-5E3B99A65F1D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2CF067CA-064B-43C6-8B88-5E3B99A65F1D}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -334,7 +346,6 @@ Global
{954CA994-D204-468B-9D69-51F6AD3E1C29} = {8E3DE014-9B28-4B32-8AC1-B2BE404E9B2D}
{D5D447D7-EF8E-43A6-B9A4-3B025DD9F45D} = {8E3DE014-9B28-4B32-8AC1-B2BE404E9B2D}
{DFD137A2-DDB5-4D22-BE0D-FA9AD4C8B059} = {8E3DE014-9B28-4B32-8AC1-B2BE404E9B2D}
{AB3C207C-0126-4143-8D62-1119DF80D366} = {8E3DE014-9B28-4B32-8AC1-B2BE404E9B2D}
{C0C45321-B51D-4D8D-9B7B-AA4C2E0B2962} = {8E3DE014-9B28-4B32-8AC1-B2BE404E9B2D}
{1C981BB3-26F7-494C-9005-CC27A5144233} = {8E3DE014-9B28-4B32-8AC1-B2BE404E9B2D}
{05660F47-D649-48BD-9DED-DF4E01E7CFF9} = {8E3DE014-9B28-4B32-8AC1-B2BE404E9B2D}
@ -361,6 +372,9 @@ Global
{3787DDE5-E5C8-4841-BDA7-DCB325388064} = {8E3DE014-9B28-4B32-8AC1-B2BE404E9B2D}
{5531E894-D259-45A3-AA61-26DBE720C1CE} = {8E3DE014-9B28-4B32-8AC1-B2BE404E9B2D}
{8A9FDB57-342D-49C2-BAFC-D885AAE5CC7C} = {8E3DE014-9B28-4B32-8AC1-B2BE404E9B2D}
{91BC2E7F-DA04-421C-98EF-76D37CEC130C} = {8E3DE014-9B28-4B32-8AC1-B2BE404E9B2D}
{E826F796-8CE3-4B5B-8423-5AA5F81D2FC3} = {8E3DE014-9B28-4B32-8AC1-B2BE404E9B2D}
{2CF067CA-064B-43C6-8B88-5E3B99A65F1D} = {8E3DE014-9B28-4B32-8AC1-B2BE404E9B2D}
{33B1BC8D-E292-4972-A363-22056B207156} = {75E7476C-C05B-4C41-8E38-081D3EB55659}
{CB70A642-8CEC-4DDE-8C9F-AD08900EC98D} = {84650275-884D-4CBB-9CC0-67553996E211}
EndGlobalSection

View File

@ -232,13 +232,35 @@ namespace Orchard.Core.Tests.Common.Providers {
_container.Resolve<DefaultShapeTableManagerTests.TestShapeProvider>().Discover =
b => b.Describe("Parts_Common_Owner_Edit").From(TestFeature())
.Placement(ShapePlacementParsingStrategy.BuildPredicate(c => true, new KeyValuePair<string, string>("Path", "~/yadda")), new PlacementInfo { Location = "Match" });
.Placement(ctx => new PlacementInfo { Location = "Content" });
contentManager.UpdateEditor(item.ContentItem, updater);
Assert.That(updater.ModelErrors.ContainsKey("OwnerEditor.Owner"), Is.True);
}
[Test]
public void PublishingShouldNotFailIfOwnerIsEmptyAndShapeIsHidden() {
var contentManager = _container.Resolve<IContentManager>();
var item = contentManager.Create<ICommonPart>("test-item", VersionOptions.Draft, init => { });
var user = contentManager.New<IUser>("User");
_authn.Setup(x => x.GetAuthenticatedUser()).Returns(user);
_authz.Setup(x => x.TryCheckAccess(StandardPermissions.SiteOwner, user, item)).Returns(true);
item.Owner = user;
var updater = new UpdatModelStub() { Owner = "" };
_container.Resolve<DefaultShapeTableManagerTests.TestShapeProvider>().Discover =
b => b.Describe("Parts_Common_Owner_Edit").From(TestFeature())
.Placement(ctx => new PlacementInfo { Location = "-" });
contentManager.UpdateEditor(item.ContentItem, updater);
Assert.That(updater.ModelErrors.ContainsKey("OwnerEditor.Owner"), Is.False);
}
[Test]
public void CreatingShouldSetCreatedAndModifiedUtc() {
var contentManager = _container.Resolve<IContentManager>();

View File

@ -8,7 +8,6 @@ From the base of the checkout, execute
* the ./orchard.proj creates an orchard web site at ./build/Profiling
* the ./src/Orchard.Profile/profiling-setup-commands.txt holds the additional orchard.exe steps used to initialize
* the ./src/Orchard.Experimental/Commands/ProfilingCommands.cs holds an additional handful of steps to populate items
The localhost:80 web server should be pointed to the ./build/Profiling folder at this point
The "admin" password is "profiling-secret" without quotes

View File

@ -1 +1 @@
setup /SiteName:Profiling /AdminUsername:admin /AdminPassword:profiling-secret /DatabaseProvider:SQLServer /DatabaseConnectionString:"Data Source=.;Initial Catalog=Orchard;Integrated Security=True" /EnabledFeatures:Profiling,Orchard.Framework,Common,Containers,Contents,Dashboard,Feeds,Navigation,Reports,Scheduling,Settings,Shapes,Title,PackagingServices,Gallery,Orchard.PublishLater,Orchard.Blogs,Orchard.Comments,Orchard.ContentTypes,Orchard.jQuery,Orchard.Lists,Orchard.Media,Orchard.MediaPicker,Orchard.Modules,Orchard.Packaging,Orchard.Pages,Orchard.Recipes,Orchard.Roles,Orchard.Tags,Orchard.Themes,Orchard.Users,Orchard.Scripting,Orchard.Scripting.Lightweight,Orchard.Widgets,TinyMce,TheThemeMachine,Orchard.Tokens,Orchard.Alias,Orchard.Autoroute
setup /SiteName:Profiling /AdminUsername:admin /AdminPassword:profiling-secret /DatabaseProvider:SQLServer /DatabaseConnectionString:"Data Source=.;Initial Catalog=Orchard;Integrated Security=True" /EnabledFeatures:Profiling,Orchard.Framework,Common,Containers,Contents,Dashboard,Feeds,Navigation,Reports,Scheduling,Settings,Shapes,Title,PackagingServices,Gallery,Orchard.PublishLater,Orchard.Blogs,Orchard.Comments,Orchard.ContentTypes,Orchard.jQuery,Orchard.Lists,Orchard.Media,Orchard.ContentPicker,Orchard.MediaPicker,Orchard.Modules,Orchard.Packaging,Orchard.Pages,Orchard.Recipes,Orchard.Roles,Orchard.Tags,Orchard.Themes,Orchard.Users,Orchard.Scripting,Orchard.Scripting.Lightweight,Orchard.Widgets,TinyMce,TheThemeMachine,Orchard.Tokens,Orchard.Alias,Orchard.Autoroute

View File

@ -23,7 +23,7 @@ namespace Orchard.Specs.Bindings {
webApp.GivenIHaveACleanSiteWith(
virtualDirectory,
TableData(
new { extension = "Module", names = "Orchard.Setup, Orchard.Pages, Orchard.Blogs, Orchard.Messaging, Orchard.Media, Orchard.MediaPicker, Orchard.Modules, Orchard.Packaging, Orchard.PublishLater, Orchard.Themes, Orchard.Scripting, Orchard.Widgets, Orchard.Users, Orchard.ContentTypes, Orchard.Roles, Orchard.Comments, Orchard.jQuery, Orchard.Tags, TinyMce, Orchard.Packaging, Orchard.Recipes, Orchard.Warmup, Orchard.Alias, Orchard.Forms, Orchard.Tokens, Orchard.Autoroute, Orchard.Projections, Orchard.Fields" },
new { extension = "Module", names = "Orchard.Setup, Orchard.Pages, Orchard.Blogs, Orchard.Messaging, Orchard.Media, Orchard.MediaPicker, Orchard.ContentPicker, Orchard.Modules, Orchard.Packaging, Orchard.PublishLater, Orchard.Themes, Orchard.Scripting, Orchard.Widgets, Orchard.Users, Orchard.ContentTypes, Orchard.Roles, Orchard.Comments, Orchard.jQuery, Orchard.Tags, TinyMce, Orchard.Packaging, Orchard.Recipes, Orchard.Warmup, Orchard.Alias, Orchard.Forms, Orchard.Tokens, Orchard.Autoroute, Orchard.Projections, Orchard.Fields" },
new { extension = "Core", names = "Common, Containers, Dashboard, Feeds, Navigation, Contents, Scheduling, Settings, Shapes, XmlRpc, Title" },
new { extension = "Theme", names = "SafeMode, TheAdmin, TheThemeMachine" }));

View File

@ -39,7 +39,7 @@ Scenario: Some of the initial form values are required
Scenario: Calling setup on a brand new install
Given I have a clean site with
| extension | names |
| Module | Orchard.Setup, Orchard.Pages, Orchard.Blogs, Orchard.Messaging, Orchard.Media, Orchard.MediaPicker, Orchard.Modules, Orchard.Packaging, Orchard.PublishLater, Orchard.Themes, Orchard.Scripting, Orchard.Widgets, Orchard.Users, Orchard.ContentTypes, Orchard.Roles, Orchard.Comments, Orchard.jQuery, Orchard.Tags, TinyMce, Orchard.Packaging, Orchard.Recipes, Orchard.Warmup, Orchard.Alias, Orchard.Forms, Orchard.Tokens, Orchard.Autoroute, Orchard.Projections, Orchard.Fields |
| Module | Orchard.Setup, Orchard.Pages, Orchard.Blogs, Orchard.Messaging, Orchard.Media, Orchard.MediaPicker, Orchard.ContentPicker, Orchard.Modules, Orchard.Packaging, Orchard.PublishLater, Orchard.Themes, Orchard.Scripting, Orchard.Widgets, Orchard.Users, Orchard.ContentTypes, Orchard.Roles, Orchard.Comments, Orchard.jQuery, Orchard.Tags, TinyMce, Orchard.Packaging, Orchard.Recipes, Orchard.Warmup, Orchard.Alias, Orchard.Forms, Orchard.Tokens, Orchard.Autoroute, Orchard.Projections, Orchard.Fields |
| Core | Common, Containers, Dashboard, Feeds, Navigation, Contents, Scheduling, Settings, Shapes, XmlRpc, Title |
| Theme | SafeMode, TheAdmin, TheThemeMachine |
And I am on "/Setup"

View File

@ -3,7 +3,7 @@
// This code was generated by SpecFlow (http://www.specflow.org/).
// SpecFlow Version:1.8.1.0
// SpecFlow Generator Version:1.8.0.0
// Runtime Version:4.0.30319.239
// Runtime Version:4.0.30319.269
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
@ -188,7 +188,7 @@ this.ScenarioSetup(scenarioInfo);
"names"});
table4.AddRow(new string[] {
"Module",
@"Orchard.Setup, Orchard.Pages, Orchard.Blogs, Orchard.Messaging, Orchard.Media, Orchard.MediaPicker, Orchard.Modules, Orchard.Packaging, Orchard.PublishLater, Orchard.Themes, Orchard.Scripting, Orchard.Widgets, Orchard.Users, Orchard.ContentTypes, Orchard.Roles, Orchard.Comments, Orchard.jQuery, Orchard.Tags, TinyMce, Orchard.Packaging, Orchard.Recipes, Orchard.Warmup, Orchard.Alias, Orchard.Forms, Orchard.Tokens, Orchard.Autoroute, Orchard.Projections, Orchard.Fields"});
@"Orchard.Setup, Orchard.Pages, Orchard.Blogs, Orchard.Messaging, Orchard.Media, Orchard.MediaPicker, Orchard.ContentPicker, Orchard.Modules, Orchard.Packaging, Orchard.PublishLater, Orchard.Themes, Orchard.Scripting, Orchard.Widgets, Orchard.Users, Orchard.ContentTypes, Orchard.Roles, Orchard.Comments, Orchard.jQuery, Orchard.Tags, TinyMce, Orchard.Packaging, Orchard.Recipes, Orchard.Warmup, Orchard.Alias, Orchard.Forms, Orchard.Tokens, Orchard.Autoroute, Orchard.Projections, Orchard.Fields"});
table4.AddRow(new string[] {
"Core",
"Common, Containers, Dashboard, Feeds, Navigation, Contents, Scheduling, Settings," +

View File

@ -92,14 +92,14 @@ namespace Orchard.Tests.Modules.ImportExport.Services {
}
[Test]
public void ImportFailsWhenRecipeContainsNonImportSteps() {
Assert.Throws(typeof(InvalidOperationException), () => _importExportService.Import(
@"<Orchard>
<Recipe>
<Name>MyModuleInstaller</Name>
</Recipe>
<Module name=""MyModule"" />
</Orchard>"));
public void ImportDoesntFailsWhenRecipeContainsNonImportSteps() {
Assert.DoesNotThrow(() => _importExportService.Import(
@"<Orchard>
<Recipe>
<Name>MyModuleInstaller</Name>
</Recipe>
<Module name=""MyModule"" />
</Orchard>"));
}
}

View File

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using NHibernate;
@ -200,6 +201,14 @@ namespace Orchard.Tests.Data {
Assert.That(two.Name, Is.EqualTo("two"));
}
[Test]
public void StoringDateTimeDoesntRemovePrecision() {
_fooRepos.Create(new FooRecord { Name = "one", Timespan = DateTime.Parse("2001-01-01 16:28:21.489", CultureInfo.InvariantCulture) });
var one = _fooRepos.Fetch(f => f.Name == "one").Single();
Assert.That(one.Name, Is.EqualTo("one"));
Assert.That(one.Timespan.Value.Millisecond, Is.EqualTo(489));
}
}
}

View File

@ -112,7 +112,7 @@ namespace Orchard.Tests.Environment {
public void PathAlsoCausesMatch() {
var table = (IRunningShellTable)new RunningShellTable();
var settings = new ShellSettings { Name = ShellSettings.DefaultName };
var settingsA = new ShellSettings { Name = "Alpha", RequestUrlPrefix = "~/foo" };
var settingsA = new ShellSettings { Name = "Alpha", RequestUrlPrefix = "foo" };
table.Add(settings);
table.Add(settingsA);
var match = table.Match(new StubHttpContext("~/foo/bar", "a.example.com"));
@ -123,10 +123,10 @@ namespace Orchard.Tests.Environment {
public void PathAndHostMustBothMatch() {
var table = (IRunningShellTable)new RunningShellTable();
var settings = new ShellSettings { Name = ShellSettings.DefaultName, RequestUrlHost = "www.example.com", };
var settingsA = new ShellSettings { Name = "Alpha", RequestUrlHost = "wiki.example.com", RequestUrlPrefix = "~/foo" };
var settingsB = new ShellSettings { Name = "Beta", RequestUrlHost = "wiki.example.com", RequestUrlPrefix = "~/bar" };
var settingsA = new ShellSettings { Name = "Alpha", RequestUrlHost = "wiki.example.com", RequestUrlPrefix = "foo" };
var settingsB = new ShellSettings { Name = "Beta", RequestUrlHost = "wiki.example.com", RequestUrlPrefix = "bar" };
var settingsG = new ShellSettings { Name = "Gamma", RequestUrlHost = "wiki.example.com" };
var settingsD = new ShellSettings { Name = "Delta", RequestUrlPrefix = "~/Quux" };
var settingsD = new ShellSettings { Name = "Delta", RequestUrlPrefix = "Quux" };
table.Add(settings);
table.Add(settingsA);
table.Add(settingsB);
@ -152,7 +152,7 @@ namespace Orchard.Tests.Environment {
[Test]
public void PathAloneWillMatch() {
var table = (IRunningShellTable)new RunningShellTable();
var settingsA = new ShellSettings { Name = "Alpha", RequestUrlPrefix = "~/foo" };
var settingsA = new ShellSettings { Name = "Alpha", RequestUrlPrefix = "foo" };
table.Add(settingsA);
Assert.That(table.Match(new StubHttpContext("~/foo/bar", "wiki.example.com")), Is.EqualTo(settingsA).Using(new ShellComparer()));

View File

@ -1,6 +1,9 @@
using System;
namespace Orchard.Tests.Records {
public class FooRecord {
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual DateTime? Timespan { get; set; }
}
}

View File

@ -135,11 +135,11 @@ namespace Orchard.Tests.UI.Navigation {
base(navigationManager, workContextAccessor, shapeFactory) {}
public static Stack<MenuItem> FindSelectedPathAccessor(IEnumerable<MenuItem> menuItems, RouteData currentRouteData) {
return SetSelectedPath(menuItems, currentRouteData);
return NavigationHelper.SetSelectedPath(menuItems, currentRouteData);
}
public static MenuItem FindParentLocalTaskAccessor(Stack<MenuItem> selectedPath) {
return FindParentLocalTask(selectedPath);
return NavigationHelper.FindParentLocalTask(selectedPath);
}
}
}

View File

@ -18,7 +18,7 @@ namespace Orchard.Tests.UI.Navigation {
public class NavigationManagerTests {
[Test]
public void EmptyMenuIfNameDoesntMatch() {
var manager = new NavigationManager(new[] { new StubProvider() }, new StubAuth(), new UrlHelper(new RequestContext(new StubHttpContext("~/"), new RouteData())), new StubOrchardServices());
var manager = new NavigationManager(new[] { new StubProvider() }, new IMenuProvider[] { }, new StubAuth(), new INavigationFilter[0], new UrlHelper(new RequestContext(new StubHttpContext("~/"), new RouteData())), new StubOrchardServices());
var menuItems = manager.BuildMenu("primary");
Assert.That(menuItems.Count(), Is.EqualTo(0));
@ -35,7 +35,7 @@ namespace Orchard.Tests.UI.Navigation {
[Test]
public void NavigationManagerShouldUseProvidersToBuildNamedMenu() {
var manager = new NavigationManager(new[] { new StubProvider() }, new StubAuth(), new UrlHelper(new RequestContext(new StubHttpContext("~/"), new RouteData())), new StubOrchardServices());
var manager = new NavigationManager(new[] { new StubProvider() }, new IMenuProvider[] { }, new StubAuth(), new INavigationFilter[0], new UrlHelper(new RequestContext(new StubHttpContext("~/"), new RouteData())), new StubOrchardServices());
var menuItems = manager.BuildMenu("admin");
Assert.That(menuItems.Count(), Is.EqualTo(2));
@ -47,7 +47,7 @@ namespace Orchard.Tests.UI.Navigation {
[Test]
public void NavigationManagerShouldCatchProviderErrors() {
var manager = new NavigationManager(new[] { new BrokenProvider() }, new StubAuth(), new UrlHelper(new RequestContext(new StubHttpContext("~/"), new RouteData())), new StubOrchardServices());
var manager = new NavigationManager(new[] { new BrokenProvider() }, new IMenuProvider[] { }, new StubAuth(), new INavigationFilter[0], new UrlHelper(new RequestContext(new StubHttpContext("~/"), new RouteData())), new StubOrchardServices());
var menuItems = manager.BuildMenu("admin");
Assert.That(menuItems.Count(), Is.EqualTo(0));
@ -55,7 +55,7 @@ namespace Orchard.Tests.UI.Navigation {
[Test]
public void NavigationManagerShouldMergeAndOrderNavigation() {
var manager = new NavigationManager(new INavigationProvider[] { new StubProvider(), new Stub2Provider() }, new StubAuth(), new UrlHelper(new RequestContext(new StubHttpContext("~/"), new RouteData())), new StubOrchardServices());
var manager = new NavigationManager(new INavigationProvider[] { new StubProvider(), new Stub2Provider() }, new IMenuProvider[] { }, new StubAuth(), new INavigationFilter[0], new UrlHelper(new RequestContext(new StubHttpContext("~/"), new RouteData())), new StubOrchardServices());
var menuItems = manager.BuildMenu("admin");
Assert.That(menuItems.Count(), Is.EqualTo(3));

View File

@ -54,7 +54,9 @@
<staticLogFileName value="false" />
<rollingStyle value="Date" />
<datepattern value="-yyyy.MM.dd'.log'" />
<!-- prevent orchard.exe from displaying locking debug messages -->
<lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %logger - %message%newline" />
</layout>
@ -73,6 +75,9 @@
<rollingStyle value="Date" />
<datepattern value="-yyyy.MM.dd'.log'" />
<!-- prevent orchard.exe from displaying locking error messages -->
<lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
<filter type="log4net.Filter.LevelRangeFilter">
<!-- only error and fatal messages end up in this target, even if child loggers accept lower priority -->
<levelMin value="ERROR" />

View File

@ -84,6 +84,10 @@ namespace Orchard.Core.Common.Drivers {
var contentIdentity = new ContentIdentity(owner);
part.Owner = _membershipService.GetUser(contentIdentity.Get("User.UserName"));
}
// use the super user if the referenced one doesn't exist
else {
part.Owner = _membershipService.GetUser(Services.WorkContext.CurrentSite.SuperUser);
}
var container = context.Attribute(part.PartDefinition.Name, "Container");
if (container != null) {

View File

@ -39,10 +39,8 @@ namespace Orchard.Core.Common.Drivers {
var settings = field.PartFieldDefinition.Settings.GetModel<TextFieldSettings>();
object fieldValue = field.Value;
if (!string.IsNullOrWhiteSpace(settings.Flavor)) {
fieldValue = new HtmlString(_htmlFilters.Aggregate(field.Value, (text, filter) => filter.ProcessContent(text, settings.Flavor)));
}
fieldValue = new HtmlString(_htmlFilters.Aggregate(field.Value, (text, filter) => filter.ProcessContent(text, settings.Flavor)));
return shapeHelper.Fields_Common_Text(Name: field.Name, Value: fieldValue);
});
}

View File

@ -2,8 +2,8 @@
AntiForgery: enabled
Author: The Orchard Team
Website: http://orchardproject.net
Version: 1.4.2
OrchardVersion: 1.4.2
Version: 1.5
OrchardVersion: 1.5
Description: The common module introduces content parts that are going to be used by most content types (common, body, identity).
FeatureDescription: Core content parts.
Dependencies: Settings

View File

@ -1,7 +1,7 @@
@model Orchard.Core.Common.ViewModels.TextFieldDriverViewModel
<fieldset>
<label for="@Html.FieldIdFor(m => m.Text)">@Model.Field.DisplayName</label>
<label for="@Html.FieldIdFor(m => m.Text)" @if(Model.Settings.Required) { <text>class="required"</text> }>@Model.Field.DisplayName</label>
@if (String.IsNullOrWhiteSpace(Model.Settings.Flavor)) {
@Html.TextBoxFor(m => m.Text, new { @class = "text" })
@Html.ValidationMessageFor(m => m.Text)

View File

@ -1,7 +1,8 @@
@{
@using Orchard.Utility.Extensions;
@{
string name = Model.ContentField.DisplayName;
}
@if (HasText(name) && HasText(Model.Value)) {
<p class="text-field"><span class="name">@name:</span> <span class="value">@Model.Value</span></p>
<p class="text-field"><span class="name">@name:</span> <span class="value">@(new MvcHtmlString(Html.Encode((HtmlString) Model.Value).ReplaceNewLinesWith("<br />$1")))</span></p>
}

View File

@ -7,6 +7,7 @@ using Orchard.Core.Common.Models;
using Orchard.Core.Containers.Models;
using Orchard.Core.Containers.ViewModels;
using Orchard.Localization;
using Orchard.ContentManagement.Handlers;
namespace Orchard.Core.Containers.Drivers {
public class ContainablePartDriver : ContentPartDriver<ContainablePart> {
@ -40,7 +41,7 @@ namespace Orchard.Core.Containers.Drivers {
if (oldContainerId != model.ContainerId) {
if (commonPart != null) {
var containerItem = _contentManager.Get(model.ContainerId, VersionOptions.Latest);
commonPart.Record.Container = containerItem == null ? null : containerItem.Record;
commonPart.Container = containerItem;
}
}
part.Weight = model.Weight;
@ -65,5 +66,15 @@ namespace Orchard.Core.Containers.Drivers {
});
}
protected override void Importing(ContainablePart part, ImportContentContext context) {
var weight = context.Attribute(part.PartDefinition.Name, "Weight");
if (weight != null) {
part.Weight = Convert.ToInt32(weight);
}
}
protected override void Exporting(ContainablePart part, ExportContentContext context) {
context.Element(part.PartDefinition.Name).SetAttributeValue("Weight", part.Weight);
}
}
}

View File

@ -10,13 +10,11 @@ using Orchard.Core.Containers.Models;
using Orchard.Core.Containers.ViewModels;
using Orchard.Localization;
using Orchard.UI.Notify;
using Orchard.DisplayManagement;
using Orchard.Core.Containers.Extensions;
using System.Web.Routing;
using Orchard.Settings;
using Orchard.Core.Feeds;
using Orchard.UI.Navigation;
using Orchard.ContentManagement.Aspects;
namespace Orchard.Core.Containers.Drivers {
public class ContainerPartDriver : ContentPartDriver<ContainerPart> {

View File

@ -6,5 +6,5 @@ Version: 1.4.2
OrchardVersion: 1.4.2
Description: The containers module introduces container and containable behaviors for content items.
FeatureDescription: Container and containable parts to enable parent-child relationships between content items.
Dependencies: Contents
Dependencies: Contents, Feeds
Category: Content

View File

@ -275,7 +275,7 @@ namespace Orchard.Core.Contents.Controllers {
[HttpPost, ActionName("Edit")]
[FormValueRequired("submit.Publish")]
public ActionResult EditAndPublishPOST(int id, string returnUrl) {
var content = _contentManager.Get(id, VersionOptions.DraftRequired);
var content = _contentManager.Get(id, VersionOptions.Latest);
if (content == null)
return HttpNotFound();

View File

@ -20,7 +20,7 @@ namespace Orchard.Core.Contents.Controllers {
dynamic Shape { get; set; }
public IOrchardServices Services { get; private set; }
public Localizer T { get; set; }
// /Contents/Item/Display/72
public ActionResult Display(int id) {
var contentItem = _contentManager.Get(id, VersionOptions.Published);
@ -28,6 +28,10 @@ namespace Orchard.Core.Contents.Controllers {
if (contentItem == null)
return HttpNotFound();
if (!Services.Authorizer.Authorize(Permissions.ViewContent, contentItem, T("Cannot view content"))) {
return new HttpUnauthorizedResult();
}
dynamic model = _contentManager.BuildDisplay(contentItem);
return new ShapeResult(this, model);
}
@ -41,12 +45,16 @@ namespace Orchard.Core.Contents.Controllers {
versionOptions = VersionOptions.Number((int)version);
var contentItem = _contentManager.Get(id, versionOptions);
if (contentItem == null)
return HttpNotFound();
if (!Services.Authorizer.Authorize(Permissions.EditContent, contentItem, T("Cannot preview content")))
if (!Services.Authorizer.Authorize(Permissions.ViewContent, contentItem, T("Cannot preview content"))) {
return new HttpUnauthorizedResult();
}
if (!Services.Authorizer.Authorize(Permissions.EditContent, contentItem, T("Cannot preview content"))) {
return new HttpUnauthorizedResult();
}
dynamic model = _contentManager.BuildDisplay(contentItem);
return new ShapeResult(this, model);

View File

@ -15,6 +15,8 @@ namespace Orchard.Core.Contents {
private static readonly Permission EditOwnContent = new Permission { Description = "Edit {0}", Name = "EditOwn_{0}", ImpliedBy = new[] { EditContent, PublishOwnContent, Permissions.EditOwnContent } };
private static readonly Permission DeleteContent = new Permission { Description = "Delete {0} for others", Name = "Delete_{0}", ImpliedBy = new[] { Permissions.DeleteContent } };
private static readonly Permission DeleteOwnContent = new Permission { Description = "Delete {0}", Name = "DeleteOwn_{0}", ImpliedBy = new[] { DeleteContent, Permissions.DeleteOwnContent } };
private static readonly Permission ViewContent = new Permission { Description = "View {0} by others", Name = "View_{0}", ImpliedBy = new[] { Permissions.EditContent } };
private static readonly Permission ViewOwnContent = new Permission { Description = "View own {0}", Name = "ViewOwn_{0}", ImpliedBy = new[] { ViewContent, Permissions.ViewOwnContent } };
public static readonly Dictionary<string, Permission> PermissionTemplates = new Dictionary<string, Permission> {
{Permissions.PublishContent.Name, PublishContent},
@ -22,7 +24,9 @@ namespace Orchard.Core.Contents {
{Permissions.EditContent.Name, EditContent},
{Permissions.EditOwnContent.Name, EditOwnContent},
{Permissions.DeleteContent.Name, DeleteContent},
{Permissions.DeleteOwnContent.Name, DeleteOwnContent}
{Permissions.DeleteOwnContent.Name, DeleteOwnContent},
{Permissions.ViewContent.Name, ViewContent},
{Permissions.ViewOwnContent.Name, ViewOwnContent}
};
private readonly IContentDefinitionManager _contentDefinitionManager;
@ -38,8 +42,8 @@ namespace Orchard.Core.Contents {
var creatableTypes = _contentDefinitionManager.ListTypeDefinitions()
.Where(ctd => ctd.Settings.GetModel<ContentTypeSettings>().Creatable);
foreach(var typeDefinition in creatableTypes) {
foreach ( var permissionTemplate in PermissionTemplates.Values ) {
foreach (var typeDefinition in creatableTypes) {
foreach (var permissionTemplate in PermissionTemplates.Values) {
yield return CreateDynamicPermission(permissionTemplate, typeDefinition);
}
}
@ -53,7 +57,7 @@ namespace Orchard.Core.Contents {
/// Returns a dynamic permission for a content type, based on a global content permission template
/// </summary>
public static Permission ConvertToDynamicPermission(Permission permission) {
if (PermissionTemplates.ContainsKey(permission.Name) ) {
if (PermissionTemplates.ContainsKey(permission.Name)) {
return PermissionTemplates[permission.Name];
}
@ -68,7 +72,7 @@ namespace Orchard.Core.Contents {
Name = String.Format(template.Name, typeDefinition.Name),
Description = String.Format(template.Description, typeDefinition.DisplayName),
Category = typeDefinition.DisplayName,
ImpliedBy = ( template.ImpliedBy ?? new Permission[0] ).Select(t => CreateDynamicPermission(t, typeDefinition))
ImpliedBy = (template.ImpliedBy ?? new Permission[0]).Select(t => CreateDynamicPermission(t, typeDefinition))
};
}
}

View File

@ -2,8 +2,8 @@
AntiForgery: enabled
Author: The Orchard Team
Website: http://orchardproject.net
Version: 1.4.2
OrchardVersion: 1.4.2
Version: 1.5
OrchardVersion: 1.5
Description: The contents module enables the creation of custom content types.
Features:
Contents

View File

@ -14,19 +14,24 @@ namespace Orchard.Core.Contents {
public static readonly Permission EditOwnContent = new Permission { Description = "Edit own content", Name = "EditOwnContent", ImpliedBy = new[] { EditContent, PublishOwnContent } };
public static readonly Permission DeleteContent = new Permission { Description = "Delete content for others", Name = "DeleteContent" };
public static readonly Permission DeleteOwnContent = new Permission { Description = "Delete own content", Name = "DeleteOwnContent", ImpliedBy = new[] { DeleteContent } };
public static readonly Permission ViewContent = new Permission { Description = "View all content", Name = "ViewContent", ImpliedBy = new[] { EditContent } };
public static readonly Permission ViewOwnContent = new Permission { Description = "View own content", Name = "ViewOwnContent", ImpliedBy = new[] { ViewContent } };
public static readonly Permission MetaListContent = new Permission { ImpliedBy = new[] { EditOwnContent, PublishOwnContent, DeleteOwnContent } };
public virtual Feature Feature { get; set; }
public IEnumerable<Permission> GetPermissions() {
return new [] {
return new[] {
EditOwnContent,
EditContent,
PublishOwnContent,
PublishContent,
DeleteOwnContent,
DeleteContent,
ViewContent,
ViewOwnContent
};
}
@ -51,6 +56,14 @@ namespace Orchard.Core.Contents {
Name = "Contributor",
Permissions = new[] {EditOwnContent}
},
new PermissionStereotype {
Name = "Authenticated",
Permissions = new[] {ViewContent}
},
new PermissionStereotype {
Name = "Anonymous",
Permissions = new[] {ViewContent}
},
};
}

View File

@ -5,17 +5,15 @@ using Orchard.Core.Contents.Settings;
using Orchard.Security;
using Orchard.Security.Permissions;
namespace Orchard.Core.Contents.Security
{
namespace Orchard.Core.Contents.Security {
[UsedImplicitly]
public class AuthorizationEventHandler : IAuthorizationServiceEventHandler
{
public class AuthorizationEventHandler : IAuthorizationServiceEventHandler {
public void Checking(CheckAccessContext context) { }
public void Complete(CheckAccessContext context) { }
public void Adjust(CheckAccessContext context) {
if ( !context.Granted &&
context.Content.Is<ICommonPart>() ) {
if (!context.Granted &&
context.Content.Is<ICommonPart>()) {
if (OwnerVariationExists(context.Permission) &&
HasOwnership(context.User, context.Content)) {
@ -27,10 +25,10 @@ namespace Orchard.Core.Contents.Security
var typeDefinition = context.Content.ContentItem.TypeDefinition;
// replace permission if a content type specific version exists
if ( typeDefinition.Settings.GetModel<ContentTypeSettings>().Creatable ) {
if (typeDefinition.Settings.GetModel<ContentTypeSettings>().Creatable) {
var permission = GetContentTypeVariation(context.Permission);
if ( permission != null) {
if (permission != null) {
context.Adjusted = true;
context.Permission = DynamicPermissions.CreateDynamicPermission(permission, typeDefinition);
}
@ -60,6 +58,8 @@ namespace Orchard.Core.Contents.Security
return Permissions.EditOwnContent;
if (permission.Name == Permissions.DeleteContent.Name)
return Permissions.DeleteOwnContent;
if (permission.Name == Permissions.ViewContent.Name)
return Permissions.ViewOwnContent;
return null;
}

View File

@ -8,5 +8,9 @@
/// Used to determine if this content type supports draft versions
/// </summary>
public bool Draftable { get; set; }
/// <summary>
/// Defines the stereotype of the type
/// </summary>
public string Stereotype { get; set; }
}
}

View File

@ -2,8 +2,8 @@
AntiForgery: enabled
Author: The Orchard Team
Website: http://orchardproject.net
Version: 1.4.2
OrchardVersion: 1.4.2
Version: 1.5
OrchardVersion: 1.5
Description: The dashboard module is providing the dashboard screen of the admininstration UI of the application.
FeatureDescription: Standard admin dashboard.
Category: Core

View File

@ -2,8 +2,8 @@
AntiForgery: enabled
Author: The Orchard Team
Website: http://orchardproject.net
Version: 1.4.2
OrchardVersion: 1.4.2
Version: 1.5
OrchardVersion: 1.5
Description: The Feeds module is providing RSS feeds to content items.
FeatureDescription: RSS feeds for content items.
Category: Syndication

View File

@ -1,13 +1,18 @@
using Orchard.Commands;
using System.Linq;
using Orchard.Commands;
using Orchard.ContentManagement;
using Orchard.Core.Navigation.Models;
using Orchard.Core.Navigation.Services;
using Orchard.Core.Title.Models;
namespace Orchard.Core.Navigation.Commands {
public class MenuCommands : DefaultOrchardCommandHandler {
private readonly IContentManager _contentManager;
private readonly IMenuService _menuService;
public MenuCommands(IContentManager contentManager) {
public MenuCommands(IContentManager contentManager, IMenuService menuService) {
_contentManager = contentManager;
_menuService = menuService;
}
[OrchardSwitch]
@ -20,19 +25,43 @@ namespace Orchard.Core.Navigation.Commands {
public string Url { get; set; }
[OrchardSwitch]
public bool OnMainMenu { get; set; }
public string MenuName { get; set; }
[CommandName("menuitem create")]
[CommandHelp("menuitem create /MenuPosition:<position> /MenuText:<text> /Url:<url> [/OnMainMenu:true|false]\r\n\t" + "Creates a new menu item")]
[OrchardSwitches("MenuPosition,MenuText,Url,OnMainMenu")]
[CommandHelp("menuitem create /MenuPosition:<position> /MenuText:<text> /Url:<url> /MenuName:<name>\r\n\t" + "Creates a new menu item")]
[OrchardSwitches("MenuPosition,MenuText,Url,MenuName")]
public void Create() {
// flushes before doing a query in case a previous command created the menu
_contentManager.Flush();
var menu = _menuService.GetMenu(MenuName);
if(menu == null) {
Context.Output.WriteLine(T("Menu not found.").Text);
return;
}
var menuItem = _contentManager.Create("MenuItem");
menuItem.As<MenuPart>().MenuPosition = MenuPosition;
menuItem.As<MenuPart>().MenuText = T(MenuText).ToString();
menuItem.As<MenuPart>().OnMainMenu = OnMainMenu;
menuItem.As<MenuPart>().Menu = menu.ContentItem;
menuItem.As<MenuItemPart>().Url = Url;
Context.Output.WriteLine(T("Menu item created successfully.").Text);
}
[CommandName("menu create")]
[CommandHelp("menu create /MenuName:<name>\r\n\t" + "Creates a new menu")]
[OrchardSwitches("MenuName")]
public void CreateMenu() {
if (string.IsNullOrWhiteSpace(MenuName)) {
Context.Output.WriteLine(T("Menu name can't be empty.").Text);
return;
}
_menuService.Create(MenuName);
Context.Output.WriteLine(T("Menu created successfully.").Text);
}
}
}

View File

@ -2,66 +2,91 @@
using System.Linq;
using System.Web.Mvc;
using Orchard.ContentManagement;
using Orchard.Core.Common.Models;
using Orchard.Core.Navigation.Models;
using Orchard.Core.Navigation.Services;
using Orchard.Core.Navigation.ViewModels;
using Orchard.DisplayManagement;
using Orchard.Core.Title.Models;
using Orchard.Localization;
using Orchard.Mvc.AntiForgery;
using Orchard.Mvc.Extensions;
using Orchard.UI;
using Orchard.UI.Notify;
using Orchard.UI.Navigation;
using Orchard.Utility;
using System;
using Orchard.Logging;
namespace Orchard.Core.Navigation.Controllers {
[ValidateInput(false)]
public class AdminController : Controller, IUpdateModel {
private readonly IMenuService _menuService;
private readonly IOrchardServices _services;
private readonly INavigationManager _navigationManager;
private readonly IMenuManager _menuManager;
public AdminController(
IOrchardServices orchardServices,
IMenuService menuService,
IOrchardServices services,
INavigationManager navigationManager,
IShapeFactory shapeFactory) {
IMenuManager menuManager,
INavigationManager navigationManager) {
_menuService = menuService;
_services = services;
_menuManager = menuManager;
_navigationManager = navigationManager;
Services = orchardServices;
T = NullLocalizer.Instance;
Shape = shapeFactory;
Logger = NullLogger.Instance;
}
dynamic Shape { get; set; }
public Localizer T { get; set; }
public ILogger Logger { get; set; }
public IOrchardServices Services { get; set; }
public ActionResult Index(NavigationManagementViewModel model) {
if (!_services.Authorizer.Authorize(Permissions.ManageMainMenu, T("Not allowed to manage the main menu")))
public ActionResult Index(NavigationManagementViewModel model, int? menuId) {
if (!Services.Authorizer.Authorize(Permissions.ManageMainMenu, T("Not allowed to manage the main menu"))) {
return new HttpUnauthorizedResult();
}
if (model == null)
IEnumerable<TitlePart> menus = Services.ContentManager.Query<TitlePart, TitlePartRecord>().OrderBy(x => x.Title).ForType("Menu").List();
if (!menus.Any()) {
return RedirectToAction("Create", "Admin", new {area = "Contents", id = "Menu", returnUrl = Request.RawUrl});
}
IContent currentMenu = menuId == null
? menus.FirstOrDefault()
: menus.FirstOrDefault(menu => menu.Id == menuId);
if (currentMenu == null && menuId != null) { // incorrect menu id passed
Services.Notifier.Error(T("Menu not found: {0}", menuId));
return RedirectToAction("Index");
}
if (model == null) {
model = new NavigationManagementViewModel();
}
if (model.MenuItemEntries == null || model.MenuItemEntries.Count() < 1)
model.MenuItemEntries = _menuService.Get().Select(CreateMenuItemEntries).OrderBy(menuPartEntry => menuPartEntry.Position, new FlatPositionComparer()).ToList();
if (model.MenuItemEntries == null || !model.MenuItemEntries.Any()) {
model.MenuItemEntries = _menuService.GetMenuParts(currentMenu.Id).Select(CreateMenuItemEntries).OrderBy(menuPartEntry => menuPartEntry.Position, new FlatPositionComparer()).ToList();
}
model.MenuItemDescriptors = _menuManager.GetMenuItemTypes();
model.Menus = menus;
model.CurrentMenu = currentMenu;
// need action name as this action is referenced from another action
return View("Index", model);
return View(model);
}
[HttpPost, ActionName("Index")]
public ActionResult IndexPOST(IList<MenuItemEntry> menuItemEntries) {
if (!_services.Authorizer.Authorize(Permissions.ManageMainMenu, T("Couldn't manage the main menu")))
if (!Services.Authorizer.Authorize(Permissions.ManageMainMenu, T("Couldn't manage the main menu")))
return new HttpUnauthorizedResult();
// See http://orchard.codeplex.com/workitem/17116
if (menuItemEntries != null) {
foreach (var menuItemEntry in menuItemEntries) {
MenuPart menuPart = _menuService.Get(menuItemEntry.MenuItemId);
menuPart.MenuText = menuItemEntry.Text;
menuPart.MenuPosition = menuItemEntry.Position;
if (menuPart.Is<MenuItemPart>())
menuPart.As<MenuItemPart>().Url = menuItemEntry.Url;
}
}
@ -76,51 +101,26 @@ namespace Orchard.Core.Navigation.Controllers {
Position = menuPart.MenuPosition,
Url = menuPart.Is<MenuItemPart>()
? menuPart.As<MenuItemPart>().Url
: _navigationManager.GetUrl(null, _services.ContentManager.GetItemMetadata(menuPart).DisplayRouteValues),
: _navigationManager.GetUrl(null, Services.ContentManager.GetItemMetadata(menuPart).DisplayRouteValues),
ContentItem = menuPart.ContentItem,
};
}
public ActionResult Create() {
return RedirectToAction("Index");
}
[HttpPost]
public ActionResult Create(NavigationManagementViewModel model) {
if (!_services.Authorizer.Authorize(Permissions.ManageMainMenu, T("Couldn't manage the main menu")))
return new HttpUnauthorizedResult();
var menuPart = _services.ContentManager.New<MenuPart>("MenuItem");
menuPart.OnMainMenu = true;
menuPart.MenuText = model.NewMenuItem.Text;
menuPart.MenuPosition = model.NewMenuItem.Position;
if (string.IsNullOrEmpty(menuPart.MenuPosition))
menuPart.MenuPosition = Position.GetNext(_navigationManager.BuildMenu("main"));
var menuItem = menuPart.As<MenuItemPart>();
menuItem.Url = model.NewMenuItem.Url;
if (!ModelState.IsValid) {
_services.TransactionManager.Cancel();
return View("Index", model);
}
_services.ContentManager.Create(menuPart);
return RedirectToAction("Index");
}
[HttpPost]
public ActionResult Delete(int id) {
if (!_services.Authorizer.Authorize(Permissions.ManageMainMenu, T("Couldn't manage the main menu")))
if (!Services.Authorizer.Authorize(Permissions.ManageMainMenu, T("Couldn't manage the main menu")))
return new HttpUnauthorizedResult();
MenuPart menuPart = _menuService.Get(id);
if (menuPart != null) {
if (menuPart.Is<MenuItemPart>())
// if the menu item is a concrete content item, don't delete it, just unreference the menu
if (!menuPart.ContentItem.TypeDefinition.Settings.ContainsKey("Stereotype") || menuPart.ContentItem.TypeDefinition.Settings["Stereotype"] != "MenuItem") {
menuPart.Menu = null;
}
else {
_menuService.Delete(menuPart);
else
menuPart.OnMainMenu = false;
}
}
return RedirectToAction("Index");
@ -133,5 +133,71 @@ namespace Orchard.Core.Navigation.Controllers {
void IUpdateModel.AddModelError(string key, LocalizedString errorMessage) {
ModelState.AddModelError(key, errorMessage.ToString());
}
public ActionResult CreateMenuItem(string id, int menuId, string returnUrl) {
if (!Services.Authorizer.Authorize(Permissions.ManageMainMenu, T("Couldn't manage the main menu")))
return new HttpUnauthorizedResult();
// create a new temporary menu item
var menuPart = Services.ContentManager.New<MenuPart>(id);
if (menuPart == null)
return HttpNotFound();
// load the menu
var menu = Services.ContentManager.Get(menuId);
if (menu == null)
return HttpNotFound();
try {
// filter the content items for this specific menu
menuPart.MenuPosition = Position.GetNext(_navigationManager.BuildMenu(menu));
dynamic model = Services.ContentManager.BuildEditor(menuPart);
// Casting to avoid invalid (under medium trust) reflection over the protected View method and force a static invocation.
return View((object)model);
}
catch (Exception exception) {
Logger.Error(T("Creating menu item failed: {0}", exception.Message).Text);
Services.Notifier.Error(T("Creating menu item failed: {0}", exception.Message));
return this.RedirectLocal(returnUrl, () => RedirectToAction("Index"));
}
}
[HttpPost, ActionName("CreateMenuItem")]
public ActionResult CreateMenuItemPost(string id, int menuId, string returnUrl) {
if (!Services.Authorizer.Authorize(Permissions.ManageMainMenu, T("Couldn't manage the main menu")))
return new HttpUnauthorizedResult();
var menuPart = Services.ContentManager.New<MenuPart>(id);
if (menuPart == null)
return HttpNotFound();
// load the menu
var menu = Services.ContentManager.Get(menuId);
if (menu == null)
return HttpNotFound();
var model = Services.ContentManager.UpdateEditor(menuPart, this);
menuPart.MenuPosition = Position.GetNext(_navigationManager.BuildMenu(menu));
menuPart.Menu = menu;
Services.ContentManager.Create(menuPart);
if (!ModelState.IsValid) {
Services.TransactionManager.Cancel();
// Casting to avoid invalid (under medium trust) reflection over the protected View method and force a static invocation.
return View((object)model);
}
Services.Notifier.Information(T("Your {0} has been added.", menuPart.TypeDefinition.DisplayName));
return this.RedirectLocal(returnUrl, () => RedirectToAction("Index"));
}
}
}

View File

@ -0,0 +1,82 @@
using JetBrains.Annotations;
using Orchard.ContentManagement;
using Orchard.ContentManagement.Drivers;
using Orchard.ContentManagement.Handlers;
using Orchard.Core.Navigation.Models;
using Orchard.Core.Navigation.ViewModels;
using Orchard.Localization;
using Orchard.Security;
namespace Orchard.Core.Navigation.Drivers {
[UsedImplicitly]
public class ContentMenuItemPartDriver : ContentPartDriver<ContentMenuItemPart> {
private readonly IContentManager _contentManager;
private readonly IAuthorizationService _authorizationService;
private readonly IWorkContextAccessor _workContextAccessor;
public ContentMenuItemPartDriver(
IContentManager contentManager,
IAuthorizationService authorizationService,
IWorkContextAccessor workContextAccessor) {
_contentManager = contentManager;
_authorizationService = authorizationService;
_workContextAccessor = workContextAccessor;
T = NullLocalizer.Instance;
}
public Localizer T { get; set; }
protected override DriverResult Editor(ContentMenuItemPart part, dynamic shapeHelper) {
return ContentShape("Parts_ContentMenuItem_Edit",
() => {
var model = new ContentMenuItemEditViewModel {
ContentItemId = part.Content == null ? -1 : part.Content.Id,
Part = part
};
return shapeHelper.EditorTemplate(TemplateName: "Parts.ContentMenuItem.Edit", Model: model, Prefix: Prefix);
});
}
protected override DriverResult Editor(ContentMenuItemPart part, IUpdateModel updater, dynamic shapeHelper) {
var currentUser = _workContextAccessor.GetContext().CurrentUser;
if (!_authorizationService.TryCheckAccess(Permissions.ManageMainMenu, currentUser, part))
return null;
var model = new ContentMenuItemEditViewModel();
if(updater.TryUpdateModel(model, Prefix, null, null)) {
var contentItem = _contentManager.Get(model.ContentItemId);
if(contentItem == null) {
updater.AddModelError("ContentItemId", T("You must select a Content Item"));
}
else {
part.Content = contentItem;
}
}
return Editor(part, shapeHelper);
}
protected override void Importing(ContentMenuItemPart part, ImportContentContext context) {
var contentItemId = context.Attribute(part.PartDefinition.Name, "ContentItem");
if (contentItemId != null) {
var contentItem = context.GetItemFromSession(contentItemId);
part.Content = contentItem;
}
else {
part.Content = null;
}
}
protected override void Exporting(ContentMenuItemPart part, ExportContentContext context) {
if (part.Content != null) {
var contentItem = _contentManager.Get(part.Content.Id);
if (contentItem != null) {
var containerIdentity = _contentManager.GetItemMetadata(contentItem).Identity;
context.Element(part.PartDefinition.Name).SetAttributeValue("ContentItem", containerIdentity.ToString());
}
}
}
}
}

View File

@ -15,13 +15,25 @@ namespace Orchard.Core.Navigation.Drivers {
_workContextAccessor = workContextAccessor;
}
protected override DriverResult Editor(MenuItemPart itemPart, IUpdateModel updater, dynamic shapeHelper) {
protected override DriverResult Editor(MenuItemPart part, dynamic shapeHelper) {
var currentUser = _workContextAccessor.GetContext().CurrentUser;
if (!_authorizationService.TryCheckAccess(Permissions.ManageMainMenu, currentUser, itemPart))
if (!_authorizationService.TryCheckAccess(Permissions.ManageMainMenu, currentUser, part))
return null;
updater.TryUpdateModel(itemPart, Prefix, null, null);
return null;
return ContentShape("Parts_MenuItem_Edit",
() => shapeHelper.EditorTemplate(TemplateName: "Parts.MenuItem.Edit", Model: part, Prefix: Prefix));
}
protected override DriverResult Editor(MenuItemPart part, IUpdateModel updater, dynamic shapeHelper) {
var currentUser = _workContextAccessor.GetContext().CurrentUser;
if (!_authorizationService.TryCheckAccess(Permissions.ManageMainMenu, currentUser, part))
return null;
if (updater != null) {
updater.TryUpdateModel(part, Prefix, null, null);
}
return Editor(part, shapeHelper);
}
protected override void Importing(MenuItemPart part, ContentManagement.Handlers.ImportContentContext context) {

View File

@ -3,6 +3,8 @@ using JetBrains.Annotations;
using Orchard.ContentManagement;
using Orchard.ContentManagement.Drivers;
using Orchard.Core.Navigation.Models;
using Orchard.Core.Navigation.Services;
using Orchard.Core.Navigation.ViewModels;
using Orchard.Localization;
using Orchard.Security;
using Orchard.UI.Navigation;
@ -14,11 +16,17 @@ namespace Orchard.Core.Navigation.Drivers {
private readonly IAuthorizationService _authorizationService;
private readonly INavigationManager _navigationManager;
private readonly IOrchardServices _orchardServices;
private readonly IMenuService _menuService;
public MenuPartDriver(IAuthorizationService authorizationService, INavigationManager navigationManager, IOrchardServices orchardServices) {
public MenuPartDriver(
IAuthorizationService authorizationService,
INavigationManager navigationManager,
IOrchardServices orchardServices,
IMenuService menuService) {
_authorizationService = authorizationService;
_navigationManager = navigationManager;
_orchardServices = orchardServices;
_menuService = menuService;
T = NullLocalizer.Instance;
}
@ -28,21 +36,39 @@ namespace Orchard.Core.Navigation.Drivers {
if (!_authorizationService.TryCheckAccess(Permissions.ManageMainMenu, _orchardServices.WorkContext.CurrentUser, part))
return null;
return ContentShape("Parts_Navigation_Menu_Edit",
() => shapeHelper.EditorTemplate(TemplateName: "Parts.Navigation.Menu.Edit", Model: part, Prefix: Prefix));
return ContentShape("Parts_Navigation_Menu_Edit", () => {
var model = new MenuPartViewModel {
CurrentMenuId = part.Menu == null ? -1 : part.Menu.Id,
ContentItem = part.ContentItem,
Menus = _menuService.GetMenus(),
OnMenu = part.Menu != null,
MenuText = part.MenuText
};
return shapeHelper.EditorTemplate(TemplateName: "Parts.Navigation.Menu.Edit", Model: model, Prefix: Prefix);
});
}
protected override DriverResult Editor(MenuPart part, IUpdateModel updater, dynamic shapeHelper) {
if (!_authorizationService.TryCheckAccess(Permissions.ManageMainMenu, _orchardServices.WorkContext.CurrentUser, part))
return null;
if (string.IsNullOrEmpty(part.MenuPosition))
part.MenuPosition = Position.GetNext(_navigationManager.BuildMenu("main"));
var model = new MenuPartViewModel();
updater.TryUpdateModel(part, Prefix, null, null);
if(updater.TryUpdateModel(model, Prefix, null, null)) {
var menu = model.OnMenu ? _orchardServices.ContentManager.Get(model.CurrentMenuId) : null;
if (part.OnMainMenu && string.IsNullOrEmpty(part.MenuText))
updater.AddModelError("MenuText", T("The MenuText field is required"));
part.MenuText = model.MenuText;
part.Menu = menu;
if (string.IsNullOrEmpty(part.MenuPosition) && menu != null) {
part.MenuPosition = Position.GetNext(_navigationManager.BuildMenu(menu));
if (string.IsNullOrEmpty(part.MenuText)) {
updater.AddModelError("MenuText", T("The MenuText field is required"));
}
}
}
return Editor(part, shapeHelper);
}
@ -58,16 +84,27 @@ namespace Orchard.Core.Navigation.Drivers {
part.MenuPosition = position;
}
var onMainMenu = context.Attribute(part.PartDefinition.Name, "OnMainMenu");
if (onMainMenu != null) {
part.OnMainMenu = Convert.ToBoolean(onMainMenu);
var menuIdentity = context.Attribute(part.PartDefinition.Name, "Menu");
if (menuIdentity != null) {
var menu = context.GetItemFromSession(menuIdentity);
if (menu != null) {
part.Menu = menu;
}
}
}
protected override void Exporting(MenuPart part, ContentManagement.Handlers.ExportContentContext context) {
// is it on a menu ?
if(part.Menu == null) {
return;
}
var menu = _orchardServices.ContentManager.Get(part.Menu.Id);
var menuIdentity = _orchardServices.ContentManager.GetItemMetadata(menu).Identity;
context.Element(part.PartDefinition.Name).SetAttributeValue("Menu", menuIdentity);
context.Element(part.PartDefinition.Name).SetAttributeValue("MenuText", part.MenuText);
context.Element(part.PartDefinition.Name).SetAttributeValue("MenuPosition", part.MenuPosition);
context.Element(part.PartDefinition.Name).SetAttributeValue("OnMainMenu", part.OnMainMenu);
}
}
}

View File

@ -0,0 +1,209 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Web.Routing;
using Orchard.ContentManagement;
using Orchard.ContentManagement.Aspects;
using Orchard.ContentManagement.Drivers;
using Orchard.ContentManagement.Handlers;
using Orchard.Core.Navigation.Models;
using Orchard.Core.Navigation.Services;
using Orchard.Core.Navigation.ViewModels;
using Orchard.Core.Title.Models;
using Orchard.Localization;
using Orchard.UI.Navigation;
using Orchard.Utility.Extensions;
namespace Orchard.Core.Navigation.Drivers {
public class MenuWidgetPartDriver : ContentPartDriver<MenuWidgetPart> {
private readonly IContentManager _contentManager;
private readonly INavigationManager _navigationManager;
private readonly IWorkContextAccessor _workContextAccessor;
private readonly IMenuService _menuService;
public MenuWidgetPartDriver(
IContentManager contentManager,
INavigationManager navigationManager,
IWorkContextAccessor workContextAccessor,
IMenuService menuService) {
_contentManager = contentManager;
_navigationManager = navigationManager;
_workContextAccessor = workContextAccessor;
_menuService = menuService;
T = NullLocalizer.Instance;
}
public Localizer T { get; set; }
protected override string Prefix {
get {
return "MenuWidget";
}
}
protected override DriverResult Display(MenuWidgetPart part, string displayType, dynamic shapeHelper) {
return ContentShape( "Parts_MenuWidget", () => {
var menu = _menuService.GetMenu(part.Menu.Id);
if(menu == null) {
return null;
}
var menuName = menu.As<TitlePart>().Title.HtmlClassify();
var currentCulture = _workContextAccessor.GetContext().CurrentCulture;
IEnumerable<MenuItem> menuItems = _navigationManager.BuildMenu(menu);
var localized = new List<MenuItem>();
foreach(var menuItem in menuItems) {
// if there is no associated content, it as culture neutral
if(menuItem.Content == null) {
localized.Add(menuItem);
}
// if the menu item is culture neutral or of the current culture
if (String.IsNullOrEmpty(menuItem.Culture) || String.Equals(menuItem.Culture, currentCulture, StringComparison.OrdinalIgnoreCase)) {
localized.Add(menuItem);
}
}
menuItems = localized;
var routeData = _workContextAccessor.GetContext().HttpContext.Request.RequestContext.RouteData;
var selectedPath = NavigationHelper.SetSelectedPath(menuItems, routeData);
dynamic menuShape = shapeHelper.Menu();
if (part.Breadcrumb) {
menuItems = selectedPath;
foreach (var menuItem in menuItems) {
menuItem.Items = Enumerable.Empty<MenuItem>();
}
// apply level limites to breadcrumb
menuItems = menuItems.Skip(part.StartLevel - 1);
if (part.Levels > 0) {
menuItems = menuItems.Take(part.Levels);
}
var result = new List<MenuItem>(menuItems);
// inject the home page
if (part.AddHomePage) {
result.Insert(0, new MenuItem {
Href = _navigationManager.GetUrl("~/", null),
Text = T("Home")
});
}
// inject the current page
if (!part.AddCurrentPage) {
result.RemoveAt(result.Count - 1);
}
// prevent the home page to be added as the home page and the current page
if (result.Count == 2 && String.Equals(result[0].Href, result[1].Href, StringComparison.OrdinalIgnoreCase)) {
result.RemoveAt(1);
}
menuItems = result;
menuShape = shapeHelper.Breadcrumb();
}
else {
IEnumerable<MenuItem> topLevelItems = menuItems.ToList();
if(part.StartLevel > 1) {
topLevelItems = selectedPath.Where(x => x.Selected);
}
if (topLevelItems.Any()) {
// apply start level by pushing childrens as top level items
int i = 0;
for (; i < part.StartLevel - 1; i++) {
var temp = new List<MenuItem>();
foreach (var menuItem in topLevelItems) {
temp.AddRange(menuItem.Items);
}
topLevelItems = temp;
}
// apply display level
if(part.Levels > 0) {
var current = topLevelItems.ToList();
for (; i < part.Levels - part.StartLevel; i++ ) {
var temp = new List<MenuItem>();
foreach (var menuItem in current) {
temp.AddRange(menuItem.Items);
}
current = temp;
}
foreach(var menuItem in current) {
menuItem.Items = Enumerable.Empty<MenuItem>();
}
}
menuItems = topLevelItems;
}
}
menuShape.MenuName(menuName);
NavigationHelper.PopulateMenu(shapeHelper, menuShape, menuShape, menuItems);
return shapeHelper.Parts_MenuWidget(Menu: menuShape);
});
}
protected override DriverResult Editor(MenuWidgetPart part, dynamic shapeHelper) {
return ContentShape("Parts_MenuWidget_Edit", () => {
var model = new MenuWidgetViewModel {
CurrentMenuId = part.Menu == null ? -1 : part.Menu.Id,
StartLevel = part.StartLevel,
StopLevel = part.Levels,
Breadcrumb = part.Breadcrumb,
AddCurrentPage = part.AddCurrentPage,
AddHomePage = part.AddHomePage,
Menus = _menuService.GetMenus(),
};
return shapeHelper.EditorTemplate(TemplateName: "Parts.MenuWidget.Edit", Model: model, Prefix: Prefix);
});
}
protected override DriverResult Editor(MenuWidgetPart part, IUpdateModel updater, dynamic shapeHelper) {
var model = new MenuWidgetViewModel();
if(updater.TryUpdateModel(model, Prefix, null, null)) {
part.StartLevel = model.StartLevel;
part.Levels = model.StopLevel;
part.Breadcrumb = model.Breadcrumb;
part.AddHomePage = model.AddHomePage;
part.AddCurrentPage = model.AddCurrentPage;
part.Menu = _contentManager.Get(model.CurrentMenuId).Record;
}
return Editor(part, shapeHelper);
}
protected override void Importing(MenuWidgetPart part, ImportContentContext context) {
context.ImportAttribute(part.PartDefinition.Name, "StartLevel", x => part.StartLevel = Convert.ToInt32(x));
context.ImportAttribute(part.PartDefinition.Name, "Levels", x => part.Levels = Convert.ToInt32(x));
context.ImportAttribute(part.PartDefinition.Name, "Breadcrumb", x => part.Breadcrumb = Convert.ToBoolean(x));
context.ImportAttribute(part.PartDefinition.Name, "Menu", x => part.Menu = context.GetItemFromSession(x).Record);
}
protected override void Exporting(MenuWidgetPart part, ExportContentContext context) {
var menuIdentity = _contentManager.GetItemMetadata(_contentManager.Get(part.Menu.Id)).Identity;
context.Element(part.PartDefinition.Name).SetAttributeValue("Menu", menuIdentity);
context.Element(part.PartDefinition.Name).SetAttributeValue("StartLevel", part.StartLevel);
context.Element(part.PartDefinition.Name).SetAttributeValue("Levels", part.Levels);
context.Element(part.PartDefinition.Name).SetAttributeValue("Breadcrumb", part.Breadcrumb);
}
}
}

View File

@ -0,0 +1,41 @@
using Orchard.ContentManagement;
using Orchard.ContentManagement.Drivers;
using Orchard.Core.Navigation.Models;
using Orchard.Core.Navigation.ViewModels;
using Orchard.Security;
namespace Orchard.Core.Navigation.Drivers {
public class NavigationPartDriver : ContentPartDriver<NavigationPart> {
private readonly IAuthorizationService _authorizationService;
private readonly IWorkContextAccessor _workContextAccessor;
private readonly IContentManager _contentManager;
public NavigationPartDriver(
IAuthorizationService authorizationService,
IWorkContextAccessor workContextAccessor,
IContentManager contentManager) {
_authorizationService = authorizationService;
_workContextAccessor = workContextAccessor;
_contentManager = contentManager;
}
protected override DriverResult Editor(NavigationPart part, dynamic shapeHelper) {
var currentUser = _workContextAccessor.GetContext().CurrentUser;
if (!_authorizationService.TryCheckAccess(Permissions.ManageMainMenu, currentUser, part))
return null;
return ContentShape("Parts_Navigation_Edit",
() => {
// loads all menu part of type ContentMenuItem linking to the current content item
var model = new NavigationPartViewModel() {
Part = part,
ContentMenuItems = _contentManager.Query<MenuPart>()
.Join<ContentMenuItemPartRecord>().Where(x => x.ContentMenuItemRecord == part.ContentItem.Record).List()
};
return shapeHelper.EditorTemplate(TemplateName: "Parts.Navigation.Edit", Model: model, Prefix: Prefix);
});
}
}
}

View File

@ -0,0 +1,34 @@
using JetBrains.Annotations;
using Orchard.ContentManagement;
using Orchard.Core.Navigation.Models;
using Orchard.Data;
using Orchard.ContentManagement.Handlers;
namespace Orchard.Core.Navigation.Handlers {
[UsedImplicitly]
public class ContentMenuItemPartHandler : ContentHandler {
private readonly IContentManager _contentManager;
public ContentMenuItemPartHandler(IContentManager contentManager, IRepository<ContentMenuItemPartRecord> repository) {
_contentManager = contentManager;
Filters.Add(new ActivatingFilter<ContentMenuItemPart>("ContentMenuItem"));
Filters.Add(StorageFilter.For(repository));
OnLoading<ContentMenuItemPart>((context, part) => part._content.Loader(p => contentManager.Get(part.Record.ContentMenuItemRecord.Id)));
}
protected override void GetItemMetadata(GetContentItemMetadataContext context) {
base.GetItemMetadata(context);
if (context.ContentItem.ContentType != "ContentMenuItem") {
return;
}
var contentMenuItemPart = context.ContentItem.As<ContentMenuItemPart>();
// the display route for the menu item is the one for the referenced content item
if(contentMenuItemPart != null) {
context.Metadata.DisplayRouteValues = _contentManager.GetItemMetadata(contentMenuItemPart.Content).DisplayRouteValues;
}
}
}
}

View File

@ -0,0 +1,39 @@
using JetBrains.Annotations;
using Orchard.ContentManagement;
using Orchard.ContentManagement.Handlers;
using Orchard.Core.Navigation.Services;
using Orchard.Core.Title.Models;
namespace Orchard.Core.Navigation.Handlers {
[UsedImplicitly]
public class MenuHandler : ContentHandler {
private readonly IMenuService _menuService;
private readonly IContentManager _contentManager;
public MenuHandler(IMenuService menuService, IContentManager contentManager) {
_menuService = menuService;
_contentManager = contentManager;
}
protected override void GetItemMetadata(GetContentItemMetadataContext context) {
if(context.ContentItem.ContentType != "Menu") {
return;
}
context.Metadata.Identity.Add("name", context.ContentItem.As<TitlePart>().Title);
}
protected override void Removing(RemoveContentContext context) {
if (context.ContentItem.ContentType != "Menu") {
return;
}
// remove all menu items
var menuParts = _menuService.GetMenuParts(context.ContentItem.Id);
foreach(var menuPart in menuParts) {
_contentManager.Remove(menuPart.ContentItem);
}
}
}
}

View File

@ -11,13 +11,5 @@ namespace Orchard.Core.Navigation.Handlers {
Filters.Add(new ActivatingFilter<MenuItemPart>("MenuItem"));
Filters.Add(StorageFilter.For(repository));
}
protected override void GetItemMetadata(GetContentItemMetadataContext context) {
var part = context.ContentItem.As<MenuItemPart>();
if (part != null) {
context.Metadata.Identity.Add("MenuItem.Url", part.Url);
}
}
}
}

View File

@ -1,5 +1,6 @@
using System;
using JetBrains.Annotations;
using Orchard.ContentManagement;
using Orchard.ContentManagement.Handlers;
using Orchard.Core.Navigation.Models;
using Orchard.Data;
@ -7,13 +8,45 @@ using Orchard.Data;
namespace Orchard.Core.Navigation.Handlers {
[UsedImplicitly]
public class MenuPartHandler : ContentHandler {
public MenuPartHandler(IRepository<MenuPartRecord> menuPartRepository) {
private readonly IContentManager _contentManager;
public MenuPartHandler(
IRepository<MenuPartRecord> menuPartRepository,
IContentManager contentManager
) {
_contentManager = contentManager;
Filters.Add(StorageFilter.For(menuPartRepository));
OnInitializing<MenuPart>((ctx, x) => {
x.OnMainMenu = false;
x.MenuText = String.Empty;
});
OnActivated<MenuPart>(PropertySetHandlers);
}
protected static void PropertySetHandlers(ActivatedContentContext context, MenuPart menuPart) {
menuPart.MenuField.Setter(menu => {
menuPart.Record.MenuId = menu.ContentItem.Id;
return menu;
});
}
protected void LazyLoadHandlers(MenuPart menuPart) {
menuPart.MenuField.Loader(ctx =>
_contentManager.Get(menuPart.Record.MenuId, menuPart.IsPublished() ? VersionOptions.Published : VersionOptions.Latest));
}
protected override void GetItemMetadata(GetContentItemMetadataContext context) {
var part = context.ContentItem.As<MenuPart>();
if (part != null) {
string stereotype;
if (context.ContentItem.TypeDefinition.Settings.TryGetValue("Stereotype", out stereotype) && stereotype == "MenuItem") {
context.Metadata.DisplayText = part.MenuText;
}
}
}
}
}

View File

@ -0,0 +1,13 @@
using Orchard.ContentManagement.Handlers;
using Orchard.Core.Navigation.Models;
using Orchard.Data;
namespace Orchard.Core.Navigation.Handlers {
public class MenuWidgetPartHandler : ContentHandler {
public MenuWidgetPartHandler(IRepository<MenuWidgetPartRecord> repository) {
Filters.Add(StorageFilter.For(repository));
OnInitializing<MenuWidgetPart>((context, part) => { part.StartLevel = 1; });
}
}
}

View File

@ -1,11 +1,21 @@
using Orchard.ContentManagement.MetaData;
using Orchard.Core.Contents.Extensions;
using Orchard.Core.Navigation.Services;
using Orchard.Data.Migration;
namespace Orchard.Core.Navigation {
public class Migrations : DataMigrationImpl {
private readonly IMenuService _menuService;
public Migrations(IMenuService menuService ) {
_menuService = menuService;
}
public int Create() {
ContentDefinitionManager.AlterPartDefinition("MenuPart", builder => builder.Attachable());
ContentDefinitionManager.AlterPartDefinition("NavigationPart", builder => builder.Attachable());
ContentDefinitionManager.AlterTypeDefinition("Page", cfg => cfg.WithPart("MenuPart"));
SchemaBuilder.CreateTable("MenuItemPartRecord",
table => table
.ContentPartRecord()
@ -17,14 +27,79 @@ namespace Orchard.Core.Navigation {
.ContentPartRecord()
.Column<string>("MenuText")
.Column<string>("MenuPosition")
.Column<bool>("OnMainMenu")
.Column<int>("MenuId")
);
ContentDefinitionManager.AlterTypeDefinition("Page", cfg => cfg.WithPart("MenuPart"));
ContentDefinitionManager.AlterTypeDefinition("MenuItem", cfg => cfg.WithPart("MenuPart"));
ContentDefinitionManager.AlterPartDefinition("MenuPart", builder => builder.Attachable());
ContentDefinitionManager.AlterTypeDefinition("MenuItem", cfg => cfg
.WithPart("MenuPart")
.WithPart("IdentityPart")
.WithPart("CommonPart")
.DisplayedAs("Custom Link")
.WithSetting("Description", "Represents a simple custom link with a text and an url.")
.WithSetting("Stereotype", "MenuItem") // because we declare a new stereotype, the Shape MenuItem_Edit is needed
);
ContentDefinitionManager.AlterTypeDefinition("Menu", cfg => cfg
.WithPart("CommonPart", p => p.WithSetting("OwnerEditorSettings.ShowOwnerEditor", "false"))
.WithPart("TitlePart")
);
SchemaBuilder.CreateTable("MenuWidgetPartRecord", table => table
.ContentPartRecord()
.Column<int>("StartLevel")
.Column<int>("Levels")
.Column<bool>("Breadcrumb")
.Column<bool>("AddHomePage")
.Column<bool>("AddCurrentPage")
.Column<int>("Menu_id")
);
ContentDefinitionManager.AlterTypeDefinition("MenuWidget", cfg => cfg
.WithPart("CommonPart")
.WithPart("IdentityPart")
.WithPart("WidgetPart")
.WithPart("MenuWidgetPart")
.WithSetting("Stereotype", "Widget")
);
SchemaBuilder.CreateTable("AdminMenuPartRecord",
table => table
.ContentPartRecord()
.Column<string>("AdminMenuText")
.Column<string>("AdminMenuPosition")
.Column<bool>("OnAdminMenu")
);
ContentDefinitionManager.AlterTypeDefinition("HtmlMenuItem", cfg => cfg
.WithPart("MenuPart")
.WithPart("BodyPart")
.WithPart("CommonPart")
.WithPart("IdentityPart")
.DisplayedAs("Html Menu Item")
.WithSetting("Description", "Renders some custom HTML in the menu.")
.WithSetting("BodyPartSettings.FlavorDefault", "html")
.WithSetting("Stereotype", "MenuItem")
);
return 1;
ContentDefinitionManager.AlterPartDefinition("AdminMenuPart", builder => builder.Attachable());
SchemaBuilder.CreateTable("ContentMenuItemPartRecord",
table => table
.ContentPartRecord()
.Column<int>("ContentMenuItemRecord_id")
);
ContentDefinitionManager.AlterTypeDefinition("ContentMenuItem", cfg => cfg
.WithPart("MenuPart")
.WithPart("CommonPart")
.WithPart("IdentityPart")
.WithPart("ContentMenuItemPart")
.DisplayedAs("Content Menu Item")
.WithSetting("Description", "Adds a Content Item to the menu.")
.WithSetting("Stereotype", "MenuItem")
);
return 3;
}
public int UpdateFrom1() {
@ -39,5 +114,73 @@ namespace Orchard.Core.Navigation {
return 2;
}
public int UpdateFrom2() {
ContentDefinitionManager.AlterTypeDefinition("MenuItem", cfg => cfg
.WithPart("MenuPart")
.WithPart("CommonPart")
.WithPart("IdentityPart")
.DisplayedAs("Custom Link")
.WithSetting("Description", "Represents a simple custom link with a text and an url.")
.WithSetting("Stereotype", "MenuItem") // because we declare a new stereotype, the Shape MenuItem_Edit is needed
);
ContentDefinitionManager.AlterTypeDefinition("Menu", cfg => cfg
.WithPart("CommonPart")
.WithPart("TitlePart")
);
SchemaBuilder.CreateTable("MenuWidgetPartRecord",table => table
.ContentPartRecord()
.Column<int>("StartLevel")
.Column<int>("Levels")
.Column<bool>("Breadcrumb")
.Column<bool>("AddHomePage")
.Column<bool>("AddCurrentPage")
.Column<int>("Menu_id")
);
ContentDefinitionManager.AlterTypeDefinition("MenuWidget", cfg => cfg
.WithPart("CommonPart")
.WithPart("IdentityPart")
.WithPart("WidgetPart")
.WithPart("MenuWidgetPart")
.WithSetting("Stereotype", "Widget")
);
SchemaBuilder
.AlterTable("MenuPartRecord", table => table.DropColumn("OnMainMenu"))
.AlterTable("MenuPartRecord", table => table.AddColumn<int>("MenuId"))
;
ContentDefinitionManager.AlterTypeDefinition("HtmlMenuItem", cfg => cfg
.WithPart("MenuPart")
.WithPart("BodyPart")
.WithPart("CommonPart")
.WithPart("IdentityPart")
.DisplayedAs("Html Menu Item")
.WithSetting("Description", "Renders some custom HTML in the menu.")
.WithSetting("BodyPartSettings.FlavorDefault", "html")
.WithSetting("Stereotype", "MenuItem")
);
ContentDefinitionManager.AlterPartDefinition("NavigationPart", builder => builder.Attachable());
// create a Main Menu
var mainMenu = _menuService.Create("Main Menu");
// assign the Main Menu to all current menu items
foreach (var menuItem in _menuService.Get()) {
// if they don't have a position, then they are not displayed
if(string.IsNullOrWhiteSpace(menuItem.MenuPosition)) {
continue;
}
menuItem.Menu = mainMenu.ContentItem;
}
// at this point a widget should still be created to display the navigation
return 3;
}
}
}

View File

@ -0,0 +1,17 @@
using Orchard.ContentManagement;
using Orchard.ContentManagement.Utilities;
namespace Orchard.Core.Navigation.Models {
public class ContentMenuItemPart : ContentPart<ContentMenuItemPartRecord> {
public readonly LazyField<ContentItem> _content = new LazyField<ContentItem>();
public ContentItem Content {
get { return _content.Value; }
set {
_content.Value = value;
Record.ContentMenuItemRecord = value == null ? null : value.Record;
}
}
}
}

View File

@ -0,0 +1,7 @@
using Orchard.ContentManagement.Records;
namespace Orchard.Core.Navigation.Models {
public class ContentMenuItemPartRecord : ContentPartRecord {
public virtual ContentItemRecord ContentMenuItemRecord { get; set; }
}
}

View File

@ -1,9 +1,8 @@
using System.ComponentModel.DataAnnotations;
using Orchard.ContentManagement;
using Orchard.ContentManagement;
namespace Orchard.Core.Navigation.Models {
public class MenuItemPart : ContentPart<MenuItemPartRecord> {
[Required]
public string Url {
get { return Record.Url; }
set { Record.Url = value; }

View File

@ -1,12 +1,16 @@
using System.ComponentModel.DataAnnotations;
using Orchard.ContentManagement;
using Orchard.ContentManagement.Utilities;
namespace Orchard.Core.Navigation.Models {
public class MenuPart : ContentPart<MenuPartRecord> {
public bool OnMainMenu {
get { return Record.OnMainMenu; }
set { Record.OnMainMenu = value; }
private readonly LazyField<IContent> _menu = new LazyField<IContent>();
public LazyField<IContent> MenuField { get { return _menu; } }
public IContent Menu {
get { return _menu.Value; }
set { _menu.Value = value; }
}
[StringLength(MenuPartRecord.DefaultMenuTextLength)]

View File

@ -8,6 +8,6 @@ namespace Orchard.Core.Navigation.Models {
[StringLength(DefaultMenuTextLength)]
public virtual string MenuText { get; set; }
public virtual string MenuPosition { get; set; }
public virtual bool OnMainMenu { get; set; }
public virtual int MenuId { get; set; }
}
}

View File

@ -0,0 +1,36 @@
using Orchard.ContentManagement;
using Orchard.ContentManagement.Records;
namespace Orchard.Core.Navigation.Models {
public class MenuWidgetPart : ContentPart<MenuWidgetPartRecord> {
public int StartLevel {
get { return Record.StartLevel; }
set { Record.StartLevel = value; }
}
public int Levels {
get { return Record.Levels; }
set { Record.Levels = value; }
}
public bool Breadcrumb {
get { return Record.Breadcrumb; }
set { Record.Breadcrumb = value; }
}
public bool AddHomePage {
get { return Record.AddHomePage; }
set { Record.AddHomePage = value; }
}
public bool AddCurrentPage {
get { return Record.AddCurrentPage; }
set { Record.AddCurrentPage = value; }
}
public ContentItemRecord Menu {
get { return Record.Menu; }
set { Record.Menu = value; }
}
}
}

View File

@ -0,0 +1,13 @@
using Orchard.ContentManagement.Records;
namespace Orchard.Core.Navigation.Models {
public class MenuWidgetPartRecord : ContentPartRecord {
public virtual int StartLevel { get; set; }
public virtual int Levels { get; set; }
public virtual bool Breadcrumb { get; set; }
public virtual bool AddHomePage { get; set; }
public virtual bool AddCurrentPage { get; set; }
public virtual ContentItemRecord Menu { get; set; }
}
}

View File

@ -0,0 +1,9 @@
using Orchard.ContentManagement;
namespace Orchard.Core.Navigation.Models {
/// <summary>
/// Allows the management of Content Menu Items associated with a Content Item
/// </summary>
public class NavigationPart : ContentPart {
}
}

View File

@ -2,8 +2,9 @@
AntiForgery: enabled
Author: The Orchard Team
Website: http://orchardproject.net
Version: 1.4.2
OrchardVersion: 1.4.2
Version: 1.5
OrchardVersion: 1.5
Description: The navigation module creates and manages a simple navigation menu for the front-end of the application and allows you to add content items to the admin menu.
FeatureDescription: Menu management.
Category: Core
FeatureDependencies: Orchard.ContentPicker, Title

View File

@ -1,4 +1,9 @@
<Placement>
<Place Parts_Navigation_Menu_Edit="Content:9"/>
<Place Parts_Navigation_AdminMenu_Edit="Content:9.1"/>
<Place Parts_Navigation_Edit="Content:10"/>
<Place Parts_MenuItem_Edit="Content:10"/>
<Place Parts_ContentMenuItem_Edit="Content:10"/>
<Place Parts_MenuWidget_Edit="Content:10"/>
<Place Parts_MenuWidget="Content"/>
</Placement>

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appSettings>
<add key="webpages:Enabled" value="false" />
<configuration>
<appSettings>
<add key="webpages:Enabled" value="false" />
</appSettings>
<system.web>
<httpHandlers>

View File

@ -0,0 +1,400 @@
/*
* jQuery UI Nested Sortable
* v 1.4 / 30 dec 2011
* http://mjsarfatti.com/code/nestedSortable
*
* Depends on:
* jquery.ui.sortable.js 1.8+
*
* Copyright (c) 2010-2012 Manuele J Sarfatti
* Licensed under the MIT License
* http://www.opensource.org/licenses/mit-license.php
*/
(function ($) {
$.widget("mjs.nestedSortable", $.extend({}, $.ui.sortable.prototype, {
options: {
tabSize: 20,
disableNesting: 'mjs-nestedSortable-no-nesting',
errorClass: 'mjs-nestedSortable-error',
listType: 'ol',
maxLevels: 0,
protectRoot: false,
rootID: null,
rtl: false,
isAllowed: function (item, parent) { return true; }
},
_create: function () {
this.element.data('sortable', this.element.data('nestedSortable'));
if (!this.element.is(this.options.listType))
throw new Error('nestedSortable: Please check the listType option is set to your actual list type');
return $.ui.sortable.prototype._create.apply(this, arguments);
},
destroy: function () {
this.element
.removeData("nestedSortable")
.unbind(".nestedSortable");
return $.ui.sortable.prototype.destroy.apply(this, arguments);
},
_mouseDrag: function (event) {
//Compute the helpers position
this.position = this._generatePosition(event);
this.positionAbs = this._convertPositionTo("absolute");
if (!this.lastPositionAbs) {
this.lastPositionAbs = this.positionAbs;
}
//Do scrolling
if (this.options.scroll) {
var o = this.options, scrolled = false;
if (this.scrollParent[0] != document && this.scrollParent[0].tagName != 'HTML') {
if ((this.overflowOffset.top + this.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity)
this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop + o.scrollSpeed;
else if (event.pageY - this.overflowOffset.top < o.scrollSensitivity)
this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop - o.scrollSpeed;
if ((this.overflowOffset.left + this.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity)
this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft + o.scrollSpeed;
else if (event.pageX - this.overflowOffset.left < o.scrollSensitivity)
this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft - o.scrollSpeed;
} else {
if (event.pageY - $(document).scrollTop() < o.scrollSensitivity)
scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed);
else if ($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity)
scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed);
if (event.pageX - $(document).scrollLeft() < o.scrollSensitivity)
scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed);
else if ($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity)
scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed);
}
if (scrolled !== false && $.ui.ddmanager && !o.dropBehaviour)
$.ui.ddmanager.prepareOffsets(this, event);
}
//Regenerate the absolute position used for position checks
this.positionAbs = this._convertPositionTo("absolute");
//Set the helper position
if (!this.options.axis || this.options.axis != "y") this.helper[0].style.left = this.position.left + 'px';
if (!this.options.axis || this.options.axis != "x") this.helper[0].style.top = this.position.top + 'px';
//Rearrange
for (var i = this.items.length - 1; i >= 0; i--) {
//Cache variables and intersection, continue if no intersection
var item = this.items[i], itemElement = item.item[0], intersection = this._intersectsWithPointer(item);
if (!intersection) continue;
if (itemElement != this.currentItem[0] //cannot intersect with itself
&& this.placeholder[intersection == 1 ? "next" : "prev"]()[0] != itemElement //no useless actions that have been done before
&& !$.contains(this.placeholder[0], itemElement) //no action if the item moved is the parent of the item checked
&& (this.options.type == 'semi-dynamic' ? !$.contains(this.element[0], itemElement) : true)
//&& itemElement.parentNode == this.placeholder[0].parentNode // only rearrange items within the same container
) {
$(itemElement).mouseenter();
this.direction = intersection == 1 ? "down" : "up";
if (this.options.tolerance == "pointer" || this._intersectsWithSides(item)) {
$(itemElement).mouseleave();
this._rearrange(event, item);
} else {
break;
}
// Clear emtpy ul's/ol's
this._clearEmpty(itemElement);
this._trigger("change", event, this._uiHash());
break;
}
}
var parentItem = (this.placeholder[0].parentNode.parentNode &&
$(this.placeholder[0].parentNode.parentNode).closest('.ui-sortable').length)
? $(this.placeholder[0].parentNode.parentNode)
: null,
level = this._getLevel(this.placeholder),
childLevels = this._getChildLevels(this.helper),
previousItem = this.placeholder[0].previousSibling ? $(this.placeholder[0].previousSibling) : null;
if (previousItem != null) {
while (previousItem[0].nodeName.toLowerCase() != 'li' || previousItem[0] == this.currentItem[0]) {
if (previousItem[0].previousSibling) {
previousItem = $(previousItem[0].previousSibling);
} else {
previousItem = null;
break;
}
}
}
var newList = document.createElement(o.listType);
this.beyondMaxLevels = 0;
// If the item is moved to the left, send it to its parent level
if (parentItem != null &&
(o.rtl && (this.positionAbs.left + this.helper.outerWidth() > parentItem.offset().left + parentItem.outerWidth()) ||
!o.rtl && (this.positionAbs.left < parentItem.offset().left))) {
parentItem.after(this.placeholder[0]);
this._clearEmpty(parentItem[0]);
this._trigger("change", event, this._uiHash());
}
// If the item is below another one and is moved to the right, make it a children of it
else if (previousItem != null &&
(o.rtl && (this.positionAbs.left + this.helper.outerWidth() < previousItem.offset().left + previousItem.outerWidth() - o.tabSize) ||
!o.rtl && (this.positionAbs.left > previousItem.offset().left + o.tabSize))) {
this._isAllowed(previousItem, level, level + childLevels + 1);
if (!previousItem.children(o.listType).length) {
previousItem[0].appendChild(newList);
}
previousItem.children(o.listType)[0].appendChild(this.placeholder[0]);
this._trigger("change", event, this._uiHash());
}
else {
this._isAllowed(parentItem, level, level + childLevels);
}
//Post events to containers
this._contactContainers(event);
//Interconnect with droppables
if ($.ui.ddmanager) $.ui.ddmanager.drag(this, event);
//Call callbacks
this._trigger('sort', event, this._uiHash());
this.lastPositionAbs = this.positionAbs;
return false;
},
_mouseStop: function (event, noPropagation) {
// If the item is in a position not allowed, send it back
if (this.beyondMaxLevels) {
this.placeholder.removeClass(this.options.errorClass);
if (this.domPosition.prev) {
$(this.domPosition.prev).after(this.placeholder);
} else {
$(this.domPosition.parent).prepend(this.placeholder);
}
this._trigger("revert", event, this._uiHash());
}
// Clean last empty ul/ol
for (var i = this.items.length - 1; i >= 0; i--) {
var item = this.items[i].item[0];
this._clearEmpty(item);
}
$.ui.sortable.prototype._mouseStop.apply(this, arguments);
},
serialize: function (options) {
var o = $.extend({}, this.options, options),
items = this._getItemsAsjQuery(o && o.connected),
str = [];
$(items).each(function () {
var res = ($(o.item || this).attr(o.attribute || 'id') || '')
.match(o.expression || (/(.+)[-=_](.+)/)),
pid = ($(o.item || this).parent(o.listType)
.parent(o.items)
.attr(o.attribute || 'id') || '')
.match(o.expression || (/(.+)[-=_](.+)/));
if (res) {
str.push(((o.key || res[1]) + '[' + (o.key && o.expression ? res[1] : res[2]) + ']')
+ '='
+ (pid ? (o.key && o.expression ? pid[1] : pid[2]) : o.rootID));
}
});
if (!str.length && o.key) {
str.push(o.key + '=');
}
return str.join('&');
},
toHierarchy: function (options) {
var o = $.extend({}, this.options, options),
sDepth = o.startDepthCount || 0,
ret = [];
$(this.element).children(o.items).each(function () {
var level = _recursiveItems(this);
ret.push(level);
});
return ret;
function _recursiveItems(item) {
var id = ($(item).attr(o.attribute || 'id') || '').match(o.expression || (/(.+)[-=_](.+)/));
if (id) {
var currentItem = { "id": id[2] };
if ($(item).children(o.listType).children(o.items).length > 0) {
currentItem.children = [];
$(item).children(o.listType).children(o.items).each(function () {
var level = _recursiveItems(this);
currentItem.children.push(level);
});
}
return currentItem;
}
}
},
toArray: function (options) {
var o = $.extend({}, this.options, options),
sDepth = o.startDepthCount || 0,
ret = [],
left = 2;
ret.push({
"item_id": o.rootID,
"parent_id": 'none',
"depth": sDepth,
"left": '1',
"right": ($(o.items, this.element).length + 1) * 2
});
$(this.element).children(o.items).each(function () {
left = _recursiveArray(this, sDepth + 1, left);
});
ret = ret.sort(function (a, b) { return (a.left - b.left); });
return ret;
function _recursiveArray(item, depth, left) {
var right = left + 1,
id,
pid;
if ($(item).children(o.listType).children(o.items).length > 0) {
depth++;
$(item).children(o.listType).children(o.items).each(function () {
right = _recursiveArray($(this), depth, right);
});
depth--;
}
id = ($(item).attr(o.attribute || 'id')).match(o.expression || (/(.+)[-=_](.+)/));
if (depth === sDepth + 1) {
pid = o.rootID;
} else {
var parentItem = ($(item).parent(o.listType)
.parent(o.items)
.attr(o.attribute || 'id'))
.match(o.expression || (/(.+)[-=_](.+)/));
pid = parentItem[2];
}
if (id) {
ret.push({ "item_id": id[2], "parent_id": pid, "depth": depth, "left": left, "right": right });
}
left = right + 1;
return left;
}
},
_clearEmpty: function (item) {
var emptyList = $(item).children(this.options.listType);
if (emptyList.length && !emptyList.children().length) {
emptyList.remove();
}
},
_getLevel: function (item) {
var level = 1;
if (this.options.listType) {
var list = item.closest(this.options.listType);
while (!list.is('.ui-sortable')) {
level++;
list = list.parent().closest(this.options.listType);
}
}
return level;
},
_getChildLevels: function (parent, depth) {
var self = this,
o = this.options,
result = 0;
depth = depth || 0;
$(parent).children(o.listType).children(o.items).each(function (index, child) {
result = Math.max(self._getChildLevels(child, depth + 1), result);
});
return depth ? result + 1 : result;
},
_isAllowed: function (parentItem, level, levels) {
var o = this.options,
isRoot = $(this.domPosition.parent).hasClass('ui-sortable') ? true : false;
// Is the root protected?
// Are we trying to nest under a no-nest?
// Are we nesting too deep?
if (!o.isAllowed(parentItem, this.placeholder) ||
parentItem && parentItem.hasClass(o.disableNesting) ||
o.protectRoot && (parentItem == null && !isRoot || isRoot && level > 1)) {
this.placeholder.addClass(o.errorClass);
if (o.maxLevels < levels && o.maxLevels != 0) {
this.beyondMaxLevels = levels - o.maxLevels;
} else {
this.beyondMaxLevels = 1;
}
} else {
if (o.maxLevels < levels && o.maxLevels != 0) {
this.placeholder.addClass(o.errorClass);
this.beyondMaxLevels = levels - o.maxLevels;
} else {
this.placeholder.removeClass(o.errorClass);
this.beyondMaxLevels = 0;
}
}
}
}));
$.mjs.nestedSortable.prototype.options = $.extend({}, $.ui.sortable.prototype.options, $.mjs.nestedSortable.prototype.options);
})(jQuery);

View File

@ -0,0 +1,45 @@

(function ($) {
var populate = function (el, prefix) {
var pos = 1;
// direct children
var children = $(el).children('li').each(function (i, child) {
if (!prefix) prefix = '';
child = $(child);
// apply positions to all siblings
child.find('.navigation-position > input').attr('value', prefix + pos);
// recurse position for children
child.children('ol').each(function (i, item) { populate(item, prefix + pos.toString() + '.') });
pos++;
});
};
$('.navigation-menu > ol').nestedSortable({
disableNesting: 'no-nest',
forcePlaceholderSize: true,
handle: 'div',
helper: 'clone',
items: 'li',
maxLevels: 6,
opacity: 1,
placeholder: 'navigation-placeholder',
revert: 50,
tabSize: 30,
tolerance: 'pointer',
toleranceElement: '> div',
stop: function (event, ui) {
// update all positions whenever a menu item was moved
populate(this, '');
$('#save-message').show();
}
});
})(jQuery);

View File

@ -0,0 +1,28 @@
using System.Collections.Generic;
using System.Linq;
using Orchard.ContentManagement;
namespace Orchard.Core.Navigation.Services {
/// <summary>
/// Implements <see cref="IMenuManager"/> by searching for the <code>MenuItem</code> stereotype in the content type's settings.
/// </summary>
public class DefaultMenuManager : IMenuManager {
private readonly IContentManager _contentManager;
public DefaultMenuManager(IContentManager contentManager) {
_contentManager = contentManager;
}
public IEnumerable<MenuItemDescriptor> GetMenuItemTypes() {
return _contentManager.GetContentTypeDefinitions()
.Where(contentTypeDefinition => contentTypeDefinition.Settings.ContainsKey("Stereotype") && contentTypeDefinition.Settings["Stereotype"] == "MenuItem")
.Select(contentTypeDefinition =>
new MenuItemDescriptor {
Type = contentTypeDefinition.Name,
DisplayName = contentTypeDefinition.DisplayName,
Description = contentTypeDefinition.Settings.ContainsKey("Description") ? contentTypeDefinition.Settings["Description"] : null
});
}
}
}

View File

@ -0,0 +1,42 @@
using System.Web;
using Orchard.ContentManagement;
using Orchard.ContentManagement.Aspects;
using Orchard.Core.Navigation.Models;
using Orchard.Localization;
using Orchard.UI.Navigation;
namespace Orchard.Core.Navigation.Services {
public class DefaultMenuProvider : IMenuProvider {
private readonly IContentManager _contentManager;
public DefaultMenuProvider(IContentManager contentManager) {
_contentManager = contentManager;
}
public void GetMenu(IContent menu, NavigationBuilder builder) {
var menuParts = _contentManager
.Query<MenuPart, MenuPartRecord>()
.Where(x => x.MenuId == menu.Id)
.WithQueryHints(new QueryHints().ExpandRecords<MenuItemPartRecord>())
.List();
foreach (var menuPart in menuParts) {
if (menuPart != null) {
var part = menuPart;
// fetch the culture of the menu item, if any
string culture = null;
var localized = part.As<ILocalizableAspect>();
if(localized != null) {
culture = localized.Culture;
}
if (part.Is<MenuItemPart>())
builder.Add(new LocalizedString(HttpUtility.HtmlEncode(part.MenuText)), part.MenuPosition, item => item.Url(part.As<MenuItemPart>().Url).Content(part).Culture(culture));
else
builder.Add(new LocalizedString(HttpUtility.HtmlEncode(part.MenuText)), part.MenuPosition, item => item.Action(_contentManager.GetItemMetadata(part.ContentItem).DisplayRouteValues).Content(part).Culture(culture));
}
}
}
}
}

View File

@ -0,0 +1,18 @@
using System.Collections.Generic;
namespace Orchard.Core.Navigation.Services {
public interface IMenuManager : IDependency {
/// <summary>
/// Gets the list of Menu Item content types
/// </summary>
/// <returns>An IEnumerable{MenuItemDescriptor} containing the menu items content types.</returns>
IEnumerable<MenuItemDescriptor> GetMenuItemTypes();
}
public class MenuItemDescriptor {
public string Type { get; set; }
public string DisplayName { get; set; }
public string Description { get; set; }
}
}

View File

@ -1,10 +1,16 @@
using System.Collections.Generic;
using Orchard.ContentManagement;
using Orchard.Core.Navigation.Models;
namespace Orchard.Core.Navigation.Services {
public interface IMenuService : IDependency {
IEnumerable<MenuPart> Get();
MenuPart Get(int menuPartId);
IEnumerable<MenuPart> GetMenuParts(int menuId);
MenuPart Get(int id);
IContent GetMenu(int menuId);
IContent GetMenu(string name);
IEnumerable<ContentItem> GetMenus();
IContent Create(string name);
void Delete(MenuPart menuPart);
}
}

View File

@ -1,33 +0,0 @@
using System.Web;
using JetBrains.Annotations;
using Orchard.ContentManagement;
using Orchard.Core.Navigation.Models;
using Orchard.Localization;
using Orchard.UI.Navigation;
namespace Orchard.Core.Navigation.Services {
[UsedImplicitly]
public class MainMenuNavigationProvider : INavigationProvider {
private readonly IContentManager _contentManager;
public MainMenuNavigationProvider(IContentManager contentManager) {
_contentManager = contentManager;
}
public string MenuName { get { return "main"; } }
public void GetNavigation(NavigationBuilder builder) {
var menuParts = _contentManager.Query<MenuPart, MenuPartRecord>().Where(x => x.OnMainMenu).WithQueryHints(new QueryHints().ExpandRecords<MenuItemPartRecord>()).List();
foreach (var menuPart in menuParts) {
if (menuPart != null) {
var part = menuPart;
if (part.Is<MenuItemPart>())
builder.Add(new LocalizedString(HttpUtility.HtmlEncode(part.MenuText)), part.MenuPosition, item => item.Url(part.As<MenuItemPart>().Url));
else
builder.Add(new LocalizedString(HttpUtility.HtmlEncode(part.MenuText)), part.MenuPosition, item => item.Action(_contentManager.GetItemMetadata(part.ContentItem).DisplayRouteValues));
}
}
}
}
}

View File

@ -1,7 +1,10 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Linq;
using JetBrains.Annotations;
using Orchard.ContentManagement;
using Orchard.Core.Navigation.Models;
using Orchard.Core.Title.Models;
namespace Orchard.Core.Navigation.Services {
[UsedImplicitly]
@ -13,15 +16,54 @@ namespace Orchard.Core.Navigation.Services {
}
public IEnumerable<MenuPart> Get() {
return _contentManager.Query<MenuPart, MenuPartRecord>().Where(x => x.OnMainMenu).List();
return _contentManager.Query<MenuPart, MenuPartRecord>().List();
}
public IEnumerable<MenuPart> GetMenuParts(int menuId) {
return _contentManager
.Query<MenuPart, MenuPartRecord>()
.Where( x => x.MenuId == menuId)
.List();
}
public IContent GetMenu(string menuName) {
if(string.IsNullOrWhiteSpace(menuName)) {
return null;
}
return _contentManager.Query<TitlePart, TitlePartRecord>()
.Where(x => x.Title == menuName)
.ForType("Menu")
.Slice(0, 1)
.FirstOrDefault();
}
public IContent GetMenu(int menuId) {
return _contentManager.Get(menuId, VersionOptions.Published, new QueryHints().ExpandRecords<TitlePartRecord>());
}
public MenuPart Get(int menuPartId) {
return _contentManager.Get<MenuPart>(menuPartId);
}
public IContent Create(string name) {
if(string.IsNullOrWhiteSpace(name)) {
throw new ArgumentNullException(name);
}
var menu = _contentManager.Create("Menu");
menu.As<TitlePart>().Title = name;
return menu;
}
public void Delete(MenuPart menuPart) {
_contentManager.Remove(menuPart.ContentItem);
}
public IEnumerable<ContentItem> GetMenus() {
return _contentManager.Query().ForType("Menu").Join<TitlePartRecord>().OrderBy(x => x.Title).List();
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 897 B

View File

@ -0,0 +1,145 @@
#save-message {
display: none;
}
.navigation-menu ol ol {
margin: 0;
padding: 0;
padding-left: 30px; /* gap between each level */
}
.navigation-menu ol.sortable, .navigation-menu ol.sortable ol {
margin: 0;
padding: 0;
list-style-type: none;
}
.navigation-menu ol.sortable {
}
.navigation-menu li {
margin: 0;
padding: 0;
}
.navigation-menu li div {
border: 1px solid #ccc;
cursor: move;
padding: 3px 10px 3px 30px;
margin: 2px;
background: #eee;
display: inline-block;
min-width: 200px;
width: 100%;
}
.navigation-menu li div:hover {
background: #eee url(images/move.gif) no-repeat 9px 7px;
border: 1px solid #999;
}
.navigation-menu-item h2
{
display: inline;
font-size:1.077em;
}
.navigation-position
{
display: none;
}
.navigation-url
{
}
.navigation-actions
{
float: right;
}
/* style for the dynamically created placeholder */
.navigation-menu li.navigation-placeholder
{
background: #dadada;
}
/* layout */
#display-menu-controls {
display: block;
}
#display-menu-controls form, #display-menu-controls fieldset {
display: inline;
}
#navigation-menu-add {
display: inline;
position: relative;
}
.sections {
}
.primary
{
float: left;
width: 100%;
}
.container
{
margin-right:350px;
}
.secondary
{
padding:0;
margin:0;
margin-top:2px;
float:right;
width:300px;
margin-left: -300px;
}
.menu-items-zone {
/*background: #F3F4F5;*/
/*border:1px solid #E4E5E6;*/
padding:0px;
}
.menu-items-zone h2 {
font-size:1.077em;
padding:2px 2px;
}
.menu-items-zone li {
background:#FFF;
border:1px solid #CCC;
margin-bottom: 5px;
padding: 5px;
padding-right:65px;
display: block;
position:relative;
}
div.menu-item-description {
display: block;
}
div.menu-item-actions {
display: block;
position:absolute;
right:10px;
top:15px;
}
.menu-items-zone li a {
border:1px solid #EAEAEA;
}
.menu-items-zone li a:hover {
border-color:#487328;
}

View File

@ -0,0 +1,8 @@
using Orchard.Core.Navigation.Models;
namespace Orchard.Core.Navigation.ViewModels {
public class ContentMenuItemEditViewModel {
public int ContentItemId { get; set; }
public ContentMenuItemPart Part { get; set; }
}
}

View File

@ -1,4 +1,5 @@
using Orchard.UI.Navigation;
using Orchard.ContentManagement;
namespace Orchard.Core.Navigation.ViewModels {
public class MenuItemEntry {
@ -8,5 +9,7 @@ namespace Orchard.Core.Navigation.ViewModels {
public string Text { get; set; }
public string Url { get; set; }
public string Position { get; set; }
public ContentItem ContentItem { get; set; }
}
}

View File

@ -0,0 +1,13 @@
using System.Collections.Generic;
using Orchard.ContentManagement;
namespace Orchard.Core.Navigation.ViewModels {
public class MenuPartViewModel {
public IEnumerable<ContentItem> Menus { get; set; }
public int CurrentMenuId { get; set; }
public bool OnMenu { get; set; }
public ContentItem ContentItem { get; set; }
public string MenuText { get; set; }
}
}

View File

@ -0,0 +1,15 @@
using System.Collections.Generic;
using Orchard.ContentManagement;
namespace Orchard.Core.Navigation.ViewModels {
public class MenuWidgetViewModel {
public IEnumerable<ContentItem> Menus { get; set; }
public int CurrentMenuId { get; set; }
public int StartLevel { get; set; }
public int StopLevel { get; set; }
public bool Breadcrumb { get; set; }
public bool AddHomePage { get; set; }
public bool AddCurrentPage { get; set; }
}
}

View File

@ -1,5 +1,7 @@
using System.Collections.Generic;
using System.Linq;
using Orchard.ContentManagement;
using Orchard.Core.Navigation.Services;
namespace Orchard.Core.Navigation.ViewModels {
public class NavigationManagementViewModel {
@ -9,5 +11,9 @@ namespace Orchard.Core.Navigation.ViewModels {
public MenuItemEntry NewMenuItem { get; set; }
public IList<MenuItemEntry> MenuItemEntries { get; set; }
public IEnumerable<MenuItemDescriptor> MenuItemDescriptors { get; set; }
public IEnumerable<IContent> Menus { get; set; }
public IContent CurrentMenu { get; set; }
}
}

View File

@ -0,0 +1,9 @@
using System.Collections.Generic;
using Orchard.Core.Navigation.Models;
namespace Orchard.Core.Navigation.ViewModels {
public class NavigationPartViewModel {
public IEnumerable<MenuPart> ContentMenuItems { get; set; }
public NavigationPart Part { get; set; }
}
}

View File

@ -0,0 +1,7 @@
@{ Layout.Title = T("Create Menu Item").ToString(); }
@using (Html.BeginFormAntiForgeryPost()) {
@Html.ValidationSummary()
// Model is a Shape, calling Display() so that it is rendered using the most specific template for its Shape type
@Display(Model)
}

View File

@ -1,69 +1,127 @@
@model NavigationManagementViewModel
@using Orchard.ContentManagement;
@using Orchard.Core.Navigation.Models;
@using Orchard.Core.Navigation.ViewModels;
@using Orchard.Utility.Extensions;
@{ Layout.Title = T("Navigation").ToString(); }
@{
Layout.Title = T("Navigation").ToString();
Style.Include("navigation-admin.css");
@using (Html.BeginFormAntiForgeryPost()) {
<table class="items">
<colgroup>
<col id="Text" />
<col id="Position" />
<col id="Url" />
<col id="Actions" />
</colgroup>
<thead>
<tr>
<td scope="col">@T("Text")</td>
<td scope="col">@T("Position")</td>
<td scope="col">@T("Url")</td>
<td scope="col"></td>
</tr>
</thead>
<tbody>@{
var menuPartEntryIndex = 0;
foreach (var menuPartEntry in Model.MenuItemEntries) {
var i = menuPartEntryIndex;
<tr>
<td><input type="text" class="text-box" name="@Html.NameOf(m => m.MenuItemEntries[i].Text)" value="@menuPartEntry.Text" /></td>
<td><input type="text" class="text-box" name="@Html.NameOf(m => m.MenuItemEntries[i].Position)" value="@menuPartEntry.Position" /></td>
<td>@if (!menuPartEntry.IsMenuItem) {<input type="text" class="text-box disabled" disabled="disabled" value="@menuPartEntry.Url" /> } else {<input type="text" class="text-box" name="@Html.NameOf(m => m.MenuItemEntries[i].Url)" value="@menuPartEntry.Url" />}</td>
<td><input type="hidden" name="@Html.NameOf(m => m.MenuItemEntries[i].MenuItemId)" value="@menuPartEntry.MenuItemId" />@Html.ActionLink(T("Delete").Text, "Delete", new { id = menuPartEntry.MenuItemId }, new { @class="remove", itemprop="RemoveUrl UnsafeUrl" })</td>
</tr>
++menuPartEntryIndex;
}
}
</tbody>
</table>
<fieldset class="actions"><button type="submit" class="button">@T("Update All")</button></fieldset>
Script.Require("jQueryUI_Sortable");
Script.Include("jquery.mjs.nestedSortable.js");
Script.Include("navigation-admin.js");
}
<h2>@T("Add New Item")</h2>
@using (Html.BeginFormAntiForgeryPost(Url.Action("create"), FormMethod.Post)) {
<table class="menu items">
<colgroup>
<col id="AddText" />
<col id="AddPosition" />
<col id="AddUrl" />
<col id="AddActions" />
</colgroup>
<tbody>
<tr>
<td>
<label for="MenuText">@T("Text")</label>
@Html.EditorFor(m => m.NewMenuItem.Text)
</td>
<td>
<label for="MenuPosition">@T("Position")</label>
@Html.EditorFor(m => m.NewMenuItem.Position)
</td>
<td>
<label for="Url">@T("Url")</label>
@Html.EditorFor(m => m.NewMenuItem.Url)
</td>
<td><button class="add" type="submit">@T("Add")</button></td>
</tr>
</tbody>
</table>
}
<div id="save-message" class="message message-Warning">@T("You need to hit \"Save All\" in order to save your changes.")</div>
<div id="display-menu-controls">
@if (Model.Menus.Any()) {
using (Html.BeginForm("Index", "Admin", FormMethod.Get, new { area = "Navigation" })) {
<fieldset class="bulk-actions-auto">
<label for="menuId">@T("Current Menu:")</label>
<select id="menuId" name="menuId">
@foreach (var menu in Model.Menus) {
@Html.SelectOption(Model.CurrentMenu.Id, menu.Id, Html.ItemDisplayText(menu).ToString())
}
</select>
<button type="submit" class="apply-bulk-actions-auto">@T("Show")</button>
@Html.ActionLink(T("Edit").Text, "Edit", "Admin", new { area = "Contents", id = Model.CurrentMenu.Id, returnUrl = Url.Action("Index", "Admin", new { area = "Navigation" }) }, new { @class = "button" })
</fieldset>
}
}
<div id="navigation-menu-add">
@Html.Link(T("Add a new menu...").Text, Url.Action("Create", "Admin", new { area = "Contents", id = "Menu", returnUrl = Request.RawUrl }))
</div>
</div>
@using (Html.BeginFormAntiForgeryPost()) {
<div class="sections">
<div class="primary">
<div class="container">
<div class="navigation-menu">
@if (Model.MenuItemEntries.Any()) {
@RenderMenuItems(Model.MenuItemEntries, 0)
}
else {
<h2>@T("The menu is empty")</h2>
}
</div>
</div>
</div>
<div class="secondary">
<ul class="menu-items-zone">
@foreach (var descriptor in Model.MenuItemDescriptors.OrderBy(x => x.DisplayName)) {
<li>
<div class="menu-item-description"><h2>@descriptor.DisplayName.CamelFriendly()</h2>
@if (!string.IsNullOrWhiteSpace(descriptor.Description)) {
<span class="hint">@descriptor.Description</span>
}
</div>
<div class="menu-item-actions">@Html.ActionLink(T("Add").Text, "CreateMenuItem", "Admin", new { area = "Navigation", id = descriptor.Type, menuId = Model.CurrentMenu.Id, returnUrl = Request.RawUrl }, new { @class = "button grey" })</div>
</li>
}
</ul>
</div>
</div>
<fieldset class="actions">
<button type="submit" class="button">@T("Save All")</button>
</fieldset>
}
@helper RenderMenuItems(IList<MenuItemEntry> menuItems, int index) {
@:<ol>
// store current level to detect lowerb or upper level
int currentLevel = Model.MenuItemEntries[index].Position.Split('.').Length - 1;
bool first = true;
for (int i = index; i < Model.MenuItemEntries.Count; i++) {
var menuPartEntry = Model.MenuItemEntries[i];
var level = menuPartEntry.Position.Split('.').Length - 1; // 0 is for root level
if (level > currentLevel) {
// render sub level, then continue to next element
@RenderMenuItems(menuItems, i)
var j = i;
while (j < Model.MenuItemEntries.Count && Model.MenuItemEntries[j].Position.Split('.').Length - 1 > currentLevel) { j++; };
i = j - 1;
continue;
}
if (level == currentLevel) {
if (!first) {
@:</li>
}
first = false;
@:<li class="navigation-menu-item" data-index="@i">
<div>
<h2>@menuPartEntry.Text</h2>
<span class="navigation-type">(@menuPartEntry.ContentItem.TypeDefinition.DisplayName)</span>
<span class="navigation-position"><input type="text" class="text-box" name="@Html.NameOf(m => m.MenuItemEntries[i].Position)" value="@menuPartEntry.Position" /></span>
<span class="navigation-actions">
<input type="hidden" name="@Html.NameOf(m => m.MenuItemEntries[i].MenuItemId)" value="@menuPartEntry.MenuItemId" />
@Html.ItemEditLink(T("Edit").Text, menuPartEntry.ContentItem, new { returnUrl = Request.RawUrl })@T(" | ")
@Html.ActionLink(T("Delete").Text, "Delete", new { id = menuPartEntry.MenuItemId }, new { @class = "remove", itemprop = "RemoveUrl UnsafeUrl" })
</span>
</div>
continue;
}
// done with current level
if (level < currentLevel) {
@:</li>
break;
}
}
@:</ol>
}

View File

@ -0,0 +1,25 @@
@{
Model.Sidebar.Add(New.Menu_DeleteButton().ContentItem(Model.ContentItem), "25");
}
<div class="edit-item">
<div class="edit-item-primary">
@if (Model.Content != null) {
<div class="edit-item-content">
@Display(Model.Content)
</div>
}
</div>
<div class="edit-item-secondary group">
@if (Model.Actions != null) {
<div class="edit-item-actions">
@Display(Model.Actions)
</div>
}
@if (Model.Sidebar != null) {
<div class="edit-item-sidebar group">
@Display(Model.Sidebar)
</div>
}
</div>
</div>

View File

@ -0,0 +1,36 @@
@model Orchard.Core.Navigation.ViewModels.ContentMenuItemEditViewModel
@{
Script.Require("ContentPicker").AtFoot();
var title = Model.Part.Content == null ? new HtmlString(T("Empty").Text) : Html.ItemDisplayText(Model.Part.Content);
}
<fieldset>
<label>@T("Content Item")</label>
<span id="title-@Html.FieldIdFor(m => m.ContentItemId)" class="content-picker-title">@title</span>
<span id="btn-@Html.FieldIdFor(m => m.ContentItemId)" class="button">@T("Browse")</span>
@Html.HiddenFor(m => m.ContentItemId)
<span class="hint">@T("Select the Content Item to display in the menu.")</span>
</fieldset>
@using(Script.Foot()) {
<script type="text/javascript">
//<![CDATA[
jQuery('#btn-@Html.FieldIdFor(m => m.ContentItemId)').click(function() {
jQuery('#btn-@Html.FieldIdFor(m => m.ContentItemId)').trigger("orchard-admin-contentpicker-open", {
callback: function(data) {
jQuery('#@Html.FieldIdFor(m => m.ContentItemId)').val(data.id);
jQuery('#title-@Html.FieldIdFor(m => m.ContentItemId)').text(data.displayText);
// define the menu text if it's empty
var menuText = jQuery('#MenuText');
if (menuText.val().length == 0) {
menuText.val(data.displayText);
}
}
});
});
//]]>
</script>
}

View File

@ -0,0 +1,8 @@
@model MenuItemPart
@using Orchard.Core.Navigation.Models;
<fieldset>
<label for="@Html.FieldIdFor(m => m.Url)">@T("Url")</label>
@Html.TextBoxFor(m => m.Url, new { @class = "large text" })
<span class="hint">@T("A valid url, i.e. ~/my-page, http://orchardproject.net, /content/file.pdf, ...")</span>
</fieldset>

View File

@ -0,0 +1,45 @@
@model Orchard.Core.Navigation.ViewModels.MenuWidgetViewModel
@using Orchard.ContentManagement
@using Orchard.Core.Navigation.Models;
<fieldset>
@Html.LabelFor(m => m.CurrentMenuId, T("For Menu"))
<select id="@Html.FieldIdFor(m => m.CurrentMenuId)" name="@Html.FieldNameFor(m => m.CurrentMenuId)">
@foreach(ContentItem menu in Model.Menus) {
@Html.SelectOption(Model.CurrentMenuId, menu.Id, Html.ItemDisplayText(menu).ToString())
}
</select>
<span class="hint">@T("Select which menu you want to display")</span>
</fieldset>
<fieldset>
<label for="@Html.FieldIdFor(m => m.StartLevel)">@T("Start Level")</label>
@Html.TextBoxFor(m => m.StartLevel, new { @class = "text text-small" })
<span class="hint">@T("The level the menu should start at.")</span>
</fieldset>
<fieldset>
<label for="@Html.FieldIdFor(m => m.StopLevel)">@T("Levels to display")</label>
@Html.TextBoxFor(m => m.StopLevel, new { @class = "text text-small" })
<span class="hint">@T("The number of levels to display, \"0\" meaning all levels.")</span>
</fieldset>
<fieldset>
@Html.EditorFor(m => m.Breadcrumb)
<label class="forcheckbox" for="@Html.FieldIdFor(m => m.Breadcrumb)">@T("Display as Breadcrumb")</label>
<span class="hint">@T("Check to render the path to the current content item.")</span>
</fieldset>
<div data-controllerid="@Html.FieldIdFor(m => m.Breadcrumb)">
<fieldset>
@Html.EditorFor(m => m.AddHomePage)
<label class="forcheckbox" for="@Html.FieldIdFor(m => m.AddHomePage)">@T("Add the home page as the first element")</label>
<span class="hint">@T("Check to render the home page as the first element of the breadcrumb.")</span>
</fieldset>
<fieldset>
@Html.EditorFor(m => m.AddCurrentPage)
<label class="forcheckbox" for="@Html.FieldIdFor(m => m.AddCurrentPage)">@T("Add the current content item as the last element")</label>
<span class="hint">@T("Check to render the current content item as the last element.")</span>
</fieldset>
</div>

View File

@ -0,0 +1,26 @@
@model Orchard.Core.Navigation.ViewModels.NavigationPartViewModel
@using Orchard.ContentManagement
@{
var contentManager = WorkContext.Resolve<IContentManager>();
}
<fieldset>
<label>@T("Menu Items")</label>
<span class="hint">@T("The menu items linking to this content item.")</span>
@if(Model.ContentMenuItems.Any()) {
<ul>
@foreach(var menuPart in Model.ContentMenuItems) {
var menuContentItem = contentManager.Get(menuPart.Menu.Id);
var menuName = Html.ItemDisplayText(menuContentItem).ToString();
<li>
<div><span>@menuPart.MenuText</span> @T("on") <span>@Html.ActionLink(menuName, "Index", "Admin", new { area = "Navigation", menuId = menuContentItem.Id }, new {}) </span></div>
</li>
}
</ul>
}
else {
@T("Not displayed in any menu.")
}
</fieldset>

View File

@ -1,13 +1,36 @@
@model MenuPart
@model Orchard.Core.Navigation.ViewModels.MenuPartViewModel
@using Orchard.ContentManagement
@using Orchard.Core.Navigation.Models;
@{
Script.Require("ShapesBase");
@if (!Model.ContentItem.TypeDefinition.Settings.ContainsKey("Stereotype") || Model.ContentItem.TypeDefinition.Settings["Stereotype"] != "MenuItem") {
<fieldset>
@Html.EditorFor(m => m.OnMenu)
<label for="@Html.FieldIdFor(m => m.OnMenu)" class="forcheckbox">@T("Show on a menu")</label>
<div data-controllerid="@Html.FieldIdFor(m => m.OnMenu)" class="">
<select id="@Html.FieldIdFor(m => m.CurrentMenuId)" name="@Html.FieldNameFor(m => m.CurrentMenuId)">
@foreach (ContentItem menu in Model.Menus) {
@Html.SelectOption(Model.CurrentMenuId, menu.Id, Html.ItemDisplayText(menu).ToString())
}
</select>
<span class="hint">@T("Select which menu you want the content item to be displayed on.")</span>
<label for="MenuText">@T("Menu text")</label>
@Html.TextBoxFor(m => m.MenuText, new { @class = "text-box single-line" })
<span class="hint">@T("The text that should appear in the menu.")</span>
</div>
</fieldset>
}
<fieldset>
@Html.EditorFor(m => m.OnMainMenu)
<label for="OnMainMenu" class="forcheckbox">@T("Show on main menu")</label>
<div data-controllerid="OnMainMenu" class="">
else {
<fieldset>
<label for="MenuText">@T("Menu text")</label>
@Html.TextBoxFor(m => m.MenuText, new { @class = "text-box single-line" })
</div>
</fieldset>
@Html.TextBoxFor(m => m.MenuText, new { @class = "textMedium", autofocus = "autofocus" })
<span class="hint">@T("The text that should appear in the menu.")</span>
@Html.HiddenFor(m => m.OnMenu, true)
@Html.HiddenFor(m => m.CurrentMenuId, Request["menuId"])
</fieldset>
}

View File

@ -0,0 +1,14 @@
@using Orchard.ContentManagement;
@using Orchard.Core.Contents
@using Orchard.Utility.Extensions;
@{
ContentItem contentItem = Model.ContentItem;
string returnUrl = Request["returnUrl"];
}
@if (Authorizer.Authorize(Permissions.DeleteContent, contentItem)) {
<fieldset class="delete-button">
@Html.Link(T("Delete").Text, Url.ItemRemoveUrl(contentItem, new {returnUrl}), new { @class = "button", itemprop = "RemoveUrl UnsafeUrl"})
</fieldset>
}

View File

@ -0,0 +1,26 @@
@{
Model.Sidebar.Add("Foo");
}
<div class="edit-item">
<div class="edit-item-primary">
@if (Model.Content != null) {
<div class="edit-item-content">
@Display(Model.Content)
</div>
}
</div>
<div class="edit-item-secondary group">
@if (Model.Actions != null) {
<div class="edit-item-actions">
@Display(Model.Actions)
</div>
}
@if (Model.Sidebar != null) {
<div class="edit-item-sidebar group">
@Display(Model.Sidebar)
</div>
}
</div>
</div>

View File

@ -0,0 +1,8 @@
<div class="sections">
<div class="primary">
@Display(Model.Content)
</div>
<div class="secondary">
@Display(Model.Sidebar)
</div>
</div>

View File

@ -0,0 +1 @@
@Display(Model.Content)

View File

@ -0,0 +1,8 @@
@using Orchard.ContentManagement
@{
ContentItem contentItem = Model.Content.ContentItem.ContentMenuItemPart.Content;
}
@if (contentItem != null) {
<a href="@Model.Href">@Model.Text</a>
}

View File

@ -0,0 +1 @@
<span class="raw">@Html.Raw(Model.Content.BodyPart.Text)</span>

View File

@ -0,0 +1 @@
@Display(Model.Menu)

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