private void RenderScriptReferences() { // Get scripts that are added by the framework var frameworkScriptPaths = GetFrameworkScripts(); // Construct smart list var smartList = new List <string>(); // Hard-code WebForms.js - it will be rendered here, and not in Page (like by default) smartList.Add(GetUrl(new ScriptReference(this.Page.ClientScript.GetWebResourceUrl(typeof(System.Web.UI.Page), "WebForms.js")))); // Add scripts needed by the framework smartList.AddRange(frameworkScriptPaths); // Add scripts previously added to this control smartList.AddRange(this.Scripts.Select(s => GetUrl(s))); // Add scripts from the smart loader smartList.AddRange(SmartLoader.GetScriptsToLoad()); // Clear previous scripts (they are now part of smartList) Scripts.Clear(); // Initialize bundling var allowJsBundling = PortalContext.Current.BundleOptions.AllowJsBundling; var bundle = allowJsBundling ? new JsBundle() : null; // Go through all scripts foreach (var spath in smartList) { var lower = spath.ToLower(); if (lower.EndsWith(".css")) { UITools.AddStyleSheetToHeader(UITools.GetHeader(), spath); } else { var isPostponed = PortalBundleOptions.JsIsBlacklisted(spath); var isFrameworkScript = frameworkScriptPaths.Contains(spath); if (isPostponed) { _postponedList.Add(spath); } if (allowJsBundling && !isPostponed) { bundle.AddPath(spath); } if (!isPostponed && !isFrameworkScript) { Scripts.Add(new ScriptReference(spath)); } } } // Go through postponed scripts foreach (var spath in _postponedList) { Scripts.Add(new ScriptReference(spath)); } // NOTE: At this point, script order is the following: // 1) scripts added by the framework // 2) scripts added directly to this control // 3) scripts from SmartLoader (that are not blacklisted from bundling) // 4) scripts from SmartLoader (that are blacklisted from bundling) // Finalize bundling if (allowJsBundling) { // If bundling is allowed, close the bundle and process it bundle.Close(); BundleHandler.AddBundleIfNotThere(bundle); ThreadPool.QueueUserWorkItem(x => BundleHandler.AddBundleToCache(bundle)); if (BundleHandler.IsBundleInCache(bundle)) { // If the bundle is complete, use its path to replace the path of all the scripts that are not postponed _bundle = bundle; } } }
/// <summary> /// Adds a CSS link to the given header using the given order and parameters. If a link with the given order already exists new link is added right after. /// </summary> /// <param name="header">Page header</param> /// <param name="cssPath">Path of CSS file</param> /// <param name="order">Desired order of CSS link</param> /// <param name="allowBundlingIfEnabled"></param> /// <param name="control">Source control, optional. It will be used to find the current CacheablePortlet and the script reference to it too.</param> public static void AddStyleSheetToHeader(Control header, string cssPath, int order, string rel, string type, string media, string title, bool allowBundlingIfEnabled = true, Control control = null) { if (header == null) { return; } if (string.IsNullOrEmpty(cssPath)) { return; } // Take care of folders if (ServiceTools.RecurseFilesInVirtualPath(SkinManager.Resolve(cssPath), true, p => AddStyleSheetToHeader(header, p, order, rel, type, media, title, allowBundlingIfEnabled, control))) { return; } var resolvedPath = SkinManager.Resolve(cssPath); if (allowBundlingIfEnabled && rel == "stylesheet" && type == "text/css" && PortalBundleOptions.Current.AllowCssBundling) { if (!string.IsNullOrEmpty(title)) { throw new Exception("The title attribute on link tags is not supported when CSS bundling is enabled."); } PortalBundleOptions.Current.EnableCssBundling(header); // If this is CSS stylesheet and bundling is enabled, add it to the bundle // Find the bundle object for the current media var bundle = PortalBundleOptions.Current.CssBundles.SingleOrDefault(x => x.Media == media); if (bundle == null) { bundle = new CssBundle() { Media = media, }; PortalBundleOptions.Current.CssBundles.Add(bundle); } // Add the current resolved path to the bundle if (PortalBundleOptions.CssIsBlacklisted(resolvedPath)) { bundle.AddPostponedPath(resolvedPath); } else { bundle.AddPath(resolvedPath, order); } } else { // If bundling is disabled, fallback to the old behaviour var cssLink = new HtmlLink(); cssLink.ID = "cssLink_" + resolvedPath.GetHashCode().ToString(); // link already added to header if (header.FindControl(cssLink.ID) != null) { return; } cssLink.Href = resolvedPath; cssLink.Attributes["rel"] = rel; cssLink.Attributes["type"] = type; cssLink.Attributes["media"] = media; cssLink.Attributes["title"] = title; cssLink.Attributes["cssorder"] = order.ToString(); // find next control with higher order var index = -1; bool found = false; foreach (Control headerControl in header.Controls) { index++; var link = headerControl as HtmlLink; if (link == null) { continue; } var orderStr = link.Attributes["cssorder"]; if (string.IsNullOrEmpty(orderStr)) { continue; } int linkOrder = Int32.MinValue; if (Int32.TryParse(orderStr, out linkOrder) && linkOrder > order) { found = true; break; } } if (found) { // add link right before higher order link header.Controls.AddAt(index, cssLink); } else { // add link at end of header's controlcollection header.Controls.Add(cssLink); } } // Add stylesheet reference to cacheable portlet if possible, to // be able to add references even if the portlet html is cached. var cb = GetCacheablePortlet(control); if (cb != null) { cb.AddStyleSheet(new StyleSheetReference { CssPath = cssPath, Media = media, Order = order, Rel = rel, Title = title, Type = type, AllowBundlingIfEnabled = allowBundlingIfEnabled }); } }
private void RenderScriptReferences() { var smartList = SmartLoader.GetScriptsToLoad(); var allowJsBundling = PortalContext.Current.BundleOptions.AllowJsBundling; JsBundle bundle = null; List <string> postponedList = null; if (allowJsBundling) { bundle = new JsBundle(); postponedList = new List <string>(); } foreach (var spath in smartList) { var lower = spath.ToLower(); if (lower.EndsWith(".css")) { UITools.AddStyleSheetToHeader(UITools.GetHeader(), spath); } else { if (allowJsBundling) { // If bundling is allowed, add the path to the bundle - if it is not blacklisted if (PortalBundleOptions.JsIsBlacklisted(spath)) { postponedList.Add(spath); } else { bundle.AddPath(spath); } } else { // If bundling is disabled, fall back to the old behaviour var sref = new ScriptReference(spath); Scripts.Add(sref); } } } if (allowJsBundling) { // If bundling is allowed, closing the bundle and adding it as a single script reference bundle.Close(); BundleHandler.AddBundleIfNotThere(bundle); ThreadPool.QueueUserWorkItem(x => BundleHandler.AddBundleToCache(bundle)); if (BundleHandler.IsBundleInCache(bundle)) { // If the bundle is complete, add it as a single script reference var sref = new ScriptReference("/sn-bundles/" + bundle.FakeFilename); Scripts.Add(sref); } else { // The bundle will be complete in a few seconds; disallow caching the page until then this.Page.Response.Cache.SetCacheability(HttpCacheability.NoCache); // Fallback to adding every script again as separate script references foreach (var path in bundle.Paths) { var sref = new ScriptReference(path); Scripts.Add(sref); } } //add blacklisted js path's to the script collection individually foreach (var path in postponedList) { Scripts.Add(new ScriptReference(path)); } } }