Tuesday, February 5, 2013

Unobtrusive JavaScript


What it used to mean

The meaning of the phrase unobtrusive JavaScript has changed since jQuery came around. To understand this change, let’s first go back to when we used to write code like this:
<form class="validated_form" onsubmit="return validateForm(this)">
This is definitely obtrusive JavaScript, since the code is directly embedded in the HTML tags.
In order to make this unobtrusive, we pulled the JavaScript out of the HTML document and put into a separate JS file. But, as soon as we removed the JavaScript code from the onsubmit attribute, we had to write more code to accomplish the same thing. Before we could bind to the submit event, we first had to find that form tag, most likely from within an onload event-handler.
While separating the JavaScript behavior from the HTML is an improvement, we’re doing a lot more work to find the form when the page loads. This shift in where the JavaScript was located forced us to think about DOM traversal – figuring out how to find the elements that we wanted to bind the event to. However, the benefit of separating the JavaScript and HTML outweighed the performance hit of the DOM actions that were happening when the page loaded.

What it means today

In today’s world of JavaScript development, we can use jQuery to easily find elements in the DOM and attach event-handlers with a simple API. So the complex code in our separate JS file can now be written in jQuery like this:
$(function(){
  $('.validated_form').submit(function(){
    return validateForm(this);
  });
});
Although this looks innocent because of the simple jQuery syntax, it still has to search the DOM for the matching element when the page loads (DOM-ready). Essentially it’s doing same thing as our previous onload code, except that jQuery allows us to find the form element and bind events to it using much less code.
Because our code is dependent on how well jQuery performs the DOM traversal, I believe the term obtrusive now refers to the amount of work that has to be done before the user can interact with the page. Every new event-handler that needs to get bound to an element means another DOM scan, which means the user has to wait that much longer before they can use your page. The more DOM work and event-binding that occurs, the more obtrusive your JavaScript has become.

The solution

Fortunately, we can avoid this initial DOM searching by using event delegation. To make our JavaScript unobtrusive, we will essentially adopt an event-driven approach, by only binding a single event-handler to the document. In that case, nothing will happen until a submit event occurs, when it will then bubble up to the document, where the event-handler will respond. The jQuery changes slightly, to look like this:
$(document).on('submit', '.validated_form', function(){
  return validateForm(this);
});
At first glance, it doesn’t look like a whole lot has changed, but it’s actually doing something completely different. Binding event-handlers on the document is a significant change in how the JavaScript is written and how it behaves.
The jQuery on function was introduced in version 1.7, but the same thing can be accomplished in version >= 1.4.2 using the delegate function.

The foundation: event delegation

Since a reference to the document is immediately available, we don’t have to wait for an onload or DOM-ready event to attach an event-handler. As soon as the script executes, it will listen to any submit event that fires in the document and only run the callback if the triggering element matches the specified selector. When an event occurs, it will not only fire the event on the source element, but will also bubble up to its parent, and that element’s parent, firing the event along the way. It will keep bubbling up the DOM, firing the event on all ancestor elements until it reaches the document. At that point, our bound event-handler will run, but will still have access to the source element that fired the event. This process is called event delegation, since execution of the event-handler is delegated to an ancestor element. This makes our code unobtrusive because the work to determine which element triggered the event is deferred until the event fires.
Another benefit of this approach is that the submit event will also be executed for forms that don’t yet exist in the DOM. This means that if you add more forms to the document via AJAX, for example, you don’t have to worry about binding submit event-handlers to those forms. When the submit event occurs on those form elements, they’ll just bubble up to the document, where our existing event-handler will respond.
Any ancestor element can have events delegated to it, not just the document.

Creating an unobtrusive widget

Using event delegation, we can then identify common patterns and build a single reusable widget. I’ll use a keycapture widget as an example. After setting up many textareas in our application, we discovered that we kept writing the same onkeydown event-handlers, to limit input or respond to certain keystrokes. To avoid duplicating this, we created a single unobtrusive keycapture widget that listens to keydown events on the document. The basic setup looks like this:
$(document).on('keydown', 'textarea', function(e){
  var $textarea = $(this);
  // do something with this keydown event
});
Now that we can react to keydown events in a single location, how do we know what to do with that keydown event? We’ll look to the element for hints on what to do.

Markup-driven behavior

Each unobtrusive widget can be configured using HTML5 data- attributes on the element. The sole purpose of these attributes is to provide information to the JavaScript code. For now, let’s set up our keycapture widget to blur the textarea whenever the Escape key is pressed. All we have to do is add a data-escape="blur" attribute to the textarea:
<textarea name="description" data-escape="blur"></textarea>
With this embedded data on the element, the JavaScript code can now make a decision on what to do:
if ((e.which === 27) && ($textarea.data('escape') === 'blur')) {
  $textarea.blur();
}
As of version 1.4.3, jQuery automatically makes all data-* attributes available via the data function.
Now any textarea at any time can use this keycapture widget by simply adding the data-escape attribute to the tag – no additional JavaScript necessary!

Summary

Creating reusable widgets with unobtrusive JavaScript techniques gives you the following benefits:
  • Avoids duplication of JS code by having a single event-handler on the document
  • Avoids expensive DOM searches when the page loads
  • Automatically handles elements that are dynamically added to the DOM
  • Separates HTML markup from JS behavior, but provides means to configure widgets via data-* attributes

Custom Events

In the next post, I’ll discuss how we can hook into these widgets even further, using custom events in jQuery.

Create PDF’s and Images from your website in Rails 3

I am going to show you how to generate both a pdf and image from a single action in a controller using the awesome, wkhtmltopdf library. This also uses PDFKit and WebSnap gems available on GitHub.
This example assumes the following:

  • wkhtmltopdf and wkhtmltoimage are already installed and accessible on in the PATH.
  • You have an html page setup to display the record.
  • You have created a pdf CSS file to help display the pdf, if you so choose. 
# config/initializers/mime_types.rb
  Mime::Type.register "application/pdf", :pdf
  Mime::Type.register "image/png", :png
 
  # app/controllers/items_controller.rb
  def show
    @item = Item.find(params[:id])
 
    respond_to do |format|
      format.html { }
      format.pdf {
       html = render_to_string :action => "show.html.erb"
        kit  = PDFKit.new( html, :zoom => 0.75 )
        kit.stylesheets << File.join( RAILS_ROOT, "public", "stylesheets", "pdf.css" )
 
        send_data kit.to_pdf, :filename => "item.pdf", :type => 'application/pdf', :disposition => 'inline'
      }
      format.png {
       html = render_to_string :action => "show.html.erb"
 
        # I am nil'ing these options out because my version of wkhtmltoimage does
        # not support the scale options and I do not want to crop the image at all.
        snap = WebSnap::Snapper.new(html, :format => 'png', :'scale-h' => nil, :'scale-w' => nil,
          :'crop-h' => nil, :'crop-w' => nil, :quality => 100, :'crop-x' => nil, :'crop-y' => nil)
 
        send_data snap.to_bytes, :filename => "item.png", :type => "image/png", :disposition => 'inline'
      }
    end
 
You should be able to access
 
  http://example.com/items/1 # => Generates an html page.
  http://example.com/items/1.pdf # => Generates a pdf of the html page.
  http://example.com/items/1.png # => Generates a png of the html page 

(https://github.com/siuying/websnap)

10+ Useful JavaScript Regular Expression Functions to improve your web applications efficiency


10+ Useful JavaScript Regular Expression Functions to improve your web applications efficiency



Fortunately, JavaScript 1.2+ has incorporated regular expressions.JavaScript has an alternate syntax for creating Regular Expression objects that implicitly calls the RegExp constructor function.A regular expression pattern is composed of simple characters, such as /abc/, the syntax for that method is the following:
1var RegularExpression = /pattern/[switch]
To use the Regular Expression object to validate the user input you must be able to define a pattern string that represents the search criteria. Patterns are defined using string literal characters and metacharacters. The following is some useful regular expression based javascript function, some works like validating user input will be very simple by using them. :)
No.1: Check if string is non-blank
1// Check if string is non-blank
2var isNonblank_re    = /\S/;
3function isNonblank (s) {
4   return String (s).search (isNonblank_re) != -1
5}
No.2: Check if string is a whole number(digits only).
1// Check if string is a whole number(digits only).
2var isWhole_re       = /^\s*\d+\s*$/;
3function isWhole (s) {
4   return String(s).search (isWhole_re) != -1
5}
or as seen in the following snippet:
1// check 0-9 digit
2function regIsDigit(fData)
3{
4    var reg = new RegExp(”^[0-9]$”);
5    return (reg.test(fData));
6}
No.3: Checks that an input string is an integer
1// checks that an input string is an integer, with an optional +/- sign character.
2var isInteger_re     = /^\s*(\+|-)?\d+\s*$/;
3function isInteger (s) {
4   return String(s).search (isInteger_re) != -1
5}
or as seen in the following snippet:
1// check is number
2function regIsNumber(fData)
3{
4    var reg = new RegExp(”^[-]?[0-9]+[\.]?[0-9]+$”);
5    return reg.test(fData)
6}
No.4: Checks that an input string is a decimal number
1// Checks that an input string is a decimal number, with an optional +/- sign character.
2var isDecimal_re     = /^\s*(\+|-)?((\d+(\.\d+)?)|(\.\d+))\s*$/;
3function isDecimal (s) {
4   return String(s).search (isDecimal_re) != -1
5}
No.5: Check if string is currency
works just like isDecimal, except that only zero or two digits are allowed after the decimal point.
1// Check if string is currency
2var isCurrency_re    = /^\s*(\+|-)?((\d+(\.\d\d)?)|(\.\d\d))\s*$/;
3function isCurrency (s) {
4   return String(s).search (isCurrency_re) != -1
5}
No.6: Checks that an input string looks like a valid email address
1// checks that an input string looks like a valid email address.
2var isEmail_re       = /^\s*[\w\-\+_]+(\.[\w\-\+_]+)*\@[\w\-\+_]+\.[\w\-\+_]+(\.[\w\-\+_]+)*\s*$/;
3function isEmail (s) {
4   return String(s).search (isEmail_re) != -1;
5}
or as seen in the following snippet:
1// Check if string is a valid email address
2function regIsEmail(fData)
3  {
4      var reg = new RegExp(”^[0-9a-zA-Z]+@[0-9a-zA-Z]+[\.]{1}[0-9a-zA-Z]+[\.]?[0-9a-zA-Z]+$”);
5      return reg.test(fData);
6  }
No.7: Check for valid credit card type/number
1// Check for valid credit card type/number
2var creditCardList = [
3   //type      prefix   length
4   ["amex",    "34",    15],
5   ["amex",    "37",    15],
6   ["disc",    "6011",  16],
7   ["mc",      "51",    16],
8   ["mc",      "52",    16],
9   ["mc",      "53",    16],
10   ["mc",      "54",    16],
11   ["mc",      "55",    16],
12   ["visa",    "4",     13],
13   ["visa",    "4",     16]
14];
15function isValidCC (cctype, ccnumber) {
16   var cc = getdigits (ccnumber);
17   if (luhn (cc)) {
18      for (var i in creditCardList) {
19         if (creditCardList [i][0] == (cctype.toLowerCase ())) {
20            if (cc.indexOf (creditCardList [i][1]) == 0) {
21               if (creditCardList [i][2] == cc.length) {
22                  return true;
23               }
24            }
25         }
26      }
27   }
28   return false;
29}
or as seen in the following snippet:
This is the luhn checksum algorithm, used to validate such things as credit card numbers and bank routing numbers.
1function luhn (cc) {
2   var sum = 0;
3   var i;
4
5   for (i = cc.length - 2; i >= 0; i -= 2) {
6      sum += Array (0, 2, 4, 6, 8, 1, 3, 5, 7, 9) [parseInt (cc.charAt (i), 10)];
7   }
8   for (i = cc.length - 1; i >= 0; i -= 2) {
9      sum += parseInt (cc.charAt (i), 10);
10   }
11   return (sum % 10) == 0;
12}
No.8: Returns a string with everything but the digits removed
1// This returns a string with everything but the digits removed.
2function getdigits (s) {
3   return s.replace (/[^\d]/g, “”);
4}
No.9: Get String Length // Get String Length
1// Get String Length
2function regGetStrLength(fData)
3{
4    var valLength = fData.length;
5    var reg = new RegExp(”^[\u0391-\uFFE5]$”);
6    var result = 0;
7    for(i=0; i< valLength; i++)
8    {
9        if(reg.test(fData.charAt(i)))
10        {
11            result += 2;
12        }
13        else
14        {
15            result ++;
16        }
17    }
18    return result;
19}


http://ntt.cc/2008/05/10/over-10-useful-javascript-regular-expression-functions-to-improve-your-web-applications-efficiency.html