<?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>BLARGH!! for the people &#187; web development</title>
	<atom:link href="http://blargh.tommymontgomery.com/category/web-development/feed/" rel="self" type="application/rss+xml" />
	<link>http://blargh.tommymontgomery.com</link>
	<description>It&#039;s time to bring forth the rhythm and the rhyme</description>
	<lastBuildDate>Fri, 09 Jul 2010 04:03:13 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Refresh Current Page in JavaScript</title>
		<link>http://blargh.tommymontgomery.com/2010/05/refresh-current-page-in-javascript/</link>
		<comments>http://blargh.tommymontgomery.com/2010/05/refresh-current-page-in-javascript/#comments</comments>
		<pubDate>Sun, 09 May 2010 23:55:26 +0000</pubDate>
		<dc:creator>tmont</dc:creator>
				<category><![CDATA[javascript]]></category>
		<category><![CDATA[web development]]></category>

		<guid isPermaLink="false">http://blargh.tommymontgomery.com/?p=513</guid>
		<description><![CDATA[It&#8217;s more annoying than it sounds. You could do the classic:

window.location = window.location; //refresh lol!

But you&#8217;ll get screwed if there is a fragment, like, say, http://example.com/index.html#section1. The page won&#8217;t refresh. Or rather, it will, but browsers won&#8217;t send a request to the server if the url contains a fragment. It will just try to navigate [...]]]></description>
			<content:encoded><![CDATA[<p>It&#8217;s more annoying than it sounds. You could do the classic:</p>
<pre class="brush: jscript;">
window.location = window.location; //refresh lol!
</pre>
<p>But you&#8217;ll get screwed if there is a <a href="http://www.w3.org/TR/WD-html40-970708/htmlweb.html#h-4.1.1">fragment</a>, like, say, <kbd>http://example.com/index.html#section1</kbd>. The page won&#8217;t refresh. Or rather, it will, but browsers won&#8217;t send a request to the server if the url contains a fragment. It will just try to navigate to that fragment within the document.</p>
<p>Solution: be awesome.</p>
<pre class="brush: jscript;">
(function(){
  var refreshCookie = &quot;mysite.refreshFragment&quot;;

  var refresh = function() {
    var url = window.location.href;
    var fragmentPosition = url.lastIndexOf(&quot;#&quot;);
    if (fragmentPosition &gt;= 0) {
      if (fragmentPosition !== url.length - 1) {
        $.cookie(refreshCookie, url.substring(fragmentPosition + 1)); //store the fragment in a cookie
      }
      url = url.substring(0, fragmentPosition);
    }
    window.location.href = url;
  };

  var applyFragmentFromCookie = function() {
    var fragment = $.cookie(refreshCookie);
    if (fragment !== null) {
      window.location.href += &quot;#&quot; + fragment;
      $.cookie(refreshCookie, null); //delete cookie
    }
  };

  //reapply the fragment (if necessary) when the page is loaded
  $(document).ready(applyFragmentFromCookie);

  //expose to the public (you would of course properly namespace this, right?)
  window.refresh = refresh;
}());

//then, when you wanted to refresh the page...
refresh();
</pre>
<p>I use the <a href="http://plugins.jquery.com/project/cookie">jQuery cookie plugin</a>, because all the kids nowadays are using jQuery. Substitute your own <a href="http://www.dustindiaz.com/top-ten-javascript/">cookie handling framework</a>, or roll your own (I&#8217;ve done it, it&#8217;s not enjoyable).</p>
<p><a href="http://tmont.com/experiments/javascript-refresh/">See it in action.</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blargh.tommymontgomery.com/2010/05/refresh-current-page-in-javascript/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Seven CSS Tricks No One Should Ever Have to Memorize</title>
		<link>http://blargh.tommymontgomery.com/2010/05/seven-css-tricks-no-one-should-ever-have-to-memorize/</link>
		<comments>http://blargh.tommymontgomery.com/2010/05/seven-css-tricks-no-one-should-ever-have-to-memorize/#comments</comments>
		<pubDate>Sun, 02 May 2010 01:24:07 +0000</pubDate>
		<dc:creator>tmont</dc:creator>
				<category><![CDATA[web development]]></category>

		<guid isPermaLink="false">http://blargh.tommymontgomery.com/?p=489</guid>
		<description><![CDATA[CSS is kinda cool, or at least it would be if everybody used the same browser. Instead, they don&#8217;t, so doing stuff with CSS is mostly impossible. There are few super annoying hacks and tricks that I use every six months but can never remember, and then end up scouring the internet looking for an [...]]]></description>
			<content:encoded><![CDATA[<p>CSS is kinda cool, or at least it would be if everybody used the same browser. Instead, they don&#8217;t, so doing stuff with CSS is mostly impossible. There are few super annoying hacks and tricks that I use every six months but can never remember, and then end up scouring the internet looking for an implementation that&#8217;s not on <a href="http://www.webmasterworld.com/">webmasterworld.com</a>. Seriously, how is that site still so far up in the Google rankings? It&#8217;s so terrible.</p>
<p>Anyway, I&#8217;ve compiled a short list of seven things that I&#8217;m constantly googling for. Note that this isn&#8217;t a list of &#8220;Tommy&#8217;s 101 CSS tricks for beginers (sic)!&#8221;. This is a list of things I can&#8217;t be bothered to remember. I already know all of the basic stuff, and I&#8217;m assuming you do too.</p>
<h2>1. Reset</h2>
<p><a href="http://meyerweb.com/eric/tools/css/reset/">Reset CSS by Eric Meyer</a></p>
<pre class="brush: css; collapse: true; light: false; toolbar: true;">
/* v1.0 | 20080212 */

html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, font, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td {
	margin: 0;
	padding: 0;
	border: 0;
	outline: 0;
	font-size: 100%;
	vertical-align: baseline;
	background: transparent;
}
body {
	line-height: 1;
}
ol, ul {
	list-style: none;
}
blockquote, q {
	quotes: none;
}
blockquote:before, blockquote:after,
q:before, q:after {
	content: '';
	content: none;
}

/* remember to define focus styles! */
:focus {
	outline: 0;
}

/* remember to highlight inserts somehow! */
ins {
	text-decoration: none;
}
del {
	text-decoration: line-through;
}

/* tables still need 'cellspacing=&quot;0&quot;' in the markup */
table {
	border-collapse: collapse;
	border-spacing: 0;
}
</pre>
<p>The reset CSS creates an even playing field across all browsers, by removing the default styles that each applies. If you want to create a cross-browser compatible web app, then use this, and don&#8217;t question it.</p>
<h2>2. Clearfix</h2>
<p><a href="http://perishablepress.com/press/2009/12/06/new-clearfix-hack/">Clearfix</a></p>
<pre class="brush: css; collapse: true; light: false; toolbar: true;">
/* new clearfix */
.clearfix:after {
	visibility: hidden;
	display: block;
	font-size: 0;
	content: &quot; &quot;;
	clear: both;
	height: 0;
	}
* html .clearfix             { zoom: 1; } /* IE6 */
*:first-child+html .clearfix { zoom: 1; } /* IE7 */
</pre>
<p>This hack has gone through a few iterations, so I don&#8217;t know who the original author is. I use the one described at the link above. Use this if all child elements are <kbd>float</kbd>ed, and you want the parent element to retain its &#8220;assumed&#8221; height. Useful for horizontal menus made up of floated <kbd>li</kbd>s. Give your <kbd>&lt;ul&gt;</kbd> a <kbd>clearfix</kbd>.</p>
<h2>3. MIR Image Replacement</h2>
<p><a href="http://www.stuffandnonsense.co.uk/archives/examples/malarkey-method-example.html">Malarkey Image Replacement Examples</a></p>
<pre class="brush: css; collapse: true; light: false; toolbar: true;">
.mir { letter-spacing : -1000em; }
/* Just for Opera, but hide from MacIE */
/*\*/html&gt;body .mir { letter-spacing : normal; text-indent : -999em; overflow : hidden;}
/* End of hack */
</pre>
<p>This is a useful hack for when you want your fancy menus/giant <kbd>h1</kbd> tag to gracefully degrade when styles are removed. Slap a <kbd>class="mir"</kbd> on it, give it some text, and you&#8217;re good to go. See the examples for examples (derp).</p>
<h2>4. 100% height</h2>
<p><a href="http://www.tutwow.com/tips/quick-tip-css-100-height/comment-page-2/#comment-1481">CSS 100% Height</a></p>
<pre class="brush: css; collapse: true; light: false; toolbar: true;">
html { height:100%; }
body { min-height:100%; }
#content { min-height:100%; }
</pre>
<p>While you can of course solve this (and the world&#8217;s) problem with tables, you shouldn&#8217;t. Because tables suck, much like <a href="http://urmomisugly.com/">urmom</a>. But seriously, this is an incredibly difficult problem with an extremely simple solution.</p>
<h2>5. Center an unordered list</h2>
<p><a href="http://www.cssplay.co.uk/menus/centered.html">Centering a floated menu</a></p>
<pre class="brush: css; collapse: true; light: false; toolbar: true;">
.container {
  width:100%;
  overflow:hidden;
}
ul#menu2 {
  margin:0 auto;
  list-style-type:none;
  float:left;
  position:relative;
  left:50%;
}
#menu2 li {
  float:left;
  position:relative;
  right:50%;
}
</pre>
<p>You won&#8217;t figure this one out on your own. Stop trying.</p>
<h3>Tommy&#8217;s Steps to Success</h3>
<ol>
<li>Ctrl+C</li>
<li>Ctrl+V</li>
<li>???</li>
<li>Profit</li>
</ol>
<h2>6. Opacity in IE</h2>
<p><a href="http://joseph.randomnetworks.com/archives/2006/08/16/css-opacity-in-internet-explorer-ie/">CSS Opacity in IE</a></p>
<pre class="brush: css; collapse: true; light: false; toolbar: true;">
.something-with-opacity {
  opacity: 0.5; /* everybody under the sun except IE */
  filter: alpha(opacity = 50); /* IE */
}
</pre>
<p>You might also need that <kbd>zoom: 1</kbd> crap for elements that don&#8217;t <a href="http://msdn.microsoft.com/en-us/library/bb250481(VS.85).aspx">have layout</a>.</p>
<h2>7. Vertically center a block element</h2>
<p><a href="http://www.jakpsatweb.cz/css/css-vertical-center-solution.html">Vertically Centering in CSS</a> or <a href="http://phrogz.net/css/vertical-align/index.html">How (Not) to Vertically Center Content</a></p>
<p>If you already know the width and height of the container, then you should be able to figure out how to vertically center something by using math (hint: division) and absolute positioning. If it&#8217;s more fluid, then you&#8217;re probably screwed.</p>
<p>For inline elements, use <kbd>line-height</kbd>. For block elements, use JavaScript. If that&#8217;s not an option, then you can <em>attempt</em> at implementing something like the above links, but I wouldn&#8217;t hold your breath. It&#8217;s mostly impossible.</p>
<p>If absolute positioning is not an option, you can try the <kbd>display: table-cell; vertical-align: middle</kbd> route, but it&#8217;s a crapshoot, and it doesn&#8217;t seem to work in all browsers. Using <kbd>position: absolute; top: 50%;</kbd> is viable as long as you know the height of the element and don&#8217;t care about absolutely positioning something.</p>
<p>Of course, you could <kbd>valign</kbd> yourself to success if you&#8217;re using tables, but you wouldn&#8217;t be stupid enough to do something like that, would you?</p>
]]></content:encoded>
			<wfw:commentRss>http://blargh.tommymontgomery.com/2010/05/seven-css-tricks-no-one-should-ever-have-to-memorize/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Get Computed Style in JavaScript</title>
		<link>http://blargh.tommymontgomery.com/2010/04/get-computed-style-in-javascript/</link>
		<comments>http://blargh.tommymontgomery.com/2010/04/get-computed-style-in-javascript/#comments</comments>
		<pubDate>Mon, 05 Apr 2010 10:25:15 +0000</pubDate>
		<dc:creator>tmont</dc:creator>
				<category><![CDATA[javascript]]></category>
		<category><![CDATA[web development]]></category>

		<guid isPermaLink="false">http://blargh.tommymontgomery.com/?p=476</guid>
		<description><![CDATA[The computed style of an element incorporates external CSS (via stylesheets), inline styles and styles prescribed via JavaScript. It&#8217;s most commonly used to get the default style of an element if it&#8217;s not specifically assigned via styles, i.e. the default style that the browser gives an element. It&#8217;s a very undocumented part of JavaScript engines, [...]]]></description>
			<content:encoded><![CDATA[<p>The computed style of an element incorporates external CSS (via stylesheets), inline styles and styles prescribed via JavaScript. It&#8217;s most commonly used to get the default style of an element if it&#8217;s not specifically assigned via styles, i.e. the default style that the browser gives an element. It&#8217;s a very undocumented part of JavaScript engines, and, of course, there are multiple implementations. For more details, read <a href="http://blog.stchur.com/2006/06/21/css-computed-style/">this blog post</a>.</p>
<p>For my <a href="http://linkurious.com/">Linkurious</a> project, I needed to get the computed style of an element in a cross browser way. I came up with an implementation that works in every version of every browser (within reason, the <a href="http://www.armory.com/~spectre/cwi/hl/">C64</a> is not supported), and is easy to use.</p>
<p>I&#8217;ll leave the details of how it works as an exercise to the reader. I will say that this is a good example of how to use a closure to improve the efficiency of a function. Notice that the cross-browser garbage is only executed once, not on each call.</p>
<pre class="brush: jscript;">
//must be executed on or after the domready event, since it (may) require document.body to be non-null
var getComputedStyle = function() {
  var func = null;
  if (document.defaultView &amp;&amp; document.defaultView.getComputedStyle) {
    func = document.defaultView.getComputedStyle;
  } else if (typeof(document.body.currentStyle) !== &quot;undefined&quot;) {
    func = function(element, anything) {
      return element[&quot;currentStyle&quot;];
    };
  }

  return function(element, style) {
    return func(element, null)[style];
  }
}();

//and use like so:
getComputedStyle(document.getElementById(&quot;foo&quot;), &quot;display&quot;); //might return &quot;inline-block&quot;
</pre>
]]></content:encoded>
			<wfw:commentRss>http://blargh.tommymontgomery.com/2010/04/get-computed-style-in-javascript/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Fluent DOM Manipulation in JavaScript</title>
		<link>http://blargh.tommymontgomery.com/2009/11/fluent-dom-manipulation-in-javascript/</link>
		<comments>http://blargh.tommymontgomery.com/2009/11/fluent-dom-manipulation-in-javascript/#comments</comments>
		<pubDate>Thu, 19 Nov 2009 08:37:00 +0000</pubDate>
		<dc:creator>tmont</dc:creator>
				<category><![CDATA[javascript]]></category>
		<category><![CDATA[web development]]></category>

		<guid isPermaLink="false">http://blargh.tommymontgomery.com/?p=247</guid>
		<description><![CDATA[Everybody hates the DOM. Except me. I kinda love it. I get a little hit of endorphins every time I type all 23 characters of &#8220;document.getElementById&#8221;. I need a cigarette.
Anyway, I found myself  dissatisfied with the state of jQuery&#8217;s DOM manipulation (hint: there isn&#8217;t any). You can traverse, and do stuff with events, but [...]]]></description>
			<content:encoded><![CDATA[<p>Everybody hates the <acronym>DOM</acronym>. Except me. I kinda love it. I get a little hit of endorphins every time I type all 23 characters of &#8220;document.getElementById&#8221;. I need a cigarette.</p>
<p>Anyway, I found myself  dissatisfied with the state of <a href="http://jquery.com/">jQuery&#8217;s</a> <acronym>DOM</acronym> manipulation (hint: there isn&#8217;t any). You can traverse, and do stuff with events, but there&#8217;s no <acronym>API</acronym> to create elements and then append them to the <acronym>DOM</acronym>. So I looked at the jQuery plugins, and found <a href="http://plugins.jquery.com/project/appendDom">this</a>, which I tried and quickly learned to hate. Using JSON to create <acronym>DOM</acronym> elements is just as painful as creating them using the native <acronym>DOM</acronym> <acronym>API</acronym>.</p>
<p>So, like any good programmer, I rolled my own. And I called it <strong>FluentDom</strong> (or <strong>$dom</strong> for short). Tested in Firefox, <acronym>IE</acronym> and Opera. Licensed under the <a href="http://sam.zoy.org/wtfpl/">WTFPL</a> license.</p>
<h2>FluentDom.js</h2>
<pre class="brush: jscript;">
/**
 * Fluent DOM Manipulation
 *
 * @author  Tommy Montgomery &lt;http://tommymontgomery.com/&gt;
 * @license http://sam.zoy.org/wtfpl/
 */

(function(){

	var FluentDom = function(node) {
		return new FluentDomInternal(node);
	}

	FluentDom.create = function(tagName) {
		var f = new FluentDomInternal();
		f.create(tagName);
		return f;
	}

	var FluentDomInternal = function(node) {
		var root = node || null;

		this.fluentDom = &quot;1.0&quot;;

		this.append = function(obj) {
			if (!root || !root.appendChild) {
				throw new Error(&quot;Cannot append to a non-element&quot;);
			}

			var type = typeof(obj);
			if (type === &quot;object&quot;) {
				if (obj.fluentDom) {
					root.appendChild(obj.toDom());
				} else if (obj.nodeType) {
					root.appendChild(obj);
				} else {
					throw new Error(&quot;Invalid argument: not a DOM element or a FluentDom object&quot;);
				}
			} else if (type === &quot;string&quot; || type === &quot;number&quot;) {
				root.appendChild(document.createTextNode(obj));
			} else {
				throw new Error(&quot;Invalid argument: not an object (you gave me a &quot; + typeof(obj) + &quot;)&quot;);
			}

			return this;
		}

		this.attr = function(name, value) {
			if (!root || !root.setAttribute) {
				throw new Error(&quot;Cannot set an attribute on a non-element&quot;);
			}

			root.setAttribute(name, value);
			return this;
		}

		this.text = function(text) {
			return this.append(text);
		}

		this.create = function(tagName) {
			root = document.createElement(tagName);
			return this;
		}

		this.id = function(value) {
			return this.attr(&quot;id&quot;, value);
		}

		this.title = function(value) {
			return this.attr(&quot;title&quot;, value);
		}

		this.cls = function(value) {
			return this.attr(&quot;class&quot;, value);
		}

		this.clear = function() {
			root = null;
			return this;
		}

		this.toDom = function() {
			return root;
		}

		this.href = function(link) {
			return this.attr(&quot;href&quot;, link);
		}

	};

	window.FluentDom = window.$dom = FluentDom;

}());
</pre>
<h2>Usage</h2>
<p>Some sample usage, also showing how to integrate with jQuery:</p>
<pre class="brush: jscript;">
//let's make a list!
$dom(document.body).append(
	$dom.create(&quot;ul&quot;).id(&quot;menu&quot;).append(
		$dom.create(&quot;li&quot;).cls(&quot;menu-item&quot;).id(&quot;menu-item-1&quot;).append(
			$dom.create(&quot;a&quot;).text(&quot;List Item #1&quot;).href(&quot;#&quot;)
		)
	).append(
		$dom.create(&quot;li&quot;).cls(&quot;menu-item&quot;).id(&quot;menu-item-2&quot;).title(&quot;click to toggle&quot;).append(
			$($dom.create(&quot;a&quot;).text(&quot;List Item #2&quot;).href(&quot;#&quot;).toDom()).bind(&quot;click&quot;, function() {
				$(this).next(&quot;ul&quot;).toggle();
				return false;
			}).get(0)
		).append(
			$dom.create(&quot;ul&quot;).append(
				$dom.create(&quot;li&quot;).cls(&quot;sub-menu-item&quot;).id(&quot;menu-item-4&quot;).append(
					$dom.create(&quot;a&quot;).text(&quot;Sublist Item #1&quot;).href(&quot;#&quot;)
				)
			).append(
				$dom.create(&quot;li&quot;).cls(&quot;sub-menu-item&quot;).id(&quot;menu-item-5&quot;).append(
					$dom.create(&quot;a&quot;).text(&quot;Sublist Item #2&quot;).href(&quot;#&quot;)
				)
			).append(
				$dom.create(&quot;li&quot;).cls(&quot;sub-menu-item&quot;).id(&quot;menu-item-6&quot;).append(
					$dom.create(&quot;a&quot;).text(&quot;Sublist Item #3&quot;).href(&quot;#&quot;)
				)
			)
		)
	).append(
		$dom.create(&quot;li&quot;).cls(&quot;menu-item&quot;).id(&quot;menu-item-3&quot;).append(
			$dom.create(&quot;a&quot;).text(&quot;List Item #3&quot;).href(&quot;#&quot;)
		)
	)
);
</pre>
<p>Which creates and appends this <acronym>DOM</acronym> tree to <kbd>document.body</kbd>:</p>
<pre class="brush: xml;">
&lt;ul id=&quot;menu&quot;&gt;
  &lt;li class=&quot;menu-item&quot; id=&quot;menu-item-1&quot;&gt;&lt;a href=&quot;#&quot;&gt;List Item #1&lt;/a&gt;&lt;/li&gt;
  &lt;li class=&quot;menu-item&quot; id=&quot;menu-item-2&quot; title=&quot;click to toggle&quot;&gt;&lt;a href=&quot;#&quot;&gt;List Item #2&lt;/a&gt;
    &lt;ul&gt;
      &lt;li class=&quot;sub-menu-item&quot; id=&quot;menu-item-4&quot;&gt;&lt;a href=&quot;#&quot;&gt;Sublist Item #1&lt;/a&gt;&lt;/li&gt;
      &lt;li class=&quot;sub-menu-item&quot; id=&quot;menu-item-5&quot;&gt;&lt;a href=&quot;#&quot;&gt;Sublist Item #2&lt;/a&gt;&lt;/li&gt;
      &lt;li class=&quot;sub-menu-item&quot; id=&quot;menu-item-6&quot;&gt;&lt;a href=&quot;#&quot;&gt;Sublist Item #3&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li class=&quot;menu-item&quot; id=&quot;menu-item-3&quot;&gt;&lt;a href=&quot;#&quot;&gt;List Item #3&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</pre>
<p>Admittedly, it kind of looks like a lot of code, but it&#8217;s much easier to read than if you had used the native <acronym>API</acronym>. Compare that with what the same implementation would look like if you went native:</p>
<h2>Native API Implementation</h2>
<pre class="brush: jscript;">
var ul = document.createElement(&quot;ul&quot;);
ul.id = &quot;menu&quot;;
var li = document.createElement(&quot;li&quot;);
li.className = &quot;menu-item&quot;;
li.id = &quot;menu-item-1&quot;;
var a = document.createElement(&quot;a&quot;);
a.href = &quot;#&quot;;
a.appendChild(document.createTextNode(&quot;List Item #1&quot;));
li.appendChild(a);
ul.appendChild(li);

li = document.createElement(&quot;li&quot;);
li.className = &quot;menu-item&quot;;
li.id = &quot;menu-item-2&quot;;
li.title = &quot;click to toggle&quot;;
a = document.createElement(&quot;a&quot;);
a.href = &quot;#&quot;;
a.appendChild(document.createTextNode(&quot;List Item #2&quot;));
$(a).bind(&quot;click&quot;, function() {
	$(this).next(&quot;ul&quot;).toggle();
	return false;
});
li.appendChild(a);

var subList = document.createElement(&quot;ul&quot;);

var subItem = document.createElement(&quot;li&quot;);
subItem.className = &quot;menu-item&quot;;
subItem.id = &quot;menu-item-4&quot;;
var subLink = document.createElement(&quot;a&quot;);
subLink.href = &quot;#&quot;;
subLink.appendChild(document.createTextNode(&quot;Sublist Item #1&quot;));
subItem.appendChild(subLink);
subList.appendChild(subItem);

subItem = document.createElement(&quot;li&quot;);
subItem.className = &quot;menu-item&quot;;
subItem.id = &quot;menu-item-5&quot;;
subLink = document.createElement(&quot;a&quot;);
subLink.href=&quot;#&quot;;
subLink.appendChild(document.createTextNode(&quot;Sublist Item #2&quot;));
subItem.appendChild(subLink);
subList.appendChild(subItem);

subItem = document.createElement(&quot;li&quot;);
subItem.className = &quot;menu-item&quot;;
subItem.id = &quot;menu-item-6&quot;;
subLink = document.createElement(&quot;a&quot;);
subLink.href=&quot;#&quot;;
subLink.appendChild(document.createTextNode(&quot;Sublist Item #3&quot;));
subItem.appendChild(subLink);
subList.appendChild(subItem);

li.appendChild(subList);

ul.appendChild(li);

li = document.createElement(&quot;li&quot;);
li.className = &quot;menu-item&quot;;
li.id = &quot;menu-item-3&quot;;
a = document.createElement(&quot;a&quot;);
a.href = &quot;#&quot;;
a.appendChild(document.createTextNode(&quot;List Item #3&quot;));
li.appendChild(a);
ul.appendChild(li);

document.body.appendChild(ul);
</pre>
<p>30 lines vs. 70 lines. Fluent == rad. Tell your friends.</p>
]]></content:encoded>
			<wfw:commentRss>http://blargh.tommymontgomery.com/2009/11/fluent-dom-manipulation-in-javascript/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Conditional gzipping with Apache</title>
		<link>http://blargh.tommymontgomery.com/2009/08/conditional-gzipping-with-apache/</link>
		<comments>http://blargh.tommymontgomery.com/2009/08/conditional-gzipping-with-apache/#comments</comments>
		<pubDate>Sun, 30 Aug 2009 21:41:53 +0000</pubDate>
		<dc:creator>tmont</dc:creator>
				<category><![CDATA[apache]]></category>
		<category><![CDATA[web development]]></category>

		<guid isPermaLink="false">http://blargh.tommymontgomery.com/?p=123</guid>
		<description><![CDATA[I&#8217;ve never really experimented with some of the more low-level website optimizations (server side stuff, like gzipping, caching and the like), mostly because I&#8217;ve never really had to. I&#8217;m not a server admin, and my sites don&#8217;t generate enough traffic for me to really care about such minor issues. But then I released two little [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve never really experimented with some of the more low-level website optimizations (server side stuff, like gzipping, caching and the like), mostly because I&#8217;ve never really had to. I&#8217;m not a server admin, and my sites don&#8217;t generate enough traffic for me to really care about such minor issues. But then I released two <a href="http://acronymulator.com/">little</a> <a href="http://linkurious.com/">utilities</a> wherein users could just include a piece of JavaScript from my own server. You know, they would so something like this:</p>
<pre class="brush: xml;">
&lt;script type=&quot;text/javascript&quot; src=&quot;http://linkurious.com/js&quot;&gt;&lt;/script&gt;
</pre>
<p>where the <kbd>src</kbd> attribute was pointing to an external server; namely, <strong>my</strong> server. If enough people start using these utilities (extremely unlikely, although they are pretty awesome) it could be a strain on my server.</p>
<p>So I decided to offer a plain text version and a gzipped version. But I didn&#8217;t want to store two versions of the scripts in separate places on my server just to satisfy that need. The reasons had nothing to do with disk space or anything tangible; I just didn&#8217;t &#8220;feel right&#8221; doing something so hackish. Damn this ego of mine!</p>
<p>Anyway, once I figured out how to use <a href="http://httpd.apache.org/docs/2.2/mod/mod_deflate.html"><kbd>mod_deflate</kbd></a>:</p>
<pre class="brush: plain;">
#DER!
SetOutputFilter DEFLATE
</pre>
<p>I realized that that would make <strong>everything</strong> gzipped! OH NOES!! But then I noticed you could filter the&#8230; er&#8230; filter by mimetype, like so:</p>
<pre class="brush: plain;">
#only text/html will be gzipped
AddOutputFilterByType DEFLATE text/html
</pre>
<p>But that still didn&#8217;t help me. I needed <em>conditional</em> gzipping, like if the query string said <kbd>?gz</kbd> it would know to serve the document gzipped; otherwise, it would just serve it with no compression. But how to accomplish this? Apache&#8217;s docs were no help. Luckily I&#8217;m fairly proficient at <a href="http://httpd.apache.org/docs/2.2/mod/mod_rewrite.html"><kbd>mod_rewrite</kbd></a>, and I&#8217;m decently intelligent. Let&#8217;s see if I can figure it out (<strong>SPOILER</strong>: I figured it out; this 1st person past-tense non-omniscient narrative is just a literary technique).</p>
<p>Here were my requirements:</p>
<ol>
<li>A request to <tt>http://acronymulator.com/1</tt> would serve the JavaScript document with no compression</li>
<li>A request to <tt>http://acronymulator.com/1/gz</tt> would serve the JavaScript document with gzip compression</li>
<li>Only one physical copy of the document exists on the server</li>
</ol>
<p>Let&#8217;s get to work!</p>
<p>First, let&#8217;s do the rewrite rules:</p>
<pre class="brush: plain;">
RewriteEngine On
RewriteRule ^/([1-9]\d*)(?:/gz)? /acronymulates/$1.js
</pre>
<p>The first line turns on the rewrite engine. The second line matches anything from the root that is made up of numbers, at least one number long where the first number is not a zero, with an optional <tt>/gz</tt> on the end. The rule finishes by internally redirecting those to the acronymulates directory, and serves up the JavaScript file whose name is the number with <tt>.js</tt> at the end. Simple enough, right? Sure.</p>
<p>Hopefully, you&#8217;ve deduced that <tt>/gz</tt> indicates that we want gzip compression; if it&#8217;s omitted, we don&#8217;t want gzip compression. Notice that it&#8217;s redirecting to the real JavaScript file whether the <tt>/gz</tt> is tacked on the end or not.</p>
<p>Now we need to do the deflate stuff. How we do it? Well, the most obvious solution is something like this:</p>
<pre class="brush: plain;">
&lt;Directory /path/to/acronymulates&gt;
    SetOutputFilter DEFLATE
&lt;/Directory&gt;
</pre>
<p>This makes sense because the only thing in the acronymulates directory is the JavaScript files that we want to compress. See?</p>
<div id="attachment_137" class="wp-caption aligncenter" style="width: 608px"><img src="http://blargh.tommymontgomery.com/wp-content/uploads/2009/08/dynamic_gzipping_acronymulates.png" alt="The files inside the acronymulates directory" title="dynamic_gzipping_acronymulates" width="598" height="117" class="size-full wp-image-137" /><p class="wp-caption-text">The files inside the acronymulates directory</p></div>
<p>However, this will force gzip compression no matter what, and we want it be <strong>conditional</strong>: only when the <tt>/gz</tt> is part of the URL. What do we do?</p>
<p><strong>Location to the rescue!</strong></p>
<p>The <a href="http://httpd.apache.org/docs/2.2/mod/core.html#location">Location</a> directive accomplishes this for us. more specifically, the LocationMatch directive accomplishes this for us. The difference between Directory and Location is that Directory matches a physical directory on the filesystem, whereas Location just matches a virtual directory (i.e. the path of the URL: /1/gz, in our case). Now it&#8217;s fairly obvious what the solution should be:</p>
<pre class="brush: plain;">
&lt;LocationMatch /[1-9]\d*/gz&gt;
    SetOutputFilter DEFLATE
&lt;/LocationMatch&gt;
</pre>
<p>And there&#8217;s your dynamic gzipping using Apache. Note that these are real life examples (IRL ZOMG). Let&#8217;s prove it with Firebug&#8217;s help.</p>
<p>Without compression (<a href="http://acronymulator.com/1">http://acronymulator.com/1</a>:</p>
<div id="attachment_142" class="wp-caption aligncenter" style="width: 467px"><img src="http://blargh.tommymontgomery.com/wp-content/uploads/2009/08/dynamic_gzipping_11.png" alt="Dynamic gzipping: without compression" title="dynamic_gzipping_1" width="457" height="246" class="size-full wp-image-142" /><p class="wp-caption-text">Dynamic gzipping: without compression</p></div>
<p>Without compression (<a href="http://acronymulator.com/1/gz">http://acronymulator.com/1/gz</a>:</p>
<div id="attachment_143" class="wp-caption aligncenter" style="width: 467px"><img src="http://blargh.tommymontgomery.com/wp-content/uploads/2009/08/dynamic_gzipping_1_gz1.png" alt="Dynamic gzipping: with compression" title="dynamic_gzipping_1_gz" width="457" height="303" class="size-full wp-image-143" /><p class="wp-caption-text">Dynamic gzipping: with compression</p></div>
<p>And here&#8217;s proof that both URLs serve the same content:<br />
<div id="attachment_138" class="wp-caption aligncenter" style="width: 526px"><img src="http://blargh.tommymontgomery.com/wp-content/uploads/2009/08/dynamic_gzipping_md5sum.png" alt="Proof that both URLs serve the same content" title="dynamic_gzipping_md5sum" width="516" height="90" class="size-full wp-image-138" /><p class="wp-caption-text">Proof that both URLs serve the same content</p></div></p>
]]></content:encoded>
			<wfw:commentRss>http://blargh.tommymontgomery.com/2009/08/conditional-gzipping-with-apache/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Why Everybody is Losing the Browser Wars</title>
		<link>http://blargh.tommymontgomery.com/2009/08/why-everybody-is-losing-the-browser-wars/</link>
		<comments>http://blargh.tommymontgomery.com/2009/08/why-everybody-is-losing-the-browser-wars/#comments</comments>
		<pubDate>Sun, 16 Aug 2009 04:37:40 +0000</pubDate>
		<dc:creator>tmont</dc:creator>
				<category><![CDATA[rants]]></category>
		<category><![CDATA[web development]]></category>

		<guid isPermaLink="false">http://blargh.tommymontgomery.com/?p=82</guid>
		<description><![CDATA[Recently, I read about RockMelt, an upcoming new browser that is apparently &#8220;endorsed&#8221; by the guy who started Netscape. The description of RockMelt made me start thinking about how every browser sucks, and why this new one doesn&#8217;t appear to be trying to buck the trend of suck. But first, a brief, slightly egocentric history [...]]]></description>
			<content:encoded><![CDATA[<p>Recently, I read about <a href="http://rockmelt.com/">RockMelt</a>, an upcoming new browser that is apparently &#8220;endorsed&#8221; by the <a href="http://en.wikipedia.org/wiki/Marc_Andreessen">guy who started Netscape</a>. The description of RockMelt made me start thinking about how every browser sucks, and why this new one doesn&#8217;t appear to be trying to buck the trend of suck. But first, a brief, slightly egocentric history of the suck.</p>
<h2>In Review: A History of Suck</h2>
<p> In the early 90s, it was all about Netscape Navigator and its little ship helm logo. Anybody who was in junior high in the 90s should have seen it. Then, while Netscape basked in its glory, doing nothing to improve itself, along came IE and the little blue E that we&#8217;ve all come to know and <del datetime="2009-08-15T20:57:51+00:00">love</del> despise with the wrath of a thousand suns. Netscape pretty much disappeared, largely due to the fact that the early IEs were much, much better, and also because everyone started using Windows, which of course shipped with IE (since it was made by Microsoft).</p>
<p>The pinnacle of browser beauty culminated in the advent of Internet Explorer 6 in the late 90s, and pretty much spelled the doom for Netscape, which hadn&#8217;t been significantly improved for 6 years. You could look at futhermucking PNGs with IE! How could Netscape possibly compete with that!?</p>
<p>Anyway, IE and Microsoft enjoyed its reign as king of browsers, until Netscape realized they had no hope of ever competing because they were ugly and lazy and stupid. So they sold their souls to the Mozilla corporation, which took out all of the good stuff in Netscape (the Gecko engine), and left the suck to rot in versions 8 and 9. They created Firefox, which hipsters and linux geeks the world over have heralded as the second coming of Christ. Firefox basically was just a way for nerds to assert their superiority over other nerds by name-dropping it. Because everyone knows that if you haven&#8217;t heard of Firefox, you can haz a n00b. Kind of like what I did with RockMelt several paragraphs ago. Try to keep up.</p>
<p>Meanwhile, a bunch of Norwegians, in true viking style, started their own browser called &#8220;Opera&#8221;. I can only assume they named it something so lame because of the language barrier. Opera began being used by an even smaller clique of nerd know-it-alls than Firefox. They are even more annoying than their Firefox counterparts, albeit less vocal. Opera proclaimed a love for standards-compliant (an admirable goal), lightweight, portable browsers, and they pretty much succeeded. Unfortunately, nobody gives a crap, because it looks hideous.</p>
<p>Back at Microsoft, the genius engineers behind IE6 were enjoying their throngs of groupie women, failing to realize that in the last 10 years <em>things have actually happened</em>! Say what!? IE6 is a horrible, horrible abomination? I thought we could just build an application and then let it stagnate for a decade and it would still be awesome! How did we miss this!?</p>
<p>Microsoft scrambled to alleviate the most vocal of the complaints against IE6 (&#8220;no tabbed browsing!? what is this, the 12th century? Firefox is safer LOLZ&#8221;). IE7 came out, to no buzz whatsoever. Since all the people who knew how to use the web were already using Firefox (all 20 of them), and most people turn off automatic Windows updates as soon as they plugin their computers, IE7 was pretty much not adopted by anyone. All it really did was give web developers one more browser to test. Granted, in terms of standards compliance, it was <em>far</em> better than IE6 (transparent PNGs <em>gasp!</em>), but it was still worse than Firefox 1.5. And Opera. So nobody was converted, but frankly, that wasn&#8217;t really the goal of IE7 anyway, because IE still had 95% of the market share anyway. They were still sitting pretty, until&#8230;</p>
<h3>Mozilla Add-Ons, or How Firefox Lessened the Suck</h3>
<p>This was Mozilla&#8217;s most brilliant breakthrough, and frankly, it&#8217;s the only thing that&#8217;s currently keeping people from switching to a browser that doesn&#8217;t require 300MB of memory to sit idly. Mozilla created this thing called XUL, but didn&#8217;t put it to good use until they created the addons site, and people actually started using it. Suddenly, the browser wasn&#8217;t just an application, it was a <em>way of life</em>. The Firefox bigots finally had a solid reason why their browser was better: it was customizable. In a way in which pretty much no other desktop application was. It really was and is still a remarkable amount of genius. <a href="http://getfirebug.com/">Firebug</a> is the <strong>only</strong> only that reason I still use Firefox. It&#8217;s bloated, slow, resource-intensive, ugly, and its users are among the most annoying on the internet, but it&#8217;s the only way I can actually debug anything on the web.</p>
<p>Meanwhile, in Microsoft Land, IE7 was stagnating (surprise). Business managers are mostly Nazis (Godwin&#8217;s law) and don&#8217;t want anyone browsing anything besides their intranet and/or SharePoint, so they had no reason to allow their underlings to upgrade their browser to IE7. That hideous rite <a href="http://blog.digg.com/?p=878">still rages on today</a>. In Norway, Opera was developing rapidly to the tune of CSS3 and standards compliance, but nobody cares about that besides web developers, and they weren&#8217;t about to leave Firebug behind. Not to mention the fact that they were still verifying that their websites are IE4+ compatible, so any technology more recent than an animated gif was not used anyway. In version 9.5/6, Opera released Dragonfly, their own version of Firebug, which was a giant step forward, but still much worse than Firebug. Nobody was converted. The market share had shifted slightly in favor of Firefox, but IE still held a commanding 4:1 lead.</p>
<h3>Google Starts Sucking, Too</h3>
<p>Then, suddenly, a new player emerges! Google enters the fray with Chrome, a brand new browser!&#8230; Except that there wasn&#8217;t anything new or innovative about it. The one nice feature that Chrome had was that each tab was its own process, which meant that while Flash was busy crashing in one tab, the other tabs would independently and cheerfully continue to load&#8230;. Until they eventually crashed as well. Chrome captured approximately 2% of the market, which is actually pretty impressive for a browser that has nothing to offer, besides the coolness of its brand. That figure is even more impressive when you factor in how it was only available on Windows for over 6 months.</p>
<p>And here we are, in 2009, with about three browsers to choose from, all with huge, gaping flaws. You&#8217;ll notice that I left Safari out of this little anecdote. That&#8217;s because it was an <em>egocentric</em> history of browsers, and I&#8217;ve never used Safari except for testing, and marveling at how incredibly difficult it is to turn on the JavaScript error console (<kbd>defaults write com.apple.Safari IncludeDebugMenu 1</kbd>: are you %@#!ing kidding me!?).</p>
<h2>A Full Circle</h2>
<p>So, why did I go through all the trouble of outlining this? My negativity towards browsers is universal, as I&#8217;ve sampled all of the major ones and a few of the minor ones, and they all have one thing in common: sucking. The world of technology is evolving. Even though the open source community is strong, all of those people have day jobs because they can&#8217;t make a living by writing awesome software. They write awesome software on the side while they support their families by implementing <strong>SOA</strong> through <strong>REST</strong> visa vis <strong>SaaS</strong>. The software industry is a wave of fads and trends that executives latch onto to try and be the next Google, despite the fact that companies like Google <em>never</em> employed such empty things like SOA. Well, maybe they did indirectly, but that was never their strategy. Every developer who has a job now is a slave to these trends, even when they&#8217;d rather not be. Money and greed rule the day; in any industry, really. It&#8217;s the one downside of capitalism: it always seems to morph into pure greed.</p>
<p>So, allow me to come full circle on how the the browser wars are similar to the trials and tribulations of the software industry. The new waves of browsers are very similar to how non-techie executives would mandate that a software application would develop. </p>
<h3>Firesuck</h3>
<p>New features in Firefox 3.5 include one-click bookmarking, an improved address bar (awesome bar), something about tabs, better memory management and session restore. Useful features, sure, but where&#8217;s support for CSS3, or improved stability of Flash, or a faster rendering engine, or more standards-compliant HTML rendering? Besides improving the memory management, they were clearly more focused on improving the user experience than improving the actual software.</p>
<p>Not that improving the user experience is bad, but when a YouTube video causes Firefox to lock up for 30 seconds, that seems like something that should be fixed before, say, a more convenient way to bookmark pages. I mean, who even uses bookmarks anyway? I have like four bookmarks (all to login pages for paying my bills online). There&#8217;s only about 10 sites that I visit on a regular basis, and I don&#8217;t have trouble remembering the fully qualified domain names of 10 sites.</p>
<h3>Unite the Suck</h3>
<p>Opera 10 introduced Unite, which basically turns Opera into a web server. Kind of cool, I guess, but how trying to take some competition away from Firefox by making Dragonfly not the slowest piece of tripe ever? Or use a font that doesn&#8217;t look like it was created by a three year old with a box of crayons? Or make the default skin less hideous? Or support JavaScript features past version 1.5? And if someone is actually smart enough to know what a web server is, they&#8217;re probably already running their own web server, and are not going to relinquish control to a web <em>browser</em>.</p>
<h3>I&#8217;m Feeling Sucky</h3>
<p>Google recently announced that their new operating system will be available in 2010 sometime, which is basically a wrapper around their browser. A novel idea, but why I would leave my current operating system for one that&#8217;s based around a browser that I don&#8217;t use? Maybe their idea will work, but I don&#8217;t think people are quite ready to turn their computers into a giant, fancy web browser. More importantly, I don&#8217;t think the web is ready for it. Connections are too slow, servers are too easily assaulted, and web applications are too unusable (compared with desktop apps) that being as productive on the web as you are on the desktop is still 10 years away.</p>
<p><a href="http://teddziuba.com/2008/09/a-web-os-are-you-dense.html">This guy</a> says it pretty well, with some MSPaint-inspired graphics to help you learn. Because learning is fun!</p>
<h2>The Conclusion</h2>
<p>The next generation of browsers need to focus on delivering content in the easiest, fastest and least painful way possible. I would happily give up 90% of the features in Firefox if the application never crashed. Firefox crashes so often that it <strong>has its own built-in crash reporter</strong>. I might use Chrome exclusively if flash didn&#8217;t crash the browser 10% of the time. I might use Opera if Dragonfly was slightly usable. I might use Safari if&#8230; well, I&#8217;ll never use Safari. I might use IE if Microsoft didn&#8217;t insist on deviating from every known web standard.</p>
<p>RockMelt, like Chrome, seems to be focusing on bridging the gap between desktop and web. Why don&#8217;t they just focus on fixing the problems with all the other browsers? What if they made an easily debuggable, solid, secure, fast, easy-to-use, lightweight browser? Instead, we&#8217;re probably going to get another Opera Unite, with the absolute latest in bookmarking technology. We&#8217;ll be able to bookmark freaking everything! Our lives will never be the same!</p>
<h3>Plz.</h3>
<p>I appeal to the browser makers: stop giving me new features, and fix the stuff that is already broken. Right now, <em>nobody</em> is winning. Let the <em><strong>users</strong></em> win the browser wars.</p>
]]></content:encoded>
			<wfw:commentRss>http://blargh.tommymontgomery.com/2009/08/why-everybody-is-losing-the-browser-wars/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
