public override bool FileExists(string virtualPath) { return(ThemeHelper.PathIsThemeVars(virtualPath) || _previous.FileExists(virtualPath)); }
/// <summary> /// Tries to resolve a file up in the current theme's hierarchy chain. /// </summary> /// <param name="virtualPath">The original virtual path of the theme file</param> /// <returns> /// If the current working themme is based on another theme AND the requested file /// was physically found in the theme's hierarchy chain, an instance of <see cref="InheritedThemeFileResult" /> will be returned. /// In any other case the return value is <c>null</c>. /// </returns> public InheritedThemeFileResult Resolve(string virtualPath) { Guard.ArgumentNotEmpty(() => virtualPath); virtualPath = VirtualPathUtility.ToAppRelative(virtualPath); if (!ThemeHelper.PathIsInheritableThemeFile(virtualPath)) { return(null); } bool isExplicit = false; string requestedThemeName; string relativePath; string query; virtualPath = TokenizePath(virtualPath, out requestedThemeName, out relativePath, out query); Func <InheritedThemeFileResult> nullOrFile = () => { if (isExplicit) { return(new InheritedThemeFileResult { IsExplicit = true, OriginalVirtualPath = virtualPath }); } return(null); }; ThemeManifest currentTheme; var isAdmin = EngineContext.Current.Resolve <IWorkContext>().IsAdmin; // ThemeHelper.IsAdminArea() if (isAdmin) { currentTheme = _themeRegistry.GetThemeManifest(requestedThemeName); } else { bool isLess; bool isBundle; if (ThemeHelper.IsStyleSheet(relativePath, out isLess, out isBundle) && isLess) { // special consideration for LESS files: they can be validated // in the backend. For validation, a "theme" query is appended // to the url. During validation we must work with the actual // requested theme instead dynamically resolving the working theme. var httpContext = HttpContext.Current; if (httpContext != null && httpContext.Request != null) { var qs = httpContext.Request.QueryString; if (qs["theme"].HasValue()) { EngineContext.Current.Resolve <IThemeContext>().SetRequestTheme(qs["theme"]); } } } if (isLess && query != null && query.StartsWith("explicit", StringComparison.OrdinalIgnoreCase)) { // special case to support LESS @import declarations // within inherited LESS files. Snenario: an inheritor wishes to // include the same file from it's base theme (e.g. custom.less) just to tweak it // a bit for his child theme. Without the 'explicit' query the resolution starting point // for custom.less would be the CURRENT theme's folder, and NOT the requested one's, // which inevitably would result in a cyclic dependency. currentTheme = _themeRegistry.GetThemeManifest(requestedThemeName); isExplicit = true; } else { currentTheme = ThemeHelper.ResolveCurrentTheme(); } if (currentTheme.BaseTheme == null) { // dont't bother resolving files: the current theme is not inherited. // Let the current VPP do the work. return(nullOrFile()); } } if (!currentTheme.ThemeName.Equals(requestedThemeName, StringComparison.OrdinalIgnoreCase)) { if (!_themeRegistry.IsChildThemeOf(currentTheme.ThemeName, requestedThemeName)) { return(nullOrFile()); } } var fileKey = new FileKey(currentTheme.ThemeName, relativePath); var result = _files.GetOrAdd(fileKey, (k) => { // ALWAYS begin the search with the current working theme's location! string resultVirtualPath; string resultPhysicalPath; string actualLocation = LocateFile(currentTheme.ThemeName, relativePath, out resultVirtualPath, out resultPhysicalPath); if (actualLocation != null) { return(new InheritedThemeFileResult { RelativePath = relativePath, OriginalVirtualPath = virtualPath, ResultVirtualPath = resultVirtualPath, ResultPhysicalPath = resultPhysicalPath, OriginalThemeName = requestedThemeName, ResultThemeName = actualLocation }); } return(null); }); if (result == null) { return(nullOrFile()); } return(result); }