Inlay Process Pictoral - The Ottoman Tray

Posted on June 30, 2008 by The Wood Whisperer.
Categories: Contributors, Woodworking.

I’ve been getting a bunch of requests lately for a video on my decorative inlay process. This is definitely on our 2008 to-do list. But until then, I decided to resurrect an old WWA forum post from 2005. Enjoy.

The project is an ottoman tray. It will be a simple piece of 3/4 maple ply with a substantial solid padauk border. The inlay, is a simple interpretation of the sun. So here we go. It all starts with your design. Draw it out exactly how you want it to appear. It helps to have center-line and reference marks as they will make your life easier when it comes time to keep things aligned. Next, position your drawing over the substrate and tape one side in position. Now you can slide in a piece of carbon paper. Simply trace your design thereby transferring it to the substrate. For this design, the reference marks aren’t all that critical since I only need to transfer my design to the substrate once. But if you are doing a more complex design like one of my leaves, you will be re-tracing the design several times. Reference marks are then imperative.

If you havn’t already done so, you want to prepare your inlay stock at this point. I milled up few pieces of padauk for the large spikes and canarywood for the small spikes and the body of the sun. I like to aim for 1/16?-1/8? thickness for my stock. My drum sander belt is broken so these are a bit larger than I was shooting for. Since I have repeated geometric shapes, my next step was to make a template for each piece out of 1/4? ply. I simply used the carbon paper to trace the design onto the ply and cut it at the bandsaw.
Then I finessed the edges with sandpaper. If I were doing a leaf design, I would just trace my design directly to my inlay material and cut it out at the bandsaw or scroll saw. So now I use my templates to make my actual inlay pieces. I double-stick taped the template to my inlay stock, rough cut them on the bandsaw, then flush-trimmed them at the router table. These pieces are awefully small to rout, but with the proper precautions, it is possible. Any spots that send up the caution flags were touched up using sandpaper. Then I quickly cut the cararywood into a half circle using a quick rig at the bandsaw.

Now comes the fun part. This part of the process is exactly the same whether you are doing straight lines, geometric shapes, or complex designs. Start by double stick taping the piece to be inlayed into the substrate. Notice that the spikes are being done before the circle. This is because I want to circle to overlap the spikes. If I did it the other way, the continuity of the circle would be ruined. This concept is very important when creating the illusion of depth. The next few steps require a steady hand and patience. Lay off the coffee for a few hours. Or if you like a challenge, drink three cups before you start like I did. With an X-acto knife, carefully trace the outline of the inlay piece. Don’t rush this part. Start with a light touch just severing the top fibers. After a few passes you can increase the pressure and you will have a nice sharp outline.

Once the entire piece is outlined, carefully remove it with a putty knife. Now we need to make that outline a bit more visible. Simply grab your pencil and trace around the outline. Its ok to be sloppy. Then erase the line using strokes perpendicular to the outline. This will make sure the pencil residue gets loaded into the cut while cleaning the rest of the marks.

Now its time to do the routing. I generally use two bits. I hog out the material with a decent sized straight bit. Then I sneak up on the line with a 1/16? bit. Yes, its THAT small!!! Set the router to cut just a bit shy of the thickness of the inlay material, strap on your helmet, and pray for mercy. A critical tool in this process is the hands-free magnifier. With good lighting, they are worth their weight in gold. Which is probably about $20. Coincidentally that is how much they cost.

Now unfortunately, no picture can do this part justice. With the 1/16? bit, you really need to be careful when sneaking up to your line. I usually lock the router in the on position and put both hands on the base of the router. This gives me exceptional control. If you aren’t comfortable with this type of maneuver, then don’t do it. But I can’t think of any other way to get the control I need. A key point here is to watch the tearout of the router bit as you approach your line. The cool part is that as you sneak up to the line the little tearouts are clearly evident. But as soon as you kiss the line, the tearouts fly out leaving a nice clean line. That’s how you know you are there. Pre-cutting with the X-acto knife is what makes this possible.

Once the routing is complete, its time to test the fit. The piece will rarely drop right in. Usually the recess needs a bit of work. I use the X-acto knife and a chisel to hit the corner and clean up my edges. As a final touch, I sand a slight chamfer into the inlay piece. This ensures a nice tight wedged fit. Once all the pieces fit nicely, I glue them in place and clamp them down with some sort of caul. In this case, a piece of scrap ply does a fine job.

At this point, I took a lunch break. Turkey, swiss, on wheat. Light mayo. Yogurt (mixed berry). Back to the shop. Now we need to flush everything up. You can use a variety of tools for this. I like to use a block plane to remove the bulk, then I switch to a card scraper or a cabinet scraper. I finish up with a quick sanding. This is also a perfect time to hide any flaws or oopsies. Cyanoacrylate (CA) glue and a little dust from the offending inlay can give nearly undetectable repairs. A quick sanding at 150 and we are ready to add the circle part of the sun. The circle pretty much goes in like the other pieces. After hitting the circle with block plane and smoothing plane, I sanded the whole piece to 220.

As you can see, it is important to plan out the order in which you will apply the inlays. As mentioned before, I wanted to circle of the sun to be the “top-most” part of the image, so it goes on last. With my leaves, I will do one half of a leaf at a time. The leaf that is in the background is done first. The overlapping leaf is then done on top of the first leaf, giving the impression of depth.

And here is the final product with the sculpted padauk frame and several coats of lacquer.

Bob’s Bench – Completed Bench and Friendly Wager

Last Thursday I put the finishing touches on my new workbench, just in time for a Friday-morning photo session. The plan was to shoot on location, and editor Christopher Schwarz and I were discussing the plan. The one item not resolved was actually moving the bench from our shop to another shop with a more photogenic parking lot. Chris proposed moving the bench completely assembled, and I said "why don't we just take it apart and move the pieces? I think that will be easier."


His response was, "that will take 45 minutes or an hour; it will be quicker to just throw it in the truck." Never afraid to disagree with the boss, I said "It won't take that long, this will come apart in 10 or 15 minutes, and we won't need more than two people to carry the parts." We went back  and forth for a few minutes. "No you can't," "Yes I can" led to "No way," "Absolutely."

I don't remember which of us was the first to say, "Want to bet?," but the introduction of that phrase changed things from theoretical discussion to practical demonstration. The stakes were settled, and the time set for the following morning. As news of the contest spread through the office, it was mutually decided to record the proceedings on film and video.

When I designed this bench, I kept the component parts few in number. The two top slabs are held to the leg structure with four lag bolts coming up through the top rails on each end. With those bolts removed, the tops were placed out of the way on a rolling cart, and I went after the four lags that secure the lapped dovetails at the end of the upper rails. With that task accomplished, I put down the wrench and removed the boards that make up the lower shelf. Those pieces are half-lapped and simply sit on cleats attached to the rails. When those were removed and stacked, I grabbed the hammer.

I lifted the idea for the joints on the ends of the lower rails from an old drawing of a Nicholson bench. There is a dovetail-shaped slot in each leg, and half a lapped dovetail on the  end of each rail. The rails slide into the slots, drop into position and a wedge is tapped in from the outer side of the leg to lock the joint together. This is a surprisingly strong connection, and if the joints loosen over time all I need to do is reach down and give the end of the wedge a rap with my hammer. Tapping from the other direction removes the wedges, allowing the rails to move up and out. One of the wedges escaped my grasp and went scooting across the shop floot, costing me about 10 seconds of time to retrieve it.

Here's a look at the joints coming apart, and the two leg assemblies and lower rails were added to the pile. Elapsed time: 6 minutes, 30 seconds. Putting the bench back together is nearly as fast. It went back together for the photo shoot, and apart again for the return trip to the shop. At the moment it's not assembled. Another challenge has been issued, and we'll soon gather in the shop, stop watches and digital cameras at the ready, to see how fast an old man can move putting the bench back together.

Details on building and using the bench will be included in our October issue, which will be on sale around the first of September. In the meantime, there will be more about it here on the blog as I put it to use. I've enjoyed building this bench, and I'm looking forward to using it.

– Bob Lang



Using jQuery Plugins with ASP.NET

Posted on June 29, 2008 by matt@mattberseth.com.
Categories: ASP.NET, Contributors.

The controls found in the AjaxControlToolkit fit perfectly into the ASP.NET programming model (as to be expected). You can configure the controls properties through the markup which in turn affects how the control's display and behavior on the client. Many of the control's properties support databinding so using the controls within a databound control like a ListView or a GridView is no big deal. Take for example the ProgressBar Toolkit control I blogged about (here and here). One of the places that I use this control is in a GridView's TemplateField. Instead of displaying the percentage as a text value, I use the ProgressBar to display the percentage in a more visual manner. It looks something like this ...

Live Demo | Download

image

With the Toolkit, setting this up is really simple. Just use a databinding expression to set the Value property of the ProgressBar control to the value of the PercentComplete property of the databound item. Done.

  1. <mb:ProgressControl
  2.     ID="ProgressControl17" runat="server"
  3.     Value='<%# Eval("PercentComplete") %>'
  4.     Animate="true" Mode="Manual" ShowStatusText="false"
  5. />

And if I start using and building jQuery plugins I am thinking there will be cases where I am going to miss how simple this is. So after learning about jQuery's metadata plugin, I thought it would be interesting to see explore it a bit more to see if it could be used to enable some of the common scenarios. There are 2 things the metadata plugin has going for it that I think will help it fit into the ASP.NET programming model ...

  • If a jQuery plugin supports the metadata plugin in, you can specify the plugin options on a per element basis by using some JSON within the elements class attribute to specify the option properties you would like to use. To me this really doesn't feel too different than pointing a Toolkit control (using TargetControlID) at an existing web control.
  • It can all be done via markup - no need to emit any extra javascript

Creating the Plugin

Before I show how this can be done using the ListView, I thought I would show what the jQuery plugin looks like (granted it doesn't have nearly as many features as the Toolkit version, but it still very useful for the data grid scenario). Here is how the plugin works ...

  1. Coalesce the default options together with any options that are explicitly provided when the progressbar plugin is applied (Line #5)
  2. Inject the DIV elements that are used for styling the progress bar (Line #9)
  3. Check to see if the metedata plugin is available. If it is override any of the element specific options (Line 12)
  4. Finally, use find to locate the progress_indicator DIV whose background image is set to the progress image (this is applied via the stylesheet). Set the title attribute of this element and animate the width to the specified value. (Lines #16-#20)

Could it get any simpler?

  1. (function($) {
  2.  
  3.     $.fn.progressbar = function(options) {
  4.         // build main options before element iteration
  5.         var opts = $.extend({}, {value:0, tooltip:''}, options);
  6.  
  7.         return this.each(function() {
  8.             //  add the progress DOM structure
  9.             $(this).html('<div class="progress_outer"><div class="progress_inner"><div class="progress_indicator"></div></div></div>');
  10.            
  11.             //  if the metadata plug-in is installed, use it to build the options
  12.             var o = $.metadata ? $.extend({}, opts, $(this).metadata()) : opts;
  13.            
  14.             //  locate the DOM element that contains
  15.             //  the progress image       
  16.             $(this).find('.progress_indicator')
  17.                 //  add the tooltip
  18.                 .attr('title', o.tooltip)           
  19.                 //  and animate the width
  20.                 .animate({width: o.value + '%'}, 'slow');
  21.         });
  22.     };
  23.  
  24. })(jQuery);

Using the jQuery progressbar Plugin with the ListView

Then, I can use databinding expressions to encode the tooltip and value options using the databinding expression. It isn't as pretty, but it defiantly works. All of the magic happens in line #16. And if you set the control to runat server, you could populate this value from the codebehind as well.

  1. <asp:ListView ID="lvWorkItems" runat="server" DataSourceID="ldsWorkItems">
  2.     <LayoutTemplate>
  3.         <table class="yui-grid" cellspacing="0" cellpadding="0">
  4.             <tr class="hdr">
  5.                 <th><asp:LinkButton ID="btnIDSort" runat="server" Text="ID" CommandName="Sort" CommandArgument="ID" /></th>
  6.                 <th><asp:LinkButton ID="LinkButton1" runat="server" Text="Name" CommandName="Sort" CommandArgument="Name" /></th>
  7.                 <th><asp:LinkButton ID="LinkButton2" runat="server" Text="Percent Complete" CommandName="Sort" CommandArgument="PercentComplete" /></th>
  8.             </tr>
  9.             <tr id="itemPlaceholder" runat="server" />
  10.         </table>
  11.     </LayoutTemplate>
  12.     <ItemTemplate>
  13.         <tr class='<%# Container.DataItemIndex % 2 == 0 ? "row" : "altrow" %>'>
  14.             <td><%# Eval("ID") %></td>
  15.             <td><%# Eval("Name") %></td>
  16.             <td><div class='progressBar {value: "<%# Eval("PercentComplete") %>", tooltip:"<%# string.Format("Task {0} is {1}% complete!", Eval("ID"), Eval("PercentComplete")) %>"}'></div></td>
  17.         </tr>
  18.     </ItemTemplate>
  19. </asp:ListView>

Applying the Plugin

And the only remaining bit of awkwardness is that the progressbar plugin needs to be applied twice. Once when the page first loads.

  1. function pageLoad(sender, args){
  2.     if(!args.get_isPartialLoad()){
  3.         //  apply the
  4.         $('.progressBar').progressbar();
  5.     }
  6. }

And then again just after an UpdatePanel is refreshed (I apply it to the panels new contents) ...

  1. Sys.WebForms.PageRequestManager.getInstance().add_pageLoaded(function(sender, args){
  2.     var updatedPanels = args.get_panelsUpdated();
  3.     if(updatedPanels &amp;&amp; updatedPanels.length > 0){
  4.         for(var i = 0; i < updatedPanels.length; i++) {
  5.              $('.progressBar', updatedPanels[i]).progressbar();
  6.         }
  7.     }                   
  8. });

Footprint

And as promised, here is the JavaScript and CSS footprint for this example. I am using ASP.NET AJAX's ScriptManager and UpdatePanel controls - so those are the axd JavaScript references. The JavaScript for my plugin is ~1 KB unminified.

JavaScript: 113 KB

image

CSS: 2 KB

image

That's it. Enjoy!

PlacesBar Editor Customizes Windows Explorer [Featured Windows Download]

Posted on June 27, 2008 by Adam Pash.
Categories: Contributors, Windows.


Windows only: Donationware application PlacesBar Editor customizes the default shortcut locations in the Windows and Microsoft Office Save As and Open dialog boxes to give you easy access to the folders you use most. We've seen applications like this before, like previously mentioned, similarly named PlacesBar Editor, but this application's ability to set different default save locations for Microsoft Office and Windows as a whole is a great addition. PlacesBar Editor is donationware, Windows only.

PlacesBar Editor [via FreewareGenius]

glowbuttons - Writing My First jQuery Plugin

Posted on June 26, 2008 by matt@mattberseth.com.
Categories: Contributors.

So I figure what better way to learn more about jQuery than to dig right in and create a plugin or two? At first I thought this sounded pretty intimidating, but after browsing through some of the existing jQuery plugins I figured it might be easy enough to try and 'rearrange' one of the Toolkit controls that I created. So that is what I did with my GlowButtonExtender control I created a few months back (and I plan on doing it with the ProgressBar one as well very soon). I kind of liked this because I thought creating the same UI widget using both the Toolkit and jQuery might give a little more insight into what the relative advantages are between the two frameworks.

In case you didn't see my original post on creating the GlowButtonExtender control, here is how it works: When you mouse over the button, it glows as it comes into focus and of course when the mouse leaves the glow slowly fades away. These are just screen shots so you will have to check out the demo page to see it in action.

Live Demo (IE7, FF and Opera)* | Download

* IETester seems to be on the fritz - so I wasn't able to test in IE6.

image imageimageimageimage

Footprint

Before I jump into the details, I just thought that I would mention that from now on, all of my posts (at least the ones that include a live demo) will include a section titled Footprint that has a brief discussion on the size of JavaScript and CSS resources my post is making use of. I really should have been doing this all along, but better late than never, right? So here it is for this post. I am using minified versions of jQuery and the metadata plugin (58 KB total combined) plus the color plugin (another 4 KB). And finally, the JavaScript for my glowbuttons plugin is a whopping 3 KB un-minified plus another 2 KB for the CSS.

JavaScript: Total 64 KB

image

CSS: Total 2 KB

image

Basic jQuery Plugin Template

So to get started creating my glowbutton plugin I first did some googling and came across a great resource that goes over some of the basics about creating jQuery plugins. I recommend reading (and understanding) the code samples. Below is the shell that I started with for my plugin. I would pay particular attention to the following ...

  • There is a decent amount of plumbing that really needs to be included in your plugin to make sure it can play together nicely with other jQuery plugins as well as other JavaScript libraries
    • Notice the first and last lines. The plugin is wrapped in a self executing function that takes a single parameter '$'. And the last line of code invokes the function passing in the global jQuery object. If you follow this pattern you can safely use the $ shortcut to refer to the jQuery object without worrying about colliding with other bits of JavaScript code that might also be running on the client. If you don't write your plugin using this technique I believe you should not be using the $ shortcut at all (or do at your own peril).
    • Line 5 I am creating the entry point to my glowbuttons plugin and adding it to the $.fn object
    • If you notice in line 5, my plugin accepts a single parameter called options. I am using lines 19 through 24 to define the options my plugin supports as well as the default values for each of the properties. Line 8 examines the options my plugin is provided along with the default option values and fills in any missing options with the defaults. If no options are supplied all of the default values will be used.
    • Line 10 is where we actually start doing something. Here we iterate over each of the elements in the wrapped set and do something with them. Two things are important here. The first is that I am returning this which is a reference to the wrapped set. This allows users to chain calls together creating the nice compact, fluent interface that jQuery is know for. And the second is that where I have the comment 'do something with $(this)' is where the actual plug-in logic goes. We will see that soon.
  1. (function($) {
  2.   //  add our glowbuttons function.  it accepts
  3.   //  a single parameter that specifies any parameters
  4.   //  our plugin supports
  5.   $.fn.glowbuttons = function(options) {
  6.    
  7.     // build main options before element iteration
  8.     var opts = $.extend({}, $.fn.glowbuttons.defaults, options);
  9.    
  10.     return this.each(function() {
  11.  
  12.         //  do something with $(this).
  13.         //  this is where all of the core plug in code belongs
  14.  
  15.     });
  16.   };
  17.  
  18.   // default options - these are used of none others are specified
  19.   $.fn.glowbuttons.defaults = {
  20.     from: '#016bbd', '#b1ddff',
  21.     className: 'blue',
  22.     speed: 1000
  23.   };
  24.  
  25. //  invoke the function we just created passing it
  26. //  the jQuery object
  27. })(jQuery);

Adding the GlowButton Plugin Logic

So after creating the template, I went back to my existing GlowButtonsExtender logic and started moving it over into my plugin. My existing plugin did basically 3 things

  • Injected 2 SPAN's surrounding the button that I am using for styling (border and background)
  • Injected some browser-specific style workarounds
  • Setup 2 Toolkit animations for animating the background color as the mouse enters and leaves the button

And adding this logic into the plugin was really easy. Below I am just showing the part where I iterate over the wrapped set, but you can see that on line 4 I am wrapping the button in 2 spans using the wrap function. Then I navigate up to the immediate parent nodes and apply some browser hacks (I left them out of the code snippet here because they don't add much value). And finally, I attach to the outer most SPAN's hover events and run a simple color animation when the button is hovered over.

  1. return this.each(function() {
  2.     var button = $(this);
  3.     //  inject the parent nodes           
  4.     button.wrap('<span class="glow-button"><span class="inner">');
  5.    
  6.     //  ** do some browser specific style workarounds
  7.    
  8.     button.parent().each(function(){
  9.         var innerWrapper = $(this);
  10.        
  11.         //  ** do some browser specific style workarounds
  12.        
  13.         innerWrapper.parent().each(function(){
  14.        
  15.             //  ** do some browser specific style workarounds
  16.        
  17.         })           
  18.         //  add a class to the outer most node - this helps with theming
  19.         .addClass(o.className)
  20.         //  finally attach to the hover events to run the animation
  21.         .hover(
  22.             function(){
  23.                 $(this).stop();
  24.                 $(this).animate({ backgroundColor: o.to }, o.speed);
  25.             },
  26.             function(){
  27.                 $(this).stop();
  28.                 $(this).animate({ backgroundColor: o.from }, o.speed);
  29.             }
  30.         );                     
  31.     });
  32. });

And now I can do things like this ...

  1. $(document).ready(function(){   
  2.     $('.glow').glowbuttons();
  3. });

... and all of the INPUTs on my page with the glow CSS class will start glowing.

Overriding Options with the Metadata Plugin

And you could stop there if you want and have a pretty useful plugin. But, you can make your plugin even more flexible by adding support for the Metadata plugin. The Metadata plugin allows you to override the option values on a per element basis. So in the code snippet immediately above this I am applying the default options to all of the glow elements on the page. But that isn't always what you want - and that is where the Metadata plugin becomes useful. With this plugin users can override the default options by specifying option values using the class attribute as follows ...

  1. <asp:Button ID="Button1" runat="server" CssClass="glow" Text="Sign Up Now!" />       
  2. <br />
  3. <br />
  4. <asp:Button ID="Button2" runat="server" CssClass="glow {from: '#111111', to: '#555555', className: 'dark'}" Text="Sign Up Now!" />       
  5. <br />
  6. <br />
  7. <asp:Button ID="Button3" runat="server" CssClass="glow {from: '#79B837', to: '#C7EB6E', className: 'green', speed: 500}" Text="Sign Up Now!" />       
  8. <br />
  9. <br />   
  10. <asp:Button ID="Button4" runat="server" CssClass="glow {from: '#9C0063', to: '#D693BD', className: 'purple'}" Text="Sign Up Now!" />

And now we can still fire the same logic on document ready, but now because we are specifying different parameter values on a per element basis, we end up rendering the following buttons.

image

And best of all, to support this all we have to do us update our plugin and add a single line of code. In the snippet below I updated the template to check first check the current element (i.e. $(this)) to see if it has any metadata properties defined. If it does we will honor these values. And if the metadata plugin isn't available, we just fall back and use what ever options are available.

  1. (function($) {
  2.   //  add our glowbuttons function.  it accepts
  3.   //  a single parameter that specifies any parameters
  4.   //  our plugin supports
  5.   $.fn.glowbuttons = function(options) {
  6.    
  7.     // build main options before element iteration
  8.     var opts = $.extend({}, $.fn.glowbuttons.defaults, options);
  9.    
  10.     return this.each(function() {
  11.         //  if the metadata plug-in is installed, use it to build the options
  12.         var o = $.metadata ? $.extend({}, opts, $(this).metadata()) : opts;
  13.        
  14.         //  ... plugin logic
  15.        
  16.     });
  17.   };
  18.  
  19.   // default options - these are used of none others are specified
  20.   $.fn.glowbuttons.defaults = {
  21.     from: '#016bbd',
  22.   '#b1ddff',
  23.     className: 'blue',
  24.     speed: 1000
  25.   };
  26.  
  27. //  invoke the function we just created passing it
  28. //  the jQuery object
  29. })(jQuery);

And finally, here is the complete source code for the plugin.

  1. (function($) {
  2.   $.fn.glowbuttons = function(options) {
  3.     // build main options before element iteration
  4.     var opts = $.extend({}, $.fn.glowbuttons.defaults, options);
  5.    
  6.     return this.each(function() {
  7.         var button = $(this);
  8.         //  if the metadata plug-in is installed, use it to build the options
  9.         var o = $.metadata ? $.extend({}, opts, button.metadata()) : opts;
  10.         //  inject the parent nodes           
  11.         button.wrap('<span class="glow-button"><span class="inner">');
  12.         //  ie display workaround
  13.         button.css('display', $.browser.msie ? 'inline-block' : 'block');
  14.        
  15.         button.parent().each(function(){
  16.             var innerWrapper = $(this);
  17.            
  18.             //  more browser specific workarounds   
  19.             innerWrapper.css('display', $.browser.msie ? 'inline-block' : 'block');
  20.             if($.browser.msie) {
  21.                 innerWrapper.css({ 'position':'relative', 'left':'-1px' });
  22.             }
  23.            
  24.             innerWrapper.parent().each(function(){
  25.                 var outerWrapper = $(this);
  26.                 outerWrapper.css('display', $.browser.mozilla ? '-moz-inline-box' : 'inline-block');
  27.                 outerWrapper.css('backgroundColor', o.from);
  28.                
  29.                 //  our glossy image is a transparent PNG so
  30.                 //  we have a special class that uses an image filter
  31.                 if($.browser.msie &amp;&amp; $.browser.version < 7) {
  32.                     outerWrapper.addClass('ie6');   
  33.                 }                     
  34.             })
  35.             //  add a class to the outer most node - this helps with theming
  36.             .addClass(o.className)
  37.             //  finally attach to the hover events to run the animation
  38.             .hover(
  39.                 function(){
  40.                     $(this).stop();
  41.                     $(this).animate({ backgroundColor: o.to }, o.speed);
  42.                 },
  43.                 function(){
  44.                     $(this).stop();
  45.                     $(this).animate({ backgroundColor: o.from }, o.speed);
  46.                 }
  47.            );                     
  48.         });
  49.     });
  50.   };
  51.  
  52.   $.fn.glowbuttons.defaults = {
  53.     from: '#016bbd',
  54.   '#b1ddff',
  55.     className: 'blue',
  56.     speed: 1000
  57.   };
  58.  
  59. })(jQuery);

What am I doing to learn more about jQuery?

So far I have found jQuery pretty easy to learn. But I have also only just started so I feel like I have a lot of catching up to do. Here is what I am doing to learn more about jQuery ...

  • Take Scott Hanselman's advice and become a better dev by reading more code. The existing jQuery plugins are pretty readable. I think once you get past the seemingly goofy JavaScript syntax for controlling scoping the rest is pretty straight forward. Browse the plugins and see how they work. I think you might be surprised at how simple they are (I know I was)
  • Subscribe to jQuery's discussion board over on Google Groups.
  • Pick up a JavaScript reference book
  • Check out learningjquery.com it has some great information. Plus I was over there today and stumbled onto a comment that Martin Fowler made (obviously I don't know that it was him for sure, but you never know).
  • Both Dave Ward and Rick Strahl blog fairly regularly on using jQuery with ASP.NET. So if you haven't yet, subscribe to their feeds. (here and here)

That;s it. Enjoy!