How to add a class to layout-wrapper in Orchard CMS based on the current page and/or homepage
Asked Answered
P

2

8

Background: I want to avoid creating an Alternate Layout for my home-page and I'd like to keep the "The Theme Machine" zones and layout next to intact, and actually "theme" most of everything using pure CSS. So I need to selectively target CSS to specific "pages", including, and most importantly, the homepage. The simplest way to do that would be to add a class to the layout-wrapper "div" that wraps the entire layout. I could add a class to the "body" element by overriding the Document.cshtml file, but I really think it is cleaner to just work inside the Layout.chstml file and capitalize on the Model.Classes to add the needed CSS classes to the "opening" tag.

I' currently doing something like this:

string area = Model.DesignatedAreaField;
Model.Classes.Add(string.IsNullOrWhiteSpace(area) ? "home" : area);

Model.Id = "layout-wrapper";
var tag = Tag(Model, "div"); // using Tag so the layout div gets the classes, id and other attributes added to the Model

I know that the Area will not cut, because the homepage, and other pages are all in the same area, and Model.DesignatedAreaField actually returns an empty string for either the homepage or other pages. So, in the end, the code above will ALWAYS generate the following markup (I'm showing the 3 tripels on the homepage):

<div class="home tripel-123" id="layout-wrapper">

I would like to be able to add the "home" CSS class only when the homepage is being displayed. Some pseudo-code would be as follow:

string wrapperCss = IsHomepage ? 'home' : Model.GetUrlPathOrSomethingUniqueForThePath();
Model.Classes.Add(wrapperCss);

This will allow me to, for example, make the main content shrink and float to the right, and put the tripels on its left (that's how the home page design should look like, but I don't want to write an entire different layout for the home if I could do the same with simple, targeted CSS).

UPDATE: Wiring up Bertrand's answer

Bertrand's answer allowed me to add a class to the wrapping DIV depending on the URL. He didn't mention it (since Orchard is second nature to him :-) but you'll have to add an include into the Layout.cshtml file and change "my" code accordingly:

@using Orchard.Utility.Extensions;
{
/* omitted for brevity, everything in between is the same as in the Theme's Machine layout file */

string area = WorkContext.HttpContext.Request.Path.HtmlClassify();
area = string.IsNullOrWhiteSpace(area) ? "home" : area;
Model.Classes.Add("url-" + area);

It results in the following class being added to the enclosing div:

1) When the homepage gets shown:

<div class="url-orchard-local- tripel-123" id="layout-wrapper">

2) When a page named Products get shown:

<div class="url-orchard-local-products" id="layout-wrapper">

My URL reads like this on my dev machine, running inside Visual Studio's webserver:

http://localhost:30320/OrchardLocal/ or 
http://localhost:30320/OrchardLocal/Products 

I'm not betting my life, but I strongly believe that the "OrchardLocal" part will change in production once it is published, let me say, to Azure servers... So I've preemptivelly change the code to this:

string area = WorkContext.HttpContext.Request.Path.HtmlClassify();
if (area.LastOrDefault() == '-') {
    area = "home";
}
Model.Classes.Add("url-" + area);

Which results in this class when the "homepage" gets shown:

<div class="url-home tripel-123" id="layout-wrapper">

(Actually I've made the code above a one-liner abusing some ternary mixed with lambda operators :-)

I'm inferring that the only time the HtmlClassify will return a "class" ending with '-' is when it is the homepage... Or the "root" for the site... I may well be wrong! :-)

(Anyway I'm loving Orchard more than anything I've used in the past couple of years other than nHibernate, but, hey, Orchard uses it too! Perfect!)

Peterkin answered 10/9, 2012 at 23:20 Comment(1)
I changed the first line to string area = WorkContext.HttpContext.Request.Path.Substring(1).HtmlClassify(); think it may have included the inital slash so was getting a double dash after urlTenerife
K
7

Something like this should do the trick:

Model.Classes.Add("url-" + WorkContext.HttpContext.Request.Path.HtmlClassify())
Kitchenware answered 11/9, 2012 at 0:6 Comment(3)
Hi Bertrand, this worked, thanks! Since I'm using Orchard for only 2 days now, I know very little of it so I had to do a Find in files to search for HtmlClassify to see which include was needed (@using Orchard.Utility.Extensions;). Apart from that the result was this for the home-page: class="url-orchard-local- tripel-123" and this for a page called Produtos: class="url-orchard-local- ". My URL, running in VS WebServer reads /OrchardLocal... I'm inferring that it will change in production, I'll update my question with what I'm doing so far to try to determine if its the homepage, or not...Peterkin
This is why I always recommend your local dev server is in the same configuration as your production server. This can be hacked around using the site setting that sets up the base url, but there are other issues with having a different config in dev, for example link and media urls in rich content.Kitchenware
Just the other day I've spent 22 hours working straight on a demo for sales using ASP.NET MVC. It started on Sunday, and by Monday, 3 PM, the site was uploaded only to have all images (and some scripts) gone... The salesperson (and owner of the company) was in front of the customer waiting for my call to present the demo... and it wasn't working in production... I was completely sleepy by this time, and it took quite a few desperate minutes to figure out and change everything to use Url.Content (it was one of my first ASP.NET MVC works...). Production settings = Dev settings is WISDOM! :-)Peterkin
B
0

Here's a way to do this with extension methods:

public static string GetPageCssClass(this WorkContext workContext)
{
    string pageUrl = workContext.HttpContext.Request.Url.ToString();
    string baseUrl = workContext.CurrentSite.BaseUrl; //use BaseUrl to later get app relative page path

    string pageClass = workContext.IsHomePage()
        ? "home"
        : pageUrl.Substring(baseUrl.Length).HtmlClassify();

    return string.Format("{0}-page", pageClass);
}

public static bool IsHomePage(this WorkContext workContext)
{
    string pageUrl = workContext.HttpContext.Request.Url.ToString().TrimEnd('/');
    string baseUrl = workContext.CurrentSite.BaseUrl.TrimEnd('/');

    return pageUrl == baseUrl;
}

Note that this bases the class names relative to your BaseUrl set in your site settings so should work locally or in production provided your BaseUrl is set for your current environment.

You would then just need to add a using statement to your view for the namespace of your extension method class and then:

Model.Classes.Add(WorkContext.GetPageCssClass());

Another option here is to add a css class for each layer that is currently active the following extension method will add a list of {xxx}-layer css classes to your page. Here's another related question: Orchard CMS: Conditional CSS Class based on Layer

Brevet answered 5/8, 2014 at 2:0 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.