Michelle Tilley2018-04-23T17:10:30-07:00http://michelletilley.net/Michelle Tilleymichelle@michelletilley.netUsing React Motion's StaggeredMotion for Staggered Animations2016-01-10T06:39:00-08:00http://michelletilley.net/2016/01/10/react-motion-staggeredmotion<p><a href="https://twitter.com/nashvail">Nash Vail</a> recently released <a href="https://medium.com/@nashvail/a-gentle-introduction-to-react-motion-dc50dd9f2459">an <em>awesome</em> tutorial on how to create a really cool menu animation</a> using React Motion. His final product is this:</p>
<p><img src="/images/nash-vail-animation.gif" alt="Nash Vail's Menu" /></p>
<p>I found it very useful for learning how to use <a href="https://github.com/chenglou/react-motion">React Motion</a>; you should definitely <a href="https://medium.com/@nashvail/a-gentle-introduction-to-react-motion-dc50dd9f2459">check it out if you haven’t</a>.</p>
<p>Toward the end of the article, Nash changes the animation from being uniform to staggering each of the small white buttons so they animate at different times. He accomplishes this by storing individual components on the component’s state:</p>
<blockquote>
<p>We’re close, but not there yet. What if we added delay each time before the next child button starts to animate? That’s exactly what we need to do, to achieve the final effect. Doing so wasn’t so straightforward though, I had to store each motion component as an array in a state variable. Then change the state one by one for each of the child button to achieve the desired effect</p>
</blockquote>
<p>However, React Motion has a cool component called <code>StaggeredMotion</code>, which makes the interpolated value of each of a <em>list</em> of styles dependent on any of the other previous values. It was non-obvious to me how I could use this technique to make this demo work, because each button was moving in a different direction — I don’t want them to follow each other, I want them to continue to move in their own direction.</p>
<p>Finally, it occurred to me that what I really wanted to control the interpolation for was “how finished” each buttons’ animation was; for example, if the first button is about half done moving to its final position, then the second button should be about a quarter of the way, and so on. I made a few changes to the app to make this work.</p>
<p>First, I changed the function that calculates the final position of each button to take a second parameter called <code>percent</code> that would multiply the delta X and Y values by a certain amount.</p>
<gist data-id="9431d5cecc3d57c4c317" data-file="index_01.js"></gist>
<noscript><pre><code>const deltaPosition = (idx, percent) => {
const angle = BASE_ANGLE + idx * SEPARATION_ANGLE;
const dX = Math.floor(FLYOUT_RADIUS * Math.cos(toRadians(angle)) * percent);
const dY = Math.floor(-1 * FLYOUT_RADIUS * Math.sin(toRadians(angle)) * percent);
return {
dX: dX + CHILD_BUTTON_DIAM / 2,
dY: dY - CHILD_BUTTON_DIAM / 2
};
};
</code></pre><div><small><em><a href="https://gist.github.com/9431d5cecc3d57c4c317">View Gist for <code>index_01.js</code> on GitHub</a></em></small></div></noscript>
<p>So, if <code>percent</code> is 0, then the button won’t move at all, and if <code>percent</code> is 1, then the button will fully move to its final destination.</p>
<p>Next, I removed <code>mainButtonStyles</code>, <code>initialChildButtonStyles</code>, and <code>finalChildButtonStyles</code> and replaced them with methods that could be used to calculate the style for a button at any completion percentage, including rotation:</p>
<gist data-id="9431d5cecc3d57c4c317" data-file="index_02.js"></gist>
<noscript><pre><code>Not Found</code></pre><div><small><em><a href="https://gist.github.com/9431d5cecc3d57c4c317">View Gist for <code>index_02.js</code> on GitHub</a></em></small></div></noscript>
<p>Finally, I updated <code>render</code> to wire together this new method into the <code>StaggeredMotion</code> component. <code>StaggeredMotion</code> takes an <em>array</em> of styles, and its child function should take an <em>array</em> of current values.</p>
<gist data-id="9431d5cecc3d57c4c317" data-file="index_03.js"></gist>
<noscript><pre><code>Not Found</code></pre><div><small><em><a href="https://gist.github.com/9431d5cecc3d57c4c317">View Gist for <code>index_03.js</code> on GitHub</a></em></small></div></noscript>
<p>The magic here happens in <code>nextStyles</code>, where the array of final styles is calculated. In English, it would read something like the following:</p>
<ul>
<li>The first item in the array is the “leader” element and all the other values are based off it. So, if we’re working with the 0-indexed item, just return our final style.</li>
<li>Each other item in the array is calculated by looking at the previous element (i.e. the button before it).
<ul>
<li>If the previous button has animated more than 20% of the way to completion, start our own animation by returning our goal value.</li>
<li>If the previous button has not yet animated more than 20% of the way to completion, just stay where we were last iteration.</li>
</ul>
</li>
</ul>
<p>Now that we can teach <code>StaggeredMotion</code> how to “animate” over our 0-to-100% value, we can use it to calculate the correct styles for each component based on the current completion percentage.</p>
<gist data-id="9431d5cecc3d57c4c317" data-file="index_04.js"></gist>
<noscript><pre><code> return (
<div>
<StaggeredMotion defaultStyles={defaultStyles} styles={nextStyles}>
{(interpolatedStyles) => {
return <div>
{interpolatedStyles.map(({ percent }, idx) => {
const style = this.childButtonStyle(idx, percent);
return <div className="child-button" style={style} key={idx} />;
})}
</div>;
}}
</StaggeredMotion>
<div className="main-button" style={this.mainButtonStyles()} onClick={this.toggleMenu} />
</div>
);
</code></pre><div><small><em><a href="https://gist.github.com/9431d5cecc3d57c4c317">View Gist for <code>index_04.js</code> on GitHub</a></em></small></div></noscript>
<p>And that’s that! With some CSS tweaks, the final effect looks like this:</p>
<p><img src="/images/react-motion-stagger.gif" alt="Final Staggered Animation" /></p>
<p>And here’s the complete code listing:</p>
<gist data-id="9431d5cecc3d57c4c317" data-file="complete.js"></gist>
<noscript><pre><code>Not Found</code></pre><div><small><em><a href="https://gist.github.com/9431d5cecc3d57c4c317">View Gist for <code>complete.js</code> on GitHub</a></em></small></div></noscript>
<p>Thanks so much to Nash Vail for his awesome tutorial that helped lead me to understand how all this works!</p>
Writing React Components that Support the LinkedStateMixin and the valueLink Property2014-09-24T02:02:00-07:00http://michelletilley.net/2014/09/24/custom-react-components-and-the-valuelink-property<p>In a React application, it’s very common for a component to contain state that should be editable by a child component. The most basic example uses a text input with a <code>value</code> and <code>onChange</code> handler to display and update the text.</p>
<gist data-id="bd66e40b00598e1288f2" data-file="ex_01.js"></gist>
<noscript><pre><code>var Editor = React.createClass({
getInitialState: function() {
return { text: "" };
},
render: function() {
return <input type="text" value={this.state.text}
onChange={this.handleChange} />;
},
handleChange: function(evt) {
this.setState({text: evt.target.value});
}
});</code></pre><div><small><em><a href="https://gist.github.com/bd66e40b00598e1288f2">View Gist for <code>ex_01.js</code> on GitHub</a></em></small></div></noscript>
<p>Doing this over and over, especially in a component with a lot of <a href="http://facebook.github.io/react/docs/forms.html#controlled-components">controlled inputs</a>, can get repetitive. The React addons (available when you use the “React with Add-Ons” download, or via <code>require("react/addons")</code> when using a CommonJS bundler) provide the <code>LinkedStateMixin</code> to simplify situations where an input should remain in lockstep with a given piece of state.</p>
<gist data-id="bd66e40b00598e1288f2" data-file="ex_02.js"></gist>
<noscript><pre><code>var Editor = React.createClass({
mixins: [React.addons.LinkedStateMixin],
getInitialState: function() {
return { text: "" };
},
render: function() {
return <input type="text" valueLink={this.linkState("text")} />;
}
});</code></pre><div><small><em><a href="https://gist.github.com/bd66e40b00598e1288f2">View Gist for <code>ex_02.js</code> on GitHub</a></em></small></div></noscript>
<p>Now the input and the <code>text</code> state will remain synchronized; changing the state via <code>setState</code> will update the input, and changing the input will automatically call <code>setState</code>, updating the <code>text</code> key.</p>
<h2 id="thislinkstate-and-reactlink-objects">this.linkState() and ReactLink Objects</h2>
<p>But what does <code>this.linkState(key)</code>, a function provided to our component by <code>LinkedStateMixin</code>, actually return? It’s actually a very simple object created by React’s <code>ReactLink</code> module:</p>
<gist data-id="bd66e40b00598e1288f2" data-file="ex_03.js"></gist>
<noscript><pre><code>{
value: ..., // current value of this.state[key]
requestChange: function() { ... } // function to call to update this.state[key]
}</code></pre><div><small><em><a href="https://gist.github.com/bd66e40b00598e1288f2">View Gist for <code>ex_03.js</code> on GitHub</a></em></small></div></noscript>
<p>The <code>value</code> property contains the current value of <code>this.state[key]</code>, and the <code>requestChange</code> property is a function we can call with a new value for <code>this.state[key]</code> to update it.</p>
<p>That means our above example could more verbosely be written like this:</p>
<gist data-id="bd66e40b00598e1288f2" data-file="ex_04.js"></gist>
<noscript><pre><code>var Editor = React.createClass({
mixins: [React.addons.LinkedStateMixin],
getInitialState: function() {
return { text: "" };
},
render: function() {
var valueLink = this.linkState("text");
var handleChange = function(evt) {
valueLink.requestChange(evt.target.value);
};
return <input type="text" value={valueLink.value}
onChange={handleChange} />;
}
});</code></pre><div><small><em><a href="https://gist.github.com/bd66e40b00598e1288f2">View Gist for <code>ex_04.js</code> on GitHub</a></em></small></div></noscript>
<p>Written this way, it’s easy to see that the <code>valueLink</code> property is very straightforward: it simply uses the object’s <code>value</code> property as the current value of the form and the object’s <code>requestChange</code> property as the callback to change that value. We now have all the information we need to implement a <code>valueLink</code>-style property on any component we write.</p>
<h2 id="extrapolating-to-custom-components">Extrapolating to Custom Components</h2>
<p>Let’s build a simple React component that wraps a <a href="https://github.com/laktek/really-simple-color-picker">simple jQuery color picker</a>. The component wraps a single div, and we utilize React component lifecycle hooks to call appropriate plugin methods when the incoming properties change.</p>
<gist data-id="bd66e40b00598e1288f2" data-file="ex_05.js"></gist>
<noscript><pre><code>var ColorPicker = React.createClass({
propTypes: {
value: React.PropTypes.string,
onChange: React.PropTypes.func
},
getDefaultProps: function() {
return {
value: "",
onChange: function() {}
};
},
render: function() {
return <div />;
},
componentDidMount: function() {
jQuery(this.getDOMNode()).colorPicker({
// initial color from the `value` prop
pickerDefault: this.props.value,
onColorChange: this.onColorChange
});
},
componentWillReceiveProps: function(nextProps) {
if (this.props.value !== nextProps.value) {
// new `value` prop triggers manual change in plugin
var node = jQuery(this.getDOMNode());
node.val(nextProps.value);
node.change();
}
},
onColorChange: function(id, color) {
// color changes sent to parent via `onChange` prop
this.props.onChange(color);
}
});</code></pre><div><small><em><a href="https://gist.github.com/bd66e40b00598e1288f2">View Gist for <code>ex_05.js</code> on GitHub</a></em></small></div></noscript>
<p>We can use the color picker by passing it <code>value</code> and <code>onChange</code> properties, like so:</p>
<gist data-id="bd66e40b00598e1288f2" data-file="ex_06.js"></gist>
<noscript><pre><code>// ...
render: function() {
<ColorPicker value={this.state.color}
onChange={this.handleChange} />
},
handleChange: function(color) {
this.setState({color: color});
}</code></pre><div><small><em><a href="https://gist.github.com/bd66e40b00598e1288f2">View Gist for <code>ex_06.js</code> on GitHub</a></em></small></div></noscript>
<p>It would be nice if our component also supported use of the <code>LinkedStateMixin</code>. Let’s change our application to use <code>valueLink</code>:</p>
<gist data-id="bd66e40b00598e1288f2" data-file="ex_07.js"></gist>
<noscript><pre><code>// ...
mixins: [React.addons.LinkedStateMixin],
render: function() {
<ColorPicker valueLink={this.linkState("color")} />
}</code></pre><div><small><em><a href="https://gist.github.com/bd66e40b00598e1288f2">View Gist for <code>ex_07.js</code> on GitHub</a></em></small></div></noscript>
<p>Since we know that the <code>valueLink</code> property contains an object with <code>value</code> and <code>requestChange</code> properties, we can easily modify the ColorPicker component:</p>
<gist data-id="bd66e40b00598e1288f2" data-file="ex_08.js"></gist>
<noscript><pre><code>var ColorPicker = React.createClass({
propTypes: {
valueLink: React.PropTypes.shape({
value: React.PropTypes.string.isRequired,
requestChange: React.PropTypes.func.isRequired
})
},
getDefaultProps: function() {
return {
valueLink: {
value: "",
requestChange: function() {}
}
};
},
render: function() {
return <div />;
},
componentDidMount: function() {
jQuery(this.getDOMNode()).colorPicker({
// initial color from the `valueLink` prop
pickerDefault: this.props.valueLink.value,
onColorChange: this.onColorChange
});
},
componentWillReceiveProps: function(nextProps) {
if (this.props.valueLink.value !== nextProps.valueLink.value) {
// new `valueLink.value` prop triggers manual change in plugin
var node = jQuery(this.getDOMNode());
node.val(nextProps.valueLink.value);
node.change();
}
},
onColorChange: function(id, color) {
// color changes sent to parent via `valueLink` prop
this.props.valueLink.requestChange(color);
}
});</code></pre><div><small><em><a href="https://gist.github.com/bd66e40b00598e1288f2">View Gist for <code>ex_08.js</code> on GitHub</a></em></small></div></noscript>
<p>However, we’ve lost the ability to use <code>value</code> and <code>onChange</code> with our component, since we’ve hard-coded it to use <code>this.props.valueLink</code> everywhere. We could litter the component with <code>if</code> statements checking for the existence of <code>this.props.valueLink</code>, but instead let’s write a simple abstraction so we don’t have to worry about it:</p>
<gist data-id="bd66e40b00598e1288f2" data-file="ex_09.js"></gist>
<noscript><pre><code>var ColorPicker = React.createClass({
// ...
getValueLink: function(props) {
return props.valueLink || {
value: props.value,
requestChange: props.onChange
};
}
});</code></pre><div><small><em><a href="https://gist.github.com/bd66e40b00598e1288f2">View Gist for <code>ex_09.js</code> on GitHub</a></em></small></div></noscript>
<p>This <code>getValueLink</code> function takes a properties object and either returns its <code>valueLink</code> property, if it has one, or creates one from the <code>value</code> and <code>onChange</code> properties. Now, we can write our component as if we always have a <code>valueLink</code> property:</p>
<gist data-id="bd66e40b00598e1288f2" data-file="ex_10.js"></gist>
<noscript><pre><code>var ColorPicker = React.createClass({
propTypes: {
value: React.PropTypes.string,
onChange: React.PropTypes.func,
valueLink: React.PropTypes.shape({
value: React.PropTypes.string.isRequired,
requestChange: React.PropTypes.func.isRequired
})
},
getDefaultProps: function() {
return {
value: "",
onChange: function() {},
valueLink: null
};
},
getValueLink: function(props) {
return props.valueLink || {
value: props.value,
requestChange: props.onChange
};
},
render: function() {
return <div />;
},
componentDidMount: function() {
jQuery(this.getDOMNode()).colorPicker({
pickerDefault: this.getValueLink(this.props).value,
onColorChange: this.onColorChange
});
},
componentWillReceiveProps: function(nextProps) {
var currentValueLink = this.getValueLink(this.props),
nextValueLink = this.getValueLink(nextProps);
if (currentValueLink.value !== nextValueLink.value) {
var node = jQuery(this.getDOMNode());
node.val(nextValueLink.value);
node.change();
}
},
onColorChange: function(id, color) {
this.getValueLink(this.props).requestChange(color);
}
});</code></pre><div><small><em><a href="https://gist.github.com/bd66e40b00598e1288f2">View Gist for <code>ex_10.js</code> on GitHub</a></em></small></div></noscript>
<p>And that’s it! We now have a React component that works both with and without <code>valueLink</code>. <a href="http://jsfiddle.net/BinaryMuse/c3nheycp/">Here’s an example</a>:</p>
<iframe width="100%" height="400" src="http://jsfiddle.net/BinaryMuse/c3nheycp/embedded/result,js,html" allowfullscreen="allowfullscreen" frameborder="0"></iframe>
Why I'm Excited about Atom2014-02-27T00:00:00-08:00http://michelletilley.net/2014/02/27/why-im-excited-about-atom<p>If you haven’t heard, the fine folks at GitHub released <a href="http://atom.io/">a text editor called Atom</a> into beta yesterday. As with any new tool or technology, reactions were mixed. I’ve been using Atom for about two months now, since the private alpha, and I’d like to tell you why I’m excited about this little editor.</p>
<p><img src="/images/atom_screenshot.png" alt="Atom Screenshot" /></p>
<p>Atom is <a href="http://blog.atom.io/2014/02/26/the-nucleus-of-atom.html">built on Chromium</a>; it is, essentially, a web application, running inside a dedicated browser. You might not even notice this fact at first glance—it runs like any other native app, has access to the file system, and does all the things you’d expect any other native app to do. But, under the hood, Atom leverages HTML, CSS, and JavaScript for its UI and leans on <a href="http://nodejs.org/">Node.js</a> for system-level APIs.</p>
<p>This fact opens up lots of possibilities. Users can make simple customizations to their UI <a href="http://discuss.atom.io/t/atom-is-so-powerful-that-it-blows-my-mind/294">with a few lines of CSS</a>. If you’re not sure what classes to override, just pop open the inspector and take a look.</p>
<p><img src="/images/atom_inspector_ss.png" alt="Atom Inspector" /></p>
<p>Since packages are also <a href="https://github.com/atom/fuzzy-finder/">written using HTML, CSS and JavaScript</a>, the barrier to creating packages is quite low compared with many other editors. Furthermore, the Node.js backing gives you the ability to use any of the <a href="https://www.npmjs.org/">more than 60,000 Node packages on npm</a>, as well as any of Node’s built-in APIs. Want to start a web server from your package? <a href="http://nodejs.org/api/http.html">No problem</a>. Launch some external processes? <a href="http://nodejs.org/api/child_process.html">Can do</a>.</p>
<p>Really, since it’s all Chromium under the hood, the sky is the limit. Imagine the cool code visualization tools you could build using Canvas or WebGL. <a href="http://d3js.org/">D3</a> and <a href="http://threejs.org/">Three.js</a> in my editor? Yes, please!</p>
<p>Plus, what editor lets you do this with two lines of code? :)</p>
<p><img src="/images/atom_flipped.png" alt="Oops!" /></p>
<p>In short, I feel Atom takes the Emacs mode of thinking—that your editor should be just as malleable as the code you write with it—and presents it in a fresh, modern way, ready to take on the web-based world. Give it a shot if you haven’t already; sign up for a beta invite <a href="http://atom.io/">over at atom.io</a>.</p>
Creating Chrome Extensions with React2014-02-24T00:00:00-08:00http://michelletilley.net/2014/02/24/creating-chrome-extensions-with-react<p>If you’re into client-side web development to any extent, you’ve probably heard of Facebook’s <a href="http://facebook.github.io/react/index.html">React</a> library (or maybe you’ve just been living under a rock). Recently, I was working on a Chrome extension, and decided to see how well React fit in to the development I was doing. (Spoiler alert: it fit in quite well.) This post is not meant to be a React tutorial in any way, but rather a brief overview of some of React’s core concepts and some of the things I learned while building the application.</p>
<h1 id="the-extension">The Extension</h1>
<p>For reference, the extension I built with React is called <a href="https://github.com/BinaryMuse/chrome-fast-tab-switcher">Fast Tab Switcher</a>, which I made for people who, like myself, don’t seem to know how to close browser tabs, and subsequently can’t find the one they’re looking for. The extension allows users to hit a keystroke and pop open a window that shows all their currently open tabs; users can then filter the tabs with a text box, and press enter to switch to the currently selected entry. All the code is available <a href="https://github.com/BinaryMuse/chrome-fast-tab-switcher">on GitHub</a>, and the extension can also be installed from <a href="https://chrome.google.com/webstore/detail/fast-tab-switcher/jkhfenkikopkkpboaipgllclaaehgpjf">the Chrome Web Store</a>.</p>
<div style="text-align: center;">
<a href="/images/react_chrome_extension_demo.gif" target="_blank">
<img src="/images/react_chrome_extension_demo.gif" style="max-width: 100%" alt="Screenshot" />
</a>
</div>
<blockquote>
<p>Note: If a lot of time has passed since I wrote this post and the code has changed, you can always get to the original code at <a href="https://github.com/BinaryMuse/chrome-fast-tab-switcher/tree/v1.0.1">the v1.0.1 tag</a>. All the links to source files will point to this tag.</p>
</blockquote>
<p>I chose to use <a href="http://browserify.org/">Browserify</a> (and <a href="https://github.com/andreypopp/reactify">Reactify</a>, for the JSX transformation) to build this application, which allows us to build code using Node.js style <code>require</code>s and <code>module.exports</code>…s. It’s not required for building this kind of app, but having access to Node packages and tooling is a nice win. Check out <a href="https://github.com/BinaryMuse/chrome-fast-tab-switcher/tree/v1.0.1/scripts">the build scripts</a> I used to build the Browserified bundles (<code>build.sh</code> builds one time then exits, <code>watch.sh</code> watches for changes in the source files and compiles continuously).</p>
<h1 id="reacts-big-idea">React’s Big Idea</h1>
<p>If you’re not familiar with React, it’s a JavaScript library for creating UIs based on reactive data flow. The basic idea is to create components made up of idempotent rendering functions that always represent the UI for that component at any given time. When there’s a state change in your component, React calls your rendering function again and builds an in-memory representation of your UI, and compares this to the last in-memory representation to figure out what pieces of the actual DOM should be updated.</p>
<p>I’m <em>seriously</em> glossing over details here, so be sure to check out the <a href="http://facebook.github.io/react/index.html">React web site</a> and some of their <a href="http://facebook.github.io/react/docs/videos.html">awesome videos</a> to learn more. Of particular note is “Rethinking Best Practices” from JSConf.Asia 2013.</p>
<iframe width="853" height="480" src="//www.youtube.com/embed/DgVS-zXgMTk?rel=0" frameborder="0" allowfullscreen=""></iframe>
<p>If this whole thing sounds like a terrible idea to you, I urge you to give it a shot anyway—the proof of the pudding is, as they say, in the eating. I unfortunately (and <a href="/2012/01/08/programmer-criticism.html">somewhat ironically</a>) dismissed it pretty quickly when I first heard about it, but now I wish I had given it a closer look sooner.</p>
<h2 id="jsx">JSX</h2>
<p>One of React’s more unique features is called JSX—it is, quite simply, an XML-like syntax that React transforms into JavaScript.</p>
<gist data-id="7dc242ebd829c8ac0020" data-file="jsx.jsx"></gist>
<noscript><pre><code>// JSX lets you write this...
render: function() {
return (
<p onClick={this.onClick}>
Hello, <input type="text" placeholder="Your name here" />!
It is {this.getDate()}.
</p>
);
}
// ...instead of this
render: function() {
return (
React.DOM.p({onClick: this.onClick},
" Hello, ", React.DOM.input({type: "text", placeholder: "Your name here"}), "! " +
"It is ", this.getDate(), ". "
)
);
}</code></pre><div><small><em><a href="https://gist.github.com/7dc242ebd829c8ac0020">View Gist for <code>jsx.jsx</code> on GitHub</a></em></small></div></noscript>
<p>The idea is to be able to express your views with something that looks like HTML instead of a bunch of JavaScript function calls. A lot of people seem to dislike JSX; I’ve grown rather fond of it. That said, it’s completely optional; while I use it in the extension, it’s one of the least important pieces of React, and you shouldn’t let it trip you up.</p>
<h2 id="learning-react">Learning React</h2>
<p>From this point on, I’ll be assuming you know at least a tiny bit about how to use React; in particular, we’ll mention parts of a component’s lifecycle a couple times, and discuss state and properties. If you get totally lost reading this post, or want to brush up on React before we begin, check out the resources above and <a href="http://facebook.github.io/react/docs/tutorial.html">the React tutorial</a> and then come back. We’ll be waiting.</p>
<h1 id="anatomy-of-an-extension">Anatomy of an Extension</h1>
<p>Just kidding, we’re not really waiting on them. They’ll catch up.</p>
<p>Chrome allows extensions to run code in a couple different contexts; one, called a <a href="http://developer.chrome.com/extensions/background_pages.html">background page</a> (or an <a href="http://developer.chrome.com/extensions/event_pages.html">event page</a>, depending on how you use it), allows you to run code in the background. Most often, this can simply be a script, instead of a full on HTML document. The source for ours is in <code>src/js/background.js</code>.</p>
<p>The event page in our extension is basically responsible for two things: opening the tab switcher when the user presses the extension’s keyboard shortcut, and responding to messages sent from the client (one for querying the list of currently open tabs and one for asking the extension to switch to a given tab). Since we’re focusing on React in this post, we’ll gloss over the details; check out <a href="https://github.com/BinaryMuse/chrome-fast-tab-switcher/blob/v1.0.1/src/js/background.js">the source</a> if you’re curious!</p>
<h1 id="the-client">The Client</h1>
<p><code>build/html/switcher.html</code> is the HTML document that serves as the front-end for our extension. It contains nothing but some styles, a few <code>script</code> tags to load some vendored libraries and our app, and a single empty <code>div</code> element with an ID.</p>
<gist data-id="7dc242ebd829c8ac0020" data-file="switcher.html"></gist>
<noscript><pre><code><!doctype html>
<title>Fast Tab Switcher</title>
<style>
/* ... */
</style>
<div id='switcher'></div>
<script src="../js/vendor/react-0.9.min.js"></script>
<script src='../js/client-bundle.js'></script>
</code></pre><div><small><em><a href="https://gist.github.com/7dc242ebd829c8ac0020">View Gist for <code>switcher.html</code> on GitHub</a></em></small></div></noscript>
<p>When the page loads, it runs our Browserified client bundle, the entry point of which is <code>src/js/client.jsx</code>. It’s quite simple:</p>
<gist data-id="7dc242ebd829c8ac0020" data-file="client.jsx"></gist>
<noscript><pre><code>var TabSwitcher = require('./client/tab_switcher.jsx');
React.renderComponent(<TabSwitcher />, document.getElementById('switcher'));
</code></pre><div><small><em><a href="https://gist.github.com/7dc242ebd829c8ac0020">View Gist for <code>client.jsx</code> on GitHub</a></em></small></div></noscript>
<p>All of our React components are exported via <code>module.exports</code> so we can require them for use in any parent components. Here, we’re simply asking React to render a top-level <code>TabSwitcher</code> component, attaching it to our <code>div</code>.</p>
<h2 id="the-tabswitcher">The TabSwitcher</h2>
<p>This is where it really gets interesting. Here’s what the <code>TabSwitcher</code> component looks like. I’ve left out a lot of the internals so we can focus on a high-level overview; <a href="https://github.com/BinaryMuse/chrome-fast-tab-switcher/blob/v1.0.1/src/js/client/tab_switcher.jsx">see the full source on GitHub</a>.</p>
<gist data-id="7dc242ebd829c8ac0020" data-file="tab_switcher_highlevel.jsx"></gist>
<noscript><pre><code>var TabSearchBox = require('./tab_search_box.jsx');
var TabList = require('./tab_list.jsx');
var StatusBar = require('./status_bar.jsx');
// TabSwitcher
module.exports = React.createClass({
getInitialState: function() {
return {
filter: '',
selected: null,
tabs: [],
searchAllWindows: false
};
},
componentDidMount: function() {
window.onblur = this.close;
this.refreshTabs();
},
render: function() {
return (
<div>
<TabSearchBox
filter={this.state.filter}
exit={this.close}
changeFilter={this.changeFilter}
activateSelected={this.activateSelected}
modifySelected={this.modifySelected} />
<TabList
tabs={this.filteredTabs()}
filter={this.state.filter}
selectedTab={this.getSelected()}
changeSelected={this.changeSelected}
activateSelected={this.activateSelected} />
<StatusBar
searchAllWindows={this.state.searchAllWindows}
changeSearchAllWindows={this.changeSearchAllWindows} />
</div>
);
},
// ...
});
</code></pre><div><small><em><a href="https://gist.github.com/7dc242ebd829c8ac0020">View Gist for <code>tab_switcher_highlevel.jsx</code> on GitHub</a></em></small></div></noscript>
<p>When the component boots, it runs <code>getInitialState</code> to—you guessed it!—get its initial state. We can then refer to this state throughout the component via <code>this.state</code> and modify it via <code>this.setState</code>. <code>componentDidMount</code> runs after the component is mounted to the DOM; <code>refreshTabs()</code> fills in pieces of the state with data from the server—er, from the extension’s event page—by making an asynchronous request and then calling <code>setState</code> with the results. Data is not “pushed” into the extension in any way; <code>refreshTabs</code> is called any time we need to get an updated list of tabs.</p>
<gist data-id="7dc242ebd829c8ac0020" data-file="tab_switcher_setstate.jsx"></gist>
<noscript><pre><code>// TabSwitcher
module.exports = React.createClass({
// ...
refreshTabs: function() {
tabBroker.query(this.state.searchAllWindows)
.then(function(tabs) {
this.setState({tabs: tabs, selected: null});
}.bind(this));
},
// ..
});
</code></pre><div><small><em><a href="https://gist.github.com/7dc242ebd829c8ac0020">View Gist for <code>tab_switcher_setstate.jsx</code> on GitHub</a></em></small></div></noscript>
<blockquote>
<p>Note: For all practical purposes, the phrases “data from the server” and “data from the extension’s event page” are interchangeable. We’re communicating with an extension via a special Chrome API, but the design would be sound if we were communicating over HTTP, websockets, etc.</p>
</blockquote>
<p>An important consideration in this design is that <code>TabSwitcher</code> is the <strong>only</strong> component in the hierarchy that contains any mutable state or any <code>this.setState</code> calls. Similarly, it contains no logic on how to render the UI; it delegates to a few sub-components for that.</p>
<p>The data each sub-component needs to display itself is passed to it through its properties—specifically, the <code>filter</code>, <code>tabs</code>, <code>selectedTab</code>, and <code>searchAllWindows</code> properties.</p>
<gist data-id="7dc242ebd829c8ac0020" data-file="tab_switcher_render.jsx"></gist>
<noscript><pre><code>// TabSwitcher
module.exports = React.createClass({
// ...
render: function() {
return (
<div>
<TabSearchBox
filter={this.state.filter}
exit={this.close}
changeFilter={this.changeFilter}
activateSelected={this.activateSelected}
modifySelected={this.modifySelected} />
<TabList
tabs={this.filteredTabs()}
filter={this.state.filter}
selectedTab={this.getSelected()}
changeSelected={this.changeSelected}
activateSelected={this.activateSelected} />
<StatusBar
searchAllWindows={this.state.searchAllWindows}
changeSearchAllWindows={this.changeSearchAllWindows} />
</div>
);
},
// ...
});
</code></pre><div><small><em><a href="https://gist.github.com/7dc242ebd829c8ac0020">View Gist for <code>tab_switcher_render.jsx</code> on GitHub</a></em></small></div></noscript>
<p>These properties are immutable; if a child component needs to change the application’s state due to user interaction, it uses the functions that are also passed in via its properties. This allows us to keep all the state changing logic in one place, while using the sub-components’ properties as a form of inversion of control. These passed-in methods, all of which exist on <code>TabSwitcher</code>, appropriately modify the application state and then React <em>re-renders the entire component tree in memory</em>, using intelligent diffing to only modify the browser’s DOM in places that actually need changing.</p>
<p><a href="/images/react_chrome_extension_diagram.png" target="_blank">
<img src="/images/react_chrome_extension_diagram.png" style="max-width: 100%" alt="Data Flow" />
</a></p>
<p><small><em>Data only flows from top to bottom. Only <code>TabSwitcher</code> contains any mutable state. Child components are passed functions they can call if they need the applications state to be modified.</em></small></p>
<h3 id="lets-take-a-closer-look">Let’s Take a Closer Look</h3>
<p>Let’s look at the data flow a bit more closely. As an example, let’s look at what happens when the user types something in the input box, indicating their desire to filter the list of tabs to ones that match their query.</p>
<p>First, in <a href="https://github.com/BinaryMuse/chrome-fast-tab-switcher/blob/v1.0.1/src/js/client/tab_search_box.jsx">the <code>TabSearchBox</code> component</a>, we have an <code>onChange</code> event listener that fires when the user changes the text.</p>
<gist data-id="7dc242ebd829c8ac0020" data-file="tab_search_box_eventflow.jsx"></gist>
<noscript><pre><code>// TabSearchBox
module.exports = React.createClass({
// ...
render: function() {
return (
<input type='text' ref='input' onChange={this.onChange} />
);
},
onChange: function(evt) {
if (event.target.value !== this.props.filter)
this.props.changeFilter(event.target.value);
},
// ...
});
</code></pre><div><small><em><a href="https://gist.github.com/7dc242ebd829c8ac0020">View Gist for <code>tab_search_box_eventflow.jsx</code> on GitHub</a></em></small></div></noscript>
<p>The change handler calls <code>this.props.changeFilter</code>—that is, the function passed to the component on its <code>changeFilter</code> property—passing in the new string value. It very specifically <em>doesn’t</em> directly modify any state. Also note that we don’t care where the <code>changeFilter</code> function came from or what it does—only that the component’s API specifies that it requires a function on the property named <code>changeFilter</code> that it can call when it wants to change the filter.</p>
<p>The function we passed to <code>TabSearchBox</code>’s <code>changeFilter</code> method was <code>this.changeFilter</code> up in <code>TabSwitcher</code>.</p>
<gist data-id="7dc242ebd829c8ac0020" data-file="tab_switcher_eventflow.jsx"></gist>
<noscript><pre><code>// TabSwitcher
module.exports = React.createClass({
// ...
changeFilter: function(newFilter) {
this.setState({filter: newFilter, selected: null});
},
// ..
});
</code></pre><div><small><em><a href="https://gist.github.com/7dc242ebd829c8ac0020">View Gist for <code>tab_switcher_eventflow.jsx</code> on GitHub</a></em></small></div></noscript>
<p><em>This</em> is where the state change happens; we set the filter to the string that was passed as a parameter, and reset the currently selected item to <code>null</code>.</p>
<p>Changes made to the state via <code>setState</code> trigger an in-memory “render” of the component tree by React, and the new values in the state automatically flow into the child components via their properties. If React detects the actual browser DOM is out of sync with this in-memory model, it then and <em>only</em> then performs the relatively slow DOM manipulation operations necessary to bring it up to date.</p>
<p>If you’re used to a framework with built-in two-way data binding, it can take a while to migrate your mindset to this style of decoupled components. The effort can be worth it, though; relationships between components are explicit and easy to reason about, and keeping all the state changes centralized minimizes the places you need to go digging when there are bugs.</p>
<p>In fact, if you look at the other components in the extension, you’ll notice they’re very short, and do very little; the most complex logic you’ll see is determining how to format a particular string, or which function to call based on which key the user pressed.</p>
<h1 id="conclusion">Conclusion</h1>
<p>I originally wrote this post detailing an evented system I used in this application. <a href="https://twitter.com/Vjeux">@Vjeux</a> tweeted that Facebook previously had a similar event-driven architecture, but found they introduced more bugs using an evented system than they did when they simply passed callbacks around. In addition, when a component can get instantiated in more than one place, you need to find a way to target the specific instances, or use separate buses.</p>
<blockquote>
<p>Vjeux: As always, it’s hard to give general advices. But the global bus was a major source of bugs for us. Callback based api isnt :)</p>
</blockquote>
<p>I switched out the event bus for property-based function references, and I have to say I do like the explicitness of it quite a bit better. Since I’ve kept all the state changing functions in the top-level component, there’s never a question about where the state is modified, and the explicit properties make it clear at a glance which parts of the API are exposed to child components. Check out <a href="https://github.com/BinaryMuse/chrome-fast-tab-switcher/commit/a64f9dbbfc1879470a3c0f3d81b12ed00fa13b6a">the commit that removed the event bus</a> if you’re curious to see what the change looked like.</p>
<p>Have you built anything using React? What patterns did you use? Share it with us in the comments!</p>
Introducing Planetary.js2013-12-31T04:38:00-08:00http://michelletilley.net/2013/12/31/introducting-planetaryjs<p>I’ve just released a new JavaScript library called <a href="http://planetaryjs.com">Planetary.js</a> to build cool interactive globes, like this one:</p>
<p><img src="/images/planetaryjs-quake.png" alt="Planetary.js: 2013 Earthquakes" title="Planetary.js: 2013 Earthquakes" /></p>
<p>(This is a screenshot of one of the demos; <a href="http://planetaryjs.com/examples/quake/index.html">check it out</a> on the site.)</p>
<p>Planetary.js is built on a plugin-based architecture, which means it’s easy to make it do whatever you want. Out of the box, it has plugins for loading <a href="https://github.com/mbostock/topojson">TopoJSON</a> data and drawing the Earth, drawing animated “pings” on the globe, and rotating and zooming the globe with a mouse.</p>
<p>Definitely <a href="http://planetaryjs.com">check out the web site</a>; there are several <a href="http://planetaryjs.com/examples/">cool demos</a> that you can take a look at, and <a href="http://planetaryjs.com/documentation/">the documentation</a> will get you up-and-running in no time. Head over to <a href="http://planetaryjs.com/download/">the download page</a> if you want to get started right away.</p>
Client-Side Applications with AngularJS2013-08-12T02:18:00-07:00http://michelletilley.net/2013/08/12/client-side-applications-with-angularjs<p>The <a href="/2011/04/18/give-your-javascript-a-coffee-infused-backbone.html">last time I wrote about client-side applications</a>, I demonstrated an application I had built using Backbone. Since then, I, like many others, have tried out many other libraries for building client-side applications with JavaScript. Recently, I’ve taken a strong liking to <a href="http://angularjs.org/">AngularJS</a> by Google. Let’s take a look at Angular by comparing the app I built last time with a version built using Angular.</p>
<p>The full source code for the application is <a href="https://github.com/BinaryMuse/wow-realm-status-angular">available on GitHub</a>, and the application is <a href="http://binarymuse.github.io/wow-realm-status-angular/">running on GitHub pages</a>. Just as in the Backbone example, this application is written in CoffeeScript.</p>
<h1 id="angularjs-basics">AngularJS Basics</h1>
<p>One of the core concepts in AngularJS is two-way data binding. This means that manipulating a variable controlled by Angular—for example, in a text box—will automatically update any other places that variable is bound. Here’s a very basic example: a text box that updates a value in the DOM as you type.</p>
<iframe width="100%" height="150" src="http://jsfiddle.net/BinaryMuse/HQ56V/embedded/html,result" allowfullscreen="allowfullscreen" frameborder="0"></iframe>
<p>AngularJS uses dirty-checking for data binding, meaning that you get to use plain ol’ JavaScript objects—POJSO’s, if you will—as your models. It also supports a robust dependency injection system, which aids in testing, and allows for the registration various application components, including controllers, services, and filters.</p>
<p>A full exploration of the Angular framework is beyond the scope of this post, so we’ll stick to the features I used in rebuilding the app.</p>
<h2 id="services">Services</h2>
<p>In Angular, services are where you put your business logic; you can liken them to models in a server-side MVC framework like Ruby on Rails, but are more generic. In our case, we’ve created two new services.</p>
<gist data-id="6207991" data-file="services.coffee"></gist>
<noscript><pre><code># The Realms service provides a function that takes a callback and
# calls it with an array of Realms from the Blizzard API.
app.factory 'Realms', ($http) ->
(cb) ->
url = "http://us.battle.net/api/wow/realm/status?jsonp=JSON_CALLBACK"
$http.jsonp(url).success (json) -> cb(json.realms)
# The hashChange service is a function that calls a passed-in callback
# every time the URL's hash changes with the new value of the hash.
app.factory 'hashChange', ($window, $rootScope) ->
(listener) ->
$window.onhashchange = ->
$rootScope.$apply ->
listener($window.location.hash?.substr(1) ? '')
# Invoke once immediately
listener($window.location.hash?.substr(1) ? '')
</code></pre><div><small><em><a href="https://gist.github.com/6207991">View Gist for <code>services.coffee</code> on GitHub</a></em></small></div></noscript>
<p><code>Realms</code>, which depends on <a href="http://docs.angularjs.org/api/ng.$http">the built-in <code>$http</code> service</a> (Angular’s built-in services begin with a dollar sign), simply defines a function that takes a callback, makes the JSONP request to the Blizzard API, and then calls the callback with the resulting data once complete. This replaces the <code>RealmList</code> collection from the Backbone app, and the <code>Realm</code> model from the Backbone app is replace with plain JavaScript objects from the API’s JSON response.</p>
<p><code>hashChange</code> simply watches for the URL’s hash to change and calls a provided function with its new value whenever it does. The call to the function is wrapped in <code>$rootScope.$apply</code>, which ensures that the function runs within the context of Angular’s dirty tracking. This is only necessary when dealing with asynchronous code that <em>isn’t</em> managed by AngularJS by default—for example, when dealing with native browser events or third-party jQuery plugins. This will replace the routing features from the Backbone app (AngularJS has a full-featured router, but we don’t use it for this app.)</p>
<p>Once registered, both services are available to other services and controllers in our application by name; we’ll see this in a moment when we define our controller.</p>
<h2 id="controllers">Controllers</h2>
<p>Controllers are the glue between your views and your models. User events on the DOM will generally trigger functions on a controller, which will then in turn manipulate some model. The change in the model will automatically be propagated back into the view via Angular’s two-way data binding.</p>
<p>I only defined one controller for this application; though the terminology is a little different, this will basically replace all three of the views we created in the Backbone application. The controller uses various dependencies, injected in at runtime, to manage the interaction between the user and the models. You can see the list of dependencies in the controller’s function definition:</p>
<pre><code>app.controller 'RealmsController', ($scope, $timeout, $window, Realms, hashChange) ->
</code></pre>
<p>We defined <code>Realms</code> and <code>hashChange</code> ourselves in the previous section; the other three variables, which start with a dollar sign, are provided to us by the framework:</p>
<ul>
<li><code>$scope</code> is an object that is shared between the controller and the view; any property attached to the scope is automatically available in the view. <code>$scope</code> is where we put all our models, so that they can be shown in the view. Every controller gets its own <code>$scope</code> variable.</li>
<li><code>$timeout</code> is a special version of JavaScript’s <code>setTimeout</code> that ensures that Angular’s dirty-checking is triggered in the asynchronous function, similar to the <code>$rootScope.$apply</code> trick we used in the <code>hashChange</code> callback.</li>
<li><code>$window</code> is a wrapper around the JavaScript <code>window</code> object, provided mostly for its ability to be easily mocked out in tests.</li>
</ul>
<gist data-id="6207991" data-file="controllers.coffee"></gist>
<noscript><pre><code># RealmsController is the only controller in the application, which fetches
# the realm list from the Realms service and displays them in a list.
app.controller 'RealmsController', ($scope, $timeout, $window, Realms, hashChange) ->
$scope.realms = []
$scope.search = ''
$scope.lastUpdate = null
# Any time the URL hash changes, update the `search` variable.
hashChange (value) ->
$scope.search = value
# Conversely, if the user types into the search box and updates
# the `search` value, represent the change in the URL.
$scope.updateHash = ->
$window.location.hash = $scope.search
# Updates the server list and schedules another update in 5 minutes
refresh = ->
$scope.loading = true
Realms (realms) ->
$scope.realms = realms
$scope.loading = false
$scope.lastUpdate = new Date()
$timeout(refresh, 60 * 5 * 1000)
# Trigger the initial data fetch from the API
refresh()
</code></pre><div><small><em><a href="https://gist.github.com/6207991">View Gist for <code>controllers.coffee</code> on GitHub</a></em></small></div></noscript>
<p>The controller itself sets up four values on the <code>$scope</code> object:</p>
<ul>
<li><code>realms</code> is an array of servers that we’ll eventually get from the JSONP API, but for now we initialize it as an empty array.</li>
<li><code>search</code> is the current search term, initialized to an empty string.</li>
<li><code>lastUpdate</code> holds the <code>Date</code> for the last time we got fresh data from the API; here we initialize it to null.</li>
<li><code>updateHash</code> is a function that, when called, will take the current value of the <code>search</code> scope variable and make sure the current URL shows it in its hash. This is defined on the scope because we will be accessing it from the view later.</li>
</ul>
<p>We then use our <code>hashChange</code> service to make sure that our <code>search</code> scope variable changes automatically when the URL’s hash changes. Finally, we create a local function called <code>refresh</code> that fetches new data from the API and schedules another update in five minutes. The refresh function uses the <code>Realms</code> service to fetch the data and set all the relevant data in its callback.</p>
<p>We then kick everything off by calling <code>refresh</code> once manually.</p>
<h2 id="views">Views</h2>
<p>In Angular, your views are described declaratively with HTML. This is perhaps the biggest difference between it and a framework like Backbone. The view not only lays out the template, but also declares the bindings between the HTML and the controller. Here’s our full application view, defined in one file.</p>
<gist data-id="6207991" data-file="view.html"></gist>
<noscript><pre><code><html>
<head>
<title>WoW Realm Status</title>
<script type='text/javascript' src='js/angular.js'></script>
<script type='text/javascript' src='js/app.js'></script>
<link rel="stylesheet" type="text/css" href="css/app.css" />
</head>
<body ng-app='wowRealmStatus'>
<a href='https://github.com/BinaryMuse/wow-realm-status-angular'>
<img id='forkme' src='images/forkme.png'>
</a>
<div id='main' class='ng-cloak' ng-cloak ng-controller='RealmsController'>
<p id='search'>
Search:
<input type='text' size='30' ng-model='search' ng-change='updateHash()'>
<span id='loading'>
<img ng-show='loading' alt='loading' src='images/loading.gif'>
</span>
</p>
<p id='time'>
Last updated:
<span ng-hide='lastUpdate'>never</span>
<span ng-show='lastUpdate'>{{lastUpdate | date:'MMM d, h:mm a'}}</span><br>
<em>Data updates every 5 minutes</em>
</p>
<p id='reset' ng-show='search'>
<a ng-href='#'>Show All</a>
</p>
<div ng-repeat="realm in realms | filter:{name:search}">
<h1><a ng-href='#{{realm.name}}'>{{realm.name}}</a>
({{realm.type | realmType}})</h1>
<p>
Status: {{realm.status | boolToString:'Up':'Down'}}<br>
Population: {{realm.population | capitalize}}<br>
Queue: {{realm.queue | boolToString:'Yes':'No'}}
</p>
</div>
</div>
</body>
</html>
</code></pre><div><small><em><a href="https://gist.github.com/6207991">View Gist for <code>view.html</code> on GitHub</a></em></small></div></noscript>
<p>Let’s break this down piece by piece.</p>
<gist data-id="6207991" data-file="view-body.html"></gist>
<noscript><pre><code><body ng-app='wowRealmStatus'>
<!-- ... -->
<div id='main' class='ng-cloak' ng-cloak ng-controller='RealmsController'>
</code></pre><div><small><em><a href="https://gist.github.com/6207991">View Gist for <code>view-body.html</code> on GitHub</a></em></small></div></noscript>
<p>Angular views are described using <em>directives</em>, which are usually manifested as special HTML attributes or elements. For example, the <code>ng-app</code> attribute on the <code>body</code> tag tells Angular to kick off the <code>wowRealmStatus</code> module on that section of the DOM; the <code>ng-controller</code> directive on the first <code>div</code> tag tells Angular to load up the <code>RealmsController</code> for that particular part of the page. Angular has <a href="http://docs.angularjs.org/api/">several useful built-in directives</a>; we’ll cover only the ones that drive out the functionality of our application here.</p>
<gist data-id="6207991" data-file="view-input.html"></gist>
<noscript><pre><code><p id='search'>
Search:
<input type='text' size='30' ng-model='search' ng-change='updateHash()'>
<span id='loading'>
<img ng-show='loading' alt='loading' src='images/loading.gif'>
</span>
</p>
</code></pre><div><small><em><a href="https://gist.github.com/6207991">View Gist for <code>view-input.html</code> on GitHub</a></em></small></div></noscript>
<p>First, notice that our search <code>input</code> has an <code>ng-model</code> directive on it. This tells Angular to bind the value of the text input to the <code>search</code> property on the view’s associated <code>$scope</code> (which, you may recall, is shared by the <code>RealmsController</code> we defined earlier). This means that every time the user types in the box, the <code>$scope.search</code> property in the controller is automatically updated; conversely, when <code>$scope.search</code> is updated in the controller, the value shown in the text box will automatically update.</p>
<p>There is also an <code>ng-change</code> attribute on the input; this tells Angular to call the given function every time the value in the input changes. In this case, it’s calling our <code>updateHash</code> function to ensure the URL is correct.</p>
<p>The image shown next to the input has an <code>ng-show</code> attribute on it; this ensures that the image is only visible if the expression passed to the attribute is true. In this case, we only show the loading spinner if the <code>loading</code> scope value is truthy, which we manage in our <code>refresh</code> function.</p>
<gist data-id="6207991" data-file="view-time.html"></gist>
<noscript><pre><code><p id='time'>
Last updated:
<span ng-hide='lastUpdate'>never</span>
<span ng-show='lastUpdate'>{{lastUpdate | date:'MMM d, h:mm a'}}</span><br>
<em>Data updates every 5 minutes</em>
</p>
</code></pre><div><small><em><a href="https://gist.github.com/6207991">View Gist for <code>view-time.html</code> on GitHub</a></em></small></div></noscript>
<p>The paragraph containing the last updated time is interesting; it shows one of two spans depending on if the <code>lastUpdate</code> scope value is truthy or not; if it is, we use Angular’s curly-brace-based string interpolation to show the date. The pipe <code>|</code> character invokes a filter, and it works just like pipes do on UNIX-like systems—the value <code>lastUpdate</code> is passed to a function called <code>date</code>; the string <code>'MMM d, h:mm a'</code> is passed as the second parameter to this function. In this case, we’re using <a href="http://docs.angularjs.org/api/ng.filter:date">the date filter</a>, and it returns the given date formatted by the specified string. Filters allow you to keep all your formatting-related logic in the view, where it’s easy to see what’s happening and compose multiple filters together in interesting ways.</p>
<gist data-id="6207991" data-file="view-reset.html"></gist>
<noscript><pre><code><p id='reset' ng-show='search'>
<a ng-href='#'>Show All</a>
</p>
</code></pre><div><small><em><a href="https://gist.github.com/6207991">View Gist for <code>view-reset.html</code> on GitHub</a></em></small></div></noscript>
<p>We then have a paragraph that is only shown if <code>search</code> is truthy (e.g., not an empty string). If it is, we see a link with the text “Show All” that uses the URL’s hash fragment to reset the search term to empty (remember our <code>hashChange</code> callback).</p>
<gist data-id="6207991" data-file="view-repeat.html"></gist>
<noscript><pre><code><div ng-repeat="realm in realms | filter:{name:search}">
<h1><a ng-href='#{{realm.name}}'>{{realm.name}}</a>
({{realm.type | realmType}})</h1>
<p>
Status: {{realm.status | boolToString:'Up':'Down'}}<br>
Population: {{realm.population | capitalize}}<br>
Queue: {{realm.queue | boolToString:'Yes':'No'}}
</p>
</div>
</code></pre><div><small><em><a href="https://gist.github.com/6207991">View Gist for <code>view-repeat.html</code> on GitHub</a></em></small></div></noscript>
<p>Finally, we get to the really interesting part. The final <code>div</code> tag has an attribute called <code>ng-repeat</code>. This causes the DOM element to be repeated for every element in an array or object. In this case, for every element in the <code>realms</code> scope property, we’re duplicating the <code>div</code> and assigning a new local scope variable called <code>realm</code> to the array value at the current iteration. Inside the <code>div</code>, we’re using curly-braces and filters (described in the next section) to show various pieces of information about each realm.</p>
<p>Additionally, the <code>ng-repeat</code> expression itself is being piped into a filter: the <code>filter</code> filter. In this case, we’re passing as a second argument an object literal, that says to filter out from the <code>realms</code> array any value that has a <code>name</code> property that doesn’t matche the current value of the <code>search</code> scope variable. In this way, we get search functionality for free!</p>
<h2 id="filters">Filters</h2>
<p>We mentioned filters briefly in the last section, when we said that filters are special functions you can invoke in your views via the pipe <code>|</code> operator, and that they look and behave much like you’d expect based on their behavior on UNIX-like systems. Here are the filters I defined for the app.</p>
<gist data-id="6207991" data-file="filters.coffee"></gist>
<noscript><pre><code># The realmType filter simply formats the raw `type` string provided by
# the Blizzard API so that it is presented nicely in the view.
app.filter 'realmType', ->
(type) ->
switch type
when 'pve' then "PvE"
when 'pvp' then "PvP"
when 'rp' then "RP"
when 'rppvp' then "RP PvP"
# The capitalize filter capitalizes the first character in a string.
app.filter 'capitalize', ->
(str) -> if str then str[0].toUpperCase() + str[1..-1].toLowerCase() else ""
# The boolToString filter returns the first string if the value is
# turthy and the second string otherwise.
app.filter 'boolToString', ->
(boolean, trueString, falseString) -> if boolean then trueString else falseString
</code></pre><div><small><em><a href="https://gist.github.com/6207991">View Gist for <code>filters.coffee</code> on GitHub</a></em></small></div></noscript>
<p>The comments on each filter describe what it does; notice that they only return new values, not manipulate existing data. Filters allow you to transform data in your view so that you don’t have to worry about data formatting in your controllers or services, and make it easy to see how your data is transformed at a glance in your views.</p>
<h1 id="in-conclusion">In Conclusion</h1>
<p>As you can see, the code for the Angular version of this app is quite short. The functionality is nicely encapsulated, and Angular’s data binding saves us a <em>lot</em> of boilerplate code that we’d normally have to write for view updates. You can check out <a href="https://github.com/BinaryMuse/wow-realm-status-angular">the code for this project on GitHub</a>, and the working implementation is <a href="http://binarymuse.github.io/wow-realm-status-angular/">up on GitHub pages</a>.</p>
<p>If you’re interested in a more advanced example, take a look at <a href="https://github.com/BinaryMuse/MovieKue">MovieKue</a>, which behaves more like a traditional single-page application. It’s still under development, but it’s feature-complete enough to garner useful information about writing a larger AngularJS app. (It also uses <a href="https://www.firebase.com/">Firebase</a>, a cool real-time database-in-the-cloud, which I recommend checking out.)</p>
<p>Overall, this was a whirlwind tour of the AngularJS framework. Be sure to <a href="http://angularjs.org/">check it out</a> if you’re interested. I hope you found this example and comparison to the <a href="http://brandontilley.com/2011/04/18/give-your-javascript-a-coffee-infused-backbone.html">Backbone version of the app</a> useful. Please let me know in the comments or <a href="http://brandontilley.com/contact.html">via email</a> if you have any questions!</p>
Controlling an Arduino from Node.js2012-03-02T07:08:00-08:00http://michelletilley.net/2012/03/02/controlling-an-arduino-from-nodejs<p>After expressing an interested in learning microcontroller programming, a friend of mine purchased for me an <a href="http://arduino.cc/en/Main/arduinoBoardDuemilanove">Arduino Duemilanove</a>, which arrived yesterday. Being someone who enjoys web programming, I of course wasted no time in figuring out how I could get it connected to a web page. I opted to use <a href="http://nodejs.org/">Node.js</a> for my integration.</p>
<p>To communicate with the microcontroller, I used <a href="https://github.com/voodootikigod/node-serialport">node-serialport</a>, which allows you to make a connection to a serial port for reading and writing. For this test, I wrote a sketch to turn the onboard LED on pin 13 off when a <code>0</code> is read from the serial connection, and to turn the LED on when a <code>1</code> is read. The contents of this sketch follows; just upload it to your Arduino.</p>
<gist data-id="1962067" data-file="00-sketch.c"></gist>
<noscript><pre><code>const int outputPin = 13;
void setup()
{
pinMode(outputPin, OUTPUT);
Serial.begin(9600);
}
void loop()
{
if (Serial.available() > 0) {
int incomingByte = Serial.read();
if (incomingByte == 0x01) {
digitalWrite(outputPin, HIGH);
} else if (incomingByte == 0x00) {
digitalWrite(outputPin, LOW);
}
}
}</code></pre><div><small><em><a href="https://gist.github.com/1962067">View Gist for <code>00-sketch.c</code> on GitHub</a></em></small></div></noscript>
<p>Next up, we need to send a <code>0</code> or <code>1</code> byte to the Arduino from Node; here’s a short CoffeeScript program that will blink the LED every second (I’ve hardcoded the device where my Arduino lives; substitute your own).</p>
<gist data-id="1962067" data-file="01-blink.coffee"></gist>
<noscript><pre><code>{SerialPort} = require('serialport')
fs = require 'fs'
port = '/dev/tty.usbserial-A600enDA'
serial = null
value = 0x00
toggle = =>
value = if value == 0x00 then 0x01 else 0x00
serial.write new Buffer([value])
console.log "Starting..."
fs.stat port, (err, stats) ->
if err?
console.log "Couldn't stat #{port}"
process.exit()
console.log "Started."
serial = new SerialPort port, baudrate: 9600
setInterval toggle, 1000</code></pre><div><small><em><a href="https://gist.github.com/1962067">View Gist for <code>01-blink.coffee</code> on GitHub</a></em></small></div></noscript>
<p>From here, it’s not difficult to adapt this example into a more complete sample including a web server. Here’s a complete listing of my program, including a web page to access at the root URL to control the LED using jQuery Ajax requests.</p>
<gist data-id="1962067" data-file="02-server.coffee"></gist>
<noscript><pre><code>{SerialPort} = require('serialport')
fs = require 'fs'
port = '/dev/tty.usbserial-A600enDA'
express = require 'express'
serial = null
interval = null
lightOn = false
turnOn = =>
lightOn = true
serial.write new Buffer([0x01])
turnOff = =>
lightOn = false
serial.write new Buffer([0x00])
toggle = =>
if lightOn
turnOff()
else
turnOn()
app = express.createServer()
app.get '/', (req, res) ->
res.sendfile 'index.htm'
app.get '/on', (req, res) ->
clearInterval interval
turnOn()
res.end()
app.get '/off', (req, res) ->
clearInterval interval
turnOff()
res.end()
app.get '/blink', (req, res) ->
clearInterval interval
interval = setInterval toggle, 500
res.end()
console.log "Starting..."
fs.stat port, (err, stats) ->
if err?
console.log "Couldn't stat #{port}"
process.exit()
console.log "Started."
serial = new SerialPort port, baudrate: 9600
app.listen(8080)</code></pre><div><small><em><a href="https://gist.github.com/1962067">View Gist for <code>02-server.coffee</code> on GitHub</a></em></small></div></noscript>
<gist data-id="1962067" data-file="03-index.htm"></gist>
<noscript><pre><code><html>
<head>
<title>Online Lightswitch</title>
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script>
$(function() {
$("#on").click(function() {
$.ajax('/on');
});
$("#off").click(function() {
$.ajax('/off');
});
$("#blink").click(function() {
$.ajax('/blink');
});
});
</script>
<style>
button {
font-size: 20pt;
}
</style>
</head>
<body>
<button id="on">On!</button>
<button id="off">Off!</button>
<button id="blink">Blink!</button>
</body>
</html></code></pre><div><small><em><a href="https://gist.github.com/1962067">View Gist for <code>03-index.htm</code> on GitHub</a></em></small></div></noscript>
<p>Start the server and visit <code>http://localhost:8080</code> and click the buttons to control the lights!</p>
Programmer Criticism2012-01-08T09:30:00-08:00http://michelletilley.net/2012/01/08/programmer-criticism<p>I stumbled across <a href="http://commandcenter.blogspot.com/2011/12/esmereldas-imagination.html">a very interesting post</a> today. The topic of conversation used to make the point is Go and Dart, but you may substitute them with almost any new technology or language and the article reads the same (which is much of the point).</p>
<blockquote>
<p>It was unnecessary to try Go or Dart before commenting publicly on them; in fact, it was important not to (for one thing, trying them would require programming). The criticisms were loud and vociferous but irrelevant because they weren’t about the languages at all. They were just a standard reaction to something new, empty of meaning, the result of a modern programmer’s need to complain about everything different.</p>
</blockquote>
<blockquote>
<p>…</p>
</blockquote>
<blockquote>
<p>A while after Go launched, the criticisms changed tenor somewhat. Some people had actually tried it, but there were still many complainers, including the one quoted above. The problem now was that imagination had failed: Go is a language for writing Go programs, not Java programs or Haskell programs or any other language’s programs. You need to think a different way to write good Go programs. But that takes time and effort, more than most will invest.</p>
</blockquote>
<p>I urge you to <a href="http://commandcenter.blogspot.com/2011/12/esmereldas-imagination.html">read the post for yourself</a>, but if you take nothing else away, how about the author’s closing statement:</p>
<blockquote>
<p>I resolve to recognize that a complaint reveals more about the complainer than the complained-about. Authority is won not by rants but by experience and insight, which require practice and imagination. And maybe some programming.</p>
</blockquote>
Socket.IO and the Latest Chrome2011-08-13T04:05:00-07:00http://michelletilley.net/2011/08/13/socket-io-and-the-latest-chrome<p>I spent some time this morning working on an issue, and when I discovered the problem, I thought I’d share my findings.</p>
<p>The issue is Socket.IO not working quite right on the latest Chrome build (definitely the latest dev build, and I’ve heard people are having issues with the latest stable build as well). Specifically, Socket.IO over WebSockets isn’t working. I received the following error:</p>
<pre><code>warn - websocket connection invalid
</code></pre>
<p>It turns out that this is because recent builds of Chrome <a href="http://googlechromereleases.blogspot.com/2011/07/chrome-dev-channel-release.html">implement a newer version of the WebSocket protocol</a>. Although the folks at Socket.IO are <a href="https://github.com/LearnBoost/socket.io/issues/429">working on a fix</a>, it’s still not quite ready.</p>
<p>Interestingly enough, I didn’t have this issue at work, where we’re running the latest dev build of Chrome; instead, I discovered it while working on the same project at home, where I’m running dev Chrome on Ubuntu, so YMMV.</p>
<p>In the meantime, for development purposes, I’ve simply set Socket.IO to only use AJAX long polling for my app while the issue is sorted out. You can do this in your server code with:</p>
<pre><code>socket.set('transports', ['xhr-polling']);
</code></pre>
<p>Happy coding!</p>
Give Your JavaScript a Coffee-Infused Backbone2011-04-18T00:55:00-07:00http://michelletilley.net/2011/04/18/give-your-javascript-a-coffee-infused-backbone<p>Recently I was working on a little <a href="https://github.com/BinaryMuse/wow-realm-status-js">demo web app</a> that involved completely client-side code. My JavaScript-fu is the weaker of my multi-lingual toolbox, although I’ve been working on it more recently (with more client-side experiments, such as this one, as well as projects in Node.js). Anyway, the first time through the code, I ended up with what was essentially <a href="https://github.com/BinaryMuse/wow-realm-status-js/blob/f34e70dbace182df4b3cc83fd2f9d663e3031123/js/app.js#files">a bunch of jQuery statements</a> strewn about. It worked, but it wasn’t really very pretty. I decided that it was time that I learn how to do something about it. I ended up with two neat tools: <strong>CoffeeScript</strong> and <strong>Backbone</strong>.</p>
<h1 id="coffeescript">CoffeeScript</h1>
<p><a href="http://jashkenas.github.com/coffee-script/">CoffeeScript</a> is “a little language that compiles into JavaScript.” It offers a syntax reminiscent of Ruby and a few other niceties that make writing JavaScript a lot easier and more fun (in my opinion).</p>
<p>I bring it up in this post because code samples later will utilize it. For the basics, check out <a href="http://jashkenas.github.com/coffee-script/#overview">the overview</a>—it should be plenty to allow you to grok the code in this post.</p>
<h1 id="backbone">Backbone</h1>
<p><a href="http://documentcloud.github.com/backbone/">Backbone.js</a> is the library that really helped bring shape to my code. It provides models, collections, views, routing and more. Your views respond to events in your models or collections to get stuff done. It even has “magic support” for jQuery, so you don’t have to write UI code without it.</p>
<p>While Backbone is a JavaScript application framework, it doesn’t include a widget library and other frills like several others. If you want to roll your own JavaScript but struggle to keep it in check, it might be what you need.</p>
<h2 id="my-app">My App</h2>
<p>My application was a <a href="http://binarymuse.github.io/wow-realm-status-js/">World of Warcraft server status page</a> designed to demonstrate some new API’s that Blizzard is providing. I wanted it to be able to show the current status of every server (fetched via JSONP and refreshed every five minutes) and I wanted the list to be searchable with an input box on the page. Let’s take a look at the various pieces of the app.</p>
<h2 id="realm-model">Realm Model</h2>
<p>First, I created a model for a single server (aka “realm”). This model holds the name of the realm, its type, current population, whether or not the server is running, and whether or not there is a queue to play on the server. (Although it’s not necessary to set defaults, as all poperties are set automatically from JSON later, I did so here.)</p>
<gist data-id="924755" data-file="realm_model.coffee"></gist>
<noscript><pre><code>window.Realm = Backbone.Model.extend
initialize: ->
# Only set default data if it doesn't already exist.
unless this.get("name")?
this.set
name: "unknown"
slug: "unknown"
type: "n/a"
population: "n/a"
queue: false
status: false
</code></pre><div><small><em><a href="https://gist.github.com/924755">View Gist for <code>realm_model.coffee</code> on GitHub</a></em></small></div></noscript>
<h2 id="realmlist-collection">RealmList Collection</h2>
<p>Next up, I created a collection to hold a list of models. It’s through this object that I fetch new data from the JSONP endpoint and update the models accordingly.</p>
<gist data-id="924755" data-file="realmlist_model.coffee"></gist>
<noscript><pre><code>window.RealmList = Backbone.Collection.extend
model: Realm
url: "http://us.battle.net/api/wow/realm/status?jsonp=?"
initialize: ->
_.bindAll this, 'update', 'parse', 'processUpdate', 'filter'
# After the first refresh, we no longer want to replace the models
# in the collection with new ones. Thus, we will use our own 'refresh'
# method which simply updates all the models with the new data.
this.bind 'refresh', ->
this.refresh = this.processUpdate
# A wrapper around fetch() to (1) fire a "loading" event and
# (2) ensure that a timer is set so another update happens in the future.
update: ->
this.trigger 'refresh:start' # Indicates data is being collected.
this.fetch()
window.setTimeout this.update, 1000 * 60 * 5 # update every 5 minutes
# Custom parse method (1) extracts the array from Blizzard's JSON API and
# (2) adds an "id" attribute to every model equal to that Realm's slug.
parse: (response) ->
_.each response.realms, (realm) ->
realm.id = realm.slug
this.trigger 'refresh:end' # Indicates data collection has ended.
response.realms
# Our replacement 'refresh' method, for every refresh after the first.
# Iterates over the models in the collection and updates each one's data.
processUpdate: (models, options) ->
list = this
_.each models, (model) ->
id = model.id
original_model = list.get(id)
original_model.set(model)
# Called by our controller when the hash tag changes.
# We simply fire an event indicating the term has changed, and any view
# that is interested will handle the work of hiding or showing elements.
filter: (term) ->
this.trigger 'filter:change', term</code></pre><div><small><em><a href="https://gist.github.com/924755">View Gist for <code>realmlist_model.coffee</code> on GitHub</a></em></small></div></noscript>
<p>I struggled with this for a little while, as Backbone is really designed to help where CRUD and REST are in heavy use. For example, a call to <code>RealmList.fetch()</code> replaces all the models it holds with new models rather than updating the old models. This wasn’t exactly what I wanted, and since I had to update the entire list of realms via JSONP every time, I did a bit of hackery to overide the collection’s <code>refresh</code> function <em>after</em> the initial download.</p>
<p>The other thing to note here is the <code>_.bindAll</code> method. This is an <a href="http://documentcloud.github.com/underscore/">Underscore.js</a> method (Backbone depends on Underscore) that ensures that anytime any of the named methods are invoked, they are called in the context of the current object (so <code>this</code> always refers to the object where the method lives).</p>
<h2 id="realm-view">Realm View</h2>
<p>Next up is the view for a single realm; that is, one instance of a server in the list.</p>
<gist data-id="924755" data-file="realm_view.coffee"></gist>
<noscript><pre><code>window.RealmView = Backbone.View.extend
tagName: "div"
template: _.template $("#realm_template").html()
initialize: ->
_.bindAll this, 'render', 'show', 'hide'
# Whenever the data changes, the view will automatically re-render itself.
this.model.bind 'change', this.render
this.model.view = this
# Render a single realm based on the template embedded in the HTML.
render: ->
$(this.el).html(this.template(this.model.toJSON()))
this
show: ->
$(this.el).show()
hide: ->
$(this.el).hide()</code></pre><div><small><em><a href="https://gist.github.com/924755">View Gist for <code>realm_view.coffee</code> on GitHub</a></em></small></div></noscript>
<p>Notice the call to <code>_.template</code> when defining the view’s template. This is another Underscore method; it compiles JavaScript templates into functions that can be used later for rendering by passing in a context object to fill in values. Here, I created a hidden <code>div</code> on the page, and read that HTML in to the template. In a larger app, I would probably use <a href="https://github.com/pvande/Milk">Milk</a> for rendering templates.</p>
<p>Also, it’s easy to miss the magic here; it’s really only one line:</p>
<pre><code>this.model.bind 'change', this.render
</code></pre>
<p>This line of code binds its model’s <code>change</code> event to the view’s <code>render</code> element; the end result is that the view will automatically re-render itself any time its model’s data changes.</p>
<h2 id="application-view">Application View</h2>
<p>Finally we get to the view for the application; while it’s a bit longer than the other objects, it’s actually relatively simple, mostly taking responsibility for binding various UI changes to events from the realm list.</p>
<gist data-id="924755" data-file="app_view.coffee"></gist>
<noscript><pre><code>window.AppView = Backbone.View.extend
el: $("#main")
events:
"keyup input": "search"
initialize: ->
_.bindAll this, 'addOne', 'addAll', 'search', 'initSearch', 'filter', 'startLoading', 'stopLoading', 'updateTime'
Realms.bind 'refresh', this.addAll
Realms.bind 'refresh:start', this.startLoading
Realms.bind 'refresh:end', this.stopLoading
Realms.bind 'refresh:end', this.updateTime
Realms.bind 'filter:change', this.filter
Realms.update()
this.initSearch()
# Add a single realm to the page.
addOne: (realm) ->
view = new RealmView(model: realm)
this.el.append view.render().el
# Add an entire list of realms to the page.
# Deletages to this.addOne.
addAll: ->
view = this
_.each Realms.models, (realm) ->
unless realm.view?
view.addOne realm
# Now that the initial data is shown, start the controller's routing.
Backbone.history.start()
# Called when the "keyup" event is fired from the input box.
# Sets the hash tag, which the controller picks up on and fires
# events to ask the app to filter based on the input.
search: ->
window.location.hash = this.$("input").val()
# Set the initial value of the search box to be whatever is in the URL.
initSearch: ->
this.$("input").val(window.location.hash.substring(1))
this.$("input").focus()
# Called when the realm list's filter:change event is triggered.
# Iterates over the realms to see if each matches the search value.
filter: (term) ->
this.$("input").val(term)
if term == ""
this.$("#reset").hide()
else
this.$("#reset").show()
Realms.each (realm) ->
if realm.get('name').startsWith(term)
realm.view.show()
else
realm.view.hide()
startLoading: ->
this.$("#loading img").show()
stopLoading: ->
this.$("#loading img").hide()
updateTime: ->
now = new Date
hours = now.getHours()
minutes = now.getMinutes()
seconds = now.getSeconds()
meridian = if hours < 12 then "AM" else "PM"
hours -= 12 if hours > 12
hours = 12 if hours == 0
minutes = "0#{minutes}" if minutes < 10
seconds = "0#{seconds}" if seconds < 10
this.$("#time span").text("#{hours}:#{minutes}:#{seconds} #{meridian}")</code></pre><div><small><em><a href="https://gist.github.com/924755">View Gist for <code>app_view.coffee</code> on GitHub</a></em></small></div></noscript>
<p>It’s also primary responsible for handling the search functionality for the app, iterating over the list of realms and checking to see if the name starts with the serch string, and hiding or showing the views accordingly. It does this when it receives the <code>filter:change</code> event fired from <code>RealmList.filter</code>. But how does that method know when to fire that event? The answer comes from our last object, the controller.</p>
<h2 id="controller">Controller</h2>
<p>The controller is analagous to the router in a traditional Rails app; it handles changes in the hash string. Here’s our controller:</p>
<gist data-id="924755" data-file="controller.coffee"></gist>
<noscript><pre><code>window.Controller = Backbone.Controller.extend
routes:
":realm": "realm"
# Match any string in the hash tag to be the name of a realm to search for.
realm: (realm)->
Realms.filter(realm)</code></pre><div><small><em><a href="https://gist.github.com/924755">View Gist for <code>controller.coffee</code> on GitHub</a></em></small></div></noscript>
<p>The controller simply takes any hash string and passes it on to the realm list, which then fires the necessary event so that the view does the filtering.</p>
<h1 id="in-conclusion">In Conclusion</h1>
<p>I hope this post has given you a glimpse into the power of Backbone (and the syntax of CoffeeScript). There’s a bit more code I didn’t go over (and parts of the code that I did show that I glossed over). Please feel free to take a look at the <a href="https://github.com/BinaryMuse/wow-realm-status-js/blob/gh-pages/js/app.coffee#files">complete CoffeeScript source</a> for the app; you can also find a <a href="https://github.com/BinaryMuse/wow-realm-status-js/blob/d05a70e3222700d28d8a5ff597b56859cc08428c/js/app.coffee">snapshot of the code</a> from the time I wrote this post, and you can check out the <a href="https://github.com/BinaryMuse/wow-realm-status-js">entire project’s source</a> if you’re interested). Don’t hesitate to comment here or shoot me an email if you have any questions.</p>
<p>It’s becoming incresingly apparent that JavaScript and other client-side technologies are where the real power is in modern web apps; be sure you leverage the tools necessary to keep your JavaScript just as clean and decoupled as your server-side code!</p>
Stack Overflow can Make You a Better Learner, Too2011-02-06T03:58:00-08:00http://michelletilley.net/2011/02/06/stack-overflow-can-make-you-a-better-learner-too<p>Jeff Atwood recently <a href="http://www.codinghorror.com/blog/2011/02/how-to-write-without-writing.html">posted on his blog</a>, Coding Horror, about how asking and answering questions on <a href="http://stackoverflow.com/">Stack Overflow</a>, the community-driven programmer question and answer site, can make you a better writer. It’s a good read with a good point, and I completely agree. However, over the past few weeks, as I’ve tried to be more engaged with Stack Overflow by finding questions that I can answer, I’ve learned something else: Stack Overflow can make you a better <em>learner</em>.</p>
<p>I usually only utilize Stack Overflow for asking questions when I feel I’ve hit a dead-end with Google–when I feel I’ve exhausted my other options and I <a href="http://stackoverflow.com/questions/2533892/running-a-java-daemon-with-a-gwt-front-end-served-by-embedded-jetty">just can’t find an answer to the problem I’m having</a>. In that way alone, I feel Stack Overflow has changed the way I look for answers to a problem. I tend to search for longer and in more ways before posting to Stack Overflow.</p>
<p>Recently, though, I’ve been learning a lot from <em>answering</em> questions. That sounds counter-intuitive, I know. How can you answer a question unless you already know the answer? And the answer, of course, is that you find it. That is where I feel Stack Overflow has helped me the most. By finding questions (usually related to topics I’m interested in) that I don’t know the answer to and finding the answer, I’ve learned new ways of finding answers. In particular, I’m much less intimidated than I used to be about <a href="http://stackoverflow.com/questions/4911191/preventing-paperclip-from-deleting-overwriting-attachments-on-update#4911386">reading source code written by other people</a>, which is an <em>excellent</em> way to learn about software.</p>
<p>The other way I feel Stack Overflow has changed the way I think is by exposing me to problems I wouldn’t necessarily come up against in my own day-to-day coding. People have a lot of potentially <a href="http://stackoverflow.com/search?q=weird+problem">weird problems</a> on Stack Overflow, and reading them and trying to come up with an answer expands my capabilities in ways that I otherwise would never have happened upon.</p>
<p>So even if the users with thousands of rep and super-detailed answers intimidate you a little, I recommend taking some time each day and trying to answer some questions for people on Stack Overflow. Who knows what you’ll learn?</p>
Gist Tag for Jekyll2011-01-30T23:58:00-08:00http://michelletilley.net/2011/01/30/gist-tag-for-jekyll<p>One of the many reasons I <a href="/2011/01/30/so-long-wordpress.html">moved away from WordPress</a> was to make it easier to support code-laden posts. <a href="https://gist.github.com/">Gists</a> have been a favored way of incorporating code into posts (and automatically keeping them up to date!), but WordPress didn’t show the <code><script></code> tag in its editor, making it difficult edit the document around them, especially in posts with several code sections.</p>
<p>While Jekyll makes it crazy-easy to insert the necessary tags into your documents, there’s still one small problem: people who read the posts in an RSS reader miss out on the code-goodness! Sure, you can toss a quick <code><noscript></code> in there with a link to the post or to the Gist, but that feels like cheating. So, I wrote a Fluid tag for Jekyll to take care of the problem:</p>
<gist data-id="803483" data-file="gist_tag.rb"></gist>
<noscript><pre><code>require 'cgi'
require 'digest/md5'
require 'net/https'
require 'uri'
module Jekyll
class GistTag < Liquid::Tag
def initialize(tag_name, text, token)
super
@text = text
@cache_disabled = false
@cache_folder = File.expand_path "../_gist_cache", File.dirname(__FILE__)
end
def render(context)
if parts = @text.match(/([\d]*) (.*)/)
gist, file = parts[1].strip, parts[2].strip
script_url = script_url_for gist, file
code = get_cached_gist(gist, file) || get_gist_from_web(gist, file)
html_output_for script_url, code
else
""
end
end
def html_output_for(script_url, code)
code = CGI.escapeHTML code
"<script src='#{script_url}'></script><noscript><pre><code>#{code}</code></pre></noscript>"
end
def script_url_for(gist_id, filename)
"https://gist.github.com/#{gist_id}.js?file=#{filename}"
end
def get_gist_url_for(gist, file)
"https://gist.github.com/raw/#{gist}/#{file}"
end
def cache(gist, file, data)
cache_file = get_cache_file_for gist, file
File.open(cache_file, "w") do |io|
io.write data
end
end
def get_cached_gist(gist, file)
return nil if @cache_disabled
cache_file = get_cache_file_for gist, file
File.read cache_file if File.exist? cache_file
end
def get_cache_file_for(gist, file)
bad_chars = /[^a-zA-Z0-9\-_.]/
gist = gist.gsub bad_chars, ''
file = file.gsub bad_chars, ''
md5 = Digest::MD5.hexdigest "#{gist}-#{file}"
File.join @cache_folder, "#{gist}-#{file}-#{md5}.cache"
end
def get_gist_from_web(gist, file)
gist_url = get_gist_url_for gist, file
raw_uri = URI.parse gist_url
https = Net::HTTP.new raw_uri.host, raw_uri.port
https.use_ssl = true
https.verify_mode = OpenSSL::SSL::VERIFY_NONE
request = Net::HTTP::Get.new raw_uri.request_uri
data = https.request request
data = data.body
cache gist, file, data unless @cache_disabled
data
end
end
class GistTagNoCache < GistTag
def initialize(tag_name, text, token)
super
@cache_disabled = true
end
end
end
Liquid::Template.register_tag('gist', Jekyll::GistTag)
Liquid::Template.register_tag('gistnocache', Jekyll::GistTagNoCache)
</code></pre><div><small><em><a href="https://gist.github.com/803483">View Gist for <code>gist_tag.rb</code> on GitHub</a></em></small></div></noscript>
<p>(The above Gist is being shown with the Gist tag; how very meta.)</p>
<p>The code takes a Fluid tag in the form of <code>{% gist gist-number file-name %}</code> and inserts the necessary <code><script></code> tags into the document to display the given file from the given Gist. However, it also downloads the raw form of the Gist and inserts it into a <code><noscript><pre><code></code> block. It also caches the contents of the Gist into the <code>_gist_cache</code> folder of your Jekyll site (which should be added to your <code>.gitignore</code> file, etc) to make future compiles faster.</p>
<p>If you are rapidly iterating over multiple commits in your gist, you can use the <code>gistnocache</code> tag; taking the form <code>{% gistnocache gist-number file-name %}</code>, this tag does the exact same thing but skips reading from or writing to the Gist cache. Once you’re happy with your Gist, you can change the <code>gistnocache</code> tag to a regular <code>gist</code> tag. Of course, there’s always the chance that you need to remove a specific cached Gist from the cache; in that case, the files in <code>_gist_cache</code> are named intelligently to help you locate the file you need to delete.</p>
<p>Overall, it seems to be working fairly well. I hope this is of some use to others! Please let me know in the comments to this post or the comments to the Gist if you have any problems or suggestions.</p>
So Long, WordPress2011-01-30T03:44:00-08:00http://michelletilley.net/2011/01/30/so-long-wordpress<p>WordPress has served me well for a long time. I’ve used it on multiple sites over the years. But I’ve found, lately, that it just feels big and bloated. I want something small, lean, and customizable. I want something that’ll let me focus on creating content and stay out of the way. That something is <a href="https://github.com/mojombo/jekyll">Jekyll</a>.</p>
<p>Jekyll brings, to my mind, several advantages:</p>
<h1 id="static-content">Static Content</h1>
<p>Jekyll is described by its creator as “<a href="http://tom.preston-werner.com/2008/11/17/blogging-like-a-hacker.html">blogging like a hacker</a>.” At it’s most basic level, Jekyll is a static site generator. It takes HTML, Markdown, Textile and others and compiles it into static HTML. That static HTML is then fit to be served and cached like any other HTML. No server-side processing required!</p>
<h1 id="simplicity">Simplicity</h1>
<p>Jekyll is beautiful and elegant in its simplicity. Write posts in your favorite text editor in your favorite format. Store them in your Git repository for built-in backup. Create branches as you work on future posts. And publishing is as easy as an rsync to your server of choice.</p>
<h1 id="flexibility">Flexibility</h1>
<p>Jekyll imposes very few rules on you. Any file with a <a href="https://github.com/mojombo/jekyll/wiki/yaml-front-matter">YAML front matter block</a> is processed by Jekyll, making it easy to provide RSS feeds and other “special” files. Jekyll’s <a href="http://www.liquidmarkup.org/">Liquid</a> layout provides plenty of flexibility without the gross (IMO) “<a href="http://codex.wordpress.org/The_Loop">WordPress Loop</a>”.</p>
<p>So, over the next few days or weeks, I’ll be moving some of the posts from my <a href="http://binarymuse.net/">old blog</a> over to this one. Be sure to <a href="/atom.xml">resubscribe to the feed</a>, as the URL has changed!</p>
Serving Rails Apps with RVM, Nginx, Unicorn and Upstart2011-01-29T13:49:00-08:00http://michelletilley.net/2011/01/29/serving-rails-apps-with-rvm-nginx-unicorn-and-upstart<p>Ever since reading <a href="https://github.com/blog/517-unicorn">GitHub’s blog post on Unicorn</a>, I’ve been interested in trying it out. This post will document the process I used to get Unicorn serving a Rails application behind Nginx, with RVM managing Ruby. If you’ve read GitHub’s post, some of the config will look very familiar. Ideally, though, you should be able to follow this post from start to finish and have a working setup going.</p>
<h1 id="introduction">Introduction</h1>
<p>I installed this setup on Ubuntu 10.04 LTS Server Edition, 64-bit. You should be able to follow along pretty well on any sane system; that being said, I do use Upstart to manage the services toward the end of the guide. If you don’t use Upstart, you will need to substitute in your own SysVinit scripts (or scripts for whatever you use instead).</p>
<p>In a few listings, I use curl with Gist URLs to fetch the contents of files; the contents of these files are shown below the shell commands, for reference.</p>
<h1 id="installing-rvm">Installing RVM</h1>
<p>Since we’ll use RVM to manage our Rubies and gemsets on the server, we’ll start with a server-wide install of RVM. We’ll start out by installing curl and git, if necessary, then RVM, and finally the other packages RVM asks us to install. (Be sure to pay attention to these; you can view them again via <code>rvm notes</code>. You may need to install additional packages for your distro of Linux or for the Rubies you wish to use). I’m using Ruby 1.9.2-p136 here.</p>
<p>We’ll also take care to add the current user to the ‘rvm’ group. Finally, we’ll create a user called ‘unicorn’ to own our test application, later.</p>
<gist data-id="802568" data-file="00_rvm.sh"></gist>
<noscript><pre><code># Install RVM and dependencies
sudo aptitude install curl git-core
sudo bash < <( curl -L http://bit.ly/rvm-install-system-wide )
sudo aptitude install build-essential bison openssl libreadline6 libreadline6-dev curl git-core zlib1g zlib1g-dev libssl-dev libyaml-dev libsqlite3-0 libsqlite3-dev sqlite3 libxml2-dev libxslt-dev autoconf libc6-dev
sudo adduser `whoami` rvm
echo 'source /usr/local/lib/rvm' >> ~/.bashrc
# Set up users and groups
sudo useradd --home /var/www --create-home --groups rvm unicorn && sudo chmod g+w /var/www
sudo adduser `whoami` unicorn
#
# >> Log out and back in to SSH, open a new shell, etc. -- something to reload your environment
#
# Install Ruby 1.9.2-p136 and make it default
rvm install ruby-1.9.2-p136
# Make a sandwich while you wait (or have someone make you one: http://xkcd.com/149/)
rvm use ruby-1.9.2-p136 --default</code></pre><div><small><em><a href="https://gist.github.com/802568">View Gist for <code>00_rvm.sh</code> on GitHub</a></em></small></div></noscript>
<h1 id="installing-and-configuring-nginx">Installing and Configuring Nginx</h1>
<p>For simplicity’s sake, we’ll be using Nginx from APT. To make sure we’re up to date, we’ll use Nginx’s PPA.</p>
<p>You can see in the configuration file that I’ve jumped the gun and included the location of the shared socket we’ll use with our Unicorn application.</p>
<gist data-id="802568" data-file="01_nginx.sh"></gist>
<noscript><pre><code># Install Nginx
sudo bash -c 'echo "deb http://ppa.launchpad.net/nginx/stable/ubuntu $(lsb_release -cs) main" > /etc/apt/sources.list.d/nginx-stable-$(lsb_release -cs).list'
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys C300EE8C && sudo aptitude update
sudo aptitude install nginx
sudo bash -c 'curl -L https://gist.github.com/raw/802568/3a62636146eb2615cf42081b2574e8602d199658/nginx.conf > /etc/nginx/nginx.conf'</code></pre><div><small><em><a href="https://gist.github.com/802568">View Gist for <code>01_nginx.sh</code> on GitHub</a></em></small></div></noscript>
<p><code>/etc/nginx/nginx.conf</code>:</p>
<gist data-id="802568" data-file="etc_nginx.conf"></gist>
<noscript><pre><code>worker_processes 1;
user www-data www-data;
pid /tmp/nginx.pid;
error_log /tmp/nginx.error.log;
events {
worker_connections 1024;
accept_mutex off;
}
http {
include mime.types;
default_type application/octet-stream;
access_log /tmp/nginx.access.log combined;
sendfile on;
tcp_nopush on;
tcp_nodelay off;
gzip on;
gzip_http_version 1.0;
gzip_proxied any;
gzip_min_length 500;
gzip_disable "MSIE [1-6]\.";
gzip_types text/plain text/html text/xml text/css
text/comma-separated-values
text/javascript application/x-javascript
application/atom+xml;
upstream unicorn_test {
server unix:/var/www/test_app/tmp/sockets/unicorn.sock fail_timeout=0;
}
server {
listen 80;
client_max_body_size 4G;
server_name _;
keepalive_timeout 5;
root /var/www/test_app/public;
location / {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
if (!-f $request_filename) {
proxy_pass http://unicorn_test;
break;
}
}
error_page 500 502 503 504 /500.html;
location = /500.html {
root /var/www/test_app/public;
}
}
}</code></pre><div><small><em><a href="https://gist.github.com/802568">View Gist for <code>etc_nginx.conf</code> on GitHub</a></em></small></div></noscript>
<h1 id="configuring-upstart-for-nginx">Configuring Upstart for Nginx</h1>
<p>If you don’t use Upstart, or you don’t want to use Upstart, feel free to skip this section. By default, you can start Nginx with <code>sudo /etc/init.d/nginx start</code>.</p>
<gist data-id="802568" data-file="02_nginx_upstart.sh"></gist>
<noscript><pre><code>sudo rm /etc/init.d/nginx
for file in $(ls /etc/rc*/*nginx); do sudo rm $file; done
sudo bash -c 'curl -L https://gist.github.com/raw/802568/e210f8754abdf137027daeb4c41db8cc301b36ad/nginx.conf > /etc/init/nginx.conf'
sudo start nginx</code></pre><div><small><em><a href="https://gist.github.com/802568">View Gist for <code>02_nginx_upstart.sh</code> on GitHub</a></em></small></div></noscript>
<p><code>/etc/init/nginx.conf</code>:</p>
<gist data-id="802568" data-file="init_nginx.conf"></gist>
<noscript><pre><code>description "nginx http daemon"
start on runlevel [2]
stop on runlevel [016]
console owner
exec /usr/sbin/nginx -c /etc/nginx/nginx.conf -g "daemon off;"
respawn</code></pre><div><small><em><a href="https://gist.github.com/802568">View Gist for <code>init_nginx.conf</code> on GitHub</a></em></small></div></noscript>
<h1 id="creating-a-sample-rails-application">Creating a Sample Rails Application</h1>
<p>Now we’ll create a test Rails application in /var/www/test_app. We’ll use a gemset called rails_app to demonstrate Unicorn’s ability to figure out which gemset it should use for our application (for more details on this, check out step four in <a href="/2011/01/29/rvm-unicorn-and-upstart.html">my earlier post on Unicorn and Upstart</a>). For this to work, we’ll also create an RVM wrapper for Unicorn. And, of course, don’t forget your config/unicorn.rb file.</p>
<p>Again, we’ll use Upstart to start and manage our Unicorn process, but you can use whatever you’d like. If you just want to test it out, try running <code>unicorn -c /var/www/test_app/config/unicorn.rb</code> from the ‘global’ gemset.</p>
<gist data-id="802568" data-file="03_sample_app.sh"></gist>
<noscript><pre><code># Install Unicorn in the global gemset, and create a wrapper (yo yo yo in the hooouuuuuse!?)
rvm use ruby-1.9.2-p136@global
gem install unicorn --no-ri --no-rdoc
rvm wrapper ruby-1.9.2-p136 r192 unicorn
# Create and switch to a new gemset
rvm gemset create rails_app && rvm gemset use rails_app
gem install rails --no-ri --no-rdoc
# Create a sample Rails application
cd /var/www
rails new test_app
echo 'rvm use ruby-1.9.2-p136@rails_app --create' > test_app/.rvmrc
cd test_app
#
# >> Accept the .rvmrc warning
#
echo "gem 'unicorn'" >> Gemfile && bundle install
curl -L https://gist.github.com/raw/802568/998ac7c702e43d600f94fc3ee63ea05179315a0d/unicorn.rb > config/unicorn.rb
sudo bash -c 'curl -L https://gist.github.com/raw/802568/ee3f5f320c34ec2e1d1b55521776d7dccd9140d4/test_app.conf > /etc/init/test_app.conf'
sudo start test_app</code></pre><div><small><em><a href="https://gist.github.com/802568">View Gist for <code>03_sample_app.sh</code> on GitHub</a></em></small></div></noscript>
<p><code>/etc/init/test_app.conf</code>:</p>
<gist data-id="802568" data-file="test_app.conf"></gist>
<noscript><pre><code>description "Test rails application"
start on runlevel [2]
stop on runlevel [016]
console owner
exec /usr/local/rvm/bin/r192_unicorn -c /var/www/test_app/config/unicorn.rb
respawn</code></pre><div><small><em><a href="https://gist.github.com/802568">View Gist for <code>test_app.conf</code> on GitHub</a></em></small></div></noscript>
<p><code>/var/www/test_app/config/unicorn.rb</code>:</p>
<gist data-id="802568" data-file="unicorn.rb"></gist>
<noscript><pre><code>APP_ROOT = File.expand_path(File.dirname(File.dirname(__FILE__)))
if ENV['MY_RUBY_HOME'] && ENV['MY_RUBY_HOME'].include?('rvm')
begin
rvm_path = File.dirname(File.dirname(ENV['MY_RUBY_HOME']))
rvm_lib_path = File.join(rvm_path, 'lib')
$LOAD_PATH.unshift rvm_lib_path
require 'rvm'
RVM.use_from_path! APP_ROOT
rescue LoadError
raise "RVM ruby lib is currently unavailable."
end
end
ENV['BUNDLE_GEMFILE'] = File.expand_path('../Gemfile', File.dirname(__FILE__))
require 'bundler/setup'
worker_processes 4
working_directory APP_ROOT
preload_app true
timeout 30
listen APP_ROOT + "/tmp/sockets/unicorn.sock", :backlog => 64
pid APP_ROOT + "/tmp/pids/unicorn.pid"
stderr_path APP_ROOT + "/log/unicorn.stderr.log"
stdout_path APP_ROOT + "/log/unicorn.stdout.log"
before_fork do |server, worker|
defined?(ActiveRecord::Base) && ActiveRecord::Base.connection.disconnect!
old_pid = RAILS_ROOT + '/tmp/pids/unicorn.pid.oldbin'
if File.exists?(old_pid) && server.pid != old_pid
begin
Process.kill("QUIT", File.read(old_pid).to_i)
rescue Errno::ENOENT, Errno::ESRCH
puts "Old master alerady dead"
end
end
end
after_fork do |server, worker|
defined?(ActiveRecord::Base) && ActiveRecord::Base.establish_connection
end</code></pre><div><small><em><a href="https://gist.github.com/802568">View Gist for <code>unicorn.rb</code> on GitHub</a></em></small></div></noscript>
<h1 id="profit">Profit!</h1>
<p>And that’s that! Upstart will manage both Nginx and Unicorn (although either could benefit from something like Monit or God, but I’ll leave that as an exercise for the reader and/or a future blog post).</p>
RVM, Unicorn and Upstart2011-01-29T07:01:00-08:00http://michelletilley.net/2011/01/29/rvm-unicorn-and-upstart<p>I had a heck of a time this week trying to figure out how to get Upstart to start an instance of Unicorn due to the fact that Ruby was being managed with RVM. I finally realized I had been going about it the wrong way, and that RVM provided the tool that I needed: wrapper scripts. I opted to use a single wrapper script for the version of Ruby I was running, and to let Unicorn decide what gemset to use based on the .rvmrc file in the project. Here’s the whole process:</p>
<p><strong>Step 1: Make sure Unicorn is installed in the global gemset</strong></p>
<pre><code>rvm use ruby-1.9.2-p136@global
gem install unicorn
</code></pre>
<p><strong>Step 2: Create a wrapper script for Unicorn</strong></p>
<pre><code>rvm wrapper ruby-1.9.2-p136 r192 unicorn
</code></pre>
<p><strong>Step 3: Modify your Upstart configuration file’s “exec” line</strong></p>
<pre><code>exec /usr/local/rvm/bin/r192_unicorn -c /path/to/app/config/unicorn.rb
</code></pre>
<p><strong>Step 4: Modify your config/unicorn.rb file</strong></p>
<p>Use the following code at the top of your unicorn.rb file to tell Unicorn to set up the environment based on the .rvmrc file in the root of the project:</p>
<pre><code>if ENV['MY_RUBY_HOME'] && ENV['MY_RUBY_HOME'].include?('rvm')
begin
rvm_path = File.dirname(File.dirname(ENV['MY_RUBY_HOME']))
rvm_lib_path = File.join(rvm_path, 'lib')
$LOAD_PATH.unshift rvm_lib_path
require 'rvm'
RVM.use_from_path! File.dirname(File.dirname(__FILE__))
rescue LoadError
raise "The RVM Ruby library is not available."
end
end
ENV['BUNDLE_GEMFILE'] = File.expand_path('../Gemfile', File.dirname(__FILE__))
require 'bundler/setup'
</code></pre>
<p><strong>Step 5: Start your service</strong></p>
<p>Now you should be able to start your Unicorn app via <code>sudo service start appname</code>.</p>
git diff with Color in the Browser2010-09-25T06:22:00-07:00http://michelletilley.net/2010/09/25/git-diff-with-color-in-the-browser<p>If you’re anything like me (I feel sorry for you), then you use git diff pretty heavily. I like making sure I’m definitely committing what I think I’m committing, and I also like to verify my indentation, trailing whitespace, line endings, and so on are correct before I commit. I don’t tend to use many GUI tools for Git, so I end up paging through terminal output. While this works fine, I’ve discovered a solution I like more.</p>
<p>It involves <a href="http://rtomayko.github.com/bcat/">Ryan Tomayko’s bcat</a>, which is a pipe-to-browser utility. Since it supports ANSI/VT100 escape sequences, we even get nice color formatting. After <a href="http://github.com/rtomayko/bcat/blob/master/INSTALLING#files">installing</a> bcat, our options are two-fold for using it with Git:</p>
<p><strong>1. Pipe output to bcat</strong></p>
<p>If you only want to use bcat from time to time, you can easily pipe ouptut from a Git command to bcat:</p>
<pre><code>git diff | bcat
</code></pre>
<p>To get color, specify it as an option to git diff:</p>
<pre><code>git diff --color | bcat
</code></pre>
<p><strong>2. Set bcat as Git’s pager</strong></p>
<p>If you want to use bcat for every operation Git sends to your pager, try the following:</p>
<pre><code>export GIT_PAGER=bcat
git diff
git log
git log --oneline --decorate
</code></pre>
<p>And there you have it! Easy reviewing if your diffs in your browser. Be sure to check out the other examples on bcat’s homepage for some really neat uses!</p>
GWT-Wizard: A Wizard Widget for Your Project2010-04-22T12:51:00-07:00http://michelletilley.net/2010/04/22/gwt-wizard-a-wizard-widget-for-your-project<p>I thought I would take a quick moment to preset <a href="http://gwt-wizard.binarymuse.net/">GWT-Wizard</a>, a wizard widget I designed for GWT.</p>
<p><img src="/images/gwt-wizard-sample.png" alt="GWT-Wizard" title="GWT-Wizard" /></p>
<p>GWT-Wizard is very configurable, allowing you to customize everything about the Wizard–down to creating your own custom view to plug into the widget–but also comes with a set of sane defaults that allow you to get up and running quickly. If you’re interested, <a href="https://github.com/BinaryMuse/gwt-wizard">check it out on GitHub</a>. I have a hard time sometimes with over thinking and over planning things, so I’m trying to get code out to the open source community more. The project is still very young, but I’m using the widget in a production system for one of my projects, and I feel the codebase offers enough to be useful now.</p>
<p>If you have any comments or questions, or are using this widget in production somewhere, I’d be very interested to hear about it!</p>
Serving a GWT Application with an Embedded Jetty Server2010-03-27T04:12:00-07:00http://michelletilley.net/2010/03/27/serving-a-gwt-application-with-an-embedded-jetty-server<p>For a new project I am interested in starting, I want to serve a GWT application with an embedded Jetty server. I wasn’t sure how to go about doing so, but it turns out it’s easier than I could ever have expected! Check it out below.</p>
<gist data-id="346622" data-file="EmbeddedGwt.java"></gist>
<noscript><pre><code>package net.binarymuse.EmbeddedGwt;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.util.thread.QueuedThreadPool;
import org.eclipse.jetty.webapp.WebAppContext;
public class EmbeddedGwt {
public static void main(String[] args) throws Throwable {
// Create an embedded Jetty server on port 8080
Server server = new Server(8080);
// Create a handler for processing our GWT app
WebAppContext handler = new WebAppContext();
handler.setContextPath("/");
handler.setWar("./apps/GwtApplication.war");
// If your app isn't packaged into a WAR, you can do this instead
WebAppContext altHandler = new WebAppContext();
altHandler.setResourceBase("./apps/GwtApplication");
altHandler.setDescriptor("./apps/GwtApplication/WEB-INF/web.xml");
altHandler.setContextPath("/");
altHandler.setParentLoaderPriority(true);
// Add it to the server
server.setHandler(handler);
// Other misc. options
server.setThreadPool(new QueuedThreadPool(20));
// And start it up
server.start();
server.join();
}
}</code></pre><div><small><em><a href="https://gist.github.com/346622">View Gist for <code>EmbeddedGwt.java</code> on GitHub</a></em></small></div></noscript>
<p>You do, of course, need the <a href="http://download.eclipse.org/jetty/">Jetty jars</a> (I used the ones from the ‘lib’ folder in the Jetty distribution) in your classpath.</p>
Engineer Thinking and the Art of Software Engineering2010-03-12T02:06:00-08:00http://michelletilley.net/2010/03/12/engineer-thinking-and-the-art-of-software-engineering<p><a href="http://mattgemmell.com/2010/03/09/engineer-thinking">Matt Gemmell brings up an interesting point</a> in a recent blog post regarding user choice and defaults in software design.</p>
<blockquote>
<p>But a problem arises when you allow precision-based design principles to hinder user experience. All too often, when faced with a decision about how to implement certain functionality, engineers take the extreme position that:</p>
</blockquote>
<blockquote>
<ol>
<li>A feature must be exactly what 100% of users want.</li>
<li>If the above isn’t true (and it almost never is), the feature must be configurable.</li>
</ol>
</blockquote>
<blockquote>
<p>This binary approach is gravely wrong, and unjustly offloads decision-making onto the user of the software. We’ve all seen where this approach ends up: multi-row sets of tabs, scrolling panes of checkboxes, nested radio-buttons and a general overload of configuration.</p>
</blockquote>
<p>He goes on to talk about technical complexity and the responsibility of software to “mask uncertainty and to make the effort to provide a sensible default behavior.” However, as the post progresses, it evolves into an article that talks about the art of software engineering. One paragraph in particular really stood out to me:</p>
<blockquote>
<p>It all comes down to a question of art. Our art (that of software engineering) is not in making it work. If you see it as a significant success that you managed to name some methods, or write code that compiles and runs (or implemented a heap sort, or found the bounding box for a set of points, or parsed some XML), then your career goals are low indeed. Anyone in this industry can do that stuff, including any reasonably proficient final-year undergraduate in Computing Science. That’s core-skillset, vocational learning. You’re not aiming high enough.</p>
</blockquote>
<p>This got me to thinking: how often do I put ultimate importance on making something work? I’ve always been a proponent of attention to details and good UI design, but I’ve certainly been guilty of, as Matt puts it, setting my career goals too low. Something to think about.</p>
Current Working Git or SVN Branch on the Prompt2010-02-22T08:36:00-08:00http://michelletilley.net/2010/02/22/current-working-git-or-snv-branch-on-the-prompt<p>This is a nifty tip I picked up somewhere on the Internet to show the Git or Subversion branch you are currently working in on the command line prompt, which I modified to include your stash level. I haven’t done a ton of serious programming under Subversion, but I know with Git I’m branching all the time (<a href="http://whygitisbetterthanx.com/#cheap-local-branching">branches are so cheap in Git</a>!). I wasn’t sure if I’d like the results before I tried it, but as it turns out, it’s even more helpful than I thought it’d be.</p>
<p>Edit your <code>~/.bash_profile</code> to mirror the following functions. Of course, you may change the details of PS1 to your liking; it’s the <code>\$(parse_git_branch)\$(parse_svn_branch)</code> that’s important.</p>
<gist data-id="447949" data-file="DND (blog): git on prompt.sh"></gist>
<noscript><pre><code>parse_git_branch() {
git branch 2> /dev/null | sed -e '/^[^*]/d' -e "s/* \(.*\)/ (\1$(parse_git_stash))/"
}
parse_git_stash() {
git stash list 2> /dev/null | wc -l | sed -e "s/ *\([0-9]*\)/\ \+\1/g" | sed -e "s/ \+0//"
}
parse_svn_branch() {
parse_svn_url | sed -e 's#^'"$(parse_svn_repository_root)"'##g' | awk -F / '{print " ("$1 "/" $2 ")"}'
}
parse_svn_url() {
svn info 2>/dev/null | grep -e '^URL*' | sed -e 's#^URL: *\(.*\)#\1#g '
}
parse_svn_repository_root() {
svn info 2>/dev/null | grep -e '^Repository Root:*' | sed -e 's#^Repository Root: *\(.*\)#\1\/#g '
}
export PS1="[\u \w\$(parse_git_branch)\$(parse_svn_branch)]: "</code></pre><div><small><em><a href="https://gist.github.com/447949">View Gist for <code>DND (blog): git on prompt.sh</code> on GitHub</a></em></small></div></noscript>
<p>And what you end up with looks like (in this particular case):</p>
<p><code>[BinaryMuse ~/repo.git/src (FIX-15013 +2)]:</code></p>
<p>Enjoy!</p>