Philip Lippard

Please say it ain't so

My Favorite Dozen jQuery Plug-Ins

When we least expect it, an open source component like jQuery revolutionizes client-side software development, which is exactly what has happened since the initial jQuery release in Jan-2006.  I have worked with jQuery since 2008 and over the past two years I have also converted my Socrates content management framework from a ASP.NET web forms model to a ASP.NET MVC model; MVC being an excellent complement to jQuery.  The use of jQuery and jQuery UI have now become all too important.

jQuery includes a robust jQuery plug-in architecture.  3rd party jQuery plugins seem to be endless in numbers, equivalent to trying to select a suitable iPhone App from the iTunes App Store.   My favorite jQuery plug-ins include the following dozen (not necessarily in order of importance):

  1. jQuery-AD-Gallery – Photo gallery management.
  2. jQuery-Booklet – A wonderful magazine or document page flipper.
  3. jQuery-ContextMenu – And you thought right click context menus were not available.  I use it on my TreeView.
  4. jQuery-Download – Easily download files.
  5. jQuery-FancyBox – A LightBox type of plugin, however much nicer than LightBox.
  6. jQuery-TableDnD – Drag and drop rows from within a HTML table.
  7. jQuery-tmpl – Of course this is everyone’s favorite for populating content in tabular form, or in any templated form for that matter.
  8. jQuery-URL-Parser – Great when in need for a URL object.
  9. jQuery-validate – no doubt the leader in form field validation.
  10. jQuery-MeioMask – Useful form input field masking plugin.
  11. jQuery-MaskMoney – Another useful form input field for masking of currency values.
  12. jQuery-TinyMCE – The leader in client-side HTML editors.  Actually comes in non-jQuery and jQuery plugin versions.
  13. jQuery-QTip – Great for jazzing up those tooltips.
  14. jQuery-PLUPLOAD – Developed by the same people who bring us TinyMCE, PLUPLOAD is simply incredible for uploading files in a Silverlight, Flash or HTML5 environment.   Also comes in both jQuery and non-jQuery flavors.

Yes, I can count.  I promised my favorite dozen jQuery plug-ins, however I simply could not leave out two others, so I end up with a favorites list of fourteen.

jQuery and WCF Data Services OData (Open Data Protocol)

I just spend two days trying to figure out why I was getting a HTTP status code 405 (method not allowed) IIS 7.5 response when attempting a jQuery based PUT method to update an existing entity.  As it turns out I tried it with the internal VS 2010 web server and it was working OK.  This helped me to focus my Google searches a bit and I finally narrowed the problem down to having WebDAV Publishing installed on my Windows 7 development virtual machine.  I uninstalled WebDAV and the OData data service now works fine.

I found the WebDAV mention in this post… http://social.msdn.microsoft.com/Forums/en/windowsazure/thread/a22b9e60-8353-40c7-af3e-69a8f18240c1

OData_logo_MS_small

Using Paypal Buy Now Buttons with ASP.NET

I usually use Paypal Web Services for ECommerce, however for the occasional ECommerce merchant, Paypal Web Services may not be appropriate because of the minimum monthly fee.  Depending on one’s preferences, Paypal Buy Now buttons may be suitable for ECommerce.  Buy Now buttons incur no minimum monthly fee and involve conducting a copy/paste operation of HTML into one’s HTML page, as illustrated below:

   1:      <form action="https://www.paypal.com/cgi-bin/webscr" 
   2:          method="post">
   3:          <input type="hidden" 
   4:              name="cmd" 
   5:              value="_s-xclick" />
   6:          <input type="hidden" 
   7:              name="hosted_button_id" 
   8:              value="F4E333HY55FXX" />
   9:          <input type="image" 
  10:              src="https://www.paypal.com/en_US/i/btn/btn_buynow_SM.gif" 
  11:              border="0" 
  12:              name="submit" alt="PayPal - The safer, easier way to pay online!" />
  13:          <img alt="" 
  14:              border="0" 
  15:              src="https://www.paypal.com/en_US/i/scr/pixel.gif" 
  16:              width="1" 
  17:              height="1" />
  18:      </form>

With ASP.NET the above Paypal Buy Now HTML snippet is problematic because ASP.NET WebForms is limited to a single “form” tag definition.  As an alternative one can use the revised HTML snippet to accomplish the same task.

   1:          <input type="hidden" 
   2:              name="cmd" 
   3:              value="_s-xclick" />
   4:          <input type="hidden" 
   5:              name="hosted_button_id" 
   6:              value="F4E333HY55FXX" />
   7:          <asp:ImageButton runat="server" 
   8:              ImageUrl="https://www.paypal.com/en_US/i/btn/btn_buynow_SM.gif" 
   9:              PostBackUrl="https://www.paypal.com/cgi-bin/webscr" />

You will note that the above HTML snippet has been revised such that the forms tag is removed and we are conducting a postback using the ASP.NET ImageButton control.  This works fine provided we have only a single Paypal Buy Now button per WebForm page.

Let’s consider the situation where we have several product definitions defined within SQL Server along with a Paypal Buy Now HTML button definition within SQL for each product.   Let’s also say we are attempting to use an ASP.NET ListView for conducting runtime data binding, illustrated as follows:

   1:  <asp:ListView GroupItemCount="3"
   2:      DataSourceID="dataSource"
   3:      DataKeyNames="GuidKey"
   4:      runat="server">                                
   5:      <LayoutTemplate>
   6:   
   7:          <table id="productTable" runat="server" 
   8:              cellpadding="0"
   9:              cellspacing="0"  
  10:              border="0">                                            
  11:                                  
  12:              <tr runat="server" id="groupPlaceholder" />    
  13:                                                  
  14:          </table>
  15:      </LayoutTemplate>
  16:      <GroupTemplate>
  17:          <tr>
  18:              <td runat="server" id="itemPlaceholder" />
  19:          </tr>
  20:      </GroupTemplate>
  21:      <ItemTemplate>                                            
  22:          <td>
  23:              <div>
  24:                  <div>
  25:                      <asp:Literal runat="server" 
  26:                          Text='<%# Eval("Title") %>' />    
  27:                  </div>
  28:                  <div>
  29:                      <asp:Literal runat="server" 
  30:                          Text='<%# Eval("Description") %>' />
  31:                  </div>    
  32:                  <div>
  33:                      <asp:Literal runat="server" 
  34:                          Text='<%# InjectImage(Eval("Url")) %>'  />    
  35:                  </div>
  36:                  <div>
  37:                      <asp:Literal runat="server" Text='<%# Eval("ButtonHTML") %>' />
  38:                      <asp:ImageButton runat="server" 
  39:                          ImageUrl="~/Themes/Images/ECommerce-Buttons/button-add-cart-blue.gif" 
  40:                          PostBackUrl="https://www.paypal.com/cgi-bin/webscr" />
  41:                  </div>
  42:              </div>                                
  43:          </td>
  44:      </ItemTemplate>    
  45:  </asp:ListView>

The above illustration assumes that the ButtonHTML SQL field being bound contains the Paypal Buy Now HTML snippet; the snippet that has been revised for ASP.NET.  The above implementation is problematic because Paypal will encounter errors when reading the Paypal hidden fields, because there will be multiple Paypal hidden fields with the same “name” attribute; “cmd” and “hosted_button_id”, etc.

The most effective means that I have found to get around this problem is to continue to define the revised Paypal Buy Now HTML snippet as we doing above, because doing so will simplify the copy/paste operation from Paypal to our SQL Server app.  Ultimately, what we want to do is to transform all hidden field “name” attributes to “id” attributes during WebForm start-up, immediately after the ListView is rendered.  Using jQuery, we transform the productTable ListView as follows:

   1:   
   2:   
   3:  function OnAjaxLoad() {
   4:   
   5:     
   6:      jQuery(document).ready(function () {
   7:          InitializePaylBuyNowButtons();
   8:      });
   9:  }
  10:   
  11:  function InitializePaylBuyNowButtons() {
  12:   
  13:      jQuery("table[id$='_productTable']").children('tbody').children('tr').each(function () {
  14:          jQuery(this).children('td').each(function () {
  15:              jQuery(this).children('div').children('#paypalButton').each(function () {
  16:   
  17:                  var productContainer = jQuery(this);
  18:   
  19:                  // initialize standard Paypal Buy Now hidden fields - 
  20:                  // move name attribute value to id attribute
  21:                  // so these hidden fields will not be visible to Paypal
  22:                  productContainer.children('input:hidden').each(function () {
  23:   
  24:                      switch (jQuery(this).attr("name")) {
  25:                          case "cmd":
  26:                          case "hosted_button_id":
  27:                          case "currency_code":
  28:                              jQuery(this).attr("id", jQuery(this).attr("name"));
  29:                              jQuery(this).attr("name", "");
  30:                              break;
  31:                          default:
  32:                              break;
  33:                      }
  34:                  });
  35:   
  36:                  // find possible drop-down - used for multiple prices - 
  37:                  // do same name ==> id move
  38:                  productContainer.children('table').children('tbody').children('tr')
  39:                      .children('td').children('input:hidden').each(function () {
  40:   
  41:                      switch (jQuery(this).attr("name")) {
  42:                          case "on0":
  43:                              jQuery(this).attr("id", jQuery(this).attr("name"));
  44:                              jQuery(this).attr("name", "");
  45:                              break;
  46:                          default:
  47:                              break;
  48:                      }
  49:                  });
  50:   
  51:                  // find possible drop-down - used for multiple prices - 
  52:                  // do same name ==> id move
  53:                  productContainer.children('table').children('tbody').children('tr')
  54:                      .children('td').children('select').each(function () {
  55:   
  56:                      switch (jQuery(this).attr("name")) {
  57:                          case "os0":
  58:                              jQuery(this).attr("id", jQuery(this).attr("name"));
  59:                              jQuery(this).attr("name", "");
  60:                              break;
  61:                          default:
  62:                              break;
  63:                      }
  64:                  });
  65:   
  66:              });
  67:          });
  68:   
  69:      });
  70:  }
  71:   
  72:  Sys.Application.add_load(OnAjaxLoad);

After we have transformed all Paypal Buy Now button hidden fields, we want to revise our ListView definition to accommodate the above jQuery start-up transformation as follows:

   1:  <asp:ListView GroupItemCount="3"
   2:      DataSourceID="dataSource"
   3:      DataKeyNames="GuidKey"
   4:      runat="server">                                
   5:      <LayoutTemplate>
   6:   
   7:          <table id="productTable" runat="server" 
   8:              cellpadding="0"
   9:              cellspacing="0"  
  10:              border="0">                                            
  11:                                  
  12:              <tr runat="server" id="groupPlaceholder" />    
  13:                                                  
  14:          </table>
  15:      </LayoutTemplate>
  16:      <GroupTemplate>
  17:          <tr>
  18:              <td runat="server" id="itemPlaceholder" />
  19:          </tr>
  20:      </GroupTemplate>
  21:      <ItemTemplate>                                            
  22:          <td>
  23:              <div>
  24:                  <div>
  25:                      <asp:Literal runat="server" 
  26:                          Text='<%# Eval("Title") %>' />    
  27:                  </div>
  28:                  <div>
  29:                      <asp:Literal runat="server" 
  30:                          Text='<%# Eval("Description") %>' />
  31:                  </div>    
  32:                  <div>
  33:                      <asp:Literal runat="server" 
  34:                          Text='<%# InjectImage(Eval("Url")) %>'  />    
  35:                  </div>
  36:                  <div id="paypalButton">
  37:                      <asp:Literal runat="server" Text='<%# Eval("ButtonHTML") %>' />
  38:                      <asp:ImageButton runat="server" 
  39:                          ImageUrl="~/Themes/Images/ECommerce-Buttons/button-add-cart-blue.gif" 
  40:                          PostBackUrl="https://www.paypal.com/cgi-bin/webscr" 
  41:                          OnClientClick="PaypalBuyNowProductSelected(this);" />
  42:                  </div>
  43:              </div>                                
  44:          </td>
  45:      </ItemTemplate>    
  46:  </asp:ListView>

You will note that we have revised the following:

  • Added an OnClientClick event handler ( PaypalBuyNowProductSelected(this) ) on the ImageButton ASP.NET control, the purpose of which will be to reverse the effect of the hidden fields start-up transformation, but only for the single selected product.  This will ensure that only a single product is communicating with Paypal during the Buy Now postback operation.
  • Add the “id=paypalButton” attribute to the DIV section containing the Paypal Buy Now HTML snippet for each product and the ImageButton control.  This revision makes the jQuery parsing easier.

Now we need to drop in a jQuery ImageButton OnClientClick event handler:

   1:  function PaypalBuyNowProductSelected(o) {
   2:   
   3:      var productContainer = jQuery(o).parent('div');
   4:   
   5:      // activate Paypal hidden fields to properly 
   6:      // associate Paypal product being selected
   7:      productContainer.children('input:hidden').each(function () {
   8:   
   9:          switch (jQuery(this).attr("id")) {
  10:              case "cmd":
  11:              case "hosted_button_id":
  12:              case "currency_code":
  13:                  jQuery(this).attr("name", jQuery(this).attr("id"));
  14:                  break;
  15:              default:
  16:                  break;
  17:          }
  18:      });
  19:   
  20:      // find possible drop-down - used for multiple prices - 
  21:      // locate hidden input field
  22:      productContainer.children('table').children('tbody')
  23:          .children('tr').children('td')
  24:          .children('input:hidden').each(function () {
  25:   
  26:          switch (jQuery(this).attr("id")) {
  27:              case "on0":                 
  28:                  jQuery(this).attr("name", jQuery(this).attr("id"));
  29:                  break;
  30:              default:
  31:                  break;
  32:          }
  33:      });
  34:   
  35:      // find possible drop-down - used for multiple prices - 
  36:      // locate select field
  37:      productContainer.children('table').children('tbody')
  38:          .children('tr').children('td')
  39:          .children('select').each(function () {
  40:   
  41:          switch (jQuery(this).attr("id")) {
  42:              case "os0":                 
  43:                  jQuery(this).attr("name", jQuery(this).attr("id"));
  44:                  break;
  45:              default:
  46:                  break;
  47:          }
  48:      });
  49:   
  50:      return true;
  51:  }

You will note that the OnClientClick event handler is simply transforming Paypal hidden field “id” attributes to “name” attributes for the single product being selected; thus reversing the effect of the original WebForm start-up transformation for the single product only.

That is it.  Now we have working ASP.NET and jQuery code such that Paypal Buy Now buttons will work with ASP.NET and multiple product definitions.  If we use other Paypal hidden fields they can be manipulated in the same manner as the “cmd” and “hosted_button_id” hidden fields.