之前Mozilla推出Jetpack的時候,號稱很簡單就能打造出Firefox的擴充套件,那時起就一直很有興趣要來動手試試看拿來寫自己的第一個套件。最近連線上編輯器都有了,就跳下去試看看寫起來的難度如何。
一開始就有這類套件都是用Javascript寫成的認知,自己對Javascript也算是稍微熟悉了,所以不成問題。
在架構的理解上,網站上也準備了文件可以看。翻了翻幾個範例,第一印象是看來拿addon-kit裡面提供的元件兜一兜應該就能用了,如果要寫成Library之類的還有更底層的api-utils可以用。
既然目的是熟悉跟練習,就挑個簡單的題目來做好了,我想把NOWnews上有分頁的文章,合併回一頁,才不想浪費時間再點下一頁。
首先用page-mod判斷在載入NOWnews.com時觸發content scripts,然後在content scripts做抓取其他頁內容跟修改頁面的動作,只用到一項元件就完成了!
接著丟上AMO送審,非常高效率,很快就有結果,被退回了,理由是我把其他頁面的內容抓回來沒有用nsIScriptableUnescapeHTML之類的消毒過就丟innerHTML變成DOM,可能會有script標籤之類的偷藏惡意程式碼,好吧,再努力改一下。
問題來了,因為content scripts只能用來跟頁面互動,XPCOM的東西不能在content scripts裡面用,所以抓到的內容要送去add-on scripts消毒,然後再送回來,但是nsIScriptableUnescapeHTML的parseFragment()方法傳回來的是DocumentFragment物件,要給它一個DOMElement讓它掛上去,不幸的是,跟剛剛提到的相反,add-on scripts只能碰瀏覽器這邊的東西,沒辦法碰document這些頁面上的內容,所以我要去哪生DOM給它掛啊Orz
幸好小犬幫我想到了,用api-uptils裡面的hidden-frame來作為消毒場所,然後再把處理完的字串傳回去。
這裡提一下,content scripts要和add-on scripts通訊,只有postMessage跟port兩種方法,為了安全隔離,所以只能互傳字串,而用port能方便自訂事件名稱來設定多個管道,不像postMessage只有一個能用。
檢查一下消毒過後的內容,有沒有少了什麼東西,發現文章裡面用來內嵌YouTube影片的iframe標籤被濾掉了,想了半天,用了一個把iframe都先替換成video標籤的神奇方法,兩者都有width、height、src屬性,這些重要的資訊都不會遺失,只要再重新把iframe建回來就跟原先的內容一樣了。另外,我也測試了一下,embed和object標籤並不會被濾掉。
這個套件全部少少的程式碼可以在Builder站上看到,請各位多加指導。採用MIT授權,要拿去改寫對付宅宅新聞之類的請隨意,後續的更新則改在Github上面維護。
最後總算是通過審核上架了,附加元件頁面在此,用了那麼奇怪的手法居然也過關了,還真是令人開心。
要不是堅持要用Jetpack以套件的形式完成它,不然不上架就不必管安全性規則,這功能只用UserScript寫起來多簡單愉快啊,UserScript版本在此,Chrome的使用者可以直接安裝。
最後我的感想是,線上編輯器到處都可以寫,也可以用來展示程式碼的確是很方便,但是反覆測試時要花時間等它載入套件實在是太麻煩,編輯上打字又不太流暢,下次寫套件我想還是抓SDK在本機端編輯比較好。