Merge branch 'dev' into feature/recipesteps

Conflicts:
	src/Orchard.Web/Modules/Orchard.Recipes/Services/RecipeParser.cs
	src/Orchard.Web/Modules/Orchard.Setup/Recipes/blog.recipe.xml
	src/Orchard.Web/Modules/Orchard.Setup/Recipes/core.recipe.xml
	src/Orchard.Web/Modules/Orchard.Setup/Recipes/default.recipe.xml
This commit is contained in:
Sipke Schoorstra
2015-07-17 09:57:45 +01:00
24 changed files with 162 additions and 137 deletions

View File

@@ -1,16 +1,8 @@
using System; using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Autofac; using Autofac;
using NUnit.Framework; using NUnit.Framework;
using Orchard.Localization.Models; using Orchard.Localization.Models;
using Orchard.Localization.Services; using Orchard.Localization.Services;
using Orchard.Services;
namespace Orchard.Tests.Localization { namespace Orchard.Tests.Localization {
@@ -217,6 +209,17 @@ namespace Orchard.Tests.Localization {
Assert.AreEqual(dateTimeLocal, result); Assert.AreEqual(dateTimeLocal, result);
} }
[Test]
[Description("DateTime which is DateTimeKind.Local is converted to DateTimeKind.Utc.")]
public void ConvertFromLocalizedDateStringTest01() {
var container = TestHelpers.InitializeContainer("en-US", "GregorianCalendar", TimeZoneInfo.Utc);
var dateTimeLocal = new DateTime(1998, 1, 15);
var dateTimeLocalString = dateTimeLocal.ToShortDateString();
var target = container.Resolve<IDateLocalizationServices>();
var result = target.ConvertFromLocalizedDateString(dateTimeLocalString);
Assert.AreEqual(DateTimeKind.Utc, result.Value.Kind);
}
[Test] [Test]
[Description("Converting to Gregorian calendar yields a DateTimeParts instance equivalent to the original DateTime.")] [Description("Converting to Gregorian calendar yields a DateTimeParts instance equivalent to the original DateTime.")]
public void ConvertToSiteCalendarTest01() { public void ConvertToSiteCalendarTest01() {

View File

@@ -59,7 +59,7 @@
<ul class="menu-items-zone"> <ul class="menu-items-zone">
@foreach (var descriptor in Model.MenuItemDescriptors.OrderBy(x => x.DisplayName)) { @foreach (var descriptor in Model.MenuItemDescriptors.OrderBy(x => x.DisplayName)) {
<li> <li>
<div class="menu-item-description"><h2>@T(descriptor.DisplayName.CamelFriendly())</h2> <div class="menu-item-description"><h2>@T(descriptor.DisplayName)</h2>
@if (!string.IsNullOrWhiteSpace(descriptor.Description)) { @if (!string.IsNullOrWhiteSpace(descriptor.Description)) {
<span class="hint">@T(descriptor.Description)</span> <span class="hint">@T(descriptor.Description)</span>
} }

View File

@@ -2,8 +2,8 @@
namespace Orchard.Layouts.Helpers { namespace Orchard.Layouts.Helpers {
public static class MetaDataExtensions { public static class MetaDataExtensions {
public static ContentPartDefinitionBuilder Placable(this ContentPartDefinitionBuilder builder, bool placable = true) { public static ContentPartDefinitionBuilder Placeable(this ContentPartDefinitionBuilder builder, bool placeable = true) {
return builder.WithSetting("ContentPartLayoutSettings.Placable", placable.ToString()); return builder.WithSetting("ContentPartLayoutSettings.Placeable", placeable.ToString());
} }
} }
} }

View File

@@ -45,10 +45,10 @@ namespace Orchard.Layouts {
.WithSetting("Stereotype", "Widget") .WithSetting("Stereotype", "Widget")
.DisplayedAs("Layout Widget")); .DisplayedAs("Layout Widget"));
ContentDefinitionManager.AlterPartDefinition("BodyPart", part => part.Placable()); ContentDefinitionManager.AlterPartDefinition("BodyPart", part => part.Placeable());
ContentDefinitionManager.AlterPartDefinition("TitlePart", part => part.Placable()); ContentDefinitionManager.AlterPartDefinition("TitlePart", part => part.Placeable());
ContentDefinitionManager.AlterPartDefinition("CommonPart", part => part.Placable()); ContentDefinitionManager.AlterPartDefinition("CommonPart", part => part.Placeable());
ContentDefinitionManager.AlterPartDefinition("TagsPart", part => part.Placable()); ContentDefinitionManager.AlterPartDefinition("TagsPart", part => part.Placeable());
ContentDefinitionManager.AlterPartDefinition("ElementWrapperPart", part => part ContentDefinitionManager.AlterPartDefinition("ElementWrapperPart", part => part
.Attachable() .Attachable()

View File

@@ -57,7 +57,7 @@ namespace Orchard.Layouts.Providers {
? contentTypeDefinition.Parts.Select(x => x.PartDefinition) ? contentTypeDefinition.Parts.Select(x => x.PartDefinition)
: _contentDefinitionManager.Value.ListPartDefinitions(); : _contentDefinitionManager.Value.ListPartDefinitions();
return parts.Where(p => p.Settings.GetModel<ContentPartLayoutSettings>().Placable); return parts.Where(p => p.Settings.GetModel<ContentPartLayoutSettings>().Placeable);
} }
private void Displaying(ElementDisplayingContext context) { private void Displaying(ElementDisplayingContext context) {

View File

@@ -1,7 +1,7 @@
(function ($) { (function ($) {
var placable = $("input[name=\"ContentPartLayoutSettings.Placable\"]"); var placeable = $("input[name=\"ContentPartLayoutSettings.Placeable\"]");
$(placable).on("change", function (e) { $(placeable).on("change", function (e) {
syncEnableEditorInput(); syncEnableEditorInput();
}); });
@@ -11,9 +11,9 @@
var syncEnableEditorInput = function () { var syncEnableEditorInput = function () {
var enableEditorDialog = $("input[name=\"ContentPartLayoutSettings.EnableEditorDialog\"]"); var enableEditorDialog = $("input[name=\"ContentPartLayoutSettings.EnableEditorDialog\"]");
var isPlacable = placable.is(":checked"); var isPlaceable = placeable.is(":checked");
enableEditorDialog.prop("disabled", !isPlacable); enableEditorDialog.prop("disabled", !isPlaceable);
}; };
})(jQuery); })(jQuery);

View File

@@ -68,7 +68,21 @@ namespace Orchard.Layouts.Services {
} }
private IEnumerable<IContentPartDriver> GetPartDrivers(string partName) { private IEnumerable<IContentPartDriver> GetPartDrivers(string partName) {
return _contentPartDrivers.Where(x => x.GetType().BaseType.GenericTypeArguments[0].Name == partName); return _contentPartDrivers.Where(x => GetPartOfDriver(x.GetType().BaseType).Name == partName);
}
private Type GetPartOfDriver(Type type) {
var baseType = type;
while (baseType != null && typeof(IContentPartDriver).IsAssignableFrom(baseType)) {
if (baseType.GenericTypeArguments.Any()) {
return baseType.GenericTypeArguments[0];
}
baseType = baseType.BaseType;
}
return null;
} }
} }
} }

View File

@@ -1,8 +1,8 @@
namespace Orchard.Layouts.Settings { namespace Orchard.Layouts.Settings {
public class ContentPartLayoutSettings { public class ContentPartLayoutSettings {
/// <summary> /// <summary>
/// This setting is used to configure a part to be placable on a layout. /// This setting is used to configure a part to be placeable on a layout.
/// </summary> /// </summary>
public bool Placable { get; set; } public bool Placeable { get; set; }
} }
} }

View File

@@ -17,7 +17,7 @@ namespace Orchard.Layouts.Settings {
public override IEnumerable<TemplateViewModel> PartEditorUpdate(ContentPartDefinitionBuilder builder, IUpdateModel updateModel) { public override IEnumerable<TemplateViewModel> PartEditorUpdate(ContentPartDefinitionBuilder builder, IUpdateModel updateModel) {
var model = new ContentPartLayoutSettings(); var model = new ContentPartLayoutSettings();
updateModel.TryUpdateModel(model, "ContentPartLayoutSettings", null, null); updateModel.TryUpdateModel(model, "ContentPartLayoutSettings", null, null);
builder.Placable(model.Placable); builder.Placeable(model.Placeable);
yield return DefinitionTemplate(model); yield return DefinitionTemplate(model);
} }
} }

View File

@@ -4,7 +4,7 @@
Script.Include("contentpart-layouts-settings.js"); Script.Include("contentpart-layouts-settings.js");
} }
<fieldset> <fieldset>
@Html.CheckBoxFor(m => m.Placable) @Html.CheckBoxFor(m => m.Placeable)
<label for="@Html.FieldIdFor(m => m.Placable)" class="forcheckbox">@T("Placable")</label> <label for="@Html.FieldIdFor(m => m.Placeable)" class="forcheckbox">@T("Placeable")</label>
<span class="hint">@T("Check to allow this part to be placable on a layout.")</span> <span class="hint">@T("Check to allow this part to be placeable on a layout.")</span>
</fieldset> </fieldset>

View File

@@ -4,7 +4,7 @@
@{ @{
Style.Include("admin-projections.css"); Style.Include("admin-projections.css");
Layout.Title = T("Manage Queries").ToString();
var index = 0; var index = 0;
var pageSizes = new List<int?>() { 10, 50, 100 }; var pageSizes = new List<int?>() { 10, 50, 100 };

View File

@@ -7,14 +7,11 @@ using Orchard.Recipes.Models;
namespace Orchard.Recipes.Services { namespace Orchard.Recipes.Services {
public class RecipeParser : Component, IRecipeParser { public class RecipeParser : Component, IRecipeParser {
public Recipe ParseRecipe(XDocument recipeDocument) {
return ParseRecipe(recipeDocument.ToString(SaveOptions.DisableFormatting));
}
public Recipe ParseRecipe(string recipeText) { public Recipe ParseRecipe(string recipeText) {
var recipe = new Recipe(); var recipe = new Recipe();
if (String.IsNullOrEmpty(recipeText)) { if (string.IsNullOrEmpty(recipeText)) {
throw new Exception("Recipe is empty"); throw new Exception("Recipe is empty");
} }
@@ -22,7 +19,7 @@ namespace Orchard.Recipes.Services {
var recipeSteps = new List<RecipeStep>(); var recipeSteps = new List<RecipeStep>();
foreach (var element in recipeTree.Elements()) { foreach (var element in recipeTree.Elements()) {
// Recipe metadata // Recipe metadata.
if (element.Name.LocalName == "Recipe") { if (element.Name.LocalName == "Recipe") {
foreach (var metadataElement in element.Elements()) { foreach (var metadataElement in element.Elements()) {
switch (metadataElement.Name.LocalName) { switch (metadataElement.Name.LocalName) {
@@ -47,6 +44,9 @@ namespace Orchard.Recipes.Services {
case "ExportUtc": case "ExportUtc":
recipe.ExportUtc = !string.IsNullOrEmpty(metadataElement.Value) ? (DateTime?)XmlConvert.ToDateTime(metadataElement.Value, XmlDateTimeSerializationMode.Utc) : null; recipe.ExportUtc = !string.IsNullOrEmpty(metadataElement.Value) ? (DateTime?)XmlConvert.ToDateTime(metadataElement.Value, XmlDateTimeSerializationMode.Utc) : null;
break; break;
case "Category":
recipe.Category = metadataElement.Value;
break;
case "Tags": case "Tags":
recipe.Tags = metadataElement.Value; recipe.Tags = metadataElement.Value;
break; break;
@@ -56,7 +56,7 @@ namespace Orchard.Recipes.Services {
} }
} }
} }
// Recipe step // Recipe step.
else { else {
var recipeStep = new RecipeStep { Name = element.Name.LocalName, Step = element }; var recipeStep = new RecipeStep { Name = element.Name.LocalName, Step = element };
recipeSteps.Add(recipeStep); recipeSteps.Add(recipeStep);

View File

@@ -1,11 +1,9 @@
using System; using System;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Web.Mvc; using System.Web.Mvc;
using Orchard.Environment; using Orchard.Environment;
using Orchard.Environment.Configuration; using Orchard.Environment.Configuration;
using Orchard.Logging; using Orchard.Logging;
using Orchard.Recipes.Models;
using Orchard.Setup.Services; using Orchard.Setup.Services;
using Orchard.Setup.ViewModels; using Orchard.Setup.ViewModels;
using Orchard.Localization; using Orchard.Localization;
@@ -44,7 +42,7 @@ namespace Orchard.Setup.Controllers {
public ActionResult Index() { public ActionResult Index() {
var initialSettings = _setupService.Prime(); var initialSettings = _setupService.Prime();
var recipes = OrderRecipes(_setupService.Recipes()); var recipes = _setupService.Recipes().ToList();
string recipeDescription = null; string recipeDescription = null;
if (recipes.Count > 0) { if (recipes.Count > 0) {
recipeDescription = recipes[0].Description; recipeDescription = recipes[0].Description;
@@ -54,13 +52,11 @@ namespace Orchard.Setup.Controllers {
// will take a while to finish (user inputting data and the setup process itself). // will take a while to finish (user inputting data and the setup process itself).
// We use this opportunity to start a background task to "pre-compile" all the known // We use this opportunity to start a background task to "pre-compile" all the known
// views in the app folder, so that the application is more reponsive when the user // views in the app folder, so that the application is more reponsive when the user
// hits the homepage and admin screens for the first time.)) // hits the homepage and admin screens for the first time).
if (StringComparer.OrdinalIgnoreCase.Equals(initialSettings.Name, ShellSettings.DefaultName)) { if (StringComparer.OrdinalIgnoreCase.Equals(initialSettings.Name, ShellSettings.DefaultName)) {
_viewsBackgroundCompilation.Start(); _viewsBackgroundCompilation.Start();
} }
//
return IndexViewResult(new SetupViewModel { return IndexViewResult(new SetupViewModel {
AdminUsername = "admin", AdminUsername = "admin",
DatabaseIsPreconfigured = !string.IsNullOrEmpty(initialSettings.DataProvider), DatabaseIsPreconfigured = !string.IsNullOrEmpty(initialSettings.DataProvider),
@@ -71,32 +67,32 @@ namespace Orchard.Setup.Controllers {
[HttpPost, ActionName("Index")] [HttpPost, ActionName("Index")]
public ActionResult IndexPOST(SetupViewModel model) { public ActionResult IndexPOST(SetupViewModel model) {
// sets the setup request timeout to 10 minutes to give enough time to execute custom recipes. // Sets the setup request timeout to 10 minutes to give enough time to execute custom recipes.
HttpContext.Server.ScriptTimeout = 600; HttpContext.Server.ScriptTimeout = 600;
var recipes = OrderRecipes(_setupService.Recipes()); var recipes = _setupService.Recipes().ToList();
// if no builtin provider, a connection string is mandatory // If no builtin provider, a connection string is mandatory.
if (model.DatabaseProvider != SetupDatabaseType.Builtin && string.IsNullOrEmpty(model.DatabaseConnectionString)) if (model.DatabaseProvider != SetupDatabaseType.Builtin && string.IsNullOrEmpty(model.DatabaseConnectionString))
ModelState.AddModelError("DatabaseConnectionString", T("A connection string is required").Text); ModelState.AddModelError("DatabaseConnectionString", T("A connection string is required.").Text);
if (!String.IsNullOrWhiteSpace(model.ConfirmPassword) && model.AdminPassword != model.ConfirmPassword ) { if (!string.IsNullOrWhiteSpace(model.ConfirmPassword) && model.AdminPassword != model.ConfirmPassword ) {
ModelState.AddModelError("ConfirmPassword", T("Password confirmation must match").Text); ModelState.AddModelError("ConfirmPassword", T("Password confirmation must match.").Text);
} }
if (model.DatabaseProvider != SetupDatabaseType.Builtin && !String.IsNullOrWhiteSpace(model.DatabaseTablePrefix)) { if (model.DatabaseProvider != SetupDatabaseType.Builtin && !string.IsNullOrWhiteSpace(model.DatabaseTablePrefix)) {
model.DatabaseTablePrefix = model.DatabaseTablePrefix.Trim(); model.DatabaseTablePrefix = model.DatabaseTablePrefix.Trim();
if(!Char.IsLetter(model.DatabaseTablePrefix[0])) { if(!char.IsLetter(model.DatabaseTablePrefix[0])) {
ModelState.AddModelError("DatabaseTablePrefix", T("The table prefix must begin with a letter").Text); ModelState.AddModelError("DatabaseTablePrefix", T("The table prefix must begin with a letter.").Text);
} }
if(model.DatabaseTablePrefix.Any(x => !Char.IsLetterOrDigit(x))) { if(model.DatabaseTablePrefix.Any(x => !Char.IsLetterOrDigit(x))) {
ModelState.AddModelError("DatabaseTablePrefix", T("The table prefix must contain letters or digits").Text); ModelState.AddModelError("DatabaseTablePrefix", T("The table prefix must contain letters or digits.").Text);
} }
} }
if (model.Recipe == null) { if (model.Recipe == null) {
if (!(recipes.Select(r => r.Name).Contains(DefaultRecipe))) { if (!(recipes.Select(r => r.Name).Contains(DefaultRecipe))) {
ModelState.AddModelError("Recipe", T("No recipes were found in the Setup module").Text); ModelState.AddModelError("Recipe", T("No recipes were found.").Text);
} }
else { else {
model.Recipe = DefaultRecipe; model.Recipe = DefaultRecipe;
@@ -155,7 +151,7 @@ namespace Orchard.Setup.Controllers {
// uses a "single lock" mechanism for compiling views). // uses a "single lock" mechanism for compiling views).
_viewsBackgroundCompilation.Stop(); _viewsBackgroundCompilation.Stop();
// redirect to the welcome page. // Redirect to the welcome page.
return Redirect("~/" + _shellSettings.RequestUrlPrefix); return Redirect("~/" + _shellSettings.RequestUrlPrefix);
} catch (Exception ex) { } catch (Exception ex) {
Logger.Error(ex, "Setup failed"); Logger.Error(ex, "Setup failed");
@@ -170,19 +166,5 @@ namespace Orchard.Setup.Controllers {
return IndexViewResult(model); return IndexViewResult(model);
} }
} }
private static List<Recipe> OrderRecipes(IEnumerable<Recipe> recipes) {
var recipeList = new List<Recipe>();
var tempList = new List<Recipe>();
foreach (var recipe in recipes) {
if (recipe.Name == DefaultRecipe) {
recipeList.Add(recipe);
}
else {
tempList.Add(recipe);
}
}
return recipeList.Concat(tempList).ToList();
}
} }
} }

View File

@@ -5,6 +5,7 @@
<Description>A recipe providing the features you need for a personal blog site.</Description> <Description>A recipe providing the features you need for a personal blog site.</Description>
<Author>The Orchard Team</Author> <Author>The Orchard Team</Author>
<WebSite>http://orchardproject.net</WebSite> <WebSite>http://orchardproject.net</WebSite>
<Category>Default</Category>
<Tags>blog</Tags> <Tags>blog</Tags>
<Version>1.0</Version> <Version>1.0</Version>
<IsSetupRecipe>true</IsSetupRecipe> <IsSetupRecipe>true</IsSetupRecipe>
@@ -19,7 +20,7 @@
Orchard.Taxonomies,Orchard.Workflows, Orchard.Taxonomies,Orchard.Workflows,
TheThemeMachine" /> TheThemeMachine" />
<ContentSchema> <ContentDefinition>
<Types> <Types>
<Page ContentTypeSettings.Draftable="True" TypeIndexing.Indexes="Search"> <Page ContentTypeSettings.Draftable="True" TypeIndexing.Indexes="Search">
<TitlePart/> <TitlePart/>
@@ -39,7 +40,7 @@
<Parts> <Parts>
<BodyPart BodyPartSettings.FlavorDefault="html" /> <BodyPart BodyPartSettings.FlavorDefault="html" />
</Parts> </Parts>
</ContentSchema> </ContentDefinition>
<Settings> <Settings>
<SiteSettingsPart PageSize="20" PageTitleSeparator = " - " /> <SiteSettingsPart PageSize="20" PageTitleSeparator = " - " />

View File

@@ -5,6 +5,7 @@
<Description>A recipe providing only the core Orchard framework, with limited end-user functionality. This is useful for development scenarios.</Description> <Description>A recipe providing only the core Orchard framework, with limited end-user functionality. This is useful for development scenarios.</Description>
<Author>The Orchard Team</Author> <Author>The Orchard Team</Author>
<WebSite>http://orchardproject.net</WebSite> <WebSite>http://orchardproject.net</WebSite>
<Category>Default</Category>
<Tags>developer</Tags> <Tags>developer</Tags>
<Version>1.0</Version> <Version>1.0</Version>
<IsSetupRecipe>true</IsSetupRecipe> <IsSetupRecipe>true</IsSetupRecipe>
@@ -13,7 +14,7 @@
<Feature disable="Feeds, Containers" <Feature disable="Feeds, Containers"
enable="Orchard.jQuery,Orchard.Alias,Orchard.Autoroute" /> enable="Orchard.jQuery,Orchard.Alias,Orchard.Autoroute" />
<ContentSchema> <ContentDefinition>
<Types> <Types>
<Page ContentTypeSettings.Draftable="True"> <Page ContentTypeSettings.Draftable="True">
<BodyPart /> <BodyPart />
@@ -22,7 +23,7 @@
<Parts> <Parts>
<BodyPart BodyPartSettings.FlavorDefault="html" /> <BodyPart BodyPartSettings.FlavorDefault="html" />
</Parts> </Parts>
</ContentSchema> </ContentDefinition>
<Settings /> <Settings />

View File

@@ -5,6 +5,7 @@
<Description>The default recipe for an Orchard site that includes pages, blogs, custom content types, comments, tags, widgets and basic navigation.</Description> <Description>The default recipe for an Orchard site that includes pages, blogs, custom content types, comments, tags, widgets and basic navigation.</Description>
<Author>The Orchard Team</Author> <Author>The Orchard Team</Author>
<WebSite>http://orchardproject.net</WebSite> <WebSite>http://orchardproject.net</WebSite>
<Category>Default</Category>
<Tags></Tags> <Tags></Tags>
<Version>1.0</Version> <Version>1.0</Version>
<IsSetupRecipe>true</IsSetupRecipe> <IsSetupRecipe>true</IsSetupRecipe>
@@ -18,7 +19,7 @@
Orchard.Layouts,Orchard.Layouts.Tokens, Orchard.Layouts,Orchard.Layouts.Tokens,
TheThemeMachine" /> TheThemeMachine" />
<ContentSchema> <ContentDefinition>
<Types> <Types>
<Page ContentTypeSettings.Draftable="True" TypeIndexing.Indexes="Search"> <Page ContentTypeSettings.Draftable="True" TypeIndexing.Indexes="Search">
<TagsPart /> <TagsPart />
@@ -38,7 +39,7 @@
<Parts> <Parts>
<BodyPart BodyPartSettings.FlavorDefault="html" /> <BodyPart BodyPartSettings.FlavorDefault="html" />
</Parts> </Parts>
</ContentSchema> </ContentDefinition>
<Settings /> <Settings />

View File

@@ -4,6 +4,10 @@
Script.Require("ShapesBase"); Script.Require("ShapesBase");
Script.Include("setup.js"); Script.Include("setup.js");
} }
@{
var groupedRecipes = Model.Recipes.Where(x => !String.IsNullOrWhiteSpace(x.Category)).GroupBy(x => x.Category);
var unspecifiedCategoryRecipes = Model.Recipes.Where(x => String.IsNullOrWhiteSpace(x.Category)).ToList();
}
<h1>@Html.TitleForPage(T("Get Started").ToString())</h1> <h1>@Html.TitleForPage(T("Get Started").ToString())</h1>
@using (Html.BeginFormAntiForgeryPost()) { @using (Html.BeginFormAntiForgeryPost()) {
@@ -30,7 +34,7 @@
if (!Model.DatabaseIsPreconfigured) { if (!Model.DatabaseIsPreconfigured) {
<fieldset class="data"> <fieldset class="data">
<legend>@T("How would you like to store your data?")</legend> <legend>@T("How would you like to store your data?")</legend>
@Html.ValidationMessage("DatabaseOptions", "Unable to setup data storage") @Html.ValidationMessage("DatabaseOptions", "Unable to setup data storage.")
<div> <div>
@Html.RadioButtonFor(svm => svm.DatabaseProvider, Orchard.Setup.Controllers.SetupDatabaseType.Builtin.ToString(), new { id = "builtin" }) @Html.RadioButtonFor(svm => svm.DatabaseProvider, Orchard.Setup.Controllers.SetupDatabaseType.Builtin.ToString(), new { id = "builtin" })
<label for="builtin" class="forcheckbox">@T("Use built-in data storage (SQL Server Compact)")</label> <label for="builtin" class="forcheckbox">@T("Use built-in data storage (SQL Server Compact)")</label>
@@ -72,12 +76,25 @@ if (!Model.DatabaseIsPreconfigured) {
} }
<fieldset> <fieldset>
<legend>@T("Choose an Orchard Recipe")</legend> <legend>@T("Choose an Orchard Recipe")</legend>
<div>@T("Orchard Recipes allow you to setup your site with additional pre-configured options, features and settings out of the box")</div> <div>@T("Orchard Recipes allow you to setup your site with additional pre-configured options, features and settings out of the box.")</div>
<div> <div>
<select id="@Html.FieldIdFor(m => m.Recipe)" name="@Html.FieldNameFor(m => m.Recipe)" class="recipe"> <select id="@Html.FieldIdFor(m => m.Recipe)" name="@Html.FieldNameFor(m => m.Recipe)" class="recipe">
@foreach(var recipe in Model.Recipes) { @foreach(var recipeGroup in groupedRecipes.OrderBy(x => x.Key)) {
if (groupedRecipes.Count() > 1) {
<optgroup label="@recipeGroup.Key"></optgroup>
}
foreach (var recipe in recipeGroup.OrderBy(x => x.Name)) {
@Html.SelectOption(Model.Recipe, recipe.Name, recipe.Name, new { recipedescription = recipe.Description }) @Html.SelectOption(Model.Recipe, recipe.Name, recipe.Name, new { recipedescription = recipe.Description })
} }
}
@if (unspecifiedCategoryRecipes.Any()) {
if (groupedRecipes.Any()) {
<optgroup label="@T("Unspecified")"></optgroup>
}
foreach (var recipe in unspecifiedCategoryRecipes.OrderBy(x => x.Name)) {
@Html.SelectOption(Model.Recipe, recipe.Name, recipe.Name, new { recipedescription = recipe.Description })
}
}
</select> </select>
</div> </div>
<div id="recipedescription">@Model.RecipeDescription</div> <div id="recipedescription">@Model.RecipeDescription</div>

View File

@@ -30,7 +30,7 @@
var selectedTerms = Newtonsoft.Json.JsonConvert.SerializeObject(Model.Terms.Where(x => x.IsChecked).Select(x => new { label = x.Name, value = x.Id, levels = 0, disabled = true })); var selectedTerms = Newtonsoft.Json.JsonConvert.SerializeObject(Model.Terms.Where(x => x.IsChecked).Select(x => new { label = x.Name, value = x.Id, levels = 0, disabled = true }));
} }
<fieldset class="taxonomy-wrapper" data-name-prefix="@Html.FieldNameFor(m => m)" data-id-prefix="@Html.FieldIdFor(m => m)"> <fieldset class="taxonomy-wrapper" data-name-prefix="@Html.FieldNameFor(m => m)" data-id-prefix="@Html.FieldIdFor(m => m)">
<legend @if (Model.Settings.Required) { <text> class="required" </text> }>@Model.DisplayName.CamelFriendly()</legend> <legend @if(Model.Settings.Required) { <text>class="required"</text> }>@Model.DisplayName</legend>
@if (Model.Settings.Autocomplete) { @if (Model.Settings.Autocomplete) {
<div class="terms-editor" data-all-terms="@allTerms" data-selected-terms="@selectedTerms" data-allow-new-terms="@Model.Settings.AllowCustomTerms.ToString().ToLower()" data-singlechoice="@Model.Settings.SingleChoice.ToString().ToLower()"> <div class="terms-editor" data-all-terms="@allTerms" data-selected-terms="@selectedTerms" data-allow-new-terms="@Model.Settings.AllowCustomTerms.ToString().ToLower()" data-singlechoice="@Model.Settings.SingleChoice.ToString().ToLower()">
<ul></ul> <ul></ul>
@@ -69,7 +69,7 @@
@if (!Model.Terms.Any()) { @if (!Model.Terms.Any()) {
<div class="no-terms"> <div class="no-terms">
@T("There are no terms defined for {0} yet.", Model.DisplayName.CamelFriendly()) @T("There are no terms defined for {0} yet.", Model.DisplayName)
<a href="@Url.Action("Index", "TermAdmin", new { taxonomyId = Model.TaxonomyId, area = "Orchard.Taxonomies" })">@T("Create some terms")</a> <a href="@Url.Action("Index", "TermAdmin", new { taxonomyId = Model.TaxonomyId, area = "Orchard.Taxonomies" })">@T("Create some terms")</a>
</div> </div>
} }

View File

@@ -14,7 +14,7 @@
} }
<fieldset class="taxonomy-wrapper" data-name-prefix="@Html.FieldNameFor(m => m)" data-id-prefix="@Html.FieldIdFor(m => m)"> <fieldset class="taxonomy-wrapper" data-name-prefix="@Html.FieldNameFor(m => m)" data-id-prefix="@Html.FieldIdFor(m => m)">
<legend @if (settings.Required) { <text> class="required" </text> }>@Model.DisplayName.CamelFriendly()</legend> <legend @if(settings.Required) { <text>class="required"</text> }>@Model.DisplayName</legend>
<div class="expando"> <div class="expando">
@if (!String.IsNullOrWhiteSpace(Model.Settings.Hint)) { @if (!String.IsNullOrWhiteSpace(Model.Settings.Hint)) {
@@ -44,7 +44,7 @@
@if (!Model.Terms.Any()) { @if (!Model.Terms.Any()) {
<div class="no-terms"> <div class="no-terms">
@T("There are no terms defined for {0} yet.", Model.DisplayName.CamelFriendly()) @T("There are no terms defined for {0} yet.", Model.DisplayName)
<a href="@Url.Action("Index", "TermAdmin", new { taxonomyId = Model.TaxonomyId, area = "Orchard.Taxonomies" })">@T("Create some terms")</a> <a href="@Url.Action("Index", "TermAdmin", new { taxonomyId = Model.TaxonomyId, area = "Orchard.Taxonomies" })">@T("Create some terms")</a>
</div> </div>
} }

View File

@@ -110,10 +110,18 @@ namespace Orchard.DisplayManagement.Descriptors.ShapePlacementStrategy {
private void GetShapeType(PlacementShapeLocation shapeLocation, out string shapeType, out string differentiator) { private void GetShapeType(PlacementShapeLocation shapeLocation, out string shapeType, out string differentiator) {
differentiator = ""; differentiator = "";
shapeType = shapeLocation.ShapeType; shapeType = shapeLocation.ShapeType;
var separatorLengh = 2;
var separatorIndex = shapeType.LastIndexOf("__");
var dashIndex = shapeType.LastIndexOf('-'); var dashIndex = shapeType.LastIndexOf('-');
if (dashIndex > 0 && dashIndex < shapeType.Length - 1) { if (dashIndex > separatorIndex) {
differentiator = shapeType.Substring(dashIndex + 1); separatorIndex = dashIndex;
shapeType = shapeType.Substring(0, dashIndex); separatorLengh = 1;
}
if (separatorIndex > 0 && separatorIndex < shapeType.Length - separatorLengh) {
differentiator = shapeType.Substring(separatorIndex + separatorLengh);
shapeType = shapeType.Substring(0, separatorIndex);
} }
} }

View File

@@ -1,8 +1,4 @@
using System; using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Orchard.Localization.Models { namespace Orchard.Localization.Models {
public class DateLocalizationOptions { public class DateLocalizationOptions {

View File

@@ -1,9 +1,7 @@
using System; using System;
using System.Globalization; using System.Globalization;
using Orchard.ContentManagement;
using Orchard.Localization.Models; using Orchard.Localization.Models;
using Orchard.Services; using Orchard.Services;
using Orchard.Settings;
namespace Orchard.Localization.Services { namespace Orchard.Localization.Services {
@@ -218,6 +216,9 @@ namespace Orchard.Localization.Services {
} }
} }
if (options.EnableTimeZoneConversion)
dateValue = DateTime.SpecifyKind(dateValue, DateTimeKind.Utc);
return dateValue; return dateValue;
} }

View File

@@ -10,6 +10,7 @@ namespace Orchard.Recipes.Models {
public string Version { get; set; } public string Version { get; set; }
public bool IsSetupRecipe { get; set; } public bool IsSetupRecipe { get; set; }
public DateTime? ExportUtc { get; set; } public DateTime? ExportUtc { get; set; }
public string Category { get; set; }
public string Tags { get; set; } public string Tags { get; set; }
public IEnumerable<RecipeStep> RecipeSteps { get; set; } public IEnumerable<RecipeStep> RecipeSteps { get; set; }
} }