Developer forum

Forum » Development » Overwrite/Alter @Stylesheets template tag (Is it possible?)

Overwrite/Alter @Stylesheets template tag (Is it possible?)

Alexander P.
Reply
Hi all,

Excuse me in case this question is obvious, but I really have no idea if I can, or how I can modify the @Stylesheets template tag on a Master Template from a custom assembly in the bin folder. I have tried searching for this, but I have not found anything specifically on this topic, so I have decided to post here. Ideally, I would like to be able to get the value of the tag (unless I can access the individual css stylesheet path strings from elsewhere) , parse it, and then output the same stylesheets, but going through a custom aspx handler which I have already made that binds them together, minifies them, and manages caching appropriately with the client and inside the server (for better performance).

I am using Dynamicweb 8.0.2.2

I have tried hooking up to Dynamicweb.Notifications.Standard.Page.OnOutput , Loaded and AfterOutput with a Dynamicweb.Extensibility.NotificationSubscriber but with no luck - the tag was not defined in the templates, and the pageview did not have such a value (args.pageview.get_Value("Stylesheets")). I have even tried the deprecated TemplateMaster property, but found nothing useful/relevant there. I have tried setting the tag in each template in each of the notifications, but it did not change in the Master Template. 

I have also tried the same from a Dynamicweb.PageTemplateExtender, however, it did not achieve the result either.

I know all of the classes I have made get executed, as I am having each of them logging information, however, none of them actually detect the @Stylesheets Master Template Tag, nor have they managed to overwrite it. I have tried searching for a Styles class (connected to the current Area, so I can maybe reconstruct the stylesheet paths into link tags and substitute the template tag altogether if possible), however I have not found one in the API so far.

To whomever is reading this, I can provide further information, or any source code, if necessary.

Thanks in advance,
Alexander


Replies

 
Christoffer Andersen
Reply
Hi Aleaxander

Can't you just exclude the stylesheet tag and include your own references in head like below?:

<head>
<link rel="stylesheet" type="text/css" href="/Files/Templates/Designs/myProject/style.css" />
</head>

 
Alexander P.
Reply
Hi Christoffer,

Thank you for your reply.
I could, but it would make it impossible to alter these references from the administration (Management Center/Designer/Stylesheets/MyStyle/Page/Template/Stylesheet). It will also eliminate any extra stylesheets other than the main one for the current area, and I have no idea if that will break the styles anywhere.

If no other solution is available, I guess I could resort to this.

 
Pavel Volgarev
Reply
This post has been marked as an answer
Hi Alexander,

I'm going to propose a bit hacky solution since there's unfortunately no standard way of altering the contents of the "Stylesheets" tag. The idea is to surround the "Stylesheets" tag with a marker HTML comments and parse extract the contents after the tag is set.

Here's the code (tested using Desings & Layouts as well as the legacy Stylesheet approach):

using System;
using Dynamicweb.Extensibility;

namespace StylesheetParserExtender
{
    /// <summary>
    /// Allows marking stylesheet blocks before they're filled in with content.
    /// </summary>
    [Subscribe(Dynamicweb.Notifications.Standard.Page.OnOutput)]
    public class StylesheetBlockMarker : NotificationSubscriber
    {
        /// <summary>
        /// Gets the start marker.
        /// </summary>
        public const string StylesheetStart = "<!-- stylesheets:start -->";

        /// <summary>
        /// Gets the end marker.
        /// </summary>
        public const string StylesheetEnd = "<!-- stylesheets:end -->";

        /// <summary>
        /// Handles the given notification.
        /// </summary>
        /// <param name="notification">Notification.</param>
        /// <param name="args">Notification arguments.</param>
        public override void OnNotify(string notification, NotificationArgs args)
        {
            var tag = "<!--@Stylesheets-->";
            var e = args as Dynamicweb.Notifications.Standard.Page.OnOutputArgs;

            if (e != null && e.template != null)
            {
                // If using Designs & Layouts, "args.template" is the master template
                var template = e.template.Html.IndexOf(tag, StringComparison.InvariantCultureIgnoreCase) >= 0 ?
                    e.template : Dynamicweb.Frontend.PageView.Current().TemplateMaster;

                // Surrounding the tag with the marker comments
                template.Html = template.Html.Replace(tag, StylesheetStart + tag + StylesheetEnd);
            }
        }
    }

    /// <summary>
    /// Combines and minifies stylesheets.
    /// </summary>
    [Subscribe(Dynamicweb.Notifications.Standard.Page.AfterOutput)]
    public class StylesheetOptimizer : NotificationSubscriber
    {
        /// <summary>
        /// Handles the given notification.
        /// </summary>
        /// <param name="notification">Notification.</param>
        /// <param name="args">Notification arguments.</param>
        public override void OnNotify(string notification, NotificationArgs args)
        {
            var e = args as Dynamicweb.Notifications.Standard.Page.AfterOutputArgs;

            if (e != null && e.template != null)
            {
                var html = e.template.Html;

                var blockStart = html.IndexOf(StylesheetBlockMarker.StylesheetStart, StringComparison.InvariantCultureIgnoreCase);
                var blockEnd = html.IndexOf(StylesheetBlockMarker.StylesheetEnd, StringComparison.InvariantCultureIgnoreCase);

                if (blockStart >= 0 && blockEnd > 0 && blockEnd > blockStart)
                {
                    var contentStart = blockStart + StylesheetBlockMarker.StylesheetStart.Length;

                    var stylesheets = html.Substring(contentStart, blockEnd - contentStart);

                    // Removing original content, except of the start marker
                    html = html.Remove(contentStart, blockEnd + StylesheetBlockMarker.StylesheetEnd.Length - contentStart);

                    // TODO: parse stylesheet references, replace with handler reference
                    // stylesheets = ...
                    
                    // Replacing the start marker with new content
                    html = html.Replace(StylesheetBlockMarker.StylesheetStart, stylesheets);

                    // Overwriting default HTML
                    e.template.Html = html;
                }
            }
        }
    }
}


Hope this helps.

-- Pavel
Votes for this answer: 0
 
Imar Spaanjaars Dynamicweb Employee
Imar Spaanjaars
Reply
It would be interesting to open up the stylesheets field in a public property in a future version of DW so you can access the attached stylesheets, add or remove to that collection or swap them for a bundled and minimized version.

ASP.NET 4.5 is going to bring bundling and minification out the box so bundling is probably going to be more popular in the future.

Imar


 
Alexander P.
Reply
@Pavel Volgarev
Thanks man, your code provided the solution to my problem. I actually needed to use only your StylesheetOptimizer class, as I decided to loop through all link tags, detect the ones which are stylesheets and replace their href attributes if they reference local resources.

@Imar Spaanjaars
Definitely. I just think it is a little weird that the DW devs have made the @Stylesheets tag so hardcore, especially with all the work they have done on separating presentation from content and behavior. Eh well, at least the problem is not unsolvable.

 

You must be logged in to post in the forum