Skip to content

Commit 6ebfff6

Browse files
committed
Implemented support for @import directives in inherited LESS theme files (to EXPLICITLY import a base theme's file)
1 parent 9d19a6d commit 6ebfff6

6 files changed

Lines changed: 75 additions & 16 deletions

File tree

src/Presentation/SmartStore.Web.Framework/Themes/ThemeFileResolver.cs

Lines changed: 53 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -128,9 +128,22 @@ public InheritedThemeFileResult Resolve(string virtualPath)
128128
return null;
129129
}
130130

131+
bool isExplicit = false;
132+
131133
string requestedThemeName;
132134
string relativePath;
133-
TokenizePath(virtualPath, out requestedThemeName, out relativePath);
135+
string query;
136+
137+
virtualPath = TokenizePath(virtualPath, out requestedThemeName, out relativePath, out query);
138+
139+
Func<InheritedThemeFileResult> nullOrFile = () =>
140+
{
141+
if (isExplicit)
142+
{
143+
return new InheritedThemeFileResult { IsExplicit = true, OriginalVirtualPath = virtualPath };
144+
}
145+
return null;
146+
};
134147

135148
ThemeManifest currentTheme;
136149
var isAdmin = EngineContext.Current.Resolve<IWorkContext>().IsAdmin; // ThemeHelper.IsAdminArea()
@@ -141,7 +154,7 @@ public InheritedThemeFileResult Resolve(string virtualPath)
141154
else
142155
{
143156
bool isLess = false;
144-
if (ThemeHelper.IsStyleSheet(virtualPath, out isLess))
157+
if (ThemeHelper.IsStyleSheet(relativePath, out isLess) && isLess)
145158
{
146159
// special consideration for LESS files: they can be validated
147160
// in the backend. For validation, a "theme" query is appended
@@ -157,21 +170,36 @@ public InheritedThemeFileResult Resolve(string virtualPath)
157170
}
158171
}
159172
}
160-
161-
currentTheme = ThemeHelper.ResolveCurrentTheme();
173+
174+
if (isLess && query != null && query.StartsWith("explicit", StringComparison.OrdinalIgnoreCase))
175+
{
176+
// special case to support LESS @import declarations
177+
// within inherited LESS files. Snenario: an inheritor wishes to
178+
// include the same file from it's base theme (e.g. custom.less) just to tweak it
179+
// a bit for his child theme. Without the 'explicit' query the resolution starting point
180+
// for custom.less would be the CURRENT theme's folder, and NOT the requested one's,
181+
// which inevitably would result in a cyclic dependency.
182+
currentTheme = _themeRegistry.GetThemeManifest(requestedThemeName);
183+
isExplicit = true;
184+
}
185+
else
186+
{
187+
currentTheme = ThemeHelper.ResolveCurrentTheme();
188+
}
189+
162190
if (currentTheme.BaseTheme == null)
163191
{
164192
// dont't bother resolving files: the current theme is not inherited.
165193
// Let the current VPP do the work.
166-
return null;
194+
return nullOrFile();
167195
}
168196
}
169197

170198
if (!currentTheme.ThemeName.Equals(requestedThemeName, StringComparison.OrdinalIgnoreCase))
171199
{
172200
if (!_themeRegistry.IsChildThemeOf(currentTheme.ThemeName, requestedThemeName))
173201
{
174-
return null;
202+
return nullOrFile();
175203
}
176204
}
177205

@@ -200,17 +228,33 @@ public InheritedThemeFileResult Resolve(string virtualPath)
200228
return null;
201229
});
202230

231+
if (result == null)
232+
{
233+
return nullOrFile();
234+
}
235+
203236
return result;
204237
}
205238

206-
private void TokenizePath(string virtualPath, out string themeName, out string relativePath)
239+
private string TokenizePath(string virtualPath, out string themeName, out string relativePath, out string query)
207240
{
208241
themeName = null;
209242
relativePath = null;
243+
query = null;
210244

211245
var unrooted = virtualPath.Substring(ThemeHelper.ThemesBasePath.Length); // strip "~/Themes/"
212246
themeName = unrooted.Substring(0, unrooted.IndexOf('/'));
213247
relativePath = unrooted.Substring(themeName.Length + 1);
248+
249+
var idx = relativePath.IndexOf('?');
250+
if (idx > 0)
251+
{
252+
query = relativePath.Substring(idx + 1);
253+
relativePath = relativePath.Substring(0, idx);
254+
}
255+
256+
// strip out query
257+
return "{0}{1}/{2}".FormatCurrent(ThemeHelper.ThemesBasePath, themeName, relativePath);
214258
}
215259

216260
/// <summary>
@@ -293,6 +337,8 @@ public class InheritedThemeFileResult
293337
/// The name of the resulting theme where the file is actually located
294338
/// </summary>
295339
public string ResultThemeName { get; set; }
340+
341+
internal bool IsExplicit { get; set; }
296342
}
297343

298344
}

src/Presentation/SmartStore.Web.Framework/Themes/ThemeHelper.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,12 +72,12 @@ internal static bool IsAdminArea()
7272
return false;
7373
}
7474

75-
internal static bool IsStyleSheet(string virtualPath, out bool isLess)
75+
internal static bool IsStyleSheet(string path, out bool isLess)
7676
{
7777
bool isCss = false;
78-
isLess = virtualPath.EndsWith(".less", StringComparison.OrdinalIgnoreCase);
78+
isLess = path.EndsWith(".less", StringComparison.OrdinalIgnoreCase);
7979
if (!isLess)
80-
isCss = virtualPath.EndsWith(".css", StringComparison.OrdinalIgnoreCase);
80+
isCss = path.EndsWith(".css", StringComparison.OrdinalIgnoreCase);
8181
return isLess || isCss;
8282
}
8383

src/Presentation/SmartStore.Web.Framework/Themes/ThemingVirtualPathProvider.cs

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,14 @@ public override bool FileExists(string virtualPath)
2929
var result = GetResolveResult(virtualPath);
3030
if (result != null)
3131
{
32-
return true;
32+
if (!result.IsExplicit)
33+
{
34+
return true;
35+
}
36+
else
37+
{
38+
virtualPath = result.OriginalVirtualPath;
39+
}
3340
}
3441

3542
return _previous.FileExists(virtualPath);
@@ -47,7 +54,14 @@ public override VirtualFile GetFile(string virtualPath)
4754
var result = GetResolveResult(virtualPath);
4855
if (result != null)
4956
{
50-
return new InheritedVirtualThemeFile(result);
57+
if (!result.IsExplicit)
58+
{
59+
return new InheritedVirtualThemeFile(result);
60+
}
61+
else
62+
{
63+
virtualPath = result.OriginalVirtualPath;
64+
}
5165
}
5266

5367
return _previous.GetFile(virtualPath);
@@ -116,7 +130,7 @@ private string[] MapDependencyPaths(IEnumerable<string> virtualPathDependencies)
116130
var result = GetResolveResult(dep);
117131
if (result != null)
118132
{
119-
fileNames.Add(result.ResultPhysicalPath);
133+
fileNames.Add(result.IsExplicit ? HostingEnvironment.MapPath(result.OriginalVirtualPath) : result.ResultPhysicalPath);
120134
}
121135
else
122136
{

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2246,6 +2246,7 @@
22462246
<Content Include="Themes\Alpha\Content\shopbar.less" />
22472247
<Content Include="Themes\Alpha\Content\skin.less" />
22482248
<Content Include="Themes\Alpha\Content\typo.less" />
2249+
<Content Include="Themes\AlphaBlack\Content\custom.less" />
22492250
</ItemGroup>
22502251
<ItemGroup>
22512252
<Folder Include="Scripts\select2\" />

src/Presentation/SmartStore.Web/Themes/Alpha/Content/custom.less

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,3 @@
33
// or new selectors (for theme developers))
44
// --------------------------------------------------
55

6-

src/Presentation/SmartStore.Web/Themes/AlphaBlack/Content/custom.less

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
// or new selectors
44
// --------------------------------------------------
55

6-
76
.block.block-bordered .block-title a {
87
color: #fff;
9-
}
8+
}

0 commit comments

Comments
 (0)