/// <summary> /// Because we can have both internal and external dependencies rendered, we need to stagger the script tag output... if they are external, we need to stop the compressing/combining /// and write out the external dependency, then resume the compressing/combining handler. /// </summary> /// <param name="dependencies"></param> /// <param name="http"></param> /// <param name="builder"></param> /// <param name="renderCompositeFiles"></param> /// <param name="renderSingle"></param> protected void WriteStaggeredDependencies( IEnumerable<IClientDependencyFile> dependencies, HttpContextBase http, StringBuilder builder, Func<IEnumerable<IClientDependencyFile>, HttpContextBase, IDictionary<string, string>, string> renderCompositeFiles, Func<string, IDictionary<string, string>, string> renderSingle) { //This action will stagger the output based on whether or not the html attribute declarations are the same for each dependency Action<IEnumerable<IClientDependencyFile>> staggerOnDifferentAttributes = (list) => { var sameAttributes = new List<IClientDependencyFile>(); var currHtmlAttr = GetHtmlAttributes(list.ElementAt(0)); foreach (var c in list) { if (!currHtmlAttr.IsEqualTo(GetHtmlAttributes(c))) { //if the attributes are different we need to stagger if (sameAttributes.Any()) { //render the current buffer builder.Append(renderCompositeFiles(sameAttributes, http, currHtmlAttr)); //clear the buffer sameAttributes.Clear(); } } //add the item to the buffer and set the current html attributes sameAttributes.Add(c); currHtmlAttr = GetHtmlAttributes(c); } //if there's anything in the buffer then write the remaining if (sameAttributes.Any()) builder.Append(renderCompositeFiles(sameAttributes, http, currHtmlAttr)); }; var currNonRemoteFiles = new List<IClientDependencyFile>(); foreach (var f in dependencies) { //if it is an external resource, then we need to break the sequence // unless it has been explicitely required that the dependency be bundled if (http.IsAbsolutePath(f.FilePath) //remote dependencies aren't local && !new Uri(f.FilePath, UriKind.RelativeOrAbsolute).IsLocalUri(http) // not required to be bundled && !f.ForceBundle) { //we've encountered an external dependency, so we need to break the sequence and restart it after //we output the raw script tag if (currNonRemoteFiles.Count > 0) { //render the current buffer staggerOnDifferentAttributes(currNonRemoteFiles); //clear the buffer currNonRemoteFiles.Clear(); } //write out the single script tag builder.Append(renderSingle(f.FilePath, GetHtmlAttributes(f))); } else { //its a normal registration, add to the buffer currNonRemoteFiles.Add(f); } } //now check if there's anything in the buffer to render if (currNonRemoteFiles.Count > 0) { //render the current buffer staggerOnDifferentAttributes(currNonRemoteFiles); } }
/// <summary> /// Because we can have both internal and external dependencies rendered, we need to stagger the script tag output... if they are external, we need to stop the compressing/combining /// and write out the external dependency, then resume the compressing/combining handler. /// </summary> /// <param name="dependencies"></param> /// <param name="http"></param> /// <param name="builder"></param> /// <param name="renderCompositeFiles"></param> /// <param name="renderSingle"></param> protected void WriteStaggeredDependencies( IEnumerable<IClientDependencyFile> dependencies, HttpContextBase http, StringBuilder builder, Func<IEnumerable<IClientDependencyFile>, HttpContextBase, IDictionary<string, string>, string> renderCompositeFiles, Func<string, IDictionary<string, string>, string> renderSingle) { var fileBasedExtensions = ClientDependencySettings.Instance.FileBasedDependencyExtensionList .Union(FileWriters.GetRegisteredExtensions()) .ToArray(); var currNonRemoteFiles = new List<IClientDependencyFile>(); foreach (var f in dependencies) { //need to parse out the request's extensions and remove query strings //need to force non-bundled lines for items with query parameters or a hash value. var extension = f.FilePath.Contains('?') || f.FilePath.Contains('#') ? "" : Path.GetExtension(f.FilePath); var stringExt = ""; if (!string.IsNullOrWhiteSpace(extension)) { stringExt = extension.ToUpper().Split(new[] {'?'}, StringSplitOptions.RemoveEmptyEntries)[0]; } // if it is an external resource OR // if it is a non-standard JS/CSS resource (i.e. a server request) // then we need to break the sequence // unless it has been explicitely required that the dependency be bundled if (!http.IsAbsolutePath(f.FilePath) && !fileBasedExtensions.Contains(stringExt) //now check for external resources || (http.IsAbsolutePath(f.FilePath) //remote dependencies aren't local && !new Uri(f.FilePath, UriKind.RelativeOrAbsolute).IsLocalUri(http) // not required to be bundled && !f.ForceBundle)) { //we've encountered an external dependency, so we need to break the sequence and restart it after //we output the raw script tag if (currNonRemoteFiles.Count > 0) { //render the current buffer StaggerOnDifferentAttributes(http, builder, currNonRemoteFiles, renderCompositeFiles); //clear the buffer currNonRemoteFiles.Clear(); } //write out the single script tag builder.Append(renderSingle(f.FilePath, GetHtmlAttributes(f))); } else { //its a normal registration, add to the buffer currNonRemoteFiles.Add(f); } } //now check if there's anything in the buffer to render if (currNonRemoteFiles.Count > 0) { //render the current buffer StaggerOnDifferentAttributes(http, builder, currNonRemoteFiles, renderCompositeFiles); } }