Skip to content

Commit db7140d

Browse files
committed
Theming engine handles SASS files now: ThemeVars, ModuleImports (new!) etc.
1 parent 0233437 commit db7140d

17 files changed

Lines changed: 334 additions & 108 deletions

File tree

changelog.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
* (Dev) log4net integration
1515
* (Dev) proper plugin view debugging
1616
* (Dev) changes to static plugin files (css, js, etc.) immediately apply to running project
17+
* (Dev) Theming: plugins now support implicitly imported SASS files (Content/[public|admin].scss)
1718
* XML Sitemap optimized for very large catalogs:
1819
* Partitions for very large sitemaps (> 50.000 nodes or > 10 MB)
1920
* Generated in a background task. No instant invalidation anymore.

src/Libraries/SmartStore.Core/Plugins/PluginManager.cs

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,6 @@ namespace SmartStore.Core.Plugins
3333
/// </summary>
3434
public class PluginManager
3535
{
36-
#region Fields
37-
3836
private static readonly ReaderWriterLockSlim Locker = new ReaderWriterLockSlim();
3937
private static DirectoryInfo _shadowCopyFolder;
4038
//private static readonly string _installedPluginsFilePath = CommonHelper.MapPath("~/App_Data/InstalledPlugins.txt");
@@ -44,9 +42,13 @@ public class PluginManager
4442
private static readonly ConcurrentDictionary<string, PluginDescriptor> _referencedPlugins = new ConcurrentDictionary<string, PluginDescriptor>(StringComparer.OrdinalIgnoreCase);
4543
private static HashSet<Assembly> _inactiveAssemblies = new HashSet<Assembly>();
4644

47-
#endregion
48-
49-
#region Methods
45+
/// <summary>
46+
/// Returns the virtual path of the plugins folder relative to the application
47+
/// </summary>
48+
public static string PluginsLocation
49+
{
50+
get { return _pluginsPath; }
51+
}
5052

5153
/// <summary>
5254
/// Returns a collection of all referenced plugin assemblies that have been shadow copied
@@ -462,10 +464,6 @@ public static bool IsActivePluginAssembly(Assembly assembly)
462464
return !_inactiveAssemblies.Contains(assembly);
463465
}
464466

465-
#endregion
466-
467-
#region Utilities
468-
469467
private static void SetPrivateEnvPath()
470468
{
471469
string dir = Environment.Is64BitProcess ? "amd64" : "x86";
@@ -646,7 +644,5 @@ private static bool IsPackagePluginFolder(DirectoryInfo folder)
646644
if (!folder.Parent.Name.Equals("Plugins", StringComparison.InvariantCultureIgnoreCase)) return false;
647645
return true;
648646
}
649-
650-
#endregion
651647
}
652648
}

src/Libraries/SmartStore.Core/WebHelper.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ public partial class WebHelper : IWebHelper
2525
private static object s_lock = new object();
2626
private static bool? s_optimizedCompilationsEnabled;
2727
private static AspNetHostingPermissionLevel? s_trustLevel;
28-
private static readonly Regex s_staticExts = new Regex(@"(.*?)\.(css|js|png|jpg|jpeg|gif|bmp|html|htm|xml|pdf|doc|xls|rar|zip|ico|eot|svg|ttf|woff|otf|axd|ashx|less)", RegexOptions.Compiled | RegexOptions.IgnoreCase);
28+
private static readonly Regex s_staticExts = new Regex(@"(.*?)\.(css|js|png|jpg|jpeg|gif|scss|less|bmp|html|htm|xml|pdf|doc|xls|rar|zip|ico|eot|svg|ttf|woff|otf|axd|ashx)", RegexOptions.Compiled | RegexOptions.IgnoreCase);
2929
private static readonly Regex s_htmlPathPattern = new Regex(@"(?<=(?:href|src)=(?:""|'))(?!https?://)(?<url>[^(?:""|')]+)", RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.Multiline);
3030
private static readonly Regex s_cssPathPattern = new Regex(@"url\('(?<url>.+)'\)", RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.Multiline);
3131
private static ConcurrentDictionary<int, string> s_safeLocalHostNames = new ConcurrentDictionary<int, string>();

src/Libraries/SmartStore.Services/Catalog/IProductAttributeParser.cs

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -57,12 +57,19 @@ public partial interface IProductAttributeParser
5757
/// <returns>Attributes</returns>
5858
string AddProductAttribute(string attributesXml, ProductVariantAttribute pva, string value);
5959

60-
/// <summary>
61-
/// Are attributes equal
62-
/// </summary>
63-
/// <param name="attributeXml1">The attributes of the first product</param>
64-
/// <param name="attributeXml2">The attributes of the second product</param>
65-
/// <returns>Result</returns>
60+
/// <summary>
61+
/// Creates formatted xml for a list of product variant attribute values
62+
/// </summary>
63+
/// <param name="attributes">The attributes map</param>
64+
/// <returns>Attributes XML</returns>
65+
string CreateAttributesXml(Multimap<int, string> attributes);
66+
67+
/// <summary>
68+
/// Are attributes equal
69+
/// </summary>
70+
/// <param name="attributeXml1">The attributes of the first product</param>
71+
/// <param name="attributeXml2">The attributes of the second product</param>
72+
/// <returns>Result</returns>
6673
bool AreProductAttributesEqual(string attributeXml1, string attributeXml2);
6774

6875
/// <summary>

src/Libraries/SmartStore.Services/Catalog/ProductAttributeParser.cs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,32 @@ public virtual string AddProductAttribute(string attributesXml, ProductVariantAt
220220
return pva.AddProductAttribute(attributesXml, value);
221221
}
222222

223+
public virtual string CreateAttributesXml(Multimap<int, string> attributes)
224+
{
225+
Guard.NotNull(attributes, nameof(attributes));
226+
227+
if (attributes.Count == 0)
228+
return null;
229+
230+
var doc = new XmlDocument();
231+
var root = doc.AppendChild(doc.CreateElement("Attributes"));
232+
233+
foreach (var attr in attributes)
234+
{
235+
var xelAttr = root.AppendChild(doc.CreateElement("ProductVariantAttribute")) as XmlElement;
236+
xelAttr.SetAttribute("ID", attr.Key.ToString());
237+
238+
foreach (var val in attr.Value)
239+
{
240+
var xelAttrValue = xelAttr.AppendChild(doc.CreateElement("ProductVariantAttributeValue"));
241+
var xelValue = xelAttrValue.AppendChild(doc.CreateElement("Value"));
242+
xelValue.InnerText = val;
243+
}
244+
}
245+
246+
return doc.OuterXml;
247+
}
248+
223249
public virtual bool AreProductAttributesEqual(string attributeXml1, string attributeXml2)
224250
{
225251
if (attributeXml1.IsCaseInsensitiveEqual(attributeXml2))

src/Plugins/SmartStore.FacebookAuth/Content/facebookstyles.css renamed to src/Plugins/SmartStore.FacebookAuth/Content/public.scss

File renamed without changes.

src/Plugins/SmartStore.FacebookAuth/SmartStore.FacebookAuth.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -209,9 +209,9 @@
209209
</ProjectReference>
210210
</ItemGroup>
211211
<ItemGroup>
212-
<Content Include="Content\facebookstyles.css">
212+
<None Include="Content\public.scss">
213213
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
214-
</Content>
214+
</None>
215215
<Content Include="Description.txt">
216216
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
217217
</Content>

src/Plugins/SmartStore.FacebookAuth/Views/ExternalAuthFacebook/PublicInfo.cshtml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
@using SmartStore.Web.Framework.UI
22
@{
3-
Layout = "";
4-
Html.AddCssFileParts(true, "~/Plugins/SmartStore.FacebookAuth/Content/facebookstyles.css");
3+
Layout = "";
54
}
65

76
<a class="btn btn-primary btn-extauth btn-facebook btn-block" href="@Url.RouteUrl("SmartStore.FacebookAuth", new { ReturnUrl = HttpContext.Current.Request.QueryString["ReturnUrl"], action = "Login" })">

src/Presentation/SmartStore.Web.Framework/SmartStore.Web.Framework.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,7 @@
275275
<Compile Include="Theming\HttpHandlers\CssHttpHandlerBase.cs" />
276276
<Compile Include="Theming\HttpHandlers\SassCssHttpHandler.cs" />
277277
<Compile Include="Theming\LocalizedDisplayMode.cs" />
278+
<Compile Include="Theming\ModuleImportsVirtualFile.cs" />
278279
<Compile Include="Theming\ThemeFileResolver.cs" />
279280
<Compile Include="Theming\InheritedVirtualThemeFile.cs" />
280281
<Compile Include="Theming\TwoLevelViewLocationCache.cs" />
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
using System.Collections.Generic;
2+
using System.IO;
3+
using System.Text;
4+
using System.Linq;
5+
using System.Web.Hosting;
6+
using SmartStore.Core.Plugins;
7+
8+
namespace SmartStore.Web.Framework.Theming
9+
{
10+
public class ModuleImportsVirtualFile : VirtualFile
11+
{
12+
private static readonly HashSet<string> _adminImports;
13+
private static readonly HashSet<string> _publicImports;
14+
15+
static ModuleImportsVirtualFile()
16+
{
17+
_adminImports = new HashSet<string>();
18+
_publicImports = new HashSet<string>();
19+
20+
CollectModuleImports();
21+
}
22+
23+
private static void CollectModuleImports()
24+
{
25+
var installedPlugins = PluginManager.ReferencedPlugins.Where(x => x.Installed);
26+
var root = PluginManager.PluginsLocation;
27+
28+
foreach (var plugin in installedPlugins)
29+
{
30+
var contentDir = Path.Combine(plugin.PhysicalPath, "Content");
31+
if (!Directory.Exists(contentDir))
32+
continue;
33+
34+
if (File.Exists(Path.Combine(contentDir, "public.scss")))
35+
{
36+
_publicImports.Add($"{root}/{plugin.FolderName}/Content/public.scss");
37+
}
38+
39+
if (File.Exists(Path.Combine(contentDir, "admin.scss")))
40+
{
41+
_adminImports.Add($"{root}/{plugin.FolderName}/Content/admin.scss");
42+
}
43+
}
44+
}
45+
46+
private readonly bool _isAdmin;
47+
48+
public ModuleImportsVirtualFile(string virtualPath, bool isAdmin)
49+
: base(virtualPath)
50+
{
51+
_isAdmin = isAdmin;
52+
}
53+
54+
public override bool IsDirectory
55+
{
56+
get { return false; }
57+
}
58+
59+
public override Stream Open()
60+
{
61+
var sb = new StringBuilder();
62+
63+
var imports = _isAdmin ? _adminImports : _publicImports;
64+
foreach (var imp in imports)
65+
{
66+
sb.AppendLine($"@import '{imp}';");
67+
}
68+
69+
return GenerateStreamFromString(sb.ToString());
70+
}
71+
72+
private Stream GenerateStreamFromString(string value)
73+
{
74+
var stream = new MemoryStream();
75+
76+
using (var writer = new StreamWriter(stream, Encoding.Unicode, 1024, true))
77+
{
78+
writer.Write(value);
79+
writer.Flush();
80+
stream.Seek(0, SeekOrigin.Begin);
81+
return stream;
82+
}
83+
}
84+
85+
}
86+
}

0 commit comments

Comments
 (0)