Greasemonkey xhr redirection in Firefox 3

Tuesday, April 29, 2008

I found that my rssget script is not working in Firefox 3 beta for some of the link. After some investigation, the cause seems to be the difference in redirection handling. In Firefox 2, when GM_xmlhttpRequest() is fired, it would follow status like 302 to do the redirection to return the correct page response to the onload function. However, in Firefox 3, the onload would receive a status like 302 and thus the script would fail.

I don’t know whether it is the responsibility for the browser or the script to handle redirection like this. I have changed the script itself to follow the redirection. The code is like:

JavaScript:
  1. GM_xmlhttprequest({
  2.     method:"GET",
  3.     url: url,
  4.     onload: function(response){
  5.         if(response.status == 301 || response.status == 302 || response.status == 303){
  6.             var loc = /Location: ([^\n]*)\n/.exec(response.responseHeaders)[1];
  7.             GM_xmlhttprequest({
  8.                 method:"GET",
  9.                 url:loc,
  10.                 onload:arguments.callee
  11.             });
  12.             return;
  13.         }
  14.         //go on with normal parsing...
  15.     }
  16.  })

I’ve only included status 301 to 303 for the time being. Then it will try to get the ‘Location’ from its header and finally invoke another GM_xmlhttpRequest(). A little trick here is to use arguments.callee to recur itself.

The updated script is tagged as 1.5 in the code site . You will only need it if your script fail in Firefox 3.

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 就不會偵測到。

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

Appjet 陽春 Outliner

Monday, March 3, 2008

最近在 Appjet 試寫了一個簡單的 Outliner 程式,主要是想試用這個服務,也想寫一個自己可能會用得著的程式。

Appjet 早在上年十二月就已經出現了,可以在瀏覽器完成所有開發、測試、發佈等動作,本身也提供 hosting 服務。使用 Javascript 為後台語言,上手不難。簡化了後台儲存,只需直接寫入 StorableObject 。其提供的 library 可作簡單的 request dispatch。加上 wget 等一類存取其他網站的功能,可以很方便做出一些 mashup 應用。

而這個 Outliner 也是很簡單的,用戶登入後可以建立不同的 outline (其實也只是 nested list)。我的要求是:

  • 可以快速地記下一些 idea 或 draft,因此 outliner 的介面必需可以使用鍵盤作全面運作
  • 定時自動儲存
  • 可以列印

在開發上,用戶 login 直接使用 lib-user 庫,所以十分簡單。至於介面則要寫 Javascript 了,我使用了 jQuery 並開發了一個 outliner plugin 來使用,主要處理所有 add/delete/edit node 的運作和鍵盤連接。至於排版則使用了 YUI Grids CSS

開發上,Appjet 的部份並不難,反而是花比較多時間在頁面 Javascript 上的啄磨,不過基本上沒有遇上甚麼大難題,出來的東西也算是做到心中想要的效果,比較麻煩的是現在預設的控制鍵大都是英文字母,如果想打一個中文 outline 就要不停切換…

而對於 Appjet 的開發環境,有以下感想:

  • 因為 source code 是單一頁的關係,所以程式碼一多時就會有些亂
  • Appjet 並沒有 file hosting 的服務,除非你將所有檔當成 storage 物件來存,否則也是要找一些免費空間來放一些 scripts、css 等,我使用了 cachefile.net 和  googlepages.com 來放置。
  • Appjet 本身有 dispatch request 的 library,但就太簡單了些,如果慣於 MVC 模式的話可能會覺得亂。
  • Template 要自己想辦法。看到這個 lib-templates 不錯,不過今次並沒有使用。
  • 若果未來要更改 data structure,看來暫時只可以用 shell 做 up/down 的程序。

總括來說,Appjet 可以來開發簡單至中等複雜的應用,但若果是大型的,就必須自己開發一堆 library/framework 來支持了,還好在 Appjet 裏建立和引用 library 很簡單。

各位也可以試用這個 Outliner ,也是 Open Source 的 (基本上全部 Appjet 上的應用也是啦),但緊記這只是實驗性質,不要將重要資料放上去就是了。

蘋果動新聞 RSS 加取全文油猴更新

Wednesday, February 20, 2008

蘋果日報最近推出了 動新聞 不過又沒有 RSS,所以特地用 Dapper 打造了其首頁連結的 RSS ,大家可以拿來用。

美中不足的是只有標題連結,沒有內文,所以我更新了 取全文油猴腳本 ,可以照辦煮碗按 ‘G’ 取全文,大家可以點選安裝: Google Reader 版Bloglines 版Bloglines Beta 版