mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2025-08-20 10:06:07 +08:00
Merge remote-tracking branch 'remotes/origin/1.10.x' into 8565_DeleteUnpublishButtons
This commit is contained in:
commit
681986e8b1
@ -8,4 +8,8 @@ namespace Orchard.Caching.Services {
|
||||
void Remove(string key);
|
||||
void Clear();
|
||||
}
|
||||
|
||||
public interface ICacheStorageProviderWithKeyPrefix : ICacheStorageProvider {
|
||||
void Clear(string key);
|
||||
}
|
||||
}
|
||||
@ -4,41 +4,46 @@ using Orchard.ContentManagement.Handlers;
|
||||
using Orchard.Fields.Fields;
|
||||
using Orchard.Fields.Settings;
|
||||
using Orchard.Localization;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Orchard.Fields.Drivers {
|
||||
public class EnumerationFieldDriver : ContentFieldDriver<EnumerationField> {
|
||||
public IOrchardServices Services { get; set; }
|
||||
|
||||
private const string TemplateName = "Fields/Enumeration.Edit";
|
||||
|
||||
public EnumerationFieldDriver(IOrchardServices services) {
|
||||
Services = services;
|
||||
|
||||
T = NullLocalizer.Instance;
|
||||
}
|
||||
|
||||
public Localizer T { get; set; }
|
||||
|
||||
private static string GetPrefix(ContentField field, ContentPart part) =>
|
||||
part.PartDefinition.Name + "." + field.Name;
|
||||
private static string GetPrefix(ContentField field, ContentPart part) {
|
||||
return part.PartDefinition.Name + "." + field.Name;
|
||||
}
|
||||
|
||||
private static string GetDifferentiator(EnumerationField field) => field.Name;
|
||||
private static string GetDifferentiator(EnumerationField field, ContentPart part) {
|
||||
return field.Name;
|
||||
}
|
||||
|
||||
protected override DriverResult Display(ContentPart part, EnumerationField field, string displayType, dynamic shapeHelper) {
|
||||
return ContentShape("Fields_Enumeration", GetDifferentiator(field), () => shapeHelper.Fields_Enumeration());
|
||||
return ContentShape("Fields_Enumeration", GetDifferentiator(field, part),
|
||||
() => shapeHelper.Fields_Enumeration());
|
||||
}
|
||||
|
||||
protected override DriverResult Editor(ContentPart part, EnumerationField field, dynamic shapeHelper) {
|
||||
return ContentShape("Fields_Enumeration_Edit", GetDifferentiator(field), () => {
|
||||
if (part.IsNew() && string.IsNullOrEmpty(field.Value)) {
|
||||
var settings = field.PartFieldDefinition.Settings.GetModel<EnumerationFieldSettings>();
|
||||
if (!string.IsNullOrWhiteSpace(settings.DefaultValue)) {
|
||||
field.SelectedValues = new string[] { settings.DefaultValue };
|
||||
return ContentShape("Fields_Enumeration_Edit", GetDifferentiator(field, part),
|
||||
() => {
|
||||
if (part.IsNew() && String.IsNullOrEmpty(field.Value)) {
|
||||
var settings = field.PartFieldDefinition.Settings.GetModel<EnumerationFieldSettings>();
|
||||
if (!String.IsNullOrWhiteSpace(settings.DefaultValue)) {
|
||||
field.Value = settings.DefaultValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return shapeHelper.EditorTemplate(TemplateName: TemplateName, Model: field, Prefix: GetPrefix(field, part));
|
||||
});
|
||||
return shapeHelper.EditorTemplate(TemplateName: TemplateName, Model: field, Prefix: GetPrefix(field, part));
|
||||
});
|
||||
}
|
||||
|
||||
protected override DriverResult Editor(ContentPart part, EnumerationField field, IUpdateModel updater, dynamic shapeHelper) {
|
||||
|
||||
@ -7,16 +7,28 @@ namespace Orchard.Fields.Fields {
|
||||
private const char Separator = ';';
|
||||
|
||||
public string Value {
|
||||
get => Storage.Get<string>()?.Trim(Separator) ?? "";
|
||||
set => Storage.Set(string.IsNullOrWhiteSpace(value)
|
||||
? string.Empty
|
||||
// It is now the responsibility of this field to (re-)add the separators.
|
||||
: Separator + value.Trim(Separator) + Separator);
|
||||
get { return Storage.Get<string>(); }
|
||||
set { Storage.Set(value ?? String.Empty); }
|
||||
}
|
||||
|
||||
public string[] SelectedValues {
|
||||
get => Value?.Split(new[] { Separator }, StringSplitOptions.RemoveEmptyEntries) ?? new string[0];
|
||||
set => Value = value?.Length > 0 ? string.Join(Separator.ToString(), value) : "";
|
||||
get {
|
||||
var value = Value;
|
||||
if(string.IsNullOrWhiteSpace(value)) {
|
||||
return new string[0];
|
||||
}
|
||||
|
||||
return value.Split(new [] { Separator }, StringSplitOptions.RemoveEmptyEntries);
|
||||
}
|
||||
|
||||
set {
|
||||
if (value == null || value.Length == 0) {
|
||||
Value = String.Empty;
|
||||
}
|
||||
else {
|
||||
Value = Separator + string.Join(Separator.ToString(), value) + Separator;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -169,10 +169,6 @@
|
||||
<Compile Include="ViewModels\NumericFieldViewModel.cs" />
|
||||
<Compile Include="ViewModels\DateTimeFieldViewModel.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="Controllers\" />
|
||||
<Folder Include="Models\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="Views\Fields\Input.cshtml" />
|
||||
</ItemGroup>
|
||||
@ -223,4 +219,4 @@
|
||||
</FlavorProperties>
|
||||
</VisualStudio>
|
||||
</ProjectExtensions>
|
||||
</Project>
|
||||
</Project>
|
||||
@ -4,30 +4,48 @@
|
||||
|
||||
@{
|
||||
var settings = Model.PartFieldDefinition.Settings.GetModel<EnumerationFieldSettings>();
|
||||
string[] options = (!String.IsNullOrWhiteSpace(settings.Options)) ? settings.Options.Split(new string[] { System.Environment.NewLine }, StringSplitOptions.None) : new string[] { T("Select an option").ToString() };
|
||||
string[] options = (!String.IsNullOrWhiteSpace(settings.Options)) ?
|
||||
settings.Options.Split(new string[] { System.Environment.NewLine }, StringSplitOptions.None)
|
||||
: new string[] { T("Select an option").ToString() };
|
||||
}
|
||||
|
||||
<fieldset>
|
||||
<label for="@Html.FieldIdFor(m => m.Value)" @if (settings.Required) { <text> class="required" </text> }>@Model.DisplayName</label>
|
||||
@switch (settings.ListMode) {
|
||||
case ListMode.Dropdown:
|
||||
@Html.DropDownListFor(m => m.Value, new SelectList(options, Model.SelectedValues.FirstOrDefault()), settings.Required ? new { required = "required" } : null)
|
||||
@Html.DropDownListFor(
|
||||
m => m.Value,
|
||||
new SelectList(options, Model.SelectedValues.FirstOrDefault()),
|
||||
settings.Required ? new { required = "required" } : null)
|
||||
break;
|
||||
|
||||
case ListMode.Radiobutton:
|
||||
foreach (var option in options) {
|
||||
if (string.IsNullOrWhiteSpace(option)) {
|
||||
<label>@Html.RadioButton("Value", "", string.IsNullOrWhiteSpace(Model.SelectedValues.FirstOrDefault()), settings.Required ? new { required = "required" } : null)<i>@T("unset")</i></label>
|
||||
<label>@Html.RadioButton(
|
||||
"Value",
|
||||
"",
|
||||
string.IsNullOrWhiteSpace(Model.SelectedValues.FirstOrDefault()),
|
||||
settings.Required ? new { required = "required" } : null)<i>@T("unset")</i>
|
||||
</label>
|
||||
}
|
||||
else {
|
||||
<label>@Html.RadioButton("Value", option, (option == Model.SelectedValues.FirstOrDefault()), settings.Required ? new { required = "required" } : null)@option</label>
|
||||
<label>@Html.RadioButton(
|
||||
"Value",
|
||||
option,
|
||||
option == Model.SelectedValues.FirstOrDefault(),
|
||||
settings.Required ? new { required = "required" } : null)@option
|
||||
</label>
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case ListMode.Listbox:
|
||||
<input name="@Html.FieldNameFor(m => m.SelectedValues)" type="hidden" />
|
||||
@Html.ListBoxFor(m => m.SelectedValues, new MultiSelectList(options, Model.SelectedValues), settings.Required ? new { required = "required" } : null)
|
||||
@Html.ListBoxFor(
|
||||
m => m.SelectedValues,
|
||||
new MultiSelectList(options, Model.SelectedValues),
|
||||
settings.Required ? new { required = "required" } : null)
|
||||
break;
|
||||
|
||||
case ListMode.Checkbox:
|
||||
@ -37,7 +55,9 @@
|
||||
index++;
|
||||
if (!string.IsNullOrWhiteSpace(option)) {
|
||||
<div>
|
||||
<input type="checkbox" name="@Html.FieldNameFor(m => m.SelectedValues)" value="@option" @((Model.SelectedValues != null && Model.SelectedValues.Contains(option)) ? "checked=\"checked\"" : "") class="check-box" id="@Html.FieldIdFor(m => m.SelectedValues)-@index" />
|
||||
<input type="checkbox" name="@Html.FieldNameFor(m => m.SelectedValues)" value="@option"
|
||||
@((Model.SelectedValues != null && Model.SelectedValues.Contains(option)) ? "checked=\"checked\"" : "")
|
||||
class="check-box" id="@Html.FieldIdFor(m => m.SelectedValues)-@index" />
|
||||
<label class="forcheckbox" for="@Html.FieldIdFor(m => m.SelectedValues)-@index">@option</label>
|
||||
</div>
|
||||
}
|
||||
|
||||
@ -17,12 +17,16 @@ namespace Orchard.MediaLibrary.Controllers {
|
||||
[Admin, Themed(false)]
|
||||
public class OEmbedController : Controller {
|
||||
private readonly IMediaLibraryService _mediaLibraryService;
|
||||
private readonly IOEmbedService _oEmbedService;
|
||||
|
||||
public OEmbedController(
|
||||
IOrchardServices services,
|
||||
IMediaLibraryService mediaManagerService) {
|
||||
_mediaLibraryService = mediaManagerService;
|
||||
IMediaLibraryService mediaManagerService,
|
||||
IOEmbedService oEmbedService) {
|
||||
|
||||
Services = services;
|
||||
_mediaLibraryService = mediaManagerService;
|
||||
_oEmbedService = oEmbedService;
|
||||
T = NullLocalizer.Instance;
|
||||
}
|
||||
|
||||
@ -78,39 +82,9 @@ namespace Orchard.MediaLibrary.Controllers {
|
||||
}
|
||||
}
|
||||
|
||||
var webClient = new WebClient { Encoding = Encoding.UTF8 };
|
||||
try {
|
||||
// <link rel="alternate" href="http://vimeo.com/api/oembed.xml?url=http%3A%2F%2Fvimeo.com%2F23608259" type="text/xml+oembed">
|
||||
viewModel.Content = _oEmbedService.DownloadMediaData(url);
|
||||
|
||||
var source = webClient.DownloadString(url);
|
||||
|
||||
// seek type="text/xml+oembed" or application/xml+oembed
|
||||
var oembedSignature = source.IndexOf("type=\"text/xml+oembed\"", StringComparison.OrdinalIgnoreCase);
|
||||
if (oembedSignature == -1) {
|
||||
oembedSignature = source.IndexOf("type=\"application/xml+oembed\"", StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
if (oembedSignature != -1) {
|
||||
var tagStart = source.Substring(0, oembedSignature).LastIndexOf('<');
|
||||
var tagEnd = source.IndexOf('>', oembedSignature);
|
||||
var tag = source.Substring(tagStart, tagEnd - tagStart);
|
||||
var matches = new Regex("href=\"([^\"]+)\"").Matches(tag);
|
||||
if (matches.Count > 0) {
|
||||
var href = matches[0].Groups[1].Value;
|
||||
try {
|
||||
var content = webClient.DownloadString(Server.HtmlDecode(href));
|
||||
viewModel.Content = XDocument.Parse(content);
|
||||
}
|
||||
catch {
|
||||
// bubble exception
|
||||
}
|
||||
}
|
||||
}
|
||||
if (viewModel.Content == null) {
|
||||
viewModel.Content = new XDocument(
|
||||
new XDeclaration("1.0", "utf-8", "yes"),
|
||||
new XElement("oembed")
|
||||
);
|
||||
}
|
||||
var root = viewModel.Content.Root;
|
||||
if (!String.IsNullOrWhiteSpace(url)) {
|
||||
root.El("url", url);
|
||||
|
||||
@ -200,7 +200,9 @@
|
||||
<Compile Include="Security\MediaAuthorizationEventHandler.cs" />
|
||||
<Compile Include="Services\IMediaLibraryService.cs" />
|
||||
<Compile Include="Providers\IMediaFolderProvider.cs" />
|
||||
<Compile Include="Services\IOEmbedService.cs" />
|
||||
<Compile Include="Services\MediaLibraryService.cs" />
|
||||
<Compile Include="Services\OEmbedService.cs" />
|
||||
<Compile Include="Services\Shapes.cs" />
|
||||
<Compile Include="Services\XmlRpcHandler.cs" />
|
||||
<Compile Include="Settings\MediaLibraryPickerFieldEditorEvents.cs" />
|
||||
|
||||
@ -0,0 +1,7 @@
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Orchard.MediaLibrary.Services {
|
||||
public interface IOEmbedService : IDependency {
|
||||
XDocument DownloadMediaData(string url);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,51 @@
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Web;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Orchard.MediaLibrary.Services {
|
||||
public class OEmbedService : IOEmbedService {
|
||||
public XDocument DownloadMediaData(string url) {
|
||||
var webClient = new WebClient { Encoding = Encoding.UTF8 };
|
||||
XDocument doc = null;
|
||||
try {
|
||||
// <link rel="alternate" href="http://vimeo.com/api/oembed.xml?url=http%3A%2F%2Fvimeo.com%2F23608259" type="text/xml+oembed">
|
||||
var source = webClient.DownloadString(url);
|
||||
|
||||
// seek type="text/xml+oembed" or application/xml+oembed
|
||||
var oembedSignature = source.IndexOf("type=\"text/xml+oembed\"", StringComparison.OrdinalIgnoreCase);
|
||||
if (oembedSignature == -1) {
|
||||
oembedSignature = source.IndexOf("type=\"application/xml+oembed\"", StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
if (oembedSignature != -1) {
|
||||
var tagStart = source.Substring(0, oembedSignature).LastIndexOf('<');
|
||||
var tagEnd = source.IndexOf('>', oembedSignature);
|
||||
var tag = source.Substring(tagStart, tagEnd - tagStart);
|
||||
var matches = new Regex("href=\"([^\"]+)\"").Matches(tag);
|
||||
if (matches.Count > 0) {
|
||||
var href = matches[0].Groups[1].Value;
|
||||
try {
|
||||
var content = webClient.DownloadString(HttpUtility.HtmlDecode(href));
|
||||
doc = XDocument.Parse(content);
|
||||
} catch {
|
||||
// bubble exception
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
doc = null;
|
||||
}
|
||||
|
||||
if (doc == null) {
|
||||
doc = new XDocument(
|
||||
new XDeclaration("1.0", "utf-8", "yes"),
|
||||
new XElement("oembed")
|
||||
);
|
||||
}
|
||||
|
||||
return doc;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -9,10 +9,9 @@ using StackExchange.Redis;
|
||||
using System;
|
||||
|
||||
namespace Orchard.Redis.Caching {
|
||||
|
||||
[OrchardFeature("Orchard.Redis.Caching")]
|
||||
[OrchardSuppressDependency("Orchard.Caching.Services.DefaultCacheStorageProvider")]
|
||||
public class RedisCacheStorageProvider : Component, ICacheStorageProvider {
|
||||
public class RedisCacheStorageProvider : Component, ICacheStorageProviderWithKeyPrefix {
|
||||
public const string ConnectionStringKey = "Orchard.Redis.Cache";
|
||||
|
||||
private readonly ShellSettings _shellSettings;
|
||||
@ -61,6 +60,10 @@ namespace Orchard.Redis.Caching {
|
||||
_connectionMultiplexer.KeyDeleteWithPrefix(GetLocalizedKey("*"));
|
||||
}
|
||||
|
||||
public void Clear(string key) {
|
||||
_connectionMultiplexer.KeyDeleteWithPrefix(GetLocalizedKey($"{_shellSettings.Name}:{key}"));
|
||||
}
|
||||
|
||||
private string GetLocalizedKey(string key) {
|
||||
return _shellSettings.Name + ":Cache:" + key;
|
||||
}
|
||||
|
||||
16
src/Orchard/Data/Conventions/LazyLoadConvention.cs
Normal file
16
src/Orchard/Data/Conventions/LazyLoadConvention.cs
Normal file
@ -0,0 +1,16 @@
|
||||
using System;
|
||||
using FluentNHibernate.Conventions;
|
||||
using FluentNHibernate.Conventions.Instances;
|
||||
|
||||
namespace Orchard.Data.Conventions
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Property)]
|
||||
public class LazyLoadAttribute : Attribute {
|
||||
}
|
||||
|
||||
public class LazyLoadConvention : AttributePropertyConvention<LazyLoadAttribute> {
|
||||
protected override void Apply(LazyLoadAttribute attribute, IPropertyInstance instance) {
|
||||
instance.LazyLoad();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -147,6 +147,7 @@
|
||||
<ItemGroup>
|
||||
<Compile Include="ContentManagement\Extensions\DriverResultExtensions.cs" />
|
||||
<Compile Include="ContentManagement\Handlers\CloneContentContext.cs" />
|
||||
<Compile Include="Data\Conventions\LazyLoadConvention.cs" />
|
||||
<Compile Include="Data\MapAsRecordAttribute.cs" />
|
||||
<Compile Include="Data\Migration\Interpreters\PostgreSqlCommandInterpreter.cs" />
|
||||
<Compile Include="DisplayManagement\Descriptors\ShapePlacementStrategy\DefaultPlacementParseMatchProviders.cs" />
|
||||
|
||||
Loading…
Reference in New Issue
Block a user