예제 #1
0
        /// <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.NotEmpty(virtualPath, nameof(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
            {
                var styleResult    = ThemeHelper.IsStyleSheet(relativePath);
                var isPreprocessor = styleResult != null && styleResult.IsPreprocessor;
                if (isPreprocessor)
                {
                    // special consideration for SASS/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 of 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 (isPreprocessor && query != null && query.StartsWith("explicit", StringComparison.OrdinalIgnoreCase))
                {
                    // special case to support SASS/LESS @import declarations
                    // within inherited SASS/LESS files. Snenario: an inheritor wishes to
                    // include the same file from it's base theme (e.g. custom.scss) just to tweak it
                    // a bit for his child theme. Without the 'explicit' query the resolution starting point
                    // for custom.scss 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);
        }
예제 #2
0
        /// <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.NotEmpty(virtualPath, nameof(virtualPath));

            if (virtualPath[0] != '~')
            {
                virtualPath = VirtualPathUtility.ToAppRelative(virtualPath);
            }

            if (!ThemeHelper.PathIsInheritableThemeFile(virtualPath))
            {
                return(null);
            }

            bool isExplicit = false;

            virtualPath = ThemeHelper.TokenizePath(virtualPath, out var requestedThemeName, out var relativePath, out var query);

            Func <InheritedThemeFileResult> nullOrFile = () =>
            {
                return(isExplicit
                                        ? new InheritedThemeFileResult {
                    IsExplicit = true, OriginalVirtualPath = virtualPath, Query = query
                }
                                        : null);
            };

            ThemeManifest currentTheme = ResolveTheme(requestedThemeName, relativePath, query, out isExplicit);

            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());
                }
            }
            else if (isExplicit && currentTheme.BaseTheme != null)
            {
                // A file from the base theme has been requested
                currentTheme = currentTheme.BaseTheme;
            }

            var fileKey = new FileKey(currentTheme.ThemeName, relativePath, query);
            InheritedThemeFileResult result;

            using (_rwLock.GetUpgradeableReadLock())
            {
                if (!_files.TryGetValue(fileKey, out result))
                {
                    using (_rwLock.GetWriteLock())
                    {
                        // ALWAYS begin the search with the current working theme's location!
                        string actualLocation = LocateFile(currentTheme.ThemeName, relativePath, out var resultVirtualPath, out var resultPhysicalPath);

                        if (actualLocation != null)
                        {
                            result = new InheritedThemeFileResult
                            {
                                RelativePath        = relativePath,
                                OriginalVirtualPath = virtualPath,
                                ResultVirtualPath   = resultVirtualPath,
                                ResultPhysicalPath  = resultPhysicalPath,
                                OriginalThemeName   = requestedThemeName,
                                ResultThemeName     = actualLocation,
                                IsExplicit          = isExplicit,
                                Query = query
                            };
                        }

                        _files[fileKey] = result;
                    }
                }
            }

            if (result == null)
            {
                return(nullOrFile());
            }

            return(result);
        }