<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>James Tombs</title>
	<atom:link href="http://jamestombs.co.uk/feed" rel="self" type="application/rss+xml" />
	<link>http://jamestombs.co.uk</link>
	<description>Development blog from James Tombs about PHP, XHTML + CSS and Drupal</description>
	<lastBuildDate>Sun, 09 Jan 2011 01:57:55 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>World of Warcraft Progression blocks updated for WordPress and Drupal</title>
		<link>http://jamestombs.co.uk/2011-01-09/world-of-warcraft-progression-blocks-updated-for-wordpress-and-drupal/1529</link>
		<comments>http://jamestombs.co.uk/2011-01-09/world-of-warcraft-progression-blocks-updated-for-wordpress-and-drupal/1529#comments</comments>
		<pubDate>Sun, 09 Jan 2011 01:56:22 +0000</pubDate>
		<dc:creator>James</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[drupal]]></category>
		<category><![CDATA[wordpress]]></category>
		<category><![CDATA[world of warcraft]]></category>

		<guid isPermaLink="false">http://jamestombs.co.uk/?p=1529</guid>
		<description><![CDATA[With the release of World of Warcraft: Cataclysm, there are new zones and new bosses, so I have updated the progression module for Drupal and WordPress. Module/plugin details Drupal Download WordPress Download]]></description>
			<content:encoded><![CDATA[<p>With the release of World of Warcraft: Cataclysm, there are new zones and new bosses, so I have updated the progression module for Drupal and WordPress.</p>
<p><a href="http://jamestombs.co.uk/2010-07-12/world-of-warcraft-blocks-for-drupal/1279">Module/plugin details</a></p>
<h3><a href="http://jamestombs.co.uk/wp-content/uploads/2010/07/wow_blocks3.zip">Drupal Download</a></h3>
<h3><a href="http://jamestombs.co.uk/wp-content/uploads/2011/01/wow_progression.zip">WordPress Download</a></h3>
]]></content:encoded>
			<wfw:commentRss>http://jamestombs.co.uk/2011-01-09/world-of-warcraft-progression-blocks-updated-for-wordpress-and-drupal/1529/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>[Drupal] Display separate views on different taxonomy pages (parents/children) using Panels/Views</title>
		<link>http://jamestombs.co.uk/2011-01-09/drupal-display-separate-views-on-different-taxonomy-pages-parentschildren-using-panelsviews/1508</link>
		<comments>http://jamestombs.co.uk/2011-01-09/drupal-display-separate-views-on-different-taxonomy-pages-parentschildren-using-panelsviews/1508#comments</comments>
		<pubDate>Sun, 09 Jan 2011 00:32:55 +0000</pubDate>
		<dc:creator>James</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[drupal]]></category>
		<category><![CDATA[drupal planet]]></category>

		<guid isPermaLink="false">http://jamestombs.co.uk/?p=1508</guid>
		<description><![CDATA[I have come across the problem a couple of times now and have come across someone else looking for the same things on IRC where you want to have a different view for parent terms and child terms. Although this probably can be done in Views, I am none the wiser on how to do [...]]]></description>
			<content:encoded><![CDATA[<p>I have come across the problem a couple of times now and have come across someone else looking for the same things on IRC where you want to have a different view for parent terms and child terms.</p>
<p>Although this probably can be done in Views, I am none the wiser on how to do it and neither were any of the participants on IRC. So my work around is to use Panels taking advantage of Ctools contexts.</p>
<p>This tutorial is written for Drupal 6.<br />
<span id="more-1508"></span></p>
<p>First of all, we need to download and enable a few modules.</p>
<ul>
<li><strong>Ctools</strong> &#8211; (Chaos Tools, Page Manager, Views Content Panes)</li>
<li><strong>Panels</strong> &#8211; (Panels)</li>
<li><strong>Views</strong> &#8211; (Views, Views UI)</li>
</ul>
<p>Once the modules are enabled we can continue.</p>
<p>If you haven&#8217;t already, set up your taxonomy vocabulary with terms (they don&#8217;t have to be in a hierarchy but I assume most will).</p>
<p><img src="http://jamestombs.co.uk/wp-content/uploads/2011/01/terms.png" alt="" title="terms" width="152" height="360" class="alignnone size-full wp-image-1509" /></p>
<p>Next we will create our panel pages for the 2 types of term pages. In the image above, we have different types of clothing, most of which have children terms. So we want one page for all the parent terms with the exception of Suits as it doesn&#8217;t have any children and we want to show the products in that term, then another page for Suits and all the child terms.</p>
<p>Go to <strong>Administer</strong> > <strong>Site Building</strong> > <strong>Panels</strong>.</p>
<p><img src="http://jamestombs.co.uk/wp-content/uploads/2011/01/panels.png" alt="" title="panels" width="468" height="180" class="alignnone size-full wp-image-1510" /></p>
<p>On this page, under <strong>Manage pages</strong>, click the Enable button next to <strong>Taxonomy term template</strong>. When the new page loads, press the <strong>Edit</strong> button next to <strong>Taxonomy term template</strong>.</p>
<p>On this page, click the <strong>Add a new variant</strong> link.</p>
<p>I will start with the parent terms panel page, so enter in an appropriate admin title and tick the <strong>Selection rules</strong> box. In the drop down box select <strong>Taxonomy: Term </strong>and press <strong>Add</strong>.</p>
<p><img src="http://jamestombs.co.uk/wp-content/uploads/2011/01/taxonomy-term-template-3.png" alt="" title="taxonomy-term-template-3" width="258" height="181" class="alignnone size-full wp-image-1513" /></p>
<p>In the popup, hold Ctrl and click all the terms that you want this page to apply to and press <strong>Save</strong>.</p>
<p><img src="http://jamestombs.co.uk/wp-content/uploads/2011/01/taxonomy-term-template-4.png" alt="" title="taxonomy-term-template-4" width="370" height="406" class="alignnone size-full wp-image-1512" /></p>
<p>Set a page layout type and then add some basic content so that you can test that it is working properly.  You will also need to set the <strong>Title</strong> to <em>%term:name</em> to reflect the standard Drupal taxonomy pages.</p>
<p><strong>Save</strong> the page.</p>
<p>Now when you visit one of the parent terms, you will get the custom content rather than the default taxonomy page.</p>
<p><img src="http://jamestombs.co.uk/wp-content/uploads/2011/01/taxonomy-term-template-7.png" alt="" title="taxonomy-term-template-7" width="294" height="128" class="alignnone size-full wp-image-1514" /></p>
<p>And visiting a child page still displays the standard Drupal taxonomy text.</p>
<p><img src="http://jamestombs.co.uk/wp-content/uploads/2011/01/taxonomy-term-template-8.png" alt="" title="taxonomy-term-template-8" width="310" height="82" class="alignnone size-full wp-image-1515" /></p>
<p>If this is working, you can repeat the process by adding another Panel variant but this time, under selection rules selected all the child terms rather than the parent terms. Alternatively you could clone the existing variant, then under Selection rules, change the flag to <strong>Reverse (NOT)</strong>, which will also target all the child terms.</p>
<p>Once this is done, your child terms pages will also display some custom text that you defined.</p>
<p><img src="http://jamestombs.co.uk/wp-content/uploads/2011/01/taxonomy-term-9.png" alt="" title="taxonomy-term-9" width="318" height="150" class="alignnone size-full wp-image-1516" /></p>
<p>Now that is all working, we can set up our Views.</p>
<p>For the parent terms, we want to display the child terms only, no products. So when settings up the new view, select <strong>Term</strong> rather than <strong>Node</strong>.</p>
<p><img src="http://jamestombs.co.uk/wp-content/uploads/2011/01/views-1.png" alt="" title="views-1" width="271" height="526" class="alignnone size-full wp-image-1517" /></p>
<p>Add an <strong>argument</strong> and select <strong>Taxonomy: Parent term</strong>.</p>
<p><img src="http://jamestombs.co.uk/wp-content/uploads/2011/01/views-2.png" alt="" title="views-2" width="457" height="347" class="alignnone size-full wp-image-1518" /></p>
<p>Change the argument to <strong>Provide default value</strong> then select <strong>Taxonomy Term ID from URL</strong>.</p>
<p><img src="http://jamestombs.co.uk/wp-content/uploads/2011/01/views-3.png" alt="" title="views-3" width="368" height="336" class="alignnone size-full wp-image-1519" /></p>
<p>Set up the rest of the view as you see fit, apply filters etc.  Make sure that you add some way of clicking through to the child terms. If using <strong>fields</strong>, add<strong> Taxonomy: Term</strong> and make sure the <strong>Link this field to its taxonomy term page</strong> option is checked.</p>
<p>Save the View.</p>
<p>Now create another view but this time select <strong>Node</strong> rather than <strong>Term</strong>. Do the same with arguments and apply any filters, fields etc.</p>
<p>Once you are finished creating your views, head back to <strong>Administer</strong> > <strong>Site Building</strong> > <strong>Panels</strong> and click <strong>Edit</strong> next to <strong>Taxonomy term template</strong>.</p>
<p>Select one of the variants on the left and go down to <strong>Content</strong>. Remove any existing custom block content unless you want to keep it and add a new bit of content. Select <strong>Views</strong> on the left then select the appropriate view for that variant.</p>
<p>On <strong>Select display</strong>, just click <strong>Continue</strong>. On the next page, in the drop box labeled <strong>Taxonomy: Term ID:</strong>, select <strong>Term ID of first term</strong>. Repeat for the other page variant.</p>
<p>Now when we visit the taxonomy term pages the correct view will show up depending on what term is being viewed.</p>
<p>Parent item shows the child items:</p>
<p><img src="http://jamestombs.co.uk/wp-content/uploads/2011/01/views-6.png" alt="" title="views-6" width="289" height="135" class="alignnone size-full wp-image-1520" /></p>
<p>Children terms show the nodes (in this case the empty text of the view):</p>
<p><img src="http://jamestombs.co.uk/wp-content/uploads/2011/01/views-7.png" alt="" title="views-7" width="302" height="102" class="alignnone size-full wp-image-1521" /></p>
<p>You could even change the view for showing nodes of the term, by changing the argument to <strong>Taxonomy Term ID (with depth)</strong> which will show all nodes for that term and all it&#8217;s child nodes, which you could place below the node showing child terms.</p>
<p><img src="http://jamestombs.co.uk/wp-content/uploads/2011/01/views-8.png" alt="" title="views-8" width="326" height="334" class="alignnone size-full wp-image-1522" /></p>
<p>Which would result in:</p>
<p><img src="http://jamestombs.co.uk/wp-content/uploads/2011/01/views-9.png" alt="" title="views-9" width="304" height="160" class="alignnone size-full wp-image-1523" /></p>
]]></content:encoded>
			<wfw:commentRss>http://jamestombs.co.uk/2011-01-09/drupal-display-separate-views-on-different-taxonomy-pages-parentschildren-using-panelsviews/1508/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>&#8220;Disable Drupal blocks/regions&#8221; has no effect with some custom themes</title>
		<link>http://jamestombs.co.uk/2010-12-04/disable-drupal-blocksregions-has-no-effect-with-some-custom-themes/1503</link>
		<comments>http://jamestombs.co.uk/2010-12-04/disable-drupal-blocksregions-has-no-effect-with-some-custom-themes/1503#comments</comments>
		<pubDate>Sat, 04 Dec 2010 22:21:35 +0000</pubDate>
		<dc:creator>James</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[drupal]]></category>
		<category><![CDATA[drupal planet]]></category>

		<guid isPermaLink="false">http://jamestombs.co.uk/?p=1503</guid>
		<description><![CDATA[I came across a problem with a panels page when I check the &#8220;Disable Drupal blocks/regions&#8221; box, the sidebars are supposed to disappear so that the content takes the full width. But it didn&#8217;t work. Switching back to Garland and the sidebars disappeared as expected. After a quick search, I found this post on drupal.org [...]]]></description>
			<content:encoded><![CDATA[<p>I came across a problem with a panels page when I check the &#8220;Disable Drupal blocks/regions&#8221; box, the sidebars are supposed to disappear so that the content takes the full width.  But it didn&#8217;t work. </p>
<p>Switching back to Garland and the sidebars disappeared as expected.  After a quick search, I found <a href="http://drupal.org/node/467252">this post</a> on drupal.org which is the same issue but one of the replies essentially says to hack core to get it to work, but that is not necessary.</p>
<p><span id="more-1503"></span></p>
<p>In Drupal core, it only looks for sidebars named left and right. I have 4 (left_sidebar_primary, left_sidebar_secondary, right_sidebar_primary, right_sidebar_secondary), this allows me to style some blocks easier dependent on their weighting in the sidebars.</p>
<p>The workaround is very simple.  All it requires is a few lines in your template.php file in your hook_preprocess_page() function.</p>
<p>If you haven&#8217;t that function in your template.php file, then here is the necessary code:</p>
<pre class="brush: php">function theme_name_preprocess_page(&amp;$vars) {
  // Code goes in here
}</pre>
<p>The code which we need to enter is fairly simple.</p>
<pre class="brush: php">function theme_name_preprocess_page(&amp;$vars) {
  if (!$vars[&#039;show_blocks&#039;]) {
    $vars[&#039;left_primary&#039;] = &#039;&#039;;
    $vars[&#039;left_secondary&#039;] = &#039;&#039;;
    $vars[&#039;right_primary&#039;] = &#039;&#039;;
    $vars[&#039;right_secondary&#039;] = &#039;&#039;;
  }
}</pre>
<p>Here we check to see if the $vars['show_block'] variable is FALSE, if it is then we set the content of all the sidebar regions to nothing.</p>
<p>If you would like to disable more regions, just add them as they are defined in your theme_name.info file.</p>
<p>One other thing to mention is that you need to make sure in your page.tpl.php file that you correctly add the code to not show any HTML markup if the region is empty.</p>
<pre class="brush: php">&lt;?php if (!empty($left_primary)): ?&gt;
  &lt;div class=&quot;sidebar-primary&quot;&gt;
    &lt;?php print $left_primary; ?&gt;
  &lt;/div&gt;
&lt;?php endif; ?&gt;
&lt;?php if (!empty($left_secondary)): ?&gt;
  &lt;div class=&quot;sidebar-secondary&quot;&gt;
    &lt;?php print $left_secondary; ?&gt;
  &lt;/div&gt;
&lt;?php endif; ?&gt;</pre>
]]></content:encoded>
			<wfw:commentRss>http://jamestombs.co.uk/2010-12-04/disable-drupal-blocksregions-has-no-effect-with-some-custom-themes/1503/feed</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>WoW Progression Widget for WordPress</title>
		<link>http://jamestombs.co.uk/2010-11-21/wow-progression-widget-for-wordpress/1496</link>
		<comments>http://jamestombs.co.uk/2010-11-21/wow-progression-widget-for-wordpress/1496#comments</comments>
		<pubDate>Sun, 21 Nov 2010 15:14:27 +0000</pubDate>
		<dc:creator>James</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[wordpress]]></category>
		<category><![CDATA[world of warcraft]]></category>

		<guid isPermaLink="false">http://jamestombs.co.uk/?p=1496</guid>
		<description><![CDATA[I have ported the Drupal module of the Word of Warcraft Progression block to be a WordPress widget. You can download the file from here. I haven&#8217;t tested it extensively but selecting the bosses and zones on Settings screen affects the front end and the jQuery code to appears expand and collapse the zones appears [...]]]></description>
			<content:encoded><![CDATA[<p>I have ported the Drupal module of the <a href="http://jamestombs.co.uk/2010-07-12/world-of-warcraft-blocks-for-drupal/1279">Word of Warcraft Progression block</a> to be a WordPress widget.</p>
<p>You can download the file from <a href='http://jamestombs.co.uk/2011-01-09/world-of-warcraft-progression-blocks-updated-for-wordpress-and-drupal/1529'>here</a>.  I haven&#8217;t tested it extensively but selecting the bosses and zones on Settings screen affects the front end and the jQuery code to appears expand and collapse the zones appears to work.  So as far as I am concerned it works with WordPress 3.0.1 but may not work with lesser versions (judging by the WordPress Codex/API it should work for WordPress 2.7 onwards.)</p>
<h3><a href="http://jamestombs.co.uk/2011-01-09/world-of-warcraft-progression-blocks-updated-for-wordpress-and-drupal/1529">Updated module for World of Warcraft: Cataclysm</a></h3>
]]></content:encoded>
			<wfw:commentRss>http://jamestombs.co.uk/2010-11-21/wow-progression-widget-for-wordpress/1496/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Programmatically create Ubercart products with attributes and selected options in Drupal 6</title>
		<link>http://jamestombs.co.uk/2010-10-27/programmatically-create-ubercart-products-with-attributes-and-selected-options-in-drupal-6/1314</link>
		<comments>http://jamestombs.co.uk/2010-10-27/programmatically-create-ubercart-products-with-attributes-and-selected-options-in-drupal-6/1314#comments</comments>
		<pubDate>Wed, 27 Oct 2010 10:27:05 +0000</pubDate>
		<dc:creator>James</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[drupal]]></category>
		<category><![CDATA[drupal planet]]></category>

		<guid isPermaLink="false">http://jamestombs.co.uk/?p=1314</guid>
		<description><![CDATA[I have been working on a import script to import products from a previous custom Drupal module in to Ubercart. For this I have been using the Batch API to handle the large amounts of data. Upon trying to import some products using drupal_execute(), I came to realise that drupal_execute() can not be run in [...]]]></description>
			<content:encoded><![CDATA[<p>I have been working on a import script to import products from a previous custom Drupal module in to Ubercart.  For this I have been using the Batch API to handle the large amounts of data.  Upon trying to import some products using drupal_execute(), I came to realise that drupal_execute() can not be run in during a batch operation using Batch API<span id="more-1314"></span>.</p>
<p>So I ended up creating the node using node_save() which created the basic product.<br />
<!--more--></p>
<pre class="brush: php">
function my_module_create_product($data) {
  require_once &#039;modules/node/node.pages.inc&#039;; // Required for node_object_prepare();
  $node = new stdClass();
  $node-&gt;type = &#039;product&#039;;

  node_object_prepare($node); // This sets up all the default node fields so we don&#039;t accidentally leave something off.

  // Copy over all the existing settings from Drupal 5.
  $node-&gt;uid = 1;
  $node-&gt;status = $data-&gt;status;
  $node-&gt;title = $data-&gt;title;
  $node-&gt;created = $data-&gt;created;
  $node-&gt;changed = $data-&gt;changed;

  // Set Ubercart variables
  $node-&gt;model = $data-&gt;model_number; // the SKU is a required field, so I generated a SKU based on the node title
  $node-&gt;list_price = $data-&gt;price;
  $node-&gt;cost = $data-&gt;price;
  $node-&gt;sell_price = $data-&gt;price;
  $node-&gt;default_qty = 1;
  $node-&gt;pkg_qty = 1;

  // Set taxonomy + menu etc if you need to
  $node-&gt;taxonomy = array();
  $node-&gt;menu = array();

  // Save the node
  node_save($node);  // This will update the $node object with the $node-&gt;nid which is important for the next step.
}
</pre>
<p>We now have the node created with all the required information. From here, you would usually set up a the $form_state['values'] array and pass on to uc_object_attributes_form() to add the attributes to the form followed by uc_object_options_form() to set the options for these attributes both using drupal_execute().  But as we can&#8217;t do this, I copied the code from the submit handlers for both of these forms and merged them in to one (there are a few queries which are written by uc_object_attributes_form_submit() which are then overwritten or delete by uc_object_options_form_submt() which we can leave out or alter slightly to make the code shorter and to do less database queries. I have added some comments to the code which shows you the process.</p>
<pre class="brush: php">
function my_module_create_product($data) {
  // $node creation stuff from above

  // To set up the attributes we need to create a keyed array where the key is the attribute ID which contains an array of the options which need to be set.  The option in the keyed array will be set as the default option for that attribute.  If the attribute is just a blank textfield and doesn&#039;t have any options, then just pass an empty array.
  $attributes = array(
    1 =&gt; array(1, 2, 3, 4, 5, 6, 7, 8), // This could be a list of T-shirt colours, so which ever colour option 1 is will be the default option.
    2 =&gt; array(9, 10, 11, 12, 13), // This could be T-shirt sizes, again the first number will be the default which in this case is option 9.
  );

  // Go through all our attributes that we have set and set up the options in the database.
  foreach ($attributes as $aid =&gt; $options) {
    // Load the attribute
    $attribute = uc_attribute_load($aid);
    // Set the default to be the first option.
    $oid = $attributes[$aid][0];
    // Add the attribute to for the node and set the default option
    db_query(&quot;INSERT INTO {uc_product_attributes} (nid, aid, label, ordering, default_option, required, display) SELECT %d, aid, label, ordering, %d, required, display FROM {uc_attributes} WHERE aid = %d&quot;, $node-&gt;nid, $oid, $aid);
    // Set the options if they are provided
    if (is_array($attribute-&gt;options) &amp;&amp; count($attributes[$aid]) &gt; 0) {
      // Cycle through all the available options (the $option object here contains all necessary values to be put in the database.
      foreach ($attribute-&gt;options as $option) {
        if (in_array($option-&gt;oid, $attributes[$aid])) { // Check to see if the current option is in our keyed array.
          db_query(&quot;INSERT INTO {uc_product_options} (nid, oid, cost, price, weight, ordering) VALUES (%d, %d, %f, %f, %f, %d)&quot;, $node-&gt;nid, $option-&gt;oid, $option-&gt;cost, $option-&gt;price, $option-&gt;weight, $option-&gt;ordering);
        }
      }
    }
  }
}
</pre>
<p>We won&#8217;t be using adjustments, so I haven&#8217;t added that to my code.  If you wish to further your code with adjustments you will need to find the necessary form and submit function for it.</p>
]]></content:encoded>
			<wfw:commentRss>http://jamestombs.co.uk/2010-10-27/programmatically-create-ubercart-products-with-attributes-and-selected-options-in-drupal-6/1314/feed</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
		<item>
		<title>Fatal error: Cannot redeclare db_status_report()</title>
		<link>http://jamestombs.co.uk/2010-10-22/fatal-error-cannot-redeclare-db_status_report/1312</link>
		<comments>http://jamestombs.co.uk/2010-10-22/fatal-error-cannot-redeclare-db_status_report/1312#comments</comments>
		<pubDate>Fri, 22 Oct 2010 09:19:53 +0000</pubDate>
		<dc:creator>James</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[drupal]]></category>

		<guid isPermaLink="false">http://jamestombs.co.uk/?p=1312</guid>
		<description><![CDATA[The above error message is caused by using 2 seperate database drivers in your settings.php file. To fix this, make sure you use a single database driver so stick to mysql or mysqli and don&#8217;t mix the two together.]]></description>
			<content:encoded><![CDATA[<p>The above error message is caused by using 2 seperate database drivers in your settings.php file.</p>
<p>To fix this, make sure you use a single database driver so stick to mysql or mysqli and don&#8217;t mix the two together.</p>
]]></content:encoded>
			<wfw:commentRss>http://jamestombs.co.uk/2010-10-22/fatal-error-cannot-redeclare-db_status_report/1312/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Javascript Currency Validation</title>
		<link>http://jamestombs.co.uk/2010-09-15/javascript-currency-validation/1307</link>
		<comments>http://jamestombs.co.uk/2010-09-15/javascript-currency-validation/1307#comments</comments>
		<pubDate>Wed, 15 Sep 2010 11:00:08 +0000</pubDate>
		<dc:creator>James</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[validation]]></category>

		<guid isPermaLink="false">http://jamestombs.co.uk/?p=1307</guid>
		<description><![CDATA[The following will check a string to make sure it is a valid currency. It can only include numbers and a . (decimal point which is optional). function validateCurrency(amount) { var regex = /^[1-9]\d*(?:\.\d{0,2})?$/; return regex.test(amount); } The amount must start with a number 1 through 9, you can change this to 0-9 but potentially [...]]]></description>
			<content:encoded><![CDATA[<p>The following will check a string to make sure it is a valid currency.  It can only include numbers and a . (decimal point which is optional).</p>
<pre class="brush: javascript">
function validateCurrency(amount) {
  var regex = /^[1-9]\d*(?:\.\d{0,2})?$/;
  return regex.test(amount);
}
</pre>
<p><span id="more-1307"></span><br />
The amount must start with a number 1 through 9, you can change this to 0-9 but potentially allows someone to put 0.00 so you would have to apply further validation.  Then optionally the user can enter a decimal to 2 decimal places.</p>
<p>This validates for:</p>
<ul>
<li>20.00</li>
<li>13.12</li>
<li>12.5</li>
<li>1.00</li>
<li>1.50</li>
</ul>
<p>But fails on:</p>
<ul>
<li>20.000</li>
<li>0.50</li>
<li>0.2</li>
<li>1,500</li>
<li>1,200.50</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://jamestombs.co.uk/2010-09-15/javascript-currency-validation/1307/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>How not to create a registration/login process &#8211; T-mobile UK</title>
		<link>http://jamestombs.co.uk/2010-07-16/how-not-to-create-a-registrationlogin-process-t-mobile-uk/1302</link>
		<comments>http://jamestombs.co.uk/2010-07-16/how-not-to-create-a-registrationlogin-process-t-mobile-uk/1302#comments</comments>
		<pubDate>Fri, 16 Jul 2010 17:04:22 +0000</pubDate>
		<dc:creator>James</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Other]]></category>
		<category><![CDATA[accessibility]]></category>
		<category><![CDATA[user experience]]></category>
		<category><![CDATA[ux]]></category>

		<guid isPermaLink="false">http://jamestombs.co.uk/?p=1302</guid>
		<description><![CDATA[I have just come across a great example of how not to deal with users logging in or registering for a site with T-Mobile (UK). I am on my second phone with them and had an account with them for the original phone, so I tried logging in using my username which I had in [...]]]></description>
			<content:encoded><![CDATA[<p><!--1fbd454703b24bd8a49817567c36e413--></p>
<p>I have just come across a great example of how not to deal with users logging in or registering for a site with T-Mobile (UK).</p>
<p>I am on my second phone with them and had an account with them for the original phone, so I tried logging in using my username which I had in an email and my password.  It wasn&#8217;t having it.</p>
<p>So I tried the forgotten password route.  This asked for my mobile number and my username.  Entered my original number and username. Nope. Entered my new number and username. Nope.</p>
<p>So I tried the forgotten username + password route. This asks for your name, phone number and email.  I entered all this information using my original phone number. Nope.  Tried again with my new phone number. Nope.</p>
<p><span id="more-1302"></span></p>
<p>At this point I guess that I may not have an account for my new phone and my old phone was removed even though the number is still on the go on a second phone I have.</p>
<p>This time I went to the registration form. Put in my new number and entered the captcha. I was presented with another screen asking if I was the account holder, what my email was, how I was paying for the number, and a password.  I filled all of this only at this point to be told that an account already existed for this number.  Why couldn&#8217;t this error be present after the first step rather than making me enter in loads of data which was redundant.</p>
<p>So I tried to register again using my original number, entered the captcha and on to step two.  This time I was asked for different information, I assume it recognised that this was a PAYG phone and not a contract phone so rather than being asked about how I paid for it, I was asked for my name address as well as my email, password. I filled this in, but the post code lookup didn&#8217;t recognise my post code, so I tried another post code, nope, and my works post code&#8230;nope. I carried on with the form assuming that it would present some more text fields to enter my address and pressed Submit.</p>
<p>&#8220;Please select your address before proceeding&#8221;</p>
<p>It wouldn&#8217;t let me proceed as I didn&#8217;t select my address which it wouldn&#8217;t find.  Being a developer, I thought I would disable javascript.  Obviously there was a problem, with their post code look up service and with javascript disabled the form would degrade nicely with all the address fields. Nope. The same form is displayed, still showing the Find address button which the href is set to javascript:; so the link wouldn&#8217;t do anything.</p>
<p>I am now in a situation where I can&#8217;t login to a pre-existing account or create a new account for not one but two phones.</p>
<h3>Fixes</h3>
<p>There are quite a few fixes that T-Mobile need to do to get their forms up to scratch.  I can&#8217;t really say much about the login process as it may just be that the accounts don&#8217;t exist for whatever reason, I will have to wait and hear back from T-Mobile.  But the registration form needs a lot of work.</p>
<p>When registering a new account and the number exists, throw an error straight away. Some inline validation would be great, at the very least throw up an error on submitting the form rather than getting the user to type another page of information before being told that the very first thing that did on the previous page was wrong.</p>
<p>Sort out the post code lookup service. I tried 3 different post codes. I know they exist. The look up service they are using just doesn&#8217;t work. A query is sent off by the javascript but there is no response (used Firebug).</p>
<p>Degrade the form if javascript is not available. Not everyone has javascript enabled, especially on some phones. Making sure an application degrades properly if javascript is absent is vital.  If the post code lookup did work, then I wouldn&#8217;t of found this problem, but it doesn&#8217;t work and as it is javascript only, you can&#8217;t go any further.</p>
]]></content:encoded>
			<wfw:commentRss>http://jamestombs.co.uk/2010-07-16/how-not-to-create-a-registrationlogin-process-t-mobile-uk/1302/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Block API module changes coming soon</title>
		<link>http://jamestombs.co.uk/2010-07-16/block-api-module-changes-coming-soon/1299</link>
		<comments>http://jamestombs.co.uk/2010-07-16/block-api-module-changes-coming-soon/1299#comments</comments>
		<pubDate>Fri, 16 Jul 2010 10:39:16 +0000</pubDate>
		<dc:creator>James</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[block api]]></category>
		<category><![CDATA[drupal]]></category>

		<guid isPermaLink="false">http://jamestombs.co.uk/?p=1299</guid>
		<description><![CDATA[After reviewing and updating Block API for Drupal 7, I saw that there were some fairly big changes made to the way the block system works from a code perspective which meant I have had to change a fair bit of the module for Drupal 7. So rather than having 2 quite distinct bits of [...]]]></description>
			<content:encoded><![CDATA[<p>After reviewing and updating Block API for Drupal 7, I saw that there were some fairly big changes made to the way the block system works from a code perspective which meant I have had to change a fair bit of the module for Drupal 7.  So rather than having 2 quite distinct bits of code, I will be updating the Drupal 6 version to work like the Drupal 7 version so that the documentation is the same.  This not only makes the module easier to maintain from my perspective but also anyone else using Block API.</p>
<p><span id="more-1299"></span></p>
<h3>So what has changed?</h3>
<p>hook_block() no longer exists in Drupal 7.  It has been split in to individual hooks for each $op.  So rather than hook_block() we now have:</p>
<ul>
<li>hook_block_info()</li>
<li>hook_block_configure()</li>
<li>hook_block_save()</li>
<li>hook_block_view()</li>
</ul>
<p>A few of these new hooks conflicted with the hooks put in place by the Block API module, so I have made a few changes to the way other modules hook in to it.</p>
<pre class="brush: php">function html_block_block($op = &#039;list&#039;, $delta = NULL, $edit = array()) {
  $function = &#039;block_api_block_&#039;. $op;
  return $function(&#039;html_block&#039;, $delta, $edit);
}</pre>
<p>The above has gone completely. Rather than passing the modules name to the core Blocks module, Block API will pass on it&#8217;s own name and handle the block management of modules using the API itself.  This reduces the amount of code needed (although it wasn&#8217;t that much to start off with) and also makes it easier to remember what you need to use to hook in to Block API.</p>
<p><em>hook_block_api_info()</em> has now changed to <em>hook_block_api_block_types()</em>, the code stays exactly the same. This was caused by the function name changes made in Drupal 7.</p>
<p><em>hook_block_api_view()</em> has changed to <em>hook_block_api_display()</em>, this was also due to the function change in Drupal 7.</p>
<p>Everything else stays the same.  The Block API has now been made slightly easier to use and hook in to thanks to Drupal 7.</p>
<p>The code on d.o should be updated soon.</p>
]]></content:encoded>
			<wfw:commentRss>http://jamestombs.co.uk/2010-07-16/block-api-module-changes-coming-soon/1299/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>World of Warcraft &#8211; PHP Raider Block</title>
		<link>http://jamestombs.co.uk/2010-07-13/world-of-warcraft-php-raider-block/1289</link>
		<comments>http://jamestombs.co.uk/2010-07-13/world-of-warcraft-php-raider-block/1289#comments</comments>
		<pubDate>Tue, 13 Jul 2010 14:32:05 +0000</pubDate>
		<dc:creator>James</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[drupal]]></category>
		<category><![CDATA[world of warcraft]]></category>

		<guid isPermaLink="false">http://jamestombs.co.uk/?p=1289</guid>
		<description><![CDATA[This module adds the ability to have a block pulling out the upcoming raids from PHP Raider. Download: ZIP Last updated: 2010-07-13 18:30 The block displays however many raids you want to display and gives you more information which is available on mouseover. As well as the block configuration, the module has an admin form [...]]]></description>
			<content:encoded><![CDATA[<p>This module adds the ability to have a block pulling out the upcoming raids from <a href="http://www.phpraider.com/">PHP Raider</a>.</p>
<p><strong>Download:</strong> <a href="http://jamestombs.co.uk/wp-content/uploads/2010/07/wow_phpraider.zip">ZIP</a> <strong>Last updated:</strong> 2010-07-13 18:30</p>
<p><span id="more-1289"></span></p>
<p><img src="http://jamestombs.co.uk/wp-content/uploads/2010/07/raid_block.jpg" alt="" title="Raid Block" width="209" height="254" class="alignnone size-full wp-image-1291" /> <img src="http://jamestombs.co.uk/wp-content/uploads/2010/07/raid_hover.jpg" alt="" title="Raid Block - Hover" width="396" height="265" class="alignnone size-full wp-image-1292" /></p>
<p>The block displays however many raids you want to display and gives you more information which is available on mouseover.</p>
<p><img src="http://jamestombs.co.uk/wp-content/uploads/2010/07/raid_settings.jpg" alt="" title="Raider Block Settings" width="476" height="337" class="alignnone size-full wp-image-1293" /></p>
<p>As well as the block configuration, the module has an admin form that must be filled in before any blocks can be created.  This is to make sure that Drupal knows where PHP Raider is located and where the database is.</p>
<p><img src="http://jamestombs.co.uk/wp-content/uploads/2010/07/raider_config.jpg" alt="" title="PHP Raider configuration screen" width="500" height="306" class="alignnone size-full wp-image-1294" /></p>
]]></content:encoded>
			<wfw:commentRss>http://jamestombs.co.uk/2010-07-13/world-of-warcraft-php-raider-block/1289/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>World of Warcraft Blocks for Drupal</title>
		<link>http://jamestombs.co.uk/2010-07-12/world-of-warcraft-blocks-for-drupal/1279</link>
		<comments>http://jamestombs.co.uk/2010-07-12/world-of-warcraft-blocks-for-drupal/1279#comments</comments>
		<pubDate>Mon, 12 Jul 2010 17:53:03 +0000</pubDate>
		<dc:creator>James</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[drupal]]></category>

		<guid isPermaLink="false">http://jamestombs.co.uk/?p=1279</guid>
		<description><![CDATA[I have been working on a site for a World of Warcraft guild to get their frontpage up to scratch with their old site which was running the TinyPortal on SMF. With a server change and some mods becoming unsupported, the decision was made to switch to something else for the frontpage. I had only [...]]]></description>
			<content:encoded><![CDATA[<p>I have been working on a site for a World of Warcraft guild to get their frontpage up to scratch with their old site which was running the TinyPortal on SMF. With a server change and some mods becoming unsupported, the decision was made to switch to something else for the frontpage. I had only one thing on my mind which was Drupal.  But soon found that there didn&#8217;t appear to be many modules on Drupal.org for World of Warcraft.</p>
<p>So far I have created two blocks using the Block API module I developed and will release more when I have written and tested them.</p>
<p>Both blocks are set up in one module, which I have called wow_blocks. If you already have a module called wow_blocks, it may be a bit of a mission getting this to work, so you will have to chose one of the modules.</p>
<p><strong>Download:</strong> <a href="http://jamestombs.co.uk/wp-content/uploads/2010/07/wow_blocks3.zip">ZIP</a>. <strong>Last updated:</strong> 2011-01-09 00:35</p>
<h3>Updates</h3>
<dl>
<dt><strong>2011-01-09 00:35</strong></dt>
<dd>Added new zones and bosses to progression block. &#8211; <a href="http://jamestombs.co.uk/wp-content/uploads/2010/07/wow_blocks3.zip">ZIP</a></dd>
<dt><strong>2010-11-14 09:00</strong></dt>
<dd>Fixed image paths to work if base_path isn&#8217;t /.</dd>
<dt><strong>2010-11-12 19:30</strong></dt>
<dd>Updated the code for the newest version of block_api.</dd>
</dl>
<p><span id="more-1279"></span></p>
<h3>Block 1: Recruitment</h3>
<p>The first block is a block for recruitment.  An admin can set the roles and specs that the guild requires to be displayed in the block, so users know which areas the guild is recruiting in.</p>
<p><img src="http://jamestombs.co.uk/wp-content/uploads/2010/07/recruitment_block.jpg" alt="" title="recruitment_block" width="199" height="497" class="alignnone size-full wp-image-1281" /></p>
<p>All the images are included in the ZIP file.</p>
<p>The admin screen, allows the admin to select the links to use for the Apply now and Recruitment details buttons as well as options for each individual role and spec.</p>
<p><a href="http://jamestombs.co.uk/wp-content/uploads/2010/07/recruitment_settings_full.jpg" rel="shadowbox[post-1279];player=img;"><img src="http://jamestombs.co.uk/wp-content/uploads/2010/07/recruitment_settings_small.jpg" alt="" title="recruitment_settings_small" width="511" height="357" class="alignnone size-full wp-image-1283" /><br />Click for larger version</a></p>
<h3>Block 2: Progression</h3>
<p>This block shows the guilds progression against the bosses of the game.</p>
<p><img src="http://jamestombs.co.uk/wp-content/uploads/2010/07/progression_view.jpg" alt="" title="progression_view" width="436" height="296" class="alignnone size-full wp-image-1284" /></p>
<p>The block features an expandable group of game zones with all the bosses in the zone.</p>
<p>All bosses from the following zones are in the module:</p>
<ul>
<li>Icecrown Citadel</li>
<li>Argent Coliseum</li>
<li>Ulduar</li>
<li>Eye of Eternity</li>
<li>Obsidian Sanctum</li>
<li>Naxxramas</li>
<li>Vault of Archavon</li>
</ul>
<p>As of 9th January 2011 the following extra zones are available:</p>
<ul>
<li>Blackwing Descent</li>
<li>Bastion of Twilight</li>
<li>Throne of the Four Winds</li>
</ul>
<p>Admins have full control over which zones are available and shown in the block as well as selecting which bosses have been defeated.</p>
<p>If you have any requests for World of Warcraft related blocks, let me know in the comments.</p>
]]></content:encoded>
			<wfw:commentRss>http://jamestombs.co.uk/2010-07-12/world-of-warcraft-blocks-for-drupal/1279/feed</wfw:commentRss>
		<slash:comments>19</slash:comments>
		</item>
		<item>
		<title>Adding additional form elements using ahah_helper in Drupal 6</title>
		<link>http://jamestombs.co.uk/2010-07-08/adding-additional-form-elements-using-ahah_helper-in-drupal-6/1276</link>
		<comments>http://jamestombs.co.uk/2010-07-08/adding-additional-form-elements-using-ahah_helper-in-drupal-6/1276#comments</comments>
		<pubDate>Thu, 08 Jul 2010 10:41:42 +0000</pubDate>
		<dc:creator>James</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[ahah]]></category>
		<category><![CDATA[drupal]]></category>
		<category><![CDATA[drupal planet]]></category>
		<category><![CDATA[tutorial]]></category>

		<guid isPermaLink="false">http://jamestombs.co.uk/?p=1276</guid>
		<description><![CDATA[This tutorial will show you how to add new form elements which will be available in $form_state['values'] once the form has been submitted using a submit button by taking advantage of the AHAH helper module. The AHAH helper module does provide a demo, but the demo shows how to change a few fields depending on [...]]]></description>
			<content:encoded><![CDATA[<p>This tutorial will show you how to add new form elements which will be available in $form_state['values'] once the form has been submitted using a submit button by taking advantage of the <a href="http://drupal.org/project/ahah_helper">AHAH helper module</a>.</p>
<p>The AHAH helper module does provide a demo, but the demo shows how to change a few fields depending on a selection made from a select element.  The tutorials I looked at online either didn&#8217;t cover the issue properly or just didn&#8217;t work.<br />
<span id="more-1276"></span><br />
Currently the 6.x-2.0 release throws up errors if you are using certain PHP versions, but these are gone in the 6.x-2.x-dev release.</p>
<h3>Scenario</h3>
<p>You want the user to enter in some data, lets say their favourite car.  But you want the ability for them to add as many cars as they want if they have more than one.</p>
<h3>Code</h3>
<p>Firstly you will need to set up a menu callback for your form, but I will assume you know how to do this if you are looking at this tutorial.</p>
<p>We will set up the basic form first, this includes one textfield and a submit button to submit the form with the textfield in a wrapper (this is important later on for the ahah_helper module).</p>
<pre class="brush: php">function test_form($form_state = NULL) {
  $form[&#039;cars&#039;] = array(
    &#039;#type&#039; =&gt; &#039;fieldset&#039;,
    &#039;#title&#039; =&gt; t(&#039;Favourite cars(s)&#039;),
    &#039;#prefix&#039; =&gt; &#039;&lt;div id=&quot;favourite-cars-wrapper&quot;&gt;&#039;,
    &#039;#suffix&#039; =&gt; &#039;&lt;/div&gt;&#039;,
  );
  $form[&#039;cars&#039;][&#039;car&#039;] = array(
    &#039;#type&#039; =&gt; &#039;textfield&#039;,
    &#039;#title&#039; =&gt; t(&#039;Favourite car&#039;),
    &#039;#size&#039; =&gt; 36,
    &#039;#default_value&#039; =&gt; $form_state[&#039;values&#039;][&#039;car&#039;],
  );
  $form[&#039;submit&#039;] = array(
    &#039;#type&#039; =&gt; &#039;submit&#039;,
    &#039;#value&#039; =&gt; t(&#039;Submit&#039;),
  );
  return $form;
}</pre>
<p>
<!-- Begin Google Adsense code -->
<script type="text/javascript"><!--
google_ad_client = "pub-8190774722923642";
google_ad_slot = "1689935941";
google_ad_width = 336;
google_ad_height = 280;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
<!-- End Google Adsense code -->
</p>
<p>This is very basic and allows the user to enter one car and submit the form.  We now need to add in the extra functionality of ahah_helper to be able to add mulitple fields.</p>
<pre class="brush: php">function test_form($form_state = NULL) {

  ahah_helper_register($form, $form_state); // Absolutely vital for ahah_helper to do it&#039;s job

  // We check to see if quantity has been set, ie if the form has been submitted yet.  If not, we show 1 field, you can change this to however many fields you want to show up as default.
  if (!isset($form_state[&#039;storage&#039;][&#039;quantity&#039;])) {
    $quantity = 1;
  }
  else {
    // If the form has been submitted we get the quantity that was stored.
    $quantity = $form_state[&#039;storage&#039;][&#039;quantity&#039;];
    // We then do a check to see if the user has clicked the &quot;Add another car&quot; button, if they have we increase the amount by 1.
    if (isset($form_state[&#039;values&#039;][&#039;cars&#039;][&#039;add_more&#039;]) &amp;&amp; $form_state[&#039;values&#039;][&#039;op&#039;] == &#039;Add another car&#039;) {
      $quantity++;
    }
  }

  // We create a hidden form element to store the amount of fields that the user has added.
  $form[&#039;quantity&#039;] = array(
    &#039;#type&#039; =&gt; &#039;value&#039;,
    &#039;#value&#039; =&gt; $quantity,
  );

  $form[&#039;cars&#039;] = array(
    &#039;#type&#039; =&gt; &#039;fieldset&#039;,
    &#039;#title&#039; =&gt; t(&#039;Favourite cars(s)&#039;),
    &#039;#prefix&#039; =&gt; &#039;&lt;div id=&quot;favourite-cars-wrapper&quot;&gt;&#039;,
    &#039;#suffix&#039; =&gt; &#039;&lt;/div&gt;&#039;,
    &#039;#tree&#039; =&gt; TRUE // This is important for ahah_helper.
  );
  // We now do a simple loop, creating however many textfields are defined by $form_state[&#039;storage&#039;][&#039;quantity&#039;]
  for ($i = 1; $i &lt;= $quantity; $i++) {
    // The element name needs to be different for each textfield, otherwise we will only get one value after the form is submitted.
    $form[&#039;cars&#039;][&#039;car_&#039;. $i] = array(
      &#039;#type&#039; =&gt; &#039;textfield&#039;,
      &#039;#title&#039; =&gt; t(&#039;Favourite car&#039;),
      &#039;#size&#039; =&gt; 36,
      &#039;#default_value&#039; =&gt; $form_state[&#039;values&#039;][&#039;cars&#039;][&#039;car_&#039;. $i],
    );
  }

  // We add in a button with the #ahah element which will handle all our work for us.
  $form[&#039;cars&#039;][&#039;add_more&#039;] = array(
    &#039;#type&#039; =&gt; &#039;submit&#039;,
    &#039;#value&#039; =&gt; t(&#039;Add another car&#039;),
    &#039;#ahah&#039; =&gt; array(
      &#039;event&#039; =&gt; &#039;click&#039;, // When the button is &quot;clicked&quot;, AHAH will do it&#039;s job
      &#039;path&#039; =&gt; ahah_helper_path(array(&#039;cars&#039;)), // The array features the wrapper form field. So our form wrapper is $form[&#039;cars&#039;], so we set this to array(&#039;cars&#039;). If your form was $form[&#039;cars&#039;][&#039;another_wrapper&#039;], the path would be array(&#039;cars&#039;, &#039;another_wrapper&#039;).
      &#039;wrapper&#039; =&gt; &#039;favourite-cars-wrapper&#039;, // We then define the wrapper which will be changed.
    ),
  );
  $form[&#039;submit&#039;] = array(
    &#039;#type&#039; =&gt; &#039;submit&#039;,
    &#039;#value&#039; =&gt; t(&#039;Submit&#039;),
  );
  return $form;
}</pre>
<p>So what have we done&#8230;first we added the following line:</p>
<pre class="brush: php">ahah_helper_register($form, $form_state);</pre>
<p>This is a vital function that needs to be present in your form for ahah_helper to do it&#8217;s job.</p>
<p>Next we check to see if the form has been submitted before and if it has, get the amount of textfields that the form had by storing it in a hidden field.  We then do a further check to find out what button was clicked.  If the &#8220;add more&#8221; button was clicked, then we add another textfield by increasing the value of the quantity variable.</p>
<p>A minor, but very important change we make is adding &#8216;#tree&#8217; => TRUE to our wrapper element, this is a requirement for ahah_helper to do it&#8217;s job properly.</p>
<p>
<!-- Begin Google Adsense code -->
<script type="text/javascript"><!--
google_ad_client = "pub-8190774722923642";
google_ad_slot = "1689935941";
google_ad_width = 336;
google_ad_height = 280;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
<!-- End Google Adsense code -->
</p>
<p>Next we use a for loop, to add all our textfields into the form.  This should be self-explanitory but will go in to a bit more depth further on when we talk about the #ahah element.</p>
<p>We added an additional button to the form, this is so that the user can add another field to the form. You don&#8217;t need to worry about javascript degradation as ahah_helper takes care of this.</p>
<p>One attribute of #ahah on the button that isn&#8217;t listed in the form, but is very important, is the &#8220;method&#8221;.  The default value of this is replace, which is what we want. This replaces the whole contents of the wrapper which we define with the data from the path which we defined.  This is why we needed the for loop to recreate the textfields.</p>
<p>To take care of the form when javascript is disabled, you must check which button was pressed when the form was submitted.</p>
<pre class="brush: php">function test_form_submit($form, $form_state) {
  if ($form_state[&#039;values&#039;][&#039;op&#039;] == &#039;Submit&#039;) {
    drupal_set_message(&#039;Submit button clicked&#039;);
  }
  else {
    drupal_set_message(&#039;Add more button clicked&#039;);
  }
}</pre>
<p>With javascript enabled, when clicking the Add more button, Drupal will perform validation on the form, but will not submit the form.  Whereas clicking the submit button will perform validation and submit the form.</p>
]]></content:encoded>
			<wfw:commentRss>http://jamestombs.co.uk/2010-07-08/adding-additional-form-elements-using-ahah_helper-in-drupal-6/1276/feed</wfw:commentRss>
		<slash:comments>25</slash:comments>
		</item>
		<item>
		<title>Display iframed content as a block using Block API</title>
		<link>http://jamestombs.co.uk/2010-07-05/display-iframed-content-as-a-block-using-block-api/1270</link>
		<comments>http://jamestombs.co.uk/2010-07-05/display-iframed-content-as-a-block-using-block-api/1270#comments</comments>
		<pubDate>Mon, 05 Jul 2010 13:21:47 +0000</pubDate>
		<dc:creator>James</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[block api]]></category>
		<category><![CDATA[drupal]]></category>
		<category><![CDATA[drupal planet]]></category>

		<guid isPermaLink="false">http://jamestombs.co.uk/?p=1270</guid>
		<description><![CDATA[This will give a quick look over the code needed to create a block type using Block API to allow users to create new blocks which use an iframe to display content from external sites. This can be useful for widgets that the user wants to display but doesn&#8217;t know HTML, or if the admin [...]]]></description>
			<content:encoded><![CDATA[<p>This will give a quick look over the code needed to create a block type using Block API to allow users to create new blocks which use an iframe to display content from external sites.  This can be useful for widgets that the user wants to display but doesn&#8217;t know HTML, or if the admin wants to add a bit more control rather than allowing too much HTML.</p>
<p>Not every user will understand this:</p>
<pre class="brush: html">&lt;iframe src=&quot;http://drupal.org/&quot; width=&quot;100%&quot; height=&quot;500px&quot; frameborder=&quot;1&quot; scrolling=&quot;no&quot;&gt;&lt;/iframe&gt;</pre>
<p>And will find this much simpler and easier to use:</p>
<p><img src="http://jamestombs.co.uk/wp-content/uploads/2010/07/iframe_block_settings.jpg" alt="" title="iframe_block_settings" width="502" height="551" class="alignnone size-full wp-image-1271" /></p>
<p><span id="more-1270"></span></p>
<p>First off, you need to create a module like you normally would with your .info and .module files.</p>
<p>My module is going to be called iframe_block, so you will need to change this in certain cases if you use a different name.</p>
<pre class="brush: php">name = Iframe Block
description = Add new blocks which contain an iframe of a specified URL.
core = 6.x
dependencies[] = block_api</pre>
<p>That is for the .info file which sets the dependency on block_api.  If block_api isn&#8217;t available then this module can&#8217;t be used.</p>
<p>
<!-- Begin Google Adsense code -->
<script type="text/javascript"><!--
google_ad_client = "pub-8190774722923642";
google_ad_slot = "1689935941";
google_ad_width = 336;
google_ad_height = 280;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
<!-- End Google Adsense code -->
</p>
<p>Our .module file is going to be fairly simple and just hooks in to Block API, using three of the available hooks. But before we use any of the Block API hooks, we need to forwards the Drupal block related calls to the Block API module.</p>
<pre class="brush: php">function iframe_block_block($op = &#039;list&#039;, $delta = 0, $edit = array()) {
  $function = &#039;block_api_block_&#039;. $op;
  return $function(&#039;iframe_block&#039;, $delta, $edit);
}</pre>
<p>This will pass any calls to iframe_block_block() to the Block API module which in turn will add it&#8217;s own hooks which we can take advantage of.</p>
<p>The first one and most important is hook_block_api_info(), which we use to tell Drupal about our block type.</p>
<pre class="brush: php">function iframe_block_block_api_info() {
  $types[&#039;iframe_block&#039;] = array(
    &#039;title&#039; =&gt; t(&#039;Iframe Block&#039;),
    &#039;description&#039; =&gt; t(&#039;Create a block from with content from a specified URL using an iframe.&#039;),
    &#039;storage&#039; =&gt; BLOCK_API_STORAGE_DATABASE,
  );
  return $types;
}</pre>
<p><img src="http://jamestombs.co.uk/wp-content/uploads/2010/07/iframe_block_selection.jpg" alt="" title="iframe block selection" width="559" height="454" class="alignnone size-full wp-image-1272" /></p>
<p>Next we define our form for the user to fill in. The attributes we require are the source (the URL), the height and the width.  I am also going to provide the user the option of overriding the frameborder and scrolling attributes.</p>
<pre class="brush: php">function iframe_block_block_api_form($config, $edit) {
  if ($config[&#039;block_type&#039;] == &#039;iframe_block&#039;) {
    $form[&#039;url&#039;] = array(
      &#039;#type&#039; =&gt; &#039;textfield&#039;,
      &#039;#title&#039; =&gt; t(&#039;URL&#039;),
      &#039;#description&#039; =&gt; t(&#039;The URL of the page you would like to use as the source of the iframe.&#039;),
      &#039;#required&#039; =&gt; TRUE,
      &#039;#default_value&#039; =&gt; $config[&#039;settings&#039;][&#039;url&#039;],
    );
    $form[&#039;width&#039;] = array(
      &#039;#type&#039; =&gt; &#039;textfield&#039;,
      &#039;#title&#039; =&gt; t(&#039;Iframe width&#039;),
      &#039;#description&#039; =&gt; t(&#039;Enter the width of the iframe. Include the measurement type (px, em or %)&#039;),
      &#039;#default_value&#039; =&gt; $config[&#039;settings&#039;][&#039;width&#039;] ? $config[&#039;settings&#039;][&#039;width&#039;] : &#039;100%&#039;,
      &#039;#required&#039; =&gt; TRUE,
      &#039;#size&#039; =&gt; 10,
    );
    $form[&#039;height&#039;] = array(
      &#039;#type&#039; =&gt; &#039;textfield&#039;,
      &#039;#title&#039; =&gt; t(&#039;Iframe height&#039;),
      &#039;#description&#039; =&gt; t(&#039;Enter the height of the iframe. Include the measurement type (px, em or %)&#039;),
      &#039;#default_value&#039; =&gt; $config[&#039;settings&#039;][&#039;height&#039;] ? $config[&#039;settings&#039;][&#039;height&#039;] : &#039;300px&#039;,
      &#039;#required&#039; =&gt; TRUE,
      &#039;#size&#039; =&gt; 10,
    );
    $form[&#039;frameborder&#039;] = array(
      &#039;#type&#039; =&gt; &#039;select&#039;,
      &#039;#title&#039; =&gt; t(&#039;Iframe border&#039;),
      &#039;#description&#039; =&gt; t(&#039;Select whether you want to show a border around the iframe.&#039;),
      &#039;#default_value&#039; =&gt; $config[&#039;settings&#039;][&#039;frameborder&#039;] ? $config[&#039;settings&#039;][&#039;frameborder&#039;] : 0,
      &#039;#required&#039; =&gt; TRUE,
      &#039;#options&#039; =&gt; array(1 =&gt; t(&#039;Show border&#039;), 0 =&gt; t(&#039;Don\&#039;t show a border&#039;)),
    );
    $form[&#039;scrolling&#039;] = array(
      &#039;#type&#039; =&gt; &#039;select&#039;,
      &#039;#title&#039; =&gt; t(&#039;Scrolling&#039;),
      &#039;#description&#039; =&gt; t(&#039;Select whether the iframe should be scrollable or not&#039;),
      &#039;#default_value&#039; =&gt; $config[&#039;settings&#039;][&#039;scrolling&#039;] ? $config[&#039;settings&#039;][&#039;scrolling&#039;] : &#039;auto&#039;,
      &#039;#required&#039; =&gt; TRUE,
      &#039;#options&#039; =&gt; drupal_map_assoc(array(&#039;yes&#039;, &#039;no&#039;, &#039;auto&#039;)),
    );
  }
  return $form;
}</pre>
<p>
<!-- Begin Google Adsense code -->
<script type="text/javascript"><!--
google_ad_client = "pub-8190774722923642";
google_ad_slot = "1689935941";
google_ad_width = 336;
google_ad_height = 280;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
<!-- End Google Adsense code -->
</p>
<p>This will allow the user to set up their iframe by entering the required information. </p>
<p><img src="http://jamestombs.co.uk/wp-content/uploads/2010/07/iframe_block_settings.jpg" alt="" title="Iframe block settings" width="502" height="551" class="alignnone size-full wp-image-1271" /></p>
<p>Finally, we need to hook in to hook_block_api_view() to be able to display our iframe using the users input.</p>
<pre class="brush: php">function iframe_block_block_api_view($config) {
  if ($config[&#039;block_type&#039;] == &#039;iframe_block&#039;) {
    $output = &#039;&lt;iframe src=&quot;&#039;. $config[&#039;settings&#039;][&#039;url&#039;] .&#039;&quot; width=&quot;&#039;. $config[&#039;settings&#039;][&#039;width&#039;] .&#039;&quot; height=&quot;&#039;. $config[&#039;settings&#039;][&#039;height&#039;] .&#039;&quot; frameborder=&quot;&#039;. $config[&#039;settings&#039;][&#039;frameborder&#039;] .&#039;&quot; scrolling=&quot;&#039;. $config[&#039;settings&#039;][&#039;scrolling&#039;] .&#039;&quot;&gt;&#039;. $config[&#039;settings&#039;][&#039;no_iframes&#039;] .&#039;&lt;/iframe&gt;&#039;;
  }
  return array(&#039;content&#039; =&gt; $output);
}</pre>
<p>Very simply we are taking the users input and entering it in to some HTML code to give us the desired output.</p>
<p><a href="http://jamestombs.co.uk/wp-content/uploads/2010/07/iframe_block_view.jpg" rel="shadowbox[post-1270];player=img;"><img src="http://jamestombs.co.uk/wp-content/uploads/2010/07/iframe_block_view-300x257.jpg" alt="" title="Iframe Block View" width="300" height="257" class="alignnone size-medium wp-image-1273" /><br /><small>Click for larger version</small></a></p>
]]></content:encoded>
			<wfw:commentRss>http://jamestombs.co.uk/2010-07-05/display-iframed-content-as-a-block-using-block-api/1270/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Displaying nodes as blocks using Block API</title>
		<link>http://jamestombs.co.uk/2010-07-05/displaying-nodes-as-blocks-using-block-api/1252</link>
		<comments>http://jamestombs.co.uk/2010-07-05/displaying-nodes-as-blocks-using-block-api/1252#comments</comments>
		<pubDate>Mon, 05 Jul 2010 10:31:47 +0000</pubDate>
		<dc:creator>James</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[block api]]></category>
		<category><![CDATA[drupal]]></category>
		<category><![CDATA[drupal planet]]></category>

		<guid isPermaLink="false">http://jamestombs.co.uk/?p=1252</guid>
		<description><![CDATA[Recently I wrote a new module called Block API which allows other modules writers to create modules to develop templates for users to easily create new blocks rather than relying on copying and pasting HTML. The example module included copies the functionality of the core block module. Below I will show how to use Block [...]]]></description>
			<content:encoded><![CDATA[<p>Recently I wrote a new module called <a href="http://jamestombs.co.uk/2010-06-30/new-drupal-module-block-api/1245">Block API</a> which allows other modules writers to create modules to develop templates for users to easily create new blocks rather than relying on copying and pasting HTML.</p>
<p>The example module included copies the functionality of the core block module.  Below I will show how to use Block API to display a specific node as a block with further configuration options available to the user to choose from.<br />
<span id="more-1252"></span><br />
First off, if you just want to download this module to use, you can do so by <a href="http://jamestombs.co.uk/wp-content/uploads/2010/07/node_block.zip">clicking here</a>.</p>
<p>As with any other module, create an info file using whatever module name you want.  The module name I will be using is node_block.</p>
<pre class="brush: php">name = Node Block
description = Add new blocks by using pre-existing nodes.
core = 6.x
dependencies[] = block_api</pre>
<p>In your .module file, we need to first set up the hook to allow Block API to do it&#8217;s job. So our first function will be the following:</p>
<pre class="brush: php">function node_block_block($op = &#039;list&#039;, $delta = 0, $edit = array()) {
  $function = &#039;block_api_block_&#039;. $op;
  return $function(&#039;node_block&#039;, $delta, $edit);
}</pre>
<p>This passes all the hook_block calls through the Block API which then allows users to select your block types through a single interface.</p>
<p><img src="http://jamestombs.co.uk/wp-content/uploads/2010/07/module_block.jpg" alt="" title="Module Block selection through Block API" width="560" height="442" class="alignnone size-full wp-image-1257" /></p>
<p>Next, we need to define our block types that we will provide users.  To do this we use hook_block_api_info().</p>
<pre class="brush: php">function node_block_block_api_info() {
  $types[&#039;node_block&#039;] = array(
    &#039;title&#039; =&gt; t(&#039;Node Block&#039;),
    &#039;description&#039; =&gt; t(&#039;Create a block from a pre-existing node.&#039;),
    &#039;storage&#039; =&gt; BLOCK_API_STORAGE_DATABASE,
  );
  return $types;
}</pre>
<p>This is very simple, and defines the block type.</p>
<p>
<!-- Begin Google Adsense code -->
<script type="text/javascript"><!--
google_ad_client = "pub-8190774722923642";
google_ad_slot = "1689935941";
google_ad_width = 336;
google_ad_height = 280;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
<!-- End Google Adsense code -->
</p>
<p>For this module we are going to allow the user to select a node to display and choose whether to display the full node or just the teaser.  As well as this, we are going to give the administrator the choice of which node types are available to the user to chose nodes from as well as selecting whether users can use unpublished nodes or not.</p>
<p>First we will define the administration form to chose which content types are available.  To do this, we need to use hook_menu() to define our menu item pointing to our form.</p>
<pre class="brush: php">function node_block_menu() {
  $items[&#039;admin/settings/node_block&#039;] = array(
    &#039;access callback&#039; =&gt; &#039;user_access&#039;,
    &#039;access arguments&#039; =&gt; array(&#039;administer blocks&#039;),
    &#039;page callback&#039; =&gt; &#039;drupal_get_form&#039;,
    &#039;page arguments&#039; =&gt; array(&#039;node_block_admin_form&#039;),
    &#039;title&#039; =&gt; &#039;Node Block Configuration Settings&#039;,
    &#039;description&#039; =&gt; &#039;Set the configuration options for Node Blocks.&#039;,
    &#039;type&#039; =&gt; MENU_NORMAL_ITEM,
  );
  return $items;
}</pre>
<p>There is nothing complex here, just a standard menu item.  We now have to create the form node_block_admin_form().</p>
<pre class="brush: php">function node_block_admin_form() {
  $types = node_get_types(&#039;names&#039;);
  $form[&#039;node_block_content_types&#039;] = array(
    &#039;#type&#039; =&gt; &#039;checkboxes&#039;,
    &#039;#title&#039; =&gt; t(&#039;Node types available to create blocks&#039;),
    &#039;#description&#039; =&gt; t(&#039;Set the node types that are allowed to be displayed as blocks.&#039;),
    &#039;#required&#039; =&gt; TRUE,
    &#039;#options&#039; =&gt; $types,
    &#039;#default_value&#039; =&gt; variable_get(&#039;node_block_content_types&#039;, &#039;&#039;),
  );
  $form[&#039;node_block_published_only&#039;] = array(
    &#039;#type&#039; =&gt; &#039;checkbox&#039;,
    &#039;#title&#039; =&gt; t(&#039;Only allow published nodes to be shown as blocks.&#039;),
    &#039;#description&#039; =&gt; t(&#039;By checking this box only published nodes will be available for selection and appear as blocks.&#039;),
    &#039;#default_value&#039; =&gt; variable_get(&#039;node_block_published_only&#039;, 1),
  );
  $form[&#039;node_block_sql_order&#039;] = array(
    &#039;#type&#039; =&gt; &#039;select&#039;,
    &#039;#title&#039; =&gt; t(&#039;Order autocomplete results by&#039;),
    &#039;#description&#039; =&gt; t(&#039;Select the column name to order the autocomplete results by.&#039;),
    &#039;#default_value&#039; =&gt; variable_get(&#039;node_block_sql_order&#039;, &#039;nid&#039;),
    &#039;#required&#039; =&gt; TRUE,
    &#039;#options&#039; =&gt; array(&#039;nid&#039; =&gt; t(&#039;Node ID&#039;), &#039;title&#039; =&gt; t(&#039;Node title&#039;), &#039;type&#039; =&gt; t(&#039;Node type&#039;)),
  );
  $form[&#039;node_block_sql_sort&#039;] = array(
    &#039;#type&#039; =&gt; &#039;select&#039;,
    &#039;#title&#039; =&gt; t(&#039;Order of autocomplete results&#039;),
    &#039;#description&#039; =&gt; t(&#039;The order in which autocomplete results will be ordered.&#039;),
    &#039;#default_value&#039; =&gt; variable_get(&#039;node_block_sql_sort&#039;, &#039;ASC&#039;),
    &#039;#options&#039; =&gt; array(&#039;ASC&#039; =&gt; t(&#039;Ascending&#039;), &#039;DESC&#039; =&gt; t(&#039;Descending&#039;)),
    &#039;#required&#039; =&gt; TRUE,
  );
  $form[&#039;node_block_autocomplete_limit&#039;] = array(
    &#039;#type&#039; =&gt; &#039;textfield&#039;,
    &#039;#title&#039; =&gt; t(&#039;Amount of results to display in autocomplete&#039;),
    &#039;#description&#039; =&gt; t(&#039;Enter the amount of results to appear in the autocomplete when selecting a node.&#039;),
    &#039;#required&#039; =&gt; TRUE,
    &#039;#default_value&#039; =&gt; variable_get(&#039;node_block_autocomplete_limit&#039;, 25),
    &#039;#size&#039; =&gt; 5,
  );
  return system_settings_form($form);
}</pre>
<p>To get a list of nodes types, you can run your own custom SQL query, but it is a lot easier to use Drupal&#8217;s built in node_get_types() function. If you pass along &#8216;types&#8217; as the first argument, you will get a lot more information, but all we need is the node type machine name and the display name.  node_get_types(&#8216;names&#8217;) does exactly this with an associative array with the key being the machine name and the value being the display name.</p>
<p>The rest of the form is very simple, giving the administrator full control over the ordering of the autocomplete which users will select their node from.</p>
<p><img src="http://jamestombs.co.uk/wp-content/uploads/2010/07/admin_settings.jpg" alt="" title="Administration form" width="560" height="601" class="alignnone size-full wp-image-1259" /></p>
<p>
<!-- Begin Google Adsense code -->
<script type="text/javascript"><!--
google_ad_client = "pub-8190774722923642";
google_ad_slot = "1689935941";
google_ad_width = 336;
google_ad_height = 280;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
<!-- End Google Adsense code -->
</p>
<p>We now have our admin form set up, so now it is time to create the configuration form for the users when adding a new block. Again we hook in to the Block API, this time using hook_block_api_form($config, $edit).</p>
<pre class="brush: php">function node_block_block_api_form($config, $edit) {
  if ($config[&#039;block_type&#039;] == &#039;node_block&#039;) {
    $form[&#039;nid&#039;] = array(
      &#039;#type&#039; =&gt; &#039;textfield&#039;,
      &#039;#title&#039; =&gt; t(&#039;Node ID&#039;),
      &#039;#description&#039; =&gt; t(&#039;Start typing the title of the node and select it from the autocomplete list.&#039;),
      &#039;#required&#039; =&gt; TRUE,
      &#039;#default_value&#039; =&gt; $config[&#039;settings&#039;][&#039;nid&#039;],
      &#039;#autocomplete_path&#039; =&gt; &#039;js/node_block/autocomplete&#039;,
    );
    $form[&#039;teaser&#039;] = array(
      &#039;#type&#039; =&gt; &#039;select&#039;,
      &#039;#title&#039; =&gt; t(&#039;Show the Teaser or full node&#039;),
      &#039;#description&#039; =&gt; t(&#039;Select whether you would like just the teaser displayed in the block or the full node.&#039;),
      &#039;#default_value&#039; =&gt; $config[&#039;settings&#039;][&#039;teaser&#039;],
      &#039;#required&#039; =&gt; TRUE,
      &#039;#options&#039; =&gt; array(0 =&gt; t(&#039;Full node&#039;), 1 =&gt; t(&#039;Teaser&#039;)),
    );
  }
  return $form;
}</pre>
<p>Here we give the user two options.  The first is an autocomplete field to select the node and the second being a simple checkbox allowing the user to select whether they want to show the teaser of the node or the full node.</p>
<p><img src="http://jamestombs.co.uk/wp-content/uploads/2010/07/block_settings.jpg" alt="" title="Block API - Block settings form" width="544" height="432" class="alignnone size-full wp-image-1258" /></p>
<p>To get the autocomplete working, we need to set up our autocomplete menu item and function to run the search query.</p>
<p>In your existing hook_menu(), add the following to create a menu callback for our autocomplete textfield.</p>
<pre class="brush: php">$items[&#039;js/node_block/autocomplete&#039;] = array(
    &#039;page callback&#039; =&gt; &#039;node_block_js_autocomplete&#039;,
    &#039;access callback&#039; =&gt; TRUE,
    &#039;type&#039; =&gt; MENU_CALLBACK,
  );</pre>
<p>A very simple callback, no need for a title or description and access is open to everyone, although you could limit it to the users who are able to create blocks.</p>
<p>Next we need to set up the SQL query that will fetch the nodes based on the users input.</p>
<pre class="brush: php">function node_block_js_autocomplete() {
  $str = $_POST[&#039;nid&#039;];
  $sql = &quot;SELECT nid, title FROM {node} WHERE LOWER(title) LIKE LOWER(&#039;%%%s%%&#039;)&quot;;
  foreach (variable_get(&#039;node_block_content_types&#039;, &#039;&#039;) as $type =&gt; $value) {
    if (strlen($value) &gt; 1) $types[] = &#039;&quot;&#039;. $type .&#039;&quot;&#039;;
  }
  $sql .= &quot; AND type IN (&quot;. implode(&quot;, &quot;, $types) .&quot;)&quot;;
  if (variable_get(&#039;node_block_published_only&#039;, 1) == 1) {
    $sql .= &quot; AND status = 1&quot;;
  }
  $sql .= &quot; ORDER BY &quot;. variable_get(&#039;node_block_sql_order&#039;, &#039;nid&#039;) .&quot; &quot;. variable_get(&#039;node_block_sql_sort&#039;, &#039;ASC&#039;);
  $sql .= &quot; LIMIT 0, &quot;. variable_get(&#039;node_block_autocomplete_limit&#039;, 25);
  $query = db_query($sql, filter_xss($str));
  $results = array();
  while ($data = db_fetch_object($query)) {
    $results[$data-&gt;nid] = check_plain($data-&gt;title);
  }
  print drupal_to_js($results);
}</pre>
<p>We get the users current inputted text from $_POST and set up the basic SQL. As we gave the administrator the chance to limit the options available, we must now apply those filters. First we make sure the query only gets results for the right content types, then check for only published nodes if defined by the administrator. The next few lines are for the autocomplete ordering and limiting the amount of results.</p>
<p>
<!-- Begin Google Adsense code -->
<script type="text/javascript"><!--
google_ad_client = "pub-8190774722923642";
google_ad_slot = "1689935941";
google_ad_width = 336;
google_ad_height = 280;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
<!-- End Google Adsense code -->
</p>
<p>We now have our two admin forms configured, the only bit remaining is showing the block on the page.  This is done by using hook_block_api_view().</p>
<pre class="brush: php">function node_block_block_api_view($config) {
  if ($config[&#039;block_type&#039;] == &#039;node_block&#039;) {
    $node = node_load($config[&#039;settings&#039;][&#039;nid&#039;]);
    if ($node-&gt;status == 0 &amp;&amp; variable_get(&#039;node_block_published_only&#039;, 1) == 1) return FALSE;
    $output = node_view($node, $config[&#039;settings&#039;][&#039;teaser&#039;] == 1 ? TRUE : FALSE);
  }
  return array(&#039;content&#039; =&gt; $output);
}</pre>
<p>First, we load the node using the NID saved from our form by Block API.  It is probably best to add some code in to make sure that a node ID has been saved either at view stage or when saving the block.</p>
<p>Next we make sure the node is not unpublished if the administrator has defined that only published nodes can be shown as blocks.</p>
<p>Then we use the function node_view() to display the node. The second argument is the $teaser argument. If TRUE it will display the teaser of the node, otherwise the full node will be published.</p>
<p><a href="http://jamestombs.co.uk/wp-content/uploads/2010/07/block_view.jpg" rel="shadowbox[post-1252];player=img;"><img src="http://jamestombs.co.uk/wp-content/uploads/2010/07/block_view-300x163.jpg" alt="" title="Block API - Block View" width="300" height="163" class="alignnone size-medium wp-image-1260" /><br /><small>Click for larger image</small></a></p>
<p>You may also want to hide the node block if you are viewing the node page itself, so adding a line after the status line such as:</p>
<pre class="brush: php">if (arg(0) == &#039;node&#039; &amp;&amp; arg(1) == $config[&#039;settings&#039;][&#039;nid&#039;]) return FALSE;</pre>
<p>And that is it.  You will now be able to create blocks </p>
]]></content:encoded>
			<wfw:commentRss>http://jamestombs.co.uk/2010-07-05/displaying-nodes-as-blocks-using-block-api/1252/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Create a multi-step moderation process in Drupal 6</title>
		<link>http://jamestombs.co.uk/2010-06-30/create-a-multi-step-moderation-process-in-drupal-6/1189</link>
		<comments>http://jamestombs.co.uk/2010-06-30/create-a-multi-step-moderation-process-in-drupal-6/1189#comments</comments>
		<pubDate>Wed, 30 Jun 2010 14:02:25 +0000</pubDate>
		<dc:creator>James</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[drupal]]></category>
		<category><![CDATA[drupal planet]]></category>
		<category><![CDATA[tutorial]]></category>

		<guid isPermaLink="false">http://jamestombs.co.uk/?p=1189</guid>
		<description><![CDATA[This will guide you through creating a multi-step process of content moderation in Drupal 6. This is a follow on to the guide on Drupal.org about creating a revisioning system and the follow on, on creating a revisioning system with state-based access. Both of which only allow a single step revisioning sytem, i.e. Author creates [...]]]></description>
			<content:encoded><![CDATA[<p>This will guide you through creating a multi-step process of content moderation in Drupal 6. This is a follow on to the guide on Drupal.org about creating a <a href="http://drupal.org/node/408968">revisioning system</a> and the follow on, on creating a <a href="http://drupal.org/node/408052">revisioning system with state-based access</a>. Both of which only allow a single step revisioning sytem, i.e. Author creates content, moderator either edits and publishes or sends back to author to edit.</p>
<h3>Scenario</h3>
<p>A user submits a piece of content, we will refer to this user as the author. The content is not published and is sent to another user for moderation, we will refer to this user as the moderator.</p>
<p>The moderator can then either set the content from a moderation state back to a draft state for the author to amend or through to a &#8220;to be published state&#8221;.</p>
<p>Once the moderator has checked the content and made amends they can mark the content as ready for publishing.  At which point a third user which we will refer to as the publisher, can make further amends to the content and publish it, make further amends and send back to the moderator to check through the changes or mark the content as back to draft to allow the author to change it.<br />
<span id="more-1189"></span></p>
<h3>Required modules</h3>
<p>A few contributed modules are required to get this process in place as well as a couple of core modules.</p>
<ul>
<li>Trigger (Core, optional)</li>
<li>Profile (Core)</li>
<li><a href="http://drupal.org/project/module_grants">Module Grants</a> (Contrib)</li>
<li><a href="http://drupal.org/project/smart_menus">Smart tabs</a> (Contrib)</li>
<li><a href="http://drupal.org/project/revisioning">Revisioning</a> (Contrib)</li>
<li><a href="http://drupal.org/project/token">Token</a> (Contrib)</li>
<li><a href="http://drupal.org/project/workflow">Workflow</a> (Contrib)</li>
<li><a href="http://drupal.org/project/diff">Diff</a> (Contrib, optional)</li>
</ul>
<p>The <a href="http://drupal.org/project/diff">Diff module</a> is optional, but can be useful to easily see what parts of the content have changed from each revision.</p>
<h3>Enable modules</h3>
<p>Some of the modules have sub-modules which come with the main module, so be sure to check all the required modules, which are:</p>
<ul>
<li>Module Grants</li>
<li>Module Grants Monitor (Optional)</li>
<li>Node Tools</li>
<li>User Tools</li>
<li>Profile</li>
<li>Trigger (Optional)</li>
<li>Smart tabs</li>
<li>Diff (Optional)</li>
<li>Revisioning</li>
<li>Token</li>
<li>Token actions</li>
<li>Workflow</li>
<li>Workflow access</li>
</ul>
<p>If you already have content on your site, you will also need to download and install <a href="http://drupal.org/project/workflow_post_install">Workflow Post Install</a>, otherwise all old content may only be accessible by administrator.</p>
<h3>Create user roles</h3>
<p>You can have as many different roles to allow more fine grained control over who can create what content types, but to try and keep this tutorial as simple as possible, I will stick to the three main roles defined in the scenario.</p>
<ul>
<li>Author</li>
<li>Moderator</li>
<li>Publisher</li>
</ul>
<p>It may be best to give your author role a different role name as the Workflow module automatically adds a line in the admin for &#8220;author&#8221; which applies to any role creating content.</p>
<p>Go to Administer &gt; User management &gt; Roles (admin/user/roles).</p>
<p>Then add your three roles, I will be using author role, moderator role and publisher role.</p>
<p><img src="http://jamestombs.co.uk/wp-content/uploads/2010/06/roles.jpg" alt="" title="User roles" width="470" height="198" class="alignnone size-full wp-image-1194" /></p>
<h3>Set up workflow settings</h3>
<p>Go to Administer &gt; Site building &gt; Workflow (admin/build/workflow).</p>
<p>Create a new Workflow and call it <strong>Moderation</strong>. </p>
<p>In the <strong>State name</strong> box, enter <em>in draft</em> and set the <strong>weight</strong> to <em>-10</em>. Save the state.</p>
<p>Once the state has saved, click the <strong>List</strong> tab and click the <strong>Add state</strong> link.</p>
<p>Add the following states:</p>
<ul>
<li>in moderation (weight: -2)</li>
<li>is moderated (weight: 2)</li>
<li>live (weight: 10)</li>
</ul>
<p><img src="http://jamestombs.co.uk/wp-content/uploads/2010/06/workflow_states.jpg" alt="" title="Workflow states" width="428" height="238" class="alignnone size-full wp-image-1197" /></p>
<p>Underneath your states, you can apply the workflow to separate content types. I will be applying it to both the default content types (Page and Story).</p>
<p><img src="http://jamestombs.co.uk/wp-content/uploads/2010/06/workflow_content-types.jpg" alt="" title="Workflow content types" width="470" height="181" class="alignnone size-full wp-image-1198" /></p>
<p>Next to the Moderation workflow, click the <strong>Edit</strong> link.</p>
<p>This page may seem a little daunting at first, but don&#8217;t panic. The first set of checkboxes allow you to set out which roles can transition the node between certain states. You will also see the extra &#8220;author&#8221; role that I refered to earlier.</p>
<p>The first row is for the original creation of the node.  This is the transition from the <strong>(creation)</strong> state to the <strong>in draft</strong> state. The only role we are giving access to this is the Workflow defined author, note that this is not the author role that we created.</p>
<p><a href="http://jamestombs.co.uk/wp-content/uploads/2010/06/workflow-creation_to_draft.jpg" rel="shadowbox[post-1189];player=img;"><img src="http://jamestombs.co.uk/wp-content/uploads/2010/06/workflow-creation_to_draft-300x64.jpg" alt="" title="Workflow: Creation to draft" width="300" height="64" class="alignnone size-medium wp-image-1206" /><br /><small>Click for larger version</small></a></p>
<p>The next transition is from being <strong>in draft</strong> to <strong>in moderation</strong>. For this transition, we want to set this to our author role as opposed to the workflow defined author.</p>
<p><a href="http://jamestombs.co.uk/wp-content/uploads/2010/06/workflow-draft_to_moderation.jpg" rel="shadowbox[post-1189];player=img;"><img src="http://jamestombs.co.uk/wp-content/uploads/2010/06/workflow-draft_to_moderation-300x64.jpg" alt="" title="Workflow: Draft to moderation" width="300" height="64" class="alignnone size-medium wp-image-1207" /><br /><small>Click for larger version</small></a></p>
<p>The next transition is from <strong>in moderation</strong> to <strong>is moderated</strong>.  This is our moderation step where the content is moderated prior to being sent back to the author for further amends or to the publisher for final approval and publishing. We want to set the moderator role under <strong>in draft</strong> and <strong>is moderated</strong>.</p>
<p><a href="http://jamestombs.co.uk/wp-content/uploads/2010/06/workflow-moderation_to_moderated.jpg" rel="shadowbox[post-1189];player=img;"><img src="http://jamestombs.co.uk/wp-content/uploads/2010/06/workflow-moderation_to_moderated-300x64.jpg" alt="" title="Workflow: Moderation to moderated" width="300" height="64" class="alignnone size-medium wp-image-1208" /><br /><small>Click for larger version</small></a></p>
<p>Next is the step from being moderated to going to the publisher.  There are some optional transitions that you can put in here, depending on how you want to work.  The one that everyone would need is the transition from <strong>is moderated</strong> to <strong>live</strong>. The one that will differ is for rejections. Some people will want it to go back to draft, whereas others will want it to go back to moderator, others will want both options. This way if there isn&#8217;t a major problem, the content can be sent back to the moderator for further moderation rather than having to go back to the author only to be sent back to the moderator.</p>
<p><a href="http://jamestombs.co.uk/wp-content/uploads/2010/06/workflow-moderated_to_live.jpg" rel="shadowbox[post-1189];player=img;"><img src="http://jamestombs.co.uk/wp-content/uploads/2010/06/workflow-moderated_to_live-300x64.jpg" alt="" title="Workflow: Moderated to live" width="300" height="64" class="alignnone size-medium wp-image-1209" /><br /><small>Click for larger version</small></a></p>
<p>The final transition is from the <strong>live</strong> state. The only role that needs this is our author role (not the workflow author role) to be able to take the content back to <strong>in draft</strong>. This will not change the live copy, but create an unpublished revision which we will set up in the next part of the tutorial.</p>
<p><a href="http://jamestombs.co.uk/wp-content/uploads/2010/06/workflow-live.jpg" rel="shadowbox[post-1189];player=img;"><img src="http://jamestombs.co.uk/wp-content/uploads/2010/06/workflow-live-300x64.jpg" alt="" title="Workflow: Live" width="300" height="64" class="alignnone size-medium wp-image-1210" /><br /><small>Click for larger version</small></a></p>
<p>After the checkboxes, in the Comment for Workflow Log section, make sure both boxes are ticked to show a comment form in the Workflow and node edit screens to allow the roles to add their comments for the next role to read to understand why the amends were rejected or what was changed.</p>
<p><img src="http://jamestombs.co.uk/wp-content/uploads/2010/06/workflow-comments.jpg" alt="" title="Workflow: Comments" width="507" height="214" class="alignnone size-full wp-image-1213" /></p>
<p>In the <strong>Workflow tab permissions</strong>, check our three roles.</p>
<p><img src="http://jamestombs.co.uk/wp-content/uploads/2010/06/workflow-tab_permissions.jpg" alt="" title="Workflow: Tab permissions" width="507" height="250" class="alignnone size-full wp-image-1214" /></p>
<p>Next we have the Access control section.  These permissions allow you to set permissions to certain roles based on the state of the content (in draft, in moderation, is moderated, live). Take in to account that these permissions will be overridden by some of the permissions in the User management &gt; Permissions page which we will get on to later.</p>
<p>In the sections for each state, the <em>anonymous user</em> and <em>authenticated user</em> should stay ticked under <strong>Roles who can view posts in this state</strong>.</p>
<p>Under <strong>in draft</strong>, check our <strong>author role</strong> for <strong>Roles who can edit posts in this state</strong>.</p>
<p><a href="http://jamestombs.co.uk/wp-content/uploads/2010/06/workflow-access-in_draft.jpg" rel="shadowbox[post-1189];player=img;"><img src="http://jamestombs.co.uk/wp-content/uploads/2010/06/workflow-access-in_draft-300x118.jpg" alt="" title="Workflow: Access control: In draft" width="300" height="118" class="alignnone size-medium wp-image-1215" /><br /><small>Click for larger version</small></a></p>
<p>Under <strong>in moderation</strong>, check our <strong>moderator role </strong>for <strong>Roles who can edit posts in this state</strong>.</p>
<p><a href="http://jamestombs.co.uk/wp-content/uploads/2010/06/workflow-access-in_moderation.jpg" rel="shadowbox[post-1189];player=img;"><img src="http://jamestombs.co.uk/wp-content/uploads/2010/06/workflow-access-in_moderation-300x118.jpg" alt="" title="Workflow: Access control: In moderation" width="300" height="118" class="alignnone size-medium wp-image-1216" /><br /><small>Click for larger version</small></a></p>
<p>Under <strong>is moderated</strong>, check our <strong>publisher role</strong> for <strong>Roles who can edit posts in this state</strong>.<br />
<a href="http://jamestombs.co.uk/wp-content/uploads/2010/06/workflow-access-is_moderated.jpg" rel="shadowbox[post-1189];player=img;"><img src="http://jamestombs.co.uk/wp-content/uploads/2010/06/workflow-access-is_moderated-300x118.jpg" alt="" title="Workflow: Access control: Is moderated" width="300" height="118" class="alignnone size-medium wp-image-1217" /><br /><small>Click for larger version</small></a></p>
<p>Leave the live state with only the default view options checked.</p>
<p>Press <strong>Save</strong>.<br />

<!-- Begin Google Adsense code -->
<script type="text/javascript"><!--
google_ad_client = "pub-8190774722923642";
google_ad_slot = "1689935941";
google_ad_width = 336;
google_ad_height = 280;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
<!-- End Google Adsense code -->
</p>
<h3>Configure content types</h3>
<p>Go to Administer &gt; Content management &gt; Content types (admin/content/types).</p>
<p>Click the <strong>Edit</strong> link next to the content type you wish you apply the moderation workflow.</p>
<p>Under the <strong>Workflow settings</strong>, uncheck the <strong>Published</strong> box as we don&#8217;t want to publish the content until it has been moderated and approved.</p>
<p>Check both the <strong>Create new revision</strong> and <strong>New revision in draft, pending moderation (requires &#8220;Create new revision&#8221;)</strong> boxes to create a revision for each modification of the content.</p>
<p>Under <strong>Create new revision</strong>, it is up to you what setting you use, but remember to read the description text below the options.</p>
<p><a href="http://jamestombs.co.uk/wp-content/uploads/2010/06/workflow-settings.jpg" rel="shadowbox[post-1189];player=img;"><img src="http://jamestombs.co.uk/wp-content/uploads/2010/06/workflow-settings-300x217.jpg" alt="" title="Content types: Workflow settings" width="300" height="217" class="alignnone size-medium wp-image-1218" /><br /><small>Click here for larger version</small></a></p>
<p>If you have the Diff module enabled, you will get the additional option <strong>Show Preview changes button on node edit form</strong> which will allow you to see the difference between the current edits and the current revision.</p>
<p>Repeat this step for all content types that you wish to have moderation enabled for.<br />

<!-- Begin Google Adsense code -->
<script type="text/javascript"><!--
google_ad_client = "pub-8190774722923642";
google_ad_slot = "1689935941";
google_ad_width = 336;
google_ad_height = 280;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
<!-- End Google Adsense code -->
</p>
<h3>Set up user permissions</h3>
<p>Go to Administer &gt; User management &gt; Permissions (admin/user/permissions).</p>
<p>Under the <strong>module_grants_monitor module</strong> section. Tick the boxes <strong>access All tab</strong>, <strong>access I Can Edit tab</strong> and <strong>access I Can View tab</strong> for the <strong>moderator role</strong>. For the publisher role, you can tick the same boxes plus <strong>access Published tab</strong> and <strong>access Unpublished tab</strong>.</p>
<p><a href="http://jamestombs.co.uk/wp-content/uploads/2010/06/permissions-module_grants_monitor.jpg" rel="shadowbox[post-1189];player=img;"><img src="http://jamestombs.co.uk/wp-content/uploads/2010/06/permissions-module_grants_monitor-300x109.jpg" alt="" title="Permissions: Module_grants_monitor" width="300" height="109" class="alignnone size-medium wp-image-1221" /><br /><small>Click for larger version</small></a></p>
<p>Under <strong>node module</strong>, make sure <strong>anonymous user</strong> and <strong>authenticated user</strong> are both checked for <strong>access content</strong>.</p>
<p>For <strong>author role</strong>, tick the boxes to allow them to create content of selected content types as well as being able to edit their own content.</p>
<p>For the <strong>moderator</strong> and <strong>publisher roles</strong>, allow them to edit any content as well as view or revert any revisions, but if you want further control over this, you can set this later on in the revisioning section.</p>
<p><a href="http://jamestombs.co.uk/wp-content/uploads/2010/06/permissions-node.jpg" rel="shadowbox[post-1189];player=img;"><img src="http://jamestombs.co.uk/wp-content/uploads/2010/06/permissions-node-300x215.jpg" alt="" title="Permissions: Node" width="300" height="215" class="alignnone size-medium wp-image-1222" /><br /><small>Click for larger version</small></a></p>
<p>Under <strong>revisioning module</strong>, give the <strong>author role</strong> the ability to <strong>view revision status messages</strong> and to <strong>edit revisions of their own content</strong>. Moderators should have permission to <strong>access Pending tab</strong>, <strong>edit revisions</strong> and <strong>view revision status messages</strong>. The <strong>publisher role</strong> should have the same permissions as the <strong>moderator role</strong>, but should also have <strong>unpublish current revisio</strong>n and <strong>publish revisions</strong>.</p>
<p><a href="http://jamestombs.co.uk/wp-content/uploads/2010/06/permissions-revisioning.jpg" rel="shadowbox[post-1189];player=img;"><img src="http://jamestombs.co.uk/wp-content/uploads/2010/06/permissions-revisioning-300x173.jpg" alt="" title="Permissions: Revisioning" width="300" height="173" class="alignnone size-medium wp-image-1226" /><br /><small>Click for larger version</small></a></p>
<p>Press Save.</p>
<h3>Set up email triggers</h3>
<p>For information on setting up and using <a href="http://drupal.org/node/199254">Triggers and Actions in Drupal 6</a>, it is best to read the excellent page on the Drupal.org website at <a href="http://drupal.org/node/199254">http://drupal.org/node/199254</a></p>
]]></content:encoded>
			<wfw:commentRss>http://jamestombs.co.uk/2010-06-30/create-a-multi-step-moderation-process-in-drupal-6/1189/feed</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>New Drupal module &#8211; Block API</title>
		<link>http://jamestombs.co.uk/2010-06-30/new-drupal-module-block-api/1245</link>
		<comments>http://jamestombs.co.uk/2010-06-30/new-drupal-module-block-api/1245#comments</comments>
		<pubDate>Wed, 30 Jun 2010 13:25:31 +0000</pubDate>
		<dc:creator>James</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[block api]]></category>
		<category><![CDATA[drupal]]></category>
		<category><![CDATA[drupal planet]]></category>

		<guid isPermaLink="false">http://jamestombs.co.uk/?p=1245</guid>
		<description><![CDATA[I have created a new module for Drupal 6 called Block API which is available on Drupal.org. Block API is a new module I have developed for Drupal 6 which gives greater control over block templates much like you do with nodes. More information is available on my Block API page under Projects. Developer information [...]]]></description>
			<content:encoded><![CDATA[<p>I have created a new module for Drupal 6 called <a href="http://drupal.org/project/block_api">Block API</a> which is available on <a href="http://drupal.org/project/block_api">Drupal.org</a>.</p>
<blockquote><p>Block API is a new module I have developed for Drupal 6 which gives greater control over block templates much like you do with nodes.</p></blockquote>
<p>More information is available on my <a href="http://jamestombs.co.uk/projects/block-api-module-drupal">Block API</a> page under <a href="http://jamestombs.co.uk/projects">Projects</a>.</p>
<p>Developer information on how to use the module is available on the <a href="http://jamestombs.co.uk/projects/block-api-module-drupal/block-api-developers-information">Block API Developer information</a> page.</p>
<p>
<!-- Begin Google Adsense code -->
<script type="text/javascript"><!--
google_ad_client = "pub-8190774722923642";
google_ad_slot = "1689935941";
google_ad_width = 336;
google_ad_height = 280;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
<!-- End Google Adsense code -->
</p>
]]></content:encoded>
			<wfw:commentRss>http://jamestombs.co.uk/2010-06-30/new-drupal-module-block-api/1245/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>New Hosting</title>
		<link>http://jamestombs.co.uk/2010-06-25/new-hosting/1187</link>
		<comments>http://jamestombs.co.uk/2010-06-25/new-hosting/1187#comments</comments>
		<pubDate>Fri, 25 Jun 2010 22:11:51 +0000</pubDate>
		<dc:creator>James</dc:creator>
				<category><![CDATA[Other]]></category>

		<guid isPermaLink="false">http://jamestombs.co.uk/?p=1187</guid>
		<description><![CDATA[If you are seeing this post, it means you are being served through the new hosting from DamnVPS soon to be ThrustVPS. They offer very good VPS packages which are very fast for a very good price and allow a lot of customisation with some excellent backend configuration options.]]></description>
			<content:encoded><![CDATA[<p>If you are seeing this post, it means you are being served through the new hosting from <a href="https://clients.damnvps.com/aff.php?aff=043">DamnVPS</a> soon to be <a href="https://clients.damnvps.com/aff.php?aff=043">ThrustVPS</a>.</p>
<p>They offer very good VPS packages which are very fast for a very good price and allow a lot of customisation with some excellent backend configuration options.</p>
]]></content:encoded>
			<wfw:commentRss>http://jamestombs.co.uk/2010-06-25/new-hosting/1187/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Create a burst of light in Photoshop using filters</title>
		<link>http://jamestombs.co.uk/2010-06-23/create-a-burst-of-light-in-photoshop-using-filters/1174</link>
		<comments>http://jamestombs.co.uk/2010-06-23/create-a-burst-of-light-in-photoshop-using-filters/1174#comments</comments>
		<pubDate>Wed, 23 Jun 2010 15:33:17 +0000</pubDate>
		<dc:creator>James</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[photoshop]]></category>
		<category><![CDATA[tutorial]]></category>

		<guid isPermaLink="false">http://jamestombs.co.uk/?p=1174</guid>
		<description><![CDATA[This tutorial will show you how to create a burst of light in Photoshop using the basic filters provided with Photoshop. Step 1: Create a new canvas and fill the background with black (#000000) Open Photoshop and create a new canvas, whatever dimensions you want to use, I am using 500&#215;500. Fill the background layer [...]]]></description>
			<content:encoded><![CDATA[<p>This tutorial will show you how to create a burst of light in Photoshop using the basic filters provided with Photoshop.</p>
<p><img src="http://jamestombs.co.uk/wp-content/uploads/2010/06/resutl1-150x150.jpg" alt="" title="Final - Blue" width="150" height="150" class="alignnone size-thumbnail wp-image-1182" /> <img src="http://jamestombs.co.uk/wp-content/uploads/2010/06/burst-150x150.jpg" alt="" title="Final" width="150" height="150" class="alignnone size-thumbnail wp-image-1179" /></p>
<p><span id="more-1174"></span></p>
<h3>Step 1: Create a new canvas and fill the background with black (#000000)</h3>
<p>Open Photoshop and create a new canvas, whatever dimensions you want to use, I am using 500&#215;500.</p>
<p>Fill the background layer with black (#0000000).</p>
<p>
<!-- Begin Google Adsense code -->
<script type="text/javascript"><!--
google_ad_client = "pub-8190774722923642";
google_ad_slot = "1689935941";
google_ad_width = 336;
google_ad_height = 280;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
<!-- End Google Adsense code -->
</p>
<h3>Step 2: Create the initial burst of light</h3>
<p>Set the foreground colour to white (#ffffff) (you can do this by pressing <strong>d</strong> on the keyboard to reset the foreground and background colours then pressing <strong>x</strong> to switch the foreground and background).</p>
<p>Now select the <strong>Gradient tool</strong> and set the gradient to be foreground to transparent and set to a radial gradient.</p>
<p><img src="http://jamestombs.co.uk/wp-content/uploads/2010/06/gradient.jpg" alt="" title="Gradient tool options" width="268" height="125" class="alignnone size-full wp-image-1175" /></p>
<p>Now draw a radial gradient from the center of the document on a new layer.</p>
<p><img src="http://jamestombs.co.uk/wp-content/uploads/2010/06/radial-gradient.jpg" alt="" title="Radial gradient" width="500" height="500" class="alignnone size-full wp-image-1176" /></p>
<p>Next create another layer. Go to <strong>Filters</strong> &gt; <strong>Render</strong> &gt; <strong>Clouds</strong>. Set the layer blend mode in the layers panel to <strong>Soft Light</strong>.</p>
<p><img src="http://jamestombs.co.uk/wp-content/uploads/2010/06/layers-panel.jpg" alt="" title="Layers panel" width="236" height="196" class="alignnone size-full wp-image-1177" /></p>
<p>
<!-- Begin Google Adsense code -->
<script type="text/javascript"><!--
google_ad_client = "pub-8190774722923642";
google_ad_slot = "1689935941";
google_ad_width = 336;
google_ad_height = 280;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
<!-- End Google Adsense code -->
</p>
<p>With the same layer still selected, go to <strong>Filters</strong> &gt; <strong>Artistic</strong> &gt; <strong>Plastic Wrap</strong>. You will need to play around with the settings here to get your desired result, I will leave them as the defaults.</p>
<p>Next, go to <strong>Filters</strong> &gt; <strong>Blur</strong> &gt; <strong>Radial Blur</strong>. Set the <strong>Amount</strong> to <em>100</em> and the <strong>Blur Method</strong> to <em>Zoom</em>.</p>
<p><img src="http://jamestombs.co.uk/wp-content/uploads/2010/06/radial-blur.jpg" alt="" title="Radial Blur Settings" width="317" height="261" class="alignnone size-full wp-image-1178" /></p>
<p>Click OK to apply the blur.<br />

<!-- Begin Google Adsense code -->
<script type="text/javascript"><!--
google_ad_client = "pub-8190774722923642";
google_ad_slot = "1689935941";
google_ad_width = 336;
google_ad_height = 280;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
<!-- End Google Adsense code -->
</p>
<h3>Step 3: Add colour to the burst</h3>
<p>Create another layer and fill it with whatever colour you want the burst to be. I am using #8dc63f. Set the layers blend mode in the layers panel to <strong>Colour</strong>. Lower the opacity to 60-80% to get more detail from the burst.</p>
<p><strong>Result</strong></p>
<p><img src="http://jamestombs.co.uk/wp-content/uploads/2010/06/burst.jpg" alt="" title="Final" width="500" height="500" class="alignnone size-full wp-image-1179" /></p>
]]></content:encoded>
			<wfw:commentRss>http://jamestombs.co.uk/2010-06-23/create-a-burst-of-light-in-photoshop-using-filters/1174/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Create a glossy button in Photoshop</title>
		<link>http://jamestombs.co.uk/2010-06-23/create-a-glossy-button-in-photoshop/1161</link>
		<comments>http://jamestombs.co.uk/2010-06-23/create-a-glossy-button-in-photoshop/1161#comments</comments>
		<pubDate>Wed, 23 Jun 2010 10:11:38 +0000</pubDate>
		<dc:creator>James</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[photoshop]]></category>
		<category><![CDATA[tutorial]]></category>

		<guid isPermaLink="false">http://jamestombs.co.uk/?p=1161</guid>
		<description><![CDATA[This tutorial will teach you how to create a glossy button that is reusable by using Layer styles. Layer styles are not available in some older versions of Photoshop and Photoshop Elements. Step 1: Create a new canvas and create a new layer In Photoshop, create a new canvas and add a layer. In this [...]]]></description>
			<content:encoded><![CDATA[<p>This tutorial will teach you how to create a glossy button that is reusable by using <strong>Layer styles</strong>. Layer styles are not available in some older versions of Photoshop and Photoshop Elements.</p>
<p><img src="http://jamestombs.co.uk/wp-content/uploads/2010/06/glossy-final.jpg" alt="" title="Finished result" width="300" height="120" class="alignnone size-full wp-image-1162" /><br />
<span id="more-1161"></span></p>
<h3>Step 1: Create a new canvas and create a new layer</h3>
<p>In Photoshop, create a new canvas and add a layer. In this layer draw a rectangular shape using the marquee tool while leaving a small space around the canvas border.</p>
<p><img src="http://jamestombs.co.uk/wp-content/uploads/2010/06/marquee.jpg" alt="" title="Select a rectangle using the marquee tool" width="167" height="88" class="alignnone size-full wp-image-1163" /></p>
<p>Fill this shape with white on the new layer.</p>
<p>
<!-- Begin Google Adsense code -->
<script type="text/javascript"><!--
google_ad_client = "pub-8190774722923642";
google_ad_slot = "1689935941";
google_ad_width = 336;
google_ad_height = 280;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
<!-- End Google Adsense code -->
</p>
<h3>Step 2: Set the layer styles</h3>
<p>Right click the layer and select <strong>Blending Options</strong>.</p>
<p>Tick <strong>Outer Glow</strong> and set the <strong>Blend Mode</strong> to <em>Normal</em> and the <strong>Colour</strong> to <em>black (#000000)</em> and lower that <strong>Opacity</strong> to <em>10%</em>. In the <strong>Elements</strong> section, change the <strong>Size</strong> to <em>10px</em>.</p>
<p><img src="http://jamestombs.co.uk/wp-content/uploads/2010/06/outerglow.jpg" alt="" title="Outer Glow Blending Options" width="600" height="441" class="alignnone size-full wp-image-1164" /></p>
<p>Next tick <strong>Inner Glow</strong> and set the <strong>Blend Mode</strong> to <em>Normal</em> and the <strong>Colour</strong> to <em>white (#ffffff)</em> and set the <strong>Opacity</strong> to <em>40%</em>. In the <strong>Elements</strong> section, change the <strong>Size</strong> to <em>15px</em>.</p>
<p><img src="http://jamestombs.co.uk/wp-content/uploads/2010/06/innerglow.jpg" alt="" title="Inner Glow Blending Options" width="600" height="441" class="alignnone size-full wp-image-1165" /></p>
<p>Next select <strong>Gradient Overlay</strong>, leave all the settings at their defaults, but change to the <strong>Gradient</strong> to the colour you want.  In this example I have chosen #ec2f03 to #c02502.</p>
<p><img src="http://jamestombs.co.uk/wp-content/uploads/2010/06/gradientoverlay.jpg" alt="" title="Gradient Overlay Blending Options" width="600" height="441" class="alignnone size-full wp-image-1166" /></p>
<p>
<!-- Begin Google Adsense code -->
<script type="text/javascript"><!--
google_ad_client = "pub-8190774722923642";
google_ad_slot = "1689935941";
google_ad_width = 336;
google_ad_height = 280;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
<!-- End Google Adsense code -->
</p>
<p>Finally, tick the <strong>Stroke</strong> checkbox, and lower the <strong>Size</strong> to <em>2px</em> and the <strong>Position</strong> to <em>Inside</em>. Set the <strong>Colour</strong> of the stroke to something slightly different than the gradient.  I chose #ed1c24.</p>
<p><img src="http://jamestombs.co.uk/wp-content/uploads/2010/06/stroke.jpg" alt="" title="Stroke Blending Options" width="600" height="441" class="alignnone size-full wp-image-1167" /></p>
<h3>Step 3: Add a slight shine to the button</h3>
<p>Create another layer on top of the button and select the <strong>Eliptical Marquee Tool</strong> and draw an elipse covering the top half of the button.</p>
<p><img src="http://jamestombs.co.uk/wp-content/uploads/2010/06/elipse-selection.jpg" alt="" title="Elipse selection" width="177" height="92" class="alignnone size-full wp-image-1169" /></p>
<p>With the selection active, press and hold <strong>Ctrl, Alt and Shift</strong> and left click the layer preview of the button. This should limit the selection just to the area of where the selection meets the button.</p>
<p><img src="http://jamestombs.co.uk/wp-content/uploads/2010/06/elipse-selection-refined.jpg" alt="" title="Elipse Selection Refined" width="177" height="92" class="alignnone size-full wp-image-1168" /></p>
<p>
<!-- Begin Google Adsense code -->
<script type="text/javascript"><!--
google_ad_client = "pub-8190774722923642";
google_ad_slot = "1689935941";
google_ad_width = 336;
google_ad_height = 280;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
<!-- End Google Adsense code -->
</p>
<p>On the new layer, <strong>Fill</strong> this with <em>white (#ffffff)</em> and set the <strong>Opacity</strong> of the layer to <em>15%</em>.</p>
<h3>Result</h3>
<p><img src="http://jamestombs.co.uk/wp-content/uploads/2010/06/finished-button.jpg" alt="" title="Finished Button" width="140" height="60" class="alignnone size-full wp-image-1171" /></p>
]]></content:encoded>
			<wfw:commentRss>http://jamestombs.co.uk/2010-06-23/create-a-glossy-button-in-photoshop/1161/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Creating a Drupal multisite enviroment using Drupal 6</title>
		<link>http://jamestombs.co.uk/2010-06-22/creating-a-drupal-multisite-enviroment-using-drupal-6/1135</link>
		<comments>http://jamestombs.co.uk/2010-06-22/creating-a-drupal-multisite-enviroment-using-drupal-6/1135#comments</comments>
		<pubDate>Tue, 22 Jun 2010 09:35:27 +0000</pubDate>
		<dc:creator>James</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[drupal]]></category>
		<category><![CDATA[drupal planet]]></category>

		<guid isPermaLink="false">http://jamestombs.co.uk/?p=1135</guid>
		<description><![CDATA[This guide will show you how to create a multisite environment using a shared user system with the user only needing to log in once, to be logged in to all the sites. I will be doing this using WAMP on a Windows XP machine, so some of the steps won&#8217;t work if you are [...]]]></description>
			<content:encoded><![CDATA[<p>This guide will show you how to create a multisite environment using a shared user system with the user only needing to log in once, to be logged in to all the sites.</p>
<p>I will be doing this using WAMP on a Windows XP machine, so some of the steps won&#8217;t work if you are using IIS or will differ if you are using a different setup.</p>
<p>The result we will be aiming for is a shared user system allowing the user to log in/out of 3 sites which I will use the following domains:</p>
<ul>
<li>http://www.local.com</li>
<li>http://community.local.com</li>
<li>http://support.local.com</li>
</ul>
<p><span id="more-1135"></span></p>
<h3>WAMP installation</h3>
<p>Download and install the latest version of <a href="http://www.wampserver.com/en/download.php">WAMP</a> from the <a href="http://www.wampserver.com/en/download.php">WAMP website</a>. The latest version comes with PHP 5.3 which has problems with Drupal 6, so you will also need to download and install PHP 5.2.x from the <a href="http://www.wampserver.com/en/addons_php.php">WAMP Addons page</a> once WAMP is installed.</p>
<p>Once WAMP and PHP 5.2.x have been installed and WAMP has restarted, left click the WAMP icon in the system tray and go to PHP > PHP Version and select the 5.2.x version you downloaded.</p>
<p><img src="http://jamestombs.co.uk/wp-content/uploads/2010/06/php5.jpg" alt="" title="Select PHP 5.2.x from the versions list" width="312" height="240" class="alignnone size-full wp-image-1136" /></p>
<p>Left click the WAMP icon again and this time select <strong>Apache</strong> > <strong>Apache Modules</strong> and scroll down and select <strong>rewrite_module</strong> and <strong>vhost_alias_module</strong>.</p>
<p>
<!-- Begin Google Adsense code -->
<script type="text/javascript"><!--
google_ad_client = "pub-8190774722923642";
google_ad_slot = "1689935941";
google_ad_width = 336;
google_ad_height = 280;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
<!-- End Google Adsense code -->
</p>
<h3>WAMP Virtual Hosts set up</h3>
<p>Again, left click the WAMP icon and go to Apache then select <strong>httpd.conf</strong>.</p>
<p>Scroll down to the bottom of this file and look for the following lines:<br />
<code># Virtual hosts<br />
# Include conf/extra/httpd-vhosts.conf</code></p>
<p>Remove the comment from the beginning of the second line to end up with this:<br />
<code># Virtual hosts<br />
Include conf/extra/httpd-vhosts.conf</code></p>
<p>Save and close the file.</p>
<p>Now in Explorer, navigate to the <em>WAMP directory\bin\bin\apache\Apache2.2.11\conf\extra\</em> directory.</p>
<p>Open the <strong>httpd-vhosts.conf</strong> file with your favourite text editor.</p>
<p>Replace the contents of this file with the following:</p>
<p><code>NameVirtualHost *:80<br />
#<br />
# VirtualHost example:<br />
# Almost any Apache directive may go into a VirtualHost container.<br />
# The first VirtualHost section is used for all requests that do not<br />
# match a ServerName or ServerAlias in any &lt;VirtualHost&gt; block.<br />
#<br />
&lt;VirtualHost *:80&gt;<br />
    ServerAdmin webmaster@localhost<br />
    DocumentRoot &quot;c:/wamp/www/&quot;<br />
    ServerName www.local.com<br />
    ErrorLog &quot;logs/local-www-error.log&quot;<br />
    CustomLog &quot;logs/local-www-access.log&quot; common<br />
    &lt;directory &quot;c:/wamp/www/&quot;&gt;<br />
        Options Indexes FollowSymLinks<br />
        AllowOverride all<br />
        Order Deny,Allow<br />
        Deny from all<br />
        Allow from 127.0.0.1<br />
    &lt;/directory&gt;<br />
&lt;/VirtualHost&gt;<br />
&lt;VirtualHost *:80&gt;<br />
    ServerAdmin webmaster@localhost<br />
    DocumentRoot &quot;c:/wamp/www/&quot;<br />
    ServerName community.local.com<br />
    ErrorLog &quot;logs/local-com.localhost-error.log&quot;<br />
    CustomLog &quot;logs/local-com.localhost-access.log&quot; common<br />
    &lt;directory &quot;c:/wamp/www/&quot;&gt;<br />
        Options Indexes FollowSymLinks<br />
        AllowOverride all<br />
        Order Deny,Allow<br />
        Deny from all<br />
        Allow from 127.0.0.1<br />
    &lt;/directory&gt;<br />
&lt;/VirtualHost&gt;<br />
&lt;VirtualHost *:80&gt;<br />
    ServerAdmin webmaster@localhost<br />
    DocumentRoot &quot;c:/wamp/www/&quot;<br />
    ServerName support.local.com<br />
    ErrorLog &quot;logs/local-sup.localhost-error.log&quot;<br />
    CustomLog &quot;logs/local-sup.localhost-access.log&quot; common<br />
    &lt;directory &quot;c:/wamp/www/&quot;&gt;<br />
        Options Indexes FollowSymLinks<br />
        AllowOverride all<br />
        Order Deny,Allow<br />
        Deny from all<br />
        Allow from 127.0.0.1<br />
    &lt;/directory&gt;<br />
&lt;/VirtualHost&gt;</code></p>
<p>This sets up 3 virtual hosts all using the same directory for the files, as we are using a shared codebase. This is also set up to only allow traffic from the localhost. To make the site public to all, change the line:</p>
<p><code>Allow from 127.0.0.1</code></p>
<p>To:</p>
<p><code>Allow from all</code></p>
<p>Save and close the file.</p>
<p>
<!-- Begin Google Adsense code -->
<script type="text/javascript"><!--
google_ad_client = "pub-8190774722923642";
google_ad_slot = "1689935941";
google_ad_width = 336;
google_ad_height = 280;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
<!-- End Google Adsense code -->
</p>
<h3>HOSTS set up</h3>
<p>The local.com domain already exist, so we need to overwrite the IP address where it points to be the local computer in the HOSTS file. We do this by editing the HOSTS file which on Windows is located in the following directory:</p>
<p><em>C:\WINDOWS\system32\drivers\etc</em></p>
<p>The HOSTS file has no file extension. So open it up in Notepad and add the following line at the very bottom:</p>
<p><code>127.0.0.1 www.local.com community.local.com support.local.com</code></p>
<p>Save the file, but make sure you don’t add a .txt extension.</p>
<p>You will need to close all your browser windows and in some cases restart the computer for the changes to take effect.</p>
<p>Open a new browser window and try to navigate to www.local.com, you should now get the WAMP welcome screen.</p>
<h3>Create a database in MySQL</h3>
<p>Using which ever MySQL admin tool you prefer, create a new database to use for Drupal. If using WAMP, you can use PHPMyAdmin by navigating to http://localhost/phpmyadmin/</p>
<p>By default MySQL has no password in WAMP.</p>
<h3>Download and set up Drupal</h3>
<p>Download the latest version of Drupal 6 which at the time of writing is <a href="http://drupal.org/drupal-6.17">Drupal 6.17</a>.</p>
<p>Extract the files and subfolders to the <em>C:\wamp\www</em> directory overwriting the existing <strong>index.php</strong> when asked. If you are not asked to overwrite the <strong>index.php</strong> file, you have tried to extract the files at the wrong directory level.</p>
<p>Navigate to the <em>/sites/</em> directory and copy the default directory twice and rename the 2 new directories <strong>support.local.com</strong> and <strong>community.local.com</strong>.</p>
<p>Navigate in your browser to <em>www.local.com</em>, you should get the Drupal installation screen. Follow the screens through and install Drupal how you normally would. Once installation has finished and you are at the Welcome screen, navigate to <em>support.local.com</em>.</p>
<p>During installation, add a database prefix as <strong>support_</strong> and continue with installation.</p>
<p>Once at the welcome screen, do the same with <em>community.local.com</em> but this time using the prefix <strong>comm_</strong>.</p>
<h3>Configure Drupal for multisite by modifying settings.php</h3>
<p>In the /sites/ directory there are now 4 directories.</p>
<p>- all<br />
- community.local.com<br />
- default<br />
- support.local.com</p>
<p>The default directory is used for www.local.com, the other 2 xxx.local.com directories should be self explanitory and the all directory is present for modules and themes.</p>
<p>Open up the settings.php file in the default directory.</p>
<p>Around a quater of the way down the file (around line 93 for most people) there is a line for $db_prefix, if you didn’t set one it should just say:</p>
<p><code>$db_prefix = '';</code></p>
<p>Scroll 3 quaters down (around line 169) and uncomment the line:</p>
<p><code># $cookie_domain = 'example.com';</code></p>
<p>And change to:</p>
<p><code>$cookie_domain = '.local.com';</code></p>
<p>This will share the session cookie across all subdomains of local.com</p>
<p>Save and close the file.</p>
<p>Now open up <strong>settings.php</strong> from within the community.local.com directory.</p>
<p>Scroll down to line 93 and replace with the following:</p>
<p><code>$db_prefix = array(<br />
  'default' => 'comm_',<br />
  'users' => '',<br />
  'sessions' => '',<br />
  'role' => '',<br />
  'authmap' => '',<br />
  'users_roles' => '',<br />
  'profile_fields' => '',<br />
  'profile_values' => '',<br />
);</code></p>
<p>Save and close the file.</p>
<p>And again, scroll 3 quaters down (around line 169) and uncomment the line:</p>
<p><code># $cookie_domain = 'example.com';</code></p>
<p>And change to:</p>
<p><code>$cookie_domain = '.local.com';</code></p>
<p>Repeat the same for support.local.com, although this time set the default $db_prefix to <strong>support_</strong>.</p>
<p>Save and close the file.</p>
<p>Navigate to each site in the browser and log out of each site. Now log in to <em>www.local.com</em>. Now if you navigate to <em>support.local.com</em>, you should be logged in, same with <em>community.local.com</em>.</p>
<p>We now have 3 sites with a shared user base and a single signon. As you may be able to tell from the $db_prefix array above, we are sharing the users table as well as sessions which keeps the user data and log in data the same across all the sites. We also share the role and users_roles tables to be able to set multi-sitewide roles as well as the profile tables so that the user doesn’t have to type any information over and over again.</p>
<p>
<!-- Begin Google Adsense code -->
<script type="text/javascript"><!--
google_ad_client = "pub-8190774722923642";
google_ad_slot = "1689935941";
google_ad_width = 336;
google_ad_height = 280;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
<!-- End Google Adsense code -->
</p>
<h3>Cleaning up unneeded MySQL tables</h3>
<p>Now in our database, we have redundant tables which aren’t doing anything and aren’t being used. We can now delete these to keep the database a bit tidier. Delete the following tables:</p>
<ul>
<li>support_users</li>
<li>support_sessions</li>
<li>support_role</li>
<li>support_authmap</li>
<li>support_users_roles</li>
<li>support_profile_fields</li>
<li>support_profile_values</li>
<li>comm_users</li>
<li>comm_sessions</li>
<li>comm_role</li>
<li>comm_authmap</li>
<li>comm_users_roles</li>
<li>comm_profile_fields</li>
<li>comm_profile_values</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://jamestombs.co.uk/2010-06-22/creating-a-drupal-multisite-enviroment-using-drupal-6/1135/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Finding a string in any file with a subdirectory in linux</title>
		<link>http://jamestombs.co.uk/2010-05-24/finding-a-string-in-any-file-with-a-subdirectory-in-linux/1134</link>
		<comments>http://jamestombs.co.uk/2010-05-24/finding-a-string-in-any-file-with-a-subdirectory-in-linux/1134#comments</comments>
		<pubDate>Mon, 24 May 2010 15:36:38 +0000</pubDate>
		<dc:creator>James</dc:creator>
				<category><![CDATA[Other]]></category>
		<category><![CDATA[linux]]></category>

		<guid isPermaLink="false">http://jamestombs.co.uk/?p=1134</guid>
		<description><![CDATA[Nothing new or major but something that I keep forgetting. find . -exec grep -l "string to find" {} \; This will search all subdirectories from the current directory for the &#8220;string to find&#8221;.]]></description>
			<content:encoded><![CDATA[<p>Nothing new or major but something that I keep forgetting.</p>
<p><code>find . -exec grep -l "string to find" {} \;</code></p>
<p>This will search all subdirectories from the current directory for the &#8220;string to find&#8221;.</p>
]]></content:encoded>
			<wfw:commentRss>http://jamestombs.co.uk/2010-05-24/finding-a-string-in-any-file-with-a-subdirectory-in-linux/1134/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Create your own simple grid system in CSS</title>
		<link>http://jamestombs.co.uk/2010-04-05/create-your-own-simple-grid-system-in-css/1129</link>
		<comments>http://jamestombs.co.uk/2010-04-05/create-your-own-simple-grid-system-in-css/1129#comments</comments>
		<pubDate>Sun, 04 Apr 2010 23:57:57 +0000</pubDate>
		<dc:creator>James</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[css]]></category>

		<guid isPermaLink="false">http://jamestombs.co.uk/?p=1129</guid>
		<description><![CDATA[This tutorial will outline the steps required to create your own grid system like the 960.gs or Blueprint CSS frameworks. Step 1: The basics behind grid systems Grid systems allow you to create a quick framework using HTML and set CSS styles to set up div tags in to a grid like formation which saves [...]]]></description>
			<content:encoded><![CDATA[<p>This tutorial will outline the steps required to create your own grid system like the <a href="http://960.gs/">960.gs</a> or <a href="http://blueprintcss.org/">Blueprint CSS</a> frameworks.</p>
<p><span id="more-1129"></span></p>
<h4 class="step">Step 1: The basics behind grid systems</h4>
<p>Grid systems allow you to create a quick framework using HTML and set CSS styles to set up div tags in to a grid like formation which saves you from having to worry about floating elements and margins etc.</p>
<p>This tutorial is going to focus on a very basic grid that allows you to easily create 1, 2, 3, 4 column layouts.  If you are looking for something that has more depth to it and more flexibility, it will be better to look at <a href="http://960.gs/">960.gs</a> or <a href="http://blueprintcss.org/">Blueprint CSS</a>, as they will provide you with a lot more options on how you want to display your content.</p>
<h4 class="step">Step 2: The start of the CSS</h4>
<p>We need to set up some basic CSS rules to set up our grid elements or cells so that they line up in a grid like we want them to.</p>
<pre class="brush: css">.cell, .cell-2, .cell-3 {
  float: left;
  display: inline;
  margin: 0 10px;
  position: relative;
}
.alpha { margin-left: 0; }
.omega { margin-right: 0; }
</pre>
<p>Our first rule is setting the cell to float and display inline with a 10px margin on the left and right.  The next two rules allow us to remove the margin if we need to from the first rule.  So with the following HTML, the second cell would have no right margin.</p>
<pre class="brush: html">&lt;div class=&quot;cell&quot;&gt;&lt;p&gt;Text&lt;/p&gt;&lt;/div&gt;
&lt;div class=&quot;cell omega&quot;&gt;&lt;p&gt;Text&lt;/p&gt;&lt;/div&gt;</pre>
<p>To make sure our cells line up properly on different rows we need to wrap them with another div which we will give the class <em>grid</em>.</p>
<pre class="brush: css">.grid, .grid-2, .grid-3, .grid-4 {
  clear: both;
  overflow: hidden;
  margin-bottom: 1.5em;
}</pre>
<p>This makes sure that the div is a new row if the row above doesn&#8217;t use the full width.</p>
<h4 class="step">Step 3: The mathematics</h4>
<p>The basis of grid systems is some simple mathematics.  If you look at the 960.gs size and the column counts available, you can see that they are divisable to a whole number. 960/12 = 80 and 960/16 = 60.</p>
<p>To be able to start off with the maths, you need to decide on the width of the wrapper of the whole page.  Take in to account the different resolutions that people use.  At the moment the majority of users are using 1024&#215;768, so the width shouldn&#8217;t be any more than 1000px wide (also take in to account a scrollbar on the right).</p>
<p>For this tutorial I am going to show the maths for a grid system with a width of 960px.</p>
<p>So we need to set the CSS for this:</p>
<pre class="brush: css">.container {
  width: 960px;
  margin: 0 auto;
}</pre>
<p>To work out the width of a single cell that fills the full width of the wrapper we need to divide the width of the container by the number of columns (in this case 1) then minus 20 (due to the 10px margin on both the left and right).</p>
<p>So; (960 / 1) &#8211; 10 &#8211; 10 = 940</p>
<pre class="brush: css">.grid .cell { width: 940px; }</pre>
<p>That is the most basic cell in the grid which will fill up the whole width of the container with the margins.</p>
<p>Now lets work out the width needed for a 2 column layout.</p>
<p>(960 / 2) &#8211; 10 &#8211; 10 = 460</p>
<pre class="brush: css">.grid-2 .cell { width: 460px; }</pre>
<p>This would be displayed using the following HTML:</p>
<pre class="brush: html">&lt;div class=&quot;container&quot;&gt;
  &lt;div class=&quot;grid-2&quot;&gt;
    &lt;div class=&quot;cell&quot;&gt;&lt;p&gt;Text&lt;/p&gt;&lt;/div&gt;
    &lt;div class=&quot;cell&quot;&gt;&lt;p&gt;Text&lt;/p&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>
<p>Let&#8217;s work through it backwards to make sure the maths works out. 460 + 460 = 920.  That is the total width of the available content areas.  But on top of that we need to add our margins in, we have the 10px on the far left, then there are 2 lots of 10px margins in the very centre of the grid and the last 10px at the very far right side of the grid making a total of 960px.</p>
<p>A 3 column layout can container 3 cells or 2 cells where one of the cells is the size of 2 single cells.  So lets see how that works.</p>
<p>(960 / 3) &#8211; 10 -10 = 300</p>
<pre class="brush: css">.grid-3 .cell { width: 300px; }</pre>
<p>So, 3 x 300px = 900px + (20px x 3) = 960px.  That is the CSS needed for 3 single cells.</p>
<pre class="brush: html">&lt;div class=&quot;container&quot;&gt;
  &lt;div class=&quot;grid-3&quot;&gt;
    &lt;div class=&quot;cell&quot;&gt;&lt;p&gt;Text&lt;/p&gt;&lt;/div&gt;
    &lt;div class=&quot;cell&quot;&gt;&lt;p&gt;Text&lt;/p&gt;&lt;/div&gt;
    &lt;div class=&quot;cell&quot;&gt;&lt;p&gt;Text&lt;/p&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>
<p>There are 2 easy ways to find out the width of the 2 cell.</p>
<p>One way, is to take the result of the single cell which in this case is 300, then add that on again to make 600.  We then need to add 20 to that to take in to account the margin that is no longer needed between the cells.</p>
<p>((960 / 3) &#8211; 20) + ((960 / 3) &#8211; 20) + 20 = 620</p>
<p>The other way is to do the original sum without taking the margins off until you have the full width of 2 cells, like so:</p>
<p>((960 / 3) * 2) &#8211; 20 = 620</p>
<p>So the CSS would like this:</p>
<pre class="brush: css">.grid-3 .cell-2 { width: 620px; }</pre>
<p>With the HTML like this:</p>
<pre class="brush: html">&lt;div class=&quot;container&quot;&gt;
  &lt;div class=&quot;grid-3&quot;&gt;
    &lt;div class=&quot;cell-2&quot;&gt;&lt;p&gt;Text&lt;/p&gt;&lt;/div&gt;
    &lt;div class=&quot;cell&quot;&gt;&lt;p&gt;Text&lt;/p&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>
<p>We then use exactly the same principles for the 4 column layout.</p>
<p>Single cell: (960 / 4) &#8211; 10 &#8211; 10 = 220<br />
Double cell: (220 + 220) + 20 = 460<br />
Triple cell: (460 + 220) + 20 = 700</p>
<pre class="brush: css">.grid-4 .cell { width: 220px; }
.grid-4 .cell-2 { width: 460px; }
.grid-4 .cell-3 { width: 700px; }</pre>
<p>Which would give you the following combinations available:</p>
<pre class="brush: html">&lt;div class=&quot;container&quot;&gt;
  &lt;div class=&quot;grid-4&quot;&gt;
    &lt;div class=&quot;cell-3&quot;&gt;&lt;p&gt;Text&lt;/p&gt;&lt;/div&gt;
    &lt;div class=&quot;cell&quot;&gt;&lt;p&gt;Text&lt;/p&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class=&quot;grid-4&quot;&gt;
    &lt;div class=&quot;cell&quot;&gt;&lt;p&gt;Text&lt;/p&gt;&lt;/div&gt;
    &lt;div class=&quot;cell&quot;&gt;&lt;p&gt;Text&lt;/p&gt;&lt;/div&gt;
    &lt;div class=&quot;cell&quot;&gt;&lt;p&gt;Text&lt;/p&gt;&lt;/div&gt;
    &lt;div class=&quot;cell&quot;&gt;&lt;p&gt;Text&lt;/p&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class=&quot;grid-4&quot;&gt;
    &lt;div class=&quot;cell&quot;&gt;&lt;p&gt;Text&lt;/p&gt;&lt;/div&gt;
    &lt;div class=&quot;cell&quot;&gt;&lt;p&gt;Text&lt;/p&gt;&lt;/div&gt;
    &lt;div class=&quot;cell-2&quot;&gt;&lt;p&gt;Text&lt;/p&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>
<h4 class="step">Step 4: The result</h4>
<p>The result should be the following:</p>
<pre class="brush: css">.container {
  width: 960px;
  margin: 0 auto;
  padding: 1.5em 0;
}
.grid, .grid-2, .grid-3, .grid-4 {
  clear: both;
  overflow: hidden;
  margin-bottom: 1.5em;
}
.cell, .cell-2, .cell-3 {
  float: left;
  display: inline;
  margin: 0 10px;
  position: relative;
}
.alpha { margin-left: 0; }
.omega { margin-right: 0; }
.grid .cell { width: 940px; }
.grid-2 .cell, .grid-4 .cell-2 { width: 460px; }
.grid-3 .cell { width: 300px; }
.grid-3 .cell-2 { width: 620px; }
.grid-4 .cell { width: 220px; }
.grid-4 .cell-3 { width: 700px; }</pre>
<p>I have tidied up the code slightly, as the width for a 2 column cell is the same as a double cell in a 4 grid system.</p>
<p>If you look at the source code for this site, you will see that there are 2 sets of widths defined.  This is to cater for larger screens. A piece of javascript is triggered as soon as the page has finished loading and any resizing of the browser window which applies a class called wide to the body of the HTML.  If the window width is larger than 1200px then the site will be displayed in a larger grid system.  You could do the same using a stylesheet switcher to be able to change from a narrow to wide theme.</p>
]]></content:encoded>
			<wfw:commentRss>http://jamestombs.co.uk/2010-04-05/create-your-own-simple-grid-system-in-css/1129/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Photoshop Tutorial &#8211; Dark Modern Header</title>
		<link>http://jamestombs.co.uk/2010-04-04/photoshop-tutorial-dark-modern-header/1122</link>
		<comments>http://jamestombs.co.uk/2010-04-04/photoshop-tutorial-dark-modern-header/1122#comments</comments>
		<pubDate>Sun, 04 Apr 2010 00:06:56 +0000</pubDate>
		<dc:creator>James</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[photoshop]]></category>
		<category><![CDATA[tutorial]]></category>

		<guid isPermaLink="false">http://jamestombs.co.uk/?p=1122</guid>
		<description><![CDATA[This tutorial with guide you through how to make a dark modern header for your website: Step 1 Open Photoshop and create a new image how ever big you want it. Step 2 Create a black bar using the rectangular marquee tool on a new layer. Step 3 Using the same selection go to the [...]]]></description>
			<content:encoded><![CDATA[<p>This tutorial with guide you through how to make a dark modern header for your website:</p>
<p><img src="http://jamestombs.co.uk/wp-content/uploads/2010/04/example.jpg" alt="" title="example" width="400" height="150" class="alignnone size-full wp-image-1127" /></p>
<p><span id="more-1122"></span></p>
<h4 class="step">Step 1</h4>
<p>Open Photoshop and create a new image how ever big you want it.</p>
<h4 class="step">Step 2</h4>
<p>Create a black bar using the rectangular marquee tool on a new layer.</p>
<h4 class="step">Step 3</h4>
<p>Using the same selection go to the Select menu and select feather, set to 10px. On a new layer fill this with white.</p>
<p><img src="http://jamestombs.co.uk/wp-content/uploads/2010/04/1.jpg" alt="" title="1" width="400" height="150" class="alignnone size-full wp-image-1123" /></p>
<h4 class="step">Step 4</h4>
<p>Press Ctrl + T to transform the layer. Drag the bottom slider up to the top to shrink the layer.</p>
<p><img src="http://jamestombs.co.uk/wp-content/uploads/2010/04/2.jpg" alt="" title="2" width="421" height="162" class="alignnone size-full wp-image-1124" /></p>
<h4 class="step">Step 5</h4>
<p>Move the layer in to place and set the opacity to 30%.</p>
<p><img src="http://jamestombs.co.uk/wp-content/uploads/2010/04/3.jpg" alt="" title="3" width="400" height="150" class="alignnone size-full wp-image-1125" /></p>
<h4 class="step">Step 6</h4>
<p>Select the Single Row Marquee tool and create a selection, press and hold Ctrl + Alt + Shift and click on the preview area of the black box in the layers panel.</p>
<p>On a new layer fill with #00adef do this again and make sure they are one on top of the other so it&#8217;s 2px high.</p>
<p><img src="http://jamestombs.co.uk/wp-content/uploads/2010/04/4.jpg" alt="" title="4" width="400" height="150" class="alignnone size-full wp-image-1126" /></p>
<h4 class="step">Step 7</h4>
<p>Now we will add some shading over the clue bar so it isn&#8217;t so bright.</p>
<p>Press and hold Ctrl and left click the preview area of the blue bar in the layers panel.</p>
<p>On a new layer fill the selection with black.</p>
<p>Press Ctrl + D to deselect the selection.</p>
<p>Go to Filter » Blur » Gaussian Blur and set to 1px.</p>
<p>Set the layer opacity to 60%.</p>
<p>Press V and move up 1px.</p>
<h4 class="step">Step 8</h4>
<p>Add extra details to it such as text and reflection and you are finished.</p>
<p><img src="http://jamestombs.co.uk/wp-content/uploads/2010/04/example.jpg" alt="" title="example" width="400" height="150" class="alignnone size-full wp-image-1127" /></p>
<div class="note">
<p>Note: This tutorial was original posted on <a href="/skeletorscorpse/photoshop-web-graphics/163-dark-modern-header">Skeletorscorpse</a> on 01 December 2006.</p>
</div>
]]></content:encoded>
			<wfw:commentRss>http://jamestombs.co.uk/2010-04-04/photoshop-tutorial-dark-modern-header/1122/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Create stepped navigation with arrows using HTML + CSS</title>
		<link>http://jamestombs.co.uk/2010-03-30/create-stepped-navigation-with-arrows-using-html-css/1107</link>
		<comments>http://jamestombs.co.uk/2010-03-30/create-stepped-navigation-with-arrows-using-html-css/1107#comments</comments>
		<pubDate>Tue, 30 Mar 2010 18:50:55 +0000</pubDate>
		<dc:creator>James</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[css]]></category>
		<category><![CDATA[design]]></category>
		<category><![CDATA[tutorial]]></category>

		<guid isPermaLink="false">http://jamestombs.co.uk/?p=1107</guid>
		<description><![CDATA[In this tutorial I will show you how to create a stepped navigation with arrows using HTML and CSS which works in all major browsers. It is useful to show a user a stepped process such as a multi part form where there is more than one step that needs to be filled in. View [...]]]></description>
			<content:encoded><![CDATA[<p>In this tutorial I will show you how to create a stepped navigation with arrows using HTML and CSS which works in all major browsers. It is useful to show a user a stepped process such as a multi part form where there is more than one step that needs to be filled in.</p>
<p><a href="http://jamestombs.co.uk/wp-content/uploads/2010/03/final-wide.jpg" rel="shadowbox[post-1107];player=img;"><img src="http://jamestombs.co.uk/wp-content/uploads/2010/03/final-small.jpg" alt="" title="Final result" width="400" height="42" class="aligncenter size-full wp-image-1113" /></a></p>
<div class="demo-block">
<div class="demo">
<p><a href='http://jamestombs.co.uk/wp-content/uploads/2010/03/steppednav.html'>View demo</a></p>
</div>
<div class="source">
<p><a href='http://jamestombs.co.uk/wp-content/uploads/2010/03/source.txt'>View sourcecode</a></p>
</div>
</div>
<p><span id="more-1107"></span></p>
<h3>Step 1: The HTML</h3>
<p>For the HTML we will use an unordered list so the navigation is accessible and will still partly work without the CSS file such as in text browsers.</p>
<pre class="brush: html">
&lt;div class=&quot;steps&quot;&gt;
  &lt;ul&gt;
    &lt;li class=&quot;step step-1&quot;&gt;
      &lt;a href=&quot;#&quot;&gt;&lt;strong&gt;Step 1&lt;/strong&gt;&lt;br /&gt;Some random text that describes the step&lt;/a&gt;
    &lt;/li&gt;
    &lt;li class=&quot;step step-2&quot;&gt;
      &lt;a href=&quot;#&quot;&gt;&lt;strong&gt;Step 2&lt;/strong&gt;&lt;br /&gt;Some random text that describes the step&lt;/a&gt;
    &lt;/li&gt;
    &lt;li class=&quot;step step-3&quot;&gt;
      &lt;a href=&quot;#&quot;&gt;&lt;strong&gt;Step 3&lt;/strong&gt;&lt;br /&gt;Some random text that describes the step&lt;/a&gt;
    &lt;/li&gt;
  &lt;/ul&gt;
&lt;/div&gt;
</pre>
<p>This will leave us with the following &#8211; <a href='http://jamestombs.co.uk/wp-content/uploads/2010/03/step-1.html'>view step 1 result</a>.</p>
<h3>Step 2: Style with CSS</h3>
<p>We now need to make it pretty, firstly we reset the default CSS rules applied to unordered lists by the browsers.</p>
<pre class="brush: css">
.steps ul, .steps li {
  margin: 0;
  padding: 0;
  list-style: none;
}
</pre>
<p>This resets the margins and padding around each the list itself and each list element within the list as well as removing the list-style (i.e. the bullet).</p>
<p>To make the elements appear side-by-side rather than on top of one another, we need to float the list elements.</p>
<pre class="brush: css">
.steps ul { float: left; }
.steps li {
  float: left;
}
</pre>
<p>This will leave you with your list elements side-by-side. <a href='http://jamestombs.co.uk/wp-content/uploads/2010/03/step-2.html'>View the result of step 2</a>.</p>
<p><script type="text/javascript"><!--
google_ad_client = "pub-8190774722923642";
/* 336x280, created 3/31/10 */
google_ad_slot = "1689935941";
google_ad_width = 336;
google_ad_height = 280;
//-->
</script><br />
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script></p>
<h3>Step 3: Make the steps in to arrows</h3>
<p>The next step is to add in our arrows to be background images.</p>
<pre class="brush: css">.steps li a {
  display: block;
  padding: 15px 20px;
  color: #fff;
  line-height: 1.5em;
  text-decoration: none;
}</pre>
<p>This makes the anchor tags act like block level elements so that they fill out in to their parent item which is the &lt;li&gt;. We also add some padding and set the line-height to make it look nicer.</p>
<p>Next we add in the background images for our list elements. You can use these images for the time being to speed up the process, just right click them then save them in the same folder as your CSS file.  <a href="http://jamestombs.co.uk/wp-content/uploads/2010/03/step.png" rel="shadowbox[post-1107];player=img;">Normal</a> &amp; <a href="http://jamestombs.co.uk/wp-content/uploads/2010/03/step_over.png" rel="shadowbox[post-1107];player=img;">Hover</a>. The images are basic PNGs with transparent sections on the end of arrow. There is also a 1px stroke to the right which gives you the seperator between the steps. The images should be as wide as your container, the reason for this is mentioned in step 5.</p>
<pre class="brush: css">.steps li.step a { background: transparent url(step.png) center right no-repeat; }
.steps li.step a:hover { background: transparent url(step_over.png) center right no-repeat; }</pre>
<p>This adds in the images to our steps with the hover state. <a href='http://jamestombs.co.uk/wp-content/uploads/2010/03/step-3.html'>View result of step 3</a></p>
<h3>Step 4: Setting the width and aligning the steps</h3>
<p>As you can tell from the result of step 3, we have a bit of a mess now.  So now we can clear it up.  My example is wrapped in a container which is 960px wide, so what I am going to do, is divide that by 3 as I have 3 steps.  That means each step should be 320px wide. So alter the CSS for .steps li to the following:</p>
<pre class="brush: css">
.steps li {
  float: left;
  width: 320px;
}
</pre>
<p>This now lines our steps side-by-side again with the text wrapped to fit in the width, but the arrows are stop start and aren&#8217;t covering each other.</p>
<p>To get around this, we use a negative margin to pull the element to the left, although we only apply this to the 2nd and 3rd steps.</p>
<pre class="brush: css">.steps li.step-2, .steps li.step-3 { margin-left: -30px; }</pre>
<p>Now you will notice a new problem.  The later steps are covering the earlier steps so the arrow isn&#8217;t visible.  To get around this, we will use the CSS property z-index to change the layering on the z-axis.</p>
<p>For z-index to be effective though, we also need to change the positioning type of the list element and child anchor.</p>
<pre class="brush: css">.steps li.step, .steps li.step a {
  position: relative;
  z-index: 3;
}
.steps li.step-2, .steps li.step-2 a { z-index: 2; }
.steps li.step-3, .steps li.step-3 a { z-index: 1; }</pre>
<p>Once again we have created more problems.  The first one being that some of the text is now hidden beneath the arrow of the preceeding step.  We can get around this by adding some extra padding.</p>
<pre class="brush: css">.steps li.step-2 a, .steps li.step-3 a { padding-left: 50px; }</pre>
<p>The 50px comes from the -30px which is the left negative margin + the extra 20px of padding we defined earlier on for each anchor element.</p>
<p>The negative margins also made the total width of our stepped element less than 960px so we have a gap at the end. With some simple maths we can work out the new width that each list element must be to fit the 960px width. We have a 960px container with 2 elements with negative margins of 30px, so 960px + 60px = 1020px.  Now we divide that by 3 to get our new width which is 340px.</p>
<pre class="brush: css">.steps li {
  float: left;
  width: 340px;
}</pre>
<p>This then leaves us a lot closer to our goal. <a href='http://jamestombs.co.uk/wp-content/uploads/2010/03/step-4.html'>View result of step 4</a>.</p>
<h3>Step 5: Fix the background position of the last step</h3>
<p>The arrow is showing on the 3rd step although it doesn&#8217;t go anywhere, it is the end.  To fix this, we just need to change the background position for step 3, this is the reasoning for our images being long.</p>
<pre class="brush: css">.steps li.step-3 a { background-position: center left; }
.steps li.step-3 a:hover { background-position: center left; }</pre>
<p>We change the background image to be aligned to the left so it is solid colour, as we made the images longer than the content, unless there is only 1 step (why would you be doing this tutorial if you only had 1 step?) the arrow won&#8217;t be seen.</p>
<p>Then you have a finished stepped navigation. <a href='http://jamestombs.co.uk/wp-content/uploads/2010/03/step-5.html'>View result of step 5</a>.</p>
<p>Then with a little extra CSS for text formatting and some borders on the parent element you are left with the <a href='http://jamestombs.co.uk/wp-content/uploads/2010/03/steppednav.html'>final result</a>.</p>
<p><a href="http://jamestombs.co.uk/wp-content/uploads/2010/03/final-wide.jpg" rel="shadowbox[post-1107];player=img;"><img src="http://jamestombs.co.uk/wp-content/uploads/2010/03/final-small.jpg" alt="" title="Final result" width="400" height="42" class="aligncenter size-full wp-image-1113" /></a></p>
<div class="demo-block">
<div class="demo">
<p><a href='http://jamestombs.co.uk/wp-content/uploads/2010/03/steppednav.html'>View demo</a></p>
</div>
<div class="source">
<p><a href='http://jamestombs.co.uk/wp-content/uploads/2010/03/source.txt'>View sourcecode</a></p>
</div>
</div>
]]></content:encoded>
			<wfw:commentRss>http://jamestombs.co.uk/2010-03-30/create-stepped-navigation-with-arrows-using-html-css/1107/feed</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Creating a grid of images for an album in Drupal 6 with pagination</title>
		<link>http://jamestombs.co.uk/2010-03-10/creating-a-grid-of-images-for-an-album-in-drupal-6-with-pagination/1106</link>
		<comments>http://jamestombs.co.uk/2010-03-10/creating-a-grid-of-images-for-an-album-in-drupal-6-with-pagination/1106#comments</comments>
		<pubDate>Wed, 10 Mar 2010 13:12:27 +0000</pubDate>
		<dc:creator>James</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[drupal]]></category>
		<category><![CDATA[drupal planet]]></category>

		<guid isPermaLink="false">http://jamestombs.co.uk/?p=1106</guid>
		<description><![CDATA[Following on from the original tutorial on creating a grid of images for an album in Drupal 6, a few people asked how to add pagination on to this for large albums. Unfortunately from what I can tell Drupal&#8217;s pagination function only works with SQL queries so we are unable to use the existing data [...]]]></description>
			<content:encoded><![CDATA[<p>Following on from the original tutorial on <a href="http://jamestombs.co.uk/2009-06-25/creating-a-grid-of-images-for-an-album-in-drupal/1046">creating a grid of images for an album in Drupal 6</a>, a few people asked how to add pagination on to this for large albums.</p>
<p>Unfortunately from what I can tell Drupal&#8217;s pagination function only works with SQL queries so we are unable to use the existing data available in the node object.  But due to Drupal&#8217;s nice database schema, it is very simple to write some simple SQL to give us the pager.</p>
<p><span id="more-1106"></span></p>
<p>Below is the full code and below the code I will explain what each part does.</p>
<pre class="brush: php">&lt;?php
$count = count($node-&gt;field_images);
if ($count &gt; 0):
	$images_per_page = 9;
	$sql = &quot;SELECT f.fid, i.field_images_data, f.filepath FROM content_field_images i JOIN files f ON f.fid = i.field_images_fid WHERE nid = &quot;. $node-&gt;nid;
	$count = &quot;SELECT COUNT(f.fid) FROM content_field_images i JOIN files f ON f.fid = i.field_images_fid WHERE nid = &quot;. $node-&gt;nid;
	$query = pager_query($sql, $images_per_page, 0, $count);
	while ($data = db_fetch_object($query)) {
		$images[$data-&gt;fid] = array(
			&#039;filepath&#039; =&gt; $data-&gt;filepath,
			&#039;data&#039; =&gt; unserialize($data-&gt;field_images_data),
		);
	}
	$rows = array();
	$images_per_row = 3;
	$i = 0;
	$row = 0;
	foreach ($images as $image) {
		$rows[$row][$i] = &#039;&lt;a class=&quot;gallery-thumbs&quot; title=&quot;&#039;. htmlspecialchars($image[&#039;data&#039;][&#039;description&#039;]) .&#039;&quot; rel=&quot;lightbox[photo_gallery-&#039;. $node-&gt;nid .&#039;]&quot; href=&quot;&#039;. imagecache_create_url(&#039;lightbox&#039;, $image[&#039;filepath&#039;]) .&#039;&quot;&gt;&#039;. theme(&#039;imagecache&#039;, &#039;thumbnail&#039;, $image[&#039;filepath&#039;], $image[&#039;data&#039;][&#039;title&#039;], $image[&#039;data&#039;][&#039;title&#039;]) .(trim($image[&#039;data&#039;][&#039;description&#039;]) != &#039;&#039; ? &#039;&lt;br /&gt;&lt;small&gt;&#039;. $image[&#039;data&#039;][&#039;description&#039;] .&#039;&lt;/small&gt;&lt;/a&gt;&#039; : &#039;&#039;);
		$i++;
		if ($i == $images_per_row) {
			$row++;
			$i = 0;
		}
	}
	?&gt;
  &lt;table class=&quot;views-view-grid&quot;&gt;
    &lt;tbody&gt;
      &lt;?php foreach ($rows as $row_number =&gt; $columns): ?&gt;
        &lt;?php
          $row_class = &#039;row-&#039; . ($row_number + 1);
          if ($row_number == 0) {
            $row_class .= &#039; row-first&#039;;
          }
          elseif (count($rows) == ($row_number + 1)) {
            $row_class .= &#039; row-last&#039;;
          }
        ?&gt;
        &lt;tr class=&quot;&lt;?php print $row_class; ?&gt;&quot;&gt;
          &lt;?php foreach ($columns as $column_number =&gt; $item): ?&gt;
            &lt;td class=&quot;&lt;?php print &#039;col-&#039;. ($column_number + 1); ?&gt;&quot;&gt;
              &lt;?php print $item; ?&gt;
            &lt;/td&gt;
          &lt;?php endforeach; ?&gt;
        &lt;/tr&gt;
      &lt;?php endforeach; ?&gt;
    &lt;/tbody&gt;
  &lt;/table&gt;
  &lt;?php print theme(&#039;pager&#039;, array(), $images_per_page, 0); ?&gt;
&lt;?php else: ?&gt;
  &lt;p&gt;No images in album&lt;/p&gt;
&lt;?php endif; ?&gt;</pre>
<p>First thing we do is check to see if there are any images.  Rather than doing a SQL query to get the result, I have chosen to use the already existing array of images in the node object.</p>
<pre class="brush: php">$count = count($node-&gt;field_images);</pre>
<p><script type="text/javascript"><!--
google_ad_client = "pub-8190774722923642";
/* 336x280, created 3/31/10 */
google_ad_slot = "1689935941";
google_ad_width = 336;
google_ad_height = 280;
//-->
</script><br />
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script></p>
<p>Then as before we check to make sure we have images, then create our query to generate the pager.</p>
<pre class="brush: php">$images_per_page = 9;
	$sql = &quot;SELECT f.fid, i.field_images_data, f.filepath FROM content_field_images i JOIN files f ON f.fid = i.field_images_fid WHERE nid = &quot;. $node-&gt;nid;
	$count = &quot;SELECT COUNT(f.fid) FROM content_field_images i JOIN files f ON f.fid = i.field_images_fid WHERE nid = &quot;. $node-&gt;nid;
	$query = pager_query($sql, $images_per_page, 0, $count);
	while ($data = db_fetch_object($query)) {
		$images[$data-&gt;fid] = array(
			&#039;filepath&#039; =&gt; $data-&gt;filepath,
			&#039;data&#039; =&gt; unserialize($data-&gt;field_images_data),
		);
	}</pre>
<p>In the query, we are gathering the file id (fid) of each individual image, the field_images_data which is a serializd array of the title, description and alt text of the image from when it was uploaded and the filepath of the image.  The count isn&#8217;t necessarily needed, but I have found the pager can act oddly when the $count part of <em>pager_query()</em> is missing.</p>
<p><em>pager_query()</em> also requires 2 other elements. The first after $sql, is the amount of rows to be taken out the database.  The next number is the element number.  This is needed for pages with multiple pagers on them.  If you have got multiple pagers and experience trouble then you will need to change this.</p>
<p>Then from this we recreate the $images array that we had before, although it is missing some information which is provided through the $node object, it provides everything that we need to display the image on the page.</p>
<p>The whole table HTML section remains untouched, but it is followed by an extra line:</p>
<pre class="brush: php">&lt;?php print theme(&#039;pager&#039;, array(), $images_per_page, 0); ?&gt;</pre>
<p>This prints out the Drupal pager below out table of images.  This can be used multiple times on a page, so you can have some pagination below and above the table of images.</p>
<p>If the page you are displaying the albums on already has pagers, you may need to change the 0 in both the <em>theme_pager()</em> and <em>pager_query()</em>.</p>
<p>You should now have a fully working grid with pagination.</p>
<p><strong>Edit:</strong> As pointed out by dukat in the comments, you can change the original SQL query to the following to keep the images in the order defined in the node.</p>
<pre class="brush: php">$sql = &quot;SELECT f.fid, i.field_images_data, f.filepath FROM content_field_images i JOIN files f ON f.fid = i.field_images_fid WHERE nid = &quot;. $node-&gt;nid .&quot; ORDER BY i.delta ASC&quot;;</pre>
<p>Obviously you can change the order between ASC or DESC.</p>
]]></content:encoded>
			<wfw:commentRss>http://jamestombs.co.uk/2010-03-10/creating-a-grid-of-images-for-an-album-in-drupal-6-with-pagination/1106/feed</wfw:commentRss>
		<slash:comments>22</slash:comments>
		</item>
	</channel>
</rss>
