Browser Feature Detection

Wednesday, January 13, 2010

Often when dealing with different browsers, this is something I encounter recently (with jQuery):

JavaScript:
  1. var ie6 = $.browser.msie && $.browser.version == '6.0';
  2. if(ie6){
  3.     $('html,body').css({height:'100%',width:'100%'});
  4.     target.css('position','absolute'); //IE6 has no 'fixed' position
  5.     //....
  6. }

This code is copied from a library which aims at create an overlay for modal box. From IE7 onwards, CSS style position ‘fixed’ is supported, but not in IE7’s quirks mode. So the above code would fail. The solution is let IE7 run at correct doctype. e.g.:

HTML:
  1. <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">

But the code is still fragile to the environment. In jQuery, you can use $.support to get a set of feature detect properties. So, the code can become:

JavaScript:
  1. if(!$.support.boxModel){
  2.     $('html,body').css({height:'100%',width:'100%'});
  3.     target.css('position','absolute');
  4.     //....
  5. }

But it is still based on the assumption that “no support on boxModel = no support on fixed position”, which is “politically incorrect”.

jQuery 1.3 and JS Bin

Thursday, January 15, 2009

jQuery 1.3 剛剛出籠,重點是新的 selector engine Sizzle 。效能提昇之餘,更可因此而引進新功能,如 live event delegation ,據說普通的 event delegation 也會更快 (也是因為 selector 快了吧)。而 Sizzle 本身已成為一個獨立專案,讓其他 library 也可以用。

jQuery 的 API Browser 也更新了,在試用之時發覺每一個 code example 都伴隨一個 “Edit” 連結,結果是連到 JS Bin 裏可以直接修改和測試 Code,非常方便。

但 JS Bin 不是會每三個月做 house-keeping 嗎?還是特別為 jQuery 做 host 了?結果測看了其 URL,發現原來可以用 http://jsbin.com/?html=[code]&js=[code] 來發送一個完整的例子,當然這會受到 URL 的字數限制了。

jQuery Plugin – Stupid Fixed Header for HTML Table

Thursday, October 23, 2008

Sometimes you would like to have a nice table to navigate data with the header fixed on top while scrolling. There are many Javascript dataGrid component out there to do this but sometimes you just don’t need all those features. So I have wrote a jQuery plugin to create a fixed table header on a normal HTML table. It’s called Stupid Fixed Header .

I called it ‘stupid’ because it does so many things to achieve this little effect:

  1. create extra divs to wrap table up
  2. cloning current table header
  3. put the cloned table header on top of the current table
  4. synchronize width of each cell
  5. synchronize scroll position when scrolling

This idea is not original. I have read it elsewhere but cannot find the source again. So I do it in jQuery way.

The good things:

  • supports horizontal scroll
  • work across browsers (tested on IE6/7, Firefox3.1, Opera9.5, Chrome0.2, Safari 3.1.2).

The bad things:

  • in order to calculate correct cell width in different browsers, I have made certain assumptions in the default implementation: table’s border-collapse is collapse, cell have borders, etc. Therefore, you may need to make change for the width calculation. This is made possible by supplying adjustWidth to the plugin option. (However, dealing with width in table can be really troublesome. Even current implementation is not pixel perfect.)
  • Firefox has a bug of missing border when placing table inside a overflow div. Some specific CSS rules has been added to the sample page to workaround this.
  • It’s not pixel perfect.
  • It may not perform well.
  • The header cells will not get resized when the table cells width changes. This can be done by re-calculate the cells width and add custom event to the table for triggering. I’ll leave it to someone who has interest in doing so…

To support IE6, I have worked around the z-index bug by hiding <select> component. The reason for not using iframe hack is that it will get flashy when scroll.

Feel free to check the demo and doc .

Focus first text field using jQuery

Monday, April 14, 2008

When it comes to focus the first text field on a page using jQuery , the usual solution would be:

JavaScript:
  1. $(“:text:visible:enabled:eq(0)”).focus();

This query means to find the first of input text field(s), which is/are visible and enabled. However, this would also extract text field(s) which is/are under a display:none parent(s). So a more complete way would be:

JavaScript:
  1. $(“:text:visible:enabled”).filter(function(){
  2.      return $(this).parents(“:hidden”).size()==0;
  3.  }).slice(0,1).focus();

The filter here would try to determine if the text field is a descendant of a hidden ancestor. The usage of slice(0,1) instead of get(0) is to keep the chainability. A test page is put up here .

Finally, you may wrap it up with a plugin:

JavaScript:
  1. (function($){
  2.     $.fn.focusFirstField = function(){
  3.         $this = this;
  4.         $this.find(“:text:visible:enabled”).filter(function(){
  5.             return $(this).parents(“:hidden”).size() == 0;
  6.         }).slice(0,1).focus();
  7.         return this;
  8.     }
  9. })(jQuery)

So that you can do this:

JavaScript:
  1. $(“#form1,#form2”).focusFirstField(); //form1 or form2 may be ‘hidden’ dynamically

I just wonder if there is any ‘selector-only’ solution for this?

Update: It turns out that the child’s visiblity would override parent’s visibility. So the filter should only check display none:

JavaScript:
  1. $(":text:visible:enabled").filter(function(){
  2.      return $(this).parents.filter(function(){
  3.          return this.style.display == "none"; })
  4.     .size()==0;
  5.  }).slice(0,1).focus();

I’ve updated the demo page .

jQuery validation 的 addMethod

Thursday, March 27, 2008

jQueryValidation plugins 是很強大的,基本上可以滿足各種需要。剛剛被一個小問題困擾了好一陣子,特此記下。我寫了類似的東西:

HTML:
  1. <div id=“error” style=“display:none”><ul></ul></div>
  2.  <form id=“form1”>
  3.      <input type=“hidden” name=“fff” id=“fff” value=“” class=“special” />
  4.  </form>

JavaScript:
  1. $.validator.addMethod(“special”, function(value, element, params){
  2.     //validate….
  3.     return result;
  4.  }, “This is a special checking”);
  5.  
  6.  $(document).ready(function(){
  7.      $(“#form”).validate({
  8.         messages:{ fff: {special: “This is a special checking!”} },
  9.         errorContainer: “#error”,
  10.         errorLabelContainer: “#error ul”,
  11.         wrapper: “li”
  12.      });
  13.  });

結果怎樣也出不到那個自訂的 validation rule,苦苦深研追踪 source code 後才發現,問題在於 addMethod 裏的 method 參數問題,而正確的寫法是:

JavaScript:
  1. $.validator.addMethod(“special”, function(){
  2.     //validate…
  3.     return result;
  4.  }, “This is a special checking”);

那個 method 的參數數量如果大於 3,plugins 會認為你所加的是有參數的 validation,即在 element class 可能是 {special:abc} 之類,所以當看到 input 裏只是 special 就不會偵測到。

這樣很「正路」吧?但花了不少時間去看才知道。