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.
Perl Monks, amazing quality of discussion and programming; I will admit that I just don’t have the time to go to this site much but every time I do, I always come away pledging to read it more.
U of MD High School Programming Contest, before you say that these would be too hard in an interview, ask yourself if you want developers that are at least as good as a bright high-school student. Story: I was looking at some summer intern’s code, and I thought, “decent, should probably hire him,” turns out the guy was not a college intern as I had assumed, but a high school intern from one of the schools that always score first or second in this contest (TJ); wow. Programming contests usually have good problems you can use, for example, see the Programming Contest Problem Archive.
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…
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.
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.
… 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.”
… 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.”
You can give a wrapped set as a second argument to a selector such as: $(’p', wrappedSet). This is the same as wrappedSet.find(’p').
The CSS selector ‘> *’ returns direct descendants of an element. For example, $(’> *’, $(’ul.fred’)) would bring back the list elements of any list with class ‘fred’.
The JS function window.clearInterval() will clear a timeout set with window.setTimeout().
What’s fascinating for me about this plugin is the size of it, it’s very small. Now I realize that it doesn’t do that much but the kernel is there. See this post for a discussion of different jQuery autocomplete plugins. The author of the bassistance autocomplete plugin (Jorn) has an interesting first comment.
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:
keyup Main input event that sets up the typing timeout (delay to autocomplete).
keypress Main input event that
autocomplete This is the event that triggers the autocomplete on an input control. See the autocomplete binding method for the behavior. Sets up a ‘one’ binding for the updateList event that does most the work.
updateList This event updates the list and starts the autocomplete on the input after setting up the container (opt.wrapper element). This calls autocompleteMode which does the work.
These are the autocompleteMode events:
activate.autocomplete This event is when the highlighted autocomplete list item is selected; either via the enter key or via a mouse click. Note line 51: active && input.trigger(”activate.autocomplete”, [$.data(active[0], “originalObject”)]); the input element does not have an actiavate.autocomplete handler on it but one can be added an dwill be called. This is the same for the cancel.autocomplete and itemSelected.autocomplete events.
cancel.autocomplete This cancels the autocomplete, either from an escape key or from a click on the window object.
off.autocomplete Does the work of actually turning off the autocomplete.
itemSelected.autocomplete Triggered on input when autolist item is selected.
keydown.autocomplete Straightforward; handles special keys (ESC, RETRUN, UP, DOWN, TAB).
click.autocomplete Click handler.
mouseover Mouseover handler.
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:
autocompleteMode (document.body) holds the current state of autocomplete on the current control; true if the autocomplete list is showing, false otherwise. Note that a global is all that’s needed since only one control is active at a time.
suppressKey (document.body) if set, keypress on input element is cleared and returns ignoring key. This suppresses the up/down keypress when navigating the autocomplete list from clearing the autocomplete. This is not necessary since IE does not have a keydown/up keypress event; unfortunately, this suppresses valid keys in IE. See discussion here.
originalObject (single element of autocomplete list, i.e. opt.template) this is set on every list (or opt.template) element in the matching autocomplete list. This is not state but rather a way to get back to the original object when an autocomplete item is selected.
typingTimeout (input) the return from the setTimeout function so we can clear the timeout later. Not state.
Some other notes:
I like how container is created around the autocomplete list and to remove you just have to do container.remove().
I metioned the namespaced events in previous post, but this plugin makes nice use of them.
The filter and map on list (lines 164-170) is very perlish/lispy; I love it.
I’m using a modified version with these changes:
Fixed console in autocomplete.html for IE7.
Fix suppressKey for IE (see above).
Fix pressing tab/down/up before typingTimeout. (Not setting/clearing typeTimeout data on same element.)
Bring down autocomplete list immediately on arrow up/down.
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 :)
I don’t understand when authors of provide no documentation. Programmers don’t really like doing documentation but this would get many more people to use the plugin.
It took me a while to figure out what events like ‘click.autocomplete’ were. Turns out that jQuery has a mechanism where you can namespace your events. Here is another writeup about it. Nice idea.
Getting the key in a event callback in a cross browser manner can be done succinctly like: var k = e.which || e.keyCode; I already knew about this as I know that many others do but it’s nice to note. You would think that jQuery would hide this detail. Also, I always wondered why jQuery didn’t have a map for the common keycodes. I guess you have to do it yourself: var KEY = { ESC: 27, RETURN: 13,…};
Note that the version from the site above works on IE, the one in the svn jQuery source base doesn’t.
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:
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):
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.
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:
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:
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: