BIGREDSWITCH Push it. You know you want to.

Sign o’ the Times

From the Freakonomics blog:

The latest recession indicator: more people are searching Google for “coupons” than for “Britney Spears.” And it’s not that Britney is getting less popular. By this measure, the recession began in March 2008. Check out the full time series, here.

Interview Resources

In interviews, I like to be somewhat technical ;) Some good resources:

The Humble Coupon

NY Times article This Season’s Must-Have: The Humble Coupon :

The faltering economy could mean renewed interest in coupons as shoppers refocus on the cost of the products they buy…

Already, there are some signs of a nascent coupon chic…

New technologies are also helping to renew interest in coupons, especially for younger consumers. There are scores of Web sites where coupons can be obtained by clicking rather than clipping; among them are coupons.com, couponcabin.com, couponcode.com, couponmom.com, 8coupons.com, fatwallet.com and shortcuts.com. Many also deliver coupons by e-mail messages.

Autobox2

I rolled up the autocomplete plugin (Rein + Yehuda) of my last few posts with the Facebook style text list (Guillermo) of my autobox post. We’re calling it Autobox2: click here to see the demo.

Then, download it:
jquery.ui.autobox-0.7.1.zip Updated 12/11 (see comments)
jquery.ui.autobox-0.7.0.zip

Although it is missing some of the behavior of autobox1, it’s a more solid and extendable implementation. It also fixes what is in my mind the most glaring problem of autobox1, the fact that it needed the entire list in the initial ajax call. Autobox2 makes AJAX calls the same way that the autocomplete one does, makes a server call with the current contents of the input box. This is the way you would expect. I will no longer be releasing any more changes to Autobox1 and you can consider it deprecated. (I’ve noted this on the main Autobox1 post.)

As to the implementation, it is based on the Rein and Yehuda’s autocomplete plugin as detailed in 2 previous posts. There were a few things borrowed from Guillermo’s plugin, but it was mostly the ideas and some CSS (the CSS was also simplified.) Because of this, please see the last 2 autocomplete posts here and here for documentation though I do plan on having more proper documentation. Also, see the example included in the zip (autobox.html).

Note: although I call it Autobox2 in the post, the plugin name is still “autobox”. I’ve tested on both FF3 and IE7. As usual, bug reports, fixes, and function requests and ideas are greatly appreciated.

Cyber Monday

Chris Pirillo has a great list of coupon codes, etc. for Cyber Monday Sales.

In Lean Times, Online Coupons Are Catching On

NY Times article: In Lean Times, Online Coupons Are Catching On, excerpts:

… Shoppers obsessed with finding these bargains share the latest intelligence on dozens of sites with quirky names like RetailMeNot.com, FatWallet.com and the Budget Fashionista. And more consumers than ever are scanning the listings before making a purchase at their favorite Web site.

… Her favorite sites include RetailMeNot.com, which has one of the most comprehensive lists; CouponMom.com, which includes coupons for physical stores; and CouponCode.com, which is organized by category.

… “Coupons had never been a big factor online the way they are offline. This is something new,” said Gian Fulgoni, chairman of comScore. “It’s taken pricing power away from the retailers and given it to the consumers, because the consumer is totally up to speed on what the prices are.”

…Scott Kluth founded CouponCabin in 2003…

… RetailMeNot.com goes further with an add-on to the Firefox browser that alerts users when an e-commerce site they are visiting has a discount.

… Sites like FatWallet.com and Ebates offer shoppers cash back on purchases if they sign in and then click through to the retailer.

… Among her coupon-scouting tips: search the name of an online store and the word “coupon” and compare the promotions, because bigger sites are often able to negotiate better offers; if you find a coupon for an offline store, call the Web site and ask it to match the price; and insist upon free shipping, even if it means calling the manager and asking for a coupon code.

… Deborah Dockendorf, a power Web shopper in Chicago, has another piece of advice: if you cannot immediately find a coupon code for a specific store, just wait. “It might be two weeks, but you will have a code for it,” she said. … “I used to feel a little embarrassed about using them, like I was one of those coupon queens at the grocery store,” she said. “But now there is not a day that goes by when a friend doesn’t e-mail me for codes, and if I don’t have one, I can find one for them soon.”

jQuery Autocomplete Plugin 2

Continuing from my last post.

Some notes:

What’s nice about this plugin is that it’s event driven. Sometimes that makes it hard to follow, but if you keep in mind to “just follow the events”, it’s not that hard. So, here are the events we need to follow:

These are the main input (autocomplete input text box) events:

These are the autocompleteMode events:

The key event handlers are on the input element and the mouse event handlers are on the container (wrapper) element and the body/window.

Another thing to have in mind are the data contents for the elements:

Some other notes:

I’m using a modified version with these changes:

If you want it, I’ve zipped it up here:
jquery.autocomplete-0.7.1

Postscript: I know the detail is way too much on last few posts unless you are studying these in depth. But I needed to go though these and these are my notes. So … whatever :)

jQuery Autocomplete Plugin

Some notes from looking at Yehuda Katz and Rein Henrichs autocomplete plugin:

The plugin is very succinct and I wanted to study it; these are my notes.

The plugin is split up into 2 files: jquery.ui.autocomplete.js and jquery.ui.autocomplete.ext.js. The ext file is optional, but if you are going to use it, include it before the main plugin file. I’m actually not sure why it’s optional and I would just include it in the main plugin. It has 2 methods: ajax and templateText (in the $.ui.autocomplete.ext namespace). In the main plugin, the ext methods are used like this:

112     if($.ui.autocomplete.ext) {
113       for(var ext in $.ui.autocomplete.ext) {
114         if(opt[ext]) {
115           opt = $.extend(opt, $.ui.autocomplete.ext[ext](opt));
116           delete opt[ext];
117         }
118     } }

This goes through all items in $.ui.autocomplete.ext (the 2 methods) and merges them iff the options already include those methods (line 114). It merges them (line 115) by calling the method in ext with the opt hash as the parameter and merges in the return value which is a hash; this is why the ext methods take opt as the parameter and return a hash that replaces some methods in the original opt hash. Note that it deletes the opt hash element for the ext value (line 116). This is the first time I’ve seen this type of extension mechanism. Hmm, a little obscure; I’ll reserve judgement for now.

Note how these are used in the HTML file (autocomplete.html):

29         ajax: "list",
32         templateText: "<li>Hey: <%= text %></li>"
53         templateText: "<li><%= pre_match %><span class='matching' ><%= match %></span><%= post_match %></li>"
57         ajax: "list",
60         templateText: "<li>Hey: <%= text %></li>"

It should be pretty obvious what the ext methods do (jquery.ui.autocomplete.ext.js):

18   $.ui.autocomplete.ext.ajax = function(opt) {
19     var ajax = opt.ajax;
20     return { getList: function(input) {
21       if (input.val().match(/^\s*$/)) return false;
22       $.getJSON(ajax, "val=" + input.val(), function(json) { input.trigger("updateList", [json]); });
23     } };
24   };
25 
26   $.ui.autocomplete.ext.templateText = function(opt) {
27     var template = $.makeTemplate(opt.templateText, "<%", "%>");
28     return { template: function(obj) { return template(obj); } };
29   };

Oh, it would probably help if you knew what the options actually were:

The default option values (jquery.ui.autocomplete.js):

103     opt = $.extend({}, {
104       timeout: 1000,
105       getList: function(input) { input.trigger("updateList", [opt.list]); },
106       template: function(str) { return "<li>" + opt.insertText(str) + "</li>"; },
107       insertText: function(str) { return str; },
108       match: function(typed) { return this.match(new RegExp(typed)); },
109       wrapper: "<ul class='jq-ui-autocomplete'></ul>"
110     }, opt);

That should be enough to give you an idea of how to get the plugin working. And now we are ready to roll up our sleeves and see how the plugin actually works. That will have to wait for the next post.

jQuery Templating Plugin

I wanted to take a look at the templating plugin included in the jQuery distribution (for some reason, there is no documentation of it on jquery.com, this is the same templating plugin included in ReinH/Katz autocomplete plugin here). It’s not the best documented plugin but it’s short so should be quick to figure out.

Basically, what this plugin does is take a block of text and interprets it as a template. What is a template? Well, for this plugin, think about JSP or ASP. I.e., executable code between special characters interspersed with HTML. So for example:

23       <% $(arr).each(function() { %>
24         <a href="<%= this.url %>"><%= this.text %></a>
25       <% }); %>

This code uses JSP like syntax where executable code is between ‘<%’ and ‘%>’ tags. And variable expansion uses the ‘<%=’ and ‘%>’; this means that the code inside the variable expansion gets expanded to the value in place (see this.url and this.text in example above.) Where does the arr variable come from? This is passed in as a context parameter to the completed template. Whoa, last 2 sentences need to be explained a little more. Look at the full HTML example distributed in the plugin itself:

 1 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
 2 <html>
 3   <head>
 4     <meta http-equiv="Content-type" content="text/html; charset=utf-8">
 5     <title>Templating</title>
 6     <script src="../jqueryjs/jquery/dist/jquery.js"></script>
 7     <script src="../jqueryjs/plugins/templating/jquery.templating.js"></script>
 8     <script type="text/javascript">
 9       jQuery(function($) {
10         $.pageTemplates = {};
11         $("script[type=text/x-jquery-template]").each(function() {
12           $.pageTemplates[this.title] = $.makeTemplate(this.innerHTML, "<%", "%>");
13           $("body").append($.pageTemplates["template1"]({arr: 
14             [{url: "http://www.yehudakatz.com", text: "Yehuda's site"},
15              {url: "http://www.gweezlebur.com", text: "Ivey's site"}]
16           }));
17         });
18       });
19     </script>
20   </head>
21   <body>
22     <script type="text/x-jquery-template" title="template1">
23       <% $(arr).each(function() { %>
24         <a href="<%= this.url %>"><%= this.text %></a>
25       <% }); %>
26     </script>
27     <a href="foo" rel="#myTemplate" class="updateTemplate">Click</a>
28   </body>
29 </html>

You can see the template itself in lines 22-26 cleverly embedded inside a script tag with a custom type attribute. Now look at the lines 11-17. Line 12 takes the template text itself and creates a template function. Yes, $.makeTemplate, the public templating plugin method, returns a function. That function is then called with a context parameter (a hash) and the template is evaluated. Note that the arr variable is passed into the template function on line 13.

Aight! What do you think of that? At first, I was like what the heck? but looking at it a few times now and it’s rather natural. Let’s look at the actual plugin next. It’s only 25 lines of formatted code:

 1 // Copyright Yehuda Katz
 2 // with assistance by Jay Freeman
 3 // You may distribute this code under the same license as jQuery (BSD or GPL)
 4 (function ($) {
 5   $.makeTemplate = function (template, begin, end) {
 6     var rebegin = begin.replace(/([\]{}[\\])/g, '\\$1');
 7     var reend = end.replace(/([\]{}[\\])/g, '\\$1');
 8 
 9     var code = "try { with (_context) {" +
10       "var _result = '';" +
11         template
12           .replace(/[\t\r\n]/g, ' ')
13           .replace(/^(.*)$/, end + '$1' + begin)
14           .replace(new RegExp(reend + "(.*?)" + rebegin, "g"), function (text) {
15             return text
16               .replace(new RegExp("^" + reend + "(.*)" + rebegin + "$"), "$1")
17               .replace(/\\/g, "\\\\")
18               .replace(/'/g, "\\'")
19               .replace(/^(.*)$/, end + "_result += '$1';" + begin);
20           })
21           .replace(new RegExp(rebegin + "=(.*?)" + reend, "g"), "_result += ($1);")
22           .replace(new RegExp(rebegin + "(.*?)" + reend, "g"), ' $1 ')
23           .replace(new RegExp("^" + reend + "(.*)" + rebegin + "$"), '$1') +
24       "return _result;" +
25     "} } catch(e) { return '' } ";
26 
27     return new Function("_context", code);
28   };
29 })(jQuery);

Very nicely written I would have to say.

Lines 6-7 munges the begin and end tags to be regualar expression friendly.

The next statement (lines 9-25) creates the code block. Note that the code block starts with a with (_context) { and returns the code block on line 27 with return new Function(”_context”, code). If you forgot what the with statement in JavaScript does, take a look here. There’s a bunch of regular expressions that I’m sure you can figure out (nothing too difficult), but a quick way to see what this is doing is adding the line ‘alert(code)‘ at line 26. Ahh, should be obvious now.

Doing this for the example, gives the text below and it becomes obvious:

try {
  with (_context) {
    var _result = '';
    _result += '       ';
    $(arr).each(function() {
      _result += '         <a href="';
      _result += ( this.url );
      _result += '">';
      _result += ( this.text );
      _result += '</a>       ';
    });
    _result += '     ';
    return _result;
  }
} catch(e) { return '' }

So to recap a few points:

Leningrad Cowboys & Red Army Choir

I love it, the Leningrad Cowboys and the Red Army Choir play Sweet Home Alabama.

← Before