Add a Class to container element in first block in Area
Permalink 1 user found helpful
I have an Area which contains several blocks of a single, new custom block type. The blocks generate simple output along the lines of:
> Heading
> Description
> "Read More" link
This is an HTML5 site I'm building and each block is wrapped in a <section> element generated in the view.php file for the custom block. All well so far....
However, on one page type these blocks go on, I need to add a class of "first" to the first <section>, which equates to the first Block rendered within the area.
How do I ascertain the first block rendered in an area and modify its HTML to add 'class="first"' to the section tag?
This may be a dumb question, but this is my first build using C5...
> Heading
> Description
> "Read More" link
This is an HTML5 site I'm building and each block is wrapped in a <section> element generated in the view.php file for the custom block. All well so far....
However, on one page type these blocks go on, I need to add a class of "first" to the first <section>, which equates to the first Block rendered within the area.
How do I ascertain the first block rendered in an area and modify its HTML to add 'class="first"' to the section tag?
This may be a dumb question, but this is my first build using C5...
Oh, and I know from a CSS point of view I can identify the first <section>, but I need to add this attribute into the HTML.
Does anyone know if within the view.php file of my custom block, I can check to see if this particular instance of the block about to be rendered is the first block in the area on the given page?
If I can do this, then I can put a simple conditional line in the view.php code that adds the HTML around the fields to allow me to put in class="first" or similar for the first block.
I see from core concrete code that the Area code for display($c) loops through all of the blocks for the Area, but I don't want to be doing anything in there, so hoping I can intercept it at the view.php to add my extras.
Thanks.
If I can do this, then I can put a simple conditional line in the view.php code that adds the HTML around the fields to allow me to put in class="first" or similar for the first block.
I see from core concrete code that the Area code for display($c) loops through all of the blocks for the Area, but I don't want to be doing anything in there, so hoping I can intercept it at the view.php to add my extras.
Thanks.
Hello, I don't know if you know this, but if you click on the block after you add it into your page while you are still in edit mode, you can then click on "Design", and then the tab "CSS". There you can add your page specific class or id. What this does is add a div around the block, with your custom class.
Now, option two. You can set the area to recognize which page id it is in like so (x=your page ID):
Option three, you simply tell concrete5 to get the page handle and add it as a class.
Then you can style that section per page in your css:
Option four, you can determine all of these things at once, plus only do it if there is a block there:
I hope I could help! :-D
EDIT: You can also do this:
Now, option two. You can set the area to recognize which page id it is in like so (x=your page ID):
<section class="<?php if ($c->getCollectionID() == x){ echo 'last'; } ?>"> <p>content</p> </section>
Option three, you simply tell concrete5 to get the page handle and add it as a class.
Then you can style that section per page in your css:
<section class="<?php echo $c->getCollectionHandle(); ?>"> <p>content</p> </section>
Option four, you can determine all of these things at once, plus only do it if there is a block there:
$pageHandle = $c->getCollectionHandle(); $pageID = $c->getCollectionID(); $a = new Area('Header'); $a->display($c); if (!$a->getTotalBlocksInArea($c) > 0) { echo '<section class="' . $pageID . ' ' . $pageHandle . '">'; }
I hope I could help! :-D
EDIT: You can also do this:
$inlineJS = '<script type="text/javascript">$(document).ready(function() {$("#sectionParent section:first-child").addClass("last");});</script>'; $pageID = $c->getCollectionID(); if ($pageID == x) { echo $inlineJS; } else { //do something else here if page ID isn't right. }
I thought of another thing you could do which is better. In this one you check for a page attribute, and do something if it exists:
That way you can create the page attributes in the backend, and then for the page you want to echo the class="last" bit, you simply add the attribute to that particular page.
:-D
$last = if ($c->getCollectionAttributeValue('last')){ echo 'class="last"'; } <section <?php $last ?>> <p>content</p> </section>
That way you can create the page attributes in the backend, and then for the page you want to echo the class="last" bit, you simply add the attribute to that particular page.
:-D
Thanks for the detailed response, but I think it doesn't quite hit the nail on the head.
Each of my blocks contains a Heading, Description, Link.
In the view.php I have:
So each block comes out as a fully formed section set.
When my page renders them, I just want to add class="first" to the first block.
I don't want to add it to the view (as what if these blocks are pulled for display elsewhere), I want to add it only on a particular template where the HTML is specific.
I don't want the user going in and setting attributes on what should be determinable from the system, and also, what if they change the sort order of the blocks? They would have to remember to remove and re-set attributes. Likewise, having users edit CSS is not desirable in this instance.
Thanks for the detail, but I'm not sure it solves my problem...but I might be wrong!
Each of my blocks contains a Heading, Description, Link.
In the view.php I have:
$linkedPage = $this->controller->getLinkedPage(); $nh = Loader::helper('navigation'); if ($linkedPage) { $pageURL = $nh->getLinkToCollection($linkedPage); $content = "{$detail} <a href=\"{$pageURL}\" class=\"more\">More »</a>"; } else { $content = $detail; } echo "<section>\n"; echo "<h3>{$heading}</h3>\n"; echo "<p>{$content}</p>\n"; echo "</section>\n";
So each block comes out as a fully formed section set.
When my page renders them, I just want to add class="first" to the first block.
I don't want to add it to the view (as what if these blocks are pulled for display elsewhere), I want to add it only on a particular template where the HTML is specific.
I don't want the user going in and setting attributes on what should be determinable from the system, and also, what if they change the sort order of the blocks? They would have to remember to remove and re-set attributes. Likewise, having users edit CSS is not desirable in this instance.
Thanks for the detail, but I'm not sure it solves my problem...but I might be wrong!
This goes into the theme files, not the block files.
If there is a section element underneath the parent element on a certain page id, this will add the class to the first section element it encounters. That means you don't have to worry about whether they are putting other blocks in front of your section block, or whether they change the blocks ordering.
The main problem is determining what page to do this on, and I selected the page id to check (if you know this ahead of time). But you can use a page attribute check to determine what page to activate the code snippet on. The above still applies: it won't matter whether they reorder blocks, or put different blocks everywhere. This will only select the first occurring section element inside the specified parent on the specified page ID.
If there is a section element underneath the parent element on a certain page id, this will add the class to the first section element it encounters. That means you don't have to worry about whether they are putting other blocks in front of your section block, or whether they change the blocks ordering.
The main problem is determining what page to do this on, and I selected the page id to check (if you know this ahead of time). But you can use a page attribute check to determine what page to activate the code snippet on. The above still applies: it won't matter whether they reorder blocks, or put different blocks everywhere. This will only select the first occurring section element inside the specified parent on the specified page ID.
//put this code into header $inlineJS = '<script type="text/javascript">$(document).ready(function() {$("#sectionParent section:first-child").addClass("first");});</script>'; $pageID = $c->getCollectionID(); if ($pageID == x) { echo $inlineJS; }
Thanks again - but I'd like a solution that didn't use javascript.
I'm guessing I can't work out the 1st, 2nd, 3rd, nth block in an area as it's prepared for rendering unless wanting to mess about with core Concrete?
I'm guessing I can't work out the 1st, 2nd, 3rd, nth block in an area as it's prepared for rendering unless wanting to mess about with core Concrete?
Nope, see here:
http://www.concrete5.org/community/forums/customizing_c5/find-the-l...
Maybe one of their solutions will give you an idea?
http://www.concrete5.org/community/forums/customizing_c5/find-the-l...
Maybe one of their solutions will give you an idea?
I have looked around, and I found a decent solution. :-D
In your header.php, include phpQuery file (see below for website) like so:
In your editable area where you are going to place your section blocks, place this code:
I have tested it, and it works to add the class .first to the first <section> tag it encounters for the page ID you want it to work on in the editable area you specify (Header, in this case). Again, you could use the page attributes instead of the page ID for the if statement to minimize issues with deleting a page and trying to find its page ID again, but it IS all server side. No JS. :-D
phpQuery website:http://code.google.com/p/phpquery/...
In your header.php, include phpQuery file (see below for website) like so:
include('phpQuery-onefile.php');
In your editable area where you are going to place your section blocks, place this code:
//x == your page ID you want this to work on if ($c->getCollectionID() == x) { ob_start(); $a = new Area('Header'); $a->display($c); $get = ob_get_clean(); $doc = phpQuery::newDocumentHTML($get); $doc['section']->filter(':first')->addClass('first'); echo phpQuery::getDocument($doc->getDocumentID()); } else { $a = new Area('Header'); $a->display($c); }
I have tested it, and it works to add the class .first to the first <section> tag it encounters for the page ID you want it to work on in the editable area you specify (Header, in this case). Again, you could use the page attributes instead of the page ID for the if statement to minimize issues with deleting a page and trying to find its page ID again, but it IS all server side. No JS. :-D
phpQuery website:http://code.google.com/p/phpquery/...
Thanks Boomgraphics more great info!
I did something similar when including jquery but only wanted it included once, I used a global count, if the global variable was below or equal to one then echo your class
When I was searching for the solution last time Jordan pointed me towards a getTotalBlocksInArea function. I didnt fully understand then but I believe you can take the area "contain_sections" and use it within your controller, the new class will retain all the block information about that area. (im not certain about this its all theory)
Meaning you can then to loop over the blocks in the area, filtering by Handle to retrieve only the ones you need.
You could then add these to an array check the index and if [0]?
If you add it to the controller it could be run on a $obj->isFirst();
**edit just noticed its mentioned in option 4 from BoomGraphic
global $first; $class($first<=1)?" class='first'":""; $first++;
When I was searching for the solution last time Jordan pointed me towards a getTotalBlocksInArea function. I didnt fully understand then but I believe you can take the area "contain_sections" and use it within your controller, the new class will retain all the block information about that area. (im not certain about this its all theory)
Meaning you can then to loop over the blocks in the area, filtering by Handle to retrieve only the ones you need.
You could then add these to an array check the index and if [0]?
If you add it to the controller it could be run on a $obj->isFirst();
**edit just noticed its mentioned in option 4 from BoomGraphic
Haha yes I mentioned it, but I haven't got a clue what you're talking about. :-D
All I know is that it works for that particular purpose.
All I know is that it works for that particular purpose.