<?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>Linden LAN &#187; Programming</title>
	<atom:link href="http://www.lindenlan.net/category/programming/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.lindenlan.net</link>
	<description></description>
	<lastBuildDate>Sat, 29 Nov 2014 04:54:20 +0000</lastBuildDate>
	<language>en-US</language>
		<sy:updatePeriod>hourly</sy:updatePeriod>
		<sy:updateFrequency>1</sy:updateFrequency>
	
	<item>
		<title>Vertically Align Arbitrary Length String Relative To Image</title>
		<link>http://www.lindenlan.net/2010/12/07/vertically-align-arbitrary-length-string-relative-to-image/</link>
		<comments>http://www.lindenlan.net/2010/12/07/vertically-align-arbitrary-length-string-relative-to-image/#comments</comments>
		<pubDate>Wed, 08 Dec 2010 06:14:11 +0000</pubDate>
		<dc:creator><![CDATA[Brian]]></dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[CSS]]></category>

		<guid isPermaLink="false">http://www.lindenlan.net/?p=396</guid>
		<description><![CDATA[When coding web pages, a common problem is aligning (link) text vertically, often in relation to an icon. This is easily accomplished by setting height and line-height equal and by adding padding for the icon which is set as the background-image centered vertically. &#60;style&#62; a { background:url(&#039;16x16icon.png&#039;) no-repeat left center; display:block; height:16px; line-height:16px; padding-left:20px; } [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>When coding web pages, a common problem is aligning (link) text vertically, often in relation to an icon.  This is easily accomplished by setting <code>height</code> and <code>line-height</code> equal and by adding padding for the icon which is set as the <code>background-image</code> centered vertically.</p>
<pre class="brush: html">
&lt;style&gt;
a {
  background:url(&#039;16x16icon.png&#039;) no-repeat left center;
  display:block;
  height:16px;
  line-height:16px;
  padding-left:20px;
}
&lt;/style&gt;
&lt;a href=&quot;#&quot;&gt;Link Text&lt;/a&gt;
</pre>
<p>But what if the link text needs to span more than one line for the given width?  What if the icon is taller than the text height?</p>
<p><span id="more-396"></span><br />
This is where <code>display:inline-block</code> comes in.</p>
<pre class="brush: html">
&lt;style&gt;
.container {
  width:192px;
}

.container img {
  border:0;
  vertical-align:middle
}

.container span {
  display:inline-block;
  width:128px;
  vertical-align:middle;
}
&lt;/style&gt;

&lt;div class=&quot;container&quot;&gt;
  &lt;a href=&quot;#&quot;&gt;&lt;img src=&quot;64x64icon.png&quot; alt=&quot;an icon&quot; /&gt;&lt;span&gt;Link text that is really, really long that it takes up more than one line.&lt;/span&gt;&lt;/a&gt;
&lt;/div&gt;
</pre>
<p>Because the span is a block, text will wrap if longer than the width, but since the span is also inline, <code>vertical-align:middle</code> will align the img and the span.  The only bug I’ve noticed so far is that <code>text-decoration:underline</code> doesn’t render properly during the hover state.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.lindenlan.net/2010/12/07/vertically-align-arbitrary-length-string-relative-to-image/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Spoof The iPad User-Agent And See The “AdLib” Framework In Action</title>
		<link>http://www.lindenlan.net/2010/04/08/spoof-the-ipad-user-agent-and-see-the-adlib-framework-in-action/</link>
		<comments>http://www.lindenlan.net/2010/04/08/spoof-the-ipad-user-agent-and-see-the-adlib-framework-in-action/#comments</comments>
		<pubDate>Thu, 08 Apr 2010 07:19:45 +0000</pubDate>
		<dc:creator><![CDATA[Brian]]></dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[Apple]]></category>
		<category><![CDATA[Hacking]]></category>

		<guid isPermaLink="false">http://www.lindenlan.net/?p=382</guid>
		<description><![CDATA[As reported on Almost Done, Apple apparently has its own iPad-specific web framework, which Jim Hoskins has dubbed AdLib. If you don’t own an iPad, you can still have a look at it by spoofing the user-agent courtesy of LifeHacker. Mozilla/5.0(iPad; U; CPU iPhone OS 3_2 like Mac OS X; en-us) AppleWebKit/531.21.10 (KHTML, like Gecko) [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>As reported on Almost Done, Apple apparently has its own iPad-specific web framework, which Jim Hoskins has dubbed <a href="http://almost.done21.com/2010/04/adlib-apples-secret-ipad-web-framework/">AdLib</a>.  If you don’t own an iPad, you can still have a look at it by spoofing the user-agent courtesy of <a href="http://lifehacker.com/5508260/how-to-use-gmails-attractive-new-tablet+friendly-interface-on-your-regular-old-computer">LifeHacker</a>.</p>
<pre class="brush: bash">
Mozilla/5.0(iPad; U; CPU iPhone OS 3_2 like Mac OS X; en-us) AppleWebKit/531.21.10 (KHTML, like Gecko) Version/4.0.4 Mobile/7B314 Safari/531.21.10
</pre>
<p>I tried Firefox and Chrome using their respective user-agent switcher plugins, but didn’t get very far.  So go into Safari and select Develop-&gt;User Agent-&gt;Other…  Paste in the above string, click OK, and make sure it’s active.  Next navigate to <a href="http://help.apple.com/ipad/mobile/interface/">iPad User Guide</a> and check it out.  Here’s hoping Apple will be releasing it independently or as a part of the SDK.  Here’s also hoping it’s iPhone-compatible.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.lindenlan.net/2010/04/08/spoof-the-ipad-user-agent-and-see-the-adlib-framework-in-action/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>How To Build An iPhoto Image Flipper Using The jQuery Cycle Plugin</title>
		<link>http://www.lindenlan.net/2010/04/07/how-to-build-an-iphoto-image-flipper-using-the-jquery-cycle-plugin/</link>
		<comments>http://www.lindenlan.net/2010/04/07/how-to-build-an-iphoto-image-flipper-using-the-jquery-cycle-plugin/#comments</comments>
		<pubDate>Thu, 08 Apr 2010 06:13:57 +0000</pubDate>
		<dc:creator><![CDATA[Brian]]></dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[How To]]></category>
		<category><![CDATA[JavaScript]]></category>

		<guid isPermaLink="false">http://www.lindenlan.net/?p=375</guid>
		<description><![CDATA[My favorite jQuery plugin by far has to be the jQuery Cycle Plugin. It’s a generic slideshow plugin, but it’s versatile enough that I’ve used it to build a slider, a portfolio, and just recently, an iPhoto-like image flipper. This was inspired from the CJ Image FlipBox. Unfortunately, the way the plugin is designed, you [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>My favorite jQuery plugin by far has to be the <a href="http://malsup.com/jquery/cycle/">jQuery Cycle Plugin</a>.  It’s a generic slideshow plugin, but it’s versatile enough that I’ve used it to build a slider, a portfolio, and just recently, an iPhoto-like image flipper.  This was inspired from the <a href="http://www.cjboco.com/blog.cfm/post/a-nice-jquery-plug-in-that-mimics-apple-s-iphoto-app-to-display-a-group-of-images">CJ Image FlipBox</a>.  Unfortunately, the way the plugin is designed, you can’t mesh it with <a href="http://fancybox.net/">Fancybox</a> because the plugin creates an anchor and an image which intercept the mouseclicks preventing the Fancybox from activating.  So to get around the problem, I used the Cycle plugin to create my own.</p>
<p><span id="more-375"></span></p>
<pre class="brush: html">
&lt;div id=&quot;gallery1&quot; class=&quot;gallery&quot;&gt;
    &lt;a rel=&quot;gallery1&quot; href=&quot;/path/to/fullsize1.jpg&quot;&gt;&lt;img src=&quot;/path/to/thumbnail1.jpg&quot; width=&quot;50&quot; height=&quot;50&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;
    &lt;a rel=&quot;gallery1&quot; href=&quot;/path/to/fullsize2.jpg&quot;&gt;&lt;img src=&quot;/path/to/thumbnail2.jpg&quot; width=&quot;50&quot; height=&quot;50&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;
    &lt;a rel=&quot;gallery1&quot; href=&quot;/path/to/fullsize3.jpg&quot;&gt;&lt;img src=&quot;/path/to/thumbnail3.jpg&quot; width=&quot;50&quot; height=&quot;50&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;
&lt;/div&gt;
</pre>
<p>The HTML is rather straight forward.  You’ve got a &lt;div&gt; as a container for a bunch of thumbnails, each linked to a matching fullsize image.   The CSS on the gallery has fixed dimensions matching the dimensions of the thumbnails with overflow set to hidden.  </p>
<pre class="brush: javascript">
$(&quot;.gallery&quot;).cycle({ 
    speed:      0,
    timeout:    0
});

$(&quot;.gallery&quot;).mousemove(function(e){
    var n = $(this).children().length;
    var w = $(this).width();
    var x = e.pageX - this.offsetLeft;
    var i = Math.floor(x/w * n);

    $(this).cycle(i);
}); 

$(&quot;.gallery a&quot;).fancybox();
</pre>
<p>As for the JavaScript, it’s refreshingly short, which just goes to show how much heavylifting jQuery and the two plugins do.  Let’s start with the Cycle activation.   The speed parameter is set to 0.  This means that the transition is instantaneous when an image flips.  Setting the timeout parameter to 0 prevents the Cycle plugin from auto-advancing.  So far nothing new for anyone who’s used the Cycle plugin.</p>
<p>The next part actually sets up the effect.  Just like when you mouseover an Event group in iPhoto, whenever the mouse moves within the gallery div, the position of the mouse determines the index of the image to display.  First we count the number of images within the gallery.  Next, we get the width of the gallery.  Then we get the horizontal position of the mouse within the gallery’s coordinate system.  Finally, we use those three values to calculate the index.  Using this index, we tell the Cycle plugin which image to display.</p>
<p>Now that the iPhoto effect is working, all that’s left is to activate the Fancybox plugin and we’re done. </p>
]]></content:encoded>
			<wfw:commentRss>http://www.lindenlan.net/2010/04/07/how-to-build-an-iphoto-image-flipper-using-the-jquery-cycle-plugin/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Make Rails Play Nice With FLVPlayback Skin</title>
		<link>http://www.lindenlan.net/2010/04/03/make-rails-play-nice-with-flvplayback-skin/</link>
		<comments>http://www.lindenlan.net/2010/04/03/make-rails-play-nice-with-flvplayback-skin/#comments</comments>
		<pubDate>Sat, 03 Apr 2010 08:11:02 +0000</pubDate>
		<dc:creator><![CDATA[Brian]]></dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[Apache]]></category>
		<category><![CDATA[Flash]]></category>
		<category><![CDATA[Ruby on Rails]]></category>

		<guid isPermaLink="false">http://www.lindenlan.net/?p=372</guid>
		<description><![CDATA[Flash assets like an FLVPlayback skin will typically be located in your public folder. However, according to http://kb2.adobe.com/cps/608/608abffd.html, “in a loading scenario, the skin SWF for the FLVPlayback component must be relative to the loading HTML file containing the parent SWF on the server, not to the location of the loaded SWF.” This is bad, [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Flash assets like an FLVPlayback skin will typically be located in your public folder.  However, according to <a href="http://kb2.adobe.com/cps/608/608abffd.html">http://kb2.adobe.com/cps/608/608abffd.html</a>, “in a loading scenario, the skin SWF for the FLVPlayback component must be relative to the loading HTML file containing the parent SWF on the server, not to the location of the loaded SWF.”  This is bad, since when you load a page, the URL will typically be /:controller/:action,  which means the FLVPlayback skin URL will be /:controller/myskin.swf even if your parent SWF is in /public.  You can verify this in Firebug on the Net tab.  The problem will manifest itself with a loaded Flash movie with no controls.  You can fix this by creating a rewrite rule in your .htaccess file.</p>
<pre class="brush: bash">
RewriteRule ^.*/myskin.swf$ /pathto/myskin.swf
</pre>
<p>Any request ending in myskin.swf will be redirected to /pathto/myskin.swf under the public folder.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.lindenlan.net/2010/04/03/make-rails-play-nice-with-flvplayback-skin/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>How To Simultaneously Add Multiple Products To A Magento Shopping Cart</title>
		<link>http://www.lindenlan.net/2009/09/27/how-to-simultaneously-add-multiple-products-to-a-magento-shopping-cart/</link>
		<comments>http://www.lindenlan.net/2009/09/27/how-to-simultaneously-add-multiple-products-to-a-magento-shopping-cart/#comments</comments>
		<pubDate>Mon, 28 Sep 2009 02:01:38 +0000</pubDate>
		<dc:creator><![CDATA[Brian]]></dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Magento]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.lindenlan.net/?p=349</guid>
		<description><![CDATA[This post is a bit overdue considering the project for which I did this was completed months ago. I finally got around to documenting it. Magento’s product list view lets customers add products to the shopping cart one at a time. The client wanted customers to be able to add multiple products to the shopping [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>This post is a bit overdue considering the project for which I did this was completed months ago.  I finally got around to documenting it.  Magento’s product list view lets customers add products to the shopping cart one at a time.  The client wanted customers to be able to add multiple products to the shopping cart simultaneously.  Given the time constraints for the projects, I created an ad hoc AJAX method to accomplish this feature request.</p>
<p><span id="more-349"></span></p>
<p>Adding a product to a Magento (ver. 1.3.1) shopping cart is accomplished through an HTTP GET request.  It will look like or similar to this:</p>
<pre class="brush: sh">
/path/to/app/checkout/cart/add?product=[id]&amp;qty=[qty]
</pre>
<p>That URL is output by the template helper:</p>
<pre class="brush: php">
$this-&gt;getAddToCartUrl($_product)
</pre>
<p>Since adding a product to the shopping cart is nothing more than a GET request, then all that needs to be done is queue up the URLs of the desired products, make each request in order, and then reload the page when done.</p>
<p>First, in app/design/frontend/
<package>/
<theme>/template/catalog/product/list.html, I first added checkboxes to allow customers to select which products they want and also hidden fields for storing the URLs to add the product and text fields for the quantity. </p>
<pre class="brush: php">
&lt;input type=&quot;checkbox&quot; class=&quot;input-checkbox add&quot; name=&quot;add_&lt;?php echo $_iterator; ?&gt;&quot; id=&quot;add_&lt;?php echo $_iterator; ?&gt;&quot; /&gt;
&lt;input type=&quot;hidden&quot; name=&quot;url_&lt;?php echo $_iterator; ?&gt;&quot; id=&quot;url_&lt;?php echo $_iterator; ?&gt;&quot; value=&quot;&lt;?php echo $this-&gt;getAddToCartUrl($_product) ?&gt;&quot; /&gt;
&lt;?php if(!$_product-&gt;isGrouped()): ?&gt;
     &lt;input type=&quot;text&quot; class=&quot;input-text qty&quot; name=&quot;qty_&lt;?php echo $_iterator; ?&gt;&quot; id=&quot;qty_&lt;?php echo $_iterator; ?&gt;&quot; maxlength=&quot;12&quot; value=&quot;&lt;?php echo $this-&gt;getMinimalQty($_product) ?&gt;&quot; /&gt;
&lt;?php endif; ?&gt;
</pre>
<p>I added this code within the loop that generate the HTML for the product line items for the list.  Next, I added the JavaScript that does the actual processing, also within the list section right after the script block that contains: <code>decorateList('products-list', 'none-recursive')</code>.</p>
<pre class="brush: javascript">
&lt;script type=&quot;text/javascript&quot;&gt;
    function processNext(urls, i) {
        var next = i + 1;
        $(&#039;processing-text&#039;).update(&#039;Processing item &#039; + next);
        if (next &lt; urls.size()) {
            new Ajax.Request(urls[i], {
              method: &#039;get&#039;,
              onComplete: function(transport) {
                processNext(urls, next);
              }
            });
        } else {
            new Ajax.Request(urls[i], {
              method: &#039;get&#039;,
              onComplete: function(transport) {
                window.location.reload();
              }
            });
        }
    }

    function addItemsToCart() {
        $(&#039;add-items-to-cart&#039;).hide();
        $(&#039;waiting&#039;).show();
        
        var addToCartUrls = [];
        $$(&#039;input.add&#039;).each(function(e){ 
            if(e.checked == true) {
                var id = e.readAttribute(&#039;id&#039;).split(&#039;_&#039;)[1];
                var qty = Number($(&#039;qty_&#039; + id).value);
                if (qty &lt; 1) qty = 1;
                addToCartUrls.push($(&#039;url_&#039; + id).value + &#039;qty/&#039; + qty);
            }
        });
        
        if (addToCartUrls.size() &gt; 0) {
            processNext(addToCartUrls, 0);
        } else {
            $(&#039;add-items-to-cart&#039;).show();
            $(&#039;waiting&#039;).hide();
            alert(&#039;Please check off the items you want to add.&#039;);
        }
    }
&lt;/script&gt;
</pre>
<p>At the bottom of the list I added a submit button.</p>
<pre class="brush: php">
&lt;div style=&quot;margin-bottom:5px; text-align:right;&quot;&gt;&lt;button id=&quot;add-items-to-cart&quot; class=&quot;form-button&quot; onclick=&quot;addItemsToCart()&quot;&gt;&lt;span&gt;&lt;?php echo $this-&gt;__(&#039;Add Items to Cart&#039;) ?&gt;&lt;/span&gt;&lt;/button&gt;&lt;div id=&quot;waiting&quot; style=&quot;height:22px; display:none; line-height:22px;&quot;&gt;&lt;span id=&quot;processing-text&quot;&gt;Processing...&lt;/span&gt; &lt;img src=&quot;&lt;?php echo $this-&gt;getSkinUrl().&#039;images/wait22trans.gif&#039;; ?&gt;&quot; width=&quot;22&quot; height=&quot;22&quot; style=&quot;display:inline; vertical-align:middle;&quot;/&gt;&lt;/div&gt;&lt;/div&gt;
</pre>
<p>Clicking the button calls the function <code>addItemsToCart()</code>.  The function hides the button to prevent a double click and unhides the status message.  Next, the function determines which checkboxes are checked.  For each checked checkbox, the function finds the corresponding URL field and quantity field, concatenates the two values, and stores the new URL in an array.  If the length of the array is greater than 0, then the function calls <code>processNext()</code>, otherwise it displays an error message and resets the submit button.</p>
<p>The function <code>processNext()</code> first updates the processing message.  The function takes the array of URLs and an index, and then creates an AJAX GET request using the URL at the given index in the array.  If the AJAX request completes, it calls processNext() with the same array but with an incremented index while the index is less than the array length.  If the incremented index is greater than the array length, then that ends the processing and the function reloads the page.</p>
<p>That’s it.  If there is anything wrong with the code, it assumes that all the GET requests will complete.  Unfortunately, given the time constraints there was no time to account for the scenario where a GET request fails.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.lindenlan.net/2009/09/27/how-to-simultaneously-add-multiple-products-to-a-magento-shopping-cart/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>MyGoogleCal is now RESTYLEgc</title>
		<link>http://www.lindenlan.net/2009/07/06/mygooglecal-is-now-restylegc/</link>
		<comments>http://www.lindenlan.net/2009/07/06/mygooglecal-is-now-restylegc/#comments</comments>
		<pubDate>Mon, 06 Jul 2009 16:24:40 +0000</pubDate>
		<dc:creator><![CDATA[Admin]]></dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[CSS]]></category>
		<category><![CDATA[Google]]></category>
		<category><![CDATA[Hacking]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[RESTYLEgc]]></category>

		<guid isPermaLink="false">http://www.lindenlan.net/?p=323</guid>
		<description><![CDATA[I finally got around to spinning off MyGoogleCal as a separate website. I opted to rename the script to RESTYLEgc to avoid stepping on Google’s toes. It was something that’s been gestating over the past year. I completed the site over the holiday weekend since I had the time available. The new site is at [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>I finally got around to spinning off MyGoogleCal as a separate website.  I opted to rename the script to RESTYLEgc to avoid stepping on Google’s toes.  It was something that’s been gestating over the past year.  I completed the site over the holiday weekend since I had the time available.  The new site is at <a href="http://www.restylegc.com/">www.restylegc.com</a>.  I’m also hosting the script at <a href="http://code.google.com/p/restylegc">Google Code</a>, and I even added a <a href="http://groups.google.com/group/RESTYLEgc">Google Group</a> to facilitate discussions.  After seeing the comments top 100, I realize a blog really isn’t suitable for lengthy discussions.  Hopefully, the forum and wiki features will be better for the end-user.</p>
<p>I updated MyGoogleCal4 with a small bugfix this weekend as well.  That will be the last update.  Future development will continue with RESTYLEgc.  Since the code was originally public domain, I opted to go with an MIT open source license.  I also got the code in a Subversion repository which I should’ve done a long time ago.  With the Issues tab at Google Code, I can better track and encourage bug reports and feature requests.</p>
<p>The code is still free, but paid support is available.  I’ve also got some other ideas of where I want to take the site.  So stay tuned!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.lindenlan.net/2009/07/06/mygooglecal-is-now-restylegc/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>How To Fake a Magento Subpage</title>
		<link>http://www.lindenlan.net/2009/04/21/how-to-fake-a-magento-subpage/</link>
		<comments>http://www.lindenlan.net/2009/04/21/how-to-fake-a-magento-subpage/#comments</comments>
		<pubDate>Tue, 21 Apr 2009 14:52:50 +0000</pubDate>
		<dc:creator><![CDATA[Admin]]></dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[Magento]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.lindenlan.net/?p=308</guid>
		<description><![CDATA[Magento, an open-source PHP ecommerce solution, has a very comprehensive feature list. However, its built-in CMS doesn’t support hierarchical pages. You can fake it, though. Let’s say you have a page with an SEF (search engine friendly) URL Identifier of “foo”. You’d like to have a subpage “bar” nested under foo. The CMS doesn’t let [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Magento, an open-source PHP ecommerce solution, has a very comprehensive feature list.  However, its built-in CMS doesn’t support hierarchical pages.  You can fake it, though.  </p>
<p><span id="more-308"></span></p>
<p>Let’s say you have a page with an SEF (search engine friendly) URL Identifier of “foo”.  You’d like to have a subpage “bar” nested under foo.  The CMS doesn’t let you create parent-child relationships, but Magento will let you include forward slashes in the SEF URL Identifier so that it is “foo/bar”.  </p>
<p>That’s the good news.  The bad news is if you want to use the breadcrumbs block, it won’t work out of the box.  The Magento CMS is flat, so the default breadcrumbs will always look like “Home / My Page Title.”  The optimal solution is to override the breadcrumbs module and parse the SEF URL Identifier and construct the breadcrumbs from that.  (I may write a post about it in the future so stay tuned.)  The good news for those designers out there, you don’t have to dive into code.  </p>
<p>Magento’s CMS has a feature where each page has a way to override its XML layout.  When you’re editing a page, go to the “Custom Design” tab.  There you’ll see a form field called “Layout Update XML”.  This is the key.  Here’s where you add XML to first unset the breadcrumbs block and then add it back in but with your specific breadcrumbs.  Here’s the code:</p>
<pre class="brush: html">
&lt;reference name=&quot;root&quot;&gt;
&lt;action method=&quot;unsetChild&quot;&gt;&lt;alias&gt;breadcrumbs&lt;/alias&gt;&lt;/action&gt;
&lt;/reference&gt;

&lt;reference name=&quot;root&quot;&gt;
&lt;block type=&quot;page/html_breadcrumbs&quot; name=&quot;breadcrumbs&quot; as=&quot;breadcrumbs&quot;&gt;
    &lt;action method=&quot;addCrumb&quot;&gt;
        &lt;crumbName&gt;home&lt;/crumbName&gt;
        &lt;crumbInfo&gt;&lt;label&gt;Home&lt;/label&gt;&lt;title&gt;Go to Home Page&lt;/title&gt;&lt;link&gt;/&lt;/link&gt;&lt;/crumbInfo&gt;
    &lt;/action&gt;             
    &lt;action method=&quot;addCrumb&quot;&gt;
        &lt;crumbName&gt;foo&lt;/crumbName&gt;
        &lt;crumbInfo&gt;&lt;label&gt;Foo&lt;/label&gt;&lt;title&gt;Foo&lt;/title&gt;&lt;link&gt;/foo/&lt;/link&gt;&lt;/crumbInfo&gt;
    &lt;/action&gt;             
    &lt;action method=&quot;addCrumb&quot;&gt;
        &lt;crumbName&gt;cms_page&lt;/crumbName&gt;
        &lt;crumbInfo&gt;&lt;label&gt;Bar&lt;/label&gt;&lt;title&gt;Bar&lt;/title&gt;&lt;/crumbInfo&gt;
    &lt;/action&gt;                  
&lt;/block&gt;
&lt;/reference&gt;
</pre>
<p>The first reference tells Magento to call the unset action on the root block to remove the original breadcrumbs.  The second reference tells Magento to add a new breadcrumbs block.  Then within that block it tells Magento to add three new breadcrumbs, one for “home”, one for “foo”, and another for “bar”.  crumbName is just a unique identifier.  Under crumbInfo, label is the link text, title is the hover text, and link is the URL.  You need to include the root forward slash.  The trailing slash is optional, but to be consistent with Magento you should include it.</p>
<p>And that’s all there is to it.  If you have a Magento site with lots of CMS subpages or pages that are deeply nested, then this method can get tedious.  That’s why I said the optimal solution is to override the breadcrumbs module in core as a local modification.  If you don’t have many CMS subpages and they’re only one-level deep, then this method is adequate.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.lindenlan.net/2009/04/21/how-to-fake-a-magento-subpage/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>iPhone Says Hello</title>
		<link>http://www.lindenlan.net/2009/03/18/iphone-says-hello/</link>
		<comments>http://www.lindenlan.net/2009/03/18/iphone-says-hello/#comments</comments>
		<pubDate>Wed, 18 Mar 2009 16:42:29 +0000</pubDate>
		<dc:creator><![CDATA[Brian]]></dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[iPhone]]></category>
		<category><![CDATA[Objective-C]]></category>

		<guid isPermaLink="false">http://www.lindenlan.net/?p=302</guid>
		<description><![CDATA[I finally got around to downloading the iPhone SDK to see what I can do with it. Since I’ve dabbled in game development back when I worked with Flash and Director, I figured I’d see what I can do with the iPhone. I wanted to start with a framework and I looked at Torque and [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>I finally got around to downloading the iPhone SDK to see what I can do with it.  Since I’ve dabbled in game development back when I worked with Flash and Director, I figured I’d see what I can do with the iPhone.  I wanted to start with a framework and I looked at <a href="http://www.garagegames.com/products/torque-2d/iphone">Torque</a> and <a href="http://unity3d.com/unity/features/iphone-publishing.html">Unity</a>.  Though inexpensive by game engine standards, during a recessionary time of cost cutting, it’s hard to validate a nearly $1000 purchase, especially if you don’t know yet if that investment would pay off.  So I finally settled on the <a href="http://code.google.com/p/cocos2d-iphone/">cocos2d-iphone</a> framework which is based on the <a href="http://cocos2d.org/">cocos2d</a> framework for Python.  There is little to no documentation, so be prepared to read source code.  <a href="http://monoclestudios.com/cocos2d_whitepaper.html">Monocle Studio’s whitepaper</a> will definitely help you bootstrap your project.  In the spirit of that paper, I thought I’d share my translation of the <a href="http://cocos2d.org/doc/programming_guide/hello_world.html">cocos2d “Hello, World” example</a> adapted for the cocos2d-iphone framework.</p>
<p><span id="more-302"></span></p>
<p>First step is to setup your project according to <a href="http://monoclestudios.com/cocos2d_whitepaper.html">Monocle Studio’s whitepaper</a> through “Cleaning up the project” right before “Creating a main menu”.  That’ll create the base project.  You’ll probably want to change the name to something else (e.g. CocosHelloWorld) instead of SimpleGame.  Make sure to change the name where appropriate, for example SimpleGameAppDelegate should be YourAppNameAppDelegate.</p>
<h2>Create the HelloWorld class</h2>
<ol>
<li>Click the Classes group in Groups &amp; Files pane.</li>
<li>Click the Action button</li>
<li>Select Add-&gt;New File…</li>
<li>Choose NSObject subclass</li>
<li>Name the class “HelloWorld”</li>
</ol>
<p><br/></p>
<p>Open HelloWorld.h and change the code to look like the following.  This says that the HelloWorld class is derived from the Layer class (which is derived from the CocosNode class).  </p>
<pre class="brush: cpp">
#import &lt;UIKit/UIKit.h&gt;
#import &quot;cocos2d.h&quot;

@interface HelloWorld : Layer {

}
@end
</pre>
<p>Open HelloWorld.m and change the code to the following.  This says that the HelloWorld class uses its parent class for initialization.  If the initialization is successful, then create a new label, place it in the center, and add it to the layer.  Finally, it returns itself.</p>
<pre class="brush: cpp">
#import &quot;HelloWorld.h&quot;

@implementation HelloWorld

- (id) init {
    self = [super init];
    if (self != nil) {
		Label *label = [Label labelWithString:@&quot;Hello, World!&quot; 
									 fontName:@&quot;Times New Roman&quot; 
									 fontSize:32];
		label.position = cpv(240,160);
		[self add:label];
    }
    return self;	
}

@end
</pre>
<h2>Setup the Director</h2>
<p>Open up YourAppNameAppDelegate.h and change the include declarations to:</p>
<pre class="brush: cpp">
#import &lt;UIKit/UIKit.h&gt;
#import &quot;cocos2d.h&quot;
#import &quot;HelloWorld.h&quot;
</pre>
<p>Next open YourAppNameAppDelegate.m and change it to the following.  The difference between this and the corresponding method in SimpleGame are the last two lines.  The first creates a Scene node and adds a HelloWorld node to the scene.  The next line starts the Director using the just created Scene as the initial scene.  The previous set of lines prepare the iPhone display by initializing a window, enabling the UI for the window, setting the Director to display in landscape mode, then attach the Director to the window, and finally making the window the main window and turning it on.</p>
<pre class="brush: cpp">
#import &quot;CocosHelloWorldAppDelegate.h&quot;

@implementation CocosHelloWorldAppDelegate

- (void)applicationDidFinishLaunching:(UIApplication *)application {    
    UIWindow *window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    [window setUserInteractionEnabled:YES];
    [window setMultipleTouchEnabled:YES];
    [[Director sharedDirector] setLandscape: YES];
    [[Director sharedDirector] attachInWindow:window];
	
    [window makeKeyAndVisible];
	
    Scene *s = [[Scene node] add:[HelloWorld node]];
	
    [[Director sharedDirector] runWithScene:s];	
}

@end
</pre>
<p>If all is well, if you click Build &amp; Go the iPhone simulator should display “Hello, World!”.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.lindenlan.net/2009/03/18/iphone-says-hello/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>It’s Tax(onomy) Season</title>
		<link>http://www.lindenlan.net/2009/03/10/its-taxonomy-season/</link>
		<comments>http://www.lindenlan.net/2009/03/10/its-taxonomy-season/#comments</comments>
		<pubDate>Tue, 10 Mar 2009 16:51:33 +0000</pubDate>
		<dc:creator><![CDATA[Brian]]></dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[Drupal]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.lindenlan.net/?p=298</guid>
		<description><![CDATA[Drupal has a Taxonomy module for categorizing content. The module can generate a select box based on the defined taxonomy. However, it does not support option groups. I figured I’d share my modification for those who’d like to do the same. It was based on code from a Drupal forum post which I think was [&#8230;]]]></description>
				<content:encoded><![CDATA[<p><a href="http://drupal.org/">Drupal</a> has a <a href="http://drupal.org/node/299">Taxonomy</a> module for categorizing content.  The module can generate a select box based on the defined taxonomy.  However, it does not support option groups.  I figured I’d share my modification for those who’d like to do the same.  It was based on code from <a href="http://drupal.org/node/76500">a Drupal forum post</a> which I think was based on Drupal 5, not 6.</p>
<p><span id="more-298"></span></p>
<p>The code that needs to be modified is from _taxonomy_term_select() in modules/taxonomy/taxonomy.module, after line 1032.</p>
<pre class="brush: php">
function _taxonomy_term_select($title, $name, $value, $vocabulary_id, $description, $multiple, $blank, $exclude = array()) {
  $tree = taxonomy_get_tree($vocabulary_id);
  $options = array();

  if ($blank) {
    $options[&#039;&#039;] = $blank;
  }
  if ($tree) {
    $curr_group = &#039;&#039;;
    foreach ($tree as $term) {
      if (!in_array($term-&gt;tid, $exclude)) {
        if($term-&gt;parents[0] == 0) {
          $curr_group=$term-&gt;name;
          $options[$curr_group] = array();        
        }
        else {
          $choice = new stdClass();
          $choice-&gt;option = array($term-&gt;tid =&gt; str_repeat(&#039;-&#039;, $term-&gt;depth) . $term-&gt;name);
          $options[$curr_group][] = $choice;
        }
      }
    }
  }

  return array(&#039;#type&#039; =&gt; &#039;select&#039;,
    &#039;#title&#039; =&gt; $title,
    &#039;#default_value&#039; =&gt; $value,
    &#039;#options&#039; =&gt; $options,
    &#039;#description&#039; =&gt; $description,
    &#039;#multiple&#039; =&gt; $multiple,
    &#039;#size&#039; =&gt; $multiple ? min(9, count($options)) : 0,
    &#039;#weight&#039; =&gt; -15,
    &#039;#theme&#039; =&gt; &#039;taxonomy_term_select&#039;,
  );
}
</pre>
<p>Essentially, the code simply iterates through the tree like the original code, except when it encounters a root node it creates a new key with an array value to contain the individual options, thereby creating an option group using the term’s name as its label.  The code isn’t very flexible since it won’t account for root nodes with no children.  Also it doesn’t account for options with a depth greater than 1, in which case you’d probably want to set a class and disabled attribute to make it look and act like an option group (since option groups can’t be nested).  Such a change would also involve modifying form_select_options() in includes/form.inc since attributes for option tags is not supported.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.lindenlan.net/2009/03/10/its-taxonomy-season/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Gotcha!</title>
		<link>http://www.lindenlan.net/2009/03/02/gotcha/</link>
		<comments>http://www.lindenlan.net/2009/03/02/gotcha/#comments</comments>
		<pubDate>Mon, 02 Mar 2009 16:24:34 +0000</pubDate>
		<dc:creator><![CDATA[Brian]]></dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[Ruby on Rails]]></category>

		<guid isPermaLink="false">http://www.lindenlan.net/?p=289</guid>
		<description><![CDATA[So I had to move an application that I’m developing from a MediaTemple (dv) Dedicated-Virtual to a Ruby on Rails GridContainer running on a MediaTemple (gs) Grid-Service. Most of the tutorials I found that covered installing a Rails app on a GridContainer were somewhat dated. Things that were different than expected include: Rails, a few [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>So I had to move an application that I’m developing from a <a href="http://mediatemple.net/webhosting/dv/">MediaTemple (dv) Dedicated-Virtual</a> to a <a href="http://mediatemple.net/webhosting/gs/features/containers.php#ror">Ruby on Rails GridContainer</a> running on a <a href="http://mediatemple.net/webhosting/gs/">MediaTemple (gs) Grid-Service</a>.   Most of the tutorials I found that covered installing a Rails app on a GridContainer were somewhat dated.  Things that were different than expected include:</p>
<ol>
<li>Rails, a few precompiled gems (like RMagick), and a test app are automatically installed for you.  Most of the tutorials walk you through installing Rails and the skeleton app from SSH.  That’s no longer necessary.</li>
<li>For Capistrano, you need to set the <code>syspath</code> option (“System” in the control panel) to <code>/home/[xxxxx]/containers/rails/[app_path]/current</code> where [xxxxx] is your GridContainer number and [app_path] is where you want your app located.   I kept the app path and app name the same.</li>
<li>You can’t edit application options from the web control panel.  You have to do this from a SSH session using <code>mtr set_option</code>.  You may need to do this to change the <code>syspath</code> or to set the <code>environment</code>.  For example, to set the environment to “staging” you use the following command: <code>mtr set_option [app_name] environment=staging</code>.</li>
<li>If you change the <code>syspath</code> make sure to update the symbolic link to the app’s public folder under your app’s domain, otherwise you’ll get an app not found error.  In other words, <code>~/domains/example.com/html</code> should point to <code>/home/[xxxxx]/containers/rails/[app_path]/current/public</code>.
<li>When an application fails to start, you get no feedback about the cause.  Check log/mongrel.log for details as to why your application fails to start.</li>
<li>After changing the <code>syspath</code>, the app may not restart.  You may get an <code>Address already in use - bind(2) (Errno::EADDRINUSE)</code>.  To resolve this, I ended up having to reboot the container.</li>
<li>For some reason, <code>rake gems:install</code> didn’t work.  I had to manually install each gem.</li>
</ol>
<p><br/></p>
<p>I definitely had a lot more control over the installation when I had the application running on the (dv)  using <a href="http://www.modrails.com/">Passenger Phusion</a>, especially having the ability to compile software.  However, the GridContainer runs a lot faster.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.lindenlan.net/2009/03/02/gotcha/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
