librelist archives

« back to archive

How to set @body_class variable for all pages in custom theme

How to set @body_class variable for all pages in custom theme

From:
Chad Ostrowski
Date:
2012-02-18 @ 15:24
Hi, all. I've been poking around, creating my own theme, and I'd like to 
set the class of the body tag. I was going to do this by using Flags, with
something like: 

    %body{ class: 'main-nav-page' if @page.flagged_as?('main-nav-page') }

which would probably work, but I noticed that the layout file from the 
Slate theme 
(https://github.com/gma/nesta-theme-slate/blob/master/views/layout.haml) 
already has:

    %body{ class: @body_class }

How do I set this instance variable for each page? I thought maybe I could
use a simple Sinatra `before` helper, but the `@page` variable isn't set 
yet at that point, so I can't check the page's flags. And an `after` 
helper has no useful effect on the request's instance variables.

Why do I want this?

My theme has a prominent main nav bar, and having the title of a page 
displayed both in the nav bar and on the page itself is repetitive and 
unnecessary. Alas, adding a class to the first h1 on the page causes Nesta
to not use it as the page title (that is, it doesn't show up in the 
navigation, created from the menu.txt file). This is arguably a bug; I 
would be open to fixing this bug in addition to figuring out how to set 
@body_class. 

Re: [nesta] How to set @body_class variable for all pages in custom theme

From:
James Abbott
Date:
2012-02-18 @ 17:36
Hi Chad,-

take a look at how I did this for my theme:

https://github.com/abbottjam/nesta-theme-legibilis/blob/master/app.rb

It's lines 44 to 56.

Cheers,
James



On Sat, Feb 18, 2012 at 4:24 PM, Chad Ostrowski <hi@chadoh.com> wrote:

>  Hi, all. I've been poking around, creating my own theme, and I'd like to
> set the class of the body tag. I was going to do this by using Flags, with
> something like:
>
>     %body{ class: 'main-nav-page' if @page.flagged_as?('main-nav-page') }
>
> which would probably work, but I noticed that the layout file from the
> Slate 
theme<https://github.com/gma/nesta-theme-slate/blob/master/views/layout.haml>already
has:
>
>     %body{ class: @body_class }
>
> How do I set this instance variable for each page? I thought maybe I could
> use a simple Sinatra `before` helper, but the `@page` variable isn't set
> yet at that point, so I can't check the page's flags. And an `after` helper
> has no useful effect on the request's instance variables.
>
> *Why do I want this?*
> *
> *
> My theme has a prominent main nav bar, and having the title of a page
> displayed both in the nav bar and on the page itself is repetitive and
> unnecessary. Alas, adding a class to the first h1 on the pa ge causes Nesta
> to not use it as the page title (that is, it doesn't show up in the
> navigation, created from the menu.txt file). This is arguably a bug; I
> would be open to fixing this bug in addition to figuring out how to set
> @body_class.
>

Re: [nesta] How to set @body_class variable for all pages in custom theme

From:
Chad Ostrowski
Date:
2012-02-18 @ 18:03
Hm, I guess that's an option. I'd rather not totally overwrite nesta's 
default `get '*'`, though. I'd rather hook into it in some other way, 
rather than duplicating code and making future Nesta updates more 
complicated.

Thanks for the suggestion, though! I'm gonna stick with doing my 
calculations in the layout file, for now. 


On Saturday, February 18, 2012 at 12:36 PM, James Abbott wrote:

> Hi Chad,-
> 
> take a look at how I did this for my theme:
> 
> https://github.com/abbottjam/nesta-theme-legibilis/blob/master/app.rb
> 
> It's lines 44 to 56.
> 
> Cheers,
> James
> 
> 
> 
> On Sat, Feb 18, 2012 at 4:24 PM, Chad Ostrowski <hi@chadoh.com 
(mailto:hi@chadoh.com)> wrote:
> > Hi, all. I've been poking around, creating my own theme, and I'd like 
to set the class of the body tag. I was going to do this by using Flags, 
with something like: 
> > 
> >     %body{ class: 'main-nav-page' if @page.flagged_as?('main-nav-page') }
> > 
> > which would probably work, but I noticed that the layout file from the
Slate theme 
(https://github.com/gma/nesta-theme-slate/blob/master/views/layout.haml) 
already has: 
> > 
> >     %body{ class: @body_class }
> > 
> > How do I set this instance variable for each page? I thought maybe I 
could use a simple Sinatra `before` helper, but the `@page` variable isn't
set yet at that point, so I can't check the page's flags. And an `after` 
helper has no useful effect on the request's instance variables. 
> > 
> > Why do I want this?
> > 
> > My theme has a prominent main nav bar, and having the title of a page 
displayed both in the nav bar and on the page itself is repetitive and 
unnecessary. Alas, adding a class to the first h1 on the pa ge causes 
Nesta to not use it as the page title (that is, it doesn't show up in the 
navigation, created from the menu.txt file). This is arguably a bug; I 
would be open to fixing this bug in addition to figuring out how to set 
@body_class. 

Re: [nesta] How to set @body_class variable for all pages in custom theme

From:
James Abbott
Date:
2012-02-18 @ 18:31
You're not "totally overwriting" Nesta's default get '*' by sticking in
extra two lines of code. It's change by addition, not change by
modification - the latter being the least preferred of the two.

If you want to put your logic in the view, go ahead. That's an MVC
antipattern. Sinatra isn't strictly MVC but calculations in views are, in
my opinion, a worse hack than using app.rb for what it is meant to -
overriding defaults.

/ James


On Sat, Feb 18, 2012 at 7:03 PM, Chad Ostrowski <hi@chadoh.com> wrote:

> Hm, I guess that's an option. I'd rather not totally overwrite nesta's
> default `get '*'`, though. I'd rather hook into it in some other way,
> rather than duplicating code and making future Nesta updates more
> complicated.
>
> Thanks for the suggestion, though! I'm gonna stick with doing my
> calculations in the layout file, for now.
>
> On Saturday, February 18, 2012 at 12:36 PM, James Abbott wrote:
>
> Hi Chad,-
>
> take a look at how I did this for my theme:
>
> https://github.com/abbottjam/nesta-theme-legibilis/blob/master/app.rb
>
> It's lines 44 to 56.
>
> Cheers,
> James
>
>
>
> On Sat, Feb 18, 2012 at 4:24 PM, Chad Ostrowski <hi@chadoh.com> wrote:
>
>  Hi, all. I've been poking around, creating my own theme, and I'd like to
> set the class of the body tag. I was going to do this by using Flags, with
> something like:
>
>     %body{ class: 'main-nav-page' if @page.flagged_as?('main-nav-page') }
>
> which would probably work, but I noticed that the layout file from the
> Slate 
theme<https://github.com/gma/nesta-theme-slate/blob/master/views/layout.haml>already
has:
>
>     %body{ class: @body_class }
>
> How do I set this instance variable for each page? I thought maybe I could
> use a simple Sinatra `before` helper, but the `@page` variable isn't set
> yet at that point, so I can't check the page's flags. And an `after` helper
> has no useful effect on the request's instance variables.
>
> *Why do I want this?*
> *
> *
> My theme has a prominent main nav bar, and having the title of a page
> displayed both in the nav bar and on the page itself is repetitive and
> unnecessary. Alas, adding a class to the first h1 on the pa ge causes Nesta
> to not use it as the page title (that is, it doesn't show up in the
> navigation, created from the menu.txt file). This is arguably a bug; I
> would be open to fixing this bug in addition to figuring out how to set
> @body_class.
>
>
>
>

Re: [nesta] How to set @body_class variable for all pages in custom theme

From:
Graham Ashton
Date:
2012-02-18 @ 19:00
On 18 Feb 2012, at 18:31, James Abbott wrote:

> You're not "totally overwriting" Nesta's default get '*' by sticking in 
extra two lines of code. It's change by addition, not change by 
modification - the latter being the least preferred of the two. 

It's not recommended when there are alternatives though; if (when) we 
change the default handler anybody who has redefined it won't be able to 
use the new version (unless they notice, and edit their code). As usual, 
it's a trade off...

--
Graham Ashton
Founder, The Agile Planner
http://theagileplanner.com | @agileplanner | @grahamashton


Re: [nesta] How to set @body_class variable for all pages in custom theme

From:
Chad Ostrowski
Date:
2012-02-18 @ 19:09
Thanks, Graham! That all makes a lot of sense. I didn't realize that I 
could use custom metadata. Definitely better than using Flags.

And yes, given a choice between an MVC antipattern and a DRY antipattern, 
I'll err towards the MVC one. 


On Saturday, February 18, 2012 at 2:00 PM, Graham Ashton wrote:

> On 18 Feb 2012, at 18:31, James Abbott wrote:
> 
> > You're not "totally overwriting" Nesta's default get '*' by sticking 
in extra two lines of code. It's change by addition, not change by 
modification - the latter being the least preferred of the two. 
> 
> It's not recommended when there are alternatives though; if (when) we 
change the default handler anybody who has redefined it won't be able to 
use the new version (unless they notice, and edit their code). As usual, 
it's a trade off...
> 
> --
> Graham Ashton
> Founder, The Agile Planner
> http://theagileplanner.com | @agileplanner | @grahamashton
> 
> 

Re: [nesta] How to set @body_class variable for all pages in custom theme

From:
Casey Olson
Date:
2012-02-20 @ 05:51
I have a similar question. I'd like to apply the same class, based on the 
'style' metadata to the %article in summary.haml

I've tried: %article{ :class => body_class }

But that doesn't work.

Thanks,

Casey

On Feb 18, 2012, at 2:09 PM, Chad Ostrowski wrote:

> Thanks, Graham! That all makes a lot of sense. I didn't realize that I 
could use custom metadata. Definitely better than using Flags.
> 
> And yes, given a choice between an MVC antipattern and a DRY 
antipattern, I'll err towards the MVC one.
> On Saturday, February 18, 2012 at 2:00 PM, Graham Ashton wrote:
> 
>> On 18 Feb 2012, at 18:31, James Abbott wrote:
>> 
>>> You're not "totally overwriting" Nesta's default get '*' by sticking 
in extra two lines of code. It's change by addition, not change by 
modification - the latter being the least preferred of the two.
>> 
>> It's not recommended when there are alternatives though; if (when) we 
change the default handler anybody who has redefined it won't be able to 
use the new version (unless they notice, and edit their code). As usual, 
it's a trade off...
>> 
>> --
>> Graham Ashton
>> Founder, The Agile Planner
>> http://theagileplanner.com | @agileplanner | @grahamashton
> 

Re: [nesta] How to set @body_class variable for all pages in custom theme

From:
Graham Ashton
Date:
2012-02-20 @ 07:49
On 20 Feb 2012, at 05:51, Casey Olson <casey.m.olson@gmail.com> wrote:

> But that doesn't work.

Can you expand on that a bit?

Re: [nesta] How to set @body_class variable for all pages in custom theme

From:
Graham Ashton
Date:
2012-02-18 @ 18:58
On 18 Feb 2012, at 18:03, Chad Ostrowski wrote:

> Hm, I guess that's an option. I'd rather not totally overwrite nesta's 
default `get '*'`, though. I'd rather hook into it in some other way, 
rather than duplicating code and making future Nesta updates more 
complicated.

I think, if I'd thought of it at the time, I'd have used a helper in Slate
rather than an instance variable.

%body{ :body_class => body_class }

Then in app.rb you can set it how you want. You'll need to check that 
@page isn't nil though or it'll blow up when rendering 404 pages, and the 
like.

Here's a simple one.

module Nesta
  class App
    def helpers
      def body_class
        @page && @page.metadata('style')
      end
    end
  end
end

On one of my sites (where Nesta does the sales site, and other code takes 
care of what happens when the user logs in) body_class is worked out 
automatically from the path. Here's the helper's method body:

if @page.nil?
  case request.path
  when /^\/app/  # user is logged into the app, not a nesta page
    'app'
  else
    nil
  end
else  # nesta is responsible for serving the page
  cls = request.path.sub(/^\//, '').gsub(/[^\w]+/, '-').sub(/^$/, 'home')
  cls << " #{@page.metadata('type')}" if @page.metadata('type')
  cls << " #{@page.template}" unless @page.template == 'page'
  cls
end

--
Graham Ashton
Founder, The Agile Planner
http://theagileplanner.com | @agileplanner | @grahamashton


Re: [nesta] How to set @body_class variable for all pages in custom theme

From:
Casey Olson
Date:
2012-02-20 @ 14:26
Of course.

In my app.rb I've added this:

      def body_class
         @page && @page.metadata('style')
      end

On layout.haml:

  %body{ :class => body_class }

And summaries.haml looks like this:

- unless pages.empty?
  %ol
    - pages.each do |page|
      %li
        %article{ :class => body_class }
		...

I'd like the articles on the homepage ( ol li articles ) to have the same 
class as the body on their individual page, the class I defined with 
"Style" in the metadata.

Currently the individual articles pages' body has the body_class, but the 
articles in the ol outputted by summary.haml don't have a class.

Thanks,

Casey


On Feb 18, 2012, at 10:24 AM, Chad Ostrowski wrote:

> Hi, all. I've been poking around, creating my own theme, and I'd like to
set the class of the body tag. I was going to do this by using Flags, with
something like:
> 
>     %body{ class: 'main-nav-page' if @page.flagged_as?('main-nav-page') }
> 
> which would probably work, but I noticed that the layout file from the 
Slate theme already has:
> 
>     %body{ class: @body_class }
> 
> How do I set this instance variable for each page? I thought maybe I 
could use a simple Sinatra `before` helper, but the `@page` variable isn't
set yet at that point, so I can't check the page's flags. And an `after` 
helper has no useful effect on the request's instance variables.
> 
> Why do I want this?
> 
> My theme has a prominent main nav bar, and having the title of a page 
displayed both in the nav bar and on the page itself is repetitive and 
unnecessary. Alas, adding a class to the first h1 on the pa ge causes 
Nesta to not use it as the page title (that is, it doesn't show up in the 
navigation, created from the menu.txt file). This is arguably a bug; I 
would be open to fixing this bug in addition to figuring out how to set 
@body_class.

Re: [nesta] How to set @body_class variable for all pages in custom theme

From:
Graham Ashton
Date:
2012-02-20 @ 14:53
On 20 Feb 2012, at 14:26, Casey Olson wrote:

>       def body_class
>          @page && @page.metadata('style')
>       end
> 
> And summaries.haml looks like this:
> 
> - unless pages.empty?
>   %ol
>     - pages.each do |page|
>       %li
>         %article{ :class => body_class }
> 		...
> 
> I'd like the articles on the homepage ( ol li articles ) to have the 
same class as the body on their individ ual page, the class I defined with
"Style" in the metadata.

That's because your body_class method is using @page (which is the page 
object for the page that is currently being rendered) to find out what the
style metadata is set to. You need to be asking each page inside the loop 
what their style metadata is set to instead...

--
Graham Ashton
Founder, The Agile Planner
http://theagileplanner.com | @agileplanner | @grahamashton


Re: [nesta] How to set @body_class variable for all pages in custom theme

From:
Casey Olson
Date:
2012-02-21 @ 22:27
Thanks Graham,

I was under the impression that's what I was doing by including it in the 
summaries page.

Do I need an @article or something similar?

I'm confused, and would love to read some relevant documentation that 
would help me figure this out.

Thanks,

Casey


On Feb 20, 2012, at 9:53 AM, Graham Ashton wrote:

> On 20 Feb 2012, at 14:26, Casey Olson wrote:
> 
>>      def body_class
>>         @page && @page.metadata('style')
>>      end
>> 
>> And summaries.haml looks like this:
>> 
>> - unless pages.empty?
>>  %ol
>>    - pages.each do |page|
>>      %li
>>        %article{ :class => body_class }
>> 		...
>> 
>> I'd like the articles on the homepage ( ol li articles ) to have the 
same class as the body on their individ ual page, the class I defined with
"Style" in the metadata.
> 
> That's because your body_class method is using @page (which is the page 
object for the page that is currently being rendered) to find out what the
style metadata is set to. You need to be asking each page inside the loop 
what their style metadata is set to instead...
> 
> --
> Graham Ashton
> Founder, The Agile Planner
> http://theagileplanner.com | @agileplanner | @grahamashton
> 
> 
> 

Re: [nesta] How to set @body_class variable for all pages in custom theme

From:
Graham Ashton
Date:
2012-02-21 @ 22:40
On 21 Feb 2012, at 22:27, Casey Olson wrote:

> I was under the impression that's what I was doing by including it in 
the summaries page.

I'm not sure whether you understood what I was saying.

> Do I need an @article or something similar?

Are you familiar with what the @ on the front of "page" or "article" is doing?

> I'm confused, and would love to read some relevant documentation that 
would help me figure this out.

If you want to get a grip of basic ruby, I'd recommend investing 15 
minutes in working through these exercises (they start off a bit simple, 
but I would expect them to show their worth towards the end):

http://tryruby.org/

Here's the code again:

> - pages.each do |page|
>     %li
>       %article{ :class => body_class }

Let's go through it line by line. The first one starts with "- " which is 
Haml speak for "the rest of this line is Ruby code".

"pages.each do |page|" will loop over all the objects in the "pages" 
Array, and assign each one to the "page" variable. The "page" variable is 
only being set while you're inside that loop.

The "body_class" helper didn't look at each "page" variable; it has no 
idea whatsoever that your "page" variables in the loop exist. It's looking
at a different page variable entirely, called "@page". Here's the 
body_class helper again:

> def body_class
>   @page && @page.metadata('style')
> end

The "@" in front of "page" refers to an instance variable. What that 
really means is that it's set once by Nesta before it starts rendering 
this HTML. @page represents the Markdown, Textile or Haml page that Nesta 
is currently rendering. So nothing to do with any of the objects in the 
"pages" list that we called .each on above.

So to get the behaviour you're after, you'll want to change the helper so 
that you can use it inside the loop. That means you'll want to pass the 
page object into the helper. Like this:

def body_class(page)
  page && page.metadata('style')
end

I'd probably modify it so that I could use it on the current page in a 
body tag too (in other words, I'd make the page variable optional):

def body_class(page = nil)
  page = @page if page.nil?
  page && page.metadata('style')
end

Then you could continue to do this in your body tags:

%body{ :class => body_class }

and this inside your loop:

- pages.each do |page|
    %li
      %article{ :class => body_class(page) }

I hope that's a bit clearer. It's certainly more wordy!