<?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; JavaScript</title>
	<atom:link href="http://www.lindenlan.net/tag/javascript/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>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>New Portfolio</title>
		<link>http://www.lindenlan.net/2009/11/14/new-portfolio/</link>
		<comments>http://www.lindenlan.net/2009/11/14/new-portfolio/#comments</comments>
		<pubDate>Sat, 14 Nov 2009 07:04:17 +0000</pubDate>
		<dc:creator><![CDATA[Admin]]></dc:creator>
				<category><![CDATA[Personal]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[WordPress]]></category>

		<guid isPermaLink="false">http://www.lindenlan.net/?p=360</guid>
		<description><![CDATA[I launched my new portfolio to showcase some of the work I have accomplished over the past year. I technically launched it at the beginning of the week, but didn’t add the last item until today. I put it on a separate domain so that I can brand myself and have a site focused on [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>I launched my new portfolio to showcase some of the work I have accomplished over the past year.  I technically launched it at the beginning of the week, but didn’t add the last item until today.   I put it on a separate domain so that I can brand myself and have a site focused on my work, plus any visitors would not be distracted by my blog posts.  </p>
<p>It’s built using WordPress, but you wouldn’t know it by looking at it.  This way I can add and remove samples easily.  I opted to go with a (mostly) single-page site.  There’s a second page for a contact form.   jQuery and various plugins handle the dynamic features.  I definitely prefer this over what I had before.</p>
<p>Feel free to check it out by clicking the Portfolio link above.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.lindenlan.net/2009/11/14/new-portfolio/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>Restyle Google Calendar 4</title>
		<link>http://www.lindenlan.net/2008/12/04/restyle-google-calendar-4/</link>
		<comments>http://www.lindenlan.net/2008/12/04/restyle-google-calendar-4/#comments</comments>
		<pubDate>Thu, 04 Dec 2008 07:00:55 +0000</pubDate>
		<dc:creator><![CDATA[Brian]]></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>

		<guid isPermaLink="false">http://www.lindenlan.net/?p=252</guid>
		<description><![CDATA[As a few users of MyGoogleCal3 have already pointed out, the script no longer works properly. That’s the bad news. The good news is version 4 does work. In fact, with the latest changes Google made to their code, ALL the features that were broken in 3 appear to be working now—Agenda/Week view, the calendar [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>As a few users of <a href="http://www.lindenlan.net/2008/04/23/restyle-google-calendar-3/">MyGoogleCal3</a> have already pointed out, the script no longer works properly.  That’s the bad news.  The good news is version 4 does work.  In fact, with the latest changes Google made to their code, ALL the features that were broken in 3 appear to be working now—Agenda/Week view, the calendar navigation buttons, and IE is fixed.   Please download and test out the latest version, and report any bugs in the comments and I’ll try to resolve them as time allows.</p>
<p><span id="more-252"></span><br />
<strong>UPDATE (2009 July 5):</strong> <a href="http://www.lindenlan.net/2009/07/06/mygooglecal-is-now-restylegc/">MyGoogleCal is now RESTYLEgc</a>.</p>
<p><strong>UPDATE (2009 June 23):</strong> Google’s recent update broke the jQuery injection.  In fact, the update is incompatible with injecting jQuery, Prototype, and MooTools.  The only JavaScript framework that works is Dojo.  I updated the code to inject that framework instead.  For those people who value stability over having the latest and greatest features, I also added a comment to MyGoogleCal4js.php that explains how to freeze the calendar version.  That should hopefully help all you fellow developers who tire of your clients calling you when their calendar breaks.</p>
<p><strong>UPDATE (2009 May 3):</strong> <span style="text-decoration: line-through;">MyGoogleCal4 now supports jQuery manipulation of the DOM.</span>  This gives the ability to apply styles after page load.  As an example, the default code removes the inline style on the body tag allowing the stylesheet to set the background color.  The default code also removes the width property from the inline style of the bubble class so that its width can be set in the stylesheet as well.  This should help overcome many of the problems that can’t be solved directly using a stylesheet.  You can thank <a href="http://techtriad.com/">TechTriad.com</a> for funding this new feature.</p>
<p>Download: <a href='http://www.lindenlan.net/wp-content/uploads/2008/12/mygooglecal4.zip'>mygooglecal4.zip</a>.  Contains MyGoogleCal4.php, MyGoogleCal4js.php, mygooglecal4.css, and images.  The CSS file is not guaranteed to be up-to-date so you may have to follow the instructions described in the PHP file to download the latest version from Google.  phpinfo.php is used for diagnostic purposes to make sure your PHP installation is working and that it has the required plugins.  In the archive folder, you can find previous versions of Google’s Javascript and CSS files, in case you want to use those (see MyGoogleCal4js.php).</p>
<pre class="brush: php">
&lt;?php
/*******************************************************************************
 * FILE: MyGoogleCal4.php
 *
 * DESCRIPTION:
 *  This script is an intermediary between an iframe and Google Calendar that
 *  allows you to override the default style.
 *
 * USAGE:
 *  &lt;iframe src=&quot;MyGoogleCal4.php?src=user%40domain.tld&quot;&gt;&lt;/iframe&gt;
 *
 *  where user@domain.tld is a valid Google Calendar account.
 *
 * VALID QUERY STRING PARAMETERS:
 *    title:         any valid url encoded string 
 *                   if not present, takes title from first src
 *    showTitle:     0 or 1 (default)
 *    showNav:       0 or 1 (default)
 *    showDate:      0 or 1 (default)
 *    showTabs:      0 or 1 (default)
 *    showCalendars: 0 or 1 (default)
 *    mode:          WEEK, MONTH (default), AGENDA
 *    height:        a positive integer (should be same height as iframe)
 *    wkst:          1 (Sun; default), 2 (Mon), or 7 (Sat)
 *    hl:            en, zh_TW, zh_CN, da, nl, en_GB, fi, fr, de, it, ja, ko, 
 *                   no, pl, pt_BR, ru, es, sv, tr
 *                   if not present, takes language from first src
 *    bgcolor:       url encoded hex color value, #FFFFFF (default)
 *    src:           url encoded Google Calendar account (required)
 *    color:         url encoded hex color value     
 *                   must immediately follow src
 *    
 *    The query string can contain multiple src/color pairs.  It&#039;s recommended 
 *    to have these pairs of query string parameters at the end of the query 
 *    string.
 *
 * HISTORY:
 *   03 December 2008 - Original release
 *                      Uses technique from MyGoogleCal2 for all browsers,
 *                      rather than giving IE special treatment.
 *   16 December 2008 - Modified MyGoogleCal4js.php so that the regex does a
 *                      general match rather than specifically look for the
 *                      variable &#039;Ac&#039;.
 *   Mar--Apr    2009 - Added jQuery for modifying the style after page load
 *   23 June     2009 - Replaced jQuery with Dojo since jQuery, Prototype, and
 *                      MooTools are not compatible
 *   05 July     2009 - Fixed bug to remove width style from bubble
 *                      
 *   
 * ACKNOWLEDGMENTS:
 *   Michael McCall (http://www.castlemccall.com/) for pointing out &quot;htmlembed&quot;
 *   Mike (http://mikahn.com/) for the link to the online CSS formatter
 *   TechTriad.com (http://techtriad.com/) for requesting and funding the 
 *       Javascript code to edit CSS properties and for selflessly letting the
 *       code be published for everyone&#039;s use and benefit.
 *   
 *
 * copyright (c) by Brian Gibson
 * email: bwg1974 yahoo com
 ******************************************************************************/

/* URL for overriding stylesheet
 * The best way to create this stylesheet is to 
 * 1) Load &quot;http://www.google.com/calendar/embed?src=user%40domain.tld&quot; in a
 *    browser,
 * 2) View the source (e.g., View-&gt;Page Source in Firefox),
 * 3) Copy the relative URL of the stylesheet (i.e., the href value of the 
 *    &lt;link&gt; tag), 
 * 4) Load the stylesheet in the browser by pasting the stylesheet URL into 
 *    the address bar so that it reads similar to:
 *    &quot;http://www.google.com/calendar/d003e2eff7c42eebf779ecbd527f1fe0embedcompiled.css&quot;
 * 5) Save the stylesheet (e.g., File-&gt;Save Page As in Firefox)
 * Edit this new file to change the style of the calendar.
 *
 * As an alternative method, take the URL you copied in Step 3, and paste it
 * in the URL field at http://mabblog.com/cssoptimizer/uncompress.html.
 * That site will automatically format the CSS so that it&#039;s easier to edit.
 */
$stylesheet = &#039;mygooglecal4.css&#039;;

/*******************************************************************************
 * DO NOT EDIT BELOW UNLESS YOU KNOW WHAT YOU&#039;RE DOING
 ******************************************************************************/

// URL for the calendar
$url = &quot;&quot;;
if(count($_GET) &gt; 0) {
  $url = &quot;http://www.google.com/calendar/embed?&quot; . $_SERVER[&#039;QUERY_STRING&#039;];
}

// Request the calendar
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$buffer = curl_exec($ch);
curl_close($ch);

// Point stylesheet and javascript to custom versions
$pattern = &#039;/(&lt;link.*&gt;)/&#039;;
$replacement = &#039;&lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; href=&quot;&#039; . $stylesheet . &#039;&quot; /&gt;&#039;;
$buffer = preg_replace($pattern, $replacement, $buffer);

$pattern = &#039;/src=&quot;(.*js)&quot;/&#039;;
$replacement = &#039;src=&quot;MyGoogleCal4js.php?$1&quot;&#039;;  
$buffer = preg_replace($pattern, $replacement, $buffer);

// Add a hook to the window onload function
$pattern = &#039;/}\);}&lt;\/script&gt;/&#039;;
$replacement = &#039;}); myGoogleCal();}&lt;/script&gt;&#039;;
$buffer = preg_replace($pattern, $replacement, $buffer);

// Use DHTML to modify the DOM after the calendar loads
$pattern = &#039;/(&lt;\/head&gt;)/&#039;;
$replacement = &lt;&lt;&lt;MGC
&lt;script type=&quot;text/javascript&quot; src=&quot;http://ajax.googleapis.com/ajax/libs/dojo/1.3.1/dojo/dojo.xd.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot;&gt;
function myGoogleCal() {
    // remove inline style from body so background-color can be set using the stylesheet
    dojo.removeAttr(dojo.body(),&#039;style&#039;);

    // iterate over each bubble and remove the width property from the style attribute
    // so that the width can be set using the stylesheet
    dojo.query(&#039;.bubble&#039;).forEach(function(node){
        dojo.attr(node, {style:{&#039;width&#039;: &#039;&#039;}});
    });

    // see Dojo documentation for other ways to edit DOM
    // http://dojotoolkit.org/
}
&lt;/script&gt;
&lt;/head&gt;
MGC;
$buffer = preg_replace($pattern, $replacement, $buffer);

// display the calendar
print $buffer;
?&gt;

?&gt;
</pre>
<p>If you look at lines 39–41 in MyGoogleCal4js.php, you’ll see how simple the fix is.  No more XmlHttpRequest bugs.  Thank you, Google.</p>
<pre class="brush: php">
&lt;?php header(&quot;Content-type: application/x-javascript&quot;);
/*******************************************************************************
 * FILE: MyGoogleCal4js.php
 *
 * DESCRIPTION:
 *  Companion file for MyGoogleCal4.php to edit the javascript file that
 *  generates the Google Calendar.
 *   
 * USAGE:
 *  There are no user-editable parameters.
 *
 * copyright (c) by Brian Gibson
 * email: bwg1974 yahoo com
 ******************************************************************************/
// URL for the javascript
$url = &quot;&quot;;
if(count($_GET) &gt; 0) {
  $url = &quot;http://www.google.com/calendar/&quot; . $_SERVER[&#039;QUERY_STRING&#039;];
}

/* If you would like to freeze the calendar version, download the Javascript
 * file using the same method for downloading the CSS file, as described in
 * the main script.  You can find some previous versions in the archive folder.
 * NOTE: You should use the corresponding CSS file as well.
 *
 * Edit and uncomment the following line to freeze the calendar version.
 */
//$url = &quot;http://myserver.tld/path/to/archive/6a3eb8ba4a07edb76f79a18d6bdb8933embedcompiled__en.js&quot;;

// Request the javascript
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$buffer = curl_exec($ch);
curl_close($ch);

// Fix URLs in the javascript
$pattern = &#039;/this\.[a-zA-Z]{2}\+&quot;calendar/&#039;;
$replacement = &#039;&quot;http://www.google.com/calendar&#039;;
$buffer = preg_replace($pattern, $replacement, $buffer);

// Display the javascript
print $buffer;
?&gt;
</pre>
<p>The installation of MyGoogleCal4 is the same as the <a href="http://www.lindenlan.net/2008/03/22/how-to-install-mygooglecal2php/">installation for MyGoogleCal2</a> except you download the zip file above.  You can ignore step 3 regarding the .htaccess file.  As far as I can tell, it’s no longer needed.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.lindenlan.net/2008/12/04/restyle-google-calendar-4/feed/</wfw:commentRss>
		<slash:comments>134</slash:comments>
		</item>
		<item>
		<title>Restyle Google Calendar 3</title>
		<link>http://www.lindenlan.net/2008/04/23/restyle-google-calendar-3/</link>
		<comments>http://www.lindenlan.net/2008/04/23/restyle-google-calendar-3/#comments</comments>
		<pubDate>Thu, 24 Apr 2008 05:46:09 +0000</pubDate>
		<dc:creator><![CDATA[Brian]]></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>

		<guid isPermaLink="false">http://www.lindenlan.net/2008/04/23/restyle-google-calendar-3/</guid>
		<description><![CDATA[MyGoogleCal2 no longer works 100% in Internet Explorer. A runtime error occurs when navigating month-to-month or when switching to Agenda mode. The workaround is to simply hide the navigation interface. Now, I don’t know if this bug was introduced when Google updated the code last month, or if it’s always been there and I just [&#8230;]]]></description>
				<content:encoded><![CDATA[<p><a href="http://www.lindenlan.net/2007/10/14/restyle-google-calendar-2/">MyGoogleCal2</a> no longer works 100% in Internet Explorer.  A runtime error occurs when navigating month-to-month or when switching to Agenda mode.  The workaround is to simply hide the navigation interface.  Now, I don’t know if this bug was introduced when Google updated the code last month, or if it’s always been there and I just never noticed.  In any case, the runtime error occurs when <code>//"+a.host+"/calendar</code> is replaced by <code>//www.google.com/calendar</code>.  Given the poor debugging available in IE, I didn’t get very far with figuring out why IE breaks.  I suspect that when IE makes an XmlHttpRequest, it’s double checking that the request URL matches up with the server host, or something to that effect.  Since Google obfuscates the Javascript code, it’s just way too hard to try and fix it.  Instead, I’ve opted to create a new version of MyGoogleCal that uses the <a href="http://www.lindenlan.net/2006/10/08/restyle-google-calendar/">original technique</a> for IE but uses the technique from MyGoogleCal2 for all other browsers.</p>
<p><span id="more-57"></span></p>
<p><strong>UPDATE:</strong> MyGoogleCal now has a <a href="http://www.lindenlan.net/2008/12/04/restyle-google-calendar-4/">fourth version</a>.</p>
<p>Download: <a href='http://www.lindenlan.net/wp-content/uploads/2008/04/mygooglecal3.zip' title='MyGoogleCal3 Zip file'>mygooglecal3.zip</a>.  Contains MyGoogleCal3.php, MyGoogleCal3js.php, mygooglecal3.css, mygooglecal3ie.css, and an .htaccess file.  The CSS files are not guaranteed to be up-to-date so you may have to follow the instructions described in the PHP file to download the latest version from Google.</p>
<pre class="brush: php">
&lt;?php
/*******************************************************************************
 * FILE: MyGoogleCal3.php
 *
 * DESCRIPTION:
 *  This script is an intermediary between an iframe and Google Calendar that
 *  allows you to override the default style.
 *
 * USAGE:
 *  &lt;iframe src=&quot;MyGoogleCal3.php?src=user%40domain.tld&quot;&gt;&lt;/iframe&gt;
 *
 *  where user@domain.tld is a valid Google Calendar account.
 *
 * VALID QUERY STRING PARAMETERS:
 *    title:         any valid url encoded string 
 *                   if not present, takes title from first src
 *    showTitle:     0 or 1 (default)
 *    showNav:       0 or 1 (default)
 *    showDate:      0 or 1 (default)
 *    showTabs:      0 or 1 (default)
 *    showCalendars: 0 or 1 (default)
 *    mode:          WEEK, MONTH (default), AGENDA
 *    height:        a positive integer (should be same height as iframe)
 *    wkst:          1 (Sun; default), 2 (Mon), or 7 (Sat)
 *    hl:            en, zh_TW, zh_CN, da, nl, en_GB, fi, fr, de, it, ja, ko, 
 *                   no, pl, pt_BR, ru, es, sv, tr
 *                   if not present, takes language from first src
 *    bgcolor:       url encoded hex color value, #FFFFFF (default)
 *    src:           url encoded Google Calendar account (required)
 *    color:         url encoded hex color value     
 *                   must immediately follow src
 *    
 *    The query string can contain multiple src/color pairs.  It&#039;s recommended 
 *    to have these pairs of query string parameters at the end of the query 
 *    string.
 *
 * HISTORY:
 *   21 June     2008 - Reverted to an older custom JavaScript file
 *   18 May      2008 - Corrected a bunch of typos 
 *   24 April    2008 - Original release
 *                      Uses the technique from MyGoogleCal for IE browsers and
 *                      the technique from MyGoogleCal2 for the rest.
 *   
 * ACKNOWLEDGMENTS:
 *   Michael McCall (http://www.castlemccall.com/) for pointing out &quot;htmlembed&quot;
 *   Mike (http://mikahn.com/) for the link to the online CSS formatter
 *
 * copyright (c) by Brian Gibson
 * email: bwg1974 yahoo com
 ******************************************************************************/

/* URL for overriding stylesheet
 * The best way to create this stylesheet is to 
 * 1) Load &quot;http://www.google.com/calendar/embed?src=user%40domain.tld&quot; in a
 *    browser,
 * 2) View the source (e.g., View-&gt;Page Source in Firefox),
 * 3) Copy the relative URL of the stylesheet (i.e., the href value of the 
 *    &lt;link&gt; tag), 
 * 4) Load the stylesheet in the browser by pasting the stylesheet URL into 
 *    the address bar so that it reads similar to:
 *    &quot;http://www.google.com/calendar/embed/d003e2eff7c42eebf779ecbd527f1fe0embedcompiled.css&quot;
 * 5) Save the stylesheet (e.g., File-&gt;Save Page As in Firefox)
 * Edit this new file to change the style of the calendar.
 *
 * As an alternative method, take the URL you copied in Step 3, and paste it
 * in the URL field at http://mabblog.com/cssoptimizer/uncompress.html.
 * That site will automatically format the CSS so that it&#039;s easier to edit.
 */
$stylesheet = &#039;mygooglecal3.css&#039;;

/* For the IE stylesheet replace &quot;embed&quot; with &quot;htmlembed&quot; in step (1) 
 */
$stylesheet_ie = &#039;mygooglecal3ie.css&#039;;

/*******************************************************************************
 * DO NOT EDIT BELOW UNLESS YOU KNOW WHAT YOU&#039;RE DOING
 ******************************************************************************/

// URL for the calendar
$url = &quot;&quot;;
$is_ie = FALSE;
if(count($_GET) &gt; 0) {
  if(stristr($_SERVER[&#039;HTTP_USER_AGENT&#039;], &#039;msie&#039;) === FALSE) {
    $url = &quot;http://www.google.com/calendar/embed?&quot; . $_SERVER[&#039;QUERY_STRING&#039;];
  } else {
    $url = &quot;http://www.google.com/calendar/htmlembed?&quot; . $_SERVER[&#039;QUERY_STRING&#039;];
    $is_ie = TRUE;
  }
}

// Request the calendar
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$buffer = curl_exec($ch);
curl_close($ch);

if($is_ie) {
  // Fix hrefs, image sources, and stylesheet
  $pattern = &#039;/(href=&quot;render)/&#039;;
  $replacement = &#039;href=&quot;http://www.google.com/calendar/render&#039;;
  $buffer = preg_replace($pattern, $replacement, $buffer);

  $pattern = &#039;/(href=&quot;event)/&#039;;
  $replacement = &#039;href=&quot;http://www.google.com/calendar/event&#039;;
  $buffer = preg_replace($pattern, $replacement, $buffer);

  $pattern = &#039;/(http:\/\/www.google.com\/calendar\/htmlembed)/&#039;;
  $replacement = &#039;MyGoogleCal3.php&#039;;
  $buffer = preg_replace($pattern, $replacement, $buffer);

  $pattern = &#039;/(src=&quot;images)/&#039;;
  $replacement = &#039;src=&quot;http://www.google.com/calendar/images&#039;;
  $buffer = preg_replace($pattern, $replacement, $buffer);

  $pattern = &#039;/(&lt;link.*&gt;)/&#039;;
  $replacement = &#039;&lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; href=&quot;&#039; . $stylesheet_ie . &#039;&quot; /&gt;&#039;;
  $buffer = preg_replace($pattern, $replacement, $buffer);
} else {
  // Point stylesheet and javascript to custom versions
  $pattern = &#039;/(&lt;link.*&gt;)/&#039;;
  $replacement = &#039;&lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; href=&quot;&#039; . $stylesheet . &#039;&quot; /&gt;&#039;;
  $buffer = preg_replace($pattern, $replacement, $buffer);

  $pattern = &#039;/src=&quot;(.*js)&quot;/&#039;;
  $replacement = &#039;src=&quot;MyGoogleCal3js.php?$1&quot;&#039;;
  $buffer = preg_replace($pattern, $replacement, $buffer);
}

// display the calendar
print $buffer;
?&gt;
</pre>
<p>The installation of MyGoogleCal3 is more or less the same as the <a href="http://www.lindenlan.net/2008/03/22/how-to-install-mygooglecal2php/">installation for MyGoogleCal2</a> except you download the zip file above.  Also MyGoogleCal3 uses two stylesheets, one for IE and one for all the other browsers.</p>
<p>There is a minor bug.  Despite changing the URL from <code>../images/ext/poweredby.png</code> to <code>images/poweredby.png</code> in the IE CSS file, this does not make the Powered by Google logo appear in the lower right.  I think that’s OK since it doesn’t appear on Google’s site either.</p>
<p><strong>Update (21 Jun 2008):</strong> Google changed the JavaScript once again and this time very radically.  I’ve been keeping snapshots of their JavaScript code, so I’ve changed the script to load an older customized .js file.  This is a quick fix.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.lindenlan.net/2008/04/23/restyle-google-calendar-3/feed/</wfw:commentRss>
		<slash:comments>35</slash:comments>
		</item>
		<item>
		<title>Restyle Google Calendar 2</title>
		<link>http://www.lindenlan.net/2007/10/14/restyle-google-calendar-2/</link>
		<comments>http://www.lindenlan.net/2007/10/14/restyle-google-calendar-2/#comments</comments>
		<pubDate>Mon, 15 Oct 2007 04:38:54 +0000</pubDate>
		<dc:creator><![CDATA[Brian]]></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>

		<guid isPermaLink="false">http://www.lindenlan.net/2007/10/14/restyle-google-calendar-2/</guid>
		<description><![CDATA[The long awaited new version of MyGoogleCal is here. It supports the new AJAX-enabled Javascript method Google switched to last month. As a bonus, the new version has native support for multiple calendars each with their own colors! Other changes to the code include officially switching from fopen to curl to retrieve the data. Furthermore, [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>The long awaited new version of <a href="http://www.lindenlan.net/2006/10/08/restyle-google-calendar/">MyGoogleCal</a> is here.  It supports the new AJAX-enabled Javascript method Google switched to last month.  As a bonus, the new version has native support for multiple calendars each with their own colors!  Other changes to the code include officially switching from fopen to curl to retrieve the data.  Furthermore, the code replaces much less HTML since it’s encapsulated in Javascript.  Without further ado…</p>
<p><span id="more-39"></span></p>
<p><strong>UPDATE:</strong> MyGoogleCal now has a <a href="http://www.lindenlan.net/2008/04/23/restyle-google-calendar-3/">third version</a>.</p>
<p>Download: <a href='http://www.lindenlan.net/wp-content/uploads/2007/10/mygooglecal2.zip' title='mygooglecal2.zip'>mygooglecal2.zip</a>.  Contains MyGoogleCal2.php, mygooglecal2.css, MyGoogleCal2js.php, and an .htaccess file.  The CSS file is not guaranteed to be up-to-date so you may have to follow the instructions described in the PHP file to download the latest version from Google.</p>
<pre class="brush: php">
&lt;?php
/*******************************************************************************
 * FILE: MyGoogleCal2.php
 *
 * DESCRIPTION:
 *  This script is an intermediary between an iframe and Google Calendar that
 *  allows you to override the default style.
 *
 * USAGE:
 *  &lt;iframe src=&quot;MyGoogleCal2.php?src=user%40domain.tld&quot;&gt;&lt;/iframe&gt;
 *
 *  where user@domain.tld is a valid Google Calendar account.
 *
 * VALID QUERY STRING PARAMETERS:
 *    title:         any valid url encoded string 
 *                   if not present, takes title from first src
 *    showTitle:     0 or 1 (default)
 *    showNav:       0 or 1 (default)
 *    showDate:      0 or 1 (default)
 *    showTabs:      0 or 1 (default)
 *    showCalendars: 0 or 1 (default)
 *    mode:          WEEK, MONTH (default), AGENDA
 *    height:        a positive integer (should be same height as iframe)
 *    wkst:          1 (Sun; default), 2 (Mon), or 7 (Sat)
 *    hl:            en, zh_TW, zh_CN, da, nl, en_GB, fi, fr, de, it, ja, ko, 
 *                   no, pl, pt_BR, ru, es, sv, tr
 *                   if not present, takes language from first src
 *    bgcolor:       url encoded hex color value, #FFFFFF (default)
 *    src:           url encoded Google Calendar account (required)
 *    color:         url encoded hex color value     
 *                   must immediately follow src
 *    
 *    The query string can contain multiple src/color pairs.  It&#039;s recommended 
 *    to have these pairs of query string parameters at the end of the query 
 *    string.
 *
 * HISTORY:
 *   22 March    2008 - Replaced the custom javascript with a PHP script that 
 *                      uses the same technique as MyGoogleCal.php
 *   14 March    2008 - Update to match Google changes to javascript code
 *   14 January  2008 - Fixed Add to Calendar URL to point to Google
 *    3 January  2008 - Reverted back to customized javascript code to fix
 *                      bug where no data is displayed when navigating
 *                      into future or past
 *                      Note: imported calendars (e.g. iCal) should work again
 *   29 October  2007 - Update to match Google changes to javascript code
 *                      Note: imported calendars (e.g. iCal) do not work
 *   14 October  2007 - Original release
 *   
 * copyright (c) by Brian Gibson
 * email: bwg1974 yahoo com
 ******************************************************************************/

/* URL for overriding stylesheet
 * The best way to create this stylesheet is to 
 * 1) Load &quot;http://www.google.com/calendar/embed?src=user%40domain.tld&quot; in a
 *    browser,
 * 2) View the source (e.g., View-&gt;Page Source in Firefox),
 * 3) Copy the relative URL of the stylesheet (i.e., the href value of the 
 *    &lt;link&gt; tag), 
 * 4) Load the stylesheet in the browser by pasting the stylesheet URL into 
 *    the address bar so that it reads similar to:
 *    &quot;http://www.google.com/calendar/embed/d003e2eff7c42eebf779ecbd527f1fe0embedcompiled.css&quot;
 * 5) Save the stylesheet (e.g., File-&gt;Save Page As in Firefox)
 * Edit this new file to change the style of the calendar.
 *
 * As an alternative method, take the URL you copied in Step 3, and paste it
 * in the URL field at http://mabblog.com/cssoptimizer/uncompress.html.
 * That site will automatically format the CSS so that&#039;s more easily editable.
 */
$stylesheet = &#039;mygooglecal2.css&#039;;

/*******************************************************************************
 * DO NOT EDIT BELOW UNLESS YOU KNOW WHAT YOU&#039;RE DOING
 ******************************************************************************/

// URL for the calendar
$url = &quot;&quot;;
if(count($_GET) &gt; 0) {
  $url = &quot;http://www.google.com/calendar/embed?&quot; . $_SERVER[&#039;QUERY_STRING&#039;];
}

// Request the calendar
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$buffer = curl_exec($ch);
curl_close($ch);

// Point stylesheet and javascript to custom versions
$pattern = &#039;/(&lt;link.*&gt;)/&#039;;
$replacement = &#039;&lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; href=&quot;&#039; . $stylesheet . &#039;&quot; /&gt;&#039;;
$buffer = preg_replace($pattern, $replacement, $buffer);

$pattern = &#039;/src=&quot;(.*js)&quot;/&#039;;
$replacement = &#039;src=&quot;MyGoogleCal2js.php?$1&quot;&#039;;
$buffer = preg_replace($pattern, $replacement, $buffer);

// display the calendar
print $buffer;
?&gt;
</pre>
<p>Use is similar to the original MyGoogleCal.php.  To help create the &lt;iframe&gt;, you can use the <a href="http://www.google.com/calendar/embed/EmbedHelper_en.html">Embeddable Calendar Helper</a>.  Just remember to update the src attribute to point to MyGoogleCal2.php and not http://www.google.com/calendar/embed.  </p>
<p><span style="text-decoration: line-through;">In addition to a custom CSS file the script makes use of a custom Javascript file.  Each URL is set after the script’s header and includes instructions on how to download versions of these files from Google.  This is important since it appears that the Javascript file is localized.  (I included copies that I downloaded in the above Zip file.)</span> </p>
<p><strong>Update (22 Mar 08):</strong> I created a new PHP file, MyGoogleCal2js.php, which downloads the JavaScript code and edits the code on-the-fly.  This negates the need to maintain a customized version of the JavaScript code on the same server as the MyGoogleCal.php script.   This should also lessen the chance that MyGoogleCal2.php will break when Google updates the code as long as the changes are minor.</p>
<p>The UI images are no longer contained in the CSS file.  You have two options on how to handle this.  If your site runs off of Apache, you can create a rewrite rule to hotlink to the Google images.  (I included an .htaccess file in the Zip file above that has a sample rule.)  The other, more conventional option is to create an “images” subfolder where the script is located and place copies of these images there.  You will definitely have to do this if you want to replace those images with customized versions. (I included images in the Zip file.)</p>
<p>What I’m hung-up on right now is figuring out a way to not have to save and rewrite the Javascript file.  The Javascript file is responsible for drawing the calendar, retrieving the XML data from Google, and then putting that data into the calendar.   The <code>_init()</code> function dynamically creates the URL from which to retrieve the XML data by using the browser’s window.location.host property.  Since the browser will presumably be pointing to your site, the host property will not be www.google.com.  As a result, the Javascript <span style="text-decoration: line-through;">hangs at the XML loading stage</span> fails to retrieve data when navigating into the future or past.  My attempts at circumventing this problem has been met with little success.</p>
<p>I tried the passthru directive in .htaccess file like so:</p>
<pre class="brush: xhtml">
RewriteRule ^(calendar/feeds/.*)$ http://www.google.com/$1 [P]
</pre>
<p>The browser spits out a 502 error.    </p>
<p>A redirect, [R] instead of [P], only works half-way.  The XmlHttpRequest goes thru but the data is rejected because it’s considered insecure since you can’t load data retrieved from an external domain.</p>
<p>I also tried ProxyPass/ProxyPassReverse to map</p>
<pre class="brush: xhtml">
/calendar/
</pre>
<p>to</p>
<pre class="brush: xhtml">

http://www.google.com/calendar

</pre>
<p>but it simply results in an error.  I’ll have to consult with my host to figure if the error is the configuration on their end or mine.</p>
<p><strong>Update (03 Jan 08):</strong> <em>After talking with my hosting provider it turns out this error is the fault of my virtual server and it won’t be fixed since they’re retiring the hardware.  I’ve been placed in the queue to migrate my account over to a new (hopefully problem-free) server.  In any case, I’ll definitely revisit this solution after the migration is over and test it then.</em></p>
<p>For more info, checkout: <a href="http://www.xml.com/pub/a/2005/11/09/fixing-ajax-xmlhttprequest-considered-harmful.html">Fixing AJAX: XMLHttpRequest Considered Harmful</a> or <a href="http://developer.yahoo.com/javascript/howto-proxy.html">Use a Web Proxy for Cross-Domain XMLHttpRequest Calls</a>.  The last one has pretty pictures.</p>
<p>Failed experiments include:</p>
<ul>
<li>
<p>Use the Javascript prototype mechanism to somehow override the window.location.host property to return a string of my choosing.</p>
</li>
<li>
<p>Rewrite a request to www.google.com to point to MyGoogleCal2.php so that I could inject code into the calendar page.  I thought this had a lot promise up until the point I realized I couldn’t put an .htaccess file at google.com. This was one of those “Duh!” moments.</p>
</li>
<li>
<p>Manipulate the &lt;iframe&gt; DOM in order to change its document.styleSheets property directly.  Due to security reasons, you can’t modify, let alone read, the DOM properties across different domains.</p>
</li>
<li>
<p>Proxy the XmlHttpRequest thru a curl script.  This almost worked.  The curl request succeeded in getting the JSON data, but for whatever reason, the Javascript code failed to do anything with it.  Depending on the content-type requested for the response, either nothing happening or the browser would spit out a Javascript error.  I’m sure it had to with an incomplete request header or returning just the response data instead of the entire response.  But whatever reason it was, this solution seemed more trouble than it was worth.</p>
</li>
</ul>
<p><span style="text-decoration: line-through;"><strong>Update (29 Oct 07):</strong> <em>Google’s new version of the Javascript code does not require any customization.  Do you suppose some Google developer read my post? <img src="http://www.lindenlan.net/wp-includes/images/smilies/icon_smile.gif" alt=":-)" class="wp-smiley" /> However, a side-effect is that imported calendars do not work.  I’m betting it has to do with XmlHttpRequest permissions, but I won’t know for certain without further investigation.</em></span> </p>
<p>When you’re done restyling your calendar, <a href="http://www.lindenlan.net/2008/01/10/calendar-casting-call/">show it off</a>!  Oh and don’t forget to Digg the article.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.lindenlan.net/2007/10/14/restyle-google-calendar-2/feed/</wfw:commentRss>
		<slash:comments>79</slash:comments>
		</item>
		<item>
		<title>Restyle Google Calendar Gadget</title>
		<link>http://www.lindenlan.net/2007/06/18/restyle-google-calendar-gadget/</link>
		<comments>http://www.lindenlan.net/2007/06/18/restyle-google-calendar-gadget/#comments</comments>
		<pubDate>Tue, 19 Jun 2007 00:16:34 +0000</pubDate>
		<dc:creator><![CDATA[Brian]]></dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[CSS]]></category>
		<category><![CDATA[Google]]></category>
		<category><![CDATA[Hacking]]></category>
		<category><![CDATA[JavaScript]]></category>

		<guid isPermaLink="false">http://www.lindenlan.net/2007/06/18/restyle-google-calendar-gadget/</guid>
		<description><![CDATA[My how-to for restyling Google Calendar is by far this blog’s most popular post so far. Right from the start, people had requested that I adjust the code to accommodate Google Calendar’s mini-mode. It certainly was possible using the technique I used, but it did break the agenda which was flaky to begin with given [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>My <a href="http://www.lindenlan.net/2006/10/08/restyle-google-calendar/">how-to for restyling Google Calendar</a> is by far this blog’s most popular post so far.  Right from the start, people had requested that I adjust the code to accommodate Google Calendar’s mini-mode.  It certainly was possible using the technique I used, but it did break the agenda which was flaky to begin with given the fact the feature was experimental.  Every once in a while, I’d check on the stability of mini-mode to determine if it was ripe for some hacking.  Then one day the mode simply didn’t work anymore.  It was weird, but after further research I found out why.  Mini-mode was superseded by the <a href="http://www.google.com/ig/directory?synd=open&#038;num=24&#038;url=http://www.google.com/ig/modules/calendar-for-your-site.xml">Google Calendar Gadget</a>.  The configuration form does provide some customization of the style, but it is certainly limited.  So just like before, I poked and prodded the code until I was able to find the means to restyle the gadget.</p>
<p><span id="more-29"></span></p>
<p>First step is to go to the <a href="http://www.google.com/ig/directory?synd=open&#038;num=24&#038;url=http://www.google.com/ig/modules/calendar-for-your-site.xml">Google Calendar Gadget</a> page.  Click on the “Add to Your Webpage” button.  The reason I don’t provide a direct link is because clicking on the button appears to set some locale settings.  Once there you can roughly style the calendar the way you want—like the overall size, what border, whether you want to display the calendar, agenda, or both, which calendar(s) you want to load, the link color for each event (which can be different for each calendar), etc.  Note that the calendar URL that you want to use is the XML one.  You get the URL by going to your <a href="http://www.google.com/calendar/">Google Calendar</a>, click on “Manage Calendars,” click the specific calendar, and then clicking the XML button under “Calendar Address.”  Just copy and paste the address into the form.  After you are done previewing the calendar, you’ll want to click the “Get the Code” button which will generate a script block that will be the foundation on which we’ll build.  </p>
<p>Let’s dissect the generated HTML.</p>
<pre class="brush: plain">
&lt;script src=&quot;http://gmodules.com/ig/ifr
</pre>
<p>This is some JavaScript that’s part of iGoogle and the Google Gadget framework.  A lot of the behind the scenes magic happens here.  What I’ve determined so far is that this creates a table and iframe to contain the gadget.  There’s some bad news because of this, but I’ll get to that later.</p>
<pre class="brush: plain">
?url=http://www.google.com/ig/modules/calendar-for-your-site.xml
</pre>
<p>This XML file is what defines the gadget itself.  This is where we’ll be doing most of our restyling.</p>
<pre class="brush: plain">
&amp;up_showCalendar2=1
&amp;up_showAgenda=1
&amp;up_calendarFeeds=(%7B%7D)
&amp;up_firstDay=Sunday
&amp;up_syndicatable=true
&amp;up_stylesheet=
&amp;up_sub=1
</pre>
<p>Now I added carriage returns to improve readability.  Most of these settings map directly to settings you set in the form.  Supposedly you can supply your own stylesheet, but the fact of the matter is it gets ignored because, as we’ll see later, the gadget provides it’s own styles inline.  </p>
<pre class="brush: plain">
&amp;up_c0u=http%3A%2F%2Fwww.google.com%2Fcalendar%2Ffeeds%2Fuser%2540domain.tld%2Fpublic%2Fbasic
&amp;up_c0c=
&amp;up_c1u=
&amp;up_c1c=
&amp;up_c2u=
&amp;up_c2c=
&amp;amp;up_c3u=
&amp;amp;up_c3c=
</pre>
<p>These are the XML feeds for each of the calendars.  You can embed up to four calendars and each can have a different color.  The colors won’t show up in the calendar view but will show up in the agenda view for each event link as well as each subscription link.</p>
<pre class="brush: plain">
&amp;up_min=
&amp;up_start=
&amp;up_timeFormat=1%3A00pm
&amp;up_calendarFeedsImported=0
&amp;synd=open
&amp;w=320
&amp;h=450
&amp;title=Google+Calendar
&amp;border=%23ffffff%7C3px%2C1px+solid+%23999999
&amp;output=js&quot;&gt;&lt;/script&gt;
</pre>
<p>Some more settings.  You can have a blank title if you want.  This is also where the border is defined.  Again you can have a blank border or you can be very fancy with your border design as long as it’s valid <a href="http://www.string-functions.com/urlencode.aspx">URL encoded</a> CSS.  You can also tweak the width and height if the need arises.</p>
<p>The next step is download the <a href="http://www.google.com/ig/modules/calendar-for-your-site.xml">source code</a> for the gadget.  (You can select “File-&gt;Save Page As” in Firefox if you load the source code in the browser.)  This way we now have a copy of the gadget that we can modify.  Open up the XML file in your favorite editor.  Scroll down until you find the style block.  This is where most of the style changes can be made.  Anywhere you see <code>#c3d9ff</code> or <code>rgb(195, 217, 255)</code> is Google blue.    Most of the class selectors are self-explanatory.  The one style that’s not in the style block that you may wish to change is the one contained in the table with the id <code>pickerContainer__MODULE_ID__</code>.  This is the color for the “Loading…” splash.  </p>
<p>The last step is to change the script block that loads the gadget.  Instead of </p>
<pre class="brush: plain">
&lt;script src=&quot;http://gmodules.com/ig/ifr?url=http://www.google.com/ig/modules/calendar-for-your-site.xml
</pre>
<p>you need to change it to</p>
<pre class="brush: plain">
&lt;script src=&quot;http://gmodules.com/ig/ifr?url=http://mywebsite.com/path/to/file/calendar-for-your-site.xml
</pre>
<p>Don’t forget to upload the edited XML file to your web site.  That should do it.  </p>
<p>Now about that problem I alluded to earlier.  The JavaScript that loads the gadget unfortunately has some hard coded styles, in particular, it sets the background to white.  White is certainly a popular background color, but obviously not all web sites follow that convention.  The only way to do that is to use JavaScript to dynamically change the style.  In the XML file, locate this script block at the bottom:</p>
<pre class="brush: js">
if (navigator.userAgent.toLowerCase().indexOf(&#039;msie&#039;) != -1) {
  document.body.onload = function() { new _CalendarModule(__MODULE_ID__); };
} else {
  new _CalendarModule(__MODULE_ID__);
}
</pre>
<p>and change it to</p>
<pre class="brush: js">
if (navigator.userAgent.toLowerCase().indexOf(&#039;msie&#039;) != -1) {
  document.body.onload = function() { new _CalendarModule(__MODULE_ID__); document.body.style.backgroundColor = &quot;gray&quot;; };
} else {
  new _CalendarModule(__MODULE_ID__);
  document.body.style.backgroundColor = &quot;gray&quot;;
}
</pre>
<p>Of course feel free to change the color string to match your web site.  Now don’t be surprised if after reloading the page, the background doesn’t change.  I’m not a 100% sure why this is the case.  My best guess is that the code is being cached, but clearing it on the client side doesn’t seem to have an effect.  So there appears to be some server-side caching going on.  The good news is that eventually the cached version times out and the correct background color will display.  This technique can also be used to load a background image or change other style settings.</p>
<p>Assuming you do change the background color you will have to host your own corner images on your web site.  Locate these lines in the style block of the XML file.</p>
<pre class="brush: xml">
td.tl {background:url(&quot;http://www.google.com/calendar/images/corner_tl.gif&quot;) top left}
td.bl {background:url(&quot;http://www.google.com/calendar/images/corner_bl.gif&quot;) bottom left}
td.tr {background:url(&quot;http://www.google.com/calendar/images/corner_tr.gif&quot;) top right}
td.br {background:url(&quot;http://www.google.com/calendar/images/corner_br.gif&quot;) bottom right}
</pre>
<p>You will need to download, edit those GIF files to match your background color, and then upload the files to your site.  Once that’s done, you’ll need to update the XML file to reflect the new URLs for those images.</p>
<p>Happy styling!  When you’re done restyling your calendar, <a href="http://www.lindenlan.net/2008/01/10/calendar-casting-call/">show it off</a>!</p>
<p>P.S. The technique used to <a href="http://www.lindenlan.net/2006/10/08/restyle-google-calendar/">restyle Google Calendar</a> can be used to edit the XML file.  I leave this as an exercise for the reader.  The technique described above doesn’t require PHP so will be most applicable to those non-programmers out there.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.lindenlan.net/2007/06/18/restyle-google-calendar-gadget/feed/</wfw:commentRss>
		<slash:comments>34</slash:comments>
		</item>
		<item>
		<title>setLength extension for Control.Slider</title>
		<link>http://www.lindenlan.net/2006/10/20/setlength-extension-for-controlslider/</link>
		<comments>http://www.lindenlan.net/2006/10/20/setlength-extension-for-controlslider/#comments</comments>
		<pubDate>Sat, 21 Oct 2006 05:20:52 +0000</pubDate>
		<dc:creator><![CDATA[Brian]]></dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Ruby on Rails]]></category>

		<guid isPermaLink="false">http://www.lindenlan.net/2006/10/21/setlength-extension-for-controlslider/</guid>
		<description><![CDATA[The UI on a project of mine had to be resizable. The UI included a script.aculo.us slider which unfortunately did not have a resize method nor was it smart enough to update itself should the underlying element be resized. So I created the following extension: Object.extend(Control.Slider.prototype, { setLength: function(length) { // resize the element if [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>The UI on a project of mine had to be resizable.  The UI included a <a href="http://script.aculo.us/">script.aculo.us</a> <a href="http://wiki.script.aculo.us/scriptaculous/show/Slider">slider</a> which unfortunately did not have a resize method nor was it smart enough to update itself should the underlying element be resized. So I created the following extension:</p>
<p><span id="more-13"></span></p>
<pre class="brush: js">
Object.extend(Control.Slider.prototype, {
  setLength: function(length) {
    // resize the element
    if (this.isVertical()) {
      Element.setStyle(this.track, {height: length + &quot;px&quot;});
    } else {
      Element.setStyle(this.track, {width: length + &quot;px&quot;});
    }
    
    // update lengths
    this.trackLength = this.maximumOffset() - this.minimumOffset();

    this.handleLength = this.isVertical() ? 
      (this.handles[0].offsetHeight != 0 ? 
        this.handles[0].offsetHeight : this.handles[0].style.height.replace(/px$/,&quot;&quot;)) : 
      (this.handles[0].offsetWidth != 0 ? this.handles[0].offsetWidth : 
        this.handles[0].style.width.replace(/px$/,&quot;&quot;));
    
    // reposition handles
    this.handles.each( function(h,i) {
      h.style[this.isVertical() ? &#039;top&#039; : &#039;left&#039;] = 
        this.translateToPx(this.values[i]);
    }.bind(this));
  }
})
</pre>
<p>Just drop this code into your <a href="http://wiki.script.aculo.us/scriptaculous/show/HowtoExtendAndOverride">extensions.js</a> file and you should be good to go.  Then just call the instance method like so <code>mySlider.setLength(newLength)</code> where <code>newLength</code> is an integer value.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.lindenlan.net/2006/10/20/setlength-extension-for-controlslider/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Control.Touchpad for script.aculo.us</title>
		<link>http://www.lindenlan.net/2006/10/13/controltouchpad-for-scriptaculous/</link>
		<comments>http://www.lindenlan.net/2006/10/13/controltouchpad-for-scriptaculous/#comments</comments>
		<pubDate>Fri, 13 Oct 2006 17:35:48 +0000</pubDate>
		<dc:creator><![CDATA[Brian]]></dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Ruby on Rails]]></category>

		<guid isPermaLink="false">http://www.lindenlan.net/2006/10/13/controltouchpad-for-scriptaculous/</guid>
		<description><![CDATA[I’ve submitted a patch to the Rails developers that adds a Touchpad control to script.aculo.us. It is a 2D control based heavily off of Slider and so shares some of the same options and behavior. The Touchpad callbacks output an array [x, y] rather than a single value v which is what Slider does. Touchpad [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>I’ve submitted a patch to the Rails developers that adds a <a href="http://en.wikipedia.org/wiki/Touchpad">Touchpad</a> control to <a href="http://script.aculo.us/">script.aculo.us</a>.  It is a 2D control based heavily off of <a href="http://wiki.script.aculo.us/scriptaculous/show/Slider">Slider</a> and so shares some of the same options and behavior.  The Touchpad callbacks output an array [x, y] rather than a single value v which is what Slider does.  Touchpad also has no handles so the last value is not preserved.</p>
<p><span id="more-12"></span></p>
<p>Patch: <a href="http://dev.rubyonrails.org/ticket/6398">http://dev.rubyonrails.org/ticket/6398</a></p>
<div id="pad1" style="width:100px;height:100px;background:gray;"></div>
<p id="debug1"><a href="#" onclick="demo();tp.setEnabled();return false;">Enable</a></p>
<p>So what can you do with it?  The basic use is simply to capture mouse input in a defined area of a web page and then map that input to a specific range of values.  Another use would be to hook the output of the Touchpad to the inputs of two Sliders.  This way you have one controller that can control two controllers simultaneously.  (Additionally, this preserves the last value of the Touchpad unless of course you move the Slider independent of the Touchpad.)  Another slick use is one that I’ve seen requested on the forums.  If you hide the overflow of the Touchpad and then nest a really wide div that contains thumbnails for products, you can then limit the output of the Touchpad to horizontal values—the vertical values are simply clamped to 0—and then use the callback to set the left coordinate of the child div.  Now you can scroll through your products without an ugly scrollbar.</p>
<p>If this sounds like something you can use and you can’t wait til the developers choose to add it to the trunk, then go visit the URL above.  Then simply download and run the attached diff file on your script.aculo.us installation using <a href="http://subversion.tigris.org/">Subversion</a>.  I recommend you run the functional test included in the patch (tests/run_functional_test.html –&gt; click on touchpad_test in the left frame) to see some examples of the touchpad in action.</p>
<p>script.aculo.us is at version 1.6.4 at the time of this writing.  </p>
]]></content:encoded>
			<wfw:commentRss>http://www.lindenlan.net/2006/10/13/controltouchpad-for-scriptaculous/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
