Skip to content

Commit fcaadec

Browse files
committed
Adding local video support to products (wip)
1 parent e71a50f commit fcaadec

26 files changed

Lines changed: 507 additions & 390 deletions

File tree

src/Libraries/SmartStore.Core/Utilities/CommonHelper.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,7 @@ public static ExpandoObject ToExpando(object value)
261261
public static IDictionary<string, object> ObjectToDictionary(object obj)
262262
{
263263
if (obj == null)
264-
throw new ArgumentNullException(nameof(obj));
264+
return new Dictionary<string, object>();
265265

266266
return FastProperty.ObjectToDictionary(
267267
obj,

src/Libraries/SmartStore.Services/Media/MediaFileInfo.cs

Lines changed: 90 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
using System;
2+
using System.Collections.Generic;
23
using System.Drawing;
4+
using System.Globalization;
35
using System.IO;
6+
using System.Runtime.CompilerServices;
47
using System.Threading.Tasks;
58
using Newtonsoft.Json;
69
using SmartStore.Core.Domain.Media;
@@ -10,10 +13,10 @@
1013

1114
namespace SmartStore.Services.Media
1215
{
13-
public partial class MediaFileInfo : IFile
16+
public partial class MediaFileInfo : IFile, ICloneable<MediaFileInfo>
1417
{
15-
private string _url;
16-
private string _thumbUrl;
18+
private string _alt;
19+
private string _title;
1720

1821
private readonly IMediaStorageProvider _storageProvider;
1922
private readonly IMediaUrlGenerator _urlGenerator;
@@ -32,6 +35,29 @@ public MediaFileInfo(MediaFile file, IMediaStorageProvider storageProvider, IMed
3235
_urlGenerator = urlGenerator;
3336
}
3437

38+
#region Clone
39+
40+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
41+
object ICloneable.Clone()
42+
{
43+
return Clone();
44+
}
45+
46+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
47+
public MediaFileInfo Clone()
48+
{
49+
var clone = new MediaFileInfo(File, _storageProvider, _urlGenerator, Directory)
50+
{
51+
ThumbSize = this.ThumbSize,
52+
_alt = this._alt,
53+
_title = this._title
54+
};
55+
56+
return clone;
57+
}
58+
59+
#endregion
60+
3561
[JsonIgnore]
3662
public MediaFile File { get; }
3763

@@ -59,8 +85,69 @@ public MediaFileInfo(MediaFile file, IMediaStorageProvider storageProvider, IMed
5985
[JsonProperty("createdOn")]
6086
public DateTime CreatedOn => File.CreatedOnUtc;
6187

88+
[JsonProperty("alt")]
89+
public string Alt
90+
{
91+
get => _alt ?? File.Alt;
92+
set => _alt = value;
93+
}
94+
95+
[JsonProperty("titleAttr")]
96+
public string TitleAttribute
97+
{
98+
get => _title ?? File.Title;
99+
set => _title = value;
100+
}
101+
62102
public static explicit operator MediaFile(MediaFileInfo fileInfo) => fileInfo.File;
63103

104+
#region Url
105+
106+
private readonly IDictionary<(int size, string host), string> _cachedUrls = new Dictionary<(int, string), string>();
107+
108+
[JsonProperty("url")]
109+
internal string Url
110+
{
111+
// For serialization in MediaManager
112+
get => GetUrl(0, string.Empty);
113+
}
114+
115+
[JsonProperty("thumbUrl")]
116+
internal string ThumbUrl
117+
{
118+
// For serialization in MediaManager
119+
get => GetUrl(ThumbSize, string.Empty);
120+
}
121+
122+
[JsonIgnore]
123+
internal int ThumbSize
124+
{
125+
// For serialization of "ThumbUrl" in MediaManager
126+
get; set;
127+
} = 256;
128+
129+
public string GetUrl(int maxSize = 0, string host = null)
130+
{
131+
var cacheKey = (maxSize, host);
132+
if (!_cachedUrls.TryGetValue(cacheKey, out var url))
133+
{
134+
url = _urlGenerator.GenerateUrl(this, null, host, false);
135+
136+
if (maxSize > 0)
137+
{
138+
// (perf) Instead of calling GenerateUrl() with a processing query we simply
139+
// append the query part to the string.
140+
url += "?size=" + maxSize.ToString(CultureInfo.InvariantCulture);
141+
}
142+
143+
_cachedUrls[cacheKey] = url;
144+
}
145+
146+
return url;
147+
}
148+
149+
#endregion
150+
64151
#region IFile
65152

66153
[JsonProperty("path")]
@@ -72,9 +159,6 @@ public MediaFileInfo(MediaFile file, IMediaStorageProvider storageProvider, IMed
72159
[JsonProperty("name")]
73160
public string Name => File.Name;
74161

75-
[JsonProperty("alt")]
76-
public string Alt => File.Alt;
77-
78162
[JsonProperty("title")]
79163
public string Title => System.IO.Path.GetFileNameWithoutExtension(File.Name);
80164

@@ -90,23 +174,6 @@ public MediaFileInfo(MediaFile file, IMediaStorageProvider storageProvider, IMed
90174
[JsonProperty("dimensions")]
91175
public Size Dimensions { get; }
92176

93-
[JsonProperty("url")]
94-
public string Url
95-
{
96-
get { return _url ?? (_url = _urlGenerator.GenerateUrl(this, null, string.Empty)); }
97-
set { _url = value; }
98-
}
99-
100-
[JsonProperty("thumbUrl")]
101-
public string ThumbUrl
102-
{
103-
get { return _thumbUrl ?? (_thumbUrl = _urlGenerator.GenerateUrl(this, new ProcessImageQuery { MaxSize = ThumbSize }, string.Empty)); }
104-
set { _thumbUrl = value; }
105-
}
106-
107-
[JsonIgnore]
108-
public int ThumbSize { get; set; } = 256;
109-
110177
[JsonIgnore]
111178
public bool Exists => File?.Id > 0;
112179

src/Libraries/SmartStore.Services/Media/MediaService.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -892,11 +892,13 @@ public string GetUrl(MediaFileInfo file, ProcessImageQuery imageQuery, string ho
892892

893893
#region Utils
894894

895+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
895896
public MediaFileInfo ConvertMediaFile(MediaFile file)
896897
{
897898
return ConvertMediaFile(file, _folderService.FindNode(file)?.Value);
898899
}
899900

901+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
900902
protected MediaFileInfo ConvertMediaFile(MediaFile file, MediaFolderNode folder)
901903
{
902904
var mediaFile = new MediaFileInfo(file, _storageProvider, _urlGenerator, folder?.Path)

src/Presentation/SmartStore.Web.Framework/Extensions/HtmlExtensions.cs

Lines changed: 59 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
using SmartStore.Core.Domain.Catalog;
1616
using SmartStore.Core.Domain.Localization;
1717
using SmartStore.Core.Infrastructure;
18+
using SmartStore.Core.Localization;
1819
using SmartStore.Services.Localization;
1920
using SmartStore.Services.Media;
2021
using SmartStore.Utilities;
@@ -930,61 +931,77 @@ public static MvcHtmlString IconForFileExtension(this HtmlHelper helper, string
930931
return MvcHtmlString.Create(result);
931932
}
932933

933-
#region Media
934+
#region Media
934935

935-
public static MvcHtmlString MediaThumbnail(
936-
this HtmlHelper helper,
937-
MediaFileInfo file,
938-
int size,
939-
string extraCssClasses = null)
940-
{
941-
return MediaInternal(helper, file, false, size, extraCssClasses);
942-
}
936+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
937+
public static MvcHtmlString MediaViewer(this HtmlHelper helper, MediaFileInfo file, object htmlAttributes = null)
938+
{
939+
return MediaInternal(helper, file, true, 0, CommonHelper.ObjectToDictionary(htmlAttributes));
940+
}
943941

944-
public static MvcHtmlString MediaViewer(
945-
this HtmlHelper helper,
946-
MediaFileInfo file,
947-
string extraCssClasses = null)
942+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
943+
public static MvcHtmlString MediaViewer(this HtmlHelper helper, MediaFileInfo file, IDictionary<string, object> htmlAttributes)
944+
{
945+
return MediaInternal(helper, file, true, 0, htmlAttributes);
946+
}
947+
948+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
949+
public static MvcHtmlString MediaThumbnail(this HtmlHelper helper, MediaFileInfo file, int size, object htmlAttributes = null)
948950
{
949-
return MediaInternal(helper, file, true, 0, extraCssClasses);
951+
return MediaInternal(helper, file, false, size, CommonHelper.ObjectToDictionary(htmlAttributes));
950952
}
951953

952-
private static MvcHtmlString MediaInternal(
953-
this HtmlHelper helper,
954-
MediaFileInfo file,
955-
bool renderViewer,
956-
int size,
957-
string extraCssClasses)
958-
{
959-
if (file?.File == null)
960-
{
961-
return MvcHtmlString.Empty;
962-
}
954+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
955+
public static MvcHtmlString MediaThumbnail(this HtmlHelper helper, MediaFileInfo file, int size, IDictionary<string, object> htmlAttributes)
956+
{
957+
return MediaInternal(helper, file, false, size, htmlAttributes);
958+
}
963959

964-
// Validate size parameter.
965-
if (file.MediaType != "image" && !renderViewer)
966-
{
967-
Guard.IsPositive(size, nameof(size), $"The size must be greater than 0 to get a thumbnail for type '{file.MediaType.NaIfEmpty()}'.");
968-
}
960+
private static MvcHtmlString MediaInternal(
961+
HtmlHelper helper,
962+
MediaFileInfo file,
963+
bool renderViewer,
964+
int size,
965+
IDictionary<string, object> htmlAttributes)
966+
{
967+
if (file?.File == null)
968+
{
969+
return MvcHtmlString.Empty;
970+
}
969971

970-
if (size > 0)
971-
{
972-
file.ThumbSize = size;
973-
}
972+
// Validate size parameter.
973+
if (file.MediaType != "image" && !renderViewer)
974+
{
975+
Guard.IsPositive(size, nameof(size), $"The size must be greater than 0 to get a thumbnail for type '{file.MediaType.NaIfEmpty()}'.");
976+
}
974977

975978
var f = file?.File;
976979

977980
var model = new MediaTemplateModel(file, renderViewer)
978-
{
979-
ExtraCssClasses = extraCssClasses,
980-
Title = f?.GetLocalized(x => x.Title),
981-
Alt = f?.GetLocalized(x => x.Alt)
981+
{
982+
ThumbSize = size,
983+
HtmlAttributes = htmlAttributes
982984
};
983985

984-
return helper.Partial("MediaTemplates/" + file.MediaType, model);
985-
}
986+
if (htmlAttributes.TryGetValue("alt", out var alt))
987+
{
988+
htmlAttributes.Remove("alt");
989+
}
986990

987-
#endregion
988-
}
991+
if (htmlAttributes.TryGetValue("title", out var title))
992+
{
993+
htmlAttributes.Remove("title");
994+
}
995+
996+
//alt != null ? (string)alt : f?.GetLocalized(x => x.Alt).Value
997+
998+
model.Alt = (string)(alt ?? f?.GetLocalized(x => x.Alt).Value);
999+
model.Title = (string)(title ?? f?.GetLocalized(x => x.Title).Value);
1000+
1001+
return helper.Partial("MediaTemplates/" + file.MediaType, model);
1002+
}
1003+
1004+
#endregion
1005+
}
9891006
}
9901007

src/Presentation/SmartStore.Web.Framework/Modelling/MediaTemplateModel.cs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
using SmartStore.Services.Localization;
1+
using System.Collections.Generic;
2+
using System.Web.Routing;
3+
using SmartStore.Services.Localization;
24
using SmartStore.Services.Media;
35

46
namespace SmartStore.Web.Framework.Modelling
@@ -17,9 +19,10 @@ public MediaTemplateModel(MediaFileInfo file, bool renderViewer)
1719
public MediaFileInfo File { get; private set; }
1820
public bool RenderViewer { get; private set; }
1921

20-
public string ExtraCssClasses { get; set; }
22+
public int ThumbSize { get; set; } = 256;
23+
public IDictionary<string, object> HtmlAttributes { get; set; }
2124

22-
public LocalizedValue<string> Title { get; set; }
23-
public LocalizedValue<string> Alt { get; set; }
25+
public string Title { get; set; }
26+
public string Alt { get; set; }
2427
}
2528
}

src/Presentation/SmartStore.Web/Administration/Models/Catalog/ProductModel.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -462,7 +462,7 @@ public class ProductPictureModel : EntityModelBase
462462
{
463463
public int ProductId { get; set; }
464464

465-
[UIHint("Media"), AdditionalMetadata("album", "catalog")]
465+
[UIHint("Media"), AdditionalMetadata("album", "catalog"), AdditionalMetadata("typeFilter", "image,video")]
466466
[SmartResourceDisplayName("Admin.Catalog.Products.Pictures.Fields.Picture")]
467467
public int PictureId { get; set; }
468468

src/Presentation/SmartStore.Web/Content/shared/_media.scss

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
display: inline-block;
3333
}
3434

35-
&[data-type=video]:before {
35+
&.show[data-type=video]:before {
3636
position: absolute;
3737
display: block;
3838
content: '';
@@ -44,7 +44,7 @@
4444
z-index: 1;
4545
}
4646

47-
&[data-type=video]:after {
47+
&.show[data-type=video]:after {
4848
@include fontawesome("\f04b", 1rem, solid); // fas fa-play
4949
position: absolute;
5050
left: 50%;

0 commit comments

Comments
 (0)