Skip to content

Archive for the ‘Web Design & Development’ Category

Concrete5 Mod: Form Helper Tweaks

Tuesday, August 3rd, 2010

As we were developing the new Peoria County Government website, we encountered several places where the core FormHelper class fell short of our needs. We tweaked it and present it here for your (download delight). The tweaks are described below.

The Select Helper

The standard select() helper does not allow for a <select> element to have multiple selected values. This modified version does, and keeps everything backwards-compatible.

Basically, in order to use multiple selections, you just have to flip-flop the third and fourth parameters.

The code looks like this:


$form = Loader::helper('form');
print $form->select('mySelect[]', $options, array('multiple' => true), $selections);


Explanation: Concrete5 assumes that if the third argument is an array, then it’s $miscFields and there is no selected value (although it does check $_POST for a selected value later–but either way, the selected value is not allowed to be an array of multiple values). Also, if the third argument is an array, the helper assumes no further arguments are supplied. We can use this to our advantage by supplying an array of multiple selections as the fourth parameter.

The Checkbox Helper

The standard checkbox helper assumes you want the name and id attributes of the input tag to be identical, but this assumption does not always hold true. There have been many times—especially in grid situations—when we wanted the name of a checkbox to be something like ‘selected[]‘ but the id to be unique and incremented like ‘selected0′, ‘selected1′, ‘selected2′, etc., so these elements could be scripted easily.

Our modified checkbox helper does this. All that’s needed is to make sure one of the misc fields has a key of ‘id’.

The code looks like this:


$form = Loader::helper('form');
for ($n = 0; $n < 5; $n++) {
	print $form->checkbox('selected[]', $selected[$n], false, array('id' => 'selected' . $n));
}


The File Helper

This mod simply allows for class names to be attached to the <file> tag. Usage is very straightforward, just submit the className string as the second argument of the helper.

Concrete5 Mod: Searchable HTML block

Thursday, July 29th, 2010

This mod is simple and should be incorporated into the core ASAP. It enables Concrete5′s search functionality to index textual content within the HTML block type.

Just add the following code to /root/concrete/blocks/html/controller.php, starting at line 20:


	public function getSearchableContent() {
		return strip_tags($this->content);
	}


Voila!

Site Launch: Ate Up Clothing Company

Thursday, April 22nd, 2010

Just launched a new small website for Ate Up Clothing Company. This site features some custom animation, a “crucial” design, and is our first website built on top of the Concrete5 content management system!

Congratulations Casey, on your site launch. (Now it’s time to fill it with some great content!)

Concrete5 and Dreamhost – How to get it working

Friday, April 16th, 2010

Great post on the Concrete5 forums about getting Concrete5 to work on Dreamhost servers using PHP and FastCGI.

Basically, it boils down to adding a cgi-bin directory, then creating a dispatcher.fcgi file inside it. After that, the .htaccess file needs to be tweaked a bit.

Concrete5: When and Where to Include Your JS

Wednesday, April 7th, 2010

It’s important to include Javascript in the correct places and in the correct order when building a Concrete5 site. So when and where should we include our Javascript files?

1. header_required.php

This file normally resides at /concrete/elements/header_required.php. In order to modify it, we’ll have to first copy it to the root /elements folder. Within this file, we’ll stick our Javascript base libraries and other global JS code.

Base libraries

This is where we want to include whatever base Javascript library (YUI, jQuery, EXT, mootools, etc.) we’ll use on the site.

Hint: If you don’t use jQuery as a base library on your site, it might be helpful to introduce a switch to determine whether the user is logged in or not. If he is, send the stock Concrete5 base elements (so the in-context editing will work); if not, just send your custom base libraries instead.

Note: The syntax shown here uses our Flexible JS and CSS mod.


if ($u->isRegistered()) {
   // concrete5 libraries
   $this->addHeaderItem($html->css('ccm.base.css'), 'CORE');
   $this->addHeaderItem($html->javascript('jquery.js'), 'CORE');
   $this->addHeaderItem($html->javascript('ccm.base.js'), 'CORE');
}
// your base libraries
$this->addHeaderItem($html->css(array(
   'url' => 'js/ext/resources/css/ext-all.css'
)), 'CORE');
$this->addHeaderItem($html->javascript(array(
   'url' => 'js/ext/adapter/ext/ext-base.js'
)), 'CORE');
$this->addHeaderItem($html->javascript(array(
   'url' => 'js/ext/ext-all.js'
)), 'CORE');


Other global scripts

This is also a good place to put any custom Javascript code your whole site depends upon, regardless of which template the user chooses. For instance, our practice is to always include a script here which sets up a custom Javascript namespace.


$this->addHeaderItem($html->javascript(array(
   'url' => 'js/global/onehat.js'
)));

// This script contains something along the lines of:
// var ONEHAT = {
//    app: {},
//    browser: {},
//    util: {},
//    widget: {}
// };


All the custom apps and widgets we create fit under this one global ONEHAT object so we can be sure our code plays nicely with code from other sources.

2. Templates

Each template file should include whatever scripts are unique to that template. This might include user-interface items like navigation menus or animations.


if (!$c->isEditMode()) {
   $this->addHeaderItem($html->javascript(array(
      'url' => 'navigation.js'
   )));
}


Notice that our practice is to place template-specific Javascript in a conditional block so that it only loads when the page is not in edit mode. This is so custom user-interface eye-candy doesn’t interfere with the in-context editing features of Concrete5.

Also, be aware that any Javascript inserted within a template needs to be placed before the following code (otherwise it won’t work, and will fail silently):


<?php Loader::element('header_required'); ?>


3. Page view

Various page types might have specific Javascript that needs to be inserted—single pages, especially. This can be done anywhere within the page view using $this->addHeaderItem().

4. Page controller

Page controllers are an even better place to stick Javascript includes than the view—especially if you only need it in certain cases, like when an action is being run. Most controller methods can contain a call to $this->addHeaderItem(), including __construct() (although this is usually not the best place to put it), on_start(), on_before_render() (which is where I usually put it), and view().

5. Block controller

Unfortunately, blocks are rendered after the View::outputHeaderItems() method has been run. That means any block Views which contain calls to $this->addHeaderItem() will fail silently! No exceptions will be thrown. No errors will be logged in the dashboard. It just won’t work.

This means that if a block wants to insert Javascript into the header, it must do so within that block controller’s on_page_view() method.


class FooBlockController extends BlockController {
   public function on_page_view() {
      Loader::helper('html');
      $html = new SiteHtmlHelper();
      $this->addHeaderItem($html->javascript(array(
         'url' => 'blocks/foo/bar.js',
         'inline' => false,
         'minify' => true
      )), 'VIEW');
   }

   // This must be defined or else header items will be added twice...
   // once in the header and once at the bottom
   public function outputAutoHeaderItems() { }

}


Note: It is possible for your block’s View to insert Javascript inline (without using addHeaderItem()). But if you followed our advice of moving JS to the bottom of the HTML source, you will encounter the problem of your inline JS appearing in the HTML source before the base libraries or your global namespace object have loaded. Thus, it’s likely that your code will break.

Final Thoughts

It’s important to keep your code modular and loosely-coupled. Code for blocks should not interfere with one another or be dependent on each other—they should not even be aware that the other blocks exist. Code for templates should be totally self-contained and only apply within that template.

Concrete5 Mod: Moving JS to the Bottom

Wednesday, March 31st, 2010

In our previous post, we talked about a mod to Concrete5 which would allow for flexible JS and CSS includes. In this post, we’re going to expand upon that idea with another mod which will allow us to move our Javascript code to the bottom of the HTML source, thereby providing better front-end performance for our websites.

Note: This mod only takes effect when used in conjunction with the Flexible JS and CSS Includes mod, and will have no effect on core Concrete5 Javascript includes. Thus its true benefit—at least right now—is for the public-facing end of your website, not the contextual-editing part of Concrete5.

Eventually, it would be nice to see this functionality incorporated into the Concrete5 core. Also it would be nice to see all core Javascript includes migrated to use these methods. That way, all JS scripts would be loaded last on the page but in the correct order, preserving dependencies, etc.

Instructions for Concrete v5.4

Step 1:

Copy the /concrete/libraries/view.php file to your /libraries folder.

Step 2:

Within view.php, add a private property, $footerItems, immediately after $headerItems.


private $footerItems = array();


Step 3:

Still within view.php, replace the stock outputHeaderItems() method with the following:


public function outputHeaderItems() {
   $items = $this->getHeaderItems();
   foreach($items as $item) {
      if ($item instanceof SiteJavaScriptOutputObject) {
         $this->footerItems[] = $item;
      } else {
         print $item;
         print "\n";
      }
   }
}


This is where the magic happens. We are going through the headerItems array and checking to see if there are any Javascript items that have used our modified HtmlHelper class. If so, we pull them aside and stick them in a footerItems array for later inclusion.

Step 4:

Still within view.php, add the following method:


public function outputFooterItems() {
   $items = $this->footerItems;
   foreach($items as $item) {
      print $item;
      print "\n";
   }
}


Step 5:

Create a new file in your /elements directory called footer_required.php. Insert the following code:


<?php
print $this->outputFooterItems();
echo Config::get('SITE_TRACKING_CODE');
?>


Step 6:

Now, inside your template, insert the following code, just before the closing </body> tag:


<?php Loader::element('footer_required'); ?>


Step 7:

Finally, whenever you include Javascript code, use the following syntax:


$this->addHeaderItems($html->javascript(array(
   'url' => 'myScript.js'
   // and any of the other optional parameters here
)));


That’s it! Your Javascript code will now appear last in the HTML source, and you will likely notice an improvement in front-end performance.

Hints

Modify header_required.php to use the new HtmlHelper methods

But only do this when the user is not logged in (as it will break the Concrete5 UI when the user is logged in).


if ($u->isRegistered()) {
   $this->addHeaderItem($html->css('ccm.base.css'), 'CORE');
   $this->addHeaderItem($html->javascript('jquery.js'), 'CORE');
   $this->addHeaderItem($html->javascript('ccm.base.js'), 'CORE');
} else {
   $this->addHeaderItem($html->css('ccm.base.css'), 'CORE');
   $this->addHeaderItem($html->javascript(array('url' => 'jquery.js'), 'CORE'));
   $this->addHeaderItem($html->javascript(array('url' => 'ccm.base.js'), 'CORE'));
}


And as mentioned elsewhere, don’t even bother to include the jQuery library in this file unless you’re using jQuery elsewhere on your site.

Put your JS and CSS code inline if on the home page, otherwise link externally

Usually, front pages profit from having the JS and CSS code put inline, thereby cutting down on initial HTTP requests. Internal pages to a website, on the other hand, usually benefit from the caching provided by linking to external files.


$this->addHeaderItem($html->css(array(
   'url' => 'styles/globalLayout.css',
   'inline' => $this->getCollectionParentID() ? false : true
)));


If we are on the home page (the collection’s parentID == 0, which is falsey) then our code is inserted inline. If not, we use an external link.

Use addHeaderItem() to add footer items?

It may seem a little strange to be using addHeaderItems in order to add Javascript to the footer. But we’re doing this for the sake of backward-compatibility. Adding a new method of addFooterItems would not work with existing code.

Concrete5 Mod: Flexible JS and CSS includes

Sunday, March 28th, 2010

Concrete5 is a great content management system, but the API it provides developers to add Javascript or CSS to a site is not very flexible. So one of the first things we did after deciding to migrate to Concrete5 was to rewrite the HtmlHelper class (download mod here) to be far more flexible—all the while maintaining complete backward-compatibility.

Default Behavior

In a standard Concrete5 install, the HtmlHelper’s css() and javascript() methods each take two arguments: the url of the file you want to include, and an optional package handle. They then spit out well-formed <script> and <link> tags linking to the external files you specified. These methods are also smart enough to verify that the files exist on your server and determine which directories the files reside in. They are used like so:


Loader::helper('html');
$html = new HtmlHelper();
print $html->css('myStylesheet.css');
// outputs: <link rel="stylesheet" type="text/css"
		» href="currentTheme/myStylesheet.css" />

print $html->javascript('myScript.js');
// outputs: <script type="text/javascript"
		» src="currentTheme/myScript.js"></script>


Extended Behavior

These methods are a good start, but what if I want to embed my stylesheets or scripts inline so I can cut down on the number of HTTP requests? Or what if I want to minify them on-the-fly? Or what if I want the stylesheets to only apply to certain media types (printers, or mobile devices, for instance)? Or what if I want the tags to be surrounded by IE’s conditional comments?

The SiteHtmlHelper Class

By extending the core HtmlHelper class with one of our own (called SiteHtmlHelper) and putting it in the helpers/ directory at the root of the website, we can introduce new functionality while maintaining complete backwards compatibility. We can do this because the core HtmlHelper methods each expect a string as their first argument. If we send an array instead, we can use type switching to determine whether to use the old methods or the new. Syntax for the new methods looks like:


Loader::helper('html'); // Concrete5 automatically grabs our new versions
$html = new SiteHtmlHelper();
print $html->css(array(
   'url' => 'myStylesheet.css',
   'inline' => true,
   'minify' => true,
   'media' => 'all'
));
// outputs:
// <style type="text/css" media="all">div{margin:0;}</style>

print $html->javascript(array(
   'url' => 'myScript.js',
   'inline' => true,
   'minify' => true
));

// outputs:
//   <script type="text/javascript">
//   //<![CDATA[
//   var foo=0;
//   //]]>
//   </script>


Notice the CDATA wrapper for inline JS in case you’re using XHTML.

Also, IE conditional comments can be added.


print $html->javascript(array(
   'url' => 'pngFix_IE.js',
   'IE' => true,
   'IEversion' => 'lte IE 6'
));
// outputs: <!--[if lte IE 6]><script src="currentTheme/pngFix_IE.js"
		» type="text/javascript"></script><![endif]-->


The following are optional parameters which can be passed in the array:

  • $url — STRING (relative or absolute link to the file)
  • $script — STRING (the actual js code)
  • $css — STRING (the actual css code)
  • $media — STRING (media attribute value for <style> tag)
  • $inline — BOOL (defaults to false)
  • $minify — BOOL (minify the code first? defaults to false)
  • $IE — BOOL (surround in IE conditional comments? defaults to false)
  • $IEversion — STRING (IE’s condition to check i.e. ‘lte IE 6′. Only works for $IE=true.)
  • $fullTag — STRING (if tag has already been assembled, but needs to be added to document)
  • $fixRelativeLinks — BOOL (should we fix relative links inside the CSS? Only works for $inline=true. Defaults to true.)

Additional Notes

Relative Links

Putting stylesheets inline can break relative links within the stylesheet itself, so our modified HtmlHelper class automatically compensates for this.

Caching

The core HtmlHelper class uses a __toString() method, which gets called multiple times on every CSS file during the getHeaderItems() sorting process. Our version caches the results of this method so it only gets processed once.

JS Minification

Javascript minification is handled by delegating to jsmin.php.

User-Editable CSS

This method of including CSS bypasses the user-editable CSS method of $this->getStyleSheet() but it does not break that method.

Open License

We’d like to see the core Concrete5 team adopt this modified HtmlHelper for the whole CMS, and have therefore released it under a very open license.

Coming up next…

In our next post, we’ll talk about a modification to View::outputHeaderItems and related methods which will move javascript to the bottom of the HTML code, thus enabling better front-end performance.

Scott Interviewed on WBNH

Friday, March 12th, 2010

Scott Spuler was interviewed on WBNH yesterday about the website One Hat Design Studio created for the radio station. Scott talked about the features and benefits of the site, as well as the need for non-profit organizations to have a solid web presence.

This pre-recorded segment will likely air several times next weekend as part of Share 2010, the station’s fund-raising drive.

Site Launch: Spirit of Peoria

Saturday, February 27th, 2010

Probably one of the best-looking sites we’ve ever made, the new Spirit of Peoria website has just been launched! This site has a slew of features including a dynamic scheduling application, online ticket ordering, audio and video, custom graphics, 3D animations, and more!

All cruise information is stored in a database and is available in multiple locations throughout the website.

Site Launch: WBNH Radio

Tuesday, November 3rd, 2009

WBNH RadioYesterday was the official site launch for WBNH Radio’s new website.

The site features a Google Search bar, a WordPress blog, audio players, RSS feeds, and some custom photography. The site was created to be compatible with Adobe Contribute. This means that station staff can update the site’s content quickly and easily without coming back to the original developer.

Congratulations, WBNH!

©2009 One Hat Design Studio, llc   Blog Admin

map index index map index map index map index map index map index map index map